home *** CD-ROM | disk | FTP | other *** search
/ CP/M / CPM_CDROM.iso / jsage / znode3 / tcj / tcj41.ws < prev    next >
Encoding:
Text File  |  1994-09-02  |  22.9 KB  |  462 lines

  1.  
  2.                             The Z-System Corner
  3.  
  4.                                   Jay Sage
  5.  
  6.  
  7.    By the time you read this, summer vacation will probably be just a fondì
  8. memory for you, but it is August as I write this, and I have just returnedì
  9. from three weeks in Israel.  This was a total vacation.  I didn't touch orì
  10. even think about computers the whole time I was away, except at the very endì
  11. when my mind started to refocus on the responsibilities that awaited me atì
  12. home, including this TCJ column.  It was so nice to get "computerì
  13. compulsion" out of my system that I have not been all that eager to get backì
  14. immediately to my old routine...but I know it will happen soon enough.
  15.  
  16.    Having not thought about computing for a month, I had to work to recallì
  17. the things I was excited about before I left and planned to discuss in thisì
  18. issue.  Fortunately, I left myself some notes.  One item was theì
  19. continuation of the BYE discussion, this time covering the extended DOSì
  20. functions implemented in BYE.  The truth is I have neither the energy norì
  21. the time to take up that subject now.  Instead, I am going to come back onceì
  22. again to my favorite subject: aliases and ARUNZ.
  23.  
  24.    I think ARUNZ is the one thing that keeps me hooked on Z-System and notì
  25. eager to follow after the MS-DOS crowd.  Although I have looked hard, I haveì
  26. not found anything with the combined simplicity and power of ARUNZ for MS¡
  27. DOS.  The mainframe batch processing language REXX, which has been ported byì
  28. Mansfield Software to DOS machines, is far more powerful, and some day Iì
  29. hope to port a greatly simplified version to Z-System.  The DOS version ofì
  30. REXX, you see, takes over 200K of memory while it is running!  That oftenì
  31. does not leave enough memory, even on a 640K machine, for applicationì
  32. programs to run.  I think I actually have more problems running out of TPAì
  33. on my Compaq 386 than I do on my SB180!
  34.  
  35.    Anyway, for this column I am going to begin with a very brief report on aì
  36. rather dramatic change in the works for ARUNZ and the Z-System as a whole. ì
  37. Then I am going to describe two ARUNZ applications that I recently developedì
  38. for my own use.  I think they illustrate some interesting generalì
  39. principles, and you may even find them useful as they are.
  40.  
  41.  
  42.                      The Extended Multiple Command Line
  43.  
  44.    Most people who use ARUNZ aliases -- or even standard aliases -- soonerì
  45. or later run into a situation where the command line overflows and the wholeì
  46. process comes to a crashing halt (well, not really a crash, but a suddenì
  47. stoppage).  The standard Z-System configuration supports a multiple commandì
  48. line buffer (MCL) that can accommodate 203 characters.  The largest sizeì
  49. possible is 255 characters.  Either way, there comes a time when aliases areì
  50. invoked from command lines that already contain additional commands, and theì
  51. combined command line is too long to fit in the MCL.  People like Rickì
  52. Charnes would have this happen constantly if they did not adopt a strategyì
  53. to avoid the problem (more about that in one of our examples later).
  54.  
  55.    I have long been intrigued by the possibility of having a much longerì
  56. command line.  The command processor (CPR) has always used a word-sizeì
  57. (16-bit) pointer into the command line, and so, without any change in theì
  58. ZCPR34 code, the CPR could handle a command line as big as the address spaceì
  59. of the Z80.
  60.  
  61.    To verify this, I performed a simple experiment.  I configured a Z-Systemì
  62. with free memory after the MCL, and then, using the memory utility programì
  63. MU3, I manually filled in the command line with a very long multiple commandì
  64. line sequence terminated, as required, by a null character (binary zero). ì
  65. Sure enough, after exiting from MU3, the huge command line ran without aì
  66. hitch.
  67.  
  68.    The next step was to write a special new version of ARUNZ that could beì
  69. configured to recognize an oversized MCL.  Richard Conn set up theì
  70. environment descriptor (ENV) with a one-byte value for the length of theì
  71. command line that the MCL buffer could contain.  Thus there is presently noì
  72. way to support an extended MCL (XMCL) in a system-invariant way, that is, inì
  73. a way that allows programs to determine at run time how big the MCL is.  Weì
  74. are working on that problem right now, and, by the time you are readingì
  75. this, there will almost certainly be a new ENV type defined (81H) that usesì
  76. one of the remaining spare bytes in the type-80H ENV to report the size ofì
  77. XMCL to programs smart enough to check for it.
  78.  
  79.    The original, single-byte MCL size value in the ENV has to remain as isì
  80. and contain a value no larger (by definition) than 255 (0FFH).  That valueì
  81. is used by the command processor when new user input is being requested. ì
  82. There is no way for the CPR to allow users to type in command lines longerì
  83. than 255 characters without adding a vast amount of code to perform theì
  84. line-input function now so conveniently and efficiently provided by the DOS. ì
  85. A shell could be written that included such code, but I really can't imagineì
  86. anyone typing in such long command lines.  If they do, it probably showsì
  87. that they are not making proper use of aliases.
  88.  
  89.    I have decided to use only one of the spare ENV bytes for the XMCL sizeì
  90. and to let that value represent the size -- in paragraphs -- of the totalì
  91. MCL memory buffer allocated, including the five bytes used by the addressì
  92. pointer, size bytes, and terminating null.  The term 'paragraph' as a unitì
  93. of memory is not often used in the Z80 world.  I believe it was introducedì
  94. with the 8086 processor, where the segment registers represent addressesì
  95. that are shifted four bits right.  Each unit in the segment register is,ì
  96. therefore, 16 bytes and is called a paragraph.  With this system, the XMCLì
  97. buffer can be as large as 255 * 16 = 4080, which allows command lines withì
  98. up to 4075 characters.  Rich Charnes, do you think you can live with thatì
  99. without cramping your style too much?!
  100.  
  101.    Most people will not want to allocate that much memory to the operatingì
  102. system, and I would never have considered this step before the new dynamicì
  103. versions of Z-System were available.  While I might be willing to allocateì
  104. 1K to the XMCL most of the time, I certainly would want to be able toì
  105. reclaim that memory when I need it.  I'm not sure whether NZCOM or Z3PLUSì
  106. can be cajoled into handling this kind of flexibility yet; new versions mayì
  107. be needed at some time in the future.
  108.  
  109.    I put the new version of ARUNZ out for beta test, and it worked justì
  110. fine, and one could write very long alias scripts.  Rick Charnes, however,ì
  111. quickly identified a problem.  Suppose a conventional alias appeared in theì
  112. command sequence.  After expanding itself and constructing the new commandì
  113. line, the alias would find that, as far as it knew, there was not enoughì
  114. room for it in the MCL.  In a nutshell, the hard part with going to the XMCLì
  115. is that it is not enough to have an advanced ARUNZ; all programs thatì
  116. operate on the MCL must be upgraded.  We hope to have new versions of theì
  117. library routines in Z3LIB that perform these functions.  Then, if we areì
  118. lucky, most of the utility programs can be upgraded simply by relinking. ì
  119. I'm sure it won't be quite that easy, of course!
  120.  
  121.  
  122.                                 A MEX Alias
  123.  
  124.    For those who are not familiar with it, MEX (Modem EXecutive) is anì
  125. advanced telecommunications program written by Ron Fowler of NightOwlì
  126. Software.  Early versions were released for free to the public (up toì
  127. version 1.14), while the most advanced versions (called MEX-Plus) areì
  128. commercial products.  I use version 1.65, and some of the specifics in myì
  129. example apply to that version.  I am pretty sure that the technique Iì
  130. describe can be applied to the free version as well.
  131.  
  132.    Rather than being a telecommunications program, MEX should probably beì
  133. considered a telecommunications programming language.  It supports a veryì
  134. wide range of internal commands for managing telecommunications tasks, andì
  135. it even has a script language for automating complex sequences ofì
  136. operations.
  137.  
  138.    The MEX command line allows multiple commands to be entered just as in Z¡
  139. System, and a MEX command allows the user to define the command separator. ì
  140. Although I depend on aliases to generate complex Z-System commands and MEXì
  141. script files to automate complex MEX command sequences, I still frequentlyì
  142. make use of simple, manually entered multiple commands.
  143.  
  144.    Being accustomed as I am to entering Z-System commands separated byì
  145. semicolons, I naturally set up my version of MEX to use the semicolon as itsì
  146. separator, too.  Now I can comfortably work in both environments.  However,ì
  147. I also frequently like to invoke MEX with some initial commands, which MEXì
  148. allows one to include in the command tail.  Here's a simple example.
  149.  
  150.     B11:TEMP>mex read mnp on
  151.  
  152. This command invokes MEX and tells it to run the script file MNP.MEX withì
  153. the parameter "ON".  This script causes a string to be sent to my modemì
  154. which engages the MNP error correcting mode (yes, when I purchased my mostì
  155. recent modem -- replacing a USR Password -- I decided to spend the extraì
  156. money for MNP, although at the time there weren't many systems thatì
  157. supported it; now I'm glad I did).
  158.  
  159.    That command line works fine.  But often I want to do more, and so Iì
  160. always wanted to enter something like:
  161.  
  162.     B11:TEMP>mex read mnp on;call zitel
  163.  
  164. This would start out by doing what the first example did but would thenì
  165. continue by placing a call to the ZITEL BBS.  [If you can keep a secret,ì
  166. I'll tell you that the ZITEL BBS is the MS-DOS system that I run for theì
  167. ZI/TEL Group of the Boston Computer Society.  ZI/TEL comes from the lettersì
  168. in Zilog and Intel, and it symbolizes the fact that we support the two mainì
  169. operating systems run on chips from those companies: CP/M and MS-DOS.  Theì
  170. BBS machine, a Kaypro 286/16, is sitting in the other room (you don't thinkì
  171. I'd allow it in the same room with the Z-Node, do you?), and it has an HSTì
  172. 9600 bps modem with MNP error correction.  If you want to contact me there,ì
  173. by the way, the number is 617-965-7046.]
  174.  
  175.    An on-the-ball reader already realized that the above command will notì
  176. work, because the semicolon separator before the CALL command, which Iì
  177. intended as the MEX separator, will be interpreted by the CPR as itsì
  178. separator, and it will terminate the MEX command.  What can we do aboutì
  179. this?
  180.  
  181.    Some compromise here is inescapable, and I was willing to accept -- fromì
  182. the CPR command line only -- a MEX separator other than semicolon.  Thus theì
  183. following form would be acceptable
  184.  
  185.     B11:TEMP>mex read mnp on!call zitel
  186.  
  187. with an exclamation point as the separator as in CP/M-Plus.  But for years Iì
  188. could not figure out how to accomplish this.
  189.  
  190.    At first I thought there was a very simple solution.  When MEX starts up,ì
  191. it can be set up to automatically run an initialization script file INI.MEX. ì
  192. So, I created a version of MEX (the MEX "CLONE" command makes it easy toì
  193. create new versions) that used "!" as the separator, and I created anì
  194. INI.MEX file with the command
  195.  
  196.     STAT SEP ";"
  197.  
  198. Thus, as soon as MEX was running, the separator would be set back to aì
  199. semicolon.  Unfortunately, to my chagrin, I learned that MEX invokes theì
  200. INI.MEX script only when no commands are included on the command line.  Withì
  201. the ZITEL command line shown earlier, MEX would be left with the exclamationì
  202. point as the separator.
  203.  
  204.    Here is what I thought of next (at least momentarily).  Rename MEX.COM toì
  205. MEX!.COM and set up a MEX alias in ALIAS.CMD with the definition
  206.  
  207.     MEX    mex:mex! $*!stat sep ";"
  208.  
  209. The idea here is that the user's MEX commands from the command lineì
  210. (separated by "!") will be passed in by the $* parameter and will have theì
  211. STAT command added.  Thus our earlier example will turn into the commandì
  212. line
  213.  
  214.     B11:TEMP>mex:mex! read mnp on!call zitel!stat sep ";"
  215.  
  216.    This, of course, fails for the same reason that I could not just enterì
  217. commands with semicolons in the first place.  The trick to get around thisì
  218. is to use a command that for some reason Ron Fowler does not document in theì
  219. MEX manual: POKE.  It works like the Z-System command of the same name andì
  220. places a byte of data into a specified memory address.
  221.  
  222.    I knew the value I wanted to poke: 3BH, the hex value for the semicolonì
  223. character.  The question was, where should it go?  To find out, I took aì
  224. version of MEX set up with semicolon as the separator and the version withì
  225. exclamation point as the separator and ran the utility DIFF on them (inì
  226. verbose mode to show all the differences).  Then I looked for the placeì
  227. where the former has a semicolon and the latter an exclamation point.  Forì
  228. MEX-Plus this turned out to be 0D18H so that the MEX poke command would be
  229.  
  230.     POKE $0D18 $3B
  231.  
  232. Note that MEX uses a dollar sign to designate hex numbers.  The alias nowì
  233. read
  234.  
  235.     MEX    mex:mex! $*!poke $$0d18 $$3b
  236.  
  237. Observe that a double dollar sign is needed to get a single dollar signì
  238. character into a command.  A lot of people forget this and end up withì
  239. scripts that don't do what they're supposed to.
  240.  
  241.    I tested this, and it works splendidly -- but with one possible 'gotcha'. ì
  242. The commands passed to MEX must not invoke any script files that depend onì
  243. the command separator being a semicolon (because it will be exclamationì
  244. point until the final poke command runs); nor may the read files change theì
  245. command separator (because the rest of the command sequence still assumes itì
  246. is the exclamation point).  For this reason, it is prudent to write allì
  247. script files with only one command per line so that no separator is needed. ì
  248. I haven't been doing this, but I will from now on!
  249.  
  250.    One final word on the script.  I actually did not do this exactly as Iì
  251. have described.  Instead, I left my MEX.COM set up with the semicolonì
  252. separator, and I created a distinct ARUNZ alias called MEX! so that I wouldì
  253. be reminded of the separator.  This alias script reads
  254.  
  255.     MEX!    get 100 mex:mex.com;poke d18 "!;go $*!poke $$0d18 $$3b
  256.  
  257. This uses the famous poke&go technique originated by Bruce Morgen.  MEX.COMì
  258. is loaded into memory by the GET command, and then the Z-System POKE commandì
  259. sets "!" as the command separator.  Then the modified loaded code is run byì
  260. the GO command.  The rest is as described previously.
  261.  
  262.  
  263.                             A Spell-Check Alias
  264.  
  265.    I try to remember to put all my writing through The Word Plus spellingì
  266. checker that came with WordStar Release 4 so that as many typos as possibleì
  267. will be caught.  The procedure for doing that on a Z-System is a bitì
  268. complicated because the text file is generally not in the same user area asì
  269. the spelling check program.  While writing my last TCJ column, I finally gotì
  270. fed up with the complexity and automated the whole process using a set ofì
  271. aliases.
  272.  
  273.    I wanted to support the following syntax:
  274.  
  275.         C1:TCJ>spell filename.typ dictname
  276.  
  277. If just the file name was given, the alias would prompt for the name of theì
  278. special dictionary to use, and if not even a file name was given, then theì
  279. alias would prompt for both names.  A special version of the command,ì
  280. ZSPELL, would take only the file name and would automatically use ZSYSTEM asì
  281. the name of the special dictionary (it knows about mnemonics like ZCPR, MCL,ì
  282. and RCP, and about all those special words like debugger, relocatable, andì
  283. modem).  We'll describe the general alias set first.  In listing theì
  284. aliases, we will write them in multiline format for easy reading;in theì
  285. ALIAS.CMD file the scripts have to be on a single line (though I hope thatì
  286. will change soon).
  287.  
  288.    The user-interface alias, SPELL, deals only with the matter of how manyì
  289. parameters the user has provided.  It reads as follows:
  290.  
  291.     SPELL
  292.         if nu $1;
  293.           /TW0;
  294.         else;
  295.           if nu $2;
  296.             /TW1 $1;
  297.           else;
  298.             /TW2 $1 $2;
  299.           fi;
  300.         fi
  301.  
  302. If no parameters at all are provided (IF NULL $1), then the secondary scriptì
  303. TW0 is run.  The leading slash signals ZCPR34 that the command should beì
  304. directed immediately to the extended command processor.  If a firstì
  305. parameter but no second parameter is present (IF NULL $2), then theì
  306. secondary script TW1 is run.  Finally, if both parameter are provided, thenì
  307. script TW2 is run.
  308.  
  309.    The script TW1 includes a prompt only for the name of the specialì
  310. dictionary file:
  311.  
  312.     TW1
  313.         $"Name of special dictionary: "
  314.         /TW2 $1 $'e1
  315.  
  316. The first token in any user response to the first prompt ($'E1 -- whenì
  317. working with ARUNZ you should have a printout of the parameter DOC file) isì
  318. used along with the file name that was already given, and both are passed toì
  319. TW2.
  320.  
  321.    The script TW0 includes prompts for both the file name and the specialì
  322. dictionary:
  323.  
  324.     TW0
  325.         $"Name of file to check: "
  326.         $"Name of special dictionary: "
  327.         if ~nu $'e1
  328.           /TW2 $'e1 $'e2
  329.         fi
  330.  
  331. The first tokens in the responses to the prompts are passed to script TW2. ì
  332. If no file is specified for checking, the alias simply terminates.
  333.  
  334.    Before we look at TW2, which does the real work, let me ask a rhetoricalì
  335. question: why do we break this process up into so many separate aliases. ì
  336. 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. ì
  337. The extended MCL we discussed earlier could overcome this problem, but forì
  338. another reason we would still have to use separate aliases.
  339.  
  340.    As I have discussed in past columns, ARUNZ cannot know at the time itì
  341. expands a script what the results of conditional tests will be later whenì
  342. the IF commands are run.  Thus ARUNZ must process all user input promptsì
  343. that appear in the script.  This would mean asking for a file name andì
  344. special dictionary even when the names were given on the command line.  Theì
  345. solution to this problem is to put the prompts in separate scripts that getì
  346. invoked only when the information requested in those prompts is actuallyì
  347. needed.
  348.  
  349.    Now let's look at the script TW2.
  350.  
  351.     TW2
  352.         path /d=tw:;
  353.         $td1$tu1:;
  354.         tw:tw $tf1 $tn2.cmp;
  355.         path /d=;
  356.         /twend $tn2;
  357.         $hb:
  358.  
  359. This is simpler than what you expected, no?  Well, there is still a lot ofì
  360. work imbedded in the subroutine script TWEND, which we will cover later. ì
  361. Here we broke up the script solely to prevent MCL overflow.
  362.  
  363.    The first command makes use of the ZSDOS file search path (see theì
  364. articles by Hal Bower and Cam Cotrill on ZSDOS in TCJ issues 37 and 38). ì
  365. Although there was an attempt to update WordStar Release 4 to include someì
  366. Z-System support, no such attempt was made with The Word Plus spell checker. ì
  367. In general, the file to be spell-checked will be in one directory and Theì
  368. Word files in another directory.  The main program TW.COM could be locatedì
  369. by the command processor using its search path, but TW.COM needs a number ofì
  370. auxiliary files, such as the dictionary files.  How can the system be madeì
  371. to find all of these files at the same time.  ZSDOS provides the answer.
  372.  
  373.    I have replaced the standard Z-System PATH command with the ZSDOS utilityì
  374. ZPATH (renamed to PATH).  The first command in TW2 defines the DOS searchì
  375. path to include the directory TW:, which is where I keep all the files thatì
  376. are part of The Word Plus spell-checking package.  Once that directory is onì
  377. the DOS path, all files in it will more-or-less appear to be in the currentì
  378. directory.  Very handy!  If you use ZDDOS, the search path is not available. ì
  379. I will not show it here, but you can accomplish the same thing using onlyì
  380. public files.  It's just not quite as neat and straightforward.  I amì
  381. willing to pay the small memory penalty to get the nice extra features ofì
  382. ZSDOS over ZDDOS.
  383.  
  384.    The second command logs us into the directory where the file to beì
  385. checked resides.  If we did not include a DIR: prefix, we were alreadyì
  386. there, but the extra command does not hurt, and it is nice to know that aì
  387. directory can be specified explicitly (in either DU: or DIR: form) for theì
  388. file to be checked.  There could be a problem if the file is in a user areaì
  389. above 15, since you may not be able to log into that area.  My configurationì
  390. of Z34 allows this, but when I run BGii I lose this feature (and I sure missì
  391. it).  If you can't log into those areas, then you should not keep filesì
  392. there that you want to spell-check.
  393.  
  394.    The third line actually runs the spell checker (you knew that had toì
  395. happen some time!).  Notice that even if the user specified a file type forì
  396. the special dictionary, type CMP is used.  Only the name ($TN2) without theì
  397. type is taken from the user.  As the master program TW.COM is run, it willì
  398. find its component program files (e.g., SPELL.COM, LOOKUP.COM, MARKFIX.COM)ì
  399. and the various dictionaries in the TW: directory thanks to ZSDOS, and itì
  400. will find the text file in the current directory.  As it works through theì
  401. text, if there are any questionable words, it will write out a fileì
  402. ERRWORDS.TXT to the current directory.  If any words are added to theì
  403. special or UPDATE dictionaries, then the modified dictionaries will be readì
  404. from TW: but written out to the current directory.  You must understandì
  405. these facts in order to understand the rest of the script.
  406.  
  407.    Once the spell-checking is complete, the ZSDOS path is set back to nullì
  408. (unless I have a special need to have the DOS perform a search, I leave itì
  409. this way to avoid surprises).  Then the ending script TWEND is run, andì
  410. finally the original directory ($HB:) is restored as the current directory.
  411.  
  412.    Now let's look at TWEND.  As it is invoked, the name of the specialì
  413. dictionary is passed to it.  TWEND's job is to clean up scratch files and toì
  414. take care of any updated dictionaries.  It reads
  415.  
  416.     TWEND
  417.         if ex errwords.txt;
  418.           era errwords.txt;
  419.         fi;
  420.         /dupd $1;
  421.         /dupd updict
  422.  
  423. For efficiency and to prevent MCL overflow, the dictionary updating isì
  424. performed by yet another subroutine script, DUPD.  It gets called twice,ì
  425. once with the special dictionary (if any) and once with the updateì
  426. dictionary.  It reads as follows:
  427.  
  428.     DUPD
  429.         if ex $tn1.cmp;
  430.           mcopy tw:=$tn1.cmp /ex;
  431.         fi
  432.  
  433. If an updated version of the specified dictionary exists in the currentì
  434. directory, then it is copied to the TW: directory, overwriting any existingì
  435. file of that name (MCOPY option E).  The source file is then erased (MCOPYì
  436. option X).  Oh yes, I almost forgot; the MCOPY here is my renamed version ofì
  437. the COPY program supplied with ZSDOS.
  438.  
  439.    That is it except for showing you the special ZSPELL version of theì
  440. alias.  Notice that I make the "ELL" part of the command optional byì
  441. inserting the comma in front of that part of the alias name.  I also allowì
  442. the script to be invoked under the name ZTW.  The main SPELL script actuallyì
  443. has the name "TW=SP,ELL" on my system.  Since TW: is not on my commandì
  444. search path, the command "TW" will invoke the ARUNZ script unless I am inì
  445. the TW: directory at the time.
  446.  
  447.     ZTW=ZSP,ELL
  448.         if nu $1;
  449.           /ZTW1;
  450.         else;
  451.           /TW2 $1 zsystem.cmp;
  452.         fi
  453.  
  454.     ZTW1
  455.         $"Name fo file to check: "
  456.         if ~nu $'e1
  457.           /TW2 $'e1 zsystem.cmp
  458.         fi
  459.  
  460. I hope you find these alias examples useful and instructive.  That's all forì
  461. this time.  See you again in two months.
  462.