home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 6 File / 06-File.zip / os2ntree.zip / OLDNTREE.C < prev    next >
Text File  |  1987-12-17  |  32KB  |  1,313 lines

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