/* * --- 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 # 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] \n", stdout); fputs ("\tWhere 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 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'; } }