The main topic for this column will be the second installment of the¨ discussion of ZFILER, the Z-System filer shell (Yes, I'm going to fool you¨ all by actually doing as I promised last time!). As usual, there are¨ several other items I would like to discuss briefly first. The original¨ list included the following: (1) a Z-Node update; (2) a hint on patching¨ those hardware-specific utilities provided by computer manufacturers that¨ don't work right under NZ-COM so that they will work; (3) my views on the¨ appropriate way for Z-System programs to be coded for compatibility with¨ various stages of evolution of ZCPR3; (4) an update on making PRL files¨ without a PRL-capable linker; and (5) a suggestion to programmers for how to¨ deal with bad-directory-specification errors under Z-System. As usual,¨ including all this material put TCJ's ink supply at risk, and I had room¨ only for the first two items. Now that I have finished the article and am¨ coming back to hone this section, I also have to add that I did not have¨ room to complete the ZFILER discussion; the topics of customization and¨ configuration will have to wait until another time. Z-Node Update As I mentioned in a previous issue, I have been hard at work trying to¨ survey the Z-Node remote access systems (RASs) and to revitalize the¨ network. It was Echelon's creation of that network that first got me¨ started as a Z-System activist, and I continue to feel that it is the single¨ most important source of mutual support for users and developers of the Z­ System. My list of currently active nodes is reproduced in Listing 1. I have¨ added three new columns to Echelon's original format. The one on the far¨ right shows the last date on which operation of the system was verified. ¨ The column to its left indicates for nodes accessible by PC-Pursuit the code¨ for the outdial city and the highest bit rate supported for that city. At this point I have at least attempted (usually several times) to call¨ every North American Z-Node on Echelon's old list. Where contact was made,¨ I requested that the sysops register with Z Systems Associates, and the ones¨ who have done so are designated by an "R" in the leftmost column. For this¨ listing I have retained a number of systems that seemed still to be¨ interested in the Z-System but have not yet registered. However, if I do¨ not hear from them, they will be dropped from the next list. So, if you use¨ one of those nodes (or one of the nodes I have already dropped), please let¨ the sysop know that you want him to continue as a Z-Node, and suggest that¨ he delay no longer in registering. Once we have all the sysops' names and¨ addresses, we can start to think about things like a software distribution¨ chain to make it easier for the nodes to stay current with Z-System software¨ developments. Many of the boards I called had only very old versions of¨ programs. I would like to extend a special welcome to several new Z-Nodes, and I¨ look forward to doing this in each column as more new nodes come on line. ¨ Bob Dean has for some time run the excellent Drexel Hill NorthStar system in¨ Drexel Hill, Pennsylvania, just outside Philadelphia. When I saw what an¨ enthusiastic Z-System supporter he was, I asked Bob if he would like to¨ become a Z-Node. He was delighted and has joined the network as node number¨ 6. Ted Harmon in Minneapolis has been working for some time at getting his¨ node (#80) up, and I hope that he will be in regular operation by the time¨ you read this. So far I have not succeeded in connecting with his node. Bob Cooper in Ventura, California, is the newest node (#81), and from¨ many voice conversations with him during the past couple of months I know¨ how enthusiastic Bob is. His node is no in full scale operation. Since¨ newly commissioned systems generally have fewer callers than established¨ systems, their sysops would, I am sure, especially appreciate your calls. Patching Programs for NZ-COM As I described in an earlier column, NZ-COM creates a Z-System¨ automatically from the host CP/M-2.2 system by setting up a virtual system¨ underneath the original one and forwarding calls presented to the virtual¨ BIOS (basic input/output system, the hardware-specific portion of the¨ operating system code) to the "real" BIOS except for warm boots, which are¨ intercepted to prevent a reloading of the host CP/M system. This produces a¨ software environment that is indistinguishable from a manually installed Z­ System, and all programs that adhere to CP/M or Z-System standards should¨ run perfectly. There is, however, a class of programs that generally do not follow those¨ rules. These are most often utilities supplied by the manufacturer of the¨ computer to perform special operations, such as configuration of the¨ hardware. They usually make assumptions about the internals of the¨ operating system code -- in most cases, the BIOS -- under which they are¨ running. (Regrettably, they usually take no steps to verify that the¨ environment is what they expect -- see Bridger Mitchell's column in TCJ¨ #36.) Programs of this type generally do not run correctly under NZ-COM, just¨ as they would not run correctly if the user rewrote his or her BIOS without¨ taking into account the assumptions the manufacturer made as to the location¨ of certain data structures in the BIOS. (This same problem is less likely¨ to occur, I believe, in a Z3PLUS Z-System running under CP/M-Plus, because¨ Z3PLUS operates as an RSX, which was a fully defined system facility under¨ CP/M-Plus. Manufacturers' configuration utilities are more likely to¨ understand RSXs and operate correctly under them.) There are two approaches to dealing with this challenge. In many cases¨ the configuration utilities are used only when the system is initially set¨ up (and the newly configured system is then stored on the system tracks of¨ the boot disk). In other cases the configuration utilities are used only¨ when the system is cold booted (i.e., powered up). These situations pose no¨ problem, since the hardware utilities can be run under standard CP/M before¨ the NZCOM command is issued to invoke the Z-System. In some cases, however, the configuration utilities are needed on a more¨ regular basis. Utilities for setting baud rates, screen attributes, or¨ printer characteristics may fall into this class. These situations can¨ present a considerable nuisance to the computer user, who easily becomes so¨ accustomed to the facilities of Z-System that he or she nearly loses the¨ ability to operate under vanilla CP/M. I can suggest two possible solutions¨ here. One approach is to put the configuration utility in a directory that is¨ not on the path (or to give it a new name) and invoke it indirectly by way¨ of an alias. The alias would initiate a SUBMIT batch operation, as¨ described in the NZ-COM manual, that would first remove the NZ-COM system¨ using the NZCPM command, then run the configuration utility under vanilla¨ CP/M, and finally reload the standard NZ-COM system. (If you are very¨ clever, you can probably make an ARUNZ alias figure out which of several¨ standard versions of NZ-COM is running and automatically reload it.) This¨ approach will give the appearance of successful operation under NZ-COM of a¨ utility that actually cannot run under it. The main penalty is the extra¨ time it takes to exit from and return to the NZ-COM system. There is also a¨ problem if you have loaded a module (RCP, FCP, NDR, etc.) that is not the¨ one in your standard configuration. It will be lost. The second approach is to make the utility work properly under NZ-COM. ¨ In many cases I have been able to accomplish this without the source code¨ for the utility by using the technique described below. But be forewarned;¨ the technique will not always work. Most of these BIOS-specific utilities determine the address of the data¨ structures to be modified by adding an offset to the BIOS warm boot entry¨ point whose address is obtained from the warm boot vector (jump instruction)¨ stored at address 0000H in a CP/M system. Usually the instruction LD¨ HL,(0001) is used to load the address into the HL register. The problem is¨ that under NZ-COM this vector points to the NZ-COM virtual BIOS, and offsets¨ from it generally fall right in the middle of one of the Z-System modules. ¨ Not only does the utility fail to make the desired change to the machine's¨ real BIOS; it even corrupts some other code, resulting in behavior that¨ ranges from unpredictably bizarre to instantly catastrophic. The simplest corrective patch consists of replacing the LD HL,(0001)¨ indirect load instruction with a LD HL,WBOOT direct load instruction, where¨ WBOOT is the actual warm boot entry point address of the real BIOS. This¨ kind of patch is performed by using some utility to scan the utility's code¨ for occurrences of the three-byte sequence 2A (load HL indirect immediate),¨ 01, 00 (the immediate address 0001H). ZPATCH is a natural candidate for¨ performing the search, but it unfortunately uses 00 as its string terminator¨ and thus cannot search for a zero byte. Perhaps Steve Cohen will eliminate¨ this minor shortcoming in a future version of ZPATCH (hint, hint -- I know¨ you're reading this column, Steve). The next step is to replace the 2A byte with 21, the direct load opcode. ¨ The other two bytes, 01 and 00, are replaced by the BIOS address that you¨ have determined previously (perhaps by looking at the contents of memory¨ location 0001H while running normal CP/M). The low byte is entered first in¨ place of the 01 (it will always be 03). The second byte will be a some¨ relatively large number, almost always with a first hex character of D, E,¨ or F. Blindly replacing sequences as described above does have its risks. ¨ Without careful inspection you cannot be sure that the sequences are being¨ used to perform the assumed function. If you are an experienced coder, you¨ can use a disassembler (such as the one built into debuggers like DDT and¨ DDTZ) to examine the code. The LD HL,(0001) should be followed fairly soon¨ by an ADD HL,DE or ADD HL,BC to add the offset to the BIOS structure to be¨ modified. There is also always the possibility that the utility gets the¨ address it needs in some other way (for example, LD A,(0002) will get the¨ page address of the BIOS). The procedure I just described "hardwires" the utility to a BIOS at a¨ specific address. This is fine until you someday set up a new CP/M host¨ system with a different BIOS starting address or until you give this¨ modified version to a friend with a different BIOS. By then you will have¨ forgotten all about these patches and will be pulling your hair out trying¨ to figure out why the utility that worked perfectly before is now¨ misbehaving. By then you will also have forgotten exactly what was patched¨ and will not know how to fix the utility. A more sophisticated patch will allow the program to work with a BIOS at¨ any address. This approach follows Bridger Mitchell's philosophy of "know¨ your environment." The patch checks to see if it is running under NZ-COM¨ and makes the changes only when it is. Source code for this patch, which can be applied using the MLOAD utility,¨ is given in Listing 2. There are several pieces of information that you¨ will have to determine in advance and enter into the patch code. I have put¨ all that information at the front of the patch using macros where¨ appropriate. If you do not have a macro assembler, you can always put the¨ material directly into the code where the macros are called instead. First, as before, you have to determine all the addresses at which¨ indirect loads from address 0001 have to be changed to direct loads. These¨ values have to be placed in the patch address table in the patch code. ¨ Since the patch will be added to the end of the existing utility code, you¨ will also have to determine that address. You can calculate this from the¨ file size of the COM file in records as displayed either by STAT or by SD¨ with the "C" option. Alternatively, you can read the COM file into a¨ debugger and note the next free address it reports. This address must be¨ entered as the value of the symbol PATCHADDR. Most of the utility programs I have patched this way start at 100H with a¨ jump to the actual working code. The destination address of that jump must¨ be determined and entered as the value of the symbol STARTADDR. If the¨ utility does not begin with a jump, then you will have to examine the code¨ at 100H and determine the instructions that occupy the first three or more¨ bytes. These instructions should be entered into the REPLACED macro in the¨ patch. The address of the next instruction after the ones replaced should¨ be entered as the value for STARTADDR. Once you have put all the necessary data into the UTILPAT.Z80 source¨ code, it should be assembled to a HEX file. Then the patch can be added to¨ UTIL.COM to make NEWUTIL.COM by using the following command: MLOAD NEWUTIL=UTIL.COM,UTILPAT Be sure to save the original program, and test the new version carefully. ¨ One additional word of caution. Some utilities cannot be expected to work¨ under NZ-COM no matter what you do. For example, a utility that takes the¨ running CP/M system and writes it to the system tracks will fail because¨ under NZ-COM the only part of the CP/M system that is still present is the¨ BIOS. For the same reason, programs that try to patch the BDOS will fail. ZFILER, Installment 2 ===================== Last time we covered most of the built-in functions and had left the¨ macro commands for this time. One built-in function was also deferred, the¨ option command "O", and we will take up that subject first. The Option Command When the option command letter "O" is pressed, a special options screen¨ is displayed. Eleven operating characteristics can be changed from a menu¨ with the following appearance (approximately): A. single replace query Y B. group replace query Y C. archive replace query N D. verify query Y E. verify default Y F. suppress SYS files Y G. sort by file name N H. set copied file attributes Y I. use dest file attributes Y J. archive destination Y K. search path for CMD file N We will explain the meaning of each of these options in a moment. First a¨ few words about the mechanics. While the options menu is displayed,¨ pressing the index letter at the left will cause the setting of the¨ corresponding option to be toggled, and the new state will be shown in the¨ column at the right. The listing above shows the initial state of the¨ options in my personal version of ZFILER. When you are finished toggling¨ options, just press carriage return to return to the main ZFILER menu. ¨ These option settings are stored in the ZFILER shell stack entry and will¨ thus continue in effect through all ZFILER operations until the command "X"¨ is used to terminate the shell. The first three options concern how ZFILER responds when copying (or¨ moving) files and a file of the same name already exists in the destination¨ directory. Item A applies when individual files are copied (commands "C"¨ and "M"); item B applies when a group copy is performed (commands "GC" and¨ "GM"); and item C applies when performing an archiving operation (command¨ "GA"). If the option is "YES", then ZFILER will prompt one before existing¨ files are erased and give one the chance to cancel the operation for that¨ file, leaving the existing file intact. If the option is toggled to "NO",¨ then existing files will be overwritten without even a message. The next two options affect the verification of the copied file in the¨ destination directory. Item D determines whether or not the user will be¨ asked about verification. If this option is set to "N", then the state of¨ option E will determine whether or not verification is performed on file¨ copies. If this option is set to "Y", then before each copy, move, group¨ copy, or group move, ZFILER will put up the prompt "Verify (Y/N)?". The next two options affect the way files are displayed on the screen. ¨ If item F is set to "Y", then files with the "system" or SYS attribute will¨ be suppressed, that is, not included among the selected files on which¨ ZFILER acts. This is a reasonable choice for this option, since the most¨ common use of the SYS attribute is to make the files disappear from¨ consideration during file maintenance and display operations. Item G on the¨ options menu determines whether files are sorted first by name and then by¨ type or vice versa. Changing this option is presently equivalent to the "A"¨ command from the main ZFILER command menu. The next three options concern how file attributes are treated when files¨ are copied. One possibility is to create new files with a clean slate of¨ attributes (that is, all attributes reset: not read-only, not SYS, not¨ archived). This is what will happen when option H is set to "N" (but note¨ option J, which may override this). When the attributes of the destination¨ file are to be set, they can be set in two possible ways. If a file of the¨ same name existed in the destination directory, then its file attributes¨ could be used for the copy that replaces it. This is what will be done if¨ option I is set to "Y". If option I is set to "N" or if there was no¨ matching file in the destination directory, then the attributes will be set¨ to match those of the source file. Option J can set a special override for the archive or ARC attribute. If¨ the option is set to "N", then the ARC attribute is treated just like the¨ other attributes according to options H and I. If option J is set to YES,¨ then the destination file always has its ARC attribute set. There was at one time a great deal of controversy over the way the ARC¨ attribute is handled under ZFILER. At one time it was always reset, so that¨ the destination file would be marked as not backed up. Another school of¨ thought asserted that, on the contrary, the file was backed up, since there¨ was a copy of it on the source disk from which the file was copied. That¨ latter argument made considerable sense in the case of copying files from a¨ master disk to a RAM disk before a work session. Here it was certainly¨ important to start with all files marked with the ARC attribute so that one¨ could easily tell at the end of the session which files had been modified so¨ that they could be copied back to the permanent storage medium. All in all, I never understood this controversy. Both approaches clearly¨ have merit, and since ZFILER supports both, I saw no reason for all the¨ argument. In a future version of ZFILER, I think I would like to add a flag¨ word that would indicate which drives should automatically set the ARC flag¨ when the J option is set to YES. That way, the option could be made to¨ apply to RAM drives only. The final item on the option menu, option K, determines how the macro¨ command file ZFILER.CMD (see discussion below) will be located. There are¨ two choices. If option K is set to YES, then ZFILER will look for it first¨ in the currently displayed directory and then along the entire ZCPR3 search¨ path. This option is useful if one wants to have different macro command¨ files that apply to specific directory areas. Alternatively, if option K is¨ set to NO, then ZFILER locates the CMD file without using the path. ¨ Depending on how ZFILER is configured (this will be discussed another time),¨ the file will be sought either in the root directory of the path (the last¨ directory specified on the search path) or in a specific drive/user area¨ coded into ZF.COM. This alternative results in faster operation, especially if the specified directory resides on a RAM disk. The options controlled by the option menu can also be permanently changed¨ in the ZFILER program file using a patching utility like ZPATCH. In the¨ first page of the file, you will see the ascii string "OPT:". The eleven¨ bytes following this string contain the startup values for the eleven¨ options. Patch a byte to 00 for NO or FF for YES. ZFILER Macros Although ZFILER can accomplish many tasks using its built-in functions,¨ its real power comes from the macro facility, which allows it to be extended¨ to include any functions that can be performed using combinations of other¨ programs. This is where ZFILER really makes use of its power as a shell. ¨ First I will describe how the macro facility is used, and then I will¨ describe how the user defines the macro functions. As with the built-in¨ functions, macro functions can operate either on single files or on groups¨ of files. The single-file macro facility is well developed and was already¨ present in nearly the same form in VFILER; the group macro facility is new¨ with ZFILER and has not been fully developed yet. Invoking Macros One way to initiate a macro operation on the pointed-to file is to press¨ the macro invocation key, which is normally the escape key. A prompt of¨ "Macro:" will appear after the normal ZFILER command prompt. At this point¨ you have several choices. If you know the key corresponding to the macro¨ you want to run, then you can simply press that key. ZFILER will then¨ construct a command line and pass it on to the command processor for¨ execution. If ZFILER is configured for instant macro operation (it¨ generally is), then macros associated with the number keys "0" through "9"¨ can be initiated without the macro invocation key; the number key entered¨ alone at the main ZFILER command prompt will generate the macro function. If you press the macro invocation key a second time, a user-created help¨ screen will be displayed. This screen generally lists the available macro¨ functions. You can now press the key for the desired function, or you can¨ press carriage return to cancel the macro operation and return to the main¨ ZFILER menu. The help menu screen will also be displayed if you press the¨ "#" key. This is a holdover from VFILER and arises in part because of the¨ structure of the file in which the macros are defined (more on this¨ shortly). Group macros are invoked in a similar way from the group function command¨ line. After you have tagged a group of files, press the "G" key to enter¨ group mode. The prompt will list only the built-in group functions, but if¨ you press the macro invocation key, you can proceed as described above for¨ single-file macro operations, except that the macro function will be¨ performed on each of the tagged files. The group macro facility works a little differently than the single-file¨ macro facility. Since the command line would generally not be long enough¨ to contain the commands for all the tagged files, the group macro facility¨ works by writing out a batch file for processing by ZEX or SUBMIT. In this¨ way there is virtually no limit to the number of files on which group macros¨ can operate. There are many configurable options (described below) that are associated¨ with the group macro operation. These include the name of the ZEX or SUB¨ batch file, the directory to which it is written, and the command line that¨ ZFILER generates to initiate the batch operation. The NZ-COM version of¨ ZFILER uses a file called ZFILER.ZEX and the command line "ZEX ZFILER". The¨ Z3PLUS version, under which ZEX will not run, uses a file called ZFILER.SUB¨ and a command line of "SUBMIT ZFILER". Since macros (and the main menu "Z" function) work by passing commands to¨ the command processor, file tags will be lost in the process, and when¨ ZFILER resumes operation, it starts afresh. In a future version of ZFILER,¨ I hope to preserve the tag information by having it optionally written to a¨ temporary file (the shell stack entry is far too small) and read back in¨ when ZFILER resumes. Defining Macros -- The CMD File Now let's learn how to define the macro functions we want. As I¨ indicated earlier, the macros are defined in a file called ZFILER.CMD (the¨ ZFILER ComManD file). In the version of ZFILER distributed with NZ-COM and¨ Z3PLUS, the CMD file is searched for in the root directory of the ZCPR3¨ command search path. As described earlier, the option menu allows the¨ entire path to be used. There are also some additional configurable options¨ that will be discussed another time. You must be sure to put your¨ ZFILER.CMD file in the appropriate directory. If the file cannot be¨ located, you will still get the macro prompt, but, after you have specified¨ a macro key, the error message "ZFILER.CMD NOT Found" will be displayed. The ZFILER.CMD file is an ordinary text file that you can create with any¨ editor or wordprocessor that can make plain ascii files (WordStar in¨ nondocument mode, for example). The CMD file has two parts. The first part¨ contains the macro command definitions; the second contains the help screen¨ (described earlier). In the first part of the CMD file, each line defines a macro. The¨ character in the first column is the key associated with that definition¨ (case does not matter). Macros can be associated with the 10 number keys,¨ 26 letter keys, and all printable special characters except for "#"¨ (explained below). The space character and all control characters are not¨ allowed. Owing to an oversight, the rubout character can be associated with¨ a macro! After the character that names the macro there can be any number of¨ blanks (including zero). If the first non-blank character is "!", then the¨ "strike any key" (shell-wait) prompt will appear before ZFILER puts up the¨ file display after a macro command is run. This should be used whenever the¨ macro will leave information on the screen that you will want to read. ¨ After the "!" there can again be any number of spaces. Any remaining text¨ on the line is taken as the script for the macro command. The second part of the CMD file starts when a "#" character is found in¨ the first column (hence the exclusion of that character as a macro name). ¨ Once that character appears, all remaining text, including text on the line,¨ will be used as the help screen. Since ZFILER will add some information to¨ the display (the name of the pointed-to file and a prompt), you will¨ generally want to keep the help screen to no more than 20 lines, including¨ an extra blank line at the end for spacing. With some experimentation you¨ will get the hang of designing this screen. Macro Scripts ZFILER macro scripts are similar to those in ARUNZ and in the other menu¨ shells (MENU, VMENU, FMANAGER) in that parameter expressions can appear. ¨ The critical parameters -- the ones that implement functions that cannot be¨ achieved any other way -- are those that convey information about the¨ directory currently displayed by ZFILER and about the pointed-to file. ¨ Parameters consist of a "$" character followed by one of the characters¨ listed below. User prompt parameters ' User input prompt " User input prompt Parameters for directories - currently displayed directory C DIR form D Drive letter U User number - home directory (from which ZFILER was invoked) H DU form R Home DIR Parameters for pointed-to file P Full information (DU:FN.FT) F File name (FN.FT) N File name only T File type only Special parameters ! GO substitution indicator $ The dollar character The parameters are listed in a special order above, and we will explain¨ that later. First we will just present the meaning for each parameter. The parameter expressions $" and $' are used to display a prompt message¨ to the user and to read in a response string. Single and double quotes are¨ equivalent. Once the prompt parameter has been detected, all subsequent¨ characters up to one of the quote characters are displayed as the user¨ prompt. Thus, if I am not mistaken, there is presently no way to put either¨ quote character into the prompt. The end of the line or the end of the file¨ will also terminate the prompt. No special character interpretation is performed while expanding the¨ prompt. If you want to make fancy screens, you can include escape sequences¨ and some control characters (obviously carriage return won't work). In the¨ future, ZFILER should be enhanced to provide a means to generate all control¨ characters, to allow special characters to invoke screen functions based on¨ the current terminal definition, and to expand directory and file parameters¨ in the prompt. Now for the directory parameters. Parameters C, D, and U return¨ information about the currently displayed directory, while H and R return¨ information about the home directory, the one from which ZFILER was¨ originally invoked. PLEASE NOTE: macros always operate from the home¨ directory. The reason for this is that ZFILER can display directories with¨ user numbers higher than 15 even when it is not possible to log into these¨ areas. If you want to operate in the displayed directory, then your script¨ must include an explicit directory-change command of the form "$D$U:" at the¨ beginning (or "$C:" if your system requires the use of named directories)¨ and a command of the form "$H:" (or "$R:") at the end. One special note about the parameters that return directory names. If¨ the directory has no name, then the string "NONAME" is returned. This will¨ presumably not match any actual name and will lead, one hopes, to a benign¨ error condition. These parameters are included only for systems that do not¨ allow directories to be indicated using the DU form (I hope that few if any¨ systems are set up this way). Now we come to the four file name parameters. They allow us to generate¨ easily the complete file specification or any part of it. Note that "$F" is¨ not quite the same as "$N.$T". The latter always contains a dot; the former¨ does not if the file has no file type. Finally, we have two special parameters. "$$" is included to allow a¨ dollar sign character to be entered into the script. "$!" is a control¨ parameter that is used only when a group macro is executed. If it is placed¨ immediately before a token (string of contiguous characters), then that¨ token will be replaced by the string "GO" on all but the first expansion of¨ the script. This allows group macro scripts to operate faster by avoiding¨ repetitive loading of a COM file. It must be used with great care and¨ consideration, however, for reasons that I will not go into here. Rules for Script Expansion ZFILER follows a specific sequence of steps when expanding a script, one¨ that gives it a special feature that, I would guess, few users are aware of. ¨ The first step in the expansion is to process only the user-input prompt¨ parameters, substituting for the prompt whatever the user entered in¨ response. This results in a modified script that is then processed by the¨ second step in the expansion. Because the expansion is handled this way,¨ the user input ^Scan include ZFILER script parameters! Thus the script can¨ be used to write a script. You will see an example of this later. The second step in the expansion is to substitute values for the¨ directory parameters, which are a kind of constant. They do not change as a¨ function of the pointed-to file. Finally, in a third step, the remaining¨ parameters are expanded. For group macros, this final step in the expansion¨ is repeated for each of the tagged files. The file parameters are expanded¨ differently for each file, and, starting with the second tagged file, the¨ "$!" parameter causes "GO" substitution. Macro Examples Listing 3 shows an example of a ZFILER.CMD file, one designed to¨ illustrate some techniques of macro writing. While writing this article, I¨ discovered that one can include blank lines as shown to make the CMD file¨ easier to read. The help screen part of the listing is taken from my¨ personal script file (which, I have to confess, I have not really worked¨ very hard at). The macro definition part of the listing includes only a few¨ of the definitions. The macro "Q" is included to illustrate a very simple, but useful, type¨ of macro. It invokes the very powerful file typing program QL (quick look)¨ on the pointed-to file. This is handy when you want more powerful viewing¨ capability than that offered by the built-in "V" command. QL can handle¨ crunched files and libraries, and it can display text or hex forward or¨ backward. Macro "U" uncompresses a file. It illustrates a more complex script that¨ involves flow control and parameters that extract individual components of¨ the pointed-to file name. It tests the file type to see if the middle¨ letter is "Q" or "Z". In the former case, it unsqueezes the file; in the¨ latter, it uncrunches it. The uncompressed file it put into the source¨ file's directory. Macros S, K, and B illustrate the use of input prompting. The first one¨ allows the user to specify the file attributes to be set. Note that the¨ prompt includes a helpful reminder of the syntax required by SFA. Macro K crunches files to a user-specified destination. It also¨ illustrates how one logs into the currently displayed directory. I do this¨ here so that a null answer to the prompt (i.e., just a carriage return) will¨ result in the crunched files being placed in the currently displayed¨ directory rather than in the home directory, as would otherwise be the case¨ (since that is where the macro runs from, remember). As a result, however,¨ this macro will not operate properly in user areas above 15 under BGii or¨ versions of the command processor that do not allow logging into high user¨ areas. Macro B performs a slightly more complex function. It not only¨ compresses the pointed-to file to a specified destination directory, but it¨ then marks the source file as having been backed up. A combination of the¨ group archive built-in command (to tag files that need backing up) and a¨ group macro B (to perform the backup) gives the ZFILER user a way to back up¨ files in crunched form on the backup disk. Macro M is included to show that a ZFILER macro, when it needs to do¨ something more complex than it is capable of doing all by itself, can pass¨ the task to an ARUNZ alias. The MOVE alias first determines whether the¨ source and destination are on the same drive. In that case, MOVE.COM is¨ used to perform the move. Otherwise, the source file is copied to the¨ destination and then deleted. What we have, therefore, is a MOVE command¨ that frees the user of the responsibility of worrying about which drives are¨ involved -- another example of how Z-System can free you from considerations¨ that need not concern you, that do not require human intelligence to decide. The final three macro examples are execution macros. Macro X causes the¨ pointed-to file to be executed. A more sophisticated version might check to¨ make sure that the file type is COM. I opted for the flexibility of¨ pointing, for example, to PROGRAM.Z80 and having PROGRAM.COM run. If there¨ is no COM file with a matching name, the error handler will take care of¨ things. You will note the leading colon before the "$n" parameter. It¨ makes sure that the current directory is searched even if it is not on the¨ path. Prompted input is used to allow a command tail to be included. The Z macro performs a user-specified function on the pointed-to file. ¨ Two separate user prompts allow both the command and a command tail to be¨ given. For example, if you wanted to squeeze the file to A0:, you would¨ enter "SQ" in response to the first prompt and "A0:" in response to the¨ second. The 0 macro illustrates how the response to a prompt can be used as a¨ ZFILER script. This macro takes care of all those functions we forgot to¨ include in ZFILER.CMD. The whole macro is just prompted input, and whatever¨ we answer will be run as a script. I use this function so often that I put¨ it on a number key so that it can be invoked with a single key rather than¨ the usual pair. Also, as you may have noticed, I include in the macro help¨ screen a list of the parameters that can be used. The only real limitation of this macro-to-write-a-macro approach is that¨ prompted input cannot be included in the response. As I write this,¨ however, it occurs to me that this limitation could be overcome by¨ recursively parsing the prompt parameters until none remain, and only then¨ going on to the subsequent macro expansion steps. Well, I was going to discuss patching and configuring ZFILER, but this¨ article is already too long, so that will just have to wait for another¨ time. I hope that this article will help you get more out of ZFILER. See¨ you in the next issue!