CM Version 1.10 (c) 1986 Mark E. Mallett December 27, 1986 (June, 1986) A list of all changes from various versions to the next follows this semi-instructive text. Search for "======" to find the change logs. This is a brief description of the CM program, which is a simple shell I have written to bootstrap myself into a development environment, including towards writing a real shell. I am placing it in the public domain partially because I feel that it is useful, and partially to test the reaction to this method of command parsing. React! WARNING: I have been using this program to develop software, and have not been bitten by it. However, I make no guarantees that it is error-free. As a matter of fact, I would be willing to bet that it is not. CM is a toy shell, featuring: - A limited TOPS20 style parsing, - A small set of built-in functions to facilitate software development, - Command history and recall, - Function key bindings, - Ability to execute programs from a specified search path, - Prescanning of the search path to find what programs may be run. - Ability to specify how programs are to be invoked. - Ability to execute indirect files with limited argument substitution. TOPS20 style parsing ---------- TOPS20 is an operating system that runs on DEC's PDP-20 computer systems. It features a very uniform command parsing system that gives a user a lot of help in figuring out what is expected. The basic rules are: - You can type a questionmark anywhere in the command line, and you'll immediately find out what sort of thing you are expected to type, or what the system thinks that you are in the middle of typing. This is called "incremental help". - You can type an ESCAPE character, and the system will attempt to fill out some part of what you are typing, if it has some way of determining this. This is called "completion", and in this program, is only appropriate for the built-in command keywords. A side-effect of successfully completing a field with ESCAPE is that the system will present you with additional information, in parentheses, about what you are typing. These parenthesized bits of information are called "guide strings" (and are themselves subject to completion if you type part of them or backspace over some portion of them). - The DELETE or BACKSPACE keys may be typed to erase the previous character that you typed. - Control-W may be typed to erase the previous word. - Control-U erases the current line. - Control-X erases the current line, in a different way. - Control-H AS THE FIRST THING THAT YOU TYPE will recall the last successfully parsed command or portion of a command. - Control-V prevents the next character from being interpreted specially. Thus to type any of the above characters into a command line, precede it with a control-V. This does not apply to commands in takefiles (indirect command files), except to insert a carriage return, since the above characters are only "special" in an interactive typing mode. Incremental help and completion are (I think) quite useful, and should be played with. Note that any "real" implementation would have program and file name completion as well. Commanding the shell ---------- There are two major things you can do with the shell: execute a built-in command, or run a program from disc. If you type a questiomark at the prompt, you will see that these are your choices. Built-in commands ---------- To execute a built-in command, type the name of the command, or any unique abbreviation of that name, at the prompt. Note that you can type a questionmark to find out what the names of the commands are, or what you can type after the name (should I stop harping on this? Have you got the idea?). If you wish to make sure that what you type is interpreted only as a built-in command, start it with a slash ("/"). This isolates the parsing to built-in commands only, and is recommended for use in command files. A list of the built-in commands, and what they do, follow. These descriptions are minimal; hopefully you can work them out by using incremental help and command completion. Terms used: afs Ambiguous filespec. A single file specification which may contain wildcard characters "*" and "?" (Note, to type a "?" you must precede with control-V, the quoting character.) ufs Unique filespec. A filespec which indicates a single file. List of commands: About [topic] Tells a little bit about CM. Type question mark instead of the topic name to find out what the topics are. Append s(afs) d(ufs) Appends source file(s), specified as an ambiguous filespec, to a single destination file (which may or may not already exist). Cdir dirname Connect to the specified directory. Copy s(afs) d(afs) Copy source files to destination files. Destination may indicate a directory by ending it with "\", or CM will attempt to determine this in spite of a bug in GEMDOS which prevents convenient detection of directory files. Otherwise destination may indicate a template to use in modifying the source filename. For instance, you can copy *.a to *.b, or *.* to x*.*; here, the period is significant in the interpretation of the template. Date [date] If no argument is given, reports the current date and time. If an argument is given, it is used to set the date and time to that specified. The format must be of the form yymmddhhmm.ss (all numeric). The ".ss" is optional. If you just want to set the time, use the format -hhmm.ss Delete afs Delete the specified files. Directory afs [smthd] Give a list of matching files. *.* is defaulted if no name is given. `smthd' is the method of sorting the list of files, and may be one of: "Date-Time", "Extension", "Filename", "Nothing", or "Size". If no sort method is given, the last one you selected is used (initially "Nothing"). Once a sort method has been selected, that sort method is used by CM in all of its directory accesses (such as expanding wildcard filenames in command lines). When a sort method other than "Nothing" is in effect, directories will always be sorted at the beginning of the list of files, followed by all non-directories. Within each group, the sort order applies. Exit Leave CM. If there is an environment variable called "CMEXIT", its value will be taken to be the name of a file to execute as a takefile (see TAKE) before CM exits. Freespace d Show space available on the specified drive. Hash [pstring] With an argument "pstring", CM scans each path in "pstring", adding any programs found to the internal table of known runnable programs (and attributes). Without an argument, CM deletes all its internal information and rescans the values for all environment variables beginning with "CMPATH". Program/path hashing and attributes are discussed further on, along with running programs in general. Inquire prompt Causes CM to prompt for input from the terminal. Indirect (take) files may later reference the string that was typed. Keydef keyname string Create a substitute string for a function key. The function keys are the keys above the keyboard (F0 - F10), and the keys in the arrow bank. After giving this command, when you type the specified key, CM will act as if you typed the substitute string. Type ? after the command to find out what the key names are. If you want to include control characters in the substitution string, precede them with a control-V as mentioned earlier. But if you put these commands in a Take file, don't use the control-V, since that's only a command line editing character, except to quote a carriage return. The UP and DOWN arrow keys may be defined but their substitution string will only be used in terminal mode (the Terminal command). In normal CM mode, these keys are used to scroll through the history of previous commands. Likewise, but oppositely, the UNDO key definition only applies to command mode, since the UNDO key is used to get out of terminal mode. Some keys are bound by default. UNDO is bound to control-X, to erase a line. HELP is "?", to get incremental help. Use the KEYDEF command to find out the default bindings. Mkdir dirname Create a directory with the specified name. Output [filename] This command starts or finishes output redirection. If redirection is being started, a filename must be given; this file name will be used to hold the redirected output of programs that are run, or of certain built-in commands where it makes sense to put the output to a file (directories). In the other mode, where this command finishes redirection, no filename can be entered, and redirection will be ended. NOTE WELL: Use of this command may (will?) give you bombs with some programs that aren't well- behaved, e.g., Lattice C programs. See the note in the change history somewhere in this file. Printenv [mstr] Prints environment variables and their value strings. If any argument "mstr" is given, only strings which match "mstr" are printed. Thus to display all environment variables beginning with CM, do Printenv CM* Likewise, to display any variable or value containing the word "exe", do Printenv *exe* Ptype afs Like the "Type" command. The difference is that this command will pause at the end of each screenful of text and wait for a space key (to continue) or the 'q' key (to quit) to be pressed. Pwdir Prints the current directory name (working directory). Recall [cmdnum|str] Recall a command that has been remembered in the command history list. If a number is given, that number command is recalled. If a string is given, the most recent command starting with the given string is recalled. Rename s(afs) d(afs) Rename source files to destination. Rules for naming are the same as with the Copy command. Rmdir dirname Remove the specified directory. Remenv var-name Removes the specified variable from the environment. Setenv var-name value Sets environment variable "var-name" to the specified value. The value may be blank. Environment variables are kept in alphabetical order. The value is simply some text string that may or may not have meaning to some program (such as CM). Take ufs args... Causes CM to execute the commands in the given filename as if those commands were typed to CM. The rest of the line (args...) is passed as an argument to the command file; everywhere a "$1" is found in the command file, the argument string is substituted. Pretty primitive, I admit. These commands are NOT echoed to the terminal unless the environment variable "CMECHO" is defined. Takefiles may be nested to some arbitrary limit (10). Also, if a "$i" is found in the command file, the last string typed by you in response to the "Inquire" command will be substituted. Within a takefile, any line that begins with an exclamation mark is treated as a comment (i.e., ignored. Isn't that what happens to comments?). Terminal Enter terminal mode, in which you type across the serial port. Exit by typing the UNDO key. Type afs Types out all files matching the filespec. Typeout may be aborted with control-K; control-N will abort the current file and skip to the next. Vdirectory afs [smthd] Verbose directory; same as Directory, but gives file sizes, dates, and modes. Which program CM tells how it would run the program whose name you specify. The program name is specified exactly the way it would be if you were running it, except that no command line arguments are given. Running a program ---------- Running a program is one of the two major things that CM will do (the other being executing built-in commands, as just described). CM has the capability of keeping track of some or all of the names of programs that can be run. It keeps a list of these program names, and you see the list when you type "?". If you want to make sure that you only select names from this list, start your command with "=", and only "internal" programs, as I call them, are selectable. Programs which are not in the list, or "external" programs, can be run as well. CM usually makes the distinction of whether you wish to select an internal vs an external program by whether it finds the name you type in its internal list, however if you wish to specifically run an external program, you may give explicit path information along with the program name. More is said later about how program names get on the internal list. If the command name that you type is not a built-in command, (i.e., you chose an internal or external program name in the manner just described), what you type is the name of a program to run. (If you wish to run a program that has the same name as a built-in command, you have to start your command line with "=", or supply path information, as mentioned in the preceding paragraphs). If the name that you type is not on the internal list, CM may have to try to find out more about the program. For instance, you may type the name of a program without its extension. In this case, CM will apply all of the extensions listed in the value of the environment variable "CMSUFF" until it finds one. Or you may type the name of the program without any indication of what directory it is in. Here, CM will look at all the paths listed in the values of all environment variables that begin with "CMPATH" (applying extensions from "CMSUFF" if necessary). Note well, CM will only look at those paths that aren't absolute, because it is assumed that all absolute path information has already been gathered into the internal program list. (An absolute path is a specific path. Those that aren't absolute are relative to the current directory. The only relative path information generally used is ".", the current directory.) Along with determining the exact program to run (either by looking in the internal list or by scanning the relative paths in CMPATH* variables), CM also must find out some information about how to invoke the program. One thing that is determined is whether it is a program to run, or a file of commands for CM to execute as if you typed them (a takefile, see the "Take" command, above). The rest of the command line, after the program name, is used as an argument that is passed to the program, or to the takefile as described in the "Take" command earlier. If the external name that you type is the name of a directory, not a program, CM will connect to that directory as if you had typed the "Cdir" command. Program path and invocation information ------- ---- --- ---------- ----------- Here, in a rambling way, is the promised information about how program names get on the internal list, and about program attributes. CM recognizes a related set of environment variables that control where programs are found and how they are invoked. The first set of these variables all have names starting with CMPATH. Since all environment variables are kept in alphabetical order, it is easy to temporarily adjust the order of the path by inserting or deleting path information. The value of each CMPATH variable is zero or more path and invocation specifications, like this: path-spec(attr,attr...), path-spec, ... A path spec is a directory name, which implies all files in that directory that have extensions specified in the CMSUFF environment variable, or it is a possibly wildcard file specification, which specifies zero or more specific programs. The attribute list is in parentheses immediately following the path-spec (no spaces!), and consists of zero or more keywords which control how the programs are to be invoked. These attributes are (pay attention!): gem GEM application. tos TOS application. This is the default. cm Takefile, a list of CM commands to be executed. cd Before invoking the program, connect to the directory that contains it. Useful for programs that look for other files when they start. ewf Expand wildcard filenames in the argument string. mwc Use Mark Williams style argument passing. This is a way of passing more than 127 characters (the TOS limit) as a command argument. The arguments are passed in the environment list, which works pretty nicely, except for one extraordinary case, being that an empty token terminates the list. Any program generated with the Mark Williams C package (including CM) can accept arguments this way, or the TOS way. end This means that all of the attributes have been specified for the program, and no more should be looked for (or taken). You don't have to memorize these. If you type "About Invocations" as a CM command, you'll find them there, too. Note that the attribute list is optional. These attributes may also be given along with the program name when you invoke a program that is not in the internal list. The format is the same as just described, i.e., a parenthesized list of attributes immediately following the program name (no spaces!). The order of the path-spec entries in the total path list is important. Programs will be run according to this order. When the "hash" command is given with no arguments, CM clears its internal program list and rebuilds it by scanning the CMPATH* environment variables' values. This is also done when CM is first started and no hash entries are added by the startup command file. All absolute path-specs are looked at, and all programs matching the specifications are put into the internal list. Note, only the FIRST of each root name is placed in the internal list. If there is a TEST.TOS somewhere, and a TEST.PRG is found later, only the first (TEST.TOS) is placed in the internal list. When you specify an internal program name to run, CM scans the path to make see if it can find the program in a relative path earlier than where it was found in the list. For instance, if your path is: ., c:\bin\*.tos, c:\new\(ewf) and a program named TEST.TOS has been internalized from the c:\new area, whenever you type "TEST" as a program to run, CM will look in the current directory first. It is wise to put relative path information at the END of the path, to avoid this sort of overhead. Note Well: relative path information may not contain wildcards. Relative path information must only specify directories, or it won't work. Also Note Well: if you change absolute path information in your path, you must "Hash" it for any effect. And if this weren't confusing enough: CM also maintains a suite of descriptive invocation information. This information is kept as values of all environment variables beginning with "CMINV". It is in the same format as the path information. Whenever CM attempts to run a program, it gets the invocation attributes associated with that program from its path entry, and then scans the CMINV* environment variables for more invocation information. You may use this to specify global attributes that don't necessarily have anything to do with path information. For instance, to specify that all files with an extension of ".MM" are takefiles (CM indirect files), you might have an environment variable CMINV_50 whose value is: *.mm(cm) Or you may wish to indicate that all files from a particular directory tree are to inherit certain attributes, viz: foo\*(ewf,tos) Use the "end" attribute in the path or invocation data to prevent further searching. Initialization and finalization -------------- --- ------------ CM is like any other program; you can pass it arguments on the command line when it starts. Currently it pays attention to: -e nnnn "nnnn" is the size of the environment area, where environment variables are kept (names and values). CM will choose a value that is not smaller than this number. The default is 2048 bytes. When CM starts, it attempts to TAKE a startup file. If there is an environment variable called CMSTART, its value is used as the file to Take. Otherwise, CM attempts to Take a file called "startup.mm" in the current directory, or in the root directory if that fails. After the startup file is executed, if there are no internal program names (that is, if your startup file didn't do a HASH command explicitly), CM hashes the paths from the CMPATH* environment variables, as described above. When CM exits, if there is a variable CMEXIT, its value is used as the name of a file to Take before exiting. Prompts ------- You can control what prompt CM gives you by environment variables. The variable CMPROMPT specifies the main level prompt, and the variable CMTPROMPT specifies the prompt in Takefiles (you'll only see the Takefile prompt if takefile commands are being echoed, i.e. the CMECHO variable is set). These prompt strings may have embedded format codes that are replaced with some meaningful string. Format codes are sort of like printf() codes in C language programs, in that they begin with a percent sign. The following format codes are recognized: %C Command number %D Date %L Indirect file level %N Newline %T Time of day %V CM version number %W Current (working) directory %% Percent The default main level prompt is "CM> "; the default takefile prompt is "%L_CM>> ". For a sample of an alternative set, see the example startup file elsewhere in this document. History ------- CM can record a number of the previous command lines typed, and you can recall these command lines in various ways. Tell CM how many command lines to remember by setting the CMHISTORY environment variable. The command /Setenv CMHISTORY 20 tells CM to remember the last 20 command lines entered. The default is zero, which means that no command lines are remembered. To get a list of the commands that have been remembered, use the "Recall" command with no arguments. To get back a previous command line, use the "Recall" command with an argument. Either give the number of the command to recall, or some string of characters to recall the most recently typed command line beginning with those characters. Use the "!" character as a shorthand for the Recall command. You can also scroll up and down through the command list, in a circular fashion, using the up and down arrow keys on the keyboard. In either recall method (Recall or arrows), CM will redisplay the command as if you had just typed it and were about to press the return. You must hit return to execute it, or you can use the normal command line editing keys to alter it. Command file examples --------- This is a command file, called cc.mm, that was used to compile a program with the Lattice compiler: ==== =lc1 -i\comnd\ -i\works\ -i\lib\ $1 =lc2 $1 ==== The file is invoked as "cc foo", where "foo.c" is the name of the file to compile. Here is a file used to copy a set of software. It is invoked with its argument the name of the directory to copy into. ==== /copy d:\tools\cm\makefile $1 /copy d:\tools\cm\cm.doc $1 /copy d:\tools\cm\*.h $1 /copy d:\tools\cm\*.c $1 ==== Here is an example of a startup file, executed on the outermost invocation of CM: ==== ! This is my initial startup file for CM. Last edit: Dec 18, 1986 ! Setup path and invocation rules. /Setenv CMPATH_50 c:\pkg\mwc\bin, c:\exe\bin, c:\exe\cmshell /Setenv CMINV_10 *.tos(tos), *.ttp(tos), *.prg(gem) /Setenv CMINV_11 *.mm(cm, end) /Setenv CMINV_20 *\echo.tos(ewf, mwc, end) /Setenv CMINV_21 *\more.ttp(ewf, mwc, end) /Setenv CMINV_22 *\touch.ttp(ewf, mwc, end) /Setenv CMINV_40 c:\pkg\mwc\bin\*(tos, ewf, mwc, end) ! Define CMSTART, so that this file won't get run on recursive startups. /Setenv CMSTART c:\exe\cmshell\rstartup.mm ! Define CMEXIT to outer-level exiting routine. /Setenv CMEXIT c:\exe\cmshell\exit.mm ! Random CM environment stuff: /Setenv CMERRABT /Setenv CMHISTORY 20 /Setenv CMPROMPT (value) (%W) #%C: /Setenv CMTPROMPT %L_CM>> ! BMODEM home area for bmodem scripts and ini file. /Setenv BMODEM c:\exe\bmodem ! Define variables that the Mark Williams C package needs. PATH and SUFF ! are also used by BMODEM & others. HOME is a generic. /Setenv HOME c:\ /Setenv PATH .bin,,c:\pkg\mwc\bin,c:\exe\bin,c:\pkg\mwc\lib /Setenv SUFF ,.prg,.tos,.ttp /Setenv LIBPATH c:\pkg\mwc\lib,c:\pkg\mwc\bin,c:\lib, /Setenv TMPDIR c:\pkg\mwc\tmp /Setenv INCDIR c:\pkg\mwc\include /Setenv TIMEZONE EST:0:EDT ! Make CM know about all the files in the path /Hash ! Establish normal color normal ! Define special macro key bindings. keys ! Ask me for and set the date.. /Inquire Date: /Date $i ! Get reminders remind -r ==== Note that in this startup file, the startup file is redefined to "rstartup.mm" for recursive invocations (since all environment variables are inherited from outer invocations). "rstartup.mm", in turn, redefines the CMEXIT variable to a "rexit.mm" to exit from recursive invocations. Note also that by the time "normal" is invoked, it has been hashed to "c:\bin\cmshell\normal.mm", and all CMINV* variables have been set, particularly the one that specifies that *.mm are Takefiles. The example startup file above also illustrates a peculiarity of the parsing method used. In the line that sets the prompt (CMPROMPT), the argument begins with an open parenthesis. Since a guide word string can be parsed after the "Setenv" command, the open parenthesis would be interpreted as the start of the guide word string. The rest of the string would not match what was expected and the command would fail. Thus the command has to specifically include the guide word string, as shown above. This is a file that sets up various key bindings: ==== ! Key definition file /Keydef F1 ^XDir /Keydef F2 ^XDelete /Keydef F3 ^XCopy /Keydef F8 d:\tools\cm\ /Keydef F9 c:\exe\cmshell\ /Keydef F10 c:\exe\bin\ ==== The "^X"'s above are really control-X characters in the real file. The bindings for F1-F3 are followed by a space, though you can't see it here; the ^X at the beginning erases whatever command was begun, so that pressing these keys replaces what was being typed with the key's value. Hmm, this was supposed to be brief. Oh well. I'm still claiming that this program is in essentially its final form. I'll fix any bugs that are reported, because I am using it too, but I am focusing on working on the real shell, which will not be such a kludge (i hope). Minor enhancements will also be entertained. Please note also that this program does not have any logic to detect disc changes. I suggest that if you change discs, you immediately do a directory on that drive to flush out any information that TOS is retaining in memory. Mark Mallett 20 Jeff Lane Manchester NH 03103 voice: 603 424 8129 data: 603 424 8124 BIX: mmallett usenet: ...decvax!sii!mem ...ittatc!sii!mem ==================== Changes from version 1.02 to 1.03 ==================== 860712 These changes resulted of suggestions and bug reports by BIX members rkaapke and dbetz, and those of myself: - A bug was fixed in takefile argument substitution. - Command line size has been increased to 256 characters. - Typing a filename (not a command) that includes an explicit path will prevent the action of searching the path, and simply run the specified program. Formerly, the the program had to be found along the currently specified path. - A "More" command has been added, which is like "Type" but which stops after each screen of text. - The "Directory" and "Vdirectory" commands now include a sort method. You can say DIR *.* as before, and the current sort order will be in effect. To change the sort order, do something like: DIR *.* Size Of course, using escape and questionmark will let you know what all the options are. Note also that the sort method selected will be in place for other commands which scan the directory (Type, More, Copy, etc.). - CM now attempts to decide whether output files are directories, so that you don't always have to specify a trailing "\". For example, in Copy *.c Foo if "Foo" is a directory, *.c will be copied into the directory "Foo". This was not done in the previous version due to an OS bug (actually, it was done, but the bug prevents that code from working!), but I used an more roundabout method here. Note that even this roundabout method doesn't recognize ".", so you will still have to use ".\". Sheesh. - If you specify a drive name without a path (in some commands), CM will now default to the current path. For example, if you are currently connected to E:\tools, the commands: Dir B: Copy *.C B: will reference the \tools\ directory on drive B:. - A bug was fixed in the "Freespace" command, so that if you don't give a drive name, the current drive will be used. - The "Vdirectory" command now shows file creation dates and times. - New command "Date" to set or show the date and time. - New command "Inquire" to prompt and read a string from the terminal. The string that was typed can be recalled in takefiles by using "$i". This functionality was added to be able to ask for the date in a startup file. - New command "Output" that will redirect output from programs to a specified file. Output from directories is also affected by this command (badly). Note: It appears that programs compiled with Lattice C will cause bombs if their output is redirected. I don't advice using this command, but I'm leaving it in in case anyone finds that it works with non-lattice programs. ==================== Changes from version 1.03 to 1.04 ==================== 860901 - Fix a bug where when a program's path is specified explicitly, if the program does not exist, CM would hang. - Commands are no longer preceded by "/". Command lookup is done first, then program name lookup. However the command line may begin with "/" to force command lookup (thus existing command files will work), or with "=" to bypass the command lookup, in order to run a program which has the same name as a built-in command. "/" and "=" probably should be used in command files just to insure the proper functioning of those files (just as abbreviations should be used judiciously). - Directory sort method no longer defaults as a keyword. It is now remembered as a current default method. This makes ^H command recall friendlier for directory command. - Implicit paths are now printed in lowercase. - New command "Pwdir" to show current directory. ==================== Changes from version 1.04 to 1.06 ==================== 861014 - Fix "delete" so that a file name must be given. It was originally implemented so that no argument meant all files. Yes, this was what I intended, but I changed my mind. - Added "enable" and "disable" commands. - Other things that I forgot to write down and have now forgotten what they were. Oops. ==================== Changes from version 1.06 to 1.08 ==================== 861106 - Relink with fixed scandir() library routine to fix bugs with multiple drive operations. - Minor changes to build it with Mark Williams C. Magically, the "Output" command now works with internal commands. - Get environment variables on startup. Added commands SETENV, REMENV, and PRINTENV. - Pass environment to invoked programs. - Removed the PATH command, use the CMPATH* environment variables instead. - Add invocation methods, specified in the path and in CMINV* variables. Add invocation option to expand wildcard filenames in program arguments. Use invocation options to specify TAKEfile extensions instead of using just ".mm". - Add ability to specify extension when running a program. - Removed the ENABLE and DISABLE commands, use CMERRABT environment variable for the abort-on-error flag. - Removed the HALF-DUPLEX and FULL-DUPLEX commands; use the CMDUPLEX environment variable instead (FULL or HALF). - Remove "Show-Copyright" command; add "About" command. - On startup, if CMSTART variable is set, use that to specify takefile. Otherwise use ".\startup.mm" or "\startup.mm" as before. - Don't take "exit.mm" on exit; rather, look at the CMEXIT variable for the name of the file to take. - Add hashed program names. Add "Which" command to find out about what would happen when a command is typed. Add "Hash" command. - Multiple other changes. ==================== Changes from version 1.08 to 1.09 ==================== 861115 - If the startup script does a HASH, don't hash automatically on startup. - Don't echo command files unless environment variable CMECHO is set. - More information from "Freespace" display - Be able to specify attribute list on "external" program invocation. - If an extern filename is typed, and what was typed is the name of a directory, do a Cdir to that directory. - Add argument to "Printenv" command; print any string matching the argument. - Add "Keydef" command and function key processing. - Relink with fixed COMND library to pass control characters from indirect files. - Fix bug in DATE command that rounded up seconds to the NEAREST multiple of 2 (TOS only stores with this resolution). Should always round DOWN. - Change format of the argument to the DATE command to match unix style date setting, which is easier to type and to understand. - Add history capability; environment variable CMHISTORY specifies size of history list. Added command "Recall" and the "!" character as a synonym for the it. - "!" command doubles as a comment in indirect files. - Moved all the change logs to the end of this document. - Add control of prompts via CMPROMPT and CMTPROMPT environment variables, with various formatting options. - Document the "-e" command line option - Make Printenv (and Recall, in print-history mode) pay attention to whether output is being sent to a file. - Further check the argument to the Delete command. If a directory is given as the argument, request more explicit instructions. Formerly, if the name ended in "\", CM would go ahead and delete the entire contents of the directory. That is, the argument was treated the same way as in the Directory command. - Fix a problem with relative path specifications. Turned out that CM ignored any relative paths in the CMPATH* variables and always tried "." for external program names if no explicity directory given. Oops. - Change the "More" command to "Ptype", now that I have a real "more" program. - Add "mwc" invocation method (at last). - Make "gem" invocation method work, so that GEM applications can be run from the shell. This requires that CM be run as a GEM application itself; CM's name has been changed from CM.TOS to CM.PRG accordingly. - Remove some gratuitous whitespace output by some built-in commands. ==================== Changes from version 1.09 to 1.10 ==================== 861227 - Fix bug that wouldn't allow parsing of an internal name if it begins with a digit. - Make directories sort to the top when expanding wildcards (in any situation), except when sort order is "Nothing". - Change character input back to Ccrawcin() from Bconin(2), so to be able to process typeahead. - Minor change in the "recall" command to prevent (always) the recall command itself from being put into the command list. ==================== End of change history ====================