home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / unix / volume4 / archx / archc.c next >
Encoding:
C/C++ Source or Header  |  1986-11-30  |  7.6 KB  |  338 lines

  1. /*
  2.  *            A R C H I V E
  3.  *
  4.  * Create an archive
  5.  *
  6.  */
  7.  
  8. /*)BUILD    $(TKBOPTIONS) = {
  9.             TASK    = ...ARC
  10.         }
  11. */
  12.  
  13. #ifdef    DOCUMENTATION
  14.  
  15. title    archc    text file archive creation
  16. index        text file archive creation
  17.  
  18. synopsis
  19.  
  20.     archc file[s] >archive
  21.  
  22. description
  23.  
  24.     Archc manages archives (libraries) of source files, allowing
  25.     a large number of small files to be stored without using
  26.     excessive system resources.  It copies the set of named
  27.     files to standard output in archive format.
  28.  
  29.     The archx program will recreate the files from an archive.
  30.  
  31.     Note: there are no checks against the same file appearing
  32.     twice in an archive.
  33.  
  34. archive file format
  35.  
  36.     Archive files are standard text files.  Each archive element is
  37.     preceeded by a line of the format:
  38.     .s.nf
  39.     -h-    file.name    date    true_path_name
  40.     .s.f
  41.     Note that there is no line or byte count.  To prevent problems,
  42.     a '-' at the beginning of a record within a user file or embedded
  43.     archive will be "quoted" by doubling it.  The date and true filename
  44.     fields are ignored.  On Dec operating systems, file.name is
  45.     forced to lowercase.  Certain bytes at the beginning of a record are
  46.     also prefixed by '-' to prevent mailers from treating them
  47.     as commands.
  48.  
  49. diagnostics
  50.  
  51.     Diagnostic messages should be self-explanatory
  52.  
  53. author
  54.  
  55.     Martin Minow
  56.  
  57. #endif
  58.  
  59. #include    <stdio.h>
  60. #include    <ctype.h>
  61. #ifdef vms
  62. #include        <ssdef.h>
  63. #include        <stsdef.h>
  64. #define    IO_SUCCESS    (SS$_NORMAL | STS$M_INHIB_MSG)
  65. #define    IO_ERROR    SS$_ABORT
  66. #endif
  67. /*
  68.  * Note: IO_SUCCESS and IO_ERROR are defined in the Decus C stdio.h file
  69.  */
  70. #ifndef    IO_SUCCESS
  71. #define    IO_SUCCESS    0
  72. #endif
  73. #ifndef    IO_ERROR
  74. #define    IO_ERROR    1
  75. #endif
  76. #define EOS        0
  77. #define    FALSE        0
  78. #define    TRUE        1
  79.  
  80. char        text[513];        /* Working text            */
  81. char        name[81];        /* Current archive member name    */
  82. char        pathname[81];        /* Output for argetname()    */
  83. char        *timetext;        /* Time of day text        */
  84. int        verbose        = TRUE; /* TRUE for verbosity        */
  85. FILE        *infd;            /* Input file            */
  86.  
  87. main(argc, argv)
  88. int        argc;            /* Arg count            */
  89. char        *argv[];        /* Arg vector            */
  90. {
  91.     register int        i;    /* Random counter        */
  92.     register char        *fn;    /* File name pointer        */
  93.     register char        *argp;    /* Arg pointer            */
  94.     int            nfiles;
  95.     extern char        *ctime();
  96.     extern long        time();
  97.     long            timval;
  98.  
  99.     time(&timval);
  100.     timetext = ctime(&timval);
  101.     timetext[24] = EOS;
  102. #ifdef vms
  103.     argc = getredirection(argc, argv);
  104. #endif
  105.     if (argc <= 1)
  106.         fprintf(stderr, "No files to archive?\n");
  107. #ifdef    unix
  108.     for (i = 1; i < argc; i++) {
  109.         if ((infd = fopen(argv[i], "r")) == NULL)
  110.         perror(argv[i]);
  111.         else {
  112.         strcpy(pathname, argv[i]);
  113.         import();
  114.         fclose(infd);
  115.         }
  116.     }
  117. #else
  118.     /*
  119.      * Decus C supports fwild/fnext for explicit processing
  120.      * of wild-card filenames.
  121.      */
  122.     for (i = 1; i < argc; i++) {
  123.         if ((infd = fwild(argv[i], "r")) == NULL)
  124.         perror(argv[i]);
  125.         else {
  126.         for (nfiles = 0; fnext(infd) != NULL; nfiles++) {
  127.             fgetname(infd, pathname);
  128.             import();
  129.         }
  130.         fclose(infd);
  131.         if (nfiles == 0)
  132.             fprintf(stderr, "No files match \"%s\"\n", argv[i]);
  133.         }
  134.     }
  135. #endif
  136. }
  137.  
  138. import()
  139. /*
  140.  * Add the file open on infd (with file name in pathname) to
  141.  * the archive.
  142.  */
  143. {
  144.     unsigned int    nrecords;
  145.  
  146.     fixname();
  147.     nrecords = 0;
  148.     printf("-h- %s\t%s\t%s\n", name, timetext, pathname);
  149.     while (fgets(text, sizeof text, infd) != NULL) {
  150.         switch (text[0]) {
  151.         case '-':
  152.         case '.':
  153.         case '~':
  154.         putchar('-');                /* Quote    */
  155.         }
  156.         fputs(text, stdout);
  157.         nrecords++;
  158.     }
  159.     if (ferror(infd)) {
  160.         perror(name);
  161.         fprintf(stderr, "Error when importing a file\n");
  162.     }
  163.     if (verbose) {
  164.         fprintf(stderr, "%u records read from %s\n",
  165.         nrecords, pathname);
  166.     }
  167. }
  168.  
  169. fixname()
  170. /*
  171.  * Get file name (in pathname), stripping off device:[directory]
  172.  * and ;version.  The archive name ("file.ext") is written to name[].
  173.  * On a dec operating system, name is forced to lowercase.
  174.  */
  175. {
  176.     register char    *tp;
  177.     register char    *ip;
  178.     char        bracket;
  179.     extern char    *strrchr();
  180.  
  181. #ifdef    unix
  182.     /*
  183.      * name is after all directory information
  184.      */
  185.     if ((tp = strrchr(pathname, '/')) != NULL)
  186.         tp++;
  187.     else
  188.         tp = pathname;
  189.     strcpy(name, tp);
  190. #else
  191.     strcpy(name, pathname);
  192.     if ((tp = strrchr(name, ';')) != NULL)
  193.         *tp = EOS;
  194.     while ((tp = strchr(name, ':')) != NULL)
  195.         strcpy(name, tp + 1);
  196.     switch (name[0]) {
  197.     case '[':    bracket = ']';
  198.             break;
  199.     case '<':    bracket = '>';
  200.             break;
  201.     case '(':    bracket = ')';
  202.             break;
  203.     default:    bracket = EOS;
  204.             break;
  205.     }
  206.     if (bracket != EOS) {
  207.         if ((tp = strchr(name, bracket)) == NULL) {
  208.         fprintf(stderr, "? Illegal file name \"%s\"\n",
  209.             pathname);
  210.         }
  211.         else {
  212.         strcpy(name, tp + 1);
  213.         }
  214.     }
  215.     for (tp = name; *tp != EOS; tp++) {
  216.         if (isupper(*tp))
  217.         *tp = tolower(*tp);
  218.     }
  219. #endif
  220. }
  221.  
  222. #ifdef    unix
  223. char *
  224. strrchr(stng, chr)
  225. register char    *stng;
  226. register char    chr;
  227. /*
  228.  * Return rightmost instance of chr in stng.
  229.  * This has the wrong name on some Unix systems.
  230.  */
  231. {
  232.     register char    *result;
  233.  
  234.     result = NULL;
  235.  
  236.     do {
  237.         if (*stng == chr)
  238.         result = stng;
  239.     } while (*stng++ != EOS);
  240.     return (result);
  241. }
  242. #endif
  243.  
  244. /*
  245.  * getredirection() is intended to aid in porting C programs
  246.  * to VMS (Vax-11 C) which does not support '>' and '<'
  247.  * I/O redirection.  With suitable modification, it may
  248.  * useful for other portability problems as well.
  249.  */
  250.  
  251. static int
  252. getredirection(argc, argv)
  253. int        argc;
  254. char        **argv;
  255. /*
  256.  * Process vms redirection arg's.  Exit if any error is seen.
  257.  * If getredirection() processes an argument, it is erased
  258.  * from the vector.  getredirection() returns a new argc value.
  259.  *
  260.  * Warning: do not try to simplify the code for vms.  The code
  261.  * presupposes that getredirection() is called before any data is
  262.  * read from stdin or written to stdout.
  263.  *
  264.  * Normal usage is as follows:
  265.  *
  266.  *    main(argc, argv)
  267.  *    int        argc;
  268.  *    char        *argv[];
  269.  *    {
  270.  *        argc = getredirection(argc, argv);
  271.  *    }
  272.  */
  273. {
  274. #ifdef    vms
  275.     register char        *ap;    /* Argument pointer    */
  276.     int            i;    /* argv[] index        */
  277.     int            j;    /* Output index        */
  278.     int            file;    /* File_descriptor     */
  279.  
  280.     for (j = i = 1; i < argc; i++) {   /* Do all arguments    */
  281.         switch (*(ap = argv[i])) {
  282.         case '<':            /* <file        */
  283.         if (freopen(++ap, "r", stdin) == NULL) {
  284.             perror(ap);        /* Can't find file    */
  285.             exit(IO_ERROR);    /* Is a fatal error    */
  286.         }
  287.  
  288.         case '>':            /* >file or >>file    */
  289.         if (*++ap == '>') {    /* >>file        */
  290.             /*
  291.              * If the file exists, and is writable by us,
  292.              * call freopen to append to the file (using the
  293.              * file's current attributes).  Otherwise, create
  294.              * a new file with "vanilla" attributes as if
  295.              * the argument was given as ">filename".
  296.              * access(name, 2) is TRUE if we can write on
  297.              * the specified file.
  298.              */
  299.             if (access(++ap, 2) == 0) {
  300.             if (freopen(ap, "a", stdout) != NULL)
  301.                 break;    /* Exit case statement    */
  302.             perror(ap);    /* Error, can't append    */
  303.             exit(IO_ERROR);    /* After access test    */
  304.             }            /* If file accessable    */
  305.         }
  306.         /*
  307.          * On vms, we want to create the file using "standard"
  308.          * record attributes.  create(...) creates the file
  309.          * using the caller's default protection mask and
  310.          * "variable length, implied carriage return"
  311.          * attributes. dup2() associates the file with stdout.
  312.          */
  313.         if ((file = creat(ap, 0, "rat=cr", "rfm=var")) == -1
  314.          || dup2(file, fileno(stdout)) == -1) {
  315.             perror(ap);        /* Can't create file    */
  316.             exit(IO_ERROR);    /* is a fatal error    */
  317.         }            /* If '>' creation    */
  318.         break;            /* Exit case test    */
  319.  
  320.         default:
  321.         argv[j++] = ap;        /* Not a redirector    */
  322.         break;            /* Exit case test    */
  323.         }
  324.     }                /* For all arguments    */
  325.     return (j);
  326. #else
  327.     /*
  328.      * Note: argv[] is referenced to fool the Decus C
  329.      * syntax analyser, supressing an unneeded warning
  330.      * message.
  331.      */
  332.     return (argv[0], argc);        /* Just return as seen    */
  333. #endif
  334. }
  335.  
  336.  
  337.  
  338.