Relay-Version: version B 2.10 5/3/83; site utzoo.UUCP Posting-Version: version B 2.10.1 6/24/83; site isrnix.UUCP Path: utzoo!watmath!clyde!burl!ulysses!mhuxr!mhuxt!houxm!ihnp4!inuxc!iubugs!isrnix!mr From: mr@isrnix.UUCP (michael regoli) Newsgroups: net.sources Subject: C-Shell for the PC Message-ID: <628@isrnix.UUCP> Date: Wed, 20-Nov-85 18:00:43 EST Article-I.D.: isrnix.628 Posted: Wed Nov 20 18:00:43 1985 Date-Received: Sat, 23-Nov-85 05:02:34 EST Organization: indiana university - bloomington Lines: 4922 ]:[ 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 Z#include Z#include 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 Z#include Z#include 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 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 Z#include 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 Z#include 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 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 Z#include 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 Z#include Z#include Z#include 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 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,<,,,,> 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 Z#endif Z#include Z#include 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 Z#include Z Z#include Z#include 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 Z#include 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 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 Z#include Z#include Z#include Z#include 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 Z#include Z#include Z#include Z#include 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.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 Z#include Z#include Z#include Z#include Z#include 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 - = 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 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 Z/* Z * mvcp.c - routines common to mv and cp Z */ Z#include 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 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 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 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,<> 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,<> 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,<> 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 Z#include 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 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 Z#include Z#include 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 '|!|`