Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1356 lines
42 KiB

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