mirror of
https://github.com/reactos/reactos.git
synced 2024-12-28 18:15:11 +00:00
631 lines
14 KiB
C
631 lines
14 KiB
C
/*
|
|
* COPYRIGHT: See COPYING in the top level directory
|
|
* PROJECT: Header preprocessor
|
|
* PURPOSE: Generates header files from other header files
|
|
* PROGRAMMER; Timo Kreuzer
|
|
*
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <stdarg.h>
|
|
#include <string.h>
|
|
#include <ctype.h>
|
|
|
|
//#define DBG 1
|
|
|
|
#if DBG
|
|
#define trace printf
|
|
#else
|
|
#define trace if (0) printf
|
|
#endif
|
|
|
|
typedef struct _DEFINE
|
|
{
|
|
struct _DEFINE *pNext;
|
|
int val;
|
|
char *pszName;
|
|
unsigned int cchName;
|
|
char *pszValue;
|
|
unsigned int cchValue;
|
|
char achBuffer[1];
|
|
} DEFINE, *PDEFINE;
|
|
|
|
DEFINE *gpDefines = 0;
|
|
int iLine;
|
|
const char *gpszCurFile;
|
|
|
|
char*
|
|
convert_path(const char* origpath)
|
|
{
|
|
char* newpath;
|
|
int i;
|
|
|
|
newpath = strdup(origpath);
|
|
|
|
i = 0;
|
|
while (newpath[i] != 0)
|
|
{
|
|
#ifdef UNIX_PATHS
|
|
if (newpath[i] == '\\')
|
|
{
|
|
newpath[i] = '/';
|
|
}
|
|
#else
|
|
#ifdef DOS_PATHS
|
|
if (newpath[i] == '/')
|
|
{
|
|
newpath[i] = '\\';
|
|
}
|
|
#endif
|
|
#endif
|
|
i++;
|
|
}
|
|
return newpath;
|
|
}
|
|
|
|
char*
|
|
GetFolder(const char* pszFullPath)
|
|
{
|
|
return ".";
|
|
}
|
|
|
|
void*
|
|
LoadFile(const char* pszFileName, size_t* pFileSize)
|
|
{
|
|
FILE* file;
|
|
void* pFileData = NULL;
|
|
int iFileSize;
|
|
|
|
trace("Loading file...");
|
|
|
|
file = fopen(pszFileName, "rb");
|
|
if (!file)
|
|
{
|
|
trace("Could not open file\n");
|
|
return NULL;
|
|
}
|
|
|
|
fseek(file, 0L, SEEK_END);
|
|
iFileSize = ftell(file);
|
|
fseek(file, 0L, SEEK_SET);
|
|
*pFileSize = iFileSize;
|
|
trace("ok. Size is %d\n", iFileSize);
|
|
|
|
pFileData = malloc(iFileSize + 1);
|
|
|
|
if (pFileData != NULL)
|
|
{
|
|
if (iFileSize != fread(pFileData, 1, iFileSize, file))
|
|
{
|
|
free(pFileData);
|
|
pFileData = NULL;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
trace("Could not allocate memory for file\n");
|
|
}
|
|
|
|
fclose(file);
|
|
|
|
return pFileData;
|
|
}
|
|
|
|
|
|
int
|
|
error(char *format, ...)
|
|
{
|
|
va_list valist;
|
|
int res;
|
|
va_start(valist, format);
|
|
res = vfprintf(stderr, format, valist);
|
|
va_end(valist);
|
|
return res;
|
|
}
|
|
|
|
char*
|
|
GetNextChar(const char *psz)
|
|
{
|
|
while (*psz == ' ' || *psz == '\t') psz++;
|
|
return (char*)psz;
|
|
}
|
|
|
|
char*
|
|
GetNextLine(char *pszLine)
|
|
{
|
|
/* Walk to the end of the line */
|
|
while (*pszLine != 13 && *pszLine != 10 && *pszLine != 0) pszLine++;
|
|
|
|
/* Skip one CR/LF */
|
|
if (pszLine[0] == 13 && pszLine[1] == 10)
|
|
pszLine += 2;
|
|
else if (pszLine[0] == 13 || pszLine[0] == 10)
|
|
pszLine++;
|
|
|
|
if (*pszLine == 0)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
return pszLine;
|
|
}
|
|
|
|
int
|
|
strxlen(const char *psz)
|
|
{
|
|
int len = 0;
|
|
while (isalnum(*psz) || *psz == '_')
|
|
{
|
|
psz++;
|
|
len++;
|
|
}
|
|
return len;
|
|
}
|
|
|
|
PDEFINE
|
|
FindDefine(const char *p, char **pNext)
|
|
{
|
|
PDEFINE pDefine;
|
|
int cchName;
|
|
|
|
cchName = strxlen(p);
|
|
if (pNext)
|
|
*pNext = (char*)p + cchName;
|
|
|
|
/* search for the define in the global list */
|
|
pDefine = gpDefines;
|
|
while (pDefine != 0)
|
|
{
|
|
trace("found a define: %s\n", pDefine->pszName);
|
|
if (pDefine->cchName == cchName)
|
|
{
|
|
if (strncmp(p, pDefine->pszName, cchName) == 0)
|
|
{
|
|
return pDefine;
|
|
}
|
|
}
|
|
pDefine = pDefine->pNext;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
void
|
|
WriteLine(char *pchLine, FILE *fileOut)
|
|
{
|
|
char *pch, *pchLineEnd, *pchVariable;
|
|
int len;
|
|
PDEFINE pDefine;
|
|
|
|
pchLineEnd = strchr(pchLine, '\n');
|
|
if (pchLineEnd == 0)
|
|
return;
|
|
|
|
len = pchLineEnd - pchLine + 1;
|
|
|
|
pch = pchLine;
|
|
while (len > 0)
|
|
{
|
|
/* Check if there is a $ variable in the line */
|
|
pchVariable = strchr(pch, '$');
|
|
if (pchVariable && (pchVariable < pchLineEnd))
|
|
{
|
|
/* Write all characters up to the $ */
|
|
fwrite(pch, 1, pchVariable - pch, fileOut);
|
|
|
|
/* Try to find the define */
|
|
pDefine = FindDefine(pchVariable + 1, &pch);
|
|
if (pDefine != 0)
|
|
{
|
|
/* We have a define, write the value */
|
|
fwrite(pDefine->pszValue, 1, pDefine->cchValue, fileOut);
|
|
}
|
|
else
|
|
{
|
|
len = strxlen(pchVariable + 1) + 1;
|
|
error("Could not find variable '%.*s'\n", len, pchVariable);
|
|
fwrite(pchVariable, 1, pch - pchVariable, fileOut);
|
|
}
|
|
|
|
len = pchLineEnd - pch + 1;
|
|
}
|
|
else
|
|
{
|
|
fwrite(pch, 1, len, fileOut);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
int
|
|
EvaluateConstant(const char *p, char **pNext)
|
|
{
|
|
PDEFINE pDefine;
|
|
|
|
pDefine = FindDefine(p, pNext);
|
|
if (!pDefine)
|
|
return 0;
|
|
|
|
return pDefine->val;
|
|
}
|
|
|
|
int
|
|
EvaluateExpression(char *pExpression, char **pNext)
|
|
{
|
|
char *p, *pstart;
|
|
int inv, thisval, val = 0;
|
|
|
|
trace("evaluating expression\n");
|
|
|
|
pstart = GetNextChar(pExpression);
|
|
if (*pstart != '(')
|
|
{
|
|
error("Parse error: expected '(' \n");
|
|
return -1;
|
|
}
|
|
|
|
while (1)
|
|
{
|
|
/* Get the start of the real expression */
|
|
p = pstart;
|
|
if ((p[0] == '&' && p[1] == '&') ||
|
|
(p[0] == '|' && p[1] == '|'))
|
|
{
|
|
p++;
|
|
}
|
|
p = GetNextChar(p + 1);
|
|
|
|
/* Check for inversion modifier */
|
|
if (*p == '!')
|
|
{
|
|
inv = 1;
|
|
p = GetNextChar(p + 1);
|
|
}
|
|
else
|
|
inv = 0;
|
|
|
|
/* Beginning of a new subexpression? */
|
|
if (*p == '(')
|
|
{
|
|
/* Evaluate subexpression */
|
|
thisval = EvaluateExpression(p, &p);
|
|
}
|
|
else if (isdigit(*p))
|
|
{
|
|
thisval = strtod(p, &p);
|
|
trace("found a num: %d\n", thisval);
|
|
}
|
|
else if (isalpha(*p) || *p == '_')
|
|
{
|
|
thisval = EvaluateConstant(p, &p);
|
|
}
|
|
else
|
|
{
|
|
error("..Parse error, expected '(' or constant in line %d\n",
|
|
iLine);
|
|
return -1;
|
|
}
|
|
|
|
if (inv)
|
|
thisval = !thisval;
|
|
|
|
/* Check how to combine the current value */
|
|
if (pstart[0] == '(')
|
|
{
|
|
val = thisval;
|
|
}
|
|
else if (pstart[0] == '&' && pstart[1] == '&')
|
|
{
|
|
val = val && thisval;
|
|
}
|
|
else if (pstart[0] == '&' && pstart[1] != '&')
|
|
{
|
|
val = val & thisval;
|
|
}
|
|
else if (pstart[0] == '|' && pstart[1] == '|')
|
|
{
|
|
trace("found || val = %d, thisval = %d\n", val, thisval);
|
|
val = val || thisval;
|
|
}
|
|
else if (pstart[0] == '|' && pstart[1] != '|')
|
|
{
|
|
val = val | thisval;
|
|
}
|
|
else if (pstart[0] == '+')
|
|
{
|
|
val = val + thisval;
|
|
}
|
|
else
|
|
{
|
|
error("+Parse error: expected '(' or operator in Line %d, got %c\n",
|
|
iLine, pstart[0]);
|
|
return -1;
|
|
}
|
|
|
|
p = GetNextChar(p);
|
|
|
|
/* End of current subexpression? */
|
|
if (*p == ')')
|
|
{
|
|
if (pNext)
|
|
{
|
|
*pNext = p + 1;
|
|
}
|
|
return val;
|
|
}
|
|
|
|
/* Continue with a new start position */
|
|
pstart = p;
|
|
}
|
|
|
|
return val;
|
|
}
|
|
|
|
int
|
|
ParseInputFile(const char *pszInFile, FILE *fileOut)
|
|
{
|
|
char* pInputData, *pCurrentLine, *p1, *p2;
|
|
size_t cbInFileLenth;
|
|
int iIfLevel, iCopyLevel;
|
|
|
|
trace("parsing input file: %s\n", pszInFile);
|
|
|
|
/* Set the global file name */
|
|
gpszCurFile = pszInFile;
|
|
|
|
/* Load the input file into memory */
|
|
pInputData = LoadFile(pszInFile, &cbInFileLenth);
|
|
if (!pInputData)
|
|
{
|
|
error("Could not load input file %s\n", pszInFile);
|
|
return -1;
|
|
}
|
|
|
|
/* Zero terminate the file */
|
|
pInputData[cbInFileLenth] = 0;
|
|
|
|
pCurrentLine = pInputData;
|
|
iLine = 1;
|
|
iCopyLevel = iIfLevel = 0;
|
|
|
|
/* The main processing loop */
|
|
do
|
|
{
|
|
trace("line %d: ", iLine);
|
|
|
|
/* If this is a normal line ... */
|
|
if (pCurrentLine[0] != '$')
|
|
{
|
|
/* Check if we are to copy this line */
|
|
if (iCopyLevel == iIfLevel)
|
|
{
|
|
trace("copying\n");
|
|
WriteLine(pCurrentLine, fileOut);
|
|
}
|
|
else
|
|
trace("skipping\n");
|
|
|
|
/* Continue with next line */
|
|
continue;
|
|
}
|
|
|
|
/* Check for $endif */
|
|
if (strncmp(pCurrentLine, "$endif", 6) == 0)
|
|
{
|
|
trace("found $endif\n");
|
|
if (iIfLevel <= 0)
|
|
{
|
|
error("Parse error: $endif without $if in %s:%d\n", pszInFile, iLine);
|
|
return -1;
|
|
}
|
|
if (iCopyLevel == iIfLevel)
|
|
{
|
|
iCopyLevel--;
|
|
}
|
|
iIfLevel--;
|
|
|
|
/* Continue with next line */
|
|
continue;
|
|
}
|
|
|
|
/* The rest is only parsed when we are in a true block */
|
|
if (iCopyLevel < iIfLevel)
|
|
{
|
|
trace("skipping\n");
|
|
|
|
/* Continue with next line */
|
|
continue;
|
|
}
|
|
|
|
/* Check for $define */
|
|
if (strncmp(pCurrentLine, "$define", 7) == 0)
|
|
{
|
|
PDEFINE pDefine;
|
|
char *pchName, *pchValue;
|
|
size_t cchName, cchValue;
|
|
|
|
trace("found $define\n");
|
|
p1 = GetNextChar(pCurrentLine + 7);
|
|
if (*p1 != '(')
|
|
{
|
|
error("Parse error: expected '(' at %s:%d\n",
|
|
pszInFile, iLine);
|
|
return -1;
|
|
}
|
|
|
|
pchName = GetNextChar(p1 + 1);
|
|
cchName = strxlen(pchName);
|
|
p1 = GetNextChar(pchName + cchName);
|
|
|
|
/* Check for assignment */
|
|
if (*p1 == '=')
|
|
{
|
|
trace("found $define with assignment\n");
|
|
pchValue = GetNextChar(p1 + 1);
|
|
cchValue = strxlen(pchValue);
|
|
p1 = GetNextChar(pchValue + cchValue);
|
|
}
|
|
else
|
|
{
|
|
pchValue = 0;
|
|
cchValue = 0;
|
|
}
|
|
|
|
/* Allocate a DEFINE structure */
|
|
pDefine = malloc(sizeof(DEFINE) + cchName + cchValue + 2);
|
|
if (pDefine == 0)
|
|
{
|
|
error("Failed to allocate %u bytes\n",
|
|
sizeof(DEFINE) + cchName + cchValue + 2);
|
|
return -1;
|
|
}
|
|
|
|
pDefine->pszName = pDefine->achBuffer;
|
|
strncpy(pDefine->pszName, pchName, cchName);
|
|
pDefine->pszName[cchName] = 0;
|
|
pDefine->cchName = cchName;
|
|
pDefine->val = 1;
|
|
|
|
if (pchValue != 0)
|
|
{
|
|
pDefine->pszValue = &pDefine->achBuffer[cchName + 1];
|
|
strncpy(pDefine->pszValue, pchValue, cchValue);
|
|
pDefine->pszValue[cchValue] = 0;
|
|
pDefine->cchValue = cchValue;
|
|
}
|
|
else
|
|
{
|
|
pDefine->pszValue = 0;
|
|
pDefine->cchValue = 0;
|
|
}
|
|
|
|
/* Insert the new define into the global list */
|
|
pDefine->pNext = gpDefines;
|
|
gpDefines = pDefine;
|
|
|
|
/* Check for closing ')' */
|
|
if (*p1 != ')')
|
|
{
|
|
error("Parse error: expected ')' at %s:%d\n",
|
|
pszInFile, iLine);
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
/* Check for $if */
|
|
else if (strncmp(pCurrentLine, "$if", 3) == 0)
|
|
{
|
|
int val;
|
|
|
|
trace("found $if\n");
|
|
/* Increase the if-level */
|
|
iIfLevel++;
|
|
|
|
/* Get beginning of the expression */
|
|
p1 = GetNextChar(pCurrentLine + 3);
|
|
|
|
/* evaluate the expression */
|
|
val = EvaluateExpression(p1, 0);
|
|
|
|
if (val)
|
|
{
|
|
iCopyLevel = iIfLevel;
|
|
}
|
|
else if (val == -1)
|
|
{
|
|
/* Parse error */
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
/* Check for $include */
|
|
else if (strncmp(pCurrentLine, "$include", 8) == 0)
|
|
{
|
|
int ret;
|
|
|
|
trace("found $include\n");
|
|
p1 = GetNextChar(pCurrentLine + 8);
|
|
if (*p1 != '(')
|
|
{
|
|
error("Parse error: expected '(' at %s:%d, found '%c'\n",
|
|
pszInFile, iLine, *p1);
|
|
return -1;
|
|
}
|
|
p1++;
|
|
p2 = strchr(p1, ')');
|
|
*p2 = 0;
|
|
|
|
/* Parse the included file */
|
|
ret = ParseInputFile(p1, fileOut);
|
|
|
|
/* Restore the global file name */
|
|
gpszCurFile = pszInFile;
|
|
|
|
/* Restore the zeroed character */
|
|
*p2 = ')';
|
|
|
|
if (ret == -1)
|
|
{
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
/* Check for $$ comment */
|
|
else if (strncmp(pCurrentLine, "$$", 2) == 0)
|
|
{
|
|
trace("$$ ignored\n");
|
|
/* continue with next line */
|
|
continue;
|
|
}
|
|
|
|
else
|
|
{
|
|
trace("wot:%s\n", pCurrentLine);
|
|
}
|
|
|
|
/* Continue with next line */
|
|
}
|
|
while (pCurrentLine = GetNextLine(pCurrentLine),
|
|
iLine++,
|
|
pCurrentLine != 0);
|
|
|
|
/* Free the file data */
|
|
free(pInputData);
|
|
|
|
trace("Done with file.\n\n");
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
int
|
|
main(int argc, char* argv[])
|
|
{
|
|
char *pszInFile, *pszOutFile;
|
|
FILE* fileOut;
|
|
int ret;
|
|
|
|
if (argc != 3)
|
|
{
|
|
error("Usage: hpp <inputfile> <outputfile>\n");
|
|
exit(1);
|
|
}
|
|
|
|
pszInFile = convert_path(argv[1]);
|
|
pszOutFile = convert_path(argv[2]);
|
|
|
|
fileOut = fopen(pszOutFile, "wb");
|
|
if (fileOut == NULL)
|
|
{
|
|
error("Cannot open output file %s", pszOutFile);
|
|
exit(1);
|
|
}
|
|
|
|
ret = ParseInputFile(pszInFile, fileOut);
|
|
|
|
fclose(fileOut);
|
|
free(pszInFile);
|
|
free(pszOutFile);
|
|
|
|
return ret;
|
|
}
|