home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Windows Gam…ming Gurus (2nd Edition) / Disc2.iso / msdn_vcb / samples / vc98 / sdk / sdktools / winnt / dlgedit / rwinc.c < prev    next >
C/C++ Source or Header  |  1997-10-05  |  36KB  |  1,318 lines

  1.  
  2. /******************************************************************************\
  3. *       This is a part of the Microsoft Source Code Samples. 
  4. *       Copyright (C) 1993-1997 Microsoft Corporation.
  5. *       All rights reserved. 
  6. *       This source code is only intended as a supplement to 
  7. *       Microsoft Development Tools and/or WinHelp documentation.
  8. *       See these sources for detailed information regarding the 
  9. *       Microsoft samples programs.
  10. \******************************************************************************/
  11.  
  12. /****************************** Module Header *******************************
  13. * Module Name: rwinc.c
  14. *
  15. * Does the include file reading and writing.
  16. *
  17. * Functions:
  18. *
  19. *    OpenIncludeFile()
  20. *    FreeInclude()
  21. *    WriteInc()
  22. *    LoadIncludeFile()
  23. *    GetChar()
  24. *    ReadChar()
  25. *    GetLabel()
  26. *    GetValue()
  27. *    GetWord()
  28. *    FindDefine()
  29. *    GetNextInc()
  30. *    RWToOffset()
  31. *    WriteIncChar()
  32. *    WriteIncFlush()
  33. *    WriteChangedInc()
  34. *    WriteDeletedInc()
  35. *    WriteAddedInc()
  36. *    WriteSymbol()
  37. *    WriteIDInc()
  38. *
  39. * Comments:
  40. *
  41. ****************************************************************************/
  42.  
  43. #include "dlgedit.h"
  44. #include "dlgfuncs.h"
  45. #include "dlgextrn.h"
  46.  
  47. #include <ctype.h>
  48.  
  49.  
  50. /*
  51.  * Field width that the symbol is printed within.  This indirectly
  52.  * determines where the id value starts, because blanks are added
  53.  * after the symbol is printed up to this width value.
  54.  */
  55. #define CCHSYMFIELDWIDTH    27
  56.  
  57. /*
  58.  * Return codes from the file reading functions.
  59.  */
  60. #define READ_OK             1
  61. #define READ_EOF            2
  62. #define READ_BAD            3
  63. #define READ_WRONG          4
  64. #define BAD_POINTER         ((VOID *)0xFFFF)
  65.  
  66. /*
  67.  * Return codes from the GetNextInc function.
  68.  */
  69. #define GNI_DONE            0
  70. #define GNI_NOCHANGE        1
  71. #define GNI_CHANGED         2
  72. #define GNI_DELETED         3
  73. #define GNI_ADDED           4
  74.  
  75. static BYTE abBuffer[CCHFILEBUFFER];    /* Buffer for read file data.       */
  76. static TCHAR achBuffer[CCHFILEBUFFER];  /* Unicode buffer for data.         */
  77. static INT cbBuf;                       /* Pointer into achBuffer.          */
  78. static DWORD cchFile;                   /* Count of characters read.        */
  79. static DWORD cchFileMax;                /* Max characters in file.          */
  80. static DWORD fposLastDefine;            /* Saves location of "#define".     */
  81. static DWORD fposWordStart;             /* Saves start of id value.         */
  82. static BOOL fAtNewLine;                 /* At start or \r or \n.            */
  83. static HANDLE hfInclude;                /* The current include file.        */
  84.  
  85. STATICFN BOOL LoadIncludeFile(VOID);
  86. STATICFN LPTSTR GetChar(VOID);
  87. STATICFN LPTSTR ReadChar(VOID);
  88. STATICFN INT GetLabel(BOOL *pfDups);
  89. STATICFN INT GetValue(PINT pnValue);
  90. STATICFN INT GetWord(LPTSTR pch);
  91. STATICFN INT FindDefine(VOID);
  92. STATICFN INT GetNextInc(NPLABEL *pplReturn, BOOL fFirst);
  93. STATICFN BOOL RWToOffset(HANDLE hfWrite, DWORD lOffset);
  94. STATICFN BOOL WriteIncChar(HANDLE hfWrite, TCHAR ch);
  95. STATICFN BOOL WriteIncFlush(HANDLE hfWrite);
  96. STATICFN BOOL WriteChangedInc(HANDLE hfWrite, NPLABEL plInc);
  97. STATICFN BOOL WriteDeletedInc(HANDLE hfWrite, NPLABEL plInc);
  98. STATICFN BOOL WriteAddedInc(HANDLE hfWrite, NPLABEL plInc);
  99. STATICFN BOOL WriteSymbol(HANDLE hfWrite, LPTSTR pszSymbol);
  100. STATICFN BOOL WriteIDInc(HANDLE hfWrite, INT id);
  101.  
  102.  
  103.  
  104. /****************************************************************************
  105. * OpenIncludeFile
  106. *
  107. * This function attempts to open and load the include file with name
  108. * pointed to by pszOpenInclude.  If pszOpenInclude is just a file name, and
  109. * not a path, then the path is taken from szFullLoadFile.  Otherwise
  110. * pszOpenInclude itself is used.  The full pathname is put in
  111. * szFullIncludeFile and pszIncludeFile is set to point to just the file
  112. * name in it.  
  113. *
  114. * If fDoOpen is TRUE, the file is opened.  If it is FALSE, it is assumed
  115. * that hfInc contains the file handle to the opened include file and this
  116. * handle is used.  In addition, the caller is responsible for closing
  117. * any passed in file handle if an error occurs.
  118. *
  119. * Any existing includes are freed,  szFullIncludeFile is set to the full 
  120. * include path, pszIncludeFile is set to the filename portion of this full 
  121. * path and hfInclude will contain the file handle to the include file.
  122. *
  123. * Arguments:
  124. *   LPTSTR pszOpenInclude - name of the include file to open.
  125. *
  126. * Returns:
  127. *   If the load is successful, TRUE is returned.  Otherwise,
  128. *   FALSE is returned.
  129. *
  130. ****************************************************************************/
  131.  
  132. BOOL OpenIncludeFile(
  133.     LPTSTR pszOpenInclude)
  134. {
  135.     TCHAR szFullIncludeFileTemp[CCHMAXPATH];
  136.     HCURSOR hcurSave;
  137.     BOOL fSuccess = FALSE;
  138.  
  139.     hcurSave = SetCursor(hcurWait);
  140.  
  141.     if (FileInPath(pszOpenInclude) == pszOpenInclude) {
  142.         lstrcpy(szFullIncludeFileTemp, szFullResFile);
  143.         lstrcpy(FileInPath(szFullIncludeFileTemp), pszOpenInclude);
  144.     }
  145.     else {
  146.         lstrcpy(szFullIncludeFileTemp, pszOpenInclude);
  147.     }
  148.  
  149.     /*
  150.      * Close any existing include file and free memory.
  151.      */
  152.     FreeInclude();
  153.  
  154.     if ((hfInclude = CreateFile(szFullIncludeFileTemp, GENERIC_READ,
  155.             FILE_SHARE_READ, NULL, OPEN_EXISTING,
  156.             FILE_FLAG_SEQUENTIAL_SCAN, NULL)) != (HANDLE)-1) {
  157.         if (LoadIncludeFile()) {
  158.             lstrcpy(szFullIncludeFile, szFullIncludeFileTemp);
  159.             pszIncludeFile = FileInPath(szFullIncludeFile);
  160.             fSuccess = TRUE;
  161.         }
  162.  
  163.         CloseHandle(hfInclude);
  164.     }
  165.  
  166.     /*
  167.      * Update the status windows symbol combo box.  Update other fields
  168.      * also, in case the currently selected control's symbol was affected
  169.      * by the reading of the new include file.
  170.      */
  171.     StatusFillSymbolList(plInclude);
  172.     StatusUpdate();
  173.  
  174.     ShowFileStatus(TRUE);
  175.     SetCursor(hcurSave);
  176.  
  177.     return fSuccess;
  178. }
  179.  
  180.  
  181.  
  182. /************************************************************************
  183. * LoadIncludeFile
  184. *
  185. * This function creates or adds to plInclude with all the #define
  186. * statements in the file with handle hfInclude.
  187. *
  188. * Returns:
  189. *     TRUE - Load succeeded.
  190. *     FALSE - Load failed (a read error).
  191. *
  192. ************************************************************************/
  193.  
  194. STATICFN BOOL LoadIncludeFile(VOID)
  195. {
  196.     INT RetCode;
  197.     BOOL fDups = FALSE;
  198.  
  199.     /*
  200.      * Set char count, get file cb.
  201.      */
  202.     cchFile = 0L;
  203.     cchFileMax = GetFileSize((HANDLE)hfInclude, NULL);
  204.     cbBuf = CCHFILEBUFFER;
  205.     fAtNewLine = TRUE;
  206.  
  207.     /*
  208.      * Loop through and extract all id definitions.
  209.      */
  210.     while ((RetCode = FindDefine()) != READ_EOF) {
  211.         if (RetCode == READ_BAD || (RetCode = GetLabel(&fDups)) == READ_BAD) {
  212.             Message(MSG_INTERNAL);
  213.             return FALSE;
  214.         }
  215.     }
  216.  
  217.     /*
  218.      * Warn the user if there were duplicate symbols,
  219.      * or symbols with duplicate ids.
  220.      */
  221.     if (fDups)
  222.         Message(MSG_IDUPIDS);
  223.  
  224.     return TRUE;
  225. }
  226.  
  227.  
  228.  
  229. /****************************************************************************
  230. * FindDefine
  231. *
  232. * This function looks for ^#define[\s\t], that "#define" at the start
  233. * of a line and followed by a space or a tab.
  234. *
  235. * Returns:
  236. *     READ_OK -> All OK & #define found.
  237. *     READ_EOF -> All OK, but EOF found before #define.
  238. *     READ_BAD = Failure on read.
  239. *
  240. ****************************************************************************/
  241.  
  242. STATICFN INT FindDefine(VOID)
  243. {
  244.     LPTSTR pchIn;
  245.     LPTSTR pchCmp;
  246.     BOOL fLastAtNewLine;
  247.  
  248. tryagain:
  249.  
  250.     /*
  251.      * Skip blank lines looking for a newline followed by a '#'.
  252.      */
  253.     while (TRUE) {
  254.         fLastAtNewLine = fAtNewLine;
  255.         pchIn = GetChar();
  256.  
  257.         if (pchIn == NULL)
  258.             return READ_EOF;
  259.         else if (pchIn == BAD_POINTER)
  260.             return READ_BAD;
  261.         else if (fLastAtNewLine && *pchIn == CHAR_POUND)
  262.             break;
  263.         else if (IsDBCSLeadByte((BYTE)*pchIn))
  264.             pchIn = GetChar();
  265.     }
  266.  
  267.     /*
  268.      * At this point a newline followed by a '#' has been found.
  269.      * Begin checking for "define".  Save away the file offset,
  270.      * in case we have really found one.
  271.      */
  272.     fposLastDefine = cchFile - 1;
  273.     pchCmp = ids(IDS_DEFINE);
  274.     do {
  275.         pchIn = GetChar();
  276.  
  277.         if (pchIn == BAD_POINTER)
  278.             return READ_BAD;
  279.         else if (pchIn == NULL || *pchIn != *pchCmp++)
  280.             goto tryagain;
  281.     } while (*pchCmp);
  282.  
  283.     /*
  284.      * Finally, look for the trailing space or tab after the "#define".
  285.      */
  286.     pchIn = GetChar();
  287.     if (pchIn == BAD_POINTER)
  288.         return READ_BAD;
  289.     else if (pchIn == NULL || (*pchIn != CHAR_SPACE && *pchIn != CHAR_TAB))
  290.         goto tryagain;
  291.  
  292.     return READ_OK;
  293. }
  294.  
  295.  
  296.  
  297. /************************************************************************
  298. * GetLabel
  299. *
  300. * This function gets the next two words from the file hfInclude and treats
  301. * them as a label and id, respectively.  It allocates another LABEL
  302. * and string to hold this information.
  303. *
  304. * Arguments:
  305. *   BOOL *pfDups = Points to a BOOL that will be set to TRUE if AddLabel
  306. *                  finds a duplicate symbol or id.
  307. *
  308. * Returns:
  309. *     READ_OK -> All OK.
  310. *     READ_BAD = Failure on read.
  311. *
  312. ************************************************************************/
  313.  
  314. STATICFN INT GetLabel(
  315.     BOOL *pfDups)
  316. {
  317.     INT id;
  318.     INT RetCode;
  319.     TCHAR szLabel[CCHTEXTMAX];
  320.  
  321.     /*
  322.      * Get string and ID at current position
  323.      */
  324.     switch (RetCode = GetWord(szLabel)) {
  325.         case READ_OK:
  326.             if ((RetCode = GetValue(&id)) == READ_OK) {
  327.                 AddLabel(szLabel, id, fposLastDefine,
  328.                         (INT)(fposWordStart - fposLastDefine),
  329.                         &plInclude, &plDelInclude, NULL, pfDups);
  330.             }
  331.  
  332.             break;
  333.  
  334.         default:
  335.             break;
  336.     }
  337.  
  338.     return RetCode;
  339. }
  340.  
  341.  
  342.  
  343. /************************************************************************
  344. * GetWord
  345. *
  346. * This function uses GetChar to get the next word from the include
  347. * file.  First it removes tabs and spaces, then it collects everything
  348. * to the next white space.  Finally it null terminates the word.
  349. *
  350. * Arguments:
  351. *     LPTSTR pch  - Where to put the word.
  352. *
  353. * Returns:
  354. *     READ_OK - a word was found.
  355. *     READ_EOF - EOF was found.
  356. *     READ_BAD - Error on Read.
  357. *     READ_WRONG - Found other than ' ' or '\t' followed by a letter,
  358. *                   number or _, +, -.
  359. *
  360. ************************************************************************/
  361.  
  362. STATICFN INT GetWord(
  363.     LPTSTR pch)
  364. {
  365.     TCHAR ch;
  366.     LPTSTR pchIn;
  367.  
  368.     /*
  369.      * Skip spaces.
  370.      */
  371.     while ((pchIn = GetChar()) != NULL && pchIn != BAD_POINTER &&
  372.                 ((ch = *pchIn) == CHAR_SPACE || ch == CHAR_TAB))
  373.         ;
  374.  
  375.     /*
  376.      * Errors or EOF?
  377.      */
  378.     if (pchIn == NULL)
  379.         return READ_EOF;
  380.     else if (pchIn == BAD_POINTER)
  381.         return READ_BAD;
  382.     if (!iscsym(ch) && ch != CHAR_MINUS && ch != CHAR_PLUS)
  383.         return READ_WRONG;
  384.  
  385.     /*
  386.      * Save starting location of the word in the file.
  387.      */
  388.     fposWordStart = cchFile - 1;
  389.  
  390.     /*
  391.      * Pick out the current word.
  392.      */
  393.     do {
  394.         *pch++ = ch;
  395.     } while ((pchIn = GetChar()) != NULL && pchIn != BAD_POINTER &&
  396.             (ch = *pchIn) != CHAR_SPACE && ch != CHAR_TAB &&
  397.             ch != CHAR_NEWLINE && ch != CHAR_RETURN);
  398.  
  399.     /*
  400.      * Errors or EOF?
  401.      */
  402.     if (pchIn == NULL)
  403.         return READ_WRONG;
  404.     else if (pchIn == BAD_POINTER)
  405.         return READ_BAD;
  406.  
  407.     /*
  408.      * Null terminate the word.
  409.      */
  410.     *pch = (TCHAR)0;
  411.  
  412.     return READ_OK;
  413. }
  414.  
  415.  
  416.  
  417. /************************************************************************
  418. * GetChar
  419. *
  420. * This function returns a pointer to the next character in the
  421. * stream hfInclude.  It calls ReadChar to do the actual work.
  422. *
  423. * As it is reading the stream, it will compress a comment sequence to
  424. * a single space.  This means that from a slash+asterisk to the next
  425. * asterisk+slash and from a pair of slashes to the end of the line all
  426. * that will be returned is a single space character.
  427. *
  428. * Returns:
  429. *     A pointer to next character in the stream hfInclude.
  430. *     NULL => End of file.
  431. *     BAD_POINTER => Problems reading file.
  432. *
  433. ************************************************************************/
  434.  
  435. STATICFN LPTSTR GetChar(VOID)
  436. {
  437.     register LPTSTR pch;
  438.  
  439.     /*
  440.      * Read the next character.
  441.      */
  442.     pch = ReadChar();
  443.     if (pch == NULL || pch == BAD_POINTER)
  444.         return pch;
  445.  
  446.     /*
  447.      * Possibly starting a comment?
  448.      */
  449.     if (*pch == CHAR_SLASH) {
  450.         /*
  451.          * Starting a traditional comment?
  452.          */
  453.         if (*(pch + 1) == CHAR_ASTERISK) {
  454.             /*
  455.              * Read the '*'.
  456.              */
  457.             pch = ReadChar();
  458.             if (pch == NULL || pch == BAD_POINTER)
  459.                 return pch;
  460.  
  461.             /*
  462.              * Read until the next asterisk+slash is found.
  463.              */
  464.             do {
  465.                 pch = ReadChar();
  466.                 if (pch == NULL || pch == BAD_POINTER)
  467.                     return pch;
  468.             } while (*pch != CHAR_ASTERISK || *(pch + 1) != CHAR_SLASH);
  469.  
  470.             /*
  471.              * Read the final '/'.
  472.              */
  473.             pch = ReadChar();
  474.             if (pch == NULL || pch == BAD_POINTER)
  475.                 return pch;
  476.  
  477.             /*
  478.              * Change it to a space.
  479.              */
  480.             *pch = CHAR_SPACE;
  481.         }
  482.         /*
  483.          * Starting a single line comment?
  484.          */
  485.         else if (*(pch + 1) == CHAR_SLASH) {
  486.             /*
  487.              * Read up to the end of line.
  488.              */
  489.             do {
  490.                 pch = ReadChar();
  491.                 if (pch == NULL || pch == BAD_POINTER)
  492.                     return pch;
  493.             } while (*(pch + 1) != CHAR_RETURN && *(pch + 1) != CHAR_NEWLINE);
  494.  
  495.             /*
  496.              * Convert the last character before the newline into a space.
  497.              */
  498.             *pch = CHAR_SPACE;
  499.         }
  500.     }
  501.  
  502.     return pch;
  503. }
  504.  
  505.  
  506.  
  507. /************************************************************************
  508. * ReadChar
  509. *
  510. * This function returns a pointer to the next character in the
  511. * stream hfInclude, but does it in a buffered fashion.  That is, abBuffer
  512. * is filled from hfInclude and pointers are returned to there.
  513. * Note that after ReadChar is called, all previous pointers
  514. * returned are meaningless.
  515. *
  516. * Returns:
  517. *     A pointer to next character in the stream hfInclude.
  518. *     NULL => End of file.
  519. *     BAD_POINTER => Problems reading file.
  520. *
  521. * Comments:
  522. *     May cause abBuffer to be filled from file with handle hfInclude.
  523. *     cbBuf is changed.
  524. *     cchFile is changed.
  525. *     Sets fAtNewLine = TRUE if char returned is '\n' or '\r', or FALSE
  526. *         otherwise.  Not changed unless a character is returned.
  527. *
  528. ************************************************************************/
  529.  
  530. STATICFN LPTSTR ReadChar(VOID)
  531. {
  532.     register LPTSTR pch;
  533.     INT cbRead;
  534.  
  535.     if (cchFile >= cchFileMax)
  536.         return NULL;
  537.  
  538.     if (cbBuf >= CCHFILEBUFFER) {
  539.         if ((cbRead = _lread((HFILE)hfInclude, abBuffer, CCHFILEBUFFER)) == -1)
  540.             return BAD_POINTER;
  541.  
  542.         MultiByteToWideChar(CP_ACP, 0, abBuffer, cbRead, achBuffer,
  543.                 CCHFILEBUFFER);
  544.  
  545.         cbBuf = 0;
  546.     }
  547.  
  548.     pch = achBuffer + cbBuf;
  549.     cbBuf++;
  550.     cchFile++;
  551.  
  552.     if (*pch == CHAR_DOSEOF) {
  553.         cchFile = cchFileMax;
  554.         return NULL;
  555.     }
  556.  
  557.     fAtNewLine = (*pch == CHAR_RETURN || *pch == CHAR_NEWLINE) ? TRUE : FALSE;
  558.  
  559.     return pch;
  560. }
  561.  
  562.  
  563.  
  564. /************************************************************************
  565. * GetValue
  566. *
  567. * This function reads the next word in the file hfInclude with GetWord
  568. * and converts that word to a number.
  569. *
  570. * If the second character of the word is an 'x' or 'X', the word is
  571. * assumed to be a hex number and it is converted appropriately.
  572. *
  573. * Arguments:
  574. *     npsValue - Where to put the value of the next word in file.
  575. *
  576. * Returns:
  577. *     READ_OK - success.
  578. *     READ_BAD - am error occured.
  579. *     READ_WRONG - Something other than a number was found.
  580. *
  581. ************************************************************************/
  582.  
  583. STATICFN INT GetValue(
  584.     PINT pnValue)
  585. {
  586.     TCHAR achValue[CCHTEXTMAX];
  587.     LPTSTR pch;
  588.     INT RetValue;
  589.  
  590.     *pnValue = 0;
  591.     if ((RetValue = GetWord(achValue)) != READ_OK)
  592.         return RetValue;
  593.  
  594.     /*
  595.      * Verify we have only a number.
  596.      */
  597.     pch = achValue;
  598.     if (pch[1] == CHAR_CAP_X || pch[1] == CHAR_X) {
  599.         if (*pch != CHAR_0) {
  600.             RetValue = READ_WRONG;
  601.         }
  602.         else {
  603.             for (pch += 2; *pch; pch++) {
  604.                 if (!iswxdigit(*pch)) {
  605.                     RetValue = READ_WRONG;
  606.                     break;
  607.                 }
  608.             }
  609.  
  610.             if (RetValue == READ_OK)
  611.                 *pnValue = axtoi(&achValue[2]);
  612.         }
  613.     }
  614.     else {
  615.         if (!iswdigit(*pch) && *pch != CHAR_MINUS && *pch != CHAR_PLUS) {
  616.             RetValue = READ_WRONG;
  617.         }
  618.         else {
  619.             for (pch++; *pch; pch++) {
  620.                 if (!iswdigit(*pch)) {
  621.                     RetValue = READ_WRONG;
  622.                     break;
  623.                 }
  624.             }
  625.  
  626.             if (RetValue == READ_OK)
  627.                 *pnValue = awtoi(achValue);
  628.         }
  629.     }
  630.  
  631.     return RetValue;
  632. }
  633.  
  634.  
  635.  
  636. /************************************************************************
  637. * FreeInclude
  638. *
  639. * This function frees the memory associated with an include file,
  640. * sets global variables to match, and closes the currently open
  641. * include file.  It frees plInclude, plDelInclude and all the LABELs in them.
  642. * It sets gfIncChged to FALSE, sets pszIncludeFile to NULL, and
  643. * closes any open include file.
  644. *
  645. ************************************************************************/
  646.  
  647. VOID FreeInclude(VOID)
  648. {
  649.     FreeLabels(&plInclude);
  650.     FreeLabels(&plDelInclude);
  651.     gfIncChged = FALSE;
  652.     pszIncludeFile = NULL;
  653. }
  654.  
  655.  
  656.  
  657. /************************************************************************
  658. * WriteInc
  659. *
  660. * This function writes the labels in plInclude to an include file.
  661. *
  662. * Arguments:
  663. *   HANDLE hfWrite - handle to the file to write to.
  664. *
  665. * Returns:
  666. *   TRUE if successful, FALSE if not.
  667. *
  668. ************************************************************************/
  669.  
  670. BOOL WriteInc(
  671.     HANDLE hfWrite)
  672. {
  673.     INT nGNIRet;
  674.     NPLABEL plInc;
  675.     BOOL fEOF;
  676.  
  677.     /*
  678.      * Is there an include file already specified?  If so,
  679.      * open it.  If not, we are effectively at EOF now.
  680.      */
  681.     if (pszIncludeFile) {
  682.         if ((hfInclude = CreateFile(szFullIncludeFile, GENERIC_READ,
  683.                 FILE_SHARE_READ, NULL, OPEN_EXISTING,
  684.                 FILE_FLAG_SEQUENTIAL_SCAN, NULL)) == (HANDLE)-1) {
  685.             //if the include file is missing or locked...
  686.             return FALSE;
  687.         }
  688.  
  689.         fEOF = FALSE;
  690.     }
  691.     else {
  692.         fEOF = TRUE;
  693.     }
  694.  
  695.     cchFile = 0;
  696.     cbWritePos = 0;
  697.     cbBuf = CCHFILEBUFFER;
  698.     fAtNewLine = TRUE;
  699.  
  700.     /*
  701.      * Loop through all the includes.
  702.      */
  703.     nGNIRet = GetNextInc(&plInc, TRUE);
  704.     while (nGNIRet != GNI_DONE) {
  705.         switch (nGNIRet) {
  706.             case GNI_NOCHANGE:
  707.                 break;
  708.  
  709.             case GNI_CHANGED:
  710.                 if (!WriteChangedInc(hfWrite, plInc))
  711.                     return FALSE;
  712.  
  713.                 break;
  714.  
  715.             case GNI_DELETED:
  716.                 if (!WriteDeletedInc(hfWrite, plInc))
  717.                     return FALSE;
  718.  
  719.                 break;
  720.  
  721.             case GNI_ADDED:
  722.                 /*
  723.                  * The first time we reach an added label, we know that
  724.                  * there are no more changed or deleted ones to handle
  725.                  * so we read/write up to the end of the old include file.
  726.                  * This only has to be done once.
  727.                  */
  728.                 if (!fEOF) {
  729.                     if (!RWToOffset(hfWrite, FPOS_MAX))
  730.                         return FALSE;
  731.  
  732.                     fEOF = TRUE;
  733.  
  734.                     /*
  735.                      * In the unlikely case that the read include file
  736.                      * does not end with a carriage return and/or
  737.                      * linefeed character, add them before beginning
  738.                      * to write added labels.  This ensures that the
  739.                      * first label added always starts on a new line.
  740.                      */
  741.                     if (!fAtNewLine) {
  742.                         if (!WriteIncChar(hfWrite, CHAR_RETURN))
  743.                             return FALSE;
  744.  
  745.                         if (!WriteIncChar(hfWrite, CHAR_NEWLINE))
  746.                             return FALSE;
  747.                     }
  748.                 }
  749.  
  750.                 if (!WriteAddedInc(hfWrite, plInc))
  751.                     return FALSE;
  752.  
  753.                 break;
  754.         }
  755.  
  756.         nGNIRet = GetNextInc(&plInc, FALSE);
  757.     }
  758.  
  759.     /*
  760.      * Write the rest of the file, if there is any left.
  761.      */
  762.     if (!fEOF)
  763.         if (!RWToOffset(hfWrite, FPOS_MAX))
  764.             return FALSE;
  765.  
  766.     /*
  767.      * Flush any remaining characters in the write buffer.
  768.      */
  769.     if (!WriteIncFlush(hfWrite))
  770.         return FALSE;
  771.  
  772.     /*
  773.      * If we just opened the old include file, close it.
  774.      */
  775.     if (pszIncludeFile)
  776.         CloseHandle(hfInclude);
  777.  
  778.     return TRUE;
  779. }
  780.  
  781.  
  782.  
  783. /************************************************************************
  784. * GetNextInc
  785. *
  786. * This routine will return the next label in the plInclude and plDelInclude
  787. * linked lists, as well as the status of the returned label.
  788. *
  789. * The labels will be returned in order based upon their location in the
  790. * lists, which is their order found in the include file if their fpos
  791. * field is not FPOS_MAX.  This routine looks at the next label in both the
  792. * plInclude and plDelInclude lists and returns the one with the lowest
  793. * fpos.  Labels are returned from plInclude and plDelInclude in order of
  794. * their fpos until all have been returned with a valid fpos.  After this,
  795. * all new includes are returned from plInclude.
  796. *
  797. * Call it with fFirst equal to TRUE to initialize it.
  798. *
  799. * Arguments:
  800. *   NPLABEL *pplReturn - label to return.
  801. *   BOOL fFirst - TRUE if initializing.
  802. *
  803. * Returns:
  804. *   GNI_DONE     - No more labels exist.
  805. *   GNI_NOCHANGE - An existing label is being returned.
  806. *   GNI_CHANGED  - An existing label with a changed id is being returned.
  807. *   GNI_DELETED  - A deleted label is being returned.
  808. *   GNI_ADDED    - An added label is being returned.
  809. *
  810. ************************************************************************/
  811.  
  812. STATICFN INT GetNextInc(
  813.     NPLABEL *pplReturn,
  814.     BOOL fFirst)
  815. {
  816.     static NPLABEL plCur;
  817.     static NPLABEL plDelCur;
  818.  
  819.     /*
  820.      * Initialize if this is the first time.
  821.      */
  822.     if (fFirst) {
  823.         plCur = plInclude;
  824.         plDelCur = plDelInclude;
  825.     }
  826.  
  827.     /*
  828.      * Are we out of valid includes?
  829.      */
  830.     if (!plCur) {
  831.         /*
  832.          * If there are deleted ones left, return the next one.
  833.          * Otherwise we are done.
  834.          */
  835.         if (plDelCur) {
  836.             *pplReturn = plDelCur;
  837.             plDelCur = plDelCur->npNext;
  838.             return GNI_DELETED;
  839.         }
  840.         else {
  841.             return GNI_DONE;
  842.         }
  843.     }
  844.     /*
  845.      * Have we reached the added includes (fpos == FPOS_MAX)?
  846.      */
  847.     else if (plCur->fpos == FPOS_MAX) {
  848.         /*
  849.          * If there are deleted ones remaining, return them first.
  850.          * Otherwise, return the next added one.
  851.          */
  852.         if (plDelCur) {
  853.             *pplReturn = plDelCur;
  854.             plDelCur = plDelCur->npNext;
  855.             return GNI_DELETED;
  856.         }
  857.         else {
  858.             *pplReturn = plCur;
  859.             plCur = plCur->npNext;
  860.             return GNI_ADDED;
  861.         }
  862.     }
  863.     else {
  864.         /*
  865.          * Return either the next label or the next deleted label,
  866.          * based on whether there are any deleted labels and who
  867.          * has the lowest file position (fpos).
  868.          */
  869.         if (plDelCur && plDelCur->fpos < plCur->fpos) {
  870.             *pplReturn = plDelCur;
  871.             plDelCur = plDelCur->npNext;
  872.             return GNI_DELETED;
  873.         }
  874.         else {
  875.             *pplReturn = plCur;
  876.             plCur = plCur->npNext;
  877.             /*
  878.              * Return either GNI_CHANGE or GNI_NOCHANGE based on
  879.              * whether the original id value has been changed.
  880.              */
  881.             return ((*pplReturn)->id == (*pplReturn)->idOrig) ?
  882.                     GNI_NOCHANGE : GNI_CHANGED;
  883.         }
  884.     }
  885. }
  886.  
  887.  
  888.  
  889. /************************************************************************
  890. * RWToOffset
  891. *
  892. * This routine reads from the current include file and writes to the
  893. * hfWrite file up to the lOffset position in the file.  If lOffset is
  894. * set to FPOS_MAX, reads/writes are performed up to the end of the
  895. * read file.
  896. *
  897. * Arguments:
  898. *   HANDLE hfWrite - handle to the file to write to.
  899. *   DWORD lOffset - where to write up to.
  900. *
  901. * Returns:
  902. *   TRUE if successful, FALSE if not.
  903. *
  904. * Comments:
  905. *   This routine relies on cchFile and cchFileMax to be properly updated
  906. *   by the reading and writing routines.
  907. *
  908. ************************************************************************/
  909.  
  910. STATICFN BOOL RWToOffset(
  911.     HANDLE hfWrite,
  912.     DWORD lOffset)
  913. {
  914.     LPTSTR pchIn;
  915.     DWORD cbWrite;
  916.  
  917.     if (lOffset == FPOS_MAX)
  918.         lOffset = cchFileMax;
  919.  
  920.     for (cbWrite = lOffset - cchFile; cbWrite; cbWrite--) {
  921.         /*
  922.          * NULL can be returned if there is an EOF character found in
  923.          * the file.  This is not an error, and we will stop reading
  924.          * and writing at this point.
  925.          */
  926.         if ((pchIn = ReadChar()) == NULL)
  927.             return TRUE;
  928.  
  929.         /*
  930.          * If BAD_POINTER is returned, there was an error reading the
  931.          * include file.
  932.          */
  933.         if (pchIn == BAD_POINTER)
  934.             return FALSE;
  935.  
  936.         /*
  937.          * Write out the character.
  938.          */
  939.         if (!WriteIncChar(hfWrite, *pchIn))
  940.             return FALSE;
  941.     }
  942.  
  943.     return TRUE;
  944. }
  945.  
  946.  
  947.  
  948. /************************************************************************
  949. * WriteIncChar
  950. *
  951. * This routine writes a character (ch) to the hfWrite file, doing it in a
  952. * buffered fashion.  Because it is buffered, before closing the file
  953. * any remaining characters in the buffer must be "flushed" to disk.
  954. *
  955. * Arguments:
  956. *   HANDLE hfWrite - handle to the file to write to.
  957. *   TCHAR ch - character to write.
  958. *
  959. * Returns:
  960. *   TRUE if successful, FALSE if not.
  961. *
  962. * Comments:
  963. * The globals gachWriteBuffer and cbWritePos are updated by this routine.
  964. *
  965. ************************************************************************/
  966.  
  967. STATICFN BOOL WriteIncChar(
  968.     HANDLE hfWrite,
  969.     TCHAR ch)
  970. {
  971.     INT cbWritten;
  972.  
  973.     gachWriteBuffer[cbWritePos++] = ch;
  974.  
  975.     /*
  976.      * Is the buffer full?
  977.      */
  978.     if (cbWritePos == CCHFILEBUFFER) {
  979.         CHAR abWriteBuffer[CCHFILEBUFFER];
  980.         BOOL fDefCharUsed;
  981.  
  982.         WideCharToMultiByte(CP_ACP, 0, gachWriteBuffer, CCHFILEBUFFER,
  983.                 abWriteBuffer, CCHFILEBUFFER, NULL, &fDefCharUsed);
  984.  
  985.         cbWritten = (INT)_lwrite((HFILE)hfWrite, abWriteBuffer, cbWritePos);
  986.         if (cbWritten != cbWritePos)
  987.             return FALSE;
  988.  
  989.         cbWritePos = 0;
  990.     }
  991.  
  992.     return TRUE;
  993. }
  994.  
  995.  
  996.  
  997. /************************************************************************
  998. * WriteIncFlush
  999. *
  1000. * This routine flushes the write buffer.  This must be done before
  1001. * the file is closed or data can be lost.
  1002. *
  1003. * Arguments:
  1004. *   HANDLE hfWrite - handle to the file to write to.
  1005. *
  1006. * Returns:
  1007. *   TRUE if successful, FALSE if not.
  1008. *
  1009. * Comments:
  1010. *   The global cbWritePos is updated by this routine.
  1011. *
  1012. ************************************************************************/
  1013.  
  1014. STATICFN BOOL WriteIncFlush(
  1015.     HANDLE hfWrite)
  1016. {
  1017.     INT cbWritten;
  1018.  
  1019.     /*
  1020.      * Are any bytes remaining in the buffer?
  1021.      */
  1022.     if (cbWritePos) {
  1023.         CHAR abWriteBuffer[CCHFILEBUFFER];
  1024.         BOOL fDefCharUsed;
  1025.  
  1026.         WideCharToMultiByte(CP_ACP, 0, gachWriteBuffer, cbWritePos,
  1027.                 abWriteBuffer, CCHFILEBUFFER, NULL, &fDefCharUsed);
  1028.  
  1029.         cbWritten = (INT)_lwrite((HFILE)hfWrite, abWriteBuffer, cbWritePos);
  1030.         if (cbWritten != cbWritePos)
  1031.             return FALSE;
  1032.  
  1033.         cbWritePos = 0;
  1034.     }
  1035.  
  1036.     return TRUE;
  1037. }
  1038.  
  1039.  
  1040.  
  1041. /************************************************************************
  1042. * WriteChangedInc
  1043. *
  1044. * This routine writes out a label that has had its id changed since the
  1045. * include file was last read.
  1046. *
  1047. * Arguments:
  1048. *   HANDLE hfWrite - File to write to.
  1049. *   NPLABEL plInc  - Label to write.
  1050. *
  1051. * Returns:
  1052. *   TRUE if successful, FALSE if not.
  1053. *
  1054. * History:
  1055. *   03/13/90 Byron Dazey - Created.
  1056. ************************************************************************/
  1057.  
  1058. STATICFN BOOL WriteChangedInc(
  1059.     HANDLE hfWrite,
  1060.     NPLABEL plInc)
  1061. {
  1062.     TCHAR ch;
  1063.     LPTSTR pchIn;
  1064.  
  1065.     if (!RWToOffset(hfWrite, plInc->fpos + plInc->nValueOffset))
  1066.         return FALSE;
  1067.  
  1068.     /*
  1069.      * Consume the old id value (up to the next space, tab,
  1070.      * beginning of a comment, newline or return).
  1071.      */
  1072.     while ((pchIn = ReadChar()) != NULL && pchIn != BAD_POINTER &&
  1073.             (ch = *pchIn) != CHAR_SPACE && ch != CHAR_TAB &&
  1074.             ch != CHAR_SLASH && ch != CHAR_NEWLINE && ch != CHAR_RETURN)
  1075.         ;
  1076.  
  1077.     /*
  1078.      * It is an error if ReadChar returns BAD_POINTER.  Note that it
  1079.      * is NOT an error if it reaches EOF (and returns NULL).
  1080.      */
  1081.     if (pchIn == BAD_POINTER)
  1082.         return FALSE;
  1083.  
  1084.     /*
  1085.      * Write the new one.
  1086.      */
  1087.     if (!WriteIDInc(hfWrite, plInc->id))
  1088.         return FALSE;
  1089.  
  1090.     /*
  1091.      * Remember to write the last character read after the old value.
  1092.      */
  1093.     if (pchIn != NULL)
  1094.         if (!WriteIncChar(hfWrite, *pchIn))
  1095.             return FALSE;
  1096.  
  1097.     return TRUE;
  1098. }
  1099.  
  1100.  
  1101.  
  1102. /************************************************************************
  1103. * WriteDeletedInc
  1104. *
  1105. * This routine deletes a label in the include file, closing up the
  1106. * space.  The entire line will be deleted, unless a comment is found
  1107. * after the id value.  If so, the comment and following characters will
  1108. * be left.
  1109. *
  1110. * Arguments:
  1111. *   HANDLE hfWrite - File to write to.
  1112. *   NPLABEL plInc  - Label to delete.
  1113. *
  1114. * Returns:
  1115. *   TRUE if successful, FALSE if not.
  1116. *
  1117. * History:
  1118. *   03/13/90 Byron Dazey - Created.
  1119. ************************************************************************/
  1120.  
  1121. STATICFN BOOL WriteDeletedInc(
  1122.     HANDLE hfWrite,
  1123.     NPLABEL plInc)
  1124. {
  1125.     register INT i;
  1126.     TCHAR ch;
  1127.     LPTSTR pchIn;
  1128.  
  1129.     /*
  1130.      * Read and write up to the #define to be deleted.
  1131.      */
  1132.     if (!RWToOffset(hfWrite, plInc->fpos))
  1133.         return FALSE;
  1134.  
  1135.     /*
  1136.      * Consume up to the id value.
  1137.      */
  1138.     for (i = plInc->nValueOffset; i; i--)
  1139.         if ((pchIn = ReadChar()) == NULL || pchIn == BAD_POINTER)
  1140.             return FALSE;
  1141.  
  1142.     /*
  1143.      * Consume the id value and following characters up to the end of
  1144.      * the line or the beginning of a comment.
  1145.      */
  1146.     while ((pchIn = ReadChar()) != NULL && pchIn != BAD_POINTER &&
  1147.             (ch = *pchIn) != CHAR_NEWLINE && ch != CHAR_RETURN &&
  1148.             ch != CHAR_SLASH)
  1149.         ;
  1150.  
  1151.     if (pchIn == BAD_POINTER)
  1152.         return FALSE;
  1153.  
  1154.     /*
  1155.      * We are done if we have reached EOF.
  1156.      */
  1157.     if (pchIn == NULL)
  1158.         return TRUE;
  1159.  
  1160.     /*
  1161.      * If the beginning of a comment was found, be sure to write the
  1162.      * character back out and leave the rest of the comment.
  1163.      */
  1164.     if (ch == CHAR_SLASH) {
  1165.         if (!WriteIncChar(hfWrite, ch))
  1166.             return FALSE;
  1167.     }
  1168.     else {
  1169.         /*
  1170.          * At this point either a newline or a return was found
  1171.          * and we are going to consume it.  We also want to check
  1172.          * for a return following the newline, or a newline
  1173.          * following the return and consume it also.
  1174.          */
  1175.         if ((ch == CHAR_NEWLINE && *(pchIn + 1) == CHAR_RETURN) ||
  1176.                 (ch == CHAR_RETURN && *(pchIn + 1) == CHAR_NEWLINE))
  1177.             if (ReadChar() == BAD_POINTER)
  1178.                 return FALSE;
  1179.     }
  1180.  
  1181.     return TRUE;
  1182. }
  1183.  
  1184.  
  1185.  
  1186. /************************************************************************
  1187. * WriteAddedInc
  1188. *
  1189. * Adds a label to the new include file.
  1190. *
  1191. * Arguments:
  1192. *   HANDLE hfWrite - File to write to.
  1193. *   NPLABEL plInc  - Label to add.
  1194. *
  1195. * Returns:
  1196. *   TRUE if successful, FALSE if not.
  1197. *
  1198. * History:
  1199. *   03/13/90 Byron Dazey - Created.
  1200. ************************************************************************/
  1201.  
  1202. STATICFN BOOL WriteAddedInc(
  1203.     HANDLE hfWrite,
  1204.     NPLABEL plInc)
  1205. {
  1206.     register LPTSTR psz;
  1207.  
  1208.     /*
  1209.      * Write the "#define " string.
  1210.      */
  1211.     psz = ids(IDS_POUNDDEFINE);
  1212.     while (*psz)
  1213.         if (!WriteIncChar(hfWrite, *psz++))
  1214.             return FALSE;
  1215.  
  1216.     /*
  1217.      * Write the symbol, followed by a space.
  1218.      */
  1219.     if (!WriteSymbol(hfWrite, plInc->pszLabel))
  1220.         return FALSE;
  1221.     if (!WriteIncChar(hfWrite, CHAR_SPACE))
  1222.         return FALSE;
  1223.  
  1224.     /*
  1225.      * Write the id, followed by a carriage return and newline.
  1226.      */
  1227.     if (!WriteIDInc(hfWrite, plInc->id))
  1228.         return FALSE;
  1229.     if (!WriteIncChar(hfWrite, CHAR_RETURN))
  1230.         return FALSE;
  1231.     if (!WriteIncChar(hfWrite, CHAR_NEWLINE))
  1232.         return FALSE;
  1233.  
  1234.     return TRUE;
  1235. }
  1236.  
  1237.  
  1238.  
  1239. /************************************************************************
  1240. * WriteSymbol
  1241. *
  1242. * Writes out a "#define DID_xxx  " string to hfWrite.  If the symbol
  1243. * is smaller than CCHSYMFIELDWIDTH, it will be padded with spaces out
  1244. * to this width.
  1245. *
  1246. * Arguments:
  1247. *   HANDLE hfWrite - handle to the file to write to.
  1248. *   LPTSTR pszSymbol - symbol to write.
  1249. *
  1250. * Returns:
  1251. *   TRUE if successful, FALSE if not.
  1252. *
  1253. ************************************************************************/
  1254.  
  1255. STATICFN BOOL WriteSymbol(
  1256.     HANDLE hfWrite,
  1257.     LPTSTR pszSymbol)
  1258. {
  1259.     register INT cch;
  1260.  
  1261.     /*
  1262.      * Write the symbol.
  1263.      */
  1264.     cch = 0;
  1265.     while (*pszSymbol) {
  1266.         if (!WriteIncChar(hfWrite, *pszSymbol++))
  1267.             return FALSE;
  1268.  
  1269.         cch++;
  1270.     }
  1271.  
  1272.     /*
  1273.      * Pad the field with blanks out to CCHSYMFIELDWIDTH, if necessary.
  1274.      */
  1275.     if (cch < CCHSYMFIELDWIDTH) {
  1276.         cch = CCHSYMFIELDWIDTH - cch;
  1277.         while (cch--)
  1278.             if (!WriteIncChar(hfWrite, CHAR_SPACE))
  1279.                 return FALSE;
  1280.     }
  1281.  
  1282.     return TRUE;
  1283. }
  1284.  
  1285.  
  1286.  
  1287. /************************************************************************
  1288. * WriteIDInc
  1289. *
  1290. * Writes out an id value to the hfWrite file.  The format will be in
  1291. * either hex or decimal, depending on the current mode.
  1292. *
  1293. * Arguments:
  1294. *   HANDLE hfWrite - File to write to.
  1295. *   INT id         - ID to write.
  1296. *
  1297. * Returns:
  1298. *   TRUE if successful, FALSE if not.
  1299. *
  1300. ************************************************************************/
  1301.  
  1302. STATICFN BOOL WriteIDInc(
  1303.     HANDLE hfWrite,
  1304.     INT id)
  1305. {
  1306.     register LPTSTR psz;
  1307.     TCHAR szValue[CCHIDMAX + 1];
  1308.  
  1309.     Myitoa(id, szValue);
  1310.  
  1311.     psz = szValue;
  1312.     while (*psz)
  1313.         if (!WriteIncChar(hfWrite, *psz++))
  1314.             return FALSE;
  1315.  
  1316.     return TRUE;
  1317. }
  1318.