Resync. Trying to resolve Git resync goof.
[CMakeLuaTailorHgBridge.git] / CMakeLua / Source / .#cmIfCommand.cxx.1.84
blobbfe24d02f34b1b0aa3acf0a225f35f18548c268b
1 /*=========================================================================
3   Program:   CMake - Cross-Platform Makefile Generator
4   Module:    $RCSfile: cmIfCommand.cxx,v $
5   Language:  C++
6   Date:      $Date: 2008/03/01 02:33:33 $
7   Version:   $Revision: 1.84 $
9   Copyright (c) 2002 Kitware, Inc., Insight Consortium.  All rights reserved.
10   See Copyright.txt or http://www.cmake.org/HTML/Copyright.html for details.
12      This software is distributed WITHOUT ANY WARRANTY; without even 
13      the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
14      PURPOSE.  See the above copyright notices for more information.
16 =========================================================================*/
17 #include "cmIfCommand.h"
18 #include "cmStringCommand.h"
20 #include <stdlib.h> // required for atof
21 #include <list>
22 #include <cmsys/RegularExpression.hxx>
24 bool cmIfFunctionBlocker::
25 IsFunctionBlocked(const cmListFileFunction& lff, cmMakefile &mf,
26                   cmExecutionStatus &inStatus)
28   // Prevent recusion and don't let this blocker block its own
29   // commands.
30   if (this->Executing)
31     {
32     return false;
33     }
35   // we start by recording all the functions
36   if (!cmSystemTools::Strucmp(lff.Name.c_str(),"if"))
37     {
38     this->ScopeDepth++;
39     }
40   if (!cmSystemTools::Strucmp(lff.Name.c_str(),"endif"))
41     {
42     this->ScopeDepth--;
43     // if this is the endif for this if statement, then start executing
44     if (!this->ScopeDepth) 
45       {
46       // execute the functions for the true parts of the if statement
47       this->Executing = true;
48       cmExecutionStatus status;
49       int scopeDepth = 0;
50       for(unsigned int c = 0; c < this->Functions.size(); ++c)
51         {
52         // keep track of scope depth
53         if (!cmSystemTools::Strucmp(this->Functions[c].Name.c_str(),"if"))
54           {
55           scopeDepth++;
56           }
57         if (!cmSystemTools::Strucmp(this->Functions[c].Name.c_str(),"endif"))
58           {
59           scopeDepth--;
60           }
61         // watch for our state change
62         if (scopeDepth == 0 &&
63             !cmSystemTools::Strucmp(this->Functions[c].Name.c_str(),"else"))
64           {
65           this->IsBlocking = this->HasRun;
66           this->HasRun = true;
67           }
68         else if (scopeDepth == 0 && !cmSystemTools::Strucmp
69                  (this->Functions[c].Name.c_str(),"elseif"))
70           {
71           if (this->HasRun)
72             {
73             this->IsBlocking = true;
74             }
75           else
76             {
77             char* errorString = 0;
78             
79             std::vector<std::string> expandedArguments;
80             mf.ExpandArguments(this->Functions[c].Arguments, 
81                                expandedArguments);
82             bool isTrue = 
83               cmIfCommand::IsTrue(expandedArguments,&errorString,&mf);
84             
85             if (errorString)
86               {
87               std::string err = "had incorrect arguments: ";
88               unsigned int i;
89               for(i =0; i < this->Functions[c].Arguments.size(); ++i)
90                 {
91                 err += (this->Functions[c].Arguments[i].Quoted?"\"":"");
92                 err += this->Functions[c].Arguments[i].Value;
93                 err += (this->Functions[c].Arguments[i].Quoted?"\"":"");
94                 err += " ";
95                 }
96               err += "(";
97               err += errorString;
98               err += ").";
99               cmSystemTools::Error(err.c_str());
100               delete [] errorString;
101               return false;
102               }
103         
104             if (isTrue)
105               {
106               this->IsBlocking = false;
107               this->HasRun = true;
108               }
109             }
110           }
111             
112         // should we execute?
113         else if (!this->IsBlocking)
114           {
115           status.Clear();
116           mf.ExecuteCommand(this->Functions[c],status);
117           if (status.GetReturnInvoked())
118             {
119             inStatus.SetReturnInvoked(true);
120             mf.RemoveFunctionBlocker(lff);
121             return true;
122             }
123           if (status.GetBreakInvoked())
124             {
125             inStatus.SetBreakInvoked(true);
126             mf.RemoveFunctionBlocker(lff);
127             return true;
128             }
129           }
130         }
131       mf.RemoveFunctionBlocker(lff);
132       return true;
133       }
134     }
135   
136   // record the command
137   this->Functions.push_back(lff);
138   
139   // always return true
140   return true;
143 bool cmIfFunctionBlocker::ShouldRemove(const cmListFileFunction& lff,
144                                        cmMakefile&)
146   if (!cmSystemTools::Strucmp(lff.Name.c_str(),"endif"))
147     {
148     // if the endif has arguments, then make sure
149     // they match the arguments of the matching if
150     if (lff.Arguments.size() == 0 ||
151         lff.Arguments == this->Args)
152       {
153       return true;
154       }
155     }
157   return false;
160 void cmIfFunctionBlocker::
161 ScopeEnded(cmMakefile &mf)
163   std::string errmsg = "The end of a CMakeLists file was reached with an "
164     "IF statement that was not closed properly.\nWithin the directory: ";
165   errmsg += mf.GetCurrentDirectory();
166   errmsg += "\nThe arguments are: ";
167   for(std::vector<cmListFileArgument>::const_iterator j = this->Args.begin();
168       j != this->Args.end(); ++j)
169     {   
170     errmsg += (j->Quoted?"\"":"");
171     errmsg += j->Value;
172     errmsg += (j->Quoted?"\"":"");
173     errmsg += " ";
174     }
175   cmSystemTools::Message(errmsg.c_str(), "Warning");
178 bool cmIfCommand
179 ::InvokeInitialPass(const std::vector<cmListFileArgument>& args, 
180                     cmExecutionStatus &)
182   char* errorString = 0;
183   
184   std::vector<std::string> expandedArguments;
185   this->Makefile->ExpandArguments(args, expandedArguments);
186   bool isTrue = 
187     cmIfCommand::IsTrue(expandedArguments,&errorString,this->Makefile);
188   
189   if (errorString)
190     {
191     std::string err = "had incorrect arguments: ";
192     unsigned int i;
193     for(i =0; i < args.size(); ++i)
194       {
195       err += (args[i].Quoted?"\"":"");
196       err += args[i].Value;
197       err += (args[i].Quoted?"\"":"");
198       err += " ";
199       }
200     err += "(";
201     err += errorString;
202     err += ").";
203     this->SetError(err.c_str());
204     delete [] errorString;
205     return false;
206     }
207   
208   cmIfFunctionBlocker *f = new cmIfFunctionBlocker();
209   // if is isn't true block the commands
210   f->ScopeDepth = 1;
211   f->IsBlocking = !isTrue;
212   if (isTrue)
213     {
214     f->HasRun = true;
215     }
216   f->Args = args;
217   this->Makefile->AddFunctionBlocker(f);
218   
219   return true;
222 namespace 
224   void IncrementArguments(std::list<std::string> &newArgs,
225                           std::list<std::string>::iterator &argP1,
226                           std::list<std::string>::iterator &argP2)
227   {
228     if (argP1  != newArgs.end())
229       {
230       argP1++;
231       argP2 = argP1;
232       if (argP1  != newArgs.end())
233         {
234         argP2++;
235         }
236       }
237   }
241 // order of operations, 
242 // IS_DIRECTORY EXISTS COMMAND DEFINED 
243 // MATCHES LESS GREATER EQUAL STRLESS STRGREATER STREQUAL 
244 // AND OR
246 // There is an issue on whether the arguments should be values of references,
247 // for example IF (FOO AND BAR) should that compare the strings FOO and BAR
248 // or should it really do IF (${FOO} AND ${BAR}) Currently IS_DIRECTORY
249 // EXISTS COMMAND and DEFINED all take values. EQUAL, LESS and GREATER can
250 // take numeric values or variable names. STRLESS and STRGREATER take
251 // variable names but if the variable name is not found it will use the name
252 // directly. AND OR take variables or the values 0 or 1.
255 bool cmIfCommand::IsTrue(const std::vector<std::string> &args,
256                          char **errorString, cmMakefile *makefile)
258   // check for the different signatures
259   const char *def;
260   const char *def2;
261   const char* msg = "Unknown arguments specified";
262   *errorString = new char[strlen(msg) + 1];
263   strcpy(*errorString, msg);
265   // handle empty invocation
266   if (args.size() < 1)
267     {
268     delete [] *errorString;
269     *errorString = 0;
270     return false;
271     }
273   // store the reduced args in this vector
274   std::list<std::string> newArgs;
275   int reducible;
276   unsigned int i;
278   // copy to the list structure
279   for(i = 0; i < args.size(); ++i)
280     {   
281     newArgs.push_back(args[i]);
282     }
283   std::list<std::string>::iterator argP1;
284   std::list<std::string>::iterator argP2;
286   // now loop through the arguments and see if we can reduce any of them
287   // we do this multiple times. Once for each level of precedence
288   do
289     {
290     reducible = 0;
291     std::list<std::string>::iterator arg = newArgs.begin();
292     while (arg != newArgs.end())
293       {
294       argP1 = arg;
295       IncrementArguments(newArgs,argP1,argP2);
296       // does a file exist
297       if (*arg == "EXISTS" && argP1  != newArgs.end())
298         {
299         if(cmSystemTools::FileExists((argP1)->c_str()))
300           {
301           *arg = "1";
302           }
303         else 
304           {
305           *arg = "0";
306           }
307         newArgs.erase(argP1);
308         argP1 = arg;
309         IncrementArguments(newArgs,argP1,argP2);
310         reducible = 1;
311         }
312       // does a directory with this name exist
313       if (*arg == "IS_DIRECTORY" && argP1  != newArgs.end())
314         {
315         if(cmSystemTools::FileIsDirectory((argP1)->c_str()))
316           {
317           *arg = "1";
318           }
319         else 
320           {
321           *arg = "0";
322           }
323         newArgs.erase(argP1);
324         argP1 = arg;
325         IncrementArguments(newArgs,argP1,argP2);
326         reducible = 1;
327         }
328       // is the given path an absolute path ?
329       if (*arg == "IS_ABSOLUTE" && argP1  != newArgs.end())
330         {
331         if(cmSystemTools::FileIsFullPath((argP1)->c_str()))
332           {
333           *arg = "1";
334           }
335         else 
336           {
337           *arg = "0";
338           }
339         newArgs.erase(argP1);
340         argP1 = arg;
341         IncrementArguments(newArgs,argP1,argP2);
342         reducible = 1;
343         }
344       // does a command exist
345       if (*arg == "COMMAND" && argP1  != newArgs.end())
346         {
347         if(makefile->CommandExists((argP1)->c_str()))
348           {
349           *arg = "1";
350           }
351         else 
352           {
353           *arg = "0";
354           }
355         newArgs.erase(argP1);
356         argP1 = arg;
357         IncrementArguments(newArgs,argP1,argP2);
358         reducible = 1;
359         }
360       // is a variable defined
361       if (*arg == "DEFINED" && argP1  != newArgs.end())
362         {
363         size_t argP1len = argP1->size();
364         bool bdef = false;
365         if(argP1len > 4 && argP1->substr(0, 4) == "ENV{" &&
366            argP1->operator[](argP1len-1) == '}')
367           {
368           std::string env = argP1->substr(4, argP1len-5);
369           bdef = cmSystemTools::GetEnv(env.c_str())?true:false;
370           }
371         else
372           {
373           bdef = makefile->IsDefinitionSet((argP1)->c_str());
374           }
375         if(bdef)
376           {
377           *arg = "1";
378           }
379         else 
380           {
381           *arg = "0";
382           }
383         newArgs.erase(argP1);
384         argP1 = arg;
385         IncrementArguments(newArgs,argP1,argP2);
386         reducible = 1;
387         }
388       ++arg;
389       }
390     }
391   while (reducible);
394   // now loop through the arguments and see if we can reduce any of them
395   // we do this multiple times. Once for each level of precedence
396   do
397     {
398     reducible = 0;
399     std::list<std::string>::iterator arg = newArgs.begin();
401     while (arg != newArgs.end())
402       {
403       argP1 = arg;
404       IncrementArguments(newArgs,argP1,argP2);
405       if (argP1 != newArgs.end() && argP2 != newArgs.end() &&
406         *(argP1) == "MATCHES") 
407         {
408         def = cmIfCommand::GetVariableOrString(arg->c_str(), makefile);
409         const char* rex = (argP2)->c_str();
410         cmStringCommand::ClearMatches(makefile);
411         cmsys::RegularExpression regEntry;
412         if ( !regEntry.compile(rex) )
413           {
414           cmOStringStream error;
415           error << "Regular expression \"" << rex << "\" cannot compile";
416           delete [] *errorString;
417           *errorString = new char[error.str().size() + 1];
418           strcpy(*errorString, error.str().c_str());
419           return false;
420           }
421         if (regEntry.find(def))
422           {
423           cmStringCommand::StoreMatches(makefile, regEntry);
424           *arg = "1";
425           }
426         else
427           {
428           *arg = "0";
429           }
430         newArgs.erase(argP2);
431         newArgs.erase(argP1);
432         argP1 = arg;
433         IncrementArguments(newArgs,argP1,argP2);
434         reducible = 1;
435         }
437       if (argP1 != newArgs.end() && *arg == "MATCHES") 
438         {
439         *arg = "0";
440         newArgs.erase(argP1);
441         argP1 = arg;
442         IncrementArguments(newArgs,argP1,argP2);
443         reducible = 1;
444         }
446       if (argP1 != newArgs.end() && argP2 != newArgs.end() &&
447         (*(argP1) == "LESS" || *(argP1) == "GREATER" || 
448          *(argP1) == "EQUAL")) 
449         {
450         def = cmIfCommand::GetVariableOrString(arg->c_str(), makefile);
451         def2 = cmIfCommand::GetVariableOrString((argP2)->c_str(), makefile);
452         double lhs;
453         double rhs;
454         if(sscanf(def, "%lg", &lhs) != 1 ||
455            sscanf(def2, "%lg", &rhs) != 1)
456           {
457           *arg = "0";
458           }
459         else if (*(argP1) == "LESS")
460           {
461           if(lhs < rhs)
462             {
463             *arg = "1";
464             }
465           else
466             {
467             *arg = "0";
468             }
469           }
470         else if (*(argP1) == "GREATER")
471           {
472           if(lhs > rhs)
473             {
474             *arg = "1";
475             }
476           else
477             {
478             *arg = "0";
479             }
480           }          
481         else
482           {
483           if(lhs == rhs)
484             {
485             *arg = "1";
486             }
487           else
488             {
489             *arg = "0";
490             }
491           }          
492         newArgs.erase(argP2);
493         newArgs.erase(argP1);
494         argP1 = arg;
495         IncrementArguments(newArgs,argP1,argP2);
496         reducible = 1;
497         }
499       if (argP1 != newArgs.end() && argP2 != newArgs.end() &&
500         (*(argP1) == "STRLESS" || 
501          *(argP1) == "STREQUAL" || 
502          *(argP1) == "STRGREATER")) 
503         {
504         def = cmIfCommand::GetVariableOrString(arg->c_str(), makefile);
505         def2 = cmIfCommand::GetVariableOrString((argP2)->c_str(), makefile);
506         int val = strcmp(def,def2);
507         int result;
508         if (*(argP1) == "STRLESS")
509           {
510           result = (val < 0);
511           }
512         else if (*(argP1) == "STRGREATER")
513           {
514           result = (val > 0);
515           }
516         else // strequal
517           {
518           result = (val == 0);
519           }
520         if(result)
521           {
522           *arg = "1";
523           }
524         else
525           {
526           *arg = "0";
527           }
528         newArgs.erase(argP2);
529         newArgs.erase(argP1);
530         argP1 = arg;
531         IncrementArguments(newArgs,argP1,argP2);
532         reducible = 1;
533         }
535       // is file A newer than file B
536       if (argP1 != newArgs.end() && argP2 != newArgs.end() &&
537           *(argP1) == "IS_NEWER_THAN")
538         {
539         int fileIsNewer=0;
540         bool success=cmSystemTools::FileTimeCompare(arg->c_str(),
541             (argP2)->c_str(),
542             &fileIsNewer);
543         if(success==false || fileIsNewer==1 || fileIsNewer==0)
544           {
545           *arg = "1";
546           }
547         else
548           {
549           *arg = "0";
550           }
551         newArgs.erase(argP2);
552         newArgs.erase(argP1);
553         argP1 = arg;
554         IncrementArguments(newArgs,argP1,argP2);
555         reducible = 1;
556         }
558       ++arg;
559       }
560     }
561   while (reducible);
564   // now loop through the arguments and see if we can reduce any of them
565   // we do this multiple times. Once for each level of precedence
566   do
567     {
568     reducible = 0;
569     std::list<std::string>::iterator arg = newArgs.begin();
570     while (arg != newArgs.end())
571       {
572       argP1 = arg;
573       IncrementArguments(newArgs,argP1,argP2);
574       if (argP1 != newArgs.end() && *arg == "NOT")
575         {
576         def = cmIfCommand::GetVariableOrNumber((argP1)->c_str(), makefile);
577         if(!cmSystemTools::IsOff(def))
578           {
579           *arg = "0";
580           }
581         else
582           {
583           *arg = "1";
584           }
585         newArgs.erase(argP1);
586         argP1 = arg;
587         IncrementArguments(newArgs,argP1,argP2);
588         reducible = 1;
589         }
590       ++arg;
591       }
592     }
593   while (reducible);
595   // now loop through the arguments and see if we can reduce any of them
596   // we do this multiple times. Once for each level of precedence
597   do
598     {
599     reducible = 0;
600     std::list<std::string>::iterator arg = newArgs.begin();
601     while (arg != newArgs.end())
602       {
603       argP1 = arg;
604       IncrementArguments(newArgs,argP1,argP2);
605       if (argP1 != newArgs.end() && *(argP1) == "AND" && 
606         argP2 != newArgs.end())
607         {
608         def = cmIfCommand::GetVariableOrNumber(arg->c_str(), makefile);
609         def2 = cmIfCommand::GetVariableOrNumber((argP2)->c_str(), makefile);
610         if(cmSystemTools::IsOff(def) || cmSystemTools::IsOff(def2))
611           {
612           *arg = "0";
613           }
614         else
615           {
616           *arg = "1";
617           }
618         newArgs.erase(argP2);
619         newArgs.erase(argP1);
620         argP1 = arg;
621         IncrementArguments(newArgs,argP1,argP2);
622         reducible = 1;
623         }
625       if (argP1 != newArgs.end() && *(argP1) == "OR" && 
626         argP2 != newArgs.end())
627         {
628         def = cmIfCommand::GetVariableOrNumber(arg->c_str(), makefile);
629         def2 = cmIfCommand::GetVariableOrNumber((argP2)->c_str(), makefile);
630         if(cmSystemTools::IsOff(def) && cmSystemTools::IsOff(def2))
631           {
632           *arg = "0";
633           }
634         else
635           {
636           *arg = "1";
637           }
638         newArgs.erase(argP2);
639         newArgs.erase(argP1);
640         argP1 = arg;
641         IncrementArguments(newArgs,argP1,argP2);
642         reducible = 1;
643         }
645       ++arg;
646       }
647     }
648   while (reducible);
650   // now at the end there should only be one argument left
651   if (newArgs.size() == 1)
652     {
653     delete [] *errorString;
654     *errorString = 0;
655     if (*newArgs.begin() == "0")
656       {
657       return false;
658       }
659     if (*newArgs.begin() == "1")
660       {
661       return true;
662       }
663     def = makefile->GetDefinition(args[0].c_str());
664     if(cmSystemTools::IsOff(def))
665       {
666       return false;
667       }
668     }
670   return true;
673 const char* cmIfCommand::GetVariableOrString(const char* str,
674                                              const cmMakefile* mf)
676   const char* def = mf->GetDefinition(str);
677   if(!def)
678     {
679     def = str;
680     }
681   return def;
684 const char* cmIfCommand::GetVariableOrNumber(const char* str,
685                                              const cmMakefile* mf)
687   const char* def = mf->GetDefinition(str);
688   if(!def)
689     {
690     if (atoi(str))
691       {
692       def = str;
693       }
694     }
695   return def;