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