1 | // ================================================================= // |
---|
2 | // // |
---|
3 | // File : gb_aci_impl.h // |
---|
4 | // Purpose : provide code useful to implement ACI commands // |
---|
5 | // // |
---|
6 | // Institute of Microbiology (Technical University Munich) // |
---|
7 | // http://www.arb-home.de/ // |
---|
8 | // // |
---|
9 | // ================================================================= // |
---|
10 | |
---|
11 | #ifndef GB_ACI_IMPL_H |
---|
12 | #define GB_ACI_IMPL_H |
---|
13 | |
---|
14 | #ifndef GB_ACI_H |
---|
15 | #include <gb_aci.h> |
---|
16 | #endif |
---|
17 | |
---|
18 | // export stream |
---|
19 | #define PASS_2_OUT(args,s) (args)->output.insert(s) |
---|
20 | #define COPY_2_OUT(args,s) PASS_2_OUT(args, ARB_strdup(s)) |
---|
21 | #define IN_2_OUT(args,i) PASS_2_OUT(args, args->input.get_smart(i)) |
---|
22 | #define PARAM_2_OUT(args,i) PASS_2_OUT(args, args->get_param_smart(i)) |
---|
23 | |
---|
24 | #define FORMAT_2_OUT(args,fmt,value) PASS_2_OUT(args, GBS_global_string_copy(fmt, value)) |
---|
25 | |
---|
26 | // ---------------------------- |
---|
27 | // Parameter functions |
---|
28 | |
---|
29 | namespace GBL_IMPL { |
---|
30 | |
---|
31 | const char *search_matching_parenthesis(const char *source); |
---|
32 | inline char *search_matching_parenthesis(char *source) { |
---|
33 | return const_cast<char*>(search_matching_parenthesis(const_cast<const char*>(source))); |
---|
34 | } |
---|
35 | |
---|
36 | |
---|
37 | struct gbl_param { |
---|
38 | gbl_param *next; |
---|
39 | GB_TYPES type; // type of variable |
---|
40 | void *varaddr; // address of variable where value gets stored |
---|
41 | const char *param_name; // parameter name (e.g. 'include=') |
---|
42 | const char *help_text; // help text for parameter |
---|
43 | }; |
---|
44 | |
---|
45 | #define GBL_BEGIN_PARAMS gbl_param *params = NULp |
---|
46 | |
---|
47 | inline void gbl_new_param(gbl_param **pp, GB_TYPES type, void *vaddr, const char *param_name, const char *help_text) { |
---|
48 | gbl_param *gblp = ARB_calloc<gbl_param>(1); |
---|
49 | |
---|
50 | gblp->next = *pp; |
---|
51 | *pp = gblp; |
---|
52 | |
---|
53 | gblp->type = type; |
---|
54 | gblp->varaddr = vaddr; |
---|
55 | gblp->param_name = param_name; |
---|
56 | gblp->help_text = help_text; |
---|
57 | } |
---|
58 | |
---|
59 | typedef const char *String; |
---|
60 | typedef int bit; |
---|
61 | typedef unsigned int nat; |
---|
62 | |
---|
63 | inline int gbl_param_int(const char *param_name, int def, const char *help_text, gbl_param **pp, int *vaddr) { |
---|
64 | gbl_new_param(pp, GB_INT, vaddr, param_name, help_text); |
---|
65 | return def; |
---|
66 | } |
---|
67 | |
---|
68 | inline char gbl_param_char(const char *param_name, char def, const char *help_text, gbl_param **pp, char *vaddr) { |
---|
69 | gbl_new_param(pp, GB_BYTE, vaddr, param_name, help_text); |
---|
70 | return def; |
---|
71 | } |
---|
72 | |
---|
73 | inline nat gbl_param_nat(const char *param_name, nat def, const char *help_text, gbl_param **pp, nat *vaddr) { |
---|
74 | gbl_new_param(pp, GB_INT, vaddr, param_name, help_text); |
---|
75 | return def; |
---|
76 | } |
---|
77 | |
---|
78 | inline const char *gbl_param_String(const char *param_name, const char *def, const char *help_text, gbl_param **pp, String *vaddr) { |
---|
79 | gbl_new_param(pp, GB_STRING, vaddr, param_name, help_text); |
---|
80 | return def; |
---|
81 | } |
---|
82 | |
---|
83 | inline int gbl_param_bit(const char *param_name, int def, const char *help_text, gbl_param **pp, bit *vaddr) { |
---|
84 | gbl_new_param(pp, GB_BIT, vaddr, param_name, help_text); |
---|
85 | return def; |
---|
86 | } |
---|
87 | |
---|
88 | GB_ERROR trace_params(const GBL_streams& param, gbl_param *ppara, const char *com); |
---|
89 | }; |
---|
90 | |
---|
91 | #define GBL_PARAM_TYPE(type, var, param_name, def, help_text) type var = gbl_param_##type(param_name, def, help_text, ¶ms, &var) |
---|
92 | #define GBL_STRUCT_PARAM_TYPE(type, strct, member, param_name, def, help_text) strct.member = gbl_param_##type(param_name, def, help_text, ¶ms, &strct.member) |
---|
93 | |
---|
94 | // use PARAM_IF for parameters whose existence depends on condition |
---|
95 | #define PARAM_IF(cond,param) ((cond) ? (param) : NULp) |
---|
96 | |
---|
97 | #define GBL_PARAM_INT(var, param_name, def, help_text) GBL_PARAM_TYPE(int, var, param_name, def, help_text) |
---|
98 | #define GBL_PARAM_CHAR(var, param_name, def, help_text) GBL_PARAM_TYPE(char, var, param_name, def, help_text) |
---|
99 | #define GBL_PARAM_UINT(var, param_name, def, help_text) GBL_PARAM_TYPE(nat, var, param_name, def, help_text) |
---|
100 | #define GBL_PARAM_STRING(var, param_name, def, help_text) GBL_PARAM_TYPE(String, var, param_name, def, help_text) |
---|
101 | #define GBL_PARAM_BIT(var, param_name, def, help_text) GBL_PARAM_TYPE(bit, var, param_name, def, help_text) |
---|
102 | |
---|
103 | #define GBL_STRUCT_PARAM_INT(strct, member, param_name, def, help_text) GBL_STRUCT_PARAM_TYPE(int, strct, member, param_name, def, help_text) |
---|
104 | #define GBL_STRUCT_PARAM_CHAR(strct, member, param_name, def, help_text) GBL_STRUCT_PARAM_TYPE(char, strct, member, param_name, def, help_text) |
---|
105 | #define GBL_STRUCT_PARAM_UINT(strct, member, param_name, def, help_text) GBL_STRUCT_PARAM_TYPE(nat, strct, member, param_name, def, help_text) |
---|
106 | #define GBL_STRUCT_PARAM_STRING(strct, member, param_name, def, help_text) GBL_STRUCT_PARAM_TYPE(String, strct, member, param_name, def, help_text) |
---|
107 | #define GBL_STRUCT_PARAM_BIT(strct, member, param_name, def, help_text) GBL_STRUCT_PARAM_TYPE(bit, strct, member, param_name, def, help_text) |
---|
108 | |
---|
109 | #define GBL_TRACE_PARAMS(args) \ |
---|
110 | do { \ |
---|
111 | GB_ERROR def_error = \ |
---|
112 | trace_params((args)->get_param_streams(), params, (args)->get_cmdName()); \ |
---|
113 | gb_assert((args)->set_params_checked()); \ |
---|
114 | if (def_error) { GBL_END_PARAMS; return def_error; } \ |
---|
115 | } while(0) |
---|
116 | |
---|
117 | #define GBL_END_PARAMS \ |
---|
118 | do { \ |
---|
119 | gbl_param *_gblp; \ |
---|
120 | while (params) { \ |
---|
121 | _gblp = params; \ |
---|
122 | params = params->next; \ |
---|
123 | free(_gblp); \ |
---|
124 | } \ |
---|
125 | } while (0) |
---|
126 | |
---|
127 | #define GBL_CHECK_FREE_PARAM(nr, cnt) \ |
---|
128 | do { \ |
---|
129 | if ((nr)+(cnt) >= GBL_MAX_ARGUMENTS) { \ |
---|
130 | /* gb_assert(0); */ \ |
---|
131 | return "max. parameters exceeded"; \ |
---|
132 | } \ |
---|
133 | } while (0) |
---|
134 | |
---|
135 | // @@@ remove GBL_MAX_ARGUMENTS - instead allocate dynamic |
---|
136 | |
---|
137 | // -------------------------------- |
---|
138 | // parameter/stream checks |
---|
139 | |
---|
140 | namespace GBL_IMPL { |
---|
141 | |
---|
142 | extern int traceACI; |
---|
143 | extern int traceIndent; |
---|
144 | |
---|
145 | void print_trace(const char *text); |
---|
146 | |
---|
147 | inline void modify_trace_indent(int diff) { |
---|
148 | traceIndent += diff; |
---|
149 | gb_assert(traceIndent>=0); |
---|
150 | } |
---|
151 | |
---|
152 | inline GB_ERROR check_no_parameter(GBL_command_arguments *args) { |
---|
153 | gb_assert(args->set_params_checked()); |
---|
154 | if (args->param_count() == 0) return NULp; |
---|
155 | return GBS_global_string("syntax: %s (no parameters)", args->get_cmdName()); |
---|
156 | } |
---|
157 | inline GB_ERROR check_has_parameters(GBL_command_arguments *args, const char *param_syntax) { |
---|
158 | gb_assert(args->set_params_checked()); |
---|
159 | if (args->param_count() > 0) return NULp; |
---|
160 | return GBS_global_string("syntax: %s(%s)", args->get_cmdName(), param_syntax); |
---|
161 | } |
---|
162 | inline GB_ERROR check_parameters(GBL_command_arguments *args, int expected, const char *parameterList) { |
---|
163 | gb_assert(args->set_params_checked()); |
---|
164 | if (args->param_count() == expected) return NULp; |
---|
165 | return GBS_global_string("syntax: %s(%s)", args->get_cmdName(), parameterList); |
---|
166 | } |
---|
167 | inline GB_ERROR check_optional_parameters(GBL_command_arguments *args, int fix, const char *fixParam, int opt, const char *optParam, bool opt_trailing, bool opt_expect_all) { |
---|
168 | // if opt_expect_all == true -> checks whether either NO or ALL optional parameters were specified |
---|
169 | // if opt_expect_all == false -> accept any number of parameters -> specify 'optParam' e.g. like "p3[,p4[,p5]]" |
---|
170 | // if opt_trailing == false -> optional parameters are BEFORE fixed (don't use!) |
---|
171 | gb_assert(args->set_params_checked()); |
---|
172 | |
---|
173 | int params = args->param_count(); |
---|
174 | if (params == fix || params == (fix+opt)) return NULp; |
---|
175 | if (!opt_expect_all && params >= fix && params <= (fix+opt)) return NULp; |
---|
176 | if (!fix) return GBS_global_string("syntax: %s[(%s)]", args->get_cmdName(), optParam); |
---|
177 | if (opt_trailing) return GBS_global_string("syntax: %s(%s[,%s])", args->get_cmdName(), fixParam, optParam); |
---|
178 | return GBS_global_string("syntax: %s([%s,]%s)", args->get_cmdName(), optParam, fixParam); |
---|
179 | } |
---|
180 | |
---|
181 | inline GB_ERROR check_valid_index(int number, const char *what, int min, int max) { |
---|
182 | if (number >= min && number <= max) return NULp; |
---|
183 | return GBS_global_string("Illegal %s number '%i' (allowed [%i..%i])", what, number, min, max); |
---|
184 | } |
---|
185 | inline GB_ERROR check_valid_stream_index(GBL_command_arguments *args, int number) { return check_valid_index(number, "stream", 1, args->input.size()); } |
---|
186 | inline GB_ERROR check_valid_param_index (GBL_command_arguments *args, int number) { return check_valid_index(number, "param", 0, args->param_count()-1); } |
---|
187 | |
---|
188 | inline GB_ERROR check_item_referenced(GBL_command_arguments *args) { |
---|
189 | return args->get_item_ref() |
---|
190 | ? NULp |
---|
191 | : GBS_global_string("command %s cannot be called w/o item", args->get_cmdName()); |
---|
192 | } |
---|
193 | }; |
---|
194 | |
---|
195 | #define TRACE_ACI(text) if (GBL_IMPL::traceACI) GBL_IMPL::print_trace(text) |
---|
196 | |
---|
197 | #define DO_AND_RETURN_ON_ERROR(cmd) do { \ |
---|
198 | GB_ERROR perr = (cmd); \ |
---|
199 | if (perr) return perr; \ |
---|
200 | } while(0) |
---|
201 | |
---|
202 | #define EXPECT_NO_PARAM(args) DO_AND_RETURN_ON_ERROR(GBL_IMPL::check_no_parameter(args)) |
---|
203 | #define EXPECT_PARAMS_PASSED(args,syntax) DO_AND_RETURN_ON_ERROR(GBL_IMPL::check_has_parameters(args,syntax)) |
---|
204 | #define ACCEPT_ANY_PARAMS(args) gb_assert((args)->set_params_checked()) |
---|
205 | |
---|
206 | #define EXPECT_PARAMS(args,cnt,help) DO_AND_RETURN_ON_ERROR(GBL_IMPL::check_parameters(args, cnt, help)) |
---|
207 | #define EXPECT_OPTIONAL_PARAMS(args,fixCnt,fixhelp,optCnt,opthelp) DO_AND_RETURN_ON_ERROR(GBL_IMPL::check_optional_parameters(args, fixCnt, fixhelp, optCnt, opthelp, true, true)) |
---|
208 | #define EXPECT_OPTIONAL_PARAMS_CUSTOM(args,fixCnt,fixhelp,optCnt,opthelp,trail,all) DO_AND_RETURN_ON_ERROR(GBL_IMPL::check_optional_parameters(args, fixCnt, fixhelp, optCnt, opthelp, trail, all)) |
---|
209 | |
---|
210 | #define EXPECT_LEGAL_STREAM_INDEX(args,number) do { \ |
---|
211 | GB_ERROR serr = GBL_IMPL::check_valid_stream_index(args, number); \ |
---|
212 | if (serr) return serr; \ |
---|
213 | } while(0) |
---|
214 | |
---|
215 | #define EXPECT_ITEM_REFERENCED(args) DO_AND_RETURN_ON_ERROR(GBL_IMPL::check_item_referenced(args)) |
---|
216 | |
---|
217 | |
---|
218 | #define COMMAND_DROPS_INPUT_STREAMS(args) do { \ |
---|
219 | if (GBL_IMPL::traceACI && args->input.size()>0) { \ |
---|
220 | if (args->input.size()>1 || args->input.get(0)[0]) { \ |
---|
221 | GBL_IMPL::print_trace(GBS_global_string("Warning: Dropped %i input streams\n", args->input.size())); \ |
---|
222 | } \ |
---|
223 | } \ |
---|
224 | } while(0) |
---|
225 | |
---|
226 | |
---|
227 | #else |
---|
228 | #error gb_aci_impl.h included twice |
---|
229 | #endif // GB_ACI_IMPL_H |
---|