home *** CD-ROM | disk | FTP | other *** search
- /*
- * --- UNSHAR.C ---
- *
- * --- Copywrite 24 September, 1986 ---
- * --- John Birchfield ---
- * --- 411 Crane Ave. ---
- * --- Turlock, CA 95380 ---
- * --- (209) 634-6243 ---
- *
- * Program to decode files created by the shell archive { shar }
- * utility on Un*x machines or pc's. Current capabilities include
- *
- * 1. Able to unshar into a user specified directory or subdirectory
- * as specified by a command line option { -Ddirectory_name }
- *
- * 2. Recognizes the following commands
- * cat, sed, uudecode, mkdir, chdir,
- * {test -f, test -d, test <number -ne wc ... }
- *
- * 3. Can handle shar scripts created with the
- * Options { -a -v -p -b -c -d }
- *
- * 4. Successfully traverses directories and sub-directories
- * creating the necessary subdirectories as necessary.
- *
- * CAVEATS:
- * Word Counting between Un*x machines and pc's just isn't
- * gonna work out too well. The \r\n - \n thing is not
- * an easy thing to work around - and to be quite frank
- * I just ain't up to it.
- *
- * Program written for the Desmet (C-Ware) C Compiler Version 2.61
- * not all of the routines in DOS_C.C and DOS_A.A are used by this
- * program. The program consists of the following modules:
- * UNSHAR.C
- * SHAR_CMD.C
- * DOS_C.C
- * DOS_A.A
- *
- * This program is hereby placed in the public domain for
- * non-commersial use.
- */
-
- # include <stdio.h>
- # include "unshar.h"
-
- char test_flag = '\0',
- root_dir [65] = "";
-
- FILE *input;
-
-
-
-
- /*
- * MAIN () - get the options and input filename and
- * if possible go to it.
- */
-
- main (argc, argv)
- int argc;
- char **argv;
- {
- char dts [22];
-
- dates (dts);
- strcat (&dts [8], " at ");
- times (&dts [12]);
- get_options (argc, argv);
- p_error (0, "\t\t--------------------------------------\n",
- "\t\t UNSHAR Version 24 Sep '86\n",
- "\t\t Extracting to '", (root_dir [0])?root_dir:"Current",
- "' Directory\n",
- "\t\t On", dts, "\n",
- "\t\t--------------------------------------\n", "");
- do_cmds (input);
- }
-
-
-
- /*
- * DO_CMDS () - process the input file as a token stream
- * and when a command is recognized, perform it. The
- * cmd_flag array is used to determine the current state
- * of { if then else } constructs within a shar script.
- * as you can see, it allow four levels of nesting of 'em.
- * the i/o to the token mechanism is explained somewhere
- * around get_tok ().
- */
-
- int do_cmds (fp)
- FILE *fp;
- {
- static int cmd_level = 0;
- static char cmd_flag [5] = {'\1', '\0', '\0', '\0', '\0' },
- cmd_tok [132] = "";
-
- while (get_tok (cmd_tok, fp)) {
- switch (token_type (cmd_tok)) {
- case IF_CMD:
- ++cmd_level;
- break;
- case TEST_CMD:
- cmd_flag [cmd_level] = ((char) (do_test ())
- && (cmd_flag [cmd_level-1]));
- break;
- case CAT_CMD:
- if (cmd_flag [cmd_level])
- do_cat (fp);
- else
- do_skip (fp);
- cmd_init ();
- break;
- case SED_CMD:
- if (cmd_flag [cmd_level])
- do_sed (fp);
- else
- do_skip (fp);
- cmd_init ();
- break;
- case ECHO_CMD:
- if (cmd_flag [cmd_level])
- do_echo ();
- else
- cmd_init ();
- break;
- case EXIT_CMD:
- if (cmd_flag [cmd_level])
- do_exit (fp);
- else
- cmd_init ();
- case FI_CMD:
- cmd_flag [cmd_level--] = ((char) FALSE);
- break;
- case ELSE_CMD:
- cmd_flag [cmd_level] = (!(cmd_flag [cmd_level])
- && (cmd_flag [cmd_level-1]));
- break;
- case THEN_CMD:
- break;
- case CD_CMD:
- if (cmd_flag [cmd_level])
- do_cd (fp);
- else
- cmd_init ();
- break;
- case MKDIR_CMD:
- if (cmd_flag [cmd_level])
- do_mkdir (fp);
- else
- cmd_init ();
- break;
- case UUDCD_CMD:
- if (cmd_flag [cmd_level])
- do_uudecode (fp);
- else
- cmd_init ();
- break;
- default:
- if (cmd_flag [cmd_level])
- p_error (0,
- " Skipping command '",
- cmd_tok, "' ...\n", "");
- cmd_init ();
- break;
- }
- }
- }
-
-
-
-
- /*
- * Data and Defines for token passing routines
- */
-
- # define is_white(c) ((c==' ') || (c=='\t') || (c=='\n') ||\
- (c=='\r') || (c=='\0'))
- # define not_single(c) ((c!='\0') && (c!='\'') && (c!='\n') && (c!='\r'))
- # define not_double(c) ((c!='\0') && (c!='\"') && (c!='\n') && (c!='\r'))
- char tok_buf [255] = "",
- *tbp=&tok_buf[0];
-
-
-
-
-
- /*
- * GET_BUF () - get_buf () is driven by get_tok ().
- * Basically, get_buf () is called when tok_buf has been
- * exhausted.
- */
-
- int get_buf (fp)
- FILE *fp;
- {
- int rval;
- char *tp;
-
- tbp = &tok_buf [0];
- do {
- tp = &tok_buf [0];
- if ((rval = fgets (tok_buf, 255, fp))==0)
- return 0;
- while (*tp) {
- if (*tp=='#') {
- *tp = '\0';
- break;
- }
- else
- tp++;
- }
- } while (tok_buf [0]==0);
- return rval;
- }
-
-
-
-
- /*
- * GET_TOK () - get_tok () retrieves the next token
- * available in the i/o stream being processed. The array
- * tok_buf is the token passing buffer used. Tokens are
- * of the form
- * [a-z0-9special]
- * '[a-z0-9special]' - '\'' are stripped
- * "[a-z0-9special]" - '\"' are stripped
- * get_tok () returns 0 on EOF
- */
-
- int get_tok (tok, fp)
- char *tok;
- FILE *fp;
- {
- int rval = 1;
- char *tp;
-
- tp = tok;
- *tp = '\0';
- while (*tok=='\0') {
- if (*tbp=='\0')
- if ((rval = get_buf (fp))==0)
- return rval;
- while (is_white(*tbp))
- if (*tbp=='\0')
- break;
- else
- tbp++;
- if (*tbp=='\'') {
- tbp++;
- while (not_single(*tbp))
- *tp++=*tbp++;
- *tbp++='\0';
- }
- else if (*tbp=='\"') {
- tbp++;
- while (not_double(*tbp))
- *tp++=*tbp++;
- *tbp++='\0';
- }
- else
- while (!(is_white(*tbp)))
- *tp++=*tbp++;
- *tp='\0';
- }
- return rval;
- }
-
-
-
- /*
- * TK_LIST - A list of the available commands to UNSHAR.
- * their relative displacement in the list relates
- * to a corresponding set of Defines in UNSHAR.H
- */
-
- char *tk_list [] = {
- "if", "echo", "test", "cat", "sed" , "exit", "else", "fi", "then",
- "cd", "mkdir", "uudecode"
- };
-
-
-
-
-
- /*
- * TOKEN_TYPE () - returns the relative index into the
- * tk_list array for processing by do_cmds ().
- */
-
- int token_type (tok)
- char *tok;
- {
- int i;
- for (i=0; i<TK_MAX; i++)
- if (strcmp (tok, tk_list [i])==0)
- break;
- return i;
- }
-
-
-
- /*
- * CMD_INIT () - cmd_init () is used to flush the
- * buffer tok_buf. This is necessary when a command is
- * not processed for some reason, or upon the successful
- * completion of a shar command. This is necessary
- * because the same input file is being processed thru
- * multiple buffers. After a cmd_init () call the next
- * call to get_tok () will cause the immediate refilling
- * of tok_buf by get_buf ().
- */
-
- void cmd_init ()
- {
- tok_buf [0]= '\0';
- tbp = &tok_buf [0];
- }
-
-
-
- /*
- * DO_ECHO () - do_echo () is the only shar command
- * contained in this module. It would be nicer to have
- * it with the other routines but it's so much easier here
- * since it directly reads from the tok_buf...
- */
-
- void do_echo ()
- {
- fputs (tbp, stdout);
- cmd_init ();
- }
-
-
-
- /*
- * USAGE () - Tell 'em what it's all about and
- * go home to mamma.
- */
-
- usage ()
- {
- fputs ("Usage: UNSHAR [-T -D<directory name>] <shar file name>\n",
- stdout);
- fputs ("\tWhere <directory name> specifies the root directory\n",
- stdout);
- fputs ("\t for UNSHAR to place extracted files\n\n",
- stdout);
- fputs ("\tand -T says to return TRUE from unknown 'test' commands\n\n",
- stdout);
- fputs ("\t Either Upper or lower case will work for the option flags\n\n",
- stdout);
- exit (2);
- }
-
-
-
- /*
- * GET_OPTIONS () - get_options () checks for proper options
- * and if they're valid sets things up for do_cmds.
- * the options available are...
- *
- * -t tell unshar to return true on an unknown
- * test command
- * -D<directoryname> tell unshar to build the extracted files
- * in the directory specified { if it doesn't
- * exist make it } BeWare ... It will make
- * ALL the sub-directories you specify along the
- * way.
- */
-
- get_options (argc, argv)
- int argc;
- char **argv;
- {
- char got_dir = FALSE,
- got_name = FALSE,
- file_name [65],
- *cp;
-
- if (argc < 2) {
- usage ();
- }
- file_name [0] = '\0';
- while (--argc) {
- if ((*(cp=(*++argv)))=='-')
- switch (toupper (*++cp)) {
- case 'D':
- if (got_dir)
- usage ();
- if (*++cp)
- strcpy (root_dir, cp);
- got_dir = TRUE;
- break;
- case 'T':
- test_flag = TRUE;
- break;
- default:
- p_error (0, "Invalid Option ",
- cp, "\n", "");
- usage ();
- break;
- }
- else {
- strcpy (file_name, *argv);
- break;
- }
- }
- if ((input = open (file_name, 0))==-1) {
- p_error (0, "UNSHAR: Error ... Can't Open '",
- (file_name [0])?file_name:" ","'\n", "");
- usage ();
- }
- if (root_dir [0] != '\0')
- mk_dirs (root_dir);
- }
-
-
-
-
- /*
- * MK_DIRS () - mk_dirs () is passed a path of directories.
- * It will traverse this list and make all the directories
- * along the way to the end. Like I said above, BeWare...
- */
-
- void mk_dirs (s)
- char *s;
- {
- char *p1, buf [65];
- p1 = & buf [0];
-
- if ((*s=='\\' || *s=='/') && (*(s+1)=='\0'))
- return;
-
- *p1++ = *s++;
- do {
- while (*s!='/' && *s!='\\' && *s!='\0')
- *p1++=*s++;
- *p1='\0';
- mkdir (buf);
- *p1++ = '/';
- if (*s=='\\' || *s=='/')
- s++;
- } while (*s);
- *p1='\0';
- if (*(s-1) != '\\' && *(s-1) != '//') {
- *s++='/';
- *s++='\0';
- }
- }
-