Imported Upstream version 2.8.9
[platform/upstream/cmake.git] / Source / cmSetPropertyCommand.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 "cmSetPropertyCommand.h"
13 #include "cmSetTargetPropertiesCommand.h"
14 #include "cmSetTestsPropertiesCommand.h"
15 #include "cmSetSourceFilesPropertiesCommand.h"
16
17 #include "cmCacheManager.h"
18
19 //----------------------------------------------------------------------------
20 cmSetPropertyCommand::cmSetPropertyCommand()
21 {
22   this->AppendMode = false;
23   this->AppendAsString = false;
24   this->Remove = true;
25 }
26
27 //----------------------------------------------------------------------------
28 bool cmSetPropertyCommand
29 ::InitialPass(std::vector<std::string> const& args, cmExecutionStatus &)
30 {
31   if(args.size() < 2 )
32     {
33     this->SetError("called with incorrect number of arguments");
34     return false;
35     }
36
37   // Get the scope on which to set the property.
38   std::vector<std::string>::const_iterator arg = args.begin();
39   cmProperty::ScopeType scope;
40   if(*arg == "GLOBAL")
41     {
42     scope = cmProperty::GLOBAL;
43     }
44   else if(*arg == "DIRECTORY")
45     {
46     scope = cmProperty::DIRECTORY;
47     }
48   else if(*arg == "TARGET")
49     {
50     scope = cmProperty::TARGET;
51     }
52   else if(*arg == "SOURCE")
53     {
54     scope = cmProperty::SOURCE_FILE;
55     }
56   else if(*arg == "TEST")
57     {
58     scope = cmProperty::TEST;
59     }
60   else if(*arg == "CACHE")
61     {
62     scope = cmProperty::CACHE;
63     }
64   else
65     {
66     cmOStringStream e;
67     e << "given invalid scope " << *arg << ".  "
68       << "Valid scopes are GLOBAL, DIRECTORY, TARGET, SOURCE, TEST, CACHE.";
69     this->SetError(e.str().c_str());
70     return false;
71     }
72
73   // Parse the rest of the arguments up to the values.
74   enum Doing { DoingNone, DoingNames, DoingProperty, DoingValues };
75   Doing doing = DoingNames;
76   const char* sep = "";
77   for(++arg; arg != args.end(); ++arg)
78     {
79     if(*arg == "PROPERTY")
80       {
81       doing = DoingProperty;
82       }
83     else if(*arg == "APPEND")
84       {
85       doing = DoingNone;
86       this->AppendMode = true;
87       this->AppendAsString = false;
88       }
89     else if(*arg == "APPEND_STRING")
90       {
91       doing = DoingNone;
92       this->AppendMode = true;
93       this->AppendAsString = true;
94       }
95     else if(doing == DoingNames)
96       {
97       this->Names.insert(*arg);
98       }
99     else if(doing == DoingProperty)
100       {
101       this->PropertyName = *arg;
102       doing = DoingValues;
103       }
104     else if(doing == DoingValues)
105       {
106       this->PropertyValue += sep;
107       sep = ";";
108       this->PropertyValue += *arg;
109       this->Remove = false;
110       }
111     else
112       {
113       cmOStringStream e;
114       e << "given invalid argument \"" << *arg << "\".";
115       this->SetError(e.str().c_str());
116       return false;
117       }
118     }
119
120   // Make sure a property name was found.
121   if(this->PropertyName.empty())
122     {
123     this->SetError("not given a PROPERTY <name> argument.");
124     return false;
125     }
126
127   // Dispatch property setting.
128   switch(scope)
129     {
130     case cmProperty::GLOBAL:      return this->HandleGlobalMode();
131     case cmProperty::DIRECTORY:   return this->HandleDirectoryMode();
132     case cmProperty::TARGET:      return this->HandleTargetMode();
133     case cmProperty::SOURCE_FILE: return this->HandleSourceMode();
134     case cmProperty::TEST:        return this->HandleTestMode();
135     case cmProperty::CACHE:       return this->HandleCacheMode();
136
137     case cmProperty::VARIABLE:
138     case cmProperty::CACHED_VARIABLE:
139       break; // should never happen
140     }
141   return true;
142 }
143
144 //----------------------------------------------------------------------------
145 bool cmSetPropertyCommand::HandleGlobalMode()
146 {
147   if(!this->Names.empty())
148     {
149     this->SetError("given names for GLOBAL scope.");
150     return false;
151     }
152
153   // Set or append the property.
154   cmake* cm = this->Makefile->GetCMakeInstance();
155   const char* name = this->PropertyName.c_str();
156   const char *value = this->PropertyValue.c_str();
157   if (this->Remove)
158     {
159     value = 0;
160     }
161   if(this->AppendMode)
162     {
163     cm->AppendProperty(name, value, this->AppendAsString);
164     }
165   else
166     {
167     cm->SetProperty(name, value);
168     }
169
170   return true;
171 }
172
173 //----------------------------------------------------------------------------
174 bool cmSetPropertyCommand::HandleDirectoryMode()
175 {
176   if(this->Names.size() > 1)
177     {
178     this->SetError("allows at most one name for DIRECTORY scope.");
179     return false;
180     }
181
182   // Default to the current directory.
183   cmMakefile* mf = this->Makefile;
184
185   // Lookup the directory if given.
186   if(!this->Names.empty())
187     {
188     // Construct the directory name.  Interpret relative paths with
189     // respect to the current directory.
190     std::string dir = *this->Names.begin();
191     if(!cmSystemTools::FileIsFullPath(dir.c_str()))
192       {
193       dir = this->Makefile->GetCurrentDirectory();
194       dir += "/";
195       dir += *this->Names.begin();
196       }
197
198     // The local generators are associated with collapsed paths.
199     dir = cmSystemTools::CollapseFullPath(dir.c_str());
200
201     // Lookup the generator.
202     if(cmLocalGenerator* lg =
203        (this->Makefile->GetLocalGenerator()
204         ->GetGlobalGenerator()->FindLocalGenerator(dir.c_str())))
205       {
206       // Use the makefile for the directory found.
207       mf = lg->GetMakefile();
208       }
209     else
210       {
211       // Could not find the directory.
212       this->SetError
213         ("DIRECTORY scope provided but requested directory was not found. "
214          "This could be because the directory argument was invalid or, "
215          "it is valid but has not been processed yet.");
216       return false;
217       }
218     }
219
220   // Set or append the property.
221   const char* name = this->PropertyName.c_str();
222   const char *value = this->PropertyValue.c_str();
223   if (this->Remove)
224     {
225     value = 0;
226     }
227   if(this->AppendMode)
228     {
229     mf->AppendProperty(name, value, this->AppendAsString);
230     }
231   else
232     {
233     mf->SetProperty(name, value);
234     }
235
236   return true;
237 }
238
239 //----------------------------------------------------------------------------
240 bool cmSetPropertyCommand::HandleTargetMode()
241 {
242   for(std::set<cmStdString>::const_iterator ni = this->Names.begin();
243       ni != this->Names.end(); ++ni)
244     {
245     if(cmTarget* target = this->Makefile->FindTargetToUse(ni->c_str()))
246       {
247       // Handle the current target.
248       if(!this->HandleTarget(target))
249         {
250         return false;
251         }
252       }
253     else
254       {
255       cmOStringStream e;
256       e << "could not find TARGET " << *ni
257         << ".  Perhaps it has not yet been created.";
258       this->SetError(e.str().c_str());
259       return false;
260       }
261     }
262   return true;
263 }
264
265 //----------------------------------------------------------------------------
266 bool cmSetPropertyCommand::HandleTarget(cmTarget* target)
267 {
268   // Set or append the property.
269   const char* name = this->PropertyName.c_str();
270   const char *value = this->PropertyValue.c_str();
271   if (this->Remove)
272     {
273     value = 0;
274     }
275   if(this->AppendMode)
276     {
277     target->AppendProperty(name, value, this->AppendAsString);
278     }
279   else
280     {
281     target->SetProperty(name, value);
282     }
283
284   // Check the resulting value.
285   target->CheckProperty(name, this->Makefile);
286
287   return true;
288 }
289
290 //----------------------------------------------------------------------------
291 bool cmSetPropertyCommand::HandleSourceMode()
292 {
293   for(std::set<cmStdString>::const_iterator ni = this->Names.begin();
294       ni != this->Names.end(); ++ni)
295     {
296     // Get the source file.
297     if(cmSourceFile* sf = this->Makefile->GetOrCreateSource(ni->c_str()))
298       {
299       if(!this->HandleSource(sf))
300         {
301         return false;
302         }
303       }
304     else
305       {
306       cmOStringStream e;
307       e << "given SOURCE name that could not be found or created: " << *ni;
308       this->SetError(e.str().c_str());
309       return false;
310       }
311     }
312   return true;
313 }
314
315 //----------------------------------------------------------------------------
316 bool cmSetPropertyCommand::HandleSource(cmSourceFile* sf)
317 {
318   // Set or append the property.
319   const char* name = this->PropertyName.c_str();
320   const char *value = this->PropertyValue.c_str();
321   if (this->Remove)
322     {
323     value = 0;
324     }
325
326   if(this->AppendMode)
327     {
328     sf->AppendProperty(name, value, this->AppendAsString);
329     }
330   else
331     {
332     sf->SetProperty(name, value);
333     }
334   return true;
335 }
336
337 //----------------------------------------------------------------------------
338 bool cmSetPropertyCommand::HandleTestMode()
339 {
340   // Look for tests with all names given.
341   std::set<cmStdString>::iterator next;
342   for(std::set<cmStdString>::iterator ni = this->Names.begin();
343       ni != this->Names.end(); ni = next)
344     {
345     next = ni;
346     ++next;
347     if(cmTest* test = this->Makefile->GetTest(ni->c_str()))
348       {
349       if(this->HandleTest(test))
350         {
351         this->Names.erase(ni);
352         }
353       else
354         {
355         return false;
356         }
357       }
358     }
359
360   // Names that are still left were not found.
361   if(!this->Names.empty())
362     {
363     cmOStringStream e;
364     e << "given TEST names that do not exist:\n";
365     for(std::set<cmStdString>::const_iterator ni = this->Names.begin();
366         ni != this->Names.end(); ++ni)
367       {
368       e << "  " << *ni << "\n";
369       }
370     this->SetError(e.str().c_str());
371     return false;
372     }
373   return true;
374 }
375
376 //----------------------------------------------------------------------------
377 bool cmSetPropertyCommand::HandleTest(cmTest* test)
378 {
379   // Set or append the property.
380   const char* name = this->PropertyName.c_str();
381   const char *value = this->PropertyValue.c_str();
382   if (this->Remove)
383     {
384     value = 0;
385     }
386   if(this->AppendMode)
387     {
388     test->AppendProperty(name, value, this->AppendAsString);
389     }
390   else
391     {
392     test->SetProperty(name, value);
393     }
394
395   return true;
396 }
397
398 //----------------------------------------------------------------------------
399 bool cmSetPropertyCommand::HandleCacheMode()
400 {
401   if(this->PropertyName == "ADVANCED")
402     {
403     if(!this->Remove &&
404        !cmSystemTools::IsOn(this->PropertyValue.c_str()) &&
405        !cmSystemTools::IsOff(this->PropertyValue.c_str()))
406       {
407       cmOStringStream e;
408       e << "given non-boolean value \"" << this->PropertyValue
409         << "\" for CACHE property \"ADVANCED\".  ";
410       this->SetError(e.str().c_str());
411       return false;
412       }
413     }
414   else if(this->PropertyName == "TYPE")
415     {
416     if(!cmCacheManager::IsType(this->PropertyValue.c_str()))
417       {
418       cmOStringStream e;
419       e << "given invalid CACHE entry TYPE \"" << this->PropertyValue << "\"";
420       this->SetError(e.str().c_str());
421       return false;
422       }
423     }
424   else if(this->PropertyName != "HELPSTRING" &&
425           this->PropertyName != "STRINGS" &&
426           this->PropertyName != "VALUE")
427     {
428     cmOStringStream e;
429     e << "given invalid CACHE property " << this->PropertyName << ".  "
430       << "Settable CACHE properties are: "
431       << "ADVANCED, HELPSTRING, STRINGS, TYPE, and VALUE.";
432     this->SetError(e.str().c_str());
433     return false;
434     }
435
436   for(std::set<cmStdString>::const_iterator ni = this->Names.begin();
437       ni != this->Names.end(); ++ni)
438     {
439     // Get the source file.
440     cmMakefile* mf = this->GetMakefile();
441     cmake* cm = mf->GetCMakeInstance();
442     cmCacheManager::CacheIterator it =
443       cm->GetCacheManager()->GetCacheIterator(ni->c_str());
444     if(!it.IsAtEnd())
445       {
446       if(!this->HandleCacheEntry(it))
447         {
448         return false;
449         }
450       }
451     else
452       {
453       cmOStringStream e;
454       e << "could not find CACHE variable " << *ni
455         << ".  Perhaps it has not yet been created.";
456       this->SetError(e.str().c_str());
457       return false;
458       }
459     }
460   return true;
461 }
462
463 //----------------------------------------------------------------------------
464 bool cmSetPropertyCommand::HandleCacheEntry(cmCacheManager::CacheIterator& it)
465 {
466   // Set or append the property.
467   const char* name = this->PropertyName.c_str();
468   const char* value = this->PropertyValue.c_str();
469   if (this->Remove)
470     {
471     value = 0;
472     }
473   if(this->AppendMode)
474     {
475     it.AppendProperty(name, value, this->AppendAsString);
476     }
477   else
478     {
479     it.SetProperty(name, value);
480     }
481
482   return true;
483 }