The ZSIG Column #3, January 10, 1987   This file was prepared with the PMATE text editor. All of these header  lines should be stripped away for use with other word processors.  I have used control-n in several places in the text to toggle underlining  on and off.  ZL14_10I R76;I8 The ZSIG Column Jay Sage 1435 Centre Street Newton Centre, MA 02159 When I first offered to write a regular column for The Computer¨ Journal, I wondered if I would have enough material for a column every two¨ months. Instead, the problem has become one of finding the time to set down¨ all the thoughts I have. For this issue I had planned to cover four topics,¨ there is only room for three of them. They are: 1) corrections of some¨ errors in the last column (and an excuse for more discussion of flow control¨ in Z System); 2) a brief rundown on the files in the first officially¨ released ZSIG diskette; and 3) a discussion of command-line-building¨ programs in ZCPR3, including aliases and shells. Corrections ----------- There were two errors that I noticed in the last column. One was a¨ minor one that was Art Carlson's fault; the other was more serious and was¨ my doing. First for the easy one. Art was kind enough to add information¨ at the end of the column on how to contact me, but the Z-Node he listed¨ there was not mine. It was the Lillipute Z-Node in Chicago, which is the¨ official ZSIG remote access system (its phone number is 312-649-1730). ¨ Messages left for me there will get to me, but I will get them sooner if¨ they are left for me on my own node in Boston at 617-965-7259. I can also¨ be reached on my voice phone at 617-965-3552 (please don't mix the two¨ numbers up, especially if you are calling in the middle of the night!). ¨ Finding me at home is not always easy, and your chances will be best if you¨ call between 10pm and just after 11pm (Boston time, of course). Now for the error I made. In the discussion of the flow control¨ package (FCP) and the transient IF.COM, I said that one can force use of the¨ transient program by including a DU: or DIR: prefix or even just a colon in¨ front of the 'IF'. This is not true. I thought I had verified the¨ statement experimentally, but my experiment was flawed, and the conclusion¨ incorrect. A colon does force the command processor to skip commands in the¨ resident command package (RCP) and in the CPR itself and to proceed with a¨ search for a COM file, but all the FCP resident commands are intercepted no¨ matter whether there is a colon or not. There is a very good reason for¨ this. The FCP commands must be executed even when the current IF state is¨ false. This is especially clear for commands like ELSE, which reverses the¨ current IF state, and FI, which terminates the current IF state. Transients¨ ELSE.COM and FI.COM could not do this. After a bit of thought you can¨ probably see that this is true for all the flow control commands. I have long been searching for ways to give the user control over¨ whether IF processing is performed by resident or transient code. One¨ solution that I introduced some time ago was adding alternative names for¨ condition options in IF.COM so that one could force the more powerful¨ transient processing to be performed even when the function was supported by¨ the resident FCP. The trick was to use condition names in IF.COM that were¨ different from the names of the same functions in the FCP module. ¨ Specifically, I changed the first letters to 'X' (for example XXIST for¨ EXIST and XNPUT for INPUT). Frank Gaude' in the Echelon Z-News has reported¨ examples in which the transient program is given a name other than IF.COM¨ (such as IF13.COM). Then the command "IF INPUT" gives resident processing¨ and "IF13 INPUT" transient processing. This will work correctly for first¨ level IF processing but will not work in general. Neither of these solutions was really satisfactory. A proper solution,¨ I felt, would operate both correctly and automatically. I have now written¨ a new FCP package (FCP10) that is presently under test by ZSIG program¨ committee members and should be ready for release with the next ZSIG¨ diskette. It handles both resident and transient code. It can examine the¨ command line to see if there was a colon before the IF. In that case, the¨ FCP ignores its internal condition options and invokes the transient IF.COM¨ immediately. If no colon was present, the FCP first looks to see if the¨ condition option is included in the resident code. If not, it automatically¨ invokes the transient IF processor. The user need not be concerned with¨ which options are resident in the FCP. The script "IF NULL $1" in an alias¨ will take advantage of fast resident processing if the NULL option is¨ supported in the resident code or will automatically invoke transient¨ processing if not. When one wants to be sure to get transient processing,¨ one simply uses the colon as in ":IF EXIST FILE1,FILE2". To go along with FCP10 there is a new transient IF processor, COMIF10. ¨ It supports dozens of additional condition tests. One is AMBIG, which tests¨ a file specification for ambiguity (question marks or asterisks). Register¨ (numeric) and string (alphabetic) comparisons are now extended to the full¨ range of tests: equal, not equal, greater, less, greater than or equal, and¨ less than or equal. I plan to add file attribute testing (SYS, DIR, RO, RW,¨ ARC, WP) and testing for the presence of Plu*Perfect Software's exciting¨ Backgrounder task-swapping program. The new FCP/COMIF combination also adds an important new twist in¨ transient processing. They have the option of loading the transient code¨ not at 100H, as has been done until now, but high in memory, where it will¨ not overwrite a user program that is loaded at 100H. In this way the GO¨ command can be used to rerun the last user program after flow control¨ processing no matter whether resident or transient flow processing was used. ¨ Thus the user need not concern himself with how the flow processing was¨ performed. While I was at it, I also added two new commands to the FCP module. ¨ One, IFQ (if query), is designed to help users -- advanced as well as novice¨ -- learn how flow control works (or, perhaps, is not working as one¨ intends). It displays on the screen the complete flow state of the system¨ -- the true/false status of all IF levels. The second is ZIF (zero ifs). ¨ It is like XIF (end all ifs) except for one thing. XIF clears all IF states¨ only if the current IF state is true; if the current IF state is false, XIF¨ is flushed (ignored) just like any other command. ZIF, on the other hand,¨ clears all IF states no matter what. I'm sure that everyone who has¨ experimented with flow control has at one time or another gotten himself so¨ messed up that nothing seemed to work. The only way out, short of¨ rebooting, was to type a string of FI's until things started working again. ¨ ZIF is a quick way to reinitialize the flow control system (and it takes¨ very little code in the FCP). ZSIG Diskette #1 ---------------- Now that I have atoned, I hope, for my sin in the last issue, I will¨ turn to the first new subject, the inaugural ZSIG diskette. Let me remind¨ you that this diskette and a number of others put out by NAOG/ZSIG (NAOG =¨ North American One-Eighty Group, the group formed to support the SB180¨ computer and other computers using the Hitachi HD64180 microprocessor) can¨ be ordered from NAOG/ZSIG (P.O. Box 2781, Warminster, PA 18974). I¨ encourage all of you to join ZSIG ($15). You'll get a nice newletter with Z¨ System tips and details on all the NAOG/ZSIG diskettes. Here is a listing of the files in ZSIG diskette #1. Z-RIP.LBR VERROR17.LBR VCED18.LBR ZCRCK.LBR ZFINDU.LBR ZLDIR.LBR ZTXTTOWS.LBR ZWC.LBR PPIP14.LBR UF.LBR LDSK20.LBR W20.LBR The first three programs are by Paul Pomerleau. Paul is a speed freak and,¨ like many of us, found the process of installing Z programs with Z3INS (the¨ standard installation utility) tedious and slow. So Paul wrote Z-RIP, given¨ that name because it rips through an entire disk of files at incredible¨ speed, automatically identifying the ZCPR programs and installing them. The¨ new autoinstall versions of ZCPR3 may make Z-RIP (not to mention Z3INS)¨ obsolete, but it is great for those running standard ZCPR. VERROR is Paul's¨ video error handler. It provides a screen display of the entire command¨ line in which an error was detected and allows the user to edit it freely,¨ moving about using WordStar-like commands. VCED is Paul's Video Command¨ EDitor, a video history shell. With VCED running as a shell, the user¨ always has full command-line editing. In addition, past commands can be¨ recalled, searched for, edited, and run. As if that were not enough, it¨ doubles as a video error handler as well! Paul astutely noted the¨ functional similarity between correcting old commands with errors and¨ entering new commands -- so he combined the two functions in a single¨ program. The next group of five programs comprises Z versions of common CP/M¨ utilities. Most of these were created by the prolific program fixer and¨ NAOG/ZSIG chief, Bruce Morgen. The main feature that makes these programs¨ ZCPR3-compatible is their ability to accept named directory (DIR:)¨ references as well as drive/user (DU:) references. For programmers and¨ aspiring programmers reading this, you should know that the code to do this¨ in ZCPR3 is actually much simpler than the CP/M code needed just to¨ recognize the DU: form. This is because the ZCPR3 command processor already¨ does all the work for the first two arguments on the command line (including¨ translating named directory references into drive/user values). Unlike¨ CP/M, ZCPR3 saves not only the drive but also the user number in the default¨ file control blocks at 5CH and 6CH. A ZCPR3 program need only fetch the¨ values from the appropriate locations. The hardest part of making these¨ ZCPR3 versions of the CP/M programs was stripping out the complex and¨ lengthy parsers required to accept DU: syntax in CP/M. (So much for the¨ myth of ZCPR3 complexity! Programming in ZCPR3 is often, as in this¨ example, simpler than programming in standard CP/M.) The third group of programs includes two more ZCPR3 versions of CP/M¨ programs. They are listed separately only because they do not have names¨ with Z's in front! Here is a quick listing of the functions of all seven of¨ these converted programs: ZCRCK computes cyclic redundancy check codes for files using both common CRC polynomials ZFINDU searches for text strings in files, including files that are squeezed ZLDIR displays a directory of the files in a library ZTXTTOWS converts standard text files to WordStar files ZWC counts the number of words in a text file PPIP14 copies files (as does PIP) but with nicer interface and fast -- I renamed it to COPY and use it all the time UF Steven Greenberg's ultrafast file unsqueezer The last two programs are original creations for the Z System. LDSK,¨ by Wilson Bent with modifications by Earl Boone, solves a longstanding¨ problem that owners of floppy-disk-based computers had with named¨ directories. With hard disks, there is an unchanging association between¨ directory names and drive/user values, but with floppies the association¨ changes every time the diskette is changed. Wilson devised this nifty¨ scheme for automatically loading the named directory register (NDR) with the¨ names associated with user areas on a floppy diskette. To give a user area¨ a name, one simply puts a (usually zero-length) file in that user area with¨ a name of the form "-NAME". When LDSK is run (specifying the drive to be¨ loaded), it scans the disk for files of this type, strips the leading¨ hyphen, and creates an entry in the NDR associating the name with that user¨ number on the drive. As I wrote in the last column, I still have a lot of¨ floppy-only systems, and I love LDSK. Haven't you at times wished that you could take some program that only¨ works on a single file and magically make it work with an ambiguous file¨ reference. Well, Steve Cohen did, so out of his programmer's hat he pulled¨ the wildcard shell 'W' to do it. It just shows again that the only real¨ limitation with the Z System is one's imagination! Here are some examples¨ of how 'W' can be used. Bob Freed wrote a quick little program called PCPCK¨ that checks a file for proper transmission over Telenet's PC-Pursuit packet¨ network (certain character sequences cause problems). The trouble is, PCPCK¨ only works on a single file, and it is no fun to run it manually on every¨ file one is about to send somewhere. But along comes 'W' and all I have to¨ do is enter "W PCPCK *.*" and away we go. Or suppose you are just lazy and¨ hate typing exact names of files. Just put a 'W' in front of the command¨ and enter a wildcard file name that specifies the file you want. That's all¨ there is to it. I have 'W' implemented in an alias on my Z-Node system so¨ that users can type a file without having to enter the exact name. If a¨ user can't remember (or doesn't really care) whether the file is¨ AUTOINST.FIX or AUTOINST.FQZ or AUTOINST.FZX, all he has to enter is "TYPE¨ AUTO*.*" and the file (whatever it is called) will appear on the screen. Command Line Generators ----------------------- Many people call me about problems they are having getting an alias or¨ VFILER script to work correctly. Often the problem turns out to be a¨ misunderstanding of what command line generators are really doing. I will¨ try to shed a little more light on that subject here. First a little philosophy. There are many features in the Z System¨ about which one might well at first just shrug one's shoulders and say, "So¨ what!" The flow control system discussed earlier is one such feature, and¨ multiple commands on a line might be another. After all, how many of us¨ actually think far enough ahead to enter more than one command at a time¨ anyway? Well, the answer lies in the interplay of all the features in Z¨ System and in the ways they allow things to be accomplished automatically. Aliases The multiple command capability of Z System, for example, is important¨ not so much because it allows the user to enter a whole sequence of commands¨ manually but rather because it allows other programs to do so automatically. ¨ The simple, standalone 'alias' created with the original ALIAS.COM or one of¨ the more sophisticated alias programs like TALIAS, BALIAS, or VALIAS is a¨ good example. Let's see how such an alias might be used. Suppose we are¨ working on a new program with a source file called MYPROG.Z80. Our standard¨ sequence of operations is to edit the source with a command like "EDIT¨ MYPROG.Z80" and then to assemble it with a command like "ASM MYPROG.AAZ" and¨ then to load it with a command like "MLOAD MYPROG". We can speed things up¨ and reduce the amount of typing (and the number of typos!) by creating an¨ alias which we might give the name DO.COM. We would create it, with VALIAS¨ for example, with the following script (command line form): EDIT MYPROG.Z80;ASM MYPROG.AAZ;MLOAD MYPROG Now when we want to start a new cycle, we just enter the easily spelled¨ command "DO". The rest is automatic. But how does this alias actually work? When you enter the command¨ "DO", the operating system loads DO.COM into memory and starts running it. ¨ DO contains within its file the script line put there by VALIAS.COM (for¨ example) when the alias was created. DO.COM has code to determine where the¨ Z System multiple command line is located in memory (this information comes¨ from what is called the environment descriptor, whose address is installed¨ in a standard location near the beginning of all true Z System programs). ¨ Next DO.COM takes its command script, appends any other commands in the¨ multiple command line that come after the "DO" command, and then writes the¨ result back to the command line buffer. When it then returns to Z System,¨ the ZCPR3 command processor, as usual, looks at the command line buffer to¨ see if there are more jobs listed there for it to do. Since DO.COM has¨ filled the command line buffer with the script, ZCPR3 responds just as if we¨ had typed the long command line script instead of the simple "DO". Now let's see how flow control can be used with alias scripts. One¨ problem with the command sequence in our example arises when the assembler¨ reports an error. In that case there is no sense going through the MLOAD¨ operation. Assemblers like ZAS from Echelon and Z80ASM from SLR Systems set¨ a flag in the Z System to show whether or not they encountered any fatal¨ errors during the assembly, and the flow control command "IF ERROR" can test¨ the state of that flag. We can improve our script as follows: EDIT MYPROG.Z80;ZAS MYPROG;IF ~ERROR;MLOAD MYPROG;FI In this script the MLOAD command will only be executed if the program error¨ flag has not been set by ZAS (the tilde '~' has the meaning 'not'). Typing¨ all those flow control commands manually would be more trouble than entering¨ single commands at a time, but with an alias we are still typing only two¨ letters: "DO". So far so good. But what happens when we want to start work on another¨ program, say NEWPROG? Do we have to create a new alias, such as DONEW? The¨ answer is that the alias program actually does much more than just copy a¨ command script as is into the multiple command line buffer. It is capable¨ of making parameter expansions, the simpler examples of which are like the¨ parameter expansions that occur with the CP/M SUBMIT program. We can store¨ the alias script as EDIT $1.Z80;ZAS $1;IF ~ERROR;MLOAD $1;FI The '$1' is a symbol representing the first token after the command on the¨ command line that invoked the alias program. Thus when we enter the command¨ "DO MYPROG" we get the first script we discussed, but when we enter "DO¨ NEWPROG" we get a command line for working on NEWPROG instead. A single¨ alias thus becomes very flexible. There are quite a number of parameter¨ forms that can be processed by aliases, and I refer you to Rick Conn's¨ "ZCPR3, The Manual" and various HELP files for more detailed information. Now let's try something a little trickier. Sometimes we have already¨ edited a file and just want to assemble and load it (if there is no error in¨ assembling, of course). So we create an alias called AL (for assemble/link) ZAS $1;IF ~ERROR;MLOAD $1;FI [I am using ZAS in these examples rather than the SLR Z80ASM, which I¨ prefer, because the SLR assemblers can produce a COM file directly in one¨ pass and do not need MLOAD or the flow control error checking. Thus they do¨ not serve the purposes of my example here.] Now what do you think will¨ happen if we define our DO alias as follows: EDIT $1.Z80;AL $1 Do you think that will work? One alias inside another? Well, it will¨ indeed! Aliases can be nested. How deeply? Without any limit! Before we¨ explain why this is, let's look at an even more fascinating example. When I¨ sit down to work on a program, I typically go through one edit/assemble¨ cycle after another (just don't seem to be able to get it right the first¨ time). So I make my DO alias have the following script: EDIT $1.Z80;AL $1;DO $1 This alias actually invokes itself!! When one cycle is finished, it just¨ goes back for more. Now let's look at what goes on in the system after we¨ enter the command "DO MYPROG". The DO alias expands its script and writes¨ the following command line into the multiple command line buffer: EDIT MYPROG.Z80;AL MYPROG;DO MYPROG. After the editing is finished, AL runs, expands its script, and fills the¨ command line buffer with the following command line: ZAS MYPROG;IF ~ERROR;MLOAD MYPROG;FI;DO MYPROG Note that the alias always appends to its own script any other commands in¨ the command line after itself (hence the DO MYPROG on the end). Now ZAS¨ runs, and, depending on whether there were errors or not, MLOAD may run. ¨ Finally ZCPR3 gets to the DO command, and we are right back where we¨ started. The whole process is repeated (and repeated again). In fact, the¨ only trouble with this alias is that there is no way out! You can't stop! Well, we all hope we will get the program right eventually, so we¨ really would like to be able to get out of the alias. Flow control can help¨ us again. Consider the script EDIT $1.Z80;AL $1;ECHO EDIT AGAIN?;IF INPUT;DO $1;FI Now, before reinvoking DO, the alias asks us if we want to edit the file¨ again. If we give a negative answer (anything other than carriage return,¨ space bar, 'Y' for yes, or 'T' for true), the loop is broken. If we answer¨ affirmatively with a quick tap of the return key, we start again. Very¨ quick and easy. There is one subtle problem, however. If you go through the exercise¨ of expanding the alias scripts, you will see that with each cycle an extra¨ 'FI' builds up at the end of the command line. Even more careful analysis¨ will show that with each cycle we go one IF level deeper as well. One of¨ two problems will eventually spoil our plan. Either the command line will¨ get so long that it won't fit in the command line buffer, or we will run out¨ of IF levels (eight is the maximum). What can we do about these problems? The FCP has the XIF command precisely for this reason. If we put an¨ XIF command at the beginning of the script, we will reset the IF system to¨ level 0 every time we reenter the loop. Then the limit will be overflow of¨ the command line. When this happened to me, I invented a special type of¨ alias -- the recursive alias -- and incorporated it into my VALIAS program¨ (as far as I know only VALIAS and ARUNZ support this alias type). It works¨ the same as a regular alias except for one thing -- it does not append to¨ the script expansion any commands that were pending in the command line¨ buffer; it just throws them away. Thus in the above example all the FIs¨ would be discarded when DO was invoked again, and the pileup would be¨ avoided. When an alias is created with VALIAS, one can select either a¨ normal alias or a recursive alias. But note that no other command can ever¨ follow a recursive alias on a multiple command line. Recursive aliases¨ should be used only in special cases like the one described here. Shells Aliases are not the only command line generators. Most shells also¨ generate command lines for the user. In some cases (VCED, described above,¨ and MENU) this is their main purpose; in other cases it is secondary¨ (VFILER). Before we examine the way they generate command lines, let's look¨ at the way shells operate in the Z System. The essential purpose of shells is to create just the kind of recursive¨ command situation we were just developing with our alias example. But they¨ achieve that function in a very different way. A shell has a kind of¨ schizophrenic personality as a result of being invoked in two significantly¨ different circumstances. One circumstance is when it is invoked directly or¨ indirectly (e.g., from an alias) as the result of a user command. In this¨ case, the shell has one basic purpose -- to perpetuate its own existence as¨ a command. It does this by entering its name as a command into a special¨ buffer (area in memory) in the Z System called the shell stack. Having done¨ that, it can then return control to the operating system. (The smarter¨ shells generally do something a little more sophisticated at this point, but¨ the principle is correct as I have described it.) Now we come to the unique role of shells in the Z System. The CP/M¨ command processor gets commands from only two possible sources: 1) from a¨ submit file, if one exists, or 2) from the user. The Z System gets commands¨ from at least four sources and in the following order of priority (ignoring¨ the tricky role of ZEX): 1) from the multiple command line buffer; 2) from a¨ submit file; 3) from the shell stack; and 4) if all else fails, from the¨ user. Observe that so long as the shell stack has a command in it, the¨ command processor will never turn to the user for input! That is why one¨ can regard the shell as taking over the command processor function. While¨ the shell is running, it becomes the source of commands for the system. How does the shell do this? By expressing its second and more dramatic¨ personality. Another special buffer in the Z System, the message buffer,¨ contains a flag byte that is set by the ZCPR3 command processor to indicate¨ whether a program has been invoked as a user command or as a shell (or as an¨ error handler). We have already discussed the simple goal of the shell in¨ the former case. In the latter case the shell actually carries out its real¨ function in life. Let's consider the MENU shell as an example. When the MENU.COM is loaded as a shell, it displays a screen of command¨ choices to the user. Each single-character choice is associated with a¨ command line script, much like the alias script. When the user strikes a¨ key, MENU looks up the script associated with that character, expands the¨ script (substituting parameters), and puts the resulting command into the¨ multiple command line buffer. It then returns control to the ZCPR3 command¨ processor. ZCPR3 executes the commands in the command buffer one after¨ another until they have all been performed. Then, when the command buffer¨ is empty again, ZCPR3 looks in the shell stack, finds the MENU command¨ there, and runs MENU again. This process continues until a special user key¨ is entered (control-c in the case of MENU) that signals the shell that it¨ should remove itself from the shell stack. Then things return to the state¨ they were in before the shell was invoked initially by the user. ¨ Shells, by the way, can be nested (the usual shell stack is four entries¨ deep), so when one shell removes itself from the shell stack, control may¨ still not return to the user. Another shell, whose role was superceded by¨ the most recent shell, may now come back into control. With the MENU.COM the displayed menu of choices and the scripts¨ associated with the choices are both included in a text file that is read in¨ by the program. This makes it very easy for the user to create and modify¨ the display and the scripts. Considering again our program development¨ example, we might create a menu screen with the following display: S. Select name of program E. Edit program source code A. Assemble program to HEX file L. Load program to COM file R. Run program F. Full cycle (edit, assemble, load) These choices might be associated with the following command scripts: S setfile 1 "Enter name (only) of program to work on: " E edit $n1.Z80 A zas $n1 L mload $n1 R $n1 F edit $n1.z80;zas $n1;if ~er;mload $n1;fi There are two interesting new parameters illustrated in these scripts. ¨ One is the $N1 parameter. As part of the Z System environment buffer, four¨ system file names are defined. MENU can read these four file names and put¨ into scripts the complete filename ($Fn), the name only ($Nn), or the type¨ only ($Tn), where 'n' is 1, 2, 3, or 4. The 'S' selection sets the first¨ system file name using the program SETFILE, and the others then use it. The 'S' selection illustrates the other new script parameter --¨ prompted user input. When the script for choice 'S' is being expanded, the¨ text between quotes will be displayed as a prompt to the user, and one line¨ of user input will be substituted into the command line in place of the¨ prompt. It is with prompted input that many users get confused and make¨ mistakes. Suppose you want to be clever and helpful by displaying a¨ directory of existing programs to jog the user's memory before asking for¨ his choice. You might think of using the script S dir *.z80;setfile 1 "Enter program name: " This will not have the effect intended! One must not forget that the user¨ is prompted for input by the shell at the time the script is expanded, not¨ at the time when the command line is executed. In this example the user¨ will be prompted for his choice before the directory is displayed. Thus,¨ the directory display is useless. To achieve the result intended above you must combine scripts. You can¨ create an ARUNZ alias called SETNAME with the following script (ARUNZ¨ supports prompted input): SETNAME setfile 1 "Enter name of file: " The MENU script would then be S dir *.z80;arunz setname When the MENU script is expanded, the command becomes "DIR *.Z80;ARUNZ¨ SETNAME", and this command is then run. It is not until ARUNZ SETNAME is¨ executed that ARUNZ prompts the user for the name of the file. At this¨ point the directory of files with type Z80 has already been displayed on the¨ screen. There is obviously much more that could be said about the command line¨ generators in ZCPR3. The discussion here has been only an overview, but I¨ hope that it will inspire you to take a fresh look at and to experiment with¨ aliases and shells of all kinds: the standalone aliases generated by ALIAS,¨ VALIAS, TALIAS, or BALIAS; the text-file-based alias generator ARUNZ with¨ its ALIAS.CMD file; the menu- or macro-type shells MENU, VMENU, FMANAGER,¨ VFILER, and ZFILER; and the command-line history shells HSH and VCED. Plans for Next Time ------------------- As I said at the beginning of the article, I had planned to cover,¨ along with all the subjects above, techniques for customizing the Z-COM¨ self-installing version of Z System. But there just isn't the time or¨ space. So I will have to leave that for the next issue. Let me just say¨ one thing here. If you do not already have Z System running on your¨ computer and have held back on buying Z-COM from Echelon because you thought¨ it would not offer you the flexibility of a custom installation, hold off no¨ longer. Buy Z-COM! Start the exhilarating process of discovering Z System¨ now. By the time my discussion of Z-COM hacking is complete, you will know¨ how to get just as much flexibility with Z-COM as with a manually installed¨ version. It is much more fun to start with something that is working and to¨ improve it than it is to spend many frustrating weeks trying to get an¨ initial manual version working. I want to close with my usual invitation and encouragement -- please¨ write and call with your comments and suggestions of all kinds.