home *** CD-ROM | disk | FTP | other *** search
/ ARM Club 3 / TheARMClub_PDCD3.iso / hensa / recreation / zipdebug / b055s / c / ZIP < prev    next >
Text File  |  1993-06-29  |  195KB  |  8,029 lines

  1. /* Output from p2c, the Pascal-to-C translator */
  2. /* From input file "pas.ZIP" */
  3.  
  4.  
  5. #include "p2c/p2c.h"
  6.  
  7.  
  8. #ifndef ZIPEXT_H
  9. #include "h.zip_ext"
  10. #endif
  11.  
  12.  
  13. /* Abort current command */
  14.  
  15.  
  16. #define InterpreterNumber  6
  17.  
  18. #define InterpreterChar  'n'
  19.  
  20. #define Date            "29-Jun-93"
  21.  
  22. #define Debugging       false
  23.  
  24. #define MaxSpecTxtAdrsPageNo  1
  25. #define MaxSpecTxtPageNo  3
  26. #define MaxEntryPointCnt  1999
  27.  
  28. #define MaxStack        511
  29.  
  30. #define MaxMaxNumWords  70
  31. #define MaxScreenWidth  256
  32. #define MaxLineIndex    255
  33.  
  34. #define HighByteMask    65280
  35.  
  36. #define IntToCardConst  0
  37.  
  38. #define MaxPageNo       2047
  39. #define MaxSubPageNo    0
  40. #define MinMemSpace     4096
  41.  
  42. #define PrinterName     "Listing"
  43.  
  44.  
  45. typedef Char anAddrString[80];
  46.  
  47.  
  48. typedef enum {
  49.   NoError, IllMultiOpdOp, IllNoOpdOp, IllTwoOpdOp, IllOneOpdOp,
  50.   StackUnderflow, StackOverflow, IllObjDataLoad, DivideByZero, MissingOpd,
  51.   MissingObjData, IllObjPropertyStore, IllZCodeType, NotImplemented,
  52.   KeyboardBreak, BreakPoint, OutputBufferUndefined, PC_Overflow, PC_Underflow,
  53.   TooManySeparators, TooManyLocalVariables, TooManyParameters, IllNumOperands,
  54.   IllOutputChar, IllScreenMode, NoPrinter, IllOutputMode
  55. } InternalErrors;
  56. typedef int CharSet[9];
  57.  
  58. typedef enum {
  59.   Nothing, Quit, NewAdv, Info, Help, VerifyCode, DumpOption, List, TextList,
  60.   GoSub, cDumpBytes, DumpWords, ListEntryPoints, ListObject, ListVocabulary,
  61.   ListZState, ListReg, Step, Run, Trace, Break, ModifyWords, ModifyBytes,
  62.   BPT_Cmd, SwitchToStep, SwitchToTrace, ListCalls
  63. } Commands;
  64. typedef enum {
  65.   NoDump, CodeDump, TextDump, UnpackedDump
  66. } DumpStates;
  67.  
  68. typedef enum {
  69.   CallNever, CallKeyPress, CallTimeOut
  70. } CallEvents;
  71.  
  72. typedef struct tMiscInfo {
  73.   uchar CodeType;   /* $00 */
  74.   uchar ConfigFlags;   /* $01 */
  75.   uchar ReleaseHigh;   /* $02 */
  76.   uchar ReleaseLow;   /* $03 */
  77.   uchar NumReadWriteBytesHigh;   /* $04 */
  78.   uchar NumReadWriteBytesLow;   /* $05 */
  79.   uchar StartPageNo;   /* $06 */
  80.   uchar StartIndex;   /* $07 */
  81.   uchar VocabPageNo;   /* $08 */
  82.   uchar VocabPageIndex;   /* $09 */
  83.   uchar ObjPageNo;   /* $0A */
  84.   uchar ObjPageIndex;   /* $0B */
  85.   uchar DataPageNo;   /* $0C */
  86.   uchar DataPageIndex;   /* $0D */
  87.   uchar SaveStateSizeHigh;   /* $0E */
  88.   uchar SaveStateSizeLow;   /* $0F */
  89.   uchar ScriptStatusHigh;   /* $10 */
  90.   uchar ScriptStatusLow;   /* $11 */
  91.   Char SerialNumber[6];
  92.   uchar SpecialPageNo;   /* $18 */
  93.   uchar SpecialIndex;   /* $19 */
  94.   uchar EndPageNo;   /* $1A */
  95.   uchar EndPageIndex;   /* $1B */
  96.   uchar ChkSumHigh;   /* $1C */
  97.   uchar ChkSumLow;   /* $1D */
  98.   uchar mInterpreterNumber;   /* $1E */
  99.   uchar mInterpreterVersion;   /* $1F */
  100.   uchar ScreenHeight;   /* $20 */
  101.   uchar ScreenWidth;   /* $21 */
  102.   uchar Left;   /* $22 */
  103.   uchar Right;   /* $23 */
  104.   uchar Top;   /* $24 */
  105.   uchar Bottom;   /* $25 */
  106.   uchar Unknown1;   /* $26 */
  107.   uchar Unknown2;   /* $27 */
  108.   uchar CodeStartPageNo;   /* $28 */
  109.   uchar CodeStartIndex;   /* $29 */
  110.   uchar Unused13;   /* $2A */
  111.   uchar Unused14;   /* $2B */
  112.   uchar Unknown3;   /* $2C */
  113.   uchar Unknown4;   /* $2D */
  114.   uchar Unknown5;   /* $2E */
  115.   uchar Unused21;   /* $2F */
  116.   uchar Unused22;   /* $30 */
  117.   uchar Unused23;   /* $31 */
  118.   uchar Unused24;   /* $32 */
  119.   uchar Unused25;   /* $33 */
  120.   uchar Unused26;   /* $34 */
  121.   uchar Unknown6;   /* $35 */
  122.   uchar Unused3[0xca];
  123. } tMiscInfo;
  124.  
  125. typedef enum {
  126.   OntoScreen, IntoBuffer, ToStoryOutput
  127. } OutputTypes;
  128. typedef enum {
  129.   FromDC, FromIPC
  130. } SourceTypes;
  131.  
  132. typedef enum {
  133.   UndefinedBPT, UserBPT, RunBPT, TraceBPT
  134. } BPT_Types;
  135. typedef struct aBPT *PtrBPT;
  136.  
  137. typedef struct aBPT {
  138.   int BPT_PageNo;
  139.   int BPT_PageIndex;
  140.   int HitCnt;
  141.   int BPT_No;
  142.   int OrgByte1;
  143.   int OrgByte2;
  144.   int OrgByte3;
  145.   PtrBPT NextBPT;
  146.   char BPT_Type;
  147. } aBPT;
  148.  
  149. typedef union Registers {
  150.   int a[16];
  151.   struct {
  152.     int r0;
  153.     int r1;
  154.     int r2;
  155.     int r3;
  156.     int r4;
  157.     int r5;
  158.     int r6;
  159.     int r7;
  160.     int r8;
  161.     int r9;
  162.     int r10;
  163.     int r11;
  164.     int r12;
  165.     int r13;
  166.     int r14;
  167.     int r15;
  168.   } U1;
  169. } Registers;
  170.  
  171. typedef union Operands {
  172.   int a[8];
  173.   struct {
  174.     int s0;
  175.     int s1;
  176.     int s2;
  177.     int s3;
  178.     int s4;
  179.     int s5;
  180.     int s6;
  181.     int s7;
  182.   } U1;
  183. } Operands;
  184.  
  185. typedef int CountArray[256];
  186. typedef aPage StoryFileBuffer[MaxSubPageNo + 1];
  187.  
  188. typedef Char aWord[9];
  189. typedef ShortInteger aPackedWord[3];
  190.  
  191.  
  192. Static Char CodeVersion;
  193. Static Char StoryName[256];
  194. Static tMiscInfo MiscInfo;
  195. Static int WordNumChars;
  196. Static int ObjRecSize;
  197. Static int ObjOffset;
  198. Static int ReleaseNo;
  199.  
  200. Static int PageCnt;
  201. Static uchar *PagePtrs[MaxPageNo + 1];
  202. Static uchar *DataPagePtrs[MaxPageNo + 1];
  203.  
  204. Static int DC_PageNo;
  205. Static int DC_PageIndex;
  206. Static int OldPageNo;
  207. Static int OldIndex;
  208. Static int BackPageNo;
  209. Static int BackIndex;
  210. Static int EndPageNo;
  211. Static int EndPageIndex;
  212. Static int TextPageNo;
  213. Static int TextPageIndex;
  214. Static int OldTextPageNo;
  215. Static int OldTextPageIndex;
  216. Static int BackTxtPageNo;
  217. Static int BackTxtIndex;
  218. Static int CodeEndPageIndex;
  219. Static int CodeEndPageNo;
  220. Static int InstPageNo;
  221. Static int InstPageIndex;
  222. Static int NewInstPageNo;
  223. Static int NewInstPageIndex;
  224. Static int EndIPC_PageNo;
  225. Static int EndIPC_PageIndex;
  226. Static int BackIPC_PageNo;
  227. Static int BackIPC_PageIndex;
  228. Static int OldIPC_PageNo;
  229. Static int OldIPC_PageIndex;
  230. Static int BPT_PageNo;
  231. Static int BPT_PageIndex;
  232. Static int FirstInstPageNo;
  233. Static int FirstInstPageIndex;
  234.  
  235. Static boolean DisWithIds;
  236. Static boolean DisBPTs;
  237. Static boolean Statistics;
  238. Static boolean RestartOperations;
  239. Static boolean ChkLineChars;
  240.  
  241. Static boolean WriteDump;
  242. Static char GlobalDumpState;
  243. Static int DumpCnt;
  244. Static int LineCnt;
  245. Static Char Dump[256];
  246.  
  247. Static Char BreakKey;
  248. Static Char ExitKey;
  249.  
  250. Static Char HexChars[16];
  251. Static Char Char1Table[25];
  252. Static Char Char23Table[24];
  253. Static CharSet Char1Set;
  254. Static CharSet Char23Set;
  255. Static Char GlobalTextBuffer[256];
  256.  
  257. Static Char KeyBuffer[80];
  258. Static int ReadIndex;
  259. Static int WriteIndex;
  260.  
  261. Static boolean PrintListing;
  262. Static FILE *Printer;
  263.  
  264. Static boolean SaveEntryPoints;
  265. Static boolean TryRegList;
  266. Static int EntryIndex;
  267. Static int EntryPoints[MaxEntryPointCnt + 1];
  268.  
  269. Static int CmdCode;
  270. Static int IPC_PageNo;
  271. Static int IPC_PageIndex;
  272. Static int SP;
  273. Static int MSP;
  274. Static int NumCallParams;
  275. Static int AccA;
  276. Static int AccB;
  277. Static int AccC;
  278. Static int AccD;
  279. Static int OpdCnt;
  280. Static Operands Opd;
  281. Static Registers R;
  282. Static int Stack[MaxStack + 1];
  283.  
  284. Static boolean Running;
  285. Static boolean Tracing;
  286. Static boolean Stepping;
  287. Static boolean CrashInternal;
  288. Static boolean DebugVocab;
  289. Static boolean InStory;
  290. Static boolean FaultNotImplemented;
  291.  
  292. Static int CursorX;
  293. Static int CursorY;
  294. Static int StoryCursorX;
  295. Static int StoryCursorY;
  296. Static int NonWindowCursorX;
  297. Static int NonWindowCursorY;
  298. Static int WindowCursorX;
  299. Static int WindowCursorY;
  300. Static int ScreenMode;
  301. Static int StoryScreenMode;
  302. Static int FormatMode;
  303. Static int ComMode;
  304. Static int OutputMode;
  305. Static boolean ScreenEnabled;
  306. Static boolean BufferEnabled;
  307. Static boolean DirectEnabled;
  308. Static boolean WindowEnabled;
  309. Static boolean WritingInWindow;
  310. Static boolean PrinterTried;
  311. Static boolean PrinterOpen;
  312. Static int BufferPageNo;
  313. Static int BufferPageIndex;
  314. Static int BufferIndex;
  315. Static int LineIndex;
  316. Static int LineNo;
  317. Static int ScrollTop;
  318. Static int StoryScrollTop;
  319. Static Char LineBuffer[MaxLineIndex + 1];
  320. Static Char Spaces[256];
  321.  
  322. Static CharSet TerminatorSet;
  323.  
  324. Static char Cmd;
  325. Static Char CmdLine[256];
  326. Static int FirstObj;
  327. Static int LastObj;
  328. Static int FirstHigh;
  329. Static int LastHigh;
  330. Static int RegNo;
  331.  
  332. Static int BPT_No;
  333. Static int BPT_IdCnt;
  334. Static PtrBPT BPT_List;
  335.  
  336. Static CountArray ExecCnt;
  337.  
  338. Static int CmpShift;
  339.  
  340.  
  341. Static void HandleError(boolean WriteLastInst, Char Message[256],
  342.                         boolean Crash);
  343.  
  344. Static void InternalError(char Error);
  345.  
  346.  
  347. Static void SetLength(Char S[256], int Length) {
  348.   S[Length] = '\0';
  349. /* p2c: pas.ZIP, line 248:
  350.  * Note: Modification of string length may translate incorrectly [146] */
  351. }  /* SetLength */
  352.  
  353.  
  354. Static void OpenPrinter(void) {
  355.   if (PrinterTried || PrinterOpen)
  356.     return;
  357.   if (Printer != NULL)
  358.     Printer = freopen(PrinterName, "w", Printer);
  359.   else
  360.     Printer = fopen(PrinterName, "w");
  361.   _SETIO(Printer != NULL, FileNotFound);
  362.   PrinterTried = true;
  363.   PrinterOpen = (P_ioresult == 0);
  364.   if (!PrinterOpen)
  365.     InternalError(NoPrinter);
  366. }  /* OpenPrinter */
  367.  
  368.  
  369. Static boolean PrinterEnabled(void) {
  370.   boolean PrinterEnabled_ReturnValue;
  371.   uchar ScriptLow;
  372.   boolean Enabled;
  373.  
  374.   PrinterEnabled_ReturnValue = false;
  375.   if (PagePtrs[0] == NULL)
  376.     return PrinterEnabled_ReturnValue;
  377.   ScriptLow = PagePtrs[0][17];
  378.   Enabled = TstBit(ScriptLow, 0);
  379.   if (!Enabled)
  380.     return PrinterEnabled_ReturnValue;
  381.   if (!PrinterOpen)
  382.     OpenPrinter();
  383.   if (PrinterOpen)
  384.     return true;
  385.   return PrinterEnabled_ReturnValue;
  386. }  /* PrinterEnabled */
  387.  
  388.  
  389. Static void PositionCursor(void) {
  390.   GotoXY(CursorX, CursorY);
  391. }  /* PositionCursor */
  392.  
  393.  
  394. Static void MoveCursorUp(void) {
  395.   if (CursorY > 0) {
  396.     --CursorY;
  397.     PositionCursor();
  398.   }
  399. }  /* MoveCursorUp */
  400.  
  401.  
  402. Static void MoveCursorDown(void) {
  403.   if (CursorY < ScreenHeight - 1) {
  404.     ++CursorY;
  405.     PositionCursor();
  406.   }
  407. }  /* MoveCursorDown */
  408.  
  409.  
  410. Static void MoveCursorRight(void) {
  411.   if (CursorX < ScreenWidth - 1) {
  412.     ++CursorX;
  413.     PositionCursor();
  414.   }
  415. }  /* MoveCursorRight */
  416.  
  417.  
  418. Static void MoveCursorLeft(void) {
  419.   if (CursorX > 0) {
  420.     --CursorX;
  421.     PositionCursor();
  422.   }
  423. }  /* MoveCursorLeft */
  424.  
  425.  
  426. Static void ClearCh(void) {
  427.   PositionCursor();
  428.   WriteRawChOnScreen(' ');
  429.   PositionCursor();
  430. }  /* ClearCh */
  431.  
  432.  
  433. Static void EraseCh(void) {
  434.   if (CursorX <= 0)
  435.     return;
  436.   MoveCursorLeft();
  437.   WriteRawChOnScreen(' ');
  438.   PositionCursor();
  439. }  /* EraseCh */
  440.  
  441.  
  442. Static void ZM_GotoXY(int x, int y) {
  443.   CursorX = x - 1;
  444.   CursorY = y - 1;
  445.   PositionCursor();
  446. }  /* ZM_GotoXY */
  447.  
  448.  
  449. Static void SetScreenMode(void) {
  450.   switch (ScreenMode) {
  451.  
  452.   case 0:   /* Normal */
  453.     NormalOn();
  454.     break;
  455.  
  456.   case 1:   /* Inverse */
  457.     InverseOn();
  458.     break;
  459.  
  460.   case 2:   /* Bold */
  461.     BoldOn();
  462.     break;
  463.  
  464.   case 4:   /* Italic */
  465.     ItalicOn();
  466.     break;
  467.  
  468.   case 8:   /* Title/Subtitle? */
  469.     ExtraOn();
  470.     break;
  471.  
  472.   default:
  473.     InternalError(IllScreenMode);
  474.     break;
  475.   }
  476. }  /* SetScreenMode */
  477.  
  478.  
  479. Static void ClearLines(int FirstLine, int LastLine) {
  480.   int LineCnt;
  481.  
  482.   SaveTextAttributes();
  483.   ScreenMode = 0;
  484.   SetScreenMode();
  485.   for (LineCnt = FirstLine; LineCnt <= LastLine; ++LineCnt) {
  486.     GotoXY(0, LineCnt);
  487.     ClearToEOL();
  488.   }
  489.   RestoreTextAttributes();
  490.   PositionCursor();
  491. }  /* ClearLines */
  492.  
  493.  
  494. Static void NewLine(void) {
  495.   CursorX = 0;
  496.   ++CursorY;
  497.   if (CursorY >= ScreenHeight) {
  498.     ScrollLinesUp(ScrollTop - 1);
  499.     CursorY = ScreenHeight - 1;
  500.   }
  501.   PositionCursor();
  502.   ClearToEOL();
  503. }  /* NewLine */
  504.  
  505.  
  506. Static void InitScreen(void) {
  507.   SetupTerminal(&ScreenWidth, &ScreenHeight);
  508.   ScrollTop = 1;
  509.   LineCnt = 0;
  510.   ClearScreen();
  511.   CursorOff();
  512.   CursorX = 0;
  513.   CursorY = 0;
  514.   ScreenMode = 0;
  515.   SetScreenMode();
  516. }  /* InitSCreen */
  517.  
  518.  
  519. Static void ResetScreen(void) {
  520.   ScreenMode = 0;
  521.   SetScreenMode();
  522.   CursorOff();
  523.   ResetTerminal();
  524. }  /* ResetSCreen */
  525.  
  526.  
  527. Static void ScreenCh(Char Ch) {
  528.   WriteRawChOnScreen(Ch);
  529.   ++CursorX;
  530.   /*
  531.      IF CursorX>=Pred(ScreenWidth) THEN BEGIN
  532.        CursorX:=0;
  533.        PositionCursor;
  534.      END;
  535.   */
  536. }  /* ScreenCh */
  537.  
  538.  
  539. Static void PrintCh(Char Ch) {
  540.   ScreenCh(Ch);
  541.   if (PrintListing)
  542.     putc(Ch, Printer);
  543. }  /* PrintCh */
  544.  
  545.  
  546. Static void ZM_ScreenCh(Char Ch) {
  547.   if (Ch < ' ')
  548.     InternalError(IllOutputChar);
  549.   WriteChOnScreen(Ch);
  550.   ++CursorX;
  551.   /*
  552.      IF CursorX>=Pred(ScreenWidth) THEN BEGIN
  553.        CursorX:=0;
  554.        PositionCursor;
  555.      END;
  556.   */
  557. }  /* ZM_ScreenCh */
  558.  
  559.  
  560. Static void ZM_PrintCh(Char Ch) {
  561.   ZM_ScreenCh(Ch);
  562.   if (PrintListing)
  563.     putc(Ch, Printer);
  564. }  /* ZM_PrintCh */
  565.  
  566.  
  567. Static void InitExecCnt(void) {
  568.   int Cnt;
  569.  
  570.   for (Cnt = 0; Cnt <= 255; ++Cnt)
  571.     ExecCnt[Cnt] = 0;
  572. }  /* InitExecCnt */
  573.  
  574.  
  575. Static void Push(int Value) {
  576.   if (SP > MaxStack) {
  577.     InternalError(StackOverflow);
  578.   } else {
  579.     Stack[SP] = Value;
  580.     ++SP;
  581.   }
  582. }  /* Push */
  583.  
  584.  
  585. Static int Pop(void) {
  586.   if (SP > 0) {
  587.     --SP;
  588.     return (Stack[SP]);
  589.   }
  590.   InternalError(StackUnderflow);
  591. }  /* Pop */
  592.  
  593.  
  594. Static void ChkAddress(int *PageNo, int *PageIndex) {
  595.   while (*PageIndex > 255) {
  596.     *PageIndex -= 256;
  597.     ++*PageNo;
  598.   }
  599.   while (*PageIndex < 0) {
  600.     *PageIndex += 256;
  601.     --*PageNo;
  602.   }
  603.   if (CodeVersion < '3')
  604.     return;
  605.   if (*PageNo > CodeEndPageNo) {
  606.     InternalError(PC_Overflow);
  607.   } else if (*PageNo < 0)
  608.     InternalError(PC_Underflow);
  609. }  /* ChkAddress */
  610.  
  611.  
  612. Static void Inc(int *PageNo, int *PageIndex, int Increment) {
  613.   *PageIndex += Increment;
  614.   ChkAddress(PageNo, PageIndex);
  615. }  /* Inc */
  616.  
  617.  
  618. Static void Dec(int *PageNo, int *PageIndex, int Increment) {
  619.   *PageIndex -= Increment;
  620.   ChkAddress(PageNo, PageIndex);
  621. }  /* Inc */
  622.  
  623.  
  624. Static void ExpandAddress(int AddressHigh, int AddressLow, int *PageNo,
  625.                           int *PageIndex) {
  626.   *PageNo = AddressHigh;
  627.   *PageIndex = AddressLow;
  628.   ShiftLeft(PageNo, PageIndex);
  629.   if (CodeVersion >= '4') {
  630.     ShiftLeft(PageNo, PageIndex);
  631.     if (CodeVersion >= '6')
  632.       ShiftLeft(PageNo, PageIndex);
  633.   }
  634.   ChkAddress(PageNo, PageIndex);
  635. }  /* ExpandAddress */
  636.  
  637.  
  638. Static void PrintByte(int Value, int Format) {
  639.   int SpaceCnt;
  640.   int Expanded;
  641.  
  642.   Expanded = Value;
  643.   if (Format >= 2) {
  644.     for (SpaceCnt = 3; SpaceCnt <= Format; ++SpaceCnt)
  645.       PrintCh(' ');
  646.     PrintCh(HexChars[Nibble(Expanded, 1)]);
  647.   }
  648.   PrintCh(HexChars[Nibble(Expanded, 0)]);
  649. }  /* PrintByte */
  650.  
  651.  
  652. Static void PrintWord(int Value, int Format) {
  653.   int LowByte;
  654.   int HighByte;
  655.  
  656.   SplitWord(Value, &LowByte, &HighByte);
  657.   PrintByte(HighByte, Format - 2);
  658.   PrintByte(LowByte, 2);
  659. }  /* PrintWord */
  660.  
  661.  
  662. Static void PrintInteger(int Value) {
  663.   int DigitCnt;
  664.   int Digit;
  665.   int WriteCnt;
  666.  
  667.   if (Value < 0) {
  668.     PrintCh('-');
  669.     Value = -Value;
  670.   }
  671.   DigitCnt = 0;
  672.   while (Value > 0) {
  673.     Push(Value % 10);
  674.     ++DigitCnt;
  675.     Value /= 10;
  676.   }
  677.   if (DigitCnt == 0) {
  678.     PrintCh('0');
  679.     return;
  680.   }
  681.   for (WriteCnt = 1; WriteCnt <= DigitCnt; ++WriteCnt) {
  682.     Digit = Pop();
  683.     PrintCh(Digit + '0');
  684.   }
  685. }  /* PrintInteger */
  686.  
  687.  
  688. Static void PrintString(Char S[256]) {
  689.   int ChrCnt;
  690.   int FORLIM;
  691.  
  692.   FORLIM = strlen(S);
  693.   for (ChrCnt = 1; ChrCnt <= FORLIM; ++ChrCnt)
  694.     PrintCh(S[ChrCnt - 1]);
  695. }  /* PrintString */
  696.  
  697.  
  698. Static void LineInterpreter(char *Cmd, Char CmdLine[256]);
  699.  
  700. Static void PrintStatusLine(void);
  701.  
  702.  
  703. Static void WriteLineBuffer(void) {
  704.   int ChrCnt;
  705.   int FORLIM;
  706.  
  707.   if (ScreenEnabled) {
  708.     FORLIM = LineIndex;
  709.     for (ChrCnt = 0; ChrCnt < FORLIM; ++ChrCnt)
  710.       ZM_ScreenCh(LineBuffer[ChrCnt]);
  711.   }
  712.   if (PrinterEnabled() && !WritingInWindow) {
  713.     FORLIM = LineIndex;
  714.     for (ChrCnt = 0; ChrCnt < FORLIM; ++ChrCnt)
  715.       putc(LineBuffer[ChrCnt], Printer);
  716.   }
  717.   LineIndex = 0;
  718. }  /* WriteLineBuffer */
  719.  
  720.  
  721. Static void PutChInStoryBuffer(Char Ch) {
  722.   int IndexPageNo;
  723.   int IndexPageIndex;
  724.  
  725.   if (BufferPageNo < 0)
  726.     InternalError(OutputBufferUndefined);
  727.   IndexPageNo = BufferPageNo;
  728.   IndexPageIndex = BufferPageIndex;
  729.   Inc(&IndexPageNo, &IndexPageIndex, BufferIndex);
  730.   PagePtrs[IndexPageNo][IndexPageIndex] = Ch;
  731.   ++BufferIndex;
  732. }  /* PutChInStoryBuffer */
  733.  
  734.  
  735. Static void ZM_NewLine(void) {
  736.   Char WaitKey;
  737.   int OldCursorX;
  738.   int OldCursorY;
  739.   boolean OldPrintListing;
  740.  
  741.   if (BufferEnabled) {
  742.     PutChInStoryBuffer('\015');
  743.     return;
  744.   }
  745.   OldPrintListing = PrintListing;
  746.   PrintListing = false;
  747.   if (ScreenEnabled && !WritingInWindow) {
  748.     if (LineNo >= ScreenHeight) {
  749.       PrintStatusLine();
  750.       PositionCursor();
  751.       OldCursorX = CursorX;
  752.       OldCursorY = CursorY;
  753.       LineNo = ScrollTop;
  754.       CursorOn();
  755.       PrintString("[MORE]");
  756.       WaitKey = ReadKeyWithNoEcho(-1);
  757.       CursorOff();
  758.       CursorX = OldCursorX;
  759.       CursorY = OldCursorY;
  760.       PositionCursor();
  761.       ClearToEOL();
  762.     }
  763.     ++LineNo;
  764.   }
  765.   WriteLineBuffer();
  766.   if (ScreenEnabled)
  767.     NewLine();
  768.   if (PrinterEnabled())
  769.     putc('\n', Printer);
  770.   PrintListing = OldPrintListing;
  771. }  /* ZM_NewLine */
  772.  
  773.  
  774. Static void PutChInLineBuffer(Char Ch) {
  775.   int LastIndex;
  776.   int CutIndex;
  777.   int PutIndex;
  778.  
  779.   if (Ch < ' ') {
  780.     if (ChkLineChars)
  781.       InternalError(IllOutputChar);
  782.     goto _L2;
  783.   }
  784.   LineBuffer[LineIndex] = Ch;
  785.   if (LineIndex + CursorX < ScreenWidth) {
  786.     ++LineIndex;
  787.     /*
  788.        END ELSE IF WritingInWindow AND (CursorY + 1>=ScrollTop - 1) THEN BEGIN
  789.         WriteLineBuffer;
  790.     */
  791.   } else {
  792.     LastIndex = LineIndex;
  793.     CutIndex = LineIndex;
  794.     while (CutIndex > 0) {
  795.       if (CutIndex + CursorX < ScreenWidth && LineBuffer[CutIndex] == ' ')
  796.         goto _L1;
  797.       --CutIndex;
  798.     }
  799.     CutIndex = LineIndex;
  800. _L1:
  801.     LineIndex = CutIndex;
  802.     ZM_NewLine();
  803.     if (LineBuffer[CutIndex] == ' ')
  804.       ++CutIndex;
  805.     PutIndex = 0;
  806.     while (CutIndex <= LastIndex) {
  807.       LineBuffer[PutIndex] = LineBuffer[CutIndex];
  808.       ++CutIndex;
  809.       ++PutIndex;
  810.     }
  811.     LineIndex = PutIndex;
  812.   }
  813. _L2: ;
  814. }  /* PutChInLineBuffer */
  815.  
  816.  
  817. Static void PutChToStoryOutput(Char Ch) {
  818.   if (Ch == EOL()) {
  819.     ZM_NewLine();
  820.     return;
  821.   }
  822.   if (BufferEnabled) {
  823.     PutChInStoryBuffer(Ch);
  824.     return;
  825.   }
  826.   if (!(ScreenEnabled | PrinterEnabled()))
  827.     return;
  828.   if (DirectEnabled) {
  829.     if (ScreenEnabled)
  830.       ZM_ScreenCh(Ch);
  831.     /*
  832.          IF PrinterEnabled THEN BEGIN
  833.           Write(Printer,Ch);
  834.          END;
  835.     */
  836.   } else {
  837.     PutChInLineBuffer(Ch);
  838.   }
  839. }  /* PutChToStoryOutput */
  840.  
  841.  
  842. Static void PutIntToStoryOutput(int Int) {
  843.   int DigitCnt;
  844.   int Digit;
  845.   int WriteCnt;
  846.  
  847.   if (Int < 0) {
  848.     PutChToStoryOutput('-');
  849.     Int = -Int;
  850.   }
  851.   DigitCnt = 0;
  852.   while (Int > 0) {
  853.     Push(Int % 10);
  854.     ++DigitCnt;
  855.     Int /= 10;
  856.   }
  857.   if (DigitCnt == 0) {
  858.     PutChToStoryOutput('0');
  859.     return;
  860.   }
  861.   for (WriteCnt = 1; WriteCnt <= DigitCnt; ++WriteCnt) {
  862.     Digit = Pop();
  863.     PutChToStoryOutput(Digit + '0');
  864.   }
  865. }  /* PutIntToStoryOutput */
  866.  
  867.  
  868. Static jmp_buf _JL999;
  869.  
  870.  
  871. Static void ChkWait(void) {
  872.   Char Key;
  873.  
  874.   if (KeyPressed()) {
  875.     Key = ReadKeyWithNoEcho(-1);
  876.     if (Key != ExitKey) {
  877.       KeyBuffer[WriteIndex] = Key;
  878.       ++WriteIndex;
  879.       if (WriteIndex > 79)
  880.         WriteIndex = 0;
  881.     } else {
  882.       if (PrintListing)
  883.         fprintf(Printer, "\n\n");
  884.       NewLine();
  885.       WriteDump = (GlobalDumpState != NoDump);
  886.       longjmp(_JL999, 1);
  887.     }
  888.   }
  889.   NewLine();
  890.   if (PrintListing)
  891.     putc('\n', Printer);
  892.   ++LineCnt;
  893. }  /* ChkWait */
  894.  
  895.  
  896. Static void DisposePages(void) {
  897.   int DisposeCnt;
  898.  
  899.   for (DisposeCnt = PageCnt - 1; DisposeCnt >= 0; --DisposeCnt) {
  900.     if (PagePtrs[DisposeCnt] != NULL)
  901.       Free(PagePtrs[DisposeCnt]);
  902.     if (DataPagePtrs[DisposeCnt] != NULL)
  903.       Free(DataPagePtrs[DisposeCnt]);
  904.   }
  905.   PageCnt = 0;
  906. }  /* DisposePages */
  907.  
  908.  
  909. Static void ReadPages(void) {
  910.   int SubPageCnt;
  911.   int EndPageNo;
  912.   int EndPageIndex;
  913.   int DataEndPageNo;
  914.   union {
  915.     tMiscInfo M;
  916.     aPage P;
  917.   } SwapPage;
  918.   Char FileName[256];
  919.   FILE *StoryData;
  920.   FILEBUFNC(StoryData,StoryFileBuffer);
  921.  
  922.   StoryData = NULL;
  923.   if (PageCnt > 0)
  924.     DisposePages();
  925.   strcpy(FileName, StoryName);
  926.   if (!FileExists(StoryName))
  927.     HandleError(false, "Story file not found.", false);
  928.   if (StoryData != NULL)
  929.     StoryData = freopen(FileName, "rb", StoryData);
  930.   else
  931.     StoryData = fopen(FileName, "rb");
  932.   if (StoryData == NULL)
  933.     _EscIO(FileNotFound);
  934.   RESETBUF(StoryData, StoryFileBuffer);
  935.   memcpy(SwapPage.P, AGETFBUF(StoryData, StoryFileBuffer)[0],
  936.          signedsizeof(aPage));
  937.   MiscInfo = SwapPage.M;
  938.   CodeVersion = MiscInfo.CodeType + '0';
  939.   DataEndPageNo = MiscInfo.NumReadWriteBytesHigh;
  940.   if (CodeVersion <= '2') {
  941.     CodeEndPageNo = MaxPageNo - 1;
  942.     CodeEndPageIndex = 255;
  943.   } else {
  944.     ExpandAddress(MiscInfo.EndPageNo, MiscInfo.EndPageIndex, &EndPageNo,
  945.                   &EndPageIndex);
  946.     CodeEndPageNo = EndPageNo;
  947.     CodeEndPageIndex = EndPageIndex;
  948.     if (CodeEndPageNo > MaxPageNo)
  949.       HandleError(false, "Story too large.", false);
  950.   }
  951.   while ((PageCnt <= CodeEndPageNo) & (!BUFEOF(StoryData))) {
  952.     for (SubPageCnt = 0; SubPageCnt <= MaxSubPageNo; ++SubPageCnt)
  953.     {   /* MemAvail<SizeOf(aPage)+MinMemSpace */
  954.       if (false) {
  955.         DisposePages();
  956.         HandleError(false, "Not enough memory to load story.", false);
  957.       }
  958.       if (PageCnt <= CodeEndPageNo) {
  959.         PagePtrs[PageCnt] = Malloc(signedsizeof(aPage));
  960.         memcpy(PagePtrs[PageCnt],
  961.                AGETFBUF(StoryData, StoryFileBuffer)[SubPageCnt],
  962.                signedsizeof(aPage));
  963.         if (PageCnt <= DataEndPageNo) {
  964.           DataPagePtrs[PageCnt] = Malloc(signedsizeof(aPage));
  965.           memcpy(DataPagePtrs[PageCnt],
  966.                  AGETFBUF(StoryData, StoryFileBuffer)[SubPageCnt],
  967.                  signedsizeof(aPage));
  968.         }
  969.         ++PageCnt;
  970.       }
  971.     }
  972.     GET(StoryData, StoryFileBuffer);
  973.   }
  974.   if (CodeVersion >= '3' && PageCnt < CodeEndPageNo) {
  975.     DisposePages();
  976.     HandleError(false, "Story file incomplete.", false);
  977.   }
  978.   if (!BUFEOF(StoryData)) {
  979.     PrintString("Story file too long. Story only requires");
  980.     PrintWord(CodeEndPageNo + 1, 5);
  981.     PrintString("00 bytes on disk.");
  982.     ChkWait();
  983.   }
  984.   PrintString("Loaded");
  985.   PrintWord(PageCnt, 5);
  986.   PrintString(" pages.");
  987.   ChkWait();
  988.   ChkWait();
  989.   if (StoryData != NULL)
  990.     fclose(StoryData);
  991. }  /* ReadPages */
  992.  
  993.  
  994. Static void ReloadData(void) {
  995.   int DataPageCnt;
  996.   int NumDataPages;
  997.  
  998.   DataPageCnt = 0;
  999.   NumDataPages = MiscInfo.NumReadWriteBytesHigh;
  1000.   while (DataPageCnt < NumDataPages) {
  1001.     memcpy(PagePtrs[DataPageCnt], DataPagePtrs[DataPageCnt],
  1002.            signedsizeof(aPage));
  1003.     ++DataPageCnt;
  1004.   }
  1005. }  /* ReloadData */
  1006.  
  1007.  
  1008. Static void ExecuteSubRoutine(int Address);
  1009.  
  1010.  
  1011. Static boolean ReadKey(boolean ZMachineOp, Char *Key, int TimeOut,
  1012.                        char CallEvent, int CallAddress) {
  1013.   boolean ReadKey_ReturnValue;
  1014.   Char SpecialKey;
  1015.  
  1016.   SpecialKey = '\0';
  1017.   *Key = '\0';
  1018.   ReadKey_ReturnValue = true;
  1019.   PositionCursor();
  1020.   if (ReadIndex != WriteIndex) {
  1021.     *Key = KeyBuffer[ReadIndex];
  1022.     ++ReadIndex;
  1023.     if (ReadIndex > 79)
  1024.       ReadIndex = 0;
  1025.   } else {
  1026.     do {
  1027.       *Key = ReadKeyWithNoEcho(TimeOut);
  1028.       if (ZMachineOp && *Key == '\0') {
  1029.         if (CallEvent == CallTimeOut && CallAddress > 0)
  1030.           ExecuteSubRoutine(CallAddress);
  1031.       }
  1032.     } while (*Key == '\0' && CallEvent != CallKeyPress);
  1033.   }
  1034.   if (ZMachineOp && *Key != '\0') {
  1035.     SpecialKey = '\0';
  1036.     if (*Key == UpArrow()) {
  1037.       SpecialKey = 129;
  1038.     } else if (*Key == DownArrow()) {
  1039.       SpecialKey = 130;
  1040.     } else if (*Key == LeftArrow()) {
  1041.       SpecialKey = 131;
  1042.     } else if (*Key == RightArrow()) {
  1043.       SpecialKey = 132;
  1044.     } else if (*Key == NumericSW()) {
  1045.       SpecialKey = 146;
  1046.     } else if (*Key == NumericS()) {
  1047.       SpecialKey = 147;
  1048.     } else if (*Key == NumericSE()) {
  1049.       SpecialKey = 148;
  1050.     } else if (*Key == NumericW()) {
  1051.       SpecialKey = 149;
  1052.     } else if (*Key == NumericCentre()) {
  1053.       SpecialKey = 150;
  1054.     } else if (*Key == NumericE()) {
  1055.       SpecialKey = 151;
  1056.     } else if (*Key == NumericNW()) {
  1057.       SpecialKey = 152;
  1058.     } else if (*Key == NumericN()) {
  1059.       SpecialKey = 153;
  1060.     } else if (*Key == NumericNE()) {
  1061.       SpecialKey = 154;
  1062.     } else if (IsFuncKey(*Key))
  1063.       SpecialKey = FuncKeyNo(*Key) + 132;
  1064.     if (SpecialKey != '\0') {
  1065.       ReadKey_ReturnValue = false;
  1066.       *Key = SpecialKey;
  1067.     }
  1068.   }
  1069.   if (CallEvent == CallKeyPress) {
  1070.     if (CallAddress > 0)
  1071.       ExecuteSubRoutine(CallAddress);
  1072.   }
  1073.   return ReadKey_ReturnValue;
  1074. }  /* ReadKey */
  1075.  
  1076.  
  1077. Static boolean ReadLine(boolean ZMachineOp, Char Line[256], int MaxLineLength,
  1078.                         int TimeOut, int TimeOutCallAddress) {
  1079.   int Index;
  1080.   Char Key;
  1081.   boolean Finished;
  1082.   boolean GotLine;
  1083.   int FORLIM;
  1084.  
  1085.   SaveTextAttributes();
  1086.   ScreenMode = 0;
  1087.   SetScreenMode();
  1088.   if (ZMachineOp) {
  1089.     WriteLineBuffer();
  1090.     PrintStatusLine();
  1091.     LineNo = ScrollTop;
  1092.   }
  1093.   Index = strlen(Line);
  1094.   CursorOn();
  1095.   Finished = false;
  1096.   GotLine = true;
  1097.   if (TimeOut >= 0)
  1098.     EnableTimer();
  1099.   do {
  1100.     if (!ReadKey(ZMachineOp, &Key, TimeOut, CallTimeOut, TimeOutCallAddress)) {
  1101.       Index = 1;
  1102.       Line[0] = Key;
  1103.       GotLine = false;
  1104.       Finished = true;
  1105.     }
  1106.     if (!Finished) {
  1107.       if (Key >= ' ' && Key <= '~') {
  1108.         if (Index >= MaxLineLength) {
  1109.           RingBell();
  1110.         } else {
  1111.           ScreenCh(Key);
  1112.           ++Index;
  1113.           if (ZMachineOp && isupper(Key))
  1114.             Key = _tolower(Key);
  1115.           Line[Index - 1] = Key;
  1116.         }
  1117.       } else if ((Key == Backspace()) | (Key == DeleteChar())) {
  1118.         if (Index > 0) {
  1119.           --Index;
  1120.           EraseCh();
  1121.         } else {
  1122.           RingBell();
  1123.         }
  1124.       } else if (Key == KeyToDeleteLine()) {
  1125.         for (; Index >= 1; --Index)
  1126.           EraseCh();
  1127.         Index = 0;
  1128.       } else if (Key == BreakKey && ZMachineOp) {
  1129.         RestoreTextAttributes();
  1130.         CursorOff();
  1131.         InternalError(KeyboardBreak);
  1132.       } else if (Key == EOL())
  1133.         Finished = true;
  1134.       else
  1135.         RingBell();
  1136.     }
  1137.   } while (!Finished);
  1138.   if (TimeOut >= 0)
  1139.     DisableTimer();
  1140.   SetLength(Line, Index);
  1141.   if (GotLine)
  1142.     NewLine();
  1143.   RestoreTextAttributes();
  1144.   CursorOff();
  1145.   if (!ZMachineOp)
  1146.     return GotLine;
  1147.   if (!GotLine)
  1148.     return GotLine;
  1149.   if (!PrinterEnabled())
  1150.     return GotLine;
  1151.   FORLIM = strlen(Line);
  1152.   for (Index = 1; Index <= FORLIM; ++Index)
  1153.     putc(Line[Index - 1], Printer);
  1154.   putc('\n', Printer);
  1155.   return GotLine;
  1156. }  /* ReadLine */
  1157.  
  1158.  
  1159. Static void WriteCh(Char Line[256], Char Ch) {
  1160.   int Pos;
  1161.  
  1162.   Pos = strlen(Line) + 1;
  1163.   SetLength(Line, Pos);
  1164.   Line[Pos - 1] = Ch;
  1165. }  /* WriteCh */
  1166.  
  1167.  
  1168. Static void DumpByte(Char Line[256], int Value) {
  1169.   int Expanded;
  1170.  
  1171.   Expanded = Value;
  1172.   WriteCh(Line, ' ');
  1173.   WriteCh(Line, HexChars[Nibble(Expanded, 1)]);
  1174.   WriteCh(Line, HexChars[Nibble(Expanded, 0)]);
  1175. }  /* DumpByte */
  1176.  
  1177.  
  1178. Static void AddByte(Char Line[256], int Value) {
  1179.   int Expanded;
  1180.  
  1181.   Expanded = Value;
  1182.   WriteCh(Line, HexChars[Nibble(Expanded, 1)]);
  1183.   WriteCh(Line, HexChars[Nibble(Expanded, 0)]);
  1184. }  /* AddByte */
  1185.  
  1186.  
  1187. Static void AddWord(Char Line[256], int Value) {
  1188.   int LowByte;
  1189.   int HighByte;
  1190.  
  1191.   SplitWord(Value, &LowByte, &HighByte);
  1192.   AddByte(Line, HighByte);
  1193.   AddByte(Line, LowByte);
  1194. }  /* AddWord */
  1195.  
  1196.  
  1197. Static int GetByteDC(void) {
  1198.   int GetByteDC_ReturnValue;
  1199.   int Value;
  1200.  
  1201.   ChkAddress(&DC_PageNo, &DC_PageIndex);
  1202.   Value = PagePtrs[DC_PageNo][DC_PageIndex];
  1203.   GetByteDC_ReturnValue = Value;
  1204.   Inc(&DC_PageNo, &DC_PageIndex, 1);
  1205.   if (WriteDump) {
  1206.     DumpByte(Dump, Value);
  1207.     ++DumpCnt;
  1208.   } else if (GlobalDumpState != UnpackedDump)
  1209.     DumpCnt = 11;
  1210.   return GetByteDC_ReturnValue;
  1211. }  /* GetByteDC */
  1212.  
  1213.  
  1214. Static int GetByteIPC(void) {
  1215.   int GetByteIPC_ReturnValue;
  1216.  
  1217.   ChkAddress(&IPC_PageNo, &IPC_PageIndex);
  1218.   GetByteIPC_ReturnValue = PagePtrs[IPC_PageNo][IPC_PageIndex];
  1219.   Inc(&IPC_PageNo, &IPC_PageIndex, 1);
  1220.   return GetByteIPC_ReturnValue;
  1221. }  /* GetByteIPC */
  1222.  
  1223.  
  1224. Static int GetWordDC(void) {
  1225.   int LowByte;
  1226.   int HighByte;
  1227.  
  1228.   HighByte = GetByteDC();
  1229.   LowByte = GetByteDC();
  1230.   return (JoinBytes(LowByte, HighByte));
  1231. }  /* GetWordDC */
  1232.  
  1233.  
  1234. Static int GetWordIPC(void) {
  1235.   int LowByte;
  1236.   int HighByte;
  1237.  
  1238.   HighByte = GetByteIPC();
  1239.   LowByte = GetByteIPC();
  1240.   return (JoinBytes(LowByte, HighByte));
  1241. }  /* GetWordIPC */
  1242.  
  1243.  
  1244. Static void CalcCallAddress(int Address, int *CallPageNo, int *CallPageIndex) {
  1245.   int StartPageNo;
  1246.   int StartPageIndex;
  1247.  
  1248.   *CallPageNo = 0;
  1249.   *CallPageIndex = Address;
  1250.   ShiftLeft(CallPageNo, CallPageIndex);
  1251.   if (CodeVersion >= '4') {
  1252.     ShiftLeft(CallPageNo, CallPageIndex);
  1253.     if (CodeVersion >= '6') {
  1254.       StartPageNo = MiscInfo.CodeStartPageNo;
  1255.       StartPageIndex = MiscInfo.CodeStartIndex;
  1256.       ShiftLeft(&StartPageNo, &StartPageIndex);
  1257.       ShiftLeft(&StartPageNo, &StartPageIndex);
  1258.       ShiftLeft(&StartPageNo, &StartPageIndex);
  1259.       *CallPageNo += StartPageNo;
  1260.       *CallPageIndex += StartPageIndex;
  1261.     }
  1262.   }
  1263.   ChkAddress(CallPageNo, CallPageIndex);
  1264. }  /* CalcCallAddress */
  1265.  
  1266.  
  1267. Static void StringToNumber(int *Number, anAddrString NumString) {
  1268.   int DigitCnt;
  1269.   Char HexDigit;
  1270.   int FORLIM;
  1271.  
  1272.   *Number = 0;
  1273.   FORLIM = strlen(NumString);
  1274.   for (DigitCnt = 1; DigitCnt <= FORLIM; ++DigitCnt) {
  1275.     HexDigit = NumString[DigitCnt - 1];
  1276.     if (islower(HexDigit))
  1277.       HexDigit = _toupper(HexDigit);
  1278.     if (HexDigit >= 'A')
  1279.       *Number = *Number * 16 + HexDigit - 'A' + 10;
  1280.     else
  1281.       *Number = *Number * 16 + HexDigit - '0';
  1282.   }
  1283. }  /* StringToNumber */
  1284.  
  1285.  
  1286. Static void WriteText(Char TextType, char OutputType, char SourceType,
  1287.                       Char TextBuffer[256]);
  1288.  
  1289. /* Local variables for WriteText: */
  1290. struct WriteText_LocalVariables {
  1291.   Char TextType;
  1292.   char OutputType;
  1293.   char SourceType;
  1294.   Char *TextBuffer;
  1295.   jmp_buf _JL888;
  1296.   int ChByte;
  1297.   int ChType;
  1298.   int ChBuffer;
  1299.   int ChCnt;
  1300.   int PackIndex;
  1301.   int LineIndex;
  1302.   int LineLength;
  1303.   boolean TextEnd;
  1304.   int Three;
  1305.   int ThreeLow;
  1306.   int ThreeHigh;
  1307.   /* PACKED RECORD CASE Integer OF
  1308.    1:(Word:Integer);
  1309.    2:(Chars:PACKED ARRAY [0..2] OF 0..31);
  1310.    3:(PackedChars:0..32767;
  1311.       TextEnd:Boolean)
  1312.   END; */
  1313.   Char TextLine[256];
  1314.   int StartIndex;
  1315.   int StartPageNo;
  1316.   boolean OldWriteDump;
  1317.   boolean IsVocabulary;
  1318.   boolean Error;
  1319. } ;
  1320.  
  1321. Local void HandleEndOfText(struct WriteText_LocalVariables *WriteText_Vars);
  1322.  
  1323. Local void GetCh(int *Ch, boolean *TextEnd,
  1324.                  struct WriteText_LocalVariables *WriteText_Vars) {
  1325.   if (*TextEnd) {
  1326.     HandleEndOfText(WriteText_Vars);
  1327.     longjmp(WriteText_Vars->_JL888, 1);
  1328.   }
  1329.   if (WriteText_Vars->PackIndex == 0) {
  1330.     if (WriteText_Vars->SourceType == FromIPC)
  1331.       WriteText_Vars->Three = GetWordIPC();
  1332.     else
  1333.       WriteText_Vars->Three = GetWordDC();
  1334.     SplitWord(WriteText_Vars->Three, &WriteText_Vars->ThreeLow,
  1335.               &WriteText_Vars->ThreeHigh);
  1336.     *Ch = land(lsr(WriteText_Vars->ThreeHigh, 2), 31);
  1337.   } else if (WriteText_Vars->PackIndex == 1) {
  1338.     *Ch = lor(land(lsr(WriteText_Vars->ThreeLow, 5), 7),
  1339.               lsl(land(WriteText_Vars->ThreeHigh, 3), 3));
  1340.   } else {
  1341.     *Ch = land(WriteText_Vars->ThreeLow, 31);
  1342.     *TextEnd = TstBit(WriteText_Vars->Three, 15);
  1343.     WriteText_Vars->PackIndex = -1;
  1344.   }
  1345.   ++WriteText_Vars->PackIndex;
  1346.   if (WriteText_Vars->IsVocabulary) {
  1347.     WriteText_Vars->Error = !*TextEnd;
  1348.     ++WriteText_Vars->ChCnt;
  1349.     *TextEnd = (WriteText_Vars->ChCnt == WordNumChars);
  1350.   }
  1351.   if (GlobalDumpState == UnpackedDump) {
  1352.     DumpByte(Dump, *Ch);
  1353.     ++DumpCnt;
  1354.   }
  1355. }  /* GetCh */
  1356.  
  1357. Local int GetBuffer(struct WriteText_LocalVariables *WriteText_Vars) {
  1358.   int GetBuffer_ReturnValue;
  1359.  
  1360.   if (WriteText_Vars->ChType > 127)
  1361.     return WriteText_Vars->ChBuffer;
  1362.   GetBuffer_ReturnValue = WriteText_Vars->ChType;
  1363.   WriteText_Vars->ChType = 255;
  1364.   return GetBuffer_ReturnValue;
  1365. }  /* GetCnt */
  1366.  
  1367. Local void DumpText(struct WriteText_LocalVariables *WriteText_Vars) {
  1368.   int SpaceCnt;
  1369.   int NumSpaces;
  1370.  
  1371.   SetLength(WriteText_Vars->TextLine, WriteText_Vars->LineIndex);
  1372.   if (WriteText_Vars->OutputType == OntoScreen) {
  1373.     PrintCh(WriteText_Vars->TextType);
  1374.     PrintWord(WriteText_Vars->StartPageNo, 5);
  1375.     PrintByte(WriteText_Vars->StartIndex, 2);
  1376.     PrintCh(':');
  1377.     PrintString(Dump);
  1378.     if (*WriteText_Vars->TextLine != '\0') {
  1379.       if (GlobalDumpState > CodeDump)
  1380.         NumSpaces = (12 - DumpCnt) * 3;
  1381.       else
  1382.         NumSpaces = 3;
  1383.       for (SpaceCnt = 1; SpaceCnt <= NumSpaces; ++SpaceCnt)
  1384.         PrintCh(' ');
  1385.       PrintCh('|');
  1386.       PrintString(WriteText_Vars->TextLine);
  1387.       PrintCh('|');
  1388.     }
  1389.     if (WriteText_Vars->SourceType == FromDC) {
  1390.       WriteText_Vars->StartPageNo = DC_PageNo;
  1391.       WriteText_Vars->StartIndex = DC_PageIndex;
  1392.     } else {
  1393.       WriteText_Vars->StartPageNo = IPC_PageNo;
  1394.       WriteText_Vars->StartIndex = IPC_PageIndex;
  1395.     }
  1396.     ChkWait();
  1397.   } else {
  1398.     strcat(WriteText_Vars->TextBuffer, WriteText_Vars->TextLine);
  1399.   }
  1400.   WriteText_Vars->LineIndex = 0;
  1401.   *Dump = '\0';
  1402.   DumpCnt = 0;
  1403. }  /* DumpText */
  1404.  
  1405. Local void PutCh(Char Ch, struct WriteText_LocalVariables *WriteText_Vars) {
  1406.   int ChrCnt;
  1407.   Char ByteString[256];
  1408.   int FORLIM;
  1409.  
  1410.   if (WriteText_Vars->OutputType == ToStoryOutput) {
  1411.     PutChToStoryOutput(Ch);
  1412.     return;
  1413.   }
  1414.   if (Ch == EOL()) {
  1415.     DumpText(WriteText_Vars);
  1416.     return;
  1417.   }
  1418.   if (DumpCnt > 11 || WriteText_Vars->LineIndex > WriteText_Vars->LineLength)
  1419.     DumpText(WriteText_Vars);
  1420.   ++WriteText_Vars->LineIndex;
  1421.   if (Ch >= ' ' && Ch <= '~') {
  1422.     WriteText_Vars->TextLine[WriteText_Vars->LineIndex - 1] = Ch;
  1423.     return;
  1424.   }
  1425.   PutCh('(', WriteText_Vars);
  1426.   *ByteString = '\0';
  1427.   AddByte(ByteString, Ch);
  1428.   FORLIM = strlen(ByteString);
  1429.   for (ChrCnt = 1; ChrCnt <= FORLIM; ++ChrCnt)
  1430.     PutCh(ByteString[ChrCnt - 1], WriteText_Vars);
  1431.   PutCh(')', WriteText_Vars);
  1432. }  /* PutCh */
  1433.  
  1434. Local void HandleEndOfText(struct WriteText_LocalVariables *WriteText_Vars) {
  1435.   if (WriteText_Vars->LineIndex > 0 ||
  1436.       *Dump != '\0' && GlobalDumpState == UnpackedDump)
  1437.     DumpText(WriteText_Vars);
  1438.   if (WriteText_Vars->IsVocabulary) {
  1439.     if (WriteText_Vars->Error)
  1440.       strcat(WriteText_Vars->TextBuffer, "E");
  1441.   }
  1442.   WriteDump = WriteText_Vars->OldWriteDump;
  1443. }  /* HandleEndOfText */
  1444.  
  1445. Local void WriteSpecialText(struct WriteText_LocalVariables *WriteText_Vars) {
  1446.   int SpecialNo;
  1447.   int AdrsPageNo;
  1448.   int AdrsIndex;
  1449.   int ChrCnt;
  1450.   Char SpecialBuffer[256];
  1451.   int FORLIM;
  1452.  
  1453.   GetCh(&SpecialNo, &WriteText_Vars->TextEnd, WriteText_Vars);
  1454.   AdrsIndex = SpecialNo * 2 + (WriteText_Vars->ChByte - 1) * 64 +
  1455.               MiscInfo.SpecialIndex;
  1456.   AdrsPageNo = MiscInfo.SpecialPageNo;
  1457.   ChkAddress(&AdrsPageNo, &AdrsIndex);
  1458.   if (GlobalDumpState > CodeDump) {
  1459.     if (WriteText_Vars->LineIndex > 0 || *Dump != '\0')
  1460.       DumpText(WriteText_Vars);
  1461.   }
  1462.   Push(DC_PageNo);
  1463.   Push(DC_PageIndex);
  1464.   DC_PageNo = AdrsPageNo;
  1465.   DC_PageIndex = AdrsIndex;
  1466.   AdrsPageNo = GetByteDC() * 2;
  1467.   AdrsIndex = GetByteDC() * 2;
  1468.   ChkAddress(&AdrsPageNo, &AdrsIndex);
  1469.   DC_PageNo = AdrsPageNo;
  1470.   DC_PageIndex = AdrsIndex;
  1471.   if (WriteText_Vars->OutputType == ToStoryOutput) {
  1472.     WriteText('S', ToStoryOutput, FromDC, SpecialBuffer);
  1473.   } else {
  1474.     WriteText('S', IntoBuffer, FromDC, SpecialBuffer);
  1475.     FORLIM = strlen(SpecialBuffer);
  1476.     for (ChrCnt = 1; ChrCnt <= FORLIM; ++ChrCnt)
  1477.       PutCh(SpecialBuffer[ChrCnt - 1], WriteText_Vars);
  1478.   }
  1479.   WriteText_Vars->ChType = 255;
  1480.   if (GlobalDumpState > CodeDump) {
  1481.     *Dump = '\0';
  1482.     DumpCnt = 0;
  1483.     WriteText_Vars->StartPageNo = AdrsPageNo;
  1484.     WriteText_Vars->StartIndex = AdrsIndex;
  1485.   }
  1486.   DC_PageIndex = Pop();
  1487.   DC_PageNo = Pop();
  1488. }  /* WriteSpecialText */
  1489.  
  1490.  
  1491. Static void WriteText(Char TextType_, char OutputType_, char SourceType_,
  1492.                       Char TextBuffer_[256]) {
  1493.   struct WriteText_LocalVariables V;
  1494.   int Buffer;
  1495.   int PreviousCh;
  1496.  
  1497.   V.TextType = TextType_;
  1498.   V.OutputType = OutputType_;
  1499.   V.SourceType = SourceType_;
  1500.   V.TextBuffer = TextBuffer_;
  1501.   if (setjmp(V._JL888))
  1502.     goto _L888;
  1503.   V.OldWriteDump = WriteDump;
  1504.   *V.TextBuffer = '\0';
  1505.   WriteDump = (GlobalDumpState == TextDump && V.OutputType != ToStoryOutput);
  1506.   V.PackIndex = 0;
  1507.   V.LineIndex = 0;
  1508.   *Dump = '\0';
  1509.   DumpCnt = 0;
  1510.   V.TextEnd = false;
  1511.   V.ChCnt = 0;
  1512.   if (V.SourceType == FromDC) {
  1513.     V.StartPageNo = DC_PageNo;
  1514.     V.StartIndex = DC_PageIndex;
  1515.   } else {
  1516.     V.StartPageNo = IPC_PageNo;
  1517.     V.StartIndex = IPC_PageIndex;
  1518.   }
  1519.   V.ChBuffer = 0;
  1520.   V.ChType = 255;
  1521.   V.IsVocabulary = (V.TextType == 'V');
  1522.   V.Error = false;
  1523.   if (GlobalDumpState > CodeDump)
  1524.     V.LineLength = 20;
  1525.   else
  1526.     V.LineLength = 64;
  1527.   do {
  1528.     GetCh(&V.ChByte, &V.TextEnd, &V);
  1529.     if (V.ChByte == 0) {
  1530.       PutCh(' ', &V);
  1531.     } else if (CodeVersion <= '2') {
  1532.       if (V.ChByte == 1) {
  1533.         if (CodeVersion == '1')
  1534.           PutCh(EOL(), &V);
  1535.         else
  1536.           WriteSpecialText(&V);
  1537.       } else if (V.ChByte < 4) {
  1538.         Buffer = GetBuffer(&V) + V.ChByte + 2;
  1539.         while (Buffer >= 3)
  1540.           Buffer -= 3;
  1541.         V.ChType = Buffer;
  1542.       } else if (V.ChByte < 6) {
  1543.         Buffer = GetBuffer(&V) + V.ChByte;
  1544.         while (Buffer >= 3)
  1545.           Buffer -= 3;
  1546.         V.ChBuffer = Buffer;
  1547.       } else {
  1548.         Buffer = GetBuffer(&V);
  1549.         if (Buffer == 0) {
  1550.           PutCh(V.ChByte + 91, &V);
  1551.         } else if (Buffer == 1) {
  1552.           PutCh(V.ChByte + 59, &V);
  1553.         } else {
  1554.           Buffer = V.ChByte - 7;
  1555.           if (Buffer == 0 && CodeVersion == '2') {
  1556.             PutCh(EOL(), &V);
  1557.           } else if (Buffer < 0) {
  1558.             GetCh(&V.ChByte, &V.TextEnd, &V);
  1559.             GetCh(&Buffer, &V.TextEnd, &V);
  1560.             Buffer = lor(land(V.ChByte * 32, 255), Buffer);
  1561.             if (Buffer == 9 && CodeVersion == '1')
  1562.               PutCh(' ', &V);
  1563.             else
  1564.               PutCh(Buffer, &V);
  1565.           } else if (CodeVersion == '1')
  1566.             PutCh(Char1Table[Buffer], &V);
  1567.           else
  1568.             PutCh(Char23Table[Buffer - 1], &V);
  1569.         }
  1570.       }
  1571.     } else if (CodeVersion >= '3') {
  1572.       if (V.ChByte < 4) {
  1573.         WriteSpecialText(&V);
  1574.       } else if (V.ChByte < 6) {
  1575.         Buffer = V.ChByte - 3;
  1576.         PreviousCh = GetBuffer(&V);
  1577.         if (PreviousCh == 0 && (Buffer == 0 || V.ChType > 127)) {
  1578.           V.ChType = Buffer;
  1579.         } else {
  1580.           V.ChBuffer = Buffer;
  1581.           if (PreviousCh != V.ChBuffer)
  1582.             V.ChBuffer = 0;
  1583.         }
  1584.       } else {
  1585.         PreviousCh = GetBuffer(&V);
  1586.         if (PreviousCh == 0) {
  1587.           PutCh(V.ChByte + 91, &V);
  1588.         } else if (PreviousCh == 1) {
  1589.           PutCh(V.ChByte + 59, &V);
  1590.         } else {
  1591.           Buffer = V.ChByte - 7;
  1592.           if (Buffer < 0) {
  1593.             GetCh(&V.ChByte, &V.TextEnd, &V);
  1594.             GetCh(&Buffer, &V.TextEnd, &V);
  1595.             PutCh(lor(land(V.ChByte * 32, 255), Buffer), &V);
  1596.           } else if (Buffer == 0)
  1597.             PutCh(EOL(), &V);
  1598.           else
  1599.             PutCh(Char23Table[Buffer - 1], &V);
  1600.         }
  1601.       }
  1602.     }
  1603.   } while (!V.TextEnd);
  1604.   HandleEndOfText(&V);
  1605. _L888: ;
  1606. }  /* WriteText */
  1607.  
  1608.  
  1609. Static boolean CodeCorrect(ShortInteger *CodeChkSum) {
  1610.   ShortInteger ChkSum;
  1611.   int NumDataPages;
  1612.   int PageCnt;
  1613.   int ByteCnt;
  1614.   int ChkSumLow;
  1615.   int ChkSumHigh;
  1616.   uchar *ChkPagePtr;
  1617.  
  1618.   ChkSum = 0;
  1619.   NumDataPages = MiscInfo.NumReadWriteBytesHigh;
  1620.   ChkPagePtr = DataPagePtrs[0];
  1621.   ByteCnt = 64;
  1622.   while (ByteCnt < 256) {
  1623.     ChkSum += ChkPagePtr[ByteCnt];
  1624.     ++ByteCnt;
  1625.   }
  1626.   PageCnt = 1;
  1627.   while (PageCnt < CodeEndPageNo) {
  1628.     if (PageCnt <= NumDataPages)
  1629.       ChkPagePtr = DataPagePtrs[PageCnt];
  1630.     else
  1631.       ChkPagePtr = PagePtrs[PageCnt];
  1632.     ByteCnt = 0;
  1633.     while (ByteCnt < 256) {
  1634.       ChkSum += ChkPagePtr[ByteCnt];
  1635.       ++ByteCnt;
  1636.     }
  1637.     ++PageCnt;
  1638.   }
  1639.   ByteCnt = 0;
  1640.   ChkPagePtr = PagePtrs[CodeEndPageNo];
  1641.   while (ByteCnt < CodeEndPageIndex) {
  1642.     ChkSum += ChkPagePtr[ByteCnt];
  1643.     ++ByteCnt;
  1644.   }
  1645.   *CodeChkSum = ChkSum;
  1646.   SplitWord(ChkSum, &ChkSumLow, &ChkSumHigh);
  1647.   return (ChkSumLow == MiscInfo.ChkSumLow && ChkSumHigh == MiscInfo.ChkSumHigh);
  1648. }  /* CodeCorrect */
  1649.  
  1650.  
  1651. Static void SaveEntryPoint(int EntryAddress) {
  1652.   int EntryCnt;
  1653.  
  1654.   if (!SaveEntryPoints)
  1655.     return;
  1656.   EntryAddress = land(EntryAddress, 65535);
  1657.   EntryCnt = EntryIndex - 1;
  1658.   while (EntryCnt >= 0 && EntryPoints[EntryCnt] != EntryAddress)
  1659.     --EntryCnt;
  1660.   if (EntryCnt >= 0)
  1661.     return;
  1662.   if (EntryIndex <= MaxEntryPointCnt) {
  1663.     EntryPoints[EntryIndex] = EntryAddress;
  1664.     ++EntryIndex;
  1665.     return;
  1666.   }
  1667.   PrintString("Warning: No more room to save entry points");
  1668.   RingBell();
  1669.   NewLine();
  1670. }  /* SaveEntryPoint */
  1671.  
  1672.  
  1673. Static void RemoveEntry(int EntryPageNo, int EntryPageIndex) {
  1674.   int EntryCnt;
  1675.   int PageNo;
  1676.   int PageIndex;
  1677.   boolean Found;
  1678.  
  1679.   EntryCnt = EntryIndex - 1;
  1680.   Found = false;
  1681.   while (!Found && EntryCnt >= 0) {
  1682.     CalcCallAddress(EntryPoints[EntryCnt], &PageNo, &PageIndex);
  1683.     if (PageNo == EntryPageNo && PageIndex == EntryPageIndex)
  1684.       Found = true;
  1685.     else
  1686.       --EntryCnt;
  1687.   }
  1688.   if (!Found) {
  1689.     PrintString("Error: Entry point not found:");
  1690.     PrintWord(EntryPageNo, 5);
  1691.     PrintByte(EntryPageIndex, 2);
  1692.     ChkWait();
  1693.     return;
  1694.   }
  1695.   ++EntryCnt;
  1696.   while (EntryCnt < EntryIndex) {
  1697.     EntryPoints[EntryCnt - 1] = EntryPoints[EntryCnt];
  1698.     ++EntryCnt;
  1699.   }
  1700.   --EntryIndex;
  1701. }  /* RemoveEntry */
  1702.  
  1703.  
  1704. Static void DisRegList(int NumRegsToInit) {
  1705.   boolean OldWriteDump;
  1706.   int RegCnt;
  1707.   int RegValue;
  1708.   int FirstPage;
  1709.   int FirstIndex;
  1710.   int AddressPageNo;
  1711.   int AddressIndex;
  1712.   int CodeStartPageNo;
  1713.   int CodeStartPageIndex;
  1714.   int EntryAddress;
  1715.   Char RegLine[256];
  1716.  
  1717.   FirstPage = DC_PageNo;
  1718.   FirstIndex = DC_PageIndex - 1;
  1719.   if (FirstIndex < 0) {
  1720.     FirstIndex += 256;
  1721.     --FirstPage;
  1722.   }
  1723.   if ((FirstIndex & 1) != 0 || CodeVersion >= '4' && (FirstIndex & 3) != 0) {
  1724.     PrintString("Error: Illegal entry point.");
  1725.     RingBell();
  1726.     NewLine();
  1727.     longjmp(_JL999, 1);
  1728.   }
  1729.   if (NumRegsToInit > 15) {
  1730.     PrintString("Error: Too much register data:");
  1731.     PrintByte(NumRegsToInit, 3);
  1732.     RingBell();
  1733.     NewLine();
  1734.     longjmp(_JL999, 1);
  1735.   }
  1736.   OldWriteDump = WriteDump;
  1737.   WriteDump = false;
  1738.   AddressPageNo = FirstPage;
  1739.   AddressIndex = FirstIndex;
  1740.   if (CodeVersion >= '6') {
  1741.     CodeStartPageNo = MiscInfo.CodeStartPageNo;
  1742.     CodeStartPageIndex = MiscInfo.CodeStartIndex;
  1743.     ShiftLeft(&CodeStartPageNo, &CodeStartPageIndex);
  1744.     ShiftLeft(&CodeStartPageNo, &CodeStartPageIndex);
  1745.     ShiftLeft(&CodeStartPageNo, &CodeStartPageIndex);
  1746.     AddressPageNo -= CodeStartPageNo;
  1747.     AddressIndex -= CodeStartPageIndex;
  1748.     ChkAddress(&AddressPageNo, &AddressIndex);
  1749.   }
  1750.   ShiftRight(&AddressPageNo, &AddressIndex);
  1751.   if (CodeVersion >= '4')
  1752.     ShiftRight(&AddressPageNo, &AddressIndex);
  1753.   EntryAddress = JoinBytes(AddressIndex, AddressPageNo);
  1754.   SaveEntryPoint(EntryAddress);
  1755.   if (CodeVersion < '5') {
  1756.     RegCnt = 0;
  1757.     do {
  1758.       ++RegCnt;
  1759.       if (RegCnt == 1 || strlen(RegLine) + 5 > ScreenWidth) {
  1760.         if (RegCnt > 1) {
  1761.           PrintString(RegLine);
  1762.           ChkWait();
  1763.         }
  1764.         strcpy(RegLine, "R");
  1765.         WriteCh(RegLine, ' ');
  1766.         if (RegCnt > 1) {
  1767.           AddWord(RegLine, DC_PageNo);
  1768.           AddByte(RegLine, DC_PageIndex);
  1769.         } else {
  1770.           AddWord(RegLine, FirstPage);
  1771.           AddByte(RegLine, FirstIndex);
  1772.         }
  1773.         strcat(RegLine, ":");
  1774.         strcat(RegLine, " ");
  1775.         if (RegCnt > 1) {
  1776.           strcat(RegLine, " ");
  1777.           strcat(RegLine, " ");
  1778.         } else {
  1779.           AddByte(RegLine, NumRegsToInit);
  1780.         }
  1781.         WriteCh(RegLine, ' ');
  1782.       }
  1783.       if (RegCnt <= NumRegsToInit) {
  1784.         RegValue = GetWordDC();
  1785.         AddWord(RegLine, RegValue);
  1786.         WriteCh(RegLine, ' ');
  1787.       }
  1788.     } while (RegCnt < NumRegsToInit);
  1789.   } else {
  1790.     strcpy(RegLine, "R");
  1791.     WriteCh(RegLine, ' ');
  1792.     AddWord(RegLine, FirstPage);
  1793.     AddByte(RegLine, FirstIndex);
  1794.     strcat(RegLine, ":");
  1795.     strcat(RegLine, " ");
  1796.     AddByte(RegLine, NumRegsToInit);
  1797.   }
  1798.   PrintString(RegLine);
  1799.   ChkWait();
  1800.   WriteDump = OldWriteDump;
  1801. }  /* DisRegList */
  1802.  
  1803.  
  1804. Static void GetJump(char SourceType, boolean *TrueJump, int *Distance) {
  1805.   int Offset;
  1806.   int HighByte;
  1807.   int LowByte;
  1808.  
  1809.   if (SourceType == FromDC)
  1810.     Offset = GetByteDC();
  1811.   else
  1812.     Offset = GetByteIPC();
  1813.   *TrueJump = cTrueJump(Offset);
  1814.   if (cShort(Offset)) {
  1815.     Offset = cDistance(Offset);
  1816.   } else {
  1817.     HighByte = cDistance(Offset);
  1818.     if (SourceType == FromDC)
  1819.       LowByte = GetByteDC();
  1820.     else
  1821.       LowByte = GetByteIPC();
  1822.     Offset = JoinBytes(LowByte, HighByte);
  1823.     if (TstBit(Offset, 13))
  1824.       Offset = lor(Offset, -16384);
  1825.   }
  1826.   *Distance = Offset;
  1827. }  /* GetJump */
  1828.  
  1829.  
  1830. Static void CalcJump(int FromPageNo, int FromPageIndex, int *ToPageNo,
  1831.                      int *ToPageIndex, int Offset) {
  1832.   int DestPageNo;
  1833.   int DestIndex;
  1834.   int HighByte;
  1835.   int LowByte;
  1836.  
  1837.   SplitWord(Offset - 2, &LowByte, &HighByte);
  1838.   if (CodeVersion < '4')
  1839.     DestPageNo = lsl(HighByte, 1);
  1840.   else
  1841.     DestPageNo = lsl(HighByte, 2);
  1842.   DestPageNo = lor(land(DestPageNo, HighByteMask), HighByte);
  1843.   DestIndex = FromPageIndex + LowByte;
  1844.   while (DestIndex >= 256) {
  1845.     DestIndex -= 256;
  1846.     ++DestPageNo;
  1847.   }
  1848.   while (DestIndex < 0) {
  1849.     DestIndex += 256;
  1850.     --DestPageNo;
  1851.   }
  1852.   DestPageNo += FromPageNo;
  1853.   if (CodeVersion < '4')
  1854.     DestPageNo = land(DestPageNo, 511);
  1855.   else
  1856.     DestPageNo = land(DestPageNo, 1023);
  1857.   *ToPageNo = DestPageNo;
  1858.   *ToPageIndex = DestIndex;
  1859. }  /* CalcJump */
  1860.  
  1861.  
  1862. Static void PutBPTCode(PtrBPT WrkBPT) {
  1863.   int PageNo;
  1864.   int PageIndex;
  1865.  
  1866.   PageNo = WrkBPT->BPT_PageNo;
  1867.   PageIndex = WrkBPT->BPT_PageIndex;
  1868.   WrkBPT->OrgByte1 = PagePtrs[PageNo][PageIndex];
  1869.   PagePtrs[PageNo][PageIndex] = 0;   /* BPT #xx #xx */
  1870.   Inc(&PageNo, &PageIndex, 1);
  1871.   WrkBPT->OrgByte2 = PagePtrs[PageNo][PageIndex];
  1872.   PagePtrs[PageNo][PageIndex] = WrkBPT->BPT_No;
  1873.   Inc(&PageNo, &PageIndex, 1);
  1874.   WrkBPT->OrgByte3 = PagePtrs[PageNo][PageIndex];
  1875.   PagePtrs[PageNo][PageIndex] = WrkBPT->BPT_Type;
  1876. }  /* PutBPTCode */
  1877.  
  1878.  
  1879. Static void PutOrgCode(PtrBPT WrkBPT) {
  1880.   int PageNo;
  1881.   int PageIndex;
  1882.  
  1883.   PageNo = WrkBPT->BPT_PageNo;
  1884.   PageIndex = WrkBPT->BPT_PageIndex;
  1885.   PagePtrs[PageNo][PageIndex] = WrkBPT->OrgByte1;
  1886.   Inc(&PageNo, &PageIndex, 1);
  1887.   PagePtrs[PageNo][PageIndex] = WrkBPT->OrgByte2;
  1888.   Inc(&PageNo, &PageIndex, 1);
  1889.   PagePtrs[PageNo][PageIndex] = WrkBPT->OrgByte3;
  1890. }  /* PutOrgCode */
  1891.  
  1892.  
  1893. Static void SetBPT(int BPT_No, int BPT_PageNo, int BPT_PageIndex,
  1894.                    char BPT_Type) {
  1895.   PtrBPT NewBPT;
  1896.  
  1897.   ++BPT_IdCnt;
  1898.   NewBPT = Malloc(signedsizeof(aBPT));
  1899.   NewBPT->BPT_No = BPT_No;
  1900.   NewBPT->HitCnt = 0;
  1901.   NewBPT->BPT_PageNo = BPT_PageNo;
  1902.   NewBPT->BPT_PageIndex = BPT_PageIndex;
  1903.   NewBPT->BPT_Type = BPT_Type;
  1904.   NewBPT->NextBPT = BPT_List;
  1905.   BPT_List = NewBPT;
  1906.   PutBPTCode(NewBPT);
  1907. }  /* SetBPT */
  1908.  
  1909.  
  1910. Static void ClearBPT(int BPT_No) {
  1911.   PtrBPT WrkBPT;
  1912.   PtrBPT PredBPT;
  1913.   boolean Cleared;
  1914.  
  1915.   Cleared = false;
  1916.   WrkBPT = BPT_List;
  1917.   PredBPT = NULL;
  1918.   while (WrkBPT != NULL) {
  1919.     if (WrkBPT->BPT_No != BPT_No) {
  1920.       PredBPT = WrkBPT;
  1921.       WrkBPT = WrkBPT->NextBPT;
  1922.       continue;
  1923.     }
  1924.     PutOrgCode(WrkBPT);
  1925.     if (PredBPT == NULL)
  1926.       BPT_List = WrkBPT->NextBPT;
  1927.     else
  1928.       PredBPT->NextBPT = WrkBPT->NextBPT;
  1929.     Free(WrkBPT);
  1930.     WrkBPT = NULL;
  1931.     Cleared = true;
  1932.   }
  1933.   if (!Cleared)
  1934.     HandleError(false, "Break-point not found.", false);
  1935. }  /* ClearBPT */
  1936.  
  1937.  
  1938. Static void PrintBPTs(void) {
  1939.   PtrBPT WrkBPT;
  1940.  
  1941.   PrintString("Current BPT-Id:");
  1942.   PrintByte(BPT_IdCnt, 3);
  1943.   ChkWait();
  1944.   WrkBPT = BPT_List;
  1945.   while (WrkBPT != NULL) {
  1946.     PrintWord(WrkBPT->BPT_PageNo, 4);
  1947.     PrintByte(WrkBPT->BPT_PageIndex, 2);
  1948.     PrintString(": BPT #");
  1949.     PrintByte(WrkBPT->BPT_No, 2);
  1950.     PrintString(" hits=");
  1951.     PrintWord(WrkBPT->HitCnt, 4);
  1952.     switch (WrkBPT->BPT_Type) {
  1953.  
  1954.     case UndefinedBPT:
  1955.       PrintString(" undefined");
  1956.       break;
  1957.  
  1958.     case UserBPT:
  1959.       PrintString(" user");
  1960.       break;
  1961.  
  1962.     case RunBPT:
  1963.       PrintString(" run");
  1964.       break;
  1965.  
  1966.     case TraceBPT:
  1967.       PrintString(" trace");
  1968.       break;
  1969.     }
  1970.     ChkWait();
  1971.     WrkBPT = WrkBPT->NextBPT;
  1972.   }
  1973. }  /* PrintBPTs */
  1974.  
  1975.  
  1976. typedef Char MnemString[256];
  1977.  
  1978.  
  1979. /* Local variables for Disassemble: */
  1980. struct Disassemble_LocalVariables {
  1981.   boolean GetCmdCode;
  1982.   boolean DumpText;
  1983.   boolean NextCouldBeEntryPoint;
  1984.   boolean NextShouldBeEntryPoint;
  1985.   boolean InstIsBPT;
  1986.   Char CmdLine[256];
  1987. } ;
  1988.  
  1989. Local void WriteAddressMode(Char Line[256], int AddressMode,
  1990.    struct Disassemble_LocalVariables *Disassemble_Vars) {
  1991.   if (!Disassemble_Vars->GetCmdCode) {
  1992.     strcat(Line, "Rx");
  1993.     return;
  1994.   }
  1995.   if (AddressMode == 0) {
  1996.     WriteCh(Line, 'S');
  1997.     return;
  1998.   }
  1999.   if (AddressMode < 16) {
  2000.     WriteCh(Line, 'R');
  2001.     WriteCh(Line, HexChars[Nibble(AddressMode - 1, 0)]);
  2002.   } else {
  2003.     WriteCh(Line, '*');
  2004.     AddWord(Line, (AddressMode - 16) * 2);
  2005.   }
  2006. }  /* WriteAddressMode */
  2007.  
  2008. Local void DisAddressMode(boolean Load, boolean Indirect,
  2009.    struct Disassemble_LocalVariables *Disassemble_Vars) {
  2010.   int AddressMode;
  2011.  
  2012.   if (Disassemble_Vars->GetCmdCode)
  2013.     AddressMode = GetByteDC();
  2014.   if (!Load) {
  2015.     strcat(Disassemble_Vars->CmdLine, "->");
  2016.     strcat(Disassemble_Vars->CmdLine, " ");
  2017.   }
  2018.   if (Indirect)
  2019.     WriteCh(Disassemble_Vars->CmdLine, '(');
  2020.   if (Disassemble_Vars->GetCmdCode) {
  2021.     if (AddressMode == 0) {
  2022.       if (Load)
  2023.         WriteCh(Disassemble_Vars->CmdLine, '-');
  2024.       else
  2025.         WriteCh(Disassemble_Vars->CmdLine, '+');
  2026.     }
  2027.     WriteAddressMode(Disassemble_Vars->CmdLine, AddressMode, Disassemble_Vars);
  2028.   } else {
  2029.     strcat(Disassemble_Vars->CmdLine, "Rx");
  2030.   }
  2031.   if (Indirect)
  2032.     WriteCh(Disassemble_Vars->CmdLine, ')');
  2033. }  /* DisAddressMode */
  2034.  
  2035. Local void WriteJump(int Distance,
  2036.                      struct Disassemble_LocalVariables *Disassemble_Vars) {
  2037.   int DestPageNo;
  2038.   int DestIndex;
  2039.  
  2040.   if (!Disassemble_Vars->GetCmdCode)
  2041.     return;
  2042.   CalcJump(DC_PageNo, DC_PageIndex, &DestPageNo, &DestIndex, Distance);
  2043.   AddWord(Disassemble_Vars->CmdLine, DestPageNo);
  2044.   AddByte(Disassemble_Vars->CmdLine, DestIndex);
  2045. }  /* WriteJump */
  2046.  
  2047. Local void DisJump(struct Disassemble_LocalVariables *Disassemble_Vars) {
  2048.   int Distance;
  2049.   boolean TrueJump;
  2050.  
  2051.   if (!Disassemble_Vars->GetCmdCode)
  2052.     return;
  2053.   GetJump(FromDC, &TrueJump, &Distance);
  2054.   if (TrueJump)
  2055.     strcat(Disassemble_Vars->CmdLine, "TJP");
  2056.   else
  2057.     strcat(Disassemble_Vars->CmdLine, "FJP");
  2058.   strcat(Disassemble_Vars->CmdLine, " ");
  2059.   if (Distance == 0) {
  2060.     strcat(Disassemble_Vars->CmdLine, "RTF");
  2061.     return;
  2062.   }
  2063.   if (Distance == 1)
  2064.     strcat(Disassemble_Vars->CmdLine, "RTT");
  2065.   else
  2066.     WriteJump(Distance, Disassemble_Vars);
  2067. }  /* DisJump */
  2068.  
  2069. Local void IllegalCmd(struct Disassemble_LocalVariables *Disassemble_Vars) {
  2070.   Char Mnem[256];
  2071.  
  2072.   strcpy(Mnem, "$");
  2073.   AddByte(Mnem, CmdCode);
  2074.   if (*Disassemble_Vars->CmdLine == '\0')
  2075.     strcpy(Disassemble_Vars->CmdLine, " ");
  2076.   strinsert(Mnem, (void *)Disassemble_Vars->CmdLine, 1);
  2077.   Disassemble_Vars->NextCouldBeEntryPoint = true;
  2078.   Disassemble_Vars->NextShouldBeEntryPoint = (CmdCode == 0);
  2079. }  /* IllegalCmd */
  2080.  
  2081. Local void HandleEntryAddress(int EntryAddress,
  2082.    struct Disassemble_LocalVariables *Disassemble_Vars) {
  2083.   int PageNo;
  2084.   int PageIndex;
  2085.  
  2086.   WriteCh(Disassemble_Vars->CmdLine, '#');
  2087.   SaveEntryPoint(EntryAddress);
  2088.   CalcCallAddress(EntryAddress, &PageNo, &PageIndex);
  2089.   AddWord(Disassemble_Vars->CmdLine, PageNo);
  2090.   AddByte(Disassemble_Vars->CmdLine, PageIndex);
  2091. }  /* HandleEntryAddress */
  2092.  
  2093. Local void CheckIfRegList(struct Disassemble_LocalVariables *Disassemble_Vars) {
  2094.   int EntryCnt;
  2095.   int ListPageNo;
  2096.   int ListIndex;
  2097.   int AddressPageNo;
  2098.   int AddressIndex;
  2099.   int Value1;
  2100.   int Value2;
  2101.   int Code;
  2102.   boolean GotRegList;
  2103.   boolean FetchedNext;
  2104.  
  2105.   GotRegList = false;
  2106.   FetchedNext = false;
  2107.   ListPageNo = DC_PageNo;
  2108.   ListIndex = DC_PageIndex;
  2109.   Code = GetByteDC();
  2110.   if (Code < 16 &&
  2111.       (CodeVersion <= '3' && (ListIndex & 1) == 0 ||
  2112.        CodeVersion >= '4' && CodeVersion <= '5' && (ListIndex & 3) == 0 ||
  2113.        CodeVersion >= '6' && (ListIndex & 3) == 0)) {
  2114.     EntryCnt = EntryIndex - 1;
  2115.     while (EntryCnt >= 0 && !GotRegList) {
  2116.       CalcCallAddress(EntryPoints[EntryCnt], &AddressPageNo, &AddressIndex);
  2117.       if (AddressPageNo == ListPageNo && AddressIndex == ListIndex)
  2118.         GotRegList = true;
  2119.       else
  2120.         --EntryCnt;
  2121.     }
  2122.     if (!GotRegList && (Disassemble_Vars->NextCouldBeEntryPoint ||
  2123.                         Disassemble_Vars->NextShouldBeEntryPoint)) {
  2124.       if (CodeVersion < '5') {
  2125.         if (Code == 0) {
  2126.           Value1 = GetByteDC();
  2127.           GotRegList = (Value1 != 0);
  2128.           FetchedNext = true;
  2129.         } else {
  2130.           GotRegList = (Disassemble_Vars->NextShouldBeEntryPoint ||
  2131.               (unsigned)Code < 32 && ((1 << Code) & 0x3f0038e) != 0);
  2132.         }
  2133.         if (!GotRegList && (unsigned)Code < 32 && ((1 << Code) & 0x7c70) != 0) {
  2134.           Value1 = GetByteDC();
  2135.           Value2 = GetByteDC();
  2136.           FetchedNext = true;
  2137.           GotRegList = (((unsigned)Code < 32 && ((1 << Code) & 0x4040) != 0 &&
  2138.                          (Value1 == 0 || Value2 == 0)) ||
  2139.                         ((unsigned)Code < 32 &&
  2140.                          ((1 << Code) & 0xe3c30) != 0 && Value1 == 0));
  2141.               /* OIN,INS */
  2142.           /* TSF,SEF,CLF,LDP,LPA,LNP */
  2143.         }
  2144.       } else {
  2145.         GotRegList = false;
  2146.       }
  2147.     }
  2148.   }
  2149.   if (!GotRegList || FetchedNext) {
  2150.     DC_PageIndex = ListIndex;
  2151.     DC_PageNo = ListPageNo;
  2152.     if (GotRegList)
  2153.       Code = GetByteDC();
  2154.   }
  2155.   Disassemble_Vars->NextCouldBeEntryPoint = false;
  2156.   Disassemble_Vars->NextShouldBeEntryPoint = false;
  2157.   if (GotRegList)
  2158.     DisRegList(Code);
  2159. }  /* CheckIfRegList */
  2160.  
  2161. Local void GetTwoOperands(struct Disassemble_LocalVariables *Disassemble_Vars) {
  2162.   int Wrk0;
  2163.   int Wrk1;
  2164.   int Op5;
  2165.  
  2166.   Op5 = cOp5(CmdCode);
  2167.   if (!((Op5 < 25 || Op5 < 26 && CodeVersion == '4' ||
  2168.          Op5 < 29 && CodeVersion >= '5') &&
  2169.         (Op5 != 0 || Disassemble_Vars->InstIsBPT)))
  2170.     return;
  2171.   WriteCh(Disassemble_Vars->CmdLine, ' ');
  2172.   if (TstBit(CmdCode, 6)) {   /* DLS,IGT,SEW */
  2173.     DisAddressMode(true, (unsigned)Op5 < 32 && ((1 << Op5) & 0x2030) != 0,
  2174.                    Disassemble_Vars);
  2175.   } else {
  2176.     if (Disassemble_Vars->GetCmdCode)
  2177.       Wrk0 = GetByteDC();
  2178.     if ((unsigned)Op5 < 32 && ((1 << Op5) & 0x2030) != 0) {
  2179.       WriteAddressMode(Disassemble_Vars->CmdLine, Wrk0, Disassemble_Vars);
  2180.     } else if ((Op5 == 25 || Op5 == 26) && Disassemble_Vars->GetCmdCode) {
  2181.       HandleEntryAddress(Wrk0, Disassemble_Vars);
  2182.     } else {
  2183.       WriteCh(Disassemble_Vars->CmdLine, '#');
  2184.       if (Disassemble_Vars->GetCmdCode)
  2185.         AddByte(Disassemble_Vars->CmdLine, Wrk0);
  2186.       else
  2187.         strcat(Disassemble_Vars->CmdLine, "xx");
  2188.     }
  2189.   }
  2190.   WriteCh(Disassemble_Vars->CmdLine, ' ');
  2191.   if (TstBit(CmdCode, 5)) {
  2192.     DisAddressMode(true, false, Disassemble_Vars);
  2193.   } else {
  2194.     WriteCh(Disassemble_Vars->CmdLine, '#');
  2195.     if (Disassemble_Vars->GetCmdCode) {
  2196.       Wrk1 = GetByteDC();
  2197.       AddByte(Disassemble_Vars->CmdLine, Wrk1);
  2198.     } else {
  2199.       strcat(Disassemble_Vars->CmdLine, "xx");
  2200.     }
  2201.   }
  2202.   WriteCh(Disassemble_Vars->CmdLine, ' ');
  2203.  
  2204.   /* CFC */
  2205.   /* CPC */
  2206. }  /* GetTwoOperands */
  2207.  
  2208. Local void ListTwoOperandOperation(struct Disassemble_LocalVariables *Disassemble_Vars) {
  2209.   int Op5;
  2210.   MnemString CmdMnem;
  2211.  
  2212.   Op5 = cOp5(CmdCode);
  2213.   if (Op5 >= 29 || Op5 == 0 && !Disassemble_Vars->InstIsBPT) {
  2214.     IllegalCmd(Disassemble_Vars);
  2215.     return;
  2216.   }
  2217.   switch (Op5) {
  2218.  
  2219.   case 8:
  2220.   case 9:
  2221.   case 15:
  2222.   case 16:
  2223.   case 17:
  2224.   case 18:
  2225.   case 19:
  2226.   case 20:
  2227.   case 21:
  2228.   case 22:
  2229.   case 23:
  2230.   case 24:
  2231.   case 25:
  2232.     /* LOR,AND,LDW,LDB,LDP,LPA,LNP,ADD,SUB,MUL,DIV,MOD,CFC */
  2233.     DisAddressMode(false, false, Disassemble_Vars);
  2234.     break;
  2235.  
  2236.   case 1:
  2237.   case 2:
  2238.   case 3:
  2239.   case 4:
  2240.   case 5:
  2241.   case 6:
  2242.   case 7:
  2243.   case 10:
  2244.     /* EQU,LES,GRT,DLS,IGT,OIN,TST,LOR,AND,TSF */
  2245.     DisJump(Disassemble_Vars);
  2246.     break;
  2247.   }
  2248.   switch (Op5) {
  2249.  
  2250.   case 0:
  2251.     strcpy(CmdMnem, "BPT");
  2252.     break;
  2253.  
  2254.   case 1:
  2255.     strcpy(CmdMnem, "EQU");
  2256.     break;
  2257.  
  2258.   case 2:
  2259.     strcpy(CmdMnem, "LES");
  2260.     break;
  2261.  
  2262.   case 3:
  2263.     strcpy(CmdMnem, "GRT");
  2264.     break;
  2265.  
  2266.   case 4:
  2267.     strcpy(CmdMnem, "DLS");
  2268.     break;
  2269.  
  2270.   case 5:
  2271.     strcpy(CmdMnem, "IGT");
  2272.     break;
  2273.  
  2274.   case 6:
  2275.     strcpy(CmdMnem, "OIN");
  2276.     break;
  2277.  
  2278.   case 7:
  2279.     strcpy(CmdMnem, "TST");
  2280.     break;
  2281.  
  2282.   case 8:
  2283.     strcpy(CmdMnem, "LOR");
  2284.     break;
  2285.  
  2286.   case 9:
  2287.     strcpy(CmdMnem, "AND");
  2288.     break;
  2289.  
  2290.   case 10:
  2291.     strcpy(CmdMnem, "TSF");
  2292.     break;
  2293.  
  2294.   case 11:
  2295.     strcpy(CmdMnem, "SEF");
  2296.     break;
  2297.  
  2298.   case 12:
  2299.     strcpy(CmdMnem, "CLF");
  2300.     break;
  2301.  
  2302.   case 13:
  2303.     strcpy(CmdMnem, "SEW");
  2304.     break;
  2305.  
  2306.   case 14:
  2307.     strcpy(CmdMnem, "INS");
  2308.     break;
  2309.  
  2310.   case 15:
  2311.     strcpy(CmdMnem, "LDW");
  2312.     break;
  2313.  
  2314.   case 16:
  2315.     strcpy(CmdMnem, "LDB");
  2316.     break;
  2317.  
  2318.   case 17:
  2319.     strcpy(CmdMnem, "LDP");
  2320.     break;
  2321.  
  2322.   case 18:
  2323.     strcpy(CmdMnem, "LPA");
  2324.     break;
  2325.  
  2326.   case 19:
  2327.     strcpy(CmdMnem, "LNP");
  2328.     break;
  2329.  
  2330.   case 20:
  2331.     strcpy(CmdMnem, "ADD");
  2332.     break;
  2333.  
  2334.   case 21:
  2335.     strcpy(CmdMnem, "SUB");
  2336.     break;
  2337.  
  2338.   case 22:
  2339.     strcpy(CmdMnem, "MUL");
  2340.     break;
  2341.  
  2342.   case 23:
  2343.     strcpy(CmdMnem, "DIV");
  2344.     break;
  2345.  
  2346.   case 24:
  2347.     strcpy(CmdMnem, "MOD");
  2348.     break;
  2349.  
  2350.   case 25:
  2351.     strcpy(CmdMnem, "CFC");
  2352.     break;
  2353.  
  2354.   case 26:
  2355.     strcpy(CmdMnem, "CPC");
  2356.     break;
  2357.  
  2358.   case 27:
  2359.     strcpy(CmdMnem, "N27");
  2360.     break;
  2361.  
  2362.   case 28:
  2363.     strcpy(CmdMnem, "RTM");
  2364.     break;
  2365.   }
  2366.   if (*Disassemble_Vars->CmdLine == '\0')
  2367.     strcpy(Disassemble_Vars->CmdLine, CmdMnem);
  2368.   else
  2369.     strinsert(CmdMnem, (void *)Disassemble_Vars->CmdLine, 1);
  2370. }  /* TwoOperandOperation */
  2371.  
  2372. /* Local variables for GetOneOperand: */
  2373. struct GetOneOperand_LocalVariables {
  2374.   struct Disassemble_LocalVariables *Disassemble_Vars;
  2375. } ;
  2376.  
  2377. Local void WriteImmediate(int Value, int Op4,
  2378.    struct GetOneOperand_LocalVariables *GetOneOperand_Vars) {
  2379.   if ((unsigned)Op4 < 32 && ((1 << Op4) & 0x4060) != 0) {   /* INC,DEC,MVE */
  2380.     WriteAddressMode(GetOneOperand_Vars->Disassemble_Vars->CmdLine, Value,
  2381.                      GetOneOperand_Vars->Disassemble_Vars);
  2382.     return;
  2383.   }
  2384.   if (Op4 == 12 && GetOneOperand_Vars->Disassemble_Vars->GetCmdCode)
  2385.   {   /* JMP */
  2386.     WriteJump(Value, GetOneOperand_Vars->Disassemble_Vars);
  2387.     return;
  2388.   }
  2389.   if (GetOneOperand_Vars->Disassemble_Vars->GetCmdCode &&
  2390.       (Op4 == 8 || Op4 == 15 && CodeVersion >= '5'))
  2391.   {   /* CFC */
  2392.     HandleEntryAddress(Value, GetOneOperand_Vars->Disassemble_Vars);
  2393.     return;
  2394.   }
  2395.   /* CPC */
  2396.   WriteCh(GetOneOperand_Vars->Disassemble_Vars->CmdLine, '#');
  2397.   if (GetOneOperand_Vars->Disassemble_Vars->GetCmdCode)
  2398.     AddWord(GetOneOperand_Vars->Disassemble_Vars->CmdLine, Value);
  2399.   else
  2400.     strcat(GetOneOperand_Vars->Disassemble_Vars->CmdLine, "xxxx");
  2401. }  /* WriteImmediate */
  2402.  
  2403. Local void GetOneOperand(struct Disassemble_LocalVariables *Disassemble_Vars) {
  2404.   struct GetOneOperand_LocalVariables V;
  2405.   int ImmediateValue;
  2406.   int Op4;
  2407.  
  2408.   V.Disassemble_Vars = Disassemble_Vars;
  2409.   Op4 = cOp4(CmdCode);
  2410.   WriteCh(Disassemble_Vars->CmdLine, ' ');
  2411.   switch (cMode(CmdCode)) {
  2412.  
  2413.   case 0:
  2414.     if (Disassemble_Vars->GetCmdCode)
  2415.       ImmediateValue = GetWordDC();
  2416.     WriteImmediate(ImmediateValue, Op4, &V);
  2417.     break;
  2418.  
  2419.   case 1:
  2420.     if (Disassemble_Vars->GetCmdCode)
  2421.       ImmediateValue = GetByteDC();
  2422.     WriteImmediate(ImmediateValue, Op4, &V);
  2423.     break;
  2424.  
  2425.   case 2:   /* INC,DEC,MVE */
  2426.     DisAddressMode(true, (unsigned)Op4 < 32 && ((1 << Op4) & 0x4060) != 0,
  2427.                    Disassemble_Vars);
  2428.     break;
  2429.   }
  2430. }  /* GetOneOperand */
  2431.  
  2432. Local void ListOneOperandOperation(struct Disassemble_LocalVariables *Disassemble_Vars) {
  2433.   int Op4;
  2434.   MnemString CmdMnem;
  2435.  
  2436.   Op4 = cOp4(CmdCode);
  2437.   WriteCh(Disassemble_Vars->CmdLine, ' ');
  2438.   if ((unsigned)Op4 < 32 && ((1 << Op4) & 0x411e) != 0 ||
  2439.       Op4 == 15 && CodeVersion < '5')
  2440.   {   /* NXO,FSO,PTO,LPS,CFC,MVE,NEG */
  2441.     DisAddressMode(false, false, Disassemble_Vars);
  2442.     WriteCh(Disassemble_Vars->CmdLine, ' ');
  2443.   }
  2444.   /* NEG */
  2445.   if ((unsigned)Op4 < 32 && ((1 << Op4) & 0x7) != 0)   /* EQN,NXO,FSO */
  2446.     DisJump(Disassemble_Vars);
  2447.   switch (Op4) {
  2448.  
  2449.   case 0:
  2450.     strcpy(CmdMnem, "EQN");
  2451.     break;
  2452.  
  2453.   case 1:
  2454.     strcpy(CmdMnem, "NXO");
  2455.     break;
  2456.  
  2457.   case 2:
  2458.     strcpy(CmdMnem, "FSO");
  2459.     break;
  2460.  
  2461.   case 3:
  2462.     strcpy(CmdMnem, "PTO");
  2463.     break;
  2464.  
  2465.   case 4:
  2466.     strcpy(CmdMnem, "LPS");
  2467.     break;
  2468.  
  2469.   case 5:
  2470.     strcpy(CmdMnem, "INC");
  2471.     break;
  2472.  
  2473.   case 6:
  2474.     strcpy(CmdMnem, "DEC");
  2475.     break;
  2476.  
  2477.   case 7:
  2478.     strcpy(CmdMnem, "WSB");
  2479.     break;
  2480.  
  2481.   case 8:
  2482.     if (CodeVersion < '4') {
  2483.       strcpy(CmdMnem, "$");
  2484.       AddByte(CmdMnem, CmdCode);
  2485.       Disassemble_Vars->NextCouldBeEntryPoint = true;
  2486.     } else {
  2487.       strcpy(CmdMnem, "CFC");
  2488.     }
  2489.     break;
  2490.  
  2491.   case 9:
  2492.     strcpy(CmdMnem, "RMO");
  2493.     break;
  2494.  
  2495.   case 10:
  2496.     strcpy(CmdMnem, "WTO");
  2497.     break;
  2498.  
  2499.   case 11:
  2500.     strcpy(CmdMnem, "RTN");
  2501.     Disassemble_Vars->NextCouldBeEntryPoint = true;
  2502.     break;
  2503.  
  2504.   case 12:
  2505.     strcpy(CmdMnem, "JMP");
  2506.     Disassemble_Vars->NextCouldBeEntryPoint = true;
  2507.     break;
  2508.  
  2509.   case 13:
  2510.     strcpy(CmdMnem, "WSW");
  2511.     break;
  2512.  
  2513.   case 14:
  2514.     strcpy(CmdMnem, "MVE");
  2515.     break;
  2516.  
  2517.   case 15:
  2518.     if (CodeVersion < '5')
  2519.       strcpy(CmdMnem, "NEG");
  2520.     else
  2521.       strcpy(CmdMnem, "CPC");
  2522.     break;
  2523.   }
  2524.   strinsert(CmdMnem, (void *)Disassemble_Vars->CmdLine, 1);
  2525. }  /* OneOperandOperation */
  2526.  
  2527. /* Local variables for GetMultipleOperands: */
  2528. struct GetMultipleOperands_LocalVariables {
  2529.   struct Disassemble_LocalVariables *Disassemble_Vars;
  2530.   boolean PureMultiple;
  2531.   boolean Indirect;
  2532.   int BitlCnt;
  2533.   int Value;
  2534.   int Op5;
  2535. } ;
  2536.  
  2537. Local void WriteImmediateValueOrCallAddress(boolean IsWord,
  2538.    struct GetMultipleOperands_LocalVariables *GetMultipleOperands_Vars) {
  2539.   if (GetMultipleOperands_Vars->Indirect) {
  2540.     WriteAddressMode(GetMultipleOperands_Vars->Disassemble_Vars->CmdLine,
  2541.                      GetMultipleOperands_Vars->Value,
  2542.                      GetMultipleOperands_Vars->Disassemble_Vars);
  2543.     return;
  2544.   }
  2545.   if ((GetMultipleOperands_Vars->PureMultiple &&
  2546.        ((GetMultipleOperands_Vars->BitlCnt == 3 &&
  2547.          (GetMultipleOperands_Vars->Op5 == 0 ||
  2548.           GetMultipleOperands_Vars->Op5 == 25)) ||
  2549.         (GetMultipleOperands_Vars->BitlCnt == 7 &&
  2550.          (GetMultipleOperands_Vars->Op5 == 12 ||
  2551.           GetMultipleOperands_Vars->Op5 == 26)) ||
  2552.         (GetMultipleOperands_Vars->BitlCnt == 1 &&
  2553.          GetMultipleOperands_Vars->Op5 == 22))) ||
  2554.       (!GetMultipleOperands_Vars->PureMultiple &&
  2555.        GetMultipleOperands_Vars->BitlCnt == 3 &&
  2556.        (GetMultipleOperands_Vars->Op5 == 25 ||
  2557.         GetMultipleOperands_Vars->Op5 == 26))) {
  2558.     HandleEntryAddress(GetMultipleOperands_Vars->Value,
  2559.                        GetMultipleOperands_Vars->Disassemble_Vars);
  2560.     return;
  2561.   }
  2562.   WriteCh(GetMultipleOperands_Vars->Disassemble_Vars->CmdLine, '#');
  2563.   if (IsWord)
  2564.     AddWord(GetMultipleOperands_Vars->Disassemble_Vars->CmdLine,
  2565.             GetMultipleOperands_Vars->Value);
  2566.   else
  2567.     AddByte(GetMultipleOperands_Vars->Disassemble_Vars->CmdLine,
  2568.             GetMultipleOperands_Vars->Value);
  2569. }  /* WriteImmediateValueOrCallAddress */
  2570.  
  2571. Local void GetMultipleOperands(boolean Extended, boolean NewMultiple,
  2572.    struct Disassemble_LocalVariables *Disassemble_Vars) {
  2573.   struct GetMultipleOperands_LocalVariables V;
  2574.   int Mode;
  2575.   boolean ListEnd;
  2576.  
  2577.   V.Disassemble_Vars = Disassemble_Vars;
  2578.   V.Op5 = cOp5(CmdCode);
  2579.   V.PureMultiple = (NewMultiple || CmdCode >= 224);   /* $E0 */
  2580.   if (Extended) {
  2581.     Mode = GetWordDC();
  2582.     V.BitlCnt = 7;
  2583.   } else {
  2584.     Mode = GetByteDC();
  2585.     V.BitlCnt = 3;
  2586.   }
  2587.   ListEnd = false;
  2588.   WriteCh(Disassemble_Vars->CmdLine, ' ');
  2589.   while (!ListEnd) {
  2590.     V.Indirect = (V.BitlCnt == 3 &&
  2591.                   (CmdCode == 233 ||
  2592.                    (!V.PureMultiple && (unsigned)V.Op5 < 32 &&
  2593.                     ((1 << V.Op5) & 0x2030) != 0)));
  2594.         /* PUL */
  2595.     /* DLS,IGT,SEW */
  2596.     switch (Bittle(Mode, V.BitlCnt)) {
  2597.  
  2598.     case 0:
  2599.       V.Value = GetWordDC();
  2600.       WriteImmediateValueOrCallAddress(true, &V);
  2601.       break;
  2602.  
  2603.     case 1:
  2604.       V.Value = GetByteDC();
  2605.       WriteImmediateValueOrCallAddress(false, &V);
  2606.       break;
  2607.  
  2608.     case 2:
  2609.       DisAddressMode(true, V.Indirect, Disassemble_Vars);
  2610.       break;
  2611.  
  2612.     case 3:
  2613.       ListEnd = true;
  2614.       break;
  2615.     }
  2616.     if (ListEnd)
  2617.       break;
  2618.     WriteCh(Disassemble_Vars->CmdLine, ' ');
  2619.     if (V.BitlCnt > 0)
  2620.       --V.BitlCnt;
  2621.     else
  2622.       ListEnd = true;
  2623.   }
  2624. }  /* GetMultipleOperands */
  2625.  
  2626. Local void ListMultipleOperandOperation(boolean NewVersion,
  2627.    struct Disassemble_LocalVariables *Disassemble_Vars) {
  2628.   int Op5;
  2629.   MnemString CmdMnem;
  2630.  
  2631.   Op5 = cOp5(CmdCode);
  2632.   if (Op5 >= 12 && CodeVersion < '4' || Op5 >= 24 && CodeVersion < '5') {
  2633.     IllegalCmd(Disassemble_Vars);
  2634.     return;
  2635.   }
  2636.   if ((unsigned)Op5 < 32 && ((1 << Op5) & 0xc01081) != 0 ||
  2637.       CodeVersion >= '5' && (Op5 == 4 || Op5 == 24) ||
  2638.       CodeVersion >= '6' && Op5 == 9)
  2639.         /* CFC,RND,CFC,INK,BEQ */
  2640.           DisAddressMode(false, false, Disassemble_Vars);
  2641.   /* INP */
  2642.   /* NEG */
  2643.   /* PUL */
  2644.   if (Op5 == 23) {
  2645.     WriteCh(Disassemble_Vars->CmdLine, ' ');
  2646.     DisJump(Disassemble_Vars);
  2647.   }
  2648.   if (Op5 == 31)
  2649.     DisJump(Disassemble_Vars);
  2650.   switch (Op5) {
  2651.  
  2652.   case 0:
  2653.     strcpy(CmdMnem, "CFC");
  2654.     break;
  2655.  
  2656.   case 1:
  2657.     strcpy(CmdMnem, "STW");
  2658.     break;
  2659.  
  2660.   case 2:
  2661.     strcpy(CmdMnem, "STB");
  2662.     break;
  2663.  
  2664.   case 3:
  2665.     strcpy(CmdMnem, "STP");
  2666.     break;
  2667.  
  2668.   case 4:
  2669.     strcpy(CmdMnem, "INP");
  2670.     break;
  2671.  
  2672.   case 5:
  2673.     strcpy(CmdMnem, "WTC");
  2674.     break;
  2675.  
  2676.   case 6:
  2677.     strcpy(CmdMnem, "WTI");
  2678.     break;
  2679.  
  2680.   case 7:
  2681.     strcpy(CmdMnem, "RND");
  2682.     break;
  2683.  
  2684.   case 8:
  2685.     strcpy(CmdMnem, "PSH");
  2686.     break;
  2687.  
  2688.   case 9:
  2689.     strcpy(CmdMnem, "PUL");
  2690.     break;
  2691.  
  2692.   case 10:
  2693.     strcpy(CmdMnem, "SPL");
  2694.     break;
  2695.  
  2696.   case 11:
  2697.     strcpy(CmdMnem, "POS");
  2698.     break;
  2699.  
  2700.   case 12:
  2701.     strcpy(CmdMnem, "CFC");
  2702.     break;
  2703.  
  2704.   case 13:
  2705.     strcpy(CmdMnem, "ERS");
  2706.     break;
  2707.  
  2708.   case 14:
  2709.     strcpy(CmdMnem, "ERL");
  2710.     break;
  2711.  
  2712.   case 15:
  2713.     strcpy(CmdMnem, "GYX");
  2714.     break;
  2715.  
  2716.   case 16:
  2717.     strcpy(CmdMnem, "NO2");
  2718.     break;
  2719.  
  2720.   case 17:
  2721.     strcpy(CmdMnem, "SCM");
  2722.     break;
  2723.  
  2724.   case 18:
  2725.     strcpy(CmdMnem, "FRM");
  2726.     break;
  2727.  
  2728.   case 19:
  2729.     strcpy(CmdMnem, "OUT");
  2730.     break;
  2731.  
  2732.   case 20:
  2733.     strcpy(CmdMnem, "COM");
  2734.     break;
  2735.  
  2736.   case 21:
  2737.     strcpy(CmdMnem, "BEL");
  2738.     break;
  2739.  
  2740.   case 22:
  2741.     strcpy(CmdMnem, "INK");
  2742.     break;
  2743.  
  2744.   case 23:
  2745.     strcpy(CmdMnem, "BEQ");
  2746.     break;
  2747.  
  2748.   case 24:
  2749.     strcpy(CmdMnem, "NEG");
  2750.     break;
  2751.  
  2752.   case 25:
  2753.     strcpy(CmdMnem, "CPC");
  2754.     break;
  2755.  
  2756.   case 26:
  2757.     strcpy(CmdMnem, "CPC");
  2758.     break;
  2759.  
  2760.   case 27:
  2761.     strcpy(CmdMnem, "PRS");
  2762.     break;
  2763.  
  2764.   case 28:
  2765.     strcpy(CmdMnem, "PAK");
  2766.     break;
  2767.  
  2768.   case 29:
  2769.     strcpy(CmdMnem, "BCP");
  2770.     break;
  2771.  
  2772.   case 30:
  2773.     strcpy(CmdMnem, "WTA");
  2774.     break;
  2775.  
  2776.   case 31:
  2777.     strcpy(CmdMnem, "MNP");
  2778.     break;
  2779.   }
  2780.   strinsert(CmdMnem, (void *)Disassemble_Vars->CmdLine, 1);
  2781. }  /* ListMultipleOperandOperation */
  2782.  
  2783. Local void ListNewMultipleOperandOperation(struct Disassemble_LocalVariables *Disassemble_Vars) {
  2784.   MnemString CmdMnem;
  2785.  
  2786.   if (CmdCode >= 29) {
  2787.     IllegalCmd(Disassemble_Vars);
  2788.     return;
  2789.   }
  2790.   if ((unsigned)CmdCode < 32 && ((1 << CmdCode) & 0x8061f) != 0) {
  2791.     /* SVE,RSE,LSL,ASL,FNT,X09,X10,X19 */
  2792.     DisAddressMode(false, false, Disassemble_Vars);
  2793.   }
  2794.   if ((unsigned)CmdCode < 32 && ((1 << CmdCode) & 0x1000040) != 0)
  2795.         /* TSB,X24 */
  2796.           DisJump(Disassemble_Vars);
  2797.   switch (CmdCode) {
  2798.  
  2799.   case 0:
  2800.     strcpy(CmdMnem, "SVE");
  2801.     break;
  2802.  
  2803.   case 1:
  2804.     strcpy(CmdMnem, "RSE");
  2805.     break;
  2806.  
  2807.   case 2:
  2808.     strcpy(CmdMnem, "LSL");
  2809.     break;
  2810.  
  2811.   case 3:
  2812.     strcpy(CmdMnem, "ASL");
  2813.     break;
  2814.  
  2815.   case 4:
  2816.     strcpy(CmdMnem, "FNT");
  2817.     break;
  2818.  
  2819.   case 5:
  2820.     strcpy(CmdMnem, "CLR");
  2821.     break;
  2822.  
  2823.   case 6:
  2824.     strcpy(CmdMnem, "TSB");
  2825.     break;
  2826.  
  2827.   case 7:
  2828.     strcpy(CmdMnem, "SET");
  2829.     break;
  2830.  
  2831.   case 8:
  2832.     strcpy(CmdMnem, "SWD");
  2833.     break;
  2834.  
  2835.   case 9:
  2836.     strcpy(CmdMnem, "X09");
  2837.     break;
  2838.  
  2839.   case 10:
  2840.     strcpy(CmdMnem, "X10");
  2841.     break;
  2842.  
  2843.   case 11:
  2844.     strcpy(CmdMnem, "X11");
  2845.     break;
  2846.  
  2847.   case 12:
  2848.     strcpy(CmdMnem, "X12");
  2849.     break;
  2850.  
  2851.   case 13:
  2852.     strcpy(CmdMnem, "X13");
  2853.     break;
  2854.  
  2855.   case 14:
  2856.     strcpy(CmdMnem, "X14");
  2857.     break;
  2858.  
  2859.   case 15:
  2860.     strcpy(CmdMnem, "X15");
  2861.     break;
  2862.  
  2863.   case 16:
  2864.     strcpy(CmdMnem, "X16");
  2865.     break;
  2866.  
  2867.   case 17:
  2868.     strcpy(CmdMnem, "X17");
  2869.     break;
  2870.  
  2871.   case 18:
  2872.     strcpy(CmdMnem, "X18");
  2873.     break;
  2874.  
  2875.   case 19:
  2876.     strcpy(CmdMnem, "X19");
  2877.     break;
  2878.  
  2879.   case 20:
  2880.     strcpy(CmdMnem, "X20");
  2881.     break;
  2882.  
  2883.   case 21:
  2884.     strcpy(CmdMnem, "X21");
  2885.     break;
  2886.  
  2887.   case 22:
  2888.     strcpy(CmdMnem, "X22");
  2889.     break;
  2890.  
  2891.   case 23:
  2892.     strcpy(CmdMnem, "X23");
  2893.     break;
  2894.  
  2895.   case 24:
  2896.     strcpy(CmdMnem, "X24");
  2897.     break;
  2898.  
  2899.   case 25:
  2900.     strcpy(CmdMnem, "X25");
  2901.     break;
  2902.  
  2903.   case 26:
  2904.     strcpy(CmdMnem, "X26");
  2905.     break;
  2906.  
  2907.   case 27:
  2908.     strcpy(CmdMnem, "X27");
  2909.     break;
  2910.  
  2911.   case 28:
  2912.     strcpy(CmdMnem, "X28");
  2913.     break;
  2914.   }
  2915.   if (*CmdMnem != '\0')
  2916.     strinsert(CmdMnem, (void *)Disassemble_Vars->CmdLine, 1);
  2917. }  /* ListNewMultipleOperandOperation */
  2918.  
  2919. Local void ListNoOperandOperation(struct Disassemble_LocalVariables *Disassemble_Vars) {
  2920.   MnemString CmdMnem;
  2921.   int Op4;
  2922.  
  2923.   Op4 = cOp4(CmdCode);
  2924.   if (Op4 >= 14 && CodeVersion < '5') {
  2925.     IllegalCmd(Disassemble_Vars);
  2926.   } else {
  2927.     if ((unsigned)Op4 < 32 && ((1 << Op4) & 0xa060) != 0)
  2928.     {   /* SVE,RSO,VFY,jmpop */
  2929.       if (Op4 != 15)
  2930.         WriteCh(Disassemble_Vars->CmdLine, ' ');
  2931.       if (CodeVersion < '4' || Op4 == 15)
  2932.         DisJump(Disassemble_Vars);
  2933.       else
  2934.         DisAddressMode(false, false, Disassemble_Vars);
  2935.     }
  2936.     Disassemble_Vars->DumpText = ((unsigned)Op4 < 32 &&
  2937.                                   ((1 << Op4) & 0xc) != 0 &&
  2938.                                   Disassemble_Vars->GetCmdCode);
  2939.     switch (Op4) {
  2940.  
  2941.     case 0:
  2942.       strcpy(CmdMnem, "RTT");
  2943.       Disassemble_Vars->NextCouldBeEntryPoint = true;
  2944.       break;
  2945.  
  2946.     case 1:
  2947.       strcpy(CmdMnem, "RTF");
  2948.       Disassemble_Vars->NextCouldBeEntryPoint = true;
  2949.       break;
  2950.  
  2951.     case 2:
  2952.       strcpy(CmdMnem, "WTX");
  2953.       break;
  2954.  
  2955.     case 3:
  2956.       strcpy(CmdMnem, "WTR");
  2957.       Disassemble_Vars->NextCouldBeEntryPoint = true;
  2958.       break;
  2959.  
  2960.     case 4:
  2961.       strcpy(CmdMnem, "NOP");
  2962.       break;
  2963.  
  2964.     case 5:
  2965.       strcpy(CmdMnem, "SVE");
  2966.       break;
  2967.  
  2968.     case 6:
  2969.       strcpy(CmdMnem, "RSO");
  2970.       break;
  2971.  
  2972.     case 7:
  2973.       strcpy(CmdMnem, "RST");
  2974.       break;
  2975.  
  2976.     case 8:
  2977.       strcpy(CmdMnem, "RPL");
  2978.       Disassemble_Vars->NextCouldBeEntryPoint = true;
  2979.       break;
  2980.  
  2981.     case 9:
  2982.       if (CodeVersion < '5')
  2983.         strcpy(CmdMnem, "DSC");
  2984.       else
  2985.         strcpy(CmdMnem, "PMP");
  2986.       break;
  2987.  
  2988.     case 10:
  2989.       strcpy(CmdMnem, "END");
  2990.       break;
  2991.  
  2992.     case 11:
  2993.       strcpy(CmdMnem, "NWL");
  2994.       break;
  2995.  
  2996.     case 12:
  2997.       strcpy(CmdMnem, "PSL");
  2998.       break;
  2999.  
  3000.     case 13:
  3001.       strcpy(CmdMnem, "VFY");
  3002.       break;
  3003.  
  3004.     case 14:
  3005.       if (Disassemble_Vars->GetCmdCode) {
  3006.         CmdCode = GetByteDC();
  3007.         GetMultipleOperands(false, true, Disassemble_Vars);
  3008.         if (CmdCode >= 224) {   /* $E0 */
  3009.           ListMultipleOperandOperation(true, Disassemble_Vars);
  3010.         } else if (CmdCode < 192)
  3011.           ListNewMultipleOperandOperation(Disassemble_Vars);
  3012.         else
  3013.           ListTwoOperandOperation(Disassemble_Vars);
  3014.         goto _L0;
  3015.       }
  3016.       strcpy(CmdMnem, "EXS");
  3017.       break;
  3018.  
  3019.     case 15:
  3020.       *CmdMnem = '\0';
  3021.       Disassemble_Vars->NextCouldBeEntryPoint = true;
  3022.       break;
  3023.     }
  3024.     if (*Disassemble_Vars->CmdLine == '\0')
  3025.       strcpy(Disassemble_Vars->CmdLine, " ");
  3026.     strinsert(CmdMnem, (void *)Disassemble_Vars->CmdLine, 1);
  3027.   }
  3028. _L0: ;
  3029.  
  3030.   /* $C0 */
  3031. }  /* ListNoOperandOperation */
  3032.  
  3033.  
  3034. Static void Disassemble(int NumLines, boolean GetCmdCode_) {
  3035.   struct Disassemble_LocalVariables V;
  3036.   PtrBPT WrkBPT;
  3037.   int BPT_No;
  3038.   int BPT_Type;
  3039.   int DisInstPageNo;
  3040.   int DisInstPageIndex;
  3041.   int SpaceCnt;
  3042.   int FORLIM;
  3043.  
  3044.   V.GetCmdCode = GetCmdCode_;
  3045.   if (DC_PageNo != OldPageNo || DC_PageIndex != OldIndex) {
  3046.     BackPageNo = OldPageNo;
  3047.     BackIndex = OldIndex;
  3048.     OldPageNo = DC_PageNo;
  3049.     OldIndex = DC_PageIndex;
  3050.   }
  3051.   LineCnt = 0;
  3052.   V.InstIsBPT = false;
  3053.   V.NextCouldBeEntryPoint = true;
  3054.   V.NextShouldBeEntryPoint = false;
  3055.   while (LineCnt < NumLines && EndPageNo < 0 ||
  3056.          (DC_PageNo <= EndPageNo &&
  3057.           (DC_PageNo != EndPageNo || DC_PageIndex <= EndPageIndex))) {
  3058.     if (V.GetCmdCode) {
  3059.       DisInstPageNo = DC_PageNo;
  3060.       DisInstPageIndex = DC_PageIndex;
  3061.       CmdCode = GetByteDC();
  3062.       if (CmdCode == 0) {
  3063.         BPT_No = GetByteDC();
  3064.         if (BPT_No > 0) {
  3065.           BPT_Type = GetByteDC();
  3066.           if (BPT_Type == TraceBPT || BPT_Type == RunBPT ||
  3067.               BPT_Type == UserBPT) {
  3068.             WrkBPT = BPT_List;
  3069.             while (WrkBPT != NULL) {
  3070.               if (WrkBPT->BPT_No == BPT_No)
  3071.                 goto _L1;
  3072.               WrkBPT = WrkBPT->NextBPT;
  3073.             }
  3074. _L1:
  3075.             V.InstIsBPT = (WrkBPT != NULL);
  3076.             if (V.InstIsBPT && !DisBPTs)
  3077.               PutOrgCode(WrkBPT);
  3078.           }
  3079.         }
  3080.       }
  3081.       DC_PageIndex = DisInstPageIndex;
  3082.       DC_PageNo = DisInstPageNo;
  3083.       if (TryRegList)
  3084.         CheckIfRegList(&V);
  3085.     }
  3086.     DumpCnt = 0;
  3087.     *V.CmdLine = '\0';
  3088.     *Dump = '\0';
  3089.     V.DumpText = false;
  3090.     if (V.GetCmdCode) {
  3091.       strcpy(Dump, "C");
  3092.       WriteCh(Dump, ' ');
  3093.       AddWord(Dump, DC_PageNo);
  3094.       AddByte(Dump, DC_PageIndex);
  3095.       WriteCh(Dump, ':');
  3096.       CmdCode = GetByteDC();
  3097.     }
  3098.     if (CmdCode < 128) {   /* $80 */
  3099.       GetTwoOperands(&V);
  3100.       ListTwoOperandOperation(&V);
  3101.     } else if (CmdCode < 176) {
  3102.       GetOneOperand(&V);
  3103.       ListOneOperandOperation(&V);
  3104.     } else if (CmdCode < 192) {
  3105.       ListNoOperandOperation(&V);
  3106.     } else {
  3107.       if (V.GetCmdCode)   /* $EC, extended CFC */
  3108.         GetMultipleOperands(CmdCode == 236 || CmdCode == 250, false, &V);
  3109.       else
  3110.         strcat(V.CmdLine, " multiple ");
  3111.       /* $FA, extended CPC */
  3112.       if (CmdCode < 224)   /* $E0 */
  3113.         ListTwoOperandOperation(&V);
  3114.       else
  3115.         ListMultipleOperandOperation(false, &V);
  3116.     }
  3117.     if (V.InstIsBPT && !DisBPTs) {
  3118.       PutBPTCode(WrkBPT);
  3119.       Dump[1] = '-';
  3120.       V.InstIsBPT = false;
  3121.     }
  3122.     if (V.GetCmdCode) {
  3123.       PrintString(Dump);
  3124.       FORLIM = (12 - DumpCnt) * 3;
  3125.       for (SpaceCnt = 1; SpaceCnt <= FORLIM; ++SpaceCnt)
  3126.         PrintCh(' ');
  3127.       PrintString(V.CmdLine);
  3128.     } else {
  3129.       PrintString(V.CmdLine);
  3130.       LineCnt = 1;
  3131.     }
  3132.     ChkWait();
  3133.     if (V.DumpText)
  3134.       WriteText('T', OntoScreen, FromDC, GlobalTextBuffer);
  3135.   }
  3136.  
  3137.   /* $B0 */
  3138.   /* $C0 */
  3139. }  /* Disassemble */
  3140.  
  3141.  
  3142. Static void PrintReg(int RegNo) {
  3143.   Char RegName[256];
  3144.  
  3145.   strcpy(RegName, "R*=");
  3146.   RegName[1] = HexChars[RegNo];
  3147.   PrintString(RegName);
  3148.   PrintWord(R.a[RegNo], 4);
  3149. }  /* PrintReg */
  3150.  
  3151.  
  3152. Static void SaveCursorState(void) {
  3153.   if (InStory) {
  3154.     StoryCursorX = CursorX;
  3155.     StoryCursorY = CursorY;
  3156.     SaveTextAttributes();
  3157.     ScreenMode = 0;
  3158.     SetScreenMode();
  3159.     StoryScrollTop = ScrollTop;
  3160.     if (WindowEnabled) {
  3161.       if (ScrollTop == ScreenHeight)
  3162.         ScrollTop = ScreenHeight - 5;
  3163.       ZM_GotoXY(1, ScreenHeight);
  3164.     }
  3165.   }
  3166.   InStory = false;
  3167. }  /* SaveCursorState */
  3168.  
  3169.  
  3170. Static void RestoreCursorState(void) {
  3171.   InStory = true;
  3172.   RestoreTextAttributes();
  3173.   ScrollTop = StoryScrollTop;
  3174.   if (!WindowEnabled)
  3175.     return;
  3176.   CursorX = StoryCursorX;
  3177.   CursorY = StoryCursorY;
  3178.   PositionCursor();
  3179. }  /* RestoreCursorState */
  3180.  
  3181.  
  3182. Static void PrintZState(void) {
  3183.   int RegCnt;
  3184.   int StackCnt;
  3185.  
  3186.   SaveCursorState();
  3187.   PrintString("IPC=");
  3188.   PrintWord(IPC_PageNo, 4);
  3189.   PrintByte(IPC_PageIndex, 2);
  3190.   PrintString(" SP=");
  3191.   PrintWord(SP, 4);
  3192.   PrintString(" MSP=");
  3193.   PrintWord(MSP, 4);
  3194.   PrintString(" TOS=");
  3195.   for (StackCnt = 1; StackCnt <= 9; ++StackCnt) {
  3196.     if (SP >= StackCnt)
  3197.       PrintWord(Stack[SP - StackCnt], 4);
  3198.     else
  3199.       PrintString("----");
  3200.     PrintCh(' ');
  3201.   }
  3202.   ChkWait();
  3203.   for (RegCnt = 0; RegCnt <= 15; ++RegCnt) {
  3204.     if (RegCnt == 8)
  3205.       ChkWait();
  3206.     PrintReg(RegCnt);
  3207.     PrintCh(' ');
  3208.   }
  3209.   ChkWait();
  3210. }  /* PrintZState */
  3211.  
  3212.  
  3213. Static void SetInterpreterConfiguration(void) {
  3214.   int Wrk;
  3215.   union {
  3216.     tMiscInfo *mp;
  3217.     uchar *pp;
  3218.   } H;
  3219.  
  3220.   H.pp = PagePtrs[0];
  3221.   H.mp->mInterpreterNumber = CodeVersion - '0';
  3222.   H.mp->mInterpreterVersion = _toupper(InterpreterChar);
  3223.   H.mp->ScreenWidth = ScreenWidth;
  3224.   H.mp->ScreenHeight = ScreenHeight - 1;
  3225.   H.mp->Left = 0;
  3226.   H.mp->Right = ScreenWidth;
  3227.   H.mp->Top = 0;
  3228.   H.mp->Bottom = ScreenHeight - 1;
  3229.   H.mp->Unknown1 = 1;
  3230.   H.mp->Unknown2 = 1;
  3231.   H.mp->Unknown3 = 9;
  3232.   H.mp->Unknown4 = 2;
  3233.   Wrk = MiscInfo.ConfigFlags;
  3234.   SetBit(&Wrk, 4);
  3235.   SetBit(&Wrk, 5);
  3236.   H.mp->ConfigFlags = Wrk;
  3237.   MiscInfo.ConfigFlags = Wrk;
  3238. }  /* SetInterpreterConfiguration */
  3239.  
  3240.  
  3241. Static void CalcObjAdrs(int ObjNo, int *ObjPageNo, int *ObjPageIndex,
  3242.                         int FieldOffset) {
  3243.   *ObjPageNo = MiscInfo.ObjPageNo;
  3244.   *ObjPageIndex = MiscInfo.ObjPageIndex;
  3245.   Inc(ObjPageNo, ObjPageIndex, ObjNo * ObjRecSize + ObjOffset + FieldOffset);
  3246. }  /* CalcObjAdrs */
  3247.  
  3248.  
  3249. Static void RemoveObj(int ObjNo) {
  3250.   int ObjPageNo;
  3251.   int ObjPageIndex;
  3252.   int ParentObj;
  3253.   int FirstObj;
  3254.   int WrkObj;
  3255.   int ParentPageNo;
  3256.   int ParentPageIndex;
  3257.   int PrevObj;
  3258.   int PrevPageNo;
  3259.   int PrevPageIndex;
  3260.   int LowByte;
  3261.   int HighByte;
  3262.  
  3263.   if (CodeVersion < '4') {
  3264.     CalcObjAdrs(ObjNo, &ObjPageNo, &ObjPageIndex, 4);
  3265.     ParentObj = PagePtrs[ObjPageNo][ObjPageIndex];
  3266.   } else {
  3267.     CalcObjAdrs(ObjNo, &ObjPageNo, &ObjPageIndex, 6);
  3268.     HighByte = PagePtrs[ObjPageNo][ObjPageIndex];
  3269.     Inc(&ObjPageNo, &ObjPageIndex, 1);
  3270.     LowByte = PagePtrs[ObjPageNo][ObjPageIndex];
  3271.     ParentObj = JoinBytes(LowByte, HighByte);
  3272.   }
  3273.   if (ParentObj == 0)
  3274.     return;
  3275.   if (CodeVersion < '4') {
  3276.     CalcObjAdrs(ParentObj, &ParentPageNo, &ParentPageIndex, 6);
  3277.     FirstObj = PagePtrs[ParentPageNo][ParentPageIndex];   /* PTO.FSO */
  3278.   } else {
  3279.     CalcObjAdrs(ParentObj, &ParentPageNo, &ParentPageIndex, 10);
  3280.     HighByte = PagePtrs[ParentPageNo][ParentPageIndex];
  3281.     Inc(&ParentPageNo, &ParentPageIndex, 1);
  3282.     LowByte = PagePtrs[ParentPageNo][ParentPageIndex];
  3283.     FirstObj = JoinBytes(LowByte, HighByte);
  3284.   }
  3285.   if (FirstObj == ObjNo) {
  3286.     Inc(&ObjPageNo, &ObjPageIndex, 1);
  3287.     /* PTO.FSO:=OBJ.NXO */
  3288.     if (CodeVersion < '4') {
  3289.       PagePtrs[ParentPageNo][ParentPageIndex] = PagePtrs[ObjPageNo]
  3290.         [ObjPageIndex];
  3291.     } else {
  3292.       AccB = PagePtrs[ObjPageNo][ObjPageIndex];
  3293.       Inc(&ObjPageNo, &ObjPageIndex, 1);
  3294.       PagePtrs[ParentPageNo][ParentPageIndex] = PagePtrs[ObjPageNo]
  3295.         [ObjPageIndex];
  3296.       Inc(&ParentPageNo, &ParentPageIndex, -1);
  3297.       PagePtrs[ParentPageNo][ParentPageIndex] = AccB;
  3298.     }
  3299.   } else {
  3300.     WrkObj = FirstObj;
  3301.     do {
  3302.       PrevObj = WrkObj;
  3303.       /* WrkObj:=PrevObj.NXO */
  3304.       if (CodeVersion < '4') {
  3305.         CalcObjAdrs(PrevObj, &PrevPageNo, &PrevPageIndex, 5);
  3306.         WrkObj = PagePtrs[PrevPageNo][PrevPageIndex];
  3307.       } else {
  3308.         CalcObjAdrs(PrevObj, &PrevPageNo, &PrevPageIndex, 8);
  3309.         HighByte = PagePtrs[PrevPageNo][PrevPageIndex];
  3310.         Inc(&PrevPageNo, &PrevPageIndex, 1);
  3311.         LowByte = PagePtrs[PrevPageNo][PrevPageIndex];
  3312.         WrkObj = JoinBytes(LowByte, HighByte);
  3313.       }
  3314.     } while (WrkObj != ObjNo);
  3315.     Inc(&ObjPageNo, &ObjPageIndex, 1);
  3316.     /* PrevObj.NXO:=OBJ.NXO */
  3317.     if (CodeVersion < '4') {
  3318.       PagePtrs[PrevPageNo][PrevPageIndex] = PagePtrs[ObjPageNo][ObjPageIndex];
  3319.     } else {
  3320.       AccB = PagePtrs[ObjPageNo][ObjPageIndex];
  3321.       Inc(&ObjPageNo, &ObjPageIndex, 1);
  3322.       PagePtrs[PrevPageNo][PrevPageIndex] = PagePtrs[ObjPageNo][ObjPageIndex];
  3323.       Inc(&PrevPageNo, &PrevPageIndex, -1);
  3324.       PagePtrs[PrevPageNo][PrevPageIndex] = AccB;
  3325.     }
  3326.   }
  3327.   /* OBJ.NXO:=0 */
  3328.   /* OBJ.PTO:=0 */
  3329.   PagePtrs[ObjPageNo][ObjPageIndex] = 0;
  3330.   Inc(&ObjPageNo, &ObjPageIndex, -1);
  3331.   PagePtrs[ObjPageNo][ObjPageIndex] = 0;
  3332.   if (CodeVersion < '4')
  3333.     return;
  3334.   Inc(&ObjPageNo, &ObjPageIndex, -1);
  3335.   PagePtrs[ObjPageNo][ObjPageIndex] = 0;
  3336.   Inc(&ObjPageNo, &ObjPageIndex, -1);
  3337.   PagePtrs[ObjPageNo][ObjPageIndex] = 0;
  3338. }  /* RemoveObj */
  3339.  
  3340.  
  3341. Static void InsertObj(int ObjNo, int IntoObjNo) {
  3342.   int ObjPageNo;
  3343.   int ObjPageIndex;
  3344.   int IntoPageNo;
  3345.   int IntoPageIndex;
  3346.   int Next;
  3347.   int LowByte;
  3348.   int HighByte;
  3349.  
  3350.   RemoveObj(ObjNo);
  3351.   if (CodeVersion < '4') {
  3352.     CalcObjAdrs(ObjNo, &ObjPageNo, &ObjPageIndex, 4);
  3353.     /* ObjNo.PTO:=IntoObjNo */
  3354.     PagePtrs[ObjPageNo][ObjPageIndex] = IntoObjNo;
  3355.     CalcObjAdrs(IntoObjNo, &IntoPageNo, &IntoPageIndex, 6);
  3356.     /* ObjNo.NXO:=PTO.FSO */
  3357.     /* PTO.FSO:=ObjNo */
  3358.     Inc(&ObjPageNo, &ObjPageIndex, 1);
  3359.     Next = PagePtrs[IntoPageNo][IntoPageIndex];
  3360.     PagePtrs[IntoPageNo][IntoPageIndex] = ObjNo;
  3361.     PagePtrs[ObjPageNo][ObjPageIndex] = Next;
  3362.     return;
  3363.   }
  3364.   CalcObjAdrs(ObjNo, &ObjPageNo, &ObjPageIndex, 6);
  3365.   SplitWord(IntoObjNo, &LowByte, &HighByte);
  3366.   PagePtrs[ObjPageNo][ObjPageIndex] = HighByte;
  3367.   Inc(&ObjPageNo, &ObjPageIndex, 1);
  3368.   PagePtrs[ObjPageNo][ObjPageIndex] = LowByte;
  3369.   CalcObjAdrs(IntoObjNo, &IntoPageNo, &IntoPageIndex, 10);
  3370.   Inc(&ObjPageNo, &ObjPageIndex, 1);
  3371.   SplitWord(ObjNo, &LowByte, &HighByte);
  3372.   Next = PagePtrs[IntoPageNo][IntoPageIndex];
  3373.   PagePtrs[IntoPageNo][IntoPageIndex] = HighByte;
  3374.   PagePtrs[ObjPageNo][ObjPageIndex] = Next;
  3375.   Inc(&IntoPageNo, &IntoPageIndex, 1);
  3376.   Inc(&ObjPageNo, &ObjPageIndex, 1);
  3377.   Next = PagePtrs[IntoPageNo][IntoPageIndex];
  3378.   PagePtrs[IntoPageNo][IntoPageIndex] = LowByte;
  3379.   PagePtrs[ObjPageNo][ObjPageIndex] = Next;
  3380. }  /* InsertObj */
  3381.  
  3382.  
  3383. Static boolean ObjInObj(int ObjNo, int InObjNo) {
  3384.   int ObjPageNo;
  3385.   int ObjPageIndex;
  3386.   int ParentObj;
  3387.   int LowByte;
  3388.   int HighByte;
  3389.  
  3390.   if (CodeVersion < '4') {
  3391.     CalcObjAdrs(ObjNo, &ObjPageNo, &ObjPageIndex, 4);
  3392.     ParentObj = PagePtrs[ObjPageNo][ObjPageIndex];
  3393.     return (ParentObj == InObjNo);
  3394.   }
  3395.   CalcObjAdrs(ObjNo, &ObjPageNo, &ObjPageIndex, 6);
  3396.   HighByte = PagePtrs[ObjPageNo][ObjPageIndex];
  3397.   Inc(&ObjPageNo, &ObjPageIndex, 1);
  3398.   LowByte = PagePtrs[ObjPageNo][ObjPageIndex];
  3399.   ParentObj = JoinBytes(LowByte, HighByte);
  3400.   return (ParentObj == InObjNo);
  3401. }  /* ObjInObj */
  3402.  
  3403.  
  3404. Static boolean TestFlag(int ObjNo, int FlagNo) {
  3405.   int ObjPageNo;
  3406.   int ObjPageIndex;
  3407.   int FlagsHigh;
  3408.   int FlagsLow;
  3409.  
  3410.   CalcObjAdrs(ObjNo, &ObjPageNo, &ObjPageIndex, FlagNo / 16 * 2);
  3411.   FlagsHigh = PagePtrs[ObjPageNo][ObjPageIndex];
  3412.   Inc(&ObjPageNo, &ObjPageIndex, 1);
  3413.   FlagsLow = PagePtrs[ObjPageNo][ObjPageIndex];
  3414.   return (TstBit(JoinBytes(FlagsLow, FlagsHigh), 15 - (FlagNo & 15)));
  3415. }  /* TestFlag */
  3416.  
  3417.  
  3418. Static void SetFlag(int ObjNo, int FlagNo, boolean Value) {
  3419.   int ObjPageNo;
  3420.   int ObjPageIndex;
  3421.   int HighPageNo;
  3422.   int HighPageIndex;
  3423.   int Flags;
  3424.   int FlagsLow;
  3425.   int FlagsHigh;
  3426.  
  3427.   CalcObjAdrs(ObjNo, &ObjPageNo, &ObjPageIndex, FlagNo / 16 * 2);
  3428.   FlagsHigh = PagePtrs[ObjPageNo][ObjPageIndex];
  3429.   HighPageNo = ObjPageNo;
  3430.   HighPageIndex = ObjPageIndex;
  3431.   Inc(&ObjPageNo, &ObjPageIndex, 1);
  3432.   FlagsLow = PagePtrs[ObjPageNo][ObjPageIndex];
  3433.   Flags = JoinBytes(FlagsLow, FlagsHigh);
  3434.   if (Value)
  3435.     SetBit(&Flags, 15 - (FlagNo & 15));
  3436.   else
  3437.     ClrBit(&Flags, 15 - (FlagNo & 15));
  3438.   SplitWord(Flags, &FlagsLow, &FlagsHigh);
  3439.   PagePtrs[ObjPageNo][ObjPageIndex] = FlagsLow;
  3440.   PagePtrs[HighPageNo][HighPageIndex] = FlagsHigh;
  3441. }  /* SetFlag */
  3442.  
  3443.  
  3444. Static int GetWord(int GetMode) {
  3445.   int DataPageNo;
  3446.   int DataPageIndex;
  3447.   int LowByte;
  3448.   int HighByte;
  3449.  
  3450.   if (GetMode == 0) {
  3451.     return (Pop());
  3452.   } else if (GetMode < 16) {
  3453.     return (R.a[GetMode - 1]);
  3454.   } else {
  3455.     DataPageIndex = MiscInfo.DataPageIndex + (GetMode - 16) * 2;
  3456.     DataPageNo = MiscInfo.DataPageNo;
  3457.     ChkAddress(&DataPageNo, &DataPageIndex);
  3458.     HighByte = PagePtrs[DataPageNo][DataPageIndex];
  3459.     ++DataPageIndex;
  3460.     if (DataPageIndex >= 256) {
  3461.       DataPageIndex = 0;
  3462.       ++DataPageNo;
  3463.     }
  3464.     LowByte = PagePtrs[DataPageNo][DataPageIndex];
  3465.     return (JoinBytes(LowByte, HighByte));
  3466.   }
  3467. }  /* GetWord */
  3468.  
  3469.  
  3470. Static void PutWord(int theWord, int PutMode) {
  3471.   int DataPageNo;
  3472.   int DataPageIndex;
  3473.   int LowByte;
  3474.   int HighByte;
  3475.  
  3476.   if (PutMode == 0) {
  3477.     Push(theWord);
  3478.     return;
  3479.   }
  3480.   if (PutMode < 16) {
  3481.     R.a[PutMode - 1] = theWord;
  3482.     return;
  3483.   }
  3484.   DataPageIndex = MiscInfo.DataPageIndex + (PutMode - 16) * 2;
  3485.   DataPageNo = MiscInfo.DataPageNo;
  3486.   ChkAddress(&DataPageNo, &DataPageIndex);
  3487.   SplitWord(theWord, &LowByte, &HighByte);
  3488.   PagePtrs[DataPageNo][DataPageIndex] = HighByte;
  3489.   ++DataPageIndex;
  3490.   if (DataPageIndex >= 256) {
  3491.     DataPageIndex = 0;
  3492.     ++DataPageNo;
  3493.   }
  3494.   PagePtrs[DataPageNo][DataPageIndex] = LowByte;
  3495. }  /* PutWord */
  3496.  
  3497.  
  3498. Static void GetAccA(int GetMode) {
  3499.   AccA = GetWord(GetMode);
  3500.   if (GetMode == 0)
  3501.     Push(AccA);
  3502. }  /* GetAccA */
  3503.  
  3504.  
  3505. Static void PutAccA(int PutMode) {
  3506.   int Discard;
  3507.  
  3508.   if (PutMode == 0)
  3509.     Discard = Pop();
  3510.   PutWord(AccA, PutMode);
  3511. }  /* PutAccA */
  3512.  
  3513.  
  3514. Static void PrintStatusLine(void) {
  3515.   int Data0;
  3516.   int Data1;
  3517.   int Data2;
  3518.   int RoomPageNo;
  3519.   int RoomPageIndex;
  3520.   int NamePageNo;
  3521.   int NamePageIndex;
  3522.   int OldCursorX;
  3523.   int OldCursorY;
  3524.   boolean OldPrintListing;
  3525.   Char RoomName[256];
  3526.  
  3527.   if (CodeVersion >= '4')
  3528.     return;
  3529.   OldPrintListing = PrintListing;
  3530.   PrintListing = false;
  3531.   SaveTextAttributes();
  3532.   ScreenMode = 1;
  3533.   SetScreenMode();
  3534.   OldCursorX = CursorX;
  3535.   OldCursorY = CursorY;
  3536.   GotoXY(0, 0);
  3537.   SetLength(Spaces, ScreenWidth);
  3538.   PrintString(Spaces);
  3539.   Data0 = GetWord(16);
  3540.   Data1 = GetWord(17);
  3541.   Data2 = GetWord(18);
  3542.   CalcObjAdrs(Data0, &RoomPageNo, &RoomPageIndex, 7);
  3543.   NamePageNo = PagePtrs[RoomPageNo][RoomPageIndex];
  3544.   Inc(&RoomPageNo, &RoomPageIndex, 1);
  3545.   NamePageIndex = PagePtrs[RoomPageNo][RoomPageIndex];
  3546.   Inc(&NamePageNo, &NamePageIndex, 1);
  3547.   Push(DC_PageNo);
  3548.   Push(DC_PageIndex);
  3549.   DC_PageNo = NamePageNo;
  3550.   DC_PageIndex = NamePageIndex;
  3551.   WriteText('N', IntoBuffer, FromDC, RoomName);
  3552.   DC_PageIndex = Pop();
  3553.   DC_PageNo = Pop();
  3554.   GotoXY(1, 0);
  3555.   PrintString(RoomName);
  3556.   GotoXY(ScreenWidth - 20, 0);
  3557.   if (TstBit(MiscInfo.ConfigFlags, 1)) {
  3558.     PrintString("Time:");
  3559.     PrintCh(' ');
  3560.     if (Data1 == 0) {
  3561.       PrintString("12");
  3562.     } else if (Data1 > 12)
  3563.       PrintInteger(Data1 - 12);
  3564.     else
  3565.       PrintInteger(Data1);
  3566.     PrintCh(':');
  3567.     if (Data2 < 10)
  3568.       PrintCh('0');
  3569.     PrintInteger(Data2);
  3570.     if (Data1 < 12)
  3571.       PrintString("am");
  3572.     else
  3573.       PrintString("pm");
  3574.   } else {
  3575.     PrintString("Score:");
  3576.     PrintCh(' ');
  3577.     PrintInteger(Data1);
  3578.     PrintCh('/');
  3579.     PrintInteger(Data2);
  3580.   }
  3581.   RestoreTextAttributes();
  3582.   PrintListing = OldPrintListing;
  3583.   CursorX = OldCursorX;
  3584.   CursorY = OldCursorY;
  3585.   PositionCursor();
  3586. }  /* PrintStatusLine */
  3587.  
  3588.  
  3589. Static int GetPropertyNo(int ObjDataPageNo, int ObjDataPageIndex) {
  3590.   if (CodeVersion < '4')
  3591.     return (land(PagePtrs[ObjDataPageNo][ObjDataPageIndex], 31));
  3592.   else
  3593.     return (land(PagePtrs[ObjDataPageNo][ObjDataPageIndex], 63));
  3594. }  /* GetPropertyNo */
  3595.  
  3596.  
  3597. Static int GetPropertySize(int *ObjDataPageNo, int *ObjDataPageIndex,
  3598.                            boolean FetchNext) {
  3599.   int Data;
  3600.  
  3601.   Data = PagePtrs[*ObjDataPageNo][*ObjDataPageIndex];
  3602.   if (CodeVersion < '4') {
  3603.     return (land(lsr(Data, 5), 7) + 1);
  3604.   } else if (TstBit(Data, 7)) {
  3605.     if (FetchNext)
  3606.       Inc(ObjDataPageNo, ObjDataPageIndex, 1);
  3607.     return (land(PagePtrs[*ObjDataPageNo][*ObjDataPageIndex], 63));
  3608.   } else if (TstBit(Data, 6))
  3609.     return 2;
  3610.   else
  3611.     return 1;
  3612. }  /* GetPropertySize */
  3613.  
  3614.  
  3615. Static int DoGetWord(void) {
  3616.   return (GetWord(GetByteIPC()));
  3617. }  /* DoGetWord */
  3618.  
  3619.  
  3620. Static void DoPutWord(int theWord) {
  3621.   PutWord(theWord, GetByteIPC());
  3622. }  /* DoPutWord */
  3623.  
  3624.  
  3625. Static void Call(int Address, boolean IsFunc, int NumParams) {
  3626.   int LowByte;
  3627.   int HighByte;
  3628.   int CallPageNo;
  3629.   int CallPageIndex;
  3630.   int NumLocalVariables;
  3631.   int RegCnt;
  3632.   int FORLIM;
  3633.  
  3634.   if (Address == 0) {
  3635.     if (IsFunc)
  3636.       DoPutWord(0);
  3637.     return;
  3638.   }
  3639.   Push(MSP);
  3640.   Push(NewInstPageNo);
  3641.   Push(NewInstPageIndex);
  3642.   LowByte = IPC_PageIndex;
  3643.   HighByte = IsFunc;
  3644.   Push(JoinBytes(LowByte, HighByte));
  3645.   Push(IPC_PageNo);
  3646.   CalcCallAddress(Address, &CallPageNo, &CallPageIndex);
  3647.   IPC_PageIndex = CallPageIndex;
  3648.   IPC_PageNo = CallPageNo;
  3649.   NumLocalVariables = GetByteIPC();
  3650.   if (NumLocalVariables > 15)
  3651.     InternalError(TooManyLocalVariables);
  3652.   for (RegCnt = 0; RegCnt < NumLocalVariables; ++RegCnt) {
  3653.     Push(R.a[RegCnt]);
  3654.     if (CodeVersion <= '4')
  3655.       R.a[RegCnt] = GetWordIPC();
  3656.     else
  3657.       R.a[RegCnt] = 0;
  3658.   }
  3659.   Push(NumCallParams);
  3660.   NumCallParams = NumParams;
  3661.   if (CodeVersion >= '4') {
  3662.     if (NumCallParams > NumLocalVariables)
  3663.       InternalError(TooManyParameters);
  3664.   }
  3665.   FORLIM = NumCallParams;
  3666.   for (RegCnt = 0; RegCnt < FORLIM; ++RegCnt)
  3667.     R.a[RegCnt] = Opd.a[RegCnt + 1];
  3668.   Push(NumLocalVariables);
  3669.   MSP = SP;
  3670. }  /* Call */
  3671.  
  3672.  
  3673. Static void ResetZMachine(void) {
  3674.   int RegCnt;
  3675.  
  3676.   SP = 0;
  3677.   MSP = 0;
  3678.   NumCallParams = 0;
  3679.   if (CodeVersion <= '5') {
  3680.     IPC_PageNo = MiscInfo.StartPageNo;
  3681.     IPC_PageIndex = MiscInfo.StartIndex;
  3682.   } else {
  3683.     IPC_PageNo = 0;
  3684.     IPC_PageIndex = 0;
  3685.     Call(JoinBytes(MiscInfo.StartIndex, MiscInfo.StartPageNo), 0, 0);
  3686.   }
  3687.   StoryScreenMode = 0;
  3688.   ScreenMode = 0;
  3689.   FormatMode = 0;
  3690.   ComMode = 0;
  3691.   OutputMode = 0;
  3692.   ScreenEnabled = true;
  3693.   BufferEnabled = false;
  3694.   DirectEnabled = false;
  3695.   WindowEnabled = false;
  3696.   WritingInWindow = false;
  3697.   BufferPageNo = -1;
  3698.   BufferPageIndex = -1;
  3699.   BufferIndex = 0;
  3700.   LineIndex = 0;
  3701.   ScrollTop = (CodeVersion <= '3') + 1;
  3702.   StoryScrollTop = ScrollTop;
  3703.   LineNo = ScrollTop;
  3704.   SetInterpreterConfiguration();
  3705.   for (RegCnt = 0; RegCnt <= 15; ++RegCnt)
  3706.     R.a[RegCnt] = 0;
  3707. }  /* ResetZMachine */
  3708.  
  3709.  
  3710. Static void ExecuteSingleInstruction(void);
  3711.  
  3712. Local void ExecuteOrgCode(PtrBPT WrkBPT) {
  3713.   PutOrgCode(WrkBPT);
  3714.   ExecuteSingleInstruction();
  3715.   PutBPTCode(WrkBPT);
  3716. }  /* ExecuteOrgCode */
  3717.  
  3718. Local void ExecuteBPT(void) {
  3719.   int BPT_No;
  3720.   int BPT_Type;
  3721.   PtrBPT WrkBPT;
  3722.  
  3723.   BPT_No = GetByteIPC();
  3724.   BPT_Type = GetByteIPC();
  3725.   if (BPT_No == 0 ||
  3726.       BPT_Type != TraceBPT && BPT_Type != RunBPT && BPT_Type != UserBPT)
  3727.     InternalError(BreakPoint);
  3728.   WrkBPT = BPT_List;
  3729.   while (WrkBPT != NULL) {
  3730.     if (WrkBPT->BPT_No == BPT_No)
  3731.       goto _L1;
  3732.     WrkBPT = WrkBPT->NextBPT;
  3733.   }
  3734. _L1:
  3735.   if (WrkBPT == NULL)
  3736.     InternalError(BreakPoint);
  3737.   if (WrkBPT->BPT_PageNo != NewInstPageNo ||
  3738.       WrkBPT->BPT_PageIndex != NewInstPageIndex)
  3739.     InternalError(BreakPoint);
  3740.   IPC_PageNo = NewInstPageNo;
  3741.   IPC_PageIndex = NewInstPageIndex;
  3742.   if (Stepping && BPT_Type == UserBPT ||
  3743.       FirstInstPageNo == IPC_PageNo && FirstInstPageIndex == IPC_PageIndex) {
  3744.     ExecuteOrgCode(WrkBPT);
  3745.     return;
  3746.   }
  3747.   DC_PageNo = IPC_PageNo;
  3748.   DC_PageIndex = IPC_PageIndex;
  3749.   if (BPT_Type == UserBPT) {
  3750.     ChkWait();
  3751.     RingBell();
  3752.     ++WrkBPT->HitCnt;
  3753.     PrintString("Stopped by user BPT #");
  3754.     PrintByte(BPT_No, 2);
  3755.     PrintString(" hit=");
  3756.     PrintWord(WrkBPT->HitCnt, 4);
  3757.     ChkWait();
  3758.   } else if (BPT_Type == RunBPT && Running || BPT_Type == TraceBPT && Tracing)
  3759.     ClearBPT(BPT_No);
  3760.   Running = false;
  3761.   if (Stepping) {
  3762.     Cmd = SwitchToStep;
  3763.   } else {
  3764.     PrintZState();
  3765.     Disassemble(1, true);
  3766.   }
  3767.   longjmp(_JL999, 1);
  3768. }  /* ExecuteBPT */
  3769.  
  3770. Local void Return(int Value) {
  3771.   int NumLocalVariables;
  3772.   int RegCnt;
  3773.   int Discard;
  3774.   int HighByte;
  3775.   boolean IsFunc;
  3776.  
  3777.   SP = MSP;
  3778.   NumLocalVariables = Pop();
  3779.   NumCallParams = Pop();
  3780.   for (RegCnt = NumLocalVariables - 1; RegCnt >= 0; --RegCnt)
  3781.     R.a[RegCnt] = Pop();
  3782.   IPC_PageNo = Pop();
  3783.   SplitWord(Pop(), &IPC_PageIndex, &HighByte);
  3784.   IsFunc = HighByte & 1;
  3785.   Discard = Pop();
  3786.   Discard = Pop();
  3787.   MSP = Pop();
  3788.   if (IPC_PageNo == 0 && IPC_PageIndex == 0)
  3789.     InternalError(NotImplemented);
  3790.   if (IsFunc)
  3791.     DoPutWord(Value);
  3792. }  /* Return */
  3793.  
  3794. Local void HandleTrue(void) {
  3795.   boolean TrueJump;
  3796.   int Distance;
  3797.  
  3798.   GetJump(FromIPC, &TrueJump, &Distance);
  3799.   if (!TrueJump)
  3800.     return;
  3801.   if (Distance == 0) {
  3802.     Return(0);
  3803.     return;
  3804.   }
  3805.   if (Distance == 1)
  3806.     Return(1);
  3807.   else
  3808.     CalcJump(IPC_PageNo, IPC_PageIndex, &IPC_PageNo, &IPC_PageIndex, Distance);
  3809. }  /* HandleTrue */
  3810.  
  3811. Local void HandleFalse(void) {
  3812.   boolean TrueJump;
  3813.   int Distance;
  3814.  
  3815.   GetJump(FromIPC, &TrueJump, &Distance);
  3816.   if (TrueJump)
  3817.     return;
  3818.   if (Distance == 0) {
  3819.     Return(0);
  3820.     return;
  3821.   }
  3822.   if (Distance == 1)
  3823.     Return(1);
  3824.   else
  3825.     CalcJump(IPC_PageNo, IPC_PageIndex, &IPC_PageNo, &IPC_PageIndex, Distance);
  3826. }  /* HandleFalse */
  3827.  
  3828. Local void WTX(int *TextPageNo, int *TextPageIndex, boolean IncCnt) {
  3829.   int SavePageNo;
  3830.   int SavePageIndex;
  3831.  
  3832.   Push(IPC_PageNo);
  3833.   Push(IPC_PageIndex);
  3834.   IPC_PageNo = *TextPageNo;
  3835.   IPC_PageIndex = *TextPageIndex;
  3836.   WriteText('T', ToStoryOutput, FromIPC, GlobalTextBuffer);
  3837.   SavePageNo = IPC_PageNo;
  3838.   SavePageIndex = IPC_PageIndex;
  3839.   IPC_PageIndex = Pop();
  3840.   IPC_PageNo = Pop();
  3841.   if (IncCnt) {
  3842.     *TextPageNo = SavePageNo;
  3843.     *TextPageIndex = SavePageIndex;
  3844.   }
  3845. }  /* WTX */
  3846.  
  3847. Local boolean SavedState(void) {
  3848.   boolean SavedState_ReturnValue;
  3849.   boolean OldPrintListing;
  3850.   int PageCnt;
  3851.   int NumPagesToSave;
  3852.   int LowByte;
  3853.   int HighByte;
  3854.   int RegCnt;
  3855.   int SaveIndex;
  3856.   Char Answer;
  3857.   Char FileName[256];
  3858.   Char UnixName[256];
  3859.   FILE *SaveFile;
  3860.   Char STR1[256];
  3861.   Char STR2[256];
  3862.   FILEBUFNC(SaveFile,aPage);
  3863.  
  3864.   SaveFile = NULL;
  3865.   SavedState_ReturnValue = false;
  3866.   ZM_NewLine();
  3867.   OldPrintListing = PrintListing;
  3868.   PrintListing = false;
  3869.   PrintString("Save file name -->");
  3870.   PrintCh(' ');
  3871.   SetLength(FileName, 0);
  3872.   ReadLine(true, FileName, 79, -1, 0);
  3873.   if (*FileName != '\0') {
  3874.     sprintf(FileName, "%s%s", StateDirectory(STR1), strcpy(STR2, FileName));
  3875.     Answer = 'y';
  3876.     if (FileExists(FileName)) {
  3877.       PrintString("File already exists. Overwrite it (y/n)?");
  3878.       PrintCh(' ');
  3879.       CursorOn();
  3880.       Answer = ReadKeyWithNoEcho(-1);
  3881.       CursorOff();
  3882.       if (Answer == 'Y')
  3883.         Answer = 'y';
  3884.       if (Answer == 'y')
  3885.         PrintString("yes");
  3886.       else
  3887.         PrintString("no");
  3888.       ChkWait();
  3889.     }
  3890.     if (Answer == 'y') {
  3891.       strcpy(UnixName, FileName);
  3892.       if (SaveFile != NULL)
  3893.         SaveFile = freopen(UnixName, "wb", SaveFile);
  3894.       else
  3895.         SaveFile = fopen(UnixName, "wb");
  3896.       if (SaveFile == NULL)
  3897.         _EscIO(FileNotFound);
  3898.       SETUPBUF(SaveFile, aPage);
  3899.       PageCnt = 0;
  3900.       NumPagesToSave = MiscInfo.SaveStateSizeHigh;
  3901.       AGETFBUF(SaveFile, aPage)[0] = MiscInfo.ReleaseHigh;
  3902.       AGETFBUF(SaveFile, aPage)[1] = MiscInfo.ReleaseLow;
  3903.       SplitWord(IPC_PageNo, &LowByte, &HighByte);
  3904.       AGETFBUF(SaveFile, aPage)[2] = HighByte;
  3905.       AGETFBUF(SaveFile, aPage)[3] = LowByte;
  3906.       AGETFBUF(SaveFile, aPage)[4] = IPC_PageIndex;
  3907.       SplitWord(SP, &LowByte, &HighByte);
  3908.       AGETFBUF(SaveFile, aPage)[5] = HighByte;
  3909.       AGETFBUF(SaveFile, aPage)[6] = LowByte;
  3910.       SplitWord(MSP, &LowByte, &HighByte);
  3911.       AGETFBUF(SaveFile, aPage)[7] = HighByte;
  3912.       AGETFBUF(SaveFile, aPage)[8] = LowByte;
  3913.       AGETFBUF(SaveFile, aPage)[9] = NumCallParams;
  3914.       SaveIndex = 10;
  3915.       for (RegCnt = 0; RegCnt <= 14; ++RegCnt) {
  3916.         SplitWord(R.a[RegCnt], &LowByte, &HighByte);
  3917.         AGETFBUF(SaveFile, aPage)[SaveIndex] = HighByte;
  3918.         AGETFBUF(SaveFile, aPage)[SaveIndex + 1] = LowByte;
  3919.         SaveIndex += 2;
  3920.       }
  3921.       PUT(SaveFile, aPage);
  3922.       SaveIndex = 0;
  3923.       RegCnt = 0;
  3924.       for (RegCnt = 0; RegCnt <= MaxStack; ++RegCnt) {
  3925.         SplitWord(Stack[RegCnt], &LowByte, &HighByte);
  3926.         if (SaveIndex > 255) {
  3927.           PUT(SaveFile, aPage);
  3928.           SaveIndex = 0;
  3929.         }
  3930.         AGETFBUF(SaveFile, aPage)[SaveIndex] = HighByte;
  3931.         AGETFBUF(SaveFile, aPage)[SaveIndex + 1] = LowByte;
  3932.         SaveIndex += 2;
  3933.       }
  3934.       PUT(SaveFile, aPage);
  3935.       while (PageCnt < NumPagesToSave) {
  3936.         memcpy(AGETFBUF(SaveFile, aPage), PagePtrs[PageCnt],
  3937.                signedsizeof(aPage));
  3938.         PUT(SaveFile, aPage);
  3939.         ++PageCnt;
  3940.       }
  3941.       SavedState_ReturnValue = (PageCnt == NumPagesToSave);
  3942.     }
  3943.   }
  3944.   ClosePageFile(&SaveFile);
  3945.   PrintListing = OldPrintListing;
  3946.   if (SaveFile != NULL)
  3947.     fclose(SaveFile);
  3948.   return SavedState_ReturnValue;
  3949. }  /* SavedState */
  3950.  
  3951. Local boolean RestoredState(void) {
  3952.   boolean RestoredState_ReturnValue;
  3953.   boolean OldPrintListing;
  3954.   boolean BugVersion;
  3955.   int PageCnt;
  3956.   int NumPagesToSave;
  3957.   int RegCnt;
  3958.   int SaveIndex;
  3959.   Char FileName[256];
  3960.   Char UnixName[256];
  3961.   FILE *SaveFile;
  3962.   Char STR1[256];
  3963.   Char STR2[256];
  3964.   FILEBUFNC(SaveFile,aPage);
  3965.  
  3966.   SaveFile = NULL;
  3967.   RestoredState_ReturnValue = false;
  3968.   ZM_NewLine();
  3969.   OldPrintListing = PrintListing;
  3970.   PrintListing = false;
  3971.   PrintString("Save file name -->");
  3972.   PrintCh(' ');
  3973.   SetLength(FileName, 0);
  3974.   ReadLine(true, FileName, 79, -1, 0);
  3975.   if (*FileName != '\0') {
  3976.     sprintf(FileName, "%s%s", StateDirectory(STR1), strcpy(STR2, FileName));
  3977.     if (!FileExists(FileName)) {
  3978.       PrintString("File not found.");
  3979.       ChkWait();
  3980.     } else {
  3981.       strcpy(UnixName, FileName);
  3982.       NumPagesToSave = MiscInfo.SaveStateSizeHigh;
  3983.       PageCnt = 0;
  3984.       if (SaveFile != NULL)
  3985.         SaveFile = freopen(UnixName, "rb", SaveFile);
  3986.       else
  3987.         SaveFile = fopen(UnixName, "rb");
  3988.       if (SaveFile == NULL)
  3989.         _EscIO(FileNotFound);
  3990.       RESETBUF(SaveFile, aPage);
  3991.       BugVersion = (AGETFBUF(SaveFile, aPage)[0] == 0) &
  3992.                    (AGETFBUF(SaveFile, aPage)[1] == 0);
  3993.       if (((MiscInfo.ReleaseHigh != AGETFBUF(SaveFile, aPage)[0]) |
  3994.            (MiscInfo.ReleaseLow != AGETFBUF(SaveFile, aPage)[1])) &&
  3995.           !BugVersion) {
  3996.         PrintString("Save file has wrong release number.");
  3997.         ChkWait();
  3998.       } else {
  3999.         if (BugVersion) {
  4000.           PrintString("IPC, registers and stack will not be restored.");
  4001.           ChkWait();
  4002.           GET(SaveFile, aPage);
  4003.         } else {
  4004.           IPC_PageNo = JoinBytes(AGETFBUF(SaveFile, aPage)[3],
  4005.                                  AGETFBUF(SaveFile, aPage)[2]);
  4006.           IPC_PageIndex = AGETFBUF(SaveFile, aPage)[4];
  4007.           SP = JoinBytes(AGETFBUF(SaveFile, aPage)[6],
  4008.                          AGETFBUF(SaveFile, aPage)[5]);
  4009.           MSP = JoinBytes(AGETFBUF(SaveFile, aPage)[8],
  4010.                           AGETFBUF(SaveFile, aPage)[7]);
  4011.           NumCallParams = AGETFBUF(SaveFile, aPage)[9];
  4012.           SaveIndex = 10;
  4013.           for (RegCnt = 0; RegCnt <= 14; ++RegCnt) {
  4014.             R.a[RegCnt] = JoinBytes(AGETFBUF(SaveFile, aPage)[SaveIndex + 1],
  4015.                                     AGETFBUF(SaveFile, aPage)[SaveIndex]);
  4016.             SaveIndex += 2;
  4017.           }
  4018.           GET(SaveFile, aPage);
  4019.           SaveIndex = 0;
  4020.           RegCnt = 0;
  4021.           for (RegCnt = 0; RegCnt <= MaxStack; ++RegCnt) {
  4022.             if (SaveIndex > 255) {
  4023.               GET(SaveFile, aPage);
  4024.               SaveIndex = 0;
  4025.             }
  4026.             Stack[RegCnt] = JoinBytes(AGETFBUF(SaveFile, aPage)[SaveIndex + 1],
  4027.                                       AGETFBUF(SaveFile, aPage)[SaveIndex]);
  4028.             SaveIndex += 2;
  4029.           }
  4030.         }
  4031.         GET(SaveFile, aPage);
  4032.         while ((PageCnt < NumPagesToSave) & (!BUFEOF(SaveFile))) {
  4033.           memcpy(PagePtrs[PageCnt], AGETFBUF(SaveFile, aPage),
  4034.                  signedsizeof(aPage));
  4035.           ++PageCnt;
  4036.           GET(SaveFile, aPage);
  4037.         }
  4038.         SetInterpreterConfiguration();
  4039.         RestoredState_ReturnValue = (PageCnt == NumPagesToSave);
  4040.       }
  4041.     }
  4042.   }
  4043.   ClosePageFile(&SaveFile);
  4044.   PrintListing = OldPrintListing;
  4045.   if (SaveFile != NULL)
  4046.     fclose(SaveFile);
  4047.   return RestoredState_ReturnValue;
  4048. }  /* RestoredState */
  4049.  
  4050. Local void GetObjPropertyPtr(int ObjNo, int *ObjDataPageNo,
  4051.                              int *ObjDataPageIndex) {
  4052.   int ObjPageNo;
  4053.   int ObjPageIndex;
  4054.  
  4055.   if (CodeVersion < '4')
  4056.     CalcObjAdrs(ObjNo, &ObjPageNo, &ObjPageIndex, 7);
  4057.   else
  4058.     CalcObjAdrs(ObjNo, &ObjPageNo, &ObjPageIndex, 12);
  4059.   *ObjDataPageNo = PagePtrs[ObjPageNo][ObjPageIndex];
  4060.   Inc(&ObjPageNo, &ObjPageIndex, 1);
  4061.   *ObjDataPageIndex = PagePtrs[ObjPageNo][ObjPageIndex];
  4062.   Inc(ObjDataPageNo, ObjDataPageIndex,
  4063.       PagePtrs[*ObjDataPageNo][*ObjDataPageIndex] * 2 + 1);
  4064. }  /* GetObjPropertyPtr */
  4065.  
  4066. Local void GetMultipleOperands_(boolean Extended) {
  4067.   int Mode;
  4068.   boolean Continue;
  4069.   int BitlCnt;
  4070.  
  4071.   if (Extended) {
  4072.     Mode = GetWordIPC();
  4073.     BitlCnt = 7;
  4074.   } else {
  4075.     Mode = GetByteIPC();
  4076.     BitlCnt = 3;
  4077.   }
  4078.   Continue = true;
  4079.   OpdCnt = 0;
  4080.   while (Continue) {
  4081.     switch (Bittle(Mode, BitlCnt)) {
  4082.  
  4083.     case 0:
  4084.       Opd.a[OpdCnt] = GetWordIPC();
  4085.       break;
  4086.  
  4087.     case 1:
  4088.       Opd.a[OpdCnt] = GetByteIPC();
  4089.       break;
  4090.  
  4091.     case 2:
  4092.       Opd.a[OpdCnt] = DoGetWord();
  4093.       break;
  4094.  
  4095.     case 3:
  4096.       Continue = false;
  4097.       break;
  4098.     }
  4099.     if (!Continue)
  4100.       break;
  4101.     ++OpdCnt;
  4102.     if (BitlCnt > 0)
  4103.       --BitlCnt;
  4104.     else
  4105.       Continue = false;
  4106.   }
  4107. }  /* GetMultipleOperands */
  4108.  
  4109. Local void StoreWord(void) {
  4110.   int DestPageNo;
  4111.   int DestIndex;
  4112.   int LowByte;
  4113.   int HighByte;
  4114.  
  4115.   if (OpdCnt != 3)
  4116.     InternalError(IllNumOperands);
  4117.   SplitWord(Opd.U1.s0, &DestIndex, &DestPageNo);
  4118.   DestIndex += Opd.U1.s1 * 2;
  4119.   ChkAddress(&DestPageNo, &DestIndex);
  4120.   SplitWord(Opd.U1.s2, &LowByte, &HighByte);
  4121.   PagePtrs[DestPageNo][DestIndex] = HighByte;
  4122.   Inc(&DestPageNo, &DestIndex, 1);
  4123.   PagePtrs[DestPageNo][DestIndex] = LowByte;
  4124. }  /* StoreWord */
  4125.  
  4126. Local void StoreByte(void) {
  4127.   int DestPageNo;
  4128.   int DestIndex;
  4129.  
  4130.   if (OpdCnt != 3)
  4131.     InternalError(IllNumOperands);
  4132.   SplitWord(Opd.U1.s0, &DestIndex, &DestPageNo);
  4133.   Inc(&DestPageNo, &DestIndex, Opd.U1.s1);
  4134.   PagePtrs[DestPageNo][DestIndex] = Opd.U1.s2;
  4135. }  /* StoreByte */
  4136.  
  4137. Local void StoreProperty(void) {
  4138.   int ObjDataPageNo;
  4139.   int ObjDataIndex;
  4140.   int LowByte;
  4141.   int HighByte;
  4142.  
  4143.   if (OpdCnt != 3)
  4144.     InternalError(IllNumOperands);
  4145.   GetObjPropertyPtr(Opd.U1.s0, &ObjDataPageNo, &ObjDataIndex);
  4146. _L30:
  4147.   AccA = GetPropertyNo(ObjDataPageNo, ObjDataIndex);
  4148.   if (AccA == 0)
  4149.     InternalError(MissingObjData);
  4150.   if (AccA != Opd.U1.s1) {
  4151.     Inc(&ObjDataPageNo, &ObjDataIndex,
  4152.         GetPropertySize(&ObjDataPageNo, &ObjDataIndex, true) + 1);
  4153.     goto _L30;
  4154.   }
  4155.   AccA = GetPropertySize(&ObjDataPageNo, &ObjDataIndex, true);
  4156.   Inc(&ObjDataPageNo, &ObjDataIndex, 1);
  4157.   SplitWord(Opd.U1.s2, &LowByte, &HighByte);
  4158.   if (AccA == 1) {
  4159.     PagePtrs[ObjDataPageNo][ObjDataIndex] = LowByte;
  4160.     return;
  4161.   }
  4162.   if (AccA != 2) {
  4163.     InternalError(IllObjPropertyStore);
  4164.     return;
  4165.   }
  4166.   PagePtrs[ObjDataPageNo][ObjDataIndex] = HighByte;
  4167.   Inc(&ObjDataPageNo, &ObjDataIndex, 1);
  4168.   PagePtrs[ObjDataPageNo][ObjDataIndex] = LowByte;
  4169. }  /* StoreProperty */
  4170.  
  4171. /* Local variables for PackWord: */
  4172. struct PackWord_LocalVariables {
  4173.   ShortInteger *Pkd;
  4174.   int PkdCnt;
  4175. } ;
  4176.  
  4177. Local void PutInPkd(int Value, struct PackWord_LocalVariables *PackWord_Vars) {
  4178.   int WordNo;
  4179.   int FieldNo;
  4180.   int HighByte;
  4181.   int LowByte;
  4182.  
  4183.   if (PackWord_Vars->PkdCnt >= WordNumChars)
  4184.     return;
  4185.   WordNo = PackWord_Vars->PkdCnt / 3;
  4186.   FieldNo = PackWord_Vars->PkdCnt % 3;
  4187.   SplitWord(PackWord_Vars->Pkd[WordNo], &LowByte, &HighByte);
  4188.   switch (FieldNo) {
  4189.  
  4190.   case 0:
  4191.     HighByte = lor(land(HighByte, 3), land(lsl(Value, 2), 124));
  4192.     break;
  4193.  
  4194.   case 1:
  4195.     HighByte = lor(land(HighByte, 252), land(lsr(Value, 3), 3));
  4196.     LowByte = lor(land(LowByte, 31), land(lsl(Value, 5), 224));
  4197.     break;
  4198.  
  4199.   case 2:
  4200.     LowByte = lor(land(LowByte, 224), land(Value, 31));
  4201.     break;
  4202.   }
  4203.   PackWord_Vars->Pkd[WordNo] = JoinBytes(LowByte, HighByte);
  4204.   ++PackWord_Vars->PkdCnt;
  4205. }  /* PutInPkd */
  4206.  
  4207. Local void PackWord(aWord Word, aPackedWord Pkd_) {
  4208.   struct PackWord_LocalVariables V;
  4209.   int ChrCnt;
  4210.   int SmallShift;
  4211.   int TableIndex;
  4212.   int LowByte;
  4213.   int HighByte;
  4214.   Char WrkCh;
  4215.  
  4216.   V.Pkd = Pkd_;
  4217.   V.Pkd[0] = 5285;
  4218.   V.Pkd[1] = 5285;
  4219.   V.Pkd[2] = 5285;
  4220.   V.PkdCnt = 0;
  4221.   SmallShift = 'a' - 6;
  4222.   for (ChrCnt = 0; ChrCnt <= 8; ++ChrCnt) {
  4223.     WrkCh = Word[ChrCnt];
  4224.     if (WrkCh == '\0') {
  4225.       PutInPkd(5, &V);
  4226.     } else if (islower(WrkCh)) {
  4227.       PutInPkd(WrkCh - SmallShift, &V);
  4228.     } else {
  4229.       PutInPkd(5, &V);
  4230.       if (CodeVersion == '1') {
  4231.         if (P_inset(WrkCh, Char1Set)) {
  4232.           TableIndex = 1;
  4233.           while (WrkCh != Char1Table[TableIndex - 1])
  4234.             ++TableIndex;
  4235.           PutInPkd(TableIndex + 6, &V);
  4236.         } else {
  4237.           PutInPkd(6, &V);
  4238.           PutInPkd(land(lsr(WrkCh, 5), 3), &V);
  4239.           PutInPkd(land(WrkCh, 31), &V);
  4240.         }
  4241.       } else if (P_inset(WrkCh, Char23Set)) {
  4242.         TableIndex = 1;
  4243.         while (WrkCh != Char23Table[TableIndex - 1])
  4244.           ++TableIndex;
  4245.         PutInPkd(TableIndex + 7, &V);
  4246.       } else {
  4247.         PutInPkd(6, &V);
  4248.         PutInPkd(land(lsr(WrkCh, 5), 3), &V);
  4249.         PutInPkd(land(WrkCh, 31), &V);
  4250.       }
  4251.     }
  4252.   }
  4253.   if (CodeVersion >= '4') {
  4254.     SplitWord(V.Pkd[2], &LowByte, &HighByte);
  4255.     HighByte = lor(HighByte, 128);
  4256.     V.Pkd[2] = JoinBytes(LowByte, HighByte);
  4257.   } else {
  4258.     SplitWord(V.Pkd[1], &LowByte, &HighByte);
  4259.     HighByte = lor(HighByte, 128);
  4260.     V.Pkd[1] = JoinBytes(LowByte, HighByte);
  4261.   }
  4262.   if (DebugVocab) {
  4263.     ChkWait();
  4264.     PrintWord(V.Pkd[2], 4);
  4265.     PrintWord(V.Pkd[1], 4);
  4266.     PrintWord(V.Pkd[0], 4);
  4267.     ChkWait();
  4268.   }
  4269.   V.Pkd[0] += CmpShift;
  4270.   V.Pkd[1] += CmpShift;
  4271.   V.Pkd[2] += CmpShift;
  4272. }  /* PackWord */
  4273.  
  4274. /* Local variables for ParseSentence: */
  4275. struct ParseSentence_LocalVariables {
  4276.   int LinePageNo;
  4277.   int LinePageIndex;
  4278.   int VocabPageNo;
  4279.   int VocabPageIndex;
  4280.   Char WrkCh;
  4281.   int EntryLength;
  4282.   int InputIndex;
  4283.   int InputLength;
  4284.   aPackedWord Pkd;
  4285. } ;
  4286.  
  4287. Local void GetCh_(struct ParseSentence_LocalVariables *ParseSentence_Vars) {
  4288.   if (ParseSentence_Vars->InputIndex > ParseSentence_Vars->InputLength) {
  4289.     ParseSentence_Vars->WrkCh = EOL();
  4290.     return;
  4291.   }
  4292.   ParseSentence_Vars->WrkCh = PagePtrs[ParseSentence_Vars->LinePageNo]
  4293.     [ParseSentence_Vars->LinePageIndex];
  4294.   if (isupper(ParseSentence_Vars->WrkCh))
  4295.     ParseSentence_Vars->WrkCh = _tolower(ParseSentence_Vars->WrkCh);
  4296.   Inc(&ParseSentence_Vars->LinePageNo, &ParseSentence_Vars->LinePageIndex, 1);
  4297.   ++ParseSentence_Vars->InputIndex;
  4298. }  /* GetCh */
  4299.  
  4300. Local void BackCh(struct ParseSentence_LocalVariables *ParseSentence_Vars) {
  4301.   Dec(&ParseSentence_Vars->LinePageNo, &ParseSentence_Vars->LinePageIndex, 1);
  4302.   --ParseSentence_Vars->InputIndex;
  4303. }  /* BackCh */
  4304.  
  4305. Local int GetVocabByte(struct ParseSentence_LocalVariables *ParseSentence_Vars) {
  4306.   int GetVocabByte_ReturnValue;
  4307.  
  4308.   GetVocabByte_ReturnValue = PagePtrs[ParseSentence_Vars->VocabPageNo]
  4309.     [ParseSentence_Vars->VocabPageIndex];
  4310.   Inc(&ParseSentence_Vars->VocabPageNo, &ParseSentence_Vars->VocabPageIndex,
  4311.       1);
  4312.   return GetVocabByte_ReturnValue;
  4313. }  /* GetVocabByte */
  4314.  
  4315. Local int SearchWord(int StartPageNo, int StartPageIndex, int NumWords,
  4316.                      struct ParseSentence_LocalVariables *ParseSentence_Vars) {
  4317.   int Wrk;
  4318.   int LowerNum;
  4319.   int UpperNum;
  4320.   int MiddlePageNo;
  4321.   int MiddlePageIndex;
  4322.   int HighByte;
  4323.   int LowByte;
  4324.   int WordPageNo;
  4325.   int WordPageIndex;
  4326.  
  4327.   ParseSentence_Vars->VocabPageNo = StartPageNo;
  4328.   ParseSentence_Vars->VocabPageIndex = StartPageIndex;
  4329.   WordPageNo = ParseSentence_Vars->VocabPageNo;
  4330.   WordPageIndex = ParseSentence_Vars->VocabPageIndex;
  4331.   if (NumWords == 0) {
  4332.     return 0;
  4333.   } else if (NumWords == 1) {
  4334.     if (DebugVocab) {
  4335.       DC_PageNo = WordPageNo;
  4336.       DC_PageIndex = WordPageIndex;
  4337.       WriteText('V', OntoScreen, FromDC, GlobalTextBuffer);
  4338.     }
  4339.     HighByte = GetVocabByte(ParseSentence_Vars);
  4340.     LowByte = GetVocabByte(ParseSentence_Vars);
  4341.     Wrk = JoinBytes(LowByte, HighByte);
  4342.     if (Wrk + CmpShift != ParseSentence_Vars->Pkd[0]) {
  4343.       return 0;
  4344.     } else {
  4345.       HighByte = GetVocabByte(ParseSentence_Vars);
  4346.       LowByte = GetVocabByte(ParseSentence_Vars);
  4347.       Wrk = JoinBytes(LowByte, HighByte);
  4348.       if (Wrk + CmpShift != ParseSentence_Vars->Pkd[1]) {
  4349.         return 0;
  4350.       } else if (CodeVersion < '4') {
  4351.         return (JoinBytes(WordPageIndex, WordPageNo));
  4352.       } else {
  4353.         HighByte = GetVocabByte(ParseSentence_Vars);
  4354.         LowByte = GetVocabByte(ParseSentence_Vars);
  4355.         Wrk = JoinBytes(LowByte, HighByte);
  4356.         if (Wrk + CmpShift != ParseSentence_Vars->Pkd[2])
  4357.           return 0;
  4358.         else
  4359.           return (JoinBytes(WordPageIndex, WordPageNo));
  4360.       }
  4361.     }
  4362.   } else {
  4363.     LowerNum = NumWords / 2;
  4364.     if (NumWords & 1)
  4365.       UpperNum = LowerNum;
  4366.     else
  4367.       UpperNum = LowerNum - 1;
  4368.     Inc(&ParseSentence_Vars->VocabPageNo, &ParseSentence_Vars->VocabPageIndex,
  4369.         ParseSentence_Vars->EntryLength * LowerNum);
  4370.     WordPageNo = ParseSentence_Vars->VocabPageNo;
  4371.     WordPageIndex = ParseSentence_Vars->VocabPageIndex;
  4372.     if (DebugVocab) {
  4373.       DC_PageNo = WordPageNo;
  4374.       DC_PageIndex = WordPageIndex;
  4375.       WriteText('V', OntoScreen, FromDC, GlobalTextBuffer);
  4376.     }
  4377.     MiddlePageNo = ParseSentence_Vars->VocabPageNo;
  4378.     MiddlePageIndex = ParseSentence_Vars->VocabPageIndex;
  4379.     Inc(&MiddlePageNo, &MiddlePageIndex, ParseSentence_Vars->EntryLength);
  4380.     HighByte = GetVocabByte(ParseSentence_Vars);
  4381.     LowByte = GetVocabByte(ParseSentence_Vars);
  4382.     Wrk = JoinBytes(LowByte, HighByte) + CmpShift;
  4383.     if (ParseSentence_Vars->Pkd[0] < Wrk) {
  4384.       return (SearchWord(StartPageNo, StartPageIndex, LowerNum,
  4385.                          ParseSentence_Vars));
  4386.     } else if (ParseSentence_Vars->Pkd[0] > Wrk) {
  4387.       return (SearchWord(MiddlePageNo, MiddlePageIndex, UpperNum,
  4388.                          ParseSentence_Vars));
  4389.     } else {
  4390.       HighByte = GetVocabByte(ParseSentence_Vars);
  4391.       LowByte = GetVocabByte(ParseSentence_Vars);
  4392.       Wrk = JoinBytes(LowByte, HighByte) + CmpShift;
  4393.       if (ParseSentence_Vars->Pkd[1] < Wrk) {
  4394.         return (SearchWord(StartPageNo, StartPageIndex, LowerNum,
  4395.                            ParseSentence_Vars));
  4396.       } else if (ParseSentence_Vars->Pkd[1] > Wrk) {
  4397.         return (SearchWord(MiddlePageNo, MiddlePageIndex, UpperNum,
  4398.                            ParseSentence_Vars));
  4399.       } else if (CodeVersion < '4') {
  4400.         return (JoinBytes(WordPageIndex, WordPageNo));
  4401.       } else {
  4402.         HighByte = GetVocabByte(ParseSentence_Vars);
  4403.         LowByte = GetVocabByte(ParseSentence_Vars);
  4404.         Wrk = JoinBytes(LowByte, HighByte) + CmpShift;
  4405.         if (ParseSentence_Vars->Pkd[2] < Wrk) {
  4406.           return (SearchWord(StartPageNo, StartPageIndex, LowerNum,
  4407.                              ParseSentence_Vars));
  4408.         } else if (ParseSentence_Vars->Pkd[2] > Wrk)
  4409.           return (SearchWord(MiddlePageNo, MiddlePageIndex, UpperNum,
  4410.                              ParseSentence_Vars));
  4411.         else
  4412.           return (JoinBytes(WordPageIndex, WordPageNo));
  4413.       }
  4414.     }
  4415.   }
  4416. }  /* SearchWord */
  4417.  
  4418. Local void ParseSentence(int LinePageNo_, int LinePageIndex_,
  4419.                          int ParsedPageNo, int ParsedPageIndex,
  4420.                          int VocabPageNo_, int VocabPageIndex_,
  4421.                          int DiscardNullWordInfoOffset) {
  4422.   struct ParseSentence_LocalVariables V;
  4423.   int LowByte;
  4424.   int HighByte;
  4425.   int WordStartIndex;
  4426.   int NumVocabWords;
  4427.   int VocabStartPageNo;
  4428.   int VocabStartPageIndex;
  4429.   int ParsedStartPageNo;
  4430.   int ParsedStartPageIndex;
  4431.   int ChrCnt;
  4432.   int MaxNumWords;
  4433.   int NumWords;
  4434.   int WordChCnt;
  4435.   int NumSeparators;
  4436.   int SeparatorCnt;
  4437.   CharSet SeparatorSet;
  4438.   aWord Word;
  4439.   aWord InitWord;
  4440.   CharSet SET;
  4441.  
  4442.   V.LinePageNo = LinePageNo_;
  4443.   V.LinePageIndex = LinePageIndex_;
  4444.   V.VocabPageNo = VocabPageNo_;
  4445.   V.VocabPageIndex = VocabPageIndex_;
  4446.   Inc(&V.LinePageNo, &V.LinePageIndex, 1);   /* skip max length */
  4447.   V.InputLength = PagePtrs[V.LinePageNo][V.LinePageIndex];
  4448.   V.InputIndex = 1;
  4449.   Inc(&V.LinePageNo, &V.LinePageIndex, 1);   /* skip length */
  4450.   NumSeparators = GetVocabByte(&V);
  4451.   if (NumSeparators > 10)
  4452.     InternalError(TooManySeparators);
  4453.   P_expset(SeparatorSet, 0);
  4454.   for (SeparatorCnt = 1; SeparatorCnt <= NumSeparators; ++SeparatorCnt)
  4455.     P_addset(SeparatorSet, GetVocabByte(&V));
  4456.   V.EntryLength = GetVocabByte(&V);
  4457.   HighByte = GetVocabByte(&V);
  4458.   LowByte = GetVocabByte(&V);
  4459.   NumVocabWords = JoinBytes(LowByte, HighByte);
  4460.   VocabStartPageNo = V.VocabPageNo;
  4461.   VocabStartPageIndex = V.VocabPageIndex;
  4462.   ParsedStartPageNo = ParsedPageNo;
  4463.   ParsedStartPageIndex = ParsedPageIndex;
  4464.   MaxNumWords = PagePtrs[ParsedPageNo][ParsedPageIndex];
  4465.   if (MaxNumWords == 0 || MaxNumWords > MaxMaxNumWords) {
  4466.     MaxNumWords = MaxMaxNumWords;
  4467.     PagePtrs[ParsedPageNo][ParsedPageIndex] = MaxNumWords;
  4468.   }
  4469.   Inc(&ParsedPageNo, &ParsedPageIndex, 2);
  4470.   for (ChrCnt = 0; ChrCnt <= 8; ++ChrCnt)
  4471.     InitWord[ChrCnt] = '\0';
  4472.   NumWords = 0;
  4473.   GetCh_(&V);
  4474.   BackCh(&V);
  4475.   while (V.WrkCh != EOL() && NumWords < MaxNumWords) {
  4476.     memcpy(Word, InitWord, signedsizeof(aWord));
  4477.     WordStartIndex = V.InputIndex;
  4478.     GetCh_(&V);
  4479.     if (!(((!P_inset(V.WrkCh, TerminatorSet)) |
  4480.            P_inset(V.WrkCh, SeparatorSet)) & (V.WrkCh != EOL())))
  4481.       continue;
  4482.     Word[0] = V.WrkCh;
  4483.     WordChCnt = 1;
  4484.     if (!P_inset(V.WrkCh, SeparatorSet)) {
  4485.       GetCh_(&V);
  4486.       while ((V.WrkCh != EOL()) & (!(P_inset(V.WrkCh, SeparatorSet) |
  4487.                                      P_inset(V.WrkCh, TerminatorSet)))) {
  4488.         if (WordChCnt < WordNumChars)
  4489.           Word[WordChCnt] = V.WrkCh;
  4490.         GetCh_(&V);
  4491.         ++WordChCnt;
  4492.       }
  4493.       BackCh(&V);
  4494.     }
  4495.     if (DebugVocab) {
  4496.       ChkWait();
  4497.       for (ChrCnt = 0; ChrCnt < WordChCnt; ++ChrCnt)
  4498.         PrintCh(Word[ChrCnt]);
  4499.       PrintCh(',');
  4500.       PrintByte(WordChCnt, 2);
  4501.     }
  4502.     PackWord(Word, V.Pkd);
  4503.     SplitWord(SearchWord(VocabStartPageNo, VocabStartPageIndex, NumVocabWords,
  4504.                          &V), &LowByte, &HighByte);
  4505.     if (DebugVocab) {
  4506.       PrintByte(HighByte, 2);
  4507.       PrintByte(LowByte, 2);
  4508.       ChkWait();
  4509.     }
  4510.     if (DiscardNullWordInfoOffset == 1 && LowByte == 0 && HighByte == 0) {
  4511.       /* do not store offset to word info */
  4512.       Inc(&ParsedPageNo, &ParsedPageIndex, 2);
  4513.     } else {
  4514.       PagePtrs[ParsedPageNo][ParsedPageIndex] = HighByte;
  4515.       Inc(&ParsedPageNo, &ParsedPageIndex, 1);
  4516.       PagePtrs[ParsedPageNo][ParsedPageIndex] = LowByte;
  4517.       Inc(&ParsedPageNo, &ParsedPageIndex, 1);
  4518.     }
  4519.     PagePtrs[ParsedPageNo][ParsedPageIndex] = WordChCnt;
  4520.     Inc(&ParsedPageNo, &ParsedPageIndex, 1);
  4521.     /*      IF CodeVersion>='5' THEN BEGIN */
  4522.     ++WordStartIndex;
  4523.     /*      END; */
  4524.     PagePtrs[ParsedPageNo][ParsedPageIndex] = WordStartIndex;
  4525.     Inc(&ParsedPageNo, &ParsedPageIndex, 1);
  4526.     ++NumWords;
  4527.   }
  4528.   ParsedPageNo = ParsedStartPageNo;
  4529.   ParsedPageIndex = ParsedStartPageIndex;
  4530.   Inc(&ParsedPageNo, &ParsedPageIndex, 1);
  4531.   PagePtrs[ParsedPageNo][ParsedPageIndex] = NumWords;
  4532. }  /* ParseSentence */
  4533.  
  4534. Local void ZMachineInput(void) {
  4535.   int LinePageNo;
  4536.   int LinePageIndex;
  4537.   int VocabPageNo;
  4538.   int VocabPageIndex;
  4539.   int ChPageNo;
  4540.   int ChPageIndex;
  4541.   int LineLength;
  4542.   int MaxLineLength;
  4543.   int ChrCnt;
  4544.   int ParsedPageNo;
  4545.   int ParsedPageIndex;
  4546.   boolean GotLine;
  4547.   Char InputLine[256];
  4548.   int FORLIM;
  4549.  
  4550.   if (OpdCnt < 1)
  4551.     InternalError(MissingOpd);
  4552.   if (OpdCnt > 4)
  4553.     InternalError(IllNumOperands);
  4554.   if (OpdCnt < 4) {
  4555.     Opd.U1.s3 = 0;
  4556.     if (OpdCnt < 3) {
  4557.       Opd.U1.s2 = -1;
  4558.       if (OpdCnt < 2)
  4559.         Opd.U1.s1 = 0;
  4560.     }
  4561.   }
  4562.   SplitWord(Opd.U1.s0, &LinePageIndex, &LinePageNo);
  4563.   SplitWord(Opd.U1.s1, &ParsedPageIndex, &ParsedPageNo);
  4564.   MaxLineLength = PagePtrs[LinePageNo][LinePageIndex];
  4565.   if (MaxLineLength >= ScreenWidth)
  4566.     MaxLineLength = ScreenWidth - 1;
  4567.   ChPageNo = LinePageNo;
  4568.   ChPageIndex = LinePageIndex;
  4569.   if (CodeVersion >= '5') {
  4570.     Inc(&ChPageNo, &ChPageIndex, 1);   /* skip max length */
  4571.     LineLength = PagePtrs[ChPageNo][ChPageIndex];
  4572.     for (ChrCnt = 1; ChrCnt <= LineLength; ++ChrCnt) {
  4573.       Inc(&ChPageNo, &ChPageIndex, 1);
  4574.       InputLine[ChrCnt - 1] = PagePtrs[ChPageNo][ChPageIndex];
  4575.     }
  4576.     ChPageNo = LinePageNo;
  4577.     ChPageIndex = LinePageIndex;
  4578.   } else {
  4579.     LineLength = 0;
  4580.   }
  4581.   SetLength(InputLine, LineLength);
  4582.   GotLine = ReadLine(true, InputLine, MaxLineLength, Opd.U1.s2, Opd.U1.s3);
  4583.   if (!GotLine && CodeVersion >= '5') {
  4584.     DoPutWord(InputLine[0]);
  4585.     return;
  4586.   }
  4587.   Inc(&ChPageNo, &ChPageIndex, 1);   /* skip max length */
  4588.   PagePtrs[ChPageNo][ChPageIndex] = strlen(InputLine);   /* store length */
  4589.   FORLIM = strlen(InputLine);
  4590.   for (ChrCnt = 1; ChrCnt <= FORLIM; ++ChrCnt) {
  4591.     Inc(&ChPageNo, &ChPageIndex, 1);
  4592.     PagePtrs[ChPageNo][ChPageIndex] = InputLine[ChrCnt - 1];
  4593.   }
  4594.   Inc(&ChPageNo, &ChPageIndex, 1);
  4595.   if (ParsedPageNo != 0 || ParsedPageIndex != 0) {
  4596.     VocabPageNo = MiscInfo.VocabPageNo;
  4597.     VocabPageIndex = MiscInfo.VocabPageIndex;
  4598.     ParseSentence(LinePageNo, LinePageIndex, ParsedPageNo, ParsedPageIndex,
  4599.                   VocabPageNo, VocabPageIndex, 0);
  4600.   }
  4601.   if (CodeVersion >= '5')
  4602.     DoPutWord(10);   /* we have an input line */
  4603. }  /* ZMachineInput */
  4604.  
  4605. Local void WriteSingleCharacter(void) {
  4606.   if (OpdCnt != 1)
  4607.     InternalError(IllNumOperands);
  4608.   PutChToStoryOutput(Opd.U1.s0);
  4609. }  /* WriteSingleCharacter */
  4610.  
  4611. Local void WriteInteger(void) {
  4612.   if (OpdCnt != 1)
  4613.     InternalError(IllNumOperands);
  4614.   PutIntToStoryOutput(Opd.U1.s0);
  4615. }  /* WriteInteger */
  4616.  
  4617. Local void ZMachineRandom(void) {
  4618.   boolean Negative;
  4619.   int RandomNo;
  4620.  
  4621.   if (OpdCnt != 1)
  4622.     InternalError(IllNumOperands);
  4623.   if (Opd.U1.s0 == 0) {
  4624.     DoPutWord(0);
  4625.     return;
  4626.   }
  4627.   Negative = (Opd.U1.s0 < 0);
  4628.   if (Negative)
  4629.     Opd.U1.s0 = -Opd.U1.s0;
  4630.   RandomNo = Random();
  4631.   if (RandomNo < 0)
  4632.     RandomNo = -RandomNo;
  4633.   RandomNo = RandomNo % Opd.U1.s0 + 1;
  4634.   if (Negative)
  4635.     DoPutWord(-RandomNo);
  4636.   else
  4637.     DoPutWord(RandomNo);
  4638. }  /* ZMachineRandom */
  4639.  
  4640. Local void SplitScreen(void) {
  4641.   int OldScrollTop;
  4642.  
  4643.   ScreenMode = 0;
  4644.   SetScreenMode();
  4645.   if (Opd.U1.s0 == 0) {
  4646.     WindowEnabled = false;
  4647.     ScrollTop = (CodeVersion <= '3') + 1;
  4648.     LineNo = ScrollTop;
  4649.     return;
  4650.   }
  4651.   if (Opd.U1.s0 >= ScreenHeight)
  4652.     return;
  4653.   WindowEnabled = true;
  4654.   NonWindowCursorX = 0;
  4655.   NonWindowCursorY = ScreenHeight - 1;
  4656.   WindowCursorX = 0;
  4657.   WindowCursorY = (CodeVersion <= '3');
  4658.   OldScrollTop = ScrollTop;
  4659.   ScrollTop = Opd.U1.s0 + (CodeVersion <= '3') + 1;
  4660.   if (OldScrollTop > ScrollTop)
  4661.     LineNo += ScrollTop - OldScrollTop;
  4662.   if (ScrollTop >= LineNo)
  4663.     LineNo = ScrollTop;
  4664.   if (CodeVersion < '4')
  4665.     ClearLines(1, ScrollTop - 2);
  4666.   ZM_GotoXY(1, ScreenHeight);
  4667. }  /* SplitScreen */
  4668.  
  4669. Local void ChooseWindow(void) {
  4670.   if (CodeVersion >= '5')
  4671.     WriteLineBuffer();
  4672.   if (!WindowEnabled)
  4673.     return;
  4674.   if (Opd.U1.s0 == 0) {
  4675.     if (!WritingInWindow)
  4676.       return;
  4677.     if (CodeVersion >= '4') {
  4678.       WindowCursorX = CursorX;
  4679.       WindowCursorY = CursorY;
  4680.     }
  4681.     WritingInWindow = false;
  4682.     CursorX = NonWindowCursorX;
  4683.     CursorY = NonWindowCursorY;
  4684.     PositionCursor();
  4685.     return;
  4686.   }
  4687.   if (Opd.U1.s0 != 1)
  4688.     return;
  4689.   if (WritingInWindow)
  4690.     return;
  4691.   if (CodeVersion >= '4') {
  4692.     NonWindowCursorX = CursorX;
  4693.     NonWindowCursorY = CursorY;
  4694.   }
  4695.   WritingInWindow = true;
  4696.   CursorX = WindowCursorX;
  4697.   CursorY = WindowCursorY;
  4698.   PositionCursor();
  4699. }  /* ChooseWindow */
  4700.  
  4701. Local void EraseArea(void) {
  4702.   if (Opd.U1.s0 == 0) {
  4703.     ClearLines(ScrollTop - 1, ScreenHeight - 1);
  4704.     ZM_GotoXY(1, ScreenHeight);
  4705.     return;
  4706.   }
  4707.   if (Opd.U1.s0 == 1) {
  4708.     if (WritingInWindow) {
  4709.       ClearLines(0, ScrollTop - 2);
  4710.       ZM_GotoXY(1, ScrollTop);
  4711.     } else {
  4712.       ClearScreen();
  4713.     }
  4714.     return;
  4715.   }
  4716.   if (Opd.U1.s0 != -1)
  4717.     return;
  4718.   WindowEnabled = false;
  4719.   ScrollTop = (CodeVersion <= '3') + 1;
  4720.   LineNo = ScrollTop;
  4721.   ClearScreen();
  4722. }  /* EraseArea */
  4723.  
  4724. Local void DoGotoXY(void) {
  4725.   if (CodeVersion >= '5') {
  4726.     WriteLineBuffer();
  4727.     ZM_GotoXY(Opd.U1.s1, Opd.U1.s0);
  4728.   } else if (DirectEnabled && WritingInWindow)
  4729.     ZM_GotoXY(Opd.U1.s1, Opd.U1.s0);
  4730. }  /* DoGotoXY */
  4731.  
  4732. Local void ChangeSCreenMode(void) {
  4733.   WriteLineBuffer();
  4734.   ScreenMode = Opd.U1.s0;
  4735.   SetScreenMode();
  4736. }  /* ChangeScreenMode */
  4737.  
  4738. Local void SetFormatMode(void) {
  4739.   FormatMode = Opd.U1.s0;
  4740.   switch (FormatMode) {
  4741.  
  4742.   case 0:
  4743.     WriteLineBuffer();
  4744.     DirectEnabled = true;
  4745.     break;
  4746.  
  4747.   case 1:
  4748.     DirectEnabled = false;
  4749.     break;
  4750.   }
  4751. }  /* SetFormatMode */
  4752.  
  4753. Local void SetOutputMode(void) {
  4754.   int DestPageNo;
  4755.   int DestIndex;
  4756.   int LowByte;
  4757.   int HighByte;
  4758.  
  4759.   switch (Opd.U1.s0) {
  4760.  
  4761.   case 1:
  4762.     ScreenEnabled = true;
  4763.     break;
  4764.  
  4765.   case -1:
  4766.     ScreenEnabled = false;
  4767.     break;
  4768.  
  4769.   case 2:
  4770.     LowByte = PagePtrs[0][17];
  4771.     SetBit(&LowByte, 0);
  4772.     PagePtrs[0][17] = LowByte;
  4773.     break;
  4774.  
  4775.   case -2:
  4776.     LowByte = PagePtrs[0][17];
  4777.     ClrBit(&LowByte, 0);
  4778.     PagePtrs[0][17] = LowByte;
  4779.     break;
  4780.  
  4781.   case 3:
  4782.     if (OpdCnt >= 2) {
  4783.       BufferEnabled = true;
  4784.       SplitWord(Opd.U1.s1, &BufferPageIndex, &BufferPageNo);
  4785.       BufferIndex = 2;
  4786.     } else {
  4787.       InternalError(MissingOpd);
  4788.     }
  4789.     break;
  4790.  
  4791.   case -3:
  4792.     if (BufferEnabled) {
  4793.       BufferEnabled = false;
  4794.       DestPageNo = BufferPageNo;
  4795.       DestIndex = BufferPageIndex;
  4796.       Inc(&DestPageNo, &DestIndex, BufferIndex);
  4797.       PagePtrs[DestPageNo][DestIndex] = 0;
  4798.       SplitWord(BufferIndex - 2, &LowByte, &HighByte);
  4799.       PagePtrs[BufferPageNo][BufferPageIndex] = HighByte;
  4800.       Inc(&BufferPageNo, &BufferPageIndex, 1);
  4801.       PagePtrs[BufferPageNo][BufferPageIndex] = LowByte;
  4802.       BufferPageNo = -1;
  4803.       BufferPageIndex = -1;
  4804.     } else {
  4805.       InternalError(OutputBufferUndefined);
  4806.     }
  4807.     break;
  4808.  
  4809.   default:
  4810.     InternalError(IllOutputMode);
  4811.     break;
  4812.   }
  4813. }  /* SetOutputMode */
  4814.  
  4815. Local void SetComMode(void) {
  4816.   ComMode = Opd.U1.s0;
  4817. }  /* SetComMode */
  4818.  
  4819. Local void InputKey(void) {
  4820.   Char InpKey;
  4821.  
  4822.   if (CodeVersion >= '5')
  4823.     WriteLineBuffer();
  4824.   if (OpdCnt < 1 || OpdCnt > 3)
  4825.     InternalError(IllNumOperands);
  4826.   if (OpdCnt < 3) {
  4827.     Opd.U1.s2 = 0;
  4828.     if (OpdCnt < 2)
  4829.       Opd.U1.s1 = -1;
  4830.   }
  4831.   if (Opd.U1.s0 != 1) {
  4832.     DoPutWord(0);
  4833.     return;
  4834.   }
  4835.   WriteLineBuffer();
  4836.   PrintStatusLine();
  4837.   LineNo = ScrollTop;
  4838.   PositionCursor();
  4839.   CursorOn();
  4840.   if (Opd.U1.s1 >= 0)
  4841.     EnableTimer();
  4842.   ReadKey(true, &InpKey, Opd.U1.s1, CallKeyPress, Opd.U1.s2);
  4843.   CursorOff();
  4844.   if (Opd.U1.s1 >= 0)
  4845.     DisableTimer();
  4846.   if (InpKey == EOL())
  4847.     InpKey = '\015';
  4848.   DoPutWord(InpKey);
  4849.   if (InpKey == BreakKey)
  4850.     InternalError(KeyboardBreak);
  4851. }  /* InputKey */
  4852.  
  4853. Local void BlockEqual(void) {
  4854.   int SourcePageNo;
  4855.   int SourceIndex;
  4856.   int Increment;
  4857.   boolean WordCompare;
  4858.   int LowByte;
  4859.   int HighByte;
  4860.  
  4861.   if (OpdCnt > 4)
  4862.     InternalError(IllNumOperands);
  4863.   if (OpdCnt < 4) {
  4864.     Opd.U1.s3 = 130;   /* default is word compare */
  4865.     if (OpdCnt < 3)
  4866.       InternalError(MissingOpd);
  4867.   }
  4868.   if (Opd.U1.s3 >= 128) {
  4869.     WordCompare = true;
  4870.     Increment = Opd.U1.s3 - 128;
  4871.   } else {
  4872.     WordCompare = false;
  4873.     Increment = Opd.U1.s3;
  4874.   }
  4875.   SplitWord(Opd.U1.s1, &SourceIndex, &SourcePageNo);
  4876.   ChkAddress(&SourcePageNo, &SourceIndex);
  4877.   if (WordCompare) {
  4878.     while (Opd.U1.s2 > 0) {
  4879.       HighByte = PagePtrs[SourcePageNo][SourceIndex];
  4880.       Inc(&SourcePageNo, &SourceIndex, 1);
  4881.       LowByte = PagePtrs[SourcePageNo][SourceIndex];
  4882.       Dec(&SourcePageNo, &SourceIndex, 1);
  4883.       if (JoinBytes(LowByte, HighByte) == Opd.U1.s0)
  4884.         goto _L231;
  4885.       Inc(&SourcePageNo, &SourceIndex, Increment);
  4886.       --Opd.U1.s2;
  4887.     }
  4888.   } else {
  4889.     while (Opd.U1.s2 > 0) {
  4890.       LowByte = PagePtrs[SourcePageNo][SourceIndex];
  4891.       if (LowByte == Opd.U1.s0)
  4892.         goto _L231;
  4893.       Inc(&SourcePageNo, &SourceIndex, Increment);
  4894.       --Opd.U1.s2;
  4895.     }
  4896.   }
  4897.   DoPutWord(0);
  4898.   HandleFalse();
  4899.   goto _L230;
  4900. _L231:
  4901.   DoPutWord(JoinBytes(SourceIndex, SourcePageNo));
  4902.   HandleTrue();
  4903. _L230: ;
  4904. }  /* BlockEqual */
  4905.  
  4906. Local void Parse(void) {
  4907.   int LinePageNo;
  4908.   int LinePageIndex;
  4909.   int ParsedPageNo;
  4910.   int ParsedPageIndex;
  4911.   int VocabPageNo;
  4912.   int VocabPageIndex;
  4913.  
  4914.   if (OpdCnt > 4)
  4915.     InternalError(IllNumOperands);
  4916.   if (OpdCnt < 4) {
  4917.     Opd.U1.s3 = 0;
  4918.     if (OpdCnt < 3) {
  4919.       Opd.U1.s2 = 0;
  4920.       if (OpdCnt < 2)
  4921.         InternalError(MissingOpd);
  4922.     }
  4923.   }
  4924.   SplitWord(Opd.U1.s0, &LinePageIndex, &LinePageNo);
  4925.   SplitWord(Opd.U1.s1, &ParsedPageIndex, &ParsedPageNo);
  4926.   if (Opd.U1.s2 != 0) {
  4927.     SplitWord(Opd.U1.s2, &VocabPageIndex, &VocabPageNo);
  4928.   } else {
  4929.     VocabPageNo = MiscInfo.VocabPageNo;
  4930.     VocabPageIndex = MiscInfo.VocabPageIndex;
  4931.   }
  4932.   ParseSentence(LinePageNo, LinePageIndex, ParsedPageNo, ParsedPageIndex,
  4933.                 VocabPageNo, VocabPageIndex, Opd.U1.s3);
  4934. }  /* Parse */
  4935.  
  4936. Local void PackCharacters(void) {
  4937.   int Cnt;
  4938.   int NumChars;
  4939.   int ChPageNo;
  4940.   int ChPageIndex;
  4941.   int PkdPageNo;
  4942.   int PkdPageIndex;
  4943.   int LowByte;
  4944.   int HighByte;
  4945.   aPackedWord Pkd;
  4946.   aWord Word;
  4947.  
  4948.   if (OpdCnt < 4)
  4949.     InternalError(MissingOpd);
  4950.   if (OpdCnt > 4)
  4951.     InternalError(IllNumOperands);
  4952.   SplitWord(Opd.U1.s0, &ChPageIndex, &ChPageNo);
  4953.   Inc(&ChPageNo, &ChPageIndex, Opd.U1.s2);
  4954.   SplitWord(Opd.U1.s3, &PkdPageIndex, &PkdPageNo);
  4955.   NumChars = Opd.U1.s1;
  4956.   if (NumChars > WordNumChars)
  4957.     NumChars = WordNumChars;
  4958.   for (Cnt = 0; Cnt < NumChars; ++Cnt) {
  4959.     Word[Cnt] = PagePtrs[ChPageNo][ChPageIndex];
  4960.     Inc(&ChPageNo, &ChPageIndex, 1);
  4961.   }
  4962.   for (Cnt = NumChars; Cnt <= 8; ++Cnt) {
  4963.     Word[Cnt] = 0;
  4964.     Inc(&ChPageNo, &ChPageIndex, 1);
  4965.   }
  4966.   PackWord(Word, Pkd);
  4967.   for (Cnt = 0; Cnt <= 2; ++Cnt) {
  4968.     SplitWord(Pkd[Cnt], &LowByte, &HighByte);
  4969.     PagePtrs[PkdPageNo][PkdPageIndex] = HighByte;
  4970.     Inc(&PkdPageNo, &PkdPageIndex, 1);
  4971.     PagePtrs[PkdPageNo][PkdPageIndex] = LowByte;
  4972.     Inc(&PkdPageNo, &PkdPageIndex, 1);
  4973.   }
  4974. }  /* PackCharacters */
  4975.  
  4976. Local void BlockCopy(void) {
  4977.   int EndPageNo;
  4978.   int EndIndex;
  4979.   int SourcePageNo;
  4980.   int SourceIndex;
  4981.   int DestPageNo;
  4982.   int DestIndex;
  4983.   boolean Negative;
  4984.  
  4985.   if (OpdCnt != 3)
  4986.     InternalError(IllNumOperands);
  4987.   SplitWord(Opd.U1.s0, &SourceIndex, &SourcePageNo);
  4988.   SplitWord(Opd.U1.s1, &DestIndex, &DestPageNo);
  4989.   if (DestPageNo == SourcePageNo && DestIndex == SourceIndex)
  4990.     return;
  4991.   if (Opd.U1.s2 == 0)
  4992.     return;
  4993.   if (Opd.U1.s2 < 0) {
  4994.     Negative = true;
  4995.     Opd.U1.s2 = -Opd.U1.s2;
  4996.   } else {
  4997.     Negative = false;
  4998.   }
  4999.   if (DestPageNo == 0 && DestIndex == 0) {
  5000.     do {
  5001.       PagePtrs[SourcePageNo][SourceIndex] = 0;
  5002.       Inc(&SourcePageNo, &SourceIndex, 1);
  5003.       --Opd.U1.s2;
  5004.     } while (Opd.U1.s2 != 0);
  5005.     return;
  5006.   }
  5007.   EndPageNo = SourcePageNo;
  5008.   EndIndex = SourceIndex;
  5009.   Inc(&EndPageNo, &EndIndex, Opd.U1.s2);
  5010.   if (Negative || SourcePageNo > DestPageNo ||
  5011.       SourcePageNo == DestPageNo && SourceIndex > DestIndex ||
  5012.       EndPageNo < DestPageNo ||
  5013.       EndPageNo == DestPageNo && EndIndex < DestIndex) {
  5014.     do {
  5015.       PagePtrs[DestPageNo][DestIndex] = PagePtrs[SourcePageNo][SourceIndex];
  5016.       Inc(&DestPageNo, &DestIndex, 1);
  5017.       Inc(&SourcePageNo, &SourceIndex, 1);
  5018.       --Opd.U1.s2;
  5019.     } while (Opd.U1.s2 != 0);
  5020.     return;
  5021.   }
  5022.   Inc(&SourcePageNo, &SourceIndex, Opd.U1.s2);
  5023.   Inc(&DestPageNo, &DestIndex, Opd.U1.s2);
  5024.   do {
  5025.     Dec(&SourcePageNo, &SourceIndex, 1);
  5026.     Dec(&DestPageNo, &DestIndex, 1);
  5027.     PagePtrs[DestPageNo][DestIndex] = PagePtrs[SourcePageNo][SourceIndex];
  5028.     --Opd.U1.s2;
  5029.   } while (Opd.U1.s2 != 0);
  5030. }  /* BlockCopy */
  5031.  
  5032. Local void WriteTextArea(void) {
  5033.   int SourcePageNo;
  5034.   int SourceIndex;
  5035.   int Cnt;
  5036.   int StartX;
  5037.   int StartY;
  5038.   Char Ch;
  5039.   int FORLIM;
  5040.  
  5041.   SplitWord(Opd.U1.s0, &SourceIndex, &SourcePageNo);
  5042.   if (Opd.U1.s1 <= 0)
  5043.     return;
  5044.   Push(ScreenMode);
  5045.   if (OpdCnt < 2 || OpdCnt > 3)
  5046.     InternalError(IllNumOperands);
  5047.   if (OpdCnt < 3) {
  5048.     Opd.U1.s2 = 1;
  5049.     OpdCnt = 3;
  5050.   }
  5051.   StartX = CursorX;
  5052.   StartY = CursorY;
  5053.   while (Opd.U1.s2 > 0) {
  5054.     FORLIM = Opd.U1.s1;
  5055.     for (Cnt = 1; Cnt <= FORLIM; ++Cnt) {
  5056.       Ch = PagePtrs[SourcePageNo][SourceIndex];
  5057.       if (Ch < ' ')
  5058.         InternalError(IllOutputChar);
  5059.       PutChToStoryOutput(Ch);
  5060.       Inc(&SourcePageNo, &SourceIndex, 1);
  5061.     }
  5062.     --Opd.U1.s2;
  5063.     if (Opd.U1.s2 <= 0)
  5064.       break;
  5065.     CursorX = StartX;
  5066.     CursorY = StartY;
  5067.     MoveCursorDown();
  5068.     StartX = CursorX;
  5069.     StartY = CursorY;
  5070.   }
  5071.   ScreenMode = Pop();
  5072. }  /* WriteTextArea */
  5073.  
  5074. Local void MinimalNumCallParams(void) {
  5075.   if (OpdCnt != 1)
  5076.     InternalError(IllNumOperands);
  5077.   if (Opd.U1.s0 <= NumCallParams)
  5078.     HandleTrue();
  5079.   else
  5080.     HandleFalse();
  5081. }  /* MinimalNumCallParams */
  5082.  
  5083. Local void ExecuteMultipleOperandOperation(boolean NewVersion) {
  5084.   switch (cOp5(CmdCode)) {
  5085.  
  5086.   case 0:   /* CFC */
  5087.     Call(Opd.U1.s0, true, OpdCnt - 1);
  5088.     break;
  5089.  
  5090.   case 1:   /* STW */
  5091.     StoreWord();
  5092.     break;
  5093.  
  5094.   case 2:   /* STB */
  5095.     StoreByte();
  5096.     break;
  5097.  
  5098.   case 3:   /* STP */
  5099.     StoreProperty();
  5100.     break;
  5101.  
  5102.   case 4:   /* INP */
  5103.     ZMachineInput();
  5104.     break;
  5105.  
  5106.   case 5:   /* WTC */
  5107.     WriteSingleCharacter();
  5108.     break;
  5109.  
  5110.   case 6:   /* WTI */
  5111.     WriteInteger();
  5112.     break;
  5113.  
  5114.   case 7:   /* RND */
  5115.     ZMachineRandom();
  5116.     break;
  5117.  
  5118.   case 8:   /* PSH */
  5119.     Push(Opd.U1.s0);
  5120.     break;
  5121.  
  5122.   case 9:   /* PUL */
  5123.     AccA = Pop();
  5124.     PutAccA(Opd.U1.s0);
  5125.     if (CodeVersion >= '6')
  5126.       DoPutWord(AccA);   /* ??? */
  5127.     break;
  5128.  
  5129.   case 10:   /* SPL */
  5130.     SplitScreen();
  5131.     break;
  5132.  
  5133.   case 11:   /* POS */
  5134.     ChooseWindow();
  5135.     break;
  5136.  
  5137.   case 12:   /* CFC */
  5138.     Call(Opd.U1.s0, true, OpdCnt - 1);
  5139.     break;
  5140.  
  5141.   case 13:   /* ERS */
  5142.     EraseArea();
  5143.     break;
  5144.  
  5145.   case 14:   /* ERL */
  5146.     if (Opd.U1.s0 == 1)
  5147.       ClearToEOL();
  5148.     break;
  5149.  
  5150.   case 15:   /* GYX */
  5151.     DoGotoXY();
  5152.     break;
  5153.  
  5154.   case 16:   /* M16 */
  5155.     InternalError(NotImplemented);
  5156.     break;
  5157.  
  5158.   case 17:   /* SCM */
  5159.     ChangeSCreenMode();
  5160.     break;
  5161.  
  5162.   case 18:   /* FRM */
  5163.     SetFormatMode();
  5164.     break;
  5165.  
  5166.   case 19:   /* OUT */
  5167.     SetOutputMode();
  5168.     break;
  5169.  
  5170.   case 20:   /* COM */
  5171.     SetComMode();
  5172.     break;
  5173.  
  5174.   case 21:   /* BEL */
  5175.     RingBell();
  5176.     break;
  5177.  
  5178.   case 22:   /* INK */
  5179.     InputKey();
  5180.     break;
  5181.  
  5182.   case 23:   /* BEQ */
  5183.     BlockEqual();
  5184.     break;
  5185.  
  5186.   case 24:   /* NEG */
  5187.     DoPutWord(lnot(Opd.U1.s0));
  5188.     break;
  5189.  
  5190.   case 25:   /* CPC */
  5191.     Call(Opd.U1.s0, false, OpdCnt - 1);
  5192.     break;
  5193.  
  5194.   case 26:   /* CPC */
  5195.     Call(Opd.U1.s0, false, OpdCnt - 1);
  5196.     break;
  5197.  
  5198.   case 27:   /* PRS */
  5199.     Parse();
  5200.     break;
  5201.  
  5202.   case 28:   /* PAK */
  5203.     PackCharacters();
  5204.     break;
  5205.  
  5206.   case 29:   /* BCP */
  5207.     BlockCopy();
  5208.     break;
  5209.  
  5210.   case 30:   /* WTA */
  5211.     WriteTextArea();
  5212.     break;
  5213.  
  5214.   case 31:   /* MNP */
  5215.     MinimalNumCallParams();
  5216.     break;
  5217.   }
  5218. }  /* ExecuteMultipleOperandOperation */
  5219.  
  5220. Local void LogicalShiftLeft(void) {
  5221.   if (OpdCnt != 2)
  5222.     InternalError(IllNumOperands);
  5223.   if (Opd.U1.s1 >= 0)
  5224.     DoPutWord(lsl(Opd.U1.s0, Opd.U1.s1));
  5225.   else
  5226.     DoPutWord(lsr(Opd.U1.s0, -Opd.U1.s1));
  5227. }  /* LogicalShiftLeft */
  5228.  
  5229. Local void ArithmeticShiftLeft(void) {
  5230.   if (OpdCnt != 2)
  5231.     InternalError(IllNumOperands);
  5232.   if (Opd.U1.s1 >= 0) {
  5233.     DoPutWord(lsl(Opd.U1.s0, Opd.U1.s1));
  5234.     return;
  5235.   }
  5236.   if (Opd.U1.s0 >= 0)
  5237.     DoPutWord(lsr(Opd.U1.s0, -Opd.U1.s1));
  5238.   else
  5239.     DoPutWord(lnot(lsr(lnot(Opd.U1.s0), -Opd.U1.s1)));
  5240. }  /* ArithmeticShiftLeft */
  5241.  
  5242. Local void SwitchFont(void) {
  5243.   WriteLineBuffer();
  5244.   if (SwitchToFont(Opd.U1.s0))
  5245.     DoPutWord(1);
  5246.   else
  5247.     DoPutWord(0);
  5248. }  /* SwitchFont */
  5249.  
  5250. Local void ClearFlag(void) {
  5251.   InternalError(NotImplemented);
  5252. }  /* ClearFlag */
  5253.  
  5254. Local void SetFlag_(void) {
  5255.   InternalError(NotImplemented);
  5256. }  /* SetFlag */
  5257.  
  5258. Local void TestByteArray(void) {
  5259.   InternalError(NotImplemented);
  5260.   HandleFalse();
  5261. }  /* TestByteArray */
  5262.  
  5263. Local void SWD(void) {
  5264.   InternalError(NotImplemented);
  5265. }  /* SWD */
  5266.  
  5267. Local void X09(void) {
  5268.   InternalError(NotImplemented);
  5269.   DoPutWord(0);
  5270. }  /* X09 */
  5271.  
  5272. Local void X10(void) {
  5273.   InternalError(NotImplemented);
  5274.   DoPutWord(0);
  5275. }  /* X10 */
  5276.  
  5277. Local void X11(void) {
  5278.   InternalError(NotImplemented);
  5279. }  /* X11 */
  5280.  
  5281. Local void X12(void) {
  5282.   InternalError(NotImplemented);
  5283. }  /* X12 */
  5284.  
  5285. Local void X13(void) {
  5286.   InternalError(NotImplemented);
  5287. }  /* X13 */
  5288.  
  5289. Local void X14(void) {
  5290.   InternalError(NotImplemented);
  5291. }  /* X14 */
  5292.  
  5293. Local void X15(void) {
  5294.   InternalError(NotImplemented);
  5295. }  /* X15 */
  5296.  
  5297. Local void X16(void) {
  5298.   InternalError(NotImplemented);
  5299. }  /* X16 */
  5300.  
  5301. Local void X17(void) {
  5302.   InternalError(NotImplemented);
  5303. }  /* X17 */
  5304.  
  5305. Local void X18(void) {
  5306.   InternalError(NotImplemented);
  5307. }  /* X18 */
  5308.  
  5309. Local void X19(void) {
  5310.   InternalError(NotImplemented);   /* ??? */
  5311.   DoPutWord(0);
  5312. }  /* X19 */
  5313.  
  5314. Local void X20(void) {
  5315.   InternalError(NotImplemented);
  5316. }  /* X20 */
  5317.  
  5318. Local void X21(void) {
  5319.   InternalError(NotImplemented);
  5320. }  /* X21 */
  5321.  
  5322. Local void X22(void) {
  5323.   InternalError(NotImplemented);
  5324. }  /* X22 */
  5325.  
  5326. Local void X23(void) {
  5327.   InternalError(NotImplemented);
  5328. }  /* X23 */
  5329.  
  5330. Local void X24(void) {
  5331.   InternalError(NotImplemented);
  5332.   HandleFalse();   /* ??? */
  5333. }  /* X24 */
  5334.  
  5335. Local void X25(void) {
  5336.   InternalError(NotImplemented);
  5337. }  /* X25 */
  5338.  
  5339. Local void X26(void) {
  5340.   InternalError(NotImplemented);
  5341. }  /* X26 */
  5342.  
  5343. Local void X27(void) {
  5344.   InternalError(NotImplemented);
  5345. }  /* X27 */
  5346.  
  5347. Local void X28(void) {
  5348.   InternalError(NotImplemented);
  5349. }  /* X28 */
  5350.  
  5351. Local void ExecuteNewMultipleOperandOperation(void) {
  5352.   switch (CmdCode) {
  5353.  
  5354.   case 0:   /* SVE */
  5355.     if (SavedState())
  5356.       DoPutWord(1);
  5357.     else
  5358.       DoPutWord(0);
  5359.     break;
  5360.  
  5361.   case 1:   /* RSE */
  5362.     if (RestoredState())
  5363.       DoPutWord(2);
  5364.     else
  5365.       DoPutWord(0);
  5366.     break;
  5367.  
  5368.   case 2:   /* LSL */
  5369.     LogicalShiftLeft();
  5370.     break;
  5371.  
  5372.   case 3:   /* ASL */
  5373.     ArithmeticShiftLeft();
  5374.     break;
  5375.  
  5376.   case 4:   /* FNT */
  5377.     SwitchFont();
  5378.     break;
  5379.  
  5380.   case 5:   /* CLR */
  5381.     ClearFlag();
  5382.     break;
  5383.  
  5384.   case 6:   /* TSB */
  5385.     TestByteArray();
  5386.     break;
  5387.  
  5388.   case 7:   /* SET */
  5389.     SetFlag_();
  5390.     break;
  5391.  
  5392.   case 8:   /* SWD */
  5393.     SWD();
  5394.     break;
  5395.  
  5396.   case 9:   /* X09 */
  5397.     X09();
  5398.     break;
  5399.  
  5400.   case 10:   /* X10 */
  5401.     X10();
  5402.     break;
  5403.  
  5404.   case 11:   /* X11 */
  5405.     X11();
  5406.     break;
  5407.  
  5408.   case 12:   /* X12 */
  5409.     X12();
  5410.     break;
  5411.  
  5412.   case 13:   /* X13 */
  5413.     X13();
  5414.     break;
  5415.  
  5416.   case 14:   /* X14 */
  5417.     X14();
  5418.     break;
  5419.  
  5420.   case 15:   /* X15 */
  5421.     X15();
  5422.     break;
  5423.  
  5424.   case 16:   /* X16 */
  5425.     X16();
  5426.     break;
  5427.  
  5428.   case 17:   /* X17 */
  5429.     X17();
  5430.     break;
  5431.  
  5432.   case 18:   /* X18 */
  5433.     X18();
  5434.     break;
  5435.  
  5436.   case 19:   /* X19 */
  5437.     X19();
  5438.     break;
  5439.  
  5440.   case 20:   /* X20 */
  5441.     X20();
  5442.     break;
  5443.  
  5444.   case 21:   /* X21 */
  5445.     X21();
  5446.     break;
  5447.  
  5448.   case 22:   /* X22 */
  5449.     X22();
  5450.     break;
  5451.  
  5452.   case 23:   /* X23 */
  5453.     X23();
  5454.     break;
  5455.  
  5456.   case 24:   /* X24 */
  5457.     X24();
  5458.     break;
  5459.  
  5460.   case 25:   /* X25 */
  5461.     X25();
  5462.     break;
  5463.  
  5464.   case 26:   /* X26 */
  5465.     X26();
  5466.     break;
  5467.  
  5468.   case 27:   /* X27 */
  5469.     X27();
  5470.     break;
  5471.  
  5472.   case 28:   /* X28 */
  5473.     X28();
  5474.     break;
  5475.  
  5476.   default:
  5477.     InternalError(NotImplemented);
  5478.     break;
  5479.   }
  5480. }  /* ExecuteNewMultipleOperandOperations */
  5481.  
  5482. Local void GetOneOperand_(void) {
  5483.   switch (cMode(CmdCode)) {
  5484.  
  5485.   case 0:
  5486.     Opd.U1.s0 = GetWordIPC();
  5487.     break;
  5488.  
  5489.   case 1:
  5490.     Opd.U1.s0 = GetByteIPC();
  5491.     break;
  5492.  
  5493.   case 2:
  5494.     Opd.U1.s0 = DoGetWord();
  5495.     break;
  5496.   }
  5497.   OpdCnt = 1;
  5498. }  /* GetOneOperand */
  5499.  
  5500. Local void ExecuteOneOperandOperation(void) {
  5501.   int Op4;
  5502.   int AddressHigh;
  5503.   int AddressIndex;
  5504.   int ObjPageNo;
  5505.   int ObjPageIndex;
  5506.   int WrkObj;
  5507.   int LowByte;
  5508.   int HighByte;
  5509.  
  5510.   Op4 = cOp4(CmdCode);
  5511.   switch (Op4) {
  5512.  
  5513.   case 0:   /* EQN */
  5514.     if (Opd.U1.s0 == 0)
  5515.       HandleTrue();
  5516.     else
  5517.       HandleFalse();
  5518.     break;
  5519.  
  5520.   case 1:   /* NXO */
  5521.     if (CodeVersion < '4') {
  5522.       CalcObjAdrs(Opd.U1.s0, &ObjPageNo, &ObjPageIndex, 5);
  5523.       WrkObj = PagePtrs[ObjPageNo][ObjPageIndex];
  5524.     } else {
  5525.       CalcObjAdrs(Opd.U1.s0, &ObjPageNo, &ObjPageIndex, 8);
  5526.       HighByte = PagePtrs[ObjPageNo][ObjPageIndex];
  5527.       ++ObjPageIndex;
  5528.       if (ObjPageIndex >= 256) {
  5529.         ++ObjPageNo;
  5530.         ObjPageIndex = 0;
  5531.       }
  5532.       LowByte = PagePtrs[ObjPageNo][ObjPageIndex];
  5533.       WrkObj = JoinBytes(LowByte, HighByte);
  5534.     }
  5535.     DoPutWord(WrkObj);
  5536.     if (WrkObj == 0)
  5537.       HandleFalse();
  5538.     else
  5539.       HandleTrue();
  5540.     break;
  5541.  
  5542.   case 2:   /* FSO */
  5543.     if (CodeVersion < '4') {
  5544.       CalcObjAdrs(Opd.U1.s0, &ObjPageNo, &ObjPageIndex, 6);
  5545.       WrkObj = PagePtrs[ObjPageNo][ObjPageIndex];
  5546.     } else {
  5547.       CalcObjAdrs(Opd.U1.s0, &ObjPageNo, &ObjPageIndex, 10);
  5548.       HighByte = PagePtrs[ObjPageNo][ObjPageIndex];
  5549.       Inc(&ObjPageNo, &ObjPageIndex, 1);
  5550.       LowByte = PagePtrs[ObjPageNo][ObjPageIndex];
  5551.       WrkObj = JoinBytes(LowByte, HighByte);
  5552.     }
  5553.     DoPutWord(WrkObj);
  5554.     if (WrkObj == 0)
  5555.       HandleFalse();
  5556.     else
  5557.       HandleTrue();
  5558.     break;
  5559.  
  5560.   case 3:   /* PTO */
  5561.     if (CodeVersion < '4') {
  5562.       CalcObjAdrs(Opd.U1.s0, &ObjPageNo, &ObjPageIndex, 4);
  5563.       WrkObj = PagePtrs[ObjPageNo][ObjPageIndex];
  5564.     } else {
  5565.       CalcObjAdrs(Opd.U1.s0, &ObjPageNo, &ObjPageIndex, 6);
  5566.       HighByte = PagePtrs[ObjPageNo][ObjPageIndex];
  5567.       Inc(&ObjPageNo, &ObjPageIndex, 1);
  5568.       LowByte = PagePtrs[ObjPageNo][ObjPageIndex];
  5569.       WrkObj = JoinBytes(LowByte, HighByte);
  5570.     }
  5571.     DoPutWord(WrkObj);
  5572.     break;
  5573.  
  5574.   case 4:   /* LPS */
  5575.     SplitWord(Opd.U1.s0 - 1, &AddressIndex, &AddressHigh);
  5576.     DoPutWord(GetPropertySize(&AddressHigh, &AddressIndex, false));
  5577.     break;
  5578.  
  5579.   case 5:   /* INC */
  5580.     GetAccA(Opd.U1.s0);
  5581.     ++AccA;
  5582.     PutAccA(Opd.U1.s0);
  5583.     break;
  5584.  
  5585.   case 6:   /* DEC */
  5586.     GetAccA(Opd.U1.s0);
  5587.     --AccA;
  5588.     PutAccA(Opd.U1.s0);
  5589.     break;
  5590.  
  5591.   case 7:   /* WSB */
  5592.     SplitWord(Opd.U1.s0, &AccC, &AccB);
  5593.     WTX(&AccB, &AccC, false);
  5594.     break;
  5595.  
  5596.   case 8:   /* ???/CFC */
  5597.     if (CodeVersion < '4')
  5598.       InternalError(IllOneOpdOp);
  5599.     else
  5600.       Call(Opd.U1.s0, true, OpdCnt - 1);
  5601.     break;
  5602.  
  5603.   case 9:   /* RMO */
  5604.     RemoveObj(Opd.U1.s0);
  5605.     break;
  5606.  
  5607.   case 10:   /* WTO */
  5608.     if (CodeVersion < '4')
  5609.       CalcObjAdrs(Opd.U1.s0, &ObjPageNo, &ObjPageIndex, 7);
  5610.     else
  5611.       CalcObjAdrs(Opd.U1.s0, &ObjPageNo, &ObjPageIndex, 12);
  5612.     AddressHigh = PagePtrs[ObjPageNo][ObjPageIndex];
  5613.     Inc(&ObjPageNo, &ObjPageIndex, 1);
  5614.     AddressIndex = PagePtrs[ObjPageNo][ObjPageIndex];
  5615.     Inc(&AddressHigh, &AddressIndex, 1);
  5616.     WTX(&AddressHigh, &AddressIndex, false);
  5617.     break;
  5618.  
  5619.   case 11:   /* RTN */
  5620.     Return(Opd.U1.s0);
  5621.     break;
  5622.  
  5623.   case 12:   /* JMP */
  5624.     CalcJump(IPC_PageNo, IPC_PageIndex, &IPC_PageNo, &IPC_PageIndex,
  5625.              Opd.U1.s0);
  5626.     break;
  5627.  
  5628.   case 13:   /* WSW */
  5629.     AddressHigh = 0;
  5630.     ShiftLeft(&AddressHigh, &Opd.U1.s0);
  5631.     if (CodeVersion >= '4')
  5632.       ShiftLeft(&AddressHigh, &Opd.U1.s0);
  5633.     ChkAddress(&AddressHigh, &Opd.U1.s0);
  5634.     WTX(&AddressHigh, &Opd.U1.s0, false);
  5635.     break;
  5636.  
  5637.   case 14:   /* MVE */
  5638.     GetAccA(Opd.U1.s0);
  5639.     DoPutWord(AccA);
  5640.     break;
  5641.  
  5642.   case 15:   /* NEG/CPC */
  5643.     if (CodeVersion < '5')
  5644.       DoPutWord(lnot(Opd.U1.s0));
  5645.     else
  5646.       Call(Opd.U1.s0, false, OpdCnt - 1);
  5647.     break;
  5648.   }/* CASE */
  5649. }  /* ExecuteOneOperandOperation */
  5650.  
  5651. Local void GetTwoOperands_(void) {
  5652.   if (TstBit(CmdCode, 6))
  5653.     Opd.U1.s0 = DoGetWord();
  5654.   else
  5655.     Opd.U1.s0 = GetByteIPC();
  5656.   if (TstBit(CmdCode, 5))
  5657.     Opd.U1.s1 = DoGetWord();
  5658.   else
  5659.     Opd.U1.s1 = GetByteIPC();
  5660.   OpdCnt = 2;
  5661. }  /* GetTwoOperands */
  5662.  
  5663. Local void ExecuteTwoOperandOperation(void) {
  5664.   int EquCnt;
  5665.   int AddressHigh;
  5666.   int AddressIndex;
  5667.   int ObjDataPageNo;
  5668.   int ObjDataPageIndex;
  5669.   int LowByte;
  5670.   int HighByte;
  5671.   int FORLIM;
  5672.  
  5673.   switch (cOp5(CmdCode)) {
  5674.  
  5675.   case 0:
  5676.     ExecuteBPT();
  5677.     break;
  5678.  
  5679.   case 1:   /* EQU */
  5680.     if (OpdCnt < 2)
  5681.       InternalError(MissingOpd);
  5682.     FORLIM = OpdCnt;
  5683.     for (EquCnt = 1; EquCnt < FORLIM; ++EquCnt) {
  5684.       if (Opd.U1.s0 == Opd.a[EquCnt]) {
  5685.         HandleTrue();
  5686.         goto _L100;
  5687.       }
  5688.     }
  5689.     HandleFalse();
  5690. _L100: ;
  5691.     break;
  5692.  
  5693.   case 2:   /* LES */
  5694.     if (Opd.U1.s0 < Opd.U1.s1)
  5695.       HandleTrue();
  5696.     else
  5697.       HandleFalse();
  5698.     break;
  5699.  
  5700.   case 3:   /* GRT */
  5701.     if (Opd.U1.s0 > Opd.U1.s1)
  5702.       HandleTrue();
  5703.     else
  5704.       HandleFalse();
  5705.     break;
  5706.  
  5707.   case 4:   /* DLS */
  5708.     GetAccA(Opd.U1.s0);
  5709.     --AccA;
  5710.     PutAccA(Opd.U1.s0);
  5711.     if (AccA < Opd.U1.s1)
  5712.       HandleTrue();
  5713.     else
  5714.       HandleFalse();
  5715.     break;
  5716.  
  5717.   case 5:   /* IGT */
  5718.     GetAccA(Opd.U1.s0);
  5719.     ++AccA;
  5720.     PutAccA(Opd.U1.s0);
  5721.     if (AccA > Opd.U1.s1)
  5722.       HandleTrue();
  5723.     else
  5724.       HandleFalse();
  5725.     break;
  5726.  
  5727.   case 6:   /* OIN */
  5728.     if (ObjInObj(Opd.U1.s0, Opd.U1.s1))
  5729.       HandleTrue();
  5730.     else
  5731.       HandleFalse();
  5732.     break;
  5733.  
  5734.   case 7:   /* TST */
  5735.     if (land(Opd.U1.s0, Opd.U1.s1) != Opd.U1.s1)
  5736.       HandleFalse();
  5737.     else
  5738.       HandleTrue();
  5739.     break;
  5740.  
  5741.   case 8:   /* LOR */
  5742.     DoPutWord(lor(Opd.U1.s0, Opd.U1.s1));
  5743.     break;
  5744.  
  5745.   case 9:   /* AND */
  5746.     DoPutWord(land(Opd.U1.s0, Opd.U1.s1));
  5747.     break;
  5748.  
  5749.   case 10:   /* TSF */
  5750.     if (TestFlag(Opd.U1.s0, Opd.U1.s1))
  5751.       HandleTrue();
  5752.     else
  5753.       HandleFalse();
  5754.     break;
  5755.  
  5756.   case 11:   /* SEF */
  5757.     SetFlag(Opd.U1.s0, Opd.U1.s1, true);
  5758.     break;
  5759.  
  5760.   case 12:   /* CLF */
  5761.     SetFlag(Opd.U1.s0, Opd.U1.s1, false);
  5762.     break;
  5763.  
  5764.   case 13:   /* SEW */
  5765.     AccA = Opd.U1.s1;
  5766.     PutAccA(Opd.U1.s0);
  5767.     break;
  5768.  
  5769.   case 14:   /* INS */
  5770.     InsertObj(Opd.U1.s0, Opd.U1.s1);
  5771.     break;
  5772.  
  5773.   case 15:   /* LDW */
  5774.     SplitWord(Opd.U1.s0, &AddressIndex, &AddressHigh);
  5775.     Inc(&AddressHigh, &AddressIndex, Opd.U1.s1 * 2);
  5776.     HighByte = PagePtrs[AddressHigh][AddressIndex];
  5777.     Inc(&AddressHigh, &AddressIndex, 1);
  5778.     LowByte = PagePtrs[AddressHigh][AddressIndex];
  5779.     DoPutWord(JoinBytes(LowByte, HighByte));
  5780.     break;
  5781.  
  5782.   case 16:   /* LDB */
  5783.     SplitWord(Opd.U1.s0, &AddressIndex, &AddressHigh);
  5784.     Inc(&AddressHigh, &AddressIndex, Opd.U1.s1);
  5785.     DoPutWord(PagePtrs[AddressHigh][AddressIndex]);
  5786.     break;
  5787.  
  5788.   case 17:   /* LDP */
  5789.     GetObjPropertyPtr(Opd.U1.s0, &ObjDataPageNo, &ObjDataPageIndex);
  5790. _L170:
  5791.     AccA = GetPropertyNo(ObjDataPageNo, ObjDataPageIndex);
  5792.     if (AccA > Opd.U1.s1) {
  5793.       Inc(&ObjDataPageNo, &ObjDataPageIndex,
  5794.           GetPropertySize(&ObjDataPageNo, &ObjDataPageIndex, true) + 1);
  5795.       goto _L170;
  5796.     }
  5797.     if (AccA < Opd.U1.s1) {
  5798.       ObjDataPageNo = MiscInfo.ObjPageNo;
  5799.       ObjDataPageIndex = MiscInfo.ObjPageIndex;
  5800.       Inc(&ObjDataPageNo, &ObjDataPageIndex, (Opd.U1.s1 - 1) * 2);
  5801.       HighByte = PagePtrs[ObjDataPageNo][ObjDataPageIndex];
  5802.       Inc(&ObjDataPageNo, &ObjDataPageIndex, 1);
  5803.       LowByte = PagePtrs[ObjDataPageNo][ObjDataPageIndex];
  5804.     } else {
  5805.       AccA = GetPropertySize(&ObjDataPageNo, &ObjDataPageIndex, true);
  5806.       Inc(&ObjDataPageNo, &ObjDataPageIndex, 1);
  5807.       if (AccA == 1) {
  5808.         LowByte = PagePtrs[ObjDataPageNo][ObjDataPageIndex];
  5809.         HighByte = 0;
  5810.       } else if (AccA == 2) {
  5811.         HighByte = PagePtrs[ObjDataPageNo][ObjDataPageIndex];
  5812.         Inc(&ObjDataPageNo, &ObjDataPageIndex, 1);
  5813.         LowByte = PagePtrs[ObjDataPageNo][ObjDataPageIndex];
  5814.       } else {
  5815.         InternalError(IllObjDataLoad);
  5816.       }
  5817.     }
  5818.     DoPutWord(JoinBytes(LowByte, HighByte));
  5819.     break;
  5820.  
  5821.   case 18:   /* LPA */
  5822.     GetObjPropertyPtr(Opd.U1.s0, &ObjDataPageNo, &ObjDataPageIndex);
  5823. _L180:
  5824.     AccA = GetPropertyNo(ObjDataPageNo, ObjDataPageIndex);
  5825.     if (AccA > Opd.U1.s1) {
  5826.       Inc(&ObjDataPageNo, &ObjDataPageIndex,
  5827.           GetPropertySize(&ObjDataPageNo, &ObjDataPageIndex, true) + 1);
  5828.       goto _L180;
  5829.     }
  5830.     if (AccA < Opd.U1.s1) {
  5831.       DoPutWord(0);
  5832.     } else {
  5833.       AccA = GetPropertySize(&ObjDataPageNo, &ObjDataPageIndex, true);
  5834.       DoPutWord(ObjDataPageNo * 256 + ObjDataPageIndex + 1);
  5835.     }
  5836.     break;
  5837.  
  5838.   case 19:   /* LNP */
  5839.     GetObjPropertyPtr(Opd.U1.s0, &ObjDataPageNo, &ObjDataPageIndex);
  5840.     if (Opd.U1.s1 == 0) {
  5841.       DoPutWord(GetPropertyNo(ObjDataPageNo, ObjDataPageIndex));
  5842.     } else {
  5843. _L190:
  5844.       AccA = GetPropertyNo(ObjDataPageNo, ObjDataPageIndex);
  5845.       if (AccA > Opd.U1.s1) {
  5846.         Inc(&ObjDataPageNo, &ObjDataPageIndex,
  5847.             GetPropertySize(&ObjDataPageNo, &ObjDataPageIndex, true) + 1);
  5848.         goto _L190;
  5849.       }
  5850.       if (AccA < Opd.U1.s1) {
  5851.         DoPutWord(0);
  5852.       } else {
  5853.         Inc(&ObjDataPageNo, &ObjDataPageIndex,
  5854.             GetPropertySize(&ObjDataPageNo, &ObjDataPageIndex, true) + 1);
  5855.         DoPutWord(GetPropertyNo(ObjDataPageNo, ObjDataPageIndex));
  5856.       }
  5857.     }
  5858.     break;
  5859.  
  5860.   case 20:   /* ADD */
  5861.     DoPutWord(Opd.U1.s0 + Opd.U1.s1);
  5862.     break;
  5863.  
  5864.   case 21:   /* SUB */
  5865.     DoPutWord(Opd.U1.s0 - Opd.U1.s1);
  5866.     break;
  5867.  
  5868.   case 22:   /* MUL */
  5869.     DoPutWord(Opd.U1.s0 * Opd.U1.s1);
  5870.     break;
  5871.  
  5872.   case 23:   /* DIV */
  5873.     if (Opd.U1.s1 == 0)
  5874.       InternalError(DivideByZero);
  5875.     else
  5876.       DoPutWord(Opd.U1.s0 / Opd.U1.s1);
  5877.     break;
  5878.  
  5879.   case 24:   /* MOD */
  5880.     DoPutWord(Opd.U1.s0 % Opd.U1.s1);
  5881.     break;
  5882.  
  5883.   case 25:   /* CFC */
  5884.     Call(Opd.U1.s0, true, OpdCnt - 1);
  5885.     break;
  5886.  
  5887.   case 26:   /* CPC */
  5888.     Call(Opd.U1.s0, false, OpdCnt - 1);
  5889.     break;
  5890.  
  5891.   case 27:   /* N27 */
  5892.     InternalError(NotImplemented);
  5893.     break;
  5894.  
  5895.   case 28:   /* RTM */
  5896.     MSP = Opd.U1.s1;
  5897.     Return(Opd.U1.s0);
  5898.     break;
  5899.   }
  5900. }  /* ExecuteTwoOperandOperation */
  5901.  
  5902. Local void EndOfSession(void) {
  5903.   boolean OldPrintListing;
  5904.  
  5905.   ZM_NewLine();
  5906.   OldPrintListing = PrintListing;
  5907.   PrintListing = PrinterEnabled();
  5908.   PrintString("   *** End of session ***");
  5909.   PrintListing = OldPrintListing;
  5910.   ZM_NewLine();
  5911.   longjmp(_JL999, 1);
  5912. }  /* EndOfSession */
  5913.  
  5914. Local void ExecuteNoOperandOperation(void) {
  5915.   ShortInteger ChkSum;
  5916.  
  5917.   switch (cOp4(CmdCode)) {
  5918.  
  5919.   case 0:   /* RTT */
  5920.     Return(1);
  5921.     break;
  5922.  
  5923.   case 1:   /* RTF */
  5924.     Return(0);
  5925.     break;
  5926.  
  5927.   case 2:   /* WTX */
  5928.     WTX(&IPC_PageNo, &IPC_PageIndex, true);
  5929.     break;
  5930.  
  5931.   case 3:   /* WTR */
  5932.     WTX(&IPC_PageNo, &IPC_PageIndex, true);
  5933.     ZM_NewLine();
  5934.     Return(1);
  5935.     break;
  5936.  
  5937.   case 4:   /* NOP */
  5938.     break;
  5939.  
  5940.   case 5:   /* SVE */
  5941.     if (CodeVersion < '5') {
  5942.       if (SavedState()) {
  5943.         if (CodeVersion < '4')
  5944.           HandleTrue();
  5945.         else
  5946.           DoPutWord(1);
  5947.       } else if (CodeVersion < '4')
  5948.         HandleFalse();
  5949.       else
  5950.         DoPutWord(0);
  5951.     }
  5952.     break;
  5953.  
  5954.   case 6:   /* RSE */
  5955.     if (CodeVersion < '5') {
  5956.       if (RestoredState()) {
  5957.         if (CodeVersion < '4')
  5958.           HandleTrue();
  5959.         else
  5960.           DoPutWord(2);
  5961.       } else if (CodeVersion < '4')
  5962.         HandleFalse();
  5963.       else
  5964.         DoPutWord(0);
  5965.     }
  5966.     break;
  5967.  
  5968.   case 7:   /* RST */
  5969.     ReloadData();
  5970.     ClearScreen();
  5971.     ResetZMachine();
  5972.     if (CodeVersion <= '3') {
  5973.       ScrollTop = 2;
  5974.       ZM_GotoXY(1, ScrollTop);
  5975.     } else {
  5976.       ScrollTop = 1;
  5977.     }
  5978.     LineNo = ScrollTop;
  5979.     break;
  5980.  
  5981.   case 8:   /* RPL */
  5982.     AccA = Pop();
  5983.     Return(AccA);
  5984.     break;
  5985.  
  5986.   case 9:   /* DSC/PMP */
  5987.     if (CodeVersion < '5')
  5988.       AccA = Pop();
  5989.     else
  5990.       DoPutWord(MSP);
  5991.     break;
  5992.  
  5993.   case 10:   /* END */
  5994.     EndOfSession();
  5995.     break;
  5996.  
  5997.   case 11:   /* NWL */
  5998.     ZM_NewLine();
  5999.     break;
  6000.  
  6001.   case 12:   /* PSL */
  6002.     PrintStatusLine();
  6003.     break;
  6004.  
  6005.   case 13:   /* VFY */
  6006.     if (CodeCorrect(&ChkSum)) {
  6007.       if (CodeVersion < '4')
  6008.         HandleTrue();
  6009.       else
  6010.         DoPutWord(1);
  6011.     } else if (CodeVersion < '4')
  6012.       HandleFalse();
  6013.     else
  6014.       DoPutWord(0);
  6015.     break;
  6016.  
  6017.   case 14:   /* Extensions */
  6018.     CmdCode = GetByteIPC();
  6019.     GetMultipleOperands_(false);
  6020.     if (CmdCode >= 224) {   /* $E0 */
  6021.       ExecuteMultipleOperandOperation(true);
  6022.     } else if (CmdCode < 192)
  6023.       ExecuteNewMultipleOperandOperation();
  6024.     else
  6025.       ExecuteTwoOperandOperation();
  6026.     break;
  6027.  
  6028.   case 15:
  6029.     /* blank case */
  6030.     break;
  6031.   }/* CASE */
  6032.  
  6033.   /* $C0 */
  6034. }  /* ExecuteNoOperandOperation */
  6035.  
  6036.  
  6037. Static void ExecuteSingleInstruction(void) {
  6038.   NewInstPageNo = IPC_PageNo;
  6039.   NewInstPageIndex = IPC_PageIndex;
  6040.   CmdCode = GetByteIPC();
  6041.   if (Statistics)
  6042.     ++ExecCnt[CmdCode];
  6043.   if (CmdCode == 0) {
  6044.     ExecuteBPT();
  6045.   } else if (CmdCode < 128) {
  6046.     GetTwoOperands_();
  6047.     ExecuteTwoOperandOperation();
  6048.   } else if (CmdCode < 176) {
  6049.     GetOneOperand_();
  6050.     ExecuteOneOperandOperation();
  6051.   } else if (CmdCode < 192) {
  6052.     ExecuteNoOperandOperation();
  6053.   } else {
  6054.     GetMultipleOperands_(CmdCode == 236 || CmdCode == 250);
  6055.     if (CmdCode < 224)   /* $E0 */
  6056.       ExecuteTwoOperandOperation();
  6057.     else
  6058.       ExecuteMultipleOperandOperation(false);
  6059.   }
  6060.   InstPageNo = NewInstPageNo;
  6061.   InstPageIndex = NewInstPageIndex;
  6062.  
  6063.   /* $80 */
  6064.   /* $B0 */
  6065.   /* $C0 */
  6066. }  /* ExecuteSingleInstruction */
  6067.  
  6068.  
  6069. Static void ExecuteSubRoutine(int Address) {
  6070.   int Org_PageNo;
  6071.   int Org_PageIndex;
  6072.   int OrgOpdCnt;
  6073.   Operands OrgOpd;
  6074.   int OrgCursorX;
  6075.   int OrgCursorY;
  6076.  
  6077.   OrgCursorX = CursorX;
  6078.   OrgCursorY = CursorY;
  6079.   OrgOpdCnt = OpdCnt;
  6080.   OrgOpd = Opd;
  6081.   Org_PageNo = IPC_PageNo;
  6082.   Org_PageIndex = IPC_PageIndex;
  6083.   IPC_PageNo = 0;
  6084.   IPC_PageIndex = 0;
  6085.   Call(Address, false, 0);
  6086.   do {
  6087.     ExecuteSingleInstruction();
  6088.   } while (IPC_PageNo != 0 || IPC_PageIndex != 0);
  6089.   IPC_PageNo = Org_PageNo;
  6090.   IPC_PageIndex = Org_PageIndex;
  6091.   Opd = OrgOpd;
  6092.   OpdCnt = OrgOpdCnt;
  6093.   CursorY = OrgCursorY;
  6094.   CursorX = OrgCursorX;
  6095.   PositionCursor();
  6096. }  /* ExecuteSubRoutine */
  6097.  
  6098.  
  6099. Static void RunCommand(boolean ListState, char RunCmd) {
  6100.   Char Key;
  6101.  
  6102.   Cmd = RunCmd;
  6103.   FirstInstPageNo = IPC_PageNo;
  6104.   FirstInstPageIndex = IPC_PageIndex;
  6105.   if (EndIPC_PageNo >= 0)
  6106.     SetBPT(BPT_IdCnt, EndIPC_PageNo, EndIPC_PageIndex, RunBPT);
  6107.   if (ListState)
  6108.     PrintZState();
  6109.   RestoreCursorState();
  6110.   Running = true;
  6111. _L0:
  6112.   /*
  6113.   LOOP */
  6114.   ExecuteSingleInstruction();
  6115.   if (KeyPressed()) {
  6116.     ReadKey(false, &Key, -1, CallNever, 0);
  6117.     if (Key == BreakKey)
  6118.       InternalError(KeyboardBreak);
  6119.     KeyBuffer[WriteIndex] = Key;
  6120.     ++WriteIndex;
  6121.     if (WriteIndex > 79)
  6122.       WriteIndex = 0;
  6123.   }
  6124.   goto _L0;
  6125.   /*
  6126.    END */
  6127. }  /* RunCommand */
  6128.  
  6129.  
  6130. Static void StepCommand(void) {
  6131.   Char CmdKey;
  6132.   int InstPageNo;
  6133.   int InstPageIndex;
  6134.   int LastBPT;
  6135.   int OnePageNo;
  6136.   int OnePageIndex;
  6137.  
  6138.   LastBPT = -1;
  6139.   Stepping = true;
  6140.   Cmd = Step;
  6141.   FirstInstPageNo = IPC_PageNo;
  6142.   FirstInstPageIndex = IPC_PageIndex;
  6143.   EndIPC_PageNo = -1;
  6144.   EndIPC_PageIndex = -1;
  6145.   do {
  6146.     PrintZState();
  6147.     DC_PageNo = IPC_PageNo;
  6148.     DC_PageIndex = IPC_PageIndex;
  6149.     InstPageNo = DC_PageNo;
  6150.     InstPageIndex = DC_PageIndex;
  6151.     Disassemble(1, true);
  6152.     OnePageNo = DC_PageNo;
  6153.     OnePageIndex = DC_PageIndex;
  6154.     do {
  6155.       ReadKey(false, &CmdKey, -1, CallNever, 0);
  6156.       if (islower(CmdKey))
  6157.         CmdKey = _toupper(CmdKey);
  6158.       if (CmdKey == 'L') {
  6159.         InstPageNo = DC_PageNo;
  6160.         InstPageIndex = DC_PageIndex;
  6161.         Disassemble(1, true);
  6162.       } else if (CmdKey == 'G') {
  6163.         EndIPC_PageNo = InstPageNo;
  6164.         EndIPC_PageIndex = InstPageIndex;
  6165.         RunCommand(false, Run);
  6166.       } else if (CmdKey == 'O') {
  6167.         EndIPC_PageNo = OnePageNo;
  6168.         EndIPC_PageIndex = OnePageIndex;
  6169.         RunCommand(false, Run);
  6170.       } else if (CmdKey == 'T') {
  6171.         Cmd = SwitchToTrace;
  6172.         longjmp(_JL999, 1);
  6173.       } else if (CmdKey == 'X') {
  6174.         RunCommand(true, Run);
  6175.       } else if (CmdKey == 'B') {
  6176.         LastBPT = BPT_IdCnt;
  6177.         SetBPT(BPT_IdCnt, InstPageNo, InstPageIndex, UserBPT);
  6178.         PrintString("Break-point set at last instruction.");
  6179.         ChkWait();
  6180.       } else if (CmdKey == 'C') {
  6181.         if (LastBPT < 0) {
  6182.           RingBell();
  6183.         } else {
  6184.           ClearBPT(LastBPT);
  6185.           LastBPT = -1;
  6186.           PrintString("Last break-point cleared.");
  6187.           ChkWait();
  6188.         }
  6189.       } else if (CmdKey != ExitKey && CmdKey != BreakKey && CmdKey != ' ') {
  6190.         RingBell();
  6191.         PrintString(
  6192.           "sp=step, L=list, T=trace, X=run, G=go last, O=run one, B=set BPT, C=clr BPT");
  6193.         ChkWait();
  6194.       }
  6195.     } while (CmdKey != ExitKey && CmdKey != BreakKey && CmdKey != ' ');
  6196.     if (CmdKey == ' ') {
  6197.       RestoreCursorState();
  6198.       ExecuteSingleInstruction();
  6199.     }
  6200.   } while (CmdKey != ExitKey && CmdKey != BreakKey);   /* StepCommand */
  6201. }
  6202.  
  6203.  
  6204. Static void TraceCommand(void) {
  6205.   Char Key;
  6206.  
  6207.   Cmd = Trace;
  6208.   FirstInstPageNo = IPC_PageNo;
  6209.   FirstInstPageIndex = IPC_PageIndex;
  6210.   if (EndIPC_PageNo >= 0)
  6211.     SetBPT(BPT_IdCnt, EndIPC_PageNo, EndIPC_PageIndex, TraceBPT);
  6212.   PrintZState();
  6213.   Tracing = true;
  6214. _L0:
  6215.   /*
  6216.   LOOP */
  6217.   DC_PageNo = IPC_PageNo;
  6218.   DC_PageIndex = IPC_PageIndex;
  6219.   Disassemble(1, true);
  6220.   RestoreCursorState();
  6221.   ExecuteSingleInstruction();
  6222.   PrintZState();
  6223.   if (KeyPressed()) {
  6224.     Key = ReadKeyWithNoEcho(-1);
  6225.     if (islower(Key))
  6226.       Key = _toupper(Key);
  6227.     if (Key == BreakKey) {
  6228.       ChkWait();
  6229.       longjmp(_JL999, 1);
  6230.     }
  6231.     if (Key == 'S') {
  6232.       Cmd = SwitchToStep;
  6233.       longjmp(_JL999, 1);
  6234.     } else {
  6235.       KeyBuffer[WriteIndex] = Key;
  6236.       ++WriteIndex;
  6237.       if (WriteIndex > 79)
  6238.         WriteIndex = 0;
  6239.     }
  6240.   }
  6241.   goto _L0;
  6242.   /*
  6243.    END; */
  6244. }  /* TraceCommand */
  6245.  
  6246.  
  6247. Static void StartZMachine(char StartCmd) {
  6248.   ClearScreen();
  6249.   if (CodeVersion <= '3') {
  6250.     ScrollTop = 2;
  6251.     ZM_GotoXY(1, ScrollTop);
  6252.   } else {
  6253.     ScrollTop = 1;
  6254.     ZM_GotoXY(1, ScreenHeight);
  6255.   }
  6256.   EndIPC_PageNo = -1;
  6257.   EndIPC_PageIndex = -1;
  6258.   RunCommand(false, StartCmd);
  6259. }  /* StartZMachine */
  6260.  
  6261.  
  6262. Static void CallBacktrace(void) {
  6263.   int NumLocalVariables;
  6264.   int RegCnt;
  6265.   int OldSP;
  6266.   int WrkMSP;
  6267.   int WrkNumCallParams;
  6268.   int Discard;
  6269.   Registers WrkRegs;
  6270.  
  6271.   OldSP = SP;
  6272.   WrkMSP = MSP;
  6273.   while (WrkMSP != 0) {
  6274.     SP = WrkMSP;
  6275.     NumLocalVariables = Pop();
  6276.     WrkNumCallParams = Pop();
  6277.     for (RegCnt = NumLocalVariables - 1; RegCnt >= 0; --RegCnt)
  6278.       WrkRegs.a[RegCnt] = Pop();
  6279.     Discard = Pop();
  6280.     Discard = Pop();
  6281.     DC_PageIndex = Pop();
  6282.     DC_PageNo = Pop();
  6283.     WrkMSP = Pop();
  6284.     Disassemble(1, true);
  6285.   }
  6286.   SP = OldSP;
  6287. }  /* CallBacktrace */
  6288.  
  6289.  
  6290. Static void EnterSubroutine(void) {
  6291.   int NumRegsToInit;
  6292.  
  6293.   NumRegsToInit = GetByteDC();
  6294.   DisRegList(NumRegsToInit);
  6295.   Disassemble(ScreenHeight - 5, true);
  6296. }  /* EnterSubroutine */
  6297.  
  6298.  
  6299. Static void DisplayTextData(void) {
  6300.   int CodePageNo;
  6301.   int CodeIndex;
  6302.  
  6303.   CodePageNo = DC_PageNo;
  6304.   CodeIndex = DC_PageIndex;
  6305.   BackTxtPageNo = OldTextPageNo;
  6306.   BackTxtIndex = OldTextPageIndex;
  6307.   DC_PageNo = TextPageNo;
  6308.   DC_PageIndex = TextPageIndex;
  6309.   OldTextPageNo = TextPageNo;
  6310.   OldTextPageIndex = TextPageIndex;
  6311.   do {
  6312.     WriteText('T', OntoScreen, FromDC, GlobalTextBuffer);
  6313.   } while (DC_PageNo <= EndPageNo &&
  6314.            (DC_PageNo != EndPageNo || DC_PageIndex <= EndPageIndex));
  6315.   NewLine();
  6316.   TextPageNo = DC_PageNo;
  6317.   TextPageIndex = DC_PageIndex;
  6318.   DC_PageNo = CodePageNo;
  6319.   DC_PageIndex = CodeIndex;
  6320. }  /* DisplayTextData */
  6321.  
  6322.  
  6323. Local void ListIt(void) {
  6324.   int ChrCnt;
  6325.   Char CodeName[256];
  6326.   int PageIndex;
  6327.   int PageNo;
  6328.  
  6329.   PrintString("Code type       :");
  6330.   PrintCh(' ');
  6331.   switch (CodeVersion) {
  6332.  
  6333.   case '1':
  6334.   case '2':
  6335.   case '3':
  6336.     strcpy(CodeName, "Standard");
  6337.     break;
  6338.  
  6339.   case '4':
  6340.     strcpy(CodeName, "Plus");
  6341.     break;
  6342.  
  6343.   case '5':
  6344.     strcpy(CodeName, "X");
  6345.     break;
  6346.  
  6347.   case '6':
  6348.     strcpy(CodeName, "Y");
  6349.     break;
  6350.  
  6351.   default:
  6352.     strcpy(CodeName, "Illegal");
  6353.     break;
  6354.   }
  6355.   if (CodeVersion >= '1' && CodeVersion <= '6') {
  6356.     PrintString(CodeName);
  6357.     PrintString(" Development System (");
  6358.     PrintCh(CodeVersion);
  6359.     PrintCh(')');
  6360.   } else {
  6361.     PrintString("Unknown (");
  6362.     PrintByte(MiscInfo.CodeType, 2);
  6363.     PrintCh(')');
  6364.   }
  6365.   ChkWait();
  6366.   PrintString("Release         :");
  6367.   PrintWord(ReleaseNo, 5);
  6368.   ChkWait();
  6369.   PrintString("Serialnumber    :");
  6370.   PrintCh(' ');
  6371.   for (ChrCnt = 0; ChrCnt <= 5; ++ChrCnt)
  6372.     PrintCh(MiscInfo.SerialNumber[ChrCnt]);
  6373.   ChkWait();
  6374.   PrintString("Start address   :");
  6375.   if (CodeVersion <= '5') {
  6376.     PageIndex = MiscInfo.StartIndex;
  6377.     PageNo = MiscInfo.StartPageNo;
  6378.   } else {
  6379.     CalcCallAddress(JoinBytes(MiscInfo.StartIndex, MiscInfo.StartPageNo),
  6380.                     &PageNo, &PageIndex);
  6381.   }
  6382.   PrintWord(PageNo, 5);
  6383.   PrintByte(PageIndex, 2);
  6384.   ChkWait();
  6385.   PrintString("Vocabulary base :");
  6386.   PrintWord(MiscInfo.VocabPageNo, 5);
  6387.   PrintByte(MiscInfo.VocabPageIndex, 2);
  6388.   ChkWait();
  6389.   PrintString("Special base    :");
  6390.   PrintWord(MiscInfo.SpecialPageNo, 5);
  6391.   PrintByte(MiscInfo.SpecialIndex, 2);
  6392.   ChkWait();
  6393.   PrintString("Data base       :");
  6394.   PrintWord(MiscInfo.DataPageNo, 5);
  6395.   PrintByte(MiscInfo.DataPageIndex, 2);
  6396.   ChkWait();
  6397.   PrintString("Object base     :");
  6398.   PrintWord(MiscInfo.ObjPageNo, 5);
  6399.   PrintByte(MiscInfo.ObjPageIndex, 2);
  6400.   ChkWait();
  6401.   PrintString("Code end        :");
  6402.   PrintWord(CodeEndPageNo, 5);
  6403.   PrintByte(CodeEndPageIndex, 2);
  6404.   ChkWait();
  6405.   PrintString("Code checksum   :");
  6406.   PrintByte(MiscInfo.ChkSumHigh, 3);
  6407.   PrintByte(MiscInfo.ChkSumLow, 2);
  6408.   ChkWait();
  6409.   PrintString("Data length     :");
  6410.   PrintByte(MiscInfo.NumReadWriteBytesHigh, 3);
  6411.   PrintByte(MiscInfo.NumReadWriteBytesLow, 2);
  6412.   ChkWait();
  6413.   PrintString("Save length     :");
  6414.   PrintByte(MiscInfo.SaveStateSizeHigh, 3);
  6415.   PrintByte(MiscInfo.SaveStateSizeHigh, 2);
  6416.   ChkWait();
  6417.   PrintString("Story file name :");
  6418.   PrintCh(' ');
  6419.   PrintString(StoryName);
  6420.   ChkWait();
  6421. }  /* ListIt */
  6422.  
  6423.  
  6424. Static void ListMiscInfo(void) {
  6425.   int EndPageNo;
  6426.   int EndPageIndex;
  6427.   union {
  6428.     tMiscInfo *M;
  6429.     uchar *P;
  6430.   } SwapPage;
  6431.  
  6432.   SwapPage.P = PagePtrs[0];
  6433.   MiscInfo = *SwapPage.M;
  6434.   CodeVersion = MiscInfo.CodeType + '0';
  6435.   ExpandAddress(MiscInfo.EndPageNo, MiscInfo.EndPageIndex, &EndPageNo,
  6436.                 &EndPageIndex);
  6437.   CodeEndPageNo = EndPageNo;
  6438.   CodeEndPageIndex = EndPageIndex;
  6439.   if (CodeVersion >= '4') {
  6440.     ObjRecSize = 14;
  6441.     ObjOffset = 112;
  6442.     WordNumChars = 9;
  6443.   } else {
  6444.     ObjRecSize = 9;
  6445.     ObjOffset = 53;
  6446.     WordNumChars = 6;
  6447.   }
  6448.   ListIt();
  6449. }  /* ListMiscInfo */
  6450.  
  6451.  
  6452. Static void LoadStory(void) {
  6453.   ChkWait();
  6454.   BPT_IdCnt = 1;
  6455.   BPT_No = 0;
  6456.   while (BPT_List != NULL)
  6457.     ClearBPT(BPT_List->BPT_No);
  6458.   CodeEndPageNo = MaxPageNo;
  6459.   ReadPages();
  6460.   ReleaseNo = JoinBytes(MiscInfo.ReleaseLow, MiscInfo.ReleaseHigh);
  6461.   ListMiscInfo();
  6462.   ResetZMachine();
  6463.   ChkWait();
  6464.   EntryIndex = 0;
  6465.   FirstObj = 0;
  6466.   LastObj = 0;
  6467.   FirstHigh = 0;
  6468.   LastHigh = 0;
  6469.   RegNo = 0;
  6470.   DC_PageNo = IPC_PageNo;
  6471.   DC_PageIndex = IPC_PageIndex;
  6472.   OldPageNo = DC_PageNo;
  6473.   OldIndex = DC_PageIndex;
  6474.   BackPageNo = DC_PageNo;
  6475.   BackIndex = DC_PageIndex;
  6476.   OldIPC_PageNo = DC_PageNo;
  6477.   OldIPC_PageIndex = DC_PageIndex;
  6478.   BackIPC_PageNo = DC_PageNo;
  6479.   BackIPC_PageIndex = DC_PageIndex;
  6480. }  /* LoadStory */
  6481.  
  6482.  
  6483. Static void VerifyCommand(void) {
  6484.   ShortInteger CodeChkSum;
  6485.  
  6486.   if (CodeCorrect(&CodeChkSum)) {
  6487.     PrintString("Code ok.");
  6488.   } else {
  6489.     PrintString("Checksum error:");
  6490.     PrintWord(CodeChkSum, 5);
  6491.   }
  6492.   ChkWait();
  6493. }  /* VerifyCommand */
  6494.  
  6495.  
  6496. Static void PreparePrinter(void) {
  6497.   OpenPrinter();
  6498.   if (PrinterOpen)
  6499.     PrintListing = true;
  6500. }  /* PreparePrinter */
  6501.  
  6502.  
  6503. #define Spacing         4
  6504.  
  6505.  
  6506. /* Local variables for DisplayVocabulary: */
  6507. struct DisplayVocabulary_LocalVariables {
  6508.   boolean WithPointers;
  6509.   int WordPageNo;
  6510.   int WordIndex;
  6511.   int ValuesOffset;
  6512.   int NumWords;
  6513.   int NumSpecial;
  6514.   int EntryLength;
  6515.   int Specs[16];
  6516.   int Values[16];
  6517. } ;
  6518.  
  6519. Local void DisplayHeader(struct DisplayVocabulary_LocalVariables *DisplayVocabulary_Vars) {
  6520.   int SpecialCnt;
  6521.   int FORLIM;
  6522.  
  6523.   PrintString("The vocabulary consists of");
  6524.   PrintCh(' ');
  6525.   PrintInteger(DisplayVocabulary_Vars->NumWords);
  6526.   PrintString(" words and each word requires");
  6527.   PrintCh(' ');
  6528.   PrintInteger(DisplayVocabulary_Vars->EntryLength);
  6529.   PrintString(" bytes.");
  6530.   ChkWait();
  6531.   ChkWait();
  6532.   if (DisplayVocabulary_Vars->NumSpecial == 0) {
  6533.     PrintString("The vocabulary contains no word separators.");
  6534.     return;
  6535.   }
  6536.   PrintString("Word separators:");
  6537.   FORLIM = DisplayVocabulary_Vars->NumSpecial;
  6538.   for (SpecialCnt = 1; SpecialCnt <= FORLIM; ++SpecialCnt) {
  6539.     PrintCh(' ');
  6540.     PrintCh(DisplayVocabulary_Vars->Specs[SpecialCnt - 1]);
  6541.   }
  6542. }  /* DisplayHeader */
  6543.  
  6544. Local void DisplayWord(struct DisplayVocabulary_LocalVariables *DisplayVocabulary_Vars) {
  6545.   int ValueCnt;
  6546.   int SpaceCnt;
  6547.   int FORLIM;
  6548.  
  6549.   if (DisplayVocabulary_Vars->WithPointers) {
  6550.     PrintByte(DisplayVocabulary_Vars->WordPageNo, 2);
  6551.     PrintByte(DisplayVocabulary_Vars->WordIndex, 2);
  6552.     PrintCh(':');
  6553.     PrintCh(' ');
  6554.   }
  6555.   PrintString(GlobalTextBuffer);
  6556.   FORLIM = WordNumChars - strlen(GlobalTextBuffer) + 1;
  6557.   for (SpaceCnt = 1; SpaceCnt <= FORLIM; ++SpaceCnt)
  6558.     PrintCh(' ');
  6559.   if (!DisplayVocabulary_Vars->WithPointers) {
  6560.     FORLIM = DisplayVocabulary_Vars->EntryLength - DisplayVocabulary_Vars->
  6561.                                                    ValuesOffset;
  6562.     for (ValueCnt = 0; ValueCnt <= FORLIM; ++ValueCnt)
  6563.       PrintByte(DisplayVocabulary_Vars->Values[ValueCnt], 3);
  6564.   }
  6565.   for (SpaceCnt = 1; SpaceCnt <= Spacing; ++SpaceCnt)
  6566.     PrintCh(' ');
  6567. }  /* DisplayWord */
  6568.  
  6569.  
  6570. Static void DisplayVocabulary(boolean WithPointers_) {
  6571.   struct DisplayVocabulary_LocalVariables V;
  6572.   boolean EmptyLine;
  6573.   int OldDC_PageNo;
  6574.   int OldDC_PageIndex;
  6575.   int Cnt;
  6576.   int ValueCnt;
  6577.   int WordsPerLine;
  6578.   int FORLIM;
  6579.   int FORLIM1;
  6580.  
  6581.   V.WithPointers = WithPointers_;
  6582.   OldDC_PageNo = DC_PageNo;
  6583.   OldDC_PageIndex = DC_PageIndex;
  6584.   DC_PageNo = MiscInfo.VocabPageNo;
  6585.   DC_PageIndex = MiscInfo.VocabPageIndex;
  6586.   V.NumSpecial = GetByteDC();
  6587.   if (V.NumSpecial > 16) {
  6588.     PrintString("Error: too many word separators");
  6589.     RingBell();
  6590.     ChkWait();
  6591.     goto _L777;
  6592.   }
  6593.   FORLIM = V.NumSpecial;
  6594.   for (Cnt = 1; Cnt <= FORLIM; ++Cnt)
  6595.     V.Specs[Cnt - 1] = GetByteDC();
  6596.   V.EntryLength = GetByteDC();
  6597.   V.NumWords = GetWordDC();
  6598.   V.ValuesOffset = WordNumChars / 3 * 2 + 1;
  6599.   WordsPerLine = ScreenWidth /
  6600.       (WordNumChars + (V.EntryLength - V.ValuesOffset + 1) * 3 + Spacing + 1);
  6601.   DisplayHeader(&V);
  6602.   ChkWait();
  6603.   ChkWait();
  6604.   EmptyLine = true;
  6605.   FORLIM = V.NumWords;
  6606.   for (Cnt = 1; Cnt <= FORLIM; ++Cnt) {
  6607.     V.WordPageNo = DC_PageNo;
  6608.     V.WordIndex = DC_PageIndex;
  6609.     WriteText('V', IntoBuffer, FromDC, GlobalTextBuffer);
  6610.     FORLIM1 = V.EntryLength - V.ValuesOffset;
  6611.     for (ValueCnt = 0; ValueCnt <= FORLIM1; ++ValueCnt)
  6612.       V.Values[ValueCnt] = GetByteDC();
  6613.     DisplayWord(&V);
  6614.     EmptyLine = (Cnt % WordsPerLine == 0);
  6615.     if (EmptyLine)
  6616.       ChkWait();
  6617.   }
  6618.   if (!EmptyLine)
  6619.     ChkWait();
  6620.   ChkWait();
  6621.   PrintString("Vocabulary ends at:");
  6622.   PrintWord(DC_PageNo, 5);
  6623.   PrintByte(DC_PageIndex, 2);
  6624.   ChkWait();
  6625.   DC_PageNo = OldDC_PageNo;
  6626.   DC_PageIndex = OldDC_PageIndex;
  6627. _L777: ;
  6628. }  /* DisplayVocabulary */
  6629.  
  6630. #undef Spacing
  6631.  
  6632.  
  6633. Static int FindObject(int LastObj, Char Name[256]) {
  6634.   int NamePageNo;
  6635.   int NamePageIndex;
  6636.   int NameLength;
  6637.   int ObjCnt;
  6638.   boolean NotFound;
  6639.  
  6640.   DC_PageNo = MiscInfo.ObjPageNo;
  6641.   DC_PageIndex = MiscInfo.ObjPageIndex;
  6642.   ObjCnt = 1;
  6643.   NotFound = true;
  6644.   while (NotFound && ObjCnt <= LastObj) {
  6645.     if (CodeVersion < '4')
  6646.       CalcObjAdrs(ObjCnt, &DC_PageNo, &DC_PageIndex, 7);
  6647.     else
  6648.       CalcObjAdrs(ObjCnt, &DC_PageNo, &DC_PageIndex, 12);
  6649.     NamePageNo = GetByteDC();
  6650.     NamePageIndex = GetByteDC();
  6651.     DC_PageNo = NamePageNo;
  6652.     DC_PageIndex = NamePageIndex;
  6653.     NameLength = GetByteDC();
  6654.     if (NameLength > 0 && NameLength < 80) {
  6655.       *GlobalTextBuffer = '\0';
  6656.       WriteText('N', IntoBuffer, FromDC, GlobalTextBuffer);
  6657.       NotFound = (strpos2(GlobalTextBuffer, Name, 1) == 0);
  6658.     }
  6659.     ++ObjCnt;
  6660.   }
  6661.   if (NotFound)
  6662.     return 0;
  6663.   else
  6664.     return (ObjCnt - 1);
  6665. }  /* FindObject */
  6666.  
  6667.  
  6668. Static void DispObject(int FirstObj, int LastObj, boolean WithData) {
  6669.   int OldDC_PageNo;
  6670.   int OldDC_PageIndex;
  6671.   int ObjCnt;
  6672.   int InsideObj;
  6673.   int NextObj;
  6674.   int ContainsObj;
  6675.   int NamePageNo;
  6676.   int NameIndex;
  6677.   int FlagCnt;
  6678.   int NameLength;
  6679.   int DataNo;
  6680.   int ByteCnt;
  6681.   int DataValue;
  6682.   int DataCnt;
  6683.   int DataSize;
  6684.   int Flags1Word;
  6685.   int Flags2Word;
  6686.   int Flags3Word;
  6687.   int FORLIM1;
  6688.  
  6689.   if (FirstObj == 0 || LastObj == 0) {
  6690.     PrintString("No such object.");
  6691.     ChkWait();
  6692.     return;
  6693.   }
  6694.   OldDC_PageNo = DC_PageNo;
  6695.   OldDC_PageIndex = DC_PageIndex;
  6696.   for (ObjCnt = FirstObj; ObjCnt <= LastObj; ++ObjCnt) {
  6697.     ChkWait();
  6698.     CalcObjAdrs(ObjCnt, &DC_PageNo, &DC_PageIndex, 0);
  6699.     PrintString("ObjNo:");
  6700.     PrintWord(ObjCnt, 4);
  6701.     PrintString(" RecAdrs:");
  6702.     PrintByte(DC_PageNo, 2);
  6703.     PrintByte(DC_PageIndex, 2);
  6704.     Flags1Word = GetWordDC();
  6705.     Flags2Word = GetWordDC();
  6706.     if (CodeVersion < '4') {
  6707.       Flags3Word = 0;
  6708.       InsideObj = GetByteDC();
  6709.       NextObj = GetByteDC();
  6710.       ContainsObj = GetByteDC();
  6711.     } else {
  6712.       Flags3Word = GetWordDC();
  6713.       InsideObj = GetWordDC();
  6714.       NextObj = GetWordDC();
  6715.       ContainsObj = GetWordDC();
  6716.     }
  6717.     NamePageNo = GetByteDC();
  6718.     NameIndex = GetByteDC();
  6719.     DC_PageNo = NamePageNo;
  6720.     DC_PageIndex = NameIndex;
  6721.     NameLength = GetByteDC();
  6722.     PrintString(" PTO:");
  6723.     PrintWord(InsideObj, 4);
  6724.     PrintString(" NXO:");
  6725.     PrintWord(NextObj, 4);
  6726.     PrintString(" FSO:");
  6727.     PrintWord(ContainsObj, 4);
  6728.     PrintString(" NameLen:");
  6729.     PrintByte(NameLength, 2);
  6730.     PrintString(" DataPtr:");
  6731.     PrintByte(NamePageNo, 2);
  6732.     PrintByte(NameIndex, 2);
  6733.     if (Flags1Word != 0 || Flags2Word != 0 || Flags3Word != 0) {
  6734.       ChkWait();
  6735.       PrintString("Flags set:");
  6736.       FORLIM1 = (CodeVersion >= '4') * 16 + 31;
  6737.       for (FlagCnt = 0; FlagCnt <= FORLIM1; ++FlagCnt) {
  6738.         if (TestFlag(ObjCnt, FlagCnt))
  6739.           PrintByte(FlagCnt, 3);
  6740.       }
  6741.     }
  6742.     ChkWait();
  6743.     if (NameLength > 0) {
  6744.       WriteText('N', OntoScreen, FromDC, GlobalTextBuffer);
  6745.     } else {
  6746.       PrintString("<no name>");
  6747.       ChkWait();
  6748.     }
  6749.     if (WithData) {
  6750.       DataCnt = 0;
  6751.       DataNo = GetPropertyNo(DC_PageNo, DC_PageIndex);
  6752.       while (DataNo != 0) {
  6753.         if (DataCnt % 6 == 0) {
  6754.           if (DataCnt != 0)
  6755.             ChkWait();
  6756.           PrintCh('D');
  6757.           PrintWord(DC_PageNo, 5);
  6758.           PrintByte(DC_PageIndex, 2);
  6759.           PrintCh(':');
  6760.         }
  6761.         PrintString(" #");
  6762.         PrintByte(DataNo, 2);
  6763.         DataSize = GetPropertySize(&DC_PageNo, &DC_PageIndex, true);
  6764.         Inc(&DC_PageNo, &DC_PageIndex, 1);
  6765.         if (DataSize == 1) {
  6766.           DataValue = GetByteDC();
  6767.           PrintByte(DataValue, 3);
  6768.         } else if (DataSize == 2) {
  6769.           DataValue = GetWordDC();
  6770.           PrintWord(DataValue, 5);
  6771.         } else {
  6772.           ByteCnt = 0;
  6773.           PrintCh(' ');
  6774.           while (ByteCnt < DataSize) {
  6775.             DataValue = GetByteDC();
  6776.             PrintByte(DataValue, 2);
  6777.             ++ByteCnt;
  6778.           }
  6779.         }
  6780.         ++DataCnt;
  6781.         DataNo = GetPropertyNo(DC_PageNo, DC_PageIndex);
  6782.       }
  6783.       ChkWait();
  6784.     }
  6785.   }
  6786.   DC_PageNo = OldDC_PageNo;
  6787.   DC_PageIndex = OldDC_PageIndex;
  6788. }  /* DispObject */
  6789.  
  6790.  
  6791. Static void DumpData(boolean DoBytes) {
  6792.   int CodePageNo;
  6793.   int CodeIndex;
  6794.   int ItemCnt;
  6795.   int Value;
  6796.   boolean OldWriteDump;
  6797.   boolean FirstLine;
  6798.  
  6799.   OldWriteDump = WriteDump;
  6800.   WriteDump = false;
  6801.   CodePageNo = DC_PageNo;
  6802.   CodeIndex = DC_PageIndex;
  6803.   BackTxtPageNo = OldTextPageNo;
  6804.   BackTxtIndex = OldTextPageIndex;
  6805.   DC_PageNo = TextPageNo;
  6806.   DC_PageIndex = TextPageIndex;
  6807.   OldTextPageNo = TextPageNo;
  6808.   OldTextPageIndex = TextPageIndex;
  6809.   ItemCnt = 0;
  6810.   *Dump = '\0';
  6811.   FirstLine = true;
  6812.   do {
  6813.     if ((ItemCnt & 15) == 0) {
  6814.       if (!FirstLine) {
  6815.         PrintString(Dump);
  6816.         ChkWait();
  6817.       }
  6818.       strcpy(Dump, "D");
  6819.       WriteCh(Dump, ' ');
  6820.       FirstLine = false;
  6821.       AddWord(Dump, DC_PageNo);
  6822.       AddByte(Dump, DC_PageIndex);
  6823.       WriteCh(Dump, ':');
  6824.     }
  6825.     if (DoBytes) {
  6826.       Value = GetByteDC();
  6827.       DumpByte(Dump, Value);
  6828.     } else {
  6829.       Value = GetWordDC();
  6830.       WriteCh(Dump, ' ');
  6831.       AddWord(Dump, Value);
  6832.     }
  6833.     ItemCnt += 2 - DoBytes;
  6834.   } while (DC_PageNo <= EndPageNo &&
  6835.            (DC_PageNo != EndPageNo || DC_PageIndex <= EndPageIndex));
  6836.   PrintString(Dump);
  6837.   ChkWait();
  6838.   TextPageNo = DC_PageNo;
  6839.   TextPageIndex = DC_PageIndex;
  6840.   DC_PageNo = CodePageNo;
  6841.   DC_PageIndex = CodeIndex;
  6842.   WriteDump = OldWriteDump;
  6843. }  /* DumpData */
  6844.  
  6845.  
  6846. Static void QuickSort(int StartIndex, int EndIndex) {
  6847.   int Left;
  6848.   int Right;
  6849.   int Pivot;
  6850.   int Swap;
  6851.   int Shift;
  6852.  
  6853.   Shift = IntToCardConst;
  6854.   Left = StartIndex;
  6855.   Right = EndIndex;
  6856.   Pivot = EntryPoints[(Left + Right) / 2] + Shift;
  6857.   do {
  6858.     while (EntryPoints[Left] + Shift < Pivot)
  6859.       ++Left;
  6860.     while (EntryPoints[Right] + Shift > Pivot)
  6861.       --Right;
  6862.     if (Left <= Right) {
  6863.       if (Left < Right) {
  6864.         Swap = EntryPoints[Left];
  6865.         EntryPoints[Left] = EntryPoints[Right];
  6866.         EntryPoints[Right] = Swap;
  6867.       }
  6868.       ++Left;
  6869.       --Right;
  6870.     }
  6871.   } while (Right > Left);
  6872.   if (StartIndex < Right)
  6873.     QuickSort(StartIndex, Right);
  6874.   if (Left < EndIndex)
  6875.     QuickSort(Left, EndIndex);
  6876. }  /* QuickSort */
  6877.  
  6878.  
  6879. #define PointsPerLine   10
  6880.  
  6881.  
  6882. Static void DisplayEntryPoints(void) {
  6883.   int EntryCnt;
  6884.   int PageNo;
  6885.   int PageIndex;
  6886.   int NumOnLine;
  6887.  
  6888.   if (EntryIndex > 1)
  6889.     QuickSort(0, EntryIndex - 1);
  6890.   PrintString("Number of entry points:");
  6891.   PrintWord(EntryIndex, 5);
  6892.   ChkWait();
  6893.   EntryCnt = 0;
  6894.   NumOnLine = 0;
  6895.   while (EntryCnt < EntryIndex) {
  6896.     PageNo = 0;
  6897.     PageIndex = EntryPoints[EntryCnt];
  6898.     CalcCallAddress(EntryPoints[EntryCnt], &PageNo, &PageIndex);
  6899.     PrintWord(PageNo, 5);
  6900.     PrintByte(PageIndex, 2);
  6901.     ++NumOnLine;
  6902.     if (NumOnLine == PointsPerLine) {
  6903.       ChkWait();
  6904.       NumOnLine = 0;
  6905.     }
  6906.     ++EntryCnt;
  6907.   }
  6908.   if (NumOnLine != 0)
  6909.     ChkWait();
  6910. }  /* DisplayEntryPoints */
  6911.  
  6912. #undef PointsPerLine
  6913.  
  6914.  
  6915. Static void ListCommands(void) {
  6916.   ChkWait();
  6917.   PrintString("NewCmd        = N <StoryFileName>");
  6918.   ChkWait();
  6919.   PrintString("ExecutionCmd  = ( S|X|A ) [P] <AddressRange>");
  6920.   ChkWait();
  6921.   PrintString("BPT_Cmd       = B [P] [S|C] <Address> [<Number>]");
  6922.   ChkWait();
  6923.   PrintString("EntryPointCmd = E [C|D|N|Y]");
  6924.   ChkWait();
  6925.   PrintString("SimpleCmd     = Q | ? | H | $ | I[P][M|S] | V[P|A] | C[P]");
  6926.   ChkWait();
  6927.   PrintString("              | Z [P] [S|I|R|X]");
  6928.   ChkWait();
  6929.   PrintString("OptionCmd     = D ( (N|C|T|U) | ( (B|I|K|R|S|V) (Y|N|T|F) ) )");
  6930.   ChkWait();
  6931.   PrintString(
  6932.     "ObjCmd        = O [P] ( <AddressRange> | \"<string>\" [, <Address>] ) [#]");
  6933.   ChkWait();
  6934.   PrintString("ListCmd       = ( L | G | T ) [P] <AddressRange>");
  6935.   ChkWait();
  6936.   PrintString(
  6937.     "MemoryCmd     = ( M | W ) ( W | B ) [P] <AddressRange> {, <Number>}");
  6938.   ChkWait();
  6939.   PrintString("AddressRange  = [<Address> [. <Address>]]");
  6940.   ChkWait();
  6941.   PrintString("Address       = [&] [*] <Number> [W|G] | ~ | ^ | @");
  6942.   ChkWait();
  6943.   PrintString("Number        = <Hexdigit> {<Hexdigit>}");
  6944.   ChkWait();
  6945. }  /* ListCommands */
  6946.  
  6947.  
  6948. /* Local variables for LineInterpreter: */
  6949. struct LineInterpreter_LocalVariables {
  6950.   Char *CmdLine;
  6951.   Char WrkCh;
  6952.   int Index;
  6953.   int HexDigits[9];
  6954. } ;
  6955.  
  6956. Local void GetCh__(boolean Capitalize,
  6957.    struct LineInterpreter_LocalVariables *LineInterpreter_Vars) {
  6958.   if (LineInterpreter_Vars->Index >= strlen(LineInterpreter_Vars->CmdLine)) {
  6959.     LineInterpreter_Vars->WrkCh = EOL();
  6960.     return;
  6961.   }
  6962.   ++LineInterpreter_Vars->Index;
  6963.   LineInterpreter_Vars->WrkCh =
  6964.     LineInterpreter_Vars->CmdLine[LineInterpreter_Vars->Index - 1];
  6965.   while (LineInterpreter_Vars->WrkCh == ' ' && Capitalize)
  6966.     GetCh__(true, LineInterpreter_Vars);
  6967.   if (islower(LineInterpreter_Vars->WrkCh) && Capitalize)
  6968.     LineInterpreter_Vars->WrkCh = _toupper(LineInterpreter_Vars->WrkCh);
  6969. }  /* GetCh */
  6970.  
  6971. Local void GetAddress(int *PageNo, int *PageIndex, int OldPageNo,
  6972.   int OldIndex, int BackPageNo, int BackIndex,
  6973.   struct LineInterpreter_LocalVariables *LineInterpreter_Vars) {
  6974.   int ChCnt;
  6975.   boolean DataRelative;
  6976.   boolean Indirect;
  6977.   int Page2No;
  6978.   int Page2Index;
  6979.   anAddrString AddrString;
  6980.   anAddrString AddrPart;
  6981.   int SET[3];
  6982.   int SET1[9];
  6983.  
  6984.   if (LineInterpreter_Vars->WrkCh == '~' || LineInterpreter_Vars->WrkCh == '/') {
  6985.     *PageNo = OldPageNo;
  6986.     *PageIndex = OldIndex;
  6987.     GetCh__(true, LineInterpreter_Vars);
  6988.   } else if (LineInterpreter_Vars->WrkCh == '^' ||
  6989.              LineInterpreter_Vars->WrkCh == '<') {
  6990.     *PageNo = BackPageNo;
  6991.     *PageIndex = BackIndex;
  6992.     GetCh__(true, LineInterpreter_Vars);
  6993.   } else if (LineInterpreter_Vars->WrkCh == '@') {
  6994.     *PageNo = MiscInfo.StartPageNo;
  6995.     *PageIndex = MiscInfo.StartIndex;
  6996.     GetCh__(true, LineInterpreter_Vars);
  6997.   } else {
  6998.     P_addset(P_expset(SET, 0), '*');
  6999.     if (P_inset(LineInterpreter_Vars->WrkCh,
  7000.                 P_setunion(SET1, LineInterpreter_Vars->HexDigits,
  7001.                            P_addset(SET, '&')))) {
  7002.       Indirect = (LineInterpreter_Vars->WrkCh == '&');
  7003.       if (Indirect)
  7004.         GetCh__(true, LineInterpreter_Vars);
  7005.       DataRelative = (LineInterpreter_Vars->WrkCh == '*');
  7006.       if (DataRelative)
  7007.         GetCh__(true, LineInterpreter_Vars);
  7008.       *AddrString = '\0';
  7009.       ChCnt = 0;
  7010.       while (P_inset(LineInterpreter_Vars->WrkCh,
  7011.                      LineInterpreter_Vars->HexDigits)) {
  7012.         ++ChCnt;
  7013.         AddrString[ChCnt - 1] = LineInterpreter_Vars->WrkCh;
  7014.         GetCh__(true, LineInterpreter_Vars);
  7015.       }
  7016.       SetLength(AddrString, ChCnt);
  7017.       while (strlen(AddrString) < 6)
  7018.         strinsert("0", (void *)AddrString, 1);
  7019.       sprintf(AddrPart, "%.4s", AddrString);
  7020.       StringToNumber(PageNo, AddrPart);
  7021.       strsub(AddrPart, AddrString, 5, 2);
  7022.       StringToNumber(PageIndex, AddrPart);
  7023.       if (DataRelative) {
  7024.         *PageIndex += MiscInfo.DataPageIndex;
  7025.         *PageNo += MiscInfo.DataPageNo;
  7026.         ChkAddress(PageNo, PageIndex);
  7027.       }
  7028.       if (Indirect) {
  7029.         Push(DC_PageNo);
  7030.         Push(DC_PageIndex);
  7031.         DC_PageNo = *PageNo;
  7032.         DC_PageIndex = *PageIndex;
  7033.         *PageNo = GetByteDC();
  7034.         *PageIndex = GetByteDC();
  7035.         DC_PageIndex = Pop();
  7036.         DC_PageNo = Pop();
  7037.       }
  7038.       if (LineInterpreter_Vars->WrkCh == 'W') {
  7039.         GetCh__(true, LineInterpreter_Vars);
  7040.         *PageNo *= 2;
  7041.         *PageIndex *= 2;
  7042.         ChkAddress(PageNo, PageIndex);
  7043.       } else if (LineInterpreter_Vars->WrkCh == 'Q') {
  7044.         GetCh__(true, LineInterpreter_Vars);
  7045.         *PageNo *= 4;
  7046.         *PageIndex *= 4;
  7047.         ChkAddress(PageNo, PageIndex);
  7048.       } else if (LineInterpreter_Vars->WrkCh == 'G') {
  7049.         GetCh__(true, LineInterpreter_Vars);
  7050.         CalcCallAddress(JoinBytes(*PageIndex, *PageNo), PageNo, PageIndex);
  7051.       }
  7052.     } else {
  7053.       *PageNo = OldPageNo;
  7054.       *PageIndex = OldIndex;
  7055.     }
  7056.   }
  7057.   if (LineInterpreter_Vars->WrkCh != '+')
  7058.     return;
  7059.   GetCh__(true, LineInterpreter_Vars);
  7060.   GetAddress(&Page2No, &Page2Index, OldPageNo, OldIndex, BackPageNo,
  7061.              BackIndex, LineInterpreter_Vars);
  7062.   *PageNo += Page2No;
  7063.   *PageIndex += Page2Index;
  7064.   ChkAddress(PageNo, PageIndex);
  7065. }  /* GetAddress */
  7066.  
  7067. Local void GetRange(int *StartPageNo, int *StartIndex, int *EndPageNo,
  7068.                     int *EndPageIndex, int OldPageNo, int OldIndex,
  7069.                     int BackPageNo, int BackIndex,
  7070.                     struct LineInterpreter_LocalVariables *LineInterpreter_Vars) {
  7071.   int SET[5];
  7072.   int SET1[9];
  7073.  
  7074.   P_addset(P_expset(SET, 0), '*');
  7075.   P_addset(SET, '&');
  7076.   P_addset(SET, '@');
  7077.   P_addset(SET, '~');
  7078.   P_addset(SET, '^');
  7079.   P_addset(SET, '/');
  7080.   if (!P_inset(LineInterpreter_Vars->WrkCh,
  7081.                P_setunion(SET1, LineInterpreter_Vars->HexDigits,
  7082.                           P_addset(SET, '<'))))
  7083.     return;
  7084.   GetAddress(StartPageNo, StartIndex, OldPageNo, OldIndex, BackPageNo,
  7085.              BackIndex, LineInterpreter_Vars);
  7086.   if (LineInterpreter_Vars->WrkCh != '.') {
  7087.     *EndPageNo = -1;
  7088.     *EndPageIndex = -1;
  7089.     return;
  7090.   }
  7091.   GetCh__(true, LineInterpreter_Vars);
  7092.   if (LineInterpreter_Vars->WrkCh == '.')
  7093.     GetCh__(true, LineInterpreter_Vars);
  7094.   GetAddress(EndPageNo, EndPageIndex, OldPageNo, OldIndex, BackPageNo,
  7095.              BackIndex, LineInterpreter_Vars);
  7096. }  /* GetRange */
  7097.  
  7098. Local void GetString(Char theString[256], boolean SpacesAllowed,
  7099.    CharSet Terminators,
  7100.    struct LineInterpreter_LocalVariables *LineInterpreter_Vars) {
  7101.   int ChrCnt;
  7102.  
  7103.   *theString = '\0';
  7104.   ChrCnt = 0;
  7105.   while (!P_inset(LineInterpreter_Vars->WrkCh, Terminators)) {
  7106.     if (LineInterpreter_Vars->WrkCh != ' ' || SpacesAllowed) {
  7107.       ++ChrCnt;
  7108.       SetLength(theString, ChrCnt);
  7109.       theString[ChrCnt - 1] = LineInterpreter_Vars->WrkCh;
  7110.     }
  7111.     GetCh__(false, LineInterpreter_Vars);
  7112.   }
  7113.   GetCh__(true, LineInterpreter_Vars);
  7114. }  /* GetString */
  7115.  
  7116. Local void SetDumpState(Char DumpChr,
  7117.    struct LineInterpreter_LocalVariables *LineInterpreter_Vars) {
  7118.   boolean ToValue;
  7119.  
  7120.   if (DumpChr == 'O' || DumpChr == 'F' || DumpChr == 'V' || DumpChr == 'S' ||
  7121.       DumpChr == 'R' || DumpChr == 'K' || DumpChr == 'I' || DumpChr == 'B') {
  7122.     GetCh__(true, LineInterpreter_Vars);
  7123.     if (LineInterpreter_Vars->WrkCh == 'T' ||
  7124.         LineInterpreter_Vars->WrkCh == 'Y') {
  7125.       ToValue = true;
  7126.     } else if (LineInterpreter_Vars->WrkCh == 'F' ||
  7127.                LineInterpreter_Vars->WrkCh == 'N')
  7128.       ToValue = false;
  7129.     else
  7130.       HandleError(false, "Y, N, T or F expected after switch character.",
  7131.                   false);
  7132.   }
  7133.   switch (DumpChr) {
  7134.  
  7135.   case 'B':
  7136.     DisBPTs = ToValue;
  7137.     break;
  7138.  
  7139.   case 'C':
  7140.     GlobalDumpState = CodeDump;
  7141.     break;
  7142.  
  7143.   case 'F':
  7144.     FaultNotImplemented = ToValue;
  7145.     break;
  7146.  
  7147.   case 'I':
  7148.     DisWithIds = ToValue;
  7149.     break;
  7150.  
  7151.   case 'K':
  7152.     CrashInternal = ToValue;
  7153.     break;
  7154.  
  7155.   case 'N':
  7156.     GlobalDumpState = NoDump;
  7157.     break;
  7158.  
  7159.   case 'O':
  7160.     RestartOperations = ToValue;
  7161.     break;
  7162.  
  7163.   case 'R':
  7164.     TryRegList = ToValue;
  7165.     break;
  7166.  
  7167.   case 'S':
  7168.     if (!Statistics && ToValue)
  7169.       InitExecCnt();
  7170.     Statistics = ToValue;
  7171.     break;
  7172.  
  7173.   case 'T':
  7174.     GlobalDumpState = TextDump;
  7175.     break;
  7176.  
  7177.   case 'U':
  7178.     GlobalDumpState = UnpackedDump;
  7179.     break;
  7180.  
  7181.   case 'V':
  7182.     DebugVocab = ToValue;
  7183.     break;
  7184.  
  7185.   default:
  7186.     RingBell();
  7187.     break;
  7188.   }
  7189.   WriteDump = (GlobalDumpState != NoDump);
  7190. }  /* SetDumpState */
  7191.  
  7192. Local void ModifyData(boolean DoBytes, int ModPageNo, int ModPageIndex,
  7193.    struct LineInterpreter_LocalVariables *LineInterpreter_Vars) {
  7194.   int High;
  7195.   int Low;
  7196.  
  7197.   GetCh__(true, LineInterpreter_Vars);
  7198.   High = 0;
  7199.   Low = 0;
  7200.   while (LineInterpreter_Vars->WrkCh == ',' ||
  7201.          LineInterpreter_Vars->WrkCh == ' ' ||
  7202.          LineInterpreter_Vars->WrkCh == '^' ||
  7203.          LineInterpreter_Vars->WrkCh == '~' ||
  7204.          LineInterpreter_Vars->WrkCh == '&' ||
  7205.          LineInterpreter_Vars->WrkCh == '*' ||
  7206.          isupper(LineInterpreter_Vars->WrkCh) ||
  7207.          isdigit(LineInterpreter_Vars->WrkCh)) {
  7208.     if (LineInterpreter_Vars->WrkCh == ',')
  7209.       GetCh__(true, LineInterpreter_Vars);
  7210.     GetAddress(&High, &Low, High, Low, High, Low, LineInterpreter_Vars);
  7211.     if (!DoBytes) {
  7212.       PrintWord(ModPageNo, 4);
  7213.       PrintByte(ModPageIndex, 2);
  7214.       PrintCh(':');
  7215.       PrintByte(High, 3);
  7216.       ChkWait();
  7217.       PagePtrs[ModPageNo][ModPageIndex] = High;
  7218.       Inc(&ModPageNo, &ModPageIndex, 1);
  7219.     }
  7220.     PrintWord(ModPageNo, 4);
  7221.     PrintByte(ModPageIndex, 2);
  7222.     PrintCh(':');
  7223.     PrintByte(Low, 3);
  7224.     ChkWait();
  7225.     PagePtrs[ModPageNo][ModPageIndex] = Low;
  7226.     Inc(&ModPageNo, &ModPageIndex, 1);
  7227.   }
  7228. }  /* ModifyData */
  7229.  
  7230. Local void HandleListObject(struct LineInterpreter_LocalVariables *LineInterpreter_Vars) {
  7231.   int OldHigh;
  7232.   int OldLow;
  7233.   int BackHigh;
  7234.   int BackLow;
  7235.   Char ObjectName[256];
  7236.   int SET[9];
  7237.  
  7238.   do {
  7239.     if (LineInterpreter_Vars->WrkCh == ',')
  7240.       GetCh__(true, LineInterpreter_Vars);
  7241.     OldHigh = FirstHigh;
  7242.     OldLow = FirstObj;
  7243.     BackHigh = FirstHigh;
  7244.     BackLow = FirstObj;
  7245.     if (BackHigh > 0 || BackLow > 0)
  7246.       Inc(&BackHigh, &BackLow, -1);
  7247.     Inc(&FirstHigh, &FirstObj, 1);
  7248.     if (LineInterpreter_Vars->WrkCh == '"') {
  7249.       GetCh__(false, LineInterpreter_Vars);
  7250.       P_addset(P_expset(SET, 0), '"');
  7251.       GetString(ObjectName, true, P_addset(SET, EOL()), LineInterpreter_Vars);
  7252.       if (LineInterpreter_Vars->WrkCh == ',')
  7253.         GetCh__(true, LineInterpreter_Vars);
  7254.       GetAddress(&LastHigh, &LastObj, OldHigh, OldLow, BackHigh, BackLow,
  7255.                  LineInterpreter_Vars);
  7256.       LastObj += LastHigh * 256;
  7257.       FirstObj = FindObject(LastObj, ObjectName);
  7258.       LastObj = FirstObj;
  7259.       FirstHigh = 0;
  7260.       LastHigh = 0;
  7261.     } else {
  7262.       GetRange(&FirstHigh, &FirstObj, &LastHigh, &LastObj, OldHigh, OldLow,
  7263.                BackHigh, BackLow, LineInterpreter_Vars);
  7264.       FirstObj += FirstHigh * 256;
  7265.       LastObj += LastHigh * 256;
  7266.     }
  7267.     if (LastObj < 0)
  7268.       LastObj = FirstObj;
  7269.     if (LineInterpreter_Vars->WrkCh == '#') {
  7270.       GetCh__(true, LineInterpreter_Vars);
  7271.       DispObject(FirstObj, LastObj, true);
  7272.     } else {
  7273.       DispObject(FirstObj, LastObj, false);
  7274.     }
  7275.   } while (LineInterpreter_Vars->WrkCh == ',');   /* HandleListObject */
  7276. }
  7277.  
  7278. Local void HandleListEntryPoints(struct LineInterpreter_LocalVariables *LineInterpreter_Vars) {
  7279.   int EntryPageNo;
  7280.   int EntryIdx;
  7281.  
  7282.   if (LineInterpreter_Vars->WrkCh == 'C') {
  7283.     EntryIndex = 0;
  7284.     return;
  7285.   }
  7286.   if (LineInterpreter_Vars->WrkCh == 'D') {
  7287.     do {
  7288.       GetCh__(true, LineInterpreter_Vars);
  7289.       GetAddress(&EntryPageNo, &EntryIdx, EntryPageNo, EntryIdx, EntryPageNo,
  7290.                  EntryIdx, LineInterpreter_Vars);
  7291.       RemoveEntry(EntryPageNo, EntryIdx);
  7292.     } while (LineInterpreter_Vars->WrkCh == ',');
  7293.     return;
  7294.   }
  7295.   if (LineInterpreter_Vars->WrkCh == 'Y') {
  7296.     SaveEntryPoints = true;
  7297.     return;
  7298.   }
  7299.   if (LineInterpreter_Vars->WrkCh == 'N')
  7300.     SaveEntryPoints = false;
  7301.   else
  7302.     DisplayEntryPoints();
  7303. }  /* HandleListEntryPoints */
  7304.  
  7305. Local void HandleZState(struct LineInterpreter_LocalVariables *LineInterpreter_Vars) {
  7306.   if (LineInterpreter_Vars->WrkCh == 'I') {
  7307.     ResetZMachine();
  7308.     PrintZState();
  7309.     return;
  7310.   }
  7311.   if (LineInterpreter_Vars->WrkCh == 'R') {
  7312.     ReloadData();
  7313.     ResetZMachine();
  7314.     PrintZState();
  7315.     return;
  7316.   }
  7317.   if (LineInterpreter_Vars->WrkCh == 'X') {
  7318.     ReloadData();
  7319.     ResetZMachine();
  7320.     StartZMachine(Run);
  7321.     return;
  7322.   }
  7323.   if (LineInterpreter_Vars->WrkCh == 'S')
  7324.     PrintZState();
  7325.   else
  7326.     RingBell();
  7327. }  /* HandleZState */
  7328.  
  7329. /* Local variables for ListStatistics: */
  7330. struct ListStatistics_LocalVariables {
  7331.   struct LineInterpreter_LocalVariables *LineInterpreter_Vars;
  7332.   CountArray Cnts;
  7333.   CountArray Cdes;
  7334. } ;
  7335.  
  7336. Local void QuickSort_(int StartIndex, int EndIndex,
  7337.    struct ListStatistics_LocalVariables *ListStatistics_Vars) {
  7338.   int Left;
  7339.   int Right;
  7340.   int Pivot;
  7341.   int Swap;
  7342.  
  7343.   Left = StartIndex;
  7344.   Right = EndIndex;
  7345.   Pivot = ListStatistics_Vars->Cnts[(Left + Right) / 2];
  7346.   do {
  7347.     while (ListStatistics_Vars->Cnts[Left] < Pivot)
  7348.       ++Left;
  7349.     while (ListStatistics_Vars->Cnts[Right] > Pivot)
  7350.       --Right;
  7351.     if (Left <= Right) {
  7352.       if (Left < Right) {
  7353.         Swap = ListStatistics_Vars->Cnts[Left];
  7354.         ListStatistics_Vars->Cnts[Left] = ListStatistics_Vars->Cnts[Right];
  7355.         ListStatistics_Vars->Cnts[Right] = Swap;
  7356.         Swap = ListStatistics_Vars->Cdes[Left];
  7357.         ListStatistics_Vars->Cdes[Left] = ListStatistics_Vars->Cdes[Right];
  7358.         ListStatistics_Vars->Cdes[Right] = Swap;
  7359.       }
  7360.       ++Left;
  7361.       --Right;
  7362.     }
  7363.   } while (Right > Left);
  7364.   if (StartIndex < Right)
  7365.     QuickSort_(StartIndex, Right, ListStatistics_Vars);
  7366.   if (Left < EndIndex)
  7367.     QuickSort_(Left, EndIndex, ListStatistics_Vars);
  7368. }  /* QuickSort */
  7369.  
  7370. Local void ListStatistics(struct LineInterpreter_LocalVariables *LineInterpreter_Vars) {
  7371.   struct ListStatistics_LocalVariables V;
  7372.   int Index;
  7373.   int SpaceCnt;
  7374.   int StartX;
  7375.   int FORLIM1;
  7376.  
  7377.   V.LineInterpreter_Vars = LineInterpreter_Vars;
  7378.   memcpy(V.Cnts, ExecCnt, signedsizeof(CountArray));
  7379.   for (Index = 0; Index <= 255; ++Index)
  7380.     V.Cdes[Index] = Index;
  7381.   QuickSort_(0, 255, &V);
  7382.   for (Index = 255; Index >= 0; --Index) {
  7383.     if (V.Cnts[Index] > 0) {
  7384.       StartX = CursorX;
  7385.       PrintInteger(V.Cnts[Index]);
  7386.       FORLIM1 = StartX - CursorX + 7;
  7387.       for (SpaceCnt = 1; SpaceCnt <= FORLIM1; ++SpaceCnt)
  7388.         PrintCh(' ');
  7389.       CmdCode = V.Cdes[Index];
  7390.       Disassemble(1, false);
  7391.     }
  7392.   }
  7393. }  /* ListStatistics */
  7394.  
  7395.  
  7396. Static void LineInterpreter(char *Cmd, Char CmdLine_[256]) {
  7397.   /*VAR Cmd:Commands; VAR CmdLine:aMaxString*/
  7398.   struct LineInterpreter_LocalVariables V;
  7399.   int UnusedHigh;
  7400.   boolean NewAdvOk;
  7401.   int SET[9];
  7402.  
  7403.   V.CmdLine = CmdLine_;
  7404.   P_addsetr(P_expset(V.HexDigits, 0), '0', '9');
  7405.   P_addsetr(V.HexDigits, 'A', 'F');
  7406.   V.Index = 0;
  7407.   do {
  7408.     *Cmd = Nothing;
  7409.     EndPageNo = -1;
  7410.     EndPageIndex = -1;
  7411.     EndIPC_PageNo = -1;
  7412.     EndIPC_PageIndex = -1;
  7413.     GetCh__(true, &V);
  7414.     if (V.WrkCh != EOL()) {
  7415.       switch (V.WrkCh) {
  7416.  
  7417.       case 'W':
  7418.         GetCh__(true, &V);
  7419.         if (V.WrkCh == 'W') {
  7420.           *Cmd = DumpWords;
  7421.         } else if (V.WrkCh == 'B')
  7422.           *Cmd = cDumpBytes;
  7423.         else
  7424.           *Cmd = Nothing;
  7425.         break;
  7426.  
  7427.       case 'M':
  7428.         GetCh__(true, &V);
  7429.         if (V.WrkCh == 'W') {
  7430.           *Cmd = ModifyWords;
  7431.         } else if (V.WrkCh == 'B')
  7432.           *Cmd = ModifyBytes;
  7433.         break;
  7434.  
  7435.       case 'B':
  7436.         *Cmd = BPT_Cmd;
  7437.         break;
  7438.  
  7439.       case 'Q':
  7440.         *Cmd = Quit;
  7441.         break;
  7442.  
  7443.       case 'E':
  7444.         *Cmd = ListEntryPoints;
  7445.         break;
  7446.  
  7447.       case 'C':
  7448.         *Cmd = ListCalls;
  7449.         break;
  7450.  
  7451.       case '?':
  7452.       case 'H':
  7453.         *Cmd = Help;
  7454.         break;
  7455.  
  7456.       case 'D':
  7457.         *Cmd = DumpOption;
  7458.         break;
  7459.  
  7460.       case 'I':
  7461.         *Cmd = Info;
  7462.         break;
  7463.  
  7464.       case 'N':
  7465.         *Cmd = NewAdv;
  7466.         break;
  7467.  
  7468.       case 'L':
  7469.         *Cmd = List;
  7470.         break;
  7471.  
  7472.       case 'T':
  7473.         *Cmd = TextList;
  7474.         break;
  7475.  
  7476.       case 'A':
  7477.         *Cmd = Trace;
  7478.         break;
  7479.  
  7480.       case 'G':
  7481.         *Cmd = GoSub;
  7482.         break;
  7483.  
  7484.       case 'O':
  7485.         *Cmd = ListObject;
  7486.         break;
  7487.  
  7488.       case 'V':
  7489.         *Cmd = ListVocabulary;
  7490.         break;
  7491.  
  7492.       case 'S':
  7493.         *Cmd = Step;
  7494.         break;
  7495.  
  7496.       case 'X':
  7497.         *Cmd = Run;
  7498.         break;
  7499.  
  7500.       case '$':
  7501.         *Cmd = VerifyCode;
  7502.         break;
  7503.  
  7504.       case 'Z':
  7505.         *Cmd = ListZState;
  7506.         break;
  7507.  
  7508.       case 'R':
  7509.         *Cmd = ListReg;
  7510.         break;
  7511.  
  7512.       default:
  7513.         *Cmd = Nothing;
  7514.         break;
  7515.       }
  7516.       GetCh__(*Cmd != NewAdv, &V);
  7517.       PrintListing = false;
  7518.       if (((1 << (*Cmd)) & ((1 << List) | (1 << TextList) | (1 << GoSub) |
  7519.               (1 << ListEntryPoints) | (1 << ListObject) | (1 <<
  7520.                 ListVocabulary) | (1 << cDumpBytes) | (1 << DumpWords) |
  7521.               (1 << Info) | (1 << ListZState) | (1 << ListReg) | (1 << Step) |
  7522.               (1 << Trace) | (1 << Run) | (1 << BPT_Cmd) |
  7523.               (1 << ModifyBytes) | (1 << ModifyWords) | (1 << Help) |
  7524.               (1 << ListCalls))) != 0) {
  7525.         if (V.WrkCh == 'P') {
  7526.           PreparePrinter();
  7527.           GetCh__(true, &V);
  7528.         }
  7529.       }
  7530.       if (*Cmd == Nothing)
  7531.         RingBell();
  7532.     }
  7533.     if (PageCnt == 0) {
  7534.       if (((1 << (*Cmd)) & ((1 << NewAdv) | (1 << DumpOption) | (1 << Help) |
  7535.                             (1 << Quit))) == 0) {
  7536.         PrintString("No story loaded.");
  7537.         RingBell();
  7538.         ChkWait();
  7539.         goto _L666;
  7540.       }
  7541.     }
  7542.     switch (*Cmd) {
  7543.  
  7544.     case Quit:
  7545.       /* blank case */
  7546.       break;
  7547.  
  7548.     case ListZState:
  7549.       HandleZState(&V);
  7550.       break;
  7551.  
  7552.     case ListReg:
  7553.       GetAddress(&UnusedHigh, &RegNo, UnusedHigh, RegNo, UnusedHigh,
  7554.                  RegNo - 1, &V);
  7555.       PrintReg(RegNo);
  7556.       ChkWait();
  7557.       break;
  7558.  
  7559.     case VerifyCode:
  7560.       VerifyCommand();
  7561.       break;
  7562.  
  7563.     case NewAdv:
  7564.       NewAdvOk = false;
  7565.       GetString(StoryName, false, P_addset(P_expset(SET, 0), EOL()), &V);
  7566.       if ((*StoryName == '\0') | IsDirectory(StoryName))
  7567.         strcat(StoryName, "story.dat");
  7568.       NewAdvOk = true;
  7569.       LoadStory();
  7570.       break;
  7571.  
  7572.     case Info:
  7573.       if (V.WrkCh == 'S')
  7574.         ListStatistics(&V);
  7575.       else
  7576.         ListMiscInfo();
  7577.       break;
  7578.  
  7579.     case ListCalls:
  7580.       CallBacktrace();
  7581.       break;
  7582.  
  7583.     case ListVocabulary:
  7584.       DisplayVocabulary(V.WrkCh == 'A');
  7585.       break;
  7586.  
  7587.     case DumpOption:
  7588.       do {
  7589.         if (V.WrkCh == ',')
  7590.           GetCh__(true, &V);
  7591.         SetDumpState(V.WrkCh, &V);
  7592.         GetCh__(true, &V);
  7593.       } while (V.WrkCh == ',');
  7594.       break;
  7595.  
  7596.     case Help:
  7597.       ListCommands();
  7598.       break;
  7599.  
  7600.     case cDumpBytes:
  7601.     case DumpWords:
  7602.     case ModifyWords:
  7603.     case ModifyBytes:
  7604.       do {
  7605.         if (V.WrkCh == ',')
  7606.           GetCh__(true, &V);
  7607.         GetRange(&TextPageNo, &TextPageIndex, &EndPageNo, &EndPageIndex,
  7608.                  OldTextPageNo, OldTextPageIndex, BackTxtPageNo, BackTxtIndex,
  7609.                  &V);
  7610.         if (((1 << (*Cmd)) & ((1 << ModifyWords) | (1 << ModifyBytes))) != 0)
  7611.           ModifyData(*Cmd == ModifyBytes, TextPageNo, TextPageIndex, &V);
  7612.         else
  7613.           DumpData(*Cmd == cDumpBytes);
  7614.       } while (V.WrkCh == ',');
  7615.       break;
  7616.  
  7617.     case List:
  7618.       do {
  7619.         if (V.WrkCh == ',')
  7620.           GetCh__(true, &V);
  7621.         GetRange(&DC_PageNo, &DC_PageIndex, &EndPageNo, &EndPageIndex,
  7622.                  OldPageNo, OldIndex, BackPageNo, BackIndex, &V);
  7623.         Disassemble(ScreenHeight - 5, true);
  7624.       } while (V.WrkCh == ',');
  7625.       break;
  7626.  
  7627.     case Step:
  7628.       GetRange(&IPC_PageNo, &IPC_PageIndex, &EndIPC_PageNo, &EndIPC_PageIndex,
  7629.                OldIPC_PageNo, OldIPC_PageIndex, BackIPC_PageNo,
  7630.                BackIPC_PageIndex, &V);
  7631.       StepCommand();
  7632.       break;
  7633.  
  7634.     case Trace:
  7635.       GetRange(&IPC_PageNo, &IPC_PageIndex, &EndIPC_PageNo, &EndIPC_PageIndex,
  7636.                OldIPC_PageNo, OldIPC_PageIndex, BackIPC_PageNo,
  7637.                BackIPC_PageIndex, &V);
  7638.       TraceCommand();
  7639.       break;
  7640.  
  7641.     case Run:
  7642.       GetRange(&IPC_PageNo, &IPC_PageIndex, &EndIPC_PageNo, &EndIPC_PageIndex,
  7643.                OldIPC_PageNo, OldIPC_PageIndex, BackIPC_PageNo,
  7644.                BackIPC_PageIndex, &V);
  7645.       RunCommand(true, Run);
  7646.       break;
  7647.  
  7648.     case BPT_Cmd:
  7649.       if (V.WrkCh == 'S') {
  7650.         GetCh__(true, &V);
  7651.         BPT_PageNo = IPC_PageNo;
  7652.         BPT_PageIndex = IPC_PageIndex;
  7653.         GetAddress(&BPT_PageNo, &BPT_PageIndex, OldIPC_PageNo,
  7654.                    OldIPC_PageIndex, BackIPC_PageNo, BackIPC_PageIndex, &V);
  7655.         BPT_No = BPT_IdCnt;
  7656.         GetAddress(&UnusedHigh, &BPT_No, UnusedHigh, BPT_No, UnusedHigh,
  7657.                    BPT_No, &V);
  7658.         SetBPT(BPT_No, BPT_PageNo, BPT_PageIndex, UserBPT);
  7659.       } else if (V.WrkCh == 'C') {
  7660.         GetCh__(true, &V);
  7661.         GetAddress(&UnusedHigh, &BPT_No, UnusedHigh, BPT_No, UnusedHigh,
  7662.                    BPT_No - 1, &V);
  7663.         ClearBPT(BPT_No);
  7664.       } else {
  7665.         PrintBPTs();
  7666.       }
  7667.       break;
  7668.  
  7669.     case TextList:
  7670.       do {
  7671.         if (V.WrkCh == ',')
  7672.           GetCh__(true, &V);
  7673.         GetRange(&TextPageNo, &TextPageIndex, &EndPageNo, &EndPageIndex,
  7674.                  OldTextPageNo, OldTextPageIndex, BackTxtPageNo, BackTxtIndex,
  7675.                  &V);
  7676.         DisplayTextData();
  7677.       } while (V.WrkCh == ',');
  7678.       break;
  7679.  
  7680.     case GoSub:
  7681.       do {
  7682.         if (V.WrkCh == ',')
  7683.           GetCh__(true, &V);
  7684.         GetRange(&DC_PageNo, &DC_PageIndex, &EndPageNo, &EndPageIndex,
  7685.                  OldPageNo, OldIndex, BackPageNo, BackIndex, &V);
  7686.         EnterSubroutine();
  7687.       } while (V.WrkCh == ',');
  7688.       break;
  7689.  
  7690.     case ListEntryPoints:
  7691.       HandleListEntryPoints(&V);
  7692.       break;
  7693.  
  7694.     case ListObject:
  7695.       HandleListObject(&V);
  7696.       break;
  7697.     }
  7698.   } while (V.WrkCh != EOL());
  7699. _L666: ;
  7700. }  /* LineInterpreter */
  7701.  
  7702.  
  7703. Static void Initialize(void) {
  7704.   int Cnt;
  7705.  
  7706.   InitSystem();
  7707.   for (Cnt = 0; Cnt <= MaxPageNo; ++Cnt) {
  7708.     PagePtrs[Cnt] = NULL;
  7709.     DataPagePtrs[Cnt] = NULL;
  7710.   }
  7711.   ExitKey = ESC();
  7712.   BreakKey = '\002';
  7713.   PrinterTried = false;
  7714.   PrinterOpen = false;
  7715.   PrintListing = false;
  7716.   InitScreen();
  7717.   InStory = false;
  7718.   SetLength(Spaces, 255);
  7719.   for (Cnt = 1; Cnt <= 255; ++Cnt)
  7720.     Spaces[Cnt - 1] = ' ';
  7721.   memcpy(HexChars, "0123456789ABCDEF", 16);
  7722.   P_addset(P_expset(TerminatorSet, 0), '!');
  7723.   P_addset(TerminatorSet, '?');
  7724.   P_addset(TerminatorSet, ',');
  7725.   P_addset(TerminatorSet, '.');
  7726.   P_addset(TerminatorSet, ' ');
  7727.   WordNumChars = 6;
  7728.   memcpy(Char1Table, "0123456789.,!?_#'\"/\\|-:()", 25);
  7729.   P_addsetr(P_expset(Char1Set, 0), '0', '9');
  7730.   P_addset(Char1Set, '.');
  7731.   P_addset(Char1Set, ',');
  7732.   P_addset(Char1Set, '!');
  7733.   P_addset(Char1Set, '?');
  7734.   P_addset(Char1Set, '_');
  7735.   P_addset(Char1Set, '#');
  7736.   P_addset(Char1Set, '\'');
  7737.   P_addset(Char1Set, '"');
  7738.   P_addset(Char1Set, '/');
  7739.   P_addset(Char1Set, '\\');
  7740.   P_addset(Char1Set, '|');
  7741.   P_addset(Char1Set, '-');
  7742.   P_addset(Char1Set, ':');
  7743.   P_addset(Char1Set, '(');
  7744.   P_addset(Char1Set, ')');
  7745.   memcpy(Char23Table, "0123456789.,!?_#'\"/\\-:()", 24);
  7746.   P_addsetr(P_expset(Char23Set, 0), '0', '9');
  7747.   P_addset(Char23Set, '.');
  7748.   P_addset(Char23Set, ',');
  7749.   P_addset(Char23Set, '!');
  7750.   P_addset(Char23Set, '?');
  7751.   P_addset(Char23Set, '_');
  7752.   P_addset(Char23Set, '#');
  7753.   P_addset(Char23Set, '\'');
  7754.   P_addset(Char23Set, '"');
  7755.   P_addset(Char23Set, '/');
  7756.   P_addset(Char23Set, '\\');
  7757.   P_addset(Char23Set, '-');
  7758.   P_addset(Char23Set, ':');
  7759.   P_addset(Char23Set, '(');
  7760.   P_addset(Char23Set, ')');
  7761.   CmpShift = 0;   /* Pred(-MaxInt) */
  7762.   Randomize();
  7763.   WriteIndex = 0;
  7764.   ReadIndex = WriteIndex;
  7765.   PrintListing = false;
  7766.   PrintString("Infocom Interactive Fiction Debugger       Version [");
  7767.   PrintCh(HexChars[InterpreterNumber / 10]);
  7768.   PrintCh('.');
  7769.   PrintCh(HexChars[InterpreterNumber % 10]);
  7770.   PrintCh(InterpreterChar);
  7771.   PrintCh(']');
  7772.   PrintCh(' ');
  7773.   PrintCh(' ');
  7774.   PrintString(Date);
  7775.   ChkWait();
  7776.   ChkWait();
  7777.   PrintString("Written by Frank Lancaster during 1984-1993, Bonn, Germany.");
  7778.   ChkWait();
  7779.   ChkWait();
  7780.   PrintString("This programme is free. You may do anything with it.");
  7781.   ChkWait();
  7782.   ChkWait();
  7783.   PageCnt = 0;
  7784.   GlobalDumpState = NoDump;
  7785.   WriteDump = false;
  7786.   Statistics = false;
  7787.   DisBPTs = false;
  7788.   DisWithIds = false;
  7789.   RestartOperations = true;
  7790.   ChkLineChars = false;
  7791.   Opd.U1.s0 = 0;
  7792.   Opd.U1.s1 = 0;
  7793.   Opd.U1.s2 = 0;
  7794.   Opd.U1.s3 = 0;
  7795.   Opd.U1.s4 = 0;
  7796.   Opd.U1.s5 = 0;
  7797.   Opd.U1.s6 = 0;
  7798.   Opd.U1.s7 = 0;
  7799.   R.U1.r0 = 0;
  7800.   R.U1.r1 = 0;
  7801.   R.U1.r2 = 0;
  7802.   R.U1.r3 = 0;
  7803.   R.U1.r4 = 0;
  7804.   R.U1.r5 = 0;
  7805.   R.U1.r6 = 0;
  7806.   R.U1.r7 = 0;
  7807.   R.U1.r8 = 0;
  7808.   R.U1.r9 = 0;
  7809.   R.U1.r10 = 0;
  7810.   R.U1.r11 = 0;
  7811.   R.U1.r12 = 0;
  7812.   R.U1.r13 = 0;
  7813.   R.U1.r14 = 0;
  7814.   R.U1.r15 = 0;
  7815.   TryRegList = true;
  7816.   SaveEntryPoints = true;
  7817.   CrashInternal = false;
  7818.   FaultNotImplemented = false;
  7819.   DebugVocab = false;
  7820.   TextPageNo = -1;
  7821.   TextPageIndex = -1;
  7822.   OldTextPageNo = -1;
  7823.   OldTextPageIndex = -1;
  7824.   BackTxtPageNo = -1;
  7825.   BackTxtIndex = -1;
  7826.   EndPageNo = -1;
  7827.   EndPageIndex = -1;
  7828.   EntryIndex = 0;
  7829.   BPT_List = NULL;
  7830.   StoryCursorX = 0;
  7831.   StoryCursorY = 0;
  7832.   InitExecCnt();
  7833. }  /* Initialize */
  7834.  
  7835.  
  7836. Static void HandleError(boolean WriteLastInst, Char Message[256],
  7837.                         boolean Crash) {
  7838.   /*WriteLastInst:Boolean; Message:aMaxString;
  7839.                         Crash:Boolean*/
  7840.   int *NilPtr;
  7841.  
  7842.   SaveCursorState();
  7843.   RingBell();
  7844.   PrintString("Error:");
  7845.   PrintCh(' ');
  7846.   PrintString(Message);
  7847.   ChkWait();
  7848.   if (Crash)
  7849.     NilPtr = NULL;
  7850.   if (WriteLastInst) {
  7851.     if (RestartOperations) {
  7852.       IPC_PageNo = NewInstPageNo;
  7853.       IPC_PageIndex = NewInstPageIndex;
  7854.     }
  7855.     PrintZState();
  7856.     DC_PageNo = NewInstPageNo;
  7857.     DC_PageIndex = NewInstPageIndex;
  7858.     Disassemble(1, true);
  7859.   }
  7860.   Cmd = Break;
  7861.   longjmp(_JL999, 1);
  7862. }  /* HandleError */
  7863.  
  7864.  
  7865. Static void InternalError(char Error) {
  7866.   /*Error:InternalErrors*/
  7867.   Char Message[256];
  7868.  
  7869.   strcpy(Message, "Unknown error #**");
  7870.   Message[15] = HexChars[Error / 16 - 1];
  7871.   Message[16] = HexChars[(Error & 15) - 1];
  7872.   switch (Error) {
  7873.  
  7874.   case IllMultiOpdOp:
  7875.     strcpy(Message, "Illegal multiple operand operation");
  7876.     break;
  7877.  
  7878.   case IllNoOpdOp:
  7879.     strcpy(Message, "Illegal no operand operation");
  7880.     break;
  7881.  
  7882.   case IllTwoOpdOp:
  7883.     strcpy(Message, "Illegal two operand operation");
  7884.     break;
  7885.  
  7886.   case IllOneOpdOp:
  7887.     strcpy(Message, "Illegal one operand operation");
  7888.     break;
  7889.  
  7890.   case StackUnderflow:
  7891.     strcpy(Message, "Stack underflow");
  7892.     break;
  7893.  
  7894.   case StackOverflow:
  7895.     strcpy(Message, "Stack overflow");
  7896.     break;
  7897.  
  7898.   case IllObjDataLoad:
  7899.     strcpy(Message, "Illegal object data load");
  7900.     break;
  7901.  
  7902.   case DivideByZero:
  7903.     strcpy(Message, "Divide by zero");
  7904.     break;
  7905.  
  7906.   case MissingOpd:
  7907.     strcpy(Message, "Missing operand");
  7908.     break;
  7909.  
  7910.   case MissingObjData:
  7911.     strcpy(Message, "Missing object data");
  7912.     break;
  7913.  
  7914.   case IllObjPropertyStore:
  7915.     strcpy(Message, "Illegal object property store");
  7916.     break;
  7917.  
  7918.   case IllZCodeType:
  7919.     strcpy(Message, "Illegal Z-code type");
  7920.     break;
  7921.  
  7922.   case NotImplemented:
  7923.     strcpy(Message, "Not implemented");
  7924.     break;
  7925.  
  7926.   case KeyboardBreak:
  7927.     strcpy(Message, "Keyboard break");
  7928.     break;
  7929.  
  7930.   case BreakPoint:
  7931.     strcpy(Message, "Unexpected breakpoint");
  7932.     break;
  7933.  
  7934.   case OutputBufferUndefined:
  7935.     strcpy(Message, "Output buffer is not defined");
  7936.     break;
  7937.  
  7938.   case PC_Overflow:
  7939.     strcpy(Message, "PC overflow");
  7940.     break;
  7941.  
  7942.   case PC_Underflow:
  7943.     strcpy(Message, "PC underflow");
  7944.     break;
  7945.  
  7946.   case TooManySeparators:
  7947.     strcpy(Message, "Too many separators");
  7948.     break;
  7949.  
  7950.   case TooManyLocalVariables:
  7951.     strcpy(Message, "Too many local variables");
  7952.     break;
  7953.  
  7954.   case TooManyParameters:
  7955.     strcpy(Message, "Too many parameters");
  7956.     break;
  7957.  
  7958.   case IllNumOperands:
  7959.     strcpy(Message, "Illegal number of operands");
  7960.     break;
  7961.  
  7962.   case IllOutputChar:
  7963.     strcpy(Message, "Illegal output character");
  7964.     break;
  7965.  
  7966.   case IllScreenMode:
  7967.     strcpy(Message, "Illegal screen mode");
  7968.     break;
  7969.  
  7970.   case NoPrinter:
  7971.     strcpy(Message, "Unable to open printer");
  7972.     break;
  7973.  
  7974.   case IllOutputMode:
  7975.     strcpy(Message, "Illegal output mode");
  7976.     break;
  7977.  
  7978.   default:
  7979.     strcpy(Message, "Undefined Error");
  7980.     break;
  7981.   }
  7982.   if (Error != NotImplemented || FaultNotImplemented)
  7983.     HandleError(true, Message, CrashInternal);
  7984. }  /* InternalError */
  7985.  
  7986.  
  7987. int main(int argc, Char *argv[]) {
  7988.   PASCAL_MAIN(argc, argv);
  7989.   if (setjmp(_JL999))
  7990.     goto _L999;
  7991.   Printer = NULL;
  7992.   Initialize();
  7993.   if (P_argc > 1) {
  7994.     strcpy(StoryName, P_argv[1]);
  7995.     LoadStory();
  7996.     StartZMachine(Quit);
  7997.   } else {
  7998.     ListCommands();
  7999.     *CmdLine = '\0';
  8000.     do {
  8001.       Tracing = false;
  8002.       Running = false;
  8003.       Stepping = false;
  8004.       if (Cmd == SwitchToStep) {
  8005.         StepCommand();
  8006.       } else if (Cmd == SwitchToTrace) {
  8007.         TraceCommand();
  8008.       } else {
  8009.         PrintListing = false;
  8010.         ChkWait();
  8011.         PrintCh(']');
  8012.         SetLength(CmdLine, 0);
  8013.         ReadLine(false, CmdLine, 79, -1, 0);
  8014.         LineInterpreter(&Cmd, CmdLine);
  8015.       }
  8016. _L999: ;
  8017.     } while (Cmd != Quit);
  8018.   }
  8019.   ResetScreen();
  8020.   CloseText(&Printer);
  8021.   if (Printer != NULL)
  8022.     fclose(Printer);
  8023.   exit(EXIT_SUCCESS);
  8024. }  /* InfocomInteractiveFictionDebugger */
  8025.  
  8026.  
  8027.  
  8028. /* End. */
  8029.