Annotation of mstools/samples/sdktools/windiff/list.c, revision 1.1.1.1

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: LIST.C
                     14: *
                     15: *
                     16: * Functions:
                     17: *
                     18: * Alloc()
                     19: * Free()
                     20: * List_Init()
                     21: * List_Dump()
                     22: * List_Show()
                     23: * List_Create()
                     24: * List_Destroy()
                     25: * List_AddFirst()
                     26: * List_NewFirst()
                     27: * List_DeleteFirst()
                     28: * List_AddLast()
                     29: * List_NewLast()
                     30: * LIst_DeleteLast()
                     31: * List_AddAfter()
                     32: * List_NewAfter()
                     33: * List_AddBefore()
                     34: * List_NewBefore()
                     35: * List_Delete()
                     36: * List_DeleteForwards()
                     37: * List_DeleteBackwards()
                     38: * List_ItemLength()
                     39: * List_First()
                     40: * List_Last()
                     41: * List_Next()
                     42: * List_Prev()
                     43: * List_Clear()
                     44: * List_IsEmpty()
                     45: * SwitchLists()
                     46: * List_Join()
                     47: * List_InsertListAfter()
                     48: * List_InsertListBefore()
                     49: * List_SplitAfter()
                     50: * List_SplitBefore()
                     51: * List_Card()
                     52: * List_IsOK()
                     53: * LIst_MakeOK()
                     54: * List_Check()
                     55: * List_Recover()
                     56: *
                     57: * Comments:
                     58: *
                     59: *
                     60: ****************************************************************************/
                     61: 
                     62: #include <memory.h>
                     63: #include <windows.h>
                     64: 
                     65: #include "gutils.h"
                     66: #include "list.h"
                     67: 
                     68: #define memcpy  memcpy
                     69: 
                     70: char msg[80];  /* a temp for building up wsprintf messages in */
                     71: 
                     72: #define BLOCKSIZE 25000
                     73:  typedef struct
                     74:  { HANDLE hMem;     /* memory handle for this block */
                     75:    int iInUse;    /* number of allocations taken out of it.  0 => free it */
                     76:    int iNext;     /* next byte to use */
                     77:    char chData[BLOCKSIZE];
                     78:  } BLOCK, FAR *PBLOCK;
                     79: 
                     80: static CRITICAL_SECTION CritSec;  /* to protect pCurrent */
                     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:  /* Allocate storage for List elements.  n.b. after a call to this
                     88:     you MUST record the value of pCurrent as you need to hand that in
                     89:     to Free.  You don't hand in the value of the actual storage.
                     90:     See screed above.
                     91:     This function Enters the critical section.  The caller must Leave it.
                     92:  */
                     93: static LPVOID Alloc(int size)
                     94:  { HANDLE hMem;
                     95:    LPVOID pRet;
                     96:    List_Enter_Crit(&CritSec);
                     97:    if ((pCurrent==NULL)||(pCurrent->iNext+size>BLOCKSIZE+1))
                     98:    { hMem = GlobalAlloc(GMEM_MOVEABLE|GMEM_SHARE,(DWORD)(sizeof(BLOCK)));
                     99:      if (hMem==NULL)
                    100:        { pCurrent = NULL;
                    101:          OutputDebugString("GlobalAlloc failed!!\n");
                    102:          return NULL;
                    103:        }
                    104:      pCurrent = (PBLOCK)GlobalLock(hMem);
                    105:      if (pCurrent==NULL)
                    106:        { OutputDebugString("GlobalLock failed!!\n");
                    107:          return NULL;
                    108:        }
                    109:      pCurrent->hMem = hMem;
                    110:      pCurrent->iInUse = 0;
                    111:      pCurrent->iNext = 0;
                    112:    }
                    113:    pRet = &(pCurrent->chData[pCurrent->iNext]);
                    114:    ++(pCurrent->iInUse);
                    115:    pCurrent->iNext += size;
                    116: 
                    117:    /* for MIPS we must also ensure that the data is aligned 4 byte*/
                    118:    pCurrent->iNext += 3;
                    119:    pCurrent->iNext -= pCurrent->iNext % 4;
                    120: 
                    121:    return pRet;
                    122:  } /* Alloc */
                    123: 
                    124: static void Free(PBLOCK pBlock, LPVOID p)
                    125:  { HANDLE hMem;
                    126:    List_Enter_Crit(&CritSec);
                    127:     --pBlock->iInUse;
                    128:    if (pBlock->iInUse<=0)
                    129:    { if (pBlock->iInUse<0)
                    130:      { wsprintf(msg,"Problem in List code.\nList block allocation negative (%d)", pBlock->iInUse);
                    131:        MessageBox(NULL, msg, "Error", MB_OK | MB_ICONSTOP);
                    132:      }
                    133:      hMem = pBlock->hMem;
                    134:      GlobalUnlock(hMem);
                    135:      GlobalFree(hMem);
                    136:      if (pCurrent==pBlock) pCurrent = NULL; /* defend the invariant */
                    137:    }
                    138:    List_Leave_Crit(&CritSec);
                    139:  } /* Free */
                    140: 
                    141:   /* The following definition tells the truth about what an ITEM is.  The
                    142:   |  header file says only that there's a structure with the tag item_tag and
                    143:   |  that a LIST is a pointer to one.  Here we spell out what that structure
                    144:   |  is (and a LIST is still a pointer to one).  A PLIST is defined as a
                    145:   |  pointer to one of those, but is only really used because the C
                    146:   |  parameter mechanism demands an extra level of indirection for a
                    147:   |  parameter that can be updated.  (Modula-2 VAR parameter).
                    148:   */
                    149:   typedef struct item_tag
                    150:   { struct item_tag FAR *pitNext;    /* to next in circular list */
                    151:     struct item_tag FAR *pitPrev;    /* to prev in circular list */
                    152:     PBLOCK pBlock;               /* to memory block */
                    153:     BOOL bAnchor;                /* TRUE iff an anchor block */
                    154:     BOOL bOK;                    /* true unless a list op has failed */
                    155:     int iLen;                    /* length of data only */
                    156:     char Data[1];                /* the caller's data.  The '1' is a lie */
                    157:   } ITEM;
                    158: 
                    159:   /* For an anchor block, only the fields pitNext thru bAnchor are allocated.
                    160:   |  For a normal list element, Data may well be longer than 1 byte.
                    161:   |  The bOK flag is to support a style of programming where several
                    162:   |  successive operations can be done without having to check the return
                    163:   |  code at each stage.  At the end, the list can be examined to see if
                    164:   |  the data in it is valid or if it has been made invalid by the failure
                    165:   |  of any of the previous operations.  Certain operations may result in
                    166:   |  having no list at all if they fail (e.g. create) and for these, you'd
                    167:   |  better check the result at once!
                    168:   |  ??? Some of this screed belongs in the header!!!
                    169:   */
                    170: 
                    171:   static int iAnchorSize;      /* Size of anchor block (no data, no dummy) */
                    172:   static int iHeaderSize;      /* Size of data block not counting Data
                    173:                                   and offset from cursor back to item.
                    174:                                */
                    175:   static BOOL bInited = FALSE; /* TRUE <=> iAnchorSize and iHeaderSize are OK*/
                    176: 
                    177: #define MOVEBACK(Curs)                                               \
                    178:    { Curs = ((char FAR *)Curs-iHeaderSize); } /*move from Data to pitNext*/
                    179: 
                    180:   /*==================================================================
                    181:   || Lists are circular, doubly linked with an anchor block which holds
                    182:   || pointers to both ends.  Every block has a flag which shows whether
                    183:   || it's an anchor or not.
                    184:   ||
                    185:   || Empty list:
                    186:   ||
                    187:   ||      -------------
                    188:   ||     |             |
                    189:   ||     |   Anchor    |
                    190:   ||     v   -------   |
                    191:   ||  Ul--->| Next--+--|
                    192:   ||        |-------|  |
                    193:   ||        | Prev--+--
                    194:   ||         -------
                    195:   ||
                    196:   || One entry list:
                    197:   ||
                    198:   ||      ------------------------------------
                    199:   ||     |                                    |
                    200:   ||     |   Anchor                           |
                    201:   ||     v   -------                ------    |
                    202:   ||  Ul--->| Next--+------------->| Next-+---|
                    203:   ||        |-------|    |         |------|   |
                    204:   ||        | Prev--+----          | Prev-+---
                    205:   ||         -------               |------|
                    206:   ||                               | Len  |
                    207:   ||                               |------|
                    208:   ||                               | Data |
                    209:   ||                                ------
                    210:   || Two entry list:
                    211:   ||
                    212:   ||      -------------------------------------------------
                    213:   ||     | ---------------    ---------------              |
                    214:   ||     ||               |  |               |             |
                    215:   ||     ||  Anchor       |  |               |             |
                    216:   ||     vv  --------     |  v    ------     |    ------   |
                    217:   ||  Ul--->| Next--+-----+----->| Next-+----+-->| Next-+--
                    218:   ||        |-------|     |      |------|  | |   |------|
                    219:   ||        | Prev--+--    ------+-Prev |  |  ---+-Prev |
                    220:   ||         -------   |         |------|  |     |------|
                    221:   ||                   |         | Len  |  |     | Len  |
                    222:   ||                   |         |------|  |     |------|<----Cursor
                    223:   ||                   |         | Data |  |     | Data |
                    224:   ||                   |          ------   |      ------
                    225:   ||                   |                   |
                    226:   ||                    -------------------
                    227:   ||
                    228:   || etc.
                    229:   ||
                    230:   || Note that an external cursor (i.e one which is seen by the caller)
                    231:   || points to the Data field, not to the start of the structure.
                    232:   || This allows easy access to the data by the user at the cost of a
                    233:   || slightly slower traverse.
                    234:   || Within this module, we may sometimes traverse a list with  a cursor
                    235:   || that points to the start of an item.  This is called an item cursor.
                    236:   �===================================================================*/
                    237: 
                    238:   /*------------------------------------------------------------------
                    239:   | Set iAnchorSize and iHeaderSize.  Implementation independent!
                    240:    -------------------------------------------------------------------*/
                    241: void APIENTRY List_Init(void)
                    242:   {  LIST P;
                    243:      P = (LIST)&P;                  /* really any old address will do */
                    244:      iAnchorSize = (char FAR *)&(P->iLen) - (char FAR *)&(P->pitNext);
                    245:      iHeaderSize = (char FAR *)&(P->Data) - (char FAR *)&(P->pitNext);
                    246:      InitializeCriticalSection(&CritSec);
                    247:      /* assumes layout in storage is linear */
                    248:   }
                    249: 
                    250:   /* Dump the internals to the debugger. */
                    251: void APIENTRY List_Dump(LPSTR Header, LIST lst)
                    252:   {  LIST pit;
                    253:      char msg[250];
                    254: 
                    255:      OutputDebugString(Header);  OutputDebugString("\n");
                    256:      pit = lst;
                    257:      do
                    258:      { wsprintf(msg,"%8x %8x %8x %ld %s "
                    259:                , pit, pit->pitNext, pit->pitPrev, pit->iLen
                    260:                , (pit->bAnchor ? "Anchor" : "Data")
                    261:                );
                    262:        OutputDebugString(msg);
                    263:        if (pit->pitNext->pitPrev != pit)
                    264:          OutputDebugString(" Next Prev error!!");
                    265:        if (pit->pitPrev->pitNext != pit)
                    266:          OutputDebugString(" Prev Next error!!");
                    267:        OutputDebugString("\n");
                    268:        pit = pit->pitNext;
                    269:      } while (pit!=lst);
                    270:      OutputDebugString("End of list dump\n");
                    271:   } /* List_Dump */
                    272: 
                    273:   /* Dump hex representation of handle to debugger */
                    274: void APIENTRY List_Show(LIST lst)
                    275:   { char msg[50];               
                    276:     wsprintf(msg, "%8x", lst);
                    277:     OutputDebugString(msg);
                    278:   } /* List_Show */
                    279: 
                    280:   /*------------------------------------------------------------------
                    281:   | Create a list.  It will be initially empty
                    282:    -------------------------------------------------------------------*/
                    283: LIST APIENTRY List_Create(void)
                    284:   {  LIST lst;
                    285:      if (!bInited) {List_Init(); }          /* prevent some silly errors */
                    286:      lst = Alloc(iAnchorSize);
                    287:      if (lst==NULL) { return NULL; }
                    288:      lst->pBlock = pCurrent;
                    289:      List_Leave_Crit(&CritSec);
                    290:      lst->bOK = TRUE;
                    291:      lst->pitNext = lst;
                    292:      lst->pitPrev = lst;
                    293:      lst->bAnchor = TRUE;
                    294:      /* no length field set in an anchor block */
                    295:      return lst;
                    296:   } /* List_Create */
                    297: 
                    298:   /*------------------------------------------------------------------
                    299:   | Destroy *plst.  It does not need to be empty first
                    300:    -------------------------------------------------------------------*/
                    301:   void APIENTRY List_Destroy(PLIST plst)
                    302:   {  LIST pitP;    /* item cursor on * plst */
                    303:      LIST pitQ;    /* item cursor runs one step ahead of pitQ */
                    304: 
                    305:      if (plst==NULL)
                    306:        return;
                    307:      /* There is at least an anchor block to destroy */
                    308:      pitP = *plst;
                    309:      do
                    310:      {  pitQ = pitP->pitNext;
                    311:         Free(pitP->pBlock, pitP);
                    312:         pitP = pitQ;
                    313:      }while(pitP != *plst);
                    314:      *plst = NULL;
                    315:   } /* List_Destroy */
                    316: 
                    317:   /*------------------------------------------------------------------
                    318:   | Add an item holding Object to the beginning of * plst
                    319:    -------------------------------------------------------------------*/
                    320:   void APIENTRY List_AddFirst(LIST lst, LPVOID pObject, UINT uLen)
                    321:   {  LIST pit;      /* newly allocated item */
                    322: 
                    323:      if (lst==NULL)
                    324:        return;
                    325:      pit = Alloc(iHeaderSize+uLen);
                    326:      if (pit==NULL) { lst->bOK = FALSE; return; }
                    327:      pit->pBlock = pCurrent;
                    328:      List_Leave_Crit(&CritSec);
                    329:      pit->iLen = uLen;
                    330:      pit->pitPrev = lst;
                    331:      pit->pitNext = lst->pitNext;
                    332:      lst->pitNext->pitPrev = pit; /* for empty list that set lst->pitPrev */
                    333:      lst->pitNext = pit;
                    334:      pit->bAnchor = FALSE;
                    335:      memcpy( &(pit->Data), pObject, uLen );
                    336:   } /* List_AddFirst */
                    337: 
                    338:   /*------------------------------------------------------------------
                    339:   | Return the address of the place for Len bytes of data in a new
                    340:   | item at the start of lst
                    341:    -------------------------------------------------------------------*/
                    342:   LPVOID APIENTRY List_NewFirst(LIST lst, UINT uLen)
                    343:   {  LIST pit;
                    344: 
                    345:      if (lst==NULL)
                    346:        return NULL;
                    347:      pit = Alloc(iHeaderSize+uLen);
                    348:      if (pit==NULL) { lst->bOK = FALSE; return NULL; }
                    349:      pit->pBlock = pCurrent;
                    350:      List_Leave_Crit(&CritSec);
                    351:      pit->iLen = uLen;
                    352:      pit->pitPrev = lst;
                    353:      pit->pitNext = lst->pitNext;
                    354:      lst->pitNext->pitPrev = pit; /* for empty list that set lst->pitPrev */
                    355:      lst->pitNext = pit;
                    356:      pit->bAnchor = FALSE;
                    357:      return (char FAR *)&(pit->Data);
                    358:   } /* List_NewFirst */
                    359: 
                    360:   /*------------------------------------------------------------------
                    361:   | Delete the first item in lst.  Error if lst is empty
                    362:    -------------------------------------------------------------------*/
                    363:   void APIENTRY List_DeleteFirst(LIST lst)
                    364:   {  LIST pit;
                    365: 
                    366:      if (lst==NULL)
                    367:        return;
                    368:                                /* attempting to delete the anchor block! */
                    369:      if (lst->pitNext==lst) {lst->bOK = FALSE; }
                    370:      else
                    371:         {  pit = lst->pitNext;
                    372:            pit->pitNext->pitPrev = pit->pitPrev;
                    373:            pit->pitPrev->pitNext = pit->pitNext;
                    374:            Free(pit->pBlock, pit);
                    375:         }
                    376:   } /* List_DeleteFirst */
                    377: 
                    378:   /*------------------------------------------------------------------
                    379:   | Add an item holding Object to the end of lst
                    380:    -------------------------------------------------------------------*/
                    381:   void APIENTRY List_AddLast(LIST lst, LPVOID pObject, UINT uLen)
                    382:   {  LIST pit;
                    383: 
                    384:      if (lst==NULL)
                    385:        return;
                    386:      pit = Alloc(iHeaderSize+uLen);
                    387:      if (pit==NULL) { lst->bOK = FALSE; return; }
                    388:      pit->pBlock = pCurrent;
                    389:      List_Leave_Crit(&CritSec);
                    390:      pit->iLen = uLen;
                    391:      pit->pitNext = lst;
                    392:      pit->pitPrev = lst->pitPrev;
                    393:      lst->pitPrev->pitNext = pit; /* for empty list that set lst->pitNext */
                    394:      lst->pitPrev = pit;
                    395:      pit->bAnchor = FALSE;
                    396:      memcpy( &(pit->Data), pObject, uLen );
                    397:   } /* ListAddLast */
                    398: 
                    399:   /*------------------------------------------------------------------
                    400:   | Return the address of the place for uLen bytes of data in a new
                    401:   |  item at the end of lst
                    402:    -------------------------------------------------------------------*/
                    403:   LPVOID APIENTRY List_NewLast(LIST lst, UINT uLen)
                    404:   {  LIST pit;
                    405: 
                    406:      if (lst==NULL)
                    407:        return NULL;
                    408:      pit = Alloc(iHeaderSize+uLen);
                    409:      if (pit==NULL) { lst->bOK = FALSE; return NULL; }
                    410:      pit->pBlock = pCurrent;
                    411:      List_Leave_Crit(&CritSec);
                    412:      pit->iLen = uLen;
                    413:      pit->pitNext = lst;
                    414:      pit->pitPrev = lst->pitPrev;
                    415:      lst->pitPrev->pitNext = pit; /* for empty list that set lst->pitNext */
                    416:      lst->pitPrev = pit;
                    417:      pit->bAnchor = FALSE;
                    418:      return (char FAR *)&(pit->Data);
                    419:   } /* ListNewLast */
                    420: 
                    421:   /*------------------------------------------------------------------
                    422:   | Delete the last item in lst.  Error if lst is empty
                    423:    -------------------------------------------------------------------*/
                    424:   void APIENTRY List_DeleteLast(LIST lst)
                    425:   {  LIST pit;
                    426: 
                    427:      if (lst==NULL)
                    428:        return;
                    429:                                /* attempting to delete the anchor block! */
                    430:      if (lst->pitNext==lst) {lst->bOK = FALSE; }
                    431:      else
                    432:         {  pit = lst->pitPrev;
                    433:            pit->pitNext->pitPrev = pit->pitPrev;
                    434:            pit->pitPrev->pitNext = pit->pitNext;
                    435:            Free(pit->pBlock, pit);
                    436:         }
                    437:   } /* List_DeleteLast */
                    438: 
                    439:   /*--------------------------------------------------------------------
                    440:   | Add an item holding * pObject to lst immediately after Curs.
                    441:   | List_AddAfter(lst,NULL,pObject,Len) adds it to the start of the lst
                    442:    ---------------------------------------------------------------------*/
                    443:   void APIENTRY List_AddAfter( LIST lst
                    444:                     , LPVOID Curs
                    445:                     , LPVOID pObject
                    446:                     , UINT uLen
                    447:                     )
                    448:   {  LIST pitNew;
                    449:      LIST pitAfter;
                    450: 
                    451:      if (lst==NULL)
                    452:        return;
                    453:      if (Curs==NULL){ List_AddFirst(lst, pObject, uLen);}
                    454:      else
                    455:         {  MOVEBACK(Curs);
                    456:            pitAfter = (LIST)Curs;
                    457:            pitNew = Alloc(iHeaderSize+uLen);
                    458:            if (pitNew==NULL) { lst->bOK = FALSE; return; }
                    459:            pitNew->pBlock = pCurrent;
                    460:            List_Leave_Crit(&CritSec);
                    461:            pitNew->iLen = uLen;
                    462:            pitNew->pitPrev = pitAfter;
                    463:            pitNew->pitNext = pitAfter->pitNext;
                    464:            pitAfter->pitNext->pitPrev = pitNew;
                    465:            pitAfter->pitNext = pitNew;
                    466:            pitNew->bAnchor = FALSE;
                    467:            memcpy( &(pitNew->Data), pObject, uLen );
                    468:         }
                    469:   } /* List_AddAfter */
                    470: 
                    471:   /*--------------------------------------------------------------------
                    472:   | Return the address of the place for uLen bytes of data in a new
                    473:   | item immediately after Curs.
                    474:   | List_NewAfter(Lst,NULL,uLen) returns a pointer
                    475:   | to space for uLen bytes in a new first element.
                    476:    ---------------------------------------------------------------------*/
                    477:   LPVOID APIENTRY List_NewAfter(LIST lst, LPVOID Curs, UINT uLen)
                    478:   {  LIST pitNew;
                    479:      LIST pitAfter;
                    480: 
                    481:      if (lst==NULL)
                    482:        return NULL;
                    483:      if (Curs==NULL){ return List_NewFirst(lst, uLen);}
                    484:      else
                    485:         {  MOVEBACK(Curs);
                    486:            pitAfter = (LIST)Curs;
                    487:            pitNew = Alloc(iHeaderSize+uLen);
                    488:            if (pitNew==NULL) { lst->bOK = FALSE; return NULL; }
                    489:            pitNew->pBlock = pCurrent;
                    490:            List_Leave_Crit(&CritSec);
                    491:            pitNew->iLen = uLen;
                    492:            pitNew->pitPrev = pitAfter;
                    493:            pitNew->pitNext = pitAfter->pitNext;
                    494:            pitAfter->pitNext->pitPrev = pitNew;
                    495:            pitAfter->pitNext = pitNew;
                    496:            pitNew->bAnchor = FALSE;
                    497:            return (char FAR *)&(pitNew->Data);
                    498:         }
                    499:   } /* List_NewAfter */
                    500: 
                    501:   /*--------------------------------------------------------------------
                    502:   | Add an item holding Object to lst immediately before Curs.
                    503:   | List_AddBefore(Lst,NULL,Object,uLen) adds it to the end of the list
                    504:    ---------------------------------------------------------------------*/
                    505:   void APIENTRY List_AddBefore( LIST lst
                    506:                      , LPVOID Curs
                    507:                      , LPVOID pObject
                    508:                      , UINT uLen
                    509:                      )
                    510:   {  LIST pitNew;
                    511:      LIST pitBefore;
                    512: 
                    513:      if (lst==NULL)
                    514:        return;
                    515:      if (Curs==NULL){ List_AddLast(lst, pObject, uLen);}
                    516:      else
                    517:         {  MOVEBACK(Curs);
                    518:            pitBefore = (LIST)Curs;
                    519:            pitNew = Alloc(iHeaderSize+uLen);
                    520:            if (pitNew==NULL) { lst->bOK = FALSE; return; }
                    521:            pitNew->pBlock = pCurrent;
                    522:            List_Leave_Crit(&CritSec);
                    523:            pitNew->iLen = uLen;
                    524:            pitNew->pitNext = pitBefore;
                    525:            pitNew->pitPrev = pitBefore->pitPrev;
                    526:            pitBefore->pitPrev->pitNext = pitNew;
                    527:            pitBefore->pitPrev = pitNew;
                    528:            pitNew->bAnchor = FALSE;
                    529:            memcpy( &(pitNew->Data), pObject, uLen );
                    530:         }
                    531:   } /* List_AddBefore */
                    532: 
                    533:   /*--------------------------------------------------------------------
                    534:   | Return the address of the place for uLen bytes of data in a new
                    535:   | item immediately before Curs.
                    536:   | List_NewBefore(Lst,NULL,uLen) returns a pointer
                    537:   | to space for uLen bytes in a new last element.
                    538:    ---------------------------------------------------------------------*/
                    539:   LPVOID APIENTRY List_NewBefore(LIST lst, LPVOID Curs, UINT uLen )
                    540:   {  LIST pitNew;
                    541:      LIST pitBefore;
                    542: 
                    543:      if (lst==NULL)
                    544:        return NULL;
                    545:      if (Curs==NULL){ return List_NewLast(lst, uLen);}
                    546:      else
                    547:         {  MOVEBACK(Curs);
                    548:            pitBefore = (LIST)Curs;
                    549:            pitNew = Alloc(iHeaderSize+uLen);
                    550:            if (pitNew==NULL) { lst->bOK = FALSE; return NULL; }
                    551:            pitNew->pBlock = pCurrent;
                    552:            List_Leave_Crit(&CritSec);
                    553:            pitNew->iLen = uLen;
                    554:            pitNew->pitNext = pitBefore;
                    555:            pitNew->pitPrev = pitBefore->pitPrev;
                    556:            pitBefore->pitPrev->pitNext = pitNew;
                    557:            pitBefore->pitPrev = pitNew;
                    558:            pitNew->bAnchor = FALSE;
                    559:            return (char FAR *) &(pitNew->Data);
                    560:         }
                    561:   } /* List_NewBefore */
                    562: 
                    563:   /*------------------------------------------------------------------
                    564:   | Delete the item that Curs identifies.
                    565:   | This will be only a few (maybe as little as 3) machine instructions
                    566:   | quicker than DeleteForwards or DeleteBackwards but leaves Curs dangling.
                    567:   | It is therefore NOT usually to be preferred.
                    568:   | It may be useful when you have a function which returns an LPVOID
                    569:   | since the argument does not need to be a variable.
                    570:   |     Trivial example: List_Delete(List_First(L));
                    571:    -------------------------------------------------------------------*/
                    572:   void APIENTRY List_Delete(LPVOID Curs)
                    573:   {  LIST pit;
                    574: 
                    575:      if(Curs==NULL)
                    576:        return;
                    577:      MOVEBACK(Curs)
                    578:      pit = (LIST)Curs;
                    579:      pit->pitNext->pitPrev = pit->pitPrev;
                    580:      pit->pitPrev->pitNext = pit->pitNext;
                    581:      Free(pit->pBlock, pit);
                    582:   } /* List_Delete */
                    583: 
                    584:   /*-----------------------------------------------------------------------
                    585:   | Delete the item that Curs identifies and return a cursor that
                    586:   | identifies the next item (NULL if already on last)
                    587:    ------------------------------------------------------------------------*/
                    588:   LPVOID APIENTRY List_DeleteForwards(LPVOID Curs)
                    589:   {  LIST pitDel;  /* the item to delete */
                    590:      LIST pitN;    /* the item after (could be anchor) */
                    591: 
                    592:      if(Curs==NULL)
                    593:        return NULL;
                    594:      MOVEBACK(Curs)
                    595:      pitDel = (LIST)Curs;
                    596:      pitN = pitDel->pitNext;
                    597: 
                    598:      pitN->pitPrev = pitDel->pitPrev;
                    599:      pitDel->pitPrev->pitNext = pitN;
                    600:      Free(pitDel->pBlock, pitDel);
                    601:      if (pitN->bAnchor) return NULL;
                    602:      else return (char FAR *)&(pitN->Data);
                    603:   } /* List_DeleteForwards */
                    604: 
                    605:   /*-----------------------------------------------------------------------
                    606:   | Delete the item that Curs identifies and return a cursor that
                    607:   | identifies the previous item (NULL if already on first)
                    608:    ------------------------------------------------------------------------*/
                    609:   LPVOID APIENTRY List_DeleteBackwards(LPVOID Curs)
                    610:   {  LIST pitDel;  /* the one to delete */
                    611:      LIST pitB;    /* the one before */
                    612: 
                    613:      if(Curs==NULL)
                    614:        return NULL;
                    615:      MOVEBACK(Curs)
                    616:      pitDel = (LIST)Curs;
                    617:      pitB = pitDel->pitPrev;
                    618:      pitDel->pitNext->pitPrev = pitB;
                    619:      pitB->pitNext = pitDel->pitNext;
                    620:      Free(pitDel->pBlock, pitDel);
                    621:      if (pitB->bAnchor) return NULL;
                    622:      else return (char FAR *)&(pitB->Data);
                    623:   } /* List_DeleteBackwards */
                    624: 
                    625:   /*-------------------------------------------------------------------
                    626:   | Return the length of the object identified by the cursor Curs
                    627:    -------------------------------------------------------------------*/
                    628:   int APIENTRY List_ItemLength(LPVOID Curs)
                    629:   {  LIST pit;
                    630: 
                    631:      if(Curs==NULL)
                    632:        return 0;
                    633:      MOVEBACK(Curs)
                    634:      pit = (LIST)Curs;
                    635:      return pit->iLen;
                    636:   } /* List_ItemLength */
                    637: 
                    638:   /*------------------------------------------------------------------
                    639:   | Return the address of the first object in lst
                    640:   |  If lst is empty then Return NULL.
                    641:    -------------------------------------------------------------------*/
                    642:   LPVOID APIENTRY List_First(LIST lst)
                    643:   {  
                    644:      if (lst==NULL)
                    645:        return NULL;
                    646:      if (lst->pitNext==lst) { return NULL; }
                    647:      return &(lst->pitNext->Data);
                    648:   } /* List_First */
                    649: 
                    650:   /*------------------------------------------------------------------
                    651:   | Return the address of the last object in lst
                    652:   | If lst is empty then return NULL.
                    653:    -------------------------------------------------------------------*/
                    654:   LPVOID APIENTRY List_Last(LIST lst)
                    655:   {  
                    656:      if (lst==NULL)
                    657:        return NULL;
                    658:      if (lst->pitNext==lst) { return NULL; }
                    659:      return &(lst->pitPrev->Data);
                    660:   } /* List_Last */
                    661: 
                    662:   /*------------------------------------------------------------------
                    663:   | Return the address of the object after Curs^.
                    664:   | List_Next(List_Last(lst)) == NULL;  List_Next(NULL) is an error.
                    665:    -------------------------------------------------------------------*/
                    666:   LPVOID APIENTRY List_Next(LPVOID Curs)
                    667:   {  LIST pit;
                    668: 
                    669:      if(Curs==NULL)
                    670:        return NULL;
                    671:      MOVEBACK(Curs)
                    672:      pit = (LIST)Curs;
                    673:      pit = pit->pitNext;
                    674:      if (pit->bAnchor) {return NULL;} else {return &(pit->Data);}
                    675:   } /* List_Next */
                    676: 
                    677:   /*------------------------------------------------------------------
                    678:   | Return the address of the object after Curs^.
                    679:   | List_Prev(List_First(L)) == NULL;  List_Prev(NULL) is an error.
                    680:    -------------------------------------------------------------------*/
                    681:   LPVOID APIENTRY List_Prev(LPVOID Curs)
                    682:   {  LIST pit;
                    683: 
                    684:      if(Curs==NULL)
                    685:        return NULL;
                    686:      MOVEBACK(Curs)
                    687:      pit = (LIST)Curs;
                    688:      pit = pit->pitPrev;
                    689:      if (pit->bAnchor) {return NULL;} else {return &(pit->Data);}
                    690:   } /* List_Prev */
                    691: 
                    692:   /*-------------------------------------------------------------------
                    693:   | Arrange that lst is empty after this call
                    694:    --------------------------------------------------------------------*/
                    695:   void APIENTRY List_Clear(LIST lst)
                    696:   {  LIST pitP;   /* item cursor on List, points to element starts */
                    697:      LIST pitQ;   /* runs one step ahead of pitP                   */
                    698: 
                    699:      if (lst==NULL)
                    700:        return;
                    701:      pitP = lst->pitNext;   /* first element of list proper */
                    702:      while (pitP!=lst)      /* while not wrapped onto anchor */
                    703:         {  pitQ = pitP->pitNext;
                    704:            Free(pitP->pBlock, pitP);
                    705:            pitP = pitQ;
                    706:         }
                    707:      lst->bOK = TRUE;
                    708:      lst->pitNext = lst;
                    709:      lst->pitPrev = lst;
                    710:   } /* List Clear */
                    711: 
                    712:   /*---------------------------------------------------------------------
                    713:   | Return TRUE if and only if lst is empty
                    714:    ----------------------------------------------------------------------*/
                    715:   BOOL APIENTRY List_IsEmpty(LIST lst)
                    716:   {  if (lst==NULL)
                    717:        return TRUE;   /* well it's sort of true isn't it? */
                    718:      return lst->pitNext ==lst;
                    719:   } /* List_IsEmpty */
                    720: 
                    721:   /*------------------------------------------------------------------
                    722:   | l1 had better be empty.  l1 then acquires all the elements from l2
                    723:    -------------------------------------------------------------------*/
                    724:   void APIENTRY SwitchLists(LIST l1, LIST l2)
                    725:   {  /* connect l1 to l2's elements, l1 had better be initially empty */
                    726:      l1->pitPrev = l2->pitPrev;
                    727:      l1->pitNext = l2->pitNext;
                    728:      /* connect the elements to l1 anchor block. */
                    729:      l1->pitPrev->pitNext = l1;
                    730:      l1->pitNext->pitPrev = l1;
                    731:      /* make l2 empty */
                    732:      l2->pitPrev = l2;
                    733:      l2->pitNext = l2;
                    734:   } /* SwitchLists */
                    735: 
                    736:   /*-----------------------------------------------------------------------
                    737:   | l1 := l1||l2; l2 := empty
                    738:   | The elements themselves are not moved, so pointers to them remain valid.
                    739:   |
                    740:   | l1 gets all the elements of l1 in their original order followed by
                    741:   | all the elements of l2 in the order they were in in l2.
                    742:   | l2 becomes empty.
                    743:    ------------------------------------------------------------------------*/
                    744:   void APIENTRY List_Join(LIST l1, LIST l2)
                    745:   {  if((l1==NULL)||(l2==NULL))
                    746:        return;
                    747:      l1->bOK = l1->bOK &&l2->bOK;  /* result OK if both inputs OK */
                    748:      l2->bOK = TRUE;               /* as l2 always becomes empty */
                    749:      if (l2->pitNext==l2) { /* no elements need moving */ }
                    750:      else if (l2->pitNext==l2) { SwitchLists(l1,l2); return; }
                    751:      else
                    752:         {  l2->pitNext->pitPrev = l1->pitPrev;
                    753:            l1->pitPrev->pitNext = l2->pitNext;
                    754:            l1->pitPrev = l2->pitPrev;
                    755:            l1->pitPrev->pitNext = l1;
                    756:            l2->pitNext = l2;
                    757:            l2->pitPrev = l2;
                    758:         }
                    759:   } /* List_Join */
                    760: 
                    761:   /*-----------------------------------------------------------------------
                    762:   | Let L1 be *pl1 and L2 be *pl2
                    763:   | L1 := L1[...Curs] || L2 || L1[Curs+1...]; L2 := empty
                    764:   | Curs=NULL means insert L2 at the start of L1
                    765:   | The elements themselves are not moved, so pointers to them remain valid.
                    766:   |
                    767:   | L1 gets the elements of L1 from the start up to and including the element
                    768:   | that Curs points at, in their original order,
                    769:   | followed by all the elements that were in L2, in their original order,
                    770:   | followed by the rest of L1
                    771:    ------------------------------------------------------------------------*/
                    772:   void APIENTRY List_InsertListAfter(LIST l1, LIST l2, LPVOID Curs)
                    773:   {  LIST pitA;     /* The element after Curs, could be anchor */
                    774:      LIST pit;      /* The start of the element that Curs points at
                    775:                     |  or the anchor block if Curs==NULL
                    776:                     */
                    777: 
                    778:      if ( (l1==NULL) || (l2==NULL))
                    779:        return;
                    780:      l1->bOK = l1->bOK && l2->bOK;
                    781:      l2->bOK = TRUE;
                    782:      if (l2->pitNext==l2) { /* no elements need moving */ }
                    783:      else if ( l1->pitNext==l1)
                    784:      {  /* the easy way to code this would be simply to switch the two
                    785:         |  pointers l1 and l2, but they are value parameters and we don't
                    786:         |  want to change that.
                    787:         */
                    788:         SwitchLists(l1,l2);
                    789:         return;
                    790:      }
                    791:      else
                    792:      {  if(Curs==NULL){ pit = l1;}
                    793:         else
                    794:         {  MOVEBACK(Curs)
                    795:            pit = (LIST)Curs;
                    796:         }
                    797:         /* pit points to a block to insert after, could be anchor */
                    798:         pitA = pit->pitNext;      /* Cannot be same as P, already checked */
                    799:         l2->pitNext->pitPrev = pit;    /*  P<-- elems-of-l2    A */
                    800:         l2->pitPrev->pitNext = pitA;   /*  P<-- elems-of-l2 -->A */
                    801:         pit->pitNext = l2->pitNext;    /*  P<-->elems-of-l2 -->A */
                    802:         pitA->pitPrev = l2->pitPrev;   /*  P<-->elems-of-l2<-->A */
                    803: 
                    804:         l2->pitNext = l2;
                    805:         l2->pitPrev = l2;
                    806:      }
                    807:   }  /* List_InsertListAfter */
                    808: 
                    809: 
                    810:   /*-----------------------------------------------------------------------
                    811:   | l1 := l1[...Curs-1] || l2 || l1[Curs...]; l2 := empty
                    812:   | Curs=NULL means insert l2 at the end of l1
                    813:   | The elements themselves are not moved, so pointers to them remain valid.
                    814:   |
                    815:   | l1 gets the elements of l1 from the start up to but not including the
                    816:   | element that Curs points at, in their original order,
                    817:   | followed by all the elements that were in l2, in their original order,
                    818:   | followed by the rest of l1.
                    819:    ------------------------------------------------------------------------*/
                    820:   void APIENTRY List_InsertListBefore(LIST l1, LIST l2, LPVOID Curs)
                    821:   {  LIST pitB;     /* The element before Curs, could be anchor */
                    822:      LIST pit;      /* The start of the element that Curs points at
                    823:                     |  or the anchor block if Curs==NULL
                    824:                     */
                    825: 
                    826:      if ((l1==NULL) || (l2==NULL))
                    827:        return;
                    828:      l1->bOK = l1->bOK && l2->bOK;
                    829:      l2 ->bOK = TRUE;
                    830:      if (l2->pitNext==l2) { /* no action needed */ }
                    831:      else if (l1->pitNext==l1)
                    832:      {  /* the easy way to code this would be simply to switch the two
                    833:         |  pointers l1 and l2, but they are value parameters and we don't
                    834:         |  want to change that.
                    835:         */
                    836:         SwitchLists(l1,l2);
                    837:         return;
                    838:      }
                    839:      else
                    840:      {  if(Curs==NULL) { pit = l1; }
                    841:         else
                    842:         {  MOVEBACK(Curs)
                    843:            pit = (LIST)Curs;
                    844:         }
                    845: 
                    846:         /* P points to a block to insert before, could be anchor */
                    847:         pitB = pit->pitPrev;       /* Cannot be same as P, already checked */
                    848:         l2->pitNext->pitPrev = pitB; /*  B<-- elems-of-L2    P */
                    849:         l2->pitPrev->pitNext = pit;  /*  B<-- elems-of-L2 -->P */
                    850:         pitB->pitNext = l2->pitNext; /*  B<-->elems-of-L2 -->P */
                    851:         pit->pitPrev = l2->pitPrev;  /*  B<-->elems-of-L2<-->P */
                    852:         l2->pitNext = l2;
                    853:         l2->pitPrev = l2;
                    854:      }
                    855:   } /* List_InsertListBefore */
                    856: 
                    857: 
                    858:   /*-----------------------------------------------------------------------
                    859:   | Let l1 be l1 and l2 be l2
                    860:   | Split l2 off from the front of l1:    final l2,l1 = original l1
                    861:   |
                    862:   | Split l1 into l2: objects of l1 up to and including Curs object
                    863:   |               l1: objects of l1 after Curs
                    864:   | Any original contents of l2 are freed.
                    865:   | List_Spilt(l1, l2, NULL) splits l1 before the first object so l1 gets all.
                    866:   | The elements themselves are not moved.
                    867:    ------------------------------------------------------------------------*/
                    868:   void APIENTRY List_SplitAfter(LIST l1, LIST l2, LPVOID Curs)
                    869:   {  LIST pit;
                    870: 
                    871:      if ((l1==NULL) || (l2==NULL))
                    872:        return;
                    873:      if (l2->pitNext!=l2){ List_Clear(l2); };
                    874:      if (Curs!=NULL)
                    875:      {  MOVEBACK(Curs)
                    876:         pit = (LIST)Curs;
                    877:         /* Curs had better be an item in l1! l2 had better be created! */
                    878:         if (pit==l1) { l1->bOK = FALSE; l2->bOK = FALSE; return; }
                    879:         if (pit->pitNext==l1)
                    880:         {  /* transfer whole of l2 to l1 */
                    881:            SwitchLists(l2,l1);
                    882:            return;
                    883:         }
                    884:         l2->pitPrev = pit;
                    885:         l2->pitNext = l1->pitNext;
                    886:         l1->pitNext = pit->pitNext;
                    887:         pit->pitNext = l2;
                    888:         l2->pitNext->pitPrev = l2;
                    889:         l1->pitNext->pitPrev = l1;
                    890:      }
                    891:   } /* List_SplitAfter */
                    892: 
                    893:   /*----------------------------------------------------------------------
                    894:   | Split l2 off from the back of l1:  final l1,l2 = original l1
                    895:   |
                    896:   | Split l1 into l1: objects of l1 up to but not including Curs object
                    897:   |               l2: objects of l1 from Curs onwards
                    898:   | Any original contants of l2 are freed.
                    899:   | List_Spilt(l1, l2, NULL) splits l1 after the last object so l1 gets all.
                    900:   | The elements themselves are not moved.
                    901:    -----------------------------------------------------------------------*/
                    902:   void APIENTRY List_SplitBefore(LIST l1, LIST l2, LPVOID Curs)
                    903:   {  LIST pit;
                    904: 
                    905:      if ((l1==NULL) || (l2==NULL))
                    906:        return;
                    907:      if (l2->pitNext!=l2){ List_Clear(l2); }
                    908:      if (Curs!=NULL)
                    909:      {  MOVEBACK(Curs)
                    910:         pit = (LIST)Curs;
                    911:         /* Curs had better be an item in L1! L2 had better be created! */
                    912:         if (pit==l1){ l1->bOK = FALSE; l2->bOK = FALSE; return; }
                    913:         if (pit->pitPrev==l1) { SwitchLists(l2,l1); return; }
                    914:         l2->pitNext = pit;
                    915:         l2->pitPrev = l1->pitPrev;
                    916:         l1->pitPrev = pit->pitPrev;
                    917:         pit->pitPrev = l2;
                    918:         l2->pitPrev->pitNext = l2;
                    919:         l1->pitPrev->pitNext = l1;
                    920:      }
                    921:   } /* List_SplitBefore */
                    922: 
                    923:   /*------------------------------------------------------------------
                    924:   | Return the number of items in L
                    925:    -------------------------------------------------------------------*/
                    926:   int APIENTRY List_Card(LIST lst)
                    927:   {  LIST pit;     /* item cursor on lst */
                    928:      int cit;
                    929: 
                    930:      if (lst==NULL)
                    931:        return 0;    /* well it is sort of 0 */
                    932:      pit = lst->pitNext;
                    933:      cit = 0;
                    934:      while(pit!=lst)
                    935:         {  cit++;
                    936:            pit = pit->pitNext;
                    937:         }
                    938:      return cit;
                    939:   } /* List_Card */
                    940: 
                    941:   /*------------------------------------------------------------------
                    942:   | Check return code
                    943:    -------------------------------------------------------------------*/
                    944:   BOOL APIENTRY List_IsOK(LIST lst)
                    945:   {  if(lst==NULL)
                    946:        return FALSE;       /* well it is sick ain't it! */
                    947:      return lst->bOK;
                    948:   } /* List_IsOK */
                    949: 
                    950:   /*------------------------------------------------------------------
                    951:   | Set return code to good
                    952:    -------------------------------------------------------------------*/
                    953:   void APIENTRY List_MakeOK(LIST lst)
                    954:   {  if(lst==NULL)
                    955:        return;
                    956:      lst->bOK = TRUE;
                    957:   } /* List_MakeOK */
                    958: 
                    959:   BOOL APIENTRY List_Check(LIST lst)
                    960:   { LIST pel;
                    961:     BOOL bOK;
                    962:     /*-----------------------------------------------------------------
                    963:     | Check the anchor block has the Anchor flag set.
                    964:     | Run through the LIST using the Anchor flag (which should be FALSE)
                    965:     | to mark where we have been (to test for loops in the chain)
                    966:     | and carry on until we see the Anchor flag again.  Check that this
                    967:     | is the anchor block that we started from.  Now do another pass
                    968:     | turning the Anchor flags off again and checking the Prev pointers.
                    969:      -------------------------------------------------------------------*/
                    970:     if(lst==NULL) return FALSE;  /* Should we trap?  Arguable */
                    971:     bOK = lst->bAnchor;
                    972:     pel = lst->pitNext;
                    973:     while(! pel->bAnchor)
                    974:     { pel->bAnchor = TRUE;
                    975:       pel = pel->pitNext;
                    976:     }
                    977:     bOK = bOK && (pel==lst);
                    978:     if(bOK)
                    979:     { /* Turn all the bAnchor flags off */
                    980:       pel = lst;
                    981:       do
                    982:       { pel->bAnchor = FALSE;
                    983:         bOK = bOK & (pel->pitNext->pitPrev==pel);
                    984:         pel = pel->pitNext;
                    985:       } while (pel!=lst);
                    986:       lst->bAnchor = TRUE;  /* except the real one */
                    987:     }
                    988:     else
                    989:     { /* just turn off those that we set on */
                    990:       pel = lst->pitNext;
                    991:       while (pel->bAnchor)
                    992:       { pel->bAnchor = FALSE;
                    993:         pel = pel->pitNext;
                    994:       }
                    995:       lst->bAnchor = TRUE;
                    996:     }
                    997:     return bOK;
                    998:   } /* List_Check */
                    999: 
                   1000: 
                   1001:   void APIENTRY List_Recover(PLIST plst)
                   1002:   {  LIST Last, P,Q;
                   1003:      BOOL OK;
                   1004:     /* For no particular reason we presume that the forward chain
                   1005:        is good and reconstruct the back chain from it.  A better
                   1006:        algorithm would do the kind of things that List_Check does
                   1007:        to figure out where the problems lie.  This just steps along
                   1008:        until it sees either an address that it has already seen or
                   1009:        else the anchor block.  (It's an n-squared algorithm).
                   1010:        It links the last good block found back to the anchor and
                   1011:        fixes all the Anchor flags.
                   1012:     */
                   1013:     if (plst==NULL) return;
                   1014:     if (*plst==NULL)
                   1015:     {  *plst = List_Create();
                   1016:        return;
                   1017:     }
                   1018:     (*plst)->bAnchor = TRUE;
                   1019:     P = (*plst)->pitNext;
                   1020:     Last = *plst;
                   1021:     for (; ; )
                   1022:     {  if (P==*plst) break;
                   1023:        Last = P;
                   1024:        if (P->pitNext!=*plst)
                   1025:        {   OK = TRUE;
                   1026:            Q = *plst;
                   1027:            for (; ; )
                   1028:            {   OK &= (P->pitNext!=Q);
                   1029:                if (Q==P) break;
                   1030:                Q = Q->pitNext;
                   1031:            }
                   1032:            if (!OK) break;
                   1033:        }
                   1034:        P = P->pitNext;
                   1035:     }
                   1036:     P = *plst;
                   1037:     while (P!=Last)
                   1038:     {  P->pitNext->pitPrev = P;
                   1039:        P->bAnchor = FALSE;
                   1040:        P = P->pitNext;
                   1041:     }
                   1042:     Last->pitNext = *plst;
                   1043:     (*plst)->pitPrev = Last;
                   1044:     (*plst)->bAnchor = TRUE;
                   1045:     (*plst)->bOK = TRUE;   /* Here's hoping! */
                   1046:   } /* List_Recover */

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.