drew@cgfsv1.dec.com (Steve Drew) (10/03/86)
As promised. Tried to mail to moderator for mod.sources but got bumped back with error's from his system.? Anyway, at the moment it will only run under 32 bits. But should be easy to modify for 16 bits. (READ the DOC file.) Enjoy, Steve Drew. # This is a shell archive. # Remove everything above and including the cut line. # Then run the rest of the file through sh. #----cut here-----cut here-----cut here-----cut here----# #!/bin/sh # shar: Shell Archiver # Run the following text with /bin/sh to create: # shell.doc # makefile # shell.h # comm2.c # set.c # sub.c # main.c # globals.c # comm1.c # run.c # execom.c # This archive created: Fri Oct 3 12:02:16 1986 echo shar: extracting shell.doc cat << \SHAR_EOF > shell.doc Matt Dillons Shell program. -------------------------- INSTRUCTIONS FOR 2.01A (A = AZTEC/MANX only) by Steve Drew ---------------------------------------------------------- Steve Drew at ENET: CGFSV1::DREW (Calgary,Ab.) ARPA: drew%cfgsv1.dec.com@decwrl.dec.com USENET: {decvax|decwrl}!cgfsv1.dec.com!drew VERSION RELEASES: ---------------- 2.01A 27-sep-86 Steve Drew :Major conversion from Lattice > MANX :and added more commands/features. Background: ---------- This shell program was written by Matt Dillon and provided for public domain. I have added the 'A' varient on the end of the version to distinguish between Matt's version's and my modified version for Manx C. This is actually equivalent to Matt's version 2.01 with additional commands/features and will work only on Manx C. To compile: Make (return). should be about 28500 bytes. Enjoy. Version 2.01A notes: Differences between Matt Dillons original version and this version specifically for Manx C. All of the functionality that Matt Dillon so well provided is still there plus many more goodies. - All external commands are executed via fexecv() rather than Execute() function. This allows for ^C capability and faster loading. (since run command not needed to load first). NOTE: since I have heard that there maybe problems with fexecv() under 1.2 I have include a symbol in shell.h to allow the use of Execute() rather than fexecv(). (Until fexecv() is fixed.) set USE_EXECUTE to a 1 and USE_FEXEC to a 0 to switch to Execute() By default it is set to use fexecv(). A couple of disadvantages of using fexec: - question marks to ask for prompt on bcpl programs gets ignored. - execute (the C: command) a script file will not work. this will: 'run execute file' - Changed all i/o routines that used MY.LIB written by Matt to use standard i/o or Amiga routines, since Manx is so efficeint with standard i/o routines compiling all those library functions did'nt gain anything as it does with Lattice. - Dir command rewritten to allow options: -s short mutil(4) collum display of files -d directorys only -f files only also added date and time stamp for files, and for wild carded directories always tells you what directory you are listing. the directory command will also not expand files that are directories if as result of a wildcard expansion. eg: 'dir df0:*' and 'dir df0:' will give same results expect previously if df0:* was specified all subdirectories of df0: were expanded also. (to list the subdirectories: 'dir df0:*/*') - Wildcarding now matches upper or lower case. - Command will no longer abort if one of the arguments which has wild card does not expand. - run program >redir will work properly with Shell 2.01A, as long as you run command is called 'run'. With the lattice version the command got parsed like run >redir program, so all you got in you redir file was [CLI n]. - CD command rewritten. Will change any input such as cd df0:work to be Disklabel:work, this makes it real easy when switching disks arround. Also checks if file is a directory. Note: if you for some reason do a CD dir (note upper case so will run c:CD command) it will change you current dir and will be handled properly. some examples cd df0:sub/sub2 cd / will set you to parent directory cd // two levels up cd /progs one level up and back down in progs - On startup you current directory is determined and set. - Added %full and volume name to devinfo. - copy command added. (faster that COPY under 1.1 workbench) format: copy dir/file copies file to current dir copy work/* [to] new copies all files from directory work to directory new copy foo foo2 copies foo to foo2 copy >nil: * [to] df1: copies all files in current directory to df1: & logs it to nil: (at present it will not create directorys or do a ALL option like c:COPY does). - ps command added. gives the folling info: Proc Command Name CLI Type Pri. Address Directory 1 SHELL Initial CLI 0 97b0 Stuff:shell 2 sys:c/clockmem Background -10 2101a8 Workdisk: 3 c:emacs Background 0 212f58 Stuff:shell 4 sys:c/VT100 Background 0 227328 Workdisk: Address is the addres of the task, directory is the process currently set directory. - New special symbol '_lasterror' is set to a non zero function when a command fails. Set to -1 when an iternal command fails or to the value of the return code if an external command fails. What follow are Matt's instructions for version 2.01. Which is still the same for 2.01A. ============================================================================ INSTRUCTIONS FOR SHELL 2.01 (A) Compiling (B) Overview (C) Quicky tech notes on implimentation. (D) Command pre-processor (E) Command-list (F) special SET variables (G) example .login file. (A) COMPILING: see notes on 2.01A above. (B) OVERVIEW: overview of the major features: -simple history -redirection -piping -aliases -variables & variable handling -file name expansion via '?' and '*' -conditionals -source files (w/ gotos and labels) -many built in commands to speed things up changes from V1.02: -you can now redirect through internal commands as well as external. -piping has been added. You can pipe from/to internal commands. -you can now embed strings ( charlie/$var/ben ), making the shell more flexible. -history substitution displays line to be executed. -verbose mode for debugging source files -break handled a little better (still can't send break to external commands) -some new commands sorry, I still havent figured out how to get the return value from external commands. (C) QUICK TECH NOTES: PIPES have been implimented using temporary RAM: files. Thus, you should be careful when specifying a 'ram:*' expansion as it might include the temp. files. These files are deleted on completion of the pipe segment. My favorite new feature is the fact that you can now redirect to and from, and pipe internal commands. 'echo charlie >ram:x', for instance. Another favorite: echo "echo mem | shell" | shell To accomplish these new features, I completely re-wrote the command parser in execom.c (D) COMMAND LINE PRE-PROCESSING: preprocessing is done on the command line before it is passed on to an internal or external routine: ^c where c is a character is converted to that control character. Thus, say '^l' for control-l. $name where name is a variable name. Variable names can consist of 0-9, a-z, A-Z, and underscore (_). The contents of the specified variable is used. If the variable doesn't exist, the specifier is used. That is, if the variable 'i' contains 'charlie', then '$i' -> 'charlie'. If the variable 'i' doesn't exist, then '$i'->'$i' . ; delimits commands. echo charlie ; echo ben. ' ' (a space). delimits arguments. "string" a quoted string. For instance, if you want to echo five spaces and an 'a': echo a -> a echo " a" -> a \c overide the meaning of special characters. '\^a' is a circumflex and an a rather than control-a. To get a backslash, you must say '\\'. >file specify output redirection. All output from the command is placed in the specified file. <file specify input redirection. The command takes input from the file rather than the keyboard (note: not all commands require input). It makes no sense to say 'echo <charlie' since the 'echo' command only outputs its arguments. | PIPE specifier. The output from the command on the left becomes the input to the command on the right. The current SHELL implimentation uses temporary files to store the data. !! execute the previously executed command. !nn (nn is a number). Insert the history command numbered n (see the HISTORY command) !partial search backwards through the history list for a command which looks the same as 'partial', and execute it. (E) COMMAND LIST: The first argument is the command-name... if it doesn't exist in the list below and isn't an alias, it is assumed to be an external (disk) command. NOTE: Many CLI specific external commands, such as 'path', and 'cd' will have no effect on the shell. However, you can execute these commands from the initial CLI (startup script) BEFORE you run the shell. HELP simply displays all the available commands. QUIT quit my SHELL (awww!). End, El-Zappo, Kapow. Done, Finis SET SET name SET name string The first method lists all current variable settings. The second method lists the setting for that particular variable, or creates the variable if it doesn't exist (to "") The last method sets a variable to a string. UNSET name name name.... unset one or more variables. Deletes them entirely. ALIAS ALIAS name ALIAS name string same as SET, but applies to the alias list. You can alias a single name to a set of commands. For instance: alias hi "echo a; echo b" then you can simply say 'hi'. Aliases come in two forms the second form allows you to place the arguments after an alias in a variable for retrieval: alias xxx "%i echo this $i is a test" % xxx charlie this charlie is a test The rest of the command line is placed in the specified variable for the duration of the alias. This is especially useful when used in conjunction with the 'FOREACH' command. UNALIAS name name name... delete aliases.. ECHO string ECHO -n string echo the string to the screen. If '-n' is specified, no newline is output. STRHEAD varname breakchar string remove everything after and including the breakchar in 'string' and place in variable 'varname': % strhead j . aaa.bbb % echo $j aaa % STRTAIL varname breakchar string remove everything before and including the breakchar in 'string' and place in variable 'varname': % strtail j . aaa.bbb % echo $j bbb % SOURCE file execute commands from a file. You can create SHELL programs in a file and then execute them with this command. Source'd files have the added advantage that you can have loops in your command files (see GOTO and LABEL) MV from to Exactly the Rename() call. Allows you to rename files or move them around within a disk. CD .. CD path Change your current working directory. You may specify '/' to go back one directory. RM file file file... DeleteFile(). Remove the specified files. MKDIR name name name... create the following directories. HISTORY [partial string] Displays the enumerated history list. The size of the list is controlled by the _history variable. If you specify a partial- string, only those entries matching that string are displayed. MEM Display current memory statistics. CAT [file file....] Type the specified files onto the screen. If no file is specified, STDIN in used. DIR [path path ... ] Get a directory listing of the current directory or specified directories. DEVINFO [device: device:... ] Display Device statistics for the current device (CD base), or specified devices. FOREACH varname ( strings ) command 'strings' is broken up into arguments. Each argument is placed in the variable 'varname' in turn and 'command' executed. To execute multiple commands, place them in quotes: % foreach i ( a b c d ) "echo -n $i;echo \" ha\"" a ha b ha c ha d ha RETURN [value] return from a source file. The rest of the source file is discarded. Currently, the optional value is thrown away. IF argument conditional argument ; IF argument If a single argument is something to another argument. Conditional clauses allowed: <, >, =, and combinations (wire or). Thus <> is not-equal, >= larger or equal, etc... If the left argument is numeric, both arguments are treated as numeric. usually the argument is either a constant or a variable ($varname). The second form if IF is conditional on the existance of the argument. If the argument is a "" string, then false , else TRUE. ELSE ; else clause. ENDIF ; the end of an if statement. LABEL name create a program label right here. GOTO label goto the specified label name. You can only use this command from a source file. FAILAT CHECKBREAK not implimented yet. DEC var INC var decrement or increment the numerical equivalent of the variable and place the ascii-string result back into that variable. INPUT varname input from STDIN (or a redirection, or a pipe) to a variable. The next input line is placed in the variable. VER display my name and the version number. SLEEP timeout Sleep for 'timeout' seconds. (F) SPECIAL SET VARIABLES _prompt This variable is set to the command you wish executed that will create your prompt. _history This variable is set to a numerical value, and specifies how far back your history should extend. _debug Debug mode... use it if you dare. _verbose Verbose mode (for source files). display commands as they are executed. (G) EXAMPLE .login file. from a CLI or the startup-script say 'SHELL filename'. That file is sourced first. thus, 'SHELL .login' will set up your favorite aliases: ------------------------------ example source file ----------------- echo "shells, Matt" alias l "%var if $var;echo $var;else;echo *;endif" alias c "echo ^l" alias cc "assign c: cb:c ;cd ram:" alias wb "assign c: sys:c ;cd ram:" alias ram "cp c:run ram:; cp c:assign ram:; cp c:cp ram:; assign c: ram:" alias ram2 "assign c: ram:" alias ed "run ED" alias c1 "%z foreach y ( $z ) \"echo $y;lc1 -o$temp -i$incdir/ -i$incdir/lattice/ $y\";echo DONE" alias c2 "%z foreach y ( $z ) \"echo $y;lc2 -s -v $temp$y\";echo DONE" alias ld "%var alink faster $libdir/lstartup.obj+$var library $libdir/lc.lib+$libdir/amiga.lib to $dest" alias lds "%var alink faster $libdir/Astartup.obj+$var library $libdir/my.lib+$libdir/amiga.lib+$libs to $dest" set dest ram:a set temp ram: set libdir cb:clib set incdir cb:include set libs $libdir/lc.lib cd ram: -------------------------------------------------------------------- SHAR_EOF if test 15641 -ne "`wc -c shell.doc`" then echo shar: error transmitting shell.doc '(should have been 15641 characters)' fi echo shar: extracting makefile cat << \SHAR_EOF > makefile ###################################################################### # # Makefile to build Shell 2.01a # by Steve Drew 27-sep-86 # ###################################################################### OBJS = comm1.o comm2.o main.o run.o execom.o set.o sub.o globals.o INCL = shell.h Shell : $(OBJS) ln -o Shell $(OBJS) -lc32 @Echo "Done Building Shell" comm1.o : comm1.c $(INCL) cc +L +HShell.syms comm1.c comm2.o : comm2.c $(INCL) cc +L +IShell.syms comm2.c main.o : main.c $(INCL) cc +L +IShell.syms main.c run.o : run.c $(INCL) cc +L +IShell.syms run.c set.o : set.c $(INCL) cc +L +IShell.syms set.c sub.o : sub.c $(INCL) cc +L +IShell.syms sub.c globals.o : globals.c $(INCL) cc +L +IShell.syms globals.c execom.o : execom.c $(INCL) cc +L +IShell.syms execom.c SHAR_EOF if test 814 -ne "`wc -c makefile`" then echo shar: error transmitting makefile '(should have been 814 characters)' fi echo shar: extracting shell.h cat << \SHAR_EOF > shell.h /* * SHELL.H * * Matthew Dillon, 24 Feb 1986 * version 2.01A (Manx ver) by Steve Drew 27 Sep 1986 * */ /* set one of these two symbols depending on to use dos Execute() func. * or manx fexecv() function. This flexibility provided because of * rumors that fexecv() doesnt work under 1.2 so can be a temporary * workaround. */ #define USE_FEXEC 1 /* best way to go */ #define USE_EXECUTE 0 #include <stdio.h> #include <time.h> #include <exec/types.h> #include <exec/exec.h> #include <libraries/dos.h> #include <libraries/dosextens.h> #include <exec/memory.h> #include <exec/tasks.h> #define bmov movmem #define MAXAV 200 /* Max. # arguments */ #define MAXSRC 5 /* Max. # of source file levels */ #define MAXIF 10 /* Max. # of if levels */ #define LEVEL_SET 0 #define LEVEL_ALIAS 1 #define LEVEL_LABEL 2 #define M_RESET 0 #define M_CONT 1 #define V_PROMPT "_prompt" /* Special variable names */ #define V_HIST "_history" #define V_DEBUG "_debug" #define V_VERBOSE "_verbose" #define V_LASTERROR "_lasterror" #define FL_DOLLAR 0x01 /* One of the following */ #define FL_BANG 0x02 #define FL_PERCENT 0x04 #define FL_QUOTE 0x08 #define FL_IDOLLAR 0x10 /* Any or all of the following may be set */ #define FL_EOC 0x20 #define FL_EOL 0x40 #define FL_OVERIDE 0x80 #define FL_WILD 0x100 #define FL_MASK (FL_DOLLAR|FL_BANG|FL_PERCENT|FL_QUOTE) #define VERSION "V2.01A (c)1986 Matthew Dillon. Manx ver(A) By Steve Drew" #undef NULL #define NULL ((void *)0) #define CHECKBREAK() ( breakcheck() ? (printf("^C\n"),1) : 0) struct HIST { struct HIST *next, *prev; /* doubly linked list */ char *line; /* line in history */ }; struct PERROR { int errnum; /* Format of global error lookup */ char *errstr; }; struct DPTR { /* Format of directory fetch pointer */ struct FileLock *lock; /* lock on directory */ struct FileInfoBlock *fib; /* mod'd fib for entry */ }; extern struct HIST *H_head, *H_tail; extern struct PERROR Perror[]; extern struct DPTR *dopen(); extern char *set_var(), *get_var(), *next_word(); extern char *get_history(), *compile_av(); char *malloc(), *strcpy(), *AllocMem(); extern char **expand(); extern char *av[]; extern char *Current; extern int H_len, H_tail_base, H_stack; extern int Src_stack, If_stack; extern int ac; extern int Debug, Rval, Verbose, Disable, Faillevel, Quit; extern int S_histlen; extern long Uniq; extern struct Process *Myprocess; extern long Cin, Cout; extern char *Cin_name, *Cout_name; extern char *Pipe1, *Pipe2; extern long Src_base[MAXSRC]; extern long Src_pos[MAXSRC]; extern char If_base[MAXIF]; SHAR_EOF if test 2853 -ne "`wc -c shell.h`" then echo shar: error transmitting shell.h '(should have been 2853 characters)' fi echo shar: extracting comm2.c cat << \SHAR_EOF > comm2.c /* * MORE commands * Matt Dillon * version 2.01A (Manx ver) by Steve Drew 27 Sep 1986 */ #include "shell.h" #define BPTR_TO_C(strtag, var) ((struct strtag *)(BADDR( (ULONG) var))) #define TO_ASC(n) ((n) + '0') /* make it printable! */ /* Casting conveniences */ #define PROC(task) ((struct Process *)task) #define ROOTNODE ((struct RootNode *)DOSBase->dl_Root) #define CLI(proc) (BPTR_TO_C(CommandLineInterface, proc->pr_CLI)) /* Externs */ extern struct DosLibrary *DOSBase; /* dos library base pointer */ do_return() { if (Src_stack) { fseek (Src_base[Src_stack - 1], 0, 2); /* ch to 2 fr 1 */ Rval = (ac < 2) ? 1 : atoi(av[1]); return (-1); } else { main_exit ((ac < 2) ? 1 : atoi(av[1])); } } /* * STRHEAD * * place a string into a variable removing everything after and including * the 'break' character or until a space is found in the string. * * strhead varname breakchar string * */ do_strhead() { register char *str = av[3]; char bc = *av[2]; while (*str && *str != bc) ++str; *str = '\0'; set_var (LEVEL_SET, av[1], av[3]); } do_strtail() { register char *str = av[3]; char bc = *av[2]; while (*str && *str != bc) ++str; if (*str) ++str; set_var (LEVEL_SET, av[1], str); } /* * if A < B <, >, =, <=, >=, !=, where A and B are either: * nothing * a string * a value (begins w/ number) */ do_if(garbage, com) char *garbage; { char *v1, *v2, *v3, result, num; int n1, n2; switch (com) { case 0: if (If_stack && If_base[If_stack - 1]) { If_base[If_stack++] = 1; break; } result = num = 0; if (ac <= 2) { /* if $var; */ if (ac == 1 || strlen(av[1]) == 0 || (strlen(av[1]) == 1 && *av[1] == ' ')) goto do_result; result = 1; goto do_result; } if (ac != 4) { ierror(NULL, 500); break; } v1 = av[1]; v2 = av[2]; v3 = av[3]; while (*v1 == ' ') ++v1; while (*v2 == ' ') ++v2; while (*v3 == ' ') ++v3; if (*v1 >= '0' && *v1 <= '9') { num = 1; n1 = atoi(v1); n2 = atoi(v3); } while (*v2) { switch (*v2++) { case '>': result |= (num) ? (n1 > n2) : (strcmp(v1, v3) > 0); break; case '<': result |= (num) ? (n1 < n2) : (strcmp(v1, v3) < 0); break; case '=': result |= (num) ? (n1 == n2) : (strcmp(v1, v3) ==0); break; default: ierror (NULL, 503); break; } } do_result: If_base[If_stack++] = !result; break; case 1: if (If_stack > 1 && If_base[If_stack - 2]) break; if (If_stack) If_base[If_stack - 1] ^= 1; break; case 2: if (If_stack) --If_stack; break; } Disable = (If_stack) ? If_base[If_stack - 1] : 0; return (0); } do_label() { char aseek[32]; if (Src_stack == 0) { ierror (NULL, 502); return (-1); } sprintf (aseek, "%ld %ld", Src_pos[Src_stack-1], If_stack); set_var (LEVEL_LABEL + Src_stack - 1, av[1], aseek); return (0); } do_goto() { int new; long pos; char *lab; if (Src_stack == 0) { ierror (NULL, 502); } else { lab = get_var (LEVEL_LABEL + Src_stack - 1, av[1]); if (lab == '\0') { ierror (NULL, 501); } else { pos = atoi(lab); fseek (Src_base[Src_stack - 1], pos, 0); Src_pos[Src_stack - 1] = pos; new = atoi(next_word(lab)); for (; If_stack < new; ++If_stack) If_base[If_stack] = 0; If_stack = new; } } return (-1); /* Don't execute reset of this line */ } do_failat() { Faillevel = 1; fprintf (stderr, "NOT IMPLIMENTED YET\n"); } do_checkbrk() { fprintf (stderr,"NOT IMPLIMENTED YET\n"); } do_inc(garbage, com) char *garbage; { char *var; char num[32]; if (ac == 3) com = atoi(av[2]); var = get_var (LEVEL_SET, av[1]); if (var) { sprintf (num, "%d", atoi(var)+com); set_var (LEVEL_SET, av[1], num); } } do_input() { char in[256]; if ((gets(in)) != 0) set_var (LEVEL_SET, av[1], in); return (0); } do_ver() { puts (VERSION); return (0); } do_ps() { /* this code fragment based on ps.c command by Dewi Williams */ register ULONG *tt; /* References TaskArray */ register int count; /* loop variable */ register UBYTE *port; /* msgport & ptr arith */ register struct Task *task; /* EXEC descriptor */ char strbuf[64]; /* scratch for btocstr() */ char *btocstr(); /* BCPL BSTR to ASCIIZ */ tt = (unsigned long *)(BADDR(ROOTNODE->rn_TaskArray)); printf("Proc Command Name CLI Type Pri. Address Directory\n"); Forbid(); /* need linked list consistency */ for (count = 1; count <= (int)tt[0] ; count++) {/* or just assume 20?*/ if (tt[count] == 0) continue; /* nobody home */ /* Start by pulling out MsgPort addresses from the TaskArray * area. By making unwarranted assumptions about the layout * of Process and Task structures, we can derive these * descriptors. Every task has an associated process, since * this loop drives off a CLI data area. */ port = (UBYTE *)tt[count]; task = (struct Task *)(port - sizeof(struct Task)); /* Sanity check just in case */ if (PROC(task)->pr_TaskNum == 0 || PROC(task)->pr_CLI == 0) continue; /* or complain? */ btocstr(CLI(PROC(task))->cli_CommandName, strbuf); printf("%2ld %-21s",count,strbuf); strcpy(strbuf,task->tc_Node.ln_Name); strbuf[11] = '\0'; printf("%s",strbuf); printf(" %3ld %8lx %s\n", task->tc_Node.ln_Pri,task, btocstr(CLI(PROC(task))->cli_SetName, strbuf)); } Permit(); /* outside critical region */ return(0); } char * btocstr(b, buf) ULONG b; char *buf; { register char *s; s = (char *)BADDR(b); /* Shift & get length-prefixed str */ bmov(s +1, buf, s[0]); buf[s[0]] = '\0'; return buf; } SHAR_EOF if test 6813 -ne "`wc -c comm2.c`" then echo shar: error transmitting comm2.c '(should have been 6813 characters)' fi echo shar: extracting set.c cat << \SHAR_EOF > set.c /* * SET.C * * Matthew Dillon, July 1986 * version 2.01A (Manx ver) by Steve Drew 27 Sep 1986 * */ #include "shell.h" #define MAXLEVELS (3 + MAXSRC) struct MASTER { struct MASTER *next; struct MASTER *last; char *name; char *text; }; static struct MASTER *Mbase[MAXLEVELS]; char * set_var(level, name, str) register char *name, *str; { register struct MASTER *base = Mbase[level]; register struct MASTER *last; register int len; for (len = 0; isalphanum(name[len]); ++len); while (base != NULL) { if (strlen(base->name) == len && strncmp (name, base->name, len) == 0) { Free (base->text); goto gotit; } last = base; base = base->next; } if (base == Mbase[level]) { base = Mbase[level] = (struct MASTER *)malloc (sizeof(struct MASTER)); base->last = NULL; } else { base = (struct MASTER *)malloc (sizeof(struct MASTER)); base->last = last; last->next = base; } base->name = malloc (len + 1); bmov (name, base->name, len); base->name[len] = 0; base->next = NULL; gotit: base->text = malloc (strlen(str) + 1); strcpy (base->text, str); return (base->text); } char * get_var (level, name) register char *name; { register struct MASTER *base = Mbase[level]; register unsigned char *scr; register int len; for (scr = (unsigned char *)name; *scr && *scr != 0x80 && *scr != ' ' && *scr != ';' && *scr != '|'; ++scr); len = scr - name; while (base != NULL) { if (strlen(base->name) == len && strncmp (name, base->name, len) == 0) return (base->text); base = base->next; } return (NULL); } unset_level(level) { register struct MASTER *base = Mbase[level]; while (base) { Free (base->name); Free (base->text); Free (base); base = base->next; } Mbase[level] = '\0'; } unset_var(level, name) char *name; { register struct MASTER *base = Mbase[level]; register struct MASTER *last = '\0'; register int len; for (len = 0; isalphanum(name[len]); ++len); while (base) { if (strlen(base->name) == len && strncmp (name, base->name, len) == 0) { if (base != Mbase[level]) last->next = base->next; else Mbase[level] = base->next; if (base->next != NULL) base->next->last = last; if (base == Mbase[level]) Mbase[level] = base->next; Free (base->name); Free (base->text); Free (base); return (0); } last = base; base = base->next; } return (-1); } do_unset_var(str, level) char *str; { register int i; for (i = 1; i < ac; ++i) unset_var (level, av[i]); return (0); } do_set_var(command, level) char *command; { register struct MASTER *base = Mbase[level]; register char *str; if (ac == 1) { while (base) { printf ("%-10s ", base->name); puts (base->text); base = base->next; } return (0); } if (ac == 2) { str = get_var (level, av[1]); if (str) { printf ("%-10s ", av[1]); puts(str); } else { set_var (level, av[1], ""); } } if (ac > 2) set_var (level, av[1], next_word (next_word (command))); if (*av[1] == '_') { S_histlen = (str = get_var(LEVEL_SET, V_HIST)) ? atoi(str) : 0; Debug = (str = get_var(LEVEL_SET, V_DEBUG)) ? atoi(str) : 0; Verbose = (get_var(LEVEL_SET, V_VERBOSE)) ? 1 : 0; if (S_histlen < 2) S_histlen = 2; } return (0); } SHAR_EOF if test 3622 -ne "`wc -c set.c`" then echo shar: error transmitting set.c '(should have been 3622 characters)' fi echo shar: extracting sub.c cat << \SHAR_EOF > sub.c /* * SUB.C * * Matthew Dillon, 24 Feb 1986 * version 2.01A (Manx ver) by Steve Drew 27 Sep 1986 * */ #include "shell.h" #define HM_STR 0 #define HM_REL 1 #define HM_ABS 2 extern struct FileLock *Lock(), *DupLock(), *CurrentDir(); extern struct FileLock *Clock; char * next_word(str) register char *str; { while (*str && *str != ' ' && *str != 9) ++str; while (*str && (*str == ' ' || *str == 9)) ++str; return (str); } char * compile_av(av, start, end) char **av; { char *cstr; int i, len; len = 0; for (i = start; i < end; ++i) len += strlen(av[i]) + 1; cstr = malloc(len + 1); *cstr = '\0'; for (i = start; i < end; ++i) { strcat (cstr, av[i]); strcat (cstr, " "); } return (cstr); } Free(ptr) char *ptr; { static char *old_ptr; if (old_ptr) free (old_ptr); old_ptr = ptr; } /* * Add new string to history (H_head, H_tail, H_len, * S_histlen */ add_history(str) char *str; { register struct HIST *hist; while (H_len > S_histlen) del_history(); hist = (struct HIST *)malloc (sizeof(struct HIST)); if (H_head == NULL) { H_head = H_tail = hist; hist->next = '\0'; } else { hist->next = H_head; H_head->prev = hist; H_head = hist; } hist->prev = '\0'; hist->line = malloc (strlen(str) + 1); strcpy (hist->line, str); ++H_len; } del_history() { if (H_tail) { --H_len; ++H_tail_base; free (H_tail->line); if (H_tail->prev) { H_tail = H_tail->prev; free (H_tail->next); H_tail->next = '\0'; } else { free (H_tail); H_tail = H_head = '\0'; } } } char * get_history(ptr) char *ptr; { register struct HIST *hist; register int len; int mode = HM_REL; int num = 1; char *str; char *result = '\0'; if (ptr[1] >= '0' && ptr[1] <= '9') { mode = HM_ABS; num = atoi(&ptr[1]); goto skip; } switch (ptr[1]) { case '!': break; case '-': num += atoi(&ptr[2]); break; default: mode = HM_STR; str = ptr + 1; break; } skip: switch (mode) { case HM_STR: len = strlen(str); for (hist = H_head; hist; hist = hist->next) { if (strncmp(hist->line, str, len) == 0) { result = hist->line; break; } } break; case HM_REL: for (hist = H_head; hist && num--; hist = hist->next); if (hist) result = hist->line; break; case HM_ABS: len = H_tail_base; for (hist = H_tail; hist && len != num; hist = hist->prev, ++len); if (hist) result = hist->line; break; } if (result) fprintf (stderr, "%s\n",result); return (result); } replace_head(str) char *str; { if (str == NULL) str = ""; if (H_head) { free (H_head->line); H_head->line = malloc (strlen(str)+1); strcpy (H_head->line, str); } } perror(str) char *str; { int ierr = (long)IoErr(); ierror(str, ierr); } ierror(str, err) register char *str; { register struct PERROR *per = Perror; if (err) { for (; per->errstr; ++per) { if (per->errnum == err) { fprintf (stderr,"%s%s%s\n", per->errstr, (str) ? ": " : "", (str) ? str : ""); return (err); } } fprintf (stderr, "Unknown DOS error %ld %s\n", err, (str) ? str : ""); } return (err); } /* * Disk directory routines * * dptr = dopen(name, stat) * struct DPTR *dptr; * char *name; * int *stat; * * dnext(dptr, name, stat) * struct DPTR *dptr; * char **name; * int *stat; * * dclose(dptr) -may be called with NULL without harm * * dopen() returns a struct DPTR, or NULL if the given file does not * exist. stat will be set to 1 if the file is a directory. If the * name is "", then the current directory is openned. * * dnext() returns 1 until there are no more entries. The **name and * *stat are set. *stat = 1 if the file is a directory. * * dclose() closes a directory channel. * */ struct DPTR * dopen(name, stat) char *name; int *stat; { struct DPTR *dp; int namelen, endslash = 0; getcd(); /* incase someone CD'd with c:CD dir */ namelen = strlen(name); /* if (namelen && name[namelen - 1] == '/') { name[namelen - 1] = '\0'; endslash = 1; } */ *stat = 0; dp = (struct DPTR *)malloc(sizeof(struct DPTR)); if (*name == '\0') dp->lock = DupLock (Clock); else dp->lock = Lock (name, ACCESS_READ); if (endslash) name[namelen - 1] = '/'; if (dp->lock == '\0') { free (dp); return (NULL); } dp->fib = (struct FileInfoBlock *) AllocMem((long)sizeof(struct FileInfoBlock), MEMF_PUBLIC); if (!Examine (dp->lock, dp->fib)) { perror (name); dclose (dp); return (NULL); } if (dp->fib->fib_DirEntryType >= 0) *stat = 1; return (dp); } dnext(dp, pname, stat) struct DPTR *dp; char **pname; int *stat; { if (dp == NULL) return (0); if (ExNext (dp->lock, dp->fib)) { *stat = (dp->fib->fib_DirEntryType < 0) ? 0 : 1; *pname = dp->fib->fib_FileName; return (1); } return (0); } dclose(dp) struct DPTR *dp; { if (dp == NULL) return (1); if (dp->fib) FreeMem (dp->fib, (long)sizeof(*dp->fib)); if (dp->lock) UnLock (dp->lock); free (dp); return (1); } free_expand(av) char **av; { char **base = av; if (av) { while (*av) { free (*av); ++av; } free (base); } } /* * EXPAND(wild_name, pac) * wild_name - char * (example: "df0:*.c") * pac - int * will be set to # of arguments. * * Standalone, except in requires Clock to point to the Current-Directory * lock. */ char ** expand(base, pac) char *base; int *pac; { char **eav = (char **)malloc (sizeof(char *)); int eleft, eac; char *ptr, *name; char *bname, *ename, *tail; int stat, scr; struct DPTR *dp; *pac = eleft = eac = 0; base = strcpy(malloc(strlen(base)+1), base); for (ptr = base; *ptr && *ptr != '?' && *ptr != '*'; ++ptr); for (; ptr >= base && !(*ptr == '/' || *ptr == ':'); --ptr); if (ptr < base) { bname = strcpy (malloc(1), ""); } else { scr = ptr[1]; ptr[1] = '\0'; bname = strcpy (malloc(strlen(base)+1), base); ptr[1] = scr; } ename = ptr + 1; for (ptr = ename; *ptr && *ptr != '/'; ++ptr); scr = *ptr; *ptr = '\0'; tail = (scr) ? ptr + 1 : NULL; if ((dp = dopen (bname, &stat)) == NULL || stat == 0) { free (bname); free (base); free (eav); fprintf (stderr,"Could not open directory\n"); return (NULL); } while (dnext (dp, &name, &stat)) { if (compare_ok(ename, name)) { if (tail) { int alt_ac; char *search, **alt_av, **scrav; struct FileLock *lock; if (!stat) /* expect more dirs, but this not a dir */ continue; lock = CurrentDir (Clock = dp->lock); search = malloc(strlen(name)+strlen(tail)+2); strcpy (search, name); strcat (search, "/"); strcat (search, tail); scrav = alt_av = expand (search, &alt_ac); CurrentDir (Clock = lock); if (scrav) { while (*scrav) { if (eleft < 2) { char **scrav = (char **)malloc(sizeof(char *) * (eac + 10)); bmov (eav, scrav, (eac + 1) << 2); free (eav); eav = scrav; eleft = 10; } eav[eac] = malloc(strlen(bname)+strlen(*scrav)+1); strcpy(eav[eac], bname); strcat(eav[eac], *scrav); free (*scrav); ++scrav; --eleft, ++eac; } free (alt_av); } } else { if (eleft < 2) { char **scrav = (char **)malloc(sizeof(char *) * (eac + 10)); bmov (eav, scrav, (eac + 1) << 2); free (eav); eav = scrav; eleft = 10; } eav[eac] = malloc (strlen(bname)+strlen(name)+1); eav[eac] = strcpy(eav[eac], bname); strcat(eav[eac], name); --eleft, ++eac; } } } dclose (dp); *pac = eac; eav[eac] = '\0'; free (bname); free (base); if (eac) return (eav); free (eav); return (NULL); } /* * Compare a wild card name with a normal name */ #define MAXB 8 compare_ok(wild, name) char *wild, *name; { char *w = wild; char *n = name; char *back[MAXB][2]; int bi = 0; while (*n || *w) { switch (*w) { case '*': if (bi == MAXB) { fprintf (stderr,"Too many levels of '*'\n"); return (0); } back[bi][0] = w; back[bi][1] = n; ++bi; ++w; continue; goback: --bi; while (bi >= 0 && *back[bi][1] == '\0') --bi; if (bi < 0) return (0); w = back[bi][0] + 1; n = ++back[bi][1]; ++bi; continue; case '?': if (!*n) { if (bi) goto goback; return (0); } break; default: if (tolower(*n) != tolower(*w)) { if (bi) goto goback; return (0); } break; } if (*n) ++n; if (*w) ++w; } return (1); } SHAR_EOF if test 9889 -ne "`wc -c sub.c`" then echo shar: error transmitting sub.c '(should have been 9889 characters)' fi echo shar: extracting main.c cat << \SHAR_EOF > main.c /* * MAIN.C * * Matthew Dillon, 24 Feb 1986 * * el main routine. */ #include "shell.h" #define STDBUF 256 extern long SetSignal(); extern char *btocstr(); extern char Dir_name[]; extern struct FileLock *Clock; char Inline[256]; char stdin_buff[STDBUF]; char stdout_buff[STDBUF]; main(argc, argv) register char *argv[]; { char *prompt; register int i; extern int Enable_Abort; init_vars(); init(); getcd(); Enable_Abort = 0; for (i = 1; i < argc; ++i) { strcpy (Inline, "source "); strcat (Inline, argv[i]); do_source (Inline, 0); } for (;;) { if ((prompt = get_var (LEVEL_SET, V_PROMPT)) == NULL) prompt = "echo -n \"$ \""; if (breakcheck()) { while (WaitForChar(Input(), 1L)) gets(Inline); } ++H_stack; exec_command (prompt); --H_stack; if (Quit || !gets(Inline)) main_exit(0); breakreset(); if (*Inline) exec_command(Inline); fflush(stdout); } } init_vars() { if (IsInteractive(Input())) set_var (LEVEL_SET, V_PROMPT, "echo -n \"$ \""); else set_var (LEVEL_SET, V_PROMPT, ""); set_var (LEVEL_SET, V_HIST, "20"); set_var (LEVEL_SET, V_LASTERROR, "0"); } init() { static char pipe1[32], pipe2[32]; struct Process *FindTask(); Myprocess = FindTask(0L); stdin->_buff = stdin_buff; stdin->_buflen = STDBUF; stdout->_buff = stdout_buff; stdout->_buflen = STDBUF; Uniq = (long)Myprocess; Pipe1 = pipe1; Pipe2 = pipe2; sprintf (pipe1, "ram:pipe1_%ld", Uniq); sprintf (pipe2, "ram:pipe2_%ld", Uniq); } main_exit(n) { exit (n); } breakcheck() { if (SetSignal(0L,0L) & SIGBREAKF_CTRL_C) return (1); else return (0); } breakreset() { SetSignal(0L, SIGBREAKF_CTRL_C); } /* set the current lock and extract the cd'd string */ getcd() { Clock = (struct FileLock *)( (ULONG)Myprocess->pr_CurrentDir); if (!Clock) exec_command("cd DF0:"); /* must be boot device */ btocstr( ((struct CommandLineInterface *)BADDR(Myprocess->pr_CLI))->cli_SetName, Dir_name); } /* this routine causes manx to use this Chk_Abort() rather than it's own */ /* otherwise it resets our ^C when doing any I/O (even when Enable_Abort */ /* is zero). Since we want to check for our own ^C's */ Chk_Abort() { return(0); } SHAR_EOF if test 2407 -ne "`wc -c main.c`" then echo shar: error transmitting main.c '(should have been 2407 characters)' fi echo shar: extracting globals.c cat << \SHAR_EOF > globals.c /* * GLOBALS.C * * Matthew Dillon, 24 Feb 1986 * */ #include "shell.h" struct HIST *H_head, *H_tail; struct PERROR Perror[] = { 103, "insufficient free storage", 105, "task table full", 120, "argument line invalid or too long", 121, "file is not an object module", 122, "invalid resident library during load", 201, "no default directory", 202, "object in use", 203, "object already exists", 204, "directory not found", 205, "object not found", 206, "bad stream name", 207, "object too large", 209, "action not known", 210, "invalid stream component name", 211, "invalid object lock", 212, "object not of required type", 213, "disk not validated", 214, "disk write protected", 215, "rename across devices", 216, "directory not empty", 217, "too many levels", 218, "device not mounted", 219, "seek error", 220, "comment too long", 221, "disk full", 222, "file delete protected", 223, "file write protected", 224, "file read protected", 225, "not a DOS disk", 226, "no disk", 232, "no more entries in directory", /* custom error messages */ 500, "bad arguments", 501, "label not found", 502, "must be within source file", 503, "Syntax Error", 504, "redirection error", 505, "pipe error", 506, "too many arguments", 0, NULL }; char *av[MAXAV]; long Src_base[MAXSRC]; long Src_pos[MAXSRC]; char If_base[MAXIF]; int H_len, H_tail_base, H_stack; int Src_stack, If_stack; int ac; int Debug, Rval, Disable, Faillevel, Verbose; int Quit; long Cout, Cin; /* current input and output file handles */ long Uniq; /* unique value */ struct Process *Myprocess; char *Cin_name, *Cout_name; /* redirection input/output name or NULL */ char *Pipe1, *Pipe2; /* the two pipe temp. files */ int S_histlen = 20; SHAR_EOF if test 1953 -ne "`wc -c globals.c`" then echo shar: error transmitting globals.c '(should have been 1953 characters)' fi echo shar: extracting comm1.c cat << \SHAR_EOF > comm1.c /* * COMM1.C * * Matthew Dillon, August 1986 * version 2.01A (Manx ver) by Steve Drew 27 Sep 1986 * * * */ #include "shell.h" #define DIR_SHORT 0x01 #define DIR_FILES 0x02 #define DIR_DIRS 0x04 #define BPTR_TO_C(strtag, var) ((struct strtag *)(BADDR( (ULONG) var))) #define C_TO_BPTR(strtag, var) ((struct strtag *)(((ULONG)var)>>2)) extern struct FileLock *CreateDir(), *CurrentDir(), *ParentDir(); extern struct FileLock *Lock(), *DupLock(); extern char *AllocMem(); extern struct FileHandle *Open(); extern char *btocstr(); extern int has_wild; char Dir_name[60]; struct FileLock *Clock; do_sleep() { register int i; if (ac == 2) { i = atoi(av[1]); while (i > 0) { Delay ((long)50*2); i -= 2; if (CHECKBREAK()) break; } } return (0); } do_number() { return (0); } do_cat() { FILE *fopen(), *fi; int i; char buf[256]; if (ac == 1) { while (gets(buf)) { if (CHECKBREAK()) break; puts(buf); } clearerr(stdin); return (0); } for (i = 1; i < ac; ++i) { if ((fi = fopen (av[i], "r")) != 0) { while (fgets(buf,256,fi)) { fputs(buf,stdout); fflush(stdout); if (CHECKBREAK()) break; } fclose (fi); } else { fprintf (stderr, "could not open %s\n", av[i]); } } return (0); } /* things shared with disp_entry */ int filecount, col; long bytes, blocks; do_dir(garbage, com) char *garbage; { void disp_entry(); struct DPTR *dp; struct InfoData *info; char *name; int i = 0, stat, clen, more; char options = 0; char *c; char lspec[60]; char volume[40]; char *volname(); char *dates(); col = filecount = 0; bytes = blocks = 0L; while((++i < ac) && (av[i][0] == '-')) { for (c = av[i]+1; *c ; c++) { switch(*c) { case 's': options |= DIR_SHORT; break; case 'f': options |= DIR_FILES; break; case 'd': options |= DIR_DIRS; break; default: break; } } } if (ac == i) { ++ac; av[i] = ""; if (has_wild) return(0); } if (!(options & (DIR_FILES | DIR_DIRS))) options |= (DIR_FILES | DIR_DIRS); for (; i < ac; ++i) { if (!(dp = dopen (av[i], &stat))) continue; if (com < 0) { info = (struct InfoData *)AllocMem((long)sizeof(struct InfoData), MEMF_PUBLIC); if (Info (dp->lock, info)) { printf ("Unit:%2ld Errs:%3ld Used: %-4ld %3ld%% Free: %-4ld Volume: %s\n", info->id_UnitNumber, info->id_NumSoftErrors, info->id_NumBlocksUsed, (info->id_NumBlocksUsed * 100)/ info->id_NumBlocks, (info->id_NumBlocks - info->id_NumBlocksUsed), volname(dp->lock,volume)); } else { perror (av[i]); } FreeMem (info,(long) sizeof(*info)); dclose(dp); continue; return(0); } /* start of directory routine */ c = av[i]; clen = strlen(c); if (!stat || has_wild) { /* if not wild and is a dir don't */ /* extract dir from file name */ while (clen && c[clen] != '/' && c[clen] != ':') clen--; if (c[clen] == ':' || c[clen] == '/') clen++; c[clen] = '\0'; } if (!clen) c = Dir_name; if (strcmp (c, &lspec) != 0) { strcpy(lspec, c); if (col) printf("\n"); printf ("Directory of %s\n", lspec); fflush(stdout); col = 0; } more = stat; do { if (more && !has_wild) { *lspec = '\0'; if (!(more = dnext(dp, &name, &stat))) break; } if (CHECKBREAK()) { i = ac; break; } disp_entry (dp->fib, options); } while(more && !has_wild); dclose(dp); } /* end for */ if (col) printf("\n"); if (filecount > 1) { blocks += filecount; /* account for dir blocks */ printf (" %ld Blocks, %ld Bytes used in %ld files\n", blocks, bytes, filecount); } return (0); } char * volname(lock,buf) struct FileLock *lock; char *buf; { struct DeviceList *dl; char *p; Forbid(); /* Only way I know to get Volume label since InfoData */ /* seems to always have NULL for this string */ lock = BPTR_TO_C(FileLock, lock); dl = BPTR_TO_C(DeviceList, lock->fl_Volume); p = btocstr(dl->dl_Name,buf); Permit(); return p; } void disp_entry(fib, options) char options; register struct FileInfoBlock *fib; { char str[5]; int italics; if (!(((options & DIR_FILES) && (fib->fib_DirEntryType < 0)) || ((options & DIR_DIRS) && (fib->fib_DirEntryType > 0)))) return; if (!(options & DIR_SHORT)) { str[4] = '\0'; str[0] = (fib->fib_Protection & FIBF_READ) ? '-' : 'r'; str[1] = (fib->fib_Protection & FIBF_WRITE) ? '-' : 'w'; str[2] = (fib->fib_Protection & FIBF_EXECUTE) ? '-' : 'e'; str[3] = (fib->fib_Protection & FIBF_DELETE) ? '-' : 'd'; printf (" %-24s %s ", fib->fib_FileName, str); if (fib->fib_DirEntryType < 0) printf("%6ld %4ld", (long)fib->fib_Size, (long)fib->fib_NumBlocks); else printf(" Dir "); printf(" %s", dates(&fib->fib_Date)); fflush(stdout); } else { if ((col == 2) && strlen(fib->fib_FileName)>18) { printf("\n"); col = 0; } if (fib->fib_DirEntryType > 0) { printf ("\033[3m"); italics = 1; } if (strlen(fib->fib_FileName)>18) { printf(" %-37s",fib->fib_FileName); col += 2; } else { printf(" %-18s",fib->fib_FileName); col++; } if (col > 3) { printf("\n"); col = 0; } if (italics) printf("\033[0m"); } fflush(stdout); blocks += fib->fib_NumBlocks; bytes += fib->fib_Size; filecount++; return; } /* converts dos date stamp to a time string of form dd-mmm-yy */ char * dates(dss) struct DateStamp *dss; { register struct tm tm; register long time, t; register int i; static char timestr[20]; static char months[12][4] = { "Jan","Feb","Mar","Apr","May","Jun", "Jul","Aug","Sep","Oct","Nov","Dec" }; static char days[12] = { 31,28,31,30,31,30,31,31,30,31,30,31 }; time = dss->ds_Days * 24 * 60 * 60 + dss->ds_Minute * 60 + dss->ds_Tick/TICKS_PER_SECOND; tm.tm_sec = time % 60; time /= 60; tm.tm_min = time % 60; time /= 60; tm.tm_hour= time % 24; time /= 24; tm.tm_wday= time % 7; tm.tm_year= 78 + (time/(4*365+1)) * 4; time %= 4 * 365 + 1; while (time) { t = 365; if ((tm.tm_year&3) == 0) t++; if (time < t) break; time -= t; tm.tm_year++; } tm.tm_yday = ++time; for (i=0;i<12;i++) { t = days[i]; if (i == 1 && (tm.tm_year&3) == 0) t++; if (time <= t) break; time -= t; } tm.tm_mon = i; tm.tm_mday = time; sprintf(timestr,"%02d-%s-%2d %02d:%02d:%02d\n",tm.tm_mday, months[tm.tm_mon],tm.tm_year, tm.tm_hour,tm.tm_min,tm.tm_sec); return(timestr); } date() { struct DateStamp dss; char *s, *dates(); DateStamp(&dss); s = dates(&dss); printf("%s",s); } do_quit() { if (Src_stack) { Quit = 1; return(do_return()); } main_exit (0); } do_echo(str) char *str; { register char *ptr; char nl = 1; for (ptr = str; *ptr && *ptr != ' '; ++ptr); if (*ptr == ' ') ++ptr; if (av[1] && strcmp (av[1], "-n") == 0) { nl = 0; ptr += 2; if (*ptr == ' ') ++ptr; } printf("%s",ptr); fflush(stdout); if (nl) printf("\n"); return (0); } do_source(str) char *str; { register int; register FILE *fi; char buf[256]; if (Src_stack == MAXSRC) { fprintf (stderr,"Too many source levels\n"); return(-1); } if ((fi = fopen (next_word(str), "r")) == 0) { fprintf (stderr,"Cannot open %s\n", next_word(str)); return(-1); } ++H_stack; Src_pos[Src_stack] = 0; Src_base[Src_stack] = (long)fi; ++Src_stack; while (fgets (buf, 256, fi)) { buf[strlen(buf)-1] = '\0'; Src_pos[Src_stack - 1] += 1+strlen(buf); if (Verbose) fprintf(stderr,"%s\n",buf); exec_command (buf); if (CHECKBREAK()) break; } --H_stack; --Src_stack; unset_level(LEVEL_LABEL + Src_stack); fclose (fi); return (0); } do_cd() { register char *s; int i; struct FileLock *tmplock; struct FileInfoBlock fib; char temp[60]; char *index(); if (Clock) getcd(); /* in case someone did a C:CD dir */ strcpy(temp, Dir_name); if (ac != 2) puts(Dir_name); else { s = av[1]; if (*s == '/') { while (*s == '/') { s++; for (i=strlen(Dir_name)-2; Dir_name[i] != '/' && Dir_name[i] != ':' && i; i--); Dir_name[i+1] = '\0'; } strcat(Dir_name, s); } else if (index(s, ':') == 0) { if (Dir_name[strlen(Dir_name)-1] != ':') strcat(Dir_name, "/"); strcat(Dir_name, s); } else strcpy(Dir_name, s); tmplock = Lock(Dir_name, ACCESS_READ); if (tmplock == 0) { fprintf (stderr,"not found\n"); strcpy(Dir_name, temp); return(-1); } else { if (Examine(tmplock,&fib)) { if (fib.fib_DirEntryType > 0) { Clock = tmplock; if (tmplock = CurrentDir(Clock)) UnLock(tmplock); if (Dir_name[strlen(Dir_name)-1] == '/') Dir_name[strlen(Dir_name)-1] = '\0'; if (s = index(Dir_name,':')) strcpy(Dir_name, strcat(volname(Clock,temp),s)); /* put the current dir name in our CLI task structure */ s = (char *)((ULONG)((struct CommandLineInterface *) BADDR(Myprocess->pr_CLI))->cli_SetName << 2); s[0] = strlen(Dir_name); movmem(Dir_name,s+1,(int)s[0]); } else { fprintf(stderr,"not a directory\n"); return(-1); } } else return(-1); } } return(0); } do_mkdir() { register int i; register struct FileLock *lock; for (i = 1; i < ac; ++i) { if (lock = CreateDir (av[i])) { UnLock (lock); continue; } perror (av[i]); } return (0); } do_mv() { if (Rename (av[1], av[2])) return (0); perror (NULL); return (-1); } do_rm() { register int i; for (i = 1; i < ac; ++i) { if (ac !=2) printf(" %s...",av[i]); fflush(stdout); if (CHECKBREAK()) break; if (!DeleteFile(av[i])) perror (av[i]); else { if (ac !=2) printf("Deleted\n"); } } return (0); } do_history() { register struct HIST *hist; register int i = H_tail_base; register int len = (av[1]) ? strlen(av[1]) : 0; for (hist = H_tail; hist; hist = hist->prev) { if (len == 0 || strncmp(av[1], hist->line, len) == 0) { printf ("%3ld ", i); puts (hist->line); } ++i; if (CHECKBREAK()) break; } return (0); } do_mem() { long cfree, ffree; extern long AvailMem(); Forbid(); cfree = AvailMem (MEMF_CHIP); ffree = AvailMem (MEMF_FAST); Permit(); if (ffree) { printf ("FAST memory: %ld\n", ffree); printf ("CHIP memory: %ld\n", cfree); } printf ("Total Free: %ld\n", cfree + ffree); } /* * foreach var_name ( str str str str... str ) commands * spacing is important (unfortunetly) * * ac=0 1 2 3 4 5 6 7 * foreach i ( a b c ) echo $i * foreach i ( *.c ) "echo -n "file ->";echo $i" */ do_foreach() { register int i, cstart, cend, old; register char *cstr, *vname, *ptr, *scr, *args; cstart = i = (*av[2] == '(') ? 3 : 2; while (i < ac) { if (*av[i] == ')') break; ++i; } if (i == ac) { fprintf (stderr,"')' expected\n"); return (-1); } ++H_stack; cend = i; vname = strcpy(malloc(strlen(av[1])+1), av[1]); cstr = compile_av (av, cend + 1, ac); ptr = args = compile_av (av, cstart, cend); while (*ptr) { while (*ptr == ' ' || *ptr == 9) ++ptr; scr = ptr; if (*scr == '\0') break; while (*ptr && *ptr != ' ' && *ptr != 9) ++ptr; old = *ptr; *ptr = '\0'; set_var (LEVEL_SET, vname, scr); if (CHECKBREAK()) break; exec_command (cstr); *ptr = old; } --H_stack; free (args); free (cstr); unset_var (LEVEL_SET, vname); free (vname); return (0); } do_copy() { struct DPTR *dp; char tofile[60],todir[60]; int i, stat, fstat; char *p; todir[0] = '\0'; --ac; if (ac == 1) strcpy(todir, Dir_name); else if (ac == 2) { strcpy(todir, av[ac]); } else { strcpy (todir,av[ac]); --ac; if (strcmp(av[ac],"to") && strcmp(av[ac],"TO")) ++ac; } stat = 0; if (ac == 1) ++ac; dp = dopen (todir, &stat); dclose(dp); for (i = 1;i < ac; ++i) { if (stat) { if (todir[strlen(todir)-1] != '/' && todir[strlen(todir)-1] != ':') strcat(todir,"/"); strcpy(tofile, todir); p = &av[i][strlen(av[i])-1]; while (p != av[i] && *p != ':' && *p != '/') p--; if (*p == ':' || *p == '/') p++; strcat(tofile, p); } else { strcpy(tofile, todir); if (ac > 2) { fprintf (stderr,"Copy error: %s is not a directory\n", todir); return(0); } } /* if from file is a dir name don't copy */ dp = dopen(av[i], &fstat); dclose(dp); if (fstat) continue; printf("copying %s to %s....", av[i], tofile); fflush(stdout); if (!file_copy(av[i], tofile)) printf("[ok]\n"); if (CHECKBREAK()) { return(0); } } } file_copy(s, tofile) char *s, *tofile; { struct FileHandle *copyin; struct FileHandle *copyout; long size; long actual; int ok = 1; char *copybuf; copyin = Open(s, MODE_OLDFILE); if (copyin == 0L) perror(s); else { copyout = Open(tofile, MODE_NEWFILE); if (copyout == 0) { perror(tofile); Close(copyin); } else { size = Seek(copyin, 0L, OFFSET_END); size = Seek(copyin, 0L, OFFSET_BEGINING); if (size != 0L) { /* if zero length close em */ do { copybuf = AllocMem(size, MEMF_PUBLIC|MEMF_CLEAR); if (copybuf == 0L) size = size/2; } while (copybuf == 0L & size > 512); if (copybuf == 0L) { fprintf(stderr,"Copy Error: Not Enough Memory\n"); } else do { ok = 0; actual = Read(copyin, copybuf, size); if (Write(copyout, copybuf, actual) != actual) { ok = perror(NULL); break; } } while (actual == size); } Close(copyin); Close(copyout); FreeMem(copybuf, size); if (size == 0L) ok = 0; } } return(ok); } SHAR_EOF if test 16361 -ne "`wc -c comm1.c`" then echo shar: error transmitting comm1.c '(should have been 16361 characters)' fi echo shar: extracting run.c cat << \SHAR_EOF > run.c /* * RUN.C * * Steve Drew 24-sep-86 * */ #include "shell.h" do_run(str) char *str; { int i; #if USE_FEXEC struct CommandLineInterface *cli; av[ac] = '\0'; i = fexecv(av[0],&av[0]); /* the next few lines solve a bug with fexecv and bcpl programs */ /* that muck up the input/output streams which causes GURUs */ cli = (struct CommandLineInterface *)((long)Myprocess->pr_CLI << 2); Myprocess->pr_CIS = cli->cli_StandardInput; Myprocess->pr_COS = cli->cli_StandardOutput; if (i) { fprintf(stderr,"Command not found :%s\n",av[0]); return(-1); } return(wait()); #endif #if USE_EXECUTE i = Execute(str, 0L, 0L); return ((i) ? 0 : -1); #endif } SHAR_EOF if test 742 -ne "`wc -c run.c`" then echo shar: error transmitting run.c '(should have been 742 characters)' fi echo shar: extracting execom.c cat << \SHAR_EOF > execom.c /* * EXECOM.C * * Matthew Dillon, 10 August 1986 * Finally re-written. * * version 2.01A (Manx ver) by Steve Drew 27 Sep 1986 * */ #include "shell.h" #define F_EXACT 0 #define F_ABBR 1 #define ST_COND 0x01 #define ST_NAME 0x02 int has_wild = 0; /* set if any arg has wild card */ struct _dev { long fd; short mode; }; struct COMMAND { int (*func)(); short minargs; short stat; int val; char *name; }; extern char *format_insert_string(); extern char *mpush(), *exarg(); extern int do_run(), do_number(); extern int do_quit(), do_set_var(), do_unset_var(); extern int do_echo(), do_source(), do_mv(); extern int do_cd(), do_rm(), do_mkdir(), do_history(); extern int do_mem(), do_cat(), do_dir(); extern int do_foreach(), do_return(), do_if(), do_label(), do_goto(); extern int do_failat(), do_checkbrk(), do_inc(); extern int do_input(), do_ver(), do_sleep(), do_help(); extern int do_strhead(), do_strtail(); extern int do_copy(), date(), do_ps(); static struct COMMAND Command[] = { #if USE_FEXEC do_run , 0, 0, 0 , "\001", #endif #if USE_EXECUTE do_run , 0, ST_NAME, 0 , "\001", #endif do_number , 0, 0, 0 , "\001", #if USE_FEXEC do_run , 0, ST_NAME, 0 , "run", #endif do_quit , 0, 0, 0 , "quit", do_set_var , 0, 0, LEVEL_SET , "set", do_unset_var, 0, 0, LEVEL_SET , "unset", do_set_var , 0, 0, LEVEL_ALIAS, "alias", do_unset_var, 0, 0, LEVEL_ALIAS, "unalias", do_echo , 0, 0, 0 , "echo", do_source , 0, 0, 0 , "source", do_mv , 2, 0, 0 , "mv", do_cd , 0, 0, 0 , "cd", do_rm , 0, 0, 0 , "rm", do_mkdir , 0, 0, 0 , "mkdir", do_history , 0, 0, 0 , "history", do_mem , 0, 0, 0 , "mem", do_cat , 0, 0, 0 , "cat", do_dir , 0, 0, 0 , "dir", do_dir , 0, 0, -1 , "devinfo", do_foreach , 3, 0, 0 , "foreach", do_return , 0, 0, 0 , "return", do_if , 1, ST_COND, 0 , "if", do_if , 0, ST_COND, 1 , "else", do_if , 0, ST_COND, 2 , "endif", do_label , 1, ST_COND, 0 , "label", do_goto , 1, 0, 0 , "goto", do_failat , 1, 0, 0 , "failat", do_checkbrk , 0, 0, 0 , "checkbreak", do_strhead , 3, 0, 0 , "strhead", do_strtail , 3, 0, 0 , "strtail", do_inc , 1, 0, 1 , "inc", do_inc , 1, 0, -1, "dec", do_input , 1, 0, 0, "input", do_ver , 0, 0, 0, "version", do_sleep , 0, 0, 0, "sleep", do_help , 0, 0, 0, "help", do_copy , 1, 0, 0, "copy", date , 0, 0, 0, "date", do_ps , 0, 0, 0, "ps", '\0' , 0, 0, 0 , NULL }; static unsigned char elast; /* last end delimeter */ static char Cin_ispipe, Cout_ispipe; exec_command(base) char *base; { register char *scr; register int i; if (!H_stack) add_history(base); scr = malloc((strlen(base) << 2) + 2); /* 4X */ preformat(base, scr); i = fcomm(scr, 1); return ((i) ? -1 : 1); } isalphanum(c) { if (c >= '0' && c <= '9') return (1); if (c >= 'a' && c <= 'z') return (1); if (c >= 'A' && c <= 'Z') return (1); if (c == '_') return (1); return (0); } preformat(s, d) register char *s, *d; { register int si, di, qm; si = di = qm = 0; while (s[si] == ' ' || s[si] == 9) ++si; while (s[si]) { if (qm && s[si] != '\"' && s[si] != '\\') { d[di++] = s[si++] | 0x80; continue; } switch (s[si]) { case ' ': case 9: d[di++] = ' '; while (s[si] == ' ' || s[si] == 9) ++si; if (s[si] == 0 || s[si] == '|' || s[si] == ';') --di; break; case '*': case '?': d[di++] = 0x80; case '!': d[di++] = s[si++]; break; case ';': case '|': d[di++] = s[si++]; while (s[si] == ' ' || s[si] == 9) ++si; break; case '\\': d[di++] = s[++si] | 0x80; if (s[si]) ++si; break; case '\"': qm = 1 - qm; ++si; break; case '^': d[di++] = s[++si] & 0x1F; if (s[si]) ++si; break; case '$': /* search end of var name and place false space */ d[di++] = 0x80; d[di++] = s[si++]; while (isalphanum(s[si])) d[di++] = s[si++]; d[di++] = 0x80; break; default: d[di++] = s[si++]; break; } } d[di++] = 0; d[di] = 0; if (Debug & 0x01) { fprintf (stderr,"PREFORMAT: %ld :%s:\n", strlen(d), d); } } /* * process formatted string. ' ' is the delimeter. * * 0: check '\0': no more, stop, done. * 1: check $. if so, extract, format, insert * 2: check alias. if so, extract, format, insert. goto 1 * 3: check history or substitution, extract, format, insert. goto 1 * * 4: assume first element now internal or disk based command. * * 5: extract each ' ' or 0x80 delimited argument and process, placing * in av[] list (except 0x80 args appended). check in order: * * '$' insert string straight * '>' setup stdout * '<' setup stdin * '*' or '?' do directory search and insert as separate args. * * ';' 0 '|' end of command. if '|' setup stdout * -execute command, fix stdin and out (|) sets * up stdin for next guy. */ fcomm(str, freeok) register char *str; { register char *istr; char *nextstr; char *command; char *pend_alias = '\0'; /* pending alias */ char err = 0; mpush_base(); if (*str == 0) goto done1; step1: if (*str == '$') { if (istr = get_var (LEVEL_SET, str + 1)) str = format_insert_string(str, istr, &freeok); } istr = get_var (LEVEL_ALIAS, str); if (istr) { if (*istr == '%') { pend_alias = istr; } else { str = format_insert_string(str, istr, &freeok); goto step1; } } if (*str == '!') { istr = get_history(str); replace_head(istr); str = format_insert_string(str, istr, &freeok); goto step1; } nextstr = str; command = exarg(&nextstr); if (*command == 0) goto done0; if (pend_alias == 0) { register int ccno; ccno = find_command(command); if (Command[ccno].stat & ST_COND) goto skipgood; } if (Disable) goto done0; skipgood: { register char *arg, *ptr, *scr; short redir; short doexpand; short cont; short inc; ac = 1; av[0] = command; step5: /* ac = nextac */ if (!elast || elast == ';' || elast == '|') goto stepdone; av[ac] = '\0'; cont = 1; doexpand = redir = inc = has_wild = 0; while (cont && elast) { ptr = exarg(&nextstr); inc = 1; arg = ""; cont = (elast == 0x80); switch (*ptr) { case '<': redir = -2; case '>': if ((Command[find_command(command)].stat & ST_NAME) != 0) { /* don't extract */ redir = 0; /* <> stuff if its */ arg = ptr; /* external cmd. */ break; } ++redir; arg = ptr + 1; cont = 1; break; case '$': if ((arg = get_var(LEVEL_SET, ptr + 1)) == NULL) arg = ptr; break; case '*': case '?': doexpand = 1; arg = ptr; break; default: arg = ptr; break; } /* Append arg to av[ac] */ for (scr = arg; *scr; ++scr) *scr &= 0x7F; if (av[ac]) { register char *old = av[ac]; av[ac] = mpush(strlen(arg)+1+strlen(av[ac])); strcpy(av[ac], old); strcat(av[ac], arg); } else { av[ac] = mpush(strlen(arg)+1); strcpy(av[ac], arg); } if (elast != 0x80) break; } /* process expansion */ if (doexpand) { char **eav, **ebase; int eac; has_wild = 1; eav = ebase = expand(av[ac], &eac); if (eav) { inc = 0; if (ac + eac + 2 > MAXAV) { ierror (NULL, 506); err = 1; } else { for (; eac; --eac, ++eav) av[ac++] = strcpy(mpush(strlen(*eav)+1), *eav); } free_expand (ebase); } /* else { fprintf (stderr,"null expansion\n"); err = 1; } */ } /* process redirection */ if (redir && !err) { register char *file = (doexpand) ? av[--ac] : av[ac]; if (redir < 0) Cin_name = file; else Cout_name = file; inc = 0; } /* check elast for space */ if (inc) { ++ac; if (ac + 2 > MAXAV) { ierror (NULL, 506); err = 1; /* error condition */ elast = 0; /* don't process any more arguemnts */ } } if (elast == ' ') goto step5; } stepdone: av[ac] = '\0'; /* process pipes via files */ if (elast == '|' && !err) { static int which; /* 0 or 1 in case of multiple pipes */ which = 1 - which; Cout_name = (which) ? Pipe1 : Pipe2; Cout_ispipe = 1; } /* DO COMMAND HERE! */ if (err) goto done0; { register int i, len; char save_elast; char *avline; save_elast = elast; for (i = len = 0; i < ac; ++i) len += strlen(av[i]) + 1; avline = malloc(len+1); for (len = 0, i = ((pend_alias) ? 1 : 0); i < ac; ++i) { if (Debug & 0x02) { fprintf (stderr, "AV[%2ld] %ld :%s:\n", i, strlen(av[i]), av[i]); } strcpy(avline + len, av[i]); len += strlen(av[i]); if (i + 1 < ac) avline[len++] = ' '; } avline[len] = 0; if (pend_alias) { /* special % alias */ register char *ptr, *scr; for (ptr = pend_alias; *ptr && *ptr != ' '; ++ptr); set_var (LEVEL_SET, pend_alias + 1, avline); free (avline); scr = malloc((strlen(ptr) << 2) + 2); preformat (ptr, scr); fcomm (scr, 1); unset_var (LEVEL_SET, pend_alias + 1); } else { /* normal command */ register int ccno; long oldcin, oldcout, oldstdout, oldstdin; extern struct _dev _devtab[]; char retcode[12]; struct _dev *stdfp; fflush(stdout); ccno = find_command (command); if ((Command[ccno].stat & ST_NAME) == 0) { if (Cin_name) { if ((Cin = (long)Open(Cin_name,1005)) == 0L) { ierror (NULL, 504); err = 1; Cin_name = '\0'; } else { oldcin = (long)Input(); Myprocess->pr_CIS = Cin; _devtab[stdin->_unit].fd = Cin; } } if (Cout_name) { if ((Cout = (long)Open(Cout_name,1006)) == 0L) { err = 1; ierror (NULL, 504); Cout_name = '\0'; } else { oldcout = (long)Output(); Myprocess->pr_COS = Cout; _devtab[stdout->_unit].fd = Cout; } } } if (ac < Command[ccno].minargs + 1) { ierror (NULL, 500); err = 1; } else if (!err) { if (Debug & 0x01) { fprintf(stderr,"Command = :%s:\n",avline); } err = (*Command[ccno].func)(avline, Command[ccno].val); if (err != 0) { sprintf(retcode,"%d",err); set_var (LEVEL_SET, V_LASTERROR, retcode); } } free (avline); if ((Command[ccno].stat & ST_NAME) == 0) { if (Cin_name) { fflush(stdin); clearerr(stdin); Close(Cin); Myprocess->pr_CIS = _devtab[stdin->_unit].fd = oldcin; } if (Cout_name) { fflush(stdout); clearerr(stdout); Close(Cout); Myprocess->pr_COS = _devtab[stdout->_unit].fd = oldcout; } } } if (Cin_ispipe && Cin_name) DeleteFile(Cin_name); if (Cout_ispipe) { Cin_name = Cout_name; /* ok to assign.. static name */ Cin_ispipe = 1; } else { Cin_name = '\0'; } Cout_name = '\0'; Cout_ispipe = 0; elast = save_elast; } mpop_tobase(); /* free arguments */ mpush_base(); /* push dummy base */ done0: if (elast != 0 && !err) /* done? or more? */ err = fcomm(nextstr, 0); /* do next command ';' or '|' sep. */ if (Cin_name) /* pipe segment complete */ DeleteFile(Cin_name); Cin_name = '\0'; Cin_ispipe = 0; done1: mpop_tobase(); if (freeok) free(str); return ((int)err); /* TRUE = error occured */ } char * exarg(ptr) unsigned char **ptr; { register unsigned char *end; register unsigned char *start; start = end = *ptr; while (*end && *end != 0x80 && *end != ';' && *end != '|' && *end != ' ') ++end; elast = *end; *end = '\0'; *ptr = end + 1; return ((char *)start); } static char **Mlist; mpush_base() { char *str; str = malloc(5); *(char ***)str = Mlist; str[4] = 0; Mlist = (char **)str; } char * mpush(bytes) { char *str; str = malloc(5 + bytes); *(char ***)str = Mlist; str[4] = 1; Mlist = (char **)str; return (str + 5); } mpop_tobase() { register char *next; while (Mlist) { next = *Mlist; if (((char *)Mlist)[4] == 0) { free (Mlist); Mlist = (char **)next; break; } free (Mlist); Mlist = (char **)next; } } /* * Insert 'from' string in front of 'str' while deleting the * first entry in 'str'. if freeok is set, then 'str' will be * free'd */ char * format_insert_string(str, from, freeok) char *str; char *from; int *freeok; { register char *new1, *new2; register unsigned char *strskip; int len; for (strskip = (unsigned char *)str; *strskip != '\0' && *strskip != ' ' && *strskip != ';' && *strskip != '|' && *strskip != 0x80; ++strskip); len = strlen(from); new1 = malloc((len << 2) + 2); preformat(from, new1); len = strlen(new1) + strlen(strskip); new2 = malloc(len+2); strcpy(new2, new1); strcat(new2, strskip); new2[len+1] = 0; free (new1); if (*freeok) free (str); *freeok = 1; return (new2); } find_command(str) char *str; { int i; int len = strlen(str); if (*str >= '0' && *str <= '9') return (1); for (i = 0; Command[i].func; ++i) { if (strncmp (str, Command[i].name, len) == 0) { return (i); } } return (0); } do_help() { register struct COMMAND *com; int i= 0; for (com = &Command[2]; com->func; ++com) { printf ("%-12s", com->name); if (++i % 6 == 0) printf("\n"); } printf("\n"); return(0); } SHAR_EOF if test 16212 -ne "`wc -c execom.c`" then echo shar: error transmitting execom.c '(should have been 16212 characters)' fi # End of shell archive exit 0