This, of course, fails for the same reason that I could not just enterì
commands with semicolons in the first place. The trick to get around thisì
is to use a command that for some reason Ron Fowler does not document in theì
MEX manual: POKE. It works like the Z-System command of the same name andì
places a byte of data into a specified memory address.
I knew the value I wanted to poke: 3BH, the hex value for the semicolonì
character. The question was, where should it go? To find out, I took aì
version of MEX set up with semicolon as the separator and the version withì
exclamation point as the separator and ran the utility DIFF on them (inì
verbose mode to show all the differences). Then I looked for the placeì
where the former has a semicolon and the latter an exclamation point. Forì
MEX-Plus this turned out to be 0D18H so that the MEX poke command would be
POKE $0D18 $3B
Note that MEX uses a dollar sign to designate hex numbers. The alias nowì
read
MEX mex:mex! $*!poke $$0d18 $$3b
Observe that a double dollar sign is needed to get a single dollar signì
character into a command. A lot of people forget this and end up withì
scripts that don't do what they're supposed to.
I tested this, and it works splendidly -- but with one possible 'gotcha'. ì
The commands passed to MEX must not invoke any script files that depend onì
the command separator being a semicolon (because it will be exclamationì
point until the final poke command runs); nor may the read files change theì
command separator (because the rest of the command sequence still assumes itì
is the exclamation point). For this reason, it is prudent to write allì
script files with only one command per line so that no separator is needed. ì
I haven't been doing this, but I will from now on!
One final word on the script. I actually did not do this exactly as Iì
have described. Instead, I left my MEX.COM set up with the semicolonì
separator, and I created a distinct ARUNZ alias called MEX! so that I wouldì
be reminded of the separator. This alias script reads
MEX! get 100 mex:mex.com;poke d18 "!;go $*!poke $$0d18 $$3b
This uses the famous poke&go technique originated by Bruce Morgen. MEX.COMì
is loaded into memory by the GET command, and then the Z-System POKE commandì
sets "!" as the command separator. Then the modified loaded code is run byìèthe GO command. The rest is as described previously.
A Spell-Check Alias
I try to remember to put all my writing through The Word Plus spellingì
checker that came with WordStar Release 4 so that as many typos as possibleì
will be caught. The procedure for doing that on a Z-System is a bitì
complicated because the text file is generally not in the same user area asì
the spelling check program. While writing my last TCJ column, I finally gotì
fed up with the complexity and automated the whole process using a set ofì
aliases.
I wanted to support the following syntax:
C1:TCJ>spell filename.typ dictname
If just the file name was given, the alias would prompt for the name of theì
special dictionary to use, and if not even a file name was given, then theì
alias would prompt for both names. A special version of the command,ì
ZSPELL, would take only the file name and would automatically use ZSYSTEM asì
the name of the special dictionary (it knows about mnemonics like ZCPR, MCL,ì
and RCP, and about all those special words like debugger, relocatable, andì
modem). We'll describe the general alias set first. In listing theì
aliases, we will write them in multiline format for easy reading;in theì
ALIAS.CMD file the scripts have to be on a single line (though I hope thatì
will change soon).
The user-interface alias, SPELL, deals only with the matter of how manyì
parameters the user has provided. It reads as follows:
SPELL
if nu $1;
/TW0;
else;
if nu $2;
/TW1 $1;
else;
/TW2 $1 $2;
fi;
fi
If no parameters at all are provided (IF NULL $1), then the secondary scriptì
TW0 is run. The leading slash signals ZCPR34 that the command should beì
directed immediately to the extended command processor. If a firstì
parameter but no second parameter is present (IF NULL $2), then theì
secondary script TW1 is run. Finally, if both parameter are provided, thenì
script TW2 is run.
The script TW1 includes a prompt only for the name of the specialì
dictionary file:
è TW1
$"Name of special dictionary: "
/TW2 $1 $'e1
The first token in any user response to the first prompt ($'E1 -- whenì
working with ARUNZ you should have a printout of the parameter DOC file) isì
used along with the file name that was already given, and both are passed toì
TW2.
The script TW0 includes prompts for both the file name and the specialì
dictionary:
TW0
$"Name of file to check: "
$"Name of special dictionary: "
if ~nu $'e1
/TW2 $'e1 $'e2
fi
The first tokens in the responses to the prompts are passed to script TW2. ì
If no file is specified for checking, the alias simply terminates.
Before we look at TW2, which does the real work, let me ask a rhetoricalì
question: why do we break this process up into so many separate aliases. ì
There are two main reasons. The first is that the command line buffer would overflow if all these smaller scripts were merged into a single big script. ì
The extended MCL we discussed earlier could overcome this problem, but forì
another reason we would still have to use separate aliases.
As I have discussed in past columns, ARUNZ cannot know at the time itì
expands a script what the results of conditional tests will be later whenì
the IF commands are run. Thus ARUNZ must process all user input promptsì
that appear in the script. This would mean asking for a file name andì
special dictionary even when the names were given on the command line. Theì
solution to this problem is to put the prompts in separate scripts that getì
invoked only when the information requested in those prompts is actuallyì
needed.
Now let's look at the script TW2.
TW2
path /d=tw:;
$td1$tu1:;
tw:tw $tf1 $tn2.cmp;
path /d=;
/twend $tn2;
$hb:
This is simpler than what you expected, no? Well, there is still a lot ofì
work imbedded in the subroutine script TWEND, which we will cover later. ì
Here we broke up the script solely to prevent MCL overflow.
The first command makes use of the ZSDOS file search path (see theìèarticles by Hal Bower and Cam Cotrill on ZSDOS in TCJ issues 37 and 38). ì
Although there was an attempt to update WordStar Release 4 to include someì
Z-System support, no such attempt was made with The Word Plus spell checker. ì
In general, the file to be spell-checked will be in one directory and Theì
Word files in another directory. The main program TW.COM could be locatedì
by the command processor using its search path, but TW.COM needs a number ofì
auxiliary files, such as the dictionary files. How can the system be madeì
to find all of these files at the same time. ZSDOS provides the answer.
I have replaced the standard Z-System PATH command with the ZSDOS utilityì
ZPATH (renamed to PATH). The first command in TW2 defines the DOS searchì
path to include the directory TW:, which is where I keep all the files thatì
are part of The Word Plus spell-checking package. Once that directory is onì
the DOS path, all files in it will more-or-less appear to be in the currentì
directory. Very handy! If you use ZDDOS, the search path is not available. ì
I will not show it here, but you can accomplish the same thing using onlyì
public files. It's just not quite as neat and straightforward. I amì
willing to pay the small memory penalty to get the nice extra features ofì
ZSDOS over ZDDOS.
The second command logs us into the directory where the file to beì
checked resides. If we did not include a DIR: prefix, we were alreadyì
there, but the extra command does not hurt, and it is nice to know that aì
directory can be specified explicitly (in either DU: or DIR: form) for theì
file to be checked. There could be a problem if the file is in a user areaì
above 15, since you may not be able to log into that area. My configurationì
of Z34 allows this, but when I run BGii I lose this feature (and I sure missì
it). If you can't log into those areas, then you should not keep filesì
there that you want to spell-check.
The third line actually runs the spell checker (you knew that had toì
happen some time!). Notice that even if the user specified a file type forì
the special dictionary, type CMP is used. Only the name ($TN2) without theì
type is taken from the user. As the master program TW.COM is run, it willì
find its component program files (e.g., SPELL.COM, LOOKUP.COM, MARKFIX.COM)ì
and the various dictionaries in the TW: directory thanks to ZSDOS, and itì
will find the text file in the current directory. As it works through theì
text, if there are any questionable words, it will write out a fileì
ERRWORDS.TXT to the current directory. If any words are added to theì
special or UPDATE dictionaries, then the modified dictionaries will be readì
from TW: but written out to the current directory. You must understandì
these facts in order to understand the rest of the script.
Once the spell-checking is complete, the ZSDOS path is set back to nullì
(unless I have a special need to have the DOS perform a search, I leave itì
this way to avoid surprises). Then the ending script TWEND is run, andì
finally the original directory ($HB:) is restored as the current directory.
Now let's look at TWEND. As it is invoked, the name of the specialì
dictionary is passed to it. TWEND's job is to clean up scratch files and toì
take care of any updated dictionaries. It reads
è TWEND
if ex errwords.txt;
era errwords.txt;
fi;
/dupd $1;
/dupd updict
For efficiency and to prevent MCL overflow, the dictionary updating isì
performed by yet another subroutine script, DUPD. It gets called twice,ì
once with the special dictionary (if any) and once with the updateì
dictionary. It reads as follows:
DUPD
if ex $tn1.cmp;
mcopy tw:=$tn1.cmp /ex;
fi
If an updated version of the specified dictionary exists in the currentì
directory, then it is copied to the TW: directory, overwriting any existingì
file of that name (MCOPY option E). The source file is then erased (MCOPYì
option X). Oh yes, I almost forgot; the MCOPY here is my renamed version ofì
the COPY program supplied with ZSDOS.
That is it except for showing you the special ZSPELL version of theì
alias. Notice that I make the "ELL" part of the command optional byì
inserting the comma in front of that part of the alias name. I also allowì
the script to be invoked under the name ZTW. The main SPELL script actuallyì
has the name "TW=SP,ELL" on my system. Since TW: is not on my commandì
search path, the command "TW" will invoke the ARUNZ script unless I am inì
the TW: directory at the time.
ZTW=ZSP,ELL
if nu $1;
/ZTW1;
else;
/TW2 $1 zsystem.cmp;
fi
ZTW1
$"Name fo file to check: "
if ~nu $'e1
/TW2 $'e1 zsystem.cmp
fi
I hope you find these alias examples useful and instructive. That's all forì
this time. See you again in two months.
[This article was originally published in issue 41 of The Computer Journal,
P.O. Box 12, South Plainfield, NJ 07080-0012 and is reproduced with the
permission of the author and the publisher. Further reproduction for non-
commercial purposes is authorized. This copyright notice must be retained.
(c) Copyright 1989, 1991 Socrates Press and respective authors]è