ŽFC¯ŽLM2¯ŽRM78¯ŽMDBO¯ŽVA$FI--CRASH.TXT (CLD)¯--Using the "SUbroutine Crash" Technique (1) to Test for Initialization of a Save/Get in XyWrite III+ *Without* Generating a Forced Error and (2) to Determine Whether an XPL/SPL Program is Running under XyWrite or Signature Carl L. Distefano 5/22/92 (rev. 7/11/92) ŽFC¯(Read in E-XP-anded Display Mode)ŽMDNM¯ ŽFL¯ ŽLD-¯ Preface: You can easily run the routines included in this or any other file with the following RUNCODE routine (versions for XyWrite and Signature). Save the appropriate routine to a file, and LDPM the file to a save/get, e.g., LDPM RUNCODE.PM,R. Then, DeFine the code you want to run, and execute (in the example) func @R (usually mapped to Alt-R). With *nothing* DeFined, the same routine will RUN the file displayed in the current window. If a directory is displayed, it works as a point-and-shoot RUN command. Very handy! XyWrite: ŽLB RUNCODE.XPM--A versatile routine for RUNning XPL CODE (XyIII+ v3.53+)--C.L.Distefano rev. 7/11/92¯ŽSX90,ŽVA$WS¯¯ŽIFŽPV90¯<1¯ŽPRNo file¯ŽEX¯ŽEI¯ŽIFŽPV90¯>1¯˙run˙€}˙ ŽEX¯ŽEI¯ŽSX90,ŽVA$DS¯¯ŽSX91,ŽVA$DN¯¯ŽIFŽPV90¯==ŽPV91¯¯ŽSX92,ŽVA$FP¯¯˙run ŽPV91¯˙ ŽEX¯ ŽEI¯ŽSV90,ŽEX¯˙Ŗ¯˙A˙es 1˙ ˙€k˙es 0˙ ˙˙€}˙?˙;ŽSV298¯˙=ŽSX298,ŽIS298¯+ŽIS90¯¯ŽPV298¯ŽEX¯ Signature: ŽLB RUNCODE.SPM--A versatile routine for RUNning SPL code (Sig v1.00+)-- C.L.Distefano rev. 7/11/92)¯ŽIFŽVN$WS¯<1¯ŽPRNo file¯ŽEX¯ŽEI¯ŽIFŽVN$WS¯>1¯˙run˙€}˙ ŽEX¯ŽEI¯˙‚GŽIFŽVA$DE¯<1¯ŽSX298,ŽVN$FP¯¯˙‚Ģ(run ŽPV298¯)ŽEX¯ŽEI¯ŽSV298¯˙=ŽPV298¯ŽEX¯ ŽLD-¯ XyWrite Programming Language (XPL) has no native facility for testing whether a given Save/Get (S/G) has been initialized. (This has been remedied in Signature, where ŽVA!02¯ returns a value of 255, and ŽVA|02¯ a value of 65535, if S/G 02 is not initialized.) The standard kludge is to set the error code (ŽVA$ER¯) to a known value by forcing an error (other than "No Save Get"), then testing for a change in error code after executing SUbroutine ŽSU01,ŽSX02,ŽIS02¯¯˙Ŗ¯. If the error code is different after ŽGT01¯, then "ŽSX02,ŽIS02¯¯" failed and S/G 02 was not initialized. (A SUbroutine is used in order to avoid crashing the main routine; the "No Save Get" error can't be "trapped" in XPL.) The technique can be exemplified thus: ˙˙ ŽSU01,ŽSX02,ŽIS02¯¯˙Ŗ¯ŽGT01¯ŽSX01,ŽVA$ER¯¯ŽIFŽPV01¯<>11¯ŽSV02,¯ŽEI¯ŽEX¯ The downside to this approach is that the forced error--typically "˙˙ " (No command) as in the above example, sometimes "˙=˙€Ņ" (No define block) --is awkward, slow and in most cases extraneous to the routine at hand. An elegant alternative that avoids the forced error is to set the error code to 0 with the technique explicated in Robert J. Holmgren's ZEROVAER.PM, thus: ŽSU01,ŽSV03,¯ŽSX03,ŽIS03¯+ŽVABT¯¯˙Ŗ¯ŽGT01¯ŽSU01,ŽSX02,ŽIS02¯¯˙Ŗ¯ŽGT01¯ŽSX01,ŽVA$ER¯¯ŽIFŽPV01¯<0¯ŽSV02,¯ŽEI¯ŽEX¯ This TeXT proposes another workaround that's even more compact and doesn't require testing the error code at all. ŽSX03,0¯ŽSU01,ŽSX02,ŽIS02¯¯ŽSX03,1¯˙Ŗ¯ŽGT01¯ŽIFŽPV03¯<1¯ŽSV02,¯ŽEI¯ŽEX¯ The idea is to set a S/G to a known value (here, ŽSX03,0¯), then *change* the value within the test SUb *after* performing "ŽSX02,ŽIS02¯¯". If the value of ŽSX03,¯ hasn't changed after the SUb is executed, the SUb crashed before ŽSX03,1¯ could be executed and ŽSV02,¯ was not initialized. Here's an illustrative routine that tests S/G 02 (initialized here for demonstration purposes: PRoMPT "S/G exists!" is returned): ŽSX03,0¯ŽSV02,¯ŽSU01,ŽSX02,ŽIS02¯¯ŽSX03,1¯˙Ŗ¯ŽGT01¯ŽIFŽPV03¯<1¯ŽPRS/G not initialized¯ŽEX¯ŽEI¯ŽPRS/G exists!¯ŽEX¯ If you delete "ŽSV02,¯" (second command delta), the routine returns PRoMPT "S/G not initialized". The above example generates an error beep if ŽSV02,¯ is not initialized. Typically, the way around this is to set default eb to 0,0; this avoids bugs associated with the ES (error suppression) command. In the example, however, ES can be invoked with benign results: ŽSX03,0¯ŽSV02,¯ŽSU01,˙A˙es 1˙ ˙˙€}˙?ŽSX02,ŽIS02¯¯ŽSX03,1¯˙A˙es 0˙˙€}˙?¯ŽGT01¯ŽIFŽPV03¯<1¯ŽPRS/G not initialized¯ŽEX¯ŽEI¯ŽPRS/G exists!¯ŽEX¯ By reversing the values of ŽSX03,¯, error suppression can be accomplished via a separate SUbroutine, imparting added functionality to S/G 03--albeit, in this case, at the expense of about 20 additional bytes of code: ŽSX03,1¯ŽSV02,¯ŽSU01,˙A˙es ŽPV03¯˙ ˙˙€}˙?¯ŽSU04,ŽGT01¯ŽSX02,ŽIS02¯¯ŽSX03,0¯ŽGT01¯˙Ŗ¯ŽGT04¯ŽIFŽPV03¯>0¯ŽSX03,0¯ŽGT01¯ŽPRS/G not initialized¯ŽEX¯ŽEI¯ŽPRS/G exists!¯ŽEX¯ Advanced XPL programmers can see a working example of this technique in XQUIT.PM, part of XSAVE.PM (included in XSAVE.ZIP and FLOATERS.ZIP). XQUIT is a generic routine, suitable for both XyWrite and Signature, that stores the contents of "permanent" S/Gs to disk between editing sessions. (A companion routine, XSTART.PM, restores these S/Gs to memory at the start of a new session.) Instead of a SUbroutine, XQUIT uses Robert Holmgren's concatenation technique (see CTRLCHAR.TXT, by R.J.Holmgren) to "manufacture" a subsidiary routine that performs the initialization test. The relevant code is: "ŽSV17,ŽSX18,1¯¯ŽSX18,0¯ ... ŽSX19,ŽIS04¯+ŽIS09¯+ŽIS03¯+ŽIS12¯+ŽIS04¯+ŽIS11¯+ŽIS03¯+ŽIS10¯+ŽIS10¯+ŽIS17¯+ŽIS02¯¯ŽPV19¯ŽIFŽPV18¯<1¯ŽGLc¯ŽEI¯ŽSX18,0¯ ..." SUb-crashing can be used to test reliably whether a program is running under XyWrite or Signature. The basic idea is to devise a SUbroutine that will crash in XyWrite but not in Signature. The following example takes advantage of the fact that direct string comparisons (strings enclosed in quotation marks, without having first been saved to S/Gs) were enabled for the first time in Signature. In Signature, the statement "å">"" (programming shorthand for "something is greater than nothing") evaluates as TRUE; XyWrite, on the other hand, returns an unrecoverable "Command entry error". (The use of character "å" [Greek sigma] and the ">" [greater than] is a matter of personal choice. The point is to construct a statement which, if interpreted at all, is TRUE. Here, "å">"" is terser than, say, "x"=="x"; "sigma" is vaguely mnemonic for "Signature".) If Signature is running and the SUbroutine succeeds, the value of 01 (initially 0) will change to 1. Under XyWrite, the SUb crashes, and the value of 01 will remain 0. ˙A˙es 1˙ ŽSX01,0¯ŽSU02,ŽIF"å">""¯ŽSX01,1¯ŽEI¯˙Ŗ¯ŽGT02¯ŽIFŽPV01¯<1¯˙es 0˙ ˙˙€}˙?ŽPRThis is XyWrite¯ŽEX¯ŽEI¯ŽPRThis is Signature¯ŽEX¯ Once the SUb-crash test is performed, it's easy to check at any subsequent point in the program whether the environment is Xy or Sig: just test the value of S/G 01 (0=XyWrite, 1=Signature). This is useful. SPL developers who want to preserve downward compatibility with XyWrite need not forego the many slick programming enhancements added in Signature, because routines can branch appropriately depending on the value of the "environment variable". On a fairly trivial level, note that, in the above example, error suppression is reset to 0 (es 0) and the display unfrozen (func DO) *only* if the environment is Xy; in Signature, these are reset automatically upon EXiting the main routine. A slightly more developed example is shown below, a variant on the previous example that reports the version number if the environment is Signature. Here, the version number variable (VA $VE), direct string concatentation ("This is Signature "+ŽIS01¯) and the soft-coded prompt (PR@01) are all indigenous to Signature alone; yet, the routine runs without a hitch under XyWrite, too. ˙A˙es 1˙ ŽSX01,0¯ŽSU02,ŽIF"å">""¯ŽSX01,1¯ŽEI¯˙Ŗ¯ŽGT02¯ŽIFŽPV01¯<1¯˙es 0˙ ˙˙€}˙?ŽPRThis is XyWrite¯ŽEX¯ŽEI¯ŽSX01,ŽVA$VE¯¯ŽSX01,"This is Signature "+ŽIS01¯¯ŽPR@01¯ŽEX¯ The alert reader may ask, "Why not save VA$VE to a Save/Get and test for size? Shouldn't the size be 0 in XyWrite, greater than 0 in Sig?" (E.g.: ŽSX01,ŽVA$VE¯¯ŽIF@siz(ŽIS01¯)>0¯ŽPRSignature¯ŽEX¯ŽEI¯ŽPRXyWrite¯ŽEX¯) Intuitively, the answer is yes. In reality, the size of VA$VE saved to a Save/Get in XyWrite is unstable and unpredictable, and a test based on that value is unworkable. So back we go to crashing SUbs. Carl Distefano c/o XyQuest Information Line Billerica, MA 01821 U.S.A. 508-667-5669 508-667-4963