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 std::ostringstream os;
371 os << std::scientific << r;
385 for (
i = 0;
i <
n;
i++) {
387 mstrlcat(result,
str.c_str(), size);
397 double value1, value2;
398 char value1_str[256], value2_str[256],
str[256], op[3], *p;
399 std::string value1_var, value2_var;
402 p = (
char *)condition;
408 if (strchr(
str,
'#'))
409 *strchr(
str,
'#') = 0;
411 while (strlen(
str) > 0 && (
str[strlen(
str)-1] ==
' '))
415 if (
str[0] ==
'(' && strlen(
str) > 0 &&
str[strlen(
str)-1] ==
')') {
416 mstrlcpy(value1_str,
str+1,
sizeof(value1_str));
417 mstrlcpy(
str, value1_str,
sizeof(
str));
424 for (
i = 0;
i < (int) strlen(
str);
i++)
425 if (strchr(
"<>=!&",
str[
i]) != NULL)
427 mstrlcpy(value1_str,
str,
i + 1);
428 while (value1_str[strlen(value1_str) - 1] ==
' ')
429 value1_str[strlen(value1_str) - 1] = 0;
431 if (strchr(
"<>=!&",
str[
i + 1]) != NULL)
434 for (
i++;
str[
i] ==
' ';
i++);
435 mstrlcpy(value2_str,
str +
i,
sizeof(value2_str));
437 value1_var =
eval_var(seq,
c, value1_str);
438 value2_var =
eval_var(seq,
c, value2_str);
442 if (strcmp(op,
"=") == 0)
443 return equal_ustring(value1_var.c_str(), value2_var.c_str()) ? 1 : 0;
444 if (strcmp(op,
"==") == 0)
445 return equal_ustring(value1_var.c_str(), value2_var.c_str()) ? 1 : 0;
446 if (strcmp(op,
"!=") == 0)
447 return equal_ustring(value1_var.c_str(), value2_var.c_str()) ? 0 : 1;
453 value1 = atof(value1_var.c_str());
454 value2 = atof(value2_var.c_str());
457 if (strcmp(op,
"=") == 0)
458 if (value1 == value2)
460 if (strcmp(op,
"==") == 0)
461 if (value1 == value2)
463 if (strcmp(op,
"!=") == 0)
464 if (value1 != value2)
466 if (strcmp(op,
"<") == 0)
469 if (strcmp(op,
">") == 0)
472 if (strcmp(op,
"<=") == 0)
473 if (value1 <= value2)
475 if (strcmp(op,
">=") == 0)
476 if (value1 >= value2)
478 if (strcmp(op,
"&") == 0)
479 if (((
unsigned int) value1 & (
unsigned int) value2) > 0)
487bool loadMSL(MVOdb *o,
const std::string &filename) {
489 std::ifstream
file(filename);
493 std::vector<std::string> lines;
497 while (std::getline(
file, line))
498 lines.push_back(line);
501 o->WSA(
"Script/Lines", lines, 0);
509 char *error,
int error_size,
int *error_line) {
510 char str[256], *pl, *pe;
512 int i,
j,
n, nq, n_lines, endl, line, nest, incl, library;
513 std::string xml, path, fn;
514 char *msl_include, *xml_include, *include_error;
515 int include_error_size;
516 BOOL include_status, rel_path;
519 snprintf(error, error_size,
"More than 10 nested INCLUDE statements exceeded in file \"%s\"", filename);
524 path = std::string(cpath);
525 if (path.length() > 0 && path.back() !=
'/')
528 std::string fullFilename;
530 fullFilename = path + filename;
532 fullFilename = filename;
534 int fhin = open(fullFilename.c_str(), O_RDONLY |
O_TEXT);
536 snprintf(error, error_size,
"Cannot open \"%s\", errno %d (%s)", fullFilename.c_str(), errno, strerror(errno));
540 off_t off = lseek(fhin, 0, SEEK_END);
542 snprintf(error, error_size,
"Cannot find size of \"%s\", lseek(SEEK_END) errno %d (%s)", fullFilename.c_str(), errno, strerror(errno));
547 lseek(fhin, 0, SEEK_SET);
551 s = path + xml_filename;
555 FILE *fout = fopen(s.c_str(),
"wt");
557 snprintf(error, error_size,
"Cannot write to \"%s\", fopen() errno %d (%s)", s.c_str(), errno, strerror(errno));
564 char* buf = (
char *) malloc(size + 1);
565 ssize_t rd =
read(fhin, buf, size);
568 snprintf(error, error_size,
"Cannot read \"%s\", read(%zu) errno %d (%s)", fullFilename.c_str(), size, errno, strerror(errno));
578 lines = (
char **) malloc(
sizeof(
char *));
582 for (n_lines = 0; *pl; n_lines++) {
583 lines = (
char **) realloc(lines,
sizeof(
char *) * (n_lines + 1));
585 if (strchr(pl,
'\n')) {
586 pe = strchr(pl,
'\n');
588 if (*(pe - 1) ==
'\r') {
593 pe = pl + strlen(pl);
594 mstrlcpy(
str, pl,
sizeof(
str));
599 xml +=
"<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>\n";
600 xml +=
"<!DOCTYPE RunSequence [\n";
605 char *reference = strrchr(
list[1],
'/');
611 if (strchr(reference,
'.') && !strstr(reference,
".msl") && !strstr(reference,
".MSL")) {
612 snprintf(error, error_size,
"Include file \"%s\" cannot have an extension other than .msl", reference);
617 if (
list[1][0] ==
'/') {
619 p +=
"userfiles/sequencer";
623 if (!p.empty() && p.back() !=
'/')
635 size = p.length() + 1 + 4;
636 msl_include = (
char *) malloc(size);
637 xml_include = (
char *) malloc(size);
638 mstrlcpy(msl_include, p.c_str(), size);
639 mstrlcpy(xml_include, p.c_str(), size);
640 if (!strstr(msl_include,
".msl"))
641 mstrlcat(msl_include,
".msl", size);
642 mstrlcat(xml_include,
".xml", size);
644 include_error = error + strlen(error);
645 include_error_size = error_size - strlen(error);
648 path +=
"userfiles/sequencer/";
651 include_status =
msl_parse(seq,
c, level+1, path.c_str(), msl_include, xml_include, include_error, include_error_size, error_line);
655 if (!include_status) {
657 *error_line = n_lines + 1;
662 xml +=
"<Library name=\"";
670 }
else if (!library) {
671 xml +=
"<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>\n";
676 xml +=
"<RunSequence xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:noNamespaceSchemaLocation=\"\">\n";
679 std::vector<std::string> slines;
680 for (line = 0; line < n_lines; line++) {
681 slines.push_back(lines[line]);
684 c->odbs->WSA(
"Script/Lines", slines, 0);
687 std::string p =
"/" +
c->odb_path +
"/Param/Value";
694 c->odbs->Delete(
"Variables");
695 c->odbs->Delete(
"Param");
698 for (line = 0; line < n_lines; line++) {
699 char *p = lines[line];
702 mstrlcpy(
list[0], p,
sizeof(
list[0]));
703 if (strchr(
list[0],
' '))
704 *strchr(
list[0],
' ') = 0;
705 p += strlen(
list[0]);
709 for (
i = 0;
i <
n;
i++) {
710 if (
list[
i][0] ==
'#') {
711 for (
j =
i;
j <
n;
j++)
718 for (
i = 0;
i <
n;
i++) {
719 if (strchr(
list[
i],
'#'))
720 *strchr(
list[
i],
'#') = 0;
724 for (
i = 0;
i <
n;
i++) {
731 mstrlcpy(
eq, lines[line],
sizeof(
eq));
733 *strchr(
eq,
'#') = 0;
734 for (
i = 0,
n = 0, nq = 0;
i < (int)strlen(
eq);
i++) {
736 nq = (nq == 0 ? 1 : 0);
737 if (
eq[
i] ==
'=' && nq == 0 &&
738 (
i > 0 && (
eq[
i - 1] !=
'!') &&
eq[
i - 1] !=
'<' &&
eq[
i - 1] !=
'>'))
741 if (
n == 1 &&
eq[0] !=
'=') {
743 mstrlcpy(
list[0],
"SET",
sizeof(
list[0]));
747 mstrlcpy(
list[1], p,
sizeof(
list[1]));
748 *strchr(
list[1],
'=') = 0;
749 if (strchr(
list[1],
' '))
750 *strchr(
list[1],
' ') = 0;
751 p = strchr(
eq,
'=')+1;
754 mstrlcpy(
list[2], p,
sizeof(
list[2]));
755 while (strlen(
list[2]) > 0 &&
list[2][strlen(
list[2])-1] ==
' ')
763 char *reference = strrchr(
list[1],
'/');
774 xml +=
"<Call " +
qtoString(fullFilename, line + 1, level) +
" name=" +
q(
list[1]) +
">";
775 for (
i = 2;
i < 100 &&
list[
i][0];
i++) {
784 xml +=
"<Cat " +
qtoString(fullFilename, line + 1, level) +
" name=" +
q(
list[1]) +
">";
785 for (
i = 2;
i < 100 &&
list[
i][0];
i++) {
794 xml +=
"<Comment " +
qtoString(fullFilename, line + 1, level) +
">" +
list[1] +
"</Comment>\n";
797 xml +=
"<Exit " +
qtoString(fullFilename, line + 1, level) +
" />\n";
800 xml +=
"<Goto " +
qtoString(fullFilename, line + 1, level) +
" sline=" +
q(
list[1]) +
" />\n";
803 xml +=
"<If " +
qtoString(fullFilename, line + 1, level) +
" condition=\"";
804 for (
i = 1;
i < 100 &&
list[
i][0] && stricmp(
list[
i],
"THEN") != 0;
i++) {
817 for (
i = line, nest = 0;
i < n_lines;
i++) {
831 if (
list[2][0] == 0) {
832 xml +=
"<Loop " +
qtoString(fullFilename, line + 1, level) +
" le=\"" + std::to_string(endl) +
"\" n=" +
q(
list[1]) +
">\n";
833 }
else if (
list[3][0] == 0) {
834 xml +=
"<Loop " +
qtoString(fullFilename, line + 1, level) +
" le=\"" + std::to_string(endl) +
"\" var=" +
q(
list[1]) +
" n=" +
837 xml +=
"<Loop " +
qtoString(fullFilename, line + 1, level) +
" le=\"" + std::to_string(endl) +
"\" var=" +
q(
list[1]) +
" values=\"";
838 for (
i = 2;
i < 100 &&
list[
i][0];
i++) {
850 xml +=
"<Break "+
qtoString(fullFilename, line + 1, level) +
"></Break>\n";
853 xml +=
"<Message " +
qtoString(fullFilename, line + 1, level);
854 if (
list[2][0] ==
'1')
855 xml +=
" wait=\"1\"";
858 xml +=
"</Message>\n";
862 xml +=
"<Msg " +
qtoString(fullFilename, line + 1, level) +
" type=\""+
list[2]+
"\">" +
list[1] +
"</Msg>\n";
864 xml +=
"<Msg " +
qtoString(fullFilename, line + 1, level) +
">" +
list[1] +
"</Msg>\n";
869 mstrlcpy(
list[2],
"1", 2);
870 xml +=
"<ODBInc " +
qtoString(fullFilename, line + 1, level) +
" path=" +
q(
list[1]) +
">" +
list[2] +
"</ODBInc>\n";
874 xml +=
"<ODBCreate " +
qtoString(fullFilename, line + 1, level) +
" size=" +
q(
list[3]) +
" path=" +
q(
list[1]) +
" type=" +
875 q(
list[2]) +
"></ODBCreate>\n";
877 xml +=
"<ODBCreate " +
qtoString(fullFilename, line + 1, level) +
" path=" +
q(
list[1]) +
" type=" +
q(
list[2]) +
882 xml +=
"<ODBDelete " +
qtoString(fullFilename, line + 1, level) +
">" +
list[1] +
"</ODBDelete>\n";
886 xml +=
"<ODBSet " +
qtoString(fullFilename, line + 1, level) +
" notify=" +
q(
list[3]) +
" path=" +
q(
list[1]) +
">" +
887 list[2] +
"</ODBSet>\n";
889 xml +=
"<ODBSet " +
qtoString(fullFilename, line + 1, level) +
" path=" +
q(
list[1]) +
">" +
list[2] +
"</ODBSet>\n";
894 xml +=
"<ODBLoad " +
qtoString(fullFilename, line + 1, level) +
" path=" +
q(
list[2]) +
">" +
list[1] +
"</ODBLoad>\n";
896 xml +=
"<ODBLoad " +
qtoString(fullFilename, line + 1, level) +
">" +
list[1] +
"</ODBLoad>\n";
900 xml +=
"<ODBGet " +
qtoString(fullFilename, line + 1, level) +
" path=" +
q(
list[1]) +
">" +
list[2] +
"</ODBGet>\n";
903 xml +=
"<ODBLookup " +
qtoString(fullFilename, line + 1, level) +
" path=" +
q(
list[1]) +
904 " string=" +
q(
list[2]) +
">" +
list[3] +
"</ODBLookup>\n";
907 xml +=
"<ODBSave " +
qtoString(fullFilename, line + 1, level) +
" path=" +
q(
list[1]) +
">" +
list[2] +
"</ODBSave>\n";
911 xml +=
"<ODBSubdir " +
qtoString(fullFilename, line + 1, level) +
" notify=" +
q(
list[2]) +
" path=" +
q(
list[1]) +
">\n";
913 xml +=
"<ODBSubdir " +
qtoString(fullFilename, line + 1, level) +
" path=" +
q(
list[1]) +
">\n";
916 xml +=
"</ODBSubdir>\n";
920 snprintf(error, error_size,
"Parameter \"%s\" misses 'comment'",
list[1]);
921 *error_line = line + 1;
925 xml +=
"<Param " +
qtoString(fullFilename, line + 1, level) +
" name=" +
q(
list[1]) +
" type=\"bool\" " +
" comment=" +
q(
list[2]) +
"/>\n";
927 c->odbs->RB((std::string(
"Param/Value/") +
list[1]).c_str(), &v,
true);
928 c->odbs->WS((std::string(
"Param/Comment/") +
list[1]).c_str(),
list[2]);
930 xml +=
"<Param " +
qtoString(fullFilename, line + 1, level) +
" name=" +
q(
list[1]) +
" type=\"bool\" default=" +
q(
list[4]) +
"/>\n";
931 std::string def(
list[3]);
932 bool v(def ==
"1" || def ==
"true" || def ==
"TRUE");
933 c->odbs->RB((std::string(
"Param/Value/") +
list[1]).c_str(), &v,
true);
934 c->odbs->WS((std::string(
"Param/Comment/") +
list[1]).c_str(),
list[2]);
935 c->odbs->WS((std::string(
"Param/Defaults/") +
list[1]).c_str(),
list[3]);
937 }
else if (!
list[3][0]) {
938 xml +=
"<Param " +
qtoString(fullFilename, line + 1, level) +
" name=" +
q(
list[1]) +
" comment=" +
q(
list[2]) +
" />\n";
940 c->odbs->RS((std::string(
"Param/Value/") +
list[1]).c_str(), &v,
true);
941 c->odbs->WS((std::string(
"Param/Comment/") +
list[1]).c_str(),
list[2]);
942 }
else if (!
list[4][0]) {
943 xml +=
"<Param " +
qtoString(fullFilename, line + 1, level) +
" name=" +
q(
list[1]) +
" comment=" +
q(
list[2]) +
" default=" +
q(
list[3]) +
" />\n";
944 std::string v(
list[3]);
945 c->odbs->RS((std::string(
"Param/Value/") +
list[1]).c_str(), &v,
true);
946 c->odbs->WS((std::string(
"Param/Comment/") +
list[1]).c_str(),
list[2]);
947 c->odbs->WS((std::string(
"Param/Defaults/") +
list[1]).c_str(),
list[3]);
950 xml +=
"<Param " +
qtoString(fullFilename, line + 1, level) +
" name=" +
q(
list[1]) +
" comment=" +
q(
list[2]) +
953 c->odbs->RS((std::string(
"Param/Value/") +
list[1]).c_str(), &v,
true);
954 c->odbs->WS((std::string(
"Param/Comment/") +
list[1]).c_str(),
list[2]);
955 std::vector<std::string> options;
956 for (
i = 3;
i < 100 &&
list[
i][0];
i++) {
961 options.push_back(
list[
i]);
964 c->odbs->WSA((std::string(
"Param/Options/") +
list[1]).c_str(), options, 0);
969 std::string ov = oldSeqParam[(
const char *)
list[1]];
970 c->odbs->WS((std::string(
"Param/Value/") +
list[1]).c_str(), ov.c_str());
974 xml +=
"<RunDescription " +
qtoString(fullFilename, line + 1, level) +
">" +
list[1] +
"</RunDescription>\n";
977 if (
list[2][0] == 0) {
978 xml +=
"<Script " +
qtoString(fullFilename, line + 1, level) +
">" +
list[1] +
"</Script>\n";
980 xml +=
"<Script " +
qtoString(fullFilename, line + 1, level) +
" params=\"";
981 for (
i = 2;
i < 100 &&
list[
i][0];
i++) {
989 xml +=
"</Script>\n";
993 xml +=
"<Set " +
qtoString(fullFilename, line + 1, level) +
" name=" +
q(
list[1]) +
">" +
list[2] +
"</Set>\n";
996 xml +=
"\n<Subroutine " +
qtoString(fullFilename, line + 1, level) +
" name=" +
q(
list[1]) +
">\n";
999 xml +=
"</Subroutine>\n";
1002 xml +=
"<Transition " +
qtoString(fullFilename, line + 1, level) +
">" +
list[1] +
"</Transition>\n";
1006 xml +=
"<Wait " +
qtoString(fullFilename, line + 1, level) +
" for=\"seconds\">" +
list[1] +
"</Wait>\n";
1007 }
else if (!
list[3][0]) {
1008 xml +=
"<Wait " +
qtoString(fullFilename, line + 1, level) +
" for=" +
q(
list[1]) +
">" +
list[2] +
"</Wait>\n";
1010 xml +=
"<Wait " +
qtoString(fullFilename, line + 1, level) +
" for=" +
q(
list[1]) +
" path=" +
q(
list[2]) +
" op=" +
1022 snprintf(error, error_size,
"WAIT timeout is only supported for WAIT ODBValue");
1023 *error_line = line + 1;
1027 snprintf(error, error_size,
1028 "Invalid WAIT ODBValue timeout syntax. Use: WAIT ODBValue, path, op, value, timeout, seconds[, status_variable]");
1029 *error_line = line + 1;
1032 xml +=
" timeout=" +
q(
list[6]);
1034 xml +=
" status=" +
q(
list[7]);
1037 xml +=
">" + std::string(
list[4]) +
"</Wait>\n";
1040 }
else if (
list[0][0] == 0 ||
list[0][0] ==
'#') {
1043 snprintf(error, error_size,
"Invalid command \"%s\"",
list[0]);
1044 *error_line = line + 1;
1052 xml +=
"\n</Library>\n";
1054 xml +=
"</RunSequence>\n";
1058 fprintf(fout,
"%s", xml.c_str());
1072 cm_msg(
MERROR,
"seq_read",
"Cannot find /Sequencer/State in ODB, db_find_key() status %d",
status);
1079 cm_msg(
MERROR,
"seq_read",
"Cannot get /Sequencer/State from ODB, db_get_record1() status %d",
status);
1090 cm_msg(
MERROR,
"seq_write",
"Cannot find /Sequencer/State in ODB, db_find_key() status %d",
status);
1095 cm_msg(
MERROR,
"seq_write",
"Cannot write to ODB /Sequencer/State, db_set_record() status %d",
status);
1157 midas::odb defaults(std::string(
"/") +
c->odb_path +
"/Param/Defaults");
1159 midas::odb vars(std::string(
"/") +
c->odb_path +
"/Variables");
1163 if (!
param.is_subkey(
d.get_name())) {
1164 mstrlcpy(seq.
error,
"Cannot start script because /Sequencer/Param/Value is incomplete",
sizeof(seq.
error));
1166 cm_msg(
MERROR,
"sequencer",
"Cannot start script because /Sequencer/Param/Value is incomplete");
1172 vars[p.get_name()] = p.
s();
1175 mstrlcpy(seq.
error,
"Cannot start script, no script loaded",
sizeof(seq.
error));
1189 cm_msg(
MTALK,
"sequencer",
"Sequencer started with script \"%s\" in debugging mode.", seq.
filename);
1201 path +=
"userfiles/sequencer/";
1245 for (
int i = 1;
i < mxml_get_line_number_end(mxml_find_node(
c->pnseq,
"RunSequence"));
i++) {
1246 PMXML_NODE pt = mxml_get_node_at_line(
c->pnseq,
i);
1249 if (
equal_ustring(mxml_get_attribute(pt,
"name"),
"ATEXIT")) {
1252 seq_error(seq,
c,
"Maximum subroutine level exceeded");
1299 mxml_free_tree(
c->pnseq);
1302 c->odbs->WS(
"Script/Lines",
"");
1305 int size = (int)strlen(
str) + 1;
1306 char *xml_filename = (
char *) malloc(size);
1307 mstrlcpy(xml_filename,
str, size);
1308 strsubst(xml_filename, size,
".msl",
".xml");
1312 path +=
"userfiles/sequencer/";
1314 if (xml_filename[0] ==
'/') {
1315 path += xml_filename;
1316 path = path.substr(0, path.find_last_of(
'/') + 1);
1317 mstrlcpy(xml_filename, path.substr(path.find_last_of(
'/') + 1).c_str(), size);
1324 std::string fn(path);
1325 if (!fn.empty() && fn.back() !=
'/')
1345 for (
int i=0 ;
i<9 ;
i++)
1364 if (
c->seqp->new_file) {
1365 mstrlcpy(
str,
c->seqp->path,
sizeof(
str));
1368 mstrlcat(
str,
c->seqp->filename,
sizeof(
str));
1395 std::string context;
1396 PMXML_NODE pr = mxml_find_node(
c->pnseq,
"RunSequence");
1401 for (
int i = 1;
i <= mxml_get_line_number_end(pr);
i++) {
1402 PMXML_NODE pt = mxml_get_node_at_line(
c->pnseq,
i);
1406 const char *
name = mxml_get_name(pt);
1410 int start_line = mxml_get_line_number_start(pt);
1411 int end_line = mxml_get_line_number_end(pt);
1417 if (line > start_line && line < end_line)
1418 context +=
msprintf(
"%s:%d:%d;",
name, start_line, end_line);
1428 int target_line = 0;
1429 int target_sline_found = 0;
1432 if (target_sline <= 0) {
1433 cm_msg(
MERROR,
"sequencer",
"Goto line command ignored: invalid line number %d", target_sline);
1437 if (
c->pnseq == NULL) {
1438 cm_msg(
MERROR,
"sequencer",
"Goto line command ignored: no script loaded");
1442 pr = mxml_find_node(
c->pnseq,
"RunSequence");
1444 cm_msg(
MERROR,
"sequencer",
"Goto line command ignored: cannot find <RunSequence> tag in XML file");
1451 for (
int i = 1;
i <= mxml_get_line_number_end(pr);
i++) {
1452 pt = mxml_get_node_at_line(
c->pnseq,
i);
1453 if (pt && mxml_get_attribute(pt,
"l")) {
1454 int sline = atoi(mxml_get_attribute(pt,
"l"));
1456 if (sline >= target_sline && (best_sline == 0 || sline < best_sline)) {
1458 target_sline_found = sline;
1464 if (target_line == 0) {
1466 "Goto line %d failed: no executable sequencer command found at or after this source line",
1474 cm_msg(
MERROR,
"sequencer",
"Goto line command ignored: sequencer is not running");
1485 if (current_context != target_context) {
1487 "Goto line command ignored: source line %d resolves to line %d, which is in a different LOOP/IF/SUBROUTINE context",
1488 target_sline, target_sline_found);
1493 "Goto line command: moving from source line %d to source line %d.",
1510 bool start_script =
false;
1511 bool stop_immediately =
false;
1512 bool stop_after_run =
false;
1513 bool cancel_stop_after_run =
false;
1514 bool pause_script =
false;
1515 bool resume_script =
false;
1516 bool debug_script =
false;
1517 bool step_over =
false;
1518 bool load_new_file =
false;
1520 int goto_line_size =
sizeof(goto_line);
1522 c->odbs->RB(
"Command/Start script", &start_script);
1523 c->odbs->RB(
"Command/Stop immediately", &stop_immediately);
1524 c->odbs->RB(
"Command/Stop after run", &stop_after_run);
1525 c->odbs->RB(
"Command/Cancel stop after run", &cancel_stop_after_run);
1526 c->odbs->RB(
"Command/Pause script", &pause_script);
1527 c->odbs->RB(
"Command/Resume script", &resume_script);
1528 c->odbs->RB(
"Command/Debug script", &debug_script);
1529 c->odbs->RB(
"Command/Step over", &step_over);
1530 c->odbs->RB(
"Command/Load new file", &load_new_file);
1533 if (load_new_file) {
1534 std::string filename;
1535 c->odbs->RS(
"State/Filename", &filename);
1539 if (filename.find(
"..") != std::string::npos) {
1540 mstrlcpy(seqp->
error,
"Cannot load \"",
sizeof(seqp->
error));
1541 mstrlcat(seqp->
error, filename.c_str(),
sizeof(seqp->
error));
1542 mstrlcat(seqp->
error,
"\": file names with \"..\" is not permitted",
sizeof(seqp->
error));
1544 }
else if (filename.find(
".msl") == std::string::npos) {
1545 mstrlcpy(seqp->
error,
"Cannot load \"",
sizeof(seqp->
error));
1546 mstrlcat(seqp->
error, filename.c_str(),
sizeof(seqp->
error));
1547 mstrlcat(seqp->
error,
"\": file name should end with \".msl\"",
sizeof(seqp->
error));
1552 if (path.length() > 0 && path.back() !=
'/') {
1563 c->odbs->WB(
"Command/Load new file",
false);
1568 if (goto_line != 0) {
1577 c->odbs->WB(
"Command/Start script",
false);
1579 bool seq_running =
false;
1580 c->odbs->RB(
"State/running", &seq_running);
1585 cm_msg(
MTALK,
"sequencer",
"Sequencer is already running");
1589 if (stop_immediately &&
c->pnseq != NULL) {
1591 c->odbs->WB(
"Command/Stop immediately",
false);
1593 cm_msg(
MTALK,
"sequencer",
"Sequencer is finished by \"stop immediately\".");
1595 c->odbs->WB(
"Command/Stop immediately",
false);
1596 cm_msg(
MTALK,
"sequencer",
"Sequencer received \"stop immediately\". Executing ATEXIT.");
1600 if (stop_after_run) {
1601 c->odbs->WB(
"Command/Stop after run",
false);
1605 if (cancel_stop_after_run) {
1606 c->odbs->WB(
"Command/Cancel stop after run",
false);
1612 c->odbs->WB(
"Command/Pause script",
false);
1613 cm_msg(
MTALK,
"sequencer",
"Sequencer is paused.");
1616 if (resume_script) {
1618 c->odbs->WB(
"Command/Resume script",
false);
1619 cm_msg(
MTALK,
"sequencer",
"Sequencer is resumed.");
1623 c->odbs->WB(
"Command/Debug script",
false);
1625 bool seq_running =
false;
1626 c->odbs->RB(
"State/running", &seq_running);
1631 cm_msg(
MTALK,
"sequencer",
"Sequencer is already running");
1637 c->odbs->WB(
"Command/Step over",
false);
1646 *index1 = *index2 = 0;
1647 if (odbpath[strlen(odbpath) - 1] ==
']') {
1648 if (strchr(odbpath,
'[')) {
1650 if (strchr((strchr(odbpath,
'[') + 1),
'$')) {
1651 mstrlcpy(
str, strchr(odbpath,
'[') + 1,
sizeof(
str));
1652 if (strchr(
str,
']'))
1653 *strchr(
str,
']') = 0;
1656 *strchr(odbpath,
'[') = 0;
1673 std::vector<HNDLE> keys;
1681 size =
sizeof(
data);
1714 PMXML_NODE
pn, pr, pt, pe;
1715 char odbpath[256],
data[256],
str[1024],
name[32], op[32];
1718 int i,
j, l,
n,
status, size, index1, index2,
state,
run_number, cont;
1729 if (
c->pnseq == NULL) {
1731 mstrlcpy(seq.
error,
"No script loaded",
sizeof(seq.
error));
1746 pr = mxml_find_node(
c->pnseq,
"RunSequence");
1748 seq_error(seq,
c,
"Cannot find <RunSequence> tag in XML file");
1752 int last_line = mxml_get_line_number_end(pr);
1762 cm_msg(
MTALK,
"sequencer",
"Sequencer is finished.");
1782 cm_msg(
MTALK,
"sequencer",
"Sequencer is finished.");
1808 if (mxml_get_attribute(
pn,
"var")) {
1809 mstrlcpy(
name, mxml_get_attribute(
pn,
"var"),
sizeof(
name));
1810 if (mxml_get_attribute(
pn,
"values")) {
1811 mstrlcpy(
data, mxml_get_attribute(
pn,
"values"),
sizeof(
data));
1814 }
else if (mxml_get_attribute(
pn,
"n")) {
1817 sprintf(
str,
"Variables/%s",
name);
1818 size =
value.length() + 1;
1869 if (mxml_get_attribute(
pn,
"l"))
1871 if (mxml_get_attribute(
pn,
"fn")) {
1872 std::string filename = mxml_get_attribute(
pn,
"fn");
1875 if (filename != std::string(seq.
sfilename)) {
1881 if (mxml_get_attribute(
pn,
"l") && (!mxml_get_attribute(
pn,
"lvl") || atoi(mxml_get_attribute(
pn,
"lvl")) == 0))
1890 midas::odb o(
"/" +
c->odb_path +
"/Script/Lines");
1905 if (!mxml_get_attribute(
pn,
"path")) {
1906 seq_error(seq,
c,
"Missing attribute \"path\"");
1909 std::string s = mxml_get_attribute(
pn,
"path");
1910 if (s.find(
'$') != std::string::npos)
1914 if (mxml_get_attribute(
pn,
"notify"))
1923 if (!mxml_get_attribute(
pn,
"path")) {
1924 seq_error(seq,
c,
"Missing attribute \"path\"");
1926 mstrlcpy(odbpath, seq.
subdir,
sizeof(odbpath));
1927 if (strlen(odbpath) > 0 && odbpath[strlen(odbpath) - 1] !=
'/')
1928 mstrlcat(odbpath,
"/",
sizeof(odbpath));
1929 mstrlcat(odbpath, mxml_get_attribute(
pn,
"path"),
sizeof(odbpath));
1931 if (strchr(odbpath,
'$')) {
1932 if (strchr(odbpath,
'[')) {
1934 std::string s(odbpath);
1935 std::string s1 = s.substr(0, s.find(
'['));
1936 std::string s2 = s.substr(s.find(
'['));
1939 mstrlcpy(odbpath, s1.c_str(),
sizeof(odbpath));
1942 std::string s(odbpath);
1944 mstrlcpy(odbpath, s.c_str(),
sizeof(odbpath));
1951 if (mxml_get_attribute(
pn,
"notify"))
1952 notify = atoi(mxml_get_attribute(
pn,
"notify"));
1954 index1 = index2 = 0;
1957 if (index1 < -1 || index2 < 0) {
1958 seq_error(seq,
c,
"Negative index not allowed");
1962 if (index1 > 1E6 || index2 > 1E6) {
1963 seq_error(seq,
c,
"Index too large for ODB");
1976 sprintf(
str,
"ODB key \"%s\" not found", odbpath);
1979 sprintf(
str,
"Invalid index %d for ODB key \"%s\"", index1, odbpath);
1983 sprintf(
str,
"Internal error %d",
status);
1992 if (mxml_get_value(
pn)[0] ==
'/') {
1996 path +=
"userfiles/sequencer/";
1998 value += std::string(mxml_get_value(
pn)+1);
2002 path +=
"userfiles/sequencer/";
2005 if (
value.back() !=
'/')
2010 if (
value.find(
'$') != std::string::npos)
2014 if (mxml_get_attribute(
pn,
"path")) {
2015 mstrlcpy(odbpath, seq.
subdir,
sizeof(odbpath));
2016 if (strlen(odbpath) > 0 && odbpath[strlen(odbpath) - 1] !=
'/')
2017 mstrlcat(odbpath,
"/",
sizeof(odbpath));
2018 mstrlcat(odbpath, mxml_get_attribute(
pn,
"path"),
sizeof(odbpath));
2020 if (strchr(odbpath,
'$')) {
2021 std::string s(odbpath);
2023 mstrlcpy(odbpath, s.c_str(),
sizeof(odbpath));
2047 seq_error(seq,
c,
"Internal error loading ODB file!");
2054 if (mxml_get_value(
pn)[0] ==
'/') {
2058 path +=
"userfiles/sequencer/";
2060 value += std::string(mxml_get_value(
pn)+1);
2064 path +=
"userfiles/sequencer/";
2068 size_t pos =
value.find_last_of(
'/');
2069 if (pos != std::string::npos)
2074 if (
value.find(
'$') != std::string::npos)
2078 if (mxml_get_attribute(
pn,
"path") && *mxml_get_attribute(
pn,
"path")) {
2079 mstrlcpy(odbpath, seq.
subdir,
sizeof(odbpath));
2080 if (strlen(odbpath) > 0 && odbpath[strlen(odbpath) - 1] !=
'/')
2081 mstrlcat(odbpath,
"/",
sizeof(odbpath));
2082 mstrlcat(odbpath, mxml_get_attribute(
pn,
"path"),
sizeof(odbpath));
2084 if (strchr(odbpath,
'$')) {
2085 std::string s(odbpath);
2087 mstrlcpy(odbpath, s.c_str(),
sizeof(odbpath));
2096 if (strstr(
value.c_str(),
".json") || strstr(
value.c_str(),
".JSON") || strstr(
value.c_str(),
".js") || strstr(
value.c_str(),
".JS"))
2098 else if (strstr(
value.c_str(),
".xml") || strstr(
value.c_str(),
".XML"))
2108 seq_error(seq,
c,
"No ODB path specified in ODBSAVE command");
2120 seq_error(seq,
c,
"Internal error loading ODB file!");
2127 if (!mxml_get_attribute(
pn,
"path")) {
2128 seq_error(seq,
c,
"Missing attribute \"path\"");
2130 mstrlcpy(odbpath, seq.
subdir,
sizeof(odbpath));
2131 if (strlen(odbpath) > 0 && odbpath[strlen(odbpath) - 1] !=
'/')
2132 mstrlcat(odbpath,
"/",
sizeof(odbpath));
2133 mstrlcat(odbpath, mxml_get_attribute(
pn,
"path"),
sizeof(odbpath));
2135 if (strchr(odbpath,
'$')) {
2136 if (strchr(odbpath,
'[')) {
2138 std::string s(odbpath);
2139 std::string s1 = s.substr(0, s.find(
'['));
2140 std::string s2 = s.substr(s.find(
'['));
2143 mstrlcpy(odbpath, s1.c_str(),
sizeof(odbpath));
2146 std::string s(odbpath);
2148 mstrlcpy(odbpath, s.c_str(),
sizeof(odbpath));
2153 index1 = index2 = 0;
2156 mstrlcpy(
name, mxml_get_value(
pn),
sizeof(
name));
2163 size =
sizeof(
data);
2167 value = *((
int *)
data) > 0 ?
"1" :
"0";
2171 sprintf(
str,
"Variables/%s",
name);
2172 size =
value.length() + 1;
2186 if (!mxml_get_attribute(
pn,
"path")) {
2187 seq_error(seq,
c,
"Missing attribute \"path\"");
2188 }
else if (!mxml_get_attribute(
pn,
"string")) {
2189 seq_error(seq,
c,
"Missing attribute \"string\"");
2191 mstrlcpy(odbpath, seq.
subdir,
sizeof(odbpath));
2192 if (strlen(odbpath) > 0 && odbpath[strlen(odbpath) - 1] !=
'/')
2193 mstrlcat(odbpath,
"/",
sizeof(odbpath));
2194 mstrlcat(odbpath, mxml_get_attribute(
pn,
"path"),
sizeof(odbpath));
2196 if (strchr(odbpath,
'$')) {
2197 if (strchr(odbpath,
'[')) {
2199 std::string s(odbpath);
2200 std::string s1 = s.substr(0, s.find(
'['));
2201 std::string s2 = s.substr(s.find(
'['));
2204 mstrlcpy(odbpath, s1.c_str(),
sizeof(odbpath));
2207 std::string s(odbpath);
2209 mstrlcpy(odbpath, s.c_str(),
sizeof(odbpath));
2213 mstrlcpy(
name, mxml_get_value(
pn),
sizeof(
name));
2215 auto s =
eval_var(seq,
c, mxml_get_attribute(
pn,
"string"));
2216 mstrlcpy(
str, s.c_str(),
sizeof(
str));
2227 size =
sizeof(
data);
2229 if (strcmp((
const char *)
data,
str) == 0)
2237 snprintf(
str,
sizeof(
str),
"\"ODBLOOKUP %s\" did not find string \"%s\"", odbpath, s.c_str());
2242 snprintf(
str,
sizeof(
str),
"Variables/%s",
name);
2243 size =
value.length() + 1;
2257 if (!mxml_get_attribute(
pn,
"path")) {
2258 seq_error(seq,
c,
"Missing attribute \"path\"");
2260 mstrlcpy(odbpath, seq.
subdir,
sizeof(odbpath));
2261 if (strlen(odbpath) > 0 && odbpath[strlen(odbpath) - 1] !=
'/')
2262 mstrlcat(odbpath,
"/",
sizeof(odbpath));
2263 mstrlcat(odbpath, mxml_get_attribute(
pn,
"path"),
sizeof(odbpath));
2265 if (strchr(odbpath,
'$')) {
2266 if (strchr(odbpath,
'[')) {
2268 std::string s(odbpath);
2269 std::string s1 = s.substr(0, s.find(
'['));
2270 std::string s2 = s.substr(s.find(
'['));
2273 mstrlcpy(odbpath, s1.c_str(),
sizeof(odbpath));
2276 std::string s(odbpath);
2278 mstrlcpy(odbpath, s.c_str(),
sizeof(odbpath));
2282 index1 = index2 = 0;
2292 size =
sizeof(
data);
2297 sprintf(
str,
"%lg",
d);
2298 size =
sizeof(
data);
2304 if (mxml_get_attribute(
pn,
"notify"))
2305 notify = atoi(mxml_get_attribute(
pn,
"notify"));
2315 mstrlcpy(odbpath, seq.
subdir,
sizeof(odbpath));
2316 if (strlen(odbpath) > 0 && odbpath[strlen(odbpath) - 1] !=
'/')
2317 mstrlcat(odbpath,
"/",
sizeof(odbpath));
2318 mstrlcat(odbpath, mxml_get_value(
pn),
sizeof(odbpath));
2320 if (strchr(odbpath,
'$')) {
2321 std::string s(odbpath);
2323 mstrlcpy(odbpath, s.c_str(),
sizeof(odbpath));
2336 if (!mxml_get_attribute(
pn,
"path")) {
2337 seq_error(seq,
c,
"Missing attribute \"path\"");
2338 }
else if (!mxml_get_attribute(
pn,
"type")) {
2339 seq_error(seq,
c,
"Missing attribute \"type\"");
2341 mstrlcpy(odbpath, seq.
subdir,
sizeof(odbpath));
2342 if (strlen(odbpath) > 0 && odbpath[strlen(odbpath) - 1] !=
'/')
2343 mstrlcat(odbpath,
"/",
sizeof(odbpath));
2344 mstrlcat(odbpath, mxml_get_attribute(
pn,
"path"),
sizeof(odbpath));
2346 if (strchr(odbpath,
'$')) {
2347 std::string s(odbpath);
2349 mstrlcpy(odbpath, s.c_str(),
sizeof(odbpath));
2354 for (tid = 0; tid <
TID_LAST; tid++) {
2360 seq_error(seq,
c,
"Type must be one of UINT8,INT8,UINT16,INT16,UINT32,INT32,BOOL,FLOAT,DOUBLE,STRING");
2373 memset(dummy, 0,
sizeof(dummy));
2382 if (mxml_get_attribute(
pn,
"size")) {
2383 i = atoi(
eval_var(seq,
c, mxml_get_attribute(
pn,
"size")).c_str());
2401 sprintf(
str,
"%s", mxml_get_value(
pn));
2403 if (mxml_get_attribute(
pn,
"params")) {
2404 mstrlcpy(
data, mxml_get_attribute(
pn,
"params"),
sizeof(
data));
2406 for (
i = 0;
i <
n;
i++) {
2410 mstrlcat(
str,
" ",
sizeof(
str));
2417 std::string r =
ss_execs(s.c_str());
2430 size =
sizeof(
state);
2442 size =
sizeof(
state);
2452 size =
sizeof(
state);
2464 size =
sizeof(
state);
2479 cm_msg(
MTALK,
"sequencer",
"Sequencer is finished by \"stop after current run\".");
2481 cm_msg(
MTALK,
"sequencer",
"Sequencer is going to finish by \"stop after current run\". Executing ATEXIT.");
2499 n = atoi(
eval_var(seq,
c, mxml_get_value(
pn)).c_str());
2517 }
else if (
equal_ustring(mxml_get_attribute(
pn,
"for"),
"ODBValue")) {
2520 if (!mxml_get_attribute(
pn,
"path")) {
2521 seq_error(seq,
c,
"\"path\" must be given for ODB values");
2524 mstrlcpy(odbpath, mxml_get_attribute(
pn,
"path"),
sizeof(odbpath));
2527 if (strchr(odbpath,
'$')) {
2528 if (strchr(odbpath,
'[')) {
2530 std::string s(odbpath);
2531 std::string s1 = s.substr(0, s.find(
'['));
2532 std::string s2 = s.substr(s.find(
'['));
2535 mstrlcpy(odbpath, s1.c_str(),
sizeof(odbpath));
2538 std::string s(odbpath);
2540 mstrlcpy(odbpath, s.c_str(),
sizeof(odbpath));
2544 index1 = index2 = 0;
2551 if (mxml_get_attribute(
pn,
"op"))
2552 mstrlcpy(op, mxml_get_attribute(
pn,
"op"),
sizeof(op));
2558 size =
sizeof(
data);
2561 value = *((
int *)
data) > 0 ?
"1" :
"0";
2588 bool timed_out =
false;
2589 const char *timeout_attr = mxml_get_attribute(
pn,
"timeout");
2590 if (timeout_attr && timeout_attr[0]) {
2591 float timeout_sec = (float) atof(
eval_var(seq,
c, timeout_attr).c_str());
2592 if (timeout_sec < 0) {
2593 seq_error(seq,
c,
msprintf(
"Invalid WAIT ODBValue timeout \"%s\"", timeout_attr).c_str());
2608 timed_out = elapsed_ms > (
DWORD) (1000.0f * timeout_sec);
2614 if (cont || timed_out) {
2615 if (mxml_get_attribute(
pn,
"status")) {
2616 const char *status_value = (cont && !timed_out) ?
"1" :
"0";
2618 mstrlcpy(
name, mxml_get_attribute(
pn,
"status"),
sizeof(
name));
2619 snprintf(
str,
sizeof(
str),
"Variables/%s",
name);
2620 size = strlen(status_value) + 1;
2626 if (timed_out && !cont) {
2627 cm_msg(
MINFO,
"sequencer",
"WAIT ODBValue timeout after %.1f seconds: %s %s %g not satisfied",
2665 seq_error(seq,
c,
msprintf(
"Invalid wait attribute \"%s\"", mxml_get_attribute(
pn,
"for")).c_str());
2678 seq_error(seq,
c,
"Maximum loop nesting exceeded");
2683 if (mxml_get_attribute(
pn,
"l"))
2685 if (mxml_get_attribute(
pn,
"le"))
2689 if (mxml_get_attribute(
pn,
"n")) {
2696 }
else if (mxml_get_attribute(
pn,
"values")) {
2697 mstrlcpy(
data, mxml_get_attribute(
pn,
"values"),
sizeof(
data));
2701 seq_error(seq,
c,
"Missing \"var\" or \"n\" attribute");
2705 if (mxml_get_attribute(
pn,
"var")) {
2706 mstrlcpy(
name, mxml_get_attribute(
pn,
"var"),
sizeof(
name));
2707 sprintf(
str,
"Variables/%s",
name);
2708 size =
value.length() + 1;
2739 seq_error(seq,
c,
"\"Break\" outside any loop");
2752 seq_error(seq,
c,
"Maximum number of nested if..endif exceeded");
2763 pe = mxml_get_node_at_line(
c->pnseq,
j);
2767 j = mxml_get_line_number_end(pe);
2778 mstrlcpy(
str, mxml_get_attribute(
pn,
"condition"),
sizeof(
str));
2781 seq_error(seq,
c,
"Invalid number in comparison");
2808 cm_msg(
MTALK,
"sequencer",
"Sequencer is finished.");
2814 if (!mxml_get_attribute(
pn,
"line") && !mxml_get_attribute(
pn,
"sline")) {
2818 if (mxml_get_attribute(
pn,
"line")) {
2821 if (mxml_get_attribute(
pn,
"sline")) {
2822 mstrlcpy(
str,
eval_var(seq,
c, mxml_get_attribute(
pn,
"sline")).c_str(),
sizeof(
str));
2823 for (
i = 0;
i < last_line;
i++) {
2824 pt = mxml_get_node_at_line(
c->pnseq,
i);
2825 if (pt && mxml_get_attribute(pt,
"l")) {
2826 l = atoi(mxml_get_attribute(pt,
"l"));
2827 if (atoi(
str) == l) {
2856 if (!mxml_get_attribute(
pn,
"name")) {
2860 mstrlcpy(
name, mxml_get_attribute(
pn,
"name"),
sizeof(
name));
2863 if (strchr(
name,
'[')) {
2865 mstrlcpy(
str, strchr(
name,
'[')+1,
sizeof(
str));
2866 if (strchr(
str,
']'))
2867 *strchr(
str,
']') = 0;
2869 *strchr(
name,
'[') = 0;
2870 sprintf(
str,
"Variables/%s",
name);
2876 size =
value.length() + 1;
2881 sprintf(
str,
"Variables/%s",
name);
2882 size =
value.length() + 1;
2892 if (mxml_get_attribute(pr,
"var")) {
2903 if (strchr(mxml_get_value(
pn),
'$'))
2907 const char *wait_attr = mxml_get_attribute(
pn,
"wait");
2910 wait = (atoi(wait_attr) == 1);
2946 if (strchr(mxml_get_value(
pn),
'$'))
2950 std::string
type =
"INFO";
2951 if (mxml_get_attribute(
pn,
"type"))
2952 type = std::string(mxml_get_attribute(
pn,
"type"));
2954 if (
type ==
"ERROR")
2956 else if (
type ==
"DEBUG")
2958 else if (
type ==
"LOG")
2960 else if (
type ==
"TALK")
2970 if (!mxml_get_attribute(
pn,
"name")) {
2974 mstrlcpy(
name, mxml_get_attribute(
pn,
"name"),
sizeof(
name));
2977 sprintf(
str,
"Variables/%s",
name);
2978 size = strlen(
data) + 1;
2989 seq_error(seq,
c,
"Maximum subroutine level exceeded");
2998 for (
i = 1;
i < mxml_get_line_number_end(mxml_find_node(
c->pnseq,
"RunSequence"));
i++) {
2999 pt = mxml_get_node_at_line(
c->pnseq,
i);
3002 if (
equal_ustring(mxml_get_attribute(pt,
"name"), mxml_get_attribute(
pn,
"name"))) {
3008 if (mxml_get_value(
pn)) {
3010 if (strchr(mxml_get_value(
pn),
'$'))
3011 mstrlcpy(p,
eval_var(seq,
c, mxml_get_value(
pn)).c_str(),
sizeof(p));
3013 mstrlcpy(p, mxml_get_value(
pn),
sizeof(p));
3024 if (
i == mxml_get_line_number_end(mxml_find_node(
c->pnseq,
"RunSequence"))) {
3025 seq_error(seq,
c,
msprintf(
"Subroutine '%s' not found", mxml_get_attribute(
pn,
"name")).c_str());
3037 size =
sizeof(seq1);
3048 if (seq.
debug && !skip_step)
3061 c->odbs =
gOdb->Chdir(
c->odb_path.c_str(),
true);
3066 cm_msg(
MERROR,
"init_sequencer",
"Sequencer error: Cannot find /Sequencer, db_find_key() status %d",
status);
3072 cm_msg(
MERROR,
"init_sequencer",
"Sequencer error: mismatching /Sequencer/State structure, db_check_record() status %d",
status);
3078 cm_msg(
MERROR,
"init_sequencer",
"Sequencer error: Cannot find /Sequencer/State, db_find_key() status %d",
status);
3082 int size =
sizeof(seq);
3085 cm_msg(
MERROR,
"init_sequencer",
"Sequencer error: Cannot get /Sequencer/State, db_get_record1() status %d",
status);
3102 cm_msg(
MERROR,
"init_sequencer",
"Sequencer error: Cannot watch /Sequencer/State, db_watch() status %d",
status);
3107 {
"Start script",
false},
3108 {
"Stop immediately",
false},
3109 {
"Stop after run",
false},
3110 {
"Cancel stop after run",
false},
3111 {
"Pause script",
false},
3112 {
"Resume script",
false},
3113 {
"Debug script",
false},
3114 {
"Step over",
false},
3115 {
"Load new file",
false},
3122 cm_msg(
MERROR,
"init_sequencer",
"Sequencer error: Cannot find /Sequencer/Command, db_find_key() status %d",
status);
3128 cm_msg(
MERROR,
"init_sequencer",
"Sequencer error: Cannot watch /Sequencer/Command, db_watch() status %d",
status);
3135int main(
int argc,
const char *argv[]) {
3138 char midas_hostname[256];
3139 char midas_expt[256];
3140 std::string seq_name =
"";
3142 setbuf(stdout, NULL);
3143 setbuf(stderr, NULL);
3146 signal(SIGPIPE, SIG_IGN);
3150 cm_get_environment(midas_hostname,
sizeof(midas_hostname), midas_expt,
sizeof(midas_expt));
3153 for (
int i = 1;
i < argc;
i++) {
3154 if (argv[
i][0] ==
'-' && argv[
i][1] ==
'D') {
3156 }
else if (argv[
i][0] ==
'-') {
3157 if (
i + 1 >= argc || argv[
i + 1][0] ==
'-')
3159 if (argv[
i][1] ==
'h')
3160 mstrlcpy(midas_hostname, argv[++
i],
sizeof(midas_hostname));
3161 else if (argv[
i][1] ==
'e')
3162 mstrlcpy(midas_expt, argv[++
i],
sizeof(midas_hostname));
3163 else if (argv[
i][1] ==
'c')
3164 seq_name = argv[++
i];
3167 printf(
"usage: %s [-h Hostname[:port]] [-e Experiment] [-c Name] [-D]\n\n", argv[0]);
3168 printf(
" -e experiment to connect to\n");
3169 printf(
" -c Name of additional sequencer, i.e. \'Test\'\n");
3170 printf(
" -h connect to midas server (mserver) on given host\n");
3171 printf(
" -D become a daemon\n");
3177 printf(
"Becoming a daemon...\n");
3181 std::string prg_name =
"Sequencer";
3182 std::string odb_path =
"Sequencer";
3184 if (!seq_name.empty()) {
3185 prg_name = std::string(
"Sequencer") + seq_name;
3186 odb_path = std::string(
"Sequencer") + seq_name;
3190 std::string pid_filename;
3191 pid_filename +=
"/var/run/";
3192 pid_filename += prg_name;
3193 pid_filename +=
".pid";
3195 FILE *f = fopen(pid_filename.c_str(),
"w");
3218 printf(
"%s runs already.\n", prg_name.c_str());
3232 c.seq_name = seq_name;
3233 c.prg_name = prg_name;
3234 c.odb_path = odb_path;
3238 if (seq_name.empty()) {
3239 printf(
"Sequencer started. Stop with \"!\"\n");
3241 printf(
"%s started.\n", prg_name.c_str());
3242 printf(
"Set ODB String \"/Alias/Sequencer%s\" to URL \"?cmd=sequencer&seq_name=%s\"\n", seq_name.c_str(), seq_name.c_str());
3243 printf(
"Stop with \"!\"\n");
3256 }
catch (std::string &msg) {
3258 }
catch (
const char *msg) {
3270 if ((
char) ch ==
'!')
static bool exists(const std::string &name)
void set_auto_refresh_read(bool f)
void set_auto_create(bool f)
void connect_and_fix_structure(std::string path)
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 BOOL seq_goto_line(SEQUENCER &seq, SeqCon *c, int target_sline)
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_clear_wait_state(SEQUENCER &seq)
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)
static std::string seq_goto_context(SeqCon *c, int line)
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)