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 | |
---|