cmCTest.cxx 149 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
/*=========================================================================

  Program:   CMake - Cross-Platform Makefile Generator
  Module:    $RCSfile$
  Language:  C++
  Date:      $Date$
  Version:   $Revision$

  Copyright (c) 2002 Kitware, Inc., Insight Consortium.  All rights reserved.
  See Copyright.txt or http://www.cmake.org/HTML/Copyright.html for details.

     This software is distributed WITHOUT ANY WARRANTY; without even 
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
     PURPOSE.  See the above copyright notices for more information.

=========================================================================*/
#include "cmCTest.h"
Ken Martin's avatar
Ken Martin committed
18
19
20
21
22
#include "cmake.h"
#include "cmMakefile.h"
#include "cmLocalGenerator.h"
#include "cmGlobalGenerator.h"
#include <cmsys/Directory.hxx>
23
#include "cmGlob.h"
Andy Cedilnik's avatar
Andy Cedilnik committed
24
#include "cmDynamicLoader.h"
25

26
27
#include "cmCTestSubmit.h"
#include "curl/curl.h"
Andy Cedilnik's avatar
Andy Cedilnik committed
28

29
30
#include <cmsys/RegularExpression.hxx>
#include <cmsys/Process.h>
31
#include <cmsys/Base64.h>
32

33
#include <stdlib.h> 
34
#include <time.h>
35
#include <math.h>
Andy Cedilnik's avatar
Andy Cedilnik committed
36
#include <float.h>
Andy Cedilnik's avatar
Andy Cedilnik committed
37

Ken Martin's avatar
Ken Martin committed
38
39
40
41
42
// needed for sleep
#if !defined(_WIN32)
# include <unistd.h>
#endif

Andy Cedilnik's avatar
Andy Cedilnik committed
43
#include <memory> // auto_ptr
44

45
#define SAFEDIV(x,y) (((y)!=0)?((x)/(y)):(0))
46
47
#define DEBUGOUT std::cout << __LINE__ << " "; std::cout
#define DEBUGERR std::cerr << __LINE__ << " "; std::cerr
48

49
50
51
52
53
54
55
// provide some more detailed info on the return code for ctest
#define CTEST_UPDATE_ERRORS 0x01
#define CTEST_CONFIGURE_ERRORS 0x02
#define CTEST_BUILD_ERRORS 0x04
#define CTEST_TEST_ERRORS 0x08
#define CTEST_MEMORY_ERRORS 0x10

56
static struct tm* GetNightlyTime(std::string str, bool tomorrowtag)
Andy Cedilnik's avatar
Andy Cedilnik committed
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
{
  struct tm* lctime;
  time_t tctime = time(0);
  //Convert the nightly start time to seconds. Since we are
  //providing only a time and a timezone, the current date of
  //the local machine is assumed. Consequently, nightlySeconds
  //is the time at which the nightly dashboard was opened or
  //will be opened on the date of the current client machine.
  //As such, this time may be in the past or in the future.
  time_t ntime = curl_getdate(str.c_str(), &tctime);
  tctime = time(0);
  //std::cout << "Seconds: " << tctime << std::endl;
  if ( ntime > tctime )
    {
    // If nightlySeconds is in the past, this is the current
    // open dashboard, then return nightlySeconds.  If
    // nightlySeconds is in the future, this is the next
    // dashboard to be opened, so subtract 24 hours to get the
    // time of the current open dashboard
76
    ntime -= ( 24 * 60 * 60 );
Andy Cedilnik's avatar
Andy Cedilnik committed
77
78
79
    //std::cout << "Pick yesterday" << std::endl;
    }
  //std::cout << "nightlySeconds: " << ntime << std::endl;
80
81
82
83
84
  if ( tomorrowtag )
    {
    std::cout << "Add a day" << std::endl;
    ntime += ( 24 * 60 * 60 );
    }
Andy Cedilnik's avatar
Andy Cedilnik committed
85
86
87
88
  lctime = gmtime(&ntime);
  return lctime;
}

89
static std::string CleanString(const std::string& str)
90
{
91
92
  std::string::size_type spos = str.find_first_not_of(" \n\t\r\f\v");
  std::string::size_type epos = str.find_last_not_of(" \n\t\r\f\v");
93
94
95
96
97
98
99
100
101
102
103
104
105
106
  if ( spos == str.npos )
    {
    return std::string();
    }
  if ( epos != str.npos )
    {
    epos = epos - spos + 1;
    }
  return str.substr(spos, epos);
}

static std::string CurrentTime()
{
  time_t currenttime = time(0);
107
108
109
  struct tm* t = localtime(&currenttime);
  //return ::CleanString(ctime(&currenttime));
  char current_time[1024];
Andy Cedilnik's avatar
Andy Cedilnik committed
110
  strftime(current_time, 1000, "%a %b %d %H:%M:%S %Z %Y", t);
111
112
  //std::cout << "Current_Time: " << current_time << std::endl;
  return ::CleanString(current_time);
113
114
115
116
117
118
119
120
121
}

static const char* cmCTestErrorMatches[] = {
  "^[Bb]us [Ee]rror",
  "^[Ss]egmentation [Vv]iolation",
  "^[Ss]egmentation [Ff]ault",
  "([^ :]+):([0-9]+): ([^ \\t])",
  "([^:]+): error[ \\t]*[0-9]+[ \\t]*:",
  "^Error ([0-9]+):",
Andy Cedilnik's avatar
Andy Cedilnik committed
122
123
  "^Fatal",
  "^Error: ",
124
  "^Error ",
Andy Cedilnik's avatar
Andy Cedilnik committed
125
  "[0-9] ERROR: ",
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
  "^\"[^\"]+\", line [0-9]+: [^Ww]",
  "^cc[^C]*CC: ERROR File = ([^,]+), Line = ([0-9]+)",
  "^ld([^:])*:([ \\t])*ERROR([^:])*:",
  "^ild:([ \\t])*\\(undefined symbol\\)",
  "([^ :]+) : (error|fatal error|catastrophic error)",
  "([^:]+): (Error:|error|undefined reference|multiply defined)",
  "([^:]+)\\(([^\\)]+)\\) : (error|fatal error|catastrophic error)",
  "^fatal error C[0-9]+:",
  ": syntax error ",
  "^collect2: ld returned 1 exit status",
  "Unsatisfied symbols:",
  "Undefined symbols:",
  "^Undefined[ \\t]+first referenced",
  "^CMake Error:",
  ":[ \\t]cannot find",
Andy Cedilnik's avatar
Andy Cedilnik committed
141
142
143
144
145
  ":[ \\t]can't find",
  ": \\*\\*\\* No rule to make target \\`.*\\'.  Stop",
  ": Invalid loader fixup for symbol",
  ": internal link edit command failed",
  ": Unrecognized option \\`.*\\'",
146
  "\", line [0-9]+\\.[0-9]+: [0-9]+-[0-9]+ \\([^W]\\)",
147
  "ld: 0706-006 Cannot find or open library file: -l ",
148
149
  "ild: \\(argument error\\) can't find library argument ::",
  "^could not be found and will not be loaded.",
150
151
152
153
  0
};

static const char* cmCTestErrorExceptions[] = {
Andy Cedilnik's avatar
Andy Cedilnik committed
154
155
156
157
158
159
  "instantiated from ",
  "candidates are:",
  ": warning",
  "makefile:",
  "Makefile:",
  ":[ \\t]+Where:",
160
161
162
163
164
165
166
167
168
169
170
171
  0
};

static const char* cmCTestWarningMatches[] = {
  "([^ :]+):([0-9]+): warning:",
  "^cc[^C]*CC: WARNING File = ([^,]+), Line = ([0-9]+)",
  "^ld([^:])*:([ \\t])*WARNING([^:])*:",
  "([^:]+): warning ([0-9]+):",
  "^\"[^\"]+\", line [0-9]+: [Ww]arning",
  "([^:]+): warning[ \\t]*[0-9]+[ \\t]*:",
  "^Warning ([0-9]+):",
  "^Warning ",
Andy Cedilnik's avatar
Andy Cedilnik committed
172
  "WARNING: ",
173
174
  "([^ :]+) : warning",
  "([^:]+): warning",
Andy Cedilnik's avatar
Andy Cedilnik committed
175
  "\", line [0-9]+\\.[0-9]+: [0-9]+-[0-9]+ \\(W\\)",
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
  0
};

static const char* cmCTestWarningExceptions[] = {
  "/usr/openwin/include/X11/Xlib\\.h:[0-9]+: warning: ANSI C\\+\\+ forbids declaration",
  "/usr/openwin/include/X11/Xutil\\.h:[0-9]+: warning: ANSI C\\+\\+ forbids declaration",
  "/usr/openwin/include/X11/XResource\\.h:[0-9]+: warning: ANSI C\\+\\+ forbids declaration",
  "WARNING 84 :",
  "WARNING 47 :",
  "makefile:",
  "Makefile:",
  "warning:  Clock skew detected.  Your build may be incomplete.",
  "/usr/openwin/include/GL/[^:]+:",
  "bind_at_load",
  "XrmQGetResource",
  "IceFlush",
Andy Cedilnik's avatar
Andy Cedilnik committed
192
  "warning LNK4089: all references to [^ \\t]+ discarded by .OPT:REF",
193
  "ld32: WARNING 85: definition of dataKey in",
194
  "cc: warning 422: Unknown option \"\\+b",
195
  "_with_warning_C",
196
197
198
  0
};

199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
static const char* cmCTestMemCheckResultStrings[] = {
  "ABR",
  "ABW",
  "ABWL",
  "COR",
  "EXU",
  "FFM",
  "FIM",
  "FMM",
  "FMR",
  "FMW",
  "FUM",
  "IPR",
  "IPW",
  "MAF",
  "MLK",
  "MPK",
  "NPR",
  "ODS",
  "PAR",
  "PLK",
  "UMC",
  "UMR",
  0
};

225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
static const char* cmCTestMemCheckResultLongStrings[] = {
  "ABR",
  "ABW",
  "ABWL",
  "COR",
  "EXU",
  "FFM",
  "FIM",
  "Mismatched deallocation",
  "FMR",
  "FMW",
  "FUM",
  "IPR",
  "IPW",
  "MAF",
  "Memory Leak",
  "Potential Memory Leak",
  "NPR",
  "ODS",
  "Invalid syscall param",
  "PLK",
  "Uninitialized Memory Conditional",
  "Uninitialized Memory Read",
  0
};

251
252
253
std::string cmCTest::MakeXMLSafe(const std::string& str)
{
  cmOStringStream ost;
254
255
  // By uncommenting the lcnt code, it will put newline every 120 characters
  //int lcnt = 0;
Bill Hoffman's avatar
Bill Hoffman committed
256
  for (std::string::size_type  pos = 0; pos < str.size(); pos ++ )
257
    {
258
    unsigned char ch = str[pos];
259
    if ( (ch > 126 || ch < 32) && ch != 9  && ch != 10 && ch != 13 )
260
      {
261
      char buffer[33];
262
      sprintf(buffer, "&lt;%d&gt;", (int)ch);
263
      //sprintf(buffer, "&#x%0x;", (unsigned int)ch);
264
      ost << buffer;
265
      //lcnt += 4;
266
267
268
269
270
271
272
273
      }
    else
      {
      switch ( ch )
        {
        case '&': ost << "&amp;"; break;
        case '<': ost << "&lt;"; break;
        case '>': ost << "&gt;"; break;
274
275
276
        case '\n': ost << "\n"; 
          //lcnt = 0; 
          break;
277
278
        default: ost << ch;
        }
279
      //lcnt ++;
280
      }
281
282
283
284
285
    //if ( lcnt > 120 )
    //  {
    //  ost << "\n";
    //  lcnt = 0;
    //  }
286
287
288
289
    }
  return ost.str();
}

Andy Cedilnik's avatar
Andy Cedilnik committed
290
291
292
293
std::string cmCTest::MakeURLSafe(const std::string& str)
{
  cmOStringStream ost;
  char buffer[10];
294
  for ( std::string::size_type pos = 0; pos < str.size(); pos ++ )
Andy Cedilnik's avatar
Andy Cedilnik committed
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
    {
    unsigned char ch = str[pos];
    if ( ( ch > 126 || ch < 32 ||
           ch == '&' ||
           ch == '%' ||
           ch == '+' ||
           ch == '=' || 
           ch == '@'
          ) && ch != 9 )
      {
      sprintf(buffer, "%02x;", (unsigned int)ch);
      ost << buffer;
      }
    else
      {
      ost << ch;
      }
    }
  return ost.str();
}

316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
bool TryExecutable(const char *dir, const char *file,
                   std::string *fullPath, const char *subdir)
{
  // try current directory
  std::string tryPath;
  if (dir && strcmp(dir,""))
    {
    tryPath = dir;
    tryPath += "/";
    }
  
  if (subdir && strcmp(subdir,""))
    {
    tryPath += subdir;
    tryPath += "/";
    }
  
  tryPath += file;
  if(cmSystemTools::FileExists(tryPath.c_str()))
    {
    *fullPath = cmSystemTools::CollapseFullPath(tryPath.c_str());
    return true;
    }
  tryPath += cmSystemTools::GetExecutableExtension();
  if(cmSystemTools::FileExists(tryPath.c_str()))
    {
    *fullPath = cmSystemTools::CollapseFullPath(tryPath.c_str());
    return true;
    }
  return false;
}

cmCTest::cmCTest() 
{ 
350
  m_TomorrowTag            = false;
Bill Hoffman's avatar
Bill Hoffman committed
351
  m_BuildNoCMake           = false;
Bill Hoffman's avatar
Bill Hoffman committed
352
  m_BuildNoClean           = false;
353
  m_BuildTwoConfig         = false;
Ken Martin's avatar
Ken Martin committed
354
355
356
357
358
359
360
361
  m_UseIncludeRegExp       = false;
  m_UseExcludeRegExp       = false;
  m_UseExcludeRegExpFirst  = false;
  m_Verbose                = false;
  m_DartMode               = false;
  m_ShowOnly               = false;
  m_RunConfigurationScript = false;
  m_TestModel              = cmCTest::EXPERIMENTAL;
362
  m_InteractiveDebugMode   = true;
Ken Martin's avatar
Ken Martin committed
363
  m_TimeOut                = 0;
364
  m_CompatibilityMode      = 0;
365
366
367
368
369
370
371
  int cc; 
  for ( cc=0; cc < cmCTest::LAST_TEST; cc ++ )
    {
    m_Tests[cc] = 0;
    }
}

372
int cmCTest::Initialize()
373
{
374
375
376
377
378
  if(!m_InteractiveDebugMode)
    {
    this->BlockTestErrorDiagnostics();
    }
  
379
  m_ToplevelPath = cmSystemTools::GetCurrentWorkingDirectory();
380
  cmSystemTools::ConvertToUnixSlashes(m_ToplevelPath);
381
382
383
384
  if ( !this->ReadCustomConfigurationFileTree(m_ToplevelPath.c_str()) )
    {
    return 0;
    }
385
  this->UpdateCTestConfiguration();
386
387
  if ( m_DartMode )
    {
388
    std::string testingDir = m_ToplevelPath + "/Testing";
389
390
391
392
393
394
    if ( cmSystemTools::FileExists(testingDir.c_str()) )
      {
      if ( !cmSystemTools::FileIsDirectory(testingDir.c_str()) )
        {
        std::cerr << "File " << testingDir << " is in the place of the testing directory"
                  << std::endl;
395
        return 0;
396
397
398
399
400
401
402
403
        }
      }
    else
      {
      if ( !cmSystemTools::MakeDirectory(testingDir.c_str()) )
        {
        std::cerr << "Cannot create directory " << testingDir
                  << std::endl;
404
        return 0;
405
406
407
408
409
410
        }
      }
    std::string tagfile = testingDir + "/TAG";
    std::ifstream tfin(tagfile.c_str());
    std::string tag;
    time_t tctime = time(0);
411
412
413
414
    if ( m_TomorrowTag )
      {
      tctime += ( 24 * 60 * 60 );
      }
415
    struct tm *lctime = gmtime(&tctime);
416
    if ( tfin && cmSystemTools::GetLineFromStream(tfin, tag) )
417
418
419
420
421
422
423
424
425
      {
      int year = 0;
      int mon = 0;
      int day = 0;
      int hour = 0;
      int min = 0;
      sscanf(tag.c_str(), "%04d%02d%02d-%02d%02d",
             &year, &mon, &day, &hour, &min);
      if ( year != lctime->tm_year + 1900 ||
Andy Cedilnik's avatar
Andy Cedilnik committed
426
           mon != lctime->tm_mon+1 ||
427
428
429
430
           day != lctime->tm_mday )
        {
        tag = "";
        }
431
432
433
434
435
436
437
438
439
      std::string tagmode;
      if ( cmSystemTools::GetLineFromStream(tfin, tagmode) )
        {
        if ( tagmode.size() > 4 && !( m_Tests[cmCTest::START_TEST] || m_Tests[ALL_TEST] ))
          {
          m_TestModel = cmCTest::GetTestModelFromString(tagmode.c_str());
          }
        }
      tfin.close();
440
      }
Andy Cedilnik's avatar
Andy Cedilnik committed
441
    if ( tag.size() == 0 || m_Tests[cmCTest::START_TEST] || m_Tests[ALL_TEST])
442
      {
Andy Cedilnik's avatar
Andy Cedilnik committed
443
444
      //std::cout << "TestModel: " << this->GetTestModelString() << std::endl;
      //std::cout << "TestModel: " << m_TestModel << std::endl;
445
446
      if ( m_TestModel == cmCTest::NIGHTLY )
        {
447
448
        lctime = ::GetNightlyTime(m_DartConfiguration["NightlyStartTime"],
          m_TomorrowTag);
449
        }
450
451
452
      char datestring[100];
      sprintf(datestring, "%04d%02d%02d-%02d%02d",
              lctime->tm_year + 1900,
Andy Cedilnik's avatar
Andy Cedilnik committed
453
              lctime->tm_mon+1,
454
455
456
457
458
459
460
461
              lctime->tm_mday,
              lctime->tm_hour,
              lctime->tm_min);
      tag = datestring;
      std::ofstream ofs(tagfile.c_str());
      if ( ofs )
        {
        ofs << tag << std::endl;
462
        ofs << this->GetTestModelString() << std::endl;
463
464
        }
      ofs.close();
465
466
      std::cout << "Create new tag: " << tag << " - " 
        << this->GetTestModelString() << std::endl;
467
468
469
      }
    m_CurrentTag = tag;
    }
470
  return 1;
471
472
}

473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
void cmCTest::UpdateCTestConfiguration()
{
  // parse the dart test file
  std::ifstream fin("DartConfiguration.tcl");
  if(!fin)
    {
    return;
    }

  char buffer[1024];
  while ( fin )
    {
    buffer[0] = 0;
    fin.getline(buffer, 1023);
    buffer[1023] = 0;
    std::string line = ::CleanString(buffer);
    if(line.size() == 0)
      {
      continue;
      }
    while ( fin && (line[line.size()-1] == '\\') )
      {
      line = line.substr(0, line.size()-1);
      buffer[0] = 0;
      fin.getline(buffer, 1023);
      buffer[1023] = 0;
      line += ::CleanString(buffer);
      }
    if ( line[0] == '#' )
      {
      continue;
      }
    std::string::size_type cpos = line.find_first_of(":");
    if ( cpos == line.npos )
      {
      continue;
      }
    std::string key = line.substr(0, cpos);
    std::string value = ::CleanString(line.substr(cpos+1, line.npos));
    m_DartConfiguration[key] = value;
    }
  fin.close();
  if ( m_DartMode )
    {
    m_TimeOut = atoi(m_DartConfiguration["TimeOut"].c_str());
    }
}

521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
void cmCTest::BlockTestErrorDiagnostics()
{
  cmSystemTools::PutEnv("DART_TEST_FROM_DART=1");
  cmSystemTools::PutEnv("DASHBOARD_TEST_FROM_CTEST=1");
#if defined(_WIN32)
  SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX); 
#endif
}

void cmCTest::SetTestModel(int mode)
{
  m_InteractiveDebugMode = false;
  m_TestModel = mode;
}

536
537
538
539
540
541
bool cmCTest::SetTest(const char* ttype)
{
  if ( cmSystemTools::LowerCase(ttype) == "all" )
    {
    m_Tests[cmCTest::ALL_TEST] = 1;
    }
Andy Cedilnik's avatar
Andy Cedilnik committed
542
543
544
545
  else if ( cmSystemTools::LowerCase(ttype) == "start" )
    {
    m_Tests[cmCTest::START_TEST] = 1;
    }
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
  else if ( cmSystemTools::LowerCase(ttype) == "update" )
    {
    m_Tests[cmCTest::UPDATE_TEST] = 1;
    }
  else if ( cmSystemTools::LowerCase(ttype) == "configure" )
    {
    m_Tests[cmCTest::CONFIGURE_TEST] = 1;
    }
  else if ( cmSystemTools::LowerCase(ttype) == "build" )
    {
    m_Tests[cmCTest::BUILD_TEST] = 1;
    }
  else if ( cmSystemTools::LowerCase(ttype) == "test" )
    {
    m_Tests[cmCTest::TEST_TEST] = 1;
    }
  else if ( cmSystemTools::LowerCase(ttype) == "coverage" )
    {
    m_Tests[cmCTest::COVERAGE_TEST] = 1;
    }
566
  else if ( cmSystemTools::LowerCase(ttype) == "memcheck" )
567
    {
568
    m_Tests[cmCTest::MEMCHECK_TEST] = 1;
569
    }
570
571
572
573
  else if ( cmSystemTools::LowerCase(ttype) == "notes" )
    {
    m_Tests[cmCTest::NOTES_TEST] = 1;
    }
Andy Cedilnik's avatar
Andy Cedilnik committed
574
575
576
577
  else if ( cmSystemTools::LowerCase(ttype) == "submit" )
    {
    m_Tests[cmCTest::SUBMIT_TEST] = 1;
    }
578
579
580
581
582
583
584
585
586
587
588
589
  else
    {
    std::cerr << "Don't know about test \"" << ttype << "\" yet..." << std::endl;
    return false;
    }
  return true;
}

void cmCTest::Finalize()
{
}

Andy Cedilnik's avatar
Andy Cedilnik committed
590
std::string cmCTest::FindTheExecutable(const char *exe)
591
592
593
594
595
596
{
  std::string fullPath = "";
  std::string dir;
  std::string file;

  cmSystemTools::SplitProgramPath(exe, dir, file);
597
598
599
  if(m_ConfigType != "" && 
    ::TryExecutable(dir.c_str(), file.c_str(), &fullPath, 
      m_ConfigType.c_str()))
600
601
602
603
    {
    return fullPath;
    }

604
  if (::TryExecutable(dir.c_str(),file.c_str(),&fullPath,"."))
605
606
607
608
    {
    return fullPath;
    }

609
  if (::TryExecutable(dir.c_str(),file.c_str(),&fullPath,""))
610
611
612
613
    {
    return fullPath;
    }

614
  if ( m_ConfigType == "" )
615
    {
616
617
618
619
620
    // No config type, so try to guess it
    if (::TryExecutable(dir.c_str(),file.c_str(),&fullPath,"Release"))
      {
      return fullPath;
      }
621

622
623
624
625
    if (::TryExecutable(dir.c_str(),file.c_str(),&fullPath,"Debug"))
      {
      return fullPath;
      }
626

627
628
629
630
631
632
633
634
635
    if (::TryExecutable(dir.c_str(),file.c_str(),&fullPath,"MinSizeRel"))
      {
      return fullPath;
      }

    if (::TryExecutable(dir.c_str(),file.c_str(),&fullPath,"RelWithDebInfo"))
      {
      return fullPath;
      }
636
637
638
639
640
641
642
643
644
645
646
    }

  // if everything else failed, check the users path
  if (dir != "")
    {
    std::string path = cmSystemTools::FindProgram(file.c_str());
    if (path != "")
      {
      return path;
      }
    }
647
648
649
650
651
652
653
654
655
656
657

  if ( m_ConfigType != "" )
    {
    dir += "/";
    dir += m_ConfigType;
    dir += "/";
    dir += file;
    cmSystemTools::Error("config type specified on the command line, but test executable not found.",
      dir.c_str());
    return "";
    }
658
659
660
661
662
  return fullPath;
}

int cmCTest::UpdateDirectory()
{
Andy Cedilnik's avatar
Andy Cedilnik committed
663
  int count = 0;
Andy Cedilnik's avatar
Andy Cedilnik committed
664
  std::string::size_type cc, kk;
665
666
667
668
  std::string cvsCommand = m_DartConfiguration["CVSCommand"];
  if ( cvsCommand.size() == 0 )
    {
    std::cerr << "Cannot find CVSCommand key in the DartConfiguration.tcl" << std::endl;
Andy Cedilnik's avatar
Andy Cedilnik committed
669
    return -1;
670
671
672
673
674
    }
  std::string cvsOptions = m_DartConfiguration["CVSUpdateOptions"];
  if ( cvsOptions.size() == 0 )
    {
    std::cerr << "Cannot find CVSUpdateOptions key in the DartConfiguration.tcl" << std::endl;
Andy Cedilnik's avatar
Andy Cedilnik committed
675
    return -1;
676
677
678
679
680
681
    }

  std::string sourceDirectory = m_DartConfiguration["SourceDirectory"];
  if ( sourceDirectory.size() == 0 )
    {
    std::cerr << "Cannot find SourceDirectory  key in the DartConfiguration.tcl" << std::endl;
Andy Cedilnik's avatar
Andy Cedilnik committed
682
    return -1;
683
684
    }

685
686
687
  std::string extra_update_opts;
  if ( m_TestModel == cmCTest::NIGHTLY )
    {
688
689
    struct tm* t = ::GetNightlyTime(m_DartConfiguration["NightlyStartTime"],
      m_TomorrowTag);
690
    char current_time[1024];
691
692
693
694
695
696
697
    sprintf(current_time, "%04d-%02d-%02d %02d:%02d:%02d UTC",
      t->tm_year + 1900,
      t->tm_mon + 1,
      t->tm_mday,
      t->tm_hour,
      t->tm_min,
      t->tm_sec);
Andy Cedilnik's avatar
Andy Cedilnik committed
698
    std::string today_update_date = current_time;
699
700
   
    extra_update_opts += "-D \"" + today_update_date +"\"";
Andy Cedilnik's avatar
Andy Cedilnik committed
701
    //std::cout << "Update: " << extra_update_opts << std::endl;
702
    }
Andy Cedilnik's avatar
Andy Cedilnik committed
703

704
705
  std::string command = cvsCommand + " -z3 update " + cvsOptions +
    " " + extra_update_opts;
Andy Cedilnik's avatar
Andy Cedilnik committed
706
  std::ofstream os; 
707
  if ( !this->OpenOutputFile(m_CurrentTag, "Update.xml", os) )
Andy Cedilnik's avatar
Andy Cedilnik committed
708
    {
709
    std::cerr << "Cannot open log file" << std::endl;
Andy Cedilnik's avatar
Andy Cedilnik committed
710
711
712
    }
  std::string start_time = ::CurrentTime();
 
713

714
  std::string goutput;
715
716
  int retVal = 0;
  bool res = true;
Andy Cedilnik's avatar
Andy Cedilnik committed
717
  std::ofstream ofs;
718
719
  if ( !m_ShowOnly )
    {
Andy Cedilnik's avatar
Andy Cedilnik committed
720
721
    res = cmSystemTools::RunSingleCommand(command.c_str(), &goutput, 
      &retVal, sourceDirectory.c_str(),
722
      m_Verbose, 0 /*m_TimeOut*/);
Andy Cedilnik's avatar
Andy Cedilnik committed
723
724
    if ( this->OpenOutputFile("Temporary", "LastUpdate.log", ofs) )
      {
Andy Cedilnik's avatar
Andy Cedilnik committed
725
      ofs << goutput << std::endl;; 
Andy Cedilnik's avatar
Andy Cedilnik committed
726
      }
727
728
729
730
731
    }
  else
    {
    std::cout << "Update with command: " << command << std::endl;
    }
Andy Cedilnik's avatar
Andy Cedilnik committed
732
733

  os << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
734
     << "<Update mode=\"Client\" Generator=\"ctest\">\n"
Andy Cedilnik's avatar
Andy Cedilnik committed
735
736
737
     << "\t<Site>" <<m_DartConfiguration["Site"] << "</Site>\n"
     << "\t<BuildName>" << m_DartConfiguration["BuildName"]
     << "</BuildName>\n"
738
     << "\t<BuildStamp>" << m_CurrentTag << "-"
739
740
     << this->GetTestModelString() << "</BuildStamp>" << std::endl;
  os << "\t<StartDateTime>" << start_time << "</StartDateTime>\n"
Andy Cedilnik's avatar
Andy Cedilnik committed
741
     << "\t<UpdateCommand>" << command << "</UpdateCommand>\n"
Andy Cedilnik's avatar
Andy Cedilnik committed
742
     << "\t<UpdateReturnStatus>";
743
744
  int failed = 0;
  if ( !res || retVal )
Andy Cedilnik's avatar
Andy Cedilnik committed
745
    {
746
    os << "Update error: ";
Andy Cedilnik's avatar
Andy Cedilnik committed
747
    os << goutput;
748
749
    std::cerr << "Update with command: " << command << " failed" << std::endl;
    failed = 1;
Andy Cedilnik's avatar
Andy Cedilnik committed
750
751
    }
  os << "</UpdateReturnStatus>" << std::endl;
752
753
  if ( !failed )
    {
Andy Cedilnik's avatar
Andy Cedilnik committed
754

755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
    std::vector<cmStdString> lines;
    cmSystemTools::Split(goutput.c_str(), lines);
    std::cout << "Updated; gathering version information" << std::endl;
    cmsys::RegularExpression date_author("^date: +([^;]+); +author: +([^;]+); +state: +[^;]+;");
    cmsys::RegularExpression revision("^revision +([^ ]*) *$");
    cmsys::RegularExpression end_of_file("^=============================================================================$");
    cmsys::RegularExpression end_of_comment("^----------------------------$");
    std::string current_path = "";
    bool first_file = true;

    cmCTest::AuthorsToUpdatesMap authors_files_map;
    int num_updated = 0;
    int num_modified = 0;
    int num_conflicting = 0;
    for ( cc= 0 ; cc < lines.size(); cc ++ )
      {
      const char* line = lines[cc].c_str();
      char mod = line[0];
      if ( line[1] == ' ' && mod != '?' )
        {
        count ++;
        const char* file = line + 2;
        //std::cout << "Line" << cc << ": " << mod << " - " << file << std::endl;
        std::string logcommand = cvsCommand + " -z3 log -N " + file;
        //std::cout << "Do log: " << logcommand << std::endl;
        std::string output;
        res = cmSystemTools::RunSingleCommand(logcommand.c_str(), &output, 
          &retVal, sourceDirectory.c_str(),
          m_Verbose, 0 /*m_TimeOut*/);
        if ( ofs )
Andy Cedilnik's avatar
Andy Cedilnik committed
785
          {
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
          ofs << output << std::endl;
          }
        if ( res && retVal == 0)
          {
          //std::cout << output << std::endl;
          std::vector<cmStdString> ulines;
          cmSystemTools::Split(output.c_str(), ulines);
          std::string::size_type sline = 0;
          std::string srevision1 = "Unknown";
          std::string sdate1     = "Unknown";
          std::string sauthor1   = "Unknown";
          std::string semail1    = "Unknown";
          std::string comment1   = "";
          std::string srevision2 = "Unknown";
          std::string sdate2     = "Unknown";
          std::string sauthor2   = "Unknown";
          std::string comment2   = "";
          std::string semail2    = "Unknown";
          bool have_first = false;
          bool have_second = false;
          for ( kk = 0; kk < ulines.size(); kk ++ )
Andy Cedilnik's avatar
Andy Cedilnik committed
807
            {
808
809
            const char* clp = ulines[kk].c_str();
            if ( !have_second && !sline && revision.find(clp) )
Andy Cedilnik's avatar
Andy Cedilnik committed
810
              {
811
812
813
814
815
816
817
818
              if ( !have_first )
                {
                srevision1 = revision.match(1);
                }
              else
                {
                srevision2 = revision.match(1);
                }
Andy Cedilnik's avatar
Andy Cedilnik committed
819
              }
820
            else if ( !have_second && !sline && date_author.find(clp) )
Andy Cedilnik's avatar
Andy Cedilnik committed
821
              {
822
823
824
825
826
827
828
829
830
831
832
              sline = kk + 1;
              if ( !have_first )
                {
                sdate1 = date_author.match(1);
                sauthor1 = date_author.match(2);
                }
              else
                {
                sdate2 = date_author.match(1);
                sauthor2 = date_author.match(2);
                }
Andy Cedilnik's avatar
Andy Cedilnik committed
833
              }
834
            else if ( sline && end_of_comment.find(clp) || end_of_file.find(clp))
Andy Cedilnik's avatar
Andy Cedilnik committed
835
              {
836
837
838
839
840
841
842
843
844
              if ( !have_first )
                {
                have_first = true;
                }
              else if ( !have_second )
                {
                have_second = true;
                }
              sline = 0;
Andy Cedilnik's avatar
Andy Cedilnik committed
845
              }
846
            else if ( sline )
Andy Cedilnik's avatar
Andy Cedilnik committed
847
              {
848
849
850
851
852
853
854
855
856
857
              if ( !have_first )
                {
                comment1 += clp;
                comment1 += "\n";
                }
              else
                {
                comment2 += clp;
                comment2 += "\n";
                }
Andy Cedilnik's avatar
Andy Cedilnik committed
858
859
              }
            }
860
          if ( mod == 'M' )
Andy Cedilnik's avatar
Andy Cedilnik committed
861
            {
862
            comment1 = "Locally modified file\n";
Andy Cedilnik's avatar
Andy Cedilnik committed
863
            }
864
          if ( mod == 'C' )
Andy Cedilnik's avatar
Andy Cedilnik committed
865
            {
866
867
868
869
870
871
872
            comment1 = "Conflict while updating\n";
            }
          std::string path = cmSystemTools::GetFilenamePath(file);
          std::string fname = cmSystemTools::GetFilenameName(file);
          if ( path != current_path )
            {
            if ( !first_file )
Andy Cedilnik's avatar
Andy Cedilnik committed
873
              {
874
              os << "\t</Directory>" << std::endl;
Andy Cedilnik's avatar
Andy Cedilnik committed
875
876
877
              }
            else
              {
878
              first_file = false;
Andy Cedilnik's avatar
Andy Cedilnik committed
879
              }
880
881
            os << "\t<Directory>\n"
              << "\t\t<Name>" << path << "</Name>" << std::endl;
Andy Cedilnik's avatar
Andy Cedilnik committed
882
            }
883
884
885
886
887
888
          if ( mod == 'C' )
            {
            num_conflicting ++;
            os << "\t<Conflicting>" << std::endl;
            }
          else if ( mod == 'M' )
Andy Cedilnik's avatar
Andy Cedilnik committed
889
            {
890
891
            num_modified ++;
            os << "\t<Modified>" << std::endl;
Andy Cedilnik's avatar
Andy Cedilnik committed
892
893
894
            }
          else
            {
895
896
            num_updated ++;
            os << "\t<Updated>" << std::endl;
Andy Cedilnik's avatar
Andy Cedilnik committed
897
            }
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
          if ( srevision2 == "Unknown" )
            {
            srevision2 = srevision1;
            }
          os << "\t\t<File Directory=\"" << path << "\">" << fname 
            << "</File>\n"
            << "\t\t<Directory>" << path << "</Directory>\n"
            << "\t\t<FullName>" << file << "</FullName>\n"
            << "\t\t<CheckinDate>" << sdate1 << "</CheckinDate>\n"
            << "\t\t<Author>" << sauthor1 << "</Author>\n"
            << "\t\t<Email>" << semail1 << "</Email>\n"
            << "\t\t<Log>" << this->MakeXMLSafe(comment1) << "</Log>\n"
            << "\t\t<Revision>" << srevision1 << "</Revision>\n"
            << "\t\t<PriorRevision>" << srevision2 << "</PriorRevision>"
            << std::endl;
          if ( srevision2 != srevision1 )
            {
            os
              << "\t\t<Revisions>\n"
              << "\t\t\t<Revision>" << srevision1 << "</Revision>\n"
              << "\t\t\t<PreviousRevision>" << srevision2 << "</PreviousRevision>\n"
              << "\t\t\t<Author>" << sauthor1<< "</Author>\n"
              << "\t\t\t<Date>" << sdate1 << "</Date>\n"
              << "\t\t\t<Comment>" << this->MakeXMLSafe(comment1) << "</Comment>\n"
              << "\t\t\t<Email>" << semail1 << "</Email>\n"
              << "\t\t</Revisions>\n"
              << "\t\t<Revisions>\n"
              << "\t\t\t<Revision>" << srevision2 << "</Revision>\n"
              << "\t\t\t<PreviousRevision>" << srevision2 << "</PreviousRevision>\n"
              << "\t\t\t<Author>" << sauthor2<< "</Author>\n"
              << "\t\t\t<Date>" << sdate2 << "</Date>\n"
              << "\t\t\t<Comment>" << this->MakeXMLSafe(comment2) << "</Comment>\n"
              << "\t\t\t<Email>" << semail2 << "</Email>\n"
              << "\t\t</Revisions>" << std::endl;
            }
          if ( mod == 'C' )
            {
            os << "\t</Conflicting>" << std::endl;
            }
          else if ( mod == 'M' )
            {
            os << "\t</Modified>" << std::endl;
            }
          else
            {
            os << "\t</Updated>" << std::endl;
            }
          cmCTest::UpdateFiles *u = &authors_files_map[sauthor1];
          cmCTest::StringPair p;
          p.first = path;
          p.second = fname;
          u->push_back(p);
Andy Cedilnik's avatar
Andy Cedilnik committed
950

951
952
          current_path = path;
          }
Andy Cedilnik's avatar
Andy Cedilnik committed
953
954
        }
      }
955
    if ( num_updated )
Andy Cedilnik's avatar
Andy Cedilnik committed
956
      {
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
      std::cout << "Found " << num_updated << " updated files" << std::endl;
      }
    if ( num_modified )
      {
      std::cout << "Found " << num_modified << " locally modified files" 
        << std::endl;
      }
    if ( num_conflicting )
      {
      std::cout << "Found " << num_conflicting << " conflicting files" 
        << std::endl;
      }
    if ( !first_file )
      {
      os << "\t</Directory>" << std::endl;
Andy Cedilnik's avatar
Andy Cedilnik committed
972
973
      }

974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
    cmCTest::AuthorsToUpdatesMap::iterator it;
    for ( it = authors_files_map.begin();
      it != authors_files_map.end();
      it ++ )
      {
      os << "\t<Author>\n"
        << "\t\t<Name>" << it->first << "</Name>" << std::endl;
      cmCTest::UpdateFiles *u = &(it->second);
      for ( cc = 0; cc < u->size(); cc ++ )
        {
        os << "\t\t<File Directory=\"" << (*u)[cc].first << "\">"
          << (*u)[cc].second << "</File>" << std::endl;
        }
      os << "\t</Author>" << std::endl;
      }

    //std::cout << "End" << std::endl;
    std::string end_time = ::CurrentTime();
    os << "\t<EndDateTime>" << end_time << "</EndDateTime>\n"
      << "</Update>" << std::endl;

    if ( ofs )
      {
      ofs.close();
      }
Andy Cedilnik's avatar
Andy Cedilnik committed
999
1000
    }

1001
1002
1003
  if (! res || retVal )
    {
    std::cerr << "Error(s) when updating the project" << std::endl;
1004
    std::cerr << "Output: " << goutput << std::endl;
Andy Cedilnik's avatar
Andy Cedilnik committed
1005
    return -1;
1006
    }
Andy Cedilnik's avatar
Andy Cedilnik committed
1007
  return count;
1008
1009
1010
1011
}

int cmCTest::ConfigureDirectory()
{
1012
  std::cout << "Configure project" << std::endl;
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
  std::string cCommand = m_DartConfiguration["ConfigureCommand"];
  if ( cCommand.size() == 0 )
    {
    std::cerr << "Cannot find ConfigureCommand key in the DartConfiguration.tcl" 
              << std::endl;
    return 1;
    }

  std::string buildDirectory = m_DartConfiguration["BuildDirectory"];
  if ( buildDirectory.size() == 0 )
    {
    std::cerr << "Cannot find BuildDirectory  key in the DartConfiguration.tcl" << std::endl;
    return 1;
    }

  std::string output;
  int retVal = 0;
1030
  int res = 0;
1031
1032
  if ( !m_ShowOnly )
    {
Andy Cedilnik's avatar
Andy Cedilnik committed
1033
    std::ofstream os; 
1034
    if ( !this->OpenOutputFile(m_CurrentTag, "Configure.xml", os) )
Andy Cedilnik's avatar
Andy Cedilnik committed
1035
      {
1036
1037
      std::cerr << "Cannot open configure file" << std::endl;
      return 1;
Andy Cedilnik's avatar
Andy Cedilnik committed
1038
1039
1040
      }
    std::string start_time = ::CurrentTime();

1041
    std::ofstream ofs;
1042
1043
1044
    this->OpenOutputFile("Temporary", "LastConfigure.log", ofs);
    res = this->RunMakeCommand(cCommand.c_str(), &output, 
      &retVal, buildDirectory.c_str(),
1045
      m_Verbose, 0, ofs);
1046
1047

    if ( ofs )
1048
1049
1050
      {
      ofs.close();
      }
Andy Cedilnik's avatar
Andy Cedilnik committed
1051
1052
1053
    
    if ( os )
      {
1054
1055
      this->StartXML(os);
      os << "<Configure>\n"
Andy Cedilnik's avatar
Andy Cedilnik committed
1056
         << "\t<StartDateTime>" << start_time << "</StartDateTime>" << std::endl;
1057
      if ( res == cmsysProcess_State_Exited && retVal )
Andy Cedilnik's avatar
Andy Cedilnik committed
1058
1059
1060
1061
1062
        {
        os << retVal;
        }
      os << "<ConfigureCommand>" << cCommand.c_str() << "</ConfigureCommand>" << std::endl;
      //std::cout << "End" << std::endl;
Andy Cedilnik's avatar
Andy Cedilnik committed
1063
      os << "<Log>" << this->MakeXMLSafe(output) << "</Log>" << std::endl;
Andy Cedilnik's avatar
Andy Cedilnik committed
1064
      std::string end_time = ::CurrentTime();
Andy Cedilnik's avatar
Andy Cedilnik committed
1065
1066
      os << "\t<ConfigureStatus>" << retVal << "</ConfigureStatus>\n"
         << "\t<EndDateTime>" << end_time << "</EndDateTime>\n"
1067
1068
         << "</Configure>" << std::endl;
      this->EndXML(os);
Andy Cedilnik's avatar
Andy Cedilnik committed
1069
      }    
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
    }
  else
    {
    std::cout << "Configure with command: " << cCommand << std::endl;
    }
  if (! res || retVal )
    {
    std::cerr << "Error(s) when updating the project" << std::endl;
    return 1;
    }
  return 0;
}

int cmCTest::BuildDirectory()
{
1085
  std::cout << "Build project" << std::endl;
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
  std::string makeCommand = m_DartConfiguration["MakeCommand"];
  if ( makeCommand.size() == 0 )
    {
    std::cerr << "Cannot find MakeCommand key in the DartConfiguration.tcl" << std::endl;
    return 1;
    }
  std::string buildDirectory = m_DartConfiguration["BuildDirectory"];
  if ( buildDirectory.size() == 0 )
    {
    std::cerr << "Cannot find BuildDirectory  key in the DartConfiguration.tcl" << std::endl;
    return 1;
    }

1099
1100
1101
1102
1103
  std::ofstream ofs;
  if ( !this->OpenOutputFile("Temporary", "LastBuild.log", ofs) )
    {
    std::cerr << "Cannot create LastBuild.log file" << std::endl;    
    }
1104
1105
1106
  m_StartBuild = ::CurrentTime();
  std::string output;
  int retVal = 0;
1107
  int res = cmsysProcess_State_Exited;
1108
1109
  if ( !m_ShowOnly )
    {
1110
    res = this->RunMakeCommand(makeCommand.c_str(), &output, 
Andy Cedilnik's avatar
Andy Cedilnik committed
1111
      &retVal, buildDirectory.c_str(), 
1112
      m_Verbose, 0, ofs);
1113
1114
1115
1116
1117
1118
    }
  else
    {
    std::cout << "Build with command: " << makeCommand << std::endl;
    }
  m_EndBuild = ::CurrentTime();
1119
  if (res != cmsysProcess_State_Exited || retVal )
1120
1121
1122
    {
    std::cerr << "Error(s) when building project" << std::endl;
    }
1123
1124
1125
1126
  if ( ofs )
    {
    ofs.close();
    }
1127

1128
  tm_VectorOfStrings::size_type cc;
1129
1130
  if ( m_DartConfiguration["SourceDirectory"].size() > 20 ||
    m_DartConfiguration["BuildDirectory"].size() > 20 )
1131
    {
1132
1133
1134
1135
1136
    std::string srcdir = m_DartConfiguration["SourceDirectory"] + "/";
    std::string bindir = m_DartConfiguration["BuildDirectory"] + "/";
    std::string srcdirrep;
    std::string bindirrep;
    for ( cc = srcdir.size()-2; cc > 0; cc -- )
1137
      {
1138
1139
1140
1141
1142
1143
1144
      if ( srcdir[cc] == '/' )
        {
        srcdirrep = srcdir.c_str() + cc;
        srcdirrep = "/..." + srcdirrep;
        srcdir = srcdir.substr(0, cc+1);
        break;
        }
1145
      }
1146
    for ( cc = bindir.size()-2; cc > 0; cc -- )
1147
      {
1148
1149
1150
1151
1152
1153
1154
      if ( bindir[cc] == '/' )
        {
        bindirrep = bindir.c_str() + cc;
        bindirrep = "/..." + bindirrep;
        bindir = bindir.substr(0, cc+1);
        break;
        }
1155
1156
      }

1157
1158
1159
    cmSystemTools::ReplaceString(output, srcdir.c_str(), "/.../"); //srcdirrep.c_str());
    cmSystemTools::ReplaceString(output, bindir.c_str(), "/.../"); //bindirrep.c_str());
    }
1160

1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
  // Parsing of output for errors and warnings.

  std::vector<cmStdString> lines;
  cmSystemTools::Split(output.c_str(), lines);

  
  // Lines are marked: 
  // 0 - nothing
  // 1 - error
  // > 1 - warning
  std::vector<int> markedLines(lines.size(), 0);
  
  // Errors
  for ( cc = 0; cmCTestErrorMatches[cc]; cc ++ )
    {
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
    m_CustomErrorMatches.push_back(cmCTestErrorMatches[cc]);
    }
  for ( cc = 0; cmCTestErrorExceptions[cc]; cc ++ )
    {
    m_CustomErrorExceptions.push_back(cmCTestErrorExceptions[cc]);
    }
  for ( cc = 0; cmCTestWarningMatches[cc]; cc ++ )
    {
    m_CustomWarningMatches.push_back(cmCTestWarningMatches[cc]);
    }
  for ( cc = 0; cmCTestWarningExceptions[cc]; cc ++ )
    {
    m_CustomWarningExceptions.push_back(cmCTestWarningExceptions[cc]);
    }

  for ( cc = 0; cc < m_CustomErrorMatches.size(); cc ++ )
    {
    cmsys::RegularExpression re(m_CustomErrorMatches[cc].c_str());
1194
    cmCTest::tm_VectorOfStrings::size_type kk;
1195
1196
1197
1198
1199
1200
1201
1202
1203
    for ( kk = 0; kk < lines.size(); kk ++ )
      {
      if ( re.find(lines[kk]) )
        {
        markedLines[kk] = 1;
        }
      }    
    }
  // Warnings
1204
  for ( cc = 0; cc < m_CustomWarningMatches.size(); cc ++ )
1205
    {
1206
    cmsys::RegularExpression re(m_CustomWarningMatches[cc].c_str());
1207
    cmCTest::tm_VectorOfStrings::size_type kk;
1208
1209
1210
1211
1212
1213
1214
1215
1216
    for ( kk = 0; kk < lines.size(); kk ++ )
      {
      if ( re.find(lines[kk]) )
        {
        markedLines[kk] += 2;
        }
      }    
    }
  // Errors exceptions
1217
  for ( cc = 0; cc < m_CustomErrorExceptions.size(); cc ++ )
1218
    {
1219
    cmsys::RegularExpression re(m_CustomErrorExceptions[cc].c_str());
1220
1221
1222
    std::vector<int>::size_type kk;
    for ( kk =0; kk < markedLines.size(); kk ++ )
      {
Andy Cedilnik's avatar
Andy Cedilnik committed
1223
      if ( markedLines[kk] == 1 )
1224
1225
1226
        {
        if ( re.find(lines[kk]) )
          {
Andy Cedilnik's avatar
Andy Cedilnik committed
1227
          markedLines[kk] = 0;
1228
1229
1230
1231
1232
          }
        }
      }
    }
  // Warning exceptions
1233
  for ( cc = 0; cc < m_CustomWarningExceptions.size(); cc ++ )
1234
    {
1235
    cmsys::RegularExpression re(m_CustomWarningExceptions[cc].c_str());
1236
1237
1238
    std::vector<int>::size_type kk;
    for ( kk =0; kk < markedLines.size(); kk ++ )
      {
Andy Cedilnik's avatar
Andy Cedilnik committed
1239
      if ( markedLines[kk] > 1 )
1240
1241
1242
        {
        if ( re.find(lines[kk]) )
          {
Andy Cedilnik's avatar
Andy Cedilnik committed
1243
          markedLines[kk] = 0;
1244
1245
1246
1247
1248
1249
          }
        }
      }
    }
  std::vector<cmCTestBuildErrorWarning> errorsWarnings;

1250
1251
1252
  int errors = 0;
  int warnings = 0;

1253
1254
1255
1256
1257
1258
1259
1260
  std::vector<int>::size_type kk;
  cmCTestBuildErrorWarning errorwarning;
  for ( kk =0; kk < markedLines.size(); kk ++ )
    {
    errorwarning.m_LineNumber = -1;
    bool found = false;
    if ( markedLines[kk] == 1 )
      {
1261
      //std::cout << "Error: " << lines[kk] << std::endl;
1262
1263
1264
1265
1266
      errorwarning.m_Error = true;
      found = true;
      }
    else if ( markedLines[kk] > 1 )
      {
1267
      //std::cout << "Warning: " << lines[kk] << std::endl;
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
      errorwarning.m_Error = false;
      found = true;
      }
    if ( found )
      {
      errorwarning.m_LogLine     = static_cast<int>(kk+1);
      errorwarning.m_Text        = lines[kk];
      errorwarning.m_PreContext  = "";
      errorwarning.m_PostContext = "";
      std::vector<int>::size_type jj;
      std::vector<int>::size_type ll = 0;
      if ( kk > 6 )
        {
        ll = kk - 6;
        }
1283
1284
      for ( jj = kk-1; 
            jj > 0 && jj > ll && markedLines[jj] != markedLines[kk]; 
1285
            jj -- );
1286
1287
1288
1289
      while ( markedLines[jj] == markedLines[kk] && jj < kk )
        {
        jj ++;
        }
1290
1291
1292
1293
1294
      for (; jj < kk; jj ++ )
        {
        errorwarning.m_PreContext += lines[jj] + "\n";
        }
      for ( jj = kk+1; 
1295
            jj < lines.size() && jj < kk + 7 && markedLines[jj] != markedLines[kk]; 
1296
1297
1298
1299
1300
            jj ++ )
        {
        errorwarning.m_PostContext += lines[jj] + "\n";
        }
      errorsWarnings.push_back(errorwarning);
1301
1302
1303
1304
1305
1306
1307
1308
      if ( errorwarning.m_Error )
        {
        errors ++;
        }
      else
        {
        warnings ++;
        }
1309
1310
1311
      }
    }

1312
1313
1314
  std::cout << "   " << errors << " Compiler errors" << std::endl;
  std::cout << "   " << warnings << " Compiler warnings" << std::endl;

1315
  if( !this->OpenOutputFile(m_CurrentTag, "Build.xml", ofs) )
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
    {
    std::cerr << "Cannot create build XML file" << std::endl;
    return 1;
    }
  this->GenerateDartBuildOutput(ofs, errorsWarnings);
  return 0;
}
 
int cmCTest::CoverageDirectory()
{
1326
  std::cout << "Performing coverage" << std::endl;
1327
1328
1329
  cmCTest::tm_VectorOfStrings files;
  cmCTest::tm_VectorOfStrings cfiles;
  cmCTest::tm_VectorOfStrings cdirs;
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
  bool done = false;
  std::string::size_type cc;
  std::string glob;
  std::map<std::string, std::string> allsourcefiles;
  std::map<std::string, std::string> allbinaryfiles;

  std::string start_time = ::CurrentTime();

  // Find all source files.
  std::string sourceDirectory = m_DartConfiguration["SourceDirectory"];
  if ( sourceDirectory.size() == 0 )
    {
1342
1343
1344
1345
1346
1347
1348
1349
    std::cerr << "Cannot find SourceDirectory key in the DartConfiguration.tcl" << std::endl;
    return 1;
    }

  std::string coverageCommand = m_DartConfiguration["CoverageCommand"];
  if ( coverageCommand.size() == 0 )
    {
    std::cerr << "Coverage command not defined in DartConfiguration.tcl" << std::endl;
1350