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_2 of 2: 55766 bytes) Message-ID: <644@isrnix.UUCP> Date: Sun, 15-Dec-85 13:33:54 EST Article-I.D.: isrnix.644 Posted: Sun Dec 15 13:33:54 1985 Date-Received: Tue, 17-Dec-85 04:38:34 EST Organization: indiana university - bloomington Lines: 2891 ######################################################### # # # This is a shell archive file. To extract files: # # # # 1) Make a directory for the files. # # 2) Write a file, such as "file.shar", containing # # this archive file into the directory. # # 3) Type "sh file.shar". Do not use csh. # # # ######################################################### # # echo Extracting getcmd.c: sed 's/^Z//' >getcmd.c <<\STUNKYFLUFF Z#include 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 '|!|`