MIDAS
Loading...
Searching...
No Matches
Sequencer Functions

Classes

class  SeqCon
 

Functions

 SEQUENCER_STR (sequencer_str)
 
char * stristr (const char *str, const char *pattern)
 
void strsubst (char *string, int size, const char *pattern, const char *subst)
 
static std::string toString (int v)
 
static std::string qtoString (std::string filename, int line, int level)
 
static std::string q (const char *s)
 
bool is_valid_number (const char *str)
 
void seq_error (SEQUENCER &seq, SeqCon *c, const char *str)
 
int strbreak (char *str, char list[][XNAME_LENGTH], int size, const char *brk, BOOL ignore_quotes)
 
std::string eval_var (SEQUENCER &seq, SeqCon *c, std::string value)
 
int concatenate (SEQUENCER &seq, SeqCon *c, char *result, int size, char *value)
 
int eval_condition (SEQUENCER &seq, SeqCon *c, const char *condition)
 
bool loadMSL (MVOdb *o, const std::string &filename)
 
static BOOL msl_parse (SEQUENCER &seq, SeqCon *c, int level, const char *cpath, const char *filename, const char *xml_filename, char *error, int error_size, int *error_line)
 
void seq_read (SEQUENCER *seq, SeqCon *c)
 
void seq_write (const SEQUENCER &seq, SeqCon *c)
 
void seq_clear (SEQUENCER &seq)
 
static void seq_start (SEQUENCER &seq, SeqCon *c, bool debug)
 
static void seq_stop (SEQUENCER &seq, SeqCon *c)
 
static void seq_stop_after_run (SEQUENCER &seq, SeqCon *c)
 
static void seq_cancel_stop_after_run (SEQUENCER &seq, SeqCon *c)
 
static void seq_pause (SEQUENCER &seq, SeqCon *c, bool flag)
 
static BOOL goto_at_exit (SEQUENCER &seq, SeqCon *c)
 
static void seq_step_over (SEQUENCER &seq, SeqCon *c)
 
static void seq_open_file (const char *str, SEQUENCER &seq, SeqCon *c)
 
static void seq_start_next (SEQUENCER &seq, SeqCon *c)
 
static void seq_watch (HNDLE hDB, HNDLE hKeyChanged, int index, void *info)
 
static void seq_watch_command (HNDLE hDB, HNDLE hKeyChanged, int index, void *info)
 
void seq_array_index (SEQUENCER &seq, SeqCon *c, char *odbpath, int *index1, int *index2)
 
int set_all_matching (HNDLE hDB, HNDLE hBaseKey, const char *odbpath, char *value, int index1, int index2, int notify)
 
void sequencer (SEQUENCER &seq, SeqCon *c)
 
void init_sequencer (SEQUENCER &seq, SeqCon *c)
 
int main (int argc, const char *argv[])
 

Variables

MVOdb * gOdb = NULL
 

Detailed Description

dox


Function Documentation

◆ concatenate()

int concatenate ( SEQUENCER seq,
SeqCon c,
char *  result,
int  size,
char *  value 
)

Definition at line 375 of file msequencer.cxx.

375 {
376 char list[100][XNAME_LENGTH];
377 int i, n;
378
379 n = strbreak(value, list, 100, ",", FALSE);
380
381 result[0] = 0;
382 for (i = 0; i < n; i++) {
383 std::string str = eval_var(seq, c, std::string(list[i]));
384 mstrlcat(result, str.c_str(), size);
385 }
386
387 return TRUE;
388}
#define FALSE
Definition cfortran.h:309
int strbreak(char *str, char list[][XNAME_LENGTH], int size, const char *brk, BOOL ignore_quotes)
std::string eval_var(SEQUENCER &seq, SeqCon *c, std::string value)
DWORD n[4]
Definition mana.cxx:247
INT i
Definition mdump.cxx:32
#define TRUE
Definition midas.h:182
#define XNAME_LENGTH
double value[100]
Definition odbhist.cxx:42
char str[256]
Definition odbhist.cxx:33
char c
Definition system.cxx:1312
static te_expr * list(state *s)
Definition tinyexpr.c:567
Here is the call graph for this function:
Here is the caller graph for this function:

◆ eval_condition()

int eval_condition ( SEQUENCER seq,
SeqCon c,
const char *  condition 
)

Definition at line 392 of file msequencer.cxx.

392 {
393 int i;
394 double value1, value2;
395 char value1_str[256], value2_str[256], str[256], op[3], *p;
396 std::string value1_var, value2_var;
397
398 // strip leading and trailing space
399 p = (char *)condition;
400 while (*p == ' ')
401 p++;
402 strcpy(str, p);
403
404 // strip any comment '#'
405 if (strchr(str, '#'))
406 *strchr(str, '#') = 0;
407
408 while (strlen(str) > 0 && (str[strlen(str)-1] == ' '))
409 str[strlen(str)-1] = 0;
410
411 // strip enclosing '()'
412 if (str[0] == '(' && strlen(str) > 0 && str[strlen(str)-1] == ')') {
413 mstrlcpy(value1_str, str+1, sizeof(value1_str));
414 mstrlcpy(str, value1_str, sizeof(str));
415 str[strlen(str)-1] = 0;
416 }
417
418 op[1] = op[2] = 0;
419
420 /* find value and operator */
421 for (i = 0; i < (int) strlen(str); i++)
422 if (strchr("<>=!&", str[i]) != NULL)
423 break;
424 mstrlcpy(value1_str, str, i + 1);
425 while (value1_str[strlen(value1_str) - 1] == ' ')
426 value1_str[strlen(value1_str) - 1] = 0;
427 op[0] = str[i];
428 if (strchr("<>=!&", str[i + 1]) != NULL)
429 op[1] = str[++i];
430
431 for (i++; str[i] == ' '; i++);
432 mstrlcpy(value2_str, str + i, sizeof(value2_str));
433
434 value1_var = eval_var(seq, c, value1_str);
435 value2_var = eval_var(seq, c, value2_str);
436
437 if (!is_valid_number(value1_var.c_str()) || !is_valid_number(value2_var.c_str())) {
438 // string comparison
439 if (strcmp(op, "=") == 0)
440 return equal_ustring(value1_var.c_str(), value2_var.c_str()) ? 1 : 0;
441 if (strcmp(op, "==") == 0)
442 return equal_ustring(value1_var.c_str(), value2_var.c_str()) ? 1 : 0;
443 if (strcmp(op, "!=") == 0)
444 return equal_ustring(value1_var.c_str(), value2_var.c_str()) ? 0 : 1;
445 // invalid operator for string comparisons
446 return -1;
447 }
448
449 // numeric comparison
450 value1 = atof(value1_var.c_str());
451 value2 = atof(value2_var.c_str());
452
453 /* now do logical operation */
454 if (strcmp(op, "=") == 0)
455 if (value1 == value2)
456 return 1;
457 if (strcmp(op, "==") == 0)
458 if (value1 == value2)
459 return 1;
460 if (strcmp(op, "!=") == 0)
461 if (value1 != value2)
462 return 1;
463 if (strcmp(op, "<") == 0)
464 if (value1 < value2)
465 return 1;
466 if (strcmp(op, ">") == 0)
467 if (value1 > value2)
468 return 1;
469 if (strcmp(op, "<=") == 0)
470 if (value1 <= value2)
471 return 1;
472 if (strcmp(op, ">=") == 0)
473 if (value1 >= value2)
474 return 1;
475 if (strcmp(op, "&") == 0)
476 if (((unsigned int) value1 & (unsigned int) value2) > 0)
477 return 1;
478
479 return 0;
480}
BOOL equal_ustring(const char *str1, const char *str2)
Definition odb.cxx:3285
bool is_valid_number(const char *str)
Here is the call graph for this function:
Here is the caller graph for this function:

◆ eval_var()

std::string eval_var ( SEQUENCER seq,
SeqCon c,
std::string  value 
)

Definition at line 267 of file msequencer.cxx.

267 {
268 std::string result;
269 std::string xpath;
270 xpath += "/";
271 xpath += c->odb_path;
272
273 //printf("eval [%s] xpath [%s]\n", value.c_str(), xpath.c_str());
274
275 result = value;
276
277 // replace all $... with value
278 int i1, i2;
279 std::string vsubst;
280 while ((i1 = (int)result.find("$")) != (int)std::string::npos) {
281 std::string s = result.substr(i1 + 1);
282 if (std::isdigit(s[0])) {
283 // find end of number
284 for (i2 = i1 + 1; std::isdigit(result[i2]);)
285 i2++;
286
287 // replace all $<number> with subroutine parameters
288 int index = atoi(s.c_str());
289 if (seq.stack_index > 0) {
290 std::istringstream f(seq.subroutine_param[seq.stack_index - 1]);
291 std::vector<std::string> param;
292 std::string sp;
293 while (std::getline(f, sp, ','))
294 param.push_back(sp);
295 if (index == 0 || index > (int)param.size())
296 throw "Parameter \"$" + std::to_string(index) + "\" not valid";
297 vsubst = param[index - 1];
298 if (vsubst[0] == '$')
299 vsubst = eval_var(seq, c, vsubst);
300 } else
301 throw "Parameter \"$" + std::to_string(index) + "\" not valid";
302 } else {
303 // find end of string
304 for (i2 = i1 + 1; std::isalnum(result[i2]) || result[i2] == '_';)
305 i2++;
306 s = s.substr(0, i2 - i1 - 1);
307 if (result[i2] == '[') {
308 // array
309 auto sindex = result.substr(i2+1);
310 int i = sindex.find(']');
311 if (i == (int)std::string::npos)
312 throw "Variable \"" + result +"\" does not contain ']'";
313 sindex = sindex.substr(0, i);
314 sindex = eval_var(seq, c, sindex);
315 int index;
316 try {
317 index = std::stoi(sindex);
318 } catch (...) {
319 throw "Variable \"" + s + "\" has invalid index";
320 }
321
322 try {
323 midas::odb o(xpath + "/Variables/" + s);
324 std::vector<std::string> sv = o;
325 vsubst = sv[index];
326 } catch (...) {
327 throw "Variable \"" + s + "\" not found";
328 }
329 while (result[i2] && result[i2] != ']')
330 i2++;
331 if (!result[i2])
332 throw "Variable \"" + result +"\" does not contain ']'";
333 if (result[i2] == ']')
334 i2++;
335 } else {
336 try {
337 if (!midas::odb::exists(xpath + "/Variables/" + s))
338 throw "Variable \"" + s + "\" not found";
339 midas::odb o(xpath + "/Variables/" + s);
340 vsubst = o;
341 } catch (...) {
342 throw "Variable \"" + s + "\" not found";
343 }
344 }
345 }
346
347 result = result.substr(0, i1) + vsubst + result.substr(i2);
348 }
349
350 //printf("eval [%s] xpath [%s] result [%s]\n", value.c_str(), xpath.c_str(), result.c_str());
351
352 // check if result is a list
353 if (result.find(",") != std::string::npos)
354 return result;
355
356 // check for expression
357 int error;
358 double r = te_interp(result.c_str(), &error);
359 if (error > 0) {
360 // check if result is only a string
361 if (!std::isdigit(result[0]) && result[0] != '-')
362 return result;
363
364 throw "Error in expression \"" + result + "\" position " + std::to_string(error - 1);
365 }
366
367 if (r == (int) r)
368 return std::to_string((int) r);
369
370 return std::to_string(r);
371}
static bool exists(const std::string &name)
Definition odbxx.cxx:75
INT index
Definition mana.cxx:271
char param[10][256]
Definition mana.cxx:250
int stack_index
Definition sequencer.h:40
char subroutine_param[SEQ_NEST_LEVEL_SUB][256]
Definition sequencer.h:45
double te_interp(const char *expression, int *error)
Definition tinyexpr.c:690
Here is the call graph for this function:
Here is the caller graph for this function:

◆ goto_at_exit()

static BOOL goto_at_exit ( SEQUENCER seq,
SeqCon c 
)
static

Definition at line 1210 of file msequencer.cxx.

1210 {
1211 seq_read(&seq, c);
1212
1213 // search ATEXIT subroutine
1214 for (int i = 1; i < mxml_get_line_number_end(mxml_find_node(c->pnseq, "RunSequence")); i++) {
1215 PMXML_NODE pt = mxml_get_node_at_line(c->pnseq, i);
1216 if (pt) {
1217 if (equal_ustring(mxml_get_name(pt), "Subroutine")) {
1218 if (equal_ustring(mxml_get_attribute(pt, "name"), "ATEXIT")) {
1219
1220 if (seq.stack_index == SEQ_NEST_LEVEL_SUB) {
1221 seq_error(seq, c, "Maximum subroutine level exceeded");
1222 return FALSE;
1223 }
1224
1225 // put routine end line on end stack
1226 seq.subroutine_end_line[seq.stack_index] = mxml_get_line_number_end(pt);
1227 seq.ssubroutine_call_line[seq.stack_index] = atoi(mxml_get_attribute(pt, "l"));
1228 seq.subroutine_return_line[seq.stack_index] = -1; // indicates exit on return
1229
1230 // put routine end line on end stack
1231 seq.subroutine_end_line[seq.stack_index] = mxml_get_line_number_end(pt);
1232
1233 // go to first line of subroutine
1234 seq.current_line_number = mxml_get_line_number_start(pt) + 1;
1235
1236 // increment stack
1237 seq.stack_index++;
1238
1239 seq_write(seq, c);
1240
1241 return TRUE;
1242 }
1243 }
1244 }
1245 }
1246
1247 // look for atexit subroutine
1248 return FALSE;
1249}
void seq_write(const SEQUENCER &seq, SeqCon *c)
void seq_read(SEQUENCER *seq, SeqCon *c)
void seq_error(SEQUENCER &seq, SeqCon *c, const char *str)
#define SEQ_NEST_LEVEL_SUB
Definition sequencer.h:5
int subroutine_return_line[SEQ_NEST_LEVEL_SUB]
Definition sequencer.h:42
int subroutine_end_line[SEQ_NEST_LEVEL_SUB]
Definition sequencer.h:41
int ssubroutine_call_line[SEQ_NEST_LEVEL_SUB]
Definition sequencer.h:44
int current_line_number
Definition sequencer.h:22
Here is the call graph for this function:
Here is the caller graph for this function:

◆ init_sequencer()

void init_sequencer ( SEQUENCER seq,
SeqCon c 
)

Definition at line 2834 of file msequencer.cxx.

2834 {
2835 int status;
2836 HNDLE hKey;
2837
2838 c->odbs = gOdb->Chdir(c->odb_path.c_str(), true); // create /Sequencer
2839 assert(c->odbs);
2840
2841 status = db_find_key(c->hDB, 0, c->odb_path.c_str(), &c->hSeq);
2842 if (status != DB_SUCCESS) {
2843 cm_msg(MERROR, "init_sequencer", "Sequencer error: Cannot find /Sequencer, db_find_key() status %d", status);
2844 return;
2845 }
2846
2847 status = db_check_record(c->hDB, c->hSeq, "State", strcomb1(sequencer_str).c_str(), TRUE);
2848 if (status == DB_STRUCT_MISMATCH) {
2849 cm_msg(MERROR, "init_sequencer", "Sequencer error: mismatching /Sequencer/State structure, db_check_record() status %d", status);
2850 return;
2851 }
2852
2853 status = db_find_key(c->hDB, c->hSeq, "State", &hKey);
2854 if (status != DB_SUCCESS) {
2855 cm_msg(MERROR, "init_sequencer", "Sequencer error: Cannot find /Sequencer/State, db_find_key() status %d", status);
2856 return;
2857 }
2858
2859 int size = sizeof(seq);
2860 status = db_get_record1(c->hDB, hKey, &seq, &size, 0, strcomb1(sequencer_str).c_str());
2861 if (status != DB_SUCCESS) {
2862 cm_msg(MERROR, "init_sequencer", "Sequencer error: Cannot get /Sequencer/State, db_get_record1() status %d", status);
2863 return;
2864 }
2865
2866 if (strlen(seq.path) > 0 && seq.path[strlen(seq.path) - 1] != DIR_SEPARATOR) {
2867 mstrlcat(seq.path, DIR_SEPARATOR_STR, sizeof(seq.path));
2868 }
2869
2870 if (seq.filename[0])
2871 seq_open_file(seq.filename, seq, c);
2872
2874
2875 db_set_record(c->hDB, hKey, &seq, sizeof(seq), 0);
2876
2877 status = db_watch(c->hDB, hKey, seq_watch, c);
2878 if (status != DB_SUCCESS) {
2879 cm_msg(MERROR, "init_sequencer", "Sequencer error: Cannot watch /Sequencer/State, db_watch() status %d", status);
2880 return;
2881 }
2882
2883 bool b = false;
2884 c->odbs->RB("Command/Start script", &b, true);
2885 b = false;
2886 c->odbs->RB("Command/Stop immediately", &b, true);
2887 b = false;
2888 c->odbs->RB("Command/Stop after run", &b, true);
2889 b = false;
2890 c->odbs->RB("Command/Cancel stop after run", &b, true);
2891 b = false;
2892 c->odbs->RB("Command/Pause script", &b, true);
2893 b = false;
2894 c->odbs->RB("Command/Resume script", &b, true);
2895 b = false;
2896 c->odbs->RB("Command/Debug script", &b, true);
2897 b = false;
2898 c->odbs->RB("Command/Step over", &b, true);
2899 b = false;
2900 c->odbs->RB("Command/Load new file", &b, true);
2901
2902 status = db_find_key(c->hDB, c->hSeq, "Command", &hKey);
2903 if (status != DB_SUCCESS) {
2904 cm_msg(MERROR, "init_sequencer", "Sequencer error: Cannot find /Sequencer/Command, db_find_key() status %d", status);
2905 return;
2906 }
2907
2909 if (status != DB_SUCCESS) {
2910 cm_msg(MERROR, "init_sequencer", "Sequencer error: Cannot watch /Sequencer/Command, db_watch() status %d", status);
2911 return;
2912 }
2913}
#define DB_STRUCT_MISMATCH
Definition midas.h:655
#define DB_SUCCESS
Definition midas.h:632
#define MERROR
Definition midas.h:559
INT cm_msg(INT message_type, const char *filename, INT line, const char *routine, const char *format,...)
Definition midas.cxx:930
std::string strcomb1(const char **list)
Definition odb.cxx:668
INT db_get_record1(HNDLE hDB, HNDLE hKey, void *data, INT *buf_size, INT align, const char *rec_str)
Definition odb.cxx:11581
INT db_check_record(HNDLE hDB, HNDLE hKey, const char *keyname, const char *rec_str, BOOL correct)
Definition odb.cxx:12750
INT db_watch(HNDLE hDB, HNDLE hKey, void(*dispatcher)(INT, INT, INT, void *), void *info)
Definition odb.cxx:13592
INT db_find_key(HNDLE hDB, HNDLE hKey, const char *key_name, HNDLE *subhKey)
Definition odb.cxx:4256
INT db_set_record(HNDLE hDB, HNDLE hKey, void *data, INT buf_size, INT align)
Definition odb.cxx:12067
static void seq_watch(HNDLE hDB, HNDLE hKeyChanged, int index, void *info)
MVOdb * gOdb
static void seq_watch_command(HNDLE hDB, HNDLE hKeyChanged, int index, void *info)
static void seq_open_file(const char *str, SEQUENCER &seq, SeqCon *c)
HNDLE hKey
#define DIR_SEPARATOR
Definition midas.h:193
INT HNDLE
Definition midas.h:132
#define DIR_SEPARATOR_STR
Definition midas.h:194
DWORD status
Definition odbhist.cxx:39
BOOL transition_request
Definition sequencer.h:26
char filename[256]
Definition sequencer.h:10
char path[256]
Definition sequencer.h:9
Here is the call graph for this function:
Here is the caller graph for this function:

◆ is_valid_number()

bool is_valid_number ( const char *  str)

Definition at line 147 of file msequencer.cxx.

147 {
148 std::string s(str);
149 std::stringstream ss;
150 ss << s;
151 double num = 0;
152 ss >> num;
153 if (ss.good())
154 return false;
155 else if (num == 0 && s[0] != '0')
156 return false;
157 else if (s[0] == 0)
158 return false;
159 return true;
160}
Here is the caller graph for this function:

◆ loadMSL()

bool loadMSL ( MVOdb *  o,
const std::string &  filename 
)

Definition at line 484 of file msequencer.cxx.

484 {
485
486 std::ifstream file(filename);
487 if (!file.is_open())
488 return false;
489
490 std::vector<std::string> lines;
491 std::string line;
492
493 // read all lines from file and put it into array
494 while (std::getline(file, line))
495 lines.push_back(line);
496 file.close();
497
498 o->WSA("Script/Lines", lines, 0);
499
500 return true;
501}
Here is the caller graph for this function:

◆ main()

int main ( int  argc,
const char *  argv[] 
)

Definition at line 2917 of file msequencer.cxx.

2917 {
2918 int daemon = FALSE;
2919 int status, ch;
2920 char midas_hostname[256];
2921 char midas_expt[256];
2922 std::string seq_name = "";
2923
2924 setbuf(stdout, NULL);
2925 setbuf(stderr, NULL);
2926#ifdef SIGPIPE
2927 /* avoid getting killed by "Broken pipe" signals */
2928 signal(SIGPIPE, SIG_IGN);
2929#endif
2930
2931 /* get default from environment */
2932 cm_get_environment(midas_hostname, sizeof(midas_hostname), midas_expt, sizeof(midas_expt));
2933
2934 /* parse command line parameters */
2935 for (int i = 1; i < argc; i++) {
2936 if (argv[i][0] == '-' && argv[i][1] == 'D') {
2937 daemon = TRUE;
2938 } else if (argv[i][0] == '-') {
2939 if (i + 1 >= argc || argv[i + 1][0] == '-')
2940 goto usage;
2941 if (argv[i][1] == 'h')
2942 mstrlcpy(midas_hostname, argv[++i], sizeof(midas_hostname));
2943 else if (argv[i][1] == 'e')
2944 mstrlcpy(midas_expt, argv[++i], sizeof(midas_hostname));
2945 else if (argv[i][1] == 'c')
2946 seq_name = argv[++i];
2947 } else {
2948 usage:
2949 printf("usage: %s [-h Hostname[:port]] [-e Experiment] [-c Name] [-D]\n\n", argv[0]);
2950 printf(" -e experiment to connect to\n");
2951 printf(" -c Name of additional sequencer, i.e. \'Test\'\n");
2952 printf(" -h connect to midas server (mserver) on given host\n");
2953 printf(" -D become a daemon\n");
2954 return 0;
2955 }
2956 }
2957
2958 if (daemon) {
2959 printf("Becoming a daemon...\n");
2961 }
2962
2963 std::string prg_name = "Sequencer";
2964 std::string odb_path = "Sequencer";
2965
2966 if (!seq_name.empty()) {
2967 prg_name = std::string("Sequencer") + seq_name; // sequencer program name
2968 odb_path = std::string("Sequencer") + seq_name; // sequencer ODB path
2969 }
2970
2971#ifdef OS_LINUX
2972 std::string pid_filename;
2973 pid_filename += "/var/run/";
2974 pid_filename += prg_name;
2975 pid_filename += ".pid";
2976 /* write PID file */
2977 FILE *f = fopen(pid_filename.c_str(), "w");
2978 if (f != NULL) {
2979 fprintf(f, "%d", ss_getpid());
2980 fclose(f);
2981 }
2982#endif
2983
2984 /*---- connect to experiment ----*/
2985 status = cm_connect_experiment1(midas_hostname, midas_expt, prg_name.c_str(), NULL, DEFAULT_ODB_SIZE, DEFAULT_WATCHDOG_TIMEOUT);
2987 return 1;
2988 else if (status == DB_INVALID_HANDLE) {
2989 std::string s = cm_get_error(status);
2990 puts(s.c_str());
2991 } else if (status != CM_SUCCESS) {
2992 std::string s = cm_get_error(status);
2993 puts(s.c_str());
2994 return 1;
2995 }
2996
2997 /* check if sequencer already running */
2998 status = cm_exist(prg_name.c_str(), TRUE);
2999 if (status == CM_SUCCESS) {
3000 printf("%s runs already.\n", prg_name.c_str());
3002 return 1;
3003 }
3004
3005 HNDLE hDB;
3007 gOdb = MakeMidasOdb(hDB);
3008
3009 SEQUENCER seq;
3010 SeqCon c;
3011
3012 c.seqp = &seq;
3013 c.hDB = hDB;
3014 c.seq_name = seq_name;
3015 c.prg_name = prg_name;
3016 c.odb_path = odb_path;
3017
3018 init_sequencer(seq, &c);
3019
3020 if (seq_name.empty()) {
3021 printf("Sequencer started. Stop with \"!\"\n");
3022 } else {
3023 printf("%s started.\n", prg_name.c_str());
3024 printf("Set ODB String \"/Alias/Sequencer%s\" to URL \"?cmd=sequencer&seq_name=%s\"\n", seq_name.c_str(), seq_name.c_str()); // FIXME: seq_name should be URL-encoded! K.O. Aug 2023
3025 printf("Stop with \"!\"\n");
3026 }
3027
3028 // if any commands are active, process them now
3029 seq_watch_command(hDB, 0, 0, &c);
3030
3031 /* initialize ss_getchar */
3032 ss_getchar(0);
3033
3034 /* main loop */
3035 do {
3036 try {
3037 sequencer(seq, &c);
3038 } catch (std::string &msg) {
3039 seq_error(seq, &c, msg.c_str());
3040 } catch (const char *msg) {
3041 seq_error(seq, &c, msg);
3042 }
3043
3044 status = cm_yield(0);
3045
3046 ch = 0;
3047 while (ss_kbhit()) {
3048 ch = ss_getchar(0);
3049 if (ch == -1)
3050 ch = getchar();
3051
3052 if ((char) ch == '!')
3053 break;
3054 }
3055
3056 } while (status != RPC_SHUTDOWN && ch != '!');
3057
3058 /* reset terminal */
3060
3061 /* close network connection to server */
3063
3064 return 0;
3065}
SEQUENCER * seqp
static void usage()
INT cm_yield(INT millisec)
Definition midas.cxx:5659
INT cm_get_experiment_database(HNDLE *hDB, HNDLE *hKeyClient)
Definition midas.cxx:3026
INT cm_connect_experiment1(const char *host_name, const char *default_exp_name, const char *client_name, void(*func)(char *), INT odb_size, DWORD watchdog_timeout)
Definition midas.cxx:2312
INT cm_disconnect_experiment(void)
Definition midas.cxx:2861
INT cm_get_environment(char *host_name, int host_name_size, char *exp_name, int exp_name_size)
Definition midas.cxx:2149
INT cm_exist(const char *name, BOOL bUnique)
Definition midas.cxx:7530
#define CM_SUCCESS
Definition midas.h:582
#define CM_WRONG_PASSWORD
Definition midas.h:589
#define DB_INVALID_HANDLE
Definition midas.h:636
#define RPC_SHUTDOWN
Definition midas.h:708
BOOL ss_kbhit()
Definition system.cxx:3736
INT ss_getchar(BOOL reset)
Definition system.cxx:7581
INT ss_getpid(void)
Definition system.cxx:1379
INT ss_daemon_init(BOOL keep_stdout)
Definition system.cxx:2073
std::string cm_get_error(INT code)
Definition midas.cxx:468
void init_sequencer(SEQUENCER &seq, SeqCon *c)
void sequencer(SEQUENCER &seq, SeqCon *c)
BOOL daemon
Definition mana.cxx:258
HNDLE hDB
main ODB handle
Definition mana.cxx:207
#define DEFAULT_WATCHDOG_TIMEOUT
Definition midas.h:290
#define DEFAULT_ODB_SIZE
Definition midas.h:270
Here is the call graph for this function:

◆ msl_parse()

static BOOL msl_parse ( SEQUENCER seq,
SeqCon c,
int  level,
const char *  cpath,
const char *  filename,
const char *  xml_filename,
char *  error,
int  error_size,
int *  error_line 
)
static

Definition at line 505 of file msequencer.cxx.

506 {
507 char str[256], *pl, *pe;
508 char list[100][XNAME_LENGTH], list2[100][XNAME_LENGTH], **lines;
509 int i, j, n, nq, n_lines, endl, line, nest, incl, library;
510 std::string xml, path, fn;
511 char *msl_include, *xml_include, *include_error;
512 int include_error_size;
513 BOOL include_status, rel_path;
514
515 if (level > 10) {
516 snprintf(error, error_size, "More than 10 nested INCLUDE statements exceeded in file \"%s\"", filename);
517 return FALSE;
518 }
519
520 rel_path = (filename[0] != DIR_SEPARATOR);
521 path = std::string(cpath);
522 if (path.length() > 0 && path.back() != '/')
523 path += '/';
524
525 std::string fullFilename;
526 if (rel_path)
527 fullFilename = path + filename;
528 else
529 fullFilename = filename;
530
531 int fhin = open(fullFilename.c_str(), O_RDONLY | O_TEXT);
532 if (fhin < 0) {
533 snprintf(error, error_size, "Cannot open \"%s\", errno %d (%s)", fullFilename.c_str(), errno, strerror(errno));
534 return FALSE;
535 }
536
537 off_t off = lseek(fhin, 0, SEEK_END);
538 if (off < 0) {
539 snprintf(error, error_size, "Cannot find size of \"%s\", lseek(SEEK_END) errno %d (%s)", fullFilename.c_str(), errno, strerror(errno));
540 close(fhin);
541 return FALSE;
542 }
543
544 lseek(fhin, 0, SEEK_SET);
545
546 std::string s;
547 if (rel_path)
548 s = path + xml_filename;
549 else
550 s = xml_filename;
551
552 FILE *fout = fopen(s.c_str(), "wt");
553 if (fout == NULL) {
554 snprintf(error, error_size, "Cannot write to \"%s\", fopen() errno %d (%s)", s.c_str(), errno, strerror(errno));
555 close(fhin);
556 return FALSE;
557 }
558
559 size_t size = off;
560
561 char* buf = (char *) malloc(size + 1);
562 ssize_t rd = read(fhin, buf, size);
563
564 if (rd < 0) {
565 snprintf(error, error_size, "Cannot read \"%s\", read(%zu) errno %d (%s)", fullFilename.c_str(), size, errno, strerror(errno));
566 size = 0;
567 } else {
568 size = rd;
569 }
570
571 buf[size] = 0;
572 close(fhin);
573
574 /* look for any includes */
575 lines = (char **) malloc(sizeof(char *));
576 incl = 0;
577 pl = buf;
578 library = FALSE;
579 for (n_lines = 0; *pl; n_lines++) {
580 lines = (char **) realloc(lines, sizeof(char *) * (n_lines + 1));
581 lines[n_lines] = pl;
582 if (strchr(pl, '\n')) {
583 pe = strchr(pl, '\n');
584 *pe = 0;
585 if (*(pe - 1) == '\r') {
586 *(pe - 1) = 0;
587 }
588 pe++;
589 } else
590 pe = pl + strlen(pl);
591 mstrlcpy(str, pl, sizeof(str));
592 pl = pe;
593 strbreak(str, list, 100, ", ", FALSE);
594 if (equal_ustring(list[0], "include")) {
595 if (!incl) {
596 xml += "<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>\n";
597 xml += "<!DOCTYPE RunSequence [\n";
598 incl = 1;
599 }
600
601 // if a path is given, use filename as entity reference
602 char *reference = strrchr(list[1], '/');
603 if (reference)
604 reference++;
605 else
606 reference = list[1];
607
608 if (strchr(reference, '.') && !strstr(reference, ".msl") && !strstr(reference, ".MSL")) {
609 snprintf(error, error_size, "Include file \"%s\" cannot have an extension other than .msl", reference);
610 return FALSE;
611 }
612
613 std::string p;
614 if (list[1][0] == '/') {
615 p = std::string(cm_get_path());
616 p += "userfiles/sequencer";
617 p += list[1];
618 } else {
619 p = path;
620 if (!p.empty() && p.back() != '/')
621 p += "/";
622 p += list[1];
623 }
624
625 xml += " <!ENTITY ";
626 xml += reference;
627 xml += " SYSTEM \"";
628 xml += p;
629 xml += ".xml\">\n";
630
631 // recurse
632 size = p.length() + 1 + 4;
633 msl_include = (char *) malloc(size);
634 xml_include = (char *) malloc(size);
635 mstrlcpy(msl_include, p.c_str(), size);
636 mstrlcpy(xml_include, p.c_str(), size);
637 if (!strstr(msl_include, ".msl"))
638 mstrlcat(msl_include, ".msl", size);
639 mstrlcat(xml_include, ".xml", size);
640
641 include_error = error + strlen(error);
642 include_error_size = error_size - strlen(error);
643
644 std::string path(cm_get_path());
645 path += "userfiles/sequencer/";
646 path += seq.path;
647
648 include_status = msl_parse(seq, c, level+1, path.c_str(), msl_include, xml_include, include_error, include_error_size, error_line);
649 free(msl_include);
650 free(xml_include);
651
652 if (!include_status) {
653 // report the error on CALL line instead of the one in included file
654 *error_line = n_lines + 1;
655 return FALSE;
656 }
657 }
658 if (equal_ustring(list[0], "library")) {
659 xml += "<Library name=\"";
660 xml += list[1];
661 xml += "\">\n";
662 library = TRUE;
663 }
664 }
665 if (incl) {
666 xml += "]>\n";
667 } else if (!library) {
668 xml += "<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>\n";
669 }
670
671 /* parse rest of file */
672 if (!library) {
673 xml += "<RunSequence xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:noNamespaceSchemaLocation=\"\">\n";
674 }
675
676 std::vector<std::string> slines;
677 for (line = 0; line < n_lines; line++) {
678 slines.push_back(lines[line]);
679 }
680
681 c->odbs->WSA("Script/Lines", slines, 0);
682
683 /* save parameters */
684 std::string p = "/" + c->odb_path + "/Param/Value";
685 midas::odb oldSeqParam(p);
686 oldSeqParam.set_auto_refresh_read(false);
687 oldSeqParam.set_auto_create(false);
688
689 /* clear all variables */
690 if (!seq.running) {
691 c->odbs->Delete("Variables");
692 c->odbs->Delete("Param");
693 }
694
695 for (line = 0; line < n_lines; line++) {
696 char *p = lines[line];
697 while (*p == ' ')
698 p++;
699 mstrlcpy(list[0], p, sizeof(list[0]));
700 if (strchr(list[0], ' '))
701 *strchr(list[0], ' ') = 0;
702 p += strlen(list[0]);
703 n = strbreak(p + 1, &list[1], 99, ",", FALSE) + 1;
704
705 /* remove any full comment line */
706 for (i = 0; i < n; i++) {
707 if (list[i][0] == '#') {
708 for (j = i; j < n; j++)
709 list[j][0] = 0;
710 break;
711 }
712 }
713
714 /* cut any partial comment line */
715 for (i = 0; i < n; i++) {
716 if (strchr(list[i], '#'))
717 *strchr(list[i], '#') = 0;
718 }
719
720 /* strip any trailing blanks */
721 for (i = 0; i < n; i++) {
722 while (strlen(list[i]) > 0 && list[i][strlen(list[i])-1] == ' ')
723 list[i][strlen(list[i])-1] = 0;
724 }
725
726 /* check for variable assignment */
727 char eq[1024];
728 mstrlcpy(eq, lines[line], sizeof(eq));
729 if (strchr(eq, '#'))
730 *strchr(eq, '#') = 0;
731 for (i = 0, n = 0, nq = 0; i < (int)strlen(eq); i++) {
732 if (eq[i] == '\"')
733 nq = (nq == 0 ? 1 : 0);
734 if (eq[i] == '=' && nq == 0 &&
735 (i > 0 && (eq[i - 1] != '!') && eq[i - 1] != '<' && eq[i - 1] != '>'))
736 n++;
737 }
738 if (n == 1 && eq[0] != '=') {
739 // equation found
740 mstrlcpy(list[0], "SET", sizeof(list[0]));
741 p = eq;
742 while (*p == ' ')
743 p++;
744 mstrlcpy(list[1], p, sizeof(list[1]));
745 *strchr(list[1], '=') = 0;
746 if (strchr(list[1], ' '))
747 *strchr(list[1], ' ') = 0;
748 p = strchr(eq, '=')+1;
749 while (*p == ' ')
750 p++;
751 mstrlcpy(list[2], p, sizeof(list[2]));
752 while (strlen(list[2]) > 0 && list[2][strlen(list[2])-1] == ' ')
753 list[2][strlen(list[2])-1] = 0;
754 }
755
756 if (equal_ustring(list[0], "library")) {
757
758 } else if (equal_ustring(list[0], "include")) {
759 // if a path is given, use filename as entity reference
760 char *reference = strrchr(list[1], '/');
761 if (reference)
762 reference++;
763 else
764 reference = list[1];
765
766 xml += "&";
767 xml += reference;
768 xml += ";\n";
769
770 } else if (equal_ustring(list[0], "call")) {
771 xml += "<Call " + qtoString(fullFilename, line + 1, level) + " name=" + q(list[1]) + ">";
772 for (i = 2; i < 100 && list[i][0]; i++) {
773 if (i > 2) {
774 xml += ",";
775 }
776 xml += list[i];
777 }
778 xml += "</Call>\n";
779
780 } else if (equal_ustring(list[0], "cat")) {
781 xml += "<Cat " + qtoString(fullFilename, line + 1, level) + " name=" + q(list[1]) + ">";
782 for (i = 2; i < 100 && list[i][0]; i++) {
783 if (i > 2) {
784 xml += ",";
785 }
786 xml += q(list[i]);
787 }
788 xml += "</Cat>\n";
789
790 } else if (equal_ustring(list[0], "comment")) {
791 xml += "<Comment " + qtoString(fullFilename, line + 1, level) + ">" + list[1] + "</Comment>\n";
792
793 } else if (equal_ustring(list[0], "exit")) {
794 xml += "<Exit " + qtoString(fullFilename, line + 1, level) + " />\n";
795
796 } else if (equal_ustring(list[0], "goto")) {
797 xml += "<Goto " + qtoString(fullFilename, line + 1, level) + " sline=" + q(list[1]) + " />\n";
798
799 } else if (equal_ustring(list[0], "if")) {
800 xml += "<If " + qtoString(fullFilename, line + 1, level) + " condition=\"";
801 for (i = 1; i < 100 && list[i][0] && stricmp(list[i], "THEN") != 0; i++) {
802 xml += list[i];
803 }
804 xml += "\">\n";
805
806 } else if (equal_ustring(list[0], "else")) {
807 xml += "<Else />\n";
808
809 } else if (equal_ustring(list[0], "endif")) {
810 xml += "</If>\n";
811
812 } else if (equal_ustring(list[0], "loop")) {
813 /* find end of loop */
814 for (i = line, nest = 0; i < n_lines; i++) {
815 strbreak(lines[i], list2, 100, ", ", FALSE);
816 if (equal_ustring(list2[0], "loop"))
817 nest++;
818 if (equal_ustring(list2[0], "endloop")) {
819 nest--;
820 if (nest == 0)
821 break;
822 }
823 }
824 if (i < n_lines)
825 endl = i + 1;
826 else
827 endl = line + 1;
828 if (list[2][0] == 0) {
829 xml += "<Loop " + qtoString(fullFilename, line + 1, level) + " le=\"" + std::to_string(endl) + "\" n=" + q(list[1]) + ">\n";
830 } else if (list[3][0] == 0) {
831 xml += "<Loop " + qtoString(fullFilename, line + 1, level) + " le=\"" + std::to_string(endl) + "\" var=" + q(list[1]) + " n=" +
832 q(list[2]) + ">\n";
833 } else {
834 xml += "<Loop " + qtoString(fullFilename, line + 1, level) + " le=\"" + std::to_string(endl) + "\" var=" + q(list[1]) + " values=\"";
835 for (i = 2; i < 100 && list[i][0]; i++) {
836 if (i > 2) {
837 xml += ",";
838 }
839 xml += list[i];
840 }
841 xml += "\">\n";
842 }
843 } else if (equal_ustring(list[0], "endloop")) {
844 xml += "</Loop>\n";
845
846 } else if (equal_ustring(list[0], "break")) {
847 xml += "<Break "+ qtoString(fullFilename, line + 1, level) +"></Break>\n";
848
849 } else if (equal_ustring(list[0], "message")) {
850 xml += "<Message " + qtoString(fullFilename, line + 1, level);
851 if (list[2][0] == '1')
852 xml += " wait=\"1\"";
853 xml += ">";
854 xml += list[1];
855 xml += "</Message>\n";
856
857 } else if (equal_ustring(list[0], "msg")) {
858 if (list[2][0]) {
859 xml += "<Msg " + qtoString(fullFilename, line + 1, level) + " type=\""+list[2]+"\">" + list[1] + "</Msg>\n";
860 } else {
861 xml += "<Msg " + qtoString(fullFilename, line + 1, level) + ">" + list[1] + "</Msg>\n";
862 }
863
864 } else if (equal_ustring(list[0], "odbinc")) {
865 if (list[2][0] == 0)
866 mstrlcpy(list[2], "1", 2);
867 xml += "<ODBInc " + qtoString(fullFilename, line + 1, level) + " path=" + q(list[1]) + ">" + list[2] + "</ODBInc>\n";
868
869 } else if (equal_ustring(list[0], "odbcreate")) {
870 if (list[3][0]) {
871 xml += "<ODBCreate " + qtoString(fullFilename, line + 1, level) + " size=" + q(list[3]) + " path=" + q(list[1]) + " type=" +
872 q(list[2]) + "></ODBCreate>\n";
873 } else {
874 xml += "<ODBCreate " + qtoString(fullFilename, line + 1, level) + " path=" + q(list[1]) + " type=" + q(list[2]) +
875 "></ODBCreate>\n";
876 }
877
878 } else if (equal_ustring(list[0], "odbdelete")) {
879 xml += "<ODBDelete " + qtoString(fullFilename, line + 1, level) + ">" + list[1] + "</ODBDelete>\n";
880
881 } else if (equal_ustring(list[0], "odbset")) {
882 if (list[3][0]) {
883 xml += "<ODBSet " + qtoString(fullFilename, line + 1, level) + " notify=" + q(list[3]) + " path=" + q(list[1]) + ">" +
884 list[2] + "</ODBSet>\n";
885 } else {
886 xml += "<ODBSet " + qtoString(fullFilename, line + 1, level) + " path=" + q(list[1]) + ">" + list[2] + "</ODBSet>\n";
887 }
888
889 } else if (equal_ustring(list[0], "odbload")) {
890 if (list[2][0]) {
891 xml += "<ODBLoad " + qtoString(fullFilename, line + 1, level) + " path=" + q(list[2]) + ">" + list[1] + "</ODBLoad>\n";
892 } else {
893 xml += "<ODBLoad " + qtoString(fullFilename, line + 1, level) + ">" + list[1] + "</ODBLoad>\n";
894 }
895
896 } else if (equal_ustring(list[0], "odbget")) {
897 xml += "<ODBGet " + qtoString(fullFilename, line + 1, level) + " path=" + q(list[1]) + ">" + list[2] + "</ODBGet>\n";
898
899 } else if (equal_ustring(list[0], "odblookup")) {
900 xml += "<ODBLookup " + qtoString(fullFilename, line + 1, level) + " path=" + q(list[1]) +
901 " string=" + q(list[2]) + ">" + list[3] + "</ODBLookup>\n";
902
903 } else if (equal_ustring(list[0], "odbsave")) {
904 xml += "<ODBSave " + qtoString(fullFilename, line + 1, level) + " path=" + q(list[1]) + ">" + list[2] + "</ODBSave>\n";
905
906 } else if (equal_ustring(list[0], "odbsubdir")) {
907 if (list[2][0]) {
908 xml += "<ODBSubdir " + qtoString(fullFilename, line + 1, level) + " notify=" + q(list[2]) + " path=" + q(list[1]) + ">\n";
909 } else {
910 xml += "<ODBSubdir " + qtoString(fullFilename, line + 1, level) + " path=" + q(list[1]) + ">\n";
911 }
912 } else if (equal_ustring(list[0], "endodbsubdir")) {
913 xml += "</ODBSubdir>\n";
914
915 } else if (equal_ustring(list[0], "param")) {
916 if (list[2][0] == 0 || equal_ustring(list[2], "bool")) { // name and bool
917 snprintf(error, error_size, "Parameter \"%s\" misses 'comment'", list[1]);
918 *error_line = line + 1;
919 return FALSE;
920
921 } else if (!list[4][0] && equal_ustring(list[3], "bool")) { // name, comment and bool
922 xml += "<Param " + qtoString(fullFilename, line + 1, level) + " name=" + q(list[1]) + " type=\"bool\" " + " comment=" + q(list[2]) + "/>\n";
923 bool v = false;
924 c->odbs->RB((std::string("Param/Value/") + list[1]).c_str(), &v, true);
925 c->odbs->WS((std::string("Param/Comment/") + list[1]).c_str(), list[2]);
926 } else if (!list[5][0] && equal_ustring(list[4], "bool")) { // name, comment, default and bool
927 xml += "<Param " + qtoString(fullFilename, line + 1, level) + " name=" + q(list[1]) + " type=\"bool\" default=" + q(list[4]) +"/>\n";
928 std::string def(list[3]);
929 bool v(def == "1" || def == "true" || def == "TRUE");
930 c->odbs->RB((std::string("Param/Value/") + list[1]).c_str(), &v, true);
931 c->odbs->WS((std::string("Param/Comment/") + list[1]).c_str(), list[2]);
932 c->odbs->WS((std::string("Param/Defaults/") + list[1]).c_str(), list[3]);
933
934 } else if (!list[3][0]) { // name and comment
935 xml += "<Param " + qtoString(fullFilename, line + 1, level) + " name=" + q(list[1]) + " comment=" + q(list[2]) + " />\n";
936 std::string v;
937 c->odbs->RS((std::string("Param/Value/") + list[1]).c_str(), &v, true);
938 c->odbs->WS((std::string("Param/Comment/") + list[1]).c_str(), list[2]);
939 } else if (!list[4][0]) { // name, comment and default
940 xml += "<Param " + qtoString(fullFilename, line + 1, level) + " name=" + q(list[1]) + " comment=" + q(list[2]) + " default=" + q(list[3]) + " />\n";
941 std::string v(list[3]);
942 c->odbs->RS((std::string("Param/Value/") + list[1]).c_str(), &v, true);
943 c->odbs->WS((std::string("Param/Comment/") + list[1]).c_str(), list[2]);
944 c->odbs->WS((std::string("Param/Defaults/") + list[1]).c_str(), list[3]);
945 // ss_sleep(1000); // use this for parameter test
946 } else {
947 xml += "<Param " + qtoString(fullFilename, line + 1, level) + " name=" + q(list[1]) + " comment=" + q(list[2]) +
948 " options=\"";
949 std::string v;
950 c->odbs->RS((std::string("Param/Value/") + list[1]).c_str(), &v, true);
951 c->odbs->WS((std::string("Param/Comment/") + list[1]).c_str(), list[2]);
952 std::vector<std::string> options;
953 for (i = 3; i < 100 && list[i][0]; i++) {
954 if (i > 3) {
955 xml += ",";
956 }
957 xml += list[i];
958 options.push_back(list[i]);
959 }
960 xml += "\" />\n";
961 c->odbs->WSA((std::string("Param/Options/") + list[1]).c_str(), options, 0);
962 }
963
964 // put back old parameter value if existing
965 try {
966 std::string ov = oldSeqParam[(const char *)list[1]];
967 c->odbs->WS((std::string("Param/Value/") + list[1]).c_str(), ov.c_str());
968 } catch(mexception &e) {}
969
970 } else if (equal_ustring(list[0], "rundescription")) {
971 xml += "<RunDescription " + qtoString(fullFilename, line + 1, level) + ">" + list[1] + "</RunDescription>\n";
972
973 } else if (equal_ustring(list[0], "script")) {
974 if (list[2][0] == 0) {
975 xml += "<Script " + qtoString(fullFilename, line + 1, level) + ">" + list[1] + "</Script>\n";
976 } else {
977 xml += "<Script " + qtoString(fullFilename, line + 1, level) + " params=\"";
978 for (i = 2; i < 100 && list[i][0]; i++) {
979 if (i > 2) {
980 xml += ",";
981 }
982 xml += list[i];
983 }
984 xml += "\">";
985 xml += list[1];
986 xml += "</Script>\n";
987 }
988
989 } else if (equal_ustring(list[0], "set")) {
990 xml += "<Set " + qtoString(fullFilename, line + 1, level) + " name=" + q(list[1]) + ">" + list[2] + "</Set>\n";
991
992 } else if (equal_ustring(list[0], "subroutine")) {
993 xml += "\n<Subroutine " + qtoString(fullFilename, line + 1, level) + " name=" + q(list[1]) + ">\n";
994
995 } else if (equal_ustring(list[0], "endsubroutine")) {
996 xml += "</Subroutine>\n";
997
998 } else if (equal_ustring(list[0], "transition")) {
999 xml += "<Transition " + qtoString(fullFilename, line + 1, level) + ">" + list[1] + "</Transition>\n";
1000
1001 } else if (equal_ustring(list[0], "wait")) {
1002 if (!list[2][0]) {
1003 xml += "<Wait " + qtoString(fullFilename, line + 1, level) + " for=\"seconds\">" + list[1] + "</Wait>\n";
1004 } else if (!list[3][0]) {
1005 xml += "<Wait " + qtoString(fullFilename, line + 1, level) + " for=" + q(list[1]) + ">" + list[2] + "</Wait>\n";
1006 } else {
1007 xml += "<Wait " + qtoString(fullFilename, line + 1, level) + " for=" + q(list[1]) + " path=" + q(list[2]) + " op=" +
1008 q(list[3]) + ">" + list[4] + "</Wait>\n";
1009 }
1010
1011 } else if (list[0][0] == 0 || list[0][0] == '#') {
1012 /* skip empty or out-commented lines */
1013 } else {
1014 snprintf(error, error_size, "Invalid command \"%s\"", list[0]);
1015 *error_line = line + 1;
1016 return FALSE;
1017 }
1018 }
1019
1020 free(lines);
1021 free(buf);
1022 if (library) {
1023 xml += "\n</Library>\n";
1024 } else {
1025 xml += "</RunSequence>\n";
1026 }
1027
1028 // write XML to .xml file
1029 fprintf(fout, "%s", xml.c_str());
1030 fclose(fout);
1031
1032 return TRUE;
1033}
std::string cm_get_path()
Definition midas.cxx:1552
#define O_TEXT
Definition msystem.h:227
static std::string qtoString(std::string filename, int line, int level)
static BOOL msl_parse(SEQUENCER &seq, SeqCon *c, int level, const char *cpath, const char *filename, const char *xml_filename, char *error, int error_size, int *error_line)
static std::string q(const char *s)
std::vector< FMT_ID > eq
Definition mdump.cxx:55
DWORD BOOL
Definition midas.h:105
#define read(n, a, f)
INT j
Definition odbhist.cxx:40
BOOL running
Definition sequencer.h:18
static double e(void)
Definition tinyexpr.c:136
Here is the call graph for this function:
Here is the caller graph for this function:

◆ q()

static std::string q ( const char *  s)
static

Definition at line 141 of file msequencer.cxx.

141 {
142 return "\"" + std::string(s) + "\"";
143}
Here is the caller graph for this function:

◆ qtoString()

static std::string qtoString ( std::string  filename,
int  line,
int  level 
)
static

Definition at line 133 of file msequencer.cxx.

133 {
134 std::string buf = "l=\"" + std::to_string(line) + "\"";
135 buf += " fn=\"" + filename + "\"";
136 if (level)
137 buf += " lvl=\"" + std::to_string(level) + "\"";
138 return buf;
139}
Here is the caller graph for this function:

◆ seq_array_index()

void seq_array_index ( SEQUENCER seq,
SeqCon c,
char *  odbpath,
int *  index1,
int *  index2 
)

Definition at line 1478 of file msequencer.cxx.

1478 {
1479 char str[256];
1480 *index1 = *index2 = 0;
1481 if (odbpath[strlen(odbpath) - 1] == ']') {
1482 if (strchr(odbpath, '[')) {
1483 //check for sequencer variables
1484 if (strchr((strchr(odbpath, '[') + 1), '$')) {
1485 mstrlcpy(str, strchr(odbpath, '[') + 1, sizeof(str));
1486 if (strchr(str, ']'))
1487 *strchr(str, ']') = 0;
1488 *index1 = atoi(eval_var(seq, c, str).c_str());
1489
1490 *strchr(odbpath, '[') = 0;
1491 } else {
1492 //standard expansion
1493 strarrayindex(odbpath, index1, index2);
1494 }
1495 }
1496 }
1497}
void strarrayindex(char *odbpath, int *index1, int *index2)
Definition odb.cxx:3357
Here is the call graph for this function:
Here is the caller graph for this function:

◆ seq_cancel_stop_after_run()

static void seq_cancel_stop_after_run ( SEQUENCER seq,
SeqCon c 
)
static

Definition at line 1192 of file msequencer.cxx.

1192 {
1193 seq_read(&seq, c);
1194 seq.stop_after_run = false;
1195 seq_write(seq, c);
1196}
BOOL stop_after_run
Definition sequencer.h:25
Here is the call graph for this function:
Here is the caller graph for this function:

◆ seq_clear()

void seq_clear ( SEQUENCER seq)

Definition at line 1073 of file msequencer.cxx.

1073 {
1074 seq.running = FALSE;
1075 seq.finished = FALSE;
1076 seq.paused = FALSE;
1078 seq.wait_limit = 0;
1079 seq.wait_value = 0;
1080 seq.start_time = 0;
1081 seq.wait_type[0] = 0;
1082 seq.wait_odb[0] = 0;
1083 for (int i = 0; i < SEQ_NEST_LEVEL_LOOP; i++) {
1084 seq.loop_start_line[i] = 0;
1085 seq.sloop_start_line[i] = 0;
1086 seq.loop_end_line[i] = 0;
1087 seq.sloop_end_line[i] = 0;
1088 seq.loop_counter[i] = 0;
1089 seq.loop_n[i] = 0;
1090 }
1091 for (int i = 0; i < SEQ_NEST_LEVEL_IF; i++) {
1092 seq.if_else_line[i] = 0;
1093 seq.if_endif_line[i] = 0;
1094 }
1095 for (int i = 0; i < SEQ_NEST_LEVEL_SUB; i++) {
1096 seq.subroutine_end_line[i] = 0;
1097 seq.subroutine_return_line[i] = 0;
1098 seq.subroutine_call_line[i] = 0;
1099 seq.ssubroutine_call_line[i] = 0;
1100 seq.subroutine_param[i][0] = 0;
1101 }
1102 seq.current_line_number = 0;
1103 seq.scurrent_line_number = 0;
1104 seq.sfilename[0] = 0;
1105 seq.if_index = 0;
1106 seq.stack_index = 0;
1107 seq.error[0] = 0;
1108 seq.error_line = 0;
1109 seq.serror_line = 0;
1110 seq.subdir[0] = 0;
1111 seq.subdir_end_line = 0;
1112 seq.subdir_not_notify = 0;
1113 seq.message[0] = 0;
1114 seq.message_wait = FALSE;
1115 seq.stop_after_run = FALSE;
1116}
#define SEQ_NEST_LEVEL_IF
Definition sequencer.h:4
#define SEQ_NEST_LEVEL_LOOP
Definition sequencer.h:3
int serror_line
Definition sequencer.h:15
char wait_odb[256]
Definition sequencer.h:50
int if_index
Definition sequencer.h:36
float wait_value
Definition sequencer.h:46
int loop_end_line[SEQ_NEST_LEVEL_LOOP]
Definition sequencer.h:29
float wait_limit
Definition sequencer.h:47
int sloop_start_line[SEQ_NEST_LEVEL_LOOP]
Definition sequencer.h:28
int error_line
Definition sequencer.h:14
BOOL finished
Definition sequencer.h:19
BOOL message_wait
Definition sequencer.h:17
int loop_start_line[SEQ_NEST_LEVEL_LOOP]
Definition sequencer.h:27
int if_else_line[SEQ_NEST_LEVEL_IF]
Definition sequencer.h:38
int sloop_end_line[SEQ_NEST_LEVEL_LOOP]
Definition sequencer.h:30
char subdir[256]
Definition sequencer.h:33
char message[256]
Definition sequencer.h:16
BOOL paused
Definition sequencer.h:20
int if_endif_line[SEQ_NEST_LEVEL_IF]
Definition sequencer.h:39
DWORD start_time
Definition sequencer.h:48
int subroutine_call_line[SEQ_NEST_LEVEL_SUB]
Definition sequencer.h:43
int loop_n[SEQ_NEST_LEVEL_LOOP]
Definition sequencer.h:32
int subdir_end_line
Definition sequencer.h:34
int loop_counter[SEQ_NEST_LEVEL_LOOP]
Definition sequencer.h:31
char error[256]
Definition sequencer.h:13
int scurrent_line_number
Definition sequencer.h:23
char wait_type[32]
Definition sequencer.h:49
char sfilename[256]
Definition sequencer.h:11
int subdir_not_notify
Definition sequencer.h:35
Here is the caller graph for this function:

◆ seq_error()

void seq_error ( SEQUENCER seq,
SeqCon c,
const char *  str 
)

Definition at line 164 of file msequencer.cxx.

164 {
165 int status;
166 HNDLE hKey;
167
168 mstrlcpy(seq.error, str, sizeof(seq.error));
171 seq.running = FALSE;
173
174 status = db_find_key(c->hDB, c->hSeq, "State", &hKey);
175 if (status != DB_SUCCESS)
176 return;
177 status = db_set_record(c->hDB, hKey, &seq, sizeof(seq), 0);
178 if (status != DB_SUCCESS)
179 return;
180
181 cm_msg(MTALK, "sequencer", "Sequencer has stopped with error.");
182}
#define MTALK
Definition midas.h:564
Here is the call graph for this function:
Here is the caller graph for this function:

◆ seq_open_file()

static void seq_open_file ( const char *  str,
SEQUENCER seq,
SeqCon c 
)
static

Definition at line 1262 of file msequencer.cxx.

1262 {
1263 seq.new_file = FALSE;
1264 seq.error[0] = 0;
1265 seq.error_line = 0;
1266 seq.serror_line = 0;
1267 if (c->pnseq) {
1268 mxml_free_tree(c->pnseq);
1269 c->pnseq = NULL;
1270 }
1271 c->odbs->WS("Script/Lines", "");
1272
1273 if (stristr(str, ".msl")) {
1274 int size = (int)strlen(str) + 1;
1275 char *xml_filename = (char *) malloc(size);
1276 mstrlcpy(xml_filename, str, size);
1277 strsubst(xml_filename, size, ".msl", ".xml");
1278 //printf("Parsing MSL sequencer file: %s to XML sequencer file %s\n", str, xml_filename);
1279
1280 std::string path(cm_get_path());
1281 path += "userfiles/sequencer/";
1282
1283 if (xml_filename[0] == '/') {
1284 path += xml_filename;
1285 path = path.substr(0, path.find_last_of('/') + 1);
1286 mstrlcpy(xml_filename, path.substr(path.find_last_of('/') + 1).c_str(), size);
1287 } else {
1288 path += seq.path;
1289 }
1290
1291 if (msl_parse(seq, c, 0, path.c_str(), str, xml_filename, seq.error, sizeof(seq.error), &seq.serror_line)) {
1292 //printf("Loading XML sequencer file: %s\n", xml_filename);
1293 std::string fn(path);
1294 if (!fn.empty() && fn.back() != '/')
1295 fn += '/';
1296 fn += xml_filename;
1297 c->pnseq = mxml_parse_file(fn.c_str(), seq.error, sizeof(seq.error), &seq.error_line);
1298 } else {
1299 //printf("Error in MSL sequencer file \"%s\" line %d, error: %s\n", str, seq.serror_line, seq.error);
1300 }
1301 free(xml_filename);
1302 } else {
1303 //printf("Loading XML sequencer file: %s\n", str);
1304 c->pnseq = mxml_parse_file(str, seq.error, sizeof(seq.error), &seq.error_line);
1305 }
1306}
void strsubst(char *string, int size, const char *pattern, const char *subst)
char * stristr(const char *str, const char *pattern)
BOOL new_file
Definition sequencer.h:8
Here is the call graph for this function:
Here is the caller graph for this function:

◆ seq_pause()

static void seq_pause ( SEQUENCER seq,
SeqCon c,
bool  flag 
)
static

Definition at line 1200 of file msequencer.cxx.

1200 {
1201 seq_read(&seq, c);
1202 seq.paused = flag;
1203 if (!flag)
1204 seq.debug = false;
1205 seq_write(seq, c);
1206}
BOOL debug
Definition sequencer.h:21
Here is the call graph for this function:
Here is the caller graph for this function:

◆ seq_read()

void seq_read ( SEQUENCER seq,
SeqCon c 
)

Definition at line 1037 of file msequencer.cxx.

1037 {
1038 int status;
1039 HNDLE hKey;
1040
1041 status = db_find_key(c->hDB, c->hSeq, "State", &hKey);
1042 if (status != DB_SUCCESS) {
1043 cm_msg(MERROR, "seq_read", "Cannot find /Sequencer/State in ODB, db_find_key() status %d", status);
1044 return;
1045 }
1046
1047 int size = sizeof(SEQUENCER);
1048 status = db_get_record1(c->hDB, hKey, seq, &size, 0, strcomb1(sequencer_str).c_str());
1049 if (status != DB_SUCCESS) {
1050 cm_msg(MERROR, "seq_read", "Cannot get /Sequencer/State from ODB, db_get_record1() status %d", status);
1051 return;
1052 }
1053}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ seq_start()

static void seq_start ( SEQUENCER seq,
SeqCon c,
bool  debug 
)
static

Definition at line 1120 of file msequencer.cxx.

1120 {
1121 seq_read(&seq, c);
1122 seq_clear(seq);
1123
1124 // manage sequencer parameters and variables
1125
1126 midas::odb defaults(std::string("/") + c->odb_path + "/Param/Defaults");
1127 midas::odb param(std::string("/") + c->odb_path + "/Param/Value");
1128 midas::odb vars(std::string("/") + c->odb_path + "/Variables");
1129
1130 // check if /Param/Value is there
1131 for (midas::odb& d: defaults)
1132 if (!param.is_subkey(d.get_name())) {
1133 mstrlcpy(seq.error, "Cannot start script because /Sequencer/Param/Value is incomplete", sizeof(seq.error));
1134 seq_write(seq, c);
1135 cm_msg(MERROR, "sequencer", "Cannot start script because /Sequencer/Param/Value is incomplete");
1136 return;
1137 }
1138
1139 // copy /Sequencer/Param/Value to /Sequencer/Variables
1140 for (midas::odb& p: param)
1141 vars[p.get_name()] = p.s();
1142
1143 if (!c->pnseq) {
1144 mstrlcpy(seq.error, "Cannot start script, no script loaded", sizeof(seq.error));
1145 seq_write(seq, c);
1146 return;
1147 }
1148
1149 // start sequencer
1150 seq.running = TRUE;
1151 seq.debug = debug;
1152 seq.current_line_number = 1;
1153 seq.scurrent_line_number = 1;
1154 mstrlcpy(seq.sfilename, seq.filename, sizeof(seq.sfilename));
1155 seq_write(seq, c);
1156
1157 if (debug)
1158 cm_msg(MTALK, "sequencer", "Sequencer started with script \"%s\" in debugging mode.", seq.filename);
1159 else
1160 cm_msg(MTALK, "sequencer", "Sequencer started with script \"%s\".", seq.filename);
1161}
void seq_clear(SEQUENCER &seq)
BOOL debug
debug printouts
Definition mana.cxx:254
double d
Definition system.cxx:1313
Here is the call graph for this function:
Here is the caller graph for this function:

◆ seq_start_next()

static void seq_start_next ( SEQUENCER seq,
SeqCon c 
)
static

Definition at line 1310 of file msequencer.cxx.

1310 {
1311 seq_read(&seq, c);
1312 if (seq.next_filename[0][0]) {
1313 mstrlcpy(seq.filename, seq.next_filename[0], sizeof(seq.filename));
1314 for (int i=0 ; i<9 ; i++)
1315 mstrlcpy(seq.next_filename[i], seq.next_filename[i+1], 256);
1316 seq.next_filename[9][0] = 0;
1317 seq_write(seq, c);
1318
1319 seq_open_file(seq.filename, seq, c);
1320
1321 seq_start(seq, c, false);
1322 }
1323}
static void seq_start(SEQUENCER &seq, SeqCon *c, bool debug)
char next_filename[10][256]
Definition sequencer.h:12
Here is the call graph for this function:
Here is the caller graph for this function:

◆ seq_step_over()

static void seq_step_over ( SEQUENCER seq,
SeqCon c 
)
static

Definition at line 1253 of file msequencer.cxx.

1253 {
1254 seq_read(&seq, c);
1255 seq.paused = false;
1256 seq.debug = true;
1257 seq_write(seq, c);
1258}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ seq_stop()

static void seq_stop ( SEQUENCER seq,
SeqCon c 
)
static

Definition at line 1165 of file msequencer.cxx.

1165 {
1166 seq_read(&seq, c);
1167
1168 if (seq.follow_libraries) {
1169 std::string path(cm_get_path());
1170 path += "userfiles/sequencer/";
1171 path += seq.path;
1172 path += seq.filename;
1173
1174 loadMSL(c->odbs, path);
1175 }
1176
1177 seq_clear(seq);
1178 seq.finished = TRUE;
1179 seq_write(seq, c);
1180}
bool loadMSL(MVOdb *o, const std::string &filename)
int follow_libraries
Definition sequencer.h:24
Here is the call graph for this function:
Here is the caller graph for this function:

◆ seq_stop_after_run()

static void seq_stop_after_run ( SEQUENCER seq,
SeqCon c 
)
static

Definition at line 1184 of file msequencer.cxx.

1184 {
1185 seq_read(&seq, c);
1186 seq.stop_after_run = true;
1187 seq_write(seq, c);
1188}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ seq_watch()

static void seq_watch ( HNDLE  hDB,
HNDLE  hKeyChanged,
int  index,
void *  info 
)
static

Definition at line 1327 of file msequencer.cxx.

1327 {
1328 char str[256];
1329 SeqCon* c = (SeqCon*)info;
1330
1331 seq_read(c->seqp, c);
1332
1333 if (c->seqp->new_file) {
1334 mstrlcpy(str, c->seqp->path, sizeof(str));
1335 if (strlen(str) > 1 && str[strlen(str) - 1] != DIR_SEPARATOR)
1336 mstrlcat(str, DIR_SEPARATOR_STR, sizeof(str));
1337 mstrlcat(str, c->seqp->filename, sizeof(str));
1338
1339 //printf("Load file %s\n", str);
1340
1341 seq_open_file(str, *(c->seqp), c);
1342
1343 seq_clear(*(c->seqp));
1344
1345 seq_write(*(c->seqp), c);
1346 }
1347}
void ** info
Definition fesimdaq.cxx:41
Here is the call graph for this function:
Here is the caller graph for this function:

◆ seq_watch_command()

static void seq_watch_command ( HNDLE  hDB,
HNDLE  hKeyChanged,
int  index,
void *  info 
)
static

Definition at line 1351 of file msequencer.cxx.

1351 {
1352 SeqCon* c = (SeqCon*)info;
1353 SEQUENCER* seqp = c->seqp;
1354
1355 bool start_script = false;
1356 bool stop_immediately = false;
1357 bool stop_after_run = false;
1358 bool cancel_stop_after_run = false;
1359 bool pause_script = false;
1360 bool resume_script = false;
1361 bool debug_script = false;
1362 bool step_over = false;
1363 bool load_new_file = false;
1364
1365 c->odbs->RB("Command/Start script", &start_script);
1366 c->odbs->RB("Command/Stop immediately", &stop_immediately);
1367 c->odbs->RB("Command/Stop after run", &stop_after_run);
1368 c->odbs->RB("Command/Cancel stop after run", &cancel_stop_after_run);
1369 c->odbs->RB("Command/Pause script", &pause_script);
1370 c->odbs->RB("Command/Resume script", &resume_script);
1371 c->odbs->RB("Command/Debug script", &debug_script);
1372 c->odbs->RB("Command/Step over", &step_over);
1373 c->odbs->RB("Command/Load new file", &load_new_file);
1374
1375 if (load_new_file) {
1376 std::string filename;
1377 c->odbs->RS("State/Filename", &filename);
1378
1379 // printf("## load new file %s\n", filename.c_str());
1380
1381 if (filename.find("..") != std::string::npos) {
1382 mstrlcpy(seqp->error, "Cannot load \"", sizeof(seqp->error));
1383 mstrlcat(seqp->error, filename.c_str(), sizeof(seqp->error));
1384 mstrlcat(seqp->error, "\": file names with \"..\" is not permitted", sizeof(seqp->error));
1385 seq_write(*seqp, c);
1386 } else if (filename.find(".msl") == std::string::npos) {
1387 mstrlcpy(seqp->error, "Cannot load \"", sizeof(seqp->error));
1388 mstrlcat(seqp->error, filename.c_str(), sizeof(seqp->error));
1389 mstrlcat(seqp->error, "\": file name should end with \".msl\"", sizeof(seqp->error));
1390 seq_write(*seqp, c);
1391 } else {
1392 mstrlcpy(seqp->filename, filename.c_str(), sizeof(seqp->filename));
1393 std::string path = cm_expand_env(seqp->path);
1394 if (path.length() > 0 && path.back() != '/') {
1395 path += "/";
1396 }
1397 HNDLE hDB;
1399 seq_clear(*seqp);
1400 seq_open_file(filename.c_str(), *seqp, c);
1401 seq_write(*seqp, c);
1402 }
1403
1404 // indicate that we successfully load the new file
1405 c->odbs->WB("Command/Load new file", false);
1406
1407 // printf("## Set 'load new file' false\n");
1408 }
1409
1410 if (start_script) {
1411 c->odbs->WB("Command/Start script", false);
1412
1413 bool seq_running = false;
1414 c->odbs->RB("State/running", &seq_running);
1415
1416 if (!seq_running) {
1417 seq_start(*seqp, c, false);
1418 } else {
1419 cm_msg(MTALK, "sequencer", "Sequencer is already running");
1420 }
1421 }
1422
1423 if (stop_immediately) {
1424 if (!goto_at_exit(*seqp, c)) {
1425 c->odbs->WB("Command/Stop immediately", false);
1426 seq_stop(*seqp, c);
1427 cm_msg(MTALK, "sequencer", "Sequencer is finished by \"stop immediately\".");
1428 } else {
1429 c->odbs->WB("Command/Stop immediately", false);
1430 cm_msg(MTALK, "sequencer", "Sequencer received \"stop immediately\". Executing ATEXIT.");
1431 }
1432 }
1433
1434 if (stop_after_run) {
1435 c->odbs->WB("Command/Stop after run", false);
1436 seq_stop_after_run(*seqp, c);
1437 }
1438
1439 if (cancel_stop_after_run) {
1440 c->odbs->WB("Command/Cancel stop after run", false);
1442 }
1443
1444 if (pause_script) {
1445 seq_pause(*seqp, c, true);
1446 c->odbs->WB("Command/Pause script", false);
1447 cm_msg(MTALK, "sequencer", "Sequencer is paused.");
1448 }
1449
1450 if (resume_script) {
1451 seq_pause(*seqp, c, false);
1452 c->odbs->WB("Command/Resume script", false);
1453 cm_msg(MTALK, "sequencer", "Sequencer is resumed.");
1454 }
1455
1456 if (debug_script) {
1457 c->odbs->WB("Command/Debug script", false);
1458
1459 bool seq_running = false;
1460 c->odbs->RB("State/running", &seq_running);
1461
1462 if (!seq_running) {
1463 seq_start(*seqp, c, true);
1464 } else {
1465 cm_msg(MTALK, "sequencer", "Sequencer is already running");
1466 }
1467 }
1468
1469 if (step_over) {
1470 seq_step_over(*seqp, c);
1471 c->odbs->WB("Command/Step over", false);
1472 }
1473}
std::string cm_expand_env(const char *str)
Definition midas.cxx:7720
static void seq_stop_after_run(SEQUENCER &seq, SeqCon *c)
static void seq_stop(SEQUENCER &seq, SeqCon *c)
static BOOL goto_at_exit(SEQUENCER &seq, SeqCon *c)
static void seq_step_over(SEQUENCER &seq, SeqCon *c)
static void seq_cancel_stop_after_run(SEQUENCER &seq, SeqCon *c)
static void seq_pause(SEQUENCER &seq, SeqCon *c, bool flag)
Here is the call graph for this function:
Here is the caller graph for this function:

◆ seq_write()

void seq_write ( const SEQUENCER seq,
SeqCon c 
)

Definition at line 1055 of file msequencer.cxx.

1055 {
1056 int status;
1057 HNDLE hKey;
1058
1059 status = db_find_key(c->hDB, c->hSeq, "State", &hKey);
1060 if (status != DB_SUCCESS) {
1061 cm_msg(MERROR, "seq_write", "Cannot find /Sequencer/State in ODB, db_find_key() status %d", status);
1062 return;
1063 }
1064 status = db_set_record(c->hDB, hKey, (void *) &seq, sizeof(SEQUENCER), 0);
1065 if (status != DB_SUCCESS) {
1066 cm_msg(MERROR, "seq_write", "Cannot write to ODB /Sequencer/State, db_set_record() status %d", status);
1067 return;
1068 }
1069}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ sequencer()

void sequencer ( SEQUENCER seq,
SeqCon c 
)

Definition at line 1547 of file msequencer.cxx.

1547 {
1548 PMXML_NODE pn, pr, pt, pe;
1549 char odbpath[256], data[256], str[1024], name[32], op[32];
1550 std::string value;
1551 char list[100][XNAME_LENGTH];
1552 int i, j, l, n, status, size, index1, index2, state, run_number, cont;
1553 HNDLE hKey, hKeySeq;
1554 KEY key;
1555 double d;
1556 BOOL skip_step = FALSE;
1557
1558 if (!seq.running || seq.paused) {
1559 ss_sleep(10);
1560 return;
1561 }
1562
1563 if (c->pnseq == NULL) {
1564 seq_stop(seq, c);
1565 mstrlcpy(seq.error, "No script loaded", sizeof(seq.error));
1566 seq_write(seq, c);
1567 ss_sleep(10);
1568 return;
1569 }
1570
1571 db_find_key(c->hDB, c->hSeq, "State", &hKeySeq);
1572 if (!hKeySeq)
1573 return;
1574
1575 // Retrieve last midas message and put it into seq structure (later sent to ODB via db_set_record()
1576 cm_msg_retrieve(1, str, sizeof(str));
1577 str[19] = 0;
1578 strcpy(seq.last_msg, str+11);
1579
1580 pr = mxml_find_node(c->pnseq, "RunSequence");
1581 if (!pr) {
1582 seq_error(seq, c, "Cannot find &lt;RunSequence&gt; tag in XML file");
1583 return;
1584 }
1585
1586 int last_line = mxml_get_line_number_end(pr);
1587
1588 /* check for Subroutine end */
1589 if (seq.stack_index > 0 && seq.current_line_number == seq.subroutine_end_line[seq.stack_index - 1]) {
1590 seq_read(&seq, c);
1591 seq.subroutine_end_line[seq.stack_index - 1] = 0;
1592
1593 if (seq.subroutine_return_line[seq.stack_index - 1] == -1) {
1594 // end of atexit subroutine
1595 seq_stop(seq, c);
1596 cm_msg(MTALK, "sequencer", "Sequencer is finished.");
1597
1598 seq_start_next(seq, c);
1599 return;
1600 }
1601
1603 seq.subroutine_return_line[seq.stack_index - 1] = 0;
1604 seq.subroutine_call_line[seq.stack_index - 1] = 0;
1605 seq.ssubroutine_call_line[seq.stack_index - 1] = 0;
1606 seq.stack_index--;
1607 seq_write(seq, c);
1608 return;
1609 }
1610
1611 /* check for last line of script */
1612 if (seq.current_line_number > last_line) {
1613
1614 if (!goto_at_exit(seq, c)) {
1615 seq_stop(seq, c);
1616 cm_msg(MTALK, "sequencer", "Sequencer is finished.");
1617
1618 seq_start_next(seq, c);
1619 }
1620 return;
1621 }
1622
1623 /* check for loop end */
1624 for (i = SEQ_NEST_LEVEL_LOOP-1; i >= 0; i--)
1625 if (seq.loop_start_line[i] > 0)
1626 break;
1627 if (i >= 0) {
1628 if (seq.current_line_number == seq.loop_end_line[i]) {
1629 size = sizeof(seq);
1630 db_get_record(c->hDB, hKeySeq, &seq, &size, 0);
1631
1632 if (seq.loop_counter[i] == seq.loop_n[i]) {
1633 seq.loop_counter[i] = 0;
1634 seq.loop_start_line[i] = 0;
1635 seq.sloop_start_line[i] = 0;
1636 seq.loop_end_line[i] = 0;
1637 seq.sloop_end_line[i] = 0;
1638 seq.loop_n[i] = 0;
1639 seq.current_line_number++;
1640 } else {
1641 pn = mxml_get_node_at_line(c->pnseq, seq.loop_start_line[i]);
1642 if (mxml_get_attribute(pn, "var")) {
1643 mstrlcpy(name, mxml_get_attribute(pn, "var"), sizeof(name));
1644 if (mxml_get_attribute(pn, "values")) {
1645 mstrlcpy(data, mxml_get_attribute(pn, "values"), sizeof(data));
1646 strbreak(data, list, 100, ",", FALSE);
1647 value = eval_var(seq, c, list[seq.loop_counter[i]]);
1648 } else if (mxml_get_attribute(pn, "n")) {
1649 value = std::to_string(seq.loop_counter[i] + 1);
1650 }
1651 sprintf(str, "Variables/%s", name); // FIXME: unsafe
1652 size = value.length() + 1;
1653 if (size < 32)
1654 size = 32;
1655 db_set_value(c->hDB, c->hSeq, str, value.c_str(), size, 1, TID_STRING);
1656 }
1657 seq.loop_counter[i]++;
1658 seq.current_line_number = seq.loop_start_line[i] + 1;
1659 }
1660 db_set_record(c->hDB, hKeySeq, &seq, sizeof(seq), 0);
1661 return;
1662 }
1663 }
1664
1665 /* check for end of "if" statement */
1666 if (seq.if_index > 0 && seq.current_line_number == seq.if_endif_line[seq.if_index - 1]) {
1667 size = sizeof(seq);
1668 db_get_record(c->hDB, hKeySeq, &seq, &size, 0);
1669 seq.if_index--;
1670 seq.if_line[seq.if_index] = 0;
1671 seq.if_else_line[seq.if_index] = 0;
1672 seq.if_endif_line[seq.if_index] = 0;
1673 seq.current_line_number++;
1674 db_set_record(c->hDB, hKeySeq, &seq, sizeof(seq), 0);
1675 return;
1676 }
1677
1678 /* check for ODBSubdir end */
1679 if (seq.current_line_number == seq.subdir_end_line) {
1680 size = sizeof(seq);
1681 db_get_record(c->hDB, hKeySeq, &seq, &size, 0);
1682 seq.subdir_end_line = 0;
1683 seq.subdir[0] = 0;
1685 db_set_record(c->hDB, hKeySeq, &seq, sizeof(seq), 0);
1686 return;
1687 }
1688
1689 /* find node belonging to current line */
1690 pn = mxml_get_node_at_line(c->pnseq, seq.current_line_number);
1691 if (!pn) {
1692 size = sizeof(seq);
1693 db_get_record(c->hDB, hKeySeq, &seq, &size, 0);
1694 seq.current_line_number++;
1695 db_set_record(c->hDB, hKeySeq, &seq, sizeof(seq), 0);
1696 return;
1697 }
1698
1699 /* set MSL line from current element and put script into ODB if changed (library call) */
1700 pn = mxml_get_node_at_line(c->pnseq, seq.current_line_number);
1701 if (pn) {
1702 if (seq.follow_libraries) {
1703 if (mxml_get_attribute(pn, "l"))
1704 seq.scurrent_line_number = atoi(mxml_get_attribute(pn, "l"));
1705 if (mxml_get_attribute(pn, "fn")) {
1706 std::string filename = mxml_get_attribute(pn, "fn");
1707
1708 // load file into ODB if changed
1709 if (filename != std::string(seq.sfilename)) {
1710 if (loadMSL(c->odbs, filename))
1711 mstrlcpy(seq.sfilename, filename.c_str(), sizeof(seq.sfilename));
1712 }
1713 }
1714 } else {
1715 if (mxml_get_attribute(pn, "l") && (!mxml_get_attribute(pn, "lvl") || atoi(mxml_get_attribute(pn, "lvl")) == 0))
1716 seq.scurrent_line_number = atoi(mxml_get_attribute(pn, "l"));
1717 }
1718 }
1719
1720
1721 // out-comment following lines for debug output
1722#if 0
1723 if (seq.scurrent_line_number >= 0) {
1724 midas::odb o("/" + c->odb_path + "/Script/Lines");
1725 std::string s = o[seq.scurrent_line_number - 1];
1726 printf("%3d: %s\n", seq.scurrent_line_number, s.c_str());
1727 }
1728#endif
1729
1730 if (equal_ustring(mxml_get_name(pn), "PI") || equal_ustring(mxml_get_name(pn), "RunSequence") ||
1731 equal_ustring(mxml_get_name(pn), "Comment")) {
1732 // just skip
1733 seq.current_line_number++;
1734 skip_step = TRUE;
1735 }
1736
1737 /*---- ODBSubdir ----*/
1738 else if (equal_ustring(mxml_get_name(pn), "ODBSubdir")) {
1739 if (!mxml_get_attribute(pn, "path")) {
1740 seq_error(seq, c, "Missing attribute \"path\"");
1741 } else {
1742
1743 std::string s = mxml_get_attribute(pn, "path");
1744 if (s.find('$') != std::string::npos)
1745 s = eval_var(seq, c, s);
1746
1747 mstrlcpy(seq.subdir, s.c_str(), sizeof(seq.subdir));
1748 if (mxml_get_attribute(pn, "notify"))
1749 seq.subdir_not_notify = !atoi(mxml_get_attribute(pn, "notify"));
1750 seq.subdir_end_line = mxml_get_line_number_end(pn);
1751 seq.current_line_number++;
1752 }
1753 }
1754
1755 /*---- ODBSet ----*/
1756 else if (equal_ustring(mxml_get_name(pn), "ODBSet")) {
1757 if (!mxml_get_attribute(pn, "path")) {
1758 seq_error(seq, c, "Missing attribute \"path\"");
1759 } else {
1760 mstrlcpy(odbpath, seq.subdir, sizeof(odbpath));
1761 if (strlen(odbpath) > 0 && odbpath[strlen(odbpath) - 1] != '/')
1762 mstrlcat(odbpath, "/", sizeof(odbpath));
1763 mstrlcat(odbpath, mxml_get_attribute(pn, "path"), sizeof(odbpath));
1764
1765 if (strchr(odbpath, '$')) {
1766 if (strchr(odbpath, '[')) {
1767 // keep $ in index for later evaluation
1768 std::string s(odbpath);
1769 std::string s1 = s.substr(0, s.find('['));
1770 std::string s2 = s.substr(s.find('['));
1771 s1 = eval_var(seq, c, s1);
1772 s1 += s2;
1773 mstrlcpy(odbpath, s1.c_str(), sizeof(odbpath));
1774 } else {
1775 // evaluate variable in path
1776 std::string s(odbpath);
1777 s = eval_var(seq, c, s);
1778 mstrlcpy(odbpath, s.c_str(), sizeof(odbpath));
1779 }
1780 }
1781
1782 int notify = TRUE;
1783 if (seq.subdir_not_notify)
1784 notify = FALSE;
1785 if (mxml_get_attribute(pn, "notify"))
1786 notify = atoi(mxml_get_attribute(pn, "notify"));
1787
1788 index1 = index2 = 0;
1789 seq_array_index(seq, c, odbpath, &index1, &index2);
1790
1791 if (index1 < -1 || index2 < 0) {
1792 seq_error(seq, c, "Negative index not allowed");
1793 return;
1794 }
1795
1796 if (index1 > 1E6 || index2 > 1E6) {
1797 seq_error(seq, c, "Index too large for ODB");
1798 return;
1799 }
1800
1801 value = eval_var(seq, c, mxml_get_value(pn));
1802
1803 status = set_all_matching(c->hDB, 0, odbpath, (char *)value.c_str(), index1, index2, notify);
1804
1805 if (status == DB_SUCCESS) {
1806 size = sizeof(seq);
1807 db_get_record1(c->hDB, hKeySeq, &seq, &size, 0, strcomb1(sequencer_str).c_str());// could have changed seq tree
1808 seq.current_line_number++;
1809 } else if (status == DB_NO_KEY) {
1810 sprintf(str, "ODB key \"%s\" not found", odbpath); // FIXME: unsafe
1811 seq_error(seq, c, str);
1812 } else if (status == DB_INVALID_PARAM) {
1813 sprintf(str, "Invalid index %d for ODB key \"%s\"", index1, odbpath); // FIXME: unsafe
1814 seq_error(seq, c, str);
1815 } else {
1816 //something went really wrong
1817 sprintf(str, "Internal error %d", status);
1818 seq_error(seq, c, str);
1819 return;
1820 }
1821 }
1822 }
1823
1824 /*---- ODBLoad ----*/
1825 else if (equal_ustring(mxml_get_name(pn), "ODBLoad")) {
1826 if (mxml_get_value(pn)[0] == '/') {
1827
1828 // path relative to the one set in <exp>/userfiles/sequencer
1829 std::string path(cm_get_path());
1830 path += "userfiles/sequencer/";
1831 value = path;
1832 value += std::string(mxml_get_value(pn)+1);
1833 } else {
1834 // relative path to msl file
1835 std::string path(cm_get_path());
1836 path += "userfiles/sequencer/";
1837 path += seq.path;
1838 value = path;
1839 if (value.back() != '/')
1840 value += "/";
1841 value += mxml_get_value(pn);
1842 }
1843
1844 if (value.find('$') != std::string::npos)
1845 value = eval_var(seq, c, value);
1846
1847 // if path attribute is given
1848 if (mxml_get_attribute(pn, "path")) {
1849 mstrlcpy(odbpath, seq.subdir, sizeof(odbpath));
1850 if (strlen(odbpath) > 0 && odbpath[strlen(odbpath) - 1] != '/')
1851 mstrlcat(odbpath, "/", sizeof(odbpath));
1852 mstrlcat(odbpath, mxml_get_attribute(pn, "path"), sizeof(odbpath));
1853
1854 if (strchr(odbpath, '$')) {
1855 std::string s(odbpath);
1856 s = eval_var(seq, c, s);
1857 mstrlcpy(odbpath, s.c_str(), sizeof(odbpath));
1858 }
1859
1860 // load at that key, if exists
1861 status = db_find_key(c->hDB, 0, odbpath, &hKey);
1862 if (status != DB_SUCCESS) {
1863 seq_error(seq, c, msprintf("Cannot find ODB key \"%s\"", odbpath).c_str());
1864 return;
1865 } else {
1866 status = db_load(c->hDB, hKey, value.c_str(), FALSE);
1867 }
1868 } else {
1869 // otherwise load at root
1870 status = db_load(c->hDB, 0, value.c_str(), FALSE);
1871 }
1872
1873 if (status == DB_SUCCESS) {
1874 size = sizeof(seq);
1875 db_get_record1(c->hDB, hKeySeq, &seq, &size, 0, strcomb1(sequencer_str).c_str());// could have changed seq tree
1876 seq.current_line_number++;
1877 } else if (status == DB_FILE_ERROR) {
1878 seq_error(seq, c, msprintf("Error reading file \"%s\"", value.c_str()).c_str());
1879 } else {
1880 //something went really wrong
1881 seq_error(seq, c, "Internal error loading ODB file!");
1882 return;
1883 }
1884 }
1885
1886 /*---- ODBSave ----*/
1887 else if (equal_ustring(mxml_get_name(pn), "ODBSave")) {
1888 if (mxml_get_value(pn)[0] == '/') {
1889
1890 // path relative to the one set in <exp>/userfiles/sequencer
1891 std::string path(cm_get_path());
1892 path += "userfiles/sequencer/";
1893 value = path;
1894 value += std::string(mxml_get_value(pn)+1);
1895 } else {
1896 // relative path to msl file
1897 std::string path(cm_get_path());
1898 path += "userfiles/sequencer/";
1899 path += seq.path;
1900 value = path;
1901 value += seq.filename;
1902 size_t pos = value.find_last_of('/');
1903 if (pos != std::string::npos)
1904 value = value.substr(0, pos);
1905 value += mxml_get_value(pn);
1906 }
1907
1908 if (value.find('$') != std::string::npos)
1909 value = eval_var(seq, c, value);
1910
1911 // if path attribute is given
1912 if (mxml_get_attribute(pn, "path") && *mxml_get_attribute(pn, "path")) {
1913 mstrlcpy(odbpath, seq.subdir, sizeof(odbpath));
1914 if (strlen(odbpath) > 0 && odbpath[strlen(odbpath) - 1] != '/')
1915 mstrlcat(odbpath, "/", sizeof(odbpath));
1916 mstrlcat(odbpath, mxml_get_attribute(pn, "path"), sizeof(odbpath));
1917
1918 if (strchr(odbpath, '$')) {
1919 std::string s(odbpath);
1920 s = eval_var(seq, c, s);
1921 mstrlcpy(odbpath, s.c_str(), sizeof(odbpath));
1922 }
1923
1924 // find key or subdirectory to save
1925 status = db_find_key(c->hDB, 0, odbpath, &hKey);
1926 if (status != DB_SUCCESS) {
1927 seq_error(seq, c, msprintf("Cannot find ODB key \"%s\"", odbpath).c_str());
1928 return;
1929 } else {
1930 if (strstr(value.c_str(), ".json") || strstr(value.c_str(), ".JSON") || strstr(value.c_str(), ".js") || strstr(value.c_str(), ".JS"))
1932 else if (strstr(value.c_str(), ".xml") || strstr(value.c_str(), ".XML"))
1933 status = db_save_xml(c->hDB, hKey, value.c_str());
1934 else
1935 status = db_save(c->hDB, hKey, value.c_str(), FALSE);
1936 if (status != DB_SUCCESS) {
1937 seq_error(seq, c, msprintf("Cannot save file \"%s\", error %d", value.c_str(), status).c_str());
1938 return;
1939 }
1940 }
1941 } else {
1942 seq_error(seq, c, "No ODB path specified in ODBSAVE command");
1943 return;
1944 }
1945
1946 if (status == DB_SUCCESS) {
1947 size = sizeof(seq);
1948 db_get_record1(c->hDB, hKeySeq, &seq, &size, 0, strcomb1(sequencer_str).c_str());// could have changed seq tree
1949 seq.current_line_number++;
1950 } else if (status == DB_FILE_ERROR) {
1951 seq_error(seq, c, msprintf("Error reading file \"%s\"", value.c_str()).c_str());
1952 } else {
1953 //something went really wrong
1954 seq_error(seq, c, "Internal error loading ODB file!");
1955 return;
1956 }
1957 }
1958
1959 /*---- ODBGet ----*/
1960 else if (equal_ustring(mxml_get_name(pn), "ODBGet")) {
1961 if (!mxml_get_attribute(pn, "path")) {
1962 seq_error(seq, c, "Missing attribute \"path\"");
1963 } else {
1964 mstrlcpy(odbpath, seq.subdir, sizeof(odbpath));
1965 if (strlen(odbpath) > 0 && odbpath[strlen(odbpath) - 1] != '/')
1966 mstrlcat(odbpath, "/", sizeof(odbpath));
1967 mstrlcat(odbpath, mxml_get_attribute(pn, "path"), sizeof(odbpath));
1968
1969 if (strchr(odbpath, '$')) {
1970 if (strchr(odbpath, '[')) {
1971 // keep $ in index for later evaluation
1972 std::string s(odbpath);
1973 std::string s1 = s.substr(0, s.find('['));
1974 std::string s2 = s.substr(s.find('['));
1975 s1 = eval_var(seq, c, s1);
1976 s1 += s2;
1977 mstrlcpy(odbpath, s1.c_str(), sizeof(odbpath));
1978 } else {
1979 // evaluate variable in path
1980 std::string s(odbpath);
1981 s = eval_var(seq, c, s);
1982 mstrlcpy(odbpath, s.c_str(), sizeof(odbpath));
1983 }
1984 }
1985
1986 /* check if index is supplied */
1987 index1 = index2 = 0;
1988 seq_array_index(seq, c, odbpath, &index1, &index2);
1989
1990 mstrlcpy(name, mxml_get_value(pn), sizeof(name));
1991 status = db_find_key(c->hDB, 0, odbpath, &hKey);
1992 if (status != DB_SUCCESS) {
1993 seq_error(seq, c, msprintf("Cannot find ODB key \"%s\"", odbpath).c_str());
1994 return;
1995 } else {
1996 db_get_key(c->hDB, hKey, &key);
1997 size = sizeof(data);
1998
1999 status = db_get_data_index(c->hDB, hKey, data, &size, index1, key.type);
2000 if (key.type == TID_BOOL)
2001 value = *((int *) data) > 0 ? "1" : "0";
2002 else
2003 value = db_sprintf(data, size, 0, key.type);
2004
2005 sprintf(str, "Variables/%s", name); // FIXME: unsafe
2006 size = value.length() + 1;
2007 if (size < 32)
2008 size = 32;
2009 db_set_value(c->hDB, c->hSeq, str, value.c_str(), size, 1, TID_STRING);
2010
2011 size = sizeof(seq);
2012 db_get_record1(c->hDB, hKeySeq, &seq, &size, 0, strcomb1(sequencer_str).c_str());// could have changed seq tree
2013 seq.current_line_number = mxml_get_line_number_end(pn) + 1;
2014 }
2015 }
2016 }
2017
2018 /*---- ODBLookup ----*/
2019 else if (equal_ustring(mxml_get_name(pn), "ODBLookup")) {
2020 if (!mxml_get_attribute(pn, "path")) {
2021 seq_error(seq, c, "Missing attribute \"path\"");
2022 } else if (!mxml_get_attribute(pn, "string")) {
2023 seq_error(seq, c, "Missing attribute \"string\"");
2024 } else {
2025 mstrlcpy(odbpath, seq.subdir, sizeof(odbpath));
2026 if (strlen(odbpath) > 0 && odbpath[strlen(odbpath) - 1] != '/')
2027 mstrlcat(odbpath, "/", sizeof(odbpath));
2028 mstrlcat(odbpath, mxml_get_attribute(pn, "path"), sizeof(odbpath));
2029
2030 if (strchr(odbpath, '$')) {
2031 if (strchr(odbpath, '[')) {
2032 // keep $ in index for later evaluation
2033 std::string s(odbpath);
2034 std::string s1 = s.substr(0, s.find('['));
2035 std::string s2 = s.substr(s.find('['));
2036 s1 = eval_var(seq, c, s1);
2037 s1 += s2;
2038 mstrlcpy(odbpath, s1.c_str(), sizeof(odbpath));
2039 } else {
2040 // evaluate variable in path
2041 std::string s(odbpath);
2042 s = eval_var(seq, c, s);
2043 mstrlcpy(odbpath, s.c_str(), sizeof(odbpath));
2044 }
2045 }
2046
2047 mstrlcpy(name, mxml_get_value(pn), sizeof(name));
2048
2049 auto s = eval_var(seq, c, mxml_get_attribute(pn, "string"));
2050 mstrlcpy(str, s.c_str(), sizeof(str));
2051
2052 status = db_find_key(c->hDB, 0, odbpath, &hKey);
2053 if (status != DB_SUCCESS) {
2054 seq_error(seq, c, msprintf("Cannot find ODB key \"%s\"", odbpath).c_str());
2055 return;
2056 } else {
2057 db_get_key(c->hDB, hKey, &key);
2058
2059 // search for "str"
2060 for (i = 0 ; i<key.num_values ; i++) {
2061 size = sizeof(data);
2062 status = db_get_data_index(c->hDB, hKey, data, &size, i, key.type);
2063 if (strcmp((const char *)data, str) == 0)
2064 break;
2065 }
2066
2067 size = sizeof(i);
2068 if (i < key.num_values)
2069 value = db_sprintf(&i, size, 0, TID_INT);
2070 else {
2071 snprintf(str, sizeof(str), "\"ODBLOOKUP %s\" did not find string \"%s\"", odbpath, s.c_str());
2072 seq_error(seq, c, str);
2073 return;
2074 }
2075
2076 snprintf(str, sizeof(str), "Variables/%s", name);
2077 size = value.length() + 1;
2078 if (size < 32)
2079 size = 32;
2080 db_set_value(c->hDB, c->hSeq, str, value.c_str(), size, 1, TID_STRING);
2081
2082 size = sizeof(seq);
2083 db_get_record1(c->hDB, hKeySeq, &seq, &size, 0, strcomb1(sequencer_str).c_str());// could have changed seq tree
2084 seq.current_line_number = mxml_get_line_number_end(pn) + 1;
2085 }
2086 }
2087 }
2088
2089 /*---- ODBInc ----*/
2090 else if (equal_ustring(mxml_get_name(pn), "ODBInc")) {
2091 if (!mxml_get_attribute(pn, "path")) {
2092 seq_error(seq, c, "Missing attribute \"path\"");
2093 } else {
2094 mstrlcpy(odbpath, seq.subdir, sizeof(odbpath));
2095 if (strlen(odbpath) > 0 && odbpath[strlen(odbpath) - 1] != '/')
2096 mstrlcat(odbpath, "/", sizeof(odbpath));
2097 mstrlcat(odbpath, mxml_get_attribute(pn, "path"), sizeof(odbpath));
2098
2099 if (strchr(odbpath, '$')) {
2100 if (strchr(odbpath, '[')) {
2101 // keep $ in index for later evaluation
2102 std::string s(odbpath);
2103 std::string s1 = s.substr(0, s.find('['));
2104 std::string s2 = s.substr(s.find('['));
2105 s1 = eval_var(seq, c, s1);
2106 s1 += s2;
2107 mstrlcpy(odbpath, s1.c_str(), sizeof(odbpath));
2108 } else {
2109 // evaluate variable in path
2110 std::string s(odbpath);
2111 s = eval_var(seq, c, s);
2112 mstrlcpy(odbpath, s.c_str(), sizeof(odbpath));
2113 }
2114 }
2115
2116 index1 = index2 = 0;
2117 seq_array_index(seq, c, odbpath, &index1, &index2);
2118
2119 value = eval_var(seq, c, mxml_get_value(pn));
2120
2121 status = db_find_key(c->hDB, 0, odbpath, &hKey);
2122 if (status != DB_SUCCESS) {
2123 seq_error(seq, c, msprintf("Cannot find ODB key \"%s\"", odbpath).c_str());
2124 } else {
2125 db_get_key(c->hDB, hKey, &key);
2126 size = sizeof(data);
2127 db_get_data_index(c->hDB, hKey, data, &size, index1, key.type);
2128 std::string s = db_sprintf(data, size, 0, key.type);
2129 d = std::stof(s);
2130 d += std::stof(value);
2131 sprintf(str, "%lg", d);
2132 size = sizeof(data);
2133 db_sscanf(str, data, &size, 0, key.type);
2134
2135 int notify = TRUE;
2136 if (seq.subdir_not_notify)
2137 notify = FALSE;
2138 if (mxml_get_attribute(pn, "notify"))
2139 notify = atoi(mxml_get_attribute(pn, "notify"));
2140
2141 db_set_data_index1(c->hDB, hKey, data, key.item_size, index1, key.type, notify);
2142 seq.current_line_number++;
2143 }
2144 }
2145 }
2146
2147 /*---- ODBDelete ----*/
2148 else if (equal_ustring(mxml_get_name(pn), "ODBDelete")) {
2149 mstrlcpy(odbpath, seq.subdir, sizeof(odbpath));
2150 if (strlen(odbpath) > 0 && odbpath[strlen(odbpath) - 1] != '/')
2151 mstrlcat(odbpath, "/", sizeof(odbpath));
2152 mstrlcat(odbpath, mxml_get_value(pn), sizeof(odbpath));
2153
2154 if (strchr(odbpath, '$')) {
2155 std::string s(odbpath);
2156 s = eval_var(seq, c, s);
2157 mstrlcpy(odbpath, s.c_str(), sizeof(odbpath));
2158 }
2159
2160 status = db_delete(c->hDB, 0, odbpath);
2161 if (status != DB_SUCCESS) {
2162 seq_error(seq, c, msprintf("Cannot delete ODB key \"%s\"", odbpath).c_str());
2163 } else {
2164 seq.current_line_number++;
2165 }
2166 }
2167
2168 /*---- ODBCreate ----*/
2169 else if (equal_ustring(mxml_get_name(pn), "ODBCreate")) {
2170 if (!mxml_get_attribute(pn, "path")) {
2171 seq_error(seq, c, "Missing attribute \"path\"");
2172 } else if (!mxml_get_attribute(pn, "type")) {
2173 seq_error(seq, c, "Missing attribute \"type\"");
2174 } else {
2175 mstrlcpy(odbpath, seq.subdir, sizeof(odbpath));
2176 if (strlen(odbpath) > 0 && odbpath[strlen(odbpath) - 1] != '/')
2177 mstrlcat(odbpath, "/", sizeof(odbpath));
2178 mstrlcat(odbpath, mxml_get_attribute(pn, "path"), sizeof(odbpath));
2179
2180 if (strchr(odbpath, '$')) {
2181 std::string s(odbpath);
2182 s = eval_var(seq, c, s);
2183 mstrlcpy(odbpath, s.c_str(), sizeof(odbpath));
2184 }
2185
2186 /* get TID */
2187 unsigned int tid;
2188 for (tid = 0; tid < TID_LAST; tid++) {
2189 if (equal_ustring(rpc_tid_name(tid), mxml_get_attribute(pn, "type")))
2190 break;
2191 }
2192
2193 if (tid == TID_LAST)
2194 seq_error(seq, c, "Type must be one of UINT8,INT8,UINT16,INT16,UINT32,INT32,BOOL,FLOAT,DOUBLE,STRING");
2195 else {
2196
2197 status = db_find_key(c->hDB, 0, odbpath, &hKey);
2198 if (status == DB_SUCCESS) {
2199 db_get_key(c->hDB, hKey, &key);
2200 if (key.type != tid) {
2201 db_delete_key(c->hDB, hKey);
2202 status = db_create_key(c->hDB, 0, odbpath, tid);
2203 }
2204 } else {
2205 status = db_create_key(c->hDB, 0, odbpath, tid);
2206 char dummy[32];
2207 memset(dummy, 0, sizeof(dummy));
2208 if (tid == TID_STRING || tid == TID_LINK)
2209 db_set_value(c->hDB, 0, odbpath, dummy, 32, 1, tid);
2210 }
2211
2212 if (status != DB_SUCCESS && status != DB_CREATED) {
2213 seq_error(seq, c, msprintf("Cannot create ODB key \"%s\", error code %d", odbpath, status).c_str());
2214 } else {
2215 status = db_find_key(c->hDB, 0, odbpath, &hKey);
2216 if (mxml_get_attribute(pn, "size")) {
2217 i = atoi(eval_var(seq, c, mxml_get_attribute(pn, "size")).c_str());
2218 if (i > 1)
2219 db_set_num_values(c->hDB, hKey, i);
2220 }
2221 seq.current_line_number++;
2222 }
2223 }
2224 }
2225 }
2226
2227 /*---- RunDescription ----*/
2228 else if (equal_ustring(mxml_get_name(pn), "RunDescription")) {
2229 db_set_value(c->hDB, 0, "/Experiment/Run Parameters/Run Description", mxml_get_value(pn), 256, 1, TID_STRING);
2230 seq.current_line_number++;
2231 }
2232
2233 /*---- Script ----*/
2234 else if (equal_ustring(mxml_get_name(pn), "Script")) {
2235 sprintf(str, "%s", mxml_get_value(pn)); // FIXME: unsafe
2236
2237 if (mxml_get_attribute(pn, "params")) {
2238 mstrlcpy(data, mxml_get_attribute(pn, "params"), sizeof(data));
2239 n = strbreak(data, list, 100, ",", FALSE);
2240 for (i = 0; i < n; i++) {
2241
2242 value = eval_var(seq, c, list[i]);
2243
2244 mstrlcat(str, " ", sizeof(str));
2245 mstrlcat(str, value.c_str(), sizeof(str));
2246 }
2247 }
2248
2249 std::string s(str);
2251 std::string r = ss_execs(s.c_str());
2252
2253 // put result into SCRIPT_RESULT variable
2254 db_set_value(c->hDB, c->hSeq, "Variables/SCRIPT_RESULT", r.c_str(), r.length(), 1, TID_STRING);
2255
2256 seq.current_line_number++;
2257 }
2258
2259 /*---- Transition ----*/
2260 else if (equal_ustring(mxml_get_name(pn), "Transition")) {
2261 if (equal_ustring(mxml_get_value(pn), "Start")) {
2262 if (!seq.transition_request) {
2264 size = sizeof(state);
2265 db_get_value(c->hDB, 0, "/Runinfo/State", &state, &size, TID_INT32, FALSE);
2266 if (state != STATE_RUNNING) {
2267 size = sizeof(run_number);
2268 db_get_value(c->hDB, 0, "/Runinfo/Run number", &run_number, &size, TID_INT32, FALSE);
2270 if (status != CM_SUCCESS) {
2271 seq_error(seq, c, msprintf("Cannot start run: %s", str).c_str());
2272 }
2273 }
2274 } else {
2275 // Wait until transition has finished
2276 size = sizeof(state);
2277 db_get_value(c->hDB, 0, "/Runinfo/State", &state, &size, TID_INT32, FALSE);
2278 if (state == STATE_RUNNING) {
2280 seq.current_line_number++;
2281 }
2282 }
2283 } else if (equal_ustring(mxml_get_value(pn), "Stop")) {
2284 if (!seq.transition_request) {
2286 size = sizeof(state);
2287 db_get_value(c->hDB, 0, "/Runinfo/State", &state, &size, TID_INT32, FALSE);
2288 if (state != STATE_STOPPED) {
2291 // do nothing
2292 } else if (status != CM_SUCCESS) {
2293 seq_error(seq, c, msprintf("Cannot stop run: %s", str).c_str());
2294 }
2295 }
2296 } else {
2297 // Wait until transition has finished
2298 size = sizeof(state);
2299 db_get_value(c->hDB, 0, "/Runinfo/State", &state, &size, TID_INT32, FALSE);
2300 if (state == STATE_STOPPED) {
2301 size = sizeof(seq);
2302 db_get_record(c->hDB, hKeySeq, &seq, &size, 0);
2303
2305
2306 if (seq.stop_after_run) {
2307 seq.stop_after_run = FALSE;
2308
2309 if (!goto_at_exit(seq, c)) {
2310 seq.running = FALSE;
2311 seq.finished = TRUE;
2312 seq_stop(seq, c);
2313 cm_msg(MTALK, "sequencer", "Sequencer is finished by \"stop after current run\".");
2314 } else {
2315 cm_msg(MTALK, "sequencer", "Sequencer is going to finish by \"stop after current run\". Executing ATEXIT.");
2316 }
2317 } else {
2318 seq.current_line_number++;
2319 }
2320
2321 db_set_record(c->hDB, hKeySeq, &seq, sizeof(seq), 0);
2322 }
2323 }
2324 } else {
2325 seq_error(seq, c, msprintf("Invalid transition \"%s\"", mxml_get_value(pn)).c_str());
2326 return;
2327 }
2328 }
2329
2330 /*---- Wait ----*/
2331 else if (equal_ustring(mxml_get_name(pn), "Wait")) {
2332 if (equal_ustring(mxml_get_attribute(pn, "for"), "Events")) {
2333 n = atoi(eval_var(seq, c, mxml_get_value(pn)).c_str());
2334 seq.wait_limit = (float) n;
2335 strcpy(seq.wait_type, "Events");
2336 size = sizeof(d);
2337 db_get_value(c->hDB, 0, "/Equipment/Trigger/Statistics/Events sent", &d, &size, TID_DOUBLE, FALSE);
2338 seq.wait_value = (float) d;
2339 if (d >= n) {
2340 seq.current_line_number = mxml_get_line_number_end(pn) + 1;
2341 seq.wait_limit = 0;
2342 seq.wait_value = 0;
2343 seq.wait_type[0] = 0;
2344 seq.wait_odb[0] = 0;
2345 }
2346 seq.wait_value = (float) d;
2347 } else if (equal_ustring(mxml_get_attribute(pn, "for"), "ODBValue")) {
2348 seq.wait_limit = (float) atof(eval_var(seq, c, mxml_get_value(pn)).c_str());
2349 mstrlcpy(seq.wait_type, "ODB", sizeof(seq.wait_type));
2350 if (!mxml_get_attribute(pn, "path")) {
2351 seq_error(seq, c, "\"path\" must be given for ODB values");
2352 return;
2353 } else {
2354 mstrlcpy(odbpath, mxml_get_attribute(pn, "path"), sizeof(odbpath));
2355 mstrlcpy(seq.wait_odb, odbpath, sizeof(seq.wait_odb));
2356
2357 if (strchr(odbpath, '$')) {
2358 if (strchr(odbpath, '[')) {
2359 // keep $ in index for later evaluation
2360 std::string s(odbpath);
2361 std::string s1 = s.substr(0, s.find('['));
2362 std::string s2 = s.substr(s.find('['));
2363 s1 = eval_var(seq, c, s1);
2364 s1 += s2;
2365 mstrlcpy(odbpath, s1.c_str(), sizeof(odbpath));
2366 } else {
2367 // evaluate variable in path
2368 std::string s(odbpath);
2369 s = eval_var(seq, c, s);
2370 mstrlcpy(odbpath, s.c_str(), sizeof(odbpath));
2371 }
2372 }
2373
2374 index1 = index2 = 0;
2375 seq_array_index(seq, c, odbpath, &index1, &index2);
2376 status = db_find_key(c->hDB, 0, odbpath, &hKey);
2377 if (status != DB_SUCCESS) {
2378 seq_error(seq, c, msprintf("Cannot find ODB key \"%s\"", odbpath).c_str());
2379 return;
2380 } else {
2381 if (mxml_get_attribute(pn, "op"))
2382 mstrlcpy(op, mxml_get_attribute(pn, "op"), sizeof(op));
2383 else
2384 strcpy(op, "!=");
2385 mstrlcat(seq.wait_type, op, sizeof(seq.wait_type));
2386
2387 db_get_key(c->hDB, hKey, &key);
2388 size = sizeof(data);
2389 db_get_data_index(c->hDB, hKey, data, &size, index1, key.type);
2390 if (key.type == TID_BOOL)
2391 value = *((int *) data) > 0 ? "1" : "0";
2392 else
2393 value = db_sprintf(data, size, 0, key.type);
2394 cont = FALSE;
2395 seq.wait_value = std::stof(value);
2396 if (equal_ustring(op, ">=")) {
2397 cont = (seq.wait_value >= seq.wait_limit);
2398 } else if (equal_ustring(op, ">")) {
2399 cont = (seq.wait_value > seq.wait_limit);
2400 } else if (equal_ustring(op, "<=")) {
2401 cont = (seq.wait_value <= seq.wait_limit);
2402 } else if (equal_ustring(op, "<")) {
2403 cont = (seq.wait_value < seq.wait_limit);
2404 } else if (equal_ustring(op, "==")) {
2405 cont = (seq.wait_value == seq.wait_limit);
2406 } else if (equal_ustring(op, "!=")) {
2407 cont = (seq.wait_value != seq.wait_limit);
2408 } else {
2409 seq_error(seq, c, msprintf("Invalid comaprison \"%s\"", op).c_str());
2410 return;
2411 }
2412
2413 if (cont) {
2414 seq.current_line_number = mxml_get_line_number_end(pn) + 1;
2415 seq.wait_limit = 0;
2416 seq.wait_value = 0;
2417 seq.wait_type[0] = 0;
2418 seq.wait_odb[0] = 0;
2419 }
2420 }
2421 }
2422 } else if (equal_ustring(mxml_get_attribute(pn, "for"), "Seconds")) {
2423 seq.wait_limit = 1000.0f * (float) atof(eval_var(seq, c, mxml_get_value(pn)).c_str());
2424 strcpy(seq.wait_type, "Seconds");
2425 if (seq.start_time == 0) {
2426 seq.start_time = ss_millitime();
2427 seq.wait_value = 0;
2428 } else {
2429 seq.wait_value = (float) (ss_millitime() - seq.start_time);
2430 if (seq.wait_value > seq.wait_limit)
2431 seq.wait_value = seq.wait_limit;
2432 }
2433 if (ss_millitime() - seq.start_time > (DWORD) seq.wait_limit) {
2434 seq.current_line_number++;
2435 seq.start_time = 0;
2436 seq.wait_limit = 0;
2437 seq.wait_value = 0;
2438 seq.wait_type[0] = 0;
2439 seq.wait_odb[0] = 0;
2440 }
2441 } else {
2442 seq_error(seq, c, msprintf("Invalid wait attribute \"%s\"", mxml_get_attribute(pn, "for")).c_str());
2443 }
2444
2445 // sleep to keep the CPU from consuming 100%
2446 ss_sleep(1);
2447 }
2448
2449 /*---- Loop start ----*/
2450 else if (equal_ustring(mxml_get_name(pn), "Loop")) {
2451 for (i = 0; i < SEQ_NEST_LEVEL_LOOP; i++)
2452 if (seq.loop_start_line[i] == 0)
2453 break;
2454 if (i == SEQ_NEST_LEVEL_LOOP) {
2455 seq_error(seq, c, "Maximum loop nesting exceeded");
2456 return;
2457 }
2459 seq.loop_end_line[i] = mxml_get_line_number_end(pn);
2460 if (mxml_get_attribute(pn, "l"))
2461 seq.sloop_start_line[i] = atoi(mxml_get_attribute(pn, "l"));
2462 if (mxml_get_attribute(pn, "le"))
2463 seq.sloop_end_line[i] = atoi(mxml_get_attribute(pn, "le"));
2464 seq.loop_counter[i] = 1;
2465
2466 if (mxml_get_attribute(pn, "n")) {
2467 if (equal_ustring(mxml_get_attribute(pn, "n"), "infinite"))
2468 seq.loop_n[i] = -1;
2469 else {
2470 seq.loop_n[i] = atoi(eval_var(seq, c, mxml_get_attribute(pn, "n")).c_str());
2471 }
2472 value = "1";
2473 } else if (mxml_get_attribute(pn, "values")) {
2474 mstrlcpy(data, mxml_get_attribute(pn, "values"), sizeof(data));
2475 seq.loop_n[i] = strbreak(data, list, 100, ",", FALSE);
2476 value = eval_var(seq, c, list[0]);
2477 } else {
2478 seq_error(seq, c, "Missing \"var\" or \"n\" attribute");
2479 return;
2480 }
2481
2482 if (mxml_get_attribute(pn, "var")) {
2483 mstrlcpy(name, mxml_get_attribute(pn, "var"), sizeof(name));
2484 sprintf(str, "Variables/%s", name); // FIXME: unsafe
2485 size = value.length() + 1;
2486 if (size < 32)
2487 size = 32;
2488 db_set_value(c->hDB, c->hSeq, str, value.c_str(), size, 1, TID_STRING);
2489 }
2490
2491 seq.current_line_number++;
2492 }
2493
2494 /*---- Break ----*/
2495 else if (equal_ustring(mxml_get_name(pn), "Break")) {
2496
2497 // finish current if statement
2498 while (seq.if_index > 0 &&
2499 seq.current_line_number > seq.if_line[seq.if_index - 1] &&
2500 seq.current_line_number < seq.if_endif_line[seq.if_index-1]) {
2501 size = sizeof(seq);
2502 db_get_record(c->hDB, hKeySeq, &seq, &size, 0);
2503 seq.if_index--;
2504 seq.if_line[seq.if_index] = 0;
2505 seq.if_else_line[seq.if_index] = 0;
2506 seq.if_endif_line[seq.if_index] = 0;
2507 seq.current_line_number++;
2508 db_set_record(c->hDB, hKeySeq, &seq, sizeof(seq), 0);
2509 }
2510
2511 // goto next loop end
2512 for (i = 0; i < SEQ_NEST_LEVEL_LOOP; i++)
2513 if (seq.loop_start_line[i] == 0)
2514 break;
2515 if (i == 0) {
2516 seq_error(seq, c, "\"Break\" outside any loop");
2517 return;
2518 }
2519
2520 // force end of loop in next check
2521 seq.current_line_number = seq.loop_end_line[i-1];
2522 seq.loop_counter[i-1] = seq.loop_n[i-1];
2523 }
2524
2525 /*---- If ----*/
2526 else if (equal_ustring(mxml_get_name(pn), "If")) {
2527
2528 if (seq.if_index == SEQ_NEST_LEVEL_IF) {
2529 seq_error(seq, c, "Maximum number of nested if..endif exceeded");
2530 return;
2531 }
2532
2533 // store "if" and "endif" lines
2534 seq.if_line[seq.if_index] = seq.current_line_number;
2535 seq.if_endif_line[seq.if_index] = mxml_get_line_number_end(pn);
2536
2537 // search for "else" line
2538 seq.if_else_line[seq.if_index] = 0;
2539 for (j = seq.current_line_number + 1; j < mxml_get_line_number_end(pn) + 1; j++) {
2540 pe = mxml_get_node_at_line(c->pnseq, j);
2541
2542 // skip nested if..endif
2543 if (pe && equal_ustring(mxml_get_name(pe), "If")) {
2544 j = mxml_get_line_number_end(pe);
2545 continue;
2546 }
2547
2548 // store "else" if found
2549 if (pe && equal_ustring(mxml_get_name(pe), "Else")) {
2550 seq.if_else_line[seq.if_index] = j;
2551 break;
2552 }
2553 }
2554
2555 mstrlcpy(str, mxml_get_attribute(pn, "condition"), sizeof(str));
2556 i = eval_condition(seq, c, str);
2557 if (i < 0) {
2558 seq_error(seq, c, "Invalid number in comparison");
2559 return;
2560 }
2561
2562 if (i == 1)
2563 seq.current_line_number++;
2564 else if (seq.if_else_line[seq.if_index])
2565 seq.current_line_number = seq.if_else_line[seq.if_index] + 1;
2566 else
2568
2569 seq.if_index++;
2570 }
2571
2572 /*---- Else ----*/
2573 else if (equal_ustring(mxml_get_name(pn), "Else")) {
2574 // goto next "Endif"
2575 if (seq.if_index == 0) {
2576 seq_error(seq, c, "Unexpected Else");
2577 return;
2578 }
2579 seq.current_line_number = seq.if_endif_line[seq.if_index - 1];
2580 }
2581
2582 /*---- Exit ----*/
2583 else if (equal_ustring(mxml_get_name(pn), "Exit")) {
2584 seq_stop(seq, c);
2585 cm_msg(MTALK, "sequencer", "Sequencer is finished.");
2586 return;
2587 }
2588
2589 /*---- Goto ----*/
2590 else if (equal_ustring(mxml_get_name(pn), "Goto")) {
2591 if (!mxml_get_attribute(pn, "line") && !mxml_get_attribute(pn, "sline")) {
2592 seq_error(seq, c, "Missing line number");
2593 return;
2594 }
2595 if (mxml_get_attribute(pn, "line")) {
2596 seq.current_line_number = atoi(eval_var(seq, c, mxml_get_attribute(pn, "line")).c_str());
2597 }
2598 if (mxml_get_attribute(pn, "sline")) {
2599 mstrlcpy(str, eval_var(seq, c, mxml_get_attribute(pn, "sline")).c_str(), sizeof(str));
2600 for (i = 0; i < last_line; i++) {
2601 pt = mxml_get_node_at_line(c->pnseq, i);
2602 if (pt && mxml_get_attribute(pt, "l")) {
2603 l = atoi(mxml_get_attribute(pt, "l"));
2604 if (atoi(str) == l) {
2605 seq.current_line_number = i;
2606 break;
2607 }
2608 }
2609 }
2610 }
2611 }
2612
2613 /*---- Library ----*/
2614 else if (equal_ustring(mxml_get_name(pn), "Library")) {
2615 // simply skip libraries
2616 seq.current_line_number = mxml_get_line_number_end(pn) + 1;
2617 }
2618
2619 /*---- Subroutine ----*/
2620 else if (equal_ustring(mxml_get_name(pn), "Subroutine")) {
2621 // simply skip subroutines
2622 seq.current_line_number = mxml_get_line_number_end(pn) + 1;
2623 }
2624
2625 /*---- Param ----*/
2626 else if (equal_ustring(mxml_get_name(pn), "Param")) {
2627 // simply skip parameters
2628 seq.current_line_number = mxml_get_line_number_end(pn) + 1;
2629 }
2630
2631 /*---- Set ----*/
2632 else if (equal_ustring(mxml_get_name(pn), "Set")) {
2633 if (!mxml_get_attribute(pn, "name")) {
2634 seq_error(seq, c, "Missing variable name");
2635 return;
2636 }
2637 mstrlcpy(name, mxml_get_attribute(pn, "name"), sizeof(name));
2638 value = eval_var(seq, c, mxml_get_value(pn));
2639
2640 if (strchr(name, '[')) {
2641 // array
2642 mstrlcpy(str, strchr(name, '[')+1, sizeof(str));
2643 if (strchr(str, ']'))
2644 *strchr(str, ']') = 0;
2645 int index = atoi(eval_var(seq, c, str).c_str());
2646 *strchr(name, '[') = 0;
2647 sprintf(str, "Variables/%s", name); // FIXME: unsafe
2648 status = db_find_key(c->hDB, c->hSeq, str, &hKey);
2649 if (status != DB_SUCCESS) {
2650 db_create_key(c->hDB, c->hSeq, str, TID_STRING);
2651 status = db_find_key(c->hDB, c->hSeq, str, &hKey);
2652 }
2653 size = value.length() + 1;
2654 if (size < 32)
2655 size = 32;
2656 status = db_set_data_index(c->hDB, hKey, value.c_str(), size, index, TID_STRING);
2657 } else {
2658 sprintf(str, "Variables/%s", name); // FIXME: unsafe
2659 size = value.length() + 1;
2660 if (size < 32)
2661 size = 32;
2662 db_set_value(c->hDB, c->hSeq, str, value.c_str(), size, 1, TID_STRING);
2663 }
2664
2665 // check if variable is used in loop
2666 for (i = SEQ_NEST_LEVEL_LOOP-1; i >= 0; i--)
2667 if (seq.loop_start_line[i] > 0) {
2668 pr = mxml_get_node_at_line(c->pnseq, seq.loop_start_line[i]);
2669 if (mxml_get_attribute(pr, "var")) {
2670 if (equal_ustring(mxml_get_attribute(pr, "var"), name))
2671 seq.loop_counter[i] = atoi(value.c_str());
2672 }
2673 }
2674
2675 seq.current_line_number = mxml_get_line_number_end(pn) + 1;
2676 }
2677
2678 /*---- Message ----*/
2679 else if (equal_ustring(mxml_get_name(pn), "Message")) {
2680 if (strchr(mxml_get_value(pn), '$')) // evaluate message string if $ present
2681 value = eval_var(seq, c, mxml_get_value(pn));
2682 else
2683 value = mxml_get_value(pn); // treat message as string
2684 const char *wait_attr = mxml_get_attribute(pn, "wait");
2685 bool wait = false;
2686 if (wait_attr)
2687 wait = (atoi(wait_attr) == 1);
2688
2689 if (!wait) {
2690 // message with no wait: set seq.message and move on. we do not care if web page clears it
2691 mstrlcpy(seq.message, value.c_str(), sizeof(seq.message));
2692 seq.message_wait = FALSE;
2693 db_set_record(c->hDB, hKeySeq, &seq, sizeof(seq), 0);
2694 } else {
2695 // message with wait
2696
2697 // if message_wait not set, we are here for the first time
2698 if (!seq.message_wait) {
2699 mstrlcpy(seq.message, value.c_str(), sizeof(seq.message));
2700 seq.message_wait = TRUE;
2701 db_set_record(c->hDB, hKeySeq, &seq, sizeof(seq), 0);
2702 // wait
2703 return;
2704 } else {
2705 // message_wait is set, we have been here before
2706
2707 // if web page did not clear the message, keep waiting
2708 if (seq.message[0] != 0) {
2709 // wait
2710 return;
2711 }
2712
2713 // web page cleared the message, we are done with waiting
2714 seq.message_wait = false;
2715 }
2716 }
2717
2718 seq.current_line_number = mxml_get_line_number_end(pn) + 1;
2719 }
2720
2721 /*---- Msg ----*/
2722 else if (equal_ustring(mxml_get_name(pn), "Msg")) {
2723 if (strchr(mxml_get_value(pn), '$')) // evaluate message string if $ present
2724 value = eval_var(seq, c, mxml_get_value(pn));
2725 else
2726 value = mxml_get_value(pn); // treat message as string
2727 std::string type = "INFO";
2728 if (mxml_get_attribute(pn, "type"))
2729 type = std::string(mxml_get_attribute(pn, "type"));
2730
2731 if (type == "ERROR")
2732 cm_msg(MERROR, "sequencer", "%s", value.c_str());
2733 else if (type == "DEBUG")
2734 cm_msg(MDEBUG, "sequencer", "%s", value.c_str());
2735 else if (type == "LOG")
2736 cm_msg(MLOG, "sequencer", "%s", value.c_str());
2737 else if (type == "TALK")
2738 cm_msg(MTALK, "sequencer", "%s", value.c_str());
2739 else
2740 cm_msg(MINFO, "sequencer", "%s", value.c_str());
2741
2742 seq.current_line_number = mxml_get_line_number_end(pn) + 1;
2743 }
2744
2745 /*---- Cat ----*/
2746 else if (equal_ustring(mxml_get_name(pn), "Cat")) {
2747 if (!mxml_get_attribute(pn, "name")) {
2748 seq_error(seq, c, "Missing variable name");
2749 return;
2750 }
2751 mstrlcpy(name, mxml_get_attribute(pn, "name"), sizeof(name));
2752 if (!concatenate(seq, c, data, sizeof(data), mxml_get_value(pn)))
2753 return;
2754 sprintf(str, "Variables/%s", name); // FIXME: unsafe
2755 size = strlen(data) + 1;
2756 if (size < 32)
2757 size = 32;
2758 db_set_value(c->hDB, c->hSeq, str, data, size, 1, TID_STRING);
2759
2760 seq.current_line_number = mxml_get_line_number_end(pn) + 1;
2761 }
2762
2763 /*---- Call ----*/
2764 else if (equal_ustring(mxml_get_name(pn), "Call")) {
2765 if (seq.stack_index == SEQ_NEST_LEVEL_SUB) {
2766 seq_error(seq, c, "Maximum subroutine level exceeded");
2767 return;
2768 } else {
2769 // put current line number on stack
2770 seq.subroutine_call_line[seq.stack_index] = mxml_get_line_number_end(pn);
2771 seq.ssubroutine_call_line[seq.stack_index] = atoi(mxml_get_attribute(pn, "l"));
2772 seq.subroutine_return_line[seq.stack_index] = mxml_get_line_number_end(pn) + 1;
2773
2774 // search subroutine
2775 for (i = 1; i < mxml_get_line_number_end(mxml_find_node(c->pnseq, "RunSequence")); i++) {
2776 pt = mxml_get_node_at_line(c->pnseq, i);
2777 if (pt) {
2778 if (equal_ustring(mxml_get_name(pt), "Subroutine")) {
2779 if (equal_ustring(mxml_get_attribute(pt, "name"), mxml_get_attribute(pn, "name"))) {
2780 // put routine end line on end stack
2781 seq.subroutine_end_line[seq.stack_index] = mxml_get_line_number_end(pt);
2782 // go to first line of subroutine
2783 seq.current_line_number = mxml_get_line_number_start(pt) + 1;
2784 // put parameter(s) on stack
2785 if (mxml_get_value(pn)) {
2786 char p[256];
2787 if (strchr(mxml_get_value(pn), '$')) // evaluate message string if $ present
2788 mstrlcpy(p, eval_var(seq, c, mxml_get_value(pn)).c_str(), sizeof(p));
2789 else
2790 mstrlcpy(p, mxml_get_value(pn), sizeof(p)); // treat message as string
2791
2792 mstrlcpy(seq.subroutine_param[seq.stack_index], p, 256);
2793 }
2794 // increment stack
2795 seq.stack_index++;
2796 break;
2797 }
2798 }
2799 }
2800 }
2801 if (i == mxml_get_line_number_end(mxml_find_node(c->pnseq, "RunSequence"))) {
2802 seq_error(seq, c, msprintf("Subroutine '%s' not found", mxml_get_attribute(pn, "name")).c_str());
2803 }
2804 }
2805 }
2806
2807 /*---- <unknown> ----*/
2808 else {
2809 seq_error(seq, c, msprintf("Unknown statement \"%s\"", mxml_get_name(pn)).c_str());
2810 }
2811
2812 /* get steering parameters, since they might have been changed in between */
2813 SEQUENCER seq1;
2814 size = sizeof(seq1);
2815 db_get_record(c->hDB, hKeySeq, &seq1, &size, 0);
2816 seq.running = seq1.running;
2817 seq.finished = seq1.finished;
2818 seq.paused = seq1.paused;
2819 seq.debug = seq1.debug;
2820 seq.stop_after_run = seq1.stop_after_run;
2821 mstrlcpy(seq.message, seq1.message, sizeof(seq.message));
2822 memcpy(seq.next_filename, seq1.next_filename, sizeof(seq.next_filename));
2823
2824 // in debugging mode, pause after each step
2825 if (seq.debug && !skip_step)
2826 seq.paused = TRUE;
2827
2828 /* update current line number */
2829 db_set_record(c->hDB, hKeySeq, &seq, sizeof(seq), 0);
2830}
INT cm_transition(INT transition, INT run_number, char *errstr, INT errstr_size, INT async_flag, INT debug_flag)
Definition midas.cxx:5303
#define CM_DEFERRED_TRANSITION
Definition midas.h:591
#define DB_INVALID_PARAM
Definition midas.h:640
#define DB_FILE_ERROR
Definition midas.h:648
#define DB_NO_KEY
Definition midas.h:643
#define DB_CREATED
Definition midas.h:633
#define TID_DOUBLE
Definition midas.h:343
#define TID_BOOL
Definition midas.h:340
#define TR_START
Definition midas.h:405
#define TR_SYNC
Definition midas.h:358
#define TR_MTHREAD
Definition midas.h:361
#define STATE_STOPPED
Definition midas.h:305
#define MINFO
Definition midas.h:560
#define MLOG
Definition midas.h:563
#define TID_INT32
Definition midas.h:339
#define TID_LINK
Definition midas.h:350
#define TID_STRING
Definition midas.h:346
#define STATE_RUNNING
Definition midas.h:307
#define MDEBUG
Definition midas.h:561
#define TID_INT
Definition midas.h:338
#define TR_STOP
Definition midas.h:406
#define TID_LAST
Definition midas.h:354
DWORD ss_millitime()
Definition system.cxx:3465
std::string ss_execs(const char *cmd)
Definition system.cxx:2309
std::string ss_replace_env_variables(const std::string &inputPath)
Definition system.cxx:2284
INT ss_sleep(INT millisec)
Definition system.cxx:3700
INT cm_msg_retrieve(INT n_message, char *message, INT buf_size)
Definition midas.cxx:1349
INT db_get_data_index(HNDLE hDB, HNDLE hKey, void *data, INT *buf_size, INT idx, DWORD type)
Definition odb.cxx:6664
INT db_delete_key(HNDLE hDB, HNDLE hKey, BOOL follow_links)
Definition odb.cxx:3933
INT db_get_value(HNDLE hDB, HNDLE hKeyRoot, const char *key_name, void *data, INT *buf_size, DWORD type, BOOL create)
Definition odb.cxx:5185
INT db_save_json(HNDLE hDB, HNDLE hKey, const char *filename, int flags)
Definition odb.cxx:10295
INT db_save_xml(HNDLE hDB, HNDLE hKey, const char *filename)
Definition odb.cxx:9250
INT db_create_key(HNDLE hDB, HNDLE hKey, const char *key_name, DWORD type)
Definition odb.cxx:3392
INT db_get_record(HNDLE hDB, HNDLE hKey, void *data, INT *buf_size, INT align)
Definition odb.cxx:11483
INT db_save(HNDLE hDB, HNDLE hKey, const char *filename, BOOL bRemote)
Definition odb.cxx:9010
INT db_get_key(HNDLE hDB, HNDLE hKey, KEY *key)
Definition odb.cxx:5790
INT db_load(HNDLE hDB, HNDLE hKeyRoot, const char *filename, BOOL bRemote)
Definition odb.cxx:7886
INT db_set_data_index(HNDLE hDB, HNDLE hKey, const void *data, INT data_size, INT idx, DWORD type)
Definition odb.cxx:7415
INT db_delete(HNDLE hDB, HNDLE hKeyRoot, const char *odb_path)
Definition odb.cxx:3999
INT db_sprintf(char *string, const void *data, INT data_size, INT idx, DWORD type)
Definition odb.cxx:10612
INT db_set_value(HNDLE hDB, HNDLE hKeyRoot, const char *key_name, const void *data, INT data_size, INT num_values, DWORD type)
Definition odb.cxx:5028
INT db_set_data_index1(HNDLE hDB, HNDLE hKey, const void *data, INT data_size, INT idx, DWORD type, BOOL bNotify)
Definition odb.cxx:7591
INT db_sscanf(const char *data_str, void *data, INT *data_size, INT i, DWORD tid)
Definition odb.cxx:11083
INT db_set_num_values(HNDLE hDB, HNDLE hKey, INT num_values)
Definition odb.cxx:7270
const char * rpc_tid_name(INT id)
Definition midas.cxx:11789
void seq_array_index(SEQUENCER &seq, SeqCon *c, char *odbpath, int *index1, int *index2)
int concatenate(SEQUENCER &seq, SeqCon *c, char *result, int size, char *value)
static void seq_start_next(SEQUENCER &seq, SeqCon *c)
int set_all_matching(HNDLE hDB, HNDLE hBaseKey, const char *odbpath, char *value, int index1, int index2, int notify)
int eval_condition(SEQUENCER &seq, SeqCon *c, const char *condition)
INT run_number[2]
Definition mana.cxx:246
void * data
Definition mana.cxx:268
INT type
Definition mana.cxx:269
KEY key
Definition mdump.cxx:34
#define DWORD
Definition mhdump.cxx:31
std::string msprintf(const char *format,...)
Definition midas.cxx:419
#define JSFLAG_RECURSE
Definition midas.h:1723
#define JSFLAG_FOLLOW_LINKS
Definition midas.h:1722
#define JSFLAG_OMIT_LAST_WRITTEN
Definition midas.h:1726
#define name(x)
Definition midas_macro.h:24
Definition midas.h:1027
INT num_values
Definition midas.h:1029
DWORD type
Definition midas.h:1028
INT item_size
Definition midas.h:1033
int if_line[SEQ_NEST_LEVEL_IF]
Definition sequencer.h:37
char last_msg[10]
Definition sequencer.h:51
static void pn(const te_expr *n, int depth)
Definition tinyexpr.c:702
Here is the call graph for this function:
Here is the caller graph for this function:

◆ SEQUENCER_STR()

SEQUENCER_STR ( sequencer_str  )

◆ set_all_matching()

int set_all_matching ( HNDLE  hDB,
HNDLE  hBaseKey,
const char *  odbpath,
char *  value,
int  index1,
int  index2,
int  notify 
)

Definition at line 1502 of file msequencer.cxx.

1502 {
1503 int status, size;
1504 char data[256];
1505 KEY key;
1506
1507 std::vector<HNDLE> keys;
1508 status = db_find_keys(hDB, hBaseKey, odbpath, keys);
1509
1510 if (status != DB_SUCCESS)
1511 return status;
1512
1513 for (HNDLE hKey: keys) {
1514 db_get_key(hDB, hKey, &key);
1515 size = sizeof(data);
1516 db_sscanf(value, data, &size, 0, key.type);
1517
1518 /* extend data size for single string if necessary */
1519 if ((key.type == TID_STRING || key.type == TID_LINK)
1520 && (int) strlen(data) + 1 > key.item_size && key.num_values == 1)
1521 key.item_size = strlen(data) + 1;
1522
1523 if (key.num_values > 1 && index1 == -1) {
1524 for (int i = 0; i < key.num_values; i++)
1526 } else if (key.num_values > 1 && index2 > index1) {
1527 if (index1 < 0 || index1 >= key.num_values || index2 < 0 || index2 >= key.num_values)
1528 return DB_INVALID_PARAM;
1529 for (int i = index1; i < key.num_values && i <= index2; i++)
1531 } else {
1532 if (index1 < 0 || index1 >= key.num_values)
1533 return DB_INVALID_PARAM;
1534 status = db_set_data_index1(hDB, hKey, data, key.item_size, index1, key.type, notify);
1535 }
1536
1537 if (status != DB_SUCCESS) {
1538 return status;
1539 }
1540 }
1541
1542 return DB_SUCCESS;
1543}
INT db_find_keys(HNDLE hDB, HNDLE hKeyRoot, const char *odbpath, std::vector< HNDLE > &hKeyVector)
Definition odb.cxx:4352
Here is the call graph for this function:
Here is the caller graph for this function:

◆ strbreak()

int strbreak ( char *  str,
char  list[][XNAME_LENGTH],
int  size,
const char *  brk,
BOOL  ignore_quotes 
)

Definition at line 186 of file msequencer.cxx.

189{
190 int i, j;
191 char *p;
192
193 memset(list, 0, size * XNAME_LENGTH);
194 p = str;
195 if (!p || !*p)
196 return 0;
197
198 while (*p == ' ')
199 p++;
200
201 for (i = 0; *p && i < size; i++) {
202 if (*p == '"' && !ignore_quotes) {
203 p++;
204 j = 0;
205 memset(list[i], 0, XNAME_LENGTH);
206 do {
207 /* convert two '"' to one */
208 if (*p == '"' && *(p + 1) == '"') {
209 list[i][j++] = '"';
210 p += 2;
211 } else if (*p == '"') {
212 break;
213 } else
214 list[i][j++] = *p++;
215
216 } while (j < XNAME_LENGTH - 1);
217 list[i][j] = 0;
218
219 /* skip second '"' */
220 p++;
221
222 /* skip blanks and break character */
223 while (*p == ' ')
224 p++;
225 if (*p && strchr(brk, *p))
226 p++;
227 while (*p == ' ')
228 p++;
229
230 } else {
231 mstrlcpy(list[i], p, XNAME_LENGTH);
232
233 for (j = 0; j < (int) strlen(list[i]); j++)
234 if (strchr(brk, list[i][j])) {
235 list[i][j] = 0;
236 break;
237 }
238
239 p += strlen(list[i]);
240 while (*p == ' ')
241 p++;
242 if (*p && strchr(brk, *p))
243 p++;
244 while (*p == ' ')
245 p++;
246
247 while (list[i][strlen(list[i]) - 1] == ' ')
248 list[i][strlen(list[i]) - 1] = 0;
249 }
250
251 if (!*p)
252 break;
253 }
254
255 if (i == size)
256 return size;
257
258 return i + 1;
259}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ stristr()

char * stristr ( const char *  str,
const char *  pattern 
)

Definition at line 63 of file msequencer.cxx.

63 {
64 char c1, c2, *ps, *pp;
65
66 if (str == NULL || pattern == NULL)
67 return NULL;
68
69 while (*str) {
70 ps = (char *) str;
71 pp = (char *) pattern;
72 c1 = *ps;
73 c2 = *pp;
74 if (toupper(c1) == toupper(c2)) {
75 while (*pp) {
76 c1 = *ps;
77 c2 = *pp;
78
79 if (toupper(c1) != toupper(c2))
80 break;
81
82 ps++;
83 pp++;
84 }
85
86 if (!*pp)
87 return (char *) str;
88 }
89 str++;
90 }
91
92 return NULL;
93}
Here is the caller graph for this function:

◆ strsubst()

void strsubst ( char *  string,
int  size,
const char *  pattern,
const char *  subst 
)

Definition at line 97 of file msequencer.cxx.

99{
100 char *tail, *p;
101 int s;
102
103 p = string;
104 for (p = stristr(p, pattern); p != NULL; p = stristr(p, pattern)) {
105
106 if (strlen(pattern) == strlen(subst)) {
107 memcpy(p, subst, strlen(subst));
108 } else if (strlen(pattern) > strlen(subst)) {
109 memcpy(p, subst, strlen(subst));
110 memmove(p + strlen(subst), p + strlen(pattern), strlen(p + strlen(pattern)) + 1);
111 } else {
112 tail = (char *) malloc(strlen(p) - strlen(pattern) + 1);
113 strcpy(tail, p + strlen(pattern));
114 s = size - (p - string);
115 mstrlcpy(p, subst, s);
116 mstrlcat(p, tail, s);
117 free(tail);
118 tail = NULL;
119 }
120
121 p += strlen(subst);
122 }
123}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ toString()

static std::string toString ( int  v)
static

Definition at line 127 of file msequencer.cxx.

127 {
128 char buf[256];
129 snprintf(buf, sizeof(buf), "%d", v);
130 return buf;
131}

Variable Documentation

◆ gOdb

MVOdb* gOdb = NULL

Definition at line 44 of file msequencer.cxx.