|
|
1.1 root 1:
2: /******************************************************************************\
3: * This is a part of the Microsoft Source Code Samples.
4: * Copyright (C) 1993 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:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.