Imported Upstream version 2.8.9
[platform/upstream/cmake.git] / Source / cmSetCommand.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 "cmSetCommand.h"
13
14 // cmSetCommand
15 bool cmSetCommand
16 ::InitialPass(std::vector<std::string> const& args, cmExecutionStatus &)
17 {
18   if(args.size() < 1 )
19     {
20     this->SetError("called with incorrect number of arguments");
21     return false;
22     }
23   
24   // watch for ENV signatures
25   const char* variable = args[0].c_str(); // VAR is always first
26   if (!strncmp(variable,"ENV{",4) && strlen(variable) > 5)
27     {
28     // what is the variable name
29     char *varName = new char [strlen(variable)];
30     strncpy(varName,variable+4,strlen(variable)-5);
31     varName[strlen(variable)-5] = '\0';
32     std::string putEnvArg = varName;
33     putEnvArg += "=";
34     
35     // what is the current value if any
36     const char *currValue = getenv(varName);
37     delete [] varName;
38
39     // will it be set to something, then set it
40     if (args.size() > 1 && args[1].size())
41       {
42       // but only if it is different from current value
43       if (!currValue || strcmp(currValue,args[1].c_str()))
44         {
45         putEnvArg += args[1];
46         cmSystemTools::PutEnv(putEnvArg.c_str());
47         }
48       return true;
49       }
50     
51     // if it will be cleared, then clear it if it isn;t already clear
52     if (currValue)
53       {
54       cmSystemTools::PutEnv(putEnvArg.c_str());
55       }
56     return true;
57     }
58   
59   // SET (VAR) // Removes the definition of VAR.
60   if (args.size() == 1)
61     {
62     this->Makefile->RemoveDefinition(args[0].c_str());
63     return true;
64     }
65
66   // here are the remaining options 
67   //  SET (VAR value )
68   //  SET (VAR CACHE TYPE "doc String" [FORCE])
69   //  SET (VAR value CACHE TYPE "doc string" [FORCE])
70   std::string value;  // optional
71   bool cache = false; // optional
72   bool force = false; // optional
73   bool parentScope = false;
74   cmCacheManager::CacheEntryType type 
75     = cmCacheManager::STRING; // required if cache
76   const char* docstring = 0; // required if cache
77   
78   unsigned int ignoreLastArgs = 0;
79   // look for PARENT_SCOPE argument
80   if (args.size() > 1 && args[args.size()-1] == "PARENT_SCOPE")
81     {
82     parentScope = true;
83     ignoreLastArgs++;
84     }
85   else
86     {
87     // look for FORCE argument
88     if (args.size() > 4 && args[args.size()-1] == "FORCE")
89       {
90       force = true;
91       ignoreLastArgs++;
92       }
93
94     // check for cache signature
95     if (args.size() > 3 && args[args.size() - 3 - (force ? 1 : 0)] == "CACHE")
96       {
97       cache = true;
98       ignoreLastArgs+=3;
99       }
100     }
101
102   // collect any values into a single semi-colon separated value list
103   if(static_cast<unsigned short>(args.size()) >
104      static_cast<unsigned short>(1 + ignoreLastArgs))
105     {
106     value = args[1];
107     size_t endPos = args.size() - ignoreLastArgs;
108     for(size_t i = 2; i < endPos; ++i)
109       {
110       value += ";";
111       value += args[i];
112       }
113     }
114
115   if (parentScope)
116     {
117     if (value.empty())
118       {
119       this->Makefile->RaiseScope(variable, 0);
120       }
121     else
122       {
123       this->Makefile->RaiseScope(variable, value.c_str());
124       }
125       return true;
126     }
127
128
129   // we should be nice and try to catch some simple screwups if the last or
130   // next to last args are CACHE then they screwed up.  If they used FORCE
131   // without CACHE they screwed up
132   if ((args[args.size() - 1] == "CACHE") ||
133       (args.size() > 1 && args[args.size() - 2] == "CACHE") ||
134       (force && !cache))
135     {
136     this->SetError("given invalid arguments for CACHE mode.");
137     return false;
138     }
139   
140   if(cache)
141     {
142     std::string::size_type cacheStart = args.size() - 3 - (force ? 1 : 0);
143     type = cmCacheManager::StringToType(args[cacheStart+1].c_str());
144     docstring = args[cacheStart+2].c_str();
145     }
146
147   // see if this is already in the cache
148   cmCacheManager::CacheIterator it = 
149     this->Makefile->GetCacheManager()->GetCacheIterator(variable);
150   if(!it.IsAtEnd() && (it.GetType() != cmCacheManager::UNINITIALIZED))
151     {
152     // if the set is trying to CACHE the value but the value
153     // is already in the cache and the type is not internal
154     // then leave now without setting any definitions in the cache
155     // or the makefile
156     if(cache && type != cmCacheManager::INTERNAL && !force)
157       {
158       return true;
159       }
160     }
161   
162   // if it is meant to be in the cache then define it in the cache
163   if(cache)
164     {
165     this->Makefile->AddCacheDefinition(variable,
166                                    value.c_str(),
167                                    docstring,
168                                    type, force);
169     }
170   else
171     {
172     // add the definition
173     this->Makefile->AddDefinition(variable, value.c_str());
174     }
175   return true;
176 }
177