Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
Indent the rest of the code (examples, buildtools, doc...) except for examples/SMPI...
[simgrid.git] / tools / tesh2 / src / fstream.c
1 /*\r
2  * src/fstream.c - type representing the tesh file stream.\r
3  *\r
4  * Copyright 2008,2009 Martin Quinson, Malek Cherier All right reserved. \r
5  *\r
6  * This program is free software; you can redistribute it and/or modify it \r
7  * under the terms of the license (GNU LGPL) which comes with this package.\r
8  *\r
9  * Purpose:\r
10  *              This file contains all the definitions of the functions related with\r
11  *              the tesh file stream type.\r
12  *\r
13  */  \r
14     \r
15 #include <fstream.h>\r
16 #include <xerrno.h>\r
17 #include <context.h>\r
18 #include <command.h>\r
19 #include <unit.h>\r
20 #include <str_replace.h>\r
21 #include <variable.h>\r
22     \r
23 #include <readline.h>\r
24     \r
25 #include <is_cmd.h>\r
26 #include <getpath.h>\r
27     \r
28 #ifndef _XBT_WIN32\r
29 #include <xsignal.h>\r
30 #endif  /* \r */
31     \r
32 #ifdef _XBT_WIN32\r
33 static int \r is_w32_cmd(char *cmd, char **path) \r
34 {
35   \rsize_t i = 0;
36   \rstruct stat stat_buff = { 0 };
37   \rchar buff[PATH_MAX + 1] = { 0 };
38   \r\r\r\rif (!cmd)
39     \r {
40     \rerrno = EINVAL;
41     \rreturn 0;
42     \r}
43   \r\rif (stat(cmd, &stat_buff) || !S_ISREG(stat_buff.st_mode))
44     \r {
45     \rif (path)
46       \r {
47       \rfor (i = 0; path[i] != NULL; i++)
48         \r {
49         \r
50             /* use Cat.exe on Windows */ \r
51             if (!strcmp(cmd, "cat"))
52           \rcmd[0] = 'C';
53         \r\rsprintf(buff, "%s\\%s", path[i], cmd);
54         \r\rif (!stat(buff, &stat_buff) && S_ISREG(stat_buff.st_mode))
55           \rreturn 1;
56         \r}
57       \r}
58     \r}
59   \r
60   else
61     \rreturn 1;
62   \r\r\rreturn 0;
63 \r}
64
65 \r
66 #endif  /* \r */
67     \r\rXBT_LOG_EXTERNAL_DEFAULT_CATEGORY(tesh);
68 \r\r\rlong fstream_getline(fstream_t fstream, char **buf, size_t * n)
69 {
70   \r\rreturn readline(fstream->stream, buf, n);
71 \r\r}
72
73 \r\rstatic void \r failure(unit_t unit) \r
74 {
75   \rif (!keep_going_unit_flag)
76     \r {
77     \runit_t root = unit->root ? unit->root : unit;
78     \r\rif (!root->interrupted)
79       \r {
80       \r
81           /* the unit interrupted (exit for the loop) */ \r
82           root->interrupted = 1;
83       \r\r
84           /* release the unit */ \r
85           xbt_os_sem_release(root->sem);
86       \r}
87     \r\r
88         /* if the --keep-going option is not specified */ \r
89         if (!keep_going_flag)
90       \r {
91       \rif (!interrupted)
92         \r {
93         \r
94             /* request an global interruption by the runner */ \r
95             interrupted = 1;
96         \r\r
97             /* release the runner */ \r
98             xbt_os_sem_release(units_sem);
99         \r}
100       \r}
101     \r}
102 \r}
103
104 \r\rfstream_t \r fstream_new(const char *directory, const char *name) \r
105 {
106   \rfstream_t fstream;
107   \r\rif (!name)
108     \r {
109     \rerrno = EINVAL;
110     \rreturn NULL;
111     \r}
112   \r\rif (!directory && !strcmp("stdin", name))
113     \r {
114     \rfstream = xbt_new0(s_fstream_t, 1);
115     \rfstream->name = strdup("stdin");
116     \rreturn fstream;
117     \r}
118   \r
119   else if (!directory)
120     \r {
121     \rerrno = EINVAL;
122     \rreturn NULL;
123     \r}
124   \r\rfstream = xbt_new0(s_fstream_t, 1);
125   \r\rif (!(fstream->name = strdup(name)))
126     \r {
127     \rfree(fstream);
128     \rreturn NULL;
129     \r}
130   \r\rif (!(fstream->directory = strdup(directory)))
131     \r {
132     \rfree(fstream->name);
133     \rfree(fstream);
134     \rreturn NULL;
135     \r}
136   \r\rfstream->stream = NULL;
137   \rfstream->unit = NULL;
138   \rfstream->parsed = 0;
139   \r\r\rreturn fstream;
140 \r}
141
142 \r\rint \r fstream_open(fstream_t fstream) \r
143 {
144   \rchar path[PATH_MAX + 1] = { 0 };
145   \r\r
146       /* check the parameter */ \r
147       if (!(fstream))
148     \r {
149     \rerrno = EINVAL;
150     \rreturn -1;
151     \r}
152   \r\rif (!fstream || fstream->stream)
153     \r {
154     \rerrno = EALREADY;
155     \rreturn -1;
156     \r}
157   \r\rif (!strcmp(fstream->name, "stdin"))
158     \r {
159     \rfstream->stream = stdin;
160     \rreturn 0;
161     \r}
162   \r\r
163 #ifndef _XBT_WIN32\r
164       sprintf(path, "%s/%s", fstream->directory, fstream->name);
165   \r
166 #else   /* \r */
167       sprintf(path, "%s\\%s", fstream->directory, fstream->name);
168   \r
169 #endif  /* \r */
170       \rif (!(fstream->stream = fopen(path, "r")))
171     \r {
172     \rreturn -1;
173     \r}
174   \r\rreturn 0;
175 \r}
176
177 \r\rint \r fstream_close(fstream_t fstream) \r
178 {
179   \r
180       /* check the parameter */ \r
181       if (!(fstream) || !strcmp(fstream->name, "stdin"))
182     \r {
183     \rerrno = EINVAL;
184     \rreturn -1;
185     \r}
186   \r\rif (!fstream->stream)
187     \rreturn EBADF;
188   \r\rif (EOF == fclose(fstream->stream))
189     \rreturn -1;
190   \r\rfstream->stream = NULL;
191   \r\rreturn 0;
192 \r}
193
194 \r\rint \r fstream_free(fstream_t * ptr) \r
195 {
196   \r\r
197       /* check the parameter */ \r
198       if (!(*ptr))
199     \r {
200     \rerrno = EINVAL;
201     \rreturn -1;
202     \r}
203   \r\rif (!(*ptr))
204     \rreturn EINVAL;
205   \r\rif ((*ptr)->stream)
206     \rfclose((*ptr)->stream);
207   \r\rif ((*ptr)->name)
208     \rfree((*ptr)->name);
209   \r\rif ((*ptr)->directory)
210     \rfree((*ptr)->directory);
211   \r\rfree(*ptr);
212   \r\r*ptr = NULL;
213   \r\rreturn 0;
214 \r\r}
215
216 \r\rint \r fstream_parse(fstream_t fstream, xbt_os_mutex_t mutex) \r
217 {
218   \rsize_t len;
219   \rchar *line = NULL;
220   \rint line_num = 0;
221   \rchar file_pos[256];
222   \rxbt_strbuff_t buff;
223   \rint buffbegin = 0;
224   \rcontext_t context;
225   \runit_t unit;
226   \r\r
227       /* Count the line length while checking wheather it's blank */ \r
228   int blankline;
229   \rint linelen;
230   \r
231       /* Deal with \ at the end of the line, and call handle_line on result */ \r
232   int to_be_continued;
233   \r\r
234       /* check the parameter */ \r
235       if (!(fstream) || !mutex)
236     \r {
237     \rerrno = EINVAL;
238     \rreturn -1;
239     \r}
240   \r\rbuff = xbt_strbuff_new();
241   \r\rif (!(context = context_new()))
242     \rreturn -1;
243   \r\runit = fstream->unit;
244   \r\r
245       /*while(!(unit->root->interrupted)  && getline(&line, &len, fstream->stream) != -1) */ \r
246       while (!(unit->root->interrupted)
247              && fstream_getline(fstream, &line, &len) != -1)
248     \r {
249     \r\rblankline = 1;
250     \rlinelen = 0;
251     \rto_be_continued = 0;
252     \r\rline_num++;
253     \r\rwhile (line[linelen] != '\0')
254       \r {
255       \rif (line[linelen] != ' ' && line[linelen] != '\t'
256            && line[linelen] != '\n' && line[linelen] != '\r')
257         \rblankline = 0;
258       \r\rlinelen++;
259       \r}
260     \r\rif (blankline)
261       \r {
262       \rif (!context->command_line
263            && (context->input->used || context->output->used))
264         \r {
265         \rsnprintf(file_pos, 256, "%s:%d", fstream->name, line_num);
266         \rERROR1("[%s] Error : no command found in the last chunk of lines",
267                 file_pos);
268         \r\runit_set_error(fstream->unit, ESYNTAX, 1, file_pos);
269         \r\rfailure(unit);
270         \rbreak;
271         \r}
272       \r
273       else if (unit->is_running_suite)
274         \r {                     /* it's the end of a suite */
275         \r\runit_t * current_suite =
276             xbt_dynar_get_ptr(unit->suites,
277                               xbt_dynar_length(unit->suites) - 1);
278         \r\rif (!xbt_dynar_length((*current_suite)->includes))
279           \r {
280           \rERROR2("[%s] Malformated suite `(%s)' : include missing",
281                   file_pos, (*current_suite)->description);
282           \r\runit_set_error(*current_suite, ESYNTAX, 1, file_pos);
283           \r\rfailure(unit);
284           \r\r}
285         \r\runit->is_running_suite = 0;
286         \r}
287       \r\rif (context->command_line)
288         \r {
289         \r
290 #ifdef _XBT_WIN32\r
291             if (!context->is_not_found)
292           \r {
293           \r
294 #endif  /* \r */
295               if (fstream_launch_command(fstream, context, mutex) < 0)
296             \rbreak;
297           \r\r
298 #ifdef _XBT_WIN32\r
299           }
300         \r
301 #endif  /* \r */
302         }
303       \r\rcontinue;
304       \r}
305     \r\rif (linelen > 1 && line[linelen - 2] == '\\')
306       \r {
307       \rif (linelen > 2 && line[linelen - 3] == '\\')
308         \r {
309         \r
310             /* Damn. Escaped \ */ \r
311             line[linelen - 2] = '\n';
312         \rline[linelen - 1] = '\0';
313         \r}
314       \r
315       else
316         \r {
317         \rto_be_continued = 1;
318         \rline[linelen - 2] = '\0';
319         \rlinelen -= 2;
320         \r\rif (!buff->used)
321           \rbuffbegin = line_num;
322         \r}
323       \r}
324     \r\rif (buff->used || to_be_continued)
325       \r {
326       \rxbt_strbuff_append(buff, line);
327       \r\rif (!to_be_continued)
328         \r {
329         \rsnprintf(file_pos, 256, "%s:%d", fstream->name, buffbegin);
330         \rfstream_lex_line(fstream, context, mutex, file_pos, buff->data);
331         \rxbt_strbuff_empty(buff);
332         \r}
333       \r}
334     \r
335     else
336       \r {
337       \rsnprintf(file_pos, 256, "%s:%d", fstream->name, line_num);
338       \rfstream_lex_line(fstream, context, mutex, file_pos, line);
339       \r}
340     \r}
341   \r\r
342       /* Check that last command of the file ran well */ \r
343       if (context->command_line)
344     \r {
345     \r
346 #ifdef _XBT_WIN32\r
347         if (!context->is_not_found)
348       \r {
349       \r
350 #endif  /* \r */
351           \rif (fstream_launch_command(fstream, context, mutex) < 0)
352         \rreturn -1;
353       \r\r
354 #ifdef _XBT_WIN32\r
355       }
356     \r
357 #endif  /* \r */
358     }
359   \r\r
360       /* clear buffers */ \r
361       if (line)
362     \rfree(line);
363   \r\rxbt_strbuff_free(buff);
364   \r\rif (context_free(&context) < 0)
365     \rreturn -1;
366   \r\rreturn (exit_code || errno) ? -1 : 0;
367 \r}
368
369 \r\r\rvoid \r
370 fstream_lex_line(fstream_t fstream, context_t context,
371                  xbt_os_mutex_t mutex, const char *filepos, char *line) \r
372 {
373   \rchar *line2;
374   \rvariable_t variable;
375   \runsigned int i;
376   \rchar exp[PATH_MAX + 1] = { 0 };
377   \runit_t unit = fstream->unit;
378   \rxbt_dynar_t variables = unit->runner->variables;
379   \rchar *p = NULL;
380   \rchar *end = NULL;
381   \rchar *val = NULL;
382   \rchar buff[PATH_MAX + 1] = { 0 };
383   \rsize_t len;
384   \rchar delimiters[4] = { ' ', '\t', '\n', '\0' };
385   \r\rint j;
386   \r\rif (line[0] == '#')
387     \rreturn;
388   \r\rif (unit->is_running_suite
389         && strncmp(line, "! include", strlen("! include")))
390     \r {                         /* it's the end of a suite */
391     \r\runit_t * current_suite =
392         xbt_dynar_get_ptr(unit->suites,
393                           xbt_dynar_length(unit->suites) - 1);
394     \r\rif (!xbt_dynar_length((*current_suite)->includes))
395       \rERROR2("[%s] Malformated suite `(%s)': include missing", filepos,
396               (*current_suite)->description);
397     \r
398     else
399       \rERROR2("[%s] Malformated suite `(%s)': blank line missing", filepos,
400               (*current_suite)->description);
401     \r\runit_set_error(*current_suite, ESYNTAX, 1, filepos);
402     \r\rfailure(fstream->unit);
403     \r}
404   \r\rcontext->line = strdup(filepos);
405   \r\r
406       /* search end */ \r
407       xbt_str_rtrim(line + 2, "\n");
408   \r\rline2 = strdup(line);
409   \r\rlen = strlen(line2 + 2) + 1;
410   \r\r
411       /* replace each variable by its value */ \r
412       xbt_os_mutex_acquire(unit->mutex);
413   \r\r\r
414       /* replace all existing\r
415          ${var}\r
416          ${var:=val}\r
417          ${var:+val}\r
418          ${var:-val}\r
419          ${var:?val}\r
420          ${#var}\r
421        */ \r
422       \rxbt_dynar_foreach(variables, i, variable) \r {
423     \rif (!(p = strstr(line2 + 2, "${")))
424       \rbreak;
425     \r\rmemset(buff, 0, len);
426     \r\rsprintf(buff, "${%s", variable->name);
427     \r\r
428         /* FALSE */ \r
429         if ((p = strstr(line2 + 2, buff)))
430       \r {
431       \rmemset(buff, 0, len);
432       \rp--;
433       \rj = 0;
434       \r\rwhile (*(p++) != '\0')
435         \r {
436         \rbuff[j++] = *p;
437         \r\rif (*p == '}')
438           \rbreak;
439         \r}
440       \r\rif (buff[j - 1] != '}')
441         \r {
442         \rxbt_os_mutex_release(unit->mutex);
443         \r\r\rERROR2("[%s] Syntax error : `%s'.", filepos, p - j);
444         \r\runit_set_error(fstream->unit, ESYNTAX, 1, filepos);
445         \rfailure(fstream->unit);
446         \rreturn;
447         \r}
448       \r\rif ((p = strstr(buff, ":=")))
449         \r {
450         \r
451             /* ${var:=val} */ \r
452             \r
453             /* if the value of the variable is empty, update its value by the value */ \r
454             p += 2;
455         \r\rend = strchr(p, '}');
456         \r\rif (!end || (end == p))
457           \r {
458           \rxbt_os_mutex_release(unit->mutex);
459           \r\r\rERROR2("[%s] Bad substitution : `%s'.", filepos,
460                     strstr(buff, "${"));
461           \r\runit_set_error(fstream->unit, ESYNTAX, 1, filepos);
462           \rfailure(fstream->unit);
463           \rreturn;
464           \r}
465         \r\rval = (char *) calloc((size_t) (end - p) + 1, sizeof(char));
466         \r\rstrncpy(val, p, (end - p));
467         \r\r\r
468             /* replace the expression by the expression of the value of the variable */ \r
469             sprintf(exp, "${%s:=%s}", variable->name, val);
470         \r\rif (variable->val)
471           \rstr_replace_all(&line2, exp, variable->val, NULL);
472         \r
473         else
474           \r {
475           \rstr_replace_all(&line2, exp, val, NULL);
476           \r\rvariable->val = strdup(val);
477           \r}
478         \r\rmemset(exp, 0, VAR_NAME_MAX + 1);
479         \r\rif (val)
480           \r {
481           \rfree(val);
482           \rval = NULL;
483           \r}
484         \r\r}
485       \r
486       else if ((p = strstr(buff, ":-")))
487         \r {
488         \r
489             /* ${var:-val} */ \r
490             \r
491             /* if the value of the variable is empty, replace the expression by the value */ \r
492             p += 2;
493         \rend = strchr(p, '}');
494         \r\rif (!end || (end == p))
495           \r {
496           \rxbt_os_mutex_release(unit->mutex);
497           \r\rERROR2("[%s] Bad substitution : `%s'.", filepos,
498                    strstr(line2, "${"));
499           \r\runit_set_error(fstream->unit, ESYNTAX, 1, filepos);
500           \rfailure(fstream->unit);
501           \rreturn;
502           \r}
503         \r\rval = (char *) calloc((size_t) (end - p) + 1, sizeof(char));
504         \r\rstrncpy(val, p, (end - p));
505         \r\rsprintf(exp, "${%s:-%s}", variable->name, val);
506         \r\rstr_replace_all(&line2, exp, variable->val ? variable->val : val,
507                           NULL);
508         \r\r\rmemset(exp, 0, VAR_NAME_MAX + 1);
509         \r\rif (val)
510           \r {
511           \rfree(val);
512           \rval = NULL;
513           \r}
514         \r\r}
515       \r
516       else if ((p = strstr(buff, ":+")))
517         \r {
518         \r
519             /* ${var:+val} */ \r
520             \r
521             /* if the value of the variable is not empty, replace the expression by the value */ \r
522             p += 2;
523         \r\rend = strchr(p, '}');
524         \r\rif (!end || (end == p))
525           \r {
526           \rxbt_os_mutex_release(unit->mutex);
527           \r\r\rERROR2("[%s] Bad substitution : `%s'.", filepos,
528                     strstr(line2, "${"));
529           \r\runit_set_error(fstream->unit, ESYNTAX, 1, filepos);
530           \rfailure(fstream->unit);
531           \rreturn;
532           \r}
533         \r\rval = (char *) calloc((size_t) (end - p) + 1, sizeof(char));
534         \r\rstrncpy(val, p, (end - p));
535         \r\rsprintf(exp, "${%s:+%s}", variable->name, val);
536         \r\rif (variable->val)
537           \r {
538           \rstr_replace_all(&line2, exp, val, NULL);
539           \r}
540         \r
541         else
542           \r {
543           \rstr_replace_all(&line2, exp, NULL, NULL);
544           \rvariable->val = strdup(val);
545           \r}
546         \r\rmemset(exp, 0, VAR_NAME_MAX + 1);
547         \r\rif (val)
548           \r {
549           \rfree(val);
550           \rval = NULL;
551           \r}
552         \r}
553       \r
554       else if ((p = strstr(buff, ":?")))
555         \r {
556         \r
557             /*  ${var:?val} */ \r
558             \r
559             /* if the value of the variable is not empty, replace the expression by the value */ \r
560             p += 2;
561         \rend = strchr(p, '}');
562         \r\rif (!end || (end == p))
563           \r {
564           \rxbt_os_mutex_release(unit->mutex);
565           \r\rERROR2("[%s] Bad substitution : `%s'.", filepos,
566                    strstr(line2, "${"));
567           \r\runit_set_error(fstream->unit, ESYNTAX, 1, filepos);
568           \rfailure(fstream->unit);
569           \rreturn;
570           \r}
571         \r\rval = (char *) calloc((size_t) (end - p) + 1, sizeof(char));
572         \r\rstrncpy(val, p, (end - p));
573         \r\rsprintf(exp, "${%s:?%s}", variable->name, val);
574         \r\rif (variable->val)
575           \rstr_replace_all(&line2, exp, variable->val, NULL);
576         \r
577         else
578           \r {
579           \r\rxbt_os_mutex_release(unit->mutex);
580           \r\rERROR2("[%s] %s.", filepos, val);
581           \r\runit_set_error(fstream->unit, ESYNTAX, 1, filepos);
582           \rfailure(fstream->unit);
583           \rreturn;
584           \r}
585         \r\rmemset(exp, 0, VAR_NAME_MAX + 1);
586         \r\rif (val)
587           \r {
588           \rfree(val);
589           \rval = NULL;
590           \r}
591         \r}
592       \r}
593   \r}
594   \r\r
595       /* replace all existing $var */ \r
596       xbt_dynar_foreach(variables, i, variable) \r {
597     \rif (!strchr(line2 + 2, '$'))
598       \rbreak;
599     \r\rif (strstr(line2 + 2, variable->name))
600       \r {
601       \r\rsprintf(exp, "${#%s}", variable->name);
602       \r\rif (strstr(line2 + 2, exp))
603         \r {
604         \r\rif (variable->val)
605           \r {
606           \rchar slen[4] = { 0 };
607           \rsprintf(slen, "%d", (int) strlen(variable->val));
608           \rstr_replace_all(&line2, exp, slen, NULL);
609           \r}
610         \r
611         else
612           \rstr_replace_all(&line2, exp, "0", NULL);
613         \r}
614       \r\rmemset(exp, 0, VAR_NAME_MAX + 1);
615       \r\rsprintf(exp, "${%s}", variable->name);
616       \r\rif (strstr(line2 + 2, exp))
617         \r {
618         \rif (variable->val)
619           \rstr_replace_all(&line2, exp, variable->val, NULL);
620         \r
621         else
622           \rstr_replace_all(&line2, exp, NULL, NULL);
623         \r}
624       \r\rmemset(exp, 0, VAR_NAME_MAX + 1);
625       \r\rsprintf(exp, "$%s", variable->name);
626       \r\rif ((p = strstr(line2 + 2, exp)))
627         \r {
628         \rif ((p + strlen(variable->name) + 1)[0] != '\0'
629              && !(isalpha((p + strlen(variable->name) + 1)[0])))
630           \rdelimiters[0] = (p + strlen(variable->name) + 1)[0];
631         \r\rif (variable->val)
632           \rstr_replace_all(&line2, exp, variable->val, delimiters);
633         \r
634         else
635           \rstr_replace_all(&line2, exp, NULL, delimiters);
636         \r}
637       \r\rmemset(exp, 0, VAR_NAME_MAX + 1);
638       \r\r}
639   \r}
640   \r\rwhile ((p = strstr(line2 + 2, "${")))
641     \r {
642     \r
643         /*if(*(p+1) != '{')\r
644            {\r
645            j = 0;\r
646            p --;\r
647            \r
648            while(*(p++) != '\0')\r
649            {\r
650            if(*p != ' ' && *p !='\t')\r
651            exp[j++] = *p;\r
652            else\r
653            break;\r
654            \r
655            }\r
656            \r
657            str_replace_all(&line2, exp, NULL, " \t\n\r");\r
658            memset(exp, 0, VAR_NAME_MAX + 1);\r
659            }.\r
660            else\r
661          */ \r
662     {
663       \rchar *begin = NULL;
664       \r\rj = 0;
665       \rp--;
666       \r\rwhile (*(p++) != '\0')
667         \r {
668         \rif ((!begin && *p != ' ' && *p != '\t') || begin)
669           \r {
670           \r
671               /* `:' must be before this caracter, bad substitution : exit loop \r
672                  ||\r
673                  the current character is already present, bad substitution : exit loop\r
674                */ \r
675               if (\r
676                   (\r*(p - 1) != ':' && (\r
677                                         (*p == '=') || (*p == '-')
678                                         || (*p == '+')
679                                         || (*p == '?') \r\r\r ||\r(\rbegin
680                                                                    &&
681                                                                    (\r
682                                                                     (*p ==
683                                                                      ':')
684                                                                     || (*p
685                                                                         ==
686                                                                         '=')
687                                                                     || (*p
688                                                                         ==
689                                                                         '-')
690                                                                     || (*p
691                                                                         ==
692                                                                         '+')
693                                                                     || (*p
694                                                                         ==
695                                                                         '?')
696                                                                     \r\r)
697                   \r)
698             \rbreak;
699           \r
700           else
701             \rexp[j++] = *p;
702           \r\rif (*p == ':')
703             \r {
704             \r
705                 /* save the begining of the value */ \r
706                 if ((*(p + 1) == '=') || (*(p + 1) == '-')
707                     || (*(p + 1) == '+') || (*(p + 1) == '?'))
708               \r {
709               \rbegin = p + 2;
710               \rexp[j++] = *(p + 1);
711               \rp++;
712               \rcontinue;
713               \r\r}
714             \r
715             else
716               \r
717                   /* the current char is `:' but the next is invalid, bad substitution : exit loop */ \r
718                   break;
719             \r}
720           \r
721               /* end of the substitution : exit loop */ \r
722               else if (*p == '}')
723             \rbreak;
724           \r}
725         \r
726         else
727           \rbreak;
728         \r}
729       \r\rif (exp[j - 1] == '}')
730         \r {
731         \rif (exp[2] == '#')
732           \r {
733           \r
734               /* ${#var} */ \r
735               \r\rif (4 == strlen(exp))
736             \r {
737             \rxbt_os_mutex_release(unit->mutex);
738             \r\rERROR2("[%s] Bad substitution : `%s'.", filepos,
739                      strchr(line2 + 2, '$'));
740             \r\runit_set_error(fstream->unit, ESYNTAX, 1, filepos);
741             \rfailure(fstream->unit);
742             \rreturn;
743             \r}
744           \r\rstr_replace_all(&line2, exp, "0", NULL);
745           \r}
746         \r
747         else if (strstr(exp, ":="))
748           \r {
749           \r
750               /* ${var:=value} */ \r
751               \rend = strchr(p, '}');
752           \r\rif (!end || (end == begin))
753             \r {
754             \rxbt_os_mutex_release(unit->mutex);
755             \r\r\rERROR2("[%s] Bad substitution : `%s'.", filepos,
756                       strchr(line2 + 2, '$'));
757             \r\runit_set_error(fstream->unit, ESYNTAX, 1, filepos);
758             \rfailure(fstream->unit);
759             \rreturn;
760             \r}
761           \r\rvariable = xbt_new0(s_variable_t, 1);
762           \r\rvariable->val =
763               (char *) calloc((size_t) (end - begin) + 1, sizeof(char));
764           \r\rstrncpy(variable->val, begin, (end - begin));
765           \r\rbegin = exp + 2;
766           \rend = strchr(exp, ':');
767           \r\rif (!end || (end == begin))
768             \r {
769             \rxbt_os_mutex_release(unit->mutex);
770             \r\r\rERROR2("[%s] Bad substitution : `%s'.", filepos,
771                       strchr(line2 + 2, '$'));
772             \r\runit_set_error(fstream->unit, ESYNTAX, 1, filepos);
773             \rfailure(fstream->unit);
774             \rreturn;
775             \r}
776           \r\rvariable->name =
777               (char *) calloc((size_t) (end - begin) + 1, sizeof(char));
778           \r\rstrncpy(variable->name, exp + 2, (end - begin));
779           \r\rstr_replace_all(&line2, exp, variable->val, NULL);
780           \r\rxbt_dynar_push(variables, &variable);
781           \r\r}
782         \r
783         else if (strstr(exp, ":-"))
784           \r {
785           \r
786               /* ${var:-value} */ \r
787               \r\rend = strchr(p, '}');
788           \r\rif (!end || (end == begin))
789             \r {
790             \rxbt_os_mutex_release(unit->mutex);
791             \r\r\rERROR2("[%s] Bad substitution : `%s'.", filepos,
792                       strchr(line2 + 2, '$'));
793             \r\runit_set_error(fstream->unit, ESYNTAX, 1, filepos);
794             \rfailure(fstream->unit);
795             \rreturn;
796             \r}
797           \r\rval =
798               (char *) calloc((size_t) (end - begin) + 1, sizeof(char));
799           \r\rstrncpy(val, begin, (end - begin));
800           \r\rstr_replace_all(&line2, exp, val, NULL);
801           \r\rif (val)
802             \rfree(val);
803           \r\r}
804         \r
805         else if (strstr(exp, ":+"))
806           \r {
807           \r
808               /* ${var:+value} */ \r
809               \rend = strchr(p, '}');
810           \r\rif (!end || (end == begin))
811             \r {
812             \rxbt_os_mutex_release(unit->mutex);
813             \r\rERROR2("[%s] Bad substitution : `%s'.", filepos,
814                      strchr(line2 + 2, '$'));
815             \r\runit_set_error(fstream->unit, ESYNTAX, 1, filepos);
816             \rfailure(fstream->unit);
817             \rreturn;
818             \r}
819           \r\rstr_replace_all(&line2, exp, NULL, NULL);
820           \r}
821         \r
822         else if (strstr(exp, ":?"))
823           \r {
824           \r
825               /* ${var:?value} */ \r
826               \rend = strchr(p, '}');
827           \r\rif (!end || (end == begin))
828             \r {
829             \rxbt_os_mutex_release(unit->mutex);
830             \r\rERROR2("[%s] Bad substitution : `%s'.", filepos,
831                      strchr(line2 + 2, '$'));
832             \r\runit_set_error(fstream->unit, ESYNTAX, 1, filepos);
833             \rfailure(fstream->unit);
834             \rreturn;
835             \r}
836           \r\rval =
837               (char *) calloc((size_t) (end - begin) + 1, sizeof(char));
838           \r\rstrncpy(val, begin, (end - begin));
839           \r\rxbt_os_mutex_release(unit->mutex);
840           \r\rERROR2("[%s] : `%s'.", filepos, val);
841           \r\rif (val)
842             \rfree(val);
843           \r\runit_set_error(fstream->unit, ESYNTAX, 1, filepos);
844           \rfailure(fstream->unit);
845           \r\rreturn;
846           \r\r}
847         \r
848         else
849           \r {
850           \r
851               /* ${var} */ \r
852               \rif (3 == strlen(exp))
853             \r {
854             \rxbt_os_mutex_release(unit->mutex);
855             \r\rERROR2("[%s] Bad substitution : `%s'.", filepos,
856                      strchr(line2 + 2, '$'));
857             \r\runit_set_error(fstream->unit, ESYNTAX, 1, filepos);
858             \rfailure(fstream->unit);
859             \rreturn;
860             \r}
861           \r\rstr_replace_all(&line2, exp, NULL, NULL);
862           \r\r}
863         \r\rmemset(exp, 0, VAR_NAME_MAX + 1);
864         \r}
865       \r
866       else
867         \r {
868         \rxbt_os_mutex_release(unit->mutex);
869         \r\rif (strstr(line2 + 2, "${"))
870           \rERROR2("[%s] Bad substitution : `%s'.", filepos,
871                   strstr(line2, "${"));
872         \r
873         else
874           \rERROR2("[%s] Syntax error : `%s'.", filepos,
875                   strstr(line2, "${"));
876         \r\runit_set_error(fstream->unit, ESYNTAX, 1, filepos);
877         \rfailure(fstream->unit);
878         \rreturn;
879         \r}
880     \r\r}
881     \r\r}
882   \r\rwhile (1)
883     \r {
884     \rp = line2 + (line2[0] == '<' ? 4 : 2);
885     \r\rif ((p = strchr(p, '$')))
886       \r {
887       \rif (*(p + 1) != ' ')
888         \r {
889         \rj = 0;
890         \rp--;
891         \r\rwhile (*(p++) != '\0')
892           \r {
893           \rif (*p != ' ' && *p != '\t')
894             \rexp[j++] = *p;
895           \r
896           else
897             \rbreak;
898           \r\r}
899         \r\rstr_replace_all(&line2, exp, NULL, " \t\n\r");
900         \rmemset(exp, 0, VAR_NAME_MAX + 1);
901         \r}
902       \r
903       else
904         \r {
905         \r
906             /* maybe < $ cmd */ \r
907             p++;
908         \r}
909       \r}
910     \r
911     else
912       \rbreak;
913     \r}
914   \r\rxbt_os_mutex_release(unit->mutex);
915   \r\rswitch (line2[0])
916     \r {
917     \r
918         /*case '#': \r
919            break;\r
920          */ \r
921   \rcase '$':
922   \rcase '&':
923     \r\rif (line[1] != ' ')
924       \r {
925       \r\rif (line2[0] == '$')
926         \rERROR1("[%s] Missing space after `$' `(usage : $ <command>)'",
927                 filepos);
928       \r
929       else
930         \rERROR1("[%s] Missing space after & `(usage : & <command>)'",
931                 filepos);
932       \r\runit_set_error(fstream->unit, ESYNTAX, 1, filepos);
933       \r\rfailure(unit);
934       \rreturn;
935       \r}
936     \r\rcontext->async = (line2[0] == '&');
937     \r\r\r
938         /* further trim useless chars which are significant for in/output */ \r
939         xbt_str_rtrim(line2 + 2, " \t");
940     \r\r
941         /* deal with CD commands here, not in context */ \r
942         if (!strncmp("cd ", line2 + 2, 3))
943       \r {
944       \rchar *dir = strdup(line2 + 4);
945       \r\rif (context->command_line)
946         \r {
947         \rif (fstream_launch_command(fstream, context, mutex) < 0)
948           \rreturn;
949         \r}
950       \r\r
951           /* search begining */ \r
952           while (*(dir++) == ' ');
953       \r\rdir--;
954       \r\rif (!dry_run_flag)
955         \r {
956         \rif (!silent_flag)
957           \rINFO2("[%s] cd %s", filepos, dir);
958         \r\rif (!just_print_flag)
959           \r {
960           \rif (chdir(dir))
961             \r {
962             \rERROR3("[%s] Chdir to %s failed: %s", filepos, dir,
963                     error_to_string(errno, 0));
964             \runit_set_error(fstream->unit, errno, 0, filepos);
965             \r\rfailure(unit);
966             \r}
967           \r}
968         \r}
969       \r\rbreak;
970       \r}
971     \r
972     else
973       \r {
974       \rfstream_process_token(fstream, context, mutex, filepos, line2[0],
975                              line2 + 2);
976       \rbreak;
977       \r}
978   \r\rcase '<':
979   \rcase '>':
980   \rcase '!':
981     \r\rif (line[0] == '!' && line[1] != ' ')
982       \r {
983       \rERROR1
984           ("[%s] Missing space after `!' `(usage : ! <command> [[=]value])'",
985            filepos);
986       \r\runit_set_error(fstream->unit, ESYNTAX, 1, filepos);
987       \r\rfailure(unit);
988       \rreturn;
989       \r}
990     \r\rfstream_process_token(fstream, context, mutex, filepos, line2[0],
991                             line2 + 2);
992     \rbreak;
993   \r\rcase 'p':
994     \r\r {
995       \runsigned int j;
996       \rint is_blank = 1;
997       \r\rchar *prompt = line2 + 2;
998       \r\rfor (j = 0; j < strlen(prompt); j++)
999         \r {
1000         \rif (prompt[j] != ' ' && prompt[j] != '\t')
1001           \r {
1002           \ris_blank = 0;
1003           \rbreak;
1004           \r}
1005         \r}
1006       \r\rif (is_blank)
1007         \r {
1008         \rERROR1
1009             ("[%s] Bad usage of the metacommand p `(usage : p <prompt>)'",
1010              filepos);
1011         \r\runit_set_error(fstream->unit, ESYNTAX, 1, filepos);
1012         \r\rfailure(unit);
1013         \rreturn;
1014         \r}
1015       \r\rif (!dry_run_flag)
1016         \rINFO2("[%s] %s", filepos, prompt);
1017     \r}
1018     \r\r\rbreak;
1019   \r\rcase 'P':
1020     \r\r {
1021       \runsigned int j;
1022       \rint is_blank = 1;
1023       \r\rchar *prompt = line2 + 2;
1024       \r\rfor (j = 0; j < strlen(prompt); j++)
1025         \rif (prompt[j] != ' ' && prompt[j] != '\t')
1026           \ris_blank = 0;
1027       \r\rif (is_blank)
1028         \r {
1029         \rERROR1
1030             ("[%s] Bad usage of the metacommand P `(usage : P <prompt>)'",
1031              filepos);
1032         \r\runit_set_error(fstream->unit, ESYNTAX, 1, filepos);
1033         \r\rfailure(unit);
1034         \rreturn;
1035         \r}
1036       \r\rif (!dry_run_flag)
1037         \rCRITICAL2("[%s] %s", filepos, prompt);
1038     \r}
1039     \r\rbreak;
1040   \r\rcase 'D':
1041     \rif (unit->description)
1042       \rWARN2("[%s] Description already specified `%s'", filepos,
1043              line2 + 2);
1044     \r
1045     else
1046       \r {
1047       \runsigned int j;
1048       \rint is_blank = 1;
1049       \r\rchar *desc = line2 + 2;
1050       \r\rfor (j = 0; j < strlen(desc); j++)
1051         \rif (desc[j] != ' ' && desc[j] != '\t')
1052           \ris_blank = 0;
1053       \r\rif (is_blank)
1054         \r {
1055         \rERROR1
1056             ("[%s] Bad usage of the metacommand D `(usage : D <Description>)'",
1057              filepos);
1058         \r\runit_set_error(fstream->unit, ESYNTAX, 1, filepos);
1059         \r\rfailure(unit);
1060         \rreturn;
1061         \r}
1062       \r\runit->description = strdup(desc);
1063       \r}
1064     \rbreak;
1065   \r\rdefault:
1066     \rERROR2("[%s] Syntax error `%s'", filepos, line2);
1067     \runit_set_error(fstream->unit, ESYNTAX, 1, filepos);
1068     \rfailure(unit);
1069     \rbreak;
1070     \r}
1071   \r\rfree(line2);
1072 \r}
1073
1074 \r\rvoid \r
1075 fstream_process_token(fstream_t fstream, context_t context,
1076                       xbt_os_mutex_t mutex, const char *filepos,
1077                       char token, char *line) \r
1078 {
1079   \runit_t unit = fstream->unit;
1080   \r\rswitch (token)
1081     \r {
1082   \rcase '$':
1083   \rcase '&':
1084     \r\rif (context->command_line)
1085       \r {
1086       \r\rif (context->output->used || context->input->used)
1087         \r {
1088         \rERROR2
1089             ("[%s] More than one command in this chunk of lines (previous: %s).\nDunno which input/output belongs to which command.",
1090              filepos, context->command_line);
1091         \r\runit_set_error(fstream->unit, ESYNTAX, 1, filepos);
1092         \rfailure(unit);
1093         \rreturn;
1094         \r}
1095       \r\rif (fstream_launch_command(fstream, context, mutex) < 0)
1096         \rreturn;
1097       \r\rVERB1("[%s] More than one command in this chunk of lines",
1098               filepos);
1099       \r}
1100     \r\r {
1101       \rsize_t j, \ris_blank = 1;
1102       \r\rfor (j = 0; j < strlen(line); j++)
1103         \rif (line[j] != ' ' && line[j] != '\t')
1104           \ris_blank = 0;
1105       \r\rif (is_blank)
1106         \r {
1107         \rif (token == '$')
1108           \rERROR1("[%s] Undefinite command for `$' `(usage: $ <command>)'",
1109                   filepos);
1110         \r
1111         else
1112           \rERROR1("[%s] Undefinite command for `&' `(usage: & <command>)'",
1113                   filepos);
1114         \r\runit_set_error(fstream->unit, ESYNTAX, 1, filepos);
1115         \r\rfailure(unit);
1116         \rreturn;
1117         \r}
1118     \r}
1119     \r\rcontext->command_line = strdup(line);
1120     \r\rxbt_str_ltrim(context->command_line, " ");
1121     \r\rcontext->line = /*strdup(filepos) */ filepos;
1122     \rcontext->pos = strdup(filepos);
1123     \r\r
1124 #ifdef _XBT_WIN32\r
1125     {
1126       \r\r
1127           /* translate the command line */ \r
1128       \rchar *path = NULL;
1129       \rchar *delimiter;
1130       \rchar command_line[PATH_MAX + 1] = { 0 };
1131       \rsize_t i = 0;
1132       \rchar *args = NULL;
1133       \r\r\r\r
1134           /*if(strstr(context->command_line,".exe"))\r
1135              strcpy(command_line,context->command_line); */ \r
1136           \r {
1137         \rsize_t len;
1138         \r\rsize_t j = 0;
1139         \r\rlen = strlen(context->command_line);
1140         \r\rwhile (i < len)
1141           \r {
1142           \rif (context->command_line[i] != ' '
1143                && context->command_line[i] != '\t'
1144                && context->command_line[i] != '>')
1145             \rcommand_line[j++] = context->command_line[i];
1146           \r
1147           else
1148             \rbreak;
1149           \r\ri++;
1150           \r}
1151         \r\rif (!strstr(context->command_line, ".exe"))
1152           \rstrcat(command_line, ".exe");
1153         \r\rargs = strdup(context->command_line + i);
1154       \r}
1155       \r\rif (!is_w32_cmd(command_line, fstream->unit->runner->path)
1156             && getpath(command_line, &path) < 0)
1157         \r {
1158         \rcommand_t command;
1159         \r\rERROR3("[%s] `%s' : NOK (%s)", filepos, command_line,
1160                  error_to_string(ECMDNOTFOUND, 1));
1161         \runit_set_error(fstream->unit, ECMDNOTFOUND, 1, filepos);
1162         \r\rcontext->is_not_found = 1;
1163         \r\rcommand = command_new(fstream->unit, context, mutex);
1164         \r\rcommand->status = cs_failed;
1165         \rcommand->reason = csr_command_not_found;
1166         \r\rfailure(unit);
1167         \r\r\rreturn;
1168         \r}
1169       \r\rdelimiter = strrchr(command_line, '/');
1170       \r\rif (!delimiter)
1171         \rdelimiter = strrchr(command_line, '\\');
1172       \r\r
1173           /*free(context->command_line); */ \r
1174           \r\rif (path)
1175         \r {
1176         \rif (args)
1177           \r {
1178           \rcontext->t_command_line =
1179               (char *) calloc(strlen(path) +
1180                               strlen(delimiter ? delimiter +
1181                                      1 : command_line) + strlen(args) + 2,
1182                               sizeof(char));
1183           \rsprintf(context->t_command_line, "%s\\%s%s", path,
1184                    delimiter ? delimiter + 1 : command_line, args);
1185           \r\rfree(args);
1186           \r\r}
1187         \r
1188         else
1189           \r {
1190           \rcontext->t_command_line =
1191               (char *) calloc(strlen(path) +
1192                               strlen(delimiter ? delimiter +
1193                                      1 : command_line) + 2, sizeof(char));
1194           \rsprintf(context->t_command_line, "%s\\%s", path,
1195                    delimiter ? delimiter + 1 : command_line);
1196           \r\r\rfree(path);
1197         \r}
1198       \r
1199       else
1200         \r {
1201         \rif (args)
1202           \r {
1203           \r\rcontext->t_command_line =
1204               (char *) calloc(strlen(command_line) + strlen(args) + 1,
1205                               sizeof(char));
1206           \rsprintf(context->t_command_line, "%s%s", command_line, args);
1207           \r\r\rfree(args);
1208           \r\r}
1209         \r
1210         else
1211           \r {
1212           \rcontext->t_command_line =
1213               (char *) calloc(strlen(command_line) + 1, sizeof(char));
1214           \rstrcpy(context->t_command_line, command_line);
1215     \r\r\r\r\r\r
1216 #endif  /* \r */
1217         \r\rbreak;
1218   \r\rcase '<':
1219     \rxbt_strbuff_append(context->input, line);
1220     \rxbt_strbuff_append(context->input, "\n");
1221     \rbreak;
1222   \r\rcase '>':
1223     \rxbt_strbuff_append(context->output, line);
1224     \rxbt_strbuff_append(context->output, "\n");
1225     \rbreak;
1226   \r\rcase '!':
1227     \r\rif (context->command_line)
1228       \r {
1229       \rif (fstream_launch_command(fstream, context, mutex) < 0)
1230         \rreturn;
1231       \r}
1232     \r\rif (!strncmp(line, "timeout no", strlen("timeout no")))
1233       \r {
1234       \rVERB1("[%s] (disable timeout)", filepos);
1235       \rcontext->timeout = INDEFINITE;
1236       \r}
1237     \r
1238     else if (!strncmp(line, "timeout ", strlen("timeout ")))
1239       \r {
1240       \rint i = 0;
1241       \runsigned int j;
1242       \rint is_blank = 1;
1243       \rchar *p = line + strlen("timeout ");
1244       \r\r\rfor (j = 0; j < strlen(p); j++)
1245         \rif (p[j] != ' ' && p[j] != '\t')
1246           \ris_blank = 0;
1247       \r\rif (is_blank)
1248         \r {
1249         \rERROR1
1250             ("[%s] Undefinite timeout value `(usage :timeout <seconds>)'",
1251              filepos);
1252         \r\runit_set_error(fstream->unit, ESYNTAX, 1, filepos);
1253         \r\rfailure(unit);
1254         \rreturn;
1255         \r}
1256       \r\rwhile (p[i] != '\0')
1257         \r {
1258         \rif (!isdigit(p[i]))
1259           \r {
1260           \rERROR2
1261               ("[%s] Invalid timeout value `(%s)' : `(usage :timeout <seconds>)'",
1262                filepos, line + strlen("timeout "));
1263           \r\runit_set_error(fstream->unit, ESYNTAX, 1, filepos);
1264           \r\rfailure(unit);
1265           \rreturn;
1266           \r}
1267         \r\ri++;
1268         \r}
1269       \r\rcontext->timeout = atoi(line + strlen("timeout"));
1270       \rVERB2("[%s] (new timeout value: %d)", filepos, context->timeout);
1271       \r\r}
1272     \r
1273     else if (!strncmp(line, "expect signal ", strlen("expect signal ")))
1274       \r {
1275       \runsigned int j;
1276       \rint is_blank = 1;
1277       \r\r\rchar *p = line + strlen("expect signal ");
1278       \r\r\rfor (j = 0; j < strlen(p); j++)
1279         \rif (p[j] != ' ' && p[j] != '\t')
1280           \ris_blank = 0;
1281       \r\rif (is_blank)
1282         \r {
1283         \rERROR1
1284             ("[%s] Undefinite signal name `(usage :expect signal <signal name>)'",
1285              filepos);
1286         \r\runit_set_error(fstream->unit, ESYNTAX, 1, filepos);
1287         \r\rfailure(unit);
1288         \rreturn;
1289         \r}
1290       \r\rcontext->signal = strdup(line + strlen("expect signal "));
1291       \r\rxbt_str_trim(context->signal, " \n");
1292       \r\r
1293 #ifdef _XBT_WIN32\r
1294           if (!strstr("SIGSEGVSIGTRAPSIGBUSSIGFPESIGILL", context->signal))
1295         \r {
1296         \rERROR2("[%s] Signal `%s' not supported by this platform", filepos,
1297                 context->signal);
1298         \r\runit_set_error(fstream->unit, ESYNTAX, 1, filepos);
1299         \r\r\rfailure(unit);
1300         \rreturn;
1301         \r}
1302       \r
1303 #else   /* \r */
1304           if (!sig_exists(context->signal))
1305         \r {
1306         \rERROR2("[%s] Signal `%s' not supported by Tesh", filepos,
1307                 context->signal);
1308         \r\runit_set_error(fstream->unit, ESYNTAX, 1, filepos);
1309         \r\r\rfailure(unit);
1310         \rreturn;
1311         \r}
1312       \r\r
1313 #endif  /* \r */
1314           \r\rVERB2("[%s] (next command must raise signal %s)", filepos,
1315                   context->signal);
1316       \r\r}
1317     \r
1318     else if (!strncmp(line, "expect return ", strlen("expect return ")))
1319       \r {
1320       \r\rint i = 0;
1321       \runsigned int j;
1322       \rint is_blank = 1;
1323       \rchar *p = line + strlen("expect return ");
1324       \r\r\rfor (j = 0; j < strlen(p); j++)
1325         \rif (p[j] != ' ' && p[j] != '\t')
1326           \ris_blank = 0;
1327       \r\rif (is_blank)
1328         \r {
1329         \rERROR1
1330             ("[%s] Undefinite return value `(usage :expect return <return value>)'",
1331              filepos);
1332         \r\runit_set_error(fstream->unit, ESYNTAX, 1, filepos);
1333         \r\rfailure(unit);
1334         \rreturn;
1335         \r}
1336       \r\rwhile (p[i] != '\0')
1337         \r {
1338         \rif (!isdigit(p[i]))
1339           \r {
1340           \rERROR2
1341               ("[%s] Invalid exit code value `(%s)' : must be an integer >= 0 and <=255",
1342                filepos, line + strlen("expect return "));
1343           \r\runit_set_error(fstream->unit, ESYNTAX, 1, filepos);
1344           \r\rfailure(unit);
1345           \rreturn;
1346           \r}
1347         \r\ri++;
1348         \r}
1349       \r\rcontext->exit_code = atoi(line + strlen("expect return "));
1350       \rVERB2("[%s] (next command must return code %d)", filepos,
1351              context->exit_code);
1352       \r\r}
1353     \r
1354     else if (!strncmp(line, "output ignore", strlen("output ignore")))
1355       \r {
1356       \rcontext->output_handling = oh_ignore;
1357       \rVERB1("[%s] (ignore output of next command)", filepos);
1358       \r\r}
1359     \r
1360     else if (!strncmp(line, "output display", strlen("output display")))
1361       \r {
1362       \rcontext->output_handling = oh_display;
1363       \rVERB1("[%s] (ignore output of next command)", filepos);
1364       \r\r}
1365     \r
1366     else if (!strncmp(line, "include ", strlen("include ")))
1367       \r {
1368       \rchar *p1;
1369       \rchar *p2;
1370       \r\rp1 = line + strlen("include");
1371       \r\rwhile (*p1 == ' ' || *p1 == '\t')
1372         \rp1++;
1373       \r\r\rif (p1[0] == '\0')
1374         \r {
1375         \rERROR1
1376             ("[%s] no file specified : `(usage : include <file> [<description>])'",
1377              filepos);
1378         \r\runit_set_error(fstream->unit, ESYNTAX, 1, filepos);
1379         \r\rfailure(unit);
1380         \rreturn;
1381         \r}
1382       \r
1383       else
1384         \r {
1385         \rchar file_name[PATH_MAX + 1] = { 0 };
1386         \r\rp2 = p1;
1387         \r\rwhile (*p2 != '\0' && *p2 != ' ' && *p2 != '\t')
1388           \rp2++;
1389         \r\rstrncpy(file_name, p1, p2 - p1);
1390         \r\r\rif (p2[0] != '\0')
1391           \rwhile (*p2 == ' ' || *p2 == '\t')
1392             \rp2++;
1393         \r\rfstream_handle_include(fstream, context, mutex, file_name,
1394                                  p2[0] != '\0' ? p2 : NULL);
1395         \r\r}
1396       \r}
1397     \r
1398     else if (!strncmp(line, "suite ", strlen("suite ")))
1399       \r {
1400       \runsigned int j;
1401       \rint is_blank = 1;
1402       \rchar *p = line + strlen("suite ");
1403       \r\r\rfor (j = 0; j < strlen(p); j++)
1404         \rif (p[j] != ' ' && p[j] != '\t')
1405           \ris_blank = 0;
1406       \r\rif (is_blank)
1407         \r {
1408         \rERROR1
1409             ("[%s] Undefinite suit description : `(usage : suite <description>)",
1410              filepos);
1411         \r\runit_set_error(fstream->unit, ESYNTAX, 1, filepos);
1412         \r\rfailure(unit);
1413         \rreturn;
1414         \r}
1415       \r\rif (unit->is_running_suite)
1416         \r {
1417         \rERROR1("[%s] Suite already in progress", filepos);
1418         \r\runit_set_error(fstream->unit, ESYNTAX, 1, filepos);
1419         \r\rfailure(unit);
1420         \rreturn;
1421         \r}
1422       \r\rfstream_handle_suite(fstream, line + strlen("suite "), filepos);
1423       \r}
1424     \r
1425     else if (!strncmp(line, "unsetenv ", strlen("unsetenv ")))
1426       \r {
1427       \runsigned int i, j;
1428       \rint exists = 0;
1429       \rint env = 0;
1430       \rint err = 0;
1431       \rvariable_t variable;
1432       \rint is_blank;
1433       \r\rchar *name = line + strlen("unsetenv ");
1434       \r\ris_blank = 1;
1435       \r\rfor (j = 0; j < strlen(name); j++)
1436         \rif (name[j] != ' ' && name[j] != '\t')
1437           \ris_blank = 0;
1438       \r\rif (is_blank)
1439         \r {
1440         \rERROR1
1441             ("[%s] Bad usage of the metacommand unsetenv : `(usage : unsetenv variable)'",
1442              filepos);
1443         \r\runit_set_error(fstream->unit, ESYNTAX, 1, filepos);
1444         \r\rfailure(unit);
1445         \rreturn;
1446         \r}
1447       \r\rxbt_os_mutex_acquire(unit->mutex);
1448       \r\r\rxbt_dynar_foreach(unit->runner->variables, i, variable) \r {
1449         \rif (!strcmp(variable->name, name))
1450           \r {
1451           \renv = variable->env;
1452           \rerr = variable->err;
1453           \rexists = 1;
1454           \rbreak;
1455           \r}
1456       \r}
1457       \r\rif (env)
1458         \r {
1459         \rif (exists)
1460           \r {
1461           \r
1462 #ifndef _XBT_WIN32\r
1463               unsetenv(name);
1464           \r
1465 #else   /* \r */
1466               SetEnvironmentVariable(name, NULL);
1467           \r
1468 #endif  /* \r */
1469               xbt_dynar_cursor_rm(unit->runner->variables, &i);
1470           \r}
1471         \r
1472         else
1473           \r {
1474           \rERROR2
1475               ("[%s] `(%s)' environment variable not found : impossible to unset it",
1476                filepos, name);
1477           \runit_set_error(fstream->unit, ESYNTAX, 1, filepos);
1478           \rxbt_os_mutex_release(unit->mutex);
1479           \rfailure(unit);
1480           \rreturn;
1481           \r}
1482         \r}
1483       \r
1484       else
1485         \r {
1486         \rif (exists)
1487           \r {
1488           \rif (!err)
1489             \r {
1490             \rERROR2
1491                 ("[%s] `(%s)' is not an environment variable : use `unset' instead `unsetenv'",
1492                  filepos, name);
1493             \runit_set_error(fstream->unit, ESYNTAX, 1, filepos);
1494             \rfailure(unit);
1495             \rxbt_os_mutex_release(unit->mutex);
1496             \rreturn;
1497             \r}
1498           \r
1499           else
1500             \r {
1501             \rERROR2
1502                 ("[%s] `(%s)' is not an environment variable (it's a system variable) : impossible to unset it",
1503                  filepos, name);
1504             \runit_set_error(fstream->unit, ESYNTAX, 1, filepos);
1505             \rxbt_os_mutex_release(unit->mutex);
1506             \rfailure(unit);
1507             \rreturn;
1508             \r}
1509           \r}
1510         \r
1511         else
1512           \r {
1513           \rERROR2
1514               ("[%s] `(%s)' environment variable not found : impossible to unset it",
1515                filepos, name);
1516           \runit_set_error(fstream->unit, ESYNTAX, 1, filepos);
1517           \rxbt_os_mutex_release(unit->mutex);
1518           \rfailure(unit);
1519           \rreturn;
1520           \r}
1521         \r}
1522       \r\rxbt_os_mutex_release(unit->mutex);
1523       \r\r\r}
1524     \r
1525     else if (!strncmp(line, "setenv ", strlen("setenv ")))
1526       \r {
1527       \rchar *val;
1528       \rchar name[PATH_MAX + 1] = { 0 };
1529       \rchar *p;
1530       \runsigned int i;
1531       \rint is_blank;
1532       \runsigned int j;
1533       \r\rp = line + strlen("setenv ");
1534       \r\rval = strchr(p, '=');
1535       \r\rif (val)
1536         \r {
1537         \rvariable_t variable;
1538         \rint exists = 0;
1539         \rint env = 0;
1540         \rint err = 0;
1541         \rval++;
1542         \r\r
1543             /* syntax error */ \r
1544             if (val[0] == '\0' || val[0] == ' ' || val[0] == '\t')
1545           \r {
1546           \rERROR1
1547               ("[%s] Bad usage of the metacommand setenv `(usage : setenv variable=value)'",
1548                filepos);
1549           \r\runit_set_error(fstream->unit, ESYNTAX, 1, filepos);
1550           \r\rfailure(unit);
1551           \rreturn;
1552           \r}
1553         \r\r\r\rstrncpy(name, p, (val - p - 1));
1554         \r\ris_blank = 1;
1555         \r\rfor (j = 0; j < strlen(name); j++)
1556           \rif (name[j] != ' ' && name[j] != '\t')
1557             \ris_blank = 0;
1558         \r\rif (is_blank)
1559           \r {
1560           \r\rERROR1
1561               ("[%s] Bad usage of the metacommand setenv `(usage : setenv variable=value)'",
1562                filepos);
1563           \r\runit_set_error(fstream->unit, ESYNTAX, 1, filepos);
1564           \r\rfailure(unit);
1565           \rreturn;
1566           \r}
1567         \r\r
1568             /* test if the variable is already registred */ \r
1569             xbt_os_mutex_acquire(unit->mutex);
1570         \r\rxbt_dynar_foreach(unit->runner->variables, i, variable) \r {
1571           \rif (!strcmp(variable->name, name))
1572             \r {
1573             \renv = variable->env;
1574             \rerr = variable->err;
1575             \rexists = 1;
1576             \rbreak;
1577             \r}
1578         \r}
1579         \r\r
1580             /* if the variable is already registred, update its value;\r
1581              * otherwise register it.\r
1582              */ \r
1583             if (exists)
1584           \r {
1585           \rif (env)
1586             \r {
1587             \rif (!strcmp(val, variable->val))
1588               \rWARN3
1589                   ("[%s] This environment variable `(%s)' is already set with the value `(%s)'",
1590                    filepos, name, val);
1591             \r\rfree(variable->val);
1592             \rvariable->val = strdup(val);
1593             \r\r
1594 #ifdef _XBT_WIN32\r
1595                 SetEnvironmentVariable(variable->name, variable->val);
1596             \r
1597 #else   /* \r */
1598                 setenv(variable->name, variable->val, 1);
1599             \r
1600 #endif  /* \r */
1601             }
1602           \r
1603           else
1604             \r {
1605             \rif (err)
1606               \rERROR2
1607                   ("[%s] Conflict : a system variable `(%s)' already exists",
1608                    filepos, name);
1609             \r
1610             else
1611               \rERROR2
1612                   ("[%s] Conflict : (none environment) variable `(%s)' already exists",
1613                    filepos, name);
1614             \r\runit_set_error(fstream->unit, ESYNTAX, 1, filepos);
1615             \rxbt_os_mutex_release(unit->mutex);
1616             \rfailure(unit);
1617             \rreturn;
1618             \r}
1619           \r}
1620         \r
1621         else
1622           \r {
1623           \rif (err)
1624             \r {
1625             \rERROR2("[%s] A system variable named `(%s)' already exists",
1626                     filepos, name);
1627             \r\runit_set_error(fstream->unit, ESYNTAX, 1, filepos);
1628             \rxbt_os_mutex_release(unit->mutex);
1629             \rfailure(unit);
1630             \rreturn;
1631             \r}
1632           \r
1633           else
1634             \r {
1635             \rvariable = variable_new(name, val);
1636             \rvariable->env = 1;
1637             \r\rxbt_dynar_push(unit->runner->variables, &variable);
1638             \r\r
1639 #ifdef _XBT_WIN32\r
1640                 SetEnvironmentVariable(variable->name, variable->val);
1641             \r
1642 #else   /* \r */
1643                 setenv(variable->name, variable->val, 0);
1644             \r
1645 #endif  /* \r */
1646             }
1647           \r}
1648         \r\rxbt_os_mutex_release(unit->mutex);
1649         \r\r}
1650       \r
1651       else
1652         \r {
1653         \rERROR1
1654             ("[%s] Bad usage of the metacommand setenv `(usage : setenv variable=value)'",
1655              filepos);
1656         \r\runit_set_error(fstream->unit, ESYNTAX, 1, filepos);
1657         \rfailure(unit);
1658         \rreturn;
1659         \r}
1660       \r}
1661     \r
1662     else if (!strncmp(line, "unset ", strlen("unset ")))
1663       \r {
1664       \runsigned int i, j;
1665       \rint exists = 0;
1666       \rint env = 0;
1667       \rint err = 0;
1668       \rvariable_t variable;
1669       \rint is_blank;
1670       \r\rchar *name = line + strlen("unset ");
1671       \r\ris_blank = 1;
1672       \r\rfor (j = 0; j < strlen(name); j++)
1673         \rif (name[j] != ' ' && name[j] != '\t')
1674           \ris_blank = 0;
1675       \r\rif (is_blank)
1676         \r {
1677         \r\rERROR1
1678             ("[%s] Bad usage of the metacommand unset `(usage : unset variable)'",
1679              filepos);
1680         \r\runit_set_error(fstream->unit, ESYNTAX, 1, filepos);
1681         \r\rfailure(unit);
1682         \rreturn;
1683         \r}
1684       \r\r\rxbt_os_mutex_acquire(unit->mutex);
1685       \r\rxbt_dynar_foreach(unit->runner->variables, i, variable) \r {
1686         \rif (!strcmp(variable->name, name))
1687           \r {
1688           \renv = variable->env;
1689           \rerr = variable->err;
1690           \rexists = 1;
1691           \rbreak;
1692           \r}
1693       \r}
1694       \r\rif (!env && !err)
1695         \r {
1696         \rif (exists)
1697           \r {
1698           \r
1699               /*xbt_dynar_remove_at(unit->runner->variables, i, NULL); */ \r
1700               /*xbt_dynar_cursor_rm(unit->runner->variables, &i); */ \r
1701               if (variable->val)
1702             \r {
1703             \rfree(variable->val);
1704             \rvariable->val = NULL;
1705             \r}
1706           \r
1707           else
1708             \r {
1709             \rWARN2("[%s] Variable `(%s)' already unseted", filepos,
1710                    variable->name);
1711             \r}
1712           \r}
1713         \r
1714         else
1715           \r {
1716           \rERROR2("[%s] `(%s)' variable not found", filepos, name);
1717           \runit_set_error(fstream->unit, ESYNTAX, 1, filepos);
1718           \rxbt_os_mutex_release(unit->mutex);
1719           \rfailure(unit);
1720           \rreturn;
1721           \r}
1722         \r}
1723       \r
1724       else if (env)
1725         \r {
1726         \rERROR2
1727             ("[%s] `(%s)' is an environment variable use `unsetenv' instead `unset'",
1728              filepos, name);
1729         \runit_set_error(fstream->unit, ESYNTAX, 1, filepos);
1730         \rxbt_os_mutex_release(unit->mutex);
1731         \rfailure(unit);
1732         \rreturn;
1733         \r}
1734       \r
1735       else if (err)
1736         \r {
1737         \rERROR2("[%s] `(%s)' is system variable : you can unset it",
1738                 filepos, name);
1739         \runit_set_error(fstream->unit, ESYNTAX, 1, filepos);
1740         \rxbt_os_mutex_release(unit->mutex);
1741         \rfailure(unit);
1742         \rreturn;
1743         \r}
1744       \r\rxbt_os_mutex_release(unit->mutex);
1745       \r\r}
1746     \r
1747     else if (!strncmp(line, "set ", strlen("set ")))
1748       \r {
1749       \rchar *val;
1750       \rchar name[PATH_MAX + 1] = { 0 };
1751       \runsigned int j;
1752       \rint is_blank;
1753       \r\rval = strchr(line + strlen("set "), '=');
1754       \r\rif (val)
1755         \r {
1756         \rvariable_t variable;
1757         \rint exists = 0;
1758         \runsigned int i;
1759         \rint err;
1760         \rint env;
1761         \r\rval++;
1762         \r\r\r
1763             /* syntax error */ \r
1764             if (val[0] == '\0')
1765           \r {
1766           \rERROR1
1767               ("[%s] Bad usage of the metacommand set `(usage : set variable=value)'",
1768                filepos);
1769           \r\runit_set_error(fstream->unit, ESYNTAX, 1, filepos);
1770           \r\rfailure(unit);
1771           \rreturn;
1772           \r}
1773         \r
1774         else if (val[0] == ' ' || val[0] == '\t')
1775           \r {
1776           \rstrncpy(name, line + strlen("set "),
1777                    (val - (line + strlen("set "))));
1778           \r\rERROR2("[%s] No space avaible after`(%s)'", filepos, name);
1779           \r\runit_set_error(fstream->unit, ESYNTAX, 1, filepos);
1780           \r\rfailure(unit);
1781           \rreturn;
1782           \r}
1783         \r\r\r
1784             /* assume it's a varibale */ \r
1785             \rstrncpy(name, line + strlen("set "),
1786                      (val - (line + strlen("set ")) - 1));
1787         \r\ris_blank = 1;
1788         \r\rfor (j = 0; j < strlen(name); j++)
1789           \rif (name[j] != ' ' && name[j] != '\t')
1790             \ris_blank = 0;
1791         \r\rif (is_blank)
1792           \r {
1793           \r\rERROR1
1794               ("[%s] Bad usage of the metacommand set `(usage : set variable=value)'",
1795                filepos);
1796           \r\runit_set_error(fstream->unit, ESYNTAX, 1, filepos);
1797           \r\rfailure(unit);
1798           \rreturn;
1799           \r}
1800         \r\rxbt_os_mutex_acquire(unit->mutex);
1801         \r\r
1802             /* test if the variable is already registred */ \r
1803             xbt_dynar_foreach(unit->runner->variables, i, variable) \r {
1804           \rif (!strcmp(variable->name, name))
1805             \r {
1806             \rexists = 1;
1807             \rerr = variable->err;
1808             \renv = variable->env;
1809             \rbreak;
1810             \r}
1811         \r}
1812         \r\r
1813             /* if the variable is already registred, update its value (if same value warns);\r
1814              * otherwise register it.\r
1815              */ \r
1816             if (exists)
1817           \r {
1818           \rif (err)
1819             \r {
1820             \rERROR2("[%s] A system variable named `(%s)' already exists",
1821                     filepos, name);
1822             \r\runit_set_error(fstream->unit, ESYNTAX, 1, filepos);
1823             \rxbt_os_mutex_release(unit->mutex);
1824             \r\rfailure(unit);
1825             \rreturn;
1826             \r}
1827           \rif (env)
1828             \r {
1829             \rERROR2
1830                 ("[%s] `(%s)' is an environment variable use `setenv' instead `set'",
1831                  filepos, name);
1832             \r\runit_set_error(fstream->unit, ESYNTAX, 1, filepos);
1833             \rxbt_os_mutex_release(unit->mutex);
1834             \r\rfailure(unit);
1835             \rreturn;
1836             \r}
1837           \r
1838           else
1839             \r {
1840             \rif (!strcmp(val, variable->val))
1841               \rWARN3("[%s] Variable `(%s)' already contains value `<%s>'",
1842                      filepos, variable->name, val);
1843             \r\rfree(variable->val);
1844             \rvariable->val = strdup(val);
1845             \r}
1846           \r}
1847         \r
1848         else
1849           \r {
1850           \rvariable_t new_var = variable_new(name, val);
1851           \rxbt_dynar_push(unit->runner->variables, &new_var);
1852           \r}
1853         \r\r\rxbt_os_mutex_release(unit->mutex);
1854         \r}
1855       \r
1856       else
1857         \r {
1858         \rERROR1
1859             ("[%s] Bad usage of the metacommand set `(usage : set variable=value)'",
1860              filepos);
1861         \r\runit_set_error(fstream->unit, ESYNTAX, 1, filepos);
1862         \rfailure(unit);
1863         \rreturn;
1864         \r}
1865       \r}
1866     \r
1867     else
1868       \r {                       /* assume it's a variable */
1869       \rchar *val;
1870       \rchar name[PATH_MAX + 1] = { 0 };
1871       \runsigned int i, j;
1872       \rint is_blank;
1873       \r\rval = strchr(line, '=');
1874       \r\rif (val)
1875         \r {
1876         \rvariable_t variable;
1877         \rint exists = 0;
1878         \rint err;
1879         \rint env;
1880         \rval++;
1881         \r\r\r
1882             /* syntax error */ \r
1883             if (val[0] == '\0')
1884           \r {
1885           \rstrncpy(name, line, (val - line - 1));
1886           \r\ris_blank = 1;
1887           \r\rfor (j = 0; j < strlen(name); j++)
1888             \rif (name[j] != ' ' && name[j] != '\t')
1889               \ris_blank = 0;
1890           \r\rif (is_blank)
1891             \rERROR1
1892                 ("[%s] Bad usage of Tesh variable mechanism `(usage : variable=value)'",
1893                  filepos);
1894           \r
1895           else if (!strcmp("setenv", name))
1896             \rERROR1
1897                 ("[%s] Bad usage of the metacommand setenv `(usage : setenv variable=value)'",
1898                  filepos);
1899           \r
1900           else if (!strcmp("set", name))
1901             \rERROR1
1902                 ("[%s] Bad usage of the metacommand set `(usage : set variable=value)'",
1903                  filepos);
1904           \r
1905           else
1906             \rERROR2("[%s] Undefined variable `(%s)'", filepos, name);
1907           \r\runit_set_error(fstream->unit, ESYNTAX, 1, filepos);
1908           \r\rfailure(unit);
1909           \rreturn;
1910           \r}
1911         \r
1912         else if (val[0] == ' ' || val[0] == '\t')
1913           \r {
1914           \rstrncpy(name, line, (val - line));
1915           \r\rERROR2("[%s] No space avaible after`(%s)'", filepos, name);
1916           \r\runit_set_error(fstream->unit, ESYNTAX, 1, filepos);
1917           \r\rfailure(unit);
1918           \r}
1919         \r\r\r
1920             /* assume it's a varibale */ \r
1921             \rstrncpy(name, line, (val - line - 1));
1922         \r\ris_blank = 1;
1923         \r\rfor (j = 0; j < strlen(name); j++)
1924           \rif (name[j] != ' ' && name[j] != '\t')
1925             \ris_blank = 0;
1926         \r\rif (is_blank)
1927           \r {
1928           \r\rERROR1
1929               ("[%s] Bad usage of Tesh variable capability `(usage : variable=value)'",
1930                filepos);
1931           \r\runit_set_error(fstream->unit, ESYNTAX, 1, filepos);
1932           \r\rfailure(unit);
1933           \rreturn;
1934           \r}
1935         \r\rif (!strcmp("set", name))
1936           \r {
1937           \rERROR1
1938               ("[%s] Bad usage of the metacommand set `(usage : set variable=value)'",
1939                filepos);
1940           \r\runit_set_error(fstream->unit, ESYNTAX, 1, filepos);
1941           \rfailure(unit);
1942           \rreturn;
1943           \r}
1944         \r
1945         else if (!strcmp("setenv", name))
1946           \r {
1947           \rERROR1
1948               ("[%s] Bad usage of the metacommand setenv `(usage : setenv variable=value)'",
1949                filepos);
1950           \r\runit_set_error(fstream->unit, ESYNTAX, 1, filepos);
1951           \rfailure(unit);
1952           \rreturn;
1953           \r}
1954         \r\rxbt_os_mutex_acquire(unit->mutex);
1955         \r\r
1956             /* test if the variable is already registred */ \r
1957             xbt_dynar_foreach(unit->runner->variables, i, variable) \r {
1958           \rif (!strcmp(variable->name, name))
1959             \r {
1960             \rexists = 1;
1961             \rerr = variable->err;
1962             \renv = variable->env;
1963             \rbreak;
1964             \r}
1965         \r}
1966         \r\r
1967             /* if the variable is already registred, update its value (if same value warns);\r
1968              * otherwise register it.\r
1969              */ \r
1970             if (exists)
1971           \r {
1972           \rif (err)
1973             \r {
1974             \rERROR2("[%s] A system variable named `(%s)' already exists",
1975                     filepos, name);
1976             \r\runit_set_error(fstream->unit, ESYNTAX, 1, filepos);
1977             \rxbt_os_mutex_release(unit->mutex);
1978             \rfailure(unit);
1979             \rreturn;
1980             \r}
1981           \rif (env)
1982             \r {
1983             \rERROR2
1984                 ("[%s] `(%s)' is an environment variable use `setenv' metacommand",
1985                  filepos, name);
1986             \r\runit_set_error(fstream->unit, ESYNTAX, 1, filepos);
1987             \rxbt_os_mutex_release(unit->mutex);
1988             \r\rfailure(unit);
1989             \rreturn;
1990             \r}
1991           \r
1992           else
1993             \r {
1994             \rif (!strcmp(val, variable->val))
1995               \rWARN3("[%s] Variable `(%s)' already contains value `<%s>'",
1996                      filepos, variable->name, val);
1997             \r\rfree(variable->val);
1998             \rvariable->val = strdup(val);
1999             \r}
2000           \r}
2001         \r
2002         else
2003           \r {
2004           \rvariable_t new_var = variable_new(name, val);
2005           \rxbt_dynar_push(unit->runner->variables, &new_var);
2006           \r}
2007         \r\r\rxbt_os_mutex_release(unit->mutex);
2008         \r\r}
2009       \r
2010       else
2011         \r {
2012         \rif (!strncmp("setenv", line, strlen("setenv")))
2013           \rERROR1
2014               ("[%s] Bad usage of the metacommand setenv : `(usage : setenv variable=value)'",
2015                filepos);
2016         \r
2017         else if (!strncmp("set", line, strlen("set")))
2018           \rERROR1
2019               ("[%s] Bad usage of the metacommand set : `(usage : set variable=value)'",
2020                filepos);
2021         \r
2022         else if (!strncmp("unsetenv", line, strlen("unsetenv")))
2023           \rERROR1
2024               ("[%s] Bad usage of the metacommand unsetenv : `(usage : unsetenv variable)'",
2025                filepos);
2026         \r
2027         else if (!strncmp("unset", line, strlen("unset")))
2028           \rERROR1
2029               ("[%s] Bad usage of the metacommand unset : `(usage : unset variable)'",
2030                filepos);
2031         \r
2032         else if (!strncmp("timeout", line, strlen("timeout")))
2033           \rERROR1
2034               ("[%s] Bad usage of the metacommand timeout : `(usage : timeout <integral positive integer>)'",
2035                filepos);
2036         \r
2037         else if (!strncmp("expect signal", line, strlen("expect signal")))
2038           \rERROR1
2039               ("[%s] Bad usage of the metacommand expect signal : `(usage : expect signal <sig_name>)'",
2040                filepos);
2041         \r
2042         else if (!strncmp("expect return", line, strlen("expect return")))
2043           \rERROR1
2044               ("[%s] Bad usage of the metacommand expect return : `(usage : expect return <return value (>=0 <=255)>)'",
2045                filepos);
2046         \r
2047         else if (!strncmp("include", line, strlen("include")))
2048           \rERROR1
2049               ("[%s] Bad usage of the metacommand include  :`(usage : include <file> [<description>])'",
2050                filepos);
2051         \r
2052         else if (!strncmp("suite", line, strlen("suite")))
2053           \rERROR1
2054               ("[%s] Bad usage of the metacommand suite : `(usage : suite <description>)'",
2055                filepos);
2056         \r
2057         else
2058           \rERROR2("[%s] Unknown metacommand: `%s'", filepos, line);
2059         \r\runit_set_error(fstream->unit, ESYNTAX, 1, filepos);
2060         \r\rfailure(unit);
2061         \rreturn;
2062         \r}
2063       \r}
2064     \r\rbreak;
2065     \r}
2066 \r}
2067
2068 \r\rvoid \r
2069 fstream_handle_include(fstream_t fstream, context_t context,
2070                        xbt_os_mutex_t mutex, const char *file_name,
2071                        const char *description) \r
2072 {
2073   \rdirectory_t dir;
2074   \rchar *prev_directory = NULL;
2075   \rfstream_t _fstream = NULL;
2076   \rstruct stat buffer = { 0 };
2077   \runit_t unit = fstream->unit;
2078   \r\rif (!stat(file_name, &buffer) && S_ISREG(buffer.st_mode))
2079     \r {
2080     \r
2081         /* the file is in the current directory */ \r
2082         _fstream = fstream_new(getcwd(NULL, 0), file_name);
2083     \rfstream_open(_fstream);
2084     \r}
2085   \r
2086       /* the file to include is not in the current directory, check if it is in a include directory */ \r
2087       else
2088     \r {
2089     \runsigned int i;
2090     \rprev_directory = getcwd(NULL, 0);
2091     \r\rxbt_dynar_foreach(include_dirs, i, dir) \r {
2092       \rchdir(dir->name);
2093       \r\rif (!stat(file_name, &buffer) && S_ISREG(buffer.st_mode))
2094         \r {
2095         \r_fstream = fstream_new(dir->name, file_name);
2096         \rfstream_open(_fstream);
2097         \rbreak;
2098         \r}
2099     \r}
2100     \r\rchdir(prev_directory);
2101     \rfree(prev_directory);
2102     \r}
2103   \r\r
2104       /* the file to include is not found handle the failure */ \r
2105       if (!_fstream)
2106     \r {
2107     \rif (file_name[0] == '$')
2108       \r {
2109       \rERROR3
2110           ("[%s] Include file `(%s)' not found or variable `(%s)' doesn't exist",
2111            context->line, file_name, file_name + 1);
2112       \r\r}
2113     \r
2114     else
2115       \r {
2116       \r
2117           /* may be a variable */ \r
2118           variable_t variable;
2119       \rint exists = 0;
2120       \runsigned int i;
2121       \r\rxbt_dynar_foreach(unit->runner->variables, i, variable) \r {
2122         \rif (!strcmp(variable->name, file_name))
2123           \r {
2124           \rexists = 1;
2125           \rbreak;
2126           \r}
2127       \r}
2128       \r\rif (exists)
2129         \rERROR3
2130             ("[%s] Include file `(%s)' not found (if you want to use the variable <%s> add the prefix `$')",
2131              context->line, file_name, file_name);
2132       \r
2133       else
2134         \rERROR2("[%s] Include file `(%s)' not found", context->line,
2135                 file_name);
2136       \r}
2137     \r\runit_set_error(fstream->unit, EINCLUDENOTFOUND, 1, context->line);
2138     \r\rfailure(fstream->unit);
2139     \r\rreturn;
2140     \r}
2141   \r
2142   else
2143     \r {
2144     \rif (!unit->is_running_suite)
2145       \r {                       /* it's the unit of a suite */
2146       \runit_t include = unit_new(unit->runner, unit->root, unit, _fstream);
2147       \r\rinclude->mutex = unit->root->mutex;
2148       \r\rif (description)
2149         \rinclude->description = strdup(description);
2150       \r\rxbt_dynar_push(unit->includes, &include);
2151       \r\rif (!dry_run_flag)
2152         \r {
2153         \rif (description)
2154           \rINFO2("Include from %s (%s)", _fstream->name, description);
2155         \r
2156         else
2157           \rINFO1("Include from %s", _fstream->name);
2158         \r\r}
2159       \r
2160       else
2161         \rINFO1("Checking include %s...", _fstream->name);
2162       \r\rfstream_parse(_fstream, mutex);
2163       \r}
2164     \r
2165     else
2166       \r {                       /* it's a include */
2167       \r\runit_t * owner;
2168       \runit_t include;
2169       \r\rowner =
2170           xbt_dynar_get_ptr(unit->suites,
2171                             xbt_dynar_length(unit->suites) - 1);
2172       \r\rinclude = unit_new(unit->runner, unit->root, *owner, _fstream);
2173       \r\rinclude->mutex = unit->root->mutex;
2174       \r\rif (description)
2175         \rinclude->description = strdup(description);
2176       \r\rxbt_dynar_push((*owner)->includes, &include);
2177       \r\rif (!dry_run_flag)
2178         \r {
2179         \rif (description)
2180           \rINFO2("Include from %s (%s)", _fstream->name, description);
2181         \r
2182         else
2183           \rINFO1("Include from %s", _fstream->name);
2184         \r}
2185       \r
2186       else
2187         \rINFO1("Checking include %s...", _fstream->name);
2188       \r\rfstream_parse(_fstream, mutex);
2189       \r}
2190     \r}
2191 \r}
2192
2193 \r\rvoid \r
2194 fstream_handle_suite(fstream_t fstream, const char *description,
2195                      const char *filepos) \r
2196 {
2197   \runit_t unit = fstream->unit;
2198   \runit_t suite = unit_new(unit->runner, unit->root, unit, NULL);
2199   \r\rif (description)
2200     \rsuite->description = strdup(description);
2201   \r\rsuite->filepos = strdup(filepos);
2202   \r\rxbt_dynar_push(unit->suites, &suite);
2203   \runit->is_running_suite = 1;
2204   \r\rif (!dry_run_flag)
2205     \rINFO1("Test suite %s", description);
2206   \r
2207   else
2208     \rINFO1("Checking suite %s...", description);
2209 \r\r}
2210
2211 \r\rint \r
2212 fstream_launch_command(fstream_t fstream, context_t context,
2213                        xbt_os_mutex_t mutex) \r
2214 {
2215   \runit_t unit = fstream->unit;
2216   \r\rif (!dry_run_flag)
2217     \r {
2218     \rcommand_t command;
2219     \r\rif (!(command = command_new(unit, context, mutex)))
2220       \r {
2221       \rif (EINVAL == errno)
2222         \r {
2223         \rERROR3("[%s] Cannot instantiate the command `%s' (%d)",
2224                 context->pos, strerror(errno), errno);
2225         \r\runit_set_error(unit, errno, 0, context->pos);
2226         \rfailure(unit);
2227         \rreturn -1;
2228         \r}
2229       \r
2230       else if (ENOMEM == errno)
2231         \r {
2232         \rERROR3("[%s] Cannot instantiate the command `%s' (%d)",
2233                 context->pos, strerror(errno), errno);
2234         \r\runit_set_error(unit, errno, 0, context->pos);
2235         \r\rfailure(unit);
2236         \rreturn -1;
2237         \r}
2238       \r}
2239     \r\rif (command_run(command) < 0)
2240       \r {
2241       \rERROR3("[%s] Cannot run the command `%s' (%d)", context->pos,
2242               strerror(errno), errno);
2243       \runit_set_error(unit, errno, 0, context->pos);
2244       \rfailure(unit);
2245       \rreturn -1;
2246       \r}
2247     \r}
2248   \r\rif (context_reset(context) < 0)
2249     \r {
2250     \rERROR3("[%s] Cannot reset the context of the command `%s' (%d)",
2251             context->pos, strerror(errno), errno);
2252     \r\runit_set_error(fstream->unit, errno, 0, context->pos);
2253     \r\rfailure(unit);
2254     \rreturn -1;
2255     \r}
2256   \r\rreturn 0;
2257 \r}
2258
2259 \r\r\r\r\r