/* * --- SHAR_CMD.C --- * --- Command Portion of --- * --- 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" # include "dos.h" /* * P_ERROR () - p_error () is a simple routine for * displaying a message consisting of a sequence of * strings thru stdout. The first parameter is an * integer { if non-zero an exit occurs } the last * parameter is an empty string. */ void p_error (no, args) int no; char *args; { char **tmp; tmp = &args; while (**tmp) fputs (*tmp++, stdout); if (no) _exit (no); } /* * DO_CD () - change directories */ int do_cd (fp) FILE *fp; { char buf [20]; get_tok (buf, fp); return (chdir (buf)); } /* * DO_MKDIR () - make a directory */ int do_mkdir (fp) FILE *fp; { char buf [20]; get_tok (buf, fp); return (mkdir (buf)); } /* * DO_EXIT () - Bye Bye */ void do_exit (fp) FILE *fp; { char buf [20]; get_tok (buf, fp); exit (atoi (buf)); } /* * DO_CAT () - get the destination filename, get the * terminating string open the file and pass the contents * of the input stream to it until the termination flag * is recognized. */ void do_cat (fp) FILE *fp; { FILE *f_out; char delimiter [80], fname [65], *dp, buf [256], tmp [15]; int len; fname [0] = delimiter [0] = '\0'; do { get_tok (tmp, fp); if (strncmp (tmp, "<<", 2)==0) get_tok (delimiter, fp); else if (strncmp (tmp, ">", 1)==0) get_tok (fname, fp); } while (fname [0]=='\0' || delimiter [0]=='\0'); fix_file_name (fname); if ((f_out=creat (fname))==-1) p_error (1, "Cat Can't Create '", fname, "'\n", ""); dp = &delimiter [1]; len = strlen (dp); while (fgets (buf, 256, fp)) { if (strncmp (dp, buf, len)==0) break; fputs (buf, f_out); } fclose (f_out); } /* * DO_SED () - do_sed () works just like do_cat () * except that the command line has the sed s/ // * translation parameter in it { one more token } * Command lines are of the form * sed 's/^ X//' << \SHAR_EOF > '.cshrc' */ void do_sed (fp) FILE *fp; { FILE *f_out; char replace [40], delimiter [80], fname [65], *dp, *rp, buf [256], *nbuf, tmp [15]; int len, rlen; get_tok (replace, fp); fname [0] = delimiter [0] = '\0'; do { get_tok (tmp, fp); if (strncmp (tmp, "<<", 2)==0) get_tok (delimiter, fp); else if (strncmp (tmp, ">", 1)==0) get_tok (fname, fp); } while (fname [0]=='\0' || delimiter [0]=='\0'); fix_file_name (fname); rp = &replace [3]; if (index (rp, '/')) *index (rp, '/') = '\0'; rlen = strlen (rp); nbuf = &buf [0] + rlen; if ((f_out=creat (fname))==-1) p_error (1, "Cat Can't Create '", fname, "'\n", ""); dp = &delimiter [1]; len = strlen (dp); while (fgets (buf, 256, fp)) { if (strncmp (dp, buf, len)==0) break; if (strncmp (rp, buf, rlen)==0) fputs (nbuf, f_out); else fputs (buf, f_out); } fclose (f_out); ; } /* * DO_UUDECODE () - do_uudecode () handles uudecoding * chores in the same way that do_cat () and do_sed () * process their input. There are differnces in that * the uuencoded stream has it's filename as the * beginning of the file and not imbedded in * the uudecode command line. */ void do_uudecode (fp) FILE *fp; { FILE *f_out; char delimiter [80], fname [65], *dp, buf [256]; int len; do { get_tok (delimiter, fp); } while (strncmp (delimiter, "<<", 2)); get_tok (delimiter, fp); dp = &delimiter [1]; len = strlen (dp); fname [0] = '\0'; do { if (get_tok (fname, fp)==0) p_error (2, "Uudecode: No begin statement\n", ""); } while (strcmp (fname, "begin")); get_tok (fname, fp); get_tok (fname, fp); fix_file_name (fname); if ((f_out=creat (fname))==-1) p_error (1, "Uudecode Can't Create '", fname, "'\n", ""); decode(fp, f_out); if (fgets(buf, sizeof buf, fp) == NULL || strcmp(buf, "end\n")) p_error (5, "Uudecode No end line\n", ""); while (fgets (buf, sizeof (buf), fp)) if (strncmp (buf, dp, len)==0) break; fclose (f_out); } /* * copy from in to out, decoding as you go along. */ #define DEC(c) (((c) - ' ') & 077) decode(in, out) FILE *in; FILE *out; { char buf[80]; char *bp; int n; for (;;) { /* for each input line */ if (fgets(buf, sizeof buf, in) == NULL) p_error (10, "Uudecode Short file\n", ""); n = DEC(buf[0]); if (n <= 0) break; bp = &buf[1]; while (n > 0) { outdec(bp, out, n); bp += 4; n -= 3; } } } /* * output a group of 3 bytes (4 input characters). * the input chars are pointed to by p, they are to * be output to file f. n is used to tell us not to * output all of them at the end of the file. */ outdec(p, f, n) char *p; FILE *f; { int c1, c2, c3; c1 = DEC(*p) << 2 | DEC(p[1]) >> 4; c2 = DEC(p[1]) << 4 | DEC(p[2]) >> 2; c3 = DEC(p[2]) << 6 | DEC(p[3]); if (n >= 1) fputc(c1, f); if (n >= 2) fputc(c2, f); if (n >= 3) fputc(c3, f); } /* * DO_TEST () - do_test () tries to perform the test * requested by the shar script. At the moment the * following tests are recognized * * test ! -d directoryname * test -f filename * test -ne wc ... do a word count of * the file */ int do_test (fp) FILE *fp; { FILE *tfp; char flag [10], fname [100]; int invert = FALSE; long wc_arg; get_tok (flag, fp); if (strcmp (flag, "!")==0) { invert = TRUE; get_tok (flag, fp); } if (strcmp (flag, "-f")==0) { get_tok (fname, fp); fix_file_name (fname); if (tfp=fopen (fname, "r")) fclose (tfp); } else if (strcmp (flag, "-d")==0) { get_tok (fname, fp); fix_file_name (fname); if (tfp=(FILE *) opendir (fname)) closedir (tfp); } else if (isdigit(flag [0])) { wc_arg = atol (flag); get_tok (flag, fp); if (strcmp (flag, "-ne")==0) { get_tok (fname, fp); return ((w_cnt (fname, wc_arg))); } else { cmd_init (); return ((int) test_flag); } } else { cmd_init (); return ((int) test_flag); } return ((invert)?!(tfp):tfp); } /* * W_CNT () - This part of test is a separate function * 'cause I don't like to nest that deep. by the time * w_cnt () has been passed control it's broken down the * shar script command of the form * if test 488 -ne "`wc -c < 'FileName'`" * to * `wc -c < 'FileName'` * which is not too hard to extract the filename from */ int w_cnt (name, arg) char *name; long arg; { char filename [65]; struct stat statbuf; char *np, *index (), *rindex (); np = index (name, '\'') +1; *index (np, '\'') = '\0'; strcpy (filename, np); fix_file_name (filename); stat (filename, &statbuf); if (statbuf.st_size != arg) return (1); return (0); } /* * DO_SKIP () - do_skip () passes thru the input until * he has determined that the command that would have * been processed at this point in the stream has been * flushed. */ void do_skip (fp) FILE *fp; { char buf [256], delimiter [80], *dp; int len; do { get_tok (delimiter, fp); } while (strncmp (delimiter, "<<", 2)); get_tok (delimiter, fp); dp = &delimiter [1]; len = strlen (dp); while (fgets (buf, sizeof (buf), fp)) if (strncmp (dp, buf, len)==0) break; cmd_init (); } /* * FIX_FILE_NAME () - does two things * (1) strips off any leading path identifiers * (2) appends the leading path header to the * filename presented to it. */ void fix_file_name (s) char *s; { char buf [65], *tp, *rindex (); strcpy (buf, root_dir); if (tp=rindex (s, '/')) strcat (buf, tp+1); else strcat (buf, s); strcpy (s, buf); }