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

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: LIST.C
  12. *
  13. *
  14. * Functions:
  15. *
  16. * Alloc()
  17. * Free()
  18. * List_Init()
  19. * List_Dump()
  20. * List_Show()
  21. * List_Create()
  22. * List_Destroy()
  23. * List_AddFirst()
  24. * List_NewFirst()
  25. * List_DeleteFirst()
  26. * List_AddLast()
  27. * List_NewLast()
  28. * LIst_DeleteLast()
  29. * List_AddAfter()
  30. * List_NewAfter()
  31. * List_AddBefore()
  32. * List_NewBefore()
  33. * List_Delete()
  34. * List_DeleteForwards()
  35. * List_DeleteBackwards()
  36. * List_ItemLength()
  37. * List_First()
  38. * List_Last()
  39. * List_Next()
  40. * List_Prev()
  41. * List_Clear()
  42. * List_IsEmpty()
  43. * SwitchLists()
  44. * List_Join()
  45. * List_InsertListAfter()
  46. * List_InsertListBefore()
  47. * List_SplitAfter()
  48. * List_SplitBefore()
  49. * List_Card()
  50. * List_IsOK()
  51. * LIst_MakeOK()
  52. * List_Check()
  53. * List_Recover()
  54. *
  55. * Comments:
  56. *
  57. *
  58. ****************************************************************************/
  59. #include <memory.h>
  60. #include <windows.h>
  61. #include "gutils.h"
  62. #include "list.h"
  63. #include "gutilsrc.h"
  64. #define memcpy  memcpy
  65. char msg[80];  /* a temp for building up wsprintf messages in */
  66. #define BLOCKSIZE 25000
  67.  typedef struct
  68.  { HANDLE hMem;     /* memory handle for this block */
  69.    int iInUse;    /* number of allocations taken out of it.  0 => free it */
  70.    int iNext;     /* next byte to use */
  71.    char chData[BLOCKSIZE];
  72.  } BLOCK, FAR *PBLOCK;
  73. static CRITICAL_SECTION CritSec;  /* to protect pCurrent */
  74. #define List_Enter_Crit(x)      EnterCriticalSection(x)
  75. #define List_Leave_Crit(x)      LeaveCriticalSection(x)
  76. static PBLOCK pCurrent = NULL;  /* block currently in use */
  77.                           /* must always be either NULL or valid */
  78.  /* Allocate storage for List elements.  n.b. after a call to this
  79.     you MUST record the value of pCurrent as you need to hand that in
  80.     to Free.  You don't hand in the value of the actual storage.
  81.     See screed above.
  82.     This function Enters the critical section.  The caller must Leave it.
  83.  */
  84. static LPVOID Alloc(int size)
  85.  { HANDLE hMem;
  86.    LPVOID pRet;
  87.    List_Enter_Crit(&CritSec);
  88.    if ((pCurrent==NULL)||(pCurrent->iNext+size>BLOCKSIZE+1))
  89.    { hMem = GlobalAlloc(GMEM_MOVEABLE|GMEM_SHARE,(DWORD)(sizeof(BLOCK)));
  90.      if (hMem==NULL)
  91.        { pCurrent = NULL;
  92.          OutputDebugString("GlobalAlloc failed!!n");
  93.          return NULL;
  94.        }
  95.      pCurrent = (PBLOCK)GlobalLock(hMem);
  96.      if (pCurrent==NULL)
  97.        { OutputDebugString("GlobalLock failed!!n");
  98.          return NULL;
  99.        }
  100.      pCurrent->hMem = hMem;
  101.      pCurrent->iInUse = 0;
  102.      pCurrent->iNext = 0;
  103.    }
  104.    pRet = &(pCurrent->chData[pCurrent->iNext]);
  105.    ++(pCurrent->iInUse);
  106.    pCurrent->iNext += size;
  107.    /* for MIPS we must also ensure that the data is aligned 4 byte*/
  108.    pCurrent->iNext += 3;
  109.    pCurrent->iNext -= pCurrent->iNext % 4;
  110.    return pRet;
  111.  } /* Alloc */
  112. static void Free(PBLOCK pBlock, LPVOID p)
  113.  { HANDLE hMem;
  114.    List_Enter_Crit(&CritSec);
  115.     --pBlock->iInUse;
  116.    if (pBlock->iInUse<=0)
  117.    { if (pBlock->iInUse<0)
  118.      { 
  119.         extern HANDLE hLibInst;
  120.         TCHAR szBuf[512];
  121.         LoadString(hLibInst, IDS_LIST_ALLOC_NEGATIVE, szBuf, sizeof(szBuf));
  122.  
  123.         wsprintf(msg, szBuf, pBlock->iInUse);
  124.         MessageBox(NULL, msg, NULL, MB_OK | MB_ICONSTOP);
  125.       }
  126.  
  127.      hMem = pBlock->hMem;
  128.      GlobalUnlock(hMem);
  129.      GlobalFree(hMem);
  130.      if (pCurrent==pBlock) pCurrent = NULL; /* defend the invariant */
  131.    }
  132.    List_Leave_Crit(&CritSec);
  133.  } /* Free */
  134.   /* The following definition tells the truth about what an ITEM is.  The
  135.   |  header file says only that there's a structure with the tag item_tag and
  136.   |  that a LIST is a pointer to one.  Here we spell out what that structure
  137.   |  is (and a LIST is still a pointer to one).  A PLIST is defined as a
  138.   |  pointer to one of those, but is only really used because the C
  139.   |  parameter mechanism demands an extra level of indirection for a
  140.   |  parameter that can be updated.  (Modula-2 VAR parameter).
  141.   */
  142.   typedef struct item_tag
  143.   { struct item_tag FAR *pitNext;    /* to next in circular list */
  144.     struct item_tag FAR *pitPrev;    /* to prev in circular list */
  145.     PBLOCK pBlock;               /* to memory block */
  146.     BOOL bAnchor;                /* TRUE iff an anchor block */
  147.     BOOL bOK;                    /* true unless a list op has failed */
  148.     int iLen;                    /* length of data only */
  149.     char Data[1];                /* the caller's data.  The '1' is a lie */
  150.   } ITEM;
  151.   /* For an anchor block, only the fields pitNext thru bAnchor are allocated.
  152.   |  For a normal list element, Data may well be longer than 1 byte.
  153.   |  The bOK flag is to support a style of programming where several
  154.   |  successive operations can be done without having to check the return
  155.   |  code at each stage.  At the end, the list can be examined to see if
  156.   |  the data in it is valid or if it has been made invalid by the failure
  157.   |  of any of the previous operations.  Certain operations may result in
  158.   |  having no list at all if they fail (e.g. create) and for these, you'd
  159.   |  better check the result at once!
  160.   |  ??? Some of this screed belongs in the header!!!
  161.   */
  162.   static int iAnchorSize;      /* Size of anchor block (no data, no dummy) */
  163.   static int iHeaderSize;      /* Size of data block not counting Data
  164.                                   and offset from cursor back to item.
  165.                                */
  166.   static BOOL bInited = FALSE; /* TRUE <=> iAnchorSize and iHeaderSize are OK*/
  167. #define MOVEBACK(Curs)                                               
  168.    { Curs = ((char FAR *)Curs-iHeaderSize); } /*move from Data to pitNext*/
  169.   /*==================================================================
  170.   || Lists are circular, doubly linked with an anchor block which holds
  171.   || pointers to both ends.  Every block has a flag which shows whether
  172.   || it's an anchor or not.
  173.   ||
  174.   || Empty list:
  175.   ||
  176.   ||      -------------
  177.   ||     |             |
  178.   ||     |   Anchor    |
  179.   ||     v   -------   |
  180.   ||  Ul--->| Next--+--|
  181.   ||        |-------|  |
  182.   ||        | Prev--+--
  183.   ||         -------
  184.   ||
  185.   || One entry list:
  186.   ||
  187.   ||      ------------------------------------
  188.   ||     |                                    |
  189.   ||     |   Anchor                           |
  190.   ||     v   -------                ------    |
  191.   ||  Ul--->| Next--+------------->| Next-+---|
  192.   ||        |-------|    |         |------|   |
  193.   ||        | Prev--+----          | Prev-+---
  194.   ||         -------               |------|
  195.   ||                               | Len  |
  196.   ||                               |------|
  197.   ||                               | Data |
  198.   ||                                ------
  199.   || Two entry list:
  200.   ||
  201.   ||      -------------------------------------------------
  202.   ||     | ---------------    ---------------              |
  203.   ||     ||               |  |               |             |
  204.   ||     ||  Anchor       |  |               |             |
  205.   ||     vv  --------     |  v    ------     |    ------   |
  206.   ||  Ul--->| Next--+-----+----->| Next-+----+-->| Next-+--
  207.   ||        |-------|     |      |------|  | |   |------|
  208.   ||        | Prev--+--    ------+-Prev |  |  ---+-Prev |
  209.   ||         -------   |         |------|  |     |------|
  210.   ||                   |         | Len  |  |     | Len  |
  211.   ||                   |         |------|  |     |------|<----Cursor
  212.   ||                   |         | Data |  |     | Data |
  213.   ||                   |          ------   |      ------
  214.   ||                   |                   |
  215.   ||                    -------------------
  216.   ||
  217.   || etc.
  218.   ||
  219.   || Note that an external cursor (i.e one which is seen by the caller)
  220.   || points to the Data field, not to the start of the structure.
  221.   || This allows easy access to the data by the user at the cost of a
  222.   || slightly slower traverse.
  223.   || Within this module, we may sometimes traverse a list with  a cursor
  224.   || that points to the start of an item.  This is called an item cursor.
  225.