mr@isrnix.UUCP (michael regoli) (11/21/85)
]:[ what follows is the source code for the recently-posted "shell.exe" to net.micro.pc. there have been many requests for kent's sources...*so* many, i had to post them. this package is public-domain and was downloaded from a local rbbs. for the UUENCODED(1C) version, please see the corrected version in net.micro.pc. the documentation is there also. the sources that follow have been successfully compiled using the AZTEC-C compiler. -- CHOP CHOP -- ######################################################### # # # This is a shell archive file. To extract files: # # # # 1) Make a directory for the files. # # 2) Write a file, such as "file.shar", containing # # this archive file into the directory. # # 3) Type "sh file.shar". Do not use csh. # # # ######################################################### # echo Extracting _croot.c: sed 's/^Z//' >_croot.c <<\STUNKYFLUFF Z/* Copyright (C) 1981,1982, 1983 by Manx Software Systems */ Z#include <stdio.h> Z#include <errno.h> Z#include <fcntl.h> Z#ifndef NULL Z#define NULL ((void *)0) Z#endif Z Zchar *get_first(), *get_next(), *sbrk(); Zchar *wilderr = "No wild cards in command names!!\r\n"; Z Z/* noexpand can be set by routines before calling _Croot */ Zint noexpand = 0; Z Z#define ARGMAX 256 Zstatic char *Argv[ARGMAX]; Zstatic int Argc; Zstatic char curr_path[128]; Z Z_Croot(cp,cmd) Zregister char *cp; Zint (*cmd)(); Z{ Z int returnval = 0; Z char *startbuf,*endbuf; Z register char *cp2; Z char *wild_match; Z char *index(),*rindex(), *save_str(); Z char *path,*copy; int j; Z char *quote; Z int k,omode; char *fname; Z int in = -1, out = -1; Z /* lets try not to free things not allocated by malloc */ Z startbuf = cp; endbuf = &cp[strlen(cp)]; Z if (!noexpand) Z { Z /* ls is a special case !!! */ Z if(0 == strncmp(cp,"ls",2) || 0 == strncmp(cp,"dir",3)) Z noexpand++; Z } Z Z /* loop through arguments */ Z for (Argc = 0;;) Z { Z /* skip blanks */ Z while (*cp == ' ' || *cp == '\t') Z ++cp; Z Z /* if you're at the end of command line, you're done */ Z if (*cp == 0) Z break; Z /* handle redirection . . . */ Z if (*cp == '>') Z { Z k = 1; Z if (cp[1] == '>') Z { Z ++cp; Z omode = O_CREAT | O_WRONLY | O_APPEND; Z } Z else Z omode = O_CREAT | O_WRONLY | O_TRUNC; Z goto redirect; Z } else if (*cp == '<') Z { Z k = 0; Z redirect: Z while (*++cp == ' ' || *cp == '\t') Z ; Z fname = cp; Z while(*++cp) Z if (*cp == ' ' || *cp == '\t') Z { Z *cp++ = 0; Z break; Z } Z close(k); Z if (k) Z out = k = open(fname,omode); Z else Z in = k = open(fname,O_RDONLY); Z if (k == -1) Z { Z perror("redirection"); Z return -1; Z } Z /* go back for next argument */ Z continue; Z } Z /* find beginning of next argument */ Z cp2 = cp; /* save original pointer to the string */ Z while (*++cp2) Z { Z /* if you hit a space char - stick a null in to terminate last Z argument Z */ Z if (*cp2 == ' ' || *cp2 == '\t') Z { Z *cp2++ = 0; Z break; Z } Z } Z Z /* if no wild card characters, do it the old fashioned way */ Z if (index(cp,'*') == NULL && index(cp,'?') == NULL) Z { Znotranslate: Z if (*cp == '\'') Z /* pass through untranslated, with quotes stripped */ Z { Z cp++; /* point past quote */ Z if ( NULL == (quote = rindex(cp,'\''))) Z { Z write(2,"sh - no close quotes on command line\r\n",38); Z goto free_args; Z } Z *quote = '\0'; Z } Z /* update the next argv pointer */ Z Argv[Argc] = cp; Z /* bump the argument count */ Z if (++Argc == ARGMAX) Z abort(); Z } Z else Z { Z if (*cp == '"' || *cp == '\'') Z goto notranslate; Z if (noexpand) Z goto notranslate; Z /* wild cards not permitted on first run thru */ Z if (Argc == 0) Z { Z write(2,wilderr,strlen(wilderr)); Z return -1; Z } Z /* if there is a path included, save it off */ Z if ((path = rindex(cp,'\\')) || (path = rindex(cp,'/'))) Z { Z copy = cp; Z /* copy to curr_path, mapping / to \ */ Z for (j = 0; j < sizeof(curr_path) && copy != path+1; copy++,j++) Z curr_path[j] = (*copy == '/' ? '\\' : *copy); Z /* terminate string */ Z curr_path[j] = '\0'; Z } Z else if (cp[1] == ':') Z { Z copy = cp; Z for (j = 0; j < 2; j++) Z curr_path[j] = *copy++; Z curr_path[j] = '\0'; Z } else Z /* null path */ Z curr_path[0] = 0; Z if (wild_match = get_first(cp)) Z { Z /* update the next argv pointer */ Z Argv[Argc]= save_str(wild_match); Z /* bump the argument count */ Z if (++Argc == ARGMAX) Z abort(); Z /* get the rest of the matching file names */ Z while (wild_match = get_next()) Z { Z Z /* update the next argv pointer */ Z Argv[Argc] = save_str(wild_match); Z /* bump the argument count */ Z if (++Argc == ARGMAX) Z abort(); Z } Z } Z } Z cp = cp2; /* point to beginning of next argument */ Z } Z Argv[Argc] = NULL; Z returnval=(*cmd)(Argc,Argv); Z if (in != -1) Z close(in); Z if (out != -1) Z close(out); Z /* free anything not dynamically allocated */ Zfree_args: Z if (!noexpand) Z { Z for(j = 1;j < Argc; j++) Z if ( Z !(Argv[j] >= startbuf && Argv[j] <= endbuf) /* not in cmd line */ Z && Argv[j] /* Not NULL */ Z ) Z free(Argv[j]); Z } Z noexpand = 0; Z return returnval; Z} Z Zchar * Zsave_str(s) Z register char *s; Z{ Z register char *r,*malloc(); Z int pathlen; Z /* squirrel away matched file name */ Z if (NULL == (r = malloc(strlen(s)+(pathlen = strlen(curr_path))+1))) Z abort(); Z strcat(curr_path,s); Z strcpy(r,curr_path); Z curr_path[pathlen] = '\0'; Z return r; Z} Z Zabort() Z{ Z write(2, "Too many args.", 14); Z _exit(200); Z} Z Z Ztypedef struct Z{ Z char dos_reserved[21]; Z char attribute; Z unsigned file_time; Z unsigned file_date; Z long file_size; Z char file_name[13]; Z} fcb; Zfcb wildcard; Z Zchar *get_first(fname) Z char *fname; Z{ Z register int result; Z /* set the disk transfer address */ Z bdos(0x1A,&wildcard); Z result = bdos(0x4E,fname,0); Z /* make the find first call */ Z if(2 == result || 18 == result) Z return NULL; Z return &(wildcard.file_name[0]); Z} Z Zchar *get_next() Z{ Z register int result; Z /* set the disk transfer address */ Z bdos(0x1A,&wildcard); Z result = bdos(0x4f,0,0); Z /* make the find next call */ Z if (18 == result) Z return NULL; Z return &(wildcard.file_name[0]); Z} STUNKYFLUFF set `sum _croot.c` if test 54651 != $1 then echo _croot.c: Checksum error. Is: $1, should be: 54651. fi # # echo Extracting cat.c: sed 's/^Z//' >cat.c <<\STUNKYFLUFF Z#include <stdio.h> Z#include <signal.h> Z#include <setjmp.h> Z Zvoid (*signal())(); Z ZFILE *fd1,*fd2; Z Zvoid (*oldsig)(); Zchar *fgets(); Zjmp_buf catenv; Zcatintr() Z{ Z signal(SIGINT,SIG_IGN); /* ignore signals */ Z fclose(fd1); Z fclose(fd2); Z signal(SIGINT,oldsig); /* restore shell interrupt */ Z longjmp(catenv,-1); Z} Z Zcat(argc,argv) Z char *argv[]; Z{ Z char *intmsg = "Interrupt received\n"; Z Z FILE *fdopen(), *fopen(); Z if (-1==setjmp(catenv)) Z { Z write(2,intmsg,strlen(intmsg)); Z return -1; Z } Z oldsig = signal(SIGINT,catintr); /* trap interrupts from keyboard */ Z /* get standard output opened for business */ Z if (NULL == (fd2 = fdopen(1,"w"))) Z { Z perror("cat : Can't open stdout"); Z } Z Z /* handle pipes */ Z if (argc == 1) Z { Z if (NULL == (fd1 = fdopen(0,"r"))) Z { Z perror("cat : Can't open stdin"); Z } Z _cat(); Z fclose(fd1);fclose(fd2); Z } Z /* handle specified files */ Z else Z { Z while(--argc) Z { Z if (NULL == (fd1 = fopen(*(++argv),"r"))) Z { Z fprintf(stderr,"can't open %s\n",*argv); Z continue; Z } Z _cat(); Z fclose(fd1); Z } Z } Z fclose(fd2); Z signal(SIGINT,oldsig); /* restore old int catcher */ Z} Z Z_cat() Z{ Z char buffer[512]; Z while (NULL != fgets(buffer,512,fd1)) Z fputs(buffer,fd2); Z} STUNKYFLUFF set `sum cat.c` if test 12297 != $1 then echo cat.c: Checksum error. Is: $1, should be: 12297. fi # # echo Extracting cd.c: sed 's/^Z//' >cd.c <<\STUNKYFLUFF Z#include <stdio.h> Zcd(argc,argv) Zchar *argv[]; Z{ Z static char *usage = "usage : cd newdir"; Z if (argc == 1) Z write(2,usage,strlen(usage)); Z if (-1 == chdir(*(++argv))) Z { Z perror("cd"); Z return -1; Z } Z return 0; Z} STUNKYFLUFF set `sum cd.c` if test 24433 != $1 then echo cd.c: Checksum error. Is: $1, should be: 24433. fi # # echo Extracting chmod.c: sed 's/^Z//' >chmod.c <<\STUNKYFLUFF Z#include <stdio.h> Z#include <stat.h> Z#ifdef MAIN Zmain Z#else Zch_mod Z#endif Z(argc,argv) Z char *argv[]; Z{ Z int or_mask,and_mask,file_stat; Z struct { int ax,bx,cx,dx,si,di,ds,es; } regs; Z extern int _dsval; Z char *current; Z regs.ds = _dsval; Z if (argc==1) Z { Z fprintf(stderr,"Usage : chmod +|-[ahw] file [file ...]\n"); Z } Z /* set attributes to default */ Z or_mask = 0; and_mask = 0xFFFF; Z while(--argc) Z { Z current = *(++argv); Z switch (*current) Z { Z case '-': Z while (*++current) Z { Z switch(*current) Z { Z case 'w': Z case 'W': Z or_mask |= ST_RDONLY; Z break; Z case 'h': Z case 'H': Z and_mask &= (ST_HIDDEN ^ 0xFFFF); Z break; Z case 'r': Z case 'R': Z or_mask |= ST_HIDDEN; Z break; Z case 'a': Z case 'A': Z and_mask &= (ST_ARCHIV ^ 0xFFFF); Z break; Z case 's': Z case 'S': Z and_mask &= (ST_SYSTEM ^ 0xFFFF); Z break; Z default: Z write(2,"invalid attribute\r\n",19); Z return -1; Z } Z } Z break; Z case '+': Z while(*++current) Z { Z switch(*current) Z { Z case 'w': Z case 'W': Z and_mask &= (ST_RDONLY ^ 0xFFFF); Z break; Z case 'h': Z case 'H': Z or_mask |= ST_HIDDEN; Z break; Z case 's': Z case 'S': Z or_mask |= ST_SYSTEM; Z break; Z case 'r': Z case 'R': Z and_mask &= (ST_HIDDEN ^ 0xFFFF); Z break; Z case 'a': Z case 'A': Z or_mask |= ST_ARCHIV; Z break; Z default: Z write(2,"invalid attribute\r\n",19); Z return -1; Z Z } Z } Z break; Z default: Z /* get current attribute */ Z regs.ax = 0x4300; Z regs.dx = (int)current; Z regs.ds = _dsval; Z sysint(0x21,®s,®s); Z file_stat = regs.cx; Z fprintf(stderr,"current attribute for %s = %x\n", Z current,file_stat); Z /* set new attribute */ Z file_stat |= or_mask; Z file_stat &= and_mask; Z regs.ax = 0x4301; Z regs.dx = (int)current; Z regs.cx = file_stat; Z regs.ds = _dsval; Z sysint(0x21,®s,®s); Z /* get attribute to see if it changed */ Z regs.ax = 0x4300; Z regs.dx = (int)current; Z regs.ds = _dsval; Z sysint(0x21,®s,®s); Z file_stat = regs.cx; Z fprintf(stderr,"new attribute for %s = %x\n", Z current,file_stat); Z break; Z } Z } Z} Z STUNKYFLUFF set `sum chmod.c` if test 37605 != $1 then echo chmod.c: Checksum error. Is: $1, should be: 37605. fi # # echo Extracting cmdlist.c: sed 's/^Z//' >cmdlist.c <<\STUNKYFLUFF Z Zextern int cmds(),ls(), cp(), rm(), do_prog(),pushd(),popd(),drive(), ver(), Z more(),fgrep(),scr_clear(),set(),ch_mod(),cat(),echo(), Z y(),t(),dump(), Z last(),invalid(),mv(),md(),touch(),cd(),pwd(),rd(),hist(),my_exit(); Ztypedef struct Z{ Z char *cmdname; Z int (*func)(); Z} builtin; Zbuiltin commands[] = Z{ Z "a:",drive, Z "b:",drive, Z "c:",drive, Z "cat",cat, Z "cd",cd, Z "chdir",cd, Z "chmod",ch_mod, Z "cls",scr_clear, Z "commands",cmds, Z "copy",cp, Z "cp",cp, Z "copy",cp, Z "d:",drive, Z "del",rm, Z "dir",ls, Z "dump",dump, Z "e:",drive, Z "echo",echo, Z "era",rm, Z "erase",rm, Z "error",last, Z "exit",my_exit, Z "f:",drive, Z "fgrep",fgrep, Z "g:",drive, Z "h:",drive, Z "hd",dump, Z "hist",hist, Z "history",hist, Z "i:",drive, Z "j:",drive, Z "ls",ls, Z "md",md, Z "mkdir",md, Z "more",more, Z "mv",mv, Z "no history",invalid, Z "popd",popd, Z "pushd",pushd, Z "pwd",pwd, Z "rd",rd, Z "rm",rm, Z "rmdir",rd, Z "set",set, Z "tee",t, Z "touch",touch, Z "version",ver, Z "y",y Z}; Zint numcmds = (sizeof(commands)/sizeof(builtin)); STUNKYFLUFF set `sum cmdlist.c` if test 20023 != $1 then echo cmdlist.c: Checksum error. Is: $1, should be: 20023. fi # # echo Extracting cmds: sed 's/^Z//' >cmds <<\STUNKYFLUFF Za: b: c: cat Zcd chdir chmod cls Zcommands copy cp copy Zd: del dir dump Ze: echo era erase Zerror exit f: fgrep Zg: h: hd hist Zhistory i: j: ls Zmd mkdir more mv Zno history popd pushd pwd Zrd rm rmdir set Ztee touch version y Z STUNKYFLUFF set `sum cmds` if test 18223 != $1 then echo cmds: Checksum error. Is: $1, should be: 18223. fi # # echo Extracting cmds.c: sed 's/^Z//' >cmds.c <<\STUNKYFLUFF Z#include <stdio.h> Z#include <fcntl.h> Ztypedef struct Z{ Z char *cmdname; Z int (*func)(); Z} builtin; Z Zchar *str_lower(); Z Zextern int result; Z Zextern int cmds(),ls(), cp(), rm(), do_prog(),pushd(),popd(),drive(), ver(), Z more(),fgrep(),scr_clear(),set(),ch_mod(),cat(),echo(), Z y(),t(),dump(), Z last(),invalid(),mv(),md(),touch(),cd(),pwd(),rd(),hist(),my_exit(); Z Zmy_exit(argc,argv) Z char *argv[]; Z{ Z exit(result); Z} Z Zver() Z{ Z extern char *version; Z write(2,version,strlen(version)); Z write(2,"\r\n",2); Z} Z Zextern builtin commands[]; Zextern int numcmds; Zchar *histerr = "no history"; Zint j,hiscount; Zchar *history[] = {NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL, Z NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}; Z Zint histsize = (sizeof(history)/sizeof(char *)); Z Zcmds() Z{ Z char *current; Z register int i,j,col; Z col = 1; Z for (i = 0; i < numcmds; i++) Z { Z current = commands[i].cmdname; Z write(1,current,j = strlen(current)); Z for (;j < 16;j++) Z write(1," ",1); Z if (col == 4) Z { Z col = 1; Z crlf(); Z } Z else Z ++col; Z } Z crlf(); Z} Z Zfindcmd(cmdbuf) Z char *cmdbuf; Z{ Z register int low,high,mid; Z char localbuf[256]; Z int cond; Z strcpy(localbuf,cmdbuf); Z cmdbuf = str_lower(localbuf); Z low = 0; Z high = numcmds - 1; Z while (low <= high) Z { Z mid = (low+high) / 2; Z if ( ( cond = strncmp( cmdbuf, Z commands[mid].cmdname, Z strlen(commands[mid].cmdname) ) ) < 0 ) Z high = mid - 1; Z else if (cond > 0) Z low = mid + 1; Z else Z { Z /* kludge to allow for program invocations like d:command */ Z if (cmdbuf[1] == ':') Z if (cmdbuf[2] == '\0') Z return mid; Z else Z return -1; Z return mid; Z } Z } Z return -1; Z} Z Zhist() Z{ Z register int i; Z char localbuf[256]; Z if (j < histsize) Z i = 0; Z else Z i = j - histsize + 1; Z for (;i <= j; i++) Z { Z sprintf(localbuf,"%d : %s\r\n",i,history[i % histsize]); Z write(1,localbuf,strlen(localbuf)); Z } Z} Z Zlast() Z{ Z printf("return code of last command %d\n",result); Z return result; Z} STUNKYFLUFF set `sum cmds.c` if test 01085 != $1 then echo cmds.c: Checksum error. Is: $1, should be: 01085. fi # # echo Extracting cp.c: sed 's/^Z//' >cp.c <<\STUNKYFLUFF Z#include <stdio.h> Zchar *me; Z/* cp.c - implements a version of UNIX cp */ Zchar target_name[128]; Z#ifndef MAIN Zcp Z#else Zmain Z#endif Z(argc,argv) Zint argc; Zregister char *argv[]; Z{ Z static char *usage = "cp : usage cp file1 [file2 . . fileN] target\r\n"; Z char target[128],*fname_part(); Z register int i; Z me = argv[0]; Z if (argc < 3) Z { Z write(2,usage,strlen(usage)); Z return(-1); Z } Z strcpy(target, argv[argc-1]); Z /* kill trailing backslashes */ Z if (target[i = strlen(target) - 1] == '\\') Z target[i] = '\0'; Z if (argc == 3) Z { Z if (target[1] == ':' && !target[2]) Z strcat(target,fname_part(argv[1])); Z /* if the target doesn't exist and it's not a directory then rename */ Z if (access(target,0) && !dirp(target)) Z { Z fprintf(stderr,"copying %s to %s\n",argv[1],target); Z filecopy(target,argv[1]); Z } Z else Z { Z /* if the target is a directory copy to same name that directory */ Z if (dirp(target)) Z { Z int len; Z strcpy(target_name,target); Z if (target_name[(len = strlen(target_name))-1] != '\\') Z { Z target_name[len = strlen(target_name)] = '\\'; Z target_name[len+1] = '\0'; Z } Z strcat(target_name,fname_part(argv[1])); Z fprintf(stderr,"copying %s to %s\n",argv[1],target_name); Z filecopy(target_name,argv[1]); Z } Z else Z { Z fprintf(stderr,"copying %s to %s\n",argv[1],target); Z filecopy(target,argv[1]); Z } Z } Z return(0); Z } Z /* handle special case of a drive designation */ Z if (target[(i = strlen(target))-1] != ':') Z if (!dirp(target)) Z { Z fprintf(stderr,"cp : %s isn't a directory\n",target); Z return(-1); Z } Z for (i = 1; i < argc-1; i++) Z { Z int len; Z strcpy(target_name,target); Z if (target_name[(len = strlen(target_name))-1] != '\\') Z { Z target_name[len = strlen(target_name)] = '\\'; Z target_name[len+1] = '\0'; Z } Z strcat(target_name,fname_part(argv[i])); Z if (!filep(argv[i])) Z { Z fprintf(stderr,"cp : %s isn't a file\n",argv[i]); Z continue; Z } Z fprintf(stderr,"copying %s to %s\n",argv[i],target_name); Z filecopy(target_name,argv[i]); Z } Z return 0; Z} STUNKYFLUFF set `sum cp.c` if test 27151 != $1 then echo cp.c: Checksum error. Is: $1, should be: 27151. fi # # echo Extracting crlf.c: sed 's/^Z//' >crlf.c <<\STUNKYFLUFF Zcrlf() Z{ Z static char *cr = "\r\n"; Z write(1,cr,2); Z} STUNKYFLUFF set `sum crlf.c` if test 19813 != $1 then echo crlf.c: Checksum error. Is: $1, should be: 19813. fi # # echo Extracting croot.c: sed 's/^Z//' >croot.c <<\STUNKYFLUFF Z/* Copyright (C) 1981,1982, 1983 by Manx Software Systems */ Z#include <errno.h> Z#include <fcntl.h> Z#ifndef NULL Z#define NULL ((void *)0) Z#endif Z Zchar *get_first(), *get_next(), *sbrk(); Z Z#define ARGMAX 256 Zstatic char *Argv[ARGMAX]; Zstatic int argvsize; Zstatic int Argc; Zstatic char curr_path[128]; Z Znoper() Z{ Z return 0; Z} Z Zint (*cls_)() = noper; Zextern char _ioflg[]; Z ZCroot(cp, first) Zregister char *cp; Z{ Z register char *cp2; Z char *save; Z char *wild_match; Z char *index(),*rindex(), *save_str(); Z char *path,*copy; int j; Z Z _ioflg[0] = isatty(0); /* set flag for i/o routines */ Z _ioflg[1] = isatty(1); /* set flag for i/o routines */ Z _ioflg[2] = isatty(2); /* set flag for i/o routines */ Z Z Z /* Null out first argument */ Z Argv[0] = ""; Z Argc = first; Z Z /* loop through arguments */ Z for (;;) Z { Z /* skip blanks */ Z while (*cp == ' ' || *cp == '\t') Z ++cp; Z Z /* if you're at the end of command line, you're done */ Z if (*cp == 0) Z break; Z Z /* find beginning of next argument */ Z cp2 = cp; /* save original pointer to the string */ Z *cp2 = (*cp2 == '/' ? '\\' : *cp2); Z while (*++cp2) Z { Z /* if you hit a space char - stick a null in to terminate last Z argument Z */ Z if (*cp2 == ' ' || *cp2 == '\t') Z { Z *cp2++ = 0; Z break; Z } Z *cp2 = (*cp2 == '/' ? '\\' : *cp2); Z } Z Z /* if no wild card characters, do it the old fashioned way */ Z if (index(cp,'*') == NULL && index(cp,'?') == NULL) Z { Z /* update the next argv pointer */ Z Argv[Argc] = cp; Z /* bump the argument count */ Z if (++Argc == ARGMAX) Z abort(); Z } Z else Z { Z /* if there is a path included, save it off */ Z if ((path = rindex(cp,'\\')) || (path = rindex(cp,'/'))) Z { Z copy = cp; Z /* copy to curr_path, mapping / to \ */ Z for (j = 0; j < sizeof(curr_path) && copy != path+1; copy++,j++) Z curr_path[j] = (*copy == '/' ? '\\' : *copy); Z /* terminate string */ Z curr_path[j] = '\0'; Z } Z else if (cp[1] == ':') Z { Z copy = cp; Z for (j = 0; j < 2; j++) Z curr_path[j] = *copy++; Z curr_path[j] = '\0'; Z } else Z /* null path */ Z curr_path[0] = 0; Z if (wild_match = get_first(cp)) Z { Z /* update the next argv pointer */ Z Argv[Argc]= save_str(wild_match); Z /* bump the argument count */ Z if (++Argc == ARGMAX) Z abort(); Z /* get the rest of the matching file names */ Z while (wild_match = get_next()) Z { Z Z /* update the next argv pointer */ Z Argv[Argc] = save_str(wild_match); Z /* bump the argument count */ Z if (++Argc == ARGMAX) Z abort(); Z } Z } Z } Z cp = cp2; /* point to beginning of next argument */ Z } Z Argv[Argc] = NULL; Z main(Argc,Argv); Z exit(0); Z} Z Zchar *save_str(s) Z register char *s; Z{ Z register char *r; Z int pathlen; Z /* squirrel away matched file name */ Z if (NULL == (r = sbrk(strlen(s)+(pathlen = strlen(curr_path))+1))) Z abort(); Z strcat(curr_path,s); Z strcpy(r,curr_path); Z curr_path[pathlen] = '\0'; Z return r; Z} Z Zabort() Z{ Z write(2, "Too many args.", 14); Z _exit(200); Z} Z Zexit(code) Z{ Z (*cls_)(); Z _exit(code); Z} Z Ztypedef struct Z{ Z char dos_reserved[21]; Z char attribute; Z unsigned file_time; Z unsigned file_date; Z long file_size; Z char file_name[13]; Z} fcb; Zfcb wildcard; Z Zchar *get_first(fname) Z char *fname; Z{ Z register int result; Z /* set the disk transfer address */ Z bdos(0x1A,&wildcard); Z result = bdos(0x4E,fname,0); Z /* make the find first call */ Z if(2 == result || 18 == result) Z return NULL; Z return &(wildcard.file_name[0]); Z} Z Zchar *get_next(fname) Z char *fname; Z{ Z register int result; Z /* set the disk transfer address */ Z bdos(0x1A,&wildcard); Z result = bdos(0x4f,0,0); Z /* make the find next call */ Z if (18 == result) Z return NULL; Z return &(wildcard.file_name[0]); Z} STUNKYFLUFF set `sum croot.c` if test 02895 != $1 then echo croot.c: Checksum error. Is: $1, should be: 02895. fi # # echo Extracting ctlbrk.asm: sed 's/^Z//' >ctlbrk.asm <<\STUNKYFLUFF Z; Copyright (C) 1985 by Manx Software Systems, Inc. Z; :ts=8 Z include lmacros.h Z Zdataseg segment word public 'data' Z extrn _PSP_:word Z _brkvec dw ? Z dw ? Z localstk dw 20 dup(?) Z stktop label word Z savess dw ? Z savesp dw ? Zdataseg ends Z Zourds dw 0 Z Z assume ds:dataseg Z; Z procdef ctl_brk_setup Z mov ourds,ds Z push ds Z mov ax,3523H ;get cntl-break (cntl-c) handler Z int 21H Z mov _brkvec,bx Z mov _brkvec+2,es Z mov dx,offset brk_handler Z mov ax,cs Z mov ds,ax Z mov ax,2523H ;set new cntl-break handler Z int 21H Z pop ds Z pret Z pend ctl_brk_setup Z Z procdef ctl_brk_restore Z push ds Z mov dx,_brkvec Z mov bx,word ptr _brkvec+2 Z mov ds,bx Z mov ax,2523H ;restore old cntl-break handler Z int 21H Z pop ds Z pret Z pend ctl_brk_restore Z Zbrk_handler proc far Z ;save ds and address our data segment Z push ds Z mov ds,ourds Z ;move to the local stack after saving dos stack Z push ax Z mov savess,ss Z mov savesp,sp Z mov ax,ds Z mov ss,ax Z mov sp,offset stktop Z ;save registers Z push bp Z push bx Z push cx Z push dx Z push si Z push di Z push es Z mov ah,051H ;find the current psp Z int 21H Z cmp bx,_PSP_ ;is it our program segment? Z je noabort Z ;set carry flag Z mov ax,0FFFFH ;set up to shift bit into carry Z rcr ax,1 Z jmp short done Znoabort: Z ;clear carry flag Z or ax,ax ;should clear carry Zdone: Z pop es Z pop di Z pop si Z pop dx Z pop cx Z pop bx Z pop bp Z mov ax,savess Z mov ss,ax Z mov sp,savesp Z pop ax Z pop ds Z jc abortend Z iret Zabortend: Z ret Zbrk_handler endp Z finish Z end STUNKYFLUFF set `sum ctlbrk.asm` if test 52105 != $1 then echo ctlbrk.asm: Checksum error. Is: $1, should be: 52105. fi # # echo Extracting doprog.c: sed 's/^Z//' >doprog.c <<\STUNKYFLUFF Zdo_prog(argc,argv) Zchar *argv[]; Z{ Z int result; Z if (666 == (result = fexecvp(argv[0],argv))) Z { Z invalid(argc,argv); Z perror(""); Z return -1; Z } Z return result; Z} STUNKYFLUFF set `sum doprog.c` if test 44858 != $1 then echo doprog.c: Checksum error. Is: $1, should be: 44858. fi # # echo Extracting drive.c: sed 's/^Z//' >drive.c <<\STUNKYFLUFF Z#define NULL (void *)0 Zdrive(argc,argv) Z char *argv[]; Z{ Z char *dir,*getcwd(); Z Z bdos(0xe,**argv - 'a'); /* select drive 0 */ Z if (NULL == (dir = getcwd(NULL,64))) Z return -1; Z free(dir); Z return 0; Z} STUNKYFLUFF set `sum drive.c` if test 37068 != $1 then echo drive.c: Checksum error. Is: $1, should be: 37068. fi # # echo Extracting dump2.c: sed 's/^Z//' >dump2.c <<\STUNKYFLUFF Z Z/* dump.c (10/83) Debug style dump of a file from any starting position. Z*/ Z#include <stdio.h> Z#include <ctype.h> Z#include <signal.h> Z#include <setjmp.h> Z#define FAIL 1 Z#define SUCCESS 0 Z#define TRUE (1) Z#define FALSE 0 Z#define FOREVER for (;;) Z#define PAUSE if (getch()=='\0') getch(); Z#define STDIN 0 Z#define STDOUT 1 Z#define STDERR 2 Zchar *dumpusage[] = Z{ Z "Usage: dump filespec [block [page]] | [segment:[offset]] [count]\r\n", Z "Where a block is 64K bytes and a page is 256 bytes.\r\n", Z "Segment:offset are standard 8086 notation in hexadecimal.\r\n", Z "Count is the number of bytes to dump in decimal.\r\n", Z NULL Z}; Zchar *index(); /* suppress warning about conversion to int */ Z#define BUFSIZE 512 Ztypedef unsigned ushort; Z Zstatic int _fmode = 0x8000; /* Lattice 'c' - forces binary I/O */ Zextern short errno; /* DOS 2.0 error number */ Zlong lseek(); Z Zstatic char buffer[BUFSIZE]; /* input buffer */ Zstatic ushort block = 0; /* block number ( 64k bytes/block ) */ Zstatic ushort page = 0; /* page number ( 256 bytes/page ) */ Zstatic ushort segment = 0; Zstatic ushort offset = 0; Zstatic long filpos = 0; /* beginning file position */ Zstatic long count = 0x7FFFFFFFL; /* number of bytes to dump */ Z Zvoid ohw(),ohb(),onib(),abort(); Z Zstatic jmp_buf env; Zvoid (*signal())(); Zstatic void (*oldsig)(); Zstatic onintr() Z{ Z signal(SIGINT,SIG_IGN); /* disable interrupts from kbd */ Z longjmp(env,-1); Z} Z Z#ifdef MAIN Zmain Z#else Zdump Z#endif Z(argc,argv) /* DUMP ENTRY */ Zint argc; Zchar *argv[]; Z{ Z char c; Z ushort i, numin, tot, file, cfrom; Z char *flag = 0; Z char *index(); Z oldsig=signal(SIGINT,onintr); Z if (-1 == setjmp(env)) Z { Z close(file); Z write(2,"Interrupted\r\n",13); Z signal(SIGINT,oldsig); Z return -1; Z } Z if (argc < 2) Z { Z char **u = (char **) dumpusage; Z while(*u) Z { Z write (2,*u,strlen(*u)); Z ++u; Z } Z return -1; Z } Z if ((file = open( argv[1], 0 )) == -1) Z abort( "cannot open", argv[1], errno ); Z Z if (argc > 2) { Z if ((flag = index( argv[2], ':' )) != NULL) { Z i = stch_i( argv[2], &segment ); Z stch_i( argv[2]+i+1, &offset ); Z } Z if (sscanf( argv[2], "%d", &block ) != 1) Z abort( "invalid block", argv[2], 0 ); Z } Z if (argc > 3) Z if (sscanf( argv[3], "%d", &page ) != 1) Z abort( "invalid page", argv[3], 0 ); Z Z if ( flag ) { Z filpos = (long)segment*16L + (long)offset; Z tot = offset; Z } Z else { Z filpos = (block * 65536L) + (page * 256); Z tot = page * 256; Z segment = block * 4096; Z } Z Z if (lseek( file, filpos, 0 ) == -1L) Z abort( "positioning to", argv[2], errno ); Z Z if (argc > 4) Z if (sscanf( argv[4], "%ld", &count ) != 1) Z abort( "invalid count", argv[4], 0 ); Z Z Z do { /* read & dump BUFSIZE bytes */ Z numin = read( file, buffer, BUFSIZE ); Z if (numin == -1) Z abort( "cannot read", argv[1], errno ); Z cfrom=0; Z while (cfrom < numin) { Z Z ohw(segment); /* print offset in hex */ Z putchar(':'); Z ohw(cfrom+tot); Z putchar(' '); Z Z for (i=0; i < 16; i++) { /* print 16 bytes in hex */ Z putchar(' '); Z ohb(buffer[cfrom++]); Z } Z Z putchar(' '); putchar(' '); putchar(' '); Z Z cfrom -= 16; Z for (i=0; i < 16; i++) { /* print 16 bytes in ASCII */ Z c = buffer[cfrom] & 0x7f; Z if ( isprint(c) ) /* if printable character */ Z putchar(c); Z else Z putchar('.'); /* else print period */ Z cfrom++; Z } Z Z putchar('\r'); putchar('\n'); /* print CR/LF */ Z Z if ((count -= 16) <= 0) /* is count exhausted? */ Z exit(0); Z } /* end of while */ Z tot += numin; Z if ( tot == 0 ) Z segment += 4096; Z } /* end of do */ Z while (numin == BUFSIZE); Z signal(SIGINT,oldsig); /* restore signal */ Z return 0; Z} /* end of main */ Z Zstatic void ohw(wrd) /* print a word in hex */ Zushort wrd; Z{ Z ohb( wrd>>8 ); Z ohb( wrd ); Z} Z Zstatic void ohb(byt) /* print a byte in hex */ Zchar byt; Z{ Z onib( byt>>4 ); Z onib( byt ); Z} Z Zstatic void onib(nib) /* print a nibble as a hex character */ Zchar nib; Z{ Z nib &= 15; Z putchar((nib >= 10) ? nib-10+'A': nib+'0'); Z} Z Zstatic void abort( msg1 ,msg2 ,errno) /* print error msg1, msg2, and nbr */ Zchar *msg1,*msg2; /* Does not close files. */ Zshort errno; Z{ Z char stemp[10]; Z Z write( STDERR, "ERR: ", 5 ); Z if (msg1) Z write( STDERR, msg1, strlen(msg1) ); Z if (msg2) Z write( STDERR, " ", 1 ); Z write( STDERR, msg2, strlen(msg2) ); Z if (errno) { Z sprintf( stemp," #%d", errno ); Z write( STDERR, stemp, strlen(stemp) ); Z } Z write( STDERR, "\r\n", 2 ); Z longjmp(env,-1); Z} Z/** END DUMP **/ Z Z#define BDOS_IN 7 /* input function for "getch" */ Z#define BDOS_OUT 6 /* output function for "putch" */ Z#define BDOS_CKS 11 /* check keyboard status for "kbhit" */ Z#define BDOS_BKI 10 /* buffered keyboardd input for "cgets" */ Z#define BDOS_PRT 9 /* print string for "cputs" */ Z Zstatic char pushback; /* character save for "ungetch" */ Z Zstatic getch() Z{ Zint c; Z Zif (pushback != '\0') Z { /* character was pushed back */ Z c = pushback; Z pushback = '\0'; Z return(c); Z } Zreturn(bdos(BDOS_IN, 0xFF) & 127); Z} Zstatic putch(c) Zchar c; Z{ Zbdos(BDOS_OUT, c&127); Zreturn(c); Z} Zstatic ungetch(c) Zchar c; Z{ Z Zif (pushback != '\0') return(-1); Zpushback = c; Zreturn(c); Z} Zstatic char *cgets(s) Zchar *s; Z{ Zchar *p; Z Zif (*s == 0) *s = 250; /* do not allow zero byte count */ Zbdos(BDOS_BKI, s); Zp = s+2; Zp[s[1]] = '\0'; /* set terminating byte */ Zreturn(p); Z} Zstatic cputs(s) Zchar *s; Z{ Zchar *p; Z Zfor (p = s; *p != '\0'; p++) ; /* find string terminator */ Z*p = '$'; Zbdos(BDOS_PRT, s); Z*p = '\0'; Zreturn; Z} Z Z Zstatic int stch_i(p,r) Z char *p; Z int *r; Z{ Z int count; Z int acc; Z int hdtoi(); Z count = 0; Z *r = 0; Z while (-1 != (acc = hdtoi(*p++))) Z { Z ++count; Z *r = (*r << 4) | acc; Z } Z return count; Z} Z Zstatic hdtoi(c) Z char c; Z{ Z c = toupper(c); Z if (!isxdigit(c)) Z return -1; Z if (isdigit(c)) Z return (c - '0'); Z return (c - 'A' + 10); Z} STUNKYFLUFF set `sum dump2.c` if test 53530 != $1 then echo dump2.c: Checksum error. Is: $1, should be: 53530. fi # # echo Extracting echo.c: sed 's/^Z//' >echo.c <<\STUNKYFLUFF Z Zecho(argc,argv) Z char *argv[]; Z{ Z register int i; Z for (i = 1; i < argc;i++) Z { Z write(2,argv[i],strlen(argv[i])); Z if (i < argc-1) Z write(2," ",1); Z } Z crlf(); Z return 0; Z} STUNKYFLUFF set `sum echo.c` if test 29675 != $1 then echo echo.c: Checksum error. Is: $1, should be: 29675. fi # # echo Extracting env.c: sed 's/^Z//' >env.c <<\STUNKYFLUFF Z#include <stdio.h> Z Z#define ENVSIZE 4000 Zextern int _PSP; Zvoid *calloc(); Zchar *environment=NULL, *str_upper(); Zint env_paragraph; Zchar *next_env; Z#define envlimit(a) &a[ENVSIZE-1] Z Z#ifdef MAIN Zmain Z#else Zset Z#endif Z(argc,argv) Z char *argv[]; Z{ Z if (!environment) Z init_env(); Z if (argc == 1) Z { Z show_env(); Z return 0; Z } Z while(--argc) Z { Z add_env(str_upper(*(++argv))); Z } Z return 0; Z} Z Zchar * Zstr_upper(c) Z register char *c; Z{ Z register char *save = c; Z while(*c) Z { Z *c = toupper(*c); Z c++; Z } Z return save; Z} Z Zchar * Zstr_lower(c) Z register char *c; Z{ Z register char *save = c; Z while(*c) Z { Z *c = tolower(*c); Z c++; Z } Z return save; Z} Zinit_env() Z{ Z extern unsigned _dsval; /* current data segment register value */ Z long fudgefactor; Z register int c; Z unsigned envseg; Z unsigned offset = 0; Z envseg = peekw(0x2c,_PSP); Z environment = calloc(1,ENVSIZE+16); Z fudgefactor = (long)_dsval << 4; /* convert to absolute paragraph */ Z fudgefactor += (unsigned)environment + 16; Z fudgefactor &= 0xFFFF0L; Z env_paragraph = (int)((fudgefactor >>4) & 0xFFFF); Z environment = (char *) (fudgefactor - (long)(_dsval << 4)); Z next_env = environment; Z while (c = peekb(offset,envseg)) Z { Z while (c = peekb(offset++,envseg)) Z { Z *next_env++ = c; Z } Z *next_env++ = '\0'; Z } Z} Z Zshow_env() Z{ Z register char *env; Z char c; Z for (env = environment;*env;) Z { Z while (c = *env++) Z write(1,&c,1); Z crlf(); Z } Z} Z Zstatic char *enverr = "No more environment space\r\n"; Zstatic char *enverr2 = "Improper environment string format!!\r\n"; Z Zadd_env(string) Z char *string; Z Z{ Z char *env_copy, *new, *index(); Z char *old = environment; Z char *name_end,*new_name_end; Z int added = 0; Z int namelen; Z Z if (NULL == (env_copy = new = calloc(1,ENVSIZE))) Z { Z write(2,enverr,strlen(enverr)); Z return -1; Z } Z Z while (*old) Z { Z if ( NULL == (name_end = index(old,'=')) || Z NULL == (new_name_end = index(string,'=')) Z ) Z { Z write(2,enverr2,strlen(enverr2)); Z free(env_copy); Z return -1; Z } Z namelen = (int)(name_end - old); Z if (!strncmp(old,string,namelen)) Z { Z if (new_name_end[1]) Z { Z /* if we don't have a string of the form name= */ Z /* copy new string instead of old string */ Z strcpy(new,string); Z } Z else Z /* if we have a set name= with no string then we want Z to remove the string from the environment Z */ Z ; Z added++; Z } Z else Z { Z strcpy(new,old); Z } Z new = &new[strlen(new)+1]; Z old = &old[strlen(old)+1]; Z if (new >= envlimit(new)) Z { Z write(2,enverr,strlen(enverr)); Z free(env_copy); Z return -1; Z } Z } Z if (!added) Z { Z strcpy(new,string); Z } Z new = &new[strlen(new)+1]; Z /* copy the copy back to the environment */ Z movmem(env_copy,environment,(int)(new-env_copy)+2); Z free(env_copy); Z return 0; Z} STUNKYFLUFF set `sum env.c` if test 56918 != $1 then echo env.c: Checksum error. Is: $1, should be: 56918. fi # # echo Extracting fexec.asm: sed 's/^Z//' >fexec.asm <<\STUNKYFLUFF Z; Copyright (C) 1984 by Manx Software Systems Z; :ts=8 Z include lmacros.h Zdataseg segment para public 'data' Zparam equ this word Zenv dw ? Zcline dw ?,? Zfcb1 dw ?,? Zfcb2 dw ?,? Z extrn errno_:word Zdataseg ends Z assume ds:dataseg Zsave_ss dw 0 Zsave_sp dw 0 Z procdef fexec,<<filname,ptr>,<enva,word>,<clinea,ptr>,<fcb1a,ptr>,<fcb2a,ptr>> Z; char *fexec(name,env,cline,fcb1,fcb2) Z; Z push si Z push di Z pushf Z push [030H] Z push [02EH] Z push ds Z push es Z mov cs:save_ss,ss Z mov cs:save_sp,sp Z; Z; set up parameter block for exec call Z; Z mov ax,enva Z mov env,ax Zifndef LONGPTR Z mov ax,ds Z mov es,ax Zendif Z ldptr ax,clinea,es Z mov cline,ax Z mov cline+2,es Z ldptr ax,fcb1a,es Z mov fcb1,ax Z mov fcb1+2,es Z ldptr ax,fcb2a,es Z mov fcb2,ax Z mov fcb2+2,es Z; Z mov ax,ds Z mov es,ax Z mov bx,offset param Z ldptr dx,filname,ds ;name of file to exec Z mov ax,04b00H Z int 21h Z mov ss,cs:save_ss Z mov sp,cs:save_sp Z pop es Z pop ds Z jnc noerror Z mov errno_,ax Z mov ax,666 Z jmp short done Znoerror: Z sub ax,ax Zdone: Z pop [02EH] Z pop [030H] Z popf Z pop di Z pop si Z pret Z pend fexec Z finish Z end STUNKYFLUFF set `sum fexec.asm` if test 35466 != $1 then echo fexec.asm: Checksum error. Is: $1, should be: 35466. fi # # echo Extracting fexecv.c: sed 's/^Z//' >fexecv.c <<\STUNKYFLUFF Z#ifdef DEBUG Z#ifndef FILE Z#include <stdio.h> Z#endif Z#include <ctype.h> Z#include <debug.h> Z#endif Z Z Z/* Copyright (C) 1983, 1984 by Manx Software Systems */ Z/* modified by kent williams to employ environment managed in env.c */ Zextern int env_paragraph; Z Zfexecv(path, argv) Zchar *path, **argv; Z{ Z register char *cp, *xp; Z int i; Z char buffer[258]; Z char fcb1[16], fcb2[16]; Z Z cp = buffer+1; Z i = 1; Z if (*argv) { Z ++argv; /* skip arg0, used for unix (tm) compatibility */ Z while (xp = *argv++) { Z if (i == 1) Z fcbinit(xp, fcb1); Z else if (i == 2) Z fcbinit(xp, fcb2); Z while (*xp) { Z if (cp >= buffer+256) Z goto done; Z *cp++ = *xp++; Z } Z *cp++ = ' '; Z ++i; Z } Z } Zdone: Z buffer[0] = cp - (buffer+2); Z /* terminate string */ Z buffer[buffer[0]+1] = 0; Z#ifdef DEBUG Z fprintf(stderr,"\nbuffer[0] = %d\n",buffer[0]); Z for (i = 1; buffer[i] ; i++) Z { Z if (isprint(buffer[i])) Z putchar(buffer[i]); Z else Z fprintf("buffer[%d] = %d\n",i,buffer[i]); Z } Z crlf(); Z#endif Z return fexec(path, env_paragraph, buffer, fcb1, fcb2); Z} Z STUNKYFLUFF set `sum fexecv.c` if test 22589 != $1 then echo fexecv.c: Checksum error. Is: $1, should be: 22589. fi # # echo Extracting fexecvp.c: sed 's/^Z//' >fexecvp.c <<\STUNKYFLUFF Zfexecvp(name, argv) Zchar *name, **argv; Z{ Z register char *cp, *xp; Z int result; Z char *getenv(), path[64]; Z Z if (666 != (result = tryexec("", name, argv))) Z return result; Z if ((cp = getenv("PATH")) != 0) { Z while (*cp) { Z xp = path; Z while (*cp) { Z if (*cp == ';') { Z ++cp; Z break; Z } Z *xp++ = *cp++; Z } Z *xp = 0; Z if (path[0] != 0) Z if (666 != (result = tryexec(path, name, argv))) Z return result; Z } Z } Z return 666; Z} Z Zstatic Ztryexec(dir, name, argv) Zchar *dir, *name, **argv; Z{ Z char newname[64]; Z register char *cp; Z char *rindex(),*index(); Z Z strcpy(newname, dir); Z if (((cp = index(newname, '/')) || (cp = index(newname, '\\'))) Z && *(cp+1) != '\0') Z strcat(newname, "/"); Z strcat(newname, name); Z if (index(name, '.') == 0) { Z strcat(newname, ".com"); Z if (666 != fexecv(newname, argv)) Z return wait(); Z strcpy(rindex(newname,'.'), ".exe"); Z } Z if (666 != fexecv(newname, argv)) Z return wait(); Z return 666; Z} STUNKYFLUFF set `sum fexecvp.c` if test 44134 != $1 then echo fexecvp.c: Checksum error. Is: $1, should be: 44134. fi # # echo Extracting fgrep.c: sed 's/^Z//' >fgrep.c <<\STUNKYFLUFF Z#include <stdio.h> Z#include <fcntl.h> Z Z#include <signal.h> Z#include <setjmp.h> Z Zvoid (*signal())(); Zvoid (*fgrepsig)(); Zjmp_buf fgrep_env; Z Zvoid fgrep_intr() Z{ Z /* restore old signal */ Z signal(SIGINT,fgrepsig); Z /* jump to exit */ Z longjmp(fgrep_env,-1); Z} Z ZFILE *fopen(),*fdopen(); Z Zchar *fgets(); Z Zfgrep( argc, argv ) Zint argc; Zchar * argv[]; Z { Z FILE * fd; Z int rc; Z char * pattern; Z /* handle interrupts */ Z if (-1 == setjmp(fgrep_env)) Z { Z static char *intmsg = "Interrupted\r\n"; Z write(2,intmsg,strlen(intmsg)); Z fclose(fd); Z return -1; Z } Z /* set signal catcher */ Z fgrepsig= signal(SIGINT,fgrep_intr); Z while( --argc ) Z { Z if( (*++argv)[0] == '-' ) Z switch( (*argv)[1] ) Z { Z default: Z fprintf( stderr, "invalid argument %s\n", *argv ); Z return(1); Z } Z else Z break; Z } Z Z if( argc == 0 ) Z { Z fprintf( stderr, "usage: fgrep pattern [file ...]\n" ); Z return(1); Z } Z Z pattern = *argv++; Z argc--; Z Z rc = 0; Z if( argc == 0 ) Z { Z fd = fdopen(0,"r"); Z rc = _fgrep( NULL, pattern, fd); Z fclose(fd); Z return( 0 ); Z } Z else Z while( argc-- ) Z { Z Z if( (fd = fopen( *argv, "r" )) == NULL ) Z fprintf( stderr, "couldn't open %s\n", *argv ); Z else Z { Z rc |= _fgrep( *argv, pattern, fd ); Z fclose( fd ); Z } Z argv++; Z Z } Z Z return( !rc ); Z signal(SIGINT,fgrepsig); Z } Z Z Z_fgrep( file, pattern, fd ) Zchar * file; Zchar * pattern; ZFILE * fd; Z { Z char line[BUFSIZ]; Z int rc; Z int linenumber = 1; Z rc = 0; Z while( fgets( line, sizeof(line), fd ) != NULL ) Z { Z if( rc = match( pattern, line ) ) Z printf( "%s %d: %s", (file) ? file : "stdin", linenumber, line ); Z linenumber++; Z } Z return( rc ); Z Z } Z Zmatch( pattern, line ) Zregister char * pattern; Zchar * line; Z { Z /* not a great algorithm */ Z register char * ptr; Z char * end; Z int plen = strlen(pattern); Z int llen = strlen(line); Z Z if( plen > llen ) Z return( 0 ); Z Z end = line+(llen-plen); Z Z for( ptr=line; ptr < end; ptr++ ) Z { Z if( strncmp( pattern, ptr, plen ) == 0 ) Z return( 1 ); Z } Z Z return( 0 ); Z } STUNKYFLUFF set `sum fgrep.c` if test 15656 != $1 then echo fgrep.c: Checksum error. Is: $1, should be: 15656. fi # # echo Extracting getcmd.c: sed 's/^Z//' >getcmd.c <<\STUNKYFLUFF Z#include <stdio.h> Z#include <fcntl.h> Z Zchar *gets(); Zchar rest[256]; Zchar *rptr = NULL; Zchar pipeactive = 0; Zcurrname = 0; Zchar *pipename[2] = { Z "shtmp1", Z "shtmp2"}; Zchar * Zgetnextcmd(buf) Z char *buf; Z{ Z char *fgets(),*index(),*pipe,*semi; Z if (!rptr) Z { Z register char *c; Z if (0 == read(0,rest,sizeof(rest))) Z return NULL; Z c = rptr = rest; Z while (*c) Z { Z if (*c == '\r' || *c == '\n') Z { Z *c = '\0'; Z break; Z } Z ++c; Z } Z Z } Z pipe = index(rptr,'|'); Z semi = index(rptr,';'); Z if (pipe == NULL && semi == NULL) Z { Z strcpy(buf,rptr); Z if (pipeactive) Z { Z pipeactive = 0; Z strcat(buf," < "); Z strcat(buf,pipename[currname]); Z } Z rptr=NULL; Z } Z /* one or the other, or both are not NULL, so comparison is in order */ Z else if (pipe && (!semi || (pipe < semi))) Z { Z *pipe = '\0'; /* terminate string */ Z strcpy(buf,rptr); /* copy to buf */ Z rptr = pipe+1; /* set up rest */ Z if (pipeactive++) Z { Z pipeactive = 1; Z strcat(buf," < "); Z strcat(buf,pipename[currname]); Z } Z strcat(buf," > "); Z currname ^= 1; /* flip flop pipe names */ Z strcat(buf,pipename[currname]); Z } Z else if (semi && (!pipe || (semi < pipe))) Z /* we have a semicolon to deal with */ Z { Z *semi = '\0'; Z strcpy(buf,rptr); Z rptr = semi+1; Z if (pipeactive) Z { Z pipeactive = 0; Z strcat(buf," < "); Z strcat(buf,pipename[currname]); Z } Z } Z return buf; Z} STUNKYFLUFF set `sum getcmd.c` if test 06449 != $1 then echo getcmd.c: Checksum error. Is: $1, should be: 06449. fi # # echo Extracting invalid.c: sed 's/^Z//' >invalid.c <<\STUNKYFLUFF Z Zinvalid(argc,argv) Z char *argv[]; Z{ Z register int i; Z static char *invmsg = "sh : bad command : "; Z write(2,invmsg,strlen(invmsg)); Z for (i = 0; i < argc;i++) Z { Z write(2,argv[i],strlen(argv[i])); Z write(2," ",1); Z } Z return -1; Z} STUNKYFLUFF set `sum invalid.c` if test 00995 != $1 then echo invalid.c: Checksum error. Is: $1, should be: 00995. fi # # echo Extracting ls.c: sed 's/^Z//' >ls.c <<\STUNKYFLUFF Z#include <stdio.h> Z Ztypedef struct Z{ Z char attribute; Z unsigned file_time; Z unsigned file_date; Z long file_size; Z char file_name[13]; Z} file_desc; Z Ztypedef struct Z{ Z char dos_reserved[21]; Z file_desc file; Z} fcb; Z Z#define maxfiles 128 Z Zchar printbuf[256]; Zfile_desc *getfirst(),*getnext(); Zchar *index(), *rindex(); Zint mode = 0x10; Zint verbose=0,column=4,recurse=0; Zint quiet = 0; Zint drivenum = 0; Zlong time(); Zshort year; Z Zdo_return(result) Z{ Z verbose = quiet = recurse = 0; Z column = 4; Z return result; Z} Z#ifndef MAIN Zls Z#else Zmain Z#endif Z(argc,argv) Zchar *argv[]; Z{ Z int noargs; Z char *current; Z char namebuf[128]; Z /* Z * initialize statics Z */ Z mode = 0x10; Z verbose=0;column=4;recurse=0; Z quiet = 0; Z drivenum = 0; Z /* Z * get current time Z */ Z year = (int)((time(NULL) >> 25) & 0x7F) + 80; Z /* Z * set up a default search name Z */ Z if (noargs = (argc == 1)) Z argc++; Z while(--argc) Z { Z if (noargs) Z current = "*.*"; Z else Z current = *(++argv); /* get current file name */ Z if (*current == '-') Z { Z ++current; /* point past - */ Z while (*current) Z { Z switch (*current++) Z { Z case 'l': Z case 'L': Z verbose = 1; Z if (column != 1) Z column = 2; Z if (quiet) Z { Z fprintf(stderr,"ls : verbose and quiet conflict\n"); Z do_return(-1); Z } Z break; Z case 'q': Z case 'Q': Z quiet = 1; Z if (verbose) Z { Z fprintf(stderr,"ls : quiet and verbose conflict\n"); Z do_return(-1); Z } Z break; Z case 'c': Z case 'C': Z column = 1; Z break; Z case 'a': Z case 'A': Z mode = 0x2 + 0x4 + 0x10; Z break; Z case 'r': Z case 'R': Z recurse = 1; Z mode = 0x2 + 0x4 + 0x10; Z break; Z default: Z break; Z } Z } Z /* if we're down to one argument after looking at all the Z switches, we need to set noargs to true */ Z if (noargs = (argc == 1)) Z argc++; Z continue; Z } Z /* if a drive is specified, figure out what drive it is */ Z if (current[1] == ':') Z { Z drivenum = toupper(current[0]) - 'A' + 1; Z } Z else Z drivenum = 0; Z /* if no wild cards, look for directory and drive names */ Z if ( NULL == index(current,'?') && NULL == index(current,'*')) Z { Z if (getfirst(current)->attribute & 0x10) Z { Z strcpy(namebuf,current); Z strcat(namebuf,"\\*.*"); Z current = namebuf; Z } Z /* look for drive names */ Z else if (current[strlen(current)-1] == ':' && Z !current[strlen(current)]) Z { Z strcpy(namebuf,current); Z strcat(namebuf,"\\*.*"); Z current = namebuf; Z } Z } Z do_dir(current); Z } Z do_return( 0); Z} Z Zdo_dir(current) Z char *current; Z{ Z typedef file_desc fblock[maxfiles]; /* as many as we'll likely need */ Z file_desc *files; Z file_desc *curr_file,*getnext(); Z void *malloc(); Z unsigned int ftime,date; Z int i,j,col; Z int files_cmp(); Z long total = 0; Z char atts[4]; /* drw */ Z /* allocate file block */ Z if (NULL == (files = malloc(sizeof(fblock)))) Z { Z fprintf(stderr,"Not enough memory to do directory\n"); Z return -1; Z } Z /* look for match */ Z i = 0; Z if (!(curr_file = getfirst(current))) Z { Z printf(stderr,"ls : no files matching %s\n",current); Z free(files); Z return; Z } Z files[i++] = *curr_file; Z /* get all matching */ Z while ((curr_file = getnext()) && i < maxfiles) Z files[i++] = *curr_file; Z if (i > 1) Z qsort(files,i,sizeof(file_desc),files_cmp); Z if (!quiet) Z { Z write(1,"\r\n",2); Z write(1,current,strlen(current)); Z write(1,"\r\n",2); Z } Z col = 1; Z for (j = 0; j < i; j++) Z { Z register char *c = files[j].file_name; Z if (*c == '.') Z continue; /* filter out . and .. */ Z while (*c) Z { Z *c = tolower(*c); Z c++; Z } Z if (verbose) Z { Z register char att = files[j].attribute; Z register int fyear; Z fyear = ((files[j].file_date >> 9) & 0x7F)+80; Z atts[3] = 0; /* terminate string */ Z atts[0] = att & 0x10 ? 'd' : '-'; Z atts[1] = att & 2 ? '-' : 'r'; Z atts[2] = att & 1 ? '-' : 'w'; Z if (atts[0] == 'd') Z { Z register int k; Z sprintf(printbuf,"%s %s\\",atts,files[j].file_name); Z write(1,printbuf,strlen(printbuf)); Z k = 12 - strlen(files[j].file_name)+7; Z while(k--) Z write(1," ",1); Z Z } Z else Z { Z total += files[j].file_size; Z sprintf(printbuf,"%s %-12s %-6ld ",atts,files[j].file_name, Z files[j].file_size); Z write(1,printbuf,strlen(printbuf)); Z } Z ftime = files[j].file_time; Z date = files[j].file_date; Z if (year == fyear) Z { Z sprintf(printbuf,"%02d/%02d %02d:%02d ", Z ((date >> 5) & 0x0F), /* month */ Z date & 0x1F, /* day */ Z (ftime >> 11) & 0x1F, /* hours */ Z (ftime >> 5) & 0x3F); /* minutes */ Z write(1,printbuf,strlen(printbuf)); Z } Z else Z { Z sprintf(printbuf,"%02d/%02d ", Z ((date >> 5) & 0x0F), /* month */ Z fyear, /* file year */ Z (ftime >> 11) & 0x1F, /* hours */ Z (ftime >> 5) & 0x3F); /* minutes */ Z write(1,printbuf,strlen(printbuf)); Z } Z } Z else Z { Z if (files[j].attribute & 0x10) Z { Z register int k; Z sprintf(printbuf,"%s\\",files[j].file_name); Z write(1,printbuf,strlen(printbuf)); Z k = 16 - strlen(files[j].file_name); Z while(--k) Z write(1," ",1); Z Z } Z else Z { Z sprintf(printbuf,"%-13s ",files[j].file_name); Z write(1,printbuf,strlen(printbuf)); Z } Z } Z if (col == column) Z { Z col = 1; Z write(1,"\r\n",2); Z } Z else Z col++; Z } Z write(1,"\r\n",2); Z if (verbose) Z { Z sprintf(printbuf,"%ld bytes in %d files ",total,i); Z write(1,printbuf,strlen(printbuf)); Z pr_freespace(); Z } Z if (recurse) Z for (j = 0; j < i; j++) Z { Z /* we've got a subdirectory */ Z if (files[j].attribute & 0x10 && files[j].file_name[0] != '.') Z { Z char *path; Z char dirname[48]; Z if (!strcmp(current,"*.*")) Z dirname[0] = '\0'; Z else Z strcpy(dirname,current); Z if (path = rindex(dirname,'\\')) Z *(++path) = '\0'; Z strcat(dirname,files[j].file_name); /* get name */ Z strcat(dirname,"\\*.*"); Z do_dir(dirname); Z } Z } Z free(files); Z} Z Zfiles_cmp(a,b) Z file_desc *a,*b; Z{ Z return strcmp(a->file_name,b->file_name); Z} Z Zfcb tmp; Z Zfile_desc *getfirst(fname) Z char *fname; Z{ Z register int result; Z /* set the disk transfer address */ Z bdos(0x1A,&tmp); Z result = bdos(0x4E,fname,mode); Z /* make the find first call */ Z if(2 == result || 18 == result) Z return NULL; Z return &(tmp.file); Z} Z Zfile_desc *getnext() Z{ Z register int result; Z /* set the disk transfer address */ Z bdos(0x1A,&tmp); Z result = bdos(0x4f,0,0); Z /* make the find next call */ Z if (18 == result) Z return NULL; Z return &(tmp.file); Z} Z Z/* determine available space on default drive Z*/ Z Zpr_freespace() Z{ Z /* register arguments for INT */ Z struct {int ax,bx,cx,dx,si,di,ds,es;}sysr; Z unsigned int retstat; /* flags returned from INT */ Z Z#define cls_avail sysr.bx /* number of available clusters */ Z#define cls_total sysr.dx /* total number of clusters on volume */ Z#define byt_sectr sysr.cx /* bytes per sector */ Z#define sec_clstr sysr.ax /* sectors per cluster */ Z Z unsigned long byt_clstr, /* bytes per cluster */ Z vol_total, /* total size of volume, bytes */ Z fre_total; /* size of free space, bytes */ Z Z sysr.ax = 0x3600; /* get disk free space function code */ Z sysr.dx = drivenum; /* (DL) = drive id, 0=current, 1=A, */ Z retstat = sysint(0x21,&sysr,&sysr); /* invoke DOS */ Z if( sec_clstr!=0xffff ) Z { Z byt_clstr = byt_sectr * sec_clstr; Z vol_total = cls_total * byt_clstr; Z fre_total = cls_avail * byt_clstr; Z fprintf(stdout, Z "%lu out of %lu bytes available on %c:\n", Z fre_total,vol_total, Z drivenum ? drivenum + 'A' - 1 : bdos(0x19,0,0)+'A'); Z } Z} STUNKYFLUFF set `sum ls.c` if test 06358 != $1 then echo ls.c: Checksum error. Is: $1, should be: 06358. fi # # echo Extracting main.c: sed 's/^Z//' >main.c <<\STUNKYFLUFF Z#line 1 "main.s" Z#include <stdio.h> Z#include <ctype.h> Z#include <signal.h> Z#include <fcntl.h> Z#include <setjmp.h> Ztypedef struct /* used to find builtin commands */ Z{ Z char *cmdname; Z int (*func)(); Z} builtin; Z Zextern builtin commands[]; Zextern char histerr[]; Zextern int j,hiscount; Zextern char *history[]; Zextern int histsize; Zextern int numcmds; Zstatic int quiet = 0; Z Zchar *version = "SHELL VERSION 1.2 Kent Williams"; Z Zjmp_buf env; Z Zchar *pipename[] = Z{ Z "\\shtmp1", Z "\\shtmp2" Z}; Z Zchar cmdbuf[512]; Zint currname = 0; Zint result = 0; Z Zmain(argc,argv) Z char *argv[]; Z{ Z signal(SIGINT,SIG_IGN); /* ignore breaks */ Z Z quiet = !isatty(0); /* quiet = batch shell */ Z Z /* initialize local environment */ Z init_env(); Z cli(); Z exit(0); Z} Z Z#ifndef SNODEBUG Z#define SNODEBUG Z#endif Z#line 46 "main.s" Z Z/* Z * statemachine cli Z */ Zcli () Z Z#line 48 "main.s" Z{ Z#line 49 "main.s" Z/* global variables */ Z int i; Z int repeat, state, inpipe = 0; Z static char localbuf[256]; Z static char histbuf[256]; Z static char tail[256]; Z int histindex,argindex,takeline; Z char *local = localbuf; Z char *current,*curr_save; Z char *ntharg(), *argptr; Z char *savestr(); Z Z Z/* Z * end of declarations for cli Z */ Z/* $ */ goto getline; Z#line 62 "main.s" Z Zgetline: Z{ Z#line 62 "main.s" Z /* kill tmp files */ Z unlink(pipename[0]); unlink(pipename[1]); Z Z hiscount = j % histsize; /* hiscount is current position in history */ Z if(!quiet) Z fprintf(stderr,"%d%% ",j); Z Z/* Z * The following code simply reads a line from standard input. Z * It is so complicated because when you save the standard stream Z * files and execute another program/command, standard input is Z * left in an uncertain state - the FILE stdin seems to be at EOF, Z * even when standard input is associated with the console, and Z * cr/lf combinations show up as line terminators, whereas usually Z * only linefeeds get placed in the input stream. Z * WHY? beats me. Something could be wrong with Z * 1. AZTEC C runtime Z * 2. PCDOS Z * 3. Me Z * 4. All three, or permutations of 1-3 reducto ad absurdum. Z * All I know is this works Z */ Z /* clear command buffer so string read is null terminated */ Z setmem(cmdbuf,sizeof(cmdbuf),0); Z for (current = cmdbuf;;current++) Z { Z int readresult; Z if ((readresult = read(0,current,1)) == 0 || Z readresult == -1) Z { Z/* $ */ goto terminal; Z } Z if (*current == '\r') Z { Z if ((readresult = read(0,current,1)) == 0 || Z readresult == -1) Z { Z/* $ */ goto terminal; Z } Z *current = '\0'; Z break; Z } Z else if (*current == '\n') Z { Z *current = '\0'; /* terminate string */ Z break; Z } Z } Z current = cmdbuf; /* point current at start of buffer */ Z/* Z * end of input weirdness Z */ Z /* if we're recycling history strings, free previous one */ Z if (history[hiscount]) Z free(history[hiscount]); Z Z /* save current in history array */ Z history[hiscount] = savestr(current); Z /* parse command for compound statements and pipes */ Z local = localbuf; /* set pointer to state of buffer */ Z setmem(localbuf,sizeof(localbuf),0); /* clear buffer */ Z/* $ */ goto eatwhitespace; Z Z#ifndef SNODEBUG Zgoto badstate; Z#endif Z/* Z * $endstate getline Z */ Z}; Z#line 125 "main.s" Z Z Zcharstate: Z{ Z#line 127 "main.s" Z switch(*current) Z { Z case '\0': Z *local = '\0'; Z current++; Z/* $ */ goto emit; Z case '"' : Z *local++ = *current++; Z/* $ */ goto doublequotes; Z case '/' : Z *local++ = '\\'; Z current++; Z/* $ */ goto charstate;; Z case '\'': Z *local++ = *current++; Z/* $ */ goto singlequotes; Z case '\\': Z *local++ = *++current; Z current++; Z/* $ */ goto charstate; Z case ';': Z *local = '\0'; Z current++; Z/* $ */ goto compound; Z case '|': Z *local = '\0'; Z current++; Z/* $ */ goto pipe; Z case '!': Z current++; Z/* $ */ goto histstate; Z default: Z *local++ = *current++; Z/* $ */ goto charstate; Z } Z Z#ifndef SNODEBUG Zgoto badstate; Z#endif Z/* Z * $endstate charstate Z */ Z}; Z#line 163 "main.s" Z Z Zemit: Z{ Z#line 165 "main.s" Z if (inpipe) Z { Z inpipe = 0; Z strcat(localbuf," < "); Z strcat(localbuf,pipename[currname]); Z } Z command(localbuf); Z/* $ */ goto done; Z Z#ifndef SNODEBUG Zgoto badstate; Z#endif Z/* Z * $endstate emit Z */ Z}; Z#line 174 "main.s" Z Z Zcompound: Z{ Z#line 176 "main.s" Z if (inpipe) Z { Z inpipe = 0; Z strcat(localbuf," < "); Z strcat(localbuf,pipename[currname]); Z } Z command(localbuf); Z local = localbuf; Z setmem(localbuf,sizeof(localbuf),0); /* clear buffer */ Z/* $ */ goto eatwhitespace; Z Z#ifndef SNODEBUG Zgoto badstate; Z#endif Z/* Z * $endstate compound Z */ Z}; Z#line 187 "main.s" Z Z Zsinglequotes: Z{ Z#line 189 "main.s" Z switch (*current) Z { Z case '\0': Z write(2,"No closing quotes!!\r\n",21); Z/* $ */ goto parserr; Z case '\'': Z *local++ = *current++; Z/* $ */ goto charstate; Z default: Z *local++ = *current++; Z/* $ */ goto singlequotes; Z } Z Z#ifndef SNODEBUG Zgoto badstate; Z#endif Z/* Z * $endstate singlequotes Z */ Z}; Z#line 202 "main.s" Z Z Zdoublequotes: Z{ Z#line 204 "main.s" Z switch(*current) Z { Z case '\0': Z write(2,"No closing quotes!!\r\n",21); Z/* $ */ goto done; Z case '"': Z *local++ = *current++; Z/* $ */ goto charstate; Z default: Z *local++ = *current++; Z/* $ */ goto doublequotes; Z } Z Z#ifndef SNODEBUG Zgoto badstate; Z#endif Z/* Z * $endstate doublequotes Z */ Z}; Z#line 217 "main.s" Z Z Zhiststate: Z{ Z#line 219 "main.s" Z /* handle history substitutions */ Z setmem(histbuf,sizeof(histbuf),0); /* clear buffer */ Z Z /* save current pointer into command buffer */ Z curr_save = current; Z Z /* copy command head */ Z strncpy(histbuf,cmdbuf,(int)(current-cmdbuf)-1); Z Z /* takeline means take all arguments past current one */ Z takeline = 0; Z Z /* parse history expression */ Z switch (*current) Z { Z case '!': /* last command line */ Z if (j) /* special case first time through */ Z { Z histindex = hiscount ? hiscount - 1 : histsize - 1; Z } Z else Z { Z /* force error condition */ Z write(2,histerr,strlen(histerr)); Z/* $ */ goto parserr; Z } Z current++; /* point to next */ Z break; Z case '-': /* negative (relative #) */ Z /* a particular numbered command */ Z case '0': Z case '1': Z case '2': Z case '3': Z case '4': Z case '5': Z case '6': Z case '7': Z case '8': Z case '9': Z /* repeat numbered command */ Z repeat = atoi(current); Z if (repeat < 0) /* handle relative addressing */ Z repeat += j; Z Z /* if command is within range */ Z if ((j - repeat) <= histsize && repeat < j) Z { Z histindex = repeat % histsize; Z } Z else Z { Z/* $ */ goto parserr; Z } Z Z /* skip past numeric expression */ Z while(isdigit(*current)||*current=='-') Z ++current; Z break; Z default: Z write(2,"Bad history expression\r\n",24); Z/* $ */ goto parserr; Z } Z /* look for particular argument substitutions */ Z switch (*current) Z { Z /* we want the whole enchilada */ Z case '\0': Z case '\t': Z case '\r': Z case '\n': Z case ' ': Z strcat(histbuf,history[histindex]); Z break; Z case ':': Z ++current; /* point past colon */ Z switch (*current) Z { Z case '^': Z argindex = 1; Z ++current; Z break; Z case '0': Z case '1': Z case '2': Z case '3': Z case '4': Z case '5': Z case '6': Z case '7': Z case '8': Z case '9': Z /* index of argument */ Z argindex = atoi(current); Z while(isdigit(*current)) Z ++current; Z if (*current == '*') Z { Z takeline = 1; Z current++; Z } Z break; Z case '$': Z argindex = lastarg(history[histindex]); Z current++; Z break; Z case '*': Z takeline = 1; /* take arg 1 through arg n */ Z argindex = 1; Z current++; Z break; Z default: Z/* $ */ goto parserr; Z } Z /* pick up pointer to argument in history we need */ Z if (takeline == 0) Z { Z if (NULL == Z (argptr = ntharg(history[histindex],argindex))) Z { Z/* $ */ goto parserr; Z } Z strcat(histbuf,argptr); Z } Z else Z { Z while (NULL != Z (argptr = ntharg(history[histindex],argindex++))) Z { Z strcat(histbuf,argptr); Z strcat(histbuf," "); Z } Z } Z } Z /* history substitutions */ Z /* copy command buffer tail to tail buffer */ Z strcpy(tail,current); Z /* copy histbuf back to cmdbuf */ Z strcpy(cmdbuf,histbuf); Z /* point current at history substitution to continue parsing */ Z current = --curr_save; /* -1 to backup over first ! */ Z /* copy tail in */ Z strcat(cmdbuf,tail); Z free(history[hiscount]); Z history[hiscount] = savestr(cmdbuf); Z/* $ */ goto charstate; Z Z#ifndef SNODEBUG Zgoto badstate; Z#endif Z/* Z * $endstate histstate Z */ Z}; Z#line 366 "main.s" Z Z Zpipe: Z{ Z#line 368 "main.s" Z if (inpipe++) Z { Z inpipe = 1; Z strcat(localbuf," < "); Z strcat(localbuf,pipename[currname]); Z } Z strcat(localbuf," > "); Z currname ^= 1; Z strcat(localbuf,pipename[currname]); Z command(localbuf); Z local = localbuf; Z setmem(localbuf,sizeof(localbuf),0); Z/* $ */ goto eatwhitespace; Z Z#ifndef SNODEBUG Zgoto badstate; Z#endif Z/* Z * $endstate pipe Z */ Z}; Z#line 382 "main.s" Z Z Zeatwhitespace: Z{ Z#line 384 "main.s" Z/* strip out leading white space */ Zwhile(isspace(*current)) Z current++; Z if (!*current) Z/* $ */ goto parserr; Z else Z/* $ */ goto charstate; Z Z#ifndef SNODEBUG Zgoto badstate; Z#endif Z/* Z * $endstate eatwhitespace Z */ Z}; Z#line 392 "main.s" Z Z Zparserr: Z{ Z#line 394 "main.s" Z/* $ */ goto getline; Z Z#ifndef SNODEBUG Zgoto badstate; Z#endif Z/* Z * $endstate parserr Z */ Z}; Z#line 396 "main.s" Z Z Zdone: Z{ Z#line 398 "main.s" Z j++; /* next command # */ Z/* $ */ goto getline; Z Z#ifndef SNODEBUG Zgoto badstate; Z#endif Z/* Z * $endstate done Z */ Z}; Z#line 401 "main.s" Z Z Z/* Z * BAD STATE LABEL Z */ Zbadstate: Z Z fprintf(stderr,"Fallen off end of a state!!!\n"); Z Z return -1; Z Z/* Z * TERMINAL STATE LABEL Z */ Zterminal: Z Z return 0; Z Z/* Z * end of state machine cli Z */ Z} Z Zonintr() Z{ Z longjmp(env,-1); Z} Z Zcommand(current) Z register char *current; Z{ Z extern do_prog(); Z register int i; Z std_save(); Z if (-1 == (i = findcmd(current))) Z { Z ctl_brk_setup(); Z result = _Croot(current,do_prog); Z ctl_brk_restore(); Z } Z else Z { Z if (-1 != setjmp(env)) Z { Z signal(SIGINT,onintr); Z result = _Croot(current,commands[i].func); Z } Z signal(SIGINT,SIG_IGN); Z } Z std_restore(); Z} Z Zchar * Zntharg(line,index) Zregister char *line; Z{ Z register int i; Z static char buf[64]; Z char *bptr; Z for (i = 0; *line;i++) Z { Z /* find start of arg[i] */ Z while(*line && isspace(*line)) Z { Z ++line; Z } Z /* if this is start of requested arg, return pointer to it */ Z if (i == index) Z { Z bptr = buf; Z while(*line && !isspace(*line)) Z *bptr++ = *line++; Z *bptr = '\0'; Z return buf; Z } Z /* find end of arg[i] */ Z while(*line && !isspace(*line)) Z ++line; Z } Z return NULL; Z} Z Zlastarg(line) Zregister char *line; Z{ Z register int i; Z Z for (i = 0; *line;i++) Z { Z /* find start of arg[i] */ Z while(*line && isspace(*line)) Z ++line; Z /* find end of arg[i] */ Z while(*line && !isspace(*line)) Z ++line; Z } Z return i-1; Z} STUNKYFLUFF set `sum main.c` if test 41066 != $1 then echo main.c: Checksum error. Is: $1, should be: 41066. fi # # echo Extracting main.s: sed 's/^Z//' >main.s <<\STUNKYFLUFF Z#include <stdio.h> Z#include <ctype.h> Z#include <signal.h> Z#include <fcntl.h> Z#include <setjmp.h> Ztypedef struct /* used to find builtin commands */ Z{ Z char *cmdname; Z int (*func)(); Z} builtin; Z Zextern builtin commands[]; Zextern char histerr[]; Zextern int j,hiscount; Zextern char *history[]; Zextern int histsize; Zextern int numcmds; Zstatic int quiet = 0; Z Zchar *version = "SHELL VERSION 1.1 Kent Williams"; Z Zjmp_buf env; Z Zchar *pipename[] = Z{ Z "\\shtmp1", Z "\\shtmp2" Z}; Z Zchar cmdbuf[512]; Zint currname = 0; Zint result = 0; Z Zmain(argc,argv) Z char *argv[]; Z{ Z signal(SIGINT,SIG_IGN); /* ignore breaks */ Z Z quiet = !isatty(0); /* quiet = batch shell */ Z Z /* initialize local environment */ Z init_env(); Z cli(); Z exit(0); Z} Z$nodebug /* turn off state machine debugging */ Z$machine cli getline () Z$endargs Z/* global variables */ Z int i; Z int repeat, state, inpipe = 0; Z static char localbuf[256]; Z static char histbuf[256]; Z static char tail[256]; Z int histindex,argindex,takeline; Z char *local = localbuf; Z char *current,*curr_save; Z char *ntharg(), *argptr; Z char *savestr(); Z Z$state getline Z /* kill tmp files */ Z unlink(pipename[0]); unlink(pipename[1]); Z Z hiscount = j % histsize; /* hiscount is current position in history */ Z if(!quiet) Z fprintf(stderr,"%d%% ",j); Z Z/* Z * The following code simply reads a line from standard input. Z * It is so complicated because when you save the standard stream Z * files and execute another program/command, standard input is Z * left in an uncertain state - the FILE stdin seems to be at EOF, Z * even when standard input is associated with the console, and Z * cr/lf combinations show up as line terminators, whereas usually Z * only linefeeds get placed in the input stream. Z * WHY? beats me. Something could be wrong with Z * 1. AZTEC C runtime Z * 2. PCDOS Z * 3. Me Z * 4. All three, or permutations of 1-3 reducto ad absurdum. Z * All I know is this works Z */ Z /* clear command buffer so string read is null terminated */ Z setmem(cmdbuf,sizeof(cmdbuf),0); Z for (current = cmdbuf;;current++) Z { Z int readresult; Z if ((readresult = read(0,current,1)) == 0 || Z readresult == -1) Z { Z $nextstate terminal Z } Z if (*current == '\r') Z { Z if ((readresult = read(0,current,1)) == 0 || Z readresult == -1) Z { Z $nextstate terminal Z } Z *current = '\0'; Z break; Z } Z else if (*current == '\n') Z { Z *current = '\0'; /* terminate string */ Z break; Z } Z } Z current = cmdbuf; /* point current at start of buffer */ Z/* Z * end of input weirdness Z */ Z /* if we're recycling history strings, free previous one */ Z if (history[hiscount]) Z free(history[hiscount]); Z Z /* save current in history array */ Z history[hiscount] = savestr(current); Z /* parse command for compound statements and pipes */ Z local = localbuf; /* set pointer to state of buffer */ Z setmem(localbuf,sizeof(localbuf),0); /* clear buffer */ Z $nextstate eatwhitespace Z$endstate getline Z Z$state charstate Z switch(*current) Z { Z case '\0': Z *local = '\0'; Z current++; Z $nextstate emit Z case '"' : Z *local++ = *current++; Z $nextstate doublequotes Z case '/' : Z *local++ = '\\'; Z current++; Z $nextstate charstate; Z case '\'': Z *local++ = *current++; Z $nextstate singlequotes Z case '\\': Z *local++ = *++current; Z current++; Z $nextstate charstate Z case ';': Z *local = '\0'; Z current++; Z $nextstate compound Z case '|': Z *local = '\0'; Z current++; Z $nextstate pipe Z case '!': Z current++; Z $nextstate histstate Z default: Z *local++ = *current++; Z $nextstate charstate Z } Z$endstate charstate Z Z$state emit Z if (inpipe) Z { Z inpipe = 0; Z strcat(localbuf," < "); Z strcat(localbuf,pipename[currname]); Z } Z command(localbuf); Z $nextstate done Z$endstate emit Z Z$state compound Z if (inpipe) Z { Z inpipe = 0; Z strcat(localbuf," < "); Z strcat(localbuf,pipename[currname]); Z } Z command(localbuf); Z local = localbuf; Z setmem(localbuf,sizeof(localbuf),0); /* clear buffer */ Z $nextstate eatwhitespace Z$endstate compound Z Z$state singlequotes Z switch (*current) Z { Z case '\0': Z write(2,"No closing quotes!!\r\n",21); Z $nextstate parserr Z case '\'': Z *local++ = *current++; Z $nextstate charstate Z default: Z *local++ = *current++; Z $nextstate singlequotes Z } Z$endstate singlequotes Z Z$state doublequotes Z switch(*current) Z { Z case '\0': Z write(2,"No closing quotes!!\r\n",21); Z $nextstate done Z case '"': Z *local++ = *current++; Z $nextstate charstate Z default: Z *local++ = *current++; Z $nextstate doublequotes Z } Z$endstate doublequotes Z Z$state histstate Z /* handle history substitutions */ Z setmem(histbuf,sizeof(histbuf),0); /* clear buffer */ Z Z /* save current pointer into command buffer */ Z curr_save = current; Z Z /* copy command head */ Z strncpy(histbuf,cmdbuf,(int)(current-cmdbuf)-1); Z Z /* takeline means take all arguments past current one */ Z takeline = 0; Z Z /* parse history expression */ Z switch (*current) Z { Z case '!': /* last command line */ Z if (j) /* special case first time through */ Z { Z histindex = hiscount ? hiscount - 1 : histsize - 1; Z } Z else Z { Z /* force error condition */ Z write(2,histerr,strlen(histerr)); Z $nextstate parserr Z } Z current++; /* point to next */ Z break; Z case '-': /* negative (relative #) */ Z /* a particular numbered command */ Z case '0': Z case '1': Z case '2': Z case '3': Z case '4': Z case '5': Z case '6': Z case '7': Z case '8': Z case '9': Z /* repeat numbered command */ Z repeat = atoi(current); Z if (repeat < 0) /* handle relative addressing */ Z repeat += j; Z Z /* if command is within range */ Z if ((j - repeat) <= histsize && repeat < j) Z { Z histindex = repeat % histsize; Z } Z else Z { Z $nextstate parserr Z } Z Z /* skip past numeric expression */ Z while(isdigit(*current)||*current=='-') Z ++current; Z break; Z default: Z write(2,"Bad history expression\r\n",24); Z $nextstate parserr Z } Z /* look for particular argument substitutions */ Z switch (*current) Z { Z /* we want the whole enchilada */ Z case '\0': Z case '\t': Z case '\r': Z case '\n': Z case ' ': Z strcat(histbuf,history[histindex]); Z break; Z case ':': Z ++current; /* point past colon */ Z switch (*current) Z { Z case '^': Z argindex = 1; Z ++current; Z break; Z case '0': Z case '1': Z case '2': Z case '3': Z case '4': Z case '5': Z case '6': Z case '7': Z case '8': Z case '9': Z /* index of argument */ Z argindex = atoi(current); Z while(isdigit(*current)) Z ++current; Z if (*current == '*') Z { Z takeline = 1; Z current++; Z } Z break; Z case '$': Z argindex = lastarg(history[histindex]); Z current++; Z break; Z case '*': Z takeline = 1; /* take arg 1 through arg n */ Z argindex = 1; Z current++; Z break; Z default: Z $nextstate parserr Z } Z /* pick up pointer to argument in history we need */ Z if (takeline == 0) Z { Z if (NULL == Z (argptr = ntharg(history[histindex],argindex))) Z { Z $nextstate parserr Z } Z strcat(histbuf,argptr); Z } Z else Z { Z while (NULL != Z (argptr = ntharg(history[histindex],argindex++))) Z { Z strcat(histbuf,argptr); Z strcat(histbuf," "); Z } Z } Z } Z /* history substitutions */ Z /* copy command buffer tail to tail buffer */ Z strcpy(tail,current); Z /* copy histbuf back to cmdbuf */ Z strcpy(cmdbuf,histbuf); Z /* point current at history substitution to continue parsing */ Z current = --curr_save; /* -1 to backup over first ! */ Z /* copy tail in */ Z strcat(cmdbuf,tail); Z free(history[hiscount]); Z history[hiscount] = savestr(cmdbuf); Z $nextstate charstate Z$endstate histstate Z Z$state pipe Z if (inpipe++) Z { Z inpipe = 1; Z strcat(localbuf," < "); Z strcat(localbuf,pipename[currname]); Z } Z strcat(localbuf," > "); Z currname ^= 1; Z strcat(localbuf,pipename[currname]); Z command(localbuf); Z local = localbuf; Z setmem(localbuf,sizeof(localbuf),0); Z $nextstate eatwhitespace Z$endstate pipe Z Z$state eatwhitespace Z/* strip out leading white space */ Zwhile(isspace(*current)) Z current++; Z if (!*current) Z $nextstate parserr Z else Z $nextstate charstate Z$endstate eatwhitespace Z Z$state parserr Z $nextstate getline Z$endstate parserr Z Z$state done Z j++; /* next command # */ Z $nextstate getline Z$endstate done Z Z$endmachine cli Z Zonintr() Z{ Z longjmp(env,-1); Z} Z Zcommand(current) Z register char *current; Z{ Z extern do_prog(); Z register int i; Z std_save(); Z if (-1 == (i = findcmd(current))) Z { Z ctl_brk_setup(); Z result = _Croot(current,do_prog); Z ctl_brk_restore(); Z } Z else Z { Z if (-1 != setjmp(env)) Z { Z signal(SIGINT,onintr); Z result = _Croot(current,commands[i].func); Z } Z signal(SIGINT,SIG_IGN); Z } Z std_restore(); Z} Z Zchar * Zntharg(line,index) Zregister char *line; Z{ Z register int i; Z static char buf[64]; Z char *bptr; Z for (i = 0; *line;i++) Z { Z /* find start of arg[i] */ Z while(*line && isspace(*line)) Z { Z ++line; Z } Z /* if this is start of requested arg, return pointer to it */ Z if (i == index) Z { Z bptr = buf; Z while(*line && !isspace(*line)) Z *bptr++ = *line++; Z *bptr = '\0'; Z return buf; Z } Z /* find end of arg[i] */ Z while(*line && !isspace(*line)) Z ++line; Z } Z return NULL; Z} Z Zlastarg(line) Zregister char *line; Z{ Z register int i; Z Z for (i = 0; *line;i++) Z { Z /* find start of arg[i] */ Z while(*line && isspace(*line)) Z ++line; Z /* find end of arg[i] */ Z while(*line && !isspace(*line)) Z ++line; Z } Z return i-1; Z} STUNKYFLUFF set `sum main.s` if test 47403 != $1 then echo main.s: Checksum error. Is: $1, should be: 47403. fi # # echo Extracting makefile: sed 's/^Z//' >makefile <<\STUNKYFLUFF Z# home for all commands ZBINDIR=\\bin\\ Z# small model library path ZCLIB=-l/clibs/c Z Z# source files for shell Zshsrc=main.c cd.c cp.c doprog.c fexecvp.c more.c cmds.c chmod.c y.c fexec.asm \ Zinvalid.c ls.c pushd.c fgrep.c md.c mv.c pwd.c rm.c crlf.c drive.c dump2.c \ Zrmdir.c savestr.c stdsave.c touch.c _croot.c env.c fexecv.c cat.c echo.c \ Zcmdlist.c ctlbrk.asm mvcp.c Z Z# object files for shell Zshobj=main.o cd.o cp.o doprog.o fexecvp.o more.o cmds.o chmod.o y.o fexec.o \ Zinvalid.o ls.o pushd.o fgrep.o md.o mv.o pwd.o rm.o crlf.o drive.o dump2.o \ Zrmdir.o savestr.o stdsave.o touch.o _croot.o env.o fexecv.o cat.o echo.o \ Zcmdlist.o ctlbrk.o mvcp.o Z Zmain.c : main.s Z statecom main Z Z# Z# make shell - check currency of all percursors, link and then move to Z# bin directory Z# Zshell.exe : $(shobj) Z ln -t -o $@ -f shell.lnk Z \\atron\\aztoat <shell.sym >shell.map Z chmod +w $(BINDIR)$@ Z mv $@ $(BINDIR)$@ Z chmod -w $(BINDIR)$@ Z Z# Z# make entries to produce stand-alone versions of shell builtins Z# Zchmod.com : Z cc -dMAIN $* Z ln -o $@ $*.o -l/clibs/c Z rm $*.o Z chmod +w $(BINDIR)chmod.com Z mv chmod.com $(BINDIR)chmod.com Z chmod -w $(BINDIR)chmod.com Z Zmore.com : Z cc -dMAIN $* Z ln -o $@ $*.o -l/clibs/s -l/clibs/c Z rm $*.o Z chmod +w $(BINDIR)$@ Z mv $@ $(BINDIR)$@ Z chmod -w $(BINDIR)$@ Z Zmv.com : croot.o savestr.o mvcp.o Z cc -dMAIN $* Z ln -o $@ $*.o savestr.o croot.o mvcp.o -l/clibs/c Z rm $*.o Z chmod +w $(BINDIR)$@ Z mv $@ $(BINDIR)$@ Z chmod -w $(BINDIR)$@ Z Zcp.com : croot.o savestr.o mvcp.o Z cc -dMAIN $* Z ln -o $@ $*.o savestr.o croot.o mvcp.o -l/clibs/c Z rm $*.o Z chmod +w $(BINDIR)$@ Z mv $@ $(BINDIR)$@ Z chmod -w $(BINDIR)$@ Z Zls.com : Z cc -dMAIN $* Z ln -o $@ $*.o -l/clibs/c Z rm $*.o Z chmod +w $(BINDIR)$@ Z mv $@ $(BINDIR)$@ Z chmod -w $(BINDIR)$@ Zeditall : Z z $(shsrc) Zclean : Z rm *.o *.bak *.sym STUNKYFLUFF set `sum makefile` if test 36319 != $1 then echo makefile: Checksum error. Is: $1, should be: 36319. fi # # echo Extracting md.c: sed 's/^Z//' >md.c <<\STUNKYFLUFF Zmd(argc,argv) Z char *argv[]; Z{ Z if (-1 == mkdir(*(++argv))) Z { Z perror("mkdir"); Z return -1; Z } Z return 0; Z} STUNKYFLUFF set `sum md.c` if test 21756 != $1 then echo md.c: Checksum error. Is: $1, should be: 21756. fi # # echo Extracting more.c: sed 's/^Z//' >more.c <<\STUNKYFLUFF Z#include <stdio.h> Z#include <sgtty.h> Z#include <debug.h> Z#include <ctype.h> Z#include <setjmp.h> Z#include <signal.h> Zvoid (*signal())(); Zvoid (*moresig)(); ZFILE *fdopen(); Z Zlong int size, position; Zchar filename[30]; Zchar isaconsole = '\0'; Zchar isapipe = '\0'; Zint tabsize = 8; Z#define STDIN 0 Z#define STDOUT 1 Z#define STDERR 2 Z#define ESC '\033' Z#define IBMPC /* display code dependent on PC hardware/bios */ Z#ifdef IBMPC Zextern void scr_putc(); Z#endif Zvoid std_out(c) Z{ Z write(1,&c,1); Z} Zvoid (*output)(); Z#ifdef MAIN Zcrlf() Z{ Z write(2,"\r\n",2); Z} Z#endif Zjmp_buf moreenv; Zmoreintr() Z{ Z signal(SIGINT,SIG_IGN); /* ignore signals until we finish putting stuff Z back in order */ Z longjmp(moreenv,-1); Z} Z#ifdef MAIN Zmain Z#else Zmore Z#endif Z(argc,argv) Z int argc; Z char *argv[]; Z{ Z FILE *fp, *fopen(); Z long ftell(); Z long int i; Z long int fsize(); Z Z if (-1 == setjmp(moreenv)) Z { Z write(2,"Interrupted\r\n",13); Z fclose(fp); Z signal(SIGINT,moresig); Z return -1; Z } Z Z moresig = signal(SIGINT,moreintr); Z isaconsole = isatty(STDOUT); Z isapipe = !isatty(STDIN); Z#ifdef IBMPC Z if (isaconsole) Z { Z output = scr_putc; Z scr_echo(0); Z } Z else Z#endif Z output = std_out; Z if ( (*(++argv))[0] == '-' && isdigit((*argv)[1]) ) Z { Z tabsize = atoi( (*argv+1) ); Z --argc; Z } else Z { Z --argv; Z } Z if (argc == 1) Z { Z if (NULL == (fp = fdopen(0,"r"))) Z { Z return -1; Z } Z display(fp); Z crlf(); Z return 0; Z } Z while(--argc) Z { Z if (NULL == (fp = fopen(*(++argv),"r")) ) Z { Z fprintf(stderr,"more - can't open %s\n",*argv); Z continue; Z } Z strncpy(filename,*argv,30); Z if (filename[29]) Z filename[29] = '\0'; Z if (!isapipe) Z size = fsize(fp); Z position = 0; Z if (-2 == display(fp)) Z argc = 0; /* force completion of command */ Z fclose(fp); Z } Zbugout: Z#ifdef IBMPC Z if (isaconsole) Z scr_echo(0); Z#endif Z crlf(); Z tabsize = 8; Z isaconsole = isapipe = '\0'; Z signal(SIGINT,moresig); Z return 0; Z} Z Zlong fsize(fp) Z FILE *fp; Z{ Z long ftell(); Z long position, last; Z position = ftell(fp); Z if (-1 == fseek(fp,0L,2)) Z { Z fprintf(stderr,"more - error on fseek\n"); Z } Z last = (ftell(fp)); Z fseek(fp,position,0); Z return last; Z} Z#define LBUFSIZE 160 Zchar linebuffer[LBUFSIZE]; Zint lines; Z Zdisplay(fp) Z FILE *fp; Z{ Z FILE *fgets(); Z long ftell(); Z char c; Z lines = 1; Z while ( NULL != fgets(linebuffer,LBUFSIZE,fp)) Z { Z if (isaconsole) Z { Z if (lines == 1) /* top of display */ Z { Z#ifdef IBMPC Z scr_clear(); Z#else Z/* ansi terminal screen clear */ Z printf("%c[2J",ESC); /* clear display */ Z#endif Z } Z } Z lines += localputs(linebuffer); Z if (isaconsole) Z { Z if (lines >= 24) /* bottome of display */ Z { Z char tst; Z position = ftell(fp); Z#ifdef IBMPC Z scr_curs(24,0); Z#else Z/* ansi terminal positioning */ Z printf("%c[25;1H%c[7m",ESC,ESC); Z#endif Z if (!isapipe) Z#ifdef IBMPC Z scr_printf( Z#else Z fprintf(stderr, Z#endif Z "%s - %ld bytes - %d%% displayed - <ESC> = skip to next file", Z filename,size,percent(position,size) ); Z else Z#ifdef IBMPC Z scr_printf( Z#else Z fprintf(stderr, Z#endif Z "-more-"); Z switch (bdos(7,0,0)) /* get a character no echo */ Z { Z case ESC : Z return 0; Z case 3 : Z return -2; Z default: Z break; Z } Z Z lines = 1; Z } Z } Z } Z if (isaconsole) Z { Z if (lines != 1) /* bottome of display */ Z { Z#ifdef IBMPC Z scr_curs(24,0); Z#else Z/* ansi terminal positioning */ Z printf("%c[25;1H%c[7m",ESC,ESC); Z#endif Z if (!isapipe) Z { Z position = ftell(fp); Z#ifdef IBMPC Z scr_printf( Z#else Z fprintf(stderr, Z#endif Z "%s - %ld characters - %d%% displayed", Z filename,size,percent(position,size) ); Z } Z else Z#ifdef IBMPC Z scr_printf( Z#else Z fprintf(stderr, Z#endif Z "-done-"); Z bdos(7,0,0); /* console input no echo */ Z lines = 1; Z } Z } Z} Z Zpercent(x,y) Z long int x,y; Z{ /* returns integer percentage of x into y */ Z#ifdef FLOAT Z float xf,yf; Z xf = x; yf = y; Z x = ((xf/yf)*100); Z#endif Z x *= 100; Z if (y) Z x /= y; Z else Z x = 100; Z return (x); Z} Z Zlocalputs(lb) Z register char *lb; Z{ Z int lines, pos, tabstop; Z lines = 1; Z pos = 0; Z while (*lb) Z { Z switch (*lb) Z { Z case '\t': Z tabstop = pos + (tabsize - (pos % tabsize)); Z for (;pos <= tabstop; pos++) Z (*output)(' '); Z break; Z case '\n': Z (*output)('\r'); Z default: Z (*output)(*lb); Z pos++; Z } Z if (pos == 79) Z { Z pos = 1; Z (*output)('\r'); Z (*output)('\n'); Z ++lines; Z } else if (pos > 79) Z { Z pos -= 80; Z ++lines; Z } Z ++lb; Z } Z return lines; Z} Z Z#ifdef IBMPC Zscr_printf(fmt,args) Zchar *fmt; unsigned args; Z{ Z format(scr_putc,fmt,&args); Z} Z#endif STUNKYFLUFF set `sum more.c` if test 34929 != $1 then echo more.c: Checksum error. Is: $1, should be: 34929. fi # # echo Extracting mv.c: sed 's/^Z//' >mv.c <<\STUNKYFLUFF Z/* :ts=2 */ Z#include <stdio.h> Zchar *savestr(); Z#ifndef MAIN Zextern char *fname_part(),*savestr(); Zextern char *me; Z#else Zchar *me; Z#endif Z/* mv.c - implements a version of UNIX mv */ Z#ifdef MAIN Zmain Z#else Zmv Z#endif Z(argc,argv) Z int argc; Z register char *argv[]; Z{ Z static char *usage = "mv : usage mv file1 [file2 . . fileN] target\r\n"; Z static char target_name[128]; Z char target[128],*fname_part(); Z register int i; Z int len; Z#ifndef MAIN Z me = argv[0]; /* referenced in routines common with cp.c */ Z#endif Z if (argc < 3) Z { Z write(2,usage,strlen(usage)); Z return(-1); Z } Z strcpy(target, argv[argc-1]); Z /* kill trailing backslashes */ Z if (target[i = strlen(target) - 1] == '\\') Z target[i] = '\0'; Z if (argc == 3) Z { Z /* if the target doesn't exist and it's not a directory then rename */ Z if (!filep(target)) Z { Z if (!dirp(target)) Z { Z fprintf(stderr,"rename : moving %s to %s\n" Z ,argv[1],argv[2]); Z rename(argv[1],argv[2]); Z } Z else Z { Z /* if the target is a directory copy to same name that directory */ Z strcpy(target_name,target); Z if (target_name[(len = strlen(target_name))-1] != '\\') Z { Z target_name[len = strlen(target_name)] = '\\'; Z target_name[len+1] = '\0'; Z } Z strcat(target_name,fname_part(argv[1])); Z#ifdef DEBUG Z fprintf(stderr,"interdirectory copy same name : moving %s to %s\n" Z#else Z fprintf(stderr,"moving %s to %s\n" Z#endif Z ,argv[1],target_name); Z if (-1 != maybecopy(target_name,argv[1])) Z unlink(argv[1]); Z } Z } Z else Z { Z /* target exists , and isn't a directory */ Z char *tpath,*spath; Z char tpathsaved = 0,spathsaved = 0; Z char *path_part(); Z /* find path parts of source and target */ Z if (tpath = path_part(target)) Z { Z tpath = savestr(tpath); Z tpathsaved++; Z } Z else Z tpath = "."; /* current directory */ Z if (spath = path_part(argv[1])) Z { Z spath = savestr(spath); Z spathsaved++; Z } Z else Z spath = "."; /* current directory */ Z if (0 == strcmp(tpath,spath)) Z { Z /* if source and target are in the same directory */ Z#ifdef DEBUG Z fprintf(stderr,"intradirectory delete then rename : moving %s to %s\n" Z#else Z fprintf(stderr,"moving %s to %s\n" Z#endif Z ,argv[1],target); Z unlink(target); Z rename(argv[1],target); Z } Z else Z { Z#ifdef DEBUG Z fprintf(stderr,"interdirectory file to file: moving %s to %s\n" Z#else Z fprintf(stderr,"moving %s to %s\n" Z#endif Z ,argv[1],target); Z if (-1 != maybecopy(target,argv[1])) Z unlink(argv[1]); Z } Z if (tpathsaved) Z free(tpath); Z if (spathsaved) Z free(spath); Z } Z return(0); Z } Z /* handle special case of a drive designation */ Z if (target[(i = strlen(target))-1] != ':') Z if (!dirp(target)) Z { Z fprintf(stderr,"mv : %s isn't a directory\n",target); Z return(-1); Z } Z for (i = 1; i < argc-1; i++) Z { Z strcpy(target_name,target); Z if (target_name[(len = strlen(target_name))-1] != '\\') Z { Z target_name[len = strlen(target_name)] = '\\'; Z target_name[len+1] = '\0'; Z } Z strcat(target_name,fname_part(argv[i])); Z if (!filep(argv[i])) Z { Z fprintf(stderr,"mv : %s isn't a file\n",argv[i]); Z continue; Z } Z fprintf(stderr,"moving %s to %s\n",argv[i],target_name); Z if (-1 != maybecopy(target_name,argv[i])) Z unlink(argv[i]); Z } Z return 0; Z} Z Zmaybecopy(target,source) Z char *target,*source; Z{ Z char *drive_part(); Z static char targetdrive[3], sourcedrive[3]; Z strcpy(targetdrive,drive_part(target)); Z strcpy(sourcedrive,drive_part(source)); Z if (0 == strcmp(targetdrive,sourcedrive)) Z { Z unlink(target); Z rename(source,target); Z return 0; Z } Z return (filecopy(target,source)); Z} STUNKYFLUFF set `sum mv.c` if test 37323 != $1 then echo mv.c: Checksum error. Is: $1, should be: 37323. fi # # echo Extracting mvcp.c: sed 's/^Z//' >mvcp.c <<\STUNKYFLUFF Z#include <stdio.h> Z/* Z * mvcp.c - routines common to mv and cp Z */ Z#include <fcntl.h> Zchar buffer[BUFSIZ*16]; Zextern char *me; Zfilecopy(target,source) Zchar *target,*source; Z{ Z int t,s,r; Z if (-1 == (s = open(source,O_RDONLY))) Z { Z fprintf(stderr,"%s : can't open %s\n",me,source); Z return(-1); Z } Z if (-1 == (t = open(target,O_TRUNC))) Z { Z fprintf(stderr,"%s : can't open %s\n",me,target); Z return(-1); Z } Z while(0 != (r = read(s,buffer,BUFSIZ*16)) && r != -1) Z { Z if(-1 == write(t,buffer,r)) Z { Z fprintf(stderr,"%s : error writing %s\n",me,target); Z return(-1); Z } Z } Z close(t); Z close(s); Z return (0); Z} Z Z#include <errno.h> Ztypedef struct Z{ Z char dos_reserved[21]; Z char attribute; Z unsigned file_time; Z unsigned file_date; Z long file_size; Z char file_name[13]; Z} Zfcb; Zfcb dir; Z Zdirp(s) Zchar *s; Z{ Z register int junk1,junk2; Z /* handle all of the stupid special cases */ Z if ((s[1] == ':' && s[2] == '\0') /* root directory on a drive */ Z || (s[1] == '\0') /* root directory default drive */ Z ) Z { Z return 1; Z } Z if (0 == strcmp(s,"..")) /* parent of this directory */ Z { Z int returnval; Z char *current,*parent; Z current = getcwd(NULL,64); Z if (-1 == chdir(s)) /* go to parent */ Z returnval = 0; Z else Z returnval = 1; Z parent = getcwd(NULL,64); Z chdir(current); Z free(current); free(parent); Z return returnval; Z } Z /* set the disk transfer address */ Z bdos(0x1A,&dir); Z /* do a search first for the directory path */ Z return (bdos(0x4E,s,0x10) == 0 && bdos(0x4E,s,0) != 0); Z} Z Zfilep(s) Zchar *s; Z{ Z /* set the disk transfer address */ Z bdos(0x1A,&dir); Z /* do a search first for the directory path */ Z return bdos(0x4E,s,0) == 0; Z} Zchar *fname_part(s) Zregister char *s; Z{ Z register char *r; Z char *rindex(); Z if (r = rindex(s,'\\')) Z { Z return r+1; Z } Z if (r = rindex(s,':')) Z { Z return r+1; Z } Z return s; Z} Zchar *path_part(s) Zregister char *s; Z{ Z static char buffer[64]; Z register char *r; Z char *rindex(); Z strcpy(buffer,s); /* copy string */ Z if (r = rindex(buffer,'\\')) Z { Z *++r = '\0'; Z return buffer; Z } Z if (r = rindex(buffer,':')) Z { Z *++r = '\0'; Z return buffer; Z } Z return NULL; Z} Zchar *drive_part(s) Zregister char *s; Z{ Z static char buffer[64]; Z register char *r; Z char *rindex(); Z strcpy(buffer,s); /* copy string */ Z if (buffer[1] == ':') Z { Z buffer[2] = '\0'; Z return buffer; Z } Z return NULL; Z} STUNKYFLUFF set `sum mvcp.c` if test 16416 != $1 then echo mvcp.c: Checksum error. Is: $1, should be: 16416. fi # # echo Extracting pushd.c: sed 's/^Z//' >pushd.c <<\STUNKYFLUFF Z#define NULL (void *)0 Z Zstatic char *dirstack[10]; Zstatic int dsp = -1; Z Zpushd(argc,argv) Zchar *argv[]; Z{ Z char *getcwd(), *savestr(); Z static char *usage = "usage : pushd newdir"; Z static char *pusherr = "pushd : dir stack overflow"; Z char dirbuf[64]; Z if (argc == 1) Z { Z write(2,usage,strlen(usage)); Z crlf(); Z return -1; Z } Z if (NULL == getcwd(&dirbuf[1],64)) Z { Z perror("pushd"); Z return -1; Z } Z if (++dsp == 10) Z { Z write(2,pusherr,strlen(pusherr)); Z crlf(); Z return -1; Z } Z dirbuf[0] = '\\'; Z if (-1 == chdir(*(++argv))) Z { Z --dsp; Z perror("pushd"); Z return -1; Z } Z dirstack[dsp] = savestr(dirbuf); Z return 0; Z} Z Zpopd() Z{ Z register int returnval = 0; Z static char *poperr = "popd : dir stack underflow"; Z if (dsp == -1) Z { Z write(2,poperr,strlen(poperr)); Z crlf(); Z return -1; Z } Z if (-1 == chdir(dirstack[dsp])) Z { Z perror("popd"); Z write(2,dirstack[dsp],strlen(dirstack[dsp])); Z crlf(); Z returnval = -1; Z } Z free(dirstack[dsp--]); Z return returnval; Z} STUNKYFLUFF set `sum pushd.c` if test 22547 != $1 then echo pushd.c: Checksum error. Is: $1, should be: 22547. fi # # echo Extracting pwd.c: sed 's/^Z//' >pwd.c <<\STUNKYFLUFF Z#define NULL (void *)0 Zpwd(argc,argv) Zchar *argv[]; Z{ Z char *getcwd(); Z register char *dir; Z if (!(dir = getcwd(NULL,256))) Z { Z perror("pwd"); Z return -1; Z } Z write(1,"\\",1); Z write(1,dir,strlen(dir)); Z crlf(); Z if (dir) Z free(dir); Z return 0; Z} STUNKYFLUFF set `sum pwd.c` if test 11133 != $1 then echo pwd.c: Checksum error. Is: $1, should be: 11133. fi # # echo Extracting rm.c: sed 's/^Z//' >rm.c <<\STUNKYFLUFF Z#include <stdio.h> Zrm(argc,argv) Z int argc; Z char *argv[]; Z{ Z extern int _echo; Z int oldecho = _echo; Z char ask = 0; Z Z if (argv[1][0] == '-' && toupper(argv[1][1]) == 'Q') Z { Z ask++; Z _echo = 1; Z ++argv; --argc; Z } Z while(--argc) Z { Z ++argv; Z if (ask) Z { Z fprintf(stderr,"delete %s? (y or n) : ",*argv); Z if (toupper(scr_getc()) != 'Y') Z { Z write(2,"\r\n",2); Z continue; Z } Z write(2,"\r\n",2); Z } Z if (-1 == unlink(*(argv))) Z { Z perror("rm"); Z } Z } Z _echo = oldecho; Z} Z Z STUNKYFLUFF set `sum rm.c` if test 00071 != $1 then echo rm.c: Checksum error. Is: $1, should be: 00071. fi # # echo Extracting rmdir.c: sed 's/^Z//' >rmdir.c <<\STUNKYFLUFF Z#include <stdio.h> Zrd(argc,argv) Zchar *argv[]; Z{ Z static char *usage = "usage : rmdir directory"; Z if (argc == 1) Z write(2,usage,strlen(usage)); Z if (-1 == rmdir(*(++argv))) Z { Z perror("rmdir"); Z return -1; Z } Z return 0; Z} STUNKYFLUFF set `sum rmdir.c` if test 22459 != $1 then echo rmdir.c: Checksum error. Is: $1, should be: 22459. fi # # echo Extracting savestr.c: sed 's/^Z//' >savestr.c <<\STUNKYFLUFF Z#define NULL (void *)0 Zchar * Zsavestr(s) Z register char *s; Z{ Z register char *r,*malloc(); Z /* squirrel away matched file name */ Z if (NULL == (r = malloc(strlen(s)+1))) Z abort(); Z strcpy(r,s); Z r[strlen(s)] = '\0'; Z return r; Z} STUNKYFLUFF set `sum savestr.c` if test 32164 != $1 then echo savestr.c: Checksum error. Is: $1, should be: 32164. fi # # echo Extracting shell.lnk: sed 's/^Z//' >shell.lnk <<\STUNKYFLUFF Zmain.o cd.o cp.o doprog.o fexecvp.o more.o Zinvalid.o ls.o pushd.o fgrep.o env.o cmds.o chmod.o Zmd.o mv.o pwd.o rm.o crlf.o drive.o fexecv.o Zrmdir.o savestr.o stdsave.o touch.o dump2.o mvcp.o Z_croot.o cat.o echo.o y.o fexec.o cmdlist.o ctlbrk.o Z/clibs/c.lib /clibs/s.lib STUNKYFLUFF set `sum shell.lnk` if test 41375 != $1 then echo shell.lnk: Checksum error. Is: $1, should be: 41375. fi # # echo Extracting ssbrk.asm: sed 's/^Z//' >ssbrk.asm <<\STUNKYFLUFF Z; :ts=8 Z;Copyright (C) 1983 by Manx Software Systems Z include lmacros.h Zdataseg segment word public 'data' Z extrn $MEMRY:word Z extrn _mbot_:word, _sbot_:word Z extrn _mtop_:word Z extrn errno_:word Z extrn _STKLOW_:word Z extrn _PSP_:word Zdataseg ends Z assume ds:dataseg Z; Z; sbrk(size): return address of current top & bump by size bytes Z; Z procdef sbrk,<<siz,word>> Z push di Z mov ax,siz Z mov di,$MEMRY Z add ax,di Z push ax Z call brk_ Z pop cx Z test ax,ax Z jnz brk_error Z mov ax,di ;return original value of the break Zbrk_error: Z pop di Z test ax,ax ;set flags for C Z pret Z pend sbrk Z; Z; brk(addr): set current top address to addr Z; returns 0 if ok, -1 if error Z; Z procdef brk,<<addr,word>> Z mov ax,addr Z inc ax Z and al,-2 Z cmp ax,_mbot_ Z jb brk_ov Z mov bx,_STKLOW_ Z cmp bx,0 Z jnz abovestk Z cmp ax,_sbot_ Z jae brk_ov Z mov bx,sp Z cmp ax,bx Z jae brk_ov Zbrk_ok2: Z mov $MEMRY,ax ;new value is good so save it away Z sub ax,ax Z pret Z;heap is above stack Zabovestk: Z cmp ax,_mtop_ Z ja getstore Z cmp ax,$MEMRY Z ja brk_ok2 Z; going to do a SETBLOCK call Zgetstore: Z push ax Z mov bx,ax Z mov cx,4 Z shr bx,cl Z and bx,0fffh Z add bx,65 ;bump to nearest 1k increment Z and bx,0ffc0h ;and round Z push bx Z push es Z mov cx,ds Z add bx,cx ;get actual paragraph address Z mov es,_PSP_ Z sub bx,_PSP_ Z mov ah,04ah Z int 21h ;SETBLOCK Z pop es Z pop bx Z pop ax Z jc brk_ov ; couldn't do it, so punt Z mov $MEMRY,ax Z test bx,0e000h Z jnz brk_ov Z mov cx,4 Z shl bx,cl Z mov _mtop_,bx Z sub ax,ax Z pret Z; invalid request Zbrk_ov: Z mov errno_,-4 Z mov ax,-1 Z test ax,ax Z pret Z pend brk Z; Z; rsvstk(size): set safety margin for stack Z; this will make sure that at least size Z; bytes of stack below the current level remain. Z; Z procdef rsvstk,<<stksize,word>> Z mov ax,sp Z sub ax,stksize Z mov _sbot_,ax Z pret Z pend rsvstk Z finish Z end STUNKYFLUFF set `sum ssbrk.asm` if test 58681 != $1 then echo ssbrk.asm: Checksum error. Is: $1, should be: 58681. fi # # echo Extracting stdsave.c: sed 's/^Z//' >stdsave.c <<\STUNKYFLUFF Z#include <stdio.h> Z#include <fcntl.h> Z Zint console; Zint in,out; /* old standard input and standard output */ Zstd_save() Z{ Z if (-1 == (console = open("con",O_RDWR))) Z { Z perror("sh : can't open console"); Z return -1; Z } Z in = dup(0); Z out = dup(1); Z fdup(console,0); Z fdup(console,1); Z fdup(console,2); Z return 0; Z} Zvoid Zstd_restore() Z{ Z fdup(in,0); Z fdup(out,1); Z close(console); Z close(in); Z close(out); Z} STUNKYFLUFF set `sum stdsave.c` if test 61619 != $1 then echo stdsave.c: Checksum error. Is: $1, should be: 61619. fi # # echo Extracting stksiz.c: sed 's/^Z//' >stksiz.c <<\STUNKYFLUFF Zint _STKSIZ = 8192/16; /* (in paragraphs) */ Zint _HEAPSIZ = 32768/16; /* (in paragraphs) */ Zint _STKLOW = 1; /* default is stack above heap (small only) */ STUNKYFLUFF set `sum stksiz.c` if test 11181 != $1 then echo stksiz.c: Checksum error. Is: $1, should be: 11181. fi # # echo Extracting touch.c: sed 's/^Z//' >touch.c <<\STUNKYFLUFF Z#include <stdio.h> Z Ztouch(argc,argv) Z char *argv[]; Z{ Z while(--argc) Z utime(*(++argv),NULL); Z} STUNKYFLUFF set `sum touch.c` if test 31978 != $1 then echo touch.c: Checksum error. Is: $1, should be: 31978. fi # # echo Extracting y.c: sed 's/^Z//' >y.c <<\STUNKYFLUFF Z#include <stdio.h> Z#include <signal.h> Z#include <setjmp.h> Z Z/* y and t Z * y reads the standard input to standard output, then invokes cat Z * to put one or more files to standard output Z * tee copies standard input to output and puts a copy Z * into a file specified on the command line Z */ Z Zvoid (*signal())(); Zvoid (*teesig)(); Zjmp_buf y_env; Zstatic FILE *in,*out; Z ZFILE *fopen(),*fdopen(); Z Zvoid y_intr() Z{ Z signal(SIGINT,SIG_IGN); Z longjmp(y_env,-1); Z} Z Zy(argc,argv) Z int argc; Z char *argv[]; Z{ Z register int c; Z Z /* handle interrupts */ Z if (-1 == setjmp(y_env)) Z { Z static char *intmsg = "Interrupted\r\n"; Z write(2,intmsg,strlen(intmsg)); Z fclose(in); Z fclose(out); Z signal(SIGINT,teesig); Z return -1; Z } Z Z /* set signal catcher */ Z teesig = signal(SIGINT,y_intr); Z Z if (NULL == (in = fdopen(0,"r"))) Z { Z fprintf(stderr,"can't open stdin\n"); Z }; Z if (NULL == (out = fdopen(1,"w"))) Z { Z fprintf(stderr,"can't open stdout\n"); Z }; Z Z while(EOF != (c = agetc(in))) Z aputc(c,out); Z if (argc > 1) Z cat(argc,argv); Z fclose(in); Z fclose(out); Z signal(SIGINT,teesig); Z return 0; Z} Z Zjmp_buf t_env; Z Zvoid t_intr() Z{ Z signal(SIGINT,SIG_IGN); Z longjmp(t_env,-1); Z} Z Zt(argc,argv) Z int argc; Z char *argv[]; Z{ Z register int c; Z register FILE *tfile; Z FILE *fopen(); Z Z /* handle interrupts */ Z if (-1 == setjmp(t_env)) Z { Z static char *intmsg = "Interrupted\r\n"; Z write(2,intmsg,strlen(intmsg)); Z fclose (tfile); Z fclose(in); Z fclose(out); Z signal(SIGINT,teesig); Z return -1; Z } Z Z /* set signal catcher */ Z teesig = signal(SIGINT,t_intr); Z Z if (NULL == (tfile = fopen(*(++argv),"w"))) Z { Z fprintf(stderr,"can't open %s\n",*argv); Z }; Z if (NULL == (in = fdopen(0,"r"))) Z { Z fprintf(stderr,"can't open stdin\n"); Z }; Z if (NULL == (out = fdopen(1,"w"))) Z { Z fprintf(stderr,"can't open stdout\n"); Z }; Z Z while(EOF != (c = agetc(in))) Z { Z aputc(c,out); Z if (tfile) Z aputc(c,tfile); Z } Z fclose(in); Z fclose(out); Z fclose(tfile); Z signal(SIGINT,teesig); Z return 0; Z} STUNKYFLUFF set `sum y.c` if test 44898 != $1 then echo y.c: Checksum error. Is: $1, should be: 44898. fi echo ALL DONE BUNKY! exit 0 -- -- .^. michael regoli /|\ ...ihnp4!inuxc!iuvax!isrnix!mr '|!|` <mr@isrnix.UUCP>
jim@hp-pcd.UUCP (jim) (12/09/85)
mr: The C-shell source posting for MSDOS has been truncated to 64K bytes in length on our system. Could you please split the source into two or more pieces and repost it? Thanks a lot, Jim Andreas hp-pcd\!jim (503) 757-2000 x2860 Portable Computer Division Hewlett-Packard 1000 NE Circle Boulevard Corvallis, Oregon 97333
mr@isrnix.UUCP (michael regoli) (12/15/85)
######################################################### # # # This is a shell archive file. To extract files: # # # # 1) Make a directory for the files. # # 2) Write a file, such as "file.shar", containing # # this archive file into the directory. # # 3) Type "sh file.shar". Do not use csh. # # # ######################################################### # # echo Extracting PACKING_LIST: sed 's/^Z//' >PACKING_LIST <<\STUNKYFLUFF Z Z Volume in drive A is UNIX CSH PC Z Directory of A:\ Z ZCMDS 794 10-03-85 1:56p ZMAKEFILE 1879 10-03-85 2:22p ZCSHELL ARC 86912 11-12-85 11:13a ZCTLBRK ASM 1540 10-03-85 1:29p ZFEXEC ASM 1134 9-05-85 2:23p ZSSBRK ASM 1903 9-30-85 2:35p ZCAT C 1295 9-06-85 10:18a ZCD C 231 9-06-85 9:33a ZCHMOD C 2315 9-06-85 9:33a ZCMDLIST C 1058 9-12-85 11:02a ZCMDS C 2097 9-12-85 11:02a ZCP C 2184 10-03-85 2:46p ZCRLF C 59 9-06-85 9:33a ZCROOT C 3917 8-16-85 2:31p ZDOPROG C 180 9-06-85 9:33a ZDRIVE C 214 9-06-85 9:33a ZDUMP2 C 6969 9-12-85 11:25a ZECHO C 193 9-06-85 9:33a ZENV C 2922 9-06-85 9:33a ZFEXECV C 1119 9-06-85 9:33a ZFEXECVP C 1017 9-06-85 9:33a ZFGREP C 2141 9-06-85 10:13a ZGETCMD C 1453 9-06-85 9:33a ZINVALID C 248 9-06-85 9:33a ZLS C 8042 10-03-85 12:27p ZMAIN C 11239 10-03-85 4:27p ZMD C 121 9-06-85 9:33a ZMORE C 4920 9-19-85 10:27a ZMV C 3802 10-03-85 2:43p ZMVCP C 2600 10-03-85 2:49p ZPUSHD C 1039 9-06-85 9:33a ZPWD C 268 9-06-85 9:33a ZRM C 537 9-06-85 9:33a ZRMDIR C 240 9-06-85 9:33a ZSAVESTR C 243 9-06-85 9:33a ZSTDSAVE C 438 9-06-85 9:33a ZSTKSIZ C 161 10-02-85 2:31p ZTOUCH C 104 9-06-85 9:33a ZY C 2093 9-06-85 10:17a Z_CROOT C 5537 9-19-85 10:16a ZCSHELL DOC 16714 10-03-85 2:11p ZSHELL EXE 28464 10-03-85 4:27p ZSHELL LNK 276 10-03-85 2:22p ZMAIN S 9750 10-03-85 9:24a Z 44 File(s) 115712 bytes free STUNKYFLUFF set `sum PACKING_LIST` if test 56252 != $1 then echo PACKING_LIST: Checksum error. Is: $1, should be: 56252. fi # # echo Extracting _croot.c: sed 's/^Z//' >_croot.c <<\STUNKYFLUFF Z/* Copyright (C) 1981,1982, 1983 by Manx Software Systems */ Z#include <stdio.h> Z#include <errno.h> Z#include <fcntl.h> Z#ifndef NULL Z#define NULL ((void *)0) Z#endif Z Zchar *get_first(), *get_next(), *sbrk(); Zchar *wilderr = "No wild cards in command names!!\r\n"; Z Z/* noexpand can be set by routines before calling _Croot */ Zint noexpand = 0; Z Z#define ARGMAX 256 Zstatic char *Argv[ARGMAX]; Zstatic int Argc; Zstatic char curr_path[128]; Z Z_Croot(cp,cmd) Zregister char *cp; Zint (*cmd)(); Z{ Z int returnval = 0; Z char *startbuf,*endbuf; Z register char *cp2; Z char *wild_match; Z char *index(),*rindex(), *save_str(); Z char *path,*copy; int j; Z char *quote; Z int k,omode; char *fname; Z int in = -1, out = -1; Z /* lets try not to free things not allocated by malloc */ Z startbuf = cp; endbuf = &cp[strlen(cp)]; Z if (!noexpand) Z { Z /* ls is a special case !!! */ Z if(0 == strncmp(cp,"ls",2) || 0 == strncmp(cp,"dir",3)) Z noexpand++; Z } Z Z /* loop through arguments */ Z for (Argc = 0;;) Z { Z /* skip blanks */ Z while (*cp == ' ' || *cp == '\t') Z ++cp; Z Z /* if you're at the end of command line, you're done */ Z if (*cp == 0) Z break; Z /* handle redirection . . . */ Z if (*cp == '>') Z { Z k = 1; Z if (cp[1] == '>') Z { Z ++cp; Z omode = O_CREAT | O_WRONLY | O_APPEND; Z } Z else Z omode = O_CREAT | O_WRONLY | O_TRUNC; Z goto redirect; Z } else if (*cp == '<') Z { Z k = 0; Z redirect: Z while (*++cp == ' ' || *cp == '\t') Z ; Z fname = cp; Z while(*++cp) Z if (*cp == ' ' || *cp == '\t') Z { Z *cp++ = 0; Z break; Z } Z close(k); Z if (k) Z out = k = open(fname,omode); Z else Z in = k = open(fname,O_RDONLY); Z if (k == -1) Z { Z perror("redirection"); Z return -1; Z } Z /* go back for next argument */ Z continue; Z } Z /* find beginning of next argument */ Z cp2 = cp; /* save original pointer to the string */ Z while (*++cp2) Z { Z /* if you hit a space char - stick a null in to terminate last Z argument Z */ Z if (*cp2 == ' ' || *cp2 == '\t') Z { Z *cp2++ = 0; Z break; Z } Z } Z Z /* if no wild card characters, do it the old fashioned way */ Z if (index(cp,'*') == NULL && index(cp,'?') == NULL) Z { Znotranslate: Z if (*cp == '\'') Z /* pass through untranslated, with quotes stripped */ Z { Z cp++; /* point past quote */ Z if ( NULL == (quote = rindex(cp,'\''))) Z { Z write(2,"sh - no close quotes on command line\r\n",38); Z goto free_args; Z } Z *quote = '\0'; Z } Z /* update the next argv pointer */ Z Argv[Argc] = cp; Z /* bump the argument count */ Z if (++Argc == ARGMAX) Z abort(); Z } Z else Z { Z if (*cp == '"' || *cp == '\'') Z goto notranslate; Z if (noexpand) Z goto notranslate; Z /* wild cards not permitted on first run thru */ Z if (Argc == 0) Z { Z write(2,wilderr,strlen(wilderr)); Z return -1; Z } Z /* if there is a path included, save it off */ Z if ((path = rindex(cp,'\\')) || (path = rindex(cp,'/'))) Z { Z copy = cp; Z /* copy to curr_path, mapping / to \ */ Z for (j = 0; j < sizeof(curr_path) && copy != path+1; copy++,j++) Z curr_path[j] = (*copy == '/' ? '\\' : *copy); Z /* terminate string */ Z curr_path[j] = '\0'; Z } Z else if (cp[1] == ':') Z { Z copy = cp; Z for (j = 0; j < 2; j++) Z curr_path[j] = *copy++; Z curr_path[j] = '\0'; Z } else Z /* null path */ Z curr_path[0] = 0; Z if (wild_match = get_first(cp)) Z { Z /* update the next argv pointer */ Z Argv[Argc]= save_str(wild_match); Z /* bump the argument count */ Z if (++Argc == ARGMAX) Z abort(); Z /* get the rest of the matching file names */ Z while (wild_match = get_next()) Z { Z Z /* update the next argv pointer */ Z Argv[Argc] = save_str(wild_match); Z /* bump the argument count */ Z if (++Argc == ARGMAX) Z abort(); Z } Z } Z } Z cp = cp2; /* point to beginning of next argument */ Z } Z Argv[Argc] = NULL; Z returnval=(*cmd)(Argc,Argv); Z if (in != -1) Z close(in); Z if (out != -1) Z close(out); Z /* free anything not dynamically allocated */ Zfree_args: Z if (!noexpand) Z { Z for(j = 1;j < Argc; j++) Z if ( Z !(Argv[j] >= startbuf && Argv[j] <= endbuf) /* not in cmd line */ Z && Argv[j] /* Not NULL */ Z ) Z free(Argv[j]); Z } Z noexpand = 0; Z return returnval; Z} Z Zchar * Zsave_str(s) Z register char *s; Z{ Z register char *r,*malloc(); Z int pathlen; Z /* squirrel away matched file name */ Z if (NULL == (r = malloc(strlen(s)+(pathlen = strlen(curr_path))+1))) Z abort(); Z strcat(curr_path,s); Z strcpy(r,curr_path); Z curr_path[pathlen] = '\0'; Z return r; Z} Z Zabort() Z{ Z write(2, "Too many args.", 14); Z _exit(200); Z} Z Z Ztypedef struct Z{ Z char dos_reserved[21]; Z char attribute; Z unsigned file_time; Z unsigned file_date; Z long file_size; Z char file_name[13]; Z} fcb; Zfcb wildcard; Z Zchar *get_first(fname) Z char *fname; Z{ Z register int result; Z /* set the disk transfer address */ Z bdos(0x1A,&wildcard); Z result = bdos(0x4E,fname,0); Z /* make the find first call */ Z if(2 == result || 18 == result) Z return NULL; Z return &(wildcard.file_name[0]); Z} Z Zchar *get_next() Z{ Z register int result; Z /* set the disk transfer address */ Z bdos(0x1A,&wildcard); Z result = bdos(0x4f,0,0); Z /* make the find next call */ Z if (18 == result) Z return NULL; Z return &(wildcard.file_name[0]); Z} STUNKYFLUFF set `sum _croot.c` if test 54651 != $1 then echo _croot.c: Checksum error. Is: $1, should be: 54651. fi # # echo Extracting cat.c: sed 's/^Z//' >cat.c <<\STUNKYFLUFF Z#include <stdio.h> Z#include <signal.h> Z#include <setjmp.h> Z Zvoid (*signal())(); Z ZFILE *fd1,*fd2; Z Zvoid (*oldsig)(); Zchar *fgets(); Zjmp_buf catenv; Zcatintr() Z{ Z signal(SIGINT,SIG_IGN); /* ignore signals */ Z fclose(fd1); Z fclose(fd2); Z signal(SIGINT,oldsig); /* restore shell interrupt */ Z longjmp(catenv,-1); Z} Z Zcat(argc,argv) Z char *argv[]; Z{ Z char *intmsg = "Interrupt received\n"; Z Z FILE *fdopen(), *fopen(); Z if (-1==setjmp(catenv)) Z { Z write(2,intmsg,strlen(intmsg)); Z return -1; Z } Z oldsig = signal(SIGINT,catintr); /* trap interrupts from keyboard */ Z /* get standard output opened for business */ Z if (NULL == (fd2 = fdopen(1,"w"))) Z { Z perror("cat : Can't open stdout"); Z } Z Z /* handle pipes */ Z if (argc == 1) Z { Z if (NULL == (fd1 = fdopen(0,"r"))) Z { Z perror("cat : Can't open stdin"); Z } Z _cat(); Z fclose(fd1);fclose(fd2); Z } Z /* handle specified files */ Z else Z { Z while(--argc) Z { Z if (NULL == (fd1 = fopen(*(++argv),"r"))) Z { Z fprintf(stderr,"can't open %s\n",*argv); Z continue; Z } Z _cat(); Z fclose(fd1); Z } Z } Z fclose(fd2); Z signal(SIGINT,oldsig); /* restore old int catcher */ Z} Z Z_cat() Z{ Z char buffer[512]; Z while (NULL != fgets(buffer,512,fd1)) Z fputs(buffer,fd2); Z} STUNKYFLUFF set `sum cat.c` if test 12297 != $1 then echo cat.c: Checksum error. Is: $1, should be: 12297. fi # # echo Extracting cd.c: sed 's/^Z//' >cd.c <<\STUNKYFLUFF Z#include <stdio.h> Zcd(argc,argv) Zchar *argv[]; Z{ Z static char *usage = "usage : cd newdir"; Z if (argc == 1) Z write(2,usage,strlen(usage)); Z if (-1 == chdir(*(++argv))) Z { Z perror("cd"); Z return -1; Z } Z return 0; Z} STUNKYFLUFF set `sum cd.c` if test 24433 != $1 then echo cd.c: Checksum error. Is: $1, should be: 24433. fi # # echo Extracting chmod.c: sed 's/^Z//' >chmod.c <<\STUNKYFLUFF Z#include <stdio.h> Z#include <stat.h> Z#ifdef MAIN Zmain Z#else Zch_mod Z#endif Z(argc,argv) Z char *argv[]; Z{ Z int or_mask,and_mask,file_stat; Z struct { int ax,bx,cx,dx,si,di,ds,es; } regs; Z extern int _dsval; Z char *current; Z regs.ds = _dsval; Z if (argc==1) Z { Z fprintf(stderr,"Usage : chmod +|-[ahw] file [file ...]\n"); Z } Z /* set attributes to default */ Z or_mask = 0; and_mask = 0xFFFF; Z while(--argc) Z { Z current = *(++argv); Z switch (*current) Z { Z case '-': Z while (*++current) Z { Z switch(*current) Z { Z case 'w': Z case 'W': Z or_mask |= ST_RDONLY; Z break; Z case 'h': Z case 'H': Z and_mask &= (ST_HIDDEN ^ 0xFFFF); Z break; Z case 'r': Z case 'R': Z or_mask |= ST_HIDDEN; Z break; Z case 'a': Z case 'A': Z and_mask &= (ST_ARCHIV ^ 0xFFFF); Z break; Z case 's': Z case 'S': Z and_mask &= (ST_SYSTEM ^ 0xFFFF); Z break; Z default: Z write(2,"invalid attribute\r\n",19); Z return -1; Z } Z } Z break; Z case '+': Z while(*++current) Z { Z switch(*current) Z { Z case 'w': Z case 'W': Z and_mask &= (ST_RDONLY ^ 0xFFFF); Z break; Z case 'h': Z case 'H': Z or_mask |= ST_HIDDEN; Z break; Z case 's': Z case 'S': Z or_mask |= ST_SYSTEM; Z break; Z case 'r': Z case 'R': Z and_mask &= (ST_HIDDEN ^ 0xFFFF); Z break; Z case 'a': Z case 'A': Z or_mask |= ST_ARCHIV; Z break; Z default: Z write(2,"invalid attribute\r\n",19); Z return -1; Z Z } Z } Z break; Z default: Z /* get current attribute */ Z regs.ax = 0x4300; Z regs.dx = (int)current; Z regs.ds = _dsval; Z sysint(0x21,®s,®s); Z file_stat = regs.cx; Z fprintf(stderr,"current attribute for %s = %x\n", Z current,file_stat); Z /* set new attribute */ Z file_stat |= or_mask; Z file_stat &= and_mask; Z regs.ax = 0x4301; Z regs.dx = (int)current; Z regs.cx = file_stat; Z regs.ds = _dsval; Z sysint(0x21,®s,®s); Z /* get attribute to see if it changed */ Z regs.ax = 0x4300; Z regs.dx = (int)current; Z regs.ds = _dsval; Z sysint(0x21,®s,®s); Z file_stat = regs.cx; Z fprintf(stderr,"new attribute for %s = %x\n", Z current,file_stat); Z break; Z } Z } Z} Z STUNKYFLUFF set `sum chmod.c` if test 37605 != $1 then echo chmod.c: Checksum error. Is: $1, should be: 37605. fi # # echo Extracting cmdlist.c: sed 's/^Z//' >cmdlist.c <<\STUNKYFLUFF Z Zextern int cmds(),ls(), cp(), rm(), do_prog(),pushd(),popd(),drive(), ver(), Z more(),fgrep(),scr_clear(),set(),ch_mod(),cat(),echo(), Z y(),t(),dump(), Z last(),invalid(),mv(),md(),touch(),cd(),pwd(),rd(),hist(),my_exit(); Ztypedef struct Z{ Z char *cmdname; Z int (*func)(); Z} builtin; Zbuiltin commands[] = Z{ Z "a:",drive, Z "b:",drive, Z "c:",drive, Z "cat",cat, Z "cd",cd, Z "chdir",cd, Z "chmod",ch_mod, Z "cls",scr_clear, Z "commands",cmds, Z "copy",cp, Z "cp",cp, Z "copy",cp, Z "d:",drive, Z "del",rm, Z "dir",ls, Z "dump",dump, Z "e:",drive, Z "echo",echo, Z "era",rm, Z "erase",rm, Z "error",last, Z "exit",my_exit, Z "f:",drive, Z "fgrep",fgrep, Z "g:",drive, Z "h:",drive, Z "hd",dump, Z "hist",hist, Z "history",hist, Z "i:",drive, Z "j:",drive, Z "ls",ls, Z "md",md, Z "mkdir",md, Z "more",more, Z "mv",mv, Z "no history",invalid, Z "popd",popd, Z "pushd",pushd, Z "pwd",pwd, Z "rd",rd, Z "rm",rm, Z "rmdir",rd, Z "set",set, Z "tee",t, Z "touch",touch, Z "version",ver, Z "y",y Z}; Zint numcmds = (sizeof(commands)/sizeof(builtin)); STUNKYFLUFF set `sum cmdlist.c` if test 20023 != $1 then echo cmdlist.c: Checksum error. Is: $1, should be: 20023. fi # # echo Extracting cmds: sed 's/^Z//' >cmds <<\STUNKYFLUFF Za: b: c: cat Zcd chdir chmod cls Zcommands copy cp copy Zd: del dir dump Ze: echo era erase Zerror exit f: fgrep Zg: h: hd hist Zhistory i: j: ls Zmd mkdir more mv Zno history popd pushd pwd Zrd rm rmdir set Ztee touch version y Z STUNKYFLUFF set `sum cmds` if test 18223 != $1 then echo cmds: Checksum error. Is: $1, should be: 18223. fi # # echo Extracting cmds.c: sed 's/^Z//' >cmds.c <<\STUNKYFLUFF Z#include <stdio.h> Z#include <fcntl.h> Ztypedef struct Z{ Z char *cmdname; Z int (*func)(); Z} builtin; Z Zchar *str_lower(); Z Zextern int result; Z Zextern int cmds(),ls(), cp(), rm(), do_prog(),pushd(),popd(),drive(), ver(), Z more(),fgrep(),scr_clear(),set(),ch_mod(),cat(),echo(), Z y(),t(),dump(), Z last(),invalid(),mv(),md(),touch(),cd(),pwd(),rd(),hist(),my_exit(); Z Zmy_exit(argc,argv) Z char *argv[]; Z{ Z exit(result); Z} Z Zver() Z{ Z extern char *version; Z write(2,version,strlen(version)); Z write(2,"\r\n",2); Z} Z Zextern builtin commands[]; Zextern int numcmds; Zchar *histerr = "no history"; Zint j,hiscount; Zchar *history[] = {NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL, Z NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}; Z Zint histsize = (sizeof(history)/sizeof(char *)); Z Zcmds() Z{ Z char *current; Z register int i,j,col; Z col = 1; Z for (i = 0; i < numcmds; i++) Z { Z current = commands[i].cmdname; Z write(1,current,j = strlen(current)); Z for (;j < 16;j++) Z write(1," ",1); Z if (col == 4) Z { Z col = 1; Z crlf(); Z } Z else Z ++col; Z } Z crlf(); Z} Z Zfindcmd(cmdbuf) Z char *cmdbuf; Z{ Z register int low,high,mid; Z char localbuf[256]; Z int cond; Z strcpy(localbuf,cmdbuf); Z cmdbuf = str_lower(localbuf); Z low = 0; Z high = numcmds - 1; Z while (low <= high) Z { Z mid = (low+high) / 2; Z if ( ( cond = strncmp( cmdbuf, Z commands[mid].cmdname, Z strlen(commands[mid].cmdname) ) ) < 0 ) Z high = mid - 1; Z else if (cond > 0) Z low = mid + 1; Z else Z { Z /* kludge to allow for program invocations like d:command */ Z if (cmdbuf[1] == ':') Z if (cmdbuf[2] == '\0') Z return mid; Z else Z return -1; Z return mid; Z } Z } Z return -1; Z} Z Zhist() Z{ Z register int i; Z char localbuf[256]; Z if (j < histsize) Z i = 0; Z else Z i = j - histsize + 1; Z for (;i <= j; i++) Z { Z sprintf(localbuf,"%d : %s\r\n",i,history[i % histsize]); Z write(1,localbuf,strlen(localbuf)); Z } Z} Z Zlast() Z{ Z printf("return code of last command %d\n",result); Z return result; Z} STUNKYFLUFF set `sum cmds.c` if test 01085 != $1 then echo cmds.c: Checksum error. Is: $1, should be: 01085. fi # # echo Extracting cp.c: sed 's/^Z//' >cp.c <<\STUNKYFLUFF Z#include <stdio.h> Zchar *me; Z/* cp.c - implements a version of UNIX cp */ Zchar target_name[128]; Z#ifndef MAIN Zcp Z#else Zmain Z#endif Z(argc,argv) Zint argc; Zregister char *argv[]; Z{ Z static char *usage = "cp : usage cp file1 [file2 . . fileN] target\r\n"; Z char target[128],*fname_part(); Z register int i; Z me = argv[0]; Z if (argc < 3) Z { Z write(2,usage,strlen(usage)); Z return(-1); Z } Z strcpy(target, argv[argc-1]); Z /* kill trailing backslashes */ Z if (target[i = strlen(target) - 1] == '\\') Z target[i] = '\0'; Z if (argc == 3) Z { Z if (target[1] == ':' && !target[2]) Z strcat(target,fname_part(argv[1])); Z /* if the target doesn't exist and it's not a directory then rename */ Z if (access(target,0) && !dirp(target)) Z { Z fprintf(stderr,"copying %s to %s\n",argv[1],target); Z filecopy(target,argv[1]); Z } Z else Z { Z /* if the target is a directory copy to same name that directory */ Z if (dirp(target)) Z { Z int len; Z strcpy(target_name,target); Z if (target_name[(len = strlen(target_name))-1] != '\\') Z { Z target_name[len = strlen(target_name)] = '\\'; Z target_name[len+1] = '\0'; Z } Z strcat(target_name,fname_part(argv[1])); Z fprintf(stderr,"copying %s to %s\n",argv[1],target_name); Z filecopy(target_name,argv[1]); Z } Z else Z { Z fprintf(stderr,"copying %s to %s\n",argv[1],target); Z filecopy(target,argv[1]); Z } Z } Z return(0); Z } Z /* handle special case of a drive designation */ Z if (target[(i = strlen(target))-1] != ':') Z if (!dirp(target)) Z { Z fprintf(stderr,"cp : %s isn't a directory\n",target); Z return(-1); Z } Z for (i = 1; i < argc-1; i++) Z { Z int len; Z strcpy(target_name,target); Z if (target_name[(len = strlen(target_name))-1] != '\\') Z { Z target_name[len = strlen(target_name)] = '\\'; Z target_name[len+1] = '\0'; Z } Z strcat(target_name,fname_part(argv[i])); Z if (!filep(argv[i])) Z { Z fprintf(stderr,"cp : %s isn't a file\n",argv[i]); Z continue; Z } Z fprintf(stderr,"copying %s to %s\n",argv[i],target_name); Z filecopy(target_name,argv[i]); Z } Z return 0; Z} STUNKYFLUFF set `sum cp.c` if test 27151 != $1 then echo cp.c: Checksum error. Is: $1, should be: 27151. fi # # echo Extracting crlf.c: sed 's/^Z//' >crlf.c <<\STUNKYFLUFF Zcrlf() Z{ Z static char *cr = "\r\n"; Z write(1,cr,2); Z} STUNKYFLUFF set `sum crlf.c` if test 19813 != $1 then echo crlf.c: Checksum error. Is: $1, should be: 19813. fi # # echo Extracting croot.c: sed 's/^Z//' >croot.c <<\STUNKYFLUFF Z/* Copyright (C) 1981,1982, 1983 by Manx Software Systems */ Z#include <errno.h> Z#include <fcntl.h> Z#ifndef NULL Z#define NULL ((void *)0) Z#endif Z Zchar *get_first(), *get_next(), *sbrk(); Z Z#define ARGMAX 256 Zstatic char *Argv[ARGMAX]; Zstatic int argvsize; Zstatic int Argc; Zstatic char curr_path[128]; Z Znoper() Z{ Z return 0; Z} Z Zint (*cls_)() = noper; Zextern char _ioflg[]; Z ZCroot(cp, first) Zregister char *cp; Z{ Z register char *cp2; Z char *save; Z char *wild_match; Z char *index(),*rindex(), *save_str(); Z char *path,*copy; int j; Z Z _ioflg[0] = isatty(0); /* set flag for i/o routines */ Z _ioflg[1] = isatty(1); /* set flag for i/o routines */ Z _ioflg[2] = isatty(2); /* set flag for i/o routines */ Z Z Z /* Null out first argument */ Z Argv[0] = ""; Z Argc = first; Z Z /* loop through arguments */ Z for (;;) Z { Z /* skip blanks */ Z while (*cp == ' ' || *cp == '\t') Z ++cp; Z Z /* if you're at the end of command line, you're done */ Z if (*cp == 0) Z break; Z Z /* find beginning of next argument */ Z cp2 = cp; /* save original pointer to the string */ Z *cp2 = (*cp2 == '/' ? '\\' : *cp2); Z while (*++cp2) Z { Z /* if you hit a space char - stick a null in to terminate last Z argument Z */ Z if (*cp2 == ' ' || *cp2 == '\t') Z { Z *cp2++ = 0; Z break; Z } Z *cp2 = (*cp2 == '/' ? '\\' : *cp2); Z } Z Z /* if no wild card characters, do it the old fashioned way */ Z if (index(cp,'*') == NULL && index(cp,'?') == NULL) Z { Z /* update the next argv pointer */ Z Argv[Argc] = cp; Z /* bump the argument count */ Z if (++Argc == ARGMAX) Z abort(); Z } Z else Z { Z /* if there is a path included, save it off */ Z if ((path = rindex(cp,'\\')) || (path = rindex(cp,'/'))) Z { Z copy = cp; Z /* copy to curr_path, mapping / to \ */ Z for (j = 0; j < sizeof(curr_path) && copy != path+1; copy++,j++) Z curr_path[j] = (*copy == '/' ? '\\' : *copy); Z /* terminate string */ Z curr_path[j] = '\0'; Z } Z else if (cp[1] == ':') Z { Z copy = cp; Z for (j = 0; j < 2; j++) Z curr_path[j] = *copy++; Z curr_path[j] = '\0'; Z } else Z /* null path */ Z curr_path[0] = 0; Z if (wild_match = get_first(cp)) Z { Z /* update the next argv pointer */ Z Argv[Argc]= save_str(wild_match); Z /* bump the argument count */ Z if (++Argc == ARGMAX) Z abort(); Z /* get the rest of the matching file names */ Z while (wild_match = get_next()) Z { Z Z /* update the next argv pointer */ Z Argv[Argc] = save_str(wild_match); Z /* bump the argument count */ Z if (++Argc == ARGMAX) Z abort(); Z } Z } Z } Z cp = cp2; /* point to beginning of next argument */ Z } Z Argv[Argc] = NULL; Z main(Argc,Argv); Z exit(0); Z} Z Zchar *save_str(s) Z register char *s; Z{ Z register char *r; Z int pathlen; Z /* squirrel away matched file name */ Z if (NULL == (r = sbrk(strlen(s)+(pathlen = strlen(curr_path))+1))) Z abort(); Z strcat(curr_path,s); Z strcpy(r,curr_path); Z curr_path[pathlen] = '\0'; Z return r; Z} Z Zabort() Z{ Z write(2, "Too many args.", 14); Z _exit(200); Z} Z Zexit(code) Z{ Z (*cls_)(); Z _exit(code); Z} Z Ztypedef struct Z{ Z char dos_reserved[21]; Z char attribute; Z unsigned file_time; Z unsigned file_date; Z long file_size; Z char file_name[13]; Z} fcb; Zfcb wildcard; Z Zchar *get_first(fname) Z char *fname; Z{ Z register int result; Z /* set the disk transfer address */ Z bdos(0x1A,&wildcard); Z result = bdos(0x4E,fname,0); Z /* make the find first call */ Z if(2 == result || 18 == result) Z return NULL; Z return &(wildcard.file_name[0]); Z} Z Zchar *get_next(fname) Z char *fname; Z{ Z register int result; Z /* set the disk transfer address */ Z bdos(0x1A,&wildcard); Z result = bdos(0x4f,0,0); Z /* make the find next call */ Z if (18 == result) Z return NULL; Z return &(wildcard.file_name[0]); Z} STUNKYFLUFF set `sum croot.c` if test 02895 != $1 then echo croot.c: Checksum error. Is: $1, should be: 02895. fi # # echo Extracting cshell.doc: sed 's/^Z//' >cshell.doc <<\STUNKYFLUFF Z shell.exe Z Z command processor for ms.dos Z Z This is yet another command.com replacement. It implements Z unix-like shell commands (ls, mv, fgrep, rm, chdir, chmod) etc. Z Other features include: Z Z 1. Command line expansion of ambiguous file names. Z Z Programs invoked from shell never see '*.*' as an argument - Z they see the list of all matching files in the current Z directory. Z Z 2. History substitution - ala C-shell. Z Z History substitution is a powerful means to save retyping of long Z command lines.It allows you to do things like re-execute the last Z command, re-execute the last command but redirect output to a Z file, or execute a new command with arguments from previous Z command lines. The last 20 commands are saved, and can be Z reviewed by typing the 'history' command. Z Z Previous commands can be referred to by their number, or relative Z to the current command's number. Parameters from previous Z commands can be seperated out and used individually. Z Z History substitutions specifications come in two parts - the Z command number specifier and the argument specifier, seperated Z by a colon. The argument specifier is optional; if it is Z omitted, the entire command line is specified. Z Z <command specifier> ::= !! | !n | !-n Z !! = last command Z !n = nth command Z !-n = command n commands before current command number Z Z <argument specifier> ::= :[^$*] | :n | :n* | <empty> Z n = number of argument (0 being the command name) Z ^ = first argument (i.e. argv[1]) Z $ = last argument Z * = ^-$, or nothing if only one word on command line Z n* = arguments n through $ Z Z <history subst specification> ::= <command specifier><argument specifier> Z Z This is not as complicatated as it may appear. Here is an Z example session. Z Z 0% ls *.c Z *.c Z foo.c bar.c Z 1% more foo.c Z /* edit the last argument of the last command */ Z 2% edit !!:$ Z /* go off and edit */ Z /* reference last argument of last command */ Z 3% fgrep foo !!:$ bar.c Z FOO.C : foo Z BAR.C : foo Z /* edit the second thru the last args of command 3 */ Z Z Z Z Z Z Z Z Z 4% edit !3:2* Z (go off and edit) Z /* repeat last command */ Z %5 !! Z (go off and edit) Z /* remove the 1st argument of the command 2 before the current one */ Z %6 rm !-6:^ Z Z History substitution here is a compatible subset of the C-shells Z history substitution facility. Cshell allows even weirder Z combinations. Z Z 3. Multiple commands on one command line - Command lines are Z split at semicolons. Z Z example Z Z %0 ls -l *.c ; make shell.exe ; exit Z Z 4. Character escapes and argument quoting - i.e. '\;' suppresses Z the command parser from seeing the semicolon as a command Z seperator. Z Z Quotes are handles thusly: Z Z 1. String surrounded by single quotes are stripped of the Z single quotes, and passed without wild-card expansion to the Z invoked program. Z Z 2. Strings surrounded by double quotes are passed complete Z with quotes to the calling program. This was done for a Z version of grep that I have that accepts regular expressions Z with embedded blanks within double quotes. Z Z 5. Many builtin commands. Z Z Output of the 'commands' command Z Z a: b: c: cat Z cd chdir chmod cls Z commands copy cp copy Z d: del dir dump Z e: echo era erase Z error exit f: fgrep Z g: h: hd hist Z history i: j: ls Z md mkdir more mv Z no history popd pushd pwd Z rd rm rmdir set Z tee touch version y Z Z Z There are many that are simply aliases, e.g. 'copy' and 'cp' Z invoke the same program. Z Z 6. commands description syntax Z Z terms used in syntax explanations : Z Z Z Z Z Z Z Z Z Z fname ::= PC-DOS ambiguous or unambiguous file or directory name. Z Z uname ::= unambiguous PC-DOS file or directory name Z Z string ::= any string of printable characters of arbitrary(<512) length. Z Z filelist ::= filename [filename .. filename] Z Z noargs ::= no arguments at all Z Z {arg} ::= term is optional Z Z envstring ::= <string>=<string> Z Z 7. command syntax Z Z drive Z a: | b: | c: | d: | e: | f: | g: | h: | i: | j: <noargs> Z Z changes default drive. If you don't have such a drive, Z nothing happens. Z Z cat Z cat {<filelist>} Z Z copies specified files to standard output. If none are Z given, copies standard input to standard output Z Z cp Z cp | copy <filelist> <uname> Z Z copies specified files to destination file or device. If Z more than one file is in the file list, <uname> must be a Z directory. Z Z cd Z cd | chdir <dirname> Z Z makes <dirname> the current default directory. Z Z chmod Z chmod {-|+[rwh]*} <filelist> Z Z change file permissions for specified files Z Z +r, -r turn on or off read permission - i.e. hide the file. Z +w, -w turn on or off write permission. Z +h, -h turn on or off hidden attribute - converse of r Z +a, -a turn on or off archive attribute Z Z Note that '-r' or '+rwh' are both valid syntax for switches. Z Also new permission switches are permissable between file Z names with the following warning: I don't reset the masks Z between file names - if you have a second batch of attribute Z changes on the command line, the effect is additive. If Z you're not careful, you could make a mess of a files Z attributes. Z Z Z Z Z Z Z Z Z If you don't specify any attribute switches, file attributes Z will be set to 0, which means read,write,not hidden,not Z system, not modified since last backup. Z Z cls Z cls | clear <noargs> Z Z clears the screen and homes the cursor. Z Z commands Z commands <noargs> Z Z prints a table of available built-in commands. Z Z del Z del Z Z synonym for rm. Z Z dir Z dir Z Z synonym for ls. Z Z dump Z Z dump filespec [block [page]] | [segment:[offset]] [count] Z Z Where a block is 64K bytes and a page is 256 bytes Z Segment:offset are standard 8086 notation in hexadecimal Z Count is the number of bytes to dump in decimal Z Z This came from some anonymous public domain source, ported by me Z Z echo Z echo <anything> Z Z echos argument list to screen. Z Z era Z era Z Z synonym for rm. Z Z error Z error <noargs> Z Z prints returned value of last command to the screen. Z Z exit Z exit <noargs> Z Z terminates execution of the shell. Z Z fgrep Z fgrep <pattern> <filelist> Z Z looks for unambiguous pattern <pattern> in <filelist>. echos Z Z Z Z Z Z Z Z Z lines matching to the screen. Z Z hist Z hist | history <noargs> Z Z prints history list to standard output. Z Z ls Z ls | dir {-[alqcr]} <filelist> Z Z Lists files that match <filelist> Z Z -a all files, including system files are listed. '.' and Z '..' are suppressed, but you know they're there if you need Z them, don't you? Z -l prints out file times, permissions, etc Z -q suppresses header line from display - useful when you want Z to pipe stuff into another program. Z -c print as one column. Z -r recurse through all encountered subdirectories. Z Z md Z md | mkdir <uname> Z Z make a directory. Prints an error if it can't be done Z Z more Z more {-[0-9]*} {<filelist>} Z Z List file to screen with pauses Z Z -n specify tab width when expanding tabs, where n is an Z integer. more acts like 'cat' when redirected - you can Z concatenate files in this manner. If no files are specifed, Z standard input is 'mored.' Z Z mv Z mv <filelist> <uname> Z Z moves specified file or files to target specifed by <uname>. Z If there is more than one file in list, <uname> must be a Z directory Z Z popd Z popd <noargs> Z Z returns to directory at top of directory stack. Z Z pushd Z pushd <uname> Z Z save current working directory on directory stack, and Z changes current working directory to <uname>. Z Z pwd Z pwd Z Z prints current working directory to standard output. Z Z Z Z Z Z Z Z Z rd Z rd | rmdir <uname> Z Z remove specified directory if possible. Z Z rm Z rm {-q} <filelist> Z Z blows away all files in <filelist>. If -q is specified, will Z ask if they should be removed. Z Z set Z set {<envstring> {<envstring> .. <envstring>}} Z Z sets a string in the environment. If you specify 'name=' Z with no string after, it will remove it from the Z environment. If you don't specify a string, set prints out Z current environment. Z Z tee Z tee <uname> Z Z Copies standard input to standard output, depositing a copy Z in <uname> Z Z touch Z touch <filelist> Z Z Makes the modification time of specified files the current Z date and time. Z Z y Z y <filelist> Z Z copies standard input to standard output, and then copies the Z specified files to standard output. Sort of the opposite of Z tee, in other words. Z Z 7. Helpful hints Z Z Use forward slashes in all path names - they get converted to Z back slashes before dos hears about them. If you are Z invoking a program that expects forward slashes (dos external Z commands frinstance) precede it with a back slash. Z Z put single quotes around arguments with semicolons in them, Z so they don't turn into command delimiters. Z Z The set command affects only the local shell's environment. Z You can 'exit' to command.com and the original environment is Z intact. The local environment is 4K large - which is Z useful. Z Z Exit and re-invoke if you have trouble loading large programs Z from it - shell dynamically allocates and frees memory all Z the time, but the AZTEC run-time doesn't tell DOS to shrink Z memory Z Z Z Z Z Z Z Z Z Z 8. Implementation notes Z Z DOS doesn't acknowledge a 'change default drive' command Z until you issue a 'get current directory' call. Why? The Z only way I figured this out is by disassembling command.com. Z Z This was developed with AZTEC C by MANX. In it are a few Z hacked up pieces of AZTECS library source, which I hereby Z acknowledge. If MANX has a problem with me distributing Z them, they can call me direct - I figure I'm doing them a Z favor by disseminating this program as an example of the Z power and quality of their compiler and development tools. Z Z If you have the AZTEC compiler and MANX's version of make, Z you can recreate the shell from source, by using arc to Z unpack everything into a directory, editing the macros BINDIR Z and CLIB and then making shell.com. I wouldn't try it with Z any other compiler, because I make a lot of calls to AZTEC Z specific routines. You can write your own commands and add Z them by editing cmds.c, and putting the name of your Z subroutine and its associated command string into the builtin Z array. Z Z You can safely modify any of my builtins, as long as you Z don't assume that all of your static variables are going to Z stay initialized to startup values. Z Z Any of the other code (main.c, fexecvp.c fexecv.c) modify at Z your own peril. I break them every time I do it, and I wrote Z them!!! Z Z PC|MS-DOS has a limit of 20 file handles. If you add a Z command that opens files, make sure you catch the ctrl-break Z signal and close them. Look at CAT.C or Y.C for examples. Z Z 9. BUGS Z External DOS commands have trouble parsing the command line Z when invoked from shell. The command line gets garbled. I Z spent a lot of time trying to figure this problem out to no Z avail. They apparently get their command line arguments some Z way that is a mystery to me. The only solution is either to Z either run command.com, or 'exit' to the original command Z prompt. Z Z This problem has kept me from running this as a straight Z command.com replacement. It just goes to show that Z Microsoft and IBM have one hell of a time following their own Z rules. Z Z Programs compiled by AZTEC C that don't set up their own Z signal handlers seem to be 'unbreakable' - you can't Z ctrl-break out of them, as though SIGINT is set to SIG_IGN Z before entry. You might not want to invoke such a program if Z it lasts hours and you want to be able to break out of it. Z FIXED in current version. Thanks to AZTEC Tech Support. Z Z 10. HISTORY Z Z Z Z Z Z Z Z Z Z V 1.0 - Initial release Z Z Functional, but somewhat buggy. Lacked full history Z substitution. Z Z V 1.1 Z Z Added history substitution. Fixed some bugs. This has been Z floating around for a while. Z Z V 1.2 Z Z Fixed bugs. Added 'free space' display to ls -l. Minimized Z weird behavior of cp and mv. Did you know that PC-DOS Z doesn't think the root directory is a directory if you ask Z it? Caused much pain. Z Z QUESTIONS COMMENTS GOTO Z KENT WILLIAMS Z NORAND INC. Z 550 2nd ST. S.E. Z Cedar Rapids Iowa 52401 Z (319) 338-6053 (HOME VOICE) Z Z Z Z Z Z Z Z Z Z Z Z Z Z Z Z Z Z Z Z Z Z Z Z Z Z Z Z Z Z Z Z Z Z Z Z Z Z Z STUNKYFLUFF set `sum cshell.doc` if test 25555 != $1 then echo cshell.doc: Checksum error. Is: $1, should be: 25555. fi # # echo Extracting ctlbrk.asm: sed 's/^Z//' >ctlbrk.asm <<\STUNKYFLUFF Z; Copyright (C) 1985 by Manx Software Systems, Inc. Z; :ts=8 Z include lmacros.h Z Zdataseg segment word public 'data' Z extrn _PSP_:word Z _brkvec dw ? Z dw ? Z localstk dw 20 dup(?) Z stktop label word Z savess dw ? Z savesp dw ? Zdataseg ends Z Zourds dw 0 Z Z assume ds:dataseg Z; Z procdef ctl_brk_setup Z mov ourds,ds Z push ds Z mov ax,3523H ;get cntl-break (cntl-c) handler Z int 21H Z mov _brkvec,bx Z mov _brkvec+2,es Z mov dx,offset brk_handler Z mov ax,cs Z mov ds,ax Z mov ax,2523H ;set new cntl-break handler Z int 21H Z pop ds Z pret Z pend ctl_brk_setup Z Z procdef ctl_brk_restore Z push ds Z mov dx,_brkvec Z mov bx,word ptr _brkvec+2 Z mov ds,bx Z mov ax,2523H ;restore old cntl-break handler Z int 21H Z pop ds Z pret Z pend ctl_brk_restore Z Zbrk_handler proc far Z ;save ds and address our data segment Z push ds Z mov ds,ourds Z ;move to the local stack after saving dos stack Z push ax Z mov savess,ss Z mov savesp,sp Z mov ax,ds Z mov ss,ax Z mov sp,offset stktop Z ;save registers Z push bp Z push bx Z push cx Z push dx Z push si Z push di Z push es Z mov ah,051H ;find the current psp Z int 21H Z cmp bx,_PSP_ ;is it our program segment? Z je noabort Z ;set carry flag Z mov ax,0FFFFH ;set up to shift bit into carry Z rcr ax,1 Z jmp short done Znoabort: Z ;clear carry flag Z or ax,ax ;should clear carry Zdone: Z pop es Z pop di Z pop si Z pop dx Z pop cx Z pop bx Z pop bp Z mov ax,savess Z mov ss,ax Z mov sp,savesp Z pop ax Z pop ds Z jc abortend Z iret Zabortend: Z ret Zbrk_handler endp Z finish Z end STUNKYFLUFF set `sum ctlbrk.asm` if test 52105 != $1 then echo ctlbrk.asm: Checksum error. Is: $1, should be: 52105. fi # # echo Extracting doprog.c: sed 's/^Z//' >doprog.c <<\STUNKYFLUFF Zdo_prog(argc,argv) Zchar *argv[]; Z{ Z int result; Z if (666 == (result = fexecvp(argv[0],argv))) Z { Z invalid(argc,argv); Z perror(""); Z return -1; Z } Z return result; Z} STUNKYFLUFF set `sum doprog.c` if test 44858 != $1 then echo doprog.c: Checksum error. Is: $1, should be: 44858. fi # # echo Extracting drive.c: sed 's/^Z//' >drive.c <<\STUNKYFLUFF Z#define NULL (void *)0 Zdrive(argc,argv) Z char *argv[]; Z{ Z char *dir,*getcwd(); Z Z bdos(0xe,**argv - 'a'); /* select drive 0 */ Z if (NULL == (dir = getcwd(NULL,64))) Z return -1; Z free(dir); Z return 0; Z} STUNKYFLUFF set `sum drive.c` if test 37068 != $1 then echo drive.c: Checksum error. Is: $1, should be: 37068. fi # # echo Extracting dump2.c: sed 's/^Z//' >dump2.c <<\STUNKYFLUFF Z Z/* dump.c (10/83) Debug style dump of a file from any starting position. Z*/ Z#include <stdio.h> Z#include <ctype.h> Z#include <signal.h> Z#include <setjmp.h> Z#define FAIL 1 Z#define SUCCESS 0 Z#define TRUE (1) Z#define FALSE 0 Z#define FOREVER for (;;) Z#define PAUSE if (getch()=='\0') getch(); Z#define STDIN 0 Z#define STDOUT 1 Z#define STDERR 2 Zchar *dumpusage[] = Z{ Z "Usage: dump filespec [block [page]] | [segment:[offset]] [count]\r\n", Z "Where a block is 64K bytes and a page is 256 bytes.\r\n", Z "Segment:offset are standard 8086 notation in hexadecimal.\r\n", Z "Count is the number of bytes to dump in decimal.\r\n", Z NULL Z}; Zchar *index(); /* suppress warning about conversion to int */ Z#define BUFSIZE 512 Ztypedef unsigned ushort; Z Zstatic int _fmode = 0x8000; /* Lattice 'c' - forces binary I/O */ Zextern short errno; /* DOS 2.0 error number */ Zlong lseek(); Z Zstatic char buffer[BUFSIZE]; /* input buffer */ Zstatic ushort block = 0; /* block number ( 64k bytes/block ) */ Zstatic ushort page = 0; /* page number ( 256 bytes/page ) */ Zstatic ushort segment = 0; Zstatic ushort offset = 0; Zstatic long filpos = 0; /* beginning file position */ Zstatic long count = 0x7FFFFFFFL; /* number of bytes to dump */ Z Zvoid ohw(),ohb(),onib(),abort(); Z Zstatic jmp_buf env; Zvoid (*signal())(); Zstatic void (*oldsig)(); Zstatic onintr() Z{ Z signal(SIGINT,SIG_IGN); /* disable interrupts from kbd */ Z longjmp(env,-1); Z} Z Z#ifdef MAIN Zmain Z#else Zdump Z#endif Z(argc,argv) /* DUMP ENTRY */ Zint argc; Zchar *argv[]; Z{ Z char c; Z ushort i, numin, tot, file, cfrom; Z char *flag = 0; Z char *index(); Z oldsig=signal(SIGINT,onintr); Z if (-1 == setjmp(env)) Z { Z close(file); Z write(2,"Interrupted\r\n",13); Z signal(SIGINT,oldsig); Z return -1; Z } Z if (argc < 2) Z { Z char **u = (char **) dumpusage; Z while(*u) Z { Z write (2,*u,strlen(*u)); Z ++u; Z } Z return -1; Z } Z if ((file = open( argv[1], 0 )) == -1) Z abort( "cannot open", argv[1], errno ); Z Z if (argc > 2) { Z if ((flag = index( argv[2], ':' )) != NULL) { Z i = stch_i( argv[2], &segment ); Z stch_i( argv[2]+i+1, &offset ); Z } Z if (sscanf( argv[2], "%d", &block ) != 1) Z abort( "invalid block", argv[2], 0 ); Z } Z if (argc > 3) Z if (sscanf( argv[3], "%d", &page ) != 1) Z abort( "invalid page", argv[3], 0 ); Z Z if ( flag ) { Z filpos = (long)segment*16L + (long)offset; Z tot = offset; Z } Z else { Z filpos = (block * 65536L) + (page * 256); Z tot = page * 256; Z segment = block * 4096; Z } Z Z if (lseek( file, filpos, 0 ) == -1L) Z abort( "positioning to", argv[2], errno ); Z Z if (argc > 4) Z if (sscanf( argv[4], "%ld", &count ) != 1) Z abort( "invalid count", argv[4], 0 ); Z Z Z do { /* read & dump BUFSIZE bytes */ Z numin = read( file, buffer, BUFSIZE ); Z if (numin == -1) Z abort( "cannot read", argv[1], errno ); Z cfrom=0; Z while (cfrom < numin) { Z Z ohw(segment); /* print offset in hex */ Z putchar(':'); Z ohw(cfrom+tot); Z putchar(' '); Z Z for (i=0; i < 16; i++) { /* print 16 bytes in hex */ Z putchar(' '); Z ohb(buffer[cfrom++]); Z } Z Z putchar(' '); putchar(' '); putchar(' '); Z Z cfrom -= 16; Z for (i=0; i < 16; i++) { /* print 16 bytes in ASCII */ Z c = buffer[cfrom] & 0x7f; Z if ( isprint(c) ) /* if printable character */ Z putchar(c); Z else Z putchar('.'); /* else print period */ Z cfrom++; Z } Z Z putchar('\r'); putchar('\n'); /* print CR/LF */ Z Z if ((count -= 16) <= 0) /* is count exhausted? */ Z exit(0); Z } /* end of while */ Z tot += numin; Z if ( tot == 0 ) Z segment += 4096; Z } /* end of do */ Z while (numin == BUFSIZE); Z signal(SIGINT,oldsig); /* restore signal */ Z return 0; Z} /* end of main */ Z Zstatic void ohw(wrd) /* print a word in hex */ Zushort wrd; Z{ Z ohb( wrd>>8 ); Z ohb( wrd ); Z} Z Zstatic void ohb(byt) /* print a byte in hex */ Zchar byt; Z{ Z onib( byt>>4 ); Z onib( byt ); Z} Z Zstatic void onib(nib) /* print a nibble as a hex character */ Zchar nib; Z{ Z nib &= 15; Z putchar((nib >= 10) ? nib-10+'A': nib+'0'); Z} Z Zstatic void abort( msg1 ,msg2 ,errno) /* print error msg1, msg2, and nbr */ Zchar *msg1,*msg2; /* Does not close files. */ Zshort errno; Z{ Z char stemp[10]; Z Z write( STDERR, "ERR: ", 5 ); Z if (msg1) Z write( STDERR, msg1, strlen(msg1) ); Z if (msg2) Z write( STDERR, " ", 1 ); Z write( STDERR, msg2, strlen(msg2) ); Z if (errno) { Z sprintf( stemp," #%d", errno ); Z write( STDERR, stemp, strlen(stemp) ); Z } Z write( STDERR, "\r\n", 2 ); Z longjmp(env,-1); Z} Z/** END DUMP **/ Z Z#define BDOS_IN 7 /* input function for "getch" */ Z#define BDOS_OUT 6 /* output function for "putch" */ Z#define BDOS_CKS 11 /* check keyboard status for "kbhit" */ Z#define BDOS_BKI 10 /* buffered keyboardd input for "cgets" */ Z#define BDOS_PRT 9 /* print string for "cputs" */ Z Zstatic char pushback; /* character save for "ungetch" */ Z Zstatic getch() Z{ Zint c; Z Zif (pushback != '\0') Z { /* character was pushed back */ Z c = pushback; Z pushback = '\0'; Z return(c); Z } Zreturn(bdos(BDOS_IN, 0xFF) & 127); Z} Zstatic putch(c) Zchar c; Z{ Zbdos(BDOS_OUT, c&127); Zreturn(c); Z} Zstatic ungetch(c) Zchar c; Z{ Z Zif (pushback != '\0') return(-1); Zpushback = c; Zreturn(c); Z} Zstatic char *cgets(s) Zchar *s; Z{ Zchar *p; Z Zif (*s == 0) *s = 250; /* do not allow zero byte count */ Zbdos(BDOS_BKI, s); Zp = s+2; Zp[s[1]] = '\0'; /* set terminating byte */ Zreturn(p); Z} Zstatic cputs(s) Zchar *s; Z{ Zchar *p; Z Zfor (p = s; *p != '\0'; p++) ; /* find string terminator */ Z*p = '$'; Zbdos(BDOS_PRT, s); Z*p = '\0'; Zreturn; Z} Z Z Zstatic int stch_i(p,r) Z char *p; Z int *r; Z{ Z int count; Z int acc; Z int hdtoi(); Z count = 0; Z *r = 0; Z while (-1 != (acc = hdtoi(*p++))) Z { Z ++count; Z *r = (*r << 4) | acc; Z } Z return count; Z} Z Zstatic hdtoi(c) Z char c; Z{ Z c = toupper(c); Z if (!isxdigit(c)) Z return -1; Z if (isdigit(c)) Z return (c - '0'); Z return (c - 'A' + 10); Z} STUNKYFLUFF set `sum dump2.c` if test 53530 != $1 then echo dump2.c: Checksum error. Is: $1, should be: 53530. fi # # echo Extracting echo.c: sed 's/^Z//' >echo.c <<\STUNKYFLUFF Z Zecho(argc,argv) Z char *argv[]; Z{ Z register int i; Z for (i = 1; i < argc;i++) Z { Z write(2,argv[i],strlen(argv[i])); Z if (i < argc-1) Z write(2," ",1); Z } Z crlf(); Z return 0; Z} STUNKYFLUFF set `sum echo.c` if test 29675 != $1 then echo echo.c: Checksum error. Is: $1, should be: 29675. fi # # echo Extracting env.c: sed 's/^Z//' >env.c <<\STUNKYFLUFF Z#include <stdio.h> Z Z#define ENVSIZE 4000 Zextern int _PSP; Zvoid *calloc(); Zchar *environment=NULL, *str_upper(); Zint env_paragraph; Zchar *next_env; Z#define envlimit(a) &a[ENVSIZE-1] Z Z#ifdef MAIN Zmain Z#else Zset Z#endif Z(argc,argv) Z char *argv[]; Z{ Z if (!environment) Z init_env(); Z if (argc == 1) Z { Z show_env(); Z return 0; Z } Z while(--argc) Z { Z add_env(str_upper(*(++argv))); Z } Z return 0; Z} Z Zchar * Zstr_upper(c) Z register char *c; Z{ Z register char *save = c; Z while(*c) Z { Z *c = toupper(*c); Z c++; Z } Z return save; Z} Z Zchar * Zstr_lower(c) Z register char *c; Z{ Z register char *save = c; Z while(*c) Z { Z *c = tolower(*c); Z c++; Z } Z return save; Z} Zinit_env() Z{ Z extern unsigned _dsval; /* current data segment register value */ Z long fudgefactor; Z register int c; Z unsigned envseg; Z unsigned offset = 0; Z envseg = peekw(0x2c,_PSP); Z environment = calloc(1,ENVSIZE+16); Z fudgefactor = (long)_dsval << 4; /* convert to absolute paragraph */ Z fudgefactor += (unsigned)environment + 16; Z fudgefactor &= 0xFFFF0L; Z env_paragraph = (int)((fudgefactor >>4) & 0xFFFF); Z environment = (char *) (fudgefactor - (long)(_dsval << 4)); Z next_env = environment; Z while (c = peekb(offset,envseg)) Z { Z while (c = peekb(offset++,envseg)) Z { Z *next_env++ = c; Z } Z *next_env++ = '\0'; Z } Z} Z Zshow_env() Z{ Z register char *env; Z char c; Z for (env = environment;*env;) Z { Z while (c = *env++) Z write(1,&c,1); Z crlf(); Z } Z} Z Zstatic char *enverr = "No more environment space\r\n"; Zstatic char *enverr2 = "Improper environment string format!!\r\n"; Z Zadd_env(string) Z char *string; Z Z{ Z char *env_copy, *new, *index(); Z char *old = environment; Z char *name_end,*new_name_end; Z int added = 0; Z int namelen; Z Z if (NULL == (env_copy = new = calloc(1,ENVSIZE))) Z { Z write(2,enverr,strlen(enverr)); Z return -1; Z } Z Z while (*old) Z { Z if ( NULL == (name_end = index(old,'=')) || Z NULL == (new_name_end = index(string,'=')) Z ) Z { Z write(2,enverr2,strlen(enverr2)); Z free(env_copy); Z return -1; Z } Z namelen = (int)(name_end - old); Z if (!strncmp(old,string,namelen)) Z { Z if (new_name_end[1]) Z { Z /* if we don't have a string of the form name= */ Z /* copy new string instead of old string */ Z strcpy(new,string); Z } Z else Z /* if we have a set name= with no string then we want Z to remove the string from the environment Z */ Z ; Z added++; Z } Z else Z { Z strcpy(new,old); Z } Z new = &new[strlen(new)+1]; Z old = &old[strlen(old)+1]; Z if (new >= envlimit(new)) Z { Z write(2,enverr,strlen(enverr)); Z free(env_copy); Z return -1; Z } Z } Z if (!added) Z { Z strcpy(new,string); Z } Z new = &new[strlen(new)+1]; Z /* copy the copy back to the environment */ Z movmem(env_copy,environment,(int)(new-env_copy)+2); Z free(env_copy); Z return 0; Z} STUNKYFLUFF set `sum env.c` if test 56918 != $1 then echo env.c: Checksum error. Is: $1, should be: 56918. fi # # echo Extracting fexec.asm: sed 's/^Z//' >fexec.asm <<\STUNKYFLUFF Z; Copyright (C) 1984 by Manx Software Systems Z; :ts=8 Z include lmacros.h Zdataseg segment para public 'data' Zparam equ this word Zenv dw ? Zcline dw ?,? Zfcb1 dw ?,? Zfcb2 dw ?,? Z extrn errno_:word Zdataseg ends Z assume ds:dataseg Zsave_ss dw 0 Zsave_sp dw 0 Z procdef fexec,<<filname,ptr>,<enva,word>,<clinea,ptr>,<fcb1a,ptr>,<fcb2a,ptr>> Z; char *fexec(name,env,cline,fcb1,fcb2) Z; Z push si Z push di Z pushf Z push [030H] Z push [02EH] Z push ds Z push es Z mov cs:save_ss,ss Z mov cs:save_sp,sp Z; Z; set up parameter block for exec call Z; Z mov ax,enva Z mov env,ax Zifndef LONGPTR Z mov ax,ds Z mov es,ax Zendif Z ldptr ax,clinea,es Z mov cline,ax Z mov cline+2,es Z ldptr ax,fcb1a,es Z mov fcb1,ax Z mov fcb1+2,es Z ldptr ax,fcb2a,es Z mov fcb2,ax Z mov fcb2+2,es Z; Z mov ax,ds Z mov es,ax Z mov bx,offset param Z ldptr dx,filname,ds ;name of file to exec Z mov ax,04b00H Z int 21h Z mov ss,cs:save_ss Z mov sp,cs:save_sp Z pop es Z pop ds Z jnc noerror Z mov errno_,ax Z mov ax,666 Z jmp short done Znoerror: Z sub ax,ax Zdone: Z pop [02EH] Z pop [030H] Z popf Z pop di Z pop si Z pret Z pend fexec Z finish Z end STUNKYFLUFF set `sum fexec.asm` if test 35466 != $1 then echo fexec.asm: Checksum error. Is: $1, should be: 35466. fi # # echo Extracting fexecv.c: sed 's/^Z//' >fexecv.c <<\STUNKYFLUFF Z#ifdef DEBUG Z#ifndef FILE Z#include <stdio.h> Z#endif Z#include <ctype.h> Z#include <debug.h> Z#endif Z Z Z/* Copyright (C) 1983, 1984 by Manx Software Systems */ Z/* modified by kent williams to employ environment managed in env.c */ Zextern int env_paragraph; Z Zfexecv(path, argv) Zchar *path, **argv; Z{ Z register char *cp, *xp; Z int i; Z char buffer[258]; Z char fcb1[16], fcb2[16]; Z Z cp = buffer+1; Z i = 1; Z if (*argv) { Z ++argv; /* skip arg0, used for unix (tm) compatibility */ Z while (xp = *argv++) { Z if (i == 1) Z fcbinit(xp, fcb1); Z else if (i == 2) Z fcbinit(xp, fcb2); Z while (*xp) { Z if (cp >= buffer+256) Z goto done; Z *cp++ = *xp++; Z } Z *cp++ = ' '; Z ++i; Z } Z } Zdone: Z buffer[0] = cp - (buffer+2); Z /* terminate string */ Z buffer[buffer[0]+1] = 0; Z#ifdef DEBUG Z fprintf(stderr,"\nbuffer[0] = %d\n",buffer[0]); Z for (i = 1; buffer[i] ; i++) Z { Z if (isprint(buffer[i])) Z putchar(buffer[i]); Z else Z fprintf("buffer[%d] = %d\n",i,buffer[i]); Z } Z crlf(); Z#endif Z return fexec(path, env_paragraph, buffer, fcb1, fcb2); Z} Z STUNKYFLUFF set `sum fexecv.c` if test 22589 != $1 then echo fexecv.c: Checksum error. Is: $1, should be: 22589. fi # # echo Extracting fexecvp.c: sed 's/^Z//' >fexecvp.c <<\STUNKYFLUFF Zfexecvp(name, argv) Zchar *name, **argv; Z{ Z register char *cp, *xp; Z int result; Z char *getenv(), path[64]; Z Z if (666 != (result = tryexec("", name, argv))) Z return result; Z if ((cp = getenv("PATH")) != 0) { Z while (*cp) { Z xp = path; Z while (*cp) { Z if (*cp == ';') { Z ++cp; Z break; Z } Z *xp++ = *cp++; Z } Z *xp = 0; Z if (path[0] != 0) Z if (666 != (result = tryexec(path, name, argv))) Z return result; Z } Z } Z return 666; Z} Z Zstatic Ztryexec(dir, name, argv) Zchar *dir, *name, **argv; Z{ Z char newname[64]; Z register char *cp; Z char *rindex(),*index(); Z Z strcpy(newname, dir); Z if (((cp = index(newname, '/')) || (cp = index(newname, '\\'))) Z && *(cp+1) != '\0') Z strcat(newname, "/"); Z strcat(newname, name); Z if (index(name, '.') == 0) { Z strcat(newname, ".com"); Z if (666 != fexecv(newname, argv)) Z return wait(); Z strcpy(rindex(newname,'.'), ".exe"); Z } Z if (666 != fexecv(newname, argv)) Z return wait(); Z return 666; Z} STUNKYFLUFF set `sum fexecvp.c` if test 44134 != $1 then echo fexecvp.c: Checksum error. Is: $1, should be: 44134. fi # # echo Extracting fgrep.c: sed 's/^Z//' >fgrep.c <<\STUNKYFLUFF Z#include <stdio.h> Z#include <fcntl.h> Z Z#include <signal.h> Z#include <setjmp.h> Z Zvoid (*signal())(); Zvoid (*fgrepsig)(); Zjmp_buf fgrep_env; Z Zvoid fgrep_intr() Z{ Z /* restore old signal */ Z signal(SIGINT,fgrepsig); Z /* jump to exit */ Z longjmp(fgrep_env,-1); Z} Z ZFILE *fopen(),*fdopen(); Z Zchar *fgets(); Z Zfgrep( argc, argv ) Zint argc; Zchar * argv[]; Z { Z FILE * fd; Z int rc; Z char * pattern; Z /* handle interrupts */ Z if (-1 == setjmp(fgrep_env)) Z { Z static char *intmsg = "Interrupted\r\n"; Z write(2,intmsg,strlen(intmsg)); Z fclose(fd); Z return -1; Z } Z /* set signal catcher */ Z fgrepsig= signal(SIGINT,fgrep_intr); Z while( --argc ) Z { Z if( (*++argv)[0] == '-' ) Z switch( (*argv)[1] ) Z { Z default: Z fprintf( stderr, "invalid argument %s\n", *argv ); Z return(1); Z } Z else Z break; Z } Z Z if( argc == 0 ) Z { Z fprintf( stderr, "usage: fgrep pattern [file ...]\n" ); Z return(1); Z } Z Z pattern = *argv++; Z argc--; Z Z rc = 0; Z if( argc == 0 ) Z { Z fd = fdopen(0,"r"); Z rc = _fgrep( NULL, pattern, fd); Z fclose(fd); Z return( 0 ); Z } Z else Z while( argc-- ) Z { Z Z if( (fd = fopen( *argv, "r" )) == NULL ) Z fprintf( stderr, "couldn't open %s\n", *argv ); Z else Z { Z rc |= _fgrep( *argv, pattern, fd ); Z fclose( fd ); Z } Z argv++; Z Z } Z Z return( !rc ); Z signal(SIGINT,fgrepsig); Z } Z Z Z_fgrep( file, pattern, fd ) Zchar * file; Zchar * pattern; ZFILE * fd; Z { Z char line[BUFSIZ]; Z int rc; Z int linenumber = 1; Z rc = 0; Z while( fgets( line, sizeof(line), fd ) != NULL ) Z { Z if( rc = match( pattern, line ) ) Z printf( "%s %d: %s", (file) ? file : "stdin", linenumber, line ); Z linenumber++; Z } Z return( rc ); Z Z } Z Zmatch( pattern, line ) Zregister char * pattern; Zchar * line; Z { Z /* not a great algorithm */ Z register char * ptr; Z char * end; Z int plen = strlen(pattern); Z int llen = strlen(line); Z Z if( plen > llen ) Z return( 0 ); Z Z end = line+(llen-plen); Z Z for( ptr=line; ptr < end; ptr++ ) Z { Z if( strncmp( pattern, ptr, plen ) == 0 ) Z return( 1 ); Z } Z Z return( 0 ); Z } STUNKYFLUFF set `sum fgrep.c` if test 15656 != $1 then echo fgrep.c: Checksum error. Is: $1, should be: 15656. fi echo ALL DONE BUNKY! exit 0 -- -- .^. michael regoli /|\ ...ihnp4!inuxc!iuvax!isrnix!mr '|!|` <mr@isrnix.UUCP>
mr@isrnix.UUCP (michael regoli) (12/15/85)
######################################################### # # # This is a shell archive file. To extract files: # # # # 1) Make a directory for the files. # # 2) Write a file, such as "file.shar", containing # # this archive file into the directory. # # 3) Type "sh file.shar". Do not use csh. # # # ######################################################### # # echo Extracting getcmd.c: sed 's/^Z//' >getcmd.c <<\STUNKYFLUFF Z#include <stdio.h> Z#include <fcntl.h> Z Zchar *gets(); Zchar rest[256]; Zchar *rptr = NULL; Zchar pipeactive = 0; Zcurrname = 0; Zchar *pipename[2] = { Z "shtmp1", Z "shtmp2"}; Zchar * Zgetnextcmd(buf) Z char *buf; Z{ Z char *fgets(),*index(),*pipe,*semi; Z if (!rptr) Z { Z register char *c; Z if (0 == read(0,rest,sizeof(rest))) Z return NULL; Z c = rptr = rest; Z while (*c) Z { Z if (*c == '\r' || *c == '\n') Z { Z *c = '\0'; Z break; Z } Z ++c; Z } Z Z } Z pipe = index(rptr,'|'); Z semi = index(rptr,';'); Z if (pipe == NULL && semi == NULL) Z { Z strcpy(buf,rptr); Z if (pipeactive) Z { Z pipeactive = 0; Z strcat(buf," < "); Z strcat(buf,pipename[currname]); Z } Z rptr=NULL; Z } Z /* one or the other, or both are not NULL, so comparison is in order */ Z else if (pipe && (!semi || (pipe < semi))) Z { Z *pipe = '\0'; /* terminate string */ Z strcpy(buf,rptr); /* copy to buf */ Z rptr = pipe+1; /* set up rest */ Z if (pipeactive++) Z { Z pipeactive = 1; Z strcat(buf," < "); Z strcat(buf,pipename[currname]); Z } Z strcat(buf," > "); Z currname ^= 1; /* flip flop pipe names */ Z strcat(buf,pipename[currname]); Z } Z else if (semi && (!pipe || (semi < pipe))) Z /* we have a semicolon to deal with */ Z { Z *semi = '\0'; Z strcpy(buf,rptr); Z rptr = semi+1; Z if (pipeactive) Z { Z pipeactive = 0; Z strcat(buf," < "); Z strcat(buf,pipename[currname]); Z } Z } Z return buf; Z} STUNKYFLUFF set `sum getcmd.c` if test 06449 != $1 then echo getcmd.c: Checksum error. Is: $1, should be: 06449. fi # # echo Extracting invalid.c: sed 's/^Z//' >invalid.c <<\STUNKYFLUFF Z Zinvalid(argc,argv) Z char *argv[]; Z{ Z register int i; Z static char *invmsg = "sh : bad command : "; Z write(2,invmsg,strlen(invmsg)); Z for (i = 0; i < argc;i++) Z { Z write(2,argv[i],strlen(argv[i])); Z write(2," ",1); Z } Z return -1; Z} STUNKYFLUFF set `sum invalid.c` if test 00995 != $1 then echo invalid.c: Checksum error. Is: $1, should be: 00995. fi # # echo Extracting ls.c: sed 's/^Z//' >ls.c <<\STUNKYFLUFF Z#include <stdio.h> Z Ztypedef struct Z{ Z char attribute; Z unsigned file_time; Z unsigned file_date; Z long file_size; Z char file_name[13]; Z} file_desc; Z Ztypedef struct Z{ Z char dos_reserved[21]; Z file_desc file; Z} fcb; Z Z#define maxfiles 128 Z Zchar printbuf[256]; Zfile_desc *getfirst(),*getnext(); Zchar *index(), *rindex(); Zint mode = 0x10; Zint verbose=0,column=4,recurse=0; Zint quiet = 0; Zint drivenum = 0; Zlong time(); Zshort year; Z Zdo_return(result) Z{ Z verbose = quiet = recurse = 0; Z column = 4; Z return result; Z} Z#ifndef MAIN Zls Z#else Zmain Z#endif Z(argc,argv) Zchar *argv[]; Z{ Z int noargs; Z char *current; Z char namebuf[128]; Z /* Z * initialize statics Z */ Z mode = 0x10; Z verbose=0;column=4;recurse=0; Z quiet = 0; Z drivenum = 0; Z /* Z * get current time Z */ Z year = (int)((time(NULL) >> 25) & 0x7F) + 80; Z /* Z * set up a default search name Z */ Z if (noargs = (argc == 1)) Z argc++; Z while(--argc) Z { Z if (noargs) Z current = "*.*"; Z else Z current = *(++argv); /* get current file name */ Z if (*current == '-') Z { Z ++current; /* point past - */ Z while (*current) Z { Z switch (*current++) Z { Z case 'l': Z case 'L': Z verbose = 1; Z if (column != 1) Z column = 2; Z if (quiet) Z { Z fprintf(stderr,"ls : verbose and quiet conflict\n"); Z do_return(-1); Z } Z break; Z case 'q': Z case 'Q': Z quiet = 1; Z if (verbose) Z { Z fprintf(stderr,"ls : quiet and verbose conflict\n"); Z do_return(-1); Z } Z break; Z case 'c': Z case 'C': Z column = 1; Z break; Z case 'a': Z case 'A': Z mode = 0x2 + 0x4 + 0x10; Z break; Z case 'r': Z case 'R': Z recurse = 1; Z mode = 0x2 + 0x4 + 0x10; Z break; Z default: Z break; Z } Z } Z /* if we're down to one argument after looking at all the Z switches, we need to set noargs to true */ Z if (noargs = (argc == 1)) Z argc++; Z continue; Z } Z /* if a drive is specified, figure out what drive it is */ Z if (current[1] == ':') Z { Z drivenum = toupper(current[0]) - 'A' + 1; Z } Z else Z drivenum = 0; Z /* if no wild cards, look for directory and drive names */ Z if ( NULL == index(current,'?') && NULL == index(current,'*')) Z { Z if (getfirst(current)->attribute & 0x10) Z { Z strcpy(namebuf,current); Z strcat(namebuf,"\\*.*"); Z current = namebuf; Z } Z /* look for drive names */ Z else if (current[strlen(current)-1] == ':' && Z !current[strlen(current)]) Z { Z strcpy(namebuf,current); Z strcat(namebuf,"\\*.*"); Z current = namebuf; Z } Z } Z do_dir(current); Z } Z do_return( 0); Z} Z Zdo_dir(current) Z char *current; Z{ Z typedef file_desc fblock[maxfiles]; /* as many as we'll likely need */ Z file_desc *files; Z file_desc *curr_file,*getnext(); Z void *malloc(); Z unsigned int ftime,date; Z int i,j,col; Z int files_cmp(); Z long total = 0; Z char atts[4]; /* drw */ Z /* allocate file block */ Z if (NULL == (files = malloc(sizeof(fblock)))) Z { Z fprintf(stderr,"Not enough memory to do directory\n"); Z return -1; Z } Z /* look for match */ Z i = 0; Z if (!(curr_file = getfirst(current))) Z { Z printf(stderr,"ls : no files matching %s\n",current); Z free(files); Z return; Z } Z files[i++] = *curr_file; Z /* get all matching */ Z while ((curr_file = getnext()) && i < maxfiles) Z files[i++] = *curr_file; Z if (i > 1) Z qsort(files,i,sizeof(file_desc),files_cmp); Z if (!quiet) Z { Z write(1,"\r\n",2); Z write(1,current,strlen(current)); Z write(1,"\r\n",2); Z } Z col = 1; Z for (j = 0; j < i; j++) Z { Z register char *c = files[j].file_name; Z if (*c == '.') Z continue; /* filter out . and .. */ Z while (*c) Z { Z *c = tolower(*c); Z c++; Z } Z if (verbose) Z { Z register char att = files[j].attribute; Z register int fyear; Z fyear = ((files[j].file_date >> 9) & 0x7F)+80; Z atts[3] = 0; /* terminate string */ Z atts[0] = att & 0x10 ? 'd' : '-'; Z atts[1] = att & 2 ? '-' : 'r'; Z atts[2] = att & 1 ? '-' : 'w'; Z if (atts[0] == 'd') Z { Z register int k; Z sprintf(printbuf,"%s %s\\",atts,files[j].file_name); Z write(1,printbuf,strlen(printbuf)); Z k = 12 - strlen(files[j].file_name)+7; Z while(k--) Z write(1," ",1); Z Z } Z else Z { Z total += files[j].file_size; Z sprintf(printbuf,"%s %-12s %-6ld ",atts,files[j].file_name, Z files[j].file_size); Z write(1,printbuf,strlen(printbuf)); Z } Z ftime = files[j].file_time; Z date = files[j].file_date; Z if (year == fyear) Z { Z sprintf(printbuf,"%02d/%02d %02d:%02d ", Z ((date >> 5) & 0x0F), /* month */ Z date & 0x1F, /* day */ Z (ftime >> 11) & 0x1F, /* hours */ Z (ftime >> 5) & 0x3F); /* minutes */ Z write(1,printbuf,strlen(printbuf)); Z } Z else Z { Z sprintf(printbuf,"%02d/%02d ", Z ((date >> 5) & 0x0F), /* month */ Z fyear, /* file year */ Z (ftime >> 11) & 0x1F, /* hours */ Z (ftime >> 5) & 0x3F); /* minutes */ Z write(1,printbuf,strlen(printbuf)); Z } Z } Z else Z { Z if (files[j].attribute & 0x10) Z { Z register int k; Z sprintf(printbuf,"%s\\",files[j].file_name); Z write(1,printbuf,strlen(printbuf)); Z k = 16 - strlen(files[j].file_name); Z while(--k) Z write(1," ",1); Z Z } Z else Z { Z sprintf(printbuf,"%-13s ",files[j].file_name); Z write(1,printbuf,strlen(printbuf)); Z } Z } Z if (col == column) Z { Z col = 1; Z write(1,"\r\n",2); Z } Z else Z col++; Z } Z write(1,"\r\n",2); Z if (verbose) Z { Z sprintf(printbuf,"%ld bytes in %d files ",total,i); Z write(1,printbuf,strlen(printbuf)); Z pr_freespace(); Z } Z if (recurse) Z for (j = 0; j < i; j++) Z { Z /* we've got a subdirectory */ Z if (files[j].attribute & 0x10 && files[j].file_name[0] != '.') Z { Z char *path; Z char dirname[48]; Z if (!strcmp(current,"*.*")) Z dirname[0] = '\0'; Z else Z strcpy(dirname,current); Z if (path = rindex(dirname,'\\')) Z *(++path) = '\0'; Z strcat(dirname,files[j].file_name); /* get name */ Z strcat(dirname,"\\*.*"); Z do_dir(dirname); Z } Z } Z free(files); Z} Z Zfiles_cmp(a,b) Z file_desc *a,*b; Z{ Z return strcmp(a->file_name,b->file_name); Z} Z Zfcb tmp; Z Zfile_desc *getfirst(fname) Z char *fname; Z{ Z register int result; Z /* set the disk transfer address */ Z bdos(0x1A,&tmp); Z result = bdos(0x4E,fname,mode); Z /* make the find first call */ Z if(2 == result || 18 == result) Z return NULL; Z return &(tmp.file); Z} Z Zfile_desc *getnext() Z{ Z register int result; Z /* set the disk transfer address */ Z bdos(0x1A,&tmp); Z result = bdos(0x4f,0,0); Z /* make the find next call */ Z if (18 == result) Z return NULL; Z return &(tmp.file); Z} Z Z/* determine available space on default drive Z*/ Z Zpr_freespace() Z{ Z /* register arguments for INT */ Z struct {int ax,bx,cx,dx,si,di,ds,es;}sysr; Z unsigned int retstat; /* flags returned from INT */ Z Z#define cls_avail sysr.bx /* number of available clusters */ Z#define cls_total sysr.dx /* total number of clusters on volume */ Z#define byt_sectr sysr.cx /* bytes per sector */ Z#define sec_clstr sysr.ax /* sectors per cluster */ Z Z unsigned long byt_clstr, /* bytes per cluster */ Z vol_total, /* total size of volume, bytes */ Z fre_total; /* size of free space, bytes */ Z Z sysr.ax = 0x3600; /* get disk free space function code */ Z sysr.dx = drivenum; /* (DL) = drive id, 0=current, 1=A, */ Z retstat = sysint(0x21,&sysr,&sysr); /* invoke DOS */ Z if( sec_clstr!=0xffff ) Z { Z byt_clstr = byt_sectr * sec_clstr; Z vol_total = cls_total * byt_clstr; Z fre_total = cls_avail * byt_clstr; Z fprintf(stdout, Z "%lu out of %lu bytes available on %c:\n", Z fre_total,vol_total, Z drivenum ? drivenum + 'A' - 1 : bdos(0x19,0,0)+'A'); Z } Z} STUNKYFLUFF set `sum ls.c` if test 06358 != $1 then echo ls.c: Checksum error. Is: $1, should be: 06358. fi # # echo Extracting main.c: sed 's/^Z//' >main.c <<\STUNKYFLUFF Z#line 1 "main.s" Z#include <stdio.h> Z#include <ctype.h> Z#include <signal.h> Z#include <fcntl.h> Z#include <setjmp.h> Ztypedef struct /* used to find builtin commands */ Z{ Z char *cmdname; Z int (*func)(); Z} builtin; Z Zextern builtin commands[]; Zextern char histerr[]; Zextern int j,hiscount; Zextern char *history[]; Zextern int histsize; Zextern int numcmds; Zstatic int quiet = 0; Z Zchar *version = "SHELL VERSION 1.2 Kent Williams"; Z Zjmp_buf env; Z Zchar *pipename[] = Z{ Z "\\shtmp1", Z "\\shtmp2" Z}; Z Zchar cmdbuf[512]; Zint currname = 0; Zint result = 0; Z Zmain(argc,argv) Z char *argv[]; Z{ Z signal(SIGINT,SIG_IGN); /* ignore breaks */ Z Z quiet = !isatty(0); /* quiet = batch shell */ Z Z /* initialize local environment */ Z init_env(); Z cli(); Z exit(0); Z} Z Z#ifndef SNODEBUG Z#define SNODEBUG Z#endif Z#line 46 "main.s" Z Z/* Z * statemachine cli Z */ Zcli () Z Z#line 48 "main.s" Z{ Z#line 49 "main.s" Z/* global variables */ Z int i; Z int repeat, state, inpipe = 0; Z static char localbuf[256]; Z static char histbuf[256]; Z static char tail[256]; Z int histindex,argindex,takeline; Z char *local = localbuf; Z char *current,*curr_save; Z char *ntharg(), *argptr; Z char *savestr(); Z Z Z/* Z * end of declarations for cli Z */ Z/* $ */ goto getline; Z#line 62 "main.s" Z Zgetline: Z{ Z#line 62 "main.s" Z /* kill tmp files */ Z unlink(pipename[0]); unlink(pipename[1]); Z Z hiscount = j % histsize; /* hiscount is current position in history */ Z if(!quiet) Z fprintf(stderr,"%d%% ",j); Z Z/* Z * The following code simply reads a line from standard input. Z * It is so complicated because when you save the standard stream Z * files and execute another program/command, standard input is Z * left in an uncertain state - the FILE stdin seems to be at EOF, Z * even when standard input is associated with the console, and Z * cr/lf combinations show up as line terminators, whereas usually Z * only linefeeds get placed in the input stream. Z * WHY? beats me. Something could be wrong with Z * 1. AZTEC C runtime Z * 2. PCDOS Z * 3. Me Z * 4. All three, or permutations of 1-3 reducto ad absurdum. Z * All I know is this works Z */ Z /* clear command buffer so string read is null terminated */ Z setmem(cmdbuf,sizeof(cmdbuf),0); Z for (current = cmdbuf;;current++) Z { Z int readresult; Z if ((readresult = read(0,current,1)) == 0 || Z readresult == -1) Z { Z/* $ */ goto terminal; Z } Z if (*current == '\r') Z { Z if ((readresult = read(0,current,1)) == 0 || Z readresult == -1) Z { Z/* $ */ goto terminal; Z } Z *current = '\0'; Z break; Z } Z else if (*current == '\n') Z { Z *current = '\0'; /* terminate string */ Z break; Z } Z } Z current = cmdbuf; /* point current at start of buffer */ Z/* Z * end of input weirdness Z */ Z /* if we're recycling history strings, free previous one */ Z if (history[hiscount]) Z free(history[hiscount]); Z Z /* save current in history array */ Z history[hiscount] = savestr(current); Z /* parse command for compound statements and pipes */ Z local = localbuf; /* set pointer to state of buffer */ Z setmem(localbuf,sizeof(localbuf),0); /* clear buffer */ Z/* $ */ goto eatwhitespace; Z Z#ifndef SNODEBUG Zgoto badstate; Z#endif Z/* Z * $endstate getline Z */ Z}; Z#line 125 "main.s" Z Z Zcharstate: Z{ Z#line 127 "main.s" Z switch(*current) Z { Z case '\0': Z *local = '\0'; Z current++; Z/* $ */ goto emit; Z case '"' : Z *local++ = *current++; Z/* $ */ goto doublequotes; Z case '/' : Z *local++ = '\\'; Z current++; Z/* $ */ goto charstate;; Z case '\'': Z *local++ = *current++; Z/* $ */ goto singlequotes; Z case '\\': Z *local++ = *++current; Z current++; Z/* $ */ goto charstate; Z case ';': Z *local = '\0'; Z current++; Z/* $ */ goto compound; Z case '|': Z *local = '\0'; Z current++; Z/* $ */ goto pipe; Z case '!': Z current++; Z/* $ */ goto histstate; Z default: Z *local++ = *current++; Z/* $ */ goto charstate; Z } Z Z#ifndef SNODEBUG Zgoto badstate; Z#endif Z/* Z * $endstate charstate Z */ Z}; Z#line 163 "main.s" Z Z Zemit: Z{ Z#line 165 "main.s" Z if (inpipe) Z { Z inpipe = 0; Z strcat(localbuf," < "); Z strcat(localbuf,pipename[currname]); Z } Z command(localbuf); Z/* $ */ goto done; Z Z#ifndef SNODEBUG Zgoto badstate; Z#endif Z/* Z * $endstate emit Z */ Z}; Z#line 174 "main.s" Z Z Zcompound: Z{ Z#line 176 "main.s" Z if (inpipe) Z { Z inpipe = 0; Z strcat(localbuf," < "); Z strcat(localbuf,pipename[currname]); Z } Z command(localbuf); Z local = localbuf; Z setmem(localbuf,sizeof(localbuf),0); /* clear buffer */ Z/* $ */ goto eatwhitespace; Z Z#ifndef SNODEBUG Zgoto badstate; Z#endif Z/* Z * $endstate compound Z */ Z}; Z#line 187 "main.s" Z Z Zsinglequotes: Z{ Z#line 189 "main.s" Z switch (*current) Z { Z case '\0': Z write(2,"No closing quotes!!\r\n",21); Z/* $ */ goto parserr; Z case '\'': Z *local++ = *current++; Z/* $ */ goto charstate; Z default: Z *local++ = *current++; Z/* $ */ goto singlequotes; Z } Z Z#ifndef SNODEBUG Zgoto badstate; Z#endif Z/* Z * $endstate singlequotes Z */ Z}; Z#line 202 "main.s" Z Z Zdoublequotes: Z{ Z#line 204 "main.s" Z switch(*current) Z { Z case '\0': Z write(2,"No closing quotes!!\r\n",21); Z/* $ */ goto done; Z case '"': Z *local++ = *current++; Z/* $ */ goto charstate; Z default: Z *local++ = *current++; Z/* $ */ goto doublequotes; Z } Z Z#ifndef SNODEBUG Zgoto badstate; Z#endif Z/* Z * $endstate doublequotes Z */ Z}; Z#line 217 "main.s" Z Z Zhiststate: Z{ Z#line 219 "main.s" Z /* handle history substitutions */ Z setmem(histbuf,sizeof(histbuf),0); /* clear buffer */ Z Z /* save current pointer into command buffer */ Z curr_save = current; Z Z /* copy command head */ Z strncpy(histbuf,cmdbuf,(int)(current-cmdbuf)-1); Z Z /* takeline means take all arguments past current one */ Z takeline = 0; Z Z /* parse history expression */ Z switch (*current) Z { Z case '!': /* last command line */ Z if (j) /* special case first time through */ Z { Z histindex = hiscount ? hiscount - 1 : histsize - 1; Z } Z else Z { Z /* force error condition */ Z write(2,histerr,strlen(histerr)); Z/* $ */ goto parserr; Z } Z current++; /* point to next */ Z break; Z case '-': /* negative (relative #) */ Z /* a particular numbered command */ Z case '0': Z case '1': Z case '2': Z case '3': Z case '4': Z case '5': Z case '6': Z case '7': Z case '8': Z case '9': Z /* repeat numbered command */ Z repeat = atoi(current); Z if (repeat < 0) /* handle relative addressing */ Z repeat += j; Z Z /* if command is within range */ Z if ((j - repeat) <= histsize && repeat < j) Z { Z histindex = repeat % histsize; Z } Z else Z { Z/* $ */ goto parserr; Z } Z Z /* skip past numeric expression */ Z while(isdigit(*current)||*current=='-') Z ++current; Z break; Z default: Z write(2,"Bad history expression\r\n",24); Z/* $ */ goto parserr; Z } Z /* look for particular argument substitutions */ Z switch (*current) Z { Z /* we want the whole enchilada */ Z case '\0': Z case '\t': Z case '\r': Z case '\n': Z case ' ': Z strcat(histbuf,history[histindex]); Z break; Z case ':': Z ++current; /* point past colon */ Z switch (*current) Z { Z case '^': Z argindex = 1; Z ++current; Z break; Z case '0': Z case '1': Z case '2': Z case '3': Z case '4': Z case '5': Z case '6': Z case '7': Z case '8': Z case '9': Z /* index of argument */ Z argindex = atoi(current); Z while(isdigit(*current)) Z ++current; Z if (*current == '*') Z { Z takeline = 1; Z current++; Z } Z break; Z case '$': Z argindex = lastarg(history[histindex]); Z current++; Z break; Z case '*': Z takeline = 1; /* take arg 1 through arg n */ Z argindex = 1; Z current++; Z break; Z default: Z/* $ */ goto parserr; Z } Z /* pick up pointer to argument in history we need */ Z if (takeline == 0) Z { Z if (NULL == Z (argptr = ntharg(history[histindex],argindex))) Z { Z/* $ */ goto parserr; Z } Z strcat(histbuf,argptr); Z } Z else Z { Z while (NULL != Z (argptr = ntharg(history[histindex],argindex++))) Z { Z strcat(histbuf,argptr); Z strcat(histbuf," "); Z } Z } Z } Z /* history substitutions */ Z /* copy command buffer tail to tail buffer */ Z strcpy(tail,current); Z /* copy histbuf back to cmdbuf */ Z strcpy(cmdbuf,histbuf); Z /* point current at history substitution to continue parsing */ Z current = --curr_save; /* -1 to backup over first ! */ Z /* copy tail in */ Z strcat(cmdbuf,tail); Z free(history[hiscount]); Z history[hiscount] = savestr(cmdbuf); Z/* $ */ goto charstate; Z Z#ifndef SNODEBUG Zgoto badstate; Z#endif Z/* Z * $endstate histstate Z */ Z}; Z#line 366 "main.s" Z Z Zpipe: Z{ Z#line 368 "main.s" Z if (inpipe++) Z { Z inpipe = 1; Z strcat(localbuf," < "); Z strcat(localbuf,pipename[currname]); Z } Z strcat(localbuf," > "); Z currname ^= 1; Z strcat(localbuf,pipename[currname]); Z command(localbuf); Z local = localbuf; Z setmem(localbuf,sizeof(localbuf),0); Z/* $ */ goto eatwhitespace; Z Z#ifndef SNODEBUG Zgoto badstate; Z#endif Z/* Z * $endstate pipe Z */ Z}; Z#line 382 "main.s" Z Z Zeatwhitespace: Z{ Z#line 384 "main.s" Z/* strip out leading white space */ Zwhile(isspace(*current)) Z current++; Z if (!*current) Z/* $ */ goto parserr; Z else Z/* $ */ goto charstate; Z Z#ifndef SNODEBUG Zgoto badstate; Z#endif Z/* Z * $endstate eatwhitespace Z */ Z}; Z#line 392 "main.s" Z Z Zparserr: Z{ Z#line 394 "main.s" Z/* $ */ goto getline; Z Z#ifndef SNODEBUG Zgoto badstate; Z#endif Z/* Z * $endstate parserr Z */ Z}; Z#line 396 "main.s" Z Z Zdone: Z{ Z#line 398 "main.s" Z j++; /* next command # */ Z/* $ */ goto getline; Z Z#ifndef SNODEBUG Zgoto badstate; Z#endif Z/* Z * $endstate done Z */ Z}; Z#line 401 "main.s" Z Z Z/* Z * BAD STATE LABEL Z */ Zbadstate: Z Z fprintf(stderr,"Fallen off end of a state!!!\n"); Z Z return -1; Z Z/* Z * TERMINAL STATE LABEL Z */ Zterminal: Z Z return 0; Z Z/* Z * end of state machine cli Z */ Z} Z Zonintr() Z{ Z longjmp(env,-1); Z} Z Zcommand(current) Z register char *current; Z{ Z extern do_prog(); Z register int i; Z std_save(); Z if (-1 == (i = findcmd(current))) Z { Z ctl_brk_setup(); Z result = _Croot(current,do_prog); Z ctl_brk_restore(); Z } Z else Z { Z if (-1 != setjmp(env)) Z { Z signal(SIGINT,onintr); Z result = _Croot(current,commands[i].func); Z } Z signal(SIGINT,SIG_IGN); Z } Z std_restore(); Z} Z Zchar * Zntharg(line,index) Zregister char *line; Z{ Z register int i; Z static char buf[64]; Z char *bptr; Z for (i = 0; *line;i++) Z { Z /* find start of arg[i] */ Z while(*line && isspace(*line)) Z { Z ++line; Z } Z /* if this is start of requested arg, return pointer to it */ Z if (i == index) Z { Z bptr = buf; Z while(*line && !isspace(*line)) Z *bptr++ = *line++; Z *bptr = '\0'; Z return buf; Z } Z /* find end of arg[i] */ Z while(*line && !isspace(*line)) Z ++line; Z } Z return NULL; Z} Z Zlastarg(line) Zregister char *line; Z{ Z register int i; Z Z for (i = 0; *line;i++) Z { Z /* find start of arg[i] */ Z while(*line && isspace(*line)) Z ++line; Z /* find end of arg[i] */ Z while(*line && !isspace(*line)) Z ++line; Z } Z return i-1; Z} STUNKYFLUFF set `sum main.c` if test 41066 != $1 then echo main.c: Checksum error. Is: $1, should be: 41066. fi # # echo Extracting main.s: sed 's/^Z//' >main.s <<\STUNKYFLUFF Z#include <stdio.h> Z#include <ctype.h> Z#include <signal.h> Z#include <fcntl.h> Z#include <setjmp.h> Ztypedef struct /* used to find builtin commands */ Z{ Z char *cmdname; Z int (*func)(); Z} builtin; Z Zextern builtin commands[]; Zextern char histerr[]; Zextern int j,hiscount; Zextern char *history[]; Zextern int histsize; Zextern int numcmds; Zstatic int quiet = 0; Z Zchar *version = "SHELL VERSION 1.1 Kent Williams"; Z Zjmp_buf env; Z Zchar *pipename[] = Z{ Z "\\shtmp1", Z "\\shtmp2" Z}; Z Zchar cmdbuf[512]; Zint currname = 0; Zint result = 0; Z Zmain(argc,argv) Z char *argv[]; Z{ Z signal(SIGINT,SIG_IGN); /* ignore breaks */ Z Z quiet = !isatty(0); /* quiet = batch shell */ Z Z /* initialize local environment */ Z init_env(); Z cli(); Z exit(0); Z} Z$nodebug /* turn off state machine debugging */ Z$machine cli getline () Z$endargs Z/* global variables */ Z int i; Z int repeat, state, inpipe = 0; Z static char localbuf[256]; Z static char histbuf[256]; Z static char tail[256]; Z int histindex,argindex,takeline; Z char *local = localbuf; Z char *current,*curr_save; Z char *ntharg(), *argptr; Z char *savestr(); Z Z$state getline Z /* kill tmp files */ Z unlink(pipename[0]); unlink(pipename[1]); Z Z hiscount = j % histsize; /* hiscount is current position in history */ Z if(!quiet) Z fprintf(stderr,"%d%% ",j); Z Z/* Z * The following code simply reads a line from standard input. Z * It is so complicated because when you save the standard stream Z * files and execute another program/command, standard input is Z * left in an uncertain state - the FILE stdin seems to be at EOF, Z * even when standard input is associated with the console, and Z * cr/lf combinations show up as line terminators, whereas usually Z * only linefeeds get placed in the input stream. Z * WHY? beats me. Something could be wrong with Z * 1. AZTEC C runtime Z * 2. PCDOS Z * 3. Me Z * 4. All three, or permutations of 1-3 reducto ad absurdum. Z * All I know is this works Z */ Z /* clear command buffer so string read is null terminated */ Z setmem(cmdbuf,sizeof(cmdbuf),0); Z for (current = cmdbuf;;current++) Z { Z int readresult; Z if ((readresult = read(0,current,1)) == 0 || Z readresult == -1) Z { Z $nextstate terminal Z } Z if (*current == '\r') Z { Z if ((readresult = read(0,current,1)) == 0 || Z readresult == -1) Z { Z $nextstate terminal Z } Z *current = '\0'; Z break; Z } Z else if (*current == '\n') Z { Z *current = '\0'; /* terminate string */ Z break; Z } Z } Z current = cmdbuf; /* point current at start of buffer */ Z/* Z * end of input weirdness Z */ Z /* if we're recycling history strings, free previous one */ Z if (history[hiscount]) Z free(history[hiscount]); Z Z /* save current in history array */ Z history[hiscount] = savestr(current); Z /* parse command for compound statements and pipes */ Z local = localbuf; /* set pointer to state of buffer */ Z setmem(localbuf,sizeof(localbuf),0); /* clear buffer */ Z $nextstate eatwhitespace Z$endstate getline Z Z$state charstate Z switch(*current) Z { Z case '\0': Z *local = '\0'; Z current++; Z $nextstate emit Z case '"' : Z *local++ = *current++; Z $nextstate doublequotes Z case '/' : Z *local++ = '\\'; Z current++; Z $nextstate charstate; Z case '\'': Z *local++ = *current++; Z $nextstate singlequotes Z case '\\': Z *local++ = *++current; Z current++; Z $nextstate charstate Z case ';': Z *local = '\0'; Z current++; Z $nextstate compound Z case '|': Z *local = '\0'; Z current++; Z $nextstate pipe Z case '!': Z current++; Z $nextstate histstate Z default: Z *local++ = *current++; Z $nextstate charstate Z } Z$endstate charstate Z Z$state emit Z if (inpipe) Z { Z inpipe = 0; Z strcat(localbuf," < "); Z strcat(localbuf,pipename[currname]); Z } Z command(localbuf); Z $nextstate done Z$endstate emit Z Z$state compound Z if (inpipe) Z { Z inpipe = 0; Z strcat(localbuf," < "); Z strcat(localbuf,pipename[currname]); Z } Z command(localbuf); Z local = localbuf; Z setmem(localbuf,sizeof(localbuf),0); /* clear buffer */ Z $nextstate eatwhitespace Z$endstate compound Z Z$state singlequotes Z switch (*current) Z { Z case '\0': Z write(2,"No closing quotes!!\r\n",21); Z $nextstate parserr Z case '\'': Z *local++ = *current++; Z $nextstate charstate Z default: Z *local++ = *current++; Z $nextstate singlequotes Z } Z$endstate singlequotes Z Z$state doublequotes Z switch(*current) Z { Z case '\0': Z write(2,"No closing quotes!!\r\n",21); Z $nextstate done Z case '"': Z *local++ = *current++; Z $nextstate charstate Z default: Z *local++ = *current++; Z $nextstate doublequotes Z } Z$endstate doublequotes Z Z$state histstate Z /* handle history substitutions */ Z setmem(histbuf,sizeof(histbuf),0); /* clear buffer */ Z Z /* save current pointer into command buffer */ Z curr_save = current; Z Z /* copy command head */ Z strncpy(histbuf,cmdbuf,(int)(current-cmdbuf)-1); Z Z /* takeline means take all arguments past current one */ Z takeline = 0; Z Z /* parse history expression */ Z switch (*current) Z { Z case '!': /* last command line */ Z if (j) /* special case first time through */ Z { Z histindex = hiscount ? hiscount - 1 : histsize - 1; Z } Z else Z { Z /* force error condition */ Z write(2,histerr,strlen(histerr)); Z $nextstate parserr Z } Z current++; /* point to next */ Z break; Z case '-': /* negative (relative #) */ Z /* a particular numbered command */ Z case '0': Z case '1': Z case '2': Z case '3': Z case '4': Z case '5': Z case '6': Z case '7': Z case '8': Z case '9': Z /* repeat numbered command */ Z repeat = atoi(current); Z if (repeat < 0) /* handle relative addressing */ Z repeat += j; Z Z /* if command is within range */ Z if ((j - repeat) <= histsize && repeat < j) Z { Z histindex = repeat % histsize; Z } Z else Z { Z $nextstate parserr Z } Z Z /* skip past numeric expression */ Z while(isdigit(*current)||*current=='-') Z ++current; Z break; Z default: Z write(2,"Bad history expression\r\n",24); Z $nextstate parserr Z } Z /* look for particular argument substitutions */ Z switch (*current) Z { Z /* we want the whole enchilada */ Z case '\0': Z case '\t': Z case '\r': Z case '\n': Z case ' ': Z strcat(histbuf,history[histindex]); Z break; Z case ':': Z ++current; /* point past colon */ Z switch (*current) Z { Z case '^': Z argindex = 1; Z ++current; Z break; Z case '0': Z case '1': Z case '2': Z case '3': Z case '4': Z case '5': Z case '6': Z case '7': Z case '8': Z case '9': Z /* index of argument */ Z argindex = atoi(current); Z while(isdigit(*current)) Z ++current; Z if (*current == '*') Z { Z takeline = 1; Z current++; Z } Z break; Z case '$': Z argindex = lastarg(history[histindex]); Z current++; Z break; Z case '*': Z takeline = 1; /* take arg 1 through arg n */ Z argindex = 1; Z current++; Z break; Z default: Z $nextstate parserr Z } Z /* pick up pointer to argument in history we need */ Z if (takeline == 0) Z { Z if (NULL == Z (argptr = ntharg(history[histindex],argindex))) Z { Z $nextstate parserr Z } Z strcat(histbuf,argptr); Z } Z else Z { Z while (NULL != Z (argptr = ntharg(history[histindex],argindex++))) Z { Z strcat(histbuf,argptr); Z strcat(histbuf," "); Z } Z } Z } Z /* history substitutions */ Z /* copy command buffer tail to tail buffer */ Z strcpy(tail,current); Z /* copy histbuf back to cmdbuf */ Z strcpy(cmdbuf,histbuf); Z /* point current at history substitution to continue parsing */ Z current = --curr_save; /* -1 to backup over first ! */ Z /* copy tail in */ Z strcat(cmdbuf,tail); Z free(history[hiscount]); Z history[hiscount] = savestr(cmdbuf); Z $nextstate charstate Z$endstate histstate Z Z$state pipe Z if (inpipe++) Z { Z inpipe = 1; Z strcat(localbuf," < "); Z strcat(localbuf,pipename[currname]); Z } Z strcat(localbuf," > "); Z currname ^= 1; Z strcat(localbuf,pipename[currname]); Z command(localbuf); Z local = localbuf; Z setmem(localbuf,sizeof(localbuf),0); Z $nextstate eatwhitespace Z$endstate pipe Z Z$state eatwhitespace Z/* strip out leading white space */ Zwhile(isspace(*current)) Z current++; Z if (!*current) Z $nextstate parserr Z else Z $nextstate charstate Z$endstate eatwhitespace Z Z$state parserr Z $nextstate getline Z$endstate parserr Z Z$state done Z j++; /* next command # */ Z $nextstate getline Z$endstate done Z Z$endmachine cli Z Zonintr() Z{ Z longjmp(env,-1); Z} Z Zcommand(current) Z register char *current; Z{ Z extern do_prog(); Z register int i; Z std_save(); Z if (-1 == (i = findcmd(current))) Z { Z ctl_brk_setup(); Z result = _Croot(current,do_prog); Z ctl_brk_restore(); Z } Z else Z { Z if (-1 != setjmp(env)) Z { Z signal(SIGINT,onintr); Z result = _Croot(current,commands[i].func); Z } Z signal(SIGINT,SIG_IGN); Z } Z std_restore(); Z} Z Zchar * Zntharg(line,index) Zregister char *line; Z{ Z register int i; Z static char buf[64]; Z char *bptr; Z for (i = 0; *line;i++) Z { Z /* find start of arg[i] */ Z while(*line && isspace(*line)) Z { Z ++line; Z } Z /* if this is start of requested arg, return pointer to it */ Z if (i == index) Z { Z bptr = buf; Z while(*line && !isspace(*line)) Z *bptr++ = *line++; Z *bptr = '\0'; Z return buf; Z } Z /* find end of arg[i] */ Z while(*line && !isspace(*line)) Z ++line; Z } Z return NULL; Z} Z Zlastarg(line) Zregister char *line; Z{ Z register int i; Z Z for (i = 0; *line;i++) Z { Z /* find start of arg[i] */ Z while(*line && isspace(*line)) Z ++line; Z /* find end of arg[i] */ Z while(*line && !isspace(*line)) Z ++line; Z } Z return i-1; Z} STUNKYFLUFF set `sum main.s` if test 47403 != $1 then echo main.s: Checksum error. Is: $1, should be: 47403. fi # # echo Extracting makefile: sed 's/^Z//' >makefile <<\STUNKYFLUFF Z# home for all commands ZBINDIR=\\bin\\ Z# small model library path ZCLIB=-l/clibs/c Z Z# source files for shell Zshsrc=main.c cd.c cp.c doprog.c fexecvp.c more.c cmds.c chmod.c y.c fexec.asm \ Zinvalid.c ls.c pushd.c fgrep.c md.c mv.c pwd.c rm.c crlf.c drive.c dump2.c \ Zrmdir.c savestr.c stdsave.c touch.c _croot.c env.c fexecv.c cat.c echo.c \ Zcmdlist.c ctlbrk.asm mvcp.c Z Z# object files for shell Zshobj=main.o cd.o cp.o doprog.o fexecvp.o more.o cmds.o chmod.o y.o fexec.o \ Zinvalid.o ls.o pushd.o fgrep.o md.o mv.o pwd.o rm.o crlf.o drive.o dump2.o \ Zrmdir.o savestr.o stdsave.o touch.o _croot.o env.o fexecv.o cat.o echo.o \ Zcmdlist.o ctlbrk.o mvcp.o Z Zmain.c : main.s Z statecom main Z Z# Z# make shell - check currency of all percursors, link and then move to Z# bin directory Z# Zshell.exe : $(shobj) Z ln -t -o $@ -f shell.lnk Z \\atron\\aztoat <shell.sym >shell.map Z chmod +w $(BINDIR)$@ Z mv $@ $(BINDIR)$@ Z chmod -w $(BINDIR)$@ Z Z# Z# make entries to produce stand-alone versions of shell builtins Z# Zchmod.com : Z cc -dMAIN $* Z ln -o $@ $*.o -l/clibs/c Z rm $*.o Z chmod +w $(BINDIR)chmod.com Z mv chmod.com $(BINDIR)chmod.com Z chmod -w $(BINDIR)chmod.com Z Zmore.com : Z cc -dMAIN $* Z ln -o $@ $*.o -l/clibs/s -l/clibs/c Z rm $*.o Z chmod +w $(BINDIR)$@ Z mv $@ $(BINDIR)$@ Z chmod -w $(BINDIR)$@ Z Zmv.com : croot.o savestr.o mvcp.o Z cc -dMAIN $* Z ln -o $@ $*.o savestr.o croot.o mvcp.o -l/clibs/c Z rm $*.o Z chmod +w $(BINDIR)$@ Z mv $@ $(BINDIR)$@ Z chmod -w $(BINDIR)$@ Z Zcp.com : croot.o savestr.o mvcp.o Z cc -dMAIN $* Z ln -o $@ $*.o savestr.o croot.o mvcp.o -l/clibs/c Z rm $*.o Z chmod +w $(BINDIR)$@ Z mv $@ $(BINDIR)$@ Z chmod -w $(BINDIR)$@ Z Zls.com : Z cc -dMAIN $* Z ln -o $@ $*.o -l/clibs/c Z rm $*.o Z chmod +w $(BINDIR)$@ Z mv $@ $(BINDIR)$@ Z chmod -w $(BINDIR)$@ Zeditall : Z z $(shsrc) Zclean : Z rm *.o *.bak *.sym STUNKYFLUFF set `sum makefile` if test 36319 != $1 then echo makefile: Checksum error. Is: $1, should be: 36319. fi # # echo Extracting md.c: sed 's/^Z//' >md.c <<\STUNKYFLUFF Zmd(argc,argv) Z char *argv[]; Z{ Z if (-1 == mkdir(*(++argv))) Z { Z perror("mkdir"); Z return -1; Z } Z return 0; Z} STUNKYFLUFF set `sum md.c` if test 21756 != $1 then echo md.c: Checksum error. Is: $1, should be: 21756. fi # # echo Extracting more.c: sed 's/^Z//' >more.c <<\STUNKYFLUFF Z#include <stdio.h> Z#include <sgtty.h> Z#include <debug.h> Z#include <ctype.h> Z#include <setjmp.h> Z#include <signal.h> Zvoid (*signal())(); Zvoid (*moresig)(); ZFILE *fdopen(); Z Zlong int size, position; Zchar filename[30]; Zchar isaconsole = '\0'; Zchar isapipe = '\0'; Zint tabsize = 8; Z#define STDIN 0 Z#define STDOUT 1 Z#define STDERR 2 Z#define ESC '\033' Z#define IBMPC /* display code dependent on PC hardware/bios */ Z#ifdef IBMPC Zextern void scr_putc(); Z#endif Zvoid std_out(c) Z{ Z write(1,&c,1); Z} Zvoid (*output)(); Z#ifdef MAIN Zcrlf() Z{ Z write(2,"\r\n",2); Z} Z#endif Zjmp_buf moreenv; Zmoreintr() Z{ Z signal(SIGINT,SIG_IGN); /* ignore signals until we finish putting stuff Z back in order */ Z longjmp(moreenv,-1); Z} Z#ifdef MAIN Zmain Z#else Zmore Z#endif Z(argc,argv) Z int argc; Z char *argv[]; Z{ Z FILE *fp, *fopen(); Z long ftell(); Z long int i; Z long int fsize(); Z Z if (-1 == setjmp(moreenv)) Z { Z write(2,"Interrupted\r\n",13); Z fclose(fp); Z signal(SIGINT,moresig); Z return -1; Z } Z Z moresig = signal(SIGINT,moreintr); Z isaconsole = isatty(STDOUT); Z isapipe = !isatty(STDIN); Z#ifdef IBMPC Z if (isaconsole) Z { Z output = scr_putc; Z scr_echo(0); Z } Z else Z#endif Z output = std_out; Z if ( (*(++argv))[0] == '-' && isdigit((*argv)[1]) ) Z { Z tabsize = atoi( (*argv+1) ); Z --argc; Z } else Z { Z --argv; Z } Z if (argc == 1) Z { Z if (NULL == (fp = fdopen(0,"r"))) Z { Z return -1; Z } Z display(fp); Z crlf(); Z return 0; Z } Z while(--argc) Z { Z if (NULL == (fp = fopen(*(++argv),"r")) ) Z { Z fprintf(stderr,"more - can't open %s\n",*argv); Z continue; Z } Z strncpy(filename,*argv,30); Z if (filename[29]) Z filename[29] = '\0'; Z if (!isapipe) Z size = fsize(fp); Z position = 0; Z if (-2 == display(fp)) Z argc = 0; /* force completion of command */ Z fclose(fp); Z } Zbugout: Z#ifdef IBMPC Z if (isaconsole) Z scr_echo(0); Z#endif Z crlf(); Z tabsize = 8; Z isaconsole = isapipe = '\0'; Z signal(SIGINT,moresig); Z return 0; Z} Z Zlong fsize(fp) Z FILE *fp; Z{ Z long ftell(); Z long position, last; Z position = ftell(fp); Z if (-1 == fseek(fp,0L,2)) Z { Z fprintf(stderr,"more - error on fseek\n"); Z } Z last = (ftell(fp)); Z fseek(fp,position,0); Z return last; Z} Z#define LBUFSIZE 160 Zchar linebuffer[LBUFSIZE]; Zint lines; Z Zdisplay(fp) Z FILE *fp; Z{ Z FILE *fgets(); Z long ftell(); Z char c; Z lines = 1; Z while ( NULL != fgets(linebuffer,LBUFSIZE,fp)) Z { Z if (isaconsole) Z { Z if (lines == 1) /* top of display */ Z { Z#ifdef IBMPC Z scr_clear(); Z#else Z/* ansi terminal screen clear */ Z printf("%c[2J",ESC); /* clear display */ Z#endif Z } Z } Z lines += localputs(linebuffer); Z if (isaconsole) Z { Z if (lines >= 24) /* bottome of display */ Z { Z char tst; Z position = ftell(fp); Z#ifdef IBMPC Z scr_curs(24,0); Z#else Z/* ansi terminal positioning */ Z printf("%c[25;1H%c[7m",ESC,ESC); Z#endif Z if (!isapipe) Z#ifdef IBMPC Z scr_printf( Z#else Z fprintf(stderr, Z#endif Z "%s - %ld bytes - %d%% displayed - <ESC> = skip to next file", Z filename,size,percent(position,size) ); Z else Z#ifdef IBMPC Z scr_printf( Z#else Z fprintf(stderr, Z#endif Z "-more-"); Z switch (bdos(7,0,0)) /* get a character no echo */ Z { Z case ESC : Z return 0; Z case 3 : Z return -2; Z default: Z break; Z } Z Z lines = 1; Z } Z } Z } Z if (isaconsole) Z { Z if (lines != 1) /* bottome of display */ Z { Z#ifdef IBMPC Z scr_curs(24,0); Z#else Z/* ansi terminal positioning */ Z printf("%c[25;1H%c[7m",ESC,ESC); Z#endif Z if (!isapipe) Z { Z position = ftell(fp); Z#ifdef IBMPC Z scr_printf( Z#else Z fprintf(stderr, Z#endif Z "%s - %ld characters - %d%% displayed", Z filename,size,percent(position,size) ); Z } Z else Z#ifdef IBMPC Z scr_printf( Z#else Z fprintf(stderr, Z#endif Z "-done-"); Z bdos(7,0,0); /* console input no echo */ Z lines = 1; Z } Z } Z} Z Zpercent(x,y) Z long int x,y; Z{ /* returns integer percentage of x into y */ Z#ifdef FLOAT Z float xf,yf; Z xf = x; yf = y; Z x = ((xf/yf)*100); Z#endif Z x *= 100; Z if (y) Z x /= y; Z else Z x = 100; Z return (x); Z} Z Zlocalputs(lb) Z register char *lb; Z{ Z int lines, pos, tabstop; Z lines = 1; Z pos = 0; Z while (*lb) Z { Z switch (*lb) Z { Z case '\t': Z tabstop = pos + (tabsize - (pos % tabsize)); Z for (;pos <= tabstop; pos++) Z (*output)(' '); Z break; Z case '\n': Z (*output)('\r'); Z default: Z (*output)(*lb); Z pos++; Z } Z if (pos == 79) Z { Z pos = 1; Z (*output)('\r'); Z (*output)('\n'); Z ++lines; Z } else if (pos > 79) Z { Z pos -= 80; Z ++lines; Z } Z ++lb; Z } Z return lines; Z} Z Z#ifdef IBMPC Zscr_printf(fmt,args) Zchar *fmt; unsigned args; Z{ Z format(scr_putc,fmt,&args); Z} Z#endif STUNKYFLUFF set `sum more.c` if test 34929 != $1 then echo more.c: Checksum error. Is: $1, should be: 34929. fi # # echo Extracting mv.c: sed 's/^Z//' >mv.c <<\STUNKYFLUFF Z/* :ts=2 */ Z#include <stdio.h> Zchar *savestr(); Z#ifndef MAIN Zextern char *fname_part(),*savestr(); Zextern char *me; Z#else Zchar *me; Z#endif Z/* mv.c - implements a version of UNIX mv */ Z#ifdef MAIN Zmain Z#else Zmv Z#endif Z(argc,argv) Z int argc; Z register char *argv[]; Z{ Z static char *usage = "mv : usage mv file1 [file2 . . fileN] target\r\n"; Z static char target_name[128]; Z char target[128],*fname_part(); Z register int i; Z int len; Z#ifndef MAIN Z me = argv[0]; /* referenced in routines common with cp.c */ Z#endif Z if (argc < 3) Z { Z write(2,usage,strlen(usage)); Z return(-1); Z } Z strcpy(target, argv[argc-1]); Z /* kill trailing backslashes */ Z if (target[i = strlen(target) - 1] == '\\') Z target[i] = '\0'; Z if (argc == 3) Z { Z /* if the target doesn't exist and it's not a directory then rename */ Z if (!filep(target)) Z { Z if (!dirp(target)) Z { Z fprintf(stderr,"rename : moving %s to %s\n" Z ,argv[1],argv[2]); Z rename(argv[1],argv[2]); Z } Z else Z { Z /* if the target is a directory copy to same name that directory */ Z strcpy(target_name,target); Z if (target_name[(len = strlen(target_name))-1] != '\\') Z { Z target_name[len = strlen(target_name)] = '\\'; Z target_name[len+1] = '\0'; Z } Z strcat(target_name,fname_part(argv[1])); Z#ifdef DEBUG Z fprintf(stderr,"interdirectory copy same name : moving %s to %s\n" Z#else Z fprintf(stderr,"moving %s to %s\n" Z#endif Z ,argv[1],target_name); Z if (-1 != maybecopy(target_name,argv[1])) Z unlink(argv[1]); Z } Z } Z else Z { Z /* target exists , and isn't a directory */ Z char *tpath,*spath; Z char tpathsaved = 0,spathsaved = 0; Z char *path_part(); Z /* find path parts of source and target */ Z if (tpath = path_part(target)) Z { Z tpath = savestr(tpath); Z tpathsaved++; Z } Z else Z tpath = "."; /* current directory */ Z if (spath = path_part(argv[1])) Z { Z spath = savestr(spath); Z spathsaved++; Z } Z else Z spath = "."; /* current directory */ Z if (0 == strcmp(tpath,spath)) Z { Z /* if source and target are in the same directory */ Z#ifdef DEBUG Z fprintf(stderr,"intradirectory delete then rename : moving %s to %s\n" Z#else Z fprintf(stderr,"moving %s to %s\n" Z#endif Z ,argv[1],target); Z unlink(target); Z rename(argv[1],target); Z } Z else Z { Z#ifdef DEBUG Z fprintf(stderr,"interdirectory file to file: moving %s to %s\n" Z#else Z fprintf(stderr,"moving %s to %s\n" Z#endif Z ,argv[1],target); Z if (-1 != maybecopy(target,argv[1])) Z unlink(argv[1]); Z } Z if (tpathsaved) Z free(tpath); Z if (spathsaved) Z free(spath); Z } Z return(0); Z } Z /* handle special case of a drive designation */ Z if (target[(i = strlen(target))-1] != ':') Z if (!dirp(target)) Z { Z fprintf(stderr,"mv : %s isn't a directory\n",target); Z return(-1); Z } Z for (i = 1; i < argc-1; i++) Z { Z strcpy(target_name,target); Z if (target_name[(len = strlen(target_name))-1] != '\\') Z { Z target_name[len = strlen(target_name)] = '\\'; Z target_name[len+1] = '\0'; Z } Z strcat(target_name,fname_part(argv[i])); Z if (!filep(argv[i])) Z { Z fprintf(stderr,"mv : %s isn't a file\n",argv[i]); Z continue; Z } Z fprintf(stderr,"moving %s to %s\n",argv[i],target_name); Z if (-1 != maybecopy(target_name,argv[i])) Z unlink(argv[i]); Z } Z return 0; Z} Z Zmaybecopy(target,source) Z char *target,*source; Z{ Z char *drive_part(); Z static char targetdrive[3], sourcedrive[3]; Z strcpy(targetdrive,drive_part(target)); Z strcpy(sourcedrive,drive_part(source)); Z if (0 == strcmp(targetdrive,sourcedrive)) Z { Z unlink(target); Z rename(source,target); Z return 0; Z } Z return (filecopy(target,source)); Z} STUNKYFLUFF set `sum mv.c` if test 37323 != $1 then echo mv.c: Checksum error. Is: $1, should be: 37323. fi # # echo Extracting mvcp.c: sed 's/^Z//' >mvcp.c <<\STUNKYFLUFF Z#include <stdio.h> Z/* Z * mvcp.c - routines common to mv and cp Z */ Z#include <fcntl.h> Zchar buffer[BUFSIZ*16]; Zextern char *me; Zfilecopy(target,source) Zchar *target,*source; Z{ Z int t,s,r; Z if (-1 == (s = open(source,O_RDONLY))) Z { Z fprintf(stderr,"%s : can't open %s\n",me,source); Z return(-1); Z } Z if (-1 == (t = open(target,O_TRUNC))) Z { Z fprintf(stderr,"%s : can't open %s\n",me,target); Z return(-1); Z } Z while(0 != (r = read(s,buffer,BUFSIZ*16)) && r != -1) Z { Z if(-1 == write(t,buffer,r)) Z { Z fprintf(stderr,"%s : error writing %s\n",me,target); Z return(-1); Z } Z } Z close(t); Z close(s); Z return (0); Z} Z Z#include <errno.h> Ztypedef struct Z{ Z char dos_reserved[21]; Z char attribute; Z unsigned file_time; Z unsigned file_date; Z long file_size; Z char file_name[13]; Z} Zfcb; Zfcb dir; Z Zdirp(s) Zchar *s; Z{ Z register int junk1,junk2; Z /* handle all of the stupid special cases */ Z if ((s[1] == ':' && s[2] == '\0') /* root directory on a drive */ Z || (s[1] == '\0') /* root directory default drive */ Z ) Z { Z return 1; Z } Z if (0 == strcmp(s,"..")) /* parent of this directory */ Z { Z int returnval; Z char *current,*parent; Z current = getcwd(NULL,64); Z if (-1 == chdir(s)) /* go to parent */ Z returnval = 0; Z else Z returnval = 1; Z parent = getcwd(NULL,64); Z chdir(current); Z free(current); free(parent); Z return returnval; Z } Z /* set the disk transfer address */ Z bdos(0x1A,&dir); Z /* do a search first for the directory path */ Z return (bdos(0x4E,s,0x10) == 0 && bdos(0x4E,s,0) != 0); Z} Z Zfilep(s) Zchar *s; Z{ Z /* set the disk transfer address */ Z bdos(0x1A,&dir); Z /* do a search first for the directory path */ Z return bdos(0x4E,s,0) == 0; Z} Zchar *fname_part(s) Zregister char *s; Z{ Z register char *r; Z char *rindex(); Z if (r = rindex(s,'\\')) Z { Z return r+1; Z } Z if (r = rindex(s,':')) Z { Z return r+1; Z } Z return s; Z} Zchar *path_part(s) Zregister char *s; Z{ Z static char buffer[64]; Z register char *r; Z char *rindex(); Z strcpy(buffer,s); /* copy string */ Z if (r = rindex(buffer,'\\')) Z { Z *++r = '\0'; Z return buffer; Z } Z if (r = rindex(buffer,':')) Z { Z *++r = '\0'; Z return buffer; Z } Z return NULL; Z} Zchar *drive_part(s) Zregister char *s; Z{ Z static char buffer[64]; Z register char *r; Z char *rindex(); Z strcpy(buffer,s); /* copy string */ Z if (buffer[1] == ':') Z { Z buffer[2] = '\0'; Z return buffer; Z } Z return NULL; Z} STUNKYFLUFF set `sum mvcp.c` if test 16416 != $1 then echo mvcp.c: Checksum error. Is: $1, should be: 16416. fi # # echo Extracting pushd.c: sed 's/^Z//' >pushd.c <<\STUNKYFLUFF Z#define NULL (void *)0 Z Zstatic char *dirstack[10]; Zstatic int dsp = -1; Z Zpushd(argc,argv) Zchar *argv[]; Z{ Z char *getcwd(), *savestr(); Z static char *usage = "usage : pushd newdir"; Z static char *pusherr = "pushd : dir stack overflow"; Z char dirbuf[64]; Z if (argc == 1) Z { Z write(2,usage,strlen(usage)); Z crlf(); Z return -1; Z } Z if (NULL == getcwd(&dirbuf[1],64)) Z { Z perror("pushd"); Z return -1; Z } Z if (++dsp == 10) Z { Z write(2,pusherr,strlen(pusherr)); Z crlf(); Z return -1; Z } Z dirbuf[0] = '\\'; Z if (-1 == chdir(*(++argv))) Z { Z --dsp; Z perror("pushd"); Z return -1; Z } Z dirstack[dsp] = savestr(dirbuf); Z return 0; Z} Z Zpopd() Z{ Z register int returnval = 0; Z static char *poperr = "popd : dir stack underflow"; Z if (dsp == -1) Z { Z write(2,poperr,strlen(poperr)); Z crlf(); Z return -1; Z } Z if (-1 == chdir(dirstack[dsp])) Z { Z perror("popd"); Z write(2,dirstack[dsp],strlen(dirstack[dsp])); Z crlf(); Z returnval = -1; Z } Z free(dirstack[dsp--]); Z return returnval; Z} STUNKYFLUFF set `sum pushd.c` if test 22547 != $1 then echo pushd.c: Checksum error. Is: $1, should be: 22547. fi # # echo Extracting pwd.c: sed 's/^Z//' >pwd.c <<\STUNKYFLUFF Z#define NULL (void *)0 Zpwd(argc,argv) Zchar *argv[]; Z{ Z char *getcwd(); Z register char *dir; Z if (!(dir = getcwd(NULL,256))) Z { Z perror("pwd"); Z return -1; Z } Z write(1,"\\",1); Z write(1,dir,strlen(dir)); Z crlf(); Z if (dir) Z free(dir); Z return 0; Z} STUNKYFLUFF set `sum pwd.c` if test 11133 != $1 then echo pwd.c: Checksum error. Is: $1, should be: 11133. fi # # echo Extracting rm.c: sed 's/^Z//' >rm.c <<\STUNKYFLUFF Z#include <stdio.h> Zrm(argc,argv) Z int argc; Z char *argv[]; Z{ Z extern int _echo; Z int oldecho = _echo; Z char ask = 0; Z Z if (argv[1][0] == '-' && toupper(argv[1][1]) == 'Q') Z { Z ask++; Z _echo = 1; Z ++argv; --argc; Z } Z while(--argc) Z { Z ++argv; Z if (ask) Z { Z fprintf(stderr,"delete %s? (y or n) : ",*argv); Z if (toupper(scr_getc()) != 'Y') Z { Z write(2,"\r\n",2); Z continue; Z } Z write(2,"\r\n",2); Z } Z if (-1 == unlink(*(argv))) Z { Z perror("rm"); Z } Z } Z _echo = oldecho; Z} Z Z STUNKYFLUFF set `sum rm.c` if test 00071 != $1 then echo rm.c: Checksum error. Is: $1, should be: 00071. fi # # echo Extracting rmdir.c: sed 's/^Z//' >rmdir.c <<\STUNKYFLUFF Z#include <stdio.h> Zrd(argc,argv) Zchar *argv[]; Z{ Z static char *usage = "usage : rmdir directory"; Z if (argc == 1) Z write(2,usage,strlen(usage)); Z if (-1 == rmdir(*(++argv))) Z { Z perror("rmdir"); Z return -1; Z } Z return 0; Z} STUNKYFLUFF set `sum rmdir.c` if test 22459 != $1 then echo rmdir.c: Checksum error. Is: $1, should be: 22459. fi # # echo Extracting savestr.c: sed 's/^Z//' >savestr.c <<\STUNKYFLUFF Z#define NULL (void *)0 Zchar * Zsavestr(s) Z register char *s; Z{ Z register char *r,*malloc(); Z /* squirrel away matched file name */ Z if (NULL == (r = malloc(strlen(s)+1))) Z abort(); Z strcpy(r,s); Z r[strlen(s)] = '\0'; Z return r; Z} STUNKYFLUFF set `sum savestr.c` if test 32164 != $1 then echo savestr.c: Checksum error. Is: $1, should be: 32164. fi # # echo Extracting shell.lnk: sed 's/^Z//' >shell.lnk <<\STUNKYFLUFF Zmain.o cd.o cp.o doprog.o fexecvp.o more.o Zinvalid.o ls.o pushd.o fgrep.o env.o cmds.o chmod.o Zmd.o mv.o pwd.o rm.o crlf.o drive.o fexecv.o Zrmdir.o savestr.o stdsave.o touch.o dump2.o mvcp.o Z_croot.o cat.o echo.o y.o fexec.o cmdlist.o ctlbrk.o Z/clibs/c.lib /clibs/s.lib STUNKYFLUFF set `sum shell.lnk` if test 41375 != $1 then echo shell.lnk: Checksum error. Is: $1, should be: 41375. fi # # echo Extracting ssbrk.asm: sed 's/^Z//' >ssbrk.asm <<\STUNKYFLUFF Z; :ts=8 Z;Copyright (C) 1983 by Manx Software Systems Z include lmacros.h Zdataseg segment word public 'data' Z extrn $MEMRY:word Z extrn _mbot_:word, _sbot_:word Z extrn _mtop_:word Z extrn errno_:word Z extrn _STKLOW_:word Z extrn _PSP_:word Zdataseg ends Z assume ds:dataseg Z; Z; sbrk(size): return address of current top & bump by size bytes Z; Z procdef sbrk,<<siz,word>> Z push di Z mov ax,siz Z mov di,$MEMRY Z add ax,di Z push ax Z call brk_ Z pop cx Z test ax,ax Z jnz brk_error Z mov ax,di ;return original value of the break Zbrk_error: Z pop di Z test ax,ax ;set flags for C Z pret Z pend sbrk Z; Z; brk(addr): set current top address to addr Z; returns 0 if ok, -1 if error Z; Z procdef brk,<<addr,word>> Z mov ax,addr Z inc ax Z and al,-2 Z cmp ax,_mbot_ Z jb brk_ov Z mov bx,_STKLOW_ Z cmp bx,0 Z jnz abovestk Z cmp ax,_sbot_ Z jae brk_ov Z mov bx,sp Z cmp ax,bx Z jae brk_ov Zbrk_ok2: Z mov $MEMRY,ax ;new value is good so save it away Z sub ax,ax Z pret Z;heap is above stack Zabovestk: Z cmp ax,_mtop_ Z ja getstore Z cmp ax,$MEMRY Z ja brk_ok2 Z; going to do a SETBLOCK call Zgetstore: Z push ax Z mov bx,ax Z mov cx,4 Z shr bx,cl Z and bx,0fffh Z add bx,65 ;bump to nearest 1k increment Z and bx,0ffc0h ;and round Z push bx Z push es Z mov cx,ds Z add bx,cx ;get actual paragraph address Z mov es,_PSP_ Z sub bx,_PSP_ Z mov ah,04ah Z int 21h ;SETBLOCK Z pop es Z pop bx Z pop ax Z jc brk_ov ; couldn't do it, so punt Z mov $MEMRY,ax Z test bx,0e000h Z jnz brk_ov Z mov cx,4 Z shl bx,cl Z mov _mtop_,bx Z sub ax,ax Z pret Z; invalid request Zbrk_ov: Z mov errno_,-4 Z mov ax,-1 Z test ax,ax Z pret Z pend brk Z; Z; rsvstk(size): set safety margin for stack Z; this will make sure that at least size Z; bytes of stack below the current level remain. Z; Z procdef rsvstk,<<stksize,word>> Z mov ax,sp Z sub ax,stksize Z mov _sbot_,ax Z pret Z pend rsvstk Z finish Z end STUNKYFLUFF set `sum ssbrk.asm` if test 58681 != $1 then echo ssbrk.asm: Checksum error. Is: $1, should be: 58681. fi # # echo Extracting stdsave.c: sed 's/^Z//' >stdsave.c <<\STUNKYFLUFF Z#include <stdio.h> Z#include <fcntl.h> Z Zint console; Zint in,out; /* old standard input and standard output */ Zstd_save() Z{ Z if (-1 == (console = open("con",O_RDWR))) Z { Z perror("sh : can't open console"); Z return -1; Z } Z in = dup(0); Z out = dup(1); Z fdup(console,0); Z fdup(console,1); Z fdup(console,2); Z return 0; Z} Zvoid Zstd_restore() Z{ Z fdup(in,0); Z fdup(out,1); Z close(console); Z close(in); Z close(out); Z} STUNKYFLUFF set `sum stdsave.c` if test 61619 != $1 then echo stdsave.c: Checksum error. Is: $1, should be: 61619. fi # # echo Extracting stksiz.c: sed 's/^Z//' >stksiz.c <<\STUNKYFLUFF Zint _STKSIZ = 8192/16; /* (in paragraphs) */ Zint _HEAPSIZ = 32768/16; /* (in paragraphs) */ Zint _STKLOW = 1; /* default is stack above heap (small only) */ STUNKYFLUFF set `sum stksiz.c` if test 11181 != $1 then echo stksiz.c: Checksum error. Is: $1, should be: 11181. fi # # echo Extracting touch.c: sed 's/^Z//' >touch.c <<\STUNKYFLUFF Z#include <stdio.h> Z Ztouch(argc,argv) Z char *argv[]; Z{ Z while(--argc) Z utime(*(++argv),NULL); Z} STUNKYFLUFF set `sum touch.c` if test 31978 != $1 then echo touch.c: Checksum error. Is: $1, should be: 31978. fi # # echo Extracting y.c: sed 's/^Z//' >y.c <<\STUNKYFLUFF Z#include <stdio.h> Z#include <signal.h> Z#include <setjmp.h> Z Z/* y and t Z * y reads the standard input to standard output, then invokes cat Z * to put one or more files to standard output Z * tee copies standard input to output and puts a copy Z * into a file specified on the command line Z */ Z Zvoid (*signal())(); Zvoid (*teesig)(); Zjmp_buf y_env; Zstatic FILE *in,*out; Z ZFILE *fopen(),*fdopen(); Z Zvoid y_intr() Z{ Z signal(SIGINT,SIG_IGN); Z longjmp(y_env,-1); Z} Z Zy(argc,argv) Z int argc; Z char *argv[]; Z{ Z register int c; Z Z /* handle interrupts */ Z if (-1 == setjmp(y_env)) Z { Z static char *intmsg = "Interrupted\r\n"; Z write(2,intmsg,strlen(intmsg)); Z fclose(in); Z fclose(out); Z signal(SIGINT,teesig); Z return -1; Z } Z Z /* set signal catcher */ Z teesig = signal(SIGINT,y_intr); Z Z if (NULL == (in = fdopen(0,"r"))) Z { Z fprintf(stderr,"can't open stdin\n"); Z }; Z if (NULL == (out = fdopen(1,"w"))) Z { Z fprintf(stderr,"can't open stdout\n"); Z }; Z Z while(EOF != (c = agetc(in))) Z aputc(c,out); Z if (argc > 1) Z cat(argc,argv); Z fclose(in); Z fclose(out); Z signal(SIGINT,teesig); Z return 0; Z} Z Zjmp_buf t_env; Z Zvoid t_intr() Z{ Z signal(SIGINT,SIG_IGN); Z longjmp(t_env,-1); Z} Z Zt(argc,argv) Z int argc; Z char *argv[]; Z{ Z register int c; Z register FILE *tfile; Z FILE *fopen(); Z Z /* handle interrupts */ Z if (-1 == setjmp(t_env)) Z { Z static char *intmsg = "Interrupted\r\n"; Z write(2,intmsg,strlen(intmsg)); Z fclose (tfile); Z fclose(in); Z fclose(out); Z signal(SIGINT,teesig); Z return -1; Z } Z Z /* set signal catcher */ Z teesig = signal(SIGINT,t_intr); Z Z if (NULL == (tfile = fopen(*(++argv),"w"))) Z { Z fprintf(stderr,"can't open %s\n",*argv); Z }; Z if (NULL == (in = fdopen(0,"r"))) Z { Z fprintf(stderr,"can't open stdin\n"); Z }; Z if (NULL == (out = fdopen(1,"w"))) Z { Z fprintf(stderr,"can't open stdout\n"); Z }; Z Z while(EOF != (c = agetc(in))) Z { Z aputc(c,out); Z if (tfile) Z aputc(c,tfile); Z } Z fclose(in); Z fclose(out); Z fclose(tfile); Z signal(SIGINT,teesig); Z return 0; Z} STUNKYFLUFF set `sum y.c` if test 44898 != $1 then echo y.c: Checksum error. Is: $1, should be: 44898. fi echo ALL DONE BUNKY! exit 0 -- -- .^. michael regoli /|\ ...ihnp4!inuxc!iuvax!isrnix!mr '|!|` <mr@isrnix.UUCP>