home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 6 File / 06-File.zip / os2ntree.zip / NTREE.C < prev    next >
Text File  |  1988-03-07  |  40KB  |  1,613 lines

  1. /* ***********************************************************************
  2.    **  NTREE - The search for a better tree program has ended        **
  3.    **  Version 2.4.0  [OS/2 and DOS versions]                **
  4.    **  A hack by Mitch Lichtenberg                    **
  5.    **  Modified for OS/2 by Lester Waters                **
  6.    **       Note that this cannot be a bimodal application [yet] since  **
  7.    **        the emulation of the directory handles doesn't work right   **
  8.    **       when doing lots of recursion (more than 2 levels deep).    **
  9.    **  Main module                    File: NTREE.C    **
  10.    *********************************************************************** */
  11.  
  12. /*  +-------------------------------------------------------------------+
  13.     |  Defines:                                |
  14.     |                                      |
  15.     |      OS2        - Builds version for use under OS/2.        |
  16.     |               If not defined, then DOS is assumed.        |
  17.     +-------------------------------------------------------------------+ */
  18.  
  19.  
  20. #include <stdio.h>
  21. #include <string.h>
  22. #include <signal.h>
  23. #include <errno.h>
  24.  
  25. #ifdef    OS2
  26. #include <error.h>
  27. extern int far pascal DOSFINDFIRST();
  28. extern int far pascal DOSFINDNEXT();
  29. extern int far pascal DOSFINDCLOSE();
  30. extern int far pascal DOSSETVERIFY();
  31. extern int far pascal DOSQVERIFY();
  32. extern int far pascal DOSSETFILEMODE();
  33. #endif
  34.  
  35. extern int    docopyfile();
  36. unsigned int    curdrive();
  37. unsigned int    clussize();
  38.  
  39.  
  40. /*  +-------------------------------------------------------------------+
  41.     |  Constants                            |
  42.     +-------------------------------------------------------------------+ */
  43.  
  44. #define switchp(x) ((*x) == '/')
  45.  
  46. #define FREADONLY 0x01
  47. #define FHIDDEN 0x02
  48. #define FSYSTEM 0x04
  49. #define FLABEL 0x08
  50. #define FDIRECTORY 0x10
  51. #define FARCHIVE 0x20
  52.  
  53. /*
  54.  * switch masks
  55.  */
  56. #define SFILES  0x0001
  57. #define SHIDDEN 0x0002
  58. #define SVERIFY 0x0004
  59. #define SQUERY  0x0008
  60. #define SDELETE 0x0010
  61. #define SARC    0x0020
  62. #define SUPDATE 0x0040
  63. #define SREALLY    0x0080
  64. #define SDATE   0x0100
  65. #define SOVER    0x0200
  66. #define SCALL    0x0400
  67. #define SCOPY   0x0800
  68. #define SDIR    0x1000
  69. #define STOTAL  0x2000
  70. #define SBAT    0x4000
  71. #define SINFO   0x8000
  72.  
  73. #define SQUIET  0x0001            /* sw. word 2 */
  74. #define SSILENT 0x0002            /* sw. word 2 */
  75. #define    SDEBUG    0x8000            /* sw. word 2 */
  76.  
  77. #ifndef    ERROR_ACCESS_DENIED
  78. #define    ERROR_ACCESS_DENIED    0x0005
  79. #endif
  80.  
  81. /*  +-------------------------------------------------------------------+
  82.     |  Structures                            |
  83.     +-------------------------------------------------------------------+ */
  84.  
  85. typedef unsigned char byte;
  86. typedef unsigned int word;
  87. typedef unsigned long dword;
  88.  
  89. typedef struct FileDate {
  90.     unsigned int second : 5;
  91.     unsigned int minute : 6;
  92.     unsigned int hour : 5;
  93.     unsigned int day : 5;
  94.     unsigned int month : 4;
  95.     unsigned int year : 7;
  96.     } FILEDATE;
  97.  
  98. typedef struct cons {
  99.     char *str;
  100.     int num;
  101.     } CONS;
  102.  
  103. typedef struct btree {
  104.     char *name;        /* name of node */
  105.     char *subname;        /* name of just this file */
  106.     struct btree *child;    /* children */
  107.     struct btree *sibling;    /* brothers */
  108.     } BTREE;
  109.  
  110. #ifdef    OS2
  111. typedef struct FileName {
  112.     FILEDATE fd;            /* this is an OS/2 type DTA */
  113.     unsigned int adate;
  114.     unsigned int atime;
  115.     unsigned int wdate;
  116.     unsigned int wtime;
  117.     unsigned long filesize;
  118.     unsigned long filealloc;
  119.     unsigned int attribute;
  120.     unsigned char namelen;
  121.     unsigned char name[64];
  122.     } FILENAME;
  123.     
  124. #else
  125. typedef struct FileName {        /* this is a DTA for DOS */
  126.     char reserved[21];
  127.     byte attribute;
  128.     FILEDATE fd;
  129.     dword filesize;
  130.     char name[14];
  131.     } FILENAME;
  132. #endif
  133.  
  134.  
  135. /*  +-------------------------------------------------------------------+
  136.     |  global variables                            |
  137.     +-------------------------------------------------------------------+ */
  138.  
  139. FILENAME workname;
  140.  
  141. #ifndef    OS2
  142. FILENAME    *dossetdta();
  143. #endif
  144.  
  145. int oldverify = 0;
  146.  
  147. int fncount = 0;
  148.  
  149. unsigned int dircount;
  150. unsigned int filecount;
  151.  
  152. unsigned long total;
  153. unsigned long clus;
  154. unsigned long fclus;
  155. unsigned long allocunit;
  156.  
  157. char inwildcard[20];
  158. char infnam[64];
  159. char outfnam[64];
  160. char ncallstr[64];
  161. char dbcallstr[64];
  162. char dacallstr[64];
  163. char rawoutfnam[64];
  164.  
  165. int inlen,outlen;
  166.  
  167. char temp[64];
  168. char temp2[64];
  169.  
  170. word switches = 0;
  171. word switches2 = 0;
  172.  
  173. word verbose = 1;        /* 1 means write to stdout */
  174. word showerr = 1;        /* 1 means write to stderr */
  175.  
  176. #ifdef    OS2
  177. char *version = "NTREE version 2.4 [OS/2 version]\n";
  178. #else
  179. char *version = "NTREE version 2.4 [DOS version]\n";
  180. #endif
  181.  
  182. CONS switchnames[] = {
  183.     {"A",SFILES},        /* enumerate all files */
  184.     {"H",SHIDDEN},        /* hidden too */
  185.     {"V",SVERIFY},        /* turn on verify */
  186.     {"Q",SQUERY},        /* query mode on */
  187.     {"D",SDELETE},        /* delete tree */
  188.     {"ARC",SARC},        /* use ARC to save tree */
  189.     {"U",SUPDATE},        /* update (don't do files already done) */
  190.     {"YES",SREALLY},    /* don't ask for confirmation */
  191.     {"DATE",SDATE},        /* copy only if source has later date */
  192.     {"O",SOVER},        /* overwrite dest */
  193.     {"C",SCOPY},        /* needed for copy op */
  194.     {"DIR",SDIR},        /* display <DIR> for directories*/
  195.     {"T",STOTAL},        /* total space */
  196.     {"BAT",SBAT},        /* don't do system commands just echo */
  197.     {"I",SINFO},        /* file info too */
  198.     {NULL,NULL}};
  199.  
  200. CONS switchnames2[] = {
  201.     {"QUIET",SQUIET},    /* don't write to stdout */
  202.     {"SILENT",SSILENT},    /* don't write anywhere */
  203.     {"DEBUG", SDEBUG},    /* enable debugging messages */
  204.     {NULL,NULL}};
  205.  
  206. extern unsigned int errno;
  207.  
  208. /*  +-------------------------------------------------------------------+
  209.     |  main(argc,argv)                            |
  210.     |  the beginning of the world                    |
  211.     +-------------------------------------------------------------------+ */
  212. main(argc,argv)
  213. int argc;
  214. char *argv[];
  215. {
  216.     int a,b;
  217.     char *x,*y;
  218.     BTREE *t;
  219.     BTREE *maketree();
  220.     int inthndlr();
  221.  
  222.  
  223.     fprintf(stderr,version);
  224.  
  225.     if (argc < 2) usage();
  226.  
  227.     strcpy(ncallstr,"");
  228.     strcpy(dacallstr,"");
  229.     strcpy(dbcallstr,"");
  230.  
  231.     a = 1;
  232.     argv++;
  233.     while (a < argc) {
  234.         if (strcmpi(*argv,"/CALL") == 0) {
  235.             a++; argv++;
  236.             strcpy(ncallstr,*argv);
  237.             switches |= SCALL | SFILES;
  238.             a++; argv++;
  239.             continue;
  240.             }
  241.         if (strcmpi(*argv,"/BEFORE") == 0) {
  242.             a++; argv++;
  243.             strcpy(dbcallstr,*argv);
  244.             switches |= SCALL;
  245.             a++; argv++;
  246.             continue;
  247.             }
  248.         if (strcmpi(*argv,"/AFTER") == 0) {
  249.             a++; argv++;
  250.             strcpy(dacallstr,*argv);
  251.             switches |= SCALL;
  252.             a++; argv++;
  253.             continue;
  254.             }
  255.         if (switchp(*argv)) setswitches(*argv);
  256.         else switch (fncount) {
  257.             case 0: strcpy(infnam,*argv); fncount++; break;
  258.             case 1: strcpy(outfnam,*argv); fncount++; break;
  259.             case 2: fatalerr("Incorrect number of parameters");
  260.             }
  261.         a++; argv++;
  262.         }
  263.  
  264.     /* now, process input file name into wildcard */
  265.     strcpy(inwildcard,"*.*");    /* default */
  266.  
  267.     strupr(infnam);
  268.     if (!strchr(infnam,'\\')) {
  269.         if (infnam[1] == ':') {
  270.             getdir(infnam[0]-'@',temp);
  271.             strcpy(temp2,infnam+2);
  272.             pathize(temp,temp2,infnam);
  273.             }
  274.         else {
  275.             getcwd(temp,80);
  276.             strcpy(temp2,infnam);
  277.             pathize(temp,temp2,infnam);
  278.             }
  279.         }
  280.             
  281.  
  282.     x = strchr(infnam,'?');
  283.     y = strchr(infnam,'*');        /* find first of either of these */
  284.     if (x > y) y = x;
  285.     if (y) {
  286.         while (y >= infnam) {
  287.             if (*y == '\\') break;
  288.             if (*y == ':') break;
  289.             y--;
  290.             }
  291.         y++;            /* now y points to start of wildcard */
  292.  
  293.         x = strtok(y,"/");
  294.         if (y != infnam) strcpy(inwildcard,x);
  295.         *y = '\0';                /* zap end of string */
  296.         y = strtok(NULL,"");            /* get rest of switches */
  297.         }
  298.     else {
  299.         if (x = strchr(infnam,'/')) {
  300.             *x = '\0';
  301.             y = x+1;
  302.             }
  303.         }
  304.  
  305.     if (y) {
  306.         sprintf(temp,"/%s",y);
  307.         setswitches(temp);
  308.         }
  309.  
  310.  
  311.     x = strchr(outfnam,'?');
  312.     y = strchr(outfnam,'*');    /* find first of either of these */
  313.     if (x && y && (x > y)) y = x;
  314.     if (x && !y) y = x;
  315.     if (y) {
  316.          while (y >= outfnam) {
  317.             if (*y == '\\') break;
  318.             if (*y == ':') break;
  319.             y--;
  320.             }
  321.         y++;            /* now y points to start of wildcard */
  322.  
  323.         y = strtok(y,"/");    /* get switches */
  324.         *y = '\0';
  325.         y = strtok(NULL,"");            /* get rest of switches */
  326.         }
  327.     else {
  328.         if (x = strchr(outfnam,'/')) {
  329.             *x = '\0';
  330.             y = x+1;
  331.             }
  332.         }
  333.  
  334.     if (y) {
  335.         sprintf(temp,"/%s",y);
  336.         setswitches(temp);
  337.         }
  338.  
  339.     if ((strlen(infnam) == 2) && (infnam[1] == ':')) {
  340.         strupr(infnam);
  341.         getdir((*infnam) - '@',infnam);
  342.         }
  343.     if ((strlen(outfnam) == 2) && (outfnam[1] == ':')) {
  344.         strupr(outfnam);
  345.         getdir((*outfnam) - '@',outfnam);
  346.         }
  347.  
  348.     y = infnam+strlen(infnam)-1; if (*y != '\\') strcat(infnam,"\\");
  349.     y = outfnam+strlen(outfnam)-1; if (*y != '\\') strcat(outfnam,"\\");
  350.  
  351.     if (strcmp(infnam,".\\") == 0) {
  352.         getdir(curdrive(),infnam);
  353.         strcat(infnam,"\\");
  354.         }
  355.     if (strcmp(outfnam,".\\") == 0) {
  356.         getdir(curdrive(),outfnam);
  357.         strcat(outfnam,"\\");
  358.         }
  359.  
  360.  
  361.     strcpy(rawoutfnam,outfnam);
  362.     rmslash(rawoutfnam);
  363.  
  364.     if (switches2 & SDEBUG)
  365.           {    printf("Before fixup():\n");
  366.         printf("Input filename: %s\n",infnam);
  367.         printf("output filename: %s\n",outfnam);
  368.         };
  369.  
  370.     fixup(infnam);        /* add current drive & dir */
  371.     fixup(outfnam);
  372.  
  373.     inlen = strlen(infnam);
  374.     outlen = strlen(outfnam);
  375.  
  376.     if (switches2 & SDEBUG)
  377.           {    printf("After fixup():\n");
  378.         printf("Input filename: %s\n",infnam);
  379.         printf("output filename: %s\n",outfnam);
  380.         printf("wildcard string: %s\n",inwildcard);
  381.         printf("switch masks:  %04X  %04X\n",switches, switches2);
  382.         };
  383.  
  384.     signal(SIGINT,inthndlr);
  385.  
  386. #ifdef    OS2
  387.     DOSQVERIFY((int far *) &oldverify);
  388.     if (switches & SVERIFY) DOSSETVERIFY(1);
  389. #else
  390.     oldverify = getverify();
  391.     if (switches & SVERIFY) setverify(1);
  392. #endif
  393.  
  394.     /* switch implicants */
  395.  
  396.     if (switches & SDELETE) switches |= SFILES;
  397.     if (switches & SCOPY) switches |= SFILES;
  398.     if (switches & STOTAL) switches |= SFILES;
  399.     if (switches & SINFO) switches |= SFILES;
  400.     if (switches & SDATE) switches |= SOVER;
  401.  
  402.  
  403.     b = (switches & (SCOPY | SDELETE | SARC | STOTAL | SCALL));
  404.     a = 0;
  405.     while (b) {
  406.         if (b & 1) a++;
  407.         b >>= 1;
  408.         }
  409.     if (a > 1) fatalerr("Cannot do more than one command at a time");
  410.  
  411.     if (switches2 & SQUIET) verbose = 0;
  412.     if (switches2 & SSILENT) verbose = showerr = 0;
  413.  
  414.     if (switches & SCOPY) tcopy();
  415.     else if (switches & SDELETE) tdelete();
  416.     else if (switches & SARC) tarchive();
  417.     else if (switches & STOTAL) ttotal();
  418.     else if (switches & SCALL) tcall();
  419.     else tdisplay();
  420.  
  421.  
  422. }
  423.  
  424.  
  425. /*  +-------------------------------------------------------------------+
  426.     |  setswitches(cp)                            |
  427.     |  sets switches from string ptr                    |
  428.     +-------------------------------------------------------------------+ */
  429. setswitches(cp)
  430. char *cp;
  431. {
  432.     static char *brk = "/";
  433.     char *tok;
  434.     int a;
  435.  
  436.     tok = strtok(cp,brk);
  437.     while (tok) {
  438.         a = assoc(tok,switchnames);
  439.         if (a == 0) {
  440.             a = assoc(tok,switchnames2);
  441.             if (a == 0) fatalerr("Unrecognized switch: %s",tok);
  442.             else switches2 |= a;
  443.             }
  444.         else switches |= a;
  445.         tok = strtok(NULL,brk);
  446.         }
  447. }
  448.  
  449.  
  450. /*  +-------------------------------------------------------------------+
  451.     |  fixup(string)                            |
  452.     |  Fixes up dir/path spec to be fully formed            |
  453.     +-------------------------------------------------------------------+ */
  454. fixup(str)
  455. char *str;
  456. {
  457.     char nstr[70];
  458.     char buf[70];
  459.  
  460.     strupr(str);
  461.     if (*str == '\\') {        /* just add directory */
  462.         sprintf(nstr,"%c:%s",curdrive()+'@',str);
  463.         strcpy(str,nstr);
  464.         return;
  465.         }
  466.     if ((*(str+1) == ':') && (*(str+2) != '\\')) { /* add directory */
  467.         getdir((*str) - '@',buf);
  468.         sprintf(nstr,"%c:\\%s\\%s",*str,buf+3,str+2);
  469.         strcpy(str,nstr);
  470.         return;
  471.         }
  472.     if ((*(str+1) != ':') && (*str != '\\')) { /* add drive & dir */
  473.         getdir(curdrive(),buf);
  474.         sprintf(nstr,"%c:\\%s\\%s",curdrive()+'@',buf+3,str);
  475.         strcpy(str,nstr);
  476.         return;
  477.         }
  478. }
  479.  
  480. /*  +-------------------------------------------------------------------+
  481.     |  fatalerr(a,b,c,d,e)                        |
  482.     |  die with fatal error                        |
  483.     +-------------------------------------------------------------------+ */
  484. fatalerr(a,b,c,d,e)
  485. unsigned char    *a, *b, *c, *d, *e;
  486. {
  487.     fprintf(stderr,"ntree: ");
  488.     fprintf(stderr,a,b,c,d,e);
  489.     fprintf(stderr,"\n");
  490.     exit(1);
  491. }
  492.  
  493.  
  494. /*  +-------------------------------------------------------------------+
  495.     |  printerr(a,b,c,d,e)                        |
  496.     |  print an error message                        |
  497.     +-------------------------------------------------------------------+ */
  498. printerr(a,b,c,d,e)
  499. unsigned char    *a, *b, *c, *d, *e;
  500. {
  501.     fprintf(stderr,"ntree: ");
  502.     fprintf(stderr,a,b,c,d,e);
  503.     fprintf(stderr,"\n");
  504. }
  505.  
  506.  
  507. /*  +-------------------------------------------------------------------+
  508.     |  assoc(str,lst)                            |
  509.     |  finds string in list                        |
  510.     +-------------------------------------------------------------------+ */
  511. assoc(str,lst)
  512. char *str;
  513. CONS *lst;
  514. {
  515.     while (lst->str) {
  516.         if (strcmpi(lst->str,str) == 0) return lst->num;
  517.         lst++;
  518.         }
  519.     return 0;
  520. }
  521.  
  522.  
  523. /*  +-------------------------------------------------------------------+
  524.     |  dotree(path)                            |
  525.     |  returns BTREE starting at path                    |
  526.     +-------------------------------------------------------------------+ */
  527. BTREE *dotree(path)
  528. char *path;
  529. {
  530.     BTREE *node = NULL;
  531.     BTREE *list = NULL;
  532.     FILENAME fns;
  533.     char npath[64];            /* path with wildcard */
  534.     char rpath[64];            /* recursive call path */
  535.     static char *stars = "*.*";
  536.     int status;
  537.     int attrib = FDIRECTORY;
  538. #ifdef    OS2
  539.     FILENAME far *fnsptr = &fns;
  540.     unsigned int handle = 0xFFFF;
  541.     int number = 1;
  542. #endif
  543.  
  544. #ifndef    OS2
  545.     dossetdta(&fns);
  546. #endif
  547.     strcpy(npath,path);
  548.     strcat(npath,stars);
  549.  
  550.     if (switches & SHIDDEN) attrib |= FHIDDEN;
  551.  
  552. #ifdef    OS2
  553.     status = DOSFINDFIRST((char far *) npath,
  554.                 (int far *) &handle,
  555.                 FDIRECTORY,
  556.                 fnsptr,
  557.                 sizeof(struct FileName),
  558.                 (int far *) &number,
  559.                 0L);
  560. #else
  561.     status = dosfindfirst(npath, FDIRECTORY);
  562. #endif
  563.  
  564.  
  565.     while (status == 0) {
  566.         if ((fns.attribute & FDIRECTORY) &&
  567.             (fns.name[0] != '.')) {    /* add to tree */
  568.             node = (BTREE *) calloc(1,sizeof(BTREE));
  569.             node->sibling = list;
  570.             list = node;
  571.             strcpy(rpath,path);
  572.             strcat(rpath,fns.name);
  573.             strcat(rpath,"\\");
  574.             node->subname = strdup(fns.name);
  575.             node->name = strdup(rpath);
  576.             node->child = dotree(rpath);
  577.             }
  578. #ifdef    OS2
  579.         status = DOSFINDNEXT(    handle,
  580.                 fnsptr,
  581.                 sizeof(struct FileName),
  582.                 (int far *) &number);
  583.         if (status == ERROR_INVALID_HANDLE)
  584.               {    printf("ntree: Invalid handle %u in DOSFINDNEXT()\n",
  585.                 handle);
  586.             exit(1);
  587.             };
  588. #else
  589.         dossetdta(&fns);
  590.         status = dosfindnext();
  591. #endif
  592.         }
  593.  
  594. #ifdef    OS2
  595.     DOSFINDCLOSE(handle);
  596. #endif
  597.     return list;
  598. }
  599.  
  600.  
  601.  
  602. /*  +-------------------------------------------------------------------+
  603.     |  maketree(path)                            |
  604.     |  Returns btree for path, including starting dir            |
  605.     +-------------------------------------------------------------------+ */
  606. BTREE *maketree(path)
  607. char *path;
  608. {
  609.     BTREE *btree;
  610.     int flg = 0;
  611.  
  612.     btree = (BTREE *) calloc(1,sizeof(BTREE));
  613.     btree->name = strdup(path);
  614.     btree->sibling = NULL;
  615.     btree->child = dotree(path);
  616.     return btree;
  617. }
  618.  
  619.  
  620. /*  +-------------------------------------------------------------------+
  621.     |  rmslash(str)                            |
  622.     |  removes last char of string if it is a backslash            |
  623.     +-------------------------------------------------------------------+ */
  624. rmslash(str)
  625. char *str;
  626. {
  627.     int len;
  628.  
  629.     len = strlen(str);
  630.     if ((len == 3) && (str[1] == ':') && (str[2] == '\\')) return;
  631.     if (len == 0) return;
  632.     len--;
  633.     if (str[len] == '\\') str[len] = '\0';
  634. }
  635.  
  636.  
  637. /*  +-------------------------------------------------------------------+
  638.     |  pathize(dir,name,path)                        |
  639.     |  makes a good pathname                        |
  640.     +-------------------------------------------------------------------+ */
  641. pathize(dir,name,path)
  642. char *dir;
  643. char *name;
  644. char *path;
  645. {
  646.     int len;
  647.  
  648.     strcpy(path,dir);
  649.     len = strlen(path);
  650.     if (len && (path[len-1] == '\\')) path[len-1] = '\0';
  651.     if (*name != '\\') strcat(path,"\\");
  652.     strcat(path,name);
  653. }
  654.  
  655.  
  656. /*  +-------------------------------------------------------------------+
  657.     |  fexist(name,attrib)                        |
  658.     |  test for file exist (returns attrib if yes            |
  659.     +-------------------------------------------------------------------+ */
  660. fexist(name,attrib)
  661. char *name;
  662. int attrib;
  663. {
  664.     int status;
  665.     int handle = 0x0001;
  666.     int number = 0x0001;
  667. #ifndef    OS2
  668.     FILENAME    *olddta;
  669. #endif
  670.  
  671. #ifdef    OS2
  672.     status = DOSFINDFIRST((char far *) name,
  673.                 (int far *) &handle,
  674.                 attrib,
  675.                 (FILENAME far *) &workname,
  676.                 sizeof(struct FileName),
  677.                 (int far *) &number,
  678.                 0L);
  679. #else
  680.     olddta = dossetdta(&workname);
  681.     status = dosfindfirst(name, attrib);
  682. #endif
  683.  
  684.     if (status == 0) return (workname.attribute | 0x8000);
  685.  
  686.     return 0;
  687. }
  688.  
  689.  
  690.  
  691. /*  +-------------------------------------------------------------------+
  692.     |  subtreep(a,b)                            |
  693.     |  returns 1 if a and b are subtrees of one another            |
  694.     +-------------------------------------------------------------------+ */
  695. subtreep(a,b)
  696. char *a,*b;
  697. {
  698.     if (strncmp(a,b,strlen(a)) == 0) return 1;
  699.     if (strncmp(a,b,strlen(b)) == 0) return 1;
  700.     return 0;
  701. }
  702.  
  703.  
  704. /*  +-------------------------------------------------------------------+
  705.     |  rootdirp(str)                            |
  706.     |  returns 1 if str describes a root directory            |
  707.     +-------------------------------------------------------------------+ */
  708. rootdirp(str)
  709. char *str;
  710. {
  711.     if (strcmp(str+1,":\\") == 0) return 1;
  712.     if (strcmp(str,"\\") == 0) return 1;
  713.     return 0;
  714. }
  715.  
  716.  
  717.  
  718. /*  +-------------------------------------------------------------------+
  719.     |  printdir(t,fnam)                            |
  720.     |  prints a dir file name                        |
  721.     +-------------------------------------------------------------------+ */
  722. printdir(t,fnam)
  723. BTREE *t;
  724. char *fnam;
  725. {
  726.     char newname[64];
  727.  
  728.     strcpy(newname,fnam);
  729.     rmslash(newname);
  730.     if (switches & SDIR) printf("%s\t<DIR>\n",newname);
  731.     else if (!(switches & SFILES)) printf("%s\n",newname);
  732.  
  733.     if (switches & SINFO) dircount++;
  734. }
  735.  
  736.  
  737. /*  +-------------------------------------------------------------------+
  738.     |  printname(t,str,fns)                        |
  739.     |  prints filename                            |
  740.     +-------------------------------------------------------------------+ */
  741. printname(t,str,fns)
  742. BTREE *t;
  743. char *str;
  744. FILENAME *fns;
  745. {
  746.     char fooname[64];
  747.  
  748.     strcpy(fooname,str);
  749.     rmslash(fooname);
  750.     if (switches & SINFO) {
  751.         filecount++;
  752.         total += fns->filesize;
  753.         clus += fns->filesize / allocunit;
  754.         fclus += fns->filesize / 512L;
  755.  
  756.         if ((fns->filesize % allocunit) != 0) clus++;
  757.         if ((fns->filesize % 512L) != 0) fclus++;
  758.  
  759.         printf("%-50.50s %8lu  %02d-%02d-%02d %02d:%02d\n",
  760.             str,fns->filesize,fns->fd.month+1,fns->fd.day,
  761.             fns->fd.year+1980,fns->fd.hour,fns->fd.minute);
  762.         }
  763.     else {
  764.         puts(fooname);
  765.         }
  766.  
  767. }
  768.  
  769.  
  770. /*  +-------------------------------------------------------------------+
  771.     |  enumfiles(path,t,fn)                        |
  772.     |  enumerate all files on path                    |
  773.     +-------------------------------------------------------------------+ */
  774. enumfiles(path,t,fn)
  775. char *path;
  776. BTREE *t;
  777. int (*fn)();
  778. {
  779.     FILENAME    fns;
  780.     int status;
  781.     int attrib = 0;
  782.     char npath[64];
  783.     char nfile[64];
  784. #ifdef    OS2
  785.     FILENAME far *fnsptr = &fns;
  786.     unsigned int    handle = 0xFFFF;
  787.     unsigned int number = 1;
  788. #endif
  789.  
  790.     strcpy(npath,path);
  791.     strcat(npath,inwildcard);
  792.     
  793.     if (switches & SHIDDEN) attrib |= FHIDDEN;
  794.  
  795. #ifdef    OS2
  796.     status = DOSFINDFIRST((char far *) npath,
  797.                 (int far *) &handle,
  798.                 attrib,
  799.                 fnsptr,
  800.                 sizeof(struct FileName),
  801.                 (int far *) &number,
  802.                 0L);
  803. #else
  804.     dossetdta(&fns);
  805.     status = dosfindfirst(npath, attrib);
  806. #endif
  807.  
  808.     while (status == 0) {
  809.         strcpy(nfile,path);
  810.         strcat(nfile,fns.name);
  811.         if (fns.name[0] != '.') if (fn) (*fn)(t,nfile,&fns);
  812. #ifdef    OS2
  813.         status = DOSFINDNEXT(    handle,
  814.                 fnsptr,
  815.                 sizeof(struct FileName),
  816.                 (int far *) &number);
  817. #else
  818.         dossetdta(&fns);
  819.         status = dosfindnext();
  820. #endif
  821.         }
  822. }
  823.  
  824.  
  825.  
  826. /*  +-------------------------------------------------------------------+
  827.     |  maptree(tree,prefn,postfn,namefn)                |
  828.     |  map out contents of b-tree                    |
  829.     +-------------------------------------------------------------------+ */
  830. maptree(tree,prefn,postfn,namefn)
  831. BTREE *tree;
  832. int (*prefn)();
  833. int (*postfn)();
  834. int (*namefn)();
  835. {
  836.     int i;
  837.  
  838.     if (!tree) return;
  839.  
  840.     while (tree) {
  841.         if (prefn) (*prefn)(tree,tree->name);
  842.         if (switches & SFILES) {
  843.             enumfiles(tree->name,tree,namefn);
  844.             }
  845.         if (tree->child) maptree(tree->child,prefn,postfn,namefn);
  846.         if (postfn) (*postfn)(tree,tree->name);
  847.         tree = tree->sibling;
  848.         }
  849. }
  850.  
  851.  
  852. /*  +-------------------------------------------------------------------+
  853.     |  zapdir(name)                            |
  854.     |  delete directory                            |
  855.     +-------------------------------------------------------------------+ */
  856. zapdir(t,name)
  857. BTREE *t;
  858. char *name;
  859. {
  860.     char newname[64];
  861.  
  862.     strcpy(newname,name);
  863.     rmslash(newname);
  864.     if (rootdirp(name)) return;        /* don't delete root dir */
  865.     if (verbose) printf("Deleting directory: %s\n",newname);
  866.     if (rmdir(newname) != 0) {
  867.         if (showerr) fprintf(stderr,"Could not delete directory: %s\n",newname);
  868.         }
  869. }
  870.  
  871.  
  872. /*  +-------------------------------------------------------------------+
  873.     |  zapfile(t,name,fns)                        |
  874.     |  delete file                            |
  875.     +-------------------------------------------------------------------+ */
  876. zapfile(t,name,fns)
  877. BTREE *t;
  878. char *name;
  879. FILENAME *fns;
  880. {
  881.     if (!doquery("Delete file %s? (Y/N/A/Q): ",name)) return;
  882.     if (verbose) printf("Deleting file: %s\n",name);
  883.     if (unlink(name) != 0) {
  884.         if (showerr) fprintf(stderr,"Could not delete file: %s\n",name);
  885.         }
  886. }
  887.  
  888.  
  889. /*  +-------------------------------------------------------------------+
  890.     |  copydir(t,name)                            |
  891.     |  copy directory (prefn)                        |
  892.     +-------------------------------------------------------------------+ */
  893. copydir(t,name)
  894. BTREE *t;
  895. char *name;
  896. {
  897.     char newdir[64];
  898.  
  899.     strcpy(newdir,outfnam);
  900.     strcat(newdir,name+inlen);
  901.     if (rootdirp(newdir)) return;
  902.     rmslash(newdir);
  903.     if (fexist(newdir,FDIRECTORY)) {
  904. #ifdef PAUL_DOESNT_LIKE_THIS
  905.         printf("Directory already exists: %s\n",newdir);
  906. #endif
  907.         return;
  908.         }
  909.     if (verbose) printf("Creating directory: %s\n",newdir);
  910.     if (mkdir(newdir) != 0) {
  911.         if (errno != EACCES) fatalerr("Could not create directory: %s\n",newdir);
  912. #ifdef PAUL_DOESNT_LIKE_THIS
  913.         else printf("Directory already exists: %s\n",newdir);
  914. #endif
  915.         }
  916.  
  917. }
  918.  
  919.  
  920. /*  +-------------------------------------------------------------------+
  921.     |  copyfile(t,name,fns)                        |
  922.     |  namefn for copy file                        |
  923.     +-------------------------------------------------------------------+ */
  924. copyfile(t,name,fns)
  925. BTREE *t;
  926. char *name;
  927. FILENAME *fns;
  928. {
  929.     char newname[64];
  930.     int attr;
  931.     int newatt;
  932.  
  933.  
  934.     if (switches & SUPDATE) {
  935.         if (!(fns->attribute & FARCHIVE)) return;
  936. #ifdef    OS2
  937.         DOSSETFILEMODE(    (char far *) name,
  938.                 fns->attribute & ~FARCHIVE,
  939.                 0L);
  940. #else
  941.         doschmod(name,fns->attribute & ~FARCHIVE);
  942. #endif
  943.         newatt = fns->attribute & ~FARCHIVE;
  944.         }
  945.     else newatt = fns->attribute;
  946.  
  947.     strcpy(newname,outfnam);
  948.     strcat(newname,name+inlen);
  949.  
  950.     attr = fexist(newname,0);
  951.  
  952.     if (switches & SDATE) {
  953.         if (cmpdate(&(fns->fd),&(workname.fd)) != 1) return;
  954.         }
  955.  
  956.     if (!doquery("Copy file %s? (Y/N/A/Q): ",name)) return;
  957.  
  958.     if (attr && (!(switches & SOVER))) {
  959.         if (verbose) printf("File already exists: %s\n",newname);
  960.         return;
  961.         }
  962.     if (attr & FREADONLY) {
  963.         if (verbose) printf("File is read-only: %s\n",newname);
  964.         return;
  965.         }
  966.  
  967.     if (verbose) printf("Copying %s to %s\n",name,newname);
  968.  
  969.     switch (docopyfile(name,newname))
  970.           {    case 0: break;
  971.         case 1:    {
  972.             if (errno = ERROR_ACCESS_DENIED)
  973.                 printerr("access to source file %s denied",name);
  974.             else
  975.                 fatalerr("could not open source file: %s",name);
  976.             }
  977.         case 2: {
  978.             if (errno = ERROR_ACCESS_DENIED)
  979.                 printerr("access to output file %s denied",newname);
  980.             else
  981.                 fatalerr("could not open destination file: %s",newname);
  982.             }
  983.         case 3: fatalerr("could not read source file: %s",name);
  984.         case 4: fatalerr("could not write destination file: %s",newname);
  985.         case 5: fatalerr("could not allocate memory for copy");
  986.         }
  987.  
  988. #ifdef    OS2
  989.     DOSSETFILEMODE(    (char far *) newname,
  990.             newatt,
  991.             0L);
  992. #else
  993.     doschmod(newname,newatt);
  994. #endif
  995. }
  996.  
  997. /*  +-------------------------------------------------------------------+
  998.     |  totaldir(t,name)                            |
  999.     |  totals directories                        |
  1000.     +-------------------------------------------------------------------+ */
  1001. totaldir(t,name)
  1002. BTREE *t;
  1003. char *name;
  1004. {
  1005.     dircount++;
  1006. }
  1007.  
  1008. /*  +-------------------------------------------------------------------+
  1009.     |  totalfile(t,name,fns)                        |
  1010.     |  totals all files                            |
  1011.     +-------------------------------------------------------------------+ */
  1012. totalfile(t,name,fns)
  1013. BTREE *t;
  1014. char *name;
  1015. FILENAME *fns;
  1016. {
  1017.     filecount++;
  1018.     total += fns->filesize;
  1019.     clus += fns->filesize / allocunit;
  1020.     fclus += fns->filesize / 512L;
  1021.  
  1022.     if ((fns->filesize % allocunit) != 0) clus++;
  1023.     if ((fns->filesize % 512L) != 0) fclus++;
  1024. }
  1025.  
  1026.  
  1027.  
  1028.  
  1029.  
  1030. /*  +-------------------------------------------------------------------+
  1031.     |  arcdir(name)                            |
  1032.     |  archive directory                        |
  1033.     +-------------------------------------------------------------------+ */
  1034. arcdir(t,name)
  1035. BTREE *t;
  1036. char *name;
  1037. {
  1038.     char olddir[64];
  1039.     char arcname[64];
  1040.     char cmd[128];
  1041.     char *x;
  1042.     char *y;
  1043.     int cancel = 0;
  1044.  
  1045.     getcwd(olddir,64);        /* get current drive/dir */
  1046.     strcpy(arcname,name);        /* temp */
  1047.     rmslash(arcname);
  1048.     changedir(arcname);        /* change to this new dir */
  1049.     if (verbose) printf("Now working on directory: %s\n",arcname);
  1050.  
  1051.     if (strcmp(infnam,name) == 0) strcpy(arcname,rawoutfnam); /* reached end */
  1052.     else {
  1053.         sprintf(arcname,"..\\%s.ARC",t->subname);
  1054.         }
  1055.  
  1056.     if (!cancel) {
  1057.         if (fexist(arcname,0)) {
  1058.             if (verbose) printf("Deleting old archive %s\n",arcname);
  1059.             unlink(arcname);
  1060.             }
  1061.         sprintf(cmd,"arc a %s %s *.arc",arcname,inwildcard);
  1062.         if (verbose) {
  1063.             fputs(cmd,stdout);
  1064.             fputc('\n',stdout);
  1065.             }
  1066.         system(cmd);
  1067.         }
  1068.  
  1069.     changedir(olddir);
  1070. }
  1071.     
  1072.  
  1073.  
  1074.  
  1075. /*  +-------------------------------------------------------------------+
  1076.     |  tdisplay()                            |
  1077.     |  Display tree using given switches                |
  1078.     +-------------------------------------------------------------------+ */
  1079. tdisplay()
  1080. {
  1081.     BTREE *t;
  1082.  
  1083.     if (fncount == 0) fatalerr("pathname missing for tree display");
  1084.     if (fncount != 1) fatalerr("incorrect number of pathnames");
  1085.  
  1086.     t = maketree(infnam);        /* at least this one */
  1087.  
  1088.     allocunit = (unsigned long) clussize((*infnam) - '@');
  1089.     total = 0L;
  1090.     clus = 0L;
  1091.     fclus = 0L;
  1092.     dircount = 0;
  1093.     filecount = 0;
  1094.  
  1095.     maptree(t,printdir,NULL,printname);
  1096.  
  1097.     if (switches & SINFO) sayinfo();
  1098. }
  1099.  
  1100.  
  1101.  
  1102. /*  +-------------------------------------------------------------------+
  1103.     |  tdelete()                            |
  1104.     |  delete all entries in tree                    |
  1105.     +-------------------------------------------------------------------+ */
  1106. tdelete()
  1107. {
  1108.     BTREE *t;
  1109.     char line[40];
  1110.  
  1111.     if (!(switches & SREALLY)) {
  1112.         fprintf(stderr,"Are you sure you want to delete %s%s? [NO]: ",
  1113.             infnam,inwildcard);
  1114.         while (1) {
  1115.             *line = '\0';
  1116.             gets(line);
  1117.             strupr(line);
  1118.             if (strcmp(line,"YES") == 0) break;
  1119.             if (strlen(line) == 0) fatalerr("abort");
  1120.             if (strcmp(line,"NO") == 0) fatalerr("abort");
  1121.             fprintf(stderr,"\nYou must type YES to delete the tree\nAre you sure? [NO]:");
  1122.             }
  1123.         }
  1124.  
  1125.     t = maketree(infnam);
  1126.  
  1127.     maptree(t,NULL,zapdir,zapfile);
  1128. }
  1129.  
  1130.  
  1131. /*  +-------------------------------------------------------------------+
  1132.     |  tarchive()                            |
  1133.     |  archive all tree entries                        |
  1134.     +-------------------------------------------------------------------+ */
  1135. tarchive()
  1136. {
  1137.     BTREE *t;
  1138.  
  1139.     if (fncount != 2) usage();
  1140.  
  1141.     t = maketree(infnam);
  1142.  
  1143.     maptree(t,NULL,arcdir,NULL);
  1144.  
  1145. }
  1146.  
  1147. /*  +-------------------------------------------------------------------+
  1148.     |  tcopy()                                |
  1149.     |  copy all entries in tree                        |
  1150.     +-------------------------------------------------------------------+ */
  1151. tcopy()
  1152. {
  1153.     BTREE *t;
  1154.  
  1155.     if (fncount != 2) {
  1156.         fprintf(stderr,"must supply two pathnames");
  1157.         usage();
  1158.         }
  1159.  
  1160.     if (subtreep(infnam,outfnam)) fatalerr("Trees are not disjoint: %s, %s\n",infnam,outfnam);
  1161.  
  1162.     t = maketree(infnam);
  1163.  
  1164.     maptree(t,copydir,NULL,copyfile);
  1165.  
  1166. }
  1167.  
  1168.  
  1169.  
  1170. /*  +-------------------------------------------------------------------+
  1171.     |  ttotal()                                |
  1172.     |  totals all space in tree                        |
  1173.     +-------------------------------------------------------------------+ */
  1174. ttotal()
  1175. {
  1176.     BTREE *t;
  1177.  
  1178.     if (fncount != 1) usage();
  1179.  
  1180.     t = maketree(infnam);
  1181.  
  1182.     allocunit = (unsigned long) clussize((*infnam) - '@');
  1183.     total = 0L;
  1184.     clus = 0L;
  1185.     fclus = 0L;
  1186.     dircount = 0;
  1187.     filecount = 0;
  1188.  
  1189.     maptree(t,totaldir,NULL,totalfile);
  1190.  
  1191.     sayinfo();
  1192. }
  1193.  
  1194.  
  1195. /*  +-------------------------------------------------------------------+
  1196.     |  sayinfo()                            |
  1197.     |  prints out drive info                        |
  1198.     +-------------------------------------------------------------------+ */
  1199.  
  1200. sayinfo()
  1201. {
  1202.     printf("Tree %s%s contains %d files in %d directories,\n",
  1203.         infnam,inwildcard,filecount,dircount);
  1204.     printf("%lu bytes (%luK)\n",total,(unsigned long) (total / 1024L));
  1205.     printf("%lu clusters for drive %c:  (%luK)\n",
  1206.         clus,*infnam,(unsigned long) (clus * allocunit)/1024L);
  1207.     printf("%lu clusters for floppy drive:  (%luK)\n",
  1208.         fclus,(unsigned long) (fclus * 512L)/1024L);
  1209.  
  1210. }
  1211.  
  1212. /*  +-------------------------------------------------------------------+
  1213.     |  mexpand(template,buf,dirname,fns)                |
  1214.     |  macroexpand                             |
  1215.     +-------------------------------------------------------------------+ */
  1216. mexpand(template,buf,dirname,fns)
  1217. char *template;
  1218. char *buf;
  1219. char *dirname;
  1220. FILENAME *fns;
  1221. {
  1222.     char *cp;
  1223.  
  1224.     cp = template;
  1225.  
  1226.     while (*cp) {
  1227.         if (*cp != '$') {
  1228.             *buf = *cp;
  1229.             cp++; buf++;
  1230.             continue;
  1231.             }
  1232.         cp++;
  1233.         if (!*cp) break;
  1234.         switch (*cp++) {
  1235.             case '$': *buf++ = '$'; break;
  1236.             case 's':
  1237.             case 'S': strcpy(buf,dirname);
  1238.                   buf += strlen(dirname);
  1239.                   break;
  1240.             case 'd':
  1241.             case 'D':
  1242.                   strcpy(buf,outfnam);
  1243.                   strcat(buf,dirname+inlen);
  1244.                   buf += strlen(buf);
  1245.                   break;
  1246.             case 'b':
  1247.             case 'B':
  1248.                   if (fns) {
  1249.                     sprintf(buf,"%lu",fns->filesize);
  1250.                     buf += strlen(buf);
  1251.                     }
  1252.                   break;
  1253.             case 'g':
  1254.             case 'G': *buf++ = '>'; break;
  1255.             case 'l':
  1256.             case 'L': *buf++ = '<'; break;
  1257.             case 'p':
  1258.             case 'P': *buf++ = '|'; break;
  1259.             case 'q':
  1260.             case 'Q': *buf++ = '"'; break;
  1261.             case 'f':
  1262.             case 'F':
  1263.                   if (fns) {
  1264.                 strcpy(buf,fns->name);
  1265.                 buf += strlen(buf);
  1266.                     }
  1267.                   break;
  1268.             case 'c':
  1269.             case 'C': getcwd(buf,80);
  1270.                   buf += strlen(buf);
  1271.                   break;
  1272.         
  1273.             default:
  1274.                   *buf++ = '$';
  1275.                   *buf++ = *(cp-1);
  1276.                   break;
  1277.             }
  1278.         }
  1279.     *buf = '\0';
  1280. }
  1281.  
  1282.  
  1283.  
  1284. /*  +-------------------------------------------------------------------+
  1285.     |  bcalldir(t,name)                            |
  1286.     |  do call with before directory string                |
  1287.     +-------------------------------------------------------------------+ */
  1288. bcalldir(t,name)
  1289. BTREE *t;
  1290. char *name;
  1291. {
  1292.     char newname[64];
  1293.     char cmd[128];
  1294.  
  1295.     if (strlen(dbcallstr) == 0) return;
  1296.  
  1297.     strcpy(newname,name);
  1298.     rmslash(newname);
  1299.  
  1300.     mexpand(dbcallstr,cmd,newname,NULL);
  1301.  
  1302.     if (switches & SBAT) {
  1303.         fputs(cmd,stdout);
  1304.         fputc('\n',stdout);
  1305.         }
  1306.     else {
  1307.         if (verbose) {
  1308.             fputs(cmd,stderr);
  1309.             fputc('\n',stderr);
  1310.             }
  1311.         system(cmd); 
  1312.         }
  1313.  
  1314. }
  1315.  
  1316. /*  +-------------------------------------------------------------------+
  1317.     |  acalldir(t,name)                            |
  1318.     |  do call after directory string                    |
  1319.     +-------------------------------------------------------------------+ */
  1320. acalldir(t,name)
  1321. BTREE *t;
  1322. char *name;
  1323. {
  1324.     char newname[64];
  1325.     char cmd[128];
  1326.  
  1327.     if (strlen(dacallstr) == 0) return;
  1328.  
  1329.     strcpy(newname,name);
  1330.     rmslash(newname);
  1331.  
  1332.     mexpand(dacallstr,cmd,newname,NULL);
  1333.  
  1334.     if (switches & SBAT) {
  1335.         fputs(cmd,stdout);
  1336.         fputc('\n',stdout);
  1337.         }
  1338.     else {
  1339.         if (verbose) {
  1340.             fputs(cmd,stderr);
  1341.             fputc('\n',stderr);
  1342.             }
  1343.         system(cmd); 
  1344.         }
  1345. }
  1346.  
  1347.  
  1348. /*  +-------------------------------------------------------------------+
  1349.     |  callfile(t,name,fns)                        |
  1350.     |  do call after directory string                    |
  1351.     +-------------------------------------------------------------------+ */
  1352. callfile(t,name,fns)
  1353. BTREE *t;
  1354. char *name;
  1355. FILENAME *fns;
  1356. {
  1357.     char cmd[128];
  1358.  
  1359.     if (strlen(ncallstr) == 0) return;
  1360.  
  1361.     mexpand(ncallstr,cmd,name,fns);
  1362.  
  1363.     if (switches & SBAT) {
  1364.         fputs(cmd,stdout);
  1365.         fputc('\n',stdout);
  1366.         }
  1367.     else {
  1368.         if (verbose) {
  1369.             fputs(cmd,stderr);
  1370.             fputc('\n',stderr);
  1371.             }
  1372.         system(cmd); 
  1373.         }
  1374. }
  1375.  
  1376.  
  1377.  
  1378.  
  1379. /*  +-------------------------------------------------------------------+
  1380.     |  tcall()                                |
  1381.     |  call function in tree                        |
  1382.     +-------------------------------------------------------------------+ */
  1383. tcall()
  1384. {
  1385.     BTREE *t;
  1386.  
  1387.     t = maketree(infnam);
  1388.  
  1389.     maptree(t,bcalldir,acalldir,callfile);
  1390. }
  1391.  
  1392.  
  1393. /*  +-------------------------------------------------------------------+
  1394.     |  inthndlr()                            |
  1395.     |  handles ctrl-break interrupt                    |
  1396.     +-------------------------------------------------------------------+ */
  1397. inthndlr()
  1398. {
  1399. #ifdef    OS2
  1400.     DOSSETVERIFY(oldverify);
  1401. #else
  1402.     setverify(oldverify);
  1403. #endif
  1404.     fatalerr("interrupted via Ctrl-Break");
  1405. }
  1406.  
  1407.  
  1408. /*  +-------------------------------------------------------------------+
  1409.     |  doquery(ques,file)                        |
  1410.     |  does query, returns 1 if YES, 0 if no                |
  1411.     +-------------------------------------------------------------------+ */
  1412. doquery(ques,file)
  1413. char *ques;
  1414. char *file;
  1415. {
  1416.     if (!(switches & SQUERY)) return 1;
  1417.  
  1418.     printf(ques,file);
  1419.     while (1) {
  1420.         switch (getchar()) {
  1421.             case 'y':
  1422.             case 'Y': printf("YES\n"); return 1;
  1423.             case 'n':
  1424.             case 'N': printf("NO\n"); return 0;
  1425.             case 'q':
  1426.             case 'Q': printf("QUIT\n");
  1427. #ifdef    OS2
  1428.                   DOSSETVERIFY(oldverify);
  1429. #else
  1430.                   setverify(oldverify);
  1431. #endif
  1432.                   fatalerr("exit");
  1433.             case 'a':
  1434.             case 'A': printf("ALL\n");
  1435.                   switches &= ~SQUERY;
  1436.                   return 1;
  1437.             default: break;
  1438.             }
  1439.         }
  1440. }
  1441.  
  1442.  
  1443. /*  +-------------------------------------------------------------------+
  1444.     |  usage()                                |
  1445.     |  does ntree usage                            |
  1446.     +-------------------------------------------------------------------+ */
  1447. usage()
  1448. {
  1449.     fprintf(stderr,"Usage: ntree {/sw/sw..} path1{wildcard}{/sw/sw..} {path2{/sw/sw..}} \"call\"");
  1450.     fprintf(stderr,"\n");
  1451.     fprintf(stderr,"\tntree/C path1{wild} path2        Copy tree\n");
  1452.     fprintf(stderr,"\tntree/D path1{wild}              Delete tree\n");
  1453.     fprintf(stderr,"\tntree/ARC path1{wild} arcname    Archive via ARC\n");
  1454.     fprintf(stderr,"\tntree/T path1{wild}              Total space used\n");
  1455.     fprintf(stderr,"\tntree path1{wild}                Directory display\n");
  1456.     fprintf(stderr,"\tntree path1{wild} path2 /call \"macro\" /before \"macro\" /after \"macro\"\n");
  1457.     fprintf(stderr,"\tmacros: $s=source, $d=dest, $g=>, $l=<, $p=|, $c=current dir\n");
  1458.     fprintf(stderr,"\t        $f=filename, $b=filesize, $$=$, $q=\"\n");
  1459.     fprintf(stderr,"\n\tSwitches:\n");
  1460.     fprintf(stderr,"\t   /A    Enumerate files and directories\n");
  1461.     fprintf(stderr,"\t   /H    Include hidden files\n");
  1462.     fprintf(stderr,"\t   /V    Set verify switch ON\n");
  1463.     fprintf(stderr,"\t   /U    (for copy) Copy files with archive bit on\n");
  1464.     fprintf(stderr,"\t   /DATE (for copy) Copy files with later date\n");
  1465.     fprintf(stderr,"\t   /O    (for copy) Copy files and overwrite destination\n");
  1466.     fprintf(stderr,"\t   /Q    (copy/del) Query before copy or delete\n");
  1467.     fprintf(stderr,"\t   /YES  (copy/del) Don't ask any questions..just do it\n");
  1468.     fprintf(stderr,"\t   /DIR  (display)  Display <DIR> for directories\n");
  1469.     fprintf(stderr,"\t   /BAT  (call) Don't do commands, just echo to stdout\n");
  1470.     fprintf(stderr,"\t   /QUIET   Don't write informative messages to stdout\n");
  1471.     fprintf(stderr,"\t   /SILENT  Don't write messages or errors anywhere!\n");
  1472.     exit(1);
  1473. }
  1474.  
  1475.  
  1476. /*  +-------------------------------------------------------------------+
  1477.     |  cmpdate(d1,d2)                            |
  1478.     |  compares two filedates                        |
  1479.     +-------------------------------------------------------------------+ */
  1480. int cmpdate(d1,d2)
  1481. FILEDATE *d1;
  1482. FILEDATE *d2;
  1483. {
  1484.     if (d1->year > d2->year) return 1;
  1485.     if (d1->year < d2->year) return -1;
  1486.     if (d1->month > d2->month) return 1;
  1487.     if (d1->month < d2->month) return -1;
  1488.     if (d1->day > d2->day) return 1;
  1489.     if (d1->day < d2->day) return -1;
  1490.     if (d1->hour > d2->hour) return 1;
  1491.     if (d1->hour < d2->hour) return -1;
  1492.     if (d1->second > d2->second) return 1;
  1493.     if (d1->second < d2->second) return -1;
  1494.     return 0;
  1495. }
  1496.  
  1497.  
  1498. #ifdef    OS2
  1499. /*
  1500.    +-------------------------------------------------------------------------+
  1501.    |  curdrive()                                 |
  1502.    |  Return the current drive (1=A, 2=B, 3=C, etc.)                 |
  1503.    +-------------------------------------------------------------------------+
  1504. */
  1505. unsigned int curdrive()
  1506. {
  1507.     extern int far pascal DOSQCURDISK();
  1508.     unsigned int    drivenumber;
  1509.     unsigned long    drivemap;
  1510.     unsigned int    result;
  1511.  
  1512.     result = DOSQCURDISK(    (int far *) &drivenumber,
  1513.                 (long far *) &drivemap);
  1514.  
  1515.     return ( result ? 0xFFFF : drivenumber);
  1516. }
  1517. #endif
  1518.  
  1519. #ifdef    OS2
  1520. /*
  1521.    +-------------------------------------------------------------------------+
  1522.    |  getdir(drive,buf)                                 |
  1523.    |  Get the current directory for the specified drive and place it         |
  1524.    |  into buf.  Note that the drive letter and colon are preappended to     |
  1525.    |  the contents of buf.  'drive' is an integer with a meaning as         |
  1526.    |  follows: 0 = default drive; 1 = A; 2 = B; 3 = C; etc.             |
  1527.    +-------------------------------------------------------------------------+
  1528. */
  1529. int getdir(drive, buf)
  1530. unsigned int    drive;
  1531. unsigned char    *buf;
  1532. {
  1533.     extern int far pascal DOSQCURDIR();    
  1534.     int    buflen = 64;    /* assume buffer is at least 64 bytes long */
  1535.     int    result;
  1536.  
  1537.     sprintf(buf, "%c:\\", drive+64);
  1538.     result = DOSQCURDIR(    drive,
  1539.                 (char far *) (buf+3),
  1540.                 (int far *) &buflen);
  1541.     return result;
  1542. }
  1543. #endif
  1544.  
  1545. #ifdef    OS2
  1546. /*
  1547.    +-------------------------------------------------------------------------+
  1548.    |  changedir(dir)                                 |
  1549.    |  Change the current drive and directory.                     |
  1550.    +-------------------------------------------------------------------------+
  1551. */
  1552. int changedir(dir)
  1553. unsigned char    *dir;
  1554. {
  1555.     extern int far pascal DOSCHDIR();
  1556.     extern int far pascal DOSSELECTDISK();
  1557.     int    result;
  1558.  
  1559.     result = DOSCHDIR((char far *) dir, 0L);
  1560.  
  1561.     /* now check and see if a drive letter was specified */
  1562.     if ((dir[1] == ':') && (result == 0))
  1563.         result = DOSSELECTDISK(dir[0] - '@');
  1564.  
  1565.     return result;
  1566. }
  1567. #endif
  1568.  
  1569. #ifdef    OS2
  1570. /*
  1571.    +-------------------------------------------------------------------------+
  1572.    |  clussize(drive)                                 |
  1573.    |  Return the clustersize for the specified drive.  The 'drive'         |
  1574.    |  paramater is 0 for the default, 1=A, 2=B, 3=C, etc.             |
  1575.    +-------------------------------------------------------------------------+
  1576. */
  1577. unsigned int clussize(drive)
  1578. unsigned int    drive;
  1579. {
  1580.     extern int far pascal DOSQFSINFO();
  1581.     struct FSinfo {
  1582.         unsigned long    filesystemid;
  1583.         unsigned long    sectorsperunit;
  1584.         unsigned long    allocunits;
  1585.         unsigned long    availallocunits;
  1586.         unsigned int    bytespersector;
  1587.         }  fsinfo;
  1588.  
  1589.     DOSQFSINFO(    drive,
  1590.             1,
  1591.             (struct FSinfo far *) &fsinfo,
  1592.             sizeof(struct FSinfo));
  1593.  
  1594.     return ((unsigned int) fsinfo.sectorsperunit * fsinfo.bytespersector);
  1595.  
  1596. }
  1597. #endif
  1598.  
  1599. #ifdef    CDOCOPY
  1600. /* D E B U G  use only */
  1601. /* docopyfile(from, to)  Copy a file */
  1602. int docopyfile(from, to)
  1603. unsigned char    *from;
  1604. unsigned char    *to;
  1605. {
  1606.     printf("docopyfile(%s,%s)\n", from, to);
  1607.     return 0;
  1608. }
  1609. #endif
  1610.  
  1611.  
  1612.  
  1613.