Source code of Windows XP (NT5)
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.

1358 lines
40 KiB

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