home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 9 Archive / 09-Archive.zip / SHAROS2.ZIP / SHAR.C < prev    next >
C/C++ Source or Header  |  1991-12-25  |  12KB  |  544 lines

  1. /*------------------------------------------------------------------------------
  2.  
  3.     The UNIX program 'shar' (from "shell archive") puts readable text files
  4.     together in a package from which they are easy to extract by feeding the
  5.     package to 'sh'.
  6.  
  7.     Like its predecessors, this OS/2 implementation of shar builds shell
  8.     archives but is also capable of decomposing them in the absence of the
  9.     Bourne shell.  It is thus a useful tool for dealing with shell archives
  10.     created on UNIX systems.
  11.  
  12.     v 911225    J. Saxton
  13.     -    Corrected a problem in mkdir when directory name was NOT quoted.
  14.     -    Tidied up reporting of directory operations.
  15.  
  16.     v 911205    J. Saxton
  17.     -    This version strictly for OS/2 HPFS.  No longer is any attempt made
  18.         to rectify file names for FAT or CP/M file systems.  Code for VMS
  19.         has been deleted.  Code for ULTRIX and the Amiga has been retained
  20.         without verification.
  21.     -    Detect directories and don't try to add them to archives.
  22.         (Maybe next version will allow recursion into directories?)
  23.     -    Added dequote() function to normalize directory names.
  24.     -    Generated a Makefile and a definitions file.
  25.     -    made -pX the default pattern instead of -pXX.
  26.     -    fixed 'unshar' operation to ignore leading blanks.
  27.     -    tidied up source so it now compiles with MSC 6.0A at -W3 without
  28.         complaint.
  29.  
  30.     v 910525    J. Saxton for OS/2 2.0 and HPFS 
  31.  
  32.     v 891212    J. Saxton for MSDOS and OS/2
  33.     -    index() function changed to strchr() to comply with more modern C
  34.         compilers. 
  35.     -    eliminated several warning messages generated by the Microsoft C
  36.         compiler (version 5.1) 
  37.     -    compiled as a non-PM application for OS/2 and bound as a family mode
  38.         program for MSDOS.  Does wildcard expansion on input file names. 
  39.  
  40.             cl /Ox /Fb shar.c c:\os2\lib\setargv.obj
  41.  
  42.     v 860716    M. Kersenbrock (tektronix!copper!michaelk) for Z80-CPM
  43.     -    enhanced usage message 
  44.  
  45.     v 860712    D. Wecker for ULTRIX and the AMIGA
  46.     -    stripped down..does patterns but no directories
  47.     -    added a -u (unshar) switch 
  48.  
  49. ------------------------------------------------------------------------------*/
  50.  
  51. #ifdef MSDOS
  52. #define OS2
  53. #endif
  54.  
  55. #ifdef OS2
  56. #include <string.h>
  57. #include <ctype.h>
  58. #include <malloc.h>
  59. #include <stdlib.h>
  60. #include <direct.h>
  61. #include <sys/types.h>
  62. #include <sys/stat.h>
  63. #endif
  64.  
  65. #include <stdio.h>
  66. #include <io.h>
  67. #include <time.h>
  68. #include <errno.h>
  69.  
  70. #ifdef    AMIGA
  71. #include <exec/types.h>
  72. extern char *getenv(), *scdir(), *malloc(), *strchr();
  73. #endif
  74.  
  75. #ifdef    ULTRIX
  76. #include <sys/types.h>
  77. #include <sys/stat.h>
  78. extern char *getenv(), *scdir(), *malloc(), *strchr();
  79. #endif
  80.  
  81. int
  82.     getopt(int, char **, char *),
  83.     getpat(char *),
  84.     getarg(int, char **);
  85. void
  86.     dounshar(char *),
  87.     getshpar(char *, char *, char *),
  88.     dequote(char *);
  89.  
  90. #define BADCH    ((int)'?')
  91. #define EMSG    ""
  92. #define tell(s)    {fputs(*nargv,stderr);fputs((s),stderr);fputc(optopt,stderr);fputc('\n',stderr);return(BADCH);}
  93. #define rescanopts()    (optind = 1)
  94.  
  95. int optind = 1,                    /* index into parent argv vector */
  96.     optopt;                        /* character checked for validity */
  97. long fsize;                        /* length of file */
  98. char *optarg;                    /* argument associated with option */
  99. char *sav[100];                    /* saved file names */
  100. int savind;                        /* save index */
  101.  
  102. /* OPTIONS */
  103. int Verbose = 0;                /* provide append/extract feedback */
  104. int Basename = 0;                /* extract into basenames */
  105. int Count = 0;                    /* count characters to check transfer */
  106. char *Delim = "SHAR_EOF";        /* put after each file */
  107. char Filter[100] = "cat";        /* used to extract archived files */
  108. char *Prefix = NULL;            /* line prefix to avoid funny chars */
  109. int UnShar = 0;                    /* do we unshar an input file? */
  110.  
  111. char Usage1[] =
  112. "\nSHAR: Create/extract file archive for extraction by /bin/sh (normally).\n\
  113. \n\
  114. usage: shar [-u archive] [[-a] [-p prefix]\
  115.  [-d delim] [-bcv] files > archive]\n\
  116. \n\
  117.     where:    -a  all the options (v,c,b,-pX)\n";
  118.  
  119. char Usage2[] =
  120. "        -b  extract absolute paths into current directory\n\
  121.         -c  check filesizes on extraction\n\
  122.         -d  use this EOF delimiter instead of SHAR_EOF\n";
  123.  
  124. char Usage3[] =
  125. "        -p  use this as prefix to each line in archived files\n\
  126.         -u  unshar <archive>\n\
  127.         -v  verbose on extraction, incl. echoing filesizes\n";
  128.  
  129. struct stat
  130.     FileInfo;
  131.  
  132. #define    SED "sed 's/^%s//'"
  133.  
  134. #define    OPTSTRING "u:ap:d:bcv"
  135.  
  136. int header(char **ppchFiles)
  137. {
  138.     auto long clock;
  139.     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.  
  157.     (void) time(&clock);
  158.     printf("# This archive created: %s", ctime(&clock));
  159.  
  160.     if (pchName != NULL)
  161.         printf("# By:\t%s (%s)\n", pchName,
  162.                pchOrg == NULL ? "Dave Wecker Midnight Hacks" : pchOrg);
  163.     return (0);
  164. }
  165.  
  166. int archive(char *input, char *output)
  167. {
  168.     auto char line[BUFSIZ];
  169.     register FILE *ioptr;
  170.  
  171.     if (ioptr = fopen(input, "r"))
  172.     {
  173.         printf("%s << \\%s > %s\n", Filter, Delim, output);
  174.         while (fgets(line, BUFSIZ, ioptr))
  175.         {
  176.             if (Prefix)
  177.                 fputs(Prefix, stdout);
  178.             fputs(line, stdout);
  179.             if (Count)
  180.                 fsize += strlen(line);
  181.         }
  182.         puts(Delim);
  183.         (void) fclose(ioptr);
  184.         return (0);
  185.     }
  186.     else
  187.     {
  188.         fprintf(stderr, "shar: Can't open '%s'\n", input);
  189.         return (1);
  190.     }
  191. }
  192.  
  193. void shar(char *file)
  194. {
  195.     char *basefile;
  196.  
  197.     if (!strcmp(file, "."))
  198.         return;
  199.     fsize = 0;
  200.     if (stat(file, &FileInfo))
  201.     {
  202.         fprintf(stderr,"Unable to do a stat() on '%s'\n", file);
  203.         return;
  204.     }
  205.     if (FileInfo.st_mode & S_IFMT != S_IFREG)
  206.     {
  207.         basefile = "strange file";
  208.         if (FileInfo.st_mode & S_IFCHR)
  209.             basefile = "character special file";
  210.         if (FileInfo.st_mode & S_IFDIR)
  211.             basefile = "directory";
  212.         fprintf(stderr,"Cannot archive %s '%s'\n", basefile, file);
  213.         return;
  214.     }
  215.  
  216.     basefile = file;
  217.     if (Basename)
  218.     {
  219.         while (*basefile)
  220.             basefile++;            /* go to end of name */
  221.         while (basefile > file && *(basefile - 1) != '/')
  222.             basefile--;
  223.     }
  224.     if (Verbose)
  225.         printf("echo shar: extracting %s\n", basefile);
  226.     if (archive(file, basefile))
  227.         exit(66);
  228.     if (Count)
  229.     {
  230.         printf("if test %ld -ne \"`wc -c %s`\"\n", fsize, basefile);
  231.         printf("then\necho shar: error transmitting %s ", basefile);
  232.         printf("'(should have been %ld characters)'\nfi\n", fsize);
  233.     }
  234. }
  235.  
  236. void main(int argc, char *argv[])
  237. {
  238.     auto char *ppchFiles[256];
  239.     register int C;
  240.     register char **ppchList = ppchFiles;
  241.     register int errflg = 0;
  242.  
  243.     while (EOF != (C = getopt(argc, argv, OPTSTRING)))
  244.     {
  245.         switch (C)
  246.         {
  247.         case 'v':
  248.             Verbose++;
  249.             break;
  250.         case 'c':
  251.             Count++;
  252.             break;
  253.         case 'b':
  254.             Basename++;
  255.             break;
  256.         case 'd':
  257.             Delim = optarg;
  258.             break;
  259.         case 'a':                /* all the options */
  260.             optarg = "X";
  261.             Verbose++;
  262.             Count++;
  263.             Basename++;
  264.             /* fall through to set prefix */
  265.         case 'p':
  266.             (void) sprintf(Filter, SED, Prefix = optarg);
  267.             break;
  268.         case 'u':
  269.             UnShar++;
  270.             dounshar(optarg);
  271.             break;
  272.         default:
  273.             errflg++;
  274.         }
  275.     }
  276.     if (UnShar)
  277.         exit(0);
  278.  
  279.     C = getarg(argc, argv);
  280.     if (errflg || EOF == C)
  281.     {
  282.         if (EOF == C)
  283.             fprintf(stderr, "shar: No input files\n");
  284.         fprintf(stderr, "%s%s%s", Usage1, Usage2, Usage3);
  285.         exit(1);
  286.     }
  287.  
  288.     savind = 0;
  289.     do
  290.     {
  291.         if (getpat(optarg))
  292.             exit(2);
  293.     }
  294.     while (EOF != (C = getarg(argc, argv)));
  295.  
  296.     sav[savind] = NULL;
  297.     header(sav);
  298.     for (ppchList = sav; *ppchList; ++ppchList)
  299.     {
  300.         shar(*ppchList);
  301.     }
  302.     puts("#\tEnd of shell archive");
  303.     puts("exit 0");
  304.     exit(0);
  305. }
  306.  
  307. int getpat(char *pattern)
  308. {
  309.     register char *ptr;
  310. #ifdef AMIGA
  311.     while (ptr = scdir(pattern))
  312. #else
  313.     ptr = pattern;
  314. #endif
  315.     {
  316.         sav[savind] = malloc(strlen(ptr) + 1);
  317.         strcpy(sav[savind++], ptr);
  318.  
  319.         if (access(ptr, 4))
  320.         {
  321.             printf("No read access for file: %s\n", ptr);
  322.             return (-1);
  323.         }
  324.     }
  325.     return (0);
  326. }
  327.  
  328.  
  329. /*
  330.    get option letter from argument vector 
  331. */
  332.  
  333. int getopt(int nargc, char **nargv, char *ostr)
  334. {
  335.     register char *oli;            /* option letter list index */
  336.     static char *place = EMSG;    /* option letter processing */
  337.  
  338.     if (!*place)
  339.     {                            /* update scanning pointer */
  340.         if (optind >= nargc || *(place = nargv[optind]) != '-' || !*++place)
  341.             return (EOF);
  342.         if (*place == '-')
  343.         {                        /* found "--" */
  344.             ++optind;
  345.             return EOF;
  346.         }
  347.     }                            /* option letter okay? */
  348.     if ((optopt = (int) *place++) == (int) ':' || !(oli = strchr(ostr, optopt)))
  349.     {
  350.         if (!*place)
  351.             ++optind;
  352.         tell(": illegal option -- ");
  353.     }
  354.     if (*++oli != ':')
  355.     {                            /* don't need argument */
  356.         optarg = NULL;
  357.         if (!*place)
  358.             ++optind;
  359.     }
  360.     else
  361.     {                            /* need an argument */
  362.         if (*place)
  363.         {                        /* no white space */
  364.             optarg = place;
  365.         }
  366.         else
  367.         {
  368.             if (nargc <= ++optind)
  369.             {                    /* no arg */
  370.                 place = EMSG;
  371.                 tell(": option requires an argument -- ");
  372.             }
  373.             else
  374.             {
  375.                 optarg = nargv[optind];    /* white space */
  376.             }
  377.         }
  378.         place = EMSG;
  379.         ++optind;
  380.     }
  381.     return (optopt);            /* dump back option letter */
  382. }
  383.  
  384.  
  385. int getarg(int nargc, char **nargv)
  386. {
  387.     if (nargc <= optind)
  388.     {
  389.         optarg = (char *) 0;
  390.         return EOF;
  391.     }
  392.     else
  393.     {
  394.         optarg = nargv[optind++];
  395.         return 0;
  396.     }
  397. }
  398.  
  399. void dounshar(char *ArcNam)
  400. {
  401.     int
  402.         Prefix = 0,
  403.         i;
  404.     FILE
  405.         *inptr, *outptr;
  406.     char
  407.         *ptr,
  408.         *nlf,
  409.         line[BUFSIZ],
  410.         FilNam[256],
  411.         Delim[40];
  412.  
  413.     if (!(inptr = fopen(ArcNam, "r")))
  414.     {
  415.         fprintf(stderr, "shar: Can't open archive '%s'\n", ArcNam);
  416.         return;
  417.     }
  418.     while (fgets(line, BUFSIZ, inptr))
  419.     {
  420.         ptr = line + strspn(line, " \t");
  421.         if (strncmp(ptr, "sed ", 4) == 0)
  422.         {
  423.             Prefix = 0;
  424.             if (!(ptr = strchr(ptr, '/')))
  425.                 goto getfil;
  426.             if (*++ptr == '^')
  427.                 ++ptr;
  428.             while (*ptr++ != '/')
  429.                 Prefix++;
  430.             goto getfil;
  431.         }
  432.         else
  433.         if (strncmp(ptr, "cat ", 4) == 0)
  434.         {
  435.             Prefix = 0;
  436.     getfil:
  437.             getshpar(ptr, ">", FilNam);
  438.             getshpar(ptr, "<<", Delim);
  439.             fprintf(stderr, "Creating %s ...", FilNam);
  440.             outptr = fopen(FilNam, "w");
  441.             while (fgets(line, BUFSIZ, inptr))
  442.             {
  443.                 if (strncmp(line, Delim, strlen(Delim)) == 0)
  444.                     break;
  445.                 if (outptr)
  446.                     fputs(&line[Prefix], outptr);
  447.             }
  448.             if (outptr)
  449.             {
  450.                 fclose(outptr);
  451.                 fprintf(stderr, "...done\n");
  452.             }
  453.             else
  454.                 fprintf(stderr, "...error in creating file\n");
  455.         }
  456.         else
  457.         if (strncmp(ptr, "mkdir ", 6) == 0)
  458.         {
  459.             for (nlf=ptr+6; *nlf; ++nlf)
  460.                 if (*nlf == '\n')
  461.                     *nlf = '\0';
  462.             fprintf(stderr, "Creating directory %s ...", ptr+6);
  463.             dequote(ptr+6);
  464.             i = mkdir(ptr+6);
  465.             if (i) /* then it failed */
  466.                 fprintf(stderr, "failed, errno=%u\n", errno);
  467.             else
  468.                 fprintf(stderr, "done\n");
  469.         }
  470.         else
  471.         if (strncmp(ptr, "chdir ", 6) == 0)
  472.         {
  473.             dequote(ptr+6);
  474.             chdir(ptr+6);
  475.         }
  476.         else
  477.         if (strncmp(line, "cd ", 3) == 0)
  478.         {
  479.             dequote(ptr+3);
  480.             chdir(ptr+3);
  481.         }
  482.     }
  483.     fclose(inptr);
  484. }
  485.  
  486. void getshpar(char *line, char *sea, char *par)
  487. {
  488.     register char *scr1, *scr2;
  489.  
  490.     while (*line)
  491.     {
  492.         scr1 = line;
  493.         scr2 = sea;
  494.         while (*scr1 && *scr2 && *scr1 == *scr2)
  495.         {
  496.             scr1++;
  497.             scr2++;
  498.         }
  499.         if (*scr2 == 0)
  500.         {
  501.             if (*scr1 == 0)
  502.             {
  503.                 *par = 0;
  504.                 return;
  505.             }
  506.             while (*scr1 == ' ' || *scr1 == '\t' ||
  507.                    *scr1 == '/' ||
  508.                    *scr1 == '\\' || *scr1 == '\'' || *scr1 == '"')
  509.                 scr1++;
  510.             while (*scr1 != 0 && *scr1 != ' ' && *scr1 != '\t' &&
  511. //                   *scr1 != '/' &&
  512.                    *scr1 != '\\' && *scr1 != '\'' && *scr1 != '"' &&
  513.                    *scr1 != '\n' && *scr1 != '\r')
  514.                 *par++ = *scr1++;
  515.             *par = 0;
  516.             return;
  517.         }
  518.         line++;
  519.     }
  520.     *par = 0;
  521. }
  522.  
  523. void dequote(char *p)
  524. {
  525.     char
  526.         *d = p,
  527.         q;
  528.  
  529.     while (isspace(*d))
  530.         ++d;
  531.     switch (*d)
  532.     {
  533. case '\'':
  534. case '"':
  535.         q = *d++;
  536.         break;
  537. default:
  538.         q = ' ';
  539.     }
  540.     while (*d && !isspace(*d) && *d != q)
  541.         *p++ = *d++;
  542.     *p = '\0';
  543. }
  544.