1 /*---------------------------------------------------------------------------*
2   Project:  NitroSDK - tools - makerom
3   File:     defval.c
4 
5   Copyright 2003-2008 Nintendo. All rights reserved.
6 
7   These coded instructions, statements, and computer programs contain
8   proprietary information of Nintendo of America Inc. and/or Nintendo
9   Company Ltd., and are protected by Federal copyright law. They may
10   not be disclosed to third parties or copied or duplicated in any form,
11   in whole or in part, without the prior written consent of Nintendo.
12 
13   $Log: defval.c,v $
14   Revision 1.12  2006/03/29 13:13:22  yasu
15   IF-ELSE-ENDIF support
16 
17   Revision 1.11  2006/01/18 02:11:19  kitase_hirotake
18   do-indent
19 
20   Revision 1.10  2005/02/28 05:26:03  yosizaki
21   do-indent.
22 
23   Revision 1.9  2004/08/05 13:38:44  yasu
24   Support for -M option
25 
26   Revision 1.8  2004/07/10 04:06:17  yasu
27   Added support for command 'Library'
28   Support for modifier ':x' in template
29   Fixed line continue '\' issue
30 
31   Revision 1.7  2004/06/29 04:10:45  yasu
32   Use VBuffer to resolve variables
33 
34   Revision 1.6  2004/06/23 07:51:07  yasu
35   Fixed a bug as illegal memory deallocation in the ResolveDefVal function
36 
37   Revision 1.5  2004/05/27 00:40:55  yasu
38   care also about current directory (dot ".")
39 
40   Revision 1.4  2004/05/27 00:25:40  yasu
41   care about double-dots ".." for defvalue option :r, :e
42 
43   Revision 1.3  2004/05/27 00:11:29  yasu
44   fix a error when searching a "dot" of file extension
45 
46   Revision 1.2  2004/05/26 12:02:47  yasu
47   support :h, :t, :r, :e option for variable name
48 
49   Revision 1.1  2004/03/26 05:07:33  yasu
50   Support for variables like as -DNAME=VALUE
51 
52   $NoKeywords: $
53  *---------------------------------------------------------------------------*/
54 #include	<stdio.h>
55 #include	<stdlib.h>             // getenv()
56 #include	<ctype.h>              // isspace()
57 #include	<string.h>             // strcasecmp()
58 #include	<getopt.h>             // getopt()
59 #include	"misc.h"
60 #include	"defval.h"
61 #include	"makelcf.h"
62 
63 typedef struct tValdef
64 {
65     struct tValdef *next;
66     char   *name;
67     char   *value;
68 }
69 tValdef;
70 
71 tValdef *valdef_top = NULL;
72 
73 //
74 //  Add new define value via file
75 //
76 //      opt: "DEFINE=VALUE"
77 //
AddDefValFromFile(char * filename)78 BOOL AddDefValFromFile(char *filename)
79 {
80     char   *buffer;
81     int     buffer_size;
82     int     read_size;
83     FILE   *fp;
84 
85     if (filename[0] == '-' && filename[1] == '\0')
86     {
87         fp = stdin;
88     }
89     else if (NULL == (fp = fopen(filename, "rb")))
90     {
91         fprintf(stderr, "Cannot open file \"%s\".\n", filename);
92         return FALSE;
93     }
94 
95     buffer_size = DEFVAL_DEFAULT_BUFFER_SIZE;
96 
97     if (NULL == (buffer = malloc(buffer_size)))
98     {
99         fprintf(stderr, "Cannot allocate memory.\n");
100         return FALSE;
101     }
102 
103     read_size = 0;
104 
105     while (NULL != fgets(buffer + read_size, buffer_size - read_size, fp))
106     {
107         read_size = strlen(buffer);
108 
109         if (read_size == buffer_size - 1 && buffer[read_size - 1] != '\n')
110         {
111             buffer_size *= 2;
112 
113             if (NULL == (buffer = realloc(buffer, buffer_size)))
114             {
115                 fprintf(stderr, "Cannot allocate memory.\n");
116                 return FALSE;
117             }
118             continue;
119         }
120 
121         AddDefVal(buffer);
122         read_size = 0;
123     }
124 
125     if (fp != stdin)
126     {
127         fclose(fp);
128     }
129     free(buffer);
130 
131     return TRUE;
132 }
133 
134 
135 //
136 //  Add new define value
137 //
138 //      opt: "DEFINE=VALUE"
139 //
AddDefVal(char * opt)140 void AddDefVal(char *opt)
141 {
142     int     i, lastword;
143     tValdef *t;
144 
145     for (i = lastword = 0;; i++)
146     {
147         if ('=' == opt[i] || '\0' == opt[i])
148         {
149             break;
150         }
151 
152         if (!isspace(opt[i]))
153         {
154             lastword = i + 1;
155         }
156     }
157 
158     if (lastword > 0)
159     {
160         t = Alloc(sizeof(tValdef));
161         t->name = strncpy(Alloc(lastword + 1), opt, lastword);
162         t->name[lastword] = '\0';
163 
164         if (opt[i] == '=')
165         {
166             i++;
167         }
168 
169         t->value = strdup(opt + i);
170         lastword = strlen(t->value) - 1;
171         while (lastword >= 0)
172         {
173             if ('\r' != t->value[lastword] && '\n' != t->value[lastword])
174             {
175                 break;
176             }
177             t->value[lastword] = '\0';
178             lastword--;
179         }
180 
181         t->next = valdef_top;
182         valdef_top = t;
183 
184         debug_printf("DEFINE:$(%s)=\"%s\"\n", t->name, t->value);
185     }
186     return;
187 }
188 
189 //
190 //  Search define value
191 //
192 //      Return: value of specified name
193 //
SearchDefVal(const char * name)194 const char *SearchDefVal(const char *name)
195 {
196     tValdef *t;
197 
198     for (t = valdef_top; t; t = t->next)
199     {
200         if (!strcmp(t->name, name))
201         {
202             return t->value;
203         }
204     }
205     return getenv(name);
206 }
207 
208 //
209 //  SearchDefVal with NULL string handling
210 //
SearchDefValCleaned(const char * name)211 const char *SearchDefValCleaned(const char *name)
212 {
213     const char *result = NULL;
214 
215     if (name != NULL)
216     {
217         result = SearchDefVal(name);
218     }
219 
220     return result ? result : "";
221 }
222 
223 //
224 //  Resolve modifier
225 //
226 //      Return: duplicated value of specified name modified by :x option
227 //
ResolveStringModifier(const char * in_value,char modifier)228 char   *ResolveStringModifier(const char *in_value, char modifier)
229 {
230     char   *value;
231 
232     if (in_value == NULL)
233     {
234         value = NULL;
235     }
236     else if (!modifier)                // No modifier
237     {
238         value = strdup(in_value);
239     }
240     else
241     {
242         const int NO_EXTENSION = -1;
243         int     value_len = strlen(in_value);
244         int     col_extension = NO_EXTENSION;
245         int     col_filename = 0;
246         int     i;
247 
248         for (i = 0; i < value_len; i++)
249         {
250             switch (in_value[i])
251             {
252             case '.':
253                 if (col_filename == i &&
254                     (in_value[i + 1] == '\0' ||
255                      (in_value[i + 1] == '.' && in_value[i + 2] == '\0')))
256                 {
257                     i = value_len;     // exit loop if last entry is '.' or '..'
258                 }
259                 else
260                 {
261                     col_extension = i; // Save the last dot column
262                 }
263                 break;
264 
265             case '/':
266             case '\\':
267             case ':':
268                 col_filename = i + 1;  // Save the last filename
269                 col_extension = NO_EXTENSION;   // Reset dot position
270                 break;
271 
272             default:
273                 ;
274             }
275         }
276 
277         switch (modifier)
278         {
279         case 'h':                     // Dirname with the last slash
280             value = strdup(in_value);
281             value[col_filename] = '\0';
282             break;
283 
284         case 't':                     // Filename
285             value = strdup(in_value + col_filename);
286             break;
287 
288         case 'r':                     // All without . file extension
289             value = strdup(in_value);
290             if (col_extension >= 0)
291             {
292                 value[col_extension] = '\0';
293             }
294             break;
295 
296         case 'e':                     // File extension
297             if (col_extension >= 0)
298             {
299                 value = strdup(in_value + col_extension + 1);
300             }
301             else
302             {
303                 value = strdup("");
304             }
305             break;
306 
307         default:                      // Unknown
308             fprintf(stderr, "Unknown modifier ':%c'... Ignored.\n", modifier);
309             value = strdup(in_value);
310             break;
311         }
312     }
313     return value;
314 }
315 
316 
317 //
318 //  Search define value and Modify it by ':' modifier
319 //
320 //      Return: duplicated value of specified name modified by ':X'
321 //
SearchDefValWithOption(const char * in_name)322 char   *SearchDefValWithOption(const char *in_name)
323 {
324     char   *name = strdup(in_name);
325     int     len_name = strlen(in_name);
326     char    modifier = '\0';
327     char   *value;
328 
329     if (len_name > 2 && name[len_name - 2] == ':')
330     {
331         name[len_name - 2] = '\0';
332         modifier = name[len_name - 1];
333     }
334 
335     value = ResolveStringModifier(SearchDefVal(name), modifier);
336 
337     debug_printf("REFERED(%s)=[%s]\n", in_name, value ? value : "(NULL)");
338 
339     free(name);
340 
341     return value;
342 }
343 
344 
345 //
346 //  Resolve define value
347 //
348 //      Return: new string
349 //
ResolveDefVal(char * str)350 char   *ResolveDefVal(char *str)
351 {
352     int     i, j;
353     char   *val;
354     VBuffer buf;
355 
356     InitVBuffer(&buf);
357 
358     for (i = 0; '\0' != str[i]; i++)
359     {
360         // search $(XXX)
361         if ('$' == str[i] && '(' == str[i + 1])
362         {
363             for (j = i + 2; '\0' != str[j]; j++)
364             {
365                 if (')' == str[j])
366                 {
367                     str[j] = '\0';
368 
369                     // get value of XXX
370                     val = SearchDefValWithOption(&str[i + 2]);
371 
372                     // copy value of XXX
373                     if (val)
374                     {
375                         char   *s = val;
376 
377                         while (*s)
378                         {
379                             PutVBuffer(&buf, *s);
380                             s++;
381                         }
382                         free(val);
383                     }
384                     i = j;
385                     goto next;
386                 }
387             }
388         }
389         PutVBuffer(&buf, str[i]);
390       next:;
391     }
392     return GetVBuffer(&buf);           // pass allocated buffer, should be freed by caller
393 }
394