Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
Add the new integrated files version (use xbt data structures instead my own data...
[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 \r
24 \r
25 XBT_LOG_EXTERNAL_DEFAULT_CATEGORY(tesh);\r
26 \r
27 static void\r
28 failure(unit_t unit)\r
29 {\r
30         \r
31         if(!keep_going_unit_flag)\r
32         {\r
33                 unit_t root = unit->root ? unit->root : unit;\r
34                         \r
35                 if(!root->interrupted)\r
36                 {\r
37                         /* the unit interrupted (exit for the loop) */\r
38                         root->interrupted = 1;\r
39 \r
40                         /* release the unit */\r
41                         xbt_os_sem_release(root->sem);\r
42                 }\r
43 \r
44                 /* if the --keep-going option is not specified */\r
45                 if(!keep_going_flag)\r
46                 {\r
47                         if(!interrupted)\r
48                         {\r
49                                 /* request an global interruption by the runner */\r
50                                 interrupted = 1;\r
51 \r
52                                 /* release the runner */\r
53                                 xbt_os_sem_release(units_sem);\r
54                         }\r
55                 }\r
56         }\r
57 }\r
58 \r
59 static void\r
60 syntax_error(unit_t unit)\r
61 {\r
62         error_register("Unit failure", ESYNTAX, NULL, unit->fstream->name);\r
63         \r
64         failure(unit);\r
65         \r
66 }\r
67 \r
68 static void\r
69 internal_error(unit_t unit)\r
70 {\r
71         failure(unit);\r
72 }\r
73 \r
74 static void\r
75 sys_error(unit_t unit)\r
76 {\r
77         unit_t root;\r
78         \r
79         error_register("System error", errno, NULL, unit->fstream->name);\r
80         \r
81         root = unit->root ? unit->root : unit;\r
82                         \r
83         if(!root->interrupted)\r
84         {\r
85                 /* the unit interrupted (exit for the loop) */\r
86                 root->interrupted = 1;\r
87 \r
88                 /* release the unit */\r
89                 xbt_os_sem_release(root->sem);\r
90         }\r
91         \r
92         if(!interrupted)\r
93         {\r
94                 /* request an global interruption by the runner */\r
95                 interrupted = 1;\r
96 \r
97                 /* release the runner */\r
98                 xbt_os_sem_release(units_sem);\r
99         }\r
100 }\r
101 \r
102 fstream_t\r
103 fstream_new(const char* directory, const char* name)\r
104 {\r
105         fstream_t fstream;\r
106         \r
107         if(!name)\r
108         {\r
109                 errno = EINVAL;\r
110                 return NULL;\r
111         }\r
112         \r
113         if(!directory && !strcmp("stdin", name))\r
114         {\r
115                 fstream = xbt_new0(s_fstream_t, 1);\r
116                 fstream->name = strdup("stdin");\r
117                 return fstream;\r
118         }\r
119         else if(!directory)\r
120         {\r
121                 errno = EINVAL;\r
122                 return NULL;\r
123         }\r
124         \r
125         fstream = xbt_new0(s_fstream_t, 1);\r
126         \r
127         if(!(fstream->name = strdup(name)))\r
128         {\r
129                 free(fstream);\r
130                 return NULL;\r
131         }\r
132         \r
133         if(!(fstream->directory = strdup(directory)))\r
134         {\r
135                 free(fstream->name);\r
136                 free(fstream);\r
137                 return NULL;\r
138         }\r
139         \r
140         fstream->stream = NULL;\r
141         fstream->unit = NULL;\r
142         \r
143         \r
144         return fstream;\r
145 }\r
146 \r
147 int\r
148 fstream_open(fstream_t fstream)\r
149 {\r
150         char path[PATH_MAX + 1] = {0};\r
151         \r
152         /* check the parameter */\r
153         if(!(fstream))\r
154     {\r
155         errno = EINVAL;\r
156         return -1;\r
157     }\r
158         \r
159         if(!fstream || fstream->stream)\r
160         {\r
161                 errno = EALREADY;\r
162                 return -1;\r
163         }\r
164                 \r
165         if(!strcmp(fstream->name, "stdin"))\r
166         {\r
167                 fstream->stream = stdin;\r
168                 return 0;\r
169         }\r
170         \r
171         #ifndef WIN32\r
172         sprintf(path,"%s/%s",fstream->directory, fstream->name);\r
173         #else\r
174         sprintf(path,"%s\\%s",fstream->directory, fstream->name);\r
175     #endif\r
176 \r
177         if(!(fstream->stream = fopen(path, "r")))\r
178                 return -1;\r
179         \r
180         return 0;\r
181 }\r
182 \r
183 int\r
184 fstream_close(fstream_t fstream)\r
185 {\r
186         /* check the parameter */\r
187         if(!(fstream) || !strcmp(fstream->name, "stdin") )\r
188     {\r
189         errno = EINVAL;\r
190         return -1;\r
191     }\r
192                 \r
193         if(!fstream->stream)\r
194                 return EBADF;   \r
195         \r
196         if(EOF == fclose(fstream->stream))\r
197                 return -1;\r
198                 \r
199         fstream->stream = NULL;\r
200         \r
201         return 0;\r
202 }\r
203 \r
204 int\r
205 fstream_free(fstream_t* ptr)\r
206 {\r
207         \r
208         /* check the parameter */\r
209         if(!(*ptr))\r
210     {\r
211         errno = EINVAL;\r
212         return -1;\r
213     }\r
214     \r
215         if(!(*ptr))\r
216                 return EINVAL;\r
217                 \r
218         if((*ptr)->stream)\r
219                 fclose((*ptr)->stream);\r
220         \r
221         free((*ptr)->name);\r
222         \r
223         if((*ptr)->directory)\r
224                 free((*ptr)->directory);\r
225                 \r
226         free(*ptr);\r
227 \r
228         *ptr = NULL;\r
229         \r
230         return 0;\r
231                 \r
232 }\r
233 \r
234 int\r
235 fstream_parse(fstream_t fstream, xbt_os_mutex_t mutex)\r
236 {\r
237         size_t len;\r
238         char * line = NULL;\r
239         int line_num = 0;\r
240         char file_pos[256];\r
241         xbt_strbuff_t buff;\r
242         int buffbegin = 0; \r
243         context_t context;\r
244         unit_t unit;\r
245         \r
246         /* Count the line length while checking wheather it's blank */\r
247         int blankline;\r
248         int linelen;    \r
249         /* Deal with \ at the end of the line, and call handle_line on result */\r
250         int to_be_continued;\r
251         \r
252         /* check the parameter */\r
253         if(!(fstream) || !mutex)\r
254     {\r
255         errno = EINVAL;\r
256         return -1;\r
257     }\r
258     \r
259         buff = xbt_strbuff_new();\r
260         \r
261         if(!(context = context_new()))\r
262                 return -1;\r
263                 \r
264         unit = fstream->unit;\r
265         \r
266         while(!(unit->root->interrupted)  && getline(&line, &len, fstream->stream) != -1)\r
267         {\r
268                 \r
269                 blankline=1;\r
270                 linelen = 0;    \r
271                 to_be_continued = 0;\r
272 \r
273                 line_num++;\r
274                 \r
275                 while(line[linelen] != '\0') \r
276                 {\r
277                         if (line[linelen] != ' ' && line[linelen] != '\t' && line[linelen]!='\n' && line[linelen]!='\r')\r
278                                 blankline = 0;\r
279                         \r
280                         linelen++;\r
281                 }\r
282         \r
283                 if(blankline) \r
284                 {\r
285                         if(!context->command_line && (context->input->used || context->output->used))\r
286                         {\r
287                                 ERROR1("[%d] Error: no command found in this chunk of lines.",buffbegin);\r
288                                 syntax_error(unit);\r
289                                 break;\r
290                         }\r
291                         else if(unit->is_running_suite)\r
292                         {/* it's the end of a suite */\r
293                                 unit->is_running_suite = 0;\r
294                         }\r
295                                 \r
296                         if(context->command_line)\r
297                         {\r
298                                 if(fstream_launch_command(fstream, context, mutex) < 0)\r
299                                                 break;\r
300                         }\r
301                 \r
302                         continue;\r
303                 }\r
304                 \r
305                 if(linelen>1 && line[linelen-2]=='\\') \r
306                 {\r
307                         if(linelen>2 && line[linelen-3] == '\\') \r
308                         {\r
309                                 /* Damn. Escaped \ */\r
310                                 line[linelen-2] = '\n';\r
311                                 line[linelen-1] = '\0';\r
312                         } \r
313                         else \r
314                         {\r
315                                 to_be_continued = 1;\r
316                                 line[linelen-2] = '\0';\r
317                                 linelen -= 2;  \r
318                                 \r
319                                 if (!buff->used)\r
320                                         buffbegin = line_num;\r
321                         }\r
322                 }\r
323         \r
324                 if(buff->used || to_be_continued) \r
325                 { \r
326                         xbt_strbuff_append(buff,line);\r
327         \r
328                         if (!to_be_continued) \r
329                         {\r
330                                 snprintf(file_pos,256,"%s:%d",fstream->name, buffbegin);\r
331                                 fstream_lex_line(fstream, context, mutex, file_pos, buff->data);    \r
332                                 xbt_strbuff_empty(buff);\r
333                         }\r
334                 } \r
335                 else \r
336                 {\r
337                         snprintf(file_pos,256,"%s:%d",fstream->name, line_num);\r
338                         fstream_lex_line(fstream, context, mutex, file_pos, line);      \r
339                 }\r
340         }\r
341         \r
342         /* Check that last command of the file ran well */\r
343         if(context->command_line)\r
344         {\r
345                 if(fstream_launch_command(fstream, context, mutex) < 0)\r
346                         return -1;\r
347         }\r
348         \r
349         /* clear buffers */\r
350         if(line)\r
351                 free(line);\r
352                 \r
353         xbt_strbuff_free(buff); \r
354         \r
355         if(context_free(&context) < 0)\r
356                 return -1;\r
357         \r
358         return (exit_code || errno) ? -1 : 0;\r
359 }\r
360 \r
361 \r
362 void \r
363 fstream_lex_line(fstream_t fstream, context_t context, xbt_os_mutex_t mutex, const char * filepos, char *line) \r
364 {\r
365         char* line2;\r
366         variable_t variable;\r
367         unsigned int i;\r
368         char name[VAR_NAME_MAX + 1] = {0};\r
369         unit_t unit = fstream->unit;\r
370         xbt_dynar_t variables = unit->runner->variables;\r
371         \r
372         /* search end */\r
373         xbt_str_rtrim(line + 2,"\n");\r
374         \r
375         line2 = strdup(line);\r
376         \r
377         /* replace each variable by its value */\r
378         xbt_os_mutex_acquire(unit->mutex);\r
379 \r
380         xbt_dynar_foreach(variables, i, variable)\r
381         {\r
382                 sprintf(name, "$%s", variable->name);\r
383                 str_replace_all(&line2, name, variable->val);\r
384                 memset(name, 0, VAR_NAME_MAX + 1);\r
385         }\r
386         \r
387         xbt_os_mutex_release(unit->mutex);\r
388         \r
389         switch(line2[0]) \r
390         {\r
391                 case '#': \r
392                 break;\r
393                 \r
394                 case '$':\r
395                 case '&':\r
396                         \r
397                 context->async = (line2[0] == '&');\r
398                 \r
399                 /* further trim useless chars which are significant for in/output */\r
400                 xbt_str_rtrim(line2 + 2," \t");\r
401                 \r
402                 /* deal with CD commands here, not in context */\r
403                 if(!strncmp("cd ",line2 + 2, 3)) \r
404                 {\r
405                         char* dir = strdup(line2 + 4);\r
406                         \r
407                         if(context->command_line)\r
408                         {\r
409                                 if(fstream_launch_command(fstream, context, mutex) < 0)\r
410                                         return;\r
411                         }\r
412                 \r
413                         /* search begining */\r
414                         while(*(dir++) == ' ');\r
415                         \r
416                         dir--;\r
417                         \r
418                         if(!dry_run_flag)\r
419                         {\r
420                                 if(!silent_flag)\r
421                                         INFO1("tesh cd %s",dir);\r
422                                 \r
423                                 if(!just_print_flag)\r
424                                 {\r
425                                         if(chdir(dir))\r
426                                         {\r
427                                                 ERROR1("chdir failed to set the directory to %s", dir);\r
428                                                 error_register("Unit failure", errno, NULL, unit->fstream->name);\r
429                                                 failure(unit);\r
430                                         }\r
431                                 }\r
432                         }\r
433                         \r
434                         break;\r
435                 }\r
436                 else\r
437                 {\r
438                         fstream_process_token(fstream, context, mutex, filepos, line2[0], line2 + 2);\r
439                         break;\r
440                 }\r
441                 \r
442                 case '<':\r
443                 case '>':\r
444                 case '!':\r
445                 fstream_process_token(fstream, context, mutex, filepos, line2[0], line2 + 2);    \r
446                 break;\r
447                 \r
448                 case 'p':\r
449                 if(!dry_run_flag)\r
450                         INFO2("[%s] %s",filepos,line2+2);\r
451                 break;\r
452                 \r
453                 case 'P':\r
454                 if(!dry_run_flag)\r
455                         CRITICAL2("[%s] %s",filepos,line2+2);\r
456                 break;\r
457                 \r
458                 case 'D':\r
459                         if(unit->description)\r
460                                 WARN2("Description already specified %s at %s", line2, filepos); \r
461                         else\r
462                                 unit->description = strdup(line2 + 2);\r
463                 break;\r
464                 \r
465                 default:\r
466                 error_register("Unit failure", errno, NULL, unit->fstream->name);\r
467                 syntax_error(unit);\r
468                 break;\r
469         }\r
470         \r
471         free(line2);\r
472 }\r
473 \r
474 void \r
475 fstream_process_token(fstream_t fstream, context_t context, xbt_os_mutex_t mutex, const char* filepos, char token, char *line) \r
476 {\r
477         unit_t unit = fstream->unit;\r
478         \r
479         switch (token) \r
480         {\r
481                 case '$':\r
482                 case '&':\r
483                 \r
484                 if(context->command_line) \r
485                 {\r
486                         \r
487                         if(context->output->used || context->input->used) \r
488                         {\r
489                                 ERROR2("[%s] More than one command in this chunk of lines (previous: %s).\nDunno which input/output belongs to which command.",filepos,context->command_line);\r
490                                 syntax_error(unit);\r
491                                 return;\r
492                         }\r
493                         \r
494                         if(fstream_launch_command(fstream, context, mutex) < 0)\r
495                                         return;\r
496                         \r
497                         VERB1("[%s] More than one command in this chunk of lines",filepos);\r
498                 }\r
499                 \r
500                 context->command_line = strdup(line);\r
501                 context->line = strdup(filepos);\r
502         \r
503                 \r
504                 break;\r
505                 \r
506                 case '<':\r
507                 xbt_strbuff_append(context->input,line);\r
508                 xbt_strbuff_append(context->input,"\n");\r
509                 break;\r
510                 \r
511                 case '>':\r
512                 xbt_strbuff_append(context->output,line);\r
513                 xbt_strbuff_append(context->output,"\n");\r
514                 break;\r
515                 \r
516                 case '!':\r
517                 \r
518                 if(context->command_line)\r
519                         if(fstream_launch_command(fstream, context, mutex) < 0)\r
520                                         return;\r
521                 \r
522                 if(!strncmp(line,"timeout no",strlen("timeout no"))) \r
523                 {\r
524                         VERB1("[%s] (disable timeout)", filepos);\r
525                         context->timeout = INDEFINITE;\r
526                 } \r
527                 else if(!strncmp(line,"timeout ",strlen("timeout "))) \r
528                 {\r
529                         int i = 0;\r
530                         char* p = line + strlen("timeout ");\r
531         \r
532                         while(p[i] != '\0')\r
533                         {\r
534                                 if(!isdigit(p[i]))\r
535                                 {\r
536                                         ERROR2("Invalid timeout value `%s' at %s ", line + strlen("timeout "), filepos);\r
537                                         syntax_error(unit);\r
538                                         failure(unit);\r
539                                 }\r
540 \r
541                                 i++;\r
542                         }\r
543                         \r
544                         context->timeout = atoi(line + strlen("timeout"));\r
545                         VERB2("[%s] (new timeout value: %d)",filepos,context->timeout);\r
546                 \r
547                 } \r
548                 else if (!strncmp(line,"expect signal ",strlen("expect signal "))) \r
549                 {\r
550                         context->signal = strdup(line + strlen("expect signal "));\r
551                         \r
552                         #ifdef WIN32\r
553                         if(!strstr("SIGSEGVSIGTRAPSIGBUSSIGFPESIGILL", context->signal))\r
554                         {\r
555                                 ERROR2("Incompatible signal \'%s\' detected at %s", context->signal, filepos);\r
556                                 syntax_error(unit);\r
557                         }\r
558                         #endif\r
559 \r
560                         xbt_str_trim(context->signal," \n");\r
561                         VERB2("[%s] (next command must raise signal %s)", filepos, context->signal);\r
562                 \r
563                 } \r
564                 else if (!strncmp(line,"expect return ",strlen("expect return "))) \r
565                 {\r
566 \r
567                         int i = 0;\r
568                         char* p = line + strlen("expect return ");\r
569                         \r
570                         while(p[i] != '\0')\r
571                         {\r
572                                 if(!isdigit(p[i]))\r
573                                 {\r
574                                         ERROR2("Invalid exit code value `%s' at %s ", line + strlen("expect return "), filepos);\r
575                                         syntax_error(unit);\r
576                                 }\r
577 \r
578                                 i++;\r
579                         }\r
580 \r
581                         context->exit_code = atoi(line+strlen("expect return "));\r
582                         VERB2("[%s] (next command must return code %d)",filepos, context->exit_code);\r
583                 \r
584                 } \r
585                 else if (!strncmp(line,"output ignore",strlen("output ignore"))) \r
586                 {\r
587                         context->output_handling = oh_ignore;\r
588                         VERB1("[%s] (ignore output of next command)", filepos);\r
589                 \r
590                 } \r
591                 else if (!strncmp(line,"output display",strlen("output display"))) \r
592                 {\r
593                         context->output_handling = oh_display;\r
594                         VERB1("[%s] (ignore output of next command)", filepos);\r
595                 \r
596                 } \r
597                 else if(!strncmp(line,"include ", strlen("include ")))\r
598                 {\r
599                         char* p1;\r
600                         char* p2;\r
601                         \r
602                         p1 = line + strlen("include");\r
603                         \r
604                         while(*p1 == ' ' || *p1 == '\t')\r
605                                 p1++;\r
606                                 \r
607                         \r
608                         if(p1[0] == '\0')\r
609                         {\r
610                                 ERROR1("include file not specified %s ", filepos);\r
611                                 syntax_error(unit);\r
612                         }\r
613                         else\r
614                         {\r
615                                 char file_name[PATH_MAX + 1] = {0};\r
616                                 \r
617                                 p2 = p1;\r
618                                 \r
619                                 while(*p2 != '\0' && *p2 != ' ' && *p2 != '\t')\r
620                                         p2++;\r
621                                         \r
622                                 strncpy(file_name, p1, p2 - p1);\r
623                                 \r
624                                 \r
625                                 if(p2[0] != '\0')\r
626                                         while(*p2 == ' ' || *p2 == '\t')\r
627                                                 p2++;\r
628                                         \r
629                                 fstream_handle_include(fstream, context, mutex, file_name, p2[0] != '\0' ? p2 : NULL);\r
630                                 \r
631                         }\r
632                 }\r
633                 else if(!strncmp(line,"suite ", strlen("suite ")))\r
634                 {\r
635                         if(unit->is_running_suite)\r
636                         {\r
637                                 ERROR1("Suite already in process at %s", filepos);\r
638                                 syntax_error(unit);\r
639                                 return;\r
640                         }\r
641                         \r
642                         fstream_handle_suite(fstream, context, mutex, line + strlen("suite "));\r
643                 }\r
644                 else if(!strncmp(line,"unsetenv ", strlen("unsetenv ")))\r
645                 {\r
646                         unsigned int i;\r
647                         int exists = 0;\r
648                         int env = 0;\r
649                         variable_t variable;\r
650                         char* name = line + strlen("unsetenv ");\r
651                         \r
652                         xbt_os_mutex_acquire(unit->mutex);\r
653                         \r
654 \r
655                         xbt_dynar_foreach(unit->runner->variables, i, variable)\r
656                         {\r
657                                 if(!strcmp(variable->name, name))\r
658                                 {\r
659                                         env = variable->env;\r
660                                         exists = 1;\r
661                                         break;\r
662                                 }\r
663                         }\r
664                                 \r
665                         if(env)\r
666                         {\r
667                                 if(exists)\r
668                                         /*xbt_dynar_remove_at(unit->runner->variables, i - 1, NULL);*/\r
669                                         xbt_dynar_cursor_rm(unit->runner->variables, &i);\r
670                                 else\r
671                                         WARN3("environment variable %s not found %s %s at", name, line, filepos);       \r
672                         }\r
673                         else\r
674                         {\r
675                                 if(exists)\r
676                                         WARN3("%s is an not environment variable use unset metacommand to delete it %s %s", name, line, filepos);\r
677                                 else\r
678                                         WARN3("%s environment variable not found %s %s", name, line, filepos);\r
679                         }\r
680                         \r
681                         xbt_os_mutex_release(unit->mutex);      \r
682                         \r
683                                 \r
684                 }\r
685                 else if(!strncmp(line,"setenv ", strlen("setenv ")))\r
686                 {\r
687                         char* val;\r
688                         char name[PATH_MAX + 1] = {0};\r
689                         char* p;\r
690                         unsigned int i;\r
691                         \r
692                         p = line + strlen("setenv ");\r
693                         \r
694                         val = strchr(p, '=');\r
695                         \r
696                         if(val)\r
697                         {\r
698                                 variable_t variable;\r
699                                 int exists = 0;\r
700                                 int env = 0;\r
701                                 val++;\r
702                                 \r
703                                 /* syntax error */\r
704                                 if(val[0] == '\0')\r
705                                 {\r
706                                         ERROR2("Indefinite variable value %s %s", line, filepos);\r
707                                         syntax_error(unit);\r
708                                         failure(unit);  \r
709                                 }\r
710                                 \r
711                                 \r
712                                 strncpy(name, p, (val - p -1));\r
713                                 \r
714                                 /* test if the variable is already registred */\r
715                                 xbt_os_mutex_acquire(unit->mutex);\r
716 \r
717                                 xbt_dynar_foreach(unit->runner->variables, i, variable)\r
718                                 {\r
719                                         if(!strcmp(variable->name, name))\r
720                                         {\r
721                                                 variable->env = 1;\r
722                                                 exists = 1;\r
723                                                 break;\r
724                                         }\r
725                                 }\r
726                                 \r
727                                 /* if the variable is already registred, update its value;\r
728                                  * otherwise register it.\r
729                                  */\r
730                                 if(exists)\r
731                                 {\r
732                                         if(env)\r
733                                         {\r
734                                                 free(variable->val);\r
735                                                 variable->val = strdup(val);\r
736                                                 #ifdef WIN32\r
737                                                 SetEnvironmentVariable(variable->name, variable->val);\r
738                                                 #else\r
739                                                 setenv(variable->name, variable->val, 1);\r
740                                                 #endif\r
741                                         }\r
742                                         else\r
743                                                 WARN3("%s variable already exists %s %s", name, line, filepos); \r
744                                 }\r
745                                 else\r
746                                 {\r
747                                         variable = variable_new(name, val);\r
748                                         variable->env = 1;\r
749                                         \r
750                                         xbt_dynar_push(unit->runner->variables, &variable);\r
751                                         \r
752                                         #ifdef WIN32\r
753                                         SetEnvironmentVariable(variable->name, variable->val);\r
754                                         #else\r
755                                         setenv(variable->name, variable->val, 0);\r
756                                         #endif\r
757                                 }\r
758                                 \r
759                                 xbt_os_mutex_release(unit->mutex);\r
760                                 \r
761                         }\r
762                 }\r
763                 else if(!strncmp(line,"unset ", strlen("unset ")))\r
764                 {\r
765                         unsigned int i;\r
766                         int exists = 0;\r
767                         int env = 0;\r
768                         int err = 0;\r
769                         variable_t variable;\r
770                         char* name = line + strlen("unset ");\r
771                         \r
772                         xbt_os_mutex_acquire(unit->mutex);\r
773 \r
774                         xbt_dynar_foreach(unit->runner->variables, i, variable)\r
775                         {\r
776                                 if(!strcmp(variable->name, name))\r
777                                 {\r
778                                         env = variable->env;\r
779                                         err = variable->err;\r
780                                         exists = 1;\r
781                                         break;\r
782                                 }\r
783                         }\r
784                                 \r
785                         if(!env)\r
786                         {\r
787                                 if(exists)\r
788                                         /*xbt_dynar_remove_at(unit->runner->variables, i, NULL);*/\r
789                                         xbt_dynar_cursor_rm(unit->runner->variables, &i);\r
790                                 else\r
791                                         WARN3("variable %s not found %s %s", name, line, filepos);      \r
792                         }\r
793                         else if(env)\r
794                                 WARN3("%s is an environment variable use unsetenv metacommand to delete it %s %s", name, line, filepos);        \r
795                         else\r
796                                 WARN3("%s is an error variable : you are not allowed to delete it %s %s", name, line, filepos);\r
797                         \r
798 \r
799                         xbt_os_mutex_release(unit->mutex);\r
800                                 \r
801                 }\r
802                 else\r
803                 {\r
804                         char* val;\r
805                         char name[PATH_MAX + 1] = {0};\r
806                         \r
807                         val = strchr(line, '=');\r
808                         \r
809                         if(val)\r
810                         {\r
811                                 variable_t variable;\r
812                                 int exists = 0;\r
813                                 unsigned int i;\r
814                                 val++;\r
815                                 \r
816                                 \r
817                                 /* syntax error */\r
818                                 if(val[0] == '\0')\r
819                                 {\r
820                                         ERROR2("Indefinite variable value %s %s", line, filepos);\r
821                                         syntax_error(unit);\r
822                                 }\r
823                                 \r
824                                 \r
825                                 /* assume it's a varibale */\r
826                                 strncpy(name, line, (val - line -1));\r
827                                 \r
828                                 xbt_os_mutex_acquire(unit->mutex);\r
829                                 \r
830                                 /* test if the variable is already registred */\r
831                                 xbt_dynar_foreach(unit->runner->variables, i, variable)\r
832                                 {\r
833                                         if(!strcmp(variable->name, name))\r
834                                         {\r
835                                                 exists = 1;\r
836                                                 break;\r
837                                         }\r
838                                 }\r
839                                 \r
840                                 /* if the variable is already registred, update its value;\r
841                                  * otherwise register it.\r
842                                  */\r
843                                 if(exists)\r
844                                 {\r
845                                         free(variable->val);\r
846                                         variable->val = strdup(val);\r
847                                 }\r
848                                 else\r
849                                 {\r
850                                         variable_t new_var = variable_new(name, val);\r
851                                         xbt_dynar_push(unit->runner->variables, &new_var);\r
852                                 }\r
853 \r
854                                         \r
855                                 xbt_os_mutex_release(unit->mutex);\r
856                                 \r
857                         }\r
858                         else \r
859                         {\r
860                                 ERROR2("%s: Malformed metacommand: %s",filepos,line);\r
861                                 syntax_error(unit);\r
862                                 return;\r
863                         }\r
864                 }\r
865                 \r
866                 \r
867                 break;\r
868         }\r
869 }\r
870 \r
871 void\r
872 fstream_handle_include(fstream_t fstream, context_t context, xbt_os_mutex_t mutex, const char* file_name, const char* description)\r
873 {\r
874         directory_t dir;\r
875         char* prev_directory = NULL;\r
876         fstream_t _fstream = NULL;\r
877         struct stat buffer = {0};\r
878         unit_t unit = fstream->unit;\r
879         \r
880         if(!stat(file_name, &buffer) && S_ISREG(buffer.st_mode))\r
881         {\r
882                 /* the file is in the current directory */\r
883                 _fstream = fstream_new(getcwd(NULL, 0), file_name);\r
884                 fstream_open(_fstream);\r
885         }\r
886         /* the file to include is not in the current directory, check if it is in a include directory */\r
887         else\r
888         {\r
889                 unsigned int i;\r
890                 prev_directory = getcwd(NULL, 0);\r
891                 \r
892                 xbt_dynar_foreach(include_dirs, i, dir)\r
893                 {\r
894                         chdir(dir->name);\r
895                         \r
896                         if(!stat(file_name, &buffer) && S_ISREG(buffer.st_mode))\r
897                         {\r
898                                 _fstream = fstream_new(dir->name, file_name);\r
899                                 fstream_open(_fstream);\r
900                                 break;\r
901                         }\r
902                 }\r
903 \r
904                 chdir(prev_directory);\r
905                 free(prev_directory);\r
906         }\r
907         \r
908         \r
909         \r
910         /* the file to include is not found handle the failure */\r
911         if(!_fstream)\r
912         {\r
913                 exit_code = EINCLUDENOTFOUND;\r
914                 ERROR1("Include file %s not found",file_name);\r
915                 failure(unit);\r
916         }\r
917         else\r
918         {\r
919                 \r
920                 if(!unit->is_running_suite)\r
921                 {/* it's the unit of a suite */\r
922                         unit_t include = unit_new(unit->runner,unit->root, unit, _fstream);\r
923                         \r
924                         include->mutex = unit->root->mutex;\r
925                 \r
926                         if(description)\r
927                                 include->description = strdup(description);\r
928                 \r
929                         xbt_dynar_push(unit->includes, &include);\r
930                 \r
931                         fstream_parse(_fstream, mutex);\r
932                 }\r
933                 else\r
934                 {/* it's a include */\r
935 \r
936                         unit_t* owner;\r
937                         unit_t include;\r
938 \r
939                         owner = xbt_dynar_get_ptr(unit->suites, xbt_dynar_length(unit->suites) - 1);\r
940                         \r
941                         include = unit_new(unit->runner,unit->root, *owner, _fstream);\r
942                         \r
943                         include->mutex = unit->root->mutex;\r
944                         \r
945                         if(description)\r
946                                 include->description = strdup(description);\r
947                 \r
948                         xbt_dynar_push((*owner)->includes, &include);\r
949                         fstream_parse(_fstream, mutex); \r
950                         \r
951                 }\r
952         }\r
953 }\r
954 \r
955 void\r
956 fstream_handle_suite(fstream_t fstream, context_t context, xbt_os_mutex_t mutex, const char* description)\r
957 {\r
958         unit_t unit = fstream->unit;\r
959         unit_t suite = unit_new(unit->runner, unit->root, unit, NULL);\r
960 \r
961         suite->description = strdup(description);\r
962         xbt_dynar_push(unit->suites, &suite);\r
963         unit->is_running_suite = 1;\r
964         \r
965 }\r
966 \r
967 \r
968 int\r
969 fstream_launch_command(fstream_t fstream, context_t context, xbt_os_mutex_t mutex)\r
970 {\r
971         unit_t unit = fstream->unit;\r
972         \r
973         /* TODO : check the parameters */\r
974         \r
975         if(!dry_run_flag)\r
976         {\r
977                 command_t command;\r
978                 \r
979                 if(!(command = command_new(unit, context, mutex)))\r
980                 {\r
981                         if(EINVAL == errno)\r
982                         {\r
983                                 ERROR2("Internal error : command_new() failed with the error %s (%d)",strerror(errno), errno);  \r
984                                 internal_error(unit);\r
985                                 return -1;\r
986                         }\r
987                         else if(ENOMEM == errno)\r
988                         {\r
989                                 ERROR1("System error : command_new() failed with the error code %d",errno);     \r
990                                 sys_error(unit);\r
991                                 return -1;\r
992                         }\r
993                 }\r
994                 \r
995                 if(command_run(command) < 0)\r
996                 {\r
997                         ERROR2("Internal error : command_run() failed with the error %s (%d)",strerror(errno), errno);  \r
998                         internal_error(unit);\r
999                         return -1;      \r
1000                 }\r
1001         }\r
1002         \r
1003         if(context_reset(context) < 0)\r
1004         {\r
1005                 ERROR2("Internal error : command_run() failed with the error %s (%d)",strerror(errno), errno);  \r
1006                 internal_error(unit);\r
1007                 return -1;      \r
1008         }\r
1009         \r
1010         return 0;\r
1011 }\r
1012 \r
1013 \r
1014 \r
1015 \r