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