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

Classes

class  SeqCon
 

Functions

 SEQUENCER_STR (sequencer_str)
 
charstristr (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, 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

MVOdbgOdb = 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
TH1X EXPRT * h1_book(const char *name, const char *title, int bins, double min, double max)
Definition rmidas.h:24
char c
Definition system.cxx:1310
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
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:3201
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] == '$')
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);
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:66
INT index
Definition mana.cxx:271
char param[10][256]
Definition mana.cxx:250
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++) {
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
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 2824 of file msequencer.cxx.

2824 {
2825 int status;
2826 HNDLE hKey;
2827
2828 c->odbs = gOdb->Chdir(c->odb_path.c_str(), true); // create /Sequencer
2829 assert(c->odbs);
2830
2831 status = db_find_key(c->hDB, 0, c->odb_path.c_str(), &c->hSeq);
2832 if (status != DB_SUCCESS) {
2833 cm_msg(MERROR, "init_sequencer", "Sequencer error: Cannot find /Sequencer, db_find_key() status %d", status);
2834 return;
2835 }
2836
2837 status = db_check_record(c->hDB, c->hSeq, "State", strcomb1(sequencer_str).c_str(), TRUE);
2838 if (status == DB_STRUCT_MISMATCH) {
2839 cm_msg(MERROR, "init_sequencer", "Sequencer error: mismatching /Sequencer/State structure, db_check_record() status %d", status);
2840 return;
2841 }
2842
2843 status = db_find_key(c->hDB, c->hSeq, "State", &hKey);
2844 if (status != DB_SUCCESS) {
2845 cm_msg(MERROR, "init_sequencer", "Sequencer error: Cannot find /Sequencer/State, db_find_key() status %d", status);
2846 return;
2847 }
2848
2849 int size = sizeof(seq);
2850 status = db_get_record1(c->hDB, hKey, &seq, &size, 0, strcomb1(sequencer_str).c_str());
2851 if (status != DB_SUCCESS) {
2852 cm_msg(MERROR, "init_sequencer", "Sequencer error: Cannot get /Sequencer/State, db_get_record1() status %d", status);
2853 return;
2854 }
2855
2856 if (strlen(seq.path) > 0 && seq.path[strlen(seq.path) - 1] != DIR_SEPARATOR) {
2857 mstrlcat(seq.path, DIR_SEPARATOR_STR, sizeof(seq.path));
2858 }
2859
2860 if (seq.filename[0])
2861 seq_open_file(seq.filename, seq, c);
2862
2863 seq.transition_request = FALSE;
2864
2865 db_set_record(c->hDB, hKey, &seq, sizeof(seq), 0);
2866
2867 status = db_watch(c->hDB, hKey, seq_watch, c);
2868 if (status != DB_SUCCESS) {
2869 cm_msg(MERROR, "init_sequencer", "Sequencer error: Cannot watch /Sequencer/State, db_watch() status %d", status);
2870 return;
2871 }
2872
2873 bool b = false;
2874 c->odbs->RB("Command/Start script", &b, true);
2875 b = false;
2876 c->odbs->RB("Command/Stop immediately", &b, true);
2877 b = false;
2878 c->odbs->RB("Command/Stop after run", &b, true);
2879 b = false;
2880 c->odbs->RB("Command/Cancel stop after run", &b, true);
2881 b = false;
2882 c->odbs->RB("Command/Pause script", &b, true);
2883 b = false;
2884 c->odbs->RB("Command/Resume script", &b, true);
2885 b = false;
2886 c->odbs->RB("Command/Debug script", &b, true);
2887 b = false;
2888 c->odbs->RB("Command/Step over", &b, true);
2889 b = false;
2890 c->odbs->RB("Command/Load new file", &b, true);
2891
2892 status = db_find_key(c->hDB, c->hSeq, "Command", &hKey);
2893 if (status != DB_SUCCESS) {
2894 cm_msg(MERROR, "init_sequencer", "Sequencer error: Cannot find /Sequencer/Command, db_find_key() status %d", status);
2895 return;
2896 }
2897
2899 if (status != DB_SUCCESS) {
2900 cm_msg(MERROR, "init_sequencer", "Sequencer error: Cannot watch /Sequencer/Command, db_watch() status %d", status);
2901 return;
2902 }
2903}
#define DB_STRUCT_MISMATCH
Definition midas.h:654
#define DB_SUCCESS
Definition midas.h:631
#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:915
std::string strcomb1(const char **list)
Definition odb.cxx:598
INT db_get_record1(HNDLE hDB, HNDLE hKey, void *data, INT *buf_size, INT align, const char *rec_str)
Definition odb.cxx:11805
INT db_check_record(HNDLE hDB, HNDLE hKey, const char *keyname, const char *rec_str, BOOL correct)
Definition odb.cxx:12972
INT db_watch(HNDLE hDB, HNDLE hKey, void(*dispatcher)(INT, INT, INT, void *), void *info)
Definition odb.cxx:13813
INT db_find_key(HNDLE hDB, HNDLE hKey, const char *key_name, HNDLE *subhKey)
Definition odb.cxx:4079
INT db_set_record(HNDLE hDB, HNDLE hKey, void *data, INT buf_size, INT align)
Definition odb.cxx:12291
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
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 call graph for this function:
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 call graph for this function:
Here is the caller graph for this function:

◆ main()

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

Definition at line 2907 of file msequencer.cxx.

2907 {
2908 int daemon = FALSE;
2909 int status, ch;
2910 char midas_hostname[256];
2911 char midas_expt[256];
2912 std::string seq_name = "";
2913
2914 setbuf(stdout, NULL);
2915 setbuf(stderr, NULL);
2916#ifdef SIGPIPE
2917 /* avoid getting killed by "Broken pipe" signals */
2919#endif
2920
2921 /* get default from environment */
2923
2924 /* parse command line parameters */
2925 for (int i = 1; i < argc; i++) {
2926 if (argv[i][0] == '-' && argv[i][1] == 'D') {
2927 daemon = TRUE;
2928 } else if (argv[i][0] == '-') {
2929 if (i + 1 >= argc || argv[i + 1][0] == '-')
2930 goto usage;
2931 if (argv[i][1] == 'h')
2933 else if (argv[i][1] == 'e')
2934 mstrlcpy(midas_expt, argv[++i], sizeof(midas_hostname));
2935 else if (argv[i][1] == 'c')
2936 seq_name = argv[++i];
2937 } else {
2938 usage:
2939 printf("usage: %s [-h Hostname[:port]] [-e Experiment] [-c Name] [-D]\n\n", argv[0]);
2940 printf(" -e experiment to connect to\n");
2941 printf(" -c Name of additional sequencer, i.e. \'Test\'\n");
2942 printf(" -h connect to midas server (mserver) on given host\n");
2943 printf(" -D become a daemon\n");
2944 return 0;
2945 }
2946 }
2947
2948 if (daemon) {
2949 printf("Becoming a daemon...\n");
2951 }
2952
2953 std::string prg_name = "Sequencer";
2954 std::string odb_path = "Sequencer";
2955
2956 if (!seq_name.empty()) {
2957 prg_name = std::string("Sequencer") + seq_name; // sequencer program name
2958 odb_path = std::string("Sequencer") + seq_name; // sequencer ODB path
2959 }
2960
2961#ifdef OS_LINUX
2962 std::string pid_filename;
2963 pid_filename += "/var/run/";
2964 pid_filename += prg_name;
2965 pid_filename += ".pid";
2966 /* write PID file */
2967 FILE *f = fopen(pid_filename.c_str(), "w");
2968 if (f != NULL) {
2969 fprintf(f, "%d", ss_getpid());
2970 fclose(f);
2971 }
2972#endif
2973
2974 /*---- connect to experiment ----*/
2977 return 1;
2978 else if (status == DB_INVALID_HANDLE) {
2979 std::string s = cm_get_error(status);
2980 puts(s.c_str());
2981 } else if (status != CM_SUCCESS) {
2982 std::string s = cm_get_error(status);
2983 puts(s.c_str());
2984 return 1;
2985 }
2986
2987 /* check if sequencer already running */
2988 status = cm_exist(prg_name.c_str(), TRUE);
2989 if (status == CM_SUCCESS) {
2990 printf("%s runs already.\n", prg_name.c_str());
2992 return 1;
2993 }
2994
2995 HNDLE hDB;
2998
2999 SEQUENCER seq;
3000 SeqCon c;
3001
3002 c.seqp = &seq;
3003 c.hDB = hDB;
3004 c.seq_name = seq_name;
3005 c.prg_name = prg_name;
3006 c.odb_path = odb_path;
3007
3008 init_sequencer(seq, &c);
3009
3010 if (seq_name.empty()) {
3011 printf("Sequencer started. Stop with \"!\"\n");
3012 } else {
3013 printf("%s started.\n", prg_name.c_str());
3014 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
3015 printf("Stop with \"!\"\n");
3016 }
3017
3018 // if any commands are active, process them now
3019 seq_watch_command(hDB, 0, 0, &c);
3020
3021 /* initialize ss_getchar */
3022 ss_getchar(0);
3023
3024 /* main loop */
3025 do {
3026 try {
3027 sequencer(seq, &c);
3028 } catch (std::string &msg) {
3029 seq_error(seq, &c, msg.c_str());
3030 } catch (const char *msg) {
3031 seq_error(seq, &c, msg);
3032 }
3033
3034 status = cm_yield(0);
3035
3036 ch = 0;
3037 while (ss_kbhit()) {
3038 ch = ss_getchar(0);
3039 if (ch == -1)
3040 ch = getchar();
3041
3042 if ((char) ch == '!')
3043 break;
3044 }
3045
3046 } while (status != RPC_SHUTDOWN && ch != '!');
3047
3048 /* reset terminal */
3050
3051 /* close network connection to server */
3053
3054 return 0;
3055}
SEQUENCER * seqp
static void usage()
INT cm_yield(INT millisec)
Definition midas.cxx:5642
INT cm_get_experiment_database(HNDLE *hDB, HNDLE *hKeyClient)
Definition midas.cxx:3011
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:2297
INT cm_disconnect_experiment(void)
Definition midas.cxx:2846
INT cm_get_environment(char *host_name, int host_name_size, char *exp_name, int exp_name_size)
Definition midas.cxx:2134
INT cm_exist(const char *name, BOOL bUnique)
Definition midas.cxx:7520
#define CM_SUCCESS
Definition midas.h:582
#define CM_WRONG_PASSWORD
Definition midas.h:589
#define DB_INVALID_HANDLE
Definition midas.h:635
#define RPC_SHUTDOWN
Definition midas.h:707
BOOL ss_kbhit()
Definition system.cxx:3664
INT ss_getchar(BOOL reset)
Definition system.cxx:7503
INT ss_getpid(void)
Definition system.cxx:1377
INT ss_daemon_init(BOOL keep_stdout)
Definition system.cxx:2001
std::string cm_get_error(INT code)
Definition midas.cxx:455
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;
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);
643
644 std::string path(cm_get_path());
645 path += "userfiles/sequencer/";
646 path += seq.path;
647
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";
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:1537
#define O_TEXT
Definition msystem.h:220
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
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 call graph for this function:
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
1494 }
1495 }
1496 }
1497}
void strarrayindex(char *odbpath, int *index1, int *index2)
Definition odb.cxx:3273
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}
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;
1077 seq.transition_request = 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
Here is the call graph for this function:
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));
169 seq.error_line = seq.current_line_number;
170 seq.serror_line = seq.scurrent_line_number;
171 seq.running = FALSE;
172 seq.transition_request = 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)
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}
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:1311
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)
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)
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
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:7710
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)
char filename[256]
Definition sequencer.h:10
char error[256]
Definition sequencer.h:13
char path[256]
Definition sequencer.h:9
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 1550 of file msequencer.cxx.

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

Variable Documentation

◆ gOdb

MVOdb* gOdb = NULL

Definition at line 44 of file msequencer.cxx.