2 * src/fstream.c - type representing the tesh file stream.
\r
4 * Copyright 2008,2009 Martin Quinson, Malek Cherier All right reserved.
\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
10 * This file contains all the definitions of the functions related with
\r
11 * the tesh file stream type.
\r
15 #include <fstream.h>
\r
17 #include <context.h>
\r
18 #include <command.h>
\r
20 #include <str_replace.h>
\r
21 #include <variable.h>
\r
23 #include <readline.h>
\r
28 #include <xsignal.h>
\r
33 XBT_LOG_EXTERNAL_DEFAULT_CATEGORY(tesh);
\r
38 long fstream_getline(fstream_t fstream, char **buf, size_t *n) {
\r
40 return readline(fstream->stream, buf, n);
\r
45 failure(unit_t unit)
\r
47 if(!keep_going_unit_flag)
\r
49 unit_t root = unit->root ? unit->root : unit;
\r
51 if(!root->interrupted)
\r
53 /* the unit interrupted (exit for the loop) */
\r
54 root->interrupted = 1;
\r
56 /* release the unit */
\r
57 xbt_os_sem_release(root->sem);
\r
60 /* if the --keep-going option is not specified */
\r
61 if(!keep_going_flag)
\r
65 /* request an global interruption by the runner */
\r
68 /* release the runner */
\r
69 xbt_os_sem_release(units_sem);
\r
76 fstream_new(const char* directory, const char* name)
\r
86 if(!directory && !strcmp("stdin", name))
\r
88 fstream = xbt_new0(s_fstream_t, 1);
\r
89 fstream->name = strdup("stdin");
\r
98 fstream = xbt_new0(s_fstream_t, 1);
\r
100 if(!(fstream->name = strdup(name)))
\r
106 if(!(fstream->directory = strdup(directory)))
\r
108 free(fstream->name);
\r
113 fstream->stream = NULL;
\r
114 fstream->unit = NULL;
\r
115 fstream->parsed = 0;
\r
122 fstream_open(fstream_t fstream)
\r
124 char path[PATH_MAX + 1] = {0};
\r
126 /* check the parameter */
\r
133 if(!fstream || fstream->stream)
\r
139 if(!strcmp(fstream->name, "stdin"))
\r
141 fstream->stream = stdin;
\r
146 sprintf(path,"%s/%s",fstream->directory, fstream->name);
\r
148 sprintf(path,"%s\\%s",fstream->directory, fstream->name);
\r
151 if(!(fstream->stream = fopen(path, "r")))
\r
160 fstream_close(fstream_t fstream)
\r
162 /* check the parameter */
\r
163 if(!(fstream) || !strcmp(fstream->name, "stdin") )
\r
169 if(!fstream->stream)
\r
172 if(EOF == fclose(fstream->stream))
\r
175 fstream->stream = NULL;
\r
181 fstream_free(fstream_t* ptr)
\r
184 /* check the parameter */
\r
195 fclose((*ptr)->stream);
\r
198 free((*ptr)->name);
\r
200 if((*ptr)->directory)
\r
201 free((*ptr)->directory);
\r
212 fstream_parse(fstream_t fstream, xbt_os_mutex_t mutex)
\r
215 char * line = NULL;
\r
217 char file_pos[256];
\r
218 xbt_strbuff_t buff;
\r
219 int buffbegin = 0;
\r
223 /* Count the line length while checking wheather it's blank */
\r
226 /* Deal with \ at the end of the line, and call handle_line on result */
\r
227 int to_be_continued;
\r
229 /* check the parameter */
\r
230 if(!(fstream) || !mutex)
\r
236 buff = xbt_strbuff_new();
\r
238 if(!(context = context_new()))
\r
241 unit = fstream->unit;
\r
243 /*while(!(unit->root->interrupted) && getline(&line, &len, fstream->stream) != -1)*/
\r
244 while(!(unit->root->interrupted) && fstream_getline(fstream, &line, &len) != -1)
\r
249 to_be_continued = 0;
\r
253 while(line[linelen] != '\0')
\r
255 if (line[linelen] != ' ' && line[linelen] != '\t' && line[linelen]!='\n' && line[linelen]!='\r')
\r
263 if(!context->command_line && (context->input->used || context->output->used))
\r
265 snprintf(file_pos,256,"%s:%d",fstream->name, line_num);
\r
266 ERROR1("[%s] Error : no command found in the last chunk of lines", file_pos);
\r
268 unit_set_error(fstream->unit, ESYNTAX, 1);
\r
273 else if(unit->is_running_suite)
\r
274 {/* it's the end of a suite */
\r
276 unit_t* current_suite = xbt_dynar_get_ptr(unit->suites, xbt_dynar_length(unit->suites) - 1);
\r
278 if(!xbt_dynar_length((*current_suite)->includes))
\r
280 ERROR2("[%s] Malformated suite `(%s)' : include missing", file_pos, (*current_suite)->description);
\r
282 unit_set_error(*current_suite, ESYNTAX, 1);
\r
288 unit->is_running_suite = 0;
\r
291 if(context->command_line)
\r
293 if(fstream_launch_command(fstream, context, mutex) < 0)
\r
300 if(linelen>1 && line[linelen-2]=='\\')
\r
302 if(linelen>2 && line[linelen-3] == '\\')
\r
304 /* Damn. Escaped \ */
\r
305 line[linelen-2] = '\n';
\r
306 line[linelen-1] = '\0';
\r
310 to_be_continued = 1;
\r
311 line[linelen-2] = '\0';
\r
315 buffbegin = line_num;
\r
319 if(buff->used || to_be_continued)
\r
321 xbt_strbuff_append(buff,line);
\r
323 if (!to_be_continued)
\r
325 snprintf(file_pos,256,"%s:%d",fstream->name, buffbegin);
\r
326 fstream_lex_line(fstream, context, mutex, file_pos, buff->data);
\r
327 xbt_strbuff_empty(buff);
\r
332 snprintf(file_pos,256,"%s:%d",fstream->name, line_num);
\r
333 fstream_lex_line(fstream, context, mutex, file_pos, line);
\r
337 /* Check that last command of the file ran well */
\r
338 if(context->command_line)
\r
340 if(fstream_launch_command(fstream, context, mutex) < 0)
\r
344 /* clear buffers */
\r
348 xbt_strbuff_free(buff);
\r
350 if(context_free(&context) < 0)
\r
353 return (exit_code || errno) ? -1 : 0;
\r
358 fstream_lex_line(fstream_t fstream, context_t context, xbt_os_mutex_t mutex, const char * filepos, char *line)
\r
361 variable_t variable;
\r
363 char name[VAR_NAME_MAX + 1] = {0};
\r
364 unit_t unit = fstream->unit;
\r
365 xbt_dynar_t variables = unit->runner->variables;
\r
367 if(unit->is_running_suite && strncmp(line, "! include", strlen("! include")))
\r
368 {/* it's the end of a suite */
\r
370 unit_t* current_suite = xbt_dynar_get_ptr(unit->suites, xbt_dynar_length(unit->suites) - 1);
\r
372 if(!xbt_dynar_length((*current_suite)->includes))
\r
373 ERROR2("[%s] Malformated suite `(%s)': include missing", filepos, (*current_suite)->description);
\r
375 ERROR2("[%s] Malformated suite `(%s)': blank line missing", filepos, (*current_suite)->description);
\r
377 unit_set_error(*current_suite, ESYNTAX, 1);
\r
379 failure(fstream->unit);
\r
384 context->line = strdup(filepos);
\r
388 xbt_str_rtrim(line + 2,"\n");
\r
390 line2 = strdup(line);
\r
392 /* replace each variable by its value */
\r
393 xbt_os_mutex_acquire(unit->mutex);
\r
395 xbt_dynar_foreach(variables, i, variable)
\r
397 sprintf(name, "$%s", variable->name);
\r
398 str_replace_all(&line2, name, variable->val);
\r
399 memset(name, 0, VAR_NAME_MAX + 1);
\r
402 xbt_os_mutex_release(unit->mutex);
\r
416 if(line2[0] == '$')
\r
417 ERROR1("[%s] Missing space after `$' `(usage : $ <command>)'", filepos);
\r
419 ERROR1("[%s] Missing space after & `(usage : & <command>)'", filepos);
\r
421 unit_set_error(fstream->unit, ESYNTAX, 1);
\r
427 context->async = (line2[0] == '&');
\r
430 /* further trim useless chars which are significant for in/output */
\r
431 xbt_str_rtrim(line2 + 2," \t");
\r
433 /* deal with CD commands here, not in context */
\r
434 if(!strncmp("cd ",line2 + 2, 3))
\r
436 char* dir = strdup(line2 + 4);
\r
438 if(context->command_line)
\r
440 if(fstream_launch_command(fstream, context, mutex) < 0)
\r
444 /* search begining */
\r
445 while(*(dir++) == ' ');
\r
452 INFO2("[%s] cd %s", filepos, dir);
\r
454 if(!just_print_flag)
\r
458 ERROR3("[%s] Chdir to %s failed: %s",filepos, dir,error_to_string(errno, 0));
\r
459 unit_set_error(fstream->unit, errno, 0);
\r
470 fstream_process_token(fstream, context, mutex, filepos, line2[0], line2 + 2);
\r
478 if(line[0] == '!' && line[1] != ' ')
\r
480 ERROR1("[%s] Missing space after `!' `(usage : ! <command> [[=]value])'", filepos);
\r
482 unit_set_error(fstream->unit, ESYNTAX, 1);
\r
488 fstream_process_token(fstream, context, mutex, filepos, line2[0], line2 + 2);
\r
497 char* prompt = line2 + 2;
\r
499 for(j = 0; j < strlen(prompt); j++)
\r
500 if (prompt[j] != ' ' && prompt[j] != '\t')
\r
505 ERROR1("[%s] Bad usage of the metacommand p `(usage : p <prompt>)'", filepos);
\r
507 unit_set_error(fstream->unit, ESYNTAX, 1);
\r
514 INFO2("[%s] %s",filepos,prompt);
\r
526 char* prompt = line2 + 2;
\r
528 for(j = 0; j < strlen(prompt); j++)
\r
529 if (prompt[j] != ' ' && prompt[j] != '\t')
\r
534 ERROR1("[%s] Bad usage of the metacommand P `(usage : P <prompt>)'", filepos);
\r
536 unit_set_error(fstream->unit, ESYNTAX, 1);
\r
543 CRITICAL2("[%s] %s",filepos, prompt);
\r
549 if(unit->description)
\r
550 WARN2("[%s] Description already specified `%s'",filepos, line2 + 2);
\r
556 char* desc = line2 + 2;
\r
558 for(j = 0; j < strlen(desc); j++)
\r
559 if (desc[j] != ' ' && desc[j] != '\t')
\r
564 ERROR1("[%s] Bad usage of the metacommand D `(usage : D <Description>)'", filepos);
\r
566 unit_set_error(fstream->unit, ESYNTAX, 1);
\r
572 unit->description = strdup(desc);
\r
577 ERROR2("[%s] Syntax error `%s'", filepos, line2);
\r
578 unit_set_error(fstream->unit, ESYNTAX, 1);
\r
587 fstream_process_token(fstream_t fstream, context_t context, xbt_os_mutex_t mutex, const char* filepos, char token, char *line)
\r
589 unit_t unit = fstream->unit;
\r
596 if(context->command_line)
\r
599 if(context->output->used || context->input->used)
\r
601 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
603 unit_set_error(fstream->unit, ESYNTAX, 1);
\r
608 if(fstream_launch_command(fstream, context, mutex) < 0)
\r
611 VERB1("[%s] More than one command in this chunk of lines",filepos);
\r
618 for(j = 0; j < strlen(line); j++)
\r
619 if (line[j] != ' ' && line[j] != '\t')
\r
625 ERROR1("[%s] Undefinite command for `$' `(usage: $ <command>)'", filepos);
\r
627 ERROR1("[%s] Undefinite command for `&' `(usage: & <command>)'", filepos);
\r
629 unit_set_error(fstream->unit, ESYNTAX, 1);
\r
636 context->command_line = strdup(line);
\r
637 context->line = /*strdup(filepos)*/ filepos;
\r
638 context->pos = strdup(filepos);
\r
642 xbt_strbuff_append(context->input,line);
\r
643 xbt_strbuff_append(context->input,"\n");
\r
647 xbt_strbuff_append(context->output,line);
\r
648 xbt_strbuff_append(context->output,"\n");
\r
653 if(context->command_line)
\r
655 if(fstream_launch_command(fstream, context, mutex) < 0)
\r
659 if(!strncmp(line,"timeout no",strlen("timeout no")))
\r
661 VERB1("[%s] (disable timeout)", filepos);
\r
662 context->timeout = INDEFINITE;
\r
664 else if(!strncmp(line,"timeout ",strlen("timeout ")))
\r
669 char* p = line + strlen("timeout ");
\r
672 for(j = 0; j < strlen(p); j++)
\r
673 if (p[j] != ' ' && p[j] != '\t')
\r
678 ERROR1("[%s] Undefinite timeout value `(usage :timeout <seconds>)'", filepos);
\r
680 unit_set_error(fstream->unit, ESYNTAX, 1);
\r
686 while(p[i] != '\0')
\r
690 ERROR2("[%s] Invalid timeout value `(%s)' : `(usage :timeout <seconds>)'", filepos, line + strlen("timeout "));
\r
692 unit_set_error(fstream->unit, ESYNTAX, 1);
\r
701 context->timeout = atoi(line + strlen("timeout"));
\r
702 VERB2("[%s] (new timeout value: %d)",filepos,context->timeout);
\r
705 else if (!strncmp(line,"expect signal ",strlen("expect signal ")))
\r
711 char* p = line + strlen("expect signal ");
\r
714 for(j = 0; j < strlen(p); j++)
\r
715 if (p[j] != ' ' && p[j] != '\t')
\r
720 ERROR1("[%s] Undefinite signal name `(usage :expect signal <signal name>)'", filepos);
\r
722 unit_set_error(fstream->unit, ESYNTAX, 1);
\r
728 context->signal = strdup(line + strlen("expect signal "));
\r
730 xbt_str_trim(context->signal," \n");
\r
733 if(!strstr("SIGSEGVSIGTRAPSIGBUSSIGFPESIGILL", context->signal))
\r
735 ERROR2("[%s] Signal `%s' not supported by this platform", filepos, context->signal);
\r
737 unit_set_error(fstream->unit, ESYNTAX, 1);
\r
744 if(!sig_exists(context->signal))
\r
746 ERROR2("[%s] Signal `%s' not supported by Tesh", filepos, context->signal);
\r
748 unit_set_error(fstream->unit, ESYNTAX, 1);
\r
758 VERB2("[%s] (next command must raise signal %s)", filepos, context->signal);
\r
761 else if (!strncmp(line,"expect return ",strlen("expect return ")))
\r
767 char* p = line + strlen("expect return ");
\r
770 for(j = 0; j < strlen(p); j++)
\r
771 if (p[j] != ' ' && p[j] != '\t')
\r
776 ERROR1("[%s] Undefinite return value `(usage :expect return <return value>)'", filepos);
\r
778 unit_set_error(fstream->unit, ESYNTAX, 1);
\r
784 while(p[i] != '\0')
\r
788 ERROR2("[%s] Invalid exit code value `(%s)' : must be an integer >= 0 and <=255", filepos, line + strlen("expect return "));
\r
790 unit_set_error(fstream->unit, ESYNTAX, 1);
\r
799 context->exit_code = atoi(line+strlen("expect return "));
\r
800 VERB2("[%s] (next command must return code %d)",filepos, context->exit_code);
\r
803 else if (!strncmp(line,"output ignore",strlen("output ignore")))
\r
805 context->output_handling = oh_ignore;
\r
806 VERB1("[%s] (ignore output of next command)", filepos);
\r
809 else if (!strncmp(line,"output display",strlen("output display")))
\r
811 context->output_handling = oh_display;
\r
812 VERB1("[%s] (ignore output of next command)", filepos);
\r
815 else if(!strncmp(line,"include ", strlen("include ")))
\r
820 p1 = line + strlen("include");
\r
822 while(*p1 == ' ' || *p1 == '\t')
\r
828 ERROR1("[%s] no file specified : `(usage : include <file> [<description>])'", filepos);
\r
830 unit_set_error(fstream->unit, ESYNTAX, 1);
\r
837 char file_name[PATH_MAX + 1] = {0};
\r
841 while(*p2 != '\0' && *p2 != ' ' && *p2 != '\t')
\r
844 strncpy(file_name, p1, p2 - p1);
\r
848 while(*p2 == ' ' || *p2 == '\t')
\r
851 fstream_handle_include(fstream, context, mutex, file_name, p2[0] != '\0' ? p2 : NULL);
\r
855 else if(!strncmp(line,"suite ", strlen("suite ")))
\r
859 char* p = line + strlen("suite ");
\r
862 for(j = 0; j < strlen(p); j++)
\r
863 if (p[j] != ' ' && p[j] != '\t')
\r
868 ERROR1("[%s] Undefinite suit description : `(usage : suite <description>)", filepos);
\r
870 unit_set_error(fstream->unit, ESYNTAX, 1);
\r
876 if(unit->is_running_suite)
\r
878 ERROR1("[%s] Suite already in progress", filepos);
\r
880 unit_set_error(fstream->unit, ESYNTAX, 1);
\r
886 fstream_handle_suite(fstream, line + strlen("suite "), filepos);
\r
888 else if(!strncmp(line,"unsetenv ", strlen("unsetenv ")))
\r
894 variable_t variable;
\r
897 char* name = line + strlen("unsetenv ");
\r
901 for(j = 0; j < strlen(name); j++)
\r
902 if (name[j] != ' ' && name[j] != '\t')
\r
907 ERROR1("[%s] Bad usage of the metacommand unsetenv : `(usage : unsetenv variable)'", filepos);
\r
909 unit_set_error(fstream->unit, ESYNTAX, 1);
\r
915 xbt_os_mutex_acquire(unit->mutex);
\r
918 xbt_dynar_foreach(unit->runner->variables, i, variable)
\r
920 if(!strcmp(variable->name, name))
\r
922 env = variable->env;
\r
923 err = variable->err;
\r
936 SetEnvironmentVariable(name, NULL);
\r
938 xbt_dynar_cursor_rm(unit->runner->variables, &i);
\r
942 ERROR2("[%s] `(%s)' environment variable not found : impossible to unset it",filepos, name);
\r
943 unit_set_error(fstream->unit, ESYNTAX, 1);
\r
944 xbt_os_mutex_release(unit->mutex);
\r
955 ERROR2("[%s] `(%s)' is not an environment variable : use `unset' instead `unsetenv'",filepos, name);
\r
956 unit_set_error(fstream->unit, ESYNTAX, 1);
\r
958 xbt_os_mutex_release(unit->mutex);
\r
963 ERROR2("[%s] `(%s)' is not an environment variable (it's a system variable) : impossible to unset it",filepos, name);
\r
964 unit_set_error(fstream->unit, ESYNTAX, 1);
\r
965 xbt_os_mutex_release(unit->mutex);
\r
972 ERROR2("[%s] `(%s)' environment variable not found : impossible to unset it",filepos, name);
\r
973 unit_set_error(fstream->unit, ESYNTAX, 1);
\r
974 xbt_os_mutex_release(unit->mutex);
\r
980 xbt_os_mutex_release(unit->mutex);
\r
984 else if(!strncmp(line,"setenv ", strlen("setenv ")))
\r
987 char name[PATH_MAX + 1] = {0};
\r
993 p = line + strlen("setenv ");
\r
995 val = strchr(p, '=');
\r
999 variable_t variable;
\r
1005 /* syntax error */
\r
1006 if(val[0] == '\0' || val[0] ==' ' || val[0] =='\t')
\r
1008 ERROR1("[%s] Bad usage of the metacommand setenv `(usage : setenv variable=value)'", filepos);
\r
1010 unit_set_error(fstream->unit, ESYNTAX, 1);
\r
1018 strncpy(name, p, (val - p -1));
\r
1022 for(j = 0; j < strlen(name); j++)
\r
1023 if (name[j] != ' ' && name[j] != '\t')
\r
1029 ERROR1("[%s] Bad usage of the metacommand setenv `(usage : setenv variable=value)'", filepos);
\r
1031 unit_set_error(fstream->unit, ESYNTAX, 1);
\r
1037 /* test if the variable is already registred */
\r
1038 xbt_os_mutex_acquire(unit->mutex);
\r
1040 xbt_dynar_foreach(unit->runner->variables, i, variable)
\r
1042 if(!strcmp(variable->name, name))
\r
1044 env = variable->env;
\r
1045 err = variable->err;
\r
1051 /* if the variable is already registred, update its value;
\r
1052 * otherwise register it.
\r
1058 if(!strcmp(val, variable->val))
\r
1059 WARN3("[%s] This environment variable `(%s)' is already set with the value `(%s)'", filepos, name, val);
\r
1061 free(variable->val);
\r
1062 variable->val = strdup(val);
\r
1065 SetEnvironmentVariable(variable->name, variable->val);
\r
1067 setenv(variable->name, variable->val, 1);
\r
1073 ERROR2("[%s] Conflict : a system variable `(%s)' already exists", filepos, name);
\r
1075 ERROR2("[%s] Conflict : (none environment) variable `(%s)' already exists", filepos, name);
\r
1077 unit_set_error(fstream->unit, ESYNTAX, 1);
\r
1078 xbt_os_mutex_release(unit->mutex);
\r
1087 ERROR2("[%s] A system variable named `(%s)' already exists", filepos, name);
\r
1089 unit_set_error(fstream->unit, ESYNTAX, 1);
\r
1090 xbt_os_mutex_release(unit->mutex);
\r
1096 variable = variable_new(name, val);
\r
1097 variable->env = 1;
\r
1099 xbt_dynar_push(unit->runner->variables, &variable);
\r
1102 SetEnvironmentVariable(variable->name, variable->val);
\r
1104 setenv(variable->name, variable->val, 0);
\r
1109 xbt_os_mutex_release(unit->mutex);
\r
1114 ERROR1("[%s] Bad usage of the metacommand setenv `(usage : setenv variable=value)'", filepos);
\r
1116 unit_set_error(fstream->unit, ESYNTAX, 1);
\r
1121 else if(!strncmp(line,"unset ", strlen("unset ")))
\r
1123 unsigned int i, j;
\r
1127 variable_t variable;
\r
1130 char* name = line + strlen("unset ");
\r
1134 for(j = 0; j < strlen(name); j++)
\r
1135 if (name[j] != ' ' && name[j] != '\t')
\r
1141 ERROR1("[%s] Bad usage of the metacommand unset `(usage : unset variable)'", filepos);
\r
1143 unit_set_error(fstream->unit, ESYNTAX, 1);
\r
1150 xbt_os_mutex_acquire(unit->mutex);
\r
1152 xbt_dynar_foreach(unit->runner->variables, i, variable)
\r
1154 if(!strcmp(variable->name, name))
\r
1156 env = variable->env;
\r
1157 err = variable->err;
\r
1166 /*xbt_dynar_remove_at(unit->runner->variables, i, NULL);*/
\r
1167 xbt_dynar_cursor_rm(unit->runner->variables, &i);
\r
1170 ERROR2("[%s] `(%s)' variable not found",filepos, name);
\r
1171 unit_set_error(fstream->unit, ESYNTAX, 1);
\r
1172 xbt_os_mutex_release(unit->mutex);
\r
1179 ERROR2("[%s] `(%s)' is an environment variable use `unsetenv' instead `unset'",filepos, name);
\r
1180 unit_set_error(fstream->unit, ESYNTAX, 1);
\r
1181 xbt_os_mutex_release(unit->mutex);
\r
1187 ERROR2("[%s] `(%s)' is system variable : you can unset it",filepos, name);
\r
1188 unit_set_error(fstream->unit, ESYNTAX, 1);
\r
1189 xbt_os_mutex_release(unit->mutex);
\r
1194 xbt_os_mutex_release(unit->mutex);
\r
1197 else if(!strncmp(line,"set ", strlen("set ")))
\r
1200 char name[PATH_MAX + 1] = {0};
\r
1204 val = strchr(line + strlen("set "), '=');
\r
1208 variable_t variable;
\r
1217 /* syntax error */
\r
1218 if(val[0] == '\0')
\r
1220 ERROR1("[%s] Bad usage of the metacommand set `(usage : set variable=value)'", filepos);
\r
1222 unit_set_error(fstream->unit, ESYNTAX, 1);
\r
1227 else if(val[0] ==' ' || val[0] =='\t')
\r
1229 strncpy(name, line + strlen("set "), (val - (line + strlen("set "))));
\r
1231 ERROR2("[%s] No space avaible after`(%s)'", filepos, name);
\r
1233 unit_set_error(fstream->unit, ESYNTAX, 1);
\r
1240 /* assume it's a varibale */
\r
1242 strncpy(name, line + strlen("set "), (val - (line + strlen("set ")) -1));
\r
1246 for(j = 0; j < strlen(name); j++)
\r
1247 if (name[j] != ' ' && name[j] != '\t')
\r
1253 ERROR1("[%s] Bad usage of the metacommand set `(usage : set variable=value)'", filepos);
\r
1255 unit_set_error(fstream->unit, ESYNTAX, 1);
\r
1261 xbt_os_mutex_acquire(unit->mutex);
\r
1263 /* test if the variable is already registred */
\r
1264 xbt_dynar_foreach(unit->runner->variables, i, variable)
\r
1266 if(!strcmp(variable->name, name))
\r
1269 err = variable->err;
\r
1270 env = variable->env;
\r
1275 /* if the variable is already registred, update its value (if same value warns);
\r
1276 * otherwise register it.
\r
1282 ERROR2("[%s] A system variable named `(%s)' already exists", filepos, name);
\r
1284 unit_set_error(fstream->unit, ESYNTAX, 1);
\r
1285 xbt_os_mutex_release(unit->mutex);
\r
1292 ERROR2("[%s] `(%s)' is an environment variable use `setenv' instead `set'", filepos, name);
\r
1294 unit_set_error(fstream->unit, ESYNTAX, 1);
\r
1295 xbt_os_mutex_release(unit->mutex);
\r
1302 if(!strcmp(val, variable->val))
\r
1303 WARN3("[%s] Variable `(%s)' already contains value `<%s>'",filepos, variable->name, val);
\r
1305 free(variable->val);
\r
1306 variable->val = strdup(val);
\r
1311 variable_t new_var = variable_new(name, val);
\r
1312 xbt_dynar_push(unit->runner->variables, &new_var);
\r
1316 xbt_os_mutex_release(unit->mutex);
\r
1320 ERROR1("[%s] Bad usage of the metacommand set `(usage : set variable=value)'", filepos);
\r
1322 unit_set_error(fstream->unit, ESYNTAX, 1);
\r
1328 {/* assume it's a variable */
\r
1330 char name[PATH_MAX + 1] = {0};
\r
1331 unsigned int i, j;
\r
1334 val = strchr(line, '=');
\r
1338 variable_t variable;
\r
1345 /* syntax error */
\r
1346 if(val[0] == '\0')
\r
1348 strncpy(name, line, (val - line -1));
\r
1352 for(j = 0; j < strlen(name); j++)
\r
1353 if (name[j] != ' ' && name[j] != '\t')
\r
1357 ERROR1("[%s] Bad usage of Tesh variable mechanism `(usage : variable=value)'", filepos);
\r
1358 else if(!strcmp("setenv", name))
\r
1359 ERROR1("[%s] Bad usage of the metacommand setenv `(usage : setenv variable=value)'", filepos);
\r
1360 else if(!strcmp("set", name))
\r
1361 ERROR1("[%s] Bad usage of the metacommand set `(usage : set variable=value)'", filepos);
\r
1363 ERROR2("[%s] Undefined variable `(%s)'", filepos, name);
\r
1365 unit_set_error(fstream->unit, ESYNTAX, 1);
\r
1370 else if(val[0] ==' ' || val[0] =='\t')
\r
1372 strncpy(name, line, (val - line));
\r
1374 ERROR2("[%s] No space avaible after`(%s)'", filepos, name);
\r
1376 unit_set_error(fstream->unit, ESYNTAX, 1);
\r
1382 /* assume it's a varibale */
\r
1384 strncpy(name, line, (val - line -1));
\r
1388 for(j = 0; j < strlen(name); j++)
\r
1389 if (name[j] != ' ' && name[j] != '\t')
\r
1395 ERROR1("[%s] Bad usage of Tesh variable capability `(usage : variable=value)'", filepos);
\r
1397 unit_set_error(fstream->unit, ESYNTAX, 1);
\r
1403 if(!strcmp("set", name))
\r
1405 ERROR1("[%s] Bad usage of the metacommand set `(usage : set variable=value)'", filepos);
\r
1407 unit_set_error(fstream->unit, ESYNTAX, 1);
\r
1411 else if(!strcmp("setenv", name))
\r
1413 ERROR1("[%s] Bad usage of the metacommand setenv `(usage : setenv variable=value)'", filepos);
\r
1415 unit_set_error(fstream->unit, ESYNTAX, 1);
\r
1420 xbt_os_mutex_acquire(unit->mutex);
\r
1422 /* test if the variable is already registred */
\r
1423 xbt_dynar_foreach(unit->runner->variables, i, variable)
\r
1425 if(!strcmp(variable->name, name))
\r
1428 err = variable->err;
\r
1429 env = variable->env;
\r
1434 /* if the variable is already registred, update its value (if same value warns);
\r
1435 * otherwise register it.
\r
1441 ERROR2("[%s] A system variable named `(%s)' already exists", filepos, name);
\r
1443 unit_set_error(fstream->unit, ESYNTAX, 1);
\r
1444 xbt_os_mutex_release(unit->mutex);
\r
1450 ERROR2("[%s] `(%s)' is an environment variable use `setenv' metacommand", filepos, name);
\r
1452 unit_set_error(fstream->unit, ESYNTAX, 1);
\r
1453 xbt_os_mutex_release(unit->mutex);
\r
1460 if(!strcmp(val, variable->val))
\r
1461 WARN3("[%s] Variable `(%s)' already contains value `<%s>'",filepos, variable->name, val);
\r
1463 free(variable->val);
\r
1464 variable->val = strdup(val);
\r
1469 variable_t new_var = variable_new(name, val);
\r
1470 xbt_dynar_push(unit->runner->variables, &new_var);
\r
1474 xbt_os_mutex_release(unit->mutex);
\r
1479 if(!strncmp("setenv", line, strlen("setenv")))
\r
1480 ERROR1("[%s] Bad usage of the metacommand setenv : `(usage : setenv variable=value)'", filepos);
\r
1481 else if(!strncmp("set", line, strlen("set")))
\r
1482 ERROR1("[%s] Bad usage of the metacommand set : `(usage : set variable=value)'", filepos);
\r
1483 else if(!strncmp("unsetenv", line, strlen("unsetenv")))
\r
1484 ERROR1("[%s] Bad usage of the metacommand unsetenv : `(usage : unsetenv variable)'", filepos);
\r
1485 else if(!strncmp("unset", line, strlen("unset")))
\r
1486 ERROR1("[%s] Bad usage of the metacommand unset : `(usage : unset variable)'", filepos);
\r
1487 else if(!strncmp("timeout", line, strlen("timeout")))
\r
1488 ERROR1("[%s] Bad usage of the metacommand timeout : `(usage : timeout <integral positive integer>)'", filepos);
\r
1489 else if(!strncmp("expect signal", line, strlen("expect signal")))
\r
1490 ERROR1("[%s] Bad usage of the metacommand expect signal : `(usage : expect signal <sig_name>)'", filepos);
\r
1491 else if(!strncmp("expect return", line, strlen("expect return")))
\r
1492 ERROR1("[%s] Bad usage of the metacommand expect return : `(usage : expect return <return value (>=0 <=255)>)'", filepos);
\r
1493 else if(!strncmp("include", line, strlen("include")))
\r
1494 ERROR1("[%s] Bad usage of the metacommand include :`(usage : include <file> [<description>])'", filepos);
\r
1495 else if(!strncmp("suite", line, strlen("suite")))
\r
1496 ERROR1("[%s] Bad usage of the metacommand suite : `(usage : suite <description>)'", filepos);
\r
1498 ERROR2("[%s] Unknown metacommand: `%s'",filepos,line);
\r
1500 unit_set_error(fstream->unit, ESYNTAX, 1);
\r
1512 fstream_handle_include(fstream_t fstream, context_t context, xbt_os_mutex_t mutex, const char* file_name, const char* description)
\r
1515 char* prev_directory = NULL;
\r
1516 fstream_t _fstream = NULL;
\r
1517 struct stat buffer = {0};
\r
1518 unit_t unit = fstream->unit;
\r
1520 if(!stat(file_name, &buffer) && S_ISREG(buffer.st_mode))
\r
1522 /* the file is in the current directory */
\r
1523 _fstream = fstream_new(getcwd(NULL, 0), file_name);
\r
1524 fstream_open(_fstream);
\r
1526 /* the file to include is not in the current directory, check if it is in a include directory */
\r
1530 prev_directory = getcwd(NULL, 0);
\r
1532 xbt_dynar_foreach(include_dirs, i, dir)
\r
1536 if(!stat(file_name, &buffer) && S_ISREG(buffer.st_mode))
\r
1538 _fstream = fstream_new(dir->name, file_name);
\r
1539 fstream_open(_fstream);
\r
1544 chdir(prev_directory);
\r
1545 free(prev_directory);
\r
1548 /* the file to include is not found handle the failure */
\r
1551 if(file_name[0] == '$')
\r
1553 ERROR3("[%s] Include file `(%s)' not found or variable `(%s)' doesn't exist",context->line, file_name, file_name + 1);
\r
1559 /* may be a variable */
\r
1560 variable_t variable;
\r
1564 xbt_dynar_foreach(unit->runner->variables, i, variable)
\r
1566 if(!strcmp(variable->name, file_name))
\r
1574 ERROR3("[%s] Include file `(%s)' not found (if you want to use the variable <%s> add the prefix `$')",context->line, file_name, file_name);
\r
1576 ERROR2("[%s] Include file `(%s)' not found",context->line, file_name);
\r
1579 unit_set_error(fstream->unit, EINCLUDENOTFOUND, 1);
\r
1585 if(!unit->is_running_suite)
\r
1586 {/* it's the unit of a suite */
\r
1587 unit_t include = unit_new(unit->runner, unit->root, unit, _fstream);
\r
1589 include->mutex = unit->root->mutex;
\r
1592 include->description = strdup(description);
\r
1594 xbt_dynar_push(unit->includes, &include);
\r
1597 INFO1("Include from %s", _fstream->name);
\r
1599 INFO1("Checking include %s...",_fstream->name);
\r
1601 fstream_parse(_fstream, mutex);
\r
1604 {/* it's a include */
\r
1609 owner = xbt_dynar_get_ptr(unit->suites, xbt_dynar_length(unit->suites) - 1);
\r
1611 include = unit_new(unit->runner, unit->root, *owner, _fstream);
\r
1613 include->mutex = unit->root->mutex;
\r
1616 include->description = strdup(description);
\r
1618 xbt_dynar_push((*owner)->includes, &include);
\r
1621 INFO1("Include from %s", _fstream->name);
\r
1623 INFO1("Checking include %s...",_fstream->name);
\r
1625 fstream_parse(_fstream, mutex);
\r
1631 fstream_handle_suite(fstream_t fstream, const char* description, const char* filepos)
\r
1633 unit_t unit = fstream->unit;
\r
1634 unit_t suite = unit_new(unit->runner, unit->root, unit, NULL);
\r
1637 suite->description = strdup(description);
\r
1639 suite->filepos = strdup(filepos);
\r
1641 xbt_dynar_push(unit->suites, &suite);
\r
1642 unit->is_running_suite = 1;
\r
1645 INFO1("Test suite %s", description);
\r
1647 INFO1("Checking suite %s...",description);
\r
1652 fstream_launch_command(fstream_t fstream, context_t context, xbt_os_mutex_t mutex)
\r
1654 unit_t unit = fstream->unit;
\r
1658 command_t command;
\r
1660 if(!(command = command_new(unit, context, mutex)))
\r
1662 if(EINVAL == errno)
\r
1664 ERROR3("[%s] Cannot instantiate the command `%s' (%d)",context->pos, strerror(errno), errno);
\r
1666 unit_set_error(unit, errno, 0);
\r
1670 else if(ENOMEM == errno)
\r
1672 ERROR3("[%s] Cannot instantiate the command `%s' (%d)",context->pos, strerror(errno), errno);
\r
1674 unit_set_error(unit, errno, 0);
\r
1681 if(command_run(command) < 0)
\r
1683 ERROR3("[%s] Cannot run the command `%s' (%d)",context->pos, strerror(errno), errno);
\r
1684 unit_set_error(unit, errno, 0);
\r
1690 if(context_reset(context) < 0)
\r
1692 ERROR3("[%s] Cannot reset the context of the command `%s' (%d)",context->pos, strerror(errno), errno);
\r
1694 unit_set_error(fstream->unit, errno, 0);
\r