Add INSPECTOR
authorJason Self <j@jxself.org>
Sun, 2 Jun 2019 17:11:02 +0000 (10:11 -0700)
committerJason Self <j@jxself.org>
Sun, 2 Jun 2019 17:11:02 +0000 (10:11 -0700)
For poking around inside recent Inform game files
From http://www.firthworks.com/roger/downloads/Inspect.zip

inspect/Inspect.inf [new file with mode: 0644]

diff --git a/inspect/Inspect.inf b/inspect/Inspect.inf
new file mode 100644 (file)
index 0000000..81d191a
--- /dev/null
@@ -0,0 +1,2513 @@
+!% -GS\r
+!% $MAX_STATIC_DATA=600000\r
+!%\r
+! =================================================================================================\r
+!   INSPECTOR -- examine Z-Machine files -- Roger Firth (roger@firthworks.com)\r
+!\r
+!   V1.1 29Jan04 - removed misleading comment from generated XML\r
+!   V1.0 11Nov03 - first public release\r
+!\r
+!   This program is strictly for the curious. It reads a compiled Inform 6 .z5 or .z8 game file\r
+!   and attempts to display its contents.\r
+!\r
+!   The program is a standalone Glulx utility which does not used the Inform library files.\r
+!   To compile it, you will need to include on the command line: $MAX_STATIC_DATA=600000\r
+!   and you will require the "infglk.h" header file. To run it, any Glulx interpreter should do.\r
+!\r
+!   To make any sense of the XML data produced by the R command, you will require\r
+!   the Dia drawing program (http://www.lysator.liu.se/~alla/dia). Unix and Windows only.\r
+!\r
+!   IMPORTANT NOTE: The program is much more restrictive than Ztools in the Z-Machine files that\r
+!   it will handle, and much less reliable. Its primary advantage is that, being written using\r
+!   the Inform language, it is readily amenable to being customized and extended.\r
+!\r
+!   This program is copyright Roger Firth 2003-2004. Copying and distribution, with or without \r
+!   modification, are permitted in any medium without royalty provided the copyright notice and \r
+!   this notice are preserved.\r
+!\r
+! =================================================================================================\r
+!   These arrays should be sufficient, but may need adjusting for an enormous game.\r
+\r
+Constant MAX_GAME 525000;               ! For a 512K Z8 game.\r
+Array    theGame -> MAX_GAME;\r
+\r
+Constant MAX_ROUTINES 3000;             ! Packed Routine addresses.\r
+Array    theRoutines --> MAX_ROUTINES;\r
+\r
+Constant MAX_STRINGS 5000;              ! Packed String addresses.\r
+Array    theStrings --> MAX_STRINGS;\r
+\r
+Constant MAX_ROOMS 200;                 ! Rooms (for XML map).\r
+Array    theRooms    --> MAX_ROOMS;\r
+\r
+Constant MAX_DIRPROPS 12;               ! Exits from rooms (for XML map).\r
+Array    DirPropNums --> MAX_DIRPROPS;\r
+\r
+Array    DirPropNames -->\r
+    "n_to"  "s_to"  "e_to"  "w_to"\r
+    "ne_to" "sw_to" "nw_to" "se_to"\r
+    "u_to"  "d_to"  "in_to" "out_to";\r
+\r
+Array    NfromRoom   --> MAX_ROOMS;\r
+Array    SfromRoom   --> MAX_ROOMS;\r
+Array    EfromRoom   --> MAX_ROOMS;\r
+Array    WfromRoom   --> MAX_ROOMS;\r
+Array    NEfromRoom  --> MAX_ROOMS;\r
+Array    SWfromRoom  --> MAX_ROOMS;\r
+Array    NWfromRoom  --> MAX_ROOMS;\r
+Array    SEfromRoom  --> MAX_ROOMS;\r
+Array    UfromRoom   --> MAX_ROOMS;\r
+Array    DfromRoom   --> MAX_ROOMS;\r
+Array    INfromRoom  --> MAX_ROOMS;\r
+Array    OUTfromRoom --> MAX_ROOMS;\r
+\r
+Array    theExits -->                   ! Simulate a two-dimensional array.\r
+    NfromRoom  SfromRoom  EfromRoom  WfromRoom\r
+    NEfromRoom SWfromRoom NWfromRoom SEfromRoom\r
+    UfromRoom  DfromRoom  INfromRoom OUTfromRoom;\r
+\r
+Constant MAX_DOORS 50;                  ! Doors (for XML map).\r
+Array    theDoors    --> MAX_DOORS;\r
+\r
+Array    doorToRoom  --> MAX_DOORS;\r
+\r
+Constant MAX_INPUT 50;                  ! Line of keyboard input.\r
+Array    theInput -> MAX_INPUT;\r
+\r
+Constant MAX_TOKENS 3;                  ! Input tokens.\r
+Array    TokenStart -> MAX_TOKENS;\r
+Array    TokenEnd   -> MAX_TOKENS;\r
+Array    Tokens    --> MAX_TOKENS;      ! Command, optional numbers.\r
+\r
+! =================================================================================================\r
+!   Since we're not using the Glulx Inform library files, we need to set up our own Glk\r
+!   Input/Output.\r
+\r
+Include "infglk";                       ! Use sensible names for calls to Glk.\r
+\r
+Array   gg_arguments --> 8;             ! General result passing.\r
+Array   gg_event     --> 4;             ! The event handler uses a four-word array.\r
+Global  gg_mainwin    = 0;              ! The main window.\r
+Global  gg_helpwin;                     ! For static help info.\r
+Global  gg_scriptfref = 0;              ! Fileref for Transcripts.\r
+Global  gg_scriptstr  = 0;              ! I/O Stream for Transcripts.\r
+\r
+Constant ANY_OLD_ROCK 0;                ! Rock values don't seem necessary here.\r
+\r
+! =================================================================================================\r
+!   General constants used by the tool.\r
+\r
+Constant NO_GAME_OPEN "Use ~N~ to open a new .Z5 or .Z8 game file.";\r
+\r
+Constant MAX_LOCALS   15;               ! First byte of a routine.\r
+Constant STR_TRUNC_TO 20;               ! Characters to show with @print_addr, @print_paddr\r
+\r
+Constant BIT00 $0001;\r
+Constant BIT01 $0002;\r
+Constant BIT02 $0004;\r
+Constant BIT03 $0008;\r
+Constant BIT04 $0010;\r
+Constant BIT05 $0020;\r
+Constant BIT06 $0040;\r
+Constant BIT07 $0080;\r
+Constant BIT08 $0100;\r
+Constant BIT09 $0200;\r
+Constant BIT10 $0400;\r
+Constant BIT11 $0800;\r
+Constant BIT12 $1000;\r
+Constant BIT13 $2000;\r
+Constant BIT14 $4000;\r
+Constant BIT15 $8000;\r
+\r
+Constant BITS00_04 BIT00+BIT01+BIT02+BIT03+BIT04;\r
+Constant BITS05_09 BIT05+BIT06+BIT07+BIT08+BIT09;\r
+Constant BITS10_14 BIT10+BIT11+BIT12+BIT13+BIT14;\r
+\r
+Constant BITS00_03 BIT00+BIT01+BIT02+BIT03;\r
+Constant BITS00_05 BITS00_04+BIT05;\r
+Constant BITS00_09 BITS00_04+BITS05_09;\r
+Constant BITS00_14 BITS00_09+BITS10_14;\r
+\r
+Constant HDR_ZCODEVERSION  $00;         ! byte\r
+Constant HDR_TERPFLAGS     $01;         ! byte\r
+Constant HDR_GAMERELEASE   $02;         ! word\r
+Constant HDR_HIGHMEMORY    $04;         ! word\r
+Constant HDR_INITIALPC     $06;         ! word\r
+Constant HDR_DICTIONARY    $08;         ! word\r
+Constant HDR_OBJECTS       $0A;         ! word\r
+Constant HDR_GLOBALS       $0C;         ! word\r
+Constant HDR_STATICMEMORY  $0E;         ! word\r
+Constant HDR_GAMEFLAGS     $10;         ! word\r
+Constant HDR_GAMESERIAL    $12;         ! six ASCII characters\r
+Constant HDR_ABBREVIATIONS $18;         ! word\r
+Constant HDR_FILELENGTH    $1A;         ! word\r
+Constant HDR_CHECKSUM      $1C;         ! word\r
+Constant HDR_TERPNUMBER    $1E;         ! byte\r
+Constant HDR_TERPVERSION   $1F;         ! byte\r
+Constant HDR_SCREENHLINES  $20;         ! byte\r
+Constant HDR_SCREENWCHARS  $21;         ! byte\r
+Constant HDR_SCREENWUNITS  $22;         ! word\r
+Constant HDR_SCREENHUNITS  $24;         ! word\r
+Constant HDR_FONTWUNITS    $26;         ! byte\r
+Constant HDR_FONTHUNITS    $27;         ! byte\r
+Constant HDR_ROUTINEOFFSET $28;         ! word\r
+Constant HDR_STRINGOFFSET  $2A;         ! word\r
+Constant HDR_BGCOLOUR      $2C;         ! byte\r
+Constant HDR_FGCOLOUR      $2D;         ! byte\r
+Constant HDR_TERMCHARS     $2E;         ! word\r
+Constant HDR_PIXELSTO3     $30;         ! word\r
+Constant HDR_TERPSTANDARD  $32;         ! two bytes\r
+Constant HDR_ALPHABET      $34;         ! word\r
+Constant HDR_EXTENSION     $36;         ! word\r
+Constant HDR_UNUSED        $38;         ! two words\r
+Constant HDR_INFORMVERSION $3C;         ! four ASCII characters\r
+Constant HDR_ENDOFDATA     $40;         ! Next table starts here\r
+\r
+Constant HDREXTN_SIZE      $00;         ! word\r
+Constant HDREXTN_MOUSEX    $02;         ! word\r
+Constant HDREXTN_MOUSEY    $04;         ! word\r
+Constant HDREXTN_UNICODE   $06;         ! word\r
+\r
+Array Bit -->                           ! Used to match Attribute bits.\r
+    BIT00 BIT01 BIT02 BIT03 BIT04 BIT05 BIT06 BIT07 BIT08 BIT09 BIT10 BIT11 BIT12 BIT13 BIT14 BIT15;\r
+\r
+Array a_LocalAlpha ->                   ! Used to unpack ZSCII strings.\r
+    'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 'u' 'v' 'w' 'x' 'y' 'z'\r
+    'A' 'B' 'C' 'D' 'E' 'F' 'G' 'H' 'I' 'J' 'K' 'L' 'M' 'N' 'O' 'P' 'Q' 'R' 'S' 'T' 'U' 'V' 'W' 'X' 'Y' 'Z'\r
+    ' ' '^' '0' '1' '2' '3' '4' '5' '6' '7' '8' '9' '.' ',' '!' '?' '_' '#' 039 '"' '/' '\' '-' ':' '(' ')';\r
+\r
+Array a_LocalUnicode ->                 ! Used to print 'extra' ZSCII characters.\r
+    69                                  ! Number of 16-bit entries\r
+    $00 $E4  $00 $F6  $00 $FC  $00 $C4  $00 $D6  $00 $DC  $00 $DF  $00 $BB\r
+    $00 $AB  $00 $EB  $00 $EF  $00 $FF  $00 $CB  $00 $CF  $00 $E1  $00 $E9\r
+    $00 $ED  $00 $F3  $00 $FA  $00 $FD  $00 $C1  $00 $C9  $00 $CD  $00 $D3\r
+    $00 $DA  $00 $DD  $00 $E0  $00 $E8  $00 $EC  $00 $F2  $00 $F9  $00 $C0\r
+    $00 $C8  $00 $CC  $00 $D2  $00 $D9  $00 $E2  $00 $EA  $00 $EE  $00 $F4\r
+    $00 $FB  $00 $C2  $00 $CA  $00 $CE  $00 $D4  $00 $DB  $00 $E5  $00 $C5\r
+    $00 $F8  $00 $D8  $00 $E3  $00 $F1  $00 $F5  $00 $C3  $00 $D1  $00 $D5\r
+    $00 $E6  $00 $C6  $00 $E7  $00 $C7  $00 $FE  $00 $F0  $00 $DE  $00 $D0\r
+    $00 $A3  $01 $53  $01 $52  $00 $A1  $00 $BF;\r
+\r
+! =================================================================================================\r
+!   Variables used by the tool.\r
+\r
+Global  modePause = false;              ! Pause after each screenful?\r
+Global  modeTranscript = false;         ! Write a Transcript file?\r
+Global  modeExpand = false;             ! Expand Property and Action Routines?\r
+\r
+Global   currentState;                  ! Tool state:\r
+Constant STATE_IDLE   0;                ! No game open.\r
+Constant STATE_DECODE 1;                ! Analysing the game.\r
+Constant STATE_DUMP   2;                ! Displaying general game info.\r
+Constant STATE_EMBED  3;                ! Displaying embedded strings.\r
+\r
+Global   stringOptions;                 ! Control string printing:\r
+Constant STR_NO_SPACES BIT00;           ! Map " " to "_".\r
+Constant STR_NO_QUOTES BIT01;           ! Map "'" to "^".\r
+Constant STR_UPPERCASE BIT02;           ! Fold alpha to upper case.\r
+Constant STR_TRUNCATE  BIT03;           ! Show only start of strings.\r
+Constant STR_MULTILINE BIT04;           ! Map " " to newline.\r
+\r
+Global  zcodeVersion;                   ! Z-Machine version 1-8\r
+Global  informVersion;                  ! Compiler version  5-6\r
+Global  p_Multiplier;                   ! Packed addr multiplier\r
+\r
+Global  i_FirstUserObject;              ! Obj number for (LibraryMessages)\r
+\r
+Global  n_Actions;                      ! Number of Action routines\r
+Global  n_ArrayNames;                   ! Number of Array names\r
+Global  n_AttrNames;                    ! Number of Attribute names\r
+Global  n_Classes;                      ! Number of Classes\r
+Global  n_DictEntries;                  ! Number of Dictionary entries\r
+Global  n_Objects;                      ! Number of Objects (inc Classes)\r
+Global  n_Opcodes;                      ! Number of Opcodes\r
+Global  n_PropNames;                    ! Number of Property names\r
+Global  n_Rooms;                        ! Number of Rooms\r
+Global  n_Doors;                        ! Number of Doors\r
+Global  n_Routines;                     ! Number of Routines\r
+Global  n_Strings;                      ! Number of Strings\r
+Global  n_Verbs;                        ! Number of Verb grammars\r
+\r
+Global  a_Header;                       ! ZM11 ZMxB\r
+Global  a_StringPool;                   ! TM8.3\r
+Global  a_LowStrings;                   ! TM8.5\r
+Global  a_Abbrevs;                      ! TM8.5\r
+Global  a_HeaderExtn;                   ! TM8.5\r
+Global  a_GameAlpha;                    ! ZM3.5 TM8.5\r
+Global  a_GameUnicode;                  ! ZM3.8.5 TM8.3 TM8.5\r
+Global  a_CommonPropDefaults;           ! ZM12.2\r
+Global  a_Objects;                      ! ZM12.3 TM9.4\r
+Global  a_CommonProps;                  ! ZM12.4\r
+Global  a_ClassToObject;                ! TM9.4\r
+Global  a_PropNames;                    ! TM9.7\r
+Global  a_AttrNames;                    ! TM9.7\r
+Global  a_ActionNames;                  ! TM9.7\r
+Global  a_ArrayNames;                   ! TM9.7\r
+Global  a_IndivProps;                   ! TM9.5 TM9.6\r
+Global  a_Globals;                      !\r
+Global  a_Arrays;                       !\r
+Global  a_TermChars;                    !\r
+\r
+Global  a_StaticMemory;                 !\r
+Global  a_GrammarPointers;              ! TM8.6\r
+Global  a_Grammars;                     !\r
+Global  a_Actions;                      !\r
+Global  a_PreActions;                   !\r
+Global  a_Prepositions;                 !\r
+Global  a_Dictionary;                   ! ZM13.1 TM8.5\r
+\r
+Global  a_HighMemory;                   !\r
+Global  a_Routines;                     !\r
+Global  a_TopOfRoutines;                !\r
+Global  a_Strings;                      !\r
+Global  a_TopOfGame;                    !\r
+\r
+Global  p_Routines;                     ! ZM4 ZM5 ZM14\r
+Global  p_Strings;                      ! ZM3\r
+Global  p_TopOfGame;                    !\r
+\r
+Global  a_LookupAlpha;                  ! Local or embedded in game.\r
+Global  a_LookupUnicode;                ! Local or embedded in game.\r
+\r
+! =================================================================================================\r
+!   Instructions for use.\r
+\r
+[ ShowHelp;\r
+    "This tool inspects the contents of a Z-Machine game, in much the same way as\r
+     (and much slower and less reliably than) Ztools.\r
+     It is driven by these commands:^\r
+     ^\r
+     N - open a new game file.^\r
+     Q - quit.^\r
+     ^\r
+     P - toggle Pause mode, which waits for a keypress after each screen.^\r
+     T - toggle Transcript mode, which writes the output to a file.^\r
+     X - toggle eXpanded mode, which shows Property and Action routines.^\r
+     ^\r
+     A - display All (Map, Header, Objects, Grammar).^\r
+     D - display memory Dump in hex.^\r
+     E - display print strings Embedded in Z-code.^\r
+     G - display verb Grammar.^\r
+     H - display Header information.^\r
+     L - display Low-memory strings.^\r
+     M - display Memory map.^\r
+     O - display Objects [long].^\r
+     R - display Rooms and connections in XML for Dia drawing tool [long].^\r
+     S - display high-memory Strings [long].^\r
+     V - display dictionary Vocabulary.^\r
+     Z - display Z-code routines [long].^\r
+     ^\r
+     ? - display these instructions.";\r
+];\r
+\r
+[ ShowShortHelp;\r
+    "Start/stop: ", (b) "N", "ew, ", (b) "Q", "uit.     Modes: ", (b) "P", "ause, ", (b) "T", "ranscript, e", (b) "X", "panded.^\r
+     Dumping: ", (b) "O", "bjects, ", (b) "S", "trings, ", (b) "L", "ow strings, ", (b) "E", "mbedded strings, ", (b) "G", "rammar, ",\r
+     (b) "V", "ocabulary, ", (b) "H", "eader, ", (b) "M", "emory map, ", (b) "Z", "-code, ", (b) "R", "ooms, ", (b) "A", "ll";\r
+];\r
+\r
+\r
+[ b text;\r
+    glk_set_style(style_Emphasized);\r
+    print (string) text;\r
+    glk_set_style(style_Normal);\r
+];\r
+\r
+! =================================================================================================\r
+!   This is the top-level control loop.\r
+\r
+[ Main;\r
+\r
+    @setiosys 2 0;                      ! Set Glk as the VM's I/O layer.\r
+    gg_mainwin =                        ! Open the main window.\r
+        glk_window_open(0, 0, 0, wintype_TextBuffer, ANY_OLD_ROCK);\r
+    gg_helpwin =\r
+        glk_window_open(gg_mainwin, winmethod_Above+winmethod_Fixed, 3, wintype_TextBuffer, ANY_OLD_ROCK);\r
+    glk_set_window(gg_helpwin);\r
+    ShowShorthelp();\r
+    glk_set_window(gg_mainwin);         ! Make the main window the current window.\r
+\r
+    glk_set_style(style_Header);\r
+    print "INSPECTOR";\r
+    glk_set_style(style_Normal);\r
+    print "^A tool for examining v5 and v8 Z-code files created by Inform 6.^^";\r
+    ShowHelp();                         ! Explain what they can do.\r
+\r
+    while (true) {                      ! Loop here until "Q" typed.\r
+        new_line;\r
+        if (modePause)      print "P"; else print "-";\r
+        if (modeTranscript) print "T"; else print "-";\r
+        if (modeExpand)     print "X"; else print "-";\r
+        print "> ";                     ! Prompt for a line of input.\r
+        if (~~ParseLine()) continue;    ! Nothing typed\r
+        Tokens-->0 = theInput->(TokenStart->0);\r
+        Tokens-->1 = ParseNumber(TokenStart->1, TokenEnd->1);\r
+        Tokens-->2 = ParseNumber(TokenStart->2, TokenEnd->2);\r
+        switch (Tokens-->0) {           ! Deal with the character, then loop back.\r
+          'A','a':  if (~~currentState) print (string) NO_GAME_OPEN, "^";\r
+                    else {\r
+                        DumpMemoryMap();\r
+                        DumpHeader();\r
+                        DumpObjects();\r
+                        DumpGrammar();\r
+                    }\r
+          'D','d':  DumpData();\r
+          'E','e':  DumpEmbedded();\r
+          'G','g':  DumpGrammar();\r
+          'H','h':  DumpHeader();\r
+          'L','l':  DumpLowStrings();\r
+          'M','m':  DumpMemoryMap();\r
+          'N','n':  DoOpen();\r
+          'O','o':  DumpObjects();\r
+          'P','p':  DoPause();\r
+          'Q','q':  DoQuit();\r
+          'R','r':  DumpRooms();\r
+          'S','s':  DumpStrings();\r
+          'T','t':  DoTranscript();\r
+          'V','v':  DumpVocab();\r
+          'X','x':  DoExpand();\r
+          'Z','z':  DumpZcode();\r
+          '?','/':  ShowHelp();\r
+          default:  print "Possible keys are N, Q, P|T|X, A|D|E|G|H|L|M|O|R|S|V|Z and ?^";\r
+        }\r
+    }\r
+];\r
+\r
+! [ InputChar;                          ! Input one keystroke.\r
+!   glk_request_char_event(gg_mainwin);\r
+!   while (true) {                      ! Wait for a key to be pressed.\r
+!       glk_select(gg_event);           ! CharInput is th only interesting event.\r
+!       if (gg_event-->0 == evtype_CharInput && gg_event-->1 == gg_mainwin)\r
+!           return gg_event-->2;        ! Got a character.\r
+!   }\r
+! ];\r
+\r
+[ InputLine buf buflen;                 ! Input a line of characters.\r
+    glk_request_line_event(gg_mainwin, buf, buflen, 0);\r
+    while (true) {                      ! Wait for RETURN to be pressed.\r
+        glk_select(gg_event);           ! LineInput is the only interesting event.\r
+        if (gg_event-->0 == evtype_LineInput && gg_event-->1 == gg_mainwin)\r
+            return (gg_event-->2);      ! Number of characters.\r
+    }\r
+];\r
+\r
+[ ParseLine                             ! Read line of input, find tokens\r
+    i j n;\r
+    for (i=0 : i<MAX_TOKENS : i++) TokenStart->i = TokenEnd->i = 0;\r
+    n = InputLine(theInput, MAX_INPUT);\r
+    glk_select_poll(gg_event);\r
+    if (n == 0) rfalse;                 ! Nothing typed.\r
+    for (i=j=0 : i<MAX_TOKENS : i++) {\r
+        while (theInput->j == ' ' or ',') {\r
+            j++;\r
+            if (j >= n) return i;\r
+        }\r
+        TokenStart->i = j;\r
+        while (theInput->j ~= ' ' or ',') {\r
+            j++;\r
+            TokenEnd->i = j;\r
+            if (j >= n) return i+1;\r
+        }\r
+    }\r
+    return i;\r
+];\r
+\r
+[ ParseNumber a b                       ! Parse token as bin/dec/hex number.\r
+    char base num i;\r
+    if (a == b) return -1;\r
+    base = 10; num = 0;\r
+    i = a;\r
+    if (theInput->i == '-') i++;\r
+    if (theInput->i == '$') {\r
+        base = 16; i++;\r
+        if (theInput->i == '$') { base = 2; i++; }\r
+    }\r
+    for ( : i<b : i++) {\r
+        char = theInput->i;\r
+        if (char >= '0' && char <= '9') char = char - '0';\r
+        else {\r
+            if (char >= 'A' && char <= 'Z') char = char - 'A' + 10;\r
+            else {\r
+                if (char >= 'a' && char <= 'z') char = char - 'a' + 10;\r
+                else return -1;\r
+            }\r
+        }\r
+        if (char < base) num = (num * base) + char;\r
+        else return -1;\r
+    }\r
+    if (theInput->a == '-') num = -num;\r
+    return num;\r
+];\r
+\r
+! =================================================================================================\r
+!   Quit from the utility.\r
+\r
+[ DoQuit;\r
+    print "Hit any key to exit.^"; quit;\r
+];\r
+\r
+! =================================================================================================\r
+!   Toggle Pause mode.\r
+\r
+[ DoPause;\r
+    if (modePause) {                    ! Toggle to OFF.\r
+        modePause = false;\r
+        "Pause mode now off.";\r
+    }\r
+    else {                              ! Toggle to ON.\r
+        modePause = true;\r
+        "Pause mode now on.";\r
+    }\r
+];\r
+\r
+! =================================================================================================\r
+!   Toggle Transcript mode.\r
+\r
+[ DoTranscript;\r
+    if (modeTranscript) {               ! Toggle to OFF.\r
+        glk_stream_close(gg_scriptstr); ! Close the Transcript stream.\r
+        gg_scriptstr = 0;\r
+        modeTranscript = false;\r
+        "Transcript mode now off.";\r
+    }\r
+    else {                              ! Toggle to ON.\r
+        if (gg_scriptfref == 0) {\r
+            gg_scriptfref =             ! Create a fileref for the Transcript.\r
+                glk_fileref_create_by_prompt(fileusage_TextMode+fileusage_Transcript, filemode_WriteAppend, ANY_OLD_ROCK);\r
+            if (gg_scriptfref == GLK_NULL) "Failed to create Transcript fileref.";\r
+        }\r
+        gg_scriptstr =                  ! Open a stream to write the transcript file.\r
+            glk_stream_open_file(gg_scriptfref, filemode_WriteAppend, ANY_OLD_ROCK);\r
+        if (gg_scriptstr == GLK_NULL) "failed to open Transcript stream.";\r
+                                        ! Echo everything to the Transcript.\r
+        glk_window_set_echo_stream(gg_mainwin, gg_scriptstr);\r
+        modeTranscript = true;\r
+        "Transcript mode now on.";\r
+    }\r
+];\r
+\r
+! =================================================================================================\r
+!   Toggle Expanded mode (for Property and Action routines).\r
+\r
+[ DoExpand;\r
+    if (modeExpand) {                   ! Toggle to OFF.\r
+        modeExpand = false;\r
+        "Expand mode now off.";\r
+    }\r
+    else {                              ! Toggle to ON.\r
+        modeExpand = true;\r
+        "Expand mode now on.";\r
+    }\r
+];\r
+\r
+! =================================================================================================\r
+!   Memory access routines.\r
+\r
+[ GetByte a;        return theGame->a; ];\r
+[ GetWord a;        return (theGame->a) * $00100 + theGame->(a+1); ];\r
+\r
+[ W_To_A a;         return a * 2; ];\r
+[ P_To_A a;         return a * p_Multiplier; ];\r
+[ A_To_P a;         return a / p_Multiplier; ];\r
+\r
+[ P_RoundUp a\r
+    b;              b = p_Multiplier-1; return (a + b) & ~b;\r
+];\r
+\r
+! =================================================================================================\r
+!   Print rules.\r
+\r
+[ dec2 x; if (x<10) print "0"; print x; ];\r
+[ dec3 x; if (x<10) print "0"; if (x<100) print "0"; print x; ];\r
+\r
+[ hex2 x; print                                                                (hchar) x & $000FF; ];\r
+[ hex4 x; print                                 (hchar) (x & $0FF00) / $00100, (hchar) x & $000FF; ];\r
+[ hex5 x; print (hdigit) (x & $F0000) / $10000, (hchar) (x & $0FF00) / $00100, (hchar) x & $000FF; ];\r
+[ hchar x; print (hdigit) (x & $000F0) / $00010, (hdigit) x & $0000F; ];\r
+[ hdigit x; if ((x = x%$10) < 10) print x; else print (char) x-10+'A'; ];\r
+\r
+Constant EXPECTING_A0 0;                ! character in Alphabet 0\r
+Constant EXPECTING_A1 1;                ! character in Alphabet 1\r
+Constant EXPECTING_A2 2;                ! character in Alphabet 2\r
+Constant EXPECTING_B1 3;                ! low string 0-31\r
+Constant EXPECTING_B2 4;                ! abbreviation 0-31\r
+Constant EXPECTING_B3 5;                ! abbreviation 32-63\r
+Constant EXPECTING_Z1 6;                ! high bits of ZSCII character\r
+Constant EXPECTING_Z2 7;                ! low bits of ZSCII character\r
+\r
+[ Zaddress a                            ! Print string at byte address.\r
+    w c d i n theState;\r
+\r
+    theState = EXPECTING_A0;\r
+    do {\r
+        w = GetWord(a); a = a + 2;\r
+        for (i=0 : i<3 : i++) {\r
+            switch (i) {\r
+              0:    c = (w & BITS10_14) / BIT10;\r
+              1:    c = (w & BITS05_09) / BIT05;\r
+              2:    c = (w & BITS00_04);\r
+            }\r
+            switch (theState) {\r
+              EXPECTING_A0:             ! character in Alphabet 0\r
+                switch (c) {\r
+                  0:    n = n + Zchar(' ');\r
+                  1:    theState = EXPECTING_B1;\r
+                  2:    theState = EXPECTING_B2;\r
+                  3:    theState = EXPECTING_B3;\r
+                  4:    theState = EXPECTING_A1;\r
+                  5:    theState = EXPECTING_A2;\r
+                  default:\r
+                        n = n + Zchar(a_LookupAlpha->(c-6));\r
+                }\r
+              EXPECTING_A1:             ! character in Alphabet 1\r
+                switch (c) {\r
+                  0:    n = n + Zchar(' ');\r
+                        theState = EXPECTING_A0;\r
+                  1:    theState = EXPECTING_B1;\r
+                  2:    theState = EXPECTING_B2;\r
+                  3:    theState = EXPECTING_B3;\r
+                  4:    theState = EXPECTING_A1;\r
+                  5:    theState = EXPECTING_A2;\r
+                  default:\r
+                        n = n + Zchar(a_LookupAlpha->(c-6+26));\r
+                        theState = EXPECTING_A0;\r
+                }\r
+              EXPECTING_A2:             ! character in Alphabet 2\r
+                switch (c) {\r
+                  0:    n = n + Zchar(' ');\r
+                        theState = EXPECTING_A0;\r
+                  1:    theState = EXPECTING_B1;\r
+                  2:    theState = EXPECTING_B2;\r
+                  3:    theState = EXPECTING_B3;\r
+                  4:    theState = EXPECTING_A1;\r
+                  5:    theState = EXPECTING_A2;\r
+                  6:    theState = EXPECTING_Z1;\r
+                  7:    n = n + Zchar(13);\r
+                        theState = EXPECTING_A0;\r
+                  default:\r
+                        n = n + Zchar(a_LookupAlpha->(c-6+52));\r
+                        theState = EXPECTING_A0;\r
+                }\r
+              EXPECTING_B1:             ! low strings 00-31\r
+                print "@@64", (dec2) c; n = n + 3;\r
+                theState = EXPECTING_A0;\r
+              EXPECTING_B2:             ! abbreviations 00-31\r
+                n = n + Zaddress(W_To_A(GetWord(a_Abbrevs+2*c)));       ! recurse\r
+                theState = EXPECTING_A0;\r
+              EXPECTING_B3:             ! abbreviations 32-63\r
+                n = n + Zaddress(W_To_A(GetWord(a_Abbrevs+2*c+64)));    ! recurse\r
+                theState = EXPECTING_A0;\r
+              EXPECTING_Z1:             ! hi bits of ZSCII character\r
+                d = c * 32;\r
+                theState = EXPECTING_Z2;\r
+              EXPECTING_Z2:             ! lo bits of ZSCII character\r
+                n = n + Zchar(d+c);\r
+                theState = EXPECTING_A0;\r
+            }\r
+        }\r
+    } until (w & BIT15 || ((stringOptions & STR_TRUNCATE) && n > STR_TRUNC_TO));\r
+    return n;                           ! number of characters output\r
+];\r
+\r
+[ Zchar c;                              ! Print a single ZSCII character.\r
+    switch (c) {\r
+      0:                                ! null\r
+        return 0;\r
+      13:                               ! newline\r
+        c = '^';\r
+      32:                               ! space\r
+        if (stringOptions & STR_NO_SPACES) c = '_';\r
+        if (stringOptions & STR_MULTILINE) { new_line; return 1; }\r
+      34:                               ! double quotes\r
+        c = '~';\r
+      39:                               ! single quotes\r
+        if (stringOptions & STR_NO_QUOTES) c = '^';\r
+      64:                               ! at sign\r
+        print (char) 64, (char) 64, "64"; return 4;\r
+      92:                               ! backslash\r
+        print (char) 64, (char) 64, "92"; return 4;\r
+      94:                               ! circumflex\r
+        print (char) 64, (char) 64, "94"; return 4;\r
+      126:                              ! tilde\r
+        print (char) 64, (char) 64, "126"; return 5;\r
+      32 to 126:                        ! ASCII -- print normally.\r
+        ;\r
+      155 to 251:                       ! ZSCII 'extra characters'\r
+        c = c - 154;\r
+        if (c > a_LookupUnicode->0) c = '?';\r
+        else c = a_LookupUnicode->(2*c - 1) * 256 + a_LookupUnicode->(2*c);\r
+      default:                          ! Not a ZSCII character.\r
+        c = '?';\r
+    }\r
+    if (stringOptions & STR_UPPERCASE) c = glk_char_to_upper(c);\r
+    print (char) c;\r
+    return 1;\r
+];\r
+\r
+[ Zstring a;                            ! Print string at packed address.\r
+    return Zaddress(P_To_A(a));\r
+];\r
+\r
+[ Zname o                               ! Print external name of object.\r
+    a;\r
+    if (o == nothing) print "nothing";\r
+    else {\r
+        a = a_Objects + (o-1)*14;\r
+        a = GetWord(a+12);\r
+        print (Zaddress) a+1;\r
+    }\r
+];\r
+\r
+[ Zobject o                             ! Print internal (hardware) name of object.\r
+    a;\r
+    if (o == nothing) print "nothing";\r
+    else {\r
+        a = a_Objects + (o-1)*14;\r
+        a = GetWord(a+12);\r
+        if(GetByte(a) == 1 && GetWord(a+1) == $94A5)\r
+            print "UnNamed";\r
+        else {\r
+            stringOptions = stringOptions | STR_NO_SPACES;\r
+            print (Zaddress) a+1;\r
+            stringOptions = stringOptions & ~STR_NO_SPACES;\r
+        }\r
+        print "_", o;\r
+    }\r
+];\r
+\r
+[ Zproperty p                           ! Print name of property.\r
+    x;\r
+    if (a_PropNames)\r
+        switch (p) {\r
+          2: print "class";\r
+          3: print "metaclass";\r
+          default:\r
+            x = GetWord(a_PropNames + 2*p);\r
+            if (x) print (Zstring) x;\r
+            else   print "<unknown property ", p, ">";\r
+        }\r
+    else\r
+        print "(PROP", (dec3) p, ")";\r
+];\r
+\r
+[ Zattribute q;                         ! Print name of attribute.\r
+    if (a_AttrNames)\r
+        print (Zstring) GetWord(a_AttrNames + 2*q);\r
+    else\r
+        print "(ATTR", (dec2) q, ")";\r
+];\r
+\r
+[ Zaction a;                            ! Print name of action.\r
+    if (a > 255) print "(FAKE", (dec2) a-256, ")";\r
+    else\r
+        if (a_ActionNames)\r
+            print (Zstring) GetWord(a_ActionNames + 2*a);\r
+        else\r
+            print "(ACTION", (dec3) a, ")";\r
+];\r
+\r
+! =================================================================================================\r
+!   Prompt for a Z-code file, read it into the buffer, and analyse its contents.\r
+\r
+[ DoOpen;\r
+    currentState = STATE_IDLE;\r
+    if (ReadTheFile(theGame, MAX_GAME)) return;\r
+    currentState = STATE_DECODE;\r
+    if (DecodeTheGame()) return;\r
+    currentState = STATE_DUMP;\r
+    font off;\r
+    print "^Game contents:^";\r
+    print "  Actions     ", n_Actions, "^";\r
+    print "  Attributes  ", n_AttrNames, "^";\r
+    print "  Classes     ", n_Classes, "^";\r
+    print "  Dictionary  ", n_DictEntries, "^";\r
+    print "  Objects     ", n_Objects, "^";\r
+    print "  Properties  ", n_PropNames, "^";\r
+    print "  Routines    ", n_Routines, "^";\r
+    print "  Strings     ", n_Strings, "^";\r
+    print "  Verbs       ", n_Verbs, "^";\r
+    font on;\r
+];\r
+\r
+[ ReadTheFile buf buflen\r
+    fileref stream;\r
+    fileref = glk_fileref_create_by_prompt(fileusage_BinaryMode+fileusage_Data, filemode_Read, ANY_OLD_ROCK);\r
+    if (fileref == GLK_NULL) "Failed to create Game fileref.";\r
+    stream = glk_stream_open_file(fileref, filemode_Read, ANY_OLD_ROCK);\r
+    if (stream == GLK_NULL) "Failed to open Game stream.";\r
+    glk_fileref_destroy(fileref);\r
+    glk_get_buffer_stream(stream, buf, buflen);\r
+    rfalse;                             ! Successful -- OK to continue.\r
+];\r
+\r
+[ DecodeTheGame\r
+    a b c;\r
+\r
+    ! Check which Game/Compiler versions we're dealing with\r
+\r
+    a_Header        = $00000;\r
+    a_StringPool    = a_Header+HDR_ENDOFDATA;\r
+    a_HeaderExtn    = GetWord(a_Header+HDR_EXTENSION);\r
+\r
+    zcodeVersion = GetByte(a_Header+HDR_ZCODEVERSION);\r
+    switch (zcodeVersion) {\r
+      1,2,3:    p_Multiplier = 2; "Sorry -- Z-machine version ", zcodeVersion, " not supported.";\r
+      4,6,7:    p_Multiplier = 4; "Sorry -- Z-machine version ", zcodeVersion, " not supported.";\r
+      5:        p_Multiplier = 4; ! p_Mask = $FFFFFFFC;\r
+      8:        p_Multiplier = 8; ! p_Mask = $FFFFFFF8;\r
+      'G':      "Sorry -- Glulx not supported.";\r
+      default:  "BUG: unexpected Z-Machine version number.";\r
+    }\r
+    informVersion = GetByte(a_Header+HDR_INFORMVERSION);\r
+    switch (informVersion) {\r
+      '5':      "Sorry -- Inform 5 not supported.";\r
+      '6':      informVersion = informVersion - '0';\r
+      default:  "BUG: unexpected Inform version number.";\r
+    }\r
+\r
+    ! Initialise variables and those addresses that we know\r
+\r
+    i_FirstUserObject = 0;\r
+    n_Actions = 0;\r
+    n_ArrayNames = 0;\r
+    n_AttrNames = 48;\r
+    n_Classes = 0;\r
+    n_Objects = 0;\r
+    n_Opcodes = 256 + 32;               ! Standard + Extended\r
+    n_PropNames = 0;\r
+    n_Rooms = 0;\r
+    n_Doors = 0;\r
+    n_Routines = 0;\r
+    n_Strings = 0;\r
+    n_Verbs = 0;\r
+\r
+    a_LowStrings            = GetWord(a_Header+HDR_ABBREVIATIONS);\r
+    a_Abbrevs               = a_LowStrings + 64;\r
+    a_GameAlpha             = GetWord(a_Header+HDR_ALPHABET);\r
+    if (a_GameAlpha) a_LookupAlpha = theGame + a_GameAlpha;\r
+    else             a_LookupAlpha = a_LocalAlpha;\r
+    if (a_HeaderExtn)\r
+        a_GameUnicode       = GetWord(a_HeaderExtn+HDREXTN_UNICODE);\r
+    else\r
+        a_GameUnicode       = 0;\r
+    if (a_GameUnicode) a_LookupUnicode = theGame + a_GameUnicode;\r
+    else               a_LookupUnicode = a_LocalUnicode;\r
+    a_CommonPropDefaults    = GetWord(a_Header+HDR_OBJECTS);\r
+    a_Objects               = a_CommonPropDefaults + 126;\r
+    a_CommonProps           = GetWord(a_Objects+12);\r
+    a_ClassToObject         = 0;\r
+    a_PropNames             = 0;\r
+    a_AttrNames             = 0;\r
+    a_ActionNames           = 0;\r
+    a_ArrayNames            = 0;\r
+    a_IndivProps            = 0;\r
+    a_Globals               = GetWord(a_Header+HDR_GLOBALS);\r
+    a_Arrays                = a_Globals + 480;\r
+    a_TermChars             = GetWord(a_Header+HDR_TERMCHARS);\r
+\r
+    a_StaticMemory          = GetWord(a_Header+HDR_STATICMEMORY);\r
+    a_GrammarPointers       = a_StaticMemory;\r
+    a_Grammars              = GetWord(a_GrammarPointers);\r
+    a_Actions               = 0;\r
+    a_PreActions            = 0;\r
+    a_Prepositions          = 0;\r
+    a_Dictionary            = GetWord(a_Header+HDR_DICTIONARY);\r
+\r
+    a_HighMemory            = GetWord(a_Header+HDR_HIGHMEMORY);\r
+    a_Routines              = a_HighMemory;\r
+    p_Routines              = A_To_P(a_Routines);\r
+\r
+    p_TopOfGame             = GetWord(a_Header+HDR_FILELENGTH);\r
+    a_TopOfGame             = P_To_A(p_TopOfGame);\r
+    a_TopOfRoutines         = 0;\r
+    a_Strings               = a_TopOfGame;\r
+    p_Strings               = p_TopOfGame;\r
+\r
+    ! Process the objects.\r
+\r
+    for (a=a_Objects : a<a_CommonProps : a=a+14) {\r
+        n_Objects++;                    ! Object's number\r
+        if (n_Objects%100 == 0) { print "*"; glk_select_poll(gg_event); }\r
+        b = GetWord(a+12);              ! Object's property table\r
+        c = GetByte(b++);               ! #words of shortname\r
+        if (CompareStrings("(LibraryMessages)", Zname, n_Objects, n_Objects+1))\r
+            i_FirstUserObject = n_Objects;\r
+        b = DoProperties(b+c+c);        ! First property block\r
+        if (GetWord(a+6) == 1 || n_Objects <= 4)        ! It's a Class\r
+            b = DoProperties(b+6);      ! Inheritance property block\r
+    }\r
+\r
+    ! Process the classes-to-objects table, which starts after the Objects.\r
+\r
+    a_ClassToObject = b;\r
+    for (a=GetWord(b),b=b+2 : a : a=GetWord(b),b=b+2) n_Classes++;\r
+\r
+    ! Process the names of Properties, Attributes, Actions and Arrays,\r
+    ! which start after the classes-to-objects table.\r
+\r
+    a_PropNames = b;\r
+    n_PropNames = GetWord(b);           ! Actually, numNames + 1\r
+    a_AttrNames = a_PropNames + (n_PropNames * 2);\r
+    a_ActionNames = a_AttrNames + (n_AttrNames * 2);\r
+\r
+    ! Process the Grammars (Version 2 only).\r
+\r
+    for (a=a_GrammarPointers : a<a_Grammars : a=a+2,n_Verbs++) {\r
+        b = GetWord(a);                 ! address of grammar\r
+        c = GetByte(b++);               ! number of grammar lines\r
+        while (c--) {\r
+            b = b + 2;                  ! skip action number\r
+            while (GetByte(b++) ~= 15)\r
+                b = b + 2;              ! skip rest of token\r
+        }\r
+    }\r
+    a_Actions = b;\r
+    while (GetWord(b) && b < a_Dictionary) { b = b + 2; n_Actions++; }\r
+    a_PreActions = b;\r
+\r
+    ! Process the dictionary.\r
+\r
+    n_DictEntries = GetWord(a_Dictionary + GetByte(a_Dictionary) + 2);\r
+\r
+    ! This next bit is not true, since we haven't counted the Fake Actions.\r
+    ! At the moment, they are included with the Array Names.\r
+\r
+    a_ArrayNames = a_ActionNames + (n_Actions * 2);\r
+    n_ArrayNames = (a_IndivProps - a_ArrayNames) / 2;\r
+\r
+    ! Process the Z-code.\r
+\r
+    a = a_Routines;\r
+    do {\r
+        while (GetByte(a) > MAX_LOCALS) a = P_RoundUp(a+1);\r
+        if (n_Routines >= MAX_ROUTINES-1) "Too many routines: increase MAX_ROUTINES and recompile.";\r
+        theRoutines-->n_Routines++ = A_To_P(a);\r
+        a = P_RoundUp(DumpRoutine(a));\r
+        if (n_Routines%100 == 0) { print "*"; glk_select_poll(gg_event); }\r
+    } until (a > a_TopOfRoutines);\r
+\r
+    ! This bit is dubious -- there may be another routine, so we\r
+    ! look for a small number of local variables (strings are\r
+    ! unlikely to start with these values).\r
+\r
+    if (GetByte(a) < 4) {               ! MAX_LOCALS is too big to be safe here\r
+        if (n_Routines >= MAX_ROUTINES-1) "Too many routines: increase MAX_ROUTINES and recompile.";\r
+        theRoutines-->n_Routines++ = A_To_P(a);\r
+        a = P_RoundUp(DumpRoutine(a));\r
+    }\r
+    a_TopOfRoutines = a;\r
+\r
+    ! The Strings start right after the Routines.\r
+\r
+    a_strings = a_TopOfRoutines;\r
+    p_Strings = A_To_P(a_Strings);\r
+    for (a=a_Strings : a<a_TopOfGame : a=P_RoundUp(a)) {\r
+        if (n_Strings >= MAX_STRINGS-1) "Too many strings: increase MAX_STRINGS and recompile.";\r
+        theStrings-->n_Strings++ = A_To_P(a);\r
+        do { c = GetWord(a); a = a + 2; } until (c & BIT15);\r
+        if (n_Strings%100 == 0) { print "*"; glk_select_poll(gg_event); }\r
+    }\r
+\r
+    rfalse;                             ! Successful -- OK to continue.\r
+];\r
+\r
+Constant MAX_STRINGBUF 50;\r
+Array stringBuf1 -> MAX_STRINGBUF;\r
+Array stringBuf2 -> MAX_STRINGBUF;\r
+\r
+[ CompareStrings str printrule val1 val2\r
+    currStream tempStream len1 len2 i j;\r
+\r
+    currStream = glk_stream_get_current();\r
+\r
+    tempStream = glk_stream_open_memory(stringBuf1, MAX_STRINGBUF, filemode_Write, ANY_OLD_ROCK);\r
+    glk_stream_set_current(tempStream);\r
+        print (string) str;\r
+    glk_stream_close(tempStream, gg_arguments);\r
+    len1 = gg_arguments-->1;\r
+\r
+    for (i=val1 : i<val2 : i++) {\r
+        tempStream = glk_stream_open_memory(stringBuf2, MAX_STRINGBUF, filemode_Write, ANY_OLD_ROCK);\r
+        glk_stream_set_current(tempStream);\r
+            printrule(i);\r
+        glk_stream_close(tempStream, gg_arguments);\r
+        len2 = gg_arguments-->1;\r
+\r
+        glk_stream_set_current(currStream);\r
+        if (len1 ~= len2) continue;     ! Try next value\r
+        for (j=0 : j<len1 : j++) if (stringBuf1->j ~= stringBuf2->j) jump tryNext;\r
+        return i;                       ! Found a match\r
+      .TryNext;\r
+    }\r
+    rfalse;                             ! Failed to match any.\r
+];\r
+\r
+! =================================================================================================\r
+!   Dump the game in hex.\r
+\r
+[ DumpData\r
+    i j k m;\r
+    if (~~currentState) print_ret (string) NO_GAME_OPEN;\r
+\r
+    font off;\r
+    new_line;\r
+    i = Tokens-->1; if (i == -1) i = 0; else i = (i / $10) * $10;\r
+    j = Tokens-->2; if (j == -1) j = i;\r
+    if (j < i) j = i + j;\r
+    j = ((j + $10) / $10) * $10;\r
+    for ( : i<j : i=i+$10) {\r
+        print (hex5) i, ": ";\r
+        for (k=i : k<i+16 : k=k+4) {\r
+            for (m=0 : m<4 : m++)\r
+                if (k+m < a_TopOfGame) print (hchar) GetByte(k+m); else print "xx";\r
+            print " ";\r
+            }\r
+        new_line;\r
+        }\r
+    font on;\r
+];\r
+\r
+! =================================================================================================\r
+!   Show all low-memory strings.\r
+\r
+[ DumpLowStrings\r
+    a c;\r
+    if (~~currentState) print_ret (string) NO_GAME_OPEN;\r
+\r
+    font off;\r
+    new_line;\r
+    for (a=a_StringPool : a<a_LowStrings : ) {\r
+        print (hex5) a, ": ~", (Zaddress) a, "~^";\r
+        do { c = GetWord(a); a = a + 2; } until (c & BIT15);\r
+    }\r
+    font on;\r
+];\r
+\r
+! =================================================================================================\r
+!   Show all high-memory strings.\r
+\r
+[ DumpStrings\r
+    i a;\r
+    if (~~currentState) print_ret (string) NO_GAME_OPEN;\r
+\r
+    font off;\r
+    new_line;\r
+    for (i=0 : i<n_Strings : i++) {\r
+        a = P_To_A(theStrings-->i);\r
+        print (hex5) a, ": ", (Zaddress) a, "^";\r
+        if (~~modePause) glk_select_poll(gg_event);\r
+        }\r
+    font on;\r
+];\r
+\r
+! =================================================================================================\r
+!   Show Strings embedded in @print and @print_ret statements.\r
+\r
+[ DumpEmbedded\r
+    i;\r
+    if (~~currentState) print_ret (string) NO_GAME_OPEN;\r
+\r
+    currentState = STATE_EMBED;\r
+    font off;\r
+    new_line;\r
+    for (i=0 : i<n_Routines : i++) {\r
+        DumpRoutine(P_To_A(theRoutines-->i));\r
+        if (~~modePause) glk_select_poll(gg_event);\r
+    }\r
+    font on;\r
+    currentState = STATE_DUMP;\r
+];\r
+\r
+! =================================================================================================\r
+!   Show the dictionary.\r
+\r
+[ DumpVocab\r
+    a n x y;\r
+    if (~~currentState) print_ret (string) NO_GAME_OPEN;\r
+\r
+    font off;\r
+    new_line;\r
+    for (a=a_Dictionary+GetByte(a_Dictionary)+4,n=n_DictEntries : n-- : a=a+9) {\r
+        if (GetByte(a+6) & BIT00)       ! Is this a verb?\r
+            stringOptions = stringOptions | STR_UPPERCASE;\r
+        x = Zaddress(a);\r
+        stringOptions = stringOptions & ~STR_UPPERCASE;\r
+        if (++y == 6) { new_line; y = 0; }\r
+        else           spaces 12-x;\r
+    }\r
+    new_line;\r
+    font on;\r
+];\r
+\r
+! =================================================================================================\r
+!   Show all verb grammars.\r
+\r
+Array DoneVerb -> 256;\r
+Array ActionsUsed --> 1000;\r
+\r
+[ DumpGrammar\r
+    a b n m v tt td n_ActionsUsed;\r
+    if (~~currentState) print_ret (string) NO_GAME_OPEN;\r
+\r
+    font off;\r
+    new_line;\r
+    for (n=0 : n<256 : n++) DoneVerb->n = false;\r
+\r
+    for (a=a_Dictionary+GetByte(a_Dictionary)+4,n=n_DictEntries : n-- : a=a+9) {\r
+        if (GetByte(a+6) & BIT00 == 0) continue;    ! Not a verb\r
+        v = GetByte(a+7);               ! Verb number (from 255 downwards).\r
+        if (DoneVerb->v) continue;      ! Already processed.\r
+        DoneVerb->v = true;\r
+        print "Verb '", (Zaddress) a, "'";\r
+        for (b=a+9,m=n-1 : m-- : b=b+9)\r
+            if (GetByte(b+7) == v) print " '", (Zaddress) b, "'";\r
+        b = GetWord(a_GrammarPointers + (255-v)*2);\r
+        m = GetByte(b++);               ! Number of grammar lines.\r
+        n_ActionsUsed = 0;              ! Action routines for this verb.\r
+        while (m--) {\r
+            v = GetWord(b); b = b + 2;  ! Action number\r
+            print "^    *";\r
+            for (tt=GetByte(b++) : tt~=15 : tt=GetByte(b++)) {\r
+                td = GetWord(b); b = b + 2;\r
+                if (tt & BIT04) print "/"; else print " ";\r
+                switch (tt & BITS00_03) {\r
+                  1:    switch (td) {\r
+                          0: print "noun";\r
+                          1: print "held";\r
+                          2: print "multi";\r
+                          3: print "multiheld";\r
+                          4: print "multiexcept";\r
+                          5: print "multiinside";\r
+                          6: print "creature";\r
+                          7: print "number";\r
+                          8: print "special";\r
+                          9: print "topic";\r
+                          default: print "????";\r
+                        }\r
+                  2:    print "'", (Zaddress) td, "'";\r
+                  3:    print "noun=[; $", (hex5) P_to_A(td), " ]";\r
+                  4:    print (Zattribute) td;\r
+                  5:    print "scope=[; $", (hex5) P_to_A(td), " ]";\r
+                  6:    print "[; $", (hex5) P_to_A(td), " ]";\r
+                  default:\r
+                        print "????";\r
+                }\r
+            }\r
+            print " -> ", (Zaction) v & BITS00_09;\r
+            if (v & BIT10) print " reverse";\r
+            v = P_To_A(GetWord(a_Actions + (v & BITS00_09) * 2));\r
+            print "   ! [; $", (hex5) v, " ]";\r
+            if (modeExpand && ~~FoundByScan(v, ActionsUsed, n_ActionsUsed))\r
+                ActionsUsed-->n_ActionsUsed++ = v;\r
+        }\r
+        new_line; new_line;\r
+        if (modeExpand) for (m=0 : m<n_ActionsUsed : m++) {\r
+            print "       ";\r
+            DumpRoutine(ActionsUsed-->m);\r
+            new_line; new_line;\r
+        }\r
+        if (~~modePause) glk_select_poll(gg_event);\r
+    }\r
+    font on;\r
+];\r
+\r
+! =================================================================================================\r
+!   Show contents of the game's header.\r
+\r
+[ DumpHeader\r
+    x;\r
+    if (~~currentState) print_ret (string) NO_GAME_OPEN;\r
+\r
+    font off;\r
+    new_line;\r
+    DumpByte(a_Header+HDR_ZCODEVERSION);      print "Z-machine version^";\r
+    DumpByte(a_Header+HDR_TERPFLAGS);         print "Interpreter flags^";\r
+    DumpWord(a_Header+HDR_GAMERELEASE);       print "Game release^";\r
+    DumpByteAddr(a_Header+HDR_HIGHMEMORY);    print "High memory^";\r
+    DumpByteAddr(a_Header+HDR_INITIALPC);     print "Initial PC^";\r
+    DumpByteAddr(a_Header+HDR_DICTIONARY);    print "Dictionary^";\r
+    DumpByteAddr(a_Header+HDR_OBJECTS);       print "Objects^";\r
+    DumpByteAddr(a_Header+HDR_GLOBALS);       print "Global variables^";\r
+    DumpByteAddr(a_Header+HDR_STATICMEMORY);  print "Static memory^";\r
+    x = DumpWord(a_Header+HDR_GAMEFLAGS);     print "Game flags: ";\r
+        if (x & BIT15) print "BIT_F ";\r
+        if (x & BIT14) print "BIT_E ";\r
+        if (x & BIT13) print "BIT_D ";\r
+        if (x & BIT12) print "BIT_C ";\r
+        if (x & BIT11) print "BIT_B ";\r
+        if (x & BIT10) print "print_error ";\r
+        if (x & BIT09) print "BIT_9 ";\r
+        if (x & BIT08) print "menu ";\r
+        if (x & BIT07) print "sound ";\r
+        if (x & BIT06) print "colour ";\r
+        if (x & BIT05) print "mouse ";\r
+        if (x & BIT04) print "undo ";\r
+        if (x & BIT03) print "graphic ";\r
+        if (x & BIT02) print "BIT_2 ";\r
+        if (x & BIT01) print "fixed_pitch ";\r
+        if (x & BIT00) print "transcripting ";\r
+        new_line;\r
+    DumpWord(a_Header+HDR_GAMESERIAL);        print "Game serial: ";\r
+                                              DumpASCII(a_Header+HDR_GAMESERIAL,6); new_line;\r
+    DumpWord(a_Header+HDR_GAMESERIAL+2); new_line;\r
+    DumpWord(a_Header+HDR_GAMESERIAL+4); new_line;\r
+    DumpByteAddr(a_Header+HDR_ABBREVIATIONS); print "Abbreviations^";\r
+    DumpPackedAddr(a_Header+HDR_FILELENGTH);  print "Length^";\r
+    DumpWord(a_Header+HDR_CHECKSUM);          print "Checksum^";\r
+    DumpByte(a_Header+HDR_TERPNUMBER);        print "Interpreter number^";\r
+    DumpByte(a_Header+HDR_TERPVERSION);       print "Interpreter version^";\r
+    DumpByte(a_Header+HDR_SCREENHLINES);      print "Screen height (lines)^";\r
+    DumpByte(a_Header+HDR_SCREENWCHARS);      print "Screen width (chars)^";\r
+    DumpWord(a_Header+HDR_SCREENWUNITS);      print "Screen width (units)^";\r
+    DumpWord(a_Header+HDR_SCREENHUNITS);      print "Screen height (units)^";\r
+    DumpByte(a_Header+HDR_FONTWUNITS);        print "Font width (units)^";\r
+    DumpByte(a_Header+HDR_FONTHUNITS);        print "Font height (units)^";\r
+    DumpWord(a_Header+HDR_ROUTINEOFFSET);     print "V6: Routines offset / 8^";\r
+    DumpWord(a_Header+HDR_STRINGOFFSET);      print "V6: Strings offset / 8^";\r
+    DumpByte(a_Header+HDR_BGCOLOUR);          print "Background colour^";\r
+    DumpByte(a_Header+HDR_FGCOLOUR);          print "Foreground colour^";\r
+    DumpByteAddr(a_Header+HDR_TERMCHARS);     print "Terminating chars^";\r
+    DumpWord(a_Header+HDR_PIXELSTO3);         print "V6: Pixels to stream 3^";\r
+    DumpWord(a_Header+HDR_TERPSTANDARD);      print "Interpreter conformance^";\r
+    DumpByteAddr(a_Header+HDR_ALPHABET);      print "Alphabet^";\r
+    DumpByteAddr(a_Header+HDR_EXTENSION);     print "Header extension^";\r
+    DumpWord(a_Header+HDR_UNUSED);            print "-^";\r
+    DumpWord(a_Header+HDR_UNUSED+2);          print "-^";\r
+    DumpWord(a_Header+HDR_INFORMVERSION);     print "Inform version: ";\r
+                                              DumpASCII(a_Header+HDR_INFORMVERSION,4); new_line;\r
+    DumpWord(a_Header+HDR_INFORMVERSION+2); new_line;\r
+    new_line;\r
+\r
+    if (a_HeaderExtn) {\r
+        DumpWord(a_HeaderExtn+HDREXTN_SIZE);        print "Header extension size^";\r
+        DumpWord(a_HeaderExtn+HDREXTN_MOUSEX);      print "Mouse X coordinates^";\r
+        DumpWord(a_HeaderExtn+HDREXTN_MOUSEY);      print "Mouse Y coordinates^";\r
+        DumpByteAddr(a_HeaderExtn+HDREXTN_UNICODE); print "Unicode^";\r
+    }\r
+    font on;\r
+];\r
+\r
+[ DumpByte a\r
+    val; val = GetByte(a);\r
+    print (hex5) a, ":   ", (hex2) val, "        ";\r
+    return val;\r
+];\r
+\r
+[ DumpWord a\r
+    val; val = GetWord(a);\r
+    print (hex5) a, ": ", (hex4) val, "        ";\r
+    return val;\r
+];\r
+\r
+[ DumpByteAddr a\r
+    val; val = GetWord(a);\r
+    print (hex5) a, ": ", (hex4) val, "b ", (hex5) val, " ";\r
+    return val;\r
+];\r
+\r
+[ DumpPackedAddr a\r
+    val; val = GetWord(a);\r
+    print (hex5) a, ": ", (hex4) val, "p ";\r
+    val = P_To_A(GetWord(a));\r
+    print (hex5) val, " ";\r
+    return val;\r
+];\r
+\r
+[ DumpASCII a n\r
+    i;\r
+    print "~"; for (i=0 : i<n : i++) print (char) GetByte(a+i); print "~";\r
+];\r
+\r
+! =================================================================================================\r
+!   Show the Z-Machine memory map.\r
+\r
+[ DumpMemoryMap;\r
+    if (~~currentState) print_ret (string) NO_GAME_OPEN;\r
+\r
+    font off;\r
+    new_line;\r
+    print "Header            ", (hex5) a_Header, "^";\r
+    print "String pool       ", (hex5) a_StringPool, "^";\r
+    print "32 Low strings    ", (hex5) a_LowStrings, "^";\r
+    print "64 Abbreviations  ", (hex5) a_Abbrevs, "^";\r
+    print "Header extension  ", (hex5) a_HeaderExtn, "^";\r
+    print "Alphabet table    ", (hex5) a_GameAlpha, "^";\r
+    print "Unicode table     ", (hex5) a_GameUnicode, "^";\r
+    print "Property defaults ", (hex5) a_CommonPropDefaults, "^";\r
+    print "Objects           ", (hex5) a_Objects, "^";\r
+    print "Common properties ", (hex5) a_CommonProps, "^";\r
+    print "Class-To-Object   ", (hex5) a_ClassToObject, "^";\r
+    print "Property names    ", (hex5) a_PropNames, "^";\r
+    print "Attribute names   ", (hex5) a_AttrNames, "^";\r
+    print "Action names      ", (hex5) a_ActionNames, "^";\r
+    print "Array names       ", (hex5) a_ArrayNames, "^";\r
+    print "Individual props  ", (hex5) a_IndivProps, "^";\r
+    print "Global variables  ", (hex5) a_Globals, "^";\r
+    print "Arrays            ", (hex5) a_Arrays, "^";\r
+    print "Terminating Chars ", (hex5) a_TermChars, "^";\r
+    new_line;\r
+\r
+    print "Static Memory     ", (hex5) a_StaticMemory, "^";\r
+    print "Grammar addresses ", (hex5) a_GrammarPointers, "^";\r
+    print "Grammars          ", (hex5) a_Grammars, "^";\r
+    print "Actions           ", (hex5) a_Actions, "^";\r
+    print "Parse routines    ", (hex5) a_PreActions, "^";\r
+    print "Prepositions      ", (hex5) a_Prepositions, "^";\r
+    print "Dictionary        ", (hex5) a_Dictionary, "^";\r
+    new_line;\r
+\r
+    print "High Memory       ", (hex5) a_HighMemory, "^";\r
+    print "Routines          ", (hex5) a_Routines, "^";\r
+    print "Strings           ", (hex5) a_Strings, "^";\r
+    print "Top of the game   ", (hex5) a_TopOfGame, "^";\r
+    font on;\r
+];\r
+\r
+! =================================================================================================\r
+! Show all objects, optionally expanding Routines.\r
+\r
+[ DumpObjects\r
+    a b c o p;\r
+    o = 0;\r
+    if (~~currentState) print_ret (string) NO_GAME_OPEN;\r
+\r
+    font off;\r
+    new_line;\r
+    for (a=a_Objects : a<a_CommonProps : a=a+14) {\r
+        o++;                            ! Object's number\r
+        if (o < i_FirstUserObject) continue;    ! Skip early objects\r
+        p = GetWord(a+6);               ! Object's parent\r
+        b = GetWord(a+12);              ! Object's property table\r
+        if (p == 1 || o <= 4) {         ! It's a Class\r
+            print "Class   ~", (Zaddress) b+1, "~ with^";\r
+            c = GetByte(b++);           ! #words of class's shortname\r
+            b = DoProperties(b+c+c);    ! Class's first property block\r
+            print "        ! Following values are inherited by instances of the class^";\r
+            DoProperties(b+6);          ! Inheritance property block\r
+            DoAttributes(b);            ! Inheritance attribute bytes\r
+        }\r
+        else {                          ! It's an Object\r
+            print "Object  ", (Zobject) o, " ~", (Zaddress) b+1, "~";\r
+            if (p > 1) print " ", (Zobject) p;\r
+            print " with^";\r
+            c = GetByte(b++);           ! #words of object's shortname\r
+            DoProperties(b+c+c);        ! Object's first property block\r
+            DoAttributes(a);            ! Object's attribute bytes\r
+        }\r
+        new_line;\r
+        if (~~modePause) glk_select_poll(gg_event);\r
+    }\r
+    font on;\r
+];\r
+\r
+[ DoProperties a\r
+    b p n x;\r
+    for (x=GetByte(a++) : x : x=GetByte(a++)) {\r
+        p = x & BITS00_05;              ! Common property number\r
+        if (x & BIT07) {                ! Two size-and-number bytes\r
+            n = GetByte(a++) & BITS00_05;\r
+            if (n == 0) n = 64;\r
+        }\r
+        else                            ! One size-and-number byte\r
+            if (x & BIT06) n = 2;       ! Two bytes of data\r
+            else           n = 1;       ! One byte of data\r
+        if (p ~= 3) {\r
+            if (currentState == STATE_DUMP)\r
+                DoPropNameAndValue(a, p, n);\r
+        }\r
+        else {                          ! Individual properties\r
+            b = GetWord(a);\r
+            if (a_IndivProps == 0) a_IndivProps = b;\r
+            for (x=GetWord(b),b=b+2 : x : x=GetWord(b),b=b+2) {\r
+                p = x & BITS00_14;      ! Individual property number\r
+                n = GetByte(b++);\r
+                if (currentState == STATE_DUMP) DoPropNameAndValue(b, p, n);\r
+                b = b + n;\r
+            }\r
+        }\r
+        a = a + n;\r
+    }\r
+    return a;\r
+];\r
+\r
+[ DoPropNameAndValue a p n\r
+    i j x;\r
+    print "        ", (Zproperty) p;\r
+    if (n & BIT00)                      ! odd number of bytes\r
+        for (i=0 : i<n : i++) print " ", GetByte(a++);\r
+    else                                ! even number of bytes\r
+        for (i=0,x=GetWord(a) : i<n : i=i+2,x=GetWord(a+i)) switch (p) {\r
+          1:                            ! name\r
+            if (x >= a_Dictionary && x < a_HighMemory) {\r
+                stringOptions = stringOptions | STR_NO_QUOTES;\r
+                print " '";\r
+                if (Zaddress(x) == 1) print "//";\r
+                print "'";\r
+                stringOptions = stringOptions & ~STR_NO_QUOTES;\r
+            }\r
+            else\r
+                print " ?", (hex4) x, "?";  ! not a dictionary word; maybe a character constant?\r
+          2:                            ! ofclass\r
+            print " ", (Zname) x;\r
+          3:                            ! metaclass (individual properties)\r
+            "BUG: tried to print property 3.";\r
+          default:                      ! other properties\r
+            switch (x) {\r
+              $FFFF:\r
+                print " -1";\r
+              0 to 20:                  ! probably not an object...\r
+                print " ", x;\r
+              default:\r
+                if (x <= n_Objects) print " ", (Zobject) x;\r
+                else {\r
+                    if (x >= p_Routines && x < p_Strings &&\r
+                        FoundByChop(x, theRoutines, n_Routines) && i-j < 3) {\r
+                        j = i;\r
+                        if (modeExpand) DumpRoutine(P_To_A(x));\r
+                        else            print " [; $", (hex5) P_To_A(x), " ]";\r
+                    }\r
+                    else\r
+                        if (x >= p_Strings && x < p_TopOfGame &&\r
+                            FoundByChop(x, theStrings, n_Strings) && i-j < 3) {\r
+                            j = i;\r
+                            if (true) print " ~", (Zstring) x, "~";\r
+                            !else       print " ~$", (hex5) P_To_A(x), "~";\r
+                        }\r
+                        else\r
+                            print " ", x;\r
+\r
+                }   ! end of not-an-object\r
+            }   ! end of switch(x)\r
+        }   ! end of switch(p)\r
+    print ",^";\r
+];\r
+\r
+[ FoundByChop x a l                     ! Locate value in sorted list by binary chop.\r
+    i p q;\r
+    p = 0; q = l - 1 ;\r
+    do {\r
+        i = p + (q-p)/2;                ! mid point\r
+        if (x == a-->i) return i+1;     ! found it!\r
+        if (x > a-->i) p = i + 1;       ! above the mid point\r
+        else           q = i - 1;       ! below the mid point\r
+    } until (p>q);\r
+    rfalse;\r
+];\r
+\r
+[ FoundByScan x a l                     ! Locate value in unsorted list by sequential scan.\r
+    i;\r
+    for (i=0 : i<l : i++)\r
+        if (x == a-->i) return i+1;     ! found it!\r
+    rfalse;\r
+];\r
+\r
+[ DoAttributes a\r
+    i;\r
+    if (GetWord(a) | GetWord(a+2) | GetWord(a+4)) print "  has  ";\r
+    for (i=0 : i<n_AttrNames : i++)\r
+        if (TestAttr(a, i)) print " ", (Zattribute) i;\r
+    print ";^";\r
+];\r
+\r
+[ TestAttr a q;\r
+    if (GetByte(a + q/8) & Bit-->(7 - q%8)) rtrue;\r
+    rfalse;\r
+];\r
+\r
+! =================================================================================================\r
+! Create XML markup which could be imported into the Dia diagram tool\r
+! (http://www.lysator.liu.se/~alla/dia), giving an editable map of the game.\r
+\r
+Global   CantGoProp;\r
+Global   DoorToProp;\r
+Global   xmlID;\r
+Global   mapSize;\r
+\r
+Constant GRID_SIZE  050;                ! Dia snap-to grid (all x100). Rooms are twice this size.\r
+Constant LINE_WIDTH 003;                ! For rooms and connections.\r
+Constant TEXT_OFFSET_X 010;             ! From top-left of room square\r
+Constant TEXT_OFFSET_Y 022;\r
+Constant TEXT_NAME "Verdana";\r
+Constant TEXT_SIZE 020;\r
+\r
+Constant ONE_SIDED_DOOR  20;            ! Only one link to this door.\r
+Constant UNKNOWN_ROOM    21;            ! Link to a 'room' not in the table.\r
+Constant LINK_IS_ROUTINE 22;            ! XXX_to is a property routine.\r
+\r
+[ DumpRooms\r
+    a b c o p i j n_exits x;\r
+    if (~~currentState) print_ret (string) NO_GAME_OPEN;\r
+\r
+    ! Calculate the map square necessary to display all objects.\r
+\r
+    switch (n_objects) {\r
+      0 to 99:      mapSize = 10;\r
+      100 to 399:   mapSize = 20;\r
+      400 to 899:   mapSize = 30;\r
+      900 to 1599:  mapSize = 40;\r
+      default:      mapsize = 50;\r
+    }\r
+\r
+    ! Find the XXX_to property numbers, and the 'door' attribute number.\r
+\r
+    for (i=0 : i<MAX_DIRPROPS : i++) {\r
+        DirPropNums-->i  = CompareStrings(DirPropNames-->i, ZProperty, 1, n_PropNames);\r
+        for (j=0 : j<MAX_ROOMS : j++) (theExits-->i)-->j = 0;\r
+    }\r
+    CantGoProp = CompareStrings("cant_go", ZProperty, 1, n_PropNames);\r
+    DoorToProp = CompareStrings("door_to", ZProperty, 1, n_PropNames);\r
+\r
+    ! Identify the room and door objects, and store the exits.\r
+\r
+    n_Rooms = 0; n_Doors = 0;\r
+    for (a=a_Objects,o=1 : a<a_CommonProps : a=a+14,o++) {\r
+        n_exits = 0;\r
+        b = GetWord(a+12);              ! Object's property table\r
+        c = GetByte(b++);               ! #words of object's shortname\r
+        b = b + c + c;                  ! Object's first property block\r
+\r
+        for (c=GetByte(b++) : c : c=GetByte(b++)) {\r
+            p = c & BITS00_05;          ! Common property number\r
+            if (c & BIT07) {            ! Two size-and-number bytes\r
+                c = GetByte(b++) & BITS00_05;\r
+                if (c == 0) c = 64;\r
+            }\r
+            else                        ! One size-and-number byte\r
+                if (c & BIT06) c = 2;   ! Two bytes of data\r
+                else           c = 1;   ! One byte of data (should never happen)\r
+            ! b = start of property data, c = length of data\r
+            x = GetWord(b);             ! First word of property data\r
+            b = b + c;\r
+            if (p == DoorToProp) {\r
+                if (n_Doors == MAX_DOORS) "Too many doors: increase MAX_DOORS and recompile.";\r
+                theDoors-->n_Doors = o;\r
+                doorToRoom-->n_Doors = x;\r
+                n_Doors++;\r
+                continue;\r
+            }\r
+            for (i=0 : i<MAX_DIRPROPS : i++)\r
+                if (p == DirPropNums-->i) { ! Found an exit.\r
+                    if (++n_exits == 1) {   ! First exit - found a new room.\r
+                        if (n_Rooms == MAX_ROOMS) "Too many rooms: increase MAX_ROOMS and recompile.";\r
+                        theRooms-->n_Rooms = o;\r
+                    }\r
+                    if (x > 0 && x < p_Strings)\r
+                        (theExits-->i)-->n_Rooms = x;   ! room, door or routine\r
+                }\r
+            if (p == CantGoProp && n_exits == 0) {\r
+                if (n_Rooms == MAX_ROOMS) "Too many rooms: increase MAX_ROOMS and recompile.";\r
+                theRooms-->n_Rooms = o;\r
+                n_exits++;\r
+            }\r
+        }\r
+        if (n_exits) n_Rooms++;\r
+        if (~~modePause) glk_select_poll(gg_event);\r
+    }\r
+\r
+    ! Find doors and replace by direct room-to-room links.\r
+\r
+    for (a=0 : a<n_Rooms : a++) {\r
+        for (i=0 : i<MAX_DIRPROPS : i++) {\r
+            x = (theExits-->i)-->a;\r
+            if (x > 0 && x <= n_Objects) {  ! room or door\r
+                p = FoundByChop(x, theDoors, n_Doors);\r
+                if (~~p) continue;          ! room - ignore\r
+                p--;\r
+                p = doorToRoom-->p;         ! door's door_to prop\r
+                if (p <= n_Objects) {\r
+                    (theExits-->i)-->a = p; ! a room\r
+                    continue;\r
+                }\r
+\r
+                ! door_to must be a routine\r
+\r
+                for (b=a+1 : b<n_Rooms : b++) {\r
+                    n_exits = 0;\r
+                    for (j=0 : j<MAX_DIRPROPS : j++) {\r
+                        if ((theExits-->j)-->b == x) {\r
+                            (theExits-->j)-->b = theRooms-->a;\r
+                            n_exits++;\r
+                        }\r
+                    }\r
+                    if (n_exits) {\r
+                        for (j=0 : j<MAX_DIRPROPS : j++) {\r
+                            if ((theExits-->j)-->a == x) {\r
+                                (theExits-->j)-->a = theRooms-->b;\r
+                            }\r
+                        }\r
+                    }\r
+                }\r
+                if ((theExits-->i)-->a == x) {  ! couldn't find the door elsewhere\r
+                    for (j=0 : j<MAX_DIRPROPS : j++) {\r
+                        if ((theExits-->j)-->a == x) {\r
+                            (theExits-->j)-->a = ONE_SIDED_DOOR;\r
+                        }\r
+                    }\r
+                }\r
+            }\r
+        }\r
+    }\r
+\r
+!   for (a=0 : a<n_Rooms : a++) {\r
+!       o = theRooms-->a;\r
+!       print a, " ", (Zobject) o;\r
+!       for (i=0 : i<MAX_DIRPROPS : i++) {\r
+!           x = (theExits-->i)-->a;\r
+!           print  " ", (string)DirPropNames-->i, "=", x;\r
+!           p = FoundByChop(x, theRooms, n_Rooms);\r
+!           if (~~p) continue;\r
+!           p--;\r
+!           print " at pos ", p;\r
+!           for (j=0 : j<MAX_DIRPROPS : j++)\r
+!               if ((theExits-->j)-->p == o) print " matches ", j;\r
+!       }\r
+!       new_line;\r
+!   }\r
+\r
+    font off;\r
+    new_line;\r
+    xmlID = n_objects + 1;              ! IDs for generated XML things\r
+    XMLheader();\r
+\r
+    ! Generate the XML for the rooms\r
+\r
+    XMLroom(ONE_SIDED_DOOR, "INSPECTOR^One-sided^doors");\r
+    XMLroom(UNKNOWN_ROOM, "INSPECTOR^Links to^non-rooms");\r
+    XMLroom(LINK_IS_ROUTINE, "INSPECTOR^Links^are^routines");\r
+    for (a=0 : a<n_Rooms : a++) {\r
+        XMLroom(theRooms-->a);\r
+        if (~~modePause) glk_select_poll(gg_event);\r
+    }\r
+\r
+    ! Now, generate the connections between rooms.\r
+\r
+    for (a=0 : a<n_Rooms : a++) {\r
+        o = theRooms-->a;\r
+        for (i=0 : i<MAX_DIRPROPS : i++) {\r
+            x = (theExits-->i)-->a;\r
+            if (x == 0) continue;\r
+            if (x == ONE_SIDED_DOOR) { XMLconnection(o, i, ONE_SIDED_DOOR, 7); continue; }\r
+            if (x >= p_Routines) { XMLconnection(o, i, LINK_IS_ROUTINE, 7); continue; }\r
+            p = FoundByChop(x, theRooms, n_Rooms);\r
+            if (~~p) { XMLconnection(o, i, UNKNOWN_ROOM, 7); continue; }\r
+            p--;\r
+            n_exits = 0;\r
+            j = XOR(i, 1);              ! Symmetrical exit\r
+            if ((theExits-->j)-->p == o) {\r
+                n_exits++;\r
+                if (x > o) XMLconnection(o, i, x, j);\r
+            }\r
+            else {\r
+                for (j=0 : j<MAX_DIRPROPS : j++) {\r
+                    if ((theExits-->j)-->p == o) {\r
+                        n_exits++;\r
+                        if (x > o) XMLconnection(o, i, x, j);\r
+                    }\r
+                }\r
+            }\r
+            if (n_exits == 0) XMLconnection(o, i, x, MAX_DIRPROPS);\r
+\r
+        }\r
+        if (~~modePause) glk_select_poll(gg_event);\r
+    }\r
+\r
+    XMLfooter();\r
+    font on;\r
+];\r
+\r
+[ XMLheader;\r
+    "Save the lines BETWEEN the markers in YourFileName.xml as input to Dia^\r
+     [[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[^\r
+     <?xml version=~1.0~ encoding=~UTF-8~?>^\r
+     <dia:diagram xmlns:dia=~http://www.lysator.liu.se/@@126alla/dia/~>^\r
+         <dia:diagramdata>^\r
+            <dia:attribute name=~grid~><dia:composite type=~grid~>^\r
+            <dia:attribute name=~width_x~><dia:real val=~", (XY) GRID_SIZE, "~/></dia:attribute>^\r
+            <dia:attribute name=~width_y~><dia:real val=~", (XY) GRID_SIZE, "~/></dia:attribute>^\r
+            </dia:composite></dia:attribute>^\r
+         </dia:diagramdata>^\r
+     <dia:layer name=~Background~ visible=~true~>^";\r
+];\r
+\r
+[ XMLfooter;\r
+    "</dia:layer>^\r
+     </dia:diagram>^\r
+     ]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]^\r
+     End of input to Dia. Do not include the [[[[[[ and ]]]]]] marker lines";\r
+];\r
+\r
+[ XOR a b; return (a | b) & (~(a & b)); ];\r
+\r
+[ XY p; print p/100, (char) '.', (dec2) p%100; ];\r
+\r
+[ XMLroom o str\r
+    x y;\r
+    x = objX(o);\r
+    y = objY(o);\r
+    print "<dia:group>^\r
+        <dia:object type=~Geometric - Perfect Square~ version=~0~ id=~O", o, "~>^\r
+            <dia:attribute name=~border_width~><dia:real val=~", (XY) LINE_WIDTH, "~/></dia:attribute>^\r
+            <dia:attribute name=~elem_corner~><dia:point val=~", (XY) x, ",", (XY) y, "~/></dia:attribute>^\r
+            <dia:attribute name=~elem_width~><dia:real val=~", (XY) GRID_SIZE * 2, "~/></dia:attribute>^\r
+            <dia:attribute name=~elem_height~><dia:real val=~", (XY) GRID_SIZE * 2, "~/></dia:attribute>^\r
+        </dia:object>^\r
+        <dia:object type=~Standard - Text~ version=~0~ id=~O", xmlID++, "~>^\r
+            <dia:attribute name=~text~><dia:composite type=~text~>^\r
+                <dia:attribute name=~string~>^\r
+                    <dia:string>#";\r
+                    stringOptions = stringOptions | STR_MULTILINE;\r
+                    if (str) print (string) str;\r
+                    else     print (Zname) o;\r
+                    stringOptions = stringOptions & ~STR_MULTILINE;\r
+                "#</dia:string>^\r
+                </dia:attribute>^\r
+                <dia:attribute name=~font~>^\r
+                    <dia:font family=~sans~ style=~0~ name=~", (string) TEXT_NAME, "~/>^\r
+                </dia:attribute>^\r
+                <dia:attribute name=~height~><dia:real val=~", (XY) TEXT_SIZE, "~/></dia:attribute>^\r
+                <dia:attribute name=~pos~>^\r
+                    <dia:point val=~", (XY) x+TEXT_OFFSET_X, ",", (XY) y+TEXT_OFFSET_Y, "~/>^\r
+                </dia:attribute>^\r
+            </dia:composite></dia:attribute>^\r
+        </dia:object>^\r
+    </dia:group>^";\r
+];\r
+\r
+[ XMLconnection o1 d1 o2 d2\r
+    x1 x2 y1 y2;\r
+    if (o1 == o2) return;               ! ignore circular links.\r
+    x1 = objX(o1) + connectX->d1;\r
+    y1 = objY(o1) + connectY->d1;\r
+    x2 = objX(o2) + connectX->d2;\r
+    y2 = objY(o2) + connectY->d2;\r
+    print "<dia:object type=~Standard - Line~ version=~0~ id=~O", xmlID++, "~>^\r
+        <dia:attribute name=~line_width~><dia:real val=~", (XY) LINE_WIDTH, "~/></dia:attribute>^\r
+        <dia:attribute name=~conn_endpoints~>^\r
+            <dia:point val=~", (XY) x1, ",", (XY) y1, "~/>^\r
+            <dia:point val=~", (XY) x2, ",", (XY) y2, "~/>^\r
+        </dia:attribute>^\r
+        <dia:connections>^\r
+            <dia:connection handle=~0~ to=~O", o1, "~ connection=~", connectID->d1, "~/>^\r
+            <dia:connection handle=~1~ to=~O", o2, "~ connection=~", connectID->d2, "~/>^\r
+        </dia:connections>^";\r
+    if (connectArrow->d1)\r
+        print "<dia:attribute name=~start_arrow~><dia:enum val=~", connectArrow->d1, "~/></dia:attribute>^\r
+            <dia:attribute name=~start_arrow_length~><dia:real val=~0.15~/></dia:attribute>^\r
+            <dia:attribute name=~start_arrow_width~><dia:real val=~0.15~/></dia:attribute>^";\r
+    if (connectArrow->d2)\r
+        print "<dia:attribute name=~end_arrow~><dia:enum val=~", connectArrow->d2, "~/></dia:attribute>^\r
+            <dia:attribute name=~end_arrow_length~><dia:real val=~0.15~/></dia:attribute>^\r
+            <dia:attribute name=~end_arrow_width~><dia:real val=~0.15~/></dia:attribute>^";\r
+    "</dia:object>^";\r
+];\r
+\r
+[ objX o; return o%mapSize * (GRID_SIZE * 3); ];\r
+\r
+[ objY o; return o/mapSize * (GRID_SIZE * 3); ];\r
+\r
+ Array connectX ->\r
+    GRID_SIZE                           ! North\r
+    GRID_SIZE                           ! South\r
+    GRID_SIZE * 2                       ! East\r
+    0                                   ! West\r
+    GRID_SIZE * 2                       ! Northeast\r
+    0                                   ! Southwest\r
+    0                                   ! Northwest\r
+    GRID_SIZE * 2                       ! SouthEast\r
+    GRID_SIZE * 2                       ! Up   (use Northeast)\r
+    0                                   ! Down (use Southwest)\r
+    0                                   ! In   (use Northwest)\r
+    GRID_SIZE * 2                       ! Out  (use Southeast)\r
+    GRID_SIZE * 2;                      ! None (use Southeast)\r
+\r
+Array connectY ->\r
+    0                                   ! North\r
+    GRID_SIZE * 2                       ! South\r
+    GRID_SIZE                           ! East\r
+    GRID_SIZE                           ! West\r
+    0                                   ! Northeast\r
+    GRID_SIZE * 2                       ! Southwest\r
+    0                                   ! Northwest\r
+    GRID_SIZE * 2                       ! SouthEast\r
+    0                                   ! Up   (use Northeast)\r
+    GRID_SIZE * 2                       ! Down (use Southwest)\r
+    0                                   ! In   (use Northwest)\r
+    GRID_SIZE * 2                       ! Out  (use Southeast)\r
+    GRID_SIZE * 2;                      ! None (use Southeast)\r
+\r
+Array connectID ->                      ! dia connection IDs\r
+    7                                   ! North\r
+    6                                   ! South\r
+    5                                   ! East\r
+    3                                   ! West\r
+    4                                   ! Northeast\r
+    2                                   ! Southwest\r
+    0                                   ! Northwest\r
+    1                                   ! SouthEast\r
+    4                                   ! Up   (use Northeast)\r
+    2                                   ! Down (use Southwest)\r
+    0                                   ! In   (use Northwest)\r
+    1                                   ! Out  (use Southeast)\r
+    1;                                  ! None (use Northwest???)\r
+\r
+Array connectArrow ->                   ! dia arrowheads\r
+    0                                   ! North\r
+    0                                   ! South\r
+    0                                   ! East\r
+    0                                   ! West\r
+    0                                   ! Northeast\r
+    0                                   ! Southwest\r
+    0                                   ! Northwest\r
+    0                                   ! SouthEast\r
+    9                                   ! Up\r
+    8                                   ! Down\r
+    3                                   ! In\r
+    2                                   ! Out\r
+    21;                                 ! None (not an exit)\r
+\r
+! =================================================================================================\r
+!   Show all Z-code routines.\r
+\r
+[ DumpZcode\r
+    i;\r
+    if (~~currentState) print_ret (string) NO_GAME_OPEN;\r
+\r
+    font off;\r
+    new_line;\r
+    for (i=0 : i<n_Routines : i++) {\r
+        print "       ";\r
+        DumpRoutine(P_To_A(theRoutines-->i));\r
+        print ";^^";\r
+        if (~~modePause) glk_select_poll(gg_event);\r
+    }\r
+    font on;\r
+];\r
+\r
+Array OpcodeNames -->                   ! 256 Standard opcodes + 32 Extended opcodes\r
+\r
+    ! Long 2OP: small constant, small constant\r
+    nothing         "je"            "jl"            "jg"\r
+    "dec_chk"       "inc_chk"       "jin"           "test"\r
+    "or"            "and"           "test_attr"     "set_attr"\r
+    "clear_attr"    "store"         "insert_obj"    "loadw"\r
+    "loadb"         "get_prop"      "get_prop_addr" "get_next_prop"\r
+    "add"           "sub"           "mul"           "div"\r
+    "mod"           "call_2s"       "call_2n"       "set_colour"\r
+    "throw"         nothing         nothing         nothing\r
+\r
+    ! Long 2OP: small constant, variable\r
+    nothing         "je"            "jl"            "jg"\r
+    "dec_chk"       "inc_chk"       "jin"           "test"\r
+    "or"            "and"           "test_attr"     "set_attr"\r
+    "clear_attr"    "store"         "insert_obj"    "loadw"\r
+    "loadb"         "get_prop"      "get_prop_addr" "get_next_prop"\r
+    "add"           "sub"           "mul"           "div"\r
+    "mod"           "call_2s"       "call_2n"       "set_colour"\r
+    "throw"         nothing         nothing         nothing\r
+\r
+    ! Long 2OP: variable, small constant\r
+    nothing         "je"            "jl"            "jg"\r
+    "dec_chk"       "inc_chk"       "jin"           "test"\r
+    "or"            "and"           "test_attr"     "set_attr"\r
+    "clear_attr"    "store"         "insert_obj"    "loadw"\r
+    "loadb"         "get_prop"      "get_prop_addr" "get_next_prop"\r
+    "add"           "sub"           "mul"           "div"\r
+    "mod"           "call_2s"       "call_2n"       "set_colour"\r
+    "throw"         nothing         nothing         nothing\r
+\r
+    ! Long 2OP: variable, variable\r
+    nothing         "je"            "jl"            "jg"\r
+    "dec_chk"       "inc_chk"       "jin"           "test"\r
+    "or"            "and"           "test_attr"     "set_attr"\r
+    "clear_attr"    "store"         "insert_obj"    "loadw"\r
+    "loadb"         "get_prop"      "get_prop_addr" "get_next_prop"\r
+    "add"           "sub"           "mul"           "div"\r
+    "mod"           "call_2s"       "call_2n"       "set_colour"\r
+    "throw"         nothing         nothing         nothing\r
+\r
+    ! Short 1OP: large constant\r
+    "jz"            "get_sibling"   "get_child"     "get_parent"\r
+    "get_prop_len"  "inc"           "dec"           "print_addr"\r
+    "call_1s"       "remove_obj"    "print_obj"     "ret"\r
+    "jump"          "print_paddr"   "load"          "call_1n"\r
+\r
+    ! Short 1OP: small constant\r
+    "jz"            "get_sibling"   "get_child"     "get_parent"\r
+    "get_prop_len"  "inc"           "dec"           "print_addr"\r
+    "call_1s"       "remove_obj"    "print_obj"     "ret"\r
+    "jump"          "print_paddr"   "load"          "call_1n"\r
+\r
+    ! Short 1OP: variable\r
+    "jz"            "get_sibling"   "get_child"     "get_parent"\r
+    "get_prop_len"  "inc"           "dec"           "print_addr"\r
+    "call_1s"       "remove_obj"    "print_obj"     "ret"\r
+    "jump"          "print_paddr"   "load"          "call_1n"\r
+\r
+    ! Short 0OP\r
+    "rtrue"         "rfalse"        "print"         "print_ret"\r
+    "nop"           nothing         nothing         "restart"\r
+    "ret_popped"    "catch"         "quit"          "new_line"\r
+    nothing         "verify"        "extended"      "piracy"\r
+\r
+    ! Variable 2OP: Type byte follows\r
+    nothing         "je"            "jl"            "jg"\r
+    "dec_chk"       "inc_chk"       "jin"           "test"\r
+    "or"            "and"           "test_attr"     "set_attr"\r
+    "clear_attr"    "store"         "insert_obj"    "loadw"\r
+    "loadb"         "get_prop"      "get_prop_addr" "get_next_prop"\r
+    "add"           "sub"           "mul"           "div"\r
+    "mod"           "call_2s"       "call_2n"       "set_colour"\r
+    "throw"         nothing         nothing         nothing\r
+\r
+    ! Variable VAR: Type byte(s) follow\r
+    "call_vs"       "storew"        "storeb"        "put_prop"\r
+    "aread"         "print_char"    "print_num"     "random"\r
+    "push"          "pull"          "split_window"  "set_window"\r
+    "call_vs2"      "erase_window"  "erase_line"    "set_cursor"\r
+    "get_cursor"    "set_text_style" "buffer_mode"  "output_stream"\r
+    "input_stream"  "sound_effect"  "read_char"     "scan_table"\r
+    "not"           "call_vn"       "call_vn2"      "tokenise"\r
+    "encode_text"   "copy_table"    "print_table"   "check_arg_count"\r
+\r
+    !   Extended VAR: Type byte follows\r
+    "save"          "restore"       "log_shift"     "art_shift"\r
+    "set_font"      "draw_picture"  "picture_data"  "erase_picture"\r
+    "set_margins"   "save_undo"     "restore_undo"  "print_unicode"\r
+    "check_unicode" nothing         nothing         nothing\r
+    "move_window"   "window_size"   "window_style"  "get_wind_prop"\r
+    "scroll_window" "pop_stack"     "read_mouse"    "mouse_window"\r
+    "push_stack"    "put_wind_prop" "print_form"    "make_menu"\r
+    "picture_table" nothing         nothing         nothing;\r
+\r
+!   These flags are not part of the ZSpec.\r
+\r
+Constant OK = $$00000000;               ! Normal instruction\r
+Constant ST = $$10000000;               ! Has Store variable?\r
+Constant BR = $$01000000;               ! Has Branch offset?\r
+Constant PR = $$00100000;               ! Has Printable text?\r
+Constant TY = $$00010000;               ! Has Type byte(s)?\r
+Constant tStS   = $$0101;               ! Small constant, small constant\r
+Constant tStV   = $$0110;               ! Small constant, variable\r
+Constant tVtS   = $$1001;               ! Variable, small constant\r
+Constant tVtV   = $$1010;               ! Variable, variable\r
+Constant tLtX   = $$0011;               ! Large constant\r
+Constant tStX   = $$0111;               ! Small constant\r
+Constant tVtX   = $$1011;               ! Variable\r
+Constant tXtX   = $$1111;               ! Nothing\r
+Constant MA = $$00001111;               ! Mask for Type [Type count] bytes\r
+Constant ER = $$11111111;               ! Error\r
+\r
+Constant tXtXtXtX = $$11111111;\r
+\r
+Array OpcodeFlags ->                    ! 256 Standard opcodes + 32 Extended opcodes\r
+\r
+    ! Long 2OP: small constant, small constant\r
+    ER                                  ! $00 ILLEGAL\r
+    OK     +BR                 +tStS    ! $01 je\r
+    OK     +BR                 +tStS    ! $02 jl\r
+    OK     +BR                 +tStS    ! $03 jg\r
+    OK     +BR                 +tStS    ! $04 dec_chk\r
+    OK     +BR                 +tStS    ! $05 inc_chk\r
+    OK     +BR                 +tStS    ! $06 jin\r
+    OK     +BR                 +tStS    ! $07 test\r
+    OK +ST                     +tStS    ! $08 or\r
+    OK +ST                     +tStS    ! $09 and\r
+    OK     +BR                 +tStS    ! $0Atest_attr\r
+    OK                         +tStS    ! $0B set_attr\r
+    OK                         +tStS    ! $0C clear_attr\r
+    OK                         +tStS    ! $0D store\r
+    OK                         +tStS    ! $0E insert_obj\r
+    OK +ST                     +tStS    ! $0F loadw\r
+    OK +ST                     +tStS    ! $10 loadb\r
+    OK +ST                     +tStS    ! $11 get_prop\r
+    OK +ST                     +tStS    ! $12 get_prop_addr\r
+    OK +ST                     +tStS    ! $13 get_next_prop\r
+    OK +ST                     +tStS    ! $14 add\r
+    OK +ST                     +tStS    ! $15 sub\r
+    OK +ST                     +tStS    ! $16 mul\r
+    OK +ST                     +tStS    ! $17 div\r
+    OK +ST                     +tStS    ! $18 mod\r
+    OK +ST                     +tStS    ! $19 call_2s\r
+    OK                         +tStS    ! $1A call_2n\r
+    OK                         +tStS    ! $1B set_colour\r
+    OK                         +tStS    ! $1C throw\r
+    ER                                  ! $1D ILLEGAL\r
+    ER                                  ! $1E ILLEGAL\r
+    ER                                  ! $1F ILLEGAL\r
+\r
+    ! Long 2OP: small constant, variable\r
+    ER                                  ! $20 ILLEGAL\r
+    OK     +BR                 +tStV    ! $21 je\r
+    OK     +BR                 +tStV    ! $22 jl\r
+    OK     +BR                 +tStV    ! $23 jg\r
+    OK     +BR                 +tStV    ! $24 dec_chk\r
+    OK     +BR                 +tStV    ! $25 inc_chk\r
+    OK     +BR                 +tStV    ! $26 jin\r
+    OK     +BR                 +tStV    ! $27 test\r
+    OK +ST                     +tStV    ! $28 or\r
+    OK +ST                     +tStV    ! $29 and\r
+    OK     +BR                 +tStV    ! $2Atest_attr\r
+    OK                         +tStV    ! $2B set_attr\r
+    OK                         +tStV    ! $2C clear_attr\r
+    OK                         +tStV    ! $2D store\r
+    OK                         +tStV    ! $2E insert_obj\r
+    OK +ST                     +tStV    ! $2F loadw\r
+    OK +ST                     +tStV    ! $30 loadb\r
+    OK +ST                     +tStV    ! $31 get_prop\r
+    OK +ST                     +tStV    ! $32 get_prop_addr\r
+    OK +ST                     +tStV    ! $33 get_next_prop\r
+    OK +ST                     +tStV    ! $34 add\r
+    OK +ST                     +tStV    ! $35 sub\r
+    OK +ST                     +tStV    ! $36 mul\r
+    OK +ST                     +tStV    ! $37 div\r
+    OK +ST                     +tStV    ! $38 mod\r
+    OK +ST                     +tStV    ! $39 call_2s\r
+    OK                         +tStV    ! $3A call_2n\r
+    OK                         +tStV    ! $3B set_colour\r
+    OK                         +tStV    ! $3C throw\r
+    ER                                  ! $3D ILLEGAL\r
+    ER                                  ! $3E ILLEGAL\r
+    ER                                  ! $3F ILLEGAL\r
+\r
+    ! Long 2OP: variable, small constant\r
+    ER                                  ! $40 ILLEGAL\r
+    OK     +BR                 +tVtS    ! $41 je\r
+    OK     +BR                 +tVtS    ! $42 jl\r
+    OK     +BR                 +tVtS    ! $43 jg\r
+    OK     +BR                 +tVtS    ! $44 dec_chk\r
+    OK     +BR                 +tVtS    ! $45 inc_chk\r
+    OK     +BR                 +tVtS    ! $46 jin\r
+    OK     +BR                 +tVtS    ! $47 test\r
+    OK +ST                     +tVtS    ! $48 or\r
+    OK +ST                     +tVtS    ! $49 and\r
+    OK     +BR                 +tVtS    ! $4Atest_attr\r
+    OK                         +tVtS    ! $4B set_attr\r
+    OK                         +tVtS    ! $4C clear_attr\r
+    OK                         +tVtS    ! $4D store\r
+    OK                         +tVtS    ! $4E insert_obj\r
+    OK +ST                     +tVtS    ! $4F loadw\r
+    OK +ST                     +tVtS    ! $50 loadb\r
+    OK +ST                     +tVtS    ! $51 get_prop\r
+    OK +ST                     +tVtS    ! $52 get_prop_addr\r
+    OK +ST                     +tVtS    ! $53 get_next_prop\r
+    OK +ST                     +tVtS    ! $54 add\r
+    OK +ST                     +tVtS    ! $55 sub\r
+    OK +ST                     +tVtS    ! $56 mul\r
+    OK +ST                     +tVtS    ! $57 div\r
+    OK +ST                     +tVtS    ! $58 mod\r
+    OK +ST                     +tVtS    ! $59 call_2s\r
+    OK                         +tVtS    ! $5A call_2n\r
+    OK                         +tVtS    ! $5B set_colour\r
+    OK                         +tVtS    ! $5C throw\r
+    ER                                  ! $5D ILLEGAL\r
+    ER                                  ! $5E ILLEGAL\r
+    ER                                  ! $5F ILLEGAL\r
+\r
+    ! Long 2OP: variable, variable\r
+    ER                                  ! $60 ILLEGAL\r
+    OK     +BR                 +tVtV    ! $61 je\r
+    OK     +BR                 +tVtV    ! $62 jl\r
+    OK     +BR                 +tVtV    ! $63 jg\r
+    OK     +BR                 +tVtV    ! $64 dec_chk\r
+    OK     +BR                 +tVtV    ! $65 inc_chk\r
+    OK     +BR                 +tVtV    ! $66 jin\r
+    OK     +BR                 +tVtV    ! $67 test\r
+    OK +ST                     +tVtV    ! $68 or\r
+    OK +ST                     +tVtV    ! $69 and\r
+    OK     +BR                 +tVtV    ! $6Atest_attr\r
+    OK                         +tVtV    ! $6B set_attr\r
+    OK                         +tVtV    ! $6C clear_attr\r
+    OK                         +tVtV    ! $6D store\r
+    OK                         +tVtV    ! $6E insert_obj\r
+    OK +ST                     +tVtV    ! $6F loadw\r
+    OK +ST                     +tVtV    ! $70 loadb\r
+    OK +ST                     +tVtV    ! $71 get_prop\r
+    OK +ST                     +tVtV    ! $72 get_prop_addr\r
+    OK +ST                     +tVtV    ! $73 get_next_prop\r
+    OK +ST                     +tVtV    ! $74 add\r
+    OK +ST                     +tVtV    ! $75 sub\r
+    OK +ST                     +tVtV    ! $76 mul\r
+    OK +ST                     +tVtV    ! $77 div\r
+    OK +ST                     +tVtV    ! $78 mod\r
+    OK +ST                     +tVtV    ! $79 call_2s\r
+    OK                         +tVtV    ! $7A call_2n\r
+    OK                         +tVtV    ! $7B set_colour\r
+    OK                         +tVtV    ! $7C throw\r
+    ER                                  ! $7D ILLEGAL\r
+    ER                                  ! $7E ILLEGAL\r
+    ER                                  ! $7F ILLEGAL\r
+\r
+    ! Short 1OP: large constant\r
+    OK     +BR                 +tLtX    ! $80 jz\r
+    OK +ST +BR                 +tLtX    ! $81 get_sibling\r
+    OK +ST +BR                 +tLtX    ! $82 get_child\r
+    OK +ST                     +tLtX    ! $83 get_parent\r
+    OK +ST                     +tLtX    ! $84 get_prop_len\r
+    OK                         +tLtX    ! $85 inc\r
+    OK                         +tLtX    ! $86 dec\r
+    OK                         +tLtX    ! $87 print_addr\r
+    OK +ST                     +tLtX    ! $88 call_1s\r
+    OK                         +tLtX    ! $89 remove_obj\r
+    OK                         +tLtX    ! $8A print_obj\r
+    OK                         +tLtX    ! $8B ret\r
+    OK                         +tLtX    ! $8C jump\r
+    OK                         +tLtX    ! $8D print_paddr\r
+    OK +ST                     +tLtX    ! $8E load\r
+    OK                         +tLtX    ! $8F call_1n\r
+\r
+    ! Short 1OP: small constant\r
+    OK     +BR                 +tStX    ! $90 jz\r
+    OK +ST +BR                 +tStX    ! $91 get_sibling\r
+    OK +ST +BR                 +tStX    ! $92 get_child\r
+    OK +ST                     +tStX    ! $93 get_parent\r
+    OK +ST                     +tStX    ! $94 get_prop_len\r
+    OK                         +tStX    ! $95 inc\r
+    OK                         +tStX    ! $96 dec\r
+    OK                         +tStX    ! $97 print_addr\r
+    OK +ST                     +tStX    ! $98 call_1s\r
+    OK                         +tStX    ! $99 remove_obj\r
+    OK                         +tStX    ! $9A print_obj\r
+    OK                         +tStX    ! $9B ret\r
+    OK                         +tStX    ! $9C jump\r
+    OK                         +tStX    ! $9D print_paddr\r
+    OK +ST                     +tStX    ! $9E load\r
+    OK                         +tStX    ! $9F call_1n\r
+\r
+    ! Short 1OP: variable\r
+    OK     +BR                 +tVtX    ! $A0 jz\r
+    OK +ST +BR                 +tVtX    ! $A1 get_sibling\r
+    OK +ST +BR                 +tVtX    ! $A2 get_child\r
+    OK +ST                     +tVtX    ! $A3 get_parent\r
+    OK +ST                     +tVtX    ! $A4 get_prop_len\r
+    OK                         +tVtX    ! $A5 inc\r
+    OK                         +tVtX    ! $A6 dec\r
+    OK                         +tVtX    ! $A7 print_addr\r
+    OK +ST                     +tVtX    ! $A8 call_1s\r
+    OK                         +tVtX    ! $A9 remove_obj\r
+    OK                         +tVtX    ! $AA print_obj\r
+    OK                         +tVtX    ! $AB ret\r
+    OK                         +tVtX    ! $AC jump\r
+    OK                         +tVtX    ! $AD print_paddr\r
+    OK +ST                     +tVtX    ! $AE load\r
+    OK                         +tVtX    ! $AF call_1n\r
+\r
+    ! Short 0OP\r
+    OK                         +tXtX    ! $B0 rtrue\r
+    OK                         +tXtX    ! $B1 rfalse\r
+    OK         +PR             +tXtX    ! $B2 print\r
+    OK         +PR             +tXtX    ! $B3 print_ret\r
+    OK                         +tXtX    ! $B4 nop\r
+    ER                                  ! $B5 ILLEGAL\r
+    ER                                  ! $B6 ILLEGAL\r
+    OK                         +tXtX    ! $B7 restart\r
+    OK                         +tXtX    ! $B8 ret_popped\r
+    OK +ST                     +tXtX    ! $B9 catch\r
+    OK                         +tXtX    ! $BA quit\r
+    OK                         +tXtX    ! $BB new_line\r
+    ER                                  ! $BC ILLEGAL\r
+    OK     +BR                 +tXtX    ! $BD verify\r
+    OK                         +tXtX    ! $BE extended\r
+    OK     +BR                 +tXtX    ! $BF piracy\r
+\r
+    ! Variable 2OP: Type byte follows\r
+    ER                                  ! $C0 ILLEGAL\r
+    OK     +BR             +TY +1       ! $C1 je\r
+    OK     +BR             +TY +1       ! $C2 jl\r
+    OK     +BR             +TY +1       ! $C3 jg\r
+    OK     +BR             +TY +1       ! $C4 dec_chk\r
+    OK     +BR             +TY +1       ! $C5 inc_chk\r
+    OK     +BR             +TY +1       ! $C6 jin\r
+    OK     +BR             +TY +1       ! $C7 test\r
+    OK +ST                 +TY +1       ! $C8 or\r
+    OK +ST                 +TY +1       ! $C9 and\r
+    OK     +BR             +TY +1       ! $CAtest_attr\r
+    OK                     +TY +1       ! $CB set_attr\r
+    OK                     +TY +1       ! $CC clear_attr\r
+    OK                     +TY +1       ! $CD store\r
+    OK                     +TY +1       ! $CE insert_obj\r
+    OK +ST                 +TY +1       ! $CF loadw\r
+    OK +ST                 +TY +1       ! $D0 loadb\r
+    OK +ST                 +TY +1       ! $D1 get_prop\r
+    OK +ST                 +TY +1       ! $D2 get_prop_addr\r
+    OK +ST                 +TY +1       ! $D3 get_next_prop\r
+    OK +ST                 +TY +1       ! $D4 add\r
+    OK +ST                 +TY +1       ! $D5 sub\r
+    OK +ST                 +TY +1       ! $D6 mul\r
+    OK +ST                 +TY +1       ! $D7 div\r
+    OK +ST                 +TY +1       ! $D8 mod\r
+    OK +ST                 +TY +1       ! $D9 call_2s\r
+    OK                     +TY +1       ! $DA call_2n\r
+    OK                     +TY +1       ! $DB set_colour\r
+    OK                     +TY +1       ! $DC throw\r
+    ER                                  ! $DD ILLEGAL\r
+    ER                                  ! $DE ILLEGAL\r
+    ER                                  ! $DF ILLEGAL\r
+\r
+    ! Variable VAR: Type byte(s) follow\r
+    OK +ST                 +TY +1       ! $E0 call_vs\r
+    OK                     +TY +1       ! $E1 storew\r
+    OK                     +TY +1       ! $E2 storeb\r
+    OK                     +TY +1       ! $E3 put_prop\r
+    OK +ST                 +TY +1       ! $E4 aread\r
+    OK                     +TY +1       ! $E5 print_char\r
+    OK                     +TY +1       ! $E6 print_num\r
+    OK +ST                 +TY +1       ! $E7 random\r
+    OK                     +TY +1       ! $E8 push\r
+    OK                     +TY +1       ! $E9 pull\r
+    OK                     +TY +1       ! $EA split_window\r
+    OK                     +TY +1       ! $EB set_window\r
+    OK +ST                 +TY +2       ! $EC call_vs2\r
+    OK                     +TY +1       ! $ED erase_window\r
+    OK                     +TY +1       ! $EE erase_line\r
+    OK                     +TY +1       ! $EF set_cursor\r
+    OK                     +TY +1       ! $F0 get_cursor\r
+    OK                     +TY +1       ! $F1 set_text_style\r
+    OK                     +TY +1       ! $F2 buffer_mode\r
+    OK                     +TY +1       ! $F3 output_stream\r
+    OK                     +TY +1       ! $F4 input_stream\r
+    OK                     +TY +1       ! $F5 sound_effect\r
+    OK +ST                 +TY +1       ! $F6 read_char\r
+    OK +ST +BR             +TY +1       ! $F7 scan_table\r
+    OK +ST                 +TY +1       ! $F8 not\r
+    OK                     +TY +1       ! $F9 call_vn\r
+    OK                     +TY +2       ! $FA call_vn2\r
+    OK                     +TY +1       ! $FB tokenise\r
+    OK                     +TY +1       ! $FC encode_text\r
+    OK                     +TY +1       ! $FD copy_table\r
+    OK                     +TY +1       ! $FE print_table\r
+    OK     +BR             +TY +1       ! $FF check_arg_count\r
+\r
+    ! Extended: Type byte follows\r
+    OK +ST                 +TY +1       ! $00 save\r
+    OK +ST                 +TY +1       ! $01 restore\r
+    OK +ST                 +TY +1       ! $02 log_shift\r
+    OK +ST                 +TY +1       ! $03 art_shift\r
+    OK +ST                 +TY +1       ! $04 set_font\r
+    OK                     +TY +1       ! $05 draw_picture\r
+    OK     +BR             +TY +1       ! $06 picture_data\r
+    OK                     +TY +1       ! $07 erase_picture\r
+    OK                     +TY +1       ! $08 set_margins\r
+    OK +ST                 +TY +1       ! $09 save_undo\r
+    OK +ST                 +TY +1       ! $0A restore_undo\r
+    OK                     +TY +1       ! $0B print_unicode\r
+    OK                     +TY +1       ! $0C check_unicode\r
+    ER                                  ! $0D ILLEGAL\r
+    ER                                  ! $0E ILLEGAL\r
+    ER                                  ! $0F ILLEGAL\r
+    OK                     +TY +1       ! $10 move_window\r
+    OK                     +TY +1       ! $11 window_size\r
+    OK                     +TY +1       ! $12 window_style\r
+    OK +ST                 +TY +1       ! $13 get_wind_prop\r
+    OK                     +TY +1       ! $14 scroll_window\r
+    OK                     +TY +1       ! $15 pop_stack\r
+    OK                     +TY +1       ! $16 read_mouse\r
+    OK                     +TY +1       ! $17 mouse_window\r
+    OK     +BR             +TY +1       ! $18 push_stack\r
+    OK                     +TY +1       ! $19 put_wind_prop\r
+    OK                     +TY +1       ! $1A print_form\r
+    OK     +BR             +TY +1       ! $1B make_menu\r
+    OK                     +TY +1       ! $1C picture_table\r
+    ER                                  ! $1D ILLEGAL\r
+    ER                                  ! $1E ILLEGAL\r
+    ER;                                 ! $1F ILLEGAL\r
+\r
+Constant tLargeCon  = 0;                ! First four values defined by the ZSpec.\r
+Constant tSmallCon  = 1;                !\r
+Constant tVariable  = 2;                !\r
+Constant tOmit      = 3;                !\r
+Constant tAddress   = 4;                ! Following values not part of ZSpec.\r
+Constant tObject    = 5;                !\r
+Constant tProperty  = 6;                !\r
+Constant tAttribute = 7;                !\r
+Constant tString    = 8;                !\r
+\r
+Array OperandType   -> 8;               ! Up to eight operands are permitted.\r
+Array OperandValue --> 8;\r
+\r
+[ DumpRoutine a\r
+    opc opf i n maybeHWM addrHWM;\r
+\r
+    n = GetByte(a);                     ! Number of local variables\r
+    if (n > MAX_LOCALS) "BUG: bad locals count.";\r
+\r
+    if (currentState == STATE_DUMP) {\r
+        print " [ ", (hex5) a;\r
+        for (i=1 : i<=n : i++)\r
+            print " ", (var) i;\r
+        print ";^";\r
+    }\r
+    a++;\r
+    addrHWM = 0;                        ! Highest referenced address in routine\r
+\r
+    ! loop through the individual instructions\r
+\r
+    do {\r
+        if (addrHWM < a) addrHWM = a;\r
+        maybeHWM = false;\r
+        if (currentState == STATE_DUMP) print "            ", (hex5) a, ": ";\r
+        opc = GetByte(a++);\r
+        if (opc == $BE)                 ! Extended - real opcode in next byte\r
+            opc = GetByte(a++) + 256;\r
+        if (opc >= n_Opcodes || OpcodeNames-->opc == nothing)\r
+            "BUG: bad opcode ", n, ".";\r
+        opf = OpcodeFlags->opc;\r
+        n = opf & MA;\r
+        if (opf & TY) switch (n) {      ! Types byte(s) follow\r
+              1: SetOperandTypes(0, GetByte(a++)); SetOperandTypes(4, tXtXtXtX);\r
+              2: SetOperandTypes(0, GetByte(a++)); SetOperandTypes(4, GetByte(a++));\r
+              default: "BUG: error in type bits.";\r
+            }\r
+        else {                          ! Types known from opcode\r
+            SetOperandTypes(0, (n*16)|tXtX); SetOperandTypes(4, tXtXtXtX);\r
+        }\r
+        for (i=0 : i<8 : i++) switch (OperandType->i) {\r
+              tLargeCon:                    ! Large constant\r
+                OperandValue-->i = GetWord(a); a = a + 2;\r
+              tSmallCon, tVariable:         ! Small constant, Variable\r
+                OperandValue-->i = GetByte(a++);\r
+              tOmit:                        ! Omit\r
+                ;\r
+              default: "BUG: error in types.";\r
+            }\r
+\r
+        ! We now know the opcode, and the individual operand types and values.\r
+        ! Some adjustments are necessary...\r
+\r
+        switch (opc) {\r
+\r
+            ! These adjustments are essential.\r
+\r
+          $87:                          ! print_addr\r
+            OperandType->0 = tAddress;\r
+          $8D:                          ! print_paddr\r
+            OperandValue-->0 = P_to_A(OperandValue-->0);\r
+            if (currentState == STATE_DECODE && OperandValue-->0 < a_Strings)\r
+                a_Strings = OperandValue-->0;\r
+            OperandType->0 = tAddress;\r
+          $8C:                          ! jump (signed offset)\r
+            if (OperandValue-->0 & BIT15) {\r
+                OperandValue-->0 = OperandValue-->0 | $FFFF0000;\r
+                maybeHWM = true;\r
+            }\r
+            OperandValue-->0 = OperandValue-->0 + a - 2;\r
+            if (OperandValue-->0 > addrHWM) addrHWM = OperandValue-->0;\r
+            OperandType->0 = tAddress;\r
+          $8B,$9B,$AB,                  ! ret\r
+          $B0,                          ! rtrue\r
+          $B1,                          ! rfalse\r
+          $B3,                          ! print_ret\r
+          $B8,                          ! ret_popped\r
+          $BA:                          ! quit\r
+            maybeHWM = true;\r
+          $88,                          ! call_1s\r
+          $8F:                          ! call_1n\r
+            OperandValue-->0 = P_to_A(OperandValue-->0);\r
+            if (currentState == STATE_DECODE && OperandValue-->0 > a_TopOfRoutines)\r
+                a_TopOfRoutines = OperandValue-->0;\r
+            OperandType->0 = tAddress;\r
+          $D9,                          ! call_2s\r
+          $DA,                          ! call_2n\r
+          $E0,                          ! call_vs\r
+          $EC,                          ! call_vs2\r
+          $F9,                          ! call_vn\r
+          $FA:                          ! call_vn2\r
+            if (OperandType->0 == tLargeCon) {\r
+                OperandValue-->0 = P_to_A(OperandValue-->0);\r
+                if (currentState == STATE_DECODE && OperandValue-->0 > a_TopOfRoutines)\r
+                    a_TopOfRoutines = OperandValue-->0;\r
+                OperandType->0 = tAddress;\r
+            }\r
+\r
+            ! These adjustments are cosmetic.\r
+\r
+          $06,$26,$46,$66,$C6,          ! jin\r
+          $0E,$2E,$4E,$6E,$CE:          ! insert_obj\r
+            if (OperandType->0 == tLargeCon or tSmallCon) OperandType->0 = tObject;\r
+            if (OperandType->1 == tLargeCon or tSmallCon) OperandType->1 = tObject;\r
+          $0A,$2A,$4A,$6A,$CA,          ! test_attr\r
+          $0B,$2B,$4B,$6B,$CB,          ! set_attr\r
+          $0C,$2C,$4C,$6C,$CC:          ! clear_attr\r
+            if (OperandType->0 == tLargeCon or tSmallCon) OperandType->0 = tObject;\r
+            if (OperandType->1 == tLargeCon or tSmallCon) OperandType->1 = tAttribute;\r
+          $11,$31,$51,$71,$D1,          ! get_prop\r
+          $12,$32,$52,$72,$D2,          ! get_prop_addr\r
+          $13,$33,$53,$73,$D3,          ! get_next_prop\r
+          $E3:                          ! put_prop\r
+            if (OperandType->0 == tLargeCon or tSmallCon) OperandType->0 = tObject;\r
+            if (OperandType->1 == tLargeCon or tSmallCon) OperandType->1 = tProperty;\r
+          $81,$91,                      ! get_sibling\r
+          $82,$92,                      ! get_child\r
+          $83,$93,                      ! get_parent\r
+          $89,$99,                      ! remove_obj\r
+          $8A,$9A:                      ! print_obj\r
+            if (OperandType->0 == tLargeCon or tSmallCon) OperandType->0 = tObject;\r
+\r
+        }   ! end of switch (opc)\r
+\r
+        ! Look for large constants which might be Strings.\r
+\r
+        for (i=0 : i<8 : i++) if (OperandType->i == tLargeCon) {\r
+            if (FoundByChop(OperandValue-->i, theStrings, n_Strings)) {\r
+                OperandValue-->i = P_to_A(OperandValue-->i);\r
+                OperandType->i   = tString;\r
+            }\r
+        }\r
+\r
+        ! Print the opcode and operands.\r
+\r
+        if (currentState == STATE_DUMP) {\r
+            print "@@64", (string) OpcodeNames-->opc;\r
+            for (i=0 : i<8 : i++) switch (OperandType->i) {\r
+                  tLargeCon:                ! Large constant\r
+                    print " ", (hex4) OperandValue-->i;\r
+                  tSmallCon:                ! Small constant\r
+                    print " ", (hex2) OperandValue-->i;\r
+                  tVariable:                ! Variable\r
+                    print " ", (var) OperandValue-->i;\r
+                  tOmit:                    ! No more operands\r
+                    break;\r
+                  tAddress:                 ! Address\r
+                    print " ", (hex5) OperandValue-->i;\r
+                  tObject:                  ! Name of object\r
+                    print " ", (Zobject) OperandValue-->i;\r
+                  tProperty:                ! Name of property\r
+                    print " ", (Zproperty) OperandValue-->i;\r
+                  tAttribute:               ! Name of attribute\r
+                    print " ", (zAttribute) OperandValue-->i;\r
+                  tString:                  ! Address of String\r
+                    print " S", (hex5) OperandValue-->i;\r
+                }\r
+            }\r
+\r
+        ! Deal with the optional Store/Branch/Printstring sections.\r
+\r
+        if (opf & ST) {                 ! Next is a Store variable\r
+            n = GetByte(a++);\r
+            if (currentState == STATE_DUMP) print " -> ", (var) n;\r
+        }\r
+        if (opf & BR) {                 ! Next is a Branch offset\r
+            n = GetByte(a++);\r
+            if (currentState == STATE_DUMP) if (n & BIT07) print " "; else print " @@126";\r
+            if (n & BIT06)              ! Offset 0-63\r
+                n = n & BITS00_05;\r
+            else {                      ! Signed offset\r
+                n = (n & BITS00_05) * 256 + GetByte(a++);\r
+                if (n & BIT13) n = n | $FFFFC000;\r
+            }\r
+            switch (n) {\r
+              0: if (currentState == STATE_DUMP) print "rfalse";\r
+              1: if (currentState == STATE_DUMP) print "rtrue";\r
+              default:\r
+                n = a + n - 2;\r
+                if (n > addrHWM) addrHWM = n;\r
+                if (currentState == STATE_DUMP) print (hex5) n;\r
+            }\r
+        }\r
+        if (opf & PR) {                 ! Next is an encoded String\r
+            if (currentState == STATE_DUMP) print " ~", (Zaddress) a, "~";\r
+            if (currentState == STATE_EMBED) print (hex5) a, ": ", (Zaddress) a, "^";\r
+            do { i = GetWord(a); a = a + 2; } until (i & BIT15);\r
+        }\r
+\r
+        ! End of opcode.\r
+\r
+        if (currentState == STATE_DUMP) {\r
+            print ";";\r
+            if (opc == $87 or $8D) {    ! print_addr, print_paddr\r
+                stringOptions = stringOptions | STR_TRUNCATE;\r
+                print "      ! ~", (Zaddress) OperandValue-->0, "...~";\r
+                stringOptions = stringOptions & ~STR_TRUNCATE;\r
+            }\r
+            new_line;\r
+        }\r
+    } until (maybeHWM && addrHWM < a);\r
+\r
+    ! End of routine.\r
+\r
+    if (currentState == STATE_DUMP) print "        ]";\r
+    return a;\r
+];\r
+\r
+[ SetOperandTypes n t;\r
+    OperandType->(n+0) = (t & $$11000000) / 64;\r
+    OperandType->(n+1) = (t & $$00110000) / 16;\r
+    OperandType->(n+2) = (t & $$00001100) / 4;\r
+    OperandType->(n+3) = (t & $$00000011);\r
+];\r
+\r
+[ Var n;\r
+    switch (n) {\r
+      0:                print "SP";\r
+      1 to MAX_LOCALS:  print "L", (dec2) n-1;\r
+      16 to 255:        print "G", (dec3) n-16;\r
+      default:          "BUG: unexpected variable ", n;\r
+    }\r
+];\r
+\r
+! =================================================================================================\r
+!   Miscellaneous information.\r
+\r
+! [ DumpPropertyDefaults\r
+!   a i;\r
+!   font off;\r
+!   new_line;\r
+!     for (a=a_CommonPropDefaults,i=1 : i<64 : a=a+2,i++) {\r
+!         DumpWord(a); print (Zproperty) i, "^";\r
+!     }\r
+!   new_line;\r
+!     font on;\r
+! ];\r
+\r
+! [ DumpClassesToObjects                ! Class numbers To Object numbers\r
+!     a i x;\r
+!   font off;\r
+!   new_line;\r
+!   a = a_ClassToObject;\r
+!   for (x=GetWord(a),a=a+2,i=0 : x : x=GetWord(a),a=a+2,i++)\r
+!       print "Class ", i, " maps to Object ", (Zname) x, "^";\r
+!   new_line;\r
+!   font on;\r
+! ];\r
+\r
+! [ DumpIdentifiers\r
+!   a i x;\r
+!   font off;\r
+!   new_line;\r
+!   for (a=a_PropNames+2,i=1 : i<n_PropNames : a=a+2,i++) {\r
+!       x = GetWord(a);\r
+!       print "PROP", (dec3) i, " = ";\r
+!       if (x)\r
+!           print (Zstring) x;\r
+!       else\r
+!           switch (i) {\r
+!             2:    print "(ofclass)";\r
+!             3:    print "(metaclass)";\r
+!             default:\r
+!                   print "<unknown property>";\r
+!           }\r
+!       new_line;\r
+!       }\r
+!   new_line;\r
+!   for (i=0 : i<n_AttrNames : i++,a=a+2)\r
+!       print "ATTR", (dec3) i, " = ", (Zstring) GetWord(a), "^";\r
+!   new_line;\r
+!   for (i=0 : i<n_Actions : i++,a=a+2)\r
+!       print "ACTN", (dec3) i, " = ", (Zstring) GetWord(a), "^";\r
+!   new_line;\r
+!   for (i=0 : i<n_ArrayNames : i++,a=a+2)\r
+!       print "FAKE", (dec3) i, " = ", (Zstring) GetWord(a), "^";\r
+!   new_line;\r
+!   font on;\r
+! ];\r
+\r
+! [ DumpGlobalVariables\r
+!     a i;\r
+!     font off;\r
+!   new_line;\r
+!   for (a=a_Globals,i=0 : i<240 : a=a+2,i++)\r
+!       print "G", (dec3) i, " = ", (hex4) GetWord(a), "^";\r
+!   new_line;\r
+!     font on;\r
+! ];\r
+\r
+! =================================================================================================\r