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