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.

588 lines
14 KiB

  1. /* Copyright (c) 1992, Microsoft Corporation, all rights reserved
  2. **
  3. ** dtl.c
  4. ** Double-threaded linked list manipulation core routines
  5. ** Listed alphabetically
  6. **
  7. ** 06/28/92 Steve Cobb
  8. */
  9. #include <windows.h> // Win32 root
  10. #include <nouiutil.h> // Heap definitions
  11. #include <dtl.h> // Our public header
  12. #include <debug.h> // debug macros
  13. DTLNODE*
  14. DtlMoveToTail(
  15. IN DTLLIST* pdtllist,
  16. IN DTLNODE* pdtlnode
  17. );
  18. DTLNODE*
  19. DtlAddNodeAfter(
  20. IN OUT DTLLIST* pdtllist,
  21. IN OUT DTLNODE* pdtlnodeInList,
  22. IN OUT DTLNODE* pdtlnode )
  23. /* Adds node 'pdtlnode' to list 'pdtllist' after node 'pdtlnodeInList'.
  24. ** If 'pdtlnodeInList' is NULL, 'pdtlnode' is added at the end of the
  25. ** list.
  26. **
  27. ** Returns the address of the added node, i.e. 'pdtlnode'.
  28. */
  29. {
  30. //For .Net 665628, add parameter checking for the whole dtl.c file
  31. //
  32. if( pdtllist && pdtlnode )
  33. {
  34. if (!pdtlnodeInList || !pdtlnodeInList->pdtlnodeNext)
  35. return DtlAddNodeLast( pdtllist, pdtlnode );
  36. pdtlnode->pdtlnodePrev = pdtlnodeInList;
  37. pdtlnode->pdtlnodeNext = pdtlnodeInList->pdtlnodeNext;
  38. pdtlnodeInList->pdtlnodeNext->pdtlnodePrev = pdtlnode;
  39. pdtlnodeInList->pdtlnodeNext = pdtlnode;
  40. ++pdtllist->lNodes;
  41. }
  42. return pdtlnode;
  43. }
  44. DTLNODE*
  45. DtlAddNodeBefore(
  46. IN OUT DTLLIST* pdtllist,
  47. IN OUT DTLNODE* pdtlnodeInList,
  48. IN OUT DTLNODE* pdtlnode )
  49. /* Adds node 'pdtlnode' to list 'pdtllist' before node 'pdtlnodeInList'.
  50. ** If 'pdtlnodeInList' is NULL, 'pdtlnode' is added at the beginning of
  51. ** the list.
  52. **
  53. ** Returns the address of the added node, i.e. 'pdtlnode'.
  54. */
  55. {
  56. if( pdtllist && pdtlnode )
  57. {
  58. if (!pdtlnodeInList || !pdtlnodeInList->pdtlnodePrev)
  59. return DtlAddNodeFirst( pdtllist, pdtlnode );
  60. pdtlnode->pdtlnodePrev = pdtlnodeInList->pdtlnodePrev;
  61. pdtlnode->pdtlnodeNext = pdtlnodeInList;
  62. pdtlnodeInList->pdtlnodePrev->pdtlnodeNext = pdtlnode;
  63. pdtlnodeInList->pdtlnodePrev = pdtlnode;
  64. ++pdtllist->lNodes;
  65. }
  66. return pdtlnode;
  67. }
  68. DTLNODE*
  69. DtlAddNodeFirst(
  70. IN OUT DTLLIST* pdtllist,
  71. IN OUT DTLNODE* pdtlnode )
  72. /* Adds node 'pdtlnode' at the beginning of list 'pdtllist'.
  73. **
  74. ** Returns the address of the added node, i.e. 'pdtlnode'.
  75. */
  76. {
  77. if ( pdtllist && pdtlnode )
  78. {
  79. if (pdtllist->lNodes)
  80. {
  81. pdtllist->pdtlnodeFirst->pdtlnodePrev = pdtlnode;
  82. pdtlnode->pdtlnodeNext = pdtllist->pdtlnodeFirst;
  83. }
  84. else
  85. {
  86. pdtllist->pdtlnodeLast = pdtlnode;
  87. pdtlnode->pdtlnodeNext = NULL;
  88. }
  89. pdtlnode->pdtlnodePrev = NULL;
  90. pdtllist->pdtlnodeFirst = pdtlnode;
  91. ++pdtllist->lNodes;
  92. }
  93. return pdtlnode;
  94. }
  95. DTLNODE*
  96. DtlAddNodeLast(
  97. IN OUT DTLLIST* pdtllist,
  98. IN OUT DTLNODE* pdtlnode )
  99. /* Adds 'pdtlnode' at the end of list 'pdtllist'.
  100. **
  101. ** Returns the address of the added node, i.e. 'pdtlnode'.
  102. */
  103. {
  104. if ( pdtllist && pdtlnode )
  105. {
  106. if (pdtllist->lNodes)
  107. {
  108. pdtlnode->pdtlnodePrev = pdtllist->pdtlnodeLast;
  109. pdtllist->pdtlnodeLast->pdtlnodeNext = pdtlnode;
  110. }
  111. else
  112. {
  113. pdtlnode->pdtlnodePrev = NULL;
  114. pdtllist->pdtlnodeFirst = pdtlnode;
  115. }
  116. pdtllist->pdtlnodeLast = pdtlnode;
  117. pdtlnode->pdtlnodeNext = NULL;
  118. ++pdtllist->lNodes;
  119. }
  120. return pdtlnode;
  121. }
  122. DTLLIST*
  123. DtlCreateList(
  124. IN LONG lListId )
  125. /* Allocates a list and initializes it to empty. The list is marked with
  126. ** the user-defined list identification code 'lListId'.
  127. **
  128. ** Returns the address of the list control block or NULL if out of memory.
  129. */
  130. {
  131. DTLLIST* pdtllist = Malloc( sizeof(DTLLIST) );
  132. if (pdtllist)
  133. {
  134. pdtllist->pdtlnodeFirst = NULL;
  135. pdtllist->pdtlnodeLast = NULL;
  136. pdtllist->lNodes = 0;
  137. pdtllist->lListId = lListId;
  138. }
  139. return pdtllist;
  140. }
  141. DTLNODE*
  142. DtlCreateNode(
  143. IN VOID* pData,
  144. IN LONG_PTR lNodeId )
  145. /* Allocates an unsized node and initializes it to contain the address of
  146. ** the user data block 'pData' and the user-defined node identification
  147. ** code 'lNodeId'.
  148. **
  149. ** Returns the address of the new node or NULL if out of memory.
  150. */
  151. {
  152. DTLNODE* pdtlnode = DtlCreateSizedNode( 0, lNodeId );
  153. if (pdtlnode)
  154. DtlPutData( pdtlnode, pData );
  155. return pdtlnode;
  156. }
  157. DTLNODE*
  158. DtlCreateSizedNode(
  159. IN LONG lDataBytes,
  160. IN LONG_PTR lNodeId )
  161. /* Allocates a sized node with space for 'lDataBytes' bytes of user data
  162. ** built-in. The node is initialized to contain the address of the
  163. ** built-in user data block (or NULL if of zero length) and the
  164. ** user-defined node identification code 'lNodeId'. The user data block
  165. ** is zeroed.
  166. **
  167. ** Returns the address of the new node or NULL if out of memory.
  168. */
  169. {
  170. DTLNODE* pdtlnode = Malloc( sizeof(DTLNODE) + lDataBytes );
  171. if (pdtlnode)
  172. {
  173. ZeroMemory( pdtlnode, sizeof(DTLNODE) + lDataBytes );
  174. if (lDataBytes)
  175. pdtlnode->pData = pdtlnode + 1;
  176. pdtlnode->lNodeId = lNodeId;
  177. }
  178. return pdtlnode;
  179. }
  180. DTLNODE*
  181. DtlDeleteNode(
  182. IN OUT DTLLIST* pdtllist,
  183. IN OUT DTLNODE* pdtlnode )
  184. /* Destroys node 'pdtlnode' after removing it from list 'pdtllist'.
  185. **
  186. ** Returns the address of the node after the deleted node in 'pdtllist' or
  187. ** NULL if none.
  188. */
  189. {
  190. DTLNODE* pdtlnodeNext = NULL;
  191. if( NULL == pdtllist ||
  192. NULL == pdtlnode )
  193. {
  194. return NULL;
  195. }
  196. pdtlnodeNext = pdtlnode->pdtlnodeNext;
  197. DtlRemoveNode( pdtllist, pdtlnode );
  198. DtlDestroyNode( pdtlnode );
  199. return pdtlnodeNext;
  200. }
  201. VOID
  202. DtlDestroyList(
  203. IN OUT DTLLIST* pdtllist,
  204. IN PDESTROYNODE pfuncDestroyNode )
  205. /* Deallocates all nodes in list 'pdtllist' using the node deallocation
  206. ** function 'pfuncDestroyNode' if non-NULL or DtlDestroyNode otherwise.
  207. ** Won't GP-fault if passed a NULL list, e.g. if 'pdtllist', was never
  208. ** allocated.
  209. */
  210. {
  211. if (pdtllist)
  212. {
  213. DTLNODE* pdtlnode;
  214. while (pdtlnode = DtlGetFirstNode( pdtllist ))
  215. {
  216. DtlRemoveNode( pdtllist, pdtlnode );
  217. if (pfuncDestroyNode)
  218. pfuncDestroyNode( pdtlnode );
  219. else
  220. DtlDestroyNode( pdtlnode );
  221. }
  222. Free( pdtllist );
  223. }
  224. }
  225. VOID
  226. DtlDestroyNode(
  227. IN OUT DTLNODE* pdtlnode )
  228. /* Deallocates node 'pdtlnode'. It is the caller's responsibility to free
  229. ** the entry in an unsized node, if necessary.
  230. */
  231. {
  232. Free0( pdtlnode );
  233. }
  234. DTLLIST*
  235. DtlDuplicateList(
  236. IN DTLLIST* pdtllist,
  237. IN PDUPNODE pfuncDupNode,
  238. IN PDESTROYNODE pfuncDestroyNode )
  239. /* Duplicates a list 'pdtllist' using 'pfuncDupNode' to duplicate the
  240. ** individual nodes. 'PfuncDestroyNode' is used for clean-up before
  241. ** returning an error.
  242. **
  243. ** Returns the address of the new list or NULL if out of memory. It is
  244. ** caller's responsibility to free the returned list.
  245. */
  246. {
  247. DTLNODE* pdtlnode;
  248. DTLLIST* pdtllistDup = NULL;
  249. if ( NULL == pdtllist )
  250. {
  251. return NULL;
  252. }
  253. pdtllistDup = DtlCreateList( 0 );
  254. if (!pdtllistDup)
  255. return NULL;
  256. for (pdtlnode = DtlGetFirstNode( pdtllist );
  257. pdtlnode;
  258. pdtlnode = DtlGetNextNode( pdtlnode ))
  259. {
  260. DTLNODE* pdtlnodeDup;
  261. pdtlnodeDup = pfuncDupNode( pdtlnode );
  262. if (!pdtlnodeDup)
  263. {
  264. DtlDestroyList( pdtllist, pfuncDestroyNode );
  265. break;
  266. }
  267. DtlAddNodeLast( pdtllistDup, pdtlnodeDup );
  268. }
  269. return pdtllistDup;
  270. }
  271. DTLNODE*
  272. DtlNodeFromIndex(
  273. IN DTLLIST* pdtllist,
  274. IN LONG lToFind )
  275. /* Returns the node associated with 0-based index 'lToFind' in the linked
  276. ** list of nodes, 'pdtllist', or NULL if not found.
  277. */
  278. {
  279. DTLNODE* pdtlnode;
  280. if (!pdtllist || lToFind < 0)
  281. return NULL;
  282. pdtlnode = DtlGetFirstNode( pdtllist );
  283. while (pdtlnode && lToFind--)
  284. pdtlnode = DtlGetNextNode( pdtlnode );
  285. return pdtlnode;
  286. }
  287. VOID
  288. DtlMergeSort(
  289. IN DTLLIST* pdtllist,
  290. IN PCOMPARENODE pfnCompare )
  291. /* Sorts the list 'pdtllist' in-place using merge-sort.
  292. ** The comparison-function 'pfnCompare' is passed 'DTLNODE' pointers
  293. ** when entries in the list need to be compared.
  294. **
  295. ** This implementation is a bottom-up iterative merge-sort.
  296. ** The list is sorted by merging adjacent pairs of lists of length i
  297. ** where i starts as 1 and doubles on each iteration.
  298. ** Thus for the list (3 1 4 1 5 9 2 6), the following pairs of sublists
  299. ** are merged, with the intermediate results on the right:
  300. **
  301. ** (3)-(1), (4)-(1), (5)-(9), (2)-(6) ==> (1 3 1 4 5 9 2 6)
  302. **
  303. ** (1 3)-(1 4), (5 9)-(2 6) ==> (1 1 3 4 2 5 6 9)
  304. **
  305. ** (1 1 3 4)-(2 5 6 9) ==> (1 1 2 3 4 5 6 9)
  306. **
  307. ** Mergesort is a stable sort (i.e. the order of equal items is preserved)
  308. ** and it never does more than N lg N comparisons.
  309. */
  310. {
  311. DTLNODE* a, *b;
  312. INT N, Ncmp = 0, Nsub;
  313. if ( NULL == pdtllist )
  314. {
  315. TRACE("Null pdtllist");
  316. return;
  317. }
  318. N = DtlGetNodes(pdtllist);
  319. TRACE1("DtlMergeSort: N=%d", N);
  320. //
  321. // sort and merge all adjacent sublists of length 'Nsub',
  322. // where 'Nsub' goes from 1 to N^lg('N'), by doubling on each iteration
  323. //
  324. for (Nsub = 1; Nsub < N; Nsub *= 2) {
  325. INT Nremnant;
  326. INT aLength, bLength;
  327. //
  328. // get the head of the first (left) sublist
  329. //
  330. a = DtlGetFirstNode(pdtllist);
  331. //
  332. // as long as there is a right sublist, sort
  333. //
  334. for (Nremnant = N; Nremnant > 0; Nremnant -= Nsub * 2) {
  335. //
  336. // get the head of the right sublist;
  337. // it's just the tail of the left sublist
  338. //
  339. INT i, an, bn;
  340. aLength = min(Nremnant, Nsub);
  341. for (i = aLength, b = a; i; i--, b = DtlGetNextNode(b)) { }
  342. //
  343. // compute the length of the right sublist;
  344. // in the case where there is no right sublist
  345. // set the length to zero and the loop below just moves
  346. // the left sublist
  347. //
  348. bLength = min(Nremnant - Nsub, Nsub);
  349. if (bLength < 0) { bLength = 0; }
  350. //
  351. // now merge the left and right sublists in-place;
  352. // we merge by building a sorted list at the tail of
  353. // the unsorted list
  354. //
  355. an = aLength; bn = bLength;
  356. //
  357. // as long as both sublists are non-empty, merge them
  358. // by moving the entry with the smallest key to the tail.
  359. //
  360. while (an && bn) {
  361. ++Ncmp;
  362. if (pfnCompare(a, b) <= 0) {
  363. a = DtlMoveToTail(pdtllist, a); --an;
  364. }
  365. else {
  366. b = DtlMoveToTail(pdtllist, b); --bn;
  367. }
  368. }
  369. //
  370. // one of the sublists is empty; move all the entries
  371. // in the other sublist to the end of our sorted list
  372. //
  373. if (an) do { a = DtlMoveToTail(pdtllist, a); } while(--an);
  374. else
  375. if (bn) do { b = DtlMoveToTail(pdtllist, b); } while(--bn);
  376. //
  377. // 'b' now points to the end of the right sublist,
  378. // meaning that the item after 'b' is the one which will be
  379. // the head of the left sublist on our next iteration;
  380. // we therefore update 'a' here
  381. //
  382. a = b;
  383. }
  384. }
  385. TRACE1("DtlMergeSort: Ncmp=%d", Ncmp);
  386. }
  387. DTLNODE*
  388. DtlMoveToTail(
  389. IN DTLLIST* pdtllist,
  390. IN DTLNODE* pdtlnode
  391. )
  392. /* Moves a DTLNODE to the end of a list;
  393. ** Takes the list and the node to be moved, and returns the next node.
  394. */
  395. {
  396. DTLNODE* pdtltemp = NULL;
  397. if( NULL == pdtllist ||
  398. NULL == pdtlnode )
  399. {
  400. TRACE("NULL input pointers in DtlMovetoTail()");
  401. return NULL;
  402. }
  403. pdtltemp = DtlGetNextNode(pdtlnode);
  404. DtlRemoveNode(pdtllist, pdtlnode);
  405. DtlAddNodeLast(pdtllist, pdtlnode);
  406. return pdtltemp;
  407. }
  408. DTLNODE*
  409. DtlRemoveNode(
  410. IN OUT DTLLIST* pdtllist,
  411. IN OUT DTLNODE* pdtlnodeInList )
  412. /* Removes node 'pdtlnodeInList' from list 'pdtllist'.
  413. **
  414. ** Returns the address of the removed node, i.e. 'pdtlnodeInList'.
  415. */
  416. {
  417. if ( pdtllist && pdtlnodeInList )
  418. {
  419. if (pdtlnodeInList->pdtlnodePrev)
  420. pdtlnodeInList->pdtlnodePrev->pdtlnodeNext = pdtlnodeInList->pdtlnodeNext;
  421. else
  422. pdtllist->pdtlnodeFirst = pdtlnodeInList->pdtlnodeNext;
  423. if (pdtlnodeInList->pdtlnodeNext)
  424. pdtlnodeInList->pdtlnodeNext->pdtlnodePrev = pdtlnodeInList->pdtlnodePrev;
  425. else
  426. pdtllist->pdtlnodeLast = pdtlnodeInList->pdtlnodePrev;
  427. --pdtllist->lNodes;
  428. }
  429. return pdtlnodeInList;
  430. }
  431. VOID
  432. DtlSwapLists(
  433. IN OUT DTLLIST* pdtllist1,
  434. IN OUT DTLLIST* pdtllist2 )
  435. /* Swap the node chains between lists 'pdtllist1' and 'pdtllist2'.
  436. */
  437. {
  438. DTLLIST dtllist;
  439. if( NULL == pdtllist1 ||
  440. NULL == pdtllist2 )
  441. {
  442. return;
  443. }
  444. dtllist.pdtlnodeFirst = pdtllist1->pdtlnodeFirst;
  445. dtllist.pdtlnodeLast = pdtllist1->pdtlnodeLast;
  446. dtllist.lNodes = pdtllist1->lNodes;
  447. pdtllist1->pdtlnodeFirst = pdtllist2->pdtlnodeFirst;
  448. pdtllist1->pdtlnodeLast = pdtllist2->pdtlnodeLast;
  449. pdtllist1->lNodes = pdtllist2->lNodes;
  450. pdtllist2->pdtlnodeFirst = dtllist.pdtlnodeFirst;
  451. pdtllist2->pdtlnodeLast = dtllist.pdtlnodeLast;
  452. pdtllist2->lNodes = dtllist.lNodes;
  453. }