Index: trunk/src/helpers/dosh.c
===================================================================
--- trunk/src/helpers/dosh.c	(revision 32)
+++ trunk/src/helpers/dosh.c	(revision 33)
@@ -1828,4 +1828,5 @@
  *
  *@@added V0.9.7 (2000-12-02) [umoeller]
+ *@@changed V0.9.9 (2000-02-06) [umoeller]: removed disable; this broke the WarpCenter
  */
 
@@ -1838,7 +1839,7 @@
     else
     {
-        if (pPerfSys->fInitialized)
+        /* if (pPerfSys->fInitialized)
             pPerfSys->pDosPerfSysCall(CMD_KI_DISABLE,
-                                      0, 0, 0);
+                                      0, 0, 0); */
 
         if (pPerfSys->paCPUUtils)
Index: trunk/src/helpers/prfh.c
===================================================================
--- trunk/src/helpers/prfh.c	(revision 32)
+++ trunk/src/helpers/prfh.c	(revision 33)
@@ -304,8 +304,8 @@
 
 ULONG prfhCopyKey(HINI hiniSource,       // in: source profile (can be HINI_USER or HINI_SYSTEM)
-                 const char *pcszSourceApp,      // in: source application
-                 const char *pcszKey,            // in: source/target key
-                 HINI hiniTarget,       // in: target profile (can be HINI_USER or HINI_SYSTEM)
-                 const char *pcszTargetApp)      // in: target app
+                  const char *pcszSourceApp,      // in: source application
+                  const char *pcszKey,            // in: source/target key
+                  HINI hiniTarget,       // in: target profile (can be HINI_USER or HINI_SYSTEM)
+                  const char *pcszTargetApp)      // in: target app
 {
     ULONG   ulSizeOfData = 0,
@@ -391,9 +391,15 @@
  *
  *      Returns:
+ *
  *      --  0: no error
+ *
  *      --  PRFERR_KEYSLIST: couldn't query keys for pszSourceApp
+ *
  *      --  PRFERR_DATASIZE: couldn't query data size for key
+ *
  *      --  PRFERR_MEMORY: couldn't allocate memory
+ *
  *      --  PRFERR_READ: couldn't read data from source (PrfQueryProfileData error)
+ *
  *      --  PRFERR_WRITE: couldn't write data to target (PrfWriteProfileData error)
  *
@@ -445,4 +451,83 @@
 
 /*
+ *@@ prfhRenameKey:
+ *      renames a key in an INI file.
+ *
+ *      Since there's no such thing as a PrfRename,
+ *      what we do here is load the old data, write
+ *      it under a new key, and delete the old data.
+ *
+ *      Returns:
+ *
+ *      --  0: no error
+ *
+ *      --  PRFERR_INVALID_KEY: pcszApp or pcszOldKey do not exist.
+ *
+ *      --  PRFERR_KEY_EXISTS: pcszNewApp/pcszNewKey is already occupied.
+ *
+ *      --  PRFERR_WRITE: couldn't write data to target (PrfWriteProfileData error)
+ *
+ *@@added V0.9.9 (2000-02-06) [umoeller]
+ */
+
+ULONG prfhRenameKey(HINI hini,
+                    const char *pcszOldApp,
+                    const char *pcszOldKey, // in: key to rename
+                    const char *pcszNewApp, // in: new app (if NULL, pcszOldApp is used)
+                    const char *pcszNewKey) // in: new name for pcszOldKey
+{
+    ULONG ulrc = 0;
+
+    ULONG   cbData = 0;
+    PSZ pszData = prfhQueryProfileData(hini,
+                                       pcszOldApp,
+                                       pcszOldKey,
+                                       &cbData);
+    if (!pszData)
+        // not found:
+        ulrc = PRFERR_INVALID_KEY;
+    else
+    {
+        ULONG   cb;
+
+        if (!pcszNewApp)
+            // is NULL:
+            pcszNewApp = pcszOldApp;
+
+        // make sure target doesn't exist
+        if (    (PrfQueryProfileSize(hini,
+                                     (PSZ)pcszNewApp,
+                                     (PSZ)pcszNewKey,
+                                     &cb))
+             && (cb)
+           )
+            ulrc = PRFERR_KEY_EXISTS;
+        else
+        {
+            if (!PrfWriteProfileData(hini,
+                                     (PSZ)pcszNewApp,
+                                     (PSZ)pcszNewKey,
+                                     pszData,
+                                     cbData))
+                ulrc = PRFERR_WRITE;
+            else
+            {
+                // success writing:
+                // delete old
+                PrfWriteProfileData(hini,
+                                    (PSZ)pcszOldApp,
+                                    (PSZ)pcszOldKey,
+                                    NULL,
+                                    0);
+            }
+        }
+
+        free(pszData);
+    }
+
+    return (ulrc);
+}
+
+/*
  *@@ prfhSetUserProfile:
  *      calls PrfReset to change the current user
Index: trunk/src/helpers/threads.c
===================================================================
--- trunk/src/helpers/threads.c	(revision 32)
+++ trunk/src/helpers/threads.c	(revision 33)
@@ -182,4 +182,7 @@
  *         to the caller.
  *
+ *      This now (V0.9.9) returns the TID of the new thread or
+ *      null on errors.
+ *
  *@@changed V0.9.0 [umoeller]: default stack size raised for Watcom (thanks, Rdiger Ihle)
  *@@changed V0.9.0 [umoeller]: _beginthread is now only called after all variables have been set (thanks, Rdiger Ihle)
@@ -190,14 +193,15 @@
  *@@changed V0.9.5 (2000-08-26) [umoeller]: now using PTHREADINFO
  *@@changed V0.9.7 (2000-12-18) [lafaix]: THRF_TRANSIENT support added
- */
-
-BOOL thrCreate(PTHREADINFO pti,     // out: THREADINFO data
-               PTHREADFUNC pfn,     // in: _Optlink thread function
-               PBOOL pfRunning,     // out: variable set to TRUE while thread is running;
-                                    // ptr can be NULL
-               ULONG flFlags,       // in: THRF_* flags
-               ULONG ulData)        // in: user data to be stored in THREADINFO
-{
-    BOOL            rc = FALSE;
+ *@@changed V0.9.9 (2000-02-06) [umoeller]: now returning TID
+ */
+
+ULONG thrCreate(PTHREADINFO pti,     // out: THREADINFO data
+                PTHREADFUNC pfn,     // in: _Optlink thread function
+                PBOOL pfRunning,     // out: variable set to TRUE while thread is running;
+                                     // ptr can be NULL
+                ULONG flFlags,       // in: THRF_* flags
+                ULONG ulData)        // in: user data to be stored in THREADINFO
+{
+    ULONG ulrc = 0;     // V0.9.9 (2000-02-06) [umoeller]
 
     // (2000-12-18) [lafaix] TRANSIENT
@@ -206,6 +210,4 @@
         if (pti == NULL)
             pti = (PTHREADINFO) malloc(sizeof(THREADINFO));
-        else
-            return (rc);
     }
 
@@ -223,6 +225,4 @@
         pti->ulData = ulData;
 
-        rc = TRUE;
-
         if (flFlags & THRF_WAIT)
             // "Wait" flag set: create an event semaphore which
@@ -233,9 +233,13 @@
                                   FALSE)    // not posted (reset)
                     != NO_ERROR)
-                rc = FALSE;
-
-        pti->fExit = FALSE;
-
-        if (rc)
+            {
+                if (flFlags & THRF_TRANSIENT)
+                    free(pti);
+
+                // stop right here
+                pti = NULL;
+            }
+
+        if (pti)
         {
             pti->tid = _beginthread(        // moved, V0.9.0 (hint: Rdiger Ihle)
@@ -244,7 +248,7 @@
                                     3*96000, // plenty of stack
                                     pti);   // parameter passed to thread
-            rc = (pti->tid != 0);
-
-            if (rc)
+            ulrc = pti->tid;
+
+            if (ulrc)
                 if (flFlags & THRF_WAIT)
                 {
@@ -257,5 +261,5 @@
     }
 
-    return (rc);
+    return (ulrc);
 }
 
Index: trunk/src/helpers/tree.c
===================================================================
--- trunk/src/helpers/tree.c	(revision 32)
+++ trunk/src/helpers/tree.c	(revision 33)
@@ -17,4 +17,47 @@
  *      tree sorting/comparison. This implementation is released
  *      under the GPL.
+ *
+ *      <B>Introduction</B>
+ *
+ *      Binary trees are different from linked lists in that items
+ *      are not simply linked sequentially, but instead put into
+ *      a tree-like structure.
+ *
+ *      For this, the functions here use the TREE structure. You can
+ *      easily see that this has the "left" and "right" members,
+ *      which make up the tree.
+ *
+ *      In addition, each tree has a "tree root" item, from which all
+ *      other tree nodes can be reached by following the "left" and
+ *      "right" pointers.
+ *
+ *      Per definition, in our trees, if you follow the "left" pointer,
+ *      you will reach an item which is "greater than" the current node.
+ *      Reversely, following the "right" pointer will lead you to a
+ *      node which is "less than" the current node.
+ *
+ *      The implementation here has the following characteristics:
+ *
+ *      -- We have "binary" trees. That is, there are only "left" and
+ *         "right" pointers.
+ *
+ *      -- The tree is always "balanced". The tree gets completely
+ *         reordered when items are added/removed to ensure that
+ *         all paths through the tree are approximately the same
+ *         length. This avoids the "worst case" scenario that some
+ *         paths grow terribly long while others remain short, which
+ *         can make searching very inefficient.
+ *
+ *      -- The tree nodes are marked as either "red" or "black", which
+ *         is an algorithm to allow the implementation of 2-3-4 trees
+ *         using a binary tree only. I don't fully understand how this
+ *         works, but essentially, "red" nodes represent a 3 or 4 node,
+ *         while "black" nodes are plain binary nodes.
+ *
+ *      As much as I understand about all this, red-black balanced
+ *      binary trees are the most efficient tree algorithm known to
+ *      mankind. As long as you are sure that trees are more efficient
+ *      in your situation than a linked list in the first place (see
+ *      below for comparisons), use the functions in here.
  *
  *      <B>Using binary trees</B>
@@ -31,14 +74,4 @@
  *      for a sample.
  *
- *      Each TREE node does not only contain data, but also an
- *      "id" field. The order of nodes in the tree is determined
- *      by calling a node comparison function provided by the caller
- *      (which you must write). This takes two "id" values and must
- *      return:
- *
- +           0: id1 == id2
- +          -1: id1 < id2
- +          +1: id1 > id2
- *
  *      Initialize the root of the tree with treeInit(). Then
  *      add nodes to the tree with treeInsertID() and remove nodes
@@ -48,9 +81,34 @@
  *      root with TREE_NULL.
  *
+ *      Most functions in here come in two flavors.
+ *
+ *      -- You can provide a comparison function and use the "Node"
+ *         flavors of these functions. This is useful, for example,
+ *         if you are storing strings. You can then write a short
+ *         comparison function which does a strcmp() on the data
+ *         of tree nodes.
+ *
+ *         The order of nodes in the tree is determined by calling a
+ *         node comparison function provided by the caller
+ *         (which you must write). This takes two TREE pointers and
+ *         must return:
+ *
+ +           0: tree1 == tree2
+ +          -1: tree1 < tree2
+ +          +1: tree1 > tree2
+ *
+ *      -- The "ID" functions (e.g. treeInsertID) do not require
+ *         a comparison function, but will use the "id" member of
+ *         the TREE structure instead. If this flavor is used, an
+ *         internal comparison function is used for comparing the
+ *         "id" fields, which are plain ULONGs.
+ *
+ *      <B>Trees vs. linked lists</B>
+ *
  *      Compared to linked lists (as implemented by linklist.c),
  *      trees allow for much faster searching.
  *
- *      Assuming a linked list contains N items, then searching the
- *      list for an item will take an average of N/2 comparisons
+ *      Assuming a linked list contains N items, then searching a
+ *      linked list for an item will take an average of N/2 comparisons
  *      and even N comparisons if the item cannot be found (unless
  *      you keep the list sorted, but linklist.c doesn't do this).
@@ -72,6 +130,6 @@
  *         nodes because the tree is always sorted.
  *
- *      -- You must always supply a comparison function to allow the
- *         tree functions to sort the tree.
+ *      -- If you are not using the "ID" flavors, you must supply a
+ *         comparison function to allow the tree functions to sort the tree.
  *
  *      -- As opposed to a LISTNODE, the TREE structure (which
@@ -134,4 +192,19 @@
 
 /*
+ * fnCompareIDs:
+ *
+ *added V0.9.9 (2000-02-06) [umoeller]
+ */
+
+int fnCompareIDs(unsigned long id1, unsigned long id2)
+{
+    if (id1 < id2)
+        return -1;
+    if (id1 > id2)
+        return +1;
+    return (0);
+}
+
+/*
  *@@ treeInsertID:
  *      inserts a node into an existing tree.
@@ -169,5 +242,4 @@
  +          treeInsertID(&TreeRoot,
  +                     (TREE*)pTreeItem,
- +                     fnCompare,       // your comparison function
  +                     FALSE);
  *
@@ -179,9 +251,10 @@
  *          returned if a tree item with the specified ID already
  *          exists.
+ *
+ *@@changed V0.9.9 (2000-02-06) [umoeller]: removed comparison func
  */
 
 int treeInsertID(TREE **root,             // in: root of tree
                  TREE *tree,              // in: new tree node
-                 FNTREE_COMPARE_IDS *comp,      // in: comparison function
                  BOOL fAllowDuplicates)   // in: whether duplicates with the same ID are allowed
 {
@@ -198,5 +271,5 @@
     {
         parent  = current;
-        last_comp = comp(tree->id, current->id);
+        last_comp = fnCompareIDs(tree->id, current->id);
         switch (last_comp)
         {
@@ -211,9 +284,9 @@
     }
 
-    // setup new node
-    ((TREE *) tree)->parent = parent;
-    ((TREE *) tree)->left   = TREE_NULL;
-    ((TREE *) tree)->right  = TREE_NULL;
-    ((TREE *) tree)->colour = RED;
+    // set up new node
+    ((TREE*)tree)->parent = parent;
+    ((TREE*)tree)->left   = TREE_NULL;
+    ((TREE*)tree)->right  = TREE_NULL;
+    ((TREE*)tree)->colour = RED;
 
     // insert node in tree
@@ -268,9 +341,9 @@
     }
 
-    // setup new node
-    ((TREE *) tree)->parent = parent;
-    ((TREE *) tree)->left   = TREE_NULL;
-    ((TREE *) tree)->right  = TREE_NULL;
-    ((TREE *) tree)->colour = RED;
+    // set up new node
+    ((TREE*)tree)->parent = parent;
+    ((TREE*)tree)->left   = TREE_NULL;
+    ((TREE*)tree)->right  = TREE_NULL;
+    ((TREE*)tree)->colour = RED;
 
     // insert node in tree
@@ -464,6 +537,6 @@
         return TREE_INVALID_NODE;
 
-    if (    (((TREE *) tree)->left  == TREE_NULL)
-         || (((TREE *) tree)->right == TREE_NULL)
+    if (    (((TREE*)tree)->left  == TREE_NULL)
+         || (((TREE*)tree)->right == TREE_NULL)
        )
         // descendent has a TREE_NULL node as a child
@@ -472,5 +545,5 @@
   {
         // find tree successor with a TREE_NULL node as a child
-        descendent = ((TREE *) tree)->right;
+        descendent = ((TREE*)tree)->right;
         while (descendent->left != TREE_NULL)
             descendent = descendent->left;
@@ -499,20 +572,20 @@
 
     if (descendent != (TREE *) tree)
-  {
+    {
         // Conceptually what we are doing here is moving the data from
         // descendent to tree.  In fact we do this by linking descendent
         // into the structure in the place of tree.
-        descendent->left   = ((TREE *) tree)->left;
-        descendent->right  = ((TREE *) tree)->right;
-        descendent->parent = ((TREE *) tree)->parent;
-        descendent->colour = ((TREE *) tree)->colour;
+        descendent->left   = ((TREE*)tree)->left;
+        descendent->right  = ((TREE*)tree)->right;
+        descendent->parent = ((TREE*)tree)->parent;
+        descendent->colour = ((TREE*)tree)->colour;
 
         if (descendent->parent)
-      {
+        {
             if (tree == descendent->parent->left)
                 descendent->parent->left  = descendent;
             else
                 descendent->parent->right = descendent;
-      }
+        }
         else
             *root = descendent;
@@ -618,11 +691,8 @@
  *@@ treeFindEQID:
  *      finds a node with ID exactly matching that provided.
- *      To find a tree node, your comparison function must
- *      compare the tree node IDs.
  */
 
 void* treeFindEQID(TREE **root,
-                   unsigned long id,
-                   FNTREE_COMPARE_IDS *comp)
+                   unsigned long id)
 {
     TREE
@@ -632,5 +702,5 @@
     found = NULL;
     while (current != TREE_NULL)
-        switch (comp(current->id, id))
+        switch (fnCompareIDs(current->id, id))
         {
             case -1: current = current->right; break;
@@ -651,6 +721,5 @@
 
 void* treeFindGEID(TREE **root,
-                   unsigned long idFind,
-                   FNTREE_COMPARE_IDS *comp)
+                   unsigned long idFind)
 {
     TREE
@@ -660,5 +729,5 @@
     found = NULL;
     while (current != TREE_NULL)
-        switch (comp(current->id, idFind))
+        switch (fnCompareIDs(current->id, idFind))
         {
             case -1: current = current->right; break;
@@ -873,18 +942,18 @@
     {
         process(tree, pUser);
-        treeTraverse (((TREE *) tree)->left,  process, pUser, method);
-        treeTraverse (((TREE *) tree)->right, process, pUser, method);
+        treeTraverse (((TREE*)tree)->left,  process, pUser, method);
+        treeTraverse (((TREE*)tree)->right, process, pUser, method);
     }
     else if (method == 2)
     {
-        treeTraverse (((TREE *) tree)->left,  process, pUser, method);
-        treeTraverse (((TREE *) tree)->right, process, pUser, method);
+        treeTraverse (((TREE*)tree)->left,  process, pUser, method);
+        treeTraverse (((TREE*)tree)->right, process, pUser, method);
         process(tree, pUser);
     }
     else
     {
-        treeTraverse (((TREE *) tree)->left,  process, pUser, method);
+        treeTraverse (((TREE*)tree)->left,  process, pUser, method);
         process(tree, pUser);
-        treeTraverse (((TREE *) tree)->right, process, pUser, method);
+        treeTraverse (((TREE*)tree)->right, process, pUser, method);
     }
 }
