Back to index

lightning-sunbird  0.9+nobinonly
mantomak.c
Go to the documentation of this file.
00001 /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is mozilla.org code.
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 1998
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *
00024  * Alternatively, the contents of this file may be used under the terms of
00025  * either of the GNU General Public License Version 2 or later (the "GPL"),
00026  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00027  * in which case the provisions of the GPL or the LGPL are applicable instead
00028  * of those above. If you wish to allow use of your version of this file only
00029  * under the terms of either the GPL or the LGPL, and not to allow others to
00030  * use your version of this file under the terms of the MPL, indicate your
00031  * decision by deleting the provisions above and replace them with the notice
00032  * and other provisions required by the GPL or the LGPL. If you do not delete
00033  * the provisions above, a recipient may use your version of this file under
00034  * the terms of any one of the MPL, the GPL or the LGPL.
00035  *
00036  * ***** END LICENSE BLOCK ***** */
00037 
00038 #include <stdio.h>
00039 #include <string.h>
00040 #include <stdlib.h>
00041 #include <ctype.h>
00042 
00043 #define DEFAULT_MANIFEST_EXT ".mn"
00044 #define DEFAULT_MAKEFILE_EXT ".win"
00045 
00046 typedef struct char_list_struct {
00047     char *m_pString;
00048     struct char_list_struct *m_pNext;
00049 } char_list;
00050 
00051 typedef struct macro_list_struct   {
00052     char *m_pMacro;
00053     char_list *m_pValue;
00054     struct macro_list_struct *m_pNext;
00055 } macro_list;
00056 
00057 void help(void);
00058 char *input_filename(const char *);
00059 char *output_filename(const char *, const char *);
00060 int input_to_output(FILE *, FILE *);
00061 int output_rules(FILE *);
00062 int output_end(FILE *);
00063 int buffer_to_output(char *, FILE *);
00064 macro_list *extract_macros(char *);
00065 char *find_macro(char *, char **);
00066 void add_macro(char *, macro_list **);
00067 int macro_length(char *);
00068 int value_length(char *);
00069 void add_values(char *, char_list **);
00070 char *skip_white(char *);
00071 int write_macros(macro_list *, FILE *);
00072 int write_values(char_list *, FILE *, int);
00073 void free_macro_list(macro_list *);
00074 void free_char_list(char_list *);
00075 void morph_macro(macro_list **, char *, char *, char *);
00076 void slash_convert(macro_list *, char *);
00077 int explicit_rules(macro_list *, char *, FILE *);
00078 void create_classroot(macro_list **ppList );
00079 
00080 int main(int argc, char *argv[])
00081 {
00082        int iOS = 0;
00083        char *pInputFile = NULL;
00084        char *pOutputFile = NULL;
00085 
00086        /*      Figure out arguments.
00087         *      [REQUIRED] First argument is input file.
00088         *      [OPTIONAL] Second argument is output file.
00089         */
00090        if(argc > 1)    {
00091               FILE *pInputStream = NULL;
00092               FILE *pOutputStream = NULL;
00093 
00094               /*      Form respective filenames.
00095                */
00096               pInputFile = input_filename(argv[1]);
00097               pOutputFile = output_filename(pInputFile, argc > 2 ? argv[2] : NULL);
00098 
00099               if(pInputFile == NULL)  {
00100                      fprintf(stderr, "MANTOMAK:  Unable to form input filename\n");
00101                      iOS = 1;
00102               }
00103               else    {
00104                      pInputStream = fopen(pInputFile, "rb");
00105                      if(pInputStream == NULL)        {
00106                             fprintf(stderr, "MANTOMAK:  Unable to open input file %s\n", pInputFile);
00107                             iOS = 1;
00108                      }
00109               }
00110               if(pOutputFile == NULL) {
00111                      fprintf(stderr, "MANTOMAK:  Unable to form output filename\n");
00112                      iOS = 1;
00113               }
00114               else if(pInputStream != NULL)   {
00115                      pOutputStream = fopen(pOutputFile, "wt");
00116                      if(pOutputStream == NULL)       {
00117                             fprintf(stderr, "MANTOMAK:  Unable to open output file %s\n", pOutputFile);
00118                             iOS = 1;
00119                      }
00120               }
00121 
00122               /*      Only do the real processing if our error code is not
00123                *              already set.
00124                */
00125               if(iOS == 0)    {
00126                      iOS = input_to_output(pInputStream, pOutputStream);
00127               }
00128 
00129               if(pInputStream != NULL)        {
00130                      fclose(pInputStream);
00131                      pInputStream = NULL;
00132               }
00133               if(pOutputStream != NULL)       {
00134                      fclose(pOutputStream);
00135                      pOutputStream = NULL;
00136               }
00137        }
00138        else    {
00139               help();
00140               iOS = 1;
00141        }
00142 
00143        if(pInputFile)  {
00144               free(pInputFile);
00145               pInputFile = NULL;
00146        }
00147        if(pOutputFile) {
00148               free(pOutputFile);
00149               pOutputFile = NULL;
00150        }
00151 
00152        return(iOS);
00153 }
00154 
00155 void help(void)
00156 {
00157        fprintf(stderr, "USAGE:\tmantomak.exe InputFile [OutputFile]\n\n");
00158        fprintf(stderr, "InputFile:\tManifest file.  If without extension, \"%s\" assumed.\n", DEFAULT_MANIFEST_EXT);
00159        fprintf(stderr, "OutputFile:\tNMake file.  If not present, \"InputFile%s\" assumed.\n", DEFAULT_MAKEFILE_EXT);
00160 }
00161 
00162 char *input_filename(const char *pInputFile)
00163 {
00164        char aResult[_MAX_PATH];
00165        char aDrive[_MAX_DRIVE];
00166        char aDir[_MAX_DIR];
00167        char aName[_MAX_FNAME];
00168        char aExt[_MAX_EXT];
00169 
00170        if(pInputFile == NULL)  {
00171               return(NULL);
00172        }
00173 
00174        _splitpath(pInputFile, aDrive, aDir, aName, aExt);
00175 
00176        if(aExt[0] == '\0')     {
00177               /*      No extension provided.
00178                *      Use the default.
00179                */
00180               strcpy(aExt, DEFAULT_MANIFEST_EXT);
00181        }
00182 
00183        aResult[0] = '\0';
00184        _makepath(aResult, aDrive, aDir, aName, aExt);
00185 
00186        if(aResult[0] == '\0')  {
00187               return(NULL);
00188        }
00189        else    {
00190               return(strdup(aResult));
00191        }
00192 }
00193 
00194 char *output_filename(const char *pInputFile, const char *pOutputFile)
00195 {
00196        char aResult[_MAX_PATH];
00197        char aDrive[_MAX_DRIVE];
00198        char aDir[_MAX_DIR];
00199        char aName[_MAX_FNAME];
00200        char aExt[_MAX_EXT];
00201 
00202        if(pOutputFile != NULL) {
00203               return(strdup(pOutputFile));
00204        }
00205 
00206        /*      From here on out, we have to create our own filename,
00207         *              implied from the input file name.
00208         */
00209 
00210        if(pInputFile == NULL)  {
00211               return(NULL);
00212        }
00213 
00214        _splitpath(pInputFile, aDrive, aDir, aName, aExt);
00215        strcpy(aExt, DEFAULT_MAKEFILE_EXT);
00216 
00217        aResult[0] = '\0';
00218        _makepath(aResult, aDrive, aDir, aName, aExt);
00219 
00220        if(aResult[0] == '\0')  {
00221               return(NULL);
00222        }
00223        else    {
00224               return(strdup(aResult));
00225        }
00226 }
00227 
00228 int input_to_output(FILE *pInput, FILE *pOutput)
00229 {
00230        char *pHog = NULL;
00231        long lSize = 0;
00232        int iRetval = 0;
00233 
00234        /*      Read the entire file into memory.
00235         */
00236        fseek(pInput, 0, SEEK_END);
00237        lSize = ftell(pInput);
00238        fseek(pInput, 0, SEEK_SET);
00239 
00240        pHog = (char *)malloc(lSize + 1);
00241        if(pHog)        {
00242               *(pHog + lSize) = '\0';
00243               fread(pHog, lSize, 1, pInput);
00244 
00245               iRetval = buffer_to_output(pHog, pOutput);
00246 
00247               free(pHog);
00248               pHog = NULL;
00249        }
00250        else    {
00251               fprintf(stderr, "MANTOMAK:  Out of Memory....\n");
00252               iRetval = 1;
00253        }
00254 
00255        return(iRetval);
00256 }
00257 
00258 int output_rules(FILE *pOutput)
00259 {
00260        int iRetval = 0;
00261 
00262        if(EOF ==
00263        fputs("\n"
00264              "!if \"$(MANIFEST_LEVEL)\"==\"RULES\""
00265              "\n",
00266            pOutput))
00267     {
00268               fprintf(stderr, "MANTOMAK:  Error writing to file....\n");
00269               iRetval = 1;
00270        }
00271        return(iRetval);
00272 }
00273 
00274 int output_end(FILE *pOutput)
00275 {
00276        int iRetval = 0;
00277 
00278        if(EOF ==
00279        fputs("\n"
00280              "!endif"
00281              "\n",
00282            pOutput))
00283     {
00284               fprintf(stderr, "MANTOMAK:  Error writing to file....\n");
00285               iRetval = 1;
00286        }
00287        return(iRetval);
00288 }
00289 
00290 
00291 int buffer_to_output(char *pBuffer, FILE *pOutput)
00292 {
00293     int iRetval = 0;
00294     macro_list *pMacros = NULL;
00295 
00296     /*  Tokenize the macros and their corresponding values.
00297      */
00298     pMacros = extract_macros(pBuffer);
00299     if(pMacros != NULL) {
00300        /*  Perform forward to backslash conversion on those macros known to be
00301         *      path information only.
00302         */
00303        slash_convert(pMacros, "JBOOTDIRS");
00304        slash_convert(pMacros, "JDIRS");
00305        slash_convert(pMacros, "DEPTH");
00306        slash_convert(pMacros, "NS_DEPTH");
00307        slash_convert(pMacros, "PACKAGE");
00308        slash_convert(pMacros, "JMC_GEN_DIR");
00309        slash_convert(pMacros, "DIST_PUBLIC");
00310 
00311        /*  Process some of the macros, and convert them
00312         *      into different macros with different data.
00313         */
00314        morph_macro(&pMacros, "JMC_GEN", "JMC_HEADERS", "$(JMC_GEN_DIR)\\%s.h");
00315        morph_macro(&pMacros, "JMC_GEN", "JMC_STUBS", "$(JMC_GEN_DIR)\\%s.c");
00316        morph_macro(&pMacros, "JMC_GEN", "JMC_OBJS", ".\\$(OBJDIR)\\%s.obj");
00317        morph_macro(&pMacros, "CSRCS", "C_OBJS", ".\\$(OBJDIR)\\%s.obj");
00318        morph_macro(&pMacros, "CPPSRCS", "CPP_OBJS", ".\\$(OBJDIR)\\%s.obj");
00319        morph_macro(&pMacros, "REQUIRES", "LINCS", "-I$(XPDIST)\\public\\%s");
00320 
00321        create_classroot( &pMacros );
00322 
00323        /*  Output the Macros and the corresponding values.
00324         */
00325        iRetval = write_macros(pMacros, pOutput);
00326 
00327        /*  Output rule file inclusion
00328         */
00329        if(iRetval == 0)    {
00330            iRetval = output_rules(pOutput);
00331        }
00332 
00333        /*  Output explicit build rules/dependencies for JMC_GEN.
00334         */
00335        if(iRetval == 0)    {
00336            iRetval = explicit_rules(pMacros, "JMC_GEN", pOutput);
00337        }
00338 
00339        if(iRetval == 0)    {
00340            iRetval = output_end(pOutput);
00341        }
00342        /*  Free off the macro list.
00343         */
00344        free_macro_list(pMacros);
00345        pMacros = NULL;
00346     }
00347 
00348     return(iRetval);
00349 }
00350 
00351 int explicit_rules(macro_list *pList, char *pMacro, FILE *pOutput)
00352 {
00353     int iRetval = 0;
00354     macro_list *pEntry = NULL;
00355 
00356     if(pList == NULL || pMacro == NULL || pOutput == NULL) {
00357        return(0);
00358     }
00359 
00360     /*  Find macro of said name.
00361      *  Case insensitive.
00362      */
00363     pEntry = pList;
00364     while(pEntry)    {
00365        if(stricmp(pEntry->m_pMacro, pMacro) == 0)  {
00366            break;
00367        }
00368 
00369        pEntry = pEntry->m_pNext;
00370     }
00371 
00372     if(pEntry)  {
00373        /*  Decide style of rule depending on macro name.
00374         */
00375        if(stricmp(pEntry->m_pMacro, "JMC_GEN") == 0)    {
00376            char_list *pNames = NULL;
00377            char *pModuleName = NULL;
00378            char *pClassName = NULL;
00379 
00380            pNames = pEntry->m_pValue;
00381            while(pNames)   {
00382               pModuleName = pNames->m_pString;
00383               pClassName = pModuleName + 1;
00384 
00385               fprintf(pOutput, "$(JMC_GEN_DIR)\\%s.h", pModuleName);
00386               fprintf(pOutput, ": ");
00387               fprintf(pOutput, "$(JMCSRCDIR)\\%s.class", pClassName);
00388               fprintf(pOutput, "\n    ");
00389               fprintf(pOutput, "$(JMC) -d $(JMC_GEN_DIR) -interface $(JMC_GEN_FLAGS) $(?F:.class=)");
00390               fprintf(pOutput, "\n");
00391 
00392               fprintf(pOutput, "$(JMC_GEN_DIR)\\%s.c", pModuleName);
00393               fprintf(pOutput, ": ");
00394               fprintf(pOutput, "$(JMCSRCDIR)\\%s.class", pClassName);
00395               fprintf(pOutput, "\n    ");
00396               fprintf(pOutput, "$(JMC) -d $(JMC_GEN_DIR) -module $(JMC_GEN_FLAGS) $(?F:.class=)");
00397               fprintf(pOutput, "\n");
00398 
00399               pNames = pNames->m_pNext;
00400            }
00401        }
00402        else    {
00403            /*  Don't know how to format macro.
00404             */
00405            iRetval = 69;
00406        }
00407     }
00408 
00409     return(iRetval);
00410 }
00411 
00412 void slash_convert(macro_list *pList, char *pMacro)
00413 {
00414     macro_list *pEntry = NULL;
00415 
00416     if(pList == NULL || pMacro == NULL) {
00417        return;
00418     }
00419 
00420     /*  Find macro of said name.
00421      *  Case insensitive.
00422      */
00423     pEntry = pList;
00424     while(pEntry)    {
00425        if(stricmp(pEntry->m_pMacro, pMacro) == 0)  {
00426            break;
00427        }
00428 
00429        pEntry = pEntry->m_pNext;
00430     }
00431 
00432     if(pEntry)  {
00433        char *pConvert = NULL;
00434        char_list *pValue = pEntry->m_pValue;
00435 
00436        while(pValue)   {
00437            pConvert = pValue->m_pString;
00438            while(pConvert && *pConvert)    {
00439               if(*pConvert == '/')    {
00440                   *pConvert = '\\';
00441               }
00442               pConvert++;
00443            }
00444            pValue = pValue->m_pNext;
00445        }
00446     }
00447 }
00448 
00449 void morph_macro(macro_list **ppList, char *pMacro, char *pMorph, char *pPrintf)
00450 {
00451     macro_list *pEntry = NULL;
00452 
00453     if(ppList == NULL || pMacro == NULL || pMorph == NULL || pPrintf == NULL) {
00454        return;
00455     }
00456 
00457     /*  Find macro of said name.
00458      *  Case insensitive.
00459      */
00460     pEntry = *ppList;
00461     while(pEntry)    {
00462        if(stricmp(pEntry->m_pMacro, pMacro) == 0)  {
00463            break;
00464        }
00465 
00466        pEntry = pEntry->m_pNext;
00467     }
00468 
00469     if(pEntry)  {
00470        char_list *pFilename = NULL;
00471        char aPath[_MAX_PATH];
00472        char aDrive[_MAX_DRIVE];
00473        char aDir[_MAX_DIR];
00474        char aFName[_MAX_FNAME];
00475        char aExt[_MAX_EXT];
00476        char *pBuffer = NULL;
00477 
00478        /*  Start with buffer size needed.
00479         *  We expand this as we go along if needed.
00480         */
00481        pBuffer = (char *)malloc(strlen(pMorph) + 2);
00482        strcpy(pBuffer, pMorph);
00483        strcat(pBuffer, "=");
00484 
00485        /*  Go through each value, converting over to new macro.
00486         */
00487        pFilename = pEntry->m_pValue;
00488        while(pFilename) {
00489            _splitpath(pFilename->m_pString, aDrive, aDir, aFName, aExt);
00490 
00491            /*  Expand buffer by required amount.
00492             */
00493            sprintf(aPath, pPrintf, aFName);
00494            strcat(aPath, " ");
00495            pBuffer = (char *)realloc(pBuffer, _msize(pBuffer) + strlen(aPath));
00496            strcat(pBuffer, aPath);
00497 
00498            pFilename = pFilename->m_pNext;
00499        }
00500 
00501        /*  Add the macro.
00502         */
00503        add_macro(pBuffer, ppList);
00504 
00505        free(pBuffer);
00506        pBuffer = NULL;
00507     }
00508 }
00509 
00510 void create_classroot(macro_list **ppList )
00511 {
00512     char cwd[512];
00513     int i, i2;
00514     macro_list *pEntry = NULL;
00515     macro_list *pE;
00516 
00517     /*  Find macro of said name.
00518      *  Case insensitive.
00519      */
00520     pEntry = *ppList;
00521     while(pEntry)    {
00522        if(stricmp(pEntry->m_pMacro, "PACKAGE") == 0)  {
00523            break;
00524        }
00525 
00526        pEntry = pEntry->m_pNext;
00527     }
00528 
00529     if(pEntry == 0 || pEntry->m_pValue == 0 || pEntry->m_pValue->m_pString == 0)  {
00530        return;
00531     }
00532 
00533     _getcwd( cwd, 512 );
00534 
00535     i = strlen( pEntry->m_pValue->m_pString );
00536     i2 = strlen( cwd );
00537 
00538     cwd[i2-i-1] = 0;
00539 
00540     pE = NULL;
00541     pE = (macro_list *)calloc(sizeof(macro_list),1);
00542     pE->m_pMacro = strdup("CLASSROOT");
00543     pE->m_pValue = (char_list *)calloc(sizeof(char_list),1);
00544     pE->m_pValue->m_pString = strdup(cwd);
00545 
00546     while(*ppList)  {
00547        ppList = &((*ppList)->m_pNext);
00548     }
00549     *ppList = pE;
00550 }
00551 
00552 
00553 int write_macros(macro_list *pList, FILE *pOutput)
00554 {
00555     int iRetval = 0;
00556     int iLineLength = 0;
00557 
00558     if(pList == NULL || pOutput == NULL)    {
00559        return(0);
00560     }
00561 
00562        if(EOF ==
00563        fputs("\n"
00564              "!if \"$(MANIFEST_LEVEL)\"==\"MACROS\""
00565              "\n",
00566            pOutput))
00567     {
00568               fprintf(stderr, "MANTOMAK:  Error writing to file....\n");
00569               return(1);
00570        }
00571 
00572     while(pList)    {
00573         int bIgnoreForWin16 = 0;
00574 
00575         /* The following macros should not be emitted for Win16 */
00576         if (0 == strcmp(pList->m_pMacro, "LINCS")) {
00577             bIgnoreForWin16 = 1;
00578         }
00579 
00580 
00581         if (bIgnoreForWin16) {
00582             if(0 > fprintf(pOutput, "!if \"$(MOZ_BITS)\" != \"16\"\n"))  {
00583                 fprintf(stderr, "MANTOMAK:  Error writing to file....\n");
00584                 iRetval = 1;
00585                 break;
00586             }
00587         }
00588 
00589        if(0 > fprintf(pOutput, "%s=", pList->m_pMacro))  {
00590               fprintf(stderr, "MANTOMAK:  Error writing to file....\n");
00591            iRetval = 1;
00592            break;
00593        }
00594        iLineLength += strlen(pList->m_pMacro) + 1;
00595 
00596        iRetval = write_values(pList->m_pValue, pOutput, iLineLength);
00597        if(iRetval) {
00598            break;
00599        }
00600 
00601        if(EOF == fputc('\n', pOutput))    {
00602               fprintf(stderr, "MANTOMAK:  Error writing to file....\n");
00603            iRetval = 1;
00604            break;
00605        }
00606        iLineLength = 0;
00607 
00608        pList = pList->m_pNext;
00609 
00610         if (bIgnoreForWin16) {
00611             if(0 > fprintf(pOutput, "!endif\n"))  {
00612                 fprintf(stderr, "MANTOMAK:  Error writing to file....\n");
00613                 iRetval = 1;
00614                 break;
00615             }
00616             bIgnoreForWin16 = 0;
00617         }
00618     }
00619 
00620        if(EOF ==
00621        fputs("\n"
00622              "!endif"
00623              "\n",
00624            pOutput))
00625     {
00626               fprintf(stderr, "MANTOMAK:  Error writing to file....\n");
00627               return(1);
00628        }
00629     return(iRetval);
00630 }
00631 
00632 int write_values(char_list *pList, FILE *pOutput, int iLineLength)
00633 {
00634     int iRetval = 0;
00635     
00636     if(pList == NULL || pOutput == NULL)    {
00637        return(0);
00638     }
00639 
00640     while(pList)    {
00641        if(iLineLength == 0)    {
00642            if(EOF == fputs("    ", pOutput))  {
00643                   fprintf(stderr, "MANTOMAK:  Error writing to file....\n");
00644               iRetval = 1;
00645               break;
00646            }
00647            iLineLength += 4;
00648 
00649            if(0 > fprintf(pOutput, "%s ", pList->m_pString))   {
00650                   fprintf(stderr, "MANTOMAK:  Error writing to file....\n");
00651               iRetval = 1;
00652               break;
00653            }
00654            iLineLength += strlen(pList->m_pString) + 1;
00655        }
00656        else if(iLineLength + strlen(pList->m_pString) > 72)    {
00657            if(EOF == fputs("\\\n", pOutput)) {
00658                   fprintf(stderr, "MANTOMAK:  Error writing to file....\n");
00659               iRetval = 1;
00660               break;
00661            }
00662            iLineLength = 0;
00663            continue;
00664        }
00665        else    {
00666            if(0 > fprintf(pOutput, "%s ", pList->m_pString))   {
00667                   fprintf(stderr, "MANTOMAK:  Error writing to file....\n");
00668               iRetval = 1;
00669               break;
00670            }
00671            iLineLength += strlen(pList->m_pString) + 1;
00672        }
00673 
00674        pList = pList->m_pNext;
00675     }
00676 
00677     return(iRetval);
00678 }
00679 
00680 macro_list *extract_macros(char *pBuffer)
00681 {
00682     macro_list *pRetval = NULL;
00683     char *pTraverse = NULL;
00684     char *pMacro = NULL;
00685 
00686     pTraverse = pBuffer;
00687     while(pTraverse)    {
00688        pMacro = NULL;
00689        pTraverse = find_macro(pTraverse, &pMacro);
00690        if(pMacro)  {
00691            add_macro(pMacro, &pRetval);
00692        }
00693     }
00694 
00695     return(pRetval);
00696 }
00697 
00698 void add_macro(char *pString, macro_list **ppList)
00699 {
00700     macro_list *pEntry = NULL;
00701     int iLength = 0;
00702 
00703     if(pString == NULL || *pString == '\0' || ppList == NULL) {
00704        return;
00705     }
00706 
00707     /*  Allocate a new list entry for the macro.
00708      */
00709     pEntry = (macro_list *)calloc(1, sizeof(macro_list));
00710 
00711     /*  Very first part of the string is the macro name.
00712      *  How long is it?
00713      */
00714     iLength = macro_length(pString);
00715     pEntry->m_pMacro = (char *)calloc(iLength + 1, 1);
00716     strncpy(pEntry->m_pMacro, pString, iLength);
00717 
00718     /*  Skip to the values.
00719      *  These are always on the right side of an '='
00720      */
00721     pString = strchr(pString, '=');
00722     if(pString) {
00723        pString++;
00724     }
00725     add_values(pString, &(pEntry->m_pValue));
00726 
00727     /*  Add the macro to the end of the macro list.
00728      */
00729     while(*ppList)  {
00730        ppList = &((*ppList)->m_pNext);
00731     }
00732     *ppList = pEntry;
00733 }
00734 
00735 void add_values(char *pString, char_list **ppList)
00736 {
00737     char_list **ppTraverse = NULL;
00738     char_list *pEntry = NULL;
00739     int iLength = 0;
00740     int iBackslash = 0;
00741 
00742     if(pString == NULL || *pString == '\0' || ppList == NULL)   {
00743        return;
00744     }
00745 
00746     while(pString)  {
00747        /*  Find start of value.
00748         */
00749        iBackslash = 0;
00750        while(*pString) {
00751            if(*pString == '\\')    {
00752               iBackslash++;
00753            }
00754            else if(*pString == '\n')   {
00755               if(iBackslash == 0)  {
00756                   /*  End of values.
00757                    *  Setting to NULL gets out of all loops.
00758                    */
00759                   pString = NULL;
00760                   break;
00761               }
00762               iBackslash = 0;
00763            }
00764            else if(!isspace(*pString))  {
00765               /*  Backslashes part of string.
00766                *  This screws up if a backslash is in the middle of the string.
00767                */
00768               pString -= iBackslash;
00769               break;
00770            }
00771 
00772            pString++;
00773        }
00774        if(pString == NULL || *pString == '\0') {
00775            break;
00776        }
00777 
00778        /*  Do not honor anything beginning with a #
00779         */
00780        if(*pString == '#') {
00781            /*  End of line.
00782             */
00783            while(*pString && *pString != '\n') {
00784               pString++;
00785            }
00786            continue;
00787        }
00788 
00789        /*  Very first part of the string is value name.
00790         *  How long is it?
00791         */
00792        iLength = value_length(pString);
00793 
00794        /*  Do not honor $(NULL)
00795         */
00796        if(_strnicmp(pString, "$(NULL)", 7) == 0)    {
00797            pString += iLength;
00798            continue;
00799        }
00800 
00801        /*  Allocate a new list entry for the next value.
00802         */
00803        pEntry = (char_list *)calloc(1, sizeof(char_list));
00804 
00805        pEntry->m_pString = (char *)calloc(iLength + 1, 1);
00806        strncpy(pEntry->m_pString, pString, iLength);
00807 
00808        /*  Add new value entry to the end of the list.
00809         */
00810        ppTraverse = ppList;
00811        while(*ppTraverse)  {
00812            ppTraverse = &((*ppTraverse)->m_pNext);
00813        }
00814        *ppTraverse = pEntry;
00815 
00816        /*  Go on to next value.
00817         */
00818        pString += iLength;
00819     }
00820 }
00821 
00822 char *find_macro(char *pBuffer, char **ppMacro)
00823 {
00824     char *pRetval = NULL;
00825     int iBackslash = 0;
00826 
00827     if(pBuffer == NULL || ppMacro == NULL) {
00828        return(NULL);
00829     }
00830 
00831     /*  Skip any whitespace in the buffer.
00832      *  If comments need to be skipped also, this is the place.
00833      */
00834     while(1)    {
00835        while(*pBuffer && isspace(*pBuffer))    {
00836            pBuffer++;
00837        }
00838        if(*pBuffer == '#') {
00839            /*  Go to the end of the line, it's a comment.
00840             */
00841            while(*pBuffer && *pBuffer != '\n') {
00842               pBuffer++;
00843            }
00844 
00845            continue;
00846        }
00847        break;
00848     }
00849 
00850     if(*pBuffer)    {
00851        /*  Should be at the start of a macro.
00852         */
00853        *ppMacro = pBuffer;
00854     }
00855 
00856     /*  Find the end of the macro for the return value.
00857      *  This is the end of a line which does not contain a backslash at the end.
00858      */
00859     while(*pBuffer) {
00860        if(*pBuffer == '\\')    {
00861            iBackslash++;
00862        }
00863        else if(*pBuffer == '\n')   {
00864            if(iBackslash == 0)  {
00865               pRetval = pBuffer + 1;
00866               break;
00867            }
00868            iBackslash = 0;
00869        }
00870        else if(!isspace(*pBuffer))  {
00871            iBackslash = 0;
00872        }
00873 
00874        pBuffer++;
00875     }
00876 
00877     return(pRetval);
00878 }
00879 
00880 int macro_length(char *pMacro)
00881 {
00882     int iRetval = 0;
00883 
00884     if(pMacro == NULL)  {
00885        return(0);
00886     }
00887 
00888     /*  Length is no big deal.
00889      *  Problem is finding the end:
00890      *      whitespace
00891      *      '='
00892      */
00893     while(*pMacro)  {
00894        if(*pMacro == '=')  {
00895            break;
00896        }
00897        else if(isspace(*pMacro))   {
00898            break;
00899        }
00900        
00901        pMacro++;
00902        iRetval++;
00903     }
00904 
00905     return(iRetval);
00906 }
00907 
00908 int value_length(char *pValue)
00909 {
00910     int iRetval = 0;
00911 
00912     if(pValue == NULL)  {
00913        return(0);
00914     }
00915 
00916     /*  Length is no big deal.
00917      *  Problem is finding the end:
00918      *      whitespace
00919      *      '\\'whitespace
00920      */
00921     while(*pValue)  {
00922        if(*pValue == '\\')  {
00923            char *pFindNewline = pValue + 1;
00924            /*  If whitespace to end of line, break here.
00925             */
00926            while(isspace(*pFindNewline))   {
00927               if(*pFindNewline == '\n')   {
00928                   break;
00929               }
00930               pFindNewline++;
00931            }
00932            if(*pFindNewline == '\n')   {
00933               break;
00934            }
00935        }
00936        else if(isspace(*pValue))   {
00937            break;
00938        }
00939        
00940        pValue++;
00941        iRetval++;
00942     }
00943 
00944     return(iRetval);
00945 }
00946 
00947 char *skip_white(char *pString)
00948 {
00949     if(pString == NULL) {
00950        return(NULL);
00951     }
00952 
00953     while(*pString && isspace(*pString)) {
00954        pString++;
00955     }
00956 
00957     return(pString);
00958 }
00959 
00960 void free_macro_list(macro_list *pList)
00961 {
00962     macro_list *pFree = NULL;
00963 
00964     if(pList == NULL)   {
00965        return;
00966     }
00967 
00968     while(pList)    {
00969        pFree = pList;
00970        pList = pList->m_pNext;
00971 
00972        pFree->m_pNext = NULL;
00973 
00974        free_char_list(pFree->m_pValue);
00975        pFree->m_pValue = NULL;
00976 
00977        free(pFree->m_pMacro);
00978        pFree->m_pMacro = NULL;
00979 
00980        free(pFree);
00981        pFree = NULL;
00982     }
00983 }
00984 
00985 void free_char_list(char_list *pList)
00986 {
00987     char_list *pFree = NULL;
00988 
00989     if(pList == NULL)   {
00990        return;
00991     }
00992 
00993     while(pList)    {
00994        pFree = pList;
00995        pList = pList->m_pNext;
00996 
00997        pFree->m_pNext = NULL;
00998 
00999        free(pFree->m_pString);
01000        pFree->m_pString = NULL;
01001 
01002        free(pFree);
01003        pFree = NULL;
01004     }
01005 }