Changeset 907 for trunk/dll/comp.c


Ignore:
Timestamp:
Jan 6, 2008, 8:26:17 AM (18 years ago)
Author:
Steven Levine
Message:

Avoid out of memory traps in Compare Directories
Rework Compare Directories progress display for 2 second update rate
Start refactoring to reduce dependence on fm3dll.h
Add timer services (IsITimerExpired etc.)

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/dll/comp.c

    r897 r907  
    77
    88  Copyright (c) 1993-02 M. Kimes
    9   Copyright (c) 2003, 2007 Steven H. Levine
     9  Copyright (c) 2003, 2008 Steven H. Levine
    1010
    1111  16 Oct 02 MK Baseline
     
    4040  27 Sep 07 SHL Correct ULONGLONG size formatting
    4141  30 Dec 07 GKY Use TestCDates for compare by file date/time
     42  04 Jan 08 SHL Avoid traps if CM_ALLOCRECORD returns less that requested
     43  05 Jan 08 SHL Use WM_TIMER for progress messaging
     44  05 Jan 08 SHL Use ITIMER_DESC for hogging control
    4245
    4346***********************************************************************/
     47
     48#include <stdlib.h>
     49#include <string.h>
     50#include <share.h>
     51#include <io.h>
     52#include <process.h>                    // _beginthread
    4453
    4554#define INCL_DOS
     
    4857#define INCL_GPI
    4958#define INCL_LONGLONG
    50 #include <os2.h>
    51 
    52 #include <stdio.h>
    53 #include <stdlib.h>
    54 #include <string.h>
    55 #include <ctype.h>
    56 #include <share.h>
    57 #include <io.h>
    58 #include <process.h>                    // _beginthread
    59 
    60 #include "fm3dll.h"
     59
    6160#include "fm3dlg.h"
    6261#include "fm3str.h"
     62#include "pathutil.h"                   // BldFullPathName
     63#include "filldir.h"                    // EmptyCnr...
     64#include "makelist.h"                   // AddToFileList...
     65#include "errutil.h"                    // Dos_Error...
     66#include "strutil.h"                    // GetPString
     67#include "tmrsvcs.h"                    // IsITimerExpired
     68#include "comp.h"
     69#include "fm3dll.h"
    6370
    6471typedef struct
     
    7178
    7279static PSZ pszSrcFile = __FILE__;
    73 
    74 /**
    75  * Build full path name in callers buffer given directory
    76  * name and filename
    77  * @param pszPathName points to drive/directory if not NULL
    78  * @returns pointer to full path name in caller's buffer
    79  * @note OK for pszFullPathName and pszPathName to point to same buffer
    80  *
    81  */
    82 
    83 PSZ BldFullPathName(PSZ pszFullPathName, PSZ pszPathName, PSZ pszFileName)
    84 {
    85   UINT c = pszPathName ? strlen(pszPathName) : 0;
    86   if (c > 0) {
    87     memcpy(pszFullPathName, pszPathName, c);
    88     if (pszFullPathName[c - 1] != '\\')
    89       pszFullPathName[c++] = '\\';
    90   }
    91   strcpy(pszFullPathName + c, pszFileName);
    92   return pszFullPathName;
    93 }
    9480
    9581//=== SnapShot() Write directory tree to file and recurse if requested ===
     
    116102      // 13 Aug 07 SHL fixme to report errors
    117103      if (!xDosFindFirst(mask,
    118                          &hdir,
     104                         &hdir,
    119105                         FILE_NORMAL | FILE_DIRECTORY |
    120106                         FILE_ARCHIVED | FILE_READONLY | FILE_HIDDEN |
     
    450436                        MPFROM2SHORT(CMA_FIRST, CMA_ITEMORDER));
    451437
     438      WinStartTimer(hab, cmp->hwnd, ID_TIMER, 2000);
     439
    452440      while (pci && (INT)pci != -1 && pciD && (INT)pciD != -1) {
    453441
     
    675663      } // while
    676664    Abort:
     665      WinStopTimer(hab, cmp->hwnd, ID_TIMER);
    677666      WinDestroyMsgQueue(hmq);
    678667    }
     668    PostMsg(cmp->hwnd, UM_CONTAINER_FILLED, MPFROMLONG(1L), MPVOID);
     669    PostMsg(cmp->hwnd, WM_COMMAND, MPFROM2SHORT(IDM_DESELECTALL, 0), MPVOID);
    679670    DecrThreadUsage();
    680671    WinTerminate(hab);
    681672  }
    682   PostMsg(cmp->hwnd, UM_CONTAINER_FILLED, MPFROMLONG(1L), MPVOID);
    683   PostMsg(cmp->hwnd, WM_COMMAND, MPFROM2SHORT(IDM_DESELECTALL, 0), MPVOID);
    684673  free(cmp);
    685674}
     
    707696      IncrThreadUsage();
    708697      priority_normal();
     698      WinStartTimer(hab, cmp->hwnd, ID_TIMER, 2000);
    709699      switch (cmp->action) {
    710700      case IDM_INVERT:
     
    724714        break;
    725715      }
     716      WinStopTimer(hab, cmp->hwnd, ID_TIMER);
    726717      if (!PostMsg(cmp->hwnd, UM_CONTAINER_FILLED, MPFROMLONG(1L), MPVOID))
    727718        WinSendMsg(cmp->hwnd, UM_CONTAINER_FILLED, MPFROMLONG(1L), MPVOID);
     
    738729 */
    739730
    740 static VOID FillDirList(CHAR *str, INT skiplen, BOOL recurse,
    741                         FILELIST ***list, INT *numfiles, INT *numalloc)
     731static VOID FillDirList(CHAR *str, UINT skiplen, BOOL recurse,
     732                        FILELIST ***list, UINT *pnumfiles, UINT *pnumalloc)
    742733{
    743734  CHAR *enddir;
     
    780771  ulFindCnt = FilesToGet;
    781772  rc = xDosFindFirst(maskstr, &hDir,
    782                      FILE_NORMAL | FILE_READONLY | FILE_ARCHIVED |
     773                     FILE_NORMAL | FILE_READONLY | FILE_ARCHIVED |
    783774                     FILE_SYSTEM | FILE_HIDDEN |
    784775                     (recurse ? FILE_DIRECTORY : 0),
     
    799790              strlwr(pffbFile->achName);
    800791            memcpy(enddir, pffbFile->achName, pffbFile->cchName + 1);
    801             FillDirList(maskstr, skiplen, recurse, list, numfiles, numalloc);
     792            FillDirList(maskstr, skiplen, recurse, list, pnumfiles, pnumalloc);
    802793          }
    803794        }
     
    809800          memcpy(enddir, pffbFile->achName, pffbFile->cchName + 1);
    810801          if (AddToFileList(maskstr + skiplen,
    811                             pffbFile, list, numfiles, numalloc)) {
     802                            pffbFile, list, pnumfiles, pnumalloc)) {
    812803            goto Abort;
    813804          }
     
    847838}
    848839
    849 // 20 Aug 07 SHL experimental fixme
    850 
    851 typedef struct {
    852   // Caller must init
    853   UINT sleepTime;               // How long to sleep
    854   UINT interval;                // How often to sleep
    855   // Owned by SleepIfNeeded
    856   UINT modulo;                  // How often to call GetMSecTimer
    857   UINT cntr;                    // Call counter
    858   ULONG lastMSec;               // Last time DosSleep invoked
    859 } SLEEP_DESC;
    860 
    861 VOID SleepIfNeeded(BOOL id, UINT interval, UINT sleepTime)
    862 {
    863   static ULONG lastMSec[10];
    864   static UINT cntr;
    865   static UINT modulo = 32;
    866   BOOL yes = ++cntr >= modulo;
    867 
    868   if (yes) {
    869     ULONG newMSec = GetMSecTimer();
    870     // 1st time will have large difference, but don't care
    871     ULONG diff = newMSec - lastMSec[id];
    872     cntr = 0;
    873     yes = diff >= interval;
    874     // Try to tune modulo counter to approx 12% error
    875     if (yes) {
    876       lastMSec[id] = newMSec;
    877       if (diff >= interval + (interval / 8) && modulo > 0)
    878         modulo--;
    879     }
    880     else {
    881       if (diff < interval - (interval / 8))
    882         modulo++;
    883     }
    884     DosSleep(sleepTime);
    885   }
    886 }
    887 
    888840//=== FillCnrsThread() Fill left and right containers ===
    889841
     
    894846  HMQ hmq;
    895847  BOOL notified = FALSE;
    896 
    897 #if 0
    898   ULONG lastMSec = GetMSecTimer();
    899   ULONG ul;
    900 #endif
     848  ITIMER_DESC itdSleep = { 0 };
    901849
    902850  HWND hwndLeft, hwndRight;
     
    912860
    913861  DosError(FERR_DISABLEHARDERR);
     862
     863  InitITimer(&itdSleep, 500);           // Sleep every 500 mSec
    914864
    915865  hab = WinInitialize(0);
     
    923873    else {
    924874      INT x;
    925       INT l;
    926       INT r;
     875      UINT l;
     876      UINT r;
    927877      UINT cntr;
    928878      FILELIST **filesl = NULL;
    929879      FILELIST **filesr = NULL;
    930       INT numfilesl = 0;
    931       INT numfilesr = 0;
    932       INT numallocl = 0;
    933       INT numallocr = 0;
     880      UINT numfilesl = 0;
     881      UINT numfilesr = 0;
     882      UINT numallocl = 0;
     883      UINT numallocr = 0;
    934884      INT ret = 0;
    935885      UINT lenl;                        // Directory prefix length
    936886      UINT lenr;
    937887      UINT recsNeeded;
     888      UINT recsGotten;
     889      UINT filesSeenL;
     890      UINT filesSeenR;
    938891      PCNRITEM pcilFirst;
    939892      PCNRITEM pcirFirst;
     893      PCNRITEM pcilLast;
     894      PCNRITEM pcirLast;
    940895      PCNRITEM pcil;
    941896      PCNRITEM pcir;
     
    945900      WinCancelShutdown(hmq, TRUE);
    946901      IncrThreadUsage();
     902      WinStartTimer(hab, cmp->hwnd, ID_TIMER, 2000);
     903
    947904      hwndLeft = WinWindowFromID(cmp->hwnd, COMP_LEFTDIR);
    948905      hwndRight = WinWindowFromID(cmp->hwnd, COMP_RIGHTDIR);
     
    965922        strupr(cmp->leftdir);
    966923      FillDirList(cmp->leftdir, lenl, cmp->includesubdirs,
    967                   &filesl, &numfilesl, &numallocl);
     924                  &filesl, &cmp->cmp->totalleft, &numallocl);
     925      numfilesl = cmp->cmp->totalleft;
    968926
    969927      if (filesl)
     
    979937          strupr(cmp->rightdir);
    980938        FillDirList(cmp->rightdir, lenr, cmp->includesubdirs,
    981                     &filesr, &numfilesr, &numallocr);
     939                    &filesr, &cmp->cmp->totalright, &numallocr);
     940        numfilesr = cmp->cmp->totalright;
    982941      }
    983942      else {
     
    11441103      } // while
    11451104
     1105      // Say building list - fixme to post?
    11461106      WinSendMsg(cmp->hwnd, UM_CONTAINERHWND, MPVOID, MPVOID);
    11471107
     
    11781138        pcil = pcilFirst;
    11791139        pcir = pcirFirst;
     1140        pcilLast = 0;
     1141        pcirLast = 0;
     1142
     1143        recsGotten = 0;
     1144        filesSeenL = 0;
     1145        filesSeenR = 0;
     1146
    11801147        while ((filesl && filesl[l]) || (filesr && filesr[r])) {
     1148
     1149          // 03 Jan 08 SHL fixme to have user friendly message
     1150          if (!pcil) {
     1151            Runtime_Error(pszSrcFile, __LINE__, "pcil short %u/%u",
     1152                          recsGotten, recsNeeded);
     1153            break;
     1154          }
     1155
     1156          // 03 Jan 08 SHL fixme to have user friendly message
     1157          if (!pcir) {
     1158            Runtime_Error(pszSrcFile, __LINE__, "pcir short %u/%u",
     1159                          recsGotten, recsNeeded);
     1160            break;
     1161          }
     1162          recsGotten++;
    11811163          pcir->hwndCnr = hwndRight;
    11821164          pcir->rc.hptrIcon = (HPOINTER) 0;
     
    11951177          if (x <= 0) {
    11961178            // File appears on left side
     1179            filesSeenL++;
    11971180            BldFullPathName(szBuf, cmp->leftdir, filesl[l]->fname);
    11981181            //sprintf(szBuf, "%s%s%s", cmp->leftdir,
     
    12331216          if (x >= 0) {
    12341217            // File appears on right side
     1218            filesSeenR++;
    12351219            BldFullPathName(szBuf, cmp->rightdir, filesr[r]->fname);
    12361220            //sprintf(szBuf, "%s%s%s", cmp->rightdir,
     
    12911275              strcpy(pch, GetPString(IDS_SMALLERTEXT));
    12921276              pch += 7;
    1293             }
    1294             ret = TestCDates(&pcir->date, &pcir->time,
    1295                              &pcil->date, &pcil->time);
    1296             if (ret == 1)
    1297               /*((pcil->date.year > pcir->date.year) ? TRUE :
     1277            }
     1278            ret = TestCDates(&pcir->date, &pcir->time,
     1279                             &pcil->date, &pcil->time);
     1280            if (ret == 1)
     1281              /*((pcil->date.year > pcir->date.year) ? TRUE :
    12981282                (pcil->date.year < pcir->date.year) ? FALSE :
    12991283                (pcil->date.month > pcir->date.month) ? TRUE :
     
    13161300              pch += 5;
    13171301            }
    1318             else if (ret == -1)
    1319               /*((pcil->date.year < pcir->date.year) ? TRUE :
     1302            else if (ret == -1)
     1303              /*((pcil->date.year < pcir->date.year) ? TRUE :
    13201304                     (pcil->date.year > pcir->date.year) ? FALSE :
    13211305                     (pcil->date.month < pcir->date.month) ? TRUE :
     
    13821366            pcir->pszDispAttr = NullStr;
    13831367
    1384 #if 0                                   // 20 Aug 07 SHL fixme to be gone
    1385           if (!(cntr % 500))
    1386             DosSleep(1);
    1387           else if (!(cntr % 50))
    1388             DosSleep(0);
    1389           cntr++;
    1390 #endif
    1391 #if 0                                   // 20 Aug 07 SHL
    1392           if (cntr++ % 256 == 0) {
    1393             ul = GetMSecTimer();
    1394             if (ul - lastMSec >= 200) {
    1395               lastMSec = ul;
    1396               DosSleep(1);
    1397             }
    1398           }
    1399 #endif
    1400 #if 1                                   // 20 Aug 07 SHL
    1401           SleepIfNeeded(0, 500, 1);
    1402 #endif
    1403 
     1368          // Avoid hogging systems
     1369          SleepIfNeeded(&itdSleep, 0);
     1370
     1371          pcilLast = pcil;
     1372          pcirLast = pcir;
    14041373          pcil = (PCNRITEM) pcil->rc.preccNextRecord;
    14051374          pcir = (PCNRITEM) pcir->rc.preccNextRecord;
    14061375
     1376          // Show running totals every 2 seconds
     1377          cmp->cmp->totalleft = filesSeenL;
     1378          cmp->cmp->totalright = filesSeenR;
     1379
    14071380        } // while filling left or right
     1381
     1382        // If stopped early CM_ALLOCATERECORD partially failed
     1383        // Free up container records we did not use on other side
     1384        // Free up filesl/filer entries we skipped
     1385        if (recsGotten < recsNeeded) {
     1386          if (pcil) {
     1387            pcilLast->rc.preccNextRecord = NULL;
     1388            FreeCnrItemList(hwndLeft, pcil);
     1389          }
     1390          if (filesl) {
     1391            while (filesl[l]) {
     1392              free(filesl[l]);
     1393              l++;
     1394            }
     1395          }
     1396          if (pcir) {
     1397            pcirLast->rc.preccNextRecord = NULL;
     1398            FreeCnrItemList(hwndRight, pcir);
     1399          }
     1400          if (filesr) {
     1401            while (filesr[r]) {
     1402              free(filesr[r]);
     1403              r++;
     1404            }
     1405          }
     1406          // Reduce counts to match what is in container
     1407          if (numfilesl > filesSeenL)
     1408            numfilesl = filesSeenL;
     1409          if (numfilesr > filesSeenR)
     1410            numfilesr = filesSeenR;
     1411          recsNeeded = recsGotten;
     1412        } // if insufficient resources
     1413
    14081414
    14091415        if (filesl)
     
    14131419          free(filesr);
    14141420        filesr = NULL;
    1415         // Insert 'em
     1421
     1422        // Say inserting
    14161423        WinSendMsg(cmp->hwnd, UM_CONTAINERDIR, MPVOID, MPVOID);
    14171424
     1425        // Insert left side
    14181426        memset(&ri, 0, sizeof(RECORDINSERT));
    14191427        ri.cb = sizeof(RECORDINSERT);
     
    14301438        }
    14311439
     1440        // Insert right side
    14321441        memset(&ri, 0, sizeof(RECORDINSERT));
    14331442        ri.cb = sizeof(RECORDINSERT);
     
    14531462      } // if recsNeeded
    14541463
     1464      WinStopTimer(hab, cmp->hwnd, ID_TIMER);
     1465
    14551466      Deselect(hwndLeft);
    14561467      Deselect(hwndRight);
     
    14581469      // DbgMsg(pszSrcFile, __LINE__, "FillCnrsThread deselected");
    14591470
     1471      // Request window update
    14601472      if (!PostMsg(cmp->hwnd, UM_CONTAINER_FILLED, MPVOID, MPVOID))
    14611473        WinSendMsg(cmp->hwnd, UM_CONTAINER_FILLED, MPVOID, MPVOID);
     
    14701482
    14711483      WinDestroyMsgQueue(hmq);
    1472     }
     1484    } // if have queue
     1485    if (!notified)
     1486      PostMsg(cmp->hwnd, UM_CONTAINER_FILLED, MPVOID, MPVOID);
    14731487    DecrThreadUsage();
    14741488    WinTerminate(hab);
    14751489  }
    1476   if (!notified)
    1477     PostMsg(cmp->hwnd, UM_CONTAINER_FILLED, MPVOID, MPVOID);
    14781490  free(cmp);
    14791491  DosPostEventSem(CompactSem);
     
    14851497#define hwndLeft        (WinWindowFromID(hwnd,COMP_LEFTDIR))
    14861498#define hwndRight       (WinWindowFromID(hwnd,COMP_RIGHTDIR))
    1487 
    1488 // 20 Aug 07 SHL fixme experimental
    1489 
    1490 BOOL NeedGUIUpdate(BOOL id)
    1491 {
    1492   static ULONG lastMSec[10];
    1493   static UINT cntr;
    1494   static UINT modulo = 32;
    1495   BOOL yes = ++cntr >= modulo;
    1496 
    1497   if (yes) {
    1498     ULONG newMSec = GetMSecTimer();
    1499     // 1st time will have large difference, but don't care
    1500     ULONG diff = newMSec - lastMSec[id];
    1501     cntr = 0;
    1502     yes = diff >= 500;
    1503     // Try to tune modulo counter to 10% error
    1504     if (yes) {
    1505       lastMSec[id] = newMSec;
    1506       if (diff >= 550 && modulo > 0)
    1507         modulo--;
    1508     }
    1509     else {
    1510       if (diff < 450)
    1511         modulo++;
    1512     }
    1513   }
    1514   return yes;
    1515 }
    15161499
    15171500//=== CompareDlgProc() Compare directories dialog procedure ===
     
    15211504  COMPARE *cmp;
    15221505  BOOL temp;
     1506  CHAR s[81];
    15231507
    15241508  static HPOINTER hptr;
     
    17101694
    17111695  case UM_CONTAINERHWND:
     1696    // Building list
    17121697    WinSetDlgItemText(hwnd, COMP_NOTE, GetPString(IDS_COMPHOLDBLDLISTTEXT));
    17131698    return 0;
    17141699
    17151700  case UM_CONTAINERDIR:
     1701    // Filling container
    17161702    WinSetDlgItemText(hwnd, COMP_NOTE, GetPString(IDS_COMPHOLDFILLCNRTEXT));
    17171703    return 0;
     1704
     1705  case WM_TIMER:
     1706    // Show current totals
     1707    cmp = INSTDATA(hwnd);
     1708    if (!cmp) {
     1709      Runtime_Error(pszSrcFile, __LINE__, "pCompare NULL");
     1710      WinDismissDlg(hwnd, 0);
     1711    }
     1712    else {
     1713      // 05 Jan 08 SHL fixme to use timer id to optimize output
     1714      sprintf(s, " %d", cmp->totalleft);
     1715      WinSetDlgItemText(hwnd, COMP_TOTALLEFT, s);
     1716      sprintf(s, " %d", cmp->totalright);
     1717      WinSetDlgItemText(hwnd, COMP_TOTALRIGHT, s);
     1718      sprintf(s, " %d", cmp->selleft);
     1719      WinSetDlgItemText(hwnd, COMP_SELLEFT, s);
     1720      sprintf(s, " %d", cmp->selright);
     1721      WinSetDlgItemText(hwnd, COMP_SELRIGHT, s);
     1722    }
     1723    break;
    17181724
    17191725  case UM_CONTAINER_FILLED:
     
    17241730    }
    17251731    else {
    1726       CHAR s[81];
    17271732
    17281733      // DbgMsg(pszSrcFile, __LINE__, "CompareDlgProc UM_CONTAINER_FILLED enter");
     
    19381943              else {
    19391944
    1940                 CHAR s[81];
    1941 
    19421945                cmp = INSTDATA(hwnd);
    19431946                if (pci->rc.flRecordAttr & CRA_SELECTED) {
     
    19551958                    if (cmp->selright)
    19561959                      cmp->selright--;
    1957                   }
    1958                 }
    1959                 if (SHORT1FROMMP(mp1) == COMP_LEFTDIR) {
    1960                   // if (WinIsWindowEnabled(hwndLeft) || !(cmp->selleft % 50)) {
    1961                   if (WinIsWindowEnabled(hwndLeft) || NeedGUIUpdate(0)) {
    1962                     sprintf(s, " %d", cmp->selleft);
    1963                     WinSetDlgItemText(hwnd, COMP_SELLEFT, s);
    1964                   }
    1965                 }
    1966                 else {
    1967                   // if (WinIsWindowEnabled(hwndRight) || !(cmp->selright % 50)) {
    1968                   if (WinIsWindowEnabled(hwndRight) || NeedGUIUpdate(1)) {
    1969                     sprintf(s, " %d", cmp->selright);
    1970                     WinSetDlgItemText(hwnd, COMP_SELRIGHT, s);
    19711960                  }
    19721961                }
     
    21802169            fakelist[2] = NULL;
    21812170            ExecOnList(hwnd, compare,
    2182                        WINDOWED | SEPARATEKEEP, NULL, fakelist, NULL,
    2183                        pszSrcFile, __LINE__);
     2171                       WINDOWED | SEPARATEKEEP, NULL, fakelist, NULL,
     2172                       pszSrcFile, __LINE__);
    21842173          }
    21852174          else {
Note: See TracChangeset for help on using the changeset viewer.