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

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: include.c
  12. *
  13. * This module contains routines that manipulate the linked lists
  14. * of labels (symbols plus id values).
  15. *
  16. * Functions:
  17. *    AddLabel()
  18. *    FindLabel()
  19. *    FindID()
  20. *    FindIDInRes()
  21. *    DeleteLabel()
  22. *    IsSymbol()
  23. *    IDToLabel()
  24. *    LabelToID()
  25. *    FreeLabels()
  26. *
  27. * Comments:
  28. *
  29. * The following describes the linked lists of LABEL structures that
  30. * contain all the symbols that are in the include file.  It is
  31. * important that these structures and lists be maintained properly
  32. * for the udpating of the include file to occur properly.
  33. *
  34. * The following fields are in the LABEL structure:
  35. *
  36. *   npNext   - points to * the next label in the list.  This is NULL 
  37. *              for the last link in the list.  
  38. *   pszLabel - points to a null terminated, allocated string that 
  39. *              has the symbol.  This needs to be free'd if the structure
  40. *              is free'd.
  41. *   id       - the current id value for this symbol.
  42. *   idOrig   - the id value as read from the include file.  This
  43. *              field is used to determine if the id value has been changed 
  44. *              or not, so it is the same as the id unless the user has 
  45. *              modified the id value of the symbol.  
  46. *   fpos     - the file pointer offset to the "#" in the "#define" in 
  47. *              the include file as it was read in.  This field is used 
  48. *              to determine where the "#define" line starts in the
  49. *              file.  If the label is added by the user (it does not exist 
  50. *              in the include file) this field will be set to FPOS_MAX.
  51. *   nValueOffset - the offset in bytes from the fpos value to the start of 
  52. *              the id value in the "#define" line in the include file.  This 
  53. *              will be ignored if fpos is set to FPOS_MAX.
  54. *
  55. * The order of the linked lists of labels are very important.  The order
  56. * will be exactly the same as is read from the include file.  This
  57. * allows any changes to be merged back out to the new  include file
  58. * when it is saved.  If any labels are added by the user, they will be
  59. * added to the end of the list.  The start of the new ones is detected
  60. * by the first label with an fpos value of FPOS_MAX (which all the
  61. * new ones should have).  Because the order of the new labels is not
  62. * critical (they will be added to the end of the include file) the
  63. * new labels are sorted by id value.  Because the id values given
  64. * to dialogs and controls by default are ascending, this will tend to
  65. * group dialogs labels and their associated control labels together.
  66. *
  67. * Linked lists of labels always come in pairs.  There is the linked
  68. * list of current labels (ones read from the include file followed
  69. * by labels added later), and there is also a separate linked list
  70. * of "deleted" labels.  The deleted label list is required because
  71. * when the include file is saved, the deleted labels must be removed
  72. * from the include file, so the label structure for them (which
  73. * contains their file offset and so on) must be kept around.  When
  74. * the user deletes a label, it is removed from the current label
  75. * linked list and added to the deleted label list.  The deleted label
  76. * list MUST be kept in order by fpos, but if the label that is
  77. * deleted is one that did not exist in the include file (its fpos
  78. * was FPOS_MAX) then it does NOT have to be added to the deleted
  79. * list, and can simply be free'd.  When the user adds a new label,
  80. * the deleted list is searched first to see if the label was
  81. * previously deleted.  If it was, it is removed from the deleted list
  82. * and placed back in the current label list (sorted by fpos, of
  83. * course).  If it is a new label, it is simply added to the new labels
  84. * at the end of the list (sorted by id value).  This is why every
  85. * function that takes a pointer to the head of a label list also
  86. * takes a pointer to the head of a deleted label list.
  87. *
  88. ****************************************************************************/
  89. #include "dlgedit.h"
  90. #include "dlgfuncs.h"
  91. #include "dlgextrn.h"
  92. /************************************************************************
  93. * AddLabel
  94. *
  95. * This adds a symbol/label into the given include file list.  The deleted
  96. * include list is first searched and if a deleted label is found with the
  97. * same symbol, it is transfered back into the include list.  This is to
  98. * handle the case where a user reads in an include file, deletes one of
  99. * the labels then adds it back in later.
  100. *
  101. * The npLabelSkip parameter is for the special case of changing a
  102. * label.  This is done by adding a new label then deleting the old
  103. * one, so setting this parameter prevents a spurious "duplicate id"
  104. * message during the add.
  105. *
  106. * The pfDups parameter can be used to set a flag when there is a
  107. * duplicate symbol, or a symbol with the same id found in the include
  108. * list.  If this parameter is NULL, nothing is returned and the appropriate
  109. * error message is displayed if a dup is found.  If this parameter is not
  110. * NULL, it is assumed to point to a BOOL that will be set to TRUE if either
  111. * of these conditions is found.  The flag will NOT be set to FALSE if this
  112. * condition is NOT found, so AddLabel can be used in a loop and when the
  113. * loop is done, *pfDups will contain TRUE if there were any duplicates.
  114. * Note that if pfDups is not NULL, the dup error messages will be supressed.
  115. * This routine truncates pszLabel at the first space.  It can allocate 
  116. * memory for a LABEL and for its string. The pplHead and pplDelHead lists
  117. * are updated.
  118. *
  119. * Arguments:
  120. *     LPTSTR pszLabel      = The label to add.
  121. *     INT id               = The id associated with rgchLabel.
  122. *     DWORD fpos           = The file position in the include file where the
  123. *                            "#define" for this label starts, or FPOS_MAX
  124. *                            if the label was not read from an include file.
  125. *     INT nValueOffset     = Offset from fpos where the id value begins.
  126. *     NPLABEL *pplHead     = Pointer to the head of the include list to use.
  127. *     NPLABEL *pplDelHead  = Pointer to the head of the deleted include list.
  128. *     NPLABEL npLabelSkip  = If not NULL, points to a label to skip when
  129. *                            checking for duplicates.
  130. *     BOOL *pfDups         = Points to a BOOL that is set to TRUE if there
  131. *                            is a duplicate symbol or id found.
  132. *
  133. * Returns:
  134. *     Pointer to the allocated LABEL structure - NULL for an error.
  135. *
  136. ************************************************************************/
  137. NPLABEL AddLabel(
  138.     LPTSTR pszLabel,
  139.     INT id,
  140.     DWORD fpos,
  141.     INT nValueOffset,
  142.     NPLABEL *pplHead,
  143.     NPLABEL *pplDelHead,
  144.     NPLABEL npLabelSkip,
  145.     BOOL *pfDups)
  146. {
  147.     register NPLABEL npTmp;
  148.     NPLABEL npLabel;
  149.     NPLABEL npPrevLabel;
  150.     BOOL fFoundDeleted = FALSE;
  151.     /*
  152.      * First check for a duplicate id or symbol.
  153.      */
  154.     for (npTmp = *pplHead; npTmp; npTmp = npTmp->npNext) {
  155.         if ((npTmp->id == id || lstrcmp(pszLabel, npTmp->pszLabel) == 0) &&
  156.                 npTmp != npLabelSkip) {
  157.             if (pfDups) {
  158.                 *pfDups = TRUE;
  159.             }
  160.             else {
  161.                 if (npTmp->id == id)
  162.                     Message(MSG_LABELDUPID);
  163.                 else
  164.                     Message(MSG_SYMEXISTS);
  165.             }
  166.             return NULL;
  167.         }
  168.     }
  169.     /*
  170.      * Search for this symbol in the deleted list first.
  171.      */
  172.     npPrevLabel = NULL;
  173.     for (npLabel = *pplDelHead; npLabel; npLabel = npLabel->npNext) {
  174.         if (lstrcmp(pszLabel, npLabel->pszLabel) == 0) {
  175.             fFoundDeleted = TRUE;
  176.             break;
  177.         }
  178.         npPrevLabel = npLabel;
  179.     }
  180.     /*
  181.      * Was the label found in the deleted list?
  182.      */
  183.     if (fFoundDeleted) {
  184.         /*
  185.          * Close up the deleted list where the deleted label was.
  186.          */
  187.         if (npPrevLabel)
  188.             npPrevLabel->npNext = npLabel->npNext;
  189.         else
  190.             *pplDelHead = npLabel->npNext;
  191.         /*
  192.          * Set the id in case the user is adding the same symbol
  193.          * but with a different id.
  194.          */
  195.         npLabel->id = id;
  196.         /*
  197.          * Search for where the label should be inserted
  198.          * based on its fpos.
  199.          */
  200.         npPrevLabel = NULL;
  201.         for (npTmp = *pplHead; npTmp; npTmp = npTmp->npNext) {
  202.             if (npTmp->fpos == FPOS_MAX || npTmp->fpos > npLabel->fpos)
  203.                 break;
  204.             npPrevLabel = npTmp;
  205.         }
  206.     }
  207.     else {
  208.         /*
  209.          * Label was not found in the deleted list.  Allocate, etc.
  210.          */
  211.         if (!(npLabel = (NPLABEL)MyAlloc(sizeof(LABEL))))
  212.             return NULL;
  213.         npLabel->id = id;
  214.         npLabel->idOrig = id;
  215.         npLabel->fpos = fpos;
  216.         npLabel->nValueOffset = nValueOffset;
  217.         if (!(npLabel->pszLabel =
  218.                 (LPTSTR)MyAlloc((lstrlen(pszLabel) + 1) * sizeof(TCHAR)))) {
  219.             MyFree(npLabel);
  220.             return NULL;
  221.         }
  222.         lstrcpy(npLabel->pszLabel, pszLabel);
  223.         /*
  224.          * Find where to insert the new label.  This will either be
  225.          * at the end of the list, or in ascending numerical order
  226.          * among the new labels.
  227.          */
  228.         npPrevLabel = NULL;
  229.         for (npTmp = *pplHead;
  230.                 npTmp && (npTmp->fpos != FPOS_MAX || npTmp->id < id);
  231.                 npTmp = npTmp->npNext)
  232.             npPrevLabel = npTmp;
  233.     }
  234.     /*
  235.      * At this point, npLabel points to the label to add, either
  236.      * transferred from the deleted list, or allocated fresh.
  237.      * The variable npPrevLabel points to the label to insert
  238.      * after, or is NULL to indicate that the new label should
  239.      * be inserted at the head of the list.
  240.      */
  241.     /*
  242.      * If this is the first label in the list, or if the
  243.      * first label had a greater fpos than the new label,
  244.      * insert the new label at the head of the list.
  245.      */
  246.     if (!npPrevLabel) {
  247.         npLabel->npNext = *pplHead;
  248.         *pplHead = npLabel;
  249.     }
  250.     /*
  251.      * Otherwise, insert it either in the middle of the
  252.      * list or at the end.
  253.      */
  254.     else {
  255.         npLabel->npNext = npPrevLabel->npNext;
  256.         npPrevLabel->npNext = npLabel;
  257.     }
  258.     return npLabel;
  259. }
  260. /************************************************************************
  261. * FindLabel
  262. *
  263. * Tells you if the named label is in the given include label list.
  264. *
  265. * Arguments:
  266. *     LPTSTR pszLabel = The label to find.
  267. *     NPLABEL plHead  = Head of the include list to traverse.
  268. *
  269. * Returns:
  270. *     NULL if the label is not found.
  271. *     Pointer to label structure if the label was found.
  272. *
  273. *
  274. ************************************************************************/
  275. NPLABEL FindLabel(
  276.     LPTSTR pszLabel,
  277.     NPLABEL plHead)
  278. {
  279.     NPLABEL npLabel;
  280.     for (npLabel = plHead; npLabel; npLabel = npLabel->npNext) {
  281.         if (lstrcmp(pszLabel, npLabel->pszLabel) == 0)
  282.             break;
  283.     }
  284.     return npLabel;
  285. }
  286. /************************************************************************
  287. * FindID
  288. *
  289. * Tells you if the named id is in the given include file buffer.
  290. *
  291. * Arguments:
  292. *     INT id         = The id to find.
  293. *     NPLABEL plHead = Head of the label list to use.
  294. *
  295. * Returns:
  296. *     NULL if the id was not found.
  297. *     Pointer to label struct if the id was found.
  298. *
  299. *
  300. ************************************************************************/
  301. NPLABEL FindID(
  302.     INT id,
  303.     NPLABEL plHead)
  304. {
  305.     NPLABEL npLabel;
  306.     for (npLabel = plHead; npLabel; npLabel = npLabel->npNext) {
  307.         if (npLabel->id == id)
  308.             break;
  309.     }
  310.     return npLabel;
  311. }
  312. /************************************************************************
  313. * FindIDInRes
  314. *
  315. * Tells you if the named id is used by any control in the current
  316. * resource list.  This also includes searching through the dialog
  317. * currently being edited, if there is one.
  318. *
  319. * Arguments:
  320. *   INT id = The id to find.
  321. *
  322. * Returns:
  323. *   TRUE if the id was found, or FALSE if it was not.
  324. *
  325. *
  326. ************************************************************************/
  327. BOOL FindIDInRes(
  328.     INT id)
  329. {
  330.     INT cControls;
  331.     PRESLINK prl;
  332.     PRES pRes;
  333.     PDIALOGBOXHEADER pdbh;
  334.     PCONTROLDATA pcd;
  335.     NPCTYPE npc;
  336.     BOOL fFound = FALSE;
  337.     /*
  338.      * Is there a current dialog?  If so, search it first and
  339.      * we will skip any image for it in the resource list (the
  340.      * resource list is probably out of date, anyways).
  341.      */
  342.     if (gfEditingDlg) {
  343.         /*
  344.          * Is the id the same as the current dialog's name?
  345.          */
  346.         if (IsOrd(gcd.pszDlgName) && id == (INT)OrdID(gcd.pszDlgName))
  347.             return TRUE;
  348.         /*
  349.          * Loop through the current controls, looking for an id match.
  350.          */
  351.         for (npc = npcHead; npc; npc = npc->npcNext)
  352.             if (npc->id == id)
  353.                 return TRUE;
  354.     }
  355.     for (prl = gprlHead; prl && !fFound; prl = prl->prlNext) {
  356.         /*
  357.          * Is this a dialog resource and is it NOT the current
  358.          * dialog being edited?  If it is the current dialog,
  359.          * we skip it because it is probably out of date.
  360.          */
  361.         if (prl->fDlgResource && prl != gcd.prl) {
  362.             if (IsOrd(prl->pszName) && id == (INT)OrdID(prl->pszName)) {
  363.                 fFound = TRUE;
  364.             }
  365.             else {
  366.                 pRes = (PRES)GlobalLock(prl->hRes);
  367.                 pdbh = (PDIALOGBOXHEADER)SkipResHeader(pRes);
  368.                 cControls = (INT)pdbh->NumberOfItems;
  369.                 pcd = SkipDialogBoxHeader(pdbh);
  370.                 while (cControls--) {
  371.                     if (id == (INT)pcd->wId) {
  372.                         fFound = TRUE;
  373.                         break;
  374.                     }
  375.                     pcd = SkipControlData(pcd);
  376.                 }
  377.                 GlobalUnlock(prl->hRes);
  378.             }
  379.         }
  380.     }
  381.     return fFound;
  382. }
  383. /************************************************************************
  384. * DeleteLabel
  385. *
  386. * Removes the LABEL with text pszLabel from the list of labels in
  387. * pplHead, closing up the link, and might add it to the deleted list.
  388. *
  389. * If the label is one that exists in the include file (fpos is valid)
  390. * then the label is added to the pplDelHead list in the proper position
  391. * (sorted ascending by fpos).  If the label does not exist in the
  392. * include file, there is no need to track it and it can be tossed.
  393. *
  394. * Arguments:
  395. *     LPTSTR pszLabel     = The text of the label to delete.
  396. *     NPLABEL *pplHead    = Pointer to the head of the include list to use.
  397. *     NPLABEL *pplDelHead = Pointer to the head of the deleted include list.
  398. *
  399. * Side Effects:
  400. *     Deletes from the pplHead list.
  401. *     Can null *pplHead if the last label is deleted.
  402. *     Can add to the pplDelHead list.
  403. *     Can free the memory associated with the LABEL and its string.
  404. *
  405. *
  406. ************************************************************************/
  407. VOID DeleteLabel(
  408.     LPTSTR pszLabel,
  409.     NPLABEL *pplHead,
  410.     NPLABEL *pplDelHead)
  411. {
  412.     NPLABEL npLabel;
  413.     NPLABEL npDelLabel;
  414.     NPLABEL npPrevLabel;
  415.     npPrevLabel = NULL;
  416.     for (npLabel = *pplHead; npLabel; npLabel = npLabel->npNext) {
  417.         if (lstrcmp(pszLabel, npLabel->pszLabel) == 0) {
  418.             /*
  419.              * Close up the linked list where the deleted label was.
  420.              */
  421.             if (npPrevLabel)
  422.                 npPrevLabel->npNext = npLabel->npNext;
  423.             else
  424.                 *pplHead = npLabel->npNext;
  425.             /*
  426.              * Is this a label that is NOT in the include file?
  427.              * If so, just toss it away.
  428.              */
  429.             if (npLabel->fpos == FPOS_MAX) {
  430.                 MyFree(npLabel->pszLabel);
  431.                 MyFree(npLabel);
  432.             }
  433.             /*
  434.              * Otherwise, it must be added to the deleted list.
  435.              */
  436.             else {
  437.                 /*
  438.                  * Search for where the label should be inserted
  439.                  * based on its fpos.
  440.                  */
  441.                 npPrevLabel = NULL;
  442.                 for (npDelLabel = *pplDelHead; npDelLabel;
  443.                         npDelLabel = npDelLabel->npNext) {
  444.                     if (npDelLabel->fpos > npLabel->fpos)
  445.                         break;
  446.                     npPrevLabel = npDelLabel;
  447.                 }
  448.                 /*
  449.                  * If this is the first label in the deleted list, or
  450.                  * if the first label had a greater fpos than the new
  451.                  * label, insert the new label at the head of the list.
  452.                  */
  453.                 if (!npPrevLabel) {
  454.                     npLabel->npNext = *pplDelHead;
  455.                     *pplDelHead = npLabel;
  456.                 }
  457.                 /*
  458.                  * Otherwise, insert it either in the middle of the
  459.                  * list or at the end.
  460.                  */
  461.                 else {
  462.                     npLabel->npNext = npPrevLabel->npNext;
  463.                     npPrevLabel->npNext = npLabel;
  464.                 }
  465.             }
  466.             break;
  467.         }
  468.         npPrevLabel = npLabel;
  469.     }
  470. }
  471. /****************************************************************************
  472. * IsSymbol
  473. *
  474. * This routine returns TRUE if the given string is a valid "C" or "RC"
  475. * identifier.
  476. *
  477. * Valid is:  First char is a letter or '_'.
  478. *
  479. ****************************************************************************/
  480. BOOL IsSymbol(
  481.     LPTSTR pszSym)
  482. {
  483.     register TCHAR ch = *pszSym;
  484.     return ((ch >= CHAR_CAP_A && ch <= CHAR_CAP_Z) ||
  485.             (ch >= CHAR_A && ch <= CHAR_Z) ||
  486.             (ch == CHAR_UNDERLINE));
  487. }
  488. /************************************************************************
  489. * IDToLabel
  490. *
  491. * This function finds the label with the given id.
  492. * The first LABEL in the list with the given id will be found.
  493. * The label will be put in pchLabel.
  494. * If the id was not found then the id is converted to an ascii
  495. * representation and put in pchLabel.  This ascii representation
  496. * will be in hex notation if hex mode is in effect (unless fHexOK
  497. * is FALSE).
  498. *
  499. * This function special cases the IDOK and IDCANCEL id values.
  500. * If there happens to be a label in the include file for these values
  501. * then that label will be returned, but if not, either "IDOK" or
  502. * "IDCANCEL" will be returned.
  503. *
  504. * Arguments:
  505. *   LPTSTR pchLabel - Where to put the label.
  506. *   INT id          - The id of the label to find or match.
  507. *   BOOL fHexOK     - TRUE if hex representations of the id are allowed.
  508. *
  509. *
  510. ************************************************************************/
  511. VOID IDToLabel(
  512.     LPTSTR pchLabel,
  513.     INT id,
  514.     BOOL fHexOK)
  515. {
  516.     NPLABEL npLabel;
  517.     npLabel = FindID(id, plInclude);
  518.     if (npLabel) {
  519.         lstrcpy(pchLabel, npLabel->pszLabel);
  520.     }
  521.     else {
  522.         if (id == IDOK && !FindLabel(ids(IDS_IDOK), plInclude)) {
  523.             lstrcpy(pchLabel, ids(IDS_IDOK));
  524.         }
  525.         else if (id == IDCANCEL && !FindLabel(ids(IDS_IDCANCEL), plInclude)) {
  526.             lstrcpy(pchLabel, ids(IDS_IDCANCEL));
  527.         }
  528.         else {
  529.             if (fHexOK)
  530.                 Myitoa(id, pchLabel);
  531.             else
  532.                 itoaw(id, pchLabel, 10);
  533.         }
  534.     }
  535. }
  536. /************************************************************************
  537. * LabelToID
  538. *
  539. * This function converts a label string to its associated id value.
  540. * It first checks the labels in the current include file for a
  541. * match.  If it is not found, it then checks for some special values,
  542. * like "IDOK", "IDCANCEL" and "(Unused)".
  543. *
  544. * The return value will be TRUE of the label (symbol) was found, or
  545. * FALSE if it was not.
  546. *
  547. * Arguments:
  548. *   LPTSTR pszLabel - The symbol to search for.
  549. *   PINT pID        - Where to return the associated id, if found.
  550. *
  551. ************************************************************************/
  552. BOOL LabelToID(
  553.     LPTSTR pszLabel,
  554.     PINT pID)
  555. {
  556.     INT id;
  557.     NPLABEL npLabel;
  558.     /*
  559.      * Is it an existing label?
  560.      */
  561.     if (npLabel = FindLabel(pszLabel, plInclude)) {
  562.         id = npLabel->id;
  563.     }
  564.     /*
  565.      * Is it the "unused" symbol?
  566.      */
  567.     else if (lstrcmp(pszLabel, ids(IDS_UNUSED)) == 0) {
  568.         id = IDUNUSED;
  569.     }
  570.     /*
  571.      * How about the special IDOK entry?
  572.      */
  573.     else if (lstrcmp(pszLabel, ids(IDS_IDOK)) == 0) {
  574.         id = IDOK;
  575.     }
  576.     /*
  577.      * How about the special IDCANCEL entry?
  578.      */
  579.     else if (lstrcmp(pszLabel, ids(IDS_IDCANCEL)) == 0) {
  580.         id = IDCANCEL;
  581.     }
  582.     else {
  583.         return FALSE;
  584.     }
  585.     *pID = id;
  586.     return TRUE;
  587. }
  588. /****************************************************************************
  589. * FreeLabels
  590. *
  591. * This function frees the labels in the label list pointed to by
  592. * nppLabels, including the strings.  When it is done, the label
  593. * list head is set to NULL.
  594. *
  595. ****************************************************************************/
  596. VOID FreeLabels(
  597.     NPLABEL *nppLabels)
  598. {
  599.     register NPLABEL npl;
  600.     register NPLABEL nplTemp;
  601.     npl = *nppLabels;
  602.     while (npl) {
  603.         MyFree(npl->pszLabel);
  604.         nplTemp = npl->npNext;
  605.         MyFree(npl);
  606.         npl = nplTemp;
  607.     }
  608.     *nppLabels = NULL;
  609. }