home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 11 Util / 11-Util.zip / SHAR.ZIP / SHAR.C next >
C/C++ Source or Header  |  1989-12-19  |  14KB  |  583 lines

  1. /* 
  2.  *  Shar puts readable text files together in a package
  3.  *  from which they are easy to extract.
  4.  *
  5.  *    v 891212 J. Saxton for MSDOS and OS/2
  6.  *    - index() function changed to strchr() to comply with more
  7.  *      modern C compilers.
  8.  *
  9.  *    - eliminated several warning messages generated by the
  10.  *      Microsoft C compiler (version 5.1)
  11.  *
  12.  *    - compiled as a non-PM application for OS/2 and bound as a family
  13.  *      mode program for MSDOS.  Does wildcard expansion on input file
  14.  *      names.
  15.  *
  16.  *        cl /Ox shar.c c:\os2\lib\setargv.obj
  17.  *        bind shar c:\os2\lib\doscalls.lib
  18.  *
  19.  *    v 860716 M. Kersenbrock (tektronix!copper!michaelk) for Z80-CPM
  20.  *    - enhanced usage message
  21.  *
  22.  *    v 860712 D. Wecker for ULTRIX and the AMIGA
  23.  *    - stripped down.. does patterns but no directories
  24.  *    - added a -u (unshar) switch
  25.  */
  26.  
  27. /* #define CPM */
  28.  
  29. #ifdef MSDOS
  30. #define OS2
  31. #endif
  32.  
  33. #ifdef OS2
  34. #include <string.h>
  35. #include <ctype.h>
  36. #include <malloc.h>
  37. #include <stdlib.h>
  38. #endif
  39.  
  40. #ifdef CPM
  41. #include "c:stdio.h"
  42. #include "c:fcntl.h"
  43. #else
  44. #include <stdio.h>
  45. #endif
  46.  
  47.  
  48. #ifdef CPM
  49. #define void int
  50. #define fputc putc
  51. #define strchr index
  52. #define strrchr rindex
  53. extern char *getenv(),*malloc(),*strchr(),*strrchr();
  54. int cpmversion;
  55.  
  56. #endif
  57.  
  58. #ifdef    AMIGA
  59. #include <exec/types.h>
  60. extern char *getenv(),*scdir(),*malloc(),*strchr();
  61. #endif
  62.  
  63. #ifdef    ULTRIX
  64. #include <sys/types.h>
  65. extern char *getenv(),*scdir(),*malloc(),*strchr();
  66. #endif
  67.  
  68. #ifdef    VMS
  69. #include <types.h>
  70. extern char *getenv(),*scdir(),*malloc();
  71. #endif
  72.  
  73.  
  74. #define BADCH    ((int)'?')
  75. #define EMSG    ""
  76. #define tell(s)    {fputs(*nargv,stderr);fputs((s),stderr);fputc(optopt,stderr);fputc('\n',stderr);return(BADCH);}
  77. #define rescanopts()    (optind = 1)
  78.  
  79. int    optind = 1,        /* index into parent argv vector */
  80.     optopt;            /* character checked for validity */
  81. long    fsize;            /* length of file */
  82. char    *optarg;        /* argument associated with option */
  83. char    *sav[100];        /* saved file names */
  84. int    savind;            /* save index */
  85.  
  86. /* OPTIONS */
  87. int     Verbose = 0;           /* provide append/extract feedback */
  88. int     Basename = 0;          /* extract into basenames */
  89. int     Count = 0;             /* count characters to check transfer */
  90. char    *Delim = "SHAR_EOF";   /* put after each file */
  91. char    Filter[100] = "cat";   /* used to extract archived files */
  92. char    *Prefix = NULL;        /* line prefix to avoid funny chars */
  93. int    UnShar = 0;           /* do we unshar an input file? */
  94.  
  95. char Usage1[] = 
  96. "\nSHAR: Create/extract file archive for extraction by /bin/sh (normally).\n\
  97. \n\
  98. usage: shar [-u archive] [[-a] [-p prefix]\
  99.  [-d delim] [-bcv] files > archive]\n\
  100. \n\
  101.     where:    -a  all the options (v,c,b,-pXX)\n";
  102.  
  103. char Usage2[] = 
  104. "        -b  extract absolute paths into current directory\n\
  105.         -c  check filesizes on extraction\n\
  106.         -d  use this EOF delimiter instead of SHAR_EOF\n";
  107.  
  108. char Usage3[] =
  109. "        -p  use this as prefix to each line in archived files\n\
  110.         -u  unshar <archive>\n\
  111.         -v  verbose on extraction, incl. echoing filesizes\n";
  112.  
  113.  
  114. #define    SED "sed 's/^%s//'"    /* used to remove prefix from lines */
  115.  
  116. #ifdef CPM
  117. #define    OPTSTRING "U:AP:D:BCV"
  118. #else
  119. #define    OPTSTRING "u:ap:d:bcv"
  120. #endif
  121.  
  122. #ifdef    VMS
  123. char *strchr(s,c)
  124. char    *s;
  125. char    c;
  126. {
  127.     while (*s != 0 && *s != c) s++;
  128.     if (*s == 0 && *s != c) s = 0;
  129.     return(s);    
  130. }
  131. #endif
  132.  
  133. int header(ppchFiles)
  134. char *ppchFiles[];
  135. {
  136.     extern char *ctime();
  137.     register int i;
  138.     auto long clock;
  139.     register char **ppchList;
  140.     char *pchOrg;
  141.     char *pchName;
  142.     register int  problems = 0;
  143.  
  144.     pchOrg = getenv("ORGANIZATION");
  145.     pchName = getenv("NAME");
  146.  
  147.     puts("#\tThis is a shell archive.");
  148.     puts("#\tRemove everything above and including the cut line.");
  149.     puts("#\tThen run the rest of the file through sh.");
  150.     puts("#----cut here-----cut here-----cut here-----cut here----#");
  151.     puts("#!/bin/sh");
  152.     puts("# shar:    Shell Archiver");
  153.     puts("#\tRun the following text with /bin/sh to create:");
  154.     for (ppchList = ppchFiles; *ppchList; ++ppchList)
  155.         printf("#\t%s\n", *ppchList);
  156. #ifdef CPM
  157.   if (cpmversion >= 0x30) {
  158. #endif
  159.     (void) time(& clock);
  160.     printf("# This archive created: %s", ctime(&clock));
  161. #ifdef CPM
  162.   }
  163. #endif
  164.     if (pchName)
  165.         printf("# By:\t%s (%s)\n", pchName, 
  166.         pchOrg ? pchOrg : "Dave Wecker Midnight Hacks");
  167.     return(0);
  168. }
  169.  
  170. int archive(input, output)
  171. char *input, *output;
  172. {
  173.     auto char line[BUFSIZ];
  174.     register FILE *ioptr;
  175.  
  176.     if (ioptr = fopen(input, "r")) {
  177.         printf("%s << \\%s > %s\n", Filter, Delim, output);
  178.         while(fgets(line, BUFSIZ, ioptr)) {
  179.             if (Prefix) fputs(Prefix, stdout);
  180.             fputs(line, stdout);
  181.             if (Count) fsize += strlen(line);
  182.         }
  183.         puts(Delim);
  184.         (void) fclose(ioptr);
  185.         return(0);
  186.     } 
  187.     else {
  188.         fprintf(stderr, "shar: Can't open '%s'\n", input);
  189.         return(1);
  190.     }
  191. }
  192.  
  193.  
  194. void shar(file)
  195. char *file;
  196. {
  197.     register char *basefile;
  198.     basefile = file;
  199.     if (!strcmp(file, "."))
  200.         return;
  201.     fsize = 0;
  202.     if (Basename) {
  203.         while(*basefile)
  204.             basefile++;        /* go to end of name */
  205.         while(basefile > file && *(basefile-1) != '/')
  206.             basefile--;
  207.     }
  208.     if (Verbose) printf("echo shar: extracting %s\n", basefile);
  209.     if (archive(file, basefile)) exit(66);
  210.     if (Count) {
  211.         printf("if test %ld -ne \"`wc -c %s`\"\n",fsize,basefile);
  212.         printf("then\necho shar: error transmitting %s ",basefile);
  213.         printf("'(should have been %ld characters)'\nfi\n",fsize);
  214.     }
  215. }
  216.  
  217. int main(argc, argv)
  218. int argc;
  219. char **argv;    
  220. {
  221.     auto char *ppchFiles[256];
  222.     register int  C;
  223.     register char **ppchList = ppchFiles;
  224.     register int errflg = 0;
  225.  
  226. #ifdef CPM
  227.     cpmversion = (bdoshl(0x0c,0) & 0xff);
  228. #endif
  229.  
  230.     while(EOF != (C = getopt(argc, argv, OPTSTRING))) {
  231. #ifdef CPM
  232.         switch(isupper(C) ? tolower(C) : C ) {
  233. #else
  234.         switch(C) {
  235. #endif
  236.         case 'v': 
  237.             Verbose++; 
  238.             break;
  239.         case 'c': 
  240.             Count++; 
  241.             break;
  242.         case 'b': 
  243.             Basename++; 
  244.             break;
  245.         case 'd': 
  246.             Delim = optarg; 
  247.             break;
  248.         case 'a': /* all the options */
  249.             optarg = "XX";
  250.             Verbose++;
  251.             Count++;
  252.             Basename++;
  253.             /* fall through to set prefix */
  254.         case 'p': 
  255.             (void) sprintf(Filter, SED, Prefix = optarg); 
  256.             break;
  257.         case 'u':
  258.             UnShar++;
  259.             dounshar(optarg);
  260.             break;
  261.         default: 
  262.             errflg++;
  263.         }
  264.     }
  265.     if (UnShar) exit(0);
  266.  
  267.     C = getarg(argc, argv);
  268.     if (errflg || EOF == C) {
  269.         if (EOF == C)
  270.             fprintf(stderr, "shar: No input files\n");
  271.         fprintf(stderr, "%s%s%s", Usage1, Usage2, Usage3);
  272.         exit(1);
  273.     }
  274.  
  275.     savind = 0;
  276.     do {
  277.         if (getpat(optarg)) exit(2);
  278.     } 
  279.     while (EOF != (C = getarg(argc, argv)));
  280.  
  281.     sav[savind] = 0;
  282.     header(sav);
  283.     for (ppchList = sav; *ppchList; ++ppchList) {
  284.  
  285. #ifdef CPM
  286.      strlower(*ppchList);
  287. #endif
  288.  
  289.      shar(*ppchList);
  290.     }
  291.     puts("#\tEnd of shell archive");
  292.     puts("exit 0");
  293.     exit(0);
  294. }
  295.  
  296. getpat(pattern)
  297. char *pattern;
  298. {
  299.     register char *ptr;
  300.     int temp;
  301.  
  302. #ifdef AMIGA
  303.     while (ptr = scdir(pattern)) {
  304. #else
  305.     ptr = pattern;
  306.     {
  307. #endif
  308.     sav[savind] = malloc(strlen(ptr)+1);
  309.     strcpy(sav[savind++],ptr);
  310. #ifdef CPM
  311.     temp = open(ptr,O_RDONLY);
  312.     if (temp == -1) {
  313. #else
  314.     if (access(ptr,4)) {
  315. #endif
  316.         printf("No read access for file: %s\n",ptr);
  317.         return(-1);
  318.     }
  319.  
  320. #ifdef CPM
  321.     close(temp);
  322. #endif
  323.     }
  324.     return(0);
  325. }
  326.  
  327.  
  328. /*
  329.  * get option letter from argument vector
  330.  */
  331. int
  332. getopt(nargc, nargv, ostr)
  333. int nargc;
  334. char **nargv, *ostr;
  335. {
  336.     register char    *oli;        /* option letter list index */
  337.     static char    *place = EMSG;    /* option letter processing */
  338.     if(!*place) {            /* update scanning pointer */
  339.         if(optind >= nargc || *(place = nargv[optind]) != '-' || !*++place)
  340.          return(EOF);
  341.         if (*place == '-') {    /* found "--" */
  342.             ++optind;
  343.             return EOF;
  344.         }
  345.     }                /* option letter okay? */
  346.     if ((optopt = (int)*place++) == (int)':' || !(oli = strchr(ostr,optopt))) {
  347.         if(!*place) ++optind;
  348.         tell(": illegal option -- ");
  349.     }
  350.     if (*++oli != ':') {        /* don't need argument */
  351.         optarg = NULL;
  352.         if (!*place)
  353.             ++optind;
  354.     } 
  355.     else {                /* need an argument */
  356.         if (*place) {            /* no white space */
  357.             optarg = place;
  358.         } 
  359.         else {
  360.         if (nargc <= ++optind) {    /* no arg */
  361.                     place = EMSG;
  362.                     tell(": option requires an argument -- ");
  363.                 }
  364.             else {
  365.                 optarg = nargv[optind];    /* white space */
  366.         }
  367.         }
  368.         place = EMSG;
  369.         ++optind;
  370.     }
  371.     return(optopt);            /* dump back option letter */
  372. }
  373.  
  374.  
  375. int
  376. getarg(nargc, nargv)
  377. int nargc;
  378. char **nargv;
  379. {
  380.     if (nargc <= optind) {
  381.         optarg = (char *) 0;
  382.         return EOF;
  383.     } 
  384.     else {
  385.         optarg = nargv[optind++];
  386.         return 0;
  387.     }
  388. }
  389.  
  390. dounshar(ArcNam)
  391. char *ArcNam;
  392. {
  393.     register int i,j;
  394.     register FILE *inptr,*outptr;
  395.     auto char line[BUFSIZ];
  396.     int DirNum = -1;
  397.     int Prefix = 0;
  398.     char Dirs[5][40],FilNam[128],Delim[40],ScrStr[128];
  399.     char *ptr;
  400.  
  401.     if (!(inptr = fopen(ArcNam,"r"))) {
  402.         fprintf(stderr,"shar: Can't open archive '%s'\n", ArcNam);
  403.         return;
  404.     }
  405.     while (fgets(line,BUFSIZ,inptr)) {
  406.         if (strncmp(line,"sed ",4) == 0) {
  407.             Prefix = 0;
  408.             if (!(ptr = strchr(line,'/'))) goto getfil;
  409.             if (*++ptr == '^') ++ptr;
  410.             while (*ptr++ != '/') Prefix++;
  411.             goto getfil;
  412.         }
  413.         else if (strncmp(line,"cat ",4) == 0) {
  414.             Prefix = 0;
  415.             ;
  416. getfil:
  417.  
  418. #ifdef    VMS
  419.             strcpy(FilNam,"[");
  420. #else
  421.             FilNam[0] = 0;
  422. #endif
  423.  
  424.             for (i = 0; i <= DirNum; i++) {
  425.  
  426. #ifdef    VMS
  427.                 strcat(FilNam,".");
  428.                 strcat(FilNam,Dirs[i]);
  429. #else
  430.                 strcat(FilNam,Dirs[i]);
  431.                 strcat(FilNam,"/");
  432. #endif
  433.  
  434.             }
  435.  
  436.  
  437. #ifdef    VMS
  438.             strcat(FilNam,"]");
  439. #endif
  440.  
  441.             getshpar(line,">",ScrStr);
  442.             strcat(FilNam,ScrStr);
  443.  
  444. #ifdef CPM
  445.         tocpmformat(FilNam);    /* tweek format as needed */
  446. #endif
  447.             getshpar(line,"<<",Delim);
  448.             fprintf(stderr,"Creating %s ...",FilNam);
  449.             outptr = fopen(FilNam,"w");
  450.             while (fgets(line,BUFSIZ,inptr)) {
  451.                 if (strncmp(line,Delim,strlen(Delim)) == 0) break;
  452.                 if (outptr) fputs(&line[Prefix],outptr);
  453.             }
  454.             if (outptr) {
  455.                 fclose(outptr);
  456.                 fprintf(stderr,"...done\n");
  457.             }
  458.             else fprintf(stderr,"...error in creating file\n");
  459.         }
  460.         else if (strncmp(line,"mkdir ",6) == 0) {
  461.             fprintf(stderr,"Need to make directory: %s\n",&line[6]);
  462.         }
  463.         else if (strncmp(line,"chdir ",6) == 0) {
  464.             if (line[6] == '.' && line[7] == '.') DirNum--;
  465.             else strcpy(Dirs[++DirNum],&line[6]);
  466.             if (DirNum < -1) DirNum = -1;
  467.         }
  468.         else if (strncmp(line,"cd ",3) == 0) {
  469.             if (line[3] == '.' && line[4] == '.') DirNum--;
  470.             else strcpy(Dirs[++DirNum],&line[3]);
  471.             if (DirNum < -1) DirNum = -1;
  472.         }
  473.     }
  474.     fclose(inptr);
  475. }
  476.  
  477. getshpar(line,sea,par)
  478. char *line,*sea,*par;
  479. {
  480.     register int i,j,k;
  481.     register char *scr1,*scr2;
  482.  
  483.     while (*line) {
  484.         scr1 = line;
  485.         scr2 = sea;
  486.         while (*scr1 && *scr2 && *scr1 == *scr2) { 
  487.             scr1++; 
  488.             scr2++; 
  489.         }
  490.         if (*scr2 == 0) {
  491.             if (*scr1 == 0) { 
  492.                 *par = 0; 
  493.                 return; 
  494.             }
  495.             while ( *scr1 == ' ' || *scr1 == '\t' ||
  496.                 *scr1 == '\\' || *scr1 == '\'' || *scr1 == '"') scr1++;
  497.             while ( *scr1 != 0 && *scr1 != ' ' && *scr1 != '\t' &&
  498.                 *scr1 != '\\' && *scr1 != '\'' && *scr1 != '"' &&
  499.                 *scr1 != '\n' && *scr1 != '\r') *par++ = *scr1++;
  500.             *par = 0;
  501.             return;
  502.         }
  503.         line++;
  504.     }
  505.     *par = 0;
  506. }
  507.  
  508.  
  509. #ifdef CPM
  510.  
  511. tocpmformat(filename)
  512. char *filename;
  513. {
  514.     char buffer[100];
  515.     char extension[100];
  516.     register char *temp;
  517.     int mod = 0;
  518.  
  519.     strcpy(buffer,filename);
  520.  
  521.     /* 
  522.       * Make sure we get rid of any pathnames
  523.      */
  524.     if ((temp=strrchr(buffer,'/')) != 0) {
  525.         strcpy(buffer,(char *)((temp-buffer)+filename+1));
  526.         mod = 1;
  527.     }
  528.  
  529.     if (strlen(filename) <= 8) {
  530.         if (mod != 0) {
  531.             strcpy(filename,buffer);
  532.         }
  533.         return(0);
  534.     }
  535.  
  536.     /*
  537.      * If it already is in "CPM" format we'll check if we need
  538.      * to truncate the front filename part.
  539.      */
  540.     if ((temp=strchr(buffer,'.')) != 0 ) {
  541.         if ((temp-buffer) < 8) {
  542.             if (mod != 0) {
  543.                 strcpy(filename,buffer);
  544.             }
  545.             return(0);
  546.         }
  547.         else {
  548.             strcpy(extension,temp);
  549.             strcpy(&buffer[8],extension);
  550.             buffer[12] = '\0';
  551.             strcpy(filename,buffer);
  552.             return(1);
  553.         }
  554.     }
  555.             
  556.     /*
  557.      * OK, filename is longer than can be handled, and it doesnt have
  558.      * a filetype "." marker already.  We will put one in to minimize
  559.      * truncation.
  560.      */
  561.     strcpy(extension,&buffer[8]);
  562.     buffer[8] = '.';
  563.     strcpy(&buffer[9],extension);
  564.     buffer[12] = '\0';
  565.     strcpy(filename,buffer);
  566.     return(2);
  567. }
  568.  
  569.  
  570.     
  571. strlower(string)
  572. char *string;
  573. {
  574.     register char *pointer;
  575.     char c;
  576.     for (pointer = string ; (c=*pointer) != '\0' ; pointer++ ) {
  577.         if (isupper(c))
  578.             *pointer = tolower(c);
  579.     }
  580. }
  581.  
  582. #endif
  583.