# CmdShl User's Guide

## What's That?

CmdShl is a command interpreter front-end. It mimics the CMD.EXE command line behavior. It adds the following features:

1. You can define the initial insertion/overwriting state.
2. The TAB and Shift+TAB keys provide smart name completion.
3. An alias support is included.
4. You can easily redefine keys assignments via profile.
5. The "CD" command accepts both "/" and "\".
6. The "CD -" command switches between current and previous directories.
7. You can edit lines longer than 255 chars.
8. A new "RX" internal command.
9. Using the "CD" command is optional if you want to change to another directory (aka executable directories).
10. With the "DEFine" internal command, you can set a key's value (either a text or a command).
11. The "CD" command can use the CDPATH environment variable.
12. The executable directories feature is optional (enabled by default).
13. Optional command name validation (if an unknown command name is entered, it is highlighted).
14. You can copy/paste text from line to line.
15. You can expand parameters (even environment variable and aliases, for easy editing).
16. The "CD" command allows partial path substitution.
17. You can use extended path notations, such as "~" to denote your home directory or "..." to denote "..\..".
18. and much, much more...
CmdShl can also be used as a front-end for 4OS2, or with any command interpreter that provides a REXX interface.

## Installation

Installing CmdShl is very simple: just copy CMDSHL.CMD somewhere along your PATH, REXXVIO.DLL somewhere along your LIBPATH and, if you want to use a profile file, customize PROFILE.SHL and move it somewhere along your DPATH.

If REXXVIO.DLL is currently in use, close ALL your OS/2 windowed or fullscreen sessions, and open a bare OS/2 windowed session (that is, one not starting CmdShl of Fl). You can then replace REXXVIO.DLL from this session.

If you were using a previous version of MLRXSHL, execute the following code from an OS/2 command prompt, to allow the new functions defined in REXXVIO to be registered:

   rexxtry call VioDropFuncs


If you want to use CmdShl whenever you open an OS/2 session, you can add the following statement in the Parameter field of your OS/2 Windowed (or fullscreen) session object:

   /k "cmdshl"

If you use an old OS/2 release that has no support for long files (i.e., files that are bigger than 2GB), overwrite REXXVIO.DLL with REXXVIO.OLD beforehand.

## Starting CmdShl

Syntax

   cmdshl [/?] [/I|/O] [/P profile] [/C command|/K command]


Parameters

   /?         -  Display a short explanation for CmdShl;

/I         -  Use Insert mode by default (default);
/O         -  Use Overstrike mode by default;

/P profile -  Use profile instead of "PROFILE.SHL";

/C cmd     -  Just like the CMD.EXE /C switch;
/K cmd     -  Just like the CMD.EXE /K switch.


Examples

   CMDSHL
CMDSHL /C DIR
CMDSHL /K ALIAS @myalias


## Environment variables

CmdShl recognizes the following environment variables:

   CDPATH
CMDSHL.PROMPT
CMDSHL.PROMPT.environment
PROMPT

HELP.COMMAND
HELP.SWITCHES

HOME


If one or more of those environment variables are not defined, the missing ones are silently ignored.

The HELP.* environment variables are used to define an optional external help subsystem.

### CDPATH

This environment variable specifies the path along which the CD command should search for directories.

   SET CDPATH=[path[;...]]


Example

   SET CDPATH=E:\LOCAL;E:\;E:\OS2;E:\TCPIP;


### CMDSHL.PROMPT

This environment variable specifies the prompt to be used if no specific prompt is defined for the current environment. It takes precedence over PROMPT.

See the PROMPT section for details on the possible values of CMDSHL.PROMPT.

### CMDSHL.PROMPT.environment

This environment variable specifies the prompt to be used in the given environment. It takes precedence over CMDSHL.PROMPT and PROMPT.

For example, you can define two different prompts for two different (possible) environments:

   SET CMDSHL.PROMPT.CMD=$i[$p]$s SET CMDSHL.PROMPT.EDIT=EDIT:[$p]$s  See the PROMPT section for details on the possible values of CMDSHL.PROMPT.environment. ### PROMPT This environment variable specifies the prompt to be used if no more specific prompt is defined. If PROMPT is not defined, "[$p]" is assumed.

   SET PROMPT=text


The following symbols can be used to define a new prompt. Each symbol must be preceded by a dollar symbol ($):$
$symbol _ Carriage Return / Line Feed sequence A & symbol B | symbol (pipe) C ( symbol D Date E ASCII Code 27 (escape) F ) symbol G &> symbol. H Backspace I Help bar L < symbol N Default disk unit (e.g., A:) P Current directory (e.g., E:\OS2) Q = symbol R Return code S Space T Time V Version number All other symbols are emitted without changes. Example  SET PROMPT=$i$e[33m{$r}$e[32;1m[$p]$e[0m$s


### HELP.COMMAND

If this environment variable is defined, CmdShl will not use its build-in help messages for internal commands. Instead, it will call the script/application defined by this variable.

For example, if HELP.COMMAND is defined as:

   SET HELP.COMMAND=ECHO Help for


Issuing "ALIAS /?" will give:

   Help for ALIAS /?


(In other words, the command is displayed back to the user.)

The syntax of the call is the following:

   call %HELP.COMMAND% <command> <args>


where <command> is the upper-cased full command name (namely, one of ALIAS, CD, CMDSHL, DEFINE, QUIT or RULE) and <args> the argument(s) given to the command by the user.

### HELP.SWITCHES

If this environment variable is defined, it is used as the default value for the helpSwitches environment variable. If HELP.SWITCHES is not defined, the default value for helpSwitches is "/?".

See the helpSwitches definition in CmdShl internal variables for more details.

### HOME

If this environment variable is defined, and if pathExt is set to 1, leading occurrences of the "~" symbol in paths will be replaced by its value.

Its value is assumed to be a valid and fully qualified path, but this is not enforced.

If it is not defined, it defaults to the root of the boot drive.

For example, if HOME is defined as:

   SET HOME=c:\home\me


Issuing "CD ~\tools" will change the current directory to be:

   c:\colon\home\me\tools


if pathExt has been set to 1. Otherwise, the current directory would be:

  c:\~\tools


(Assuming we were at the root of the "C" drive before calling CD.)

## Extended Path Notations

CmdShl can recognize a couple of extended path notations in path specifications if the pathExt internal variable is set to 1.

Those extended notations are handled during completion, allowing for concise entries.

The first recognized notation is a leading "~" symbol, which represents the value of the HOME environment variable (or the root of the boot drive, if HOME is not defined).

The other recognized notation is three (or more) dots as a path segment, which represents backward navigation in the same vein as "." and "..". For example, "..." is equivalent to "..\.." and "...." is equivalent to "..\..\..".

Additionaly, CmdShl can automatically expand those notations for internal commands and convert slashes to backslashes, if the autoPathExt internal variable is set to 1. (The substitution only occurs for paths that do not start with a forward slash, in order not to clash with command options).

If autoPathExt is set to 1 but pathExt remains unset, then the only changes that will occur will be the slash to backslach ones.

Neither pathExt nor autoPathExt are enabled by default.

## Editing Keys

By default, CmdShl uses CMD.EXE editing commands, as well as some EPM keys, that is:

Alt+C
Copies the marked text.
Alt+D
Deletes the current mark.
Alt+M
Moves the current mark.
Alt+U
Removes the current mark.
Alt+W
Marks the word at the current cursor position using a character mark.
Alt+Z
Character-marks the current character.
Backspace
Deletes the character to the left of the cursor.
Ctrl+E
Ctrl+End
Erases from the current cursor position to the end of the line.
Ctrl+Home
Erases from the beginning of the line to the current cursor position.
Ctrl+K
Duplicates the element preceding the cursor. (A space is added between the elements, and completion state is preserved.)
Ctrl+Left arrow
Moves the cursor to the beginning of the word.
Ctrl+Right arrow
Moves the cursor to the beginning of the next word.
Ctrl+X
Expands the element preceding the cursor.
Del
Deletes the character at the current cursor position.
Down arrow
Recalls the next entry in the command history list.
End
Moves the cursor to the end of the line.
Esc
Erases the command line.
F1
Finds the previous entry in the command history list matching the beginning of the line (from the beginning to the current cursor position).
Home
Moves the cursor to the beginning of the line.
Ins
Switches between insert and replace modes.
Left arrow
Moves the cursor one position to the left.
Right arrow
Moves the cursor one position to the right.
Shift+Tab
Replaces the element preceding the cursor with the previous matching item.
Space
Insert a space and check the validity of the element preceding the cursor if it is a command.
Tab
Replaces the element preceding the cursor with the next matching item.
Up arrow
Recalls the previous entry in the command history list.

But you can redefine almost all keys to suit your needs. As an example, the default PROFILE.SHL file provides the following additional editing keys:

   (                                -- insert () and move cursor inside
F3                               -- close the current session
F8                               -- insert current date
Shift+F7                         -- show all matching file names
F2, F5, F7                       -- save, load and rename
-- history list
Ctrl+R                           -- search command in history
Ctrl+F                           -- search next match in history
Ctrl+Down arrow                  -- save current screen
Ctrl+Up arrow                    -- restore last screen


### The expand Internal Action

The expand internal action is used to expand the element preceding the cursor. That is:

• If the element is in a command position, it is replaced with its complete filename (with full path) if applicable -- if it is an alias or an internal command, it remains unchanged. If it is an invalid command, it is highlighted;
• If the element follows an ALIAS internal command, and ends with an equal sign, the alias value is inserted (if available);
• If the element follows a RULE internal command, and ends with an equal sign, the rule value is inserted (if available);
• If the element ends with an equal sign, and if an environment variable of that name exists, its value is inserted;
• Otherwise, if the element contains environment variable names surrounded by percent sign, these parts are replaced with the environment variables values.

In the following examples, the cursor is supposed to be the underscore sign.

   keyb_fr                 -->  c:\OS2\keyb.com_fr
keyb fr_                -->  keyb fr_
alias xrn=_             -->  alias xrn=e:\local\yarn ^& yarn.exe ^& cd -
rule RD=_               -->  rule RD=%d %d*^|/?
set etc=_               -->  set etc=d:\tcpip\etc
type %etc%\connect.log_ -->  type d:\tcpip\etc\connect.log_


### The tab and backtab Internal Actions

The tab and backtab internal actions are used to complete the element preceding the cursor. That is:

• If the element at this position is expected to be an environment variable, an environment variable name whose name begins with the element preceding the cursor is searched for;
• If the element at this position is expected to be a directory, a directory name whose name begins with the element preceding the cursor is searched for -- the element preceding the cursor can contain wildcards;
• If the element at this position is expected to be a keyword or a symbol, nothing occurs;
• Otherwise, a file or directory whose name begins with the element preceding the cursor is searched for -- the element preceding the cursor can contain wildcards.

When more than one matching item is found, the tab and backtab internal actions are used to enumerate the possibilities.

The type of the element at cursor position is determined by user-defined rules. When no such rule exists, a file or directory whose name begins with the element preceding the cursor is searched for. The following rules are predefined (they can be redefined at will):

   CD           %d|%f %f|/?|
CHDIR        %d|/?|
DETACH       %x
FOR          %%%l IN (%*) DO %x
RD           %d %d*|/?
RMDIR        %d %d*|/?
SET          %e=%*|/?|
START        "%*" %o %x|"%*" %o|%o %x|%o


See the RULE command for details on rules.

### The space Internal Action

The space internal action is used to insert (or overstrike) a space and to check the validity of the command preceding it. That is to say, the command preceding the cursor is checked if it is in a command (findcontexttype() returns "c") or invalid (findcontexttype() returns "0") context, as defined by rules.

If it is a command context, nothing happens if the command found is valid. Otherwise, invalidCmd is evaluated. If it is an invalid context, invalidCmd is evaluated too.

invalidCmd by default flags the offending command in red, but it can be redefined by the user. See its definition in the Internal Variables section for details.

## Internal Commands

CmdShl adds the following internal commands:

   ALIAS [LIST|@file|alias=[cmd]]
DEFine key [value]
QUIT
RULE [LIST|@file|rule=[def]]
RX cmd


And it enhances the following underlying shell commands:

   CD [directory|string1 string2]


### ALIAS

The ALIAS command is used to view/define/remove aliases. Alias names ARE case-sensitive. Recursive aliases are not allowed (but an alias can use another alias). And an alias can use all CmdShl's internal commands.

ALIAS -----------------+------LIST------+--------------------------|
+-----@file------+
+-alias=+-------++
+-value-+

• To view all defined aliases, issue the "ALIAS LIST" command.
• To save all defined aliases in a file, redirect the previous command output into a file, as in "ALIAS LIST >mylist".
• To load an alias list, use "ALIAS @mylist" (where "mylist" is a file containing alias definitions).
• To remove an existing alias, use an empty definition, as in "ALIAS foo=".
• To define a new alias, use "ALIAS alias=def", where "alias" is the alias name, and "def" its definition (any valid command). In addition, you can use the "%*" parameter as well as "%n" (where n is the argument number in range 0..9, 0 being the alias name), which denotes runtime parameters. (If "%n" is immediately followed by "*", it means "arg n and all remaining args".) Here are some aliases definitions:
   ALIAS dir=dir %* ^| less
ALIAS prj=cd \user\alpha\smith\MyProject\Current
ALIAS makeprj=prj ^& nmake
ALIAS calc=rx say %*; RC=0
ALIAS in=cd %1 ^& %2* ^& cd -

An alias can redefine an existing command, as "dir" in the previous list. The right-hand-side "dir" is the CMD.EXE internal command -- recursive aliases are not allowed, and hence this second "dir" cannot be an alias, so it must be something else (a CMD.EXE internal command in this very case).

When defining aliases from the command line, you may have to quote special symbols (such as "&" and "|") with a "^" in order to prevent unexpected results. For example, the first (dir), third (makeprj) and last (in) aliases require an "^" in front of their "&"s when entered from the command line.

When the execution of an alias is interrupted by the user (by the mean of Ctrl+C or Ctrl+Break), the execution of the alias is interrupted, as is the execution of the possibly following commands in the current command line.

### DEFine

The DEFine command is used to [re]define a key. You can either assign to a key an internal action, an immediate command or a static text. You can also remove a key definition (the key will then returns its default value).

DEFine -------------key--------------+-----------+-----------------|
+---value---+


[In this section, if a command name is shown in mixed case, as "DEFine" above, it means it can be abbreviated. That is, you can use either "DEF", "DEFI", "DEFIN" or "DEFINE" -- upper-cased letters are required, others are optional.]

keys names

By default, the following keys-name are defined:

   A-C, A-D, A-M, A-U, A-W, A-Z, A-F10, BKSP, CURD, CURL, CURR, CURU,
C-CURL, C-CURR, C-E, C-END, C-HOME, C-PGDN, C-PGUP, C-X, DEL, END,
ENTER, ESC, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12,
HOME, INS, PGDN, PGUP, SPACE, S-TAB, TAB


[Shifted keys have a "S-" prefix, control keys have a "C-" prefix and Alt keys have a "A-" prefix.] If you want to define another key, you have to define a synonym, as in:

   RX S_F7='005A'x; C_A='01'x


The variable name is the key name, with an "_" instead of a "-", as you cannot use "-" in a REXX variable name, and the key name value is the hexadecimal value returned by the getKey function. You can use the following CmdShl command to find this value for a key:

   RX call getkey; say "'"substr(ckey,2)"'x"


Keys values

The following internal actions are available:

   backmatch, backsp, backtab, cdown, cleft, cright, ctrlend, ctrlhome,
ctrlleft, ctrlright, cup, del, dup, end, enter, esc, expand, home,
ins, mark (char|clear|copy|word|delete|move), match, space, tab


If you assign an internal action to a key, this key will act just as if the internal action was used. If you want to assign more than one internal action to a key, you can use the MC command.

For example, if you want the C_A key to act as the Home key (if you are used to EMACS), use:

   DEFINE C-A home


And, if you do not like the command validity check, use:

   DEFINE SPACE


[That is, restore default behavior -- you can use "DEFINE SPACE space" to undo your change.]

Miscellaneous

If you want to assign a static text to a key, use the TEXT command:

   DEFINE A_F10 TEXT Hello World!


If you want to assign an immediate command, use the OSNowait statement (or its SHELL synonym). It can be followed by any CmdShl valid command(s):

   DEFINE F3 OSNowait EXIT


Now, if you hit F3, your session will be closed.

If you want to assign more than one command to a key, use the MC command:

   DEFINE " MC /TEXT ""/cleft


The first non-blank character following MC is the separator. It does not have to be a "/".

[See PROFILE1.SHL for more complex keys definitions.]

### QUIT

The QUIT command is used to exit from CmdShl. It does not close the underlying CMD.EXE session.

QUIT --------------------------------------------------------------|


### RULE

The RULE command is used to view/define/remove rules. Rules names ARE case-sensitive but a case-insensitive rule is assumed if rule name is in UPPERCASE.

Rules are used to help providing smart completion and command checking.

RULE -------------------+------LIST-----+--------------------------|
+-----@file-----+
+-rule=+-------++
+--def--+

• To view all defined rules, issue the "RULE LIST" command.
• To save all defined rules in a file, redirect the previous command output into a file, as in "RULE LIST >myrules".
• To load an rule list, use "RULE @myrules" (where "myrules" is a file containing rule definitions).
• To remove an existing rule, use an empty definition, as in "RULE foo=".
• To define a new rule, use "RULE rule=def", where "rule" is the rule name, and "def" its definition. The definition can contain more than one clause (in which case the clauses are separated by "|"). When more than one definition is given, they are checked from left to right, the first matching clause being retained. When specifying a definition, the following elements can be used to denote the argument type: %*, %c, %d, %e, %f, %l, %o, %u and %x. See below for details.
   RULE WHENCE=%f %e
RULE CD=%d^|%f %f^|/?|

When defining rules from the command line, you may have to quote special symbols (such as "&" and "|") with a "^" in order to prevent unexpected results.

Rules

A rule contains one or more clauses, separated by "|". Each clause describes a possible parameter list for the command.

In a clause, you can use any literal symbol, or one of the following values:

(space)
One (or more) space.
%%
The symbol "%".
%(list)
A file name matching at least an element of the space- or comma-delimited list.
%*
Anything.
%c
A command name.
%d
A directory name.
%e
An environment variable name.
%f
A file name.
%l
A single letter.
%o
A (possibly empty) list of OS/2-style options.
%u
A (possibly empty) list of Unix-style options.
%x
An expression

For example, the rule for the FOR command would be:

   RULE FOR=%%%l IN (%*) DO %x


It means that the FOR command requires a "%" sign immediately followed by a letter, then one (or more) space, an "IN" keyword (case insensitive), one (or more) space again, an open parent, one or more symbols, a close parent, one (or more) space, a "DO" keyword (case insensitive), one (or more) space and finally an expression.

Another example is the rule for the START command, which contains four clauses:

   RULE START="%*" %o %x|"%*" %o|%o %x|%o


An example using the "%(list)" specification follows:

   RULE EDITINI=%(*.INI *.FOO)


It means that the (hypothetical) EDITINI command requires a file whose extension is either ".INI" or ".FOO" (case insensitive).

If the last element of a clause is one of the special symbols listed above followed by a "*", it means this element can be repeated zero or more time.

For example, the RD (aka RMDIR) command is described with the following rule by default:

   RULE RD=%d %d*|/?


The first clause specifies that RD can take one or more directory name on its command line.

Case sensitivity

The left hand side of a rule respects the following:

• If you want to define a rule for a command, regardless of its case, use an all-upper-cased name;
• If you want to define a rule for a case-sensitive command (for example for an alias which overrides an internal command or such), use the case-sensitive name.

For example, assuming the following:

   RULE FOO=BAR|BAZ
RULE foo=FOOBAR
RULE Foo=FOOBARBAZ


If you enter "foo", rule 2 applies. If you enter "Foo", rule 3 applies. If you enter anything else (such as "FOO" or "foO"), rule 1 applies. It means that, if you want to define a specific rule for an all-upper-cased command, you have to define the default rule for all other cases.

For example:

   RULE IN=<a special rule>
RULE In=<the default rule>
RULE in=<the default rule>
RULE iN=<the default rule>


The right hand side respects:

• The special symbols (such as %c, %d, etc.) are case sensitive;
• All other symbols and letters are case insensitive.

For example, assuming the default rule for FOR, the following entries are all valid:

   for %a in (a b) do echo %a
for %a In (a b) Do echo %a
for %a IN (a b) DO echo %a


Predefined rules

The following rules are defined by default (they describe the various CMD.EXE internal commands):

   CD           %d|%f %f|/?|
CHDIR        %d|/?|
DETACH       %x
FOR          %%%l IN (%*) DO %x
RD           %d %d*|/?
RMDIR        %d %d*|/?
SET          %e=%*|/?|
START        "%*" %o %x|"%*" %o|%o %x|%o


You can redefine or remove them if needed, by using the RULE command (either in a PROFILE file or directly from the command line).

If no rules is defined for a command, "%*" is assumed.

### RX

RX is CmdShl's backdoor. You can use any valid REXX statement as a parameter, and you can check/set CmdShl internal variables, or call CmdShl internal functions. It is useful, but mostly for "power users" :-)

RX ---------------------------statement----------------------------|


[See PROFILE1.SHL for some RX usage samples.]

### CD

The CD command now accepts a new parameter, "-", and uses the CDPATH environment variable. Additionally, both "\" and "/" can be used in directories specifications and the drive is changed. Partial path substitution is also allowed.

CD ------------------------+-------------+-------------------------|
+--directory--+
+--old---new--+
+----- - -----+


The CDPATH environment variable contains a list of paths. You do not have to include the current (".") directory in it. It is always looked up first.

For example, if CDPATH is defined as:

  SET CDPATH=C:\;C:\OS2;


Issuing the "CD APPS" command will bring you to "C:\OS2\APPS" (if there was no APPS entry in the then-current directory).

If the directory specification starts with one of "/", "\", "./", "../", and so on, CDPATH is not used.

A trailing "/" or "\" is allowed in directories specification.

You can perform path substitution. For example, if you are currently in C:\project\beta\source and want to switch to C:\project\gamma\source, you can use "CD BETA GAMMA".

If path extensions are enabled, they are recognized and handled correctly. Hence you can use shortcuts like "CD ~/Mail" or "CD ..." If you want to switch to a directory named "-", you will have to enclose it with double quotes, follow it with "\" or precede it with ".\" as in:

   CD "-"
CD -\
CD .\-


You may prefer to use the CHDIR command, which does not provide the enhanced features of CD:

   CHDIR -


## Known Limitations

• When using CmdShl as a CMD.EXE front-end, interrupting the execution of a CMD.EXE internal command aborts CmdShl too. Not much can be done regarding this problem except waiting for a new CMD.EXE with a better signal handling...
• When using CmdShl as a CMD.EXE front-end with OS/2 2.x, your command-line window may not close upon shutdown. THIS PROBLEM NO LONGER OCCURS WITH WARP.
• Alias names ARE case-sensitive. This is intentional but if you do not like it that way, please, let me know!
• If you want to switch to a directory named "-", you will have to enclose it with double quotes or precede it with ".\" or append "\" to it or use the CHDIR command, as in:
   CD "-"
CD .\-
CD -\
CHDIR -

• When "implied" CD is enabled, a directory name takes the precedence over an executable name with no arguments. That is, if "foo" is a subdirectory of the current directory and there also exists a "foo.exe" somewhere along the PATH, issuing the "foo" command will change the current directory. If you want to call "foo.exe", either use some arguments, or specify the file's extension, as in:
   foo bar
foo.exe


[This behavior is the default, but you can choose to give precedence to an executable name with no arguments by setting impCD to 2. See the impCD definition in CmdShl internal variables.]

• CmdShl aliases and so-called "internal commands" (i.e., ALIAS, RX, QUIT and DEFine) can not be used in sub-expressions. That is, in:
   for %i in (foo bar) do alias do_%i=baz %i

or
   (foo prj & bar prj) >foobar.log


CmdShl's ALIAS command is not called in the first statement, and foo and bar cannot be aliases.

• The & ("and") operator cannot be used in an expression for the RX command. CmdShl interprets it as a command separator. For example:
   RX say foo & bar


can be interpreted either as "RX say foo" followed by a "bar" command, or as "RX say foo & bar", displaying 1 if foo and bar are both equal to 1 and 0 otherwise. As there is no way to choose between those two valid interpretations, the first one is retained.

• Due to a limitation with the linein() builtin function, lines in a PROFILE file exceeding 250 characters may cause problem. An easy fix is to break it in more than one piece:
   'a very long line...'


can be entered as:

   'a very',
'long line...'


(Note the ending comma at the end of the first line.)

## Related Files

df.cmd [drive ...]

This is a UNIX "df" clone. It displays all available (or specified) drives, with their total, used and free capacity.

pushd.cmd [new dir]

This command pushes the current directory in a directory stack, and (optionally) changes to the given disk/directory.

popd.cmd

This command pops the head of the directory stack, and go to this new directory.

whence.cmd file [path]

This command tries to find a file along a path (PATH by default). If the file is found, its complete path is displayed.

## National Language Support

There are just six language-dependent messages which are not automatically adjusted: it is the alias command help string (aliasHelp), the CmdShl help string (cmdHelp), the define command help string (defHelp), the quit command help string (quitHelp), the rule command help string (ruleHelp) and the additional CD help string (cdHelp). They are at the beginning of the file, and you can translate them. Or, even better, you can define them in your PROFILE.SHL (see below).

All other language-dependent messages are automatically adjusted by CmdShl (secondary prompt, top of screen help string, ...).

## Profile Support

CmdShl supports profile files. By default, PROFILE.SHL is used, but you can override it via the /P switch.

If present, the profile file should be somewhere along the DPATH, or you can alternatively specify its complete path.

A profile file is a plain REXX file. It is called after command line arguments, but before any user interaction. It's usually used to redefine keys assignments, displaying or setting some session-dependent data, and so on...

Please refer to PROFILE1.SHL for more explanations.

### PROFILE1.SHL

This is my current profile file, which you can use as a sample profile file for CmdShl. [Hint: for better startup performances, you can remove all comments -- that is, all except the first.]

For a detailed explanation of the features added by this profile file, read the end of this section.


/* profile.shl - sample bindings                               990601 */

/* This profile file demonstrates typical profile usage:              */
/*                                                                    */
/*       - Improving/tailoring existing commands, adding shortcuts    */
/*         [The auto-close '(', the insert-date key (F8), and S-F7,   */
/*         which displays all possible filenames.]                    */
/*                                                                    */
/*       - Adding new functions                                       */
/*         [The persistent command history, F2 (save), F5 (load) and  */
/*         F7 (name), tools to search items through command history   */
/*         as well as screen management system with C-UP, C-DOWN and  */
/*                                                                    */
/*       - National Language Support                                  */
/*         [on-line messages in French.]                              */
/*                                                                    */
/*       - Useful global aliases and rules                            */

/* In a profile file, you can use any REXX instruction, but, due to   */
/* the current implementation, it must fit in one line.               */
/*                                                                    */
/* That is, you can use:                                              */
/*                                                                    */
/*     if foo = 'XYZZY' then say 'Nothing happens'; else  x = x + 1   */
/*                                                                    */
/* But you cannot use:                                                */
/*                                                                    */
/*     if foo = 'XYZZY' then                                          */
/*        say 'Twice as much happens'                                 */
/*     else                                                           */
/*        x = x + 1                                                   */
/*                                                                    */
/* Alternatively, you can use the comma as a line continuation marker */
/*                                                                    */
/*     foo = 'Hello',                                                 */
/*           'world'                                                  */
/*                                                                    */
/* Another important difference with standard REXX scripts is that    */
/* you cannot call CmdShl commands in a REXX structure using the      */
/* standard way.  You have to use the eval function.  That is,        */
/*                                                                    */
/*     if answer = 'YES' then                                         */
/*        'DEFINE F12 OSNOWAIT shutdown'                              */
/*     else                                                           */
/*        'DEFINE F12 TEXT shutdown'                                  */
/*                                                                    */
/* does not work.  You have to use:                                   */
/*                                                                    */
/*     if answer = 'YES' then                                         */
/*        call eval 'DEFINE F12 OSNOWAIT shutdown'                    */
/*     else                                                           */
/*        call eval 'DEFINE F12 TEXT shutdown'                        */
/*                                                                    */
/* [But it works just fine outside of a structure.]                   */

/* Note: when a command name is in mixed case, like DEFine below, it  */
/*       means that you can use DEF, DEFI, DEFIN or DEFINE.           */

/*                                                                    */
/* There is currently only one pseudo command, DEFine, which is most  */
/* useful in profile file. Its syntax is as follows:                  */
/*                                                                    */
/*     DEFine key value                                               */
/*                                                                    */
/* Key is a user-defined key or a predefined one:                     */
/*                                                                    */
/*     A-F10, BKSP, CURD, CURL, CURR, CURU, C-CURL, C-CURR, C-END,    */
/*     C-HOME, C-PGDN, C-PGUP, DEL, END, ENTER, ESC, F1, F2, F3, F4,  */
/*     F5, F6, F7, F8, F9, F10, F11, F12, HOME, INS, PGDN, PGUP,      */
/*     SPACE, S-TAB, TAB                                              */
/*                                                                    */
/*     [Shifted keys have a "S-" prefix, control keys have a "C-"     */
/*      prefix and Alt keys have a "A-" prefix.]                      */
/*                                                                    */
/* and value is an internal action or MC nnn, OSNowait nnn or         */
/* TEXT nnn:                                                          */
/*                                                                    */
/*     backmatch, backsp, cdown, cleft, cright, ctrlend, ctrlhome,    */
/*     ctrlleft, ctrlright, cup, del, end, enter, esc, match, home,   */
/*     ins, tab, space, expand                                        */
/*                                                                    */
/*     TEXT nnn simulates the keyboard entry of nnn                   */
/*                                                                    */
/*     OSNowait cmd executes cmd (via the CmdShl interpreter)         */
/*                                                                    */
/*     MC separator cmd1 separator cmd2... allows the usage of more   */
/*     than one command for a key                                     */
/*                                                                    */
/* All other pseudo commands are executed via CmdShl's interpreter.   */

/* [In fact, the DEFine command could have been implemented as an     */
/*  alias:                                                            */
/*                                                                    */
/*     ALIAS DEFINE=RX _args="%*";                                    */
/*                     parse value _args with key rest;               */
/*                     if length(key) > 1 then                        */
/*                        key = value(translate(key,"_","-"));        */
/*                     if rest \= "" then                             */
/*                        call value "key._"c2x(key), rest;           */
/*                     else interpret "drop key._"c2x(key)            */
/*                                                                    */
/*  It is functionally equivalent.]                                   */

/* user-defined key name - note the usage of "_" in place of "-" in   */
/*                         the key name (you can't use "-" in a REXX  */
/*                         variable name).                            */
/*                                                                    */
/*                         The value of a key name is the hexadecimal */
/*                         value returned by the getKey function when */
/*                         pressing it (you can use the following     */
/*                         CmdShl command to find it) :               */
/*                                                                    */
/*                         RX call getkey; say "'"substr(ckey,2)"'x"  */

/* Note: by default, variables are hidden when inside a getLine call. */
/*       If you want to expose some of them, add them to the global   */
/*       variable -- global = global "newname1 newname2"              */
/*                                                                    */
/*       So, each time you use one of your variable in the right hand */
/*       side of a DEFine command, you have to expose it.             */

S_F7 = '005A'x; C_CURU = '008D'x; C_CURD = '0091'x; C_PADPLUS = '0090'x

/* defining key value - a shifted key can use "-" or "_" in its name  */
'DEFINE F3 OSNOWAIT EXIT'

/* you can even do complex things:                                    */
'DEFINE (  MC /TEXT ()/cleft'

'DEFINE F8 OSNOWAIT RX line = insert(date(),line,currOfs); currOfs = currOfs+length(date())'

'DEFINE S-F7 osn rx if currTab = 0 then currTab = findcontextcompletion(); if currTab \= 0 then do; say; do i = 1 to tree.0; say tree.i; end; call charout, print(); oline=""; parse value SysCurPos() with origRow origCol .; key="tab"; end'

/* first, we define a file name (and make it public, F7 requires it): */
history = expand('%tmp%\history.shl'); global = global 'history'

'ALIAS LOADHIST=RX drop prevLine.; i = 0; call stream history, "c", openread; do while lines(history); i = i+1; prevLine.i = linein(history); end; prevLine.0 = i; call stream history, "c", "close"'

/* now, we define three function keys, F2 (save), F5 (load/refresh)   */
/* and F7 (name)                                                      */
'DEFINE F2 OSNOWAIT RX "@del /f" history; do i = 1 to prevLine.0; call lineout history, prevLine.i; end; call stream history, "c", "close"'
'DEFINE F7 OSNOWAIT RX call charout ,"1b"x"[s"||"1b"x"[0;0H"||"1b"x"[1;37;42m"||"1b"x"[KNew history name: "; history=getLine(history); call charout ,"1b"x"[0;0H"||"1b"x"[0;34;47m"||"1b"x"[K"helpstring"1b"x"[0m"||"1b"x"[u"'

/* finally, we load the default history                               */

/* We can even define a screen management system.                     */
scr.0 = 0; global = global 'scr.'

'ALIAS PUSHSCR=RX i = scr.0 + 1; scr.i._C = SysCurPos(); scr.i._P = currOfs origRow origCol; scr.i._L = line; scr.i._S = VioReadCellStr(0,0); scr.i._O = oldDir; scr.i._D = directory(); scr.0 = i'
'ALIAS POPSCR=RX i = scr.0; if i > 0 then do; call VioWrtCellStr 0,0,scr.i._S; line = scr.i._L; call SysCurPos word(scr.i._c,1), word(scr.i._c,2); parse var scr.i._P currOfs origRow origCol; oldDir = scr.i._O; call directory scr.i._D; scr.0 = i-1; end'
'ALIAS SWAPTMPSCR=RX i = scr.0 + 1; scr.i._C = scr._C; scr.i._P = scr._P; scr.i._L = scr._L; scr.i._S = scr._S; scr.i._O = scr._O; scr.i._D = scr._D; scr.0 = i'
'ALIAS SWAPSCR=RX if scr.0 > 0 then do; scr._C = SysCurPos(); scr._P = currOfs origRow origCol; scr._L = line; scr._S = VioReadCellStr(0,0); scr._O = oldDir; scr._D = directory(); call eval "POPSCR & SWAPTMPSCR"; end'

'DEFINE C-CURD OSNOWAIT PUSHSCR'
'DEFINE C-CURU OSNOWAIT POPSCR'

/* We redefine C-K to a smarter duplication function.                 */
'DEFINE C-K MC /dup/tab'

/* We define tools to search through command history.                 */
C_F = '06'x; C_R = '12'x; global = global 'item'; item = ''
'DEFINE C-R OSN RX oldLine=currLine;call charout ,"1b"x"[s"||"1b"x"[0;0H"||"1b"x"[1;37;42m"||"1b"x"[KSearch for: "; item=getLine(item); call charout ,"1b"x"[0;0H"||"1b"x"[0;34;47m"||"1b"x"[K"helpstring"1b"x"[0m"||"1b"x"[u";',
'if item \= "" then do;prevLine.0=prevLine.0-1;currLine=oldLine-1;if currLine=0 then currLine=prevLine.0;do prevLine.0 while pos(item,prevLine.currLine) = 0;currLine = currLine-1;',
'if currLine=0 then currLine=prevLine.0;end;if pos(item,prevLine.currLine) \= 0 then line=prevLine.currLine;currOfs=length(line);xOfs=0;end'
'DEFINE C-F OSN RX if item\="" then do; oldCur=currLine;currLine = currLine-1;if currLine = 0 then currLine=prevLine.0;',
'do prevLine.0 while pos(item,prevLine.currLine) = 0;currLine = currLine-1;if currLine=0 then currLine=prevLine.0;end;if pos(item,prevLine.currLine) \= 0 then line=prevLine.currLine;currOfs=length(line);xOfs=0; end'

/* Here, we redefine help messages in French...                       */
defHelp = "Utilisez la command DEFINE pour (re)définir le rôle des touches"nl||,
"du clavier."nl||nl||,
"SYNTAXE:    DEF touche [valeur]"nl||,
"         DEFINE touche [valeur]"nl||nl||,
"          touche  Spécifie le nom de la touche à définir."nl||,
"          valeur  Valeur affectée à la touche. Ce peut être une"nl||,
"                  commande interne, MC xxx, OSNowait yyy ou TEXT zzz."nl||nl||,
"Exemples:"nl||,
"          DEF F12 TEXT dir /w"nl||,
"       DEFINE F3  OSNOWAIT exit"nl||,
"          DEF F12"
aliasHelp = "Utilisez la commande ALIAS pour afficher, définir ou"nl||,
"supprimer un alias."nl||nl||,
"SYNTAXE: ALIAS [LIST|alias=[chaîne]|@fichier]"nl||nl||,
"          LIST     Affiche la liste des alias en cours."nl||,
"          alias    Spécifie le nom de l'alias."nl||,
"          chaîne   Valeur alphanumérique affectée à l'alias."nl||,
"          fichier  Nom d'un fichier contenant un ensemble de"nl||,
"                   définitions d'alias."nl||nl||,
"Dans la définition d'un alias, %* correspond aux paramètres"nl||,
"passés sur la ligne de commande."
ruleHelp = "Utilisez la commande RULE pour afficher, définir ou"nl||,
"supprimer une règle."nl||nl||,
"SYNTAXE: RULE [LIST|règle=[chaîne]|@fichier]"nl||nl||,
"          LIST     Affiche la liste des règles en cours."nl||,
"          règle    Spécifie le nom de la règle."nl||,
"          chaîne   Valeur alphanumérique affectée à la règle."nl||,
"          fichier  Nom d'un fichier contenant un ensemble de"nl||,
"                   définitions de règles."nl||nl||,
"Dans la définition d'une règle, %*, %c, %d, %e, %f, %l, %o et"nl||
"%x dénotent le type des paramètres."
cmdHelp = "Utilisez la commande CMDSHL pour augmenter les capacités de"nl||,
"votre interpréteur de commande."nl||nl||,
"SYNTAXE: CMDSHL [/I|/O] [/P profile] [/C cmd|/K cmd]"nl||nl||,
"          /I    Sélecte le mode Insertion par défaut."nl||,
"          /O    Sélecte le mode surfrappe par défaut."nl||,
"          /P    Utilise le fichier profile spécifié."nl||,
"          /C    Exécute la commande cmd et met fin à l'exécution"nl||,
"                de CMDSHL."nl||,
"          /K    Exécute la commande cmd sans mettre fin à l'exécution"nl||,
"                de CMDSHL."nl||nl||,
"Par défaut, le mode Insertion est actif et le fichier PROFILE.SHL"nl||,
"est utilisé comme profile s'il existe sur le chemin spécifié par"nl||,
"la variable d'environnement DPATH."
cdHelp = "Tapez CD -        Pour retourner au répertoire précédent."nl||,
"Tapez CD s1 s2    Pour remplacer s1 par s2 dans le répertoire en cours."
quitHelp = "Utilisez la commande QUIT pour quitter CMDSHL."nl||nl||,
"SYNTAXE: QUIT"

/* useful aliases... from my point of view :-) */
'ALIAS rlogin=cls ^& ckermit ^& UTIL\telnet %1.unice.fr ^& cd -'
'ALIAS xrn=e:\local\yarn ^& yarn.exe ^& cd -'
'ALIAS open=rx xline = "%*"; if xline = "" then xline = directory(); else xline = findcommand(); call SysOpenObject xline,"DEFAULT",1; call SysOpenObject xline,"DEFAULT",1'
'ALIAS tc=java TCTypeCheck %*'
'ALIAS dir='SysSearchPath('PATH', 'sdir.cmd')' %*'
'ALIAS netscape=rx url=stream("%1", "c", "query exists"); if url="" then call eval("start netscape.exe %1"); else call eval("start netscape.exe" url)'
'ALIAS loop=rx do %*'
'ALIAS qd=query date'
'ALIAS qt=query time'
'ALIAS recurse=rx orgdir=directory(); call SysFileTree "*","dirs.","DSO"; do i=1 to dirs.0; call directory dirs.i; call eval "%1*^&rx needCR=0"; end; call directory orgdir'
'ALIAS revmap=rx call SysFileTree "*","dirs.","DSO"; do i=dirs.0 to 1 by -1; call eval "%1*" dirs.i "^&rx needCR=0"; end'
'ALIAS map=rx call SysFileTree "*","dirs.","DSO"; do i=1 to dirs.0; call eval "%1*" dirs.i "^&rx needCR=0"; end'
'ALIAS except=rx parse value "%1*" with "(" liste ")" cmde; line=""; currOfs=0; call findmulticompletion liste; do _i = 1 to tree.0; "attrib +H" tree._i; end; call eval cmde, "except"; do _i = 1 to tree.0; "attrib -H" tree._i; end'

/* useful rule... from my point of view :-) */
'RULE WHENCE=%f %e'
'RULE UNZIP=%u %(*.zip *.exe *.jar) %*'
'RULE VIEW=%(*.inf *.hlp) %*'
'RULE recurse=%x'
'RULE except=(%*) %x'


This profile file does the following:

• It redefines the "(" key so that it adds the closing ")";
• It defines the F8 key so that it inserts the current date at the cursor position;
• It defines the Shift+F7 key so that it displays all possible completions for the element preceding the cursor;
• It defines a persistent history feature:

The command history is read from/stored in the file whose name is contained in the history variable (by default %tmp%\history.shl).

F2 is used to store the current command history list to this file.

F5 is used to replace the current history list by the one defined in the file.

F7 is used to interactively give a new name for the file (to be used by subsequent F2 or F5 actions).

• A screen management system is added:

You can save the current "screen" by pressing Ctrl+Down arrow.

You can restore a previously saved "screen" by pressing Ctrl+Up arrow.

You can toggle between the current "screen" and the last previously saved one by pressing Ctrl+Numpad +. It allows you to easily switch between two different "screens".

When more than one "screen" are saved, they are stored in a stack (that is, the last stored "screen" is the first restored one.)

The "screen" above means the current state (screen layout, currently edited command, current directory and such). This feature has been added to circumvent the 16 OS/2 sessions limit and also because it is much simpler to press Ctrl+Up/Down arrow than to start or switch to another session. On the down side, it does not work from other VIO applications;

• It redefines the Ctrl+K key so that it steps to the next completion too, after duplicating the element preceding the cursor;
• It adds tools to search through command history:

Ctrl+R asks (on the top screen line) an item to search, and find (if any) the first occurrence of it in the command history (starting from current line, and going backward).

Ctrl+F finds (if any) the next occurrence (going backward, too).

Those two definitions show another way to add functionality without using aliases. It is a bit faster that way but it is also less user-friendly (no way to easily edit such definitions, ...). Reserve it for editing features;

• It redefines all CmdShl's messages in French. You can freely scrap it if you do not want them, or translate them in your own language (see CmdShl.cmd for the English version of those messages);
• It then defines some aliases:

rlogin is probably useless for you :-)

xrn is used to launch my newsreader (Yarn/2). You probably will not use it, but it shows you how to launch an application that does not reside in the PATH.

open is used to open the current directory (or the specified argument, either a directory or file) in a window. The default view is used (as defined by your current Workplace Shell settings).

tc is again probably of no use :-)

dir overrides the default CMD.EXE's DIR command with the enhanced SDIR.CMD one. (SDir is part of MLRXSHL.) The SysSearchPath function is called so that an absolute path is used by the alias. It means the alias will always call the same script, irrespective of the current directory content.

netscape is used so that you can simply enter "netscape index.html" instead of "netscape file:index.html" which is required by Netscape if you do not want to receive an error message. If you specify an URL instead of a file name, it still works, too.

loop allows you to do a command more than once. Please note that it requires a REXX syntax. For example "loop 10; 'mp123 Lillith.mp3'; end" will play the Lillith song ten times.

[Lillith is a track from Plaid's album "Not For Threes", featuring Björk.]

qd and qt are simple synonyms for "query date" and "query time", respectively. Not that useful if you are not used to use those two-letters commands to get current date/time;

recurse is used to repeat a command in each subdirectories beneath the current directory. The order in which the subdirectories are enumerated is filesystem-dependent. The only guarantee is that a child subdirectory comes after its parent. The given command is not run on the current directory.

map and revmap are two commands used to map (i.e., apply) a command over the list of subdirectories. The order in which the subdirectories are enumerated is filesystem-dependent. The only guarantee is that a subdirectory comes after its parent for map and before its parent for revmap. The command passed in argument receives one additional parameter, a full directory name. That is, if we suppose the current directory contains two subdirectories, one of which contains another subdirectory, the following commands would be issued:

   map aCommand              --> aCommand x:\curdir\subdir1
aCommand x:\curdir\subdir2
aCommand x:\curdir\subdir1\subsubdir1
revmap aCommand arg1      --> aCommand arg1 x:\curdir\subdir2
aCommand arg1 x:\curdir\subdir1\subsubdir1
aCommand arg1 x:\curdir\subdir1


So the following would define a simple "deltree" command:

   ALIAS zap=del %1* /n ^& rd %1*
ALIAS deltree=revmap zap


And the following...

   ALIAS tricky=pushd ^& alias _foo=cd ^%1 ^^^& %1* ^& map _foo ^& popd


...is another way to define the recurse alias given above. How it works is left as an exercise to the reader :-)

except is used to exclude a list of file from the effect of the specified command (in most case). For example, if you want to move all .class files except the ones starting with test or tmp to a given directory, use:

   except (test* tmp*) move *.class foo\bar\baz


[This alias is not 100% bullet-proof in that it simply temporarily sets the hidden attribute for the specified files. If the command ignores this attribute, then strange results may occur.]

• It finally defines a rule for the WHENCE, UNZIP and VIEW commands and the recurse and except aliases.

## CmdShl Internal Functions

This section describes useful CmdShl internal functions. Please note that theses functions may evolve in future releases.

The addAlias command adds (or removes) an alias to (from) the alias database.

No return value.

Examples

   call addAlias "foo=cd e:2_X/unix/emacs19.29/info/beta"


The addRule command adds (or removes) a rule to (from) the rule database.

No return value.

Examples

   call addRule "CD=%d|%f %f|/?|"


canonize(path)

The canonize function returns path in which all occurrences of environment variables surrounded by "%" are substituted by their values, and in which all possible extended path notations are expanded if the pathExt variable is set to 1. Double quotes are removed and slashes are converted to backslashes too.

If an environment variable contains extended path notations, they will be expanded if appropriate.

Examples

   With pathExt set to 1

say canonize('~/foo')         --> 'c:\home\me\foo'
say canonize('./~/foo')       --> '.\~\foo'
say canonize('".../bar"')     --> '..\..\bar'
say canonize('%etc%/.../baz') --> 'c:\baz'

With pathExt set to 0 (default)

say canonize('~/foo')         --> '~\foo'
say canonize('./~/foo')       --> '.\~\foo'
say canonize('".../bar"')     --> '...\bar'
say canonize('%etc%/.../baz') --> 'c:\MPTN\ETC\...\baz'


double(expr)

The double function returns expr in which all occurrences of "%" are doubled.

Examples

   say double('foo bar')         --> 'foo bar'
say double('echo %abc%')      --> 'echo %%abc%%'
say double(double('5%'))      --> '5%%%%'


eval(line [,current])

The eval command evaluate its line argument. The optional current parameter is here to prevent recursive execution of aliases (current is a space-delimited list of alias names).

Returns 0 if it evaluates the QUIT command, 1 otherwise.

Examples

   call eval "FOO"                  If FOO is an alias or an
external command, it is
executed.

call eval "FOO", "FOO"           If FOO is an external command,
it is executed.  Error SYS1041
occurs otherwise.

call eval "FOO & BAR", "ZOO BAZ" FOO and BAR will be executed in
sequence.  If they are alias,
and if they call ZOO or BAZ
(either directly or
indirectly), it is the external
command ZOO or BAZ that will
be used.


expand(string)

The expand function returns string where all occurrences of environment variables surrounded by "%" are substituted by their values.

Examples

   say expand('%tmp%\foo')        --> 'E:\IBMCPP\TMP\foo'
say expand('%unknown%')        --> '%unknown%'
say expand('%unknown%tmp%')    --> '%unknownE:\IBMCPP\TMP'
say expand('100%')             --> '100%'


expandpathext(path)

The expandpathext function returns path where all extended path notations are replaced with their standard translations if the variable pathExt is set to 1. Nothing is done otherwise.

The recognized extended path notations are "~" , either alone or followed by a slash or a backslash at the begining of the path, and "...", "...." and so on.

path must not contains double quotes, or else incorrect expansion may take place.

   say expandpathext('~/foo/bar') --> 'c:\home\mo\foo/bar'
say expandpathext('"~/foo"')   --> '"~/foo"'
say expandpathext('~/.../b')   --> 'c:\home\me\..\../b'
say expandpathext('"~/.../b"') --> '"~/../../b"'


findcommand([arg])

The findcommand function returns the expanded command name defined by xline, if any, or "" if xline is not a valid command.

If arg is specified, the real command name is returned. If no arg is used (or if arg is empty) an approximation is returned (in this case, aliases and internal commands take precedence over directories, regardless of the "implied" CD status -- it is faster, because the possible disk access is delayed).

• If implied CD is "1", and if xline is a valid directory name somewhere along the CDPATH environment variable, the complete directory path is returned;
• If xline is a defined alias, it is returned as is;
• If xline is an internal command, it is returned as is;
• If xline is a fully qualified name, and if the corresponding file exists (without additional extension, or with one in extList), the fully qualified name (with its extension) is returned;
• If xline is a valid name somewhere along the PATH environment variable (without additional extension, or with one in extList), the fully qualified name (with its extension) is returned;
• If implied CD is "2", and if xline is a valid directory name somewhere along the CDPATH environment variable, the complete directory path is returned.

Examples

   xline = "keyb"; say findcommand()   --> 'C:\OS2\keyb.COM'
xline = "xyzzy"; say findcommand()  --> ''


findcompletion([type])

The findcompletion function returns 1 if it can find a file name completion for the element preceding the cursor position, or 0 otherwise.

If successful, tree. contains the possible completions.

If type is specified, only names of the specified type are returned. The possible types are "F" or "D", for respectively file and directory.

Example

   if findcompletion() then
do i = 1 to tree.0
say tree.i
end
else
say "No match!"


findcontextcompletion()

The findcontextcompletion function returns 1 if it can find a completion for the element preceding the cursor position, or 0 otherwise. It uses the context (as defined by rules) to find a completion:

• If the element is expected to be a directory name, tree. contains the possible completions as a directory;
• If the element is expected to be an environment variable name, tree. contains the possible completions as an environment variable;
• If the element is expected to a file, a command or a undefined item, tree. contains the possible completions as either a directory name or filename;
• If something else is expected, 0 is returned and hence the content of tree. is irrelevant.

Example

   if findcontextcompletion() then
do i = 1 to tree.0
say tree.i
end
else
say "No match!"


findcontexttype([cmd])

The findcontexttype function returns the type of the element preceding the cursor position (or, if cmd is provided, the cursor is supposed to follow the last character of cmd). The returned value is one of: "a", "c", "d", "e", "f", "(list)", "" or "0":

• If it is "a", an undefined item is expected. That is, anything is allowed at that position;
• If it is "c", a command name is expected;
• If it is "d", a directory name is expected;
• If it is "e", an environment variable name is expected;
• If it is "f", a file name is expected;
• If it is "(list)", a file name whose name matches at least one specification contained in the space- or comma-delimited list is expected;
• If it is "", nothing is expected at that position;
• If it is "0", a rule has been defined for the context, but the context does not match it. It indicates either a syntax error in the command or an incorrectly defined rule.

Examples

   say findcontexttype('cd')           --> 'c'
say findcontexttype('cd ')          --> 'd'
say findcontexttype('cd e:')        --> 'd'
say findcontexttype('cd e: ')       --> 'f'
say findcontexttype('for %i is')    --> '0'


If we assume the default rules for the CD and FOR commands, which are "%d|%f %f|/?|" and "%%%l IN (%*) DO %x".

findcurrentcommand(cmd)

The findcurrentcommand function returns the command ending cmd. It does just return the command, its (possible) arguments are not. If the line is empty, an empty string is returned.

It does not always returns the finest command (for example, in the third example below, "for" is returned, not "del") but it nonetheless returns a valid one, so that the context can be correctly determined.

This function modifies the xline global variable. It contains the command plus its arguments, if any. (Warning: the length of xline is correct, but all opening and closing parents in it are replaced by spaces.)

Examples

   say findcurrentcommand('dir *foo')                          --> 'dir'
say xline                                                   --> 'dir *foo'
say findcurrentcommand('dir & cd bar')                      --> 'cd'
say xline                                                   --> 'cd bar'
say findcurrentcommand('for %i in (a b) do del %i')         --> 'for'
say xline                                                   --> 'for %i in  a b  do del %i'
say findcurrentcommand('for %i in (a b) do (echo %i & del') --> 'del'
say xline                                                   --> 'del'


findenvcompletion()

The findenvcompletion function returns 1 if it can find an environment variable completion for the element preceding the cursor position, or 0 otherwise.

If successful, tree. contains the possible completions.

Example

   if findenvcompletion() then
do i = 1 to tree.0
say tree.i
end
else
say "No match!"


findmulticompletion(list)

The findmulticompletion function returns 1 if it can find a file name completion whose name matches at least an element of the space- or comma-delimited list for the element preceding the cursor position, or 0 otherwise.

If successful, tree. contains the possible completions.

Example

   if findmulticompletion('*.exe *.cmd') then
do i = 1 to tree.0
say tree.i
end
else
say "No match!"


getArg(cmd)

The getArg function returns the first argument contained in cmd. An argument can contain spaces if they are enclosed in quotes. If the first argument of cmd contains no spaces, getArg is equivalent to word(cmd, 1). If the first argument contains an open quote, cmd is returned.

Examples

   say getArg('dir /w')                --> 'dir'
say getArg('"Desktop archive"')     --> '"Desktop archive"'
say getArg('A" "funny" command" !') --> 'A" "funny" command"'
say getArg('"Oops ...')             --> '"Oops ...'


getFileSpec(cmd)

The getFileSpec function returns the (possibly) partial file name ending cmd. It also sets the fileOfs variable to point to the first symbol of the file specification.

Examples

   say getFileSpec('dir c:\os2\dll')     -->    c:\os2\dll
say getFileSpec('dir "My Desktop"')   -->    "My Desktop"


getHome()

This function returns the home directory, followed by a trailing backslash.

The home directory is either the value of the HOME environment variable, if defined, or the root of the boot drive. No check is made to ensure that the returned directory exists, or even that it is a valid directory name.

getKey()

This function reads a key from the keyboard, and returns its value, as defined by the DEFine command. If the key has not been DEFined, the key itself is returned.

As a side effect, the ckey value is set to the internal representation of the key (a "_" followed by 2 to 4 hexadecimal digits).

Examples

   say getKey()      --> F3      --> OSNOWAIT EXIT  (ckey is _003D)
say getKey()      --> a       --> a              (ckey is _61)


getLine([line])

This function reads an entry from the user, and returns it. It can be a multi-line entry. All currently defined editing keys can be used. If line is specified, it is the default value.

Warning: getLine can be used recursively, but the command history is shared among all calls.

halt()

This function is called when an alias execution is interrupted by the user (by using either Ctrl+C or Ctrl+Break).

Its default action is to stop the execution of the command, switch to the orgdir directory (if defined) and resume execution of the command interpreter.

mark()

This function handles mark management. It is used to remove or copy mark, and to mark word/elements. It sets the following variables: markLen, markOfs and markLine.

This function has no argument, but it uses the second word of the key variable ("word", "char", "clear", "delete", "move" or "copy"). It can only be used while in editing mode.

print()

This function returns the string corresponding to the current prompt (as defined by the CMDSHL.PROMPT.environment (or CMDSHL.PROMPT or PROMPT) environment variable, if any). It can then be displayed by charout.

Example

   call charout, print()


profile()

This procedure read a profile file from disk, and interpret it. The real file name is derived from the profileName variable (if it is not an absolute path, it is searched via DPATH).

No return value.

[This procedure can be used to execute enhanced command scripts, that is, command script calling CmdShl-specific commands -- but keep in mind that CmdShl profiles suffer some syntax restrictions.]

Examples

   profileName = 'D:\tmp\foo.cmd'; call profile
'ALIAS EXEC=RX profileName = SysSearchPath("PATH","%*"); call profile'


profilesyntax()

This procedure is called when a syntax error is detected in the profile file. It displays the offending file and line number, as well as the error message. Interpretation of the profile is aborted, but the execution of CmdShl continues.

stripdoublequotes(string)

This function returns string, where all occurrences of """ are removed. Other characters are left unchanged.

Examples

   say stripdoublequotes('foo bar')           --> 'foo bar'
say stripdoublequotes('foo" "bar')         --> 'foo bar'
say stripdoublequotes('"""')               --> ''


substitute(line, arg)

This function returns line, where all occurrences of %[n]* or %n (if any) have been replaced with the nth word of arg (or the nth word of arg and all following word if n is followed by *).

Examples

   say substitute('bla bla', 'xxx')           --> bla bla
say substitute("it's %1 (%2)", 'yyy zzz')  --> it's yyy (zzz)
say substitute('%1 (%2*)', 'x y z')        --> x (y z)


## CmdShl Internal Variables

This section describes useful CmdShl internal variables. Please note that theses variables may evolve in future releases.

aliasHelp [string]

What to display when the "ALIAS /?" command is issued. You can translate this message (the recommended place to do so is in your PROFILE.SHL).

aliasNames [string]

A space-delimited list of name (case is sensitive) which enumerates all defined aliases. This list is maintained automatically by the ALIAS command, but you can use it to check the existence of an alias, or ...

Example

   'ALIAS EXISTS?=RX if wordpos("%*",aliasNames) > 0 then say YES;
else say NO'


aliasStem. [stem]

The aliases definitions.

autoPathExt [0|1]

If enabled (i.e., set to 1), path conversion will be attempted on commands listed in cnvList. If disabled (i.e., set to 0, the default), no path conversion will occur.

cdHelp [string]

What to display in addition to the default "CD /?" output (in fact, a description of the "CD -" and "CD path1 path2" commands). You can translate this message (the recommended place to do so is in your PROFILE.SHL)

cmdHelp [string]

What to display when the "CMDSHL /?" command is issued. You can translate this message (the recommended place to do so is in your PROFILE.SHL).

cmdList [string]

The list of all internal command interpreter commands, in uppercase (that is, CD, DIR, etc.). Used when command validation is enabled.

cmdQueue [0|1]

The history-list behavior. Can be 0 or 1 (the default). If cmdQueue is 1, a recalled command is moved to the end of the history list; otherwise, it remains in place.

[the default behavior mimics the CMD.EXE behavior.]

cnvList [string]

The list of all internal command interpreter commands, in uppercase, that may need path conversions, if autoPathExt is set to 1. This is a subset of cmdList.

Path extension is performed if autoPathExt is set to 1, and if the currently evaluated command is in both cmdList and cnvList.

defHelp [string]

What to display when the "DEFine /?" command is issued. You can translate this message (the recommended place to do so is in your PROFILE.SHL).

extList [string]

The extensions to be tried by the findcommand function. Its value is "exe cmd bat com" by default.

fileOfs [number]

The position of the first symbol of the last file name specification queried by getFileSpec.

fileSeparator [string]

When trying to find a file name, where to stop. Used by filename completion. Its value is " =;<&>|().&" by default.

helpColor1, helpColor2 [strings]

helpColor1 contains the ANSI escape sequence to use at the beginning of the (optional) top line help string, and helpColor2 contains the ANSI escape sequence to use at the end of this string. Theses two strings should not move the cursor or ... They should only change the color attribute. Their default values is:

   helpColor1='1b'x'[34;47m'    -- blue on white background
helpColor2='1b'x'[0m'        -- default color


helpSwitches [string]

helpSwitches contains the list of blank-separated switches used to obtain help from an internal command. Its value is "/?" by default.

For example, if you come from an UNIX background, you may be used to type "-h" to get help. Changing helpSwitches to be "/? -h" will then suits your habits.

See HELP.COMMAND and HELP.SWITCHES for more details on how to define an optional help subsystem. (If you redefine helpSwitches in your PROFILE.SHL, this redefinition will take precedence over the HELP.SWITCHES environment variable.)

impCD [0|1|2]

The "implied CD" (aka "executable" directories) state (1 by default, can be overridden in your PROFILE.SHL).

If impCD is 0, the "implied CD" feature is disabled. When impCD is 1, a directory name takes precedence over a possible command with no arguments. When impCD is 2, a command with no arguments takes precedence over a directory name.

To explain the difference between the 1 and 2 values, lets assume the following command was entered:

   help


If impCD is 1, and if there exists a directory named HELP accessible via the CDPATH environment variable, the current directory will be changed to it. Otherwise, the "\OS2\HELP.CMD" command is executed.

If impCD is 2, the "\OS2\HELP.CMD" command is executed, regardless of the presence of a possible HELP directory accessible via the CDPATH environment variable. (You can naturally still reach it by issuing "help/" or "help\" or "cd help".)

insertMode. [stem]

How to display the cursor in insert/overwrite mode (by default, "-80 -90", i.e. a low bar, and "0 -90", i.e. a plain box).

   insertMode.1 = '-80 -90'
insertMode.0 = '0 -90'

The two numbers for each state are the horizontal scan lines that mark the top and bottom of the cursor. 0 is the top scan line, and n-1 is the bottom one (where n is the scan lines in the character cell -- it cannot exceeds 32).

To set start line and end line independent of the number of scan lines for each character cell, you may specify these parameters as percentages. OS/2 then calculates the physical start and end scan lines, respectively, by multiplying the percentage specified for the parameter by the total number of scan lines in the character cell and rounding to the nearest scan line. Percentages are specified as negative values (or 0) in the range 0 through -100. Specifying start line = -90 and end line = -100 requests a cursor that occupies the bottom 10 percent of the character cell.

insertState [0|1]

The default insertion state (1 by default, can be overridden via CmdShl's "/O" switch). Each time you start to edit a new command, the insertion state is reset to insertState value (when editing a command, you can change the insertion state by using the Ins key -- by default, but theses changes are local).

invalidCmd [string]

What to interpret when an invalid command is found on the command line. In addition to the usual editing variables, xlen contains the position of the first symbol of the offending command and xline is the offending command. invalidCmd default's value is

   invalidCmd = "call VioWrtNAttr origRow + xlen % col, xlen // col, length(xline), 12;",
"xOfs = currOfs+1"


[That is, it displays the offending command in red.]

_LEVEL_ [number]

The current recursion level of the eval command.

oldDir [string]

The previously visited directory. This variable is maintained by CmdShl's CD command.

The command string required by the STREAM build-in function to open a file in (shared) read mode only. The required value changes whether Object REXX is enabled or not. openread default value is

   "open read shared"


when Object REXX is enabled and

   "open read"


otherwise.

pathExt [0|1]

The path extension state (0 if disabled, by default ; 1 if enabled). When enabled, extended path notations are recognized by filename completion and such. I.e., leading "~" in paths are recognized as denoting the home directory, and "..." as denoting "..\..".

Enabling path extension does not enable automatic conversions, though. In order to do that, you must set autoPathExt accordingly.

preEvalCmd, postEvalCmd [strings]

What to interpret when a command is about to be evaluated, or after it has completed. In addition to the internal variables described in this section, three variables are of interest: cmd contains the command to be executed, ucmd contains the command to be executed in uppercase, and args contains the command arguments. [Please note that the commands and args are not preprocessed in any way. Alias and variable substitution is not performed at this stage.]

By default, those strings are empty.

If we want to have a "special" _TIME variable that represent the current time, we can define:

   preEvalCmd = 'call value "_TIME", time(), "OS2ENVIRONMENT"'


Then, using "ECHO %_TIME%" will display the current time. The pre- and post-eval variables are interpreted (if not empty) before and after each command. If multiple commands are provided in the command line, the pre- and post-eval variables are interpreted multiple times. Hence, in the example above, "ECHO %_TIME% & ECHO %_TIME" may display two different times.

prevLine. [stem]

The commands history list. prevLine.0 contains the history size.

profileName [string]

The file name to be used by the profile() internal function.

quitHelp [string]

What to display when the "QUIT /?" command is issued. You can translate this message (the recommended place to do so is in your PROFILE.SHL).

rules. [stem]

The rules definitions.

rulesList [string]

A space-delimited list of name (case is sensitive) which enumerates all defined rules. This list is maintained automatically by the RULE command, but you can use it to check the existence of a rule, or ...

Example

   'ALIAS SHOWRULE=RX if wordpos("%*",rulesList) > 0 then say rules.%*;
else say "(undefined)"'


shlList [string]

The list of enabled CmdShl internal commands (in uppercase). Used when command validation is enabled.

## CmdShl Editing Variables

This section describes the variables which can be used while editing a command (that is, only usable when used in a key definition).

col [number]

The current screen width.

currOfs [number]

The current cursor position in the command (first char is at currOfs 1).

currTab [number]

If not null, we are in filename completion mode. If null, we are not (or, no longer). The "tab" and "backtab" internal actions enter completion mode. ALL OTHER internal actions exit completion mode. If you want to remain in completion mode after having used another action, add the following code after your action definition:

   key = "tab"


key [string]

The internal action name being executed (see currTab for an important note).

line [string]

The line being edited.

markLine [number]
markLen [number]
markOfs [number]

The position and length of the mark. if markLen is null, there is no mark.

oline [string]

The edited line before its last modification.

origCol [number]
origRow [number]

The initial cursor position (that is to say, where the cursor was just after displaying the prompt).

row [number]

The current screen height.

tree. [stem]

If tree.0 is not null, the stem contains the matching file names.

## History

 WARNING:  This product does work well with Object REXX as included
in DEVCON 10 or higher.  It does not work well with the one
included in DEVCON 8/9.

1.40.000    May 25 2006

--- New feature:
o preliminary support for generic path extensions (autoPathExt and
--- Misc. changes:
o CDPATH no longer used if CDing to an absolute destination or one
starting with a drive name or "./" or "../" and so on.
--- Bug fix:
o fixed incorrect double quotes handling in file name completion.
o fixed incorrect trailing '/' or '\' handling in CD command when
pathExt enabled.

1.39.000    Feb 24 2004

--- New feature:
o optionally allows path extensions ('~', '...', and the likes).
Set pathExt to 1 to enable.

1.38.000    Sep 16 2002

--- Bug fix:
o findcommand now handles leading double quotes correctly.
(I.e., entering a double quote followed by a space in a
command position no longer crashes.)

1.37.000    Feb 24 2002

--- New feature:
o added pre- and post-eval optional user-definable commands
(preEvalCmd and postEvalCmd, respectively).

1.36.000    Nov 12 2000

--- Bug fix:
catched.

1.35.000    Sep 12 2000

--- Bug fix:
o profile file (if any) is now open in shared read mode only when
using Object Rexx.

1.34.000    Jul 03 2000

--- Bug fix:
o profile file (if any) is now open in read mode only, so that
multiple instances could start simultaneously.

1.33.000    Sep 09 1998

--- Bug fix:
o incorrect behavior (and REXX/CMD.EXE bug?) when '|' abutted to
a single command (i.e., things like "dir|less").

1.32.000    Jun 26 1998

--- Misc. change:
o 'file:///' recognized while completing filename.

1.31.000    Jan 28 1998

--- New feature:
o %u implemented in rules.
--- Bug fix:
o fixed problems while completing an item specified by a %(list)
rule.

1.30.000    Dec 22 1997

--- New feature:
o %(list) implemented in rules.
--- Misc. change:
o Default rule provided for CHDIR.

1.29.000    Dec 21 1997

--- New features:
o better error handling in profiles.
o halt procedure added for use in aliases.

1.28.000    Dec 09 1997

--- New feature:
o Optional external help subsystem added (use HELP.COMMAND and
HELP.SWITCHES if defined).

1.27.000    Nov 27 1997

--- Bug fix:
o CD sets RC when called (either directly or indirectly).

1.26.000    Nov 25 1997

--- Bug fix:
o findcontexttype abend when called with an argument.
--- Misc. changes:
o Using CMDSHL.PROMPT instead of CMDSHLPROMPT.
o Case sensitiveness added to rule names.
--- New feature:

1.25.000    Nov 19 1997

[Those changes were made to unify CmdShl with Ulrich Möller's CommandPak.]

--- Misc. changes:
o The priority of implicit CDs is now user-definable (that is,
it can now preempt or not a command with no argument).
o User-definable help switch (helpSwitches) so that internal
commands can use -h or whatever the user expects for obtaining
help.
o quitHelp added to describe QUIT usage.
o SHELL allowed as OSNowait synonym.
--- New feature:
o If a CMDSHLPROMPT environment variable is defined, it is used
in place of PROMPT.

1.24.000    Nov 15 1997

--- Misc. change:
o "expand" also uses rules.  So commands are expanded even when
they are not in first position.

1.23.000    Nov 07 1997

--- Bug fix:
o %c in findcontexttype was not initializing xline correctly
(the current context was flaged as incorrect, not just the
offending command).

1.22.000    Nov 06 1997

--- Bug fixes:
o findcurrentcommand was returning incorrect result when command
was either START or DETACH.
o file was not cleared in findenvcompletion.
--- Misc. changes:
o %o implemented in rules.
o "space" uses rules, too.

1.21.000    Nov 03 1997

--- Bug fix:
o Environment variable in commands were incorrectly handled.
--- Misc. change:
o "expand" now also expands rules.

1.20.000    Nov 02 1997

--- Misc. changes:
o '*' allowed in rules definition to denote repetition.
o Default rules provided for RD and RMDIR.

1.19.000    Oct 31 1997

--- Bug fix:
o RC is now a public variable.
--- New features:
o Enhanced rules definition.
o Default rule provided for FOR.

1.18.000    Oct 23 1997

--- New features:
o Default rules provided for START, DETACH, CD and SET.

1.17.000    Oct 22 1997

--- New features:
o Completion also completes environment variable name if the
current command is 'SET'.
o Rules (partialy) implemented to help providing smart
completion and command checking.
--- Misc. change:
o Enhancing command detection algorithm.

1.16.000    Jun 17 1997

--- New feature:
o A "dup" internal action added.

1.15.000    Jun 10 1997

--- Bug fix:
o Quoted elements now supported in path substitution.

1.14.000    Jun 03 1997

--- Bug fixes:
o Quoted command and directory names now correctly handled.
o Multiple commands in "/c" and "/k" correctly handled when
specified in quotes.
o Incorrect display if cursor is on lower right corner and
spacebar is pressed.

1.13.000    Mar 13 1997

--- Bug fix:
o interactive was not initialised when using the "/k" switch.

1.12.000    Oct 07 1996

--- Bug fix:
o OSNowait now accepts quoted '&'.

1.11.000    Sep 28 1996

--- Bug fix:
o xOfs reseted by "esc", "match", "backmatch", "cup" and "cdown".
--- Misc. changes:
o Removed "STDOUT:" statements.
o "space" now understands START and DETACH.

1.10.000    Sep 16 1996

--- Bug fixes:
o '%' handled correctly in command name and arguments.
o Filenames with '(' or ')' correctly handled during filename
completion.
o CD no longer overrides oldDir if not relevant.
--- Misc. changes:
o Enhancing CD with path substitution.

1.09.000    Sep 13 1996

--- Misc. changes:
o Speeding up filename completion.
o Speeding up command line display.

1.08.000    Sep 12 1996

--- Bug fixes:
o "PROMPT" added in the CMD internal command list.
o Fully qualidied directory path correctly recognized as
a valid command when implicit CD is enabled.
o Unit specification correctly recognized as a valid command.
--- Misc. change:
o '/' or '\' allowed at the end of directories names during CD
(either implicit or explicit).

1.07.000    May 23 1996

--- Bug fixes:
o "space" handles stream redirections ('>&') correctly.
o "expand" was duplicating command name when there was only spaces
between cursor and command name.
o '&&' correctly handled.
--- Misc. change:
o findcommand speed optimized when checking aliases and internal
commands.

1.06.000    Apr 29 1996

--- Misc. changes:
o Displaying helpString is a bit faster now.
o Removing the unused assignment to line in loop:.
o Executable filename extensions are stored in extList instead of
beeing hardcoded.

1.05.000    Apr 19 1996

--- Bug fixes:
o Fully qualified directory specifications recognized by findcommand
(and hence by on the fly command checking).
o The eval function is now safely recursive.
--- New feature:
o A new "backmatch" command.

1.04.000    Mar 26 1996

--- Bug fix:
o Stream redirection (i.e., things like 2>&1) handled correctly.

1.03.000    Mar 07 1996

--- New features:
o A new key-related function, MC.
o "expand" now also expands aliases.
o "mark move" and "mark delete" have been added (if the mark is
not on current line, "mark move" do a copy, and "mark delete"
do nothing).

1.02.000    Mar 05 1996

--- New feature:
o The "expand" internal action also expands command name (with
its path and extension, if applicable).
--- Buf fixes:
o getFileSpec failed if first char was '"' in arg(1) and there was
an odd number of '"'.
o A fully qualified path was incorrectly flagged as being an
invalid command.
--- Misc. changes:
o RexxVIO is now required (was optional since 0.98.000).
o "f1" internal action now called "match".

1.01.000    Mar 04 1996

--- New features:
o A new "expand" internal action (bound to C_X by default).
o Command line copy/paste added (mark char|clear|copy|word).

1.00.000    Feb 22 1996

--- New feature:
o File name completion understands environment variables.

0.99.000    Feb 19 1996

--- Bug fixes:
o Re-enabling environment variable substitution in 'CD' commands.
o Command line checking now handles fully qualified commands.
--- New feature:
o User-definable file separator (fileSeparator, ' =;<&>|()' by.
default).

0.98.000    Feb 15 1996

--- New feature:
o If RexxVIO is present, cursor reflects insert state (insertMode,
overwriteMode).

0.97.000    Feb 02 1996

--- Bug fixes:
o Incorrect alias handling when no substitution was required.
o Blank lines no longer emitted while processing profile file.
o helpColor1 and helpColor2 are now public.
--- New feature:

0.96.000    Nov 15 1995

--- Bug fixes:
o Command line checking now handles correctly quoted "&" and "|".
o Quoted "&" and "|" are now correctly handled when defining an
alias from the command prompt.
--- New features:
o Command line checking now uses a user-defined function to warn
the user (so, if you prefer an audible clue, you can define it)
(invalidCmd).
o The help line color is user-definable (helpColor1, helpColor2).

0.95.000    Oct 18 1995

--- New features:
o CmdShl internal commands can be enabled/disabled.
o Enhanced ALIAS substitution parameters (%[0-9]?[*]).

0.94.000    Oct 12 1995

--- Bug fix:
o CMD.EXE quoting symbol (^) is now correctly handled.

0.93.000    Oct 11 1995

--- Bug fixes:
o Command line checking handles '|', '(' and ')'  correctly.
o DEFINE no longer crashes if its first parameter is invalid.
o "CD -" now works with implicit CDs.
--- New features:
o Improved command line parsing (strings and subexpressions are
now recognized).
o Speed improvement when using CMD.EXE internal commands.

0.92.000    Oct 06 1995

--- New features:
o Implicit "CD" feature is now optional (impCD).
o Optional command line checking (if a command is nonexistent, its
name is highlighted).

0.91.000    Aug 08 1995

--- Bug fixes:
o Default messages are now in English.
o Newline no longer automatically emitted after a RX command.
--- New commands:
o A new DEFINE internal command.
o And two new key-related functions, TEXT and OSNOWAIT.
--- New features:
o An improved profile interpreter (multi-lines, REXX expression
allowed in external commands).
o getLine can be called recursively.
o Interesting internal functions have been documented.
o Some key names have been defined (for use with the DEFINE
command).

0.90.000    Jul 27 1995

--- First public release