da.c
Upload User: xhy777
Upload Date: 2007-02-14
Package Size: 24088k
Code Size: 22k
Category:

Windows Kernel

Development Platform:

Visual C++

  1. // Dynamic Array APIs
  2. #include "ctlspriv.h"
  3. //
  4. // Heapsort is a bit slower, but it doesn't use any stack or memory...
  5. // Mergesort takes a bit of memory (O(n)) and stack (O(log(n)), but very fast...
  6. //
  7. #ifdef WIN32
  8. #define MERGESORT
  9. #else
  10. #define USEHEAPSORT
  11. #endif
  12. #ifdef DEBUG
  13. #define DSA_MAGIC   ('S' | ('A' << 256))
  14. #define IsDSA(pdsa) ((pdsa) && (pdsa)->magic == DSA_MAGIC)
  15. #define DPA_MAGIC   ('P' | ('A' << 256))
  16. #define IsDPA(pdpa) ((pdpa) && (pdpa)->magic == DPA_MAGIC)
  17. #else
  18. #define IsDSA(pdsa)
  19. #define IsDPA(pdsa)
  20. #endif
  21. typedef struct {
  22.     void FAR* FAR* pp;
  23.     PFNDPACOMPARE pfnCmp;
  24.     LPARAM lParam;
  25.     int cp;
  26. #ifdef MERGESORT
  27.     void FAR* FAR* ppT;
  28. #endif
  29. } SORTPARAMS;
  30. BOOL NEAR DPA_QuickSort(SORTPARAMS FAR* psp);
  31. BOOL NEAR DPA_QuickSort2(int i, int j, SORTPARAMS FAR* psp);
  32. BOOL NEAR DPA_HeapSort(SORTPARAMS FAR* psp);
  33. void NEAR DPA_HeapSortPushDown(int first, int last, SORTPARAMS FAR* psp);
  34. BOOL NEAR DPA_MergeSort(SORTPARAMS FAR* psp);
  35. void NEAR DPA_MergeSort2(SORTPARAMS FAR* psp, int iFirst, int cItems);
  36. //========== Dynamic structure array ====================================
  37. // Dynamic structure array
  38. typedef struct _DSA {
  39. // NOTE: The following field MUST be defined at the beginning of the
  40. // structure in order for GetItemCount() to work.
  41. //
  42.     int cItem; // # of elements in dsa
  43.     void FAR* aItem; // memory for elements
  44.     int cItemAlloc; // # items which fit in aItem
  45.     int cbItem; // size of each item
  46.     int cItemGrow; // # items to grow cItemAlloc by
  47. #ifdef DEBUG
  48.     UINT magic;
  49. #endif
  50. } DSA;
  51. #define DSA_PITEM(pdsa, index)    ((void FAR*)(((char FAR*)(pdsa)->aItem) + ((index) * (pdsa)->cbItem)))
  52. HDSA WINAPI DSA_Create(int cbItem, int cItemGrow)
  53. {
  54.     HDSA pdsa = Alloc(sizeof(DSA));
  55.     Assert(cbItem);
  56.     if (pdsa)
  57.     {
  58.         pdsa->cItem = 0;
  59.         pdsa->cItemAlloc = 0;
  60.         pdsa->cbItem = cbItem;
  61.         pdsa->cItemGrow = (cItemGrow == 0 ? 1 : cItemGrow);
  62.         pdsa->aItem = NULL;
  63. #ifdef DEBUG
  64.         pdsa->magic = DSA_MAGIC;
  65. #endif
  66.     }
  67.     return pdsa;
  68. }
  69. BOOL WINAPI DSA_Destroy(HDSA pdsa)
  70. {
  71.     Assert(IsDSA(pdsa));
  72.     if (pdsa == NULL)       // allow NULL for low memory cases, still assert
  73.         return TRUE;
  74. #ifdef DEBUG
  75.     pdsa->cItem = 0;
  76.     pdsa->cItemAlloc = 0;
  77.     pdsa->cbItem = 0;
  78.     pdsa->magic = 0;
  79. #endif
  80.     if (pdsa->aItem && !Free(pdsa->aItem))
  81.         return FALSE;
  82.     return Free(pdsa);
  83. }
  84. BOOL WINAPI DSA_GetItem(HDSA pdsa, int index, void FAR* pitem)
  85. {
  86.     Assert(IsDSA(pdsa));
  87.     Assert(pitem);
  88.     if (index < 0 || index >= pdsa->cItem)
  89.     {
  90.         DebugMsg(DM_ERROR, "DSA: Invalid index: %d", index);
  91.         return FALSE;
  92.     }
  93.     hmemcpy(pitem, DSA_PITEM(pdsa, index), pdsa->cbItem);
  94.     return TRUE;
  95. }
  96. void FAR* WINAPI DSA_GetItemPtr(HDSA pdsa, int index)
  97. {
  98.     Assert(IsDSA(pdsa));
  99.     if (index < 0 || index >= pdsa->cItem)
  100.     {
  101.         DebugMsg(DM_ERROR, "DSA: Invalid index: %d", index);
  102.         return NULL;
  103.     }
  104.     return DSA_PITEM(pdsa, index);
  105. }
  106. BOOL WINAPI DSA_SetItem(HDSA pdsa, int index, void FAR* pitem)
  107. {
  108.     Assert(pitem);
  109.     Assert(IsDSA(pdsa));
  110.     if (index < 0)
  111.     {
  112.         DebugMsg(DM_ERROR, "DSA: Invalid index: %d", index);
  113.         return FALSE;
  114.     }
  115.     if (index >= pdsa->cItem)
  116.     {
  117.         if (index + 1 > pdsa->cItemAlloc)
  118.         {
  119.             int cItemAlloc = (((index + 1) + pdsa->cItemGrow - 1) / pdsa->cItemGrow) * pdsa->cItemGrow;
  120.             void FAR* aItemNew = ReAlloc(pdsa->aItem, cItemAlloc * pdsa->cbItem);
  121.             if (!aItemNew)
  122.                 return FALSE;
  123.             pdsa->aItem = aItemNew;
  124.             pdsa->cItemAlloc = cItemAlloc;
  125.         }
  126.         pdsa->cItem = index + 1;
  127.     }
  128.     hmemcpy(DSA_PITEM(pdsa, index), pitem, pdsa->cbItem);
  129.     return TRUE;
  130. }
  131. int WINAPI DSA_InsertItem(HDSA pdsa, int index, void FAR* pitem)
  132. {
  133.     Assert(pitem);
  134.     Assert(IsDSA(pdsa));
  135.     if (index < 0)
  136.     {
  137.         DebugMsg(DM_ERROR, "DSA: Invalid index: %d", index);
  138.         return -1;
  139.     }
  140.     if (index > pdsa->cItem)
  141.         index = pdsa->cItem;
  142.     if (pdsa->cItem + 1 > pdsa->cItemAlloc)
  143.     {
  144.         void FAR* aItemNew = ReAlloc(pdsa->aItem,
  145.                 (pdsa->cItemAlloc + pdsa->cItemGrow) * pdsa->cbItem);
  146.         if (!aItemNew)
  147.             return -1;
  148.         pdsa->aItem = aItemNew;
  149.         pdsa->cItemAlloc += pdsa->cItemGrow;
  150.     }
  151.     if (index < pdsa->cItem)
  152.     {
  153.         hmemcpy(DSA_PITEM(pdsa, index + 1), DSA_PITEM(pdsa, index),
  154.             (pdsa->cItem - index) * pdsa->cbItem);
  155.     }
  156.     pdsa->cItem++;
  157.     hmemcpy(DSA_PITEM(pdsa, index), pitem, pdsa->cbItem);
  158.     return index;
  159. }
  160. BOOL WINAPI DSA_DeleteItem(HDSA pdsa, int index)
  161. {
  162.     Assert(IsDSA(pdsa));
  163.     if (index < 0 || index >= pdsa->cItem)
  164.     {
  165.         DebugMsg(DM_ERROR, "DSA: Invalid index: %d", index);
  166.         return FALSE;
  167.     }
  168.     if (index < pdsa->cItem - 1)
  169.     {
  170.         hmemcpy(DSA_PITEM(pdsa, index), DSA_PITEM(pdsa, index + 1),
  171.             (pdsa->cItem - (index + 1)) * pdsa->cbItem);
  172.     }
  173.     pdsa->cItem--;
  174.     if (pdsa->cItemAlloc - pdsa->cItem > pdsa->cItemGrow)
  175.     {
  176.         void FAR* aItemNew = ReAlloc(pdsa->aItem,
  177.                 (pdsa->cItemAlloc - pdsa->cItemGrow) * pdsa->cbItem);
  178.         Assert(aItemNew);
  179.         pdsa->aItem = aItemNew;
  180.         pdsa->cItemAlloc -= pdsa->cItemGrow;
  181.     }
  182.     return TRUE;
  183. }
  184. BOOL WINAPI DSA_DeleteAllItems(HDSA pdsa)
  185. {
  186.     Assert(IsDSA(pdsa));
  187.     if (pdsa->aItem && !Free(pdsa->aItem))
  188.         return FALSE;
  189.     pdsa->aItem = NULL;
  190.     pdsa->cItem = pdsa->cItemAlloc = 0;
  191.     return TRUE;
  192. }
  193. //================== Dynamic pointer array implementation ===========
  194. typedef struct _DPA {
  195. // NOTE: The following two fields MUST be defined in this order, at
  196. // the beginning of the structure in order for the macro APIs to work.
  197. //
  198.     int cp;
  199.     void FAR* FAR* pp;
  200.     HANDLE hheap;        // Heap to allocate from if NULL use shared
  201.     int cpAlloc;
  202.     int cpGrow;
  203. #ifdef DEBUG
  204.     UINT magic;
  205. #endif
  206. } DPA;
  207. HDPA WINAPI DPA_Create(int cpGrow)
  208. {
  209.     HDPA pdpa = Alloc(sizeof(DPA));
  210.     if (pdpa)
  211.     {
  212.         pdpa->cp = 0;
  213.         pdpa->cpAlloc = 0;
  214.         pdpa->cpGrow = (cpGrow < 8 ? 8 : cpGrow);
  215.         pdpa->pp = NULL;
  216. #ifdef WIN32
  217.         pdpa->hheap = g_hSharedHeap;   // Defaults to use shared one (for now...)
  218. #else
  219.         pdpa->hheap = NULL;       // Defaults to use shared one (for now...)
  220. #endif
  221. #ifdef DEBUG
  222.         pdpa->magic = DPA_MAGIC;
  223. #endif
  224.     }
  225.     return pdpa;
  226. }
  227. // Should nuke the standard DPA above...
  228. HDPA WINAPI DPA_CreateEx(int cpGrow, HANDLE hheap)
  229. {
  230.     HDPA pdpa;
  231.     if (hheap == NULL)
  232.     {
  233.         pdpa = Alloc(sizeof(DPA));
  234. #ifdef WIN32
  235.         hheap = g_hSharedHeap;
  236. #endif
  237.     }
  238.     else
  239.         pdpa = ControlAlloc(hheap, sizeof(DPA));
  240.     if (pdpa)
  241.     {
  242.         pdpa->cp = 0;
  243.         pdpa->cpAlloc = 0;
  244.         pdpa->cpGrow = (cpGrow < 8 ? 8 : cpGrow);
  245.         pdpa->pp = NULL;
  246.         pdpa->hheap = hheap;
  247. #ifdef DEBUG
  248.         pdpa->magic = DPA_MAGIC;
  249. #endif
  250.     }
  251.     return pdpa;
  252. }
  253. BOOL WINAPI DPA_Destroy(HDPA pdpa)
  254. {
  255.     Assert(IsDPA(pdpa));
  256.     if (pdpa == NULL)       // allow NULL for low memory cases, still assert
  257.         return TRUE;
  258. #ifdef WIN32
  259.     Assert (pdpa->hheap);
  260. #endif
  261. #ifdef DEBUG
  262.     pdpa->cp = 0;
  263.     pdpa->cpAlloc = 0;
  264.     pdpa->magic = 0;
  265. #endif
  266.     if (pdpa->pp && !ControlFree(pdpa->hheap, pdpa->pp))
  267.         return FALSE;
  268.     return ControlFree(pdpa->hheap, pdpa);
  269. }
  270. HDPA WINAPI DPA_Clone(HDPA pdpa, HDPA pdpaNew)
  271. {
  272.     BOOL fAlloc = FALSE;
  273.     if (!pdpaNew)
  274.     {
  275.         pdpaNew = DPA_CreateEx(pdpa->cpGrow, pdpa->hheap);
  276.         if (!pdpaNew)
  277.             return NULL;
  278.         fAlloc = TRUE;
  279.     }
  280.     if (!DPA_Grow(pdpaNew, pdpa->cpAlloc)) {
  281. if (!fAlloc)
  282.     DPA_Destroy(pdpaNew);
  283. return NULL;
  284.     }
  285.     pdpaNew->cp = pdpa->cp;
  286.     hmemcpy(pdpaNew->pp, pdpa->pp, pdpa->cp * sizeof(void FAR*));
  287.     return pdpaNew;
  288. }
  289. void FAR* WINAPI DPA_GetPtr(HDPA pdpa, int index)
  290. {
  291.     Assert(IsDPA(pdpa));
  292.     if (index < 0 || index >= pdpa->cp)
  293.         return NULL;
  294.     return pdpa->pp[index];
  295. }
  296. int WINAPI DPA_GetPtrIndex(HDPA pdpa, void FAR* p)
  297. {
  298.     void FAR* FAR* pp;
  299.     void FAR* FAR* ppMax;
  300.     Assert(IsDPA(pdpa));
  301.     if (pdpa->pp)
  302.     {
  303.         pp = pdpa->pp;
  304.         ppMax = pp + pdpa->cp;
  305.         for ( ; pp < ppMax; pp++)
  306.         {
  307.             if (*pp == p)
  308.                 return (pp - pdpa->pp);
  309.         }
  310.     }
  311.     return -1;
  312. }
  313. BOOL WINAPI DPA_Grow(HDPA pdpa, int cpAlloc)
  314. {
  315.     Assert(IsDPA(pdpa));
  316.     if (cpAlloc > pdpa->cpAlloc)
  317.     {
  318.         void FAR* FAR* ppNew;
  319.         cpAlloc = ((cpAlloc + pdpa->cpGrow - 1) / pdpa->cpGrow) * pdpa->cpGrow;
  320.         if (pdpa->pp)
  321.             ppNew = (void FAR* FAR*)ControlReAlloc(pdpa->hheap, pdpa->pp, cpAlloc * sizeof(void FAR*));
  322.         else
  323.             ppNew = (void FAR* FAR*)ControlAlloc(pdpa->hheap, cpAlloc * sizeof(void FAR*));
  324.         if (!ppNew)
  325.             return FALSE;
  326.         pdpa->pp = ppNew;
  327.         pdpa->cpAlloc = cpAlloc;
  328.     }
  329.     return TRUE;
  330. }
  331. BOOL WINAPI DPA_SetPtr(HDPA pdpa, int index, void FAR* p)
  332. {
  333.     Assert(IsDPA(pdpa));
  334.     if (index < 0)
  335.     {
  336.         DebugMsg(DM_ERROR, "DPA: Invalid index: %d", index);
  337.         return FALSE;
  338.     }
  339.     if (index >= pdpa->cp)
  340.     {
  341.         if (!DPA_Grow(pdpa, index + 1))
  342.             return FALSE;
  343.         pdpa->cp = index + 1;
  344.     }
  345.     pdpa->pp[index] = p;
  346.     return TRUE;
  347. }
  348. int WINAPI DPA_InsertPtr(HDPA pdpa, int index, void FAR* p)
  349. {
  350.     Assert(IsDPA(pdpa));
  351.     if (index < 0)
  352.     {
  353.         DebugMsg(DM_ERROR, "DPA: Invalid index: %d", index);
  354.         return -1;
  355.     }
  356.     if (index > pdpa->cp)
  357.         index = pdpa->cp;
  358.     // Make sure we have room for one more item
  359.     //
  360.     if (pdpa->cp + 1 > pdpa->cpAlloc)
  361.     {
  362.         if (!DPA_Grow(pdpa, pdpa->cp + 1))
  363.             return -1;
  364.     }
  365.     // If we are inserting, we need to slide everybody up
  366.     //
  367.     if (index < pdpa->cp)
  368.     {
  369. #ifndef IEWIN31_25
  370.         hmemcpy(&pdpa->pp[index + 1], &pdpa->pp[index],
  371.             (pdpa->cp - index) * sizeof(void FAR*));
  372. #else
  373.         // memcpy is *UNDEFINED* for overlapping copies!
  374.         // hopefully we'll never have too many things to move.
  375.         // (the size is max 32767 *  sizeof (pointer), or 128k...)
  376.         _fmemmove(&pdpa->pp[index + 1], &pdpa->pp[index],
  377.             (pdpa->cp - index) * sizeof(void FAR*));
  378. #endif
  379.     }
  380.     pdpa->pp[index] = p;
  381.     pdpa->cp++;
  382.     return index;
  383. }
  384. void FAR* WINAPI DPA_DeletePtr(HDPA pdpa, int index)
  385. {
  386.     void FAR* p;
  387.     Assert(IsDPA(pdpa));
  388.     if (index < 0 || index >= pdpa->cp)
  389.     {
  390.         DebugMsg(DM_ERROR, "DPA: Invalid index: %d", index);
  391.         return NULL;
  392.     }
  393.     p = pdpa->pp[index];
  394.     if (index < pdpa->cp - 1)
  395.     {
  396.         hmemcpy(&pdpa->pp[index], &pdpa->pp[index + 1],
  397.             (pdpa->cp - (index + 1)) * sizeof(void FAR*));
  398.     }
  399.     pdpa->cp--;
  400.     if (pdpa->cpAlloc - pdpa->cp > pdpa->cpGrow)
  401.     {
  402.         void FAR* FAR* ppNew;
  403.         ppNew = ControlReAlloc(pdpa->hheap, pdpa->pp, (pdpa->cpAlloc - pdpa->cpGrow) * sizeof(void FAR*));
  404.         Assert(ppNew);
  405.         pdpa->pp = ppNew;
  406.         pdpa->cpAlloc -= pdpa->cpGrow;
  407.     }
  408.     return p;
  409. }
  410. BOOL WINAPI DPA_DeleteAllPtrs(HDPA pdpa)
  411. {
  412.     Assert(IsDPA(pdpa));
  413.     if (pdpa->pp && !ControlFree(pdpa->hheap, pdpa->pp))
  414.         return FALSE;
  415.     pdpa->pp = NULL;
  416.     pdpa->cp = pdpa->cpAlloc = 0;
  417.     return TRUE;
  418. }
  419. BOOL WINAPI DPA_Sort(HDPA pdpa, PFNDPACOMPARE pfnCmp, LPARAM lParam)
  420. {
  421.     SORTPARAMS sp;
  422.     sp.cp = pdpa->cp;
  423.     sp.pp = pdpa->pp;
  424.     sp.pfnCmp = pfnCmp;
  425.     sp.lParam = lParam;
  426. #ifdef USEQUICKSORT
  427.     return DPA_QuickSort(&sp);
  428. #endif
  429. #ifdef USEHEAPSORT
  430.     return DPA_HeapSort(&sp);
  431. #endif
  432. #ifdef MERGESORT
  433.     return DPA_MergeSort(&sp);
  434. #endif
  435. }
  436. #ifdef USEQUICKSORT
  437. BOOL NEAR DPA_QuickSort(SORTPARAMS FAR* psp)
  438. {
  439.     return DPA_QuickSort2(0, psp->cp - 1, psp);
  440. }
  441. BOOL NEAR DPA_QuickSort2(int i, int j, SORTPARAMS FAR* psp)
  442. {
  443.     void FAR* FAR* pp = psp->pp;
  444.     LPARAM lParam = psp->lParam;
  445.     PFNDPACOMPARE pfnCmp = psp->pfnCmp;
  446.     int iPivot;
  447.     void FAR* pFirst;
  448.     int k;
  449.     int result;
  450.     iPivot = -1;
  451.     pFirst = pp[i];
  452.     for (k = i + 1; k <= j; k++)
  453.     {
  454.         result = (*pfnCmp)(pp[k], pFirst, lParam);
  455.         if (result > 0)
  456.         {
  457.             iPivot = k;
  458.             break;
  459.         }
  460.         else if (result < 0)
  461.         {
  462.             iPivot = i;
  463.             break;
  464.         }
  465.     }
  466.     if (iPivot != -1)
  467.     {
  468.         int l = i;
  469.         int r = j;
  470.         void FAR* pivot = pp[iPivot];
  471.         do
  472.         {
  473.             void FAR* p;
  474.             p = pp[l];
  475.             pp[l] = pp[r];
  476.             pp[r] = p;
  477.             while ((*pfnCmp)(pp[l], pivot, lParam) < 0)
  478.                 l++;
  479.             while ((*pfnCmp)(pp[r], pivot, lParam) >= 0)
  480.                 r--;
  481.         } while (l <= r);
  482.         if (l - 1 > i)
  483.             DPA_QuickSort2(i, l - 1, psp);
  484.         if (j > l)
  485.             DPA_QuickSort2(l, j, psp);
  486.     }
  487.     return TRUE;
  488. }
  489. #endif  // USEQUICKSORT
  490. #ifdef USEHEAPSORT
  491. void NEAR DPA_HeapSortPushDown(int first, int last, SORTPARAMS FAR* psp)
  492. {
  493.     void FAR* FAR* pp = psp->pp;
  494.     LPARAM lParam = psp->lParam;
  495.     PFNDPACOMPARE pfnCmp = psp->pfnCmp;
  496.     int r;
  497.     int r2;
  498.     void FAR* p;
  499.     r = first;
  500.     while (r <= last / 2)
  501.     {
  502.         int wRTo2R;
  503.         r2 = r * 2;
  504.         wRTo2R = (*pfnCmp)(pp[r-1], pp[r2-1], lParam);
  505.         if (r2 == last)
  506.         {
  507.             if (wRTo2R < 0)
  508.             {
  509.                 p = pp[r-1]; pp[r-1] = pp[r2-1]; pp[r2-1] = p;
  510.             }
  511.             break;
  512.         }
  513.         else
  514.         {
  515.             int wR2toR21 = (*pfnCmp)(pp[r2-1], pp[r2+1-1], lParam);
  516.             if (wRTo2R < 0 && wR2toR21 >= 0)
  517.             {
  518.                 p = pp[r-1]; pp[r-1] = pp[r2-1]; pp[r2-1] = p;
  519.                 r = r2;
  520.             }
  521.             else if ((*pfnCmp)(pp[r-1], pp[r2+1-1], lParam) < 0 && wR2toR21 < 0)
  522.             {
  523.                 p = pp[r-1]; pp[r-1] = pp[r2+1-1]; pp[r2+1-1] = p;
  524.                 r = r2 + 1;
  525.             }
  526.             else
  527.             {
  528.                 break;
  529.             }
  530.         }
  531.     }
  532. }
  533. BOOL NEAR DPA_HeapSort(SORTPARAMS FAR* psp)
  534. {
  535.     void FAR* FAR* pp = psp->pp;
  536.     int c = psp->cp;
  537.     int i;
  538.     for (i = c / 2; i >= 1; i--)
  539.         DPA_HeapSortPushDown(i, c, psp);
  540.     for (i = c; i >= 2; i--)
  541.     {
  542.         void FAR* p = pp[0]; pp[0] = pp[i-1]; pp[i-1] = p;
  543.         DPA_HeapSortPushDown(1, i - 1, psp);
  544.     }
  545.     return TRUE;
  546. }
  547. #endif  // USEHEAPSORT
  548. #if defined(MERGESORT) && defined(WIN32)
  549. #define SortCompare(psp, pp1, i1, pp2, i2) 
  550. (psp->pfnCmp(pp1[i1], pp2[i2], psp->lParam))
  551. //
  552. //  This function merges two sorted lists and makes one sorted list.
  553. //   psp->pp[iFirst, iFirst+cItes/2-1], psp->pp[iFirst+cItems/2, iFirst+cItems-1]
  554. //
  555. void NEAR DPA_MergeThem(SORTPARAMS FAR* psp, int iFirst, int cItems)
  556. {
  557.     //
  558.     // Notes:
  559.     //  This function is separated from DPA_MergeSort2() to avoid comsuming
  560.     // stack variables. Never inline this.
  561.     //
  562.     int cHalf = cItems/2;
  563.     int iIn1, iIn2, iOut;
  564.     LPVOID * ppvSrc = &psp->pp[iFirst];
  565.     // Copy the first part to temp storage so we can write directly into
  566.     // the final buffer.  Note that this takes at most psp->cp/2 DWORD's
  567.     hmemcpy(psp->ppT, ppvSrc, cHalf*sizeof(LPVOID));
  568.     for (iIn1=0, iIn2=cHalf, iOut=0;;)
  569.     {
  570. if (SortCompare(psp, psp->ppT, iIn1, ppvSrc, iIn2) <= 0) {
  571.     ppvSrc[iOut++] = psp->ppT[iIn1++];
  572.     if (iIn1==cHalf) {
  573. // We used up the first half; the rest of the second half
  574. // should already be in place
  575. break;
  576.     }
  577. } else {
  578.     ppvSrc[iOut++] = ppvSrc[iIn2++];
  579.     if (iIn2==cItems) {
  580. // We used up the second half; copy the rest of the first half
  581. // into place
  582. hmemcpy(&ppvSrc[iOut], &psp->ppT[iIn1], (cItems-iOut)*sizeof(LPVOID));
  583. break;
  584.     }
  585. }
  586.     }
  587. }
  588. //
  589. //  This function sorts a give list (psp->pp[iFirst,iFirst-cItems-1]).
  590. //
  591. void NEAR DPA_MergeSort2(SORTPARAMS FAR* psp, int iFirst, int cItems)
  592. {
  593.     //
  594.     // Notes:
  595.     //   This function is recursively called. Therefore, we should minimize
  596.     //  the number of local variables and parameters. At this point, we
  597.     //  use one local variable and three parameters.
  598.     //
  599.     int cHalf;
  600.     switch(cItems)
  601.     {
  602.     case 1:
  603. return;
  604.     case 2:
  605. // Swap them, if they are out of order.
  606. if (SortCompare(psp, psp->pp, iFirst, psp->pp, iFirst+1) > 0)
  607. {
  608.     psp->ppT[0] = psp->pp[iFirst];
  609.     psp->pp[iFirst] = psp->pp[iFirst+1];
  610.     psp->pp[iFirst+1] = psp->ppT[0];
  611. }
  612. break;
  613.     default:
  614.      cHalf = cItems/2;
  615. // Sort each half
  616. DPA_MergeSort2(psp, iFirst, cHalf);
  617. DPA_MergeSort2(psp, iFirst+cHalf, cItems-cHalf);
  618. // Then, merge them.
  619. DPA_MergeThem(psp, iFirst, cItems);
  620. break;
  621.     }
  622. }
  623. BOOL NEAR DPA_MergeSort(SORTPARAMS FAR* psp)
  624. {
  625.     if (psp->cp==0)
  626. return TRUE;
  627.     // Note that we divide by 2 below; we want to round down
  628.     psp->ppT = LocalAlloc(LPTR, psp->cp/2 * sizeof(LPVOID));
  629.     if (!psp->ppT)
  630. return FALSE;
  631.     DPA_MergeSort2(psp, 0, psp->cp);
  632.     LocalFree(psp->ppT);
  633.     return TRUE;
  634. }
  635. #endif // MERGESORT
  636. // Search function
  637. //
  638. int WINAPI DPA_Search(HDPA pdpa, void FAR* pFind, int iStart,
  639.             PFNDPACOMPARE pfnCompare, LPARAM lParam, UINT options)
  640. {
  641.     int cp = DPA_GetPtrCount(pdpa);
  642.     Assert(pfnCompare);
  643.     Assert(0 <= iStart);
  644.     // Only allow these wierd flags if the list is sorted
  645.     Assert((options & DPAS_SORTED) || !(options & (DPAS_INSERTBEFORE | DPAS_INSERTAFTER)));
  646.     if (!(options & DPAS_SORTED))
  647.     {
  648.         // Not sorted: do linear search.
  649.         int i;
  650.         for (i = iStart; i < cp; i++)
  651.         {
  652.             if (0 == pfnCompare(pFind, DPA_FastGetPtr(pdpa, i), lParam))
  653.                 return i;
  654.         }
  655.         return -1;
  656.     }
  657.     else
  658.     {
  659.         // Search the array using binary search.  If several adjacent 
  660.         // elements match the target element, the index of the first
  661.         // matching element is returned.
  662.         int iRet = -1;      // assume no match
  663.         BOOL bFound = FALSE;
  664.         int nCmp = 0;
  665.         int iLow = 0;       // Don't bother using iStart for binary search
  666.         int iMid = 0;
  667.         int iHigh = cp - 1;
  668.         // (OK for cp == 0)
  669.         while (iLow <= iHigh)
  670.         {
  671.             iMid = (iLow + iHigh) / 2;
  672.             nCmp = pfnCompare(pFind, DPA_FastGetPtr(pdpa, iMid), lParam);
  673.             if (0 > nCmp)
  674.                 iHigh = iMid - 1;       // First is smaller
  675.             else if (0 < nCmp)
  676.                 iLow = iMid + 1;        // First is larger
  677.             else
  678.             {
  679.                 // Match; search back for first match
  680.                 bFound = TRUE;
  681.                 while (0 < iMid)
  682.                 {
  683.                     if (0 != pfnCompare(pFind, DPA_FastGetPtr(pdpa, iMid-1), lParam))
  684.                         break;
  685.                     else
  686.                         iMid--;
  687.                 }
  688.                 break;
  689.             }
  690.         }
  691.         if (bFound)
  692.         {
  693.             Assert(0 <= iMid);
  694.             iRet = iMid;
  695.         }
  696.         // Did the search fail AND
  697.         // is one of the strange search flags set?
  698.         if (!bFound && (options & (DPAS_INSERTAFTER | DPAS_INSERTBEFORE)))
  699.         {
  700.             // Yes; return the index where the target should be inserted
  701.             // if not found
  702.             if (0 < nCmp)       // First is larger
  703.                 iRet = iLow;
  704.             else
  705.                 iRet = iMid;
  706.             // (We don't distinguish between the two flags anymore)
  707.         }
  708.         else if ( !(options & (DPAS_INSERTAFTER | DPAS_INSERTBEFORE)) )
  709.         {
  710.             // Sanity check with linear search
  711.             Assert(DPA_Search(pdpa, pFind, iStart, pfnCompare, lParam, options & ~DPAS_SORTED) == iRet);
  712.         }
  713.         return iRet;
  714.     }
  715. }
  716. //===========================================================================
  717. //
  718. // String ptr management routines
  719. //
  720. // Copy as much of *psz to *pszBuf as will fit
  721. //
  722. int WINAPI Str_GetPtr(LPCSTR psz, LPSTR pszBuf, int cchBuf)
  723. {
  724.     int cch = 0;
  725.     // if pszBuf is NULL, just return length of string.
  726.     //
  727.     if (!pszBuf && psz)
  728.         return lstrlen(psz);
  729.     if (cchBuf)
  730.     {
  731.         if (psz)
  732.         {
  733.             cch = lstrlen(psz);
  734.             if (cch > cchBuf - 1)
  735.                 cch = cchBuf - 1;
  736.             hmemcpy(pszBuf, psz, cch);
  737.         }
  738.         pszBuf[cch] = 0;
  739.     }
  740.     return cch;
  741. }
  742. #ifdef WIN32
  743. BOOL Str_Set(LPSTR *ppsz, LPCSTR psz)
  744. {
  745.     if (!psz)
  746.     {
  747.         if (*ppsz)
  748.         {
  749.             LocalFree(*ppsz);
  750.             *ppsz = NULL;
  751.         }
  752.     }
  753.     else
  754.     {
  755. LPSTR pszNew;
  756.         UINT cbSize = lstrlen(psz) + 1;
  757. if (*ppsz)
  758.     pszNew = LocalReAlloc(*ppsz, cbSize, LMEM_MOVEABLE | LMEM_ZEROINIT);
  759. else
  760.     pszNew = LocalAlloc(LPTR, cbSize);
  761.         if (!pszNew)
  762.             return FALSE;
  763.         lstrcpy(pszNew, psz);
  764.         *ppsz = pszNew;
  765.     }
  766.     return TRUE;
  767. }
  768. #endif
  769. // Set *ppsz to a copy of psz, reallocing as needed
  770. //
  771. BOOL WINAPI Str_SetPtr(LPSTR FAR* ppsz, LPCSTR psz)
  772. {
  773.     if (!psz)
  774.     {
  775.         if (*ppsz)
  776.         {
  777.             Free(*ppsz);
  778.             *ppsz = NULL;
  779.         }
  780.     }
  781.     else
  782.     {
  783.         LPSTR pszNew = (LPSTR)ReAlloc(*ppsz, lstrlen(psz) + 1);
  784.         if (!pszNew)
  785.             return FALSE;
  786.         lstrcpy(pszNew, psz);
  787.         *ppsz = pszNew;
  788.     }
  789.     return TRUE;
  790. }