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!cbosgd!ihnp4!inuxc!iubugs!isrnix!mr From: mr@isrnix.UUCP (michael regoli) Newsgroups: net.sources Subject: C-Shell for the PC (PART_1: 60224 bytes) Message-ID: <643@isrnix.UUCP> Date: Sun, 15-Dec-85 13:32:38 EST Article-I.D.: isrnix.643 Posted: Sun Dec 15 13:32:38 1985 Date-Received: Tue, 17-Dec-85 04:37:08 EST Organization: indiana university - bloomington Lines: 2630 ######################################################### # # # 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 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 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 ::= !! | !n | !-n Z !! = last command Z !n = nth command Z !-n = command n commands before current command number Z Z ::= :[^$*] | :n | :n* | 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 ::= 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 ::= = Z Z 7. command syntax Z Z drive Z a: | b: | c: | d: | e: | f: | g: | h: | i: | j: Z Z changes default drive. If you don't have such a drive, Z nothing happens. Z Z cat Z cat {} 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 Z Z copies specified files to destination file or device. If Z more than one file is in the file list, must be a Z directory. Z Z cd Z cd | chdir Z Z makes the current default directory. Z Z chmod Z chmod {-|+[rwh]*} 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 Z Z clears the screen and homes the cursor. Z Z commands Z commands 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 Z Z echos argument list to screen. Z Z era Z era Z Z synonym for rm. Z Z error Z error Z Z prints returned value of last command to the screen. Z Z exit Z exit Z Z terminates execution of the shell. Z Z fgrep Z fgrep Z Z looks for unambiguous pattern in . echos Z Z Z Z Z Z Z Z Z lines matching to the screen. Z Z hist Z hist | history Z Z prints history list to standard output. Z Z ls Z ls | dir {-[alqcr]} Z Z Lists files that match 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 Z Z make a directory. Prints an error if it can't be done Z Z more Z more {-[0-9]*} {} 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 Z Z moves specified file or files to target specifed by . Z If there is more than one file in list, must be a Z directory Z Z popd Z popd Z Z returns to directory at top of directory stack. Z Z pushd Z pushd Z Z save current working directory on directory stack, and Z changes current working directory to . 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 Z Z remove specified directory if possible. Z Z rm Z rm {-q} Z Z blows away all files in . If -q is specified, will Z ask if they should be removed. Z Z set Z set { { .. }} 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 Z Z Copies standard input to standard output, depositing a copy Z in Z Z touch Z touch Z Z Makes the modification time of specified files the current Z date and time. Z Z y Z y 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 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 ALL DONE BUNKY! exit 0 -- -- .^. michael regoli /|\ ...ihnp4!inuxc!iuvax!isrnix!mr '|!|`