Changeset 55


Ignore:
Timestamp:
Apr 6, 2001, 7:12:11 PM (24 years ago)
Author:
umoeller
Message:

misc changes

Location:
trunk
Files:
8 edited

Legend:

Unmodified
Added
Removed
  • trunk/include/helpers/dosh.h

    r54 r55  
    4343    BOOL doshQueryShiftState(VOID);
    4444
    45     BOOL doshIsWarp4(VOID);
     45    ULONG doshIsWarp4(VOID);
    4646
    4747    PSZ doshQuerySysErrorMsg(APIRET arc);
     
    297297
    298298    PSZ doshCreateBackupFileName(const char* pszExisting);
     299
     300    APIRET doshCreateTempFileName(PSZ pszTempFileName,
     301                                  const char *pcszDir,
     302                                  const char *pcszPrefix,
     303                                  const char *pcszExt);
    299304
    300305    APIRET doshWriteTextFile(const char* pszFile,
  • trunk/include/helpers/tree.h

    r54 r55  
    178178    void *treeLast     (TREE *tree);
    179179
     180    TREE** treeBuildArray(TREE* pRoot,
     181                          unsigned long *pulCount);
     182
    180183    //  Return codes
    181184    #define TREE_OK                 0
  • trunk/src/helpers/dialog.c

    r54 r55  
    157157typedef struct _ROWDEF
    158158{
    159     PTABLEDEF   pOwningTable;   // table whose linked list this row belongs to
    160 
    161     LINKLIST    llColumns;      // contains COLUMNDEF structs, no auto-free
     159    PTABLEDEF   pOwningTable;       // table whose linked list this row belongs to
     160
     161    LINKLIST    llColumns;          // contains COLUMNDEF structs, no auto-free
     162
     163    ULONG       flRowFormat;        // one of:
     164                                    // -- ROW_VALIGN_BOTTOM           0x0000
     165                                    // -- ROW_VALIGN_CENTER           0x0001
     166                                    // -- ROW_VALIGN_TOP              0x0002
    162167
    163168    CONTROLPOS  cpRow;
     
    188193{
    189194    PROCESS_CALC_SIZES,             // step 1
    190     PROCESS_CALC_POSITIONS,         // step 2
    191     PROCESS_CREATE_CONTROLS         // step 3
     195    PROCESS_CALC_POSITIONS,         // step 3
     196    PROCESS_CREATE_CONTROLS         // step 4
    192197} PROCESSMODE;
    193198
     
    212217
    213218VOID CalcAutoSizeText(PCONTROLDEF pControlDef,
     219                      BOOL fMultiLine,          // in: if TRUE, multiple lines
    214220                      PSIZEL pszlAuto,          // out: computed size
    215221                      PDLGPRIVATE pDlgData)
     
    265271    if (pControlDef->pcszText)
    266272    {
    267         POINTL aptl[TXTBOX_COUNT];
    268         GpiQueryTextBox(pDlgData->hps,
    269                         strlen(pControlDef->pcszText),
    270                         (PCH)pControlDef->pcszText,
    271                         TXTBOX_COUNT,
    272                         aptl);
    273         pszlAuto->cx = aptl[TXTBOX_TOPRIGHT].x - aptl[TXTBOX_BOTTOMLEFT].x;
     273        // do we have multiple lines?
     274        if (fMultiLine)
     275        {
     276            RECTL rcl = {0, 0, 1000, 1000};
     277            winhDrawFormattedText(pDlgData->hps,
     278                                  &rcl,
     279                                  pControlDef->pcszText,
     280                                  DT_LEFT | DT_TOP | DT_WORDBREAK | DT_QUERYEXTENT);
     281            pszlAuto->cx = rcl.xRight - rcl.xLeft;
     282            pszlAuto->cy = rcl.yTop - rcl.yBottom;
     283        }
     284        else
     285        {
     286            POINTL aptl[TXTBOX_COUNT];
     287            GpiQueryTextBox(pDlgData->hps,
     288                            strlen(pControlDef->pcszText),
     289                            (PCH)pControlDef->pcszText,
     290                            TXTBOX_COUNT,
     291                            aptl);
     292            pszlAuto->cx = aptl[TXTBOX_TOPRIGHT].x - aptl[TXTBOX_BOTTOMLEFT].x;
     293        }
    274294    }
    275295}
     
    292312        case 0xffff0003L: // WC_BUTTON:
    293313            CalcAutoSizeText(pControlDef,
     314                             FALSE,         // no multiline
    294315                             pszlAuto,
    295316                             pDlgData);
     
    316337            if (pControlDef->flStyle & SS_TEXT)
    317338                CalcAutoSizeText(pControlDef,
     339                                 ((pControlDef->flStyle & DT_WORDBREAK) != 0),
    318340                                 pszlAuto,
    319341                                 pDlgData);
     
    384406    pColumnDef->pOwningRow = pOwningRow;
    385407
    386     // for PROCESS_CALC_SIZES: have control return its size
    387     //      plus spacings into szlControl
    388     // for PROCESS_CALC_POSITIONS: have control compute its
    389     //      position from the column position (there may be
    390     //      spacings)
    391     // for PROCESS_CREATE_CONTROLS: well, create the control
    392408    switch (ProcessMode)
    393409    {
     410        /*
     411         * PROCESS_CALC_SIZES:
     412         *      step 1.
     413         */
     414
    394415        case PROCESS_CALC_SIZES:
    395416        {
     
    454475        break; }
    455476
     477        /*
     478         * PROCESS_CALC_POSITIONS:
     479         *      step 2.
     480         */
     481
    456482        case PROCESS_CALC_POSITIONS:
    457483        {
     
    459485            ULONG ulSpacing = 0;
    460486
    461             // column position = *plX
     487            // column position = *plX on ProcessRow stack
    462488            pColumnDef->cpColumn.x = *plX;
    463489            pColumnDef->cpColumn.y = pOwningRow->cpRow.y;
     490
     491            // check vertical alignment of row;
     492            // we might need to increase column y
     493            switch (pOwningRow->flRowFormat & ROW_VALIGN_MASK)
     494            {
     495                // case ROW_VALIGN_BOTTOM:      // do nothing
     496
     497                case ROW_VALIGN_CENTER:
     498                    if (pColumnDef->cpColumn.cy < pOwningRow->cpRow.cy)
     499                        pColumnDef->cpColumn.y
     500                            += (   (pOwningRow->cpRow.cy - pColumnDef->cpColumn.cy)
     501                                 / 2);
     502                break;
     503
     504                case ROW_VALIGN_TOP:
     505                    if (pColumnDef->cpColumn.cy < pOwningRow->cpRow.cy)
     506                        pColumnDef->cpColumn.y
     507                            += (pOwningRow->cpRow.cy - pColumnDef->cpColumn.cy);
     508                break;
     509            }
    464510
    465511            if (pColumnDef->fIsNestedTable)
     
    481527            *plX += pColumnDef->cpColumn.cx;
    482528
    483             // calculate control pos by applying spacing
     529            // calculate CONTROL pos from COLUMN pos by applying spacing
    484530            pColumnDef->cpControl.x =   pColumnDef->cpColumn.x
    485531                                      + ulSpacing;
     
    499545            }
    500546        break; }
     547
     548        /*
     549         * PROCESS_CREATE_CONTROLS:
     550         *      step 3.
     551         */
    501552
    502553        case PROCESS_CREATE_CONTROLS:
     
    11761227                        lstInit(&pCurrentRow->llColumns, FALSE);
    11771228
     1229                        pCurrentRow->flRowFormat = pItemThis->ulData;
     1230
    11781231                        lstAppendItem(&pCurrentTable->llRows, pCurrentRow);
    11791232                    }
  • trunk/src/helpers/dosh.c

    r54 r55  
    144144}
    145145
    146 
    147146/*
    148147 *@@ doshIsWarp4:
    149  *      returns TRUE only if at least OS/2 Warp 4 is running.
     148 *      checks the OS/2 system version number.
     149 *
     150 *      Returns:
     151 *
     152 *      -- 0 (FALSE): OS/2 2.x or Warp 3 is running.
     153 *
     154 *      -- 1: Warp 4.0 is running.
     155 *
     156 *      -- 2: Warp 4.5 is running (WSeB or Warp 4 FP 13+ or eCS
     157 *            or ACP/MCP), or even something newer.
    150158 *
    151159 *@@changed V0.9.2 (2000-03-05) [umoeller]: reported TRUE on Warp 3 also; fixed
    152160 *@@changed V0.9.6 (2000-10-16) [umoeller]: patched for speed
    153  */
    154 
    155 BOOL doshIsWarp4(VOID)
    156 {
    157     static BOOL s_brc = FALSE;
    158     static BOOL s_fQueried = FALSE;
     161 *@@changed V0.9.9 (2001-04-04) [umoeller]: now returning 2 for Warp 4.5 and above
     162 */
     163
     164ULONG doshIsWarp4(VOID)
     165{
     166    static BOOL     s_fQueried = FALSE;
     167    static ULONG    s_ulrc = 0;
     168
    159169    if (!s_fQueried)
    160170    {
     
    170180
    171181        if     (    (aulBuf[0] > 20)        // major > 20; not the case with Warp 3, 4, 5
    172                  || (   (aulBuf[0] == 20)   // major == 20 and minor >= 40
    173                      && (aulBuf[1] >= 40)
     182                 || (   (aulBuf[0] == 20)   // major == 20 and minor >= 45
     183                     && (aulBuf[1] >= 45)
    174184                    )
    175185               )
    176             s_brc = TRUE;
     186            // Warp 4.5 or newer:
     187            s_ulrc = 2;
     188        else if (   (aulBuf[0] == 20)   // major == 20 and minor == 40
     189                 && (aulBuf[1] == 40)
     190                )
     191            // Warp 4:
     192            s_ulrc = 1;
    177193
    178194        s_fQueried = TRUE;
    179195    }
    180196
    181     return (s_brc);
     197    return (s_ulrc);
    182198}
    183199
     
    11421158
    11431159    return (strdup(szFilename));
     1160}
     1161
     1162/*
     1163 *@@ doshCreateTempFileName:
     1164 *      produces a file name in the the specified directory
     1165 *      or $(TEMP) which presently doesn't exist. This
     1166 *      checks the directory for existing files, but does
     1167 *      not open the temp file.
     1168 *
     1169 *      If (pcszDir != NULL), we look into that directory.
     1170 *      Otherwise we look into the directory specified
     1171 *      by the $(TEMP) environment variable.
     1172 *      If $(TEMP) is not set, $(TMP) is tried next.
     1173 *
     1174 *      If the directory thus specified does not exist, the
     1175 *      root directory of the boot drive is used instead.
     1176 *      As a result, this function should be fairly bomb-proof.
     1177 *
     1178 *      If (pcszExt != NULL), the temp file receives
     1179 *      that extension, or no extension otherwise.
     1180 *      Do not specify the dot in pcszExt.
     1181 *
     1182 *      pszTempFileName receives the fully qualified
     1183 *      file name of the temp file in that directory
     1184 *      and must point to a buffer CCHMAXPATH in size.
     1185 *      The file name is 8+3 compliant if pcszExt does
     1186 *      not exceed three characters.
     1187 *
     1188 *      If (pcszPrefix != NULL), the temp file name
     1189 *      is prefixed with pcszPrefix. Since the temp
     1190 *      file name must not exceed 8+3 letters, we
     1191 *      can only use ( 8 - strlen(pcszPrefix ) digits
     1192 *      for a random number to make the temp file name
     1193 *      unique. You must therefore use a maximum of
     1194 *      four characters for the prefix. Otherwise
     1195 *      ERROR_INVALID_PARAMETER is returned.
     1196 *
     1197 *      Example: Assuming TEMP is set to C:\TEMP,
     1198 +
     1199 +          dosCreateTempFileName(szBuffer,
     1200 +                                NULL,             // use $(TEMP)
     1201 +                                "pre",            // prefix
     1202 +                                "tmp")            // extension
     1203 +
     1204 *      would produce something like "C:\TEMP\pre07FG2.tmp".
     1205 *
     1206 *@@added V0.9.9 (2001-04-04) [umoeller]
     1207 */
     1208
     1209APIRET doshCreateTempFileName(PSZ pszTempFileName,        // out: fully q'fied temp file name
     1210                              const char *pcszDir,        // in: dir or NULL for %TEMP%
     1211                              const char *pcszPrefix,     // in: prefix for temp file or NULL
     1212                              const char *pcszExt)        // in: extension (without dot) or NULL
     1213{
     1214    APIRET      arc = NO_ERROR;
     1215
     1216    ULONG       ulPrefixLen = (pcszPrefix)
     1217                                    ? strlen(pcszPrefix)
     1218                                    : 0;
     1219
     1220    if (    (!pszTempFileName)
     1221         || (ulPrefixLen > 4)
     1222       )
     1223        arc = ERROR_INVALID_PARAMETER;
     1224    else
     1225    {
     1226        CHAR        szDir[CCHMAXPATH] = "";
     1227        FILESTATUS3 fs3;
     1228
     1229        const char  *pcszTemp = pcszDir;
     1230
     1231        if (!pcszTemp)
     1232        {
     1233            pcszTemp = getenv("TEMP");
     1234            if (!pcszTemp)
     1235                pcszTemp = getenv("TMP");
     1236        }
     1237
     1238        if (pcszTemp)       // either pcszDir or $(TEMP) or $(TMP) now
     1239            if (DosQueryPathInfo((PSZ)pcszTemp,
     1240                                 FIL_STANDARD,
     1241                                 &fs3,
     1242                                 sizeof(fs3)))
     1243                // TEMP doesn't exist:
     1244                pcszTemp = NULL;
     1245
     1246        if (!pcszTemp)
     1247            // not set, or doesn't exist:
     1248            // use root directory on boot drive
     1249            sprintf(szDir,
     1250                    "%c:\\",
     1251                    doshQueryBootDrive());
     1252        else
     1253        {
     1254            strcpy(szDir, pcszTemp);
     1255            if (szDir[strlen(szDir) - 1] != '\\')
     1256                strcat(szDir, "\\");
     1257        }
     1258
     1259        if (!szDir[0])
     1260            arc = ERROR_PATH_NOT_FOUND;     // shouldn't happen
     1261        else
     1262        {
     1263            ULONG       ulRandom = 0;
     1264            ULONG       cAttempts = 0;
     1265
     1266            // produce random number
     1267            DosQuerySysInfo(QSV_MS_COUNT,
     1268                            QSV_MS_COUNT,
     1269                            &ulRandom,
     1270                            sizeof(ulRandom));
     1271
     1272            do
     1273            {
     1274                CHAR szFile[20] = "",
     1275                     szFullTryThis[CCHMAXPATH];
     1276
     1277                // use the lower eight hex digits of the
     1278                // system uptime as the temp dir name
     1279                sprintf(szFile,
     1280                        "%08lX",
     1281                        ulRandom & 0xFFFFFFFF);
     1282
     1283                // if prefix is specified, overwrite the
     1284                // first characters in the random number
     1285                if (pcszPrefix)
     1286                    memcpy(szFile, pcszPrefix, ulPrefixLen);
     1287
     1288                if (pcszExt)
     1289                {
     1290                    szFile[8] = '.';
     1291                    strcpy(szFile + 9, pcszExt);
     1292                }
     1293
     1294                // now compose full temp file name
     1295                strcpy(szFullTryThis, szDir);
     1296                strcat(szFullTryThis, szFile);
     1297                // now we have: "C:\temp\wpiXXXXX"
     1298                if (DosQueryPathInfo(szFullTryThis,
     1299                                     FIL_STANDARD,
     1300                                     &fs3,
     1301                                     sizeof(fs3))
     1302                        == ERROR_FILE_NOT_FOUND)
     1303                {
     1304                    // file or dir doesn't exist:
     1305                    // cool, we're done
     1306                    strcpy(pszTempFileName, szFullTryThis);
     1307                    return (NO_ERROR);
     1308                }
     1309
     1310                // if this didn't work, raise ulRandom and try again
     1311                ulRandom += 123;
     1312
     1313                // try only 100 times, just to be sure
     1314                cAttempts++;
     1315            } while (cAttempts < 100);
     1316
     1317            // 100 loops elapsed:
     1318            arc = ERROR_BAD_FORMAT;
     1319        }
     1320    }
     1321
     1322    return (arc);
    11441323}
    11451324
  • trunk/src/helpers/dosh2.c

    r54 r55  
    17891789 */
    17901790
    1791 int Compare(const void *key,
    1792             const void *element)
     1791int _Optlink Compare(const void *key,
     1792                     const void *element)
    17931793{
    17941794    USHORT        usOrdinal = *((PUSHORT) key);
     
    18651865                                    &ulDummy)))
    18661866                {
    1867                     if ((pFunction = bsearch(&usOrdinal,
    1868                                              paFunctions,
    1869                                              cFunctions,
    1870                                              sizeof(FSYSFUNCTION),
    1871                                              Compare)))
     1867                    if ((pFunction = (PFSYSFUNCTION)bsearch(&usOrdinal,
     1868                                                            paFunctions,
     1869                                                            cFunctions,
     1870                                                            sizeof(FSYSFUNCTION),
     1871                                                            Compare)))
    18721872                    {
    18731873                        memcpy(pFunction->achFunctionName,
  • trunk/src/helpers/except.c

    r32 r55  
    1616 *      especially applies to multi-thread programs using
    1717 *      mutex semaphores (more on that below). The functions
    18  *      and macros in here are designed to make that more simple.
    19  *
    20  *      The macros in except.h automatically insert code for properly
    21  *      registering and deregistering the handlers in except.c. You
    22  *      should ALWAYS use these macros instead of directly registering
    23  *      the handlers to avoid accidentally forgetting to deregister
    24  *      them. If you forget to deregister an exception handler, this
    25  *      can lead to really strange errors (crashes, hangs) which are
    26  *      nearly impossible to debug because the thread's stack space
    27  *      might get completely messed up.
    28  *
    29  *      The general idea of these macros is to define TRY / CATCH
    30  *      blocks similar to C++. If an exception occurs in the TRY block,
    31  *      execution is transferred to the CATCH block. (This works in both
    32  *      C and C++, by the way.)
    33  *
    34  *      The "OnKill" function that was added with V0.9.0 has been
    35  *      removed again with V0.9.7. Use DosEnterMustComplete instead.
    36  *      Details follow.
     18 *      and macros in here are designed to make that more
     19 *      simple.
     20 *
     21 *      The macros in except.h automatically insert code for
     22 *      properly registering and deregistering the handlers
     23 *      in except.c. You should ALWAYS use these macros
     24 *      instead  of directly registering the handlers to avoid
     25 *      accidentally  forgetting to deregister them. If you
     26 *      forget to deregister an exception handler, this can
     27 *      lead to really strange errors (crashes, hangs) which
     28 *      are nearly impossible to debug because the thread's
     29 *      stack probably got completely messed up.
     30 *
     31 *      The general idea of these macros is to define
     32 *      TRY / CATCH blocks similar to C++. If an exception
     33 *      occurs in the TRY block, execution is transferred to
     34 *      the CATCH block. (This works in both C and C++, by the
     35 *      way.)
     36 *
     37 *      The "OnKill" function that was added with V0.9.0 has
     38 *      been removed again with V0.9.7.
    3739 *
    3840 *      The general usage is like this:
     
    4244 +              TRY_LOUD(excptid)         // or: TRY_QUIET(excptid)
    4345 +              {
     46 +                  char *p = NULL;
     47 +
    4448 +                  ....        // the stuff in here is protected by
    4549 +                              // the excHandlerLoud or excHandlerQuiet
    4650 +                              // exception handler
     51 +                  *p = "A";
    4752 +              }
    4853 +              CATCH(excptid)
     
    5863 *      exception occurs.
    5964 *      The CATCH block is _required_ even if you do nothing
    60  *      in there.
     65 *      in there, because the CATCH() macro will deregister
     66 *      the handler.
    6167 *
    6268 *      "excptid" can be any C identifier which is not used in
     
    7884 *      get called. So if you enclose your main() code in a
    7985 *      TRY_* block, your entire application is protected.
     86 *      If any subfunction fails, execution is transferred to
     87 *      the closest CATCH() that was installed (as with C++
     88 *      try and catch).
    8089 *
    8190 *      <B>Asynchronous exceptions</B>
     
    8392 *      The exception handlers in this file (which are installed
    8493 *      with the TRY/CATCH mechanism) only intercept synchronous
    85  *      exceptions (see excHandlerLoud for a list). They do not
    86  *      protect your code against asynchronous exceptions.
     94 *      exceptions, most importantly, XCPT_ACCESS_VIOLATION (see
     95 *      excHandlerLoud for a list). They do not protect your code
     96 *      against asynchronous exceptions.
    8797 *
    8898 *      OS/2 defines asynchronous exceptions to be those that
     
    100110 *
    101111 *      The problem with OS/2 mutex semaphores is that they are
    102  *      not automatically released when a thread terminates.
    103  *      If the thread owning the mutex died without releasing
    104  *      the mutex, other threads which are blocked on that mutex
    105  *      will wait forever and become zombie threads. Even worse,
    106  *      if this happens to a PM thread, this will hang the system.
    107  *
    108  *      Here's the typical scenario with two threads:
    109  *
    110  *      1)  Thread 2 requests a mutex and does lots of processing.
    111  *
    112  *      2)  Thread 1 requests the mutex. Since it's still owned
    113  *          by thread 2, thread 1 blocks.
    114  *
    115  *      3)  Thread 2 crashes in its processing. Without an
    116  *          exception handler, OS/2 will terminate the process.
    117  *          It will first kill thread 2 and then attempt to
    118  *          kill thread 1. This fails because it is still
    119  *          blocking on the semaphore that thread 2 never
    120  *          released. Boom.
    121  *
    122  *      The same scenario happens when a process gets killed.
    123  *      Since OS/2 will kill secondary threads before thread 1,
    124  *      the same situation can arise.
    125  *
    126  *      As a result, you must protect any section of code which
    127  *      requests a semaphore _both_ against crashes _and_
    128  *      termination.
     112 *      sometimes not automatically released when a thread terminates.
     113 *      If there are several mutexes involved and they are released
     114 *      in improper order, you can get zombie threads on exit.
     115 *      Even worse, if this happens to a PM thread, this will hang
     116 *      the system.
     117 *
     118 *      As a result, you should protect any section of code which
     119 *      requests a semaphore with the exception handlers. To protect
     120 *      yourself against thread termination, use must-complete
     121 *      sections as well (but be careful with those if your code
     122 *      takes a long time to execute... but then you shouldn't
     123 *      request a mutex in the first place).
    129124 *
    130125 *      So _whenever_ you request a mutex semaphore, enclose
     
    141136 +
    142137 +              DosEnterMustComplete(&ulNesting);
    143  +              TRY_QUIET(excpt1, OnKillYourFunc) // or TRY_LOUD
     138 +              TRY_QUIET(excpt1)          // or TRY_LOUD
    144139 +              {
    145  +                  fSemOwned = (WinRequestMutexSem(hmtx, ...) == NO_ERROR);
     140 +                  fSemOwned = !WinRequestMutexSem(hmtx, ...);
    146141 +                  if (fSemOwned)
    147142 +                  {       ... // work on your protected data
    148143 +                  }
     144 +                  // mutex gets released below
    149145 +              }
    150146 +              CATCH(excpt1) { } END_CATCH();    // always needed!
    151147 +
    152  +              if (fSemOwned) {
     148 +              if (fSemOwned)
     149 +              {
    153150 +                  // this gets executed always, even if an exception occured
    154151 +                  DosReleaseMutexSem(hmtx);
  • trunk/src/helpers/stringh.c

    r54 r55  
    11901190 *
    11911191 *@@added V0.9.0 [umoeller]
     1192 *@@changed V0.9.9 (2001-04-04) [umoeller]: this failed on "123" strings in quotes, fixed
    11921193 */
    11931194
     
    11981199    PSZ pParam;
    11991200    if ((pParam = strhFindAttribValue(pszSearchIn, pszTag)))
     1201    {
     1202        if (    (*pParam == '\"')
     1203             || (*pParam == '\'')
     1204           )
     1205            pParam++;           // V0.9.9 (2001-04-04) [umoeller]
     1206
    12001207        sscanf(pParam, "%ld", pl);
     1208    }
    12011209
    12021210    return (pParam);
  • trunk/src/helpers/tree.c

    r54 r55  
    10971097}
    10981098
    1099 
     1099/*
     1100 *@@ treeBuildArray:
     1101 *      builds an array of TREE* pointers containing
     1102 *      all tree items in sorted order.
     1103 *
     1104 *      This returns a TREE** pointer to the array.
     1105 *      Each item in the array is a TREE* pointer to
     1106 *      the respective tree item.
     1107 *
     1108 *      The array has been allocated using malloc()
     1109 *      and must be free()'d by the caller.
     1110 *
     1111 *      NOTE: This will only work if you maintain a
     1112 *      tree node count yourself, which you must pass
     1113 *      in *pulCount on input.
     1114 *
     1115 *      This is most useful if you want to delete an
     1116 *      entire tree without having to traverse it
     1117 *      and rebalance the tree on every delete.
     1118 *
     1119 *      Example usage for deletion:
     1120 *
     1121 +          TREE    *G_TreeRoot;
     1122 +          treeInit(&G_TreeRoot);
     1123 +
     1124 +          // add stuff to the tree
     1125 +          TREE    *pNewNode = malloc(...);
     1126 +          treeInsertID(&G_TreeRoot, pNewNode, FALSE)
     1127 +
     1128 +          // now delete all nodes
     1129 +          ULONG   cItems = ... // insert item count here
     1130 +          TREE**  papNodes = treeBuildArray(G_TreeRoot,
     1131 +                                            &cItems);
     1132 +          if (papNodes)
     1133 +          {
     1134 +              ULONG ul;
     1135 +              for (ul = 0; ul < cItems; ul++)
     1136 +              {
     1137 +                  TREE *pNodeThis = papNodes[ul];
     1138 +                  free(pNodeThis);
     1139 +              }
     1140 +
     1141 +              free(papNodes);
     1142 +          }
     1143 +
     1144 *
     1145 *@@added V0.9.9 (2001-04-05) [umoeller]
     1146 */
     1147
     1148TREE** treeBuildArray(TREE* pRoot,
     1149                      unsigned long *pulCount)  // in: item count, out: array item count
     1150{
     1151    TREE            **papNodes = NULL,
     1152                    **papThis = NULL;
     1153    unsigned long   cb = (sizeof(TREE*) * (*pulCount)),
     1154                    cNodes = 0;
     1155
     1156    if (cb)
     1157    {
     1158        papNodes = (TREE**)malloc(cb);
     1159        papThis = papNodes;
     1160
     1161        if (papNodes)
     1162        {
     1163            TREE    *pNode = (TREE*)treeFirst(pRoot);
     1164
     1165            memset(papNodes, 0, cb);
     1166
     1167            // copy nodes to array
     1168            while (    pNode
     1169                    && cNodes < (*pulCount)     // just to make sure
     1170                  )
     1171            {
     1172                *papThis = pNode;
     1173                cNodes++;
     1174                papThis++;
     1175
     1176                pNode = (TREE*)treeNext(pNode);
     1177            }
     1178
     1179            // output count
     1180            *pulCount = cNodes;
     1181        }
     1182    }
     1183
     1184    return (papNodes);
     1185}
     1186
     1187
Note: See TracChangeset for help on using the changeset viewer.