26#define XNAME_LENGTH 256
65 char c1, c2, *ps, *pp;
67 if (
str == NULL || pattern == NULL)
72 pp = (
char *) pattern;
75 if (toupper(c1) == toupper(c2)) {
80 if (toupper(c1) != toupper(c2))
98void strsubst(
char *
string,
int size,
const char *pattern,
const char *subst)
105 for (p =
stristr(p, pattern); p != NULL; p =
stristr(p, pattern)) {
107 if (strlen(pattern) == strlen(subst)) {
108 memcpy(p, subst, strlen(subst));
109 }
else if (strlen(pattern) > strlen(subst)) {
110 memcpy(p, subst, strlen(subst));
111 memmove(p + strlen(subst), p + strlen(pattern), strlen(p + strlen(pattern)) + 1);
113 tail = (
char *) malloc(strlen(p) - strlen(pattern) + 1);
114 strcpy(tail, p + strlen(pattern));
115 s = size - (p - string);
116 mstrlcpy(p, subst, s);
117 mstrlcat(p, tail, s);
130 snprintf(buf,
sizeof(buf),
"%d", v);
134static std::string
qtoString(std::string filename,
int line,
int level) {
135 std::string buf =
"l=\"" + std::to_string(line) +
"\"";
136 buf +=
" fn=\"" + filename +
"\"";
138 buf +=
" lvl=\"" + std::to_string(level) +
"\"";
142static std::string
q(
const char *s) {
143 return "\"" + std::string(s) +
"\"";
161 int n_lines_,
char** lines_,
char (*list_)[
XNAME_LENGTH], std::string& xml_,
162 char* error_,
int error_size_,
int* error_line_)
211 if (
list[2][0] ==
'1')
212 ctx.
xml +=
" wait=\"1\"";
215 ctx.
xml +=
"</Message>\n";
237 if (
list[2][0] == 0) {
241 for (
int i = 2;
i < 100 &&
list[
i][0];
i++) {
249 ctx.
xml +=
"</Script>\n";
269 for (
int i = 2;
i < 100 &&
list[
i][0];
i++) {
275 ctx.
xml +=
"</Cat>\n";
286 }
else if (!
list[3][0]) {
301 snprintf(ctx.
error, ctx.
error_size,
"WAIT timeout is only supported for WAIT ODBValue");
307 "Invalid WAIT ODBValue timeout syntax. Use: WAIT ODBValue, path, op, value, timeout, seconds[, status_variable]");
311 ctx.
xml +=
" timeout=" +
q(
list[6]);
316 ctx.
xml +=
">" + std::string(
list[4]) +
"</Wait>\n";
346 list[2] +
"</ODBSet>\n";
368 mstrlcpy(
list[2],
"1", 2);
381 q(
list[2]) +
"></ODBCreate>\n";
428 " string=" +
q(
list[2]) +
">" +
list[3] +
"</ODBLookup>\n";
437 PMXML_NODE
pn = ctx.
pn;
445 if (!mxml_get_attribute(
pn,
"path")) {
446 seq_error(seq,
c,
"Missing attribute \"path\"");
447 }
else if (!mxml_get_attribute(
pn,
"string")) {
448 seq_error(seq,
c,
"Missing attribute \"string\"");
450 mstrlcpy(odbpath, seq.
subdir,
sizeof(odbpath));
451 if (strlen(odbpath) > 0 && odbpath[strlen(odbpath) - 1] !=
'/')
452 mstrlcat(odbpath,
"/",
sizeof(odbpath));
453 mstrlcat(odbpath, mxml_get_attribute(
pn,
"path"),
sizeof(odbpath));
455 if (strchr(odbpath,
'$')) {
456 if (strchr(odbpath,
'[')) {
458 std::string s(odbpath);
459 std::string s1 = s.substr(0, s.find(
'['));
460 std::string s2 = s.substr(s.find(
'['));
463 mstrlcpy(odbpath, s1.c_str(),
sizeof(odbpath));
466 std::string s(odbpath);
468 mstrlcpy(odbpath, s.c_str(),
sizeof(odbpath));
472 mstrlcpy(
name, mxml_get_value(
pn),
sizeof(
name));
474 auto s =
eval_var(seq,
c, mxml_get_attribute(
pn,
"string"));
475 mstrlcpy(
str, s.c_str(),
sizeof(
str));
488 if (strcmp((
const char *)
data,
str) == 0)
496 snprintf(
str,
sizeof(
str),
"\"ODBLOOKUP %s\" did not find string \"%s\"", odbpath, s.c_str());
501 snprintf(
str,
sizeof(
str),
"Variables/%s",
name);
502 size =
value.length() + 1;
527 PMXML_NODE
pn = ctx.
pn;
530 if (strchr(mxml_get_value(
pn),
'$'))
534 const char *wait_attr = mxml_get_attribute(
pn,
"wait");
537 wait = (atoi(wait_attr) == 1);
576 PMXML_NODE
pn = ctx.
pn;
579 if (strchr(mxml_get_value(
pn),
'$'))
583 std::string
type =
"INFO";
584 if (mxml_get_attribute(
pn,
"type"))
585 type = std::string(mxml_get_attribute(
pn,
"type"));
589 else if (
type ==
"DEBUG")
591 else if (
type ==
"LOG")
593 else if (
type ==
"TALK")
606 PMXML_NODE
pn = ctx.
pn;
612 sprintf(
str,
"%s", mxml_get_value(
pn));
614 if (mxml_get_attribute(
pn,
"params")) {
615 mstrlcpy(
data, mxml_get_attribute(
pn,
"params"),
sizeof(
data));
617 for (
i = 0;
i <
n;
i++) {
621 mstrlcat(
str,
" ",
sizeof(
str));
628 std::string r =
ss_execs(s.c_str());
641 PMXML_NODE
pn = ctx.
pn;
648 if (!mxml_get_attribute(
pn,
"name")) {
653 mstrlcpy(
name, mxml_get_attribute(
pn,
"name"),
sizeof(
name));
656 if (strchr(
name,
'[')) {
658 mstrlcpy(
str, strchr(
name,
'[')+1,
sizeof(
str));
659 if (strchr(
str,
']'))
660 *strchr(
str,
']') = 0;
662 *strchr(
name,
'[') = 0;
663 sprintf(
str,
"Variables/%s",
name);
669 size =
value.length() + 1;
674 sprintf(
str,
"Variables/%s",
name);
675 size =
value.length() + 1;
685 if (mxml_get_attribute(pr,
"var")) {
699 PMXML_NODE
pn = ctx.
pn;
703 if (!mxml_get_attribute(
pn,
"name")) {
708 mstrlcpy(
name, mxml_get_attribute(
pn,
"name"),
sizeof(
name));
711 sprintf(
str,
"Variables/%s",
name);
712 size = strlen(
data) + 1;
725 PMXML_NODE
pn = ctx.
pn;
726 char odbpath[256],
data[256], op[32];
728 int n,
status, size, index1, index2, cont;
755 if (!mxml_get_attribute(
pn,
"path")) {
756 seq_error(seq,
c,
"\"path\" must be given for ODB values");
759 mstrlcpy(odbpath, mxml_get_attribute(
pn,
"path"),
sizeof(odbpath));
762 if (strchr(odbpath,
'$')) {
763 if (strchr(odbpath,
'[')) {
765 std::string s(odbpath);
766 std::string s1 = s.substr(0, s.find(
'['));
767 std::string s2 = s.substr(s.find(
'['));
770 mstrlcpy(odbpath, s1.c_str(),
sizeof(odbpath));
773 std::string s(odbpath);
775 mstrlcpy(odbpath, s.c_str(),
sizeof(odbpath));
786 if (mxml_get_attribute(
pn,
"op"))
787 mstrlcpy(op, mxml_get_attribute(
pn,
"op"),
sizeof(op));
823 bool timed_out =
false;
824 const char *timeout_attr = mxml_get_attribute(
pn,
"timeout");
825 if (timeout_attr && timeout_attr[0]) {
826 float timeout_sec = (float) atof(
eval_var(seq,
c, timeout_attr).c_str());
827 if (timeout_sec < 0) {
828 seq_error(seq,
c,
msprintf(
"Invalid WAIT ODBValue timeout \"%s\"", timeout_attr).c_str());
843 timed_out = elapsed_ms > (
DWORD) (1000.0f * timeout_sec);
849 if (cont || timed_out) {
850 if (mxml_get_attribute(
pn,
"status")) {
852 char status_path[256];
853 const char *status_value = (cont && !timed_out) ?
"1" :
"0";
855 mstrlcpy(status_name, mxml_get_attribute(
pn,
"status"),
sizeof(status_name));
856 snprintf(status_path,
sizeof(status_path),
"Variables/%s", status_name);
860 if (timed_out && !cont) {
861 cm_msg(
MINFO,
"sequencer",
"WAIT ODBValue timeout after %.1f seconds: %s %s %g not satisfied",
899 seq_error(seq,
c,
msprintf(
"Invalid wait attribute \"%s\"", mxml_get_attribute(
pn,
"for")).c_str());
919 PMXML_NODE
pn = ctx.
pn;
927 size =
sizeof(
state);
939 size =
sizeof(
state);
949 size =
sizeof(
state);
961 size =
sizeof(
state);
976 cm_msg(
MTALK,
"sequencer",
"Sequencer is finished by \"stop after current run\".");
978 cm_msg(
MTALK,
"sequencer",
"Sequencer is going to finish by \"stop after current run\". Executing ATEXIT.");
998 cm_msg(
MTALK,
"sequencer",
"Sequencer is finished.");
1006 PMXML_NODE
pn = ctx.
pn;
1008 char odbpath[256],
str[1024];
1010 int status, size, index1, index2;
1012 if (!mxml_get_attribute(
pn,
"path")) {
1013 seq_error(seq,
c,
"Missing attribute \"path\"");
1015 mstrlcpy(odbpath, seq.
subdir,
sizeof(odbpath));
1016 if (strlen(odbpath) > 0 && odbpath[strlen(odbpath) - 1] !=
'/')
1017 mstrlcat(odbpath,
"/",
sizeof(odbpath));
1018 mstrlcat(odbpath, mxml_get_attribute(
pn,
"path"),
sizeof(odbpath));
1020 if (strchr(odbpath,
'$')) {
1021 if (strchr(odbpath,
'[')) {
1023 std::string s(odbpath);
1024 std::string s1 = s.substr(0, s.find(
'['));
1025 std::string s2 = s.substr(s.find(
'['));
1028 mstrlcpy(odbpath, s1.c_str(),
sizeof(odbpath));
1031 std::string s(odbpath);
1033 mstrlcpy(odbpath, s.c_str(),
sizeof(odbpath));
1040 if (mxml_get_attribute(
pn,
"notify"))
1041 notify = atoi(mxml_get_attribute(
pn,
"notify"));
1043 index1 = index2 = 0;
1046 if (index1 < -1 || index2 < 0) {
1047 seq_error(seq,
c,
"Negative index not allowed");
1051 if (index1 > 1E6 || index2 > 1E6) {
1052 seq_error(seq,
c,
"Index too large for ODB");
1065 sprintf(
str,
"ODB key \"%s\" not found", odbpath);
1068 sprintf(
str,
"Invalid index %d for ODB key \"%s\"", index1, odbpath);
1072 sprintf(
str,
"Internal error %d",
status);
1085 PMXML_NODE
pn = ctx.
pn;
1087 char odbpath[256],
data[256],
str[1024],
name[32];
1089 int status, size, index1, index2;
1093 if (!mxml_get_attribute(
pn,
"path")) {
1094 seq_error(seq,
c,
"Missing attribute \"path\"");
1096 mstrlcpy(odbpath, seq.
subdir,
sizeof(odbpath));
1097 if (strlen(odbpath) > 0 && odbpath[strlen(odbpath) - 1] !=
'/')
1098 mstrlcat(odbpath,
"/",
sizeof(odbpath));
1099 mstrlcat(odbpath, mxml_get_attribute(
pn,
"path"),
sizeof(odbpath));
1101 if (strchr(odbpath,
'$')) {
1102 if (strchr(odbpath,
'[')) {
1104 std::string s(odbpath);
1105 std::string s1 = s.substr(0, s.find(
'['));
1106 std::string s2 = s.substr(s.find(
'['));
1109 mstrlcpy(odbpath, s1.c_str(),
sizeof(odbpath));
1112 std::string s(odbpath);
1114 mstrlcpy(odbpath, s.c_str(),
sizeof(odbpath));
1119 index1 = index2 = 0;
1122 mstrlcpy(
name, mxml_get_value(
pn),
sizeof(
name));
1129 size =
sizeof(
data);
1133 value = *((
int *)
data) > 0 ?
"1" :
"0";
1137 sprintf(
str,
"Variables/%s",
name);
1138 size =
value.length() + 1;
1156 PMXML_NODE
pn = ctx.
pn;
1157 char odbpath[256],
data[256],
str[1024];
1159 int status, size, index1, index2;
1164 if (!mxml_get_attribute(
pn,
"path")) {
1165 seq_error(seq,
c,
"Missing attribute \"path\"");
1167 mstrlcpy(odbpath, seq.
subdir,
sizeof(odbpath));
1168 if (strlen(odbpath) > 0 && odbpath[strlen(odbpath) - 1] !=
'/')
1169 mstrlcat(odbpath,
"/",
sizeof(odbpath));
1170 mstrlcat(odbpath, mxml_get_attribute(
pn,
"path"),
sizeof(odbpath));
1172 if (strchr(odbpath,
'$')) {
1173 if (strchr(odbpath,
'[')) {
1175 std::string s(odbpath);
1176 std::string s1 = s.substr(0, s.find(
'['));
1177 std::string s2 = s.substr(s.find(
'['));
1180 mstrlcpy(odbpath, s1.c_str(),
sizeof(odbpath));
1183 std::string s(odbpath);
1185 mstrlcpy(odbpath, s.c_str(),
sizeof(odbpath));
1189 index1 = index2 = 0;
1199 size =
sizeof(
data);
1204 sprintf(
str,
"%lg",
d);
1205 size =
sizeof(
data);
1211 if (mxml_get_attribute(
pn,
"notify"))
1212 notify = atoi(mxml_get_attribute(
pn,
"notify"));
1226 PMXML_NODE
pn = ctx.
pn;
1232 if (!mxml_get_attribute(
pn,
"path")) {
1233 seq_error(seq,
c,
"Missing attribute \"path\"");
1234 }
else if (!mxml_get_attribute(
pn,
"type")) {
1235 seq_error(seq,
c,
"Missing attribute \"type\"");
1237 mstrlcpy(odbpath, seq.
subdir,
sizeof(odbpath));
1238 if (strlen(odbpath) > 0 && odbpath[strlen(odbpath) - 1] !=
'/')
1239 mstrlcat(odbpath,
"/",
sizeof(odbpath));
1240 mstrlcat(odbpath, mxml_get_attribute(
pn,
"path"),
sizeof(odbpath));
1242 if (strchr(odbpath,
'$')) {
1243 std::string s(odbpath);
1245 mstrlcpy(odbpath, s.c_str(),
sizeof(odbpath));
1250 for (tid = 0; tid <
TID_LAST; tid++) {
1256 seq_error(seq,
c,
"Type must be one of UINT8,INT8,UINT16,INT16,UINT32,INT32,BOOL,FLOAT,DOUBLE,STRING");
1269 memset(dummy, 0,
sizeof(dummy));
1278 if (mxml_get_attribute(
pn,
"size")) {
1279 int i = atoi(
eval_var(seq,
c, mxml_get_attribute(
pn,
"size")).c_str());
1295 PMXML_NODE
pn = ctx.
pn;
1299 mstrlcpy(odbpath, seq.
subdir,
sizeof(odbpath));
1300 if (strlen(odbpath) > 0 && odbpath[strlen(odbpath) - 1] !=
'/')
1301 mstrlcat(odbpath,
"/",
sizeof(odbpath));
1302 mstrlcat(odbpath, mxml_get_value(
pn),
sizeof(odbpath));
1304 if (strchr(odbpath,
'$')) {
1305 std::string s(odbpath);
1307 mstrlcpy(odbpath, s.c_str(),
sizeof(odbpath));
1324 PMXML_NODE
pn = ctx.
pn;
1331 if (mxml_get_value(
pn)[0] ==
'/') {
1335 path +=
"userfiles/sequencer/";
1337 value += std::string(mxml_get_value(
pn)+1);
1341 path +=
"userfiles/sequencer/";
1344 if (
value.back() !=
'/')
1349 if (
value.find(
'$') != std::string::npos)
1353 if (mxml_get_attribute(
pn,
"path")) {
1354 mstrlcpy(odbpath, seq.
subdir,
sizeof(odbpath));
1355 if (strlen(odbpath) > 0 && odbpath[strlen(odbpath) - 1] !=
'/')
1356 mstrlcat(odbpath,
"/",
sizeof(odbpath));
1357 mstrlcat(odbpath, mxml_get_attribute(
pn,
"path"),
sizeof(odbpath));
1359 if (strchr(odbpath,
'$')) {
1360 std::string s(odbpath);
1362 mstrlcpy(odbpath, s.c_str(),
sizeof(odbpath));
1386 seq_error(seq,
c,
"Internal error loading ODB file!");
1397 PMXML_NODE
pn = ctx.
pn;
1404 if (mxml_get_value(
pn)[0] ==
'/') {
1408 path +=
"userfiles/sequencer/";
1410 value += std::string(mxml_get_value(
pn)+1);
1414 path +=
"userfiles/sequencer/";
1418 size_t pos =
value.find_last_of(
'/');
1419 if (pos != std::string::npos)
1424 if (
value.find(
'$') != std::string::npos)
1428 if (mxml_get_attribute(
pn,
"path") && *mxml_get_attribute(
pn,
"path")) {
1429 mstrlcpy(odbpath, seq.
subdir,
sizeof(odbpath));
1430 if (strlen(odbpath) > 0 && odbpath[strlen(odbpath) - 1] !=
'/')
1431 mstrlcat(odbpath,
"/",
sizeof(odbpath));
1432 mstrlcat(odbpath, mxml_get_attribute(
pn,
"path"),
sizeof(odbpath));
1434 if (strchr(odbpath,
'$')) {
1435 std::string s(odbpath);
1437 mstrlcpy(odbpath, s.c_str(),
sizeof(odbpath));
1446 if (strstr(
value.c_str(),
".json") || strstr(
value.c_str(),
".JSON") || strstr(
value.c_str(),
".js") || strstr(
value.c_str(),
".JS"))
1448 else if (strstr(
value.c_str(),
".xml") || strstr(
value.c_str(),
".XML"))
1458 seq_error(seq,
c,
"No ODB path specified in ODBSAVE command");
1470 seq_error(seq,
c,
"Internal error loading ODB file!");
1535 { NULL, NULL, NULL, NULL }
1566 std::stringstream ss;
1572 else if (num == 0 && s[0] !=
'0')
1598 cm_msg(
MTALK,
"sequencer",
"Sequencer has stopped with error.");
1618 for (
i = 0; *p &&
i < size;
i++) {
1619 if (*p ==
'"' && !ignore_quotes) {
1625 if (*p ==
'"' && *(p + 1) ==
'"') {
1628 }
else if (*p ==
'"') {
1642 if (*p && strchr(brk, *p))
1650 for (
j = 0;
j < (int) strlen(
list[
i]);
j++)
1651 if (strchr(brk,
list[
i][
j])) {
1656 p += strlen(
list[
i]);
1659 if (*p && strchr(brk, *p))
1680extern char *
stristr(
const char *
str,
const char *pattern);
1688 xpath +=
c->odb_path;
1697 while ((i1 = (
int)result.find(
"$")) != (
int)std::string::npos) {
1698 std::string s = result.substr(i1 + 1);
1699 if (std::isdigit(s[0])) {
1701 for (i2 = i1 + 1; std::isdigit(result[i2]);)
1705 int index = atoi(s.c_str());
1708 std::vector<std::string>
param;
1710 while (std::getline(f, sp,
','))
1711 param.push_back(sp);
1713 throw "Parameter \"$" + std::to_string(
index) +
"\" not valid";
1715 if (vsubst[0] ==
'$')
1718 throw "Parameter \"$" + std::to_string(
index) +
"\" not valid";
1721 for (i2 = i1 + 1; std::isalnum(result[i2]) || result[i2] ==
'_';)
1723 s = s.substr(0, i2 - i1 - 1);
1724 if (result[i2] ==
'[') {
1726 auto sindex = result.substr(i2+1);
1727 int i = sindex.find(
']');
1728 if (
i == (
int)std::string::npos)
1729 throw "Variable \"" + result +
"\" does not contain ']'";
1730 sindex = sindex.substr(0,
i);
1734 index = std::stoi(sindex);
1736 throw "Variable \"" + s +
"\" has invalid index";
1741 std::vector<std::string> sv = o;
1744 throw "Variable \"" + s +
"\" not found";
1746 while (result[i2] && result[i2] !=
']')
1749 throw "Variable \"" + result +
"\" does not contain ']'";
1750 if (result[i2] ==
']')
1755 throw "Variable \"" + s +
"\" not found";
1759 throw "Variable \"" + s +
"\" not found";
1764 result = result.substr(0, i1) + vsubst + result.substr(i2);
1770 if (result.find(
",") != std::string::npos)
1775 double r =
te_interp(result.c_str(), &error);
1778 if (!std::isdigit(result[0]) && result[0] !=
'-')
1781 throw "Error in expression \"" + result +
"\" position " + std::to_string(error - 1);
1785 return std::to_string((
int) r);
1787 std::ostringstream os;
1788 os << std::scientific << r;
1802 for (
i = 0;
i <
n;
i++) {
1804 mstrlcat(result,
str.c_str(), size);
1814 double value1, value2;
1815 char value1_str[256], value2_str[256],
str[256], op[3], *p;
1816 std::string value1_var, value2_var;
1819 p = (
char *)condition;
1825 if (strchr(
str,
'#'))
1826 *strchr(
str,
'#') = 0;
1828 while (strlen(
str) > 0 && (
str[strlen(
str)-1] ==
' '))
1832 if (
str[0] ==
'(' && strlen(
str) > 0 &&
str[strlen(
str)-1] ==
')') {
1833 mstrlcpy(value1_str,
str+1,
sizeof(value1_str));
1834 mstrlcpy(
str, value1_str,
sizeof(
str));
1841 for (
i = 0;
i < (int) strlen(
str);
i++)
1842 if (strchr(
"<>=!&",
str[
i]) != NULL)
1844 mstrlcpy(value1_str,
str,
i + 1);
1845 while (value1_str[strlen(value1_str) - 1] ==
' ')
1846 value1_str[strlen(value1_str) - 1] = 0;
1848 if (strchr(
"<>=!&",
str[
i + 1]) != NULL)
1851 for (
i++;
str[
i] ==
' ';
i++);
1852 mstrlcpy(value2_str,
str +
i,
sizeof(value2_str));
1854 value1_var =
eval_var(seq,
c, value1_str);
1855 value2_var =
eval_var(seq,
c, value2_str);
1859 if (strcmp(op,
"=") == 0)
1860 return equal_ustring(value1_var.c_str(), value2_var.c_str()) ? 1 : 0;
1861 if (strcmp(op,
"==") == 0)
1862 return equal_ustring(value1_var.c_str(), value2_var.c_str()) ? 1 : 0;
1863 if (strcmp(op,
"!=") == 0)
1864 return equal_ustring(value1_var.c_str(), value2_var.c_str()) ? 0 : 1;
1870 value1 = atof(value1_var.c_str());
1871 value2 = atof(value2_var.c_str());
1874 if (strcmp(op,
"=") == 0)
1875 if (value1 == value2)
1877 if (strcmp(op,
"==") == 0)
1878 if (value1 == value2)
1880 if (strcmp(op,
"!=") == 0)
1881 if (value1 != value2)
1883 if (strcmp(op,
"<") == 0)
1884 if (value1 < value2)
1886 if (strcmp(op,
">") == 0)
1887 if (value1 > value2)
1889 if (strcmp(op,
"<=") == 0)
1890 if (value1 <= value2)
1892 if (strcmp(op,
">=") == 0)
1893 if (value1 >= value2)
1895 if (strcmp(op,
"&") == 0)
1896 if (((
unsigned int) value1 & (
unsigned int) value2) > 0)
1904bool loadMSL(MVOdb *o,
const std::string &filename) {
1906 std::ifstream
file(filename);
1907 if (!
file.is_open())
1910 std::vector<std::string> lines;
1914 while (std::getline(
file, line))
1915 lines.push_back(line);
1918 o->WSA(
"Script/Lines", lines, 0);
1926 char *error,
int error_size,
int *error_line) {
1927 char str[256], *pl, *pe;
1929 int i,
j,
n, nq, n_lines, endl, line, nest, incl, library;
1930 std::string xml, path, fn;
1931 char *msl_include, *xml_include, *include_error;
1932 int include_error_size;
1933 BOOL include_status, rel_path;
1934 std::vector<std::string> subroutine_names;
1937 snprintf(error, error_size,
"More than 10 nested INCLUDE statements exceeded in file \"%s\"", filename);
1942 path = std::string(cpath);
1943 if (path.length() > 0 && path.back() !=
'/')
1946 std::string fullFilename;
1948 fullFilename = path + filename;
1950 fullFilename = filename;
1952 int fhin = open(fullFilename.c_str(), O_RDONLY |
O_TEXT);
1954 snprintf(error, error_size,
"Cannot open \"%s\", errno %d (%s)", fullFilename.c_str(), errno, strerror(errno));
1958 off_t off = lseek(fhin, 0, SEEK_END);
1960 snprintf(error, error_size,
"Cannot find size of \"%s\", lseek(SEEK_END) errno %d (%s)", fullFilename.c_str(), errno, strerror(errno));
1965 lseek(fhin, 0, SEEK_SET);
1969 s = path + xml_filename;
1973 FILE *fout = fopen(s.c_str(),
"wt");
1975 snprintf(error, error_size,
"Cannot write to \"%s\", fopen() errno %d (%s)", s.c_str(), errno, strerror(errno));
1982 char* buf = (
char *) malloc(size + 1);
1983 ssize_t rd =
read(fhin, buf, size);
1986 snprintf(error, error_size,
"Cannot read \"%s\", read(%zu) errno %d (%s)", fullFilename.c_str(), size, errno, strerror(errno));
1996 lines = (
char **) malloc(
sizeof(
char *));
2000 for (n_lines = 0; *pl; n_lines++) {
2001 lines = (
char **) realloc(lines,
sizeof(
char *) * (n_lines + 1));
2002 lines[n_lines] = pl;
2003 if (strchr(pl,
'\n')) {
2004 pe = strchr(pl,
'\n');
2006 if (*(pe - 1) ==
'\r') {
2011 pe = pl + strlen(pl);
2012 mstrlcpy(
str, pl,
sizeof(
str));
2016 subroutine_names.emplace_back(
list[1]);
2019 xml +=
"<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>\n";
2020 xml +=
"<!DOCTYPE RunSequence [\n";
2025 char *reference = strrchr(
list[1],
'/');
2029 reference =
list[1];
2031 if (strchr(reference,
'.') && !strstr(reference,
".msl") && !strstr(reference,
".MSL")) {
2032 snprintf(error, error_size,
"Include file \"%s\" cannot have an extension other than .msl", reference);
2037 if (
list[1][0] ==
'/') {
2039 p +=
"userfiles/sequencer";
2043 if (!p.empty() && p.back() !=
'/')
2048 xml +=
" <!ENTITY ";
2050 xml +=
" SYSTEM \"";
2055 size = p.length() + 1 + 4;
2056 msl_include = (
char *) malloc(size);
2057 xml_include = (
char *) malloc(size);
2058 mstrlcpy(msl_include, p.c_str(), size);
2059 mstrlcpy(xml_include, p.c_str(), size);
2060 if (!strstr(msl_include,
".msl"))
2061 mstrlcat(msl_include,
".msl", size);
2062 mstrlcat(xml_include,
".xml", size);
2064 include_error = error + strlen(error);
2065 include_error_size = error_size - strlen(error);
2068 path +=
"userfiles/sequencer/";
2071 include_status =
msl_parse(seq,
c, level+1, path.c_str(), msl_include, xml_include, include_error, include_error_size, error_line);
2075 if (!include_status) {
2077 *error_line = n_lines + 1;
2082 xml +=
"<Library name=\"";
2090 }
else if (!library) {
2091 xml +=
"<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>\n";
2096 xml +=
"<RunSequence xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:noNamespaceSchemaLocation=\"\">\n";
2099 std::vector<std::string> slines;
2100 for (line = 0; line < n_lines; line++) {
2101 slines.push_back(lines[line]);
2104 c->odbs->WSA(
"Script/Lines", slines, 0);
2107 std::string p =
"/" +
c->odb_path +
"/Param/Value";
2114 c->odbs->Delete(
"Variables");
2115 c->odbs->Delete(
"Param");
2118 for (line = 0; line < n_lines; line++) {
2119 char *p1 = lines[line];
2122 mstrlcpy(
list[0], p1,
sizeof(
list[0]));
2123 if (strchr(
list[0],
' '))
2124 *strchr(
list[0],
' ') = 0;
2125 p1 += strlen(
list[0]);
2134 for (
i = 0;
i <
n;
i++) {
2135 if (
list[
i][0] ==
'#') {
2136 for (
j =
i;
j <
n;
j++)
2143 for (
i = 0;
i <
n;
i++) {
2144 if (strchr(
list[
i],
'#'))
2145 *strchr(
list[
i],
'#') = 0;
2149 for (
i = 0;
i <
n;
i++) {
2156 mstrlcpy(
eq, lines[line],
sizeof(
eq));
2157 if (strchr(
eq,
'#'))
2158 *strchr(
eq,
'#') = 0;
2159 for (
i = 0,
n = 0, nq = 0;
i < (int)strlen(
eq);
i++) {
2161 nq = (nq == 0 ? 1 : 0);
2162 if (
eq[
i] ==
'=' && nq == 0 &&
2163 (
i > 0 && (
eq[
i - 1] !=
'!') &&
eq[
i - 1] !=
'<' &&
eq[
i - 1] !=
'>'))
2166 if (
n == 1 &&
eq[0] !=
'=') {
2168 mstrlcpy(
list[0],
"SET",
sizeof(
list[0]));
2172 mstrlcpy(
list[1], p1,
sizeof(
list[1]));
2173 *strchr(
list[1],
'=') = 0;
2174 if (strchr(
list[1],
' '))
2175 *strchr(
list[1],
' ') = 0;
2176 p1 = strchr(
eq,
'=')+1;
2179 mstrlcpy(
list[2], p1,
sizeof(
list[2]));
2180 while (strlen(
list[2]) > 0 &&
list[2][strlen(
list[2])-1] ==
' ')
2185 if (parse_command && parse_command->
parse_msl) {
2186 SeqParseContext ctx(seq,
c, level, fullFilename, line, n_lines, lines,
list, xml, error, error_size, error_line);
2194 char *reference = strrchr(
list[1],
'/');
2198 reference =
list[1];
2205 std::any_of(subroutine_names.begin(), subroutine_names.end(),
2206 [&](
const std::string &
name) { return equal_ustring(list[0], name.c_str()); })) {
2208 int first_arg = explicit_call ? 2 : 1;
2209 xml +=
"<Call " +
qtoString(fullFilename, line + 1, level) +
" name=" +
q(
list[explicit_call ? 1 : 0]) +
">";
2210 for (
i = first_arg;
i < 100 &&
list[
i][0];
i++) {
2211 if (
i > first_arg) {
2219 xml +=
"<Goto " +
qtoString(fullFilename, line + 1, level) +
" sline=" +
q(
list[1]) +
" />\n";
2222 xml +=
"<If " +
qtoString(fullFilename, line + 1, level) +
" condition=\"";
2223 for (
i = 1;
i < 100 &&
list[
i][0] && stricmp(
list[
i],
"THEN") != 0;
i++) {
2229 xml +=
"<Else />\n";
2236 for (
i = line, nest = 0;
i < n_lines;
i++) {
2250 if (
list[2][0] == 0) {
2251 xml +=
"<Loop " +
qtoString(fullFilename, line + 1, level) +
" le=\"" + std::to_string(endl) +
"\" n=" +
q(
list[1]) +
">\n";
2252 }
else if (
list[3][0] == 0) {
2253 xml +=
"<Loop " +
qtoString(fullFilename, line + 1, level) +
" le=\"" + std::to_string(endl) +
"\" var=" +
q(
list[1]) +
" n=" +
2256 xml +=
"<Loop " +
qtoString(fullFilename, line + 1, level) +
" le=\"" + std::to_string(endl) +
"\" var=" +
q(
list[1]) +
" values=\"";
2257 for (
i = 2;
i < 100 &&
list[
i][0];
i++) {
2269 xml +=
"<Break "+
qtoString(fullFilename, line + 1, level) +
"></Break>\n";
2273 xml +=
"<ODBSubdir " +
qtoString(fullFilename, line + 1, level) +
" notify=" +
q(
list[2]) +
" path=" +
q(
list[1]) +
">\n";
2275 xml +=
"<ODBSubdir " +
qtoString(fullFilename, line + 1, level) +
" path=" +
q(
list[1]) +
">\n";
2278 xml +=
"</ODBSubdir>\n";
2282 snprintf(error, error_size,
"Parameter \"%s\" misses 'comment'",
list[1]);
2283 *error_line = line + 1;
2287 xml +=
"<Param " +
qtoString(fullFilename, line + 1, level) +
" name=" +
q(
list[1]) +
" type=\"bool\" " +
" comment=" +
q(
list[2]) +
"/>\n";
2289 c->odbs->RB((std::string(
"Param/Value/") +
list[1]).c_str(), &v,
true);
2290 c->odbs->WS((std::string(
"Param/Comment/") +
list[1]).c_str(),
list[2]);
2292 xml +=
"<Param " +
qtoString(fullFilename, line + 1, level) +
" name=" +
q(
list[1]) +
" type=\"bool\" default=" +
q(
list[4]) +
"/>\n";
2293 std::string def(
list[3]);
2294 bool v(def ==
"1" || def ==
"true" || def ==
"TRUE");
2295 c->odbs->RB((std::string(
"Param/Value/") +
list[1]).c_str(), &v,
true);
2296 c->odbs->WS((std::string(
"Param/Comment/") +
list[1]).c_str(),
list[2]);
2297 c->odbs->WS((std::string(
"Param/Defaults/") +
list[1]).c_str(),
list[3]);
2299 }
else if (!
list[3][0]) {
2300 xml +=
"<Param " +
qtoString(fullFilename, line + 1, level) +
" name=" +
q(
list[1]) +
" comment=" +
q(
list[2]) +
" />\n";
2302 c->odbs->RS((std::string(
"Param/Value/") +
list[1]).c_str(), &v,
true);
2303 c->odbs->WS((std::string(
"Param/Comment/") +
list[1]).c_str(),
list[2]);
2304 }
else if (!
list[4][0]) {
2305 xml +=
"<Param " +
qtoString(fullFilename, line + 1, level) +
" name=" +
q(
list[1]) +
" comment=" +
q(
list[2]) +
" default=" +
q(
list[3]) +
" />\n";
2306 std::string v(
list[3]);
2307 c->odbs->RS((std::string(
"Param/Value/") +
list[1]).c_str(), &v,
true);
2308 c->odbs->WS((std::string(
"Param/Comment/") +
list[1]).c_str(),
list[2]);
2309 c->odbs->WS((std::string(
"Param/Defaults/") +
list[1]).c_str(),
list[3]);
2312 xml +=
"<Param " +
qtoString(fullFilename, line + 1, level) +
" name=" +
q(
list[1]) +
" comment=" +
q(
list[2]) +
2315 c->odbs->RS((std::string(
"Param/Value/") +
list[1]).c_str(), &v,
true);
2316 c->odbs->WS((std::string(
"Param/Comment/") +
list[1]).c_str(),
list[2]);
2317 std::vector<std::string> options;
2318 for (
i = 3;
i < 100 &&
list[
i][0];
i++) {
2323 options.push_back(
list[
i]);
2326 c->odbs->WSA((std::string(
"Param/Options/") +
list[1]).c_str(), options, 0);
2331 std::string ov = oldSeqParam[(
const char *)
list[1]];
2332 c->odbs->WS((std::string(
"Param/Value/") +
list[1]).c_str(), ov.c_str());
2336 xml +=
"\n<Subroutine " +
qtoString(fullFilename, line + 1, level) +
" name=" +
q(
list[1]) +
">\n";
2339 xml +=
"</Subroutine>\n";
2341 }
else if (
list[0][0] == 0 ||
list[0][0] ==
'#') {
2344 snprintf(error, error_size,
"Invalid command \"%s\"",
list[0]);
2345 *error_line = line + 1;
2353 xml +=
"\n</Library>\n";
2355 xml +=
"</RunSequence>\n";
2359 fprintf(fout,
"%s", xml.c_str());
2373 cm_msg(
MERROR,
"seq_read",
"Cannot find /Sequencer/State in ODB, db_find_key() status %d",
status);
2380 cm_msg(
MERROR,
"seq_read",
"Cannot get /Sequencer/State from ODB, db_get_record1() status %d",
status);
2391 cm_msg(
MERROR,
"seq_write",
"Cannot find /Sequencer/State in ODB, db_find_key() status %d",
status);
2396 cm_msg(
MERROR,
"seq_write",
"Cannot write to ODB /Sequencer/State, db_set_record() status %d",
status);
2458 midas::odb defaults(std::string(
"/") +
c->odb_path +
"/Param/Defaults");
2460 midas::odb vars(std::string(
"/") +
c->odb_path +
"/Variables");
2464 if (!
param.is_subkey(
d.get_name())) {
2465 mstrlcpy(seq.
error,
"Cannot start script because /Sequencer/Param/Value is incomplete",
sizeof(seq.
error));
2467 cm_msg(
MERROR,
"sequencer",
"Cannot start script because /Sequencer/Param/Value is incomplete");
2473 vars[p.get_name()] = p.
s();
2476 mstrlcpy(seq.
error,
"Cannot start script, no script loaded",
sizeof(seq.
error));
2490 cm_msg(
MTALK,
"sequencer",
"Sequencer started with script \"%s\" in debugging mode.", seq.
filename);
2502 path +=
"userfiles/sequencer/";
2546 for (
int i = 1;
i < mxml_get_line_number_end(mxml_find_node(
c->pnseq,
"RunSequence"));
i++) {
2547 PMXML_NODE pt = mxml_get_node_at_line(
c->pnseq,
i);
2550 if (
equal_ustring(mxml_get_attribute(pt,
"name"),
"ATEXIT")) {
2553 seq_error(seq,
c,
"Maximum subroutine level exceeded");
2600 mxml_free_tree(
c->pnseq);
2603 c->odbs->WS(
"Script/Lines",
"");
2606 int size = (int)strlen(
str) + 1;
2607 char *xml_filename = (
char *) malloc(size);
2608 mstrlcpy(xml_filename,
str, size);
2609 strsubst(xml_filename, size,
".msl",
".xml");
2613 path +=
"userfiles/sequencer/";
2615 if (xml_filename[0] ==
'/') {
2616 path += xml_filename;
2617 path = path.substr(0, path.find_last_of(
'/') + 1);
2618 mstrlcpy(xml_filename, path.substr(path.find_last_of(
'/') + 1).c_str(), size);
2625 std::string fn(path);
2626 if (!fn.empty() && fn.back() !=
'/')
2646 for (
int i=0 ;
i<9 ;
i++)
2665 if (
c->seqp->new_file) {
2666 mstrlcpy(
str,
c->seqp->path,
sizeof(
str));
2669 mstrlcat(
str,
c->seqp->filename,
sizeof(
str));
2696 std::string context;
2697 PMXML_NODE pr = mxml_find_node(
c->pnseq,
"RunSequence");
2702 for (
int i = 1;
i <= mxml_get_line_number_end(pr);
i++) {
2703 PMXML_NODE pt = mxml_get_node_at_line(
c->pnseq,
i);
2707 const char *
name = mxml_get_name(pt);
2711 int start_line = mxml_get_line_number_start(pt);
2712 int end_line = mxml_get_line_number_end(pt);
2718 if (line > start_line && line < end_line)
2719 context +=
msprintf(
"%s:%d:%d;",
name, start_line, end_line);
2729 int target_line = 0;
2730 int target_sline_found = 0;
2733 if (target_sline <= 0) {
2734 cm_msg(
MERROR,
"sequencer",
"Goto line command ignored: invalid line number %d", target_sline);
2738 if (
c->pnseq == NULL) {
2739 cm_msg(
MERROR,
"sequencer",
"Goto line command ignored: no script loaded");
2743 pr = mxml_find_node(
c->pnseq,
"RunSequence");
2745 cm_msg(
MERROR,
"sequencer",
"Goto line command ignored: cannot find <RunSequence> tag in XML file");
2752 for (
int i = 1;
i <= mxml_get_line_number_end(pr);
i++) {
2753 pt = mxml_get_node_at_line(
c->pnseq,
i);
2754 if (pt && mxml_get_attribute(pt,
"l")) {
2755 int sline = atoi(mxml_get_attribute(pt,
"l"));
2757 if (sline >= target_sline && (best_sline == 0 || sline < best_sline)) {
2759 target_sline_found = sline;
2765 if (target_line == 0) {
2767 "Goto line %d failed: no executable sequencer command found at or after this source line",
2775 cm_msg(
MERROR,
"sequencer",
"Goto line command ignored: sequencer is not running");
2786 if (current_context != target_context) {
2788 "Goto line command ignored: source line %d resolves to line %d, which is in a different LOOP/IF/SUBROUTINE context",
2789 target_sline, target_sline_found);
2794 "Goto line command: moving from source line %d to source line %d.",
2811 bool start_script =
false;
2812 bool stop_immediately =
false;
2813 bool stop_after_run =
false;
2814 bool cancel_stop_after_run =
false;
2815 bool pause_script =
false;
2816 bool resume_script =
false;
2817 bool debug_script =
false;
2818 bool step_over =
false;
2819 bool load_new_file =
false;
2821 int goto_line_size =
sizeof(goto_line);
2823 c->odbs->RB(
"Command/Start script", &start_script);
2824 c->odbs->RB(
"Command/Stop immediately", &stop_immediately);
2825 c->odbs->RB(
"Command/Stop after run", &stop_after_run);
2826 c->odbs->RB(
"Command/Cancel stop after run", &cancel_stop_after_run);
2827 c->odbs->RB(
"Command/Pause script", &pause_script);
2828 c->odbs->RB(
"Command/Resume script", &resume_script);
2829 c->odbs->RB(
"Command/Debug script", &debug_script);
2830 c->odbs->RB(
"Command/Step over", &step_over);
2831 c->odbs->RB(
"Command/Load new file", &load_new_file);
2834 if (load_new_file) {
2835 std::string filename;
2836 c->odbs->RS(
"State/Filename", &filename);
2840 if (filename.find(
"..") != std::string::npos) {
2841 mstrlcpy(seqp->
error,
"Cannot load \"",
sizeof(seqp->
error));
2842 mstrlcat(seqp->
error, filename.c_str(),
sizeof(seqp->
error));
2843 mstrlcat(seqp->
error,
"\": file names with \"..\" is not permitted",
sizeof(seqp->
error));
2845 }
else if (filename.find(
".msl") == std::string::npos) {
2846 mstrlcpy(seqp->
error,
"Cannot load \"",
sizeof(seqp->
error));
2847 mstrlcat(seqp->
error, filename.c_str(),
sizeof(seqp->
error));
2848 mstrlcat(seqp->
error,
"\": file name should end with \".msl\"",
sizeof(seqp->
error));
2853 if (path.length() > 0 && path.back() !=
'/') {
2864 c->odbs->WB(
"Command/Load new file",
false);
2869 if (goto_line != 0) {
2878 c->odbs->WB(
"Command/Start script",
false);
2880 bool seq_running =
false;
2881 c->odbs->RB(
"State/running", &seq_running);
2886 cm_msg(
MTALK,
"sequencer",
"Sequencer is already running");
2890 if (stop_immediately &&
c->pnseq != NULL) {
2892 c->odbs->WB(
"Command/Stop immediately",
false);
2894 cm_msg(
MTALK,
"sequencer",
"Sequencer is finished by \"stop immediately\".");
2896 c->odbs->WB(
"Command/Stop immediately",
false);
2897 cm_msg(
MTALK,
"sequencer",
"Sequencer received \"stop immediately\". Executing ATEXIT.");
2901 if (stop_after_run) {
2902 c->odbs->WB(
"Command/Stop after run",
false);
2906 if (cancel_stop_after_run) {
2907 c->odbs->WB(
"Command/Cancel stop after run",
false);
2913 c->odbs->WB(
"Command/Pause script",
false);
2914 cm_msg(
MTALK,
"sequencer",
"Sequencer is paused.");
2917 if (resume_script) {
2919 c->odbs->WB(
"Command/Resume script",
false);
2920 cm_msg(
MTALK,
"sequencer",
"Sequencer is resumed.");
2924 c->odbs->WB(
"Command/Debug script",
false);
2926 bool seq_running =
false;
2927 c->odbs->RB(
"State/running", &seq_running);
2932 cm_msg(
MTALK,
"sequencer",
"Sequencer is already running");
2938 c->odbs->WB(
"Command/Step over",
false);
2947 *index1 = *index2 = 0;
2948 if (odbpath[strlen(odbpath) - 1] ==
']') {
2949 if (strchr(odbpath,
'[')) {
2951 if (strchr((strchr(odbpath,
'[') + 1),
'$')) {
2952 mstrlcpy(
str, strchr(odbpath,
'[') + 1,
sizeof(
str));
2953 if (strchr(
str,
']'))
2954 *strchr(
str,
']') = 0;
2957 *strchr(odbpath,
'[') = 0;
2974 std::vector<HNDLE> keys;
2982 size =
sizeof(
data);
3029 if (!mxml_get_attribute(
pn,
"path")) {
3030 seq_error(seq,
c,
"Missing attribute \"path\"");
3033 std::string s = mxml_get_attribute(
pn,
"path");
3034 if (s.find(
'$') != std::string::npos)
3038 if (mxml_get_attribute(
pn,
"notify"))
3051 seq_error(seq,
c,
"Maximum loop nesting exceeded");
3056 if (mxml_get_attribute(
pn,
"l"))
3058 if (mxml_get_attribute(
pn,
"le"))
3062 if (mxml_get_attribute(
pn,
"n")) {
3069 }
else if (mxml_get_attribute(
pn,
"values")) {
3070 mstrlcpy(
data, mxml_get_attribute(
pn,
"values"),
sizeof(
data));
3074 seq_error(seq,
c,
"Missing \"var\" or \"n\" attribute");
3078 if (mxml_get_attribute(
pn,
"var")) {
3079 mstrlcpy(
name, mxml_get_attribute(
pn,
"var"),
sizeof(
name));
3080 sprintf(
str,
"Variables/%s",
name);
3081 size =
value.length() + 1;
3112 seq_error(seq,
c,
"\"Break\" outside any loop");
3125 seq_error(seq,
c,
"Maximum number of nested if..endif exceeded");
3136 pe = mxml_get_node_at_line(
c->pnseq,
j);
3140 j = mxml_get_line_number_end(pe);
3151 mstrlcpy(
str, mxml_get_attribute(
pn,
"condition"),
sizeof(
str));
3154 seq_error(seq,
c,
"Invalid number in comparison");
3180 if (!mxml_get_attribute(
pn,
"line") && !mxml_get_attribute(
pn,
"sline")) {
3184 if (mxml_get_attribute(
pn,
"line")) {
3187 if (mxml_get_attribute(
pn,
"sline")) {
3188 mstrlcpy(
str,
eval_var(seq,
c, mxml_get_attribute(
pn,
"sline")).c_str(),
sizeof(
str));
3189 for (
i = 0;
i < last_line;
i++) {
3190 pt = mxml_get_node_at_line(
c->pnseq,
i);
3191 if (pt && mxml_get_attribute(pt,
"l")) {
3192 l = atoi(mxml_get_attribute(pt,
"l"));
3193 if (atoi(
str) == l) {
3223 seq_error(seq,
c,
"Maximum subroutine level exceeded");
3232 for (
i = 1;
i < mxml_get_line_number_end(mxml_find_node(
c->pnseq,
"RunSequence"));
i++) {
3233 pt = mxml_get_node_at_line(
c->pnseq,
i);
3236 if (
equal_ustring(mxml_get_attribute(pt,
"name"), mxml_get_attribute(
pn,
"name"))) {
3242 if (mxml_get_value(
pn)) {
3244 if (strchr(mxml_get_value(
pn),
'$'))
3245 mstrlcpy(p,
eval_var(seq,
c, mxml_get_value(
pn)).c_str(),
sizeof(p));
3247 mstrlcpy(p, mxml_get_value(
pn),
sizeof(p));
3258 if (
i == mxml_get_line_number_end(mxml_find_node(
c->pnseq,
"RunSequence"))) {
3259 seq_error(seq,
c,
msprintf(
"Subroutine '%s' not found", mxml_get_attribute(
pn,
"name")).c_str());
3289 if (
c->pnseq == NULL) {
3291 mstrlcpy(seq.
error,
"No script loaded",
sizeof(seq.
error));
3306 pr = mxml_find_node(
c->pnseq,
"RunSequence");
3308 seq_error(seq,
c,
"Cannot find <RunSequence> tag in XML file");
3312 int last_line = mxml_get_line_number_end(pr);
3322 cm_msg(
MTALK,
"sequencer",
"Sequencer is finished.");
3342 cm_msg(
MTALK,
"sequencer",
"Sequencer is finished.");
3368 if (mxml_get_attribute(
pn,
"var")) {
3369 mstrlcpy(
name, mxml_get_attribute(
pn,
"var"),
sizeof(
name));
3370 if (mxml_get_attribute(
pn,
"values")) {
3371 mstrlcpy(
data, mxml_get_attribute(
pn,
"values"),
sizeof(
data));
3374 }
else if (mxml_get_attribute(
pn,
"n")) {
3377 sprintf(
str,
"Variables/%s",
name);
3378 size =
value.length() + 1;
3429 if (mxml_get_attribute(
pn,
"l"))
3431 if (mxml_get_attribute(
pn,
"fn")) {
3432 std::string filename = mxml_get_attribute(
pn,
"fn");
3435 if (filename != std::string(seq.
sfilename)) {
3441 if (mxml_get_attribute(
pn,
"l") && (!mxml_get_attribute(
pn,
"lvl") || atoi(mxml_get_attribute(
pn,
"lvl")) == 0))
3450 midas::odb o(
"/" +
c->odb_path +
"/Script/Lines");
3461 size =
sizeof(seq1);
3472 if (seq.
debug && !skip_step)
3485 c->odbs =
gOdb->Chdir(
c->odb_path.c_str(),
true);
3490 cm_msg(
MERROR,
"init_sequencer",
"Sequencer error: Cannot find /Sequencer, db_find_key() status %d",
status);
3496 cm_msg(
MERROR,
"init_sequencer",
"Sequencer error: mismatching /Sequencer/State structure, db_check_record() status %d",
status);
3502 cm_msg(
MERROR,
"init_sequencer",
"Sequencer error: Cannot find /Sequencer/State, db_find_key() status %d",
status);
3506 int size =
sizeof(seq);
3509 cm_msg(
MERROR,
"init_sequencer",
"Sequencer error: Cannot get /Sequencer/State, db_get_record1() status %d",
status);
3526 cm_msg(
MERROR,
"init_sequencer",
"Sequencer error: Cannot watch /Sequencer/State, db_watch() status %d",
status);
3531 {
"Start script",
false},
3532 {
"Stop immediately",
false},
3533 {
"Stop after run",
false},
3534 {
"Cancel stop after run",
false},
3535 {
"Pause script",
false},
3536 {
"Resume script",
false},
3537 {
"Debug script",
false},
3538 {
"Step over",
false},
3539 {
"Load new file",
false},
3546 cm_msg(
MERROR,
"init_sequencer",
"Sequencer error: Cannot find /Sequencer/Command, db_find_key() status %d",
status);
3552 cm_msg(
MERROR,
"init_sequencer",
"Sequencer error: Cannot watch /Sequencer/Command, db_watch() status %d",
status);
3559int main(
int argc,
const char *argv[]) {
3562 char midas_hostname[256];
3563 char midas_expt[256];
3564 std::string seq_name =
"";
3566 setbuf(stdout, NULL);
3567 setbuf(stderr, NULL);
3570 signal(SIGPIPE, SIG_IGN);
3574 cm_get_environment(midas_hostname,
sizeof(midas_hostname), midas_expt,
sizeof(midas_expt));
3577 for (
int i = 1;
i < argc;
i++) {
3578 if (argv[
i][0] ==
'-' && argv[
i][1] ==
'D') {
3580 }
else if (argv[
i][0] ==
'-') {
3581 if (
i + 1 >= argc || argv[
i + 1][0] ==
'-')
3583 if (argv[
i][1] ==
'h')
3584 mstrlcpy(midas_hostname, argv[++
i],
sizeof(midas_hostname));
3585 else if (argv[
i][1] ==
'e')
3586 mstrlcpy(midas_expt, argv[++
i],
sizeof(midas_hostname));
3587 else if (argv[
i][1] ==
'c')
3588 seq_name = argv[++
i];
3591 printf(
"usage: %s [-h Hostname[:port]] [-e Experiment] [-c Name] [-D]\n\n", argv[0]);
3592 printf(
" -e experiment to connect to\n");
3593 printf(
" -c Name of additional sequencer, i.e. \'Test\'\n");
3594 printf(
" -h connect to midas server (mserver) on given host\n");
3595 printf(
" -D become a daemon\n");
3601 printf(
"Becoming a daemon...\n");
3605 std::string prg_name =
"Sequencer";
3606 std::string odb_path =
"Sequencer";
3608 if (!seq_name.empty()) {
3609 prg_name = std::string(
"Sequencer") + seq_name;
3610 odb_path = std::string(
"Sequencer") + seq_name;
3614 std::string pid_filename;
3615 pid_filename +=
"/var/run/";
3616 pid_filename += prg_name;
3617 pid_filename +=
".pid";
3619 FILE *f = fopen(pid_filename.c_str(),
"w");
3642 printf(
"%s runs already.\n", prg_name.c_str());
3656 c.seq_name = seq_name;
3657 c.prg_name = prg_name;
3658 c.odb_path = odb_path;
3662 if (seq_name.empty()) {
3663 printf(
"Sequencer started. Stop with \"!\"\n");
3665 printf(
"%s started.\n", prg_name.c_str());
3666 printf(
"Set ODB String \"/Alias/Sequencer%s\" to URL \"?cmd=sequencer&seq_name=%s\"\n", seq_name.c_str(), seq_name.c_str());
3667 printf(
"Stop with \"!\"\n");
3680 }
catch (std::string &msg) {
3682 }
catch (
const char *msg) {
3694 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)
static BOOL seq_execute_script(SeqExecContext &ctx)
static BOOL seq_parse_odbget(SeqParseContext &ctx)
int concatenate(SEQUENCER &seq, SeqCon *c, char *result, int size, char *value)
static BOOL seq_execute_odbsave(SeqExecContext &ctx)
static BOOL seq_parse_odbsave(SeqParseContext &ctx)
static void seq_stop_after_run(SEQUENCER &seq, SeqCon *c)
static SeqCommand seq_command_table[]
static BOOL seq_execute_odbinc(SeqExecContext &ctx)
static BOOL seq_execute_transition(SeqExecContext &ctx)
static BOOL seq_goto_line(SEQUENCER &seq, SeqCon *c, int target_sline)
static BOOL seq_parse_run_description(SeqParseContext &ctx)
static BOOL seq_execute_set(SeqExecContext &ctx)
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)
static BOOL seq_parse_comment(SeqParseContext &ctx)
static SeqCommand * seq_find_msl_command(const char *name)
void strsubst(char *string, int size, const char *pattern, const char *subst)
static BOOL seq_execute_xml_node(SEQUENCER &seq, SeqCon *c, PMXML_NODE pn, HNDLE hKeySeq, int last_line, BOOL &skip_step)
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 seq_execute_wait(SeqExecContext &ctx)
static BOOL seq_parse_msg(SeqParseContext &ctx)
static BOOL goto_at_exit(SEQUENCER &seq, SeqCon *c)
static BOOL seq_execute_odbdelete(SeqExecContext &ctx)
static BOOL seq_parse_odblookup(SeqParseContext &ctx)
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)
static BOOL seq_parse_message(SeqParseContext &ctx)
void init_sequencer(SEQUENCER &seq, SeqCon *c)
static BOOL seq_parse_wait(SeqParseContext &ctx)
static BOOL seq_parse_odbset(SeqParseContext &ctx)
static BOOL seq_parse_exit(SeqParseContext &ctx)
static void seq_step_over(SEQUENCER &seq, SeqCon *c)
static void seq_cancel_stop_after_run(SEQUENCER &seq, SeqCon *c)
static BOOL seq_execute_msg(SeqExecContext &ctx)
static BOOL seq_parse_transition(SeqParseContext &ctx)
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)
static BOOL seq_execute_odblookup(SeqExecContext &ctx)
int set_all_matching(HNDLE hDB, HNDLE hBaseKey, const char *odbpath, char *value, int index1, int index2, int notify)
static BOOL seq_execute_odbget(SeqExecContext &ctx)
static BOOL seq_execute_run_description(SeqExecContext &ctx)
static BOOL seq_execute_odbload(SeqExecContext &ctx)
static BOOL seq_execute_message(SeqExecContext &ctx)
static BOOL seq_execute_odbcreate(SeqExecContext &ctx)
static std::string q(const char *s)
std::string eval_var(SEQUENCER &seq, SeqCon *c, std::string value)
static BOOL seq_parse_script(SeqParseContext &ctx)
static BOOL seq_execute_odbset(SeqExecContext &ctx)
static BOOL seq_parse_cat(SeqParseContext &ctx)
static BOOL seq_execute_skip_node(SeqExecContext &ctx)
bool loadMSL(MVOdb *o, const std::string &filename)
static BOOL seq_execute_cat(SeqExecContext &ctx)
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)
static BOOL seq_parse_set(SeqParseContext &ctx)
bool is_valid_number(const char *str)
static SeqCommand * seq_find_xml_command(const char *name)
void seq_clear(SEQUENCER &seq)
static void seq_open_file(const char *str, SEQUENCER &seq, SeqCon *c)
static BOOL seq_parse_odbcreate(SeqParseContext &ctx)
static BOOL seq_parse_odbload(SeqParseContext &ctx)
static std::string seq_goto_context(SeqCon *c, int line)
static BOOL seq_execute_exit(SeqExecContext &ctx)
static BOOL seq_parse_odbinc(SeqParseContext &ctx)
static BOOL seq_parse_odbdelete(SeqParseContext &ctx)
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]
BOOL(* execute_xml)(SeqExecContext &ctx)
BOOL(* parse_msl)(SeqParseContext &ctx)
SeqExecContext(SEQUENCER &seq_, SeqCon *c_, PMXML_NODE pn_, HNDLE hKeySeq_, int last_line_, BOOL &skip_step_)
SeqParseContext(SEQUENCER &seq_, SeqCon *c_, int level_, const std::string &full_filename_, int line_, int n_lines_, char **lines_, char(*list_)[XNAME_LENGTH], std::string &xml_, char *error_, int error_size_, int *error_line_)
const std::string & full_filename
char(* list)[XNAME_LENGTH]
double te_interp(const char *expression, int *error)
static void pn(const te_expr *n, int depth)
static te_expr * list(state *s)