home *** CD-ROM | disk | FTP | other *** search
/ ftp.barnyard.co.uk / 2015.02.ftp.barnyard.co.uk.tar / ftp.barnyard.co.uk / cpm / walnut-creek-CDROM / CPM / ZCPR33 / TCJ / TCJ35.MZG / TCJ35.MAG
Text File  |  2000-06-30  |  28KB  |  526 lines

  1.      My column about shells and WordStar Release 4 (WS4) in TCJ issue #33
  2. prompted more than the usual level of commentary.  There were extensive
  3. discussions on Z-Node-Central and the Lillipute Z-Node (the official TCJ
  4. bulletin board), and several messages reached me over the ARPA network.  Not
  5. all of the comments were favorable, but I was nevertheless happy to receive
  6. them.  They helped further clarify my thinking on the very important subject
  7. of shells and have spurred me on to prove my points by actually converting
  8. WS4 to a ZCPR2-style shell!  After a bit of follow-up discussion, I will
  9. describe how this conversion was accomplished.
  10.  
  11.  
  12.                 Corrections
  13.  
  14.      There were some things I said in the previous column that were
  15. factually wrong, and before I do anything else I wish to correct them.
  16.  
  17.      First, I stated that the Z-System code in WS4 was written by someone
  18. other than MicroPro.  I was wrong.  David McCord, who was vice president at
  19. Echelon at the time WS4 was developed, sent me a message with the facts of
  20. this matter.  Echelon, through staff like David and through published
  21. materials, educated Peter Mireau of MicroPro on the facilities and
  22. philosophy of Z-System.  Peter did all the actual programming, so the coding
  23. mistakes were his fault, not Echelon's or David's.
  24.  
  25.      From a broader perspective, however, as I stated in the previous
  26. column, the real culprit was inadequate testing.  Bugs in the code would
  27. have been discovered and conceptual issues clarified had more people in the
  28. Z community been involved as beta testers.  There are so many different
  29. styles of using Z-System that it takes a number of testers to uncover
  30. problems.  Within days after copies of WS4 were delivered to users of my Z-
  31. Node, I started getting questions about strange behavior exhibited by WS4,
  32. behavior that turned out to result from its operation as a shell.
  33.  
  34.      A second mistake in the earlier column was my implication that WS4 does
  35. not get its own name from the ZCPR3 external file control block (XFCB).  I
  36. no longer remember what made me think that this was the case, but David
  37. McCord assured me (and I have now verified for myself) that WS4 does,
  38. indeed, get its name from the XFCB when it sets up the shell stack entry.
  39.  
  40.      Finally, one reader reported to me that my WSSHLOFF routine (the one
  41. that completely disables shells while WS4 is running and reenables them when
  42. WS4 terminated) crashed his system.  Unfortunately, a large number of
  43. misprints crept into the listings in going from my disk file to the printed
  44. pages.    Most of the typos were obvious, but one was compounded by a double
  45. error.    In the WSSHLOFF listing, the value for EXITSUB was printed as 03BVh.
  46. The 'V' was obviously a mistake, and clever readers looked at the similar
  47. listing for WSSHLFIX, where the value was given as 03B3h.  This,
  48. regrettably, looks correct but was also a typo.  The proper value is 03BEh.
  49. We hope that Art Carlson will make sure that the listings in this column are
  50. transcribed accurately (so that all the mistakes will be mine!).
  51.  
  52.  
  53.                  More WS4 Comments
  54.  
  55.      While on the subject of WS4, I would like to add a few further comments
  56. about how it works.  Not surprisingly (considering when it was developed),
  57. in creating its shell stack entry WS4 does not make use of the facility
  58. introduced with ZCPR version 3.3 that allows a program to determine from the
  59. XFCB not only its name but also the directory from which it was actually
  60. loaded (the user number is at offset 13 and the drive, with A=1, at offset
  61. 14).
  62.  
  63.      As a result, in order for WS4 to be reinvoked as a shell, the command
  64. search path must include the directory in which WS4 is located.  I mention
  65. this here as a reminder and suggestion to authors of new or updated shells
  66. and error handlers that they use this Z33 facility to avoid the requirement
  67. that the program be on the path and to speed up loading of the program (by
  68. eliminating any search for it).  My WordStar conversion described later adds
  69. this feature.
  70.  
  71.      With WS4 it is generally necessary that the command search path include
  72. WS4's directory for an additional reason.  I learned the hard way that when
  73. WS4 runs under Z-System, it pays no attention to the drive and user number
  74. that WSCHANGE specified as the location for the overlay files; it only uses
  75. the search path to try to locate them.
  76.  
  77.      This is a problem for me because, as I have explained at length in
  78. previous columns, I put only my small RAM disk on the path and use ARUNZ
  79. aliases to invoke all programs except the very few that fit on the RAM disk.
  80. With this approach, there is no way to get WS4 to find its overlay files.
  81. The conversion addresses this problem also.
  82.  
  83.  
  84.                ZCPR2 vs. ZCPR3 Shells
  85.  
  86.      I would not like to take up again one of the subjects raised in issue
  87. #33: ZCPR2-style versus ZCPR3-style shells.
  88.  
  89.      First an aside.  Shells seem to be a surprisingly emotional issue.  I
  90. thought my earlier column presented a fairly carefully and calmly reasoned
  91. discussion of some aspects of shells, including their pros and their cons.
  92. Some readers, however, took great offense at my even questioning the current
  93. method of implementing shells or of what some people are trying to do with
  94. them.
  95.  
  96.      One reader went so far as to suggest that I had no business commenting
  97. on the subject when, by my own admission, there are a number of shells that
  98. I have never used.  Besides the fact that this is hardly a reasoned
  99. argument, I would like to make sure that the following facts about shells
  100. are fully appreciated.
  101.  
  102.      ZCPR3-style shells are a facility of the command processor.  Without
  103. special code in the CPR, there would be no such shells.  As the author of
  104. the two latest versions of the ZCPR command processor, I think I can speak
  105. with some authority (though certainly not with infallibility) on the
  106. subject, since in writing that code I had to consider the issue of shells
  107. rather carefully from a rigorous theoretical viewpoint.
  108.  
  109.      ZCPR2-style shells, quite the contrary, are not a facility of the
  110. command processor; they are a facility of the individual shell programs.
  111. Their functioning depends only on the operation of the multiple command line
  112. facility.  The command processor does not treat a Z2 shell command any
  113. differently than it treats any other command.  This is really the key to the
  114. difference between the two shell implementations.
  115.  
  116.      In the previous column I stated: "...I am coming to the conclusion that
  117. only programs like history shells...should be implemented as ZCPR3-style
  118. shells.  Other programs, like ZFILER and WordStar should use the ZCPR2
  119. style."  I then invited readers to enlighten me if I was missing some
  120. important point.  I got some responses to this invitation, but no one yet
  121. has offered me any evidence that I had missed any important point.
  122.  
  123.      One reader reiterated essentially the same difference between Z2 and Z3
  124. shells that I attempted to demonstrate with my example in which WordStar was
  125. invoked in a multiple command line.  Apparently the point bears repeating.
  126.  
  127.      This reader presented the point using a command line like the
  128. following:
  129.  
  130.         ZFILER;ECHO TESTING
  131.  
  132. Under ZCPR2, ZFILER would run and present its file display to the user.  If
  133. the user generated a command line "CMDLINE" as the result of a macro or in
  134. response to the prompt after the 'Z' command, a Z2-shell version of ZFILER
  135. would build the command sequence "CMDLINE;ZFILER" and insert it into the
  136. multiple command line buffer just before the next command to be executed.
  137. This would give:
  138.  
  139.         CMDLINE;ZFILER;ECHO TESTING
  140.  
  141. The user's command line would run, and then ZFILER would be invoked again.
  142. Only on termination of ZFILER would the last command, "ECHO TESTING", be
  143. performed.
  144.  
  145.      A Z3 shell would respond to the same command line from the user in
  146. quite a different way.    As before, ZFILER would be invoked first.  It would
  147. determine from the Z3 message buffer that it had been invoked manually and
  148. would respond by pushing its own name onto the shell stack.  Then it would
  149. terminate.  The command processor would then proceed to run "ECHO TESTING".
  150. Only after that, once the command line was empty, would ZFILER be reloaded,
  151. this time as a shell.  Recognizing its shell status, it would now display
  152. its screen of file names and do its real work.
  153.  
  154.      The reader who submitted this example, if I understood him correctly,
  155. viewed the Z3 behavior as correct and the Z2 behavior as wrong.  If you are
  156. an experienced Z-System user, you will probably recognize in this reader a
  157. fellow expert (and, indeed, he is).  He is so used to ZCPR3 that he no
  158. longer notices that it is the behavior of the Z3 shell that is truly
  159. bizarre!
  160.  
  161.      Consider the following two command lines:
  162.  
  163.     (1) ZFILER;ECHO TESTING
  164.     (2) ECHO TESTING;ZFILER
  165.  
  166. We have already analyzed the first one; the second one can safely be left as
  167. an exercise for the reader.  We will simply state the answer that under
  168. ZCPR3 they will accomplish exactly the same thing!  This is hardly a result
  169. that conforms to intuition, and I still remember in my early days as a Z-
  170. Node sysop trying to explain to quite a few users why the second command on
  171. a VFILER command line executes first!
  172.  
  173.      Under ZCPR2 the result is just what one would expect.  In the first
  174. case, ZFILER runs first, and ECHO runs only after the user terminates ZFILER
  175. using its 'X' command.    In the second case, ECHO runs first and ZFILER
  176. second.  In other words, with Z2 shells, commands are executed in the order
  177. they are entered, a notion that does not require long experience and great
  178. expertise to understand and get used to!  And it gives the user a greater
  179. measure of control.
  180.  
  181.  
  182.                Mixed Z2 and Z3 Shells
  183.  
  184.      The same reader submitted another interesting example that illustrates
  185. the confusing behavior that can arise when Z2 and Z3 shells are mixed.    Here
  186. we assume that WordStar has been implemented as a Z2 shell and ZFILER as a
  187. Z3 shell.  Suppose we use the 'R' command of WordStar to enter the command
  188. "ZFILER".  WS4, as a Z2 shell, would generate the command line
  189.  
  190.         ZFILER;WS
  191.  
  192. ZFILER, as a Z3 shell, would install itself on the shell stack and proceed
  193. to execute "WS".  ZFILER would not run in its file maintenance mode until
  194. after we terminated WordStar.
  195.  
  196.      This is, admittedly, probably not what one intended, since we most
  197. likely entered the ZFILER command with the intention of doing some file
  198. maintenance before returning to WordStar.  On the other hand, it is
  199. certainly no more bizarre than what we saw in our earlier example.
  200.  
  201.      If both WS4 and ZFILER were Z3 shells, then the invocation of ZFILER
  202. from the WS4 'R' command would cause it to become the active shell (the one
  203. on the top of the shell stack).  The WS4 shell would be pushed down in the
  204. shell stack, and ZFILER would take control.  With a little thought, however,
  205. you will see that the same is also true if both ZFILER and WS4 are Z2
  206. shells!
  207.  
  208.      The strange behavior with the mixed shells in the above example arises
  209. in part because ZFILER was not really being used as a shell in the Z3 sense,
  210. namely, as a replacement for the command processor's command-line input
  211. routine.  It was intended as a file maintenance utility.
  212.  
  213.      Suppose we had entered the command "EASE" (the Z3-type history shell)
  214. instead of "ZFILER" from our Z2 version of WordStar.  This would establish
  215. EASE as the current shell and return to WordStar.  That behavior would not
  216. seem strange, because in this case we would be thinking of our EASE command
  217. as establishing the shell to be used in place of the command processor the
  218. next time the command processor needed a new command line.  So long as
  219. WordStar is running, there is no need for EASE to do anything.    We expect it
  220. to take effect only after we are finished using WordStar.
  221.  
  222.  
  223.            Nested Z2 Shells and Recursive Aliases
  224.  
  225.      Although I had once thought that the Z3 shell stack was required in
  226. order to nest shells, I showed in the earlier column that this is not the
  227. case. Z2-style shells can, in fact, be nested more flexibly.  There is no
  228. predetermined limit to the nesting depth or to the amount of information
  229. that can be passed with each shell command line.  The only limit is imposed
  230. by the length of the multiple command line buffer, just as with the nesting
  231. of aliases.
  232.  
  233.      With the standard shell stack configuration of 4 32-byte entries, if a
  234. shell command uses only 16 bytes, 16 bytes are wasted.    On the other hand,
  235. if a shell command needs 48 bytes to hold its information, it cannot run at
  236. all under this configuration (NZ-COM can come to the rescue by allowing the
  237. shell stack configuration to be changed on the fly).  With Z2 shells, these
  238. problems go away.  In 64 bytes of command line, one can have two 32-byte
  239. shell commands or a combination of one 16-byte shell command and one 48-byte
  240. shell command (or five 12-byte shell commands).
  241.  
  242.      I did overlook one point when I described putting data for the shells
  243. on the command line.  In the Z3 shell stack, one can include, after the
  244. shell command's terminating null, any binary data that one wishes.  Thus 256
  245. values are possible for each extra byte in the shell stack entry.
  246.  
  247.      In order to carry shell data on the command line, several additional
  248. constraints apply.  First, the command processor strips the high bits off
  249. all characters in the command line, so only 128 values are available to
  250. start with.  Secondly, the null character cannot be used because the command
  251. processor would interpret this as the end of the command line (that leaves
  252. 127 values).  Finally, letters are converted to upper case, thereby making
  253. the characters from 'a' to 'z' inaccessible (scratch another 26).  This
  254. leaves only 101 possible values out of the original 256.  Moreover, extra
  255. characters are required as flags to signal the program to consider itself as
  256. having been invoked as a shell (a service provided in ZCPR3 by a flag in the
  257. message buffer).  All of these things reduce the efficiency with which the
  258. space in the command line buffer can be used compared to the space in the
  259. shell stack.
  260.  
  261.      One reader pointed out that recursive aliases cannot be used with
  262. Z2-type shells.  This is true...but only if one is using the pseudo-
  263. recursive alias that I invented.  This kind of alias accomplishes a crude
  264. approximation to recursion by discarding any pending commands in the command
  265. line buffer.  This will, indeed, discard any shell reinvocation commands.
  266. However, if one uses the logically sound and rigorous recursive alias
  267. technique invented by Dreas Nielsen (see my column in issue #28), there is
  268. no problem.  It sometimes pays to do things right!
  269.  
  270.      In fact, it seems to me that the Z2 shell is, in essence, a recursive
  271. alias, a program that keeps invoking itself.  And this is just what most (if
  272. not all) Z3 shells actually do.  I am still awaiting an example of something
  273. (good) that a Z3 shell can do that cannot be done in some equivalent way
  274. with a Z2 shell or recursive alias.
  275.  
  276.  
  277.             The Real Difference Between
  278.                   Z2 and Z3 Shells
  279.  
  280.      After much reflection, I think I have finally put my finger on the
  281. fundamental distinction between Z2 and Z3 shells.  It derives from the facts
  282. I alluded to earlier: that the Z3 shell is a true creature of the command
  283. processor and the Z2 shell is not.
  284.  
  285.      Here is an example that will illustrate the point.  Suppose the history
  286. shell EASE were implemented as a Z2-style shell and that while it is
  287. running, we issue the command "DIR".  EASE will insert into the command line
  288. a sequence like the following:
  289.  
  290.         DIR;EASE
  291.  
  292. DIR will run, and then EASE will be reinvoked.    Looks fine!  But now suppose
  293. the user enters the command "IF EXIST FN.FT".  EASE will then generate the
  294. command line
  295.  
  296.         IF EXIST FN.FT;EASE
  297.  
  298. If the file FN.FT exists, this will again work just fine, but suppose the
  299. file does not exist.  Then the system will enter a false flow state, and the
  300. EASE command (and perhaps other commands pending in the command line after
  301. it) will be flushed by the command processor.  The shell function will be
  302. lost, and any other pending commands will be processed in an unintended way.
  303.  
  304.      For a Z2 shell to function properly in general, all command lines
  305. inserted by it must result in the same flow state at the end of the command
  306. line as at the beginning.  With a MENU shell it could be possible for the
  307. system designer to guarantee this, since he can control which commands are
  308. generated by the shell.  With a history type shell it would be nearly
  309. impossible to ensure that this condition would always be met.
  310.  
  311.      The critical feature of shell processing under ZCPR3 is that flow
  312. processing is suspended during the operation of shells.  This allows them to
  313. run, as they must, even after the user has passed a command that leaves the
  314. system in a false flow state.  The ZCPR33 Users Guide goes into some detail
  315. on this matter, and had I remembered better what I wrote there, it would not
  316. have taken me this long to come to the essence of the Z2-vs.-Z3 shell issue.
  317.  
  318.      Some users of ZCPR33 have modified the way the command processor deals
  319. with flow control in shell processing.    No one has yet convinced me of the
  320. value of this (the risks are undeniable).  It still seems to me that Z2-type
  321. shells and recursive aliases can accomplish the same thing, but in a
  322. logically sound way.
  323.  
  324.      I have extended an invitation to Dreas Nielsen to write a series of
  325. columns for TCJ explaining his very powerful shell programs.  Since he is
  326. also one of the people who has made this modification to the CPR, perhaps he
  327. will also present the other side of this story and explain why it is
  328. necessary or desirable to treat shells the way he does.
  329.  
  330.  
  331.             Remaking WordStar Release 4
  332.  
  333.      When I first received my copy of WordStar 4 and encountered problems
  334. with the way it handled shells, I fired up the DSD debugger and tried to
  335. figure out how to fix it.  After a considerable amount of rummaging about in
  336. the code (and especially trying to figure out what was going on inside
  337. WS.OVR), I gave up.  Later I tried again...and failed again.  In the course
  338. of preparing this column, I decided to have one more go at it, and this time
  339. things started to click.
  340.  
  341.      The patches I will describe here are preliminary and have not yet been
  342. extensively tested.  In fact, as I write this, I am the only one who has
  343. used them, and you know what I said above about the dangers of a test
  344. program that does not involve a variety of Z-System users.  So, you are
  345. hereby recruited, if you are willing, to join the test program.
  346.  
  347.      Since I may very well have made some mistakes, and since there are
  348. further changes that people may want to make (let's hear your suggestions),
  349. I will not only give the results; I will describe the process by which these
  350. patches have been developed.
  351.  
  352.  
  353.                  Cracking the Code
  354.  
  355.      The first step toward changing the code was figuring out how the virgin
  356. WordStar was doing what it did.  In particular, I wanted to locate routines
  357. related to Z-System functions, so the first thing I tried was searching for
  358. all references to address 109h, which contains the address of the Z-System
  359. environment (ENV).  Any WS4 feature that made use of a Z-System facility
  360. would have to get information from the ENV.
  361.  
  362.      As best I recall, this did not turn up many references and did not
  363. particularly help (though it was a good idea, and that's why I mention it).
  364. In the end, I just started tracing the code from the beginning, figuring
  365. that WS4 would have to determine fairly early whether it was running under
  366. Z-System or standard CP/M.  This turned out to be correct, and very soon I
  367. came to the key Z routine, at address 0AA4h in WS.COM.    This routine returns
  368. the address and size of a Z-System module specified by an offset passed in
  369. the E register.
  370.  
  371.      Having discovered this routine, I used DSD to find all references to it
  372. in WS.COM and WS.OVR.  They occur with the following values of E:
  373.  
  374.     E =  9h     the command search path (PATH)
  375.     E = 15h     the named directory register (NDR)
  376.     E = 18h     the multiple command line buffer (MCL)
  377.     E = 1Eh     the shell stack (SHL)
  378.     E = 22h     the message buffer (MSG)
  379.     E = 24h     the external file control block (XFCB)
  380.  
  381.  
  382.              Setting up the Shell Stack
  383.  
  384.      The block of code beginning around address 3CBFh in WS.OVR makes
  385. references to MCL, XFCB, and SHL.  I guessed correctly that this had to be
  386. the code where WS4 sets up its shell stack entry.  (This block of code, by
  387. the way, is where the shell-pushing mistake occurs for the case where the
  388. shell stack is currently empty.)
  389.  
  390.      The patch for this part of WS.OVR (see Listing 1) modifies this code.
  391. First of all, since WS4 is going to operate as a Z2-type shell, we do not
  392. want it to do anything with the shell stack.  It is easy to disable the code
  393. by simply skipping over it, but one has to watch out for subtleties.
  394. Indeed, in order for the 'R' command to use the MCL and not chain using the
  395. greatly inferior CP/M method, WS4 has to think that the shell entry was
  396. established successfully.
  397.  
  398.      I noticed that a flag was being set into address 2200h, and I surmised
  399. that it is used by WS4 to show that it is running under Z-System.  In the
  400. patch, I set this flag even though the shell stack entry is not being set
  401. up.  I have not examined all references to this flag, and there is a chance
  402. that there are additional, more complex effects.  If any problems appear
  403. with the patched version of WordStar, this flag might be involved.  For the
  404. initial attempt at fixing WS4, I just took the easiest course of action, and
  405. so far it appears to have worked.
  406.  
  407.      It seemed foolish to waste space in WS.OVR by doing nothing more than
  408. setting the flag and jumping to where the original code resumed (60AAh).
  409. Instead, I have used the space to compute the command line necessary to
  410. reinvoke WordStar.  The code gets not only the name by which WordStar was
  411. invoked but also the drive and user number from which it was loaded.  A
  412. command line of the form ";DUU:WSNAME" is generated.
  413.  
  414.      There is one extra step in this part of the patch.  When running as a
  415. Z3 shell, WS4 knows from the command status flag in the message buffer when
  416. it was invoked as a shell so it can put up the press-any-key message before
  417. clearing the screen and resuming operation.  As a Z2 shell, WS4 cannot use
  418. this facility.    Instead, a signal has to be included in the command tail.
  419. For reasons that I will not go into in full detail, I chose for this signal
  420. a comma at the very end of the tail.  Very briefly, the comma is a handy
  421. character because it is not parsed into the default file control blocks,
  422. where a program could confuse it with a file name.
  423.  
  424.      The final reinvocation command line, with its terminating null, takes
  425. the form
  426.  
  427.         ;DUU:WSNAME ,<0>
  428.  
  429. Since I could not be sure that this section of overlay code would persist in
  430. memory until the command would be used, I store it at the top of the WS4's
  431. user patch area (MORPAT).
  432.  
  433.  
  434.          The Initialization and Termination Patches
  435.  
  436.      Having made the above modification, we must make two others in order to
  437. remain consistent.  First, we must modify the WS4 initialization code in
  438. which it determines whether or not it was invoked as a shell.  This is the
  439. patch at address 1A2Fh in WS.COM.  The patch calculates the address of the
  440. last character passed in the command tail and checks to see if it was a
  441. comma.    If not, it proceeds with normal operation of the program.
  442.  
  443.      If there is a comma, the shell-wait message must be displayed until the
  444. user presses a key.  But one must also remove the comma from the command
  445. tail to ensure that WordStar not think it has been passed a file name.    At
  446. present I do this by replacing the comma with a space.    This is not
  447. rigorous, but it seems to work, since WS4 is apparently not confused by a
  448. tail consisting only of spaces (unfortunately, a number of programs are).
  449.  
  450.      Since WS4 no longer pushes its name onto the shell stack, we must also
  451. prevent it from popping the shell stack when it terminates.  This is the
  452. patch at address 13CEh in WS.COM.  This is the easiest patch of all, since
  453. we simply have to skip some code.  As an additional benefit, this frees up
  454. about 40 bytes of space that we use for some of our other patch code.
  455.  
  456.  
  457.                Fixing the 'R' Command
  458.  
  459.      Now we come to the main item in this set of patches -- the code that
  460. makes the 'R' command work as a ZCPR2-type shell.  The new code here is much
  461. more complex than what it replaces, and we can only fit part of it at the
  462. original location 67B2h in WS.OVR.  We put what we can there and continue
  463. with the rest in the MORPAT area in WS.COM.
  464.  
  465.      The basic strategy is to take the command line entered by the user in
  466. response to the 'R' command prompt, append the WS reinvocation command
  467. (including its semicolon separator), and append any remaining command line
  468. pending in the multiple command line buffer (if there is one, it will begin
  469. with a semicolon also).  If there is enough room for the result in the MCL,
  470. then it is moved there and chained to.    If not, a warning message is
  471. displayed on the screen until a key is pressed, and the user command is
  472. ignored.
  473.  
  474.      To implement this strategy, I chose the simplest method I could think
  475. of.  Since the 'R' command operates from the WordStar no-file menu, the
  476. entire WS edit buffer is available as a scratch area.  I picked an arbitrary
  477. address of A000h for a buffer in which to build the new command line.
  478. Again, rigorous code calculate the address.  My code is a quick-and-dirty
  479. solution.
  480.  
  481.  
  482.              Finding the Overlay Files
  483.  
  484.      As I noted earlier, with my style of operation, WS4 had trouble finding
  485. its overlays.  To solve that problem, the patch includes an optional section
  486. to install an internal search path for the overlay files.  This patch is
  487. installed at address 0F5Fh in WS.COM, where it replaces a call for the
  488. location of the Z-System path with a call to a routine that returns the
  489. address and size of an internal path.  In Listing 1 the internal path has
  490. the single element B4:, the directory in which I keep my WordStar program
  491. files.    You can put any values you want here.
  492.  
  493.  
  494.                Installing the Patches
  495.  
  496.      It is not possible to install the patches in WS.OVR using MLOAD or a
  497. debugger, because the OVR file is too large to load entirely into memory.
  498. ZPATCH, on the other hand, can handle the job splendidly.  ZPATCH assumes an
  499. offset of 0000 for a file of type OVR, while the addresses in the listing
  500. are those shown when the file (as much as can fit) is read into memory under
  501. a debugger.  To make things consistent, you should use the ZPATCH 'O'
  502. command to set the offset to 100.
  503.  
  504.      Key in the new data carefully, checking from time to time that the
  505. address is still correct.  Also, be careful not to go beyond a record
  506. boundary while in ZPATCH.  It wraps from the end of the record back to the
  507. beginning of that record without warning (this really gave me grief until I
  508. caught on to the problem).  When you get to the end of the current record,
  509. write it out (^W), advance to the next record (>), and reenter edit mode
  510. (E).  Then you can resume entering data.
  511.  
  512.      The attached listing was made with a specially configured version of
  513. the SLR Z80ASM assembler.  Normally, I have it display addresses in logical
  514. order for easier interpretation.  For hand keying of a patch, however, it is
  515. far more convenient to have the bytes of a word in physical order.  Just
  516. watch out when reading the displayed symbol values.  They, too, are stored
  517. in byte-reversed format.
  518.  
  519.      It is possible to use MLOAD to install just the patches for WS.COM.
  520. Simply delete the parts of WSPAT.Z80 that refer to patches in WS.OVR and
  521. assemble the remaining code to a HEX file.
  522.  
  523.      Enjoy playing with (and using) this different (improved) version of
  524. WordStar 4, and let me know what you think and what further suggestions you
  525. have.
  526.