RWINC.C
上传用户:bangxh
上传日期:2007-01-31
资源大小:42235k
文件大小:35k
源码类别:

Windows编程

开发平台:

Visual C++

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