From: cherierm Date: Thu, 19 Jun 2008 19:25:28 +0000 (+0000) Subject: last modification of the tesh2 files (variable extend and some corrections) X-Git-Tag: v3.3~325 X-Git-Url: http://info.iut-bm.univ-fcomte.fr/pub/gitweb/simgrid.git/commitdiff_plain/1c622be53c551a86b0fbf5ce8f2ee2d776f421b2 last modification of the tesh2 files (variable extend and some corrections) git-svn-id: svn+ssh://scm.gforge.inria.fr/svn/simgrid/simgrid/trunk@5772 48e7efb5-ca39-0410-a469-dd3cf9ba447f --- diff --git a/tools/tesh2/examples/catch-return.tesh b/tools/tesh2/examples/catch-return.tesh index 50d48ae124..6411ec9005 100644 --- a/tools/tesh2/examples/catch-return.tesh +++ b/tools/tesh2/examples/catch-return.tesh @@ -1 +1 @@ -#! ./tesh # This suite builds and uses a program returning 1. # tesh must detect this condition and report the issue. $ rm -rf temp_testdir $ mkdir temp_testdir $ cd temp_testdir < #include < int main(void) { < exit(1); < } $ cat > return1.c $ gcc -o return1 return1.c ! expect return $EEXITCODENOTMATCH < $ ./return1 $ ../tesh --log="log.thresh:info tesh.fmt:%m%n" > Test unit from stdin > [stdin:1] ./return1 > [stdin:1] ./return1 : NOK (returned code `1' instead `0') > Output of so far: > || > Test unit `stdin': NOK ( exit code mismatch) $ cd .. $ rm -rf temp_testdir \ No newline at end of file +#! ./tesh # This suite builds and uses a program returning 1. # tesh must detect this condition and report the issue. $ rm -rf temp_testdir $ mkdir temp_testdir $ cd temp_testdir < #include < int main(void) { < exit(1); < } $ cat > return1.c $ gcc -o return1 return1.c ! expect return $EEXITCODENOTMATCH < $ ./return1 $ ../tesh --log="log.thresh:info tesh.fmt:%m%n" > Test unit from stdin > [stdin:1] ./return1 > [stdin:1] ./return1 : NOK (returned code `1' instead `0') > Output of so far: > || > Test unit `stdin': NOK ( exit code mismatch) $ cd .. $ rm -rf temp_testdir \ No newline at end of file diff --git a/tools/tesh2/examples/var.tesh b/tools/tesh2/examples/var.tesh index 7b42d40f37..31000bce4b 100644 --- a/tools/tesh2/examples/var.tesh +++ b/tools/tesh2/examples/var.tesh @@ -105,27 +105,62 @@ $ ./tesh --log="log.thresh:info tesh.fmt:%m%n" > [stdin:1] A system variable named `(ENOENT)' already exists > Test unit `stdin': NOK ( 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} diff --git a/tools/tesh2/include/str_replace.h b/tools/tesh2/include/str_replace.h index c58242a70d..4c18e355d2 100644 --- a/tools/tesh2/include/str_replace.h +++ b/tools/tesh2/include/str_replace.h @@ -1,14 +1,16 @@ #ifndef __STR_REPLACE_H #define __STR_REPLACE_H +#include + #ifdef __cplusplus extern "C" { #endif int -str_replace(char** str, const char *what, const char *with); +str_replace(char** str, const char *what, const char *with, const char* delimiters); int -str_replace_all(char** str, const char* what, const char* with); +str_replace_all(char** str, const char* what, const char* with, const char* delimiters); #ifdef __cplusplus } diff --git a/tools/tesh2/include/types.h b/tools/tesh2/include/types.h index f3edcb1866..ae5fcc4251 100644 --- a/tools/tesh2/include/types.h +++ b/tools/tesh2/include/types.h @@ -315,6 +315,11 @@ typedef struct s_context 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; /* diff --git a/tools/tesh2/src/command.c b/tools/tesh2/src/command.c index 3e11849946..958c0f4a7a 100644 --- a/tools/tesh2/src/command.c +++ b/tools/tesh2/src/command.c @@ -162,7 +162,7 @@ command_new(unit_t unit, context_t context, xbt_os_mutex_t mutex) int command_run(command_t command) { - if(!silent_flag) + if(!silent_flag && !interrupted) INFO2("[%s] %s",command->context->pos, command->context->command_line); if(!just_print_flag) @@ -208,7 +208,13 @@ command_start(void* p) xbt_os_mutex_release(command->mutex); /* execute the command of the test */ + + #ifndef WIN32 command_exec(command, command->context->command_line); + #else + /* play the translated command line on Windows */ + command_exec(command, command->context->t_command_line); + #endif if(cs_in_progress == command->status) { @@ -816,7 +822,7 @@ command_check(command_t command) xbt_strbuff_trim(command->output); xbt_strbuff_trim(command->context->output); - if(!success) + if(!success && !strcmp(command->output->data, command->context->output->data)) { xbt_dynar_t a = xbt_str_split(command->output->data, "\n"); char *out = xbt_str_join(a,"\n||"); @@ -830,6 +836,7 @@ command_check(command_t command) if(command->output->used != command->context->output->used || strcmp(command->output->data, command->context->output->data)) { char *diff; + ERROR2("[%s] `%s' : NOK (outputs mismatch):", command->context->pos, command->context->command_line); diff --git a/tools/tesh2/src/context.c b/tools/tesh2/src/context.c index 22a44fc3a5..877ffc22bf 100644 --- a/tools/tesh2/src/context.c +++ b/tools/tesh2/src/context.c @@ -34,6 +34,10 @@ context_new(void) context->signal = INDEFINITE_SIGNAL; context->output_handling = oh_check; context->async = 0; + + #ifdef WIN32 + context->t_command_line = NULL; + #endif return context; } @@ -56,6 +60,11 @@ context_free(context_t* ptr) if((*ptr)->signal) free((*ptr)->signal); + #ifdef WIN32 + if((*ptr)->t_command_line) + free((*ptr)->t_command_line); + #endif + *ptr = NULL; return 0; @@ -73,6 +82,14 @@ context_reset(context_t context) context->command_line = NULL; } + #ifdef WIN32 + if(context->t_command_line) + { + free(context->t_command_line); + context->t_command_line = NULL; + } + #endif + if(context->pos) { free(context->pos); @@ -111,6 +128,12 @@ context_dup(context_t context) dup->line = context->line; dup->pos = strdup(context->pos); dup->command_line = strdup(context->command_line); + + + #ifdef WIN32 + dup->t_command_line = strdup(context->t_command_line); + #endif + dup->exit_code = context->exit_code; dup->timeout = context->timeout; dup->output = NULL; @@ -158,6 +181,14 @@ context_clear(context_t context) context->command_line = NULL; } + #ifdef WIN32 + if(context->t_command_line) + { + free(context->t_command_line); + context->t_command_line = NULL; + } + #endif + if(context->pos) { free(context->pos); diff --git a/tools/tesh2/src/fstream.c b/tools/tesh2/src/fstream.c index 5d10d82294..36bb0f16e6 100644 --- a/tools/tesh2/src/fstream.c +++ b/tools/tesh2/src/fstream.c @@ -23,16 +23,52 @@ #include #include +#include #ifndef WIN32 #include #endif +#ifdef WIN32 +static int +is_w32_cmd(const char* cmd, char** path) +{ + size_t i = 0; + struct stat stat_buff = {0}; + char buff[PATH_MAX + 1] = {0}; + -XBT_LOG_EXTERNAL_DEFAULT_CATEGORY(tesh); + if(!cmd) + { + errno = EINVAL; + return 0; + } + + if(stat(cmd, &stat_buff) || !S_ISREG(stat_buff.st_mode)) + { + if(path) + { + for (i = 0; path[i] != NULL; i++) + { + + sprintf(buff,"%s\\%s",path[i], cmd); + + if(!stat(buff, &stat_buff) && S_ISREG(stat_buff.st_mode)) + return 1; + } + } + } + else + return 1; + + + return 0; +} +#endif +XBT_LOG_EXTERNAL_DEFAULT_CATEGORY(tesh); long fstream_getline(fstream_t fstream, char **buf, size_t *n) { @@ -360,9 +396,20 @@ fstream_lex_line(fstream_t fstream, context_t context, xbt_os_mutex_t mutex, con char* line2; variable_t variable; unsigned int i; - char name[VAR_NAME_MAX + 1] = {0}; + char exp[VAR_NAME_MAX + 1] = {0}; unit_t unit = fstream->unit; xbt_dynar_t variables = unit->runner->variables; + char* p= NULL; + char* end = NULL; + char* val = NULL; + char buff[VAR_NAME_MAX + 1] = {0}; + size_t len; + char delimiters[4] = {' ', '\t', '\n', '\0'}; + + int j; + + if(line[0] == '#') + return; if(unit->is_running_suite && strncmp(line, "! include", strlen("! include"))) {/* it's the end of a suite */ @@ -377,35 +424,605 @@ fstream_lex_line(fstream_t fstream, context_t context, xbt_os_mutex_t mutex, con unit_set_error(*current_suite, ESYNTAX, 1, filepos); failure(fstream->unit); - - } context->line = strdup(filepos); - /* search end */ xbt_str_rtrim(line + 2,"\n"); line2 = strdup(line); - + + len = strlen(line2 + 2) + 1; + /* replace each variable by its value */ xbt_os_mutex_acquire(unit->mutex); + + + /* replace all existing + ${var} + ${var:=val} + ${var:+val} + ${var:-val} + ${var:?val} + ${#var} + */ + + xbt_dynar_foreach(variables, i, variable) + { + if(!(p = strstr(line2 + 2, "${"))) + break; + + memset(buff, 0, len); + + sprintf(buff,"${%s",variable->name); + + /* FALSE */ + if((p = strstr(line2 + 2, buff))) + { + memset(buff, 0, len); + p--; + j = 0; + + while(*(p++) != '\0') + { + buff[j++] = *p; + + if(*p == '}') + break; + } + + if(buff[j - 1] != '}') + { + xbt_os_mutex_release(unit->mutex); + + + ERROR2("[%s] Syntax error : `%s'.",filepos, p - j); + + unit_set_error(fstream->unit, ESYNTAX, 1, filepos); + failure(fstream->unit); + return; + } + + if((p = strstr(buff , ":="))) + { + /* ${var:=val} */ + + /* if the value of the variable is empty, update its value by the value*/ + p += 2; + + end = strchr(p, '}'); + + if(!end || (end == p)) + { + xbt_os_mutex_release(unit->mutex); + + + ERROR2("[%s] Bad substitution : `%s'.",filepos, strstr(buff, "${")); + + unit_set_error(fstream->unit, ESYNTAX, 1, filepos); + failure(fstream->unit); + return; + } + + val = (char*) calloc((size_t)(end - p) + 1, sizeof(char)); + + strncpy(val, p,(end - p)); + + + /* replace the expression by the expression of the value of the variable*/ + sprintf(exp, "${%s:=%s}", variable->name, val); + + if(variable->val) + str_replace_all(&line2, exp, variable->val, NULL); + else + { + str_replace_all(&line2, exp, val, NULL); + + variable->val = strdup(val); + } + + memset(exp, 0, VAR_NAME_MAX + 1); + + if(val) + { + free(val); + val = NULL; + } + + } + else if((p = strstr(buff, ":-"))) + { + /* ${var:-val} */ + + /* if the value of the variable is empty, replace the expression by the value */ + p += 2; + end = strchr(p, '}'); + + if(!end || (end == p)) + { + xbt_os_mutex_release(unit->mutex); + + ERROR2("[%s] Bad substitution : `%s'.",filepos, strstr(line2, "${")); + + unit_set_error(fstream->unit, ESYNTAX, 1, filepos); + failure(fstream->unit); + return; + } + + val = (char*) calloc((size_t)(end - p) + 1, sizeof(char)); + + strncpy(val, p,(end - p)); + + sprintf(exp, "${%s:-%s}", variable->name, val); + + str_replace_all(&line2, exp, variable->val ? variable->val : val, NULL); + + + memset(exp, 0, VAR_NAME_MAX + 1); + + if(val) + { + free(val); + val = NULL; + } + + } + else if((p = strstr(buff, ":+"))) + { + /* ${var:+val} */ + + /* if the value of the variable is not empty, replace the expression by the value */ + p += 2; + + end = strchr(p, '}'); + + if(!end || (end == p)) + { + xbt_os_mutex_release(unit->mutex); + + + ERROR2("[%s] Bad substitution : `%s'.",filepos, strstr(line2, "${")); + + unit_set_error(fstream->unit, ESYNTAX, 1, filepos); + failure(fstream->unit); + return; + } + + val = (char*) calloc((size_t)(end - p) + 1, sizeof(char)); + + strncpy(val, p,(end - p)); + + sprintf(exp, "${%s:+%s}", variable->name, val); + + if(variable->val) + { + str_replace_all(&line2, exp, val, NULL); + } + else + { + str_replace_all(&line2, exp, NULL , NULL); + variable->val = strdup(val); + } + + memset(exp, 0, VAR_NAME_MAX + 1); + + if(val) + { + free(val); + val = NULL; + } + } + else if((p = strstr(buff, ":?"))) + { + /* ${var:?val} */ + + /* if the value of the variable is not empty, replace the expression by the value */ + p += 2; + end = strchr(p, '}'); + + if(!end || (end == p)) + { + xbt_os_mutex_release(unit->mutex); + + ERROR2("[%s] Bad substitution : `%s'.",filepos, strstr(line2, "${")); + + unit_set_error(fstream->unit, ESYNTAX, 1, filepos); + failure(fstream->unit); + return; + } + + val = (char*) calloc((size_t)(end - p) + 1, sizeof(char)); + + strncpy(val, p,(end - p)); + + sprintf(exp, "${%s:?%s}", variable->name, val); + + if(variable->val) + str_replace_all(&line2, exp, variable->val, NULL); + else + { + + xbt_os_mutex_release(unit->mutex); + + ERROR2("[%s] %s.",filepos, val); + + unit_set_error(fstream->unit, ESYNTAX, 1, filepos); + failure(fstream->unit); + return; + } + + memset(exp, 0, VAR_NAME_MAX + 1); + + if(val) + { + free(val); + val = NULL; + } + } + } + } + /* replace all existing $var */ xbt_dynar_foreach(variables, i, variable) { - sprintf(name, "$%s", variable->name); - str_replace_all(&line2, name, variable->val); - memset(name, 0, VAR_NAME_MAX + 1); + if(!strchr(line2 + 2, '$')) + break; + + if(strstr(line2 + 2, variable->name)) + { + + sprintf(exp, "${#%s}", variable->name); + + if(strstr(line2 + 2, exp)) + { + + if(variable->val) + { + char slen[4] = {0}; + sprintf(slen,"%d", (int)strlen(variable->val)); + str_replace_all(&line2, exp, slen, NULL); + } + else + str_replace_all(&line2, exp, "0", NULL); + } + + memset(exp, 0, VAR_NAME_MAX + 1); + + sprintf(exp, "${%s}", variable->name); + + if(strstr(line2 + 2, exp)) + { + if(variable->val) + str_replace_all(&line2, exp, variable->val, NULL); + else + str_replace_all(&line2, exp, NULL, NULL); + } + + memset(exp, 0, VAR_NAME_MAX + 1); + + sprintf(exp, "$%s", variable->name); + + if((p = strstr(line2 + 2, exp))) + { + if((p + strlen(variable->name) + 1)[0] != '\0') + delimiters[0] = (p + strlen(variable->name) + 1)[0]; + + if(variable->val) + str_replace_all(&line2, exp, variable->val, delimiters); + else + str_replace_all(&line2, exp, NULL, delimiters); + } + + memset(exp, 0, VAR_NAME_MAX + 1); + + } + } + + while((p = strstr(line2 + 2, "${"))) + { + /*if(*(p+1) != '{') + { + j = 0; + p --; + + while(*(p++) != '\0') + { + if(*p != ' ' && *p !='\t') + exp[j++] = *p; + else + break; + + } + + str_replace_all(&line2, exp, NULL, " \t\n\r"); + memset(exp, 0, VAR_NAME_MAX + 1); + }. + else + */ + { + char* begin = NULL; + + j = 0; + p --; + + while(*(p++) != '\0') + { + if((!begin && *p != ' ' && *p !='\t') || begin) + { + /* `:' must be before this caracter, bad substitution : exit loop + || + the current character is already present, bad substitution : exit loop + */ + if( + ( + *(p - 1) != ':' && ( + (*p == '=') || (*p == '-') || (*p == '+') || (*p == '?') + ) + ) + || + ( + begin && ( + (*p == ':') || (*p == '=') || (*p == '-') || (*p == '+') || (*p == '?') + ) + ) + ) + break; + else + exp[j++] = *p; + + if(*p == ':') + { + /* save the begining of the value */ + if((*(p+1) == '=') || (*(p+1) == '-') || (*(p+1) == '+') || (*(p+1) == '?')) + { + begin = p + 2; + exp[j++] = *(p+1); + p++; + continue; + + } + else + /* the current char is `:' but the next is invalid, bad substitution : exit loop */ + break; + } + /* end of the substitution : exit loop */ + else if(*p == '}') + break; + } + else + break; + } + + if(exp[j - 1] == '}') + { + if(exp[2] == '#') + { + /* ${#var} */ + + + if(4 == strlen(exp)) + { + xbt_os_mutex_release(unit->mutex); + + ERROR2("[%s] Bad substitution : `%s'.",filepos, strchr(line2 + 2, '$')); + + unit_set_error(fstream->unit, ESYNTAX, 1, filepos); + failure(fstream->unit); + return; + } + + str_replace_all(&line2, exp, "0", NULL); + } + else if(strstr(exp,":=")) + { + /* ${var:=value} */ + + end = strchr(p, '}'); + + if(!end || (end == begin)) + { + xbt_os_mutex_release(unit->mutex); + + + ERROR2("[%s] Bad substitution : `%s'.",filepos, strchr(line2 + 2, '$')); + + unit_set_error(fstream->unit, ESYNTAX, 1, filepos); + failure(fstream->unit); + return; + } + + variable = xbt_new0(s_variable_t, 1); + + variable->val = (char*) calloc((size_t)(end - begin) + 1, sizeof(char)); + + strncpy(variable->val, begin ,(end - begin)); + + begin = exp + 2; + end = strchr(exp, ':'); + + if(!end || (end == begin)) + { + xbt_os_mutex_release(unit->mutex); + + + ERROR2("[%s] Bad substitution : `%s'.",filepos, strchr(line2 + 2, '$')); + + unit_set_error(fstream->unit, ESYNTAX, 1, filepos); + failure(fstream->unit); + return; + } + + variable->name = (char*) calloc((size_t)(end - begin) + 1, sizeof(char)); + + strncpy(variable->name, exp + 2 ,(end - begin)); + + str_replace_all(&line2, exp, variable->val, NULL); + + xbt_dynar_push(variables, &variable); + + } + else if(strstr(exp,":-")) + { + /* ${var:-value} */ + + + end = strchr(p, '}'); + + if(!end || (end == begin)) + { + xbt_os_mutex_release(unit->mutex); + + + ERROR2("[%s] Bad substitution : `%s'.",filepos, strchr(line2 + 2, '$')); + + unit_set_error(fstream->unit, ESYNTAX, 1, filepos); + failure(fstream->unit); + return; + } + + val = (char*) calloc((size_t)(end - begin) + 1, sizeof(char)); + + strncpy(val, begin ,(end - begin)); + + str_replace_all(&line2, exp, val, NULL); + + if(val) + free(val); + + } + else if(strstr(exp,":+")) + { + /* ${var:+value} */ + + end = strchr(p, '}'); + + if(!end || (end == begin)) + { + xbt_os_mutex_release(unit->mutex); + + ERROR2("[%s] Bad substitution : `%s'.",filepos, strchr(line2 + 2, '$')); + + unit_set_error(fstream->unit, ESYNTAX, 1, filepos); + failure(fstream->unit); + return; + } + + str_replace_all(&line2, exp, NULL, NULL); + } + else if(strstr(exp,":?")) + { + /* ${var:?value} */ + + end = strchr(p, '}'); + + if(!end || (end == begin)) + { + xbt_os_mutex_release(unit->mutex); + + ERROR2("[%s] Bad substitution : `%s'.",filepos, strchr(line2 + 2, '$')); + + unit_set_error(fstream->unit, ESYNTAX, 1, filepos); + failure(fstream->unit); + return; + } + + val = (char*) calloc((size_t)(end - begin) + 1, sizeof(char)); + + strncpy(val, begin ,(end - begin)); + + xbt_os_mutex_release(unit->mutex); + + ERROR2("[%s] : `%s'.",filepos, val); + + if(val) + free(val); + + unit_set_error(fstream->unit, ESYNTAX, 1, filepos); + failure(fstream->unit); + + return; + + } + else + { + /* ${var} */ + + if(3 == strlen(exp)) + { + xbt_os_mutex_release(unit->mutex); + + ERROR2("[%s] Bad substitution : `%s'.",filepos, strchr(line2 + 2, '$')); + + unit_set_error(fstream->unit, ESYNTAX, 1, filepos); + failure(fstream->unit); + return; + } + + str_replace_all(&line2, exp, NULL, NULL); + + } + + memset(exp, 0, VAR_NAME_MAX + 1); + } + else + { + xbt_os_mutex_release(unit->mutex); + + if(strstr(line2 + 2, "${")) + ERROR2("[%s] Bad substitution : `%s'.",filepos, strstr(line2, "${")); + else + ERROR2("[%s] Syntax error : `%s'.",filepos, strstr(line2, "${")); + + unit_set_error(fstream->unit, ESYNTAX, 1, filepos); + failure(fstream->unit); + return; + } + + } + } - xbt_os_mutex_release(unit->mutex); + p = line2 + 2; + + while(p && 1) + { + if((p = strchr(p, '$'))) + { + if(*(p+1) != ' ') + { + j = 0; + p --; + + while(*(p++) != '\0') + { + if(*p != ' ' && *p !='\t') + exp[j++] = *p; + else + break; + + } + + str_replace_all(&line2, exp, NULL, " \t\n\r"); + memset(exp, 0, VAR_NAME_MAX + 1); + } + else + { + /* maybe < $ cmd */ + p++; + } + } + else + break; + } + xbt_os_mutex_release(unit->mutex); switch(line2[0]) { - case '#': + /*case '#': break; + */ case '$': case '&': @@ -496,9 +1113,14 @@ fstream_lex_line(fstream_t fstream, context_t context, xbt_os_mutex_t mutex, con char* prompt = line2 + 2; - for(j = 0; j < strlen(prompt); j++) + for(j = 0; j < strlen(prompt); j++) + { if (prompt[j] != ' ' && prompt[j] != '\t') + { is_blank = 0; + break; + } + } if(is_blank) { @@ -634,8 +1256,106 @@ fstream_process_token(fstream_t fstream, context_t context, xbt_os_mutex_t mutex } context->command_line = strdup(line); + + xbt_str_ltrim(context->command_line," "); + context->line = /*strdup(filepos)*/ filepos; context->pos = strdup(filepos); + + #ifdef WIN32 + { + + /* translate the command line */ + + char* path; + char* delimiter; + char command_line[PATH_MAX + 1] = {0}; + size_t i = 0; + char* args = NULL; + + + + if(strstr(context->command_line,".exe")) + strcpy(command_line,context->command_line); + else + { + size_t len; + + size_t j = 0; + + len = strlen(context->command_line); + + while(i < len) + { + if(context->command_line[i] != ' ' && context->command_line[i] != '\t' && context->command_line[i] != '>') + command_line[j++] = context->command_line[i]; + else + break; + + i++; + } + + strcat(command_line,".exe"); + + args = strdup(context->command_line + i); + } + + if(getpath(command_line, &path) && !is_w32_cmd(command_line, fstream->unit->runner->path)) + { + ERROR3("[%s] `%s' : NOK (%s)", filepos, context->command_line, error_to_string(ECMDNOTFOUND, 1)); + unit_set_error(fstream->unit, ECMDNOTFOUND, 1, filepos); + failure(unit); + return; + } + + delimiter = strrchr(command_line,'/'); + + if(!delimiter) + delimiter = strrchr(command_line,'\\'); + + /*free(context->command_line);*/ + + + if(path) + { + if(args) + { + context->t_command_line = (char*)calloc(strlen(path) + strlen(delimiter ? delimiter + 1 : command_line) + strlen(args) + 2, sizeof(char)); + sprintf(context->t_command_line,"%s\\%s%s",path,delimiter ? delimiter + 1 : command_line, args); + + free(args); + + } + else + { + context->t_command_line = (char*)calloc(strlen(path) + strlen(delimiter ? delimiter + 1 : command_line) + 2, sizeof(char)); + sprintf(context->t_command_line,"%s\\%s",path,delimiter ? delimiter + 1 : command_line); + } + + free(path); + } + else + { + if(args) + { + context->t_command_line = (char*)calloc(strlen(command_line) + strlen(args) + 1, sizeof(char)); + sprintf(context->t_command_line,"%s%s",command_line, args); + + free(args); + + } + else + { + context->t_command_line = (char*)calloc(strlen(command_line) + 1, sizeof(char)); + strcpy(context->t_command_line,command_line); + } + } + + + } + #endif + + break; case '<': @@ -1163,8 +1883,19 @@ fstream_process_token(fstream_t fstream, context_t context, xbt_os_mutex_t mutex if(!env && !err) { if(exists) + { /*xbt_dynar_remove_at(unit->runner->variables, i, NULL);*/ - xbt_dynar_cursor_rm(unit->runner->variables, &i); + /*xbt_dynar_cursor_rm(unit->runner->variables, &i);*/ + if(variable->val) + { + free(variable->val); + variable->val = NULL; + } + else + { + WARN2("[%s] Variable `(%s)' already unseted",filepos, variable->name); + } + } else { ERROR2("[%s] `(%s)' variable not found",filepos, name); diff --git a/tools/tesh2/src/getpath.c b/tools/tesh2/src/getpath.c index 54d1a2466e..40b98809ab 100644 --- a/tools/tesh2/src/getpath.c +++ b/tools/tesh2/src/getpath.c @@ -1,5 +1,7 @@ #include +XBT_LOG_EXTERNAL_DEFAULT_CATEGORY(tesh); + /*#include #include @@ -300,13 +302,14 @@ translatepath(const char* totranslate, char** translated) return len; } #else -int +/*int getpath(const char* file, char** path) { DWORD len; char* part = NULL; char buffer[PATH_MAX + 1] = {0}; struct stat info = {0}; + len = GetFullPathName(file, PATH_MAX, buffer, &part ); @@ -315,7 +318,6 @@ getpath(const char* file, char** path) *path = NULL; return -1; } - if(stat(buffer, &info) || !S_ISREG(info.st_mode)) { @@ -330,8 +332,54 @@ getpath(const char* file, char** path) *path = strncpy(*path, buffer, strlen(buffer) - strlen(part) - 1); return (int)(strlen(buffer) - strlen(part) -1); +}*/ + +int +getpath(const char* file, char** path) +{ + char buf1[PATH_MAX + 1] = {0}; + char buf2[PATH_MAX + 1] = {0}; + struct stat info = {0}; + + char* delimiter; + + if(!file) + { + *path = NULL; + return -1; + } + + delimiter = strrchr(file,'/'); + + if(!delimiter) + delimiter = strrchr(file,'\\'); + + if(!delimiter) + { + *path = getcwd(NULL,0); + } + else + { + strncpy(buf2, file, (delimiter - file)); + + if(translatepath(buf2, path) < 0) + return -1; + } + + sprintf(buf1,"%s\\%s", *path, delimiter ? delimiter + 1 : file); + + if(stat(buf1, &info) || !S_ISREG(info.st_mode)) + { + free(*path); + *path = NULL; + errno = ENOENT; + return -1; + } + + return (int) strlen(*path); } + int translatepath(const char* totranslate, char** translated) { @@ -363,6 +411,7 @@ translatepath(const char* totranslate, char** translated) { *translated = getcwd(NULL,0); (*translated)[2] = '\0'; + return (int)strlen(*translated); } /* it's a relative directory name build the full directory name */ @@ -401,7 +450,7 @@ translatepath(const char* totranslate, char** translated) break; } } - + if(j == 1 && buffer1[i - 1] == '/') { /* perhaps it's a relative directory : `dir/' */ @@ -412,7 +461,7 @@ translatepath(const char* totranslate, char** translated) getcwd(buffer1, PATH_MAX + 1); strcat(buffer1,"\\"); strcat(buffer1,buffer2); - + *translated = (char*) calloc(strlen(buffer1) + 1, sizeof(char)); strcpy(*translated, buffer1); @@ -447,6 +496,7 @@ translatepath(const char* totranslate, char** translated) len = (int)strlen(buffer2); *translated = (char*) calloc(len + 1, sizeof(char)); + strcpy(*translated, buffer2); if(!(*translated)) { diff --git a/tools/tesh2/src/reader.c b/tools/tesh2/src/reader.c index 851fcadd98..ddff42174f 100644 --- a/tools/tesh2/src/reader.c +++ b/tools/tesh2/src/reader.c @@ -96,7 +96,7 @@ reader_start_routine(void* p) if(number_of_bytes_readed > 0) { for(i= 0, j= 0; i < number_of_bytes_readed; i++) - if((int)(buffer[i]) != 13) + if((buffer[i]) != '\r') clean[j++] = buffer[i]; xbt_strbuff_append(output,clean); diff --git a/tools/tesh2/src/runner.c b/tools/tesh2/src/runner.c index 7c6b6ae4a2..075c765970 100644 --- a/tools/tesh2/src/runner.c +++ b/tools/tesh2/src/runner.c @@ -1,681 +1,702 @@ -/* - * 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 -#include -#include -#include -#include - -#include /* for error code */ -#include /* for calloc() */ -#include - -#include - -#ifndef WIN32 -#include -#include -#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; -} - +/* + * 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 +#include +#include +#include +#include + +#include /* for error code */ +#include /* for calloc() */ +#include + +#include +#include + +#ifndef WIN32 +#include +#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 + + +# ifdef __APPLE__ +/* 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 */ +# include +# define environ (*_NSGetEnviron()) +# elif !defined(WIN32) + /* the environment, as specified by the opengroup, used to initialize the process properties */ + extern char **environ; +# 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)) + #else + if(!strcmp("Path", buffer) || !strcmp("PATH", buffer)) + #endif + { + char* p; + size_t j,k, len; + + /* get the list of paths */ + + #ifdef WIN32 + runner->path = explode(';', val); + #else + runner->path = explode(':', val); + #endif + + /* 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); + + #ifndef WIN32 + for(j = len - 1; p[j] == '/' || p[j] == ' '; j--) + #else + for(j = len - 1; p[j] == '\\' || p[j] == ' '; j--) + #endif + p[j] = '\0'; + } + } + + + 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; +} + diff --git a/tools/tesh2/src/str_replace.c b/tools/tesh2/src/str_replace.c index 5c868333b9..e53c505c06 100644 --- a/tools/tesh2/src/str_replace.c +++ b/tools/tesh2/src/str_replace.c @@ -5,7 +5,7 @@ #include -int +/*int str_replace(char** str, const char* what, const char* with) { size_t pos, i; @@ -53,8 +53,187 @@ str_replace(char** str, const char* what, const char* with) return 0; } +*/ + +/* last version int +str_replace(char** str, const char* what, const char* with, const char* delimiters) +{ + size_t pos, i, len; + char* begin; + char* buf; + char* delimited; + int size; + + if(!*str || !what || !with || !delimiters) + { + errno = EINVAL; + return -1; + } + + + if(!(delimited = (char*) calloc((strlen(what) + 2) , sizeof(char)))) + return -1; + + len = strlen(delimiters); + + for(i = 0; i < len; i++) + { + memset(delimited, 0, (strlen(what) + 2)); + + sprintf(delimited,"%s%c", what, delimiters[i]); + + if((begin = strstr(*str, delimited))) + break; + } + + free(delimited); + + + if(!begin && (size = (int)strlen(*str) - (int)strlen(what)) >= 0 && !strcmp(*str + size, what)) + begin = strstr(*str, what); + + if(!begin) + { + errno = ESRCH; + return -1; + } + + pos = begin - *str; + + i = 0; + + pos += strlen(what); + + if(begin == *str) + { + + + if(!(buf = (char*) calloc(strlen(with) + ((pos < strlen(*str)) ? strlen(*str + pos) : 0) + 1, sizeof(char)))) + return -1; + + strcpy(buf, with); + + if(pos < strlen(*str)) + strcpy(buf + strlen(with), *str + pos); + } + else + { + if(!(buf = (char*) calloc((begin - *str) + strlen(with) + ((pos < strlen(*str)) ? strlen(*str + pos) : 0) + 1, sizeof(char)))) + return -1; + + strncpy(buf, *str, (begin - *str)); + strcpy(buf + (begin - *str) , with); + + if(pos < strlen(*str)) + strcpy(buf + (begin - *str) + strlen(with), *str + pos); + } + + free(*str);; + *str = buf; + + return 0; + +}*/ int +str_replace(char** str, const char* what, const char* with, const char* delimiters) +{ + size_t pos, i, len; + char* begin; + char* buf; + int size; + + if(!*str || !what) + { + errno = EINVAL; + return -1; + } + + if(delimiters) + { + char* delimited; + + if(!(delimited = (char*) calloc((strlen(what) + 2) , sizeof(char)))) + return -1; + + len = strlen(delimiters); + + for(i = 0; i < len; i++) + { + memset(delimited, 0, (strlen(what) + 2)); + + sprintf(delimited,"%s%c", what, delimiters[i]); + + if((begin = strstr(*str, delimited))) + break; + } + + free(delimited); + } + else + begin = strstr(*str, what); + + + if(!begin && (size = (int)strlen(*str) - (int)strlen(what)) >= 0 && !strcmp(*str + size, what)) + begin = strstr(*str, what); + + if(!begin) + { + errno = ESRCH; + return -1; + } + + pos = begin - *str; + + i = 0; + + pos += strlen(what); + + if(begin == *str) + { + if(!(buf = (char*) calloc((with ? strlen(with) : 0) + ((pos < strlen(*str)) ? strlen(*str + pos) : 0) + 1, sizeof(char)))) + return -1; + + if(with) + strcpy(buf, with); + + if(pos < strlen(*str)) + strcpy(buf + (with ? strlen(with) : 0), *str + pos); + } + else + { + if(!(buf = (char*) calloc((begin - *str) + (with ? strlen(with) : 0) + ((pos < strlen(*str)) ? strlen(*str + pos) : 0) + 1, sizeof(char)))) + return -1; + + strncpy(buf, *str, (begin - *str)); + + if(with) + strcpy(buf + (begin - *str) , with); + + if(pos < strlen(*str)) + strcpy(buf + (begin - *str) + (with ? strlen(with) : 0), *str + pos); + } + + free(*str); + + *str = buf; + + return 0; + +} + +int +str_replace_all(char** str, const char* what, const char* with, const char* delimiters) +{ + int rv; + + while(!(rv = str_replace(str, what, with, delimiters))); + + return (errno == ESRCH) ? 0 : -1; +} + + +/*int str_replace_all(char** str, const char* what, const char* with) { int rv; @@ -62,6 +241,7 @@ str_replace_all(char** str, const char* what, const char* with) while(!(rv = str_replace(str, what, with))); return (errno == ESRCH) ? 0 : -1; -} +}*/ + diff --git a/tools/tesh2/src/variable.c b/tools/tesh2/src/variable.c index d89983cbb1..77268da0b0 100644 --- a/tools/tesh2/src/variable.c +++ b/tools/tesh2/src/variable.c @@ -7,7 +7,7 @@ variable_new(const char* name, const char* val) { variable_t variable; - if(!name || !val) + if(!name) { errno = EINVAL; return NULL; @@ -16,7 +16,10 @@ variable_new(const char* name, const char* val) variable = xbt_new0(s_variable_t, 1); variable->name = strdup(name); - variable->val = strdup(val); + + if(val) + variable->val = strdup(val); + variable->used = 0; variable->env = 0; variable->err = 0; diff --git a/tools/tesh2/tesh/tesh.vcproj b/tools/tesh2/tesh/tesh.vcproj index e765046ffb..2c6d45745d 100644 --- a/tools/tesh2/tesh/tesh.vcproj +++ b/tools/tesh2/tesh/tesh.vcproj @@ -44,6 +44,7 @@ MinimalRebuild="true" BasicRuntimeChecks="3" RuntimeLibrary="2" + BufferSecurityCheck="true" UsePrecompiledHeader="0" WarningLevel="3" Detect64BitPortabilityProblems="true" @@ -226,6 +227,14 @@ + + +