home *** CD-ROM | disk | FTP | other *** search
/ Dream 48 / Amiga_Dream_48.iso / Atari / c / sozobon-v2 / scsrc20.lzh / TOOLS.LZH / AR.C next >
C/C++ Source or Header  |  1991-02-22  |  20KB  |  1,077 lines

  1. /* Copyright (c) 1988,89,90,91 by Sozobon, Limited.  Author: Tony Andrews
  2.  *
  3.  * Permission is granted to anyone to use this software for any purpose
  4.  * on any computer system, and to redistribute it freely, with the
  5.  * following restrictions:
  6.  * 1) No charge may be made other than reasonable charges for reproduction.
  7.  * 2) Modified versions must be clearly marked as such.
  8.  * 3) The authors are not responsible for any harmful consequences
  9.  *    of using this software, even if they result from defects in it.
  10.  */
  11.  
  12. static    char    Version[] =
  13. "ar: version 2.00  Copyright (c) 1988,89,90,91 by Sozobon, Limited.";
  14.  
  15. /*
  16.  * ar - archive manipulation program
  17.  */
  18.  
  19. #include <stdio.h>
  20. #ifndef UNIXHOST
  21. #include <ar.h>
  22. #else
  23. #include "crossar.h"
  24. #endif
  25.  
  26. #ifdef    MINIX
  27.  
  28. #include <sys/stat.h>
  29.  
  30. #define    O_RDONLY    0
  31. #define    O_RDWR        2
  32.  
  33. #define    strrchr    rindex
  34.  
  35. #define    SEPCHAR    '/'
  36. #define    ACMODE    0666
  37. #define    FCMODE    a.ar_mode
  38. #define SIZE(a)    (a).ar_size
  39. #define SWAPW(w)
  40.  
  41. #else
  42. #ifndef UNIXHOST
  43.  
  44. #include <fcntl.h>
  45.  
  46. #define    SEPCHAR    '\\'
  47. #define    ACMODE    0
  48. #define    FCMODE    0
  49. #define SIZE(a)    (a).ar_size
  50. #define SWAPW(w)
  51.  
  52. #else
  53.  
  54. #include <fcntl.h>
  55. long crossl();
  56. #define SEPCHAR    '/'
  57. #define ACMODE    0666
  58. #define FCMODE    0666
  59. #define SIZE(a)    crossl((a).ar_size)
  60. #define SWAPW(w)    swapw(w)
  61.  
  62. #endif
  63. #endif
  64.  
  65. #ifndef    FALSE
  66. #define    FALSE    (0)
  67. #define    TRUE    !FALSE
  68. #endif
  69.  
  70. /*
  71.  * Program options
  72.  */
  73. int    vflag = FALSE;    /* verbose option */
  74. int    cflag = FALSE;    /* suppress archive creation message */
  75. int    Vflag = FALSE;    /* print the version message */
  76.  
  77. /*
  78.  * Basic Command
  79.  */
  80. #define    NONE    0    /* missing command spec */
  81. #define    DELETE    1    /* delete members */
  82. #define    REPLACE    2    /* replace (or add) members */
  83. #define    QAPPEND    3    /* quickly append to the archive */
  84. #define    TABLE    4    /* table of contents */
  85. #define    PRINT    5    /* print a member */
  86. #define    MOVE    6    /* move to the end of the archive */
  87. #define    EXTRACT    7    /* extract members */
  88.  
  89. int    cmd = 0;    /* the command we're executing */
  90.  
  91. char    *afile;        /* name of the archive we're messing with */
  92. char    **files;    /* piece of argv starting at the file list */
  93.  
  94. #define    NAMLEN    14        /* length of a file name in the archive */
  95.  
  96. #define    TFILE    "ar_tmp.xxx"    /* temp file base name */
  97. char    tfile[128];        /* temp file name (in same dir as archive) */
  98.  
  99. extern    long    lseek();
  100.  
  101. usage()
  102. {
  103.     fprintf(stderr, "usage: ar {drqtpmx}[vcVl] afile [name] ...\n");
  104.     exit(1);
  105. }
  106.  
  107. main(argc, argv)
  108. int    argc;
  109. char    *argv[];
  110. {
  111.     char    *strrchr();
  112.     register int    status;
  113.     register char    *s;
  114.  
  115.     if (argc < 2)
  116.         usage();
  117.  
  118.     s = (argv[1][0] == '-') ? &argv[1][1] : &argv[1][0];
  119.  
  120.     /*
  121.      * Get the command character
  122.      */
  123.     switch (*s) {
  124.  
  125.     case 'd':
  126.     case 'D':
  127.         cmd = DELETE;    break;
  128.     case 'r':
  129.     case 'R':
  130.         cmd = REPLACE;    break;
  131.     case 'q':
  132.     case 'Q':
  133.         cmd = QAPPEND;    break;
  134.     case 't':
  135.     case 'T':
  136.         cmd = TABLE;    break;
  137.     case 'p':
  138.     case 'P':
  139.         cmd = PRINT;    break;
  140.     case 'm':
  141.     case 'M':
  142.         cmd = MOVE;    break;
  143.     case 'x':
  144.     case 'X':
  145.         cmd = EXTRACT;    break;
  146.     case 'V':
  147.         Vflag = TRUE;    break;
  148.  
  149.     default:
  150.         fprintf(stderr, "ar: invalid command character '%c'\n", *s);
  151.         usage();
  152.     }
  153.  
  154.     /*
  155.      * Check for optional flags
  156.      */
  157.     for (++s; *s ;++s) {
  158.         switch (*s) {
  159.         case 'v':
  160.             vflag = TRUE;    break;
  161.         case 'c':
  162.         case 'C':
  163.             cflag = TRUE;    break;
  164.         case 'V':
  165.             Vflag = TRUE;    break;
  166.         case 'l':        /* ignore to match Minix */
  167.         case 'L':
  168.             break;
  169.         default:
  170.             fprintf(stderr, "ar: invalid option flag '%c'\n", *s);
  171.             usage();
  172.         }
  173.     }
  174.  
  175.     if (Vflag)
  176.         printf("%s\n", Version);
  177.  
  178.     if (argc < 3)
  179.         usage();
  180.  
  181.     afile = argv[2];
  182.     files = &argv[3];
  183.  
  184.     /*
  185.      * Construct the temp file name based on the directory of the
  186.      * archive file.
  187.      */
  188.     if (strrchr(afile, SEPCHAR) != NULL) {
  189.         strcpy(tfile, afile);
  190.         s = strrchr(tfile, SEPCHAR);
  191.         strcpy(s+1, TFILE);
  192.     } else
  193.         strcpy(tfile, TFILE);    /* in the current directory */
  194.  
  195.     switch (cmd) {
  196.  
  197.     case DELETE:
  198.         status = dodelete();
  199.         break;
  200.  
  201.     case REPLACE:
  202.         status = doreplace();
  203.         break;
  204.  
  205.     case QAPPEND:
  206.         status = doqappend();
  207.         break;
  208.  
  209.     case TABLE:
  210.         status = dotable();
  211.         break;
  212.  
  213.     case PRINT:
  214.         status = doprint();
  215.         break;
  216.  
  217.     case MOVE:
  218.         status = domove();
  219.         break;
  220.  
  221.     case EXTRACT:
  222.         status = doextract();
  223.         break;
  224.  
  225.     default:
  226.         fprintf(stderr, "ar: invalid operation\n");
  227.         usage();
  228.     }
  229.  
  230.     exit(status);
  231. }
  232.  
  233. error(s)
  234. char    *s;
  235. {
  236.     fprintf(stderr, "ar: fatal error - %s\n", s);
  237.     exit(1);
  238. }
  239.  
  240. /*
  241.  * base(f) - return a pointer to the base of file 'f'
  242.  *
  243.  * Given a filename like "a/b/c", base returns a pointer to 'c'.
  244.  */
  245. char *
  246. base(f)
  247. register char    *f;
  248. {
  249.     char    *strrchr();
  250.     char    *p;
  251.  
  252.     if ((p = strrchr(f, SEPCHAR)) != NULL)
  253.         return p+1;        /* name starts after the separator */
  254.     else
  255.         return f;        /* no separator, return original */
  256. }
  257.  
  258. /*
  259.  * inlist(f) - is file 'f' in the file list on the command line?
  260.  *
  261.  * If the file is on the list, return a pointer to the full name as it
  262.  * appeared on the command line (possibly including a full path). If not
  263.  * found, returns NULL.
  264.  */
  265. char *
  266. inlist(f)
  267. register char    *f;
  268. {
  269.     register int    i;
  270.  
  271.     for (i=0; files[i] != NULL ;i++) {
  272.         if (strncmp(f, base(files[i]), NAMLEN) == 0)
  273.             return files[i];
  274.     }
  275.     return NULL;
  276. }
  277.  
  278. /*
  279.  * dellist(f) - remove file 'f' from the command line list
  280.  *
  281.  * We 'delete' an entry by truncating it to zero.
  282.  */
  283. dellist(f)
  284. register char    *f;
  285. {
  286.     register int    i;
  287.  
  288.     for (i=0; files[i] != NULL ;i++) {
  289.         if (strncmp(f, base(files[i]), NAMLEN) == 0)
  290.             files[i][0] = '\0';
  291.     }
  292. }
  293.  
  294. /*
  295.  * copy(ofd, nfd, size) - copy a file
  296.  *
  297.  * Copies 'size' bytes from 'ofd' to 'nfd', which must both reference
  298.  * open file descriptors.
  299.  */
  300. #define    BSIZE    8192    /* buffer size */
  301.  
  302. int
  303. copy(ofd, nfd, size)
  304. register int    ofd, nfd;
  305. long    size;
  306. {
  307.     static    char    buf[BSIZE];
  308.     register int    n;
  309.  
  310.     for (n = size; n >= BSIZE; n -= BSIZE) {
  311.         if (read(ofd, buf, BSIZE) != BSIZE)
  312.             return FALSE;
  313.         if (write(nfd, buf, BSIZE) != BSIZE) {
  314.             fprintf(stderr, "ar: disk out of space\n");
  315.             return FALSE;
  316.         }
  317.     }
  318.  
  319.     if (n > 0) {
  320.         if (read(ofd, buf, n) != n)
  321.             return FALSE;
  322.         if (write(nfd, buf, n) != n) {
  323.             fprintf(stderr, "ar: disk out of space\n");
  324.             return FALSE;
  325.         }
  326.     }
  327.     return TRUE;
  328. }
  329.  
  330. /*
  331.  * chkhdr(fd) - make sure the magic number is right
  332.  */
  333. chkhdr(fd)
  334. int    fd;
  335. {
  336.     unsigned short    magic;
  337.  
  338.     if (read(fd, &magic, 2) != 2)
  339.         error("chkhdr: malformed archive");
  340.  
  341.     SWAPW(&magic);
  342.     if (magic != ARMAG1 && magic != ARMAG2)
  343.         error("chkhdr: bad magic");
  344. }
  345.  
  346. /*
  347.  * tostart(fd) - move to the start of the archive
  348.  */
  349. tostart(fd)
  350. int    fd;
  351. {
  352.     lseek(fd, 2L, 0);
  353. }
  354.  
  355. /*
  356.  * gethdr(fd, a) - read a header at the current file position
  357.  *
  358.  * Returns TRUE on success, FALSE at eof.
  359.  */
  360. int
  361. gethdr(fd, a)
  362. int    fd;
  363. struct    ar_hdr    *a;
  364. {
  365.     if (read(fd, a, ARHSZ) == ARHSZ)
  366.         return (a->ar_name[0] != '\0');
  367.     else
  368.         return FALSE;
  369. }
  370.  
  371. /*
  372.  * skipit(fd, a) - skip the current archive element
  373.  *
  374.  * Assumes that we're still positioned right after the header.
  375.  * Returns TRUE on success, FALSE on failure.
  376.  */
  377. int
  378. skipit(fd, a)
  379. int    fd;
  380. struct    ar_hdr    *a;
  381. {
  382.     long    size;
  383.  
  384.     size = SIZE(*a);
  385.  
  386.     return (lseek(fd, size, 1) >= 0);
  387. }
  388.  
  389. /*
  390.  * moveto(fd, name, ar) - find the object 'name' in the given archive
  391.  *
  392.  * Finds the given element in the archive referenced by the given
  393.  * file desciptor. Leaves the file pointer positioned after the
  394.  * header for the element, at the start of the contents. Return the
  395.  * header via pointer 'ar'.
  396.  *
  397.  * Returns TRUE on success, FALSE if no such name found.
  398.  */
  399. int
  400. moveto(fd, name, ar)
  401. register int    fd;
  402. register char    *name;
  403. register struct    ar_hdr    *ar;
  404. {
  405.     tostart(fd);
  406.  
  407.     while (gethdr(fd, ar)) {
  408.         if (strncmp(ar->ar_name, name, NAMLEN) == 0)
  409.             return TRUE;
  410.         if (!skipit(fd, ar))
  411.             break;
  412.     }
  413.  
  414.     return FALSE;
  415. }
  416.  
  417. /*
  418.  * modestr(mode) - return the string representation of a mode word
  419.  */
  420. char *
  421. modestr(mode)
  422. register int    mode;
  423. {
  424.     static    char    mstr[10];
  425.  
  426.     mstr[9] = '\0';
  427.  
  428.     mstr[8] = (mode & 0001) ? 'x' : '-';
  429.     mstr[7] = (mode & 0002) ? 'w' : '-';
  430.     mstr[6] = (mode & 0004) ? 'r' : '-';
  431.  
  432.     mstr[5] = (mode & 0010) ? 'x' : '-';
  433.     mstr[4] = (mode & 0020) ? 'w' : '-';
  434.     mstr[3] = (mode & 0040) ? 'r' : '-';
  435.  
  436.     mstr[2] = (mode & 0100) ? 'x' : '-';
  437.     mstr[1] = (mode & 0200) ? 'w' : '-';
  438.     mstr[0] = (mode & 0400) ? 'r' : '-';
  439.  
  440.     return mstr;
  441. }
  442.  
  443. /*
  444.  * ropen(f) - open archive 'f' for reading
  445.  *
  446.  * Open the named archive 'read only' and check the magic word.
  447.  */
  448. int
  449. ropen(f)
  450. char    *f;
  451. {
  452.     register int    fd;
  453.  
  454.     if ((fd = open(f, O_RDONLY)) < 0)
  455.         return -1;
  456.  
  457.     chkhdr(fd);
  458.  
  459.     return fd;
  460. }
  461.  
  462. /*
  463.  * wopen(f) - open archive 'f' for writing
  464.  *
  465.  * If the archive already exists, open it and check it's magic.
  466.  * If it doesn't exists, create it, and write a valid magic word.
  467.  */
  468. int
  469. wopen(f, domsg)
  470. char    *f;
  471. int    domsg;
  472. {
  473.     register int    fd;
  474.     unsigned short    magic;
  475.  
  476.     if ((fd = open(f, O_RDWR)) < 0) {    /* doesn't exist */
  477.         if ((fd = creat(f, ACMODE)) < 0) {
  478.             fprintf(stderr, "ar: can't create archive '%s'\n", f);
  479.             exit(1);
  480.         }
  481.         if (!cflag && domsg)
  482.             printf("ar: creating archive '%s'\n", f);
  483.  
  484.         magic = ARMAG1;
  485.         SWAPW(&magic);
  486.         write(fd, &magic, 2);
  487.     } else
  488.         chkhdr(fd);
  489.  
  490.     return fd;
  491. }
  492.  
  493. /*
  494.  * wclose(f) - close archive opened with wopen.
  495.  *
  496.  * Write four null bytes to the end of the archive and then close
  497.  * it. This doesn't bother anyone, and seems to make one of the
  498.  * utilities with the 'aln' linker happy.
  499.  */
  500. int
  501. wclose(fd)
  502. int    fd;
  503. {
  504.     long    foo = 0;
  505.  
  506.     write(fd, &foo, 4);
  507.     close(fd);
  508. }
  509.  
  510. /*
  511.  * putfile(fd, f, achar) - write file 'f' to an open archive file
  512.  *
  513.  * The file named by 'f' is written as an archive member to the open
  514.  * file descriptor 'fd'. The "action" character 'achar' is used to
  515.  * print a message if the verbose option is set.
  516.  */
  517. putfile(fd, f, achar)
  518. register int    fd;
  519. register char    *f;
  520. char    achar;
  521. {
  522.     register int    xfd;
  523.     struct    ar_hdr    a;
  524.     register long    size;
  525.     char    null = 0;
  526. #ifdef    MINIX
  527.     struct    stat    s;
  528. #endif
  529.  
  530.     if ((xfd = open(f, O_RDONLY)) < 0) {
  531.         printf("%s: can't open\n", f);
  532.         return;
  533.     }
  534.     strncpy(a.ar_name, base(f), NAMLEN);
  535.  
  536. #ifdef    MINIX
  537.     if (fstat(xfd, &s) != 0) {
  538.         printf("%s: can't stat\n", f);
  539.         return;
  540.     }
  541.     a.ar_date = s.st_mtime;
  542.     a.ar_uid  = s.st_uid;
  543.     a.ar_gid  = s.st_gid;
  544.     a.ar_mode = s.st_mode & 0666;
  545.     size = s.st_size;
  546. #else
  547. #ifndef UNIXHOST
  548.     a.ar_date = 0;
  549. #else
  550.     pcrossl(0, a.ar_date);
  551. #endif
  552.     a.ar_uid = 0;
  553.     a.ar_gid = 0;
  554.     a.ar_mode = 0666;
  555.     SWAPW(&a.ar_mode);
  556.  
  557.     /*
  558.      * Get the size of the file by doing an lseek. This is
  559.      * easier and more portable than doing the equivalent
  560.      * of an fstat().
  561.      */
  562.     size = lseek(xfd, 0L, 2);
  563. #endif
  564.     /*
  565.      * If the file size is odd, pad it out with an extra
  566.      * byte to be compatible with the Alcyon ar68.prg
  567.      */
  568. #ifndef UNIXHOST
  569.     if (size & 1)
  570.         a.ar_size = size+1;
  571.     else
  572.         a.ar_size = size;
  573. #else
  574.     if (size & 1)
  575.         pcrossl(size+1, a.ar_size);
  576.     else
  577.         pcrossl(size, a.ar_size);
  578. #endif
  579.     a.ar_fill = 0;
  580.  
  581.     if (write(fd, &a, ARHSZ) != ARHSZ)
  582.         error("ar: can't write to archive");
  583.  
  584.     if (vflag)
  585.         printf("%c %s\n", achar, base(f));
  586.  
  587.     lseek(xfd, 0L, 0);        /* rewind */
  588.     if (!copy(xfd, fd, size))
  589.         error("ar: can't write to archive");
  590.  
  591.     close(xfd);
  592.  
  593.     if (size & 1)            /* need a pad byte? */
  594.         write(fd, &null, 1);
  595. }
  596.  
  597. /*
  598.  * Functions to perform the basic commands
  599.  */
  600.  
  601. int
  602. dodelete()
  603. {
  604.     register int    fd, tfd;
  605.     register int    i;
  606.     struct    ar_hdr    a;
  607.  
  608.     if (files[0] == NULL)    /* no work to do */
  609.         return 0;
  610.  
  611.     tfd = wopen(tfile, FALSE);
  612.  
  613.     if ((fd = ropen(afile)) < 0)
  614.         error("can't read archive");
  615.  
  616.     while (gethdr(fd, &a)) {
  617.  
  618.         if (inlist(a.ar_name) != NULL) {
  619.  
  620.             /*
  621.              * Skip over the copy in the original archive.
  622.              */
  623.             if (!skipit(fd, &a)) {
  624.                 close(tfd);
  625.                 close(fd);
  626.                 unlink(tfile);
  627.                 error("delete: malformed archive");
  628.             }
  629.             if (vflag)
  630.                 printf("d %s\n", a.ar_name);
  631.  
  632.             dellist(a.ar_name);
  633.     
  634.         } else {    /* copy from the old archive */
  635.  
  636.             if (write(tfd, &a, ARHSZ) != ARHSZ) {
  637.                 close(tfd);
  638.                 close(fd);
  639.                 unlink(tfile);
  640.                 error("delete: can't write to archive");
  641.             }
  642.             copy(fd, tfd, SIZE(a));
  643.         }
  644.     }
  645.     close(fd);
  646.     wclose(tfd);
  647.  
  648.     /*
  649.      * Note any files not found
  650.      */
  651.     for (i=0; files[i] != NULL ;i++) {
  652.         if (files[i][0] != '\0')
  653.             printf("%s: not found\n", files[i]);
  654.     }
  655.  
  656.     /*
  657.      * Unlink the original archive and rename the
  658.      * temp file on top of it.
  659.      */
  660.     unlink(afile);
  661.     rename(tfile, afile);
  662.  
  663.     return 0;
  664. }
  665.  
  666. int
  667. doreplace()
  668. {
  669.     register int    fd, tfd;
  670.     register int    i;
  671.     register char    *f;
  672.     struct    ar_hdr    a;
  673.  
  674.     if (files[0] == NULL)    /* no work to do */
  675.         return 0;
  676.  
  677.     tfd = wopen(tfile, FALSE);
  678.  
  679.     /*
  680.      * If there's no current archive, skip the section dealing
  681.      * with updates, and just append the named files to the
  682.      * newly created archive.
  683.      */
  684.     if ((fd = ropen(afile)) < 0) {
  685.         if (!cflag)
  686.             printf("ar: creating archive '%s'\n", afile);
  687.         goto append;
  688.     }
  689.  
  690.     while (gethdr(fd, &a)) {
  691.  
  692.         if ((f = inlist(a.ar_name)) != NULL) {
  693.  
  694.             /*
  695.              * Skip over the old copy in the original archive.
  696.              */
  697.             if (!skipit(fd, &a)) {
  698.                 close(tfd);
  699.                 close(fd);
  700.                 unlink(tfile);
  701.                 error("doreplace: malformed archive");
  702.             }
  703.  
  704.             putfile(tfd, f, 'r');
  705.  
  706.             dellist(a.ar_name);
  707.  
  708.         } else {    /* copy from the old archive */
  709.  
  710.             if (write(tfd, &a, ARHSZ) != ARHSZ) {
  711.                 close(tfd);
  712.                 close(fd);
  713.                 unlink(tfile);
  714.                 error("replace: can't write to archive");
  715.             }
  716.             copy(fd, tfd, SIZE(a));
  717.         }
  718.     }
  719.     close(fd);
  720.  
  721.     /*
  722.      * Now go back through the file list and append any files
  723.      * that didn't turn up in the old archive.
  724.      */
  725. append:
  726.     for (i=0; files[i] != NULL ;i++) {
  727.         if (files[i][0] != '\0')    /* wasn't deleted before */
  728.             putfile(tfd, files[i], 'a');
  729.     }
  730.     wclose(tfd);
  731.  
  732.     /*
  733.      * Unlink the original archive and rename the
  734.      * temp file on top of it.
  735.      */
  736.     unlink(afile);
  737.     rename(tfile, afile);
  738.  
  739.     return 0;
  740. }
  741.  
  742. int
  743. doqappend()
  744. {
  745.     register int    fd;
  746.     register int    i;
  747.     struct    ar_hdr    a;
  748.     long    fpos;
  749.  
  750.     if (files[0] == NULL)    /* no work to do */
  751.         return 0;
  752.  
  753.     fd = wopen(afile, TRUE);
  754.  
  755.     /*
  756.      * Get positioned just after the last member
  757.      */
  758.     fpos = 2;
  759.     while (gethdr(fd, &a)) {
  760.         if (!skipit(fd, &a))
  761.             error("doqappend: malformed archive");
  762.         fpos = lseek(fd, 0L, 1);
  763.     }
  764.     /*
  765.      * Go back to the end of the last valid archive member
  766.      */
  767.     lseek(fd, fpos, 0);
  768.  
  769.     for (i=0; files[i] != NULL ;i++)
  770.         putfile(fd, files[i], 'a');
  771.  
  772.     wclose(fd);
  773.     return 0;
  774. }
  775.  
  776. int
  777. dotable()
  778. {
  779.     register int    fd;
  780.     register int    i;
  781.     struct    ar_hdr    a;
  782.  
  783.     if ((fd = ropen(afile)) < 0)
  784.         error("can't read archive");
  785.  
  786.     if (files[0] == NULL) {
  787.         while (gethdr(fd, &a)) {
  788.             if (vflag) {
  789. #ifdef    MINIX
  790.                 char    *tp, *ctime();
  791.                 tp = ctime(&a.ar_date);
  792.                 printf("%s%4d/%4d%7ld %.12s %.4s %.14s\n",
  793.                     modestr(a.ar_mode),
  794.                     a.ar_uid, a.ar_gid,
  795.                     a.ar_size, tp + 4, tp + 20,
  796.                     a.ar_name);
  797. #else
  798.                 SWAPW(&a.ar_mode);
  799.                 printf("%s%4d/%4d%7ld %.14s\n",
  800.                     modestr(a.ar_mode),
  801.                     a.ar_uid, a.ar_gid,
  802.                     SIZE(a),
  803.                     a.ar_name);
  804. #endif
  805.             } else
  806.                 printf("%.14s\n", a.ar_name);
  807.             if (!skipit(fd, &a))
  808.                 break;
  809.         }
  810.         close(fd);
  811.         return 0;
  812.     }
  813.  
  814.     for (i=0; files[i] != NULL ;i++) {
  815.         if (moveto(fd, files[i], &a)) {
  816.             if (vflag) {
  817. #ifdef    MINIX
  818.                 char    *tp, *ctime();
  819.                 tp = ctime(&a.ar_date);
  820.                 printf("%s%4d/%4d%7ld %.12s %.4s %.14s\n",
  821.                     modestr(a.ar_mode),
  822.                     a.ar_uid, a.ar_gid,
  823.                     a.ar_size, tp + 4, tp + 20,
  824.                     a.ar_name);
  825. #else
  826.                 SWAPW(a.ar_mode);
  827.                 printf("%s%4d/%4d%7ld %.14s\n",
  828.                     modestr(a.ar_mode),
  829.                     a.ar_uid, a.ar_gid,
  830.                     SIZE(a),
  831.                     a.ar_name);
  832. #endif
  833.             } else
  834.                 printf("%.14s\n", a.ar_name);
  835.         } else
  836.             fprintf(stderr, "%s: not found\n", files[i]);
  837.     }
  838.     close(fd);
  839.     return 0;
  840. }
  841.  
  842. int
  843. doprint()
  844. {
  845.     register int    fd;
  846.     register int    i;
  847.     struct    ar_hdr    a;
  848.  
  849.     /*
  850.      * If no file names given, error.
  851.      */
  852.     if (files[0] == NULL) {
  853.         fprintf(stderr, "ar: no filenames given\n");
  854.         return 1;
  855.     }
  856.  
  857.     if ((fd = ropen(afile)) < 0)
  858.         error("can't read archive");
  859.  
  860.     for (i=0; files[i] != NULL ;i++) {
  861.         if (moveto(fd, files[i], &a)) {
  862.             copy(fd, 1, SIZE(a));
  863.         } else
  864.             fprintf(stderr, "%s: not found\n", files[i]);
  865.     }
  866.     close(fd);
  867.  
  868.     return 0;
  869. }
  870.  
  871. int
  872. domove()
  873. {
  874.     register int    fd, tfd;
  875.     register int    i;
  876.     struct    ar_hdr    a;
  877.  
  878.     if (files[0] == NULL)    /* no work to do */
  879.         return 0;
  880.  
  881.     tfd = wopen(tfile, FALSE);
  882.  
  883.     if ((fd = ropen(afile)) < 0) {
  884.         fprintf(stderr, "ar: can't open archive '%s'\n", afile);
  885.         exit(1);
  886.     }
  887.  
  888.     while (gethdr(fd, &a)) {
  889.  
  890.         if (inlist(a.ar_name) != NULL) {
  891.  
  892.             /*
  893.              * Don't copy anything that we need
  894.              * to move to the end.
  895.              */
  896.             if (!skipit(fd, &a)) {
  897.                 close(tfd);
  898.                 close(fd);
  899.                 unlink(tfile);
  900.                 error("domove: malformed archive");
  901.             }
  902.  
  903.         } else {    /* copy from the old archive */
  904.  
  905.             if (write(tfd, &a, ARHSZ) != ARHSZ) {
  906.                 close(tfd);
  907.                 close(fd);
  908.                 unlink(tfile);
  909.                 error("move: can't write to archive");
  910.             }
  911.             if (!copy(fd, tfd, SIZE(a))) {
  912.                 close(tfd);
  913.                 close(fd);
  914.                 unlink(tfile);
  915.                 error("move: can't write to archive");
  916.             }
  917.         }
  918.     }
  919.  
  920.     /*
  921.      * Now everything that isn't to be moved has been copied
  922.      * to the temp file. Now go back and get the stuff to be
  923.      * moved and copy it.
  924.      */
  925.     for (i=0; files[i] != NULL ;i++) {
  926.  
  927.         if (moveto(fd, files[i], &a)) {
  928.             if (vflag)
  929.                 printf("m %s\n", files[i]);
  930.  
  931.             if (write(tfd, &a, ARHSZ) != ARHSZ) {
  932.                 close(tfd);
  933.                 close(fd);
  934.                 unlink(tfile);
  935.                 error("move: can't write to archive");
  936.             }
  937.             if (!copy(fd, tfd, SIZE(a))) {
  938.                 close(tfd);
  939.                 close(fd);
  940.                 unlink(tfile);
  941.                 error("move: can't write to archive");
  942.             }
  943.         } else
  944.             printf("%s: not in archive\n", files[i]);
  945.     }
  946.     close(fd);
  947.     wclose(tfd);
  948.  
  949.     /*
  950.      * Unlink the original archive and rename the
  951.      * temp file on top of it.
  952.      */
  953.     unlink(afile);
  954.     rename(tfile, afile);
  955.  
  956.     return 0;
  957. }
  958.  
  959. int
  960. doextract()
  961. {
  962.     register int    fd, xfd;
  963.     register int    i;
  964.     struct    ar_hdr    a;
  965.  
  966.     if ((fd = ropen(afile)) < 0)
  967.         error("can't read archive");
  968.  
  969.     /*
  970.      * If no file names given, extract everything.
  971.      */
  972.     if (files[0] == NULL) {
  973.         while (gethdr(fd, &a)) {
  974.             if ((xfd = creat(a.ar_name, FCMODE)) < 0) {
  975.                 fprintf(stderr,"%s: can't create\n", a.ar_name);
  976.                 continue;
  977.             }
  978.             if (vflag)
  979.                 printf("x %s\n", a.ar_name);
  980.             copy(fd, xfd, SIZE(a));
  981.             close(xfd);
  982.         }
  983.         close(fd);
  984.         return 0;
  985.     }
  986.  
  987.     for (i=0; files[i] != NULL ;i++) {
  988.         if (moveto(fd, files[i], &a)) {
  989.             if ((xfd = creat(a.ar_name, FCMODE)) >= 0) {
  990.                 if (vflag)
  991.                     printf("x %s\n", a.ar_name);
  992.                 copy(fd, xfd, SIZE(a));
  993.                 close(xfd);
  994.             } else
  995.                 fprintf(stderr, "%s: can't create\n", files[i]);
  996.         } else
  997.             fprintf(stderr, "%s: not found\n", files[i]);
  998.     }
  999.     close(fd);
  1000.  
  1001.     return 0;
  1002. }
  1003.  
  1004. #ifdef    MINIX
  1005.  
  1006. rename(f1, f2)
  1007. char    *f1, *f2;
  1008. {
  1009.     unlink(f2);
  1010.     link(f1, f2);
  1011.     unlink(f1);
  1012. }
  1013.  
  1014. #endif
  1015.  
  1016. #ifdef UNIXHOST
  1017. long
  1018. crossl(cp)
  1019. char *cp;
  1020. {
  1021.     union {
  1022.         long l;
  1023.         char c[4];
  1024.     } u;
  1025.  
  1026. #ifdef LITTLE_ENDIAN
  1027.     u.c[0] = cp[3];
  1028.     u.c[1] = cp[2];
  1029.     u.c[2] = cp[1];
  1030.     u.c[3] = cp[0];
  1031. #else
  1032.     u.c[0] = cp[0];
  1033.     u.c[1] = cp[1];
  1034.     u.c[2] = cp[2];
  1035.     u.c[3] = cp[3];
  1036. #endif
  1037.     return u.l;
  1038. }
  1039.  
  1040. pcrossl(l, cp)
  1041. long l;
  1042. char *cp;
  1043. {
  1044.     union {
  1045.         long l;
  1046.         char c[4];
  1047.     } u;
  1048.  
  1049.     u.l = l;
  1050. #ifdef LITTLE_ENDIAN
  1051.     cp[0] = u.c[3];
  1052.     cp[1] = u.c[2];
  1053.     cp[2] = u.c[1];
  1054.     cp[3] = u.c[0];
  1055. #else
  1056.     cp[0] = u.c[0];
  1057.     cp[1] = u.c[1];
  1058.     cp[2] = u.c[2];
  1059.     cp[3] = u.c[3];
  1060. #endif
  1061. }
  1062.  
  1063. swapw(cp)
  1064. char *cp;
  1065. {
  1066. #ifdef LITTLE_ENDIAN
  1067.     char t;
  1068.  
  1069.     t = cp[1];
  1070.     cp[1] = cp[0];
  1071.     cp[0] = t;
  1072.     cp += 2;
  1073. #endif
  1074.     return 0;
  1075. }
  1076. #endif
  1077.