home *** CD-ROM | disk | FTP | other *** search
/ Power-Programmierung / CD1.mdf / magazine / pcmagazi / 1991 / 08 / cdx / cdx.c < prev    next >
Text File  |  1991-03-15  |  30KB  |  847 lines

  1. /************************************************************************
  2.  *                                    *
  3.  *    CDX.C - Change Directory, Extended                *
  4.  *                                    *
  5.  *    By: Michael Holmes & Bob Flanders                *
  6.  *        Copyright (c) 1991, Ziff Communications Co.         *
  7.  *                                    *
  8.  *    This module has been tested to compile and work under        *
  9.  *        MSC 5.1 and 6.0                        *
  10.  *        TurboC 2.0                            *
  11.  *        Borland C++ 2.0                        *
  12.  *                                    *
  13.  *    Use the following commands to compile, based on compiler used:    *
  14.  *                                    *
  15.  *    Microsoft C 6.0:                        *
  16.  *        cl -AT -Gs -Os cdx.c /link /NOE                *
  17.  *                                    *
  18.  *    Microsoft C 5.1:                        *
  19.  *        cl -AS -D_MSC_VER=510 -Gs -Os cdx.c /link /NOE        *
  20.  *                                    *
  21.  *    Turbo C 2.0:                            *
  22.  *        tcc -mt -G -O -Z cdx.c                    *
  23.  *                                    *
  24.  *    Borland C++ 2.0:                        *
  25.  *        bcc -mt -lt -G -O -Z cdx.c                    *
  26.  *                                    *
  27.  ************************************************************************
  28.  *                                    *
  29.  *    Modification log:                        *
  30.  *    -----------------                        *
  31.  *                                    *
  32.  *    13/15/91 - Initial version completed. (rvf & mdh)        *
  33.  *                                    *
  34.  ************************************************************************/
  35.  
  36. /***********************************************************************
  37.  *     Common Includes for all compilers                   *
  38.  ***********************************************************************/
  39.  
  40. #include <dos.h>                /* compiler header files    */
  41. #include <stdlib.h>
  42. #include <string.h>
  43.  
  44. #define  QLEN    68                /* maximum len of question    */
  45.  
  46.  
  47.  
  48. /***********************************************************************
  49.  *    Microsoft C dependancies                       *
  50.  ***********************************************************************/
  51.  
  52. #if defined(_MSC_VER)                /* MSC specific definitions */
  53.  
  54. #pragma pack(1)                 /* pack structs/byte boundry*/
  55. #include <memory.h>                /* MSC header file needed    */
  56.  
  57. void _far *    _fmalloc(size_t);        /* far malloc function    */
  58. typedef struct find_t FindParms;        /* dos find block        */
  59.  
  60.  
  61.  
  62. /***********************************************************************
  63.  *    MSC 6.0 Dependancies                           *
  64.  ***********************************************************************/
  65.  
  66. #if    _MSC_VER >= 600                /* MSC 6 or greater     */
  67.  
  68. #define _FASTCALL _fastcall            /* MSC v6 quick calling    */
  69.  
  70. #else                        /* end of MSC 6 definitions */
  71.  
  72.  
  73. /***********************************************************************
  74.  *    MSC 5.1 Dependancies                           *
  75.  ***********************************************************************/
  76.  
  77. #define _FASTCALL                /* MSC 5 definitions    */
  78.  
  79. void _fstrcpy(char far *to, char far *from) /* _fstrcpy interface    */
  80.     {                        /* use memmove to move data */
  81.     movedata(FP_SEG(from), FP_OFF(from),
  82.          FP_SEG(to),   FP_OFF(to),     QLEN);
  83.     }
  84.  
  85. #endif                        /* end of MSC 5 definitions */
  86.  
  87.  
  88. /************************************************************************
  89.  *    nullcheck -- replace MSC's null pointer assignment routine      *
  90.  ************************************************************************/
  91.  
  92. int  _nullcheck()
  93. {
  94.  
  95. return(0);
  96.  
  97. }
  98.  
  99. /************************************************************************
  100.  *    setenvp -- replace MSC's set environment routine                *
  101.  ************************************************************************/
  102.  
  103. void _setenvp()
  104. {
  105.  
  106. return;
  107.  
  108. }
  109.  
  110.  
  111. /***********************************************************************
  112.  *    Turbo C & Borland C Dependancies                   *
  113.  ***********************************************************************/
  114.  
  115. #elif defined(__TURBOC__)            /* Turbo C definitions    */
  116.  
  117. #include <mem.h>                /* TC header files needed    */
  118. #include <dir.h>
  119. #include <alloc.h>
  120.  
  121. #define _FASTCALL                /* not supported: fastcall    */
  122. #define _far far                /* far definition        */
  123.  
  124. typedef struct ffblk FindParms;         /* find parameters    */
  125.  
  126. #define _dos_findfirst(path, attrib, block)    /* find first in dir    */ \
  127.     findfirst(path, block, attrib)
  128.  
  129. #define _dos_findnext(block)            /* find next in dir    */ \
  130.     findnext(block)
  131.  
  132. extern int directvideo = 0;            /* use bios routines    */
  133.  
  134. #define _A_NORMAL    0x0000            /* normal attribute    */
  135. #define _A_SUBDIR    FA_DIREC            /* directory attribute    */
  136.  
  137. #define _ffree         farfree            /* free call        */
  138. #define _fmalloc     farmalloc            /* far allocate call    */
  139. #define name         ff_name            /* name field in parms    */
  140. #define attrib         ff_attrib            /* file attributes field*/
  141.  
  142. void _dos_setdrive(int drive, int *drives)    /* dos setdrive     */
  143.     {
  144.     if(!drive)                    /* q. drive requested?    */
  145.     _DL = getdisk();            /* a. no .. get current */
  146.     else
  147.     _DL = drive-1;                /* else .. set up drive */
  148.     _AH = 0x0E;                 /* ah = drive to setup    */
  149.     geninterrupt(0x21);             /* set the drive    */
  150.     *drives = _AL;                /* .. return drive    */
  151.     }
  152.  
  153. void _dos_getdrive(int *drive)            /* get the curret disk    */
  154.     {
  155.     *drive = (getdisk()+1);            /* set drive to current */
  156.     }
  157.  
  158. void _getdcwd(int drive, char *buf, int len)    /* get current directory*/
  159.     {
  160.     len = len;                    /* use len        */
  161.     buf[0] = drive + ('A' - 1);                 /* store in drive       */
  162.     buf[1] = ':';                               /* ..and colon          */
  163.     buf[2] = '\\';                              /* ..and roots backslash*/
  164.     getcurdir(drive, &buf[3]);            /* ..and rest of path    */
  165.     }
  166.  
  167.  
  168. /***********************************************************************
  169.  *    Turbo C 2.0 dependancies                       *
  170.  ***********************************************************************/
  171.  
  172. #if (__TURBOC__ < 0x0297)
  173.  
  174. void _fstrcpy(char far *to, char far *from) /* _fstrcpy interface    */
  175.     {                        /* use memmove to move data */
  176.     movedata(FP_SEG(from), FP_OFF(from),
  177.          FP_SEG(to),   FP_OFF(to),     QLEN);
  178.     }
  179.  
  180. #endif
  181.  
  182.  
  183. #endif                        /* end of Borland def's     */
  184.  
  185.  
  186. /***********************************************************************
  187.  *    Common Definitions                           *
  188.  ***********************************************************************/
  189.  
  190. #define CHR(x)    x + 'A' - 1                 /* nbr to drive letter      */
  191. #define NOT    !                /* longhand for clarity    */
  192.  
  193. /***********************************************************************
  194.  *    Formal routine declarations                       *
  195.  ***********************************************************************/
  196.  
  197. void _FASTCALL srch_drv(int, char);        /* formal declarations    */
  198. void _FASTCALL cdxlook(char *, char *);
  199. int  _FASTCALL cdxdir(char *, int *, FindParms *);
  200. void           cdxhelp();
  201. void _FASTCALL cdxreq(char *);
  202. void           cdxask();
  203. void _FASTCALL cdxdisp(char *);
  204. void _FASTCALL cdxff(char *);
  205.  
  206. int  _FASTCALL drvrdy(char);
  207.  
  208. /***********************************************************************
  209.  *    global work areas                           *
  210.  ***********************************************************************/
  211.  
  212. int    level,                    /* current level        */
  213.     batch,                    /* /b switch encountered    */
  214.     f_parm,                 /* file parameter number    */
  215.     ac;                    /* argument count        */
  216.  
  217. enum    {
  218.     NOFF,                    /* no /F switch        */
  219.     FFSET,                    /* /F found, no * directory */
  220.     FFALL                    /* /F found, * dir found    */
  221.     } fsw;                    /* /f switch found        */
  222.  
  223. char    **av,                    /* argument list        */
  224.     *check_path,                /* path to check & not scan */
  225.     *file_wa;                /* work area for file name    */
  226.  
  227. FindParms ffb;                    /* file find block        */
  228.  
  229.  
  230. /***********************************************************************
  231.  *     request structure & pointers                       *
  232.  ***********************************************************************/
  233.  
  234. struct    req
  235.     {
  236.     struct req _far *nxtreq;            /* pointer to next request    */
  237.     char        reqdisp;            /* TRUE if already displayed*/
  238.     char        reqpath[QLEN];        /* path for request w/drive */
  239.     } _far *firstreq, _far *lastreq;        /* first & last pointers    */
  240.  
  241.  
  242. /***********************************************************************
  243.  *    main -- CDX  change directory, extended                *
  244.  ***********************************************************************/
  245.  
  246. void    main(int argc, char *argv[])
  247. {
  248. char    start_path[65],             /* starting path        */
  249.     drive_list[27],             /* list of drives to search */
  250.     *q, *p;                 /* work pointer        */
  251. int    start_drive,                /* starting drive        */
  252.     max_drive,                /* max number of drives    */
  253.     start_parm,                /* 1st arg to search for    */
  254.     floppies = 0,                /* search floppy drives    */
  255.     i, j;                    /* work counter        */
  256. static
  257. char    sn[3][3] = { "\\", ".", ".." },     /* special directory names  */
  258.     hdr[] = "CDX 1.0 -- Copyright (c) 1991 Ziff Communications Co.\r\n"
  259.         "PC Magazine ■ Michael Holmes and Bob Flanders\r\n";
  260.  
  261.  
  262. cputs(hdr);                    /* put out pgm banner    */
  263. ac = argc;                    /* make arg count global    */
  264.  
  265. if (ac == 1)                    /* q. need help?        */
  266.     cdxhelp();                    /* a. yes .. give it to 'em */
  267.  
  268. firstreq = (void _far *) 0;            /* zero first request    */
  269. lastreq  = (void _far *) 0;            /* ..and last request ptrs    */
  270.  
  271. check_path = malloc(65);            /* get memory for path    */
  272. file_wa = malloc(65);                /* get memory for file work */
  273.  
  274. /************************************************************************
  275.  *    rearrange paramters, /parms first                *
  276.  ************************************************************************/
  277.  
  278. av = (char **)malloc(sizeof(char *)*(ac+2));/* allocate arg ptrs    */
  279.  
  280. av[j = 0] = argv[0];                /* setup base pointer    */
  281.  
  282. for (i = j = 1; i <= ac; i++)            /* setup slash-parameters    */
  283.     {
  284.     strupr(argv[i]);                /* uppercase string     */
  285.  
  286.     if (argv[i][0] == '/')                  /* q. slash parameter?      */
  287.        {                    /* a. yes ..        */
  288.        av[j++] = argv[i];            /* .. move in the pointer    */
  289.  
  290.        if (argv[i][1] == 'F')               /* q. /F parameter?         */
  291.       av[j++] = argv[++i];            /* a. yes .. next too    */
  292.        }
  293.     }
  294.  
  295. for (i = 1; i <= ac; i++)            /* setup dir's, if any      */
  296.     {
  297.     if (argv[i][0] != '/')                  /* q. slash parameter?      */
  298.     av[j++] = argv[i];            /* a. no .. set dir parm    */
  299.  
  300.      else if (argv[i][1] == 'F')            /* q. /F parmater?          */
  301.     i++;                    /* a. yes .. skip next parm */
  302.     }
  303.  
  304. p = av[1];                    /* get pointer to 1st arg    */
  305.  
  306. _dos_getdrive(&start_drive);            /* ..then current drive    */
  307. _dos_setdrive(0, &max_drive);            /* get max nbr of drives    */
  308.  
  309. drive_list[0] = CHR(start_drive);        /* setup default drive list */
  310. drive_list[1] = 0;
  311.  
  312.  
  313. /************************************************************************
  314.  *    parse parameters                        *
  315.  ************************************************************************/
  316.  
  317. for (start_parm = 1; start_parm < ac;        /* for all arguments    */
  318.      start_parm++)
  319.     {
  320.     if (*av[start_parm] != '/')             /* q. slash paramter?       */
  321.     break;                    /* a. no .. exit now    */
  322.  
  323.     p = av[start_parm];             /* get pointer to string    */
  324.  
  325.     switch (*(++p))                /* switch character     */
  326.     {
  327.     case 'B':                           /* batch switch             */
  328.         batch = 1;                /* accept first found    */
  329.         break;                /* check next parameter    */
  330.  
  331.     case 'P':                           /* prompt switch            */
  332.         batch = 0;                /* accept first found    */
  333.         break;                /* check next parameter    */
  334.  
  335.     case 'F':                           /* find file parameter      */
  336.         if (++start_parm >= ac)        /* q. not enough parms?    */
  337.         cdxhelp();            /* a. yes .. get some help    */
  338.  
  339.         fsw = FFSET;            /* show /f encountered    */
  340.         f_parm = start_parm;        /* save parameter number    */
  341.         break;                /* check next parameter    */
  342.  
  343.     case '+':                           /* search floppies?         */
  344.         floppies = 1;            /* set the switch        */
  345.         break;                /* check next parm        */
  346.  
  347.     default:                /* error otherwise        */
  348.         cdxhelp();                /* give help & die        */
  349.     }
  350.     }
  351.  
  352. if (start_parm >= ac)                /* q. directories not given?*/
  353.     if (fsw)                    /* q. file switch given?    */
  354.     {
  355.     av[start_parm] = "*";               /* a. yes .. do all drives  */
  356.     ac++;                    /* bump up argument count    */
  357.     }
  358.  
  359.      else
  360.     cdxhelp();                /* else .. just give help    */
  361.  
  362. /************************************************************************
  363.  *    Build drive list                        *
  364.  ************************************************************************/
  365.  
  366. if (fsw && (*av[start_parm] == '*'))        /* q. need to check root?   */
  367.     fsw = FFALL;                /* a. yes .. set flag    */
  368.  
  369. if ((q=strchr(p=av[start_parm], ':')) != 0) /* q. drive list supplied?  */
  370.     {                        /* a. yes .. build list    */
  371.     *q = 0;                    /* .. and terminate string    */
  372.  
  373.     if (NOT strlen(av[start_parm] = ++q))   /* q. anything after drives?*/
  374.     if (++start_parm >= ac)         /* q. any other arguments?    */
  375.         {
  376.         av[start_parm] = "*";           /* a. no .. force any dir   */
  377.         ac++;
  378.         }
  379.  
  380.     strupr(q = p);                /* uppercase the list    */
  381.  
  382.     if ((*p == '*') ||                      /* q. look at all drives?   */
  383.     (*p == '-'))                        /* or exclude some drives?  */
  384.     {                    /* a. yes .. set up list    */
  385.     for (p = drive_list, i = 3;        /* setup the drive list    */
  386.          i <= max_drive; i++)
  387.         if (NOT strchr(q, CHR(i)))        /* q. in exclude list?    */
  388.         *p++ = CHR(i);            /* a. no .. add to list    */
  389.  
  390.     for (i = 1; (i<3) && floppies; i++) /* check if A: & B: are out */
  391.         if (NOT strchr(q, CHR(i)))        /* q. in exclude list?    */
  392.         *p++ = CHR(i);            /* a. no .. add to list    */
  393.  
  394.     *p = 0;                 /* terminate drv search list*/
  395.     }
  396.  
  397.     else
  398.     strcpy(drive_list, p);            /* else .. copy in drives    */
  399.     }
  400.  
  401. /************************************************************************
  402.  *    Check for "special" parameters \, .. (parent) and . (current)   *
  403.  ************************************************************************/
  404.  
  405. for (p = av[start_parm], i = 3; i--;)        /* check the special names    */
  406.     if (NOT strcmp(p, sn[i]) &&         /* q. is it a special arg.. */
  407.     (start_parm == (ac - 1)) )        /* .. and is the only parm    */
  408.     {
  409.     _dos_setdrive(drive_list[0] -        /* a. yes .. change drives    */
  410.                 ('A' - 1), &i);
  411.     chdir(p);                /* .. and directories ..    */
  412.     exit(0);                /* .. then exit        */
  413.     }
  414.  
  415. /************************************************************************
  416.  *    Start searching the requested drives                *
  417.  ************************************************************************/
  418.  
  419. cdxask();                    /* tell 'em we're looking.. */
  420.  
  421. for (p = drive_list; *p; p++)            /* loop thru drive list    */
  422.     srch_drv(start_parm, *p);            /* ..checking for the path    */
  423.  
  424. while (firstreq)                /* q. request active?    */
  425.     cdxask();                    /* a. yes .. check if ans'd */
  426.  
  427. /************************************************************************
  428.  *    If we get here, the path was not found.             *
  429.  ************************************************************************/
  430.  
  431. batch = 0;                    /* let this msg get out */
  432. cdxdisp("Requested path/file not found\n\r");   /* ..give error message */
  433. exit(1);                    /* ..then exit w/error    */
  434.  
  435. }
  436.  
  437.  
  438.  
  439. /***********************************************************************
  440.  *    srch_drv -- check a drive for a particular directory           *
  441.  ***********************************************************************/
  442.  
  443. void _FASTCALL srch_drv(int start_parm,     /* 1st directory entry    */
  444.             char drive)        /* drive to search        */
  445. {
  446. int    i;                    /* work drive nbr        */
  447. char    cur_path[65];                /* current path        */
  448. register
  449. char    *p, *q;                 /* work pointers        */
  450.  
  451.  
  452. if (drvrdy(drive))                /* q. is drive ready?    */
  453.     return;                    /* a. no .. exit now    */
  454.  
  455. drive -= ('A' - 1);                         /* setup drive as 1=A:      */
  456.  
  457. *check_path = 0;                /* clear check path     */
  458. _getdcwd(drive, cur_path, sizeof(cur_path));/* get current path     */
  459.  
  460. if (*(p = av[start_parm]) == '\\')          /* q. start from root?      */
  461.     {
  462.     cur_path[3] = 0;                /* a. yes .. chg to root    */
  463.     p++;                    /* ..and start past "\"     */
  464.  
  465.     if (strcmp(av[start_parm], "\\") == 0)  /* q. 1st parm bkslash?     */
  466.     p = av[++start_parm];            /* a. yes.. reset start    */
  467.     }
  468.  
  469. if (cur_path[strlen(cur_path)-1] != '\\')   /* q. end in "\"?           */
  470.     strcat(cur_path, "\\");                 /* a. no .. add one         */
  471.  
  472.  
  473. /************************************************************************
  474.  *    Look for the directory on requested drive            *
  475.  ************************************************************************/
  476.  
  477. for(;;)                     /* loop thru looking..    */
  478.     {
  479.     level = start_parm;             /* setup which arg is 1st    */
  480.     cdxlook(cur_path, p);            /* look for a directory    */
  481.     strcpy(check_path, cur_path);        /* save old path        */
  482.  
  483.     cur_path[strlen(cur_path) - 1] = 0;     /* trim off trailing "\"    */
  484.  
  485.     if ((q = strrchr(cur_path, '\\')) != 0) /* q. are we at the root?   */
  486.     *(q + 1) = 0;                /* a. no .. back up a subdir*/
  487.      else
  488.     break;                    /* else .. not found here    */
  489.     }
  490. }
  491.  
  492.  
  493.  
  494. /***********************************************************************
  495.  *    cdxlook -- look at a particular directory for target           *
  496.  ***********************************************************************/
  497.  
  498. void _FASTCALL cdxlook(char *wtl,        /* where to look        */
  499.                char *wtlf)        /* what to look for     */
  500. {
  501. int    i;                    /* flag variable        */
  502. register
  503. char   *wwtlf,                    /* working what to look for */
  504.        *p;                    /* string pointer        */
  505. FindParms *fb;                    /* find block pointer    */
  506.  
  507.  
  508. fb = (FindParms *)malloc(sizeof(FindParms));/* get a find block     */
  509. wwtlf = (char *)malloc(65);            /* ..and working string    */
  510.  
  511. if ((fsw == FFALL) && (strlen(wtl) == 3))   /* q. file switch set?    */
  512.     cdxff(wtl);                 /* a. yes .. check here    */
  513.  
  514. p = &wwtlf[strlen(wtl)];            /* save end of string ptr    */
  515. strcpy(wwtlf, wtl);                /* build what to look for.. */
  516. strcpy(p, wtlf);
  517. strcat(p, strchr(wtlf, '.') ? "*" : "*.*"); /* append appropriate wild  */
  518.  
  519. /************************************************************************
  520.  *    loop to reentrantly search for requested directory        *
  521.  ************************************************************************/
  522.  
  523. for (i = 0; cdxdir(wwtlf, &i, fb);)        /* look for dir's to search */
  524.     {
  525.     strcpy(p, fb->name);            /* copy in directory name    */
  526.     strcat(p, "\\");                        /* ..and the trailing "\"   */
  527.  
  528.     if (++level == ac)                /* q. at bottom level?    */
  529.     {                    /* a. yes .. test this dir    */
  530.     if (fsw != NOFF)            /* q. file switch set?    */
  531.         cdxff(wwtlf);            /* a. yes .. check for file */
  532.      else                    /* else ..            */
  533.         cdxreq(wwtlf);            /* .. build req for this dir*/
  534.     }
  535.  
  536.      else
  537.     cdxlook(wwtlf, av[level]);        /* else, look for next level*/
  538.  
  539.     level--;                    /* on failure.. go back 1    */
  540.     }
  541.  
  542. strcpy(p, "*.*");                           /* setup to look at any dirs*/
  543.  
  544. for (i = 0; cdxdir(wwtlf, &i, fb);)        /* look thru dir at this lvl*/
  545.     {
  546.     strcpy(p, fb->name);            /* bld nxt search recoursion*/
  547.     strcat(p, "\\");                        /* ..ending with a backslash*/
  548.  
  549.     if (strcmpi(check_path, wwtlf))        /* q. already do this dir?    */
  550.     cdxlook(wwtlf, wtlf);            /* a. no .. look down path    */
  551.     }
  552.  
  553. free(wwtlf);                    /* free gotten memory    */
  554. free(fb);                    /* . . . . .        */
  555.  
  556. }
  557.  
  558.  
  559.  
  560. /***********************************************************************
  561.  *    cdxdir -- find the next directory entry                *
  562.  ***********************************************************************/
  563.  
  564. int _FASTCALL cdxdir(char *wwtlf,        /* working what to look for */
  565.              int *l,            /* first/next flag        */
  566.              FindParms *fb)        /* find directory entry blk */
  567. {
  568.  
  569. /************************************************************************
  570.  *    look for directory entry using Find First & Find Next        *
  571.  ************************************************************************/
  572.  
  573. while((*l ? _dos_findnext(fb) :         /* q. find a file/directory?*/
  574.         _dos_findfirst(wwtlf, _A_SUBDIR, fb)) == 0)
  575.     {
  576.     *l = 1;                    /* a. yes .. set flag    */
  577.  
  578.  
  579.     if ((fb->attrib & _A_SUBDIR) &&        /* q. a sub-directory?    */
  580.     (fb->name[0] != '.'))               /* ..and not "." or ".."    */
  581.     return(1);                /* a. yes .. return a subdir*/
  582.  
  583.      else if (kbhit())                /* q. key hit?        */
  584.     cdxask();                /* a. yes .. check it out    */
  585.     }
  586.  
  587. return(*l = 0);                 /* return to caller, w/error*/
  588. }
  589.  
  590.  
  591.  
  592. /***********************************************************************
  593.  *    cdxreq -- build request structure                   *
  594.  ***********************************************************************/
  595.  
  596. void _FASTCALL cdxreq(char *msg)        /* allocate/build req    */
  597.  
  598. {
  599. register
  600. struct req _far *wr;                /* work req pointer     */
  601.  
  602. int    i;                    /* work variable        */
  603.  
  604.  
  605. while ((wr = _fmalloc((size_t)            /* q. memory allocate ok?    */
  606.            sizeof(struct req))) == 0)
  607.     cdxask();                    /* a. no .. wait for answer */
  608.  
  609. wr->reqdisp = 0;                /* show not displayed    */
  610. _fstrcpy(wr->reqpath, (char far *) msg);    /* .. copy in message    */
  611. wr->nxtreq = (void _far *) 0;            /* zero next pointer    */
  612.  
  613. if (firstreq)                    /* q. previous request?    */
  614.     lastreq->nxtreq = wr;            /* a. yes.. set prev's nxt  */
  615.  else
  616.     firstreq = wr;                /* else .. set up first req */
  617.  
  618. lastreq = wr;                    /* .. and set up new last    */
  619.  
  620. cdxask();                    /* let user see the prompt    */
  621. }
  622.  
  623.  
  624.  
  625. /***********************************************************************
  626.  *    cdxask -- display path & ask                       *
  627.  ***********************************************************************/
  628.  
  629. void cdxask()                    /* ask if this dir is it    */
  630. {
  631. char    ques[75],                /* question to ask        */
  632.     c;                    /* response character    */
  633. static
  634. int    looking = 0;                /* looking displayed    */
  635. register
  636. struct    req _far *wr;                /* work req pointer     */
  637. int    i;                    /* work variable        */
  638.  
  639. /************************************************************************
  640.  *    If any requests are present ...                 *
  641.  ************************************************************************/
  642.  
  643. if (firstreq)                    /* q. any request present?    */
  644.     {                        /* a. yes.. process it    */
  645.     if (NOT firstreq->reqdisp)            /* q. message displayed?    */
  646.     {                    /* a. no .. display it    */
  647.     _fstrcpy((char far *) ques,        /* .. copy in message    */
  648.         firstreq->reqpath);
  649.     strcat(ques, " ?");                 /* add a question mark      */
  650.  
  651.     cdxdisp(ques);                /* .. display the question    */
  652.  
  653.     firstreq->reqdisp = 1;            /* indicate req displayed    */
  654.     looking = 0;                /* show looking not disp'd  */
  655.     }
  656.  
  657.     if ((i = kbhit()) != 0)            /* q. any char yet?     */
  658.     c = getch();                /* a. yes .. get it     */
  659.  
  660.     if (i || batch)                /* q. char found or batch?    */
  661.     {
  662.     if ((toupper(c) == 'Y') || batch)   /* q. this the path?        */
  663.         {                    /* a. yes.. go to the path    */
  664.         _fstrcpy((char far *) ques,     /* move in the path     */
  665.            firstreq->reqpath);
  666.  
  667.         _dos_setdrive(*ques - ('A'-1), &i); /* set the drive        */
  668.  
  669.         if (strlen(ques) > 3)        /* q. root directory?    */
  670.         ques[strlen(ques) - 1] = 0; /* a. no .. remove last '\' */
  671.  
  672.         chdir(ques);            /* .. go to the path    */
  673.         exit(0);                /* .. and then to dos    */
  674.         }
  675.  
  676.      else                    /* else.. if response is no */
  677.         {                    /* free the request     */
  678.         wr = firstreq;            /* save pointer to current    */
  679.         firstreq = wr->nxtreq;        /* reset first pointer    */
  680.         _ffree(wr);             /* free the request     */
  681.  
  682.         cdxask();                /* display another entry ..*/
  683.         }
  684.     }
  685.     }
  686.  
  687. /************************************************************************
  688.  *    This is the first request ...                    *
  689.  ************************************************************************/
  690.  
  691.  else                        /* no requests are on queue */
  692.     {
  693.     while(kbhit())                /* clear other keys..    */
  694.     getch();                /* .. don't allow buffering */
  695.  
  696.     if (NOT looking)                /* q. looking displayed?    */
  697.     {                    /* a. no .. display it    */
  698.     cdxdisp("Searching ...");           /* display "men at work"    */
  699.  
  700.     looking = 1;                /* .. show we're displayed  */
  701.     }
  702.     }
  703. }
  704.  
  705.  
  706.  
  707. /***********************************************************************
  708.  *    cdxdisp -- display the requested value                   *
  709.  ***********************************************************************/
  710.  
  711. void    _FASTCALL cdxdisp(char *ques)        /* display the request    */
  712. {
  713. register
  714. int    i;                    /* work variable        */
  715. char    line[76];                /* work area        */
  716.  
  717.  
  718. if (batch)                    /* q. in batch mode?    */
  719.     return;                    /* a. yes .. don't display  */
  720.  
  721. line[0] = '\r';                             /* start with return        */
  722. for(i = 73; i--; line[i+1] = ' ');          /* blank out line           */
  723. line[74] = '\r';                            /* .. kill the string       */
  724. line[75] = 0;                    /* .. end the string    */
  725. cputs(line);                    /* .. clear question line    */
  726.  
  727. cputs(ques);                    /* display the question    */
  728. }
  729.  
  730.  
  731.  
  732. /***********************************************************************
  733.  *    cdxhelp -- give help message and die                   *
  734.  ***********************************************************************/
  735.  
  736. void    cdxhelp()
  737. {
  738.  
  739. cputs("\nformat  CDX  [/B] [/+] [/F file] [d:]p1 p2 .. pn\n\r\n"
  740.       "  where:\r\n"
  741.       "    /B       change to first qualifying directory\r\n"
  742.       "    /+       include floppies in * or - search\r\n"
  743.       "    /F file  find directory containing file\r\n"
  744.       "             file may contain wildcard ? or * characters\r\n"
  745.       "    d        are the drives to search\r\n"
  746.       "               *: searches all drives\r\n"
  747.       "               -ddd: searches all drives except ddd\r\n"
  748.       "               ddd:  searches only drives ddd\r\n"
  749.       "    p1..pn   are the names of directories to search\r\n\n");
  750.  
  751. exit(1);                    /* give help and rtn to DOS */
  752.  
  753. }
  754.  
  755.  
  756.  
  757. /***********************************************************************
  758.  *    cdxff -- check if /f file in this directory               *
  759.  ***********************************************************************/
  760.  
  761. void    _FASTCALL cdxff(char *s)
  762. {
  763. char    file_wa[65];                /* file name work area    */
  764.  
  765.  
  766. strcpy(file_wa, s);                /* a. yes .. copy in dir    */
  767. strcat(file_wa, av[f_parm]);            /* .. and file parameter    */
  768.  
  769. if (_dos_findfirst(file_wa,            /* q. file found?        */
  770.         _A_NORMAL, &ffb) == 0)
  771.     cdxreq(s);                    /* a. yes .. build request    */
  772.  
  773. }
  774.  
  775.  
  776.  
  777. /***********************************************************************
  778.  *    drvrdy -- check if drive is ready                   *
  779.  ***********************************************************************/
  780.  
  781. int    _FASTCALL drvrdy(char d)    /* returns true if drive Not rdy*/
  782. {
  783. struct    dos4_i25            /* dos 4.0 int 25 block     */
  784.     {
  785.     long sector;            /* sector to read        */
  786.     int  num_secs;            /* number of sectors to read    */
  787.     char far *read_addr;        /* address of input area    */
  788.     } d4_i25, far *d4_i25p;     /* area and pointer        */
  789. union    REGS r;             /* work registers        */
  790. struct    SREGS s;            /* ..and work segment regs    */
  791.  
  792.  
  793. char    _far *bootrec;            /* place to read boot sector    */
  794.  
  795. d -= 'A';                               /* d = 0 based drive number     */
  796.  
  797. /************************************************************************
  798.  *    DOS 3 or above, check for remote drive                *
  799.  ************************************************************************/
  800.  
  801. if (_osmajor >= 3)            /* q. at least DOS 3.00?    */
  802.     {                    /* a. yes ..            */
  803.     r.x.ax=0x4409;            /* ax = check remote status    */
  804.     r.h.bl = d + 1 ;            /* bl = number of drive     */
  805.     int86x(0x21, &r, &r, &s);        /* ask dos about drive        */
  806.  
  807.     if (r.x.dx & 0x1000)        /* q. is drive remote?        */
  808.     return(0);            /* a. yes .. assume ready    */
  809.     }
  810.  
  811. bootrec = _fmalloc((size_t) 4096);    /* get space for a sector    */
  812.  
  813. /************************************************************************
  814.  *    DOS 3.31 and above INT 25h (read sector) interface        *
  815.  ************************************************************************/
  816.  
  817. if (_osmajor > 3 || ((_osmajor == 3) &&     /* dos version 4 interface? */
  818.              (_osminor > 30)))
  819.     {                        /* a. yes.. use long read    */
  820.     r.x.cx = -1;                /* cx = 0xffff        */
  821.     d4_i25.sector = 0L;             /* read sector 0        */
  822.     d4_i25.num_secs = 1;            /* .. for 1 sector        */
  823.     d4_i25.read_addr = bootrec;         /* .. into boot record    */
  824.     d4_i25p = &d4_i25;                /* set up pointer        */
  825.     r.x.bx = FP_OFF(d4_i25p);            /* bx = offset of parm block*/
  826.     s.ds   = FP_SEG(d4_i25p);            /* ds = segment of block    */
  827.     }
  828.  
  829. /************************************************************************
  830.  *    pre-DOS 3.31 INT 25h (read sector) interface            *
  831.  ************************************************************************/
  832.  else
  833.     {
  834.     r.x.cx = 1;                 /* cx = number of sectors    */
  835.     r.x.dx = 0;                 /* dx = starting sector    */
  836.     r.x.bx = FP_OFF(bootrec);            /* bx = offset of buffer    */
  837.     s.ds   = FP_SEG(bootrec);            /* ds = segment of buffer    */
  838.     }
  839.  
  840. r.h.al = d;                    /* al = drive number    */
  841. int86x(0x25, &r, &r, &s);            /* read boot sector     */
  842.  
  843. _ffree(bootrec);                /* free the boot record    */
  844.  
  845. return(r.x.cflag);                /* return true if not ready */
  846. }
  847.