00001
00062 #include <string.h>
00063 #include <stdlib.h>
00064 #include <time.h>
00065 #include <ctype.h>
00066 #include <math.h>
00067 #include <string>
00068 using std::string;
00069 #include <stack>
00070 #include <vector>
00071 #include <strstream.h>
00072 #include <fstream>
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 #include "stringutils.h"
00084 #include "polymorph.h"
00085
00086
00087 #ifdef EXPLICIT_INSTANTIATION_FOR_STATICS
00088 template class PolymorphBase<Tristate>;
00089 template class PolymorphBase<int>;
00090 template class PolymorphBase<double>;
00091 template class PolymorphBase<string>;
00092 template class ParameterDefinition<int>;
00093 #endif
00094
00095
00096
00097
00098
00099
00100
00101
00102 #define PARENTPE (0)
00103 #define AMPARENTPE (ipc_my_process()==PARENTPE)
00104
00105
00106
00107
00108 #define CMDDEF_MAX_NUM 64
00109 #define CMDDEF_MAX_NAME_LENGTH 64
00110 #define CMDDEF_MAX_PREREQS 2
00112
00113 struct CommandDefinition {
00114 char name[CMDDEF_MAX_NAME_LENGTH+1];
00115 CmdWrapper* function;
00116 int minargs;
00117 int catchup;
00118 int num_prereqs;
00119 int prereqs[CMDDEF_MAX_PREREQS];
00120 int callstatus;
00121 const char *usage;
00122 const char *doc;
00127 BlackboardType* params;
00128 BlackboardType& parameters() { assert(params); return *params; }
00129 ~CommandDefinition() { delete params; }
00130 };
00131
00132
00133 typedef struct{
00134 int num;
00135 CommandDefinition list[CMDDEF_MAX_NUM];
00136 }CommandDefinitionBlackboard;
00137
00138
00139 typedef struct{
00140 int argc;
00141 const char *argv[CMD_MAX_ARGUMENTS];
00142 CommandDefinition* def;
00143 }Command;
00144
00145 #define CMD_CALL(cmd) (*((cmd).def->function))((cmd).argc, (cmd).argv)
00146
00147
00148
00149
00150
00151 typedef struct
00152 {
00153 int start;
00154 int end;
00155 int step;
00157 int order;
00158 char *argstofree[CMD_MAX_ARGUMENTS+1];
00159 Command cmd;
00160 } CounterHookDefinition;
00161
00162 #define HOOKLIST_MAX_NUM 128
00163 #define HOOKLIST_MAX_NAME_LENGTH 32
00164
00165
00166 typedef struct
00167 {
00168 char name[HOOKLIST_MAX_NAME_LENGTH];
00169 char countername[HOOKLIST_MAX_NAME_LENGTH];
00170 int current;
00171 int num;
00172 CounterHookDefinition defs[HOOKLIST_MAX_NUM];
00173 } CounterHooklist;
00174
00175 #define HOOKLISTS_MAX_NUM 4
00176
00177 #define HAS_CURRENT_HOOK(hooklist) ((hooklist).current < (hooklist).num)
00178 #define CURRENT_HOOK(hooklist) ((hooklist).defs[(hooklist).current])
00179
00180
00181 typedef struct
00182 {
00183 int num;
00184 CounterHooklist lists[HOOKLISTS_MAX_NUM];
00185 } CounterHooklists;
00186
00187
00188
00189
00190
00191 typedef struct
00192 {
00193 int num;
00194 const char* names[CMDDEF_MAX_NUM*CMDDEF_MAX_PREREQS];
00195 const char* prereqs[CMDDEF_MAX_NUM*CMDDEF_MAX_PREREQS];
00196 } PrereqList;
00197
00198
00199
00200
00201
00202
00203
00204 CounterHooklists hooklists;
00205
00206 BlackboardType global_blackboard;
00207 BlackboardType* blackboard_ptr=&global_blackboard;
00208 BlackboardType blackboard_for_commands(&blackboard,"cmd");
00209 CommandDefinitionBlackboard command_definitions;
00211 int commands_succeeded = 0;
00212 int commands_failed = 0;
00213 int command_num_called = 0;
00214
00215 int hook_definition_counter=0;
00216 int cmdparam_warn_unknown=true;
00217 double command_msg_time=1.0;
00218
00219
00220 FILE *cmddefs_file=NULL;
00221 string commandpath = "../command/ ../../command/ ../samples/ ../ /usr/local/lissom/command/";
00222
00223
00224 std::stack<StringParser::arglist> cmddefs_exec_file_arglists;
00226 char cmddefs_line_buffer[CMD_MAX_LINE_LENGTH+1+sizeof(int)];
00227
00228 PrereqList prereq_storage;
00229
00230
00231 #ifndef NO_SIGNAL_HANDLING
00232 typedef void (*signal_handler_type)(int);
00233 sigjmp_buf jmp_env;
00234 #endif
00235
00236
00237
00238
00239
00240
00241
00242 CMD_DECLARE(call);
00243 CMD_DECLARE(clear_hooks);
00244 CMD_DECLARE(define_param);
00245 CMD_DECLARE(define_param_set);
00246 CMD_DECLARE(select_param_set);
00247 CMD_DECLARE(param_default);
00248 CMD_DECLARE(dotimes);
00249 CMD_DECLARE(exec);
00250 CMD_DECLARE(exec_catchup);
00251 CMD_DECLARE(exec_file);
00252 CMD_DECLARE(for);
00253 CMD_DECLARE(hook);
00254 CMD_DECLARE(if);
00255 CMD_DECLARE(echo);
00256 CMD_DECLARE(print);
00257 CMD_DECLARE(quit);
00258 CMD_DECLARE(read_args);
00259 CMD_DECLARE(set);
00260 CMD_DECLARE(system);
00261
00262 size_t cmdparam_identifier_length(const char* str);
00263 void ipc_init_hook( void );
00264
00265 int cmddef_compare(const void* hook1, const void* hook2);
00266 void cmddefs_sort(void);
00267 int cmddefs_get_line_from_file( void );
00268
00269 int command_check_usage(Command* command);
00270 cmdstat command_exec(Command *cmd);
00271 CommandDefinition* cmddefs_lookup(const char *name);
00272 int command_parse_line(Command *command, char *string);
00273 const char* command_parse_token(char** remaining);
00274 void command_print_to_str( const Command *cmd, char *str, size_t nchars);
00275 void cmddef_print_usage(FILE *fp, const CommandDefinition* cmddef);
00276 void cmddef_print_usage_to_str(const CommandDefinition* cmddef, char *str, size_t nchars);
00277 void cmddefs_activate_prereqs( void );
00278 void cmddefs_activate_command_prereq( const char* name, const char *prereq );
00279
00280 int hook_compare(const void* hook1, const void* hook2);
00281 void hook_copy( CounterHookDefinition *source, CounterHookDefinition *dest);
00282 void hooklists_log(void);
00283 int hook_parse_specifier( CounterHookDefinition *hook, Parse& parser );
00284 void hook_print_to_str( CounterHookDefinition *hook, char *hooklistname, char *str, size_t nchars);
00285 void hooklists_sort(HooklistNum hooklist);
00286
00287
00288
00289 #ifndef NO_SIGNAL_HANDLING
00290 void command_exec_sigint_handler( int sig );
00291 #endif
00292
00293
00294
00295
00296
00297
00298
00303 void cmdparam_init_hook( void )
00304 {
00305 ipc_init_hook();
00306
00307
00308
00309 CMD_DOC(clear_hooks,NULL,0,"%s [<hook_list>]*",
00310 "Delete all the currently-defined hooks in the given list(s), or delete\n"
00311 "all hooks in all lists if no lists are specified.");
00312
00313 CMD_DOC(define_param,NULL,2,"%s [<path>::]<name> <type> [<lowbound> [<highbound> [<helpstring>] [<initialvalue>]]]",
00314 "Define a new parameter of the given type. Space for the parameter is\n"
00315 "immediately allocated from the heap, but it is not initialized until\n"
00316 "the parameter is set unless an initial value is supplied. Available <types>\n"
00317 "include Integer, Float, Boolean, and String. The <highbound> is ignored if\n"
00318 "it is lower than the <lowbound>. Calling this command multiple times for\n"
00319 "the same <name> is not an error unless the type differs, but the bounds,\n"
00320 "<helpstring>, and <initialvalue> are only installed on the first call.\n"
00321 "Note: The <lowbound> and <highbound> are currently truncated to integers,\n"
00322 "but for Float parameters this restriction may be relaxed in future");
00323
00324 CMD_DOC(define_param_set,NULL,1,"%s [<path>::]<name>",
00325 "Define a new set of parameters rooted at the given path, which defaults to\n"
00326 "the global set of parameters. Useful in e.g. scripts to avoid conflicts\n"
00327 "with any global parameters that may be defined. Calling this command\n"
00328 "multiple times with the same arguments> is not an error, but has no effect.");
00329
00330 CMD_DOC(select_param_set,NULL,0,"%s [<path>::]",
00331 "Make the specified set of parameters (previously defined with\n"
00332 "define_param_set) be the default for all operations. With no arguments makes\n"
00333 "the previous parameter set (or root if none) be the default.");
00334
00335 CMD_DOC(param_default,NULL,2,"%s <name> <expression>",
00336 "For a existing parameter <name>, declare that if the user has not explicitly\n"
00337 "set this parameter (using the set command) by the time init_network\n"
00338 "is called, the program should then evaluate the given expression (i.e.\n"
00339 "anything accepted by the set command) to determine the value for that\n"
00340 "parameter.\n\n"
00341
00342 "The global order of evaluation of default expressions is undefined, and thus\n"
00343 "no expression should refer to any other parameter that also has a default\n"
00344 "expression defined. (In that case the resulting values would depend on the\n"
00345 "order of evaluation of the default expressions, and would be undefined.)");
00346
00347 CMD_DOC(dotimes,NULL,2,"%s <expr> <command> [<argument>]*",
00348 "Execute the given command with the given arguments, the number of times\n"
00349 "specified by the given numeric expression.");
00350
00351 CMD_DOC(for,NULL,3,"%s <param>=<initvalue> <test-expr> <param>=<incrementvalue> [<command> [<argument>]*]",
00352 "Execute the given command with the given arguments a number of times.\n"
00353 "First, the first param-value pair is passed to the set command, then as\n"
00354 "long as the numeric <test-expr> evaluates to a true value, the given command\n"
00355 "is executed and the second param-value pair is passed to the set command.\n"
00356 "Example: `define_param angle Param_Integer', then\n"
00357 "`for angle=0 angle<180 angle=angle+10 print angle'.");
00358
00359 CMD_DOC(if,NULL,2,"%s <expr> <command> [<argument>]*",
00360 "If the given numeric expression evaluates to a non-zero value, execute\n"
00361 "the given command with the given arguments.");
00362
00363 CMD_DOC(call,NULL,1,"%s <filename> [<param>=<value>]*",
00364 "Same as exec_file, but suppresses verbose parameter change and other\n"
00365 "messages. This is intended for calling a file as a procedure, where only\n"
00366 "error reporting is usually desired. The output would otherwise be very\n"
00367 "verbose if the file contains a long loop or calls other files repeatedly.");
00368
00369 CMD_DOC(exec_file,NULL,1,"%s <filename> [<param>=<value>]*",
00370 "Execute the given command file. The parameter settings included on the\n"
00371 "command line will be saved but not evaluated until a read_args command\n"
00372 "is called within the command file. Also see the help for read_args.");
00373
00374 CMD_DOC(exec,NULL,1,"%s [<command-string>]*",
00375 "Execute the commands specified by the given strings, in order. Before being\n"
00376 "executed, each string is interpreted for string substitutions as for the set\n"
00377 "command for string parameters, so it's possible to use constructions like\n"
00378 "`exec \"${command}\" \"set x=y\"'.");
00379
00380 CMD_DEFINE_CATCHUP(1,exec_catchup,"%s [<command-string>]*",
00381 "Same as exec, but never skipped when catching up to a new iteration. Useful\n"
00382 "to force execution of a hook which would otherwise be skipped.");
00383
00384 CMD_DOC(echo,NULL,1,"%s <string>*",
00385 "Displays the given strings, each on a new line, after string substitution.");
00386
00387 CMD_DOC(print,NULL,1,"%s <expression>*",
00388 "Displays the value of the given expression(s), which can either be the name of\n"
00389 "any parameter (preceded by a dollar sign (`$') if desired), or an arbitrary\n"
00390 "numeric expression allowed as a <value> by the set command. Examples: \n"
00391 "`print filename', `print 2*radius-1'.");
00392
00393 CMD_DOC(read_args,NULL,0,"%s [<parent>]",
00394 "If called within a file executed using the exec_file or call commands,\n"
00395 "evaluates the arguments supplied when the file was originally called (if any).\n"
00396 "The evaluation is done using the set command, called within the <parent>'s\n"
00397 "set of parameters. This command provides a rudimentary form of argument\n"
00398 "passing to allow command files to be used like procedures. Trivial example\n"
00399 "(e.g. in a file named `countup.command'):\n\n"
00400
00401 " define_param n Param_Integer # Declare argument(s)\n"
00402 " set n=10 # Default value\n"
00403 " read_args # Read argument(s)\n\n"
00404
00405 " define_param i Param_Integer # Declare global variable to be used as a local\n"
00406 " for i=0 i<n i=i+1 print i # Actually do something\n\n"
00407
00408 "If this file is called as `exec_file countup.command n=5', it will print\n"
00409 "out the numbers less than 5 (amidst various \"helpful\" debugging messages).\n"
00410 "Of course, since all parameters are currently globals, be careful\n"
00411 "not to assume the procedures act like safer ones offered by a more powerful\n"
00412 "language.");
00413
00414
00415
00416
00417
00418
00419
00420
00421 CMD_DEFINE_CATCHUP(1,set,"[%s] [[[::]<path>::]<name>=<value>]+",
00422 "Allows any parameter to be set to an arbitrary value, within the type\n"
00423 "and range of that parameter. The keyword 'set' can be omitted. \n"
00424 "Multiple pairs of names and values are acceptable as long as the\n"
00425 "CMD_MAX_ARGUMENTS limit is not reached. Values may not contain spaces\n"
00426 "unless the entire triple ('x=y') or the value (x='y') are enclosed in\n"
00427 "quotes. The path may contain the name of a particular set of parameters\n"
00428 "to use; it is often omitted, in which case the global set is used.\n"
00429 "Parameter set names in the path may start and/or end with a wildcard\n"
00430 "('*'), in which case all sets of parameters matching at that level\n"
00431 "are searched for parameters to set. If the path starts with :: the\n"
00432 "value is searched from the toplevel (root) parameter set.\n\n"
00433
00434 "If the <value> is surrounded by backquotes (`...`), it is evaluated for\n"
00435 "string substitution and then passed to the system shell as a command, and\n"
00436 "the output of that command is used as the <value> instead. This evaluation\n"
00437 "requires a temporary file, and is not truly multi-processor or multi-process\n"
00438 "safe because the file names from different processes may (in rare cases)\n"
00439 "conflict.\n\n"
00440
00441 "The <value> for a parameter of String type may contain references to\n"
00442 "other parameters if preceded by a dollar sign (`$') and (optionally)\n"
00443 "enclosed in braces. Non-string parameter values are printed to a\n"
00444 "simple string representation. Example: `set filename=\n"
00445 "${filename}_${angle}_A' might set it to `oldname_76.5_A'.\n\n"
00446
00447 "If you wish to control the printing format used, you may supply\n"
00448 "flags in approximately the format accepted by the C printf command\n"
00449 "for the appropriate datatype, just before the parameter name. Example:\n"
00450 "`set filename=${filename}_${06.2angle}_A' might set it to\n"
00451 "`oldname_076.50_A', if angle is 76.5.\n\n"
00452
00453 "As an extension to the C printf-style formatting, conditional text\n"
00454 "expansion is supported. Given a value like `${?param,text}', the\n"
00455 "expansion will be `text' unless `param' is numeric and zero, or\n"
00456 "non-numeric and expanding to the empty string. If `,text' is omitted,\n"
00457 "the expansion will be the parameter value itself. Example:\n"
00458 "`set filename=${filename}${?plotname,_}${plotname}' might set the\n"
00459 "filename to `oldname_Plot', if plotname is Plot, or `oldname' if\n"
00460 "plotname is "". Or `set filename=${filename}${?angle,_}${?06.2angle}_A'\n"
00461 "might set filename to `oldname_076.50_A', if angle is 76.5, or `oldname_A'\n"
00462 "if angle is zero.\n\n"
00463
00464 "The <value> for numeric types (Integer, Float, and Boolean) may be an\n"
00465 "expression matching the following (recursive) grammar:\n\n"
00466
00467 " <term> == <number>|<paramname>|(<value>)\n"
00468 " <value> == <term>[<binop><value>]\n"
00469 " <binop> == +|-|*|/|%|<|>|==|!=|<=|>=|<?|>?|@;|@:\n\n"
00470
00471 "Thus a literal numeric value will suffice, or else an infix arithmetic\n"
00472 "expression like `RN' or `i/2' or `RN/2.5*(N-1)' or `RN%8' can be used,\n"
00473 "where i, RN, and N are parameters whose current value will be substituted\n"
00474 "before evaluation.\n\n"
00475
00476 "The operators <binop> are as defined in ANSI C, except as noted here and\n"
00477 "below. The >? and <? operators are borrowed from GNU C++; they take the\n"
00478 "maximum and the minimum of their arguments, respectively. The @; and @:\n"
00479 "operators were invented as a bizarre but useful hack; they multiply the\n"
00480 "left argument by the sine or cosine of the right argument, respectively.\n\n"
00481
00482 "The `*', `/', and `%%' operators are equal in precedence and are greater\n"
00483 "in precedence than all the others; otherwise evaluation occurs from left\n"
00484 "to right. Thus simple arithmetic expressions will have the same\n"
00485 "interpretation as in C, but parentheses should be used liberally on\n"
00486 "anything complicated (particularly for comparisons) to ensure that they\n"
00487 "are calculated correctly.\n\n"
00488
00489 "All intermediate numeric results are of type double (or long double,\n"
00490 "if available), which is then rounded (not truncated) to an integer.\n"
00491 "Thus expression values involving e.g. integer division may differ from\n"
00492 "their C equivalents, but this is usually an improvement.\n\n"
00493
00494 "Boolean variables have numeric types, but the symbolic values True,\n"
00495 "False, Yes, No, and Uninitialized are accepted as standing for 1,0,1,0,\n"
00496 "and -1, respectively. Boolean expressions like ((x<0)||(x>N))&&C can be\n"
00497 "computed by writing their arithmetic equivalent, e.g. `((x<0)+(x>N))*C',\n"
00498 "as long as none of the Boolean variables are Uninitialized.");
00499
00500 CMD_DOC(system,NULL,1,"%s <shell-command> [<shell-command-arg>]*",
00501 "Execute the given system shell command (e.g. `ls -l file'). Arguments\n"
00502 "which require quoting should be enclosed in single quotes surrounded by\n"
00503 "double quotes, e.g. `ls -l \"'file with spaces'\"', or vice versa.\n"
00504 "Parameter values may be used in arguments if preceded by a dollar sign, as\n"
00505 "for string parameters in the `set' command. Consequently, shell variables\n"
00506 "cannot be used in arguments; if this were to present a problem, \n"
00507 "the system command (or cmdi) could be rewritten to suppress variable\n"
00508 "substitution if it detects embedded single quotes.");
00509
00510 CMD_DOC(quit,NULL,0,"%s [<exit-message>]",
00511 "Exit from the program with no error condition.");
00512
00513 CMD_DEFINE_CATCHUP(3,hook,"%s <hook_list> <counter_specifier> <command> [<argument>]*",
00514 "This command allows you to specify that the given command should be\n"
00515 "executed at location <hook_list> when a counter reaches the value\n"
00516 "specified by the <counter_specifier>, where the <counter_specifier>\n"
00517 "is of the (recursive) form:\n\n"
00518
00519 " <counter_start>[-<counter_end>[%<step>]][,<counter_specifier>]\n\n"
00520
00521 "For example, the <counter_specifier> can be\n"
00522 "a single value ((e.g. 1000), a range of values (e.g. 1-1000), a\n"
00523 "range with a stepsize (e.g. 1-1000%%10), or a list of any of these\n"
00524 "(e.g. 1,10,100-200%%20,7,50-60).\n\n"
00525
00526 "For a given hook_list and counter value, all the hooks that apply\n"
00527 "are executed in the order of their counter_start and (if those\n"
00528 "match) the order in which they were defined.");
00529
00530
00531 PARAM_N(PARAM_USTRING,commandpath,
00532 "Space-separated list of paths to search for command files. The current\n"
00533 "directory is always searched first.");
00534
00535 PARAM_N(PARAM_DOUBLE,command_msg_time,
00536 "If a command takes longer than this time (in seconds) to execute, the time\n"
00537 "taken will be displayed when the command completes.");
00538
00539 PARAM_L(PARAM_INT, command_num_called,0,
00540 "Read-only parameter returning the number of commands called so far this\n"
00541 "run; is incremented whenever a command is executed. Primarily useful for\n"
00542 "constructing the command prompt.");
00543
00544 PARAM_A(blackboard,"squote",string("'"),,
00545 "Read-only parameter holding a single quote mark ('); used for hairy string\n"
00546 "substitution tricks.");
00547
00548 PARAM_A(blackboard,"dquote",string("\""),,
00549 "Read-only parameter holding a double quote mark (\"); used for hairy string\n"
00550 "substitution tricks.");
00551
00552 blackboard.init_hook();
00553 ipc_init_hook();
00554
00555
00556 Polymorph<Tristate>::set_typestring("Boolean");
00557 Polymorph<int>::set_typestring("Integer");
00558 Polymorph<double>::set_typestring("Float");
00559 Polymorph<string>::set_typestring("String");
00560
00561
00562
00563
00564
00565
00566 cmddefs_sort();
00567 cmddefs_activate_prereqs();
00568
00569
00570
00571 }
00572
00573
00574
00579 void ipc_init_hook( void )
00580 {
00581 PARAM_I(PARAM_INT, ipc_msg_level, IPC_NONE,IPC_OVERWHELM, ipc_msg_level_docstring);
00582 PARAM_I(PARAM_INT, ipc_msg_forceall_level, IPC_NONE,IPC_OVERWHELM, ipc_msg_forceall_level_docstring);
00583 PARAM_I(PARAM_INT, ipc_msg_synch_level, IPC_NONE,IPC_OVERWHELM, ipc_msg_synch_level_docstring);
00584 PARAM_L(PARAM_INT, ipc_exit_on_error_num,0, ipc_exit_on_error_num_docstring);
00585 PARAM_L(PARAM_INT, ipc_max_warnings,0, ipc_max_warnings_docstring);
00586 PARAM_L(PARAM_INT, ipc_max_errors,0, ipc_max_errors_docstring);
00587
00588 CONST_I(IPC_None, IPC_NONE, False,
00589 "Symbol representing `no message'. Ordinarily, no message should be declared\n"
00590 "with a level this high, and then this level may be used to turn off all\n"
00591 "messages.");
00592
00593 CONST_I(IPC_Error, IPC_ERROR, False,
00594 "Symbol representing `error message'. It should be used for a fairly serious\n"
00595 "problem, e.g. one which causes the current computation to be aborted.");
00596
00597 CONST_I(IPC_Warning, IPC_WARNING, False,
00598 "Symbol representing `warning message'. It should be used for a condition\n"
00599 "that is clearly bad but which won't stop computation from proceeding, e.g.\n"
00600 "if a meaningful default value can be used in place of an out-of-range\n"
00601 "parameter.");
00602
00603 CONST_I(IPC_Caution, IPC_CAUTION, False,
00604 "Symbol representing `caution message'. It should be used for a condition that\n"
00605 "is probably bad but which is common enough not to be worth tabulating in total\n"
00606 "warning counts.");
00607
00608 CONST_I(IPC_Alert, IPC_ALERT, False,
00609 "Symbol representing `alert message'. It is primarily a placeholder, marking\n"
00610 "all higher message levels as being in the `alert' category instead of merely\n"
00611 "informational. It may also be used for any particularly important message\n"
00612 "which should almost never be suppressed.");
00613
00614 CONST_I(IPC_Requested, IPC_REQUESTED,False,
00615 "Symbol representing `user-requested message'. It should be used for messages\n"
00616 "that a user has requested specifically, and thus which should not ordinarily\n"
00617 "be turned off.");
00618
00619 CONST_I(IPC_Summary, IPC_SUMMARY, False,
00620 "Symbol representing `summary message'. It should be used for messages that\n"
00621 "are particularly important but which do not report an anomalous condition.");
00622
00623 CONST_I(IPC_Std, IPC_STD, False,
00624 "Symbol representing `standard message'. It should be used for messages that\n"
00625 "a user will probably want to see for every run.");
00626
00627 CONST_I(IPC_Verbose, IPC_VERBOSE, False,
00628 "Symbol representing `verbose message'. It should be used for messages which\n"
00629 "a user will probably want to see only when requested.");
00630
00631 CONST_I(IPC_Overwhelm, IPC_OVERWHELM,False,
00632 "Symbol representing `overwhelming amount of messages'. It should be used\n"
00633 "for debugging messages and similar trivia that may generate a lot of output.");
00634 }
00635
00636
00637
00638
00639
00640
00641
00642
00643
00644
00645
00646
00648 void cmddefs_define_command( const char* name, CmdWrapper* function, int minargs, int exec_for_catchups )
00649 {
00650 if (command_definitions.num >= CMDDEF_MAX_NUM)
00651 ipc_notify(IPC_ONE,IPC_WARNING,"Command blackboard is full; can't add entry for %s",name);
00652 else if (strlen(name)!=cmdparam_identifier_length(name))
00653 ipc_notify(IPC_ALL,IPC_WARNING,"Invalid characters in command name; can't define it");
00654 else if (minargs > CMD_MAX_ARGUMENTS)
00655 ipc_notify(IPC_ONE,IPC_ERROR,"Command %s expects too many arguments (%d > %d); can't define it",
00656 name, minargs,(int)CMD_MAX_ARGUMENTS);
00657 else {
00658 CommandDefinition& newcmd = command_definitions.list[command_definitions.num];
00659 strncpy(newcmd.name, name,CMDDEF_MAX_NAME_LENGTH);
00660 newcmd.function = function;
00661 newcmd.minargs = minargs;
00662 newcmd.catchup = exec_for_catchups;
00663 newcmd.usage = NULL;
00664 newcmd.doc = NULL;
00665 newcmd.num_prereqs = 0;
00666 newcmd.callstatus = CMD_NEVER_CALLED;
00667 newcmd.params = new BlackboardType(&blackboard_for_commands,name);
00668 command_definitions.num++;
00669 }
00670 }
00671
00672
00673
00675 void cmddefs_define_command_doc( const char* name, const char *usage, const char *doc )
00676 {
00677 int idx = 0;
00678 int changed = False;
00679
00680
00681 for (idx=command_definitions.num-1; !changed && idx >= 0; idx--)
00682 if (strncmp(name,command_definitions.list[idx].name,CMDDEF_MAX_NAME_LENGTH) == 0) {
00683 command_definitions.list[idx].usage = usage;
00684 command_definitions.list[idx].doc = doc;
00685 changed = True;
00686 }
00687
00688 if (!changed)
00689 ipc_notify(IPC_ONE,IPC_ERROR,"Failed to add documentation to command %s",name);
00690 }
00691
00692
00693
00699 void cmddefs_define_command_prereq( const char* name, const char *prereq )
00700 {
00701 if (!prereq)
00702 return;
00703
00704 if (prereq_storage.num >= CMDDEF_MAX_NUM*CMDDEF_MAX_PREREQS) {
00705 ipc_notify(IPC_ONE,IPC_ERROR,"Prerequisite storage area full; can't add prerequisite %s for command %s",
00706 prereq,name);
00707 return;
00708 }
00709
00710 prereq_storage.names[prereq_storage.num]=name;
00711 prereq_storage.prereqs[prereq_storage.num]=prereq;
00712 prereq_storage.num++;
00713 }
00714
00715
00716
00724 void cmddefs_declare_prereq_status( const char * name, cmdstat status )
00725 {
00726 CommandDefinition* def=cmddefs_lookup(name);
00727 if (def) def->callstatus = status;
00728 }
00729
00730
00731
00732 void cmddefs_activate_prereqs( void )
00733 {
00734 int i;
00735
00736 for (i=0; i< prereq_storage.num; i++)
00737 cmddefs_activate_command_prereq(prereq_storage.names[i],prereq_storage.prereqs[i]);
00738 }
00739
00740
00741
00746 void cmddefs_activate_command_prereq( const char* name, const char *prereq )
00747 {
00748 int idx,pidx;
00749 int changed = False;
00750 int found = False;
00751
00752 if (!prereq)
00753 return;
00754
00755
00756 for (idx=command_definitions.num-1; !changed && idx >= 0; idx--)
00757 if (strncmp(name,command_definitions.list[idx].name,CMDDEF_MAX_NAME_LENGTH) == 0) {
00758 CommandDefinition* cmddef = &(command_definitions.list[idx]);
00759
00760 for (pidx=command_definitions.num-1; !found && pidx >= 0; pidx--)
00761 if (strncmp(prereq,command_definitions.list[pidx].name,CMDDEF_MAX_NAME_LENGTH) == 0) {
00762 found=True;
00763 if (cmddef->num_prereqs >= CMDDEF_MAX_PREREQS)
00764 ipc_notify(IPC_ONE,IPC_ERROR,"Maximum limit on command prerequisites (%d) reached; can't add another",
00765 CMDDEF_MAX_PREREQS);
00766 else {
00767 cmddef->prereqs[cmddef->num_prereqs++]=pidx;
00768
00769 }
00770 }
00771 changed = True;
00772 }
00773
00774 if (!changed)
00775 ipc_notify(IPC_ONE,IPC_ERROR,"Failed to add prerequisite to command %s",name);
00776 }
00777
00778
00779
00784 CommandDefinition* cmddefs_lookup(const char *name)
00785 {
00786 int command_def=0;
00787
00788
00789 while ((command_def < command_definitions.num) &&
00790 (strncmp(name,command_definitions.list[command_def].name,CMDDEF_MAX_NAME_LENGTH) != 0))
00791 command_def++;
00792
00793
00794 if (command_def < command_definitions.num)
00795 return &(command_definitions.list[command_def]);
00796 else {
00797 if (cmdparam_warn_unknown)
00798 ipc_notify(IPC_ONE,IPC_ERROR,"Unknown command: %s",name);
00799 return NULL;
00800 }
00801 }
00802
00803
00804
00805 cmdstat cmddefs_exec_by_name(const char* name, CMD_ARGS)
00806 {
00807 CommandDefinition* def = cmddefs_lookup(name);
00808
00809 if (!def)
00810 return CMD_PARAMETER_ERROR;
00811
00812 else {
00813 Command cmd;
00814 int i;
00815
00816 cmd.def=def;
00817 cmd.argc=argc;
00818 for (i=0; i<argc; i++)
00819 cmd.argv[i]=argv[i];
00820
00821 return command_exec(&cmd);
00822 }
00823 }
00824
00825
00826
00827
00828
00829
00830
00831 char* consume_quote(char** remaining)
00832 {
00833 const char* quotepos=*remaining;
00834 while (*(++(*remaining)) && (**remaining!=*quotepos));
00835 char* end=*remaining;
00836 if (!**remaining) ipc_notify(IPC_ONE,IPC_ERROR,"Unmatched %c",*quotepos);
00837 else (*remaining)++;
00838 return end;
00839 }
00840
00841
00842 inline bool isquote(char character)
00843 { return (character=='"' || character=='\'' || character=='`'); }
00844
00845
00859 const char* command_parse_token(char** remaining)
00860 {
00861 char* start;
00862 char* end;
00863
00864 while (isspace(**remaining)) (*remaining)++;
00865 start=*remaining;
00866 end=*remaining;
00867
00868 switch (**remaining) {
00869
00870 case '\0':
00871 break;
00872
00873 case '#':
00874 while (*(++(*remaining)));
00875 start=end=(*remaining);
00876 break;
00877
00878 case '\"':
00879 start++;
00880 end=consume_quote(remaining);
00881 break;
00882
00883 case '`':
00884 start++;
00885 end=consume_quote(remaining);
00886 break;
00887
00888 case '\'':
00889 start++;
00890 end=consume_quote(remaining);
00891 break;
00892
00893 default:
00894 while (*(++(*remaining)) && !isspace(**remaining) && !isquote(**remaining) && **remaining!='#');
00895 if (isquote(**remaining))
00896 consume_quote(remaining);
00897 end=*remaining;
00898 break;
00899 }
00900
00901
00902 while (isspace(**remaining)) (*remaining)++;
00903 if (**remaining=='#') while (*(++(*remaining)));
00904
00905
00906 if (end) *end='\0';
00907 return start;
00908 }
00909
00910
00911
00922 int command_parse_line(Command *command, char* const cmdtxt)
00923 {
00924 bool seterror=false;
00925 bool paramsset=false;
00926 char* remaining=cmdtxt;
00927
00928
00929 const char* name = command_parse_token(&remaining);
00930
00931
00932 while (cmdparams_set_single(blackboard,name,seterror)) {
00933 paramsset=true;
00934 name = command_parse_token(&remaining);
00935 }
00936 if (seterror) {
00937 commands_failed++;
00938 return 0;
00939 }
00940
00941
00942 if (!*name) {
00943 if (paramsset) commands_succeeded++;
00944 return 0;
00945 }
00946
00947
00948 command->def = cmddefs_lookup(name);
00949 if (!command->def) {
00950 commands_failed++;
00951 return 0;
00952 }
00953
00954
00955 command->argc=0;
00956 while ( (command->argc < CMD_MAX_ARGUMENTS) && *remaining )
00957 command->argv[(command->argc)++]=command_parse_token(&remaining);
00958
00959
00960 if (!command_check_usage(command)) {
00961 commands_failed++;
00962 return 0;
00963 }
00964
00965 return 1;
00966 }
00967
00968
00969
00970 int command_check_usage(Command* command)
00971 {
00972
00973 if (command->argc >= CMD_MAX_ARGUMENTS)
00974 ipc_notify(IPC_ONE,IPC_WARNING,"Argument list may be truncated (limit is %d)",CMD_MAX_ARGUMENTS);
00975 if (command->argc < command->def->minargs) {
00976 char buf[CMD_MAX_LINE_LENGTH];
00977 cmddef_print_usage_to_str(command->def, buf, CMD_MAX_LINE_LENGTH);
00978 ipc_notify(IPC_ONE,IPC_ERROR,"Command %s requires %d arguments but %d supplied",
00979 command->def->name,command->def->minargs,command->argc);
00980 ipc_notify(IPC_ONE,IPC_STD,"Usage: %s",buf);
00981 return 0;
00982 }
00983
00984 return 1;
00985 }
00986
00987
00988
00989 #ifndef NO_SIGNAL_HANDLING
00990 void command_exec_sigint_handler( int sig)
00991 {
00992 (void)sig;
00993
00994 ipc_notify(IPC_ALL,IPC_ERROR,
00995 "Aborting command due to SIGINT; program may now be in an undefined state");
00996 longjmp(jmp_env,CMD_SIGINT_ERROR);
00997 }
00998 #endif
00999
01000
01001
01003 cmdstat command_exec(Command *cmd)
01004 {
01005 time_t end_of_command;
01006 time_t start_of_command;
01007 double elapsed_time;
01008 int command_number=command_num_called++;
01009 char str[CMD_MAX_LINE_LENGTH];
01010 int i;
01011 int status = CMD_NO_ERROR;
01012
01013 if (ipc_msg_level >= IPC_VERBOSE) {
01014 command_print_to_str( cmd, str, CMD_MAX_LINE_LENGTH);
01015 ipc_notify(IPC_ONE,IPC_VERBOSE,"Command %2d (%s) executing",
01016 command_number,str);
01017 }
01018
01019
01020 for (i=0; i< cmd->def->num_prereqs && status >= CMD_NO_ERROR; i++)
01021 if (command_definitions.list[cmd->def->prereqs[i]].callstatus == CMD_NEVER_CALLED) {
01022 Command temp;
01023 temp.def=cmddefs_lookup(command_definitions.list[cmd->def->prereqs[i]].name);
01024 temp.argc=0;
01025 status = command_exec(&temp);
01026 }
01027 else status = command_definitions.list[cmd->def->prereqs[i]].callstatus;
01028
01029
01030
01031 start_of_command = time(NULL);
01032 if (status >= CMD_NO_ERROR) {
01033
01034 #ifdef NO_SIGNAL_HANDLING
01035 status = CMD_CALL(*cmd);
01036 #else
01037
01038 signal_handler_type original_handler =
01039 signal(SIGINT,command_exec_sigint_handler);
01040
01041
01042 if (sigsetjmp(jmp_env,True)==0)
01043
01044 status = CMD_CALL(*cmd);
01045 else
01046
01047 status = CMD_SIGINT_ERROR;
01048
01049
01050 signal(SIGINT,original_handler);
01051 #endif
01052
01053 ipc_notify(IPC_ONE,IPC_VERBOSE,"Command %2d exited with return code %d",
01054 command_number,status);
01055 cmd->def->callstatus = status;
01056 }
01057 else {
01058 ipc_notify(IPC_ONE,IPC_WARNING,"Command %2d not being called due to unsatisfiable prerequisite: %s",
01059 command_number,command_definitions.list[cmd->def->prereqs[i-1]].name);
01060 status = CMD_PREREQ_ERROR;
01061 }
01062
01063
01064 if (status >= CMD_NO_ERROR) {
01065 commands_succeeded++;
01066 }
01067 else
01068 commands_failed++;
01069
01070 ipc_barrier();
01071
01072 end_of_command = time(NULL);
01073 elapsed_time = difftime(end_of_command, start_of_command);
01074
01075 if (elapsed_time > command_msg_time || ipc_msg_level >= IPC_OVERWHELM) {
01076 int elapsed_sec=int(fmod(elapsed_time, 60));
01077 int elapsed_min=int(fmod(elapsed_time/60, 60));
01078 int elapsed_hours=int( elapsed_time/60/60);
01079 if (ipc_msg_level >= IPC_VERBOSE) {
01080 command_print_to_str( &(*cmd), str, CMD_MAX_LINE_LENGTH);
01081 ipc_notify(IPC_ONE,IPC_VERBOSE,"Command %2d (%s) took %g seconds (%d:%02d:%02d), completing %.24s",
01082 command_number, str, (double)elapsed_time,
01083 elapsed_hours,elapsed_min,elapsed_sec,
01084 ctime(&end_of_command));
01085 }
01086 else
01087 ipc_notify(IPC_ONE,IPC_STD,"Command %2d (%s) took %g seconds (%d:%02d:%02d), completing %.24s",
01088 command_number, cmd->def->name, (double)elapsed_time,
01089 elapsed_hours,elapsed_min,elapsed_sec,
01090 ctime(&end_of_command));
01091 }
01092
01093 return status;
01094 }
01095
01096
01097
01099 cmdstat cmddefs_exec_str(const char* cmdtxt)
01100 {
01101 Command cmd;
01102 char buf[CMD_MAX_LINE_LENGTH];
01103
01104
01105 buf[CMD_MAX_LINE_LENGTH-2]=0;
01106 strncpy(buf,cmdtxt,CMD_MAX_LINE_LENGTH);
01107 if (buf[CMD_MAX_LINE_LENGTH-2]!=0)
01108 ipc_notify(IPC_ONE,IPC_ERROR,"Line length exceeded hard-coded limit of %d",int(CMD_MAX_LINE_LENGTH));
01109
01110 if (!command_parse_line(&cmd, buf))
01111 return CMD_EMPTY;
01112
01113 return command_exec(&cmd);
01114 }
01115
01116
01117
01133 int cmddefs_exec_batch(CmdDefs_LineGenerator fn, const char * description)
01134 {
01135 int command_count;
01136 int orig_commands_succeeded=commands_succeeded;
01137 int orig_commands_failed=commands_failed;
01138 static int done;
01139 static unsigned linelength;
01140 time_t current_time;
01141
01142 command_count=0;
01143 done=False;
01144
01145 if (cmdparam_changes_verbose){
01146 current_time = time(NULL);
01147 ipc_notify(IPC_ONE,IPC_SUMMARY,"Command %s execution started %.24s",
01148 description,ctime(¤t_time));
01149 }
01150
01151
01152
01153
01154
01155 while (!done) {
01156
01157
01158 if (AMPARENTPE){
01159 linelength=0;
01160 cmddefs_line_buffer[0]='\0';
01161 done=(*fn)();
01162
01163 if (!done && *cmddefs_line_buffer) {
01164 linelength=strlen(cmddefs_line_buffer);
01165
01166
01167 if (cmddefs_line_buffer[linelength-1] == '\n') {
01168 cmddefs_line_buffer[linelength-1]='\0';
01169 linelength--;
01170 }
01171
01172 if (linelength >= CMD_MAX_LINE_LENGTH)
01173 ipc_notify(IPC_ALL,IPC_WARNING,"Command line may be truncated (limit is %d)",CMD_MAX_LINE_LENGTH);
01174 }
01175 }
01176
01177
01178 ipc_barrier();
01179 ipc_get(&done, IPC_INT, 1, PARENTPE);
01180 ipc_get(&linelength, IPC_UNSIGNED, 1, PARENTPE);
01181 if (!done && linelength>0)
01182 ipc_get((int *)(&cmddefs_line_buffer[0]), IPC_INT, (linelength+1)/sizeof(int)+1, PARENTPE);
01183
01184
01185 ipc_barrier();
01186
01187
01188 if (!done && linelength>0) {
01189 ipc_notify(IPC_ONE,IPC_OVERWHELM,"Parsing command string `%s'",cmddefs_line_buffer);
01190 if (cmddefs_exec_str(cmddefs_line_buffer) != CMD_EMPTY)
01191 command_count++;
01192 }
01193 }
01194
01195 done=False;
01196
01197 current_time = time(NULL);
01198 const bool haderrors = (commands_failed-orig_commands_failed > 0);
01199 if (cmdparam_changes_verbose || haderrors)
01200 ipc_notify(IPC_ONE,(haderrors? IPC_ALERT : IPC_SUMMARY),
01201 "Command %s execution completed %.24s; %d succeeded, %d failed",
01202 description,ctime(¤t_time),
01203 commands_succeeded-orig_commands_succeeded,
01204 commands_failed-orig_commands_failed);
01205
01206 return commands_failed-orig_commands_failed;
01207 }
01208
01209
01210
01213 int cmddefs_get_line_from_file( void )
01214 {
01215 if (!cmddefs_file)
01216 return true;
01217
01218 bool done=false;
01219 char* lastchar=cmddefs_line_buffer;
01220 *lastchar='\\';
01221
01222 while (!done && *lastchar=='\\') {
01223 done = (fgets(lastchar,CMD_MAX_LINE_LENGTH+1,cmddefs_file) == NULL);
01224 lastchar += strlen(lastchar)-2;
01225 if (lastchar < cmddefs_line_buffer) lastchar = cmddefs_line_buffer;
01226 }
01227 return done;
01228 }
01229
01230
01231
01235 int cmddefs_exec_file(const char *filename)
01236 {
01237 char description[255];
01238 int status,nofile=False;
01239 FILE *orig_cmddefs_file=cmddefs_file;
01240
01241 cmddefs_file=0;
01242
01243
01244
01245
01246
01247
01248
01249
01250 if (AMPARENTPE){
01251
01252 cmddefs_file=fopen(filename,"r");
01253
01254
01255 if (!cmddefs_file){
01256 StringParser p;
01257 StringParser::arglist words;
01258 p.parse(commandpath,words);
01259 StringParser::argptr i=words.begin();
01260 while (i!=words.end() && !cmddefs_file) {
01261 const string name = (*i)+filename;
01262 cmddefs_file=fopen(name.c_str(),"r");
01263 i++;
01264 }
01265 }
01266 if (!cmddefs_file){
01267 ipc_notify(IPC_ALL,IPC_ERROR,"Couldn't open command file %s",filename);
01268 nofile=True;
01269 }
01270 }
01271
01272 SNPRINTF(description,255,"file %s",filename);
01273 status = cmddefs_exec_batch(&cmddefs_get_line_from_file,description);
01274
01275 if (cmddefs_file)
01276 fclose(cmddefs_file);
01277
01278 cmddefs_file=orig_cmddefs_file;
01279
01280 return (nofile? CMD_FILE_ERROR : status);
01281 }
01282
01283
01284
01286 int cmddefs_num_total(void)
01287 { return command_definitions.num; }
01288
01289
01290
01295 void command_print_to_str( const Command *cmd, char *str, size_t nchars)
01296 {
01297 int i;
01298 char *str_ptr=str;
01299 size_t charsleft=nchars-1;
01300
01301
01302 SNPRINTF(str_ptr,charsleft,"%s",cmd->def->name);
01303 charsleft -= strlen(str_ptr);
01304 str_ptr += strlen(str_ptr);
01305
01306
01307 for(i=0; i < cmd->argc; i++){
01308 SNPRINTF(str_ptr,charsleft," %s",cmd->argv[i]);
01309 charsleft -= strlen(str_ptr);
01310 str_ptr += strlen(str_ptr);
01311 }
01312 }
01313
01314
01315
01316 void cmddefs_sort(void)
01317 {
01318 qsort(command_definitions.list, command_definitions.num,
01319 sizeof(CommandDefinition), cmddef_compare);
01320 }
01321
01322
01324 int my_strncasecmp(const char *str1, const char *str2, size_t n)
01325 {
01326 for (; n>0 ; n--, str1++, str2++) {
01327 if (toupper(*str1) != toupper(*str2))
01328 return (toupper(*str1) - toupper(*str2));
01329 if (*str1 == '\0') return 0;
01330 }
01331 return 0;
01332 }
01333
01334
01336 int cmddef_compare(const void* def1, const void* def2)
01337 {
01338 return( my_strncasecmp(((const CommandDefinition*)def1)->name,
01339 ((const CommandDefinition*)def2)->name,
01340 CMDDEF_MAX_NAME_LENGTH) );
01341 }
01342
01343
01345 void cmddef_print_usage(FILE *fp, const CommandDefinition* cmddef)
01346 {
01347 if (cmddef->usage)
01348 fprintf(fp,cmddef->usage,cmddef->name);
01349 else {
01350 int i;
01351 fprintf(fp,"%s",cmddef->name);
01352 for (i=0; i< cmddef->minargs; i++)
01353 fprintf(fp," <arg>");
01354 fprintf(fp," [<optional-args>]");
01355 }
01356 }
01357
01358
01360 void cmddef_print_usage_to_str(const CommandDefinition* cmddef, char *str, size_t nchars)
01361 {
01362 if (cmddef->usage)
01363 SNPRINTF(str,nchars,cmddef->usage,cmddef->name);
01364 else {
01365 char *str_ptr=str;
01366 size_t charsleft=nchars-1;
01367 int i;
01368
01369
01370 SNPRINTF(str_ptr,charsleft,"%s",cmddef->name);
01371 charsleft -= strlen(str_ptr);
01372 str_ptr += strlen(str_ptr);
01373
01374
01375 for (i=0; i< cmddef->minargs; i++) {
01376 SNPRINTF(str_ptr,charsleft," <arg%d>",i+1);
01377 charsleft -= strlen(str_ptr);
01378 str_ptr += strlen(str_ptr);
01379 }
01380 SNPRINTF(str_ptr,charsleft," [<optional-args>]");
01381 charsleft -= strlen(str_ptr);
01382 str_ptr += strlen(str_ptr);
01383 }
01384 }
01385
01386
01387
01389 void cmddefs_print_all(FILE *fp)
01390 {
01391 int i;
01392
01393 for(i=0; i< command_definitions.num; i++) {
01394 cmddef_print_usage(fp,&(command_definitions.list[i]));
01395 fprintf(fp,"\n");
01396 }
01397 }
01398
01399
01400
01401 void cmddefs_print_doc_for_index(FILE *fp, int idx)
01402 {
01403 cmddef_print_usage(fp,&(command_definitions.list[idx]));
01404 fprintf(fp,"\n\n");
01405
01406 if (command_definitions.list[idx].doc) {
01407 fprintf(fp,command_definitions.list[idx].doc,
01408 command_definitions.list[idx].name);
01409 fprintf(fp,"\n");
01410 }
01411 else
01412 fprintf(fp,"No further help available.\n");
01413 }
01414
01415
01416
01418 void cmddefs_print_doc(FILE *fp, const char* name)
01419 {
01420 int idx = 0;
01421 int found = False;
01422
01423 for (idx=command_definitions.num-1; !found && idx >= 0; idx--)
01424 if (strncmp(name,command_definitions.list[idx].name,CMDDEF_MAX_NAME_LENGTH) == 0) {
01425 cmddefs_print_doc_for_index(fp,idx);
01426 found = True;
01427 }
01428
01429 if (!found)
01430 ipc_notify(IPC_ONE,IPC_ERROR,"Don't know anything about command %s",name);
01431 }
01432
01433
01434
01435 void cmddefs_print_all_doc(FILE *file)
01436 {
01437 int i;
01438 fprintf(file,"%s\n",BlackboardType::help_separator);
01439 for (i=0; i< cmddefs_num_total(); i++) {
01440 cmddefs_print_doc_for_index(file,i);
01441 fprintf(file,BlackboardType::help_separator);
01442 fprintf(file,"\n");
01443 }
01444 }
01445
01446
01447
01454 char* cmddefs_completion_generator (char *text, int state)
01455 {
01456 static int idx, len;
01457 char *name;
01458
01459
01460
01461
01462
01463 if (!state) {
01464 idx = 0;
01465 len = strlen(text);
01466 }
01467
01468
01469 while (idx < command_definitions.num) {
01470 name = command_definitions.list[idx++].name;
01471 if (strncmp (name, text, len) == 0)
01472 return (cmdparam_dupstr(name));
01473 }
01474
01475 return ((char *)NULL);
01476 }
01477
01478
01479
01480
01481
01482
01483
01484
01506 int hooklists_define_list( const char * listname, const char * countername )
01507 {
01508 if (hooklists.num >= HOOKLISTS_MAX_NUM) {
01509 ipc_notify(IPC_ONE,IPC_ERROR,"Maximum number of hook lists reached");
01510 return CMD_PARAMETER_ERROR;
01511 }
01512
01513 strncpy(hooklists.lists[hooklists.num].name,listname,HOOKLIST_MAX_NAME_LENGTH);
01514 strncpy(hooklists.lists[hooklists.num].countername,countername,HOOKLIST_MAX_NAME_LENGTH);
01515 hooklists.lists[hooklists.num].current=0;
01516 hooklists.num++;
01517
01518 return hooklists.num - 1;
01519 }
01520
01521
01522
01523
01524
01525
01526
01527
01528
01529
01530
01531
01532
01533
01534
01535
01536
01537
01538
01539
01540
01541
01542
01543
01544
01545
01546
01547
01548
01549
01550 #define nexthooknum (hooklists.lists[hooklist].num)
01551 cmdstat cmd_hook( CMD_ARGS )
01552 {
01553 int i;
01554 HooklistNum hooklist=Uninitialized;
01555 CounterHookDefinition* hook = NULL;
01556 const char *specifier=argv[1];
01557
01558
01559 for (i=0; i<hooklists.num; i++)
01560 if (!strncmp(hooklists.lists[i].name,argv[0],HOOKLIST_MAX_NAME_LENGTH))
01561 hooklist=i;
01562
01563 if (hooklist==Uninitialized) {
01564 ipc_notify(IPC_ONE,IPC_ERROR,"Hook list is not defined: %s",argv[0]);
01565 return CMD_PARAMETER_ERROR;
01566 }
01567
01568 if (nexthooknum >= HOOKLIST_MAX_NUM) {
01569 ipc_notify(IPC_ONE,IPC_ERROR,"Reached limit for number of counter hooks");
01570 return CMD_PARAMETER_ERROR;
01571 }
01572
01573 hook = &(hooklists.lists[hooklist].defs[nexthooknum]);
01574 hook->order=hook_definition_counter++;
01575
01576
01577 {
01578 CommandDefinition* def = cmddefs_lookup(argv[2]);
01579 if (!def) return CMD_PARAMETER_ERROR;
01580 hook->cmd.def = def;
01581 }
01582
01583
01584 hook->cmd.argc = argc-3;
01585 for (i=0; i< argc-3; i++) {
01586 hook->argstofree[i] = cmdparam_dupstr(argv[i+3]);
01587 hook->cmd.argv[i] = hook->argstofree[i];
01588 }
01589 hook->argstofree[i]=NULL;
01590
01591 if (!command_check_usage(&(hook->cmd)))
01592 return CMD_PARAMETER_ERROR;
01593
01594 if (hook->cmd.def->minargs > argc-3)
01595 ipc_notify(IPC_ONE,IPC_WARNING,"Command %s in hook requires %d args but only %d supplied");
01596
01597
01598 Parse parser(blackboard, specifier);
01599 while (!parser.empty()) {
01600
01601
01602 if (!hook_parse_specifier( hook, parser)) {
01603 ipc_notify(IPC_ONE,IPC_ERROR,"Could not parse counter specifier");
01604 return CMD_PARAMETER_ERROR;
01605 }
01606 nexthooknum++;
01607
01608
01609 if (ipc_msg_level >= IPC_VERBOSE) {
01610 char str[CMD_MAX_LINE_LENGTH];
01611 command_print_to_str(&(hook->cmd),str,CMD_MAX_LINE_LENGTH);
01612 ipc_notify(IPC_ONE,IPC_VERBOSE,"Defined counter_hook %d-%d%%%d %s",
01613 hook->start,hook->end,hook->step,str);
01614 }
01615
01616
01617 if (*specifier) {
01618 if (nexthooknum >= HOOKLIST_MAX_NUM) {
01619 ipc_notify(IPC_ONE,IPC_ERROR,"Reached limit for number of counter hooks");
01620 return CMD_PARAMETER_ERROR;
01621 }
01622
01623 hook_copy( hook, &(hooklists.lists[hooklist].defs[nexthooknum]));
01624 hook = &(hooklists.lists[hooklist].defs[nexthooknum]);
01625 }
01626 }
01627
01628
01629
01630 hooklists_sort(hooklist);
01631
01632 return CMD_NO_ERROR;
01633 }
01634
01635
01636
01638 int hook_parse_specifier( CounterHookDefinition *hook, Parse& parser )
01639 {
01640 hook->step = 1;
01641
01642
01643 hook->start = hook->end = (int)ROUND(parser.getnumericval());
01644 if (hook->start < 0) return False;
01645 if (parser.empty()) return True;
01646
01647
01648 if (parser.consumeifpresent("-")) {
01649 if (parser.empty()) return False;
01650 hook->end = (int)ROUND(parser.getnumericval());
01651 if (hook->end < 0) return False;
01652 }
01653 if (parser.empty()) return True;
01654
01655
01656 if (parser.consumeifpresent("%")) {
01657 if (parser.empty()) return False;
01658 int num = (int)ROUND(parser.getnumericval());
01659 if (num < 1) return False;
01660 hook->step = num;
01661 }
01662 if (parser.empty()) return True;
01663
01664
01665 if (parser.consumeifpresent(",")) {
01666 if (parser.empty()) return False;
01667 }
01668 else
01669 if (!parser.empty())
01670 return False;
01671
01672 return True;
01673 }
01674
01675
01676
01678 void hook_copy( CounterHookDefinition *source, CounterHookDefinition *dest)
01679 {
01680 int i;
01681
01682
01683 dest->cmd.def = source->cmd.def;
01684
01685
01686 dest->cmd.argc = source->cmd.argc;
01687 for (i=0; i< source->cmd.argc; i++)
01688 dest->cmd.argv[i] = source->cmd.argv[i];
01689 dest->argstofree[0]=NULL;
01690
01691
01692 dest->start = source->start;
01693 dest->end = source->end;
01694 dest->step = source->step;
01695
01696
01697 dest->order = source->order;
01698 }
01699
01700
01701
01706 void hooklists_sort(HooklistNum hooklist)
01707 {
01708 qsort(&(CURRENT_HOOK(hooklists.lists[hooklist])),
01709 hooklists.lists[hooklist].num - hooklists.lists[hooklist].current,
01710 sizeof(CounterHookDefinition),
01711 hook_compare);
01712 }
01713
01714
01715
01718 int hook_compare(const void* hook1, const void* hook2)
01719 {
01720 const CounterHookDefinition* h1=(const CounterHookDefinition*)hook1;
01721 const CounterHookDefinition* h2=(const CounterHookDefinition*)hook2;
01722
01723 return ( h1->start == h2->start ?
01724 h1->order - h2->order :
01725 h1->start - h2->start );
01726 }
01727
01728
01729
01739 void hooklists_run_list(HooklistNum hooklist, int counter, int catchuponly)
01740 {
01741 int i;
01742
01743
01744 if (!HAS_CURRENT_HOOK(hooklists.lists[hooklist]))
01745 return;
01746
01747
01748 if (counter < CURRENT_HOOK(hooklists.lists[hooklist]).start)
01749 return;
01750
01751
01752
01753
01754
01755
01756
01757
01758
01759
01760
01761
01762
01763 for (; (HAS_CURRENT_HOOK(hooklists.lists[hooklist])) &&
01764 (counter > CURRENT_HOOK(hooklists.lists[hooklist]).end);
01765 hooklists.lists[hooklist].current++)
01766 if ( ( CURRENT_HOOK(hooklists.lists[hooklist]).end != counter-1) &&
01767 ( CURRENT_HOOK(hooklists.lists[hooklist]).cmd.def->catchup ) )
01768 command_exec(&(CURRENT_HOOK(hooklists.lists[hooklist]).cmd));
01769
01770
01771 for (i=hooklists.lists[hooklist].current;
01772 (i<hooklists.lists[hooklist].num) &&
01773 (counter >= hooklists.lists[hooklist].defs[i].start);
01774 i++) {
01775 CounterHookDefinition* hookdef= &(hooklists.lists[hooklist].defs[i]);
01776
01777
01778 if ( (counter <= hookdef->end) &&
01779 ((counter % hookdef->step) == 0) &&
01780 (!catchuponly || hookdef->cmd.def->catchup ) ) {
01781
01782 if (hookdef->step !=1 || counter == hookdef->start)
01783 ipc_notify(IPC_ONE,IPC_STD,"Running hook `%s' %s at %s %d",
01784 hookdef->cmd.def->name,
01785 hooklists.lists[hooklist].name,
01786 hooklists.lists[hooklist].countername,
01787 counter);
01788 if (hookdef->step==1 && counter==hookdef->start && hookdef->end > hookdef->start)
01789 ipc_notify(IPC_ONE,IPC_STD,"(Hook `%s' will run at every %s until %s %d)",
01790 hookdef->cmd.def->name,
01791 hooklists.lists[hooklist].countername,
01792 hooklists.lists[hooklist].countername,
01793 hookdef->end);
01794 command_exec(&(hookdef->cmd));
01795 }
01796 }
01797 }
01798
01799
01800
01802 void hooklists_reset_list(HooklistNum hooklist)
01803 {
01804 hooklists.lists[hooklist].current=0;
01805 hooklists_sort(hooklist);
01806
01807 return;
01808 }
01809
01810
01811
01813 void hooklists_empty_list(HooklistNum hooklistnum)
01814 {
01815 int i;
01816 CounterHooklist* hooklist = &(hooklists.lists[hooklistnum]);
01817
01818
01819 for (i=0; i<hooklist->num; i++) {
01820 int arg=0;
01821 while (hooklist->defs[i].argstofree[arg])
01822 free(hooklist->defs[i].argstofree[arg++]);
01823 }
01824
01825 hooklist->num=0;
01826 hooklist->current=0;
01827
01828 return;
01829 }
01830
01831
01832
01837 void hook_print_to_str( CounterHookDefinition *hook, char *hooklistname, char *str, size_t nchars)
01838 {
01839 char *str_ptr=str;
01840 size_t charsleft=nchars-1;
01841
01842 SNPRINTF(str_ptr,charsleft,"hook %-15s %6d", hooklistname, hook->start);
01843 charsleft -= strlen(str_ptr); str_ptr += strlen(str_ptr);
01844
01845
01846 if (hook->end != hook->start) {
01847 SNPRINTF(str_ptr,charsleft,"-%d",hook->end);
01848 charsleft -= strlen(str_ptr); str_ptr += strlen(str_ptr);
01849 }
01850
01851
01852 if (hook->step != 1) {
01853 SNPRINTF(str_ptr,charsleft,"%%%d", hook->step);
01854 charsleft -= strlen(str_ptr); str_ptr += strlen(str_ptr);
01855 }
01856
01857
01858 SNPRINTF(str_ptr,charsleft," ");
01859 charsleft -= strlen(str_ptr); str_ptr += strlen(str_ptr);
01860 command_print_to_str(&(hook->cmd), str_ptr,charsleft);
01861 charsleft -= strlen(str_ptr); str_ptr += strlen(str_ptr);
01862 }
01863
01864
01865
01870 void hooklists_log(void)
01871 {
01872 int i,hooklist;
01873 char str[CMD_MAX_LINE_LENGTH];
01874
01875 for (hooklist=0; hooklist<hooklists.num; hooklist++)
01876 for (i=0; i<hooklists.lists[hooklist].num; i++) {
01877 hook_print_to_str( &(hooklists.lists[hooklist].defs[i]),
01878 hooklists.lists[hooklist].name,
01879 str, CMD_MAX_LINE_LENGTH);
01880 ipc_log(IPC_ONE,"%s\n",str);
01881 }
01882
01883 ipc_log(IPC_ONE,"\n");
01884 }
01885
01886
01887
01888
01889
01890
01891
01892
01896 size_t cmdparam_identifier_length(const char* str)
01897 {
01898 const char * rem;
01899
01900
01901 if (!str || !isalpha(*str)) return 0;
01902
01903
01904 for (rem=str; isalnum(*rem) || *rem == '_'; rem++);
01905
01906 return rem-str;
01907 }
01908
01909
01910
01912 char* cmdparam_dupstr (const char *str)
01913 {
01914 char *newstr = (char *)malloc(strlen(str)+1);
01915 if (!newstr)
01916 ipc_abort(IPC_EXIT_OUT_OF_MEMORY,"Cannot allocate string");
01917 strcpy (newstr, str);
01918 return (newstr);
01919 }
01920
01921
01922
01925 int cmdparams_print_doc(FILE *fp, const char* name)
01926 {
01927 int idx = 0;
01928 int found = False;
01929
01930 const ParamType& param=blackboard.lookup_with_path(name,false);
01931 if (param.is_valid()) {
01932 fprintf(fp,param.doc_string().c_str());
01933 found = True;
01934 }
01935 else
01936 for (idx=command_definitions.num-1; !found && idx >= 0; idx--)
01937 if (strncmp(name,command_definitions.list[idx].name,CMDDEF_MAX_NAME_LENGTH) == 0) {
01938 cmddefs_print_doc_for_index(fp,idx);
01939 found = True;
01940 }
01941
01942 return found;
01943 }
01944
01945
01948 char* params_completion_generator (char *text, int state)
01949 { return blackboard.completion_generator (text,state); }
01950
01951
01953 char* cmdparams_completion_generator (char *text, int state)
01954 {
01955 char *name = cmddefs_completion_generator (text, state);
01956 if (name) return name;
01957 return blackboard.completion_generator (text, state);
01958 }
01959
01960
01961 int cmdparam_save_current_state(const char * filename)
01962 {
01963 int i,hooklist;
01964 FILE *file;
01965 char str[CMD_MAX_LINE_LENGTH];
01966
01967 file=fopen(filename,"w+");
01968 if(file==NULL) {
01969 ipc_notify(IPC_ALL,IPC_ERROR,"Can't open %s file", filename);
01970 return CMD_FILE_ERROR;
01971 }
01972
01973 fprintf(file,"# Parameters:\n\n");
01974 blackboard.root().save_parameters(file);
01975
01976 fprintf(file,"\n# Hooks:\n\n");
01977 for (hooklist=0; hooklist<hooklists.num; hooklist++)
01978 for (i=0; i<hooklists.lists[hooklist].num; i++) {
01979 hook_print_to_str( &(hooklists.lists[hooklist].defs[i]),
01980 hooklists.lists[hooklist].name,
01981 str, CMD_MAX_LINE_LENGTH);
01982 fprintf(file,"%s\n",str);
01983 }
01984
01985 fprintf(file,"\n");
01986 fclose(file);
01987
01988 return CMD_NO_ERROR;
01989 }
01990
01991
01992
01994 string trim_quotes(const string& s)
01995 {
01996 if (s.empty()) return s;
01997 unsigned front = 0;
01998 unsigned back = s.length()-1;
01999 if (s[front] == '"' || s[front] == '\'') {
02000 front++;
02001 if (s[back] == s[0])
02002 back--;
02003 }
02004 return string(s,front,back-front+1);
02005 }
02006
02007
02008
02009
02010
02011
02012
02013
02014
02015
02016
02017
02018
02019
02020
02021 string filter_backquotes(const string arg)
02022 {
02023 if (arg.empty() || arg[0]!='`' || arg[arg.length()-1]!='`')
02024 return arg;
02025
02026
02027 const string noquotes(arg,1,arg.length()-2);
02028 string parsed;
02029 parsed = CmdParamStringParser(blackboard).parse(noquotes,parsed);
02030
02031 const string tempname = TEMPNAME(NULL,"backq");
02032 const string shellcmd = parsed+" > "+tempname;
02033 system(shellcmd.c_str());
02034 std::ifstream s(tempname.c_str());
02035
02036
02037
02038 const int buffsize=1024;
02039 char buffer[buffsize];
02040 s.getline(buffer,buffsize,EOF);
02041
02042
02043 string str=buffer;
02044 if (!str.empty() && str[str.length()-1]=='\n')
02045 str.replace(str.length()-1,1,"");
02046
02047 remove(tempname.c_str());
02048
02049 return str;
02050 }
02051
02052
02053
02060 bool cmdparams_set_single( BlackboardType& params, const string& arg,
02061 bool& seterror, bool mark, bool verbose,
02062 bool copysetfn)
02063 {
02064
02065 unsigned pos = arg.find("=");
02066 if (pos>=arg.length())
02067 return false;
02068
02069
02070
02071 unsigned spacepos = arg.find(" ");
02072 if (spacepos<pos)
02073 return false;
02074
02075 const string pathstr = string(arg,0,pos);
02076 const string valstr = filter_backquotes(trim_quotes(string(arg,pos+1,arg.length())));
02077
02078 if (!params.set_matching(CmdParamStringParser(params),
02079 pathstr,valstr,mark,verbose,false,copysetfn))
02080 seterror=true;
02081
02082 return true;
02083 }
02084
02085
02086 cmdstat cmdparams_set( BlackboardType& params, StringArgs& arglist,
02087 bool mark, bool warn, bool verbose, bool copysetfns)
02088 {
02089 bool seterror = false;
02090
02091 while (!arglist.empty()) {
02092 if (!cmdparams_set_single(params, arglist.top(string("")),
02093 seterror,mark,verbose,copysetfns)) {
02094 if (warn) {
02095 const string rest = arglist.stringrep();
02096 ipc_notify(IPC_ONE,IPC_ERROR,"Syntax error in set arguments ('%s' is not of the form 'x=y')",
02097 rest.c_str());
02098 return CMD_PARAMETER_ERROR;
02099 }
02100 return CMD_NO_ERROR;
02101 }
02102
02103
02104 arglist.skip();
02105 }
02106
02107 return (seterror? CMD_PARAMETER_ERROR : CMD_NO_ERROR);
02108 }
02109
02110
02111
02112
02113
02114
02115
02116
02118 cmdstat cmd_set( CMD_ARGS )
02119 {
02120 CMD_ARG_LIST;
02121 return cmdparams_set(blackboard,arglist,true,true);
02122 }
02123
02124
02125
02126 cmdstat cmd_quit( CMD_ARGS )
02127 {
02128 time_t current_time = time(NULL);
02129 ipc_notify(IPC_ONE,IPC_SUMMARY,"Exiting at %.24s", ctime(¤t_time));
02130
02131 if (argc>0)
02132 ipc_exit(IPC_EXIT_NORMAL,argv[0]);
02133 else
02134 ipc_exit(IPC_EXIT_NORMAL,"Exited via quit command");
02135
02136 return CMD_NO_ERROR;
02137 }
02138
02139
02140
02141 cmdstat cmd_clear_hooks( CMD_ARGS )
02142 {
02143 int status=CMD_NO_ERROR;
02144 HooklistNum hooklist;
02145
02146 if (argc<1)
02147 for (hooklist=0; hooklist<hooklists.num; hooklist++) {
02148 if (hooklists.lists[hooklist].num) {
02149 hooklists_empty_list(hooklist);
02150 ipc_notify(IPC_ONE,IPC_STD,"Emptied hooklist %s",hooklists.lists[hooklist].name);
02151 }
02152 }
02153 else {
02154 int i,arg;
02155
02156 for (arg=0; arg<argc; arg++) {
02157 hooklist = Uninitialized;
02158
02159
02160 for (i=0; i<hooklists.num; i++)
02161 if (!strncmp(hooklists.lists[i].name,argv[arg],HOOKLIST_MAX_NAME_LENGTH))
02162 hooklist=i;
02163
02164 if (hooklist==Uninitialized) {
02165 ipc_notify(IPC_ONE,IPC_ERROR,"Hook list is not defined: %s",argv[0]);
02166 status= CMD_PARAMETER_ERROR;
02167 }
02168 else if (hooklists.lists[hooklist].num) {
02169 hooklists_empty_list(hooklist);
02170 ipc_notify(IPC_ONE,IPC_STD,"Emptied hooklist %s",hooklists.lists[hooklist].name);
02171 }
02172 }
02173 }
02174
02175 return status;
02176 }
02177
02178
02179
02180 cmdstat cmd_exec( CMD_ARGS )
02181 {
02182 int status=0;
02183
02184 for (int i=0; i<argc; i++) {
02185 int newstatus = cmddefs_exec_str(PARSE_C(argv[i]));
02186 if (newstatus>=0) status=newstatus;
02187 }
02188
02189 return status;
02190 }
02191
02192
02193
02194 cmdstat cmd_exec_catchup( CMD_ARGS )
02195 {
02196 int status=0;
02197
02198 for (int i=0; i<argc; i++) {
02199 int newstatus = cmddefs_exec_str(PARSE_C(argv[i]));
02200 if (newstatus>=0) status=newstatus;
02201 }
02202
02203 return status;
02204 }
02205
02206
02207
02208 cmdstat cmd_exec_file( CMD_ARGS )
02209 {
02210 CMD_ARG_LIST;
02211 int status;
02212
02213 cmddefs_exec_file_arglists.push(argl);
02214 status=cmddefs_exec_file(PARSE_C(argv[0]));
02215 cmddefs_exec_file_arglists.pop();
02216
02217 return (status? CMD_FILE_ERROR : CMD_NO_ERROR);
02218 }
02219
02220
02221
02222 cmdstat cmd_call( CMD_ARGS )
02223 {
02224 CMD_ARG_LIST;
02225
02226 int status;
02227 const int oldipcverbosity = ipc_msg_level;
02228 const int newipcverbosity = IPC_REQUESTED;
02229
02230 if (ipc_msg_level > newipcverbosity)
02231 ipc_msg_level = newipcverbosity;
02232
02233 cmddefs_exec_file_arglists.push(argl);
02234 status=cmddefs_exec_file(PARSE_C(argv[0]));
02235 cmddefs_exec_file_arglists.pop();
02236 if (ipc_msg_level==newipcverbosity)
02237 ipc_msg_level=oldipcverbosity;
02238
02239 return (status? CMD_FILE_ERROR : CMD_NO_ERROR);
02240 }
02241
02242
02243
02245 cmdstat cmd_read_args( CMD_ARGS )
02246 {
02247 CMD_ARG_LIST;
02248 StringArgs sargs(p, cmddefs_exec_file_arglists.top().begin(), cmddefs_exec_file_arglists.top().end());
02249 sargs.skip();
02250
02251 const string parentstr = arglist.next(string(""));
02252 BlackboardType& parent = blackboard.lookup_map(parentstr);
02253 return cmdparams_set(parent,sargs,true,true);
02254 }
02255
02256
02257
02258 cmdstat cmd_define_param( CMD_ARGS )
02259 {
02260 CMD_ARG_PARAMS(define_param);
02261
02262 const string pathstr = arglist.next(string(""));
02263 PathSpecification path(pathstr);
02264 const string name = path.last();
02265
02266
02267
02268 const string type = arglist.next(string());
02269 const bool has_lbound =!arglist.empty();
02270 const int lower_bound = arglist.next(int(Uninitialized));
02271 const bool has_ubound =!arglist.empty();
02272 const int upper_bound = arglist.next(int(Uninitialized));
02273 const string helpstr = arglist.next(string());
02274 const bool has_initval =!arglist.empty();
02275 const string initval = arglist.next(string());
02276
02277
02278 const string helpstring = String::replace_all(string(helpstr),string("\\n"),string("\n"));
02279
02280 BlackboardType& parent = blackboard.lookup_map(path.allbutlast(),true,path.isrooted());
02281 if (parent.defined_locally(name))
02282 return CMD_NO_ERROR;
02283
02284 BlackboardType::ParamType newparam;
02285 if (type == "Param_String" || type == "String" ) newparam = DECLARE_A(name.c_str(),false,string());
02286 else if (type == "Param_Boolean" || type == "Boolean") newparam = DECLARE_A(name.c_str(),false,False);
02287 else if (type == "Param_Integer" || type == "Integer") newparam = DECLARE_A(name.c_str(),false,0);
02288 else if (type == "Param_Float" || type == "Float" ) newparam = DECLARE_A(name.c_str(),false,0.0);
02289 else {
02290 ipc_notify(IPC_ONE,IPC_ERROR,"Couldn't define parameter of type %s",type.c_str());
02291 return CMD_PARAMETER_ERROR;
02292 }
02293
02294 if (has_lbound && type != "Param_String") newparam.add_lower_bound(lower_bound);
02295 if (has_ubound && type != "Param_String" && !(upper_bound < lower_bound))
02296 newparam.add_upper_bound(upper_bound);
02297 if (helpstring!="") newparam.add_doc(cmdparam_dupstr(helpstring.c_str()));
02298 if (has_initval) newparam.set(CmdParamStringParser(parent),initval);
02299
02300 if (parent.define_param(newparam) == 1 && cmdparam_changes_verbose)
02301 ipc_notify(IPC_ONE,IPC_STD,"Defined parameter %s",pathstr.c_str());
02302
02303 return CMD_NO_ERROR;
02304 }
02305
02306
02307
02308 cmdstat cmd_define_param_set( CMD_ARGS )
02309 {
02310 CMD_ARG_PARAMS(define_param_set);
02311
02312 const string pathstr = arglist.next(string(""));
02313 PathSpecification path(pathstr);
02314
02315 if (path.all().empty()) {
02316 ipc_notify(IPC_ONE,IPC_ERROR,"A parameter set must have a non-empty name");
02317 return CMD_PARAMETER_ERROR;
02318 }
02319
02320 BlackboardType& parent = blackboard.lookup_map(path.allbutlast(),true,path.isrooted());
02321
02322
02323 if (&parent == &(parent.lookup_map(path.last(),false)))
02324 parent.new_child(path.last(),true);
02325
02326 return CMD_NO_ERROR;
02327 }
02328
02329
02330
02331 cmdstat cmd_select_param_set( CMD_ARGS )
02332 {
02333 CMD_ARG_PARAMS(select_param_set);
02334 static std::vector<BlackboardType*> blackboardstack;
02335
02336 const string pathstr = arglist.next(string(""));
02337 PathSpecification path(pathstr);
02338
02339
02340 if (!path.isrooted() && path.all().empty()) {
02341 if (blackboardstack.empty())
02342 ipc_notify(IPC_ONE,IPC_ERROR,"At the root level; cannot pop back to another parameter set");
02343 else {
02344 blackboard_ptr=blackboardstack.back();
02345 blackboardstack.pop_back();
02346 }
02347 }
02348
02349
02350 else {
02351 blackboardstack.push_back(blackboard_ptr);
02352
02353 blackboard_ptr = &(blackboard.lookup_map(path.all(),true,path.isrooted()));
02354 }
02355
02356 return CMD_NO_ERROR;
02357 }
02358
02359
02360
02361 cmdstat cmd_param_default( CMD_ARGS )
02362 {
02363 (void)argc;
02364
02365 blackboard.lookup(argv[0]).add_default_expr(argv[1]);
02366
02367 return CMD_NO_ERROR;
02368 }
02369
02370
02371
02372 cmdstat cmd_if( CMD_ARGS )
02373 {
02374 if (PARSE_I(argv[0]))
02375 return cmddefs_exec_by_name(argv[1],argc-2,&(argv[2]));
02376
02377 return CMD_NO_ERROR;
02378 }
02379
02380
02381
02382 cmdstat cmd_dotimes( CMD_ARGS )
02383 {
02384 int i;
02385 int status = CMD_NO_ERROR;
02386
02387 for (i=0; i<PARSE_I(argv[0]); i++) {
02388 status = cmddefs_exec_by_name(argv[1],argc-2,&(argv[2]));
02389 if (status) return status;
02390 }
02391
02392 return CMD_NO_ERROR;
02393 }
02394
02395
02396
02397 cmdstat cmd_for( CMD_ARGS )
02398 {
02399 int status = CMD_NO_ERROR;
02400
02401 for (cmd_set(1,&(argv[0])); PARSE_I(argv[1]); cmd_set(1,&(argv[2]))) {
02402 status = cmddefs_exec_by_name(argv[3],argc-4,&(argv[4]));
02403 if (status) return status;
02404 }
02405
02406 return CMD_NO_ERROR;
02407 }
02408
02409
02410
02411 cmdstat cmd_print( CMD_ARGS )
02412 {
02413 int i;
02414
02415 for (i=0; i<argc; i++) {
02416 const string squeezed = String::replace_all(string(argv[i]),string("::"),string(""));
02417
02418
02419 if (String::C_identifier_length(squeezed) == squeezed.length()) {
02420 const ParamType& param = blackboard.lookup_with_path(argv[i]);
02421 if (param.is_valid())
02422 ipc_notify(IPC_ONE,IPC_REQUESTED,"%s == %s",argv[i],param.stringrep().c_str());
02423 }
02424
02425 else if (*argv[i] == '$')
02426 ipc_notify(IPC_ONE,IPC_REQUESTED,"%s == %s",argv[i],PARSE_C(argv[i]));
02427
02428 else {
02429 double value = PARSE_F(argv[i]);
02430 ipc_notify(IPC_ONE,IPC_REQUESTED,"%s == %g",argv[i],value);
02431 }
02432 }
02433
02434 return CMD_NO_ERROR;
02435 }
02436
02437
02438
02439 cmdstat cmd_echo( CMD_ARGS )
02440 {
02441 for (int i=0; i<argc; i++) {
02442 const string str = String::replace_all(string(PARSE_C(argv[i])),string("\\n"),string("\n"));
02443 ipc_notify(IPC_ONE,IPC_REQUESTED,"%s",str.c_str());
02444 }
02445
02446 return CMD_NO_ERROR;
02447 }
02448
02449
02450
02451 cmdstat cmd_system( CMD_ARGS )
02452 {
02453 char str[CMD_MAX_LINE_LENGTH];
02454 char *str_ptr=str;
02455 size_t charsleft=CMD_MAX_LINE_LENGTH-1;
02456 int i;
02457 int status=0;
02458
02459
02460 for(i=0; i < argc; i++){
02461 SNPRINTF(str_ptr,charsleft,"%s%s",(i==0? "" : " "),PARSE_C(argv[i]));
02462 charsleft -= strlen(str_ptr);
02463 str_ptr += strlen(str_ptr);
02464 }
02465
02466 ipc_notify(IPC_ONE,IPC_VERBOSE,"Executing shell command `%s'",str);
02467 if (AMPARENTPE)
02468 status=system(str);
02469
02470 return (status? CMD_MISC_ERROR : CMD_NO_ERROR);
02471 }