00001
00065 #include <string.h>
00066 #include <stdlib.h>
00067 #include <time.h>
00068 #include <ctype.h>
00069 #include <math.h>
00070 #include <string>
00071 #include <vector>
00072 #include <strstream.h>
00073 using std::vector;
00074
00075
00076 #ifndef NO_SIGNAL_HANDLING
00077 #include <signal.h>
00078 #include <setjmp.h>
00079 #endif
00080
00081 #include "ipc.h"
00082 #include "cmdparam.h"
00083
00084
00085
00086
00087
00088
00089
00090
00091 #define PARENTPE (0)
00092 #define AMPARENTPE (ipc_my_process()==PARENTPE)
00093
00094
00095
00096
00097 #define PARAM_MAX_NAME_LENGTH 64
00098
00099 typedef union { char *c; int i; double f; } bound;
00100
00101
00102 typedef struct
00103 {
00104 char name[PARAM_MAX_NAME_LENGTH];
00105 int data_type ;
00106 int is_constant;
00111 union t { char *c; int *i; double *f; } data_ptr;
00112 bound lower_bound;
00113 int enforce_lower;
00114 bound upper_bound;
00115 int enforce_upper;
00116 SetFnWrapper* setfn;
00117 const char *doc;
00118 int been_set;
00119 const char *default_expr;
00120 } ParamInterface;
00121
00122 #define PARAM_MAX_ENTRIES 275
00123
00124
00125 typedef struct{
00126 int num;
00127 ParamInterface list[PARAM_MAX_ENTRIES];
00128 }Blackboard;
00129
00130
00131 #ifndef LONG_DOUBLE_UNAVAILABLE
00132 typedef long double exprtype;
00133 #else
00134 typedef double exprtype;
00135 #endif
00136
00137
00138
00139 #define CMDDEF_MAX_NUM 64
00140 #define CMDDEF_MAX_NAME_LENGTH 64
00141 #define CMDDEF_MAX_PREREQS 2
00143
00144 typedef struct{
00145 char name[CMDDEF_MAX_NAME_LENGTH+1];
00146 CmdWrapper* function;
00147 int minargs;
00148 int catchup;
00149 int num_prereqs;
00150 int prereqs[CMDDEF_MAX_PREREQS];
00151 int callstatus;
00152 const char *usage;
00153 const char *doc;
00154 }CommandDefinition;
00155
00156
00157 typedef struct{
00158 int num;
00159 CommandDefinition list[CMDDEF_MAX_NUM];
00160 }CommandDefinitionBlackboard;
00161
00162
00163 typedef struct{
00164 int argc;
00165 const char *argv[CMD_MAX_ARGUMENTS];
00166 CommandDefinition* def;
00167 }Command;
00168
00169 #define CMD_CALL(cmd) (*((cmd).def->function))((cmd).argc, (cmd).argv)
00170
00171
00172
00173
00174
00175 typedef struct
00176 {
00177 int start;
00178 int end;
00179 int step;
00181 int order;
00182 char *argstofree[CMD_MAX_ARGUMENTS+1];
00183 Command cmd;
00184 } CounterHookDefinition;
00185
00186 #define HOOKLIST_MAX_NUM 128
00187 #define HOOKLIST_MAX_NAME_LENGTH 32
00188
00189
00190 typedef struct
00191 {
00192 char name[HOOKLIST_MAX_NAME_LENGTH];
00193 char countername[HOOKLIST_MAX_NAME_LENGTH];
00194 int current;
00195 int num;
00196 CounterHookDefinition defs[HOOKLIST_MAX_NUM];
00197 } CounterHooklist;
00198
00199 #define HOOKLISTS_MAX_NUM 4
00200
00201 #define HAS_CURRENT_HOOK(hooklist) ((hooklist).current < (hooklist).num)
00202 #define CURRENT_HOOK(hooklist) ((hooklist).defs[(hooklist).current])
00203
00204
00205 typedef struct
00206 {
00207 int num;
00208 CounterHooklist lists[HOOKLISTS_MAX_NUM];
00209 } CounterHooklists;
00210
00211
00212 00213 00214
00215 typedef struct
00216 {
00217 int num;
00218 const char* names[CMDDEF_MAX_NUM*CMDDEF_MAX_PREREQS];
00219 const char* prereqs[CMDDEF_MAX_NUM*CMDDEF_MAX_PREREQS];
00220 } PrereqList;
00221
00222
00223
00224
00225
00226
00227
00228 CounterHooklists hooklists;
00229
00230 Blackboard blackboard;
00231 CommandDefinitionBlackboard command_definitions;
00233 int cmdparam_warn_unknown = True;
00234 int cmdparam_changes_verbose = True;
00236 int commands_succeeded = 0;
00237 int commands_failed = 0;
00238 int command_num_called = 0;
00239
00240
00241 int hook_definition_counter=0;
00242
00243
00244 FILE *cmddefs_file=NULL;
00245 char commandpath[CMD_MAX_LINE_LENGTH] = "../command/ ../../command/ ../samples/";
00246
00247
00248 int cmddefs_exec_file_argc=0;
00249 const char **cmddefs_exec_file_argv=NULL;
00250
00251 char cmddefs_line_buffer[CMD_MAX_LINE_LENGTH+1+sizeof(int)];
00252
00253 PrereqList prereq_storage;
00254
00255 const char cmdparam_help_separator[]=
00256 "_______________________________________________________________________________\n";
00257
00258
00259 #ifndef NO_SIGNAL_HANDLING
00260 typedef void (*signal_handler_type)(int);
00261 jmp_buf jmp_env;
00262 #endif
00263
00264
00265
00266
00267
00268
00269
00270 CMD_DECLARE(call);
00271 CMD_DECLARE(clear_hooks);
00272 CMD_DECLARE(define_param);
00273 CMD_DECLARE(dotimes);
00274 CMD_DECLARE(exec);
00275 CMD_DECLARE(exec_file);
00276 CMD_DECLARE(for);
00277 CMD_DECLARE(hook);
00278 CMD_DECLARE(if);
00279 CMD_DECLARE(print);
00280 CMD_DECLARE(quit);
00281 CMD_DECLARE(read_args);
00282 CMD_DECLARE(save_params);
00283 CMD_DECLARE(set);
00284 CMD_DECLARE(system);
00285
00286 size_t cmdparam_identifier_length(const char* str);
00287 void ipc_init_hook( void );
00288
00289 exprtype params_apply_op(exprtype lval, string op, exprtype rval);
00290 exprtype params_getnumericval(const char **remaining );
00291 const char *params_getstringval(const char **remaining );
00292 void* params_getval(int* type, const char **remaining );
00293 exprtype params_next_term(const char **remaining, string previous_op="");
00294 ParamInterface* params_lookup(const char *name, size_t len);
00295 string params_next_op(const char **remaining);
00296 exprtype params_parse_expr(const char **remaining);
00297 exprtype params_read_float(const char* str);
00298
00299 int cmddef_compare(const void* hook1, const void* hook2);
00300 void cmddefs_sort(void);
00301 int cmddefs_get_line_from_file( void );
00302
00303 int command_check_usage(Command* command);
00304 cmdstat command_exec(Command *cmd);
00305 CommandDefinition* cmddefs_lookup(const char *name);
00306 int command_parse_line(Command *command, char *string);
00307 const char* command_parse_token(char** remaining);
00308 void command_print_to_str( const Command *cmd, char *str, size_t nchars);
00309 void cmddef_print_usage(FILE *fp, const CommandDefinition* cmddef);
00310 void cmddef_print_usage_to_str(const CommandDefinition* cmddef, char *str, size_t nchars);
00311 void cmddefs_activate_prereqs( void );
00312 void cmddefs_activate_command_prereq( const char* name, const char *prereq );
00313
00314 int hook_compare(const void* hook1, const void* hook2);
00315 void hook_copy( CounterHookDefinition *source, CounterHookDefinition *dest);
00316 void hooklists_log(void);
00317 int hook_parse_specifier( CounterHookDefinition *hook, const char **specifier );
00318 void hook_print_to_str( CounterHookDefinition *hook, char *hooklistname, char *str, size_t nchars);
00319 void hooklists_sort(HooklistNum hooklist);
00320
00321 int param_check( const ParamInterface* param, const void * valueptr);
00322 int param_compare(const void* param1, const void* param2);
00323 const char *param_pp_boolean(int value);
00324 const char *param_pp_float(float value);
00325 const char *param_pp_int(int value);
00326 const char *param_pp_scalar(const ParamInterface* def, void *value);
00327 int param_print_range(FILE *fp, ParamInterface* param);
00328 int param_print_type(FILE *fp, ParamInterface* param);
00329 int param_print_usage(FILE *fp, ParamInterface* param);
00330 int param_print_value(FILE *fp, ParamInterface* param);
00331 void params_sort(void);
00332
00333
00334 #ifndef NO_SIGNAL_HANDLING
00335 void command_exec_sigint_handler( int sig );
00336 #endif
00337
00338
00339
00340
00341
00346 void cmdparam_init_hook( void )
00347 {
00348 ipc_init_hook();
00349
00350
00351
00352 CMD_DOC(clear_hooks,NULL,0,"%s [<hook_list>]*",
00353 "Delete all the currently-defined hooks in the given list(s), or delete\n"
00354 "all hooks in all lists if no lists are specified.");
00355
00356 CMD_DOC(define_param,NULL,2,"%s <name> <type> [<lowbound> [<highbound> [<helpstring>] [<initialvalue>]]]",
00357 "Define a new parameter of the given type. Space for the parameter is\n"
00358 "immediately allocated from the heap, but it is not initialized until\n"
00359 "the parameter is set unless an initial value is supplied. The type name\n"
00360 "should be prefixed with Param_, e.g. Param_Integer,Param_Float,Param_Boolean,\n"
00361 "or Param_String. Calling this command multiple times for the same name is not\n"
00362 "an error unless the type differs, but the bounds, helpstring, and initialvalue\n"
00363 "are only installed on the first call.");
00364
00365 CMD_DOC(dotimes,NULL,2,"%s <expr> <command> [<argument>]*",
00366 "Execute the given command with the given arguments, the number of times\n"
00367 "specified by the given numeric expression.");
00368
00369 CMD_DOC(for,NULL,8,"%s <param>=<initvalue> <test-expr> <param>=<incrementvalue> <command> [<argument>]*",
00370 "Execute the given command with the given arguments a number of times.\n"
00371 "First, the first param-value pair is passed to the set command, then as\n"
00372 "long as the numeric <test-expr> evaluates to a true value, the given command\n"
00373 "is executed and the second param-value pair is passed to the set command.\n"
00374 "Example: `define_param angle Param_Integer', then\n"
00375 "`for angle=0 angle<180 angle=angle+10 print angle'.");
00376
00377 CMD_DOC(if,NULL,2,"%s <expr> <command> [<argument>]*",
00378 "If the given numeric expression evaluates to a non-zero value, execute\n"
00379 "the given command with the given arguments.");
00380
00381 CMD_DOC(call,NULL,1,"%s <filename> [<param>=<value>]*",
00382 "Same as exec_file, but suppresses verbose parameter change and other messages.\n"
00383 "This is intended for calling a file as a procedure; only error reporting is\n"
00384 "usually desired since the file may contain a long loop or may call other files\n"
00385 "repeatedly.");
00386
00387 CMD_DOC(exec_file,NULL,1,"%s <filename> [<param>=<value>]*",
00388 "Execute the given command file. The parameter settings included on the\n"
00389 "command line will be saved but not evaluated until the next call to the\n"
00390 "read_args command, which will presumably be from inside the command file.\n"
00391 "See the help for read_args.");
00392
00393 CMD_DOC(exec,NULL,1,"%s [<command-string>]*",
00394 "Execute the commands specified by the given strings, in order. Before being\n"
00395 "executed, each string is interpreted for string substitutions as for the set\n"
00396 "command for string parameters, so it's possible to use constructions like\n"
00397 "`exec \"${command}\" \"set x=y\"'.");
00398
00399 CMD_DOC(print,NULL,1,"%s <expression>*",
00400 "Displays the value of the given expression(s), which can either be the name of\n"
00401 "any parameter, preceded by a dollar sign (`$'), or an arbitrary numeric\n"
00402 "expression allowed as a <value> by the set command. Examples: \n"
00403 "`print $filename', `print 2*radius-1'.");
00404
00405 CMD_DOC(read_args,NULL,0,"%s",
00406 "If called within a file executed using the exec_file command, evaluates (using\n"
00407 "the set command) the parameter values defined by that call. This provides\n"
00408 "a rudimentary form of argument passing to allow command files to be used like\n"
00409 "procedures. Trivial example (e.g. in a file named `countup.command'):\n\n"
00410
00411 " define_param n Param_Integer # Declare argument(s)\n"
00412 " set n=10 # Default value\n"
00413 " read_args # Read argument(s)\n\n"
00414
00415 " define_param i Param_Integer # Declare global variable to be used as a local\n"
00416 " for i=0 i<n i=i+1 print i # Actually do something\n\n"
00417
00418 "If this file is called as `exec_file countup.command n=5', it will print\n"
00419 "out the numbers less than 5 (amidst various \"helpful\" debugging messages).\n"
00420 "Of course, since all parameters are currently globals, be careful\n"
00421 "not to assume the procedures act like safer ones offered by a more powerful\n"
00422 "language.");
00423
00424 CMD_DOC(save_params,NULL,1,"%s <filename>",
00425 "Save current values of parameters and currently-defined hooks in a format\n"
00426 "suitable for exec_file.");
00427
00428 CMD_DEFINE_CATCHUP(3,set,"%s <name>=<value> [<name>=<value>]*",
00429 "Allows any parameter to be set to an arbitrary value, within the type\n"
00430 "and range of that parameter. It can accept multiple pairs of names and\n"
00431 "values as long as the CMD_MAX_ARGUMENTS limit is not reached. Values\n"
00432 "may not contain spaces unless they are enclosed in quotes.\n\n"
00433
00434 "The <value> for a parameter of String type may contain references to\n"
00435 "other parameters if preceded by a dollar sign (`$') and (optionally)\n"
00436 "enclosed in braces. Non-string parameter values are printed to a\n"
00437 "simple string representation. Example: `set filename=\n"
00438 "${filename}_${angle}_A' might set it to `oldname_76.5_A'.\n\n"
00439
00440 "The <value> for numeric types (Integer, Float, and Boolean) may be an\n"
00441 "expression matching the following (recursive) grammar:\n\n"
00442
00443 " <term> == <number>|<paramname>|(<value>)\n\n"
00444 " <value> == <term>[+|-|>|<|<?|>?|*|/|%<value>]\n\n"
00445
00446 "Thus a literal numeric value will suffice, or else an infix arithmetic\n"
00447 "expression like `RN' or `i/2' or `RN/2.5*(N-1)' or `RN%8' can be used,\n"
00448 "where i, RN, and N are parameters whose current value will be substituted\n"
00449 "before evaluation. The >? and <? operators are borrowed from GNU C++;\n"
00450 "they take the maximum and the minimum of their arguments, respectively.\n"
00451 "The rest of the arguments are defined as in ANSI C, except as noted below.\n\n"
00452
00453 "The `*', `/', and `%%' operators are equal in precedence and are greater\n"
00454 "in precedence than all the others; otherwise evaluation occurs from left\n"
00455 "to right. Thus simple arithmetic expressions will have the same\n"
00456 "interpretation as in C, but parentheses should be used liberally on\n"
00457 "anything complicated (particularly for comparisons) to ensure that they\n"
00458 "are calculated correctly.\n\n"
00459
00460 "All intermediate numeric results are of type double (or long double,\n"
00461 "if available), which is then rounded (not truncated) to an integer.\n"
00462 "Thus expression values involving e.g. integer division may differ from\n"
00463 "their C equivalents, but this is usually an improvement.\n\n"
00464
00465 "Boolean variables have numeric types, but the symbolic values True,\n"
00466 "False, Yes, No, and Uninitialized are accepted as standing for 1,0,1,0,\n"
00467 "and -1, respectively. Boolean expressions like ((x<0)||(x>N))&&C can be\n"
00468 "computed by writing their arithmetic equivalent, e.g. `((x<0)+(x>N))*C',\n"
00469 "as long as none of the Boolean variables are Uninitialized.");
00470
00471 CMD_DOC(system,NULL,1,"%s <shell-command> [<shell-command-arg>]*",
00472 "Execute the given system shell command (e.g. `ls -l file'). Arguments\n"
00473 "which require quoting should be enclosed in single quotes surrounded by\n"
00474 "double quotes, e.g. `ls -l \"'file with spaces'\"', or vice versa.\n"
00475 "Parameter values may be used in arguments if preceded by a dollar sign, as\n"
00476 "for string parameters in the `set' command. Consequently, shell variables\n"
00477 "cannot be used in arguments; if this were to present a problem, \n"
00478 "the system command (or cmdi) could be rewritten to suppress variable\n"
00479 "substitution if it detects embedded single quotes.");
00480
00481 CMD_DOC(quit,NULL,0,"%s [<exit-message>]",
00482 "Exit from the program with no error condition.");
00483
00484 CMD_DEFINE_CATCHUP(3,hook,"%s <hook_list> <counter_specifier> <command> [<argument>]*",
00485 "This command allows you to specify that the given command should be\n"
00486 "executed at location <hook_list> when a counter reaches the value\n"
00487 "specified by the <counter_specifier>, where the <counter_specifier>\n"
00488 "is of the (recursive) form:\n\n"
00489
00490 " <counter_start>[-<counter_end>[%<step>]][,<counter_specifier>]\n\n"
00491
00492 "For example, the <counter_specifier> can be\n"
00493 "a single value ((e.g. 1000), a range of values (e.g. 1-1000), a\n"
00494 "range with a stepsize (e.g. 1-1000%%10), or a list of any of these\n"
00495 "(e.g. 1,10,100-200%%20,7,50-60).\n\n"
00496
00497 "For a given hook_list and counter value, all the hooks that apply\n"
00498 "are executed in the order of their counter_start and (if those\n"
00499 "match) the order in which they were defined.");
00500
00501
00502
00503 CONST_F(PI, M_PI, False,"Symbol representing PI.");
00504 CONST_B(True, True, False,"Symbol representing Boolean `True'.");
00505 CONST_B(False, False, False,"Symbol representing Boolean `False'.");
00506 CONST_B(Yes, True, False,"Symbol representing Boolean `True'.");
00507 CONST_B(No, False, False,"Symbol representing Boolean `False'.");
00508 CONST_I(Uninitialized,Uninitialized,False,"Symbol representing an uninitialized or default value.");
00509 CONST_I(MaxInt, INT_MAX-1, False,"Symbol representing the maximum integer value.");
00510 CONST_I(MinInt, INT_MIN+1, False,"Symbol representing the minimum integer value.");
00511
00512
00513 CONST_I(Param_String, PARAM_STRING,False,"Symbol representing the string parameter type.");
00514 CONST_I(Param_Boolean, PARAM_BOOL, False,"Symbol representing the Boolean parameter type.");
00515 CONST_I(Param_Integer, PARAM_INT, False,"Symbol representing the integer parameter type.");
00516 CONST_I(Param_Float, PARAM_DOUBLE,False,"Symbol representing the floating-point parameter type.");
00517
00518 PARAM_I(PARAM_STRING,commandpath,1,CMD_MAX_LINE_LENGTH,
00519 "Space-separated list of paths to search for command files. The current\n"
00520 "directory is always searched first.");
00521
00522
00523 params_sort();
00524 cmddefs_sort();
00525 cmddefs_activate_prereqs();
00526
00527
00528 }
00529
00530
00531
00536 void ipc_init_hook( void )
00537 {
00538 PARAM_I(PARAM_INT, ipc_msg_level, IPC_NONE,IPC_OVERWHELM, ipc_msg_level_docstring);
00539 PARAM_I(PARAM_INT, ipc_msg_forceall_level, IPC_NONE,IPC_OVERWHELM, ipc_msg_forceall_level_docstring);
00540 PARAM_I(PARAM_INT, ipc_msg_synch_level, IPC_NONE,IPC_OVERWHELM, ipc_msg_synch_level_docstring);
00541 PARAM_L(PARAM_INT, ipc_exit_on_error_num,0, ipc_exit_on_error_num_docstring);
00542 PARAM_L(PARAM_INT, ipc_max_warnings,0, ipc_max_warnings_docstring);
00543 PARAM_L(PARAM_INT, ipc_max_errors,0, ipc_max_errors_docstring);
00544
00545 CONST_I(IPC_None, IPC_NONE, False,
00546 "Symbol representing `no message'. Ordinarily, no message should be declared\n"
00547 "with a level this high, and then this level may be used to turn off all\n"
00548 "messages.");
00549
00550 CONST_I(IPC_Error, IPC_ERROR, False,
00551 "Symbol representing `error message'. It should be used for a fairly serious\n"
00552 "problem, e.g. one which causes the current computation to be aborted.");
00553
00554 CONST_I(IPC_Warning, IPC_WARNING, False,
00555 "Symbol representing `warning message'. It should be used for a condition\n"
00556 "that is clearly bad but which won't stop computation from proceeding, e.g.\n"
00557 "if a meaningful default value can be used in place of an out-of-range\n"
00558 "parameter.");
00559
00560 CONST_I(IPC_Caution, IPC_CAUTION, False,
00561 "Symbol representing `caution message'. It should be used for a condition that\n"
00562 "is probably bad but which is common enough not to be worth tabulating in total\n"
00563 "warning counts.");
00564
00565 CONST_I(IPC_Alert, IPC_ALERT, False,
00566 "Symbol representing `alert message'. It is primarily a placeholder, marking\n"
00567 "all higher message levels as being in the `alert' category instead of merely\n"
00568 "informational. It may also be used for any particularly important message\n"
00569 "which should almost never be suppressed.");
00570
00571 CONST_I(IPC_Summary, IPC_SUMMARY, False,
00572 "Symbol representing `summary message'. It should be used for messages that\n"
00573 "are particularly important but which do not report an anomalous condition.");
00574
00575 CONST_I(IPC_Std, IPC_STD, False,
00576 "Symbol representing `standard message'. It should be used for messages that\n"
00577 "a user will probably want to see for every run.");
00578
00579 CONST_I(IPC_Verbose, IPC_VERBOSE, False,
00580 "Symbol representing `verbose message'. It should be used for messages which\n"
00581 "a user will probably want to see only when requested.");
00582
00583 CONST_I(IPC_Overwhelm, IPC_OVERWHELM,False,
00584 "Symbol representing `overwhelming amount of messages'. It should be used\n"
00585 "for debugging messages and similar trivia that may generate a lot of output.");
00586 }
00587
00588
00589
00590
00591
00592
00593
00598 int params_define_param(const char *name, int type, int is_constant, void *pointer)
00599 {
00600 const ParamInterface* existing = params_lookup(name, strlen(name));
00601
00602 if (existing) {
00603 if (existing->data_type != type)
00604 ipc_notify(IPC_ALL,IPC_ERROR,"Parameter %s already exists with a different type; can't redefine it",name);
00605 else if (existing->is_constant != is_constant)
00606 ipc_notify(IPC_ALL,IPC_ERROR,"%s is constant; can't redefine it",name);
00607 else {
00608
00609 return 2;
00610 }
00611 }
00612 else if (blackboard.num >= PARAM_MAX_ENTRIES)
00613 ipc_notify(IPC_ALL,IPC_WARNING,"Blackboard is full; can't add entry for %s",name);
00614 else if (strlen(name)!=cmdparam_identifier_length(name))
00615 ipc_notify(IPC_ALL,IPC_WARNING,"Invalid characters in parameter name %s; can't define it",name);
00616 else {
00617 ParamInterface* param=&(blackboard.list[blackboard.num]);
00618
00619 strncpy(param->name, name,PARAM_MAX_NAME_LENGTH);
00620 param->data_type = type;
00621 param->is_constant = is_constant;
00622 param->enforce_upper = False;
00623 param->enforce_lower = False;
00624 param->setfn = NULL;
00625 param->been_set = False;
00626 param->default_expr = NULL;
00627
00628 switch(type){
00629 case PARAM_STRING: param->data_ptr.c = (char*)pointer; break;
00630 case PARAM_BOOL:
00631 case PARAM_INT: param->data_ptr.i = (int*)pointer; break;
00632 case PARAM_DOUBLE: param->data_ptr.f = (double*)pointer; break;
00633 default:
00634 ipc_notify(IPC_ONE,IPC_ERROR,"Unknown datatype %d; can't define param",type);
00635 return 0;
00636 }
00637 blackboard.num++;
00638
00639 return 1;
00640 }
00641
00642 return 0;
00643 }
00644
00645
00646
00652 void params_add_lower_bound_int(const char *name, int lower_bound)
00653 {
00654 int idx = 0;
00655 int changed = False;
00656
00657
00658 for (idx=blackboard.num-1; !changed && idx >= 0; idx--)
00659 if (strncmp(name,blackboard.list[idx].name,PARAM_MAX_NAME_LENGTH) == 0)
00660 switch(blackboard.list[idx].data_type) {
00661
00662 case PARAM_STRING:
00663 case PARAM_BOOL:
00664 case PARAM_INT:
00665 blackboard.list[idx].lower_bound.i = lower_bound;
00666 blackboard.list[idx].enforce_lower = True;
00667 changed = True;
00668 break;
00669
00670 case PARAM_DOUBLE:
00671 blackboard.list[idx].lower_bound.f = lower_bound;
00672 blackboard.list[idx].enforce_lower = True;
00673 changed = True;
00674 break;
00675 }
00676
00677 if (!changed)
00678 ipc_notify(IPC_ONE,IPC_ERROR,"Failed to add lower bound to parameter %s",name);
00679 }
00680
00681
00682
00688 void params_add_upper_bound_int(const char *name, int upper_bound)
00689 {
00690 int idx = 0;
00691 int changed = False;
00692
00693
00694 for (idx=blackboard.num-1; !changed && idx >= 0; idx--)
00695 if (strncmp(name,blackboard.list[idx].name,PARAM_MAX_NAME_LENGTH) == 0)
00696 switch(blackboard.list[idx].data_type) {
00697
00698 case PARAM_STRING:
00699 case PARAM_BOOL:
00700 case PARAM_INT:
00701 blackboard.list[idx].upper_bound.i = upper_bound;
00702 blackboard.list[idx].enforce_upper = True;
00703 changed = True;
00704 break;
00705
00706 case PARAM_DOUBLE:
00707 blackboard.list[idx].upper_bound.f = upper_bound;
00708 blackboard.list[idx].enforce_upper = True;
00709 changed = True;
00710 break;
00711 }
00712
00713 if (!changed)
00714 ipc_notify(IPC_ONE,IPC_ERROR,"Failed to add upper bound to parameter %s",name);
00715 }
00716
00717
00718
00726 void params_define_default_expr(const char *name, const char *expr)
00727 {
00728 int idx = 0;
00729 int changed = False;
00730
00731
00732 for (idx=blackboard.num-1; !changed && idx >= 0; idx--)
00733 if (strncmp(name,blackboard.list[idx].name,PARAM_MAX_NAME_LENGTH) == 0) {
00734 blackboard.list[idx].default_expr = expr;
00735 changed = True;
00736 }
00737
00738 if (!changed)
00739 ipc_notify(IPC_ONE,IPC_ERROR,"Failed to add default expression to parameter %s",name);
00740 }
00741
00742
00743
00749 void params_update_default_value(int idx)
00750 {
00751 ParamInterface* param = &(blackboard.list[idx]);
00752 if (!param->been_set && param->default_expr) {
00753 cmdparam_set( param->name, param->default_expr );
00754
00755 param->been_set = False;
00756 }
00757 }
00758
00759
00760
00762 void params_update_default_value(const char* name)
00763 {
00764 int idx;
00765 int changed=False;
00766
00767 for (idx=blackboard.num-1; !changed && idx >= 0; idx--)
00768 if (strncmp(name,blackboard.list[idx].name,PARAM_MAX_NAME_LENGTH) == 0) {
00769 params_update_default_value(idx);
00770 changed = True;
00771 }
00772
00773 if (!changed)
00774 ipc_notify(IPC_ONE,IPC_ERROR,"Can't find parameter %s to update its default value",name);
00775 }
00776
00777
00778
00780 void params_update_all_default_values( void )
00781 {
00782 for (int idx=0; idx<blackboard.num; idx++)
00783 params_update_default_value(idx);
00784 }
00785
00786
00787
00792 int param_check( const ParamInterface* param, const void * valueptr)
00793 {
00794 switch(param->data_type) {
00795
00796 case PARAM_STRING:
00797 {
00798 int value = strlen((const char *)valueptr);
00799
00800 if ( param->enforce_lower && value < param->lower_bound.i ) {
00801 ipc_notify(IPC_ONE,IPC_ERROR,"%s too short (%d < %d)",param->name,value,param->lower_bound.i);
00802 return 1;
00803 }
00804 if ( param->enforce_upper && value > param->upper_bound.i ) {
00805 ipc_notify(IPC_ONE,IPC_ERROR,"%s too long (%d > %d)", param->name,value,param->upper_bound.i);
00806 return 1;
00807 }
00808 return 0;
00809 }
00810
00811
00812 case PARAM_BOOL:
00813 {
00814 int value = *((const int *)valueptr);
00815
00816 if ( (param->enforce_lower && value < param->lower_bound.i) ||
00817 (param->enforce_upper && value > param->upper_bound.i) ) {
00818 ipc_notify(IPC_ONE,IPC_ERROR,"%s is invalid (%d)",param->name,value);
00819 return 1;
00820 }
00821 return 0;
00822 }
00823
00824
00825 case PARAM_INT:
00826 {
00827 int value = *((const int *)valueptr);
00828
00829 if ( param->enforce_lower && value < param->lower_bound.i ) {
00830 ipc_notify(IPC_ONE,IPC_ERROR,"%s too small (%s < %d)",param->name,
00831 param_pp_int(value),(int)(param->lower_bound.i));
00832 return 1;
00833 }
00834 if ( param->enforce_upper && value > param->upper_bound.i ) {
00835 ipc_notify(IPC_ONE,IPC_ERROR,"%s too large (%s > %d)",param->name,
00836 param_pp_int(value),(int)(param->upper_bound.i));
00837 return 1;
00838 }
00839 return 0;
00840 }
00841
00842
00843 case PARAM_DOUBLE:
00844 {
00845 double value = *((const double *)valueptr);
00846
00847 if ( param->enforce_lower && value < param->lower_bound.f ) {
00848 ipc_notify(IPC_ONE,IPC_ERROR,"%s too small (%s < %g)",param->name,
00849 param_pp_float(value),(double)(param->lower_bound.f));
00850 return 1;
00851 }
00852 if ( param->enforce_upper && value > param->upper_bound.f ) {
00853 ipc_notify(IPC_ONE,IPC_ERROR,"%s too large (%s > %g)",param->name,
00854 param_pp_float(value),(double)(param->upper_bound.f));
00855 return 1;
00856 }
00857 return 0;
00858 }
00859
00860 default:
00861 ipc_notify(IPC_ONE,IPC_WARNING,"Datatype of %s unknown; can't check bounds",param->name);
00862 return 0;
00863 }
00864 }
00865
00866
00867
00874 void params_define_doc( const char* name, const char *doc )
00875 {
00876 int idx = 0;
00877 int changed = False;
00878
00879
00880 for (idx=blackboard.num-1; !changed && idx >= 0; idx--)
00881 if (strncmp(name,blackboard.list[idx].name,PARAM_MAX_NAME_LENGTH) == 0) {
00882 blackboard.list[idx].doc = doc;
00883 changed = True;
00884 }
00885
00886 if (!changed)
00887 ipc_notify(IPC_ONE,IPC_ERROR,"Failed to add documentation to param %s",name);
00888 }
00889
00890
00891
00893 void params_define_setfn( const char* name, SetFnWrapper* setfn )
00894 {
00895 int idx = 0;
00896 int changed = False;
00897
00898
00899 for (idx=blackboard.num-1; !changed && idx >= 0; idx--)
00900 if (strncmp(name,blackboard.list[idx].name,PARAM_MAX_NAME_LENGTH) == 0) {
00901 blackboard.list[idx].setfn = setfn;
00902 changed = True;
00903 }
00904
00905 if (!changed)
00906 ipc_notify(IPC_ONE,IPC_ERROR,"Failed to add setting function to param %s",name);
00907 }
00908
00909
00910
00914 int params_check_all( void )
00915 {
00916 int idx, numerrors=0;
00917
00918 for (idx=0; idx < blackboard.num; idx++)
00919 numerrors += param_check( &(blackboard.list[idx]),
00920 (void *)(blackboard.list[idx].data_ptr.i) );
00921 return numerrors;
00922 }
00923
00924
00925
00926
00928 int params_num_total(void)
00929 { return blackboard.num; }
00930
00931
00932
00937 int params_print_to_str( int number, char *str, size_t nchars)
00938 {
00939 char *str_ptr=str;
00940 size_t charsleft=nchars-1;
00941 ParamInterface* param;
00942
00943 if (number >= blackboard.num) {
00944 ipc_notify(IPC_ONE,IPC_ERROR,"Unknown parameter number: %d",number);
00945 return 0;
00946 }
00947 param = &(blackboard.list[number]);
00948
00949 snprintf(str_ptr,charsleft,"set %s=",param->name);
00950 charsleft -= strlen(str_ptr);
00951 str_ptr += strlen(str_ptr);
00952
00953 if (param->data_type == PARAM_STRING)
00954 snprintf(str_ptr,charsleft,"\"%s\"", (param->data_ptr.c));
00955 else
00956 snprintf(str_ptr,charsleft,"%s", param_pp_scalar(param, param->data_ptr.i));
00957
00958 return 1;
00959 }
00960
00961
00962
00964 void params_log(void)
00965 {
00966 int i;
00967 char buf[CMD_MAX_LINE_LENGTH];
00968
00969 for(i=0; i< blackboard.num; i++)
00970 if (params_print_to_str( i, buf, CMD_MAX_LINE_LENGTH))
00971 ipc_log(IPC_ALL,"%s\n",buf);
00972
00973 ipc_log(IPC_ALL,"\n");
00974
00975 hooklists_log();
00976 }
00977
00978
00980 void params_sort(void)
00981 {
00982 qsort(blackboard.list,
00983 blackboard.num,
00984 sizeof(ParamInterface),
00985 param_compare);
00986 }
00987
00988
00989
00991 int param_compare(const void* param1, const void* param2)
00992 {
00993 return( strncasecmp(((const ParamInterface*)param1)->name,
00994 ((const ParamInterface*)param2)->name,
00995 CMDDEF_MAX_NAME_LENGTH) );
00996 }
00997
00998
00999
01001 void params_print_all(FILE *fp)
01002 {
01003 int i;
01004 for(i=0; i< blackboard.num; i++){
01005 param_print_usage(fp,&(blackboard.list[i]));
01006 fprintf(fp,"\n");
01007 }
01008 }
01009
01010
01011
01013 void params_print_parameters(FILE *fp)
01014 {
01015 int i;
01016 for(i=0; i< blackboard.num; i++)
01017 if (!blackboard.list[i].is_constant) {
01018 param_print_usage(fp,&(blackboard.list[i]));
01019 fprintf(fp,"\n");
01020 }
01021 }
01022
01023
01024
01026 void params_print_constants(FILE *fp)
01027 {
01028 int i;
01029 for(i=0; i< blackboard.num; i++)
01030 if (blackboard.list[i].is_constant) {
01031 param_print_usage(fp,&(blackboard.list[i]));
01032 fprintf(fp,"\n");
01033 }
01034 }
01035
01036
01037
01038 const char *param_pp_boolean(int value)
01039 {
01040 if (value == Uninitialized)
01041 return "Uninitialized";
01042 else if (value)
01043 return "True";
01044 else return "False";
01045 }
01046
01047
01048
01049 const char *param_pp_int(int value)
01050 {
01051 static char buf[20];
01052
01053 if (value == Uninitialized)
01054 return "Uninitialized";
01055
01056 snprintf(buf,20,"%d",value);
01057 return buf;
01058 }
01059
01060
01061
01062 const char *param_pp_float(float value)
01063 {
01064 static char buf[20];
01065
01066 if (value == Uninitialized)
01067 return "Uninitialized";
01068
01069 snprintf(buf,20,"%g",value);
01070 return buf;
01071 }
01072
01073
01074
01075 const char *param_pp_scalar(const ParamInterface* def, void *value)
01076 {
01077 switch(def->data_type){
01078 case PARAM_BOOL : return param_pp_boolean( *(int *)value);
01079 case PARAM_INT : return param_pp_int( *(int *)value);
01080 case PARAM_DOUBLE: return param_pp_float(*(double *)value);
01081 default:
01082 ipc_notify(IPC_ONE,IPC_WARNING,"Datatype of %s unknown; can't print value",def->name);
01083 }
01084 return "";
01085 }
01086
01087
01088
01089 int param_print_value(FILE *fp, ParamInterface* param)
01090 {
01091 int pos=0;
01092
01093 if (param->data_type == PARAM_STRING)
01094 pos += fprintf(fp,"\"%s\"", (param->data_ptr.c));
01095 else
01096 pos += fprintf(fp,"%s", param_pp_scalar(param, param->data_ptr.i));
01097
01098 return pos;
01099 }
01100
01101
01102
01103 int param_print_type(FILE *fp, ParamInterface* param)
01104 {
01105 int pos=0;
01106
01107 switch(param->data_type){
01108 case PARAM_STRING: pos += fprintf(fp,"String"); break;
01109 case PARAM_BOOL : pos += fprintf(fp,"Boolean"); break;
01110 case PARAM_INT : pos += fprintf(fp,"Integer"); break;
01111 case PARAM_DOUBLE: pos += fprintf(fp,"Float"); break;
01112 default:
01113 ipc_notify(IPC_ONE,IPC_WARNING,"Datatype of %s unknown; can't print type",param->name);
01114 }
01115
01116 return pos;
01117 }
01118
01119
01120 int param_print_range(FILE *fp, ParamInterface* param)
01121 {
01122 int pos=0;
01123
01124 pos += fprintf(fp,"[");
01125 if (param->enforce_lower) {
01126 if (param->data_type == PARAM_STRING)
01127 pos += fprintf(fp,"%d",param->lower_bound.i);
01128 else
01129 pos += fprintf(fp,"%s", param_pp_scalar(param, &(param->lower_bound)));
01130 }
01131 else
01132 pos += fprintf(fp,"*");
01133
01134 pos += fprintf(fp,",");
01135
01136 if (param->enforce_upper) {
01137 if (param->data_type == PARAM_STRING)
01138 pos += fprintf(fp,"%d",param->upper_bound.i);
01139 else
01140 pos += fprintf(fp,"%s", param_pp_scalar(param, &(param->upper_bound)));
01141 }
01142 else
01143 pos += fprintf(fp,"*");
01144
01145 pos += fprintf(fp,"]");
01146
01147 return pos;
01148 }
01149
01150
01151
01152 int param_print_usage(FILE *fp, ParamInterface* param)
01153 {
01154 int pos=0;
01155
01156 pos += fprintf(fp,"%s=",param->name);
01157 pos += param_print_value(fp,param);
01158
01159 pos += fprintf(fp,"%*s(",MAX(0,39-pos)," ");
01160 pos += param_print_type(fp,param);
01161
01162 if (param->is_constant)
01163 pos += fprintf(fp," constant");
01164 else
01165 if (param->enforce_lower || param->enforce_upper) {
01166 pos += fprintf(fp," with %srange ",
01167 (param->data_type==PARAM_STRING ? "length " : ""));
01168 pos += param_print_range(fp,param);
01169 }
01170
01171 pos += fprintf(fp,")");
01172
01173 return pos;
01174 }
01175
01176
01177
01178 void params_print_doc_for_index(FILE *fp, int idx)
01179 {
01180 ParamInterface* param = &(blackboard.list[idx]);
01181
01182 param_print_usage(fp,param);
01183 fprintf(fp,"\n");
01184
01185 if (param->doc) {
01186 fprintf(fp,"\n");
01187 fprintf(fp,param->doc,param->name);
01188 fprintf(fp,"\n");
01189 }
01190 }
01191
01192
01193
01194 int params_is_constant(int idx)
01195 {
01196 return blackboard.list[idx].is_constant;
01197 }
01198
01199
01200
01202 void params_print_doc(FILE *fp, const char* name)
01203 {
01204 int idx = 0;
01205 int found = False;
01206
01207 for (idx=blackboard.num-1; !found && idx >= 0; idx--)
01208 if (strncmp(name,blackboard.list[idx].name,PARAM_MAX_NAME_LENGTH) == 0) {
01209 params_print_doc_for_index(fp,idx);
01210 found = True;
01211 }
01212
01213 if (!found)
01214 ipc_notify(IPC_ONE,IPC_ERROR,"Don't know anything about parameter %s",name);
01215 }
01216
01217
01218
01219 void params_print_constants_doc(FILE *file)
01220 {
01221 int i;
01222 fprintf(file,cmdparam_help_separator);
01223 for (i=0; i< params_num_total(); i++)
01224 if (params_is_constant(i)) {
01225 params_print_doc_for_index(file,i);
01226 fprintf(file,cmdparam_help_separator);
01227 fprintf(file,"\n");
01228 }
01229 }
01230
01231
01232
01233 void params_print_parameters_doc(FILE *file)
01234 {
01235 int i;
01236 fprintf(file,cmdparam_help_separator);
01237 for (i=0; i< params_num_total(); i++)
01238 if (!params_is_constant(i)) {
01239 params_print_doc_for_index(file,i);
01240 fprintf(file,cmdparam_help_separator);
01241 fprintf(file,"\n");
01242 }
01243 }
01244
01245
01246
01253 char* params_completion_generator (char *text, int state)
01254 {
01255 static int idx, len;
01256 char *name;
01257
01258 01259 01260 01261
01262 if (!state) {
01263 idx = 0;
01264 len = strlen(text);
01265 }
01266
01267
01268 while (idx < blackboard.num) {
01269 name = blackboard.list[idx++].name;
01270 if (strncmp (name, text, len) == 0)
01271 return (cmdparam_dupstr(name));
01272 }
01273
01274 return ((char *)NULL);
01275 }
01276
01277
01278
01284 double* params_lookup_double(const char *name)
01285 {
01286 ParamInterface* param = params_lookup(name,strlen(name));
01287
01288 if (param && param->data_type==PARAM_DOUBLE)
01289 return param->data_ptr.f;
01290 else
01291 return NULL;
01292 }
01293
01294
01295
01301 ParamInterface* params_lookup(const char *name, size_t len)
01302 {
01303 int idx=0;
01304
01305
01306 while (idx < blackboard.num &&
01307 (strncmp(name,blackboard.list[idx].name, len) != 0 ||
01308 strlen(blackboard.list[idx].name) != len))
01309 idx++;
01310
01311 return (idx < blackboard.num ? &(blackboard.list[idx]) : NULL);
01312 }
01313
01314
01315
01329 void* params_getval( int* type, const char **remaining )
01330 {
01331 const char* str = *remaining;
01332 int identlen = cmdparam_identifier_length(str);
01333 size_t checklen = MIN(identlen,PARAM_MAX_NAME_LENGTH);
01334
01335 static double numval;
01336 ParamInterface* paramptr;
01337
01338
01339 if (!identlen) {
01340 char *rem;
01341 numval = strtod(str,&rem);
01342 *remaining=rem;
01343
01344 if (str == *remaining) {
01345 ipc_notify(IPC_ONE,IPC_ERROR, "Can't parse expression: `%s'",str);
01346 return NULL;
01347 }
01348 *type=PARAM_DOUBLE;
01349 return &numval;
01350 }
01351
01352
01353 paramptr = params_lookup(str, checklen);
01354 *remaining=str+identlen;
01355 if (paramptr) {
01356 *type = paramptr->data_type;
01357 return paramptr->data_ptr.i;
01358 }
01359 else {
01360
01361 ipc_notify(IPC_ONE,IPC_ERROR,"No parameter or constant %.*s is defined",checklen,str);
01362 *type=PARAM_INT;
01363 return NULL;
01364 }
01365
01366 }
01367
01368
01369
01380 const char *params_getstringval(const char **remaining )
01381 {
01382 const ParamInterface* paramptr;
01383 const char* str = *remaining;
01384 static char buf[CMD_MAX_LINE_LENGTH];
01385
01386 char* bufptr=buf;
01387 int bracefound=False;
01388 int identlen;
01389
01390 while (*remaining && **remaining && (bufptr-buf < CMD_MAX_LINE_LENGTH)) {
01391 while (**remaining && **remaining != '$' && (bufptr-buf < CMD_MAX_LINE_LENGTH))
01392 *(bufptr++) = *(*remaining)++;
01393
01394 if (**remaining == '$') {
01395 (*remaining)++;
01396 if (**remaining == '$')
01397 *(bufptr++) = *(*remaining)++;
01398 else {
01399 if (**remaining == '{') {
01400 bracefound=True;
01401 (*remaining)++;
01402 }
01403 identlen = cmdparam_identifier_length(*remaining);
01404
01405
01406 paramptr = params_lookup(*remaining, identlen);
01407 if (paramptr) {
01408 if (paramptr->data_type == PARAM_STRING)
01409 bufptr += sprintf(bufptr,"%s", paramptr->data_ptr.c);
01410 else
01411 bufptr += sprintf(bufptr,"%s", param_pp_scalar(paramptr, paramptr->data_ptr.i));
01412 }
01413 else
01414 ipc_notify(IPC_ONE,IPC_ERROR,"No parameter or constant %.*s is defined",identlen,*remaining);
01415 *remaining +=identlen;
01416
01417 if (bracefound) {
01418 if (**remaining == '}')
01419 (*remaining)++;
01420 else
01421 ipc_notify(IPC_ONE,IPC_WARNING,"Missing right brace in %s",str);
01422 }
01423 }
01424 }
01425 }
01426 *bufptr='\0';
01427
01428 return buf;
01429 }
01430
01431
01432
01438 exprtype params_getnumericval(const char **remaining )
01439 {
01440 int type;
01441 const void* paramptr;
01442 const char* str = *remaining;
01443
01444 if (**remaining == '(') {
01445 exprtype subexpr;
01446 (*remaining)++;
01447 subexpr=(params_parse_expr(remaining));
01448
01449 if (**remaining != ')')
01450 ipc_notify(IPC_ONE,IPC_ERROR,"Missing right parenthesis");
01451 else
01452 (*remaining)++;
01453 return subexpr;
01454 }
01455
01456 if (**remaining == '-') {
01457 (*remaining)++;
01458 return -1.0*params_next_term(remaining);
01459 }
01460
01461 paramptr = params_getval(&type,remaining);
01462
01463 if (paramptr != NULL)
01464 switch (type) {
01465 case PARAM_BOOL : return (exprtype) *(const int*)paramptr;
01466 case PARAM_INT : return (exprtype) *(const int*)paramptr;
01467 case PARAM_DOUBLE: return (exprtype) *(const double*)paramptr;
01468 default:
01469 ipc_notify(IPC_ONE,IPC_ERROR,"Invalid param type in expression `%s'",str);
01470 }
01471
01472 return Uninitialized;
01473 }
01474
01475
01477 exprtype params_apply_op(exprtype lval, string op, exprtype rval)
01478 {
01479 if (op == "+") return lval + rval;
01480 else if (op == "-") return lval - rval;
01481 else if (op == "*") return lval * rval;
01482 else if (op == "<") return lval < rval;
01483 else if (op == ">") return lval > rval;
01484
01485 01486 01487 01488 01489 01490
01491 01492 01493 01494 01495 01496
01497
01498 else if (op == "<?") return MIN(lval,rval);
01499 else if (op == ">?") return MAX(lval,rval);
01500
01501 else if (op == "%" || op == "/") {
01502 if (rval==0) {
01503 ipc_notify(IPC_ONE,IPC_ERROR,"Division by zero");
01504 return Uninitialized;
01505 }
01506 if (op == "/") return lval / rval;
01507 else return fmod(lval,rval);
01508 }
01509
01510 ipc_notify(IPC_ONE,IPC_ERROR,"Unknown operator %s",op.c_str());
01511 return Uninitialized;
01512 }
01513
01514
01515 int params_op_has_precedence(const string& previous_op, const string& op)
01516 {
01517 (void) previous_op;
01518
01519 return (op=="*" || op=="/" | op=="%");
01520 }
01521
01522
01523 string params_next_op(const char **remaining)
01524 {
01525 const char* start=*remaining;
01526
01527 while (ispunct(**remaining) && !(**remaining=='('))
01528 (*remaining)++;
01529
01530 const char* end=*remaining;
01531
01532 return string(start,end-start);
01533 }
01534
01535
01536
01537 exprtype params_next_term(const char **remaining, string previous_op)
01538 {
01539 exprtype lval = params_getnumericval(remaining);
01540 string op = params_next_op(remaining);
01541
01542
01543 while (params_op_has_precedence(previous_op, op)) {
01544 if (! **remaining) {
01545 ipc_notify(IPC_ONE,IPC_ERROR,"Missing right value in `%s'",*remaining);
01546 return lval;
01547 }
01548 lval=params_apply_op(lval,op,params_getnumericval(remaining));
01549 previous_op = op;
01550 op = params_next_op(remaining);
01551 }
01552 *remaining -= op.length();
01553
01554 return lval;
01555 }
01556
01557
01558
01559 exprtype params_parse_expr(const char **remaining)
01560 {
01561 const char* str = *remaining;
01562 exprtype lval = params_next_term(remaining);
01563
01564 while (**remaining && **remaining != ')') {
01565 string op= params_next_op(remaining);
01566
01567 if (! **remaining) {
01568 ipc_notify(IPC_ONE,IPC_ERROR,"Missing right value in `%s'",str);
01569 return lval;
01570 }
01571
01572 lval = params_apply_op(lval,op,params_next_term(remaining,op));
01573 }
01574
01575 return lval;
01576 }
01577
01578
01579
01581 exprtype params_read_float(const char* str)
01582 {
01583 const char* remaining=str;
01584 exprtype val = params_parse_expr(&remaining);
01585
01586 if (str == remaining) {
01587 ipc_notify(IPC_ONE,IPC_ERROR, "No number found in string: `%s'",str);
01588 return Uninitialized;
01589 }
01590
01591 if (*remaining)
01592 ipc_notify(IPC_ONE,IPC_WARNING,
01593 "Trailing characters in expression ignored: `%s'",remaining);
01594 return val;
01595 }
01596
01597
01598
01599
01600
01601
01602
01603
01605 double cmdf(const char* str)
01606 { return (double)params_read_float(str); }
01607
01608
01609
01611 long cmdi(const char* str)
01612 {
01613 exprtype result = params_read_float(str);
01614 if (result >= INT_MAX)
01615 ipc_notify(IPC_ONE,IPC_WARNING,"Value %g greater than integer type can contain (%d); may cause overflow",
01616 (double)result,(int)INT_MAX);
01617
01618 else if (result <= INT_MIN)
01619 ipc_notify(IPC_ONE,IPC_WARNING,"Value %g smaller than integer type can contain (%d); may cause underflow",
01620 (double)result,(int)(INT_MIN));
01621
01622 return (long)ROUND(result);
01623 }
01624
01625
01627 const char* cmds(const char* str)
01628 { return params_getstringval(&str); }
01629
01630
01631
01632
01633
01634
01635
01636
01637
01639 void cmddefs_define_command( const char* name, CmdWrapper* function, int minargs, int exec_for_catchups )
01640 {
01641 if (command_definitions.num >= CMDDEF_MAX_NUM)
01642 ipc_notify(IPC_ONE,IPC_WARNING,"Command blackboard is full; can't add entry for %s",name);
01643 else if (strlen(name)!=cmdparam_identifier_length(name))
01644 ipc_notify(IPC_ALL,IPC_WARNING,"Invalid characters in command name; can't define it");
01645 else if (minargs > CMD_MAX_ARGUMENTS)
01646 ipc_notify(IPC_ONE,IPC_ERROR,"Command %s expects too many arguments (%d > %d); can't define it",
01647 name, minargs,(int)CMD_MAX_ARGUMENTS);
01648 else {
01649 strncpy(command_definitions.list[command_definitions.num].name, name,CMDDEF_MAX_NAME_LENGTH);
01650 command_definitions.list[command_definitions.num].function = function;
01651 command_definitions.list[command_definitions.num].minargs = minargs;
01652 command_definitions.list[command_definitions.num].catchup = exec_for_catchups;
01653 command_definitions.list[command_definitions.num].usage = NULL;
01654 command_definitions.list[command_definitions.num].doc = NULL;
01655 command_definitions.list[command_definitions.num].num_prereqs = 0;
01656 command_definitions.list[command_definitions.num].callstatus = CMD_NEVER_CALLED;
01657 command_definitions.num++;
01658 }
01659 }
01660
01661
01662
01664 void cmddefs_define_command_doc( const char* name, const char *usage, const char *doc )
01665 {
01666 int idx = 0;
01667 int changed = False;
01668
01669
01670 for (idx=command_definitions.num-1; !changed && idx >= 0; idx--)
01671 if (strncmp(name,command_definitions.list[idx].name,CMDDEF_MAX_NAME_LENGTH) == 0) {
01672 command_definitions.list[idx].usage = usage;
01673 command_definitions.list[idx].doc = doc;
01674 changed = True;
01675 }
01676
01677 if (!changed)
01678 ipc_notify(IPC_ONE,IPC_ERROR,"Failed to add documentation to command %s",name);
01679 }
01680
01681
01682
01688 void cmddefs_define_command_prereq( const char* name, const char *prereq )
01689 {
01690 if (!prereq)
01691 return;
01692
01693 if (prereq_storage.num >= CMDDEF_MAX_NUM*CMDDEF_MAX_PREREQS) {
01694 ipc_notify(IPC_ONE,IPC_ERROR,"Prerequisite storage area full; can't add prerequisite %s for command %s",
01695 prereq,name);
01696 return;
01697 }
01698
01699 prereq_storage.names[prereq_storage.num]=name;
01700 prereq_storage.prereqs[prereq_storage.num]=prereq;
01701 prereq_storage.num++;
01702 }
01703
01704
01705
01713 void cmddefs_declare_prereq_status( const char * name, cmdstat status )
01714 {
01715 CommandDefinition* def=cmddefs_lookup(name);
01716 if (def) def->callstatus = status;
01717 }
01718
01719
01720
01721 void cmddefs_activate_prereqs( void )
01722 {
01723 int i;
01724
01725 for (i=0; i< prereq_storage.num; i++)
01726 cmddefs_activate_command_prereq(prereq_storage.names[i],prereq_storage.prereqs[i]);
01727 }
01728
01729
01730
01735 void cmddefs_activate_command_prereq( const char* name, const char *prereq )
01736 {
01737 int idx,pidx;
01738 int changed = False;
01739 int found = False;
01740
01741 if (!prereq)
01742 return;
01743
01744
01745 for (idx=command_definitions.num-1; !changed && idx >= 0; idx--)
01746 if (strncmp(name,command_definitions.list[idx].name,CMDDEF_MAX_NAME_LENGTH) == 0) {
01747 CommandDefinition* cmddef = &(command_definitions.list[idx]);
01748
01749 for (pidx=command_definitions.num-1; !found && pidx >= 0; pidx--)
01750 if (strncmp(prereq,command_definitions.list[pidx].name,CMDDEF_MAX_NAME_LENGTH) == 0) {
01751 found=True;
01752 if (cmddef->num_prereqs >= CMDDEF_MAX_PREREQS)
01753 ipc_notify(IPC_ONE,IPC_ERROR,"Maximum limit on command prerequisites (%d) reached; can't add another",
01754 CMDDEF_MAX_PREREQS);
01755 else {
01756 cmddef->prereqs[cmddef->num_prereqs++]=pidx;
01757
01758 }
01759 }
01760 changed = True;
01761 }
01762
01763 if (!changed)
01764 ipc_notify(IPC_ONE,IPC_ERROR,"Failed to add prerequisite to command %s",name);
01765 }
01766
01767
01768
01773 CommandDefinition* cmddefs_lookup(const char *name)
01774 {
01775 int command_def=0;
01776
01777
01778 while ((command_def < command_definitions.num) &&
01779 (strncmp(name,command_definitions.list[command_def].name,CMDDEF_MAX_NAME_LENGTH) != 0))
01780 command_def++;
01781
01782
01783 if (command_def < command_definitions.num)
01784 return &(command_definitions.list[command_def]);
01785 else {
01786 if (cmdparam_warn_unknown)
01787 ipc_notify(IPC_ONE,IPC_ERROR,"Unknown command: %s",name);
01788 return NULL;
01789 }
01790 }
01791
01792
01793
01794 cmdstat cmddefs_exec_by_name(const char* name, CMD_ARGS)
01795 {
01796 CommandDefinition* def = cmddefs_lookup(name);
01797
01798 if (!def)
01799 return CMD_PARAMETER_ERROR;
01800
01801 else {
01802 Command cmd;
01803 int i;
01804
01805 cmd.def=def;
01806 cmd.argc=argc;
01807 for (i=0; i<argc; i++)
01808 cmd.argv[i]=argv[i];
01809
01810 return command_exec(&cmd);
01811 }
01812 }
01813
01814
01815
01839 const char* command_parse_token(char** remaining)
01840 {
01841 char* start;
01842 char* end;
01843 static const char eq[]="=";
01844 static bool nexttokenis_eq=false;
01845
01846
01847 if (nexttokenis_eq) {
01848 nexttokenis_eq=false;
01849 return eq;
01850 }
01851
01852 while (isspace(**remaining)) (*remaining)++;
01853 start=*remaining;
01854 end=*remaining;
01855
01856 switch (**remaining) {
01857
01858 case '\0':
01859 break;
01860
01861 case '#':
01862 while (*(++(*remaining)));
01863 start=end=(*remaining);
01864 break;
01865
01866 case '\"':
01867 while (*(++(*remaining)) && (**remaining!='\"'));
01868 start++;
01869 end=(*remaining);
01870 if (!**remaining) ipc_notify(IPC_ONE,IPC_ERROR,"Unmatched \"");
01871 else (*remaining)++;
01872 break;
01873
01874 case '\'':
01875 while (*(++(*remaining)) && (**remaining!='\''));
01876 start++;
01877 end=(*remaining);
01878 if (!**remaining) ipc_notify(IPC_ONE,IPC_ERROR,"Unmatched \'");
01879 else (*remaining)++;
01880 break;
01881
01882 default:
01883 while (*(++(*remaining)) && !isspace(**remaining) && **remaining!='=' && **remaining!='#');
01884 end=*remaining;
01885 break;
01886 }
01887
01888
01889 if (end && *end=='=') {
01890 nexttokenis_eq=true;
01891 *end=' ';
01892 }
01893
01894
01895 while (isspace(**remaining)) (*remaining)++;
01896 if (**remaining=='#') while (*(++(*remaining)));
01897
01898
01899 if (end) *end='\0';
01900 return start;
01901 }
01902
01903
01904
01915 int command_parse_line(Command *command, char* const cmdtxt)
01916 {
01917 char* remaining=cmdtxt;
01918
01919
01920 const char* name = command_parse_token(&remaining);
01921 if (!*name) return 0;
01922
01923
01924 command->def = cmddefs_lookup(name);
01925 if (!command->def) {
01926 commands_failed++;
01927 return 0;
01928 }
01929
01930
01931 command->argc=0;
01932 while ( (command->argc < CMD_MAX_ARGUMENTS) && *remaining )
01933 command->argv[(command->argc)++]=command_parse_token(&remaining);
01934
01935
01936 if (!command_check_usage(command)) {
01937 commands_failed++;
01938 return 0;
01939 }
01940
01941 return 1;
01942 }
01943
01944
01945
01946 int command_check_usage(Command* command)
01947 {
01948
01949 if (command->argc >= CMD_MAX_ARGUMENTS)
01950 ipc_notify(IPC_ONE,IPC_WARNING,"Argument list may be truncated (limit is %d)",CMD_MAX_ARGUMENTS);
01951 if (command->argc < command->def->minargs) {
01952 char buf[CMD_MAX_LINE_LENGTH];
01953 cmddef_print_usage_to_str(command->def, buf, CMD_MAX_LINE_LENGTH);
01954 ipc_notify(IPC_ONE,IPC_ERROR,"Command %s requires %d arguments but %d supplied",
01955 command->def->name,command->def->minargs,command->argc);
01956 ipc_notify(IPC_ONE,IPC_STD,"Usage: %s",buf);
01957 return 0;
01958 }
01959
01960 return 1;
01961 }
01962
01963
01964
01965 #ifndef NO_SIGNAL_HANDLING
01966 void command_exec_sigint_handler( int sig)
01967 {
01968 (void)sig;
01969
01970 ipc_notify(IPC_ALL,IPC_ERROR,
01971 "Aborting command due to SIGINT; program may now be in an undefined state");
01972 longjmp(jmp_env,CMD_SIGINT_ERROR);
01973 }
01974 #endif
01975
01976
01977
01979 cmdstat command_exec(Command *cmd)
01980 {
01981 time_t end_of_command;
01982 time_t start_of_command;
01983 double elapsed_time;
01984 int command_number=command_num_called++;
01985 char str[CMD_MAX_LINE_LENGTH];
01986 int i;
01987 int status = CMD_NO_ERROR;
01988
01989 if (ipc_msg_level >= IPC_VERBOSE) {
01990 command_print_to_str( cmd, str, CMD_MAX_LINE_LENGTH);
01991 ipc_notify(IPC_ONE,IPC_VERBOSE,"Command %2d (%s) executing",
01992 command_number,str);
01993 }
01994
01995
01996 for (i=0; i< cmd->def->num_prereqs && status >= CMD_NO_ERROR; i++)
01997 if (command_definitions.list[cmd->def->prereqs[i]].callstatus == CMD_NEVER_CALLED) {
01998 Command temp;
01999 temp.def=cmddefs_lookup(command_definitions.list[cmd->def->prereqs[i]].name);
02000 temp.argc=0;
02001 status = command_exec(&temp);
02002 }
02003 else status = command_definitions.list[cmd->def->prereqs[i]].callstatus;
02004
02005
02006
02007 start_of_command = time(NULL);
02008 if (status >= CMD_NO_ERROR) {
02009
02010 #ifdef NO_SIGNAL_HANDLING
02011 status = CMD_CALL(*cmd);
02012 #else
02013
02014 signal_handler_type original_handler =
02015 signal(SIGINT,command_exec_sigint_handler);
02016
02017
02018 if (sigsetjmp(jmp_env,True)==0)
02019
02020 status = CMD_CALL(*cmd);
02021 else
02022
02023 status = CMD_SIGINT_ERROR;
02024
02025
02026 signal(SIGINT,original_handler);
02027 #endif
02028
02029 ipc_notify(IPC_ONE,IPC_VERBOSE,"Command %2d exited with return code %d",
02030 command_number,status);
02031 cmd->def->callstatus = status;
02032 }
02033 else {
02034 ipc_notify(IPC_ONE,IPC_WARNING,"Command %2d not being called due to unsatisfiable prerequisite: %s",
02035 command_number,command_definitions.list[cmd->def->prereqs[i-1]].name);
02036 status = CMD_PREREQ_ERROR;
02037 }
02038
02039
02040 if (status >= CMD_NO_ERROR) {
02041 commands_succeeded++;
02042 }
02043 else
02044 commands_failed++;
02045
02046 ipc_barrier();
02047
02048 end_of_command = time(NULL);
02049 elapsed_time = difftime(end_of_command, start_of_command);
02050
02051 if (elapsed_time != 0 || ipc_msg_level >= IPC_OVERWHELM) {
02052 if (ipc_msg_level >= IPC_VERBOSE) {
02053 command_print_to_str( &(*cmd), str, CMD_MAX_LINE_LENGTH);
02054 ipc_notify(IPC_ONE,IPC_VERBOSE,"Command %2d (%s) took %g seconds, completing %.24s",
02055 command_number, str,
02056 (double)elapsed_time, ctime(&end_of_command));
02057 }
02058 else
02059 ipc_notify(IPC_ONE,IPC_STD,"Command %2d (%s) took %g seconds, completing %.24s",
02060 command_number, cmd->def->name,
02061 (double)elapsed_time, ctime(&end_of_command));
02062 }
02063
02064 return status;
02065 }
02066
02067
02068
02070 cmdstat cmddefs_exec_str(const char* cmdtxt)
02071 {
02072 Command cmd;
02073 char buf[CMD_MAX_LINE_LENGTH];
02074 strncpy(buf,cmdtxt,CMD_MAX_LINE_LENGTH);
02075
02076 if (!command_parse_line(&cmd, buf))
02077 return CMD_EMPTY;
02078
02079 return command_exec(&cmd);
02080 }
02081
02082
02083
02099 int cmddefs_exec_batch(CmdDefs_LineGenerator fn, const char * description)
02100 {
02101 int command_count;
02102 int orig_commands_succeeded=commands_succeeded;
02103 int orig_commands_failed=commands_failed;
02104 static int done;
02105 static unsigned linelength;
02106 time_t current_time;
02107
02108 command_count=0;
02109 done=False;
02110
02111 if (cmdparam_changes_verbose){
02112 current_time = time(NULL);
02113 ipc_notify(IPC_ONE,IPC_SUMMARY,"Command %s execution started %.24s",
02114 description,ctime(¤t_time));
02115 }
02116
02117
02118 02119 02120
02121 while (!done) {
02122
02123
02124 if (AMPARENTPE){
02125 linelength=0;
02126 cmddefs_line_buffer[0]='\0';
02127 done=(*fn)();
02128
02129 if (!done && *cmddefs_line_buffer) {
02130 linelength=strlen(cmddefs_line_buffer);
02131
02132
02133 if (cmddefs_line_buffer[linelength-1] == '\n') {
02134 cmddefs_line_buffer[linelength-1]='\0';
02135 linelength--;
02136 }
02137
02138 if (linelength >= CMD_MAX_LINE_LENGTH)
02139 ipc_notify(IPC_ALL,IPC_WARNING,"Command line may be truncated (limit is %d)",CMD_MAX_LINE_LENGTH);
02140 }
02141 }
02142
02143
02144 ipc_barrier();
02145 ipc_get(&done, IPC_INT, 1, PARENTPE);
02146 ipc_get(&linelength, IPC_UNSIGNED, 1, PARENTPE);
02147 if (!done && linelength>0)
02148 ipc_get((int *)(&cmddefs_line_buffer[0]), IPC_INT, (linelength+1)/sizeof(int)+1, PARENTPE);
02149
02150
02151 ipc_barrier();
02152
02153
02154 if (!done && linelength>0) {
02155 ipc_notify(IPC_ONE,IPC_OVERWHELM,"Parsing command string `%s'",cmddefs_line_buffer);
02156 if (cmddefs_exec_str(cmddefs_line_buffer) != CMD_EMPTY)
02157 command_count++;
02158 }
02159 }
02160
02161 done=False;
02162
02163 current_time = time(NULL);
02164 if (cmdparam_changes_verbose)
02165 ipc_notify(IPC_ONE,IPC_SUMMARY,"Command %s execution completed %.24s; %d succeeded, %d failed",
02166 description,ctime(¤t_time),
02167 commands_succeeded-orig_commands_succeeded,
02168 commands_failed-orig_commands_failed);
02169
02170 return commands_failed-orig_commands_failed;
02171 }
02172
02173
02174
02177 int cmddefs_get_line_from_file( void )
02178 {
02179 if (!cmddefs_file)
02180 return true;
02181
02182 bool done=false;
02183 char* lastchar=cmddefs_line_buffer;
02184 *lastchar='\\';
02185
02186 while (!done && *lastchar=='\\') {
02187 done = (fgets(lastchar,CMD_MAX_LINE_LENGTH+1,cmddefs_file) == NULL);
02188 lastchar += strlen(lastchar)-2;
02189 if (lastchar < cmddefs_line_buffer) lastchar = cmddefs_line_buffer;
02190 }
02191 return done;
02192 }
02193
02194
02195
02199 int cmddefs_exec_file(const char *filename)
02200 {
02201 char description[255];
02202 int status,nofile=False;
02203 FILE *orig_cmddefs_file=cmddefs_file;
02204
02205 cmddefs_file=0;
02206
02207
02208 if (AMPARENTPE){
02209
02210 cmddefs_file=fopen(filename,"r");
02211
02212
02213 if (!cmddefs_file){
02214 StringParser p;
02215 StringParser::arglist words;
02216 p.parse(commandpath,words);
02217 StringParser::argptr i=words.begin();
02218 while (i!=words.end() && !cmddefs_file) {
02219 const string name = (*i)+filename;
02220 cmddefs_file=fopen(name.c_str(),"r");
02221 i++;
02222 }
02223 }
02224 if (!cmddefs_file){
02225 ipc_notify(IPC_ALL,IPC_ERROR,"Couldn't open command file %s",filename);
02226 nofile=True;
02227 }
02228 }
02229
02230 snprintf(description,255,"file %s",filename);
02231 status = cmddefs_exec_batch(&cmddefs_get_line_from_file,description);
02232
02233 if (cmddefs_file)
02234 fclose(cmddefs_file);
02235
02236 cmddefs_file=orig_cmddefs_file;
02237
02238 return (nofile? CMD_FILE_ERROR : status);
02239 }
02240
02241
02242
02244 int cmddefs_num_total(void)
02245 { return command_definitions.num; }
02246
02247
02248
02253 void command_print_to_str( const Command *cmd, char *str, size_t nchars)
02254 {
02255 int i;
02256 char *str_ptr=str;
02257 size_t charsleft=nchars-1;
02258
02259
02260 snprintf(str_ptr,charsleft,"%s",cmd->def->name);
02261 charsleft -= strlen(str_ptr);
02262 str_ptr += strlen(str_ptr);
02263
02264
02265 for(i=0; i < cmd->argc; i++){
02266 snprintf(str_ptr,charsleft," %s",cmd->argv[i]);
02267 charsleft -= strlen(str_ptr);
02268 str_ptr += strlen(str_ptr);
02269 }
02270 }
02271
02272
02273
02274 void cmddefs_sort(void)
02275 {
02276 qsort(command_definitions.list, command_definitions.num,
02277 sizeof(CommandDefinition), cmddef_compare);
02278 }
02279
02280
02281
02283 int cmddef_compare(const void* def1, const void* def2)
02284 {
02285 return( strncasecmp(((const CommandDefinition*)def1)->name,
02286 ((const CommandDefinition*)def2)->name,
02287 CMDDEF_MAX_NAME_LENGTH) );
02288 }
02289
02290
02292 void cmddef_print_usage(FILE *fp, const CommandDefinition* cmddef)
02293 {
02294 if (cmddef->usage)
02295 fprintf(fp,cmddef->usage,cmddef->name);
02296 else {
02297 int i;
02298 fprintf(fp,"%s",cmddef->name);
02299 for (i=0; i< cmddef->minargs; i++)
02300 fprintf(fp," <arg>");
02301 fprintf(fp," [<optional-args>]");
02302 }
02303 }
02304
02305
02307 void cmddef_print_usage_to_str(const CommandDefinition* cmddef, char *str, size_t nchars)
02308 {
02309 if (cmddef->usage)
02310 snprintf(str,nchars,cmddef->usage,cmddef->name);
02311 else {
02312 char *str_ptr=str;
02313 size_t charsleft=nchars-1;
02314 int i;
02315
02316
02317 snprintf(str_ptr,charsleft,"%s",cmddef->name);
02318 charsleft -= strlen(str_ptr);
02319 str_ptr += strlen(str_ptr);
02320
02321
02322 for (i=0; i< cmddef->minargs; i++) {
02323 snprintf(str_ptr,charsleft," <arg%d>",i+1);
02324 charsleft -= strlen(str_ptr);
02325 str_ptr += strlen(str_ptr);
02326 }
02327 snprintf(str_ptr,charsleft," [<optional-args>]");
02328 charsleft -= strlen(str_ptr);
02329 str_ptr += strlen(str_ptr);
02330 }
02331 }
02332
02333
02334
02336 void cmddefs_print_all(FILE *fp)
02337 {
02338 int i;
02339
02340 for(i=0; i< command_definitions.num; i++) {
02341 cmddef_print_usage(fp,&(command_definitions.list[i]));
02342 fprintf(fp,"\n");
02343 }
02344 }
02345
02346
02347
02348 void cmddefs_print_doc_for_index(FILE *fp, int idx)
02349 {
02350 cmddef_print_usage(fp,&(command_definitions.list[idx]));
02351 fprintf(fp,"\n\n");
02352
02353 if (command_definitions.list[idx].doc) {
02354 fprintf(fp,command_definitions.list[idx].doc,
02355 command_definitions.list[idx].name);
02356 fprintf(fp,"\n");
02357 }
02358 else
02359 fprintf(fp,"No further help available.\n");
02360 }
02361
02362
02363
02365 void cmddefs_print_doc(FILE *fp, const char* name)
02366 {
02367 int idx = 0;
02368 int found = False;
02369
02370 for (idx=command_definitions.num-1; !found && idx >= 0; idx--)
02371 if (strncmp(name,command_definitions.list[idx].name,CMDDEF_MAX_NAME_LENGTH) == 0) {
02372 cmddefs_print_doc_for_index(fp,idx);
02373 found = True;
02374 }
02375
02376 if (!found)
02377 ipc_notify(IPC_ONE,IPC_ERROR,"Don't know anything about command %s",name);
02378 }
02379
02380
02381
02382 void cmddefs_print_all_doc(FILE *file)
02383 {
02384 int i;
02385 fprintf(file,cmdparam_help_separator);
02386 for (i=0; i< cmddefs_num_total(); i++) {
02387 cmddefs_print_doc_for_index(file,i);
02388 fprintf(file,cmdparam_help_separator);
02389 fprintf(file,"\n");
02390 }
02391 }
02392
02393
02394
02401 char* cmddefs_completion_generator (char *text, int state)
02402 {
02403 static int idx, len;
02404 char *name;
02405
02406 02407 02408 02409
02410 if (!state) {
02411 idx = 0;
02412 len = strlen(text);
02413 }
02414
02415
02416 while (idx < command_definitions.num) {
02417 name = command_definitions.list[idx++].name;
02418 if (strncmp (name, text, len) == 0)
02419 return (cmdparam_dupstr(name));
02420 }
02421
02422 return ((char *)NULL);
02423 }
02424
02425
02426
02427
02428
02429
02430
02431
02453 int hooklists_define_list( const char * listname, const char * countername )
02454 {
02455 if (hooklists.num >= HOOKLISTS_MAX_NUM) {
02456 ipc_notify(IPC_ONE,IPC_ERROR,"Maximum number of hook lists reached");
02457 return CMD_PARAMETER_ERROR;
02458 }
02459
02460 strncpy(hooklists.lists[hooklists.num].name,listname,HOOKLIST_MAX_NAME_LENGTH);
02461 strncpy(hooklists.lists[hooklists.num].countername,countername,HOOKLIST_MAX_NAME_LENGTH);
02462 hooklists.lists[hooklists.num].current=0;
02463 hooklists.num++;
02464
02465 return hooklists.num - 1;
02466 }
02467
02468
02469
02470 02471 02472 02473 02474 02475 02476 02477 02478 02479 02480 02481 02482 02483 02484 02485 02486 02487 02488 02489 02490 02491 02492 02493 02494 02495 02496
02497 #define nexthooknum (hooklists.lists[hooklist].num)
02498 cmdstat cmd_hook( CMD_ARGS )
02499 {
02500 int i;
02501 HooklistNum hooklist=Uninitialized;
02502 CounterHookDefinition* hook = NULL;
02503 const char *specifier=argv[1];
02504
02505
02506 for (i=0; i<hooklists.num; i++)
02507 if (!strncmp(hooklists.lists[i].name,argv[0],HOOKLIST_MAX_NAME_LENGTH))
02508 hooklist=i;
02509
02510 if (hooklist==Uninitialized) {
02511 ipc_notify(IPC_ONE,IPC_ERROR,"Hook list is not defined: %s",argv[0]);
02512 return CMD_PARAMETER_ERROR;
02513 }
02514
02515 if (nexthooknum >= HOOKLIST_MAX_NUM) {
02516 ipc_notify(IPC_ONE,IPC_ERROR,"Reached limit for number of counter hooks");
02517 return CMD_PARAMETER_ERROR;
02518 }
02519
02520 hook = &(hooklists.lists[hooklist].defs[nexthooknum]);
02521 hook->order=hook_definition_counter++;
02522
02523
02524 {
02525 CommandDefinition* def = cmddefs_lookup(argv[2]);
02526 if (!def) return CMD_PARAMETER_ERROR;
02527 hook->cmd.def = def;
02528 }
02529
02530
02531 hook->cmd.argc = argc-3;
02532 for (i=0; i< argc-3; i++) {
02533 hook->argstofree[i] = cmdparam_dupstr(argv[i+3]);
02534 hook->cmd.argv[i] = hook->argstofree[i];
02535 }
02536 hook->argstofree[i]=NULL;
02537
02538 if (!command_check_usage(&(hook->cmd)))
02539 return CMD_PARAMETER_ERROR;
02540
02541 if (hook->cmd.def->minargs > argc-3)
02542 ipc_notify(IPC_ONE,IPC_WARNING,"Command %s in hook requires %d args but only %d supplied");
02543
02544
02545 while (*specifier) {
02546
02547
02548 if (!hook_parse_specifier( hook, &specifier )) {
02549 ipc_notify(IPC_ONE,IPC_ERROR,"Could not parse counter specifier");
02550 return CMD_PARAMETER_ERROR;
02551 }
02552 nexthooknum++;
02553
02554
02555 if (ipc_msg_level >= IPC_VERBOSE) {
02556 char str[CMD_MAX_LINE_LENGTH];
02557 command_print_to_str(&(hook->cmd),str,CMD_MAX_LINE_LENGTH);
02558 ipc_notify(IPC_ONE,IPC_VERBOSE,"Defined counter_hook %d-%d%%%d %s",
02559 hook->start,hook->end,hook->step,str);
02560 }
02561
02562
02563 if (*specifier) {
02564 if (nexthooknum >= HOOKLIST_MAX_NUM) {
02565 ipc_notify(IPC_ONE,IPC_ERROR,"Reached limit for number of counter hooks");
02566 return CMD_PARAMETER_ERROR;
02567 }
02568
02569 hook_copy( hook, &(hooklists.lists[hooklist].defs[nexthooknum]));
02570 hook = &(hooklists.lists[hooklist].defs[nexthooknum]);
02571 }
02572 }
02573
02574
02575
02576 hooklists_sort(hooklist);
02577
02578 return CMD_NO_ERROR;
02579 }
02580
02581
02582
02584 int hook_parse_specifier( CounterHookDefinition *hook, const char **remaining )
02585 {
02586 hook->step = 1;
02587
02588
02589 hook->start = hook->end = (int)ROUND(params_getnumericval(remaining));
02590 if (hook->start < 0) return False;
02591 if (! (**remaining)) return True;
02592
02593
02594 if (**remaining == '-') {
02595 if (! ++(*remaining)) return False;
02596 hook->end = (int)ROUND(params_getnumericval(remaining));
02597 if (hook->end < 0) return False;
02598 }
02599 if (! (**remaining)) return True;
02600
02601
02602 if (**remaining == '%') {
02603 int num;
02604 if (! ++(*remaining)) return False;
02605 num = (int)ROUND(params_getnumericval(remaining));
02606 if (num < 1) return False;
02607 hook->step = num;
02608 }
02609 if (! (**remaining)) return True;
02610
02611
02612 if (**remaining == ',') {
02613 if (! ++(*remaining)) return False;
02614 }
02615 else
02616 if (**remaining)
02617 return False;
02618
02619 return True;
02620 }
02621
02622
02623
02625 void hook_copy( CounterHookDefinition *source, CounterHookDefinition *dest)
02626 {
02627 int i;
02628
02629
02630 dest->cmd.def = source->cmd.def;
02631
02632
02633 dest->cmd.argc = source->cmd.argc;
02634 for (i=0; i< source->cmd.argc; i++)
02635 dest->cmd.argv[i] = source->cmd.argv[i];
02636 dest->argstofree[0]=NULL;
02637
02638
02639 dest->start = source->start;
02640 dest->end = source->end;
02641 dest->step = source->step;
02642
02643
02644 dest->order = source->order;
02645 }
02646
02647
02648
02653 void hooklists_sort(HooklistNum hooklist)
02654 {
02655 qsort(&(CURRENT_HOOK(hooklists.lists[hooklist])),
02656 hooklists.lists[hooklist].num - hooklists.lists[hooklist].current,
02657 sizeof(CounterHookDefinition),
02658 hook_compare);
02659 }
02660
02661
02662
02665 int hook_compare(const void* hook1, const void* hook2)
02666 {
02667 const CounterHookDefinition* h1=(const CounterHookDefinition*)hook1;
02668 const CounterHookDefinition* h2=(const CounterHookDefinition*)hook2;
02669
02670 return ( h1->start == h2->start ?
02671 h1->order - h2->order :
02672 h1->start - h2->start );
02673 }
02674
02675
02676
02686 void hooklists_run_list(HooklistNum hooklist, int counter, int catchuponly)
02687 {
02688 int i;
02689
02690
02691 if (!HAS_CURRENT_HOOK(hooklists.lists[hooklist]))
02692 return;
02693
02694
02695 if (counter < CURRENT_HOOK(hooklists.lists[hooklist]).start)
02696 return;
02697
02698 02699 02700 02701 02702 02703 02704 02705 02706 02707 02708 02709
02710 for (; (HAS_CURRENT_HOOK(hooklists.lists[hooklist])) &&
02711 (counter > CURRENT_HOOK(hooklists.lists[hooklist]).end);
02712 hooklists.lists[hooklist].current++)
02713 if ( ( CURRENT_HOOK(hooklists.lists[hooklist]).end != counter-1) &&
02714 ( CURRENT_HOOK(hooklists.lists[hooklist]).cmd.def->catchup ) )
02715 command_exec(&(CURRENT_HOOK(hooklists.lists[hooklist]).cmd));
02716
02717
02718 for (i=hooklists.lists[hooklist].current;
02719 (i<hooklists.lists[hooklist].num) &&
02720 (counter >= hooklists.lists[hooklist].defs[i].start);
02721 i++) {
02722 CounterHookDefinition* hookdef= &(hooklists.lists[hooklist].defs[i]);
02723
02724
02725 if ( (counter <= hookdef->end) &&
02726 ((counter % hookdef->step) == 0) &&
02727 (!catchuponly || hookdef->cmd.def->catchup ) ) {
02728
02729 if (hookdef->step !=1 || counter == hookdef->start)
02730 ipc_notify(IPC_ONE,IPC_STD,"Running hook `%s' %s at %s %d",
02731 hookdef->cmd.def->name,
02732 hooklists.lists[hooklist].name,
02733 hooklists.lists[hooklist].countername,
02734 counter);
02735 if (hookdef->step==1 && counter==hookdef->start && hookdef->end > hookdef->start)
02736 ipc_notify(IPC_ONE,IPC_STD,"(Hook `%s' will run at every %s until %s %d)",
02737 hookdef->cmd.def->name,
02738 hooklists.lists[hooklist].countername,
02739 hooklists.lists[hooklist].countername,
02740 hookdef->end);
02741 command_exec(&(hookdef->cmd));
02742 }
02743 }
02744 }
02745
02746
02747
02749 void hooklists_reset_list(HooklistNum hooklist)
02750 {
02751 hooklists.lists[hooklist].current=0;
02752 hooklists_sort(hooklist);
02753
02754 return;
02755 }
02756
02757
02758
02760 void hooklists_empty_list(HooklistNum hooklistnum)
02761 {
02762 int i;
02763 CounterHooklist* hooklist = &(hooklists.lists[hooklistnum]);
02764
02765
02766 for (i=0; i<hooklist->num; i++) {
02767 int arg=0;
02768 while (hooklist->defs[i].argstofree[arg])
02769 free(hooklist->defs[i].argstofree[arg++]);
02770 }
02771
02772 hooklist->num=0;
02773 hooklist->current=0;
02774
02775 return;
02776 }
02777
02778
02779
02784 void hook_print_to_str( CounterHookDefinition *hook, char *hooklistname, char *str, size_t nchars)
02785 {
02786 char *str_ptr=str;
02787 size_t charsleft=nchars-1;
02788
02789 snprintf(str_ptr,charsleft,"hook %-15s %6d", hooklistname, hook->start);
02790 charsleft -= strlen(str_ptr); str_ptr += strlen(str_ptr);
02791
02792
02793 if (hook->end != hook->start) {
02794 snprintf(str_ptr,charsleft,"-%d",hook->end);
02795 charsleft -= strlen(str_ptr); str_ptr += strlen(str_ptr);
02796 }
02797
02798
02799 if (hook->step != 1) {
02800 snprintf(str_ptr,charsleft,"%%%d", hook->step);
02801 charsleft -= strlen(str_ptr); str_ptr += strlen(str_ptr);
02802 }
02803
02804
02805 snprintf(str_ptr,charsleft," ");
02806 charsleft -= strlen(str_ptr); str_ptr += strlen(str_ptr);
02807 command_print_to_str(&(hook->cmd), str_ptr,charsleft);
02808 charsleft -= strlen(str_ptr); str_ptr += strlen(str_ptr);
02809 }
02810
02811
02812
02817 void hooklists_log(void)
02818 {
02819 int i,hooklist;
02820 char str[CMD_MAX_LINE_LENGTH];
02821
02822 for (hooklist=0; hooklist<hooklists.num; hooklist++)
02823 for (i=0; i<hooklists.lists[hooklist].num; i++) {
02824 hook_print_to_str( &(hooklists.lists[hooklist].defs[i]),
02825 hooklists.lists[hooklist].name,
02826 str, CMD_MAX_LINE_LENGTH);
02827 ipc_log(IPC_ONE,"%s\n",str);
02828 }
02829
02830 ipc_log(IPC_ONE,"\n");
02831 }
02832
02833
02834
02835
02836
02837
02838
02839
02843 size_t cmdparam_identifier_length(const char* str)
02844 {
02845 const char * rem;
02846
02847
02848 if (!str || !isalpha(*str)) return 0;
02849
02850
02851 for (rem=str; isalnum(*rem) || *rem == '_'; rem++);
02852
02853 return rem-str;
02854 }
02855
02856
02857
02859 char* cmdparam_dupstr (const char *str)
02860 {
02861 char *newstr = (char *)malloc(strlen(str)+1);
02862 if (!newstr)
02863 ipc_abort(IPC_EXIT_OUT_OF_MEMORY,"Cannot allocate string");
02864 strcpy (newstr, str);
02865 return (newstr);
02866 }
02867
02868
02869
02872 int cmdparams_print_doc(FILE *fp, const char* name)
02873 {
02874 int idx = 0;
02875 int found = False;
02876
02877 for (idx=blackboard.num-1; !found && idx >= 0; idx--)
02878 if (strncmp(name,blackboard.list[idx].name,PARAM_MAX_NAME_LENGTH) == 0) {
02879 params_print_doc_for_index(fp,idx);
02880 found = True;
02881 }
02882
02883 if (!found)
02884 for (idx=command_definitions.num-1; !found && idx >= 0; idx--)
02885 if (strncmp(name,command_definitions.list[idx].name,CMDDEF_MAX_NAME_LENGTH) == 0) {
02886 cmddefs_print_doc_for_index(fp,idx);
02887 found = True;
02888 }
02889
02890 return found;
02891 }
02892
02893
02894
02896 char* cmdparams_completion_generator (char *text, int state)
02897 {
02898 char *name = cmddefs_completion_generator (text, state);
02899 if (name) return name;
02900 return params_completion_generator (text, state);
02901 }
02902
02903
02904 int cmdparam_save_current_state(const char * filename)
02905 {
02906 int i,hooklist;
02907 FILE *file;
02908 char str[CMD_MAX_LINE_LENGTH];
02909
02910 file=fopen(filename,"w+");
02911 if(file==NULL) {
02912 ipc_notify(IPC_ALL,IPC_ERROR,"Can't open %s file", filename);
02913 return CMD_FILE_ERROR;
02914 }
02915
02916 fprintf(file,"# Parameters:\n\n");
02917
02918 for(i=0; i< blackboard.num; i++)
02919 if (!blackboard.list[i].is_constant &&
02920 params_print_to_str( i, str, CMD_MAX_LINE_LENGTH))
02921 fprintf(file,"%s\n",str);
02922
02923 fprintf(file,"\n# Hooks:\n\n");
02924
02925 for (hooklist=0; hooklist<hooklists.num; hooklist++)
02926 for (i=0; i<hooklists.lists[hooklist].num; i++) {
02927 hook_print_to_str( &(hooklists.lists[hooklist].defs[i]),
02928 hooklists.lists[hooklist].name,
02929 str, CMD_MAX_LINE_LENGTH);
02930 fprintf(file,"%s\n",str);
02931 }
02932
02933 fprintf(file,"\n");
02934 fclose(file);
02935
02936 return CMD_NO_ERROR;
02937 }
02938
02939
02940
02942 cmdstat cmdparam_set( const char *name, const char *expr )
02943 {
02944 int status = CMD_NO_ERROR;
02945 int idx = 0;
02946 int found = False;
02947
02948 for (idx=0; !found && idx < blackboard.num; idx++)
02949 if (strncmp(name,blackboard.list[idx].name,PARAM_MAX_NAME_LENGTH) == 0) {
02950 ParamInterface* def = &(blackboard.list[idx]);
02951 found = True;
02952
02953 if (def->is_constant) {
02954 ipc_notify(IPC_ONE,IPC_ERROR,"Can't change value of symbolic constant");
02955 status = CMD_PARAMETER_ERROR;
02956 }
02957 else
02958 switch(def->data_type) {
02959
02960
02961 case PARAM_STRING:
02962 {
02963 if (param_check( def, expr))
02964 status = CMD_PARAMETER_ERROR;
02965 else {
02966 const char* str=cmds(expr);
02967 int differs=strcmp(def->data_ptr.c,str);
02968
02969 if (def->setfn)
02970 status = (*def->setfn)(def->name,def->data_ptr.c,str);
02971 else
02972 strcpy(def->data_ptr.c,str);
02973
02974 if (differs && cmdparam_changes_verbose)
02975 ipc_notify(IPC_ONE,IPC_STD,"Changed parameter %s to \"%s\"",def->name,str);
02976 }
02977 break;
02978 }
02979
02980
02981 case PARAM_BOOL:
02982 {
02983 int oldvalue = *(def->data_ptr.i);
02984 int newvalue = cmdi(expr);
02985
02986
02987 if (newvalue!=Uninitialized && newvalue!=False)
02988 newvalue=True;
02989
02990 if (param_check( def, &newvalue))
02991 status = CMD_PARAMETER_ERROR;
02992 else {
02993 if (def->setfn)
02994 status = (*def->setfn)(def->name,def->data_ptr.i,&newvalue);
02995 else
02996 *(def->data_ptr.i) = newvalue;
02997
02998 if (cmdparam_changes_verbose && *(def->data_ptr.i) != oldvalue)
02999 ipc_notify(IPC_ONE,IPC_STD,"Changed parameter %s to %s",def->name,
03000 param_pp_boolean(*(def->data_ptr.i)));
03001 }
03002 break;
03003 }
03004
03005
03006 case PARAM_INT:
03007 {
03008 int oldvalue = *(def->data_ptr.i);
03009 int newvalue = cmdi(expr);
03010
03011 if (param_check( def, &newvalue))
03012 status = CMD_PARAMETER_ERROR;
03013 else {
03014 if (def->setfn)
03015 status = (*def->setfn)(def->name,def->data_ptr.i,&newvalue);
03016 else
03017 *(def->data_ptr.i) = newvalue;
03018
03019 if (cmdparam_changes_verbose && *(def->data_ptr.i) != oldvalue)
03020 ipc_notify(IPC_ONE,IPC_STD,"Changed parameter %s to %s",
03021 def->name,param_pp_int(*(def->data_ptr.i)));
03022 }
03023 break;
03024 }
03025
03026
03027 case PARAM_DOUBLE:
03028 {
03029 double oldvalue = *(def->data_ptr.f);
03030 double newvalue = cmdf(expr);
03031
03032 if (param_check( def, &newvalue))
03033 status = CMD_PARAMETER_ERROR;
03034 else {
03035 if (def->setfn)
03036 status = (*def->setfn)(def->name, def->data_ptr.f, &newvalue);
03037 else
03038 *(def->data_ptr.f) = newvalue;
03039 if (cmdparam_changes_verbose && *(def->data_ptr.f) != oldvalue)
03040 ipc_notify(IPC_ONE,IPC_STD,"Changed parameter %s to %s",
03041 def->name,param_pp_float(*(def->data_ptr.f)));
03042 }
03043 break;
03044 }
03045
03046
03047 default:
03048 ipc_notify(IPC_ONE,IPC_WARNING,"Datatype of %s unknown; can't change it",name);
03049 status = CMD_PARAMETER_ERROR;
03050 }
03051 def->been_set = True;
03052 }
03053
03054 if (!found) {
03055 if (cmdparam_warn_unknown)
03056 ipc_notify(IPC_ONE,IPC_ERROR,"Unknown parameter: %s", name);
03057 status = CMD_PARAMETER_ERROR;
03058 }
03059
03060 return status;
03061 }
03062
03063
03064
03065
03066
03067
03068
03069
03071 cmdstat cmd_set( CMD_ARGS )
03072 {
03073 if (argc < 3 || argc%3 != 0) {
03074 ipc_notify(IPC_ONE,IPC_ERROR,"Wrong number of arguments to set (%d)",argc);
03075 return CMD_PARAMETER_ERROR;
03076 }
03077
03078 int status = CMD_NO_ERROR;
03079
03080 for (int namearg=0,pivotarg=1,valuearg=2; valuearg<argc; namearg+=3,pivotarg+=3,valuearg+=3) {
03081 if (*argv[pivotarg] != '=') {
03082 ipc_notify(IPC_ONE,IPC_ERROR,"Syntax error in set arguments ('%s' is not '=')",argv[pivotarg]);
03083 return CMD_PARAMETER_ERROR;
03084 }
03085
03086
03087 status = std::min(status,cmdparam_set( argv[namearg], argv[valuearg] ));
03088 }
03089
03090 return status;
03091 }
03092
03093
03094
03095 cmdstat cmd_quit( CMD_ARGS )
03096 {
03097 time_t current_time = time(NULL);
03098 ipc_notify(IPC_ONE,IPC_SUMMARY,"Exiting at %.24s", ctime(¤t_time));
03099
03100 if (argc>0)
03101 ipc_exit(IPC_EXIT_NORMAL,argv[0]);
03102 else
03103 ipc_exit(IPC_EXIT_NORMAL,"Exited via quit command");
03104
03105 return CMD_NO_ERROR;
03106 }
03107
03108
03109
03110 cmdstat cmd_clear_hooks( CMD_ARGS )
03111 {
03112 int status=CMD_NO_ERROR;
03113 HooklistNum hooklist;
03114
03115 if (argc<1)
03116 for (hooklist=0; hooklist<hooklists.num; hooklist++) {
03117 if (hooklists.lists[hooklist].num) {
03118 hooklists_empty_list(hooklist);
03119 ipc_notify(IPC_ONE,IPC_STD,"Emptied hooklist %s",hooklists.lists[hooklist].name);
03120 }
03121 }
03122 else {
03123 int i,arg;
03124
03125 for (arg=0; arg<argc; arg++) {
03126 hooklist = Uninitialized;
03127
03128
03129 for (i=0; i<hooklists.num; i++)
03130 if (!strncmp(hooklists.lists[i].name,argv[arg],HOOKLIST_MAX_NAME_LENGTH))
03131 hooklist=i;
03132
03133 if (hooklist==Uninitialized) {
03134 ipc_notify(IPC_ONE,IPC_ERROR,"Hook list is not defined: %s",argv[0]);
03135 status= CMD_PARAMETER_ERROR;
03136 }
03137 else if (hooklists.lists[hooklist].num) {
03138 hooklists_empty_list(hooklist);
03139 ipc_notify(IPC_ONE,IPC_STD,"Emptied hooklist %s",hooklists.lists[hooklist].name);
03140 }
03141 }
03142 }
03143
03144 return status;
03145 }
03146
03147
03148
03149 cmdstat cmd_save_params( CMD_ARGS )
03150 {
03151 (void)argc;
03152 return cmdparam_save_current_state(cmds(argv[0]));
03153 }
03154
03155
03156
03157 cmdstat cmd_exec( CMD_ARGS )
03158 {
03159 int status=0;
03160
03161 for (int i=0; i<argc; i++) {
03162 int newstatus = cmddefs_exec_str(cmds(argv[i]));
03163 if (newstatus>=0) status=newstatus;
03164 }
03165
03166 return status;
03167 }
03168
03169
03170
03171 cmdstat cmd_exec_file( CMD_ARGS )
03172 {
03173 int status;
03174
03175 cmddefs_exec_file_argc = argc-1;
03176 cmddefs_exec_file_argv = (argc>1 ? &argv[1] : NULL);
03177
03178 status=cmddefs_exec_file(cmds(argv[0]));
03179 cmddefs_exec_file_argc=0;
03180
03181 return (status? CMD_FILE_ERROR : CMD_NO_ERROR);
03182 }
03183
03184
03185
03186 cmdstat cmd_call( CMD_ARGS )
03187 {
03188 int status;
03189 const int oldipcverbosity = ipc_msg_level;
03190 const int newipcverbosity = IPC_ALERT;
03191
03192 if (ipc_msg_level > newipcverbosity)
03193 ipc_msg_level = newipcverbosity;
03194
03195 cmddefs_exec_file_argc = argc-1;
03196 cmddefs_exec_file_argv = (argc>1 ? &argv[1] : NULL);
03197
03198
03199 status=cmddefs_exec_file(cmds(argv[0]));
03200 cmddefs_exec_file_argc=0;
03201 if (ipc_msg_level==newipcverbosity)
03202 ipc_msg_level=oldipcverbosity;
03203
03204 return (status? CMD_FILE_ERROR : CMD_NO_ERROR);
03205 }
03206
03207
03208
03210 cmdstat cmd_read_args( CMD_ARGS )
03211 {
03212 (void)argc;
03213 (void)argv;
03214
03215 return (cmddefs_exec_file_argc<1 ? CMD_NO_ERROR :
03216 cmd_set(cmddefs_exec_file_argc,cmddefs_exec_file_argv));
03217 }
03218
03219
03220
03221 cmdstat cmd_define_param( CMD_ARGS )
03222 {
03223 const char* name = argv[0];
03224 const int type = (argc<=1 ? PARAM_DOUBLE : cmdi(argv[1]));
03225 const bool has_lbound = (type == PARAM_STRING ? True : argc>2);
03226 const int lower_bound = (argc>2 ? cmdi(argv[2]) : (type == PARAM_STRING ? 0 : Uninitialized));
03227 const bool has_ubound = (type == PARAM_STRING ? True : argc>3);
03228 const int ub = (argc>3 ? cmdi(argv[3]) : Uninitialized);
03229 const int upper_bound = (type==PARAM_STRING && ub==Uninitialized ? CMD_MAX_LINE_LENGTH : ub);
03230 const char* helpstring = (argc>4 ? cmds(argv[4]) : NULL);
03231 const bool has_initval = argc>5;
03232 const char* initval = (argc>5 ? argv[5] : NULL);
03233
03234 size_t size = (type == PARAM_STRING ? upper_bound : MAX(sizeof(double),sizeof(int)));
03235 void *pointer = (void *)malloc(size);
03236
03237
03238 if (params_define_param(name, type, False, pointer) == 1) {
03239 if (has_lbound) params_add_lower_bound_int(name,lower_bound);
03240 if (has_ubound) params_add_upper_bound_int(name,upper_bound);
03241 if (helpstring) params_define_doc(name,cmdparam_dupstr(helpstring));
03242 if (cmdparam_changes_verbose)
03243 ipc_notify(IPC_ONE,IPC_STD,"Defined parameter %s",name);
03244 if (has_initval)
03245 cmdparam_set( name, initval );
03246 }
03247
03248 return CMD_NO_ERROR;
03249 }
03250
03251
03252
03253 cmdstat cmd_if( CMD_ARGS )
03254 {
03255 if (cmdi(argv[0]))
03256 return cmddefs_exec_by_name(argv[1],argc-2,&(argv[2]));
03257
03258 return CMD_NO_ERROR;
03259 }
03260
03261
03262
03263 cmdstat cmd_dotimes( CMD_ARGS )
03264 {
03265 int i;
03266 int status = CMD_NO_ERROR;
03267
03268 for (i=0; i<cmdi(argv[0]); i++) {
03269 status = cmddefs_exec_by_name(argv[1],argc-2,&(argv[2]));
03270 if (status) return status;
03271 }
03272
03273 return CMD_NO_ERROR;
03274 }
03275
03276
03277
03278 cmdstat cmd_for( CMD_ARGS )
03279 {
03280 int status = CMD_NO_ERROR;
03281
03282 for (cmd_set(3,&(argv[0])); cmdi(argv[3]); cmd_set(3,&(argv[4]))) {
03283 status = cmddefs_exec_by_name(argv[7],argc-8,&(argv[8]));
03284 if (status) return status;
03285 }
03286
03287 return CMD_NO_ERROR;
03288 }
03289
03290
03291
03292 cmdstat cmd_print( CMD_ARGS )
03293 {
03294 int i;
03295
03296 for (i=0; i<argc; i++)
03297 if (*argv[i] == '$')
03298 ipc_notify(IPC_ONE,IPC_SUMMARY,"%s == %s",argv[i],cmds(argv[i]));
03299 else {
03300 double value = cmdf(argv[i]);
03301 ipc_notify(IPC_ONE,IPC_SUMMARY,"%s == %g",argv[i],value);
03302 }
03303
03304 return CMD_NO_ERROR;
03305 }
03306
03307
03308
03309 cmdstat cmd_system( CMD_ARGS )
03310 {
03311 char str[CMD_MAX_LINE_LENGTH];
03312 char *str_ptr=str;
03313 size_t charsleft=CMD_MAX_LINE_LENGTH-1;
03314 int i;
03315 int status=0;
03316
03317
03318 for(i=0; i < argc; i++){
03319 snprintf(str_ptr,charsleft,"%s%s",(i==0? "" : " "),cmds(argv[i]));
03320 charsleft -= strlen(str_ptr);
03321 str_ptr += strlen(str_ptr);
03322 }
03323
03324 ipc_notify(IPC_ONE,IPC_VERBOSE,"Executing shell command `%s'",str);
03325 if (AMPARENTPE)
03326 status=system(str);
03327
03328 return (status? CMD_MISC_ERROR : CMD_NO_ERROR);
03329 }