/* * Shar puts readable text files together in a package * * from which they are easy to extract. * * v 860716 M. Kersenbrock (tektronix!copper!michaelk) for Z80-CPM * - enhanced usage message * * v 860712 D. Wecker for ULTRIX and the AMIGA * - stripped down.. does patterns but no directories * - added a -u (unshar) switch */ #define CPM #ifdef CPM #include "c:stdio.h" #include "c:fcntl.h" #else #include #endif #ifdef CPM #define void int #define fputc putc extern char *getenv(),*malloc(),*index(),*rindex(); int cpmversion; #endif #ifdef AMIGA #include extern char *getenv(),*scdir(),*malloc(),*index(); #endif #ifdef ULTRIX #include extern char *getenv(),*scdir(),*malloc(),*index(); #endif #ifdef VMS #include extern char *getenv(),*scdir(),*malloc(); #endif #define BADCH ((int)'?') #define EMSG "" #define tell(s) {fputs(*nargv,stderr);fputs((s),stderr);fputc(optopt,stderr);fputc('\n',stderr);return(BADCH);} #define rescanopts() (optind = 1) int optind = 1, /* index into parent argv vector */ optopt; /* character checked for validity */ long fsize; /* length of file */ char *optarg; /* argument associated with option */ char *sav[100]; /* saved file names */ int savind; /* save index */ /* OPTIONS */ int Verbose = 0; /* provide append/extract feedback */ int Basename = 0; /* extract into basenames */ int Count = 0; /* count characters to check transfer */ char *Delim = "SHAR_EOF"; /* put after each file */ char Filter[100] = "cat"; /* used to extract archived files */ char *Prefix = NULL; /* line prefix to avoid funny chars */ int UnShar = 0; /* do we unshar an input file? */ char Usage1[] = "\nSHAR: Create/extract file archive for extraction by /bin/sh (normally).\n\ \n\ usage: shar [-u archive] [[-a] [-p prefix]\ [-d delim] [-bcv] files > archive]\n\ \n\ where: -a all the options (v,c,b,-pXX)\n"; char Usage2[] = " -b extract absolute paths into current directory\n\ -c check filesizes on extraction\n\ -d use this EOF delimiter instead of SHAR_EOF\n"; char Usage3[] = " -p use this as prefix to each line in archived files\n\ -u unshar \n\ -v verbose on extraction, incl. echoing filesizes\n"; #define SED "sed 's/^%s//'" /* used to remove prefix from lines */ #ifdef CPM #define OPTSTRING "U:AP:D:BCV" #else #define OPTSTRING "u:ap:d:bcv" #endif #ifdef VMS char *index(s,c) char *s; char c; { while (*s != 0 && *s != c) s++; if (*s == 0 && *s != c) s = 0; return(s); } #endif int header(ppchFiles) char *ppchFiles[]; { extern char *ctime(); register int i; auto long clock; register char **ppchList; char *pchOrg; char *pchName; register int problems = 0; pchOrg = getenv("ORGANIZATION"); pchName = getenv("NAME"); puts("#\tThis is a shell archive."); puts("#\tRemove everything above and including the cut line."); puts("#\tThen run the rest of the file through sh."); puts("#----cut here-----cut here-----cut here-----cut here----#"); puts("#!/bin/sh"); puts("# shar: Shell Archiver"); puts("#\tRun the following text with /bin/sh to create:"); for (ppchList = ppchFiles; *ppchList; ++ppchList) printf("#\t%s\n", *ppchList); #ifdef CPM if (cpmversion >= 0x30) { #endif (void) time(& clock); printf("# This archive created: %s", ctime(&clock)); #ifdef CPM } #endif if (pchName) printf("# By:\t%s (%s)\n", pchName, pchOrg ? pchOrg : "Dave Wecker Midnight Hacks"); return(0); } int archive(input, output) char *input, *output; { auto char line[BUFSIZ]; register FILE *ioptr; if (ioptr = fopen(input, "r")) { printf("%s << \\%s > %s\n", Filter, Delim, output); while(fgets(line, BUFSIZ, ioptr)) { if (Prefix) fputs(Prefix, stdout); fputs(line, stdout); if (Count) fsize += strlen(line); } puts(Delim); (void) fclose(ioptr); return(0); } else { fprintf(stderr, "shar: Can't open '%s'\n", input); return(1); } } void shar(file) char *file; { register char *basefile; basefile = file; if (!strcmp(file, ".")) return; fsize = 0; if (Basename) { while(*basefile) basefile++; /* go to end of name */ while(basefile > file && *(basefile-1) != '/') basefile--; } if (Verbose) printf("echo shar: extracting %s\n", basefile); if (archive(file, basefile)) exit(66); if (Count) { printf("if test %ld -ne \"`wc -c %s`\"\n",fsize,basefile); printf("then\necho shar: error transmitting %s ",basefile); printf("'(should have been %ld characters)'\nfi\n",fsize); } } int main(argc, argv) int argc; char **argv; { auto char *ppchFiles[256]; register int C; register char **ppchList = ppchFiles; register int errflg = 0; #ifdef CPM cpmversion = (bdoshl(0x0c,0) & 0xff); #endif while(EOF != (C = getopt(argc, argv, OPTSTRING))) { #ifdef CPM switch(isupper(C) ? tolower(C) : C ) { #else switch(C) { #endif case 'v': Verbose++; break; case 'c': Count++; break; case 'b': Basename++; break; case 'd': Delim = optarg; break; case 'a': /* all the options */ optarg = "XX"; Verbose++; Count++; Basename++; /* fall through to set prefix */ case 'p': (void) sprintf(Filter, SED, Prefix = optarg); break; case 'u': UnShar++; dounshar(optarg); break; default: errflg++; } } if (UnShar) exit(0); C = getarg(argc, argv); if (errflg || EOF == C) { if (EOF == C) fprintf(stderr, "shar: No input files\n"); fprintf(stderr, "%s%s%s", Usage1, Usage2, Usage3); exit(1); } savind = 0; do { if (getpat(optarg)) exit(2); } while (EOF != (C = getarg(argc, argv))); sav[savind] = 0; header(sav); for (ppchList = sav; *ppchList; ++ppchList) { #ifdef CPM strlower(*ppchList); #endif shar(*ppchList); } puts("#\tEnd of shell archive"); puts("exit 0"); exit(0); } getpat(pattern) char *pattern; { register char *ptr; int temp; #ifdef AMIGA while (ptr = scdir(pattern)) { #else ptr = pattern; { #endif sav[savind] = malloc(strlen(ptr)+1); strcpy(sav[savind++],ptr); #ifdef CPM temp = open(ptr,O_RDONLY); if (temp == -1) { #else if (access(ptr,4)) { #endif printf("No read access for file: %s\n",ptr); return(-1); } #ifdef CPM close(temp); #endif } return(0); } /* * get option letter from argument vector */ int getopt(nargc, nargv, ostr) int nargc; char **nargv, *ostr; { register char *oli; /* option letter list index */ static char *place = EMSG; /* option letter processing */ if(!*place) { /* update scanning pointer */ if(optind >= nargc || *(place = nargv[optind]) != '-' || !*++place) return(EOF); if (*place == '-') { /* found "--" */ ++optind; return EOF; } } /* option letter okay? */ if ((optopt = (int)*place++) == (int)':' || !(oli = index(ostr,optopt))) { if(!*place) ++optind; tell(": illegal option -- "); } if (*++oli != ':') { /* don't need argument */ optarg = NULL; if (!*place) ++optind; } else { /* need an argument */ if (*place) { /* no white space */ optarg = place; } else { if (nargc <= ++optind) { /* no arg */ place = EMSG; tell(": option requires an argument -- "); } else { optarg = nargv[optind]; /* white space */ } } place = EMSG; ++optind; } return(optopt); /* dump back option letter */ } int getarg(nargc, nargv) int nargc; char **nargv; { if (nargc <= optind) { optarg = (char *) 0; return EOF; } else { optarg = nargv[optind++]; return 0; } } dounshar(ArcNam) char *ArcNam; { register int i,j; register FILE *inptr,*outptr; auto char line[BUFSIZ]; int DirNum = -1; int Prefix = 0; char Dirs[5][40],FilNam[128],Delim[40],ScrStr[128]; char *ptr; if (!(inptr = fopen(ArcNam,"r"))) { fprintf(stderr,"shar: Can't open archive '%s'\n", ArcNam); return; } while (fgets(line,BUFSIZ,inptr)) { if (strncmp(line,"sed ",4) == 0) { Prefix = 0; if (!(ptr = index(line,'/'))) goto getfil; if (*++ptr == '^') ++ptr; while (*ptr++ != '/') Prefix++; goto getfil; } else if (strncmp(line,"cat ",4) == 0) { Prefix = 0; ; getfil: #ifdef VMS strcpy(FilNam,"["); #else FilNam[0] = 0; #endif for (i = 0; i <= DirNum; i++) { #ifdef VMS strcat(FilNam,"."); strcat(FilNam,Dirs[i]); #else strcat(FilNam,Dirs[i]); strcat(FilNam,"/"); #endif } #ifdef VMS strcat(FilNam,"]"); #endif getshpar(line,">",ScrStr); strcat(FilNam,ScrStr); #ifdef CPM tocpmformat(FilNam); /* tweek format as needed */ #endif getshpar(line,"<<",Delim); fprintf(stderr,"Creating %s ...",FilNam); outptr = fopen(FilNam,"w"); while (fgets(line,BUFSIZ,inptr)) { if (strncmp(line,Delim,strlen(Delim)) == 0) break; if (outptr) fputs(&line[Prefix],outptr); } if (outptr) { fclose(outptr); fprintf(stderr,"...done\n"); } else fprintf(stderr,"...error in creating file\n"); } else if (strncmp(line,"mkdir ",6) == 0) { sprintf(stderr,"Need to make directory: %s\n",&line[6]); } else if (strncmp(line,"chdir ",6) == 0) { if (line[6] == '.' && line[7] == '.') DirNum--; else strcpy(Dirs[++DirNum],&line[6]); if (DirNum < -1) DirNum = -1; } else if (strncmp(line,"cd ",3) == 0) { if (line[3] == '.' && line[4] == '.') DirNum--; else strcpy(Dirs[++DirNum],&line[3]); if (DirNum < -1) DirNum = -1; } } fclose(inptr); } getshpar(line,sea,par) char *line,*sea,*par; { register int i,j,k; register char *scr1,*scr2; while (*line) { scr1 = line; scr2 = sea; while (*scr1 && *scr2 && *scr1 == *scr2) { scr1++; scr2++; } if (*scr2 == 0) { if (*scr1 == 0) { *par = 0; return; } while ( *scr1 == ' ' || *scr1 == '\t' || *scr1 == '\\' || *scr1 == '\'' || *scr1 == '"') scr1++; while ( *scr1 != 0 && *scr1 != ' ' && *scr1 != '\t' && *scr1 != '\\' && *scr1 != '\'' && *scr1 != '"' && *scr1 != '\n' && *scr1 != '\r') *par++ = *scr1++; *par = 0; return; } line++; } *par = 0; } #ifdef CPM tocpmformat(filename) char *filename; { char buffer[100]; char extension[100]; register char *temp; int mod = 0; strcpy(buffer,filename); /* * Make sure we get rid of any pathnames */ if ((temp=rindex(buffer,'/')) != 0) { strcpy(buffer,(char *)((temp-buffer)+filename+1)); mod = 1; } if (strlen(filename) <= 8) { if (mod != 0) { strcpy(filename,buffer); } return(0); } /* * If it already is in "CPM" format we'll check if we need * to truncate the front filename part. */ if ((temp=index(buffer,'.')) != 0 ) { if ((temp-buffer) < 8) { if (mod != 0) { strcpy(filename,buffer); } return(0); } else { strcpy(extension,temp); strcpy(&buffer[8],extension); buffer[12] = '\0'; strcpy(filename,buffer); return(1); } } /* * OK, filename is longer than can be handled, and it doesnt have * a filetype "." marker already. We will put one in to minimize * truncation. */ strcpy(extension,&buffer[8]); buffer[8] = '.'; strcpy(&buffer[9],extension); buffer[12] = '\0'; strcpy(filename,buffer); return(2); } strlower(string) char *string; { register char *pointer; char c; for (pointer = string ; (c=*pointer) != '\0' ; pointer++ ) { if (isupper(c)) *pointer = tolower(c); } } #endif