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