mdoerr@uklirb.UUCP (10/21/86)
# This is a shell archive. # Remove everything above and including the cut line. # Then run the rest of the file through sh. #----cut here-----cut here-----cut here-----cut here----# #!/bin/sh # shar: Shell Archiver # Run the following text with /bin/sh to create: # SHAR.DOC # SHAR.C # README.AMG # # This archive created: Oct 21, 1986 -- 12:36:48 # By: a friendly ATARI ST hacker (using that wonderful machine :-) # echo shar: extracting SHAR.DOC sed 's/^XX//' << \SHAR_EOF > SHAR.DOC XXShar/Unshar for the ST! XX XXSome of you have been requesting a program to unshar USENET postings on the XXAtari ST. I finally could spare some time to port such a utility to the ST. XXIt has been written by Dave Wecker and was posted to mod.amiga.sources some XXtime ago. (It pays off to look into other news groups, too :-) XX XXI've tried to keep its original functionality: It should still work on UNIX, XXVMS and the Amiga. The Atari stuff is new and has been done by me. It does XXcontain #ifdef's for Megamax, Lattice and DRI-C. It has never been compiled XXwith the dev-kit compiler, because wild cards on the command line are a sure XXway to bomb every DRI-C program (look for the comments in the source). The XXprogram runs fine, however, when compiled with Megamax or Lattice. (Beware XXof bugs in the Lattice V.3.03 library!) XX XXIt's a great tool, that should be on every netlander's utility disk: Nice for XXUNIX folks (transfer only one file instead of many) and a real life saver XXfor all (poor) BITNET and VMS hackers, who don't have access to the Bourne XXshell. However, this program is not a REAL shell! XX XXIt will unshar most of the common shell archives (cat- and sed-type). But it XXstill has problems with some of the bizarre formats Rich $alz (moderator of XXmod.sources) has been posting lately. He's assigning file names to the shell XXvariable $OUT and unpacking on the ST ends up with only the last file of the XXarchive being put into the file $OUT. Stop him doing such strange things :-( XX XXAs all the CLI's for the ST (at least all I know of) don't do wild card XXexpansion, I have included a routine of my own. Drive specs, directories and XXambigous path names are accepted. Say 'a:', 'a:\', 'a:*.*', or 'a:\*.*' to XXshar all regular files on drive A. Or say 'megamax\headers', 'megamax\headers\', XX'megamax\headers\*.*', or 'megamax\headers\*.h' to pack all header files of XXthe Megamax compiler into an archive. XX XXShar output usually goes to stdout and can be redirected when calling the XXTTP-application from the desktop. As everyone probably knows by now, XXMegamax and Lattice programs want to do I/O-redirection of their own and XXcome into real problems when the redirection is done by a CLI. That's why XXI've added an additional -o option to the shell archiver. Use '-o outfile' XXinstead of '>outfile' and you're not going to have any problems. (Well, XXdon't flame me, iff you do get some problems. Send mail instead.) XX XXI'm including the README file of the original posting, too. Maybe someone XXis having a ST [real workhorse] and an Amiga [nice game machine]. XX XXMichael Doerr University of Kaiserslautern (West Germany) XX uucp: ...!seismo!unido!uklirb!mdoerr XX SHAR_EOF if test 2645 -ne "`wc -c SHAR.DOC`" then echo shar: error transmitting SHAR.DOC '(should have been 2645 characters)' fi echo shar: extracting SHAR.C sed 's/^XX//' << \SHAR_EOF > SHAR.C XX/* XX * Shar puts readable text files together in a package XX * from which they are easy to extract. XX * XX * v 860712 D. Wecker for ULTRIX and the AMIGA XX * - stripped down.. does patterns but no directories XX * - added a -u (unshar) switch XX * v 860715 DBW XX * - fixed bug with leading white space in unshar command recognition XX * - fixed bug in getting sh paramaters with quotes XX * XX * 13.10.86 started work on Atari ST Version - msd XX * XX */ XX XX#define ATARI XX#define MEGAMAX XX XX#include <stdio.h> XX XX#ifdef AMIGA XX#include <exec/types.h> XXextern char *getenv(),*scdir(),*malloc(),*index(); XX#endif XX XX#ifdef ULTRIX XX#include <sys/types.h> XXextern char *getenv(),*scdir(),*malloc(),*index(); XX#endif XX XX#ifdef VMS XX#include <types.h> XXextern char *getenv(),*scdir(),*malloc(); XX#endif XX XX#ifdef ATARI XX#include <osbind.h> XX XX#ifdef MEGAMAX XX#define BUFSIZ _BUFSIZE XX#define WORD int XX#endif XX XX#ifdef LATTICE XX/* Don't use the library of version 3.03 or you'll get bombs when opening XX * the 21st file after 20 files have been opened AND CLOSED. XX */ XX#define WORD short XX#define index strchr XX#define rindex strrchr XX#endif XX XX#ifdef DRI XX/* DON'T use wildcards (* or ?) on the command line of a DRI-C program. XX * The startup code tries to expand the wildcards in CP/M-68K fashion. XX * That's a guaranteed way to get bombs. XX */ XX#define WORD short XXextern char *fopen(); XX#endif XX XXextern char *malloc(),*index(),*rindex(); XX XXtypedef struct { XX char reserved[21]; /* bytes 0-20 */ XX char attrib; /* byte 21 */ XX WORD time; /* bytes 22-23 */ XX WORD date; /* bytes 24-25 */ XX long size; /* bytes 26-29 */ XX char fname[14]; /* bytes 30-43 */ XX} DTA; XX#endif XX XX XX#define BADCH ((int)'?') XX#define EMSG "" XX#define tell(s) {fputs(*nargv,stderr);fputs((s),stderr); \ XX fputc(optopt,stderr);fputc('\n',stderr);return(BADCH);} XX#define rescanopts() (optind = 1) XX XXint optind = 1, /* index into parent argv vector */ XX optopt; /* character checked for validity */ XXlong fsize; /* length of file */ XXchar *optarg; /* argument associated with option */ XXchar *sav[100]; /* saved file names */ XXint savind; /* save index */ XXFILE *OutPut; XX XX/* OPTIONS */ XXint Verbose = 0; /* provide append/extract feedback */ XXint Basename = 0; /* extract into basenames */ XXint Count = 0; /* count characters to check transfer */ XXchar *Delim = "SHAR_EOF"; /* put after each file */ XXchar Filter[100] = "cat"; /* used to extract archived files */ XXchar *Prefix = NULL; /* line prefix to avoid funny chars */ XXint UnShar = 0; /* do we unshar an input file? */ XX XX#define SED "sed 's/^%s//'" /* used to remove prefix from lines */ XX#define USAGE "[-u archive] [[-a] [-p prefix] [-d delim] [-bcv] [-o archive] files]" XX#define OPTSTRING "U:u:AaP:p:D:d:BbCcVvO:o:" XX XX#ifdef VMS XXchar *index(s,c) XXchar *s; XXchar c; XX{ XX while (*s != 0 && *s != c) s++; XX if (*s == 0 && *s != c) s = 0; XX return(s); XX} XX#endif XX XX#ifdef ATARI XXtime(clock) XXlong *clock; XX{ XX *clock = Gettime(); XX} XX XXchar *ctime(clock) XXlong *clock; XX{ XX char datetime[50]; XX static char *month[] = XX { "Jan", "Feb", "Mar", "Apr", "Mai", "Jun", XX "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; XX sprintf(datetime, "%s %d, %d -- %d:%02d:%02d\n", XX month[((*clock >> 21) & 0xf) - 1], XX (int) (*clock >> 16) & 0x1f, XX (int) ((*clock >> 25) & 0x7f) + 1980, XX (int) (*clock >> 11) & 0x1f, XX (int) (*clock >> 5) & 0x3f, XX (int) (*clock & 0x1f) * 2); XX return &datetime; XX} XX#endif XX XXint header(ppchFiles) XXchar *ppchFiles[]; XX{ XX extern char *ctime(); XX auto long clock; XX register char **ppchList; XX#ifdef ATARI XX char *pchOrg = "using that wonderful machine :-"; XX char *pchName = "a friendly ATARI ST hacker"; XX#else XX register char *pchOrg = getenv("ORGANIZATION"); XX register char *pchName = getenv("NAME"); XX#endif XX XX fputs("# This is a shell archive.\n", OutPut); XX fputs("# Remove everything above and including the cut line.\n", OutPut); XX fputs("# Then run the rest of the file through sh.\n", OutPut); XX fputs("#----cut here-----cut here-----cut here-----cut here----#\n", OutPut); XX fputs("#!/bin/sh\n", OutPut); XX fputs("# shar:\tShell Archiver\n", OutPut); XX fputs("# Run the following text with /bin/sh to create:\n", OutPut); XX for (ppchList = ppchFiles; *ppchList; ++ppchList) XX fprintf(OutPut, "#\t%s\n", *ppchList); XX time(& clock); XX fprintf(OutPut, "#\n# This archive created: %s", ctime(&clock)); XX if (pchName) XX fprintf(OutPut, "# By:\t%s (%s)\n#\n", pchName, XX pchOrg ? pchOrg : "Dave Wecker Midnight Hacks"); XX return(0); XX} XX XXint archive(input, output) XXchar *input, *output; XX{ XX auto char line[BUFSIZ]; XX register FILE *ioptr; XX register char *ctrl_z; XX XX if (ioptr = fopen(input, "r")) { XX fprintf(OutPut, "%s << \\%s > %s\n", Filter, Delim, output); XX while(fgets(line, BUFSIZ, ioptr)) { XX#ifdef ATARI XX /* My TVX usually appends ^Z to a file. */ XX if (ctrl_z = index(line, '\032')) { XX *ctrl_z++ = '\n'; XX *ctrl_z = '\0'; XX } XX#endif XX if (Prefix) fputs(Prefix, OutPut); XX fputs(line, OutPut); XX if (Count) fsize += strlen(line); XX } XX fputs(Delim, OutPut); XX fputc('\n', OutPut); XX fclose(ioptr); XX return(0); XX } XX else { XX fprintf(stderr, "shar: Can't open '%s'\n", input); XX return(1); XX } XX} XX XXshar(file) XXchar *file; XX{ XX register char *basefile = file; XX if (!strcmp(file, ".")) XX return; XX fsize = 0; XX if (Basename) { XX while(*basefile) XX basefile++; /* go to end of name */ XX while (basefile > file && XX#ifdef ATARI XX *(basefile-1) != '\\' && *(basefile-1) != ':') XX#else XX *(basefile-1) != '/') XX#endif XX basefile--; XX } XX if (Verbose) fprintf(OutPut, "echo shar: extracting %s\n", basefile); XX if (archive(file, basefile)) exit(66); XX if (Count) { XX fprintf(OutPut, "if test %ld -ne \"`wc -c %s`\"\n",fsize,basefile); XX fprintf(OutPut, "then\necho shar: error transmitting %s ",basefile); XX fprintf(OutPut, "'(should have been %ld characters)'\nfi\n",fsize); XX } XX} XX XXint main(argc, argv) XXint argc; XXchar **argv; XX{ XX auto char *ppchFiles[256]; XX register int C; XX register char **ppchList = ppchFiles; XX register int errflg = 0; XX XX OutPut = stdout; XX while(EOF != (C = getopt(argc, argv, OPTSTRING))) { XX switch(tolower(C)) { XX case 'v': XX Verbose++; XX break; XX case 'c': XX Count++; XX break; XX case 'b': XX Basename++; XX break; XX case 'd': XX Delim = optarg; XX break; XX case 'a': /* all the options */ XX optarg = "XX"; XX Verbose++; XX Count++; XX Basename++; XX /* fall through to set prefix */ XX case 'p': XX sprintf(Filter, SED, Prefix = optarg); XX break; XX case 'o': XX if (!(OutPut = fopen(optarg, "w"))) { XX fprintf(stderr, "shar: Can't open '%s'\n", optarg); XX exit(1); XX } XX break; XX case 'u': XX UnShar++; XX dounshar(optarg); XX break; XX default: XX errflg++; XX } XX } XX XX if (UnShar) exit(0); XX XX C = getarg(argc, argv); XX if (errflg || EOF == C) { XX if (EOF == C) XX fprintf(stderr, "shar: No input files\n"); XX fprintf(stderr, "usage: shar %s\n", USAGE); XX exit(1); XX } XX XX savind = 0; XX do { XX if (getpat(optarg)) exit(2); XX } XX while (EOF != (C = getarg(argc, argv))); XX XX sav[savind] = 0; XX header(sav); XX for (ppchList = sav; *ppchList; ++ppchList) shar(*ppchList); XX fputs("# End of shell archive\n", OutPut); XX fputs("exit 0\n", OutPut); XX exit(0); XX} XX XXint getpat (pattern) XXchar *pattern; XX{ XX#ifdef ATARI XX/* include normal, read-only, hidden, system and updated files */ XX#define all_files 0x27 XX XX DTA dta, *old_dta; XX char lead_in[256], path[256]; XX XX old_dta = (DTA *) Fgetdta(); XX Fsetdta(&dta); XX if (fix_path(pattern, &lead_in, &path)) XX { XX if (!Fsfirst(&path, all_files)) XX { XX do { XX sav[savind] = malloc(strlen(lead_in)+strlen(dta.fname)+1); XX strcpy(sav[savind], lead_in); XX strcat(sav[savind++], dta.fname); XX } while (!Fsnext()); XX } XX } XX Fsetdta(old_dta); XX#else XX register char *ptr; XX XX#ifdef AMIGA XX while (ptr = scdir(pattern)) { XX#else XX ptr = pattern; XX { XX#endif XX sav[savind] = malloc(strlen(ptr)+1); XX strcpy(sav[savind++],ptr); XX if (access(ptr,4)) { XX fprintf(stderr, "No read access for file: %s\n",ptr); XX return(-1); XX } XX } XX#endif XX return(0); XX} XX XX/* XX * get option letter from argument vector XX */ XXint getopt(nargc, nargv, ostr) XXint nargc; XXchar **nargv, *ostr; XX{ XX register char *oli; /* option letter list index */ XX static char *place = EMSG; /* option letter processing */ XX XX if(!*place) { /* update scanning pointer */ XX if(optind >= nargc || *(place = nargv[optind]) != '-' || !*++place) XX return(EOF); XX if (*place == '-') { /* found "--" */ XX ++optind; XX return EOF; XX } XX } /* option letter okay? */ XX if ((optopt = (int)*place++) == (int)':' || !(oli = index(ostr,optopt))) { XX if(!*place) ++optind; XX tell(": illegal option -- "); XX } XX if (*++oli != ':') { /* don't need argument */ XX optarg = NULL; XX if (!*place) XX ++optind; XX } XX else { /* need an argument */ XX if (*place) { /* no white space */ XX optarg = place; XX } XX else if (nargc <= ++optind) { /* no arg */ XX place = EMSG; XX tell(": option requires an argument -- "); XX } XX else { XX optarg = nargv[optind]; /* white space */ XX } XX place = EMSG; XX ++optind; XX } XX return optopt; /* dump back option letter */ XX} XX XXint getarg(nargc, nargv) XXint nargc; XXchar **nargv; XX{ XX if (nargc <= optind) { XX optarg = (char *) 0; XX return EOF; XX } XX else { XX optarg = nargv[optind++]; XX return 0; XX } XX} XX XXdounshar(ArcNam) XXchar *ArcNam; XX{ XX register int i,j,strt; XX register FILE *inptr,*outptr; XX auto char line[BUFSIZ]; XX int DirNum = -1; XX int Prefix = 0; XX char Dirs[5][40],FilNam[128],Delim[40],ScrStr[128]; XX char *ptr; XX XX if (!(inptr = fopen(ArcNam,"r"))) { XX fprintf(stderr,"shar: Can't open archive '%s'\n", ArcNam); XX return; XX } XX while (fgets(line,BUFSIZ,inptr)) { XX for (strt = 0; line[strt] == ' ' || line[strt] == '\t'; strt++) ; XX if (strncmp(&line[strt],"sed ",4) == 0) { XX Prefix = 0; XX if (!(ptr = index(&line[strt],'/'))) goto getfil; XX if (*++ptr == '^') XX if (*++ptr == '@') goto getfil; XX while (*ptr++ != '/') Prefix++; XX goto getfil; XX } XX else if (strncmp(&line[strt],"cat ",4) == 0) { XX Prefix = 0; XX ; XXgetfil: XX XX#ifdef VMS XX strcpy(FilNam,"["); XX#else XX FilNam[0] = 0; XX#endif XX XX for (i = 0; i <= DirNum; i++) { XX XX#ifdef VMS XX strcat(FilNam,"."); XX strcat(FilNam,Dirs[i]); XX#else XX strcat(FilNam,Dirs[i]); XX strcat(FilNam,"/"); XX#endif XX XX } XX XX XX#ifdef VMS XX strcat(FilNam,"]"); XX#endif XX XX getshpar(line,">",ScrStr); XX strcat(FilNam,ScrStr); XX getshpar(line,"<<",Delim); XX fprintf(stderr,"Creating %s ...",FilNam); XX fflush(stderr); XX outptr = fopen(FilNam,"w"); XX while (fgets(line,BUFSIZ,inptr)) { XX if (strncmp(line,Delim,strlen(Delim)) == 0) break; XX if (outptr) XX if (strlen(line) <= Prefix) XX fputs(line,outptr); XX else XX fputs(&line[Prefix],outptr); XX } XX if (outptr) { XX fclose(outptr); XX fprintf(stderr,"...done\n"); XX } XX else fprintf(stderr,"...error in creating file\n"); XX } XX else if (strncmp(&line[strt],"mkdir ",6) == 0) { XX fprintf(stderr,"Need to make directory:\t%s\n",&line[strt+6]); XX } XX else if (strncmp(&line[strt],"chdir ",6) == 0) { XX if (line[strt+6] == '.' && line[strt+7] == '.') DirNum--; XX else strcpy(Dirs[++DirNum],&line[strt+6]); XX if (DirNum < -1) DirNum = -1; XX } XX else if (strncmp(&line[strt],"cd ",3) == 0) { XX if (line[strt+3] == '.' && line[strt+4] == '.') DirNum--; XX else strcpy(Dirs[++DirNum],&line[strt+3]); XX if (DirNum < -1) DirNum = -1; XX } XX } XX fclose(inptr); XX} XX XXgetshpar(line,sea,par) XXchar *line,*sea,*par; XX{ XX register char *scr1,*scr2; XX XX while (*line) { XX scr1 = line; XX scr2 = sea; XX while (*scr1 && *scr2 && *scr1 == *scr2) { XX scr1++; XX scr2++; XX } XX if (*scr2 == 0) { XX if (*scr1 == 0) { XX *par = 0; XX return; XX } XX while ( *scr1 == ' ' || *scr1 == '\t' || XX *scr1 == '\\' || *scr1 == '\'' || *scr1 == '"') { XX if (*scr1 == '\'' || *scr1 == '"') { XX scr2 = scr1++; XX break; XX } XX scr1++; XX } XX if (*scr2 != 0) { XX while (*scr1 != *scr2 && *scr1 != 0) *par++ = *scr1++; XX *par = 0; XX return; XX } XX while ( *scr1 != 0 && *scr1 != ' ' && *scr1 != '\t' && XX *scr1 != '\n' && *scr1 != '\r') { XX if (*scr1 != '\\') *par++ = *scr1++; XX else scr1++; XX } XX *par = 0; XX return; XX } XX line++; XX } XX *par = 0; XX} XX XX#ifdef ATARI XXint fix_path (pattern, lead_in, path) XXregister char *pattern, *lead_in, *path; XX{ XX register int pat_len, state, attrib; XX register char *ptr; XX XX if ((!(pat_len = strlen(pattern))) || XX ((pat_len == 2) && (pattern[1] == ':')) || XX (pattern[pat_len-1] == '\\') ) XX state = 1; XX else XX { /* get attrib of path */ XX attrib = Fattrib(pattern, 0, 0); XX if (attrib == -33 /* file not found */) XX state = 3; XX /* Very strange feature (??? - bug ?) of GEMDOS: XX * This happens, when looking at non existing files and XX * *DIRECTORIES*. I've expected Fattrib returning 0x10, XX * but directories don't seem to be files to GEMDOS. XX * Assume we're looking at a directory. XX */ XX else if (attrib < 0 /* other errors */) XX state = 0; XX else if (!(attrib & 0x10) /* not a directory */) XX state = 2; XX else if ((attrib & 0x10) /* is a directory */) XX state = 3; XX else /* catch unexpected results */ XX state = 0; XX } XX switch (state) XX { XX case 0: XX *lead_in = '\0'; XX *path = '\0'; XX break; XX case 1: XX strcpy(lead_in, pattern); XX strcpy(path, pattern); XX strcat(path, "*.*"); XX break; XX case 2: XX strcpy(path, pattern); XX if ((ptr = rindex(pattern, '\\')) || XX (ptr = rindex(pattern, ':')) ) XX { XX strcpy(lead_in, pattern); XX lead_in[(ptr-pattern)+1] = '\0'; XX } XX else XX *lead_in = '\0'; XX break; XX case 3: XX strcpy(lead_in, pattern); XX strcat(lead_in, "\\"); XX strcpy(path, pattern); XX strcat(path, "\\*.*"); XX break; XX default: XX return 0; XX } XX return (state != 0); XX} XX#endif XX SHAR_EOF if test 13843 -ne "`wc -c SHAR.C`" then echo shar: error transmitting SHAR.C '(should have been 13843 characters)' fi echo shar: extracting README.AMG sed 's/^XX//' << \SHAR_EOF > README.AMG XX XXEnclosed is a first version of "shar.c" (v 860712 DBW) that will run on XXULTRIX (U**X 4.n), VMS and the AMIGA. I finally got fed up with ARCV XXMKARCV and decided to do things right. XX XXThe main item of interest is that it handles wild-cards on the AMIGA and will XXalso UNSHAR a file (for the AMIGA and VMS which don't necessarly have XXthe Bourne Shell). It will NOT create a SHAR file with sub directories. The XXAmiga version was done with MANX-Aztec-C, it probably needs some changes to XXrun under Lattice. XX XX/* Moderators note: This program will allow interchanging shar formats from XX * Unix and the Amiga. I have tried several Unix shar formats and they have XX * all successfully unshared using this program on the amiga, and this will XX * also create shar files that will unshar under Bourne Shell without any XX * problems. XX */ XX XX regards, XX dave (ucbvax!decwrl!cookie.dec.com!wecker) XX XXCreating a shar file: XX XX AMIGA: shar >foo.shar -a makefile *.h *.c XX XX VMS: create a batch job that executes: XX $ shar -a makefile *.h *.c XX edit the batch .LOG file (which is your shar file) XX XX U**X: shar -a makefile *.h *.c >foo.shar XX XX (P.S. the -a switch means do all options) XX XXExtracting from a shar file: XX XX AMIGA: shar -u foo.shar XX XX VMS: shar -u foo.shar XX XX U**X: shar -u foo.shar or sh foo.shar XX XX XXInstallation: XX XX AMIGA: cc -DAMIGA shar.c XX ln -o shar shar.o -lc XX XX VMS: cc/DEFINE=VMS shar.c XX link shar,sys$library:vaxcrtl/lib XX shar :== $dev:[dir]shar XX XX U**X: cc -O -DULTRIX -o shar shar.c -lc XX XX XXJust typing "shar" will yield a usage line. (Doc: thanks for the code to XXbase this off of). XX XX SHAR_EOF if test 1580 -ne "`wc -c README.AMG`" then echo shar: error transmitting README.AMG '(should have been 1580 characters)' fi # End of shell archive exit 0