Merge from amd64 branch:
[reactos.git] / reactos / tools / hpp / hpp.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: Header preprocessor
4 * PURPOSE: Generates header files from other header files
5 * PROGRAMMER; Timo Kreuzer
6 *
7 */
8
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <stdarg.h>
12 #include <string.h>
13 #include <ctype.h>
14
15 #if DBG
16 #define trace printf
17 #else
18 #define trace if (0) printf
19 #endif
20
21 typedef struct _DEFINE
22 {
23 struct _DEFINE *pNext;
24 int len;
25 int val;
26 char szName[1];
27 } DEFINE, *PDEFINE;
28
29 DEFINE *gpDefines = 0;
30 int iLine;
31 const char *gpszCurFile;
32
33 char*
34 convert_path(const char* origpath)
35 {
36 char* newpath;
37 int i;
38
39 newpath = strdup(origpath);
40
41 i = 0;
42 while (newpath[i] != 0)
43 {
44 #ifdef UNIX_PATHS
45 if (newpath[i] == '\\')
46 {
47 newpath[i] = '/';
48 }
49 #else
50 #ifdef DOS_PATHS
51 if (newpath[i] == '/')
52 {
53 newpath[i] = '\\';
54 }
55 #endif
56 #endif
57 i++;
58 }
59 return(newpath);
60 }
61
62 char*
63 GetFolder(const char* pszFullPath)
64 {
65 return ".";
66 }
67
68 void*
69 LoadFile(const char* pszFileName, size_t* pFileSize)
70 {
71 FILE* file;
72 void* pFileData = NULL;
73
74 file = fopen(pszFileName, "rb");
75 if (file != NULL)
76 {
77 fseek(file, 0L, SEEK_END);
78 *pFileSize = ftell(file);
79 fseek(file, 0L, SEEK_SET);
80 pFileData = malloc(*pFileSize);
81 if (pFileData != NULL)
82 {
83 if (*pFileSize != fread(pFileData, 1, *pFileSize, file))
84 {
85 free(pFileData);
86 pFileData = NULL;
87 }
88 }
89 fclose(file);
90 }
91 return pFileData;
92 }
93
94
95 int
96 error(char *format, ...)
97 {
98 va_list valist;
99 int res;
100 va_start(valist, format);
101 res = vfprintf(stderr, format, valist);
102 va_end(valist);
103 return res;
104 }
105
106 char*
107 GetNextChar(const char *psz)
108 {
109 while (*psz == ' ' || *psz == '\t') psz++;
110 return (char*)psz;
111 }
112
113 char*
114 GetNextLine(char *pszLine)
115 {
116 /* Walk to the end of the line */
117 while (*pszLine != 13 && *pszLine != 10 && *pszLine != 0) pszLine++;
118
119 /* Skip one CR/LF */
120 if (pszLine[0] == 13 && pszLine[1] == 10)
121 pszLine += 2;
122 else if (pszLine[0] == 13 || pszLine[0] == 10)
123 pszLine++;
124
125 if (*pszLine == 0)
126 {
127 return 0;
128 }
129
130 return pszLine;
131 }
132
133 int
134 strxlen(const char *psz)
135 {
136 int len = 0;
137 while (isalnum(*psz) || *psz == '_')
138 {
139 psz++;
140 len++;
141 }
142 return len;
143 }
144
145
146 void
147 WriteLine(char *pszLine, FILE *fileOut)
148 {
149 char * pszEnd;
150
151 pszEnd = strchr(pszLine, '\n');
152 if (pszEnd)
153 {
154 int len = pszEnd - pszLine + 1;
155 fwrite(pszLine, 1, len, fileOut);
156 }
157 }
158
159 int
160 EvaluateConstant(const char *p, char **pNext)
161 {
162 PDEFINE pDefine;
163 int len;
164
165 len = strxlen(p);
166 if (pNext)
167 *pNext = (char*)p + len;
168
169 /* search for the define in the global list */
170 pDefine = gpDefines;
171 while (pDefine != 0)
172 {
173 trace("found a define: %s\n", pDefine->szName);
174 if (pDefine->len == len)
175 {
176 if (strncmp(p, pDefine->szName, len) == 0)
177 {
178 return pDefine->val;
179 }
180 }
181 pDefine = pDefine->pNext;
182 }
183 return 0;
184 }
185
186 int
187 EvaluateExpression(char *pExpression, char **pNext)
188 {
189 char *p, *pstart;
190 int inv, thisval, val = 0;
191
192 trace("evaluating expression\n");
193
194 pstart = GetNextChar(pExpression);
195 if (*pstart != '(')
196 {
197 error("Parse error: expected '(' \n");
198 return -1;
199 }
200
201 while (1)
202 {
203 /* Get the start of the real expression */
204 p = pstart;
205 if ((p[0] == '&' && p[1] == '&') ||
206 (p[0] == '|' && p[1] == '|'))
207 {
208 p++;
209 }
210 p = GetNextChar(p + 1);
211
212 /* Check for inversion modifier */
213 if (*p == '!')
214 {
215 inv = 1;
216 p = GetNextChar(p + 1);
217 }
218 else
219 inv = 0;
220
221 /* Beginning of a new subexpression? */
222 if (*p == '(')
223 {
224 /* Evaluate subexpression */
225 thisval = EvaluateExpression(p, &p);
226 }
227 else if (isdigit(*p))
228 {
229 thisval = strtod(p, &p);
230 trace("found a num: %d\n", thisval);
231 }
232 else if (isalpha(*p) || *p == '_')
233 {
234 thisval = EvaluateConstant(p, &p);
235 }
236 else
237 {
238 error("..Parse error, expected '(' or constant in line %d\n",
239 iLine);
240 return -1;
241 }
242
243 if (inv)
244 thisval = !thisval;
245
246 /* Check how to combine the current value */
247 if (pstart[0] == '(')
248 {
249 val = thisval;
250 }
251 else if (pstart[0] == '&' && pstart[1] == '&')
252 {
253 val = val && thisval;
254 }
255 else if (pstart[0] == '&' && pstart[1] != '&')
256 {
257 val = val & thisval;
258 }
259 else if (pstart[0] == '|' && pstart[1] == '|')
260 {
261 trace("found || val = %d, thisval = %d\n", val, thisval);
262 val = val || thisval;
263 }
264 else if (pstart[0] == '|' && pstart[1] != '|')
265 {
266 val = val | thisval;
267 }
268 else if (pstart[0] == '+')
269 {
270 val = val + thisval;
271 }
272 else
273 {
274 error("+Parse error: expected '(' or operator in Line %d, got %c\n",
275 iLine, pstart[0]);
276 return -1;
277 }
278
279 p = GetNextChar(p);
280
281 /* End of current subexpression? */
282 if (*p == ')')
283 {
284 if (pNext)
285 {
286 *pNext = p + 1;
287 }
288 return val;
289 }
290
291 /* Continue with a new start position */
292 pstart = p;
293 }
294
295 return val;
296 }
297
298 int
299 ParseInputFile(const char *pszInFile, FILE *fileOut)
300 {
301 char* pInputData, *pCurrentLine, *p1, *p2;
302 size_t cbInFileLenth, len;
303 int iIfLevel, iCopyLevel;
304
305 trace("parsing input file: %s\n", pszInFile);
306
307 /* Set the global file name */
308 gpszCurFile = pszInFile;
309
310 /* Load the input file into memory */
311 pInputData = LoadFile(pszInFile, &cbInFileLenth);
312 if (!pInputData)
313 {
314 error("Could not load input file %s\n", pszInFile);
315 return -1;
316 }
317
318 /* Zero terminate the file */
319 pInputData[cbInFileLenth] = 0;
320
321 pCurrentLine = pInputData;
322 iLine = 1;
323 iCopyLevel = iIfLevel = 0;
324
325 /* The main processing loop */
326 do
327 {
328 trace("line %d: ", iLine);
329
330 /* If this is a normal line ... */
331 if (pCurrentLine[0] != '$')
332 {
333 /* Check if we are to copy this line */
334 if (iCopyLevel == iIfLevel)
335 {
336 trace("copying\n");
337 WriteLine(pCurrentLine, fileOut);
338 }
339 else
340 trace("skipping\n");
341
342 /* Continue with next line */
343 continue;
344 }
345
346 /* Check for $endif */
347 if (strncmp(pCurrentLine, "$endif", 6) == 0)
348 {
349 trace("found $endif\n");
350 if (iIfLevel <= 0)
351 {
352 error("Parse error: $endif without $if in %s:%d\n", pszInFile, iLine);
353 return -1;
354 }
355 if (iCopyLevel == iIfLevel)
356 {
357 iCopyLevel--;
358 }
359 iIfLevel--;
360
361 /* Continue with next line */
362 continue;
363 }
364
365 /* The rest is only parsed when we are in a true block */
366 if (iCopyLevel < iIfLevel)
367 {
368 trace("skipping\n");
369
370 /* Continue with next line */
371 continue;
372 }
373
374 /* Check for $define */
375 if (strncmp(pCurrentLine, "$define", 7) == 0)
376 {
377 PDEFINE pDefine;
378
379 trace("found $define\n");
380 p1 = GetNextChar(pCurrentLine + 7);
381 if (*p1 != '(')
382 {
383 error("Parse error: expected '(' at %s:%d\n",
384 pszInFile, iLine);
385 return -1;
386 }
387 p1 = GetNextChar(p1 + 1);
388 len = strxlen(p1);
389 p2 = p1 + len;
390 if (*p2 != ')')
391 {
392 error("Parse error: expected ')' at %s:%d\n",
393 pszInFile, iLine);
394 return -1;
395 }
396
397 /* Insert the new define into the global list */
398 pDefine = malloc(sizeof(DEFINE) + len);
399 strncpy(pDefine->szName, p1, len);
400 pDefine->szName[len] = 0;
401 pDefine->len = len;
402 pDefine->val = 1;
403 pDefine->pNext = gpDefines;
404 gpDefines = pDefine;
405 }
406
407 /* Check for $if */
408 else if (strncmp(pCurrentLine, "$if", 3) == 0)
409 {
410 int val;
411
412 trace("found $if\n");
413 /* Increase the if-level */
414 iIfLevel++;
415
416 /* Get beginning of the expression */
417 p1 = GetNextChar(pCurrentLine + 3);
418
419 /* evaluate the expression */
420 val = EvaluateExpression(p1, 0);
421
422 if (val)
423 {
424 iCopyLevel = iIfLevel;
425 }
426 else if (val == -1)
427 {
428 /* Parse error */
429 return -1;
430 }
431 }
432
433 /* Check for $include */
434 else if (strncmp(pCurrentLine, "$include", 8) == 0)
435 {
436 int ret;
437
438 trace("found $include\n");
439 p1 = GetNextChar(pCurrentLine + 8);
440 if (*p1 != '(')
441 {
442 error("Parse error: expected '(' at %s:%d, found '%c'\n",
443 pszInFile, iLine, *p1);
444 return -1;
445 }
446 p1++;
447 p2 = strchr(p1, ')');
448 *p2 = 0;
449
450 /* Parse the included file */
451 ret = ParseInputFile(p1, fileOut);
452
453 /* Restore the global file name */
454 gpszCurFile = pszInFile;
455
456 if (ret == -1)
457 {
458 return -1;
459 }
460 }
461
462 /* Check for $$ comment */
463 else if (strncmp(pCurrentLine, "$$", 2) == 0)
464 {
465 trace("$$ ignored\n");
466 /* continue with next line */
467 continue;
468 }
469
470 else
471 {
472 trace("wot:%s\n", pCurrentLine);
473 }
474
475 /* Continue with next line */
476 }
477 while (pCurrentLine = GetNextLine(pCurrentLine),
478 iLine++,
479 pCurrentLine != 0);
480
481 /* Free the file data */
482 free(pInputData);
483
484 return 0;
485 }
486
487
488 int
489 main(int argc, char* argv[])
490 {
491 char *pszInFolder, *pszInFile, *pszOutFile;
492 FILE* fileOut;
493 int ret;
494
495 if (argc != 3)
496 {
497 error("Usage: hc <inputfile> <outputfile>\n");
498 exit(1);
499 }
500
501 pszInFile = convert_path(argv[1]);
502 pszOutFile = convert_path(argv[2]);
503 pszInFolder = GetFolder(pszInFile);
504
505 fileOut = fopen(pszOutFile, "wb");
506 if (fileOut == NULL)
507 {
508 error("Cannot open output file %s", pszOutFile);
509 exit(1);
510 }
511
512 ret = ParseInputFile(pszInFile, fileOut);
513
514 fclose(fileOut);
515
516 return ret;
517 }