home *** CD-ROM | disk | FTP | other *** search
/ Media Share 9 / MEDIASHARE_09.ISO / pascal / tplib21.zip / INSTALL.EXE / ENHCON.PAS < prev    next >
Pascal/Delphi Source File  |  1993-06-24  |  106KB  |  2,716 lines

  1. (*
  2.     TURBO PASCAL LIBRARY 2.1
  3.     ENHCON unit: Enhanced console I/O routines
  4. *)
  5.  
  6. UNIT ENHCON;
  7.  
  8. {$V-}
  9.  
  10. {$L CRTVDU}
  11. {$L CRTKB}
  12.  
  13. INTERFACE
  14.  
  15. USES
  16.     DOS,CRT,STRINGS,TIME;
  17.  
  18.  
  19. TYPE
  20.     CharSet     =   SET OF CHAR;
  21.     ConsoleStr  =   STRING[80];
  22.  
  23.     SignalErrorProc  =  PROCEDURE(width: BYTE);
  24.  
  25.     EditFormatRec =                   { Edit configuration record }
  26.         RECORD
  27.             Attribute:      BYTE;             { Text attr. for editing field }
  28.             StartChar,
  29.             EndChar:        CHAR;             { Start/end marker characters }
  30.             MarkerAttr:     BYTE;             { Text attribute for markers }
  31.             AllowChars,                       { Allowable chars. in string }
  32.             ExitKeys:       CharSet;          { Keys to end edit }
  33.             EditKey,                          { Key to start edit }
  34.             RestoreKey,                       { Key to restore original }
  35.             AbortKey:       CHAR;             { Key to abort edit }
  36.             NumFormat:      STRING[12];       { Format for numeric fields }
  37.             SignalError:    SignalErrorProc;  { Called to report an error }
  38.             Flags:          WORD;             { General control flags }
  39.         END;
  40.  
  41.  
  42.     WindowStatus    = (Undefined,Closed,Hidden,Open,Active);
  43.     WindowBorder    = ARRAY[1..8] OF CHAR;
  44.     WindowJustify   = (WJustLeft,WJustCenter,WJustRight);
  45.     WindowMovement  = (WMoveLeft,WMoveRight,WMoveUp,WMoveDown);
  46.  
  47.     WindowDefinition =
  48.         RECORD                  { Definition of window }
  49.             X1, Y1, X2, Y2:     BYTE;           { Absolute co-ordinates }
  50.             DefaultAttr:        BYTE;           { Text attr. when opening }
  51.             DefaultCrsrHide:    BOOLEAN;        { Default cursor hide status }
  52.             DefaultCrsrSize:    WORD;           { Default cursor size }
  53.             Border:             WindowBorder;   { Border characters }
  54.             BorderAttr:         BYTE;           { Border colors }
  55.             HdrText, FtrText:   ConsoleStr;     { Header/footer text }
  56.             HdrAttr, FtrAttr:   BYTE;           { Header/footer text colors }
  57.             HdrPos,  FtrPos:    WindowJustify;  { Header/footer position }
  58.             Flags:              BYTE;           { User flags }
  59.         END;
  60.  
  61.     HelpConfiguration =
  62.         RECORD
  63.             WindowID:           BYTE;           { Window no. for help system }
  64.             HelpFileName:       ConsoleStr;     { Name of help file }
  65.             X1, Y1, X2, Y2:     BYTE;           { Co-ordinates of help window }
  66.             NormalAttr,                         { Attribute for normal text }
  67.             IndexAttr,                          { Attribute for index words }
  68.             SelectAttr:         BYTE;           { Attribute for selected word }
  69.             Border:             WindowBorder;   { Border characters }
  70.             BorderAttr:         BYTE;           { Attribute for border }
  71.             HdrText, FtrText:   ConsoleStr;     { Header/footer text }
  72.             HdrPos,  FtrPos:    WindowJustify;  { Position of header/footer }
  73.             HdrAttr, FtrAttr:   BYTE;           { Attribute for header/footer }
  74.             GeneralKey,                         { Key for general help index }
  75.             ContextKey,                         { Key for context help }
  76.             LastHelpKey,                        { Key for last help screen }
  77.             MoveWindowKey:      CHAR;           { Key for window movement }
  78.             Flags:              BYTE;           { User flags }
  79.         END;
  80.  
  81.     HelpErrorProc   = PROCEDURE(HErr: BYTE);
  82.  
  83.  
  84.  
  85. CONST
  86.  
  87. { Flag constants for edit format records and window definitions }
  88.  
  89.     { Flags affecting string edits only }
  90.  
  91.     EdFlagTrimL     = $0001;        { Trim leading blanks }
  92.     EdFlagTrimR     = $0002;        { Trim trailing blanks }
  93.     EdFlagPadL      = $0004;        { Pad with leading blanks }
  94.     EdFlagPadR      = $0008;        { Pad with trailing blanks }
  95.     EdFlagUpper     = $0010;        { Force to upper case }
  96.  
  97.     { Flags affecting all edits }
  98.  
  99.     EdFlagFlushKB   = $0100;        { Flush keyboard buffer }
  100.     EdFlagInsert    = $0200;        { Set insert/overwrite mode for edit }
  101.     EdFlagForceIns  = $0400;        { Force insert toggle to required state }
  102.     EdFlagInsStat   = $0800;        { Use insert toggle status for mode }
  103.     EdFlagFirstClr  = $1000;        { First character clears field }
  104.     EdFlagEdKeyExit = $2000;        { Allow edit key to terminate edit }
  105.     EdFlagHideCrsr  = $4000;        { Hide cursor before edit }
  106.  
  107.     { Values for Flags field in WindowDefinition }
  108.  
  109.     WFlagClrOpen    = $01;          { Clear window when opening }
  110.     WFlagClrClose   = $02;          { Clear window when closing }
  111.     WFlagClrHide    = $04;          { Clear window when hiding }
  112.     WFlagRestore    = $08;          { Restore original screen when closed }
  113.     WFlagShowBrdr   = $10;          { Display border around window }
  114.     WFlagWriteBrdr  = $20;          { Allow writing on border }
  115.  
  116.     { Values for Flags field in HelpConfiguration }
  117.  
  118.     HFlagPageText   = $01;          { Use text instead of page arrows }
  119.     HFlagPageInd    = $02;          { Show page up/down indication in footer }
  120.     HFlagTitle      = $04;          { Show section title in header }
  121.  
  122.     { Values for cursor-size selection }
  123.  
  124.     WCrsrDefault    = $FF00;
  125.     WCrsrLine       = $FE00;
  126.     WCrsrBlock      = $FD00;
  127.  
  128.     { Key value for scroll lock control of help window }
  129.  
  130.     HMoveScroll     = #$FF;
  131.  
  132.  
  133. { Common border definitions }
  134.  
  135.     WBorder1:       WindowBorder  =
  136.         (#218,#196,#191,#179,#217,#196,#192,#179);      { Single line }
  137.     WBorder2:       WindowBorder  =
  138.         (#201,#205,#187,#186,#188,#205,#200,#186);      { Double line }
  139.     WBorderV1H2:    WindowBorder  =
  140.         (#213,#205,#184,#179,#190,#205,#212,#179);      { Horiz. double }
  141.     WBorderH1V2:    WindowBorder  =
  142.         (#214,#196,#183,#186,#189,#196,#211,#186);      { Verticals double }
  143.  
  144.  
  145. { Text attributes for monochrome display (Add $80 for blinking) }
  146.  
  147.     MonoNone        = $00;
  148.     MonoUnderline   = $01;
  149.     MonoNormal      = $07;
  150.     MonoIntenseUL   = $09;
  151.     MonoIntense     = $0F;
  152.     MonoReverse     = $70;
  153.  
  154.  
  155. { ASCII control codes }
  156.  
  157.     NUL = #$00;     { Null }
  158.     SOH = #$01;     { Start Of Header }
  159.     STX = #$02;     { Start of Text }
  160.     ETX = #$03;     { End of Text }
  161.     EOT = #$04;     { End Of Transmission }
  162.     ENQ = #$05;     { Enquiry }
  163.     ACK = #$06;     { Acknowledge }
  164.     BEL = #$07;     { Bell }
  165.     BS  = #$08;     { Backspace }
  166.     HT  = #$09;     { Horizontal Tab }
  167.     LF  = #$0A;     { Line Feed }
  168.     VT  = #$0B;     { Vertical Tab }
  169.     FF  = #$0C;     { Form Feed }
  170.     CR  = #$0D;     { Carriage Return }
  171.     SO  = #$0E;     { Shift Out }
  172.     SI  = #$0F;     { Shift In }
  173.     DLE = #$10;     { Data Link Escape }
  174.     DC1 = #$11;     { Device Control 1 }
  175.     DC2 = #$12;     { Device Control 2 }
  176.     DC3 = #$13;     { Device Control 3 }
  177.     DC4 = #$14;     { Device Control 4 }
  178.     NAK = #$15;     { Negative Acknowledge }
  179.     SYN = #$16;     { Synchronous idle }
  180.     ETB = #$17;     { End Transmission Block }
  181.     CAN = #$18;     { Cancel }
  182.     EM  = #$19;     { End of Medium }
  183.     SUB = #$1A;     { Substitute }
  184.     ESC = #$1B;     { Escape }
  185.     FS  = #$1C;     { File Separator }
  186.     GS  = #$1D;     { Group Separator }
  187.     RS  = #$1E;     { Record Separator }
  188.     US  = #$1F;     { Unit Separator }
  189.     DEL = #$7F;     { Delete }
  190.  
  191.     PoundSign = #$9C;               { British pounds-sterling character }
  192.  
  193.     StandardChars = [#32..#126];    { Set of printable, standard characters }
  194.  
  195.  
  196. { Extended keys - Values returned by ENHCON.ReadKey }
  197.  
  198.     KeyIns      = #$80;
  199.     KeyDel      = #$81;
  200.     KeyUp       = #$82;
  201.     KeyDown     = #$83;
  202.     KeyLeft     = #$84;         KeyCLeft    = #$8A;
  203.     KeyRight    = #$85;         KeyCRight   = #$8B;
  204.     KeyHome     = #$86;         KeyCHome    = #$8C;
  205.     KeyEnd      = #$87;         KeyCEnd     = #$8D;
  206.     KeyPgUp     = #$88;         KeyCPgUp    = #$8E;
  207.     KeyPgDn     = #$89;         KeyCPgDn    = #$8F;
  208.  
  209.     KeyA0   = #$90;             KeyAHyphen  = #$9A;
  210.     KeyA1   = #$91;             KeyAEquals  = #$9B;
  211.     KeyA2   = #$92;
  212.     KeyA3   = #$93;
  213.     KeyA4   = #$94;             KeySTab     = #$9D;
  214.     KeyA5   = #$95;             KeyCPrtSc   = #$9E;
  215.     KeyA6   = #$96;
  216.     KeyA7   = #$97;
  217.     KeyA8   = #$98;
  218.     KeyA9   = #$99;
  219.  
  220.     KeyF1  = #$A0;  KeySF1  = #$B0;     KeyCF1  = #$C0;     KeyAF1  = #$D0;
  221.     KeyF2  = #$A1;  KeySF2  = #$B1;     KeyCF2  = #$C1;     KeyAF2  = #$D1;
  222.     KeyF3  = #$A2;  KeySF3  = #$B2;     KeyCF3  = #$C2;     KeyAF3  = #$D2;
  223.     KeyF4  = #$A3;  KeySF4  = #$B3;     KeyCF4  = #$C3;     KeyAF4  = #$D3;
  224.     KeyF5  = #$A4;  KeySF5  = #$B4;     KeyCF5  = #$C4;     KeyAF5  = #$D4;
  225.     KeyF6  = #$A5;  KeySF6  = #$B5;     KeyCF6  = #$C5;     KeyAF6  = #$D5;
  226.     KeyF7  = #$A6;  KeySF7  = #$B6;     KeyCF7  = #$C6;     KeyAF7  = #$D6;
  227.     KeyF8  = #$A7;  KeySF8  = #$B7;     KeyCF8  = #$C7;     KeyAF8  = #$D7;
  228.     KeyF9  = #$A8;  KeySF9  = #$B8;     KeyCF9  = #$C8;     KeyAF9  = #$D8;
  229.     KeyF10 = #$A9;  KeySF10 = #$B9;     KeyCF10 = #$C9;     KeyAF10 = #$D9;
  230.  
  231.     KeyAA  = #$E1;              KeyAP  = #$F0;
  232.     KeyAB  = #$E2;              KeyAQ  = #$F1;
  233.     KeyAC  = #$E3;              KeyAR  = #$F2;
  234.     KeyAD  = #$E4;              KeyAS  = #$F3;
  235.     KeyAE  = #$E5;              KeyAT  = #$F4;
  236.     KeyAF  = #$E6;              KeyAU  = #$F5;
  237.     KeyAG  = #$E7;              KeyAV  = #$F6;
  238.     KeyAH  = #$E8;              KeyAW  = #$F7;
  239.     KeyAI  = #$E9;              KeyAX  = #$F8;
  240.     KeyAJ  = #$EA;              KeyAY  = #$F9;
  241.     KeyAK  = #$EB;              KeyAZ  = #$FA;
  242.     KeyAL  = #$EC;
  243.     KeyAM  = #$ED;
  244.     KeyAN  = #$EE;
  245.     KeyAO  = #$EF;
  246.  
  247.  
  248. { Error codes }
  249.  
  250.     ConErrXY            = $01;  { Co-ordinates invalid }
  251.     ConErrBorderXY      = $02;  { Co-ordinates invalid when border used }
  252.     ConErrMove          = $03;  { Cannot move window in specified direction }
  253.     ConErrOpen          = $04;  { Window is open }
  254.     ConErrClosed        = $05;  { Window not open }
  255.     ConErrHidden        = $06;  { Window is hidden }
  256.     ConErrNotHidden     = $07;  { Window not hidden }
  257.     ConErrZero          = $08;  { Cannot use window zero }
  258.     ConErrDefined       = $09;  { Window already defined }
  259.     ConErrUndefined     = $0A;  { Window has not been defined }
  260.     ConErrReturn        = $0B;  { Cannot return to previous window }
  261.     ConErrHeap          = $10;  { No heap store available }
  262.     ConErrHelpRead      = $11;  { Error reading from help file }
  263.     ConErrHelpInit      = $12;  { Help system already initialized }
  264.     ConErrNoHelpFile    = $13;  { Can't find/open specified help file }
  265.     ConErrHelpFormat    = $14;  { Format error in help file }
  266.     ConErrHelpIndex     = $15;  { Index entry invalid for specified window }
  267.     ConErrHelpInvalid   = $16;  { Help/window definition invalid }
  268.     ConErrHelpStkFull   = $17;  { Context stack overflow }
  269.     ConErrHelpStkEmpty  = $18;  { Context stack empty }
  270.  
  271.  
  272. { General control variables }
  273.  
  274.     InsKeyEnable:       BOOLEAN = FALSE;    { Ins key mode select }
  275.     CursorInsert:       BOOLEAN = FALSE;    { Change cursor size flag }
  276.     WindowCheck:        BOOLEAN = TRUE;     { Control internal error checking }
  277.     EnhConHaltError:    WORD    = 0;        { Code for halt on error }
  278.     HelpContext:        BYTE    = 0;        { Section for context-sens. help }
  279.  
  280.  
  281. VAR
  282.     HelpError:  HelpErrorProc;              { Address of help error handler }
  283.  
  284.  
  285.  
  286. FUNCTION  ColorDisplay: BOOLEAN;
  287. FUNCTION  MaxCursorSize: BYTE;
  288. PROCEDURE SetCursor(size: WORD);
  289. FUNCTION  GetCursor: WORD;
  290. PROCEDURE HideCursor(hide: BOOLEAN);
  291. FUNCTION  CursorHidden: BOOLEAN;
  292. PROCEDURE OrigCursor;
  293. PROCEDURE LineCursor;
  294. PROCEDURE BlockCursor;
  295. FUNCTION  GetDisplayPage: BYTE;
  296. FUNCTION  GetDisplayBase: WORD;
  297. PROCEDURE GetMaxXY(VAR x,y: BYTE);
  298. PROCEDURE FlushKB;
  299. FUNCTION  CapsLock: BOOLEAN;
  300. FUNCTION  NumLock: BOOLEAN;
  301. FUNCTION  ScrollLock: BOOLEAN;
  302. FUNCTION  InsertLock: BOOLEAN;
  303. PROCEDURE ForceInsert(Ins: BOOLEAN);
  304. PROCEDURE StdSignalError(width: BYTE);
  305. FUNCTION  EditString(form: EditFormatRec; VAR s: STRING; width: BYTE): CHAR;
  306. FUNCTION  EditInt(form: EditFormatRec; VAR i: LongInt; min,max: LongInt): CHAR;
  307. FUNCTION  EditReal(form: EditFormatRec; VAR r: REAL; min,max: REAL): CHAR;
  308. FUNCTION  EditDate(form: EditFormatRec; VAR Dt: DateRec): CHAR;
  309. FUNCTION  EditTime(form: EditFormatRec; VAR Tm: TimeRec): CHAR;
  310. FUNCTION  WindowResult: BYTE;
  311. FUNCTION  ConErrorMsg(ErrNum: BYTE): ConsoleStr;
  312. PROCEDURE GetWindowDef(WindowID: BYTE; VAR d: WindowDefinition);
  313. FUNCTION  WindowStat(WindowID: BYTE): WindowStatus;
  314. FUNCTION  CurrentWindow: BYTE;
  315. PROCEDURE DefineWindow(WindowID: BYTE; d: WindowDefinition);
  316. PROCEDURE PurgeWindow(WindowID: BYTE);
  317. PROCEDURE OpenWindow(WindowID: BYTE);
  318. PROCEDURE SelectWindow(WindowID: BYTE);
  319. PROCEDURE CloseWindow(WindowID: BYTE);
  320. PROCEDURE HideWindow(WindowID: BYTE);
  321. PROCEDURE ShowWindow(WindowID: BYTE);
  322. PROCEDURE RelocateWindow(WindowID: BYTE; X,Y: BYTE);
  323. PROCEDURE MoveWindow(WindowID: BYTE; Direction: WindowMovement);
  324. PROCEDURE WriteWindow(s: ConsoleStr);
  325. PROCEDURE HelpReset;
  326. PROCEDURE PushHelpContext(NewContext: BYTE);
  327. PROCEDURE PopHelpContext;
  328. PROCEDURE HelpInitialize(h: HelpConfiguration);
  329. PROCEDURE TextMode(Mode: WORD);
  330. FUNCTION  ReadKey: CHAR;
  331.  
  332.  
  333. IMPLEMENTATION
  334.  
  335. TYPE
  336.     ScreenBlock     = ARRAY[0..4000] OF WORD;   { Access to screen store }
  337.     ScreenBlockPtr  = ^ScreenBlock;
  338.  
  339.     SysWindowDefinition =       { System's window definition record (WDR) }
  340.         RECORD
  341.             U:                  WindowDefinition;   { User's window defn. }
  342.             SavePosX, SavePosY: BYTE;               { Saved cursor position }
  343.             SaveAttr:           BYTE;               { Saved text attribute }
  344.             SaveCrsrHide:       BOOLEAN;            { Saved crsr hide status }
  345.             SaveCrsrSize:       WORD;               { Saved cursor size }
  346.             SaveScreen:         ScreenBlockPtr;     { Pointer to saved screen }
  347.             PrevWindow:         BYTE;               { ID of previous window }
  348.             SysFlags:           BYTE;               { Flags for internal use }
  349.         END;
  350.  
  351.     WindowRecPointer    = ^SysWindowDefinition;
  352.  
  353.     HelpIndexString = STRING[30];       { String to hold help index }
  354.     HelpStrPtr      = ^ConsoleStr;      { Used to build help section in store }
  355.  
  356.     HelpRec     =   RECORD              { Record format in help file }
  357.                         CASE SecNum: BYTE OF
  358.                             0:  (SecOfs:    LONGINT;
  359.                                  SecLength: WORD;
  360.                                  SecName:   HelpIndexString);
  361.                             1:  (HelpText:  ConsoleStr);
  362.                       END;
  363.  
  364.  
  365.  
  366. CONST
  367.  
  368.     BIOS_VIDEO  = $10;
  369.  
  370.     { Keys used by edit routines }
  371.  
  372.     EditKeys = [KeyLeft,KeyRight,KeyHome,KeyEnd,KeyDel,KeyIns,BS];
  373.  
  374.  
  375.     { Conversion table for extended keys }
  376.  
  377.     ExtKey: ARRAY[CHAR] OF CHAR =
  378.                    (NUL,       NUL,       NUL,       NUL,
  379.                     NUL,       NUL,       NUL,       NUL,
  380.                     NUL,       NUL,       NUL,       NUL,
  381.                     NUL,       NUL,       NUL,       KeySTab,
  382.                     KeyAQ,     KeyAW,     KeyAE,     KeyAR,
  383.                     KeyAT,     KeyAY,     KeyAU,     KeyAI,
  384.                     KeyAO,     KeyAP,     NUL,       NUL,
  385.                     NUL,       NUL,       KeyAA,     KeyAS,
  386.                     KeyAD,     KeyAF,     KeyAG,     KeyAH,
  387.                     KeyAJ,     KeyAK,     KeyAL,     NUL,
  388.                     NUL,       NUL,       NUL,       NUL,
  389.                     KeyAZ,     KeyAX,     KeyAC,     KeyAV,
  390.                     KeyAB,     KeyAN,     KeyAM,     NUL,
  391.                     NUL,       NUL,       NUL,       NUL,
  392.                     NUL,       NUL,       NUL,       KeyF1,
  393.                     KeyF2,     KeyF3,     KeyF4,     KeyF5,
  394.                     KeyF6,     KeyF7,     KeyF8,     KeyF9,
  395.                     KeyF10,    NUL,       NUL,       KeyHome,
  396.                     KeyUp,     KeyPgUp,   NUL,       KeyLeft,
  397.                     NUL,       KeyRight,  NUL,       KeyEnd,
  398.                     KeyDown,   KeyPgDn,   KeyIns,    KeyDel,
  399.                     KeySF1,    KeySF2,    KeySF3,    KeySF4,
  400.                     KeySF5,    KeySF6,    KeySF7,    KeySF8,
  401.                     KeySF9,    KeySF10,   KeyCF1,    KeyCF2,
  402.                     KeyCF3,    KeyCF4,    KeyCF5,    KeyCF6,
  403.                     KeyCF7,    KeyCF8,    KeyCF9,    KeyCF10,
  404.                     KeyAF1,    KeyAF2,    KeyAF3,    KeyAF4,
  405.                     KeyAF5,    KeyAF6,    KeyAF7,    KeyAF8,
  406.                     KeyAF9,    KeyAF10,   KeyCPrtSc, KeyCLeft,
  407.                     KeyCRight, KeyCEnd,   KeyCPgDn,  KeyCHome,
  408.                     KeyA1,     KeyA2,     KeyA3,     KeyA4,
  409.                     KeyA5,     KeyA6,     KeyA7,     KeyA8,
  410.                     KeyA9,     KeyA0,     KeyAHyphen,KeyAEquals,
  411.                     KeyCPgUp,  NUL,       NUL,       NUL,
  412.                     NUL,       NUL,       NUL,       NUL,
  413.                     NUL,       NUL,       NUL,       NUL,
  414.                     NUL,       NUL,       NUL,       NUL,
  415.                     NUL,       NUL,       NUL,       NUL,
  416.                     NUL,       NUL,       NUL,       NUL,
  417.                     NUL,       NUL,       NUL,       NUL,
  418.                     NUL,       NUL,       NUL,       NUL,
  419.                     NUL,       NUL,       NUL,       NUL,
  420.                     NUL,       NUL,       NUL,       NUL,
  421.                     NUL,       NUL,       NUL,       NUL,
  422.                     NUL,       NUL,       NUL,       NUL,
  423.                     NUL,       NUL,       NUL,       NUL,
  424.                     NUL,       NUL,       NUL,       NUL,
  425.                     NUL,       NUL,       NUL,       NUL,
  426.                     NUL,       NUL,       NUL,       NUL,
  427.                     NUL,       NUL,       NUL,       NUL,
  428.                     NUL,       NUL,       NUL,       NUL,
  429.                     NUL,       NUL,       NUL,       NUL,
  430.                     NUL,       NUL,       NUL,       NUL,
  431.                     NUL,       NUL,       NUL,       NUL,
  432.                     NUL,       NUL,       NUL,       NUL,
  433.                     NUL,       NUL,       NUL,       NUL,
  434.                     NUL,       NUL,       NUL,       NUL,
  435.                     NUL,       NUL,       NUL,       NUL,
  436.                     NUL,       NUL,       NUL,       NUL,
  437.                     NUL,       NUL,       NUL,       NUL,
  438.                     NUL,       NUL,       NUL,       NUL,
  439.                     NUL,       NUL,       NUL,       NUL,
  440.                     NUL,       NUL,       NUL,       NUL,
  441.                     NUL,       NUL,       NUL,       NUL);
  442.  
  443.     { Date and time constants }
  444.  
  445.     DateFieldSize   =   SizeOf(DateString)-1;
  446.     TimeFieldSize   =   SizeOf(TimeString)-1;
  447.  
  448.  
  449.     { Values for SysFlags in WDR }
  450.  
  451.     SysFlagOpen     = $01;      { Window is open }
  452.     SysFlagHidden   = $02;      { Window is hidden }
  453.  
  454.     { Initialized variables }
  455.  
  456.     ErrorHalt:          BOOLEAN = FALSE;    { Signal to exit handler }
  457.     HelpInitialized:    BOOLEAN = FALSE;    { Set when help initialized }
  458.     HelpActive:         BOOLEAN = FALSE;    { Controls help access in ReadKey }
  459.     LastHelpSec:        BYTE    = 0;        { Section number of last help }
  460.     ErrCode:            BYTE    = 0;        { Holds result of last operation }
  461.  
  462.  
  463. VAR
  464.     ExitSave:       POINTER;        { For use by exit procedure }
  465.     CGAcursor:      BOOLEAN;        { True if CGA cursor, false if MDA/EGA }
  466.     OrigCursorSize: WORD;           { Size of cursor at start of program }
  467.     OrigCursorHide: BOOLEAN;        { Hide/show status of cursor at start }
  468.     LineCrsr,
  469.     BlockCrsr:      WORD;           { Line/block cursors for current mode }
  470.     DisplayBase:    WORD;           { Holds base address of display store }
  471.     MaxScreenX,                     { Hold size of screen in columns/rows }
  472.     MaxScreenY:     BYTE;
  473.     RoutineName:    ConsoleStr;     { Name of routine for error handler }
  474.     ActiveWindow:   BYTE;           { ID of currently active window }
  475.  
  476.     WindowPtr:      ARRAY[0..255] OF WindowRecPointer;  { Pointers to WDRs }
  477.  
  478.     HelpConfig:     HelpConfiguration;              { Current config. }
  479.     HelpFile:       FILE OF HelpRec;                { Help file }
  480.     HelpVar:        HelpRec;                        { For access to file }
  481.     HelpIndexStr:   ARRAY[1..255] OF HelpIndexString;   { Holds index words }
  482.     HelpSectionOfs: ARRAY[1..255] OF LONGINT;       { Offset to sec start }
  483.     HelpSectionLen: ARRAY[1..255] OF WORD;          { Length of each sec }
  484.     MaxHelpSec:     BYTE;                           { No. of highest sec }
  485.     HelpStore:      ARRAY[1..1000] OF HelpStrPtr;   { Ptrs to help buffer }
  486.     HelpStoreSize:  WORD;                           { No. of recs in store }
  487.     IndexRows,                                      { No. of rows for index }
  488.     IndexCols,                                      { No. of cols.for index }
  489.     IndexColWidth:  BYTE;                           { Width of index column }
  490.     HelpCtxStack:   ARRAY[1..128] OF BYTE;          { For push/pop of context }
  491.     HelpCtxIndex:   BYTE;                           { Stack pointer }
  492.  
  493.  
  494.  
  495. FUNCTION  GAcheck: BYTE; EXTERNAL;
  496. { Called during initialization.  Returns 2 if EGA, 1 if VGA, 0 otherwise. }
  497. { Turns on CGA cursor emulation if VGA adapter is present }
  498.  
  499. PROCEDURE SetAbsCrsr(size: WORD); EXTERNAL;
  500. FUNCTION ColorDisplay: BOOLEAN; EXTERNAL;
  501. FUNCTION MaxCursorSize: BYTE; EXTERNAL;
  502.  
  503. PROCEDURE SetCursor(size: WORD);
  504.  
  505.     BEGIN
  506.         IF size=WCrsrLine THEN              { Check for line/block request }
  507.             SetAbsCrsr(LineCrsr)
  508.         ELSE
  509.             IF size=WCrsrBlock THEN
  510.                 SetAbsCrsr(BlockCrsr)
  511.             ELSE
  512.                 IF size<>WCrsrDefault THEN  { Otherwise, set requested size }
  513.                     SetAbsCrsr(size);
  514.     END;
  515.  
  516.  
  517. FUNCTION  GetCursor: WORD; EXTERNAL;
  518. PROCEDURE HideCursor(hide: BOOLEAN); EXTERNAL;
  519. FUNCTION  CursorHidden: BOOLEAN; EXTERNAL;
  520.  
  521. PROCEDURE OrigCursor;
  522.  
  523.     BEGIN
  524.         SetAbsCrsr(OrigCursorSize);
  525.         HideCursor(OrigCursorHide);
  526.     END;
  527.  
  528.  
  529. PROCEDURE LineCursor;
  530.  
  531.     BEGIN
  532.         SetAbsCrsr(LineCrsr);
  533.     END;
  534.  
  535.  
  536. PROCEDURE BlockCursor;
  537.  
  538.     BEGIN
  539.         SetAbsCrsr(BlockCrsr);
  540.     END;
  541.  
  542.  
  543.  
  544. FUNCTION  ReadDisplay: WORD; EXTERNAL;
  545. PROCEDURE WriteDisplay(CharAttr: WORD); EXTERNAL;
  546. FUNCTION  GetDisplayPage: BYTE; EXTERNAL;
  547.  
  548. FUNCTION  GetDisplayBase: WORD;
  549.  
  550.     BEGIN
  551.         GetDisplayBase:=DisplayBase;
  552.     END;
  553.  
  554.  
  555. PROCEDURE GetMaxXY(VAR x,y: BYTE);
  556.    
  557.     BEGIN
  558.         x:=MaxScreenX;
  559.         y:=MaxScreenY;
  560.     END;
  561.  
  562.  
  563. PROCEDURE FlushKB; EXTERNAL;
  564. FUNCTION  CapsLock: BOOLEAN; EXTERNAL;
  565. FUNCTION  NumLock: BOOLEAN; EXTERNAL;
  566. FUNCTION  ScrollLock: BOOLEAN; EXTERNAL;
  567. FUNCTION  InsertLock: BOOLEAN; EXTERNAL;
  568. PROCEDURE ForceInsert(Ins: BOOLEAN); EXTERNAL;
  569.  
  570. PROCEDURE StdSignalError(width: BYTE);
  571.  
  572.     BEGIN
  573.         Write(BEL);
  574.     END;
  575.  
  576.  
  577. FUNCTION EditString(form: EditFormatRec; VAR s: STRING; width: BYTE): CHAR;
  578. { Assumes that cursor is positioned at start of field upon entry.
  579.   Exits with cursor in same position. }
  580.  
  581.     LABEL
  582.         GetNextKey;                 { Used in main editing loop }
  583.  
  584.     VAR
  585.         SavedAttr:      BYTE;       { Saved text attribute }
  586.         SavedX,SavedY:  BYTE;       { Saved cursor position upon entry }
  587.         SavedStartCh,
  588.         SavedEndCh:     WORD;       { Saved character/attribute for markers }
  589.         SavedString:    STRING;     { Saved string (used by restore) }
  590.         SavedCursor:    BOOLEAN;    { Saved hide state of cursor }
  591.         Done,                       { Loop control variable }
  592.         FirstKey:       BOOLEAN;    { Cleared after first edit key pressed }
  593.         i:              BYTE;       { Index to string and temp. storage }
  594.         ch:             CHAR;       { User input }
  595.  
  596.  
  597.     PROCEDURE MoveCursor;       { Move cursor to position i }
  598.  
  599.         BEGIN
  600.             FirstKey:=FALSE;                { Edit key has been pressed }
  601.             GotoXY(SavedX+i-1,SavedY);
  602.         END;
  603.  
  604.  
  605.     PROCEDURE ReWriteStr;       { Update string on display }
  606.  
  607.         BEGIN
  608.             GotoXY(SavedX,SavedY);
  609.             Write(PadR(s,width));
  610.             MoveCursor;
  611.         END;
  612.  
  613.  
  614.     FUNCTION InsertStat: BOOLEAN;   { Return current insert mode }
  615.  
  616.         BEGIN
  617.             WITH form DO
  618.                 IF (Flags AND EdFlagInsStat)<>0 THEN
  619.                     InsertStat:=InsertLock
  620.                 ELSE
  621.                     InsertStat:=(Flags AND EdFlagInsert)<>0;
  622.         END;
  623.  
  624.  
  625.     BEGIN  { EditString }
  626.         SavedAttr:=TextAttr;        { Save display status }
  627.         SavedX:=WhereX;
  628.         SavedY:=WhereY;
  629.         SavedCursor:=CursorHidden;
  630.         SavedString:=s;             { Save original field contents }
  631.         WITH form DO
  632.             BEGIN
  633.                 IF MarkerAttr=0 THEN        { Use i to store marker attribute }
  634.                     i:=TextAttr             { Set to original if zero }
  635.                 ELSE
  636.                     i:=MarkerAttr;
  637.                 IF Attribute<>0 THEN        { Set field attr, if required }
  638.                     TextAttr:=Attribute;
  639.                 IF StartChar<>NUL THEN      { Display start-of-field marker }
  640.                     BEGIN
  641.                         GotoXY(SavedX-1,SavedY);
  642.                         SavedStartCh:=ReadDisplay;
  643.                         WriteDisplay((i SHL 8)+ORD(StartChar));
  644.                     END;
  645.                 IF EndChar<>NUL THEN        { Display end-of-field marker }
  646.                     BEGIN
  647.                         GotoXY(SavedX+width,SavedY);
  648.                         SavedEndCh:=ReadDisplay;
  649.                         WriteDisplay((i SHL 8)+ORD(EndChar));
  650.                     END;
  651.                 IF (Flags AND EdFlagForceIns)<>0 THEN
  652.                     ForceInsert((Flags AND EdFlagInsert)<>0);
  653.                 Done:=FALSE;        { Set up loop }
  654.                 i:=1;               { Start at first character }
  655.                 ReWriteStr;         { Display current string in new attribute }
  656.                 FirstKey:=TRUE;     { No editing done yet }
  657.                 IF (Flags AND EdFlagFlushKB)<>0 THEN
  658.                     FlushKB;        { Clear keyboard buffer if required }
  659.  
  660.                 REPEAT          { Main editing loop }
  661.                     IF (Flags AND EdFlagHideCrsr)<>0 THEN   { Hide crsr if }
  662.                         HideCursor(FirstKey);               { 1st & enabled }
  663.                     ch:=ReadKey;
  664.                     IF (Flags AND EdFlagUpper)<>0 THEN      { Force upper }
  665.                         ch:=UpCase(ch);
  666.                     IF ch IN AllowChars THEN                { Add character }
  667.                         BEGIN
  668.                             IF FirstKey AND
  669.                               ((Flags AND EdFlagFirstClr)<>0) THEN
  670.                                 s:='';          { Clear field, if necessary }
  671.                             IF InsertStat THEN          { Insert mode }
  672.                                 BEGIN
  673.                                     IF LENGTH(s)=width THEN { Del if too long }
  674.                                         DELETE(s,width,1);
  675.                                     INSERT(ch,s,i);         { Insert at crsr }
  676.                                 END
  677.                             ELSE                        { Overwrite mode }
  678.                                 BEGIN
  679.                                     DELETE(s,i,1);          { Replace char }
  680.                                     INSERT (ch,s,i);
  681.                                 END;
  682.                             IF i<width THEN     { Move forward unless at end }
  683.                                 INC(i);
  684.                             ReWriteStr;         { Update display }
  685.                         END;
  686.                     IF ch IN ExitKeys THEN      { Chars to terminate edit }
  687.                         BEGIN
  688.                             IF NOT(ch IN EditKeys) OR
  689.                               ((Flags AND EdFlagEdKeyExit)<>0) OR FirstKey THEN
  690.                                 Done:=TRUE;     { Only allow edit keys if 1st }
  691.                             GOTO GetNextKey;    { key or appropriate flag set }
  692.                         END;
  693.                     IF ch=EditKey THEN
  694.                         BEGIN
  695.                             FirstKey:=FALSE;    { Disable "first clear" code }
  696.                             GOTO GetNextKey;
  697.                         END;
  698.                     IF ch=AbortKey THEN
  699.                         IF (AbortKey<>RestoreKey) OR FirstKey THEN
  700.                             BEGIN               { If abort key=restore key }
  701.                                 s:=SavedString; { only allow if first key }
  702.                                 i:=1;
  703.                                 Done:=TRUE;     { Set flag to exit loop }
  704.                                 GOTO GetNextKey;
  705.                             END;
  706.                     IF ch=RestoreKey THEN
  707.                         BEGIN
  708.                             s:=SavedString;     { Restore original string }
  709.                             i:=1;               { Move to first character }
  710.                             ReWriteStr;         { Update display }
  711.                             FirstKey:=TRUE;     { Reset "edited" flag }
  712.                             GOTO GetNextKey;
  713.                         END;
  714.                     CASE ch OF                  { Check for all other keys }
  715.                         KeyLeft:    IF i>1 THEN
  716.                                         BEGIN
  717.                                             DEC(i);
  718.                                             MoveCursor;
  719.                                         END;
  720.                         KeyRight:   IF (i<width) AND (i<=LENGTH(s)) THEN
  721.                                         BEGIN
  722.                                             INC(i);
  723.                                             MoveCursor;
  724.                                         END;
  725.                         KeyHome:    BEGIN
  726.                                         i:=1;
  727.                                         MoveCursor;
  728.                                     END;
  729.                         KeyEnd:     BEGIN
  730.                                         IF LENGTH(s)<width THEN
  731.                                             i:=LENGTH(s)+1
  732.                                         ELSE
  733.                                             i:=LENGTH(s);
  734.                                         MoveCursor;
  735.                                     END;
  736.                         KeyDel:     BEGIN
  737.                                         DELETE(s,i,1);
  738.                                         ReWriteStr;
  739.                                     END;
  740.                         BS:         IF i>1 THEN
  741.                                         BEGIN
  742.                                             DEC(i);
  743.                                             IF InsertStat THEN
  744.                                                 DELETE(s,i,1)
  745.                                             ELSE
  746.                                                 s[i]:=' ';
  747.                                             ReWriteStr;
  748.                                         END;
  749.                     END;  { CASE ch }
  750.             GetNextKey:
  751.                 UNTIL Done;
  752.  
  753.                 EditString:=ch;                     { Set return code }
  754.                 IF (Flags AND EdFlagTrimL)<>0 THEN  { Adjust string }
  755.                     s:=TrimL(s);
  756.                 IF (Flags AND EdFlagTrimR)<>0 THEN
  757.                     s:=TrimR(s);
  758.                 IF (Flags AND EdFlagPadL)<>0 THEN
  759.                     s:=PadL(s,width);
  760.                 IF (Flags AND EdFlagPadR)<>0 THEN
  761.                     s:=PadR(s,width);
  762.                 IF StartChar<>NUL THEN              { Replace markers }
  763.                     BEGIN
  764.                         GotoXY(SavedX-1,SavedY);
  765.                         WriteDisplay(SavedStartCh);
  766.                     END;
  767.                 IF EndChar<>NUL THEN
  768.                     BEGIN
  769.                         GotoXY(SavedX+width,SavedY);
  770.                         WriteDisplay(SavedEndCh);
  771.                     END;
  772.                 TextAttr:=SavedAttr;    { Update display in orig attribute }
  773.                 i:=1;
  774.                 ReWriteStr;
  775.                 IF (Flags AND EdFlagHideCrsr)<>0 THEN   { Restore cursor }
  776.                     HideCursor(SavedCursor);
  777.             END;  { WITH form }
  778.     END;  { EditString }
  779.  
  780.  
  781. FUNCTION EditInt(form: EditFormatRec; VAR i: LongInt; min,max: LongInt): CHAR;
  782.  
  783.     VAR
  784.         SavedInt:       LongInt;        { Saved input integer }
  785.         SavedX, SavedY: BYTE;           { Saved cursor position }
  786.         Done:           BOOLEAN;        { Loop control variable }
  787.         width,                          { Field width for edit }
  788.         decimals:       BYTE;           { Number of (assumed) decimal places }
  789.         ch:             CHAR;
  790.         s:              ConsoleStr;
  791.         x:              INTEGER;
  792.  
  793.  
  794.     FUNCTION CalcAdjustment(d: BYTE): REAL;    { Raise 10 to power d }
  795.  
  796.         VAR
  797.             r:  REAL;
  798.             k:  BYTE;
  799.  
  800.         BEGIN
  801.             IF d=0 THEN
  802.                 CalcAdjustment:=1
  803.             ELSE
  804.                 BEGIN
  805.                     r:=10.0;
  806.                     FOR k:=2 TO d DO
  807.                         r:=r*10.0;
  808.                     CalcAdjustment:=r;
  809.                 END;
  810.         END;
  811.  
  812.  
  813.     BEGIN  { EditInt }
  814.         Done:=FALSE;
  815.         SavedX:=WhereX;
  816.         SavedY:=WhereY;
  817.         SavedInt:=i;
  818.         WITH form DO
  819.             BEGIN
  820.                 AllowChars:=['0'..'9', '+', '-', '.', ',', ' '];
  821.                 s:=Format(1.0,NumFormat);   { Determine field width and }
  822.                 width:=LENGTH(s);           { no. of (assumed) decimal places }
  823.                 s:=Follow(s,'.');
  824.                 s:=Span(s,DecDigits);
  825.                 decimals:=LENGTH(s);
  826.  
  827.                 REPEAT
  828.                     s:=Format(i/CalcAdjustment(decimals),NumFormat);
  829.                     ch:=EditString(form,s,width);   { Edit string rep. of no. }
  830.                     x:=POS('-',s);                  { Check for negative no. }
  831.                     IF x=0 THEN
  832.                         x:=POS('(',s);
  833.                     WITH FormatConfig DO            { Remove signs & padding }
  834.                         s:=Remove(s,CONCAT(' ,+-()*',Fill,Currency));
  835.                     IF LENGTH(s)=0 THEN             { Allow blank for zero }
  836.                         s:='0';
  837.                     IF x<>0 THEN                    { Prefix - sign if neg. }
  838.                         s:=CONCAT('-',s);
  839.                     IF POS('.',s)=0 THEN            { Add decimal point }
  840.                         s:=CONCAT(s,'.');
  841.                     IF LENGTH(Follow(s,'.'))>decimals THEN
  842.                         SignalError(width)          { Check for excess dec. }
  843.                     ELSE
  844.                         BEGIN
  845.                             s:=CONCAT(s,
  846.                                 DuplChar('0',decimals-LENGTH(Follow(s,'.'))));
  847.                             DELETE(s,POS('.',s),1); { Add zeros/remove point }
  848.                             VAL(s,i,x);             { Convert back to number }
  849.                             IF (x=0) AND (i>=min) AND (i<=max) THEN
  850.                                 Done:=TRUE          { Exit loop if successful }
  851.                             ELSE                    { else restore original }
  852.                                 BEGIN
  853.                                     SignalError(width);
  854.                                     i:=SavedInt;
  855.                                 END;
  856.                         END;
  857.                 UNTIL Done;
  858.  
  859.                 Write(Format(i/CalcAdjustment(decimals),NumFormat));
  860.                 GotoXY(SavedX,SavedY);              { Re-format }
  861.                 EditInt:=ch;
  862.             END;  { WITH form }
  863.     END;  { EditInt }
  864.  
  865.  
  866.  
  867. FUNCTION  EditReal(form: EditFormatRec; VAR r: REAL; min, max: REAL): CHAR;
  868.  
  869.     LABEL
  870.         RepeatEdit;
  871.  
  872.     VAR
  873.         SavedReal:      REAL;           { Saved input }
  874.         SavedX,SavedY:  BYTE;           { Saved cursor position }
  875.         Done:           BOOLEAN;        { Loop control variable }
  876.         width,                          { Field width for edit }
  877.         decimals:       BYTE;           { Number of decimal places }
  878.         ch:             CHAR;
  879.         s:              ConsoleStr;
  880.         x:              INTEGER;
  881.  
  882.  
  883.     BEGIN  { EditReal }
  884.         Done:=FALSE;
  885.         SavedX:=WhereX;
  886.         SavedY:=WhereY;
  887.         SavedReal:=r;
  888.         WITH form DO
  889.             BEGIN
  890.                 s:=Format(1.0,NumFormat);   { Determine field width and }
  891.                 width:=LENGTH(s);           { number of decimal places }
  892.                 s:=Follow(s,'.');
  893.                 s:=Span(s,DecDigits);
  894.                 decimals:=LENGTH(s);
  895.                 AllowChars:=['0'..'9', '+', '-', '.', ',', ' '];
  896.                 IF decimals=0 THEN
  897.                     AllowChars:=AllowChars+['E','e'];
  898.  
  899.                 REPEAT
  900.                     IF decimals=0 THEN          { Convert to string }
  901.                         STR(r:width,s)          { Use scientific if zero }
  902.                     ELSE                        { decimals specified, else }
  903.                         s:=Format(r,NumFormat); { standard formatting }
  904.                     ch:=EditString(form,s,width);   { Edit string rep. of no. }
  905.                     s:=Remove(s,' ,');
  906.                     IF decimals<>0 THEN
  907.                         BEGIN
  908.                             x:=POS('-',s);      { Check for negative numbers }
  909.                             IF x=0 THEN
  910.                                 x:=POS('(',s);
  911.                             s:=Remove(s,CONCAT('+-()*$',PoundSign));
  912.                             IF LENGTH(s)=0 THEN     { Blank to zero }
  913.                                 s:='0';
  914.                             IF x<>0 THEN            { Add minus }
  915.                                 s:=CONCAT('-',s);
  916.                             IF LENGTH(Follow(s,'.'))>decimals THEN
  917.                                 BEGIN               { Check decimals }
  918.                                     SignalError(width);
  919.                                     GOTO RepeatEdit;
  920.                                 END;
  921.                         END;
  922.                     VAL(s,r,x);                 { Convert back }
  923.                     IF (x=0) AND (r>=min) AND (r<=max) THEN
  924.                         Done:=TRUE              { If successful, exit loop }
  925.                     ELSE                        { Otherwise, restore value }
  926.                         BEGIN
  927.                             SignalError(width);
  928.                             r:=SavedReal;
  929.                         END;
  930.             RepeatEdit:
  931.                 UNTIL Done;
  932.  
  933.                 IF decimals=0 THEN
  934.                       Write(r:width)
  935.                 ELSE
  936.                       Write(Format(r,NumFormat));   { Re-format display }
  937.                 GotoXY(SavedX,SavedY);
  938.                 EditReal:=ch;
  939.             END;  { WITH form }
  940.     END;  { EditReal }
  941.  
  942.  
  943.  
  944. FUNCTION EditDate(form: EditFormatRec; VAR Dt: DateRec): CHAR;
  945.  
  946.     VAR
  947.         s1,s2:  DateString;
  948.         ch:     CHAR;
  949.         i,x,y:  BYTE;
  950.         v:      BOOLEAN;
  951.  
  952.     BEGIN
  953.         WITH form DO                { Build list of allowable characters }
  954.             BEGIN
  955.                 AllowChars:=['0'..'9','A'..'Z','a'..'z'];
  956.                 FOR i:=1 TO LENGTH(DateParseDelims) DO
  957.                     AllowChars:=AllowChars+[DateParseDelims[i]];
  958.                 AllowChars:=AllowChars-[HT];
  959.             END;
  960.         x:=WhereX;                              { Save cursor position }
  961.         y:=WhereY;
  962.         s1:=PadL(DateStr(Dt),DateFieldSize);    { Convert date to string }
  963.         REPEAT
  964.             s2:=s1;
  965.             ch:=EditString(form,s2,DateFieldSize); { Edit string rep. }
  966.             v:=DateParse(s2,Dt);                { Validate string & convert }
  967.             IF NOT(v) THEN                      { Signal error if invalid }
  968.                 form.SignalError(DateFieldSize);
  969.         UNTIL v;
  970.         Write(PadL(DateStr(Dt),DateFieldSize));
  971.         GotoXY(x,y);
  972.         EditDate:=ch;               { Return exit-key code }
  973.     END;  { EditDate }
  974.  
  975.  
  976.  
  977. FUNCTION EditTime(form: EditFormatRec; VAR Tm: TimeRec): CHAR;
  978.  
  979.     VAR
  980.         s1,s2:  TimeString;
  981.         ch:     CHAR;
  982.         i,x,y:  BYTE;
  983.         v:      BOOLEAN;
  984.  
  985.     BEGIN
  986.         WITH form DO                { Build list of allowable characters }
  987.             BEGIN
  988.                 AllowChars:=['0'..'9','A','a','P','p','M','m'];
  989.                 FOR i:=1 TO LENGTH(TimeParseDelims) DO
  990.                     AllowChars:=AllowChars+[TimeParseDelims[i]];
  991.                 AllowChars:=AllowChars-[HT];
  992.             END;
  993.         x:=WhereX;                                  { Save cursor position }
  994.         y:=WhereY;
  995.         s1:=PadL(TimeStr(Tm),TimeFieldSize);        { Convert time to string }
  996.         REPEAT
  997.             s2:=s1;
  998.             ch:=EditString(form,s2,TimeFieldSize);  { Allow user to edit it }
  999.             v:=TimeParse(s2,Tm);                    { Validate string }
  1000.             IF NOT(v) THEN                          { Signal error if invalid }
  1001.                 form.SignalError(TimeFieldSize);
  1002.         UNTIL v;
  1003.         Write(PadL(TimeStr(Tm),TimeFieldSize));     { Re-format display }
  1004.         GotoXY(x,y);
  1005.         EditTime:=ch;               { Return exit-key code }
  1006.     END;  { EditTime }
  1007.  
  1008.  
  1009. FUNCTION  WindowResult: BYTE;   { Return last error code and reset to zero }
  1010.  
  1011.     BEGIN
  1012.         WindowResult:=ErrCode;
  1013.         ErrCode:=0;
  1014.     END;
  1015.  
  1016.  
  1017. FUNCTION ConErrorMsg(ErrNum: BYTE): ConsoleStr;
  1018.  
  1019.     CONST
  1020.         Msg:  ARRAY[0..$18] OF ConsoleStr =
  1021.                     ('Successful',
  1022.                     'Invalid co-ordinates',
  1023.                     'Invalid border co-ordinates',
  1024.                     'Invalid direction',
  1025.                     'Window is open',
  1026.                     'Window not open',
  1027.                     'Window is hidden',
  1028.                     'Window not hidden',
  1029.                     'Illegal window zero operation',
  1030.                     'Window already defined',
  1031.                     'Undefined window',
  1032.                     'Cannot return to previous window',
  1033.                     'Undefined error',
  1034.                     'Undefined error',
  1035.                     'Undefined error',
  1036.                     'Undefined error',
  1037.                     'Out of memory',
  1038.                     'Cannot access help file',
  1039.                     'Help system already initialized',
  1040.                     'Help file not found',
  1041.                     'Invalid format in help file',
  1042.                     'Invalid format for help index',
  1043.                     'Help record invalid',
  1044.                     'Help context stack overflow',
  1045.                     'Help context stack empty');
  1046.  
  1047.  
  1048.     BEGIN
  1049.         IF ErrNum<=$18 THEN
  1050.             ConErrorMsg:=Msg[ErrNum]
  1051.         ELSE
  1052.             ConErrorMsg:='Undefined error';
  1053.     END;
  1054.  
  1055.  
  1056.  
  1057. PROCEDURE WError(e: BYTE);      { Set up a windows-unit error condition }
  1058.  
  1059.     BEGIN
  1060.         ErrCode:=e;                     { Store error code }
  1061.         IF WindowCheck THEN             { If internal checking is enabled }
  1062.             BEGIN                       { signal windows error and terminate }
  1063.                 ErrorHalt:=TRUE;
  1064.                 HALT(EnhConHaltError);
  1065.             END;
  1066.     END;
  1067.  
  1068.  
  1069. {$F+}
  1070.  
  1071. PROCEDURE HError(e: BYTE);      { Set up an error condition }
  1072.  
  1073.     BEGIN
  1074.         ErrCode:=e;                 { Store error code }
  1075.         ErrorHalt:=TRUE;
  1076.         HALT(EnhConHaltError);
  1077.     END;
  1078.  
  1079. {$F-}
  1080.  
  1081.  
  1082.  
  1083. FUNCTION CalcScreenMem(X1,Y1,X2,Y2: BYTE): WORD;
  1084. { Calculate size of heap store required to save area of screen }
  1085.  
  1086.     BEGIN
  1087.         CalcScreenMem:=(X2-X1+1)*(Y2-Y1+1)*2;
  1088.     END;
  1089.  
  1090.  
  1091. PROCEDURE WriteScreen(X1,Y1,X2,Y2: BYTE; P: ScreenBlockPtr);
  1092. { Store screen area to heap }
  1093.  
  1094.     VAR
  1095.         ScrStore:   ScreenBlockPtr;
  1096.         R:          Registers;
  1097.         HeapOfs:    WORD;
  1098.         i:          WORD;
  1099.         x,y,z:      BYTE;
  1100.  
  1101.     BEGIN
  1102.         HeapOfs:=0;
  1103.         IF DirectVideo AND NOT(CheckSnow) THEN  { Access screen directly }
  1104.             BEGIN
  1105.                 ScrStore:=PTR(GetDisplayBase,0);
  1106.                 FOR y:=Y1 TO Y2 DO                  { For each row }
  1107.                     BEGIN
  1108.                         i:=(y-1)*MaxScreenX;        { Offset to start of row }
  1109.                         FOR x:=X1 TO X2 DO          { Save each chr./attr. }
  1110.                             BEGIN
  1111.                                 P^[HeapOfs]:=ScrStore^[i+(x-1)];
  1112.                                 INC(HeapOfs);
  1113.                             END;
  1114.                     END;
  1115.             END
  1116.         ELSE                                    { Use BIOS calls }
  1117.             BEGIN
  1118.                 z:=GetDisplayPage;
  1119.                 R.BH:=z;
  1120.                 R.AH:=$03;
  1121.                 INTR(BIOS_VIDEO,R);                 { Get cursor position }
  1122.                 i:=R.DX;
  1123.                 FOR y:=Y1 TO Y2 DO                  { For each row and column }
  1124.                     FOR x:=X1 TO X2 DO
  1125.                         BEGIN
  1126.                             R.BH:=z;                { Move cursor to position }
  1127.                             R.DH:=y-1;
  1128.                             R.DL:=x-1;
  1129.                             R.AH:=$02;
  1130.                             INTR(BIOS_VIDEO,R);
  1131.                             R.BH:=z;
  1132.                             R.AH:=$08;
  1133.                             INTR(BIOS_VIDEO,R);     { Read character/attr }
  1134.                             P^[HeapOfs]:=R.AX;
  1135.                             INC(HeapOfs);           { Store in heap block }
  1136.                         END;
  1137.                 R.BH:=z;
  1138.                 R.DX:=i;
  1139.                 R.AH:=$02;
  1140.                 INTR(BIOS_VIDEO,R);                 { Restore cursor location }
  1141.             END;
  1142.     END;  { WriteScreen }
  1143.  
  1144.  
  1145. PROCEDURE ReadScreen(X1,Y1,X2,Y2: BYTE; P: ScreenBlockPtr);
  1146. { Read screen area back from heap }
  1147.  
  1148.     VAR
  1149.         ScrStore:   ScreenBlockPtr;
  1150.         R:          Registers;
  1151.         HeapOfs:    WORD;
  1152.         i:          WORD;
  1153.         x,y,z:      BYTE;
  1154.  
  1155.     BEGIN
  1156.         HeapOfs:=0;
  1157.         IF DirectVideo AND NOT(CheckSnow) THEN  { Access screen directly }
  1158.             BEGIN
  1159.                 ScrStore:=PTR(GetDisplayBase,0);
  1160.                 FOR y:=Y1 TO Y2 DO                  { For each row }
  1161.                     BEGIN
  1162.                         i:=(y-1)*MaxScreenX;        { Offset to start of row }
  1163.                         FOR x:=X1 TO X2 DO          { Get each chr./attribute }
  1164.                             BEGIN
  1165.                                 ScrStore^[i+(x-1)]:=P^[HeapOfs];
  1166.                                 INC(HeapOfs);
  1167.                             END;
  1168.                     END;
  1169.             END
  1170.         ELSE                        { Use BIOS calls }
  1171.             BEGIN
  1172.               z:=GetDisplayPage;
  1173.               R.BH:=z;
  1174.               R.AH:=$03;
  1175.               INTR(BIOS_VIDEO,R);       { Save cursor position }
  1176.               i:=R.DX;
  1177.               FOR y:=Y1 TO Y2 DO        { For each row and column }
  1178.                   FOR x:=X1 TO X2 DO
  1179.                       BEGIN
  1180.                           R.BH:=z;      { Move cursor to position }
  1181.                           R.DH:=y-1;
  1182.                           R.DL:=x-1;
  1183.                           R.AH:=$02;
  1184.                           INTR(BIOS_VIDEO,R);
  1185.                           R.BH:=z;
  1186.                           R.CX:=1;
  1187.                           R.BL:=HI(P^[HeapOfs]);
  1188.                           R.AL:=LO(P^[HeapOfs]);
  1189.                           R.AH:=$09;
  1190.                           INTR(BIOS_VIDEO,R);   { Write to screen store }
  1191.                           INC(HeapOfs);
  1192.                       END;
  1193.               R.BH:=z;
  1194.               R.DX:=i;
  1195.               R.AH:=$02;
  1196.               INTR(BIOS_VIDEO,R);       { Restore original cursor location }
  1197.           END;
  1198.     END;  { ReadScreen }
  1199.  
  1200.  
  1201. PROCEDURE GetWindowDef(WindowID: BYTE; VAR d: WindowDefinition);
  1202.  
  1203.     BEGIN
  1204.         RoutineName:='GetWindowDef';
  1205.         ErrCode:=0;
  1206.         IF WindowPtr[WindowID]=NIL THEN
  1207.             WError(ConErrUndefined)             { Window must be defined }
  1208.         ELSE
  1209.             d:=WindowPtr[WindowID]^.U;
  1210.     END;
  1211.  
  1212.  
  1213. FUNCTION WindowStat(WindowID: BYTE): WindowStatus;
  1214. { Return current status of specified window }
  1215.  
  1216.     BEGIN
  1217.         ErrCode:=0;
  1218.         IF WindowPtr[WindowID]=NIL THEN
  1219.             WindowStat:=Undefined
  1220.         ELSE
  1221.             WITH WindowPtr[WindowID]^ DO
  1222.                 IF (SysFlags AND SysFlagOpen)=0 THEN
  1223.                     WindowStat:=Closed
  1224.                 ELSE
  1225.                     IF (SysFlags AND SysFlagHidden)=0 THEN
  1226.                         WindowStat:=Open
  1227.                     ELSE
  1228.                         WindowStat:=Hidden;
  1229.         IF WindowID=ActiveWindow THEN
  1230.             WindowStat:=Active;
  1231.     END;
  1232.  
  1233.  
  1234. FUNCTION CurrentWindow: BYTE;
  1235.  
  1236.     BEGIN
  1237.         ErrCode:=0;
  1238.         CurrentWindow:=ActiveWindow;
  1239.     END;
  1240.  
  1241.  
  1242. PROCEDURE DefineWindow(WindowID: BYTE; d: WindowDefinition);
  1243.  
  1244.     BEGIN
  1245.         RoutineName:='DefineWindow';
  1246.         ErrCode:=0;
  1247.         IF WindowID=0 THEN                  { Can't define window zero }
  1248.             BEGIN
  1249.                 WError(ConErrZero);
  1250.                 EXIT;
  1251.             END;
  1252.         IF WindowPtr[WindowID]<>NIL THEN    { Check for already defined }
  1253.             BEGIN
  1254.                 WError(ConErrDefined);
  1255.                 EXIT;
  1256.             END;
  1257.         WITH d DO
  1258.             BEGIN
  1259.                 IF (X1<1) OR (Y1<1) OR (X2>MaxScreenX) OR (Y2>MaxScreenY) OR
  1260.                    (X2<X1) OR (Y2<Y1) THEN
  1261.                     BEGIN
  1262.                         WError(ConErrXY);   { Check for invalid co-ordinates }
  1263.                         EXIT;
  1264.                     END;
  1265.                 IF ((Flags AND WFlagShowBrdr)<>0) AND
  1266.                    (((X2-X1)<2) OR ((Y2-Y1)<2)) THEN
  1267.                     BEGIN
  1268.                         WError(ConErrBorderXY);
  1269.                         EXIT;
  1270.                     END;
  1271.             END;
  1272.         NEW(WindowPtr[WindowID]);           { Allocate WDR on heap }
  1273.         IF WindowPtr[WindowID]=NIL THEN
  1274.             BEGIN
  1275.                 WError(ConErrHeap);
  1276.                 EXIT;
  1277.             END;
  1278.         WITH WindowPtr[WindowID]^ DO
  1279.             BEGIN
  1280.                 U:=d;                       { Transfer user window into WDR }
  1281.                 SaveScreen:=NIL;            { No saved-screen block allocated }
  1282.                 SysFlags:=0;                { Clear all system flags in WDR }
  1283.             END;
  1284.     END;  { DefineWindow }
  1285.  
  1286.  
  1287. PROCEDURE PurgeWindow(WindowID: BYTE);
  1288.  
  1289.     BEGIN
  1290.         RoutineName:='PurgeWindow';
  1291.         ErrCode:=0;
  1292.         IF WindowID=0 THEN
  1293.             BEGIN
  1294.                 WError(ConErrZero);             { Can't purge window zero }
  1295.                 EXIT;
  1296.             END;
  1297.         IF WindowPtr[WindowID]=NIL THEN
  1298.             BEGIN
  1299.                 WError(ConErrUndefined);        { Window must be defined }
  1300.                 EXIT;
  1301.             END;
  1302.         IF (WindowPtr[WindowID]^.SysFlags AND SysFlagOpen)<>0 THEN
  1303.             BEGIN
  1304.                 WError(ConErrOpen);             { Window must be closed }
  1305.                 EXIT;
  1306.             END;
  1307.         DISPOSE(WindowPtr[WindowID]);
  1308.         WindowPtr[WindowID]:=NIL;
  1309.     END;  { PurgeWindow }
  1310.  
  1311.  
  1312.  
  1313. PROCEDURE DrawBorder(d: WindowDefinition);
  1314. { Draws border for window.  Assumes window co-ordinates already set. }
  1315.  
  1316.     VAR
  1317.         i,p:    BYTE;
  1318.         a,b:    BYTE;
  1319.         s:      ConsoleStr;
  1320.  
  1321.  
  1322.     PROCEDURE WriteScrBIOS (ch: CHAR; count: WORD; x, y: BYTE);
  1323.     { Calls BIOS to write count copies of ch to screen using BorderAttr }
  1324.     { attribute and starting at cursor position x, y }
  1325.  
  1326.         VAR
  1327.             R:  Registers;
  1328.  
  1329.         BEGIN
  1330.             GotoXY(x,y);
  1331.             R.BH:=p;
  1332.             R.AL:=ORD(ch);
  1333.             R.BL:=d.BorderAttr;
  1334.             R.CX:=count;
  1335.             R.AH:=$09;
  1336.             INTR(BIOS_VIDEO,R);
  1337.         END;
  1338.  
  1339.  
  1340.     BEGIN  { DrawBorder }
  1341.         p:=GetDisplayPage;
  1342.         WITH d DO
  1343.             BEGIN
  1344.                 a:=X2-X1+1;
  1345.                 b:=Y2-Y1+1;
  1346.                 WriteScrBIOS(Border[1],1,1,1);          { Top left corner }
  1347.                 WriteScrBIOS(Border[3],1,a,1);          { Top right corner }
  1348.                 WriteScrBIOS(Border[5],1,a,b);          { Bottom right corner }
  1349.                 WriteScrBIOS(Border[7],1,1,b);          { Bottom left corner }
  1350.                 FOR i:=2 TO (Y2-Y1) DO
  1351.                     BEGIN
  1352.                         WriteScrBIOS(Border[4],1,a,i);  { Right-hand side }
  1353.                         WriteScrBIOS(Border[8],1,1,i);  { Left-hand side }
  1354.                     END;
  1355.                 WriteScrBIOS(Border[2],a-2,2,1);        { Top border }
  1356.                 WriteScrBIOS(Border[6],a-2,2,b);        { Bottom border }
  1357.                 TextAttr:=HdrAttr;                      { Header text }
  1358.                 s:=TruncR(HdrText,a-2);
  1359.                 CASE HdrPos OF
  1360.                     WJustLeft:      GotoXY(2,1);
  1361.                     WJustCenter:    GotoXY((((a-2)-LENGTH(s)) DIV 2)+2,1);
  1362.                     WJustRight:     GotoXY(a-LENGTH(s),1);
  1363.                 END;
  1364.                 WRITE(s);
  1365.                 TextAttr:=FtrAttr;                      { Footer text }
  1366.                 s:=TruncR(FtrText,a-2);
  1367.                 CASE FtrPos OF
  1368.                     WJustLeft:      GotoXY(2,b);
  1369.                     WJustCenter:    GotoXY((((a-2)-LENGTH(s)) DIV 2)+2,b);
  1370.                     WJustRight:     GotoXY(a-LENGTH(s),b);
  1371.                 END;
  1372.                 WRITE(s);
  1373.             END;
  1374.     END;  { DrawBorder }
  1375.  
  1376.  
  1377. PROCEDURE ClrScrArea(X1,Y1,X2,Y2: BYTE; A: BYTE);
  1378. { Clears screen area specified to attribute value in A }
  1379. { Leaves window definition, attribute, and cursor position unchanged }
  1380.  
  1381.     VAR
  1382.         SaveA,SaveX1,SaveY1,SaveX2,SaveY2,SaveX,SaveY:  BYTE;
  1383.  
  1384.     BEGIN
  1385.         SaveA:=TextAttr;
  1386.         SaveX:=WhereX;
  1387.         SaveY:=WhereY;
  1388.         SaveX1:=LO(WindMin)+1;      { Save current window co-ordinates and }
  1389.         SaveY1:=HI(WindMin)+1;      { cursor position }
  1390.         SaveX2:=LO(WindMax)+1;
  1391.         SaveY2:=HI(WindMax)+1;
  1392.         WINDOW(X1,Y1,X2,Y2);        { Set co-ordinates to window to clear }
  1393.         TextAttr:=A;
  1394.         ClrScr;                     { Clear window, then restore everything }
  1395.         WINDOW(SaveX1,SaveY1,SaveX2,SaveY2);
  1396.         GotoXY(SaveX,SaveY);
  1397.         TextAttr:=SaveA;
  1398.     END;
  1399.  
  1400.  
  1401.  
  1402. PROCEDURE OpenWindow(WindowID: BYTE);
  1403.  
  1404.     BEGIN
  1405.         RoutineName:='OpenWindow';
  1406.         ErrCode:=0;
  1407.         IF WindowID=0 THEN                  { Trap calls for window zero }
  1408.             BEGIN
  1409.                 WError(ConErrZero);
  1410.                 EXIT;
  1411.             END;
  1412.         IF WindowPtr[WindowID]=NIL THEN     { Check that window is defined }
  1413.             BEGIN
  1414.                 WError(ConErrUndefined);
  1415.                 EXIT;
  1416.             END;
  1417.         IF (WindowPtr[WindowID]^.SysFlags AND SysFlagOpen)<>0 THEN
  1418.             BEGIN
  1419.                 WError(ConErrOpen);         { Check window not already open }
  1420.                 EXIT;
  1421.             END;
  1422.         WITH WindowPtr[ActiveWindow]^ DO    { Save current window details }
  1423.             BEGIN
  1424.                 SavePosX:=WhereX;
  1425.                 SavePosY:=WhereY;
  1426.                 SaveCrsrHide:=CursorHidden;
  1427.                 SaveCrsrSize:=GetCursor;
  1428.                 SaveAttr:=TextAttr;
  1429.             END;
  1430.         WITH WindowPtr[WindowID]^,U DO      { Set up new window }
  1431.             BEGIN
  1432.                 IF (Flags AND WFlagRestore)<>0 THEN     
  1433.                     BEGIN                   { Save screen if necessary }
  1434.                         GETMEM(SaveScreen,CalcScreenMem(X1,Y1,X2,Y2));
  1435.                         IF SaveScreen=NIL THEN
  1436.                             BEGIN
  1437.                                 WError(ConErrHeap);
  1438.                                 EXIT;
  1439.                             END;
  1440.                         WriteScreen(X1,Y1,X2,Y2,SaveScreen);
  1441.                     END;
  1442.                 WINDOW(X1,Y1,X2,Y2);        { Set new co-ordinates for window }
  1443.                 TextAttr:=DefaultAttr;      { Set default cursor & text attr. }
  1444.                 SetCursor(DefaultCrsrSize);
  1445.                 HideCursor(DefaultCrsrHide);
  1446.                 IF (Flags AND WFlagClrOpen)<>0 THEN     
  1447.                     CLRSCR;                 { Clear window if required }
  1448.                 IF (Flags AND WFlagShowBrdr)<>0 THEN    
  1449.                     BEGIN                   { Draw border if required }
  1450.                         DrawBorder(WindowPtr[WindowID]^.U);
  1451.                         IF (Flags AND WFlagWriteBrdr)=0 THEN
  1452.                             WINDOW(X1+1,Y1+1,X2-1,Y2-1);
  1453.                         TextAttr:=DefaultAttr;
  1454.                     END;
  1455.                 PrevWindow:=ActiveWindow;   { Save for close routine }
  1456.                 SysFlags:=SysFlagOpen;      { Flag window as open }
  1457.             END;  { WITH WindowPtr[WindowID]^,U }
  1458.         GotoXY(1,1);
  1459.         ActiveWindow:=WindowID;             { New window is now active }
  1460.     END;  { OpenWindow }
  1461.  
  1462.  
  1463. PROCEDURE SelectWindow(WindowID: BYTE);
  1464.  
  1465.     BEGIN
  1466.         RoutineName:='SelectWindow';
  1467.         ErrCode:=0;
  1468.         IF WindowPtr[WindowID]=NIL THEN         { Check for window is defined }
  1469.             BEGIN
  1470.                 WError(ConErrUndefined);
  1471.                 EXIT;
  1472.             END;
  1473.         WITH WindowPtr[WindowID]^ DO
  1474.             BEGIN
  1475.                 IF (SysFlags AND SysFlagOpen)=0 THEN
  1476.                     BEGIN                       { Check that window is open }
  1477.                         WError(ConErrClosed);
  1478.                         EXIT;
  1479.                     END;
  1480.                 IF (SysFlags AND SysFlagHidden)<>0 THEN
  1481.                     BEGIN                       { Check window is not hidden }
  1482.                         WError(ConErrHidden);
  1483.                         EXIT;
  1484.                     END;
  1485.             END;
  1486.         WITH WindowPtr[ActiveWindow]^ DO        { Save current cursor & attr. }
  1487.             BEGIN
  1488.                 SavePosX:=WhereX;
  1489.                 SavePosY:=WhereY;
  1490.                 SaveCrsrHide:=CursorHidden;
  1491.                 SaveCrsrSize:=GetCursor;
  1492.                 SaveAttr:=TextAttr;
  1493.             END;
  1494.         WITH WindowPtr[WindowID]^,U DO          { Set up for new window }
  1495.             BEGIN
  1496.                 IF ((Flags AND WFlagWriteBrdr)<>0) OR
  1497.                    ((Flags AND WFlagShowBrdr)=0) THEN
  1498.                     WINDOW(X1,Y1,X2,Y2)
  1499.                 ELSE
  1500.                     WINDOW(X1+1,Y1+1,X2-1,Y2-1);
  1501.                 TextAttr:=SaveAttr;
  1502.                 HideCursor(SaveCrsrHide);
  1503.                 SetCursor(SaveCrsrSize);
  1504.                 GotoXY(SavePosX,SavePosY);
  1505.             END;
  1506.         ActiveWindow:=WindowID;
  1507.     END;  { SelectWindow }
  1508.  
  1509.  
  1510. PROCEDURE CloseWindow(WindowID: BYTE);
  1511.  
  1512.     BEGIN
  1513.         RoutineName:='CloseWindow';
  1514.         ErrCode:=0;
  1515.         IF WindowID=0 THEN                  { Can't close window zero }
  1516.             BEGIN
  1517.                 WError(ConErrZero);
  1518.                 EXIT;
  1519.             END;
  1520.         IF WindowPtr[WindowID]=NIL THEN     { Can't close an undefined window }
  1521.             BEGIN
  1522.                 WError(ConErrUndefined);
  1523.                 EXIT;
  1524.             END;
  1525.         WITH WindowPtr[WindowID]^,U DO
  1526.             BEGIN
  1527.                 IF (SysFlags AND SysFlagOpen)=0 THEN
  1528.                     BEGIN
  1529.                         WError(ConErrClosed);   { Window must be open }
  1530.                         EXIT;
  1531.                     END;
  1532.  
  1533.                 { If current, return to previous window }
  1534.                 IF WindowID=ActiveWindow THEN
  1535.                     IF WindowStat(PrevWindow)=Open THEN
  1536.                         SelectWindow(PrevWindow)
  1537.                     ELSE
  1538.                         BEGIN
  1539.                             WError(ConErrReturn);
  1540.                             EXIT;
  1541.                         END;
  1542.  
  1543.                 IF ((Flags AND WFlagClrClose)<>0) AND
  1544.                    ((SysFlags AND SysFlagHidden)=0) THEN
  1545.                     ClrScrArea(X1,Y1,X2,Y2,DefaultAttr);
  1546.                 IF SaveScreen<>NIL THEN     { Restore saved screen }
  1547.                     BEGIN
  1548.                         IF (SysFlags AND SysFlagHidden)=0 THEN
  1549.                             ReadScreen(X1,Y1,X2,Y2,SaveScreen);
  1550.                         FREEMEM(SaveScreen,CalcScreenMem(X1,Y1,X2,Y2));
  1551.                         SaveScreen:=NIL;
  1552.                     END;
  1553.                 SysFlags:=0;
  1554.             END;
  1555.     END;  { CloseWindow }
  1556.  
  1557.  
  1558. PROCEDURE HideWindow(WindowID: BYTE);
  1559.  
  1560.     VAR
  1561.         s:  ScreenBlockPtr;
  1562.  
  1563.     BEGIN
  1564.         RoutineName:='HideWindow';
  1565.         ErrCode:=0;
  1566.         IF WindowID=0 THEN                  { Can't hide window zero }
  1567.             BEGIN
  1568.                 WError(ConErrZero);
  1569.                 EXIT;
  1570.             END;
  1571.         IF WindowPtr[WindowID]=NIL THEN
  1572.             BEGIN
  1573.                 WError(ConErrUndefined);    { Window must be defined }
  1574.                 EXIT;
  1575.             END;
  1576.         WITH WindowPtr[WindowID]^,U DO      { Must be open and not hidden }
  1577.             BEGIN
  1578.                 IF (SysFlags AND SysFlagOpen)=0 THEN
  1579.                     BEGIN
  1580.                         WError(ConErrClosed);
  1581.                         EXIT;
  1582.                     END;
  1583.                 IF (SysFlags AND SysFlagHidden)<>0 THEN
  1584.                     BEGIN
  1585.                         WError(ConErrHidden);
  1586.                         EXIT;
  1587.                     END;
  1588.                 GETMEM(s,CalcScreenMem(X1,Y1,X2,Y2));   { Allocate block }
  1589.                 IF s=NIL THEN
  1590.                     BEGIN
  1591.                         WError(ConErrHeap); { Check for out-of-memory }
  1592.                         EXIT;
  1593.                     END;
  1594.                 IF WindowID=ActiveWindow THEN
  1595.                     SelectWindow(0);        { Select window zero if active }
  1596.                 WriteScreen(X1,Y1,X2,Y2,s); { Save window contents on heap }
  1597.                 IF (Flags AND WFlagClrHide)<>0 THEN     { Clear if required }
  1598.                     ClrScrArea(X1,Y1,X2,Y2,DefaultAttr);
  1599.                 IF SaveScreen<>NIL THEN
  1600.                     BEGIN
  1601.                         ReadScreen(X1,Y1,X2,Y2,SaveScreen);
  1602.                         FREEMEM(SaveScreen,CalcScreenMem(X1,Y1,X2,Y2));
  1603.                     END;
  1604.                 SaveScreen:=s;       { Set WDR ptr to saved window; set flag }
  1605.                 SysFlags:=SysFlags OR SysFlagHidden;
  1606.             END;
  1607.     END;  { HideWindow }
  1608.  
  1609.  
  1610. PROCEDURE ShowWindow(WindowID: BYTE);
  1611.  
  1612.     VAR
  1613.         s:  ScreenBlockPtr;
  1614.  
  1615.     BEGIN
  1616.         RoutineName:='ShowWindow';
  1617.         ErrCode:=0;
  1618.         IF WindowID=0 THEN                      { Not valid for window zero }
  1619.             BEGIN
  1620.                 WError(ConErrZero);
  1621.                 EXIT;
  1622.             END;
  1623.         IF WindowPtr[WindowID]=NIL THEN         { Window must be defined }
  1624.             BEGIN
  1625.                 WError(ConErrUndefined);
  1626.                 EXIT;
  1627.             END;
  1628.         WITH WindowPtr[WindowID]^,U DO
  1629.             BEGIN
  1630.                 IF (SysFlags AND SysFlagOpen)=0 THEN
  1631.                     BEGIN
  1632.                         WError(ConErrClosed);   { Check that window is open }
  1633.                         EXIT;
  1634.                     END;
  1635.                 IF (SysFlags AND SysFlagHidden)=0 THEN
  1636.                     BEGIN
  1637.                         WError(ConErrNotHidden);    { Check window is hidden }
  1638.                         EXIT;
  1639.                     END;
  1640.                 IF (Flags AND WFlagRestore)<>0 THEN { Save screen if required }
  1641.                     BEGIN
  1642.                         GETMEM(s,CalcScreenMem(X1,Y1,X2,Y2));
  1643.                         IF s=NIL THEN
  1644.                             BEGIN
  1645.                                 WError(ConErrHeap); { Check for out-of-memory }
  1646.                                 EXIT;
  1647.                             END;
  1648.                         WriteScreen(X1,Y1,X2,Y2,s);
  1649.                     END
  1650.                 ELSE
  1651.                     s:=NIL;
  1652.                 ReadScreen(X1,Y1,X2,Y2,SaveScreen); { Restore window }
  1653.                 FREEMEM(SaveScreen,CalcScreenMem(X1,Y1,X2,Y2));
  1654.                 SaveScreen:=s;
  1655.                 SysFlags:=SysFlags AND (NOT(SysFlagHidden));
  1656.             END;
  1657.     END;  { ShowWindow }
  1658.  
  1659.  
  1660. PROCEDURE RelocateWindow(WindowID: BYTE; X, Y: BYTE);
  1661.  
  1662.     VAR
  1663.         WindowWidth,
  1664.         WindowHeight:   BYTE;
  1665.         RelocateStat:   WindowStatus;
  1666.         s:              ScreenBlockPtr;
  1667.  
  1668.  
  1669.     PROCEDURE StoreNewXY;
  1670.     { Stores new top-left co-ordinates in specified WDR }
  1671.     { Adjusts bottom-right co-ordinates to keep window size the same }
  1672.  
  1673.         BEGIN
  1674.             WITH WindowPtr[WindowID]^,U DO
  1675.                 BEGIN
  1676.                     X1:=X;
  1677.                     Y1:=Y;
  1678.                     X2:=X+WindowWidth;
  1679.                     Y2:=Y+WindowHeight;
  1680.                 END;
  1681.         END;
  1682.  
  1683.  
  1684.     BEGIN  { RelocateWindow }
  1685.         RoutineName:='RelocateWindow';
  1686.         ErrCode:=0;
  1687.         IF WindowID=0 THEN                  { Can't relocate window zero }
  1688.             BEGIN
  1689.                 WError(ConErrZero);
  1690.                 EXIT;
  1691.             END;
  1692.         IF WindowPtr[WindowID]=NIL THEN     { Window must be defined }
  1693.             BEGIN
  1694.                 WError(ConErrUndefined);
  1695.                 EXIT;
  1696.             END;
  1697.         WITH WindowPtr[WindowID]^,U DO      { Calc. window size and check }
  1698.             BEGIN
  1699.                 WindowWidth:=X2-X1;
  1700.                 WindowHeight:=Y2-Y1;
  1701.             END;
  1702.         IF (X<1) OR (Y<1) OR
  1703.            ((X+WindowWidth)>MaxScreenX) OR ((Y+WindowHeight)>MaxScreenY) THEN
  1704.             BEGIN
  1705.                 WError(ConErrXY);
  1706.                 EXIT;
  1707.             END;
  1708.         RelocateStat:=WindowStat(WindowID);
  1709.         IF RelocateStat<Open THEN           { If closed/hidden, store new XY }
  1710.             StoreNewXY
  1711.         ELSE                                { If on-screen, remove it, store }
  1712.             WITH WindowPtr[WindowID]^,U DO  { new XY, then redisplay }
  1713.               BEGIN
  1714.                   GETMEM(s,CalcScreenMem(X1,Y1,X2,Y2));
  1715.                   IF s=NIL THEN
  1716.                       BEGIN
  1717.                           WError(ConErrHeap);
  1718.                           EXIT;
  1719.                       END;
  1720.                   WriteScreen(X1,Y1,X2,Y2,s);
  1721.                   IF (Flags AND WFlagClrHide)<>0 THEN
  1722.                       ClrScrArea(X1,Y1,X2,Y2,DefaultAttr);
  1723.                   IF SaveScreen<>NIL THEN
  1724.                       ReadScreen(X1,Y1,X2,Y2,SaveScreen);
  1725.                   StoreNewXY;
  1726.                   IF SaveScreen<>NIL THEN
  1727.                       WriteScreen(X1,Y1,X2,Y2,SaveScreen);
  1728.                   ReadScreen(X1,Y1,X2,Y2,s);
  1729.                   FREEMEM(s,CalcScreenMem(X1,Y1,X2,Y2));
  1730.                   IF RelocateStat=Active THEN
  1731.                       SelectWindow(WindowID);
  1732.               END;
  1733.     END;  { RelocateWindow }
  1734.  
  1735.  
  1736. PROCEDURE MoveWindow(WindowID: BYTE; Direction: WindowMovement);
  1737.  
  1738.     CONST
  1739.         RtnName = 'MoveWindow';
  1740.  
  1741.     VAR
  1742.         x,y:            BYTE;
  1743.         SaveErrCheck:   BOOLEAN;
  1744.  
  1745.     BEGIN
  1746.         RoutineName:=RtnName;
  1747.         ErrCode:=0;
  1748.         IF WindowID=0 THEN                  { Can't move window zero }
  1749.             BEGIN
  1750.                 WError(ConErrZero);
  1751.                 EXIT;
  1752.             END;
  1753.         IF WindowPtr[WindowID]=NIL THEN     { Window must be defined }
  1754.             BEGIN
  1755.                 WError(ConErrUndefined);
  1756.                 EXIT;
  1757.             END;
  1758.         x:=0;                               { Error trap value }
  1759.         WITH WindowPtr[WindowID]^,U DO
  1760.             CASE Direction OF               { Set new top-left co-ordinates }
  1761.                 WMoveLeft:  IF X1>1 THEN
  1762.                                 BEGIN
  1763.                                     x:=X1-1;
  1764.                                     y:=Y1;
  1765.                                 END;
  1766.                 WMoveRight: IF X2<MaxScreenX THEN
  1767.                                 BEGIN
  1768.                                     x:=X1+1;
  1769.                                     y:=Y1;
  1770.                                 END;
  1771.                 WMoveUp:    IF Y1>1 THEN
  1772.                                 BEGIN
  1773.                                     x:=X1;
  1774.                                     y:=Y1-1;
  1775.                                 END;
  1776.                 WMoveDown:  IF Y2<MaxScreenY THEN
  1777.                                 BEGIN
  1778.                                     x:=X1;
  1779.                                     y:=Y1+1;
  1780.                                 END;
  1781.             END;  { CASE Direction }
  1782.         IF x=0 THEN
  1783.             BEGIN
  1784.                 WError(ConErrMove);         { Check for move errors }
  1785.                 EXIT;
  1786.             END;
  1787.         SaveErrCheck:=WindowCheck;      { Save WindowCheck and set false so }
  1788.         WindowCheck:=FALSE;             { RelocateWindow cannot cause error }
  1789.         RelocateWindow(WindowID,x,y);   { Call RelocateWindow to move window }
  1790.         WindowCheck:=SaveErrCheck;      { Restore setting of WindowCheck }
  1791.         IF ErrCode<>0 THEN
  1792.             BEGIN
  1793.                 RoutineName:=RtnName;   { If failed, generate an error }
  1794.                 WError(ErrCode);
  1795.             END;
  1796.     END;  { MoveWindow }
  1797.  
  1798.  
  1799.  
  1800. PROCEDURE WriteWindow(s: ConsoleStr);
  1801.  
  1802.     VAR
  1803.         i,j:    BYTE;
  1804.         k:      WORD;
  1805.         w:      ScreenBlockPtr;
  1806.  
  1807.     BEGIN
  1808.         RoutineName:='WriteWindow';
  1809.         ErrCode:=0;
  1810.         s:=TruncR(s,LO(WindMax)-LO(WindMin)-WhereX+2);  { Limit string length }
  1811.         IF LENGTH(s)=0 THEN EXIT;                       { Trap null string }
  1812.         GETMEM(w,LENGTH(s)*2);                          { Allocate heap }
  1813.         IF w=NIL THEN
  1814.             BEGIN
  1815.                 WError(ConErrHeap);
  1816.                 EXIT;
  1817.             END;
  1818.         k:=TextAttr SHL 8;
  1819.         FOR i:=1 TO LENGTH(s) DO                    { Build in memory }
  1820.             w^[i-1]:=ORD(s[i])+k;
  1821.         i:=LO(WindMin)+WhereX;
  1822.         j:=HI(WindMin)+WhereY;
  1823.         ReadScreen(i,j,i+LENGTH(s)-1,j,w);          { Read block & discard }
  1824.         FREEMEM(w,LENGTH(s)*2);
  1825.     END;  { WriteWindow }
  1826.  
  1827.  
  1828. PROCEDURE DisposeAll;
  1829. { Throws away all heap-allocated storage }
  1830.  
  1831.     VAR
  1832.         i:  BYTE;
  1833.  
  1834.     BEGIN
  1835.         FOR i:=0 TO 255 DO                      { Look at each pointer }
  1836.             IF WindowPtr[i]<>NIL THEN           { If window is defined }
  1837.                 BEGIN
  1838.                     WITH WindowPtr[i]^,U DO     { Dispose of screen block }
  1839.                         IF SaveScreen<>NIL THEN
  1840.                             FREEMEM(SaveScreen,CalcScreenMem(X1,Y1,X2,Y2));
  1841.                         DISPOSE(WindowPtr[i]);  { Dispose of WDR }
  1842.                         WindowPtr[i]:=NIL;
  1843.                 END;
  1844.     END;
  1845.  
  1846.  
  1847.  
  1848. PROCEDURE Initialize;
  1849. { Called at start-up and after a call to TextMode }
  1850.  
  1851.     VAR
  1852.         i:  BYTE;
  1853.  
  1854.     BEGIN
  1855.         RoutineName:='initialization code';
  1856.         ErrCode:=0;
  1857.         MaxScreenX:=LO(WindMax)+1;          { Save max. screen co-ordinates }
  1858.         MaxScreenY:=HI(WindMax)+1;
  1859.         IF MaxScreenX=40 THEN               { Calculate base address }
  1860.             DisplayBase:=GetDisplayPage*$0080+$B000
  1861.         ELSE
  1862.             DisplayBase:=GetDisplayPage*$0100+$B000;
  1863.         IF ColorDisplay THEN
  1864.             DisplayBase:=DisplayBase+$0800;
  1865.         CASE GAcheck OF                     { Check display adapter }
  1866.             0:  CGAcursor:=ColorDisplay;
  1867.             1:  CGAcursor:=TRUE;
  1868.             2:  CGAcursor:=FALSE;
  1869.         END;
  1870.         IF CGAcursor THEN                   { Set default cursor values }
  1871.             BEGIN
  1872.                 LineCrsr:=$0607;
  1873.                 BlockCrsr:=$0107;
  1874.             END
  1875.         ELSE
  1876.             BEGIN
  1877.                 LineCrsr:=$0B0C;
  1878.                 BlockCrsr:=$010C;
  1879.             END;
  1880.         OrigCursorSize:=GetCursor;          { Store cursor size for exit }
  1881.         OrigCursorHide:=CursorHidden;
  1882.         FOR i:=1 TO 255 DO                  { Set all window pointers to nil }
  1883.             WindowPtr[i]:=NIL;
  1884.         NEW(WindowPtr[0]);
  1885.         IF WindowPtr[0]=NIL THEN
  1886.             BEGIN
  1887.                 WError(ConErrHeap);
  1888.                 EXIT;
  1889.             END;
  1890.         WITH WindowPtr[0]^ DO               { Set up window-zero WDR }
  1891.             BEGIN
  1892.                 WITH U DO
  1893.                     BEGIN
  1894.                         X1:=1;
  1895.                         Y1:=1;
  1896.                         X2:=MaxScreenX;
  1897.                         Y2:=MaxScreenY;
  1898.                         DefaultAttr:=TextAttr;
  1899.                         DefaultCrsrHide:=FALSE;
  1900.                         DefaultCrsrSize:=WCrsrDefault;
  1901.                         Flags:=0;
  1902.                     END;
  1903.                 SaveScreen:=NIL;
  1904.                 SysFlags:=SysFlagOpen;
  1905.             END;
  1906.         ClrScr;
  1907.         ActiveWindow:=0;                    { Assume window zero active }
  1908.     END;  { Initialize }
  1909.  
  1910.  
  1911. {$F+}
  1912.  
  1913. PROCEDURE ExitRestore;          { Unit's exit handler }
  1914.  
  1915.     BEGIN
  1916.         ExitProc:=ExitSave;                 { Restore exit chain pointer }
  1917.         IF HelpInitialized THEN
  1918.             HelpReset;
  1919.         DisposeAll;                         { Throw away all WDRs }
  1920.         WINDOW(1,1,MaxScreenX,MaxScreenY);  { Screen to full size }
  1921.         GotoXY(1,MaxScreenY);
  1922.         OrigCursor;
  1923.         IF ErrorHalt THEN                   { If exit due to error }
  1924.             BEGIN                           { display an error message }
  1925.                 TextAttr:=MonoNormal;
  1926.                 WRITELN;
  1927.                 WRITELN('ENHCON unit run-time error ',HexStr(ErrCode,2));
  1928.                 WRITELN(ConErrorMsg(ErrCode),' in ',RoutineName);
  1929.             END;
  1930.     END;
  1931.  
  1932. {$F-}
  1933.  
  1934.  
  1935. PROCEDURE ClearHelpPointers;
  1936. { Initialize all help storage pointers to nil }
  1937.          
  1938.     VAR
  1939.         k: WORD;
  1940.  
  1941.     BEGIN
  1942.         FOR k:=1 to 1000 DO
  1943.             HelpStore[k]:=NIL;
  1944.     END;
  1945.  
  1946.  
  1947. PROCEDURE DisposeHelpStore;
  1948. { Disposes of dynamically allocated help store and resets pointers }
  1949.  
  1950.     VAR
  1951.         k:  WORD;
  1952.  
  1953.     BEGIN
  1954.         FOR k:=1 TO 1000 DO
  1955.             IF HelpStore[k]<>NIL THEN
  1956.                 BEGIN
  1957.                     DISPOSE(HelpStore[k]);
  1958.                     HelpStore[k]:=NIL;
  1959.                 END;
  1960.     END;
  1961.  
  1962.  
  1963. PROCEDURE HelpReset;
  1964.  
  1965.     VAR
  1966.         SaveWindowCheck:    BOOLEAN;
  1967.         SaveRtnName:        ConsoleStr;
  1968.         SaveErrCode:        BYTE;
  1969.         i:                  BYTE;
  1970.  
  1971.     BEGIN
  1972.         SaveRtnName:=RoutineName;
  1973.         SaveErrCode:=ErrCode;
  1974.         {$I-}
  1975.         CLOSE(HelpFile);
  1976.         i:=IOResult;
  1977.         {$I+}
  1978.         DisposeHelpStore;
  1979.         SaveWindowCheck:=WindowCheck;
  1980.         WindowCheck:=FALSE;
  1981.         WITH HelpConfig DO
  1982.             BEGIN
  1983.                 CloseWindow(WindowID);
  1984.                 PurgeWindow(WindowID);
  1985.                 WindowID:=0;
  1986.             END;
  1987.         WindowCheck:=SaveWindowCheck;
  1988.         HelpInitialized:=FALSE;
  1989.         ErrCode:=SaveErrCode;
  1990.         RoutineName:=SaveRtnName;
  1991.     END;
  1992.  
  1993.  
  1994.  
  1995. PROCEDURE HelpRequest(ch: CHAR);
  1996. { Activates help system.  On entry ch must hold code for
  1997.   GeneralKey, ContextKey, or LastHelpKey }
  1998.  
  1999.     CONST
  2000.         RtnName = 'HelpRequest';
  2001.  
  2002.     VAR
  2003.         i:                  BYTE;
  2004.         UserOption:         INTEGER;
  2005.         SaveWindowCheck:    BOOLEAN;
  2006.         MoveHelp:           BOOLEAN;
  2007.  
  2008.  
  2009.     PROCEDURE UpdateHdr(SectionNum: BYTE);
  2010.     { Updates header to to reflect section name.  Zero indicates index. }
  2011.  
  2012.         VAR
  2013.               s:    ConsoleStr;
  2014.               i:    BYTE;
  2015.  
  2016.         BEGIN
  2017.             WITH HelpConfig DO
  2018.                 BEGIN
  2019.                     GotoXY(2,1);            { Position cursor & set attribs. }
  2020.                     TextAttr:=BorderAttr;
  2021.                     WRITE(DuplChar(Border[2],X2-X1-1));
  2022.                     s:=HdrText;             { Get header text }
  2023.                     IF (Flags AND HFlagTitle)<>0 THEN
  2024.                         IF SectionNum=0 THEN            { Append section }
  2025.                             s:=CONCAT(s,'Index')        { name or index }
  2026.                         ELSE
  2027.                             s:=CONCAT(s,HelpIndexStr[SectionNum]);
  2028.                     s:=TruncR(s,X2-X1-1);
  2029.                     i:=X2-X1+1;             { Rewrite header on screen }
  2030.                     CASE HdrPos OF
  2031.                         WJustLeft:    GotoXY(2,1);
  2032.                         WJustCenter:  GotoXY((((i-2)-LENGTH(s)) DIV 2)+2,1);
  2033.                         WJustRight:   GotoXY(i-LENGTH(s),1);
  2034.                     END;
  2035.                     TextAttr:=HdrAttr;
  2036.                     WRITE(s);
  2037.                 END;
  2038.         END;  { UpdateHdr }
  2039.  
  2040.  
  2041.     PROCEDURE UpdateFtr (PgInd: BYTE);
  2042.     { Writes footer to window if required, showing PgUp/PgDn indicators }
  2043.     { 0=None, 1=PgUp, 2=PgDn, 3=PgUp/PgDn }
  2044.  
  2045.         VAR
  2046.             s:    ConsoleStr;
  2047.             i,j:  BYTE;
  2048.  
  2049.         BEGIN
  2050.             WITH HelpConfig DO
  2051.                 BEGIN
  2052.                     GotoXY(2,Y2-Y1+1);  { Position cursor & set attributes }
  2053.                     TextAttr:=BorderAttr;
  2054.                     WRITE(DuplChar(Border[6],X2-X1-1));
  2055.                     s:=FtrText;         { User's text }
  2056.                     IF (Flags AND HFlagPageInd)<>0 THEN { Page indicators }
  2057.                         CASE (Flags AND HFlagPageText)*4+PgInd OF
  2058.                             1:  s:=CONCAT(s,#24,#32);
  2059.                             2:  s:=CONCAT(s,#32,#25);
  2060.                             3:  s:=CONCAT(s,#24,#25);
  2061.                             5:  s:=CONCAT(s,'PgUp');
  2062.                             6:  s:=CONCAT(s,'PgDn');
  2063.                             7:  s:=CONCAT(s,'PgUp/PgDn');
  2064.                           END;
  2065.                     IF (PgInd<>0) AND (LENGTH(FtrText)<>0) THEN
  2066.                         INSERT(#32,s,LENGTH(FtrText)+1);
  2067.                     s:=TruncR(s,X2-X1-1);   { Calc. position of footer text }
  2068.                     i:=X2-X1+1;
  2069.                     j:=Y2-Y1+1;
  2070.                     CASE FtrPos OF
  2071.                         WJustLeft:      GotoXY(2,j);
  2072.                         WJustCenter:    GotoXY((((i-2)-LENGTH(s)) DIV 2)+2,j);
  2073.                         WJustRight:     GotoXY(i-LENGTH(s),j);
  2074.                     END;
  2075.                     TextAttr:=FtrAttr;
  2076.                     WindowCheck:=FALSE;
  2077.                     WriteWindow(s);         { Display footer }
  2078.                     WindowCheck:=SaveWindowCheck;
  2079.                     RoutineName:=RtnName;
  2080.                     IF WindowResult<>0 THEN
  2081.                         BEGIN
  2082.                             HelpReset;
  2083.                             HelpError(ConErrHeap);
  2084.                             EXIT;
  2085.                         END;
  2086.                 END;  { WITH HelpConfig }
  2087.         END;  { UpdateFtr }
  2088.  
  2089.  
  2090.  
  2091.     FUNCTION ShowSection (Section: BYTE): INTEGER;
  2092.     { Displays specified help section, allowing PgUp/PgDn keys to scroll text.
  2093.       Returns 0 if exit due to general-help key, -1 if due to Escape. }
  2094.  
  2095.         VAR
  2096.             UserOption:   CHAR;     { Used to get user's response }
  2097.             SLen:         WORD;     { Length of section }
  2098.             k:            WORD;     { Top-of-window line counter }
  2099.             i,j,w:        BYTE;
  2100.             s:            ConsoleStr;
  2101.  
  2102.         BEGIN  { ShowSection }
  2103.             MoveHelp:=FALSE;
  2104.             WITH HelpConfig DO
  2105.                 BEGIN
  2106.                     UpdateHdr(Section);             { Update header }
  2107.                     SLen:=HelpSectionLen[Section];  { Get length of section }
  2108.                     {$I-}
  2109.                     SEEK(HelpFile,HelpSectionOfs[Section]); { Position file }
  2110.                     {$I+}
  2111.                     IF IOResult<>0 THEN
  2112.                         BEGIN
  2113.                             HelpReset;
  2114.                             HelpError(ConErrHelpRead);
  2115.                             EXIT;
  2116.                         END;
  2117.                     FOR k:=1 TO SLen DO             { Read section to heap }
  2118.                         BEGIN
  2119.                             {$I-}
  2120.                             READ(HelpFile,HelpVar);
  2121.                             {$I+}
  2122.                             IF IOResult<>0 THEN
  2123.                                 BEGIN
  2124.                                     HelpReset;
  2125.                                     HelpError(ConErrHelpRead);
  2126.                                     EXIT;
  2127.                                 END;
  2128.                             HelpStore[k]^:=HelpVar.HelpText;
  2129.                         END;
  2130.                     i:=Y2-Y1-1;             { Calc. no. of rows in area }
  2131.                     w:=X2-X1-1;             { Calculate maximum line length }
  2132.                     k:=1;                   { Start at 1st rec.in section }
  2133.                     REPEAT
  2134.                         TextAttr:=NormalAttr;
  2135.                         FOR j:=0 TO (i-1) DO        { Display help in window }
  2136.                             BEGIN
  2137.                                 GotoXY(2,j+2);      { Position cursor }
  2138.                                 WindowCheck:=FALSE;
  2139.                                 IF (k+j)>SLen THEN  { Display help }
  2140.                                     WriteWindow(DuplChar(#32,w))
  2141.                                 ELSE
  2142.                                     WriteWindow
  2143.                                         (TruncR(PadR(HelpStore[k+j]^,80),w));
  2144.                                 WindowCheck:=SaveWindowCheck;
  2145.                                 RoutineName:=RtnName;
  2146.                                 IF WindowResult<>0 THEN
  2147.                                     BEGIN
  2148.                                         HelpReset;
  2149.                                         HelpError(ConErrHeap);
  2150.                                         EXIT;
  2151.                                     END;
  2152.                             END;  { FOR j }
  2153.                         IF k>1 THEN     { Determine whether PgUp/PgDn allowed }
  2154.                             j:=1        { update footer accordingly }
  2155.                         ELSE
  2156.                             j:=0;
  2157.                         IF (k+i)<=SLen THEN
  2158.                             j:=j+2;
  2159.                         UpdateFtr(j);
  2160.                         UserOption:=ReadKey;
  2161.                         CASE UserOption OF
  2162.                             KeyLeft,KeyRight,KeyUp,KeyDown:
  2163.                                 IF (MoveHelp=TRUE) OR
  2164.                                     ((MoveWindowKey=HMoveScroll) AND
  2165.                                         ScrollLock) THEN
  2166.                                     BEGIN
  2167.                                         WindowCheck:=FALSE;
  2168.                                         CASE UserOption OF
  2169.                                             KeyUp:
  2170.                                                 MoveWindow(WindowID,WMoveUp);
  2171.                                             KeyDown:
  2172.                                                 MoveWindow(WindowID,WMoveDown);
  2173.                                             KeyLeft:
  2174.                                                 MoveWindow(WindowID,WMoveLeft);
  2175.                                             KeyRight:
  2176.                                                 MoveWindow(WindowID,
  2177.                                                            WMoveRight);
  2178.                                         END;
  2179.                                         j:=WindowResult;
  2180.                                         WindowCheck:=SaveWindowCheck;
  2181.                                         RoutineName:=RtnName;
  2182.                                         IF (j<>0) AND (j<>ConErrMove) THEN
  2183.                                             BEGIN
  2184.                                                 HelpReset;
  2185.                                                 IF j=ConErrHeap THEN
  2186.                                                     HelpError(ConErrHeap)
  2187.                                                 ELSE
  2188.                                                     HelpError
  2189.                                                         (ConErrHelpInvalid);
  2190.                                                 EXIT;
  2191.                                             END;
  2192.                                     END;
  2193.                             KeyPgUp:
  2194.                                 IF k>1 THEN
  2195.                                     k:=k-i;
  2196.                             KeyPgDn:
  2197.                                 IF (k+i)<=SLen THEN
  2198.                                     k:=k+i;
  2199.                             KeyHome:
  2200.                                 k:=1;
  2201.                             KeyEnd:
  2202.                                 WHILE (k+i)<=SLen DO
  2203.                                     k:=k+i;
  2204.                             ESC:
  2205.                                 ShowSection:=-1;
  2206.                           ELSE
  2207.                                 IF UserOption=GeneralKey THEN
  2208.                                     ShowSection:=0
  2209.                                 ELSE
  2210.                                     IF UserOption=MoveWindowKey THEN
  2211.                                         MoveHelp:=NOT(MoveHelp);
  2212.                         END;  { CASE UserOption }
  2213.                     UNTIL UserOption IN [GeneralKey,ESC];
  2214.                 END;  { WITH HelpConfig }
  2215.             LastHelpSec:=Section;
  2216.         END;  { ShowSection }
  2217.  
  2218.  
  2219.     FUNCTION ShowIndex: INTEGER;
  2220.     { Display help index and allow user to select required section.
  2221.       Returns section number of selected item or -1 if Escape. }
  2222.  
  2223.         VAR
  2224.             CrsrRow,
  2225.             CrsrCol:    BYTE;
  2226.             i,j,k:      BYTE;
  2227.             UserOption: CHAR;
  2228.  
  2229.  
  2230.         PROCEDURE DisplayEntry (Selected: BOOLEAN);
  2231.         { Display index entry using normal index or selected index attribute.
  2232.           Uses CrsrRow/Col and top-of-window counter k to determine which
  2233.           entry to use. }
  2234.  
  2235.             VAR
  2236.               i:    BYTE;
  2237.  
  2238.             BEGIN
  2239.                 IF Selected THEN                            { Set attributes }
  2240.                     TextAttr:=HelpConfig.SelectAttr
  2241.                 ELSE
  2242.                     TextAttr:=HelpConfig.IndexAttr;
  2243.                 GotoXY(((CrsrCol-1)*IndexColWidth)+2,CrsrRow+1);
  2244.                 i:=(CrsrCol-1)*IndexRows+(CrsrRow-1)+k;
  2245.                 IF i<=MaxHelpSec THEN                       { Display name }
  2246.                     WRITE(PadR(HelpIndexStr[i],IndexColWidth-2))
  2247.                 ELSE
  2248.                     BEGIN
  2249.                         TextAttr:=HelpConfig.NormalAttr;
  2250.                         WRITE(DuplChar(#32,IndexColWidth-2));
  2251.                     END;
  2252.               END;  { DisplayEntry }
  2253.  
  2254.  
  2255.         PROCEDURE RedrawIndex;      { Redraws current index page }
  2256.  
  2257.             VAR
  2258.                 SaveRow,
  2259.                 SaveCol:    BYTE;
  2260.                 i,j:        BYTE;
  2261.  
  2262.             BEGIN
  2263.                 SaveRow:=CrsrRow;       { Save current row/column pointers }
  2264.                 SaveCol:=CrsrCol;
  2265.                 IF k>1 THEN             { Check whether PgUp/PgDn required }
  2266.                     j:=1
  2267.                 ELSE
  2268.                     j:=0;
  2269.                 IF (IndexRows*IndexCols+k)<=MaxHelpSec THEN
  2270.                     j:=j+2;
  2271.                 UpdateFtr(j);           { Display or remove PgUp/PgDn }
  2272.                 FOR i:=1 TO IndexCols DO
  2273.                     BEGIN               { Redraw each entry within window }
  2274.                         CrsrCol:=i;
  2275.                         FOR j:=1 TO IndexRows DO
  2276.                             BEGIN
  2277.                                 CrsrRow:=j;
  2278.                                 DisplayEntry(FALSE);
  2279.                             END;
  2280.                     END;
  2281.                 CrsrRow:=SaveRow;       { Restore original row/col pointers }
  2282.                 CrsrCol:=SaveCol;
  2283.             END;  { RedrawIndex }
  2284.  
  2285.  
  2286.         PROCEDURE NextPage;     { Move to next index page }
  2287.  
  2288.             BEGIN
  2289.                 IF (IndexRows*IndexCols+k)<=MaxHelpSec THEN
  2290.                     BEGIN
  2291.                         k:=k+IndexRows*IndexCols;
  2292.                         RedrawIndex;
  2293.                         CrsrCol:=1;
  2294.                         CrsrRow:=1;
  2295.                     END;
  2296.             END;  { NextPage }
  2297.  
  2298.  
  2299.         PROCEDURE PrevPage;     { Move to previous index page }
  2300.  
  2301.             BEGIN
  2302.                 IF k>1 THEN
  2303.                     BEGIN
  2304.                         k:=k-IndexRows*IndexCols;
  2305.                         RedrawIndex;
  2306.                         CrsrCol:=IndexCols;
  2307.                         CrsrRow:=IndexRows;
  2308.                     END;
  2309.             END;  { PrevPage }
  2310.  
  2311.  
  2312.         PROCEDURE NextSection;
  2313.         { Move index highlight bar to next section, advance to
  2314.           next page if necessary }
  2315.  
  2316.             BEGIN
  2317.                 IF ((CrsrCol-1)*IndexRows+(CrsrRow-1)+k+1)<=MaxHelpSec THEN
  2318.                     BEGIN
  2319.                         INC(CrsrRow);
  2320.                         IF CrsrRow>IndexRows THEN
  2321.                             BEGIN
  2322.                                 INC(CrsrCol);
  2323.                                 CrsrRow:=1;
  2324.                                 IF CrsrCol>IndexCols THEN
  2325.                                     NextPage;
  2326.                             END;
  2327.                     END;
  2328.             END;
  2329.  
  2330.  
  2331.         PROCEDURE PrevSection;
  2332.         { Move index highlight bar to previous section, move to
  2333.           previous page if necessary }
  2334.  
  2335.             BEGIN
  2336.                 IF (CrsrCol>1) OR (CrsrRow>1) OR (k>1) THEN
  2337.                     BEGIN
  2338.                         DEC(CrsrRow);
  2339.                         IF CrsrRow=0 THEN
  2340.                             BEGIN
  2341.                                 DEC(CrsrCol);
  2342.                                 CrsrRow:=IndexRows;
  2343.                                 IF CrsrCol=0 THEN
  2344.                                     PrevPage;
  2345.                             END;
  2346.                     END;
  2347.             END;
  2348.  
  2349.  
  2350.         BEGIN  { ShowIndex }
  2351.             WITH HelpConfig DO              { Clear help window }
  2352.                 BEGIN
  2353.                     TextAttr:=NormalAttr;
  2354.                     FOR i:=2 TO (Y2-Y1) DO
  2355.                         BEGIN
  2356.                             GotoXY(2,i);
  2357.                             WRITE(DuplChar(#32,X2-X1-1));
  2358.                         END;
  2359.                 END;  { WITH HelpConfig }
  2360.             k:=1;                           { Start at top of index }
  2361.             CrsrCol:=1;
  2362.             CrsrRow:=1;                     { Position cursor on first entry }
  2363.             UpdateHdr(0);                   { Update header text }
  2364.             RedrawIndex;                    { Display first page of index }
  2365.             WITH HelpConfig DO
  2366.                 REPEAT
  2367.                     DisplayEntry(TRUE);     { Highlight entry, get user's }
  2368.                     UserOption:=ReadKey;    { option, restore entry to normal }
  2369.                     DisplayEntry(FALSE);
  2370.                     CASE UserOption OF
  2371.                         KeyUp,KeyDown,KeyLeft,KeyRight:
  2372.                             IF (MoveHelp=TRUE) OR
  2373.                                 ((MoveWindowKey=HMoveScroll) AND
  2374.                                     ScrollLock) THEN
  2375.                                 BEGIN
  2376.                                     WindowCheck:=FALSE;
  2377.                                     CASE UserOption OF
  2378.                                         KeyUp:
  2379.                                             MoveWindow(WindowID,WMoveUp);
  2380.                                         KeyDown:
  2381.                                             MoveWindow(WindowID,WMoveDown);
  2382.                                         KeyLeft:
  2383.                                             MoveWindow(WindowID,WMoveLeft);
  2384.                                         KeyRight:
  2385.                                             MoveWindow(WindowID,WMoveRight);
  2386.                                     END;
  2387.                                     j:=WindowResult;
  2388.                                     RoutineName:=RtnName;
  2389.                                     WindowCheck:=SaveWindowCheck;
  2390.                                     IF (j<>0) AND (j<>ConErrMove) THEN
  2391.                                         BEGIN
  2392.                                             HelpReset;
  2393.                                             IF j=ConErrHeap THEN
  2394.                                                 HelpError(ConErrHeap)
  2395.                                             ELSE
  2396.                                                 HelpError(ConErrHelpInvalid);
  2397.                                             EXIT;
  2398.                                         END;
  2399.                                 END
  2400.                             ELSE
  2401.                                 CASE UserOption OF
  2402.                                     KeyUp:    PrevSection;
  2403.                                     KeyDown:  NextSection;
  2404.                                     KeyLeft:  IF CrsrCol>1 THEN
  2405.                                                 DEC(CrsrCol);
  2406.                                     KeyRight:
  2407.                                         IF (CrsrCol<IndexCols) AND
  2408.                                            ((CrsrCol*IndexRows+(CrsrRow-1)+k)
  2409.                                                 <=MaxHelpSec) THEN
  2410.                                             INC(CrsrCol);
  2411.                                 END;
  2412.  
  2413.                         KeyPgUp:    PrevPage;
  2414.                         KeyPgDn:    NextPage;
  2415.  
  2416.                         KeySTab:    PrevSection;
  2417.                         HT:         NextSection;
  2418.  
  2419.                         ESC:        ShowIndex:=-1;
  2420.                     ELSE
  2421.                         IF UserOption IN [CR,ContextKey] THEN
  2422.                             ShowIndex:=(CrsrCol-1)*IndexRows+(CrsrRow-1)+k
  2423.                         ELSE
  2424.                             IF UserOption=LastHelpKey THEN
  2425.                               ShowIndex:=LastHelpSec;
  2426.                     END;  { CASE UserOption }
  2427.                 UNTIL UserOption IN [ESC,CR,ContextKey,LastHelpKey];
  2428.         END;  { ShowIndex }
  2429.  
  2430.  
  2431.  
  2432.     BEGIN  { HelpRequest }
  2433.         IF NOT (HelpInitialized) THEN       { Skip if not initialized }
  2434.             EXIT;
  2435.         RoutineName:=RtnName;
  2436.         ErrCode:=0;
  2437.         SaveWindowCheck:=WindowCheck;
  2438.         WindowCheck:=FALSE;
  2439.         WITH HelpConfig DO                  { Open window }
  2440.             BEGIN
  2441.                 OpenWindow(WindowID);
  2442.                 i:=WindowResult;
  2443.                 WindowCheck:=SaveWindowCheck;
  2444.                 RoutineName:=RtnName;
  2445.                 IF i=ConErrHeap THEN
  2446.                     BEGIN
  2447.                         HelpReset;
  2448.                         HelpError(ConErrHeap);
  2449.                         EXIT;
  2450.                     END;
  2451.                 IF i<>0 THEN
  2452.                     BEGIN
  2453.                         HelpReset;
  2454.                         RoutineName:=RtnName;
  2455.                         HelpError(ConErrHelpInvalid);
  2456.                         EXIT;
  2457.                     END;
  2458.                 IF ch=GeneralKey THEN       { Check help key }
  2459.                     UserOption:=0;
  2460.                 IF ch=LastHelpKey THEN
  2461.                     UserOption:=LastHelpSec;
  2462.                 IF ch=ContextKey THEN
  2463.                     IF HelpContext<=MaxHelpSec THEN
  2464.                       UserOption:=HelpContext
  2465.                     ELSE
  2466.                       UserOption:=0;
  2467.                 REPEAT
  2468.                     IF UserOption=0 THEN    { If section=0 show index }
  2469.                         UserOption:=ShowIndex
  2470.                     ELSE
  2471.                         UserOption:=ShowSection(UserOption);
  2472.                     IF NOT(HelpInitialized) THEN
  2473.                         EXIT;
  2474.                 UNTIL UserOption=-1;        { Loop until Esc pressed }
  2475.                 WindowCheck:=FALSE;         { Close help window }
  2476.                 CloseWindow(WindowID);
  2477.                 RoutineName:=RtnName;
  2478.                 WindowCheck:=SaveWindowCheck;
  2479.                 IF WindowResult<>0 THEN
  2480.                     BEGIN
  2481.                         HelpReset;
  2482.                         HelpError(ConErrHelpInvalid);
  2483.                     END;
  2484.             END;  { WITH HelpConfig }
  2485.     END;  { HelpRequest }
  2486.  
  2487.  
  2488. PROCEDURE PushHelpContext(NewContext: BYTE);
  2489. { Store current context value on stack, set new context value }
  2490.  
  2491.     BEGIN
  2492.         RoutineName:='PushHelpContext';
  2493.         IF NOT(HelpInitialized) THEN    { Ignore request if not installed }
  2494.             EXIT;
  2495.         IF HelpCtxIndex<>0 THEN         { Check for stack overflow }
  2496.             BEGIN                       { Add existing value to stack }
  2497.                 HelpCtxStack[HelpCtxIndex]:=HelpContext;
  2498.                 DEC(HelpCtxIndex);
  2499.                 HelpContext:=NewContext;
  2500.                 ErrCode:=0;
  2501.             END
  2502.         ELSE
  2503.             BEGIN                       { Report overflow error }
  2504.                 HelpReset;
  2505.                 HelpError(ConErrHelpStkFull);
  2506.             END;
  2507.     END;
  2508.  
  2509.  
  2510. PROCEDURE PopHelpContext;
  2511. { Retrieve context value from stack }
  2512.  
  2513.     BEGIN
  2514.         RoutineName:='PopHelpContext';
  2515.         IF NOT(HelpInitialized) THEN    { Ignore if not installed }
  2516.             EXIT;
  2517.         IF HelpCtxIndex<>128 THEN       { Check for empty stack }
  2518.             BEGIN                       { Retrieve value from stack }
  2519.                 INC(HelpCtxIndex);
  2520.                 HelpContext:=HelpCtxStack[HelpCtxIndex];
  2521.             END
  2522.         ELSE
  2523.             BEGIN                       { Report stack-empty error }
  2524.                 HelpReset;
  2525.                 HelpError(ConErrHelpStkEmpty);
  2526.             END;
  2527.     END;
  2528.  
  2529.  
  2530. PROCEDURE HelpInitialize(h: HelpConfiguration);
  2531.  
  2532.     CONST
  2533.         RtnName = 'HelpInitialize';
  2534.  
  2535.     VAR
  2536.         HelpWindow:         WindowDefinition;
  2537.         i:                  BYTE;
  2538.         k:                  WORD;
  2539.         SaveWindowCheck:    BOOLEAN;
  2540.  
  2541.     BEGIN
  2542.         RoutineName:=RtnName;
  2543.         ErrCode:=0;
  2544.         IF HelpInitialized THEN         { Check whether already initialized }
  2545.             BEGIN
  2546.                 HelpError(ConErrHelpInit);
  2547.                 EXIT;
  2548.             END;
  2549.         WITH HelpWindow DO              { Set up definition for help window }
  2550.             BEGIN
  2551.                 X1:=h.X1;
  2552.                 Y1:=h.Y1;
  2553.                 X2:=h.X2;
  2554.                 Y2:=h.Y2;
  2555.                 DefaultAttr:=h.NormalAttr;
  2556.                 DefaultCrsrSize:=WCrsrDefault;
  2557.                 DefaultCrsrHide:=TRUE;
  2558.                 Border:=h.Border;
  2559.                 BorderAttr:=h.BorderAttr;
  2560.                 HdrText:='';
  2561.                 FtrText:='';
  2562.                 Flags:=WFlagClrOpen+WFlagRestore+WFlagShowBrdr+WFlagWriteBrdr;
  2563.             END;
  2564.         HelpConfig:=h;
  2565.         SaveWindowCheck:=WindowCheck;   { Define the help window }
  2566.         WindowCheck:=FALSE;
  2567.         DefineWindow(h.WindowID,HelpWindow);
  2568.         i:=WindowResult;
  2569.         WindowCheck:=SaveWindowCheck;
  2570.         RoutineName:=RtnName;
  2571.         IF i<>0 THEN
  2572.             BEGIN
  2573.                 HelpError(i);
  2574.                 EXIT;
  2575.             END;
  2576.         ASSIGN(HelpFile,h.HelpFileName);    { Open help file }
  2577.         {$I-}
  2578.         RESET(HelpFile);
  2579.         {$I+}
  2580.         IF IOResult<>0 THEN
  2581.             BEGIN
  2582.                 HelpReset;
  2583.                 HelpError(ConErrNoHelpFile);
  2584.                 EXIT;
  2585.             END;
  2586.         i:=0;
  2587.         REPEAT                          { Build help index }
  2588.             IF EOF(HelpFile) THEN
  2589.                 BEGIN                   { If EOF, file is in error }
  2590.                     HelpReset;
  2591.                     HelpError(ConErrHelpFormat);
  2592.                     EXIT;
  2593.                 END;
  2594.             {$I-}
  2595.             READ(HelpFile,HelpVar);     { Get next record }
  2596.             {$I+}
  2597.             IF IOResult<>0 THEN
  2598.                 BEGIN
  2599.                     HelpReset;
  2600.                     HelpError(ConErrHelpRead);
  2601.                     EXIT;
  2602.                 END;
  2603.             WITH HelpVar DO
  2604.                 IF SecNum=0 THEN
  2605.                     BEGIN               { If it is an index entry }
  2606.                         IF i=255 THEN
  2607.                             BEGIN
  2608.                                 HelpReset;
  2609.                                 HelpError(ConErrHelpFormat);
  2610.                                 EXIT;
  2611.                             END;
  2612.                         INC(i);         { Increment array index }
  2613.                         HelpIndexStr[i]:=SecName;   { Store index & }
  2614.                         HelpSectionOfs[i]:=SecOfs;  { file offset }
  2615.                         HelpSectionLen[i]:=SecLength;
  2616.                     END;
  2617.         UNTIL HelpVar.SecNum>0;         { Repeat until end of index }
  2618.         MaxHelpSec:=i;
  2619.         IF i=0 THEN
  2620.             BEGIN                       { Error if no index records found }
  2621.                 HelpReset;
  2622.                 HelpError(ConErrHelpFormat);
  2623.                 EXIT;
  2624.             END;
  2625.         HelpStoreSize:=0;               { Determine largest section size }
  2626.         IndexColWidth:=0;               { and length of longest index entry }
  2627.         FOR i:=1 to MaxHelpSec DO
  2628.             BEGIN
  2629.                 IF HelpSectionLen[i]>HelpStoreSize THEN
  2630.                     HelpStoreSize:=HelpSectionLen[i];
  2631.                 IF LENGTH(HelpIndexStr[i])>IndexColWidth THEN
  2632.                     IndexColWidth:=LENGTH(HelpIndexStr[i]);
  2633.             END;
  2634.         IndexColWidth:=IndexColWidth+2;
  2635.         WITH HelpConfig DO              { Calc. shape/size of index display }
  2636.             BEGIN
  2637.                 IndexCols:=(X2-X1-1) DIV IndexColWidth;
  2638.                 IndexRows:=Y2-Y1-1;
  2639.             END;
  2640.         IF IndexCols<1 THEN
  2641.             BEGIN
  2642.                 HelpReset;
  2643.                 HelpError(ConErrHelpIndex);
  2644.                 EXIT;
  2645.             END;
  2646.         FOR k:=1 to HelpStoreSize DO    { Allocate help storage space on heap }
  2647.             BEGIN
  2648.                 NEW(HelpStore[k]);
  2649.                 IF HelpStore[k]=NIL THEN
  2650.                     BEGIN
  2651.                         HelpReset;
  2652.                         HelpError(ConErrHeap);
  2653.                         EXIT;
  2654.                     END;
  2655.             END;
  2656.         HelpCtxIndex:=128;      { Initialize context stack }
  2657.         HelpInitialized:=TRUE;
  2658.     END; { HelpInitialize }
  2659.  
  2660.  
  2661.  
  2662. PROCEDURE TextMode(Mode: WORD);
  2663. { Add ENHCON code for text mode changes }
  2664.  
  2665.     BEGIN
  2666.         HelpReset;              { Reset help system }
  2667.         DisposeAll;             { Discard WDRs and saved screen areas }
  2668.         CRT.TextMode(Mode);     { Call CRT unit to switch modes }
  2669.         Initialize;             { Re-initialize ENHCON unit }
  2670.     END;
  2671.  
  2672.  
  2673.  
  2674. FUNCTION ReadKey: CHAR;
  2675. { Chained into CRT.ReadKey.  Performs cursor size change and checks
  2676.   for help requests. }
  2677.  
  2678.     VAR
  2679.         ch: CHAR;
  2680.  
  2681.     BEGIN
  2682.         REPEAT
  2683.             REPEAT
  2684.                 IF CursorInsert THEN        { If cursor-change enabled }
  2685.                     IF InsertLock THEN      { set cursor to appropriate size }
  2686.                         BlockCursor
  2687.                     ELSE
  2688.                         LineCursor;
  2689.                 ch:=CRT.ReadKey;            { Call regular ReadKey function }
  2690.             UNTIL (ch<DEL) OR (ch=PoundSign);
  2691.             IF ch=NUL THEN                  { Check for extended key }
  2692.                 ch:=ExtKey[CRT.ReadKey];    { If found, get scan & convert }
  2693.             IF NOT(HelpActive) THEN         { Check for help request key }
  2694.                 WITH HelpConfig DO
  2695.                     IF (ch IN [GeneralKey,ContextKey,LastHelpKey]) THEN
  2696.                         BEGIN
  2697.                             HelpActive:=TRUE;
  2698.                             HelpRequest(ch);
  2699.                             HelpActive:=FALSE;
  2700.                             ch:=NUL;
  2701.                         END;
  2702.         UNTIL (InsKeyEnable OR (ch<>KeyIns)) AND (ch<>NUL);
  2703.         ReadKey:=ch;                        { Try again if key invalid }
  2704.     END;  { ReadKey }
  2705.  
  2706.  
  2707. BEGIN  { Unit initialization code }
  2708.     ExitSave:=ExitProc;         { Install exit procedure }
  2709.     ExitProc:=@ExitRestore;
  2710.     Initialize;                 { Initialize to current display mode }
  2711.     HelpError:=HError;          { Install error handler }
  2712.     ClearHelpPointers;          { Reset help system }
  2713.     HelpConfig.WindowID:=0;
  2714. END.
  2715.  
  2716.