Subversion Repositories f9daq

Rev

Rev 16 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | RSS feed

  1. //-------------------------------------------------------------------------------------------
  2. // klist.c - parts to maintain a doubly linked list (org microsoft)
  3. //
  4. // Please announce changes and hints to ARW Elektronik
  5. //
  6. //
  7. // $Log: Klist.c,v $
  8. // Revision 1.2  2004/07/24 07:47:46  klaus
  9. // revised, removed wrong license terms
  10. //
  11. // Revision 1.1.1.1  2003/11/14 23:17:18  klaus
  12. // First put into repository
  13. //
  14. // Revision 1.2  2002/10/27 17:05:33  klaus
  15. // CVS log added, file addressing bug > 2 Gbtye circumvent
  16. //
  17. // what                                                              who    when
  18. // first steps                                                       AR     07.11.1999
  19. //
  20.  
  21. //-------------------------------------------------------------------------------------------
  22. // INCLUDES
  23. //
  24. #include <memory.h>
  25. #include <windows.h>
  26. #include <Klist.h>
  27.  
  28. //-------------------------------------------------------------------------------------------
  29. // DEFINES
  30. //
  31. #define memcpy  memcpy
  32. #define BLOCKSIZE 0x4000
  33.  
  34. //-------------------------------------------------------------------------------------------
  35. // TYPEDEFS
  36. //
  37. typedef struct
  38. {
  39.         HANDLE hMem;   // memory handle for this block  
  40.         int iInUse;    // number of allocations taken out of it.  0 => free it  
  41.         int iNext;     // next byte to use  
  42.         char chData[BLOCKSIZE];
  43. } BLOCK, FAR *PBLOCK;
  44.  
  45. /* The following definition tells the truth about what an ITEM is.  The
  46. |  header file says only that there's a structure with the tag item_tag and
  47. |  that a LIST is a pointer to one.  Here we spell out what that structure
  48. |  is (and a LIST is still a pointer to one).  A PLIST is defined as a
  49. |  pointer to one of those, but is only really used because the C
  50. |  parameter mechanism demands an extra level of indirection for a
  51. |  parameter that can be updated.  (Modula-2 VAR parameter).
  52. */
  53. typedef struct item_tag
  54. {
  55.         struct item_tag FAR *pitNext;    /* to next in circular list */
  56.     struct item_tag FAR *pitPrev;    /* to prev in circular list */
  57.     PBLOCK pBlock;               /* to memory block */
  58.     BOOL bAnchor;                /* TRUE iff an anchor block */
  59.     BOOL bOK;                    /* true unless a list op has failed */
  60.     int iLen;                    /* length of data only */
  61.     char Data[1];                /* the caller's data.  The '1' is a lie */
  62. } ITEM;
  63.  
  64. /* For an anchor block, only the fields pitNext thru bAnchor are allocated.
  65. |  For a normal list element, Data may well be longer than 1 byte.
  66. |  The bOK flag is to support a style of programming where several
  67. |  successive operations can be done without having to check the return
  68. |  code at each stage.  At the end, the list can be examined to see if
  69. |  the data in it is valid or if it has been made invalid by the failure
  70. |  of any of the previous operations.  Certain operations may result in
  71. |  having no list at all if they fail (e.g. create) and for these, you'd
  72. |  better check the result at once!
  73. |  ??? Some of this screed belongs in the header!!!
  74. */
  75.  
  76. //-------------------------------------------------------------------------------------------
  77. // LOCALS
  78. //
  79. static CRITICAL_SECTION CritSec;  /* to protect pCurrent */
  80.  
  81. #define List_Enter_Crit(x)      EnterCriticalSection(x)
  82. #define List_Leave_Crit(x)      LeaveCriticalSection(x)
  83.  
  84. static PBLOCK pCurrent = NULL;  // block currently in use  
  85.                           // must always be either NULL or valid  
  86.  
  87. static int iAnchorSize;      /* Size of anchor block (no data, no dummy) */
  88. static int iHeaderSize;      /* Size of data block not counting Data
  89.                               and offset from cursor back to item.       */
  90. static BOOL bInited = FALSE; /* TRUE <=> iAnchorSize and iHeaderSize are OK*/
  91.  
  92. #define MOVEBACK(Curs)                                               \
  93.    { Curs = ((char FAR *)Curs-iHeaderSize); } /*move from Data to pitNext*/
  94.  
  95. //-------------------------------------------------------------------------------------------
  96. // EXTERNALS
  97. //
  98.  
  99. //-------------------------------------------------------------------------------------------
  100. // GLOBALS
  101. //
  102.  
  103. //-------------------------------------------------------------------------------------------
  104. // FUNCTIONS
  105. //
  106.  
  107. /* Allocate storage for List elements.  n.b. after a call to this
  108.    you MUST record the value of pCurrent as you need to hand that in
  109.    to Free.  You don't hand in the value of the actual storage.
  110.    See screed above.
  111.    This function Enters the critical section.  The caller must Leave it.
  112. */
  113. static LPVOID Alloc(int size)
  114. {
  115.         HANDLE hMem;
  116.         LPVOID pRet;
  117.         List_Enter_Crit(&CritSec);
  118.         if ((pCurrent==NULL)||(pCurrent->iNext+size>BLOCKSIZE+1))
  119.         {
  120.                 hMem = GlobalAlloc(GMEM_MOVEABLE|GMEM_SHARE,(DWORD)(sizeof(BLOCK)));
  121.                 if (hMem==NULL)
  122.                 {
  123.                         pCurrent = NULL;
  124.                         OutputDebugString("GlobalAlloc failed!!\n");
  125.                         return NULL;
  126.                 }
  127.                 pCurrent = (PBLOCK)GlobalLock(hMem);
  128.                 if (pCurrent==NULL)
  129.                 {
  130.                         OutputDebugString("GlobalLock failed!!\n");
  131.                         return NULL;
  132.                 }
  133.                 pCurrent->hMem = hMem;
  134.                 pCurrent->iInUse = 0;
  135.                 pCurrent->iNext = 0;
  136.         }
  137.         pRet = &(pCurrent->chData[pCurrent->iNext]);
  138.         ++(pCurrent->iInUse);
  139.         pCurrent->iNext += size;
  140.  
  141.         // ensure that the data is aligned 4 byte
  142.         pCurrent->iNext += 3;
  143.         pCurrent->iNext -= pCurrent->iNext % 4;
  144.  
  145.         return pRet;
  146. }
  147.  
  148. static void Free(PBLOCK pBlock, LPVOID p)
  149. {
  150.         HANDLE hMem;
  151.         List_Enter_Crit(&CritSec);
  152.     --pBlock->iInUse;
  153.         if (pBlock->iInUse<=0)
  154.         {
  155.                 if (pBlock->iInUse<0)
  156.                 {
  157.                         // don't know what to do with it
  158.                 }
  159.  
  160.                 hMem = pBlock->hMem;
  161.                 GlobalUnlock(hMem);
  162.                 GlobalFree(hMem);
  163.                 if (pCurrent==pBlock) pCurrent = NULL; /* defend the invariant */
  164.         }
  165.         List_Leave_Crit(&CritSec);
  166. }
  167.  
  168.   /*==================================================================
  169.   || Lists are circular, doubly linked with an anchor block which holds
  170.   || pointers to both ends.  Every block has a flag which shows whether
  171.   || it's an anchor or not.
  172.   ||
  173.   || Empty list:
  174.   ||
  175.   ||      -------------
  176.   ||     |             |
  177.   ||     |   Anchor    |
  178.   ||     v   -------   |
  179.   ||  Ul--->| Next--+--|
  180.   ||        |-------|  |
  181.   ||        | Prev--+--
  182.   ||         -------
  183.   ||
  184.   || One entry list:
  185.   ||
  186.   ||      ------------------------------------
  187.   ||     |                                    |
  188.   ||     |   Anchor                           |
  189.   ||     v   -------                ------    |
  190.   ||  Ul--->| Next--+------------->| Next-+---|
  191.   ||        |-------|    |         |------|   |
  192.   ||        | Prev--+----          | Prev-+---
  193.   ||         -------               |------|
  194.   ||                               | Len  |
  195.   ||                               |------|
  196.   ||                               | Data |
  197.   ||                                ------
  198.   || Two entry list:
  199.   ||
  200.   ||      -------------------------------------------------
  201.   ||     | ---------------    ---------------              |
  202.   ||     ||               |  |               |             |
  203.   ||     ||  Anchor       |  |               |             |
  204.   ||     vv  --------     |  v    ------     |    ------   |
  205.   ||  Ul--->| Next--+-----+----->| Next-+----+-->| Next-+--
  206.   ||        |-------|     |      |------|  | |   |------|
  207.   ||        | Prev--+--    ------+-Prev |  |  ---+-Prev |
  208.   ||         -------   |         |------|  |     |------|
  209.   ||                   |         | Len  |  |     | Len  |
  210.   ||                   |         |------|  |     |------|<----Cursor
  211.   ||                   |         | Data |  |     | Data |
  212.   ||                   |          ------   |      ------
  213.   ||                   |                   |
  214.   ||                    -------------------
  215.   ||
  216.   || etc.
  217.   ||
  218.   || Note that an external cursor (i.e one which is seen by the caller)
  219.   || points to the Data field, not to the start of the structure.
  220.   || This allows easy access to the data by the user at the cost of a
  221.   || slightly slower traverse.
  222.   || Within this module, we may sometimes traverse a list with  a cursor
  223.   || that points to the start of an item.  This is called an item cursor.
  224.   È===================================================================*/
  225.  
  226.   /*------------------------------------------------------------------
  227.   | Set iAnchorSize and iHeaderSize.  Implementation independent!
  228.    -------------------------------------------------------------------*/
  229. void APIENTRY List_Init(void)
  230. {  
  231.         LIST P;
  232.  
  233.     P = (LIST)&P;                  /* really any old address will do */
  234.     iAnchorSize = (char FAR *)&(P->iLen) - (char FAR *)&(P->pitNext);
  235.     iHeaderSize = (char FAR *)&(P->Data) - (char FAR *)&(P->pitNext);
  236.     InitializeCriticalSection(&CritSec);
  237.     /* assumes layout in storage is linear */
  238. }
  239.  
  240.   /*------------------------------------------------------------------
  241.   | Create a list.  It will be initially empty
  242.    -------------------------------------------------------------------*/
  243. LIST APIENTRY List_Create(void)
  244. {  
  245.         LIST lst;
  246.  
  247.     if (!bInited) {List_Init(); }          /* prevent some silly errors */
  248.     lst = Alloc(iAnchorSize);
  249.     if (lst==NULL) { return NULL; }
  250.     lst->pBlock = pCurrent;
  251.     List_Leave_Crit(&CritSec);
  252.     lst->bOK = TRUE;
  253.     lst->pitNext = lst;
  254.     lst->pitPrev = lst;
  255.     lst->bAnchor = TRUE;
  256.     /* no length field set in an anchor block */
  257.     return lst;
  258. }
  259.  
  260.   /*------------------------------------------------------------------
  261.   | Destroy *plst.  It does not need to be empty first
  262.    -------------------------------------------------------------------*/
  263. void APIENTRY List_Destroy(PLIST plst)
  264. {  
  265.         LIST pitP;    /* item cursor on * plst */
  266.     LIST pitQ;    /* item cursor runs one step ahead of pitQ */
  267.  
  268.     if (plst==NULL)
  269.        return;
  270.     /* There is at least an anchor block to destroy */
  271.     pitP = *plst;
  272.     do
  273.     {  
  274.                 pitQ = pitP->pitNext;
  275.         Free(pitP->pBlock, pitP);
  276.         pitP = pitQ;
  277.     }while(pitP != *plst);
  278.     *plst = NULL;
  279. }
  280.  
  281.    /*------------------------------------------------------------------
  282.   | Return the address of the place for Len bytes of data in a new
  283.   | item at the start of lst
  284.    -------------------------------------------------------------------*/
  285. LPVOID APIENTRY List_NewFirst(LIST lst, UINT uLen)
  286. {  
  287.         LIST pit;
  288.  
  289.     if (lst==NULL)
  290.        return NULL;
  291.     pit = Alloc(iHeaderSize+uLen);
  292.     if (pit==NULL) { lst->bOK = FALSE; return NULL; }
  293.     pit->pBlock = pCurrent;
  294.     List_Leave_Crit(&CritSec);
  295.     pit->iLen = uLen;
  296.     pit->pitPrev = lst;
  297.     pit->pitNext = lst->pitNext;
  298.     lst->pitNext->pitPrev = pit; /* for empty list that set lst->pitPrev */
  299.     lst->pitNext = pit;
  300.     pit->bAnchor = FALSE;
  301.     return (char FAR *)&(pit->Data);
  302. }
  303.  
  304.  
  305.   /*------------------------------------------------------------------
  306.   | Delete the item that Curs identifies.
  307.   | This will be only a few (maybe as little as 3) machine instructions
  308.   | quicker than DeleteForwards or DeleteBackwards but leaves Curs dangling.
  309.   | It is therefore NOT usually to be preferred.
  310.   | It may be useful when you have a function which returns an LPVOID
  311.   | since the argument does not need to be a variable.
  312.   |     Trivial example: List_Delete(List_First(L));
  313.    -------------------------------------------------------------------*/
  314. void APIENTRY List_Delete(LPVOID Curs)
  315. {  
  316.         LIST pit;
  317.  
  318.     if(Curs==NULL)
  319.        return;
  320.     MOVEBACK(Curs)
  321.     pit = (LIST)Curs;
  322.     pit->pitNext->pitPrev = pit->pitPrev;
  323.     pit->pitPrev->pitNext = pit->pitNext;
  324.     Free(pit->pBlock, pit);
  325. }
  326.  
  327.  
  328.   /*---------------------------------------------------------------------
  329.   | Return TRUE if and only if lst is empty
  330.    ----------------------------------------------------------------------*/
  331. BOOL APIENTRY List_IsEmpty(LIST lst)
  332. {  
  333.         if (lst==NULL)
  334.        return TRUE;   /* well it's sort of true isn't it? */
  335.     return lst->pitNext ==lst;
  336. }
  337.  
  338.