/* sh - JimG's version of sh to unshar files */ char *help = "\ Usage: sh [-v(012)] [-s(01)] [-o(01)] [filename]\n\ -v = verbosity\n\ 0 = print nothing\n\ 1 = print anything not understood\n\ 2 = echo commands as they are executed\n\ -s = safety\n\ 1 = exit when something is not understood\n"; char *help2 = "\ -o = overwrite\n\ 1 = don't overwrite existing files\n\ filename\n\ read shar file from here (or stdin if missing)\n"; #define NDEBUG #include #include #include #include #define ST_CMDLINE 1 #define ST_CAT 2 #define ST_SED 3 #define TST_OUT 1 #define TST_QUOTE 2 #define TST_ALPHA 3 #define TST_DIR 4 #define BUFSIZE 161 char buf1[BUFSIZE], buf2[BUFSIZE]; char *buff1end = buf1 + BUFSIZE; unsigned short int verbosity = 1; unsigned short int safety = 0; unsigned short int overwrite = 1; FILE *fopen(char*,char*); void sh(FILE*); int tokenize(char**,int,char*); void bumpstr(char*); void ind_error(char**,int); void fileparse(char**,int,char*,FILE**); int fillbuffer(char*,int,FILE*); int match(char*,char*); void ptokens(char**,int,FILE*); int fillbuffer(buf,len,fp) /* This will read up to len-1 characters */ char *buf; int len; FILE *fp; { register int i, c; for (i=1; i 0) && ((*++argv)[0] == '-')) for (s = argv[0]+1; *s != '\0'; s++) switch (*s) { case 'v': switch (s[1]) { case '0': case '1': case '2': verbosity = (*++s) - '0'; break; default: verbosity = 1; break; } break; case 's': switch(s[1]) { case '0': case '1': safety = (*++s) - '0'; break; default: safety = 1; break; } break; case 'o': switch(s[1]) { case '0': case '1': overwrite = (*++s) - '0'; break; default: overwrite = 1; break; } break; default: fputs("sh: illegal option ",stderr); putc(*s,stderr); putc('\n',stderr); exit(10); break; } switch (argc) { case 0: sh(stdin); break; case 1: fp = fopen(argv[0],"r"); if (fp == NULL) { fputs("Error - can't open file: ",stderr); fputs(argv[0],stderr); putc('\n',stderr); exit(10); } sh(fp); fclose(fp); break; default: fputs(help,stderr); fputs(help2,stderr); exit(5); } return (0); } int match(pat,str) register char *pat, *str; { while (*pat != '\0') if (*pat++ != *str++) return (0); return(1); } void sh(fp) FILE *fp; { int state = ST_CMDLINE; int oldc, c, tcnt; FILE *outfp; char *tokens[20]; char schar; oldc = '\n'; while ((c = fillbuffer(buf1, BUFSIZE, fp)) != EOF ) { switch (state) { case ST_CMDLINE: if (oldc != '\n') break; if (*buf1 == '#') break; tcnt = tokenize(tokens, 20, buf1); if (tcnt == 0) break; if (strcmp(tokens[0],"echo") == 0) { ptokens(tokens+1,tcnt-1,stdout); } else if (strcmp(tokens[0],"cat") == 0) { fileparse(tokens,tcnt,buf2,&outfp); if (*buf2) { state = ST_CAT; if (verbosity == 2) { fputs("I am executing: ",stdout); ptokens(tokens,tcnt,stdout); } } else if (outfp != stdout) fclose(outfp); } else if (strcmp(tokens[0],"sed") == 0) { fileparse(tokens,tcnt,buf2,&outfp); if (*buf2) { if (verbosity == 2) { fputs("I am executing: ",stdout); ptokens(tokens,tcnt,stdout); } if ((tokens[1][0] == 's') && (tokens[1][1] == tokens[1][4]) && (tokens[1][2] == '^') && (tokens[1][5] == tokens[1][1])) { schar = tokens[1][3]; state = ST_SED; } else { fputs("Warning -- unknown sed option\n",stderr); fputs(tokens[1],stderr); fputs("\nI am treating it as a 'cat'\n",stderr); fflush(stderr); state = ST_CAT; } } else if (outfp != stdout) fclose(outfp); } else if (strcmp(tokens[0], "exit") == 0) { return; } else { if (verbosity > 0) { /* fputs("I don't understand and am ignoring:\n",stdout);*/ fputs("Don't understand: ",stdout); ptokens(tokens,tcnt,stdout); } if (safety == 1) exit(5); } break; case ST_CAT: if ((oldc == '\n') && (match(buf2,buf1))) { state = ST_CMDLINE; if (outfp != stdout) fclose(outfp); } else fputs(buf1,outfp); break; case ST_SED: if ((oldc == '\n') && (match(buf2,buf1))) { state = ST_CMDLINE; if (outfp != stdout) fclose(outfp); } else if ((oldc == '\n') && (*buf1 == schar)) fputs(buf1+1,outfp); else fputs(buf1,outfp); break; default: fputs("\nInternal Error -- unknown state!\n",stderr); exit(20); } oldc = c; } } void ptokens(tokens, size, fp) char *tokens[]; int size; FILE *fp; { register int i; for (i = 0; i < (size - 1); i++) { fputs(tokens[i],fp); putc(' ',fp); } if (size > 0) fputs(tokens[size - 1],fp); putc('\n',fp); fflush(fp); } int tokenize(tokens, tsize, buf) char *tokens[]; int tsize; char *buf; { register char c; char quote; int tcnt; char *tbuf; int state; tcnt = 0; state = TST_OUT; for (; ((c = *buf) != NULL); buf++) { switch (state) { case TST_OUT: switch (c) { case ' ': case '\t': case '\n': break; case '\'': case '"': case '`': quote = c; state = TST_QUOTE; if (tcnt >= tsize) return(tsize); tokens[tcnt++] = tbuf = (buf + 1); tbuf++; break; case '<': case '>': state = TST_DIR; if (tcnt >= tsize) return(tsize); tokens[tcnt++] = tbuf = buf; tbuf++; break; case '\\': buf++; default: state = TST_ALPHA; if (tcnt >= tsize) return(tsize); tokens[tcnt++] = tbuf = buf; tbuf++; break; } /* end of switch (c) */ break; case TST_QUOTE: if (c == quote) { *buf = 0; state = TST_OUT; } else { /* *tbuf++ = c; */ /* Currently no-op */ } break; case TST_DIR: if ((c != '>') && (c != '<')) { if ((c != ' ') && (c != '\t') && (c != '\n')) bumpstr(buf); *buf = 0; state = TST_OUT; } else { /* *tbuf++ = c; */ /* Currently no-op */ } break; case TST_ALPHA: if ((c == ' ') || (c == '\t') || (c == '\n')) { *tbuf = 0; state = TST_OUT; } else if (c != '\\') { *tbuf++ = c; /* *tbuf++ = c; */ /* Currently no-op */ } break; } /* end switch (state) */ } return (tcnt); } void bumpstr(buff) /* buff has to be a pointer in buf1 !!!!! */ register char *buff; { register char c1, c2; assert(((buff >= buf1) && (buff < buff1end))); c1 = *buff++; while (buff != buff1end) { c2 = *buff; *buff++ = c1; if ((buff == buff1end) || (c1 == 0)) break; c1 = *buff; *buff++ = c2; if (c2 == 0) break; } } void ind_error(tokens, tcnt) char *tokens[]; int tcnt; { fputs("Error in indirection -- ignored\n",stderr); ptokens(tokens,tcnt,stderr); } void fileparse(tokens, tcnt, buf, outfp) char *tokens[]; int tcnt; char *buf; FILE **outfp; { int i; *buf = 0; *outfp = NULL; for (i=0; i < tcnt; i++) { if (strcmp(">",tokens[i])==0) { if (*outfp) ind_error(tokens,tcnt); else if (++i == tcnt) ind_error(tokens,tcnt); else { if (overwrite == 1) { *outfp = fopen(tokens[i],"r"); if (*outfp != NULL) { fputs("Warning: will not overwrite: ",stderr); fputs(tokens[i],stderr); putc('\n',stderr); fflush(stderr); fclose(*outfp); tokens[i]="nil:"; } } *outfp = fopen(tokens[i],"w"); if (*outfp == NULL) ind_error(tokens,tcnt); } } else if (strcmp(">>",tokens[i])==0) { if (*outfp) ind_error(tokens,tcnt); else if (++i == tcnt) ind_error(tokens,tcnt); else { *outfp = fopen(tokens[i],"a"); if (*outfp == NULL) ind_error(tokens,tcnt); } } else if (strcmp("<<",tokens[i])==0) { if (*buf) ind_error(tokens,tcnt); else if (++i == tcnt) ind_error(tokens,tcnt); else strcpy(buf,tokens[i]); } } /* end for */ if (*outfp == NULL) *outfp = stdout; }