-#! ./tesh\r# This suite builds and uses a program returning 1.\r# tesh must detect this condition and report the issue.\r\r$ rm -rf temp_testdir\r$ mkdir temp_testdir\r\r$ cd temp_testdir\r\r< #include <stdlib.h>\r< int main(void) {\r< exit(1);\r< }\r$ cat > return1.c\r\r$ gcc -o return1 return1.c\r\r\r\r! expect return $EEXITCODENOTMATCH\r< $ ./return1\r$ ../tesh --log="log.thresh:info tesh.fmt:%m%n"\r> Test unit from stdin\r> [stdin:1] ./return1\r> [stdin:1] ./return1 : NOK (returned code `1' instead `0')\r> Output of <stdin:1> so far: \r> ||\r> Test unit `stdin': NOK (<stdin:1> exit code mismatch)\r\r\r\r$ cd ..\r$ rm -rf temp_testdir\r
\ No newline at end of file
+#! ./tesh\r# This suite builds and uses a program returning 1.\r# tesh must detect this condition and report the issue.\r\r$ rm -rf temp_testdir\r$ mkdir temp_testdir\r\r$ cd temp_testdir\r\r< #include <stdlib.h>\r< int main(void) {\r< exit(1);\r< }\r$ cat > return1.c\r\r$ gcc -o return1 return1.c\r\r! expect return $EEXITCODENOTMATCH\r< $ ./return1\r$ ../tesh --log="log.thresh:info tesh.fmt:%m%n"\r> Test unit from stdin\r> [stdin:1] ./return1\r> [stdin:1] ./return1 : NOK (returned code `1' instead `0')\r> Output of <stdin:1> so far: \r> ||\r> Test unit `stdin': NOK (<stdin:1> exit code mismatch)\r\r\r\r$ cd ..\r$ rm -rf temp_testdir\r
\ No newline at end of file
> [stdin:1] A system variable named `(ENOENT)' already exists
> Test unit `stdin': NOK (<stdin:1> syntax error)
+# Substitution usage
+! new=1
+p new is `$new ' or `${new}'
+p the len of new is : ${#new}
+! unset new
+p new is empty <$new> and is len is <${#new}>
+# display 66 and assign 6 to the value 66 of the variable new
+p ${new:=66}
+p new is `$new ' or `${new}'
+p the len of new is : ${#new}
+# display 66 and do not assign the value 69 to the variable
+p ${new:=69}
+p new is `$new ' or `${new}'
+p the len of new is : ${#new}
+! unset new
+# display 79 and do not assigne the value 79 to the variable
+# new is empty
+p ${new:-79}
+p new is `$new ' or `${new}'
+p the len of new is : ${#new}
+# display nothing and do not assigne the value 89 to the variable
+# new is empty
+p is empty ${new:+89}
+p new is `$new ' or `${new}'
+p the len of new is : ${#new}
+! set new=999
+# display 99 and do not assigne the value 99 to the variable (do not dispaly the value of new)
+# new is empty
+p is empty ${new:+99}
+p new is `$new ' or `${new}'
+p the len of new is : ${#new}
+
+! unset new
+
+# p ${new:?new is empty}
#ifndef __STR_REPLACE_H\r
#define __STR_REPLACE_H\r
\r
+#include <com.h>\r
+\r
#ifdef __cplusplus\r
extern "C" {\r
#endif\r
int\r
-str_replace(char** str, const char *what, const char *with);\r
+str_replace(char** str, const char *what, const char *with, const char* delimiters);\r
\r
int\r
-str_replace_all(char** str, const char* what, const char* with);\r
+str_replace_all(char** str, const char* what, const char* with, const char* delimiters);\r
\r
#ifdef __cplusplus\r
}\r
xbt_strbuff_t output; /* the expected output of the command of the test */
output_handling_t output_handling;
int async; /* if 1, the command is asynchronous */
+
+ #ifdef WIN32
+ char* t_command_line; /* translate the command line on Windows */
+ #endif
+
}s_context_t,* context_t;
/*
int\r
command_run(command_t command)\r
{\r
- if(!silent_flag)\r
+ if(!silent_flag && !interrupted)\r
INFO2("[%s] %s",command->context->pos, command->context->command_line);\r
\r
if(!just_print_flag)\r
xbt_os_mutex_release(command->mutex);\r
\r
/* execute the command of the test */\r
+\r
+ #ifndef WIN32\r
command_exec(command, command->context->command_line);\r
+ #else\r
+ /* play the translated command line on Windows */\r
+ command_exec(command, command->context->t_command_line);\r
+ #endif\r
\r
if(cs_in_progress == command->status)\r
{\r
xbt_strbuff_trim(command->output);\r
xbt_strbuff_trim(command->context->output);\r
\r
- if(!success)\r
+ if(!success && !strcmp(command->output->data, command->context->output->data))\r
{\r
xbt_dynar_t a = xbt_str_split(command->output->data, "\n");\r
char *out = xbt_str_join(a,"\n||");\r
if(command->output->used != command->context->output->used || strcmp(command->output->data, command->context->output->data))\r
{\r
char *diff;\r
+\r
\r
ERROR2("[%s] `%s' : NOK (outputs mismatch):", command->context->pos, command->context->command_line);\r
\r
context->signal = INDEFINITE_SIGNAL;\r
context->output_handling = oh_check;\r
context->async = 0;\r
+\r
+ #ifdef WIN32\r
+ context->t_command_line = NULL;\r
+ #endif\r
\r
return context;\r
}\r
if((*ptr)->signal)\r
free((*ptr)->signal);\r
\r
+ #ifdef WIN32\r
+ if((*ptr)->t_command_line)\r
+ free((*ptr)->t_command_line);\r
+ #endif\r
+\r
*ptr = NULL;\r
\r
return 0;\r
context->command_line = NULL;\r
}\r
\r
+ #ifdef WIN32\r
+ if(context->t_command_line)\r
+ {\r
+ free(context->t_command_line);\r
+ context->t_command_line = NULL;\r
+ }\r
+ #endif\r
+\r
if(context->pos)\r
{\r
free(context->pos);\r
dup->line = context->line;\r
dup->pos = strdup(context->pos);\r
dup->command_line = strdup(context->command_line);\r
+\r
+ \r
+ #ifdef WIN32\r
+ dup->t_command_line = strdup(context->t_command_line);\r
+ #endif\r
+\r
dup->exit_code = context->exit_code;\r
dup->timeout = context->timeout;\r
dup->output = NULL;\r
context->command_line = NULL;\r
}\r
\r
+ #ifdef WIN32\r
+ if(context->t_command_line)\r
+ {\r
+ free(context->t_command_line);\r
+ context->t_command_line = NULL;\r
+ }\r
+ #endif\r
+\r
if(context->pos)\r
{\r
free(context->pos);\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(const 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
-XBT_LOG_EXTERNAL_DEFAULT_CATEGORY(tesh);\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
+ \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
char* line2;\r
variable_t variable;\r
unsigned int i;\r
- char name[VAR_NAME_MAX + 1] = {0};\r
+ char exp[VAR_NAME_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[VAR_NAME_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
unit_set_error(*current_suite, ESYNTAX, 1, filepos);\r
\r
failure(fstream->unit);\r
- \r
- \r
}\r
\r
context->line = strdup(filepos);\r
\r
- \r
/* search end */\r
xbt_str_rtrim(line + 2,"\n");\r
\r
line2 = strdup(line);\r
- \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
- sprintf(name, "$%s", variable->name);\r
- str_replace_all(&line2, name, variable->val);\r
- memset(name, 0, VAR_NAME_MAX + 1);\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')\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
- xbt_os_mutex_release(unit->mutex);\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
+ /*case '#': \r
break;\r
+ */\r
\r
case '$':\r
case '&':\r
\r
char* prompt = line2 + 2;\r
\r
- for(j = 0; j < strlen(prompt); j++) \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
}\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;\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
+ else\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
+ strcat(command_line,".exe");\r
+\r
+ args = strdup(context->command_line + i);\r
+ }\r
+ \r
+ if(getpath(command_line, &path) && !is_w32_cmd(command_line, fstream->unit->runner->path))\r
+ {\r
+ ERROR3("[%s] `%s' : NOK (%s)", filepos, context->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
+ 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
+ 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
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
+ /*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
#include <com.h>\r
\r
+XBT_LOG_EXTERNAL_DEFAULT_CATEGORY(tesh);\r
+\r
/*#include <stdlib.h>\r
#include <string.h>\r
\r
return len;\r
}\r
#else\r
-int\r
+/*int\r
getpath(const char* file, char** path)\r
{\r
DWORD len;\r
char* part = NULL;\r
char buffer[PATH_MAX + 1] = {0}; \r
struct stat info = {0};\r
+\r
\r
len = GetFullPathName(file, PATH_MAX, buffer, &part );\r
\r
*path = NULL;\r
return -1;\r
}\r
-\r
\r
if(stat(buffer, &info) || !S_ISREG(info.st_mode))\r
{\r
*path = strncpy(*path, buffer, strlen(buffer) - strlen(part) - 1);\r
\r
return (int)(strlen(buffer) - strlen(part) -1);\r
+}*/\r
+\r
+int\r
+getpath(const char* file, char** path)\r
+{\r
+ char buf1[PATH_MAX + 1] = {0};\r
+ char buf2[PATH_MAX + 1] = {0};\r
+ struct stat info = {0};\r
+\r
+ char* delimiter;
+
+ if(!file)\r
+ {\r
+ *path = NULL;\r
+ return -1;\r
+ }
+
+ delimiter = strrchr(file,'/');
+
+ if(!delimiter)
+ delimiter = strrchr(file,'\\');\r
+\r
+ if(!delimiter)\r
+ {\r
+ *path = getcwd(NULL,0);\r
+ }\r
+ else\r
+ {\r
+ strncpy(buf2, file, (delimiter - file));\r
+\r
+ if(translatepath(buf2, path) < 0)\r
+ return -1;\r
+ }\r
+\r
+ sprintf(buf1,"%s\\%s", *path, delimiter ? delimiter + 1 : file);\r
+ \r
+ if(stat(buf1, &info) || !S_ISREG(info.st_mode))\r
+ {\r
+ free(*path);\r
+ *path = NULL;\r
+ errno = ENOENT;\r
+ return -1;\r
+ } \r
+ \r
+ return (int) strlen(*path);\r
}\r
\r
+\r
int\r
translatepath(const char* totranslate, char** translated)\r
{\r
{\r
*translated = getcwd(NULL,0);\r
(*translated)[2] = '\0';\r
+\r
return (int)strlen(*translated);\r
}\r
/* it's a relative directory name build the full directory name */\r
break;\r
}\r
}\r
- \r
+\r
if(j == 1 && buffer1[i - 1] == '/')\r
{\r
/* perhaps it's a relative directory : `dir/' */\r
getcwd(buffer1, PATH_MAX + 1);\r
strcat(buffer1,"\\");\r
strcat(buffer1,buffer2);\r
- \r
+\r
*translated = (char*) calloc(strlen(buffer1) + 1, sizeof(char));\r
strcpy(*translated, buffer1);\r
\r
len = (int)strlen(buffer2);\r
\r
*translated = (char*) calloc(len + 1, sizeof(char));\r
+ strcpy(*translated, buffer2);\r
\r
if(!(*translated))\r
{\r
if(number_of_bytes_readed > 0) \r
{\r
for(i= 0, j= 0; i < number_of_bytes_readed; i++)\r
- if((int)(buffer[i]) != 13)\r
+ if((buffer[i]) != '\r')\r
clean[j++] = buffer[i];\r
\r
xbt_strbuff_append(output,clean);\r
-/*
- * src/runner.c - type representing the runner.
- *
- * Copyright 2008,2009 Martin Quinson, Malek Cherier All right reserved.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the license (GNU LGPL) which comes with this package.
- *
- * Purpose:
- * This file contains all the definitions of the functions related with
- * the tesh runner type.
- *
- */
-#include <runner.h>
-#include <units.h>
-#include <unit.h>
-#include <xerrno.h>
-#include <variable.h>
-
-#include <errno.h> /* for error code */
-#include <stdlib.h> /* for calloc() */
-#include <stdio.h>
-
-#include <readline.h>
-
-#ifndef WIN32
-#include <sys/resource.h>
-#include <explode.h>
-#endif
-
-
-
-
-#define _RUNNER_HASHCODE 0xFEFEAAAA
-
-XBT_LOG_EXTERNAL_DEFAULT_CATEGORY(tesh);
-
-#if (!defined(__BUILTIN) && defined(__CHKCMD) && !defined(WIN32))
-static const char* builtin[] =
-{
- "alias",
- "bind",
- "builtin",
- "caller",
- "cd",
- "command",
- "compgen",
- "complete",
- "declare",
- "disown",
- "echo",
- "enable",
- "eval",
- "exec",
- "export",
- "false",
- "fc",
- "function",
- "getopts",
- "hash",
- "history",
- "jobs",
- "let",
- "logout",
- "printf",
- "pwd",
- "readonly",
- "shift",
- "shopt",
- "source",
- "suspend",
- "test",
- "time",
- "times",
- "trap",
- "true",
- "type",
- "typeset",
- "ulimit",
- "umask",
- "unalias",
- "unset",
- NULL
-};
-
-#define __BUILTIN_MAX ((size_t)42)
-#endif
-
-#ifndef WIN32
-extern char**
-environ;
-#endif
-
-/* the unique tesh runner */
-static runner_t
-runner = NULL;
-
-/* wait for the tesh runner terminaison */
-static void
-runner_wait(void);
-
-static void*
-runner_start_routine(void* p);
-
-
-/* check the syntax of the tesh files if
- * the check_syntax_flag is specified. Returns
- * 0 if the syntax is clean.
- */
-/*static void
-check_syntax(void);*/
-
-#ifdef WIN32
-
-static HANDLE
-timer_handle = NULL;
-
-
-static void*
-runner_start_routine(void* p)
-{
-
- LARGE_INTEGER li;
-
- li.QuadPart=- runner->timeout * 10000000; /* 10000000 = 10 000 000 * 100 nanoseconds = 1 second */
-
- /* create the waitable timer */
- timer_handle = CreateWaitableTimer(NULL, TRUE, NULL);
-
- /* set a timer to wait for timeout seconds */
- SetWaitableTimer(timer_handle, &li, 0, NULL, NULL, 0);
-
- /* wait for the timer */
- WaitForSingleObject(timer_handle, INFINITE);
-
- if(runner->waiting)
- {
- exit_code = ELEADTIME;
- err_kind = 1;
- runner->timeouted = 1;
- xbt_os_sem_release(units_sem);
- }
-
- return NULL;
-}
-
-#else
-static void*
-runner_start_routine(void* p)
-{
- struct timespec ts;
- int timeout = runner->timeout;
-
-
- while(timeout-- && runner->waiting)
- {
- ts.tv_sec = 1;
- ts.tv_nsec = 0L;
-
- do
- {
- nanosleep(&ts, &ts);
- }while(EINTR == errno);
- }
-
- if(errno)
- {
- /* TODO process the error */
- }
- else
- {
- if(runner->waiting)
- {
- exit_code = ELEADTIME;
- err_kind = 1;
- runner->timeouted = 1;
- xbt_os_sem_release(units_sem);
- }
- }
-
- return NULL;
-}
-#endif
-
-
-int
-runner_init(/*int check_syntax_flag, */int timeout, fstreams_t fstreams)
-{
-
- int i;
- char* val;
- char buffer[PATH_MAX + 1] = {0};
-
- int code;
- const char* cstr;
- variable_t variable;
-
- #if (defined(__CHKCMD) && defined(__BUILTIN) && !defined(WIN32))
- FILE* s;
- int n = 0;
- size_t len;
- char* line = NULL;
- int is_blank;
- #endif
-
-
- if(runner)
- {
- ERROR0("The runner is already initialized");
- return -1;
- }
-
- runner = xbt_new0(s_runner_t, 1);
-
- runner->path = NULL;
- runner->builtin = NULL;
-
- if(!(runner->units = units_new(runner, fstreams)))
- {
- free(runner);
- runner = NULL;
- return -1;
- }
-
- runner->timeout = timeout;
- runner->timeouted = 0;
- runner->interrupted = 0;
- runner->number_of_ended_units = 0;
- runner->number_of_runned_units = 0;
- runner->waiting = 0;
-
- runner->total_of_tests = 0;
- runner->total_of_successeded_tests = 0;
- runner->total_of_failed_tests = 0;
- runner->total_of_interrupted_tests = 0;
-
- runner->total_of_units = 0;
- runner->total_of_successeded_units = 0;
- runner->total_of_failed_units = 0;
- runner->total_of_interrupted_units = 0;
-
- runner->total_of_suites = 0;
- runner->total_of_successeded_suites = 0;
- runner->total_of_failed_suites = 0;
- runner->total_of_interrupted_suites = 0;
-
- /* initialize the vector of variables */
- runner->variables = xbt_dynar_new(sizeof(variable_t), (void_f_pvoid_t)variable_free);
-
- /* add the environment variables in the vector */
- for(i = 0; environ[i] != NULL; i++)
- {
- val = strchr(environ[i], '=');
-
- if(val)
- {
- val++;
-
- if(val[0] != '\0')
- strncpy(buffer, environ[i], (val - environ[i] -1));
-
- if(!strcmp("TESH_PPID", buffer))
- is_tesh_root = 0;
-
- variable = variable_new(buffer, val);
- variable->env = 1;
- xbt_dynar_push(runner->variables, &variable);
-
- #ifndef WIN32
- if(!strcmp("PATH", buffer))
- {
- char* p;
- size_t j,k, len;
-
- /* get the list of paths */
-
- runner->path = explode(':', val);
-
- /* remove spaces and backslahes at the end of the path */
- for (k = 0; runner->path[k] != NULL; k++)
- {
- p = runner->path[k];
-
- len = strlen(p);
-
- for(j = len - 1; p[j] == '/' || p[j] == ' '; j--)
-
- p[j] = '\0';
- }
- }
- #endif
-
- memset(buffer, 0, PATH_MAX + 1);
- }
- }
-
- if(is_tesh_root)
- {
- char* tesh_dir = getcwd(NULL, 0);
-
- sprintf(buffer,"%d",getpid());
-
- #ifndef WIN32
- setenv("TESH_PPID", buffer, 0);
- setenv("TESH_DIR", tesh_dir, 0);
- #else
- SetEnvironmentVariable("TESH_PPID", buffer);
- SetEnvironmentVariable("TESH_DIR", tesh_dir);
- #endif
-
- variable = variable_new("TESH_PPID", buffer);
- variable->err = 1;
-
- xbt_dynar_push(runner->variables, &variable);
-
- variable = variable_new("TESH_DIR", tesh_dir);
- variable->err = 1;
-
- xbt_dynar_push(runner->variables, &variable);
-
- free(tesh_dir);
- }
-
- variable = variable_new("EXIT_SUCCESS", "0");
- variable->err = 1;
-
- xbt_dynar_push(runner->variables, &variable);
-
- variable = variable_new("EXIT_FAILURE", "1");
- variable->err = 1;
-
- xbt_dynar_push(runner->variables, &variable);
-
- variable = variable_new("TRUE", "0");
- variable->err = 1;
-
- xbt_dynar_push(runner->variables, &variable);
-
- variable = variable_new("FALSE", "1");
- variable->err = 1;
-
- xbt_dynar_push(runner->variables, &variable);
-
- i = 0;
-
- /* add the errors variables */
- while((cstr = error_get_at(i++, &code)))
- {
- sprintf(buffer,"%d",code);
- variable = variable_new(cstr, buffer);
- variable->err = 1;
- xbt_dynar_push(runner->variables, &variable);
- }
-
- /* if the user want check the syntax, check it */
- /*if(check_syntax_flag)
- check_syntax();
- */
-
- #if (!defined(WIN32) && defined(__CHKCMD))
- #if defined(__BUILTIN)
-
- if(!is_tesh_root)
- {
- /* compute the full path the builtin.def file */
- sprintf(buffer,"%s/builtin.def",getenv("TESH_DIR"));
-
- if(!(s = fopen(buffer, "r")))
- {
- ERROR1("File `(%s)' not found", buffer);
- return -1;
- }
-
- }
- else
- {
- if(!(s = fopen("builtin.def", "r")))
- {
- ERROR0("File `(builtin.def)' not found");
- return -1;
- }
- }
-
- if(s)
- {
- fpos_t begin;
-
- fgetpos(s, &begin);
-
- while(readline(s, &line, &len) != -1)
- {
- i = 0;
- is_blank = 1;
-
-
- while(line[i] != '\0')
- {
- if (line[i] != ' ' && line[i] != '\t' && line[i]!='\n' && line[i]!='\r')
- {
- is_blank = 0;
- break;
- }
-
- i++;
- }
-
- if(!is_blank)
- n++;
- }
-
- fsetpos(s, &begin);
- free(line);
- line = NULL;
-
- if(n)
- {
- char* l;
-
- runner->builtin = xbt_new0(char*, n + 1); /* (char**) calloc(n + 1, sizeof(char*));*/
-
- n = 0;
-
- while(readline(s, &line, &len) != -1)
- {
- i = 0;
- is_blank = 1;
-
- while(line[i] != '\0')
- {
- if (line[i] != ' ' && line[i] != '\t' && line[i]!='\n' && line[i]!='\r')
- {
- is_blank = 0;
- break;
- }
-
- i++;
- }
-
- if(!is_blank)
- {
- l = strdup(line);
-
- l[strlen(l) - 1] = '\0';
-
- (runner->builtin)[n++] = l;
-
- }
- }
-
- }
- else
- {
- WARN0("The file `(builtin.def)' is empty");
- free(runner->builtin);
- runner->builtin = NULL;
- }
-
-
- fclose(s);
-
- if(line)
- free(line);
-
- }
-
- #else
- runner->builtin = xbt_new0(char*, __BUILTIN_MAX + 1); /* (char**) calloc(__BUILTIN_MAX + 1, sizeof(char*));*/
-
- for(i = 0; i < __BUILTIN_MAX; i++)
- runner->builtin[i] = strdup(builtin[i]);
- #endif
- #endif
-
- return exit_code ? -1 : 0;
-}
-
-void
-runner_destroy(void)
-{
- int i;
-
- if(runner->units)
- units_free((void**)(&(runner->units)));
-
- if(runner->variables)
- xbt_dynar_free(&runner->variables);
-
- #ifdef WIN32
- CloseHandle(timer_handle);
- #endif
-
- if(runner->thread)
- xbt_os_thread_join(runner->thread, NULL);
-
- if(runner->path)
- {
- for (i = 0; runner->path[i] != NULL; i++)
- free(runner->path[i]);
-
- free(runner->path);
- }
-
- if(runner->builtin)
- {
- for (i = 0; runner->builtin[i] != NULL; i++)
- free(runner->builtin[i]);
-
- free(runner->builtin);
- }
-
- free(runner);
-
-
- runner = NULL;
-}
-
-void
-runner_run(void)
-{
- /* allocate the mutex used by the units to asynchronously access
- * to the properties of the runner.
- */
- xbt_os_mutex_t mutex = xbt_os_mutex_init();
-
- /* run all the units */
- units_run_all(runner->units, mutex);
-
-
- if(!interrupted)
- runner_wait();
-
-
- /* if the runner is timeouted or receive a interruption request
- * , interrupt all the active units.
- */
- if(runner->timeouted || interrupted)
- runner_interrupt();
-
- /* joins all the units */
- units_join_all(runner->units);
-
- /* release the mutex resource */
- xbt_os_mutex_destroy(mutex);
-
-}
-
-static void
-runner_wait(void)
-{
- if(runner->timeout > 0)
- runner->thread = xbt_os_thread_create("", runner_start_routine, NULL);
-
- /* signal that the runner is waiting */
- runner->waiting = 1;
-
- /* wait for the end of all the units */
- xbt_os_sem_acquire(units_sem);
-
-
- runner->waiting = 0;
-}
-
-
-
-/*
- * interrupt all the active units.
- * this function is called when the lead time of the execution is reached
- * or when a failed unit requests an interruption of the execution.
- */
-void
-runner_interrupt(void)
-{
- units_interrupt_all(runner->units);
-}
-
-void
-runner_summarize(void)
-{
-
- if(!dry_run_flag)
- {
- #ifndef WIN32
- struct rusage r_usage;
- #else
- FILETIME start_time;
- FILETIME exit_time;
- FILETIME kernel_time;
- FILETIME user_time;
- SYSTEMTIME si;
- #endif
-
- printf("\n TEst SHell utility - mini shell specialized in running test units.\n");
- printf(" =============================================================================\n");
-
- units_summuarize(runner->units);
-
- printf(" =====================================================================%s\n",
- runner->total_of_failed_tests ? "== FAILED": (runner->total_of_interrupted_tests || runner->total_of_interrupted_units) ? "==== INTR" : "====== OK");
-
- printf(" TOTAL : Suite(s): %.0f%% ok (%d suite(s): %d ok",
- (runner->total_of_suites ? (1-((double)runner->total_of_failed_suites + (double)runner->total_of_interrupted_suites)/(double)runner->total_of_suites)*100.0 : 100.0),
- runner->total_of_suites, runner->total_of_successeded_suites);
-
- if(runner->total_of_failed_suites > 0)
- printf(", %d failed", runner->total_of_failed_suites);
-
- if(runner->total_of_interrupted_suites > 0)
- printf(", %d interrupted)", runner->total_of_interrupted_suites);
-
- printf(")\n");
-
- printf(" Unit(s): %.0f%% ok (%d unit(s): %d ok",
- (runner->total_of_units ? (1-((double)runner->total_of_failed_units + (double)runner->total_of_interrupted_units)/(double)runner->total_of_units)*100.0 : 100.0),
- runner->total_of_units, runner->total_of_successeded_units);
-
- if(runner->total_of_failed_units > 0)
- printf(", %d failed", runner->total_of_failed_units);
-
- if(runner->total_of_interrupted_units > 0)
- printf(", %d interrupted)", runner->total_of_interrupted_units);
-
- printf(")\n");
-
- printf(" Test(s): %.0f%% ok (%d test(s): %d ok",
- (runner->total_of_tests ? (1-((double)runner->total_of_failed_tests + (double)runner->total_of_interrupted_tests)/(double)runner->total_of_tests)*100.0 : 100.0),
- runner->total_of_tests, runner->total_of_successeded_tests);
-
- if(runner->total_of_failed_tests > 0)
- printf(", %d failed", runner->total_of_failed_tests);
-
- if(runner->total_of_interrupted_tests > 0)
- printf(", %d interrupted)", runner->total_of_interrupted_tests);
-
- printf(")\n\n");
-
- #ifndef WIN32
- if(!getrusage(RUSAGE_SELF, &r_usage))
- {
-
- printf(" Total tesh user time used: %ld second(s) %ld microsecond(s)\n", r_usage.ru_utime.tv_sec, r_usage.ru_utime.tv_usec);
- printf(" Total tesh system time used: %ld second(s) %ld microsecond(s)\n\n", r_usage.ru_stime.tv_sec, r_usage.ru_stime.tv_usec);
-
- if(!getrusage(RUSAGE_CHILDREN, &r_usage))
- {
- printf(" Total children user time used: %ld second(s) %ld microsecond(s)\n", r_usage.ru_utime.tv_sec, r_usage.ru_utime.tv_usec);
- printf(" Total children system time used: %ld second(s) %ld microsecond(s)\n\n", r_usage.ru_stime.tv_sec, r_usage.ru_stime.tv_usec);
-
- }
- }
- #else
-
- if(GetProcessTimes(GetCurrentProcess(), &start_time, &exit_time, &kernel_time, &user_time))
- {
- FileTimeToSystemTime(&user_time, &si);
-
- printf(" Total tesh user time used: %uhour(s) %uminute(s) %usecond(s) %millisecond(s)\n", si.wHour, si.wMinute, si.wSecond, si.wMilliseconds );
-
- FileTimeToSystemTime(&kernel_time, &si);
-
- printf(" Total tesh kernel time used: %uhour(s) %uminute(s) %usecond(s) %millisecond(s)\n", si.wHour, si.wMinute, si.wSecond, si.wMilliseconds );
- }
-
-
-
- #endif
- }
- else
- {
- if(exit_code)
- ERROR0("Syntax NOK");
- else if(!exit_code)
- INFO0("Syntax 0K");
- }
-}
-
-int
-runner_is_timedout(void)
-{
- return runner->timeouted;
-}
-
+/*\r
+ * src/runner.c - type representing the runner.\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 runner type.\r
+ *\r
+ */\r
+#include <runner.h>\r
+#include <units.h>\r
+#include <unit.h>\r
+#include <xerrno.h>\r
+#include <variable.h>\r
+\r
+#include <errno.h> /* for error code */\r
+#include <stdlib.h> /* for calloc() */\r
+#include <stdio.h>\r
+\r
+#include <readline.h>\r
+#include <explode.h>\r
+\r
+#ifndef WIN32\r
+#include <sys/resource.h>\r
+#endif\r
+\r
+\r
+\r
+\r
+\r
+#define _RUNNER_HASHCODE 0xFEFEAAAA \r
+\r
+XBT_LOG_EXTERNAL_DEFAULT_CATEGORY(tesh);\r
+\r
+#if (!defined(__BUILTIN) && defined(__CHKCMD) && !defined(WIN32))\r
+static const char* builtin[] =\r
+{\r
+ "alias",\r
+ "bind",\r
+ "builtin",\r
+ "caller",\r
+ "cd",\r
+ "command",\r
+ "compgen",\r
+ "complete",\r
+ "declare",\r
+ "disown",\r
+ "echo",\r
+ "enable",\r
+ "eval",\r
+ "exec",\r
+ "export",\r
+ "false",\r
+ "fc",\r
+ "function",\r
+ "getopts",\r
+ "hash",\r
+ "history",\r
+ "jobs",\r
+ "let",\r
+ "logout",\r
+ "printf",\r
+ "pwd",\r
+ "readonly",\r
+ "shift",\r
+ "shopt",\r
+ "source",\r
+ "suspend",\r
+ "test",\r
+ "time",\r
+ "times",\r
+ "trap",\r
+ "true",\r
+ "type",\r
+ "typeset",\r
+ "ulimit",\r
+ "umask",\r
+ "unalias",\r
+ "unset",\r
+ NULL\r
+};\r
+\r
+#define __BUILTIN_MAX ((size_t)42)\r
+#endif\r
+\r
+\r
+# ifdef __APPLE__\r
+/* under darwin, the environment gets added to the process at startup time. So, it's not defined at library link time, forcing us to extra tricks */\r
+# include <crt_externs.h>\r
+# define environ (*_NSGetEnviron())\r
+# elif !defined(WIN32)\r
+ /* the environment, as specified by the opengroup, used to initialize the process properties */\r
+ extern char **environ;\r
+# endif\r
+\r
+#ifndef WIN32\r
+extern char**\r
+environ;\r
+#endif\r
+\r
+/* the unique tesh runner */\r
+static runner_t\r
+runner = NULL;\r
+\r
+/* wait for the tesh runner terminaison */\r
+static void\r
+runner_wait(void);\r
+\r
+static void*\r
+runner_start_routine(void* p);\r
+\r
+\r
+/* check the syntax of the tesh files if \r
+ * the check_syntax_flag is specified. Returns\r
+ * 0 if the syntax is clean.\r
+ */\r
+/*static void\r
+check_syntax(void);*/\r
+\r
+#ifdef WIN32\r
+\r
+static HANDLE \r
+timer_handle = NULL;\r
+\r
+\r
+static void*\r
+runner_start_routine(void* p)\r
+{\r
+ \r
+ LARGE_INTEGER li;\r
+\r
+ li.QuadPart=- runner->timeout * 10000000; /* 10000000 = 10 000 000 * 100 nanoseconds = 1 second */\r
+\r
+ /* create the waitable timer */\r
+ timer_handle = CreateWaitableTimer(NULL, TRUE, NULL);\r
+\r
+ /* set a timer to wait for timeout seconds */\r
+ SetWaitableTimer(timer_handle, &li, 0, NULL, NULL, 0);\r
+ \r
+ /* wait for the timer */\r
+ WaitForSingleObject(timer_handle, INFINITE);\r
+\r
+ if(runner->waiting)\r
+ {\r
+ exit_code = ELEADTIME;\r
+ err_kind = 1;\r
+ runner->timeouted = 1;\r
+ xbt_os_sem_release(units_sem);\r
+ }\r
+\r
+ return NULL;\r
+}\r
+\r
+#else\r
+static void*\r
+runner_start_routine(void* p)\r
+{\r
+ struct timespec ts;\r
+ int timeout = runner->timeout;\r
+ \r
+ \r
+ while(timeout-- && runner->waiting)\r
+ {\r
+ ts.tv_sec = 1;\r
+ ts.tv_nsec = 0L;\r
+\r
+ do\r
+ {\r
+ nanosleep(&ts, &ts);\r
+ }while(EINTR == errno);\r
+ }\r
+ \r
+ if(errno)\r
+ {\r
+ /* TODO process the error */\r
+ }\r
+ else\r
+ {\r
+ if(runner->waiting)\r
+ {\r
+ exit_code = ELEADTIME;\r
+ err_kind = 1;\r
+ runner->timeouted = 1;\r
+ xbt_os_sem_release(units_sem);\r
+ }\r
+ }\r
+ \r
+ return NULL;\r
+}\r
+#endif\r
+\r
+\r
+int\r
+runner_init(/*int check_syntax_flag, */int timeout, fstreams_t fstreams)\r
+{\r
+ \r
+ int i;\r
+ char* val;\r
+ char buffer[PATH_MAX + 1] = {0};\r
+\r
+ int code;\r
+ const char* cstr;\r
+ variable_t variable;\r
+ \r
+ #if (defined(__CHKCMD) && defined(__BUILTIN) && !defined(WIN32))\r
+ FILE* s;\r
+ int n = 0;\r
+ size_t len;\r
+ char* line = NULL;\r
+ int is_blank;\r
+ #endif\r
+ \r
+ \r
+ if(runner)\r
+ {\r
+ ERROR0("The runner is already initialized");\r
+ return -1;\r
+ }\r
+ \r
+ runner = xbt_new0(s_runner_t, 1);\r
+ \r
+ runner->path = NULL;\r
+ runner->builtin = NULL;\r
+ \r
+ if(!(runner->units = units_new(runner, fstreams)))\r
+ {\r
+ free(runner);\r
+ runner = NULL;\r
+ return -1;\r
+ }\r
+\r
+ runner->timeout = timeout;\r
+ runner->timeouted = 0;\r
+ runner->interrupted = 0;\r
+ runner->number_of_ended_units = 0;\r
+ runner->number_of_runned_units = 0;\r
+ runner->waiting = 0;\r
+ \r
+ runner->total_of_tests = 0;\r
+ runner->total_of_successeded_tests = 0;\r
+ runner->total_of_failed_tests = 0;\r
+ runner->total_of_interrupted_tests = 0;\r
+ \r
+ runner->total_of_units = 0;\r
+ runner->total_of_successeded_units = 0;\r
+ runner->total_of_failed_units = 0;\r
+ runner->total_of_interrupted_units = 0;\r
+ \r
+ runner->total_of_suites = 0;\r
+ runner->total_of_successeded_suites = 0;\r
+ runner->total_of_failed_suites = 0;\r
+ runner->total_of_interrupted_suites = 0;\r
+ \r
+ /* initialize the vector of variables */\r
+ runner->variables = xbt_dynar_new(sizeof(variable_t), (void_f_pvoid_t)variable_free);\r
+ \r
+ /* add the environment variables in the vector */\r
+ for(i = 0; environ[i] != NULL; i++)\r
+ {\r
+ val = strchr(environ[i], '=');\r
+ \r
+ if(val)\r
+ {\r
+ val++;\r
+ \r
+ if(val[0] != '\0')\r
+ strncpy(buffer, environ[i], (val - environ[i] -1));\r
+ \r
+ if(!strcmp("TESH_PPID", buffer))\r
+ is_tesh_root = 0;\r
+ \r
+ variable = variable_new(buffer, val);\r
+ variable->env = 1;\r
+ xbt_dynar_push(runner->variables, &variable);\r
+ \r
+ #ifndef WIN32\r
+ if(!strcmp("PATH", buffer))\r
+ #else\r
+ if(!strcmp("Path", buffer) || !strcmp("PATH", buffer))\r
+ #endif\r
+ {\r
+ char* p;\r
+ size_t j,k, len;\r
+ \r
+ /* get the list of paths */\r
+ \r
+ #ifdef WIN32\r
+ runner->path = explode(';', val);\r
+ #else\r
+ runner->path = explode(':', val);\r
+ #endif\r
+\r
+ /* remove spaces and backslahes at the end of the path */\r
+ for (k = 0; runner->path[k] != NULL; k++)\r
+ {\r
+ p = runner->path[k];\r
+ \r
+ len = strlen(p);\r
+ \r
+ #ifndef WIN32\r
+ for(j = len - 1; p[j] == '/' || p[j] == ' '; j--)\r
+ #else\r
+ for(j = len - 1; p[j] == '\\' || p[j] == ' '; j--)\r
+ #endif\r
+ p[j] = '\0';\r
+ }\r
+ }\r
+ \r
+ \r
+ memset(buffer, 0, PATH_MAX + 1);\r
+ }\r
+ }\r
+ \r
+ if(is_tesh_root)\r
+ {\r
+ char* tesh_dir = getcwd(NULL, 0);\r
+ \r
+ sprintf(buffer,"%d",getpid());\r
+ \r
+ #ifndef WIN32\r
+ setenv("TESH_PPID", buffer, 0);\r
+ setenv("TESH_DIR", tesh_dir, 0);\r
+ #else\r
+ SetEnvironmentVariable("TESH_PPID", buffer);\r
+ SetEnvironmentVariable("TESH_DIR", tesh_dir);\r
+ #endif\r
+ \r
+ variable = variable_new("TESH_PPID", buffer);\r
+ variable->err = 1;\r
+ \r
+ xbt_dynar_push(runner->variables, &variable);\r
+\r
+ variable = variable_new("TESH_DIR", tesh_dir);\r
+ variable->err = 1;\r
+ \r
+ xbt_dynar_push(runner->variables, &variable);\r
+ \r
+ free(tesh_dir);\r
+ }\r
+ \r
+ variable = variable_new("EXIT_SUCCESS", "0");\r
+ variable->err = 1;\r
+ \r
+ xbt_dynar_push(runner->variables, &variable);\r
+\r
+ variable = variable_new("EXIT_FAILURE", "1");\r
+ variable->err = 1;\r
+ \r
+ xbt_dynar_push(runner->variables, &variable);\r
+\r
+ variable = variable_new("TRUE", "0");\r
+ variable->err = 1;\r
+ \r
+ xbt_dynar_push(runner->variables, &variable);\r
+\r
+ variable = variable_new("FALSE", "1");\r
+ variable->err = 1;\r
+ \r
+ xbt_dynar_push(runner->variables, &variable);\r
+\r
+ i = 0;\r
+ \r
+ /* add the errors variables */\r
+ while((cstr = error_get_at(i++, &code)))\r
+ {\r
+ sprintf(buffer,"%d",code);\r
+ variable = variable_new(cstr, buffer);\r
+ variable->err = 1;\r
+ xbt_dynar_push(runner->variables, &variable);\r
+ }\r
+ \r
+ /* if the user want check the syntax, check it */\r
+ /*if(check_syntax_flag)\r
+ check_syntax();\r
+ */\r
+ \r
+ #if (!defined(WIN32) && defined(__CHKCMD))\r
+ #if defined(__BUILTIN)\r
+ \r
+ if(!is_tesh_root)\r
+ {\r
+ /* compute the full path the builtin.def file */\r
+ sprintf(buffer,"%s/builtin.def",getenv("TESH_DIR"));\r
+ \r
+ if(!(s = fopen(buffer, "r"))) \r
+ {\r
+ ERROR1("File `(%s)' not found", buffer);\r
+ return -1;\r
+ }\r
+ \r
+ }\r
+ else\r
+ {\r
+ if(!(s = fopen("builtin.def", "r"))) \r
+ {\r
+ ERROR0("File `(builtin.def)' not found");\r
+ return -1;\r
+ }\r
+ }\r
+ \r
+ if(s)\r
+ {\r
+ fpos_t begin;\r
+\r
+ fgetpos(s, &begin);\r
+\r
+ while(readline(s, &line, &len) != -1)\r
+ {\r
+ i = 0;\r
+ is_blank = 1;\r
+ \r
+\r
+ while(line[i] != '\0') \r
+ {\r
+ if (line[i] != ' ' && line[i] != '\t' && line[i]!='\n' && line[i]!='\r')\r
+ {\r
+ is_blank = 0;\r
+ break;\r
+ }\r
+ \r
+ i++;\r
+ }\r
+\r
+ if(!is_blank)\r
+ n++;\r
+ }\r
+\r
+ fsetpos(s, &begin);\r
+ free(line);\r
+ line = NULL;\r
+\r
+ if(n)\r
+ {\r
+ char* l;\r
+ \r
+ runner->builtin = xbt_new0(char*, n + 1); /* (char**) calloc(n + 1, sizeof(char*));*/\r
+ \r
+ n = 0;\r
+ \r
+ while(readline(s, &line, &len) != -1)\r
+ {\r
+ i = 0;\r
+ is_blank = 1;\r
+\r
+ while(line[i] != '\0') \r
+ {\r
+ if (line[i] != ' ' && line[i] != '\t' && line[i]!='\n' && line[i]!='\r')\r
+ {\r
+ is_blank = 0;\r
+ break;\r
+ }\r
+ \r
+ i++;\r
+ }\r
+\r
+ if(!is_blank)\r
+ {\r
+ l = strdup(line);\r
+\r
+ l[strlen(l) - 1] = '\0';\r
+\r
+ (runner->builtin)[n++] = l;\r
+ \r
+ }\r
+ }\r
+ \r
+ }\r
+ else\r
+ {\r
+ WARN0("The file `(builtin.def)' is empty");\r
+ free(runner->builtin);\r
+ runner->builtin = NULL;\r
+ }\r
+ \r
+\r
+ fclose(s);\r
+ \r
+ if(line)\r
+ free(line);\r
+ \r
+ }\r
+ \r
+ #else\r
+ runner->builtin = xbt_new0(char*, __BUILTIN_MAX + 1); /* (char**) calloc(__BUILTIN_MAX + 1, sizeof(char*));*/\r
+ \r
+ for(i = 0; i < __BUILTIN_MAX; i++)\r
+ runner->builtin[i] = strdup(builtin[i]); \r
+ #endif\r
+ #endif\r
+\r
+ return exit_code ? -1 : 0;\r
+}\r
+\r
+void\r
+runner_destroy(void)\r
+{\r
+ int i;\r
+ \r
+ if(runner->units)\r
+ units_free((void**)(&(runner->units)));\r
+ \r
+ if(runner->variables)\r
+ xbt_dynar_free(&runner->variables);\r
+ \r
+ #ifdef WIN32\r
+ CloseHandle(timer_handle);\r
+ #endif\r
+\r
+ if(runner->thread)\r
+ xbt_os_thread_join(runner->thread, NULL);\r
+ \r
+ if(runner->path)\r
+ {\r
+ for (i = 0; runner->path[i] != NULL; i++)\r
+ free(runner->path[i]);\r
+ \r
+ free(runner->path);\r
+ }\r
+\r
+ if(runner->builtin)\r
+ {\r
+ for (i = 0; runner->builtin[i] != NULL; i++)\r
+ free(runner->builtin[i]);\r
+ \r
+ free(runner->builtin);\r
+ }\r
+\r
+ free(runner);\r
+ \r
+\r
+ runner = NULL;\r
+}\r
+\r
+void\r
+runner_run(void)\r
+{\r
+ /* allocate the mutex used by the units to asynchronously access \r
+ * to the properties of the runner.\r
+ */\r
+ xbt_os_mutex_t mutex = xbt_os_mutex_init();\r
+ \r
+ /* run all the units */\r
+ units_run_all(runner->units, mutex);\r
+ \r
+ \r
+ if(!interrupted)\r
+ runner_wait();\r
+\r
+ \r
+ /* if the runner is timeouted or receive a interruption request\r
+ * , interrupt all the active units.\r
+ */\r
+ if(runner->timeouted || interrupted)\r
+ runner_interrupt();\r
+ \r
+ /* joins all the units */\r
+ units_join_all(runner->units);\r
+ \r
+ /* release the mutex resource */\r
+ xbt_os_mutex_destroy(mutex);\r
+\r
+}\r
+\r
+static void\r
+runner_wait(void)\r
+{\r
+ if(runner->timeout > 0)\r
+ runner->thread = xbt_os_thread_create("", runner_start_routine, NULL);\r
+ \r
+ /* signal that the runner is waiting */\r
+ runner->waiting = 1;\r
+ \r
+ /* wait for the end of all the units */\r
+ xbt_os_sem_acquire(units_sem);\r
+\r
+ \r
+ runner->waiting = 0;\r
+}\r
+\r
+\r
+\r
+/*\r
+ * interrupt all the active units.\r
+ * this function is called when the lead time of the execution is reached\r
+ * or when a failed unit requests an interruption of the execution.\r
+ */\r
+void\r
+runner_interrupt(void)\r
+{\r
+ units_interrupt_all(runner->units);\r
+}\r
+\r
+void\r
+runner_summarize(void)\r
+{\r
+ \r
+ if(!dry_run_flag)\r
+ {\r
+ #ifndef WIN32\r
+ struct rusage r_usage;\r
+ #else\r
+ FILETIME start_time;\r
+ FILETIME exit_time;\r
+ FILETIME kernel_time;\r
+ FILETIME user_time;\r
+ SYSTEMTIME si;\r
+ #endif\r
+ \r
+ printf("\n TEst SHell utility - mini shell specialized in running test units.\n");\r
+ printf(" =============================================================================\n");\r
+ \r
+ units_summuarize(runner->units);\r
+ \r
+ printf(" =====================================================================%s\n",\r
+ runner->total_of_failed_tests ? "== FAILED": (runner->total_of_interrupted_tests || runner->total_of_interrupted_units) ? "==== INTR" : "====== OK");\r
+ \r
+ printf(" TOTAL : Suite(s): %.0f%% ok (%d suite(s): %d ok",\r
+ (runner->total_of_suites ? (1-((double)runner->total_of_failed_suites + (double)runner->total_of_interrupted_suites)/(double)runner->total_of_suites)*100.0 : 100.0),\r
+ runner->total_of_suites, runner->total_of_successeded_suites);\r
+ \r
+ if(runner->total_of_failed_suites > 0)\r
+ printf(", %d failed", runner->total_of_failed_suites);\r
+ \r
+ if(runner->total_of_interrupted_suites > 0)\r
+ printf(", %d interrupted)", runner->total_of_interrupted_suites);\r
+ \r
+ printf(")\n"); \r
+ \r
+ printf(" Unit(s): %.0f%% ok (%d unit(s): %d ok",\r
+ (runner->total_of_units ? (1-((double)runner->total_of_failed_units + (double)runner->total_of_interrupted_units)/(double)runner->total_of_units)*100.0 : 100.0),\r
+ runner->total_of_units, runner->total_of_successeded_units);\r
+ \r
+ if(runner->total_of_failed_units > 0)\r
+ printf(", %d failed", runner->total_of_failed_units);\r
+ \r
+ if(runner->total_of_interrupted_units > 0)\r
+ printf(", %d interrupted)", runner->total_of_interrupted_units);\r
+ \r
+ printf(")\n");\r
+ \r
+ printf(" Test(s): %.0f%% ok (%d test(s): %d ok",\r
+ (runner->total_of_tests ? (1-((double)runner->total_of_failed_tests + (double)runner->total_of_interrupted_tests)/(double)runner->total_of_tests)*100.0 : 100.0),\r
+ runner->total_of_tests, runner->total_of_successeded_tests);\r
+ \r
+ if(runner->total_of_failed_tests > 0)\r
+ printf(", %d failed", runner->total_of_failed_tests);\r
+ \r
+ if(runner->total_of_interrupted_tests > 0)\r
+ printf(", %d interrupted)", runner->total_of_interrupted_tests);\r
+ \r
+ printf(")\n\n");\r
+ \r
+ #ifndef WIN32\r
+ if(!getrusage(RUSAGE_SELF, &r_usage))\r
+ {\r
+ \r
+ printf(" Total tesh user time used: %ld second(s) %ld microsecond(s)\n", r_usage.ru_utime.tv_sec, r_usage.ru_utime.tv_usec);\r
+ printf(" Total tesh system time used: %ld second(s) %ld microsecond(s)\n\n", r_usage.ru_stime.tv_sec, r_usage.ru_stime.tv_usec);\r
+ \r
+ if(!getrusage(RUSAGE_CHILDREN, &r_usage))\r
+ {\r
+ printf(" Total children user time used: %ld second(s) %ld microsecond(s)\n", r_usage.ru_utime.tv_sec, r_usage.ru_utime.tv_usec);\r
+ printf(" Total children system time used: %ld second(s) %ld microsecond(s)\n\n", r_usage.ru_stime.tv_sec, r_usage.ru_stime.tv_usec);\r
+ \r
+ } \r
+ }\r
+ #else\r
+ \r
+ if(GetProcessTimes(GetCurrentProcess(), &start_time, &exit_time, &kernel_time, &user_time))\r
+ {\r
+ FileTimeToSystemTime(&user_time, &si);\r
+ \r
+ printf(" Total tesh user time used: %uhour(s) %uminute(s) %usecond(s) %millisecond(s)\n", si.wHour, si.wMinute, si.wSecond, si.wMilliseconds );\r
+ \r
+ FileTimeToSystemTime(&kernel_time, &si);\r
+ \r
+ printf(" Total tesh kernel time used: %uhour(s) %uminute(s) %usecond(s) %millisecond(s)\n", si.wHour, si.wMinute, si.wSecond, si.wMilliseconds );\r
+ }\r
+\r
+\r
+\r
+ #endif\r
+ }\r
+ else\r
+ {\r
+ if(exit_code)\r
+ ERROR0("Syntax NOK");\r
+ else if(!exit_code)\r
+ INFO0("Syntax 0K");\r
+ }\r
+}\r
+\r
+int\r
+runner_is_timedout(void)\r
+{\r
+ return runner->timeouted;\r
+}\r
+\r
\r
#include <stdio.h>\r
\r
-int\r
+/*int\r
str_replace(char** str, const char* what, const char* with)\r
{\r
size_t pos, i;\r
return 0;\r
\r
} \r
+*/\r
+\r
+/* last version int\r
+str_replace(char** str, const char* what, const char* with, const char* delimiters)\r
+{\r
+ size_t pos, i, len;\r
+ char* begin;\r
+ char* buf;\r
+ char* delimited;\r
+ int size;\r
+\r
+ if(!*str || !what || !with || !delimiters)\r
+ {\r
+ errno = EINVAL;\r
+ return -1;\r
+ }\r
+\r
+ \r
+ if(!(delimited = (char*) calloc((strlen(what) + 2) , sizeof(char))))\r
+ return -1;\r
+\r
+ len = strlen(delimiters);\r
+\r
+ for(i = 0; i < len; i++)\r
+ {\r
+ memset(delimited, 0, (strlen(what) + 2));\r
+\r
+ sprintf(delimited,"%s%c", what, delimiters[i]);\r
+ \r
+ if((begin = strstr(*str, delimited)))\r
+ break;\r
+ }\r
+ \r
+ free(delimited);\r
+ \r
+ \r
+ if(!begin && (size = (int)strlen(*str) - (int)strlen(what)) >= 0 && !strcmp(*str + size, what))\r
+ begin = strstr(*str, what);\r
+ \r
+ if(!begin)\r
+ {\r
+ errno = ESRCH;\r
+ return -1;\r
+ }\r
+ \r
+ pos = begin - *str;\r
+ \r
+ i = 0;\r
+ \r
+ pos += strlen(what);\r
+\r
+ if(begin == *str)\r
+ {\r
+ \r
+\r
+ if(!(buf = (char*) calloc(strlen(with) + ((pos < strlen(*str)) ? strlen(*str + pos) : 0) + 1, sizeof(char))))\r
+ return -1;\r
+ \r
+ strcpy(buf, with);\r
+ \r
+ if(pos < strlen(*str))\r
+ strcpy(buf + strlen(with), *str + pos);\r
+ }\r
+ else\r
+ {\r
+ if(!(buf = (char*) calloc((begin - *str) + strlen(with) + ((pos < strlen(*str)) ? strlen(*str + pos) : 0) + 1, sizeof(char))))\r
+ return -1;\r
+ \r
+ strncpy(buf, *str, (begin - *str));\r
+ strcpy(buf + (begin - *str) , with);\r
+\r
+ if(pos < strlen(*str))\r
+ strcpy(buf + (begin - *str) + strlen(with), *str + pos);\r
+ } \r
+ \r
+ free(*str);;\r
+ *str = buf;\r
+ \r
+ return 0;\r
+ \r
+}*/\r
\r
int\r
+str_replace(char** str, const char* what, const char* with, const char* delimiters)\r
+{\r
+ size_t pos, i, len;\r
+ char* begin;\r
+ char* buf;\r
+ int size;\r
+\r
+ if(!*str || !what)\r
+ {\r
+ errno = EINVAL;\r
+ return -1;\r
+ }\r
+\r
+ if(delimiters)\r
+ {\r
+ char* delimited;\r
+\r
+ if(!(delimited = (char*) calloc((strlen(what) + 2) , sizeof(char))))\r
+ return -1;\r
+\r
+ len = strlen(delimiters);\r
+\r
+ for(i = 0; i < len; i++)\r
+ {\r
+ memset(delimited, 0, (strlen(what) + 2));\r
+\r
+ sprintf(delimited,"%s%c", what, delimiters[i]);\r
+ \r
+ if((begin = strstr(*str, delimited)))\r
+ break;\r
+ }\r
+ \r
+ free(delimited);\r
+ }\r
+ else\r
+ begin = strstr(*str, what);\r
+ \r
+ \r
+ if(!begin && (size = (int)strlen(*str) - (int)strlen(what)) >= 0 && !strcmp(*str + size, what))\r
+ begin = strstr(*str, what);\r
+ \r
+ if(!begin)\r
+ {\r
+ errno = ESRCH;\r
+ return -1;\r
+ }\r
+ \r
+ pos = begin - *str;\r
+ \r
+ i = 0;\r
+ \r
+ pos += strlen(what);\r
+\r
+ if(begin == *str)\r
+ {\r
+ if(!(buf = (char*) calloc((with ? strlen(with) : 0) + ((pos < strlen(*str)) ? strlen(*str + pos) : 0) + 1, sizeof(char))))\r
+ return -1;\r
+ \r
+ if(with)\r
+ strcpy(buf, with);\r
+ \r
+ if(pos < strlen(*str))\r
+ strcpy(buf + (with ? strlen(with) : 0), *str + pos);\r
+ }\r
+ else\r
+ {\r
+ if(!(buf = (char*) calloc((begin - *str) + (with ? strlen(with) : 0) + ((pos < strlen(*str)) ? strlen(*str + pos) : 0) + 1, sizeof(char))))\r
+ return -1;\r
+ \r
+ strncpy(buf, *str, (begin - *str));\r
+ \r
+ if(with)\r
+ strcpy(buf + (begin - *str) , with);\r
+\r
+ if(pos < strlen(*str))\r
+ strcpy(buf + (begin - *str) + (with ? strlen(with) : 0), *str + pos);\r
+ } \r
+ \r
+ free(*str);\r
+\r
+ *str = buf;\r
+ \r
+ return 0;\r
+ \r
+} \r
+\r
+int\r
+str_replace_all(char** str, const char* what, const char* with, const char* delimiters)\r
+{\r
+ int rv;\r
+ \r
+ while(!(rv = str_replace(str, what, with, delimiters)));\r
+ \r
+ return (errno == ESRCH) ? 0 : -1;\r
+}\r
+\r
+\r
+/*int\r
str_replace_all(char** str, const char* what, const char* with)\r
{\r
int rv;\r
while(!(rv = str_replace(str, what, with)));\r
\r
return (errno == ESRCH) ? 0 : -1;\r
-}\r
+}*/\r
+\r
\r
\r
{\r
variable_t variable;\r
\r
- if(!name || !val)\r
+ if(!name)\r
{\r
errno = EINVAL;\r
return NULL;\r
variable = xbt_new0(s_variable_t, 1);\r
\r
variable->name = strdup(name);\r
- variable->val = strdup(val);\r
+\r
+ if(val)\r
+ variable->val = strdup(val);\r
+\r
variable->used = 0;\r
variable->env = 0;\r
variable->err = 0;\r
MinimalRebuild="true"\r
BasicRuntimeChecks="3"\r
RuntimeLibrary="2"\r
+ BufferSecurityCheck="true"\r
UsePrecompiledHeader="0"\r
WarningLevel="3"\r
Detect64BitPortabilityProblems="true"\r
<File\r
RelativePath="..\src\main.c"\r
>\r
+ <FileConfiguration\r
+ Name="Debug|Win32"\r
+ >\r
+ <Tool\r
+ Name="VCCLCompilerTool"\r
+ BufferSecurityCheck="false"\r
+ />\r
+ </FileConfiguration>\r
</File>\r
<File\r
RelativePath="..\src\reader.c"\r