MIDAS
Loading...
Searching...
No Matches
Sequencer Functions

Classes

class  SeqCon
 
struct  SeqParseContext
 
struct  SeqExecContext
 
struct  SeqCommand
 

Functions

 SEQUENCER_STR (sequencer_str)
 
char * stristr (const char *str, const char *pattern)
 
void strsubst (char *string, int size, const char *pattern, const char *subst)
 
static std::string toString (int v)
 
static std::string qtoString (std::string filename, int line, int level)
 
static std::string q (const char *s)
 
std::string eval_var (SEQUENCER &seq, SeqCon *c, std::string value)
 
void seq_error (SEQUENCER &seq, SeqCon *c, const char *str)
 
int strbreak (char *str, char list[][XNAME_LENGTH], int size, const char *brk, BOOL ignore_quotes)
 
int concatenate (SEQUENCER &seq, SeqCon *c, char *result, int size, char *value)
 
void seq_array_index (SEQUENCER &seq, SeqCon *c, char *odbpath, int *index1, int *index2)
 
int set_all_matching (HNDLE hDB, HNDLE hBaseKey, const char *odbpath, char *value, int index1, int index2, int notify)
 
static void seq_stop (SEQUENCER &seq, SeqCon *c)
 
static BOOL goto_at_exit (SEQUENCER &seq, SeqCon *c)
 
static BOOL seq_parse_comment (SeqParseContext &ctx)
 
static BOOL seq_parse_message (SeqParseContext &ctx)
 
static BOOL seq_parse_msg (SeqParseContext &ctx)
 
static BOOL seq_parse_script (SeqParseContext &ctx)
 
static BOOL seq_parse_set (SeqParseContext &ctx)
 
static BOOL seq_parse_cat (SeqParseContext &ctx)
 
static BOOL seq_parse_wait (SeqParseContext &ctx)
 
static BOOL seq_parse_run_description (SeqParseContext &ctx)
 
static BOOL seq_parse_transition (SeqParseContext &ctx)
 
static BOOL seq_parse_exit (SeqParseContext &ctx)
 
static BOOL seq_parse_odbset (SeqParseContext &ctx)
 
static BOOL seq_parse_odbget (SeqParseContext &ctx)
 
static BOOL seq_parse_odbinc (SeqParseContext &ctx)
 
static BOOL seq_parse_odbcreate (SeqParseContext &ctx)
 
static BOOL seq_parse_odbdelete (SeqParseContext &ctx)
 
static BOOL seq_parse_odbload (SeqParseContext &ctx)
 
static BOOL seq_parse_odbsave (SeqParseContext &ctx)
 
static BOOL seq_parse_odblookup (SeqParseContext &ctx)
 
static BOOL seq_execute_odblookup (SeqExecContext &ctx)
 
static BOOL seq_execute_skip_node (SeqExecContext &ctx)
 
static BOOL seq_execute_message (SeqExecContext &ctx)
 
static BOOL seq_execute_msg (SeqExecContext &ctx)
 
static BOOL seq_execute_script (SeqExecContext &ctx)
 
static BOOL seq_execute_set (SeqExecContext &ctx)
 
static BOOL seq_execute_cat (SeqExecContext &ctx)
 
static BOOL seq_execute_wait (SeqExecContext &ctx)
 
static BOOL seq_execute_run_description (SeqExecContext &ctx)
 
static BOOL seq_execute_transition (SeqExecContext &ctx)
 
static BOOL seq_execute_exit (SeqExecContext &ctx)
 
static BOOL seq_execute_odbset (SeqExecContext &ctx)
 
static BOOL seq_execute_odbget (SeqExecContext &ctx)
 
static BOOL seq_execute_odbinc (SeqExecContext &ctx)
 
static BOOL seq_execute_odbcreate (SeqExecContext &ctx)
 
static BOOL seq_execute_odbdelete (SeqExecContext &ctx)
 
static BOOL seq_execute_odbload (SeqExecContext &ctx)
 
static BOOL seq_execute_odbsave (SeqExecContext &ctx)
 
static SeqCommandseq_find_msl_command (const char *name)
 
static SeqCommandseq_find_xml_command (const char *name)
 
bool is_valid_number (const char *str)
 
int eval_condition (SEQUENCER &seq, SeqCon *c, const char *condition)
 
bool loadMSL (MVOdb *o, const std::string &filename)
 
static BOOL msl_parse (SEQUENCER &seq, SeqCon *c, int level, const char *cpath, const char *filename, const char *xml_filename, char *error, int error_size, int *error_line)
 
void seq_read (SEQUENCER *seq, SeqCon *c)
 
void seq_write (const SEQUENCER &seq, SeqCon *c)
 
void seq_clear (SEQUENCER &seq)
 
static void seq_start (SEQUENCER &seq, SeqCon *c, bool debug)
 
static void seq_stop_after_run (SEQUENCER &seq, SeqCon *c)
 
static void seq_cancel_stop_after_run (SEQUENCER &seq, SeqCon *c)
 
static void seq_pause (SEQUENCER &seq, SeqCon *c, bool flag)
 
static void seq_step_over (SEQUENCER &seq, SeqCon *c)
 
static void seq_open_file (const char *str, SEQUENCER &seq, SeqCon *c)
 
static void seq_start_next (SEQUENCER &seq, SeqCon *c)
 
static void seq_watch (HNDLE hDB, HNDLE hKeyChanged, int index, void *info)
 
static void seq_clear_wait_state (SEQUENCER &seq)
 
static std::string seq_goto_context (SeqCon *c, int line)
 
static BOOL seq_goto_line (SEQUENCER &seq, SeqCon *c, int target_sline)
 
static void seq_watch_command (HNDLE hDB, HNDLE hKeyChanged, int index, void *info)
 
static BOOL seq_execute_xml_node (SEQUENCER &seq, SeqCon *c, PMXML_NODE pn, HNDLE hKeySeq, int last_line, BOOL &skip_step)
 
void sequencer (SEQUENCER &seq, SeqCon *c)
 
void init_sequencer (SEQUENCER &seq, SeqCon *c)
 
int main (int argc, const char *argv[])
 

Variables

MVOdb * gOdb = NULL
 
static SeqCommand seq_command_table []
 

Detailed Description

dox


Function Documentation

◆ concatenate()

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

Definition at line 1795 of file msequencer.cxx.

1795 {
1796 char list[100][XNAME_LENGTH];
1797 int i, n;
1798
1799 n = strbreak(value, list, 100, ",", FALSE);
1800
1801 result[0] = 0;
1802 for (i = 0; i < n; i++) {
1803 std::string str = eval_var(seq, c, std::string(list[i]));
1804 mstrlcat(result, str.c_str(), size);
1805 }
1806
1807 return TRUE;
1808}
#define FALSE
Definition cfortran.h:309
int strbreak(char *str, char list[][XNAME_LENGTH], int size, const char *brk, BOOL ignore_quotes)
std::string eval_var(SEQUENCER &seq, SeqCon *c, std::string value)
DWORD n[4]
Definition mana.cxx:247
INT i
Definition mdump.cxx:32
#define TRUE
Definition midas.h:182
#define XNAME_LENGTH
double value[100]
Definition odbhist.cxx:42
char str[256]
Definition odbhist.cxx:33
char c
Definition system.cxx:1312
static te_expr * list(state *s)
Definition tinyexpr.c:567
Here is the call graph for this function:
Here is the caller graph for this function:

◆ eval_condition()

int eval_condition ( SEQUENCER seq,
SeqCon c,
const char *  condition 
)

Definition at line 1812 of file msequencer.cxx.

1812 {
1813 int i;
1814 double value1, value2;
1815 char value1_str[256], value2_str[256], str[256], op[3], *p;
1816 std::string value1_var, value2_var;
1817
1818 // strip leading and trailing space
1819 p = (char *)condition;
1820 while (*p == ' ')
1821 p++;
1822 strcpy(str, p);
1823
1824 // strip any comment '#'
1825 if (strchr(str, '#'))
1826 *strchr(str, '#') = 0;
1827
1828 while (strlen(str) > 0 && (str[strlen(str)-1] == ' '))
1829 str[strlen(str)-1] = 0;
1830
1831 // strip enclosing '()'
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));
1835 str[strlen(str)-1] = 0;
1836 }
1837
1838 op[1] = op[2] = 0;
1839
1840 /* find value and operator */
1841 for (i = 0; i < (int) strlen(str); i++)
1842 if (strchr("<>=!&", str[i]) != NULL)
1843 break;
1844 mstrlcpy(value1_str, str, i + 1);
1845 while (value1_str[strlen(value1_str) - 1] == ' ')
1846 value1_str[strlen(value1_str) - 1] = 0;
1847 op[0] = str[i];
1848 if (strchr("<>=!&", str[i + 1]) != NULL)
1849 op[1] = str[++i];
1850
1851 for (i++; str[i] == ' '; i++);
1852 mstrlcpy(value2_str, str + i, sizeof(value2_str));
1853
1854 value1_var = eval_var(seq, c, value1_str);
1855 value2_var = eval_var(seq, c, value2_str);
1856
1857 if (!is_valid_number(value1_var.c_str()) || !is_valid_number(value2_var.c_str())) {
1858 // string comparison
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;
1865 // invalid operator for string comparisons
1866 return -1;
1867 }
1868
1869 // numeric comparison
1870 value1 = atof(value1_var.c_str());
1871 value2 = atof(value2_var.c_str());
1872
1873 /* now do logical operation */
1874 if (strcmp(op, "=") == 0)
1875 if (value1 == value2)
1876 return 1;
1877 if (strcmp(op, "==") == 0)
1878 if (value1 == value2)
1879 return 1;
1880 if (strcmp(op, "!=") == 0)
1881 if (value1 != value2)
1882 return 1;
1883 if (strcmp(op, "<") == 0)
1884 if (value1 < value2)
1885 return 1;
1886 if (strcmp(op, ">") == 0)
1887 if (value1 > value2)
1888 return 1;
1889 if (strcmp(op, "<=") == 0)
1890 if (value1 <= value2)
1891 return 1;
1892 if (strcmp(op, ">=") == 0)
1893 if (value1 >= value2)
1894 return 1;
1895 if (strcmp(op, "&") == 0)
1896 if (((unsigned int) value1 & (unsigned int) value2) > 0)
1897 return 1;
1898
1899 return 0;
1900}
BOOL equal_ustring(const char *str1, const char *str2)
Definition odb.cxx:3780
bool is_valid_number(const char *str)
Here is the call graph for this function:
Here is the caller graph for this function:

◆ eval_var()

std::string eval_var ( SEQUENCER seq,
SeqCon c,
std::string  value 
)

Definition at line 1684 of file msequencer.cxx.

1684 {
1685 std::string result;
1686 std::string xpath;
1687 xpath += "/";
1688 xpath += c->odb_path;
1689
1690 //printf("eval [%s] xpath [%s]\n", value.c_str(), xpath.c_str());
1691
1692 result = value;
1693
1694 // replace all $... with value
1695 int i1, i2;
1696 std::string vsubst;
1697 while ((i1 = (int)result.find("$")) != (int)std::string::npos) {
1698 std::string s = result.substr(i1 + 1);
1699 if (std::isdigit(s[0])) {
1700 // find end of number
1701 for (i2 = i1 + 1; std::isdigit(result[i2]);)
1702 i2++;
1703
1704 // replace all $<number> with subroutine parameters
1705 int index = atoi(s.c_str());
1706 if (seq.stack_index > 0) {
1707 std::istringstream f(seq.subroutine_param[seq.stack_index - 1]);
1708 std::vector<std::string> param;
1709 std::string sp;
1710 while (std::getline(f, sp, ','))
1711 param.push_back(sp);
1712 if (index == 0 || index > (int)param.size())
1713 throw "Parameter \"$" + std::to_string(index) + "\" not valid";
1714 vsubst = param[index - 1];
1715 if (vsubst[0] == '$')
1716 vsubst = eval_var(seq, c, vsubst);
1717 } else
1718 throw "Parameter \"$" + std::to_string(index) + "\" not valid";
1719 } else {
1720 // find end of string
1721 for (i2 = i1 + 1; std::isalnum(result[i2]) || result[i2] == '_';)
1722 i2++;
1723 s = s.substr(0, i2 - i1 - 1);
1724 if (result[i2] == '[') {
1725 // array
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);
1731 sindex = eval_var(seq, c, sindex);
1732 int index;
1733 try {
1734 index = std::stoi(sindex);
1735 } catch (...) {
1736 throw "Variable \"" + s + "\" has invalid index";
1737 }
1738
1739 try {
1740 midas::odb o(xpath + "/Variables/" + s);
1741 std::vector<std::string> sv = o;
1742 vsubst = sv[index];
1743 } catch (...) {
1744 throw "Variable \"" + s + "\" not found";
1745 }
1746 while (result[i2] && result[i2] != ']')
1747 i2++;
1748 if (!result[i2])
1749 throw "Variable \"" + result +"\" does not contain ']'";
1750 if (result[i2] == ']')
1751 i2++;
1752 } else {
1753 try {
1754 if (!midas::odb::exists(xpath + "/Variables/" + s))
1755 throw "Variable \"" + s + "\" not found";
1756 midas::odb o(xpath + "/Variables/" + s);
1757 vsubst = o;
1758 } catch (...) {
1759 throw "Variable \"" + s + "\" not found";
1760 }
1761 }
1762 }
1763
1764 result = result.substr(0, i1) + vsubst + result.substr(i2);
1765 }
1766
1767 //printf("eval [%s] xpath [%s] result [%s]\n", value.c_str(), xpath.c_str(), result.c_str());
1768
1769 // check if result is a list
1770 if (result.find(",") != std::string::npos)
1771 return result;
1772
1773 // check for expression
1774 int error;
1775 double r = te_interp(result.c_str(), &error);
1776 if (error > 0) {
1777 // check if result is only a string
1778 if (!std::isdigit(result[0]) && result[0] != '-')
1779 return result;
1780
1781 throw "Error in expression \"" + result + "\" position " + std::to_string(error - 1);
1782 }
1783
1784 if (r == (int) r)
1785 return std::to_string((int) r);
1786
1787 std::ostringstream os;
1788 os << std::scientific << r;
1789
1790 return os.str();
1791}
static bool exists(const std::string &name)
Definition odbxx.cxx:76
INT index
Definition mana.cxx:271
char param[10][256]
Definition mana.cxx:250
int stack_index
Definition sequencer.h:40
char subroutine_param[SEQ_NEST_LEVEL_SUB][256]
Definition sequencer.h:45
double te_interp(const char *expression, int *error)
Definition tinyexpr.c:690
Here is the call graph for this function:
Here is the caller graph for this function:

◆ goto_at_exit()

static BOOL goto_at_exit ( SEQUENCER seq,
SeqCon c 
)
static

Definition at line 2542 of file msequencer.cxx.

2542 {
2543 seq_read(&seq, c);
2544
2545 // search ATEXIT subroutine
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);
2548 if (pt) {
2549 if (equal_ustring(mxml_get_name(pt), "Subroutine")) {
2550 if (equal_ustring(mxml_get_attribute(pt, "name"), "ATEXIT")) {
2551
2552 if (seq.stack_index == SEQ_NEST_LEVEL_SUB) {
2553 seq_error(seq, c, "Maximum subroutine level exceeded");
2554 return FALSE;
2555 }
2556
2557 // put routine end line on end stack
2558 seq.subroutine_end_line[seq.stack_index] = mxml_get_line_number_end(pt);
2559 seq.ssubroutine_call_line[seq.stack_index] = atoi(mxml_get_attribute(pt, "l"));
2560 seq.subroutine_return_line[seq.stack_index] = -1; // indicates exit on return
2561
2562 // put routine end line on end stack
2563 seq.subroutine_end_line[seq.stack_index] = mxml_get_line_number_end(pt);
2564
2565 // go to first line of subroutine
2566 seq.current_line_number = mxml_get_line_number_start(pt) + 1;
2567
2568 // increment stack
2569 seq.stack_index++;
2570
2571 seq_write(seq, c);
2572
2573 return TRUE;
2574 }
2575 }
2576 }
2577 }
2578
2579 // look for atexit subroutine
2580 return FALSE;
2581}
void seq_write(const SEQUENCER &seq, SeqCon *c)
void seq_read(SEQUENCER *seq, SeqCon *c)
void seq_error(SEQUENCER &seq, SeqCon *c, const char *str)
#define SEQ_NEST_LEVEL_SUB
Definition sequencer.h:5
int subroutine_return_line[SEQ_NEST_LEVEL_SUB]
Definition sequencer.h:42
int subroutine_end_line[SEQ_NEST_LEVEL_SUB]
Definition sequencer.h:41
int ssubroutine_call_line[SEQ_NEST_LEVEL_SUB]
Definition sequencer.h:44
int current_line_number
Definition sequencer.h:22
Here is the call graph for this function:
Here is the caller graph for this function:

◆ init_sequencer()

void init_sequencer ( SEQUENCER seq,
SeqCon c 
)

Definition at line 3481 of file msequencer.cxx.

3481 {
3482 int status;
3483 HNDLE hKey;
3484
3485 c->odbs = gOdb->Chdir(c->odb_path.c_str(), true); // create /Sequencer
3486 assert(c->odbs);
3487
3488 status = db_find_key(c->hDB, 0, c->odb_path.c_str(), &c->hSeq);
3489 if (status != DB_SUCCESS) {
3490 cm_msg(MERROR, "init_sequencer", "Sequencer error: Cannot find /Sequencer, db_find_key() status %d", status);
3491 return;
3492 }
3493
3494 status = db_check_record(c->hDB, c->hSeq, "State", strcomb1(sequencer_str).c_str(), TRUE);
3495 if (status == DB_STRUCT_MISMATCH) {
3496 cm_msg(MERROR, "init_sequencer", "Sequencer error: mismatching /Sequencer/State structure, db_check_record() status %d", status);
3497 return;
3498 }
3499
3500 status = db_find_key(c->hDB, c->hSeq, "State", &hKey);
3501 if (status != DB_SUCCESS) {
3502 cm_msg(MERROR, "init_sequencer", "Sequencer error: Cannot find /Sequencer/State, db_find_key() status %d", status);
3503 return;
3504 }
3505
3506 int size = sizeof(seq);
3507 status = db_get_record1(c->hDB, hKey, &seq, &size, 0, strcomb1(sequencer_str).c_str());
3508 if (status != DB_SUCCESS) {
3509 cm_msg(MERROR, "init_sequencer", "Sequencer error: Cannot get /Sequencer/State, db_get_record1() status %d", status);
3510 return;
3511 }
3512
3513 if (strlen(seq.path) > 0 && seq.path[strlen(seq.path) - 1] != DIR_SEPARATOR) {
3514 mstrlcat(seq.path, DIR_SEPARATOR_STR, sizeof(seq.path));
3515 }
3516
3517 if (seq.filename[0])
3518 seq_open_file(seq.filename, seq, c);
3519
3521
3522 db_set_record(c->hDB, hKey, &seq, sizeof(seq), 0);
3523
3524 status = db_watch(c->hDB, hKey, seq_watch, c);
3525 if (status != DB_SUCCESS) {
3526 cm_msg(MERROR, "init_sequencer", "Sequencer error: Cannot watch /Sequencer/State, db_watch() status %d", status);
3527 return;
3528 }
3529
3530 midas::odb command = {
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},
3540 {"Goto line", 0},
3541 };
3542 command.connect_and_fix_structure("/" + c->odb_path + "/Command");
3543
3544 status = db_find_key(c->hDB, c->hSeq, "Command", &hKey);
3545 if (status != DB_SUCCESS) {
3546 cm_msg(MERROR, "init_sequencer", "Sequencer error: Cannot find /Sequencer/Command, db_find_key() status %d", status);
3547 return;
3548 }
3549
3551 if (status != DB_SUCCESS) {
3552 cm_msg(MERROR, "init_sequencer", "Sequencer error: Cannot watch /Sequencer/Command, db_watch() status %d", status);
3553 return;
3554 }
3555}
void connect_and_fix_structure(std::string path)
Definition odbxx.cxx:1472
#define DB_STRUCT_MISMATCH
Definition midas.h:655
#define DB_SUCCESS
Definition midas.h:632
#define MERROR
Definition midas.h:559
INT cm_msg(INT message_type, const char *filename, INT line, const char *routine, const char *format,...)
Definition midas.cxx:939
std::string strcomb1(const char **list)
Definition odb.cxx:684
INT db_get_record1(HNDLE hDB, HNDLE hKey, void *data, INT *buf_size, INT align, const char *rec_str)
Definition odb.cxx:12395
INT db_check_record(HNDLE hDB, HNDLE hKey, const char *keyname, const char *rec_str, BOOL correct)
Definition odb.cxx:13564
INT db_watch(HNDLE hDB, HNDLE hKey, void(*dispatcher)(INT, INT, INT, void *), void *info)
Definition odb.cxx:14406
INT db_find_key(HNDLE hDB, HNDLE hKey, const char *key_name, HNDLE *subhKey)
Definition odb.cxx:4751
INT db_set_record(HNDLE hDB, HNDLE hKey, void *data, INT buf_size, INT align)
Definition odb.cxx:12881
static void seq_watch(HNDLE hDB, HNDLE hKeyChanged, int index, void *info)
MVOdb * gOdb
static void seq_watch_command(HNDLE hDB, HNDLE hKeyChanged, int index, void *info)
static void seq_open_file(const char *str, SEQUENCER &seq, SeqCon *c)
HNDLE hKey
#define DIR_SEPARATOR
Definition midas.h:193
INT HNDLE
Definition midas.h:132
#define DIR_SEPARATOR_STR
Definition midas.h:194
DWORD status
Definition odbhist.cxx:39
BOOL transition_request
Definition sequencer.h:26
char filename[256]
Definition sequencer.h:10
char path[256]
Definition sequencer.h:9
Here is the call graph for this function:
Here is the caller graph for this function:

◆ is_valid_number()

bool is_valid_number ( const char *  str)

Definition at line 1564 of file msequencer.cxx.

1564 {
1565 std::string s(str);
1566 std::stringstream ss;
1567 ss << s;
1568 double num = 0;
1569 ss >> num;
1570 if (ss.good())
1571 return false;
1572 else if (num == 0 && s[0] != '0')
1573 return false;
1574 else if (s[0] == 0)
1575 return false;
1576 return true;
1577}
Here is the caller graph for this function:

◆ loadMSL()

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

Definition at line 1904 of file msequencer.cxx.

1904 {
1905
1906 std::ifstream file(filename);
1907 if (!file.is_open())
1908 return false;
1909
1910 std::vector<std::string> lines;
1911 std::string line;
1912
1913 // read all lines from file and put it into array
1914 while (std::getline(file, line))
1915 lines.push_back(line);
1916 file.close();
1917
1918 o->WSA("Script/Lines", lines, 0);
1919
1920 return true;
1921}
Here is the caller graph for this function:

◆ main()

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

Definition at line 3559 of file msequencer.cxx.

3559 {
3560 int daemon = FALSE;
3561 int status, ch;
3562 char midas_hostname[256];
3563 char midas_expt[256];
3564 std::string seq_name = "";
3565
3566 setbuf(stdout, NULL);
3567 setbuf(stderr, NULL);
3568#ifdef SIGPIPE
3569 /* avoid getting killed by "Broken pipe" signals */
3570 signal(SIGPIPE, SIG_IGN);
3571#endif
3572
3573 /* get default from environment */
3574 cm_get_environment(midas_hostname, sizeof(midas_hostname), midas_expt, sizeof(midas_expt));
3575
3576 /* parse command line parameters */
3577 for (int i = 1; i < argc; i++) {
3578 if (argv[i][0] == '-' && argv[i][1] == 'D') {
3579 daemon = TRUE;
3580 } else if (argv[i][0] == '-') {
3581 if (i + 1 >= argc || argv[i + 1][0] == '-')
3582 goto usage;
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];
3589 } else {
3590 usage:
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");
3596 return 0;
3597 }
3598 }
3599
3600 if (daemon) {
3601 printf("Becoming a daemon...\n");
3603 }
3604
3605 std::string prg_name = "Sequencer";
3606 std::string odb_path = "Sequencer";
3607
3608 if (!seq_name.empty()) {
3609 prg_name = std::string("Sequencer") + seq_name; // sequencer program name
3610 odb_path = std::string("Sequencer") + seq_name; // sequencer ODB path
3611 }
3612
3613#ifdef OS_LINUX
3614 std::string pid_filename;
3615 pid_filename += "/var/run/";
3616 pid_filename += prg_name;
3617 pid_filename += ".pid";
3618 /* write PID file */
3619 FILE *f = fopen(pid_filename.c_str(), "w");
3620 if (f != NULL) {
3621 fprintf(f, "%d", ss_getpid());
3622 fclose(f);
3623 }
3624#endif
3625
3626 /*---- connect to experiment ----*/
3627 status = cm_connect_experiment1(midas_hostname, midas_expt, prg_name.c_str(), NULL, DEFAULT_ODB_SIZE, DEFAULT_WATCHDOG_TIMEOUT);
3629 return 1;
3630 else if (status == DB_INVALID_HANDLE) {
3631 std::string s = cm_get_error(status);
3632 puts(s.c_str());
3633 } else if (status != CM_SUCCESS) {
3634 std::string s = cm_get_error(status);
3635 puts(s.c_str());
3636 return 1;
3637 }
3638
3639 /* check if sequencer already running */
3640 status = cm_exist(prg_name.c_str(), TRUE);
3641 if (status == CM_SUCCESS) {
3642 printf("%s runs already.\n", prg_name.c_str());
3644 return 1;
3645 }
3646
3647 HNDLE hDB;
3649 gOdb = MakeMidasOdb(hDB);
3650
3651 SEQUENCER seq;
3652 SeqCon c;
3653
3654 c.seqp = &seq;
3655 c.hDB = hDB;
3656 c.seq_name = seq_name;
3657 c.prg_name = prg_name;
3658 c.odb_path = odb_path;
3659
3660 init_sequencer(seq, &c);
3661
3662 if (seq_name.empty()) {
3663 printf("Sequencer started. Stop with \"!\"\n");
3664 } else {
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()); // FIXME: seq_name should be URL-encoded! K.O. Aug 2023
3667 printf("Stop with \"!\"\n");
3668 }
3669
3670 // if any commands are active, process them now
3671 seq_watch_command(hDB, 0, 0, &c);
3672
3673 /* initialize ss_getchar */
3674 ss_getchar(0);
3675
3676 /* main loop */
3677 do {
3678 try {
3679 sequencer(seq, &c);
3680 } catch (std::string &msg) {
3681 seq_error(seq, &c, msg.c_str());
3682 } catch (const char *msg) {
3683 seq_error(seq, &c, msg);
3684 }
3685
3686 status = cm_yield(0);
3687
3688 ch = 0;
3689 while (ss_kbhit()) {
3690 ch = ss_getchar(0);
3691 if (ch == -1)
3692 ch = getchar();
3693
3694 if ((char) ch == '!')
3695 break;
3696 }
3697
3698 } while (status != RPC_SHUTDOWN && ch != '!');
3699
3700 /* reset terminal */
3702
3703 /* close network connection to server */
3705
3706 return 0;
3707}
SEQUENCER * seqp
static void usage()
INT cm_yield(INT millisec)
Definition midas.cxx:5716
INT cm_get_experiment_database(HNDLE *hDB, HNDLE *hKeyClient)
Definition midas.cxx:3083
INT cm_exist(const char *name, BOOL bClientName)
Definition midas.cxx:7594
INT cm_connect_experiment1(const char *host_name, const char *default_exp_name, const char *client_name, void(*func)(char *), INT odb_size, DWORD watchdog_timeout)
Definition midas.cxx:2371
INT cm_disconnect_experiment(void)
Definition midas.cxx:2918
INT cm_get_environment(char *host_name, int host_name_size, char *exp_name, int exp_name_size)
Definition midas.cxx:2208
#define CM_SUCCESS
Definition midas.h:582
#define CM_WRONG_PASSWORD
Definition midas.h:589
#define DB_INVALID_HANDLE
Definition midas.h:636
#define RPC_SHUTDOWN
Definition midas.h:708
BOOL ss_kbhit()
Definition system.cxx:3743
INT ss_getchar(BOOL reset)
Definition system.cxx:7588
INT ss_getpid(void)
Definition system.cxx:1379
INT ss_daemon_init(BOOL keep_stdout)
Definition system.cxx:2073
std::string cm_get_error(INT code)
Definition midas.cxx:473
void init_sequencer(SEQUENCER &seq, SeqCon *c)
void sequencer(SEQUENCER &seq, SeqCon *c)
BOOL daemon
Definition mana.cxx:258
HNDLE hDB
main ODB handle
Definition mana.cxx:207
#define DEFAULT_WATCHDOG_TIMEOUT
Definition midas.h:290
#define DEFAULT_ODB_SIZE
Definition midas.h:270
Here is the call graph for this function:

◆ msl_parse()

static BOOL msl_parse ( SEQUENCER seq,
SeqCon c,
int  level,
const char *  cpath,
const char *  filename,
const char *  xml_filename,
char *  error,
int  error_size,
int *  error_line 
)
static

Definition at line 1925 of file msequencer.cxx.

1926 {
1927 char str[256], *pl, *pe;
1928 char list[100][XNAME_LENGTH], list2[100][XNAME_LENGTH], **lines;
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;
1935
1936 if (level > 10) {
1937 snprintf(error, error_size, "More than 10 nested INCLUDE statements exceeded in file \"%s\"", filename);
1938 return FALSE;
1939 }
1940
1941 rel_path = (filename[0] != DIR_SEPARATOR);
1942 path = std::string(cpath);
1943 if (path.length() > 0 && path.back() != '/')
1944 path += '/';
1945
1946 std::string fullFilename;
1947 if (rel_path)
1948 fullFilename = path + filename;
1949 else
1950 fullFilename = filename;
1951
1952 int fhin = open(fullFilename.c_str(), O_RDONLY | O_TEXT);
1953 if (fhin < 0) {
1954 snprintf(error, error_size, "Cannot open \"%s\", errno %d (%s)", fullFilename.c_str(), errno, strerror(errno));
1955 return FALSE;
1956 }
1957
1958 off_t off = lseek(fhin, 0, SEEK_END);
1959 if (off < 0) {
1960 snprintf(error, error_size, "Cannot find size of \"%s\", lseek(SEEK_END) errno %d (%s)", fullFilename.c_str(), errno, strerror(errno));
1961 close(fhin);
1962 return FALSE;
1963 }
1964
1965 lseek(fhin, 0, SEEK_SET);
1966
1967 std::string s;
1968 if (rel_path)
1969 s = path + xml_filename;
1970 else
1971 s = xml_filename;
1972
1973 FILE *fout = fopen(s.c_str(), "wt");
1974 if (fout == NULL) {
1975 snprintf(error, error_size, "Cannot write to \"%s\", fopen() errno %d (%s)", s.c_str(), errno, strerror(errno));
1976 close(fhin);
1977 return FALSE;
1978 }
1979
1980 size_t size = off;
1981
1982 char* buf = (char *) malloc(size + 1);
1983 ssize_t rd = read(fhin, buf, size);
1984
1985 if (rd < 0) {
1986 snprintf(error, error_size, "Cannot read \"%s\", read(%zu) errno %d (%s)", fullFilename.c_str(), size, errno, strerror(errno));
1987 size = 0;
1988 } else {
1989 size = rd;
1990 }
1991
1992 buf[size] = 0;
1993 close(fhin);
1994
1995 /* look for any includes */
1996 lines = (char **) malloc(sizeof(char *));
1997 incl = 0;
1998 pl = buf;
1999 library = FALSE;
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');
2005 *pe = 0;
2006 if (*(pe - 1) == '\r') {
2007 *(pe - 1) = 0;
2008 }
2009 pe++;
2010 } else
2011 pe = pl + strlen(pl);
2012 mstrlcpy(str, pl, sizeof(str));
2013 pl = pe;
2014 strbreak(str, list, 100, ", ", FALSE);
2015 if (equal_ustring(list[0], "subroutine") && list[1][0])
2016 subroutine_names.emplace_back(list[1]);
2017 if (equal_ustring(list[0], "include")) {
2018 if (!incl) {
2019 xml += "<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>\n";
2020 xml += "<!DOCTYPE RunSequence [\n";
2021 incl = 1;
2022 }
2023
2024 // if a path is given, use filename as entity reference
2025 char *reference = strrchr(list[1], '/');
2026 if (reference)
2027 reference++;
2028 else
2029 reference = list[1];
2030
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);
2033 return FALSE;
2034 }
2035
2036 std::string p;
2037 if (list[1][0] == '/') {
2038 p = std::string(cm_get_path());
2039 p += "userfiles/sequencer";
2040 p += list[1];
2041 } else {
2042 p = path;
2043 if (!p.empty() && p.back() != '/')
2044 p += "/";
2045 p += list[1];
2046 }
2047
2048 xml += " <!ENTITY ";
2049 xml += reference;
2050 xml += " SYSTEM \"";
2051 xml += p;
2052 xml += ".xml\">\n";
2053
2054 // recurse
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);
2063
2064 include_error = error + strlen(error);
2065 include_error_size = error_size - strlen(error);
2066
2067 std::string path(cm_get_path());
2068 path += "userfiles/sequencer/";
2069 path += seq.path;
2070
2071 include_status = msl_parse(seq, c, level+1, path.c_str(), msl_include, xml_include, include_error, include_error_size, error_line);
2072 free(msl_include);
2073 free(xml_include);
2074
2075 if (!include_status) {
2076 // report the error on CALL line instead of the one in included file
2077 *error_line = n_lines + 1;
2078 return FALSE;
2079 }
2080 }
2081 if (equal_ustring(list[0], "library")) {
2082 xml += "<Library name=\"";
2083 xml += list[1];
2084 xml += "\">\n";
2085 library = TRUE;
2086 }
2087 }
2088 if (incl) {
2089 xml += "]>\n";
2090 } else if (!library) {
2091 xml += "<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>\n";
2092 }
2093
2094 /* parse rest of file */
2095 if (!library) {
2096 xml += "<RunSequence xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:noNamespaceSchemaLocation=\"\">\n";
2097 }
2098
2099 std::vector<std::string> slines;
2100 for (line = 0; line < n_lines; line++) {
2101 slines.push_back(lines[line]);
2102 }
2103
2104 c->odbs->WSA("Script/Lines", slines, 0);
2105
2106 /* save parameters */
2107 std::string p = "/" + c->odb_path + "/Param/Value";
2108 midas::odb oldSeqParam(p);
2109 oldSeqParam.set_auto_refresh_read(false);
2110 oldSeqParam.set_auto_create(false);
2111
2112 /* clear all variables */
2113 if (!seq.running) {
2114 c->odbs->Delete("Variables");
2115 c->odbs->Delete("Param");
2116 }
2117
2118 for (line = 0; line < n_lines; line++) {
2119 char *p1 = lines[line];
2120 while (*p1 == ' ')
2121 p1++;
2122 mstrlcpy(list[0], p1, sizeof(list[0]));
2123 if (strchr(list[0], ' '))
2124 *strchr(list[0], ' ') = 0;
2125 p1 += strlen(list[0]);
2126 if (*p1)
2127 n = strbreak(p1 + 1, &list[1], 99, ",", FALSE) + 1;
2128 else {
2129 memset(&list[1], 0, 99 * XNAME_LENGTH);
2130 n = 1;
2131 }
2132
2133 /* remove any full comment line */
2134 for (i = 0; i < n; i++) {
2135 if (list[i][0] == '#') {
2136 for (j = i; j < n; j++)
2137 list[j][0] = 0;
2138 break;
2139 }
2140 }
2141
2142 /* cut any partial comment line */
2143 for (i = 0; i < n; i++) {
2144 if (strchr(list[i], '#'))
2145 *strchr(list[i], '#') = 0;
2146 }
2147
2148 /* strip any trailing blanks */
2149 for (i = 0; i < n; i++) {
2150 while (strlen(list[i]) > 0 && list[i][strlen(list[i])-1] == ' ')
2151 list[i][strlen(list[i])-1] = 0;
2152 }
2153
2154 /* check for variable assignment */
2155 char eq[1024];
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++) {
2160 if (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] != '>'))
2164 n++;
2165 }
2166 if (n == 1 && eq[0] != '=') {
2167 // equation found
2168 mstrlcpy(list[0], "SET", sizeof(list[0]));
2169 p1 = eq;
2170 while (*p1 == ' ')
2171 p1++;
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;
2177 while (*p1 == ' ')
2178 p1++;
2179 mstrlcpy(list[2], p1, sizeof(list[2]));
2180 while (strlen(list[2]) > 0 && list[2][strlen(list[2])-1] == ' ')
2181 list[2][strlen(list[2])-1] = 0;
2182 }
2183
2184 SeqCommand* parse_command = seq_find_msl_command(list[0]);
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);
2187 if (!parse_command->parse_msl(ctx))
2188 return FALSE;
2189
2190 } else if (equal_ustring(list[0], "library")) {
2191
2192 } else if (equal_ustring(list[0], "include")) {
2193 // if a path is given, use filename as entity reference
2194 char *reference = strrchr(list[1], '/');
2195 if (reference)
2196 reference++;
2197 else
2198 reference = list[1];
2199
2200 xml += "&";
2201 xml += reference;
2202 xml += ";\n";
2203
2204 } else if (equal_ustring(list[0], "call") ||
2205 std::any_of(subroutine_names.begin(), subroutine_names.end(),
2206 [&](const std::string &name) { return equal_ustring(list[0], name.c_str()); })) {
2207 bool explicit_call = equal_ustring(list[0], "call");
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) {
2212 xml += ",";
2213 }
2214 xml += list[i];
2215 }
2216 xml += "</Call>\n";
2217
2218 } else if (equal_ustring(list[0], "goto")) {
2219 xml += "<Goto " + qtoString(fullFilename, line + 1, level) + " sline=" + q(list[1]) + " />\n";
2220
2221 } else if (equal_ustring(list[0], "if")) {
2222 xml += "<If " + qtoString(fullFilename, line + 1, level) + " condition=\"";
2223 for (i = 1; i < 100 && list[i][0] && stricmp(list[i], "THEN") != 0; i++) {
2224 xml += list[i];
2225 }
2226 xml += "\">\n";
2227
2228 } else if (equal_ustring(list[0], "else")) {
2229 xml += "<Else />\n";
2230
2231 } else if (equal_ustring(list[0], "endif")) {
2232 xml += "</If>\n";
2233
2234 } else if (equal_ustring(list[0], "loop")) {
2235 /* find end of loop */
2236 for (i = line, nest = 0; i < n_lines; i++) {
2237 strbreak(lines[i], list2, 100, ", ", FALSE);
2238 if (equal_ustring(list2[0], "loop"))
2239 nest++;
2240 if (equal_ustring(list2[0], "endloop")) {
2241 nest--;
2242 if (nest == 0)
2243 break;
2244 }
2245 }
2246 if (i < n_lines)
2247 endl = i + 1;
2248 else
2249 endl = line + 1;
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=" +
2254 q(list[2]) + ">\n";
2255 } else {
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++) {
2258 if (i > 2) {
2259 xml += ",";
2260 }
2261 xml += list[i];
2262 }
2263 xml += "\">\n";
2264 }
2265 } else if (equal_ustring(list[0], "endloop")) {
2266 xml += "</Loop>\n";
2267
2268 } else if (equal_ustring(list[0], "break")) {
2269 xml += "<Break "+ qtoString(fullFilename, line + 1, level) +"></Break>\n";
2270
2271 } else if (equal_ustring(list[0], "odbsubdir")) {
2272 if (list[2][0]) {
2273 xml += "<ODBSubdir " + qtoString(fullFilename, line + 1, level) + " notify=" + q(list[2]) + " path=" + q(list[1]) + ">\n";
2274 } else {
2275 xml += "<ODBSubdir " + qtoString(fullFilename, line + 1, level) + " path=" + q(list[1]) + ">\n";
2276 }
2277 } else if (equal_ustring(list[0], "endodbsubdir")) {
2278 xml += "</ODBSubdir>\n";
2279
2280 } else if (equal_ustring(list[0], "param")) {
2281 if (list[2][0] == 0 || equal_ustring(list[2], "bool")) { // name and bool
2282 snprintf(error, error_size, "Parameter \"%s\" misses 'comment'", list[1]);
2283 *error_line = line + 1;
2284 return FALSE;
2285
2286 } else if (!list[4][0] && equal_ustring(list[3], "bool")) { // name, comment and bool
2287 xml += "<Param " + qtoString(fullFilename, line + 1, level) + " name=" + q(list[1]) + " type=\"bool\" " + " comment=" + q(list[2]) + "/>\n";
2288 bool v = false;
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]);
2291 } else if (!list[5][0] && equal_ustring(list[4], "bool")) { // name, comment, default and bool
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]);
2298
2299 } else if (!list[3][0]) { // name and comment
2300 xml += "<Param " + qtoString(fullFilename, line + 1, level) + " name=" + q(list[1]) + " comment=" + q(list[2]) + " />\n";
2301 std::string v;
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]) { // name, comment and default
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]);
2310 // ss_sleep(1000); // use this for parameter test
2311 } else {
2312 xml += "<Param " + qtoString(fullFilename, line + 1, level) + " name=" + q(list[1]) + " comment=" + q(list[2]) +
2313 " options=\"";
2314 std::string v;
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++) {
2319 if (i > 3) {
2320 xml += ",";
2321 }
2322 xml += list[i];
2323 options.push_back(list[i]);
2324 }
2325 xml += "\" />\n";
2326 c->odbs->WSA((std::string("Param/Options/") + list[1]).c_str(), options, 0);
2327 }
2328
2329 // put back old parameter value if existing
2330 try {
2331 std::string ov = oldSeqParam[(const char *)list[1]];
2332 c->odbs->WS((std::string("Param/Value/") + list[1]).c_str(), ov.c_str());
2333 } catch(mexception &e) {}
2334
2335 } else if (equal_ustring(list[0], "subroutine")) {
2336 xml += "\n<Subroutine " + qtoString(fullFilename, line + 1, level) + " name=" + q(list[1]) + ">\n";
2337
2338 } else if (equal_ustring(list[0], "endsubroutine")) {
2339 xml += "</Subroutine>\n";
2340
2341 } else if (list[0][0] == 0 || list[0][0] == '#') {
2342 /* skip empty or out-commented lines */
2343 } else {
2344 snprintf(error, error_size, "Invalid command \"%s\"", list[0]);
2345 *error_line = line + 1;
2346 return FALSE;
2347 }
2348 }
2349
2350 free(lines);
2351 free(buf);
2352 if (library) {
2353 xml += "\n</Library>\n";
2354 } else {
2355 xml += "</RunSequence>\n";
2356 }
2357
2358 // write XML to .xml file
2359 fprintf(fout, "%s", xml.c_str());
2360 fclose(fout);
2361
2362 return TRUE;
2363}
std::string cm_get_path()
Definition midas.cxx:1587
#define O_TEXT
Definition msystem.h:227
static SeqCommand * seq_find_msl_command(const char *name)
static std::string qtoString(std::string filename, int line, int level)
static BOOL msl_parse(SEQUENCER &seq, SeqCon *c, int level, const char *cpath, const char *filename, const char *xml_filename, char *error, int error_size, int *error_line)
static std::string q(const char *s)
std::vector< FMT_ID > eq
Definition mdump.cxx:55
DWORD BOOL
Definition midas.h:105
#define read(n, a, f)
#define name(x)
Definition midas_macro.h:24
INT j
Definition odbhist.cxx:40
BOOL running
Definition sequencer.h:18
BOOL(* parse_msl)(SeqParseContext &ctx)
static double e(void)
Definition tinyexpr.c:136
Here is the call graph for this function:
Here is the caller graph for this function:

◆ q()

static std::string q ( const char *  s)
static

Definition at line 142 of file msequencer.cxx.

142 {
143 return "\"" + std::string(s) + "\"";
144}
Here is the caller graph for this function:

◆ qtoString()

static std::string qtoString ( std::string  filename,
int  line,
int  level 
)
static

Definition at line 134 of file msequencer.cxx.

134 {
135 std::string buf = "l=\"" + std::to_string(line) + "\"";
136 buf += " fn=\"" + filename + "\"";
137 if (level)
138 buf += " lvl=\"" + std::to_string(level) + "\"";
139 return buf;
140}
Here is the caller graph for this function:

◆ seq_array_index()

void seq_array_index ( SEQUENCER seq,
SeqCon c,
char *  odbpath,
int *  index1,
int *  index2 
)

Definition at line 2945 of file msequencer.cxx.

2945 {
2946 char str[256];
2947 *index1 = *index2 = 0;
2948 if (odbpath[strlen(odbpath) - 1] == ']') {
2949 if (strchr(odbpath, '[')) {
2950 //check for sequencer variables
2951 if (strchr((strchr(odbpath, '[') + 1), '$')) {
2952 mstrlcpy(str, strchr(odbpath, '[') + 1, sizeof(str));
2953 if (strchr(str, ']'))
2954 *strchr(str, ']') = 0;
2955 *index1 = atoi(eval_var(seq, c, str).c_str());
2956
2957 *strchr(odbpath, '[') = 0;
2958 } else {
2959 //standard expansion
2960 strarrayindex(odbpath, index1, index2);
2961 }
2962 }
2963 }
2964}
void strarrayindex(char *odbpath, int *index1, int *index2)
Definition odb.cxx:3852
Here is the call graph for this function:
Here is the caller graph for this function:

◆ seq_cancel_stop_after_run()

static void seq_cancel_stop_after_run ( SEQUENCER seq,
SeqCon c 
)
static

Definition at line 2524 of file msequencer.cxx.

2524 {
2525 seq_read(&seq, c);
2526 seq.stop_after_run = false;
2527 seq_write(seq, c);
2528}
BOOL stop_after_run
Definition sequencer.h:25
Here is the call graph for this function:
Here is the caller graph for this function:

◆ seq_clear()

void seq_clear ( SEQUENCER seq)

Definition at line 2403 of file msequencer.cxx.

2403 {
2404 seq.running = FALSE;
2405 seq.finished = FALSE;
2406 seq.paused = FALSE;
2408 seq.wait_limit = 0;
2409 seq.wait_value = 0;
2410 seq.timeout_limit = 0;
2411 seq.timeout_value = 0;
2412 seq.start_time = 0;
2413 seq.wait_type[0] = 0;
2414 seq.wait_odb[0] = 0;
2415 for (int i = 0; i < SEQ_NEST_LEVEL_LOOP; i++) {
2416 seq.loop_start_line[i] = 0;
2417 seq.sloop_start_line[i] = 0;
2418 seq.loop_end_line[i] = 0;
2419 seq.sloop_end_line[i] = 0;
2420 seq.loop_counter[i] = 0;
2421 seq.loop_n[i] = 0;
2422 }
2423 for (int i = 0; i < SEQ_NEST_LEVEL_IF; i++) {
2424 seq.if_else_line[i] = 0;
2425 seq.if_endif_line[i] = 0;
2426 }
2427 for (int i = 0; i < SEQ_NEST_LEVEL_SUB; i++) {
2428 seq.subroutine_end_line[i] = 0;
2429 seq.subroutine_return_line[i] = 0;
2430 seq.subroutine_call_line[i] = 0;
2431 seq.ssubroutine_call_line[i] = 0;
2432 seq.subroutine_param[i][0] = 0;
2433 }
2434 seq.current_line_number = 0;
2435 seq.scurrent_line_number = 0;
2436 seq.sfilename[0] = 0;
2437 seq.if_index = 0;
2438 seq.stack_index = 0;
2439 seq.error[0] = 0;
2440 seq.error_line = 0;
2441 seq.serror_line = 0;
2442 seq.subdir[0] = 0;
2443 seq.subdir_end_line = 0;
2444 seq.subdir_not_notify = 0;
2445 seq.message[0] = 0;
2446 seq.message_wait = FALSE;
2447 seq.stop_after_run = FALSE;
2448}
#define SEQ_NEST_LEVEL_IF
Definition sequencer.h:4
#define SEQ_NEST_LEVEL_LOOP
Definition sequencer.h:3
int serror_line
Definition sequencer.h:15
char wait_odb[256]
Definition sequencer.h:52
int if_index
Definition sequencer.h:36
float wait_value
Definition sequencer.h:46
int loop_end_line[SEQ_NEST_LEVEL_LOOP]
Definition sequencer.h:29
float wait_limit
Definition sequencer.h:47
float timeout_value
Definition sequencer.h:48
int sloop_start_line[SEQ_NEST_LEVEL_LOOP]
Definition sequencer.h:28
int error_line
Definition sequencer.h:14
BOOL finished
Definition sequencer.h:19
BOOL message_wait
Definition sequencer.h:17
int loop_start_line[SEQ_NEST_LEVEL_LOOP]
Definition sequencer.h:27
int if_else_line[SEQ_NEST_LEVEL_IF]
Definition sequencer.h:38
int sloop_end_line[SEQ_NEST_LEVEL_LOOP]
Definition sequencer.h:30
char subdir[256]
Definition sequencer.h:33
char message[256]
Definition sequencer.h:16
BOOL paused
Definition sequencer.h:20
int if_endif_line[SEQ_NEST_LEVEL_IF]
Definition sequencer.h:39
DWORD start_time
Definition sequencer.h:50
int subroutine_call_line[SEQ_NEST_LEVEL_SUB]
Definition sequencer.h:43
int loop_n[SEQ_NEST_LEVEL_LOOP]
Definition sequencer.h:32
int subdir_end_line
Definition sequencer.h:34
int loop_counter[SEQ_NEST_LEVEL_LOOP]
Definition sequencer.h:31
char error[256]
Definition sequencer.h:13
float timeout_limit
Definition sequencer.h:49
int scurrent_line_number
Definition sequencer.h:23
char wait_type[32]
Definition sequencer.h:51
char sfilename[256]
Definition sequencer.h:11
int subdir_not_notify
Definition sequencer.h:35
Here is the caller graph for this function:

◆ seq_clear_wait_state()

static void seq_clear_wait_state ( SEQUENCER seq)
static

Definition at line 2683 of file msequencer.cxx.

2683 {
2684 seq.start_time = 0;
2685 seq.wait_limit = 0;
2686 seq.wait_value = 0;
2687 seq.timeout_limit = 0;
2688 seq.timeout_value = 0;
2689 seq.wait_type[0] = 0;
2690 seq.wait_odb[0] = 0;
2691}
Here is the caller graph for this function:

◆ seq_error()

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

Definition at line 1581 of file msequencer.cxx.

1581 {
1582 int status;
1583 HNDLE hKey;
1584
1585 mstrlcpy(seq.error, str, sizeof(seq.error));
1588 seq.running = FALSE;
1590
1591 status = db_find_key(c->hDB, c->hSeq, "State", &hKey);
1592 if (status != DB_SUCCESS)
1593 return;
1594 status = db_set_record(c->hDB, hKey, &seq, sizeof(seq), 0);
1595 if (status != DB_SUCCESS)
1596 return;
1597
1598 cm_msg(MTALK, "sequencer", "Sequencer has stopped with error.");
1599}
#define MTALK
Definition midas.h:564
Here is the call graph for this function:
Here is the caller graph for this function:

◆ seq_execute_cat()

static BOOL seq_execute_cat ( SeqExecContext ctx)
static

Definition at line 695 of file msequencer.cxx.

696{
697 SEQUENCER& seq = ctx.seq;
698 SeqCon* c = ctx.c;
699 PMXML_NODE pn = ctx.pn;
700 char data[256], str[1024], name[32];
701 int size;
702
703 if (!mxml_get_attribute(pn, "name")) {
704 seq_error(seq, c, "Missing variable name");
705 return FALSE;
706 }
707
708 mstrlcpy(name, mxml_get_attribute(pn, "name"), sizeof(name));
709 if (!concatenate(seq, c, data, sizeof(data), mxml_get_value(pn)))
710 return FALSE;
711 sprintf(str, "Variables/%s", name); // FIXME: unsafe
712 size = strlen(data) + 1;
713 if (size < 32)
714 size = 32;
715 db_set_value(c->hDB, c->hSeq, str, data, size, 1, TID_STRING);
716
717 seq.current_line_number = mxml_get_line_number_end(pn) + 1;
718 return TRUE;
719}
#define TID_STRING
Definition midas.h:346
INT db_set_value(HNDLE hDB, HNDLE hKeyRoot, const char *key_name, const void *data, INT data_size, INT num_values, DWORD type)
Definition odb.cxx:5523
int concatenate(SEQUENCER &seq, SeqCon *c, char *result, int size, char *value)
void * data
Definition mana.cxx:268
SEQUENCER & seq
PMXML_NODE pn
static void pn(const te_expr *n, int depth)
Definition tinyexpr.c:702
Here is the call graph for this function:

◆ seq_execute_exit()

static BOOL seq_execute_exit ( SeqExecContext ctx)
static

Definition at line 995 of file msequencer.cxx.

996{
997 seq_stop(ctx.seq, ctx.c);
998 cm_msg(MTALK, "sequencer", "Sequencer is finished.");
999 return FALSE;
1000}
static void seq_stop(SEQUENCER &seq, SeqCon *c)
Here is the call graph for this function:

◆ seq_execute_message()

static BOOL seq_execute_message ( SeqExecContext ctx)
static

Definition at line 523 of file msequencer.cxx.

524{
525 SEQUENCER& seq = ctx.seq;
526 SeqCon* c = ctx.c;
527 PMXML_NODE pn = ctx.pn;
528 std::string value;
529
530 if (strchr(mxml_get_value(pn), '$')) // evaluate message string if $ present
531 value = eval_var(seq, c, mxml_get_value(pn));
532 else
533 value = mxml_get_value(pn); // treat message as string
534 const char *wait_attr = mxml_get_attribute(pn, "wait");
535 bool wait = false;
536 if (wait_attr)
537 wait = (atoi(wait_attr) == 1);
538
539 if (!wait) {
540 // message with no wait: set seq.message and move on. we do not care if web page clears it
541 mstrlcpy(seq.message, value.c_str(), sizeof(seq.message));
542 seq.message_wait = FALSE;
543 db_set_record(c->hDB, ctx.hKeySeq, &seq, sizeof(seq), 0);
544 } else {
545 // message with wait
546
547 // if message_wait not set, we are here for the first time
548 if (!seq.message_wait) {
549 mstrlcpy(seq.message, value.c_str(), sizeof(seq.message));
550 seq.message_wait = TRUE;
551 db_set_record(c->hDB, ctx.hKeySeq, &seq, sizeof(seq), 0);
552 // wait
553 return FALSE;
554 } else {
555 // message_wait is set, we have been here before
556
557 // if web page did not clear the message, keep waiting
558 if (seq.message[0] != 0) {
559 // wait
560 return FALSE;
561 }
562
563 // web page cleared the message, we are done with waiting
564 seq.message_wait = false;
565 }
566 }
567
568 seq.current_line_number = mxml_get_line_number_end(pn) + 1;
569 return TRUE;
570}
Here is the call graph for this function:

◆ seq_execute_msg()

static BOOL seq_execute_msg ( SeqExecContext ctx)
static

Definition at line 572 of file msequencer.cxx.

573{
574 SEQUENCER& seq = ctx.seq;
575 SeqCon* c = ctx.c;
576 PMXML_NODE pn = ctx.pn;
577 std::string value;
578
579 if (strchr(mxml_get_value(pn), '$')) // evaluate message string if $ present
580 value = eval_var(seq, c, mxml_get_value(pn));
581 else
582 value = mxml_get_value(pn); // treat message as string
583 std::string type = "INFO";
584 if (mxml_get_attribute(pn, "type"))
585 type = std::string(mxml_get_attribute(pn, "type"));
586
587 if (type == "ERROR")
588 cm_msg(MERROR, "sequencer", "%s", value.c_str());
589 else if (type == "DEBUG")
590 cm_msg(MDEBUG, "sequencer", "%s", value.c_str());
591 else if (type == "LOG")
592 cm_msg(MLOG, "sequencer", "%s", value.c_str());
593 else if (type == "TALK")
594 cm_msg(MTALK, "sequencer", "%s", value.c_str());
595 else
596 cm_msg(MINFO, "sequencer", "%s", value.c_str());
597
598 seq.current_line_number = mxml_get_line_number_end(pn) + 1;
599 return TRUE;
600}
#define MINFO
Definition midas.h:560
#define MLOG
Definition midas.h:563
#define MDEBUG
Definition midas.h:561
INT type
Definition mana.cxx:269
Here is the call graph for this function:

◆ seq_execute_odbcreate()

static BOOL seq_execute_odbcreate ( SeqExecContext ctx)
static

Definition at line 1222 of file msequencer.cxx.

1223{
1224 SEQUENCER& seq = ctx.seq;
1225 SeqCon* c = ctx.c;
1226 PMXML_NODE pn = ctx.pn;
1227 char odbpath[256];
1228 int status;
1229 HNDLE hKey;
1230 KEY key;
1231
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\"");
1236 } else {
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));
1241
1242 if (strchr(odbpath, '$')) {
1243 std::string s(odbpath);
1244 s = eval_var(seq, c, s);
1245 mstrlcpy(odbpath, s.c_str(), sizeof(odbpath));
1246 }
1247
1248 /* get TID */
1249 unsigned int tid;
1250 for (tid = 0; tid < TID_LAST; tid++) {
1251 if (equal_ustring(rpc_tid_name(tid), mxml_get_attribute(pn, "type")))
1252 break;
1253 }
1254
1255 if (tid == TID_LAST)
1256 seq_error(seq, c, "Type must be one of UINT8,INT8,UINT16,INT16,UINT32,INT32,BOOL,FLOAT,DOUBLE,STRING");
1257 else {
1258
1259 status = db_find_key(c->hDB, 0, odbpath, &hKey);
1260 if (status == DB_SUCCESS) {
1261 db_get_key(c->hDB, hKey, &key);
1262 if (key.type != tid) {
1263 db_delete_key(c->hDB, hKey);
1264 status = db_create_key(c->hDB, 0, odbpath, tid);
1265 }
1266 } else {
1267 status = db_create_key(c->hDB, 0, odbpath, tid);
1268 char dummy[32];
1269 memset(dummy, 0, sizeof(dummy));
1270 if (tid == TID_STRING || tid == TID_LINK)
1271 db_set_value(c->hDB, 0, odbpath, dummy, 32, 1, tid);
1272 }
1273
1274 if (status != DB_SUCCESS && status != DB_CREATED) {
1275 seq_error(seq, c, msprintf("Cannot create ODB key \"%s\", error code %d", odbpath, status).c_str());
1276 } else {
1277 status = db_find_key(c->hDB, 0, odbpath, &hKey);
1278 if (mxml_get_attribute(pn, "size")) {
1279 int i = atoi(eval_var(seq, c, mxml_get_attribute(pn, "size")).c_str());
1280 if (i > 1)
1281 db_set_num_values(c->hDB, hKey, i);
1282 }
1283 seq.current_line_number++;
1284 }
1285 }
1286 }
1287
1288 return TRUE;
1289}
#define DB_CREATED
Definition midas.h:633
#define TID_LINK
Definition midas.h:350
#define TID_LAST
Definition midas.h:354
INT db_delete_key(HNDLE hDB, HNDLE hKey, BOOL follow_links)
Definition odb.cxx:4428
INT db_create_key(HNDLE hDB, HNDLE hKey, const char *key_name, DWORD type)
Definition odb.cxx:3887
INT db_get_key(HNDLE hDB, HNDLE hKey, KEY *key)
Definition odb.cxx:6538
INT db_set_num_values(HNDLE hDB, HNDLE hKey, INT num_values)
Definition odb.cxx:8018
const char * rpc_tid_name(INT id)
Definition midas.cxx:11997
KEY key
Definition mdump.cxx:34
std::string msprintf(const char *format,...)
Definition midas.cxx:419
Definition midas.h:1027
DWORD type
Definition midas.h:1028
Here is the call graph for this function:

◆ seq_execute_odbdelete()

static BOOL seq_execute_odbdelete ( SeqExecContext ctx)
static

Definition at line 1291 of file msequencer.cxx.

1292{
1293 SEQUENCER& seq = ctx.seq;
1294 SeqCon* c = ctx.c;
1295 PMXML_NODE pn = ctx.pn;
1296 char odbpath[256];
1297 int status;
1298
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));
1303
1304 if (strchr(odbpath, '$')) {
1305 std::string s(odbpath);
1306 s = eval_var(seq, c, s);
1307 mstrlcpy(odbpath, s.c_str(), sizeof(odbpath));
1308 }
1309
1310 status = db_delete(c->hDB, 0, odbpath);
1311 if (status != DB_SUCCESS) {
1312 seq_error(seq, c, msprintf("Cannot delete ODB key \"%s\"", odbpath).c_str());
1313 } else {
1314 seq.current_line_number++;
1315 }
1316
1317 return TRUE;
1318}
INT db_delete(HNDLE hDB, HNDLE hKeyRoot, const char *odb_path)
Definition odb.cxx:4494
Here is the call graph for this function:

◆ seq_execute_odbget()

static BOOL seq_execute_odbget ( SeqExecContext ctx)
static

Definition at line 1081 of file msequencer.cxx.

1082{
1083 SEQUENCER& seq = ctx.seq;
1084 SeqCon* c = ctx.c;
1085 PMXML_NODE pn = ctx.pn;
1086 HNDLE hKeySeq = ctx.hKeySeq;
1087 char odbpath[256], data[256], str[1024], name[32];
1088 std::string value;
1089 int status, size, index1, index2;
1090 HNDLE hKey;
1091 KEY key;
1092
1093 if (!mxml_get_attribute(pn, "path")) {
1094 seq_error(seq, c, "Missing attribute \"path\"");
1095 } else {
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));
1100
1101 if (strchr(odbpath, '$')) {
1102 if (strchr(odbpath, '[')) {
1103 // keep $ in index for later evaluation
1104 std::string s(odbpath);
1105 std::string s1 = s.substr(0, s.find('['));
1106 std::string s2 = s.substr(s.find('['));
1107 s1 = eval_var(seq, c, s1);
1108 s1 += s2;
1109 mstrlcpy(odbpath, s1.c_str(), sizeof(odbpath));
1110 } else {
1111 // evaluate variable in path
1112 std::string s(odbpath);
1113 s = eval_var(seq, c, s);
1114 mstrlcpy(odbpath, s.c_str(), sizeof(odbpath));
1115 }
1116 }
1117
1118 /* check if index is supplied */
1119 index1 = index2 = 0;
1120 seq_array_index(seq, c, odbpath, &index1, &index2);
1121
1122 mstrlcpy(name, mxml_get_value(pn), sizeof(name));
1123 status = db_find_key(c->hDB, 0, odbpath, &hKey);
1124 if (status != DB_SUCCESS) {
1125 seq_error(seq, c, msprintf("Cannot find ODB key \"%s\"", odbpath).c_str());
1126 return FALSE;
1127 } else {
1128 db_get_key(c->hDB, hKey, &key);
1129 size = sizeof(data);
1130
1131 status = db_get_data_index(c->hDB, hKey, data, &size, index1, key.type);
1132 if (key.type == TID_BOOL)
1133 value = *((int *) data) > 0 ? "1" : "0";
1134 else
1135 value = db_sprintf(data, size, 0, key.type);
1136
1137 sprintf(str, "Variables/%s", name); // FIXME: unsafe
1138 size = value.length() + 1;
1139 if (size < 32)
1140 size = 32;
1141 db_set_value(c->hDB, c->hSeq, str, value.c_str(), size, 1, TID_STRING);
1142
1143 size = sizeof(seq);
1144 db_get_record1(c->hDB, hKeySeq, &seq, &size, 0, strcomb1(sequencer_str).c_str());// could have changed seq tree
1145 seq.current_line_number = mxml_get_line_number_end(pn) + 1;
1146 }
1147 }
1148
1149 return TRUE;
1150}
#define TID_BOOL
Definition midas.h:340
INT db_get_data_index(HNDLE hDB, HNDLE hKey, void *data, INT *buf_size, INT idx, DWORD type)
Definition odb.cxx:7412
INT db_sprintf(char *string, const void *data, INT data_size, INT idx, DWORD type)
Definition odb.cxx:11426
void seq_array_index(SEQUENCER &seq, SeqCon *c, char *odbpath, int *index1, int *index2)
Here is the call graph for this function:

◆ seq_execute_odbinc()

static BOOL seq_execute_odbinc ( SeqExecContext ctx)
static

Definition at line 1152 of file msequencer.cxx.

1153{
1154 SEQUENCER& seq = ctx.seq;
1155 SeqCon* c = ctx.c;
1156 PMXML_NODE pn = ctx.pn;
1157 char odbpath[256], data[256], str[1024];
1158 std::string value;
1159 int status, size, index1, index2;
1160 HNDLE hKey;
1161 KEY key;
1162 double d;
1163
1164 if (!mxml_get_attribute(pn, "path")) {
1165 seq_error(seq, c, "Missing attribute \"path\"");
1166 } else {
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));
1171
1172 if (strchr(odbpath, '$')) {
1173 if (strchr(odbpath, '[')) {
1174 // keep $ in index for later evaluation
1175 std::string s(odbpath);
1176 std::string s1 = s.substr(0, s.find('['));
1177 std::string s2 = s.substr(s.find('['));
1178 s1 = eval_var(seq, c, s1);
1179 s1 += s2;
1180 mstrlcpy(odbpath, s1.c_str(), sizeof(odbpath));
1181 } else {
1182 // evaluate variable in path
1183 std::string s(odbpath);
1184 s = eval_var(seq, c, s);
1185 mstrlcpy(odbpath, s.c_str(), sizeof(odbpath));
1186 }
1187 }
1188
1189 index1 = index2 = 0;
1190 seq_array_index(seq, c, odbpath, &index1, &index2);
1191
1192 value = eval_var(seq, c, mxml_get_value(pn));
1193
1194 status = db_find_key(c->hDB, 0, odbpath, &hKey);
1195 if (status != DB_SUCCESS) {
1196 seq_error(seq, c, msprintf("Cannot find ODB key \"%s\"", odbpath).c_str());
1197 } else {
1198 db_get_key(c->hDB, hKey, &key);
1199 size = sizeof(data);
1200 db_get_data_index(c->hDB, hKey, data, &size, index1, key.type);
1201 std::string s = db_sprintf(data, size, 0, key.type);
1202 d = std::stof(s);
1203 d += std::stof(value);
1204 sprintf(str, "%lg", d);
1205 size = sizeof(data);
1206 db_sscanf(str, data, &size, 0, key.type);
1207
1208 int notify = TRUE;
1209 if (seq.subdir_not_notify)
1210 notify = FALSE;
1211 if (mxml_get_attribute(pn, "notify"))
1212 notify = atoi(mxml_get_attribute(pn, "notify"));
1213
1214 db_set_data_index1(c->hDB, hKey, data, key.item_size, index1, key.type, notify);
1215 seq.current_line_number++;
1216 }
1217 }
1218
1219 return TRUE;
1220}
INT db_set_data_index1(HNDLE hDB, HNDLE hKey, const void *data, INT data_size, INT idx, DWORD type, BOOL bNotify)
Definition odb.cxx:8339
INT db_sscanf(const char *data_str, void *data, INT *data_size, INT i, DWORD tid)
Definition odb.cxx:11897
INT item_size
Definition midas.h:1033
double d
Definition system.cxx:1313
Here is the call graph for this function:

◆ seq_execute_odbload()

static BOOL seq_execute_odbload ( SeqExecContext ctx)
static

Definition at line 1320 of file msequencer.cxx.

1321{
1322 SEQUENCER& seq = ctx.seq;
1323 SeqCon* c = ctx.c;
1324 PMXML_NODE pn = ctx.pn;
1325 HNDLE hKeySeq = ctx.hKeySeq;
1326 char odbpath[256];
1327 std::string value;
1328 int status, size;
1329 HNDLE hKey;
1330
1331 if (mxml_get_value(pn)[0] == '/') {
1332
1333 // path relative to the one set in <exp>/userfiles/sequencer
1334 std::string path(cm_get_path());
1335 path += "userfiles/sequencer/";
1336 value = path;
1337 value += std::string(mxml_get_value(pn)+1);
1338 } else {
1339 // relative path to msl file
1340 std::string path(cm_get_path());
1341 path += "userfiles/sequencer/";
1342 path += seq.path;
1343 value = path;
1344 if (value.back() != '/')
1345 value += "/";
1346 value += mxml_get_value(pn);
1347 }
1348
1349 if (value.find('$') != std::string::npos)
1350 value = eval_var(seq, c, value);
1351
1352 // if path attribute is given
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));
1358
1359 if (strchr(odbpath, '$')) {
1360 std::string s(odbpath);
1361 s = eval_var(seq, c, s);
1362 mstrlcpy(odbpath, s.c_str(), sizeof(odbpath));
1363 }
1364
1365 // load at that key, if exists
1366 status = db_find_key(c->hDB, 0, odbpath, &hKey);
1367 if (status != DB_SUCCESS) {
1368 seq_error(seq, c, msprintf("Cannot find ODB key \"%s\"", odbpath).c_str());
1369 return FALSE;
1370 } else {
1371 status = db_load(c->hDB, hKey, value.c_str(), FALSE);
1372 }
1373 } else {
1374 // otherwise load at root
1375 status = db_load(c->hDB, 0, value.c_str(), FALSE);
1376 }
1377
1378 if (status == DB_SUCCESS) {
1379 size = sizeof(seq);
1380 db_get_record1(c->hDB, hKeySeq, &seq, &size, 0, strcomb1(sequencer_str).c_str());// could have changed seq tree
1381 seq.current_line_number++;
1382 } else if (status == DB_FILE_ERROR) {
1383 seq_error(seq, c, msprintf("Error reading file \"%s\"", value.c_str()).c_str());
1384 } else {
1385 //something went really wrong
1386 seq_error(seq, c, "Internal error loading ODB file!");
1387 return FALSE;
1388 }
1389
1390 return TRUE;
1391}
#define DB_FILE_ERROR
Definition midas.h:648
INT db_load(HNDLE hDB, HNDLE hKeyRoot, const char *filename, BOOL bRemote)
Definition odb.cxx:8634
Here is the call graph for this function:

◆ seq_execute_odblookup()

static BOOL seq_execute_odblookup ( SeqExecContext ctx)
static

Definition at line 433 of file msequencer.cxx.

434{
435 SEQUENCER& seq = ctx.seq;
436 SeqCon* c = ctx.c;
437 PMXML_NODE pn = ctx.pn;
438 HNDLE hKeySeq = ctx.hKeySeq;
439 char odbpath[256], data[256], str[1024], name[32];
440 std::string value;
441 int i, status, size;
442 HNDLE hKey;
443 KEY key;
444
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\"");
449 } else {
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));
454
455 if (strchr(odbpath, '$')) {
456 if (strchr(odbpath, '[')) {
457 // keep $ in index for later evaluation
458 std::string s(odbpath);
459 std::string s1 = s.substr(0, s.find('['));
460 std::string s2 = s.substr(s.find('['));
461 s1 = eval_var(seq, c, s1);
462 s1 += s2;
463 mstrlcpy(odbpath, s1.c_str(), sizeof(odbpath));
464 } else {
465 // evaluate variable in path
466 std::string s(odbpath);
467 s = eval_var(seq, c, s);
468 mstrlcpy(odbpath, s.c_str(), sizeof(odbpath));
469 }
470 }
471
472 mstrlcpy(name, mxml_get_value(pn), sizeof(name));
473
474 auto s = eval_var(seq, c, mxml_get_attribute(pn, "string"));
475 mstrlcpy(str, s.c_str(), sizeof(str));
476
477 status = db_find_key(c->hDB, 0, odbpath, &hKey);
478 if (status != DB_SUCCESS) {
479 seq_error(seq, c, msprintf("Cannot find ODB key \"%s\"", odbpath).c_str());
480 return FALSE;
481 } else {
482 db_get_key(c->hDB, hKey, &key);
483
484 // search for "str"
485 for (i = 0 ; i<key.num_values ; i++) {
486 size = sizeof(data);
487 status = db_get_data_index(c->hDB, hKey, data, &size, i, key.type);
488 if (strcmp((const char *)data, str) == 0)
489 break;
490 }
491
492 size = sizeof(i);
493 if (i < key.num_values)
494 value = db_sprintf(&i, size, 0, TID_INT);
495 else {
496 snprintf(str, sizeof(str), "\"ODBLOOKUP %s\" did not find string \"%s\"", odbpath, s.c_str());
497 seq_error(seq, c, str);
498 return FALSE;
499 }
500
501 snprintf(str, sizeof(str), "Variables/%s", name);
502 size = value.length() + 1;
503 if (size < 32)
504 size = 32;
505 db_set_value(c->hDB, c->hSeq, str, value.c_str(), size, 1, TID_STRING);
506
507 size = sizeof(seq);
508 db_get_record1(c->hDB, hKeySeq, &seq, &size, 0, strcomb1(sequencer_str).c_str());// could have changed seq tree
509 seq.current_line_number = mxml_get_line_number_end(pn) + 1;
510 }
511 }
512
513 return TRUE;
514}
#define TID_INT
Definition midas.h:338
INT num_values
Definition midas.h:1029
Here is the call graph for this function:

◆ seq_execute_odbsave()

static BOOL seq_execute_odbsave ( SeqExecContext ctx)
static

Definition at line 1393 of file msequencer.cxx.

1394{
1395 SEQUENCER& seq = ctx.seq;
1396 SeqCon* c = ctx.c;
1397 PMXML_NODE pn = ctx.pn;
1398 HNDLE hKeySeq = ctx.hKeySeq;
1399 char odbpath[256];
1400 std::string value;
1401 int status, size;
1402 HNDLE hKey;
1403
1404 if (mxml_get_value(pn)[0] == '/') {
1405
1406 // path relative to the one set in <exp>/userfiles/sequencer
1407 std::string path(cm_get_path());
1408 path += "userfiles/sequencer/";
1409 value = path;
1410 value += std::string(mxml_get_value(pn)+1);
1411 } else {
1412 // relative path to msl file
1413 std::string path(cm_get_path());
1414 path += "userfiles/sequencer/";
1415 path += seq.path;
1416 value = path;
1417 value += seq.filename;
1418 size_t pos = value.find_last_of('/');
1419 if (pos != std::string::npos)
1420 value = value.substr(0, pos);
1421 value += mxml_get_value(pn);
1422 }
1423
1424 if (value.find('$') != std::string::npos)
1425 value = eval_var(seq, c, value);
1426
1427 // if path attribute is given
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));
1433
1434 if (strchr(odbpath, '$')) {
1435 std::string s(odbpath);
1436 s = eval_var(seq, c, s);
1437 mstrlcpy(odbpath, s.c_str(), sizeof(odbpath));
1438 }
1439
1440 // find key or subdirectory to save
1441 status = db_find_key(c->hDB, 0, odbpath, &hKey);
1442 if (status != DB_SUCCESS) {
1443 seq_error(seq, c, msprintf("Cannot find ODB key \"%s\"", odbpath).c_str());
1444 return FALSE;
1445 } else {
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"))
1449 status = db_save_xml(c->hDB, hKey, value.c_str());
1450 else
1451 status = db_save(c->hDB, hKey, value.c_str(), FALSE);
1452 if (status != DB_SUCCESS) {
1453 seq_error(seq, c, msprintf("Cannot save file \"%s\", error %d", value.c_str(), status).c_str());
1454 return FALSE;
1455 }
1456 }
1457 } else {
1458 seq_error(seq, c, "No ODB path specified in ODBSAVE command");
1459 return FALSE;
1460 }
1461
1462 if (status == DB_SUCCESS) {
1463 size = sizeof(seq);
1464 db_get_record1(c->hDB, hKeySeq, &seq, &size, 0, strcomb1(sequencer_str).c_str());// could have changed seq tree
1465 seq.current_line_number++;
1466 } else if (status == DB_FILE_ERROR) {
1467 seq_error(seq, c, msprintf("Error reading file \"%s\"", value.c_str()).c_str());
1468 } else {
1469 //something went really wrong
1470 seq_error(seq, c, "Internal error loading ODB file!");
1471 return FALSE;
1472 }
1473
1474 return TRUE;
1475}
INT db_save_json(HNDLE hDB, HNDLE hKey, const char *filename, int flags)
Definition odb.cxx:11109
INT db_save_xml(HNDLE hDB, HNDLE hKey, const char *filename)
Definition odb.cxx:9998
INT db_save(HNDLE hDB, HNDLE hKey, const char *filename, BOOL bRemote)
Definition odb.cxx:9758
#define JSFLAG_RECURSE
Definition midas.h:1664
#define JSFLAG_FOLLOW_LINKS
Definition midas.h:1663
#define JSFLAG_OMIT_LAST_WRITTEN
Definition midas.h:1667
Here is the call graph for this function:

◆ seq_execute_odbset()

static BOOL seq_execute_odbset ( SeqExecContext ctx)
static

Definition at line 1002 of file msequencer.cxx.

1003{
1004 SEQUENCER& seq = ctx.seq;
1005 SeqCon* c = ctx.c;
1006 PMXML_NODE pn = ctx.pn;
1007 HNDLE hKeySeq = ctx.hKeySeq;
1008 char odbpath[256], str[1024];
1009 std::string value;
1010 int status, size, index1, index2;
1011
1012 if (!mxml_get_attribute(pn, "path")) {
1013 seq_error(seq, c, "Missing attribute \"path\"");
1014 } else {
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));
1019
1020 if (strchr(odbpath, '$')) {
1021 if (strchr(odbpath, '[')) {
1022 // keep $ in index for later evaluation
1023 std::string s(odbpath);
1024 std::string s1 = s.substr(0, s.find('['));
1025 std::string s2 = s.substr(s.find('['));
1026 s1 = eval_var(seq, c, s1);
1027 s1 += s2;
1028 mstrlcpy(odbpath, s1.c_str(), sizeof(odbpath));
1029 } else {
1030 // evaluate variable in path
1031 std::string s(odbpath);
1032 s = eval_var(seq, c, s);
1033 mstrlcpy(odbpath, s.c_str(), sizeof(odbpath));
1034 }
1035 }
1036
1037 int notify = TRUE;
1038 if (seq.subdir_not_notify)
1039 notify = FALSE;
1040 if (mxml_get_attribute(pn, "notify"))
1041 notify = atoi(mxml_get_attribute(pn, "notify"));
1042
1043 index1 = index2 = 0;
1044 seq_array_index(seq, c, odbpath, &index1, &index2);
1045
1046 if (index1 < -1 || index2 < 0) {
1047 seq_error(seq, c, "Negative index not allowed");
1048 return FALSE;
1049 }
1050
1051 if (index1 > 1E6 || index2 > 1E6) {
1052 seq_error(seq, c, "Index too large for ODB");
1053 return FALSE;
1054 }
1055
1056 value = eval_var(seq, c, mxml_get_value(pn));
1057
1058 status = set_all_matching(c->hDB, 0, odbpath, (char *)value.c_str(), index1, index2, notify);
1059
1060 if (status == DB_SUCCESS) {
1061 size = sizeof(seq);
1062 db_get_record1(c->hDB, hKeySeq, &seq, &size, 0, strcomb1(sequencer_str).c_str());// could have changed seq tree
1063 seq.current_line_number++;
1064 } else if (status == DB_NO_KEY) {
1065 sprintf(str, "ODB key \"%s\" not found", odbpath); // FIXME: unsafe
1066 seq_error(seq, c, str);
1067 } else if (status == DB_INVALID_PARAM) {
1068 sprintf(str, "Invalid index %d for ODB key \"%s\"", index1, odbpath); // FIXME: unsafe
1069 seq_error(seq, c, str);
1070 } else {
1071 //something went really wrong
1072 sprintf(str, "Internal error %d", status);
1073 seq_error(seq, c, str);
1074 return FALSE;
1075 }
1076 }
1077
1078 return TRUE;
1079}
#define DB_INVALID_PARAM
Definition midas.h:640
#define DB_NO_KEY
Definition midas.h:643
int set_all_matching(HNDLE hDB, HNDLE hBaseKey, const char *odbpath, char *value, int index1, int index2, int notify)
Here is the call graph for this function:

◆ seq_execute_run_description()

static BOOL seq_execute_run_description ( SeqExecContext ctx)
static

Definition at line 907 of file msequencer.cxx.

908{
909 db_set_value(ctx.c->hDB, 0, "/Experiment/Run Parameters/Run Description",
910 mxml_get_value(ctx.pn), 256, 1, TID_STRING);
912 return TRUE;
913}
HNDLE hDB
Here is the call graph for this function:

◆ seq_execute_script()

static BOOL seq_execute_script ( SeqExecContext ctx)
static

Definition at line 602 of file msequencer.cxx.

603{
604 SEQUENCER& seq = ctx.seq;
605 SeqCon* c = ctx.c;
606 PMXML_NODE pn = ctx.pn;
607 char data[256], str[1024];
608 char list[100][XNAME_LENGTH];
609 int i, n;
610 std::string value;
611
612 sprintf(str, "%s", mxml_get_value(pn)); // FIXME: unsafe
613
614 if (mxml_get_attribute(pn, "params")) {
615 mstrlcpy(data, mxml_get_attribute(pn, "params"), sizeof(data));
616 n = strbreak(data, list, 100, ",", FALSE);
617 for (i = 0; i < n; i++) {
618
619 value = eval_var(seq, c, list[i]);
620
621 mstrlcat(str, " ", sizeof(str));
622 mstrlcat(str, value.c_str(), sizeof(str));
623 }
624 }
625
626 std::string s(str);
628 std::string r = ss_execs(s.c_str());
629
630 // put result into SCRIPT_RESULT variable
631 db_set_value(c->hDB, c->hSeq, "Variables/SCRIPT_RESULT", r.c_str(), r.length(), 1, TID_STRING);
632
634 return TRUE;
635}
std::string ss_execs(const char *cmd)
Definition system.cxx:2309
std::string ss_replace_env_variables(const std::string &inputPath)
Definition system.cxx:2284
Here is the call graph for this function:

◆ seq_execute_set()

static BOOL seq_execute_set ( SeqExecContext ctx)
static

Definition at line 637 of file msequencer.cxx.

638{
639 SEQUENCER& seq = ctx.seq;
640 SeqCon* c = ctx.c;
641 PMXML_NODE pn = ctx.pn;
642 PMXML_NODE pr;
643 char str[1024], name[32];
644 std::string value;
645 int i, status, size;
646 HNDLE hKey;
647
648 if (!mxml_get_attribute(pn, "name")) {
649 seq_error(seq, c, "Missing variable name");
650 return FALSE;
651 }
652
653 mstrlcpy(name, mxml_get_attribute(pn, "name"), sizeof(name));
654 value = eval_var(seq, c, mxml_get_value(pn));
655
656 if (strchr(name, '[')) {
657 // array
658 mstrlcpy(str, strchr(name, '[')+1, sizeof(str));
659 if (strchr(str, ']'))
660 *strchr(str, ']') = 0;
661 int index = atoi(eval_var(seq, c, str).c_str());
662 *strchr(name, '[') = 0;
663 sprintf(str, "Variables/%s", name); // FIXME: unsafe
664 status = db_find_key(c->hDB, c->hSeq, str, &hKey);
665 if (status != DB_SUCCESS) {
666 db_create_key(c->hDB, c->hSeq, str, TID_STRING);
667 status = db_find_key(c->hDB, c->hSeq, str, &hKey);
668 }
669 size = value.length() + 1;
670 if (size < 32)
671 size = 32;
672 status = db_set_data_index(c->hDB, hKey, value.c_str(), size, index, TID_STRING);
673 } else {
674 sprintf(str, "Variables/%s", name); // FIXME: unsafe
675 size = value.length() + 1;
676 if (size < 32)
677 size = 32;
678 db_set_value(c->hDB, c->hSeq, str, value.c_str(), size, 1, TID_STRING);
679 }
680
681 // check if variable is used in loop
682 for (i = SEQ_NEST_LEVEL_LOOP-1; i >= 0; i--)
683 if (seq.loop_start_line[i] > 0) {
684 pr = mxml_get_node_at_line(c->pnseq, seq.loop_start_line[i]);
685 if (mxml_get_attribute(pr, "var")) {
686 if (equal_ustring(mxml_get_attribute(pr, "var"), name))
687 seq.loop_counter[i] = atoi(value.c_str());
688 }
689 }
690
691 seq.current_line_number = mxml_get_line_number_end(pn) + 1;
692 return TRUE;
693}
INT db_set_data_index(HNDLE hDB, HNDLE hKey, const void *data, INT data_size, INT idx, DWORD type)
Definition odb.cxx:8163
Here is the call graph for this function:

◆ seq_execute_skip_node()

static BOOL seq_execute_skip_node ( SeqExecContext ctx)
static

Definition at line 516 of file msequencer.cxx.

517{
519 ctx.skip_step = TRUE;
520 return TRUE;
521}

◆ seq_execute_transition()

static BOOL seq_execute_transition ( SeqExecContext ctx)
static

Definition at line 915 of file msequencer.cxx.

916{
917 SEQUENCER& seq = ctx.seq;
918 SeqCon* c = ctx.c;
919 PMXML_NODE pn = ctx.pn;
920 HNDLE hKeySeq = ctx.hKeySeq;
921 char str[1024];
922 int status, size, state, run_number;
923
924 if (equal_ustring(mxml_get_value(pn), "Start")) {
925 if (!seq.transition_request) {
927 size = sizeof(state);
928 db_get_value(c->hDB, 0, "/Runinfo/State", &state, &size, TID_INT32, FALSE);
929 if (state != STATE_RUNNING) {
930 size = sizeof(run_number);
931 db_get_value(c->hDB, 0, "/Runinfo/Run number", &run_number, &size, TID_INT32, FALSE);
933 if (status != CM_SUCCESS) {
934 seq_error(seq, c, msprintf("Cannot start run: %s", str).c_str());
935 }
936 }
937 } else {
938 // Wait until transition has finished
939 size = sizeof(state);
940 db_get_value(c->hDB, 0, "/Runinfo/State", &state, &size, TID_INT32, FALSE);
941 if (state == STATE_RUNNING) {
944 }
945 }
946 } else if (equal_ustring(mxml_get_value(pn), "Stop")) {
947 if (!seq.transition_request) {
949 size = sizeof(state);
950 db_get_value(c->hDB, 0, "/Runinfo/State", &state, &size, TID_INT32, FALSE);
951 if (state != STATE_STOPPED) {
954 // do nothing
955 } else if (status != CM_SUCCESS) {
956 seq_error(seq, c, msprintf("Cannot stop run: %s", str).c_str());
957 }
958 }
959 } else {
960 // Wait until transition has finished
961 size = sizeof(state);
962 db_get_value(c->hDB, 0, "/Runinfo/State", &state, &size, TID_INT32, FALSE);
963 if (state == STATE_STOPPED) {
964 size = sizeof(seq);
965 db_get_record(c->hDB, hKeySeq, &seq, &size, 0);
966
968
969 if (seq.stop_after_run) {
970 seq.stop_after_run = FALSE;
971
972 if (!goto_at_exit(seq, c)) {
973 seq.running = FALSE;
974 seq.finished = TRUE;
975 seq_stop(seq, c);
976 cm_msg(MTALK, "sequencer", "Sequencer is finished by \"stop after current run\".");
977 } else {
978 cm_msg(MTALK, "sequencer", "Sequencer is going to finish by \"stop after current run\". Executing ATEXIT.");
979 }
980 } else {
982 }
983
984 db_set_record(c->hDB, hKeySeq, &seq, sizeof(seq), 0);
985 }
986 }
987 } else {
988 seq_error(seq, c, msprintf("Invalid transition \"%s\"", mxml_get_value(pn)).c_str());
989 return FALSE;
990 }
991
992 return TRUE;
993}
INT cm_transition(INT transition, INT run_number, char *errstr, INT errstr_size, INT async_flag, INT debug_flag)
Definition midas.cxx:5360
#define CM_DEFERRED_TRANSITION
Definition midas.h:591
#define TR_START
Definition midas.h:405
#define TR_SYNC
Definition midas.h:358
#define TR_MTHREAD
Definition midas.h:361
#define STATE_STOPPED
Definition midas.h:305
#define TID_INT32
Definition midas.h:339
#define STATE_RUNNING
Definition midas.h:307
#define TR_STOP
Definition midas.h:406
INT db_get_value(HNDLE hDB, HNDLE hKeyRoot, const char *key_name, void *data, INT *buf_size, DWORD type, BOOL create)
Definition odb.cxx:5680
INT db_get_record(HNDLE hDB, HNDLE hKey, void *data, INT *buf_size, INT align)
Definition odb.cxx:12297
static BOOL goto_at_exit(SEQUENCER &seq, SeqCon *c)
INT run_number[2]
Definition mana.cxx:246
Here is the call graph for this function:

◆ seq_execute_wait()

static BOOL seq_execute_wait ( SeqExecContext ctx)
static

Definition at line 721 of file msequencer.cxx.

722{
723 SEQUENCER& seq = ctx.seq;
724 SeqCon* c = ctx.c;
725 PMXML_NODE pn = ctx.pn;
726 char odbpath[256], data[256], op[32];
727 std::string value;
728 int n, status, size, index1, index2, cont;
729 HNDLE hKey;
730 KEY key;
731 double d;
732
733 if (equal_ustring(mxml_get_attribute(pn, "for"), "Events")) {
734 n = atoi(eval_var(seq, c, mxml_get_value(pn)).c_str());
735 seq.wait_limit = (float) n;
736 strcpy(seq.wait_type, "Events");
737 seq.timeout_limit = 0;
738 seq.timeout_value = 0;
739 size = sizeof(d);
740 db_get_value(c->hDB, 0, "/Equipment/Trigger/Statistics/Events sent", &d, &size, TID_DOUBLE, FALSE);
741 seq.wait_value = (float) d;
742 if (d >= n) {
743 seq.current_line_number = mxml_get_line_number_end(pn) + 1;
744 seq.wait_limit = 0;
745 seq.wait_value = 0;
746 seq.timeout_limit = 0;
747 seq.timeout_value = 0;
748 seq.wait_type[0] = 0;
749 seq.wait_odb[0] = 0;
750 }
751 seq.wait_value = (float) d;
752 } else if (equal_ustring(mxml_get_attribute(pn, "for"), "ODBValue")) {
753 seq.wait_limit = (float) atof(eval_var(seq, c, mxml_get_value(pn)).c_str());
754 mstrlcpy(seq.wait_type, "ODB", sizeof(seq.wait_type));
755 if (!mxml_get_attribute(pn, "path")) {
756 seq_error(seq, c, "\"path\" must be given for ODB values");
757 return FALSE;
758 } else {
759 mstrlcpy(odbpath, mxml_get_attribute(pn, "path"), sizeof(odbpath));
760 mstrlcpy(seq.wait_odb, odbpath, sizeof(seq.wait_odb));
761
762 if (strchr(odbpath, '$')) {
763 if (strchr(odbpath, '[')) {
764 // keep $ in index for later evaluation
765 std::string s(odbpath);
766 std::string s1 = s.substr(0, s.find('['));
767 std::string s2 = s.substr(s.find('['));
768 s1 = eval_var(seq, c, s1);
769 s1 += s2;
770 mstrlcpy(odbpath, s1.c_str(), sizeof(odbpath));
771 } else {
772 // evaluate variable in path
773 std::string s(odbpath);
774 s = eval_var(seq, c, s);
775 mstrlcpy(odbpath, s.c_str(), sizeof(odbpath));
776 }
777 }
778
779 index1 = index2 = 0;
780 seq_array_index(seq, c, odbpath, &index1, &index2);
781 status = db_find_key(c->hDB, 0, odbpath, &hKey);
782 if (status != DB_SUCCESS) {
783 seq_error(seq, c, msprintf("Cannot find ODB key \"%s\"", odbpath).c_str());
784 return FALSE;
785 } else {
786 if (mxml_get_attribute(pn, "op"))
787 mstrlcpy(op, mxml_get_attribute(pn, "op"), sizeof(op));
788 else
789 strcpy(op, "!=");
790 mstrlcat(seq.wait_type, op, sizeof(seq.wait_type));
791
792 db_get_key(c->hDB, hKey, &key);
793 size = sizeof(data);
794 db_get_data_index(c->hDB, hKey, data, &size, index1, key.type);
795 if (key.type == TID_BOOL)
796 value = *((int *) data) > 0 ? "1" : "0";
797 else
798 value = db_sprintf(data, size, 0, key.type);
799 cont = FALSE;
800 seq.wait_value = std::stof(value);
801 if (equal_ustring(op, ">=")) {
802 cont = (seq.wait_value >= seq.wait_limit);
803 } else if (equal_ustring(op, ">")) {
804 cont = (seq.wait_value > seq.wait_limit);
805 } else if (equal_ustring(op, "<=")) {
806 cont = (seq.wait_value <= seq.wait_limit);
807 } else if (equal_ustring(op, "<")) {
808 cont = (seq.wait_value < seq.wait_limit);
809 } else if (equal_ustring(op, "==")) {
810 cont = (seq.wait_value == seq.wait_limit);
811 } else if (equal_ustring(op, "!=")) {
812 cont = (seq.wait_value != seq.wait_limit);
813 } else {
814 seq_error(seq, c, msprintf("Invalid comaprison \"%s\"", op).c_str());
815 return FALSE;
816 }
817
818 // Keep the existing ODB wait display semantics:
819 // wait_limit = requested ODB target value
820 // wait_value = current ODB value
821 // Publish the optional timeout separately so the web interface can
822 // display the ODB condition and a normal progress bar at the same time.
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());
829 return FALSE;
830 }
831
832 // Use the same monotonic millisecond clock base as WAIT Seconds.
833 if (seq.start_time == 0)
834 seq.start_time = ss_millitime();
835
836 DWORD elapsed_ms = ss_millitime() - seq.start_time;
837
838 seq.timeout_limit = timeout_sec;
839 seq.timeout_value = (float) elapsed_ms / 1000.0f;
840 if (seq.timeout_value > seq.timeout_limit)
842
843 timed_out = elapsed_ms > (DWORD) (1000.0f * timeout_sec);
844 } else {
845 seq.timeout_limit = 0;
846 seq.timeout_value = 0;
847 }
848
849 if (cont || timed_out) {
850 if (mxml_get_attribute(pn, "status")) {
851 char status_name[NAME_LENGTH];
852 char status_path[256];
853 const char *status_value = (cont && !timed_out) ? "1" : "0";
854
855 mstrlcpy(status_name, mxml_get_attribute(pn, "status"), sizeof(status_name));
856 snprintf(status_path, sizeof(status_path), "Variables/%s", status_name);
857 db_set_value(c->hDB, c->hSeq, status_path, status_value, 32, 1, TID_STRING);
858 }
859
860 if (timed_out && !cont) {
861 cm_msg(MINFO, "sequencer", "WAIT ODBValue timeout after %.1f seconds: %s %s %g not satisfied",
862 seq.timeout_limit, odbpath, op, seq.wait_limit);
863 }
864 seq.current_line_number = mxml_get_line_number_end(pn) + 1;
865 seq.start_time = 0;
866 seq.wait_limit = 0;
867 seq.wait_value = 0;
868 seq.timeout_limit = 0;
869 seq.timeout_value = 0;
870 seq.wait_type[0] = 0;
871 seq.wait_odb[0] = 0;
872 }
873 }
874 }
875 } else if (equal_ustring(mxml_get_attribute(pn, "for"), "Seconds")) {
876 seq.wait_limit = 1000.0f * (float) atof(eval_var(seq, c, mxml_get_value(pn)).c_str());
877 strcpy(seq.wait_type, "Seconds");
878 seq.timeout_limit = 0;
879 seq.timeout_value = 0;
880 if (seq.start_time == 0) {
881 seq.start_time = ss_millitime();
882 seq.wait_value = 0;
883 } else {
884 seq.wait_value = (float) (ss_millitime() - seq.start_time);
885 if (seq.wait_value > seq.wait_limit)
886 seq.wait_value = seq.wait_limit;
887 }
888 if (ss_millitime() - seq.start_time > (DWORD) seq.wait_limit) {
890 seq.start_time = 0;
891 seq.wait_limit = 0;
892 seq.wait_value = 0;
893 seq.timeout_limit = 0;
894 seq.timeout_value = 0;
895 seq.wait_type[0] = 0;
896 seq.wait_odb[0] = 0;
897 }
898 } else {
899 seq_error(seq, c, msprintf("Invalid wait attribute \"%s\"", mxml_get_attribute(pn, "for")).c_str());
900 }
901
902 // sleep to keep the CPU from consuming 100%
903 ss_sleep(1);
904 return TRUE;
905}
unsigned int DWORD
Definition mcstd.h:51
#define TID_DOUBLE
Definition midas.h:343
DWORD ss_millitime()
Definition system.cxx:3472
INT ss_sleep(INT millisec)
Definition system.cxx:3707
#define DWORD
Definition mhdump.cxx:31
#define NAME_LENGTH
Definition midas.h:272
Here is the call graph for this function:

◆ seq_execute_xml_node()

static BOOL seq_execute_xml_node ( SEQUENCER seq,
SeqCon c,
PMXML_NODE  pn,
HNDLE  hKeySeq,
int  last_line,
BOOL skip_step 
)
static

Definition at line 3014 of file msequencer.cxx.

3014 {
3015 PMXML_NODE pt, pe;
3016 char data[256], str[1024], name[32];
3017 std::string value;
3018 char list[100][XNAME_LENGTH];
3019 int i, j, l, size;
3020
3021 SeqCommand* exec_command = seq_find_xml_command(mxml_get_name(pn));
3022 if (exec_command && exec_command->execute_xml) {
3023 SeqExecContext ctx(seq, c, pn, hKeySeq, last_line, skip_step);
3024 return exec_command->execute_xml(ctx);
3025 }
3026
3027 /*---- ODBSubdir ----*/
3028 if (equal_ustring(mxml_get_name(pn), "ODBSubdir")) {
3029 if (!mxml_get_attribute(pn, "path")) {
3030 seq_error(seq, c, "Missing attribute \"path\"");
3031 } else {
3032
3033 std::string s = mxml_get_attribute(pn, "path");
3034 if (s.find('$') != std::string::npos)
3035 s = eval_var(seq, c, s);
3036
3037 mstrlcpy(seq.subdir, s.c_str(), sizeof(seq.subdir));
3038 if (mxml_get_attribute(pn, "notify"))
3039 seq.subdir_not_notify = !atoi(mxml_get_attribute(pn, "notify"));
3040 seq.subdir_end_line = mxml_get_line_number_end(pn);
3041 seq.current_line_number++;
3042 }
3043 }
3044
3045 /*---- Loop start ----*/
3046 else if (equal_ustring(mxml_get_name(pn), "Loop")) {
3047 for (i = 0; i < SEQ_NEST_LEVEL_LOOP; i++)
3048 if (seq.loop_start_line[i] == 0)
3049 break;
3050 if (i == SEQ_NEST_LEVEL_LOOP) {
3051 seq_error(seq, c, "Maximum loop nesting exceeded");
3052 return FALSE;
3053 }
3055 seq.loop_end_line[i] = mxml_get_line_number_end(pn);
3056 if (mxml_get_attribute(pn, "l"))
3057 seq.sloop_start_line[i] = atoi(mxml_get_attribute(pn, "l"));
3058 if (mxml_get_attribute(pn, "le"))
3059 seq.sloop_end_line[i] = atoi(mxml_get_attribute(pn, "le"));
3060 seq.loop_counter[i] = 1;
3061
3062 if (mxml_get_attribute(pn, "n")) {
3063 if (equal_ustring(mxml_get_attribute(pn, "n"), "infinite"))
3064 seq.loop_n[i] = -1;
3065 else {
3066 seq.loop_n[i] = atoi(eval_var(seq, c, mxml_get_attribute(pn, "n")).c_str());
3067 }
3068 value = "1";
3069 } else if (mxml_get_attribute(pn, "values")) {
3070 mstrlcpy(data, mxml_get_attribute(pn, "values"), sizeof(data));
3071 seq.loop_n[i] = strbreak(data, list, 100, ",", FALSE);
3072 value = eval_var(seq, c, list[0]);
3073 } else {
3074 seq_error(seq, c, "Missing \"var\" or \"n\" attribute");
3075 return FALSE;
3076 }
3077
3078 if (mxml_get_attribute(pn, "var")) {
3079 mstrlcpy(name, mxml_get_attribute(pn, "var"), sizeof(name));
3080 sprintf(str, "Variables/%s", name); // FIXME: unsafe
3081 size = value.length() + 1;
3082 if (size < 32)
3083 size = 32;
3084 db_set_value(c->hDB, c->hSeq, str, value.c_str(), size, 1, TID_STRING);
3085 }
3086
3087 seq.current_line_number++;
3088 }
3089
3090 /*---- Break ----*/
3091 else if (equal_ustring(mxml_get_name(pn), "Break")) {
3092
3093 // finish current if statement
3094 while (seq.if_index > 0 &&
3095 seq.current_line_number > seq.if_line[seq.if_index - 1] &&
3096 seq.current_line_number < seq.if_endif_line[seq.if_index-1]) {
3097 size = sizeof(seq);
3098 db_get_record(c->hDB, hKeySeq, &seq, &size, 0);
3099 seq.if_index--;
3100 seq.if_line[seq.if_index] = 0;
3101 seq.if_else_line[seq.if_index] = 0;
3102 seq.if_endif_line[seq.if_index] = 0;
3103 seq.current_line_number++;
3104 db_set_record(c->hDB, hKeySeq, &seq, sizeof(seq), 0);
3105 }
3106
3107 // goto next loop end
3108 for (i = 0; i < SEQ_NEST_LEVEL_LOOP; i++)
3109 if (seq.loop_start_line[i] == 0)
3110 break;
3111 if (i == 0) {
3112 seq_error(seq, c, "\"Break\" outside any loop");
3113 return FALSE;
3114 }
3115
3116 // force end of loop in next check
3117 seq.current_line_number = seq.loop_end_line[i-1];
3118 seq.loop_counter[i-1] = seq.loop_n[i-1];
3119 }
3120
3121 /*---- If ----*/
3122 else if (equal_ustring(mxml_get_name(pn), "If")) {
3123
3124 if (seq.if_index == SEQ_NEST_LEVEL_IF) {
3125 seq_error(seq, c, "Maximum number of nested if..endif exceeded");
3126 return FALSE;
3127 }
3128
3129 // store "if" and "endif" lines
3130 seq.if_line[seq.if_index] = seq.current_line_number;
3131 seq.if_endif_line[seq.if_index] = mxml_get_line_number_end(pn);
3132
3133 // search for "else" line
3134 seq.if_else_line[seq.if_index] = 0;
3135 for (j = seq.current_line_number + 1; j < mxml_get_line_number_end(pn) + 1; j++) {
3136 pe = mxml_get_node_at_line(c->pnseq, j);
3137
3138 // skip nested if..endif
3139 if (pe && equal_ustring(mxml_get_name(pe), "If")) {
3140 j = mxml_get_line_number_end(pe);
3141 continue;
3142 }
3143
3144 // store "else" if found
3145 if (pe && equal_ustring(mxml_get_name(pe), "Else")) {
3146 seq.if_else_line[seq.if_index] = j;
3147 break;
3148 }
3149 }
3150
3151 mstrlcpy(str, mxml_get_attribute(pn, "condition"), sizeof(str));
3152 i = eval_condition(seq, c, str);
3153 if (i < 0) {
3154 seq_error(seq, c, "Invalid number in comparison");
3155 return FALSE;
3156 }
3157
3158 if (i == 1)
3159 seq.current_line_number++;
3160 else if (seq.if_else_line[seq.if_index])
3161 seq.current_line_number = seq.if_else_line[seq.if_index] + 1;
3162 else
3164
3165 seq.if_index++;
3166 }
3167
3168 /*---- Else ----*/
3169 else if (equal_ustring(mxml_get_name(pn), "Else")) {
3170 // goto next "Endif"
3171 if (seq.if_index == 0) {
3172 seq_error(seq, c, "Unexpected Else");
3173 return FALSE;
3174 }
3175 seq.current_line_number = seq.if_endif_line[seq.if_index - 1];
3176 }
3177
3178 /*---- Goto ----*/
3179 else if (equal_ustring(mxml_get_name(pn), "Goto")) {
3180 if (!mxml_get_attribute(pn, "line") && !mxml_get_attribute(pn, "sline")) {
3181 seq_error(seq, c, "Missing line number");
3182 return FALSE;
3183 }
3184 if (mxml_get_attribute(pn, "line")) {
3185 seq.current_line_number = atoi(eval_var(seq, c, mxml_get_attribute(pn, "line")).c_str());
3186 }
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) {
3194 seq.current_line_number = i;
3195 break;
3196 }
3197 }
3198 }
3199 }
3200 }
3201
3202 /*---- Library ----*/
3203 else if (equal_ustring(mxml_get_name(pn), "Library")) {
3204 // simply skip libraries
3205 seq.current_line_number = mxml_get_line_number_end(pn) + 1;
3206 }
3207
3208 /*---- Subroutine ----*/
3209 else if (equal_ustring(mxml_get_name(pn), "Subroutine")) {
3210 // simply skip subroutines
3211 seq.current_line_number = mxml_get_line_number_end(pn) + 1;
3212 }
3213
3214 /*---- Param ----*/
3215 else if (equal_ustring(mxml_get_name(pn), "Param")) {
3216 // simply skip parameters
3217 seq.current_line_number = mxml_get_line_number_end(pn) + 1;
3218 }
3219
3220 /*---- Call ----*/
3221 else if (equal_ustring(mxml_get_name(pn), "Call")) {
3222 if (seq.stack_index == SEQ_NEST_LEVEL_SUB) {
3223 seq_error(seq, c, "Maximum subroutine level exceeded");
3224 return FALSE;
3225 } else {
3226 // put current line number on stack
3227 seq.subroutine_call_line[seq.stack_index] = mxml_get_line_number_end(pn);
3228 seq.ssubroutine_call_line[seq.stack_index] = atoi(mxml_get_attribute(pn, "l"));
3229 seq.subroutine_return_line[seq.stack_index] = mxml_get_line_number_end(pn) + 1;
3230
3231 // search subroutine
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);
3234 if (pt) {
3235 if (equal_ustring(mxml_get_name(pt), "Subroutine")) {
3236 if (equal_ustring(mxml_get_attribute(pt, "name"), mxml_get_attribute(pn, "name"))) {
3237 // put routine end line on end stack
3238 seq.subroutine_end_line[seq.stack_index] = mxml_get_line_number_end(pt);
3239 // go to first line of subroutine
3240 seq.current_line_number = mxml_get_line_number_start(pt) + 1;
3241 // put parameter(s) on stack
3242 if (mxml_get_value(pn)) {
3243 char p[256];
3244 if (strchr(mxml_get_value(pn), '$')) // evaluate message string if $ present
3245 mstrlcpy(p, eval_var(seq, c, mxml_get_value(pn)).c_str(), sizeof(p));
3246 else
3247 mstrlcpy(p, mxml_get_value(pn), sizeof(p)); // treat message as string
3248
3249 mstrlcpy(seq.subroutine_param[seq.stack_index], p, 256);
3250 }
3251 // increment stack
3252 seq.stack_index++;
3253 break;
3254 }
3255 }
3256 }
3257 }
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());
3260 }
3261 }
3262 }
3263
3264 /*---- <unknown> ----*/
3265 else {
3266 seq_error(seq, c, msprintf("Unknown statement \"%s\"", mxml_get_name(pn)).c_str());
3267 }
3268
3269
3270 return TRUE;
3271}
int eval_condition(SEQUENCER &seq, SeqCon *c, const char *condition)
static SeqCommand * seq_find_xml_command(const char *name)
int if_line[SEQ_NEST_LEVEL_IF]
Definition sequencer.h:37
BOOL(* execute_xml)(SeqExecContext &ctx)
Here is the call graph for this function:
Here is the caller graph for this function:

◆ seq_find_msl_command()

static SeqCommand * seq_find_msl_command ( const char *  name)
static

Definition at line 1538 of file msequencer.cxx.

1539{
1540 if (!name || !name[0])
1541 return NULL;
1542
1543 for (int i = 0; seq_command_table[i].msl_name || seq_command_table[i].xml_name; i++)
1544 if (seq_command_table[i].msl_name && equal_ustring(name, seq_command_table[i].msl_name))
1545 return &seq_command_table[i];
1546
1547 return NULL;
1548}
static SeqCommand seq_command_table[]
const char * xml_name
const char * msl_name
Here is the call graph for this function:
Here is the caller graph for this function:

◆ seq_find_xml_command()

static SeqCommand * seq_find_xml_command ( const char *  name)
static

Definition at line 1550 of file msequencer.cxx.

1551{
1552 if (!name || !name[0])
1553 return NULL;
1554
1555 for (int i = 0; seq_command_table[i].msl_name || seq_command_table[i].xml_name; i++)
1556 if (seq_command_table[i].xml_name && equal_ustring(name, seq_command_table[i].xml_name))
1557 return &seq_command_table[i];
1558
1559 return NULL;
1560}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ seq_goto_context()

static std::string seq_goto_context ( SeqCon c,
int  line 
)
static

Definition at line 2695 of file msequencer.cxx.

2695 {
2696 std::string context;
2697 PMXML_NODE pr = mxml_find_node(c->pnseq, "RunSequence");
2698
2699 if (!pr)
2700 return context;
2701
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);
2704 if (!pt)
2705 continue;
2706
2707 const char *name = mxml_get_name(pt);
2708 if (!equal_ustring(name, "Loop") && !equal_ustring(name, "If") && !equal_ustring(name, "Subroutine"))
2709 continue;
2710
2711 int start_line = mxml_get_line_number_start(pt);
2712 int end_line = mxml_get_line_number_end(pt);
2713
2714 // The block opener itself is not considered inside the block. Jumping
2715 // to a LOOP/IF/SUBROUTINE line is allowed only if the surrounding
2716 // context matches; the normal statement handler will initialize or skip
2717 // the block state.
2718 if (line > start_line && line < end_line)
2719 context += msprintf("%s:%d:%d;", name, start_line, end_line);
2720 }
2721
2722 return context;
2723}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ seq_goto_line()

static BOOL seq_goto_line ( SEQUENCER seq,
SeqCon c,
int  target_sline 
)
static

Definition at line 2727 of file msequencer.cxx.

2727 {
2728 PMXML_NODE pr, pt;
2729 int target_line = 0;
2730 int target_sline_found = 0;
2731 int best_sline = 0;
2732
2733 if (target_sline <= 0) {
2734 cm_msg(MERROR, "sequencer", "Goto line command ignored: invalid line number %d", target_sline);
2735 return FALSE;
2736 }
2737
2738 if (c->pnseq == NULL) {
2739 cm_msg(MERROR, "sequencer", "Goto line command ignored: no script loaded");
2740 return FALSE;
2741 }
2742
2743 pr = mxml_find_node(c->pnseq, "RunSequence");
2744 if (!pr) {
2745 cm_msg(MERROR, "sequencer", "Goto line command ignored: cannot find <RunSequence> tag in XML file");
2746 return FALSE;
2747 }
2748
2749 // Find the first executable XML node generated at or after the requested
2750 // source line. This lets "Goto line" work when the requested source line is
2751 // a comment or blank line.
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"));
2756
2757 if (sline >= target_sline && (best_sline == 0 || sline < best_sline)) {
2758 best_sline = sline;
2759 target_sline_found = sline;
2760 target_line = i;
2761 }
2762 }
2763 }
2764
2765 if (target_line == 0) {
2766 cm_msg(MERROR, "sequencer",
2767 "Goto line %d failed: no executable sequencer command found at or after this source line",
2768 target_sline);
2769 return FALSE;
2770 }
2771
2772 seq_read(&seq, c);
2773
2774 if (!seq.running) {
2775 cm_msg(MERROR, "sequencer", "Goto line command ignored: sequencer is not running");
2776 return FALSE;
2777 }
2778
2779 std::string current_context = seq_goto_context(c, seq.current_line_number);
2780 std::string target_context = seq_goto_context(c, target_line);
2781
2782 // Phase two: do not allow jumps into or out of LOOP/IF/SUBROUTINE blocks.
2783 // This prevents stale loop counters, IF bookkeeping, or subroutine return
2784 // stack state. A later phase could allow jump-out by explicitly unwinding
2785 // the affected state.
2786 if (current_context != target_context) {
2787 cm_msg(MERROR, "sequencer",
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);
2790 return FALSE;
2791 }
2792
2793 cm_msg(MINFO, "sequencer",
2794 "Goto line command: moving from source line %d to source line %d.",
2795 seq.scurrent_line_number, target_sline_found);
2796
2798 seq.current_line_number = target_line;
2799 seq.scurrent_line_number = target_sline_found;
2800
2801 seq_write(seq, c);
2802
2803 return TRUE;
2804}
static void seq_clear_wait_state(SEQUENCER &seq)
static std::string seq_goto_context(SeqCon *c, int line)
Here is the call graph for this function:
Here is the caller graph for this function:

◆ seq_open_file()

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

Definition at line 2594 of file msequencer.cxx.

2594 {
2595 seq.new_file = FALSE;
2596 seq.error[0] = 0;
2597 seq.error_line = 0;
2598 seq.serror_line = 0;
2599 if (c->pnseq) {
2600 mxml_free_tree(c->pnseq);
2601 c->pnseq = NULL;
2602 }
2603 c->odbs->WS("Script/Lines", "");
2604
2605 if (stristr(str, ".msl")) {
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");
2610 //printf("Parsing MSL sequencer file: %s to XML sequencer file %s\n", str, xml_filename);
2611
2612 std::string path(cm_get_path());
2613 path += "userfiles/sequencer/";
2614
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);
2619 } else {
2620 path += seq.path;
2621 }
2622
2623 if (msl_parse(seq, c, 0, path.c_str(), str, xml_filename, seq.error, sizeof(seq.error), &seq.serror_line)) {
2624 //printf("Loading XML sequencer file: %s\n", xml_filename);
2625 std::string fn(path);
2626 if (!fn.empty() && fn.back() != '/')
2627 fn += '/';
2628 fn += xml_filename;
2629 c->pnseq = mxml_parse_file(fn.c_str(), seq.error, sizeof(seq.error), &seq.error_line);
2630 } else {
2631 //printf("Error in MSL sequencer file \"%s\" line %d, error: %s\n", str, seq.serror_line, seq.error);
2632 }
2633 free(xml_filename);
2634 } else {
2635 //printf("Loading XML sequencer file: %s\n", str);
2636 c->pnseq = mxml_parse_file(str, seq.error, sizeof(seq.error), &seq.error_line);
2637 }
2638}
void strsubst(char *string, int size, const char *pattern, const char *subst)
char * stristr(const char *str, const char *pattern)
BOOL new_file
Definition sequencer.h:8
Here is the call graph for this function:
Here is the caller graph for this function:

◆ seq_parse_cat()

static BOOL seq_parse_cat ( SeqParseContext ctx)
static

Definition at line 264 of file msequencer.cxx.

265{
266 char (*list)[XNAME_LENGTH] = ctx.list;
267
268 ctx.xml += "<Cat " + qtoString(ctx.full_filename, ctx.line + 1, ctx.level) + " name=" + q(list[1]) + ">";
269 for (int i = 2; i < 100 && list[i][0]; i++) {
270 if (i > 2) {
271 ctx.xml += ",";
272 }
273 ctx.xml += q(list[i]);
274 }
275 ctx.xml += "</Cat>\n";
276
277 return TRUE;
278}
std::string & xml
const std::string & full_filename
char(* list)[XNAME_LENGTH]
Here is the call graph for this function:

◆ seq_parse_comment()

static BOOL seq_parse_comment ( SeqParseContext ctx)
static

Definition at line 200 of file msequencer.cxx.

201{
202 ctx.xml += "<Comment " + qtoString(ctx.full_filename, ctx.line + 1, ctx.level) + ">" + ctx.list[1] + "</Comment>\n";
203 return TRUE;
204}
Here is the call graph for this function:

◆ seq_parse_exit()

static BOOL seq_parse_exit ( SeqParseContext ctx)
static

Definition at line 334 of file msequencer.cxx.

335{
336 ctx.xml += "<Exit " + qtoString(ctx.full_filename, ctx.line + 1, ctx.level) + " />\n";
337 return TRUE;
338}
Here is the call graph for this function:

◆ seq_parse_message()

static BOOL seq_parse_message ( SeqParseContext ctx)
static

Definition at line 206 of file msequencer.cxx.

207{
208 char (*list)[XNAME_LENGTH] = ctx.list;
209
210 ctx.xml += "<Message " + qtoString(ctx.full_filename, ctx.line + 1, ctx.level);
211 if (list[2][0] == '1')
212 ctx.xml += " wait=\"1\"";
213 ctx.xml += ">";
214 ctx.xml += list[1];
215 ctx.xml += "</Message>\n";
216
217 return TRUE;
218}
Here is the call graph for this function:

◆ seq_parse_msg()

static BOOL seq_parse_msg ( SeqParseContext ctx)
static

Definition at line 220 of file msequencer.cxx.

221{
222 char (*list)[XNAME_LENGTH] = ctx.list;
223
224 if (list[2][0]) {
225 ctx.xml += "<Msg " + qtoString(ctx.full_filename, ctx.line + 1, ctx.level) + " type=\"" + list[2] + "\">" + list[1] + "</Msg>\n";
226 } else {
227 ctx.xml += "<Msg " + qtoString(ctx.full_filename, ctx.line + 1, ctx.level) + ">" + list[1] + "</Msg>\n";
228 }
229
230 return TRUE;
231}
Here is the call graph for this function:

◆ seq_parse_odbcreate()

static BOOL seq_parse_odbcreate ( SeqParseContext ctx)
static

Definition at line 375 of file msequencer.cxx.

376{
377 char (*list)[XNAME_LENGTH] = ctx.list;
378
379 if (list[3][0]) {
380 ctx.xml += "<ODBCreate " + qtoString(ctx.full_filename, ctx.line + 1, ctx.level) + " size=" + q(list[3]) + " path=" + q(list[1]) + " type=" +
381 q(list[2]) + "></ODBCreate>\n";
382 } else {
383 ctx.xml += "<ODBCreate " + qtoString(ctx.full_filename, ctx.line + 1, ctx.level) + " path=" + q(list[1]) + " type=" + q(list[2]) +
384 "></ODBCreate>\n";
385 }
386
387 return TRUE;
388}
Here is the call graph for this function:

◆ seq_parse_odbdelete()

static BOOL seq_parse_odbdelete ( SeqParseContext ctx)
static

Definition at line 390 of file msequencer.cxx.

391{
392 char (*list)[XNAME_LENGTH] = ctx.list;
393
394 ctx.xml += "<ODBDelete " + qtoString(ctx.full_filename, ctx.line + 1, ctx.level) + ">" + list[1] + "</ODBDelete>\n";
395
396 return TRUE;
397}
Here is the call graph for this function:

◆ seq_parse_odbget()

static BOOL seq_parse_odbget ( SeqParseContext ctx)
static

Definition at line 354 of file msequencer.cxx.

355{
356 char (*list)[XNAME_LENGTH] = ctx.list;
357
358 ctx.xml += "<ODBGet " + qtoString(ctx.full_filename, ctx.line + 1, ctx.level) + " path=" + q(list[1]) + ">" + list[2] + "</ODBGet>\n";
359
360 return TRUE;
361}
Here is the call graph for this function:

◆ seq_parse_odbinc()

static BOOL seq_parse_odbinc ( SeqParseContext ctx)
static

Definition at line 363 of file msequencer.cxx.

364{
365 char (*list)[XNAME_LENGTH] = ctx.list;
366
367 if (list[2][0] == 0)
368 mstrlcpy(list[2], "1", 2);
369
370 ctx.xml += "<ODBInc " + qtoString(ctx.full_filename, ctx.line + 1, ctx.level) + " path=" + q(list[1]) + ">" + list[2] + "</ODBInc>\n";
371
372 return TRUE;
373}
Here is the call graph for this function:

◆ seq_parse_odbload()

static BOOL seq_parse_odbload ( SeqParseContext ctx)
static

Definition at line 399 of file msequencer.cxx.

400{
401 char (*list)[XNAME_LENGTH] = ctx.list;
402
403 if (list[2][0]) {
404 ctx.xml += "<ODBLoad " + qtoString(ctx.full_filename, ctx.line + 1, ctx.level) + " path=" + q(list[2]) + ">" + list[1] +
405 "</ODBLoad>\n";
406 } else {
407 ctx.xml += "<ODBLoad " + qtoString(ctx.full_filename, ctx.line + 1, ctx.level) + ">" + list[1] + "</ODBLoad>\n";
408 }
409
410 return TRUE;
411}
Here is the call graph for this function:

◆ seq_parse_odblookup()

static BOOL seq_parse_odblookup ( SeqParseContext ctx)
static

Definition at line 423 of file msequencer.cxx.

424{
425 char (*list)[XNAME_LENGTH] = ctx.list;
426
427 ctx.xml += "<ODBLookup " + qtoString(ctx.full_filename, ctx.line + 1, ctx.level) + " path=" + q(list[1]) +
428 " string=" + q(list[2]) + ">" + list[3] + "</ODBLookup>\n";
429
430 return TRUE;
431}
Here is the call graph for this function:

◆ seq_parse_odbsave()

static BOOL seq_parse_odbsave ( SeqParseContext ctx)
static

Definition at line 413 of file msequencer.cxx.

414{
415 char (*list)[XNAME_LENGTH] = ctx.list;
416
417 ctx.xml += "<ODBSave " + qtoString(ctx.full_filename, ctx.line + 1, ctx.level) + " path=" + q(list[1]) + ">" + list[2] +
418 "</ODBSave>\n";
419
420 return TRUE;
421}
Here is the call graph for this function:

◆ seq_parse_odbset()

static BOOL seq_parse_odbset ( SeqParseContext ctx)
static

Definition at line 340 of file msequencer.cxx.

341{
342 char (*list)[XNAME_LENGTH] = ctx.list;
343
344 if (list[3][0]) {
345 ctx.xml += "<ODBSet " + qtoString(ctx.full_filename, ctx.line + 1, ctx.level) + " notify=" + q(list[3]) + " path=" + q(list[1]) + ">" +
346 list[2] + "</ODBSet>\n";
347 } else {
348 ctx.xml += "<ODBSet " + qtoString(ctx.full_filename, ctx.line + 1, ctx.level) + " path=" + q(list[1]) + ">" + list[2] + "</ODBSet>\n";
349 }
350
351 return TRUE;
352}
Here is the call graph for this function:

◆ seq_parse_run_description()

static BOOL seq_parse_run_description ( SeqParseContext ctx)
static

Definition at line 322 of file msequencer.cxx.

323{
324 ctx.xml += "<RunDescription " + qtoString(ctx.full_filename, ctx.line + 1, ctx.level) + ">" + ctx.list[1] + "</RunDescription>\n";
325 return TRUE;
326}
Here is the call graph for this function:

◆ seq_parse_script()

static BOOL seq_parse_script ( SeqParseContext ctx)
static

Definition at line 233 of file msequencer.cxx.

234{
235 char (*list)[XNAME_LENGTH] = ctx.list;
236
237 if (list[2][0] == 0) {
238 ctx.xml += "<Script " + qtoString(ctx.full_filename, ctx.line + 1, ctx.level) + ">" + list[1] + "</Script>\n";
239 } else {
240 ctx.xml += "<Script " + qtoString(ctx.full_filename, ctx.line + 1, ctx.level) + " params=\"";
241 for (int i = 2; i < 100 && list[i][0]; i++) {
242 if (i > 2) {
243 ctx.xml += ",";
244 }
245 ctx.xml += list[i];
246 }
247 ctx.xml += "\">";
248 ctx.xml += list[1];
249 ctx.xml += "</Script>\n";
250 }
251
252 return TRUE;
253}
Here is the call graph for this function:

◆ seq_parse_set()

static BOOL seq_parse_set ( SeqParseContext ctx)
static

Definition at line 255 of file msequencer.cxx.

256{
257 char (*list)[XNAME_LENGTH] = ctx.list;
258
259 ctx.xml += "<Set " + qtoString(ctx.full_filename, ctx.line + 1, ctx.level) + " name=" + q(list[1]) + ">" + list[2] + "</Set>\n";
260
261 return TRUE;
262}
Here is the call graph for this function:

◆ seq_parse_transition()

static BOOL seq_parse_transition ( SeqParseContext ctx)
static

Definition at line 328 of file msequencer.cxx.

329{
330 ctx.xml += "<Transition " + qtoString(ctx.full_filename, ctx.line + 1, ctx.level) + ">" + ctx.list[1] + "</Transition>\n";
331 return TRUE;
332}
Here is the call graph for this function:

◆ seq_parse_wait()

static BOOL seq_parse_wait ( SeqParseContext ctx)
static

Definition at line 280 of file msequencer.cxx.

281{
282 char (*list)[XNAME_LENGTH] = ctx.list;
283
284 if (!list[2][0]) {
285 ctx.xml += "<Wait " + qtoString(ctx.full_filename, ctx.line + 1, ctx.level) + " for=\"seconds\">" + list[1] + "</Wait>\n";
286 } else if (!list[3][0]) {
287 ctx.xml += "<Wait " + qtoString(ctx.full_filename, ctx.line + 1, ctx.level) + " for=" + q(list[1]) + ">" + list[2] + "</Wait>\n";
288 } else {
289 ctx.xml += "<Wait " + qtoString(ctx.full_filename, ctx.line + 1, ctx.level) + " for=" + q(list[1]) + " path=" + q(list[2]) + " op=" +
290 q(list[3]);
291
292 // Optional timeout for ODBValue waits:
293 // WAIT ODBValue, path, op, value, timeout, seconds[, status_variable]
294 // Store the timeout in the XML node. The runtime publishes progress
295 // through State/Timeout value and State/Timeout limit. If a status
296 // variable name is given, the runtime writes Variables/<status_variable>:
297 // 1 = condition satisfied before timeout
298 // 0 = timeout expired before condition was satisfied
299 if (list[5][0]) {
300 if (!equal_ustring(list[1], "ODBValue")) {
301 snprintf(ctx.error, ctx.error_size, "WAIT timeout is only supported for WAIT ODBValue");
302 *ctx.error_line = ctx.line + 1;
303 return FALSE;
304 }
305 if (!equal_ustring(list[5], "timeout") || !list[6][0] || list[8][0]) {
306 snprintf(ctx.error, ctx.error_size,
307 "Invalid WAIT ODBValue timeout syntax. Use: WAIT ODBValue, path, op, value, timeout, seconds[, status_variable]");
308 *ctx.error_line = ctx.line + 1;
309 return FALSE;
310 }
311 ctx.xml += " timeout=" + q(list[6]);
312 if (list[7][0])
313 ctx.xml += " status=" + q(list[7]);
314 }
315
316 ctx.xml += ">" + std::string(list[4]) + "</Wait>\n";
317 }
318
319 return TRUE;
320}
Here is the call graph for this function:

◆ seq_pause()

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

Definition at line 2532 of file msequencer.cxx.

2532 {
2533 seq_read(&seq, c);
2534 seq.paused = flag;
2535 if (!flag)
2536 seq.debug = false;
2537 seq_write(seq, c);
2538}
BOOL debug
Definition sequencer.h:21
Here is the call graph for this function:
Here is the caller graph for this function:

◆ seq_read()

void seq_read ( SEQUENCER seq,
SeqCon c 
)

Definition at line 2367 of file msequencer.cxx.

2367 {
2368 int status;
2369 HNDLE hKey;
2370
2371 status = db_find_key(c->hDB, c->hSeq, "State", &hKey);
2372 if (status != DB_SUCCESS) {
2373 cm_msg(MERROR, "seq_read", "Cannot find /Sequencer/State in ODB, db_find_key() status %d", status);
2374 return;
2375 }
2376
2377 int size = sizeof(SEQUENCER);
2378 status = db_get_record1(c->hDB, hKey, seq, &size, 0, strcomb1(sequencer_str).c_str());
2379 if (status != DB_SUCCESS) {
2380 cm_msg(MERROR, "seq_read", "Cannot get /Sequencer/State from ODB, db_get_record1() status %d", status);
2381 return;
2382 }
2383}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ seq_start()

static void seq_start ( SEQUENCER seq,
SeqCon c,
bool  debug 
)
static

Definition at line 2452 of file msequencer.cxx.

2452 {
2453 seq_read(&seq, c);
2454 seq_clear(seq);
2455
2456 // manage sequencer parameters and variables
2457
2458 midas::odb defaults(std::string("/") + c->odb_path + "/Param/Defaults");
2459 midas::odb param(std::string("/") + c->odb_path + "/Param/Value");
2460 midas::odb vars(std::string("/") + c->odb_path + "/Variables");
2461
2462 // check if /Param/Value is there
2463 for (midas::odb& d: defaults)
2464 if (!param.is_subkey(d.get_name())) {
2465 mstrlcpy(seq.error, "Cannot start script because /Sequencer/Param/Value is incomplete", sizeof(seq.error));
2466 seq_write(seq, c);
2467 cm_msg(MERROR, "sequencer", "Cannot start script because /Sequencer/Param/Value is incomplete");
2468 return;
2469 }
2470
2471 // copy /Sequencer/Param/Value to /Sequencer/Variables
2472 for (midas::odb& p: param)
2473 vars[p.get_name()] = p.s();
2474
2475 if (!c->pnseq) {
2476 mstrlcpy(seq.error, "Cannot start script, no script loaded", sizeof(seq.error));
2477 seq_write(seq, c);
2478 return;
2479 }
2480
2481 // start sequencer
2482 seq.running = TRUE;
2483 seq.debug = debug;
2484 seq.current_line_number = 1;
2485 seq.scurrent_line_number = 1;
2486 mstrlcpy(seq.sfilename, seq.filename, sizeof(seq.sfilename));
2487 seq_write(seq, c);
2488
2489 if (debug)
2490 cm_msg(MTALK, "sequencer", "Sequencer started with script \"%s\" in debugging mode.", seq.filename);
2491 else
2492 cm_msg(MTALK, "sequencer", "Sequencer started with script \"%s\".", seq.filename);
2493}
void seq_clear(SEQUENCER &seq)
BOOL debug
debug printouts
Definition mana.cxx:254
Here is the call graph for this function:
Here is the caller graph for this function:

◆ seq_start_next()

static void seq_start_next ( SEQUENCER seq,
SeqCon c 
)
static

Definition at line 2642 of file msequencer.cxx.

2642 {
2643 seq_read(&seq, c);
2644 if (seq.next_filename[0][0]) {
2645 mstrlcpy(seq.filename, seq.next_filename[0], sizeof(seq.filename));
2646 for (int i=0 ; i<9 ; i++)
2647 mstrlcpy(seq.next_filename[i], seq.next_filename[i+1], 256);
2648 seq.next_filename[9][0] = 0;
2649 seq_write(seq, c);
2650
2651 seq_open_file(seq.filename, seq, c);
2652
2653 seq_start(seq, c, false);
2654 }
2655}
static void seq_start(SEQUENCER &seq, SeqCon *c, bool debug)
char next_filename[10][256]
Definition sequencer.h:12
Here is the call graph for this function:
Here is the caller graph for this function:

◆ seq_step_over()

static void seq_step_over ( SEQUENCER seq,
SeqCon c 
)
static

Definition at line 2585 of file msequencer.cxx.

2585 {
2586 seq_read(&seq, c);
2587 seq.paused = false;
2588 seq.debug = true;
2589 seq_write(seq, c);
2590}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ seq_stop()

static void seq_stop ( SEQUENCER seq,
SeqCon c 
)
static

Definition at line 2497 of file msequencer.cxx.

2497 {
2498 seq_read(&seq, c);
2499
2500 if (seq.follow_libraries) {
2501 std::string path(cm_get_path());
2502 path += "userfiles/sequencer/";
2503 path += seq.path;
2504 path += seq.filename;
2505
2506 loadMSL(c->odbs, path);
2507 }
2508
2509 seq_clear(seq);
2510 seq.finished = TRUE;
2511 seq_write(seq, c);
2512}
bool loadMSL(MVOdb *o, const std::string &filename)
int follow_libraries
Definition sequencer.h:24
Here is the call graph for this function:
Here is the caller graph for this function:

◆ seq_stop_after_run()

static void seq_stop_after_run ( SEQUENCER seq,
SeqCon c 
)
static

Definition at line 2516 of file msequencer.cxx.

2516 {
2517 seq_read(&seq, c);
2518 seq.stop_after_run = true;
2519 seq_write(seq, c);
2520}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ seq_watch()

static void seq_watch ( HNDLE  hDB,
HNDLE  hKeyChanged,
int  index,
void *  info 
)
static

Definition at line 2659 of file msequencer.cxx.

2659 {
2660 char str[256];
2661 SeqCon* c = (SeqCon*)info;
2662
2663 seq_read(c->seqp, c);
2664
2665 if (c->seqp->new_file) {
2666 mstrlcpy(str, c->seqp->path, sizeof(str));
2667 if (strlen(str) > 1 && str[strlen(str) - 1] != DIR_SEPARATOR)
2668 mstrlcat(str, DIR_SEPARATOR_STR, sizeof(str));
2669 mstrlcat(str, c->seqp->filename, sizeof(str));
2670
2671 //printf("Load file %s\n", str);
2672
2673 seq_open_file(str, *(c->seqp), c);
2674
2675 seq_clear(*(c->seqp));
2676
2677 seq_write(*(c->seqp), c);
2678 }
2679}
void ** info
Definition fesimdaq.cxx:41
Here is the call graph for this function:
Here is the caller graph for this function:

◆ seq_watch_command()

static void seq_watch_command ( HNDLE  hDB,
HNDLE  hKeyChanged,
int  index,
void *  info 
)
static

Definition at line 2807 of file msequencer.cxx.

2807 {
2808 SeqCon* c = (SeqCon*)info;
2809 SEQUENCER* seqp = c->seqp;
2810
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;
2820 int goto_line = 0;
2821 int goto_line_size = sizeof(goto_line);
2822
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);
2832 db_get_value(c->hDB, c->hSeq, "Command/Goto line", &goto_line, &goto_line_size, TID_INT, TRUE);
2833
2834 if (load_new_file) {
2835 std::string filename;
2836 c->odbs->RS("State/Filename", &filename);
2837
2838 // printf("## load new file %s\n", filename.c_str());
2839
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));
2844 seq_write(*seqp, c);
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));
2849 seq_write(*seqp, c);
2850 } else {
2851 mstrlcpy(seqp->filename, filename.c_str(), sizeof(seqp->filename));
2852 std::string path = cm_expand_env(seqp->path);
2853 if (path.length() > 0 && path.back() != '/') {
2854 path += "/";
2855 }
2856 HNDLE hDB;
2858 seq_clear(*seqp);
2859 seq_open_file(filename.c_str(), *seqp, c);
2860 seq_write(*seqp, c);
2861 }
2862
2863 // indicate that we successfully load the new file
2864 c->odbs->WB("Command/Load new file", false);
2865
2866 // printf("## Set 'load new file' false\n");
2867 }
2868
2869 if (goto_line != 0) {
2870 int zero = 0;
2871
2872 // Reset the command immediately so a failed goto does not repeat forever.
2873 db_set_value(c->hDB, c->hSeq, "Command/Goto line", &zero, sizeof(zero), 1, TID_INT);
2874 seq_goto_line(*seqp, c, goto_line);
2875 }
2876
2877 if (start_script) {
2878 c->odbs->WB("Command/Start script", false);
2879
2880 bool seq_running = false;
2881 c->odbs->RB("State/running", &seq_running);
2882
2883 if (!seq_running) {
2884 seq_start(*seqp, c, false);
2885 } else {
2886 cm_msg(MTALK, "sequencer", "Sequencer is already running");
2887 }
2888 }
2889
2890 if (stop_immediately && c->pnseq != NULL) {
2891 if (!goto_at_exit(*seqp, c)) {
2892 c->odbs->WB("Command/Stop immediately", false);
2893 seq_stop(*seqp, c);
2894 cm_msg(MTALK, "sequencer", "Sequencer is finished by \"stop immediately\".");
2895 } else {
2896 c->odbs->WB("Command/Stop immediately", false);
2897 cm_msg(MTALK, "sequencer", "Sequencer received \"stop immediately\". Executing ATEXIT.");
2898 }
2899 }
2900
2901 if (stop_after_run) {
2902 c->odbs->WB("Command/Stop after run", false);
2903 seq_stop_after_run(*seqp, c);
2904 }
2905
2906 if (cancel_stop_after_run) {
2907 c->odbs->WB("Command/Cancel stop after run", false);
2909 }
2910
2911 if (pause_script) {
2912 seq_pause(*seqp, c, true);
2913 c->odbs->WB("Command/Pause script", false);
2914 cm_msg(MTALK, "sequencer", "Sequencer is paused.");
2915 }
2916
2917 if (resume_script) {
2918 seq_pause(*seqp, c, false);
2919 c->odbs->WB("Command/Resume script", false);
2920 cm_msg(MTALK, "sequencer", "Sequencer is resumed.");
2921 }
2922
2923 if (debug_script) {
2924 c->odbs->WB("Command/Debug script", false);
2925
2926 bool seq_running = false;
2927 c->odbs->RB("State/running", &seq_running);
2928
2929 if (!seq_running) {
2930 seq_start(*seqp, c, true);
2931 } else {
2932 cm_msg(MTALK, "sequencer", "Sequencer is already running");
2933 }
2934 }
2935
2936 if (step_over) {
2937 seq_step_over(*seqp, c);
2938 c->odbs->WB("Command/Step over", false);
2939 }
2940}
std::string cm_expand_env(const char *str)
Definition midas.cxx:7823
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_step_over(SEQUENCER &seq, SeqCon *c)
static void seq_cancel_stop_after_run(SEQUENCER &seq, SeqCon *c)
static void seq_pause(SEQUENCER &seq, SeqCon *c, bool flag)
Here is the call graph for this function:
Here is the caller graph for this function:

◆ seq_write()

void seq_write ( const SEQUENCER seq,
SeqCon c 
)

Definition at line 2385 of file msequencer.cxx.

2385 {
2386 int status;
2387 HNDLE hKey;
2388
2389 status = db_find_key(c->hDB, c->hSeq, "State", &hKey);
2390 if (status != DB_SUCCESS) {
2391 cm_msg(MERROR, "seq_write", "Cannot find /Sequencer/State in ODB, db_find_key() status %d", status);
2392 return;
2393 }
2394 status = db_set_record(c->hDB, hKey, (void *) &seq, sizeof(SEQUENCER), 0);
2395 if (status != DB_SUCCESS) {
2396 cm_msg(MERROR, "seq_write", "Cannot write to ODB /Sequencer/State, db_set_record() status %d", status);
2397 return;
2398 }
2399}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ sequencer()

void sequencer ( SEQUENCER seq,
SeqCon c 
)

Definition at line 3275 of file msequencer.cxx.

3275 {
3276 PMXML_NODE pn, pr;
3277 char data[256], str[1024], name[32];
3278 std::string value;
3279 char list[100][XNAME_LENGTH];
3280 int i, size;
3281 HNDLE hKeySeq;
3282 BOOL skip_step = FALSE;
3283
3284 if (!seq.running || seq.paused) {
3285 ss_sleep(10);
3286 return;
3287 }
3288
3289 if (c->pnseq == NULL) {
3290 seq_stop(seq, c);
3291 mstrlcpy(seq.error, "No script loaded", sizeof(seq.error));
3292 seq_write(seq, c);
3293 ss_sleep(10);
3294 return;
3295 }
3296
3297 db_find_key(c->hDB, c->hSeq, "State", &hKeySeq);
3298 if (!hKeySeq)
3299 return;
3300
3301 // Retrieve last midas message and put it into seq structure (later sent to ODB via db_set_record()
3302 cm_msg_retrieve(1, str, sizeof(str));
3303 str[19] = 0;
3304 strcpy(seq.last_msg, str+11);
3305
3306 pr = mxml_find_node(c->pnseq, "RunSequence");
3307 if (!pr) {
3308 seq_error(seq, c, "Cannot find &lt;RunSequence&gt; tag in XML file");
3309 return;
3310 }
3311
3312 int last_line = mxml_get_line_number_end(pr);
3313
3314 /* check for Subroutine end */
3315 if (seq.stack_index > 0 && seq.current_line_number == seq.subroutine_end_line[seq.stack_index - 1]) {
3316 seq_read(&seq, c);
3317 seq.subroutine_end_line[seq.stack_index - 1] = 0;
3318
3319 if (seq.subroutine_return_line[seq.stack_index - 1] == -1) {
3320 // end of atexit subroutine
3321 seq_stop(seq, c);
3322 cm_msg(MTALK, "sequencer", "Sequencer is finished.");
3323
3324 seq_start_next(seq, c);
3325 return;
3326 }
3327
3329 seq.subroutine_return_line[seq.stack_index - 1] = 0;
3330 seq.subroutine_call_line[seq.stack_index - 1] = 0;
3331 seq.ssubroutine_call_line[seq.stack_index - 1] = 0;
3332 seq.stack_index--;
3333 seq_write(seq, c);
3334 return;
3335 }
3336
3337 /* check for last line of script */
3338 if (seq.current_line_number > last_line) {
3339
3340 if (!goto_at_exit(seq, c)) {
3341 seq_stop(seq, c);
3342 cm_msg(MTALK, "sequencer", "Sequencer is finished.");
3343
3344 seq_start_next(seq, c);
3345 }
3346 return;
3347 }
3348
3349 /* check for loop end */
3350 for (i = SEQ_NEST_LEVEL_LOOP-1; i >= 0; i--)
3351 if (seq.loop_start_line[i] > 0)
3352 break;
3353 if (i >= 0) {
3354 if (seq.current_line_number == seq.loop_end_line[i]) {
3355 size = sizeof(seq);
3356 db_get_record(c->hDB, hKeySeq, &seq, &size, 0);
3357
3358 if (seq.loop_counter[i] == seq.loop_n[i]) {
3359 seq.loop_counter[i] = 0;
3360 seq.loop_start_line[i] = 0;
3361 seq.sloop_start_line[i] = 0;
3362 seq.loop_end_line[i] = 0;
3363 seq.sloop_end_line[i] = 0;
3364 seq.loop_n[i] = 0;
3365 seq.current_line_number++;
3366 } else {
3367 pn = mxml_get_node_at_line(c->pnseq, seq.loop_start_line[i]);
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));
3372 strbreak(data, list, 100, ",", FALSE);
3373 value = eval_var(seq, c, list[seq.loop_counter[i]]);
3374 } else if (mxml_get_attribute(pn, "n")) {
3375 value = std::to_string(seq.loop_counter[i] + 1);
3376 }
3377 sprintf(str, "Variables/%s", name); // FIXME: unsafe
3378 size = value.length() + 1;
3379 if (size < 32)
3380 size = 32;
3381 db_set_value(c->hDB, c->hSeq, str, value.c_str(), size, 1, TID_STRING);
3382 }
3383 seq.loop_counter[i]++;
3384 seq.current_line_number = seq.loop_start_line[i] + 1;
3385 }
3386 db_set_record(c->hDB, hKeySeq, &seq, sizeof(seq), 0);
3387 return;
3388 }
3389 }
3390
3391 /* check for end of "if" statement */
3392 if (seq.if_index > 0 && seq.current_line_number == seq.if_endif_line[seq.if_index - 1]) {
3393 size = sizeof(seq);
3394 db_get_record(c->hDB, hKeySeq, &seq, &size, 0);
3395 seq.if_index--;
3396 seq.if_line[seq.if_index] = 0;
3397 seq.if_else_line[seq.if_index] = 0;
3398 seq.if_endif_line[seq.if_index] = 0;
3399 seq.current_line_number++;
3400 db_set_record(c->hDB, hKeySeq, &seq, sizeof(seq), 0);
3401 return;
3402 }
3403
3404 /* check for ODBSubdir end */
3405 if (seq.current_line_number == seq.subdir_end_line) {
3406 size = sizeof(seq);
3407 db_get_record(c->hDB, hKeySeq, &seq, &size, 0);
3408 seq.subdir_end_line = 0;
3409 seq.subdir[0] = 0;
3411 db_set_record(c->hDB, hKeySeq, &seq, sizeof(seq), 0);
3412 return;
3413 }
3414
3415 /* find node belonging to current line */
3416 pn = mxml_get_node_at_line(c->pnseq, seq.current_line_number);
3417 if (!pn) {
3418 size = sizeof(seq);
3419 db_get_record(c->hDB, hKeySeq, &seq, &size, 0);
3420 seq.current_line_number++;
3421 db_set_record(c->hDB, hKeySeq, &seq, sizeof(seq), 0);
3422 return;
3423 }
3424
3425 /* set MSL line from current element and put script into ODB if changed (library call) */
3426 pn = mxml_get_node_at_line(c->pnseq, seq.current_line_number);
3427 if (pn) {
3428 if (seq.follow_libraries) {
3429 if (mxml_get_attribute(pn, "l"))
3430 seq.scurrent_line_number = atoi(mxml_get_attribute(pn, "l"));
3431 if (mxml_get_attribute(pn, "fn")) {
3432 std::string filename = mxml_get_attribute(pn, "fn");
3433
3434 // load file into ODB if changed
3435 if (filename != std::string(seq.sfilename)) {
3436 if (loadMSL(c->odbs, filename))
3437 mstrlcpy(seq.sfilename, filename.c_str(), sizeof(seq.sfilename));
3438 }
3439 }
3440 } else {
3441 if (mxml_get_attribute(pn, "l") && (!mxml_get_attribute(pn, "lvl") || atoi(mxml_get_attribute(pn, "lvl")) == 0))
3442 seq.scurrent_line_number = atoi(mxml_get_attribute(pn, "l"));
3443 }
3444 }
3445
3446
3447 // out-comment following lines for debug output
3448#if 0
3449 if (seq.scurrent_line_number >= 0) {
3450 midas::odb o("/" + c->odb_path + "/Script/Lines");
3451 std::string s = o[seq.scurrent_line_number - 1];
3452 printf("%3d: %s\n", seq.scurrent_line_number, s.c_str());
3453 }
3454#endif
3455
3456 if (!seq_execute_xml_node(seq, c, pn, hKeySeq, last_line, skip_step))
3457 return;
3458
3459 /* get steering parameters, since they might have been changed in between */
3460 SEQUENCER seq1;
3461 size = sizeof(seq1);
3462 db_get_record(c->hDB, hKeySeq, &seq1, &size, 0);
3463 seq.running = seq1.running;
3464 seq.finished = seq1.finished;
3465 seq.paused = seq1.paused;
3466 seq.debug = seq1.debug;
3467 seq.stop_after_run = seq1.stop_after_run;
3468 mstrlcpy(seq.message, seq1.message, sizeof(seq.message));
3469 memcpy(seq.next_filename, seq1.next_filename, sizeof(seq.next_filename));
3470
3471 // in debugging mode, pause after each step
3472 if (seq.debug && !skip_step)
3473 seq.paused = TRUE;
3474
3475 /* update current line number */
3476 db_set_record(c->hDB, hKeySeq, &seq, sizeof(seq), 0);
3477}
INT cm_msg_retrieve(INT n_message, char *message, INT buf_size)
Definition midas.cxx:1381
static void seq_start_next(SEQUENCER &seq, SeqCon *c)
static BOOL seq_execute_xml_node(SEQUENCER &seq, SeqCon *c, PMXML_NODE pn, HNDLE hKeySeq, int last_line, BOOL &skip_step)
char last_msg[10]
Definition sequencer.h:53
Here is the call graph for this function:
Here is the caller graph for this function:

◆ SEQUENCER_STR()

SEQUENCER_STR ( sequencer_str  )

◆ set_all_matching()

int set_all_matching ( HNDLE  hDB,
HNDLE  hBaseKey,
const char *  odbpath,
char *  value,
int  index1,
int  index2,
int  notify 
)

Definition at line 2969 of file msequencer.cxx.

2969 {
2970 int status, size;
2971 char data[256];
2972 KEY key;
2973
2974 std::vector<HNDLE> keys;
2975 status = db_find_keys(hDB, hBaseKey, odbpath, keys);
2976
2977 if (status != DB_SUCCESS)
2978 return status;
2979
2980 for (HNDLE hKey: keys) {
2981 db_get_key(hDB, hKey, &key);
2982 size = sizeof(data);
2983 db_sscanf(value, data, &size, 0, key.type);
2984
2985 /* extend data size for single string if necessary */
2986 if ((key.type == TID_STRING || key.type == TID_LINK)
2987 && (int) strlen(data) + 1 > key.item_size && key.num_values == 1)
2988 key.item_size = strlen(data) + 1;
2989
2990 if (key.num_values > 1 && index1 == -1) {
2991 for (int i = 0; i < key.num_values; i++)
2993 } else if (key.num_values > 1 && index2 > index1) {
2994 if (index1 < 0 || index1 >= key.num_values || index2 < 0 || index2 >= key.num_values)
2995 return DB_INVALID_PARAM;
2996 for (int i = index1; i < key.num_values && i <= index2; i++)
2998 } else {
2999 if (index1 < 0 || index1 >= key.num_values)
3000 return DB_INVALID_PARAM;
3001 status = db_set_data_index1(hDB, hKey, data, key.item_size, index1, key.type, notify);
3002 }
3003
3004 if (status != DB_SUCCESS) {
3005 return status;
3006 }
3007 }
3008
3009 return DB_SUCCESS;
3010}
INT db_find_keys(HNDLE hDB, HNDLE hKeyRoot, const char *odbpath, std::vector< HNDLE > &hKeyVector)
Definition odb.cxx:4847
Here is the call graph for this function:
Here is the caller graph for this function:

◆ strbreak()

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

Definition at line 1603 of file msequencer.cxx.

1606{
1607 int i, j;
1608 char *p;
1609
1610 memset(list, 0, size * XNAME_LENGTH);
1611 p = str;
1612 if (!p || !*p)
1613 return 0;
1614
1615 while (*p == ' ')
1616 p++;
1617
1618 for (i = 0; *p && i < size; i++) {
1619 if (*p == '"' && !ignore_quotes) {
1620 p++;
1621 j = 0;
1622 memset(list[i], 0, XNAME_LENGTH);
1623 do {
1624 /* convert two '"' to one */
1625 if (*p == '"' && *(p + 1) == '"') {
1626 list[i][j++] = '"';
1627 p += 2;
1628 } else if (*p == '"') {
1629 break;
1630 } else
1631 list[i][j++] = *p++;
1632
1633 } while (j < XNAME_LENGTH - 1);
1634 list[i][j] = 0;
1635
1636 /* skip second '"' */
1637 p++;
1638
1639 /* skip blanks and break character */
1640 while (*p == ' ')
1641 p++;
1642 if (*p && strchr(brk, *p))
1643 p++;
1644 while (*p == ' ')
1645 p++;
1646
1647 } else {
1648 mstrlcpy(list[i], p, XNAME_LENGTH);
1649
1650 for (j = 0; j < (int) strlen(list[i]); j++)
1651 if (strchr(brk, list[i][j])) {
1652 list[i][j] = 0;
1653 break;
1654 }
1655
1656 p += strlen(list[i]);
1657 while (*p == ' ')
1658 p++;
1659 if (*p && strchr(brk, *p))
1660 p++;
1661 while (*p == ' ')
1662 p++;
1663
1664 while (list[i][strlen(list[i]) - 1] == ' ')
1665 list[i][strlen(list[i]) - 1] = 0;
1666 }
1667
1668 if (!*p)
1669 break;
1670 }
1671
1672 if (i == size)
1673 return size;
1674
1675 return i + 1;
1676}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ stristr()

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

Definition at line 64 of file msequencer.cxx.

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

◆ strsubst()

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

Definition at line 98 of file msequencer.cxx.

100{
101 char *tail, *p;
102 int s;
103
104 p = string;
105 for (p = stristr(p, pattern); p != NULL; p = stristr(p, pattern)) {
106
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);
112 } else {
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);
118 free(tail);
119 tail = NULL;
120 }
121
122 p += strlen(subst);
123 }
124}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ toString()

static std::string toString ( int  v)
static

Definition at line 128 of file msequencer.cxx.

128 {
129 char buf[256];
130 snprintf(buf, sizeof(buf), "%d", v);
131 return buf;
132}

Variable Documentation

◆ gOdb

MVOdb* gOdb = NULL

Definition at line 45 of file msequencer.cxx.

◆ seq_command_table

SeqCommand seq_command_table[]
static
Initial value:
= {
{ "comment", "Comment", seq_parse_comment, seq_execute_skip_node },
{ "message", "Message", seq_parse_message, seq_execute_message },
{ "msg", "Msg", seq_parse_msg, seq_execute_msg },
{ "script", "Script", seq_parse_script, seq_execute_script },
{ "set", "Set", seq_parse_set, seq_execute_set },
{ "cat", "Cat", seq_parse_cat, seq_execute_cat },
{ "wait", "Wait", seq_parse_wait, seq_execute_wait },
{ "rundescription", "RunDescription", seq_parse_run_description, seq_execute_run_description },
{ "transition", "Transition", seq_parse_transition, seq_execute_transition },
{ "exit", "Exit", seq_parse_exit, seq_execute_exit },
{ "odbset", "ODBSet", seq_parse_odbset, seq_execute_odbset },
{ "odbget", "ODBGet", seq_parse_odbget, seq_execute_odbget },
{ "odbinc", "ODBInc", seq_parse_odbinc, seq_execute_odbinc },
{ "odbcreate", "ODBCreate", seq_parse_odbcreate, seq_execute_odbcreate },
{ "odbdelete", "ODBDelete", seq_parse_odbdelete, seq_execute_odbdelete },
{ "odbload", "ODBLoad", seq_parse_odbload, seq_execute_odbload },
{ "odbsave", "ODBSave", seq_parse_odbsave, seq_execute_odbsave },
{ "odblookup", "ODBLookup", seq_parse_odblookup, seq_execute_odblookup },
{ NULL, "PI", NULL, seq_execute_skip_node },
{ NULL, "RunSequence", NULL, seq_execute_skip_node },
{ NULL, NULL, NULL, NULL }
}
static BOOL seq_execute_script(SeqExecContext &ctx)
static BOOL seq_parse_odbget(SeqParseContext &ctx)
static BOOL seq_execute_odbsave(SeqExecContext &ctx)
static BOOL seq_parse_odbsave(SeqParseContext &ctx)
static BOOL seq_execute_odbinc(SeqExecContext &ctx)
static BOOL seq_execute_transition(SeqExecContext &ctx)
static BOOL seq_parse_run_description(SeqParseContext &ctx)
static BOOL seq_execute_set(SeqExecContext &ctx)
static BOOL seq_parse_comment(SeqParseContext &ctx)
static BOOL seq_execute_wait(SeqExecContext &ctx)
static BOOL seq_parse_msg(SeqParseContext &ctx)
static BOOL seq_execute_odbdelete(SeqExecContext &ctx)
static BOOL seq_parse_odblookup(SeqParseContext &ctx)
static BOOL seq_parse_message(SeqParseContext &ctx)
static BOOL seq_parse_wait(SeqParseContext &ctx)
static BOOL seq_parse_odbset(SeqParseContext &ctx)
static BOOL seq_parse_exit(SeqParseContext &ctx)
static BOOL seq_execute_msg(SeqExecContext &ctx)
static BOOL seq_parse_transition(SeqParseContext &ctx)
static BOOL seq_execute_odblookup(SeqExecContext &ctx)
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 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)
static BOOL seq_execute_cat(SeqExecContext &ctx)
static BOOL seq_parse_set(SeqParseContext &ctx)
static BOOL seq_parse_odbcreate(SeqParseContext &ctx)
static BOOL seq_parse_odbload(SeqParseContext &ctx)
static BOOL seq_execute_exit(SeqExecContext &ctx)
static BOOL seq_parse_odbinc(SeqParseContext &ctx)
static BOOL seq_parse_odbdelete(SeqParseContext &ctx)

Definition at line 1511 of file msequencer.cxx.

1511 {
1512 { "comment", "Comment", seq_parse_comment, seq_execute_skip_node },
1513 { "message", "Message", seq_parse_message, seq_execute_message },
1514 { "msg", "Msg", seq_parse_msg, seq_execute_msg },
1515 { "script", "Script", seq_parse_script, seq_execute_script },
1516 { "set", "Set", seq_parse_set, seq_execute_set },
1517 { "cat", "Cat", seq_parse_cat, seq_execute_cat },
1518 { "wait", "Wait", seq_parse_wait, seq_execute_wait },
1519 { "rundescription", "RunDescription", seq_parse_run_description, seq_execute_run_description },
1520 { "transition", "Transition", seq_parse_transition, seq_execute_transition },
1521 { "exit", "Exit", seq_parse_exit, seq_execute_exit },
1522 { "odbset", "ODBSet", seq_parse_odbset, seq_execute_odbset },
1523 { "odbget", "ODBGet", seq_parse_odbget, seq_execute_odbget },
1524 { "odbinc", "ODBInc", seq_parse_odbinc, seq_execute_odbinc },
1525 { "odbcreate", "ODBCreate", seq_parse_odbcreate, seq_execute_odbcreate },
1526 { "odbdelete", "ODBDelete", seq_parse_odbdelete, seq_execute_odbdelete },
1527 { "odbload", "ODBLoad", seq_parse_odbload, seq_execute_odbload },
1528 { "odbsave", "ODBSave", seq_parse_odbsave, seq_execute_odbsave },
1529 { "odblookup", "ODBLookup", seq_parse_odblookup, seq_execute_odblookup },
1530
1531 /* XML-only nodes produced by the sequencer XML generator/parser. */
1532 { NULL, "PI", NULL, seq_execute_skip_node },
1533 { NULL, "RunSequence", NULL, seq_execute_skip_node },
1534
1535 { NULL, NULL, NULL, NULL }
1536};