home *** CD-ROM | disk | FTP | other *** search
/ CP/M / CPM_CDROM.iso / mbug / mbug100.arc / AR.C < prev    next >
Text File  |  1979-12-31  |  9KB  |  336 lines

  1. /* 
  2. **   AR -- File Archiver
  3. **
  4. **   usage: ar -{dptux} arcfile [file...]
  5. **
  6. **   Ar collects text files into a single archive file.
  7. **   Files can be extracted, new ones added,
  8. **   old ones replaced or deleted, and
  9. **   a list of the archive contents produced.
  10. **
  11. **   The first argument is a switch from the following set.
  12. **   The second argument is the name of the archive file.
  13. **   The third and subsequent arguments are file names. 
  14. **
  15. **   -d  delete named files from the library.
  16. **   -p  print named, or all, files on stdout.
  17. **   -t  table of contents of named, or all, files to stdout.
  18. **   -u  update the archive by adding/replacing files
  19. **       (used to create a new library).
  20. **       If no file names are specified in the command line,
  21. **       they are obtained from stdin.
  22. **   -x  extract named, or all, files.
  23. **
  24. **   Control-S to pause execution and control-C to abort.
  25. **
  26. **   This program was given as a class assignment in the
  27. **   Computer Science Department at the University of Arizona.
  28. **   It was contributed by Ernext Payne.  Orignially it was
  29. **   written to work with tape archives, but this version has
  30. **   been modified for higher speed operation with diskette
  31. **   archives under CP/M.
  32. */
  33.  
  34. #include stdio.h
  35.  
  36. #define NAMESIZE 20
  37. #define MAXLINE  500
  38. #define MAXFILES 20
  39. #define HDR      ">>>"
  40. #define AUXSIZE  4096
  41.  
  42. char tname[]="  ar.$$$";
  43. int fnptr[MAXFILES];
  44. int fstat[MAXFILES];
  45. int nfiles;
  46. int errchk;
  47.  
  48. main(argc,argv) int argc, argv[]; {
  49.   char cmd[3], aname[NAMESIZE];
  50.   if(getarg(1,  cmd,       3,argc,argv) == EOF) usage();
  51.   if(getarg(2,aname,NAMESIZE,argc,argv) == EOF) usage();
  52.   if(aname[1] == ':') {
  53.     tname[0] = aname[0];
  54.     tname[1] = aname[1];
  55.     }
  56.   else left(tname);
  57.   getfns(argc,argv);
  58.   switch(toupper(cmd[1])) {
  59.     case 'D': drop(aname);
  60.               break;
  61.     case 'T': table(aname);
  62.               break;
  63.     case 'U': update(aname);
  64.               break;
  65.     case 'X':
  66.     case 'P': extract(aname, toupper(cmd[1]));
  67.               break;
  68.      default: usage();
  69.     }
  70.   }
  71.  
  72. /* acopy - copy size characters from fpi to fpo */
  73. acopy(fpi,fpo,size) int fpi, fpo; int size; {
  74.   int c;
  75.   while(size-- > 0) {
  76.     poll(YES);
  77.     if((c = getc(fpi)) == EOF)
  78.       break;
  79.     putc(c,fpo);
  80.     }
  81.   }
  82.  
  83. /* addfile - add file "name" to archive */
  84. addfile(name,fp) char *name; int fp; {
  85.   int nfp;
  86.   if((nfp = fopen(name,"r")) == NULL) {
  87.     fprintf(stderr,"%s: can't open\n",name);
  88.     errchk = 1;
  89.     }
  90.   if (errchk == 0) {
  91.     if(name[1] == ':') name += 2;
  92.     fprintf(fp,"%s %s %d\n",HDR,name,fsize(nfp));
  93.     fcopy(nfp,fp);
  94.     fclose(nfp);
  95.     fprintf(stderr, " copied new %s\n", name);
  96.     }
  97.   }
  98.  
  99. /* amove - move file1 to file2 */
  100. amove(file1,file2) char *file1, *file2; {
  101.   if(errchk) {
  102.     printf("fatal errors - archive not altered\n");
  103.     unlink(file1);
  104.     exit(7);
  105.     }
  106.   unlink(file2);
  107.   if(file2[1] == ':') file2 += 2;
  108.   if(rename(file1, file2)) {
  109.     printf("can't rename %s to %s\n", file1, file2);
  110.     exit(7);
  111.     }
  112.   }
  113.  
  114. /* cant - print file name and die */
  115. cant(name) char *name; {
  116.   fprintf(stderr,"%s: can't open\n",name);
  117.   exit(7);
  118.   }
  119.  
  120. /* drop - delete files from archive */
  121. drop(aname) char *aname; {
  122.   int afp, tfp;
  123.   if(nfiles <= 0) /* protect innocents  */
  124.     error("delete by name only");
  125.   afp = mustopen(aname,"r");
  126.   tfp = mustopen(tname,"w");
  127.   auxbuf(tfp, AUXSIZE);
  128.   replace(afp,tfp,'d');
  129.   notfound();
  130.   fclose(afp);
  131.   fclose(tfp);
  132.   amove(tname,aname);
  133.   }
  134.  
  135. /* error - print message and die */
  136. error(msg) char *msg; {
  137.   fprintf(stderr,"%s\n",msg);
  138.   exit(7);
  139.   }
  140.  
  141. /* extract - extract files from archive */
  142. extract(aname,cmd) char *aname, cmd; {
  143.   int afp, efp;
  144.   char ename[NAMESIZE], in[MAXLINE];
  145.   int size;
  146.   afp = mustopen(aname,"r");
  147.   auxbuf(afp, AUXSIZE);
  148.   if(cmd == 'P') efp = stdout;
  149.   else           efp = NULL;
  150.   while((size = gethdr(afp,in,ename)) >= 0)
  151.     if(!fmatch(ename, YES)) fskip(afp,size);
  152.     else {
  153.       if(efp != stdout) efp = fopen(ename,"w");
  154.       if(efp == NULL) {
  155.         fprintf(stderr,"%s: can't create\n",ename);
  156.         errchk = 1;
  157.         fskip(afp,size);
  158.         }
  159.       else {
  160.         acopy(afp,efp,size);
  161.         if(cmd == 'P') fprintf(stderr, "printed %s\n", ename);
  162.         else           fprintf(stderr, "created %s\n", ename);
  163.         if(efp != stdout) fclose(efp);
  164.         }
  165.       }
  166.   notfound();
  167.   fclose(afp);
  168.   }
  169.  
  170. /* fcopy - copy file in to file out */
  171. fcopy(in,out) int in, out; {
  172.   int c;
  173.   while((c = getc(in)) != EOF) {
  174.     poll(YES);
  175.     putc(c,out);
  176.     }
  177.   }
  178.  
  179. /* fmatch - check if name matches argument list */
  180. fmatch(name, quit) char *name; int quit; {
  181.   int i, done;
  182.   char *fnp;
  183.   if(nfiles <= 0) return(1);
  184.   done = YES;
  185.   for(i=0;i<nfiles;++i) {
  186.     fnp = fnptr[i];
  187.     if(fnp[1] == ':') fnp += 2;
  188.     if(strcmp(name,fnp) == 0) {
  189.       fstat[i] = 1;
  190.       return(1);
  191.       }
  192.     if(fstat[i] == 0) done = NO;
  193.     }
  194.   if(quit && done) exit(0);
  195.   return(0);
  196.   }
  197.  
  198. /* fsize - size of file in characters */
  199. fsize(fp) int fp; {
  200.   int i;
  201.   for(i=0; getc(fp) != EOF; ++i) ;
  202.   rewind(fp);
  203.   return(i);
  204.   }
  205.  
  206. /* fskip - skip n characters on file fp */
  207. fskip(fp,n) int fp, n; {
  208.   while(n-- > 0) {
  209.     poll(YES);
  210.     if(fgetc(fp) == EOF) break;
  211.     }
  212.   }
  213.  
  214. /* getfns - get file names into fname, check for duplicates */
  215. getfns(argc,argv) int argc, argv[]; {
  216.   int i, j;
  217.   nfiles = argc - 3;
  218.   if(nfiles > MAXFILES)
  219.     error("too many file names");
  220.   for(i=0,j=3; i<nfiles; i++,j++)
  221.     fnptr[i] = argv[j];
  222.   for(i = 0; i < nfiles-1; ++i)
  223.     for(j = i+1; j < nfiles; ++j) {
  224.       if(strcmp(fnptr[i],fnptr[j]) == 0) {
  225.         fprintf(stderr,"%s:duplicate file names\n",fnptr[i]);
  226.         exit(7);
  227.         }
  228.     }
  229.   }
  230.  
  231. /* gethdr - get header info from fp */
  232. gethdr(fp,buf,name) int fp; char *buf, *name; {
  233.   if(fgets(buf,MAXLINE,fp) == NULL)
  234.     return(-1);
  235.   buf = getwrd(buf,name);
  236.   if(strcmp(name,HDR) != 0)
  237.     error("archive not in proper format");
  238.   buf = getwrd(buf,name);
  239.   return(atoi(buf));
  240.   }
  241.  
  242. /* getwrd - copy first word of s to t */
  243. getwrd(s,t) char *s, *t; {
  244.   while(isspace(*s)) ++s;
  245.   while(*s != '\0' && !isspace(*s))  *t++ = *s++;
  246.   *t = '\0';
  247.   return(s);
  248.   }
  249.  
  250. /* mustopen - open file or die */
  251. mustopen(name,mode) char *name, *mode; {
  252.   int fp;
  253.   if(fp = fopen(name,mode)) return(fp);
  254.   cant(name);
  255.   }
  256.  
  257. /* notfound - print "not found" message */
  258. notfound() {
  259.   int i;
  260.   for(i=0;i<nfiles;++i)
  261.     if(fstat[i] == 0) {
  262.       fprintf(stderr,"%s not in archive\n",fnptr[i]);
  263.       errchk = 1;
  264.     }
  265.   }
  266.  
  267. /* replace - replace or delete files */
  268. replace(afp,tfp,cmd) int afp, tfp; char cmd; {
  269.   char in[MAXLINE], uname[NAMESIZE];
  270.   int size;
  271.   while((size = gethdr(afp,in,uname)) >= 0) {
  272.     if(fmatch(uname, NO)) {
  273.       if(cmd == 'u')    /* add new one */
  274.         addfile(uname,tfp);
  275.       fskip(afp,size);  /* discard old one */
  276.       fprintf(stderr, "dropped old %s\n", uname);
  277.       }
  278.     else {
  279.       fputs(in,tfp);
  280.       acopy(afp,tfp,size);
  281.       }
  282.     }
  283.   }
  284.  
  285. /* table - print table of archive contents  */
  286. table(aname) char *aname; {
  287.   char in[MAXLINE], lname[NAMESIZE];
  288.   int afp, size;
  289.   afp = mustopen(aname,"r");
  290.   while((size = gethdr(afp,in,lname)) >= 0) {
  291.     poll(YES);
  292.     if(fmatch(lname, YES)) printf("%s\n", lname);
  293.     fskip(afp,size);
  294.     }
  295.   notfound();
  296.   fclose(afp);
  297.   }
  298.  
  299. /* update - update existing files, add new ones at end */
  300. update(aname) char *aname; {
  301.   int afp, i, tfp;
  302.   char fn[NAMESIZE];
  303.   if((afp = fopen(aname,"r+")) == NULL)
  304.     /* maybe archive does not exist yet */
  305.     afp = mustopen(aname,"w+");
  306.   tfp = mustopen(tname,"w+");
  307.   auxbuf(tfp, AUXSIZE);
  308.   replace(afp,tfp,'u');   /* update existing */
  309.   if(nfiles > 0) {
  310.     for(i=0;i<nfiles;++i) /* add new ones */
  311.       if(fstat[i] == 0) {
  312.         addfile(fnptr[i],tfp);
  313.         if(errchk) break;
  314.         fstat[i] = 1;
  315.         }
  316.     }
  317.   else
  318.     while(1) {
  319.       poll(YES);
  320.       if(iscons(stdin)) fprintf(stdout,"file - ");
  321.       if(!fgets(fn, NAMESIZE, stdin) || *fn == '\n') break;
  322.       for(i=0; fn[i]; i++)
  323.         if((fn[i] = toupper(fn[i])) == '\n') fn[i] = NULL;
  324.       addfile(&fn[0], tfp);
  325.       if(errchk) break;
  326.       }
  327.   fclose(afp);
  328.   fclose(tfp);
  329.   amove(tname,aname);
  330.   }
  331.  
  332. /* usage - abort with a usage message */
  333. usage() {
  334.   error("usage: ar -{dptux} arcfile [file...]");
  335.   }
  336.