MIDAS
Sequencer Functions

Classes

class  SeqCon
 

Functions

 SEQUENCER_STR (sequencer_str)
 
char * stristr (const char *str, const char *pattern)
 
void strsubst (char *string, int size, const char *pattern, const char *subst)
 
static std::string toString (int v)
 
static std::string qtoString (std::string filename, int line, int level)
 
static std::string q (const char *s)
 
bool is_valid_number (const char *str)
 
void seq_error (SEQUENCER &seq, SeqCon *c, const char *str)
 
int strbreak (char *str, char list[][XNAME_LENGTH], int size, const char *brk, BOOL ignore_quotes)
 
std::string eval_var (SEQUENCER &seq, SeqCon *c, std::string value)
 
int concatenate (SEQUENCER &seq, SeqCon *c, char *result, int size, char *value)
 
int eval_condition (SEQUENCER &seq, SeqCon *c, const char *condition)
 
bool loadMSL (MVOdb *o, const std::string &filename)
 
static BOOL msl_parse (SEQUENCER &seq, SeqCon *c, int level, const char *cpath, const char *filename, const char *xml_filename, char *error, int error_size, int *error_line)
 
void seq_read (SEQUENCER *seq, SeqCon *c)
 
void seq_write (const SEQUENCER &seq, SeqCon *c)
 
void seq_clear (SEQUENCER &seq)
 
static void seq_start (SEQUENCER &seq, SeqCon *c, bool debug)
 
static void seq_stop (SEQUENCER &seq, SeqCon *c)
 
static void seq_stop_after_run (SEQUENCER &seq, SeqCon *c)
 
static void seq_cancel_stop_after_run (SEQUENCER &seq, SeqCon *c)
 
static void seq_pause (SEQUENCER &seq, SeqCon *c, bool flag)
 
static 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

MVOdb * gOdb = NULL
 

Detailed Description

dox


Function Documentation

◆ concatenate()

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

Definition at line 368 of file msequencer.cxx.

368  {
369  char list[100][XNAME_LENGTH];
370  int i, n;
371 
372  n = strbreak(value, list, 100, ",", FALSE);
373 
374  result[0] = 0;
375  for (i = 0; i < n; i++) {
376  std::string str = eval_var(seq, c, std::string(list[i]));
377  strlcat(result, str.c_str(), size);
378  }
379 
380  return TRUE;
381 }
#define FALSE
Definition: cfortran.h:309
int strbreak(char *str, char list[][XNAME_LENGTH], int size, const char *brk, BOOL ignore_quotes)
Definition: msequencer.cxx:186
std::string eval_var(SEQUENCER &seq, SeqCon *c, std::string value)
Definition: msequencer.cxx:267
DWORD n[4]
Definition: mana.cxx:247
INT i
Definition: mdump.cxx:35
size_t EXPRT strlcat(char *dst, const char *src, size_t size)
#define TRUE
Definition: midas.h:182
#define XNAME_LENGTH
Definition: msequencer.cxx:25
double value[100]
Definition: odbhist.cxx:42
char str[256]
Definition: odbhist.cxx:33
char c
Definition: system.cxx:1316
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 385 of file msequencer.cxx.

385  {
386  int i;
387  double value1, value2;
388  char value1_str[256], value2_str[256], str[256], op[3], *p;
389  std::string value1_var, value2_var;
390 
391  // strip leading and trailing space
392  p = (char *)condition;
393  while (*p == ' ')
394  p++;
395  strcpy(str, p);
396 
397  // strip any comment '#'
398  if (strchr(str, '#'))
399  *strchr(str, '#') = 0;
400 
401  while (strlen(str) > 0 && (str[strlen(str)-1] == ' '))
402  str[strlen(str)-1] = 0;
403 
404  // strip enclosing '()'
405  if (str[0] == '(' && strlen(str) > 0 && str[strlen(str)-1] == ')') {
406  strlcpy(value1_str, str+1, sizeof(value1_str));
407  strlcpy(str, value1_str, sizeof(str));
408  str[strlen(str)-1] = 0;
409  }
410 
411  op[1] = op[2] = 0;
412 
413  /* find value and operator */
414  for (i = 0; i < (int) strlen(str); i++)
415  if (strchr("<>=!&", str[i]) != NULL)
416  break;
417  strlcpy(value1_str, str, i + 1);
418  while (value1_str[strlen(value1_str) - 1] == ' ')
419  value1_str[strlen(value1_str) - 1] = 0;
420  op[0] = str[i];
421  if (strchr("<>=!&", str[i + 1]) != NULL)
422  op[1] = str[++i];
423 
424  for (i++; str[i] == ' '; i++);
425  strlcpy(value2_str, str + i, sizeof(value2_str));
426 
427  value1_var = eval_var(seq, c, value1_str);
428  value2_var = eval_var(seq, c, value2_str);
429 
430  if (!is_valid_number(value1_var.c_str()) || !is_valid_number(value2_var.c_str())) {
431  // string comparison
432  if (strcmp(op, "=") == 0)
433  return equal_ustring(value1_var.c_str(), value2_var.c_str()) ? 1 : 0;
434  if (strcmp(op, "==") == 0)
435  return equal_ustring(value1_var.c_str(), value2_var.c_str()) ? 1 : 0;
436  if (strcmp(op, "!=") == 0)
437  return equal_ustring(value1_var.c_str(), value2_var.c_str()) ? 0 : 1;
438  // invalid operator for string comparisons
439  return -1;
440  }
441 
442  // numeric comparison
443  value1 = atof(value1_var.c_str());
444  value2 = atof(value2_var.c_str());
445 
446  /* now do logical operation */
447  if (strcmp(op, "=") == 0)
448  if (value1 == value2)
449  return 1;
450  if (strcmp(op, "==") == 0)
451  if (value1 == value2)
452  return 1;
453  if (strcmp(op, "!=") == 0)
454  if (value1 != value2)
455  return 1;
456  if (strcmp(op, "<") == 0)
457  if (value1 < value2)
458  return 1;
459  if (strcmp(op, ">") == 0)
460  if (value1 > value2)
461  return 1;
462  if (strcmp(op, "<=") == 0)
463  if (value1 <= value2)
464  return 1;
465  if (strcmp(op, ">=") == 0)
466  if (value1 >= value2)
467  return 1;
468  if (strcmp(op, "&") == 0)
469  if (((unsigned int) value1 & (unsigned int) value2) > 0)
470  return 1;
471 
472  return 0;
473 }
BOOL equal_ustring(const char *str1, const char *str2)
Definition: odb.cxx:3191
bool is_valid_number(const char *str)
Definition: msequencer.cxx:147
size_t EXPRT strlcpy(char *dst, const char *src, size_t size)
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]) && atoi(s.c_str()) > 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 found";
297  vsubst = param[index - 1];
298  if (vsubst[0] == '$')
299  vsubst = eval_var(seq, c, vsubst);
300  } else
301  throw "Parameter $" + std::to_string(index) + " not found";
302  } else {
303  // find end of string
304  for (i2 = i1 + 1; std::isalnum(result[i2]) || result[i2] == '_';)
305  i2++;
306  s = s.substr(0, i2 - i1 - 1);
307  if (result[i2] == '[') {
308  // array
309  auto sindex = result.substr(i2+1);
310  int i = sindex.find(']');
311  if (i == (int)std::string::npos)
312  throw "Variable \"" + result +"\" does not contain ']'";
313  sindex = sindex.substr(0, i);
314  sindex = eval_var(seq, c, sindex);
315  int index;
316  try {
317  index = std::stoi(sindex);
318  } catch (...) {
319  throw "Variable \"" + s + "\" has invalid index";
320  }
321 
322  try {
323  midas::odb o(xpath + "/Variables/" + s);
324  std::vector<std::string> sv = o;
325  vsubst = sv[index];
326  } catch (...) {
327  throw "Variable \"" + s + "\" not found";
328  }
329  while (result[i2] && result[i2] != ']')
330  i2++;
331  if (!result[i2])
332  throw "Variable \"" + result +"\" does not contain ']'";
333  if (result[i2] == ']')
334  i2++;
335  } else {
336  try {
337  midas::odb o(xpath + "/Variables/" + s);
338  vsubst = o;
339  } catch (...) {
340  throw "Variable \"" + s + "\" not found";
341  }
342  }
343  }
344 
345  result = result.substr(0, i1) + vsubst + result.substr(i2);
346  }
347 
348  //printf("eval [%s] xpath [%s] result [%s]\n", value.c_str(), xpath.c_str(), result.c_str());
349 
350  int error;
351  double r = te_interp(result.c_str(), &error);
352  if (error > 0) {
353  // check if result is only a string
354  if (!std::isdigit(result[0]) && result[0] != '-')
355  return result;
356 
357  throw "Error in expression \"" + result + "\" position " + std::to_string(error - 1);
358  }
359 
360  if (r == (int) r)
361  return std::to_string((int) r);
362 
363  return std::to_string(r);
364 }
INT index
Definition: mana.cxx:271
char param[10][256]
Definition: mana.cxx:250
static std::string to_string(int v)
Definition: odbinit.cxx:22
int stack_index
Definition: sequencer.h:40
char subroutine_param[SEQ_NEST_LEVEL_SUB][256]
Definition: sequencer.h:45
double te_interp(const char *expression, int *error)
Definition: tinyexpr.c:690
Here is the call graph for this function:
Here is the caller graph for this function:

◆ init_sequencer()

void init_sequencer ( SEQUENCER seq,
SeqCon c 
)

Definition at line 2643 of file msequencer.cxx.

2643  {
2644  int status;
2645  HNDLE hKey;
2646 
2647  c->odbs = gOdb->Chdir(c->odb_path.c_str(), true); // create /Sequencer
2648  assert(c->odbs);
2649 
2650  status = db_find_key(c->hDB, 0, c->odb_path.c_str(), &c->hSeq);
2651  if (status != DB_SUCCESS) {
2652  cm_msg(MERROR, "init_sequencer", "Sequencer error: Cannot find /Sequencer, db_find_key() status %d", status);
2653  return;
2654  }
2655 
2656  status = db_check_record(c->hDB, c->hSeq, "State", strcomb1(sequencer_str).c_str(), TRUE);
2657  if (status == DB_STRUCT_MISMATCH) {
2658  cm_msg(MERROR, "init_sequencer", "Sequencer error: mismatching /Sequencer/State structure, db_check_record() status %d", status);
2659  return;
2660  }
2661 
2662  status = db_find_key(c->hDB, c->hSeq, "State", &hKey);
2663  if (status != DB_SUCCESS) {
2664  cm_msg(MERROR, "init_sequencer", "Sequencer error: Cannot find /Sequencer/State, db_find_key() status %d", status);
2665  return;
2666  }
2667 
2668  int size = sizeof(seq);
2669  status = db_get_record1(c->hDB, hKey, &seq, &size, 0, strcomb1(sequencer_str).c_str());
2670  if (status != DB_SUCCESS) {
2671  cm_msg(MERROR, "init_sequencer", "Sequencer error: Cannot get /Sequencer/State, db_get_record1() status %d", status);
2672  return;
2673  }
2674 
2675  if (strlen(seq.path) > 0 && seq.path[strlen(seq.path) - 1] != DIR_SEPARATOR) {
2676  strlcat(seq.path, DIR_SEPARATOR_STR, sizeof(seq.path));
2677  }
2678 
2679  if (seq.filename[0])
2680  seq_open_file(seq.filename, seq, c);
2681 
2682  seq.transition_request = FALSE;
2683 
2684  db_set_record(c->hDB, hKey, &seq, sizeof(seq), 0);
2685 
2686  status = db_watch(c->hDB, hKey, seq_watch, c);
2687  if (status != DB_SUCCESS) {
2688  cm_msg(MERROR, "init_sequencer", "Sequencer error: Cannot watch /Sequencer/State, db_watch() status %d", status);
2689  return;
2690  }
2691 
2692  bool b = false;
2693  c->odbs->RB("Command/Start script", &b, true);
2694  b = false;
2695  c->odbs->RB("Command/Stop immediately", &b, true);
2696  b = false;
2697  c->odbs->RB("Command/Stop after run", &b, true);
2698  b = false;
2699  c->odbs->RB("Command/Cancel stop after run", &b, true);
2700  b = false;
2701  c->odbs->RB("Command/Pause script", &b, true);
2702  b = false;
2703  c->odbs->RB("Command/Resume script", &b, true);
2704  b = false;
2705  c->odbs->RB("Command/Debug script", &b, true);
2706  b = false;
2707  c->odbs->RB("Command/Step over", &b, true);
2708  b = false;
2709  c->odbs->RB("Command/Load new file", &b, true);
2710  std::string s;
2711  c->odbs->RS("Command/Load filename", &s, true);
2712 
2713  status = db_find_key(c->hDB, c->hSeq, "Command", &hKey);
2714  if (status != DB_SUCCESS) {
2715  cm_msg(MERROR, "init_sequencer", "Sequencer error: Cannot find /Sequencer/Command, db_find_key() status %d", status);
2716  return;
2717  }
2718 
2719  status = db_watch(c->hDB, hKey, seq_watch_command, c);
2720  if (status != DB_SUCCESS) {
2721  cm_msg(MERROR, "init_sequencer", "Sequencer error: Cannot watch /Sequencer/Command, db_watch() status %d", status);
2722  return;
2723  }
2724 }
#define DB_STRUCT_MISMATCH
Definition: midas.h:660
#define DB_SUCCESS
Definition: midas.h:637
#define MERROR
Definition: midas.h:565
INT cm_msg(INT message_type, const char *filename, INT line, const char *routine, const char *format,...)
Definition: midas.cxx:917
std::string strcomb1(const char **list)
Definition: odb.cxx:601
INT db_get_record1(HNDLE hDB, HNDLE hKey, void *data, INT *buf_size, INT align, const char *rec_str)
Definition: odb.cxx:11809
INT db_check_record(HNDLE hDB, HNDLE hKey, const char *keyname, const char *rec_str, BOOL correct)
Definition: odb.cxx:12975
INT db_watch(HNDLE hDB, HNDLE hKey, void(*dispatcher)(INT, INT, INT, void *), void *info)
Definition: odb.cxx:13815
INT db_find_key(HNDLE hDB, HNDLE hKey, const char *key_name, HNDLE *subhKey)
Definition: odb.cxx:4069
INT db_set_record(HNDLE hDB, HNDLE hKey, void *data, INT buf_size, INT align)
Definition: odb.cxx:12295
static void seq_watch(HNDLE hDB, HNDLE hKeyChanged, int index, void *info)
MVOdb * gOdb
Definition: msequencer.cxx:44
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
Definition: lazylogger.cxx:207
#define DIR_SEPARATOR
Definition: midas.h:193
INT HNDLE
Definition: midas.h:132
#define DIR_SEPARATOR_STR
Definition: midas.h:194
DWORD status
Definition: odbhist.cxx:39
BOOL transition_request
Definition: sequencer.h:26
char filename[256]
Definition: sequencer.h:10
char path[256]
Definition: sequencer.h:9
Here is the call graph for this function:
Here is the caller graph for this function:

◆ is_valid_number()

bool is_valid_number ( const char *  str)

Definition at line 147 of file msequencer.cxx.

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

◆ loadMSL()

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

Definition at line 477 of file msequencer.cxx.

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

◆ main()

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

Definition at line 2728 of file msequencer.cxx.

2728  {
2729  int daemon = FALSE;
2730  int status, ch;
2731  char midas_hostname[256];
2732  char midas_expt[256];
2733  std::string seq_name = "";
2734 
2735  setbuf(stdout, NULL);
2736  setbuf(stderr, NULL);
2737 #ifdef SIGPIPE
2738  /* avoid getting killed by "Broken pipe" signals */
2739  signal(SIGPIPE, SIG_IGN);
2740 #endif
2741 
2742  /* get default from environment */
2743  cm_get_environment(midas_hostname, sizeof(midas_hostname), midas_expt, sizeof(midas_expt));
2744 
2745  /* parse command line parameters */
2746  for (int i = 1; i < argc; i++) {
2747  if (argv[i][0] == '-' && argv[i][1] == 'D') {
2748  daemon = TRUE;
2749  } else if (argv[i][0] == '-') {
2750  if (i + 1 >= argc || argv[i + 1][0] == '-')
2751  goto usage;
2752  if (argv[i][1] == 'h')
2753  strlcpy(midas_hostname, argv[++i], sizeof(midas_hostname));
2754  else if (argv[i][1] == 'e')
2755  strlcpy(midas_expt, argv[++i], sizeof(midas_hostname));
2756  else if (argv[i][1] == 'c')
2757  seq_name = argv[++i];
2758  } else {
2759  usage:
2760  printf("usage: %s [-h Hostname[:port]] [-e Experiment] [-c Name] [-D]\n\n", argv[0]);
2761  printf(" -e experiment to connect to\n");
2762  printf(" -c Name of additional sequencer, i.e. \'Test\'\n");
2763  printf(" -h connect to midas server (mserver) on given host\n");
2764  printf(" -D become a daemon\n");
2765  return 0;
2766  }
2767  }
2768 
2769  if (daemon) {
2770  printf("Becoming a daemon...\n");
2772  }
2773 
2774  std::string prg_name = "Sequencer";
2775  std::string odb_path = "Sequencer";
2776 
2777  if (!seq_name.empty()) {
2778  prg_name = std::string("Sequencer") + seq_name; // sequencer program name
2779  odb_path = std::string("Sequencer") + seq_name; // sequencer ODB path
2780  }
2781 
2782 #ifdef OS_LINUX
2783  std::string pid_filename;
2784  pid_filename += "/var/run/";
2785  pid_filename += prg_name;
2786  pid_filename += ".pid";
2787  /* write PID file */
2788  FILE *f = fopen(pid_filename.c_str(), "w");
2789  if (f != NULL) {
2790  fprintf(f, "%d", ss_getpid());
2791  fclose(f);
2792  }
2793 #endif
2794 
2795  /*---- connect to experiment ----*/
2796  status = cm_connect_experiment1(midas_hostname, midas_expt, prg_name.c_str(), NULL, DEFAULT_ODB_SIZE, DEFAULT_WATCHDOG_TIMEOUT);
2797  if (status == CM_WRONG_PASSWORD)
2798  return 1;
2799  else if (status == DB_INVALID_HANDLE) {
2800  std::string s = cm_get_error(status);
2801  puts(s.c_str());
2802  } else if (status != CM_SUCCESS) {
2803  std::string s = cm_get_error(status);
2804  puts(s.c_str());
2805  return 1;
2806  }
2807 
2808  /* check if sequencer already running */
2809  status = cm_exist(prg_name.c_str(), TRUE);
2810  if (status == CM_SUCCESS) {
2811  printf("%s runs already.\n", prg_name.c_str());
2813  return 1;
2814  }
2815 
2816  HNDLE hDB;
2818  gOdb = MakeMidasOdb(hDB);
2819 
2820  SEQUENCER seq;
2821  SeqCon c;
2822 
2823  c.seqp = &seq;
2824  c.hDB = hDB;
2825  c.seq_name = seq_name;
2826  c.prg_name = prg_name;
2827  c.odb_path = odb_path;
2828 
2829  init_sequencer(seq, &c);
2830 
2831  if (seq_name.empty()) {
2832  printf("Sequencer started. Stop with \"!\"\n");
2833  } else {
2834  printf("%s started.\n", prg_name.c_str());
2835  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
2836  printf("Stop with \"!\"\n");
2837  }
2838 
2839  // if any commands are active, process them now
2840  seq_watch_command(hDB, 0, 0, &c);
2841 
2842  /* initialize ss_getchar */
2843  ss_getchar(0);
2844 
2845  /* main loop */
2846  do {
2847  try {
2848  sequencer(seq, &c);
2849  } catch (std::string &msg) {
2850  seq_error(seq, &c, msg.c_str());
2851  } catch (const char *msg) {
2852  seq_error(seq, &c, msg);
2853  }
2854 
2855  status = cm_yield(0);
2856 
2857  ch = 0;
2858  while (ss_kbhit()) {
2859  ch = ss_getchar(0);
2860  if (ch == -1)
2861  ch = getchar();
2862 
2863  if ((char) ch == '!')
2864  break;
2865  }
2866 
2867  } while (status != RPC_SHUTDOWN && ch != '!');
2868 
2869  /* reset terminal */
2870  ss_getchar(TRUE);
2871 
2872  /* close network connection to server */
2874 
2875  return 0;
2876 }
static void usage()
Definition: fetest_tmfe.cxx:98
INT cm_yield(INT millisec)
Definition: midas.cxx:5638
INT cm_get_experiment_database(HNDLE *hDB, HNDLE *hKeyClient)
Definition: midas.cxx:3005
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:2299
INT cm_disconnect_experiment(void)
Definition: midas.cxx:2840
INT cm_get_environment(char *host_name, int host_name_size, char *exp_name, int exp_name_size)
Definition: midas.cxx:2136
INT cm_exist(const char *name, BOOL bUnique)
Definition: midas.cxx:7484
#define CM_SUCCESS
Definition: midas.h:588
#define CM_WRONG_PASSWORD
Definition: midas.h:595
#define DB_INVALID_HANDLE
Definition: midas.h:641
#define RPC_SHUTDOWN
Definition: midas.h:713
BOOL ss_kbhit()
Definition: system.cxx:3603
INT ss_getchar(BOOL reset)
Definition: system.cxx:7442
INT ss_getpid(void)
Definition: system.cxx:1383
INT ss_daemon_init(BOOL keep_stdout)
Definition: system.cxx:1972
std::string cm_get_error(INT code)
Definition: midas.cxx:457
void init_sequencer(SEQUENCER &seq, SeqCon *c)
void sequencer(SEQUENCER &seq, SeqCon *c)
void seq_error(SEQUENCER &seq, SeqCon *c, const char *str)
Definition: msequencer.cxx:164
BOOL daemon
Definition: mana.cxx:258
HNDLE hDB
main ODB handle
Definition: mana.cxx:207
#define DEFAULT_WATCHDOG_TIMEOUT
Definition: midas.h:297
#define DEFAULT_ODB_SIZE
Definition: midas.h:277
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 498 of file msequencer.cxx.

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

1362  {
1363  char str[256];
1364  *index1 = *index2 = 0;
1365  if (odbpath[strlen(odbpath) - 1] == ']') {
1366  if (strchr(odbpath, '[')) {
1367  //check for sequencer variables
1368  if (strchr((strchr(odbpath, '[') + 1), '$')) {
1369  strlcpy(str, strchr(odbpath, '[') + 1, sizeof(str));
1370  if (strchr(str, ']'))
1371  *strchr(str, ']') = 0;
1372  *index1 = atoi(eval_var(seq, c, str).c_str());
1373 
1374  *strchr(odbpath, '[') = 0;
1375  } else {
1376  //standard expansion
1377  strarrayindex(odbpath, index1, index2);
1378  }
1379  }
1380  }
1381 }
void strarrayindex(char *odbpath, int *index1, int *index2)
Definition: odb.cxx:3263
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 1132 of file msequencer.cxx.

1132  {
1133  seq_read(&seq, c);
1134  seq.stop_after_run = false;
1135  seq_write(seq, c);
1136 }
void seq_write(const SEQUENCER &seq, SeqCon *c)
Definition: msequencer.cxx:995
void seq_read(SEQUENCER *seq, SeqCon *c)
Definition: msequencer.cxx:977
BOOL stop_after_run
Definition: sequencer.h:25
Here is the call graph for this function:
Here is the caller graph for this function:

◆ seq_clear()

void seq_clear ( SEQUENCER seq)

Definition at line 1013 of file msequencer.cxx.

1013  {
1014  seq.running = FALSE;
1015  seq.finished = FALSE;
1016  seq.paused = FALSE;
1017  seq.transition_request = FALSE;
1018  seq.wait_limit = 0;
1019  seq.wait_value = 0;
1020  seq.start_time = 0;
1021  seq.wait_type[0] = 0;
1022  seq.wait_odb[0] = 0;
1023  for (int i = 0; i < SEQ_NEST_LEVEL_LOOP; i++) {
1024  seq.loop_start_line[i] = 0;
1025  seq.sloop_start_line[i] = 0;
1026  seq.loop_end_line[i] = 0;
1027  seq.sloop_end_line[i] = 0;
1028  seq.loop_counter[i] = 0;
1029  seq.loop_n[i] = 0;
1030  }
1031  for (int i = 0; i < SEQ_NEST_LEVEL_IF; i++) {
1032  seq.if_else_line[i] = 0;
1033  seq.if_endif_line[i] = 0;
1034  }
1035  for (int i = 0; i < SEQ_NEST_LEVEL_SUB; i++) {
1036  seq.subroutine_end_line[i] = 0;
1037  seq.subroutine_return_line[i] = 0;
1038  seq.subroutine_call_line[i] = 0;
1039  seq.ssubroutine_call_line[i] = 0;
1040  seq.subroutine_param[i][0] = 0;
1041  }
1042  seq.current_line_number = 0;
1043  seq.scurrent_line_number = 0;
1044  seq.sfilename[0] = 0;
1045  seq.if_index = 0;
1046  seq.stack_index = 0;
1047  seq.error[0] = 0;
1048  seq.error_line = 0;
1049  seq.serror_line = 0;
1050  seq.subdir[0] = 0;
1051  seq.subdir_end_line = 0;
1052  seq.subdir_not_notify = 0;
1053  seq.message[0] = 0;
1054  seq.message_wait = FALSE;
1055  seq.stop_after_run = FALSE;
1056 }
#define SEQ_NEST_LEVEL_IF
Definition: sequencer.h:4
#define SEQ_NEST_LEVEL_LOOP
Definition: sequencer.h:3
#define SEQ_NEST_LEVEL_SUB
Definition: sequencer.h:5
int serror_line
Definition: sequencer.h:15
char wait_odb[256]
Definition: sequencer.h:50
int if_index
Definition: sequencer.h:36
float wait_value
Definition: sequencer.h:46
int loop_end_line[SEQ_NEST_LEVEL_LOOP]
Definition: sequencer.h:29
float wait_limit
Definition: sequencer.h:47
int sloop_start_line[SEQ_NEST_LEVEL_LOOP]
Definition: sequencer.h:28
int error_line
Definition: sequencer.h:14
BOOL finished
Definition: sequencer.h:19
int subroutine_return_line[SEQ_NEST_LEVEL_SUB]
Definition: sequencer.h:42
BOOL message_wait
Definition: sequencer.h:17
int loop_start_line[SEQ_NEST_LEVEL_LOOP]
Definition: sequencer.h:27
int subroutine_end_line[SEQ_NEST_LEVEL_SUB]
Definition: sequencer.h:41
int if_else_line[SEQ_NEST_LEVEL_IF]
Definition: sequencer.h:38
int sloop_end_line[SEQ_NEST_LEVEL_LOOP]
Definition: sequencer.h:30
char subdir[256]
Definition: sequencer.h:33
char message[256]
Definition: sequencer.h:16
BOOL paused
Definition: sequencer.h:20
int if_endif_line[SEQ_NEST_LEVEL_IF]
Definition: sequencer.h:39
DWORD start_time
Definition: sequencer.h:48
int subroutine_call_line[SEQ_NEST_LEVEL_SUB]
Definition: sequencer.h:43
int loop_n[SEQ_NEST_LEVEL_LOOP]
Definition: sequencer.h:32
int ssubroutine_call_line[SEQ_NEST_LEVEL_SUB]
Definition: sequencer.h:44
int subdir_end_line
Definition: sequencer.h:34
int loop_counter[SEQ_NEST_LEVEL_LOOP]
Definition: sequencer.h:31
int current_line_number
Definition: sequencer.h:22
char error[256]
Definition: sequencer.h:13
int scurrent_line_number
Definition: sequencer.h:23
char wait_type[32]
Definition: sequencer.h:49
char sfilename[256]
Definition: sequencer.h:11
int subdir_not_notify
Definition: sequencer.h:35
Here is the caller graph for this function:

◆ seq_error()

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

Definition at line 164 of file msequencer.cxx.

164  {
165  int status;
166  HNDLE hKey;
167 
168  strlcpy(seq.error, str, sizeof(seq.error));
171  seq.running = FALSE;
173 
174  status = db_find_key(c->hDB, c->hSeq, "State", &hKey);
175  if (status != DB_SUCCESS)
176  return;
177  status = db_set_record(c->hDB, hKey, &seq, sizeof(seq), 0);
178  if (status != DB_SUCCESS)
179  return;
180 
181  cm_msg(MTALK, "sequencer", "Sequencer has stopped with error.");
182 }
#define MTALK
Definition: midas.h:570
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 1157 of file msequencer.cxx.

1157  {
1158  seq.new_file = FALSE;
1159  seq.error[0] = 0;
1160  seq.error_line = 0;
1161  seq.serror_line = 0;
1162  if (c->pnseq) {
1163  mxml_free_tree(c->pnseq);
1164  c->pnseq = NULL;
1165  }
1166  c->odbs->WS("Script/Lines", "");
1167 
1168  if (stristr(str, ".msl")) {
1169  int size = strlen(str) + 1;
1170  char *xml_filename = (char *) malloc(size);
1171  strlcpy(xml_filename, str, size);
1172  strsubst(xml_filename, size, ".msl", ".xml");
1173  //printf("Parsing MSL sequencer file: %s to XML sequencer file %s\n", str, xml_filename);
1174 
1175  std::string path(cm_get_path());
1176  path += "userfiles/sequencer/";
1177 
1178  if (xml_filename[0] == '/') {
1179  path += xml_filename;
1180  path = path.substr(0, path.find_last_of('/') + 1);
1181  strlcpy(xml_filename, path.substr(path.find_last_of('/') + 1).c_str(), size);
1182  } else {
1183  path += seq.path;
1184  }
1185 
1186  if (msl_parse(seq, c, 0, path.c_str(), str, xml_filename, seq.error, sizeof(seq.error), &seq.serror_line)) {
1187  //printf("Loading XML sequencer file: %s\n", xml_filename);
1188  std::string fn(path);
1189  if (fn.length() > 0 && fn.back() != '/')
1190  fn += '/';
1191  fn += xml_filename;
1192  c->pnseq = mxml_parse_file(fn.c_str(), seq.error, sizeof(seq.error), &seq.error_line);
1193  } else {
1194  //printf("Error in MSL sequencer file \"%s\" line %d, error: %s\n", str, seq.serror_line, seq.error);
1195  }
1196  free(xml_filename);
1197  } else {
1198  //printf("Loading XML sequencer file: %s\n", str);
1199  c->pnseq = mxml_parse_file(str, seq.error, sizeof(seq.error), &seq.error_line);
1200  }
1201 }
void strsubst(char *string, int size, const char *pattern, const char *subst)
Definition: msequencer.cxx:97
char * stristr(const char *str, const char *pattern)
Definition: msequencer.cxx:63
BOOL new_file
Definition: sequencer.h:8
Here is the call graph for this function:
Here is the caller graph for this function:

◆ seq_pause()

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

Definition at line 1140 of file msequencer.cxx.

1140  {
1141  seq_read(&seq, c);
1142  seq.paused = flag;
1143  if (!flag)
1144  seq.debug = false;
1145  seq_write(seq, c);
1146 }
BOOL debug
Definition: sequencer.h:21
Here is the call graph for this function:
Here is the caller graph for this function:

◆ seq_read()

void seq_read ( SEQUENCER seq,
SeqCon c 
)

Definition at line 977 of file msequencer.cxx.

977  {
978  int status;
979  HNDLE hKey;
980 
981  status = db_find_key(c->hDB, c->hSeq, "State", &hKey);
982  if (status != DB_SUCCESS) {
983  cm_msg(MERROR, "seq_read", "Cannot find /Sequencer/State in ODB, db_find_key() status %d", status);
984  return;
985  }
986 
987  int size = sizeof(SEQUENCER);
988  status = db_get_record1(c->hDB, hKey, seq, &size, 0, strcomb1(sequencer_str).c_str());
989  if (status != DB_SUCCESS) {
990  cm_msg(MERROR, "seq_read", "Cannot get /Sequencer/State from ODB, db_get_record1() status %d", status);
991  return;
992  }
993 }
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 1060 of file msequencer.cxx.

1060  {
1061  seq_read(&seq, c);
1062  seq_clear(seq);
1063 
1064  // manage sequencer parameters and variables
1065 
1066  midas::odb defaults(std::string("/") + c->odb_path + "/Param/Defaults");
1067  midas::odb param(std::string("/") + c->odb_path + "/Param/Value");
1068  midas::odb vars(std::string("/") + c->odb_path + "/Variables");
1069 
1070  // check if /Param/Value is there
1071  for (midas::odb& d: defaults)
1072  if (!param.is_subkey(d.get_name())) {
1073  strlcpy(seq.error, "Cannot start script because /Sequencer/Param/Value is incomplete", sizeof(seq.error));
1074  seq_write(seq, c);
1075  cm_msg(MERROR, "sequencer", "Cannot start script because /Sequencer/Param/Value is incomplete");
1076  return;
1077  }
1078 
1079  // copy /Sequencer/Param/Value to /Sequencer/Variables
1080  for (midas::odb& p: param)
1081  vars[p.get_name()] = p.s();
1082 
1083  if (!c->pnseq) {
1084  strlcpy(seq.error, "Cannot start script, no script loaded", sizeof(seq.error));
1085  seq_write(seq, c);
1086  return;
1087  }
1088 
1089  // start sequencer
1090  seq.running = TRUE;
1091  seq.debug = debug;
1092  seq.current_line_number = 1;
1093  seq.scurrent_line_number = 1;
1094  strlcpy(seq.sfilename, seq.filename, sizeof(seq.sfilename));
1095  seq_write(seq, c);
1096 
1097  if (debug)
1098  cm_msg(MTALK, "sequencer", "Sequencer started with script \"%s\" in debugging mode.", seq.filename);
1099  else
1100  cm_msg(MTALK, "sequencer", "Sequencer started with script \"%s\".", seq.filename);
1101 }
void seq_clear(SEQUENCER &seq)
BOOL debug
debug printouts
Definition: mana.cxx:254
double d
Definition: system.cxx:1317
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 1205 of file msequencer.cxx.

1205  {
1206  seq_read(&seq, c);
1207  if (seq.next_filename[0][0]) {
1208  strlcpy(seq.filename, seq.next_filename[0], sizeof(seq.filename));
1209  for (int i=0 ; i<9 ; i++)
1210  strlcpy(seq.next_filename[i], seq.next_filename[i+1], 256);
1211  seq.next_filename[9][0] = 0;
1212  seq_write(seq, c);
1213 
1214  seq_open_file(seq.filename, seq, c);
1215 
1216  seq_start(seq, c, false);
1217  }
1218 }
static void seq_start(SEQUENCER &seq, SeqCon *c, bool debug)
char next_filename[10][256]
Definition: sequencer.h:12
Here is the call graph for this function:
Here is the caller graph for this function:

◆ seq_step_over()

static void seq_step_over ( SEQUENCER seq,
SeqCon c 
)
static

Definition at line 1148 of file msequencer.cxx.

1148  {
1149  seq_read(&seq, c);
1150  seq.paused = false;
1151  seq.debug = true;
1152  seq_write(seq, c);
1153 }
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 1105 of file msequencer.cxx.

1105  {
1106  seq_read(&seq, c);
1107 
1108  if (seq.follow_libraries) {
1109  std::string path(cm_get_path());
1110  path += "userfiles/sequencer/";
1111  path += seq.path;
1112  path += seq.filename;
1113 
1114  loadMSL(c->odbs, seq.filename);
1115  }
1116 
1117  seq_clear(seq);
1118  seq.finished = TRUE;
1119  seq_write(seq, c);
1120 }
bool loadMSL(MVOdb *o, const std::string &filename)
Definition: msequencer.cxx:477
int follow_libraries
Definition: sequencer.h:24
Here is the call graph for this function:
Here is the caller graph for this function:

◆ seq_stop_after_run()

static void seq_stop_after_run ( SEQUENCER seq,
SeqCon c 
)
static

Definition at line 1124 of file msequencer.cxx.

1124  {
1125  seq_read(&seq, c);
1126  seq.stop_after_run = true;
1127  seq_write(seq, c);
1128 }
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 1222 of file msequencer.cxx.

1222  {
1223  char str[256];
1224  SeqCon* c = (SeqCon*)info;
1225 
1226  seq_read(c->seqp, c);
1227 
1228  if (c->seqp->new_file) {
1229  strlcpy(str, c->seqp->path, sizeof(str));
1230  if (strlen(str) > 1 && str[strlen(str) - 1] != DIR_SEPARATOR)
1231  strlcat(str, DIR_SEPARATOR_STR, sizeof(str));
1232  strlcat(str, c->seqp->filename, sizeof(str));
1233 
1234  //printf("Load file %s\n", str);
1235 
1236  seq_open_file(str, *(c->seqp), c);
1237 
1238  seq_clear(*(c->seqp));
1239 
1240  seq_write(*(c->seqp), c);
1241  }
1242 }
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 1244 of file msequencer.cxx.

1244  {
1245  SeqCon* c = (SeqCon*)info;
1246  SEQUENCER* seqp = c->seqp;
1247 
1248  bool start_script = false;
1249  bool stop_immediately = false;
1250  bool stop_after_run = false;
1251  bool cancel_stop_after_run = false;
1252  bool pause_script = false;
1253  bool resume_script = false;
1254  bool debug_script = false;
1255  bool step_over = false;
1256  bool load_new_file = false;
1257 
1258  c->odbs->RB("Command/Start script", &start_script);
1259  c->odbs->RB("Command/Stop immediately", &stop_immediately);
1260  c->odbs->RB("Command/Stop after run", &stop_after_run);
1261  c->odbs->RB("Command/Cancel stop after run", &cancel_stop_after_run);
1262  c->odbs->RB("Command/Pause script", &pause_script);
1263  c->odbs->RB("Command/Resume script", &resume_script);
1264  c->odbs->RB("Command/Debug script", &debug_script);
1265  c->odbs->RB("Command/Step over", &step_over);
1266  c->odbs->RB("Command/Load new file", &load_new_file);
1267 
1268  if (load_new_file) {
1269  std::string filename;
1270  c->odbs->RS("Command/Load filename", &filename);
1271 
1272  if (filename.find("..") != std::string::npos) {
1273  strlcpy(seqp->error, "Cannot load \"", sizeof(seqp->error));
1274  strlcat(seqp->error, filename.c_str(), sizeof(seqp->error));
1275  strlcat(seqp->error, "\": file names with \"..\" is not permitted", sizeof(seqp->error));
1276  seq_write(*seqp, c);
1277  } else if (filename.find(".msl") == std::string::npos) {
1278  strlcpy(seqp->error, "Cannot load \"", sizeof(seqp->error));
1279  strlcat(seqp->error, filename.c_str(), sizeof(seqp->error));
1280  strlcat(seqp->error, "\": file name should end with \".msl\"", sizeof(seqp->error));
1281  seq_write(*seqp, c);
1282  } else {
1283  strlcpy(seqp->filename, filename.c_str(), sizeof(seqp->filename));
1284  std::string path = cm_expand_env(seqp->path);
1285  if (path.length() > 0 && path.back() != '/') {
1286  path += "/";
1287  }
1288  HNDLE hDB;
1290  seq_clear(*seqp);
1291  seq_open_file(filename.c_str(), *seqp, c);
1292  seq_write(*seqp, c);
1293  }
1294 
1295  // indicate that we successfully load the new file
1296  c->odbs->WB("Command/Load new file", false);
1297  }
1298 
1299  if (start_script) {
1300  c->odbs->WB("Command/Start script", false);
1301 
1302  bool seq_running = false;
1303  c->odbs->RB("State/running", &seq_running);
1304 
1305  if (!seq_running) {
1306  seq_start(*seqp, c, false);
1307  } else {
1308  cm_msg(MTALK, "sequencer", "Sequencer is already running");
1309  }
1310  }
1311 
1312  if (stop_immediately) {
1313  c->odbs->WB("Command/Stop immediately", false);
1314  seq_stop(*seqp, c);
1315  cm_msg(MTALK, "sequencer", "Sequencer is finished by \"stop immediately\".");
1316  }
1317 
1318  if (stop_after_run) {
1319  c->odbs->WB("Command/Stop after run", false);
1320  seq_stop_after_run(*seqp, c);
1321  }
1322 
1323  if (cancel_stop_after_run) {
1324  c->odbs->WB("Command/Cancel stop after run", false);
1325  seq_cancel_stop_after_run(*seqp, c);
1326  }
1327 
1328  if (pause_script) {
1329  seq_pause(*seqp, c, true);
1330  c->odbs->WB("Command/Pause script", false);
1331  cm_msg(MTALK, "sequencer", "Sequencer is paused.");
1332  }
1333 
1334  if (resume_script) {
1335  seq_pause(*seqp, c, false);
1336  c->odbs->WB("Command/Resume script", false);
1337  cm_msg(MTALK, "sequencer", "Sequencer is resumed.");
1338  }
1339 
1340  if (debug_script) {
1341  c->odbs->WB("Command/Debug script", false);
1342 
1343  bool seq_running = false;
1344  c->odbs->RB("State/running", &seq_running);
1345 
1346  if (!seq_running) {
1347  seq_start(*seqp, c, true);
1348  } else {
1349  cm_msg(MTALK, "sequencer", "Sequencer is already running");
1350  }
1351  }
1352 
1353  if (step_over) {
1354  seq_step_over(*seqp, c);
1355  c->odbs->WB("Command/Step over", false);
1356  }
1357 }
std::string cm_expand_env(const char *str)
Definition: midas.cxx:7675
static void seq_stop_after_run(SEQUENCER &seq, SeqCon *c)
static void seq_stop(SEQUENCER &seq, SeqCon *c)
static void seq_step_over(SEQUENCER &seq, SeqCon *c)
static void seq_cancel_stop_after_run(SEQUENCER &seq, SeqCon *c)
static void seq_pause(SEQUENCER &seq, SeqCon *c, bool flag)
Here is the call graph for this function:
Here is the caller graph for this function:

◆ seq_write()

void seq_write ( const SEQUENCER seq,
SeqCon c 
)

Definition at line 995 of file msequencer.cxx.

995  {
996  int status;
997  HNDLE hKey;
998 
999  status = db_find_key(c->hDB, c->hSeq, "State", &hKey);
1000  if (status != DB_SUCCESS) {
1001  cm_msg(MERROR, "seq_write", "Cannot find /Sequencer/State in ODB, db_find_key() status %d", status);
1002  return;
1003  }
1004  status = db_set_record(c->hDB, hKey, (void *) &seq, sizeof(SEQUENCER), 0);
1005  if (status != DB_SUCCESS) {
1006  cm_msg(MERROR, "seq_write", "Cannot write to ODB /Sequencer/State, db_set_record() status %d", status);
1007  return;
1008  }
1009 }
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 1434 of file msequencer.cxx.

1434  {
1435  PMXML_NODE pn, pr, pt, pe;
1436  char odbpath[256], value[256], data[256], str[1024], name[32], op[32];
1437  char list[100][XNAME_LENGTH];
1438  int i, j, l, n, status, size, index1, index2, state, run_number, cont;
1439  HNDLE hKey, hKeySeq;
1440  KEY key;
1441  double d;
1442  BOOL skip_step = FALSE;
1443 
1444  if (!seq.running || seq.paused) {
1445  ss_sleep(10);
1446  return;
1447  }
1448 
1449  if (c->pnseq == NULL) {
1450  seq_stop(seq, c);
1451  strlcpy(seq.error, "No script loaded", sizeof(seq.error));
1452  seq_write(seq, c);
1453  ss_sleep(10);
1454  return;
1455  }
1456 
1457  db_find_key(c->hDB, c->hSeq, "State", &hKeySeq);
1458  if (!hKeySeq)
1459  return;
1460 
1461  // Retrieve last midas message and put it into seq structure (later sent to ODB via db_set_record()
1462  cm_msg_retrieve(1, str, sizeof(str));
1463  str[19] = 0;
1464  strcpy(seq.last_msg, str+11);
1465 
1466  pr = mxml_find_node(c->pnseq, "RunSequence");
1467  if (!pr) {
1468  seq_error(seq, c, "Cannot find &lt;RunSequence&gt; tag in XML file");
1469  return;
1470  }
1471 
1472  int last_line = mxml_get_line_number_end(pr);
1473 
1474  /* check for Subroutine end */
1475  if (seq.stack_index > 0 && seq.current_line_number == seq.subroutine_end_line[seq.stack_index - 1]) {
1476  size = sizeof(seq);
1477  db_get_record(c->hDB, hKeySeq, &seq, &size, 0);
1478  seq.subroutine_end_line[seq.stack_index - 1] = 0;
1480  seq.subroutine_return_line[seq.stack_index - 1] = 0;
1481  seq.subroutine_call_line[seq.stack_index - 1] = 0;
1482  seq.ssubroutine_call_line[seq.stack_index - 1] = 0;
1483  seq.stack_index--;
1484  db_set_record(c->hDB, hKeySeq, &seq, sizeof(seq), 0);
1485  return;
1486  }
1487 
1488  /* check for last line of script */
1489  if (seq.current_line_number > last_line) {
1490  seq_stop(seq, c);
1491  cm_msg(MTALK, "sequencer", "Sequencer is finished.");
1492 
1493  seq_start_next(seq, c);
1494  return;
1495  }
1496 
1497  /* check for loop end */
1498  for (i = SEQ_NEST_LEVEL_LOOP-1; i >= 0; i--)
1499  if (seq.loop_start_line[i] > 0)
1500  break;
1501  if (i >= 0) {
1502  if (seq.current_line_number == seq.loop_end_line[i]) {
1503  size = sizeof(seq);
1504  db_get_record(c->hDB, hKeySeq, &seq, &size, 0);
1505 
1506  if (seq.loop_counter[i] == seq.loop_n[i]) {
1507  seq.loop_counter[i] = 0;
1508  seq.loop_start_line[i] = 0;
1509  seq.sloop_start_line[i] = 0;
1510  seq.loop_end_line[i] = 0;
1511  seq.sloop_end_line[i] = 0;
1512  seq.loop_n[i] = 0;
1513  seq.current_line_number++;
1514  } else {
1515  pn = mxml_get_node_at_line(c->pnseq, seq.loop_start_line[i]);
1516  if (mxml_get_attribute(pn, "var")) {
1517  strlcpy(name, mxml_get_attribute(pn, "var"), sizeof(name));
1518  if (mxml_get_attribute(pn, "values")) {
1519  strlcpy(data, mxml_get_attribute(pn, "values"), sizeof(data));
1520  strbreak(data, list, 100, ",", FALSE);
1521  strlcpy(value, eval_var(seq, c, list[seq.loop_counter[i]]).c_str(), sizeof(value));
1522  } else if (mxml_get_attribute(pn, "n")) {
1523  sprintf(value, "%d", seq.loop_counter[i] + 1);
1524  }
1525  sprintf(str, "Variables/%s", name);
1526  size = strlen(value) + 1;
1527  if (size < 32)
1528  size = 32;
1529  db_set_value(c->hDB, c->hSeq, str, value, size, 1, TID_STRING);
1530  }
1531  seq.loop_counter[i]++;
1532  seq.current_line_number = seq.loop_start_line[i] + 1;
1533  }
1534  db_set_record(c->hDB, hKeySeq, &seq, sizeof(seq), 0);
1535  return;
1536  }
1537  }
1538 
1539  /* check for end of "if" statement */
1540  if (seq.if_index > 0 && seq.current_line_number == seq.if_endif_line[seq.if_index - 1]) {
1541  size = sizeof(seq);
1542  db_get_record(c->hDB, hKeySeq, &seq, &size, 0);
1543  seq.if_index--;
1544  seq.if_line[seq.if_index] = 0;
1545  seq.if_else_line[seq.if_index] = 0;
1546  seq.if_endif_line[seq.if_index] = 0;
1547  seq.current_line_number++;
1548  db_set_record(c->hDB, hKeySeq, &seq, sizeof(seq), 0);
1549  return;
1550  }
1551 
1552  /* check for ODBSubdir end */
1553  if (seq.current_line_number == seq.subdir_end_line) {
1554  size = sizeof(seq);
1555  db_get_record(c->hDB, hKeySeq, &seq, &size, 0);
1556  seq.subdir_end_line = 0;
1557  seq.subdir[0] = 0;
1558  seq.subdir_not_notify = FALSE;
1559  db_set_record(c->hDB, hKeySeq, &seq, sizeof(seq), 0);
1560  return;
1561  }
1562 
1563  /* find node belonging to current line */
1564  pn = mxml_get_node_at_line(c->pnseq, seq.current_line_number);
1565  if (!pn) {
1566  size = sizeof(seq);
1567  db_get_record(c->hDB, hKeySeq, &seq, &size, 0);
1568  seq.current_line_number++;
1569  db_set_record(c->hDB, hKeySeq, &seq, sizeof(seq), 0);
1570  return;
1571  }
1572 
1573  /* set MSL line from current element and put script into ODB if changed (library call) */
1574  pn = mxml_get_node_at_line(c->pnseq, seq.current_line_number);
1575  if (pn) {
1576  if (seq.follow_libraries) {
1577  if (mxml_get_attribute(pn, "l"))
1578  seq.scurrent_line_number = atoi(mxml_get_attribute(pn, "l"));
1579  if (mxml_get_attribute(pn, "fn")) {
1580  std::string filename = mxml_get_attribute(pn, "fn");
1581 
1582  // load file into ODB if changed
1583  if (filename != std::string(seq.sfilename)) {
1584  if (loadMSL(c->odbs, filename))
1585  strlcpy(seq.sfilename, filename.c_str(), sizeof(seq.sfilename));
1586  }
1587  }
1588  } else {
1589  if (mxml_get_attribute(pn, "l") && (!mxml_get_attribute(pn, "lvl") || atoi(mxml_get_attribute(pn, "lvl")) == 0))
1590  seq.scurrent_line_number = atoi(mxml_get_attribute(pn, "l"));
1591  }
1592  }
1593 
1594 
1595  // out-comment following lines for debug output
1596 #if 0
1597  if (seq.scurrent_line_number >= 0) {
1598  midas::odb o("/" + c->odb_path + "/Script/Lines");
1599  std::string s = o[seq.scurrent_line_number - 1];
1600  printf("%3d: %s\n", seq.scurrent_line_number, s.c_str());
1601  }
1602 #endif
1603 
1604  if (equal_ustring(mxml_get_name(pn), "PI") || equal_ustring(mxml_get_name(pn), "RunSequence") ||
1605  equal_ustring(mxml_get_name(pn), "Comment")) {
1606  // just skip
1607  seq.current_line_number++;
1608  skip_step = TRUE;
1609  }
1610 
1611  /*---- ODBSubdir ----*/
1612  else if (equal_ustring(mxml_get_name(pn), "ODBSubdir")) {
1613  if (!mxml_get_attribute(pn, "path")) {
1614  seq_error(seq, c, "Missing attribute \"path\"");
1615  } else {
1616  strlcpy(seq.subdir, mxml_get_attribute(pn, "path"), sizeof(seq.subdir));
1617  if (mxml_get_attribute(pn, "notify"))
1618  seq.subdir_not_notify = !atoi(mxml_get_attribute(pn, "notify"));
1619  seq.subdir_end_line = mxml_get_line_number_end(pn);
1620  seq.current_line_number++;
1621  }
1622  }
1623 
1624  /*---- ODBSet ----*/
1625  else if (equal_ustring(mxml_get_name(pn), "ODBSet")) {
1626  if (!mxml_get_attribute(pn, "path")) {
1627  seq_error(seq, c, "Missing attribute \"path\"");
1628  } else {
1629  strlcpy(odbpath, seq.subdir, sizeof(odbpath));
1630  if (strlen(odbpath) > 0 && odbpath[strlen(odbpath) - 1] != '/')
1631  strlcat(odbpath, "/", sizeof(odbpath));
1632  strlcat(odbpath, mxml_get_attribute(pn, "path"), sizeof(odbpath));
1633 
1634  if (strchr(odbpath, '$')) {
1635  if (strchr(odbpath, '[')) {
1636  // keep $ in index for later evaluation
1637  std::string s(odbpath);
1638  std::string s1 = s.substr(0, s.find('['));
1639  std::string s2 = s.substr(s.find('['));
1640  s1 = eval_var(seq, c, s1);
1641  s1 += s2;
1642  strlcpy(odbpath, s1.c_str(), sizeof(odbpath));
1643  } else {
1644  // evaluate variable in path
1645  std::string s(odbpath);
1646  s = eval_var(seq, c, s);
1647  strlcpy(odbpath, s.c_str(), sizeof(odbpath));
1648  }
1649  }
1650 
1651  int notify = TRUE;
1652  if (seq.subdir_not_notify)
1653  notify = FALSE;
1654  if (mxml_get_attribute(pn, "notify"))
1655  notify = atoi(mxml_get_attribute(pn, "notify"));
1656 
1657  index1 = index2 = 0;
1658  seq_array_index(seq, c, odbpath, &index1, &index2);
1659 
1660  strlcpy(value, eval_var(seq, c, mxml_get_value(pn)).c_str(), sizeof(value));
1661 
1662  status = set_all_matching(c->hDB, 0, odbpath, value, index1, index2, notify);
1663 
1664  if (status == DB_SUCCESS) {
1665  size = sizeof(seq);
1666  db_get_record1(c->hDB, hKeySeq, &seq, &size, 0, strcomb1(sequencer_str).c_str());// could have changed seq tree
1667  seq.current_line_number++;
1668  } else if (status == DB_NO_KEY) {
1669  sprintf(str, "ODB key \"%s\" not found", odbpath);
1670  seq_error(seq, c, str);
1671  } else {
1672  //something went really wrong
1673  sprintf(str, "Internal error %d", status);
1674  seq_error(seq, c, str);
1675  return;
1676  }
1677  }
1678  }
1679 
1680  /*---- ODBLoad ----*/
1681  else if (equal_ustring(mxml_get_name(pn), "ODBLoad")) {
1682  if (mxml_get_value(pn)[0] == '/') {
1683 
1684  // path relative to the one set in <exp>/userfiles/sequencer
1685  std::string path(cm_get_path());
1686  path += "userfiles/sequencer/";
1687  strlcpy(value, path.c_str(), sizeof(value));
1688  strlcat(value, mxml_get_value(pn)+1, sizeof(value));
1689 
1690  } else {
1691  // relative path to msl file
1692  std::string path(cm_get_path());
1693  path += "userfiles/sequencer/";
1694  path += seq.path;
1695  strlcpy(value, path.c_str(), sizeof(value));
1696  strlcat(value, seq.filename, sizeof(value));
1697  char *fullpath = strrchr(value, '/');
1698  if (fullpath)
1699  *(++fullpath) = '\0';
1700  strlcat(value, mxml_get_value(pn), sizeof(value));
1701  }
1702 
1703  // if path attribute is given
1704  if (mxml_get_attribute(pn, "path")) {
1705  strlcpy(odbpath, seq.subdir, sizeof(odbpath));
1706  if (strlen(odbpath) > 0 && odbpath[strlen(odbpath) - 1] != '/')
1707  strlcat(odbpath, "/", sizeof(odbpath));
1708  strlcat(odbpath, mxml_get_attribute(pn, "path"), sizeof(odbpath));
1709 
1710  if (strchr(odbpath, '$')) {
1711  std::string s(odbpath);
1712  s = eval_var(seq, c, s);
1713  strlcpy(odbpath, s.c_str(), sizeof(odbpath));
1714  }
1715 
1716  //load at that key, if exists
1717  status = db_find_key(c->hDB, 0, odbpath, &hKey);
1718  if (status != DB_SUCCESS) {
1719  char errorstr[512];
1720  sprintf(errorstr, "Cannot find ODB key \"%s\"", odbpath);
1721  seq_error(seq, c, errorstr);
1722  return;
1723  } else {
1724  status = db_load(c->hDB, hKey, value, FALSE);
1725  }
1726  } else {
1727  //otherwise load at root
1728  status = db_load(c->hDB, 0, value, FALSE);
1729  }
1730 
1731  if (status == DB_SUCCESS) {
1732  size = sizeof(seq);
1733  db_get_record1(c->hDB, hKeySeq, &seq, &size, 0, strcomb1(sequencer_str).c_str());// could have changed seq tree
1734  seq.current_line_number++;
1735  } else if (status == DB_FILE_ERROR) {
1736  sprintf(str, "Error reading file \"%s\"", value);
1737  seq_error(seq, c, str);
1738  } else {
1739  //something went really wrong
1740  seq_error(seq, c, "Internal error loading ODB file!");
1741  return;
1742  }
1743  }
1744 
1745  /*---- ODBSave ----*/
1746  else if (equal_ustring(mxml_get_name(pn), "ODBSave")) {
1747  if (mxml_get_value(pn)[0] == '/') {
1748 
1749  // path relative to the one set in <exp>/userfiles/sequencer
1750  std::string path(cm_get_path());
1751  path += "userfiles/sequencer/";
1752  strlcpy(value, path.c_str(), sizeof(value));
1753  strlcat(value, mxml_get_value(pn)+1, sizeof(value));
1754 
1755  } else {
1756  // relative path to msl file
1757  std::string path(cm_get_path());
1758  path += "userfiles/sequencer/";
1759  path += seq.path;
1760  strlcpy(value, path.c_str(), sizeof(value));
1761  strlcat(value, seq.filename, sizeof(value));
1762  char *fullpath = strrchr(value, '/');
1763  if (fullpath)
1764  *(++fullpath) = '\0';
1765  strlcat(value, mxml_get_value(pn), sizeof(value));
1766  }
1767 
1768  if (strchr(value, '$')) {
1769  std::string s(value);
1770  s = eval_var(seq, c, s);
1771  strlcpy(value, s.c_str(), sizeof(value));
1772  }
1773 
1774  // if path attribute is given
1775  if (mxml_get_attribute(pn, "path") && *mxml_get_attribute(pn, "path")) {
1776  strlcpy(odbpath, seq.subdir, sizeof(odbpath));
1777  if (strlen(odbpath) > 0 && odbpath[strlen(odbpath) - 1] != '/')
1778  strlcat(odbpath, "/", sizeof(odbpath));
1779  strlcat(odbpath, mxml_get_attribute(pn, "path"), sizeof(odbpath));
1780 
1781  if (strchr(odbpath, '$')) {
1782  std::string s(odbpath);
1783  s = eval_var(seq, c, s);
1784  strlcpy(odbpath, s.c_str(), sizeof(odbpath));
1785  }
1786 
1787  // find key or subdirectory to save
1788  status = db_find_key(c->hDB, 0, odbpath, &hKey);
1789  if (status != DB_SUCCESS) {
1790  char errorstr[512];
1791  sprintf(errorstr, "Cannot find ODB key \"%s\"", odbpath);
1792  seq_error(seq, c, errorstr);
1793  return;
1794  } else {
1795  if (strstr(value, ".json") || strstr(value, ".JSON") || strstr(value, ".js") || strstr(value, ".JS"))
1797  else if (strstr(value, ".xml") || strstr(value, ".XML"))
1798  status = db_save_xml(c->hDB, hKey, value);
1799  else
1800  status = db_save(c->hDB, hKey, value, FALSE);
1801  if (status != DB_SUCCESS) {
1802  char err[1024];
1803  sprintf(err, "Cannot save file \"%s\", error %d", value, status);
1804  seq_error(seq, c, err);
1805  return;
1806  }
1807  }
1808  } else {
1809  seq_error(seq, c, "No ODB path specified in ODBSAVE command");
1810  return;
1811  }
1812 
1813  if (status == DB_SUCCESS) {
1814  size = sizeof(seq);
1815  db_get_record1(c->hDB, hKeySeq, &seq, &size, 0, strcomb1(sequencer_str).c_str());// could have changed seq tree
1816  seq.current_line_number++;
1817  } else if (status == DB_FILE_ERROR) {
1818  sprintf(str, "Error reading file \"%s\"", value);
1819  seq_error(seq, c, str);
1820  } else {
1821  //something went really wrong
1822  seq_error(seq, c, "Internal error loading ODB file!");
1823  return;
1824  }
1825  }
1826 
1827  /*---- ODBGet ----*/
1828  else if (equal_ustring(mxml_get_name(pn), "ODBGet")) {
1829  if (!mxml_get_attribute(pn, "path")) {
1830  seq_error(seq, c, "Missing attribute \"path\"");
1831  } else {
1832  strlcpy(odbpath, seq.subdir, sizeof(odbpath));
1833  if (strlen(odbpath) > 0 && odbpath[strlen(odbpath) - 1] != '/')
1834  strlcat(odbpath, "/", sizeof(odbpath));
1835  strlcat(odbpath, mxml_get_attribute(pn, "path"), sizeof(odbpath));
1836 
1837  if (strchr(odbpath, '$')) {
1838  if (strchr(odbpath, '[')) {
1839  // keep $ in index for later evaluation
1840  std::string s(odbpath);
1841  std::string s1 = s.substr(0, s.find('['));
1842  std::string s2 = s.substr(s.find('['));
1843  s1 = eval_var(seq, c, s1);
1844  s1 += s2;
1845  strlcpy(odbpath, s1.c_str(), sizeof(odbpath));
1846  } else {
1847  // evaluate variable in path
1848  std::string s(odbpath);
1849  s = eval_var(seq, c, s);
1850  strlcpy(odbpath, s.c_str(), sizeof(odbpath));
1851  }
1852  }
1853 
1854  /* check if index is supplied */
1855  index1 = index2 = 0;
1856  seq_array_index(seq, c, odbpath, &index1, &index2);
1857 
1858  strlcpy(name, mxml_get_value(pn), sizeof(name));
1859  status = db_find_key(c->hDB, 0, odbpath, &hKey);
1860  if (status != DB_SUCCESS) {
1861  char errorstr[512];
1862  sprintf(errorstr, "Cannot find ODB key \"%s\"", odbpath);
1863  seq_error(seq, c, errorstr);
1864  return;
1865  } else {
1866  db_get_key(c->hDB, hKey, &key);
1867  size = sizeof(data);
1868 
1869  status = db_get_data_index(c->hDB, hKey, data, &size, index1, key.type);
1870  if (key.type == TID_BOOL)
1871  strlcpy(value, *((int *) data) > 0 ? "1" : "0", sizeof(value));
1872  else
1873  db_sprintf(value, data, size, 0, key.type);
1874 
1875  sprintf(str, "Variables/%s", name);
1876  size = strlen(value) + 1;
1877  if (size < 32)
1878  size = 32;
1879  db_set_value(c->hDB, c->hSeq, str, value, size, 1, TID_STRING);
1880 
1881  size = sizeof(seq);
1882  db_get_record1(c->hDB, hKeySeq, &seq, &size, 0, strcomb1(sequencer_str).c_str());// could have changed seq tree
1883  seq.current_line_number = mxml_get_line_number_end(pn) + 1;
1884  }
1885  }
1886  }
1887 
1888  /*---- ODBInc ----*/
1889  else if (equal_ustring(mxml_get_name(pn), "ODBInc")) {
1890  if (!mxml_get_attribute(pn, "path")) {
1891  seq_error(seq, c, "Missing attribute \"path\"");
1892  } else {
1893  strlcpy(odbpath, seq.subdir, sizeof(odbpath));
1894  if (strlen(odbpath) > 0 && odbpath[strlen(odbpath) - 1] != '/')
1895  strlcat(odbpath, "/", sizeof(odbpath));
1896  strlcat(odbpath, mxml_get_attribute(pn, "path"), sizeof(odbpath));
1897 
1898  if (strchr(odbpath, '$')) {
1899  if (strchr(odbpath, '[')) {
1900  // keep $ in index for later evaluation
1901  std::string s(odbpath);
1902  std::string s1 = s.substr(0, s.find('['));
1903  std::string s2 = s.substr(s.find('['));
1904  s1 = eval_var(seq, c, s1);
1905  s1 += s2;
1906  strlcpy(odbpath, s1.c_str(), sizeof(odbpath));
1907  } else {
1908  // evaluate variable in path
1909  std::string s(odbpath);
1910  s = eval_var(seq, c, s);
1911  strlcpy(odbpath, s.c_str(), sizeof(odbpath));
1912  }
1913  }
1914 
1915  index1 = index2 = 0;
1916  seq_array_index(seq, c, odbpath, &index1, &index2);
1917 
1918  strlcpy(value, eval_var(seq, c, mxml_get_value(pn)).c_str(), sizeof(value));
1919 
1920  status = db_find_key(c->hDB, 0, odbpath, &hKey);
1921  if (status != DB_SUCCESS) {
1922  char errorstr[512];
1923  sprintf(errorstr, "Cannot find ODB key \"%s\"", odbpath);
1924  seq_error(seq, c, errorstr);
1925  } else {
1926  db_get_key(c->hDB, hKey, &key);
1927  size = sizeof(data);
1928  db_get_data_index(c->hDB, hKey, data, &size, index1, key.type);
1929  db_sprintf(str, data, size, 0, key.type);
1930  d = atof(str);
1931  d += atof(value);
1932  sprintf(str, "%lg", d);
1933  size = sizeof(data);
1934  db_sscanf(str, data, &size, 0, key.type);
1935 
1936  int notify = TRUE;
1937  if (seq.subdir_not_notify)
1938  notify = FALSE;
1939  if (mxml_get_attribute(pn, "notify"))
1940  notify = atoi(mxml_get_attribute(pn, "notify"));
1941 
1942  db_set_data_index1(c->hDB, hKey, data, key.item_size, index1, key.type, notify);
1943  seq.current_line_number++;
1944  }
1945  }
1946  }
1947 
1948  /*---- ODBDelete ----*/
1949  else if (equal_ustring(mxml_get_name(pn), "ODBDelete")) {
1950  strlcpy(odbpath, seq.subdir, sizeof(odbpath));
1951  if (strlen(odbpath) > 0 && odbpath[strlen(odbpath) - 1] != '/')
1952  strlcat(odbpath, "/", sizeof(odbpath));
1953  strlcat(odbpath, mxml_get_value(pn), sizeof(odbpath));
1954 
1955  if (strchr(odbpath, '$')) {
1956  std::string s(odbpath);
1957  s = eval_var(seq, c, s);
1958  strlcpy(odbpath, s.c_str(), sizeof(odbpath));
1959  }
1960 
1961  status = db_find_key(c->hDB, 0, odbpath, &hKey);
1962  if (status != DB_SUCCESS) {
1963  char errorstr[512];
1964  sprintf(errorstr, "Cannot find ODB key \"%s\"", odbpath);
1965  seq_error(seq, c, errorstr);
1966  } else {
1967  status = db_delete_key(c->hDB, hKey, FALSE);
1968  if (status != DB_SUCCESS) {
1969  char errorstr[512];
1970  sprintf(errorstr, "Cannot delete ODB key \"%s\"", odbpath);
1971  seq_error(seq, c, errorstr);
1972  } else
1973  seq.current_line_number++;
1974  }
1975  }
1976 
1977  /*---- ODBCreate ----*/
1978  else if (equal_ustring(mxml_get_name(pn), "ODBCreate")) {
1979  if (!mxml_get_attribute(pn, "path")) {
1980  seq_error(seq, c, "Missing attribute \"path\"");
1981  } else if (!mxml_get_attribute(pn, "type")) {
1982  seq_error(seq, c, "Missing attribute \"type\"");
1983  } else {
1984  strlcpy(odbpath, seq.subdir, sizeof(odbpath));
1985  if (strlen(odbpath) > 0 && odbpath[strlen(odbpath) - 1] != '/')
1986  strlcat(odbpath, "/", sizeof(odbpath));
1987  strlcat(odbpath, mxml_get_attribute(pn, "path"), sizeof(odbpath));
1988 
1989  if (strchr(odbpath, '$')) {
1990  std::string s(odbpath);
1991  s = eval_var(seq, c, s);
1992  strlcpy(odbpath, s.c_str(), sizeof(odbpath));
1993  }
1994 
1995  /* get TID */
1996  unsigned int tid;
1997  for (tid = 0; tid < TID_LAST; tid++) {
1998  if (equal_ustring(rpc_tid_name(tid), mxml_get_attribute(pn, "type")))
1999  break;
2000  }
2001 
2002  if (tid == TID_LAST)
2003  seq_error(seq, c, "Type must be one of UINT8,INT8,UINT16,INT16,UINT32,INT32,BOOL,FLOAT,DOUBLE,STRING");
2004  else {
2005 
2006  status = db_find_key(c->hDB, 0, odbpath, &hKey);
2007  if (status == DB_SUCCESS) {
2008  db_get_key(c->hDB, hKey, &key);
2009  if (key.type != tid) {
2010  db_delete_key(c->hDB, hKey, FALSE);
2011  status = db_create_key(c->hDB, 0, odbpath, tid);
2012  }
2013  } else {
2014  status = db_create_key(c->hDB, 0, odbpath, tid);
2015  char dummy[32];
2016  memset(dummy, 0, sizeof(dummy));
2017  if (tid == TID_STRING || tid == TID_LINK)
2018  db_set_value(c->hDB, 0, odbpath, dummy, 32, 1, tid);
2019  }
2020 
2021  if (status != DB_SUCCESS && status != DB_CREATED) {
2022  char errorstr[512];
2023  sprintf(errorstr, "Cannot createODB key \"%s\", error code %d", odbpath, status);
2024  seq_error(seq, c, errorstr);
2025  } else {
2026  status = db_find_key(c->hDB, 0, odbpath, &hKey);
2027  if (mxml_get_attribute(pn, "size")) {
2028  i = atoi(eval_var(seq, c, mxml_get_attribute(pn, "size")).c_str());
2029  if (i > 1)
2030  db_set_num_values(c->hDB, hKey, i);
2031  }
2032  seq.current_line_number++;
2033  }
2034  }
2035  }
2036  }
2037 
2038  /*---- RunDescription ----*/
2039  else if (equal_ustring(mxml_get_name(pn), "RunDescription")) {
2040  db_set_value(c->hDB, 0, "/Experiment/Run Parameters/Run Description", mxml_get_value(pn), 256, 1, TID_STRING);
2041  seq.current_line_number++;
2042  }
2043 
2044  /*---- Script ----*/
2045  else if (equal_ustring(mxml_get_name(pn), "Script")) {
2046  sprintf(str, "%s", mxml_get_value(pn));
2047 
2048  if (mxml_get_attribute(pn, "params")) {
2049  strlcpy(data, mxml_get_attribute(pn, "params"), sizeof(data));
2050  n = strbreak(data, list, 100, ",", FALSE);
2051  for (i = 0; i < n; i++) {
2052 
2053  strlcpy(value, eval_var(seq, c, list[i]).c_str(), sizeof(value));
2054 
2055  strlcat(str, " ", sizeof(str));
2056  strlcat(str, value, sizeof(str));
2057  }
2058  }
2059 
2060  std::string s(str);
2061  s = ss_replace_env_variables(s);
2062  std::string r = ss_execs(s.c_str());
2063 
2064  // put result into SCRIPT_RESULT variable
2065  db_set_value(c->hDB, c->hSeq, "Variables/SCRIPT_RESULT", r.c_str(), r.length(), 1, TID_STRING);
2066 
2067  seq.current_line_number++;
2068  }
2069 
2070  /*---- Transition ----*/
2071  else if (equal_ustring(mxml_get_name(pn), "Transition")) {
2072  if (equal_ustring(mxml_get_value(pn), "Start")) {
2073  if (!seq.transition_request) {
2074  seq.transition_request = TRUE;
2075  size = sizeof(state);
2076  db_get_value(c->hDB, 0, "/Runinfo/State", &state, &size, TID_INT32, FALSE);
2077  if (state != STATE_RUNNING) {
2078  size = sizeof(run_number);
2079  db_get_value(c->hDB, 0, "/Runinfo/Run number", &run_number, &size, TID_INT32, FALSE);
2081  if (status != CM_SUCCESS) {
2082  char errorstr[1500];
2083  sprintf(errorstr, "Cannot start run: %s", str);
2084  seq_error(seq, c, errorstr);
2085  }
2086  }
2087  } else {
2088  // Wait until transition has finished
2089  size = sizeof(state);
2090  db_get_value(c->hDB, 0, "/Runinfo/State", &state, &size, TID_INT32, FALSE);
2091  if (state == STATE_RUNNING) {
2092  seq.transition_request = FALSE;
2093  seq.current_line_number++;
2094  }
2095  }
2096  } else if (equal_ustring(mxml_get_value(pn), "Stop")) {
2097  if (!seq.transition_request) {
2098  seq.transition_request = TRUE;
2099  size = sizeof(state);
2100  db_get_value(c->hDB, 0, "/Runinfo/State", &state, &size, TID_INT32, FALSE);
2101  if (state != STATE_STOPPED) {
2102  status = cm_transition(TR_STOP, 0, str, sizeof(str), TR_MTHREAD | TR_SYNC, FALSE);
2103  if (status == CM_DEFERRED_TRANSITION) {
2104  // do nothing
2105  } else if (status != CM_SUCCESS) {
2106  char errorstr[1500];
2107  sprintf(errorstr, "Cannot stop run: %s", str);
2108  seq_error(seq, c, errorstr);
2109  }
2110  }
2111  } else {
2112  // Wait until transition has finished
2113  size = sizeof(state);
2114  db_get_value(c->hDB, 0, "/Runinfo/State", &state, &size, TID_INT32, FALSE);
2115  if (state == STATE_STOPPED) {
2116  size = sizeof(seq);
2117  db_get_record(c->hDB, hKeySeq, &seq, &size, 0);
2118 
2119  seq.transition_request = FALSE;
2120 
2121  if (seq.stop_after_run) {
2122  seq.stop_after_run = FALSE;
2123  seq.running = FALSE;
2124  seq.finished = TRUE;
2125  seq_stop(seq, c);
2126  cm_msg(MTALK, "sequencer", "Sequencer is finished by \"stop after current run\".");
2127  } else {
2128  seq.current_line_number++;
2129  }
2130 
2131  db_set_record(c->hDB, hKeySeq, &seq, sizeof(seq), 0);
2132  }
2133  }
2134  } else {
2135  sprintf(str, "Invalid transition \"%s\"", mxml_get_value(pn));
2136  seq_error(seq, c, str);
2137  return;
2138  }
2139  }
2140 
2141  /*---- Wait ----*/
2142  else if (equal_ustring(mxml_get_name(pn), "Wait")) {
2143  if (equal_ustring(mxml_get_attribute(pn, "for"), "Events")) {
2144  n = atoi(eval_var(seq, c, mxml_get_value(pn)).c_str());
2145  seq.wait_limit = (float) n;
2146  strcpy(seq.wait_type, "Events");
2147  size = sizeof(d);
2148  db_get_value(c->hDB, 0, "/Equipment/Trigger/Statistics/Events sent", &d, &size, TID_DOUBLE, FALSE);
2149  seq.wait_value = (float) d;
2150  if (d >= n) {
2151  seq.current_line_number = mxml_get_line_number_end(pn) + 1;
2152  seq.wait_limit = 0;
2153  seq.wait_value = 0;
2154  seq.wait_type[0] = 0;
2155  seq.wait_odb[0] = 0;
2156  }
2157  seq.wait_value = (float) d;
2158  } else if (equal_ustring(mxml_get_attribute(pn, "for"), "ODBValue")) {
2159  seq.wait_limit = (float) atof(eval_var(seq, c, mxml_get_value(pn)).c_str());
2160  strlcpy(seq.wait_type, "ODB", sizeof(seq.wait_type));
2161  if (!mxml_get_attribute(pn, "path")) {
2162  seq_error(seq, c, "\"path\" must be given for ODB values");
2163  return;
2164  } else {
2165  strlcpy(odbpath, mxml_get_attribute(pn, "path"), sizeof(odbpath));
2166  strlcpy(seq.wait_odb, odbpath, sizeof(seq.wait_odb));
2167 
2168  if (strchr(odbpath, '$')) {
2169  if (strchr(odbpath, '[')) {
2170  // keep $ in index for later evaluation
2171  std::string s(odbpath);
2172  std::string s1 = s.substr(0, s.find('['));
2173  std::string s2 = s.substr(s.find('['));
2174  s1 = eval_var(seq, c, s1);
2175  s1 += s2;
2176  strlcpy(odbpath, s1.c_str(), sizeof(odbpath));
2177  } else {
2178  // evaluate variable in path
2179  std::string s(odbpath);
2180  s = eval_var(seq, c, s);
2181  strlcpy(odbpath, s.c_str(), sizeof(odbpath));
2182  }
2183  }
2184 
2185  index1 = index2 = 0;
2186  seq_array_index(seq, c, odbpath, &index1, &index2);
2187  status = db_find_key(c->hDB, 0, odbpath, &hKey);
2188  if (status != DB_SUCCESS) {
2189  char errorstr[512];
2190  sprintf(errorstr, "Cannot find ODB key \"%s\"", odbpath);
2191  seq_error(seq, c, errorstr);
2192  return;
2193  } else {
2194  if (mxml_get_attribute(pn, "op"))
2195  strlcpy(op, mxml_get_attribute(pn, "op"), sizeof(op));
2196  else
2197  strcpy(op, "!=");
2198  strlcat(seq.wait_type, op, sizeof(seq.wait_type));
2199 
2200  db_get_key(c->hDB, hKey, &key);
2201  size = sizeof(data);
2202  db_get_data_index(c->hDB, hKey, data, &size, index1, key.type);
2203  if (key.type == TID_BOOL)
2204  strlcpy(str, *((int *) data) > 0 ? "1" : "0", sizeof(str));
2205  else
2206  db_sprintf(str, data, size, 0, key.type);
2207  cont = FALSE;
2208  seq.wait_value = (float) atof(str);
2209  if (equal_ustring(op, ">=")) {
2210  cont = (seq.wait_value >= seq.wait_limit);
2211  } else if (equal_ustring(op, ">")) {
2212  cont = (seq.wait_value > seq.wait_limit);
2213  } else if (equal_ustring(op, "<=")) {
2214  cont = (seq.wait_value <= seq.wait_limit);
2215  } else if (equal_ustring(op, "<")) {
2216  cont = (seq.wait_value < seq.wait_limit);
2217  } else if (equal_ustring(op, "==")) {
2218  cont = (seq.wait_value == seq.wait_limit);
2219  } else if (equal_ustring(op, "!=")) {
2220  cont = (seq.wait_value != seq.wait_limit);
2221  } else {
2222  sprintf(str, "Invalid comaprison \"%s\"", op);
2223  seq_error(seq, c, str);
2224  return;
2225  }
2226 
2227  if (cont) {
2228  seq.current_line_number = mxml_get_line_number_end(pn) + 1;
2229  seq.wait_limit = 0;
2230  seq.wait_value = 0;
2231  seq.wait_type[0] = 0;
2232  seq.wait_odb[0] = 0;
2233  }
2234  }
2235  }
2236  } else if (equal_ustring(mxml_get_attribute(pn, "for"), "Seconds")) {
2237  seq.wait_limit = 1000.0f * (float) atof(eval_var(seq, c, mxml_get_value(pn)).c_str());
2238  strcpy(seq.wait_type, "Seconds");
2239  if (seq.start_time == 0) {
2240  seq.start_time = ss_millitime();
2241  seq.wait_value = 0;
2242  } else {
2243  seq.wait_value = (float) (ss_millitime() - seq.start_time);
2244  if (seq.wait_value > seq.wait_limit)
2245  seq.wait_value = seq.wait_limit;
2246  }
2247  if (ss_millitime() - seq.start_time > (DWORD) seq.wait_limit) {
2248  seq.current_line_number++;
2249  seq.start_time = 0;
2250  seq.wait_limit = 0;
2251  seq.wait_value = 0;
2252  seq.wait_type[0] = 0;
2253  seq.wait_odb[0] = 0;
2254  }
2255  } else {
2256  sprintf(str, "Invalid wait attribute \"%s\"", mxml_get_attribute(pn, "for"));
2257  seq_error(seq, c, str);
2258  }
2259 
2260  // sleep to keep the CPU from consuming 100%
2261  ss_sleep(100);
2262  }
2263 
2264  /*---- Loop start ----*/
2265  else if (equal_ustring(mxml_get_name(pn), "Loop")) {
2266  for (i = 0; i < SEQ_NEST_LEVEL_LOOP; i++)
2267  if (seq.loop_start_line[i] == 0)
2268  break;
2269  if (i == SEQ_NEST_LEVEL_LOOP) {
2270  seq_error(seq, c, "Maximum loop nesting exceeded");
2271  return;
2272  }
2274  seq.loop_end_line[i] = mxml_get_line_number_end(pn);
2275  if (mxml_get_attribute(pn, "l"))
2276  seq.sloop_start_line[i] = atoi(mxml_get_attribute(pn, "l"));
2277  if (mxml_get_attribute(pn, "le"))
2278  seq.sloop_end_line[i] = atoi(mxml_get_attribute(pn, "le"));
2279  seq.loop_counter[i] = 1;
2280 
2281  if (mxml_get_attribute(pn, "n")) {
2282  if (equal_ustring(mxml_get_attribute(pn, "n"), "infinite"))
2283  seq.loop_n[i] = -1;
2284  else {
2285  seq.loop_n[i] = atoi(eval_var(seq, c, mxml_get_attribute(pn, "n")).c_str());
2286  }
2287  strlcpy(value, "1", sizeof(value));
2288  } else if (mxml_get_attribute(pn, "values")) {
2289  strlcpy(data, mxml_get_attribute(pn, "values"), sizeof(data));
2290  seq.loop_n[i] = strbreak(data, list, 100, ",", FALSE);
2291  strlcpy(value, eval_var(seq, c, list[0]).c_str(), sizeof(value));
2292  } else {
2293  seq_error(seq, c, "Missing \"var\" or \"n\" attribute");
2294  return;
2295  }
2296 
2297  if (mxml_get_attribute(pn, "var")) {
2298  strlcpy(name, mxml_get_attribute(pn, "var"), sizeof(name));
2299  sprintf(str, "Variables/%s", name);
2300  size = strlen(value) + 1;
2301  if (size < 32)
2302  size = 32;
2303  db_set_value(c->hDB, c->hSeq, str, value, size, 1, TID_STRING);
2304  }
2305 
2306  seq.current_line_number++;
2307  }
2308 
2309  /*---- Break ----*/
2310  else if (equal_ustring(mxml_get_name(pn), "Break")) {
2311 
2312  // finish current if statement
2313  while (seq.if_index > 0 &&
2314  seq.current_line_number > seq.if_line[seq.if_index - 1] &&
2315  seq.current_line_number < seq.if_endif_line[seq.if_index-1]) {
2316  size = sizeof(seq);
2317  db_get_record(c->hDB, hKeySeq, &seq, &size, 0);
2318  seq.if_index--;
2319  seq.if_line[seq.if_index] = 0;
2320  seq.if_else_line[seq.if_index] = 0;
2321  seq.if_endif_line[seq.if_index] = 0;
2322  seq.current_line_number++;
2323  db_set_record(c->hDB, hKeySeq, &seq, sizeof(seq), 0);
2324  }
2325 
2326  // goto next loop end
2327  for (i = 0; i < SEQ_NEST_LEVEL_LOOP; i++)
2328  if (seq.loop_start_line[i] == 0)
2329  break;
2330  if (i == 0) {
2331  seq_error(seq, c, "\"Break\" outside any loop");
2332  return;
2333  }
2334 
2335  // force end of loop in next check
2336  seq.current_line_number = seq.loop_end_line[i-1];
2337  seq.loop_counter[i-1] = seq.loop_n[i-1];
2338  }
2339 
2340  /*---- If ----*/
2341  else if (equal_ustring(mxml_get_name(pn), "If")) {
2342 
2343  if (seq.if_index == SEQ_NEST_LEVEL_IF) {
2344  seq_error(seq, c, "Maximum number of nested if..endif exceeded");
2345  return;
2346  }
2347 
2348  // store "if" and "endif" lines
2349  seq.if_line[seq.if_index] = seq.current_line_number;
2350  seq.if_endif_line[seq.if_index] = mxml_get_line_number_end(pn);
2351 
2352  // search for "else" line
2353  seq.if_else_line[seq.if_index] = 0;
2354  for (j = seq.current_line_number + 1; j < mxml_get_line_number_end(pn) + 1; j++) {
2355  pe = mxml_get_node_at_line(c->pnseq, j);
2356 
2357  // skip nested if..endif
2358  if (pe && equal_ustring(mxml_get_name(pe), "If")) {
2359  j = mxml_get_line_number_end(pe);
2360  continue;
2361  }
2362 
2363  // store "else" if found
2364  if (pe && equal_ustring(mxml_get_name(pe), "Else")) {
2365  seq.if_else_line[seq.if_index] = j;
2366  break;
2367  }
2368  }
2369 
2370  strlcpy(str, mxml_get_attribute(pn, "condition"), sizeof(str));
2371  i = eval_condition(seq, c, str);
2372  if (i < 0) {
2373  seq_error(seq, c, "Invalid number in comparison");
2374  return;
2375  }
2376 
2377  if (i == 1)
2378  seq.current_line_number++;
2379  else if (seq.if_else_line[seq.if_index])
2380  seq.current_line_number = seq.if_else_line[seq.if_index] + 1;
2381  else
2383 
2384  seq.if_index++;
2385  }
2386 
2387  /*---- Else ----*/
2388  else if (equal_ustring(mxml_get_name(pn), "Else")) {
2389  // goto next "Endif"
2390  if (seq.if_index == 0) {
2391  seq_error(seq, c, "Unexpected Else");
2392  return;
2393  }
2394  seq.current_line_number = seq.if_endif_line[seq.if_index - 1];
2395  }
2396 
2397  /*---- Exit ----*/
2398  else if (equal_ustring(mxml_get_name(pn), "Exit")) {
2399  seq_stop(seq, c);
2400  cm_msg(MTALK, "sequencer", "Sequencer is finished.");
2401  return;
2402  }
2403 
2404  /*---- Goto ----*/
2405  else if (equal_ustring(mxml_get_name(pn), "Goto")) {
2406  if (!mxml_get_attribute(pn, "line") && !mxml_get_attribute(pn, "sline")) {
2407  seq_error(seq, c, "Missing line number");
2408  return;
2409  }
2410  if (mxml_get_attribute(pn, "line")) {
2411  seq.current_line_number = atoi(eval_var(seq, c, mxml_get_attribute(pn, "line")).c_str());
2412  }
2413  if (mxml_get_attribute(pn, "sline")) {
2414  strlcpy(str, eval_var(seq, c, mxml_get_attribute(pn, "sline")).c_str(), sizeof(str));
2415  for (i = 0; i < last_line; i++) {
2416  pt = mxml_get_node_at_line(c->pnseq, i);
2417  if (pt && mxml_get_attribute(pt, "l")) {
2418  l = atoi(mxml_get_attribute(pt, "l"));
2419  if (atoi(str) == l) {
2420  seq.current_line_number = i;
2421  break;
2422  }
2423  }
2424  }
2425  }
2426  }
2427 
2428  /*---- Library ----*/
2429  else if (equal_ustring(mxml_get_name(pn), "Library")) {
2430  // simply skip libraries
2431  seq.current_line_number = mxml_get_line_number_end(pn) + 1;
2432  }
2433 
2434  /*---- Subroutine ----*/
2435  else if (equal_ustring(mxml_get_name(pn), "Subroutine")) {
2436  // simply skip subroutines
2437  seq.current_line_number = mxml_get_line_number_end(pn) + 1;
2438  }
2439 
2440  /*---- Param ----*/
2441  else if (equal_ustring(mxml_get_name(pn), "Param")) {
2442  // simply skip parameters
2443  seq.current_line_number = mxml_get_line_number_end(pn) + 1;
2444  }
2445 
2446  /*---- Set ----*/
2447  else if (equal_ustring(mxml_get_name(pn), "Set")) {
2448  if (!mxml_get_attribute(pn, "name")) {
2449  seq_error(seq, c, "Missing variable name");
2450  return;
2451  }
2452  strlcpy(name, mxml_get_attribute(pn, "name"), sizeof(name));
2453  strlcpy(value, eval_var(seq, c, mxml_get_value(pn)).c_str(), sizeof(value));
2454 
2455  if (strchr(name, '[')) {
2456  // array
2457  strlcpy(str, strchr(name, '[')+1, sizeof(str));
2458  if (strchr(str, ']'))
2459  *strchr(str, ']') = 0;
2460  int index = atoi(eval_var(seq, c, str).c_str());
2461  *strchr(name, '[') = 0;
2462  sprintf(str, "Variables/%s", name);
2463  status = db_find_key(c->hDB, c->hSeq, str, &hKey);
2464  if (status != DB_SUCCESS) {
2465  db_create_key(c->hDB, c->hSeq, str, TID_STRING);
2466  status = db_find_key(c->hDB, c->hSeq, str, &hKey);
2467  }
2468  size = strlen(value) + 1;
2469  if (size < 32)
2470  size = 32;
2471  status = db_set_data_index(c->hDB, hKey, value, size, index, TID_STRING);
2472  } else {
2473  sprintf(str, "Variables/%s", name);
2474  size = strlen(value) + 1;
2475  if (size < 32)
2476  size = 32;
2477  db_set_value(c->hDB, c->hSeq, str, value, size, 1, TID_STRING);
2478  }
2479 
2480  // check if variable is used in loop
2481  for (i = SEQ_NEST_LEVEL_LOOP-1; i >= 0; i--)
2482  if (seq.loop_start_line[i] > 0) {
2483  pr = mxml_get_node_at_line(c->pnseq, seq.loop_start_line[i]);
2484  if (mxml_get_attribute(pr, "var")) {
2485  if (equal_ustring(mxml_get_attribute(pr, "var"), name))
2486  seq.loop_counter[i] = atoi(value);
2487  }
2488  }
2489 
2490  seq.current_line_number = mxml_get_line_number_end(pn) + 1;
2491  }
2492 
2493  /*---- Message ----*/
2494  else if (equal_ustring(mxml_get_name(pn), "Message")) {
2495  if (strchr(mxml_get_value(pn), '$')) // evaluate message string if $ present
2496  strlcpy(value, eval_var(seq, c, mxml_get_value(pn)).c_str(), sizeof(value));
2497  else
2498  strlcpy(value, mxml_get_value(pn), sizeof(value)); // treat message as string
2499  const char *wait_attr = mxml_get_attribute(pn, "wait");
2500  bool wait = false;
2501  if (wait_attr)
2502  wait = (atoi(wait_attr) == 1);
2503 
2504  if (!wait) {
2505  // message with no wait: set seq.message and move on. we do not care if web page clears it
2506  strlcpy(seq.message, value, sizeof(seq.message));
2507  seq.message_wait = FALSE;
2508  db_set_record(c->hDB, hKeySeq, &seq, sizeof(seq), 0);
2509  } else {
2510  // message with wait
2511 
2512  // if message_wait not set, we are here for the first time
2513  if (!seq.message_wait) {
2514  strlcpy(seq.message, value, sizeof(seq.message));
2515  seq.message_wait = TRUE;
2516  db_set_record(c->hDB, hKeySeq, &seq, sizeof(seq), 0);
2517  // wait
2518  return;
2519  } else {
2520  // message_wait is set, we have been here before
2521 
2522  // if web page did not clear the message, keep waiting
2523  if (seq.message[0] != 0) {
2524  // wait
2525  return;
2526  }
2527 
2528  // web page cleared the message, we are done with waiting
2529  seq.message_wait = false;
2530  }
2531  }
2532 
2533  seq.current_line_number = mxml_get_line_number_end(pn) + 1;
2534  }
2535 
2536  /*---- Msg ----*/
2537  else if (equal_ustring(mxml_get_name(pn), "Msg")) {
2538  if (strchr(mxml_get_value(pn), '$')) // evaluate message string if $ present
2539  strlcpy(value, eval_var(seq, c, mxml_get_value(pn)).c_str(), sizeof(value));
2540  else
2541  strlcpy(value, mxml_get_value(pn), sizeof(value)); // treat message as string
2542  std::string type = "INFO";
2543  if (mxml_get_attribute(pn, "type"))
2544  type = std::string(mxml_get_attribute(pn, "type"));
2545 
2546  if (type == "ERROR")
2547  cm_msg(MERROR, "sequencer", "%s", value);
2548  else if (type == "DEBUG")
2549  cm_msg(MDEBUG, "sequencer", "%s", value);
2550  else if (type == "LOG")
2551  cm_msg(MLOG, "sequencer", "%s", value);
2552  else if (type == "TALK")
2553  cm_msg(MTALK, "sequencer", "%s", value);
2554  else
2555  cm_msg(MINFO, "sequencer", "%s", value);
2556 
2557  seq.current_line_number = mxml_get_line_number_end(pn) + 1;
2558  }
2559 
2560  /*---- Cat ----*/
2561  else if (equal_ustring(mxml_get_name(pn), "Cat")) {
2562  if (!mxml_get_attribute(pn, "name")) {
2563  seq_error(seq, c, "Missing variable name");
2564  return;
2565  }
2566  strlcpy(name, mxml_get_attribute(pn, "name"), sizeof(name));
2567  if (!concatenate(seq, c, value, sizeof(value), mxml_get_value(pn)))
2568  return;
2569  sprintf(str, "Variables/%s", name);
2570  size = strlen(value) + 1;
2571  if (size < 32)
2572  size = 32;
2573  db_set_value(c->hDB, c->hSeq, str, value, size, 1, TID_STRING);
2574 
2575  seq.current_line_number = mxml_get_line_number_end(pn) + 1;
2576  }
2577 
2578  /*---- Call ----*/
2579  else if (equal_ustring(mxml_get_name(pn), "Call")) {
2580  if (seq.stack_index == SEQ_NEST_LEVEL_SUB) {
2581  seq_error(seq, c, "Maximum subroutine level exceeded");
2582  return;
2583  } else {
2584  // put current line number on stack
2585  seq.subroutine_call_line[seq.stack_index] = mxml_get_line_number_end(pn);
2586  seq.ssubroutine_call_line[seq.stack_index] = atoi(mxml_get_attribute(pn, "l"));
2587  seq.subroutine_return_line[seq.stack_index] = mxml_get_line_number_end(pn) + 1;
2588 
2589  // search subroutine
2590  for (i = 1; i < mxml_get_line_number_end(mxml_find_node(c->pnseq, "RunSequence")); i++) {
2591  pt = mxml_get_node_at_line(c->pnseq, i);
2592  if (pt) {
2593  if (equal_ustring(mxml_get_name(pt), "Subroutine")) {
2594  if (equal_ustring(mxml_get_attribute(pt, "name"), mxml_get_attribute(pn, "name"))) {
2595  // put routine end line on end stack
2596  seq.subroutine_end_line[seq.stack_index] = mxml_get_line_number_end(pt);
2597  // go to first line of subroutine
2598  seq.current_line_number = mxml_get_line_number_start(pt) + 1;
2599  // put parameter(s) on stack
2600  if (mxml_get_value(pn))
2601  strlcpy(seq.subroutine_param[seq.stack_index], mxml_get_value(pn), 256);
2602  // increment stack
2603  seq.stack_index++;
2604  break;
2605  }
2606  }
2607  }
2608  }
2609  if (i == mxml_get_line_number_end(mxml_find_node(c->pnseq, "RunSequence"))) {
2610  sprintf(str, "Subroutine '%s' not found", mxml_get_attribute(pn, "name"));
2611  seq_error(seq, c, str);
2612  }
2613  }
2614  }
2615 
2616  /*---- <unknown> ----*/
2617  else {
2618  sprintf(str, "Unknown statement \"%s\"", mxml_get_name(pn));
2619  seq_error(seq, c, str);
2620  }
2621 
2622  /* get steering parameters, since they might have been changed in between */
2623  SEQUENCER seq1;
2624  size = sizeof(seq1);
2625  db_get_record(c->hDB, hKeySeq, &seq1, &size, 0);
2626  seq.running = seq1.running;
2627  seq.finished = seq1.finished;
2628  seq.paused = seq1.paused;
2629  seq.debug = seq1.debug;
2630  seq.stop_after_run = seq1.stop_after_run;
2631  strlcpy(seq.message, seq1.message, sizeof(seq.message));
2632 
2633  // in debugging mode, pause after each step
2634  if (seq.debug && !skip_step)
2635  seq.paused = TRUE;
2636 
2637  /* update current line number */
2638  db_set_record(c->hDB, hKeySeq, &seq, sizeof(seq), 0);
2639 }
INT cm_transition(INT transition, INT run_number, char *errstr, INT errstr_size, INT async_flag, INT debug_flag)
Definition: midas.cxx:5282
#define CM_DEFERRED_TRANSITION
Definition: midas.h:597
#define DB_FILE_ERROR
Definition: midas.h:653
#define DB_NO_KEY
Definition: midas.h:648
#define DB_CREATED
Definition: midas.h:638
#define TID_DOUBLE
Definition: midas.h:350
#define TID_BOOL
Definition: midas.h:347
#define TR_START
Definition: midas.h:412
#define TR_SYNC
Definition: midas.h:365
#define TR_MTHREAD
Definition: midas.h:368
#define STATE_STOPPED
Definition: midas.h:312
#define MINFO
Definition: midas.h:566
#define MLOG
Definition: midas.h:569
#define TID_INT32
Definition: midas.h:346
#define TID_LINK
Definition: midas.h:357
#define TID_STRING
Definition: midas.h:353
#define STATE_RUNNING
Definition: midas.h:314
#define MDEBUG
Definition: midas.h:567
#define TR_STOP
Definition: midas.h:413
#define TID_LAST
Definition: midas.h:361
DWORD ss_millitime()
Definition: system.cxx:3332
std::string ss_execs(const char *cmd)
Definition: system.cxx:2208
std::string ss_replace_env_variables(const std::string &inputPath)
Definition: system.cxx:2183
INT ss_sleep(INT millisec)
Definition: system.cxx:3567
INT cm_msg_retrieve(INT n_message, char *message, INT buf_size)
Definition: midas.cxx:1336
INT db_get_data_index(HNDLE hDB, HNDLE hKey, void *data, INT *buf_size, INT idx, DWORD type)
Definition: odb.cxx:6885
INT db_delete_key(HNDLE hDB, HNDLE hKey, BOOL follow_links)
Definition: odb.cxx:3846
INT db_get_value(HNDLE hDB, HNDLE hKeyRoot, const char *key_name, void *data, INT *buf_size, DWORD type, BOOL create)
Definition: odb.cxx:5405
INT db_save_json(HNDLE hDB, HNDLE hKey, const char *filename, int flags)
Definition: odb.cxx:10531
INT db_save_xml(HNDLE hDB, HNDLE hKey, const char *filename)
Definition: odb.cxx:9483
INT db_create_key(HNDLE hDB, HNDLE hKey, const char *key_name, DWORD type)
Definition: odb.cxx:3298
INT db_get_record(HNDLE hDB, HNDLE hKey, void *data, INT *buf_size, INT align)
Definition: odb.cxx:11713
INT db_save(HNDLE hDB, HNDLE hKey, const char *filename, BOOL bRemote)
Definition: odb.cxx:9246
INT db_get_key(HNDLE hDB, HNDLE hKey, KEY *key)
Definition: odb.cxx:6009
INT db_load(HNDLE hDB, HNDLE hKeyRoot, const char *filename, BOOL bRemote)
Definition: odb.cxx:8120
INT db_set_data_index(HNDLE hDB, HNDLE hKey, const void *data, INT data_size, INT idx, DWORD type)
Definition: odb.cxx:7642
INT db_sprintf(char *string, const void *data, INT data_size, INT idx, DWORD type)
Definition: odb.cxx:10847
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:5251
INT db_set_data_index1(HNDLE hDB, HNDLE hKey, const void *data, INT data_size, INT idx, DWORD type, BOOL bNotify)
Definition: odb.cxx:7822
INT db_sscanf(const char *data_str, void *data, INT *data_size, INT i, DWORD tid)
Definition: odb.cxx:11318
INT db_set_num_values(HNDLE hDB, HNDLE hKey, INT num_values)
Definition: odb.cxx:7496
const char * rpc_tid_name(INT id)
Definition: midas.cxx:11731
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)
Definition: msequencer.cxx:368
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)
Definition: msequencer.cxx:385
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:37
#define DWORD
Definition: mhdump.cxx:31
#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:1032
DWORD type
Definition: midas.h:1033
INT item_size
Definition: midas.h:1038
int if_line[SEQ_NEST_LEVEL_IF]
Definition: sequencer.h:37
char last_msg[10]
Definition: sequencer.h:51
Definition: tinyexpr.c:70
struct state state
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 1386 of file msequencer.cxx.

1386  {
1387  int status, size;
1388  char data[256];
1389  KEY key;
1390 
1391  std::vector<HNDLE> keys;
1392  status = db_find_keys(hDB, hBaseKey, odbpath, keys);
1393 
1394  if (status != DB_SUCCESS)
1395  return status;
1396 
1397  for (HNDLE hKey: keys) {
1398  db_get_key(hDB, hKey, &key);
1399  size = sizeof(data);
1400  db_sscanf(value, data, &size, 0, key.type);
1401 
1402  /* extend data size for single string if necessary */
1403  if ((key.type == TID_STRING || key.type == TID_LINK)
1404  && (int) strlen(data) + 1 > key.item_size && key.num_values == 1)
1405  key.item_size = strlen(data) + 1;
1406 
1407  if (key.num_values > 1 && index1 == -1) {
1408  for (int i = 0; i < key.num_values; i++)
1410  } else if (key.num_values > 1 && index2 > index1) {
1411  for (int i = index1; i < key.num_values && i <= index2; i++)
1413  } else {
1414  if (key.num_values > 1) {
1415  status = db_set_data_index1(hDB, hKey, data, key.item_size, index1, key.type, notify);
1416  } else {
1417  if (notify)
1419  else
1421  }
1422  }
1423 
1424  if (status != DB_SUCCESS) {
1425  return status;
1426  }
1427  }
1428 
1429  return DB_SUCCESS;
1430 }
INT db_find_keys(HNDLE hDB, HNDLE hKeyRoot, char *odbpath, std::vector< HNDLE > &hKeyVector)
Definition: odb.cxx:4576
INT db_set_data(HNDLE hDB, HNDLE hKey, const void *data, INT buf_size, INT num_values, DWORD type)
Definition: odb.cxx:7209
INT db_set_data1(HNDLE hDB, HNDLE hKey, const void *data, INT buf_size, INT num_values, DWORD type)
Definition: odb.cxx:7307
INT num_values
Definition: midas.h:1034
Here is the call graph for this function:
Here is the caller graph for this function:

◆ strbreak()

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

Definition at line 186 of file msequencer.cxx.

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

◆ stristr()

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

Definition at line 63 of file msequencer.cxx.

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

◆ strsubst()

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

Definition at line 97 of file msequencer.cxx.

99 {
100  char *tail, *p;
101  int s;
102 
103  p = string;
104  for (p = stristr(p, pattern); p != NULL; p = stristr(p, pattern)) {
105 
106  if (strlen(pattern) == strlen(subst)) {
107  memcpy(p, subst, strlen(subst));
108  } else if (strlen(pattern) > strlen(subst)) {
109  memcpy(p, subst, strlen(subst));
110  memmove(p + strlen(subst), p + strlen(pattern), strlen(p + strlen(pattern)) + 1);
111  } else {
112  tail = (char *) malloc(strlen(p) - strlen(pattern) + 1);
113  strcpy(tail, p + strlen(pattern));
114  s = size - (p - string);
115  strlcpy(p, subst, s);
116  strlcat(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  sprintf(buf, "%d", v);
130  return buf;
131 }

Variable Documentation

◆ gOdb

MVOdb* gOdb = NULL

Definition at line 44 of file msequencer.cxx.