home *** CD-ROM | disk | FTP | other *** search
/ PC World Komputer 1995 November / PCWK1195.iso / inne / podstawy / dos / 4dos / 4uzytki / 4d24h20b.exe / 4DOS24H2.ASM < prev    next >
Assembly Source File  |  1993-05-01  |  54KB  |  889 lines

  1. PAGE    60,132
  2. TITLE   4DOS24H2.ASM
  3. SUBTTL  Critical Error Handler for 4DOS
  4. ;
  5. ; Copenhagen,  August 3. 1992 (revised May 1992)
  6. ;
  7. ; The documentation, this source file and the compiled program are released
  8. ; to the Public Domain.  Nobody is authorized to charge any amount of money
  9. ; for the included files.  Feel free to modify the code but please don't put
  10. ; my name under if redistributed.
  11. ;
  12. ; As a common convention the comments in this source file are Pascal-like
  13. ; statements to allow for a better overwiev of the program.
  14. ;
  15. ; The code is highly optimized to minimize use of memory but without
  16. ; compromising the user interface.  I don't think it is possible to squeeze
  17. ; this code much more than a few bytes, but I would like to hear from
  18. ; everybody who succeeds in making this program use less memory (without
  19. ; loosing features).  Also any other comments about bugs or whatever it might
  20. ; be would be very appreciated.
  21. ;
  22. ; You can reach me with E-mail at the following Internet address:
  23. ;
  24. ;    ehlig@ask.diku.dk
  25. ;
  26. ; please use subject: 4DOS24H2
  27. ;
  28. ; If you cannot reach me through E-mail you can write to the following address:
  29. ;
  30. ;    Niels Jensen
  31. ;    Vaerebrovej 40,7,3
  32. ;    2880 Bagsvaerd
  33. ;    Denmark DK
  34. ;
  35. ;                               Niels Jensen
  36. ;
  37. ;                  --------------------------------------
  38. ;
  39. ;
  40. ; To re-assemble using Microsoft Macro Assembler (MASM) or Borlands Turbo
  41. ; Assembler (TASM):
  42. ;
  43. ;    TASM or MASM 4DOS24H2;
  44. ;    LINK 4DOS24H2;
  45. ;    EXE2BIN 4DOS24H2 4DOS24H2.COM
  46. ;    DEL 4DOS24H2.EXE
  47. ;    DEL 4DOS24H2.OBJ
  48. ;
  49. ; If you want 4DOS24H2 to be compatible with the old 40 columns modes change
  50. ; the define option on the command line to reflect:
  51. ;
  52. ;    /Dshadow=1
  53. ;
  54. ; If you hate shadow simulation change the define option of the command to:
  55. ;
  56. ;    /Dshadow=0
  57. ;
  58. ;--- Conditional defines ------------------------+------------------------------
  59. ;   The following code causes two shadow columns as default in case nothing or
  60. ;   a wrong value is specified on the command line.
  61. ;------------------------------------------------+------------------------------
  62.   IF1                                            ;
  63.    IFDEF shadow                                  ;
  64.     IF (shadow GT 2) + (shadow LT 0)             ; Default num. of shadow cols.
  65.      shadow = 2                                  ; if not defined.
  66.     ENDIF                                        ;
  67.    ELSE                                          ;
  68.     shadow = 2                                   ; Default num. of shadow cols.
  69.    ENDIF                                         ; if value outside prop. range.
  70.   ENDIF                                          ;
  71.                                                  ;
  72. ;--- Boolean constants --------------------------+------------------------------
  73. False          EQU      0                        ;
  74. True           EQU      1                        ;
  75.                                                  ;
  76. ;--- Bit constants ------------------------------+------------------------------
  77. Bit7           EQU      80h                      ;
  78. Bit6           EQU      40h                      ;
  79. Bit5           EQU      20h                      ;
  80. Bit4           EQU      10h                      ;
  81. Bit3           EQU      08h                      ;
  82. Bit2           EQU      04h                      ;
  83. Bit1           EQU      02h                      ;
  84. Bit0           EQU      01h                      ;
  85.                                                  ;
  86. ;--- Colour constants ---------------------------+------------------------------
  87. Black          EQU      00h                      ; Low intensity colours
  88. Blue           EQU      01h                      ;
  89. Green          EQU      02h                      ;
  90. Cyan           EQU      03h                      ;
  91. Red            EQU      04h                      ;
  92. Magenta        EQU      05h                      ;
  93. Brown          EQU      06h                      ;
  94. LightGray      EQU      07h                      ;
  95.                                                  ;------------------------------
  96. Gray           EQU      08h                      ; High intensity colours
  97. LightBlue      EQU      09h                      ;
  98. LightGreen     EQU      0Ah                      ;
  99. LightCyan      EQU      0Bh                      ;
  100. LightRed       EQU      0Ch                      ;
  101. LightMagenta   EQU      0Dh                      ;
  102. Yellow         EQU      0Eh                      ;
  103. White          EQU      0Fh                      ;
  104.                                                  ;
  105. ;--- Key Definitions ----------------------------+------------------------------
  106. Enter          EQU      0Dh                      ; Enter-key
  107. Escape         EQU      1Bh                      ; Escape-key
  108. CtrlC          EQU      03h                      ; Ctrl-C (Ctrl-Break)
  109. CtrlP          EQU      10h                      ; Ctrl-P (Printer on/off)
  110.                                                  ;
  111. ;--- Interrupt constants ------------------------+------------------------------
  112. Video          EQU      10h                      ; BIOS Video service
  113. Equipmnt       EQU      11h                      ; BIOS Equipment service
  114. KeyBoard       EQU      16h                      ; BIOS Keyboard service
  115. ReadKey        EQU      00h                      ; BIOS Keyboard: Read key
  116. TestKey        EQU      01h                      ; BIOS Keyboard: Test for key
  117. Quit           EQU      20h                      ; DOS Service: Terminate
  118. DOS            EQU      21h                      ; DOS Service Interrupt
  119. GetKeyPress    EQU      07h                      ; DOS Service: Get key (raw)
  120. DosReadKey     EQU      08h                      ; DOS Service: Read keystroke
  121. PrintStr       EQU      09h                      ; DOS Service: Print String
  122. SetVector      EQU      25h                      ; DOS Service: Set int. vector
  123. GetVector      EQU      35h                      ; DOS Service: Get int. vector
  124. FreeMem        EQU      49h                      ; DOS Service: Free memory blk.
  125. BreakInt       EQU      23h                      ; Interrupt 23h (Ctrl-Break)
  126. CritErrInt     EQU      24h                      ; Interrupt 24h (Crit. Err.)
  127. TSR            EQU      27h                      ; Terminate and stay resident
  128. MultiPlex      EQU      2Fh                      ; Multiplex interrupt
  129. IDvector       EQU      61h                      ; Vector used for identification
  130.                                                  ;
  131. ;--- Screen related addresses -------------------+------------------------------
  132. MonoSeg        EQU      0B000h                   ; Segment adr. for mono-scr.
  133. ColrSeg        EQU      0B800h                   ; Segment adr. for colour-scr.
  134. ScrRows        EQU      0484h                    ; Ofs. adr. of screen rows
  135. ScrCols        EQU      044Ah                    ; Ofs. adr. of screen columns
  136. RegenBufLen    EQU      044Ch                    ; Ofs. adr. of regen.buf.length
  137.                                                  ;
  138. ;--- Response constants -------------------------+------------------------------
  139. IgnoreOK       EQU      Bit5                     ; Set if ignore allowed
  140. RetryOK        EQU      Bit4                     ; Set if retry allowed
  141. FailOK         EQU      Bit3                     ; Set if fail allowed
  142.  
  143. IgnoreResp     EQU      0                        ; Response in case of ignore
  144. RetryResp      EQU      1                        ; Response in case of retry
  145. AbortResp      EQU      2                        ; Response in case of abort
  146. FailResp       EQU      3                        ; Response in case of fail
  147.                                                  ;
  148. ;--- Window constants ---------------------------+------------------------------
  149. WinLins        EQU      14                       ; Num. of lines in window
  150.  
  151.   IF shadow EQ 0
  152. WinCols        EQU      39                       ; Num. of columns in window
  153.   ELSE
  154.     IF shadow EQ 1
  155. WinCols        EQU      40                       ; Num. of columns in window
  156.     ELSE
  157. WinCols        EQU      41                       ; Num. of columns in window
  158.     ENDIF
  159.   ENDIF
  160.  
  161. WinSize        EQU      WinLins*(WinCols-2)      ; Num. of chars in window
  162. TopLines       EQU      4                        ; Num. of lines over window
  163. TxtAttr        EQU      Yellow+(Blue SHL 4)      ; Attribute of the window text
  164. ;
  165. ; Note: Remember to change the colour of the abort-message in the
  166. ;       window accordingly if you change TxtAttr
  167.                                                  ;
  168. ;--- Misc. Program Constants --------------------+------------------------------
  169. IDsign         EQU      '4D'                     ; Identification letters
  170. MemSwc           EQU    'M'                      ; Memory information switch
  171.                                                  ;
  172. ;------------------------------------------------+------------------------------
  173. ;
  174. ;                                 M A C R O S
  175. ;
  176. ;------------------------------------------------+------------------------------
  177. PushM          MACRO regs                        ;; Push Multiple registers
  178.                 IRP register,<regs>              ;;   - Pushes all registers
  179.                  push register                   ;;   between "<" and ">"
  180.                 ENDM                             ;;   separated by commas.
  181.                ENDM                              ;;   Ex.  PushM <ax,bx,cx>
  182.                                                  ;;
  183. PopM           MACRO regs                        ;; Pop Multiple registers
  184.                 IRP register,<regs>              ;;   - Pops all registers
  185.                  pop register                    ;;   between "<" and ">"
  186.                 ENDM                             ;;   separated by commas.
  187.                ENDM                              ;;   Ex.  PopM  <cx,bx,ax>
  188. ;------------------------------------------------+------------------------------
  189. ;
  190. ;                             C O D E   S T A R T
  191. ;
  192. ;------------------------------------------------+------------------------------
  193. Code           SEGMENT
  194.                ASSUME   CS:Code, DS:Code, ES:Code, SS:Code
  195. ;--- PSP addresses ------------------------------+------------------------------
  196.            ORG    12h             ; - Offset address of old 24h
  197. PSP24hOfs      LABEL    WORD                     ;  handler.
  198.            ORG    14h             ; - Segment address of old 24h
  199. PSP24hSeg      LABEL    WORD                     ;  handler.
  200.            ORG    16h             ; - Segment address of parent
  201. ParentPSP      LABEL    WORD                     ;  PSP.
  202.            ORG    2Ch             ; - Segment address of
  203. EnvSegm        LABEL    WORD                     ;  environment block.
  204.                ORG      5Ch                      ; - Offset where resident code
  205. FreePSP        LABEL    WORD                     ;  overlays unused part of PSP.
  206.                ORG      80h                      ; - Field indicating parameter
  207. ParLen         LABEL    BYTE                     ;  length
  208.                ORG      81h                      ; - Start of command line
  209. ParmStr        LABEL    BYTE                     ;  parameter string
  210.                ORG      100h                     ; - Starting offset for COM-prgs.
  211. ;------------------------------------------------+------------------------------
  212. Start:         JMP      Begin                    ; Go to installation process
  213.                ORG      100h+FreePSP             ; Start offset address 15Ch
  214. IDintOfs       LABEL    NEAR                     ; If ID-int goto old vect. adr.
  215.                DB       0EAh                     ; JMP Far Ptr OldIDvector
  216. OldIDvectOfs   DW       ?                        ;  { Original content of the }
  217. OldIDvectSeg   DW       ?                        ;  { ID-vector.              }
  218.                                                  ;
  219. ;--- Variables ----------------------------------+------------------------------
  220. IDword         DW       IDsign                   ; Identification word
  221. ScrSeg         DW       ColrSeg                  ; Screen address.
  222. DevHdr         LABEL    DWORD                    ; Device Header Pointer
  223. DevHdrOfs      DW       ?                        ;  Address of the device
  224. DevHdrSeg      DW       ?                        ;  in error from BP:SI.
  225. Errcode        DW       ?                        ; Error code from DI.
  226.                                                  ;
  227. ;--- Error message strings ----------------------+------------------------------
  228. ClrStr         DB   (WinCols-7) DUP(' '),0       ; Clear string for erasing
  229. Msg0           DB   'Disk is write protected',0  ; Disk write protected
  230. Msg1           DB   'Unknown unit',0             ; Device not known
  231. Msg2a          DB   'Disk drive not ready',0     ; Disk drive not ready
  232. Msg2b          DB   'Device not ready',0         ; Device not ready
  233. Msg3           DB   'Unknown command',0          ; Device command unrecognized
  234. Msg4           DB   'Data error (CRC)',0         ; Disk data error
  235. Msg5           DB   'Bad request struc. length',0; Device call format wrong
  236. Msg6           DB   'Seek error',0               ; Disk seek error
  237. Msg7           DB   'Unknown media type',0       ; Disk not recognized
  238. Msg8           DB   'Sector not found',0         ; Disk sector not found
  239. Msg9           DB   'Printer out of paper',0     ; Device out of paper
  240. MsgA           DB   'Write fault',0              ; Device write fault
  241. MsgB           DB   'Read fault',0               ; Device read fault
  242. MsgC           DB   'General failure',0          ; Disk general error
  243. MsgF           DB   'Invalid disk change',0      ; Disk is replaced
  244. Msg10h         DB   'FCB unavailable',0          ; Device error
  245. Msg11h         DB   'Sharing buffer overflow',0  ; Device error
  246. MsgU           DB   'Unknown error',0            ; Wrong error code
  247.                                                  ;
  248. ErrMsg         DW   Msg0, Msg1, Msg2a, Msg3, Msg4; String pointer table with
  249.                DW   Msg5, Msg6, Msg7, Msg8, Msg9 ; pointers to the error 
  250.                DW   MsgA, MsgB, MsgC, MsgU, MsgU ; messages
  251.                DW   MsgF, Msg10h, Msg11h         ;
  252.                                                  ;
  253. ;--- Disk error message parts -------------------+------------------------------
  254. DskMsg1        DB   'Disk ',0                    ;
  255. DskMsg2A       DB   'read ',0                    ;
  256. DskMsg2B       DB   'write ',0                   ;
  257. DskMsg3        DB   'error on drive '            ;
  258. Drive          DB   'A: in ',0                   ;
  259. DskMsg4A       DB   'DOS system area',0          ;
  260. DskMsg4B       DB   'FAT-area (File Allocation Table)',0
  261. DskMsg4C       DB   'the root directory area',0  ;
  262. DskMsg4D       DB   'the data area',0            ;
  263. DskMsg4        DW   DskMsg4A,DskMsg4B,DskMsg4C,DskMsg4D
  264.                                                  ;
  265. ;--- Device error message parts -----------------+------------------------------
  266. DevMsg1        DB   'Device error on device ',0  ;
  267. DevMsg2        DB   'Memory copy of FAT is bad',0;
  268.                                                  ;
  269. ;--- Basic message window -----------------------+------------------------------
  270.  
  271.   IF shadow EQ 0
  272.  
  273. MsgBuf         DB   '┌──── DOS Critical Error Handler ────┐'
  274.                DB   '│            Version  2.00            │'
  275.                DB   '│                                     │'
  276.                DB   '│  '
  277. MsgPos1        DB         '                                   │'
  278.                DB   '│  '
  279. MsgPos2        DB         '                                   │'
  280.                DB   '│                                     │'
  281.                DB   '│  Error: '
  282. MsgPos3        DB                       '                            │'
  283.                DB   '│                                     │'
  284.                DB   '│  Please hit:                        │'
  285.                DB   '│     A - to Abort current operation  │'
  286.                DB   '│     R - to Retry the operation      │'
  287.                DB   '│     '
  288. MsgPos5        DB               '                                │'
  289.                DB   '│  '
  290. MsgPos6        DB         '                                   │'
  291.                DB   '└─────────────────────────────────────┘'
  292.  
  293.   ELSE
  294.     IF shadow EQ 1
  295.  
  296. MsgBuf         DB   '┌──── DOS Critical Error Handler ────┐'
  297.                DB   '│            Version  2.00            │ '
  298.                DB   '│                                     │ '
  299.                DB   '│  '
  300. MsgPos1        DB         '                                   │ '
  301.                DB   '│  '
  302. MsgPos2        DB         '                                   │ '
  303.                DB   '│                                     │ '
  304.                DB   '│  Error: '
  305. MsgPos3        DB                       '                            │ '
  306.                DB   '│                                     │ '
  307.                DB   '│  Please hit:                        │ '
  308.                DB   '│     A - to Abort current operation  │ '
  309.                DB   '│     R - to Retry the operation      │ '
  310.                DB   '│     '
  311. MsgPos5        DB               '                                │ '
  312.                DB   '│  '
  313. MsgPos6        DB         '                                   │ '
  314.                DB   '└─────────────────────────────────────┘ '
  315.                DB     '                                       '
  316.     ELSE
  317. MsgBuf         DB   '┌──── DOS Critical Error Handler ────┐'
  318.                DB   '│            Version  2.00            │  '
  319.                DB   '│                                     │  '
  320.                DB   '│  '
  321. MsgPos1        DB         '                                   │  '
  322.                DB   '│  '
  323. MsgPos2        DB         '                                   │  '
  324.                DB   '│                                     │  '
  325.                DB   '│  Error: '
  326. MsgPos3        DB                       '                            │  '
  327.                DB   '│                                     │  '
  328.                DB   '│  Please hit:                        │  '
  329.                DB   '│     A - to Abort current operation  │  '
  330.                DB   '│     R - to Retry the operation      │  '
  331.                DB   '│     '
  332. MsgPos5        DB               '                                │  '
  333.                DB   '│  '
  334. MsgPos6        DB         '                                   │  '
  335.                DB   '└─────────────────────────────────────┘  '
  336.                DB       '                                       '
  337.     ENDIF
  338.   ENDIF
  339.                                                  ;
  340. ;--- Response message parts ---------------------+------------------------------
  341. ; RetryMsg       DB   'R - to Retry the operation',0;
  342. ; RetryMsgLen    EQU  $-RetryMsg-1                 ;
  343.  
  344. IgnoreMsg      DB   'I - to Ignore the error  ',0;
  345. IgnoreMsgLen   EQU  $-IgnoreMsg-1                ;
  346. FailMsg        DB   'F - to Fail the operation',0;
  347.                                                  ;
  348. ;------------------------------------------------+------------------------------
  349. ;
  350. ;                S U B R O U T I N E S
  351. ;
  352. ;-------------------------------------------------------------------------------
  353. ; S w a p
  354. ;-------------------------------------------------------------------------------
  355. ; Does    :  Swaps the buffer containing the message window with the data on
  356. ;            the screen located where the window is to be displayed.
  357. ; On call :  DS:SI = Source; ES:DI = Destination (MsgBuf/Screen)
  358. ; Uses    :  BX, BP, CX, SI, DI
  359. ; Changes :  BX, BP, CX, SI, DI
  360. ;
  361. ;--- Start of Swap ------------------------------+------------------------------
  362. Swap     PROC     NEAR                           ; Procedure Swap;
  363.                                                  ; begin
  364.          MOV      SI, Offset MsgBuf              ;   ds:si:= MsgBuf;
  365.          MOV      DI, DX                         ;   es:di:= Scr;
  366.   IF shadow EQ 0
  367.          MOV      CX, WinLins                    ;   cx:= WinLins;
  368.   ELSE
  369.          MOV      CX, WinLins+1                  ;   cx:= WinLins+1;
  370.   ENDIF
  371. Loop1:   PUSH     CX                             ;   for cx1:= WinLins+1 downto 1 do
  372.   IF shadow NE 0
  373.          MOV      AX, CX                         ;
  374.          DEC      AX                             ;     ax:= cx1 - 1;
  375.   ENDIF
  376.          MOV      CL, WinCols                    ;     if (cx1 = WinLins+1) or
  377.   IF shadow NE 0
  378.          JE       NoShadC                        ;        (cx1 = 1)
  379.          CMP      AL, WinLins-1                  ;     then tmp:= WinCols
  380.          JBE      Loop11                         ;     else tmp:= WinCols+1;
  381.     IF shadow EQ 1
  382. NoShadC: DEC      CX                             ;
  383.     ELSE
  384. NoShadC: SUB      CL, 2                          ;     for cx2:= tmp downto 1 do begin
  385.     ENDIF
  386.   ENDIF
  387. Loop11:  MOV      BX, ES:[DI]                    ;       bx:= Scr[ds:si];
  388.   IF shadow NE 0
  389.          CMP      AL, WinLins-1                  ;       if (cx1 <= WinLins)
  390.          JA       NoShade                        ;       then
  391.          OR       AX, AX                         ;         if (cx2 <= 2) or
  392.          JZ       Shade                          ;            (cx1 = 1)
  393.     IF shadow EQ 1
  394.          CMP      CL, 1                          ;
  395.          JNE      NoShade                        ;
  396.     ELSE
  397.          CMP      CL, 2                          ;
  398.          JA       NoShade                        ;
  399.     ENDIF
  400. Shade:   MOV      [SI], BL                       ;         then Buf[si]:= bl;
  401.   ENDIF
  402. NoShade: MOVSW                                   ;       Scr[di]:= Buf[si];
  403.          MOV      [SI-2], BX                     ;       di:= di+2; si:= si+2;
  404.          LOOP     Loop11                         ;       Buf[si-2]:= bx
  405.                                                  ;     end; (* for cx2 ... *)
  406.   IF shadow NE 0
  407.          CMP      AL, WinLins                    ;     if (ax = WinLins) or
  408.          JE       Adj                            ;        (ax = 1)
  409.          CMP      AL, 1                          ;
  410.          JNE      NoAdj                          ;     then
  411.     IF shadow EQ 1
  412. Adj:     INC      DI                             ;
  413.          INC      DI                             ;       di:= di + 2;
  414.     ELSE
  415. Adj:     ADD      DI, 4                          ;       di:= di + 4;
  416.     ENDIF
  417.   ENDIF
  418. NoAdj:   ADD      DI, BP                         ;     di:= di + bp;
  419.          POP      CX                             ;
  420.          LOOP     Loop1                          ;   end (* for cx1 ... *)
  421.          RET                                     ; end;
  422. Swap     ENDP                                    ;
  423. ;------------------------------------------------+------------------------------
  424. ; P u t S t r
  425. ;-------------------------------------------------------------------------------
  426. ; Does    :  Displays a null-teminated string. Length must be greater than 0.
  427. ; On call :  AH = Attribute Byte;
  428. ;            DS:SI = ^Source;
  429. ;            ES:DI = ^Destination (Screen memory)
  430. ; Uses    :  AX, SI, DI, DS, ES
  431. ; Changes :  AL, SI, DI
  432. ;
  433. ;------------------------------------------------+------------------------------
  434. PutStr   PROC     NEAR                           ; Procedure PutStr;
  435. again:   LODSB                                   ; begin
  436.          STOSW                                   ;   repeat
  437.          CMP      Byte Ptr [SI], 0               ;     al:= Buf[si]; write(ax);
  438.          JNE      again                          ;     Inc(si)
  439.          RET                                     ;   until Buf[si] = 0
  440. PutStr   ENDP                                    ; end;
  441. ;------------------------------------------------+------------------------------
  442. ;
  443. ;           N e w   i n t e r r u p t   h a n d l e r
  444. ;
  445. ;-------------------------------------------------------------------------------
  446. ;
  447. ; In case of a critical error during a graphics session this handler would
  448. ; not behave normaly because the information window is written directly to
  449. ; the screen memory.  Instead the handler checks for graphics modes and
  450. ; calls the old critical error handler in case the current mode is not a
  451. ; text mode.
  452. ;
  453. ; Graphics modes are detected automatically by checking the length of the
  454. ; screen regenerate buffer and compare it against the (last) text screen
  455. ; solution.  This is only tested on a Tseng ET4000 based Super VGA card and
  456. ; therefore NOT garanteed to work with other display adapters.
  457. ;
  458. ;
  459. ;      Special register use:
  460. ;
  461. ;         BP:  Holds the constant 2*(ScrCols-WinCols) used during swapping of
  462. ;              the message window and the screen.  The constant expresses the
  463. ;              byte distance in display memory from the end of a line in the
  464. ;              message window to the beginning of the next.
  465. ;
  466. ;         DX:  Holds the constant (TopLines*2*ScrCols + 2*Indent) which is the
  467. ;              offset from the start of display memory to the upper left corner
  468. ;              of the message window.
  469. ;
  470. ;------------------------------------------------+------------------------------
  471. New24h:
  472.                PushM    <BX,CX,DX,SI,DI,BP,DS,ES>; Save(registers);
  473.                PUSH     AX                       ;  {AX = error locus info}
  474.                PUSH     CS                       ; ds:= cs;
  475.                POP      DS                       ;  {BP:SI => dev. drv. header}
  476.                MOV      DevHdrOfs, SI            ; DevHdrOfs:= si;
  477.                MOV      DevHdrSeg, BP            ; DevHdrSeg:= bp;
  478.                AND      DI, 001Fh                ; di:= di and 001Fh;
  479.                MOV      ErrCode, DI              ; ErrCode:= di;
  480.                XOR      DX, DX                   ; dx:= 0;
  481.                MOV      ES, DX                   ; es:= dx;
  482. ;--- Check for graphics mode ---------------------------------------------------
  483. Patch1         LABEL    WORD                     ; { Address for patching }
  484.                MOV      AL, 24                   ; {$IF EGA} al:= ScrRows-1;
  485.                NOP                               ; {$ELSE}   al:= 24;
  486.                NOP                               ; {$ENDIF}
  487.                INC      AX                       ; al:= al+1;
  488.                MUL      Byte Ptr ES:ScrCols      ; ax:= ScrRows*ScrCols;
  489.                SHL      AX, 1                    ; ax:= ax*2;
  490.                MOV      DX, ES:RegenBufLen       ; dx:= RegenBufLength;
  491.                SHR      DX, 1                    ; dx:= dx/2;
  492.                JZ       OldHandler               ; if (dx=0) or (ax<=dx)
  493.                CMP      AX, DX                   ; then begin
  494.                JA       TxtMode                  ;  { Jump to old handler }
  495. OldHandler:    PopM  <AX,ES,DS,BP,DI,SI,DX,CX,BX>;   Rest(regs);
  496.                DB       0EAh                     ;   JMP Far Ptr OldHandler
  497. OldInt24hOfs   DW       ?                        ;  { Pointer to original }
  498. OldInt24hSeg   DW       ?                        ;  { int 24h handler     }
  499.                                                  ; end;
  500. ;--- Calculate top margin and window start position ----------------------------
  501.  
  502. TxtMode:       MOV      AX, ES:ScrCols           ; ax:= ScrCols;
  503.                MOV      BP, AX                   ; bp:= ax;
  504.                SUB      BP, WinCols              ; bp:= ScrCols - WinCols;
  505.                MOV      AH, TopLines*2           ;  {Calc. byte cnt for topmarg}
  506.                MUL      AH                       ; ax:= TopLines * 2*ScrCols;
  507.                ADD      AX, BP                   ; ax:= ax + Indent;
  508.                SHL      BP, 1                    ; bp:= 2 * bp;
  509.                MOV      DX, AX                   ; dx:= ax; { Window start pos }
  510.              IF (WinCols AND 1)                  ; if Odd(WinCols)
  511.                DEC      DX                       ; then dx:= dx - 1;
  512.              ENDIF                               ;
  513.                PUSH     CS                       ;  { Setup ES }
  514.                POP      ES                       ; es:= cs;
  515.  
  516. ;--- Test bit 7 for disk error -------------------------------------------------
  517.  
  518.                POP      BX                       ;  { Get org. AX in BX }
  519.                PUSH     BX                       ; bx:= ErrInfo;
  520.                MOV      AH, TxtAttr              ; ah:= TxtAttr;
  521.                MOV      DI, Offset MsgPos1       ; di:= MsgPos1;
  522.                TEST     BH, Bit7                 ; if DiskError
  523.                JNZ      GetName                  ; then begin
  524. ;--- Put disk error message ----------------------------------------------------
  525.                MOV      ErrMsg[2*2], Offset Msg2a;   ErrMsg[2]:= Msg2a;
  526.                MOV      SI, Offset DskMsg1       ;   si:= ^DskMsg1;
  527.                CALL     PutStr                   ;   PutStr(si,di);
  528. ;--- Get error type info from bit 0 --------------------------------------------
  529.                TEST     BH, Bit0                 ;   if WriteError
  530.                MOV      SI, Offset DskMsg2A      ;   then si:= ^DskMsg2B
  531.                JZ       ReadError                ;   else si:= ^DskMsg2A;
  532.                MOV      SI, Offset DskMsg2B      ;   PutStr(si,di);
  533. ReadError:     CALL     PutStr                   ;    { Patch drive letter }
  534.                ADD      Drive, BL                ;   Inc(DskMsg3[Drv],cl);
  535.                MOV      SI, Offset DskMsg3       ;   si:= ^DskMsg3;
  536.                CALL     PutStr                   ;   PutStr(si,di);
  537.                MOV      Drive, 'A'               ;   DskMsg3[Drv]:= 'A';
  538. ;--- Get error area info from bits 1 and 2 -------------------------------------
  539.                MOV      DI, Offset MsgPos2       ;   di:= MsgPos2;
  540.                PUSH     DI                       ;
  541.                MOV      BL, BH                   ;
  542.                AND      BX, 0006h                ;   bx:= bx mod 7;
  543.                MOV      SI, Offset ClrStr        ;   si:= Ofs(ClrStr);
  544.                CALL     PutStr                   ;   PutStr(si,di);
  545.                POP      DI                       ;   di:= MsgPos2;
  546.                MOV      SI, DskMsg4[BX]          ;   si:= DskMsg4[bx];
  547.                CALL     PutStr                   ;   PutStr(si,di)
  548.                JMP      Short GetError           ; end
  549.  
  550. ;--- Device error - test bit 15 of device attribute for char/blok device -------
  551. GetName:
  552.                MOV      ErrMsg[2*2], Offset Msg2b; else begin
  553.                PUSH     ES                       ;   ErrMsg[2]:= Msg2b;
  554.                LES      SI, DevHdr               ;   es:si:= ^DeviceHeader;
  555.                MOV      CX, ES:[SI+4]            ;   cx:= DeviceAttr;
  556.                MOV      SI, Offset DevMsg1       ;
  557.                TEST     CH, Bit7                 ;   if CharDevice
  558.                JNZ      CharDev                  ;   then si:= DevMsg1
  559.                MOV      SI, Offset DevMsg2       ;   else si:= DevMsg2;
  560. CharDev:       POP      ES                       ;
  561.                CALL     PutStr                   ;   PutStr(si,di);
  562.                TEST     CH, Bit7                 ;
  563.                JZ       ClrMsgPos2               ;   if CharDevice
  564.                PUSH     DS                       ;   then begin {Get dev. name}
  565.                LDS      SI, DevHdr               ;     ds:si:= ^DeviceName;
  566.                ADD      SI, 10                   ;     for cx1:= 1 to 8 do begin
  567.                MOV      CX, 8                    ;       Win[di]:= DevName[si+10];
  568. GetLoop1:      LODSB                             ;       Inc(di); Inc(si)
  569.                STOSW                             ;     end
  570.                LOOP     GetLoop1                 ;   end;
  571.                POP      DS                       ;   si:= ClrStr;
  572. ClrMsgPos2:    MOV      SI, Offset ClrStr        ;   di:= MsgPos2;
  573.                MOV      DI, Offset MsgPos2       ;   PutStr(si,di)
  574.                CALL     PutStr                   ; end;
  575.  
  576. ;--- Generate specific error information ---------------------------------------
  577. GetError:
  578.                MOV      DI, Offset MsgPos3       ; di:= MsgPos3;
  579.                MOV      SI, Offset ClrStr+6      ; si:= SubStr(6,ClrStr);
  580.                CALL     PutStr                   ; PutStr(si,di);
  581.                MOV      DI, Offset MsgPos3       ; di:= MsgPos3;
  582.                MOV      SI, Offset MsgU          ;
  583.                CMP      ErrCode, 0011h           ;
  584.                JA       NoValidCode              ; if ErrCode > 11h
  585.                MOV      SI, ErrCode              ; then si:= MsgU { Unkn. err. }
  586.                SHL      SI, 1                    ; else si:= ErrMsg[ErrCode];
  587.                MOV      SI, ErrMsg[SI]           ;
  588. NoValidCode:   CALL     PutStr                   ; PutStr(si,di);
  589.  
  590. ;--- Find out what response is allowed -----------------------------------------
  591.  
  592.                MOV      SI, Offset ClrStr        ; si:= ClrStr;
  593.                MOV      DI, Offset MsgPos6       ; di:= MsgPos6;
  594.                CALL     PutStr                   ; PutStr(si,di);
  595.                POP      BX                       ; bx:= errlocus;
  596.                MOV      DI, Offset MsgPos5       ;  { Test for retry }
  597. ;               MOV      DI, Offset MsgPos4       ;  { Test for retry }
  598. ;TestRetry:                                       ;
  599. ;               TEST     BH, RetryOK              ; if RetryOK
  600. ;               JZ       TestIgnore               ; then begin
  601. ;               MOV      SI, Offset RetryMsg      ;   PutStr(RetryMsg);
  602. ;               CALL     PutStr                   ;   di:= NextPos
  603. ;               ADD      DI, 2*(WinCols-RetryMsgLen);
  604. TestIgnore:                                      ; end;
  605.                TEST     BH, IgnoreOK             ; if IgnoreOK
  606.                JZ       TestFail                 ; then begin
  607.                MOV      SI, Offset IgnoreMsg     ;   PutStr(IgnoreMsg);
  608.                CALL     PutStr                   ;   di:= NextPos
  609.                ADD      DI, 2*(WinCols-IgnoreMsgLen);
  610. TestFail:                                        ; end;
  611.                MOV      SI, Offset ClrStr+3      ; if FailOK
  612.                TEST     BH, FailOK               ; then si:= FailMsg
  613.                JZ       EndRespTst               ; else si:= ClrStr;
  614.                MOV      SI, Offset FailMsg       ;
  615. EndRespTst:    CALL     PutStr                   ; PutStr(SI,DI);
  616. ;--- Show message window -------------------------------------------------------
  617.                MOV      ES, ScrSeg               ; es:= ScrSeg;
  618.                PUSH     BX                       ;
  619.                CALL     Swap                     ; Swap(Screen,MsgBuf);
  620.                POP      BX                       ;
  621. ;--- Get user response ---------------------------------------------------------
  622. GetKey:        MOV      AH, TestKey              ;  { Get keystroke }
  623.                INT      KeyBoard                 ; repeat
  624.                JZ       GetKey                   ;   while not KeyPrs do
  625.                CMP      AL, CtrlP                ;     TestKey(al);
  626.                JNE      NormalKey                ;   if al = '^P'
  627.                MOV      AH, DosReadKey           ;   then
  628.                INT      Dos                      ;     DosReadKey(al)
  629.                JMP      Short GetKey             ; until al <> '^P';
  630.  
  631. NormalKey:     MOV      AH, ReadKey              ;
  632.                INT      Keyboard                 ; ReadKey(al);
  633.                SUB      AL, 'A'                  ;
  634.                CMP      AL, ('Z'-'A')            ; if al in ['A'..'Z']
  635.                JA       ProcessIgnore            ; then
  636.                ADD      AL, 20h                  ;   al:= LowCase(al);
  637. ;--- Process response ----------------------------------------------------------
  638.                                                  ; case al of
  639. ProcessIgnore: CMP      AL, ('i'-'A')            ;   'i': begin {** Ignore **}
  640.                JNE      ProcessRetry             ;          if Not IgnoreOK
  641.                TEST     BH, Bit5                 ;          then goto GetKey;
  642.                JZ       GetKey                   ;          al:= 0;
  643.                MOV      AL, IgnoreResp           ;        end;
  644. ProcessRetry:  CMP      AL, ('r'-'A')            ;   'r',
  645.                JE       RetryAct                 ;
  646.                CMP      AL, (Enter-'A')          ;   Enter,
  647.                JE       RetryAct                 ;
  648.                CMP      AL, (' '-'A')            ;   ' ': begin {** Retry **}
  649.                JNE      ProcessFail              ;          al:= 1
  650. RetryAct:      MOV      AL, RetryResp            ;        end;
  651.                ;TEST     BH, Bit4                 ;          if Not RetryOK
  652.                ;JZ       GetKey                   ;          then goto GetKey;
  653. ProcessFail:   CMP      AL, ('f'-'A')            ;   'f': begin {** Fail **}
  654.                JNE      ProcessAbort             ;          if Not IgnoreOK
  655.                TEST     BH, Bit3                 ;          then goto GetKey
  656.                JZ       GetKey                   ;          al:= 3;
  657.                MOV      AL, FailResp             ;        end;
  658. ProcessAbort:  CMP      AL, ('a'-'A')            ;   'a',
  659.                JE       AbortAct                 ;
  660.                CMP      AL, ('q'-'A')            ;   'q',
  661.                JE       AbortAct                 ;
  662.                CMP      AL, ('x'-'A')            ;   'x',
  663.                JE       AbortAct                 ;
  664.                CMP      AL, (CtrlC-'A')          ;   ^C ,
  665.                JE       AbortAct                 ;
  666.                CMP      AL, (Escape-'A')         ;   Esc: begin {** Abort **}
  667.                JNE      ElseCase                 ;          AL:= 2
  668. AbortAct:      MOV      AL, AbortResp            ;        end;
  669. ElseCase:      CMP      AL, FailResp             ;   else goto GetKey
  670.                JA       GetKey                   ; end;  { case }
  671. ;--- Restore screen and exit ---------------------------------------------------
  672.                PUSH     AX                       ;
  673.                CALL     Swap                     ; Swap(MsgBuf,Screen);
  674.                POP      AX                       ;
  675.                XOR      AH, AH                   ; ah:= 0;
  676.                POPM     <ES,DS,BP,DI,SI,DX,CX,BX>; Rest(regs)
  677.                IRET                            ; end;
  678. EndOfCode      EQU      $                      ;
  679. ;----------------------------------------------+--------------------------------
  680. ;
  681. ;                   E N D   O F   R E S I D E N T   C O D E
  682. ;
  683. ;-------------------------------------------------------------------------------
  684. ;  L o a d e r - p r o g r a m
  685. ;
  686. ;  This part of the code is responsible for:
  687. ;    - loading the handler
  688. ;    - high load without trouble under 386Max or QEMM if required
  689. ;    - detection of screen hardware
  690. ;    - the handler being continuously active during shells
  691. ;
  692. ;------------------------------------------------+------------------------------
  693. ;                 P R O C E D U R E   D E C L A R A T I O N S
  694. ;------------------------------------------------+------------------------------
  695. ;   Procedure WriteInt (ax: int);
  696. ;------------------------------------------------+------------------------------
  697. WriteInt       PROC     NEAR                     ; Procedure WriteInt (ax:int);
  698.                PushM    <AX,BX,CX,DX,BP>         ;  { Writes int w/o leading 0 }
  699.                MOV      BX, 0007h                ; begin
  700.                MOV      BP, 10000                ;   bp:= 10000;
  701.                XOR      CX, CX                   ;   cx:= 0;
  702. WriteLoop:     XOR      DX, DX                   ;   repeat
  703.                DIV      BP                       ;     dx:= ax mod bp;
  704.                PUSH     DX                       ;     ax:= ax div bp;
  705.                ADD      CL, AL                   ;     cl:= cl + al;
  706.                JZ       LeadZero                 ;     if cl > 0
  707.                ADD      AL, '0'                  ;     then begin
  708.                MOV      AH, 0Eh                  ;       al:= Char(al);
  709.                INT      Video                    ;       write(al)
  710. LeadZero:      MOV      AX, BP                   ;     end;
  711.                MOV      BP, 10                   ;
  712.                XOR      DX, DX                   ;     dx:= 0;
  713.                DIV      BP                       ;     bp:= bp div 10;
  714.                MOV      BP, AX                   ;
  715.                POP      AX                       ;     ax:= dx
  716.                CMP      BP, 0                    ;   until bp <= 0;
  717.                JG       WriteLoop                ; end;
  718.                PopM     <BP,DX,CX,BX,AX>         ;
  719.                RET                               ;
  720. WriteInt       ENDP                              ;
  721. ;------------------------------------------------+------------------------------
  722. ;   Procedure WriteHex (ax: int);
  723. ;------------------------------------------------+------------------------------
  724. WriteHex       PROC     NEAR                     ; Procedure WriteHex (ax:int);
  725.                PushM    <BX,CX,DX,AX>            ; begin
  726.                MOV      AH, 2                    ;   ah:= 2;
  727.                MOV      CX, 4                    ;   cx:= 4;
  728. WriteLoop1:    POP      BX                       ;   for i:= 1 to cx do begin
  729.                ROL      BX, 1                    ;     bx:= Rotate(bx,1);
  730.                ROL      BX, 1                    ;     bx:= Rotate(bx,1);
  731.                ROL      BX, 1                    ;     bx:= Rotate(bx,1);
  732.                ROL      BX, 1                    ;     bx:= Rotate(bx,1);
  733.                PUSH     BX                       ;
  734.                AND      BX, 000Fh                ;     bx:= bx mod 16;
  735.                MOV      DL, HexCif[BX]           ;     dl:= HexCif[bx];
  736.                INT      Dos                      ;     write(dl);
  737.                LOOP     WriteLoop1               ;   end
  738.                PopM     <AX,DX,CX,BX>            ; end;
  739.                RET                               ;
  740. ;------------------------------------------------+ { Local constant }
  741. HexCif         DB       '0123456789ABCDEF'       ; const HexCif = '0..9ABCDEF';
  742. WriteHex       ENDP                              ;
  743. ;------------------------------------------------+------------------------------
  744.  
  745. ;--- Test if already installed -------------------------------------------------
  746.  
  747. Begin:                                         ; begin
  748.                MOV      AL, CritErrInt          ;
  749.                MOV      AH, GetVector            ;
  750.                INT      Dos                      ; GetVect(CritErrInt,es:bx);
  751.                PUSH     ES                       ; Save(Int24hSeg);
  752.                PUSH     BX                       ; Save(Int24hOfs);
  753.                                                  ;  { Install by modifying PSP }
  754.                MOV      PSP24hOfs, Offset New24h ; PSP24hOfs:= Ofs(New24h);
  755.                MOV      AH, GetVector            ;  { See if already installed }
  756.                MOV      AL, IDvector             ; GetVect(IDvector,es:bx);
  757.                INT      Dos                      ;
  758.                CMP      ES:IDword, IDsign        ; if es:IDword = IDsign
  759.                JNE      NotInst                  ; then begin
  760.  
  761. ;--- Handler already installed -------------------------------------------------
  762.                                                  ;    { Reinstall handler }
  763.                MOV      PSP24hSeg, ES            ;   PSP24hSeg:= es;
  764.                                                  ;    { Update stored address }
  765.                                                  ;    { of old handler.       }
  766.                POP      ES:OldInt24hOfs          ;   Rest(es:OldInt24hOfs);
  767.                POP      ES:OldInt24hSeg          ;   Rest(es:OldInt24hSeg);
  768.                MOV      AX, 4C00h                ;   Halt(0)
  769.                INT      Dos                      ; end;
  770.  
  771. ;--- Handler not installed -----------------------------------------------------
  772.  
  773. NotInst:       MOV      DX, Offset ProgInfo      ;  { Print program info }
  774.                MOV      AH, PrintStr             ; write(ProgInfo);
  775.                INT      Dos                      ;
  776.                MOV      AX, 0D44Dh               ;  { Test if 4DOS is present }
  777.                XOR      BX, BX                   ; ax:= 0D44Dh;
  778.                INT      MultiPlex                ; bx:= 0;
  779.                CMP      AX, 44DDh                ; MultiPlex(ax,bx);
  780.                JE       Found4DOS                ; if ax <> 44DDh
  781.                MOV      DX, Offset LoadErr1      ; then begin
  782.                MOV      AH, PrintStr             ;    { 4DOS not found }
  783.                INT      Dos                      ;   write(LoadErr1);
  784.                MOV      AH, GetKeyPress          ;    { Wait for key press }
  785.                INT      Dos                      ;   GetKeyPress;
  786.                MOV      AX, 4C01h                ;   Halt(1)
  787.                INT      Dos                      ; end
  788. Found4DOS:                                       ;  { Install by modifying PSP }
  789.                POP      OldInt24hOfs             ; OldInt24hOfs:= Int24hOfs;
  790.                POP      OldInt24hSeg             ; OldInt24hSeg:= Int24hSeg;
  791.                                                  ;
  792.                MOV      BX, CS                   ;  { Calc. new segm. value }
  793.                SUB      BX, 10h                  ;
  794.                MOV      PSP24hSeg, BX            ; PSP24hSeg:= Seg(New24h);
  795.  
  796. ;--- Release Environment Block -------------------------------------------------
  797.                MOV      ES, CS:EnvSegm           ;  { Release environm. block }
  798.                MOV      AH, FreeMem              ; ES:= ^Env;
  799.                INT      Dos                      ; FreeMem(ES);
  800. ;--- Screen-Detection ----------------------------------------------------------
  801.                MOV      AH, 12h                  ;  { Test for EGA+ adapter }
  802.                MOV      BL, 10h                  ; bl:= 10h;
  803.                INT      Video                    ; GetEGAinfo(bl);
  804.                CMP      BL, 10h                  ; if bl <> 10h
  805.                JE       TestCOorBW               ; then begin
  806.                MOV      Patch1, 0A026h           ;   PatchByte(Patch1);
  807.                MOV      [Patch1+2], 0484h        ;   PatchByte(Patch1+2)
  808. TestCOorBW:                                      ; end;
  809.                INT      Equipmnt                 ; BIOS(Equip);
  810.                TEST     AX, Bit5+Bit4            ; if Bit4 and Bit5
  811.                JNP      EndDetect                ; then ScrSeg:= MonoSeg
  812.                MOV      ScrSeg, MonoSeg          ; else ScrSeg:= ColrSeg;
  813. EndDetect:                                       ;
  814. ;--- Test for memory info switch as paramter -----------------------------------
  815.                MOV      SI, Offset ParmStr       ; si:= Ofs(ParmStr);
  816.                XOR      CX, CX                   ; cx:= Length(ParmStr);
  817.                MOV      CL, ParLen               ; if cx <> 0
  818.                JCXZ     NoMemStat                ; then begin
  819.                                                  ;  { ParmStr[1] always space }
  820.                                                  ;  { or switch char ('/').   }
  821. ParTest:       INC      SI                       ;   repeat
  822.                OR       Byte Ptr [SI], 20h       ;     Inc(si); Dec(cx);
  823. SwcTest:       CMP      Byte Ptr [SI], (MemSwc or 20h);LowCase([si]);
  824.                LOOPNE   ParTest                  ;   until ([si]=MemSwc)or(cx=0);
  825.                JNE      NoMemStat                ;   if [si] = MemSwc
  826. ;--- Print Memory Statistics ---------------------------------------------------
  827.                MOV      DX, Offset MemInfo       ;   then begin
  828.                MOV      AH, PrintStr             ;    { Print memory status }
  829.                INT      Dos                      ;     write(MemInfo);
  830.                MOV      AX, CS                   ;      { Print load address }
  831.                CALL     WriteHex                 ;     WriteHex(CS);
  832.                MOV      DX, Offset MemInfo1      ;
  833.                MOV      AH, PrintStr             ;      { Print memory usage }
  834.                INT      Dos                      ;     write(MemInfo1);
  835.                MOV      AX, Offset EndOfCode-100h;
  836.                CALL     WriteInt                 ;     WriteInt(EndOfCode-100);
  837.                MOV      DX, Offset MemInfo2      ;
  838.                MOV      AH, PrintStr             ;     writeln(MemInfo2);
  839.                INT      Dos                      ;     writeln;
  840.                                                  ;   end
  841. NoMemStat:                                       ; end;
  842. ;--- Install Identification mark -----------------------------------------------
  843.                MOV      AL, IDvector             ;  { Install identification }
  844.                MOV      AH, GetVector            ; GetVector(IDvect,es:bx);
  845.                INT      Dos                      ; OldIDvectSeg:= es;
  846.                MOV      OldIDvectOfs, BX         ; OldIDvectOfs:= bx;
  847.                MOV      OldIDvectSeg, ES         ;
  848.                PUSH     DS                       ; Save(ds); {!}
  849.                MOV      DS, PSP24hSeg            ; ds:= Seg(IDintSeg);
  850.                MOV      DX, Offset IDintOfs      ; dx:= Ofs(IDintOfs);
  851.                MOV      AH, SetVector            ; SetVect(IDvect,ds:dx);
  852.                INT      Dos                      ;
  853. ;--- High Load precautions under QEMM and 386Max -------------------------------
  854.                PUSH     DS                       ;  { Modify parent PSP. }
  855.                MOV      DS, CS:ParentPSP         ; ds:= Seg(ParentPSP);
  856.                MOV      PSP24hOfs, Offset New24h ; ds:PSP24hOfs:= Ofs(New24h);
  857.                POP      PSP24hSeg                ; ds:PSP24hSeg:= Seg(New24h);
  858.                POP      DS                       ; Rest(ds);
  859. ;--- Move code to overlay unused part of PSP -----------------------------------
  860.                PUSH     CS                       ;  { Overlay FCB-area and
  861.                POP      ES                       ;    parameters to save mem. }
  862.                MOV      DI, Offset FreePSP       ; di:= Ofs(FreePSP);
  863.                MOV      SI, Offset IDintOfs      ; si:= Ofs(code);
  864.                MOV      CX, Offset EndOfCode-IDintOfs; cx:= EndOfCode-IDintOfs;
  865.                CLD                               ; for i:= 0 to cx-1 do
  866.                REP      MOVSB                    ;   Mem[di+i]:= Mem[si+i];
  867. ;--- Terminate and Stay Resident ----------------+------------------------------
  868.            MOV    DX, Offset EndOfCode-(IDintOfs-FreePSP)
  869.            INT    TSR             ; Keep
  870.                            ; end.
  871. ;----------------------------------------------+--------------------------------
  872.  
  873. ProgInfo       DB       '4DOS Critical Error Handler Version 2.00, rev. B',10,13
  874.                DB       'Written by Niels Jensen  -  May, 1993',13,10,'$'
  875.  
  876. MemInfo        DB       'Resident at address $'
  877. MemInfo1       DB       ':0000 (hex) consuming $'
  878. MemInfo2       DB       ' bytes of memory.',13,10,'$'
  879.  
  880. LoadErr1       DB       10
  881.                DB       'The critical error handler is not installed due to an error.',13,10,10
  882.                DB       'The running command interpreter is not a version of 4DOS or NDOS.',10,13
  883.                DB       'You need the 4DOS or NDOS command interpreter from JP Software to',10,13
  884.                DB       'use this handler - it will not work under COMMAND.COM.',13,10,10
  885.                DB       'Press any key to continue . . .$'
  886. ;------------------------------------------------+------------------------------
  887. Code           ENDS
  888.                END      Start
  889.