1926 {
1927 char str[256], *pl, *pe;
1929 int i,
j,
n, nq, n_lines, endl, line, nest, incl, library;
1930 std::string xml, path, fn;
1931 char *msl_include, *xml_include, *include_error;
1932 int include_error_size;
1933 BOOL include_status, rel_path;
1934 std::vector<std::string> subroutine_names;
1935
1936 if (level > 10) {
1937 snprintf(error, error_size, "More than 10 nested INCLUDE statements exceeded in file \"%s\"", filename);
1939 }
1940
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));
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);
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);
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
1996 lines = (char **) malloc(sizeof(char *));
1997 incl = 0;
1998 pl = buf;
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;
2016 subroutine_names.emplace_back(
list[1]);
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
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);
2034 }
2035
2036 std::string p;
2037 if (
list[1][0] ==
'/') {
2039 p += "userfiles/sequencer";
2041 } else {
2042 p = path;
2043 if (!p.empty() && p.back() != '/')
2044 p += "/";
2046 }
2047
2048 xml += " <!ENTITY ";
2049 xml += reference;
2050 xml += " SYSTEM \"";
2051 xml += p;
2052 xml += ".xml\">\n";
2053
2054
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
2068 path += "userfiles/sequencer/";
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
2077 *error_line = n_lines + 1;
2079 }
2080 }
2082 xml += "<Library name=\"";
2084 xml += "\">\n";
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
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
2107 std::string p =
"/" +
c->odb_path +
"/Param/Value";
2109 oldSeqParam.set_auto_refresh_read(false);
2110 oldSeqParam.set_auto_create(false);
2111
2112
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)
2128 else {
2131 }
2132
2133
2134 for (
i = 0;
i <
n;
i++) {
2135 if (
list[
i][0] ==
'#') {
2136 for (
j =
i;
j <
n;
j++)
2138 break;
2139 }
2140 }
2141
2142
2143 for (
i = 0;
i <
n;
i++) {
2144 if (strchr(
list[
i],
'#'))
2145 *strchr(
list[
i],
'#') = 0;
2146 }
2147
2148
2149 for (
i = 0;
i <
n;
i++) {
2152 }
2153
2154
2156 mstrlcpy(
eq, lines[line],
sizeof(
eq));
2157 if (strchr(
eq,
'#'))
2158 *strchr(
eq,
'#') = 0;
2159 for (
i = 0,
n = 0, nq = 0;
i < (int)strlen(
eq);
i++) {
2161 nq = (nq == 0 ? 1 : 0);
2162 if (
eq[
i] ==
'=' && nq == 0 &&
2163 (
i > 0 && (
eq[
i - 1] !=
'!') &&
eq[
i - 1] !=
'<' &&
eq[
i - 1] !=
'>'))
2165 }
2166 if (
n == 1 &&
eq[0] !=
'=') {
2167
2168 mstrlcpy(
list[0],
"SET",
sizeof(
list[0]));
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] ==
' ')
2182 }
2183
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);
2189
2191
2193
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
2205 std::any_of(subroutine_names.begin(), subroutine_names.end(),
2206 [&](
const std::string &
name) { return equal_ustring(list[0], name.c_str()); })) {
2208 int first_arg = explicit_call ? 2 : 1;
2209 xml +=
"<Call " +
qtoString(fullFilename, line + 1, level) +
" name=" +
q(
list[explicit_call ? 1 : 0]) +
">";
2210 for (
i = first_arg;
i < 100 &&
list[
i][0];
i++) {
2211 if (
i > first_arg) {
2212 xml += ",";
2213 }
2215 }
2216 xml += "</Call>\n";
2217
2219 xml +=
"<Goto " +
qtoString(fullFilename, line + 1, level) +
" sline=" +
q(
list[1]) +
" />\n";
2220
2222 xml +=
"<If " +
qtoString(fullFilename, line + 1, level) +
" condition=\"";
2223 for (
i = 1;
i < 100 &&
list[
i][0] && stricmp(
list[
i],
"THEN") != 0;
i++) {
2225 }
2226 xml += "\">\n";
2227
2229 xml += "<Else />\n";
2230
2232 xml += "</If>\n";
2233
2235
2236 for (
i = line, nest = 0;
i < n_lines;
i++) {
2239 nest++;
2241 nest--;
2242 if (nest == 0)
2243 break;
2244 }
2245 }
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=" +
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++) {
2259 xml += ",";
2260 }
2262 }
2263 xml += "\">\n";
2264 }
2266 xml += "</Loop>\n";
2267
2269 xml +=
"<Break "+
qtoString(fullFilename, line + 1, level) +
"></Break>\n";
2270
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 }
2278 xml += "</ODBSubdir>\n";
2279
2282 snprintf(error, error_size,
"Parameter \"%s\" misses 'comment'",
list[1]);
2283 *error_line = line + 1;
2285
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]);
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]) {
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]) {
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
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++) {
2320 xml += ",";
2321 }
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
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());
2334
2336 xml +=
"\n<Subroutine " +
qtoString(fullFilename, line + 1, level) +
" name=" +
q(
list[1]) +
">\n";
2337
2339 xml += "</Subroutine>\n";
2340
2341 }
else if (
list[0][0] == 0 ||
list[0][0] ==
'#') {
2342
2343 } else {
2344 snprintf(error, error_size,
"Invalid command \"%s\"",
list[0]);
2345 *error_line = line + 1;
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
2359 fprintf(fout, "%s", xml.c_str());
2360 fclose(fout);
2361
2363}
std::string cm_get_path()
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)
BOOL(* parse_msl)(SeqParseContext &ctx)