home *** CD-ROM | disk | FTP | other *** search
/ Tools / WinSN5.0Ver.iso / NETSCAP.50 / WIN1998.ZIP / ns / config / mantomak.c < prev    next >
Encoding:
C/C++ Source or Header  |  1998-04-08  |  21.5 KB  |  990 lines

  1. /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
  2.  *
  3.  * The contents of this file are subject to the Netscape Public License
  4.  * Version 1.0 (the "NPL"); you may not use this file except in
  5.  * compliance with the NPL.  You may obtain a copy of the NPL at
  6.  * http://www.mozilla.org/NPL/
  7.  *
  8.  * Software distributed under the NPL is distributed on an "AS IS" basis,
  9.  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
  10.  * for the specific language governing rights and limitations under the
  11.  * NPL.
  12.  *
  13.  * The Initial Developer of this code under the NPL is Netscape
  14.  * Communications Corporation.  Portions created by Netscape are
  15.  * Copyright (C) 1998 Netscape Communications Corporation.  All Rights
  16.  * Reserved.
  17.  */
  18.  
  19. #include <stdio.h>
  20. #include <string.h>
  21. #include <stdlib.h>
  22. #include <ctype.h>
  23.  
  24. #define DEFAULT_MANIFEST_EXT ".mn"
  25. #define DEFAULT_MAKEFILE_EXT ".win"
  26.  
  27. typedef struct char_list_struct {
  28.     char *m_pString;
  29.     struct char_list_struct *m_pNext;
  30. } char_list;
  31.  
  32. typedef struct macro_list_struct   {
  33.     char *m_pMacro;
  34.     char_list *m_pValue;
  35.     struct macro_list_struct *m_pNext;
  36. } macro_list;
  37.  
  38. void help(void);
  39. char *input_filename(const char *);
  40. char *output_filename(const char *, const char *);
  41. int input_to_output(FILE *, FILE *);
  42. int output_rules(FILE *);
  43. int output_end(FILE *);
  44. int buffer_to_output(char *, FILE *);
  45. macro_list *extract_macros(char *);
  46. char *find_macro(char *, char **);
  47. void add_macro(char *, macro_list **);
  48. int macro_length(char *);
  49. int value_length(char *);
  50. void add_values(char *, char_list **);
  51. char *skip_white(char *);
  52. int write_macros(macro_list *, FILE *);
  53. int write_values(char_list *, FILE *, int);
  54. void free_macro_list(macro_list *);
  55. void free_char_list(char_list *);
  56. void morph_macro(macro_list **, char *, char *, char *);
  57. void slash_convert(macro_list *, char *);
  58. int explicit_rules(macro_list *, char *, FILE *);
  59. void create_classroot(macro_list **ppList );
  60.  
  61. int main(int argc, char *argv[])
  62. {
  63.     int iOS = 0;
  64.     char *pInputFile = NULL;
  65.     char *pOutputFile = NULL;
  66.  
  67.     /*      Figure out arguments.
  68.      *      [REQUIRED] First argument is input file.
  69.      *      [OPTIONAL] Second argument is output file.
  70.      */
  71.     if(argc > 1)    {
  72.         FILE *pInputStream = NULL;
  73.         FILE *pOutputStream = NULL;
  74.  
  75.         /*      Form respective filenames.
  76.          */
  77.         pInputFile = input_filename(argv[1]);
  78.         pOutputFile = output_filename(pInputFile, argc > 2 ? argv[2] : NULL);
  79.  
  80.         if(pInputFile == NULL)  {
  81.             fprintf(stderr, "MANTOMAK:  Unable to form input filename\n");
  82.             iOS = 1;
  83.         }
  84.         else    {
  85.             pInputStream = fopen(pInputFile, "rb");
  86.             if(pInputStream == NULL)        {
  87.                 fprintf(stderr, "MANTOMAK:  Unable to open input file %s\n", pInputFile);
  88.                 iOS = 1;
  89.             }
  90.         }
  91.         if(pOutputFile == NULL) {
  92.             fprintf(stderr, "MANTOMAK:  Unable to form output filename\n");
  93.             iOS = 1;
  94.         }
  95.         else if(pInputStream != NULL)   {
  96.             pOutputStream = fopen(pOutputFile, "wt");
  97.             if(pOutputStream == NULL)       {
  98.                 fprintf(stderr, "MANTOMAK:  Unable to open output file %s\n", pOutputFile);
  99.                 iOS = 1;
  100.             }
  101.         }
  102.  
  103.         /*      Only do the real processing if our error code is not
  104.          *              already set.
  105.          */
  106.         if(iOS == 0)    {
  107.             iOS = input_to_output(pInputStream, pOutputStream);
  108.         }
  109.  
  110.         if(pInputStream != NULL)        {
  111.             fclose(pInputStream);
  112.             pInputStream = NULL;
  113.         }
  114.         if(pOutputStream != NULL)       {
  115.             fclose(pOutputStream);
  116.             pOutputStream = NULL;
  117.         }
  118.     }
  119.     else    {
  120.         help();
  121.         iOS = 1;
  122.     }
  123.  
  124.     if(pInputFile)  {
  125.         free(pInputFile);
  126.         pInputFile = NULL;
  127.     }
  128.     if(pOutputFile) {
  129.         free(pOutputFile);
  130.         pOutputFile = NULL;
  131.     }
  132.  
  133.     return(iOS);
  134. }
  135.  
  136. void help(void)
  137. {
  138.     fprintf(stderr, "USAGE:\tmantomak.exe InputFile [OutputFile]\n\n");
  139.     fprintf(stderr, "InputFile:\tManifest file.  If without extension, \"%s\" assumed.\n", DEFAULT_MANIFEST_EXT);
  140.     fprintf(stderr, "OutputFile:\tNMake file.  If not present, \"InputFile%s\" assumed.\n", DEFAULT_MAKEFILE_EXT);
  141. }
  142.  
  143. char *input_filename(const char *pInputFile)
  144. {
  145.     char aResult[_MAX_PATH];
  146.     char aDrive[_MAX_DRIVE];
  147.     char aDir[_MAX_DIR];
  148.     char aName[_MAX_FNAME];
  149.     char aExt[_MAX_EXT];
  150.  
  151.     if(pInputFile == NULL)  {
  152.         return(NULL);
  153.     }
  154.  
  155.     _splitpath(pInputFile, aDrive, aDir, aName, aExt);
  156.  
  157.     if(aExt[0] == '\0')     {
  158.         /*      No extension provided.
  159.          *      Use the default.
  160.          */
  161.         strcpy(aExt, DEFAULT_MANIFEST_EXT);
  162.     }
  163.  
  164.     aResult[0] = '\0';
  165.     _makepath(aResult, aDrive, aDir, aName, aExt);
  166.  
  167.     if(aResult[0] == '\0')  {
  168.         return(NULL);
  169.     }
  170.     else    {
  171.         return(strdup(aResult));
  172.     }
  173. }
  174.  
  175. char *output_filename(const char *pInputFile, const char *pOutputFile)
  176. {
  177.     char aResult[_MAX_PATH];
  178.     char aDrive[_MAX_DRIVE];
  179.     char aDir[_MAX_DIR];
  180.     char aName[_MAX_FNAME];
  181.     char aExt[_MAX_EXT];
  182.  
  183.     if(pOutputFile != NULL) {
  184.         return(strdup(pOutputFile));
  185.     }
  186.  
  187.     /*      From here on out, we have to create our own filename,
  188.      *              implied from the input file name.
  189.      */
  190.  
  191.     if(pInputFile == NULL)  {
  192.         return(NULL);
  193.     }
  194.  
  195.     _splitpath(pInputFile, aDrive, aDir, aName, aExt);
  196.     strcpy(aExt, DEFAULT_MAKEFILE_EXT);
  197.  
  198.     aResult[0] = '\0';
  199.     _makepath(aResult, aDrive, aDir, aName, aExt);
  200.  
  201.     if(aResult[0] == '\0')  {
  202.         return(NULL);
  203.     }
  204.     else    {
  205.         return(strdup(aResult));
  206.     }
  207. }
  208.  
  209. int input_to_output(FILE *pInput, FILE *pOutput)
  210. {
  211.     char *pHog = NULL;
  212.     long lSize = 0;
  213.     int iRetval = 0;
  214.  
  215.     /*      Read the entire file into memory.
  216.      */
  217.     fseek(pInput, 0, SEEK_END);
  218.     lSize = ftell(pInput);
  219.     fseek(pInput, 0, SEEK_SET);
  220.  
  221.     pHog = (char *)malloc(lSize + 1);
  222.     if(pHog)        {
  223.         *(pHog + lSize) = '\0';
  224.         fread(pHog, lSize, 1, pInput);
  225.  
  226.         iRetval = buffer_to_output(pHog, pOutput);
  227.  
  228.         free(pHog);
  229.         pHog = NULL;
  230.     }
  231.     else    {
  232.         fprintf(stderr, "MANTOMAK:  Out of Memory....\n");
  233.         iRetval = 1;
  234.     }
  235.  
  236.     return(iRetval);
  237. }
  238.  
  239. int output_rules(FILE *pOutput)
  240. {
  241.     int iRetval = 0;
  242.  
  243.     if(EOF ==
  244.     fputs("\n"
  245.           "!if \"$(MANIFEST_LEVEL)\"==\"RULES\""
  246.           "\n",
  247.         pOutput))
  248.     {
  249.         fprintf(stderr, "MANTOMAK:  Error writing to file....\n");
  250.         iRetval = 1;
  251.     }
  252.     return(iRetval);
  253. }
  254.  
  255. int output_end(FILE *pOutput)
  256. {
  257.     int iRetval = 0;
  258.  
  259.     if(EOF ==
  260.     fputs("\n"
  261.           "!endif"
  262.           "\n",
  263.         pOutput))
  264.     {
  265.         fprintf(stderr, "MANTOMAK:  Error writing to file....\n");
  266.         iRetval = 1;
  267.     }
  268.     return(iRetval);
  269. }
  270.  
  271.  
  272. int buffer_to_output(char *pBuffer, FILE *pOutput)
  273. {
  274.     int iRetval = 0;
  275.     macro_list *pMacros = NULL;
  276.  
  277.     /*  Tokenize the macros and their corresponding values.
  278.      */
  279.     pMacros = extract_macros(pBuffer);
  280.     if(pMacros != NULL) {
  281.     /*  Perform forward to backslash conversion on those macros known to be
  282.      *      path information only.
  283.      */
  284.     slash_convert(pMacros, "JBOOTDIRS");
  285.     slash_convert(pMacros, "JDIRS");
  286.     slash_convert(pMacros, "DEPTH");
  287.     slash_convert(pMacros, "PACKAGE");
  288.     slash_convert(pMacros, "JMC_GEN_DIR");
  289.     slash_convert(pMacros, "DIST_PUBLIC");
  290.  
  291.     /*  Process some of the macros, and convert them
  292.      *      into different macros with different data.
  293.      */
  294.     morph_macro(&pMacros, "JMC_GEN", "JMC_HEADERS", "$(JMC_GEN_DIR)\\%s.h");
  295.     morph_macro(&pMacros, "JMC_GEN", "JMC_STUBS", "$(JMC_GEN_DIR)\\%s.c");
  296.     morph_macro(&pMacros, "JMC_GEN", "JMC_OBJS", ".\\$(OBJDIR)\\%s.obj");
  297.     morph_macro(&pMacros, "CSRCS", "C_OBJS", ".\\$(OBJDIR)\\%s.obj");
  298.     morph_macro(&pMacros, "CPPSRCS", "CPP_OBJS", ".\\$(OBJDIR)\\%s.obj");
  299.     morph_macro(&pMacros, "REQUIRES", "LINCS", "-I$(XPDIST)\\public\\%s");
  300.  
  301.     create_classroot( &pMacros );
  302.  
  303.     /*  Output the Macros and the corresponding values.
  304.      */
  305.     iRetval = write_macros(pMacros, pOutput);
  306.  
  307.     /*  Output rule file inclusion
  308.      */
  309.     if(iRetval == 0)    {
  310.         iRetval = output_rules(pOutput);
  311.     }
  312.  
  313.     /*  Output explicit build rules/dependencies for JMC_GEN.
  314.      */
  315.     if(iRetval == 0)    {
  316.         iRetval = explicit_rules(pMacros, "JMC_GEN", pOutput);
  317.     }
  318.  
  319.     if(iRetval == 0)    {
  320.         iRetval = output_end(pOutput);
  321.     }
  322.     /*  Free off the macro list.
  323.      */
  324.     free_macro_list(pMacros);
  325.     pMacros = NULL;
  326.     }
  327.  
  328.     return(iRetval);
  329. }
  330.  
  331. int explicit_rules(macro_list *pList, char *pMacro, FILE *pOutput)
  332. {
  333.     int iRetval = 0;
  334.     macro_list *pEntry = NULL;
  335.  
  336.     if(pList == NULL || pMacro == NULL || pOutput == NULL) {
  337.     return(0);
  338.     }
  339.  
  340.     /*  Find macro of said name.
  341.      *  Case insensitive.
  342.      */
  343.     pEntry = pList;
  344.     while(pEntry)    {
  345.     if(stricmp(pEntry->m_pMacro, pMacro) == 0)  {
  346.         break;
  347.     }
  348.  
  349.     pEntry = pEntry->m_pNext;
  350.     }
  351.  
  352.     if(pEntry)  {
  353.     /*  Decide style of rule depending on macro name.
  354.      */
  355.     if(stricmp(pEntry->m_pMacro, "JMC_GEN") == 0)    {
  356.         char_list *pNames = NULL;
  357.         char *pModuleName = NULL;
  358.         char *pClassName = NULL;
  359.  
  360.         pNames = pEntry->m_pValue;
  361.         while(pNames)   {
  362.         pModuleName = pNames->m_pString;
  363.         pClassName = pModuleName + 1;
  364.  
  365.         fprintf(pOutput, "$(JMC_GEN_DIR)\\%s.h", pModuleName);
  366.         fprintf(pOutput, ": ");
  367.         fprintf(pOutput, "$(JMCSRCDIR)\\%s.class", pClassName);
  368.         fprintf(pOutput, "\n    ");
  369.         fprintf(pOutput, "$(JMC) -d $(JMC_GEN_DIR) -interface $(JMC_GEN_FLAGS) $(?F:.class=)");
  370.         fprintf(pOutput, "\n");
  371.  
  372.         fprintf(pOutput, "$(JMC_GEN_DIR)\\%s.c", pModuleName);
  373.         fprintf(pOutput, ": ");
  374.         fprintf(pOutput, "$(JMCSRCDIR)\\%s.class", pClassName);
  375.         fprintf(pOutput, "\n    ");
  376.         fprintf(pOutput, "$(JMC) -d $(JMC_GEN_DIR) -module $(JMC_GEN_FLAGS) $(?F:.class=)");
  377.         fprintf(pOutput, "\n");
  378.  
  379.         pNames = pNames->m_pNext;
  380.         }
  381.     }
  382.     else    {
  383.         /*  Don't know how to format macro.
  384.          */
  385.         iRetval = 69;
  386.     }
  387.     }
  388.  
  389.     return(iRetval);
  390. }
  391.  
  392. void slash_convert(macro_list *pList, char *pMacro)
  393. {
  394.     macro_list *pEntry = NULL;
  395.  
  396.     if(pList == NULL || pMacro == NULL) {
  397.     return;
  398.     }
  399.  
  400.     /*  Find macro of said name.
  401.      *  Case insensitive.
  402.      */
  403.     pEntry = pList;
  404.     while(pEntry)    {
  405.     if(stricmp(pEntry->m_pMacro, pMacro) == 0)  {
  406.         break;
  407.     }
  408.  
  409.     pEntry = pEntry->m_pNext;
  410.     }
  411.  
  412.     if(pEntry)  {
  413.     char *pConvert = NULL;
  414.     char_list *pValue = pEntry->m_pValue;
  415.  
  416.     while(pValue)   {
  417.         pConvert = pValue->m_pString;
  418.         while(pConvert && *pConvert)    {
  419.         if(*pConvert == '/')    {
  420.             *pConvert = '\\';
  421.         }
  422.         pConvert++;
  423.         }
  424.         pValue = pValue->m_pNext;
  425.     }
  426.     }
  427. }
  428.  
  429. void morph_macro(macro_list **ppList, char *pMacro, char *pMorph, char *pPrintf)
  430. {
  431.     macro_list *pEntry = NULL;
  432.  
  433.     if(ppList == NULL || pMacro == NULL || pMorph == NULL || pPrintf == NULL) {
  434.     return;
  435.     }
  436.  
  437.     /*  Find macro of said name.
  438.      *  Case insensitive.
  439.      */
  440.     pEntry = *ppList;
  441.     while(pEntry)    {
  442.     if(stricmp(pEntry->m_pMacro, pMacro) == 0)  {
  443.         break;
  444.     }
  445.  
  446.     pEntry = pEntry->m_pNext;
  447.     }
  448.  
  449.     if(pEntry)  {
  450.     char_list *pFilename = NULL;
  451.     char aPath[_MAX_PATH];
  452.     char aDrive[_MAX_DRIVE];
  453.     char aDir[_MAX_DIR];
  454.     char aFName[_MAX_FNAME];
  455.     char aExt[_MAX_EXT];
  456.     char *pBuffer = NULL;
  457.  
  458.     /*  Start with buffer size needed.
  459.      *  We expand this as we go along if needed.
  460.      */
  461.     pBuffer = (char *)malloc(strlen(pMorph) + 2);
  462.     strcpy(pBuffer, pMorph);
  463.     strcat(pBuffer, "=");
  464.  
  465.     /*  Go through each value, converting over to new macro.
  466.      */
  467.     pFilename = pEntry->m_pValue;
  468.     while(pFilename) {
  469.         _splitpath(pFilename->m_pString, aDrive, aDir, aFName, aExt);
  470.  
  471.         /*  Expand buffer by required amount.
  472.          */
  473.         sprintf(aPath, pPrintf, aFName);
  474.         strcat(aPath, " ");
  475.         pBuffer = (char *)realloc(pBuffer, _msize(pBuffer) + strlen(aPath));
  476.         strcat(pBuffer, aPath);
  477.  
  478.         pFilename = pFilename->m_pNext;
  479.     }
  480.  
  481.     /*  Add the macro.
  482.      */
  483.     add_macro(pBuffer, ppList);
  484.  
  485.     free(pBuffer);
  486.     pBuffer = NULL;
  487.     }
  488. }
  489.  
  490. void create_classroot(macro_list **ppList )
  491. {
  492.     char cwd[512];
  493.     int i, i2;
  494.     macro_list *pEntry = NULL;
  495.     macro_list *pE;
  496.  
  497.     /*  Find macro of said name.
  498.      *  Case insensitive.
  499.      */
  500.     pEntry = *ppList;
  501.     while(pEntry)    {
  502.     if(stricmp(pEntry->m_pMacro, "PACKAGE") == 0)  {
  503.         break;
  504.     }
  505.  
  506.     pEntry = pEntry->m_pNext;
  507.     }
  508.  
  509.     if(pEntry == 0 || pEntry->m_pValue == 0 || pEntry->m_pValue->m_pString == 0)  {
  510.     return;
  511.     }
  512.  
  513.     _getcwd( cwd, 512 );
  514.  
  515.     i = strlen( pEntry->m_pValue->m_pString );
  516.     i2 = strlen( cwd );
  517.  
  518.     cwd[i2-i-1] = 0;
  519.  
  520.     pE = NULL;
  521.     pE = (macro_list *)calloc(sizeof(macro_list),1);
  522.     pE->m_pMacro = strdup("CLASSROOT");
  523.     pE->m_pValue = (char_list *)calloc(sizeof(char_list),1);
  524.     pE->m_pValue->m_pString = strdup(cwd);
  525.  
  526.     while(*ppList)  {
  527.     ppList = &((*ppList)->m_pNext);
  528.     }
  529.     *ppList = pE;
  530. }
  531.  
  532.  
  533. int write_macros(macro_list *pList, FILE *pOutput)
  534. {
  535.     int iRetval = 0;
  536.     int iLineLength = 0;
  537.  
  538.     if(pList == NULL || pOutput == NULL)    {
  539.     return(0);
  540.     }
  541.  
  542.     if(EOF ==
  543.     fputs("\n"
  544.           "!if \"$(MANIFEST_LEVEL)\"==\"MACROS\""
  545.           "\n",
  546.         pOutput))
  547.     {
  548.         fprintf(stderr, "MANTOMAK:  Error writing to file....\n");
  549.         return(1);
  550.     }
  551.  
  552.     while(pList)    {
  553.         int bIgnoreForWin16 = 0;
  554.  
  555.         /* The following macros should not be emitted for Win16 */
  556.         if (0 == strcmp(pList->m_pMacro, "LINCS")) {
  557.             bIgnoreForWin16 = 1;
  558.         }
  559.  
  560.  
  561.         if (bIgnoreForWin16) {
  562.             if(0 > fprintf(pOutput, "!if \"$(MOZ_BITS)\" != \"16\"\n"))  {
  563.                 fprintf(stderr, "MANTOMAK:  Error writing to file....\n");
  564.                 iRetval = 1;
  565.                 break;
  566.             }
  567.         }
  568.  
  569.     if(0 > fprintf(pOutput, "%s=", pList->m_pMacro))  {
  570.         fprintf(stderr, "MANTOMAK:  Error writing to file....\n");
  571.         iRetval = 1;
  572.         break;
  573.     }
  574.     iLineLength += strlen(pList->m_pMacro) + 1;
  575.  
  576.     iRetval = write_values(pList->m_pValue, pOutput, iLineLength);
  577.     if(iRetval) {
  578.         break;
  579.     }
  580.  
  581.     if(EOF == fputc('\n', pOutput))    {
  582.         fprintf(stderr, "MANTOMAK:  Error writing to file....\n");
  583.         iRetval = 1;
  584.         break;
  585.     }
  586.     iLineLength = 0;
  587.  
  588.     pList = pList->m_pNext;
  589.  
  590.         if (bIgnoreForWin16) {
  591.             if(0 > fprintf(pOutput, "!endif\n"))  {
  592.                 fprintf(stderr, "MANTOMAK:  Error writing to file....\n");
  593.                 iRetval = 1;
  594.                 break;
  595.             }
  596.             bIgnoreForWin16 = 0;
  597.         }
  598.     }
  599.  
  600.     if(EOF ==
  601.     fputs("\n"
  602.           "!endif"
  603.           "\n",
  604.         pOutput))
  605.     {
  606.         fprintf(stderr, "MANTOMAK:  Error writing to file....\n");
  607.         return(1);
  608.     }
  609.     return(iRetval);
  610. }
  611.  
  612. int write_values(char_list *pList, FILE *pOutput, int iLineLength)
  613. {
  614.     int iRetval = 0;
  615.     
  616.     if(pList == NULL || pOutput == NULL)    {
  617.     return(0);
  618.     }
  619.  
  620.     while(pList)    {
  621.     if(iLineLength == 0)    {
  622.         if(EOF == fputs("    ", pOutput))  {
  623.             fprintf(stderr, "MANTOMAK:  Error writing to file....\n");
  624.         iRetval = 1;
  625.         break;
  626.         }
  627.         iLineLength += 4;
  628.  
  629.         if(0 > fprintf(pOutput, "%s ", pList->m_pString))   {
  630.             fprintf(stderr, "MANTOMAK:  Error writing to file....\n");
  631.         iRetval = 1;
  632.         break;
  633.         }
  634.         iLineLength += strlen(pList->m_pString) + 1;
  635.     }
  636.     else if(iLineLength + strlen(pList->m_pString) > 72)    {
  637.         if(EOF == fputs("\\\n", pOutput)) {
  638.             fprintf(stderr, "MANTOMAK:  Error writing to file....\n");
  639.         iRetval = 1;
  640.         break;
  641.         }
  642.         iLineLength = 0;
  643.         continue;
  644.     }
  645.     else    {
  646.         if(0 > fprintf(pOutput, "%s ", pList->m_pString))   {
  647.             fprintf(stderr, "MANTOMAK:  Error writing to file....\n");
  648.         iRetval = 1;
  649.         break;
  650.         }
  651.         iLineLength += strlen(pList->m_pString) + 1;
  652.     }
  653.  
  654.     pList = pList->m_pNext;
  655.     }
  656.  
  657.     return(iRetval);
  658. }
  659.  
  660. macro_list *extract_macros(char *pBuffer)
  661. {
  662.     macro_list *pRetval = NULL;
  663.     char *pTraverse = NULL;
  664.     char *pMacro = NULL;
  665.  
  666.     pTraverse = pBuffer;
  667.     while(pTraverse)    {
  668.     pMacro = NULL;
  669.     pTraverse = find_macro(pTraverse, &pMacro);
  670.     if(pMacro)  {
  671.         add_macro(pMacro, &pRetval);
  672.     }
  673.     }
  674.  
  675.     return(pRetval);
  676. }
  677.  
  678. void add_macro(char *pString, macro_list **ppList)
  679. {
  680.     macro_list *pEntry = NULL;
  681.     int iLength = 0;
  682.  
  683.     if(pString == NULL || *pString == '\0' || ppList == NULL) {
  684.     return;
  685.     }
  686.  
  687.     /*  Allocate a new list entry for the macro.
  688.      */
  689.     pEntry = (macro_list *)malloc(sizeof(macro_list));
  690.     memset(pEntry, 0, sizeof(macro_list));
  691.  
  692.     /*  Very first part of the string is the macro name.
  693.      *  How long is it?
  694.      */
  695.     iLength = macro_length(pString);
  696.     pEntry->m_pMacro = (char *)malloc(iLength + 1);
  697.     memset(pEntry->m_pMacro, 0, iLength + 1);
  698.     strncpy(pEntry->m_pMacro, pString, iLength);
  699.  
  700.     /*  Skip to the values.
  701.      *  These are always on the right side of an '='
  702.      */
  703.     pString = strchr(pString, '=');
  704.     if(pString) {
  705.     pString++;
  706.     }
  707.     add_values(pString, &(pEntry->m_pValue));
  708.  
  709.     /*  Add the macro to the end of the macro list.
  710.      */
  711.     while(*ppList)  {
  712.     ppList = &((*ppList)->m_pNext);
  713.     }
  714.     *ppList = pEntry;
  715. }
  716.  
  717. void add_values(char *pString, char_list **ppList)
  718. {
  719.     char_list **ppTraverse = NULL;
  720.     char_list *pEntry = NULL;
  721.     int iLength = 0;
  722.     int iBackslash = 0;
  723.  
  724.     if(pString == NULL || *pString == '\0' || ppList == NULL)   {
  725.     return;
  726.     }
  727.  
  728.     while(pString)  {
  729.     /*  Find start of value.
  730.      */
  731.     iBackslash = 0;
  732.     while(*pString) {
  733.         if(*pString == '\\')    {
  734.         iBackslash++;
  735.         }
  736.         else if(*pString == '\n')   {
  737.         if(iBackslash == 0)  {
  738.             /*  End of values.
  739.              *  Setting to NULL gets out of all loops.
  740.              */
  741.             pString = NULL;
  742.             break;
  743.         }
  744.         iBackslash = 0;
  745.         }
  746.         else if(!isspace(*pString))  {
  747.         /*  Backslashes part of string.
  748.          *  This screws up if a backslash is in the middle of the string.
  749.          */
  750.         pString -= iBackslash;
  751.         break;
  752.         }
  753.  
  754.         pString++;
  755.     }
  756.     if(pString == NULL || *pString == '\0') {
  757.         break;
  758.     }
  759.  
  760.     /*  Do not honor anything beginning with a #
  761.      */
  762.     if(*pString == '#') {
  763.         /*  End of line.
  764.          */
  765.         while(*pString && *pString != '\n') {
  766.         pString++;
  767.         }
  768.         continue;
  769.     }
  770.  
  771.     /*  Very first part of the string is value name.
  772.      *  How long is it?
  773.      */
  774.     iLength = value_length(pString);
  775.  
  776.     /*  Do not honor $(NULL)
  777.      */
  778.     if(_strnicmp(pString, "$(NULL)", 7) == 0)    {
  779.         pString += iLength;
  780.         continue;
  781.     }
  782.  
  783.     /*  Allocate a new list entry for the next value.
  784.      */
  785.     pEntry = (char_list *)malloc(sizeof(char_list));
  786.     memset(pEntry, 0, sizeof(char_list));
  787.  
  788.     pEntry->m_pString = (char *)malloc(iLength + 1);
  789.     memset(pEntry->m_pString, 0, iLength + 1);
  790.     strncpy(pEntry->m_pString, pString, iLength);
  791.  
  792.     /*  Add new value entry to the end of the list.
  793.      */
  794.     ppTraverse = ppList;
  795.     while(*ppTraverse)  {
  796.         ppTraverse = &((*ppTraverse)->m_pNext);
  797.     }
  798.     *ppTraverse = pEntry;
  799.  
  800.     /*  Go on to next value.
  801.      */
  802.     pString += iLength;
  803.     }
  804. }
  805.  
  806. char *find_macro(char *pBuffer, char **ppMacro)
  807. {
  808.     char *pRetval = NULL;
  809.     int iBackslash = 0;
  810.  
  811.     if(pBuffer == NULL || ppMacro == NULL) {
  812.     return(NULL);
  813.     }
  814.  
  815.     /*  Skip any whitespace in the buffer.
  816.      *  If comments need to be skipped also, this is the place.
  817.      */
  818.     while(1)    {
  819.     while(*pBuffer && isspace(*pBuffer))    {
  820.         pBuffer++;
  821.     }
  822.     if(*pBuffer == '#') {
  823.         /*  Go to the end of the line, it's a comment.
  824.          */
  825.         while(*pBuffer && *pBuffer != '\n') {
  826.         pBuffer++;
  827.         }
  828.  
  829.         continue;
  830.     }
  831.     break;
  832.     }
  833.  
  834.     if(*pBuffer)    {
  835.     /*  Should be at the start of a macro.
  836.      */
  837.     *ppMacro = pBuffer;
  838.     }
  839.  
  840.     /*  Find the end of the macro for the return value.
  841.      *  This is the end of a line which does not contain a backslash at the end.
  842.      */
  843.     while(*pBuffer) {
  844.     if(*pBuffer == '\\')    {
  845.         iBackslash++;
  846.     }
  847.     else if(*pBuffer == '\n')   {
  848.         if(iBackslash == 0)  {
  849.         pRetval = pBuffer + 1;
  850.         break;
  851.         }
  852.         iBackslash = 0;
  853.     }
  854.     else if(!isspace(*pBuffer))  {
  855.         iBackslash = 0;
  856.     }
  857.  
  858.     pBuffer++;
  859.     }
  860.  
  861.     return(pRetval);
  862. }
  863.  
  864. int macro_length(char *pMacro)
  865. {
  866.     int iRetval = 0;
  867.  
  868.     if(pMacro == NULL)  {
  869.     return(0);
  870.     }
  871.  
  872.     /*  Length is no big deal.
  873.      *  Problem is finding the end:
  874.      *      whitespace
  875.      *      '='
  876.      */
  877.     while(*pMacro)  {
  878.     if(*pMacro == '=')  {
  879.         break;
  880.     }
  881.     else if(isspace(*pMacro))   {
  882.         break;
  883.     }
  884.     
  885.     pMacro++;
  886.     iRetval++;
  887.     }
  888.  
  889.     return(iRetval);
  890. }
  891.  
  892. int value_length(char *pValue)
  893. {
  894.     int iRetval = 0;
  895.  
  896.     if(pValue == NULL)  {
  897.     return(0);
  898.     }
  899.  
  900.     /*  Length is no big deal.
  901.      *  Problem is finding the end:
  902.      *      whitespace
  903.      *      '\\'whitespace
  904.      */
  905.     while(*pValue)  {
  906.     if(*pValue == '\\')  {
  907.         char *pFindNewline = pValue + 1;
  908.         /*  If whitespace to end of line, break here.
  909.          */
  910.         while(isspace(*pFindNewline))   {
  911.         if(*pFindNewline == '\n')   {
  912.             break;
  913.         }
  914.         pFindNewline++;
  915.         }
  916.         if(*pFindNewline == '\n')   {
  917.         break;
  918.         }
  919.     }
  920.     else if(isspace(*pValue))   {
  921.         break;
  922.     }
  923.     
  924.     pValue++;
  925.     iRetval++;
  926.     }
  927.  
  928.     return(iRetval);
  929. }
  930.  
  931. char *skip_white(char *pString)
  932. {
  933.     if(pString == NULL) {
  934.     return(NULL);
  935.     }
  936.  
  937.     while(*pString && isspace(*pString)) {
  938.     pString++;
  939.     }
  940.  
  941.     return(pString);
  942. }
  943.  
  944. void free_macro_list(macro_list *pList)
  945. {
  946.     macro_list *pFree = NULL;
  947.  
  948.     if(pList == NULL)   {
  949.     return;
  950.     }
  951.  
  952.     while(pList)    {
  953.     pFree = pList;
  954.     pList = pList->m_pNext;
  955.  
  956.     pFree->m_pNext = NULL;
  957.  
  958.     free_char_list(pFree->m_pValue);
  959.     pFree->m_pValue = NULL;
  960.  
  961.     free(pFree->m_pMacro);
  962.     pFree->m_pMacro = NULL;
  963.  
  964.     free(pFree);
  965.     pFree = NULL;
  966.     }
  967. }
  968.  
  969. void free_char_list(char_list *pList)
  970. {
  971.     char_list *pFree = NULL;
  972.  
  973.     if(pList == NULL)   {
  974.     return;
  975.     }
  976.  
  977.     while(pList)    {
  978.     pFree = pList;
  979.     pList = pList->m_pNext;
  980.  
  981.     pFree->m_pNext = NULL;
  982.  
  983.     free(pFree->m_pString);
  984.     pFree->m_pString = NULL;
  985.  
  986.     free(pFree);
  987.     pFree = NULL;
  988.     }
  989. }
  990.