Imported Upstream version 2.8.12.2
[platform/upstream/cmake.git] / Source / cmCTest.cxx
1 /*============================================================================
2   CMake - Cross Platform Makefile Generator
3   Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
4
5   Distributed under the OSI-approved BSD License (the "License");
6   see accompanying file Copyright.txt for details.
7
8   This software is distributed WITHOUT ANY WARRANTY; without even the
9   implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
10   See the License for more information.
11 ============================================================================*/
12 #include "cm_curl.h"
13
14 #include "cmCTest.h"
15 #include "cmake.h"
16 #include "cmMakefile.h"
17 #include "cmLocalGenerator.h"
18 #include "cmGlobalGenerator.h"
19 #include <cmsys/Base64.h>
20 #include <cmsys/Directory.hxx>
21 #include <cmsys/SystemInformation.hxx>
22 #include "cmDynamicLoader.h"
23 #include "cmGeneratedFileStream.h"
24 #include "cmXMLSafe.h"
25 #include "cmVersionMacros.h"
26 #include "cmCTestCommand.h"
27 #include "cmCTestStartCommand.h"
28
29 #include "cmCTestBuildHandler.h"
30 #include "cmCTestBuildAndTestHandler.h"
31 #include "cmCTestConfigureHandler.h"
32 #include "cmCTestCoverageHandler.h"
33 #include "cmCTestMemCheckHandler.h"
34 #include "cmCTestScriptHandler.h"
35 #include "cmCTestSubmitHandler.h"
36 #include "cmCTestTestHandler.h"
37 #include "cmCTestUpdateHandler.h"
38 #include "cmCTestUploadHandler.h"
39
40 #include "cmVersion.h"
41
42 #include <cmsys/RegularExpression.hxx>
43 #include <cmsys/Process.h>
44 #include <cmsys/Glob.hxx>
45
46 #include <stdlib.h>
47 #include <math.h>
48 #include <float.h>
49 #include <ctype.h>
50
51 #include <cmsys/auto_ptr.hxx>
52
53 #include <cm_zlib.h>
54 #include <cmsys/Base64.h>
55
56 #if defined(__BEOS__)
57 #include <be/kernel/OS.h>   /* disable_debugger() API. */
58 #endif
59
60 #if defined(__HAIKU__)
61 #include <os/kernel/OS.h>   /* disable_debugger() API. */
62 #endif
63
64
65 #define DEBUGOUT std::cout << __LINE__ << " "; std::cout
66 #define DEBUGERR std::cerr << __LINE__ << " "; std::cerr
67
68 //----------------------------------------------------------------------
69 struct tm* cmCTest::GetNightlyTime(std::string str,
70                                    bool tomorrowtag)
71 {
72   struct tm* lctime;
73   time_t tctime = time(0);
74   lctime = gmtime(&tctime);
75   char buf[1024];
76   // add todays year day and month to the time in str because
77   // curl_getdate no longer assumes the day is today
78   sprintf(buf, "%d%02d%02d %s",
79           lctime->tm_year+1900,
80           lctime->tm_mon +1,
81           lctime->tm_mday,
82           str.c_str());
83   cmCTestLog(this, OUTPUT, "Determine Nightly Start Time" << std::endl
84     << "   Specified time: " << str.c_str() << std::endl);
85   //Convert the nightly start time to seconds. Since we are
86   //providing only a time and a timezone, the current date of
87   //the local machine is assumed. Consequently, nightlySeconds
88   //is the time at which the nightly dashboard was opened or
89   //will be opened on the date of the current client machine.
90   //As such, this time may be in the past or in the future.
91   time_t ntime = curl_getdate(buf, &tctime);
92   cmCTestLog(this, DEBUG, "   Get curl time: " << ntime << std::endl);
93   tctime = time(0);
94   cmCTestLog(this, DEBUG, "   Get the current time: " << tctime << std::endl);
95
96   const int dayLength = 24 * 60 * 60;
97   cmCTestLog(this, DEBUG, "Seconds: " << tctime << std::endl);
98   while ( ntime > tctime )
99     {
100     // If nightlySeconds is in the past, this is the current
101     // open dashboard, then return nightlySeconds.  If
102     // nightlySeconds is in the future, this is the next
103     // dashboard to be opened, so subtract 24 hours to get the
104     // time of the current open dashboard
105     ntime -= dayLength;
106     cmCTestLog(this, DEBUG, "Pick yesterday" << std::endl);
107     cmCTestLog(this, DEBUG, "   Future time, subtract day: " << ntime
108       << std::endl);
109     }
110   while ( tctime > (ntime + dayLength) )
111     {
112     ntime += dayLength;
113     cmCTestLog(this, DEBUG, "   Past time, add day: " << ntime << std::endl);
114     }
115   cmCTestLog(this, DEBUG, "nightlySeconds: " << ntime << std::endl);
116   cmCTestLog(this, DEBUG, "   Current time: " << tctime
117     << " Nightly time: " << ntime << std::endl);
118   if ( tomorrowtag )
119     {
120     cmCTestLog(this, OUTPUT, "   Use future tag, Add a day" << std::endl);
121     ntime += dayLength;
122     }
123   lctime = gmtime(&ntime);
124   return lctime;
125 }
126
127 //----------------------------------------------------------------------
128 std::string cmCTest::CleanString(const std::string& str)
129 {
130   std::string::size_type spos = str.find_first_not_of(" \n\t\r\f\v");
131   std::string::size_type epos = str.find_last_not_of(" \n\t\r\f\v");
132   if ( spos == str.npos )
133     {
134     return std::string();
135     }
136   if ( epos != str.npos )
137     {
138     epos = epos - spos + 1;
139     }
140   return str.substr(spos, epos);
141 }
142
143 //----------------------------------------------------------------------
144 std::string cmCTest::CurrentTime()
145 {
146   time_t currenttime = time(0);
147   struct tm* t = localtime(&currenttime);
148   //return ::CleanString(ctime(&currenttime));
149   char current_time[1024];
150   if ( this->ShortDateFormat )
151     {
152     strftime(current_time, 1000, "%b %d %H:%M %Z", t);
153     }
154   else
155     {
156     strftime(current_time, 1000, "%a %b %d %H:%M:%S %Z %Y", t);
157     }
158   cmCTestLog(this, DEBUG, "   Current_Time: " << current_time << std::endl);
159   return cmXMLSafe(cmCTest::CleanString(current_time)).str();
160 }
161
162 //----------------------------------------------------------------------
163 std::string cmCTest::GetCostDataFile()
164 {
165   std::string fname = this->GetCTestConfiguration("CostDataFile");
166   if(fname == "")
167     {
168     fname= this->GetBinaryDir() + "/Testing/Temporary/CTestCostData.txt";
169     }
170   return fname;
171 }
172
173 #ifdef CMAKE_BUILD_WITH_CMAKE
174 //----------------------------------------------------------------------------
175 static size_t
176 HTTPResponseCallback(void *ptr, size_t size, size_t nmemb, void *data)
177 {
178   int realsize = (int)(size * nmemb);
179
180   std::string *response
181     = static_cast<std::string*>(data);
182   const char* chPtr = static_cast<char*>(ptr);
183   *response += chPtr;
184
185   return realsize;
186 }
187
188 //----------------------------------------------------------------------------
189 int cmCTest::HTTPRequest(std::string url, HTTPMethod method,
190                                        std::string& response,
191                                        std::string fields,
192                                        std::string putFile, int timeout)
193 {
194   CURL* curl;
195   FILE* file;
196   ::curl_global_init(CURL_GLOBAL_ALL);
197   curl = ::curl_easy_init();
198
199   //set request options based on method
200   switch(method)
201     {
202     case cmCTest::HTTP_POST:
203       ::curl_easy_setopt(curl, CURLOPT_POST, 1);
204       ::curl_easy_setopt(curl, CURLOPT_POSTFIELDS, fields.c_str());
205       break;
206     case cmCTest::HTTP_PUT:
207       if(!cmSystemTools::FileExists(putFile.c_str()))
208         {
209         response = "Error: File ";
210         response += putFile + " does not exist.\n";
211         return -1;
212         }
213       ::curl_easy_setopt(curl, CURLOPT_PUT, 1);
214       file = ::fopen(putFile.c_str(), "rb");
215       ::curl_easy_setopt(curl, CURLOPT_INFILE, file);
216       //fall through to append GET fields
217     case cmCTest::HTTP_GET:
218       if(fields.size())
219         {
220         url += "?" + fields;
221         }
222       break;
223     default:
224       break;
225     }
226
227   ::curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
228   ::curl_easy_setopt(curl, CURLOPT_TIMEOUT, timeout);
229   ::curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1);
230
231   //set response options
232   ::curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, HTTPResponseCallback);
233   ::curl_easy_setopt(curl, CURLOPT_FILE, (void *)&response);
234   ::curl_easy_setopt(curl, CURLOPT_FAILONERROR, 1);
235
236   CURLcode res = ::curl_easy_perform(curl);
237
238   ::curl_easy_cleanup(curl);
239   ::curl_global_cleanup();
240
241   return static_cast<int>(res);
242 }
243 #endif
244
245 //----------------------------------------------------------------------
246 std::string cmCTest::MakeURLSafe(const std::string& str)
247 {
248   cmOStringStream ost;
249   char buffer[10];
250   for ( std::string::size_type pos = 0; pos < str.size(); pos ++ )
251     {
252     unsigned char ch = str[pos];
253     if ( ( ch > 126 || ch < 32 ||
254            ch == '&' ||
255            ch == '%' ||
256            ch == '+' ||
257            ch == '=' ||
258            ch == '@'
259           ) && ch != 9 )
260       {
261       sprintf(buffer, "%02x;", (unsigned int)ch);
262       ost << buffer;
263       }
264     else
265       {
266       ost << ch;
267       }
268     }
269   return ost.str();
270 }
271
272 //----------------------------------------------------------------------------
273 std::string cmCTest::DecodeURL(const std::string& in)
274 {
275   std::string out;
276   for(const char* c = in.c_str(); *c; ++c)
277     {
278     if(*c == '%' && isxdigit(*(c+1)) && isxdigit(*(c+2)))
279       {
280       char buf[3] = {*(c+1), *(c+2), 0};
281       out.append(1, char(strtoul(buf, 0, 16)));
282       c += 2;
283       }
284     else
285       {
286       out.append(1, *c);
287       }
288     }
289   return out;
290 }
291
292 //----------------------------------------------------------------------
293 cmCTest::cmCTest()
294 {
295   this->LabelSummary           = true;
296   this->ParallelLevel          = 1;
297   this->ParallelLevelSetInCli  = false;
298   this->SubmitIndex            = 0;
299   this->Failover               = false;
300   this->BatchJobs              = false;
301   this->ForceNewCTestProcess   = false;
302   this->TomorrowTag            = false;
303   this->Verbose                = false;
304
305   this->Debug                  = false;
306   this->ShowLineNumbers        = false;
307   this->Quiet                  = false;
308   this->ExtraVerbose           = false;
309   this->ProduceXML             = false;
310   this->ShowOnly               = false;
311   this->RunConfigurationScript = false;
312   this->UseHTTP10              = false;
313   this->PrintLabels            = false;
314   this->CompressTestOutput     = true;
315   this->CompressMemCheckOutput = true;
316   this->TestModel              = cmCTest::EXPERIMENTAL;
317   this->MaxTestNameWidth       = 30;
318   this->InteractiveDebugMode   = true;
319   this->TimeOut                = 0;
320   this->GlobalTimeout          = 0;
321   this->LastStopTimeout        = 24 * 60 * 60;
322   this->CompressXMLFiles       = false;
323   this->CTestConfigFile        = "";
324   this->ScheduleType           = "";
325   this->StopTime               = "";
326   this->NextDayStopTime        = false;
327   this->OutputLogFile          = 0;
328   this->OutputLogFileLastTag   = -1;
329   this->SuppressUpdatingCTestConfiguration = false;
330   this->DartVersion            = 1;
331   this->DropSiteCDash          = false;
332   this->OutputTestOutputOnTestFailure = false;
333   this->ComputedCompressTestOutput = false;
334   this->ComputedCompressMemCheckOutput = false;
335   if(cmSystemTools::GetEnv("CTEST_OUTPUT_ON_FAILURE"))
336     {
337     this->OutputTestOutputOnTestFailure = true;
338     }
339   this->InitStreams();
340
341   this->Parts[PartStart].SetName("Start");
342   this->Parts[PartUpdate].SetName("Update");
343   this->Parts[PartConfigure].SetName("Configure");
344   this->Parts[PartBuild].SetName("Build");
345   this->Parts[PartTest].SetName("Test");
346   this->Parts[PartCoverage].SetName("Coverage");
347   this->Parts[PartMemCheck].SetName("MemCheck");
348   this->Parts[PartSubmit].SetName("Submit");
349   this->Parts[PartNotes].SetName("Notes");
350   this->Parts[PartExtraFiles].SetName("ExtraFiles");
351   this->Parts[PartUpload].SetName("Upload");
352
353   // Fill the part name-to-id map.
354   for(Part p = PartStart; p != PartCount; p = Part(p+1))
355     {
356     this->PartMap[cmSystemTools::LowerCase(this->Parts[p].GetName())] = p;
357     }
358
359   this->ShortDateFormat        = true;
360
361   this->TestingHandlers["build"]     = new cmCTestBuildHandler;
362   this->TestingHandlers["buildtest"] = new cmCTestBuildAndTestHandler;
363   this->TestingHandlers["coverage"]  = new cmCTestCoverageHandler;
364   this->TestingHandlers["script"]    = new cmCTestScriptHandler;
365   this->TestingHandlers["test"]      = new cmCTestTestHandler;
366   this->TestingHandlers["update"]    = new cmCTestUpdateHandler;
367   this->TestingHandlers["configure"] = new cmCTestConfigureHandler;
368   this->TestingHandlers["memcheck"]  = new cmCTestMemCheckHandler;
369   this->TestingHandlers["submit"]    = new cmCTestSubmitHandler;
370   this->TestingHandlers["upload"]    = new cmCTestUploadHandler;
371
372   cmCTest::t_TestingHandlers::iterator it;
373   for ( it = this->TestingHandlers.begin();
374     it != this->TestingHandlers.end(); ++ it )
375     {
376     it->second->SetCTestInstance(this);
377     }
378
379   // Make sure we can capture the build tool output.
380   cmSystemTools::EnableVSConsoleOutput();
381 }
382
383 //----------------------------------------------------------------------
384 cmCTest::~cmCTest()
385 {
386   cmCTest::t_TestingHandlers::iterator it;
387   for ( it = this->TestingHandlers.begin();
388     it != this->TestingHandlers.end(); ++ it )
389     {
390     delete it->second;
391     it->second = 0;
392     }
393   this->SetOutputLogFileName(0);
394 }
395
396 void cmCTest::SetParallelLevel(int level)
397 {
398   this->ParallelLevel = level < 1 ? 1 : level;
399 }
400
401 //----------------------------------------------------------------------------
402 bool cmCTest::ShouldCompressTestOutput()
403 {
404   if(!this->ComputedCompressTestOutput)
405     {
406     std::string cdashVersion = this->GetCDashVersion();
407     //version >= 1.6?
408     bool cdashSupportsGzip = cmSystemTools::VersionCompare(
409       cmSystemTools::OP_GREATER, cdashVersion.c_str(), "1.6") ||
410       cmSystemTools::VersionCompare(cmSystemTools::OP_EQUAL,
411       cdashVersion.c_str(), "1.6");
412     this->CompressTestOutput &= cdashSupportsGzip;
413     this->ComputedCompressTestOutput = true;
414     }
415   return this->CompressTestOutput;
416 }
417
418 //----------------------------------------------------------------------------
419 bool cmCTest::ShouldCompressMemCheckOutput()
420 {
421   if(!this->ComputedCompressMemCheckOutput)
422     {
423     std::string cdashVersion = this->GetCDashVersion();
424
425     bool compressionSupported = cmSystemTools::VersionCompare(
426       cmSystemTools::OP_GREATER, cdashVersion.c_str(), "1.9.0");
427     this->CompressMemCheckOutput &= compressionSupported;
428     this->ComputedCompressMemCheckOutput = true;
429     }
430   return this->CompressMemCheckOutput;
431 }
432
433 //----------------------------------------------------------------------------
434 std::string cmCTest::GetCDashVersion()
435 {
436 #ifdef CMAKE_BUILD_WITH_CMAKE
437   //First query the server.  If that fails, fall back to the local setting
438   std::string response;
439   std::string url = "http://";
440   url += this->GetCTestConfiguration("DropSite");
441
442   std::string cdashUri = this->GetCTestConfiguration("DropLocation");
443   cdashUri = cdashUri.substr(0, cdashUri.find("/submit.php"));
444
445   int res = 1;
446   if ( ! cdashUri.empty() )
447   {
448     url += cdashUri + "/api/getversion.php";
449     res = cmCTest::HTTPRequest(url, cmCTest::HTTP_GET, response, "", "", 3);
450   }
451
452   return res ? this->GetCTestConfiguration("CDashVersion") : response;
453 #else
454   return this->GetCTestConfiguration("CDashVersion");
455 #endif
456 }
457
458 //----------------------------------------------------------------------------
459 cmCTest::Part cmCTest::GetPartFromName(const char* name)
460 {
461   // Look up by lower-case to make names case-insensitive.
462   std::string lower_name = cmSystemTools::LowerCase(name);
463   PartMapType::const_iterator i = this->PartMap.find(lower_name);
464   if(i != this->PartMap.end())
465     {
466     return i->second;
467     }
468
469   // The string does not name a valid part.
470   return PartCount;
471 }
472
473 //----------------------------------------------------------------------
474 int cmCTest::Initialize(const char* binary_dir, cmCTestStartCommand* command)
475 {
476   cmCTestLog(this, DEBUG, "Here: " << __LINE__ << std::endl);
477   if(!this->InteractiveDebugMode)
478     {
479     this->BlockTestErrorDiagnostics();
480     }
481   else
482     {
483     cmSystemTools::PutEnv("CTEST_INTERACTIVE_DEBUG_MODE=1");
484     }
485
486   this->BinaryDir = binary_dir;
487   cmSystemTools::ConvertToUnixSlashes(this->BinaryDir);
488
489   this->UpdateCTestConfiguration();
490
491   cmCTestLog(this, DEBUG, "Here: " << __LINE__ << std::endl);
492   if ( this->ProduceXML )
493     {
494     cmCTestLog(this, DEBUG, "Here: " << __LINE__ << std::endl);
495     cmCTestLog(this, OUTPUT,
496       "   Site: " << this->GetCTestConfiguration("Site") << std::endl
497       << "   Build name: " << this->GetCTestConfiguration("BuildName")
498       << std::endl);
499     cmCTestLog(this, DEBUG, "Produce XML is on" << std::endl);
500     if ( this->TestModel == cmCTest::NIGHTLY &&
501          this->GetCTestConfiguration("NightlyStartTime").empty() )
502       {
503       cmCTestLog(this, WARNING,
504                  "WARNING: No nightly start time found please set in"
505                  " CTestConfig.cmake or DartConfig.cmake" << std::endl);
506       cmCTestLog(this, DEBUG, "Here: " << __LINE__ << std::endl);
507       return 0;
508       }
509     }
510
511   cmake cm;
512   cmGlobalGenerator gg;
513   gg.SetCMakeInstance(&cm);
514   cmsys::auto_ptr<cmLocalGenerator> lg(gg.CreateLocalGenerator());
515   cmMakefile *mf = lg->GetMakefile();
516   if ( !this->ReadCustomConfigurationFileTree(this->BinaryDir.c_str(), mf) )
517     {
518     cmCTestLog(this, DEBUG, "Cannot find custom configuration file tree"
519       << std::endl);
520     return 0;
521     }
522
523   if ( this->ProduceXML )
524     {
525     // Verify "Testing" directory exists:
526     //
527     std::string testingDir = this->BinaryDir + "/Testing";
528     if ( cmSystemTools::FileExists(testingDir.c_str()) )
529       {
530       if ( !cmSystemTools::FileIsDirectory(testingDir.c_str()) )
531         {
532         cmCTestLog(this, ERROR_MESSAGE, "File " << testingDir
533           << " is in the place of the testing directory" << std::endl);
534         return 0;
535         }
536       }
537     else
538       {
539       if ( !cmSystemTools::MakeDirectory(testingDir.c_str()) )
540         {
541         cmCTestLog(this, ERROR_MESSAGE, "Cannot create directory "
542           << testingDir << std::endl);
543         return 0;
544         }
545       }
546
547     // Create new "TAG" file or read existing one:
548     //
549     bool createNewTag = true;
550     if (command)
551       {
552       createNewTag = command->ShouldCreateNewTag();
553       }
554
555     std::string tagfile = testingDir + "/TAG";
556     std::ifstream tfin(tagfile.c_str());
557     std::string tag;
558
559     if (createNewTag)
560       {
561       time_t tctime = time(0);
562       if ( this->TomorrowTag )
563         {
564         tctime += ( 24 * 60 * 60 );
565         }
566       struct tm *lctime = gmtime(&tctime);
567       if ( tfin && cmSystemTools::GetLineFromStream(tfin, tag) )
568         {
569         int year = 0;
570         int mon = 0;
571         int day = 0;
572         int hour = 0;
573         int min = 0;
574         sscanf(tag.c_str(), "%04d%02d%02d-%02d%02d",
575                &year, &mon, &day, &hour, &min);
576         if ( year != lctime->tm_year + 1900 ||
577              mon != lctime->tm_mon+1 ||
578              day != lctime->tm_mday )
579           {
580           tag = "";
581           }
582         std::string tagmode;
583         if ( cmSystemTools::GetLineFromStream(tfin, tagmode) )
584           {
585           if (tagmode.size() > 4 && !this->Parts[PartStart])
586             {
587             this->TestModel = cmCTest::GetTestModelFromString(tagmode.c_str());
588             }
589           }
590         tfin.close();
591         }
592       if (tag.size() == 0 || (0 != command) || this->Parts[PartStart])
593         {
594         cmCTestLog(this, DEBUG, "TestModel: " << this->GetTestModelString()
595           << std::endl);
596         cmCTestLog(this, DEBUG, "TestModel: " << this->TestModel << std::endl);
597         if ( this->TestModel == cmCTest::NIGHTLY )
598           {
599           lctime = this->GetNightlyTime(
600             this->GetCTestConfiguration("NightlyStartTime"),
601             this->TomorrowTag);
602           }
603         char datestring[100];
604         sprintf(datestring, "%04d%02d%02d-%02d%02d",
605                 lctime->tm_year + 1900,
606                 lctime->tm_mon+1,
607                 lctime->tm_mday,
608                 lctime->tm_hour,
609                 lctime->tm_min);
610         tag = datestring;
611         std::ofstream ofs(tagfile.c_str());
612         if ( ofs )
613           {
614           ofs << tag << std::endl;
615           ofs << this->GetTestModelString() << std::endl;
616           }
617         ofs.close();
618         if ( 0 == command )
619           {
620           cmCTestLog(this, OUTPUT, "Create new tag: " << tag << " - "
621             << this->GetTestModelString() << std::endl);
622           }
623         }
624       }
625     else
626       {
627       if ( tfin )
628         {
629         cmSystemTools::GetLineFromStream(tfin, tag);
630         tfin.close();
631         }
632
633       if ( tag.empty() )
634         {
635         cmCTestLog(this, ERROR_MESSAGE,
636           "Cannot read existing TAG file in " << testingDir
637           << std::endl);
638         return 0;
639         }
640
641       cmCTestLog(this, OUTPUT, "  Use existing tag: " << tag << " - "
642         << this->GetTestModelString() << std::endl);
643       }
644
645     this->CurrentTag = tag;
646     }
647
648   return 1;
649 }
650
651 //----------------------------------------------------------------------
652 bool cmCTest::InitializeFromCommand(cmCTestStartCommand* command)
653 {
654   std::string src_dir
655     = this->GetCTestConfiguration("SourceDirectory").c_str();
656   std::string bld_dir = this->GetCTestConfiguration("BuildDirectory").c_str();
657   this->DartVersion = 1;
658   this->DropSiteCDash = false;
659   for(Part p = PartStart; p != PartCount; p = Part(p+1))
660     {
661     this->Parts[p].SubmitFiles.clear();
662     }
663
664   cmMakefile* mf = command->GetMakefile();
665   std::string fname;
666
667   std::string src_dir_fname = src_dir;
668   src_dir_fname += "/CTestConfig.cmake";
669   cmSystemTools::ConvertToUnixSlashes(src_dir_fname);
670
671   std::string bld_dir_fname = bld_dir;
672   bld_dir_fname += "/CTestConfig.cmake";
673   cmSystemTools::ConvertToUnixSlashes(bld_dir_fname);
674
675   if ( cmSystemTools::FileExists(bld_dir_fname.c_str()) )
676     {
677     fname = bld_dir_fname;
678     }
679   else if ( cmSystemTools::FileExists(src_dir_fname.c_str()) )
680     {
681     fname = src_dir_fname;
682     }
683
684   if ( !fname.empty() )
685     {
686     cmCTestLog(this, OUTPUT, "   Reading ctest configuration file: "
687       << fname.c_str() << std::endl);
688     bool readit = mf->ReadListFile(mf->GetCurrentListFile(),
689       fname.c_str() );
690     if(!readit)
691       {
692       std::string m = "Could not find include file: ";
693       m += fname;
694       command->SetError(m.c_str());
695       return false;
696       }
697     }
698   else
699     {
700     cmCTestLog(this, WARNING,
701       "Cannot locate CTest configuration: in BuildDirectory: "
702       << bld_dir_fname.c_str() << std::endl);
703     cmCTestLog(this, WARNING,
704       "Cannot locate CTest configuration: in SourceDirectory: "
705       << src_dir_fname.c_str() << std::endl);
706     }
707
708   this->SetCTestConfigurationFromCMakeVariable(mf, "NightlyStartTime",
709     "CTEST_NIGHTLY_START_TIME");
710   this->SetCTestConfigurationFromCMakeVariable(mf, "Site", "CTEST_SITE");
711   this->SetCTestConfigurationFromCMakeVariable(mf, "BuildName",
712     "CTEST_BUILD_NAME");
713   const char* dartVersion = mf->GetDefinition("CTEST_DART_SERVER_VERSION");
714   if ( dartVersion )
715     {
716     this->DartVersion = atoi(dartVersion);
717     if ( this->DartVersion < 0 )
718       {
719       cmCTestLog(this, ERROR_MESSAGE, "Invalid Dart server version: "
720         << dartVersion << ". Please specify the version number."
721         << std::endl);
722       return false;
723       }
724     }
725   this->DropSiteCDash = mf->IsOn("CTEST_DROP_SITE_CDASH");
726
727   if ( !this->Initialize(bld_dir.c_str(), command) )
728     {
729     return false;
730     }
731   cmCTestLog(this, OUTPUT, "   Use " << this->GetTestModelString()
732     << " tag: " << this->GetCurrentTag() << std::endl);
733   return true;
734 }
735
736
737 //----------------------------------------------------------------------
738 bool cmCTest::UpdateCTestConfiguration()
739 {
740   if ( this->SuppressUpdatingCTestConfiguration )
741     {
742     return true;
743     }
744   std::string fileName = this->CTestConfigFile;
745   if ( fileName.empty() )
746     {
747     fileName = this->BinaryDir + "/CTestConfiguration.ini";
748     if ( !cmSystemTools::FileExists(fileName.c_str()) )
749       {
750       fileName = this->BinaryDir + "/DartConfiguration.tcl";
751       }
752     }
753   cmCTestLog(this, HANDLER_VERBOSE_OUTPUT, "UpdateCTestConfiguration  from :"
754              << fileName.c_str() << "\n");
755   if ( !cmSystemTools::FileExists(fileName.c_str()) )
756     {
757     // No need to exit if we are not producing XML
758     if ( this->ProduceXML )
759       {
760       cmCTestLog(this, ERROR_MESSAGE, "Cannot find file: " << fileName.c_str()
761         << std::endl);
762       return false;
763       }
764     }
765   else
766     {
767     cmCTestLog(this, HANDLER_VERBOSE_OUTPUT, "Parse Config file:"
768                << fileName.c_str() << "\n");
769     // parse the dart test file
770     std::ifstream fin(fileName.c_str());
771
772     if(!fin)
773       {
774       return false;
775       }
776
777     char buffer[1024];
778     while ( fin )
779       {
780       buffer[0] = 0;
781       fin.getline(buffer, 1023);
782       buffer[1023] = 0;
783       std::string line = cmCTest::CleanString(buffer);
784       if(line.size() == 0)
785         {
786         continue;
787         }
788       while ( fin && (line[line.size()-1] == '\\') )
789         {
790         line = line.substr(0, line.size()-1);
791         buffer[0] = 0;
792         fin.getline(buffer, 1023);
793         buffer[1023] = 0;
794         line += cmCTest::CleanString(buffer);
795         }
796       if ( line[0] == '#' )
797         {
798         continue;
799         }
800       std::string::size_type cpos = line.find_first_of(":");
801       if ( cpos == line.npos )
802         {
803         continue;
804         }
805       std::string key = line.substr(0, cpos);
806       std::string value
807         = cmCTest::CleanString(line.substr(cpos+1, line.npos));
808       this->CTestConfiguration[key] = value;
809       }
810     fin.close();
811     }
812   if ( !this->GetCTestConfiguration("BuildDirectory").empty() )
813     {
814     this->BinaryDir = this->GetCTestConfiguration("BuildDirectory");
815     cmSystemTools::ChangeDirectory(this->BinaryDir.c_str());
816     }
817   this->TimeOut = atoi(this->GetCTestConfiguration("TimeOut").c_str());
818   if ( this->ProduceXML )
819     {
820     this->CompressXMLFiles = cmSystemTools::IsOn(
821       this->GetCTestConfiguration("CompressSubmission").c_str());
822     }
823   return true;
824 }
825
826 //----------------------------------------------------------------------
827 void cmCTest::BlockTestErrorDiagnostics()
828 {
829   cmSystemTools::PutEnv("DART_TEST_FROM_DART=1");
830   cmSystemTools::PutEnv("DASHBOARD_TEST_FROM_CTEST=" CMake_VERSION);
831 #if defined(_WIN32)
832   SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX);
833 #elif defined(__BEOS__) || defined(__HAIKU__)
834   disable_debugger(1);
835 #endif
836 }
837
838 //----------------------------------------------------------------------
839 void cmCTest::SetTestModel(int mode)
840 {
841   this->InteractiveDebugMode = false;
842   this->TestModel = mode;
843 }
844
845 //----------------------------------------------------------------------
846 bool cmCTest::SetTest(const char* ttype, bool report)
847 {
848   if ( cmSystemTools::LowerCase(ttype) == "all" )
849     {
850     for(Part p = PartStart; p != PartCount; p = Part(p+1))
851       {
852       this->Parts[p].Enable();
853       }
854     return true;
855     }
856   Part p = this->GetPartFromName(ttype);
857   if(p != PartCount)
858     {
859     this->Parts[p].Enable();
860     return true;
861     }
862   else
863     {
864     if ( report )
865       {
866       cmCTestLog(this, ERROR_MESSAGE, "Don't know about test \"" << ttype
867         << "\" yet..." << std::endl);
868       }
869     return false;
870     }
871 }
872
873 //----------------------------------------------------------------------
874 void cmCTest::Finalize()
875 {
876 }
877
878 //----------------------------------------------------------------------
879 bool cmCTest::OpenOutputFile(const std::string& path,
880                      const std::string& name, cmGeneratedFileStream& stream,
881                      bool compress)
882 {
883   std::string testingDir = this->BinaryDir + "/Testing";
884   if ( path.size() > 0 )
885     {
886     testingDir += "/" + path;
887     }
888   if ( cmSystemTools::FileExists(testingDir.c_str()) )
889     {
890     if ( !cmSystemTools::FileIsDirectory(testingDir.c_str()) )
891       {
892       cmCTestLog(this, ERROR_MESSAGE, "File " << testingDir
893                 << " is in the place of the testing directory"
894                 << std::endl);
895       return false;
896       }
897     }
898   else
899     {
900     if ( !cmSystemTools::MakeDirectory(testingDir.c_str()) )
901       {
902       cmCTestLog(this, ERROR_MESSAGE, "Cannot create directory " << testingDir
903                 << std::endl);
904       return false;
905       }
906     }
907   std::string filename = testingDir + "/" + name;
908   stream.Open(filename.c_str());
909   if( !stream )
910     {
911     cmCTestLog(this, ERROR_MESSAGE, "Problem opening file: " << filename
912       << std::endl);
913     return false;
914     }
915   if ( compress )
916     {
917     if ( this->CompressXMLFiles )
918       {
919       stream.SetCompression(true);
920       }
921     }
922   return true;
923 }
924
925 //----------------------------------------------------------------------
926 bool cmCTest::AddIfExists(Part part, const char* file)
927 {
928   if ( this->CTestFileExists(file) )
929     {
930     this->AddSubmitFile(part, file);
931     }
932   else
933     {
934     std::string name = file;
935     name += ".gz";
936     if ( this->CTestFileExists(name.c_str()) )
937       {
938       this->AddSubmitFile(part, file);
939       }
940     else
941       {
942       return false;
943       }
944     }
945   return true;
946 }
947
948 //----------------------------------------------------------------------
949 bool cmCTest::CTestFileExists(const std::string& filename)
950 {
951   std::string testingDir = this->BinaryDir + "/Testing/" +
952     this->CurrentTag + "/" + filename;
953   return cmSystemTools::FileExists(testingDir.c_str());
954 }
955
956 //----------------------------------------------------------------------
957 cmCTestGenericHandler* cmCTest::GetInitializedHandler(const char* handler)
958 {
959   cmCTest::t_TestingHandlers::iterator it =
960     this->TestingHandlers.find(handler);
961   if ( it == this->TestingHandlers.end() )
962     {
963     return 0;
964     }
965   it->second->Initialize();
966   return it->second;
967 }
968
969 //----------------------------------------------------------------------
970 cmCTestGenericHandler* cmCTest::GetHandler(const char* handler)
971 {
972   cmCTest::t_TestingHandlers::iterator it =
973     this->TestingHandlers.find(handler);
974   if ( it == this->TestingHandlers.end() )
975     {
976     return 0;
977     }
978   return it->second;
979 }
980
981 //----------------------------------------------------------------------
982 int cmCTest::ExecuteHandler(const char* shandler)
983 {
984   cmCTestGenericHandler* handler = this->GetHandler(shandler);
985   if ( !handler )
986     {
987     return -1;
988     }
989   handler->Initialize();
990   return handler->ProcessHandler();
991 }
992
993 //----------------------------------------------------------------------
994 int cmCTest::ProcessTests()
995 {
996   int res = 0;
997   bool notest = true;
998   int update_count = 0;
999
1000   for(Part p = PartStart; notest && p != PartCount; p = Part(p+1))
1001     {
1002     notest = !this->Parts[p];
1003     }
1004   if (this->Parts[PartUpdate] &&
1005       (this->GetRemainingTimeAllowed() - 120 > 0))
1006     {
1007     cmCTestGenericHandler* uphandler = this->GetHandler("update");
1008     uphandler->SetPersistentOption("SourceDirectory",
1009       this->GetCTestConfiguration("SourceDirectory").c_str());
1010     update_count = uphandler->ProcessHandler();
1011     if ( update_count < 0 )
1012       {
1013       res |= cmCTest::UPDATE_ERRORS;
1014       }
1015     }
1016   if ( this->TestModel == cmCTest::CONTINUOUS && !update_count )
1017     {
1018     return 0;
1019     }
1020   if (this->Parts[PartConfigure] &&
1021       (this->GetRemainingTimeAllowed() - 120 > 0))
1022     {
1023     if (this->GetHandler("configure")->ProcessHandler() < 0)
1024       {
1025       res |= cmCTest::CONFIGURE_ERRORS;
1026       }
1027     }
1028   if (this->Parts[PartBuild] &&
1029       (this->GetRemainingTimeAllowed() - 120 > 0))
1030     {
1031     this->UpdateCTestConfiguration();
1032     if (this->GetHandler("build")->ProcessHandler() < 0)
1033       {
1034       res |= cmCTest::BUILD_ERRORS;
1035       }
1036     }
1037   if ((this->Parts[PartTest] || notest) &&
1038       (this->GetRemainingTimeAllowed() - 120 > 0))
1039     {
1040     this->UpdateCTestConfiguration();
1041     if (this->GetHandler("test")->ProcessHandler() < 0)
1042       {
1043       res |= cmCTest::TEST_ERRORS;
1044       }
1045     }
1046   if (this->Parts[PartCoverage] &&
1047       (this->GetRemainingTimeAllowed() - 120 > 0))
1048     {
1049     this->UpdateCTestConfiguration();
1050     if (this->GetHandler("coverage")->ProcessHandler() < 0)
1051       {
1052       res |= cmCTest::COVERAGE_ERRORS;
1053       }
1054     }
1055   if (this->Parts[PartMemCheck] &&
1056       (this->GetRemainingTimeAllowed() - 120 > 0))
1057     {
1058     this->UpdateCTestConfiguration();
1059     if (this->GetHandler("memcheck")->ProcessHandler() < 0)
1060       {
1061       res |= cmCTest::MEMORY_ERRORS;
1062       }
1063     }
1064   if ( !notest )
1065     {
1066     std::string notes_dir = this->BinaryDir + "/Testing/Notes";
1067     if ( cmSystemTools::FileIsDirectory(notes_dir.c_str()) )
1068       {
1069       cmsys::Directory d;
1070       d.Load(notes_dir.c_str());
1071       unsigned long kk;
1072       for ( kk = 0; kk < d.GetNumberOfFiles(); kk ++ )
1073         {
1074         const char* file = d.GetFile(kk);
1075         std::string fullname = notes_dir + "/" + file;
1076         if ( cmSystemTools::FileExists(fullname.c_str()) &&
1077           !cmSystemTools::FileIsDirectory(fullname.c_str()) )
1078           {
1079           if ( this->NotesFiles.size() > 0 )
1080             {
1081             this->NotesFiles += ";";
1082             }
1083           this->NotesFiles += fullname;
1084           this->Parts[PartNotes].Enable();
1085           }
1086         }
1087       }
1088     }
1089   if (this->Parts[PartNotes])
1090     {
1091     this->UpdateCTestConfiguration();
1092     if ( this->NotesFiles.size() )
1093       {
1094       this->GenerateNotesFile(this->NotesFiles.c_str());
1095       }
1096     }
1097   if (this->Parts[PartSubmit])
1098     {
1099     this->UpdateCTestConfiguration();
1100     if (this->GetHandler("submit")->ProcessHandler() < 0)
1101       {
1102       res |= cmCTest::SUBMIT_ERRORS;
1103       }
1104     }
1105   if ( res != 0 )
1106     {
1107     cmCTestLog(this, ERROR_MESSAGE, "Errors while running CTest"
1108                  << std::endl);
1109     }
1110   return res;
1111 }
1112
1113 //----------------------------------------------------------------------
1114 std::string cmCTest::GetTestModelString()
1115 {
1116   if ( !this->SpecificTrack.empty() )
1117     {
1118     return this->SpecificTrack;
1119     }
1120   switch ( this->TestModel )
1121     {
1122   case cmCTest::NIGHTLY:
1123     return "Nightly";
1124   case cmCTest::CONTINUOUS:
1125     return "Continuous";
1126     }
1127   return "Experimental";
1128 }
1129
1130 //----------------------------------------------------------------------
1131 int cmCTest::GetTestModelFromString(const char* str)
1132 {
1133   if ( !str )
1134     {
1135     return cmCTest::EXPERIMENTAL;
1136     }
1137   std::string rstr = cmSystemTools::LowerCase(str);
1138   if ( strncmp(rstr.c_str(), "cont", 4) == 0 )
1139     {
1140     return cmCTest::CONTINUOUS;
1141     }
1142   if ( strncmp(rstr.c_str(), "nigh", 4) == 0 )
1143     {
1144     return cmCTest::NIGHTLY;
1145     }
1146   return cmCTest::EXPERIMENTAL;
1147 }
1148
1149 //######################################################################
1150 //######################################################################
1151 //######################################################################
1152 //######################################################################
1153
1154 //----------------------------------------------------------------------
1155 int cmCTest::RunMakeCommand(const char* command, std::string* output,
1156   int* retVal, const char* dir, int timeout, std::ofstream& ofs)
1157 {
1158   // First generate the command and arguments
1159   std::vector<cmStdString> args = cmSystemTools::ParseArguments(command);
1160
1161   if(args.size() < 1)
1162     {
1163     return false;
1164     }
1165
1166   std::vector<const char*> argv;
1167   for(std::vector<cmStdString>::const_iterator a = args.begin();
1168     a != args.end(); ++a)
1169     {
1170     argv.push_back(a->c_str());
1171     }
1172   argv.push_back(0);
1173
1174   if ( output )
1175     {
1176     *output = "";
1177     }
1178
1179   cmCTestLog(this, HANDLER_VERBOSE_OUTPUT, "Run command:");
1180   std::vector<const char*>::iterator ait;
1181   for ( ait = argv.begin(); ait != argv.end() && *ait; ++ ait )
1182     {
1183     cmCTestLog(this, HANDLER_VERBOSE_OUTPUT, " \"" << *ait << "\"");
1184     }
1185   cmCTestLog(this, HANDLER_VERBOSE_OUTPUT, std::endl);
1186
1187   // Now create process object
1188   cmsysProcess* cp = cmsysProcess_New();
1189   cmsysProcess_SetCommand(cp, &*argv.begin());
1190   cmsysProcess_SetWorkingDirectory(cp, dir);
1191   cmsysProcess_SetOption(cp, cmsysProcess_Option_HideWindow, 1);
1192   cmsysProcess_SetTimeout(cp, timeout);
1193   cmsysProcess_Execute(cp);
1194
1195   // Initialize tick's
1196   std::string::size_type tick = 0;
1197   std::string::size_type tick_len = 1024;
1198   std::string::size_type tick_line_len = 50;
1199
1200   char* data;
1201   int length;
1202   cmCTestLog(this, HANDLER_OUTPUT,
1203     "   Each . represents " << tick_len << " bytes of output" << std::endl
1204     << "    " << std::flush);
1205   while(cmsysProcess_WaitForData(cp, &data, &length, 0))
1206     {
1207     if ( output )
1208       {
1209       for(int cc =0; cc < length; ++cc)
1210         {
1211         if(data[cc] == 0)
1212           {
1213           data[cc] = '\n';
1214           }
1215         }
1216
1217       output->append(data, length);
1218       while ( output->size() > (tick * tick_len) )
1219         {
1220         tick ++;
1221         cmCTestLog(this, HANDLER_OUTPUT, "." << std::flush);
1222         if ( tick % tick_line_len == 0 && tick > 0 )
1223           {
1224           cmCTestLog(this, HANDLER_OUTPUT, "  Size: "
1225             << int((double(output->size()) / 1024.0) + 1) << "K" << std::endl
1226             << "    " << std::flush);
1227           }
1228         }
1229       }
1230     cmCTestLog(this, HANDLER_VERBOSE_OUTPUT, cmCTestLogWrite(data, length));
1231     if ( ofs )
1232       {
1233       ofs << cmCTestLogWrite(data, length);
1234       }
1235     }
1236   cmCTestLog(this, OUTPUT, " Size of output: "
1237     << int(double(output->size()) / 1024.0) << "K" << std::endl);
1238
1239   cmsysProcess_WaitForExit(cp, 0);
1240
1241   int result = cmsysProcess_GetState(cp);
1242
1243   if(result == cmsysProcess_State_Exited)
1244     {
1245     *retVal = cmsysProcess_GetExitValue(cp);
1246     cmCTestLog(this, HANDLER_VERBOSE_OUTPUT, "Command exited with the value: "
1247       << *retVal << std::endl);
1248     }
1249   else if(result == cmsysProcess_State_Exception)
1250     {
1251     *retVal = cmsysProcess_GetExitException(cp);
1252     cmCTestLog(this, WARNING, "There was an exception: " << *retVal
1253       << std::endl);
1254     }
1255   else if(result == cmsysProcess_State_Expired)
1256     {
1257     cmCTestLog(this, WARNING, "There was a timeout" << std::endl);
1258     }
1259   else if(result == cmsysProcess_State_Error)
1260     {
1261     *output += "\n*** ERROR executing: ";
1262     *output += cmsysProcess_GetErrorString(cp);
1263     *output += "\n***The build process failed.";
1264     cmCTestLog(this, ERROR_MESSAGE, "There was an error: "
1265       << cmsysProcess_GetErrorString(cp) << std::endl);
1266     }
1267
1268   cmsysProcess_Delete(cp);
1269
1270   return result;
1271 }
1272
1273 //######################################################################
1274 //######################################################################
1275 //######################################################################
1276 //######################################################################
1277
1278 //----------------------------------------------------------------------
1279 int cmCTest::RunTest(std::vector<const char*> argv,
1280                      std::string* output, int *retVal,
1281                      std::ostream* log, double testTimeOut,
1282                      std::vector<std::string>* environment)
1283 {
1284   bool modifyEnv = (environment && environment->size()>0);
1285
1286   // determine how much time we have
1287   double timeout = this->GetRemainingTimeAllowed() - 120;
1288   if (this->TimeOut > 0 && this->TimeOut < timeout)
1289     {
1290     timeout = this->TimeOut;
1291     }
1292   if (testTimeOut > 0
1293       && testTimeOut < this->GetRemainingTimeAllowed())
1294     {
1295     timeout = testTimeOut;
1296     }
1297
1298   // always have at least 1 second if we got to here
1299   if (timeout <= 0)
1300     {
1301     timeout = 1;
1302     }
1303   cmCTestLog(this, HANDLER_VERBOSE_OUTPUT,
1304              "Test timeout computed to be: " << timeout << "\n");
1305   if(cmSystemTools::SameFile(argv[0], this->CTestSelf.c_str()) &&
1306      !this->ForceNewCTestProcess)
1307     {
1308     cmCTest inst;
1309     inst.ConfigType = this->ConfigType;
1310     inst.TimeOut = timeout;
1311
1312     // Capture output of the child ctest.
1313     cmOStringStream oss;
1314     inst.SetStreams(&oss, &oss);
1315
1316     std::vector<std::string> args;
1317     for(unsigned int i =0; i < argv.size(); ++i)
1318       {
1319       if(argv[i])
1320         {
1321         // make sure we pass the timeout in for any build and test
1322         // invocations. Since --build-generator is required this is a
1323         // good place to check for it, and to add the arguments in
1324         if (strcmp(argv[i],"--build-generator") == 0 && timeout > 0)
1325           {
1326           args.push_back("--test-timeout");
1327           cmOStringStream msg;
1328           msg << timeout;
1329           args.push_back(msg.str());
1330           }
1331         args.push_back(argv[i]);
1332         }
1333       }
1334     if ( log )
1335       {
1336       *log << "* Run internal CTest" << std::endl;
1337       }
1338     std::string oldpath = cmSystemTools::GetCurrentWorkingDirectory();
1339
1340     cmsys::auto_ptr<cmSystemTools::SaveRestoreEnvironment> saveEnv;
1341     if (modifyEnv)
1342       {
1343       saveEnv.reset(new cmSystemTools::SaveRestoreEnvironment);
1344       cmSystemTools::AppendEnv(*environment);
1345       }
1346
1347     *retVal = inst.Run(args, output);
1348     *output += oss.str();
1349     if ( log )
1350       {
1351       *log << output->c_str();
1352       }
1353     cmSystemTools::ChangeDirectory(oldpath.c_str());
1354
1355     cmCTestLog(this, HANDLER_VERBOSE_OUTPUT,
1356       "Internal cmCTest object used to run test." << std::endl
1357       <<  *output << std::endl);
1358
1359     return cmsysProcess_State_Exited;
1360     }
1361   std::vector<char> tempOutput;
1362   if ( output )
1363     {
1364     *output = "";
1365     }
1366
1367   cmsys::auto_ptr<cmSystemTools::SaveRestoreEnvironment> saveEnv;
1368   if (modifyEnv)
1369     {
1370     saveEnv.reset(new cmSystemTools::SaveRestoreEnvironment);
1371     cmSystemTools::AppendEnv(*environment);
1372     }
1373
1374   cmsysProcess* cp = cmsysProcess_New();
1375   cmsysProcess_SetCommand(cp, &*argv.begin());
1376   cmCTestLog(this, DEBUG, "Command is: " << argv[0] << std::endl);
1377   if(cmSystemTools::GetRunCommandHideConsole())
1378     {
1379     cmsysProcess_SetOption(cp, cmsysProcess_Option_HideWindow, 1);
1380     }
1381
1382   cmsysProcess_SetTimeout(cp, timeout);
1383   cmsysProcess_Execute(cp);
1384
1385   char* data;
1386   int length;
1387   while(cmsysProcess_WaitForData(cp, &data, &length, 0))
1388     {
1389     if ( output )
1390       {
1391       tempOutput.insert(tempOutput.end(), data, data+length);
1392       }
1393     cmCTestLog(this, HANDLER_VERBOSE_OUTPUT, cmCTestLogWrite(data, length));
1394     if ( log )
1395       {
1396       log->write(data, length);
1397       }
1398     }
1399
1400   cmsysProcess_WaitForExit(cp, 0);
1401   if(output && tempOutput.begin() != tempOutput.end())
1402     {
1403     output->append(&*tempOutput.begin(), tempOutput.size());
1404     }
1405   cmCTestLog(this, HANDLER_VERBOSE_OUTPUT, "-- Process completed"
1406     << std::endl);
1407
1408   int result = cmsysProcess_GetState(cp);
1409
1410   if(result == cmsysProcess_State_Exited)
1411     {
1412     *retVal = cmsysProcess_GetExitValue(cp);
1413     if(*retVal != 0 && this->OutputTestOutputOnTestFailure)
1414       {
1415         OutputTestErrors(tempOutput);
1416       }
1417     }
1418   else if(result == cmsysProcess_State_Exception)
1419     {
1420     if(this->OutputTestOutputOnTestFailure)
1421       {
1422         OutputTestErrors(tempOutput);
1423       }
1424     *retVal = cmsysProcess_GetExitException(cp);
1425     std::string outerr = "\n*** Exception executing: ";
1426     outerr += cmsysProcess_GetExceptionString(cp);
1427     *output += outerr;
1428     cmCTestLog(this, HANDLER_VERBOSE_OUTPUT, outerr.c_str() << std::endl
1429       << std::flush);
1430     }
1431   else if(result == cmsysProcess_State_Error)
1432     {
1433     std::string outerr = "\n*** ERROR executing: ";
1434     outerr += cmsysProcess_GetErrorString(cp);
1435     *output += outerr;
1436     cmCTestLog(this, HANDLER_VERBOSE_OUTPUT, outerr.c_str() << std::endl
1437       << std::flush);
1438     }
1439   cmsysProcess_Delete(cp);
1440
1441   return result;
1442 }
1443
1444 //----------------------------------------------------------------------
1445 std::string cmCTest::SafeBuildIdField(const std::string& value)
1446 {
1447   std::string safevalue(value);
1448
1449   if (safevalue != "")
1450     {
1451     // Disallow non-filename and non-space whitespace characters.
1452     // If they occur, replace them with ""
1453     //
1454     const char *disallowed = "\\/:*?\"<>|\n\r\t\f\v";
1455
1456     if (safevalue.find_first_of(disallowed) != value.npos)
1457       {
1458       std::string::size_type i = 0;
1459       std::string::size_type n = strlen(disallowed);
1460       char replace[2];
1461       replace[1] = 0;
1462
1463       for (i= 0; i<n; ++i)
1464         {
1465         replace[0] = disallowed[i];
1466         cmSystemTools::ReplaceString(safevalue, replace, "");
1467         }
1468       }
1469
1470     safevalue = cmXMLSafe(safevalue).str();
1471     }
1472
1473   if (safevalue == "")
1474     {
1475     safevalue = "(empty)";
1476     }
1477
1478   return safevalue;
1479 }
1480
1481 //----------------------------------------------------------------------
1482 void cmCTest::StartXML(std::ostream& ostr, bool append)
1483 {
1484   if(this->CurrentTag.empty())
1485     {
1486     cmCTestLog(this, ERROR_MESSAGE,
1487                "Current Tag empty, this may mean"
1488                " NightlStartTime was not set correctly." << std::endl);
1489     cmSystemTools::SetFatalErrorOccured();
1490     }
1491
1492   // find out about the system
1493   cmsys::SystemInformation info;
1494   info.RunCPUCheck();
1495   info.RunOSCheck();
1496   info.RunMemoryCheck();
1497
1498   std::string buildname = cmCTest::SafeBuildIdField(
1499     this->GetCTestConfiguration("BuildName"));
1500   std::string stamp = cmCTest::SafeBuildIdField(
1501     this->CurrentTag + "-" + this->GetTestModelString());
1502   std::string site = cmCTest::SafeBuildIdField(
1503     this->GetCTestConfiguration("Site"));
1504
1505   ostr << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
1506        << "<Site BuildName=\"" << buildname << "\"\n"
1507        << "\tBuildStamp=\"" << stamp << "\"\n"
1508        << "\tName=\"" << site << "\"\n"
1509        << "\tGenerator=\"ctest-" << cmVersion::GetCMakeVersion() << "\"\n"
1510        << (append? "\tAppend=\"true\"\n":"")
1511        << "\tCompilerName=\"" << this->GetCTestConfiguration("Compiler")
1512        << "\"\n"
1513 #ifdef _COMPILER_VERSION
1514        << "\tCompilerVersion=\"_COMPILER_VERSION\"\n"
1515 #endif
1516        << "\tOSName=\"" << info.GetOSName() << "\"\n"
1517        << "\tHostname=\"" << info.GetHostname() << "\"\n"
1518        << "\tOSRelease=\"" << info.GetOSRelease() << "\"\n"
1519        << "\tOSVersion=\"" << info.GetOSVersion() << "\"\n"
1520        << "\tOSPlatform=\"" << info.GetOSPlatform() << "\"\n"
1521        << "\tIs64Bits=\"" << info.Is64Bits() << "\"\n"
1522        << "\tVendorString=\"" << info.GetVendorString() << "\"\n"
1523        << "\tVendorID=\"" << info.GetVendorID() << "\"\n"
1524        << "\tFamilyID=\"" << info.GetFamilyID() << "\"\n"
1525        << "\tModelID=\"" << info.GetModelID() << "\"\n"
1526        << "\tProcessorCacheSize=\"" << info.GetProcessorCacheSize() << "\"\n"
1527        << "\tNumberOfLogicalCPU=\"" << info.GetNumberOfLogicalCPU() << "\"\n"
1528        << "\tNumberOfPhysicalCPU=\""<< info.GetNumberOfPhysicalCPU() << "\"\n"
1529        << "\tTotalVirtualMemory=\"" << info.GetTotalVirtualMemory() << "\"\n"
1530        << "\tTotalPhysicalMemory=\""<< info.GetTotalPhysicalMemory() << "\"\n"
1531        << "\tLogicalProcessorsPerPhysical=\""
1532        << info.GetLogicalProcessorsPerPhysical() << "\"\n"
1533        << "\tProcessorClockFrequency=\""
1534        << info.GetProcessorClockFrequency() << "\"\n"
1535        << ">" << std::endl;
1536   this->AddSiteProperties(ostr);
1537 }
1538
1539 //----------------------------------------------------------------------
1540 void cmCTest::AddSiteProperties(std::ostream& ostr)
1541 {
1542   cmCTestScriptHandler* ch =
1543     static_cast<cmCTestScriptHandler*>(this->GetHandler("script"));
1544   cmake* cm =  ch->GetCMake();
1545   // if no CMake then this is the old style script and props like
1546   // this will not work anyway.
1547   if(!cm)
1548     {
1549     return;
1550     }
1551   // This code should go when cdash is changed to use labels only
1552   const char* subproject = cm->GetProperty("SubProject", cmProperty::GLOBAL);
1553   if(subproject)
1554     {
1555     ostr << "<Subproject name=\"" << subproject << "\">\n";
1556     const char* labels =
1557       ch->GetCMake()->GetProperty("SubProjectLabels", cmProperty::GLOBAL);
1558     if(labels)
1559       {
1560       ostr << "  <Labels>\n";
1561       std::string l = labels;
1562       std::vector<std::string> args;
1563       cmSystemTools::ExpandListArgument(l, args);
1564       for(std::vector<std::string>::iterator i = args.begin();
1565           i != args.end(); ++i)
1566         {
1567         ostr << "    <Label>" << i->c_str() << "</Label>\n";
1568         }
1569       ostr << "  </Labels>\n";
1570       }
1571     ostr << "</Subproject>\n";
1572     }
1573
1574   // This code should stay when cdash only does label based sub-projects
1575   const char* label = cm->GetProperty("Label", cmProperty::GLOBAL);
1576   if(label)
1577     {
1578     ostr << "<Labels>\n";
1579     ostr << "  <Label>" << label << "</Label>\n";
1580     ostr << "</Labels>\n";
1581     }
1582 }
1583
1584
1585 //----------------------------------------------------------------------
1586 void cmCTest::EndXML(std::ostream& ostr)
1587 {
1588   ostr << "</Site>" << std::endl;
1589 }
1590
1591 //----------------------------------------------------------------------
1592 int cmCTest::GenerateCTestNotesOutput(std::ostream& os,
1593   const cmCTest::VectorOfStrings& files)
1594 {
1595   cmCTest::VectorOfStrings::const_iterator it;
1596   os << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
1597      << "<?xml-stylesheet type=\"text/xsl\" "
1598     "href=\"Dart/Source/Server/XSL/Build.xsl "
1599     "<file:///Dart/Source/Server/XSL/Build.xsl> \"?>\n"
1600      << "<Site BuildName=\"" << this->GetCTestConfiguration("BuildName")
1601      << "\" BuildStamp=\""
1602      << this->CurrentTag << "-" << this->GetTestModelString() << "\" Name=\""
1603      << this->GetCTestConfiguration("Site") << "\" Generator=\"ctest"
1604      << cmVersion::GetCMakeVersion()
1605      << "\">\n";
1606   this->AddSiteProperties(os);
1607   os << "<Notes>" << std::endl;
1608
1609   for ( it = files.begin(); it != files.end(); it ++ )
1610     {
1611     cmCTestLog(this, OUTPUT, "\tAdd file: " << it->c_str() << std::endl);
1612     std::string note_time = this->CurrentTime();
1613     os << "<Note Name=\"" << cmXMLSafe(*it) << "\">\n"
1614       << "<Time>" << cmSystemTools::GetTime() << "</Time>\n"
1615       << "<DateTime>" << note_time << "</DateTime>\n"
1616       << "<Text>" << std::endl;
1617     std::ifstream ifs(it->c_str());
1618     if ( ifs )
1619       {
1620       std::string line;
1621       while ( cmSystemTools::GetLineFromStream(ifs, line) )
1622         {
1623         os << cmXMLSafe(line) << std::endl;
1624         }
1625       ifs.close();
1626       }
1627     else
1628       {
1629       os << "Problem reading file: " << it->c_str() << std::endl;
1630       cmCTestLog(this, ERROR_MESSAGE, "Problem reading file: " << it->c_str()
1631         << " while creating notes" << std::endl);
1632       }
1633     os << "</Text>\n"
1634       << "</Note>" << std::endl;
1635     }
1636   os << "</Notes>\n"
1637     << "</Site>" << std::endl;
1638   return 1;
1639 }
1640
1641 //----------------------------------------------------------------------
1642 int cmCTest::GenerateNotesFile(const std::vector<cmStdString> &files)
1643 {
1644   cmGeneratedFileStream ofs;
1645   if ( !this->OpenOutputFile(this->CurrentTag, "Notes.xml", ofs) )
1646     {
1647     cmCTestLog(this, ERROR_MESSAGE, "Cannot open notes file" << std::endl);
1648     return 1;
1649     }
1650
1651   this->GenerateCTestNotesOutput(ofs, files);
1652   return 0;
1653 }
1654
1655 //----------------------------------------------------------------------
1656 int cmCTest::GenerateNotesFile(const char* cfiles)
1657 {
1658   if ( !cfiles )
1659     {
1660     return 1;
1661     }
1662
1663   std::vector<cmStdString> files;
1664
1665   cmCTestLog(this, OUTPUT, "Create notes file" << std::endl);
1666
1667   files = cmSystemTools::SplitString(cfiles, ';');
1668   if ( files.size() == 0 )
1669     {
1670     return 1;
1671     }
1672
1673   return this->GenerateNotesFile(files);
1674 }
1675
1676 //----------------------------------------------------------------------
1677 std::string cmCTest::Base64GzipEncodeFile(std::string file)
1678 {
1679   std::string tarFile = file + "_temp.tar.gz";
1680   std::vector<cmStdString> files;
1681   files.push_back(file);
1682
1683   if(!cmSystemTools::CreateTar(tarFile.c_str(), files, true, false, false))
1684     {
1685     cmCTestLog(this, ERROR_MESSAGE, "Error creating tar while "
1686       "encoding file: " << file << std::endl);
1687     return "";
1688     }
1689   std::string base64 = this->Base64EncodeFile(tarFile);
1690   cmSystemTools::RemoveFile(tarFile.c_str());
1691   return base64;
1692 }
1693
1694 //----------------------------------------------------------------------
1695 std::string cmCTest::Base64EncodeFile(std::string file)
1696 {
1697   long len = cmSystemTools::FileLength(file.c_str());
1698   std::ifstream ifs(file.c_str(), std::ios::in
1699 #ifdef _WIN32
1700     | std::ios::binary
1701 #endif
1702     );
1703   unsigned char *file_buffer = new unsigned char [ len + 1 ];
1704   ifs.read(reinterpret_cast<char*>(file_buffer), len);
1705   ifs.close();
1706
1707   unsigned char *encoded_buffer
1708     = new unsigned char [ static_cast<int>(
1709         static_cast<double>(len) * 1.5 + 5.0) ];
1710
1711   unsigned long rlen
1712     = cmsysBase64_Encode(file_buffer, len, encoded_buffer, 1);
1713
1714   std::string base64 = "";
1715   for(unsigned long i = 0; i < rlen; i++)
1716     {
1717     base64 += encoded_buffer[i];
1718     }
1719   delete [] file_buffer;
1720   delete [] encoded_buffer;
1721
1722   return base64;
1723 }
1724
1725
1726 //----------------------------------------------------------------------
1727 bool cmCTest::SubmitExtraFiles(const std::vector<cmStdString> &files)
1728 {
1729   std::vector<cmStdString>::const_iterator it;
1730   for ( it = files.begin();
1731     it != files.end();
1732     ++ it )
1733     {
1734     if ( !cmSystemTools::FileExists(it->c_str()) )
1735       {
1736       cmCTestLog(this, ERROR_MESSAGE, "Cannot find extra file: "
1737         << it->c_str() << " to submit."
1738         << std::endl;);
1739       return false;
1740       }
1741     this->AddSubmitFile(PartExtraFiles, it->c_str());
1742     }
1743   return true;
1744 }
1745
1746 //----------------------------------------------------------------------
1747 bool cmCTest::SubmitExtraFiles(const char* cfiles)
1748 {
1749   if ( !cfiles )
1750     {
1751     return 1;
1752     }
1753
1754   std::vector<cmStdString> files;
1755
1756   cmCTestLog(this, OUTPUT, "Submit extra files" << std::endl);
1757
1758   files = cmSystemTools::SplitString(cfiles, ';');
1759   if ( files.size() == 0 )
1760     {
1761     return 1;
1762     }
1763
1764   return this->SubmitExtraFiles(files);
1765 }
1766
1767
1768 //-------------------------------------------------------
1769 // for a -D argument convert the next argument into
1770 // the proper list of dashboard steps via SetTest
1771 bool cmCTest::AddTestsForDashboardType(std::string &targ)
1772 {
1773   if ( targ == "Experimental" )
1774     {
1775     this->SetTestModel(cmCTest::EXPERIMENTAL);
1776     this->SetTest("Start");
1777     this->SetTest("Configure");
1778     this->SetTest("Build");
1779     this->SetTest("Test");
1780     this->SetTest("Coverage");
1781     this->SetTest("Submit");
1782     }
1783   else if ( targ == "ExperimentalStart" )
1784     {
1785     this->SetTestModel(cmCTest::EXPERIMENTAL);
1786     this->SetTest("Start");
1787     }
1788   else if ( targ == "ExperimentalUpdate" )
1789     {
1790     this->SetTestModel(cmCTest::EXPERIMENTAL);
1791     this->SetTest("Update");
1792     }
1793   else if ( targ == "ExperimentalConfigure" )
1794     {
1795     this->SetTestModel(cmCTest::EXPERIMENTAL);
1796     this->SetTest("Configure");
1797     }
1798   else if ( targ == "ExperimentalBuild" )
1799     {
1800     this->SetTestModel(cmCTest::EXPERIMENTAL);
1801     this->SetTest("Build");
1802     }
1803   else if ( targ == "ExperimentalTest" )
1804     {
1805     this->SetTestModel(cmCTest::EXPERIMENTAL);
1806     this->SetTest("Test");
1807     }
1808   else if ( targ == "ExperimentalMemCheck"
1809             || targ == "ExperimentalPurify" )
1810     {
1811     this->SetTestModel(cmCTest::EXPERIMENTAL);
1812     this->SetTest("MemCheck");
1813     }
1814   else if ( targ == "ExperimentalCoverage" )
1815     {
1816     this->SetTestModel(cmCTest::EXPERIMENTAL);
1817     this->SetTest("Coverage");
1818     }
1819   else if ( targ == "ExperimentalSubmit" )
1820     {
1821     this->SetTestModel(cmCTest::EXPERIMENTAL);
1822     this->SetTest("Submit");
1823     }
1824   else if ( targ == "Continuous" )
1825     {
1826     this->SetTestModel(cmCTest::CONTINUOUS);
1827     this->SetTest("Start");
1828     this->SetTest("Update");
1829     this->SetTest("Configure");
1830     this->SetTest("Build");
1831     this->SetTest("Test");
1832     this->SetTest("Coverage");
1833     this->SetTest("Submit");
1834     }
1835   else if ( targ == "ContinuousStart" )
1836     {
1837     this->SetTestModel(cmCTest::CONTINUOUS);
1838     this->SetTest("Start");
1839     }
1840   else if ( targ == "ContinuousUpdate" )
1841     {
1842     this->SetTestModel(cmCTest::CONTINUOUS);
1843     this->SetTest("Update");
1844     }
1845   else if ( targ == "ContinuousConfigure" )
1846     {
1847     this->SetTestModel(cmCTest::CONTINUOUS);
1848     this->SetTest("Configure");
1849     }
1850   else if ( targ == "ContinuousBuild" )
1851     {
1852     this->SetTestModel(cmCTest::CONTINUOUS);
1853     this->SetTest("Build");
1854     }
1855   else if ( targ == "ContinuousTest" )
1856     {
1857     this->SetTestModel(cmCTest::CONTINUOUS);
1858     this->SetTest("Test");
1859     }
1860   else if ( targ == "ContinuousMemCheck"
1861         || targ == "ContinuousPurify" )
1862     {
1863     this->SetTestModel(cmCTest::CONTINUOUS);
1864     this->SetTest("MemCheck");
1865     }
1866   else if ( targ == "ContinuousCoverage" )
1867     {
1868     this->SetTestModel(cmCTest::CONTINUOUS);
1869     this->SetTest("Coverage");
1870     }
1871   else if ( targ == "ContinuousSubmit" )
1872     {
1873     this->SetTestModel(cmCTest::CONTINUOUS);
1874     this->SetTest("Submit");
1875     }
1876   else if ( targ == "Nightly" )
1877     {
1878     this->SetTestModel(cmCTest::NIGHTLY);
1879     this->SetTest("Start");
1880     this->SetTest("Update");
1881     this->SetTest("Configure");
1882     this->SetTest("Build");
1883     this->SetTest("Test");
1884     this->SetTest("Coverage");
1885     this->SetTest("Submit");
1886     }
1887   else if ( targ == "NightlyStart" )
1888     {
1889     this->SetTestModel(cmCTest::NIGHTLY);
1890     this->SetTest("Start");
1891     }
1892   else if ( targ == "NightlyUpdate" )
1893     {
1894     this->SetTestModel(cmCTest::NIGHTLY);
1895     this->SetTest("Update");
1896     }
1897   else if ( targ == "NightlyConfigure" )
1898     {
1899     this->SetTestModel(cmCTest::NIGHTLY);
1900     this->SetTest("Configure");
1901     }
1902   else if ( targ == "NightlyBuild" )
1903     {
1904     this->SetTestModel(cmCTest::NIGHTLY);
1905     this->SetTest("Build");
1906     }
1907   else if ( targ == "NightlyTest" )
1908     {
1909     this->SetTestModel(cmCTest::NIGHTLY);
1910     this->SetTest("Test");
1911     }
1912   else if ( targ == "NightlyMemCheck"
1913             || targ == "NightlyPurify" )
1914     {
1915     this->SetTestModel(cmCTest::NIGHTLY);
1916     this->SetTest("MemCheck");
1917     }
1918   else if ( targ == "NightlyCoverage" )
1919     {
1920     this->SetTestModel(cmCTest::NIGHTLY);
1921     this->SetTest("Coverage");
1922     }
1923   else if ( targ == "NightlySubmit" )
1924     {
1925     this->SetTestModel(cmCTest::NIGHTLY);
1926     this->SetTest("Submit");
1927     }
1928   else if ( targ == "MemoryCheck" )
1929     {
1930     this->SetTestModel(cmCTest::EXPERIMENTAL);
1931     this->SetTest("Start");
1932     this->SetTest("Configure");
1933     this->SetTest("Build");
1934     this->SetTest("MemCheck");
1935     this->SetTest("Coverage");
1936     this->SetTest("Submit");
1937     }
1938   else if ( targ == "NightlyMemoryCheck" )
1939     {
1940     this->SetTestModel(cmCTest::NIGHTLY);
1941     this->SetTest("Start");
1942     this->SetTest("Update");
1943     this->SetTest("Configure");
1944     this->SetTest("Build");
1945     this->SetTest("MemCheck");
1946     this->SetTest("Coverage");
1947     this->SetTest("Submit");
1948     }
1949   else
1950     {
1951     return false;
1952     }
1953   return true;
1954 }
1955
1956
1957 //----------------------------------------------------------------------
1958 void cmCTest::ErrorMessageUnknownDashDValue(std::string &val)
1959 {
1960   cmCTestLog(this, ERROR_MESSAGE,
1961     "CTest -D called with incorrect option: " << val << std::endl);
1962
1963   cmCTestLog(this, ERROR_MESSAGE,
1964     "Available options are:" << std::endl
1965     << "  ctest -D Continuous" << std::endl
1966     << "  ctest -D Continuous(Start|Update|Configure|Build)" << std::endl
1967     << "  ctest -D Continuous(Test|Coverage|MemCheck|Submit)" << std::endl
1968     << "  ctest -D Experimental" << std::endl
1969     << "  ctest -D Experimental(Start|Update|Configure|Build)" << std::endl
1970     << "  ctest -D Experimental(Test|Coverage|MemCheck|Submit)" << std::endl
1971     << "  ctest -D Nightly" << std::endl
1972     << "  ctest -D Nightly(Start|Update|Configure|Build)" << std::endl
1973     << "  ctest -D Nightly(Test|Coverage|MemCheck|Submit)" << std::endl
1974     << "  ctest -D NightlyMemoryCheck" << std::endl);
1975 }
1976
1977
1978 //----------------------------------------------------------------------
1979 bool cmCTest::CheckArgument(const std::string& arg, const char* varg1,
1980   const char* varg2)
1981 {
1982   return (varg1 && arg == varg1) || (varg2 && arg == varg2);
1983 }
1984
1985
1986 //----------------------------------------------------------------------
1987 // Processes one command line argument (and its arguments if any)
1988 // for many simple options and then returns
1989 void cmCTest::HandleCommandLineArguments(size_t &i,
1990                                          std::vector<std::string> &args)
1991 {
1992   std::string arg = args[i];
1993
1994   if(this->CheckArgument(arg, "-F"))
1995     {
1996     this->Failover = true;
1997     }
1998   if(this->CheckArgument(arg, "-j", "--parallel") && i < args.size() - 1)
1999     {
2000     i++;
2001     int plevel = atoi(args[i].c_str());
2002     this->SetParallelLevel(plevel);
2003     this->ParallelLevelSetInCli = true;
2004     }
2005   else if(arg.find("-j") == 0)
2006     {
2007     int plevel = atoi(arg.substr(2).c_str());
2008     this->SetParallelLevel(plevel);
2009     this->ParallelLevelSetInCli = true;
2010     }
2011
2012   if(this->CheckArgument(arg, "--no-compress-output"))
2013     {
2014     this->CompressTestOutput = false;
2015     this->CompressMemCheckOutput = false;
2016     }
2017
2018   if(this->CheckArgument(arg, "--print-labels"))
2019     {
2020     this->PrintLabels = true;
2021     }
2022
2023   if(this->CheckArgument(arg, "--http1.0"))
2024     {
2025     this->UseHTTP10 = true;
2026     }
2027
2028   if(this->CheckArgument(arg, "--timeout") && i < args.size() - 1)
2029     {
2030     i++;
2031     double timeout = (double)atof(args[i].c_str());
2032     this->GlobalTimeout = timeout;
2033     }
2034
2035   if(this->CheckArgument(arg, "--stop-time") && i < args.size() - 1)
2036     {
2037     i++;
2038     this->SetStopTime(args[i]);
2039     }
2040
2041   if(this->CheckArgument(arg, "-C", "--build-config") &&
2042      i < args.size() - 1)
2043     {
2044     i++;
2045     this->SetConfigType(args[i].c_str());
2046     }
2047
2048   if(this->CheckArgument(arg, "--debug"))
2049     {
2050     this->Debug = true;
2051     this->ShowLineNumbers = true;
2052     }
2053   if(this->CheckArgument(arg, "--track") && i < args.size() - 1)
2054     {
2055     i++;
2056     this->SpecificTrack = args[i];
2057     }
2058   if(this->CheckArgument(arg, "--show-line-numbers"))
2059     {
2060     this->ShowLineNumbers = true;
2061     }
2062   if(this->CheckArgument(arg, "--no-label-summary"))
2063     {
2064     this->LabelSummary = false;
2065     }
2066   if(this->CheckArgument(arg, "-Q", "--quiet"))
2067     {
2068     this->Quiet = true;
2069     }
2070   if(this->CheckArgument(arg, "-V", "--verbose"))
2071     {
2072     this->Verbose = true;
2073     }
2074   if(this->CheckArgument(arg, "-B"))
2075     {
2076     this->BatchJobs = true;
2077     }
2078   if(this->CheckArgument(arg, "-VV", "--extra-verbose"))
2079     {
2080     this->ExtraVerbose = true;
2081     this->Verbose = true;
2082     }
2083   if(this->CheckArgument(arg, "--output-on-failure"))
2084     {
2085     this->OutputTestOutputOnTestFailure = true;
2086     }
2087
2088   if(this->CheckArgument(arg, "-N", "--show-only"))
2089     {
2090     this->ShowOnly = true;
2091     }
2092
2093   if(this->CheckArgument(arg, "-O", "--output-log") && i < args.size() - 1 )
2094     {
2095     i++;
2096     this->SetOutputLogFileName(args[i].c_str());
2097     }
2098
2099   if(this->CheckArgument(arg, "--tomorrow-tag"))
2100     {
2101     this->TomorrowTag = true;
2102     }
2103   if(this->CheckArgument(arg, "--force-new-ctest-process"))
2104     {
2105     this->ForceNewCTestProcess = true;
2106     }
2107   if(this->CheckArgument(arg, "-W", "--max-width") && i < args.size() - 1)
2108     {
2109     i++;
2110     this->MaxTestNameWidth = atoi(args[i].c_str());
2111     }
2112   if(this->CheckArgument(arg, "--interactive-debug-mode") &&
2113      i < args.size() - 1 )
2114     {
2115     i++;
2116     this->InteractiveDebugMode = cmSystemTools::IsOn(args[i].c_str());
2117     }
2118   if(this->CheckArgument(arg, "--submit-index") && i < args.size() - 1 )
2119     {
2120     i++;
2121     this->SubmitIndex = atoi(args[i].c_str());
2122     if ( this->SubmitIndex < 0 )
2123       {
2124       this->SubmitIndex = 0;
2125       }
2126     }
2127
2128   if(this->CheckArgument(arg, "--overwrite") && i < args.size() - 1)
2129     {
2130     i++;
2131     this->AddCTestConfigurationOverwrite(args[i].c_str());
2132     }
2133   if(this->CheckArgument(arg, "-A", "--add-notes") && i < args.size() - 1)
2134     {
2135     this->ProduceXML = true;
2136     this->SetTest("Notes");
2137     i++;
2138     this->SetNotesFiles(args[i].c_str());
2139     }
2140
2141   // options that control what tests are run
2142   if(this->CheckArgument(arg, "-I", "--tests-information") &&
2143      i < args.size() - 1)
2144     {
2145     i++;
2146     this->GetHandler("test")->SetPersistentOption("TestsToRunInformation",
2147                                                   args[i].c_str());
2148     this->GetHandler("memcheck")->
2149       SetPersistentOption("TestsToRunInformation",args[i].c_str());
2150     }
2151   if(this->CheckArgument(arg, "-U", "--union"))
2152     {
2153     this->GetHandler("test")->SetPersistentOption("UseUnion", "true");
2154     this->GetHandler("memcheck")->SetPersistentOption("UseUnion", "true");
2155     }
2156   if(this->CheckArgument(arg, "-R", "--tests-regex") && i < args.size() - 1)
2157     {
2158     i++;
2159     this->GetHandler("test")->
2160       SetPersistentOption("IncludeRegularExpression", args[i].c_str());
2161     this->GetHandler("memcheck")->
2162       SetPersistentOption("IncludeRegularExpression", args[i].c_str());
2163     }
2164   if(this->CheckArgument(arg, "-L", "--label-regex") && i < args.size() - 1)
2165     {
2166     i++;
2167     this->GetHandler("test")->
2168       SetPersistentOption("LabelRegularExpression", args[i].c_str());
2169     this->GetHandler("memcheck")->
2170       SetPersistentOption("LabelRegularExpression", args[i].c_str());
2171     }
2172   if(this->CheckArgument(arg, "-LE", "--label-exclude") && i < args.size() - 1)
2173     {
2174     i++;
2175     this->GetHandler("test")->
2176       SetPersistentOption("ExcludeLabelRegularExpression", args[i].c_str());
2177     this->GetHandler("memcheck")->
2178       SetPersistentOption("ExcludeLabelRegularExpression", args[i].c_str());
2179     }
2180
2181   if(this->CheckArgument(arg, "-E", "--exclude-regex") &&
2182      i < args.size() - 1)
2183     {
2184     i++;
2185     this->GetHandler("test")->
2186       SetPersistentOption("ExcludeRegularExpression", args[i].c_str());
2187     this->GetHandler("memcheck")->
2188       SetPersistentOption("ExcludeRegularExpression", args[i].c_str());
2189     }
2190 }
2191
2192 //----------------------------------------------------------------------
2193 // handle the -S -SR and -SP arguments
2194 void cmCTest::HandleScriptArguments(size_t &i,
2195                                     std::vector<std::string> &args,
2196                                     bool &SRArgumentSpecified)
2197 {
2198   std::string arg = args[i];
2199   if(this->CheckArgument(arg, "-SP", "--script-new-process") &&
2200      i < args.size() - 1 )
2201     {
2202     this->RunConfigurationScript = true;
2203     i++;
2204     cmCTestScriptHandler* ch
2205       = static_cast<cmCTestScriptHandler*>(this->GetHandler("script"));
2206     // -SR is an internal argument, -SP should be ignored when it is passed
2207     if (!SRArgumentSpecified)
2208       {
2209       ch->AddConfigurationScript(args[i].c_str(),false);
2210       }
2211     }
2212
2213   if(this->CheckArgument(arg, "-SR", "--script-run") &&
2214      i < args.size() - 1 )
2215     {
2216     SRArgumentSpecified = true;
2217     this->RunConfigurationScript = true;
2218     i++;
2219     cmCTestScriptHandler* ch
2220       = static_cast<cmCTestScriptHandler*>(this->GetHandler("script"));
2221     ch->AddConfigurationScript(args[i].c_str(),true);
2222     }
2223
2224   if(this->CheckArgument(arg, "-S", "--script") && i < args.size() - 1 )
2225     {
2226     this->RunConfigurationScript = true;
2227     i++;
2228     cmCTestScriptHandler* ch
2229       = static_cast<cmCTestScriptHandler*>(this->GetHandler("script"));
2230     // -SR is an internal argument, -S should be ignored when it is passed
2231     if (!SRArgumentSpecified)
2232       {
2233       ch->AddConfigurationScript(args[i].c_str(),true);
2234       }
2235     }
2236 }
2237
2238 //----------------------------------------------------------------------
2239 bool cmCTest::AddVariableDefinition(const std::string &arg)
2240 {
2241   std::string name;
2242   std::string value;
2243   cmCacheManager::CacheEntryType type = cmCacheManager::UNINITIALIZED;
2244
2245   if (cmCacheManager::ParseEntry(arg.c_str(), name, value, type))
2246     {
2247     this->Definitions[name] = value;
2248     return true;
2249     }
2250
2251   return false;
2252 }
2253
2254 //----------------------------------------------------------------------
2255 // the main entry point of ctest, called from main
2256 int cmCTest::Run(std::vector<std::string> &args, std::string* output)
2257 {
2258   this->FindRunningCMake();
2259   const char* ctestExec = "ctest";
2260   bool cmakeAndTest = false;
2261   bool executeTests = true;
2262   bool SRArgumentSpecified = false;
2263
2264   // copy the command line
2265   for(size_t i=0; i < args.size(); ++i)
2266     {
2267     this->InitialCommandLineArguments.push_back(args[i]);
2268     }
2269
2270   // process the command line arguments
2271   for(size_t i=1; i < args.size(); ++i)
2272     {
2273     // handle the simple commandline arguments
2274     this->HandleCommandLineArguments(i,args);
2275
2276     // handle the script arguments -S -SR -SP
2277     this->HandleScriptArguments(i,args,SRArgumentSpecified);
2278
2279     // handle a request for a dashboard
2280     std::string arg = args[i];
2281     if(this->CheckArgument(arg, "-D", "--dashboard") && i < args.size() - 1 )
2282       {
2283       this->ProduceXML = true;
2284       i++;
2285       std::string targ = args[i];
2286       // AddTestsForDashboard parses the dashboard type and converts it
2287       // into the separate stages
2288       if (!this->AddTestsForDashboardType(targ))
2289         {
2290         if (!this->AddVariableDefinition(targ))
2291           {
2292           this->ErrorMessageUnknownDashDValue(targ);
2293           executeTests = false;
2294           }
2295         }
2296       }
2297
2298     // If it's not exactly -D, but it starts with -D, then try to parse out
2299     // a variable definition from it, same as CMake does. Unsuccessful
2300     // attempts are simply ignored since previous ctest versions ignore
2301     // this too. (As well as many other unknown command line args.)
2302     //
2303     if(arg != "-D" && cmSystemTools::StringStartsWith(arg.c_str(), "-D"))
2304       {
2305       std::string input = arg.substr(2);
2306       this->AddVariableDefinition(input);
2307       }
2308
2309     if(this->CheckArgument(arg, "-T", "--test-action") &&
2310       (i < args.size() -1) )
2311       {
2312       this->ProduceXML = true;
2313       i++;
2314       if ( !this->SetTest(args[i].c_str(), false) )
2315         {
2316         executeTests = false;
2317         cmCTestLog(this, ERROR_MESSAGE,
2318           "CTest -T called with incorrect option: "
2319           << args[i].c_str() << std::endl);
2320         cmCTestLog(this, ERROR_MESSAGE, "Available options are:" << std::endl
2321           << "  " << ctestExec << " -T all" << std::endl
2322           << "  " << ctestExec << " -T start" << std::endl
2323           << "  " << ctestExec << " -T update" << std::endl
2324           << "  " << ctestExec << " -T configure" << std::endl
2325           << "  " << ctestExec << " -T build" << std::endl
2326           << "  " << ctestExec << " -T test" << std::endl
2327           << "  " << ctestExec << " -T coverage" << std::endl
2328           << "  " << ctestExec << " -T memcheck" << std::endl
2329           << "  " << ctestExec << " -T notes" << std::endl
2330           << "  " << ctestExec << " -T submit" << std::endl);
2331         }
2332       }
2333
2334     // what type of test model
2335     if(this->CheckArgument(arg, "-M", "--test-model") &&
2336       (i < args.size() -1) )
2337       {
2338       i++;
2339       std::string const& str = args[i];
2340       if ( cmSystemTools::LowerCase(str) == "nightly" )
2341         {
2342         this->SetTestModel(cmCTest::NIGHTLY);
2343         }
2344       else if ( cmSystemTools::LowerCase(str) == "continuous" )
2345         {
2346         this->SetTestModel(cmCTest::CONTINUOUS);
2347         }
2348       else if ( cmSystemTools::LowerCase(str) == "experimental" )
2349         {
2350         this->SetTestModel(cmCTest::EXPERIMENTAL);
2351         }
2352       else
2353         {
2354         executeTests = false;
2355         cmCTestLog(this, ERROR_MESSAGE,
2356           "CTest -M called with incorrect option: " << str.c_str()
2357           << std::endl);
2358         cmCTestLog(this, ERROR_MESSAGE, "Available options are:" << std::endl
2359           << "  " << ctestExec << " -M Continuous" << std::endl
2360           << "  " << ctestExec << " -M Experimental" << std::endl
2361                    << "  " << ctestExec << " -M Nightly" << std::endl);
2362         }
2363       }
2364
2365     if(this->CheckArgument(arg, "--extra-submit") && i < args.size() - 1)
2366       {
2367       this->ProduceXML = true;
2368       this->SetTest("Submit");
2369       i++;
2370       if ( !this->SubmitExtraFiles(args[i].c_str()) )
2371         {
2372         return 0;
2373         }
2374       }
2375
2376     // --build-and-test options
2377     if(this->CheckArgument(arg, "--build-and-test") && i < args.size() - 1)
2378       {
2379       cmakeAndTest = true;
2380       }
2381
2382     if(this->CheckArgument(arg, "--schedule-random"))
2383       {
2384       this->ScheduleType = "Random";
2385       }
2386
2387     // pass the argument to all the handlers as well, but i may no longer be
2388     // set to what it was originally so I'm not sure this is working as
2389     // intended
2390     cmCTest::t_TestingHandlers::iterator it;
2391     for ( it = this->TestingHandlers.begin();
2392       it != this->TestingHandlers.end();
2393       ++ it )
2394       {
2395       if ( !it->second->ProcessCommandLineArguments(arg, i, args) )
2396         {
2397         cmCTestLog(this, ERROR_MESSAGE,
2398           "Problem parsing command line arguments within a handler");
2399         return 0;
2400         }
2401       }
2402     } // the close of the for argument loop
2403
2404   if (!this->ParallelLevelSetInCli)
2405     {
2406     if (const char *parallel = cmSystemTools::GetEnv("CTEST_PARALLEL_LEVEL"))
2407       {
2408       int plevel = atoi(parallel);
2409       this->SetParallelLevel(plevel);
2410       }
2411     }
2412
2413   // now what sould cmake do? if --build-and-test was specified then
2414   // we run the build and test handler and return
2415   if(cmakeAndTest)
2416     {
2417     this->Verbose = true;
2418     cmCTestBuildAndTestHandler* handler =
2419       static_cast<cmCTestBuildAndTestHandler*>(this->GetHandler("buildtest"));
2420     int retv = handler->ProcessHandler();
2421     *output = handler->GetOutput();
2422 #ifdef CMAKE_BUILD_WITH_CMAKE
2423     cmDynamicLoader::FlushCache();
2424 #endif
2425     if(retv != 0)
2426       {
2427       cmCTestLog(this, DEBUG, "build and test failing returning: " << retv
2428                  << std::endl);
2429       }
2430     return retv;
2431     }
2432
2433   if(executeTests)
2434     {
2435     int res;
2436     // call process directory
2437     if (this->RunConfigurationScript)
2438       {
2439       if ( this->ExtraVerbose )
2440         {
2441         cmCTestLog(this, OUTPUT, "* Extra verbosity turned on" << std::endl);
2442         }
2443       cmCTest::t_TestingHandlers::iterator it;
2444       for ( it = this->TestingHandlers.begin();
2445         it != this->TestingHandlers.end();
2446         ++ it )
2447         {
2448         it->second->SetVerbose(this->ExtraVerbose);
2449         it->second->SetSubmitIndex(this->SubmitIndex);
2450         }
2451       this->GetHandler("script")->SetVerbose(this->Verbose);
2452       res = this->GetHandler("script")->ProcessHandler();
2453       if(res != 0)
2454         {
2455         cmCTestLog(this, DEBUG, "running script failing returning: " << res
2456                    << std::endl);
2457         }
2458
2459       }
2460     else
2461       {
2462       // What is this?  -V seems to be the same as -VV,
2463       // and Verbose is always on in this case
2464       this->ExtraVerbose = this->Verbose;
2465       this->Verbose = true;
2466       cmCTest::t_TestingHandlers::iterator it;
2467       for ( it = this->TestingHandlers.begin();
2468         it != this->TestingHandlers.end();
2469         ++ it )
2470         {
2471         it->second->SetVerbose(this->Verbose);
2472         it->second->SetSubmitIndex(this->SubmitIndex);
2473         }
2474       std::string cwd = cmSystemTools::GetCurrentWorkingDirectory();
2475       if(!this->Initialize(cwd.c_str(), 0))
2476         {
2477         res = 12;
2478         cmCTestLog(this, ERROR_MESSAGE, "Problem initializing the dashboard."
2479           << std::endl);
2480         }
2481       else
2482         {
2483         res = this->ProcessTests();
2484         }
2485       this->Finalize();
2486       }
2487     if(res != 0)
2488       {
2489       cmCTestLog(this, DEBUG, "Running a test(s) failed returning : " << res
2490                  << std::endl);
2491       }
2492     return res;
2493     }
2494
2495   return 1;
2496 }
2497
2498 //----------------------------------------------------------------------
2499 void cmCTest::FindRunningCMake()
2500 {
2501   // Find our own executable.
2502   this->CTestSelf = cmSystemTools::GetExecutableDirectory();
2503   this->CTestSelf += "/ctest";
2504   this->CTestSelf += cmSystemTools::GetExecutableExtension();
2505   if(!cmSystemTools::FileExists(this->CTestSelf.c_str()))
2506     {
2507     cmSystemTools::Error("CTest executable cannot be found at ",
2508                          this->CTestSelf.c_str());
2509     }
2510
2511   this->CMakeSelf = cmSystemTools::GetExecutableDirectory();
2512   this->CMakeSelf += "/cmake";
2513   this->CMakeSelf += cmSystemTools::GetExecutableExtension();
2514   if(!cmSystemTools::FileExists(this->CMakeSelf.c_str()))
2515     {
2516     cmSystemTools::Error("CMake executable cannot be found at ",
2517                          this->CMakeSelf.c_str());
2518     }
2519 }
2520
2521 //----------------------------------------------------------------------
2522 void cmCTest::SetNotesFiles(const char* notes)
2523 {
2524   if ( !notes )
2525     {
2526     return;
2527     }
2528   this->NotesFiles = notes;
2529 }
2530
2531 //----------------------------------------------------------------------
2532 void cmCTest::SetStopTime(std::string time)
2533 {
2534   this->StopTime = time;
2535   this->DetermineNextDayStop();
2536 }
2537
2538 //----------------------------------------------------------------------
2539 int cmCTest::ReadCustomConfigurationFileTree(const char* dir, cmMakefile* mf)
2540 {
2541   bool found = false;
2542   VectorOfStrings dirs;
2543   VectorOfStrings ndirs;
2544   cmCTestLog(this, DEBUG, "* Read custom CTest configuration directory: "
2545     << dir << std::endl);
2546
2547   std::string fname = dir;
2548   fname += "/CTestCustom.cmake";
2549   cmCTestLog(this, DEBUG, "* Check for file: "
2550     << fname.c_str() << std::endl);
2551   if ( cmSystemTools::FileExists(fname.c_str()) )
2552     {
2553     cmCTestLog(this, DEBUG, "* Read custom CTest configuration file: "
2554       << fname.c_str() << std::endl);
2555     bool erroroc = cmSystemTools::GetErrorOccuredFlag();
2556     cmSystemTools::ResetErrorOccuredFlag();
2557
2558     if ( !mf->ReadListFile(0, fname.c_str()) ||
2559       cmSystemTools::GetErrorOccuredFlag() )
2560       {
2561       cmCTestLog(this, ERROR_MESSAGE,
2562         "Problem reading custom configuration: "
2563         << fname.c_str() << std::endl);
2564       }
2565     found = true;
2566     if ( erroroc )
2567       {
2568       cmSystemTools::SetErrorOccured();
2569       }
2570     }
2571
2572   std::string rexpr = dir;
2573   rexpr += "/CTestCustom.ctest";
2574   cmCTestLog(this, DEBUG, "* Check for file: "
2575     << rexpr.c_str() << std::endl);
2576   if ( !found && cmSystemTools::FileExists(rexpr.c_str()) )
2577     {
2578     cmsys::Glob gl;
2579     gl.RecurseOn();
2580     gl.FindFiles(rexpr);
2581     std::vector<std::string>& files = gl.GetFiles();
2582     std::vector<std::string>::iterator fileIt;
2583     for ( fileIt = files.begin(); fileIt != files.end();
2584       ++ fileIt )
2585       {
2586       cmCTestLog(this, DEBUG, "* Read custom CTest configuration file: "
2587         << fileIt->c_str() << std::endl);
2588       if ( !mf->ReadListFile(0, fileIt->c_str()) ||
2589         cmSystemTools::GetErrorOccuredFlag() )
2590         {
2591         cmCTestLog(this, ERROR_MESSAGE,
2592           "Problem reading custom configuration: "
2593           << fileIt->c_str() << std::endl);
2594         }
2595       }
2596     found = true;
2597     }
2598
2599   if ( found )
2600     {
2601     cmCTest::t_TestingHandlers::iterator it;
2602     for ( it = this->TestingHandlers.begin();
2603       it != this->TestingHandlers.end(); ++ it )
2604       {
2605       cmCTestLog(this, DEBUG,
2606         "* Read custom CTest configuration vectors for handler: "
2607         << it->first.c_str() << " (" << it->second << ")" << std::endl);
2608       it->second->PopulateCustomVectors(mf);
2609       }
2610     }
2611
2612   return 1;
2613 }
2614
2615 //----------------------------------------------------------------------
2616 void cmCTest::PopulateCustomVector(cmMakefile* mf, const char* def,
2617   VectorOfStrings& vec)
2618 {
2619   if ( !def)
2620     {
2621     return;
2622     }
2623   const char* dval = mf->GetDefinition(def);
2624   if ( !dval )
2625     {
2626     return;
2627     }
2628   cmCTestLog(this, DEBUG, "PopulateCustomVector: " << def << std::endl);
2629   std::vector<std::string> slist;
2630   cmSystemTools::ExpandListArgument(dval, slist);
2631   std::vector<std::string>::iterator it;
2632
2633   vec.clear();
2634
2635   for ( it = slist.begin(); it != slist.end(); ++it )
2636     {
2637     cmCTestLog(this, DEBUG, "  -- " << it->c_str() << std::endl);
2638     vec.push_back(it->c_str());
2639     }
2640 }
2641
2642 //----------------------------------------------------------------------
2643 void cmCTest::PopulateCustomInteger(cmMakefile* mf, const char* def, int& val)
2644 {
2645   if ( !def)
2646     {
2647     return;
2648     }
2649   const char* dval = mf->GetDefinition(def);
2650   if ( !dval )
2651     {
2652     return;
2653     }
2654   val = atoi(dval);
2655 }
2656
2657 //----------------------------------------------------------------------
2658 std::string cmCTest::GetShortPathToFile(const char* cfname)
2659 {
2660   const std::string& sourceDir
2661     = cmSystemTools::CollapseFullPath(
2662         this->GetCTestConfiguration("SourceDirectory").c_str());
2663   const std::string& buildDir
2664     = cmSystemTools::CollapseFullPath(
2665         this->GetCTestConfiguration("BuildDirectory").c_str());
2666   std::string fname = cmSystemTools::CollapseFullPath(cfname);
2667
2668   // Find relative paths to both directories
2669   std::string srcRelpath
2670     = cmSystemTools::RelativePath(sourceDir.c_str(), fname.c_str());
2671   std::string bldRelpath
2672     = cmSystemTools::RelativePath(buildDir.c_str(), fname.c_str());
2673
2674   // If any contains "." it is not parent directory
2675   bool inSrc = srcRelpath.find("..") == srcRelpath.npos;
2676   bool inBld = bldRelpath.find("..") == bldRelpath.npos;
2677   // TODO: Handle files with .. in their name
2678
2679   std::string* res = 0;
2680
2681   if ( inSrc && inBld )
2682     {
2683     // If both have relative path with no dots, pick the shorter one
2684     if ( srcRelpath.size() < bldRelpath.size() )
2685       {
2686       res = &srcRelpath;
2687       }
2688     else
2689       {
2690       res = &bldRelpath;
2691       }
2692     }
2693   else if ( inSrc )
2694     {
2695     res = &srcRelpath;
2696     }
2697   else if ( inBld )
2698     {
2699     res = &bldRelpath;
2700     }
2701
2702   std::string path;
2703
2704   if ( !res )
2705     {
2706     path = fname;
2707     }
2708   else
2709     {
2710     cmSystemTools::ConvertToUnixSlashes(*res);
2711
2712     path = "./" + *res;
2713     if ( path[path.size()-1] == '/' )
2714       {
2715       path = path.substr(0, path.size()-1);
2716       }
2717     }
2718
2719   cmsys::SystemTools::ReplaceString(path, ":", "_");
2720   cmsys::SystemTools::ReplaceString(path, " ", "_");
2721   return path;
2722 }
2723
2724 //----------------------------------------------------------------------
2725 std::string cmCTest::GetCTestConfiguration(const char *name)
2726 {
2727   if ( this->CTestConfigurationOverwrites.find(name) !=
2728     this->CTestConfigurationOverwrites.end() )
2729     {
2730     return this->CTestConfigurationOverwrites[name];
2731     }
2732   return this->CTestConfiguration[name];
2733 }
2734
2735 //----------------------------------------------------------------------
2736 void cmCTest::EmptyCTestConfiguration()
2737 {
2738   this->CTestConfiguration.clear();
2739 }
2740
2741 //----------------------------------------------------------------------
2742 void cmCTest::DetermineNextDayStop()
2743 {
2744   struct tm* lctime;
2745   time_t current_time = time(0);
2746   lctime = gmtime(&current_time);
2747   int gm_hour = lctime->tm_hour;
2748   time_t gm_time = mktime(lctime);
2749   lctime = localtime(&current_time);
2750   int local_hour = lctime->tm_hour;
2751
2752   int tzone_offset = local_hour - gm_hour;
2753   if(gm_time > current_time && gm_hour < local_hour)
2754     {
2755     // this means gm_time is on the next day
2756     tzone_offset -= 24;
2757     }
2758   else if(gm_time < current_time && gm_hour > local_hour)
2759     {
2760     // this means gm_time is on the previous day
2761     tzone_offset += 24;
2762     }
2763
2764   tzone_offset *= 100;
2765   char buf[1024];
2766   sprintf(buf, "%d%02d%02d %s %+05i",
2767           lctime->tm_year + 1900,
2768           lctime->tm_mon + 1,
2769           lctime->tm_mday,
2770           this->StopTime.c_str(),
2771           tzone_offset);
2772
2773   time_t stop_time = curl_getdate(buf, &current_time);
2774
2775   if(stop_time < current_time)
2776     {
2777     this->NextDayStopTime = true;
2778     }
2779 }
2780
2781 //----------------------------------------------------------------------
2782 void cmCTest::SetCTestConfiguration(const char *name, const char* value)
2783 {
2784   cmCTestLog(this, HANDLER_VERBOSE_OUTPUT, "SetCTestConfiguration:"
2785     << name << ":" << (value ? value : "(null)") << "\n");
2786
2787   if ( !name )
2788     {
2789     return;
2790     }
2791   if ( !value )
2792     {
2793     this->CTestConfiguration.erase(name);
2794     return;
2795     }
2796   this->CTestConfiguration[name] = value;
2797 }
2798
2799
2800 //----------------------------------------------------------------------
2801 std::string cmCTest::GetCurrentTag()
2802 {
2803   return this->CurrentTag;
2804 }
2805
2806 //----------------------------------------------------------------------
2807 std::string cmCTest::GetBinaryDir()
2808 {
2809   return this->BinaryDir;
2810 }
2811
2812 //----------------------------------------------------------------------
2813 std::string const& cmCTest::GetConfigType()
2814 {
2815   return this->ConfigType;
2816 }
2817
2818 //----------------------------------------------------------------------
2819 bool cmCTest::GetShowOnly()
2820 {
2821   return this->ShowOnly;
2822 }
2823
2824 //----------------------------------------------------------------------
2825 int cmCTest::GetMaxTestNameWidth() const
2826 {
2827   return this->MaxTestNameWidth;
2828 }
2829
2830 //----------------------------------------------------------------------
2831 void cmCTest::SetProduceXML(bool v)
2832 {
2833   this->ProduceXML = v;
2834 }
2835
2836 //----------------------------------------------------------------------
2837 bool cmCTest::GetProduceXML()
2838 {
2839   return this->ProduceXML;
2840 }
2841
2842 //----------------------------------------------------------------------
2843 const char* cmCTest::GetSpecificTrack()
2844 {
2845   if ( this->SpecificTrack.empty() )
2846     {
2847     return 0;
2848     }
2849   return this->SpecificTrack.c_str();
2850 }
2851
2852 //----------------------------------------------------------------------
2853 void cmCTest::SetSpecificTrack(const char* track)
2854 {
2855   if ( !track )
2856     {
2857     this->SpecificTrack = "";
2858     return;
2859     }
2860   this->SpecificTrack = track;
2861 }
2862
2863 //----------------------------------------------------------------------
2864 void cmCTest::AddSubmitFile(Part part, const char* name)
2865 {
2866   this->Parts[part].SubmitFiles.push_back(name);
2867 }
2868
2869 //----------------------------------------------------------------------
2870 void cmCTest::AddCTestConfigurationOverwrite(const char* encstr)
2871 {
2872   std::string overStr = encstr;
2873   size_t epos = overStr.find("=");
2874   if ( epos == overStr.npos )
2875     {
2876     cmCTestLog(this, ERROR_MESSAGE,
2877       "CTest configuration overwrite specified in the wrong format."
2878       << std::endl
2879       << "Valid format is: --overwrite key=value" << std::endl
2880       << "The specified was: --overwrite " << overStr.c_str() << std::endl);
2881     return;
2882     }
2883   std::string key = overStr.substr(0, epos);
2884   std::string value = overStr.substr(epos+1, overStr.npos);
2885   this->CTestConfigurationOverwrites[key] = value;
2886 }
2887
2888 //----------------------------------------------------------------------
2889 void cmCTest::SetConfigType(const char* ct)
2890 {
2891   this->ConfigType = ct?ct:"";
2892   cmSystemTools::ReplaceString(this->ConfigType, ".\\", "");
2893   std::string confTypeEnv
2894     = "CMAKE_CONFIG_TYPE=" + this->ConfigType;
2895   cmSystemTools::PutEnv(confTypeEnv.c_str());
2896 }
2897
2898 //----------------------------------------------------------------------
2899 bool cmCTest::SetCTestConfigurationFromCMakeVariable(cmMakefile* mf,
2900   const char* dconfig, const char* cmake_var)
2901 {
2902   const char* ctvar;
2903   ctvar = mf->GetDefinition(cmake_var);
2904   if ( !ctvar )
2905     {
2906     return false;
2907     }
2908   cmCTestLog(this, HANDLER_VERBOSE_OUTPUT,
2909              "SetCTestConfigurationFromCMakeVariable:"
2910              << dconfig << ":" << cmake_var << std::endl);
2911   this->SetCTestConfiguration(dconfig, ctvar);
2912   return true;
2913 }
2914
2915 bool cmCTest::RunCommand(
2916   const char* command,
2917   std::string* stdOut,
2918   std::string* stdErr,
2919   int *retVal,
2920   const char* dir,
2921   double timeout)
2922 {
2923   std::vector<cmStdString> args = cmSystemTools::ParseArguments(command);
2924
2925   if(args.size() < 1)
2926     {
2927     return false;
2928     }
2929
2930   std::vector<const char*> argv;
2931   for(std::vector<cmStdString>::const_iterator a = args.begin();
2932       a != args.end(); ++a)
2933     {
2934     argv.push_back(a->c_str());
2935     }
2936   argv.push_back(0);
2937
2938   *stdOut = "";
2939   *stdErr = "";
2940
2941   cmsysProcess* cp = cmsysProcess_New();
2942   cmsysProcess_SetCommand(cp, &*argv.begin());
2943   cmsysProcess_SetWorkingDirectory(cp, dir);
2944   if(cmSystemTools::GetRunCommandHideConsole())
2945     {
2946     cmsysProcess_SetOption(cp, cmsysProcess_Option_HideWindow, 1);
2947     }
2948   cmsysProcess_SetTimeout(cp, timeout);
2949   cmsysProcess_Execute(cp);
2950
2951   std::vector<char> tempOutput;
2952   std::vector<char> tempError;
2953   char* data;
2954   int length;
2955   int res;
2956   bool done = false;
2957   while(!done)
2958     {
2959     res = cmsysProcess_WaitForData(cp, &data, &length, 0);
2960     switch ( res )
2961       {
2962     case cmsysProcess_Pipe_STDOUT:
2963       tempOutput.insert(tempOutput.end(), data, data+length);
2964       break;
2965     case cmsysProcess_Pipe_STDERR:
2966       tempError.insert(tempError.end(), data, data+length);
2967       break;
2968     default:
2969       done = true;
2970       }
2971     if ( (res == cmsysProcess_Pipe_STDOUT ||
2972         res == cmsysProcess_Pipe_STDERR) && this->ExtraVerbose )
2973       {
2974       cmSystemTools::Stdout(data, length);
2975       }
2976     }
2977
2978   cmsysProcess_WaitForExit(cp, 0);
2979   if ( tempOutput.size() > 0 )
2980     {
2981     stdOut->append(&*tempOutput.begin(), tempOutput.size());
2982     }
2983   if ( tempError.size() > 0 )
2984     {
2985     stdErr->append(&*tempError.begin(), tempError.size());
2986     }
2987
2988   bool result = true;
2989   if(cmsysProcess_GetState(cp) == cmsysProcess_State_Exited)
2990     {
2991     if ( retVal )
2992       {
2993       *retVal = cmsysProcess_GetExitValue(cp);
2994       }
2995     else
2996       {
2997       if ( cmsysProcess_GetExitValue(cp) !=  0 )
2998         {
2999         result = false;
3000         }
3001       }
3002     }
3003   else if(cmsysProcess_GetState(cp) == cmsysProcess_State_Exception)
3004     {
3005     const char* exception_str = cmsysProcess_GetExceptionString(cp);
3006     cmCTestLog(this, ERROR_MESSAGE, exception_str << std::endl);
3007     stdErr->append(exception_str, strlen(exception_str));
3008     result = false;
3009     }
3010   else if(cmsysProcess_GetState(cp) == cmsysProcess_State_Error)
3011     {
3012     const char* error_str = cmsysProcess_GetErrorString(cp);
3013     cmCTestLog(this, ERROR_MESSAGE, error_str << std::endl);
3014     stdErr->append(error_str, strlen(error_str));
3015     result = false;
3016     }
3017   else if(cmsysProcess_GetState(cp) == cmsysProcess_State_Expired)
3018     {
3019     const char* error_str = "Process terminated due to timeout\n";
3020     cmCTestLog(this, ERROR_MESSAGE, error_str << std::endl);
3021     stdErr->append(error_str, strlen(error_str));
3022     result = false;
3023     }
3024
3025   cmsysProcess_Delete(cp);
3026   return result;
3027 }
3028
3029 //----------------------------------------------------------------------
3030 void cmCTest::SetOutputLogFileName(const char* name)
3031 {
3032   if ( this->OutputLogFile)
3033     {
3034     delete this->OutputLogFile;
3035     this->OutputLogFile= 0;
3036     }
3037   if ( name )
3038     {
3039     this->OutputLogFile = new cmGeneratedFileStream(name);
3040     }
3041 }
3042
3043 //----------------------------------------------------------------------
3044 static const char* cmCTestStringLogType[] =
3045 {
3046   "DEBUG",
3047   "OUTPUT",
3048   "HANDLER_OUTPUT",
3049   "HANDLER_VERBOSE_OUTPUT",
3050   "WARNING",
3051   "ERROR_MESSAGE",
3052   0
3053 };
3054
3055 //----------------------------------------------------------------------
3056 #ifdef cerr
3057 #  undef cerr
3058 #endif
3059 #ifdef cout
3060 #  undef cout
3061 #endif
3062
3063 #define cmCTestLogOutputFileLine(stream) \
3064   if ( this->ShowLineNumbers ) \
3065     { \
3066     (stream) << std::endl << file << ":" << line << " "; \
3067     }
3068
3069 void cmCTest::InitStreams()
3070 {
3071   // By default we write output to the process output streams.
3072   this->StreamOut = &std::cout;
3073   this->StreamErr = &std::cerr;
3074 }
3075
3076 void cmCTest::Log(int logType, const char* file, int line, const char* msg)
3077 {
3078   if ( !msg || !*msg )
3079     {
3080     return;
3081     }
3082   if ( this->OutputLogFile )
3083     {
3084     bool display = true;
3085     if ( logType == cmCTest::DEBUG && !this->Debug ) { display = false; }
3086     if ( logType == cmCTest::HANDLER_VERBOSE_OUTPUT && !this->Debug &&
3087       !this->ExtraVerbose ) { display = false; }
3088     if ( display )
3089       {
3090       cmCTestLogOutputFileLine(*this->OutputLogFile);
3091       if ( logType != this->OutputLogFileLastTag )
3092         {
3093         *this->OutputLogFile << "[";
3094         if ( logType >= OTHER || logType < 0 )
3095           {
3096           *this->OutputLogFile << "OTHER";
3097           }
3098         else
3099           {
3100           *this->OutputLogFile << cmCTestStringLogType[logType];
3101           }
3102         *this->OutputLogFile << "] " << std::endl << std::flush;
3103         }
3104       *this->OutputLogFile << msg << std::flush;
3105       if ( logType != this->OutputLogFileLastTag )
3106         {
3107         *this->OutputLogFile << std::endl << std::flush;
3108         this->OutputLogFileLastTag = logType;
3109         }
3110       }
3111     }
3112   if ( !this->Quiet )
3113     {
3114     std::ostream& out = *this->StreamOut;
3115     std::ostream& err = *this->StreamErr;
3116     switch ( logType )
3117       {
3118     case DEBUG:
3119       if ( this->Debug )
3120         {
3121         cmCTestLogOutputFileLine(out);
3122         out << msg;
3123         out.flush();
3124         }
3125       break;
3126     case OUTPUT: case HANDLER_OUTPUT:
3127       if ( this->Debug || this->Verbose )
3128         {
3129         cmCTestLogOutputFileLine(out);
3130         out << msg;
3131         out.flush();
3132         }
3133       break;
3134     case HANDLER_VERBOSE_OUTPUT:
3135       if ( this->Debug || this->ExtraVerbose )
3136         {
3137         cmCTestLogOutputFileLine(out);
3138         out << msg;
3139         out.flush();
3140         }
3141       break;
3142     case WARNING:
3143       cmCTestLogOutputFileLine(err);
3144       err << msg;
3145       err.flush();
3146       break;
3147     case ERROR_MESSAGE:
3148       cmCTestLogOutputFileLine(err);
3149       err << msg;
3150       err.flush();
3151       cmSystemTools::SetErrorOccured();
3152       break;
3153     default:
3154       cmCTestLogOutputFileLine(out);
3155       out << msg;
3156       out.flush();
3157       }
3158     }
3159 }
3160
3161 //-------------------------------------------------------------------------
3162 double cmCTest::GetRemainingTimeAllowed()
3163 {
3164   if (!this->GetHandler("script"))
3165     {
3166     return 1.0e7;
3167     }
3168
3169   cmCTestScriptHandler* ch
3170     = static_cast<cmCTestScriptHandler*>(this->GetHandler("script"));
3171
3172   return ch->GetRemainingTimeAllowed();
3173 }
3174
3175 //----------------------------------------------------------------------
3176 void cmCTest::OutputTestErrors(std::vector<char> const &process_output)
3177 {
3178   std::string test_outputs("\n*** Test Failed:\n");
3179   if(process_output.size())
3180     {
3181     test_outputs.append(&*process_output.begin(), process_output.size());
3182     }
3183   cmCTestLog(this, HANDLER_OUTPUT, test_outputs << std::endl << std::flush);
3184 }
3185
3186 //----------------------------------------------------------------------
3187 bool cmCTest::CompressString(std::string& str)
3188 {
3189   int ret;
3190   z_stream strm;
3191
3192   unsigned char* in = reinterpret_cast<unsigned char*>(
3193     const_cast<char*>(str.c_str()));
3194   //zlib makes the guarantee that this is the maximum output size
3195   int outSize = static_cast<int>(
3196     static_cast<double>(str.size()) * 1.001 + 13.0);
3197   unsigned char* out = new unsigned char[outSize];
3198
3199   strm.zalloc = Z_NULL;
3200   strm.zfree = Z_NULL;
3201   strm.opaque = Z_NULL;
3202   ret = deflateInit(&strm, -1); //default compression level
3203   if (ret != Z_OK)
3204     {
3205     delete[] out;
3206     return false;
3207     }
3208
3209   strm.avail_in = static_cast<uInt>(str.size());
3210   strm.next_in = in;
3211   strm.avail_out = outSize;
3212   strm.next_out = out;
3213   ret = deflate(&strm, Z_FINISH);
3214
3215   if(ret == Z_STREAM_ERROR || ret != Z_STREAM_END)
3216     {
3217     cmCTestLog(this, ERROR_MESSAGE, "Error during gzip compression."
3218       << std::endl);
3219     delete[] out;
3220     return false;
3221     }
3222
3223   (void)deflateEnd(&strm);
3224
3225   // Now base64 encode the resulting binary string
3226   unsigned char* base64EncodedBuffer
3227     = new unsigned char[static_cast<int>(outSize * 1.5)];
3228
3229   unsigned long rlen
3230     = cmsysBase64_Encode(out, strm.total_out, base64EncodedBuffer, 1);
3231
3232   str = "";
3233   str.append(reinterpret_cast<char*>(base64EncodedBuffer), rlen);
3234
3235   delete [] base64EncodedBuffer;
3236   delete [] out;
3237
3238   return true;
3239 }