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