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