home *** CD-ROM | disk | FTP | other *** search
/ Resource Library: Multimedia / Resource Library: Multimedia.iso / archvrs / msdos / unshar / unshar.c < prev    next >
Encoding:
C/C++ Source or Header  |  1986-09-25  |  9.5 KB  |  453 lines

  1. /*
  2.  *               ---   UNSHAR.C   ---
  3.  *
  4.  *          ---   Copywrite 24 September, 1986   ---
  5.  *              ---    John Birchfield      ---
  6.  *              ---    411 Crane Ave.       ---
  7.  *              ---    Turlock, CA  95380   ---
  8.  *              ---      (209) 634-6243     ---
  9.  *
  10.  *    Program to decode files created by the shell archive { shar }
  11.  *    utility on Un*x machines or pc's.  Current capabilities include
  12.  *
  13.  *    1.    Able to unshar into a user specified directory or subdirectory
  14.  *        as specified by a command line option { -Ddirectory_name }
  15.  *
  16.  *    2.    Recognizes the following commands
  17.  *            cat, sed, uudecode, mkdir, chdir, 
  18.  *            {test -f, test -d, test <number -ne wc ... }
  19.  *
  20.  *    3.    Can handle shar scripts created with the
  21.  *            Options { -a -v -p -b -c -d }
  22.  *
  23.  *    4.    Successfully traverses directories and sub-directories
  24.  *        creating the necessary subdirectories as necessary.
  25.  *
  26.  *    CAVEATS:
  27.  *        Word Counting between Un*x machines and pc's just isn't
  28.  *        gonna work out too well.  The \r\n - \n thing is not
  29.  *        an easy thing to work around - and to be quite frank
  30.  *        I just ain't up to it.
  31.  *
  32.  *    Program written for the Desmet (C-Ware) C Compiler Version 2.61
  33.  *    not all of the routines in DOS_C.C and DOS_A.A are used by this
  34.  *    program.  The program consists of the following modules:
  35.  *        UNSHAR.C
  36.  *        SHAR_CMD.C
  37.  *        DOS_C.C
  38.  *        DOS_A.A
  39.  *
  40.  *    This program is hereby placed in the public domain for 
  41.  *    non-commersial use.
  42.  */
  43.  
  44. # include <stdio.h>
  45. # include "unshar.h"
  46.  
  47. char    test_flag = '\0',
  48.     root_dir [65] = "";
  49.  
  50. FILE *input;
  51.  
  52.  
  53.  
  54.  
  55. /*
  56.  *    MAIN ()    -    get the options and input filename and
  57.  *        if possible go to it.
  58.  */
  59.  
  60. main (argc, argv)
  61. int argc;
  62. char **argv;
  63. {
  64.     char dts [22];
  65.  
  66.     dates (dts);
  67.     strcat (&dts [8], " at ");
  68.     times (&dts [12]);
  69.     get_options (argc, argv);
  70.     p_error (0, "\t\t--------------------------------------\n",
  71.         "\t\t      UNSHAR  Version 24 Sep '86\n",
  72.         "\t\t    Extracting to '", (root_dir [0])?root_dir:"Current",
  73.         "' Directory\n",
  74.         "\t\t       On", dts, "\n",
  75.         "\t\t--------------------------------------\n", "");
  76.     do_cmds (input);
  77. }
  78.  
  79.  
  80.  
  81. /*
  82.  *    DO_CMDS ()    -    process the input file as a token stream
  83.  *        and when a command is recognized, perform it.  The 
  84.  *        cmd_flag array is used to determine the current state
  85.  *        of { if then else } constructs within a shar script.
  86.  *        as you can see, it allow four levels of nesting of 'em.
  87.  *        the i/o to the token mechanism is explained somewhere
  88.  *        around get_tok ().
  89.  */
  90.  
  91. int do_cmds (fp)
  92. FILE *fp;
  93. {
  94.     static int  cmd_level = 0;
  95.     static char cmd_flag [5] = {'\1', '\0', '\0', '\0', '\0' },    
  96.                 cmd_tok [132] = "";
  97.  
  98.     while (get_tok (cmd_tok, fp)) {
  99.         switch (token_type (cmd_tok)) {
  100.             case IF_CMD:
  101.                 ++cmd_level;
  102.                 break;                
  103.             case TEST_CMD:
  104.                 cmd_flag [cmd_level] = ((char) (do_test ())
  105.                     && (cmd_flag [cmd_level-1]));
  106.                 break;
  107.             case CAT_CMD:
  108.                 if (cmd_flag [cmd_level])
  109.                     do_cat (fp);
  110.                 else
  111.                     do_skip (fp);
  112.                 cmd_init ();
  113.                 break;
  114.             case SED_CMD:
  115.                 if (cmd_flag [cmd_level])
  116.                     do_sed (fp);
  117.                 else
  118.                     do_skip (fp);
  119.                 cmd_init ();
  120.                 break;
  121.             case ECHO_CMD:
  122.                 if (cmd_flag [cmd_level])
  123.                     do_echo ();
  124.                 else
  125.                     cmd_init ();
  126.                 break;
  127.             case EXIT_CMD:
  128.                 if (cmd_flag [cmd_level])
  129.                     do_exit (fp);
  130.                 else
  131.                     cmd_init ();
  132.             case FI_CMD:
  133.                 cmd_flag [cmd_level--] = ((char) FALSE);
  134.                 break;
  135.             case ELSE_CMD:
  136.                 cmd_flag [cmd_level] = (!(cmd_flag [cmd_level])
  137.                         && (cmd_flag [cmd_level-1]));
  138.                 break;
  139.             case THEN_CMD:
  140.                 break;
  141.             case CD_CMD:
  142.                 if (cmd_flag [cmd_level])
  143.                     do_cd (fp);
  144.                 else
  145.                     cmd_init ();
  146.                 break;
  147.             case MKDIR_CMD:
  148.                 if (cmd_flag [cmd_level])
  149.                     do_mkdir (fp);
  150.                 else
  151.                     cmd_init ();
  152.                 break;
  153.             case UUDCD_CMD:
  154.                 if (cmd_flag [cmd_level])
  155.                     do_uudecode (fp);
  156.                 else
  157.                     cmd_init ();
  158.                 break;
  159.             default:
  160.                 if (cmd_flag [cmd_level])
  161.                     p_error (0,
  162.                        "   Skipping command '",
  163.                        cmd_tok, "' ...\n", "");
  164.                 cmd_init ();
  165.                 break;
  166.         }
  167.     }
  168. }
  169.  
  170.  
  171.  
  172.  
  173. /*
  174.  *    Data and Defines for token passing routines
  175.  */
  176.  
  177. # define is_white(c)    ((c==' ') || (c=='\t') || (c=='\n') ||\
  178.              (c=='\r') || (c=='\0'))
  179. # define not_single(c)    ((c!='\0') && (c!='\'') && (c!='\n') && (c!='\r'))
  180. # define not_double(c)    ((c!='\0') && (c!='\"') && (c!='\n') && (c!='\r'))
  181. char tok_buf [255] = "",
  182.      *tbp=&tok_buf[0];
  183.  
  184.  
  185.  
  186.  
  187.  
  188. /*
  189.  *    GET_BUF ()    -    get_buf () is driven by get_tok ().
  190.  *        Basically, get_buf () is called when tok_buf has been
  191.  *        exhausted.
  192.  */
  193.  
  194. int get_buf (fp)
  195. FILE *fp;
  196. {
  197.     int rval;
  198.     char *tp;
  199.     
  200.     tbp = &tok_buf [0];
  201.     do {
  202.         tp = &tok_buf [0];
  203.         if ((rval = fgets (tok_buf, 255, fp))==0)
  204.             return 0;
  205.         while (*tp) {
  206.             if (*tp=='#') {
  207.                 *tp = '\0';
  208.                 break;
  209.             }
  210.             else
  211.                 tp++;
  212.         }
  213.     } while (tok_buf [0]==0);
  214.     return rval;
  215. }
  216.  
  217.  
  218.  
  219.  
  220. /*
  221.  *    GET_TOK ()    -    get_tok () retrieves the next token
  222.  *        available in the i/o stream being processed. The array
  223.  *        tok_buf is the token passing buffer used. Tokens are
  224.  *        of the form
  225.  *            [a-z0-9special]
  226.  *            '[a-z0-9special]' - '\'' are stripped
  227.  *            "[a-z0-9special]" - '\"' are stripped
  228.  *        get_tok () returns 0 on EOF
  229.  */
  230.  
  231. int get_tok (tok, fp)
  232. char *tok;
  233. FILE *fp;
  234. {
  235.     int rval = 1;
  236.     char *tp;
  237.  
  238.     tp = tok;
  239.     *tp = '\0';
  240.     while (*tok=='\0') {
  241.         if (*tbp=='\0')
  242.             if ((rval = get_buf (fp))==0)
  243.                 return rval;
  244.         while (is_white(*tbp))
  245.             if (*tbp=='\0')
  246.                 break;
  247.             else
  248.                 tbp++;
  249.         if (*tbp=='\'') {
  250.             tbp++;
  251.             while (not_single(*tbp))
  252.                 *tp++=*tbp++;
  253.             *tbp++='\0';
  254.         }
  255.         else if (*tbp=='\"') {
  256.             tbp++;
  257.             while (not_double(*tbp))
  258.                 *tp++=*tbp++;
  259.             *tbp++='\0';
  260.         }
  261.         else
  262.             while (!(is_white(*tbp)))
  263.                 *tp++=*tbp++;
  264.         *tp='\0';
  265.     }
  266.     return rval;
  267. }
  268.  
  269.  
  270.  
  271. /*
  272.  *    TK_LIST    -    A list of the available commands to UNSHAR.
  273.  *        their relative displacement in the list relates
  274.  *        to a corresponding set of Defines in UNSHAR.H
  275.  */
  276.  
  277. char *tk_list [] = {
  278.     "if", "echo", "test", "cat", "sed" , "exit", "else", "fi", "then",
  279.     "cd", "mkdir", "uudecode"
  280. };
  281.  
  282.  
  283.  
  284.  
  285.  
  286. /*
  287.  *    TOKEN_TYPE ()    -    returns the relative index into the
  288.  *        tk_list array for processing by do_cmds ().
  289.  */
  290.  
  291. int token_type (tok)
  292. char *tok;
  293. {
  294.     int i;
  295.     for (i=0; i<TK_MAX; i++)
  296.         if (strcmp (tok, tk_list [i])==0)
  297.             break;
  298.     return i;
  299. }
  300.  
  301.  
  302.  
  303. /*
  304.  *    CMD_INIT ()    -    cmd_init () is used to flush the
  305.  *        buffer tok_buf.  This is necessary when a command is
  306.  *        not processed for some reason, or upon the successful
  307.  *        completion of a shar command.  This is necessary
  308.  *        because the same input file is being processed thru
  309.  *        multiple buffers.  After a cmd_init () call the next
  310.  *        call to get_tok () will cause the immediate refilling
  311.  *        of tok_buf by get_buf ().
  312.  */
  313.  
  314. void cmd_init ()
  315. {
  316.     tok_buf [0]= '\0';
  317.     tbp = &tok_buf [0];
  318. }
  319.  
  320.  
  321.  
  322. /*
  323.  *    DO_ECHO ()    -    do_echo () is the only shar command
  324.  *        contained in this module.  It would be nicer to have
  325.  *        it with the other routines but it's so much easier here
  326.  *        since it directly reads from the tok_buf...
  327.  */
  328.  
  329. void do_echo ()
  330. {
  331.     fputs (tbp, stdout);
  332.     cmd_init ();
  333. }
  334.  
  335.  
  336.  
  337. /*
  338.  *    USAGE ()    -    Tell 'em what it's all about and
  339.  *        go home to mamma.
  340.  */
  341.  
  342. usage ()
  343. {
  344.   fputs ("Usage: UNSHAR [-T -D<directory name>] <shar file name>\n",
  345.       stdout);
  346.   fputs ("\tWhere <directory name> specifies the root directory\n",
  347.       stdout);
  348.   fputs ("\t   for UNSHAR to place extracted files\n\n", 
  349.     stdout);
  350.   fputs ("\tand -T says to return TRUE from unknown 'test' commands\n\n",
  351.       stdout);
  352.   fputs ("\t   Either Upper or lower case will work for the option flags\n\n",
  353.       stdout);
  354.   exit (2);
  355. }
  356.  
  357.  
  358.  
  359. /*
  360.  *    GET_OPTIONS ()    -    get_options () checks for proper options
  361.  *        and if they're valid sets things up for do_cmds.
  362.  *        the options available are...
  363.  *
  364.  *    -t            tell unshar to return true on an unknown
  365.  *                test command
  366.  *    -D<directoryname>    tell unshar to build the extracted files
  367.  *                in the directory specified { if it doesn't
  368.  *                exist make it } BeWare ... It will make
  369.  *                ALL the sub-directories you specify along the
  370.  *                way.
  371.  */
  372.  
  373. get_options (argc, argv)
  374. int argc;
  375. char **argv;
  376. {
  377.     char got_dir = FALSE,
  378.          got_name = FALSE,
  379.          file_name [65],
  380.          *cp;
  381.     
  382.     if (argc < 2) {
  383.         usage ();
  384.     }
  385.     file_name [0] = '\0';
  386.     while (--argc) {
  387.         if ((*(cp=(*++argv)))=='-')
  388.             switch (toupper (*++cp)) {
  389.                 case 'D':
  390.                     if (got_dir)
  391.                         usage ();
  392.                     if (*++cp)
  393.                         strcpy (root_dir, cp);
  394.                     got_dir = TRUE;
  395.                     break;
  396.                 case 'T':
  397.                     test_flag = TRUE;
  398.                     break;
  399.                 default:
  400.                     p_error (0, "Invalid Option ",
  401.                          cp, "\n", "");
  402.                     usage ();
  403.                     break;
  404.             }
  405.         else {
  406.             strcpy (file_name, *argv);
  407.             break;
  408.         }
  409.     }
  410.     if ((input = open (file_name, 0))==-1) {
  411.         p_error (0, "UNSHAR: Error ... Can't Open '",
  412.             (file_name [0])?file_name:" ","'\n", "");
  413.         usage ();
  414.     }
  415.     if (root_dir [0] != '\0')
  416.         mk_dirs (root_dir);
  417. }
  418.  
  419.  
  420.  
  421.  
  422. /*
  423.  *    MK_DIRS ()    -    mk_dirs () is passed a path of directories.
  424.  *        It will traverse this list and make all the directories
  425.  *        along the way to the end.  Like I said above, BeWare...
  426.  */
  427.  
  428. void mk_dirs (s)
  429. char *s;
  430. {
  431.     char *p1, buf [65];
  432.     p1 = & buf [0];
  433.  
  434.     if ((*s=='\\' || *s=='/') && (*(s+1)=='\0'))
  435.         return;
  436.  
  437.     *p1++ = *s++;
  438.     do {
  439.         while (*s!='/' && *s!='\\' && *s!='\0')
  440.             *p1++=*s++;
  441.         *p1='\0';
  442.         mkdir (buf);
  443.         *p1++ = '/';
  444.         if (*s=='\\' || *s=='/')
  445.             s++;
  446.     } while (*s);
  447.     *p1='\0';
  448.     if (*(s-1) != '\\' && *(s-1) != '//') {
  449.         *s++='/';
  450.         *s++='\0';
  451.     }
  452. }
  453.