home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 8 Other / 08-Other.zip / eidete19.zip / CDTEST.CPP next >
C/C++ Source or Header  |  1995-10-29  |  25KB  |  950 lines

  1. /*  CDtest 1.2
  2.  
  3.     Tests if simultaneous I/O corrupts CD-ROM reading.  If so, likely causes are the
  4.     PCI RZ-1000 EIDE chip, the CMD-640 EIDE chip or a faulty DMA controller.
  5.     Runs under DOS, DESQview, Windows, NT and OS/2 in DOS emulation mode.
  6.  
  7.     This program may be copied freely and used for any purpose except military.
  8.     (c) copyright 1995 by
  9.     Roedy Green
  10.     Canadian Mind Products
  11.     #601 - 1330 Burrard Street
  12.     Vancouver, BC Canada V6Z 2B8
  13.     (604) 685-8412
  14.     Internet Roedy@bix.com
  15.  
  16.     compiled under SMALL model
  17.  
  18.     It works by reading a set of files repeatedly from the CD-ROM drive
  19.     and computing a checksum on each file.  It reads the same set of
  20.     files multiple times with as much I/o as possible
  21.     interfering.  It ensures the same checksum is computed each time.
  22.  
  23.  
  24.     Version history
  25.  
  26.     1.2 - consistent use of term CMD-640.
  27.     1.1 - add warning about turnin on background execution.
  28.     1.0 - first version, cloned and modified from EIDEtest
  29.     */
  30.  
  31. /* D E F I N E S */
  32.  
  33. #define BufferSizeInBytes 31744
  34. /* size of buffer for reading the files.
  35.    This size should generate lots of physical I/O.
  36.    Smaller sizes might come out of cache.
  37.    Bigger sizes do only a few big I/Os */
  38.  
  39. #define TestSizeInBytes 7616560L
  40. /* aggregate bytes to read for the test per pass, spread over many files. */
  41.  
  42. #define MaxFiles 2000
  43. /* maximum number of files on CDROM that will be processed.
  44.    Up to this many will have checksums computed.
  45.    Usually TestSizeInBytes will be the limiting factor. */
  46.  
  47. #define StartDecorate "\xb0\xb1\xb2\xdb"
  48. /* line of pretty blobs in oemfont to attract attention */
  49. #define EndDecorate   "\xdb\xb2\xb1\xb0"
  50.  
  51. #define Esc '\x1b'
  52.  
  53. /* T Y P E D E F S */
  54.  
  55. typedef unsigned short WORD;
  56.  
  57. typedef unsigned char BYTE;
  58.  
  59. typedef enum BOOL
  60. {
  61.   FALSE, TRUE
  62. } BOOL;
  63.  
  64. typedef enum TESTRESULT
  65. {
  66.    PASS, FAIL, INCOMPLETE
  67. } TESTRESULT;
  68.  
  69. typedef unsigned int ATTRIB;
  70.  
  71. typedef char ATTRIBPATTERN [7];
  72.  
  73. /* I N C L U D E S */
  74.  
  75. #include <stdlib.h>
  76. // e.g. exit, min, max
  77.  
  78. #include <stdio.h>
  79. // e.g. FILE, printf, fopen
  80.  
  81. #include <conio.h>
  82. // e.g. getch kbhit crlscr
  83.  
  84. #include <alloc.h>
  85. // e.g. malloc free
  86.  
  87. #include <dos.h>
  88. // _dos_findfirst _dos_findnext
  89.  
  90. #include <string.h>
  91. // strcpy
  92.  
  93. /* G L O B A L S */
  94.  
  95. char WildCard[] = "E:\\*.*";
  96. /*  Wildcard to describe all files on the EIDE CD-ROM */
  97.  
  98. /* P R O T O T Y P E S */
  99.  
  100. int main( int argc,  char *argv[] );
  101. void Banner ( void );
  102. void beep (void );
  103. int pause ( void );
  104. int DoesOSDoSimultaneousIO ( void );
  105. int CheckForEsc ( void );
  106.  
  107. /* ***************************************** */
  108.  
  109. /* C L A S S  D E C L A R A T I O N */
  110.  
  111. class FILETREE
  112.     {
  113.     /* class to process a set of files matching a wildcard */
  114.  public:
  115.  
  116.     FILETREE() {};
  117.  
  118.     ~FILETREE() {};
  119.  
  120.     void ForEachFile(char * WildCard, ATTRIBPATTERN AttribPattern, BOOL Recurse );
  121.     /* calls ProcessOneFile for each match
  122.      *                      ADVSHR
  123.      * e.g. C:\XXX\*.TXT,  "?00+1-", TRUE if /S style apply recursively to subdirs */
  124.  
  125.     /* attribute pattern string is of form:
  126.      * ADVSHR A-archive D-directory V-volume S-system H-hidden R-read-only
  127.      * "ADVSHR"
  128.      * "?00+1-" <-- example
  129.      * ?=ignore, irrelevant.
  130.      * 1=must be 1
  131.      * 0=must be 0
  132.      * +=must have some 1s, all plus slots many not be 0
  133.      * -=must have some 0s, all minus slots may not be 1 */
  134.  
  135.  
  136.     virtual BOOL ProcessOneFile ( char * QualFileName, long FileSize ) = 0;
  137.     /* returns true to abort entire process.
  138.        Code to process one file, custom-written for each use. */
  139.  
  140.  protected:
  141.  
  142.     BOOL Stop; /* true if we want to stop ForEachFile early */
  143.  
  144.     void ProcessSubs( char * WildCard );
  145.     /* recursively process all files in all subdirs matching the
  146.      * given wildcard pattern.
  147.      * WildCard will be of form C:\xxx\*.TXT */
  148.  
  149.     void ProcessFiles ( char * WildCard );
  150.     /* process all files matching given WildCard.  No recursion.
  151.      * WildCard will be of form C:\xxx\*.TXT */
  152.  
  153.     char * Join ( char * Result, char * WildCard, char * SubDir, char * FileName );
  154.     /* append Subdir and FileName onto WildCard,
  155.      * e.g. C:\xxx\*.* , yyy , a.b -> C:\xxx\yyy\a.b
  156.      * Subdir or FileName might be null */
  157.  
  158.     BOOL    FineAttribFilter[64];
  159.     /* whether to accept each of 64 possible
  160.      * attributes.  Built by invoking the
  161.      * ProbeAttribFilter function with each of the
  162.      * 64 possible attributes. */
  163.  
  164.     ATTRIB  CoarseAttribFilter;
  165.     /* Attribute mask to grossly filter out files never wanted. DOS behaves a
  166.      * little strangely when fed a coarse filter.  It completely ignores the
  167.      * read-only and archive bits. If you ask for DIRs, you get normal files
  168.      * too. But, if you ask for Vol, you DON'T get anything but VOL. It is
  169.      * all bizarrely asymmetric. We ignore this, and carry on as if DOS were
  170.      * consistent.  It comes out ok in the wash, since the FineAttribFilter
  171.      * filters the mess DOS gives us. */
  172.  
  173.     void InitAttribFilters (ATTRIBPATTERN AttribPattern);
  174.     /* calculate FineAttribFilter and CoarseAttribFilter  */
  175.  
  176.     BOOL ProbeAttribFilter(ATTRIB Attrib, ATTRIBPATTERN AttribPattern);
  177.     /* returns true if given attribute
  178.        bit pattern is acceptable according to AttribPattern */
  179.  
  180. };
  181.  
  182. /*********************/
  183.  
  184. class CRC
  185.     {
  186.     /* calculate 16-bit checksums  */
  187.  public:
  188.  
  189.     CRC(void) { work = 0; }
  190.  
  191.     ~CRC() { }
  192.  
  193.     WORD Result(void) { return work; }
  194.  
  195.     void Reset(void) { work = 0; }
  196.  
  197.     void Append( BYTE *String, WORD Length );
  198.  
  199.     static int InitCRCTable(WORD Poly = 0x8408);
  200.     /* usually we would use Poly = 0x8408, the 16-bit CCITT polynomial.
  201.        build lookup table to help compute the CRC function.
  202.        Only needs be called once. */
  203.  
  204.  protected:
  205.  
  206.     static WORD CRCTable[256];
  207.     /* magic numbers used to compute CRC .
  208.        table of constants.  Only one copy needed */
  209.  
  210.     WORD work;
  211.     /* where we accumulate the crc */
  212.  
  213. };
  214.  
  215. /* ***************************************** */
  216.  
  217. class VERIFY : public FILETREE
  218.     {
  219.     /* class to repeatedly read files off the CD-ROM and make sure they are
  220.        the same each time.  Computes and compares checksums */
  221.  public:
  222.  
  223.     VERIFY(void);
  224.  
  225.     ~VERIFY() {};
  226.  
  227.     void VERIFY::Phase1 ( void );
  228.  
  229.     void VERIFY::Phase2 ( void );
  230.  
  231.     void DisplayResults( void );
  232.  
  233.     BOOL ProcessOneFile ( char * QualFileName, long FileSize );
  234.     /* returns true to abort entire process.
  235.        Computes checksum for one file.
  236.        It gets passed a fully qualified FileName and its size */
  237.  
  238.     CRC OneFileCRC;
  239.     /* CRC object to compute CRC for current file. */
  240.  
  241.     int Phase; /* 1=compute CRC or 2=verify CRC */
  242.  
  243.     TESTRESULT TestResult;
  244.     /* result of the entire test */
  245.  
  246.     BOOL TestDone;
  247.     /* true if no more processing to do */
  248.  
  249.     WORD ExpectedCRC [MaxFiles];
  250.     /* CRC expected for each file */
  251.  
  252.     int  FileIndex; /* which file we are processing on CD ROM */
  253.  
  254.     long ToGo;
  255.     /* How many more bytes we need to read for the pass.
  256.        We don't read the entire CD-ROM, just the first 7 MB or so */
  257.  
  258. };
  259.  
  260. /* ***************************************** */
  261.  
  262. /* S T A T I C   D E F I N I T I O N S */
  263.  
  264. /* must define, as opposed to declare, static variables in class
  265.    in order to allocate static RAM for them. */
  266.  
  267. WORD CRC::CRCTable[256];
  268. int dummy = CRC::InitCRCTable();
  269.  
  270. /* ***************************************** */
  271.  
  272. /* F U N C T I O N   D E F I N I T I O N S */
  273.  
  274. int main( int argc,  char *argv[] )
  275.  
  276. {
  277.     Banner();
  278.  
  279.     if ( argc != 2 /*  0=CDtest.Exe 1=E: */ )
  280.     {
  281.     printf("Oops!  usage:  CDtest  E:"
  282.         "\nwhere E: is the EIDE CD-ROM to test.");
  283.     exit (2);
  284.     }
  285.  
  286.     /* replace first letter of WildCard with Drive Letter */
  287.     /* e.g. WildCard might now read:  E:\*.* */
  288.     WildCard[0] = *argv[1];
  289.  
  290.     VERIFY Verify; /* object to do all the CD-ROM reading tests */
  291.  
  292.     printf("\nYou must run CDtest with background execution configured on."
  293.     "\nAbort now if you have not done so."
  294.     "\n");
  295.  
  296.     if ( pause() == 2 )  Verify.TestDone = TRUE; /* user ESC abort */
  297.     else
  298.     {
  299.     printf("\nInsert any CD-ROM in drive %s", argv[1]);
  300.     if ( pause() == 2 )  Verify.TestDone = TRUE; /* user ESC abort */
  301.     }
  302.  
  303.     /* do Phase 1 */
  304.     Verify.Phase1();
  305.     beep(); /* announce Phase1 over */
  306.  
  307.     /* do Phase 2 */
  308.     Verify.Phase2();
  309.     beep(); /* announce Phase2 over */
  310.  
  311.     Verify.DisplayResults(); /* report good or bad news */
  312.  
  313.     return (int) Verify.TestResult ; /* 0 = pass, 1 = fail, 2 = incomplete */
  314.  
  315. } /* end main */
  316.  
  317.  
  318. /*****************/
  319.  
  320. void Banner(void)
  321. {
  322.     /* display copyright banner. */
  323.  
  324.     clrscr(); /* clear screen */
  325.  
  326.     printf("\n" StartDecorate " CDtest 1.2 " EndDecorate
  327.     "\n"
  328.     "\nFreeware to test for the flawed EIDE controllers such as the"
  329.     "\nPC-Tech RZ-1000 and the CMD-640."
  330.     "\nRuns under DESQview, Windows, Windows For WorkGroups, Windows-95, NT"
  331.     "\nand OS/2 all in DOS emulation mode."
  332.     "\n"
  333.     "\nCopyright (c) 1995 Canadian Mind Products"
  334.     "\n#601 - 1330 Burrard Street, Vancouver BC CANADA V6Z 2B8  (604) 685-8412"
  335.     "\nInternet: Roedy@bix.com <Roedy Green>"
  336.     "\nMay be used freely for non-military use only."
  337.     "\n\n");
  338.  
  339. } /* end Banner */
  340.  
  341. /*****************/
  342.  
  343. VERIFY::VERIFY(void)
  344. {
  345.     /* constructor */
  346.     TestResult = INCOMPLETE;
  347.     TestDone = FALSE;
  348.     FileIndex = 0;
  349.     ToGo =TestSizeInBytes;
  350.  
  351. }
  352. /*****************/
  353.  
  354. void VERIFY::Phase1 ( void )
  355. {
  356.     Phase = 1;
  357.  
  358.     if (TestDone) return;
  359.  
  360.     clrscr(); /* clear screen */
  361.  
  362.     printf("\n" StartDecorate " PHASE 1 " EndDecorate
  363.     "\nDuring phase 1, do not run any other programs."
  364.     "\nEspecially avoid using the tape or floppy drive."
  365.     "\nShutdown all background programs BEFORE you proceed."
  366.     "\nIf you can't get them all, not to worry;"
  367.     "\nthe test results will still be valid."
  368.     "\n");
  369.  
  370.     if ( pause() == 2 )
  371.     {
  372.     TestDone = TRUE;
  373.     return; /* user abort */
  374.     }
  375.     printf("\nPhase 1 in progress.  Please stand by...\n");
  376.  
  377.  
  378.     /* read about 7 Mb of files, computing checksums. User may abort by hitting ESC */
  379.     FileIndex = 0;
  380.     ToGo =TestSizeInBytes;
  381.     ForEachFile ( WildCard,/* ADVSHR */  "?000??", TRUE /* recurse */ );
  382.     return;
  383. }       /* end Phase1 */
  384.  
  385.  
  386. /*****************/
  387.  
  388. void VERIFY::Phase2 ( void )
  389.  
  390. {
  391.     if (TestDone) return;
  392.  
  393.     clrscr(); /* clear screen */
  394.  
  395.     Phase = 2;
  396.  
  397.     switch (DoesOSDoSimultaneousIO())
  398.     {
  399.  
  400.     case 0: /* DOS */
  401.         clrscr(); /* clear screen */
  402.         printf( "\n" StartDecorate " PHASE 2 " EndDecorate
  403.         "\n"
  404.         "\nDURING phase 2, do as many of these tests with as you can"
  405.         "\neach with background execution configured ON,"
  406.         "\nto generate simultaneous I/O:"
  407.         "\n"
  408.         "\n- Backup some files to floppy with MWBackup, MSBackup, Norton Backup"
  409.         "\n  or other high performance floppy backup program with fast-mode"
  410.         "\n  simultaneous disk I/O configured."
  411.         "\n- Backup a file using your mag tape backup software with fast-mode"
  412.         "\n  simultaneous disk I/O configured."
  413.         "\n- Exercise any simultaneous I/O devices e.g. modem, mouse or sound card."
  414.         "\n");
  415.         break;
  416.  
  417.     case 1: /* OS */
  418.         clrscr(); /* clear screen */
  419.         printf( "\n" StartDecorate " PHASE 2 " EndDecorate
  420.         "\n"
  421.         "\nDURING phase 2, do as many of these tests with as you can"
  422.         "\neach with background execution configured ON,"
  423.         "\nto generate simultaneous I/O:"
  424.         "\n"
  425.         "\n- Format a floppy."
  426.         "\n- Backup some files to floppy with MWBackup, MSBackup, Norton Backup"
  427.         "\n  or other high performance floppy backup program with fast-mode"
  428.         "\n  simultaneous disk I/O configured."
  429.         "\n- Backup a file using your mag tape backup software with fast-mode"
  430.         "\n  simultaneous disk I/O configured."
  431.         "\n- Scan a document with your scanner."
  432.         "\n- Browse some files on other hard disks and CD-ROM."
  433.         "\n- Exercise any simultaneous I/O devices e.g. modem, mouse or sound card."
  434.         "\n");
  435.         break;
  436.  
  437.     case 2: /* esc */
  438.         TestDone = TRUE;
  439.         return;
  440.     }
  441.  
  442.  
  443.     printf("\nYour experiments may run slowly because of CDtest's I/O overhead."
  444.     "\n"
  445.     "\nBEGIN YOUR EXPERIMENTS NOW!"
  446.     "\n"
  447.     "\nTake all the time you want -- days even."
  448.     "\nWhen you have finished all your tests, come back and hit the space bar."
  449.     "\n"
  450.     "\nPhase 2 in progress..."
  451.     "\n");
  452.  
  453.     while ( ! TestDone )
  454.     {
  455.     /* keep repeating the test till user hits ESC or space bar */
  456.     FileIndex = 0;
  457.     ToGo = TestSizeInBytes;
  458.     ForEachFile ( WildCard,/* ADVSHR */  "?000??", TRUE /* recurse */ );
  459.     }
  460.     return;
  461. } /* Phase2 */
  462.  
  463. /*****************/
  464.  
  465. void VERIFY::DisplayResults( void )
  466. {
  467.  
  468.     clrscr(); /* clear screen */
  469.  
  470.     printf( "\n" StartDecorate " TEST RESULTS " EndDecorate
  471.     "\n");
  472.  
  473.     switch (TestResult)
  474.     {
  475.     case PASS:
  476.         printf("\nCDtest passed.  No flaws found."
  477.         "\nYou may still have a flawed EIDE controller chip with a"
  478.         "\nsuccessful software bypass."
  479.         "\nKeep in mind, that unless you carefully followed the"
  480.         " instructions on the,"
  481.         "\nscreen, especially running all tests with background execution"
  482.         "\nconfigured on, the results of this test are meaningless."
  483.         "\n");
  484.         break;
  485.  
  486.     case FAIL:
  487.         printf("\nCDtest failed."
  488.         "\nIf you have a PCI motherboard the failure is probably due to a faultly"
  489.         "\nPC-Tech RZ-1000 or CMD-640 EIDE controller chip."
  490.         "\nIt could also be due to overheating, a faulty DMA controller,"
  491.         "\nor software bugs.");
  492.         break;
  493.  
  494.     case INCOMPLETE:
  495.     default:
  496.         printf("\nCDtest not completed."
  497.         "\nPossibly a user abort or problems reading the CD-ROM drive."
  498.         "\n");
  499.         break;
  500.  
  501.     }
  502.     printf("\nPlease admire the test results.\n");
  503.     pause();
  504.  
  505. } /* end DisplayResults */
  506.  
  507. /* ***************************************** */
  508.  
  509. BOOL VERIFY::ProcessOneFile ( char * QualFileName, long FileSize )
  510. {
  511.     /* Gets called once for each file on the CD-ROM matching
  512.        WildCard and attribute filter.
  513.        It opens the file, and computes the checksum.
  514.        In Phase 1, computes checksums.  In Phase 2, verifies them */
  515.  
  516.     FILE *TempFile;
  517.  
  518.     BYTE *Buffer = new BYTE [BufferSizeInBytes];
  519.  
  520.     if (FileSize)
  521.     {
  522.     TempFile = fopen(QualFileName,"rb"); /* read binary mode */
  523.     if (TempFile )
  524.         {
  525.         /* got an acceptable file, start a fresh checksum */
  526.         OneFileCRC.Reset();
  527.  
  528.         size_t BytesActuallyRead;
  529.         size_t BytesToRead;
  530.         long   ToGoInThisFile = min ( FileSize, ToGo );
  531.  
  532.         /* read test file, till eof, or we have enough bytes, failure or user abort */
  533.         while (ToGoInThisFile && !TestDone)
  534.         {
  535.         BytesToRead = (size_t) min ( (long) BufferSizeInBytes ,ToGoInThisFile );
  536.         BytesActuallyRead = fread(Buffer, 1, BytesToRead,  TempFile);
  537.         if (BytesActuallyRead == BytesToRead)
  538.             {
  539.             OneFileCRC.Append(Buffer,BytesActuallyRead);
  540.             ToGo -= BytesActuallyRead;
  541.             ToGoInThisFile -= BytesActuallyRead;
  542.             }
  543.         else
  544.             {
  545.             TestResult = FAIL;
  546.             TestDone = TRUE;
  547.             break;
  548.             }
  549.  
  550.         if (CheckForEsc()) TestDone = TRUE;
  551.         /* check for user abort every block read */
  552.         }
  553.         fclose(TempFile);
  554.         }
  555.     else
  556.         {
  557.         /* file would not open */
  558.         TestResult = FAIL;
  559.         TestDone = TRUE;
  560.         }
  561.     }
  562.     else /* NOP */; /* ignore 0-length files */
  563.  
  564.     if (!TestDone) switch (Phase)
  565.     {
  566.     case 1:
  567.         /* save computed checksum */
  568.         ExpectedCRC [FileIndex++] = OneFileCRC.Result();
  569.         break;
  570.  
  571.     case 2:
  572.         /* ensure checksum is same as last time */
  573.         if (ExpectedCRC [FileIndex++] == OneFileCRC.Result())
  574.         TestResult = PASS;
  575.         else
  576.         {
  577.         /* crc check failed */
  578.         TestResult = FAIL;
  579.         TestDone = TRUE;
  580.         }
  581.         break;
  582.     }
  583.  
  584.  
  585.     delete Buffer;
  586.  
  587.     return (BOOL) ((ToGo <= 0) || (FileIndex >= MaxFiles) || TestDone);
  588.     /* quit calling this function as soon as enough bytes read,
  589.        enough files read,
  590.        or test aborted by user or  test failure. */
  591.  
  592. } /* end ProcessOneFile */
  593.  
  594. /* ***************************************** */
  595.  
  596. void beep (void)
  597. {
  598.     /* long beep to attract attention */
  599.     printf("\x07\x07\x07\x07");
  600. } /* end beep */
  601.  
  602. /*****************/
  603.  
  604. int pause (void)
  605. {
  606.     /*
  607.     returns 1=user hit space
  608.     returns 2=user hit ESC
  609.     */
  610.     int Result = 0;
  611.     /* pause until the user hits the space bar */
  612.     printf ("\nWhen you are ready to proceed, hit the space bar; hit ESC to abort");
  613.  
  614.     while (!Result)
  615.     {
  616.     switch (getch())
  617.         {
  618.         case ' ':
  619.         Result = 1; /*  space we are done */
  620.         break;
  621.         case Esc:
  622.         Result = 2; /* Esc, Abort */
  623.         break;
  624.         default:
  625.         printf("\x07" );  /* beep to indicate char ignored. */
  626.         break;
  627.         }
  628.     }
  629.     printf("\r                                                                  \n\n");
  630.     /* erase the  prompt line, to ack the space bar */
  631.     return Result;
  632.  
  633. } /* end pause */
  634.  
  635. /*****************/
  636.  
  637. int DoesOSDoSimultaneousIO (void)
  638. {
  639.  
  640.     /*
  641.       returns 0= no, DESQiew, Windows,...
  642.       returns 1= yes. OS/2, NT...
  643.       returns 2=user hit ESC
  644.        */
  645.     int Result = -1;
  646.  
  647.     printf( "\nDoes your operating system do more than one I/O at a time?"
  648.     "\nAnswer N for DOS, DESQview, Windows, Windows for Workgroups or Windows-95."
  649.     "\nAnswer Y for OS/2, Warp, NT, Linux, SCO XENIX or UNIX.");
  650.     /* don't advertise the ESC possibility */
  651.  
  652.     while (Result == -1)
  653.     {
  654.     switch (getch())
  655.         {
  656.         case 'N':
  657.         case 'n':
  658.         Result = 0; /*  No */
  659.         break;
  660.         case 'Y':
  661.         case 'y':
  662.         Result = 1; /* Yes */
  663.         break;
  664.         case Esc:
  665.         Result = 2; /* Esc, Abort */
  666.         break;
  667.         default:
  668.         printf("\x07" );  /* beep to indicate char ignored. */
  669.         break;
  670.         }
  671.     }
  672.  
  673.     return Result;
  674.  
  675. } /* end DoesOSDoSimultaneousIO */
  676.  
  677. /* ***************************************** */
  678.  
  679. int CheckForEsc (void)
  680. {
  681.  
  682.     /*
  683.       returns 0=user did nothing.  We don't wait for him to hit a key.
  684.       returns 1=user hit space
  685.       returns 2=user hit ESC
  686.       */
  687.     int Result = 0;
  688.  
  689.     if (kbhit())
  690.     {
  691.     switch (getch())
  692.         {
  693.         case ' ':
  694.         Result = 1; /*  space we are done */
  695.         break;
  696.         case Esc:
  697.         Result = 2; /* Esc, Abort */
  698.         break;
  699.         default:
  700.         printf("\x07" );  /* beep to indicate char ignored. */
  701.         Result = 0;
  702.         break;
  703.         }
  704.     }
  705.     else
  706.     Result = 0; /* no key hit */
  707.     return Result;
  708.  
  709. } /* end CheckForEsc */
  710.  
  711. /* ***************************************** */
  712.  
  713. int CRC::InitCRCTable (WORD Poly)
  714. {
  715.     WORD       i;
  716.     WORD     crc;
  717.  
  718.     /* usually we would use Poly = 0x8408, the 16-bit CCITT polynomial */
  719.  
  720.     for (i = 0; i < 256; i++)
  721.     {
  722.     crc = (WORD) i;
  723.     /* ^ is bitwise XOR */
  724.     crc = (crc >> 1) ^ ((crc & 1) ? Poly : 0);
  725.     crc = (crc >> 1) ^ ((crc & 1) ? Poly : 0);
  726.     crc = (crc >> 1) ^ ((crc & 1) ? Poly : 0);
  727.     crc = (crc >> 1) ^ ((crc & 1) ? Poly : 0);
  728.     crc = (crc >> 1) ^ ((crc & 1) ? Poly : 0);
  729.     crc = (crc >> 1) ^ ((crc & 1) ? Poly : 0);
  730.     crc = (crc >> 1) ^ ((crc & 1) ? Poly : 0);
  731.     crc = (crc >> 1) ^ ((crc & 1) ? Poly : 0);
  732.  
  733.     CRCTable[i] = crc;
  734.  
  735.     }
  736.     return 0; /* dummy */
  737.  
  738. } /* end InitCRCTable */
  739.  
  740. /* ***************************************** */
  741.  
  742. void CRC::Append ( BYTE* String, WORD Length )
  743. {
  744.     /* cumulatively compute the CRC of this string. */
  745.     /* string may contain nulls */
  746.  
  747.     /* character of the string, start with len byte */
  748.  
  749.     while (Length--)
  750.     work = (work >> 8) ^ CRCTable[(work & 0xff) ^ *String++];
  751.     /* ^ is bitwise XOR */
  752.  
  753. }  /* end Append */
  754.  
  755. /* ***************************************** */
  756.  
  757. void FILETREE::ForEachFile  (char * WildCard, ATTRIBPATTERN AttribPattern, BOOL Recurse )
  758. {
  759.     Stop = FALSE;
  760.     InitAttribFilters(AttribPattern);
  761.  
  762.     if (Recurse) ProcessSubs(WildCard);
  763.     else ProcessFiles(WildCard);
  764.  
  765. } /* end ForEachFile */
  766.  
  767. /* ***************************************** */
  768.  
  769. void  FILETREE::ProcessSubs(char *WildCard)
  770. /* We recursively process all WildCard-matching ordinary files and all
  771.  * subdirs of this dir.  Since we
  772.  * are processing recursively we use new rather than the stack to avoid
  773.  * overflowing it. Wildcard describes files, not subdirs. */
  774.  
  775. {
  776.     struct find_t * Hit  = new struct find_t;
  777.     /* a subdir found by _dos_findnext */
  778.  
  779.     char * FindSubsWildCard = new char [FILENAME_MAX];
  780.  
  781.     char * SubWildCard = new char [FILENAME_MAX];
  782.  
  783.     if (WildCard && WildCard[0]) /* not null */
  784.     {
  785.     ProcessFiles(WildCard); /* process ordinary files first */
  786.  
  787.     /* ignore file part when searching for dirs.
  788.      * e.g. E:/MyDir/*.* to search for any subdirs.
  789.      * Process only Subdirs, including hidden, system etc. subdirs.
  790.      * Ignore all hits but true subdirs.
  791.      * User's FineAttribFilter is irrelevant */
  792.     if (!Stop && _dos_findfirst(Join ( FindSubsWildCard, WildCard, NULL, "*.*"),
  793.         (_A_SUBDIR | _A_ARCH | _A_RDONLY | _A_HIDDEN | _A_SYSTEM),
  794.         Hit) == 0)
  795.         do
  796.         {
  797.         if ((Hit->attrib & _A_SUBDIR) && Hit->name[0] != '.')
  798.             {
  799.             /* e.g. E:/MyDir/MySub/*.TXT */
  800.             ProcessSubs(Join(SubWildCard, WildCard, Hit->name, NULL ));
  801.             /* recursively */
  802.             }
  803.         }
  804.         while (!Stop && _dos_findnext(Hit) == 0);
  805.     }
  806.     delete FindSubsWildCard;
  807.     delete SubWildCard;
  808.     delete Hit;
  809.  
  810. }  /* end ProcessSubs */
  811.  
  812. /* ***************************************** */
  813.  
  814. void FILETREE::ProcessFiles( char * WildCard )
  815. {
  816.     /* non-recursively process files in directory described by WildCard. */
  817.     struct find_t * Hit = new struct find_t;
  818.     /* a file found by _dos_findnext */
  819.  
  820.     char * QualFileName = new char [FILENAME_MAX];
  821.  
  822.     if (WildCard && WildCard[0]) /* not null */
  823.     if (_dos_findfirst(WildCard, CoarseAttribFilter, Hit) == 0)
  824.         do
  825.         {
  826.         if (FineAttribFilter[Hit->attrib])
  827.             {
  828.             if (ProcessOneFile
  829.             (Join(QualFileName, WildCard, NULL, Hit->name),
  830.             Hit->size ))
  831.             {
  832.             Stop = TRUE;
  833.             break;
  834.             }
  835.             }
  836.         } while (_dos_findnext(Hit) == 0);
  837.  
  838.     delete QualFileName;
  839.     delete Hit;
  840.  
  841. }    /* end ProcessFiles */
  842.  
  843. /* ***************************************** */
  844.  
  845. void FILETREE::InitAttribFilters (ATTRIBPATTERN AttribPattern)
  846. {
  847.     /* Prepare FineAttribFilter so we don't have to keep invoking the
  848.      * slow ProbeAttribFilter function.
  849.      * Also prepare CoarseAttribFilter -- special types of files
  850.      * EVER wanted.
  851.      * We can use CoarseAttribFilter to get DOS to do some gross filtering. */
  852.     ATTRIB           Attrib;
  853.     CoarseAttribFilter = 0;
  854.     for (Attrib = 0; Attrib < 64; Attrib++)
  855.     {
  856.     if ((FineAttribFilter[Attrib] = ProbeAttribFilter(Attrib, AttribPattern)))
  857.         CoarseAttribFilter |= Attrib;
  858.     }
  859. } /* end InitAttribFilters */
  860.  
  861. /* ***************************************** */
  862.  
  863. BOOL FILETREE::ProbeAttribFilter(ATTRIB Attrib, ATTRIBPATTERN AttribPattern)
  864. {
  865.     /* true if Attrib matches the given string pattern .
  866.      * attribute pattern string is of form:
  867.      * ADVSHR A-archive D-directory V-volume S-system H-hidden R-read-only
  868.      * "ADVSHR"
  869.      * "?00+1-" <-- example
  870.      * ?=ignore, irrelevant.
  871.      * 1=must be 1
  872.      * 0=must be 0
  873.      * +=must have some 1s, all plus slots many not be 0
  874.      * -=must have some 0s, all minus slots may not be 1 */
  875.  
  876.     BOOL           Bit;
  877.     BOOL           NeedPlus = FALSE; /* no + seen yet, so no need for 1s in + slots */
  878.     BOOL           NeedMinus = FALSE; /* ditto for minus */
  879.     int            i;
  880.     WORD           PlusCount = 0;
  881.     WORD           MinusCount = 0;
  882.  
  883.     /* work right to left comparing the Pattern char string with the Attrib bits */
  884.     for (i = 5; i >= 0; i--)
  885.     {
  886.     Bit = (BOOL) (((WORD) Attrib >> (5 - i)) & 1);
  887.     switch (AttribPattern[i])
  888.         {
  889.         case '1':
  890.         if (!Bit)
  891.             return (FALSE);
  892.         break;
  893.         case '0':
  894.         if (Bit)
  895.             return (FALSE);
  896.         break;
  897.         case '+':
  898.         NeedPlus = TRUE;
  899.         if (Bit)
  900.             PlusCount++;
  901.         break;
  902.         case '-':
  903.         NeedMinus = TRUE;
  904.         if (!Bit)
  905.             MinusCount++;
  906.         break;
  907.         case '?':
  908.         break;
  909.         default:
  910.         printf(
  911.             "\n Programmer error: Invalid WildCard attribute specifier string: %s.\n",
  912.             AttribPattern);
  913.         exit(99);
  914.         } /* end switch */
  915.     } /* end for */
  916.     if (NeedPlus && (PlusCount == 0))
  917.     return (FALSE);
  918.     if (NeedMinus && (MinusCount == 0))
  919.     return (FALSE);
  920.     return (TRUE);
  921.  
  922. } /* end ProbeAttribFilter */
  923.  
  924. /* ***************************************** */
  925.  
  926. char * FILETREE::Join(char *Result, char *WildCard, char *SubDir, char *FileName)
  927.  
  928. {
  929.     /* Glue Wildcard, Subdir and FileName together */
  930.     /* SubDir and FileName might be null */
  931.     char            Drive[_MAX_DRIVE];
  932.     char            Dir[_MAX_DIR];
  933.     char            Fname[_MAX_FNAME];
  934.     char            Ext[_MAX_EXT];
  935.  
  936.     _splitpath(WildCard, Drive, Dir, Fname, Ext);
  937.     /* Dir will usually have lead and trail backslash */
  938.  
  939.     if (SubDir) strcat(Dir, SubDir);
  940.  
  941.     if (FileName) _makepath(Result, Drive, Dir, FileName, NULL);
  942.     else _makepath(Result, Drive, Dir, Fname, Ext);
  943.     return Result;
  944.  
  945. } /* end Join */
  946.  
  947. /* ***************************************** */
  948.  
  949. /* -30- */
  950.