Index: /trunk/src/kObjCache/kObjCache.c
===================================================================
--- /trunk/src/kObjCache/kObjCache.c	(revision 1041)
+++ /trunk/src/kObjCache/kObjCache.c	(revision 1042)
@@ -29,4 +29,8 @@
 *   Header Files                                                               *
 *******************************************************************************/
+#if 0
+# define ELECTRIC_HEAP
+# include "../kmk/electric.h"
+#endif
 #include <string.h>
 #include <stdlib.h>
@@ -191,5 +195,5 @@
 }
 
-
+#ifndef ELECTRIC_HEAP
 void *xmalloc(size_t cb)
 {
@@ -201,12 +205,4 @@
 
 
-void *xmallocz(size_t cb)
-{
-    void *pv = xmalloc(cb);
-    memset(pv, 0, cb);
-    return pv;
-}
-
-
 void *xrealloc(void *pvOld, size_t cb)
 {
@@ -225,4 +221,15 @@
     return psz;
 }
+#endif
+
+
+void *xmallocz(size_t cb)
+{
+    void *pv = xmalloc(cb);
+    memset(pv, 0, cb);
+    return pv;
+}
+
+
 
 
@@ -684,4 +691,5 @@
 {
     MD5Final(&pSum->md5[0], &pCtx->MD5Ctx);
+    pSum->fUsed = 1;
 }
 
@@ -992,6 +1000,6 @@
     if (!off)
         FatalDie("Failed to find abs path for '%s'!\n", pszFilename);
-    pEntry->pszDir = xmalloc(off - 1);
-    memcpy(pEntry->pszDir, pEntry->pszAbsPath, off);
+    pEntry->pszDir = xmalloc(off);
+    memcpy(pEntry->pszDir, pEntry->pszAbsPath, off - 1);
     pEntry->pszDir[off - 1] = '\0';
 
@@ -1067,5 +1075,4 @@
             int fBad = 0;
             int fBadBeforeMissing = 1;
-            int fFirstSum = 1;
             while (fgets(g_szLine, sizeof(g_szLine), pFile))
             {
@@ -1105,4 +1112,11 @@
                         break;
                 }
+                else if (!strcmp(g_szLine, "cpp-sum"))
+                {
+                    KOCSUM Sum;
+                    if ((fBad = kOCSumInitFromString(&Sum, pszVal)))
+                        break;
+                    kOCSumAdd(&pEntry->Old.SumHead, &Sum);
+                }
                 else if (!strcmp(g_szLine, "cc-argc"))
                 {
@@ -1120,10 +1134,10 @@
                     pEntry->Old.papszArgvCompile[i] = xstrdup(pszVal);
                 }
-                else if (!strcmp(g_szLine, "sum"))
+                else if (!strcmp(g_szLine, "cc-argv-sum"))
                 {
-                    KOCSUM Sum;
-                    if ((fBad = kOCSumInitFromString(&Sum, pszVal)))
+                    if ((fBad = !kOCSumIsEmpty(&pEntry->Old.SumCompArgv)))
                         break;
-                    kOCSumAdd(&pEntry->Old.SumHead, &Sum);
+                    if ((fBad = kOCSumInitFromString(&pEntry->Old.SumCompArgv, pszVal)))
+                        break;
                 }
                 else if (!strcmp(g_szLine, "target"))
@@ -1133,7 +1147,16 @@
                     pEntry->Old.pszTarget = xstrdup(pszVal);
                 }
+                else if (!strcmp(g_szLine, "key"))
+                {
+                    char *pszNext;
+                    if ((fBad = pEntry->uKey != 0))
+                        break;
+                    pEntry->uKey = strtoul(pszVal, &pszNext, 0);
+                    if ((fBad = pszNext && *pszNext))
+                        break;
+                }
                 else if (!strcmp(g_szLine, "the-end"))
                 {
-                    fBadBeforeMissing = fBad = !strcmp(pszVal, "fine");
+                    fBadBeforeMissing = fBad = strcmp(pszVal, "fine");
                     break;
                 }
@@ -1160,5 +1183,5 @@
                          || !pEntry->Old.pszObjName
                          || !pEntry->Old.pszCppName
-                         || fFirstSum))
+                         || kOCSumIsEmpty(&pEntry->Old.SumHead)))
                     fBad = 1;
                 if (!fBad)
@@ -1227,5 +1250,5 @@
     unsigned i;
 
-    InfoMsg(1, "writing cache file...\n");
+    InfoMsg(1, "writing cache entry '%s'...\n", pEntry->pszName);
     pFile = FOpenFileInDir(pEntry->pszName, pEntry->pszDir, "wb");
     if (!pFile)
@@ -1238,4 +1261,5 @@
     fprintf(pFile, "magic=kObjCache-1\n");
     CHECK_LEN(fprintf(pFile, "target=%s\n", pEntry->New.pszTarget ? pEntry->New.pszTarget : pEntry->Old.pszTarget));
+    CHECK_LEN(fprintf(pFile, "key=%u\n", (unsigned long)pEntry->uKey));
     CHECK_LEN(fprintf(pFile, "obj=%s\n", pEntry->New.pszObjName ? pEntry->New.pszObjName : pEntry->Old.pszObjName));
     CHECK_LEN(fprintf(pFile, "cpp=%s\n", pEntry->New.pszCppName ? pEntry->New.pszCppName : pEntry->Old.pszCppName));
@@ -1260,9 +1284,9 @@
 
 
-    for (pSum = kOCSumIsEmpty(&pEntry->New.SumHead) ? &pEntry->New.SumHead : &pEntry->Old.SumHead;
+    for (pSum = !kOCSumIsEmpty(&pEntry->New.SumHead) ? &pEntry->New.SumHead : &pEntry->Old.SumHead;
          pSum;
          pSum = pSum->pNext)
     {
-        fprintf(pFile, "sum=");
+        fprintf(pFile, "cpp-sum=");
         kOCSumFPrintf(pSum, pFile);
     }
@@ -1277,4 +1301,5 @@
      * files the next time or upset make with new timestamps.
      */
+    errno = 0;
     if (    fflush(pFile) < 0
         ||  ferror(pFile))
@@ -1322,13 +1347,14 @@
      */
     pEntry->New.cArgvCompile = cArgvCompile;
-    pEntry->New.papszArgvCompile = xmalloc(cArgvCompile + 1);
+    pEntry->New.papszArgvCompile = xmalloc((cArgvCompile + 1) * sizeof(pEntry->New.papszArgvCompile[0]));
     kOCSumInitWithCtx(&pEntry->New.SumCompArgv, &Ctx);
     for (i = 0; i < cArgvCompile; i++)
     {
         pEntry->New.papszArgvCompile[i] = xstrdup(papszArgvCompile[i]);
-        kOCSumUpdate(&pEntry->New.SumCompArgv, &Ctx, papszArgvCompile[i], strlen(papszArgvCompile[i]));
+        kOCSumUpdate(&pEntry->New.SumCompArgv, &Ctx, papszArgvCompile[i], strlen(papszArgvCompile[i]) + 1);
     }
     kOCSumFinalize(&pEntry->New.SumCompArgv, &Ctx);
     pEntry->New.papszArgvCompile[i] = NULL; /* for exev/spawnv */
+    kOCSumInfo(&pEntry->New.SumCompArgv, 1, "comp-argv");
 
     /*
@@ -1775,5 +1801,5 @@
     kOCSumUpdate(&pEntry->New.SumHead, &Ctx, pEntry->New.pszCppMapping, pEntry->New.cbCpp);
     kOCSumFinalize(&pEntry->New.SumHead, &Ctx);
-    kOCSumInfo(&pEntry->New.SumHead, 1, "");
+    kOCSumInfo(&pEntry->New.SumHead, 1, "cpp (file)");
 }
 
@@ -1838,4 +1864,5 @@
     pEntry->New.cbCpp = cbAlloc - cbLeft;
     kOCSumFinalize(&pEntry->New.SumHead, &Ctx);
+    kOCSumInfo(&pEntry->New.SumHead, 1, "cpp (pipe)");
 }
 
@@ -1916,5 +1943,6 @@
         long cbLeft;
         char *psz;
-        int fd = OpenFileInDir(pEntry->New.pszCppName, pEntry->pszDir, O_WRONLY | O_TRUNC | O_BINARY, 0666);
+        int fd = OpenFileInDir(pEntry->New.pszCppName, pEntry->pszDir,
+                               O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0666);
         if (fd == -1)
             FatalDie("Failed to create '%s' in '%s': %s\n",
@@ -1935,4 +1963,7 @@
                          pEntry->New.pszCppName, pEntry->pszDir, strerror(iErr));
             }
+
+            psz += cbWritten;
+            cbLeft -= cbWritten;
         }
         close(fd);
@@ -2097,4 +2128,5 @@
     pEntry->New.cbCpp = cbAlloc - cbLeft;
     kOCSumFinalize(&pEntry->New.SumHead, &Ctx);
+    kOCSumInfo(&pEntry->New.SumHead, 1, "cpp (tee)");
 
     /*
@@ -2668,4 +2700,5 @@
 
     pDigest->uKey = pEntry->uKey;
+    pDigest->pszTarget = xstrdup(pEntry->New.pszTarget ? pEntry->New.pszTarget : pEntry->Old.pszTarget);
 
     kOCSumInit(&pDigest->SumCompArgv);
@@ -2777,4 +2810,6 @@
     /** The cache file descriptor. */
     int fd;
+    /** The stream associated with fd. */
+    FILE *pFile;
     /** Whether it's currently locked or not. */
     unsigned fLocked;
@@ -2828,9 +2863,31 @@
     if (!off)
         FatalDie("Failed to find abs path for '%s'!\n", pszCacheFile);
-    pCache->pszDir = xmalloc(off - 1);
-    memcpy(pCache->pszDir, pCache->pszAbsPath, off);
+    pCache->pszDir = xmalloc(off);
+    memcpy(pCache->pszDir, pCache->pszAbsPath, off - 1);
     pCache->pszDir[off - 1] = '\0';
 
     return pCache;
+}
+
+
+/**
+ * Destroys the cache - closing any open files, freeing up heap memory and such.
+ *
+ * @param   pCache      The cache.
+ */
+static void kObjCacheDestroy(PKOBJCACHE pCache)
+{
+    if (pCache->pFile)
+    {
+        errno = 0;
+        if (fclose(pCache->pFile) != 0)
+            FatalMsg("fclose failed: %s\n", strerror(errno));
+        pCache->pFile = NULL;
+        pCache->fd = -1;
+    }
+    free(pCache->paDigests);
+    free(pCache->pszAbsPath);
+    free(pCache->pszDir);
+    free(pCache);
 }
 
@@ -2859,15 +2916,16 @@
 static void kObjCacheRead(PKOBJCACHE pCache)
 {
-    FILE *pFile;
     unsigned i;
+    char szBuf[8192];
     int fBad = 0;
 
     /*
-     * Rewind the file and associate it with a buffered file stream.
+     * Rewind the file & stream, and associate a temporary buffer
+     * with the stream to speed up reading.
      */
     if (lseek(pCache->fd, 0, SEEK_SET) == -1)
         FatalDie("lseek(cache-fd) failed: %s\n", strerror(errno));
-    pFile = fdopen(pCache->fd, "rb");
-    if (!pFile)
+    rewind(pCache->pFile);
+    if (setvbuf(pCache->pFile, szBuf, _IOFBF, sizeof(szBuf)) != 0)
         FatalDie("fdopen(cache-fd,rb) failed: %s\n", strerror(errno));
 
@@ -2875,5 +2933,5 @@
      * Read magic and generation.
      */
-    if (    !fgets(g_szLine, sizeof(g_szLine), pFile)
+    if (    !fgets(g_szLine, sizeof(g_szLine), pCache->pFile)
         ||  strcmp(g_szLine, "magic=kObjCache-v0.1.0\n"))
     {
@@ -2881,5 +2939,5 @@
         fBad = 1;
     }
-    else if (    !fgets(g_szLine, sizeof(g_szLine), pFile)
+    else if (    !fgets(g_szLine, sizeof(g_szLine), pCache->pFile)
              ||  strncmp(g_szLine, "generation=", sizeof("generation=") - 1))
     {
@@ -2890,5 +2948,5 @@
              && pCache->uGeneration == atol(&g_szLine[sizeof("generation=") - 1]))
     {
-        InfoMsg(1, "cache file unchanged\n");
+        InfoMsg(1, "drop re-read unmodified cache file\n");
         fBad = 0;
     }
@@ -2922,10 +2980,12 @@
             if (psz)
             {
-                i = strtoul(psz, &psz, 0);
-                if ((fBad = psz && *psz))
+                char *pszNext;
+                i = strtoul(++psz, &pszNext, 0);
+                if ((fBad = pszNext && *pszNext))
                     break;
                 if ((fBad = i >= pCache->cDigests))
                     break;
                 pDigest = &pCache->paDigests[i];
+                *psz = '\0';
             }
             else
@@ -2934,5 +2994,5 @@
 
             /* string case on value name. */
-            if (!strncmp(g_szLine, "sum-#", sizeof("sum-sum-#") - 1))
+            if (!strcmp(g_szLine, "sum-#"))
             {
                 KOCSUM Sum;
@@ -2941,5 +3001,5 @@
                 kOCSumAdd(&pDigest->SumHead, &Sum);
             }
-            else if (!strncmp(g_szLine, "digest-abs-#", sizeof("digest-abs-#") - 1))
+            else if (!strcmp(g_szLine, "digest-abs-#"))
             {
                 if ((fBad = pDigest->pszAbsPath != NULL))
@@ -2947,5 +3007,5 @@
                 pDigest->pszAbsPath = xstrdup(pszVal);
             }
-            else if (!strncmp(g_szLine, "digest-rel-#", sizeof("digest-rel-#") - 1))
+            else if (!strcmp(g_szLine, "digest-rel-#"))
             {
                 if ((fBad = pDigest->pszRelPath != NULL))
@@ -2953,5 +3013,5 @@
                 pDigest->pszRelPath = xstrdup(pszVal);
             }
-            else if (!strncmp(g_szLine, "key-#", sizeof("key-#") - 1))
+            else if (!strcmp(g_szLine, "key-#"))
             {
                 if ((fBad = pDigest->uKey != 0))
@@ -2963,5 +3023,5 @@
                     pCache->uNextKey = pDigest->uKey + 1;
             }
-            else if (!strncmp(g_szLine, "comp-argv-sum-#", sizeof("comp-argv-sum-#") - 1))
+            else if (!strcmp(g_szLine, "comp-argv-sum-#"))
             {
                 if ((fBad = !kOCSumIsEmpty(&pDigest->SumCompArgv)))
@@ -2970,5 +3030,5 @@
                     break;
             }
-            else if (!strncmp(g_szLine, "target-#", sizeof("target-#") - 1))
+            else if (!strcmp(g_szLine, "target-#"))
             {
                 if ((fBad = pDigest->pszTarget != NULL))
@@ -3006,5 +3066,5 @@
                 break;
             }
-        } while (fgets(g_szLine, sizeof(g_szLine), pFile));
+        } while (fgets(g_szLine, sizeof(g_szLine), pCache->pFile));
 
         /*
@@ -3032,5 +3092,5 @@
         if (fBad)
             InfoMsg(1, "bad cache file (%s)\n", fBadBeforeMissing ? g_szLine : "missing stuff");
-        else if (ferror(pFile))
+        else if (ferror(pCache->pFile))
         {
             InfoMsg(1, "cache file read error\n");
@@ -3045,7 +3105,9 @@
 
     /*
-     * Close the stream.
-     */
-    fclose(pFile);
+     * Disassociate the buffer from the stream changing
+     * it to non-buffered mode.
+     */
+    if (setvbuf(pCache->pFile, NULL, _IONBF, 0) != 0)
+        FatalDie("setvbuf(,0,,0) failed: %s\n", strerror(errno));
 }
 
@@ -3058,18 +3120,19 @@
 static void kObjCacheWrite(PKOBJCACHE pCache)
 {
-    FILE *pFile;
     unsigned i;
     off_t cb;
+    char szBuf[8192];
     assert(pCache->fLocked);
     assert(pCache->fDirty);
 
     /*
-     * Rewind the file and associate it with a buffered file stream.
+     * Rewind the file & stream, and associate a temporary buffer
+     * with the stream to speed up the writing.
      */
     if (lseek(pCache->fd, 0, SEEK_SET) == -1)
         FatalDie("lseek(cache-fd) failed: %s\n", strerror(errno));
-    pFile = fdopen(pCache->fd, "w+b");
-    if (!pFile)
-        FatalDie("fdopen(cache-fd,w+b) failed: %s\n", strerror(errno));
+    rewind(pCache->pFile);
+    if (setvbuf(pCache->pFile, szBuf, _IOFBF, sizeof(szBuf)) != 0)
+        FatalDie("setvbuf failed: %s\n", strerror(errno));
 
     /*
@@ -3077,5 +3140,5 @@
      */
     pCache->uGeneration++;
-    fprintf(pFile,
+    fprintf(pCache->pFile,
             "magic=kObjCache-v0.1.0\n"
             "generation=%d\n"
@@ -3087,5 +3150,5 @@
      * Write the digests.
      */
-    for (i = 0; pCache->cDigests; i++)
+    for (i = 0; i < pCache->cDigests; i++)
     {
         PCKOCDIGEST pDigest = &pCache->paDigests[i];
@@ -3093,15 +3156,15 @@
 
         if (pDigest->pszAbsPath)
-            fprintf(pFile, "digest-abs-#%u=%s\n", i, pDigest->pszAbsPath);
+            fprintf(pCache->pFile, "digest-abs-#%u=%s\n", i, pDigest->pszAbsPath);
         if (pDigest->pszRelPath)
-            fprintf(pFile, "digest-rel-#%u=%s\n", i, pDigest->pszRelPath);
-        fprintf(pFile, "key-#%u=%u\n", i, pDigest->uKey);
-        fprintf(pFile, "target-#%u=%s\n", i, pDigest->pszTarget);
-        fprintf(pFile, "comp-argv-sum-#%u=", i);
-        kOCSumFPrintf(&pDigest->SumCompArgv, pFile);
+            fprintf(pCache->pFile, "digest-rel-#%u=%s\n", i, pDigest->pszRelPath);
+        fprintf(pCache->pFile, "key-#%u=%u\n", i, pDigest->uKey);
+        fprintf(pCache->pFile, "target-#%u=%s\n", i, pDigest->pszTarget);
+        fprintf(pCache->pFile, "comp-argv-sum-#%u=", i);
+        kOCSumFPrintf(&pDigest->SumCompArgv, pCache->pFile);
         for (pSum = &pDigest->SumHead; pSum; pSum = pSum->pNext)
         {
-            fprintf(pFile, "sum-#%u=", i);
-            kOCSumFPrintf(pSum, pFile);
+            fprintf(pCache->pFile, "sum-#%u=", i);
+            kOCSumFPrintf(pSum, pCache->pFile);
         }
     }
@@ -3111,16 +3174,17 @@
      * (Closing the stream shouldn't close the file handle IIRC...)
      */
-    fprintf(pFile, "the-end=fine\n");
-    fflush(pFile);
-    if (    fflush(pFile) < 0
-        ||  ferror(pFile))
+    fprintf(pCache->pFile, "the-end=fine\n");
+    errno = 0;
+    if (    fflush(pCache->pFile) < 0
+        ||  ferror(pCache->pFile))
     {
         int iErr = errno;
-        fclose(pFile);
+        fclose(pCache->pFile);
         UnlinkFileInDir(pCache->pszName, pCache->pszDir);
         FatalDie("Stream error occured while writing '%s' in '%s': %s\n",
                  pCache->pszName, pCache->pszDir, strerror(iErr));
     }
-    fclose(pFile);
+    if (setvbuf(pCache->pFile, NULL, _IONBF, 0) != 0)
+        FatalDie("setvbuf(,0,,0) failed: %s\n", strerror(errno));
 
     cb = lseek(pCache->fd, 0, SEEK_CUR);
@@ -3133,5 +3197,5 @@
 #endif
         FatalDie("file truncation failed: %s\n", strerror(errno));
-    InfoMsg(1, "Wrote '%s' in '%s', %d bytes\n", pCache->pszName, pCache->pszDir, cb);
+    InfoMsg(1, "wrote '%s' in '%s', %d bytes\n", pCache->pszName, pCache->pszDir, cb);
 }
 
@@ -3186,4 +3250,8 @@
 {
     struct stat st;
+#if defined(__WIN__)
+    OVERLAPPED OverLapped;
+#endif
+
     assert(!pCache->fLocked);
 
@@ -3201,4 +3269,10 @@
                 FatalDie("Failed to create '%s' in '%s': %s\n", pCache->pszName, pCache->pszDir, strerror(errno));
         }
+
+        pCache->pFile = fdopen(pCache->fd, "r+b");
+        if (!pCache->pFile)
+            FatalDie("fdopen failed: %s\n", strerror(errno));
+        if (setvbuf(pCache->pFile, NULL, _IONBF, 0) != 0)
+            FatalDie("setvbuf(,0,,0) failed: %s\n", strerror(errno));
     }
 
@@ -3207,5 +3281,6 @@
      */
 #if defined(__WIN__)
-    if (!LockFileEx((HANDLE)_get_osfhandle(pCache->fd), LOCKFILE_EXCLUSIVE_LOCK, 0, ~0, 0, NULL))
+    memset(&OverLapped, 0, sizeof(OverLapped));
+    if (!LockFileEx((HANDLE)_get_osfhandle(pCache->fd), LOCKFILE_EXCLUSIVE_LOCK, 0, ~0, 0, &OverLapped))
         FatalDie("Failed to lock the cache file: Windows Error %d\n", GetLastError());
 #else
@@ -3237,4 +3312,7 @@
 static void kObjCacheUnlock(PKOBJCACHE pCache)
 {
+#if defined(__WIN__)
+    OVERLAPPED OverLapped;
+#endif
     assert(pCache->fLocked);
 
@@ -3255,5 +3333,6 @@
      */
 #if defined(__WIN__)
-    if (!UnlockFileEx((HANDLE)_get_osfhandle(pCache->fd), 0, ~0U, 0, NULL))
+    memset(&OverLapped, 0, sizeof(OverLapped));
+    if (!UnlockFileEx((HANDLE)_get_osfhandle(pCache->fd), 0, ~0U, 0, &OverLapped))
         FatalDie("Failed to unlock the cache file: Windows Error %d\n", GetLastError());
 #else
@@ -3313,4 +3392,6 @@
      */
     pEntry->uKey = pCache->uNextKey++;
+    if (!pEntry->uKey)
+        pEntry->uKey = pCache->uNextKey++;
     i = pCache->cDigests;
     while (i-- > 0)
@@ -3328,5 +3409,5 @@
     if (    !(pCache->cDigests & 3)
         &&  (pCache->cDigests || !pCache->paDigests))
-        pCache->paDigests = xrealloc(pCache->paDigests, sizeof(pCache->paDigests[0]) * pCache->cDigests + 4);
+        pCache->paDigests = xrealloc(pCache->paDigests, sizeof(pCache->paDigests[0]) * (pCache->cDigests + 4));
 
     /*
@@ -3619,5 +3700,5 @@
     pCache = kObjCacheCreate(pszCacheFile);
 
-    pEntry = kOCEntryCreate(pszCacheFile);
+    pEntry = kOCEntryCreate(pszEntryFile);
     kOCEntryRead(pEntry);
     kOCEntrySetCompileArgv(pEntry, papszArgvCompile, cArgvCompile);
@@ -3638,5 +3719,7 @@
          * Optimize this path as it is frequently used when making a clean build.
          */
+        kObjCacheUnlock(pCache);
         kOCEntryPreCompileAndCompile(pEntry, papszArgvPreComp, cArgvPreComp);
+        kObjCacheLock(pCache);
     }
     else
@@ -3670,4 +3753,6 @@
             }
         }
+        else
+            kObjCacheLock(pCache);
     }
 
@@ -3678,4 +3763,5 @@
     kOCEntryWrite(pEntry);
     kObjCacheUnlock(pCache);
+    kObjCacheDestroy(pCache);
     return 0;
 }
