home *** CD-ROM | disk | FTP | other *** search
/ Shareware Overload / ShartewareOverload.cdr / virus / njfin112.zip / NJFIND.C < prev    next >
Text File  |  1990-02-13  |  42KB  |  1,459 lines

  1.   
  2. /* --------------------------------------------------------------------------
  3.    Nifty James' Famous File Find Utility
  4.  
  5.    Version 1.00 of 20 November 1989
  6.    Version 1.10 of 16 December 1989
  7.     Version 1.11 of  5 January  1990
  8.     Version 1.12 of 13 February 1990
  9.  
  10.    (C) Copyright 1989 by Mike Blaszczak
  11.    All Rights Reserved.
  12.  
  13.    Written for the Microsoft C Compiler Version 5.10.
  14.    LINK with an increased stack size!
  15.  
  16.    "I had a dream of a winter garden
  17.     A midnight rendezvous
  18.     silver, blue, and frozen silence
  19.     what a fool I was for you!"
  20.         -- Rush, 'Presto'
  21. */
  22.  
  23.  
  24. /* --------------------------------------------------------------------------
  25.    Needed #include Files
  26. */
  27.  
  28. #pragma pack(1)                           /* don't space structure members */
  29. #include <dos.h>
  30. #include <signal.h>
  31. #include <stdio.h>
  32. #include <stdlib.h>
  33. #include <string.h>
  34.  
  35. #define  byte     unsigned char
  36. #define  word     unsigned int
  37. #define  dword    unsigned long
  38. #define  boolean  char
  39. #define  TRUE     (1==1)
  40. #define  FALSE    (!TRUE)
  41.  
  42.  
  43. /* --------------------------------------------------------------------------
  44.    Structures used here
  45. */
  46.  
  47. struct   fullfilename               /* used internally to hold filenames   */
  48. {
  49.    char  filename[9];
  50.    char  fileextension[4];
  51. };
  52.  
  53.  
  54. /* This is the "local file header" for zip files.  The zip_lfh structure
  55.    preceeds each file in the ZIP file, and describes the individual files
  56.    stored there.  Note that we read one of these and then fseek() over it
  57.    by using the value in zip_lfh.csize to get the new area.
  58. */
  59.  
  60. struct   zip_lfh
  61. {
  62.    dword signature;                 /* signature, must be 0x04034B50       */
  63.    word  exversion;                 /* version needed to extract           */
  64.    word  bitflags;                  /* general purpose bit flags           */
  65.    word  compression;               /* compression method                  */
  66.    word  modtime;
  67.    word  moddate;                   /* last modification time and date     */
  68.    dword crc32;                     /* crc32 filecheck for file            */
  69.    dword csize;                     /* compressed size                     */
  70.    dword usize;                     /* uncompressed size                   */
  71.    word  fnlength;                  /* filename length                     */
  72.    word  extralength;               /* extra field length                  */
  73. };
  74.  
  75. /* This is the "local file header" for ARC files.  The arc_lfh structure
  76.    preceeds each file in the ARC file, and describes the individual files
  77.    stored there.  Note that we read one of these and then fseek() over
  78.    the compressed file by using the value arc_lfh.csize to get the new
  79.    area.
  80.  
  81.    Note that ARC and PAK files use this same structure!
  82. */
  83.  
  84. struct   arc_lfh
  85. {
  86.    byte  marker;                    /* always 01Ah                         */
  87.    byte  compression;               /* how was this file stored?           */
  88.    char  filename[13];              /* filename is always 13 long          */
  89.    dword csize;                     /* compressed size                     */
  90.    word  date;                      /* date of original file               */
  91.    word  time;                      /* time of original file               */
  92.    word  crc;                       /* sixteen-bit CRC for this file       */
  93.    dword usize;                     /* uncompressed size                   */
  94. };
  95.  
  96.  
  97. struct   lzh_lfh
  98. {
  99.    byte  unknown[7];                /* unknown area                        */
  100.    dword csize;                     /* compressed size                     */
  101.    dword usize;                     /* original size                       */
  102.    word  time;                      /* last modification of date and time  */
  103.    word  date;                      /*     of the stored file              */
  104.    byte  unknown3[2];
  105.    byte  fnlength;                  /* length of file name                 */
  106. };
  107.  
  108.  
  109. struct   zoo_lfh
  110. {
  111.    word  time;                      /* last modification of date and time  */
  112.    word  date;                      /*     of the stored file              */       
  113.    word  unknownword;
  114.    dword usize;                     /* original file size                  */
  115.    dword csize;                     /* compressed size                     */
  116.    byte  unknown[10];               /* unknown area ...                    */
  117.    char  filename[13];              /* ASCIIZ filename                     */
  118. };
  119.  
  120.  
  121. /* --------------------------------------------------------------------------
  122.    Global Variables
  123. */
  124.  
  125. unsigned       result;              /* stored result of _dos_find*() calls */
  126. char           *temp;               /* temporary pointer for strings       */
  127. char           *extension;          /* pointer to file extension           */
  128. char           template[_MAX_PATH]; /* template to match files searched    */
  129. char           *inputfile;          /* pointer to wildcard name            */
  130.  
  131. struct fullfilename
  132.                tempfullname,        /* full name of file we're working on  */
  133.                matchname;           /* name to match                       */
  134.  
  135. unsigned       found =0;            /* count of found files                */
  136. unsigned long  totallength = 0L;    /* total of file lengths               */
  137.  
  138. unsigned       archivefound = 0;    /* count of found files in archves     */
  139. unsigned long  archivetotallength = 0L;
  140.                                     /* total file lengths of archive files.*/
  141.  
  142. struct zip_lfh zipworker;           /* workspace for zip files             */
  143. struct arc_lfh arcworker;           /* workspace for arc files             */
  144. struct lzh_lfh lzhworker;           /* workspace for lzh files             */
  145. struct zoo_lfh zooworker;           /* workspace for zoo files             */
  146.  
  147. boolean        searchzips = TRUE;   /* flags for options on searching      */
  148. boolean        searchlzhs = TRUE;   /*    the different archive types      */
  149. boolean        searchzoos = TRUE;
  150. boolean        searcharcs = TRUE;
  151. boolean        searchpaks = TRUE;
  152.  
  153. boolean        verbose = FALSE;     /* TRUE for verbose mode               */
  154. boolean        progress = FALSE;    /* TRUE to show progress               */
  155. boolean        totalsmode = FALSE;  /* TURE for display totals             */
  156. boolean        changedrive = FALSE; /* set TRUE if user changed disks      */
  157.  
  158. boolean        broken = FALSE;      /* set true if user does CTRL+BREAK    */
  159.  
  160. boolean        alldrives = FALSE;   /* search through all drives           */
  161.  
  162. char           fiftyspaces[55];     /* a bunch of spaces for printmatch()  */
  163.  
  164. unsigned       drivecount;          /* used to change disk drives          */
  165. unsigned       newdrive;
  166. unsigned       olddrive;
  167. unsigned       lastdrive;
  168. char           newdriveletter[3];
  169.  
  170. char           drivelist[28];       /* list of drives to search            */
  171. char           *currentdrive;
  172.  
  173.  
  174. /* --------------------------------------------------------------------------
  175.    Global Constants
  176. */
  177.  
  178. const char     *fmessageread  = "Couldn't open file \"%s\" for read.\n";
  179. const char     *readbinary    = "rb";
  180. const char     *notsearching  = "Not searching %s files\n";
  181. const char     *eraseline     = "\t\t\t\t\t\t\t\t\t\r";
  182. const char     *wfi           = " was found in ";
  183. const char     *swfis         = "%s was found in %s%s";
  184.  
  185. const char *month3names[12] =
  186.    { "Jan", "Feb", "Mar", "Apr", "May", "Jun",
  187.      "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
  188. };
  189.  
  190.  
  191. /* --------------------------------------------------------------------------
  192.    ANSI-C Standard Function Prototypes
  193. */
  194.  
  195. void  processzip(char *filename, struct find_t *info);
  196. void  processpak(char *filename, struct find_t *info);
  197. void  processarc(char *filename, struct find_t *info);
  198. void  processlzh(char *filename, struct find_t *info);
  199. void  processzoo(char *filename, struct find_t *info);
  200.  
  201. void  printinside(char *filename, char *archive, dword filesize, word date, word time);
  202. void  printmatch(char *filename, dword filesize, word date, word time);
  203. void  printdate(word date);
  204. void  printtime(word time);
  205. int   comparenames(struct fullfilename *left, struct fullfilename *right);
  206. void  maketemplate(void);
  207. void  makefullname(struct fullfilename *ffn, char *path);
  208. void  searchdir(char *dirname);
  209. void  showusage(void);
  210. void  handleoption(char *option);
  211. void  breakout(void);
  212. void  builddrivelist(void);
  213. void  main(int argc, char *argv[]);
  214.  
  215.  
  216. /* --------------------------------------------------------------------------
  217. */
  218.  
  219. void  processzip(char *filename, struct find_t *info)
  220. {
  221.    FILE                 *zipfile;
  222.    char                 *insidefilename = NULL;
  223.    struct fullfilename  zipfullname;
  224.    char                 *temporary;
  225.  
  226. #if defined(DEBUG)
  227.    printf("processzip(\"%s\")\n", info->name);
  228. #endif
  229.  
  230.    /* if the file name doesn't match the requested template name,
  231.       return now and don't even bother opening the zip file.
  232.    */
  233.  
  234.    if (comparenames(&tempfullname, &matchname) == 0)
  235.       {
  236.       found++;
  237.       if (totalsmode == FALSE)
  238.          if (verbose == TRUE)
  239.             printmatch(filename, info->size, info->wr_date, info->wr_time);
  240.          else
  241.             printf("%s%s\n", newdriveletter, filename);
  242.  
  243.       totallength += info->size;
  244.       }
  245.  
  246.    if (searchzips == FALSE)
  247.       return;
  248.  
  249.    /* open the zip file by name and see if it was successful.
  250.    */
  251.  
  252.    zipfile = fopen(filename, readbinary);
  253.    if (zipfile == NULL)
  254.       {
  255.       fprintf(stderr, fmessageread, filename);
  256.       return;
  257.       }
  258.  
  259.    /* loop through the whole file
  260.    */
  261.  
  262.    while(!feof(zipfile))
  263.       {
  264.    /* read the local file header.
  265.       if we don't get it, break the loop.
  266.       At this same time, check it for a valid signature.
  267.    */
  268.  
  269.       if (fread(&zipworker, sizeof(struct zip_lfh), (size_t) 1, zipfile) != 1)
  270.          break;
  271.  
  272.       if (zipworker.signature != 0x04034B50)
  273.          break;
  274.  
  275.    /* free the temporary file name area
  276.       and allocate a space for the new name.
  277.       read it from the zip file.
  278.    */
  279.       if (insidefilename != NULL)
  280.          free(insidefilename);
  281.  
  282.       insidefilename = (char *) malloc(zipworker.fnlength+1);
  283.  
  284.       if (fread((void *) insidefilename,  zipworker.fnlength, (size_t) 1, zipfile) != 1)
  285.          break;
  286.       insidefilename[zipworker.fnlength] = '\0';
  287.  
  288.       temporary = strrchr(insidefilename, '/');
  289.       if (temporary != NULL)
  290.          insidefilename = temporary+1;
  291.  
  292.       makefullname(&zipfullname, insidefilename);
  293.       if (comparenames(&zipfullname, &matchname) == 0)
  294.          {
  295.          archivefound++;
  296.          archivetotallength += zipworker.usize;
  297.          if (totalsmode == FALSE)
  298.             if (verbose == TRUE)
  299.                printinside(filename, insidefilename, zipworker.usize,
  300.                   zipworker.moddate, zipworker.modtime);
  301.             else
  302.                {
  303.                printf(swfis, insidefilename, newdriveletter, filename);
  304.                putchar('\n');
  305.                }
  306.          }
  307.       else
  308.          if (progress == TRUE)
  309.             printf("%s%s\t\t\r", newdriveletter, insidefilename);
  310.  
  311. #if defined(DEBUG)
  312.       printf("insidefilename = \"%s\"\n", insidefilename);
  313. #endif
  314.  
  315.    /* seek around the compressed file.
  316.    */
  317.       fseek(zipfile, zipworker.csize + zipworker.extralength, SEEK_CUR);
  318.  
  319.    /* at this point, the file pointer is once again at the
  320.       next local file header ...
  321.    */
  322.       }
  323.  
  324.    if (insidefilename != NULL)
  325.       free(insidefilename);
  326.  
  327.    if (progress == TRUE)
  328.       printf(eraseline);
  329.    fclose(zipfile);
  330.    return;
  331. }
  332.  
  333.  
  334. /* --------------------------------------------------------------------------
  335. */
  336.  
  337. void  processpak(char *filename, struct find_t *info)
  338. {
  339.    FILE                 *pakfile;
  340.    struct fullfilename  pakfullname;
  341.  
  342. #if defined(DEBUG)
  343.    printf("processpak(\"%s\")\n", info->name);
  344. #endif
  345.  
  346.    /* if the file name doesn't match the requested template name,
  347.       return now and don't even bother opening the zip file.
  348.    */
  349.  
  350.    if (comparenames(&tempfullname, &matchname) == 0)
  351.       {
  352.       found++;
  353.       if (totalsmode == FALSE)
  354.          if (verbose == TRUE)
  355.             printmatch(filename, info->size, info->wr_date, info->wr_time);
  356.          else
  357.             printf("%s%s\n", newdriveletter, filename);
  358.       totallength += info->size;
  359.       }
  360.  
  361.    if (searchpaks == FALSE)
  362.       return;
  363.  
  364.    /* open the pak file by name and see if it was successful.
  365.    */
  366.  
  367.    pakfile = fopen(filename, readbinary);
  368.    if (pakfile == NULL)
  369.       {
  370.       fprintf(stderr, fmessageread, filename);
  371.       return;
  372.       }
  373.  
  374.    /* loop through the whole file
  375.    */
  376.  
  377.    while(!feof(pakfile))
  378.       {
  379.    /* read the local file header.
  380.       if we don't get it, break the loop.
  381.    */
  382.  
  383.       if (fread(&arcworker, sizeof(struct arc_lfh), (size_t) 1, pakfile) != 1)
  384.          break;
  385.  
  386.    /* check the compression method.
  387.       if it is zero, the pak file is over.
  388.    */
  389.  
  390.       if (arcworker.compression == 0)
  391.          break;
  392.  
  393.       makefullname(&pakfullname, arcworker.filename);
  394.       if (comparenames(&pakfullname, &matchname) == 0)
  395.          {
  396.          archivefound++;
  397.          archivetotallength += arcworker.usize;
  398.          if (totalsmode == FALSE)
  399.             if (verbose == TRUE)
  400.                printinside(filename, arcworker.filename, arcworker.usize,
  401.                   arcworker.date, arcworker.time);
  402.             else
  403.                {
  404.                printf(swfis, arcworker.filename, newdriveletter, filename);
  405.                putchar('\n');
  406.                }
  407.          }
  408.       else
  409.          if (progress == TRUE)
  410.             printf("%s\t\t\r", arcworker.filename);
  411.  
  412. #if defined(DEBUG)
  413.       printf("filename = \"%s\"\n", arcworker.filename);
  414. #endif
  415.  
  416.    /* seek around the compressed file.
  417.    */
  418.       fseek(pakfile, arcworker.csize, SEEK_CUR);
  419.  
  420.    /* at this point, the file pointer is once again at the
  421.       next local file header ...
  422.    */
  423.       }
  424.  
  425.    if (progress == TRUE)
  426.       printf(eraseline);
  427.    fclose(pakfile);
  428.    return;
  429. }
  430.  
  431.  
  432. /* --------------------------------------------------------------------------
  433. */
  434.  
  435. void  processarc(char *filename, struct find_t *info)
  436. {
  437.    FILE                 *arcfile;
  438.    struct fullfilename  arcfullname;
  439.  
  440. #if defined(DEBUG)
  441.    printf("processarc(\"%s\")\n", info->name);
  442. #endif
  443.  
  444.    /* if the file name doesn't match the requested template name,
  445.       return now and don't even bother opening the zip file.
  446.    */
  447.  
  448.    if (comparenames(&tempfullname, &matchname) == 0)
  449.       {
  450.       found++;
  451.       if (totalsmode == FALSE)
  452.          if (verbose == TRUE)
  453.             printmatch(filename, info->size, info->wr_date, info->wr_time);
  454.          else
  455.             printf("%s%s\n", newdriveletter, filename);
  456.       totallength += info->size;
  457.       }
  458.  
  459.    if (searcharcs == FALSE)
  460.       return;
  461.  
  462.    /* open the arc file by name and see if it was successful.
  463.    */
  464.  
  465.    arcfile = fopen(filename, readbinary);
  466.    if (arcfile == NULL)
  467.       {
  468.       fprintf(stderr, fmessageread, filename);
  469.       return;
  470.       }
  471.  
  472.    /* loop through the whole file
  473.    */
  474.  
  475.    while(!feof(arcfile))
  476.       {
  477.    /* read the local file header.
  478.       if we don't get it, break the loop.
  479.    */
  480.  
  481.       if (fread(&arcworker, sizeof(struct arc_lfh), (size_t) 1, arcfile) != 1)
  482.          break;
  483.  
  484.    /* check the compression method.
  485.       if it is zero, the pak file is over.
  486.    */
  487.  
  488.       if (arcworker.compression == 0)
  489.          break;
  490.  
  491.       makefullname(&arcfullname, arcworker.filename);
  492.       if (comparenames(&arcfullname, &matchname) == 0)
  493.          {
  494.          archivefound++;
  495.          archivetotallength += arcworker.usize;
  496.          if (totalsmode == FALSE)
  497.             if (verbose == TRUE)
  498.                printinside(filename, arcworker.filename, arcworker.usize,
  499.                   arcworker.date, arcworker.time);
  500.             else
  501.                {
  502.                printf(swfis, arcworker.filename, newdriveletter, filename);
  503.                putchar('\n');
  504.                }
  505.          }
  506.       else
  507.          if (progress == TRUE)
  508.             printf("%s\t\t\r", arcworker.filename);
  509.  
  510. #if defined(DEBUG)
  511.       printf("filename = \"%s\"\n", arcworker.filename);
  512. #endif
  513.  
  514.    /* seek around the compressed file.
  515.    */
  516.       fseek(arcfile, arcworker.csize, SEEK_CUR);
  517.  
  518.    /* at this point, the file pointer is once again at the
  519.       next local file header ...
  520.    */
  521.       }
  522.  
  523.    if (progress == TRUE)
  524.       printf(eraseline);
  525.    fclose(arcfile);
  526.    return;
  527. }
  528.  
  529.  
  530. /* --------------------------------------------------------------------------
  531. */
  532.  
  533. void  processlzh(char *filename, struct find_t *info)
  534. {
  535.    FILE                 *lzhfile;
  536.    char                 *insidefilename = NULL;
  537.    struct fullfilename  lzhfullname;
  538.    char                 *temporary;
  539.  
  540. #if defined(DEBUG)
  541.    printf("processlzh(\"%s\")\n", info->name);
  542. #endif
  543.  
  544.    /* if the file name doesn't match the requested template name,
  545.       return now and don't even bother opening the lzh file.
  546.    */
  547.  
  548.    if (comparenames(&tempfullname, &matchname) == 0)
  549.       {
  550.       found++;
  551.       if (totalsmode == FALSE)
  552.          if (verbose == TRUE)
  553.             printmatch(filename, info->size, info->wr_date, info->wr_time);
  554.          else
  555.             printf("%s%s\n", newdriveletter, filename);
  556.       totallength += info->size;
  557.       }
  558.  
  559.    if (searchlzhs == FALSE)
  560.       return;
  561.  
  562.    /* open the lzh file by name and see if it was successful.
  563.    */
  564.  
  565.    lzhfile = fopen(filename, readbinary);
  566.    if (lzhfile == NULL)
  567.       {
  568.       fprintf(stderr, fmessageread, filename);
  569.       return;
  570.       }
  571.  
  572.    /* loop through the whole file
  573.    */
  574.  
  575.    while(!feof(lzhfile))
  576.       {
  577.    /* read the local file header.
  578.       if we don't get it, break the loop.
  579.    */
  580.  
  581.       if (fread(&lzhworker, sizeof(struct lzh_lfh), (size_t) 1, lzhfile) != 1)
  582.          break;
  583.  
  584.    /* free the temporary file name area
  585.       and allocate a space for the new name.
  586.       read it from the lzh file.
  587.    */
  588.       if (insidefilename != NULL)
  589.          free(insidefilename);
  590.  
  591.       insidefilename = (char *) malloc(lzhworker.fnlength+1);
  592.  
  593.       if (fread((void *) insidefilename,  lzhworker.fnlength, (size_t) 1, lzhfile) != 1)
  594.          break;
  595.       insidefilename[lzhworker.fnlength] = '\0';
  596.  
  597.       temporary = strrchr(insidefilename, '\\');
  598.       if (temporary != NULL)
  599.          insidefilename = temporary+1;
  600.  
  601.       makefullname(&lzhfullname, insidefilename);
  602.       if (comparenames(&lzhfullname, &matchname) == 0)
  603.          {
  604.          archivefound++;
  605.          archivetotallength += lzhworker.usize;
  606.          if (totalsmode == FALSE)
  607.             if (verbose == TRUE)
  608.                printinside(filename, insidefilename, lzhworker.usize,
  609.                   lzhworker.date, lzhworker.time);
  610.             else
  611.                {
  612.                printf(swfis, insidefilename, newdriveletter, filename);
  613.                putchar('\n');
  614.                }
  615.          }
  616.       else
  617.          if (progress == TRUE)
  618.             printf("%s\t\t\r", insidefilename);
  619.  
  620. #if defined(DEBUG)
  621.       printf("insidefilename = \"%s\"\n", insidefilename);
  622. #endif
  623.  
  624.    /* seek around the compressed file.
  625.    */
  626.       fseek(lzhfile, lzhworker.csize+2L, SEEK_CUR);
  627.  
  628.    /* at this point, the file pointer is once again at the
  629.       next local file header ...
  630.    */
  631.       }
  632.  
  633.    if (insidefilename != NULL)
  634.       free(insidefilename);
  635.  
  636.    if (progress == TRUE)
  637.       printf(eraseline);
  638.    fclose(lzhfile);
  639.    return;
  640. }
  641.  
  642.  
  643. /* --------------------------------------------------------------------------
  644. */
  645.  
  646. void  processzoo(char *filename, struct find_t *info)
  647. {
  648.    FILE                 *zoofile;
  649.    struct fullfilename  zoofullname;
  650.    int                  thischar;
  651.  
  652. #if defined(DEBUG)
  653.    printf("processzoo(\"%s\")\n", info->name);
  654. #endif
  655.  
  656.    /* if the file name doesn't match the requested template name,
  657.       return now and don't even bother opening the zip file.
  658.    */
  659.  
  660.    if (comparenames(&tempfullname, &matchname) == 0)
  661.       {
  662.       if (totalsmode == FALSE)
  663.          if (verbose == TRUE)
  664.             printmatch(filename, info->size, info->wr_date, info->wr_time);
  665.          else
  666.             printf("%s%s\n", filename);
  667.       found++;
  668.       totallength += info->size;
  669.       }
  670.  
  671.    if (searchzoos == FALSE)
  672.       return;
  673.  
  674.    /* open the zoo file by name and see if it was successful.
  675.    */
  676.  
  677.    zoofile = fopen(filename, readbinary);
  678.    if (zoofile == NULL)
  679.       {
  680.       fprintf(stderr, fmessageread, filename);
  681.       return;
  682.       }
  683.  
  684.    /* first, skip over the ZOO FILE message
  685.    */
  686.  
  687.    while (!feof(zoofile))
  688.       {
  689.       thischar = fgetc(zoofile);
  690.       if (thischar == 0x1A)
  691.          break;
  692.       }
  693.  
  694.    if (feof(zoofile))
  695.       {
  696.       fclose(zoofile);
  697.       return;
  698.       }
  699.  
  700.    /* skip over more header junk */
  701.  
  702.    fseek(zoofile, 38L, SEEK_CUR);
  703.  
  704.    /* loop through the whole file
  705.    */
  706.  
  707.    while(!feof(zoofile))
  708.       {
  709.    /* read the local file header.
  710.       if we don't get it, break the loop.
  711.    */
  712.  
  713.       if (fread(&zooworker, sizeof(struct zoo_lfh), (size_t) 1, zoofile) != 1)
  714.          break;
  715.  
  716.    /* check the compression method.
  717.       if it is zero, the pak file is over.
  718.    */
  719.  
  720.       if (zooworker.filename[0] == '\0')
  721.          break;
  722.  
  723.       strupr(zooworker.filename);
  724.       makefullname(&zoofullname, zooworker.filename);
  725.       if (comparenames(&zoofullname, &matchname) == 0)
  726.          {
  727.          archivefound++;
  728.          totallength += zooworker.usize;
  729.          if (totalsmode == FALSE)
  730.             if (verbose == TRUE)
  731.                printinside(filename, zooworker.filename, zooworker.usize,
  732.                   zooworker.date, zooworker.time);
  733.             else
  734.                {
  735.                printf(swfis, zooworker.filename, newdriveletter, filename);
  736.                putchar('\n');
  737.                }
  738.          }
  739.       else
  740.          if (progress == TRUE)
  741.             printf("%s\t\t\r", zooworker.filename);
  742.  
  743. #if defined(DEBUG)
  744.       printf("filename = \"%s\"\n", zooworker.filename);
  745. #endif
  746.  
  747.    /* seek around the compressed file.
  748.    */
  749.       fseek(zoofile, zooworker.csize+34L, SEEK_CUR);
  750.  
  751.    /* at this point, the file pointer is once again at the
  752.       next local file header ...
  753.    */
  754.       }
  755.  
  756.    if (progress == TRUE)
  757.       printf(eraseline);
  758.    fclose(zoofile);
  759.    return;
  760. }
  761.  
  762.  
  763. /* --------------------------------------------------------------------------
  764. */
  765.  
  766. void  processnormal(char *filename, struct find_t *info)
  767. {
  768. #if defined(DEBUG)
  769.    printf("processnormal(\"%s\")   ", info->name);
  770.    printf("comparenames = %d\n", comparenames(&tempfullname, &matchname));
  771. #endif
  772.  
  773.    if (comparenames(&tempfullname, &matchname) == 0)
  774.       {
  775.       found++;
  776.       if (totalsmode == FALSE)
  777.          if (verbose == TRUE)
  778.             printmatch(filename, info->size, info->wr_date, info->wr_time);
  779.          else
  780.             printf("%s%s\n", newdriveletter, filename);
  781.       totallength += info->size;
  782.       }
  783.    else
  784.       if (progress == TRUE)
  785.          printf("%s\t\t\r", info->name);
  786.  
  787.    return;
  788. }
  789.  
  790.  
  791. /* --------------------------------------------------------------------------
  792.    printinside() prints out the file information from within an archive.
  793.    This makes it different than printmatch only in that the file name
  794.    *and* the name of the archive the file was in are printed.
  795. */
  796.  
  797. void    printinside(char *filename, char *archive,
  798.                dword filesize, word date, word time)
  799. {
  800.    int   count;
  801.  
  802.    count = strlen(filename) + 14 + strlen(archive) + strlen(newdriveletter);
  803.    printf(swfis, archive, newdriveletter, filename);
  804.  
  805.    if (count > 48)
  806.       {
  807.       putchar('\n');
  808.       printf("%s", fiftyspaces);
  809.       }
  810.    else
  811.       while (count < 48)
  812.          {
  813.          putchar(' ');
  814.          count++;
  815.          }
  816.  
  817.    printf("%8lu ", filesize);
  818.    printdate(date);
  819.    printtime(time);
  820.    putchar('\n');
  821.  
  822.    return;
  823. }
  824.  
  825.  
  826. /* --------------------------------------------------------------------------
  827.    printmatch() prints out the file's information.  It does this all in a
  828.    neat, tidy way.  The width of 50 characters for the file name is imposed
  829.    because for eleven characters of a date, eight characters for a time,
  830.    one character for a space, and nine characters for a file size.
  831. */
  832.  
  833. void  printmatch(char *filename, dword filesize, word date, word time)
  834. {
  835.    int count;
  836.  
  837.    count = strlen(filename)+strlen(newdriveletter);
  838.    printf("%s%s", newdriveletter, filename);
  839.  
  840.    if (count > 48)
  841.       {
  842.       putchar('\n');
  843.       printf("%s", fiftyspaces);
  844.       }
  845.    else
  846.       while (count < 48)
  847.          {
  848.          putchar(' ');
  849.          count++;
  850.          }
  851.  
  852.    printf("%8lu ", filesize);
  853.    printdate(date);
  854.    printtime(time);
  855.    putchar('\n');
  856.  
  857.    return;
  858. }
  859.  
  860. /* --------------------------------------------------------------------------
  861.    printdate() accepts a word of the DOS date and prints it out in
  862.    the format "DD-MMM-CC".  MMM is a three-letter name for the month.
  863. */
  864.  
  865. void  printdate(word date)
  866. {
  867.    printf("%02d-%s-%d  ", date & 0x001F,
  868.       month3names[((date >> 5) & 0x000F) -1], 1980+(date >> 9));
  869.  
  870.    return;
  871. }
  872.  
  873.  
  874. /* --------------------------------------------------------------------------
  875.    printtime() accepts the DOS-format for the time as a word and
  876.    prints out the time in the format "HH:MM:SS".  Note that the
  877.    time is in twenty-four hour format.
  878. */
  879.  
  880. void  printtime(word time)
  881. {
  882.    printf("%2.2d:%2.2d:%2.2d", 
  883.       time >> 11, (time >> 5) & 0x003F, (time & 0x001F) << 1);
  884.  
  885.    return;
  886. }
  887.  
  888.  
  889. /* --------------------------------------------------------------------------
  890.    This function compares two fill file name structures.  It ignores
  891.    question marks during the comparison, so it will match filenames that
  892.    have expanded wildcards.  This routine will return a zero if the files
  893.    are equivalent (or match by wildcard), and will return a one if the
  894.    files names are not comparable.
  895. */
  896.  
  897. int   comparenames(struct fullfilename *left, struct fullfilename *right)
  898. {
  899.    register char  *source;                /* working pointers for compare  */
  900.    register char  *dest;
  901.  
  902.    source = left->filename;
  903.    dest   = right->filename;
  904.  
  905.    while(*source && *dest)
  906.       {
  907.       if (*source != '?' && *dest != '?')
  908.          if (*source != *dest)
  909.             return 1;               /* not equal!  */
  910.       source++;
  911.       dest++;
  912.       }
  913.  
  914.     /* code added version 1.11    */
  915.  
  916.     if (*source == '\0' && *dest != '\0')
  917.         return 1;
  918.  
  919.     /* end code added version 1.11    */
  920.  
  921.    source = left->fileextension;
  922.    dest   = right->fileextension;
  923.  
  924.    while(*source && *dest)
  925.       {
  926.       if (*source != '?' && *dest != '?')       /* skip questionmarks   */
  927.          if (*source != *dest)
  928.             return 1;               /* not equal!  */
  929.       source++;
  930.       dest++;
  931.       }
  932.  
  933.     /* code added version 1.11    */
  934.  
  935.     if (*source == '\0' && *dest != '\0')
  936.         return 1;
  937.  
  938.     /* end code added version 1.11    */
  939.  
  940.    return 0;                        /* zero indicates success  */
  941. }
  942.  
  943.  
  944. /* --------------------------------------------------------------------------
  945.    maketemplate() takes inputfile[] and expands all the asterisks to
  946.    question marks.  This is done once, first, so that the checkmatch()
  947.    routine can more quickly and efficiently check for matches in file
  948.    names.
  949. */
  950.  
  951. void  maketemplate()
  952. {
  953.    register char  *source = inputfile; /* pointers for copying data  */
  954.    register char  *dest = template;
  955.    int   count = 0;                    /* count of template length   */
  956.    int   inextension = 0;              /* set after we get a .       */
  957.  
  958.    *dest++ = '\\';
  959.  
  960.    while(*source != '\0' && count < 13 && inextension < 4)
  961.       {
  962.       if (*source != '*')
  963.          {
  964.          *dest++ = *source;
  965.          count++;
  966.          if (count == 9 || *source == '.')
  967.             inextension++;
  968.          source++;
  969.          }
  970.       else
  971.          {
  972.          if (inextension != 0)
  973.             {
  974.             for ( ; inextension<4; inextension++)
  975.                *dest++ = '?';
  976.             *dest = '\0';
  977.             break;
  978.             }
  979.          else
  980.             {
  981.             for ( ; count<8; count++)
  982.                *dest++ = '?';
  983.             *dest++ = '.';
  984.             inextension = 1;
  985.             source++;
  986.             if (*source == '.')
  987.                source++;
  988.             }
  989.          }
  990.       }
  991.  
  992.    *dest = '\0';
  993.    return;
  994. }
  995.  
  996.  
  997. /* --------------------------------------------------------------------------
  998.    makefullname() accepts a pointer to a DOS path name and a pointer to
  999.    a fullfilename structure.  makefullname() puts the file name from
  1000.    the path into the fullfilename structure and returns.
  1001. */
  1002.  
  1003. void  makefullname(struct fullfilename *ffn, char *path)
  1004. {
  1005.    register char  *source;
  1006.    register char  *dest;
  1007.    int            counter;
  1008.  
  1009.    source = strrchr(path, '\\');
  1010.    if (source == NULL)
  1011.       source = path;
  1012.    else
  1013.       source++;
  1014.  
  1015.    for (dest = ffn->filename, counter = 0; *source && counter<8; counter++)
  1016.       if (*source == '.')
  1017.          *dest++ = ' ';
  1018.       else
  1019.          *dest++ = *source++;
  1020.  
  1021.    *dest = '\0';
  1022.    if (*source != '\0')
  1023.       source++;
  1024.  
  1025.    for (dest = ffn->fileextension, counter = 0; counter<3; counter++)
  1026.       if (*source == '\0')
  1027.          *dest++ = ' ';
  1028.       else
  1029.          *dest++ = *source++;
  1030.  
  1031.    *dest = '\0';
  1032.  
  1033.    return;
  1034. }
  1035.  
  1036.  
  1037. /* --------------------------------------------------------------------------
  1038.    searchdir() accepts the name of a directory.  That name *MUST* include
  1039.    wildcards, and may include a partial filename, a full pathname, or a
  1040.    drive specification.
  1041.  
  1042.    The function will search all directories and go lower, and will call
  1043.    itself recursively if it finds any more subdirectories.  In this way,
  1044.    it traverses the subdirectory tree in an "inorder" fasion.
  1045. */
  1046.  
  1047. void searchdir(char *dirname)
  1048. {
  1049.    char           temppath[_MAX_PATH];
  1050.    char           thisfilename[_MAX_PATH];
  1051.    struct find_t  dirinfo;
  1052.  
  1053.  
  1054.    strcpy(temppath, dirname);
  1055.    result = _dos_findfirst(temppath, _A_NORMAL | _A_SUBDIR, &dirinfo);
  1056.  
  1057.    do {
  1058.       strcpy(thisfilename, dirname);
  1059.       *(strrchr(thisfilename, '\\')+1) = '\0';
  1060.       strcat(thisfilename, dirinfo.name);
  1061. #if defined(DEBUG)
  1062.       printf("%s ", thisfilename);
  1063. #endif
  1064.  
  1065.       if ((dirinfo.attrib & _A_SUBDIR) &&
  1066.            dirinfo.name[0] != '.')
  1067.          {
  1068. #if defined(DEBUG)
  1069.          printf("(DIRECTORY)\n");
  1070. #endif
  1071.          strcat(thisfilename, "\\*.*");
  1072.          searchdir(thisfilename);
  1073.          }
  1074.       else
  1075.          {
  1076. #if defined(DEBUG)
  1077.          putchar('\n');
  1078. #endif
  1079.  
  1080.          while(broken == FALSE)
  1081.             {
  1082.             extension = strchr(thisfilename, '.');
  1083.             if (*(extension-1) == '\\')
  1084.                break;
  1085.  
  1086.             makefullname(&tempfullname, thisfilename);
  1087.  
  1088.             if (extension != NULL)
  1089.                {
  1090.                if (strcmp(extension, ".LZH") == 0)
  1091.                   {
  1092.                   processlzh(thisfilename, &dirinfo);
  1093.                   break;
  1094.                   }
  1095.  
  1096.          /* Note that we call the same routine for .PAK and .ARC.
  1097.             They have the same (basic) format!
  1098.          */
  1099.  
  1100.                if (strcmp(extension, ".PAK") == 0)
  1101.                   {
  1102.                   processpak(thisfilename, &dirinfo);
  1103.                   break;
  1104.                   }
  1105.  
  1106.                if (strcmp(extension, ".ARC") == 0)
  1107.                   {
  1108.                   processarc(thisfilename, &dirinfo);
  1109.                   break;
  1110.                   }
  1111.  
  1112.                if (strcmp(extension, ".ZOO") == 0)
  1113.                   {
  1114.                   processzoo(thisfilename, &dirinfo);
  1115.                   break;
  1116.                   }
  1117.  
  1118.                if (strcmp(extension, ".ZIP") == 0)
  1119.                   {
  1120.                   processzip(thisfilename, &dirinfo);
  1121.                   break;
  1122.                   }
  1123.                
  1124.                }
  1125.  
  1126.             processnormal(thisfilename, &dirinfo);
  1127.             break;
  1128.             }
  1129.          }
  1130.  
  1131.       result = _dos_findnext(&dirinfo);
  1132.       } while (result == 0 && broken == FALSE);
  1133.  
  1134.    if (progress == TRUE)
  1135.       printf(eraseline);
  1136.    return;
  1137. }
  1138.  
  1139.  
  1140. /* --------------------------------------------------------------------------
  1141.    showusage() is a kind of error routine.  It is called when we get confused
  1142.    parsing the command line and bail out gracefully.  This prints the
  1143.    program usage and quits.
  1144. */
  1145.  
  1146. void  showusage()
  1147. {
  1148.    fputs("Usage: NJFIND [options] <filespec>\n", stderr);
  1149.    fputs("[options] include:\n", stderr);
  1150.    fputs("\t/O - do not search *.ZOO files\n", stderr);
  1151.    fputs("\t/Z - do not search *.ZIP files\n", stderr);
  1152.    fputs("\t/A - do not search *.ARC files\n", stderr);
  1153.    fputs("\t/P - do not search *.PAK files\n", stderr);
  1154.    fputs("\t/L - do not search *.LZH files\n", stderr);
  1155.    fputs("\t/N - only search normal files (combo of /O /Z /P /A /L)\n\n", stderr);
  1156.    fputs("\t/V - verbose mode; prints statistics\n", stderr);
  1157.    fputs("\t/T - totals mode; prints no found filenames\n", stderr);
  1158.    fputs("\t/D - progress display prints filenames as searched\n", stderr);
  1159.    fputs("\t/R - run search across all DOS drives\n\n", stderr);
  1160.    exit(1);
  1161. }
  1162.  
  1163.  
  1164. /* --------------------------------------------------------------------------
  1165.    handleoption() takes care of the options the program accepts.  since
  1166.    these are all just switches, we just tweak the boolean variables that
  1167.    represent each option.
  1168. */
  1169.  
  1170. void  handleoption(char *option)
  1171. {
  1172.    switch(toupper(*option))
  1173.       {
  1174.       case 'N':   searchzoos =
  1175.                   searchpaks =
  1176.                   searcharcs =
  1177.                   searchlzhs =            /* normal files ...     */
  1178.                   searchzips = FALSE;
  1179.                   fprintf(stderr, notsearching, "ZOO, ZIP, ARC, PAK, or LZH");
  1180.                   break;
  1181.  
  1182.       case 'O':   searchzoos = FALSE;     /* turn off ZOO files   */
  1183.                   fprintf(stderr, notsearching, "ZOO");
  1184.                   break;
  1185.  
  1186.       case 'Z':   searchzips = FALSE;     /* turn off ZIP files   */
  1187.                   fprintf(stderr, notsearching, "ZIP");
  1188.                   break;
  1189.  
  1190.       case 'A':   searcharcs = FALSE;     /* turn off ARC files   */
  1191.                   fprintf(stderr, notsearching, "ARC");
  1192.                   break;
  1193.  
  1194.       case 'L':   searchlzhs = FALSE;
  1195.                   fprintf(stderr, notsearching, "LZH");
  1196.                   break;
  1197.  
  1198.       case 'P':   searchpaks = FALSE;
  1199.                   fprintf(stderr, notsearching, "PAK");
  1200.                   break;
  1201.  
  1202.       case 'V':   verbose = TRUE;
  1203.                   fputs("Verbose mode\n", stderr);
  1204.                   break;
  1205.  
  1206.       case 'D':   progress = TRUE;
  1207.                   fputs("Progress displays enabled\n", stderr);
  1208.                   break;
  1209.  
  1210.       case 'T':   totalsmode = TRUE;
  1211.                   fputs("Totals mode only\n", stderr);
  1212.                   break;
  1213.  
  1214.       /* added code, version 1.10   */
  1215.  
  1216.       case 'R':   alldrives = TRUE;
  1217.                   fputs("Search all drives\n", stderr);
  1218.                   break;
  1219.  
  1220.       /* end of added code          */
  1221.  
  1222.       default:    fprintf(stderr, "NJFIND: Unrecognized Option '%c'\n", *option);
  1223.                   showusage();
  1224.       }
  1225.  
  1226.    /* added code, version 1.10   */
  1227.  
  1228.    fputc('\n', stderr);
  1229.  
  1230.    /* end of added code          */
  1231.  
  1232.    return;
  1233. }
  1234.  
  1235.  
  1236. /* --------------------------------------------------------------------------
  1237.    builddrivelist() sets drivelist to an ASCII string of the drive
  1238.    letters that are valid on this system.  drivelist will only contain
  1239.    the identifiers of hard disk drives (with the media type 0xF8.)
  1240.    This function was added for Version 1.10.
  1241. */
  1242.  
  1243. void builddrivelist()
  1244. {
  1245.    union REGS     inregs;
  1246.    struct SREGS   segregs;
  1247.  
  1248.    unsigned int   far *walker;
  1249.    unsigned int   far *newwalker;
  1250.    unsigned int   far *nextone_off;
  1251.    unsigned int   far *nextone_seg;
  1252.    char  far *media_type;
  1253.    char  *dest;
  1254.  
  1255.    dest = drivelist;
  1256.    *dest = '\0';
  1257.  
  1258.    inregs.h.ah = 0x52;
  1259.    int86x(0x21, &inregs, &inregs, &segregs);
  1260.  
  1261.    FP_OFF(newwalker) = inregs.x.bx;
  1262.    FP_SEG(newwalker) = segregs.es;
  1263.  
  1264.    FP_OFF(walker) = newwalker[0];
  1265.    FP_SEG(walker) = newwalker[1];
  1266.  
  1267.    while(1)
  1268.       {
  1269.  
  1270.       if (_osmajor == 2)
  1271.          {
  1272.          media_type = (char far *) walker + 0x16;
  1273.          nextone_off = walker + 0x0C;
  1274.          nextone_seg = walker + 0x0D;
  1275.          }
  1276.       else if (_osmajor == 3)
  1277.          {
  1278.          media_type = (char far *) walker + 0x16;
  1279.          nextone_off = walker + 0x0C;
  1280.          nextone_seg = walker + 0x0D;
  1281.          }
  1282.       else if (_osmajor == 4)
  1283.          {
  1284.          media_type = (char far *) walker + 0x17;
  1285.          nextone_off = (unsigned int far *) ((char far *) walker + 0x19);
  1286.          nextone_seg = (unsigned int far *) ((char far *) walker + 0x1B);
  1287.          }
  1288.  
  1289.       if ((*media_type & 0x00FF) == 0xF8)
  1290.          {
  1291.          *dest++ = (char) *walker + 'A';
  1292.          *dest = '\0';
  1293.          }
  1294.  
  1295.       FP_OFF(walker) = *nextone_off;
  1296.       FP_SEG(walker) = *nextone_seg;
  1297.  
  1298.       if ((*walker & 0x00FF) > 26)
  1299.          break;
  1300.  
  1301.       if (FP_OFF(walker) == 0xFFFF)
  1302.          break;
  1303.       }
  1304.  
  1305.    return;
  1306. }
  1307.  
  1308.  
  1309. /* --------------------------------------------------------------------------
  1310.    The breakout() function handles the SIGINT signal for the program.
  1311.    Here, we simply set a flag so that the working loop will terminate
  1312.    and return.  This allows us to leave neatly, by resetting the
  1313.    current drive and printing out our totals.  (That doesn't take very
  1314.    long and should not be much of an annoyance to the user.)
  1315. */
  1316.  
  1317. void  breakout()
  1318. {
  1319.    signal(SIGINT, SIG_IGN);
  1320.    signal(SIGINT, breakout);
  1321.  
  1322.    putchar('\n');
  1323.    broken = TRUE;
  1324.  
  1325.    return;
  1326. }
  1327.  
  1328.  
  1329. /* --------------------------------------------------------------------------
  1330.    The Main Thang.
  1331. */
  1332.  
  1333. void main(int argc, char *argv[])
  1334. {
  1335.    int   argcounter;
  1336.    char  *userfilespec;
  1337.  
  1338.    signal(SIGINT, breakout);
  1339.  
  1340.    for (argcounter = 0; argcounter < 50; argcounter++)
  1341.       fiftyspaces[argcounter] = ' ';
  1342.    fiftyspaces[argcounter] = '\0';
  1343.  
  1344.    fputs("Nifty James' File Finder\n", stderr);
  1345.    fputs("Version 1.12/ASP of 13 February 1990\n", stderr);
  1346.    fputs("(C) Copyright 1989, 1990 by Mike Blaszczak\n\n", stderr);
  1347.  
  1348.    builddrivelist();
  1349.  
  1350.    if (argc < 2)
  1351.       showusage();
  1352.  
  1353.    userfilespec = NULL;
  1354.    for (argcounter = 1; argcounter<argc; argcounter++)
  1355.       if (argv[argcounter][0] == '/' || argv[argcounter][0] == '-')
  1356.          handleoption(argv[argcounter]+1);
  1357.       else
  1358.          if (userfilespec == NULL)
  1359.             userfilespec = argv[argcounter];
  1360.          else
  1361.             {
  1362.             fputs("Only one filespec allowed!\n\n", stderr);
  1363.             exit(1);
  1364.             }
  1365.  
  1366.    _dos_getdrive(&olddrive);
  1367.    newdriveletter[0] = '\0';
  1368.  
  1369.    if (userfilespec == NULL)
  1370.       {
  1371.       userfilespec = "X:\\*.*";
  1372.       userfilespec[0] = (char) olddrive + 'A';
  1373.       drivelist[0] = userfilespec[0];
  1374.       drivelist[1] = '\0';
  1375.       }
  1376.    else
  1377.       if (alldrives == FALSE)
  1378.          {
  1379.          if (userfilespec[1] == ':')
  1380.             {
  1381.             *userfilespec = (char) toupper(*userfilespec);
  1382.             newdrive = (unsigned) (*userfilespec - 'A' +1);
  1383.             _dos_setdrive(newdrive, &drivecount);
  1384.             _dos_getdrive(&lastdrive);
  1385.  
  1386.             if (lastdrive != newdrive)
  1387.                {
  1388.                fprintf(stderr, "NJFIND: Invalid drive %c:.\n", *userfilespec);
  1389.                fprintf(stderr, "        Valid drives are A: to %c:\n",
  1390.                   drivelist[strlen(drivelist)-1]);
  1391.                exit(1);
  1392.                }
  1393.             else
  1394.                {
  1395.                changedrive = TRUE;
  1396.                drivelist[0] = *userfilespec;
  1397.                drivelist[1] = '\0';
  1398.                userfilespec += 2;
  1399.                }
  1400.             }
  1401.          else
  1402.             {
  1403.             drivelist[0] = (char) (olddrive + 'A' -1);
  1404.             drivelist[1] = '\0';
  1405.             }
  1406.          }
  1407.       else
  1408.          {
  1409.          changedrive = TRUE;
  1410.          if (userfilespec[1] == ':')
  1411.             userfilespec += 2;
  1412.          }
  1413.  
  1414.    inputfile = strupr(userfilespec);
  1415.    maketemplate();
  1416.    makefullname(&matchname, template);
  1417. #if defined(DEBUG)
  1418.    printf("template: %s\n", template);
  1419. #endif
  1420.  
  1421.    for (currentdrive = drivelist; *currentdrive != '\0';
  1422.             currentdrive++)
  1423.       {
  1424.       newdriveletter[0] = *currentdrive;
  1425.       newdriveletter[1] = ':';
  1426.       newdriveletter[2] = '\0';
  1427.       newdrive = (unsigned) (*currentdrive - 'A' +1);
  1428.       _dos_setdrive(newdrive, &drivecount);
  1429.       searchdir("\\*.*");
  1430.       }
  1431.  
  1432.    if (broken == TRUE)
  1433.       printf("\nNJFIND: Searching interrupted!\n\n");
  1434.  
  1435.    printf("\n   %5u file", found);
  1436.    if (found != 1)
  1437.       putchar('s');
  1438.    printf(" found.\n");
  1439.    printf("   %5u archived file", archivefound);
  1440.    if (archivefound != 1)
  1441.       putchar('s');
  1442.    printf(" found.\n\n");
  1443.  
  1444.    if (totalsmode == TRUE || verbose == TRUE)
  1445.       {
  1446.       if (found != 0)
  1447.          printf("Found files total %lu bytes.\n", totallength);
  1448.       if (archivefound != 0)
  1449.          printf("Found archive files total %lu bytes.\n", archivetotallength);
  1450.       }
  1451.  
  1452.    if (changedrive == TRUE)
  1453.       _dos_setdrive(olddrive, &drivecount);
  1454.  
  1455.    exit(0);
  1456. }
  1457.  
  1458.  
  1459.