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:75
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 2837 of file msequencer.cxx.

2837 {
2838 int status;
2839 HNDLE hKey;
2840
2841 c->odbs = gOdb->Chdir(c->odb_path.c_str(), true); // create /Sequencer
2842 assert(c->odbs);
2843
2844 status = db_find_key(c->hDB, 0, c->odb_path.c_str(), &c->hSeq);
2845 if (status != DB_SUCCESS) {
2846 cm_msg(MERROR, "init_sequencer", "Sequencer error: Cannot find /Sequencer, db_find_key() status %d", status);
2847 return;
2848 }
2849
2850 status = db_check_record(c->hDB, c->hSeq, "State", strcomb1(sequencer_str).c_str(), TRUE);
2851 if (status == DB_STRUCT_MISMATCH) {
2852 cm_msg(MERROR, "init_sequencer", "Sequencer error: mismatching /Sequencer/State structure, db_check_record() status %d", status);
2853 return;
2854 }
2855
2856 status = db_find_key(c->hDB, c->hSeq, "State", &hKey);
2857 if (status != DB_SUCCESS) {
2858 cm_msg(MERROR, "init_sequencer", "Sequencer error: Cannot find /Sequencer/State, db_find_key() status %d", status);
2859 return;
2860 }
2861
2862 int size = sizeof(seq);
2863 status = db_get_record1(c->hDB, hKey, &seq, &size, 0, strcomb1(sequencer_str).c_str());
2864 if (status != DB_SUCCESS) {
2865 cm_msg(MERROR, "init_sequencer", "Sequencer error: Cannot get /Sequencer/State, db_get_record1() status %d", status);
2866 return;
2867 }
2868
2869 if (strlen(seq.path) > 0 && seq.path[strlen(seq.path) - 1] != DIR_SEPARATOR) {
2870 mstrlcat(seq.path, DIR_SEPARATOR_STR, sizeof(seq.path));
2871 }
2872
2873 if (seq.filename[0])
2874 seq_open_file(seq.filename, seq, c);
2875
2876 seq.transition_request = FALSE;
2877
2878 db_set_record(c->hDB, hKey, &seq, sizeof(seq), 0);
2879
2880 status = db_watch(c->hDB, hKey, seq_watch, c);
2881 if (status != DB_SUCCESS) {
2882 cm_msg(MERROR, "init_sequencer", "Sequencer error: Cannot watch /Sequencer/State, db_watch() status %d", status);
2883 return;
2884 }
2885
2886 bool b = false;
2887 c->odbs->RB("Command/Start script", &b, true);
2888 b = false;
2889 c->odbs->RB("Command/Stop immediately", &b, true);
2890 b = false;
2891 c->odbs->RB("Command/Stop after run", &b, true);
2892 b = false;
2893 c->odbs->RB("Command/Cancel stop after run", &b, true);
2894 b = false;
2895 c->odbs->RB("Command/Pause script", &b, true);
2896 b = false;
2897 c->odbs->RB("Command/Resume script", &b, true);
2898 b = false;
2899 c->odbs->RB("Command/Debug script", &b, true);
2900 b = false;
2901 c->odbs->RB("Command/Step over", &b, true);
2902 b = false;
2903 c->odbs->RB("Command/Load new file", &b, true);
2904
2905 status = db_find_key(c->hDB, c->hSeq, "Command", &hKey);
2906 if (status != DB_SUCCESS) {
2907 cm_msg(MERROR, "init_sequencer", "Sequencer error: Cannot find /Sequencer/Command, db_find_key() status %d", status);
2908 return;
2909 }
2910
2912 if (status != DB_SUCCESS) {
2913 cm_msg(MERROR, "init_sequencer", "Sequencer error: Cannot watch /Sequencer/Command, db_watch() status %d", status);
2914 return;
2915 }
2916}
#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:11806
INT db_check_record(HNDLE hDB, HNDLE hKey, const char *keyname, const char *rec_str, BOOL correct)
Definition odb.cxx:12973
INT db_watch(HNDLE hDB, HNDLE hKey, void(*dispatcher)(INT, INT, INT, void *), void *info)
Definition odb.cxx:13814
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:12292
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 2920 of file msequencer.cxx.

2920 {
2921 int daemon = FALSE;
2922 int status, ch;
2923 char midas_hostname[256];
2924 char midas_expt[256];
2925 std::string seq_name = "";
2926
2927 setbuf(stdout, NULL);
2928 setbuf(stderr, NULL);
2929#ifdef SIGPIPE
2930 /* avoid getting killed by "Broken pipe" signals */
2932#endif
2933
2934 /* get default from environment */
2936
2937 /* parse command line parameters */
2938 for (int i = 1; i < argc; i++) {
2939 if (argv[i][0] == '-' && argv[i][1] == 'D') {
2940 daemon = TRUE;
2941 } else if (argv[i][0] == '-') {
2942 if (i + 1 >= argc || argv[i + 1][0] == '-')
2943 goto usage;
2944 if (argv[i][1] == 'h')
2946 else if (argv[i][1] == 'e')
2947 mstrlcpy(midas_expt, argv[++i], sizeof(midas_hostname));
2948 else if (argv[i][1] == 'c')
2949 seq_name = argv[++i];
2950 } else {
2951 usage:
2952 printf("usage: %s [-h Hostname[:port]] [-e Experiment] [-c Name] [-D]\n\n", argv[0]);
2953 printf(" -e experiment to connect to\n");
2954 printf(" -c Name of additional sequencer, i.e. \'Test\'\n");
2955 printf(" -h connect to midas server (mserver) on given host\n");
2956 printf(" -D become a daemon\n");
2957 return 0;
2958 }
2959 }
2960
2961 if (daemon) {
2962 printf("Becoming a daemon...\n");
2964 }
2965
2966 std::string prg_name = "Sequencer";
2967 std::string odb_path = "Sequencer";
2968
2969 if (!seq_name.empty()) {
2970 prg_name = std::string("Sequencer") + seq_name; // sequencer program name
2971 odb_path = std::string("Sequencer") + seq_name; // sequencer ODB path
2972 }
2973
2974#ifdef OS_LINUX
2975 std::string pid_filename;
2976 pid_filename += "/var/run/";
2977 pid_filename += prg_name;
2978 pid_filename += ".pid";
2979 /* write PID file */
2980 FILE *f = fopen(pid_filename.c_str(), "w");
2981 if (f != NULL) {
2982 fprintf(f, "%d", ss_getpid());
2983 fclose(f);
2984 }
2985#endif
2986
2987 /*---- connect to experiment ----*/
2990 return 1;
2991 else if (status == DB_INVALID_HANDLE) {
2992 std::string s = cm_get_error(status);
2993 puts(s.c_str());
2994 } else if (status != CM_SUCCESS) {
2995 std::string s = cm_get_error(status);
2996 puts(s.c_str());
2997 return 1;
2998 }
2999
3000 /* check if sequencer already running */
3001 status = cm_exist(prg_name.c_str(), TRUE);
3002 if (status == CM_SUCCESS) {
3003 printf("%s runs already.\n", prg_name.c_str());
3005 return 1;
3006 }
3007
3008 HNDLE hDB;
3011
3012 SEQUENCER seq;
3013 SeqCon c;
3014
3015 c.seqp = &seq;
3016 c.hDB = hDB;
3017 c.seq_name = seq_name;
3018 c.prg_name = prg_name;
3019 c.odb_path = odb_path;
3020
3021 init_sequencer(seq, &c);
3022
3023 if (seq_name.empty()) {
3024 printf("Sequencer started. Stop with \"!\"\n");
3025 } else {
3026 printf("%s started.\n", prg_name.c_str());
3027 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
3028 printf("Stop with \"!\"\n");
3029 }
3030
3031 // if any commands are active, process them now
3032 seq_watch_command(hDB, 0, 0, &c);
3033
3034 /* initialize ss_getchar */
3035 ss_getchar(0);
3036
3037 /* main loop */
3038 do {
3039 try {
3040 sequencer(seq, &c);
3041 } catch (std::string &msg) {
3042 seq_error(seq, &c, msg.c_str());
3043 } catch (const char *msg) {
3044 seq_error(seq, &c, msg);
3045 }
3046
3047 status = cm_yield(0);
3048
3049 ch = 0;
3050 while (ss_kbhit()) {
3051 ch = ss_getchar(0);
3052 if (ch == -1)
3053 ch = getchar();
3054
3055 if ((char) ch == '!')
3056 break;
3057 }
3058
3059 } while (status != RPC_SHUTDOWN && ch != '!');
3060
3061 /* reset terminal */
3063
3064 /* close network connection to server */
3066
3067 return 0;
3068}
SEQUENCER * seqp
static void usage()
INT cm_yield(INT millisec)
Definition midas.cxx:5650
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:7528
#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:7509
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:7718
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 1547 of file msequencer.cxx.

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