| 1 | // =============================================================== // |
|---|
| 2 | // // |
|---|
| 3 | // File : adperl.cxx // |
|---|
| 4 | // Purpose : helper functions used by perl interface // |
|---|
| 5 | // (see ../PERL2ARB) // |
|---|
| 6 | // // |
|---|
| 7 | // Institute of Microbiology (Technical University Munich) // |
|---|
| 8 | // http://www.arb-home.de/ // |
|---|
| 9 | // // |
|---|
| 10 | // =============================================================== // |
|---|
| 11 | |
|---|
| 12 | #include "gb_local.h" |
|---|
| 13 | #include "adperl.h" |
|---|
| 14 | |
|---|
| 15 | // used by perl interface, see ../PERL2ARB/ARB_ext.c@GBP_croak_function |
|---|
| 16 | void (*GBP_croak_function)(const char *message) = NULp; |
|---|
| 17 | |
|---|
| 18 | static void die(const char *with_last_words) { |
|---|
| 19 | // raise exception in caller (assuming caller is a perl script) |
|---|
| 20 | |
|---|
| 21 | if (GBP_croak_function) { |
|---|
| 22 | GBP_croak_function(with_last_words); |
|---|
| 23 | } |
|---|
| 24 | else { |
|---|
| 25 | fputs("Warning: GBP_croak_function undefined. terminating..\n", stderr); |
|---|
| 26 | GBK_terminate(with_last_words); |
|---|
| 27 | } |
|---|
| 28 | } |
|---|
| 29 | |
|---|
| 30 | // ------------------------------------------- |
|---|
| 31 | // "generic" enum<->string-conversion |
|---|
| 32 | |
|---|
| 33 | union known_enum { |
|---|
| 34 | int as_int; |
|---|
| 35 | |
|---|
| 36 | GB_SEARCH_TYPE search_type; |
|---|
| 37 | GB_CASE case_sensitivity; |
|---|
| 38 | GB_TYPES db_type; |
|---|
| 39 | GB_UNDO_TYPE undo_type; |
|---|
| 40 | GB_alignment_type ali_type; |
|---|
| 41 | }; |
|---|
| 42 | |
|---|
| 43 | #define ILLEGAL_VALUE (-666) |
|---|
| 44 | |
|---|
| 45 | |
|---|
| 46 | typedef const char *(*enum2string)(known_enum enumValue); |
|---|
| 47 | |
|---|
| 48 | static known_enum next_known_enum_value(known_enum greaterThan, enum2string lookup) { |
|---|
| 49 | known_enum enumValue, lookupLimit; |
|---|
| 50 | |
|---|
| 51 | enumValue.as_int = greaterThan.as_int+1; |
|---|
| 52 | lookupLimit.as_int = enumValue.as_int+256; |
|---|
| 53 | |
|---|
| 54 | while (enumValue.as_int <= lookupLimit.as_int) { |
|---|
| 55 | const char *valueExists = lookup(enumValue); |
|---|
| 56 | if (valueExists) return enumValue; |
|---|
| 57 | enumValue.as_int++; |
|---|
| 58 | } |
|---|
| 59 | |
|---|
| 60 | enumValue.as_int = ILLEGAL_VALUE; |
|---|
| 61 | return enumValue; |
|---|
| 62 | } |
|---|
| 63 | |
|---|
| 64 | static known_enum first_known_enum_value(known_enum greaterEqualThan, enum2string lookup) { |
|---|
| 65 | return (lookup(greaterEqualThan)) |
|---|
| 66 | ? greaterEqualThan |
|---|
| 67 | : next_known_enum_value(greaterEqualThan, lookup); |
|---|
| 68 | } |
|---|
| 69 | |
|---|
| 70 | static known_enum string2enum(const char *string, enum2string lookup, known_enum start) { |
|---|
| 71 | |
|---|
| 72 | for (start = first_known_enum_value(start, lookup); |
|---|
| 73 | start.as_int != ILLEGAL_VALUE; |
|---|
| 74 | start = next_known_enum_value(start, lookup)) |
|---|
| 75 | { |
|---|
| 76 | const char *asString = lookup(start); |
|---|
| 77 | gb_assert(asString); |
|---|
| 78 | if (strcasecmp(asString, string) == 0) break; // found |
|---|
| 79 | } |
|---|
| 80 | return start; |
|---|
| 81 | } |
|---|
| 82 | |
|---|
| 83 | static char *buildAllowedValuesString(known_enum start, enum2string lookup) { |
|---|
| 84 | char *allowed = NULp; |
|---|
| 85 | |
|---|
| 86 | for (start = first_known_enum_value(start, lookup); |
|---|
| 87 | start.as_int != ILLEGAL_VALUE; |
|---|
| 88 | start = next_known_enum_value(start, lookup)) |
|---|
| 89 | { |
|---|
| 90 | const char *asString = lookup(start); |
|---|
| 91 | gb_assert(asString); |
|---|
| 92 | |
|---|
| 93 | if (allowed) freeset(allowed, GBS_global_string_copy("%s, '%s'", allowed, asString)); |
|---|
| 94 | else allowed = GBS_global_string_copy("'%s'", asString); |
|---|
| 95 | } |
|---|
| 96 | |
|---|
| 97 | if (!allowed) allowed = ARB_strdup("none (this is a bug)"); |
|---|
| 98 | |
|---|
| 99 | return allowed; |
|---|
| 100 | } |
|---|
| 101 | |
|---|
| 102 | static known_enum string2enum_or_die(const char *enum_name, const char *string, enum2string lookup, known_enum start) { |
|---|
| 103 | known_enum found = string2enum(string, lookup, start); |
|---|
| 104 | |
|---|
| 105 | if (found.as_int == ILLEGAL_VALUE) { |
|---|
| 106 | char *allowed_values = buildAllowedValuesString(start, lookup); |
|---|
| 107 | char *usage = GBS_global_string_copy("Error: value '%s' is not a legal %s\n" |
|---|
| 108 | "Known %ss are: %s", |
|---|
| 109 | string, enum_name, enum_name, allowed_values); |
|---|
| 110 | free(allowed_values); |
|---|
| 111 | die(usage); |
|---|
| 112 | } |
|---|
| 113 | |
|---|
| 114 | return found; |
|---|
| 115 | } |
|---|
| 116 | |
|---|
| 117 | /* -------------------------------------------------------------------------------- |
|---|
| 118 | * conversion declarations for different used enums |
|---|
| 119 | * |
|---|
| 120 | * To add a new enum type |
|---|
| 121 | * - write a function to convert your enum-values into a string (example: GBP_gb_search_types_to_string) |
|---|
| 122 | * - write a reverse-wrapper (example: GBP_string_to_gb_search_types) |
|---|
| 123 | * |
|---|
| 124 | * [Code-Tag: enum_conversion_functions] |
|---|
| 125 | * see also ../PERLTOOLS/arb_proto_2_xsub.cxx@enum_type_replacement |
|---|
| 126 | */ |
|---|
| 127 | |
|---|
| 128 | // ------------------------ |
|---|
| 129 | // GB_SEARCH_TYPE |
|---|
| 130 | |
|---|
| 131 | const char *GBP_GB_SEARCH_TYPE_2_charPtr(GB_SEARCH_TYPE search_type) { |
|---|
| 132 | switch (search_type) { |
|---|
| 133 | case SEARCH_BROTHER: return "brother"; |
|---|
| 134 | case SEARCH_CHILD: return "child"; |
|---|
| 135 | case SEARCH_GRANDCHILD: return "grandchild"; |
|---|
| 136 | case SEARCH_NEXT_BROTHER: return "next_brother"; |
|---|
| 137 | case SEARCH_CHILD_OF_NEXT: return "child_of_next"; |
|---|
| 138 | } |
|---|
| 139 | |
|---|
| 140 | return NULp; |
|---|
| 141 | } |
|---|
| 142 | |
|---|
| 143 | GB_SEARCH_TYPE GBP_charPtr_2_GB_SEARCH_TYPE(const char *search_mode) { |
|---|
| 144 | known_enum start; start.as_int = 0; |
|---|
| 145 | known_enum found = string2enum_or_die("search-type", search_mode, CASTSIG(enum2string, GBP_GB_SEARCH_TYPE_2_charPtr), start); |
|---|
| 146 | return found.search_type; |
|---|
| 147 | } |
|---|
| 148 | |
|---|
| 149 | // ------------------ |
|---|
| 150 | // GB_TYPES |
|---|
| 151 | |
|---|
| 152 | const char *GBP_GB_TYPES_2_charPtr(GB_TYPES type) { |
|---|
| 153 | switch (type) { |
|---|
| 154 | case GB_NONE: return "NONE"; |
|---|
| 155 | case GB_BIT: return "BIT"; |
|---|
| 156 | case GB_BYTE: return "BYTE"; |
|---|
| 157 | case GB_INT: return "INT"; |
|---|
| 158 | case GB_FLOAT: return "FLOAT"; |
|---|
| 159 | case GB_BITS: return "BITS"; |
|---|
| 160 | case GB_BYTES: return "BYTES"; |
|---|
| 161 | case GB_INTS: return "INTS"; |
|---|
| 162 | case GB_FLOATS: return "FLOATS"; |
|---|
| 163 | case GB_STRING: return "STRING"; |
|---|
| 164 | case GB_DB: return "CONTAINER"; |
|---|
| 165 | |
|---|
| 166 | default: break; |
|---|
| 167 | } |
|---|
| 168 | return NULp; |
|---|
| 169 | } |
|---|
| 170 | |
|---|
| 171 | GB_TYPES GBP_charPtr_2_GB_TYPES(const char *type_name) { |
|---|
| 172 | known_enum start; start.as_int = 0; |
|---|
| 173 | known_enum found = string2enum_or_die("db-type", type_name, CASTSIG(enum2string, GBP_GB_TYPES_2_charPtr), start); |
|---|
| 174 | return found.db_type; |
|---|
| 175 | } |
|---|
| 176 | |
|---|
| 177 | |
|---|
| 178 | // ---------------------- |
|---|
| 179 | // GB_UNDO_TYPE |
|---|
| 180 | |
|---|
| 181 | const char *GBP_GB_UNDO_TYPE_2_charPtr(GB_UNDO_TYPE undo_type) { |
|---|
| 182 | switch (undo_type) { |
|---|
| 183 | case GB_UNDO_UNDO: return "undo"; |
|---|
| 184 | case GB_UNDO_REDO: return "redo"; |
|---|
| 185 | |
|---|
| 186 | case GB_UNDO_NONE: |
|---|
| 187 | case GB_UNDO_KILL: |
|---|
| 188 | case GB_UNDO_UNDO_REDO: |
|---|
| 189 | break; |
|---|
| 190 | } |
|---|
| 191 | return NULp; |
|---|
| 192 | } |
|---|
| 193 | |
|---|
| 194 | GB_UNDO_TYPE GBP_charPtr_2_GB_UNDO_TYPE(const char *undo_type) { |
|---|
| 195 | known_enum start; start.as_int = 0; |
|---|
| 196 | known_enum found = string2enum_or_die("undo-type", undo_type, CASTSIG(enum2string, GBP_GB_UNDO_TYPE_2_charPtr), start); |
|---|
| 197 | return found.undo_type; |
|---|
| 198 | } |
|---|
| 199 | |
|---|
| 200 | |
|---|
| 201 | // ----------------- |
|---|
| 202 | // GB_CASE |
|---|
| 203 | |
|---|
| 204 | const char *GBP_GB_CASE_2_charPtr(GB_CASE sensitivity) { |
|---|
| 205 | switch (sensitivity) { |
|---|
| 206 | case GB_IGNORE_CASE: return "ignore_case"; |
|---|
| 207 | case GB_MIND_CASE: return "mind_case"; |
|---|
| 208 | case GB_CASE_UNDEFINED: return "case_undef"; |
|---|
| 209 | } |
|---|
| 210 | return NULp; |
|---|
| 211 | } |
|---|
| 212 | |
|---|
| 213 | GB_CASE GBP_charPtr_2_GB_CASE(const char *sensitivity) { |
|---|
| 214 | known_enum start; start.as_int = 0; |
|---|
| 215 | known_enum found = string2enum_or_die("sensitivity", sensitivity, CASTSIG(enum2string, GBP_GB_CASE_2_charPtr), start); |
|---|
| 216 | return found.case_sensitivity; |
|---|
| 217 | } |
|---|
| 218 | |
|---|
| 219 | // --------------------------- |
|---|
| 220 | // GB_alignment_type |
|---|
| 221 | |
|---|
| 222 | const char *GBP_GB_alignment_type_2_charPtr(GB_alignment_type ali_type) { |
|---|
| 223 | switch (ali_type) { |
|---|
| 224 | case GB_AT_RNA: return "RNA"; |
|---|
| 225 | case GB_AT_DNA: return "DNA"; |
|---|
| 226 | case GB_AT_AA: return "AMINO"; |
|---|
| 227 | |
|---|
| 228 | case GB_AT_UNKNOWN: break; |
|---|
| 229 | } |
|---|
| 230 | return NULp; |
|---|
| 231 | } |
|---|
| 232 | |
|---|
| 233 | GB_alignment_type GBP_charPtr_2_GB_alignment_type(const char *ali_type) { |
|---|
| 234 | known_enum start; start.as_int = 0; |
|---|
| 235 | known_enum found = string2enum_or_die("alignment-type", ali_type, CASTSIG(enum2string, GBP_GB_alignment_type_2_charPtr), start); |
|---|
| 236 | return found.ali_type; |
|---|
| 237 | } |
|---|
| 238 | |
|---|
| 239 | // ----------------------------------------- |
|---|
| 240 | // wrap functions moved to CORE lib |
|---|
| 241 | // |
|---|
| 242 | // As long as CORE lib is not xsub'd, we use wrappers for some |
|---|
| 243 | // functions used in perl |
|---|
| 244 | |
|---|
| 245 | GB_ERROR GBC_await_error() { |
|---|
| 246 | return GB_await_error(); |
|---|
| 247 | } |
|---|
| 248 | |
|---|
| 249 | // -------------------- |
|---|
| 250 | // perl panic |
|---|
| 251 | |
|---|
| 252 | void GBP_prepare_to_die() { |
|---|
| 253 | // called from die() in ../PERL2ARB/ARB.pm@prepare_to_die |
|---|
| 254 | gb_abort_and_close_all_DBs(); |
|---|
| 255 | } |
|---|
| 256 | |
|---|