Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
change the free function by a free_error function to clean all the tesh errors from...
authorcherierm <cherierm@48e7efb5-ca39-0410-a469-dd3cf9ba447f>
Wed, 21 May 2008 09:04:48 +0000 (09:04 +0000)
committercherierm <cherierm@48e7efb5-ca39-0410-a469-dd3cf9ba447f>
Wed, 21 May 2008 09:04:48 +0000 (09:04 +0000)
change some distraction in tesh files.

git-svn-id: svn+ssh://scm.gforge.inria.fr/svn/simgrid/simgrid/trunk@5476 48e7efb5-ca39-0410-a469-dd3cf9ba447f

tools/tesh2/examples/auto.tesh
tools/tesh2/examples/catch-wrong-output.tesh
tools/tesh2/src/main.c

index 5e7cff6..2d415b6 100644 (file)
@@ -10,7 +10,7 @@
 ! include catch-signal.tesh
 ! include catch-timeout.tesh
 ! include cd.tesh
 ! include catch-signal.tesh
 ! include catch-timeout.tesh
 ! include cd.tesh
-#! include IO-broken-pipe.tesh
+! include IO-broken-pipe.tesh
 ! include IO-orders.tesh
 ! include set-ignore-output.tesh
 ! include set-return.tesh
 ! include IO-orders.tesh
 ! include set-ignore-output.tesh
 ! include set-return.tesh
index 1356a1e..753d0c7 100644 (file)
@@ -1,16 +1,12 @@
-#! ./tesh\r
-\r
-p This tests whether TESH detects wrong outputs\r
-\r
-! expect return 2\r
-< > TOTO\r
-< < TUTU\r
-< $ cat\r
-$ ./tesh --log="log.thresh:info tesh.fmt:%m%n"\r
-> Test suite from stdin\r
-> [stdin:3] cat\r
-> Output of <stdin:3> mismatch:\r
-> - TOTO\r
-> + TUTU\r
-> Test suite `(stdin)': NOK (<stdin:3> output mismatch)\r
-\r
+#! ./tesh
+
+p This tests whether TESH detects wrong outputs
+
+! expect return $EOUTPUTNOTMATCH
+< > TOTO
+< < TUTU
+< $ cat
+$ ./tesh --log='log.thresh:info tesh.fmt:%m%n' --silent
+
+
+
index a3bea8e..01aac05 100644 (file)
-/*\r
- * src/main.c - this file contains the main function of tesh.\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
- *\r
- */\r
-#include <runner.h>\r
-#include <fstream.h>\r
-#include <fstreams.h>\r
-#include <directory.h>\r
-#include <directories.h>\r
-#include <excludes.h>\r
-#include <getopt.h>\r
-#include <getpath.h>\r
-\r
-#include <locale.h>\r
-\r
-/*\r
- * entry used to define the parameter of a tesh option.\r
- */\r
-typedef struct s_optentry\r
-{\r
-       int c;                                                          /* the character of the option                                                                                  */\r
-       \r
-       /* \r
-        * the type of the argument of the option \r
-        */\r
-       enum                                            \r
-       {\r
-               flag,                                                   /* it's a flag option, by default the flag is set to zero                               */                                              \r
-               string,                                                 /* the option has strings as argument                                                                   */                                      \r
-               number                                                  /* the option has an integral positive number as argument                               */                      \r
-       }type;\r
-       \r
-       byte* value;                                            /* the value of the option                                                                                              */                      \r
-       byte* optional_value;                           /* the optional value of the option if not specified                                    */\r
-       const char * long_name;                         /* the long name of the command                                                                                 */\r
-}s_optentry_t,* optentry_t;\r
-\r
-\r
-/* logs */\r
-XBT_LOG_NEW_DEFAULT_CATEGORY(tesh,"TEst SHell utility");\r
-\r
-#ifdef WIN32\r
-/* Windows specific : the previous process error mode                  */\r
-static UINT \r
-prev_error_mode = 0;\r
-#endif\r
-\r
-/* this object represents the root directory */\r
-directory_t\r
-root_directory = NULL;\r
-\r
-/* the current version of tesh                                                                 */\r
-static const char* \r
-version = "1.0";\r
-\r
-/* ------------------------------------------------------------ */\r
-/* options                                                                                                             */\r
-/* ------------------------------------------------------------ */\r
-\r
-/* ------------------------------------------------------------ */\r
-/* numbers                                                                                                             */\r
-/* ------------------------------------------------------------ */\r
-\r
-\r
-/* --jobs is specified with arg                                                                        */\r
-static int \r
-jobs_nb = -2;\r
-\r
-/* --jobs option is not specified (use the default job count)  */\r
-static int \r
-default_jobs_nb = 1;\r
-\r
-/* --jobs is specified but has no arg (one job per unit)               */\r
-static int \r
-optional_jobs_nb = -1;\r
-\r
-/* the global timeout                                                                                  */\r
-static int\r
-timeout = INDEFINITE;\r
-\r
-/* ------------------------------------------------------------ */\r
-/* strings                                                                                     */\r
-/* ------------------------------------------------------------ */\r
-\r
-/* --C change the directory before running the units                   */\r
-static directories_t \r
-directories = NULL;\r
-\r
-/* the include directories : see the !i metacommand                            */\r
-/*vector_t \r
-include_dirs = NULL;*/\r
-xbt_dynar_t\r
-include_dirs = NULL;\r
-\r
-/* the list of tesh files to run                                                               */\r
-static fstreams_t \r
-fstreams = NULL;\r
-\r
-/* xbt logs                                                                                                            */\r
-static xbt_dynar_t\r
-logs = NULL;\r
-\r
-/* the list of tesh file suffixes                                                              */\r
-static xbt_dynar_t\r
-suffixes = NULL;\r
-\r
-\r
-static excludes_t\r
-excludes = NULL;\r
-\r
-\r
-/* ------------------------------------------------------------ */\r
-/* flags                                                                                                               */\r
-/* ------------------------------------------------------------ */\r
-\r
-/* if 1, keep going when some commands can't be found\r
- * default value 0 : not keep going\r
- */\r
-int \r
-keep_going_flag = 0;\r
-\r
-/* if 1, ignore failures from commands\r
- * default value : do not ignore failures\r
- */\r
-int \r
-keep_going_unit_flag = 0;\r
-\r
-/* if 1, display tesh usage                                                                            */\r
-static int \r
-print_usage_flag = 0;\r
-\r
-/* if 1, display the tesh version                                                              */\r
-static int \r
-print_version_flag = 0;\r
-\r
-/* if 1, the syntax of all tesh files is checked \r
- * before running them\r
- */\r
-static int\r
-check_syntax_flag = 0;\r
-\r
-/* if 1, the status of all the units is display at\r
- * the end.\r
- */\r
-static int\r
-summary_flag = 0;\r
-\r
-/* if 1 and the flag want_summay is set to 1 tesh display the detailed summary of the run */\r
-int \r
-detail_summary_flag = 0;\r
-\r
-/* if 1, the directories are displayed                                                 */\r
-int \r
-print_directory_flag = 0;\r
-\r
-/* if 1, just check the syntax of all the tesh files\r
- * do not run them.\r
- */\r
-int\r
-dry_run_flag = 0;\r
-\r
-/* if 1, display the tesh files syntax and exit                                        */\r
-static int\r
-print_readme_flag = 0;\r
-\r
-int \r
-silent_flag = 0;\r
-\r
-int \r
-just_print_flag = 0;\r
-\r
-static int \r
-env_overrides_flag  = 0;\r
-\r
-static int \r
-print_database_flag = 0;\r
-\r
-static int \r
-question_flag = 0;\r
-\r
-/* the semaphore used to synchronize the jobs */\r
-xbt_os_sem_t\r
-jobs_sem = NULL;\r
-\r
-/* the semaphore used by the runner to wait the end of all the units */\r
-xbt_os_sem_t\r
-units_sem = NULL;\r
-\r
-static int\r
-loaded = 0;\r
-\r
-int \r
-interrupted = 0;\r
-\r
-int\r
-exit_code = 0; \r
-\r
-pid_t\r
-pid =0;\r
-\r
-int \r
-is_tesh_root = 1;\r
-\r
-xbt_dynar_t\r
-errors = NULL;\r
-\r
-xbt_os_mutex_t\r
-err_mutex = NULL;\r
-\r
-/* the table of the entries of the options */ \r
-static const struct s_optentry opt_entries[] =\r
-{\r
-       { 'C', string, (byte*)NULL, 0, "directory" },\r
-       { 'x', string, (byte*)&suffixes, 0, "suffix" },\r
-       { 'e', flag, (byte*)&env_overrides_flag, 0, "environment-overrides", },\r
-       { 'f', string, (byte*)&fstreams, 0, "file" },\r
-       { 'h', flag, (byte*)&print_usage_flag, 0, "help" },\r
-       { 'a', flag, (byte*)&print_readme_flag, 0, "read-me" },\r
-       { 'i', flag, (byte*)&keep_going_unit_flag, 0, "keep-going-unit" },\r
-       { 'I', string, (byte*)&include_dirs, 0, "include-dir" },\r
-       { 'j', number, (byte*)&jobs_nb, (byte*) &optional_jobs_nb, "jobs" },\r
-       { 'k', flag, (byte*)&keep_going_flag, 0, "keep-going" },\r
-       { 'm', flag, (byte*)&detail_summary_flag, 0, "detail-summary" },\r
-       { 'c', flag, (byte*)&just_print_flag, 0, "just-print" },\r
-       { 'd', flag, (byte*)&print_database_flag, 0,"display-data-base" },\r
-       { 'q', flag, (byte*)&question_flag, 0, "question_flag" },\r
-       { 's', flag, (byte*)&silent_flag, 0, "silent" },\r
-       { 'V', flag, (byte*)&print_version_flag, 0, "version" },\r
-       { 'w', flag, (byte*)&print_directory_flag, 0,"dont-display-directory" },\r
-       { 'n', flag, (byte*)&dry_run_flag, 0, "dry-run"},\r
-       { 't', number, (byte*)&timeout, 0, "timeout" },\r
-       { 'S', flag, (byte*)&check_syntax_flag, 0, "check-syntax"},\r
-       { 'r', string, (byte*)&directories, 0, "load-directory"},\r
-       { 'v', flag, (byte*)&summary_flag, 0, "summary"},\r
-       { 'F', string,(byte*)&excludes, 0, "exclude"},\r
-       { 'l', string,(byte*)&logs,0,"log"},\r
-       { 0, 0, 0, 0, 0}\r
-};\r
-\r
-/* the tesh usage                                                                                              */\r
-static const char* usage[] =\r
-{\r
-       "Options:\n",\r
-       "  -C DIRECTORY, --directory=DIRECTORY   Change to DIRECTORY before running any commands.\n",\r
-       "  -e, --environment-overrides           Environment variables override files.\n",\r
-       "  -f FILE, --file=FILE                  Read FILE as a teshfile.\n",\r
-       "                                           remark :\n",\r
-       "                                           all argument of the command line without\n",\r
-       "                                           option is dealed as a tesh file.\n",\r
-       "  -h, --help                            Print this message and exit.\n",\r
-       "  -i, --keep-going-unit                 Ignore failures from commands.\n",\r
-       "                                        The possible failures are :\n",\r
-       "                                         - the exit code differ from the expected\n",\r
-       "                                         - the signal throw differ from the expected\n",\r
-       "                                         - the output differ from the expected\n",\r
-       "                                         - the read pipe is broken\n",\r
-       "                                         - the write pipe is broken\n",\r
-       "                                         - the command assigned delay is outdated\n",\r
-       "  -I DIRECTORY, --include-dir=DIRECTORY Search DIRECTORY for included files.\n",\r
-       "  -j [N], --jobs[=N]                    Allow N commands at once; infinite commands with\n"\r
-       "                                        no arg.\n",\r
-       "  -k, --keep-going                      Keep going when some commands can't be made or\n",\r
-       "                                        failed.\n",\r
-       "  -c, --just-print                      Don't actually run any commands; just print them.\n",\r
-       "  -p, --print-data-base                 Display tesh's internal database.\n",\r
-       "  -q, --question                        Run no commands; exit status says if up to date.\n",\r
-       "  -s, --silent,                         Don't echo commands.\n",\r
-       "  -V, --version                         Print the version number of tesh and exit.\n",\r
-       "  -d, --dont-print-directory            Don't display the current directory.\n",\r
-       "  -n, --dry-run                         Check the syntax of the specified tesh files, display the result and exit.\n",\r
-       "  -t, --timeout                         Wait the end of the commands at most timeout seconds.\n",\r
-       "  -S, --check-syntax                    Check the syntax of the tesh files before run them. \n",\r
-       "  -x, --suffix                          Consider the new suffix for the tesh files.\n"\r
-       "                                           remark :\n",\r
-       "                                           the default suffix for the tesh files is \".tesh\".\n",\r
-       " -a, --read-me                          Print the read me file and exit.\n",\r
-       " -b, --build-file                       Build a tesh file.\n",\r
-       " -r, --load-directory                   Run all the tesh files located in the directories specified by the option --directory.\n",\r
-       " -v, --summary                          Display the status of the commands.\n",\r
-       " -m, --detail-summary                   Detail the summary of the run.\n",\r
-       " -F file , --exclude=FILE               Ignore the tesh file FILE.\n",\r
-       " -l format, --log                       Format of the xbt logs.\n",\r
-       NULL\r
-};\r
-\r
-/* the string of options of tesh                                                               */                                                              \r
-static char \r
-optstring[1 + sizeof (opt_entries) / sizeof (opt_entries[0]) * 3];\r
-\r
-/* the option table of tesh                                                                            */\r
-static struct \r
-option longopts[(sizeof (opt_entries) / sizeof (s_optentry_t))];\r
-\r
-static void\r
-init_options(void);\r
-\r
-static int\r
-process_command_line(int argc, char** argv);\r
-\r
-static void\r
-load(void);\r
-\r
-static void\r
-print_usage(void);\r
-\r
-static void\r
-print_version(void);\r
-\r
-static void\r
-finalize(void);\r
-\r
-static void\r
-print_readme(void);\r
-\r
-static int\r
-init(void);\r
-\r
-\r
-static void \r
-sig_abort_handler(int signum)\r
-{\r
-       /* TODO : implement this function */\r
-       INFO0("sig_abort_handler() called");\r
-}\r
-\r
-static void \r
-sig_int_handler(int signum)\r
-{\r
-       /* TODO : implement this function */\r
-       INFO0("sig_int_handler() called");\r
-}\r
-\r
-static void \r
-free_string(void* str)\r
-{\r
-       free(*(void**)str);\r
-}\r
-\r
-int\r
-main(int argc, char* argv[])\r
-{\r
-       int _argc;\r
-\r
-       /* set the locale to the default*/\r
-       setlocale(LC_ALL,"");\r
-       \r
-       /* initialize tesh */\r
-       if(init() < 0)\r
-               finalize();\r
-               \r
-       /* process the command line */\r
-       if(process_command_line(argc, argv) < 0)\r
-               finalize();\r
-       \r
-       /* move to the root directory (the directory may change during the command line processing) */\r
-       chdir(root_directory->name);\r
-               \r
-       /* initialize the xbt library \r
-        * for thread portability layer\r
-        */\r
-        \r
-       /* xbt initialization */\r
-\r
-       if((_argc = xbt_dynar_length(logs)))\r
-       {\r
-               int i;\r
-\r
-               char** _argv = (char**)calloc(_argc, sizeof(char*));\r
-               \r
-               for(i = 0; i < _argc; i++)\r
-                       xbt_dynar_pop(logs, &(_argv[i]));\r
-\r
-               xbt_init(&_argc, _argv);\r
-\r
-               while(--i)\r
-                       free(_argv[i]);\r
-\r
-               free(_argv);\r
-       }\r
-       else\r
-               xbt_init(&argc, argv);\r
-               \r
-       /* the user wants to display the usage of tesh */\r
-       if(print_version_flag)\r
-       {\r
-               print_version();\r
-\r
-               if(!print_usage_flag)\r
-                       finalize();\r
-       }\r
-       \r
-       /* the user wants to display the usage of tesh */\r
-       if(print_usage_flag)\r
-       {\r
-               print_usage();\r
-               finalize();\r
-       }\r
-       \r
-       /* the user wants to display the semantic of the tesh file metacommands */\r
-       if(print_readme_flag)\r
-       {\r
-               print_readme();\r
-               finalize();\r
-       }\r
-       \r
-       /* load tesh files */\r
-       load();\r
-       \r
-       \r
-       /* use by the finalize function to known if it must display the tesh usage */   \r
-       loaded = 1;\r
-\r
-       if(-2 == jobs_nb)\r
-       {/* --jobs is not specified (use the default value) */\r
-               jobs_nb = default_jobs_nb;\r
-       }\r
-       else if(optional_jobs_nb == jobs_nb)\r
-       {/* --jobs option is specified with no args (use one job per unit) */\r
-               jobs_nb = fstreams_get_size(fstreams);\r
-       }\r
-\r
-       if(jobs_nb > fstreams_get_size(fstreams))\r
-       {/* --jobs = N is specified and N is more than the number of tesh files */\r
-               \r
-               WARN0("Number of requested jobs exceed the number of files to run");\r
-               \r
-               /* assume one job per file */\r
-               jobs_nb = fstreams_get_size(fstreams);\r
-       }\r
-\r
-       /* initialize the semaphore used to synchronize all the units */\r
-       jobs_sem = xbt_os_sem_init(jobs_nb);\r
-\r
-       /* initialize the semaphore used by the runner to wait for the end of all units */\r
-       units_sem = xbt_os_sem_init(0);\r
-       \r
-       /* initialize the runner */\r
-       if(runner_init(check_syntax_flag, timeout, fstreams) < 0)\r
-               finalize();\r
-               \r
-       if(just_print_flag && silent_flag)\r
-               silent_flag = 0;\r
-               \r
-       if(just_print_flag && dry_run_flag)\r
-               WARN0("mismatch in the syntax : --just-check-syntax and --just-display options at same time");\r
-       \r
-       /* run all the units */\r
-       runner_run();\r
-       \r
-       \r
-       /* show the result of the units */\r
-       if(summary_flag || dry_run_flag)\r
-               runner_summarize();\r
-               \r
-       /* all the test are runned, destroy the runner */\r
-       runner_destroy();\r
-       \r
-       /* then, finalize tesh (release all the allocated memory and exits) */\r
-       finalize();\r
-       \r
-       #ifndef WIN32\r
-       return exit_code;\r
-       #endif\r
-       \r
-}\r
-\r
-/* init --     initialize tesh : allocated all the objects needed by tesh to run\r
- *                     the tesh files specified in the command line.\r
- *\r
- * return      If successful the function returns zero. Otherwise the function returns\r
- *                     -1 and sets the global variable errno to the appropriate error code.\r
- */\r
-\r
-\r
-\r
-static int\r
-init(void)\r
-{\r
-       char* buffer;\r
-       char* suffix = strdup(".tesh");\r
-       \r
-       #ifdef WIN32\r
-       /* Windows specific : don't display the general-protection-fault message box and\r
-        * the the critical-error-handler message box (instead the system send the error\r
-        * to the calling process : tesh)\r
-        */\r
-       prev_error_mode = SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX);\r
-       #else\r
-       struct sigaction act;\r
-       /* Ignore pipe issues.\r
-        * They will show up when we try to send data to dead buddies, \r
-     * but we will stop doing so when we're done with provided input \r
-     */\r
-       memset(&act,0, sizeof(struct sigaction));\r
-       act.sa_handler = SIG_IGN;\r
-       sigaction(SIGPIPE, &act, NULL);\r
-       \r
-       \r
-       memset(&act,0, sizeof(struct sigaction));\r
-       act.sa_handler = sig_abort_handler;\r
-       sigaction(SIGABRT, &act, NULL);\r
-       \r
-       memset(&act,0, sizeof(struct sigaction));\r
-       act.sa_handler = sig_int_handler;\r
-       sigaction(SIGINT, &act, NULL);\r
-       \r
-       #endif\r
-       \r
-       err_mutex = xbt_os_mutex_init();\r
-       \r
-       /* handle the abort signal */\r
-       /*signal(SIGABRT, sig_abort_handler);*/\r
-       \r
-       /* handle the interrupt signal */\r
-       /*signal(SIGINT, sig_int_handler);*/\r
-       \r
-       /* used to store the files to run */\r
-       if(!(fstreams = fstreams_new(DEFAULT_FSTREAMS_CAPACITY, (void_f_pvoid_t)fstream_free)))\r
-       {\r
-               ERROR1("(system error) %s", strerror(errno));\r
-               return -1;\r
-       }\r
-       \r
-       /* register the current directory */\r
-       if(!(buffer  = getcwd(NULL, 0)))\r
-       {\r
-               ERROR1("(system error) %s", strerror(errno));\r
-               return -1;\r
-       }\r
-       \r
-       /* save the root directory */\r
-       if(!(root_directory = directory_new(buffer)))\r
-       {\r
-               ERROR1("(system error) %s", strerror(errno));\r
-               return -1;\r
-       }\r
-       \r
-       free(buffer);\r
-       \r
-       /* this vector contains all the errors of the run */\r
-       errors = xbt_dynar_new(sizeof(xerror_t), free);\r
-       \r
-       /* the directories to loads */\r
-       if(!(directories = directories_new()))\r
-       {\r
-               ERROR1("(system error) %s", strerror(errno));\r
-               return -1;\r
-       }\r
-       \r
-       /* the include directories */\r
-       include_dirs = xbt_dynar_new(sizeof(directory_t), (void_f_pvoid_t)directory_free);\r
-       \r
-       /* xbt logs option */\r
-       if(!(logs = xbt_dynar_new(sizeof(char*), free_string)))\r
-       {\r
-               ERROR1("(system error) %s", strerror(errno));\r
-               return -1;\r
-       }\r
-       \r
-       /* the excluded files */\r
-       if(!(excludes = excludes_new()))\r
-       {\r
-               ERROR1("(system error) %s", strerror(errno));\r
-               return -1;\r
-       }\r
-       \r
-       /* the suffixes */\r
-       suffixes = xbt_dynar_new(sizeof(char*),free_string);\r
-       \r
-       /* register the default suffix ".tesh" */\r
-       xbt_dynar_push(suffixes, &suffix);\r
-       \r
-       return 0;\r
-}\r
-\r
-/* load -- load the tesh files to run */\r
-static void\r
-load(void)\r
-{\r
-       \r
-       /* if the directories object is not empty load all the tesh files contained in\r
-        * the directories specified in the command line (this tesh files must have the\r
-        * a suffix specified in the suffixes object.\r
-        */\r
-       if(!directories_is_empty(directories))\r
-               directories_load(directories, fstreams, suffixes);\r
-       \r
-       /* if no tesh file has been specified in the command line try to load the default tesh file\r
-        * teshfile from the current directory\r
-        */\r
-       if(fstreams_is_empty(fstreams))\r
-       {\r
-               struct stat buffer = {0};\r
-               \r
-               /* add the default tesh file if it exists in the current directory */\r
-               if(!stat("teshfile", &buffer) && S_ISREG(buffer.st_mode))\r
-                       fstreams_add(fstreams, fstream_new(getcwd(NULL, 0), "teshfile"));\r
-       }\r
-       \r
-       /* excludes the files specified in the command line and stored in the excludes object */\r
-       if(!excludes_is_empty(excludes) && !fstreams_is_empty(fstreams))\r
-       {\r
-               /* check the files to excludes before */        \r
-               excludes_check(excludes, fstreams);\r
-               \r
-               /* exclude the specified tesh files */\r
-               fstreams_exclude(fstreams, excludes);\r
-       }\r
-       \r
-       /* if the fstreams object is empty use the stdin */\r
-       if(fstreams_is_empty(fstreams))\r
-               fstreams_add(fstreams, fstream_new(NULL, "stdin"));\r
-       \r
-       /* load the tesh files (open them) */\r
-       fstreams_load(fstreams);\r
-       \r
-}\r
-\r
-/* finalize -- cleanup all the allocated objects and display the tesh usage if needed */\r
-static void\r
-finalize(void)\r
-{\r
-       \r
-       if(is_tesh_root && !summary_flag)\r
-       {\r
-               xerror_t error;\r
-               unsigned int i;\r
-\r
-               xbt_dynar_foreach(errors, i, error)\r
-               {\r
-                       if(error->command)\r
-                               fprintf(stderr, "[tesh/ERROR] %s : <Command `%s'> <Unit `%s'> <C%d (%s)>\n", error->reason, error->command, error->unit, error->errcode, error_to_string(error->errcode));\r
-                       else if(!error->command && error->unit)\r
-                               fprintf(stderr, "[tesh/ERROR] %s : Unit `%s' - C%d (%s)\n", error->reason, error->unit, error->errcode, error_to_string(error->errcode));\r
-                       else if(!error->command && !error->unit && error->reason)\r
-                               fprintf(stderr, "[tesh/ERROR] %s : C%d (%s)\n", error->reason, error->errcode, error_to_string(error->errcode));                \r
-                       else if(!error->command && !error->unit && !error->reason)\r
-                               fprintf(stderr, "[tesh/ERROR] C%d (%s)\n", error->errcode, error_to_string(error->errcode));            \r
-                       \r
-               }\r
-       }\r
-       \r
-       /* delete vector of errors */\r
-       if(errors)\r
-               xbt_dynar_free(&errors);\r
-               \r
-       xbt_os_mutex_destroy(err_mutex);\r
-       \r
-       /* delete the fstreams object */\r
-       if(fstreams)\r
-               fstreams_free((void**)&fstreams);\r
-       \r
-       /* delete the excludes object */\r
-       if(excludes)    \r
-               excludes_free((void**)&excludes);\r
-       \r
-       /* delete the directories object */\r
-       if(directories)\r
-               directories_free((void**)&directories);\r
-               \r
-       /* delete the root directory object */\r
-       if(root_directory)\r
-               directory_free((void**)&root_directory);\r
-       \r
-       /* delete the include directories object */\r
-       if(include_dirs)\r
-               xbt_dynar_free(&include_dirs);\r
-       \r
-       /* delete the list of tesh files suffixes */    \r
-       if(suffixes)\r
-               xbt_dynar_free(&suffixes);\r
-       \r
-       /* delete the xbt log options list */\r
-       if(logs)\r
-               xbt_dynar_free(&logs);\r
-               \r
-       /* destroy the semaphore used to synchronize the units */\r
-       if(jobs_sem)\r
-               xbt_os_sem_destroy(jobs_sem);\r
-       \r
-       /* destroy the semaphore used by the runner used to wait for the end of the units */\r
-       if(units_sem)\r
-               xbt_os_sem_destroy(units_sem);\r
-       \r
-       /* exit from the xbt framework */\r
-       xbt_exit();\r
-       \r
-       /* Windows specific (restore the previouse error mode */\r
-       #ifdef WIN32\r
-       SetErrorMode(prev_error_mode);\r
-       #endif\r
-       \r
-       if(!summary_flag && !dry_run_flag && !silent_flag && !just_print_flag && !print_version_flag && !print_usage_flag && is_tesh_root)\r
-       {\r
-               if(!exit_code)\r
-                       INFO2("tesh terminated with exit code %d : %s",exit_code, "success");\r
-               else\r
-                       ERROR2("tesh terminated with exit code %d : %s",exit_code, error_to_string(exit_code));\r
-       }\r
-       \r
-       \r
-       /* exit with the last error code */\r
-       exit(exit_code);\r
-}\r
-\r
-/* init_options -- initialize the options string */\r
-static void\r
-init_options (void)\r
-{\r
-       char *p;\r
-       unsigned int i;\r
-       \r
-       /* the function has been already called */\r
-       if(optstring[0] != '\0')\r
-               return;\r
-       \r
-       p = optstring;\r
-       \r
-       *p++ = '-';\r
-       \r
-       for (i = 0; opt_entries[i].c != '\0'; ++i)\r
-       {\r
-               /* initialize the long name of the option*/\r
-               longopts[i].name = (opt_entries[i].long_name == 0 ? "" : opt_entries[i].long_name);\r
-               \r
-               /* getopt_long returns the value of val */\r
-               longopts[i].flag = 0;\r
-               \r
-               /* the short option */\r
-               longopts[i].val = opt_entries[i].c;\r
-               \r
-               /* add the short option in the options string */\r
-               *p++ = opt_entries[i].c;\r
-               \r
-               switch (opt_entries[i].type)\r
-               {\r
-                       /* if this option is used to set a flag or if the argument must be ignored\r
-                        * the option has no argument\r
-                        */\r
-                       case flag:\r
-                       longopts[i].has_arg = no_argument;\r
-                       break;\r
-               \r
-                       /* the option has an argument */\r
-                       case string:\r
-                       case number:\r
-                       \r
-                       *p++ = ':';\r
-                       \r
-                       if(opt_entries[i].optional_value != 0)\r
-                       {\r
-                               *p++ = ':';\r
-                               \r
-                               longopts[i].has_arg = optional_argument;\r
-                       }\r
-                       else\r
-                               longopts[i].has_arg = required_argument;\r
-                       \r
-                       break;\r
-               }\r
-       }\r
-       \r
-       *p = '\0';\r
-       longopts[i].name = 0;\r
-}\r
-\r
-/* process_command_line --     process the command line\r
- *\r
- * param                                       argc the number of the arguments contained by the command line.\r
- * param                                       The array of C strings containing all the arguments of the command \r
- *                                                     line.\r
- *\r
- * return                                      If successful, the function returns 0. Otherwise -1 is returned\r
- *                                                     and sets the global variable errno to indicate the error.\r
- *\r
- * errors      [ENOENT]                A file name specified in the command line does not exist\r
- */    \r
-\r
-static int\r
-process_command_line(int argc, char** argv)\r
-{\r
-       register const struct s_optentry* entry;\r
-       register int c;\r
-       directory_t directory;\r
-       fstream_t fstream;\r
-       \r
-       /* initialize the options string of tesh */\r
-       init_options();\r
-       \r
-       /* let the function getopt_long display the errors if any */\r
-       opterr = 1;\r
-       \r
-       /* set option index to zero */\r
-       optind = 0;\r
-       \r
-       while (optind < argc)\r
-       {\r
-               c = getopt_long(argc, argv, optstring, longopts, (int *) 0);\r
-               \r
-               if(c == EOF)\r
-               {\r
-                       /* end of the command line or "--".  */\r
-                       break;\r
-               }\r
-               else if (c == 1)\r
-               {\r
-                       /* no option specified, assume it's a tesh file to run */\r
-                       char* path;\r
-                       char* delimiter;\r
-                       \r
-                       /* getpath returns -1 when the file to get the path doesn't exist */\r
-                       if(getpath(optarg, &path) < 0)\r
-                       {\r
-                               exit_code = errno;\r
-                               \r
-                               if(ENOENT == errno)\r
-                                       ERROR1("File %s does not exist", optarg);\r
-                               else\r
-                                       ERROR0("Insufficient memory is available to parse the command line : system error");\r
-                                       \r
-                               return -1;\r
-                       }\r
-                       \r
-                       /* get to the last / (if any) to get the short name of the file */\r
-                       delimiter = strrchr(optarg,'/');\r
-                       \r
-                       /* create a new file stream which represents the tesh file to run */\r
-                       fstream = fstream_new(path, delimiter ? delimiter + 1 : optarg);\r
-                       \r
-                       free(path);\r
-                       \r
-                       /* if the list of all tesh files to run already contains this file\r
-                        * destroy it and display a warning, otherwise add it in the list.\r
-                        */\r
-                       if(fstreams_contains(fstreams, fstream))\r
-                       {\r
-                               fstream_free(&fstream);\r
-                               WARN1("File %s already specified to be run", optarg);\r
-                       }\r
-                       else\r
-                               fstreams_add(fstreams, fstream);\r
-                               \r
-                       \r
-                               \r
-                       \r
-               }\r
-               else if (c == '?')\r
-               {\r
-                       /* unknown option, let getopt_long() displays the error */\r
-                       ERROR0("Command line processing failed : invalid command line");\r
-                       exit_code = EINVCMDLINE;\r
-                       return -1;\r
-               }\r
-               else\r
-               {\r
-                       for(entry = opt_entries; entry->c != '\0'; ++entry)\r
-                               \r
-                               if(c == entry->c)\r
-                               {\r
-               \r
-                                       switch (entry->type)\r
-                                       {\r
-                                               /* impossible */\r
-                                               default:\r
-                                               ERROR0("Command line processing failed : internal error");\r
-                                               exit_code = EPROCCMDLINE;\r
-                                               return -1;\r
-                                               \r
-                                               \r
-                                               /* flag options */\r
-                                               case flag:\r
-                                               /* set the flag to one */\r
-                                               *(int*) entry->value = 1;\r
-                                               \r
-                                               break;\r
-                                               \r
-                                               /* string options */\r
-                                               case string:\r
-               \r
-                                               if(!optarg)\r
-                                               {\r
-                                                       /* an option with a optional arg is specified use the entry->optional_value */\r
-                                                       optarg = (char*)entry->optional_value;\r
-                                               }\r
-                                               else if (*optarg == '\0')\r
-                                               {\r
-                                                       /* a non optional argument is not specified */\r
-                                                       ERROR2("Option %c \"%s\"requires an argument",entry->c,entry->long_name);\r
-                                                       exit_code = ENOARG;\r
-                                                       return -1;\r
-                                               }\r
-                                               \r
-                                               /* --load-directory option */\r
-                                               if(!strcmp(entry->long_name,"load-directory"))\r
-                                               {\r
-                                                       #ifdef WIN32\r
-                                                       struct stat info = {0};\r
-                                                       if(stat(optarg, &info) || !S_ISDIR(info.st_mode))\r
-                                                       {\r
-                                                               ERROR1("%s is not a directory",optarg);\r
-                                                               exit_code = ENOTDIR;\r
-                                                               return -1;\r
-                                                       }       \r
-\r
-                                                       #else\r
-                                                       char* path;\r
-                                                       \r
-                                                       if(translatepath(optarg, &path) < 0)\r
-                                                       {\r
-                                                               exit_code = errno;\r
-                                                               \r
-                                                               if(ENOTDIR == errno)\r
-                                                                       ERROR1("%s is not a directory",optarg);\r
-                                                               else\r
-                                                                       ERROR0("Insufficient memory is available to process the command line - system error");\r
-                                                                       \r
-                                                               return -1;\r
-                                                               \r
-                                                       }\r
-                                                       #endif\r
-                                                       else\r
-                                                       {\r
-                                                               #ifdef WIN32\r
-                                                               directory = directory_new(optarg);\r
-                                                               #else\r
-                                                               directory = directory_new(path);\r
-                                                               free(path);\r
-                                                               #endif\r
-                                               \r
-                                                               if(directories_contains(directories, directory))\r
-                                                               {\r
-                                                                       directory_free((void**)&directory);\r
-                                                                       WARN1("Directory %s already specified to be load",optarg);\r
-                                                               }\r
-                                                               else\r
-                                                                        directories_add(directories, directory);\r
-                                                                        \r
-                                                               \r
-                                                       }                       \r
-                                               }\r
-                                               else if(!strcmp(entry->long_name,"directory"))\r
-                                               {\r
-                                                       #ifdef WIN32\r
-                                                       struct stat info = {0};\r
-                                                       if(stat(optarg, &info) || !S_ISDIR(info.st_mode))\r
-                                                       {\r
-                                                               ERROR1("%s is not a directory",optarg);\r
-                                                               exit_code = ENOTDIR;\r
-                                                               return -1;\r
-                                                       }       \r
-\r
-                                                       #else\r
-                                                       char* path ;\r
-                                                       \r
-                                                       if(translatepath(optarg, &path) < 0)\r
-                                                       {\r
-                                                               exit_code = errno;\r
-                                                               \r
-                                                               if(ENOTDIR == errno)\r
-                                                                       ERROR1("%s is not a directory",optarg);\r
-                                                               else\r
-                                                                       ERROR0("Insufficient memory is available to process the command line - system error");\r
-                                                                       \r
-                                                               return -1;\r
-                                                       }\r
-                                                       #endif\r
-                                                       else\r
-                                                       {\r
-                                                               char* buffer = getcwd(NULL, 0);\r
-\r
-                                                               #ifdef WIN32\r
-                                                               \r
-                                                               if(!strcmp(buffer, optarg))\r
-                                                                       WARN1("Already in the directory %s", optarg);\r
-                                                               else if(!print_directory_flag)\r
-                                                                       INFO1("Entering directory \"%s\"",optarg);\r
-                                                               \r
-                                                               chdir(optarg);\r
-                                                               #else\r
-                                                               \r
-                                                               if(!strcmp(buffer, path))\r
-                                                                       WARN1("Already in the directory %s", optarg);\r
-                                                               else if(!print_directory_flag)\r
-                                                                       INFO1("Entering directory \"%s\"",path);\r
-\r
-                                                               chdir(path);\r
-                                                               free(path);\r
-                                                               #endif\r
-\r
-                                                               free(buffer);\r
-                                                               \r
-                                                               \r
-                                                       }       \r
-                                               }\r
-                                               \r
-                                               /* --suffix option */\r
-                                               else if(!strcmp(entry->long_name,"suffix"))\r
-                                               {\r
-                                                       if(strlen(optarg) > MAX_SUFFIX)\r
-                                                       {\r
-                                                               ERROR1("Suffix %s too long",optarg);\r
-                                                               exit_code = ESUFFIXTOOLONG;     \r
-                                                               return -1;\r
-                                                       }\r
-                                                       \r
-                                                       if(optarg[0] == '.')\r
-                                                       {\r
-                                                               char* cur;\r
-                                                               unsigned int i;\r
-                                                               int exists = 0;\r
-\r
-                                                               char suffix[MAX_SUFFIX + 2] = {0};\r
-                                                               sprintf(suffix,".%s",optarg);\r
-                                                               \r
-                                                               xbt_dynar_foreach(suffixes, i, cur)\r
-                                                               {\r
-                                                                       if(!strcmp(suffix, cur))\r
-                                                                       {\r
-                                                                               exists = 1;\r
-                                                                               break;\r
-                                                                       }\r
-                                                               }\r
-\r
-                                                               if(exists)\r
-                                                                       WARN1("Suffix %s already specified to be used", optarg);\r
-                                                               else\r
-                                                                       xbt_dynar_push(suffixes, &suffix);\r
-                                                       }\r
-                                                       else\r
-                                                       {\r
-                                                               char* cur;\r
-                                                               unsigned int i;\r
-                                                               int exists = 0;\r
-\r
-                                                               xbt_dynar_foreach(suffixes, i, cur)\r
-                                                               {\r
-                                                                       if(!strcmp(optarg, cur))\r
-                                                                       {\r
-                                                                               exists = 1;\r
-                                                                               break;\r
-                                                                       }\r
-                                                               }\r
-\r
-                                                               if(exists)\r
-                                                                       WARN1("Suffix %s already specified to be used", optarg);\r
-                                                               else\r
-                                                                       xbt_dynar_push(suffixes, &optarg);      \r
-                                                       }\r
-                                               }\r
-                                               /* --file option */\r
-                                               else if(!strcmp(entry->long_name,"file"))\r
-                                               {\r
-                                                       char* path;\r
-                                                       char* delimiter;\r
-                                                       \r
-                                                       if(getpath(optarg, &path) < 0)\r
-                                                       {\r
-                                                               exit_code = errno;\r
-                                                               \r
-                                                               if(ENOENT == errno)\r
-                                                                       ERROR1("File %s does not exist", optarg);\r
-                                                               else\r
-                                                                       ERROR0("Insufficient memory is available to process the command line - system error");\r
-                                                               \r
-                                                               return -1;\r
-                                                       }\r
-                                                       \r
-                                                       delimiter = strrchr(optarg,'/');\r
-                                                       \r
-                                                       fstream = fstream_new(path, delimiter ? delimiter + 1 : optarg);\r
-                                                       \r
-                                                       free(path);\r
-                                                       \r
-                                                       if(fstreams_contains(fstreams, fstream))\r
-                                                       {\r
-                                                               fstream_free(&fstream);\r
-                                                               WARN1("File %s already specified to run", optarg);\r
-                                                       }\r
-                                                       else\r
-                                                               fstreams_add(fstreams, fstream);\r
-                                               }\r
-                                               /* --include-dir option */\r
-                                               else if(!strcmp(entry->long_name,"include-dir"))\r
-                                               {\r
-                                                       #ifdef WIN32\r
-                                                       struct stat info = {0};\r
-                                                       if(stat(optarg, &info) || !S_ISDIR(info.st_mode))\r
-                                                       {\r
-                                                               ERROR1("%s is not a directory",optarg);\r
-                                                               exit_code = ENOTDIR;\r
-                                                               return -1;\r
-                                                       }       \r
-\r
-                                                       #else\r
-                                                       char* path ;\r
-                                                       \r
-                                                       if(translatepath(optarg, &path) < 0)\r
-                                                       {\r
-                                                               exit_code = errno;\r
-                                                               \r
-                                                               if(ENOTDIR == errno)\r
-                                                                       ERROR1("%s is not a directory",optarg);\r
-                                                               else\r
-                                                                       ERROR0("Insufficient memory is available to process the command line - system error");\r
-                                                                       \r
-                                                               return -1;\r
-                                                       }\r
-                                                       #endif\r
-                                                       else\r
-                                                       {\r
-                                                               int exists = 0;\r
-                                                               unsigned int i;\r
-                                                               directory_t cur;\r
-                                                               #ifdef WIN32\r
-                                                               directory = directory_new(optarg);\r
-                                                               #else\r
-                                                               directory = directory_new(path);\r
-                                                               free(path);\r
-                                                               #endif\r
-\r
-                                                               xbt_dynar_foreach(include_dirs, i , cur)\r
-                                                               {\r
-                                                                       if(!strcmp(cur->name, optarg))\r
-                                                                       {\r
-                                                                               exists = 1;\r
-                                                                               break;\r
-                                                                       }\r
-                                                               }\r
-\r
-                                                               if(exists)\r
-                                                               {\r
-                                                                       directory_free((void**)&directory);\r
-                                                                       WARN1("Include directory %s already specified to be used",optarg);\r
-                                                                       \r
-                                                               }\r
-                                                               else\r
-                                                                       xbt_dynar_push(include_dirs, &directory);\r
-\r
-                                                       }\r
-                                               }\r
-                                               /* --exclude option */ \r
-                                               else if(!strcmp(entry->long_name,"exclude"))\r
-                                               {\r
-                                                       char* path;\r
-                                                       char* delimiter;\r
-                       \r
-                                                       if(getpath(optarg, &path) < 0)\r
-                                                       {\r
-                                                               exit_code = errno;\r
-                                                               \r
-                                                               if(ENOENT == errno)\r
-                                                                       ERROR1("file %s does not exist", optarg);\r
-                                                               else\r
-                                                                       ERROR0("Insufficient memory is available to process the command line - system error");\r
-                                                                       \r
-                                                               return -1;\r
-                                                       }\r
-                       \r
-                                                       delimiter = strrchr(optarg,'/');\r
-                       \r
-                                                       fstream = fstream_new(path, delimiter ? delimiter + 1 : optarg);\r
-                                                       free(path);\r
-                       \r
-                                                       if(excludes_contains(excludes, fstream))\r
-                                                       {\r
-                                                               fstream_free(&fstream);\r
-                                                               WARN1("File %s already specified to be exclude", optarg);\r
-                                                       }\r
-                                                       else\r
-                                                               excludes_add(excludes, fstream);\r
-                                                                       \r
-                                               }\r
-                                               /* --log option */\r
-                                               else if(!strcmp(entry->long_name,"log"))\r
-                                               {\r
-                                                       xbt_dynar_push(logs, &optarg);\r
-                                               }\r
-                                               else\r
-                                               {\r
-                                                       INFO1("Unexpected option %s", optarg);\r
-                                                       return -1;\r
-                                               }\r
-                                               \r
-                                               \r
-                                               break;\r
-                                               \r
-                                               /* strictly positve number options */\r
-                                               case number:\r
-                                                       \r
-                                               if ((NULL == optarg) && (argc > optind))\r
-                                               {\r
-                                                       const char* cp;\r
-                                                       \r
-                                                       for (cp = argv[optind]; isdigit(cp[0]); ++cp)\r
-                                                               if(cp[0] == '\0')\r
-                                                                       optarg = argv[optind++];\r
-                                               }\r
-               \r
-                                               /* the number option is specified */\r
-                                               if(NULL != optarg)\r
-                                               {\r
-                                                       int i = atoi(optarg);\r
-                                                       const char *cp;\r
-\r
-                                                       for (cp = optarg; isdigit(cp[0]); ++cp);\r
-               \r
-                                                       if (i < 1 || cp[0] != '\0')\r
-                                                       {\r
-                                                               ERROR2("Option %c \"%s\" requires an strictly positive integer as argument",entry->c, entry->long_name);\r
-                                                               exit_code = ENOTPOSITIVENUM;\r
-                                                               return -1;\r
-                                                       }\r
-                                                       else\r
-                                                               *(int*)entry->value = i;\r
-                                               }\r
-                                               /* the number option is specified but has no arg, use the optional value*/\r
-                                               else\r
-                                                       *(int*)entry->value = *(int*) entry->optional_value;\r
-                                               \r
-                                               break;\r
-               \r
-                               }\r
-                               break;\r
-                       }\r
-               }\r
-       }\r
-\r
-       return 0;\r
-}\r
-\r
-static void\r
-print_usage(void)\r
-{\r
-       const char **cpp;\r
-       FILE* stream;\r
-       \r
-       stream = exit_code ? stderr : stdout;\r
-       \r
-       fprintf (stream, "Usage: tesh [options] [file] ...\n");\r
-       \r
-       for (cpp = usage; *cpp; ++cpp)\r
-               fputs (*cpp, stream);\r
-       \r
-       fprintf(stream, "\nReport bugs to <martin.quinson@loria.fr | malek.cherier@loria.fr>\n");\r
-}\r
-\r
-static void\r
-print_version(void)\r
-{\r
-       /* TODO : display the version of tesh */\r
-       printf("Version :\n");\r
-       printf("  tesh version %s : Mini shell specialized in running test units by Martin Quinson \n", version);\r
-       printf("  and Malek Cherier\n");\r
-       printf("  Copyright (c) 2007, 2008 Martin Quinson, Malek Cherier\n");\r
-       printf("  All rights reserved\n");\r
-       printf("  This program is free software; you can redistribute it and/or modify it\n");\r
-       printf("  under the terms of the license (GNU LGPL) which comes with this package.\n\n");\r
-       \r
-       if(!print_usage_flag)\r
-               printf("Report bugs to <martin.quinson@loria.fr | malek.cherier@loria.fr>");\r
-}\r
-\r
-static void\r
-print_readme(void)\r
-{\r
-       size_t len;\r
-       char * line = NULL;\r
-       \r
-       FILE* stream = fopen("README.txt", "r");\r
-       \r
-       if(!stream)\r
-       {\r
-               ERROR0("Unable to locate the README.txt file");\r
-               exit_code = EREADMENOTFOUND;\r
-               return;\r
-       }\r
-       \r
-       while(getline(&line, &len, stream) != -1)\r
-               printf("%s",line);\r
-               \r
-       fclose(stream);\r
-}\r
-\r
-\r
+/*
+ * src/main.c - this file contains the main function of tesh.
+ *
+ * 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.
+ *
+ *
+ */
+#include <runner.h>
+#include <fstream.h>
+#include <fstreams.h>
+#include <directory.h>
+#include <directories.h>
+#include <excludes.h>
+#include <getopt.h>
+#include <getpath.h>
+
+#include <locale.h>
+
+/*
+ * entry used to define the parameter of a tesh option.
+ */
+typedef struct s_optentry
+{
+       int c;                                                          /* the character of the option                                                                                  */
+       
+       /* 
+        * the type of the argument of the option 
+        */
+       enum                                            
+       {
+               flag,                                                   /* it's a flag option, by default the flag is set to zero                               */                                              
+               string,                                                 /* the option has strings as argument                                                                   */                                      
+               number                                                  /* the option has an integral positive number as argument                               */                      
+       }type;
+       
+       byte* value;                                            /* the value of the option                                                                                              */                      
+       byte* optional_value;                           /* the optional value of the option if not specified                                    */
+       const char * long_name;                         /* the long name of the command                                                                                 */
+}s_optentry_t,* optentry_t;
+
+
+/* logs */
+XBT_LOG_NEW_DEFAULT_CATEGORY(tesh,"TEst SHell utility");
+
+#ifdef WIN32
+/* Windows specific : the previous process error mode                  */
+static UINT 
+prev_error_mode = 0;
+#endif
+
+/* this object represents the root directory */
+directory_t
+root_directory = NULL;
+
+/* the current version of tesh                                                                 */
+static const char* 
+version = "1.0";
+
+/* ------------------------------------------------------------ */
+/* options                                                                                                             */
+/* ------------------------------------------------------------ */
+
+/* ------------------------------------------------------------ */
+/* numbers                                                                                                             */
+/* ------------------------------------------------------------ */
+
+
+/* --jobs is specified with arg                                                                        */
+static int 
+jobs_nb = -2;
+
+/* --jobs option is not specified (use the default job count)  */
+static int 
+default_jobs_nb = 1;
+
+/* --jobs is specified but has no arg (one job per unit)               */
+static int 
+optional_jobs_nb = -1;
+
+/* the global timeout                                                                                  */
+static int
+timeout = INDEFINITE;
+
+/* ------------------------------------------------------------ */
+/* strings                                                                                     */
+/* ------------------------------------------------------------ */
+
+/* --C change the directory before running the units                   */
+static directories_t 
+directories = NULL;
+
+/* the include directories : see the !i metacommand                            */
+/*vector_t 
+include_dirs = NULL;*/
+xbt_dynar_t
+include_dirs = NULL;
+
+/* the list of tesh files to run                                                               */
+static fstreams_t 
+fstreams = NULL;
+
+/* xbt logs                                                                                                            */
+static xbt_dynar_t
+logs = NULL;
+
+/* the list of tesh file suffixes                                                              */
+static xbt_dynar_t
+suffixes = NULL;
+
+
+static excludes_t
+excludes = NULL;
+
+
+/* ------------------------------------------------------------ */
+/* flags                                                                                                               */
+/* ------------------------------------------------------------ */
+
+/* if 1, keep going when some commands can't be found
+ * default value 0 : not keep going
+ */
+int 
+keep_going_flag = 0;
+
+/* if 1, ignore failures from commands
+ * default value : do not ignore failures
+ */
+int 
+keep_going_unit_flag = 0;
+
+/* if 1, display tesh usage                                                                            */
+static int 
+print_usage_flag = 0;
+
+/* if 1, display the tesh version                                                              */
+static int 
+print_version_flag = 0;
+
+/* if 1, the syntax of all tesh files is checked 
+ * before running them
+ */
+static int
+check_syntax_flag = 0;
+
+/* if 1, the status of all the units is display at
+ * the end.
+ */
+static int
+summary_flag = 0;
+
+/* if 1 and the flag want_summay is set to 1 tesh display the detailed summary of the run */
+int 
+detail_summary_flag = 0;
+
+/* if 1, the directories are displayed                                                 */
+int 
+print_directory_flag = 0;
+
+/* if 1, just check the syntax of all the tesh files
+ * do not run them.
+ */
+int
+dry_run_flag = 0;
+
+/* if 1, display the tesh files syntax and exit                                        */
+static int
+print_readme_flag = 0;
+
+int 
+silent_flag = 0;
+
+int 
+just_print_flag = 0;
+
+static int 
+env_overrides_flag  = 0;
+
+static int 
+print_database_flag = 0;
+
+static int 
+question_flag = 0;
+
+/* the semaphore used to synchronize the jobs */
+xbt_os_sem_t
+jobs_sem = NULL;
+
+/* the semaphore used by the runner to wait the end of all the units */
+xbt_os_sem_t
+units_sem = NULL;
+
+static int
+loaded = 0;
+
+int 
+interrupted = 0;
+
+int
+exit_code = 0; 
+
+pid_t
+pid =0;
+
+int 
+is_tesh_root = 1;
+
+xbt_dynar_t
+errors = NULL;
+
+xbt_os_mutex_t
+err_mutex = NULL;
+
+/* the table of the entries of the options */ 
+static const struct s_optentry opt_entries[] =
+{
+       { 'C', string, (byte*)NULL, 0, "directory" },
+       { 'x', string, (byte*)&suffixes, 0, "suffix" },
+       { 'e', flag, (byte*)&env_overrides_flag, 0, "environment-overrides", },
+       { 'f', string, (byte*)&fstreams, 0, "file" },
+       { 'h', flag, (byte*)&print_usage_flag, 0, "help" },
+       { 'a', flag, (byte*)&print_readme_flag, 0, "semantic" },
+       { 'i', flag, (byte*)&keep_going_unit_flag, 0, "keep-going-unit" },
+       { 'I', string, (byte*)&include_dirs, 0, "include-dir" },
+       { 'j', number, (byte*)&jobs_nb, (byte*) &optional_jobs_nb, "jobs" },
+       { 'k', flag, (byte*)&keep_going_flag, 0, "keep-going" },
+       { 'm', flag, (byte*)&detail_summary_flag, 0, "detail-summary" },
+       { 'c', flag, (byte*)&just_print_flag, 0, "just-print" },
+       { 'd', flag, (byte*)&print_database_flag, 0,"display-data-base" },
+       { 'q', flag, (byte*)&question_flag, 0, "question_flag" },
+       { 's', flag, (byte*)&silent_flag, 0, "silent" },
+       { 'V', flag, (byte*)&print_version_flag, 0, "version" },
+       { 'w', flag, (byte*)&print_directory_flag, 0,"dont-display-directory" },
+       { 'n', flag, (byte*)&dry_run_flag, 0, "dry-run"},
+       { 't', number, (byte*)&timeout, 0, "timeout" },
+       { 'S', flag, (byte*)&check_syntax_flag, 0, "check-syntax"},
+       { 'r', string, (byte*)&directories, 0, "load-directory"},
+       { 'v', flag, (byte*)&summary_flag, 0, "summary"},
+       { 'F', string,(byte*)&excludes, 0, "exclude"},
+       { 'l', string,(byte*)&logs,0,"log"},
+       { 0, 0, 0, 0, 0}
+};
+
+/* the tesh usage                                                                                              */
+static const char* usage[] =
+{
+       "Options:\n",
+       "  -C DIRECTORY, --directory=DIRECTORY   Change to DIRECTORY before running any commands.\n",
+       "  -e, --environment-overrides           Environment variables override files.\n",
+       "  -f FILE, --file=FILE                  Read FILE as a teshfile.\n",
+       "                                           remark :\n",
+       "                                           all argument of the command line without\n",
+       "                                           option is dealed as a tesh file.\n",
+       "  -h, --help                            Print this message and exit.\n",
+       "  -i, --keep-going-unit                 Ignore failures from commands.\n",
+       "                                        The possible failures are :\n",
+       "                                         - the exit code differ from the expected\n",
+       "                                         - the signal throw differ from the expected\n",
+       "                                         - the output differ from the expected\n",
+       "                                         - the read pipe is broken\n",
+       "                                         - the write pipe is broken\n",
+       "                                         - the command assigned delay is outdated\n",
+       "  -I DIRECTORY, --include-dir=DIRECTORY Search DIRECTORY for included files.\n",
+       "  -j [N], --jobs[=N]                    Allow N commands at once; infinite commands with\n"
+       "                                        no arg.\n",
+       "  -k, --keep-going                      Keep going when some commands can't be made or\n",
+       "                                        failed.\n",
+       "  -c, --just-print                      Don't actually run any commands; just print them.\n",
+       "  -p, --print-data-base                 Display tesh's internal database.\n",
+       "  -q, --question                        Run no commands; exit status says if up to date.\n",
+       "  -s, --silent,                         Don't echo commands.\n",
+       "  -V, --version                         Print the version number of tesh and exit.\n",
+       "  -d, --dont-print-directory            Don't display the current directory.\n",
+       "  -n, --dry-run                         Check the syntax of the specified tesh files, display the result and exit.\n",
+       "  -t, --timeout                         Wait the end of the commands at most timeout seconds.\n",
+       "  -S, --check-syntax                    Check the syntax of the tesh files before run them. \n",
+       "  -x, --suffix                          Consider the new suffix for the tesh files.\n"
+       "                                           remark :\n",
+       "                                           the default suffix for the tesh files is \".tesh\".\n",
+       " -a, --read-me                          Print the read me file and exit.\n",
+       " -b, --build-file                       Build a tesh file.\n",
+       " -r, --load-directory                   Run all the tesh files located in the directories specified by the option --directory.\n",
+       " -v, --summary                          Display the status of the commands.\n",
+       " -m, --detail-summary                   Detail the summary of the run.\n",
+       " -F file , --exclude=FILE               Ignore the tesh file FILE.\n",
+       " -l format, --log                       Format of the xbt logs.\n",
+       NULL
+};
+
+/* the string of options of tesh                                                               */                                                              
+static char 
+optstring[1 + sizeof (opt_entries) / sizeof (opt_entries[0]) * 3];
+
+/* the option table of tesh                                                                            */
+static struct 
+option longopts[(sizeof (opt_entries) / sizeof (s_optentry_t))];
+
+static void
+init_options(void);
+
+static int
+process_command_line(int argc, char** argv);
+
+static void
+load(void);
+
+static void
+print_usage(void);
+
+static void
+print_version(void);
+
+static void
+finalize(void);
+
+static void
+print_readme(void);
+
+static int
+init(void);
+
+
+static void 
+sig_abort_handler(int signum)
+{
+       /* TODO : implement this function */
+       INFO0("sig_abort_handler() called");
+}
+
+static void 
+sig_int_handler(int signum)
+{
+       /* TODO : implement this function */
+       INFO0("sig_int_handler() called");
+}
+
+static void 
+free_string(void* str)
+{
+       free(*(void**)str);
+}
+
+static void 
+free_error(void* e)
+{
+       free(*(void**)e);
+}
+
+int
+main(int argc, char* argv[])
+{
+       int _argc;
+
+       /* set the locale to the default*/
+       setlocale(LC_ALL,"");
+       
+       /* initialize tesh */
+       if(init() < 0)
+               finalize();
+               
+       /* process the command line */
+       if(process_command_line(argc, argv) < 0)
+               finalize();
+       
+       /* move to the root directory (the directory may change during the command line processing) */
+       chdir(root_directory->name);
+               
+       /* initialize the xbt library 
+        * for thread portability layer
+        */
+        
+       /* xbt initialization */
+
+       if((_argc = xbt_dynar_length(logs)))
+       {
+               int i;
+
+               char** _argv = (char**)calloc(_argc, sizeof(char*));
+               
+               for(i = 0; i < _argc; i++)
+                       xbt_dynar_pop(logs, &(_argv[i]));
+
+               xbt_init(&_argc, _argv);
+
+               while(--i)
+                       free(_argv[i]);
+
+               free(_argv);
+       }
+       else
+               xbt_init(&argc, argv);
+               
+       /* the user wants to display the usage of tesh */
+       if(print_version_flag)
+       {
+               print_version();
+
+               if(!print_usage_flag)
+                       finalize();
+       }
+       
+       /* the user wants to display the usage of tesh */
+       if(print_usage_flag)
+       {
+               print_usage();
+               finalize();
+       }
+       
+       /* the user wants to display the semantic of the tesh file metacommands */
+       if(print_readme_flag)
+       {
+               print_readme();
+               finalize();
+       }
+       
+       /* load tesh files */
+       load();
+       
+       
+       /* use by the finalize function to known if it must display the tesh usage */   
+       loaded = 1;
+
+       if(-2 == jobs_nb)
+       {/* --jobs is not specified (use the default value) */
+               jobs_nb = default_jobs_nb;
+       }
+       else if(optional_jobs_nb == jobs_nb)
+       {/* --jobs option is specified with no args (use one job per unit) */
+               jobs_nb = fstreams_get_size(fstreams);
+       }
+
+       if(jobs_nb > fstreams_get_size(fstreams))
+       {/* --jobs = N is specified and N is more than the number of tesh files */
+               
+               WARN0("Number of requested jobs exceed the number of files to run");
+               
+               /* assume one job per file */
+               jobs_nb = fstreams_get_size(fstreams);
+       }
+
+       /* initialize the semaphore used to synchronize all the units */
+       jobs_sem = xbt_os_sem_init(jobs_nb);
+
+       /* initialize the semaphore used by the runner to wait for the end of all units */
+       units_sem = xbt_os_sem_init(0);
+       
+       /* initialize the runner */
+       if(runner_init(check_syntax_flag, timeout, fstreams) < 0)
+               finalize();
+               
+       if(just_print_flag && silent_flag)
+               silent_flag = 0;
+               
+       if(just_print_flag && dry_run_flag)
+               WARN0("mismatch in the syntax : --just-check-syntax and --just-display options at same time");
+       
+       /* run all the units */
+       runner_run();
+       
+       
+       /* show the result of the units */
+       if(summary_flag || dry_run_flag)
+               runner_summarize();
+               
+       /* all the test are runned, destroy the runner */
+       runner_destroy();
+       
+       /* then, finalize tesh (release all the allocated memory and exits) */
+       finalize();
+       
+       #ifndef WIN32
+       return exit_code;
+       #endif
+       
+}
+
+/* init --     initialize tesh : allocated all the objects needed by tesh to run
+ *                     the tesh files specified in the command line.
+ *
+ * return      If successful the function returns zero. Otherwise the function returns
+ *                     -1 and sets the global variable errno to the appropriate error code.
+ */
+
+
+
+static int
+init(void)
+{
+       char* buffer;
+       char* suffix = strdup(".tesh");
+       
+       #ifdef WIN32
+       /* Windows specific : don't display the general-protection-fault message box and
+        * the the critical-error-handler message box (instead the system send the error
+        * to the calling process : tesh)
+        */
+       prev_error_mode = SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX);
+       #else
+       struct sigaction act;
+       /* Ignore pipe issues.
+        * They will show up when we try to send data to dead buddies, 
+     * but we will stop doing so when we're done with provided input 
+     */
+       memset(&act,0, sizeof(struct sigaction));
+       act.sa_handler = SIG_IGN;
+       sigaction(SIGPIPE, &act, NULL);
+       
+       
+       memset(&act,0, sizeof(struct sigaction));
+       act.sa_handler = sig_abort_handler;
+       sigaction(SIGABRT, &act, NULL);
+       
+       memset(&act,0, sizeof(struct sigaction));
+       act.sa_handler = sig_int_handler;
+       sigaction(SIGINT, &act, NULL);
+       
+       #endif
+       
+       err_mutex = xbt_os_mutex_init();
+       
+       /* handle the abort signal */
+       /*signal(SIGABRT, sig_abort_handler);*/
+       
+       /* handle the interrupt signal */
+       /*signal(SIGINT, sig_int_handler);*/
+       
+       /* used to store the files to run */
+       if(!(fstreams = fstreams_new(DEFAULT_FSTREAMS_CAPACITY, (void_f_pvoid_t)fstream_free)))
+       {
+               ERROR1("(system error) %s", strerror(errno));
+               return -1;
+       }
+       
+       /* register the current directory */
+       if(!(buffer  = getcwd(NULL, 0)))
+       {
+               ERROR1("(system error) %s", strerror(errno));
+               return -1;
+       }
+       
+       /* save the root directory */
+       if(!(root_directory = directory_new(buffer)))
+       {
+               ERROR1("(system error) %s", strerror(errno));
+               return -1;
+       }
+       
+       free(buffer);
+       
+       /* this vector contains all the errors of the run */
+       errors = xbt_dynar_new(sizeof(xerror_t), free_error);
+       
+       /* the directories to loads */
+       if(!(directories = directories_new()))
+       {
+               ERROR1("(system error) %s", strerror(errno));
+               return -1;
+       }
+       
+       /* the include directories */
+       include_dirs = xbt_dynar_new(sizeof(directory_t), (void_f_pvoid_t)directory_free);
+       
+       /* xbt logs option */
+       if(!(logs = xbt_dynar_new(sizeof(char*), free_string)))
+       {
+               ERROR1("(system error) %s", strerror(errno));
+               return -1;
+       }
+       
+       /* the excluded files */
+       if(!(excludes = excludes_new()))
+       {
+               ERROR1("(system error) %s", strerror(errno));
+               return -1;
+       }
+       
+       /* the suffixes */
+       suffixes = xbt_dynar_new(sizeof(char*),free_string);
+       
+       /* register the default suffix ".tesh" */
+       xbt_dynar_push(suffixes, &suffix);
+       
+       return 0;
+}
+
+/* load -- load the tesh files to run */
+static void
+load(void)
+{
+       
+       /* if the directories object is not empty load all the tesh files contained in
+        * the directories specified in the command line (this tesh files must have the
+        * a suffix specified in the suffixes object.
+        */
+       if(!directories_is_empty(directories))
+               directories_load(directories, fstreams, suffixes);
+       
+       /* if no tesh file has been specified in the command line try to load the default tesh file
+        * teshfile from the current directory
+        */
+       if(fstreams_is_empty(fstreams))
+       {
+               struct stat buffer = {0};
+               
+               /* add the default tesh file if it exists in the current directory */
+               if(!stat("teshfile", &buffer) && S_ISREG(buffer.st_mode))
+                       fstreams_add(fstreams, fstream_new(getcwd(NULL, 0), "teshfile"));
+       }
+       
+       /* excludes the files specified in the command line and stored in the excludes object */
+       if(!excludes_is_empty(excludes) && !fstreams_is_empty(fstreams))
+       {
+               /* check the files to excludes before */        
+               excludes_check(excludes, fstreams);
+               
+               /* exclude the specified tesh files */
+               fstreams_exclude(fstreams, excludes);
+       }
+       
+       /* if the fstreams object is empty use the stdin */
+       if(fstreams_is_empty(fstreams))
+               fstreams_add(fstreams, fstream_new(NULL, "stdin"));
+       
+       /* load the tesh files (open them) */
+       fstreams_load(fstreams);
+       
+}
+
+/* finalize -- cleanup all the allocated objects and display the tesh usage if needed */
+static void
+finalize(void)
+{
+       
+       if(is_tesh_root && !summary_flag)
+       {
+               xerror_t error;
+               unsigned int i;
+
+               xbt_dynar_foreach(errors, i, error)
+               {
+                       if(error->command)
+                               fprintf(stderr, "[tesh/ERROR] %s : <Command `%s'> <Unit `%s'> <C%d (%s)>\n", error->reason, error->command, error->unit, error->errcode, error_to_string(error->errcode));
+                       else if(!error->command && error->unit)
+                               fprintf(stderr, "[tesh/ERROR] %s : Unit `%s' - C%d (%s)\n", error->reason, error->unit, error->errcode, error_to_string(error->errcode));
+                       else if(!error->command && !error->unit && error->reason)
+                               fprintf(stderr, "[tesh/ERROR] %s : C%d (%s)\n", error->reason, error->errcode, error_to_string(error->errcode));                
+                       else if(!error->command && !error->unit && !error->reason)
+                               fprintf(stderr, "[tesh/ERROR] C%d (%s)\n", error->errcode, error_to_string(error->errcode));            
+                       
+               }
+       }
+       
+       
+       /* delete vector of errors */
+       if(errors)
+               xbt_dynar_free(&errors);
+               
+       xbt_os_mutex_destroy(err_mutex);
+       
+       /* delete the fstreams object */
+       if(fstreams)
+               fstreams_free((void**)&fstreams);
+       
+       /* delete the excludes object */
+       if(excludes)    
+               excludes_free((void**)&excludes);
+       
+       /* delete the directories object */
+       if(directories)
+               directories_free((void**)&directories);
+               
+       /* delete the root directory object */
+       if(root_directory)
+               directory_free((void**)&root_directory);
+       
+       /* delete the include directories object */
+       if(include_dirs)
+               xbt_dynar_free(&include_dirs);
+       
+       /* delete the list of tesh files suffixes */    
+       if(suffixes)
+               xbt_dynar_free(&suffixes);
+       
+       /* delete the xbt log options list */
+       if(logs)
+               xbt_dynar_free(&logs);
+               
+               
+       /* destroy the semaphore used to synchronize the units */
+       if(jobs_sem)
+               xbt_os_sem_destroy(jobs_sem);
+       
+       /* destroy the semaphore used by the runner used to wait for the end of the units */
+       if(units_sem)
+               xbt_os_sem_destroy(units_sem);
+       
+       /* exit from the xbt framework */
+       xbt_exit();
+       
+       /* Windows specific (restore the previouse error mode */
+       #ifdef WIN32
+       SetErrorMode(prev_error_mode);
+       #endif
+       
+       if(!summary_flag && !dry_run_flag && !silent_flag && !just_print_flag && !print_version_flag && !print_usage_flag && is_tesh_root)
+       {
+               if(!exit_code)
+                       INFO2("tesh terminated with exit code %d : %s",exit_code, "success");
+               else
+                       ERROR2("tesh terminated with exit code %d : %s",exit_code, error_to_string(exit_code));
+       }
+       
+       
+       /* exit with the last error code */
+       exit(exit_code);
+}
+
+/* init_options -- initialize the options string */
+static void
+init_options (void)
+{
+       char *p;
+       unsigned int i;
+       
+       /* the function has been already called */
+       if(optstring[0] != '\0')
+               return;
+       
+       p = optstring;
+       
+       *p++ = '-';
+       
+       for (i = 0; opt_entries[i].c != '\0'; ++i)
+       {
+               /* initialize the long name of the option*/
+               longopts[i].name = (opt_entries[i].long_name == 0 ? "" : opt_entries[i].long_name);
+               
+               /* getopt_long returns the value of val */
+               longopts[i].flag = 0;
+               
+               /* the short option */
+               longopts[i].val = opt_entries[i].c;
+               
+               /* add the short option in the options string */
+               *p++ = opt_entries[i].c;
+               
+               switch (opt_entries[i].type)
+               {
+                       /* if this option is used to set a flag or if the argument must be ignored
+                        * the option has no argument
+                        */
+                       case flag:
+                       longopts[i].has_arg = no_argument;
+                       break;
+               
+                       /* the option has an argument */
+                       case string:
+                       case number:
+                       
+                       *p++ = ':';
+                       
+                       if(opt_entries[i].optional_value != 0)
+                       {
+                               *p++ = ':';
+                               
+                               longopts[i].has_arg = optional_argument;
+                       }
+                       else
+                               longopts[i].has_arg = required_argument;
+                       
+                       break;
+               }
+       }
+       
+       *p = '\0';
+       longopts[i].name = 0;
+}
+
+/* process_command_line --     process the command line
+ *
+ * param                                       argc the number of the arguments contained by the command line.
+ * param                                       The array of C strings containing all the arguments of the command 
+ *                                                     line.
+ *
+ * return                                      If successful, the function returns 0. Otherwise -1 is returned
+ *                                                     and sets the global variable errno to indicate the error.
+ *
+ * errors      [ENOENT]                A file name specified in the command line does not exist
+ */    
+
+static int
+process_command_line(int argc, char** argv)
+{
+       register const struct s_optentry* entry;
+       register int c;
+       directory_t directory;
+       fstream_t fstream;
+       
+       /* initialize the options string of tesh */
+       init_options();
+       
+       /* let the function getopt_long display the errors if any */
+       opterr = 1;
+       
+       /* set option index to zero */
+       optind = 0;
+       
+       while (optind < argc)
+       {
+               c = getopt_long(argc, argv, optstring, longopts, (int *) 0);
+               
+               if(c == EOF)
+               {
+                       /* end of the command line or "--".  */
+                       break;
+               }
+               else if (c == 1)
+               {
+                       /* no option specified, assume it's a tesh file to run */
+                       char* path;
+                       char* delimiter;
+                       
+                       /* getpath returns -1 when the file to get the path doesn't exist */
+                       if(getpath(optarg, &path) < 0)
+                       {
+                               exit_code = errno;
+                               
+                               if(ENOENT == errno)
+                                       ERROR1("File %s does not exist", optarg);
+                               else
+                                       ERROR0("Insufficient memory is available to parse the command line : system error");
+                                       
+                               return -1;
+                       }
+                       
+                       /* get to the last / (if any) to get the short name of the file */
+                       delimiter = strrchr(optarg,'/');
+                       
+                       /* create a new file stream which represents the tesh file to run */
+                       fstream = fstream_new(path, delimiter ? delimiter + 1 : optarg);
+                       
+                       free(path);
+                       
+                       /* if the list of all tesh files to run already contains this file
+                        * destroy it and display a warning, otherwise add it in the list.
+                        */
+                       if(fstreams_contains(fstreams, fstream))
+                       {
+                               fstream_free(&fstream);
+                               WARN1("File %s already specified to be run", optarg);
+                       }
+                       else
+                               fstreams_add(fstreams, fstream);
+                               
+                       
+                               
+                       
+               }
+               else if (c == '?')
+               {
+                       /* unknown option, let getopt_long() displays the error */
+                       ERROR0("Command line processing failed : invalid command line");
+                       exit_code = EINVCMDLINE;
+                       return -1;
+               }
+               else
+               {
+                       for(entry = opt_entries; entry->c != '\0'; ++entry)
+                               
+                               if(c == entry->c)
+                               {
+               
+                                       switch (entry->type)
+                                       {
+                                               /* impossible */
+                                               default:
+                                               ERROR0("Command line processing failed : internal error");
+                                               exit_code = EPROCCMDLINE;
+                                               return -1;
+                                               
+                                               
+                                               /* flag options */
+                                               case flag:
+                                               /* set the flag to one */
+                                               *(int*) entry->value = 1;
+                                               
+                                               break;
+                                               
+                                               /* string options */
+                                               case string:
+               
+                                               if(!optarg)
+                                               {
+                                                       /* an option with a optional arg is specified use the entry->optional_value */
+                                                       optarg = (char*)entry->optional_value;
+                                               }
+                                               else if (*optarg == '\0')
+                                               {
+                                                       /* a non optional argument is not specified */
+                                                       ERROR2("Option %c \"%s\"requires an argument",entry->c,entry->long_name);
+                                                       exit_code = ENOARG;
+                                                       return -1;
+                                               }
+                                               
+                                               /* --load-directory option */
+                                               if(!strcmp(entry->long_name,"load-directory"))
+                                               {
+                                                       #ifdef WIN32
+                                                       struct stat info = {0};
+                                                       if(stat(optarg, &info) || !S_ISDIR(info.st_mode))
+                                                       {
+                                                               ERROR1("%s is not a directory",optarg);
+                                                               exit_code = ENOTDIR;
+                                                               return -1;
+                                                       }       
+
+                                                       #else
+                                                       char* path;
+                                                       
+                                                       if(translatepath(optarg, &path) < 0)
+                                                       {
+                                                               exit_code = errno;
+                                                               
+                                                               if(ENOTDIR == errno)
+                                                                       ERROR1("%s is not a directory",optarg);
+                                                               else
+                                                                       ERROR0("Insufficient memory is available to process the command line - system error");
+                                                                       
+                                                               return -1;
+                                                               
+                                                       }
+                                                       #endif
+                                                       else
+                                                       {
+                                                               #ifdef WIN32
+                                                               directory = directory_new(optarg);
+                                                               #else
+                                                               directory = directory_new(path);
+                                                               free(path);
+                                                               #endif
+                                               
+                                                               if(directories_contains(directories, directory))
+                                                               {
+                                                                       directory_free((void**)&directory);
+                                                                       WARN1("Directory %s already specified to be load",optarg);
+                                                               }
+                                                               else
+                                                                        directories_add(directories, directory);
+                                                                        
+                                                               
+                                                       }                       
+                                               }
+                                               else if(!strcmp(entry->long_name,"directory"))
+                                               {
+                                                       #ifdef WIN32
+                                                       struct stat info = {0};
+                                                       if(stat(optarg, &info) || !S_ISDIR(info.st_mode))
+                                                       {
+                                                               ERROR1("%s is not a directory",optarg);
+                                                               exit_code = ENOTDIR;
+                                                               return -1;
+                                                       }       
+
+                                                       #else
+                                                       char* path ;
+                                                       
+                                                       if(translatepath(optarg, &path) < 0)
+                                                       {
+                                                               exit_code = errno;
+                                                               
+                                                               if(ENOTDIR == errno)
+                                                                       ERROR1("%s is not a directory",optarg);
+                                                               else
+                                                                       ERROR0("Insufficient memory is available to process the command line - system error");
+                                                                       
+                                                               return -1;
+                                                       }
+                                                       #endif
+                                                       else
+                                                       {
+                                                               char* buffer = getcwd(NULL, 0);
+
+                                                               #ifdef WIN32
+                                                               
+                                                               if(!strcmp(buffer, optarg))
+                                                                       WARN1("Already in the directory %s", optarg);
+                                                               else if(!print_directory_flag)
+                                                                       INFO1("Entering directory \"%s\"",optarg);
+                                                               
+                                                               chdir(optarg);
+                                                               #else
+                                                               
+                                                               if(!strcmp(buffer, path))
+                                                                       WARN1("Already in the directory %s", optarg);
+                                                               else if(!print_directory_flag)
+                                                                       INFO1("Entering directory \"%s\"",path);
+
+                                                               chdir(path);
+                                                               free(path);
+                                                               #endif
+
+                                                               free(buffer);
+                                                               
+                                                               
+                                                       }       
+                                               }
+                                               
+                                               /* --suffix option */
+                                               else if(!strcmp(entry->long_name,"suffix"))
+                                               {
+                                                       if(strlen(optarg) > MAX_SUFFIX)
+                                                       {
+                                                               ERROR1("Suffix %s too long",optarg);
+                                                               exit_code = ESUFFIXTOOLONG;     
+                                                               return -1;
+                                                       }
+                                                       
+                                                       if(optarg[0] == '.')
+                                                       {
+                                                               char* cur;
+                                                               unsigned int i;
+                                                               int exists = 0;
+
+                                                               char suffix[MAX_SUFFIX + 2] = {0};
+                                                               sprintf(suffix,".%s",optarg);
+                                                               
+                                                               xbt_dynar_foreach(suffixes, i, cur)
+                                                               {
+                                                                       if(!strcmp(suffix, cur))
+                                                                       {
+                                                                               exists = 1;
+                                                                               break;
+                                                                       }
+                                                               }
+
+                                                               if(exists)
+                                                                       WARN1("Suffix %s already specified to be used", optarg);
+                                                               else
+                                                                       xbt_dynar_push(suffixes, &suffix);
+                                                       }
+                                                       else
+                                                       {
+                                                               char* cur;
+                                                               unsigned int i;
+                                                               int exists = 0;
+
+                                                               xbt_dynar_foreach(suffixes, i, cur)
+                                                               {
+                                                                       if(!strcmp(optarg, cur))
+                                                                       {
+                                                                               exists = 1;
+                                                                               break;
+                                                                       }
+                                                               }
+
+                                                               if(exists)
+                                                                       WARN1("Suffix %s already specified to be used", optarg);
+                                                               else
+                                                                       xbt_dynar_push(suffixes, &optarg);      
+                                                       }
+                                               }
+                                               /* --file option */
+                                               else if(!strcmp(entry->long_name,"file"))
+                                               {
+                                                       char* path;
+                                                       char* delimiter;
+                                                       
+                                                       if(getpath(optarg, &path) < 0)
+                                                       {
+                                                               exit_code = errno;
+                                                               
+                                                               if(ENOENT == errno)
+                                                                       ERROR1("File %s does not exist", optarg);
+                                                               else
+                                                                       ERROR0("Insufficient memory is available to process the command line - system error");
+                                                               
+                                                               return -1;
+                                                       }
+                                                       
+                                                       delimiter = strrchr(optarg,'/');
+                                                       
+                                                       fstream = fstream_new(path, delimiter ? delimiter + 1 : optarg);
+                                                       
+                                                       free(path);
+                                                       
+                                                       if(fstreams_contains(fstreams, fstream))
+                                                       {
+                                                               fstream_free(&fstream);
+                                                               WARN1("File %s already specified to run", optarg);
+                                                       }
+                                                       else
+                                                               fstreams_add(fstreams, fstream);
+                                               }
+                                               /* --include-dir option */
+                                               else if(!strcmp(entry->long_name,"include-dir"))
+                                               {
+                                                       #ifdef WIN32
+                                                       struct stat info = {0};
+                                                       if(stat(optarg, &info) || !S_ISDIR(info.st_mode))
+                                                       {
+                                                               ERROR1("%s is not a directory",optarg);
+                                                               exit_code = ENOTDIR;
+                                                               return -1;
+                                                       }       
+
+                                                       #else
+                                                       char* path ;
+                                                       
+                                                       if(translatepath(optarg, &path) < 0)
+                                                       {
+                                                               exit_code = errno;
+                                                               
+                                                               if(ENOTDIR == errno)
+                                                                       ERROR1("%s is not a directory",optarg);
+                                                               else
+                                                                       ERROR0("Insufficient memory is available to process the command line - system error");
+                                                                       
+                                                               return -1;
+                                                       }
+                                                       #endif
+                                                       else
+                                                       {
+                                                               int exists = 0;
+                                                               unsigned int i;
+                                                               directory_t cur;
+                                                               #ifdef WIN32
+                                                               directory = directory_new(optarg);
+                                                               #else
+                                                               directory = directory_new(path);
+                                                               free(path);
+                                                               #endif
+
+                                                               xbt_dynar_foreach(include_dirs, i , cur)
+                                                               {
+                                                                       if(!strcmp(cur->name, optarg))
+                                                                       {
+                                                                               exists = 1;
+                                                                               break;
+                                                                       }
+                                                               }
+
+                                                               if(exists)
+                                                               {
+                                                                       directory_free((void**)&directory);
+                                                                       WARN1("Include directory %s already specified to be used",optarg);
+                                                                       
+                                                               }
+                                                               else
+                                                                       xbt_dynar_push(include_dirs, &directory);
+
+                                                       }
+                                               }
+                                               /* --exclude option */ 
+                                               else if(!strcmp(entry->long_name,"exclude"))
+                                               {
+                                                       char* path;
+                                                       char* delimiter;
+                       
+                                                       if(getpath(optarg, &path) < 0)
+                                                       {
+                                                               exit_code = errno;
+                                                               
+                                                               if(ENOENT == errno)
+                                                                       ERROR1("file %s does not exist", optarg);
+                                                               else
+                                                                       ERROR0("Insufficient memory is available to process the command line - system error");
+                                                                       
+                                                               return -1;
+                                                       }
+                       
+                                                       delimiter = strrchr(optarg,'/');
+                       
+                                                       fstream = fstream_new(path, delimiter ? delimiter + 1 : optarg);
+                                                       free(path);
+                       
+                                                       if(excludes_contains(excludes, fstream))
+                                                       {
+                                                               fstream_free(&fstream);
+                                                               WARN1("File %s already specified to be exclude", optarg);
+                                                       }
+                                                       else
+                                                               excludes_add(excludes, fstream);
+                                                                       
+                                               }
+                                               /* --log option */
+                                               else if(!strcmp(entry->long_name,"log"))
+                                               {
+                                                       xbt_dynar_push(logs, &optarg);
+                                               }
+                                               else
+                                               {
+                                                       INFO1("Unexpected option %s", optarg);
+                                                       return -1;
+                                               }
+                                               
+                                               
+                                               break;
+                                               
+                                               /* strictly positve number options */
+                                               case number:
+                                                       
+                                               if ((NULL == optarg) && (argc > optind))
+                                               {
+                                                       const char* cp;
+                                                       
+                                                       for (cp = argv[optind]; isdigit(cp[0]); ++cp)
+                                                               if(cp[0] == '\0')
+                                                                       optarg = argv[optind++];
+                                               }
+               
+                                               /* the number option is specified */
+                                               if(NULL != optarg)
+                                               {
+                                                       int i = atoi(optarg);
+                                                       const char *cp;
+
+                                                       for (cp = optarg; isdigit(cp[0]); ++cp);
+               
+                                                       if (i < 1 || cp[0] != '\0')
+                                                       {
+                                                               ERROR2("Option %c \"%s\" requires an strictly positive integer as argument",entry->c, entry->long_name);
+                                                               exit_code = ENOTPOSITIVENUM;
+                                                               return -1;
+                                                       }
+                                                       else
+                                                               *(int*)entry->value = i;
+                                               }
+                                               /* the number option is specified but has no arg, use the optional value*/
+                                               else
+                                                       *(int*)entry->value = *(int*) entry->optional_value;
+                                               
+                                               break;
+               
+                               }
+                               break;
+                       }
+               }
+       }
+
+       return 0;
+}
+
+static void
+print_usage(void)
+{
+       const char **cpp;
+       FILE* stream;
+       
+       stream = exit_code ? stderr : stdout;
+       
+       fprintf (stream, "Usage: tesh [options] [file] ...\n");
+       
+       for (cpp = usage; *cpp; ++cpp)
+               fputs (*cpp, stream);
+       
+       fprintf(stream, "\nReport bugs to <martin.quinson@loria.fr | malek.cherier@loria.fr>\n");
+}
+
+static void
+print_version(void)
+{
+       /* TODO : display the version of tesh */
+       printf("Version :\n");
+       printf("  tesh version %s : Mini shell specialized in running test units by Martin Quinson \n", version);
+       printf("  and Malek Cherier\n");
+       printf("  Copyright (c) 2007, 2008 Martin Quinson, Malek Cherier\n");
+       printf("  All rights reserved\n");
+       printf("  This program is free software; you can redistribute it and/or modify it\n");
+       printf("  under the terms of the license (GNU LGPL) which comes with this package.\n\n");
+       
+       if(!print_usage_flag)
+               printf("Report bugs to <martin.quinson@loria.fr | malek.cherier@loria.fr>");
+}
+
+static void
+print_readme(void)
+{
+       size_t len;
+       char * line = NULL;
+       
+       FILE* stream = fopen("README.txt", "r");
+       
+       if(!stream)
+       {
+               ERROR0("Unable to locate the README.txt file");
+               exit_code = EREADMENOTFOUND;
+               return;
+       }
+       
+       while(getline(&line, &len, stream) != -1)
+               printf("%s",line);
+               
+       fclose(stream);
+}
+
+