/* * COPYRIGHT: See COPYING in the top level directory * PROJECT: Header preprocessor * PURPOSE: Generates header files from other header files * PROGRAMMER; Timo Kreuzer * */ #include #include #include #include #include //#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 \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; }