mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-25 13:51:41 +00:00
1006 lines
21 KiB
C
1006 lines
21 KiB
C
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
/* ***** BEGIN LICENSE BLOCK *****
|
|
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
|
*
|
|
* The contents of this file are subject to the Mozilla Public License Version
|
|
* 1.1 (the "License"); you may not use this file except in compliance with
|
|
* the License. You may obtain a copy of the License at
|
|
* http://www.mozilla.org/MPL/
|
|
*
|
|
* Software distributed under the License is distributed on an "AS IS" basis,
|
|
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
|
* for the specific language governing rights and limitations under the
|
|
* License.
|
|
*
|
|
* The Original Code is mozilla.org code.
|
|
*
|
|
* The Initial Developer of the Original Code is
|
|
* Netscape Communications Corporation.
|
|
* Portions created by the Initial Developer are Copyright (C) 1998
|
|
* the Initial Developer. All Rights Reserved.
|
|
*
|
|
* Contributor(s):
|
|
*
|
|
* Alternatively, the contents of this file may be used under the terms of
|
|
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
|
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
|
* in which case the provisions of the GPL or the LGPL are applicable instead
|
|
* of those above. If you wish to allow use of your version of this file only
|
|
* under the terms of either the GPL or the LGPL, and not to allow others to
|
|
* use your version of this file under the terms of the MPL, indicate your
|
|
* decision by deleting the provisions above and replace them with the notice
|
|
* and other provisions required by the GPL or the LGPL. If you do not delete
|
|
* the provisions above, a recipient may use your version of this file under
|
|
* the terms of any one of the MPL, the GPL or the LGPL.
|
|
*
|
|
* ***** END LICENSE BLOCK ***** */
|
|
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <stdlib.h>
|
|
#include <ctype.h>
|
|
|
|
#define DEFAULT_MANIFEST_EXT ".mn"
|
|
#define DEFAULT_MAKEFILE_EXT ".win"
|
|
|
|
typedef struct char_list_struct {
|
|
char *m_pString;
|
|
struct char_list_struct *m_pNext;
|
|
} char_list;
|
|
|
|
typedef struct macro_list_struct {
|
|
char *m_pMacro;
|
|
char_list *m_pValue;
|
|
struct macro_list_struct *m_pNext;
|
|
} macro_list;
|
|
|
|
void help(void);
|
|
char *input_filename(const char *);
|
|
char *output_filename(const char *, const char *);
|
|
int input_to_output(FILE *, FILE *);
|
|
int output_rules(FILE *);
|
|
int output_end(FILE *);
|
|
int buffer_to_output(char *, FILE *);
|
|
macro_list *extract_macros(char *);
|
|
char *find_macro(char *, char **);
|
|
void add_macro(char *, macro_list **);
|
|
int macro_length(char *);
|
|
int value_length(char *);
|
|
void add_values(char *, char_list **);
|
|
char *skip_white(char *);
|
|
int write_macros(macro_list *, FILE *);
|
|
int write_values(char_list *, FILE *, int);
|
|
void free_macro_list(macro_list *);
|
|
void free_char_list(char_list *);
|
|
void morph_macro(macro_list **, char *, char *, char *);
|
|
void slash_convert(macro_list *, char *);
|
|
int explicit_rules(macro_list *, char *, FILE *);
|
|
void create_classroot(macro_list **ppList );
|
|
|
|
int main(int argc, char *argv[])
|
|
{
|
|
int iOS = 0;
|
|
char *pInputFile = NULL;
|
|
char *pOutputFile = NULL;
|
|
|
|
/* Figure out arguments.
|
|
* [REQUIRED] First argument is input file.
|
|
* [OPTIONAL] Second argument is output file.
|
|
*/
|
|
if(argc > 1) {
|
|
FILE *pInputStream = NULL;
|
|
FILE *pOutputStream = NULL;
|
|
|
|
/* Form respective filenames.
|
|
*/
|
|
pInputFile = input_filename(argv[1]);
|
|
pOutputFile = output_filename(pInputFile, argc > 2 ? argv[2] : NULL);
|
|
|
|
if(pInputFile == NULL) {
|
|
fprintf(stderr, "MANTOMAK: Unable to form input filename\n");
|
|
iOS = 1;
|
|
}
|
|
else {
|
|
pInputStream = fopen(pInputFile, "rb");
|
|
if(pInputStream == NULL) {
|
|
fprintf(stderr, "MANTOMAK: Unable to open input file %s\n", pInputFile);
|
|
iOS = 1;
|
|
}
|
|
}
|
|
if(pOutputFile == NULL) {
|
|
fprintf(stderr, "MANTOMAK: Unable to form output filename\n");
|
|
iOS = 1;
|
|
}
|
|
else if(pInputStream != NULL) {
|
|
pOutputStream = fopen(pOutputFile, "wt");
|
|
if(pOutputStream == NULL) {
|
|
fprintf(stderr, "MANTOMAK: Unable to open output file %s\n", pOutputFile);
|
|
iOS = 1;
|
|
}
|
|
}
|
|
|
|
/* Only do the real processing if our error code is not
|
|
* already set.
|
|
*/
|
|
if(iOS == 0) {
|
|
iOS = input_to_output(pInputStream, pOutputStream);
|
|
}
|
|
|
|
if(pInputStream != NULL) {
|
|
fclose(pInputStream);
|
|
pInputStream = NULL;
|
|
}
|
|
if(pOutputStream != NULL) {
|
|
fclose(pOutputStream);
|
|
pOutputStream = NULL;
|
|
}
|
|
}
|
|
else {
|
|
help();
|
|
iOS = 1;
|
|
}
|
|
|
|
if(pInputFile) {
|
|
free(pInputFile);
|
|
pInputFile = NULL;
|
|
}
|
|
if(pOutputFile) {
|
|
free(pOutputFile);
|
|
pOutputFile = NULL;
|
|
}
|
|
|
|
return(iOS);
|
|
}
|
|
|
|
void help(void)
|
|
{
|
|
fprintf(stderr, "USAGE:\tmantomak.exe InputFile [OutputFile]\n\n");
|
|
fprintf(stderr, "InputFile:\tManifest file. If without extension, \"%s\" assumed.\n", DEFAULT_MANIFEST_EXT);
|
|
fprintf(stderr, "OutputFile:\tNMake file. If not present, \"InputFile%s\" assumed.\n", DEFAULT_MAKEFILE_EXT);
|
|
}
|
|
|
|
char *input_filename(const char *pInputFile)
|
|
{
|
|
char aResult[_MAX_PATH];
|
|
char aDrive[_MAX_DRIVE];
|
|
char aDir[_MAX_DIR];
|
|
char aName[_MAX_FNAME];
|
|
char aExt[_MAX_EXT];
|
|
|
|
if(pInputFile == NULL) {
|
|
return(NULL);
|
|
}
|
|
|
|
_splitpath(pInputFile, aDrive, aDir, aName, aExt);
|
|
|
|
if(aExt[0] == '\0') {
|
|
/* No extension provided.
|
|
* Use the default.
|
|
*/
|
|
strcpy(aExt, DEFAULT_MANIFEST_EXT);
|
|
}
|
|
|
|
aResult[0] = '\0';
|
|
_makepath(aResult, aDrive, aDir, aName, aExt);
|
|
|
|
if(aResult[0] == '\0') {
|
|
return(NULL);
|
|
}
|
|
else {
|
|
return(strdup(aResult));
|
|
}
|
|
}
|
|
|
|
char *output_filename(const char *pInputFile, const char *pOutputFile)
|
|
{
|
|
char aResult[_MAX_PATH];
|
|
char aDrive[_MAX_DRIVE];
|
|
char aDir[_MAX_DIR];
|
|
char aName[_MAX_FNAME];
|
|
char aExt[_MAX_EXT];
|
|
|
|
if(pOutputFile != NULL) {
|
|
return(strdup(pOutputFile));
|
|
}
|
|
|
|
/* From here on out, we have to create our own filename,
|
|
* implied from the input file name.
|
|
*/
|
|
|
|
if(pInputFile == NULL) {
|
|
return(NULL);
|
|
}
|
|
|
|
_splitpath(pInputFile, aDrive, aDir, aName, aExt);
|
|
strcpy(aExt, DEFAULT_MAKEFILE_EXT);
|
|
|
|
aResult[0] = '\0';
|
|
_makepath(aResult, aDrive, aDir, aName, aExt);
|
|
|
|
if(aResult[0] == '\0') {
|
|
return(NULL);
|
|
}
|
|
else {
|
|
return(strdup(aResult));
|
|
}
|
|
}
|
|
|
|
int input_to_output(FILE *pInput, FILE *pOutput)
|
|
{
|
|
char *pHog = NULL;
|
|
long lSize = 0;
|
|
int iRetval = 0;
|
|
|
|
/* Read the entire file into memory.
|
|
*/
|
|
fseek(pInput, 0, SEEK_END);
|
|
lSize = ftell(pInput);
|
|
fseek(pInput, 0, SEEK_SET);
|
|
|
|
pHog = (char *)malloc(lSize + 1);
|
|
if(pHog) {
|
|
*(pHog + lSize) = '\0';
|
|
fread(pHog, lSize, 1, pInput);
|
|
|
|
iRetval = buffer_to_output(pHog, pOutput);
|
|
|
|
free(pHog);
|
|
pHog = NULL;
|
|
}
|
|
else {
|
|
fprintf(stderr, "MANTOMAK: Out of Memory....\n");
|
|
iRetval = 1;
|
|
}
|
|
|
|
return(iRetval);
|
|
}
|
|
|
|
int output_rules(FILE *pOutput)
|
|
{
|
|
int iRetval = 0;
|
|
|
|
if(EOF ==
|
|
fputs("\n"
|
|
"!if \"$(MANIFEST_LEVEL)\"==\"RULES\""
|
|
"\n",
|
|
pOutput))
|
|
{
|
|
fprintf(stderr, "MANTOMAK: Error writing to file....\n");
|
|
iRetval = 1;
|
|
}
|
|
return(iRetval);
|
|
}
|
|
|
|
int output_end(FILE *pOutput)
|
|
{
|
|
int iRetval = 0;
|
|
|
|
if(EOF ==
|
|
fputs("\n"
|
|
"!endif"
|
|
"\n",
|
|
pOutput))
|
|
{
|
|
fprintf(stderr, "MANTOMAK: Error writing to file....\n");
|
|
iRetval = 1;
|
|
}
|
|
return(iRetval);
|
|
}
|
|
|
|
|
|
int buffer_to_output(char *pBuffer, FILE *pOutput)
|
|
{
|
|
int iRetval = 0;
|
|
macro_list *pMacros = NULL;
|
|
|
|
/* Tokenize the macros and their corresponding values.
|
|
*/
|
|
pMacros = extract_macros(pBuffer);
|
|
if(pMacros != NULL) {
|
|
/* Perform forward to backslash conversion on those macros known to be
|
|
* path information only.
|
|
*/
|
|
slash_convert(pMacros, "JBOOTDIRS");
|
|
slash_convert(pMacros, "JDIRS");
|
|
slash_convert(pMacros, "DEPTH");
|
|
slash_convert(pMacros, "NS_DEPTH");
|
|
slash_convert(pMacros, "PACKAGE");
|
|
slash_convert(pMacros, "JMC_GEN_DIR");
|
|
slash_convert(pMacros, "DIST_PUBLIC");
|
|
|
|
/* Process some of the macros, and convert them
|
|
* into different macros with different data.
|
|
*/
|
|
morph_macro(&pMacros, "JMC_GEN", "JMC_HEADERS", "$(JMC_GEN_DIR)\\%s.h");
|
|
morph_macro(&pMacros, "JMC_GEN", "JMC_STUBS", "$(JMC_GEN_DIR)\\%s.c");
|
|
morph_macro(&pMacros, "JMC_GEN", "JMC_OBJS", ".\\$(OBJDIR)\\%s.obj");
|
|
morph_macro(&pMacros, "CSRCS", "C_OBJS", ".\\$(OBJDIR)\\%s.obj");
|
|
morph_macro(&pMacros, "CPPSRCS", "CPP_OBJS", ".\\$(OBJDIR)\\%s.obj");
|
|
morph_macro(&pMacros, "REQUIRES", "LINCS", "-I$(XPDIST)\\public\\%s");
|
|
|
|
create_classroot( &pMacros );
|
|
|
|
/* Output the Macros and the corresponding values.
|
|
*/
|
|
iRetval = write_macros(pMacros, pOutput);
|
|
|
|
/* Output rule file inclusion
|
|
*/
|
|
if(iRetval == 0) {
|
|
iRetval = output_rules(pOutput);
|
|
}
|
|
|
|
/* Output explicit build rules/dependencies for JMC_GEN.
|
|
*/
|
|
if(iRetval == 0) {
|
|
iRetval = explicit_rules(pMacros, "JMC_GEN", pOutput);
|
|
}
|
|
|
|
if(iRetval == 0) {
|
|
iRetval = output_end(pOutput);
|
|
}
|
|
/* Free off the macro list.
|
|
*/
|
|
free_macro_list(pMacros);
|
|
pMacros = NULL;
|
|
}
|
|
|
|
return(iRetval);
|
|
}
|
|
|
|
int explicit_rules(macro_list *pList, char *pMacro, FILE *pOutput)
|
|
{
|
|
int iRetval = 0;
|
|
macro_list *pEntry = NULL;
|
|
|
|
if(pList == NULL || pMacro == NULL || pOutput == NULL) {
|
|
return(0);
|
|
}
|
|
|
|
/* Find macro of said name.
|
|
* Case insensitive.
|
|
*/
|
|
pEntry = pList;
|
|
while(pEntry) {
|
|
if(stricmp(pEntry->m_pMacro, pMacro) == 0) {
|
|
break;
|
|
}
|
|
|
|
pEntry = pEntry->m_pNext;
|
|
}
|
|
|
|
if(pEntry) {
|
|
/* Decide style of rule depending on macro name.
|
|
*/
|
|
if(stricmp(pEntry->m_pMacro, "JMC_GEN") == 0) {
|
|
char_list *pNames = NULL;
|
|
char *pModuleName = NULL;
|
|
char *pClassName = NULL;
|
|
|
|
pNames = pEntry->m_pValue;
|
|
while(pNames) {
|
|
pModuleName = pNames->m_pString;
|
|
pClassName = pModuleName + 1;
|
|
|
|
fprintf(pOutput, "$(JMC_GEN_DIR)\\%s.h", pModuleName);
|
|
fprintf(pOutput, ": ");
|
|
fprintf(pOutput, "$(JMCSRCDIR)\\%s.class", pClassName);
|
|
fprintf(pOutput, "\n ");
|
|
fprintf(pOutput, "$(JMC) -d $(JMC_GEN_DIR) -interface $(JMC_GEN_FLAGS) $(?F:.class=)");
|
|
fprintf(pOutput, "\n");
|
|
|
|
fprintf(pOutput, "$(JMC_GEN_DIR)\\%s.c", pModuleName);
|
|
fprintf(pOutput, ": ");
|
|
fprintf(pOutput, "$(JMCSRCDIR)\\%s.class", pClassName);
|
|
fprintf(pOutput, "\n ");
|
|
fprintf(pOutput, "$(JMC) -d $(JMC_GEN_DIR) -module $(JMC_GEN_FLAGS) $(?F:.class=)");
|
|
fprintf(pOutput, "\n");
|
|
|
|
pNames = pNames->m_pNext;
|
|
}
|
|
}
|
|
else {
|
|
/* Don't know how to format macro.
|
|
*/
|
|
iRetval = 69;
|
|
}
|
|
}
|
|
|
|
return(iRetval);
|
|
}
|
|
|
|
void slash_convert(macro_list *pList, char *pMacro)
|
|
{
|
|
macro_list *pEntry = NULL;
|
|
|
|
if(pList == NULL || pMacro == NULL) {
|
|
return;
|
|
}
|
|
|
|
/* Find macro of said name.
|
|
* Case insensitive.
|
|
*/
|
|
pEntry = pList;
|
|
while(pEntry) {
|
|
if(stricmp(pEntry->m_pMacro, pMacro) == 0) {
|
|
break;
|
|
}
|
|
|
|
pEntry = pEntry->m_pNext;
|
|
}
|
|
|
|
if(pEntry) {
|
|
char *pConvert = NULL;
|
|
char_list *pValue = pEntry->m_pValue;
|
|
|
|
while(pValue) {
|
|
pConvert = pValue->m_pString;
|
|
while(pConvert && *pConvert) {
|
|
if(*pConvert == '/') {
|
|
*pConvert = '\\';
|
|
}
|
|
pConvert++;
|
|
}
|
|
pValue = pValue->m_pNext;
|
|
}
|
|
}
|
|
}
|
|
|
|
void morph_macro(macro_list **ppList, char *pMacro, char *pMorph, char *pPrintf)
|
|
{
|
|
macro_list *pEntry = NULL;
|
|
|
|
if(ppList == NULL || pMacro == NULL || pMorph == NULL || pPrintf == NULL) {
|
|
return;
|
|
}
|
|
|
|
/* Find macro of said name.
|
|
* Case insensitive.
|
|
*/
|
|
pEntry = *ppList;
|
|
while(pEntry) {
|
|
if(stricmp(pEntry->m_pMacro, pMacro) == 0) {
|
|
break;
|
|
}
|
|
|
|
pEntry = pEntry->m_pNext;
|
|
}
|
|
|
|
if(pEntry) {
|
|
char_list *pFilename = NULL;
|
|
char aPath[_MAX_PATH];
|
|
char aDrive[_MAX_DRIVE];
|
|
char aDir[_MAX_DIR];
|
|
char aFName[_MAX_FNAME];
|
|
char aExt[_MAX_EXT];
|
|
char *pBuffer = NULL;
|
|
|
|
/* Start with buffer size needed.
|
|
* We expand this as we go along if needed.
|
|
*/
|
|
pBuffer = (char *)malloc(strlen(pMorph) + 2);
|
|
strcpy(pBuffer, pMorph);
|
|
strcat(pBuffer, "=");
|
|
|
|
/* Go through each value, converting over to new macro.
|
|
*/
|
|
pFilename = pEntry->m_pValue;
|
|
while(pFilename) {
|
|
_splitpath(pFilename->m_pString, aDrive, aDir, aFName, aExt);
|
|
|
|
/* Expand buffer by required amount.
|
|
*/
|
|
sprintf(aPath, pPrintf, aFName);
|
|
strcat(aPath, " ");
|
|
pBuffer = (char *)realloc(pBuffer, _msize(pBuffer) + strlen(aPath));
|
|
strcat(pBuffer, aPath);
|
|
|
|
pFilename = pFilename->m_pNext;
|
|
}
|
|
|
|
/* Add the macro.
|
|
*/
|
|
add_macro(pBuffer, ppList);
|
|
|
|
free(pBuffer);
|
|
pBuffer = NULL;
|
|
}
|
|
}
|
|
|
|
void create_classroot(macro_list **ppList )
|
|
{
|
|
char cwd[512];
|
|
int i, i2;
|
|
macro_list *pEntry = NULL;
|
|
macro_list *pE;
|
|
|
|
/* Find macro of said name.
|
|
* Case insensitive.
|
|
*/
|
|
pEntry = *ppList;
|
|
while(pEntry) {
|
|
if(stricmp(pEntry->m_pMacro, "PACKAGE") == 0) {
|
|
break;
|
|
}
|
|
|
|
pEntry = pEntry->m_pNext;
|
|
}
|
|
|
|
if(pEntry == 0 || pEntry->m_pValue == 0 || pEntry->m_pValue->m_pString == 0) {
|
|
return;
|
|
}
|
|
|
|
_getcwd( cwd, 512 );
|
|
|
|
i = strlen( pEntry->m_pValue->m_pString );
|
|
i2 = strlen( cwd );
|
|
|
|
cwd[i2-i-1] = 0;
|
|
|
|
pE = NULL;
|
|
pE = (macro_list *)calloc(sizeof(macro_list),1);
|
|
pE->m_pMacro = strdup("CLASSROOT");
|
|
pE->m_pValue = (char_list *)calloc(sizeof(char_list),1);
|
|
pE->m_pValue->m_pString = strdup(cwd);
|
|
|
|
while(*ppList) {
|
|
ppList = &((*ppList)->m_pNext);
|
|
}
|
|
*ppList = pE;
|
|
}
|
|
|
|
|
|
int write_macros(macro_list *pList, FILE *pOutput)
|
|
{
|
|
int iRetval = 0;
|
|
int iLineLength = 0;
|
|
|
|
if(pList == NULL || pOutput == NULL) {
|
|
return(0);
|
|
}
|
|
|
|
if(EOF ==
|
|
fputs("\n"
|
|
"!if \"$(MANIFEST_LEVEL)\"==\"MACROS\""
|
|
"\n",
|
|
pOutput))
|
|
{
|
|
fprintf(stderr, "MANTOMAK: Error writing to file....\n");
|
|
return(1);
|
|
}
|
|
|
|
while(pList) {
|
|
int bIgnoreForWin16 = 0;
|
|
|
|
/* The following macros should not be emitted for Win16 */
|
|
if (0 == strcmp(pList->m_pMacro, "LINCS")) {
|
|
bIgnoreForWin16 = 1;
|
|
}
|
|
|
|
|
|
if (bIgnoreForWin16) {
|
|
if(0 > fprintf(pOutput, "!if \"$(MOZ_BITS)\" != \"16\"\n")) {
|
|
fprintf(stderr, "MANTOMAK: Error writing to file....\n");
|
|
iRetval = 1;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if(0 > fprintf(pOutput, "%s=", pList->m_pMacro)) {
|
|
fprintf(stderr, "MANTOMAK: Error writing to file....\n");
|
|
iRetval = 1;
|
|
break;
|
|
}
|
|
iLineLength += strlen(pList->m_pMacro) + 1;
|
|
|
|
iRetval = write_values(pList->m_pValue, pOutput, iLineLength);
|
|
if(iRetval) {
|
|
break;
|
|
}
|
|
|
|
if(EOF == fputc('\n', pOutput)) {
|
|
fprintf(stderr, "MANTOMAK: Error writing to file....\n");
|
|
iRetval = 1;
|
|
break;
|
|
}
|
|
iLineLength = 0;
|
|
|
|
pList = pList->m_pNext;
|
|
|
|
if (bIgnoreForWin16) {
|
|
if(0 > fprintf(pOutput, "!endif\n")) {
|
|
fprintf(stderr, "MANTOMAK: Error writing to file....\n");
|
|
iRetval = 1;
|
|
break;
|
|
}
|
|
bIgnoreForWin16 = 0;
|
|
}
|
|
}
|
|
|
|
if(EOF ==
|
|
fputs("\n"
|
|
"!endif"
|
|
"\n",
|
|
pOutput))
|
|
{
|
|
fprintf(stderr, "MANTOMAK: Error writing to file....\n");
|
|
return(1);
|
|
}
|
|
return(iRetval);
|
|
}
|
|
|
|
int write_values(char_list *pList, FILE *pOutput, int iLineLength)
|
|
{
|
|
int iRetval = 0;
|
|
|
|
if(pList == NULL || pOutput == NULL) {
|
|
return(0);
|
|
}
|
|
|
|
while(pList) {
|
|
if(iLineLength == 0) {
|
|
if(EOF == fputs(" ", pOutput)) {
|
|
fprintf(stderr, "MANTOMAK: Error writing to file....\n");
|
|
iRetval = 1;
|
|
break;
|
|
}
|
|
iLineLength += 4;
|
|
|
|
if(0 > fprintf(pOutput, "%s ", pList->m_pString)) {
|
|
fprintf(stderr, "MANTOMAK: Error writing to file....\n");
|
|
iRetval = 1;
|
|
break;
|
|
}
|
|
iLineLength += strlen(pList->m_pString) + 1;
|
|
}
|
|
else if(iLineLength + strlen(pList->m_pString) > 72) {
|
|
if(EOF == fputs("\\\n", pOutput)) {
|
|
fprintf(stderr, "MANTOMAK: Error writing to file....\n");
|
|
iRetval = 1;
|
|
break;
|
|
}
|
|
iLineLength = 0;
|
|
continue;
|
|
}
|
|
else {
|
|
if(0 > fprintf(pOutput, "%s ", pList->m_pString)) {
|
|
fprintf(stderr, "MANTOMAK: Error writing to file....\n");
|
|
iRetval = 1;
|
|
break;
|
|
}
|
|
iLineLength += strlen(pList->m_pString) + 1;
|
|
}
|
|
|
|
pList = pList->m_pNext;
|
|
}
|
|
|
|
return(iRetval);
|
|
}
|
|
|
|
macro_list *extract_macros(char *pBuffer)
|
|
{
|
|
macro_list *pRetval = NULL;
|
|
char *pTraverse = NULL;
|
|
char *pMacro = NULL;
|
|
|
|
pTraverse = pBuffer;
|
|
while(pTraverse) {
|
|
pMacro = NULL;
|
|
pTraverse = find_macro(pTraverse, &pMacro);
|
|
if(pMacro) {
|
|
add_macro(pMacro, &pRetval);
|
|
}
|
|
}
|
|
|
|
return(pRetval);
|
|
}
|
|
|
|
void add_macro(char *pString, macro_list **ppList)
|
|
{
|
|
macro_list *pEntry = NULL;
|
|
int iLength = 0;
|
|
|
|
if(pString == NULL || *pString == '\0' || ppList == NULL) {
|
|
return;
|
|
}
|
|
|
|
/* Allocate a new list entry for the macro.
|
|
*/
|
|
pEntry = (macro_list *)calloc(1, sizeof(macro_list));
|
|
|
|
/* Very first part of the string is the macro name.
|
|
* How long is it?
|
|
*/
|
|
iLength = macro_length(pString);
|
|
pEntry->m_pMacro = (char *)calloc(iLength + 1, 1);
|
|
strncpy(pEntry->m_pMacro, pString, iLength);
|
|
|
|
/* Skip to the values.
|
|
* These are always on the right side of an '='
|
|
*/
|
|
pString = strchr(pString, '=');
|
|
if(pString) {
|
|
pString++;
|
|
}
|
|
add_values(pString, &(pEntry->m_pValue));
|
|
|
|
/* Add the macro to the end of the macro list.
|
|
*/
|
|
while(*ppList) {
|
|
ppList = &((*ppList)->m_pNext);
|
|
}
|
|
*ppList = pEntry;
|
|
}
|
|
|
|
void add_values(char *pString, char_list **ppList)
|
|
{
|
|
char_list **ppTraverse = NULL;
|
|
char_list *pEntry = NULL;
|
|
int iLength = 0;
|
|
int iBackslash = 0;
|
|
|
|
if(pString == NULL || *pString == '\0' || ppList == NULL) {
|
|
return;
|
|
}
|
|
|
|
while(pString) {
|
|
/* Find start of value.
|
|
*/
|
|
iBackslash = 0;
|
|
while(*pString) {
|
|
if(*pString == '\\') {
|
|
iBackslash++;
|
|
}
|
|
else if(*pString == '\n') {
|
|
if(iBackslash == 0) {
|
|
/* End of values.
|
|
* Setting to NULL gets out of all loops.
|
|
*/
|
|
pString = NULL;
|
|
break;
|
|
}
|
|
iBackslash = 0;
|
|
}
|
|
else if(!isspace(*pString)) {
|
|
/* Backslashes part of string.
|
|
* This screws up if a backslash is in the middle of the string.
|
|
*/
|
|
pString -= iBackslash;
|
|
break;
|
|
}
|
|
|
|
pString++;
|
|
}
|
|
if(pString == NULL || *pString == '\0') {
|
|
break;
|
|
}
|
|
|
|
/* Do not honor anything beginning with a #
|
|
*/
|
|
if(*pString == '#') {
|
|
/* End of line.
|
|
*/
|
|
while(*pString && *pString != '\n') {
|
|
pString++;
|
|
}
|
|
continue;
|
|
}
|
|
|
|
/* Very first part of the string is value name.
|
|
* How long is it?
|
|
*/
|
|
iLength = value_length(pString);
|
|
|
|
/* Do not honor $(NULL)
|
|
*/
|
|
if(_strnicmp(pString, "$(NULL)", 7) == 0) {
|
|
pString += iLength;
|
|
continue;
|
|
}
|
|
|
|
/* Allocate a new list entry for the next value.
|
|
*/
|
|
pEntry = (char_list *)calloc(1, sizeof(char_list));
|
|
|
|
pEntry->m_pString = (char *)calloc(iLength + 1, 1);
|
|
strncpy(pEntry->m_pString, pString, iLength);
|
|
|
|
/* Add new value entry to the end of the list.
|
|
*/
|
|
ppTraverse = ppList;
|
|
while(*ppTraverse) {
|
|
ppTraverse = &((*ppTraverse)->m_pNext);
|
|
}
|
|
*ppTraverse = pEntry;
|
|
|
|
/* Go on to next value.
|
|
*/
|
|
pString += iLength;
|
|
}
|
|
}
|
|
|
|
char *find_macro(char *pBuffer, char **ppMacro)
|
|
{
|
|
char *pRetval = NULL;
|
|
int iBackslash = 0;
|
|
|
|
if(pBuffer == NULL || ppMacro == NULL) {
|
|
return(NULL);
|
|
}
|
|
|
|
/* Skip any whitespace in the buffer.
|
|
* If comments need to be skipped also, this is the place.
|
|
*/
|
|
while(1) {
|
|
while(*pBuffer && isspace(*pBuffer)) {
|
|
pBuffer++;
|
|
}
|
|
if(*pBuffer == '#') {
|
|
/* Go to the end of the line, it's a comment.
|
|
*/
|
|
while(*pBuffer && *pBuffer != '\n') {
|
|
pBuffer++;
|
|
}
|
|
|
|
continue;
|
|
}
|
|
break;
|
|
}
|
|
|
|
if(*pBuffer) {
|
|
/* Should be at the start of a macro.
|
|
*/
|
|
*ppMacro = pBuffer;
|
|
}
|
|
|
|
/* Find the end of the macro for the return value.
|
|
* This is the end of a line which does not contain a backslash at the end.
|
|
*/
|
|
while(*pBuffer) {
|
|
if(*pBuffer == '\\') {
|
|
iBackslash++;
|
|
}
|
|
else if(*pBuffer == '\n') {
|
|
if(iBackslash == 0) {
|
|
pRetval = pBuffer + 1;
|
|
break;
|
|
}
|
|
iBackslash = 0;
|
|
}
|
|
else if(!isspace(*pBuffer)) {
|
|
iBackslash = 0;
|
|
}
|
|
|
|
pBuffer++;
|
|
}
|
|
|
|
return(pRetval);
|
|
}
|
|
|
|
int macro_length(char *pMacro)
|
|
{
|
|
int iRetval = 0;
|
|
|
|
if(pMacro == NULL) {
|
|
return(0);
|
|
}
|
|
|
|
/* Length is no big deal.
|
|
* Problem is finding the end:
|
|
* whitespace
|
|
* '='
|
|
*/
|
|
while(*pMacro) {
|
|
if(*pMacro == '=') {
|
|
break;
|
|
}
|
|
else if(isspace(*pMacro)) {
|
|
break;
|
|
}
|
|
|
|
pMacro++;
|
|
iRetval++;
|
|
}
|
|
|
|
return(iRetval);
|
|
}
|
|
|
|
int value_length(char *pValue)
|
|
{
|
|
int iRetval = 0;
|
|
|
|
if(pValue == NULL) {
|
|
return(0);
|
|
}
|
|
|
|
/* Length is no big deal.
|
|
* Problem is finding the end:
|
|
* whitespace
|
|
* '\\'whitespace
|
|
*/
|
|
while(*pValue) {
|
|
if(*pValue == '\\') {
|
|
char *pFindNewline = pValue + 1;
|
|
/* If whitespace to end of line, break here.
|
|
*/
|
|
while(isspace(*pFindNewline)) {
|
|
if(*pFindNewline == '\n') {
|
|
break;
|
|
}
|
|
pFindNewline++;
|
|
}
|
|
if(*pFindNewline == '\n') {
|
|
break;
|
|
}
|
|
}
|
|
else if(isspace(*pValue)) {
|
|
break;
|
|
}
|
|
|
|
pValue++;
|
|
iRetval++;
|
|
}
|
|
|
|
return(iRetval);
|
|
}
|
|
|
|
char *skip_white(char *pString)
|
|
{
|
|
if(pString == NULL) {
|
|
return(NULL);
|
|
}
|
|
|
|
while(*pString && isspace(*pString)) {
|
|
pString++;
|
|
}
|
|
|
|
return(pString);
|
|
}
|
|
|
|
void free_macro_list(macro_list *pList)
|
|
{
|
|
macro_list *pFree = NULL;
|
|
|
|
if(pList == NULL) {
|
|
return;
|
|
}
|
|
|
|
while(pList) {
|
|
pFree = pList;
|
|
pList = pList->m_pNext;
|
|
|
|
pFree->m_pNext = NULL;
|
|
|
|
free_char_list(pFree->m_pValue);
|
|
pFree->m_pValue = NULL;
|
|
|
|
free(pFree->m_pMacro);
|
|
pFree->m_pMacro = NULL;
|
|
|
|
free(pFree);
|
|
pFree = NULL;
|
|
}
|
|
}
|
|
|
|
void free_char_list(char_list *pList)
|
|
{
|
|
char_list *pFree = NULL;
|
|
|
|
if(pList == NULL) {
|
|
return;
|
|
}
|
|
|
|
while(pList) {
|
|
pFree = pList;
|
|
pList = pList->m_pNext;
|
|
|
|
pFree->m_pNext = NULL;
|
|
|
|
free(pFree->m_pString);
|
|
pFree->m_pString = NULL;
|
|
|
|
free(pFree);
|
|
pFree = NULL;
|
|
}
|
|
}
|