-#include <fstream.h>
-#include <errno.h>
-#include <context.h>
-#include <command.h>
-#include <unit.h>
-
-XBT_LOG_EXTERNAL_DEFAULT_CATEGORY(tesh);
-
-fstream_t
-fstream_new(const char* directory, const char* name)
-{
- fstream_t fstream;
- /*struct stat buffer = {0};*/
-
- if(!name)
- {
- errno = EINVAL;
- return NULL;
- }
-
- if(!directory && !strcmp("stdin", name))
- {
- fstream = xbt_new0(s_fstream_t, 1);
- fstream->name = strdup("stdin");
- return fstream;
- }
- else if(!directory)
- {
- errno = EINVAL;
- return NULL;
- }
-
- /*if(stat(name, &buffer))
- return NULL;
-
- if(!S_ISREG(buffer.st_mode))
- {
- errno = ENOENT;
- return NULL;
- }*/
-
- fstream = xbt_new0(s_fstream_t, 1);
-
- fstream->name = strdup(name);
-
- fstream->directory = strdup(directory);
- fstream->stream = NULL;
-
-
- return fstream;
-}
-
-int
-fstream_open(fstream_t fstream)
-{
- if(!fstream || fstream->stream)
- return EINVAL;
-
- if(!strcmp(fstream->name, "stdin"))
- {
- fstream->stream = stdin;
- return 0;
- }
-
- if(!(fstream->stream = fopen(fstream->name, "r")))
- return errno;
-
- return 0;
-}
-
-int
-fstream_close(fstream_t fstream)
-{
- if(!fstream || !strcmp(fstream->name, "stdin"))
- return EINVAL;
-
- if(!fstream->stream)
- return EBADF;
-
- fclose(fstream->stream);
- fstream->stream = NULL;
- return errno;
-}
-
-int
-fstream_free(void** fstreamptr)
-{
- if(!(*fstreamptr))
- return EINVAL;
-
- if((*((fstream_t*)fstreamptr))->stream)
- fclose((*((fstream_t*)fstreamptr))->stream);
-
- free((*((fstream_t*)fstreamptr))->name);
-
- if((*((fstream_t*)fstreamptr))->directory)
- free((*((fstream_t*)fstreamptr))->directory);
-
- free(*fstreamptr);
-
- *fstreamptr = NULL;
-
- return 0;
-
-}
-
-void
-fstream_parse( fstream_t fstream, unit_t unit)
-{
- size_t len;
- char * line = NULL;
- int line_num = 0;
- char file_pos[256];
- xbt_strbuff_t buff;
- int buffbegin = 0;
- context_t context;
- xbt_os_mutex_t mutex = unit->mutex;
-
- /* Count the line length while checking wheather it's blank */
- int blankline;
- int linelen;
- /* Deal with \ at the end of the line, and call handle_line on result */
- int to_be_continued;
-
- buff=xbt_strbuff_new();
- context = context_new();
-
- while(!unit->interrupted && getline(&line, &len, fstream->stream) != -1)
- {
- blankline=1;
- linelen = 0;
- to_be_continued = 0;
-
- line_num++;
-
- while(line[linelen] != '\0')
- {
- if (line[linelen] != ' ' && line[linelen] != '\t' && line[linelen]!='\n' && line[linelen]!='\r')
- blankline = 0;
-
- linelen++;
- }
-
- if(blankline)
- {
- if(!context->command_line && (context->input->used || context->output->used))
- {
- ERROR1("[%d] Error: no command found in this chunk of lines.",buffbegin);
-
- if(unit->parsing_include_file)
- ERROR1("Unit `%s': NOK (syntax error)", fstream->name);
- else
- ERROR2("Unit `%s' inclued in `%s' : NOK (syntax error)", fstream->name, fstream->name);
-
- exit_code = ESYNTAX;
- unit_handle_failure(unit);
- break;
- }
-
- if(context->command_line)
- {
- if(!want_dry_run)
- {
- command_t command = command_new(unit, context, mutex);
- command_run(command);
- }
-
- context_reset(context);
- }
-
-
- continue;
-
- }
-
- if(linelen>1 && line[linelen-2]=='\\')
- {
- if (linelen>2 && line[linelen-3] == '\\')
- {
- /* Damn. Escaped \ */
- line[linelen-2] = '\n';
- line[linelen-1] = '\0';
- }
- else
- {
- to_be_continued = 1;
- line[linelen-2] = '\0';
- linelen -= 2;
-
- if (!buff->used)
- buffbegin = line_num;
- }
- }
-
- if(buff->used || to_be_continued)
- {
- xbt_strbuff_append(buff,line);
-
- if (!to_be_continued)
- {
- snprintf(file_pos,256,"%s:%d",fstream->name, buffbegin);
- unit_handle_line(unit, context, mutex, file_pos, buff->data);
- xbt_strbuff_empty(buff);
- }
- }
- else
- {
- snprintf(file_pos,256,"%s:%d",fstream->name, line_num);
- unit_handle_line(unit, context, mutex, file_pos, line);
- }
- }
-
- /* Check that last command of the file ran well */
- if(context->command_line)
- {
- if(!want_dry_run)
- {
- command_t command = command_new(unit, context, mutex);
- command_run(command);
- }
-
- context_reset(context);
- }
-
- /* Clear buffers */
- if (line)
- free(line);
-
- xbt_strbuff_free(buff);
-}
-
-
+/*\r
+ * src/fstream.c - type representing the tesh file stream.\r
+ *\r
+ * Copyright 2008,2009 Martin Quinson, Malek Cherier All right reserved. \r
+ *\r
+ * This program is free software; you can redistribute it and/or modify it \r
+ * under the terms of the license (GNU LGPL) which comes with this package.\r
+ *\r
+ * Purpose:\r
+ * This file contains all the definitions of the functions related with\r
+ * the tesh file stream type.\r
+ *\r
+ */\r
+\r
+#include <fstream.h>\r
+#include <xerrno.h>\r
+#include <context.h>\r
+#include <command.h>\r
+#include <unit.h>\r
+#include <str_replace.h>\r
+#include <variable.h>\r
+\r
+#include <readline.h>\r
+\r
+#include <is_cmd.h>\r
+#include <getpath.h>\r
+\r
+#ifndef WIN32\r
+#include <xsignal.h>\r
+#endif\r
+\r
+#ifdef WIN32\r
+static int\r
+is_w32_cmd(char* cmd, char** path)\r
+{\r
+ size_t i = 0;\r
+ struct stat stat_buff = {0};\r
+ char buff[PATH_MAX + 1] = {0};\r
+ \r
+\r
+\r
+ if(!cmd)\r
+ {\r
+ errno = EINVAL;\r
+ return 0;\r
+ }\r
+ \r
+ if(stat(cmd, &stat_buff) || !S_ISREG(stat_buff.st_mode))\r
+ {\r
+ if(path)\r
+ {\r
+ for (i = 0; path[i] != NULL; i++)\r
+ {\r
+ /* use Cat.exe on Windows */\r
+ if(!strcmp(cmd, "cat"))\r
+ cmd[0] = 'C';\r
+ \r
+ sprintf(buff,"%s\\%s",path[i], cmd);\r
+ \r
+ if(!stat(buff, &stat_buff) && S_ISREG(stat_buff.st_mode))\r
+ return 1;\r
+ }\r
+ }\r
+ }\r
+ else\r
+ return 1;\r
+ \r
+\r
+ return 0;\r
+}\r
+#endif\r
+\r
+\r
+XBT_LOG_EXTERNAL_DEFAULT_CATEGORY(tesh);\r
+\r
+\r
+long fstream_getline(fstream_t fstream, char **buf, size_t *n) {\r
+\r
+ return readline(fstream->stream, buf, n);\r
+ \r
+}\r
+\r
+static void\r
+failure(unit_t unit)\r
+{\r
+ if(!keep_going_unit_flag)\r
+ {\r
+ unit_t root = unit->root ? unit->root : unit;\r
+ \r
+ if(!root->interrupted)\r
+ {\r
+ /* the unit interrupted (exit for the loop) */\r
+ root->interrupted = 1;\r
+\r
+ /* release the unit */\r
+ xbt_os_sem_release(root->sem);\r
+ }\r
+\r
+ /* if the --keep-going option is not specified */\r
+ if(!keep_going_flag)\r
+ {\r
+ if(!interrupted)\r
+ {\r
+ /* request an global interruption by the runner */\r
+ interrupted = 1;\r
+\r
+ /* release the runner */\r
+ xbt_os_sem_release(units_sem);\r
+ }\r
+ }\r
+ }\r
+}\r
+\r
+fstream_t\r
+fstream_new(const char* directory, const char* name)\r
+{\r
+ fstream_t fstream;\r
+ \r
+ if(!name)\r
+ {\r
+ errno = EINVAL;\r
+ return NULL;\r
+ }\r
+ \r
+ if(!directory && !strcmp("stdin", name))\r
+ {\r
+ fstream = xbt_new0(s_fstream_t, 1);\r
+ fstream->name = strdup("stdin");\r
+ return fstream;\r
+ }\r
+ else if(!directory)\r
+ {\r
+ errno = EINVAL;\r
+ return NULL;\r
+ }\r
+ \r
+ fstream = xbt_new0(s_fstream_t, 1);\r
+ \r
+ if(!(fstream->name = strdup(name)))\r
+ {\r
+ free(fstream);\r
+ return NULL;\r
+ }\r
+ \r
+ if(!(fstream->directory = strdup(directory)))\r
+ {\r
+ free(fstream->name);\r
+ free(fstream);\r
+ return NULL;\r
+ }\r
+ \r
+ fstream->stream = NULL;\r
+ fstream->unit = NULL;\r
+ fstream->parsed = 0;\r
+ \r
+ \r
+ return fstream;\r
+}\r
+\r
+int\r
+fstream_open(fstream_t fstream)\r
+{\r
+ char path[PATH_MAX + 1] = {0};\r
+ \r
+ /* check the parameter */\r
+ if(!(fstream))\r
+ {\r
+ errno = EINVAL;\r
+ return -1;\r
+ }\r
+ \r
+ if(!fstream || fstream->stream)\r
+ {\r
+ errno = EALREADY;\r
+ return -1;\r
+ }\r
+ \r
+ if(!strcmp(fstream->name, "stdin"))\r
+ {\r
+ fstream->stream = stdin;\r
+ return 0;\r
+ }\r
+ \r
+ #ifndef WIN32\r
+ sprintf(path,"%s/%s",fstream->directory, fstream->name);\r
+ #else\r
+ sprintf(path,"%s\\%s",fstream->directory, fstream->name);\r
+ #endif\r
+\r
+ if(!(fstream->stream = fopen(path, "r")))\r
+ {\r
+ return -1;\r
+ }\r
+ \r
+ return 0;\r
+}\r
+\r
+int\r
+fstream_close(fstream_t fstream)\r
+{\r
+ /* check the parameter */\r
+ if(!(fstream) || !strcmp(fstream->name, "stdin") )\r
+ {\r
+ errno = EINVAL;\r
+ return -1;\r
+ }\r
+ \r
+ if(!fstream->stream)\r
+ return EBADF; \r
+ \r
+ if(EOF == fclose(fstream->stream))\r
+ return -1;\r
+ \r
+ fstream->stream = NULL;\r
+ \r
+ return 0;\r
+}\r
+\r
+int\r
+fstream_free(fstream_t* ptr)\r
+{\r
+ \r
+ /* check the parameter */\r
+ if(!(*ptr))\r
+ {\r
+ errno = EINVAL;\r
+ return -1;\r
+ }\r
+ \r
+ if(!(*ptr))\r
+ return EINVAL;\r
+ \r
+ if((*ptr)->stream)\r
+ fclose((*ptr)->stream);\r
+ \r
+ if((*ptr)->name)\r
+ free((*ptr)->name);\r
+ \r
+ if((*ptr)->directory)\r
+ free((*ptr)->directory);\r
+ \r
+ free(*ptr);\r
+\r
+ *ptr = NULL;\r
+ \r
+ return 0;\r
+ \r
+}\r
+\r
+int\r
+fstream_parse(fstream_t fstream, xbt_os_mutex_t mutex)\r
+{\r
+ size_t len;\r
+ char * line = NULL;\r
+ int line_num = 0;\r
+ char file_pos[256];\r
+ xbt_strbuff_t buff;\r
+ int buffbegin = 0; \r
+ context_t context;\r
+ unit_t unit;\r
+ \r
+ /* Count the line length while checking wheather it's blank */\r
+ int blankline;\r
+ int linelen; \r
+ /* Deal with \ at the end of the line, and call handle_line on result */\r
+ int to_be_continued;\r
+ \r
+ /* check the parameter */\r
+ if(!(fstream) || !mutex)\r
+ {\r
+ errno = EINVAL;\r
+ return -1;\r
+ }\r
+ \r
+ buff = xbt_strbuff_new();\r
+ \r
+ if(!(context = context_new()))\r
+ return -1;\r
+ \r
+ unit = fstream->unit;\r
+ \r
+ /*while(!(unit->root->interrupted) && getline(&line, &len, fstream->stream) != -1)*/\r
+ while(!(unit->root->interrupted) && fstream_getline(fstream, &line, &len) != -1)\r
+ {\r
+ \r
+ blankline=1;\r
+ linelen = 0; \r
+ to_be_continued = 0;\r
+\r
+ line_num++;\r
+ \r
+ while(line[linelen] != '\0') \r
+ {\r
+ if (line[linelen] != ' ' && line[linelen] != '\t' && line[linelen]!='\n' && line[linelen]!='\r')\r
+ blankline = 0;\r
+ \r
+ linelen++;\r
+ }\r
+ \r
+ if(blankline) \r
+ {\r
+ if(!context->command_line && (context->input->used || context->output->used))\r
+ {\r
+ snprintf(file_pos,256,"%s:%d",fstream->name, line_num);\r
+ ERROR1("[%s] Error : no command found in the last chunk of lines", file_pos);\r
+ \r
+ unit_set_error(fstream->unit, ESYNTAX, 1, file_pos);\r
+\r
+ failure(unit);\r
+ break;\r
+ }\r
+ else if(unit->is_running_suite)\r
+ {/* it's the end of a suite */\r
+ \r
+ unit_t* current_suite = xbt_dynar_get_ptr(unit->suites, xbt_dynar_length(unit->suites) - 1);\r
+\r
+ if(!xbt_dynar_length((*current_suite)->includes))\r
+ {\r
+ ERROR2("[%s] Malformated suite `(%s)' : include missing", file_pos, (*current_suite)->description);\r
+ \r
+ unit_set_error(*current_suite, ESYNTAX, 1, file_pos);\r
+\r
+ failure(unit);\r
+ \r
+ }\r
+ \r
+ unit->is_running_suite = 0;\r
+ }\r
+ \r
+ if(context->command_line)\r
+ {\r
+ if(fstream_launch_command(fstream, context, mutex) < 0)\r
+ break;\r
+ }\r
+ \r
+ continue;\r
+ }\r
+ \r
+ if(linelen>1 && line[linelen-2]=='\\') \r
+ {\r
+ if(linelen>2 && line[linelen-3] == '\\') \r
+ {\r
+ /* Damn. Escaped \ */\r
+ line[linelen-2] = '\n';\r
+ line[linelen-1] = '\0';\r
+ } \r
+ else \r
+ {\r
+ to_be_continued = 1;\r
+ line[linelen-2] = '\0';\r
+ linelen -= 2; \r
+ \r
+ if (!buff->used)\r
+ buffbegin = line_num;\r
+ }\r
+ }\r
+ \r
+ if(buff->used || to_be_continued) \r
+ { \r
+ xbt_strbuff_append(buff,line);\r
+ \r
+ if (!to_be_continued) \r
+ {\r
+ snprintf(file_pos,256,"%s:%d",fstream->name, buffbegin);\r
+ fstream_lex_line(fstream, context, mutex, file_pos, buff->data); \r
+ xbt_strbuff_empty(buff);\r
+ }\r
+ } \r
+ else \r
+ {\r
+ snprintf(file_pos,256,"%s:%d",fstream->name, line_num);\r
+ fstream_lex_line(fstream, context, mutex, file_pos, line); \r
+ }\r
+ }\r
+ \r
+ /* Check that last command of the file ran well */\r
+ if(context->command_line)\r
+ {\r
+ if(fstream_launch_command(fstream, context, mutex) < 0)\r
+ return -1;\r
+ }\r
+ \r
+ /* clear buffers */\r
+ if(line)\r
+ free(line);\r
+ \r
+ xbt_strbuff_free(buff); \r
+ \r
+ if(context_free(&context) < 0)\r
+ return -1;\r
+ \r
+ return (exit_code || errno) ? -1 : 0;\r
+}\r
+\r
+\r
+void \r
+fstream_lex_line(fstream_t fstream, context_t context, xbt_os_mutex_t mutex, const char * filepos, char *line) \r
+{\r
+ char* line2;\r
+ variable_t variable;\r
+ unsigned int i;\r
+ char exp[PATH_MAX + 1] = {0};\r
+ unit_t unit = fstream->unit;\r
+ xbt_dynar_t variables = unit->runner->variables;\r
+ char* p= NULL;\r
+ char* end = NULL;\r
+ char* val = NULL;\r
+ char buff[PATH_MAX + 1] = {0}; \r
+ size_t len;\r
+ char delimiters[4] = {' ', '\t', '\n', '\0'}; \r
+ \r
+ int j;\r
+ \r
+ if(line[0] == '#')\r
+ return;\r
+\r
+ if(unit->is_running_suite && strncmp(line, "! include", strlen("! include")))\r
+ {/* it's the end of a suite */\r
+ \r
+ unit_t* current_suite = xbt_dynar_get_ptr(unit->suites, xbt_dynar_length(unit->suites) - 1);\r
+\r
+ if(!xbt_dynar_length((*current_suite)->includes))\r
+ ERROR2("[%s] Malformated suite `(%s)': include missing", filepos, (*current_suite)->description);\r
+ else\r
+ ERROR2("[%s] Malformated suite `(%s)': blank line missing", filepos, (*current_suite)->description);\r
+ \r
+ unit_set_error(*current_suite, ESYNTAX, 1, filepos);\r
+\r
+ failure(fstream->unit);\r
+ }\r
+ \r
+ context->line = strdup(filepos);\r
+ \r
+ /* search end */\r
+ xbt_str_rtrim(line + 2,"\n");\r
+ \r
+ line2 = strdup(line);\r
+\r
+ len = strlen(line2 + 2) + 1;\r
+\r
+ /* replace each variable by its value */\r
+ xbt_os_mutex_acquire(unit->mutex);\r
+ \r
+\r
+ /* replace all existing\r
+ ${var}\r
+ ${var:=val}\r
+ ${var:+val}\r
+ ${var:-val}\r
+ ${var:?val}\r
+ ${#var}\r
+ */\r
+ \r
+ xbt_dynar_foreach(variables, i, variable)\r
+ {\r
+ if(!(p = strstr(line2 + 2, "${")))\r
+ break;\r
+\r
+ memset(buff, 0, len);\r
+\r
+ sprintf(buff,"${%s",variable->name);\r
+ \r
+ /* FALSE */\r
+ if((p = strstr(line2 + 2, buff)))\r
+ {\r
+ memset(buff, 0, len);\r
+ p--;\r
+ j = 0;\r
+\r
+ while(*(p++) != '\0')\r
+ {\r
+ buff[j++] = *p;\r
+\r
+ if(*p == '}')\r
+ break;\r
+ }\r
+\r
+ if(buff[j - 1] != '}')\r
+ {\r
+ xbt_os_mutex_release(unit->mutex); \r
+ \r
+ \r
+ ERROR2("[%s] Syntax error : `%s'.",filepos, p - j);\r
+ \r
+ unit_set_error(fstream->unit, ESYNTAX, 1, filepos);\r
+ failure(fstream->unit);\r
+ return;\r
+ }\r
+\r
+ if((p = strstr(buff , ":=")))\r
+ {\r
+ /* ${var:=val} */\r
+ \r
+ /* if the value of the variable is empty, update its value by the value*/\r
+ p += 2;\r
+ \r
+ end = strchr(p, '}');\r
+\r
+ if(!end || (end == p))\r
+ {\r
+ xbt_os_mutex_release(unit->mutex); \r
+ \r
+ \r
+ ERROR2("[%s] Bad substitution : `%s'.",filepos, strstr(buff, "${"));\r
+ \r
+ unit_set_error(fstream->unit, ESYNTAX, 1, filepos);\r
+ failure(fstream->unit);\r
+ return;\r
+ }\r
+\r
+ val = (char*) calloc((size_t)(end - p) + 1, sizeof(char));\r
+\r
+ strncpy(val, p,(end - p));\r
+ \r
+ \r
+ /* replace the expression by the expression of the value of the variable*/\r
+ sprintf(exp, "${%s:=%s}", variable->name, val);\r
+\r
+ if(variable->val)\r
+ str_replace_all(&line2, exp, variable->val, NULL);\r
+ else\r
+ {\r
+ str_replace_all(&line2, exp, val, NULL);\r
+\r
+ variable->val = strdup(val);\r
+ }\r
+\r
+ memset(exp, 0, VAR_NAME_MAX + 1);\r
+\r
+ if(val)\r
+ {\r
+ free(val);\r
+ val = NULL;\r
+ }\r
+\r
+ }\r
+ else if((p = strstr(buff, ":-")))\r
+ {\r
+ /* ${var:-val} */\r
+ \r
+ /* if the value of the variable is empty, replace the expression by the value */\r
+ p += 2;\r
+ end = strchr(p, '}');\r
+\r
+ if(!end || (end == p))\r
+ {\r
+ xbt_os_mutex_release(unit->mutex); \r
+ \r
+ ERROR2("[%s] Bad substitution : `%s'.",filepos, strstr(line2, "${"));\r
+ \r
+ unit_set_error(fstream->unit, ESYNTAX, 1, filepos);\r
+ failure(fstream->unit);\r
+ return;\r
+ }\r
+\r
+ val = (char*) calloc((size_t)(end - p) + 1, sizeof(char));\r
+\r
+ strncpy(val, p,(end - p)); \r
+\r
+ sprintf(exp, "${%s:-%s}", variable->name, val);\r
+ \r
+ str_replace_all(&line2, exp, variable->val ? variable->val : val, NULL);\r
+ \r
+\r
+ memset(exp, 0, VAR_NAME_MAX + 1);\r
+ \r
+ if(val)\r
+ {\r
+ free(val);\r
+ val = NULL;\r
+ }\r
+\r
+ }\r
+ else if((p = strstr(buff, ":+")))\r
+ {\r
+ /* ${var:+val} */\r
+ \r
+ /* if the value of the variable is not empty, replace the expression by the value */\r
+ p += 2;\r
+\r
+ end = strchr(p, '}');\r
+\r
+ if(!end || (end == p))\r
+ {\r
+ xbt_os_mutex_release(unit->mutex); \r
+ \r
+ \r
+ ERROR2("[%s] Bad substitution : `%s'.",filepos, strstr(line2, "${"));\r
+ \r
+ unit_set_error(fstream->unit, ESYNTAX, 1, filepos);\r
+ failure(fstream->unit);\r
+ return;\r
+ }\r
+\r
+ val = (char*) calloc((size_t)(end - p) + 1, sizeof(char));\r
+\r
+ strncpy(val, p,(end - p));\r
+\r
+ sprintf(exp, "${%s:+%s}", variable->name, val);\r
+\r
+ if(variable->val)\r
+ {\r
+ str_replace_all(&line2, exp, val, NULL);\r
+ }\r
+ else\r
+ {\r
+ str_replace_all(&line2, exp, NULL , NULL);\r
+ variable->val = strdup(val);\r
+ }\r
+ \r
+ memset(exp, 0, VAR_NAME_MAX + 1);\r
+ \r
+ if(val)\r
+ {\r
+ free(val);\r
+ val = NULL;\r
+ }\r
+ }\r
+ else if((p = strstr(buff, ":?")))\r
+ {\r
+ /* ${var:?val} */\r
+ \r
+ /* if the value of the variable is not empty, replace the expression by the value */\r
+ p += 2;\r
+ end = strchr(p, '}');\r
+\r
+ if(!end || (end == p))\r
+ {\r
+ xbt_os_mutex_release(unit->mutex); \r
+ \r
+ ERROR2("[%s] Bad substitution : `%s'.",filepos, strstr(line2, "${"));\r
+ \r
+ unit_set_error(fstream->unit, ESYNTAX, 1, filepos);\r
+ failure(fstream->unit);\r
+ return;\r
+ }\r
+\r
+ val = (char*) calloc((size_t)(end - p) + 1, sizeof(char));\r
+\r
+ strncpy(val, p,(end - p));\r
+\r
+ sprintf(exp, "${%s:?%s}", variable->name, val);\r
+ \r
+ if(variable->val)\r
+ str_replace_all(&line2, exp, variable->val, NULL);\r
+ else\r
+ {\r
+\r
+ xbt_os_mutex_release(unit->mutex); \r
+\r
+ ERROR2("[%s] %s.",filepos, val);\r
+\r
+ unit_set_error(fstream->unit, ESYNTAX, 1, filepos);\r
+ failure(fstream->unit);\r
+ return;\r
+ }\r
+ \r
+ memset(exp, 0, VAR_NAME_MAX + 1);\r
+ \r
+ if(val)\r
+ {\r
+ free(val);\r
+ val = NULL;\r
+ }\r
+ }\r
+ }\r
+ }\r
+\r
+ /* replace all existing $var */\r
+ xbt_dynar_foreach(variables, i, variable)\r
+ {\r
+ if(!strchr(line2 + 2, '$'))\r
+ break;\r
+\r
+ if(strstr(line2 + 2, variable->name))\r
+ {\r
+\r
+ sprintf(exp, "${#%s}", variable->name);\r
+ \r
+ if(strstr(line2 + 2, exp))\r
+ {\r
+\r
+ if(variable->val)\r
+ {\r
+ char slen[4] = {0};\r
+ sprintf(slen,"%d", (int)strlen(variable->val));\r
+ str_replace_all(&line2, exp, slen, NULL);\r
+ }\r
+ else\r
+ str_replace_all(&line2, exp, "0", NULL);\r
+ }\r
+\r
+ memset(exp, 0, VAR_NAME_MAX + 1);\r
+\r
+ sprintf(exp, "${%s}", variable->name);\r
+\r
+ if(strstr(line2 + 2, exp))\r
+ {\r
+ if(variable->val)\r
+ str_replace_all(&line2, exp, variable->val, NULL);\r
+ else\r
+ str_replace_all(&line2, exp, NULL, NULL);\r
+ }\r
+\r
+ memset(exp, 0, VAR_NAME_MAX + 1);\r
+\r
+ sprintf(exp, "$%s", variable->name);\r
+ \r
+ if((p = strstr(line2 + 2, exp)))\r
+ {\r
+ if((p + strlen(variable->name) + 1)[0] != '\0' && !(isalpha((p + strlen(variable->name) + 1)[0])))\r
+ delimiters[0] = (p + strlen(variable->name) + 1)[0];\r
+\r
+ if(variable->val)\r
+ str_replace_all(&line2, exp, variable->val, delimiters);\r
+ else\r
+ str_replace_all(&line2, exp, NULL, delimiters);\r
+ }\r
+\r
+ memset(exp, 0, VAR_NAME_MAX + 1);\r
+\r
+ }\r
+ }\r
+\r
+ while((p = strstr(line2 + 2, "${")))\r
+ {\r
+ /*if(*(p+1) != '{')\r
+ {\r
+ j = 0;\r
+ p --;\r
+\r
+ while(*(p++) != '\0')\r
+ {\r
+ if(*p != ' ' && *p !='\t')\r
+ exp[j++] = *p;\r
+ else\r
+ break;\r
+\r
+ }\r
+ \r
+ str_replace_all(&line2, exp, NULL, " \t\n\r");\r
+ memset(exp, 0, VAR_NAME_MAX + 1);\r
+ }.\r
+ else\r
+ */\r
+ {\r
+ char* begin = NULL;\r
+ \r
+ j = 0;\r
+ p --;\r
+\r
+ while(*(p++) != '\0')\r
+ {\r
+ if((!begin && *p != ' ' && *p !='\t') || begin)\r
+ {\r
+ /* `:' must be before this caracter, bad substitution : exit loop \r
+ ||\r
+ the current character is already present, bad substitution : exit loop\r
+ */\r
+ if(\r
+ (\r
+ *(p - 1) != ':' && (\r
+ (*p == '=') || (*p == '-') || (*p == '+') || (*p == '?')\r
+ )\r
+ )\r
+ || \r
+ (\r
+ begin && (\r
+ (*p == ':') || (*p == '=') || (*p == '-') || (*p == '+') || (*p == '?')\r
+ )\r
+ )\r
+ )\r
+ break;\r
+ else\r
+ exp[j++] = *p;\r
+\r
+ if(*p == ':')\r
+ {\r
+ /* save the begining of the value */\r
+ if((*(p+1) == '=') || (*(p+1) == '-') || (*(p+1) == '+') || (*(p+1) == '?'))\r
+ {\r
+ begin = p + 2;\r
+ exp[j++] = *(p+1);\r
+ p++;\r
+ continue;\r
+\r
+ }\r
+ else\r
+ /* the current char is `:' but the next is invalid, bad substitution : exit loop */\r
+ break;\r
+ }\r
+ /* end of the substitution : exit loop */\r
+ else if(*p == '}')\r
+ break;\r
+ }\r
+ else\r
+ break;\r
+ }\r
+ \r
+ if(exp[j - 1] == '}')\r
+ {\r
+ if(exp[2] == '#')\r
+ {\r
+ /* ${#var} */\r
+\r
+\r
+ if(4 == strlen(exp))\r
+ {\r
+ xbt_os_mutex_release(unit->mutex); \r
+ \r
+ ERROR2("[%s] Bad substitution : `%s'.",filepos, strchr(line2 + 2, '$'));\r
+ \r
+ unit_set_error(fstream->unit, ESYNTAX, 1, filepos);\r
+ failure(fstream->unit);\r
+ return;\r
+ }\r
+ \r
+ str_replace_all(&line2, exp, "0", NULL); \r
+ }\r
+ else if(strstr(exp,":="))\r
+ {\r
+ /* ${var:=value} */ \r
+ \r
+ end = strchr(p, '}');\r
+\r
+ if(!end || (end == begin))\r
+ {\r
+ xbt_os_mutex_release(unit->mutex); \r
+ \r
+ \r
+ ERROR2("[%s] Bad substitution : `%s'.",filepos, strchr(line2 + 2, '$'));\r
+ \r
+ unit_set_error(fstream->unit, ESYNTAX, 1, filepos);\r
+ failure(fstream->unit);\r
+ return;\r
+ }\r
+\r
+ variable = xbt_new0(s_variable_t, 1);\r
+\r
+ variable->val = (char*) calloc((size_t)(end - begin) + 1, sizeof(char));\r
+\r
+ strncpy(variable->val, begin ,(end - begin));\r
+\r
+ begin = exp + 2;\r
+ end = strchr(exp, ':');\r
+\r
+ if(!end || (end == begin))\r
+ {\r
+ xbt_os_mutex_release(unit->mutex); \r
+ \r
+ \r
+ ERROR2("[%s] Bad substitution : `%s'.",filepos, strchr(line2 + 2, '$'));\r
+ \r
+ unit_set_error(fstream->unit, ESYNTAX, 1, filepos);\r
+ failure(fstream->unit);\r
+ return;\r
+ }\r
+\r
+ variable->name = (char*) calloc((size_t)(end - begin) + 1, sizeof(char));\r
+\r
+ strncpy(variable->name, exp + 2 ,(end - begin));\r
+\r
+ str_replace_all(&line2, exp, variable->val, NULL);\r
+\r
+ xbt_dynar_push(variables, &variable);\r
+\r
+ }\r
+ else if(strstr(exp,":-"))\r
+ {\r
+ /* ${var:-value} */ \r
+\r
+ \r
+ end = strchr(p, '}');\r
+\r
+ if(!end || (end == begin))\r
+ {\r
+ xbt_os_mutex_release(unit->mutex); \r
+ \r
+ \r
+ ERROR2("[%s] Bad substitution : `%s'.",filepos, strchr(line2 + 2, '$'));\r
+ \r
+ unit_set_error(fstream->unit, ESYNTAX, 1, filepos);\r
+ failure(fstream->unit);\r
+ return;\r
+ }\r
+\r
+ val = (char*) calloc((size_t)(end - begin) + 1, sizeof(char));\r
+\r
+ strncpy(val, begin ,(end - begin));\r
+\r
+ str_replace_all(&line2, exp, val, NULL);\r
+\r
+ if(val)\r
+ free(val);\r
+\r
+ }\r
+ else if(strstr(exp,":+"))\r
+ {\r
+ /* ${var:+value} */ \r
+\r
+ end = strchr(p, '}');\r
+\r
+ if(!end || (end == begin))\r
+ {\r
+ xbt_os_mutex_release(unit->mutex); \r
+ \r
+ ERROR2("[%s] Bad substitution : `%s'.",filepos, strchr(line2 + 2, '$'));\r
+ \r
+ unit_set_error(fstream->unit, ESYNTAX, 1, filepos);\r
+ failure(fstream->unit);\r
+ return;\r
+ }\r
+\r
+ str_replace_all(&line2, exp, NULL, NULL);\r
+ }\r
+ else if(strstr(exp,":?"))\r
+ {\r
+ /* ${var:?value} */\r
+ \r
+ end = strchr(p, '}');\r
+\r
+ if(!end || (end == begin))\r
+ {\r
+ xbt_os_mutex_release(unit->mutex); \r
+ \r
+ ERROR2("[%s] Bad substitution : `%s'.",filepos, strchr(line2 + 2, '$'));\r
+ \r
+ unit_set_error(fstream->unit, ESYNTAX, 1, filepos);\r
+ failure(fstream->unit);\r
+ return;\r
+ }\r
+\r
+ val = (char*) calloc((size_t)(end - begin) + 1, sizeof(char));\r
+\r
+ strncpy(val, begin ,(end - begin));\r
+\r
+ xbt_os_mutex_release(unit->mutex); \r
+ \r
+ ERROR2("[%s] : `%s'.",filepos, val);\r
+\r
+ if(val)\r
+ free(val);\r
+ \r
+ unit_set_error(fstream->unit, ESYNTAX, 1, filepos);\r
+ failure(fstream->unit);\r
+\r
+ return;\r
+ \r
+ }\r
+ else\r
+ {\r
+ /* ${var} */\r
+\r
+ if(3 == strlen(exp))\r
+ {\r
+ xbt_os_mutex_release(unit->mutex); \r
+ \r
+ ERROR2("[%s] Bad substitution : `%s'.",filepos, strchr(line2 + 2, '$'));\r
+ \r
+ unit_set_error(fstream->unit, ESYNTAX, 1, filepos);\r
+ failure(fstream->unit);\r
+ return;\r
+ }\r
+\r
+ str_replace_all(&line2, exp, NULL, NULL);\r
+ \r
+ }\r
+\r
+ memset(exp, 0, VAR_NAME_MAX + 1);\r
+ }\r
+ else\r
+ {\r
+ xbt_os_mutex_release(unit->mutex); \r
+ \r
+ if(strstr(line2 + 2, "${"))\r
+ ERROR2("[%s] Bad substitution : `%s'.",filepos, strstr(line2, "${"));\r
+ else\r
+ ERROR2("[%s] Syntax error : `%s'.",filepos, strstr(line2, "${"));\r
+\r
+ unit_set_error(fstream->unit, ESYNTAX, 1, filepos);\r
+ failure(fstream->unit);\r
+ return;\r
+ }\r
+\r
+ }\r
+ \r
+ }\r
+ \r
+ p = line2 + 2;\r
+ \r
+ while(p && 1)\r
+ {\r
+ if((p = strchr(p, '$')))\r
+ {\r
+ if(*(p+1) != ' ')\r
+ {\r
+ j = 0;\r
+ p --;\r
+\r
+ while(*(p++) != '\0')\r
+ {\r
+ if(*p != ' ' && *p !='\t')\r
+ exp[j++] = *p;\r
+ else\r
+ break;\r
+\r
+ }\r
+ \r
+ str_replace_all(&line2, exp, NULL, " \t\n\r");\r
+ memset(exp, 0, VAR_NAME_MAX + 1);\r
+ }\r
+ else\r
+ {\r
+ /* maybe < $ cmd */\r
+ p++;\r
+ }\r
+ }\r
+ else\r
+ break;\r
+ }\r
+\r
+ xbt_os_mutex_release(unit->mutex); \r
+ \r
+ switch(line2[0]) \r
+ {\r
+ /*case '#': \r
+ break;\r
+ */\r
+ \r
+ case '$':\r
+ case '&':\r
+\r
+ if(line[1] != ' ')\r
+ {\r
+ \r
+ if(line2[0] == '$')\r
+ ERROR1("[%s] Missing space after `$' `(usage : $ <command>)'", filepos);\r
+ else\r
+ ERROR1("[%s] Missing space after & `(usage : & <command>)'", filepos);\r
+ \r
+ unit_set_error(fstream->unit, ESYNTAX, 1, filepos);\r
+\r
+ failure(unit);\r
+ return;\r
+ }\r
+ \r
+ context->async = (line2[0] == '&');\r
+\r
+ \r
+ /* further trim useless chars which are significant for in/output */\r
+ xbt_str_rtrim(line2 + 2," \t");\r
+ \r
+ /* deal with CD commands here, not in context */\r
+ if(!strncmp("cd ",line2 + 2, 3)) \r
+ {\r
+ char* dir = strdup(line2 + 4);\r
+ \r
+ if(context->command_line)\r
+ {\r
+ if(fstream_launch_command(fstream, context, mutex) < 0)\r
+ return;\r
+ }\r
+ \r
+ /* search begining */\r
+ while(*(dir++) == ' ');\r
+ \r
+ dir--;\r
+ \r
+ if(!dry_run_flag)\r
+ {\r
+ if(!silent_flag)\r
+ INFO2("[%s] cd %s", filepos, dir);\r
+ \r
+ if(!just_print_flag)\r
+ {\r
+ if(chdir(dir))\r
+ {\r
+ ERROR3("[%s] Chdir to %s failed: %s",filepos, dir,error_to_string(errno, 0));\r
+ unit_set_error(fstream->unit, errno, 0, filepos);\r
+\r
+ failure(unit);\r
+ }\r
+ }\r
+ }\r
+ \r
+ break;\r
+ }\r
+ else\r
+ {\r
+ fstream_process_token(fstream, context, mutex, filepos, line2[0], line2 + 2);\r
+ break;\r
+ }\r
+ \r
+ case '<':\r
+ case '>':\r
+ case '!':\r
+ \r
+ if(line[0] == '!' && line[1] != ' ')\r
+ {\r
+ ERROR1("[%s] Missing space after `!' `(usage : ! <command> [[=]value])'", filepos);\r
+ \r
+ unit_set_error(fstream->unit, ESYNTAX, 1, filepos);\r
+\r
+ failure(unit);\r
+ return;\r
+ }\r
+\r
+ fstream_process_token(fstream, context, mutex, filepos, line2[0], line2 + 2); \r
+ break;\r
+ \r
+ case 'p':\r
+ \r
+ {\r
+ unsigned int j;\r
+ int is_blank = 1;\r
+ \r
+ char* prompt = line2 + 2;\r
+\r
+ for(j = 0; j < strlen(prompt); j++)\r
+ {\r
+ if (prompt[j] != ' ' && prompt[j] != '\t')\r
+ {\r
+ is_blank = 0;\r
+ break;\r
+ }\r
+ }\r
+\r
+ if(is_blank)\r
+ {\r
+ ERROR1("[%s] Bad usage of the metacommand p `(usage : p <prompt>)'", filepos);\r
+ \r
+ unit_set_error(fstream->unit, ESYNTAX, 1, filepos);\r
+\r
+ failure(unit);\r
+ return;\r
+ }\r
+\r
+ if(!dry_run_flag)\r
+ INFO2("[%s] %s",filepos,prompt);\r
+ }\r
+\r
+ \r
+ break;\r
+ \r
+ case 'P':\r
+ \r
+ {\r
+ unsigned int j;\r
+ int is_blank = 1;\r
+ \r
+ char* prompt = line2 + 2;\r
+\r
+ for(j = 0; j < strlen(prompt); j++) \r
+ if (prompt[j] != ' ' && prompt[j] != '\t')\r
+ is_blank = 0;\r
+\r
+ if(is_blank)\r
+ {\r
+ ERROR1("[%s] Bad usage of the metacommand P `(usage : P <prompt>)'", filepos);\r
+ \r
+ unit_set_error(fstream->unit, ESYNTAX, 1, filepos);\r
+\r
+ failure(unit);\r
+ return;\r
+ }\r
+\r
+ if(!dry_run_flag) \r
+ CRITICAL2("[%s] %s",filepos, prompt);\r
+ }\r
+\r
+ break;\r
+ \r
+ case 'D':\r
+ if(unit->description)\r
+ WARN2("[%s] Description already specified `%s'",filepos, line2 + 2); \r
+ else\r
+ {\r
+ unsigned int j;\r
+ int is_blank = 1;\r
+ \r
+ char* desc = line2 + 2;\r
+\r
+ for(j = 0; j < strlen(desc); j++) \r
+ if (desc[j] != ' ' && desc[j] != '\t')\r
+ is_blank = 0;\r
+\r
+ if(is_blank)\r
+ {\r
+ ERROR1("[%s] Bad usage of the metacommand D `(usage : D <Description>)'", filepos);\r
+ \r
+ unit_set_error(fstream->unit, ESYNTAX, 1, filepos);\r
+\r
+ failure(unit);\r
+ return;\r
+ }\r
+\r
+ unit->description = strdup(desc);\r
+ }\r
+ break;\r
+ \r
+ default:\r
+ ERROR2("[%s] Syntax error `%s'", filepos, line2);\r
+ unit_set_error(fstream->unit, ESYNTAX, 1, filepos);\r
+ failure(unit);\r
+ break;\r
+ }\r
+ \r
+ free(line2);\r
+}\r
+\r
+void \r
+fstream_process_token(fstream_t fstream, context_t context, xbt_os_mutex_t mutex, const char* filepos, char token, char *line) \r
+{\r
+ unit_t unit = fstream->unit;\r
+ \r
+ switch (token) \r
+ {\r
+ case '$':\r
+ case '&':\r
+ \r
+ if(context->command_line) \r
+ {\r
+ \r
+ if(context->output->used || context->input->used) \r
+ {\r
+ 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
+\r
+ unit_set_error(fstream->unit, ESYNTAX, 1, filepos);\r
+ failure(unit);\r
+ return;\r
+ }\r
+ \r
+ if(fstream_launch_command(fstream, context, mutex) < 0)\r
+ return;\r
+ \r
+ VERB1("[%s] More than one command in this chunk of lines",filepos);\r
+ }\r
+ \r
+ {\r
+ size_t j,\r
+ is_blank = 1;\r
+\r
+ for(j = 0; j < strlen(line); j++) \r
+ if (line[j] != ' ' && line[j] != '\t')\r
+ is_blank = 0;\r
+\r
+ if(is_blank)\r
+ {\r
+ if(token == '$')\r
+ ERROR1("[%s] Undefinite command for `$' `(usage: $ <command>)'", filepos);\r
+ else\r
+ ERROR1("[%s] Undefinite command for `&' `(usage: & <command>)'", filepos);\r
+\r
+ unit_set_error(fstream->unit, ESYNTAX, 1, filepos);\r
+\r
+ failure(unit);\r
+ return;\r
+ }\r
+ }\r
+ \r
+ context->command_line = strdup(line);\r
+\r
+ xbt_str_ltrim(context->command_line," ");\r
+ \r
+ context->line = /*strdup(filepos)*/ filepos;\r
+ context->pos = strdup(filepos);\r
+ \r
+ #ifdef WIN32\r
+ {\r
+\r
+ /* translate the command line */\r
+\r
+ char* path = NULL;\r
+ char* delimiter;\r
+ char command_line[PATH_MAX + 1] = {0};\r
+ size_t i = 0;\r
+ char* args = NULL;\r
+\r
+ \r
+\r
+ /*if(strstr(context->command_line,".exe"))\r
+ strcpy(command_line,context->command_line);*/\r
+ \r
+ {\r
+ size_t len;\r
+ \r
+ size_t j = 0;\r
+ \r
+ len = strlen(context->command_line);\r
+ \r
+ while(i < len)\r
+ {\r
+ if(context->command_line[i] != ' ' && context->command_line[i] != '\t' && context->command_line[i] != '>')\r
+ command_line[j++] = context->command_line[i];\r
+ else\r
+ break;\r
+ \r
+ i++;\r
+ }\r
+ \r
+ if(!strstr(context->command_line,".exe"))\r
+ strcat(command_line,".exe");\r
+\r
+ args = strdup(context->command_line + i);\r
+ }\r
+ \r
+ if(!is_w32_cmd(command_line, fstream->unit->runner->path) && getpath(command_line, &path) < 0)\r
+ {\r
+ ERROR3("[%s] `%s' : NOK (%s)", filepos, command_line, error_to_string(ECMDNOTFOUND, 1));\r
+ unit_set_error(fstream->unit, ECMDNOTFOUND, 1, filepos);\r
+ failure(unit);\r
+ return;\r
+ }\r
+ \r
+ delimiter = strrchr(command_line,'/');\r
+\r
+ if(!delimiter)\r
+ delimiter = strrchr(command_line,'\\');\r
+ \r
+ /*free(context->command_line);*/\r
+ \r
+ \r
+ if(path)\r
+ {\r
+ if(args)\r
+ {\r
+ context->t_command_line = (char*)calloc(strlen(path) + strlen(delimiter ? delimiter + 1 : command_line) + strlen(args) + 2, sizeof(char));\r
+ sprintf(context->t_command_line,"%s\\%s%s",path,delimiter ? delimiter + 1 : command_line, args);\r
+\r
+ free(args);\r
+\r
+ }\r
+ else\r
+ {\r
+ context->t_command_line = (char*)calloc(strlen(path) + strlen(delimiter ? delimiter + 1 : command_line) + 2, sizeof(char));\r
+ sprintf(context->t_command_line,"%s\\%s",path,delimiter ? delimiter + 1 : command_line);\r
+ }\r
+ \r
+ free(path);\r
+ }\r
+ else\r
+ {\r
+ if(args)\r
+ {\r
+\r
+ context->t_command_line = (char*)calloc(strlen(command_line) + strlen(args) + 1, sizeof(char));\r
+ sprintf(context->t_command_line,"%s%s",command_line, args);\r
+\r
+ \r
+ free(args);\r
+\r
+ }\r
+ else\r
+ {\r
+ context->t_command_line = (char*)calloc(strlen(command_line) + 1, sizeof(char));\r
+ strcpy(context->t_command_line,command_line);\r
+ }\r
+ }\r
+\r
+\r
+ }\r
+ #endif\r
+\r
+\r
+ break;\r
+ \r
+ case '<':\r
+ xbt_strbuff_append(context->input,line);\r
+ xbt_strbuff_append(context->input,"\n");\r
+ break;\r
+ \r
+ case '>':\r
+ xbt_strbuff_append(context->output,line);\r
+ xbt_strbuff_append(context->output,"\n");\r
+ break;\r
+ \r
+ case '!':\r
+ \r
+ if(context->command_line)\r
+ {\r
+ if(fstream_launch_command(fstream, context, mutex) < 0)\r
+ return;\r
+ }\r
+ \r
+ if(!strncmp(line,"timeout no",strlen("timeout no"))) \r
+ {\r
+ VERB1("[%s] (disable timeout)", filepos);\r
+ context->timeout = INDEFINITE;\r
+ } \r
+ else if(!strncmp(line,"timeout ",strlen("timeout "))) \r
+ {\r
+ int i = 0;\r
+ unsigned int j;\r
+ int is_blank = 1;\r
+ char* p = line + strlen("timeout ");\r
+\r
+\r
+ for(j = 0; j < strlen(p); j++) \r
+ if (p[j] != ' ' && p[j] != '\t')\r
+ is_blank = 0;\r
+\r
+ if(is_blank)\r
+ {\r
+ ERROR1("[%s] Undefinite timeout value `(usage :timeout <seconds>)'", filepos);\r
+ \r
+ unit_set_error(fstream->unit, ESYNTAX, 1, filepos);\r
+\r
+ failure(unit);\r
+ return;\r
+ }\r
+ \r
+ while(p[i] != '\0')\r
+ {\r
+ if(!isdigit(p[i]))\r
+ {\r
+ ERROR2("[%s] Invalid timeout value `(%s)' : `(usage :timeout <seconds>)'", filepos, line + strlen("timeout "));\r
+\r
+ unit_set_error(fstream->unit, ESYNTAX, 1, filepos);\r
+ \r
+ failure(unit);\r
+ return;\r
+ }\r
+\r
+ i++;\r
+ }\r
+ \r
+ context->timeout = atoi(line + strlen("timeout"));\r
+ VERB2("[%s] (new timeout value: %d)",filepos,context->timeout);\r
+ \r
+ } \r
+ else if (!strncmp(line,"expect signal ",strlen("expect signal "))) \r
+ {\r
+ unsigned int j;\r
+ int is_blank = 1;\r
+\r
+ \r
+ char* p = line + strlen("expect signal ");\r
+\r
+\r
+ for(j = 0; j < strlen(p); j++) \r
+ if (p[j] != ' ' && p[j] != '\t')\r
+ is_blank = 0;\r
+\r
+ if(is_blank)\r
+ {\r
+ ERROR1("[%s] Undefinite signal name `(usage :expect signal <signal name>)'", filepos);\r
+ \r
+ unit_set_error(fstream->unit, ESYNTAX, 1, filepos);\r
+\r
+ failure(unit);\r
+ return;\r
+ }\r
+\r
+ context->signal = strdup(line + strlen("expect signal "));\r
+ \r
+ xbt_str_trim(context->signal," \n");\r
+\r
+ #ifdef WIN32\r
+ if(!strstr("SIGSEGVSIGTRAPSIGBUSSIGFPESIGILL", context->signal))\r
+ {\r
+ ERROR2("[%s] Signal `%s' not supported by this platform", filepos, context->signal);\r
+\r
+ unit_set_error(fstream->unit, ESYNTAX, 1, filepos);\r
+\r
+\r
+ failure(unit);\r
+ return;\r
+ }\r
+ #else\r
+ if(!sig_exists(context->signal))\r
+ {\r
+ ERROR2("[%s] Signal `%s' not supported by Tesh", filepos, context->signal);\r
+ \r
+ unit_set_error(fstream->unit, ESYNTAX, 1, filepos);\r
+\r
+\r
+ failure(unit);\r
+ return;\r
+ }\r
+\r
+ #endif\r
+\r
+ \r
+ VERB2("[%s] (next command must raise signal %s)", filepos, context->signal);\r
+ \r
+ } \r
+ else if (!strncmp(line,"expect return ",strlen("expect return "))) \r
+ {\r
+\r
+ int i = 0;\r
+ unsigned int j;\r
+ int is_blank = 1;\r
+ char* p = line + strlen("expect return ");\r
+\r
+\r
+ for(j = 0; j < strlen(p); j++) \r
+ if (p[j] != ' ' && p[j] != '\t')\r
+ is_blank = 0;\r
+\r
+ if(is_blank)\r
+ {\r
+ ERROR1("[%s] Undefinite return value `(usage :expect return <return value>)'", filepos);\r
+ \r
+ unit_set_error(fstream->unit, ESYNTAX, 1, filepos);\r
+\r
+ failure(unit);\r
+ return;\r
+ }\r
+ \r
+ while(p[i] != '\0')\r
+ {\r
+ if(!isdigit(p[i]))\r
+ {\r
+ ERROR2("[%s] Invalid exit code value `(%s)' : must be an integer >= 0 and <=255", filepos, line + strlen("expect return "));\r
+\r
+ unit_set_error(fstream->unit, ESYNTAX, 1, filepos);\r
+\r
+ failure(unit);\r
+ return;\r
+ }\r
+\r
+ i++;\r
+ }\r
+\r
+ context->exit_code = atoi(line+strlen("expect return "));\r
+ VERB2("[%s] (next command must return code %d)",filepos, context->exit_code);\r
+ \r
+ } \r
+ else if (!strncmp(line,"output ignore",strlen("output ignore"))) \r
+ {\r
+ context->output_handling = oh_ignore;\r
+ VERB1("[%s] (ignore output of next command)", filepos);\r
+ \r
+ } \r
+ else if (!strncmp(line,"output display",strlen("output display"))) \r
+ {\r
+ context->output_handling = oh_display;\r
+ VERB1("[%s] (ignore output of next command)", filepos);\r
+ \r
+ } \r
+ else if(!strncmp(line,"include ", strlen("include ")))\r
+ {\r
+ char* p1;\r
+ char* p2;\r
+ \r
+ p1 = line + strlen("include");\r
+ \r
+ while(*p1 == ' ' || *p1 == '\t')\r
+ p1++;\r
+ \r
+ \r
+ if(p1[0] == '\0')\r
+ {\r
+ ERROR1("[%s] no file specified : `(usage : include <file> [<description>])'", filepos);\r
+\r
+ unit_set_error(fstream->unit, ESYNTAX, 1, filepos);\r
+\r
+ failure(unit);\r
+ return;\r
+ }\r
+ else\r
+ {\r
+ char file_name[PATH_MAX + 1] = {0};\r
+ \r
+ p2 = p1;\r
+ \r
+ while(*p2 != '\0' && *p2 != ' ' && *p2 != '\t')\r
+ p2++;\r
+ \r
+ strncpy(file_name, p1, p2 - p1);\r
+ \r
+ \r
+ if(p2[0] != '\0')\r
+ while(*p2 == ' ' || *p2 == '\t')\r
+ p2++;\r
+ \r
+ fstream_handle_include(fstream, context, mutex, file_name, p2[0] != '\0' ? p2 : NULL);\r
+ \r
+ }\r
+ }\r
+ else if(!strncmp(line,"suite ", strlen("suite ")))\r
+ {\r
+ unsigned int j;\r
+ int is_blank = 1;\r
+ char* p = line + strlen("suite ");\r
+\r
+\r
+ for(j = 0; j < strlen(p); j++) \r
+ if (p[j] != ' ' && p[j] != '\t')\r
+ is_blank = 0;\r
+ \r
+ if(is_blank)\r
+ {\r
+ ERROR1("[%s] Undefinite suit description : `(usage : suite <description>)", filepos);\r
+\r
+ unit_set_error(fstream->unit, ESYNTAX, 1, filepos);\r
+\r
+ failure(unit);\r
+ return;\r
+ }\r
+\r
+ if(unit->is_running_suite)\r
+ {\r
+ ERROR1("[%s] Suite already in progress", filepos);\r
+\r
+ unit_set_error(fstream->unit, ESYNTAX, 1, filepos);\r
+\r
+ failure(unit);\r
+ return;\r
+ }\r
+ \r
+ fstream_handle_suite(fstream, line + strlen("suite "), filepos);\r
+ }\r
+ else if(!strncmp(line,"unsetenv ", strlen("unsetenv ")))\r
+ {\r
+ unsigned int i, j;\r
+ int exists = 0;\r
+ int env = 0;\r
+ int err = 0;\r
+ variable_t variable;\r
+ int is_blank;\r
+\r
+ char* name = line + strlen("unsetenv ");\r
+\r
+ is_blank = 1;\r
+\r
+ for(j = 0; j < strlen(name); j++) \r
+ if (name[j] != ' ' && name[j] != '\t')\r
+ is_blank = 0;\r
+\r
+ if(is_blank)\r
+ {\r
+ ERROR1("[%s] Bad usage of the metacommand unsetenv : `(usage : unsetenv variable)'", filepos);\r
+ \r
+ unit_set_error(fstream->unit, ESYNTAX, 1, filepos);\r
+\r
+ failure(unit);\r
+ return;\r
+ }\r
+ \r
+ xbt_os_mutex_acquire(unit->mutex);\r
+ \r
+\r
+ xbt_dynar_foreach(unit->runner->variables, i, variable)\r
+ {\r
+ if(!strcmp(variable->name, name))\r
+ {\r
+ env = variable->env;\r
+ err = variable->err;\r
+ exists = 1;\r
+ break;\r
+ }\r
+ }\r
+ \r
+ if(env)\r
+ {\r
+ if(exists)\r
+ {\r
+ #ifndef WIN32\r
+ unsetenv(name);\r
+ #else\r
+ SetEnvironmentVariable(name, NULL);\r
+ #endif\r
+ xbt_dynar_cursor_rm(unit->runner->variables, &i);\r
+ }\r
+ else\r
+ {\r
+ ERROR2("[%s] `(%s)' environment variable not found : impossible to unset it",filepos, name); \r
+ unit_set_error(fstream->unit, ESYNTAX, 1, filepos);\r
+ xbt_os_mutex_release(unit->mutex);\r
+ failure(unit);\r
+ return;\r
+ }\r
+ }\r
+ else\r
+ {\r
+ if(exists)\r
+ {\r
+ if(!err)\r
+ {\r
+ ERROR2("[%s] `(%s)' is not an environment variable : use `unset' instead `unsetenv'",filepos, name); \r
+ unit_set_error(fstream->unit, ESYNTAX, 1, filepos);\r
+ failure(unit);\r
+ xbt_os_mutex_release(unit->mutex);\r
+ return;\r
+ }\r
+ else\r
+ {\r
+ ERROR2("[%s] `(%s)' is not an environment variable (it's a system variable) : impossible to unset it",filepos, name); \r
+ unit_set_error(fstream->unit, ESYNTAX, 1, filepos);\r
+ xbt_os_mutex_release(unit->mutex);\r
+ failure(unit);\r
+ return;\r
+ }\r
+ }\r
+ else\r
+ {\r
+ ERROR2("[%s] `(%s)' environment variable not found : impossible to unset it",filepos, name); \r
+ unit_set_error(fstream->unit, ESYNTAX, 1, filepos);\r
+ xbt_os_mutex_release(unit->mutex);\r
+ failure(unit);\r
+ return;\r
+ }\r
+ }\r
+ \r
+ xbt_os_mutex_release(unit->mutex); \r
+ \r
+ \r
+ }\r
+ else if(!strncmp(line,"setenv ", strlen("setenv ")))\r
+ {\r
+ char* val;\r
+ char name[PATH_MAX + 1] = {0};\r
+ char* p;\r
+ unsigned int i;\r
+ int is_blank;\r
+ unsigned int j;\r
+ \r
+ p = line + strlen("setenv ");\r
+ \r
+ val = strchr(p, '=');\r
+ \r
+ if(val)\r
+ {\r
+ variable_t variable;\r
+ int exists = 0;\r
+ int env = 0;\r
+ int err = 0;\r
+ val++;\r
+ \r
+ /* syntax error */\r
+ if(val[0] == '\0' || val[0] ==' ' || val[0] =='\t')\r
+ {\r
+ ERROR1("[%s] Bad usage of the metacommand setenv `(usage : setenv variable=value)'", filepos); \r
+\r
+ unit_set_error(fstream->unit, ESYNTAX, 1, filepos);\r
+\r
+ failure(unit);\r
+ return;\r
+ }\r
+ \r
+ \r
+ \r
+ strncpy(name, p, (val - p -1));\r
+\r
+ is_blank = 1;\r
+\r
+ for(j = 0; j < strlen(name); j++) \r
+ if (name[j] != ' ' && name[j] != '\t')\r
+ is_blank = 0;\r
+\r
+ if(is_blank)\r
+ {\r
+ \r
+ ERROR1("[%s] Bad usage of the metacommand setenv `(usage : setenv variable=value)'", filepos);\r
+ \r
+ unit_set_error(fstream->unit, ESYNTAX, 1, filepos);\r
+\r
+ failure(unit);\r
+ return;\r
+ }\r
+ \r
+ /* test if the variable is already registred */\r
+ xbt_os_mutex_acquire(unit->mutex);\r
+\r
+ xbt_dynar_foreach(unit->runner->variables, i, variable)\r
+ {\r
+ if(!strcmp(variable->name, name))\r
+ {\r
+ env = variable->env;\r
+ err = variable->err;\r
+ exists = 1;\r
+ break;\r
+ }\r
+ }\r
+ \r
+ /* if the variable is already registred, update its value;\r
+ * otherwise register it.\r
+ */\r
+ if(exists)\r
+ {\r
+ if(env)\r
+ {\r
+ if(!strcmp(val, variable->val))\r
+ WARN3("[%s] This environment variable `(%s)' is already set with the value `(%s)'", filepos, name, val);\r
+\r
+ free(variable->val);\r
+ variable->val = strdup(val);\r
+\r
+ #ifdef WIN32\r
+ SetEnvironmentVariable(variable->name, variable->val);\r
+ #else\r
+ setenv(variable->name, variable->val, 1);\r
+ #endif\r
+ }\r
+ else\r
+ {\r
+ if(err)\r
+ ERROR2("[%s] Conflict : a system variable `(%s)' already exists", filepos, name);\r
+ else\r
+ ERROR2("[%s] Conflict : (none environment) variable `(%s)' already exists", filepos, name); \r
+\r
+ unit_set_error(fstream->unit, ESYNTAX, 1, filepos);\r
+ xbt_os_mutex_release(unit->mutex);\r
+ failure(unit);\r
+ return;\r
+ }\r
+ }\r
+ else\r
+ {\r
+ if(err)\r
+ {\r
+ ERROR2("[%s] A system variable named `(%s)' already exists", filepos, name);\r
+ \r
+ unit_set_error(fstream->unit, ESYNTAX, 1, filepos);\r
+ xbt_os_mutex_release(unit->mutex);\r
+ failure(unit);\r
+ return;\r
+ }\r
+ else\r
+ {\r
+ variable = variable_new(name, val);\r
+ variable->env = 1;\r
+ \r
+ xbt_dynar_push(unit->runner->variables, &variable);\r
+ \r
+ #ifdef WIN32\r
+ SetEnvironmentVariable(variable->name, variable->val);\r
+ #else\r
+ setenv(variable->name, variable->val, 0);\r
+ #endif\r
+ }\r
+ }\r
+ \r
+ xbt_os_mutex_release(unit->mutex);\r
+ \r
+ }\r
+ else\r
+ {\r
+ ERROR1("[%s] Bad usage of the metacommand setenv `(usage : setenv variable=value)'", filepos);\r
+ \r
+ unit_set_error(fstream->unit, ESYNTAX, 1, filepos);\r
+ failure(unit);\r
+ return;\r
+ }\r
+ }\r
+ else if(!strncmp(line,"unset ", strlen("unset ")))\r
+ {\r
+ unsigned int i, j;\r
+ int exists = 0;\r
+ int env = 0;\r
+ int err = 0;\r
+ variable_t variable;\r
+ int is_blank;\r
+\r
+ char* name = line + strlen("unset ");\r
+\r
+ is_blank = 1;\r
+\r
+ for(j = 0; j < strlen(name); j++) \r
+ if (name[j] != ' ' && name[j] != '\t')\r
+ is_blank = 0;\r
+\r
+ if(is_blank)\r
+ {\r
+ \r
+ ERROR1("[%s] Bad usage of the metacommand unset `(usage : unset variable)'", filepos);\r
+ \r
+ unit_set_error(fstream->unit, ESYNTAX, 1, filepos);\r
+\r
+ failure(unit);\r
+ return;\r
+ }\r
+\r
+ \r
+ xbt_os_mutex_acquire(unit->mutex);\r
+\r
+ xbt_dynar_foreach(unit->runner->variables, i, variable)\r
+ {\r
+ if(!strcmp(variable->name, name))\r
+ {\r
+ env = variable->env;\r
+ err = variable->err;\r
+ exists = 1;\r
+ break;\r
+ }\r
+ }\r
+ \r
+ if(!env && !err)\r
+ {\r
+ if(exists)\r
+ {\r
+ /*xbt_dynar_remove_at(unit->runner->variables, i, NULL);*/\r
+ /*xbt_dynar_cursor_rm(unit->runner->variables, &i);*/\r
+ if(variable->val)\r
+ {\r
+ free(variable->val);\r
+ variable->val = NULL;\r
+ }\r
+ else\r
+ {\r
+ WARN2("[%s] Variable `(%s)' already unseted",filepos, variable->name);\r
+ }\r
+ } \r
+ else\r
+ {\r
+ ERROR2("[%s] `(%s)' variable not found",filepos, name); \r
+ unit_set_error(fstream->unit, ESYNTAX, 1, filepos);\r
+ xbt_os_mutex_release(unit->mutex);\r
+ failure(unit);\r
+ return;\r
+ }\r
+ }\r
+ else if(env)\r
+ {\r
+ ERROR2("[%s] `(%s)' is an environment variable use `unsetenv' instead `unset'",filepos, name); \r
+ unit_set_error(fstream->unit, ESYNTAX, 1, filepos);\r
+ xbt_os_mutex_release(unit->mutex);\r
+ failure(unit);\r
+ return;\r
+ }\r
+ else if(err)\r
+ {\r
+ ERROR2("[%s] `(%s)' is system variable : you can unset it",filepos, name); \r
+ unit_set_error(fstream->unit, ESYNTAX, 1, filepos);\r
+ xbt_os_mutex_release(unit->mutex);\r
+ failure(unit);\r
+ return;\r
+ }\r
+ \r
+ xbt_os_mutex_release(unit->mutex);\r
+ \r
+ }\r
+ else if(!strncmp(line,"set ", strlen("set ")))\r
+ {\r
+ char* val;\r
+ char name[PATH_MAX + 1] = {0};\r
+ unsigned int j; \r
+ int is_blank;\r
+ \r
+ val = strchr(line + strlen("set "), '=');\r
+ \r
+ if(val)\r
+ {\r
+ variable_t variable;\r
+ int exists = 0;\r
+ unsigned int i;\r
+ int err;\r
+ int env;\r
+\r
+ val++;\r
+ \r
+ \r
+ /* syntax error */\r
+ if(val[0] == '\0')\r
+ {\r
+ ERROR1("[%s] Bad usage of the metacommand set `(usage : set variable=value)'", filepos);\r
+ \r
+ unit_set_error(fstream->unit, ESYNTAX, 1, filepos);\r
+\r
+ failure(unit);\r
+ return;\r
+ }\r
+ else if(val[0] ==' ' || val[0] =='\t')\r
+ {\r
+ strncpy(name, line + strlen("set "), (val - (line + strlen("set "))));\r
+\r
+ ERROR2("[%s] No space avaible after`(%s)'", filepos, name);\r
+\r
+ unit_set_error(fstream->unit, ESYNTAX, 1, filepos);\r
+\r
+ failure(unit);\r
+ return;\r
+ }\r
+ \r
+ \r
+ /* assume it's a varibale */\r
+ \r
+ strncpy(name, line + strlen("set "), (val - (line + strlen("set ")) -1));\r
+ \r
+ is_blank = 1;\r
+\r
+ for(j = 0; j < strlen(name); j++) \r
+ if (name[j] != ' ' && name[j] != '\t')\r
+ is_blank = 0;\r
+\r
+ if(is_blank)\r
+ {\r
+ \r
+ ERROR1("[%s] Bad usage of the metacommand set `(usage : set variable=value)'", filepos);\r
+ \r
+ unit_set_error(fstream->unit, ESYNTAX, 1, filepos);\r
+\r
+ failure(unit);\r
+ return;\r
+ }\r
+\r
+ xbt_os_mutex_acquire(unit->mutex);\r
+ \r
+ /* test if the variable is already registred */\r
+ xbt_dynar_foreach(unit->runner->variables, i, variable)\r
+ {\r
+ if(!strcmp(variable->name, name))\r
+ {\r
+ exists = 1;\r
+ err = variable->err;\r
+ env = variable->env;\r
+ break;\r
+ }\r
+ }\r
+ \r
+ /* if the variable is already registred, update its value (if same value warns);\r
+ * otherwise register it.\r
+ */\r
+ if(exists)\r
+ {\r
+ if(err)\r
+ {\r
+ ERROR2("[%s] A system variable named `(%s)' already exists", filepos, name);\r
+ \r
+ unit_set_error(fstream->unit, ESYNTAX, 1, filepos);\r
+ xbt_os_mutex_release(unit->mutex);\r
+\r
+ failure(unit);\r
+ return;\r
+ }\r
+ if(env)\r
+ {\r
+ ERROR2("[%s] `(%s)' is an environment variable use `setenv' instead `set'", filepos, name);\r
+ \r
+ unit_set_error(fstream->unit, ESYNTAX, 1, filepos);\r
+ xbt_os_mutex_release(unit->mutex);\r
+\r
+ failure(unit);\r
+ return;\r
+ }\r
+ else\r
+ {\r
+ if(!strcmp(val, variable->val))\r
+ WARN3("[%s] Variable `(%s)' already contains value `<%s>'",filepos, variable->name, val);\r
+\r
+ free(variable->val);\r
+ variable->val = strdup(val);\r
+ }\r
+ }\r
+ else\r
+ {\r
+ variable_t new_var = variable_new(name, val);\r
+ xbt_dynar_push(unit->runner->variables, &new_var);\r
+ }\r
+\r
+ \r
+ xbt_os_mutex_release(unit->mutex);\r
+ }\r
+ else\r
+ {\r
+ ERROR1("[%s] Bad usage of the metacommand set `(usage : set variable=value)'", filepos);\r
+ \r
+ unit_set_error(fstream->unit, ESYNTAX, 1, filepos);\r
+ failure(unit);\r
+ return;\r
+ }\r
+ }\r
+ else\r
+ {/* assume it's a variable */\r
+ char* val;\r
+ char name[PATH_MAX + 1] = {0};\r
+ unsigned int i, j; \r
+ int is_blank;\r
+ \r
+ val = strchr(line, '=');\r
+\r
+ if(val)\r
+ {\r
+ variable_t variable;\r
+ int exists = 0;\r
+ int err;\r
+ int env;\r
+ val++;\r
+ \r
+ \r
+ /* syntax error */\r
+ if(val[0] == '\0')\r
+ {\r
+ strncpy(name, line, (val - line -1));\r
+\r
+ is_blank = 1;\r
+\r
+ for(j = 0; j < strlen(name); j++) \r
+ if (name[j] != ' ' && name[j] != '\t')\r
+ is_blank = 0;\r
+\r
+ if(is_blank)\r
+ ERROR1("[%s] Bad usage of Tesh variable mechanism `(usage : variable=value)'", filepos);\r
+ else if(!strcmp("setenv", name))\r
+ ERROR1("[%s] Bad usage of the metacommand setenv `(usage : setenv variable=value)'", filepos);\r
+ else if(!strcmp("set", name))\r
+ ERROR1("[%s] Bad usage of the metacommand set `(usage : set variable=value)'", filepos);\r
+ else\r
+ ERROR2("[%s] Undefined variable `(%s)'", filepos, name);\r
+\r
+ unit_set_error(fstream->unit, ESYNTAX, 1, filepos);\r
+\r
+ failure(unit);\r
+ return;\r
+ }\r
+ else if(val[0] ==' ' || val[0] =='\t')\r
+ {\r
+ strncpy(name, line, (val - line));\r
+\r
+ ERROR2("[%s] No space avaible after`(%s)'", filepos, name);\r
+\r
+ unit_set_error(fstream->unit, ESYNTAX, 1, filepos);\r
+\r
+ failure(unit); \r
+ }\r
+ \r
+ \r
+ /* assume it's a varibale */\r
+ \r
+ strncpy(name, line, (val - line -1));\r
+\r
+ is_blank = 1;\r
+\r
+ for(j = 0; j < strlen(name); j++) \r
+ if (name[j] != ' ' && name[j] != '\t')\r
+ is_blank = 0;\r
+\r
+ if(is_blank)\r
+ {\r
+ \r
+ ERROR1("[%s] Bad usage of Tesh variable capability `(usage : variable=value)'", filepos);\r
+\r
+ unit_set_error(fstream->unit, ESYNTAX, 1, filepos);\r
+\r
+ failure(unit);\r
+ return;\r
+ }\r
+ \r
+ if(!strcmp("set", name))\r
+ {\r
+ ERROR1("[%s] Bad usage of the metacommand set `(usage : set variable=value)'", filepos);\r
+ \r
+ unit_set_error(fstream->unit, ESYNTAX, 1, filepos);\r
+ failure(unit);\r
+ return;\r
+ }\r
+ else if(!strcmp("setenv", name))\r
+ {\r
+ ERROR1("[%s] Bad usage of the metacommand setenv `(usage : setenv variable=value)'", filepos);\r
+ \r
+ unit_set_error(fstream->unit, ESYNTAX, 1, filepos);\r
+ failure(unit);\r
+ return;\r
+ }\r
+\r
+ xbt_os_mutex_acquire(unit->mutex);\r
+ \r
+ /* test if the variable is already registred */\r
+ xbt_dynar_foreach(unit->runner->variables, i, variable)\r
+ {\r
+ if(!strcmp(variable->name, name))\r
+ {\r
+ exists = 1;\r
+ err = variable->err;\r
+ env = variable->env;\r
+ break;\r
+ }\r
+ }\r
+ \r
+ /* if the variable is already registred, update its value (if same value warns);\r
+ * otherwise register it.\r
+ */\r
+ if(exists)\r
+ {\r
+ if(err)\r
+ {\r
+ ERROR2("[%s] A system variable named `(%s)' already exists", filepos, name);\r
+ \r
+ unit_set_error(fstream->unit, ESYNTAX, 1, filepos);\r
+ xbt_os_mutex_release(unit->mutex);\r
+ failure(unit);\r
+ return;\r
+ }\r
+ if(env)\r
+ {\r
+ ERROR2("[%s] `(%s)' is an environment variable use `setenv' metacommand", filepos, name);\r
+ \r
+ unit_set_error(fstream->unit, ESYNTAX, 1, filepos);\r
+ xbt_os_mutex_release(unit->mutex);\r
+\r
+ failure(unit);\r
+ return;\r
+ }\r
+ else\r
+ {\r
+ if(!strcmp(val, variable->val))\r
+ WARN3("[%s] Variable `(%s)' already contains value `<%s>'",filepos, variable->name, val);\r
+\r
+ free(variable->val);\r
+ variable->val = strdup(val);\r
+ }\r
+ }\r
+ else\r
+ {\r
+ variable_t new_var = variable_new(name, val);\r
+ xbt_dynar_push(unit->runner->variables, &new_var);\r
+ }\r
+\r
+ \r
+ xbt_os_mutex_release(unit->mutex);\r
+ \r
+ }\r
+ else \r
+ {\r
+ if(!strncmp("setenv", line, strlen("setenv")))\r
+ ERROR1("[%s] Bad usage of the metacommand setenv : `(usage : setenv variable=value)'", filepos);\r
+ else if(!strncmp("set", line, strlen("set")))\r
+ ERROR1("[%s] Bad usage of the metacommand set : `(usage : set variable=value)'", filepos);\r
+ else if(!strncmp("unsetenv", line, strlen("unsetenv")))\r
+ ERROR1("[%s] Bad usage of the metacommand unsetenv : `(usage : unsetenv variable)'", filepos);\r
+ else if(!strncmp("unset", line, strlen("unset")))\r
+ ERROR1("[%s] Bad usage of the metacommand unset : `(usage : unset variable)'", filepos);\r
+ else if(!strncmp("timeout", line, strlen("timeout")))\r
+ ERROR1("[%s] Bad usage of the metacommand timeout : `(usage : timeout <integral positive integer>)'", filepos);\r
+ else if(!strncmp("expect signal", line, strlen("expect signal")))\r
+ ERROR1("[%s] Bad usage of the metacommand expect signal : `(usage : expect signal <sig_name>)'", filepos);\r
+ else if(!strncmp("expect return", line, strlen("expect return")))\r
+ ERROR1("[%s] Bad usage of the metacommand expect return : `(usage : expect return <return value (>=0 <=255)>)'", filepos);\r
+ else if(!strncmp("include", line, strlen("include")))\r
+ ERROR1("[%s] Bad usage of the metacommand include :`(usage : include <file> [<description>])'", filepos);\r
+ else if(!strncmp("suite", line, strlen("suite")))\r
+ ERROR1("[%s] Bad usage of the metacommand suite : `(usage : suite <description>)'", filepos);\r
+ else\r
+ ERROR2("[%s] Unknown metacommand: `%s'",filepos,line);\r
+\r
+ unit_set_error(fstream->unit, ESYNTAX, 1, filepos);\r
+\r
+ failure(unit);\r
+ return;\r
+ }\r
+ }\r
+ \r
+ break;\r
+ }\r
+}\r
+\r
+void\r
+fstream_handle_include(fstream_t fstream, context_t context, xbt_os_mutex_t mutex, const char* file_name, const char* description)\r
+{\r
+ directory_t dir;\r
+ char* prev_directory = NULL;\r
+ fstream_t _fstream = NULL;\r
+ struct stat buffer = {0};\r
+ unit_t unit = fstream->unit;\r
+ \r
+ if(!stat(file_name, &buffer) && S_ISREG(buffer.st_mode))\r
+ {\r
+ /* the file is in the current directory */\r
+ _fstream = fstream_new(getcwd(NULL, 0), file_name);\r
+ fstream_open(_fstream);\r
+ }\r
+ /* the file to include is not in the current directory, check if it is in a include directory */\r
+ else\r
+ {\r
+ unsigned int i;\r
+ prev_directory = getcwd(NULL, 0);\r
+ \r
+ xbt_dynar_foreach(include_dirs, i, dir)\r
+ {\r
+ chdir(dir->name);\r
+ \r
+ if(!stat(file_name, &buffer) && S_ISREG(buffer.st_mode))\r
+ {\r
+ _fstream = fstream_new(dir->name, file_name);\r
+ fstream_open(_fstream);\r
+ break;\r
+ }\r
+ }\r
+\r
+ chdir(prev_directory);\r
+ free(prev_directory);\r
+ }\r
+ \r
+ /* the file to include is not found handle the failure */\r
+ if(!_fstream)\r
+ {\r
+ if(file_name[0] == '$')\r
+ {\r
+ ERROR3("[%s] Include file `(%s)' not found or variable `(%s)' doesn't exist",context->line, file_name, file_name + 1);\r
+ \r
+ }\r
+ else\r
+ {\r
+ /* may be a variable */\r
+ variable_t variable;\r
+ int exists = 0;\r
+ unsigned int i;\r
+\r
+ xbt_dynar_foreach(unit->runner->variables, i, variable)\r
+ {\r
+ if(!strcmp(variable->name, file_name))\r
+ {\r
+ exists = 1;\r
+ break;\r
+ }\r
+ }\r
+\r
+ if(exists)\r
+ 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
+ else\r
+ ERROR2("[%s] Include file `(%s)' not found",context->line, file_name);\r
+ }\r
+ \r
+ unit_set_error(fstream->unit, EINCLUDENOTFOUND, 1, context->line);\r
+\r
+ failure(fstream->unit);\r
+\r
+ return;\r
+ }\r
+ else\r
+ {\r
+ if(!unit->is_running_suite)\r
+ {/* it's the unit of a suite */\r
+ unit_t include = unit_new(unit->runner, unit->root, unit, _fstream);\r
+ \r
+ include->mutex = unit->root->mutex;\r
+ \r
+ if(description)\r
+ include->description = strdup(description);\r
+ \r
+ xbt_dynar_push(unit->includes, &include);\r
+ \r
+ if(!dry_run_flag)\r
+ {\r
+ if(description)\r
+ INFO2("Include from %s (%s)", _fstream->name, description);\r
+ else\r
+ INFO1("Include from %s", _fstream->name);\r
+\r
+ }\r
+ else\r
+ INFO1("Checking include %s...",_fstream->name);\r
+ \r
+ fstream_parse(_fstream, mutex);\r
+ }\r
+ else\r
+ {/* it's a include */\r
+\r
+ unit_t* owner;\r
+ unit_t include;\r
+\r
+ owner = xbt_dynar_get_ptr(unit->suites, xbt_dynar_length(unit->suites) - 1);\r
+ \r
+ include = unit_new(unit->runner, unit->root, *owner, _fstream);\r
+ \r
+ include->mutex = unit->root->mutex;\r
+ \r
+ if(description)\r
+ include->description = strdup(description);\r
+ \r
+ xbt_dynar_push((*owner)->includes, &include);\r
+ \r
+ if(!dry_run_flag)\r
+ {\r
+ if(description)\r
+ INFO2("Include from %s (%s)", _fstream->name, description);\r
+ else\r
+ INFO1("Include from %s", _fstream->name);\r
+ }\r
+ else\r
+ INFO1("Checking include %s...",_fstream->name);\r
+ \r
+ fstream_parse(_fstream, mutex);\r
+ }\r
+ }\r
+}\r
+\r
+void\r
+fstream_handle_suite(fstream_t fstream, const char* description, const char* filepos)\r
+{\r
+ unit_t unit = fstream->unit;\r
+ unit_t suite = unit_new(unit->runner, unit->root, unit, NULL);\r
+ \r
+ if(description)\r
+ suite->description = strdup(description);\r
+\r
+ suite->filepos = strdup(filepos); \r
+\r
+ xbt_dynar_push(unit->suites, &suite);\r
+ unit->is_running_suite = 1;\r
+ \r
+ if(!dry_run_flag)\r
+ INFO1("Test suite %s", description);\r
+ else\r
+ INFO1("Checking suite %s...",description);\r
+ \r
+}\r
+\r
+int\r
+fstream_launch_command(fstream_t fstream, context_t context, xbt_os_mutex_t mutex)\r
+{\r
+ unit_t unit = fstream->unit;\r
+\r
+ if(!dry_run_flag)\r
+ {\r
+ command_t command;\r
+ \r
+ if(!(command = command_new(unit, context, mutex)))\r
+ {\r
+ if(EINVAL == errno)\r
+ {\r
+ ERROR3("[%s] Cannot instantiate the command `%s' (%d)",context->pos, strerror(errno), errno); \r
+\r
+ unit_set_error(unit, errno, 0, context->pos);\r
+ failure(unit);\r
+ return -1;\r
+ }\r
+ else if(ENOMEM == errno)\r
+ {\r
+ ERROR3("[%s] Cannot instantiate the command `%s' (%d)",context->pos, strerror(errno), errno);\r
+\r
+ unit_set_error(unit, errno, 0, context->pos);\r
+\r
+ failure(unit);\r
+ return -1;\r
+ }\r
+ }\r
+ \r
+ if(command_run(command) < 0)\r
+ {\r
+ ERROR3("[%s] Cannot run the command `%s' (%d)",context->pos, strerror(errno), errno); \r
+ unit_set_error(unit, errno, 0, context->pos);\r
+ failure(unit);\r
+ return -1; \r
+ }\r
+ }\r
+ \r
+ if(context_reset(context) < 0)\r
+ {\r
+ ERROR3("[%s] Cannot reset the context of the command `%s' (%d)",context->pos, strerror(errno), errno); \r
+\r
+ unit_set_error(fstream->unit, errno, 0, context->pos);\r
+\r
+ failure(unit);\r
+ return -1; \r
+ }\r
+ \r
+ return 0;\r
+}\r
+\r
+\r
+\r
+\r