Update copyright to LGPL on all files
[dyninst.git] / testsuite / src / test_driver.C
1 /*
2  * Copyright (c) 1996-2009 Barton P. Miller
3  * 
4  * We provide the Paradyn Parallel Performance Tools (below
5  * described as "Paradyn") on an AS IS basis, and do not warrant its
6  * validity or performance.  We reserve the right to update, modify,
7  * or discontinue this software at any time.  We shall have no
8  * obligation to supply such updates or modifications or any other
9  * form of support to you.
10  * 
11  * By your use of Paradyn, you understand and agree that we (or any
12  * other person or entity with proprietary rights in Paradyn) are
13  * under no obligation to provide either maintenance services,
14  * update services, notices of latent defects, or correction of
15  * defects for Paradyn.
16  * 
17  * This library is free software; you can redistribute it and/or
18  * modify it under the terms of the GNU Lesser General Public
19  * License as published by the Free Software Foundation; either
20  * version 2.1 of the License, or (at your option) any later version.
21  * 
22  * This library is distributed in the hope that it will be useful,
23  * but WITHOUT ANY WARRANTY; without even the implied warranty of
24  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
25  * Lesser General Public License for more details.
26  * 
27  * You should have received a copy of the GNU Lesser General Public
28  * License along with this library; if not, write to the Free Software
29  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
30  */
31
32 // $Id: test_driver.C,v 1.7 2008/10/30 19:16:50 legendre Exp $
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <stdarg.h>
36 #include <string.h>
37 #include <string>
38 #include <errno.h>
39 #include <vector>
40 #include <iostream>
41 #include <sstream>
42 #include <assert.h>
43 #include <algorithm>
44 #include <sys/stat.h>
45 #include <time.h>
46
47 #if defined(os_windows_test)
48 #define vsnprintf _vsnprintf
49 #define snprintf _snprintf
50 #pragma warning(disable:4786)
51 #include <direct.h>
52 #else
53 #include <fnmatch.h>
54 #include <dirent.h>
55 #include <unistd.h>
56 #include <sys/times.h>
57 #include <strings.h>
58 #endif
59
60 #include "ParameterDict.h"
61 #include "test_lib.h"
62 #include "error.h"
63 #include "ResumeLog.h"
64 #include "TestOutputDriver.h"
65 #include "StdOutputDriver.h"
66 #include "comptester.h"
67 #include "help.h"
68
69 #define opt_none 1<<0
70 #define opt_low 1<<1
71 #define opt_high 1<<2
72 #define opt_max 1<<3
73 #define opt_all (opt_none|opt_low|opt_high|opt_max)
74
75 struct compiler_t {
76    const char *option;
77    const char *mutatee_str;
78    bool enabled;
79 };
80
81 #define NUM_COMPILERS 19
82 compiler_t compilers[] = {
83    { "-gcc", "gcc", false },
84    { "-g++", "g++", true },
85    { "-g77", "g77", true },
86    { "-icc", "icc", false },
87    { "-icpc", "icpc", false },
88    { "-pgcc", "pgcc", false },
89    { "-pgCC", "pgCC", false },
90    { "-cc", "cc", false },
91    { "-CC", "CC", false },
92    { "-cxx", "cxx", false },
93    { "-VC", "VC", false },
94    { "-VC++", "VC++", true },
95    { "-suncc", "suncc", false },
96    { "-xlc", "xlc", false },
97    { "-xlC", "xlC", false },
98    { "-ibmas", "ibmas", false },
99    { "-masm", "masm", false },
100    { "-nasm", "nasm", false },
101    { "-nocompiler", "nocompiler", true }
102 };
103    
104 // These determine the defaults when test driver is invoked with no options
105 int optLevel = opt_none;
106 bool runDefaultOpts = true;
107 bool runAllTests = true;
108 bool runAllMutatees = true;
109 bool runDefaultCompilers = true;
110 bool runAllCompilers = false;
111 bool runDefaultStarts = true;
112 bool runCreate = true;
113 bool runAttach = false;
114 bool runRewriter = false;
115 bool runDeserialize = false;
116 bool useHumanLog = true;
117 bool enableLogging = true;
118 bool printLabels = false;
119 bool shouldDebugBreak = false;
120 bool called_from_runTests = false;
121 bool quietFormat = false;
122 bool runDyninst = false;
123 bool runSymtab = false;
124 bool runInstruction = false;
125 bool runAllComps = true;
126 bool printMutateeLogHeader = false;
127 bool measureMEMCPU = false;
128 bool runAllABIs = true;
129 bool runABI_32 = false;
130 bool runABI_64 = false;
131 bool limitSkippedTests = false;
132 bool noclean = false;
133 int limitResumeGroup = -1;
134 int limitResumeTest = -1;
135 int skipToTest = 0;
136 int skipToMutatee = 0;
137 int skipToOption = 0;
138 int testLimit = 0;
139 int testsRun = 0;
140 int errorPrint = 0;
141 int debugPrint = 0;
142 char *resumelog_name = "resumelog";
143 char *humanlog_name = "-";
144 char *crashlog_name = "crashlog";
145 char *measureFileName = "-";
146 std::vector<char *> mutatee_list;
147 std::vector<char *> test_list;
148
149 #if defined(os_windows_test)
150 char *logfilename = "NUL";
151 #else
152 char *logfilename = "/dev/null";
153 #endif
154 FILE *outlog = NULL;
155 FILE *errlog = NULL;
156
157 char *pdscrdir = NULL;
158 char *uw_pdscrdir = "/p/paradyn/builds/scripts";
159 char *umd_pdscrdir = "/fs/dyninst/dyninst/current/scripts";
160
161 int parseArgs(int argc, char *argv[]);
162 int setupLogs();
163
164 // Include test setup data
165 #include "test_info_new.h"
166
167 #if !defined(os_windows_test)
168 int runScript(const char *name, ...)
169 {
170    char test[1024];
171    int result;
172    va_list ap;
173    va_start(ap, name);
174    vsnprintf(test, 1024, name, ap);
175    va_end(ap);
176
177    char test2[1024];
178    if ((outlog != NULL) && (outlog != stdout)) {
179       snprintf(test2, 1024, "sh -c \"%s\" >>%s 2>&1", test, logfilename);
180    } else {
181       snprintf(test2, 1024, "%s", test);
182    }
183
184    // Flush before/after script run
185    flushOutputLog();
186    flushErrorLog();
187    result = system(test2);
188    flushOutputLog();
189    flushErrorLog();
190
191    return result;
192 }
193 #else
194 int runScript(const char *name, ...) {
195    getOutput()->log(STDERR, "runScript not implemented on Windows\n");
196    assert(0);
197    return -1;
198 }
199 #endif
200
201 #if !defined(os_windows_test)
202 static void *mem_start;
203 static struct tms start_time;
204
205 #include <unistd.h>
206
207 void measureStart()
208 {
209    if (!measureMEMCPU)
210       return;
211
212    mem_start = sbrk(0);
213    times(&start_time);
214 }
215
216 void measureEnd()
217 {
218    if (!measureMEMCPU)
219       return;
220
221    void *mem_end = sbrk(0);
222    struct tms end_time;
223    times(&end_time);
224
225    signed long mem_diff = ((char *) mem_end) - ((char *) mem_start);
226    clock_t utime = end_time.tms_utime - start_time.tms_utime;
227    clock_t stime = end_time.tms_stime - start_time.tms_stime;
228
229    FILE *measure_file = NULL;
230    bool using_stdout;
231    if (strcmp(measureFileName, "-") == 0) {
232       using_stdout = true;
233       measure_file = stdout;
234    }
235    else {
236       using_stdout = false;
237       measure_file = fopen(measureFileName, "a");
238    }
239    if (!measure_file)
240    {
241       perror("Unable to open file for CPU/MEM measurement");
242       return;
243    }
244
245    fprintf(measure_file, "mem=%ld\tutime=%ld\tstime=%ld\n",
246            mem_diff, utime, stime);
247    if (!using_stdout)
248       fclose(measure_file);
249 }
250
251 void setupProcessGroup()
252 {
253    if (!called_from_runTests)
254       return;
255
256    setpgrp();
257 }
258
259 #else
260
261 void measureStart()
262 {
263 }
264
265 void measureEnd()
266 {
267 }
268
269 void setupProcessGroup()
270 {
271 }
272
273 #endif
274
275 void printLogMutateeHeader(const char *mutatee)
276 {
277    if (!enableLogging)
278       return;
279    flushOutputLog();
280    flushErrorLog();
281    // Mutatee Description
282    // Mutatee Info
283    if ( (mutatee != NULL) && (strcmp(mutatee, "") != 0) ) {
284       getOutput()->log(LOGINFO, "[Tests with %s]\n", mutatee);
285 #if !defined(os_windows_test)
286       if ( pdscrdir ) {
287          runScript("ls -lLF %s", mutatee);
288          runScript("%s/ldd_PD %s", pdscrdir, mutatee);
289       }
290 #endif
291    } else {
292       getOutput()->log(LOGINFO, "[Tests with none]\n");
293    }
294
295    getOutput()->log(LOGINFO, "\n");
296    flushOutputLog();
297    flushErrorLog();
298 }
299
300 void printLogOptionHeader(TestInfo *tinfo)
301 {
302    if (!printMutateeLogHeader)
303       return;
304    flushOutputLog();
305    flushErrorLog();
306    // Full test description
307    getOutput()->log(LOGINFO, "test-info: %s\n", tinfo->label);
308    flushOutputLog();
309    flushErrorLog();
310 }
311
312 void printHumanTestHeader(test_data_t &test, char *mutatee, bool useAttach)
313 {
314    flushOutputLog();
315    flushErrorLog();
316    // Test Header
317    getOutput()->log(LOGINFO, "Running: %s", test.name);
318    if ( strcmp(mutatee, "") != 0 )
319    {
320       getOutput()->log(LOGINFO, " with mutatee: %s", mutatee);
321    }
322    if ( useAttach )
323    {
324       getOutput()->log(LOGINFO, " in attach mode");
325    }
326    getOutput()->log(LOGINFO, ".\n");
327
328
329    flushOutputLog();
330    flushErrorLog();
331 }
332
333 struct formatStrings
334 {
335    formatStrings(const std::string& pass, const std::string& skip, const std::string& fail, const std::string& crash, 
336                  const std::string& create, const std::string& attach, const std::string& testNameFormat) :
337       passStr(pass), skipStr(skip), failStr(fail), crashStr(crash), createStr(create), attachStr(attach), testNameFormatStr(testNameFormat) 
338    {
339    }
340    formatStrings() 
341    {
342    }
343   
344    std::string passStr;
345    std::string skipStr;
346    std::string failStr;
347    std::string crashStr;
348    std::string createStr;
349    std::string attachStr;
350    std::string testNameFormatStr;
351 };
352
353 static formatStrings verboseStrings("PASSED\n", "SKIPPED\n", "FAILED\n", "CRASHED\n", "create\tresult: ", "attach\tresult: ", "%s: mutatee: %s create_mode: ");
354 static formatStrings compactStrings(".", "S", "F", "C", "", "", "");
355
356 struct failureInfo
357 {
358    std::string testName;
359    bool createMode;
360    bool wasCrash;
361 };
362
363 // Performs a wildcard string match on Unix-like systems, and a standard string
364 // match on Windows
365 // Returns true for match found, false for no match
366 bool nameMatches(const char *wcname, const char *tomatch) {
367 #if defined(os_windows_test)
368    // Sadly, we can't assume the presence of fnmatch on Windows
369    return (strcmp(wcname, tomatch) == 0);
370 #else
371    // The other systems we support are unix-based and should provide fnmatch (?)
372    return (fnmatch(wcname, tomatch, 0) == 0);
373 #endif
374 }
375
376 // Returns true if the vector mutatee_list contains the string mutatee, and
377 // returns false if it does not
378 bool mutateeListContains(std::vector<char *> mutatee_list, const char *mutatee) {
379    if (NULL == mutatee) {
380       return false;
381    }
382    for (size_t i = 0; i < mutatee_list.size(); i++) {
383       if (nameMatches(mutatee_list[i], mutatee)) {
384          return true;
385       }
386    }
387    return false;
388 }
389
390 // Runs through all the test names in testsn, and enables any matching tests
391 // in testsv.  If any tests matched, returns true.  If there were no matching
392 // tests, returns false
393 // Okay, we don't actually enable any tests here; we just disable tests that
394 // don't match.  All tests start out enabled, and we previously disabled any
395 // that are crashing while we were parsing the resume log.
396 bool testListContains(TestInfo * test,
397                       std::vector<char *> &testsn) {
398    bool match_found = false;
399
400    for (size_t i = 0; i < testsn.size(); i++) {
401       if (nameMatches(testsn[i], test->name))
402          return true;
403    }
404    return false;
405 }
406
407 int numUnreportedTests(RunGroup *group)
408 {
409    int num_unreported = 0;
410
411    for (unsigned i=0; i<group->tests.size(); i++)
412    {
413       if (shouldRunTest(group, group->tests[i]))
414       {
415         num_unreported++;
416       }
417    }
418
419    return num_unreported;
420 }
421
422 void executeTest(ComponentTester *tester,
423                  RunGroup *group, TestInfo *test, 
424                  ParameterDict param)
425 {
426    std::map<std::string, std::string> attrs;
427    TestOutputDriver::getAttributesMap(test, group, attrs);
428
429    std::vector<ParamString*> new_params;
430    int group_num = group->index;
431    int test_num = test->index;
432
433    std::map<std::string, std::string>::iterator i = attrs.begin();
434    for (; i != attrs.end(); i++)
435    {
436       ParamString *pstr = new ParamString((*i).second.c_str());
437       param[(*i).first] = pstr;
438       new_params.push_back(pstr);
439    }
440
441    if (shouldRunTest(group, test))
442    {
443       log_teststart(group_num, test_num, test_setup_rs);
444       test->results[test_setup_rs] = tester->test_setup(test, param);
445       log_testresult(test->results[test_setup_rs]);
446    }
447
448    if (shouldRunTest(group, test))
449    {
450       log_teststart(group_num, test_num, test_execute_rs);
451       test->results[test_execute_rs] = test->mutator->executeTest();
452       log_testresult(test->results[test_execute_rs]);
453    }
454
455    if (shouldRunTest(group, test))
456    {
457       log_teststart(group_num, test_num, test_teardown_rs);
458       test->results[test_teardown_rs] = tester->test_teardown(test, param);
459       log_testresult(test->results[test_teardown_rs]);
460    }
461
462    for (unsigned j=0; j<new_params.size(); j++)
463       delete new_params[j];
464 }
465
466 void disableUnwantedTests(std::vector<RunGroup *> groups)
467 {
468    if (!runCreate || !runAttach || !runRewriter || !runDeserialize) {
469       for (unsigned  i = 0; i < groups.size(); i++) {
470          if (((groups[i]->useAttach == CREATE) && !runCreate) ||
471              ((groups[i]->useAttach == USEATTACH) && !runAttach) ||
472              ((groups[i]->useAttach == DISK) && !runRewriter) ||
473              ((groups[i]->useAttach == DESERIALIZE) && !runDeserialize))
474          {
475             for (unsigned j=0; j<groups[i]->tests.size(); j++)
476                groups[i]->tests[j]->disabled = true;
477             groups[i]->disabled = true;
478          }
479       }
480    }
481    if (!runAllTests)
482    {
483       for (unsigned  i = 0; i < groups.size(); i++) {
484          for (unsigned j=0; j<groups[i]->tests.size(); j++) {
485             if (!testListContains(groups[i]->tests[j], test_list)) {
486                groups[i]->tests[j]->disabled = true;
487             }
488          }
489       }
490    }
491    if (!runAllMutatees)
492    {
493       for (unsigned  i = 0; i < groups.size(); i++) {
494          if (!mutateeListContains(mutatee_list, groups[i]->mutatee))
495          {
496             for (unsigned j=0; j<groups[i]->tests.size(); j++)
497                groups[i]->tests[j]->disabled = true;
498             groups[i]->disabled = true;
499          }
500       }
501    }
502    if (!runAllComps && runAllMutatees)
503    {
504       for (unsigned  i = 0; i < groups.size(); i++) {
505          if (!groups[i]->mod || 
506              (!runDyninst && groups[i]->mod->name == std::string("dyninst")) ||
507              (!runSymtab && groups[i]->mod->name == std::string("symtab")) ||
508              (!runInstruction && groups[i]->mod->name == std::string("instruction")))
509          {
510             groups[i]->disabled = true;
511          }
512       }
513    }
514    else 
515    {
516       for (unsigned  i = 0; i < groups.size(); i++) {
517          if (!groups[i]->mod)
518             groups[i]->disabled = true;
519       }
520    }
521    if (!runAllCompilers && runAllMutatees)
522    {
523       for (unsigned i=0; i<groups.size(); i++)
524       {
525          if (groups[i]->disabled)
526             continue;
527          bool compiler_enabled = false;
528          const char *compiler_name;
529          if (!groups[i]->mutatee || strlen(groups[i]->mutatee) == 0)
530             compiler_name = "nocompiler";
531          else {
532             compiler_name = groups[i]->compiler;
533          }
534          for (unsigned j=0; j<NUM_COMPILERS; j++)
535          {
536             if (strcmp(compiler_name, compilers[j].mutatee_str) == 0)
537             {
538                compiler_enabled = compilers[j].enabled;
539                break;
540             }
541          }
542          if (!compiler_enabled)
543             groups[i]->disabled = true;
544       }
545    }
546    if (optLevel != opt_all && runAllMutatees)
547    {
548       for (unsigned  i = 0; i < groups.size(); i++) {
549          if (groups[i]->disabled)
550             continue;
551          if (!groups[i]->optlevel)
552             continue;
553          if ((optLevel&opt_none) && (strcmp(groups[i]->optlevel, "none")==0))
554             continue;
555          if ((optLevel&opt_low) && (strcmp(groups[i]->optlevel, "low")==0))
556             continue;
557          if ((optLevel&opt_high) && (strcmp(groups[i]->optlevel, "high")==0))
558             continue;
559          if ((optLevel&opt_max) && (strcmp(groups[i]->optlevel, "max")==0))
560             continue;
561          groups[i]->disabled = true;
562       }      
563    }
564 #if defined(cap_32_64_test)
565    if (!runAllABIs && runAllMutatees)
566    {
567       for (unsigned  i = 0; i < groups.size(); i++) 
568       {
569          if (groups[i]->disabled)
570             continue;
571          if (runABI_32 && strcmp(groups[i]->abi, "32") == 0)
572             continue;
573          if (runABI_64 && strcmp(groups[i]->abi, "64") == 0)
574             continue;
575          groups[i]->disabled = true;            
576       }
577    }
578 #endif
579
580    parse_resumelog(groups);
581
582    if (testLimit) {
583       int test_run = 0;
584       for (unsigned  i = 0; i < groups.size(); i++) 
585       {
586          if (groups[i]->disabled)
587             continue;
588          for (unsigned j=0; j<groups[i]->tests.size(); j++) 
589          {
590             if (groups[i]->tests[j]->disabled)
591                continue;
592             if (test_run < testLimit) {
593                test_run++;
594                continue;
595             }
596
597             groups[i]->tests[j]->disabled = true;
598             if (!limitSkippedTests) {
599                limitSkippedTests = true;
600                limitResumeGroup = i;
601                limitResumeTest = j;
602             }
603          }      
604       }
605    }
606
607    for (unsigned  i = 0; i < groups.size(); i++) {
608       if (groups[i]->disabled)
609          continue;
610       groups[i]->disabled = true;
611       if (groups[i]->mod) {
612          for (unsigned j=0; j<groups[i]->tests.size(); j++) {
613             if (!groups[i]->tests[j]->disabled)
614                groups[i]->disabled = false;
615          }
616       }
617    }
618 }
619
620 void setIndexes(std::vector<RunGroup *> groups)
621 {
622    int maxlen = 0;
623    for (unsigned  i = 0; i < groups.size(); i++) {
624       groups[i]->index = i;
625       for (unsigned j=0; j<groups[i]->tests.size(); j++) {
626          groups[i]->tests[j]->index = j;
627          int namelen = strlen(groups[i]->tests[j]->name);
628                  if (namelen > maxlen)
629                          maxlen = namelen;
630       }
631    }
632    TestInfo::setMaxTestNameLength(maxlen);
633 }   
634
635 volatile int dont_optimize = 0;
636 void tests_breakpoint()
637 {
638   dont_optimize++;
639   //Breakpoint here to get a binary with test libraries loaded.
640 }
641
642 void executeGroup(ComponentTester *tester, RunGroup *group, 
643                   ParameterDict param)
644 {
645    test_results_t result;
646    // setupMutatorsForRunGroup creates TestMutator objects and
647    // sets a pointer in the TestInfo object to point to the TestMutator for
648    // each test.
649    int tests_found = setupMutatorsForRunGroup(group);
650    if (tests_found <= 0)
651       return;
652    tests_breakpoint();
653
654    int groupnum = group->index;
655
656    ParamString mutatee_prm(group->mutatee);
657    ParamInt startstate_prm((int) group->state);
658    ParamInt createmode_prm((int) group->useAttach);
659    ParamInt customexecution_prm((int) group->customExecution);
660    ParamInt selfstart_prm((int) group->selfStart);
661    param["pathname"] = &mutatee_prm;
662    param["startState"] = &startstate_prm;
663    param["useAttach"] = &createmode_prm;
664    param["customExecution"] = &customexecution_prm;
665    param["selfStart"] = &selfstart_prm;
666
667    for (unsigned i=0; i<group->tests.size(); i++)
668    {
669       if (shouldRunTest(group, group->tests[i]))
670          testsRun++;
671    }
672
673    log_teststart(groupnum, 0, group_setup_rs);
674    result = tester->group_setup(group, param);
675    log_testresult(result);
676    if (result != PASSED && result != SKIPPED && result != UNKNOWN) {
677       getOutput()->log(LOGERR, "Group setup failed: %s\n", 
678                        tester->getLastErrorMsg().c_str());
679    }
680    if (result != UNKNOWN) {
681       for (unsigned int i = 0; i < group->tests.size(); i++) {
682          group->tests[i]->results[group_setup_rs] = result;
683       }
684    }
685
686    for(unsigned i = 0; i < group->tests.size(); i++)
687    {
688       // Print mutator log header
689           assert(group->tests[i]);
690       printLogOptionHeader(group->tests[i]);
691
692       if (shouldRunTest(group, group->tests[i])) {
693          log_teststart(groupnum, i, test_init_rs);
694          if(group->tests[i]->mutator)
695          {
696             test_results_t setup_res = group->tests[i]->mutator->setup(param);
697             group->tests[i]->results[test_init_rs] = setup_res;
698             if (setup_res != PASSED)
699             {
700                logerror("%s[%d]:  setup failed (%d) for test %s\n", 
701                         FILE__, __LINE__, (int) setup_res, group->tests[i]->name);
702             }
703          }
704          else
705          {
706             logerror("No mutator object found for test: %s\n", group->tests[i]->name);
707             group->tests[i]->results[test_init_rs] = FAILED;
708          }
709          log_testresult(group->tests[i]->results[test_init_rs]);
710       }
711    }
712       
713    for (size_t i = 0; i < group->tests.size(); i++) {
714       executeTest(tester, group, group->tests[i], param);
715    }
716
717    log_teststart(groupnum, 0, group_teardown_rs);
718    result = tester->group_teardown(group, param);
719    log_testresult(result);
720    if (result != PASSED && result != SKIPPED && result != UNKNOWN) {
721       getOutput()->log(LOGERR, "Group teardown failed: %s\n", 
722                        tester->getLastErrorMsg().c_str());
723    }
724    if (result != UNKNOWN) {
725       for (unsigned int i = 0; i < group->tests.size(); i++) {
726          group->tests[i]->results[group_teardown_rs] = result;
727       }
728    }
729
730    for (int i = 0; i < group->tests.size(); i++) {
731       reportTestResult(group, group->tests[i]);
732    }
733 }
734
735 #define is_int(x) (x >= '0' && x <= '9')
736 bool strint_lt(const char *lv, const char *rv)
737 {
738    int i = 0;
739    while (lv[i] != '\0' && rv[i] != '\0')
740    {
741       if (lv[i] == rv[i]) {
742          i++;
743          continue;
744       }
745
746       bool lint = is_int(lv[i]);
747       bool rint = is_int(rv[i]);
748
749       if (lint && !rint)
750          return true;
751       else if (!lint && rint)
752          return false;
753       else if (!lint && !rint)
754          return (lv[i] < rv[i]);
755       else {
756          return atoi(lv+i) < atoi(rv+i);
757       }
758    }
759    if (lv[i] == '\0' && rv[i] != '\0')
760       return true;
761    return false;
762 }
763
764 struct groupcmp 
765 {
766    bool operator()(const RunGroup* lv, const RunGroup* rv)
767    {
768       if (!lv->mod)
769          return false;
770       if (!rv->mod)
771          return true;
772       if (lv->useAttach == DESERIALIZE && rv->useAttach != DESERIALIZE)
773          return false;
774       if (rv->useAttach == DESERIALIZE && lv->useAttach != DESERIALIZE)
775          return true;
776       if (lv->mod == rv->mod)
777       {
778          return strint_lt(lv->mutatee, rv->mutatee);
779       }
780       return std::string(lv->mod->name).compare(rv->mod->name) == -1;
781    }
782 };
783
784 struct testcmp 
785 {
786    bool operator()(const TestInfo* lv, const TestInfo* rv)
787    {
788       return strint_lt(lv->name, rv->name);
789    }
790 };
791
792 void initModuleIfNecessary(RunGroup *group, std::vector<RunGroup *> &groups, 
793                            ParameterDict &params)
794 {
795    bool initModule = false;
796    if (group->disabled)
797       return;
798    for (unsigned j=0; j<group->tests.size(); j++)
799    {
800       if (group->mod && !group->mod->setupRun() && !group->tests[j]->disabled)
801          initModule = true;
802    }
803    if (!initModule)
804       return;
805
806    log_teststart(group->index, 0, program_setup_rs);
807    test_results_t result = group->mod->tester->program_setup(params);
808    log_testresult(result);
809
810    group->mod->setSetupRun(true);
811
812    for (unsigned i=0; i<groups.size(); i++) {
813       if (groups[i]->disabled || groups[i]->mod != group->mod)
814          continue;
815       for (unsigned j=0; j<groups[i]->tests.size(); j++) {
816          if (groups[i]->tests[j]->disabled)
817             continue;
818          groups[i]->tests[j]->results[program_setup_rs] = result;
819          if (result != PASSED)
820             reportTestResult(groups[i], groups[i]->tests[j]);
821       }
822    }
823 }
824          
825
826 void startAllTests(std::vector<RunGroup *> &groups,
827                    std::vector<char *> mutatee_list)
828 {
829    // Begin setting up test parameters
830    ParameterDict param;
831    unsigned i;
832    bool aborted_group = false;
833
834    ParamString logfile_p(logfilename);
835    ParamInt verbose_p((int) !quietFormat);
836    ParamInt usehuman_p((int) useHumanLog);
837    ParamInt printlabels_p((int) printLabels);
838    ParamInt debugprint_p((int) debugPrint);
839    ParamInt noclean_p((int) noclean);
840    ParamString humanname_p(humanlog_name);
841
842    param["logfilename"] = &logfile_p;
843    param["verbose"] = &verbose_p;
844    param["usehumanlog"] = &usehuman_p;
845    param["humanlogname"] = &humanname_p;
846    param["printlabels"] = &printlabels_p;
847    param["debugPrint"] = &debugprint_p;
848    param["noClean"] = &noclean_p;
849
850    // Print Test Log Header
851    getOutput()->log(LOGINFO, "Commencing test(s) ...\n");
852 #if !defined(os_windows_test)
853    if ( pdscrdir )
854    {
855       runScript("date");
856       runScript("uname -a");
857    }
858    getOutput()->log(LOGINFO, "TESTDIR=%s\n", getenv("PWD"));
859 #else
860         char* cwd = _getcwd(NULL, 0);
861         if(cwd) {
862            getOutput()->log(LOGINFO, "TESTDIR=%s\n", cwd);
863         } else {
864                 getOutput()->log(LOGERR, "Couldn't get working directory!\n");
865         }
866         free(cwd);
867 #endif
868    // Sets the disable flag on groups and tests that weren't selected by
869    // options or have alread been passed according to the resumelog
870    std::sort(groups.begin(), groups.end(), groupcmp());
871    for (i=0; i<groups.size(); i++)
872       std::sort(groups[i]->tests.begin(), groups[i]->tests.end(), testcmp());
873
874    setIndexes(groups);
875    disableUnwantedTests(groups);
876
877    std::vector<Module *> modules;
878    Module::getAllModules(modules);
879
880    measureStart();
881
882    for (i = 0; i < groups.size(); i++) {
883       if (groups[i]->disabled)
884          continue;
885
886       //If we fail then have the log resume us at this group
887       log_resumepoint(i, 0);
888
889       initModuleIfNecessary(groups[i], groups, param);
890
891       // Print mutatee (run group) header
892       printLogMutateeHeader(groups[i]->mutatee);
893
894       int before_group = numUnreportedTests(groups[i]);
895       if (!before_group)
896          continue;
897
898       executeGroup(groups[i]->mod->tester, groups[i], param);
899       int after_group = numUnreportedTests(groups[i]);
900    
901       if (after_group) {
902          if (before_group == after_group) {
903             //This should be uncommon.  We made no forward progress
904             // running tests in the group, and we have tests that didn't run.
905             // Mark the group as failed, as we don't want to just spin here.
906             for (unsigned j=0; j<groups[i]->tests.size(); j++) {
907                if (!shouldRunTest(groups[i], groups[i]->tests[j]))
908                   continue;
909                groups[i]->tests[j]->results[group_teardown_rs] = FAILED;
910                reportTestResult(groups[i], groups[i]->tests[j]);
911             }
912          }
913          else {
914             aborted_group = true;
915             break;
916          }
917       }
918    }
919
920    unsigned final_group = i;
921    
922    for (i = 0; i < final_group; i++) {
923      Module *mod = groups[i]->mod;
924      if (!mod || !mod->isInitialized() || groups[i]->disabled)
925        continue;
926      
927      log_teststart(groups[i]->index, 0, program_teardown_rs);
928      test_results_t result = mod->tester->program_teardown(param);
929      log_testresult(result);
930
931      for (unsigned j=0; j < groups[i]->tests.size(); j++)
932      {
933        if (!groups[i]->tests[j]->disabled) {
934           groups[i]->tests[j]->results[program_teardown_rs] = result;
935        }
936        reportTestResult(groups[i], groups[i]->tests[j]);
937      }
938      mod->setInitialized(false);
939    }
940
941    if (!aborted_group) {
942      if (limitSkippedTests) {
943        log_resumepoint(limitResumeGroup, limitResumeTest);
944      } else {
945        log_clear();
946      }
947    }
948       
949    measureEnd();
950
951    cleanPIDFile();
952    return;
953 } // startAllTests()
954
955 void DebugPause() {
956    getOutput()->log(STDERR, "Waiting for attach by debugger\n");
957 #if defined(os_windows_test)
958    DebugBreak();
959 #else
960    static volatile int set_me = 0;
961    while (!set_me)
962      P_sleep(1);
963 #endif
964 }
965
966 // Find the paradyn scripts directory.  It can be specified in the environment
967 // variable 'PDSCRDIR', or we pick up a default location for the UW and UMD
968 // sites, or we generate a default based on the DYNINST_ROOT directory, or
969 // we use a default '../../../scripts'.
970 void setPDScriptDir(bool skip_warning)
971 {
972    pdscrdir = getenv("PDSCRDIR");
973    if ( pdscrdir == NULL )
974    {
975 #if !defined(os_windows_test)
976       // Environment variable not set, try default wisc/umd directories
977       DIR *dir;
978       dir = opendir(uw_pdscrdir);
979       if ( dir != NULL ) {
980          closedir(dir);
981          pdscrdir = uw_pdscrdir;
982          return;
983       }
984       dir = opendir(umd_pdscrdir);
985       if ( dir != NULL ) {
986          closedir(dir);
987          pdscrdir = umd_pdscrdir;
988          return;
989       }
990
991       // Environment variable not set and default UW/UMD directories missing.
992       // Derive default from DYNINST_ROOT
993       char *basedir = getenv("DYNINST_ROOT");
994       if (NULL == basedir) {
995          // DYNINST_ROOT not set.  Print a warning, and default it to "../../.."
996          if (!skip_warning) {
997             getOutput()->log(STDERR, "** WARNING: DYNINST_ROOT not set.  Please set the environment variable\n");
998             getOutput()->log(STDERR, "\tto the path for the top of the Dyninst library installation.\n");
999             getOutput()->log(STDERR, "\tUsing default: '../../..'\n");
1000          }
1001          basedir = "../../..";
1002       }
1003       int basedir_len = strlen(basedir);
1004       int pdscrdir_len = basedir_len + strlen("/scripts") + 1;
1005       // BUG This allocated array lasts for the lifetime of the program, so it's
1006       // currently not worth worrying about freeing the memory.
1007       pdscrdir = new char[pdscrdir_len];
1008       strncpy(pdscrdir, basedir, basedir_len + 1);
1009       strcat(pdscrdir, "/scripts");
1010
1011       dir = opendir(pdscrdir);
1012       if (!dir) {
1013          pdscrdir = NULL;
1014       } else {
1015          closedir(dir);
1016       }
1017
1018 #endif
1019    }
1020 }
1021    
1022 void updateSearchPaths(const char *filename) {
1023 #if !defined(os_windows_test)
1024    // First, find the directory we reside in
1025
1026     bool include_cwd_always = false;
1027 #if defined(os_aix_test)
1028     // AIX strips a ./ from the start of argv[0], so
1029     // we will execute ./test_driver and see test_driver
1030
1031     include_cwd_always = true;
1032 #endif
1033
1034    char *execpath;
1035    char pathname[PATH_MAX];
1036    getcwd(pathname, PATH_MAX);
1037
1038    if (filename[0] == '/') {
1039       // If it begins with a slash, it's an absolute path
1040       execpath = strdup(filename);
1041    } else if (strchr(filename,'/') || include_cwd_always) {
1042       // If it contains slashes, it's a relative path
1043       char *filename_copy = strdup(filename);
1044       
1045       execpath = (char *) ::malloc(strlen(pathname) + strlen(filename_copy) + 2);
1046       strcpy(execpath,pathname);
1047       strcat(execpath,"/");
1048       strcat(execpath,filename_copy);
1049       ::free(filename_copy);
1050    } else {
1051       // If it's just a name, it was found in PATH. 
1052       // Add current directory to the search path
1053       const char *pathenv = getenv("PATH");
1054       char *newpath = (char *) malloc (strlen(pathenv)+3);
1055       strcat(newpath, pathenv);
1056       strcat(newpath, ":.");
1057       execpath = searchPath(newpath, filename);
1058       if(execpath == NULL) {
1059          //  Not found in PATH - we'll assume it should be in CWD
1060          return;
1061       }
1062    }
1063
1064    *strrchr(execpath, '/') = '\0';
1065    // Now update PATH and LD_LIBRARY_PATH/LIBPATH
1066
1067    char *envCopy;
1068
1069    char *envPath = getenv("PATH");
1070    envCopy = (char *) ::malloc(((envPath && strlen(envPath)) ? strlen(envPath) + 1 : 0) + strlen(execpath) + 6);
1071    strcpy(envCopy, "PATH=");
1072    if (envPath && strlen(envPath)) {
1073       strcat(envCopy, envPath);
1074       strcat(envCopy, ":");
1075    }
1076    strcat(envCopy, execpath);
1077    assert(!putenv(envCopy));
1078     
1079    char *envLibPath;
1080 #if defined(os_aix_test)
1081    envLibPath = getenv("LIBPATH");
1082 #else
1083    envLibPath = getenv("LD_LIBRARY_PATH");
1084 #endif
1085     
1086    envCopy = (char *) ::malloc(((envLibPath && strlen(envLibPath)) ? strlen(envLibPath) + 1 : 0) + strlen(execpath) + 17);
1087 #if defined(os_aix_test)
1088    strcpy(envCopy, "LIBPATH=");
1089 #else
1090    strcpy(envCopy, "LD_LIBRARY_PATH=");
1091 #endif
1092    if (envLibPath && strlen(envLibPath)) {
1093       strcat(envCopy, envLibPath);
1094       strcat(envCopy, ":");
1095    }
1096    strcat(envCopy, execpath);
1097    assert(!putenv(envCopy));
1098
1099    //fprintf(stderr, "%s[%d]:  set LD_LIBRARY_PATH to %s\n", FILE__, __LINE__, getenv("LD_LIBRARY_PATH"));
1100    ::free(execpath);
1101 #endif
1102 }
1103
1104 bool testsRemain(std::vector<RunGroup *> &groups)
1105 {
1106    for (unsigned  i = 0; i < groups.size(); i++) {
1107       if (groups[i]->disabled)
1108          continue;
1109       for (unsigned j=0; j<groups[i]->tests.size(); j++) {
1110          if (shouldRunTest(groups[i], groups[i]->tests[j]))
1111             return true;
1112       }
1113    }
1114    return false;
1115 }
1116
1117 int main(int argc, char *argv[]) {
1118    updateSearchPaths(argv[0]);
1119
1120    setOutput(new StdOutputDriver(NULL));
1121    
1122    int result = parseArgs(argc, argv);
1123    if (result)
1124       exit(result);
1125
1126    // Fill in tests vector with lists of test to run
1127    std::vector<RunGroup *> tests;
1128    initialize_mutatees(tests);  
1129
1130    result = setupLogs();
1131    if (result)
1132       exit(result);
1133
1134    setupProcessGroup();
1135
1136    // Set the resume log name
1137    if ( getenv("RESUMELOG") ) {
1138       resumelog_name = getenv("RESUMELOG");
1139    }
1140
1141    if ( shouldDebugBreak ) {
1142       DebugPause();
1143    }
1144
1145    startAllTests(tests, mutatee_list);
1146
1147    if ((outlog != NULL) && (outlog != stdout)) {
1148       fclose(outlog);
1149    }
1150    fflush(stdout);
1151
1152    if (!testsRemain(tests) && !limitSkippedTests)
1153       return NOTESTS;
1154    return 0;
1155 }
1156
1157 int setupLogs()
1158 {
1159    // Set the script dir if we require scripts
1160    if ( enableLogging )
1161    {
1162      setPDScriptDir(true);
1163    }
1164
1165    // Set up the logging file..
1166    if ((logfilename != NULL) && (strcmp(logfilename, "-") != 0)) {
1167       outlog = fopen(logfilename, "a");
1168       if (NULL == outlog) {
1169          getOutput()->log(STDERR, "Error opening log file '%s'\n", logfilename);
1170          return NOTESTS;
1171       }
1172       errlog = outlog;
1173    } else {
1174       outlog = stdout;
1175       errlog = stderr;
1176    }
1177    setOutputLog(outlog);
1178    setErrorLog(errlog);
1179    setOutputLogFilename(logfilename);
1180    setErrorLogFilename(logfilename);
1181
1182    if ((logfilename != NULL) && (strcmp(logfilename, "-") != 0)) {
1183       getOutput()->redirectStream(LOGINFO, logfilename);
1184       getOutput()->redirectStream(LOGERR, logfilename);
1185    }
1186    if (useHumanLog) {
1187       getOutput()->redirectStream(HUMAN, humanlog_name);
1188    } else {
1189       getOutput()->redirectStream(HUMAN, NULL);
1190    }
1191    return 0;
1192 }
1193
1194 int parseArgs(int argc, char *argv[])
1195 {
1196    for (unsigned i=1; i < argc; i++ )
1197    {
1198
1199       if (strncmp(argv[i], "-v+", 3) == 0)
1200          errorPrint++;
1201       if (strncmp(argv[i], "-v++", 4) == 0)
1202          errorPrint++;
1203       if (strncmp(argv[i], "-verbose", 2) == 0)
1204          debugPrint = 1;
1205       else if (strcmp(argv[i], "-q") == 0)
1206       {
1207          getOutput()->log(STDERR, "[%s:%u] - Quiet format not yet enabled\n");
1208          quietFormat = true;
1209       }
1210       else if ( strcmp(argv[i], "-skipTo")==0)
1211       {
1212          // skip to test i+1
1213          skipToTest = atoi(argv[++i]);
1214       }
1215       else if ( strcmp(argv[i], "-log")==0)
1216       {
1217          logfilename = "-";
1218          if ((i + 1) < argc) {
1219             if ((argv[i + 1][0] != '-') || (argv[i + 1][1] == '\0')) {
1220                i += 1;
1221                logfilename = argv[i];
1222             }
1223          }
1224       }
1225       else if ( strcmp(argv[i], "-logfile") == 0) {
1226          getOutput()->log(STDERR, "WARNING: -logfile is a deprecated option; use -log instead\n");
1227          /* Store the log file name */
1228          if ((i + 1) >= argc) {
1229             getOutput()->log(STDERR, "Missing log file name\n");
1230             return NOTESTS;
1231          }
1232          i += 1;
1233          logfilename = argv[i];
1234       }
1235       else if ( strcmp(argv[i], "-debug")==0)
1236       {
1237          shouldDebugBreak = true;
1238       }
1239       else if ( strcmp(argv[i], "-test") == 0)
1240       {
1241          char *tests;
1242          char *name;
1243
1244          runAllTests = false;
1245          if ( i + 1 >= argc )
1246          {
1247             getOutput()->log(STDERR, "-test must be followed by a testname\n");
1248             return NOTESTS;
1249          }
1250
1251          tests = strdup(argv[++i]);
1252
1253          name = strtok(tests, ","); // FIXME Use strtok_r()
1254          test_list.push_back(name);
1255          while ( name != NULL )
1256          {
1257             name = strtok(NULL, ",");
1258             if ( name != NULL )
1259             {
1260                test_list.push_back(name);
1261             }
1262          }
1263       }
1264       else if ( strcmp(argv[i], "-mutatee") == 0)
1265       {
1266          char *mutatees;
1267          char *name;
1268
1269          runAllMutatees = false;
1270          if ( i + 1 >= argc )
1271          {
1272             getOutput()->log(STDERR, "-mutatee must be followed by mutatee names\n");
1273             return NOTESTS;
1274          }
1275
1276          mutatees = strdup(argv[++i]);
1277
1278          name = strtok(mutatees, ","); // FIXME Use strtok_r()
1279          if (NULL == name) {
1280             // Special handling for a "" mutatee specified on the command line
1281             mutatee_list.push_back("");
1282          } else {
1283             mutatee_list.push_back(name);
1284          }
1285          while ( name != NULL )
1286          {
1287             name = strtok(NULL, ","); // FIXME Use strtok_r()
1288             if ( name != NULL )
1289             {
1290                mutatee_list.push_back(name);
1291             }
1292          }
1293       }
1294       // TODO: Remove the -run option, it is replaced by the -test option
1295       else if ( strcmp(argv[i], "-run") == 0)
1296       {
1297          unsigned int j;
1298          runAllTests = false;
1299          for ( j = i+1; j < argc; j++ )
1300          {
1301             if ( argv[j][0] == '-' )
1302             {
1303                // end of test list
1304                break;
1305             }
1306             else
1307             {
1308                test_list.push_back(argv[j]);
1309             }
1310          }
1311          i = j - 1;
1312       }
1313       // TODO -attach and -create are DyninstAPI specific
1314       else if ( strcmp(argv[i], "-attach") == 0 )
1315       {
1316          if (runDefaultStarts)
1317          {
1318             runCreate = false;
1319             runRewriter = false;
1320          }
1321          runAttach = true;
1322          runDefaultStarts = false;
1323       }
1324       else if ( strcmp(argv[i], "-create") == 0 )
1325       {
1326          if (runDefaultStarts)
1327          {
1328             runAttach = false;
1329             runRewriter = false;
1330          }
1331          runCreate = true;
1332          runDefaultStarts = false;
1333       }
1334       else if ( strcmp(argv[i], "-rewriter") == 0 )
1335       {
1336          if (runDefaultStarts)
1337          {
1338             runCreate = false;
1339             runAttach = false;
1340          }
1341          runRewriter = true;
1342          runDefaultStarts = false;
1343       }
1344       else if ( strcmp(argv[i], "-noclean") == 0 )
1345       {
1346          noclean = true;
1347       }
1348       else if ( strcmp(argv[i], "-serialize") == 0 )
1349       {
1350          runDefaultStarts = false;
1351          runCreate = true;
1352          runAttach = false;
1353          runDeserialize = true;
1354       }
1355       else if (strcmp(argv[i], "-allmode") == 0)
1356       {
1357          runCreate = true;
1358          runAttach = true;
1359          runDeserialize = true;
1360          runRewriter = false;
1361          runDefaultStarts = false;
1362       }
1363       else if (strcmp(argv[i], "-all") == 0)
1364       {
1365          runCreate = true;
1366          runAttach = true;
1367          runDeserialize = true;
1368          runRewriter = true;
1369          runAllCompilers = true;
1370          runAllComps = true;
1371       }
1372       else if (strcmp(argv[i], "-full") == 0)
1373       {
1374          //Like -all, but with full optimization levels
1375          runCreate = true;
1376          runAttach = true;
1377          runDeserialize = true;
1378          runRewriter = true;
1379          runAllCompilers = true;
1380          runAllComps = true;
1381          optLevel = opt_all;
1382       }
1383       else if ( strcmp(argv[i], "-dyninst") == 0)
1384       {
1385          runDyninst = true;
1386          runAllComps = false;
1387       }
1388       else if ( strcmp(argv[i], "-symtab") == 0)
1389       {
1390          runSymtab = true;
1391          runAllComps = false;
1392       }
1393       else if (strcmp(argv[i], "-instruction") == 0)
1394       {
1395         runInstruction = true;
1396         runAllComps = false;
1397       }
1398       else if (strcmp(argv[i], "-allcomp") == 0)
1399       {
1400          runSymtab = true;
1401          runDyninst = true;
1402          runInstruction = true;
1403          runAllComps = true;
1404       }
1405       else if (strcmp(argv[i], "-max") == 0)
1406       {
1407          if (runDefaultOpts)
1408             optLevel = 0;
1409          runDefaultOpts = false;
1410          optLevel |= opt_max;
1411       }
1412       else if (strcmp(argv[i], "-high") == 0)
1413       {
1414          if (runDefaultOpts)
1415             optLevel = 0;
1416          runDefaultOpts = false;
1417          optLevel |= opt_high;
1418       }
1419       else if (strcmp(argv[i], "-low") == 0)
1420       {
1421          if (runDefaultOpts)
1422             optLevel = 0;
1423          runDefaultOpts = false;
1424          optLevel |= opt_low;
1425       }
1426       else if (strcmp(argv[i], "-none") == 0)
1427       {
1428          if (runDefaultOpts)
1429             optLevel = 0;
1430          runDefaultOpts = false;
1431          optLevel |= opt_none;
1432       }
1433       else if (strcmp(argv[i], "-allopt") == 0)
1434       {
1435          runDefaultOpts = false;
1436          optLevel |= opt_all;
1437       }
1438       else if (strcmp(argv[i], "-32") == 0)
1439       {
1440          runAllABIs = false;
1441          runABI_32 = true;
1442       }
1443       else if (strcmp(argv[i], "-64") == 0)
1444       {
1445          runAllABIs = false;
1446          runABI_64 = true;
1447       }
1448       else if ((strcmp(argv[i], "-cpumem") == 0) ||
1449                (strcmp(argv[i], "-memcpu") == 0))
1450       {
1451          measureMEMCPU = true;
1452          if (i+1 < argc)
1453          {
1454             if (argv[i+1][0] != '-')
1455             {
1456                i++;
1457                measureFileName = argv[i];
1458             }
1459             else if (argv[i+1][1] == '\0')
1460             {
1461                i++;
1462                measureFileName = "-";
1463             }
1464          }
1465       }
1466       else if ((strcmp(argv[i], "-enable-resume") == 0) ||
1467                (strcmp(argv[i], "-use-resume") == 0)) {
1468          enableResumeLog();
1469       } else if ( strcmp(argv[i], "-header") == 0 ) {
1470          printMutateeLogHeader = true;
1471       } else if ( strcmp(argv[i], "-limit") == 0 ) {
1472          if ( i + 1 >= argc ) {
1473             getOutput()->log(STDERR, "-limit must be followed by an integer limit\n");
1474             return NOTESTS;
1475          }
1476          testLimit = strtol(argv[++i], NULL, 10);
1477          if ((0 == testLimit) && (EINVAL == errno)) {
1478             getOutput()->log(STDERR, "-limit must be followed by an integer limit\n");
1479             return NOTESTS;
1480          }
1481       }
1482       else if ( strcmp(argv[i], "-humanlog") == 0 ) {
1483          // Verify that the following argument exists
1484          if ( i + 1 >= argc )
1485          {
1486             getOutput()->log(STDERR, "-humanlog must by followed by a filename\n");
1487             return NOTESTS;
1488          }
1489
1490          useHumanLog = true;
1491          humanlog_name = argv[++i];
1492       } else if (strcmp(argv[i], "-under-runtests") == 0) {
1493          called_from_runTests = true;
1494       }
1495       else if ((strcmp(argv[i], "-help") == 0) ||
1496                (strcmp(argv[i], "--help") == 0)) {
1497          print_help();
1498          exit(-5);
1499       }
1500       else if (strcmp(argv[i], "-pidfile") == 0) {
1501          char *pidFilename = NULL;
1502          if (i + 1 >= argc) {
1503             getOutput()->log(STDERR, "-pidfile must be followed by a filename\n");
1504             return NOTESTS;
1505          }
1506          i += 1;
1507          pidFilename = argv[i];
1508          setPIDFilename(pidFilename);
1509       }
1510       else if (strcmp(argv[i], "-dboutput") == 0) {
1511          char * failedOutputFile = NULL;
1512          //check if a failed output file is specified
1513          if ((i + 1) < argc) {
1514             if (argv[i+1][0] != '-' || argv[i+1][1] == '\0') {
1515                //either it doesn't start with - or it's exactly -
1516                i++;
1517                failedOutputFile = argv[i];
1518             }
1519          }
1520
1521          if (NULL == failedOutputFile) {
1522             //TODO insert proper value
1523             time_t rawtime;
1524             struct tm * timeinfo = (tm *)malloc(sizeof(struct tm));
1525
1526             time(&rawtime);
1527             timeinfo = localtime(&rawtime);
1528
1529             failedOutputFile = (char*)malloc(sizeof(char) * strlen("sql_dblog-xxxx-xx-xx0"));
1530             if (failedOutputFile == NULL) {
1531                fprintf(stderr, "[%s:%u] - Out of memory!\n", __FILE__, __LINE__);
1532                // TODO Handle error;
1533             }
1534             sprintf(failedOutputFile, "sql_dblog-%4d-%02d-%02d",
1535                     timeinfo->tm_year + 1900, timeinfo->tm_mon + 1, timeinfo->tm_mday);
1536
1537             getOutput()->log(STDERR, "No 'SQL log file' found, using default %s\n", failedOutputFile);
1538          }
1539
1540          std::string s_failedOutputFile (failedOutputFile);
1541          TestOutputDriver *newoutput = loadOutputDriver("DatabaseOutputDriver", &s_failedOutputFile);
1542
1543          //make sure it loaded correctly before replacing default output
1544          if (newoutput != NULL) {
1545             setOutput(newoutput);
1546          }
1547       }
1548       else if (strcmp(argv[i], "-allcompilers") == 0)
1549       {
1550          runDefaultCompilers = false;
1551          runAllCompilers = true;
1552       }
1553       else
1554       {
1555          bool found_compiler_option = false;
1556          for (unsigned j=0; j<NUM_COMPILERS; j++)
1557          {
1558             if (runDefaultCompilers)
1559             {
1560                //The first time we see a compiler option, disable the
1561                // ones that are default on.
1562                compilers[j].enabled = false;
1563             }
1564             if (strcmp(argv[i], compilers[j].option) == 0)
1565             {
1566                compilers[j].enabled = true;
1567                found_compiler_option = true;
1568             }
1569          }
1570          runDefaultCompilers = false;
1571
1572          if (!found_compiler_option) {
1573             getOutput()->log(STDOUT, "Unrecognized option: '%s'\n", argv[i]);
1574             return NOTESTS;
1575          }
1576       }
1577    }
1578    return 0;
1579 }
1580