25#define XNAME_LENGTH 256
64 char c1, c2, *ps, *pp;
66 if (
str == NULL || pattern == NULL)
71 pp = (
char *) pattern;
74 if (toupper(c1) == toupper(c2)) {
79 if (toupper(c1) != toupper(c2))
97void strsubst(
char *
string,
int size,
const char *pattern,
const char *subst)
104 for (p =
stristr(p, pattern); p != NULL; p =
stristr(p, pattern)) {
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);
112 tail = (
char *) malloc(strlen(p) - strlen(pattern) + 1);
113 strcpy(tail, p + strlen(pattern));
114 s = size - (p - string);
115 mstrlcpy(p, subst, s);
116 mstrlcat(p, tail, s);
129 snprintf(buf,
sizeof(buf),
"%d", v);
133static std::string
qtoString(std::string filename,
int line,
int level) {
134 std::string buf =
"l=\"" + std::to_string(line) +
"\"";
135 buf +=
" fn=\"" + filename +
"\"";
137 buf +=
" lvl=\"" + std::to_string(level) +
"\"";
141static std::string
q(
const char *s) {
142 return "\"" + std::string(s) +
"\"";
149 std::stringstream ss;
155 else if (num == 0 && s[0] !=
'0')
181 cm_msg(
MTALK,
"sequencer",
"Sequencer has stopped with error.");
201 for (
i = 0; *p &&
i < size;
i++) {
202 if (*p ==
'"' && !ignore_quotes) {
208 if (*p ==
'"' && *(p + 1) ==
'"') {
211 }
else if (*p ==
'"') {
225 if (*p && strchr(brk, *p))
233 for (
j = 0;
j < (int) strlen(
list[
i]);
j++)
234 if (strchr(brk,
list[
i][
j])) {
239 p += strlen(
list[
i]);
242 if (*p && strchr(brk, *p))
263extern char *
stristr(
const char *
str,
const char *pattern);
271 xpath +=
c->odb_path;
280 while ((i1 = (
int)result.find(
"$")) != (
int)std::string::npos) {
281 std::string s = result.substr(i1 + 1);
282 if (std::isdigit(s[0])) {
284 for (i2 = i1 + 1; std::isdigit(result[i2]);)
288 int index = atoi(s.c_str());
291 std::vector<std::string>
param;
293 while (std::getline(f, sp,
','))
296 throw "Parameter \"$" + std::to_string(
index) +
"\" not valid";
298 if (vsubst[0] ==
'$')
301 throw "Parameter \"$" + std::to_string(
index) +
"\" not valid";
304 for (i2 = i1 + 1; std::isalnum(result[i2]) || result[i2] ==
'_';)
306 s = s.substr(0, i2 - i1 - 1);
307 if (result[i2] ==
'[') {
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);
317 index = std::stoi(sindex);
319 throw "Variable \"" + s +
"\" has invalid index";
324 std::vector<std::string> sv = o;
327 throw "Variable \"" + s +
"\" not found";
329 while (result[i2] && result[i2] !=
']')
332 throw "Variable \"" + result +
"\" does not contain ']'";
333 if (result[i2] ==
']')
338 throw "Variable \"" + s +
"\" not found";
342 throw "Variable \"" + s +
"\" not found";
347 result = result.substr(0, i1) + vsubst + result.substr(i2);
353 if (result.find(
",") != std::string::npos)
358 double r =
te_interp(result.c_str(), &error);
361 if (!std::isdigit(result[0]) && result[0] !=
'-')
364 throw "Error in expression \"" + result +
"\" position " + std::to_string(error - 1);
368 return std::to_string((
int) r);
370 return std::to_string(r);
382 for (
i = 0;
i <
n;
i++) {
384 mstrlcat(result,
str.c_str(), size);
394 double value1, value2;
395 char value1_str[256], value2_str[256],
str[256], op[3], *p;
396 std::string value1_var, value2_var;
399 p = (
char *)condition;
405 if (strchr(
str,
'#'))
406 *strchr(
str,
'#') = 0;
408 while (strlen(
str) > 0 && (
str[strlen(
str)-1] ==
' '))
412 if (
str[0] ==
'(' && strlen(
str) > 0 &&
str[strlen(
str)-1] ==
')') {
413 mstrlcpy(value1_str,
str+1,
sizeof(value1_str));
414 mstrlcpy(
str, value1_str,
sizeof(
str));
421 for (
i = 0;
i < (int) strlen(
str);
i++)
422 if (strchr(
"<>=!&",
str[
i]) != NULL)
424 mstrlcpy(value1_str,
str,
i + 1);
425 while (value1_str[strlen(value1_str) - 1] ==
' ')
426 value1_str[strlen(value1_str) - 1] = 0;
428 if (strchr(
"<>=!&",
str[
i + 1]) != NULL)
431 for (
i++;
str[
i] ==
' ';
i++);
432 mstrlcpy(value2_str,
str +
i,
sizeof(value2_str));
434 value1_var =
eval_var(seq,
c, value1_str);
435 value2_var =
eval_var(seq,
c, value2_str);
439 if (strcmp(op,
"=") == 0)
440 return equal_ustring(value1_var.c_str(), value2_var.c_str()) ? 1 : 0;
441 if (strcmp(op,
"==") == 0)
442 return equal_ustring(value1_var.c_str(), value2_var.c_str()) ? 1 : 0;
443 if (strcmp(op,
"!=") == 0)
444 return equal_ustring(value1_var.c_str(), value2_var.c_str()) ? 0 : 1;
450 value1 = atof(value1_var.c_str());
451 value2 = atof(value2_var.c_str());
454 if (strcmp(op,
"=") == 0)
455 if (value1 == value2)
457 if (strcmp(op,
"==") == 0)
458 if (value1 == value2)
460 if (strcmp(op,
"!=") == 0)
461 if (value1 != value2)
463 if (strcmp(op,
"<") == 0)
466 if (strcmp(op,
">") == 0)
469 if (strcmp(op,
"<=") == 0)
470 if (value1 <= value2)
472 if (strcmp(op,
">=") == 0)
473 if (value1 >= value2)
475 if (strcmp(op,
"&") == 0)
476 if (((
unsigned int) value1 & (
unsigned int) value2) > 0)
484bool loadMSL(MVOdb *o,
const std::string &filename) {
486 std::ifstream
file(filename);
490 std::vector<std::string> lines;
494 while (std::getline(
file, line))
495 lines.push_back(line);
498 o->WSA(
"Script/Lines", lines, 0);
506 char *error,
int error_size,
int *error_line) {
507 char str[256], *pl, *pe;
509 int i,
j,
n, nq, n_lines, endl, line, nest, incl, library;
510 std::string xml, path, fn;
511 char *msl_include, *xml_include, *include_error;
512 int include_error_size;
513 BOOL include_status, rel_path;
516 snprintf(error, error_size,
"More than 10 nested INCLUDE statements exceeded in file \"%s\"", filename);
521 path = std::string(cpath);
522 if (path.length() > 0 && path.back() !=
'/')
525 std::string fullFilename;
527 fullFilename = path + filename;
529 fullFilename = filename;
531 int fhin = open(fullFilename.c_str(), O_RDONLY |
O_TEXT);
533 snprintf(error, error_size,
"Cannot open \"%s\", errno %d (%s)", fullFilename.c_str(), errno, strerror(errno));
537 off_t off = lseek(fhin, 0, SEEK_END);
539 snprintf(error, error_size,
"Cannot find size of \"%s\", lseek(SEEK_END) errno %d (%s)", fullFilename.c_str(), errno, strerror(errno));
544 lseek(fhin, 0, SEEK_SET);
548 s = path + xml_filename;
552 FILE *fout = fopen(s.c_str(),
"wt");
554 snprintf(error, error_size,
"Cannot write to \"%s\", fopen() errno %d (%s)", s.c_str(), errno, strerror(errno));
561 char* buf = (
char *) malloc(size + 1);
562 ssize_t rd =
read(fhin, buf, size);
565 snprintf(error, error_size,
"Cannot read \"%s\", read(%zu) errno %d (%s)", fullFilename.c_str(), size, errno, strerror(errno));
575 lines = (
char **) malloc(
sizeof(
char *));
579 for (n_lines = 0; *pl; n_lines++) {
580 lines = (
char **) realloc(lines,
sizeof(
char *) * (n_lines + 1));
582 if (strchr(pl,
'\n')) {
583 pe = strchr(pl,
'\n');
585 if (*(pe - 1) ==
'\r') {
590 pe = pl + strlen(pl);
591 mstrlcpy(
str, pl,
sizeof(
str));
596 xml +=
"<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>\n";
597 xml +=
"<!DOCTYPE RunSequence [\n";
602 char *reference = strrchr(
list[1],
'/');
608 if (strchr(reference,
'.') && !strstr(reference,
".msl") && !strstr(reference,
".MSL")) {
609 snprintf(error, error_size,
"Include file \"%s\" cannot have an extension other than .msl", reference);
614 if (
list[1][0] ==
'/') {
616 p +=
"userfiles/sequencer";
620 if (!p.empty() && p.back() !=
'/')
632 size = p.length() + 1 + 4;
633 msl_include = (
char *) malloc(size);
634 xml_include = (
char *) malloc(size);
635 mstrlcpy(msl_include, p.c_str(), size);
636 mstrlcpy(xml_include, p.c_str(), size);
637 if (!strstr(msl_include,
".msl"))
638 mstrlcat(msl_include,
".msl", size);
639 mstrlcat(xml_include,
".xml", size);
641 include_error = error + strlen(error);
642 include_error_size = error_size - strlen(error);
645 path +=
"userfiles/sequencer/";
648 include_status =
msl_parse(seq,
c, level+1, path.c_str(), msl_include, xml_include, include_error, include_error_size, error_line);
652 if (!include_status) {
654 *error_line = n_lines + 1;
659 xml +=
"<Library name=\"";
667 }
else if (!library) {
668 xml +=
"<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>\n";
673 xml +=
"<RunSequence xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:noNamespaceSchemaLocation=\"\">\n";
676 std::vector<std::string> slines;
677 for (line = 0; line < n_lines; line++) {
678 slines.push_back(lines[line]);
681 c->odbs->WSA(
"Script/Lines", slines, 0);
684 std::string p =
"/" +
c->odb_path +
"/Param/Value";
691 c->odbs->Delete(
"Variables");
692 c->odbs->Delete(
"Param");
695 for (line = 0; line < n_lines; line++) {
696 char *p = lines[line];
699 mstrlcpy(
list[0], p,
sizeof(
list[0]));
700 if (strchr(
list[0],
' '))
701 *strchr(
list[0],
' ') = 0;
702 p += strlen(
list[0]);
706 for (
i = 0;
i <
n;
i++) {
707 if (
list[
i][0] ==
'#') {
708 for (
j =
i;
j <
n;
j++)
715 for (
i = 0;
i <
n;
i++) {
716 if (strchr(
list[
i],
'#'))
717 *strchr(
list[
i],
'#') = 0;
721 for (
i = 0;
i <
n;
i++) {
728 mstrlcpy(
eq, lines[line],
sizeof(
eq));
730 *strchr(
eq,
'#') = 0;
731 for (
i = 0,
n = 0, nq = 0;
i < (int)strlen(
eq);
i++) {
733 nq = (nq == 0 ? 1 : 0);
734 if (
eq[
i] ==
'=' && nq == 0 &&
735 (
i > 0 && (
eq[
i - 1] !=
'!') &&
eq[
i - 1] !=
'<' &&
eq[
i - 1] !=
'>'))
738 if (
n == 1 &&
eq[0] !=
'=') {
740 mstrlcpy(
list[0],
"SET",
sizeof(
list[0]));
744 mstrlcpy(
list[1], p,
sizeof(
list[1]));
745 *strchr(
list[1],
'=') = 0;
746 if (strchr(
list[1],
' '))
747 *strchr(
list[1],
' ') = 0;
748 p = strchr(
eq,
'=')+1;
751 mstrlcpy(
list[2], p,
sizeof(
list[2]));
752 while (strlen(
list[2]) > 0 &&
list[2][strlen(
list[2])-1] ==
' ')
760 char *reference = strrchr(
list[1],
'/');
771 xml +=
"<Call " +
qtoString(fullFilename, line + 1, level) +
" name=" +
q(
list[1]) +
">";
772 for (
i = 2;
i < 100 &&
list[
i][0];
i++) {
781 xml +=
"<Cat " +
qtoString(fullFilename, line + 1, level) +
" name=" +
q(
list[1]) +
">";
782 for (
i = 2;
i < 100 &&
list[
i][0];
i++) {
791 xml +=
"<Comment " +
qtoString(fullFilename, line + 1, level) +
">" +
list[1] +
"</Comment>\n";
794 xml +=
"<Exit " +
qtoString(fullFilename, line + 1, level) +
" />\n";
797 xml +=
"<Goto " +
qtoString(fullFilename, line + 1, level) +
" sline=" +
q(
list[1]) +
" />\n";
800 xml +=
"<If " +
qtoString(fullFilename, line + 1, level) +
" condition=\"";
801 for (
i = 1;
i < 100 &&
list[
i][0] && stricmp(
list[
i],
"THEN") != 0;
i++) {
814 for (
i = line, nest = 0;
i < n_lines;
i++) {
828 if (
list[2][0] == 0) {
829 xml +=
"<Loop " +
qtoString(fullFilename, line + 1, level) +
" le=\"" + std::to_string(endl) +
"\" n=" +
q(
list[1]) +
">\n";
830 }
else if (
list[3][0] == 0) {
831 xml +=
"<Loop " +
qtoString(fullFilename, line + 1, level) +
" le=\"" + std::to_string(endl) +
"\" var=" +
q(
list[1]) +
" n=" +
834 xml +=
"<Loop " +
qtoString(fullFilename, line + 1, level) +
" le=\"" + std::to_string(endl) +
"\" var=" +
q(
list[1]) +
" values=\"";
835 for (
i = 2;
i < 100 &&
list[
i][0];
i++) {
847 xml +=
"<Break "+
qtoString(fullFilename, line + 1, level) +
"></Break>\n";
850 xml +=
"<Message " +
qtoString(fullFilename, line + 1, level);
851 if (
list[2][0] ==
'1')
852 xml +=
" wait=\"1\"";
855 xml +=
"</Message>\n";
859 xml +=
"<Msg " +
qtoString(fullFilename, line + 1, level) +
" type=\""+
list[2]+
"\">" +
list[1] +
"</Msg>\n";
861 xml +=
"<Msg " +
qtoString(fullFilename, line + 1, level) +
">" +
list[1] +
"</Msg>\n";
866 mstrlcpy(
list[2],
"1", 2);
867 xml +=
"<ODBInc " +
qtoString(fullFilename, line + 1, level) +
" path=" +
q(
list[1]) +
">" +
list[2] +
"</ODBInc>\n";
871 xml +=
"<ODBCreate " +
qtoString(fullFilename, line + 1, level) +
" size=" +
q(
list[3]) +
" path=" +
q(
list[1]) +
" type=" +
872 q(
list[2]) +
"></ODBCreate>\n";
874 xml +=
"<ODBCreate " +
qtoString(fullFilename, line + 1, level) +
" path=" +
q(
list[1]) +
" type=" +
q(
list[2]) +
879 xml +=
"<ODBDelete " +
qtoString(fullFilename, line + 1, level) +
">" +
list[1] +
"</ODBDelete>\n";
883 xml +=
"<ODBSet " +
qtoString(fullFilename, line + 1, level) +
" notify=" +
q(
list[3]) +
" path=" +
q(
list[1]) +
">" +
884 list[2] +
"</ODBSet>\n";
886 xml +=
"<ODBSet " +
qtoString(fullFilename, line + 1, level) +
" path=" +
q(
list[1]) +
">" +
list[2] +
"</ODBSet>\n";
891 xml +=
"<ODBLoad " +
qtoString(fullFilename, line + 1, level) +
" path=" +
q(
list[2]) +
">" +
list[1] +
"</ODBLoad>\n";
893 xml +=
"<ODBLoad " +
qtoString(fullFilename, line + 1, level) +
">" +
list[1] +
"</ODBLoad>\n";
897 xml +=
"<ODBGet " +
qtoString(fullFilename, line + 1, level) +
" path=" +
q(
list[1]) +
">" +
list[2] +
"</ODBGet>\n";
900 xml +=
"<ODBLookup " +
qtoString(fullFilename, line + 1, level) +
" path=" +
q(
list[1]) +
901 " string=" +
q(
list[2]) +
">" +
list[3] +
"</ODBLookup>\n";
904 xml +=
"<ODBSave " +
qtoString(fullFilename, line + 1, level) +
" path=" +
q(
list[1]) +
">" +
list[2] +
"</ODBSave>\n";
908 xml +=
"<ODBSubdir " +
qtoString(fullFilename, line + 1, level) +
" notify=" +
q(
list[2]) +
" path=" +
q(
list[1]) +
">\n";
910 xml +=
"<ODBSubdir " +
qtoString(fullFilename, line + 1, level) +
" path=" +
q(
list[1]) +
">\n";
913 xml +=
"</ODBSubdir>\n";
917 snprintf(error, error_size,
"Parameter \"%s\" misses 'comment'",
list[1]);
918 *error_line = line + 1;
922 xml +=
"<Param " +
qtoString(fullFilename, line + 1, level) +
" name=" +
q(
list[1]) +
" type=\"bool\" " +
" comment=" +
q(
list[2]) +
"/>\n";
924 c->odbs->RB((std::string(
"Param/Value/") +
list[1]).c_str(), &v,
true);
925 c->odbs->WS((std::string(
"Param/Comment/") +
list[1]).c_str(),
list[2]);
927 xml +=
"<Param " +
qtoString(fullFilename, line + 1, level) +
" name=" +
q(
list[1]) +
" type=\"bool\" default=" +
q(
list[4]) +
"/>\n";
928 std::string def(
list[3]);
929 bool v(def ==
"1" || def ==
"true" || def ==
"TRUE");
930 c->odbs->RB((std::string(
"Param/Value/") +
list[1]).c_str(), &v,
true);
931 c->odbs->WS((std::string(
"Param/Comment/") +
list[1]).c_str(),
list[2]);
932 c->odbs->WS((std::string(
"Param/Defaults/") +
list[1]).c_str(),
list[3]);
934 }
else if (!
list[3][0]) {
935 xml +=
"<Param " +
qtoString(fullFilename, line + 1, level) +
" name=" +
q(
list[1]) +
" comment=" +
q(
list[2]) +
" />\n";
937 c->odbs->RS((std::string(
"Param/Value/") +
list[1]).c_str(), &v,
true);
938 c->odbs->WS((std::string(
"Param/Comment/") +
list[1]).c_str(),
list[2]);
939 }
else if (!
list[4][0]) {
940 xml +=
"<Param " +
qtoString(fullFilename, line + 1, level) +
" name=" +
q(
list[1]) +
" comment=" +
q(
list[2]) +
" default=" +
q(
list[3]) +
" />\n";
941 std::string v(
list[3]);
942 c->odbs->RS((std::string(
"Param/Value/") +
list[1]).c_str(), &v,
true);
943 c->odbs->WS((std::string(
"Param/Comment/") +
list[1]).c_str(),
list[2]);
944 c->odbs->WS((std::string(
"Param/Defaults/") +
list[1]).c_str(),
list[3]);
947 xml +=
"<Param " +
qtoString(fullFilename, line + 1, level) +
" name=" +
q(
list[1]) +
" comment=" +
q(
list[2]) +
950 c->odbs->RS((std::string(
"Param/Value/") +
list[1]).c_str(), &v,
true);
951 c->odbs->WS((std::string(
"Param/Comment/") +
list[1]).c_str(),
list[2]);
952 std::vector<std::string> options;
953 for (
i = 3;
i < 100 &&
list[
i][0];
i++) {
958 options.push_back(
list[
i]);
961 c->odbs->WSA((std::string(
"Param/Options/") +
list[1]).c_str(), options, 0);
966 std::string ov = oldSeqParam[(
const char *)
list[1]];
967 c->odbs->WS((std::string(
"Param/Value/") +
list[1]).c_str(), ov.c_str());
971 xml +=
"<RunDescription " +
qtoString(fullFilename, line + 1, level) +
">" +
list[1] +
"</RunDescription>\n";
974 if (
list[2][0] == 0) {
975 xml +=
"<Script " +
qtoString(fullFilename, line + 1, level) +
">" +
list[1] +
"</Script>\n";
977 xml +=
"<Script " +
qtoString(fullFilename, line + 1, level) +
" params=\"";
978 for (
i = 2;
i < 100 &&
list[
i][0];
i++) {
986 xml +=
"</Script>\n";
990 xml +=
"<Set " +
qtoString(fullFilename, line + 1, level) +
" name=" +
q(
list[1]) +
">" +
list[2] +
"</Set>\n";
993 xml +=
"\n<Subroutine " +
qtoString(fullFilename, line + 1, level) +
" name=" +
q(
list[1]) +
">\n";
996 xml +=
"</Subroutine>\n";
999 xml +=
"<Transition " +
qtoString(fullFilename, line + 1, level) +
">" +
list[1] +
"</Transition>\n";
1003 xml +=
"<Wait " +
qtoString(fullFilename, line + 1, level) +
" for=\"seconds\">" +
list[1] +
"</Wait>\n";
1004 }
else if (!
list[3][0]) {
1005 xml +=
"<Wait " +
qtoString(fullFilename, line + 1, level) +
" for=" +
q(
list[1]) +
">" +
list[2] +
"</Wait>\n";
1007 xml +=
"<Wait " +
qtoString(fullFilename, line + 1, level) +
" for=" +
q(
list[1]) +
" path=" +
q(
list[2]) +
" op=" +
1016 snprintf(error, error_size,
"WAIT timeout is only supported for WAIT ODBValue");
1017 *error_line = line + 1;
1021 snprintf(error, error_size,
1022 "Invalid WAIT ODBValue timeout syntax. Use: WAIT ODBValue, path, op, value, timeout, seconds");
1023 *error_line = line + 1;
1026 xml +=
" timeout=" +
q(
list[6]);
1029 xml +=
">" + std::string(
list[4]) +
"</Wait>\n";
1032 }
else if (
list[0][0] == 0 ||
list[0][0] ==
'#') {
1035 snprintf(error, error_size,
"Invalid command \"%s\"",
list[0]);
1036 *error_line = line + 1;
1044 xml +=
"\n</Library>\n";
1046 xml +=
"</RunSequence>\n";
1050 fprintf(fout,
"%s", xml.c_str());
1064 cm_msg(
MERROR,
"seq_read",
"Cannot find /Sequencer/State in ODB, db_find_key() status %d",
status);
1071 cm_msg(
MERROR,
"seq_read",
"Cannot get /Sequencer/State from ODB, db_get_record1() status %d",
status);
1082 cm_msg(
MERROR,
"seq_write",
"Cannot find /Sequencer/State in ODB, db_find_key() status %d",
status);
1087 cm_msg(
MERROR,
"seq_write",
"Cannot write to ODB /Sequencer/State, db_set_record() status %d",
status);
1149 midas::odb defaults(std::string(
"/") +
c->odb_path +
"/Param/Defaults");
1151 midas::odb vars(std::string(
"/") +
c->odb_path +
"/Variables");
1155 if (!
param.is_subkey(
d.get_name())) {
1156 mstrlcpy(seq.
error,
"Cannot start script because /Sequencer/Param/Value is incomplete",
sizeof(seq.
error));
1158 cm_msg(
MERROR,
"sequencer",
"Cannot start script because /Sequencer/Param/Value is incomplete");
1164 vars[p.get_name()] = p.
s();
1167 mstrlcpy(seq.
error,
"Cannot start script, no script loaded",
sizeof(seq.
error));
1181 cm_msg(
MTALK,
"sequencer",
"Sequencer started with script \"%s\" in debugging mode.", seq.
filename);
1193 path +=
"userfiles/sequencer/";
1237 for (
int i = 1;
i < mxml_get_line_number_end(mxml_find_node(
c->pnseq,
"RunSequence"));
i++) {
1238 PMXML_NODE pt = mxml_get_node_at_line(
c->pnseq,
i);
1241 if (
equal_ustring(mxml_get_attribute(pt,
"name"),
"ATEXIT")) {
1244 seq_error(seq,
c,
"Maximum subroutine level exceeded");
1291 mxml_free_tree(
c->pnseq);
1294 c->odbs->WS(
"Script/Lines",
"");
1297 int size = (int)strlen(
str) + 1;
1298 char *xml_filename = (
char *) malloc(size);
1299 mstrlcpy(xml_filename,
str, size);
1300 strsubst(xml_filename, size,
".msl",
".xml");
1304 path +=
"userfiles/sequencer/";
1306 if (xml_filename[0] ==
'/') {
1307 path += xml_filename;
1308 path = path.substr(0, path.find_last_of(
'/') + 1);
1309 mstrlcpy(xml_filename, path.substr(path.find_last_of(
'/') + 1).c_str(), size);
1316 std::string fn(path);
1317 if (!fn.empty() && fn.back() !=
'/')
1337 for (
int i=0 ;
i<9 ;
i++)
1356 if (
c->seqp->new_file) {
1357 mstrlcpy(
str,
c->seqp->path,
sizeof(
str));
1360 mstrlcat(
str,
c->seqp->filename,
sizeof(
str));
1378 bool start_script =
false;
1379 bool stop_immediately =
false;
1380 bool stop_after_run =
false;
1381 bool cancel_stop_after_run =
false;
1382 bool pause_script =
false;
1383 bool resume_script =
false;
1384 bool debug_script =
false;
1385 bool step_over =
false;
1386 bool load_new_file =
false;
1388 c->odbs->RB(
"Command/Start script", &start_script);
1389 c->odbs->RB(
"Command/Stop immediately", &stop_immediately);
1390 c->odbs->RB(
"Command/Stop after run", &stop_after_run);
1391 c->odbs->RB(
"Command/Cancel stop after run", &cancel_stop_after_run);
1392 c->odbs->RB(
"Command/Pause script", &pause_script);
1393 c->odbs->RB(
"Command/Resume script", &resume_script);
1394 c->odbs->RB(
"Command/Debug script", &debug_script);
1395 c->odbs->RB(
"Command/Step over", &step_over);
1396 c->odbs->RB(
"Command/Load new file", &load_new_file);
1398 if (load_new_file) {
1399 std::string filename;
1400 c->odbs->RS(
"State/Filename", &filename);
1404 if (filename.find(
"..") != std::string::npos) {
1405 mstrlcpy(seqp->
error,
"Cannot load \"",
sizeof(seqp->
error));
1406 mstrlcat(seqp->
error, filename.c_str(),
sizeof(seqp->
error));
1407 mstrlcat(seqp->
error,
"\": file names with \"..\" is not permitted",
sizeof(seqp->
error));
1409 }
else if (filename.find(
".msl") == std::string::npos) {
1410 mstrlcpy(seqp->
error,
"Cannot load \"",
sizeof(seqp->
error));
1411 mstrlcat(seqp->
error, filename.c_str(),
sizeof(seqp->
error));
1412 mstrlcat(seqp->
error,
"\": file name should end with \".msl\"",
sizeof(seqp->
error));
1417 if (path.length() > 0 && path.back() !=
'/') {
1428 c->odbs->WB(
"Command/Load new file",
false);
1434 c->odbs->WB(
"Command/Start script",
false);
1436 bool seq_running =
false;
1437 c->odbs->RB(
"State/running", &seq_running);
1442 cm_msg(
MTALK,
"sequencer",
"Sequencer is already running");
1446 if (stop_immediately &&
c->pnseq != NULL) {
1448 c->odbs->WB(
"Command/Stop immediately",
false);
1450 cm_msg(
MTALK,
"sequencer",
"Sequencer is finished by \"stop immediately\".");
1452 c->odbs->WB(
"Command/Stop immediately",
false);
1453 cm_msg(
MTALK,
"sequencer",
"Sequencer received \"stop immediately\". Executing ATEXIT.");
1457 if (stop_after_run) {
1458 c->odbs->WB(
"Command/Stop after run",
false);
1462 if (cancel_stop_after_run) {
1463 c->odbs->WB(
"Command/Cancel stop after run",
false);
1469 c->odbs->WB(
"Command/Pause script",
false);
1470 cm_msg(
MTALK,
"sequencer",
"Sequencer is paused.");
1473 if (resume_script) {
1475 c->odbs->WB(
"Command/Resume script",
false);
1476 cm_msg(
MTALK,
"sequencer",
"Sequencer is resumed.");
1480 c->odbs->WB(
"Command/Debug script",
false);
1482 bool seq_running =
false;
1483 c->odbs->RB(
"State/running", &seq_running);
1488 cm_msg(
MTALK,
"sequencer",
"Sequencer is already running");
1494 c->odbs->WB(
"Command/Step over",
false);
1503 *index1 = *index2 = 0;
1504 if (odbpath[strlen(odbpath) - 1] ==
']') {
1505 if (strchr(odbpath,
'[')) {
1507 if (strchr((strchr(odbpath,
'[') + 1),
'$')) {
1508 mstrlcpy(
str, strchr(odbpath,
'[') + 1,
sizeof(
str));
1509 if (strchr(
str,
']'))
1510 *strchr(
str,
']') = 0;
1513 *strchr(odbpath,
'[') = 0;
1530 std::vector<HNDLE> keys;
1538 size =
sizeof(
data);
1571 PMXML_NODE
pn, pr, pt, pe;
1572 char odbpath[256],
data[256],
str[1024],
name[32], op[32];
1575 int i,
j, l,
n,
status, size, index1, index2,
state,
run_number, cont;
1586 if (
c->pnseq == NULL) {
1588 mstrlcpy(seq.
error,
"No script loaded",
sizeof(seq.
error));
1603 pr = mxml_find_node(
c->pnseq,
"RunSequence");
1605 seq_error(seq,
c,
"Cannot find <RunSequence> tag in XML file");
1609 int last_line = mxml_get_line_number_end(pr);
1619 cm_msg(
MTALK,
"sequencer",
"Sequencer is finished.");
1639 cm_msg(
MTALK,
"sequencer",
"Sequencer is finished.");
1665 if (mxml_get_attribute(
pn,
"var")) {
1666 mstrlcpy(
name, mxml_get_attribute(
pn,
"var"),
sizeof(
name));
1667 if (mxml_get_attribute(
pn,
"values")) {
1668 mstrlcpy(
data, mxml_get_attribute(
pn,
"values"),
sizeof(
data));
1671 }
else if (mxml_get_attribute(
pn,
"n")) {
1674 sprintf(
str,
"Variables/%s",
name);
1675 size =
value.length() + 1;
1726 if (mxml_get_attribute(
pn,
"l"))
1728 if (mxml_get_attribute(
pn,
"fn")) {
1729 std::string filename = mxml_get_attribute(
pn,
"fn");
1732 if (filename != std::string(seq.
sfilename)) {
1738 if (mxml_get_attribute(
pn,
"l") && (!mxml_get_attribute(
pn,
"lvl") || atoi(mxml_get_attribute(
pn,
"lvl")) == 0))
1747 midas::odb o(
"/" +
c->odb_path +
"/Script/Lines");
1762 if (!mxml_get_attribute(
pn,
"path")) {
1763 seq_error(seq,
c,
"Missing attribute \"path\"");
1766 std::string s = mxml_get_attribute(
pn,
"path");
1767 if (s.find(
'$') != std::string::npos)
1771 if (mxml_get_attribute(
pn,
"notify"))
1780 if (!mxml_get_attribute(
pn,
"path")) {
1781 seq_error(seq,
c,
"Missing attribute \"path\"");
1783 mstrlcpy(odbpath, seq.
subdir,
sizeof(odbpath));
1784 if (strlen(odbpath) > 0 && odbpath[strlen(odbpath) - 1] !=
'/')
1785 mstrlcat(odbpath,
"/",
sizeof(odbpath));
1786 mstrlcat(odbpath, mxml_get_attribute(
pn,
"path"),
sizeof(odbpath));
1788 if (strchr(odbpath,
'$')) {
1789 if (strchr(odbpath,
'[')) {
1791 std::string s(odbpath);
1792 std::string s1 = s.substr(0, s.find(
'['));
1793 std::string s2 = s.substr(s.find(
'['));
1796 mstrlcpy(odbpath, s1.c_str(),
sizeof(odbpath));
1799 std::string s(odbpath);
1801 mstrlcpy(odbpath, s.c_str(),
sizeof(odbpath));
1808 if (mxml_get_attribute(
pn,
"notify"))
1809 notify = atoi(mxml_get_attribute(
pn,
"notify"));
1811 index1 = index2 = 0;
1814 if (index1 < -1 || index2 < 0) {
1815 seq_error(seq,
c,
"Negative index not allowed");
1819 if (index1 > 1E6 || index2 > 1E6) {
1820 seq_error(seq,
c,
"Index too large for ODB");
1833 sprintf(
str,
"ODB key \"%s\" not found", odbpath);
1836 sprintf(
str,
"Invalid index %d for ODB key \"%s\"", index1, odbpath);
1840 sprintf(
str,
"Internal error %d",
status);
1849 if (mxml_get_value(
pn)[0] ==
'/') {
1853 path +=
"userfiles/sequencer/";
1855 value += std::string(mxml_get_value(
pn)+1);
1859 path +=
"userfiles/sequencer/";
1862 if (
value.back() !=
'/')
1867 if (
value.find(
'$') != std::string::npos)
1871 if (mxml_get_attribute(
pn,
"path")) {
1872 mstrlcpy(odbpath, seq.
subdir,
sizeof(odbpath));
1873 if (strlen(odbpath) > 0 && odbpath[strlen(odbpath) - 1] !=
'/')
1874 mstrlcat(odbpath,
"/",
sizeof(odbpath));
1875 mstrlcat(odbpath, mxml_get_attribute(
pn,
"path"),
sizeof(odbpath));
1877 if (strchr(odbpath,
'$')) {
1878 std::string s(odbpath);
1880 mstrlcpy(odbpath, s.c_str(),
sizeof(odbpath));
1904 seq_error(seq,
c,
"Internal error loading ODB file!");
1911 if (mxml_get_value(
pn)[0] ==
'/') {
1915 path +=
"userfiles/sequencer/";
1917 value += std::string(mxml_get_value(
pn)+1);
1921 path +=
"userfiles/sequencer/";
1925 size_t pos =
value.find_last_of(
'/');
1926 if (pos != std::string::npos)
1931 if (
value.find(
'$') != std::string::npos)
1935 if (mxml_get_attribute(
pn,
"path") && *mxml_get_attribute(
pn,
"path")) {
1936 mstrlcpy(odbpath, seq.
subdir,
sizeof(odbpath));
1937 if (strlen(odbpath) > 0 && odbpath[strlen(odbpath) - 1] !=
'/')
1938 mstrlcat(odbpath,
"/",
sizeof(odbpath));
1939 mstrlcat(odbpath, mxml_get_attribute(
pn,
"path"),
sizeof(odbpath));
1941 if (strchr(odbpath,
'$')) {
1942 std::string s(odbpath);
1944 mstrlcpy(odbpath, s.c_str(),
sizeof(odbpath));
1953 if (strstr(
value.c_str(),
".json") || strstr(
value.c_str(),
".JSON") || strstr(
value.c_str(),
".js") || strstr(
value.c_str(),
".JS"))
1955 else if (strstr(
value.c_str(),
".xml") || strstr(
value.c_str(),
".XML"))
1965 seq_error(seq,
c,
"No ODB path specified in ODBSAVE command");
1977 seq_error(seq,
c,
"Internal error loading ODB file!");
1984 if (!mxml_get_attribute(
pn,
"path")) {
1985 seq_error(seq,
c,
"Missing attribute \"path\"");
1987 mstrlcpy(odbpath, seq.
subdir,
sizeof(odbpath));
1988 if (strlen(odbpath) > 0 && odbpath[strlen(odbpath) - 1] !=
'/')
1989 mstrlcat(odbpath,
"/",
sizeof(odbpath));
1990 mstrlcat(odbpath, mxml_get_attribute(
pn,
"path"),
sizeof(odbpath));
1992 if (strchr(odbpath,
'$')) {
1993 if (strchr(odbpath,
'[')) {
1995 std::string s(odbpath);
1996 std::string s1 = s.substr(0, s.find(
'['));
1997 std::string s2 = s.substr(s.find(
'['));
2000 mstrlcpy(odbpath, s1.c_str(),
sizeof(odbpath));
2003 std::string s(odbpath);
2005 mstrlcpy(odbpath, s.c_str(),
sizeof(odbpath));
2010 index1 = index2 = 0;
2013 mstrlcpy(
name, mxml_get_value(
pn),
sizeof(
name));
2020 size =
sizeof(
data);
2024 value = *((
int *)
data) > 0 ?
"1" :
"0";
2028 sprintf(
str,
"Variables/%s",
name);
2029 size =
value.length() + 1;
2043 if (!mxml_get_attribute(
pn,
"path")) {
2044 seq_error(seq,
c,
"Missing attribute \"path\"");
2045 }
else if (!mxml_get_attribute(
pn,
"string")) {
2046 seq_error(seq,
c,
"Missing attribute \"string\"");
2048 mstrlcpy(odbpath, seq.
subdir,
sizeof(odbpath));
2049 if (strlen(odbpath) > 0 && odbpath[strlen(odbpath) - 1] !=
'/')
2050 mstrlcat(odbpath,
"/",
sizeof(odbpath));
2051 mstrlcat(odbpath, mxml_get_attribute(
pn,
"path"),
sizeof(odbpath));
2053 if (strchr(odbpath,
'$')) {
2054 if (strchr(odbpath,
'[')) {
2056 std::string s(odbpath);
2057 std::string s1 = s.substr(0, s.find(
'['));
2058 std::string s2 = s.substr(s.find(
'['));
2061 mstrlcpy(odbpath, s1.c_str(),
sizeof(odbpath));
2064 std::string s(odbpath);
2066 mstrlcpy(odbpath, s.c_str(),
sizeof(odbpath));
2070 mstrlcpy(
name, mxml_get_value(
pn),
sizeof(
name));
2072 auto s =
eval_var(seq,
c, mxml_get_attribute(
pn,
"string"));
2073 mstrlcpy(
str, s.c_str(),
sizeof(
str));
2084 size =
sizeof(
data);
2086 if (strcmp((
const char *)
data,
str) == 0)
2094 snprintf(
str,
sizeof(
str),
"\"ODBLOOKUP %s\" did not find string \"%s\"", odbpath, s.c_str());
2099 snprintf(
str,
sizeof(
str),
"Variables/%s",
name);
2100 size =
value.length() + 1;
2114 if (!mxml_get_attribute(
pn,
"path")) {
2115 seq_error(seq,
c,
"Missing attribute \"path\"");
2117 mstrlcpy(odbpath, seq.
subdir,
sizeof(odbpath));
2118 if (strlen(odbpath) > 0 && odbpath[strlen(odbpath) - 1] !=
'/')
2119 mstrlcat(odbpath,
"/",
sizeof(odbpath));
2120 mstrlcat(odbpath, mxml_get_attribute(
pn,
"path"),
sizeof(odbpath));
2122 if (strchr(odbpath,
'$')) {
2123 if (strchr(odbpath,
'[')) {
2125 std::string s(odbpath);
2126 std::string s1 = s.substr(0, s.find(
'['));
2127 std::string s2 = s.substr(s.find(
'['));
2130 mstrlcpy(odbpath, s1.c_str(),
sizeof(odbpath));
2133 std::string s(odbpath);
2135 mstrlcpy(odbpath, s.c_str(),
sizeof(odbpath));
2139 index1 = index2 = 0;
2149 size =
sizeof(
data);
2154 sprintf(
str,
"%lg",
d);
2155 size =
sizeof(
data);
2161 if (mxml_get_attribute(
pn,
"notify"))
2162 notify = atoi(mxml_get_attribute(
pn,
"notify"));
2172 mstrlcpy(odbpath, seq.
subdir,
sizeof(odbpath));
2173 if (strlen(odbpath) > 0 && odbpath[strlen(odbpath) - 1] !=
'/')
2174 mstrlcat(odbpath,
"/",
sizeof(odbpath));
2175 mstrlcat(odbpath, mxml_get_value(
pn),
sizeof(odbpath));
2177 if (strchr(odbpath,
'$')) {
2178 std::string s(odbpath);
2180 mstrlcpy(odbpath, s.c_str(),
sizeof(odbpath));
2193 if (!mxml_get_attribute(
pn,
"path")) {
2194 seq_error(seq,
c,
"Missing attribute \"path\"");
2195 }
else if (!mxml_get_attribute(
pn,
"type")) {
2196 seq_error(seq,
c,
"Missing attribute \"type\"");
2198 mstrlcpy(odbpath, seq.
subdir,
sizeof(odbpath));
2199 if (strlen(odbpath) > 0 && odbpath[strlen(odbpath) - 1] !=
'/')
2200 mstrlcat(odbpath,
"/",
sizeof(odbpath));
2201 mstrlcat(odbpath, mxml_get_attribute(
pn,
"path"),
sizeof(odbpath));
2203 if (strchr(odbpath,
'$')) {
2204 std::string s(odbpath);
2206 mstrlcpy(odbpath, s.c_str(),
sizeof(odbpath));
2211 for (tid = 0; tid <
TID_LAST; tid++) {
2217 seq_error(seq,
c,
"Type must be one of UINT8,INT8,UINT16,INT16,UINT32,INT32,BOOL,FLOAT,DOUBLE,STRING");
2230 memset(dummy, 0,
sizeof(dummy));
2239 if (mxml_get_attribute(
pn,
"size")) {
2240 i = atoi(
eval_var(seq,
c, mxml_get_attribute(
pn,
"size")).c_str());
2258 sprintf(
str,
"%s", mxml_get_value(
pn));
2260 if (mxml_get_attribute(
pn,
"params")) {
2261 mstrlcpy(
data, mxml_get_attribute(
pn,
"params"),
sizeof(
data));
2263 for (
i = 0;
i <
n;
i++) {
2267 mstrlcat(
str,
" ",
sizeof(
str));
2274 std::string r =
ss_execs(s.c_str());
2287 size =
sizeof(
state);
2299 size =
sizeof(
state);
2309 size =
sizeof(
state);
2321 size =
sizeof(
state);
2336 cm_msg(
MTALK,
"sequencer",
"Sequencer is finished by \"stop after current run\".");
2338 cm_msg(
MTALK,
"sequencer",
"Sequencer is going to finish by \"stop after current run\". Executing ATEXIT.");
2356 n = atoi(
eval_var(seq,
c, mxml_get_value(
pn)).c_str());
2374 }
else if (
equal_ustring(mxml_get_attribute(
pn,
"for"),
"ODBValue")) {
2377 if (!mxml_get_attribute(
pn,
"path")) {
2378 seq_error(seq,
c,
"\"path\" must be given for ODB values");
2381 mstrlcpy(odbpath, mxml_get_attribute(
pn,
"path"),
sizeof(odbpath));
2384 if (strchr(odbpath,
'$')) {
2385 if (strchr(odbpath,
'[')) {
2387 std::string s(odbpath);
2388 std::string s1 = s.substr(0, s.find(
'['));
2389 std::string s2 = s.substr(s.find(
'['));
2392 mstrlcpy(odbpath, s1.c_str(),
sizeof(odbpath));
2395 std::string s(odbpath);
2397 mstrlcpy(odbpath, s.c_str(),
sizeof(odbpath));
2401 index1 = index2 = 0;
2408 if (mxml_get_attribute(
pn,
"op"))
2409 mstrlcpy(op, mxml_get_attribute(
pn,
"op"),
sizeof(op));
2415 size =
sizeof(
data);
2418 value = *((
int *)
data) > 0 ?
"1" :
"0";
2445 bool timed_out =
false;
2446 const char *timeout_attr = mxml_get_attribute(
pn,
"timeout");
2447 if (timeout_attr && timeout_attr[0]) {
2448 float timeout_sec = (float) atof(
eval_var(seq,
c, timeout_attr).c_str());
2449 if (timeout_sec < 0) {
2450 seq_error(seq,
c,
msprintf(
"Invalid WAIT ODBValue timeout \"%s\"", timeout_attr).c_str());
2465 timed_out = elapsed_ms > (
DWORD) (1000.0f * timeout_sec);
2471 if (cont || timed_out) {
2472 if (timed_out && !cont) {
2473 cm_msg(
MINFO,
"sequencer",
"WAIT ODBValue timeout after %.1f seconds: %s %s %g not satisfied",
2511 seq_error(seq,
c,
msprintf(
"Invalid wait attribute \"%s\"", mxml_get_attribute(
pn,
"for")).c_str());
2524 seq_error(seq,
c,
"Maximum loop nesting exceeded");
2529 if (mxml_get_attribute(
pn,
"l"))
2531 if (mxml_get_attribute(
pn,
"le"))
2535 if (mxml_get_attribute(
pn,
"n")) {
2542 }
else if (mxml_get_attribute(
pn,
"values")) {
2543 mstrlcpy(
data, mxml_get_attribute(
pn,
"values"),
sizeof(
data));
2547 seq_error(seq,
c,
"Missing \"var\" or \"n\" attribute");
2551 if (mxml_get_attribute(
pn,
"var")) {
2552 mstrlcpy(
name, mxml_get_attribute(
pn,
"var"),
sizeof(
name));
2553 sprintf(
str,
"Variables/%s",
name);
2554 size =
value.length() + 1;
2585 seq_error(seq,
c,
"\"Break\" outside any loop");
2598 seq_error(seq,
c,
"Maximum number of nested if..endif exceeded");
2609 pe = mxml_get_node_at_line(
c->pnseq,
j);
2613 j = mxml_get_line_number_end(pe);
2624 mstrlcpy(
str, mxml_get_attribute(
pn,
"condition"),
sizeof(
str));
2627 seq_error(seq,
c,
"Invalid number in comparison");
2654 cm_msg(
MTALK,
"sequencer",
"Sequencer is finished.");
2660 if (!mxml_get_attribute(
pn,
"line") && !mxml_get_attribute(
pn,
"sline")) {
2664 if (mxml_get_attribute(
pn,
"line")) {
2667 if (mxml_get_attribute(
pn,
"sline")) {
2668 mstrlcpy(
str,
eval_var(seq,
c, mxml_get_attribute(
pn,
"sline")).c_str(),
sizeof(
str));
2669 for (
i = 0;
i < last_line;
i++) {
2670 pt = mxml_get_node_at_line(
c->pnseq,
i);
2671 if (pt && mxml_get_attribute(pt,
"l")) {
2672 l = atoi(mxml_get_attribute(pt,
"l"));
2673 if (atoi(
str) == l) {
2702 if (!mxml_get_attribute(
pn,
"name")) {
2706 mstrlcpy(
name, mxml_get_attribute(
pn,
"name"),
sizeof(
name));
2709 if (strchr(
name,
'[')) {
2711 mstrlcpy(
str, strchr(
name,
'[')+1,
sizeof(
str));
2712 if (strchr(
str,
']'))
2713 *strchr(
str,
']') = 0;
2715 *strchr(
name,
'[') = 0;
2716 sprintf(
str,
"Variables/%s",
name);
2722 size =
value.length() + 1;
2727 sprintf(
str,
"Variables/%s",
name);
2728 size =
value.length() + 1;
2738 if (mxml_get_attribute(pr,
"var")) {
2749 if (strchr(mxml_get_value(
pn),
'$'))
2753 const char *wait_attr = mxml_get_attribute(
pn,
"wait");
2756 wait = (atoi(wait_attr) == 1);
2792 if (strchr(mxml_get_value(
pn),
'$'))
2796 std::string
type =
"INFO";
2797 if (mxml_get_attribute(
pn,
"type"))
2798 type = std::string(mxml_get_attribute(
pn,
"type"));
2800 if (
type ==
"ERROR")
2802 else if (
type ==
"DEBUG")
2804 else if (
type ==
"LOG")
2806 else if (
type ==
"TALK")
2816 if (!mxml_get_attribute(
pn,
"name")) {
2820 mstrlcpy(
name, mxml_get_attribute(
pn,
"name"),
sizeof(
name));
2823 sprintf(
str,
"Variables/%s",
name);
2824 size = strlen(
data) + 1;
2835 seq_error(seq,
c,
"Maximum subroutine level exceeded");
2844 for (
i = 1;
i < mxml_get_line_number_end(mxml_find_node(
c->pnseq,
"RunSequence"));
i++) {
2845 pt = mxml_get_node_at_line(
c->pnseq,
i);
2848 if (
equal_ustring(mxml_get_attribute(pt,
"name"), mxml_get_attribute(
pn,
"name"))) {
2854 if (mxml_get_value(
pn)) {
2856 if (strchr(mxml_get_value(
pn),
'$'))
2857 mstrlcpy(p,
eval_var(seq,
c, mxml_get_value(
pn)).c_str(),
sizeof(p));
2859 mstrlcpy(p, mxml_get_value(
pn),
sizeof(p));
2870 if (
i == mxml_get_line_number_end(mxml_find_node(
c->pnseq,
"RunSequence"))) {
2871 seq_error(seq,
c,
msprintf(
"Subroutine '%s' not found", mxml_get_attribute(
pn,
"name")).c_str());
2883 size =
sizeof(seq1);
2894 if (seq.
debug && !skip_step)
2907 c->odbs =
gOdb->Chdir(
c->odb_path.c_str(),
true);
2912 cm_msg(
MERROR,
"init_sequencer",
"Sequencer error: Cannot find /Sequencer, db_find_key() status %d",
status);
2918 cm_msg(
MERROR,
"init_sequencer",
"Sequencer error: mismatching /Sequencer/State structure, db_check_record() status %d",
status);
2924 cm_msg(
MERROR,
"init_sequencer",
"Sequencer error: Cannot find /Sequencer/State, db_find_key() status %d",
status);
2928 int size =
sizeof(seq);
2931 cm_msg(
MERROR,
"init_sequencer",
"Sequencer error: Cannot get /Sequencer/State, db_get_record1() status %d",
status);
2948 cm_msg(
MERROR,
"init_sequencer",
"Sequencer error: Cannot watch /Sequencer/State, db_watch() status %d",
status);
2953 c->odbs->RB(
"Command/Start script", &b,
true);
2955 c->odbs->RB(
"Command/Stop immediately", &b,
true);
2957 c->odbs->RB(
"Command/Stop after run", &b,
true);
2959 c->odbs->RB(
"Command/Cancel stop after run", &b,
true);
2961 c->odbs->RB(
"Command/Pause script", &b,
true);
2963 c->odbs->RB(
"Command/Resume script", &b,
true);
2965 c->odbs->RB(
"Command/Debug script", &b,
true);
2967 c->odbs->RB(
"Command/Step over", &b,
true);
2969 c->odbs->RB(
"Command/Load new file", &b,
true);
2973 cm_msg(
MERROR,
"init_sequencer",
"Sequencer error: Cannot find /Sequencer/Command, db_find_key() status %d",
status);
2979 cm_msg(
MERROR,
"init_sequencer",
"Sequencer error: Cannot watch /Sequencer/Command, db_watch() status %d",
status);
2986int main(
int argc,
const char *argv[]) {
2989 char midas_hostname[256];
2990 char midas_expt[256];
2991 std::string seq_name =
"";
2993 setbuf(stdout, NULL);
2994 setbuf(stderr, NULL);
2997 signal(SIGPIPE, SIG_IGN);
3001 cm_get_environment(midas_hostname,
sizeof(midas_hostname), midas_expt,
sizeof(midas_expt));
3004 for (
int i = 1;
i < argc;
i++) {
3005 if (argv[
i][0] ==
'-' && argv[
i][1] ==
'D') {
3007 }
else if (argv[
i][0] ==
'-') {
3008 if (
i + 1 >= argc || argv[
i + 1][0] ==
'-')
3010 if (argv[
i][1] ==
'h')
3011 mstrlcpy(midas_hostname, argv[++
i],
sizeof(midas_hostname));
3012 else if (argv[
i][1] ==
'e')
3013 mstrlcpy(midas_expt, argv[++
i],
sizeof(midas_hostname));
3014 else if (argv[
i][1] ==
'c')
3015 seq_name = argv[++
i];
3018 printf(
"usage: %s [-h Hostname[:port]] [-e Experiment] [-c Name] [-D]\n\n", argv[0]);
3019 printf(
" -e experiment to connect to\n");
3020 printf(
" -c Name of additional sequencer, i.e. \'Test\'\n");
3021 printf(
" -h connect to midas server (mserver) on given host\n");
3022 printf(
" -D become a daemon\n");
3028 printf(
"Becoming a daemon...\n");
3032 std::string prg_name =
"Sequencer";
3033 std::string odb_path =
"Sequencer";
3035 if (!seq_name.empty()) {
3036 prg_name = std::string(
"Sequencer") + seq_name;
3037 odb_path = std::string(
"Sequencer") + seq_name;
3041 std::string pid_filename;
3042 pid_filename +=
"/var/run/";
3043 pid_filename += prg_name;
3044 pid_filename +=
".pid";
3046 FILE *f = fopen(pid_filename.c_str(),
"w");
3069 printf(
"%s runs already.\n", prg_name.c_str());
3083 c.seq_name = seq_name;
3084 c.prg_name = prg_name;
3085 c.odb_path = odb_path;
3089 if (seq_name.empty()) {
3090 printf(
"Sequencer started. Stop with \"!\"\n");
3092 printf(
"%s started.\n", prg_name.c_str());
3093 printf(
"Set ODB String \"/Alias/Sequencer%s\" to URL \"?cmd=sequencer&seq_name=%s\"\n", seq_name.c_str(), seq_name.c_str());
3094 printf(
"Stop with \"!\"\n");
3107 }
catch (std::string &msg) {
3109 }
catch (
const char *msg) {
3121 if ((
char) ch ==
'!')
static bool exists(const std::string &name)
void set_auto_refresh_read(bool f)
void set_auto_create(bool f)
INT cm_yield(INT millisec)
INT cm_get_experiment_database(HNDLE *hDB, HNDLE *hKeyClient)
INT cm_transition(INT transition, INT run_number, char *errstr, INT errstr_size, INT async_flag, INT debug_flag)
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)
std::string cm_expand_env(const char *str)
INT cm_disconnect_experiment(void)
std::string cm_get_path()
INT cm_get_environment(char *host_name, int host_name_size, char *exp_name, int exp_name_size)
INT cm_exist(const char *name, BOOL bUnique)
#define CM_DEFERRED_TRANSITION
#define CM_WRONG_PASSWORD
#define DB_STRUCT_MISMATCH
#define DB_INVALID_HANDLE
INT ss_getchar(BOOL reset)
std::string ss_execs(const char *cmd)
std::string ss_replace_env_variables(const std::string &inputPath)
INT ss_daemon_init(BOOL keep_stdout)
INT ss_sleep(INT millisec)
std::string cm_get_error(INT code)
INT cm_msg(INT message_type, const char *filename, INT line, const char *routine, const char *format,...)
INT cm_msg_retrieve(INT n_message, char *message, INT buf_size)
BOOL equal_ustring(const char *str1, const char *str2)
INT db_get_data_index(HNDLE hDB, HNDLE hKey, void *data, INT *buf_size, INT idx, DWORD type)
INT db_delete_key(HNDLE hDB, HNDLE hKey, BOOL follow_links)
INT db_get_value(HNDLE hDB, HNDLE hKeyRoot, const char *key_name, void *data, INT *buf_size, DWORD type, BOOL create)
INT db_save_json(HNDLE hDB, HNDLE hKey, const char *filename, int flags)
std::string strcomb1(const char **list)
INT db_save_xml(HNDLE hDB, HNDLE hKey, const char *filename)
INT db_get_record1(HNDLE hDB, HNDLE hKey, void *data, INT *buf_size, INT align, const char *rec_str)
INT db_create_key(HNDLE hDB, HNDLE hKey, const char *key_name, DWORD type)
INT db_check_record(HNDLE hDB, HNDLE hKey, const char *keyname, const char *rec_str, BOOL correct)
INT db_get_record(HNDLE hDB, HNDLE hKey, void *data, INT *buf_size, INT align)
INT db_save(HNDLE hDB, HNDLE hKey, const char *filename, BOOL bRemote)
INT db_get_key(HNDLE hDB, HNDLE hKey, KEY *key)
INT db_load(HNDLE hDB, HNDLE hKeyRoot, const char *filename, BOOL bRemote)
INT db_set_data_index(HNDLE hDB, HNDLE hKey, const void *data, INT data_size, INT idx, DWORD type)
INT db_watch(HNDLE hDB, HNDLE hKey, void(*dispatcher)(INT, INT, INT, void *), void *info)
INT db_delete(HNDLE hDB, HNDLE hKeyRoot, const char *odb_path)
INT db_sprintf(char *string, const void *data, INT data_size, INT idx, DWORD type)
void strarrayindex(char *odbpath, int *index1, int *index2)
INT db_set_value(HNDLE hDB, HNDLE hKeyRoot, const char *key_name, const void *data, INT data_size, INT num_values, DWORD type)
INT db_find_key(HNDLE hDB, HNDLE hKey, const char *key_name, HNDLE *subhKey)
INT db_find_keys(HNDLE hDB, HNDLE hKeyRoot, const char *odbpath, std::vector< HNDLE > &hKeyVector)
INT db_set_record(HNDLE hDB, HNDLE hKey, void *data, INT buf_size, INT align)
INT db_set_data_index1(HNDLE hDB, HNDLE hKey, const void *data, INT data_size, INT idx, DWORD type, BOOL bNotify)
INT db_sscanf(const char *data_str, void *data, INT *data_size, INT i, DWORD tid)
INT db_set_num_values(HNDLE hDB, HNDLE hKey, INT num_values)
const char * rpc_tid_name(INT id)
static void seq_watch(HNDLE hDB, HNDLE hKeyChanged, int index, void *info)
void seq_array_index(SEQUENCER &seq, SeqCon *c, char *odbpath, int *index1, int *index2)
int concatenate(SEQUENCER &seq, SeqCon *c, char *result, int size, char *value)
static void seq_stop_after_run(SEQUENCER &seq, SeqCon *c)
static void seq_start_next(SEQUENCER &seq, SeqCon *c)
static void seq_stop(SEQUENCER &seq, SeqCon *c)
void seq_write(const SEQUENCER &seq, SeqCon *c)
int strbreak(char *str, char list[][XNAME_LENGTH], int size, const char *brk, BOOL ignore_quotes)
void strsubst(char *string, int size, const char *pattern, const char *subst)
static std::string qtoString(std::string filename, int line, int level)
static void seq_watch_command(HNDLE hDB, HNDLE hKeyChanged, int index, void *info)
char * stristr(const char *str, const char *pattern)
static BOOL goto_at_exit(SEQUENCER &seq, SeqCon *c)
void seq_read(SEQUENCER *seq, SeqCon *c)
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 init_sequencer(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)
void sequencer(SEQUENCER &seq, SeqCon *c)
static std::string toString(int v)
void seq_error(SEQUENCER &seq, SeqCon *c, const char *str)
int set_all_matching(HNDLE hDB, HNDLE hBaseKey, const char *odbpath, char *value, int index1, int index2, int notify)
static std::string q(const char *s)
std::string eval_var(SEQUENCER &seq, SeqCon *c, std::string value)
bool loadMSL(MVOdb *o, const std::string &filename)
int eval_condition(SEQUENCER &seq, SeqCon *c, const char *condition)
static void seq_start(SEQUENCER &seq, SeqCon *c, bool debug)
bool is_valid_number(const char *str)
void seq_clear(SEQUENCER &seq)
static void seq_open_file(const char *str, SEQUENCER &seq, SeqCon *c)
BOOL debug
debug printouts
std::string msprintf(const char *format,...)
#define DIR_SEPARATOR_STR
#define DEFAULT_WATCHDOG_TIMEOUT
#define JSFLAG_FOLLOW_LINKS
#define JSFLAG_OMIT_LAST_WRITTEN
#define SEQ_NEST_LEVEL_IF
#define SEQUENCER_STR(_name)
#define SEQ_NEST_LEVEL_LOOP
#define SEQ_NEST_LEVEL_SUB
int if_line[SEQ_NEST_LEVEL_IF]
int loop_end_line[SEQ_NEST_LEVEL_LOOP]
int sloop_start_line[SEQ_NEST_LEVEL_LOOP]
int subroutine_return_line[SEQ_NEST_LEVEL_SUB]
int loop_start_line[SEQ_NEST_LEVEL_LOOP]
int subroutine_end_line[SEQ_NEST_LEVEL_SUB]
int if_else_line[SEQ_NEST_LEVEL_IF]
int sloop_end_line[SEQ_NEST_LEVEL_LOOP]
int if_endif_line[SEQ_NEST_LEVEL_IF]
int subroutine_call_line[SEQ_NEST_LEVEL_SUB]
int loop_n[SEQ_NEST_LEVEL_LOOP]
int ssubroutine_call_line[SEQ_NEST_LEVEL_SUB]
char subroutine_param[SEQ_NEST_LEVEL_SUB][256]
int loop_counter[SEQ_NEST_LEVEL_LOOP]
char next_filename[10][256]
double te_interp(const char *expression, int *error)
static void pn(const te_expr *n, int depth)
static te_expr * list(state *s)