ide: Memory leaks fixes
[sdk] / ide / src / project / ProjectConfig.ec
1 #ifndef MAKEFILE_GENERATOR
2 import "ide"
3 #endif
4
5 import "Project"
6
7 enum DirExpressionType { unknown, targetDir, intermediateObjectsDir };  // "type" is not right
8
9 class DirExpression : struct
10 {
11    char * dir;
12    DirExpressionType type;
13
14    ~DirExpression()
15    {
16       delete dir;
17    }
18
19    property char * dir
20    {
21       get
22       {
23          return dir ? dir : "";
24       }
25       set
26       {
27          delete dir;
28          if(value && value[0])
29             dir = CopyString(value);
30          else
31             dir = CopyString("");
32       }
33    }
34
35    void Evaluate(char * expression, Project project)
36    {
37       int len;
38       char * expr = expression;
39       if(!expr || !expr[0])
40       {
41          char buffer[MAX_LOCATION];
42          if(ideSettings)
43          {
44          if(type == targetDir)
45             expr = ideSettings.projectDefaultTargetDir;
46          else if(type == intermediateObjectsDir)
47             expr = ideSettings.projectDefaultIntermediateObjDir;
48          }
49          if(!expr || !expr[0])
50             expr = defaultObjDirExpression;
51       }
52       if((len = strlen(expr)))
53       {
54          int c, d;
55          CompilerConfig compiler = GetCompilerConfig();
56          ProjectConfig config = project.config;
57          char * configName = config && config.name && config.name[0] ? config.name : "Common";
58          char * projectName = project.name ? project.name : "";
59          char * moduleName = project.moduleName ? project.moduleName : "";
60          char * compilingPlatformName = GetRuntimePlatform();
61          char * compilerName = (compiler && compiler.name) ? compiler.name : defaultCompilerName;
62          char * targetPlatformName = compiler && compiler.targetPlatform ? compiler.targetPlatform : "";
63          char buffer[MAX_LOCATION];
64          for(c = 0, d = 0; c < len; c++)
65          {
66             if(expr[c] == '$' && c < len - 1 && expr[c + 1] == '(')
67             {
68                int i;
69                for(i = c + 2; i < len; i++)
70                {
71                   if(expr[i] == ')')
72                   {
73                      int n = i - c - 2;
74                      if(n > 0)
75                      {
76                         if(!strnicmp(&expr[c + 2], "Config", n) || !strnicmp(&expr[c + 2], "Config", n))
77                         {
78                            buffer[d] = '\0';
79                            strcat(buffer, configName);
80                            CamelCase(&buffer[d]);
81                            d += strlen(configName);
82                            c = i;
83                         }
84                         else if(!strnicmp(&expr[c + 2], "Module", n) || !strnicmp(&expr[c + 2], "Project", n))
85                         {
86                            buffer[d] = '\0';
87                            strcat(buffer, moduleName);
88                            //CamelCase(&buffer[d]);
89                            d += strlen(moduleName);
90                            c = i;
91                         }
92                         else if(!strnicmp(&expr[c + 2], "Platform", n))
93                         {
94                            buffer[d] = '\0';
95                            strcat(buffer, targetPlatformName);
96                            CamelCase(&buffer[d]);
97                            d += strlen(targetPlatformName);
98                            /*if(strcmpi(targetPlatformName, compilingPlatformName))
99                            {
100                               strcat(buffer, "~");
101                               d++;
102                               strcat(buffer, compilingPlatformName);
103                               d += strlen(compilingPlatformName);
104                            }*/
105                            c = i;
106                         }
107                         else if(!strnicmp(&expr[c + 2], "Compiler", n))
108                         {
109                            buffer[d] = '\0';
110                            strcat(buffer, compilerName);
111                            CamelCase(&buffer[d]);
112                            d += strlen(compilerName);
113                            c = i;
114                         }
115                         else
116                         {
117                            buffer[d++] = expr[c];
118                         }
119                      }
120                      else
121                      {
122                         buffer[d++] = expr[c];
123                      }
124                      i = len - 1;
125                      break;
126                   }
127                   else if(expr[i] == '\\' || expr[i] == '/')
128                   {
129                      buffer[d++] = '\0';
130                      strncat(buffer, &expr[i], i - c);
131                      d += i - c;
132                      c = i;
133                      i = len - 1;
134                      break;
135                   }
136                }
137                if(i == len)
138                   buffer[d++] = expr[c];
139             }
140             else
141             {
142                buffer[d++] = expr[c];
143             }
144          }
145          buffer[d] = '\0';
146          if(dir && strcmp(buffer, dir))
147             delete dir;
148          if(!dir)
149             dir = CopyString(buffer);
150          delete compiler;
151       }
152       else
153       {
154          delete dir;
155          dir = CopyString("");
156       }
157    }
158 }
159
160 public enum TargetTypes { unset, executable, sharedLibrary, staticLibrary };
161 public enum OptimizationStrategy { unset, none, speed, size };
162 public enum WarningsOption { unset, normal, none, all }; // TOCHECK: More options?
163
164 Array<String> CopyArrayString(Array<String> array)
165 {
166    Array<String> copy = null;
167    if(array)
168    {
169       copy = { };
170       for(s : array) copy.Add(CopyString(s));
171    }
172    return copy;
173 }
174
175 public class ProjectOptions
176 {
177 public:
178    // Compiler Options
179    property SetBool allWarnings
180    {
181       set
182       {
183          if(value == true)
184             warnings = all;
185       }
186    }
187    WarningsOption warnings;
188    SetBool debug;
189    SetBool memoryGuard;
190    SetBool profile;
191    SetBool noLineNumbers;
192    OptimizationStrategy optimization;
193    Array<String> preprocessorDefinitions;
194    property Array<String> includeDirs
195    {
196       set
197       {
198          if(includeDirs)
199             includeDirs.Free();
200          if(value && value.count)
201          {
202             if(!includeDirs)
203                includeDirs = { };
204             for(s : value)
205                includeDirs.Add(CopyValidateMakefilePath(s));
206             value.Free();
207             delete value;
208          }
209          else
210             delete includeDirs;
211       }
212       get { return includeDirs; }
213       isset { return  includeDirs && includeDirs.count; }
214    }
215    String defaultNameSpace;
216    SetBool strictNameSpaces;
217
218    // Linker Options
219    TargetTypes targetType;
220    // NOTE: The JSON Parser deletes strings after setting a String property, so we do a copy here.
221    //       (This behavior is different from Objects (class instances) values which are not deleted)
222    //       Code calling these properties should *NOT* use CopyString().
223    property char * targetFileName
224    {
225       set { delete targetFileName; if(value && value[0]) targetFileName = CopyValidateMakefilePath(value); }
226       get { return targetFileName; }
227       isset { return targetFileName && targetFileName[0]; }
228    }
229    property char * targetDirectory
230    {
231       set { delete targetDirectory; if(value /*&& value[0]*/) targetDirectory = CopyValidateMakefilePath(value); }
232       get { return targetDirectory; }
233       isset { return targetDirectory != null/*&& targetDirectory[0]*/; }
234    }
235    property char * objectsDirectory
236    {
237       set { delete objectsDirectory; if(value /*&& value[0]*/) objectsDirectory = CopyValidateMakefilePath(value); }
238       get { return objectsDirectory; }
239       isset { return objectsDirectory != null/*&& objectsDirectory[0]*/; }
240    }
241    Array<String> libraries;
242    Array<String> linkerOptions;
243    property Array<String> libraryDirs
244    {
245       set
246       {
247          if(libraryDirs)
248             libraryDirs.Free();
249          if(value && value.count)
250          {
251             if(!libraryDirs)
252                libraryDirs = { };
253             for(s : value)
254                libraryDirs.Add(CopyValidateMakefilePath(s));
255             value.Free(); // why do I have to do this here? it's a property, shouldn't json deal with this?
256             delete value;
257          }
258          else
259             delete libraryDirs;
260       }
261       get { return libraryDirs; }
262       isset { return  libraryDirs && libraryDirs.count; }
263    }
264    SetBool console;
265    SetBool compress;
266
267    SetBool excludeFromBuild;
268
269    property Array<String> prebuildCommands
270    {
271       set
272       {
273          if(prebuildCommands)
274             prebuildCommands.Free();
275          if(value && value.count)
276          {
277             if(!prebuildCommands)
278                prebuildCommands = { };
279             for(s : value)
280                prebuildCommands.Add(CopyValidateMakefilePath(s));
281             value.Free();
282             delete value;
283          }
284          else
285             delete prebuildCommands;
286       }
287       get { return prebuildCommands; }
288       isset { return  prebuildCommands && prebuildCommands.count; }
289    }
290    property Array<String> postbuildCommands
291    {
292       set
293       {
294          if(postbuildCommands)
295             postbuildCommands.Free();
296          if(value && value.count)
297          {
298             if(!postbuildCommands)
299                postbuildCommands = { };
300             for(s : value)
301                postbuildCommands.Add(CopyValidateMakefilePath(s));
302             value.Free();
303             delete value;
304          }
305          else
306             delete postbuildCommands;
307       }
308       get { return postbuildCommands; }
309       isset { return  postbuildCommands && postbuildCommands.count; }
310    }
311
312    ProjectOptions Copy()
313    {
314       // TODO: We'll want some solution so that we can use OnCopy for copying containers (Array<String>)
315       return
316       {
317          warnings = warnings,
318          debug = debug,
319          memoryGuard = memoryGuard,
320          profile = profile,
321          noLineNumbers = noLineNumbers;
322          optimization = optimization,
323          defaultNameSpace = CopyString(defaultNameSpace),
324          strictNameSpaces = strictNameSpaces,
325          targetType = targetType,
326          targetFileName = /*CopyString(*/targetFileName/*)*/,
327          targetDirectory = /*CopyString(*/targetDirectory/*)*/,
328          objectsDirectory = /*CopyString(*/objectsDirectory/*)*/,
329          console = console,
330          compress = compress,
331          excludeFromBuild = excludeFromBuild,
332          preprocessorDefinitions = CopyArrayString(preprocessorDefinitions),
333          includeDirs = CopyArrayString(includeDirs),
334          libraries = CopyArrayString(libraries),
335          linkerOptions = CopyArrayString(linkerOptions),
336          libraryDirs = CopyArrayString(libraryDirs),
337          prebuildCommands = CopyArrayString(prebuildCommands),
338          postbuildCommands = CopyArrayString(postbuildCommands)
339       };
340    }
341
342    ~ProjectOptions()
343    {
344       if(preprocessorDefinitions) { preprocessorDefinitions.Free(); delete preprocessorDefinitions; }
345       if(includeDirs) { includeDirs.Free(); delete includeDirs; }
346       delete defaultNameSpace;
347       delete targetFileName;
348       delete targetDirectory;
349       delete objectsDirectory;
350       if(libraries) { libraries.Free(); delete libraries; }
351       if(linkerOptions) { linkerOptions.Free(); delete linkerOptions; }
352       if(libraryDirs) { libraryDirs.Free(); delete libraryDirs; }
353       if(prebuildCommands) { prebuildCommands.Free(); delete prebuildCommands; }
354       if(postbuildCommands) { postbuildCommands.Free(); delete postbuildCommands; }
355    }
356 private:
357    Array<String> includeDirs;
358    String targetFileName;
359    String targetDirectory;
360    String objectsDirectory;
361    Array<String> libraryDirs;
362    Array<String> prebuildCommands;
363    Array<String> postbuildCommands;
364
365    property bool isEmpty
366    {
367       get
368       {
369          if(warnings == unset &&
370             debug == unset &&
371             memoryGuard == unset &&
372             profile == unset &&
373             noLineNumbers == unset &&
374             optimization == unset &&
375             !preprocessorDefinitions &&
376             (!includeDirs || !includeDirs.count) &&
377             !defaultNameSpace &&
378             strictNameSpaces == unset &&
379             targetType == unset &&
380             !targetFileName &&
381             !targetDirectory &&
382             !objectsDirectory &&
383             !libraries &&
384             !linkerOptions &&
385             (!libraryDirs || !libraryDirs.count) &&
386             console == unset &&
387             compress == unset &&
388             excludeFromBuild == unset &&
389             (!prebuildCommands || !prebuildCommands.count) &&
390             (!postbuildCommands || !postbuildCommands.count) )
391             return true;
392          return false;          
393       }
394    }
395 }
396
397 public class PlatformOptions
398 {
399 public:
400    String name;
401    property ProjectOptions options { get { return options; } set { options = value; } isset { return options && !options.isEmpty; } }
402
403    ~PlatformOptions()
404    {
405       delete name;
406       delete options;
407    }
408
409    PlatformOptions Copy()
410    {
411       return
412       {
413          CopyString(name),
414          options ? options.Copy() : null
415       };
416    }
417 private:
418    ProjectOptions options;
419 }
420
421 class ProjectConfig : struct
422 {
423 public:
424    String name;
425    property ProjectOptions options { get { return options; } set { options = value; } isset { return options && !options.isEmpty; } }
426    property Array<PlatformOptions> platforms
427    {
428       get { return platforms; }
429       set
430       {
431          if(platforms) { platforms.Free(); delete platforms; }
432          if(value)
433          {
434             List<PlatformOptions> empty { };
435             Iterator<PlatformOptions> it { value };
436             platforms = value;
437             for(p : platforms; !p.options || p.options.isEmpty) empty.Add(p);
438             for(p : empty; it.Find(p)) platforms.Delete(it.pointer);
439             delete empty;
440          }
441       }
442       isset
443       {
444          if(platforms)
445          {
446             for(p : platforms)
447             {
448                if(p.options && !p.options.isEmpty)
449                   return true;
450             }
451          }
452          return false;
453       }
454    }
455
456 private:
457    ProjectOptions options;
458    bool makingModified;
459    bool compilingModified, linkingModified, symbolGenModified;
460    Array<PlatformOptions> platforms;
461
462    ~ProjectConfig()
463    {
464       // Configuration
465       delete name;
466       delete options;
467       if(platforms) { platforms.Free(); delete platforms; }
468    }
469
470    ProjectConfig Copy()
471    {
472       Array<PlatformOptions> platforms = null;
473       if(this.platforms)
474       {
475          platforms = { };
476          for(p : this.platforms)
477          {
478             platforms.Add(p.Copy());
479          }
480       }
481       return
482       {
483          CopyString(name),
484          options ? options.Copy() : null,
485          platforms
486       };
487    }
488 }