test.c

Bookmarks
Notes
Line SL5
sideBar
Line:

Add To:
  1. '   
  2. /* --------------------------------------------------------------------------
  3.    Nifty James' Famous File Find Utility

  4.    Version 1.00 of 20 November 1989
    Enter comment.
    Enter comment.
    Enter comment.
  5.    Version 1.10 of 16 December 1989
  6.    Version 1.11 of  5 January  1990
  7.    Version 1.12 of 13 February 1990
  8.    Version 1.50 of 25 March    1990
  9.    Version 2.00 of  3 April    1990
  10.    Version 2.10 of 25 August   1991
  11.    Version 2.15 of  9 December 1991
  12.    Version 2.16 of 19 October  1992
  13.    Version 2.17 of 22 March    1993 

  14.    (C) Copyright 1989, 1990, 1991, 1992 by Mike Blaszczak
  15.    All Rights Reserved.

  16.    Written for the Microsoft C Compiler Version 6.00AX.
  17.    LINK with an increased stack size!

  18.    Updated for Microsoft C/C++ Version 8.00 at Version 2.17
  19. */


  20. /* --------------------------------------------------------------------------
  21.    Needed #include Files
  22. */

  23. #pragma pack(1)                           /* don't space structure members */
  24. #include <ctype.h>
  25. #include <dos.h>
  26. #include <signal.h>
  27. #include <stdio.h>
  28. #include <stdlib.h>
  29. #include <string.h>
  30. #include <time.h>

  31. typedef  unsigned char byte;
  32. typedef  unsigned int word;
  33. typedef  unsigned long dword;    
  34. typedef  char boolean

  35. #define  TRUE     (1==1)
  36. #define  FALSE    (!TRUE)

  37. #define ELEMENTS(array) (sizeof(array)/sizeof(array[0]))

  38. /* --------------------------------------------------------------------------
  39.    Structures used here
  40. */

  41. struct   fullfilename               /* used internally to hold filenames   */
  42. {
  43.    char  filename[9];
  44.    char  fileextension[4];
  45. };


  46. /* This is the "local file header" for zip files.  The zip_lfh structure
  47.    preceeds each file in the ZIP file, and describes the individual files
  48.    stored there.  Note that we read one of these and then fseek() over it
  49.    by using the value in zip_lfh.csize to get the new area.
  50. */

  51. struct   zip_lfh
  52. {
  53.    dword signature;                 /* signature, must be 0x04034B50       */
  54.    word  exversion;                 /* version needed to extract           */
  55.    word  bitflags;                  /* general purpose bit flags           */
  56.    word  compression;               /* compression method                  */
  57.    word  modtime;
  58.    word  moddate;                   /* last modification time and date     */
  59.    dword crc32;                     /* crc32 filecheck for file            */
  60.    dword csize;                     /* compressed size                     */
  61.    dword usize;                     /* uncompressed size                   */
  62.    word  fnlength;                  /* filename length                     */
  63.    word  extralength;               /* extra field length                  */
  64. };

  65. /* This is the "local file header" for ARC files.  The arc_lfh structure
  66.    preceeds each file in the ARC file, and describes the individual files
  67.    stored there.  Note that we read one of these and then fseek() over
  68.    the compressed file by using the value arc_lfh.csize to get the new
  69.    area.

  70.    Note that ARC and PAK files use this same structure!
  71. */

  72. struct   arc_lfh
  73. {
  74.    byte  marker;                    /* always 01Ah                         */
  75.    byte  compression;               /* how was this file stored?           */
  76.    char  filename[13];              /* filename is always 13 long          */
  77.    dword csize;                     /* compressed size                     */
  78.    word  date;                      /* date of original file               */
  79.    word  time;                      /* time of original file               */
  80.    word  crc;                       /* sixteen-bit CRC for this file       */
  81.    dword usize;                     /* uncompressed size                   */
  82. };


  83. struct   lzh_lfh
  84. {
  85.    byte  unknown[7];                /* unknown area                        */
  86.    dword csize;                     /* compressed size                     */
  87.    dword usize;                     /* original size                       */
  88.    word  time;                      /* last modification of date and time  */
  89.    word  date;                      /*     of the stored file              */
  90.    byte  unknown3[2];
  91.    byte  fnlength;                  /* length of file name                 */
  92. };


  93. struct   zoo_lfh
  94. {
  95.    word  time;                      /* last modification of date and time  */
  96.    word  date;                      /*     of the stored file              */       
  97.    word  unknownword;
  98.    dword usize;                     /* original file size                  */
  99.    dword csize;                     /* compressed size                     */
  100.    byte  unknown[10];               /* unknown area ...                    */
  101.    char  filename[13];              /* ASCIIZ filename                     */
  102. };

  103. struct   dwc_lfh
  104. {
  105.    char  name[13];                  /* file name                           */
  106.    dword size;                      /* original size                       */
  107.    dword time;                      /* file timestamp                      */
  108.    dword new_size;                  /* compressed size                     */
  109.    dword pos;                       /* fseek() of this file in archive     */
  110.    byte  method;                    /* compression code                    */
  111.    byte  comment_size;              /* length of file comment              */
  112.    byte  directory_size;            /* length of directory name tag        */
  113.    word  crc;                       /* file CRC value                      */
  114. };


  115. /* DWC files are different because they have a big archive-wide information
  116.    area that NJFIND needs to use.  This is defined in dwc_block.
  117. */

  118. struct   dwc_block
  119. {
  120.    word  size;                      /* size of this structure              */
  121.    byte  ent_sz;                    /* size of dwc_lfh structure           */
  122.    char  header[13];                /* name of header file for listings    */
  123.    dword time;                      /* timestamp of last archive change    */
  124.    dword entries;                   /* entries in the archive              */
  125.    char  id[3];                     /* "DWC" to identify archive           */
  126. };


  127. /* ARJ files are even stranger; they have their own information block
  128.    which is defined here, starting in Version 2.10.
  129. */

  130. struct   arj_lfh
  131. {
  132.    unsigned int   wHeaderID;
  133.    unsigned int   wBasicHeaderSize;
  134.    unsigned char  bFirstHeaderSize;
  135.    unsigned char  bArchiverVersionNumber;
  136.    unsigned char  bMinimumToExtract;
  137.    unsigned char  bHostOS;
  138.    unsigned char  bARJFlags;
  139.    unsigned char  bMethod;
  140.    unsigned char  bFileType;
  141.    unsigned char  bReserved;
  142.    unsigned long  dwDateTimeStamp;
  143.    unsigned long  dwCompressedSize;
  144.    unsigned long  dwOriginalSize;
  145.    unsigned long  dwOriginalFileCRC;
  146.    unsigned int   wEntryNamePos;
  147.    unsigned int   wFileAccessMode;
  148.    unsigned int   wHostData;
  149. };



  150. /* --------------------------------------------------------------------------
  151.    Global Variables
  152. */

  153. unsigned       result;              /* stored result of _dos_find*() calls */
  154. char           *temp;               /* temporary pointer for strings       */
  155. char           *extension;          /* pointer to file extension           */
  156. char           template[_MAX_PATH]; /* template to match files searched    */
  157. char           *inputfile;          /* pointer to wildcard name            */

  158. struct fullfilename
  159.                tempfullname,        /* full name of file we're working on  */
  160.                matchname;           /* name to match                       */

  161. unsigned       found =0;            /* count of found files                */
  162. unsigned long  totallength = 0L;    /* total of file lengths               */

  163. unsigned       archivefound = 0;    /* count of found files in archves     */
  164. unsigned long  archivetotallength = 0L;
  165.                                     /* total file lengths of archive files.*/

  166. struct zip_lfh zipworker;           /* workspace for zip files             */
  167. struct arc_lfh arcworker;           /* workspace for arc files             */
  168. struct lzh_lfh lzhworker;           /* workspace for lzh files             */
  169. struct zoo_lfh zooworker;           /* workspace for zoo files             */

  170. boolean        searchzips = TRUE;   /* flags for options on searching      */
  171. boolean        searchlzhs = TRUE;   /*    the different archive types      */
  172. boolean        searchzoos = TRUE;
  173. boolean        searcharcs = TRUE;
  174. boolean        searchpaks = TRUE;
  175. boolean        searchdwcs = TRUE;
  176. boolean        searcharjs = TRUE;

  177. boolean        verbose = FALSE;     /* TRUE for verbose mode               */
  178. boolean        progress = FALSE;    /* TRUE to show progress               */
  179. boolean        totalsmode = FALSE;  /* TURE for display totals             */
  180. boolean        changedrive = FALSE; /* set TRUE if user changed disks      */

  181. boolean        broken = FALSE;      /* set true if user does CTRL+BREAK    */

  182. boolean        alldrives = FALSE;   /* search through all drives           */

  183. char           fiftyspaces[55];     /* a bunch of spaces for printmatch()  */

  184. unsigned       drivecount;          /* used to change disk drives          */
  185. unsigned       newdrive;
  186. unsigned       olddrive;
  187. unsigned       lastdrive;
  188. char           newdriveletter[3];

  189. char           drivelist[28];       /* list of drives to search            */
  190. char           *currentdrive;

  191. char           szFileNameBuffer[4096];


  192. /* --------------------------------------------------------------------------
  193.    Global Constants
  194. */

  195. const char     *fmessageread  = "Couldn't open file \"%s\" for read.\n";
  196. const char     *readbinary    = "rb";
  197. const char     *notsearching  = "Not searching %s files\n";
  198. const char     *eraseline     = "\t\t\t\t\t\t\t\t\t\r";
  199. const char     *wfi           = " was found in ";
  200. const char     *swfis         = "%s was found in %s%s";

  201. const char *month3names[12] =
  202. {
  203.    "Jan", "Feb", "Mar", "Apr", "May", "Jun",
  204.    "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
  205. };


  206. /* --------------------------------------------------------------------------
  207.    ANSI-C Standard Function Prototypes
  208. */

  209. void  processzip(char *filenamestruct find_t *info);
  210. void  processpak(char *filenamestruct find_t *info);
  211. void  processarc(char *filenamestruct find_t *info);
  212. void  processlzh(char *filenamestruct find_t *info);
  213. void  processzoo(char *filenamestruct find_t *info);
  214. void  processdwc(char *filenamestruct find_t *info);
  215. void  processarj(char *filenamestruct find_t *info);

  216. void  printinside(char *filenamechar *archivedword filesizeword dateword time);
  217. void  printinsidedwc(char *filenamechar *archivedword filesize, time_t date);
  218. void  printmatch(char *filenamedword filesizeword dateword time);
  219. void  printdate(word date);
  220. void  printtime(word time);
  221. int   comparenames(struct fullfilename *leftstruct fullfilename *right);
  222. void  maketemplate(void);
  223. void  makefullname(struct fullfilename *ffnchar *path);
  224. void  searchdir(char *dirname);
  225. void  showusage(void);
  226. void  handleoption(char *optionboolean inenvironment);
  227. void  breakout(void);
  228. void  builddrivelist(void);
  229. void  handleenvironment(void);
  230. void  main(int argcchar *argv[]);


  231. /* --------------------------------------------------------------------------
  232. */

  233. void  processzip(char *filenamestruct find_t *info)
  234. {
  235.    FILE                 *zipfile;
  236.    char                 *insidefilename = NULL;
  237.    struct fullfilename  zipfullname;
  238.    char                 *temporary;

  239. #if defined(DEBUG)
  240.    printf("processzip(\"%s\")\n"info->name);
  241. #endif

  242.    /* if the file name doesn't match the requested template name,
  243.       return now and don't even bother opening the zip file.
  244.    */

  245.    if (comparenames(&tempfullname, &matchname) == 0)
  246.       {
  247.       found++;
  248.       if (totalsmode == FALSE)
  249.          if (verbose == TRUE)
  250.             printmatch(filenameinfo->size, info->wr_date, info->wr_time);
  251.          else
  252.             printf("%s%s\n"newdriveletterfilename);

  253.       totallength += info->size;
  254.       }

  255.    if (searchzips == FALSE)
  256.       return;

  257.    /* open the zip file by name and see if it was successful.
  258.    */

  259.    zipfile = fopen(filenamereadbinary);
  260.    if (zipfile == NULL)
  261.       {
  262.       fprintf(stderr, fmessagereadfilename);
  263.       return;
  264.       }

  265.    /* loop through the whole file
  266.    */

  267.    while(!feof(zipfile))
  268.       {
  269.    /* read the local file header.
  270.       if we don't get it, break the loop.
  271.       At this same time, check it for a valid signature.
  272.    */

  273.       if (fread(&zipworkersizeof(struct zip_lfh), (size_t) 1, zipfile) != 1)
  274.          break;

  275.       if (zipworker.signature != 0x04034B50)
  276.          break;

  277.    /* free the temporary file name area
  278.       and allocate a space for the new name.
  279.       read it from the zip file.
  280.    */
  281.       insidefilename = szFileNameBuffer;

  282.       if (fread((void *) insidefilename,  zipworker.fnlength, (size_t) 1, zipfile) != 1)
  283.          break;
  284.       insidefilename[zipworker.fnlength] = '\0';

  285.       temporary = strrchr(insidefilename, '/');
  286.       if (temporary != NULL)
  287.          temporary++;
  288.       else
  289.          temporary = insidefilename;

  290.       makefullname(&zipfullnametemporary);
  291.       if (comparenames(&zipfullname, &matchname) == 0)
  292.          {
  293.          archivefound++;
  294.          archivetotallength += zipworker.usize;
  295.          if (totalsmode == FALSE)
  296.             if (verbose == TRUE)
  297.                printinside(filenametemporaryzipworker.usize,
  298.                   zipworker.moddate, zipworker.modtime);
  299.             else
  300.                {
  301.                printf(swfistemporarynewdriveletterfilename);
  302.                putchar('\n');
  303.                }
  304.          }
  305.       else
  306.          if (progress == TRUE)
  307.             printf("%s%s\t\t\r"newdrivelettertemporary);

  308. #if defined(DEBUG)
  309.       printf("temporary = \"%s\"\n"temporary);
  310. #endif

  311.    /* seek around the compressed file.
  312.    */
  313.       fseek(zipfile, zipworker.csize + zipworker.extralength, SEEK_CUR);

  314.    /* at this point, the file pointer is once again at the
  315.       next local file header ...
  316.    */
  317.       }


  318.    if (progress == TRUE)
  319.       printf(eraseline);
  320.    fclose(zipfile);
  321.    return;
  322. }


  323. /* --------------------------------------------------------------------------
  324. */

  325. void  processpak(char *filenamestruct find_t *info)
  326. {
  327.    FILE                 *pakfile;
  328.    struct fullfilename  pakfullname;

  329. #if defined(DEBUG)
  330.    printf("processpak(\"%s\")\n"info->name);
  331. #endif

  332.    /* if the file name doesn't match the requested template name,
  333.       return now and don't even bother opening the zip file.
  334.    */

  335.    if (comparenames(&tempfullname, &matchname) == 0)
  336.       {
  337.       found++;
  338.       if (totalsmode == FALSE)
  339.          if (verbose == TRUE)
  340.             printmatch(filenameinfo->size, info->wr_date, info->wr_time);
  341.          else
  342.             printf("%s%s\n"newdriveletterfilename);
  343.       totallength += info->size;
  344.       }

  345.    if (searchpaks == FALSE)
  346.       return;

  347.    /* open the pak file by name and see if it was successful.
  348.    */

  349.    pakfile = fopen(filenamereadbinary);
  350.    if (pakfile == NULL)
  351.       {
  352.       fprintf(stderr, fmessagereadfilename);
  353.       return;
  354.       }

  355.    /* loop through the whole file
  356.    */

  357.    while(!feof(pakfile))
  358.       {
  359.    /* read the local file header.
  360.       if we don't get it, break the loop.
  361.    */

  362.       if (fread(&arcworkersizeof(struct arc_lfh), (size_t) 1, pakfile) != 1)
  363.          break;

  364.    /* check the compression method.
  365.       if it is zero, the pak file is over.
  366.    */

  367.       if (arcworker.compression == 0)
  368.          break;

  369.       makefullname(&pakfullnamearcworker.filename);
  370.       if (comparenames(&pakfullname, &matchname) == 0)
  371.          {
  372.          archivefound++;
  373.          archivetotallength += arcworker.usize;
  374.          if (totalsmode == FALSE)
  375.             if (verbose == TRUE)
  376.                printinside(filenamearcworker.filenamearcworker.usize,
  377.                   arcworker.date, arcworker.time);
  378.             else
  379.                {
  380.                printf(swfisarcworker.filenamenewdriveletterfilename);
  381.                putchar('\n');
  382.                }
  383.          }
  384.       else
  385.          if (progress == TRUE)
  386.             printf("%s\t\t\r"arcworker.filename);

  387. #if defined(DEBUG)
  388.       printf("filename = \"%s\"\n"arcworker.filename);
  389. #endif

  390.    /* seek around the compressed file.
  391.    */
  392.       fseek(pakfile, arcworker.csize, SEEK_CUR);

  393.    /* at this point, the file pointer is once again at the
  394.       next local file header ...
  395.    */
  396.       }

  397.    if (progress == TRUE)
  398.       printf(eraseline);
  399.    fclose(pakfile);
  400.    return;
  401. }


  402. /* --------------------------------------------------------------------------
  403. */

  404. void  processarc(char *filenamestruct find_t *info)
  405. {
  406.    FILE                 *arcfile;
  407.    struct fullfilename  arcfullname;

  408. #if defined(DEBUG)
  409.    printf("processarc(\"%s\")\n"info->name);
  410. #endif

  411.    /* if the file name doesn't match the requested template name,
  412.       return now and don't even bother opening the zip file.
  413.    */

  414.    if (comparenames(&tempfullname, &matchname) == 0)
  415.       {
  416.       found++;
  417.       if (totalsmode == FALSE)
  418.          if (verbose == TRUE)
  419.             printmatch(filenameinfo->size, info->wr_date, info->wr_time);
  420.          else
  421.             printf("%s%s\n"newdriveletterfilename);
  422.       totallength += info->size;
  423.       }

  424.    if (searcharcs == FALSE)
  425.       return;

  426.    /* open the arc file by name and see if it was successful.
  427.    */

  428.    arcfile = fopen(filenamereadbinary);
  429.    if (arcfile == NULL)
  430.       {
  431.       fprintf(stderr, fmessagereadfilename);
  432.       return;
  433.       }

  434.    /* loop through the whole file
  435.    */

  436.    while(!feof(arcfile))
  437.       {
  438.    /* read the local file header.
  439.       if we don't get it, break the loop.
  440.    */

  441.       if (fread(&arcworkersizeof(struct arc_lfh), (size_t) 1, arcfile) != 1)
  442.          break;

  443.    /* check the compression method.
  444.       if it is zero, the pak file is over.
  445.    */

  446.       if (arcworker.compression == 0)
  447.          break;

  448.       makefullname(&arcfullnamearcworker.filename);
  449.       if (comparenames(&arcfullname, &matchname) == 0)
  450.          {
  451.          archivefound++;
  452.          archivetotallength += arcworker.usize;
  453.          if (totalsmode == FALSE)
  454.             if (verbose == TRUE)
  455.                printinside(filenamearcworker.filenamearcworker.usize,
  456.                   arcworker.date, arcworker.time);
  457.             else
  458.                {
  459.                printf(swfisarcworker.filenamenewdriveletterfilename);
  460.                putchar('\n');
  461.                }
  462.          }
  463.       else
  464.          if (progress == TRUE)
  465.             printf("%s\t\t\r"arcworker.filename);

  466. #if defined(DEBUG)
  467.       printf("filename = \"%s\"\n"arcworker.filename);
  468. #endif

  469.    /* seek around the compressed file.
  470.    */
  471.       fseek(arcfile, arcworker.csize, SEEK_CUR);

  472.    /* at this point, the file pointer is once again at the
  473.       next local file header ...
  474.    */
  475.       }

  476.    if (progress == TRUE)
  477.       printf(eraseline);
  478.    fclose(arcfile);
  479.    return;
  480. }


  481. /* --------------------------------------------------------------------------
  482. */

  483. void  processlzh(char *filenamestruct find_t *info)
  484. {
  485.    FILE                 *lzhfile;
  486.    char                 *insidefilename = NULL;
  487.    struct fullfilename  lzhfullname;
  488.    char                 *temporary;

  489. #if defined(DEBUG)
  490.    printf("processlzh(\"%s\")\n"info->name);
  491. #endif

  492.    /* if the file name doesn't match the requested template name,
  493.       return now and don't even bother opening the lzh file.
  494.    */

  495.    if (comparenames(&tempfullname, &matchname) == 0)
  496.       {
  497.       found++;
  498.       if (totalsmode == FALSE)
  499.          if (verbose == TRUE)
  500.             printmatch(filenameinfo->size, info->wr_date, info->wr_time);
  501.          else
  502.             printf("%s%s\n"newdriveletterfilename);
  503.       totallength += info->size;
  504.       }

  505.    if (searchlzhs == FALSE)
  506.       return;

  507.    /* open the lzh file by name and see if it was successful.
  508.    */

  509.    lzhfile = fopen(filenamereadbinary);
  510.    if (lzhfile == NULL)
  511.       {
  512.       fprintf(stderr, fmessagereadfilename);
  513.       return;
  514.       }

  515.    /* loop through the whole file
  516.    */

  517.    while(!feof(lzhfile))
  518.       {
  519.    /* read the local file header.
  520.       if we don't get it, break the loop.
  521.    */

  522.       if (fread(&lzhworkersizeof(struct lzh_lfh), (size_t) 1, lzhfile) != 1)
  523.          break;

  524.       insidefilename = szFileNameBuffer;

  525.       if (fread((void *) insidefilename,  lzhworker.fnlength, (size_t) 1, lzhfile) != 1)
  526.          break;
  527.       insidefilename[lzhworker.fnlength] = '\0';

  528.       temporary = strrchr(insidefilename, '\\');
  529.       if (temporary != NULL)
  530.          {
  531.          temporary++;
  532.          }
  533.       else
  534.          {
  535.          temporary = insidefilename;
  536.          }

  537.       makefullname(&lzhfullnametemporary);
  538.       if (comparenames(&lzhfullname, &matchname) == 0)
  539.          {
  540.          archivefound++;
  541.          archivetotallength += lzhworker.usize;
  542.          if (totalsmode == FALSE)
  543.             if (verbose == TRUE)
  544.                printinside(filenametemporarylzhworker.usize,
  545.                   lzhworker.date, lzhworker.time);
  546.             else
  547.                {
  548.                printf(swfistemporarynewdriveletterfilename);
  549.                putchar('\n');
  550.                }
  551.          }
  552.       else
  553.          if (progress == TRUE)
  554.             printf("%s\t\t\r"temporary);

  555. #if defined(DEBUG)
  556.       printf("temporary = \"%s\"\n"temporary);
  557. #endif

  558.    /* seek around the compressed file.
  559.    */
  560.       fseek(lzhfile, lzhworker.csize+2L, SEEK_CUR);

  561.    /* at this point, the file pointer is once again at the
  562.       next local file header ...
  563.    */
  564.       }

  565.    if (progress == TRUE)
  566.       printf(eraseline);
  567.    fclose(lzhfile);
  568.    return;
  569. }


  570. /* --------------------------------------------------------------------------
  571. */

  572. void  processzoo(char *filenamestruct find_t *info)
  573. {
  574.    FILE                 *zoofile;
  575.    struct fullfilename  zoofullname;
  576.    int                  thischar;

  577. #if defined(DEBUG)
  578.    printf("processzoo(\"%s\")\n"info->name);
  579. #endif

  580.    /* if the file name doesn't match the requested template name,
  581.       return now and don't even bother opening the zip file.
  582.    */

  583.    if (comparenames(&tempfullname, &matchname) == 0)
  584.       {
  585.       if (totalsmode == FALSE)
  586.          if (verbose == TRUE)
  587.             printmatch(filenameinfo->size, info->wr_date, info->wr_time);
  588.          else
  589.             printf("%s%s\n"filename);
  590.       found++;
  591.       totallength += info->size;
  592.       }

  593.    if (searchzoos == FALSE)
  594.       return;

  595.    /* open the zoo file by name and see if it was successful.
  596.    */

  597.    zoofile = fopen(filenamereadbinary);
  598.    if (zoofile == NULL)
  599.       {
  600.       fprintf(stderr, fmessagereadfilename);
  601.       return;
  602.       }

  603.    /* first, skip over the ZOO FILE message
  604.    */

  605.    while (!feof(zoofile))
  606.       {
  607.       thischar = fgetc(zoofile);
  608.       if (thischar == 0x1A)
  609.          break;
  610.       }

  611.    if (feof(zoofile))
  612.       {
  613.       fclose(zoofile);
  614.       return;
  615.       }

  616.    /* skip over more header junk */

  617.    fseek(zoofile, 38L, SEEK_CUR);

  618.    /* loop through the whole file
  619.    */

  620.    while(!feof(zoofile))
  621.       {
  622.    /* read the local file header.
  623.       if we don't get it, break the loop.
  624.    */

  625.       if (fread(&zooworkersizeof(struct zoo_lfh), (size_t) 1, zoofile) != 1)
  626.          break;

  627.    /* check the compression method.
  628.       if it is zero, the pak file is over.
  629.    */

  630.       if (zooworker.filename[0] == '\0')
  631.          break;

  632.       strupr(zooworker.filename);
  633.       makefullname(&zoofullnamezooworker.filename);
  634.       if (comparenames(&zoofullname, &matchname) == 0)
  635.          {
  636.          archivefound++;
  637.          totallength += zooworker.usize;
  638.          if (totalsmode == FALSE)
  639.             if (verbose == TRUE)
  640.                printinside(filenamezooworker.filenamezooworker.usize,
  641.                   zooworker.date, zooworker.time);
  642.             else
  643.                {
  644.                printf(swfiszooworker.filenamenewdriveletterfilename);
  645.                putchar('\n');
  646.                }
  647.          }
  648.       else
  649.          if (progress == TRUE)
  650.             printf("%s\t\t\r"zooworker.filename);

  651. #if defined(DEBUG)
  652.       printf("filename = \"%s\"\n"zooworker.filename);
  653. #endif

  654.    /* seek around the compressed file.
  655.    */
  656.       fseek(zoofile, zooworker.csize+34L, SEEK_CUR);

  657.    /* at this point, the file pointer is once again at the
  658.       next local file header ...
  659.    */
  660.       }

  661.    if (progress == TRUE)
  662.       printf(eraseline);
  663.    fclose(zoofile);
  664.    return;
  665. }


  666. /* --------------------------------------------------------------------------
  667. */

  668. void  processdwc(char *filenamestruct find_t *info)
  669. {
  670.    char                 buff[256];
  671.    dword                entrycount;
  672.    long                 l;
  673.    int                  num;
  674.    int                  i=-1;
  675.    int                  j;
  676.    FILE                 *dwcfile;
  677.    struct dwc_block     archive_block;
  678.    struct dwc_lfh       dwc_entry;
  679.    struct fullfilename  dwcfullname;

  680. #if defined(DEBUG)
  681.    printf("processdwc(\"%s\")\n"info->name);
  682. #endif

  683.    /* if the file name doesn't match the requested template name,
  684.       return now and don't even bother opening the zip file.
  685.    */

  686.    if (comparenames(&tempfullname, &matchname) == 0)
  687.       {
  688.       if (totalsmode == FALSE)
  689.          if (verbose == TRUE)
  690.             printmatch(filenameinfo->size, info->wr_date, info->wr_time);
  691.          else
  692.             printf("%s%s\n"filename);
  693.       found++;
  694.       totallength += info->size;
  695.       }

  696.    if (searchzoos == FALSE)
  697.       return;

  698.    /* open the zoo file by name and see if it was successful.
  699.    */

  700.    dwcfile = fopen(filenamereadbinary);
  701.    if (dwcfile == NULL)
  702.       {
  703.       fprintf(stderr, fmessagereadfilename);
  704.       return;
  705.       }

  706.    /* find (and read) the archive descriptor structure
  707.    */

  708.    for (j=1; j <11 && i<0; j++)
  709.       {
  710.       if (fseek(dwcfile, - ((long) ELEMENTS(buff)*j - (j-1)*5), SEEK_END))
  711.          {
  712.          fseek(dwcfile, 0L, SEEK_SET);
  713.          }
  714.       else
  715.          {
  716.          l = ftell(dwcfile);
  717.          }

  718.       num = fread((void *) buffsizeof(char), ELEMENTS(buff), dwcfile);

  719.       for (i = num-3; i>=0 && strncmp(buff+i, "DWC", 3); i--)
  720.          ;
  721.       }

  722.    if (i<0)
  723.       {
  724.       fprintf(stderr, "NJFIND: Invalid DWC file format in file %s\n"filename);
  725.       fclose(dwcfile);
  726.       return;
  727.       }

  728.    l += i+3;

  729.    fseek(dwcfile, l - sizeof(archive_block), SEEK_SET);
  730.    fread((void *) &archive_blocksizeof(archive_block), 1, dwcfile);

  731.    if (archive_block.entries > 5000 || archive_block.entries < 0)
  732.       {
  733.       fprintf(stderr, "NJFIND: Invalid DWC file format in file %s\n"filename);
  734.       fclose(dwcfile);
  735.       return;
  736.       }

  737.    l -= ((longarchive_block.entries * archive_block.ent_sz +
  738.       archive_block.size);

  739.    fseek(dwcfile, l, SEEK_SET);

  740.    /* get each one   */

  741.    for (entrycount = 0; entrycount < archive_block.entries; entrycount++)
  742.       {
  743.       fread((void *) &dwc_entrysizeof(dwc_entry), 1, dwcfile);

  744.       if (sizeof(dwc_entry) < archive_block.ent_sz)
  745.          fseek(dwcfile, (long) (archive_block.ent_sz - sizeof(dwc_entry)), SEEK_CUR);

  746.       makefullname(&dwcfullnamedwc_entry.name);

  747.       if (comparenames(&dwcfullname, &matchname) == 0)
  748.          {
  749.          archivefound++;
  750.          archivetotallength += dwc_entry.new_size;
  751.          if (totalsmode == FALSE)
  752.             if (verbose == TRUE)
  753.                {
  754.                printinsidedwc(filenamedwc_entry.name, dwc_entry.new_size,
  755.                   dwc_entry.time);
  756.                }
  757.             else
  758.                {
  759.                printf(swfisdwc_entry.name, newdriveletterfilename);
  760.                putchar('\n');
  761.                }
  762.          }
  763.       else
  764.          if (progress == TRUE)
  765.             printf("%s%s\t\t\r"newdriveletterdwc_entry.name);
  766.       }


  767.    if (progress == TRUE)
  768.       printf(eraseline);

  769.    fclose(dwcfile);
  770.    return;
  771. }


  772. /* --------------------------------------------------------------------------
  773. */

  774. void  processarj(char *pstrFileNamestruct find_t *info)
  775. {
  776.    FILE                 *fARJFile;
  777.    char                 *pstrTemporary;
  778.    struct fullfilename  zipfullname;
  779.    unsigned int         wExtHeaderSize;
  780.    boolean              bSkippedHeader;
  781.    struct arj_lfh       sBlock;
  782.    int                  nNameLength;

  783.    fARJFile = fopen(pstrFileName, "rb");
  784.    if (fARJFile == NULL)
  785.       {
  786.       fprintf(stderr, "NJFIND: Invalid ARJ file format in %s\n"pstrFileName);
  787.       fclose(fARJFile);
  788.       return;
  789.       }

  790.    bSkippedHeader = FALSE;

  791.    while (!feof(fARJFile))
  792.       {
  793.       fread(&sBlocksizeof(struct arj_lfh), 1, fARJFile);

  794.       if (sBlock.wBasicHeaderSize == 0)
  795.          continue;

  796.       nNameLength = sBlock.wBasicHeaderSize-sizeof(struct arj_lfh)+4;

  797.       fread(szFileNameBuffer, 1, nNameLength, fARJFile);

  798.       fseek(fARJFile, 4L, SEEK_CUR);

  799.       while ((wExtHeaderSize = (unsigned int) getw(fARJFile)) != 0)
  800.          {
  801.          fseek(fARJFile, wExtHeaderSize+2, SEEK_CUR);
  802.          }

  803.       fseek(fARJFile, sBlock.dwCompressedSize, SEEK_CUR);

  804.       if (bSkippedHeader == FALSE)
  805.          {
  806.          bSkippedHeader = TRUE;
  807.          }
  808.       else
  809.          {
  810.          pstrTemporary = strchr(szFileNameBuffer, '/');

  811.          if (pstrTemporary != NULL)
  812.             {
  813.             pstrTemporary++;
  814.             }
  815.          else
  816.             {
  817.             pstrTemporary = szFileNameBuffer;
  818.             }

  819.          makefullname(&zipfullnamepstrTemporary);
  820.          if (comparenames(&zipfullname, &matchname) == 0)
  821.             {
  822.             archivefound++;
  823.             archivetotallength += sBlock.dwOriginalSize;

  824.             if (totalsmode == FALSE)
  825.                {
  826.                if (verbose == TRUE)
  827.                   {
  828.                   printinside(pstrFileNamepstrTemporarysBlock.dwOriginalSize,
  829.                      (word) (sBlock.dwDateTimeStamp >> 16),
  830.                      (word) (sBlock.dwDateTimeStamp & 0x0000FFFFL));
  831.                   }
  832.                else
  833.                   {
  834.                   printf(swfisszFileNameBuffernewdriveletterpstrFileName);
  835.                   putchar('\n');
  836.                   }
  837.                }
  838.             }
  839.          else
  840.             {
  841.             if (progress == TRUE)
  842.                {
  843.                printf("%s%s\t\t\r"newdriveletterszFileNameBuffer);
  844.                }
  845.             }
  846.          }
  847.       }

  848.    fclose(fARJFile);
  849.    return;
  850. }



  851. /* --------------------------------------------------------------------------
  852. */

  853. void  processnormal(char *filenamestruct find_t *info)
  854. {
  855. #if defined(DEBUG)
  856.    printf("processnormal(\"%s\")   "info->name);
  857.    printf("comparenames = %d\n"comparenames(&tempfullname, &matchname));
  858. #endif

  859.    if (comparenames(&tempfullname, &matchname) == 0)
  860.       {
  861.       found++;
  862.       if (totalsmode == FALSE)
  863.          if (verbose == TRUE)
  864.             printmatch(filenameinfo->size, info->wr_date, info->wr_time);
  865.          else
  866.             printf("%s%s\n"newdriveletterfilename);
  867.       totallength += info->size;
  868.       }
  869.    else
  870.       if (progress == TRUE)
  871.          printf("%s\t\t\r"info->name);

  872.    return;
  873. }


  874. /* --------------------------------------------------------------------------
  875.    printinside() prints out the file information from within an archive.
  876.    This makes it different than printmatch only in that the file name
  877.    *and* the name of the archive the file was in are printed.
  878. */

  879. void  printinside(char *filenamechar *archive,
  880.                dword filesizeword dateword time)
  881. {
  882.    int   count;

  883.    count = strlen(filename) + 14 + strlen(archive) + strlen(newdriveletter);
  884.    printf(swfisarchivenewdriveletterfilename);

  885.    if (count > 48)
  886.       {
  887.       putchar('\n');
  888.       printf("%s"fiftyspaces);
  889.       }
  890.    else
  891.       while (count < 48)
  892.          {
  893.          putchar(' ');
  894.          count++;
  895.          }

  896.    printf("%8lu "filesize);
  897.    printdate(date);
  898.    printtime(time);
  899.    putchar('\n');

  900.    return;
  901. }



  902. /* --------------------------------------------------------------------------
  903.    printinsidedwc() prints out the file information from within a DWC
  904.    archive.  DWC archives are a little different because they store
  905.    the date and time stamp for each file in the Unix-like "localtime()"
  906.    format.

  907.    For this function, then, we've repleaced the printdate() and
  908.    printtime() calls with slightly different code.
  909. */

  910. void  printinsidedwc(char *filenamechar *archive,
  911.             dword filesize, time_t date)
  912. {
  913.    int   count;
  914.    struct tm *filetime;

  915.    filetime = localtime(&date);

  916.    count = strlen(filename) + 14 + strlen(archive) + strlen(newdriveletter);
  917.    printf(swfisarchivenewdriveletterfilename);

  918.    if (count > 48)
  919.       {
  920.       putchar('\n');
  921.       printf("%s"fiftyspaces);
  922.       }
  923.    else
  924.       while (count < 48)
  925.          {
  926.          putchar(' ');
  927.          count++;
  928.          }

  929.    printf("%8lu "filesize);

  930.    printf("%02d-%s-%d  "filetime->tm_mday, month3names[filetime->tm_mon],
  931.       filetime->tm_year);

  932.    printf("%2.2d:%2.2d:%2.2d\n"filetime->tm_hour, filetime->tm_min,
  933.       filetime->tm_sec);

  934.    return;
  935. }



  936. /* --------------------------------------------------------------------------
  937. */

  938. void  printinsidearj(char *filenamechar *archivedword filesizedword datedword time)
  939. {
  940.    int   count;

  941.    count = strlen(filename) + 14 + strlen(archive) + strlen(newdriveletter);
  942.    printf(swfisarchivenewdriveletterfilename);

  943.    if (count > 48)
  944.       {
  945.       putchar('\n');
  946.       printf("%s"fiftyspaces);
  947.       }
  948.    else
  949.       {
  950.       while (count < 48)
  951.          {
  952.          putchar(' ');
  953.          count++;
  954.          }
  955.       }

  956.    printf("%8lu "filesize);
  957.    printdate((word) (date >> 16));
  958.    printtime((word) (time & 0x0000FFFFL));
  959.    putchar('\n');
  960.    return;
  961. }


  962. /* --------------------------------------------------------------------------
  963.    printmatch() prints out the file's information.  It does this all in a
  964.    neat, tidy way.  The width of 50 characters for the file name is imposed
  965.    because for eleven characters of a date, eight characters for a time,
  966.    one character for a space, and nine characters for a file size.
  967. */

  968. void  printmatch(char *filenamedword filesizeword dateword time)
  969. {
  970.    int count;

  971.    count = strlen(filename)+strlen(newdriveletter);
  972.    printf("%s%s"newdriveletterfilename);

  973.    if (count > 48)
  974.       {
  975.       putchar('\n');
  976.       printf("%s"fiftyspaces);
  977.       }
  978.    else
  979.       while (count < 48)
  980.          {
  981.          putchar(' ');
  982.          count++;
  983.          }

  984.    printf("%8lu "filesize);
  985.    printdate(date);
  986.    printtime(time);
  987.    putchar('\n');

  988.    return;
  989. }

  990. /* --------------------------------------------------------------------------
  991.    printdate() accepts a word of the DOS date and prints it out in
  992.    the format "DD-MMM-CC".  MMM is a three-letter name for the month.
  993. */

  994. void  printdate(word date)
  995. {
  996.    printf("%02d-%s-%d  "date & 0x001F,
  997.       month3names[((date >> 5) & 0x000F) -1], 1980+(date >> 9));

  998.    return;
  999. }


  1000. /* --------------------------------------------------------------------------
  1001.    printtime() accepts the DOS-format for the time as a word and
  1002.    prints out the time in the format "HH:MM:SS".  Note that the
  1003.    time is in twenty-four hour format.
  1004. */

  1005. void  printtime(word time)
  1006. {
  1007.    printf("%2.2d:%2.2d:%2.2d"
  1008.       time >> 11, (time >> 5) & 0x003F, (time & 0x001F) << 1);

  1009.    return;
  1010. }


  1011. /* --------------------------------------------------------------------------
  1012.    This function compares two fill file name structures.  It ignores
  1013.    question marks during the comparison, so it will match filenames that
  1014.    have expanded wildcards.  This routine will return a zero if the files
  1015.    are equivalent (or match by wildcard), and will return a one if the
  1016.    files names are not comparable.
  1017. */

  1018. int   comparenames(struct fullfilename *leftstruct fullfilename *right)
  1019. {
  1020.    register char  *source;                /* working pointers for compare  */
  1021.    register char  *dest;

  1022.    source = left->filename;
  1023.    dest   = right->filename;

  1024.    while(*source && *dest)
  1025.       {
  1026.       if (*source != '?' && *dest != '?')
  1027.          if (*source != *dest)
  1028.             return 1;               /* not equal!  */
  1029.       source++;
  1030.       dest++;
  1031.       }

  1032.    /* code added version 1.11 */

  1033.    if (*source == '\0' && *dest != '\0')
  1034.       return 1;

  1035.    /* end code added version 1.11   */

  1036.    source = left->fileextension;
  1037.    dest   = right->fileextension;

  1038.    while(*source && *dest)
  1039.       {
  1040.       if (*source != '?' && *dest != '?')       /* skip questionmarks   */
  1041.          if (*source != *dest)
  1042.             return 1;               /* not equal!  */
  1043.       source++;
  1044.       dest++;
  1045.       }

  1046.    /* code added version 1.11 */

  1047.    if (*source == '\0' && *dest != '\0')
  1048.       return 1;

  1049.    /* end code added version 1.11   */

  1050.    return 0;                        /* zero indicates success  */
  1051. }


  1052. /* --------------------------------------------------------------------------
  1053.    maketemplate() takes inputfile[] and expands all the asterisks to
  1054.    question marks.  This is done once, first, so that the checkmatch()
  1055.    routine can more quickly and efficiently check for matches in file
  1056.    names.
  1057. */

  1058. void  maketemplate()
  1059. {
  1060.    register char  *source = inputfile; /* pointers for copying data  */
  1061.    register char  *dest = template;
  1062.    int   count = 0;                    /* count of template length   */
  1063.    int   inextension = 0;              /* set after we get a .       */

  1064.    *dest++ = '\\';

  1065.    while(*source != '\0' && count < 13 && inextension < 4)
  1066.       {
  1067.       if (*source != '*')
  1068.          {
  1069.          *dest++ = *source;
  1070.          count++;
  1071.          if (count == 9 || *source == '.')
  1072.             inextension++;
  1073.          source++;
  1074.          }
  1075.       else
  1076.          {
  1077.          if (inextension != 0)
  1078.             {
  1079.             for ( ; inextension<4; inextension++)
  1080.                *dest++ = '?';
  1081.             *dest = '\0';
  1082.             break;
  1083.             }
  1084.          else
  1085.             {
  1086.             for ( ; count<8; count++)
  1087.                *dest++ = '?';
  1088.             *dest++ = '.';
  1089.             inextension = 1;
  1090.             source++;
  1091.             if (*source == '.')
  1092.                source++;
  1093.             }
  1094.          }
  1095.       }

  1096.    *dest = '\0';
  1097.    return;
  1098. }


  1099. /* --------------------------------------------------------------------------
  1100.    makefullname() accepts a pointer to a DOS path name and a pointer to
  1101.    a fullfilename structure.  makefullname() puts the file name from
  1102.    the path into the fullfilename structure and returns.
  1103. */

  1104. void  makefullname(struct fullfilename *ffnchar *path)
  1105. {
  1106.    register char  *source;
  1107.    register char  *dest;
  1108.    int            counter;

  1109.    source = strrchr(path, '\\');
  1110.    if (source == NULL)
  1111.       source = path;
  1112.    else
  1113.       source++;

  1114.    for (dest = ffn->filename, counter = 0; *source && counter<8; counter++)
  1115.       if (*source == '.')
  1116.          *dest++ = ' ';
  1117.       else
  1118.          *dest++ = *source++;

  1119.    *dest = '\0';
  1120.    if (*source != '\0')
  1121.       source++;

  1122.    for (dest = ffn->fileextension, counter = 0; counter<3; counter++)
  1123.       if (*source == '\0')
  1124.          *dest++ = ' ';
  1125.       else
  1126.          *dest++ = *source++;

  1127.    *dest = '\0';

  1128.    return;
  1129. }


  1130. /* --------------------------------------------------------------------------
  1131.    searchdir() accepts the name of a directory.  That name *MUST* include
  1132.    wildcards, and may include a partial filename, a full pathname, or a
  1133.    drive specification.

  1134.    The function will search all directories and go lower, and will call
  1135.    itself recursively if it finds any more subdirectories.  In this way,
  1136.    it traverses the subdirectory tree in an "inorder" fasion.
  1137. */

  1138. void searchdir(char *dirname)
  1139. {
  1140.    char           temppath[_MAX_PATH];
  1141.    char           thisfilename[_MAX_DIR+_MAX_FNAME+_MAX_EXT];
  1142.    struct find_t  dirinfo;

  1143.    strcpy(temppathdirname);
  1144.    result = _dos_findfirst(temppath, _A_NORMAL | _A_SUBDIR, &dirinfo);

  1145.    do {
  1146.       strcpy(thisfilenamedirname);
  1147.       *(strrchr(thisfilename, '\\')+1) = '\0';
  1148.       strcat(thisfilenamedirinfo.name);
  1149. #if defined(DEBUG)
  1150.       printf("%s "thisfilename);
  1151. #endif

  1152.       if ((dirinfo.attrib & _A_SUBDIR) &&
  1153.            dirinfo.name[0] != '.')
  1154.          {
  1155. #if defined(DEBUG)
  1156.          printf("(DIRECTORY) %s\n"thisfilename);
  1157. #endif
  1158.          strcat(thisfilename, "\\*.*");
  1159.          searchdir(thisfilename);
  1160.          }
  1161.       else
  1162.          {
  1163. #if defined(DEBUG)
  1164.          putchar('\n');
  1165. #endif

  1166.          while(broken == FALSE)
  1167.             {
  1168.             extension = strchr(thisfilename, '.');
  1169.             if (*(extension-1) == '\\')
  1170.                break;

  1171.             makefullname(&tempfullnamethisfilename);

  1172.             if (extension != NULL)
  1173.                {
  1174.                if (strcmp(extension, ".LZH") == 0)
  1175.                   {
  1176.                   processlzh(thisfilename, &dirinfo);
  1177.                   break;
  1178.                   }

  1179.          /* Note that we call the same routine for .PAK and .ARC.
  1180.             They have the same (basic) format!
  1181.          */

  1182.                if (strcmp(extension, ".PAK") == 0)
  1183.                   {
  1184.                   processpak(thisfilename, &dirinfo);
  1185.                   break;
  1186.                   }

  1187.                if (strcmp(extension, ".ARC") == 0)
  1188.                   {
  1189.                   processarc(thisfilename, &dirinfo);
  1190.                   break;
  1191.                   }

  1192.                if (strcmp(extension, ".ZOO") == 0)
  1193.                   {
  1194.                   processzoo(thisfilename, &dirinfo);
  1195.                   break;
  1196.                   }

  1197.                if (strcmp(extension, ".ZIP") == 0)
  1198.                   {
  1199.                   processzip(thisfilename, &dirinfo);
  1200.                   break;
  1201.                   }

  1202.          /* DWC was added in version 2.00 */

  1203.                if (strcmp(extension, ".DWC") == 0)
  1204.                   {
  1205.                   processdwc(thisfilename, &dirinfo);
  1206.                   break;
  1207.                   }

  1208.          /* ARJ was added in version 2.10 */

  1209.                if (strcmp(extension, ".ARJ") == 0)
  1210.                   {
  1211.                   processarj(thisfilename, &dirinfo);
  1212.                   break;
  1213.                   }
  1214.                
  1215.                }

  1216.             processnormal(thisfilename, &dirinfo);
  1217.             break;
  1218.             }
  1219.          }

  1220.       result = _dos_findnext(&dirinfo);
  1221.       } while (result == 0 && broken == FALSE);

  1222.    if (progress == TRUE)
  1223.       printf(eraseline);
  1224.    return;
  1225. }


  1226. /* --------------------------------------------------------------------------
  1227.    showusage() is a kind of error routine.  It is called when we get confused
  1228.    parsing the command line and bail out gracefully.  This prints the
  1229.    program usage and quits.
  1230. */

  1231. void  showusage()
  1232. {
  1233.    fputs("Usage: NJFIND [options] <filespec>\n", stderr);
  1234.    fputs("[options] include:\n", stderr);
  1235.    fputs("\t/A - do not search *.ARC files\n", stderr);
  1236.    fputs("\t/J - do not search *.ARJ files\n", stderr);
  1237.    fputs("\t/W - do not search *.DWC files\n", stderr);
  1238.    fputs("\t/L - do not search *.LZH files\n", stderr);
  1239.    fputs("\t/P - do not search *.PAK files\n", stderr);
  1240.    fputs("\t/O - do not search *.ZOO files\n", stderr);
  1241.    fputs("\t/Z - do not search *.ZIP files\n", stderr);
  1242.    fputs("\t/N - only search normal files (combo of /W /J /O /Z /P /A /L)\n\n", stderr);
  1243.    fputs("\t/V - verbose mode; prints statistics\n", stderr);
  1244.    fputs("\t/T - totals mode; prints no found filenames\n", stderr);
  1245.    fputs("\t/D - progress display prints filenames as searched\n", stderr);
  1246.    fputs("\t/R - run search across all DOS drives\n\n", stderr);

  1247.    exit(1);
  1248. }


  1249. /* --------------------------------------------------------------------------
  1250.    handleoption() takes care of the options the program accepts.  since
  1251.    these are all just switches, we just tweak the boolean variables that
  1252.    represent each option.
  1253. */

  1254. void  handleoption(char *optionboolean inenvironment)
  1255. {
  1256.    switch(toupper(*option))
  1257.       {
  1258.       case 'N':   searchzoos =
  1259.                   searchpaks =
  1260.                   searcharcs =
  1261.                   searchlzhs =            /* normal files ...     */
  1262.                   searchzips = FALSE;
  1263.                   fprintf(stderr, notsearching, "ARC, ARJ, DWC, LZH, PAK, ZIP, or ZOO");
  1264.                   break;

  1265.       case 'O':   searchzoos = FALSE;     /* turn off ZOO files   */
  1266.                   fprintf(stderr, notsearching, "ZOO");
  1267.                   break;

  1268.    /* added code, version 2.00   */

  1269.       case 'W':   searchdwcs = FALSE;     /* turn off DWC files   */
  1270.                   fprintf(stderr, notsearching, "DWC");
  1271.                   break;

  1272.    /* end added code */

  1273.    /* added code, version 2.10   */

  1274.       case 'J':   searcharjs = FALSE;
  1275.                   fprintf(stderr, notsearching, "ARJ");
  1276.                   break;

  1277.    /* end added code */

  1278.       case 'Z':   searchzips = FALSE;     /* turn off ZIP files   */
  1279.                   fprintf(stderr, notsearching, "ZIP");
  1280.                   break;

  1281.       case 'A':   searcharcs = FALSE;     /* turn off ARC files   */
  1282.                   fprintf(stderr, notsearching, "ARC");
  1283.                   break;

  1284.       case 'L':   searchlzhs = FALSE;
  1285.                   fprintf(stderr, notsearching, "LZH");
  1286.                   break;

  1287.       case 'P':   searchpaks = FALSE;
  1288.                   fprintf(stderr, notsearching, "PAK");
  1289.                   break;

  1290.       case 'V':   verbose = TRUE;
  1291.                   fputs("Verbose mode\n", stderr);
  1292.                   break;

  1293.       case 'D':   progress = TRUE;
  1294.                   fputs("Progress displays enabled\n", stderr);
  1295.                   break;

  1296.       case 'T':   totalsmode = TRUE;
  1297.                   fputs("Totals mode only\n", stderr);
  1298.                   break;

  1299.    /* added code, version 1.10   */

  1300.       case 'R':   alldrives = TRUE;
  1301.                   fputs("Search all drives\n", stderr);
  1302.                   break;

  1303.    /* end of added code          */

  1304.       default:    fprintf(stderr, "NJFIND: Unrecognized Option '%c'", *option);
  1305.       
  1306.    /* added code, version 2.00   */

  1307.                   if (inenvironment == TRUE)
  1308.                      fprintf(stderr, " in NJFIND environment variable");
  1309.                   fputc('\n', stderr);
  1310.                   fputc('\n', stderr);

  1311.    /* end added code */
  1312.                   showusage();
  1313.       }

  1314.    return;
  1315. }



  1316. /* --------------------------------------------------------------------------
  1317. */

  1318. void vBuildDOS6List(void)
  1319. {
  1320.    unsigned int   nMax;
  1321.    unsigned int   nTry;
  1322.    unsigned int   nOld;
  1323.    unsigned int   nCurrent;
  1324.    char           *pstrDest;
  1325.    unsigned int   far *uipNewWalker;

  1326.    union REGS     inregs;
  1327.    struct SREGS   segregs;

  1328.    pstrDest = drivelist;

  1329.    _dos_getdrive(&nOld);
  1330.    _dos_setdrive(nOld, &nMax);

  1331.    for (nTry = 1; nTry < nMaxnTry++)
  1332.       {
  1333.       _dos_setdrive(nTry, &nMax);
  1334.       _dos_getdrive(&nCurrent);

  1335.       if (nCurrent == nTry)
  1336.          {
  1337.          inregs.h.bl = (unsigned charnTry;
  1338.          inregs.x.ax = 0x4408;
  1339.          int86x(0x21, &inregs, &inregs, &segregs);

  1340.          if (inregs.x.ax == 0x0001)
  1341.             {
  1342.             inregs.h.ah = 0x1C;
  1343.             inregs.h.dl = (unsigned charnTry;
  1344.             int86x(0x21, &inregs, &inregs, &segregs);

  1345.             FP_OFF(uipNewWalker) = inregs.x.bx;
  1346.             FP_SEG(uipNewWalker) = segregs.ds;

  1347.             if ((*uipNewWalker & 0x00FF) == 0xF8)
  1348.                {
  1349.                *pstrDest++ = 'A' + nTry - 1;
  1350.                *pstrDest = '\0';
  1351.                }
  1352.             }
  1353.          }
  1354.       }

  1355.    _dos_setdrive(nOld, &nMax);

  1356.    return;
  1357. }


  1358. /* --------------------------------------------------------------------------
  1359.    builddrivelist() sets drivelist to an ASCII string of the drive
  1360.    letters that are valid on this system.  drivelist will only contain
  1361.    the identifiers of hard disk drives (with the media type 0xF8.)
  1362.    This function was added for Version 1.10.  This function was changed
  1363.    with Version 2.10 to accomodate DOS 5.0.
  1364. */

  1365. void builddrivelist()
  1366. {
  1367.    union REGS     inregs;
  1368.    struct SREGS   segregs;

  1369.    unsigned int   far *walker;
  1370.    unsigned int   far *newwalker;
  1371.    unsigned int   far *nextone_off;
  1372.    unsigned int   far *nextone_seg;
  1373.    char  far *media_type;
  1374.    char  *dest;

  1375.    if (_osmajor == 6)
  1376.       {
  1377.       vBuildDOS6List();
  1378.       return;
  1379.       }

  1380.    dest = drivelist;
  1381.    *dest = '\0';

  1382.    inregs.h.ah = 0x52;
  1383.    int86x(0x21, &inregs, &inregs, &segregs);

  1384.    FP_OFF(newwalker) = inregs.x.bx;
  1385.    FP_SEG(newwalker) = segregs.es;

  1386.    FP_OFF(walker) = newwalker[0];
  1387.    FP_SEG(walker) = newwalker[1];

  1388.    while(1)
  1389.       {
  1390.       switch (_osmajor)
  1391.          {
  1392.          case 2:
  1393.             media_type = (char far *) walker + 0x16;
  1394.             nextone_off = walker + 0x0C;
  1395.             nextone_seg = walker + 0x0D;
  1396.             break;

  1397.          case 3:
  1398.             media_type = (char far *) walker + 0x16;
  1399.             nextone_off = walker + 0x0C;
  1400.             nextone_seg = walker + 0x0D;
  1401.             break;

  1402.          case 4:
  1403.          case 5:
  1404.             media_type = (char far *) walker + 0x17;
  1405.             nextone_off = (unsigned int far *) ((char far *) walker + 0x19);
  1406.             nextone_seg = (unsigned int far *) ((char far *) walker + 0x1B);
  1407.             break;

  1408.          default:
  1409.             fprintf(stderr, "NJFIND: Incompatible DOS Version: %d.%d\n",
  1410.                _osmajor, _osminor);
  1411.             exit(1);
  1412.             break;
  1413.          }

  1414.       if ((*media_type & 0x00FF) == 0xF8)
  1415.          {
  1416.          *dest++ = (char) *walker + 'A';
  1417.          *dest = '\0';
  1418.          }

  1419.       FP_OFF(walker) = *nextone_off;
  1420.       FP_SEG(walker) = *nextone_seg;

  1421.       if (FP_OFF(walker) == 0xFFFF)
  1422.          break;

  1423.       if ((*walker & 0x00FF) > 26)
  1424.          break;
  1425.       }

  1426.    return;
  1427. }


  1428. /* --------------------------------------------------------------------------
  1429.    The breakout() function handles the SIGINT signal for the program.
  1430.    Here, we simply set a flag so that the working loop will terminate
  1431.    and return.  This allows us to leave neatly, by resetting the
  1432.    current drive and printing out our totals.  (That doesn't take very
  1433.    long and should not be much of an annoyance to the user.)
  1434. */

  1435. void  breakout(void)
  1436. {
  1437.    signal(SIGINT, SIG_IGN);
  1438.    signal(SIGINT, breakout);

  1439.    putchar('\n');
  1440.    broken = TRUE;

  1441.    return;
  1442. }


  1443. /* --------------------------------------------------------------------------
  1444.    handleenvironment() takes care of looking at the environment to
  1445.    find NJFIND settings.  If such an entry is found, it is parsed by
  1446.    running pointers through it and calling handleoption().

  1447.    This function is new for Version 2.00.
  1448. */

  1449. void handleenvironment()
  1450. {
  1451.    char *environment;
  1452.    char *walker;
  1453.    char *destination;
  1454.    char copy[10];
  1455.    int  len;

  1456.    environment = getenv("NJFIND");
  1457.    if (environment == NULL)
  1458.       return;

  1459. #if defined(DEBUG)
  1460.    printf("NJFIND found!\n");
  1461. #endif

  1462.    walker = environment;

  1463.    while (*walker != '\0')
  1464.       {
  1465.       while (isspace(*walker))
  1466.          {
  1467.          walker++;
  1468.          }

  1469.       if (*walker == '\0')
  1470.          break;

  1471.       destination = copy;
  1472.       len = 0;

  1473.       while (!isspace(*walker) && *walker != '\0')
  1474.          {
  1475.          *destination++ = *walker++;
  1476.          *destination = '\0';

  1477.          if (++len == ELEMENTS(copy))
  1478.             {
  1479.             fputs("NJFIND: option too long in environment\n", stderr);
  1480.             exit(1);
  1481.             }
  1482.          }

  1483.       if (copy[0] == '/' || copy[0] == '-')
  1484.          handleoption(copy+1, TRUE);
  1485.       else
  1486.          {
  1487.          fputs("NJFIND: only options supported in environment\n", stderr);
  1488.          exit(1);
  1489.          }

  1490.       }

  1491.    return;
  1492. }


  1493. /* --------------------------------------------------------------------------
  1494.    The Main Thang.
  1495. */

  1496. void main(int argcchar *argv[])
  1497. {
  1498.    int   argcounter;
  1499.    char  *userfilespec;

  1500.    signal(SIGINT, breakout);

  1501.    for (argcounter = 0; argcounter < 50; argcounter++)
  1502.       fiftyspaces[argcounter] = ' ';
  1503.    fiftyspaces[argcounter] = '\0';

  1504.    fputs("Nifty James' File Finder\n", stderr);
  1505.    fputs("Version 2.17/ASP of 22 March, 1993\n", stderr);
  1506.    fputs("(C) Copyright 1989-1993 by Mike Blaszczak\n\n", stderr);

  1507.    builddrivelist();

  1508.    if (argc < 2)
  1509.       {
  1510.       showusage();
  1511.       }

  1512.    userfilespec = NULL;
  1513.    for (argcounter = 1; argcounter<argcargcounter++)
  1514.       {
  1515.       if (argv[argcounter][0] == '/' || argv[argcounter][0] == '-')
  1516.          {
  1517.          handleoption(argv[argcounter]+1, FALSE);
  1518.          }
  1519.       else
  1520.          {
  1521.          if (userfilespec == NULL)
  1522.             {
  1523.             userfilespec = argv[argcounter];
  1524.             }
  1525.          else
  1526.             {
  1527.             fputs("Only one filespec allowed!\n\n", stderr);
  1528.             exit(1);
  1529.             }
  1530.          }
  1531.       }

  1532.    handleenvironment();

  1533.    /* moved from handleoption in version 2.00   */

  1534.    fputc('\n', stderr);

  1535.    /* end of moved code */

  1536.    _dos_getdrive(&olddrive);
  1537.    newdriveletter[0] = '\0';

  1538.    if (userfilespec == NULL)
  1539.       {
  1540.       userfilespec = "X:\\*.*";
  1541.       userfilespec[0] = (char) olddrive + 'A';
  1542.       drivelist[0] = userfilespec[0];
  1543.       drivelist[1] = '\0';
  1544.       }
  1545.    else
  1546.       if (alldrives == FALSE)
  1547.          {
  1548.          if (userfilespec[1] == ':')
  1549.             {
  1550.             *userfilespec = (char) toupper(*userfilespec);
  1551.             newdrive = (unsigned) (*userfilespec - 'A' +1);
  1552.             _dos_setdrive(newdrive, &drivecount);
  1553.             _dos_getdrive(&lastdrive);

  1554.             if (lastdrive != newdrive)
  1555.                {
  1556.                fprintf(stderr, "NJFIND: Invalid drive %c:.\n", *userfilespec);
  1557.                fprintf(stderr, "        Valid drives are A: to %c:\n",
  1558.                   drivelist[strlen(drivelist)-1]);
  1559.                exit(1);
  1560.                }
  1561.             else
  1562.                {
  1563.                changedrive = TRUE;
  1564.                drivelist[0] = *userfilespec;
  1565.                drivelist[1] = '\0';
  1566.                userfilespec += 2;
  1567.                }
  1568.             }
  1569.          else
  1570.             {
  1571.             drivelist[0] = (char) (olddrive + 'A' -1);
  1572.             drivelist[1] = '\0';
  1573.             }
  1574.          }
  1575.       else
  1576.          {
  1577.          changedrive = TRUE;
  1578.          if (userfilespec[1] == ':')
  1579.             userfilespec += 2;
  1580.          }

  1581.    inputfile = strupr(userfilespec);
  1582.    maketemplate();
  1583.    makefullname(&matchnametemplate);
  1584. #if defined(DEBUG)
  1585.    printf("template: %s\n"template);
  1586. #endif

  1587.    for (currentdrive = drivelist; *currentdrive != '\0';
  1588.             currentdrive++)
  1589.       {
  1590.       newdriveletter[0] = *currentdrive;
  1591.       newdriveletter[1] = ':';
  1592.       newdriveletter[2] = '\0';

  1593.       newdrive = (unsigned) (*currentdrive - 'A' +1);
  1594.       _dos_setdrive(newdrive, &drivecount);
  1595.       searchdir("\\*.*");
  1596.       }

  1597.    if (broken == TRUE)
  1598.       printf("\nNJFIND: Searching interrupted!\n\n");

  1599.    /* print out statistics */

  1600.    printf("\n   %5u file", found);
  1601.    if (found != 1)
  1602.       putchar('s');
  1603.    printf(" found.\n");
  1604.    printf("   %5u archived file", archivefound);
  1605.    if (archivefound != 1)
  1606.       putchar('s');
  1607.    printf(" found.\n");

  1608.    if (found != 0 && archivefound != 0)
  1609.       printf("   %5u files found in total.\n", found + archivefound);
  1610.    else
  1611.       putchar('\n');

  1612.    putchar('\n');
  1613.     
  1614.    if (totalsmode == TRUE || verbose == TRUE)
  1615.       {
  1616.       if (found != 0)
  1617.          printf("Found files total %lu bytes.\n"totallength);
  1618.       if (archivefound != 0)
  1619.          printf("Found archive files total %lu bytes.\n"archivetotallength);
  1620.       }

  1621.    if (changedrive == TRUE)
  1622.       _dos_setdrive(olddrive, &drivecount);

  1623.    exit(0);
  1624. }