home *** CD-ROM | disk | FTP | other *** search
/ The C Users' Group Library 1994 August / wc-cdrom-cusersgrouplibrary-1994-08.iso / vol_200 / 265_01 / cugcpio.c < prev    next >
Text File  |  1990-02-15  |  12KB  |  489 lines

  1. /*
  2.  *    c u g c p i o . c
  3.  *    -----------------
  4.  *    The CUG Data Exchange Format Archive Creator/Extractor.
  5.  *
  6.  *    Written by    Rainer Gerhards
  7.  *            Petronellastr. 6
  8.  *            D-5112 Baesweiler
  9.  *            West Germany
  10.  *
  11.  *            Phone (West Germany) 2401 - 1601
  12.  *
  13.  *    release history
  14.  *    ---------------
  15.  *    Mar 26, 1988    begin implementation
  16.  *    Nov 16, 1988    switches d and p added
  17.  */
  18. #include "environ.h"
  19. #include <stdio.h>
  20. #include <ctype.h>
  21.  
  22.  
  23. /*
  24.  *    preprocessor constants
  25.  *    ----------------------
  26.  */
  27. #define    VERSION        2        /* current program version    */
  28. #define    MAGIC        070707        /* magic archive number        */
  29. #define    TRAILER        "TRAILER!!!"    /* trailer file name        */
  30. #define    MAKEFILE    "makefile"    /* name of makefiles        */
  31. #define    FILLCHR        '\032'        /* block fill character        */
  32. #define    MAXNMSZ        100        /* longest possible file name    */
  33. #define    BUFSIZE        512        /* C-library max buffer size    */
  34. #define    TABCOLS        8        /* OS tab settings        */
  35. #define    BLOCKSZ        512        /* output block size        */
  36.  
  37. /*
  38.  * The following defines describe the processing modes. They are
  39.  * mainly used to avoid enums.
  40.  */
  41. #define    CREATE        0
  42. #define    EXTRACT        1
  43. #define    CATALOG        2
  44.  
  45. /*
  46.  *    static data
  47.  *    -----------
  48.  */
  49. STATIC FILE    *archive;        /* archive file pointer        */
  50. STATIC char    opn_mode[8];        /* archive file open mode    */
  51. STATIC int    procmode = CATALOG;    /* processing mode        */
  52. STATIC int    verbose = FALSE;    /* verbose output        */
  53. STATIC int    silent = FALSE;        /* totally silent mode        */
  54. STATIC int    exptab = FALSE;        /* expand tabulation stops    */
  55. STATIC int    convert = FALSE;    /* do several conversions    */
  56. STATIC int    makeflok = FALSE;    /* look for makefiles        */
  57. STATIC int    ignpath = FALSE;    /* ignore path names in archive */
  58. STATIC int    destroy = FALSE;    /* destroy existing files    */
  59.  
  60. /*
  61.  *    functions
  62.  *    ---------
  63.  */
  64.  
  65.  
  66. /*---------------------------------------------------------------------------
  67.  * Display usage information. This function terminates the program!
  68.  */
  69. void        usage()
  70. {
  71. fprintf(stderr, "Usage:\tcugcpio -[i|o|t][cdempsv] archive [files...]\n");
  72. fprintf(stderr, "\nprocessing modes:\n");
  73. fprintf(stderr, "i\textract files\n");
  74. fprintf(stderr, "o\tcreate archive\n");
  75. fprintf(stderr, "t\tlist archive directory\n");
  76. fprintf(stderr, "\nprocessing modifiers (options):\n");
  77. fprintf(stderr, "c\tdo several conversions\n");
  78. fprintf(stderr, "d\tsilently overwrite existing files on extract\n");
  79. fprintf(stderr, "e\texpand horizontal tabs (input only)\n");
  80. fprintf(stderr, "m\tdon't expand HTs in makefiles\n");
  81. fprintf(stderr, "p\tignore stored path name\n");
  82. fprintf(stderr, "s\tsilent operation - no messages displayed\n");
  83. fprintf(stderr, "v\tverbose listing\n");
  84. exit(2);
  85. /*NOTREACHED*/
  86. }
  87.  
  88.  
  89. /*---------------------------------------------------------------------------
  90.  * Check if file is existent. We assume it isn't, if we can't open it.
  91.  * This may not be the safest method, but it should be the most portable one.
  92.  */
  93. int        exist(file)
  94. char        *file;
  95. {
  96. FILE        *fp;
  97. int        ret;
  98.  
  99. ret = ((fp = fopen(file, OPM_RT)) == NULL) ? 0 : 1;
  100. if(ret)
  101.     fclose(fp);
  102. return(ret);
  103. }
  104.  
  105.  
  106. /*---------------------------------------------------------------------------
  107.  * Test if character is pathname-delimiter. Returns 1 if yes, 0 otherwise.
  108.  */
  109. STATIC int    pathdelm(c)
  110. int        c;
  111. {
  112. int        state;
  113.  
  114. if((c == '/') || (c == '\\'))
  115.     state = 1;    /* delemiter found!    */
  116. else
  117.     state = 0;
  118. return(state);
  119. }
  120.  
  121.  
  122. /*---------------------------------------------------------------------------
  123.  * Get filename only (path stripped).
  124.  */
  125. STATIC char    *nameonly(cp)
  126. register char    *cp;
  127. {
  128. register char    *orgcp;
  129.  
  130. for(orgcp = cp ; *cp ; ++cp)
  131.     ;        /* search end of string        */
  132. for( ; !pathdelm(*cp) && (cp != orgcp) ; --cp)
  133.     ;        /* search path delemiter    */
  134. if(pathdelm(*cp))
  135.     ++cp;
  136. return(cp);
  137. }
  138.  
  139.  
  140. /*---------------------------------------------------------------------------
  141.  * Get pathname only (filename stripped).
  142.  */
  143. STATIC char    *pathonly(cp)
  144. char        *cp;
  145. {
  146. register int    i;
  147. register char    *endcp;
  148. static char    pathname[MAXNMSZ];
  149.  
  150. endcp = nameonly(cp);
  151. for(i = 0 ; cp != endcp ; ++cp, ++i)
  152.     pathname[i] = *cp;
  153. pathname[i] = '\0';
  154. return(pathname);
  155. }
  156.  
  157.  
  158. /*---------------------------------------------------------------------------
  159.  * Convert String to lower case.
  160.  */
  161. STATIC void    lowerstr(cp)
  162. register char    *cp;
  163. {
  164. for( ; *cp ; ++cp)
  165.     if(isupper(*cp))
  166.         *cp = tolower(*cp);
  167. }
  168.  
  169.  
  170. /*---------------------------------------------------------------------------
  171.  * Set operation modes according to switch characters. If an error is
  172.  * detected in them the usage message is displayed and the program terminates.
  173.  */
  174. STATIC void    setmodes(sw)
  175. register char    *sw;
  176. {
  177. while(*sw)
  178.     switch(*sw++)
  179.         {
  180.         case 'o':    procmode = CREATE;    /* output    */
  181.                 strcpy(opn_mode, OPM_WB);
  182.                 break;
  183.         case 'i':    procmode = EXTRACT;    /* input    */
  184.                 strcpy(opn_mode, OPM_RB);
  185.                 break;
  186.         case 't':    procmode = CATALOG;    /* catalog    */
  187.                 strcpy(opn_mode, OPM_RB);
  188.                 break;
  189.         case 'v':    verbose = TRUE;        /* verbose     */
  190.                 break;
  191.         case 's':    silent = TRUE;        /* total silent    */
  192.                 break;
  193.         case 'c':    convert = TRUE;        /* conversion    */
  194.                 break;
  195.         case 'e':    exptab = TRUE;        /* expand HT    */
  196.                 break;
  197.         case 'm':    makeflok = TRUE;    /* makefile opt    */
  198.                 break;
  199.         case 'p':    ignpath = TRUE;        /* ignore path    */
  200.                 break;
  201.         case 'd':    destroy = TRUE;        /* destroy files*/
  202.                 break;
  203.         default:    usage();
  204.                 /*NOTREACHED*/
  205.         }
  206. }
  207.  
  208.  
  209. /*---------------------------------------------------------------------------
  210.  * Write archive file header
  211.  */
  212. void        wrthead(name, textsize)
  213. register char    *name;
  214. long        textsize;
  215. {
  216. fprintf(archive,
  217.        "%6.6o%6.6o%6.6o%6.6o%6.6o%6.6o%6.6o%6.6o%11.11lo%6.6o%11.11lo",
  218.        MAGIC, 0, 0, 0100666, 0, 0, 1, 0, 0l, strlen(name) + 1, textsize);
  219. for( ; *name ; ++name)
  220.     fputc(((convert == TRUE) && islower(*name)) ? toupper(*name) : *name,
  221.            archive);
  222. fputc('\0', archive);
  223. }
  224.  
  225.  
  226. /*---------------------------------------------------------------------------
  227.  * Read archive file header. Returns TRUE if read head was trailer record
  228.  * otherwise FALSE. If the magic number is incorrect, an error message is
  229.  * generated and the program terminated.
  230.  */
  231. STATIC int    get_head(name, textsize)
  232. char        *name;
  233. long        *textsize;
  234. {
  235. register char    *cp;
  236. int        magic;
  237. int        namesize;
  238. int        retval;
  239.  
  240. fscanf(archive, "%6o%*6o%*6o%*6o%*6o%*6o%*6o%*6o%*11lo%6o%11lo",
  241.       &magic, &namesize, textsize);
  242. if(magic == 070707)
  243.     {
  244.     cp = name;
  245.     while(namesize--)
  246.         *cp++ = fgetc(archive);
  247.     *cp = '\0';
  248.     }
  249. else
  250.     {
  251.     fprintf(stderr, "ERROR: Archive file inconsistency, magic = %6.6o\n");
  252.     exit(1);
  253.     }
  254. retval = ((*textsize == 0l) && (!strcmp(name, TRAILER))) ? TRUE : FALSE;
  255. if(convert == TRUE)
  256.     lowerstr(name);
  257. return(retval);
  258. }
  259.  
  260.  
  261. /*---------------------------------------------------------------------------
  262.  * Skip n bytes of the input archive file.
  263.  */
  264. STATIC void    skipinp(n)
  265. long        n;
  266. {
  267. fseek(archive, n, 1);
  268. }
  269.  
  270.  
  271. /*---------------------------------------------------------------------------
  272.  * Write single file to archive.
  273.  */
  274. void        wrtout(fil)
  275. char        *fil;
  276. {
  277. register FILE    *fp;
  278. register int    c;
  279. int        i;
  280. int        curcol = 0;
  281. long        headpos;
  282. long        textsize = 0l;
  283. long        nonascii = 0l;
  284. long        nonprint = 0l;
  285.  
  286. if((fp = fopen(fil, "r")) == NULL)
  287.     fprintf(stderr, "ERROR: Can't open %s\n", fil);
  288. else
  289.     {
  290.     headpos = ftell(archive);
  291.     /* The following written dummy header becomes updated at end of
  292.        processing. The actual file size isn't known at this moment. */
  293.     wrthead(fil, 0l);
  294.     /* copy file */
  295.     while((c = fgetc(fp)) != EOF)
  296.         {
  297.         if((c == '\t') && (exptab == TRUE))
  298.             {
  299.             i = TABCOLS - (curcol % TABCOLS);
  300.             textsize = textsize + i;
  301.             curcol += i;
  302.             while(i--)
  303.                 fputc(' ', archive);
  304.             }
  305.         else
  306.             {
  307.             if(c == '\n')
  308.                 curcol = 0;
  309.             else
  310.                 ++curcol;
  311.             if(!isascii(c))
  312.                 ++nonascii;
  313.             else if(!isprint(c) && (c != '\n'))
  314.                 ++nonprint;
  315.             fputc(c, archive);
  316.             ++textsize;
  317.             }
  318.         }
  319.     /* copy done, update header */
  320.     fseek(archive, headpos, 0);    /* go back to update header    */
  321.     wrthead(fil, textsize);
  322.     fseek(archive, 0l, 2);        /* back to eof            */
  323.     if(   (silent == FALSE)
  324.        && ((verbose == TRUE) || (nonascii > 0l) || (nonprint > 0l))
  325.       )
  326.         {
  327.         fprintf(stderr, "%s: %ld byte", fil, textsize);
  328.         if(nonascii > 0l)
  329.             fprintf(stderr, ", %ld non-ascii", nonascii);
  330.         if(nonprint > 0l)
  331.             fprintf(stderr, ", %ld non-printable", nonprint);
  332.         fprintf(stderr, ".\n");
  333.         }
  334.     }
  335. fclose(fp);
  336. }
  337.  
  338.  
  339. /*---------------------------------------------------------------------------
  340.  * Write trailer record.
  341.  */
  342. void        wrttrail()
  343. {
  344. int    i = 512;    /* for compatibility with Unix cpio        */
  345.  
  346. wrthead(TRAILER, 0l);
  347. i = BLOCKSZ - ftell(archive) % BLOCKSZ;
  348. while(i--)
  349.     fputc(FILLCHR, archive);
  350. }
  351.  
  352.  
  353. /*---------------------------------------------------------------------------
  354.  * Print archive file table of contents. No output files are created.
  355.  */
  356. STATIC void    prnt_toc()
  357. {
  358. long        size;
  359. char        name[MAXNMSZ];
  360.  
  361. if(verbose == TRUE)
  362.     printf("  Size - Name\n");
  363. while(get_head(name, &size) != TRUE)    /* while(not TRAILER read)    */
  364.     {
  365.     if(ignpath)
  366.         printf("%6ld - [%s] %s\n", size, pathonly(name),
  367.             nameonly(name));
  368.     else
  369.         printf("%6ld - %s\n", size, name);
  370.     skipinp(size);
  371.     }
  372. }
  373.  
  374.  
  375. /*---------------------------------------------------------------------------
  376.  * Extract whole archive file. The extracted files are ctreated in the
  377.  * current working directory.
  378.  */
  379. STATIC void    extract()
  380. {
  381. register FILE    *fp;
  382. long        size;
  383. char        *fname;
  384. char        name[MAXNMSZ];
  385. char        linebuf[BUFSIZE];
  386.  
  387. while(get_head(name, &size) != TRUE)    /* while(not TRAILER read)    */
  388.     {
  389.     if(verbose == TRUE)
  390.         if(ignpath)
  391.             printf("[%s] %s: %ld bytes\n", pathonly(name),
  392.                 nameonly(name), size);
  393.         else
  394.             printf("%s: %ld bytes\n", name, size);
  395.     if(ignpath)
  396.         fname = nameonly(name);
  397.     else
  398.         fname = name;
  399.     if((destroy == FALSE) && exist(fname))
  400.         {
  401.         fprintf(stderr, "File %s exists - overwrite (y/n)? ", fname);
  402.         gets(linebuf);
  403.         if(tolower(*linebuf) != 'y')
  404.             {
  405.             /*
  406.              * file can't be written, so 1. skip input,
  407.              * 2. start new cycle.
  408.              */
  409.             skipinp(size);
  410.             continue;     
  411.             }
  412.         }
  413.     if((fp = fopen(fname, OPM_WT)) == NULL)
  414.         {
  415.         fprintf(stderr, "ERROR: Can't output to %s - skipped\n", name);
  416.         skipinp(size);
  417.         }
  418.     else
  419.         {
  420.         while(size--)
  421.             fputc(fgetc(archive), fp);
  422.         fclose(fp);
  423.         }
  424.     }
  425. }
  426.  
  427.  
  428. /*---------------------------------------------------------------------------
  429.  * control module
  430.  */
  431. int        main(argc, argv)
  432. int        argc;
  433. char        **argv;
  434. {
  435. int        exptabsv;
  436.  
  437. if(argc == 1)
  438.     usage();
  439. --argc;                    /* programm name not used    */
  440. if(**++argv == '-')            /* switch character given?    */
  441.     setmodes((*argv) + 1);        /* yes -> set modes        */
  442. else
  443.     usage();            /* no -> terminate        */
  444. if(silent == TRUE)            /* silent mode overrides    */
  445.     verbose = FALSE;        /* verbose mode            */
  446. if(verbose == TRUE)
  447.     {
  448.     fprintf(stderr,
  449.           "The CUG Data Exchange Format Archive File Creator/Extractor.\n");
  450.     fprintf(stderr, "Written by Rainer Gerhards, Version %d.\n\n", VERSION);
  451.     }
  452. --argc;                    /* switches processed        */
  453. if((archive = fopen(*++argv, opn_mode)) == NULL)
  454.     {
  455.     fprintf(stderr, "ERROR: Can't open/create archive file %s\n");
  456.     exit(1);
  457.     /*NOTREACHED*/
  458.     }
  459. if(procmode == CREATE)
  460.     {
  461.     while(--argc)
  462.         {
  463.         ++argv;            /* next argument        */
  464.         if((makeflok == TRUE) && !strcmp(*argv, MAKEFILE))
  465.             {
  466.             exptabsv = exptab;
  467.             exptab = FALSE;
  468.             wrtout(*argv);
  469.             exptab = exptabsv;
  470.             }
  471.         else
  472.             wrtout(*argv);
  473.         }
  474.     wrttrail();
  475.     }
  476. else if(procmode == CATALOG)
  477.     prnt_toc();
  478. else if(procmode == EXTRACT)
  479.     extract();
  480. else
  481.     {
  482.     fprintf(stderr, "ERROR: Program logic fault, invalid procmode %d\n",
  483.         procmode);
  484.     exit(1);
  485.     }
  486. fclose(archive);
  487. return(0);
  488. }
  489.