home *** CD-ROM | disk | FTP | other *** search
/ Simtel MSDOS - Coast to Coast / simteldosarchivecoasttocoast.iso / keyboard / kbedit20.asm < prev    next >
Assembly Source File  |  1994-03-04  |  75KB  |  3,325 lines

  1.         TITLE    KEYBOARD BUFFER
  2.         PAGE 60, 132
  3.  
  4. ;**********************************************************************
  5. ;* Keyboard Buffer and Editor    VERSION 2.0
  6. ;*
  7. ;*      This program provides two independent functions:
  8. ;*       1) it extends the DOS_keyboard_buffer to 128 characters and
  9. ;*       2) it provides command-line storage and editing facilities
  10. ;*
  11. ;*      Source: self contained 8088/8086 Macro Assembler Language
  12. ;*      Script: MASM KBEDIT;
  13. ;*              LINK KBEDIT;
  14. ;*              EXE2BIN KBEDIT.EXE KBEDIT.SYS
  15. ;*
  16. ;*      Usage:  install as a device driver by including a statement
  17. ;*              in the  CONFIG.SYS file of the form:
  18. ;*
  19. ;*                DEVICE=KBEDIT.SYS [B:nnn] [C:nnn] [K:nnn] [/A] [/N]
  20. ;*
  21. ;*              B:nnn      is buffer size for stored strings in bytes
  22. ;*                       (default = 512)
  23. ;*              C:nnn      is maximum number of strings in the string buffer
  24. ;*                       (default = 32)
  25. ;*              K:nnn      is keyboard buffer size in characters
  26. ;*                       (default = 128)
  27. ;*
  28. ;**********************************************************************
  29.  
  30. JMPS            MACRO    LABEL
  31.                 JMP        SHORT    LABEL
  32.                 ENDM
  33.  
  34. CLR                MACRO    REG
  35.                 SUB        REG, REG
  36.                 ENDM
  37.  
  38. GET_CHAR        MACRO
  39.  
  40.         ;----- return keyboard input in AL through DOS-call
  41.         ;
  42.  
  43.                 MOV        AH, 8    ;; function number
  44.                 INT        21H
  45.                 ENDM
  46.  
  47.  
  48.         ; -----DOS-keyboard pointers
  49.         ;
  50.  
  51. DOS_DATA_AREA            SEGMENT AT 40H
  52.  
  53.                         ORG        17H
  54. DOS_KB_FLAG                DB        ?
  55.                         ORG        1AH
  56. KB_HEAD                    DW        ?
  57. KB_TAIL                    DW        ?
  58.                         ORG        71H
  59. DOS_BREAK_FLAG            DW        ?
  60.                         ORG        80H
  61. DOS_BUFFER_START        DW        ?
  62. DOS_BUFFER_END            DW        ?
  63.  
  64. DOS_DATA_AREA            ENDS
  65.  
  66.  
  67.         ;----- interrupt_vector_adresses_equates
  68.         ;
  69.  
  70. KB_INTERRUPT            EQU        4*9H
  71. KB_IO_ROUTINE            EQU        4*16H
  72. DOS_FUNCTION_INT        EQU        4*21H
  73.  
  74.         ;----- equates
  75.         ;
  76.  
  77.   NULL            EQU        00H
  78.   CR            EQU        0DH
  79.   LF            EQU        0AH
  80.   BACKSPACE        EQU        08H
  81.   ESCAPE        EQU        1BH
  82.   CTRL_U        EQU     15H
  83.   CTRL_W        EQU     17H
  84.   EOF            EQU        1AH
  85.   ACK            EQU        06H
  86.   TAB            EQU        09H
  87.  
  88.   OFF            EQU        0
  89.   ON            EQU        NOT OFF
  90.   NOT_INST        EQU        0AAH            ;
  91.  
  92.  
  93.         ;-----
  94.         ; the following keys are identified by extended ascii-codes
  95.         ; the second byte is given in these equates
  96.         ;
  97.  
  98.   INSERT        EQU        052H
  99.   DELETE        EQU        053H
  100.   CURSOR_LEFT    EQU        04BH
  101.   CURSOR_RIGHT    EQU        04DH
  102.   PREV_LINE        EQU        048H    ; = cursor up
  103.   NEXT_LINE        EQU        050H    ; = cursor down
  104.   CURSOR_BEGIN    EQU        047H    ; = home key
  105.   CURSOR_END    EQU        04FH    ; = end key
  106.   F1            EQU        03BH
  107.   F2            EQU        03CH
  108.   F3            EQU        03DH
  109.   F4            EQU        03EH
  110.   F5            EQU        03FH
  111.   F6            EQU        040H
  112.   F7            EQU        041H
  113.   CTRL_LEFT        EQU        073H
  114.   CTRL_RIGHT    EQU        074H
  115.   CTRL_HOME        EQU        077H
  116.   CTRL_END        EQU        075H
  117.   CTRL_PGUP        EQU        084H
  118.   CTRL_PGDN        EQU        076H
  119.   SHIFT_F5        EQU        058H
  120.   SHIFT_F6        EQU        059H
  121.   ALT_1            EQU        078H
  122.   ALT_2            EQU        079H
  123.   ALT_3            EQU        07AH
  124.   ALT_4            EQU        07BH
  125.   ALT_5            EQU        07CH
  126.   ALT_6            EQU        07DH
  127.   ALT_7            EQU        07EH
  128.   ALT_8            EQU        07FH
  129.   ALT_9            EQU        080H
  130.   ALT_0            EQU        081H
  131.  
  132.  
  133.  
  134.  
  135. CODE            SEGMENT PUBLIC
  136.                 ASSUME    CS:CODE
  137.  
  138. START_CODE        =        $
  139.  
  140.       HEADER    DD        -1                ; device_driver obligatory
  141.                                         ; first four bytes
  142.       ATTRIBUTE DW        8000H            ; attribute byte:
  143.  
  144.                 DW        D_STRATEGY
  145.                 DW        D_INTERRUPT
  146.  
  147.      DRVNAME    DB        'KBEDT     '
  148.  
  149.         ;----- installation messages
  150.         ;
  151.  
  152.  MSG_VERSION    DB        'Keyboard Buffer and Command Line Editor,'
  153.                 DB        '    Version 2.0', CR, LF, LF, NULL
  154.                 DB        ' author: P. Kranenburg'
  155.                 DB        ' University of Leiden, The Netherlands'
  156.  
  157.  
  158.         ;----- keyboard related messages
  159.         ;
  160.  
  161.  MSG_KB_1        DB        '  Keyboard buffer size            : ', NULL
  162.  MSG_KB_2        DB        ' characters', CR, LF, NULL
  163.  
  164.  MSG_KB_NO_1    DB        '  KeyBoard Buffer size ', NULL
  165.  MSG_KB_NO_2    DB        ' is too small: not installed', CR, LF, NULL
  166.  MSG_KB_IN        DB        '  KeyBoard Buffer Installed'
  167.                 DB        CR, LF, NULL
  168.  MSG_KB_UN        DB        '  KeyBoard Buffer Uninstalled'
  169.                 DB        CR, LF, NULL
  170.  MSG_KB_PR        DB        '  Keyboard Buffer already installed'
  171.                 DB        CR, LF, NULL
  172.  MSG_KB_NOT_PR    DB        '  Keyboard Buffer was not active'
  173.                 DB        CR, LF, NULL
  174.  
  175.  
  176.         ;----- editor related messages
  177.         ;
  178.  
  179.  MSG_EDT_1        DB        '  Command line buffer size        : ', NULL
  180.  MSG_EDT_2        DB        ' bytes', CR, LF
  181.                 DB        '  Number of commands in buffer : ', NULL
  182.  MSG_EDT_3        DB        ' ', CR, LF, LF, NULL
  183.  
  184.  MSG_EDT_IN        DB        '  Command Line Editor Installed'
  185.                 DB        CR, LF, NULL
  186.  
  187.  MSG_EDT_UN        DB        '  Command Line Editor Uninstalled'
  188.                 DB        CR, LF, NULL
  189.  
  190.  MSG_EDT_PR        DB        '  Command Line Editor already installed'
  191.                 DB        CR, LF, NULL
  192.  
  193.  MSG_EDT_NOT_PR DB        '  Command Line Editor was not active'
  194.                 DB        CR, LF, NULL
  195.  
  196.  
  197.         ;----- pointers to request_header
  198.         ;
  199.  
  200. REQ_HEADER_OFS    DW        ?
  201. REQ_HEADER_SEG    DW        ?
  202.  
  203.  
  204.         ;----- control data sent to output-routine of driver
  205.         ;
  206.  
  207. EXPECTSECOND    DB        OFF        ; first/second byte indicator
  208. FIRSTPART        DB        LOW ON    ; first byte of incoming control codes
  209. KB_INST            DB        OFF        ; keyboard buffer presence flag
  210. EDT_INST        DB        NOT_INST; keyboard editor presence flag
  211. BIOS_TTY_SW        DB        LOW ON    ; true on driver initialization
  212. TEN                DW        10        ; operand for MULtiply operation
  213.  
  214.  
  215.         ;----- local stack for processing buffered input function call
  216.         ;
  217.  
  218. LOCAL_STACK        DW        256 DUP(?)
  219.  
  220.  
  221.         ;----- containers for user stack-segment and -pointer
  222.         ;
  223.  
  224. CALLERS_STACK_SEGMENT    DW        ?
  225. CALLERS_STACK_POINTER    DW        ?
  226.  
  227. RET_FROM_STACK_ROUTINES DW        ?        ; temp var for SETSTACK and RESETSTACK
  228.  
  229.  
  230.         ;----- routines to switch stacks
  231.         ;
  232.  
  233. SETSTACK        PROC    NEAR
  234.  
  235.                 POP        RET_FROM_STACK_ROUTINES       ; save return address
  236.                 MOV        CALLERS_STACK_SEGMENT, SS  ; now save user stack
  237.                 MOV        CALLERS_STACK_POINTER, SP  ;
  238.                 PUSH    CS
  239.                 POP        SS                           ; install new stack
  240.                 MOV        SP, OFFSET LOCAL_STACK + SIZE LOCAL_STACK
  241.                 JMP        RET_FROM_STACK_ROUTINES       ; return
  242. SETSTACK        ENDP
  243.  
  244. RESETSTACK        PROC    NEAR
  245.  
  246.                 POP        RET_FROM_STACK_ROUTINES
  247.                 PUSH    CALLERS_STACK_SEGMENT
  248.                 POP        SS                           ; restore stack registers
  249.                 MOV        SP, CALLERS_STACK_POINTER  ;
  250.                 JMP        RET_FROM_STACK_ROUTINES
  251. RESETSTACK        ENDP
  252.  
  253.  
  254.  
  255.         ;----- enlarged keyboard buffer
  256.         ;
  257.  
  258. KBBUFFER_SIZE    DW        256
  259. KBBUFFER        DW        ?
  260.  
  261.  
  262.         ;----- containers for old interrupt_vector_adresses
  263.         ;
  264.  
  265. OLD_KEYB_IO                DD        ?
  266. OLD_KEYB_INT            DD        ?
  267. OLD_FUNCTION_INT        DD        ?
  268. OLD_DOS_BUFFER_START    DW        ?
  269. OLD_DOS_BUFFER_END        DW        ?
  270.  
  271.  
  272.  
  273.  
  274. ;#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#
  275. ;#
  276. ;# *** Description of data-structure used in Editor-routines ***
  277. ;#
  278. ;#    Quantities                                           Assignments
  279. ;#
  280. ;#
  281. ;#      - actice/inactive switch                        - - -     EDT_INST
  282. ;#
  283. ;#     Buffer data:
  284. ;#
  285. ;#      - current character pointer in buffer            - - -     register DI
  286. ;#      - current number of characters in buffer        - - -     register BL
  287. ;#      - current number of characters up to but        - - -     register BH
  288. ;#        not including the current cursor
  289. ;#      - maximum number of characters in buffer        - - -     register DL
  290. ;#        exclusive final Carriage Return
  291. ;#      - insert/overwrite mode                        - - -     INSERT_TOGGLE
  292. ;#
  293. ;#     Display data:
  294. ;#
  295. ;#      - screen coordinates of start displayed string- - -     STR_START_POS
  296. ;#      - screen coordinates of end displayed string    - - -     STR_END_POS
  297. ;#      - current video page                            - - -     VIDEO_PAGE
  298. ;#      - current cursor position on the screen        - - -     CURSOR_POS
  299. ;#      - cursor shape                                - - -     CURSOR_TYPE
  300. ;#      - current screen width                        - - -     MAX_COL
  301. ;#      - number of character rows                    - - -     MAX_ROW (fixed:25)
  302. ;#
  303. ;#      - full/partial editing capability                - - -     FULL_EDIT
  304. ;#      - defer-mode when redirected input/output        - - -     DEFER_DSPL
  305. ;#      - cursor positioning through ANSI-escape codes- - -     ANSI
  306. ;#
  307. ;#
  308. ;#
  309. ;#    Lay-out of the buffer passed through DS:DX
  310. ;#
  311. ;#
  312. ;#     +----------+----------+-------+--/ /--+---------+-------+--/ /--+--------+
  313. ;#     | BufLen    | #chars   | D(1)  |  ...  |D(#chars)| 'CR'     |    ...     |    N+3      |
  314. ;#     |      = N    |  in buf  |       |       |         |         |         |          |
  315. ;#     +----------+----------+-------+--/ /--+---------+-------+--/ /--+--------+
  316. ;#
  317. ;#    at offset 0: length of buffer (exclusive first two bytes and final CR)
  318. ;#              1: length of actual number of characters in buffer
  319. ;#                                  (exclusive final CR)
  320. ;#              2 .. [byte(1)]+1 : data
  321. ;#              [byte(2)]+2 : 'Carriage Return'
  322. ;#
  323. ;#
  324. ;# The buffer can contain a string on input as well. This is checked for at
  325. ;# entrance ( a carriage return must be present at the byte
  326. ;#              with index: [byte(2)]+2 )
  327. ;# If present the input string is inserted in the string buffer to make it
  328. ;# available for editing.
  329. ;#
  330. ;#
  331. ;#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#
  332.  
  333.  
  334.  
  335. INSERT_TOGGLE            DB        OFF
  336.  
  337. DEFER_DSPL                DB        OFF
  338. FULL_EDIT                DB        OFF
  339. CURSOR_TYPE                DW        ?                ; cursor-status on entry
  340. CURSOR_MASK                EQU        00011111B        ; mask for set cursor
  341. INSERT_SHIFT            DB        4                ; determines cursor-shape
  342.                                                 ; change in INSERT-mode
  343. CURSOR_POS                LABEL    WORD
  344. CURSOR_COL                DB        ?
  345. CURSOR_ROW                DB        ?
  346. STR_START_POS            LABEL    WORD
  347. STR_START_COL            DB        ?
  348. STR_START_ROW            DB        ?
  349. STR_END_POS                LABEL    WORD
  350. STR_END_COL                DB        ?
  351. STR_END_ROW                DB        ?
  352.  
  353. MAX_ROW                    EQU        25
  354. MAX_COL                    DB        80        ; assumed default for display-width
  355. VIDEO_PAGE                DB        0
  356.  
  357. ANSI                    DB        OFF
  358. ANSI_GET_CURSOR            DB        ESCAPE, '[6n', NULL
  359.  
  360.  
  361.      DEVICE_PROLOGUE    PROC    NEAR
  362.  
  363.         ;****************************************************************
  364.         ;*    Find out about devices attached to standard input and ouput by
  365.         ;*    issuing a IOCTL (044H) function call.
  366.         ;*
  367.         ;*    If either STDIN or STDOUT is attached to a file then writing
  368.         ;*    characters to STDOUT is deferred until editing is complete.
  369.         ;*
  370.         ;*    If STDOUT is NOT the Console Output then direct cursor
  371.         ;*    manipulation is disabled, i.e. when a multiple line string,
  372.         ;*    the cursor position on the screen does not reflect the current
  373.         ;*    position in the string.
  374.         ;*
  375.         ;*
  376.  
  377.     STDIN        EQU        0
  378.     STDOUT        EQU        1
  379.     ISDEV        EQU        0080H
  380.     ISCOT        EQU        0002H
  381.  
  382.                 PUSH    DX
  383.                 PUSH    BX
  384.  
  385.         ;----- initialize variables
  386.         ;
  387.                 MOV        DEFER_DSPL, ON
  388.                 MOV        FULL_EDIT, OFF;
  389.                 MOV        STR_START_POS, 0
  390.                 MOV        STR_END_POS, 0
  391.                 MOV        CURSOR_POS, 0
  392.  
  393.         ;----- check standard input
  394.         ;
  395.  
  396.                 MOV        BX, STDIN        ; BX is handle
  397.                 MOV        AX, 4400H        ; AL = 0: get device information
  398.                 INT        21H                ; status returned in DX
  399.                 TEST    DX, ISDEV
  400.                 JZ        DP_LX            ; if bit off then file
  401.                                         ;             else device
  402.  
  403.         ;----- check standard output
  404.         ;
  405.  
  406.                 MOV        BX, STDOUT        ; BX is handle
  407.                 MOV        AX, 4400H        ; AL = 0: get device information
  408.                 INT        21H                ; status returned in DX
  409.                 TEST    DX, ISDEV
  410.                 JZ        DP_LX            ; bit not set: file
  411.                 MOV        DEFER_DSPL, OFF ;
  412.                 TEST    DX, ISCOT
  413.                 JZ        DP_LX
  414.  
  415.                 CMP        ANSI, ON        ; ANSI or BIOS cursor handling ?
  416.                 JE        DP_L1
  417.  
  418.         ;----- get video state
  419.         ;
  420.  
  421.                 MOV        AH, 0FH
  422.                 INT        10H
  423.                 MOV        MAX_COL, AH
  424.                 MOV        VIDEO_PAGE, BH
  425.  
  426.         ;----- get cursor position and attributes
  427.         ;
  428.  
  429.                 MOV        AH, 03            ; BH still contains video page number
  430.                 INT        10H                ; get current cursor
  431.                 MOV        CURSOR_TYPE, CX ; save cursor data
  432.                 JMPS    DP_L2
  433.  
  434.          DP_L1:
  435.                 LEA        SI, ANSI_GET_CURSOR        ; get cursor position through
  436.                 CALL    PRINT                    ;  ANSI-sequence <esc>[6n
  437.  
  438.                 CALL    ANSI_REPLY                ; get ANSI-reply
  439.  
  440.          DP_L2:
  441.                 MOV        CURSOR_POS, DX            ; initialize cursor variables
  442.                 MOV        STR_START_POS, DX        ;
  443.                 MOV        STR_END_POS, DX            ;
  444.                 MOV        FULL_EDIT, ON            ;
  445.  
  446.          DP_LX:
  447.                 POP        BX
  448.                 POP        DX
  449.                 RET
  450.      DEVICE_PROLOGUE    ENDP
  451.  
  452.  
  453.      DEVICE_EPILOGUE    PROC    NEAR
  454.  
  455.         ;-----------------------------------------------------
  456.         ; in: SI = pointer to start of string
  457.         ; If DEFER_DSPL is ON then now is the time to display
  458.         ; the completed current string.
  459.         ; A final carriage return is sent to standard output
  460.         ; in all cases.
  461.         ;
  462.  
  463.                 MOV        INSERT_TOGGLE, OFF
  464.                 CALL    SET_CURSOR_TYPE
  465.  
  466.                 CMP        DEFER_DSPL, ON
  467.                 MOV        DEFER_DSPL, OFF ; tell DISPLAY_COMPLEX to no longer
  468.                                         ;  postpone display
  469.                 JNE        DE_L2
  470.  
  471.         ;-----    must send string to STDOUT now
  472.  
  473.                 CLR        CH
  474.                 MOV        CL, [SI-1]        ; load length of string
  475.                 JCXZ    DE_L2
  476.  
  477.                 CLD
  478.         DE_L1:
  479.                 LODSB
  480.                 CALL    DISPLAY_COMPLEX
  481.                 LOOP    DE_L1
  482.  
  483.         DE_L2:
  484.                 MOV        AL, CR
  485.                 CALL    DISPLAY_CHAR
  486.                 RET
  487.      DEVICE_EPILOGUE    ENDP
  488.  
  489.  
  490.      SET_CURSOR_POS        PROC    NEAR
  491.  
  492.         ;-----------------------------------------------
  493.         ; If FULL_EDIT is ON then the cursor position
  494.         ; on the screen is updated according to the value
  495.         ; in CURSOR_POS.
  496.         ; If ANSI is ON then cursor-positioning is done
  497.         ; through ANSI-escape-sequences, else through
  498.         ; BIOS video-routines.
  499.         ;
  500.                 PUSH    DX
  501.                 PUSH    BX
  502.                 PUSH    AX
  503.                 CMP        FULL_EDIT, ON
  504.                 JNE        SCP_LX
  505.                 MOV        DX, CURSOR_POS
  506.  
  507.                 CMP        ANSI, ON
  508.                 JE        SCP_L1
  509.  
  510.         ;----- cursor positioning through BIOS
  511.         ;       function no. 2, DX = cursor-pos
  512.         ;
  513.                 MOV        BH, VIDEO_PAGE
  514.                 MOV        AH, 2
  515.                 INT        10H
  516.                 JMPS    SCP_LX
  517.  
  518.         SCP_L1:
  519.  
  520.         ;----- cursor positioning through ANSI
  521.         ;       output ANSI-sequence <esc>[<col>;<row>f
  522.         ;       Note: ANSI row- and column-numbers are
  523.         ;       in the range: 1 .. MaxRow/MaxCol
  524.         ;
  525.                 MOV        AL, ESCAPE
  526.                 CALL    WRITE_CHAR        ; <esc>
  527.                 MOV        AL, '['
  528.                 CALL    WRITE_CHAR        ; [
  529.                 MOV        AL, DH            ; print row number
  530.                 INC        AL
  531.                 CLR        AH                ;
  532.                 CALL    PRINT_NUM        ;
  533.                 MOV        AL, ';'            ; ;
  534.                 CALL    WRITE_CHAR
  535.                 MOV        AL, DL            ; print column number
  536.                 INC        AL
  537.                 CLR        AH                ;
  538.                 CALL    PRINT_NUM        ;
  539.                 MOV        AL, 'f'            ; f
  540.                 CALL    WRITE_CHAR
  541.         SCP_LX:
  542.                 POP        AX
  543.                 POP        BX
  544.                 POP        DX
  545.                 RET
  546.      SET_CURSOR_POS        ENDP
  547.  
  548.  
  549.      SET_CURSOR_TYPE    PROC    NEAR
  550.  
  551.         ;----------------------------------------------------------------
  552.         ; Set cursor shape to value in variable CURSOR_TYPE.
  553.         ; This can only be done through BIOS-VIDEO call so
  554.         ; full edit mode must be ON and ANSI mode OFF
  555.         ;
  556.  
  557.                 CMP        FULL_EDIT, ON
  558.                 JNE        SCT_L2
  559.                 CMP        ANSI, OFF        ; no cursor type change
  560.                 JNE        SCT_L2            ; if ANSI on
  561.                 PUSH    CX
  562.                 PUSH    AX
  563.                 MOV        CX, CURSOR_TYPE            ; set proper cursor type
  564.                 CMP        INSERT_TOGGLE, ON
  565.                 JNE        SCT_L1                    ; if insert-state
  566.                 SUB        CH, INSERT_SHIFT        ; make larger cursor
  567.         SCT_L1:
  568.                 AND        CH, CURSOR_MASK
  569.                 MOV        AH, 01
  570.                 INT        10H
  571.                 POP        AX
  572.                 POP        CX
  573.         SCT_L2:
  574.                 RET
  575.      SET_CURSOR_TYPE    ENDP
  576.  
  577.         ANSI_REPLY        PROC    NEAR
  578.  
  579.         ;-------------------------------
  580.         ; get reply from ANSI-driver
  581.         ; must be of the form <esc>[#;#R<cr>
  582.         ; out: DX=#;#
  583.         ;
  584.                 PUSH    CX
  585.                 PUSH    BX
  586.  
  587.                 GET_CHAR                ;
  588.                 CMP        AL, ESCAPE        ; <esc> ?
  589.                 JNE        AR_LX
  590.                 GET_CHAR
  591.                 CMP        AL, '['            ; [
  592.                 JNE        AR_LX
  593.  
  594.                 MOV        BL, ';'            ; get first # (row)
  595.                 CLR        CX
  596.         AR_L1:                            ; CX = intermediate number
  597.                 GET_CHAR
  598.                 CMP        AL, BL            ;
  599.                 JE        AR_L3            ;
  600.                 CMP        AL, '9'            ; read number and convert
  601.                 JA        AR_LX            ;
  602.                 SUB        AL, '0'            ;
  603.                 JB        AR_LX            ;
  604.                 XCHG    CX, AX
  605.                 PUSH    DX
  606.                 MUL        TEN
  607.                 POP        DX
  608.                 JNC        AR_L2            ; test for overflow
  609.                 OR        AX, TEN            ; do something to reset Z-flag
  610.                 JMPS    AR_LX
  611.         AR_L2:
  612.                 CLR        CH                ; add new digit
  613.                 ADD        AX, CX
  614.                 XCHG    CX, AX
  615.                 JMP        AR_L1
  616.  
  617.         AR_L3:
  618.                 DEC        CL                ; 1 .. Max --> 0 .. Max-1
  619.                 CMP        BL, 'R'            ; read second # (column)
  620.                 JE        AR_L4
  621.                 MOV        DH, CL
  622.                 MOV        BL, 'R'
  623.                 CLR        CX
  624.                 JMP        AR_L1
  625.  
  626.         AR_L4:
  627.                 MOV        DL, CL
  628.  
  629.         AR_LX:
  630.                 GET_CHAR                ; wait for Carriage Return
  631.                 CMP        AL, CR            ;
  632.                 JNE        AR_LX            ;
  633.  
  634.                 POP        BX
  635.                 POP        CX
  636.                 RET
  637.         ANSI_REPLY        ENDP
  638.  
  639.  
  640. SECOND_CODE_TABLE        LABEL    BYTE
  641.  
  642.         ;----- table of extended ascii-codes
  643.         ;
  644.  
  645.                         DB        INSERT
  646.                         DB        DELETE
  647.                         DB        CURSOR_LEFT
  648.                         DB        CURSOR_RIGHT
  649.                         DB        PREV_LINE
  650.                         DB        NEXT_LINE
  651.                         DB        CURSOR_BEGIN
  652.                         DB        CURSOR_END
  653.                         DB        F1
  654.                         DB        F2
  655.                         DB        F3
  656.                         DB        F4
  657.                         DB        F5
  658.                         DB        F6
  659.                         DB        F7
  660.                         DB        CTRL_LEFT
  661.                         DB        CTRL_RIGHT
  662.                         DB        CTRL_HOME
  663.                         DB        CTRL_END
  664.                         DB        CTRL_PGUP
  665.                         DB        CTRL_PGDN
  666.                         DB        SHIFT_F5
  667.                         DB        SHIFT_F6
  668.                         DB        ALT_1
  669.                         DB        ALT_2
  670.                         DB        ALT_3
  671.                         DB        ALT_4
  672.                         DB        ALT_5
  673.                         DB        ALT_6
  674.                         DB        ALT_7
  675.                         DB        ALT_8
  676.                         DB        ALT_9
  677.                         DB        ALT_0
  678.                         DB        00                ; end of table
  679.  
  680. CODE_TABLE_LENGTH        =      $ - OFFSET SECOND_CODE_TABLE
  681.  
  682.         ;----- ECJT = Extended Code Jump Table
  683.         ;
  684.  
  685.         ECJT    LABEL    WORD
  686.                 DW        MAIN_LOOP_RETURN
  687.                 DW        ALT_DIGIT        ; get old string
  688.                 DW        ALT_DIGIT
  689.                 DW        ALT_DIGIT
  690.                 DW        ALT_DIGIT
  691.                 DW        ALT_DIGIT
  692.                 DW        ALT_DIGIT
  693.                 DW        ALT_DIGIT
  694.                 DW        ALT_DIGIT
  695.                 DW        ALT_DIGIT
  696.                 DW        ALT_DIGIT
  697.  
  698.                 DW        SHIFT_F6_R        ; cursor shape control
  699.                 DW        SHIFT_F5_R        ; for INSERT-mode
  700.  
  701.                 DW        CTRL_PGDN_R        ; cursor-bottom up
  702.                 DW        CTRL_PGUP_R        ; cursor-top up
  703.                 DW        CTRL_END_R        ; cursor-bottom down
  704.                 DW        CTRL_HOME_R        ; cursor-top down
  705.                 DW        CTRL_RIGHT_R    ; cursor up
  706.                 DW        CTRL_LEFT_R        ; cursor down
  707.  
  708.                 DW        F7_R            ; zero-byte in string
  709.                 DW        F6_R            ; control-Z in string
  710.                 DW        F5_R            ; add string to buffer
  711.                 DW        F4_R            ; erase from begin to cursor
  712.                 DW        F3_R            ; erase from cursor to end
  713.                 DW        F2_R            ; word right
  714.                 DW        F1_R            ; word left
  715.  
  716.                 DW        CURSOR_END_R
  717.                 DW        CURSOR_BEGIN_R
  718.                 DW        NEXT_LINE_R
  719.                 DW        PREV_LINE_R
  720.                 DW        CURSOR_RIGHT_R
  721.                 DW        CURSOR_LEFT_R
  722.                 DW        DELETE_R
  723.                 DW        INSERT_R
  724.  
  725.                 PAGE
  726.  
  727. ;#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-
  728. ;#
  729. ;#    *** Data structure to maintain a buffer of previous strings ***
  730. ;#
  731. ;#
  732. ;#                                                       ___/------ STR_BUF_START
  733. ;#     C_TBL_START ------\ _________                      |_x_|
  734. ;#                        |_________|                      |_x_|
  735. ;#                        |_________|                      |_x_|
  736. ;#                        |_________|                      |_x_|
  737. ;#      C_TBL_HEAD ------>|_________|-------\              |_x_|
  738. ;#                        |_________|----\   \          |_x_|
  739. ;#                        |_________|        \    \-------> |_x_|
  740. ;#                        |_________|         \              |_y |
  741. ;#                        |_________|          \              |_y |
  742. ;#      C_TBL_TAIL ------>|_________|-- \       \          |_y_|
  743. ;#                        |_________|       \    \          |_y_|
  744. ;#                        |_________|        \     \          |_y |
  745. ;#    C_TBL_END ---------/                 \      \-----> |_y_|
  746. ;#                                          \              ~      ~
  747. ;#                        C-table               \          ~_ _~
  748. ;#                                            \          |_z_|
  749. ;#                                             \          |_z_|
  750. ;#                                              \          |_z_|
  751. ;#                                               \----> |_z_|
  752. ;#                                                      |___|
  753. ;#                                                      |___|
  754. ;#                                                      |___|
  755. ;#                                                           \------- STR_BUF_END
  756. ;#
  757. ;#                                                  string-buffer
  758. ;#
  759. ;#
  760. ;#    The entries in C_TABLE point to the last character of a string
  761. ;#    in STR_BUF.
  762. ;#
  763. ;#    C_TBL_HEAD points to the entry in C-table which identifies the oldest
  764. ;#    string in the string-buffer.
  765. ;#
  766. ;#    C_TBL_TAIL points to the entry in C-table which points to the last
  767. ;#    byte of free space in the string-buffer.
  768. ;#
  769. ;#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-
  770.  
  771.  
  772.     STR_BUF_SIZE        DW        512                ; default string-buffer
  773.                                                 ; size is 512
  774.     STR_BUF_START        DW        ?
  775.     STR_BUF_END            DW        ?
  776.  
  777.         ;----- pointers to mark begin and end of data in the string buffer
  778.         ;
  779.  
  780.     STR_BUF_HEAD        DW        ?
  781.     STR_BUF_TAIL        DW        ?
  782.  
  783.         ;----- table of pointers to strings in string buffer
  784.         ;
  785.         ;       pointers in string pointer table to locate
  786.         ;       the string currently being processed
  787.         ;
  788.         ;       C_TBL_HEAD identifies the oldest string in STR_BUF
  789.         ;       C_TBL_TAIL points to the last free byte in STR_BUF, i.e. the byte
  790.         ;       before the begin of the string pointed to by C_TBL_HEAD
  791.         ;
  792.  
  793.  
  794. C_TBL_SIZE          DW      60                    ; default 30 commands
  795.  
  796.     C_TBL_START      DW      ?
  797.     C_TBL_END      DW      ?
  798.  
  799.     C_TBL_HEAD      DW      ?
  800.     C_TBL_TAIL      DW      ?
  801.  
  802.     CURRENT          DW      ?                        ; identifies the string current-
  803.                                                 ; ly being edited
  804.  
  805.         ;************************************************************
  806.         ; Next are a couple of routines to handle pointer-
  807.         ; updating for the cyclic buffers defined above.
  808.         ; Pointers are passed in the BX register
  809.         ; BX is advanced to the next or previous table-item.
  810.         ;************************************************************
  811.  
  812.   SCROLLUP_TBL    PROC    NEAR
  813.                 CMP        BX, C_TBL_START ; at start of table?
  814.                 JNE        SUT_L1            ; no: then go update pointer
  815.                 MOV        BX, C_TBL_END    ; yes: scroll to end of
  816.                                         ;       table first
  817.       SUT_L1:
  818.                 DEC        BX                ;
  819.                 DEC        BX                ; pointer to previous entry
  820.                 RET
  821.   SCROLLUP_TBL    ENDP
  822.  
  823.  
  824.   SCROLLDO_TBL    PROC    NEAR
  825.                 INC        BX                ; pointer to next entry
  826.                 INC        BX                ;
  827.                 CMP        BX, C_TBL_END    ; past end?
  828.                 JNE        SDT_L1            ; no: all is well
  829.                 MOV        BX, C_TBL_START ; yes: back to start of table
  830.  
  831.       SDT_L1:
  832.                 RET
  833.   SCROLLDO_TBL    ENDP
  834.  
  835.  
  836.  
  837.         BEEP    PROC    NEAR
  838.  
  839.       ;----------------------------------------------
  840.       ; Buffer full/error beep
  841.       ;
  842.  
  843.                 PUSH    CX
  844.                 PUSH    AX
  845.  
  846.                 MOV        AL, 10010110B    ; select Timer 2, low order Count
  847.                 OUT        43H, AL
  848.                 CLR        AL                ; set low order Count
  849.                 JMP        $+2                ; allow for AT pecularities
  850.                 OUT        42H, AL            ;  (slow 8053-chip)
  851.  
  852.                 MOV        AL, 10100110B    ; select Timer 2, high order Count
  853.                 OUT        43H, AL
  854.                 MOV        AL, 3            ; pitch
  855.                 JMP        $+2
  856.                 OUT        42H, AL            ; set high order Count
  857.  
  858.                 IN        AL, 61H
  859.                 MOV        AH, AL            ; save value
  860.                 OR        AL, 03H            ; turn speaker on
  861.                 JMP        $+2
  862.                 OUT        61H, AL
  863.  
  864.                 MOV        CX, 20000        ; beep length
  865.  
  866.         BRRR:
  867.                 LOOP    BRRR
  868.  
  869.                 MOV        AL, AH            ; restore old value
  870.                 OUT        61H, AL
  871.  
  872.                 POP        AX
  873.                 POP        CX
  874.                 RET
  875.         BEEP    ENDP
  876.  
  877.   WRITE_CHAR    PROC    NEAR
  878.  
  879.         ;------------------------------------------
  880.         ; Display character in AL via OS call 2
  881.         ; or through BIOS TTY routine 0EH
  882.         ;  (necessary at initialization)
  883.         ;
  884.  
  885.                 PUSH    AX
  886.                 CMP        BIOS_TTY_SW, ON
  887.                 JNE        W_CH_L1
  888.                 MOV        AH, 0EH            ; TTY-command
  889.                 INT        10H                ; video-BIOS-routine
  890.                 JMPS    W_CH_LX
  891.  
  892.         W_CH_L1:
  893.                 PUSH    DX
  894.                 MOV        DL, AL            ; deliver in DL
  895.                 MOV        AH, 2            ; function number
  896.                 INT        21H
  897.                 POP        DX
  898.  
  899.         W_CH_LX:
  900.                 POP        AX
  901.                 RET
  902.   WRITE_CHAR    ENDP
  903.  
  904.      PRINT        PROC    NEAR
  905.  
  906.         ;-------------------------------------------------------------
  907.         ;  This routine displays a string a string of characters on
  908.         ;  the crt-screen.
  909.         ;  The string is assumed to start at address DS:SI
  910.         ;  and must end with a null byte.
  911.         ;
  912.  
  913.                 CLD
  914.  
  915.       PRINT_L1:
  916.                 LODS    BYTE PTR CS:[SI]
  917.                 OR        AL, AL            ; load bytes until
  918.                 JZ        PRINT_L2        ; a zero is read
  919.                 CALL    WRITE_CHAR
  920.                 JMP        PRINT_L1
  921.  
  922.       PRINT_L2:
  923.                 RET
  924.      PRINT        ENDP
  925.  
  926.      PRINT_NUM    PROC    NEAR
  927.  
  928.         ;---------------------------------------
  929.         ; Convert to ascii and display number
  930.         ; in: AX: unsigned integer
  931.         ;
  932.         ;
  933.                 PUSH    DX
  934.                 PUSH    CX
  935.                 PUSH    BX
  936.                 MOV        BX, 10            ; BX = divisor
  937.                 CLR        CX                ; CX = digit count
  938.  
  939.         PR_N_L1:
  940.                 CLR        DX                ; DX:AX = dividend
  941.                 DIV        BX
  942.                 PUSH    DX                ; remainder on stack
  943.                 INC        CX                ; keep count
  944.                 OR        AX, AX            ; quotient = 0 ?
  945.                 JNE        PR_N_L1            ; if not, compute next digit
  946.  
  947.         PR_N_L2:
  948.                 POP        AX                ; get digits from stack
  949.                 ADD        AL, '0'            ; convert to ascii
  950.                 CALL    WRITE_CHAR        ; and display
  951.                 LOOP    PR_N_L2            ;
  952.  
  953.                 POP        BX
  954.                 POP        CX
  955.                 POP        DX
  956.                 RET
  957.      PRINT_NUM    ENDP
  958.  
  959.                 PAGE
  960.  
  961. DISPLAY_CHAR    PROC    NEAR
  962.  
  963.         ;---------------------------------------------------------------
  964.         ;  Display character in AL.
  965.         ;  Update cursor data.
  966.         ;
  967.  
  968.                 CALL    WRITE_CHAR
  969.  
  970.                 CMP        AL, CR
  971.                 JNE        DCH_L1
  972.  
  973.         ;----- carriage return
  974.         ;
  975.                 MOV        CURSOR_COL, 0
  976.                 RET
  977.  
  978.         DCH_L1:
  979.                 CMP        AL, LF
  980.                 JNE        DCH_L3
  981.  
  982.         ;----- line feed
  983.         ;
  984.                 CMP        CURSOR_ROW, MAX_ROW - 1
  985.                 JE        DCH_L2
  986.                 INC        CURSOR_ROW
  987.  
  988.         DCH_L2:
  989.                 RET
  990.  
  991.         DCH_L3:
  992.                 CMP        AL, BACKSPACE
  993.                 JNE        DCH_L5
  994.  
  995.         ;----- backspace
  996.         ;
  997.                 DEC        CURSOR_COL                ; cursor one left
  998.                 JNS        DCH_L4                    ; if < 0
  999.                 MOV        AL, MAX_COL                ; wrap back to previous row
  1000.                 ADD        CURSOR_COL, AL            ;
  1001.                 DEC        CURSOR_ROW
  1002.                 CALL    SET_CURSOR_POS            ; must set cursor explicitly
  1003.  
  1004.         DCH_L4:                                    ; for wrap back
  1005.                 RET
  1006.  
  1007.         DCH_L5:
  1008.  
  1009.         ;----- other characters
  1010.         ;
  1011.  
  1012.                 MOV        AX, STR_END_POS            ; AX := difference between
  1013.                 SUB        AX, CURSOR_POS            ;        STR_END and CURRENT
  1014.                 PUSH    AX
  1015.                 INC        CURSOR_COL
  1016.                 MOV        AL, MAX_COL                ; increment column count
  1017.                 CMP        CURSOR_COL, AL            ; if at end move to next line
  1018.                 JB        DCH_L6                    ;
  1019.                 MOV        CURSOR_COL, 0            ;
  1020.                 CMP        CURSOR_ROW, MAX_ROW - 1 ; on last row ?
  1021.                 JE        DCH_L6                    ; yes, don't increment ROW
  1022.                 INC        CURSOR_ROW                ; because of scrolling
  1023.  
  1024.         DCH_L6:
  1025.                 POP        AX
  1026.                 OR        AX, AX                    ; update STR_END_POS
  1027.                 JNZ        DCH_L7                    ; if necessary
  1028.                 MOV        AX, CURSOR_POS
  1029.                 MOV        STR_END_POS, AX
  1030.  
  1031.         DCH_L7:
  1032.                 RET
  1033.  
  1034. DISPLAY_CHAR    ENDP
  1035.  
  1036.  
  1037. DISPLAY_COMPLEX PROC    NEAR
  1038.  
  1039.         ;**************************************************************
  1040.         ;* This procedure takes an ascii-code looks for control-code
  1041.         ;* and displays it on the screen in the proper format
  1042.         ;* in: AL : ascii-code
  1043.         ;*
  1044.         ;* Irregular service for BS and TAB
  1045.         ;*
  1046.         ;* If DEFER_DSPL is ON then display of the string being edited
  1047.         ;* is deferred until editing is complete.
  1048.         ;***************************************************************
  1049.  
  1050.                 CMP        DEFER_DSPL, ON
  1051.                 JE        DC_X
  1052.                 CMP        AL, 20H            ; is it a control character ?
  1053.                 JNB        DC_NO_CTRL        ;
  1054.  
  1055.                 CMP        AL, BACKSPACE    ; control characters,
  1056.                 JE        DC_NO_CTRL        ; handle BS and TAB different
  1057.                 CMP        AL, TAB            ;
  1058.                 JNE        DC_L2            ;
  1059.  
  1060.         ;----- display TAB character, ie. display spaces until
  1061.         ;       current column number = 0 (MOD 8)
  1062.         ;
  1063.  
  1064.                 PUSH    CX
  1065.                 CLR        CH
  1066.                 MOV        CL, CURSOR_COL    ;
  1067.                 OR        CL, 0F8H        ;  CL := 8 - (CURSOR_COL MOD 8)
  1068.                 NEG        CL                ;
  1069.  
  1070.       DC_L1:
  1071.                 MOV        AL, ' '
  1072.                 CALL    DISPLAY_CHAR
  1073.                 LOOP    DC_L1
  1074.                 POP        CX
  1075.                 JMPS    DC_X
  1076.  
  1077.         ;----- display control character other then TAB or BS
  1078.         ;       first display a caret, then the corresponding capital
  1079.         ;       ie. ascii 1 displays as: '^A'
  1080.         ;
  1081.  
  1082.       DC_L2:
  1083.                 PUSH    AX
  1084.                 MOV        AL, '^'            ; display ascii-control-character
  1085.                 CALL    DISPLAY_CHAR
  1086.                 POP        AX
  1087.                 OR        AL, 40H            ; make it readable
  1088.  
  1089.   DC_NO_CTRL:
  1090.                 CALL    DISPLAY_CHAR
  1091.  
  1092.        DC_X:
  1093.                 RET
  1094. DISPLAY_COMPLEX ENDP
  1095.  
  1096.  
  1097.  
  1098. DISPLAY_TAIL    PROC    NEAR
  1099.  
  1100.         ;*************************************************
  1101.         ;* this routine displays the substring starting
  1102.         ;* at the character pointed to by DI, to the end
  1103.         ;* of the buffer
  1104.         ;* in: CX: number of blanks to display after the
  1105.         ;* string to blank out any remnant characters
  1106.         ;*************************************************
  1107.  
  1108.                 PUSH    CURSOR_POS        ; save current screen position
  1109.                 PUSH    CX
  1110.                 MOV        CL, BL            ; get length of substring
  1111.                 SUB        CL, BH            ; in CX
  1112.                 CLR        CH
  1113.                 JCXZ    DT_L2            ; display specified blanks if
  1114.                                         ; the substring is empty
  1115.                 MOV        SI, DI
  1116.  
  1117.        DT_L1:
  1118.                 LODSB                    ; get character to display
  1119.                 CALL    DISPLAY_COMPLEX
  1120.                 LOOP    DT_L1
  1121.  
  1122.        DT_L2:
  1123.                 POP        CX                ; recover number of additional blanks
  1124.                 JCXZ    DT_L4
  1125.  
  1126.        DT_L3:
  1127.                 MOV        AL, ' '            ;
  1128.                 CALL    DISPLAY_COMPLEX ;
  1129.                 LOOP    DT_L3
  1130.  
  1131.        DT_L4:
  1132.                 POP        CX                ; recover screen position
  1133.                 MOV        AL, CH            ; AL := (OLD)STR_END_ROW
  1134.                 SUB        CX, CURSOR_POS    ;
  1135.                 NEG        CX                ; !! CX := CURSOR_POS - (OLD)STR_END_POS
  1136.                 SUB        AL, CURSOR_ROW
  1137.                 NEG        AL                ; AL := CURSOR_ROW - (OLD)STR_END_ROW
  1138.                 MOV        AH, MAX_COL        ; sofar we pretended each row is 256
  1139.                 NEG        AH                ; characters long, so now we must
  1140.                 MUL        AH                ; compensate for this by subtracting
  1141.                 SUB        CX, AX            ; (256 - characters/column)*ROW_diff.
  1142.                                         ;
  1143.                 JCXZ    DT_L6
  1144.  
  1145.        DT_L5:
  1146.                 MOV        AL, BACKSPACE    ; use as backspace count
  1147.                 CALL    DISPLAY_COMPLEX ; move cursor back
  1148.                 LOOP    DT_L5
  1149.  
  1150.        DT_L6:
  1151.                 RET
  1152. DISPLAY_TAIL    ENDP
  1153.  
  1154.  
  1155. MOVE_TAIL_LEFT    PROC    NEAR
  1156.  
  1157.         ;***************************************************
  1158.         ;* routine to move the substring starting right of
  1159.         ;* the current cursor position, pointed to by DI,
  1160.         ;* one position to the left, overwriting the current
  1161.         ;* cursor position
  1162.         ;* none of the pointers are updated
  1163.         ;***************************************************
  1164.  
  1165.                 PUSH    CX
  1166.                 PUSH    DI
  1167.                 CLR        CH                ;
  1168.                 MOV        CL, BL            ; get length of substring
  1169.                 SUB        CL, BH            ; in CX
  1170.                 DEC        CX
  1171.                 JNA        MTL_LX            ; test for non-empty substring
  1172.  
  1173.                 MOV        SI, DI            ;
  1174.                 INC        SI                ; SI at first item to move
  1175.                 CLD                        ; count forward
  1176.                 REP MOVSB                ;
  1177.  
  1178.        MTL_LX:
  1179.                 POP        DI
  1180.                 POP        CX
  1181.                 RET
  1182. MOVE_TAIL_LEFT    ENDP
  1183.  
  1184.  
  1185. MOVE_TAIL_RIGHT PROC    NEAR
  1186.  
  1187.         ;***************************************************
  1188.         ;* routine to move the substring starting at
  1189.         ;* the current cursor position, pointed to by DI,
  1190.         ;* one position to the right.
  1191.         ;* none of the pointers are updated
  1192.         ;***************************************************
  1193.  
  1194.                 PUSH    CX
  1195.                 PUSH    DI
  1196.                 CLR        CH                ;
  1197.                 MOV        CL, BL            ; length of substring in CX
  1198.                 SUB        CL, BH            ;
  1199.                 JCXZ    MTR_LX            ; no business for empty string
  1200.  
  1201.                 ADD        DI, CX            ; DI one past end string
  1202.                 MOV        SI, DI
  1203.                 DEC        SI                ; SI at end string
  1204.                 STD                        ; count backward
  1205.                 REP MOVSB                ;
  1206.  
  1207.        MTR_LX:
  1208.                 POP        DI
  1209.                 POP        CX
  1210.                 RET
  1211. MOVE_TAIL_RIGHT ENDP
  1212.  
  1213.  
  1214. BACK_TAB        PROC    NEAR
  1215.  
  1216.         ;************************************************************
  1217.         ;* Compute number of backspaces needed to remove a TAB
  1218.         ;* at the current cursor position.
  1219.         ;* It is assumed that string pointers are consistent
  1220.         ;* i.e. DI points to position of TAB to be removed
  1221.         ;*    and BL, BH give length of whole string and prefix resp.
  1222.         ;* required number = 8 - (current screen colunm MOD 8)
  1223.         ;*
  1224.         ;* out: CL: equivalent number of spaces for TAB in question
  1225.         ;************************************************************
  1226.  
  1227.                 PUSH    DI        ; save current string index
  1228.                 PUSH    DX        ; save string length
  1229.                 DEC        DI        ; position on previous character
  1230.                 CLR        CH
  1231.                 MOV        CL, BH    ; CX := prefix length
  1232.                 MOV        DH, 07H
  1233.                 MOV        AL, 20H
  1234.                 JCXZ    BT_3
  1235.                 STD                ; scan downwards through prefix
  1236.  
  1237.         BT_1:
  1238.                 SCASB
  1239.                 JBE        BT_2    ; control character ?
  1240.                 CMP        BYTE PTR ES:[DI+1], TAB     ;
  1241.                 JE        BT_4    ; if tab then exit loop (we certainly are
  1242.                                 ;  at screen position which equals 0 (MOD 8) )
  1243.                 DEC        DH
  1244.  
  1245.         BT_2:
  1246.                 LOOP    BT_1
  1247.                                         ; here: CL = length to penultimate tab
  1248.                                         ;             or zero (if no tab)
  1249.         BT_3:                            ;  and: DH = - (no of carets)
  1250.                 SUB        DH, STR_START_COL ; DH := - carets - STR_START_COL
  1251.  
  1252.         BT_4:
  1253.                 SUB        DH, BH            ; DH := - carets {- STR_START_COL}
  1254.                                         ;        - total
  1255.                 ADD        CL, DH            ; CL := - carets {- STR_START_COL}
  1256.                                         ;        - (length since penultimate tab)
  1257.                 AND        CL, 07H            ; CL := 8 - ((-CL) MOD 8)
  1258.                 INC        CL                ;
  1259.                 CLD                ; reset direction flag
  1260.                 POP        DX        ; restore string length
  1261.                 POP        DI        ; and string index
  1262.                 RET
  1263. BACK_TAB        ENDP
  1264.  
  1265.                 PAGE
  1266.  
  1267. ;-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
  1268. ;
  1269. ;        K E Y B O A R D      E D I T O R     ( ENTRY POINT )
  1270. ;
  1271. ;-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
  1272.  
  1273.  
  1274. FUNCTION_INT_ENTRY        PROC
  1275.  
  1276.         ;****************************************************************
  1277.         ;* the address of this routine is placed in the interrupt vector
  1278.         ;* to intercept interrupt 21H. Function call 0AH is handled here,
  1279.         ;* others are passed on to DOS
  1280.         ;*
  1281.         ;****************************************************************
  1282.  
  1283.                 CMP        EDT_INST, OFF
  1284.                 JZ        FI_NOT_ACTIVE
  1285.                 CMP        AH, 0AH
  1286.                 JZ        FI_ENTRY
  1287.  
  1288. FI_NOT_ACTIVE:
  1289.  
  1290.         ;----- go on to DOS-routines
  1291.         ;
  1292.  
  1293.                 JMP        CS: OLD_FUNCTION_INT
  1294.  
  1295.     FI_ENTRY:
  1296.                 STI
  1297.                 PUSH    ES                ;
  1298.                 PUSH    DS                ;
  1299.                 PUSH    BP                ;
  1300.                 PUSH    DI                ;
  1301.                 PUSH    SI                ; save registers
  1302.                 PUSH    DX                ;
  1303.                 PUSH    CX                ;
  1304.                 PUSH    BX                ;
  1305.                 PUSH    AX
  1306.                 CALL    SETSTACK        ; use own stack
  1307.  
  1308.                 CALL    DEVICE_PROLOGUE
  1309.  
  1310.                 MOV        AX, DS            ; make ES point to buffer-
  1311.                 MOV        ES, AX            ; segment also
  1312.                 MOV        SI, DX
  1313.                 CLD
  1314.                 LODSW                    ; get length of the passed buffer
  1315.                 PUSH    SI                ; save address of start of actual string
  1316.                 OR        AL, AL            ; if length = zero return
  1317.                 JZ        FI_EXIT
  1318.  
  1319.                 MOV        DL, AL            ; DL will contain the string's
  1320.                 DEC        DL                ; maximum length, without the
  1321.                                         ; final Carriage Return
  1322.                 MOV        CL, AH
  1323.                 CLR        CH
  1324.                 MOV        BX, CX
  1325.                 JCXZ    FI_RESTART
  1326.                 CMP        BYTE PTR DS:[SI+BX], CR     ; is input-string
  1327.                                                  ; terminated properly ?
  1328.                 JNE        FI_RESTART                 ; no, ignore
  1329.                 CALL    STR_BUF_INSERT
  1330.  
  1331.   FI_RESTART:
  1332.                 MOV        DH, STR_START_COL        ; initialize column counter
  1333.                 MOV        CURSOR_COL, DH
  1334.                 CALL    SET_CURSOR_POS
  1335.  
  1336.                 MOV        INSERT_TOGGLE, OFF        ; overwrite mode
  1337.                 CALL    SET_CURSOR_TYPE
  1338.  
  1339.                 CLR        BL                ; BL will contain the current number
  1340.                                         ; of characters in the string
  1341.                 CLR        BH                ; BH will contain the number of
  1342.                                         ; characters up to but not including
  1343.                                         ; the cursor position
  1344.                 POP        DI                ; DI is the current position in the
  1345.                                         ; buffer
  1346.                 PUSH    DI                ; address back on stack
  1347.                 GET_CHAR                ; get first character
  1348.                 CMP        AL, LF            ; if first character is a
  1349.                 JE        MAIN_LOOP        ; line-feed then throw it away
  1350.                 JMP        MAIN_ENTRY        ; enter main loop at main
  1351.                                         ; entrance-point
  1352.  
  1353.     FI_EXIT:
  1354.                 POP        SI
  1355.                 CALL    DEVICE_EPILOGUE
  1356.  
  1357.                 CALL    RESETSTACK        ; restore user stack
  1358.  
  1359.                 POP        AX                ;
  1360.                 POP        BX                ;
  1361.                 POP        CX                ;
  1362.                 POP        DX                ;
  1363.                 POP        SI                ; restore registers
  1364.                 POP        DI                ;
  1365.                 POP        BP                ;
  1366.                 POP        DS                ;
  1367.                 POP        ES                ;
  1368.                 IRET
  1369.  
  1370. FUNCTION_INT_ENTRY        ENDP
  1371.  
  1372.  
  1373. MAIN_LOOP        PROC    NEAR
  1374.  
  1375.                 GET_CHAR
  1376.  
  1377. MAIN_ENTRY:
  1378.                 CMP        AL, ACK
  1379.                 JE        MAIN_LOOP                ; no ACK's
  1380.  
  1381.                 LEA        BP, MAIN_LOOP            ; set up return address on
  1382.                 PUSH    BP                        ; the stack for all routines
  1383.                                                 ; wishing to return to MAIN_LOOP
  1384.                 CMP        AL, LF
  1385.                 JE        LF_RN                    ;
  1386.                 CMP        AL, BACKSPACE            ; find out whether one
  1387.                 JE        BACKSPACE_RN            ; of these special
  1388. ;                CMP        AL, ESCAPE                ; characters was read
  1389. ;                JE        ESCAPE_RN                ;
  1390.                 CMP      AL, CTRL_U
  1391.                 JE        ESCAPE_RN
  1392.                 CMP        AL, CR                    ; search for editing
  1393.                 JE        CR_R                    ; keys
  1394.                 CMP     AL, CTRL_W
  1395.                 JE        CW_RN
  1396.                 CMP        AL, 0                    ;
  1397.                 JE        EXTENDED_ASCIIN            ;
  1398.  
  1399.  
  1400.         ;----- a character must be inserted in the current string
  1401.         ;
  1402.  
  1403.         M_L1:
  1404.                 CMP        INSERT_TOGGLE, ON        ; insert- or
  1405.                 JNE        OVERWRITE                ; overwrite-mode?
  1406.  
  1407.                 CMP        BL, DL                    ; is buffer full ?
  1408.                 JB        M_L2                    ; no: put this character
  1409.                 CALL    BEEP                    ; in the buffer
  1410.                 RET                                ; else: ring the bell
  1411.  
  1412.         M_L2:
  1413.                 CALL    MOVE_TAIL_RIGHT            ; make room for new character
  1414.                 CLD                                ;
  1415.                 STOSB                            ; insert the new character
  1416.                 INC        BL                        ; update length
  1417.                 INC        BH                        ; and cursor position
  1418.                 CLR        CX
  1419.  
  1420.         ;---- display updated string
  1421.         ;      also postlude for OVERWRITE routine
  1422.         ;
  1423.  
  1424.         M_L3:
  1425.                 CALL    DISPLAY_COMPLEX            ; display the new character
  1426.                 CALL    DISPLAY_TAIL            ; and those to the right of it
  1427.         M_L4:
  1428.                 RET
  1429.  
  1430.  
  1431.     OVERWRITE:
  1432.                 CMP        BH, BL                    ; if cursor position
  1433.                 JB        M_L6                    ; at end, then check for
  1434.                 CMP        BL, DL                    ; full buffer
  1435.                 JB        M_L5                    ;
  1436.                 CALL    BEEP                    ;
  1437.                 RET                                ;
  1438.  
  1439.         M_L5:                                    ;
  1440.                 INC        BL
  1441.         M_L6:                                    ; if a character is added at
  1442.                 INC        BH                        ; the end, update total
  1443.                                                 ; length also
  1444.                 CLR        CX
  1445.                 CMP        BH, BL                    ; at end of string ?
  1446.                 JE        M_L8                    ; yes, just add it
  1447.  
  1448.         ;----- must overwrite some character
  1449.         ;       get character to overwrite in AH
  1450.         ;       character to overwrite with still in AL
  1451.  
  1452.                 MOV        AH, ES:[DI]
  1453.  
  1454.                 CMP        AH, TAB                    ; is it a TAB ?
  1455.                 JNE        M_L7                    ; go if not
  1456.  
  1457.         ;----- get rid of TAB
  1458.         ;
  1459.  
  1460.                 PUSH    AX
  1461.                 DEC        BH                        ; BACKTAB expects string
  1462.                 CALL    BACK_TAB                ; pointers set up for tab prefix
  1463.                 INC        BH                        ; restore prefix length
  1464.                 DEC        CX
  1465.                 POP        AX
  1466.                 JMPS    M_L8
  1467.  
  1468.         M_L7:
  1469.                 CMP        AH, 20H                    ; if control character
  1470.                 JAE        M_L8                    ; then check character to write
  1471.                 INC        CX
  1472.                 CMP        AL, TAB                    ; tab can also show as one space
  1473.                 JE        M_L8
  1474.                 CMP        AL, 20H
  1475.                 JNB        M_L8                    ; if not cntr-char
  1476.                 DEC        CX                        ; display extra space
  1477.  
  1478.         ;----- character to buffer
  1479.         ;
  1480.  
  1481.         M_L8:
  1482.                 CLD
  1483.                 STOSB
  1484.                 JMP        M_L3                    ; go update screen
  1485.  
  1486.  
  1487.  
  1488.         ;----- boost some conditional jumps
  1489.         ;
  1490.  
  1491. LF_RN:            JMP        LF_R
  1492. BACKSPACE_RN:    JMP        BACKSPACE_R
  1493. ESCAPE_RN:        JMP        ESCAPE_R
  1494. CW_RN:            JMP        CTRL_W_R
  1495. EXTENDED_ASCIIN:JMP        EXTENDED_ASCII
  1496.  
  1497.  
  1498. CR_R:
  1499.  
  1500.         ;----------------------------
  1501.         ; add a Carriage Return to the end of the string, set string-length byte
  1502.         ; insert in STR_BUF, and go to exit
  1503.         ; ! the carriage return character is sent to STDOUT in DEVICE_EPILOGUE
  1504.         ;
  1505.  
  1506.                 CLR        CH                ;
  1507.                 MOV        CL, BL            ; set DI to end of string
  1508.                 SUB        CL, BH            ;
  1509.                 ADD        DI, CX            ;
  1510.                 STOSB                    ; and put carriage return there
  1511.  
  1512.                 PUSH    STR_END_POS
  1513.                 POP        CURSOR_POS
  1514.                 CALL    SET_CURSOR_POS
  1515.  
  1516.                 POP        BP                ; remove return address from stack
  1517.                 POP        SI                ; recover first-byte address
  1518.                 PUSH    SI
  1519.                 LEA        BP, FI_EXIT
  1520.                 PUSH    BP
  1521.  
  1522.                 MOV        [SI-1], BL        ; store count
  1523.  
  1524.                 CLR        CH
  1525.                 MOV        CL, BL            ; length in CX
  1526.  
  1527.  
  1528. STR_BUF_INSERT:
  1529.  
  1530.       ;-----------------------------------------------------
  1531.       ; On entry CX contains the length of the string
  1532.       ;         and SI points to the string's first byte.
  1533.       ; note: this code is called as a subroutine at entry
  1534.       ;           and by F5_R
  1535.       ; When freeing space to insert a new string, as many of
  1536.       ; the oldest strings are removed as is necessary to make
  1537.       ; room for the new one. Because maximum string length is
  1538.       ; is 255 and minimum length of strings in the buffer is 1
  1539.       ; it follows that no more than 255 should ever be removed.
  1540.       ; Therefore, a counter is maintained during the the loop
  1541.       ; which removes old strings from the buffer to prevent an
  1542.       ; accidentally corrupted data-structure from causing an
  1543.       ; endless loop here.
  1544.       ;
  1545.  
  1546.                 JCXZ    SBI_L17            ; if string-length = 0 don't insert
  1547.  
  1548.       ;----- load register DI with address of last byte before
  1549.       ;         begin of free space in STR_BUF
  1550.       ;
  1551.  
  1552.                 MOV        BX, C_TBL_TAIL    ;
  1553.                 MOV        CURRENT, BX        ; must update CURRENT
  1554.                 CMP        BX, C_TBL_HEAD
  1555.                 JE        SBI_L1
  1556.                 CALL    SCROLLUP_TBL
  1557.  
  1558.       SBI_L1:
  1559.                 MOV        DI, CS:[BX]
  1560.                 JE        SBI_L18            ; if table empty, we should not enter
  1561.                                         ; compare routine
  1562.                                         ; ! proc SCROLLUP does not set Z-flag
  1563.  
  1564.       ;----- determine whether string is different from previous
  1565.       ;
  1566.  
  1567.                 PUSH    DI
  1568.                 MOV        AX, DI
  1569.                 CMP        BX, C_TBL_HEAD    ; wrap pointers if appropriate
  1570.                 JNE        SBI_L11            ;
  1571.                 MOV        BX, C_TBL_TAIL    ;
  1572.                 JMPS    SBI_L12
  1573.  
  1574.       SBI_L11:
  1575.                 CALL    SCROLLUP_TBL
  1576.  
  1577.       SBI_L12:
  1578.                 MOV        DI, CS:[BX]
  1579.                 SUB        AX, DI            ; compute length of previous string
  1580.                 JAE        SBI_L13            ;
  1581.                 ADD        AX, STR_BUF_SIZE; string can wrap in STR_BUF
  1582.  
  1583.       SBI_L13:
  1584.                 CMP        AX, CX            ; compare lengths
  1585.                 JNE        SBI_L16            ; go if not equal
  1586.  
  1587.                 PUSH    ES                ; save registers altered
  1588.                 PUSH    SI                ; when comparing strings
  1589.                 PUSH    CX                ;
  1590.  
  1591.                 MOV        AX, CS            ; set up addressing
  1592.                 MOV        ES, AX            ;
  1593.                 CLD                        ;
  1594.                 INC        DI                ;
  1595.  
  1596.       SBI_L14:
  1597.                 CMP        DI, STR_BUF_END ; compare string in
  1598.                 JNE        SBI_L15            ; STR_BUF with input string
  1599.                 MOV        DI, STR_BUF_START ;
  1600.                                         ;
  1601.       SBI_L15:                            ;
  1602.                 CMPSB                    ;
  1603.                 LOOPZ    SBI_L14            ;
  1604.  
  1605.                 POP        CX                ; restore registers
  1606.                 POP        SI                ;
  1607.                 POP        ES                ;
  1608.  
  1609.       SBI_L16:
  1610.                 POP        DI
  1611.                 JNE        SBI_L18
  1612.  
  1613.       SBI_L17:
  1614.                 RET                        ; return if strings proved equal
  1615.  
  1616.       SBI_L18:
  1617.  
  1618.       ;----- next get an entry in C_TBL for the new string
  1619.       ;
  1620.  
  1621.                 MOV        BX, C_TBL_TAIL    ; C_TBL_TAIL is moved to make room,
  1622.                 MOV        AX, CS:[BX]        ; save its contents first, ...
  1623.                 PUSH    DI                ;
  1624.                 ADD        DI, CX            ; calculate where new string
  1625.                 CMP        DI, STR_BUF_END ; will end in STR_BUF,
  1626.                 JB        SBI_L2            ;
  1627.                 SUB        DI, STR_BUF_SIZE
  1628.  
  1629.        SBI_L2:
  1630.                 MOV        CS:[BX], DI        ; ... then fill it with new length
  1631.                 POP        DI
  1632.  
  1633.                 CLR        DH                ; use as retry count for loop
  1634.                                         ; starting at label SBI_L3
  1635.  
  1636.                 CALL    SCROLLDO_TBL    ;
  1637.                 MOV        C_TBL_TAIL, BX    ; new tail
  1638.                 MOV        CURRENT, BX        ; and new current also
  1639.                 CMP        BX, C_TBL_HEAD    ; collision with head ?
  1640.                 JNE        SBI_L3            ; no, go and restore contents
  1641.  
  1642.                 PUSH    BX                ; yes, remove oldest string
  1643.                 CALL    SCROLLDO_TBL    ; space is automatically deallocated
  1644.                 MOV        C_TBL_HEAD, BX    ; by moving the pointers
  1645.                 POP        BX                ; BX back at tail
  1646.  
  1647.                 MOV        AX, CS:[BX]        ; new value for end of free space
  1648.  
  1649.        SBI_L3:
  1650.                 MOV        CS:[BX], AX        ; set new C_TBL_TAIL to current
  1651.                                         ; end of free space
  1652.  
  1653.       ;----- determine if there is enough free space to hold the new
  1654.       ;         string and keep removing old entries until there is
  1655.       ;
  1656.  
  1657.                 SUB        AX, DI            ; AX contains current end of free space
  1658.                 JA        SBI_L4            ; AX=DI means STR_BUF is empty (free-
  1659.                                         ; pointer = last-string-pointer)
  1660.                 ADD        AX, STR_BUF_SIZE; undo wrap-around effect
  1661.  
  1662.        SBI_L4:
  1663.                 CMP        AX, CX            ; is there enough ?
  1664.                 JA        SBI_L5            ; yes, go and do the transfer
  1665.                                         ; note: always keep one byte free
  1666.                 DEC        DH                ; how many times did we try ?
  1667.                 JZ        SBI_ERR            ; if zero too many: something is wrong
  1668.                                         ; exit with beep, also RESET is called
  1669.                 PUSH    BX                ; no, remove another entry from TABLE
  1670.                 MOV        BX, C_TBL_HEAD
  1671.                 MOV        AX, CS:[BX]        ; get address of last byte occupied
  1672.                 CALL    SCROLLDO_TBL    ; by this entry's string
  1673.                 MOV        C_TBL_HEAD, BX    ; new head of the table
  1674.                 POP        BX                ;
  1675.  
  1676.                 JMP        SBI_L3            ; try again
  1677.  
  1678.       ;----- now we are ready for the transfer
  1679.       ;
  1680.  
  1681.        SBI_L5:
  1682.                 MOV        AX, CS            ;
  1683.                 MOV        ES, AX            ; set up target pointers
  1684.                 INC        DI                ;
  1685.                 CLD                        ; count in right direction
  1686.  
  1687.        SBI_L6:
  1688.                 CMP        DI, STR_BUF_END ;
  1689.                 JNE        SBI_L7            ; wrap-around if neccesary
  1690.                 MOV        DI, STR_BUF_START
  1691.  
  1692.        SBI_L7:
  1693.                 MOVSB                    ; store bytes of string
  1694.                 LOOP    SBI_L6            ; until done (CX=0)
  1695.  
  1696.                 MOV        AX, DS            ;
  1697.                 MOV        ES, AX            ; restore ES
  1698.  
  1699.        SBI_LX:
  1700.                 RET
  1701.  
  1702.        SBI_ERR:
  1703.                 CALL    RESET_EDT
  1704.                 CALL    BEEP
  1705.                 RET
  1706.  
  1707. LF_R:
  1708.                 CALL    CURSOR_END_R
  1709.                 MOV        AL, LF
  1710.                 CALL    DISPLAY_CHAR
  1711.                 MOV        AL, CR
  1712.                 CALL    DISPLAY_CHAR
  1713.                 RET
  1714.  
  1715.  
  1716. BACKSPACE_R:
  1717.                 OR        BH, BH            ; is cursor at begin of string ?
  1718.                 JZ        BS_L1            ; yes, then nothing to do
  1719.                 CALL    CURSOR_LEFT_R    ; otherwise, delete the character
  1720.                 CALL    DELETE_R        ; left of the current cursor-position
  1721.         BS_L1:    RET
  1722.  
  1723.  
  1724.  
  1725. ;---------------------------------
  1726. ; abandon current string and start editing a new one
  1727. ESCAPE_R:        CALL    CURSOR_BEGIN_R
  1728.                   CALL    F4_R
  1729.                 CALL    CURSOR_END_R
  1730.                 ADD        SP, 2            ; discard return address on stack
  1731.                 JMP        FI_RESTART        ; redo from scratch
  1732.  
  1733. ; Delete previous whitespace, or alphanumerics
  1734. CTRL_W_R:        CALL    BACKSPACE_R        ; delete a character in any case
  1735.                 OR        BH, BH            ; at beginning of string?
  1736.                 JZ        CW_RET            ; yes, done
  1737.                 CMP     BYTE PTR [DI-1],'    ' ; tab or...
  1738.                 JZ        CTRL_W_BL
  1739.                 CMP     BYTE PTR [DI-1],' ' ; blank or...
  1740.                 JZ        CTRL_W_BL
  1741. CTRL_W_LOOP:    CMP        BYTE PTR [DI-1],'0'    ; numeric
  1742.                 JB        CW_RET
  1743.                 CMP        BYTE PTR [DI-1],'9' ; ...
  1744.                 JBE        CTRL_W_NB
  1745.                 CMP        BYTE PTR [DI-1],'A' ; or alpha, continue deletion
  1746.                 JB        CW_RET
  1747.                 CMP        BYTE PTR [DI-1],'Z'
  1748.                 JBE        CTRL_W_NB
  1749.                 CMP        BYTE PTR [DI-1],'a'
  1750.                 JB        CW_RET
  1751.                 CMP        BYTE PTR [DI-1],'z'
  1752.                 JBE        CTRL_W_NB
  1753. CW_RET:            RET
  1754.  
  1755. CTRL_W_BL:        CALL    BACKSPACE_R        ; Flush previous character
  1756.                 OR        BH,BH            ; at beginning?
  1757.                 JZ        CW_RET            ; Yes...
  1758.                 CMP     BYTE PTR [DI-1],'    ' ; tab or...
  1759.                 JZ        CTRL_W_BL
  1760.                 CMP     BYTE PTR [DI-1],' ' ; blank or...
  1761.                 JZ        CTRL_W_BL
  1762.                 JMP        CW_RET
  1763.  
  1764. CTRL_W_NB:        CALL    BACKSPACE_R        ; delete a character in any case
  1765.                 OR        BH, BH            ; at beginning of string?
  1766.                 JZ        CW_RET            ; yes, done
  1767.                 JMP        CTRL_W_LOOP
  1768.  
  1769. EXTENDED_ASCII:
  1770.                 GET_CHAR
  1771.                 PUSH    ES                ; the second code is in AL now
  1772.                 PUSH    DI
  1773.                 MOV        DI, CS
  1774.                 MOV        ES, DI
  1775.                 LEA        DI, SECOND_CODE_TABLE
  1776.                 MOV        CX, CODE_TABLE_LENGTH
  1777.                 CLD
  1778.                 CLI                        ; we need CX after scan
  1779.                 REPNE SCASB                ; search for extended code in table
  1780.                 STI
  1781.                 SHL        CX, 1            ; CX is now offset in jump-table
  1782.                 MOV        BP, CX
  1783.                 POP        DI
  1784.                 POP        ES
  1785.                 JMP        [BP+ECJT]
  1786.  
  1787. INSERT_R:
  1788.  
  1789.         ;----- flip the insert-toggle
  1790.         ;
  1791.  
  1792.                 NOT        INSERT_TOGGLE
  1793.  
  1794.                 CALL    SET_CURSOR_TYPE
  1795.                 RET
  1796.  
  1797.  
  1798. DELETE_R:
  1799.  
  1800.         ;----- delete the character under the cursor
  1801.         ;
  1802.  
  1803.                 CMP        BL, BH            ; if cursor at end
  1804.                 JE        DR_L2            ; then nothing to delete
  1805.  
  1806.                 MOV        AH, ES:[DI]        ; remember victim for display update
  1807.                 CALL    MOVE_TAIL_LEFT    ; remove from buffer
  1808.                 DEC        BL                ; update total length
  1809.  
  1810.         ;----- next update display
  1811.         ;
  1812.  
  1813.                 MOV        CX, 1            ; at least one character to erase
  1814.  
  1815.                 CMP        AH, 20H            ; control character ?
  1816.                 JAE        DR_L1            ;
  1817.  
  1818.                 INC        CX                ; yes, erase the caret too
  1819.                 CMP        AH, TAB            ; beware of the TAB
  1820.                 JNE        DR_L1            ; if TAB then some calculation required
  1821.                                         ; to determine shift of display
  1822.                 CALL    BACK_TAB
  1823.  
  1824.         DR_L1:
  1825.                 CALL    DISPLAY_TAIL
  1826.  
  1827.         DR_L2:
  1828.                 RET
  1829.  
  1830. CURSOR_LEFT_R:
  1831.  
  1832.         ;----- move current cursor position one to the left
  1833.         ;
  1834.  
  1835.                 OR        BH, BH
  1836.                 JZ        CL_ATBEGIN        ; cursor at begin of string
  1837.                 DEC        DI                ; update pointers
  1838.                 DEC        BH                ;
  1839.  
  1840.         ;----- update display
  1841.         ;
  1842.  
  1843.                 MOV        CX, 1            ; set up for one backspace
  1844.  
  1845.                 MOV        AH, [DI]        ; get character under cursor
  1846.                 CMP        AH, 20H            ; if control-character then
  1847.                 JAE        CL_BS            ; two backspaces are required
  1848.  
  1849.                 INC        CL                ; if ctrl-char then two backspaces
  1850.                 CMP        AH, TAB            ; exception: tab-character
  1851.                 JNE        CL_BS            ;
  1852.  
  1853.                 CALL    BACK_TAB        ; compute number of backspaces
  1854.                                         ; needed for this tab (returned in CL;)
  1855.  
  1856.         CL_BS:
  1857.                 MOV        AL, BACKSPACE
  1858.                 CALL    DISPLAY_COMPLEX
  1859.                 LOOP    CL_BS
  1860.                 RET
  1861.  
  1862.    CL_ATBEGIN:
  1863.                 CALL    BEEP
  1864.                 RET
  1865.  
  1866.  
  1867. CURSOR_RIGHT_R:
  1868.  
  1869.         ;----- move current cursor position one to the right
  1870.         ;
  1871.  
  1872.                 CMP        BL, BH
  1873.                 JE        CR_AT_END        ; cursor at end of string
  1874.                 MOV        AL, [DI]        ; get character under cursor
  1875.                 INC        DI                ; update pointers
  1876.                 INC        BH                ;
  1877.  
  1878.         ;----- update display
  1879.         ;
  1880.  
  1881.                 CMP        AL, 20H
  1882.                 JB        CRR_L2
  1883.  
  1884.         ;----- non-control ascii character, so
  1885.         ;       cursor must move right one position
  1886.         ;       see if this can be done by cursor control
  1887.         ;       if not then redisplay character
  1888.         ;
  1889.  
  1890.                 CMP        FULL_EDIT, ON
  1891.                 JNE        CRR_L2
  1892.  
  1893.                 MOV        AX, CURSOR_POS
  1894.                 INC        AL
  1895.                 CMP        AL, MAX_COL
  1896.                 JB        CRR_L1
  1897.                 CLR        AL
  1898.                 CMP        AH, MAX_ROW - 1
  1899.                 JE        CRR_L1
  1900.                 INC        AH
  1901.  
  1902.         CRR_L1:
  1903.                 MOV        CURSOR_POS, AX
  1904.                 CALL    SET_CURSOR_POS
  1905.                 RET
  1906.  
  1907.         CRR_L2:
  1908.  
  1909.         ;----- move cursor right by redisplaying the character
  1910.         ;       which is under cursor now
  1911.         ;
  1912.  
  1913.                 CALL    DISPLAY_COMPLEX
  1914.                 RET
  1915.  
  1916.     CR_AT_END:
  1917.                 CALL    BEEP
  1918.                 RET
  1919.  
  1920. PREV_LINE_R:
  1921.  
  1922.         ;------------------------------
  1923.         ; empty the current buffer and get the one less
  1924.         ; recent string from the string buffer
  1925.  
  1926.                 MOV        BP, SP            ; need access to buffer address
  1927.                                         ; which is saved on the stack
  1928.                 PUSH    STR_END_POS        ; save current end of string on screen
  1929.                 CALL    CURSOR_BEGIN_R
  1930.  
  1931.         ;----- next find a new string to be edited
  1932.         ;
  1933.  
  1934.                 MOV        AX, C_TBL_HEAD    ; take a look in the
  1935.                 CMP        AX, C_TBL_TAIL    ; string pointer table
  1936.                 JE        PNL_EMPTY        ; no string there
  1937.                                         ; proceed with empty string
  1938.                 MOV        BX, CURRENT        ;
  1939.                 CMP        BX, AX            ; determine previous entry
  1940.                 JNE        PL_L1            ; in TABLE,
  1941.                 MOV        BX, C_TBL_TAIL    ;
  1942.         PL_L1:
  1943.                 CALL    SCROLLUP_TBL    ;
  1944.                 MOV        CURRENT, BX        ; and make it the current one
  1945.                 MOV        CX, CS:[BX]        ;
  1946.                 CMP        BX, AX            ; determine length of this
  1947.                 JNE        PL_L2            ; candidate     by scrolling up
  1948.                 MOV        BX, C_TBL_TAIL    ; another entry ...
  1949.                 JMPS    PL_L3            ;
  1950.         PL_L2:
  1951.                 CALL    SCROLLUP_TBL    ;
  1952.         PL_L3:                            ;
  1953.                 MOV        SI, CS:[BX]        ; ... and subtracting the
  1954.  
  1955.        PNL_L1:
  1956.                 SUB        CX, SI            ; addresses of the strings'
  1957.                 JA        PNL_L2            ; last bytes.
  1958.                 ADD        CX, STR_BUF_SIZE; we have wrapped around in STR_BUF
  1959.        PNL_L2:
  1960.                 JCXZ    PNL_EMPTY
  1961.                 MOV        BL, CL            ; CL now contains the candidate's
  1962.                 MOV        BH, CL            ; length.
  1963.                 CMP        DL, CL            ; initialize string-pointers
  1964.                 JNB        PNL_L3
  1965.  
  1966.                 CALL    BEEP            ; if too long ring bell twice (as long)
  1967.                 CALL    BEEP
  1968.  
  1969.     PNL_EMPTY:
  1970.                 ADD        SP, 4            ; discard return address and
  1971.                                         ; EOS which are on the stack
  1972.                 JMP        FI_RESTART
  1973.  
  1974.  
  1975.         ;----- the new string can be transferred now
  1976.         ;
  1977.  
  1978.        PNL_L3:
  1979.                 MOV        DI, [BP+2]        ; get address of target buffer
  1980.  
  1981.                 INC        SI                ; set source pointer
  1982.        PNL_L4:
  1983.                 CMP        SI, STR_BUF_END ; wrap-around in STR_BUF
  1984.                 JNE        PNL_L5            ; if nessecary
  1985.                 MOV        SI, STR_BUF_START
  1986.        PNL_L5:
  1987.                 LODS    BYTE PTR CS:[SI]; do the transfer
  1988.                 STOSB                    ;
  1989.                 CALL    DISPLAY_COMPLEX ; display this byte
  1990.                 LOOP    PNL_L4            ;
  1991.  
  1992.         ;-----the pointers BH, BL, and DI are properly set up now
  1993.         ;      the current cursor-position is at the end of the new string
  1994.         ;
  1995.  
  1996.         ;----- compute difference in string length
  1997.         ;
  1998.  
  1999.                 POP        CX                ; recover saved STR_END_POS
  2000.                                         ;  of previous string
  2001.                 MOV        AL, CH            ; AL := (OLD)STR_END_ROW
  2002.                 SUB        CX, CURSOR_POS    ; !! CX := CURSOR_POS - (OLD)STR_END_POS
  2003.                 JBE        PNL_L8            ; new > old ?
  2004.                 SUB        AL, CURSOR_ROW    ; AL := CURSOR_ROW - (OLD)STR_END_ROW
  2005.                 MOV        AH, MAX_COL
  2006.                 NEG        AH
  2007.                 MUL        AH                ; multiply by (256 - characters/column)
  2008.                 SUB        CX, AX            ; compensate for subtraction !!
  2009.                                         ; CX := (oldROW - newROW)*MAX_COL +
  2010.                                         ;        (oldCOL - newCOL)
  2011.                 PUSH    CX
  2012.  
  2013.         PNL_L6:
  2014.                 MOV        AL, ' '            ; blank out remnant characters
  2015.                 CALL    DISPLAY_COMPLEX
  2016.                 LOOP    PNL_L6
  2017.                 POP        CX
  2018.  
  2019.         PNL_L7:
  2020.                 MOV        AL, BACKSPACE    ; set cursor back
  2021.                 CALL    DISPLAY_COMPLEX
  2022.                 LOOP    PNL_L7
  2023.  
  2024.         PNL_L8:
  2025.  
  2026.                 PUSH    CURSOR_POS
  2027.                 POP        STR_END_POS
  2028.                 RET                        ; top of stack = address MAINLOOP
  2029.  
  2030.  
  2031.  
  2032.  
  2033. NEXT_LINE_R:
  2034.  
  2035.         ;---------------------------
  2036.         ; empty the current buffer and get the one more
  2037.         ; recent string from the string buffer
  2038.  
  2039.                 MOV        BP, SP            ; need access to buffer address
  2040.                                         ; which is saved on the stack
  2041.                 PUSH    STR_END_POS        ; save current end of string on screen
  2042.                 CALL    CURSOR_BEGIN_R
  2043.  
  2044.         ;----- find next string
  2045.         ;
  2046.  
  2047.                 MOV        AX, C_TBL_TAIL
  2048.                 CMP        AX, C_TBL_HEAD
  2049.                 JE        PNL_EMPTY        ; no string found
  2050.                 MOV        BX, CURRENT
  2051.                 MOV        SI, CS:[BX]        ; get current string's end
  2052.                 CMP        BX, AX            ; current=tail ?
  2053.                 JE        NL_L2            ; yes, wraparound
  2054.                 CALL    SCROLLDO_TBL    ; else, scroll down
  2055.                 CMP        BX, AX            ; at tail now ?
  2056.                 JNE        NL_L3            ; no, go and update CURRENT
  2057.                 MOV        SI, CS:[BX]        ; else, new old string's end
  2058.  
  2059.         NL_L2:
  2060.                 MOV        BX, C_TBL_HEAD    ; wraparound
  2061.  
  2062.         NL_L3:
  2063.                 MOV        CURRENT, BX        ; new current string
  2064.                 MOV        CX, CS:[BX]        ; new string's end
  2065.                 JMP        PNL_L1            ; next check the length
  2066.  
  2067.  
  2068. CURSOR_BEGIN_R:
  2069.  
  2070.         ;----- moves the cursor to the start of the buffer
  2071.         ;
  2072.  
  2073.                 OR        BH, BH            ; is cursor at start ?
  2074.                 JZ        CBR_DONE        ; if so then return
  2075.                 CALL    CURSOR_LEFT_R    ; move one to the left
  2076.                 JMP        CURSOR_BEGIN_R    ; and again until at start
  2077.    CBR_DONE:
  2078.                 RET
  2079.  
  2080. CURSOR_END_R:
  2081.  
  2082.         ;----- moves the cursor to the end of the buffer
  2083.         ;
  2084.  
  2085.                 CMP        BL, BH            ; is cursor at end ?
  2086.                 JE        CER_DONE        ; yes: return
  2087.                 CALL    CURSOR_RIGHT_R    ; move one towards the end
  2088.                 JMP        CURSOR_END_R    ; until done
  2089.    CER_DONE:
  2090.                 RET
  2091.  
  2092. F1_R:
  2093.  
  2094.         ;----- move cursor one word left
  2095.         ;
  2096.  
  2097.                 CALL    CURSOR_LEFT_R            ;
  2098.                 OR        BH, BH                    ; move one character left
  2099.                 JZ        F1_L2                    ; until a non-blank is
  2100.                 CMP        BYTE PTR [DI-1], ' '    ; reached
  2101.                 JE        F1_R                    ;
  2102.  
  2103.         F1_L1:
  2104.                 CALL    CURSOR_LEFT_R            ; now move left until
  2105.                 OR        BH, BH                    ; the next blank
  2106.                 JZ        F1_L2                    ;
  2107.                 CMP        BYTE PTR [DI-1], ' '    ;
  2108.                 JNE        F1_L1
  2109.  
  2110.         F1_L2:                                    ;
  2111.                 RET
  2112.  
  2113.  
  2114. F2_R:
  2115.  
  2116.         ;----- move cursor one word right
  2117.         ;
  2118.  
  2119.                 CALL    CURSOR_RIGHT_R            ;
  2120.                 CMP        BL, BH                    ; move one character right
  2121.                 JE        F2_L2                    ; until a blank is reached
  2122.                 CMP        BYTE PTR [DI], ' '        ;
  2123.                 JNE        F2_R
  2124.  
  2125.         F2_L1:
  2126.                 CALL    CURSOR_RIGHT_R
  2127.                 OR        BH, BH                    ; move on until the
  2128.                 JZ        F2_L2                    ; next non-blank
  2129.                 CMP        BYTE PTR [DI], ' '        ;
  2130.                 JE        F2_L1                    ;
  2131.  
  2132.         F2_L2:                                    ;
  2133.                 RET
  2134.  
  2135.  
  2136. F3_R:
  2137.  
  2138.         ;----- erase from begin of the string to the current cursor position
  2139.         ;
  2140.  
  2141.                 CLR        CH
  2142.                 MOV        CL, BH
  2143.                 JCXZ    F3_L2            ; CX=0: we are at start of string
  2144.  
  2145.         F3_L1:
  2146.                 PUSH    CX                ; save number of characters
  2147.                 CALL    BACKSPACE_R        ; we are going to remove
  2148.                 POP        CX                ; recover number of characters
  2149.                 LOOP    F3_L1            ;
  2150.  
  2151.         F3_L2:
  2152.                 RET
  2153.  
  2154.  
  2155. F4_R:
  2156.  
  2157.         ;----- erase from the current cursor position to the end
  2158.         ;
  2159.  
  2160.                 CLR        CH
  2161.                 MOV        CL, BL
  2162.                 SUB        CL, BH
  2163.                 JZ        F4_L2
  2164.                 CALL    CURSOR_END_R
  2165.  
  2166.         F4_L1:
  2167.                 PUSH    CX
  2168.                 CALL    BACKSPACE_R
  2169.                 POP        CX
  2170.                 LOOP    F4_L1
  2171.  
  2172.         F4_L2:
  2173.                 RET
  2174.  
  2175.  
  2176. F5_R:
  2177.  
  2178.         ;----- insert current string in STR_BUF and start editing a fresh one
  2179.         ;
  2180.  
  2181.                 MOV        BP, SP            ; need access to buffer address
  2182.                                         ; which is saved on the stack
  2183.                 CALL    CURSOR_END_R
  2184.                 MOV        AL, '@'            ; show what is going to happen
  2185.                 CALL    DISPLAY_CHAR    ;
  2186.                 MOV        AL, CR
  2187.                 CALL    DISPLAY_CHAR
  2188.                 MOV        AL, LF
  2189.                 CALL    DISPLAY_CHAR
  2190.  
  2191.                 MOV        SI, [BP+2]        ; get source pointer from stack
  2192.                 CLR        CH
  2193.                 MOV        CL, BL
  2194.                 CALL    STR_BUF_INSERT
  2195.  
  2196.                 ADD        SP, 2            ; discard return address on stack
  2197.                 JMP        FI_RESTART
  2198.  
  2199.  
  2200. F6_R:
  2201.  
  2202.         ;----- End Of File character on function-key 6
  2203.         ;
  2204.  
  2205.                 MOV        AL, EOF
  2206.                 JMP        M_L1            ; go insert this character
  2207.  
  2208.  
  2209. F7_R:
  2210.  
  2211.         ;----- Nul on function-key 7
  2212.         ;
  2213.  
  2214.                 CLR        AL
  2215.                 JMP        M_L1            ; go insert this character
  2216.  
  2217.  
  2218. CTRL_LEFT_R:
  2219.  
  2220.         ;----- move cursor downwards
  2221.         ;
  2222.  
  2223.                 MOV        AX, CURSOR_TYPE
  2224.                 CMP        AL, CURSOR_MASK
  2225.                 JE        CTRL_LR_X
  2226.                 INC        AL
  2227.                 INC        AH
  2228.                 MOV        CURSOR_TYPE, AX
  2229.                 CALL    SET_CURSOR_TYPE
  2230.     CTRL_LR_X:
  2231.                 RET
  2232.  
  2233. CTRL_RIGHT_R:
  2234.  
  2235.         ;----- move cursor upwards
  2236.         ;
  2237.  
  2238.                 MOV        AX, CURSOR_TYPE
  2239.                 OR        AH, AH
  2240.                 JZ        CTRL_RR_X
  2241.                 DEC        AL
  2242.                 DEC        AH
  2243.                 MOV        CURSOR_TYPE, AX
  2244.                 CALL    SET_CURSOR_TYPE
  2245.     CTRL_RR_X:
  2246.                 RET
  2247.  
  2248. CTRL_HOME_R:
  2249.  
  2250.         ;----- move cursor-top downwards
  2251.         ;
  2252.  
  2253.                 MOV        AX, CURSOR_TYPE
  2254.                 CMP        AH, CURSOR_MASK
  2255.                 JE        CTRL_HR_X
  2256.                 INC        AH
  2257.                 MOV        CURSOR_TYPE, AX
  2258.                 CALL    SET_CURSOR_TYPE
  2259.     CTRL_HR_X:
  2260.                 RET
  2261.  
  2262. CTRL_END_R:
  2263.  
  2264.         ;----- move cursor-bottom downwards
  2265.         ;
  2266.  
  2267.                 MOV        AX, CURSOR_TYPE
  2268.                 CMP        AL, CURSOR_MASK
  2269.                 JE        CTRL_ER_X
  2270.                 INC        AL
  2271.                 MOV        CURSOR_TYPE, AX
  2272.                 CALL    SET_CURSOR_TYPE
  2273.      CTRL_ER_X:
  2274.                 RET
  2275.  
  2276. CTRL_PGUP_R:
  2277.  
  2278.         ;----- move cursor-top upwards
  2279.         ;
  2280.  
  2281.                 MOV        AX, CURSOR_TYPE
  2282.                 OR        AH, AH
  2283.                 JZ        CTRL_PU_X
  2284.                 DEC        AH
  2285.                 MOV        CURSOR_TYPE, AX
  2286.                 CALL    SET_CURSOR_TYPE
  2287.      CTRL_PU_X:
  2288.                 RET
  2289.  
  2290. CTRL_PGDN_R:
  2291.  
  2292.         ;----- move cursor-bottom upwards
  2293.         ;
  2294.  
  2295.                 MOV        AX, CURSOR_TYPE
  2296.                 OR        AL, AL
  2297.                 JZ        CTRL_PD_X
  2298.                 DEC        AL
  2299.                 MOV        CURSOR_TYPE, AX
  2300.                 CALL    SET_CURSOR_TYPE
  2301.      CTRL_PD_X:
  2302.                 RET
  2303.  
  2304. SHIFT_F5_R:
  2305.  
  2306.         ;----- decrement change in INSERT cursor-shape
  2307.         ;
  2308.  
  2309.                 CMP        INSERT_SHIFT, 0
  2310.                 JE        SHIFT_F5_X
  2311.                 DEC        INSERT_SHIFT
  2312.                 CALL    SET_CURSOR_TYPE
  2313.      SHIFT_F5_X:
  2314.                 RET
  2315.  
  2316. SHIFT_F6_R:
  2317.  
  2318.         ;----- increment change in INSERT cursor-shape
  2319.         ;
  2320.  
  2321.                 CMP        INSERT_SHIFT, CURSOR_MASK
  2322.                 JE        SHIFT_F6_X
  2323.                 INC        INSERT_SHIFT
  2324.                 CALL    SET_CURSOR_TYPE
  2325.      SHIFT_F6_X:
  2326.                 RET
  2327.  
  2328.  
  2329. ALT_DIGIT:
  2330.  
  2331.         ;----- scroll up through previous strings a number of
  2332.         ;       times given by the digit key which was pressed
  2333.         ;       along with the ALT-key.
  2334.         ;
  2335.  
  2336.                 SUB        AL, ALT_1        ; make use of contiguous range of codes
  2337.                                         ; generated by the ALT-digit keys
  2338.                                         ; AL now in range 0 .. 9
  2339.                 CLR        CH
  2340.                 MOV        CL, AL
  2341.                 JCXZ    DA_LX            ; so ALT_1 same as arrow-up
  2342.  
  2343.                 PUSH    BX
  2344.                 MOV        BX, CURRENT        ; get CURRENT
  2345.  
  2346.         DA_L1:
  2347.                 CMP        BX, C_TBL_HEAD    ; at oldest string in table ?
  2348.                 JNE        DA_L2            ; if so, stop, no wrap around
  2349.                 CALL    SCROLLDO_TBL    ; and undo last scrollup
  2350.                 JMPS    DA_L3
  2351.  
  2352.         DA_L2:
  2353.                 CALL    SCROLLUP_TBL    ; else one entry up
  2354.                 LOOP    DA_L1            ; repeat CX times
  2355.  
  2356.         DA_L3:
  2357.                 MOV        CURRENT, BX        ; update CURRENT
  2358.                 POP        BX
  2359.  
  2360.         DA_LX:
  2361.                 JMP        PREV_LINE_R        ;
  2362.  
  2363.  
  2364.  
  2365. MAIN_LOOP_RETURN:
  2366.  
  2367.         ;----- no match in extended ascii found, return to main loop
  2368.         ;
  2369.  
  2370.                 RET
  2371.  
  2372.  
  2373.  
  2374. MAIN_LOOP        ENDP
  2375.  
  2376.  
  2377. REQ_HDR            STRUC
  2378.  
  2379.     LENGTH        DB        ?
  2380.     UNIT        DB        ?
  2381.     COMMAND        DB        ?
  2382.     STATUS        DW        ?
  2383.     RESERV        DB        8 DUP(?)
  2384.  
  2385. REQ_HDR            ENDS
  2386.  
  2387. INIT_HDR        STRUC
  2388.  
  2389.                 DB        SIZE REQ_HDR DUP(?)
  2390.     NO_UNITS    DB        ?
  2391.     END_ADR        DD        ?
  2392.     PARMS        DD        ?
  2393.  
  2394. INIT_HDR        ENDS
  2395.  
  2396. IO_HDR            STRUC
  2397.  
  2398.                 DB        SIZE REQ_HDR DUP(?)
  2399.     MEDIA        DB        ?
  2400.     BUFFER_ADR    DD        ?
  2401.     COUNT        DW        ?
  2402.  
  2403. IO_HDR            ENDS
  2404.  
  2405. ;-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
  2406. ;
  2407. ;        D E V I C E      S T R A T E G Y     ( ENTRY POINT )
  2408. ;
  2409. ;-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
  2410.  
  2411. D_STRATEGY        PROC    FAR
  2412.  
  2413.         ;----- save request header address
  2414.         ;
  2415.  
  2416.                 MOV        REQ_HEADER_OFS, BX
  2417.                 MOV        REQ_HEADER_SEG, ES
  2418.                 RET
  2419.  
  2420. D_STRATEGY        ENDP
  2421.  
  2422.  
  2423. D_F_TABLE        LABEL    WORD            ; this table contains routine addresses
  2424.                                         ; for the device-driver functions
  2425.  
  2426.                 DW        D_INIT            ;  0: driver initialization
  2427.                 DW        D_NOP            ;  1: media check
  2428.                 DW        D_NOP            ;  2: build BPB
  2429.                 DW        D_IOCTL_IN        ;  3: IO-control input
  2430.                 DW        D_INPUT            ;  4: input
  2431.                 DW        D_NON_DSTR_IN    ;  5: non-destructive input
  2432.                 DW        D_INPUT_STATUS    ;  6: input status
  2433.                 DW        D_INPUT_FLUSH    ;  7: input flush
  2434.                 DW        D_OUTPUT        ;  8: output
  2435.                 DW        D_OUTPUT_VER    ;  9: output with verify
  2436.                 DW        D_OUTPUT_STATUS ; 10: output status
  2437.                 DW        D_OUTPUT_FLUSH    ; 11: output flush
  2438.                 DW        D_IOCTL_OUT        ; 12: IO-control output
  2439.                 DW        D_OPEN            ; 13: device open
  2440.                 DW        D_CLOSE            ; 14: device close
  2441.                 DW        D_NOP            ; 15: removable media
  2442.  
  2443. D_F_TABLE_LEN    =        $ - D_F_TABLE
  2444.  
  2445. ;-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
  2446. ;
  2447. ;        D E V I C E      I N T E R R U P T       ( ENTRY POINT )
  2448. ;
  2449. ;-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
  2450.  
  2451. D_INTERRUPT        PROC    FAR                                ;
  2452.                 STI
  2453.                 PUSH    ES                                ;
  2454.                 PUSH    DS                                ;
  2455.                 PUSH    BP                                ; save
  2456.                 PUSH    DI                                ; registers
  2457.                 PUSH    SI                                ;
  2458.                 PUSH    DX                                ;
  2459.                 PUSH    CX                                ;
  2460.                 PUSH    BX                                ;
  2461.                 PUSH    AX
  2462.  
  2463.                 CALL    SETSTACK                        ; to internal stack
  2464.                 MOV        BIOS_TTY_SW, ON
  2465.                 MOV        ES, REQ_HEADER_SEG                ; get request-
  2466.                 MOV        BX, REQ_HEADER_OFS                ; header block
  2467.                 MOV        AL, ES: [BX].COMMAND            ; get opcode
  2468.                 CLR        AH
  2469.                 SHL        AX, 1
  2470.                 CMP        AX, D_F_TABLE_LEN
  2471.                 JAE        D_ERROR
  2472.                 MOV        SI, AX
  2473.                 JMP        D_F_TABLE[SI]                    ; do request
  2474.  
  2475.         ;----- it is assumed that all routines preserve
  2476.         ;       the ES:BX pointer to the Request Header
  2477.         ;
  2478.  
  2479.       D_ERROR:
  2480.                 OR        ES: [BX].STATUS, 8003H            ; invalid code
  2481.  
  2482.       D_EXIT:
  2483.                 OR        ES: [BX].STATUS, 0100H            ; status_ok
  2484.                 MOV        BIOS_TTY_SW, OFF
  2485.                 CALL    RESETSTACK                        ; back to
  2486.                                                         ; callers stack
  2487.                 POP        AX
  2488.                 POP        BX
  2489.                 POP        CX                                ;
  2490.                 POP        DX                                ;
  2491.                 POP        SI                                ; restore
  2492.                 POP        DI                                ; registers
  2493.                 POP        BP                                ;
  2494.                 POP        DS                                ;
  2495.                 POP        ES                                ;
  2496.                 RET
  2497.  
  2498.  
  2499. D_INTERRUPT        ENDP
  2500.  
  2501.  
  2502.     D_NOP             :
  2503.     D_IOCTL_IN         :
  2504.     D_INPUT             :
  2505.     D_NON_DSTR_IN     :
  2506.     D_INPUT_STATUS     :
  2507.     D_INPUT_FLUSH     :
  2508.     D_OUTPUT_STATUS     :
  2509.     D_OUTPUT_FLUSH     :
  2510.     D_IOCTL_OUT         :
  2511.     D_OPEN             :
  2512.     D_CLOSE             :
  2513.                         JMP        D_ERROR
  2514.  
  2515.  
  2516. INSTALL_BUF        PROC    NEAR
  2517.  
  2518.         ;***************************************************************
  2519.         ;* Redirect the DOS-keyboard-buffer pointers to enlarged buffer
  2520.         ;* Copy old buffer contents to the new buffer
  2521.         ;***************************************************************
  2522.  
  2523.                 PUSH    DS
  2524.                 CMP        KB_INST, ON        ;
  2525.                 JNE        IB_L1            ; buffer is already here
  2526.                 LEA        SI, MSG_KB_PR    ; already present message
  2527.                 JMP        IB_LX
  2528.        IB_L1:
  2529.                 CMP        KBBUFFER_SIZE, 32        ; worth the trouble ?
  2530.                 JA        IB_L2                    ;
  2531.  
  2532.                 LEA        SI, MSG_KB_NO_1            ; message: no succes
  2533.                 CALL    PRINT
  2534.                 MOV        AX, KBBUFFER_SIZE
  2535.                 SHR        AX, 1
  2536.                 CALL    PRINT_NUM
  2537.                 LEA        SI, MSG_KB_NO_2
  2538.                 JMP        IB_LX
  2539.  
  2540.        IB_L2:
  2541.                 ASSUME    DS: DOS_DATA_AREA        ;
  2542.                 MOV        AX, DOS_DATA_AREA        ; data segment on
  2543.                 MOV        DS, AX                    ; DOS-OS Data
  2544.                 CLR        DI
  2545.                 MOV        BX, KBBUFFER
  2546.                 CLI
  2547.                 MOV        SI, KB_HEAD                ; move any data already
  2548.        IB_L3:
  2549.                 CMP        SI, KB_TAIL                ; in the DOS-buffer to
  2550.                 JE        IB_L4                    ; new buffer
  2551.                 CMP        DI, 32                    ; can not copy indefinitely
  2552.                 JE        IB_L4                    ; because new buffer overlays
  2553.                                                 ; initialization code
  2554.                 MOV        AX, [SI]                ;
  2555.                 MOV        CS: [BX+DI], AX            ; transfer item
  2556.                 INC        DI                        ; keep character count
  2557.                 INC        DI                        ;
  2558.                 INC        SI                        ;
  2559.                 INC        SI                        ;
  2560.                 CMP        SI, DOS_BUFFER_END        ; wraparound if
  2561.                 JNE        IB_L3                    ; neccesary
  2562.                 MOV        SI, DOS_BUFFER_START    ;
  2563.                 JMP        IB_L3                    ;
  2564.        IB_L4:
  2565.                 MOV        AX, DOS_BUFFER_START
  2566.                 MOV        OLD_DOS_BUFFER_START, AX
  2567.                 MOV        AX, DOS_BUFFER_END
  2568.                 MOV        OLD_DOS_BUFFER_END, AX
  2569.                 MOV        AX, CS                    ;
  2570.                 SUB        AX, DOS_DATA_AREA        ; make AX point to offset
  2571.                 MOV        CL, 4                    ; KBBUFFER relative to
  2572.                 SHL        AX, CL                    ; segment DOS_DATA_AREA
  2573.                 ADD        AX, KBBUFFER            ;
  2574.                 MOV        DOS_BUFFER_START, AX    ;
  2575.                 MOV        KB_HEAD, AX                ; change pointers to
  2576.                 MOV        KB_TAIL, AX                ; our own buffer
  2577.                 ADD        KB_TAIL, DI                ;
  2578.                 ADD        AX, KBBUFFER_SIZE        ; add number of characters
  2579.                 MOV        DOS_BUFFER_END, AX        ; taken over from old buffer
  2580.                 STI
  2581.                 ASSUME    DS: NOTHING
  2582.  
  2583.                 MOV        KB_INST, ON        ; presence-flag on
  2584.                 LEA        SI, MSG_KB_IN    ; message: succes
  2585.                 CALL    PRINT
  2586.                 LEA        SI, MSG_KB_1    ; give size of buffer
  2587.                 CALL    PRINT
  2588.                 MOV        AX, KBBUFFER_SIZE
  2589.                 SHR        AX, 1
  2590.                 CALL    PRINT_NUM
  2591.                 LEA        SI, MSG_KB_2
  2592.  
  2593.          IB_LX:
  2594.                 CALL    PRINT            ;
  2595.                 POP        DS
  2596.                 RET
  2597. INSTALL_BUF        ENDP
  2598.  
  2599.  
  2600.  
  2601. UNINSTALL_BUF    PROC    NEAR
  2602.  
  2603.         ;************************************************
  2604.         ;* Restore original keyboard buffer pointers
  2605.         ;*************************************************
  2606.  
  2607.                 PUSH    DS
  2608.  
  2609.                 CMP        KB_INST, OFF
  2610.                 JE        UB_L1
  2611.  
  2612.                 ASSUME    DS: DOS_DATA_AREA        ;
  2613.                 MOV        AX, DOS_DATA_AREA        ; data segment on
  2614.                 MOV        DS, AX                    ; DOS-OS Data
  2615.                 CLI
  2616.                 MOV        AX, OLD_DOS_BUFFER_START
  2617.                 MOV        DOS_BUFFER_START, AX    ; restore old
  2618.                 MOV        KB_HEAD, AX                ; buffer addresses
  2619.                 MOV        KB_TAIL, AX                ; note:
  2620.                 MOV        AX, OLD_DOS_BUFFER_END    ;    buffer is flushed
  2621.                 MOV        DOS_BUFFER_END, AX
  2622.                 STI
  2623.                 ASSUME    DS: NOTHING
  2624.  
  2625.                 MOV        KB_INST, OFF
  2626.                 LEA        SI, MSG_KB_UN    ; buffer-gone message
  2627.                 JMPS    UB_LX
  2628.  
  2629.          UB_L1:
  2630.                 LEA        SI, MSG_KB_NOT_PR        ; error message
  2631.  
  2632.          UB_LX:
  2633.                 CALL    PRINT            ; display message
  2634.  
  2635.                 POP        DS
  2636.                 RET
  2637. UNINSTALL_BUF    ENDP
  2638.  
  2639.  
  2640. INSTALL_ED        PROC    NEAR
  2641.  
  2642.         ;**********************************************************
  2643.         ;* Redirect interrupt 21H function 0AH to enable enhanced
  2644.         ;* editing and buffering
  2645.         ;**********************************************************
  2646.  
  2647.                 PUSH    ES
  2648.                 CMP        EDT_INST, ON    ;
  2649.                 JE        IE_L2            ; editor already installed
  2650.  
  2651.                 CMP        EDT_INST, NOT_INST        ; test for first turn on
  2652.                 MOV        EDT_INST, ON            ; presence-flag on
  2653.                 JNE        IE_L1                    ; install INT21H interrupt
  2654.                                                 ; address, if not already done
  2655.                 CLR        AX                        ; segment 0 for interrupt-
  2656.                 MOV        ES, AX                    ; address manipulation
  2657.                 LES        BX, ES: [DOS_FUNCTION_INT]
  2658.                                                 ; save old address
  2659.                 MOV        WORD PTR OLD_FUNCTION_INT, BX
  2660.                 MOV        WORD PTR OLD_FUNCTION_INT[2], ES
  2661.                 MOV        ES, AX
  2662.                                                 ; replace with new address
  2663.                 CLI
  2664.                 MOV        ES: [DOS_FUNCTION_INT], OFFSET FUNCTION_INT_ENTRY
  2665.                 MOV        ES: [DOS_FUNCTION_INT + 2], CS
  2666.                 STI
  2667.  
  2668.         IE_L1:
  2669.                 LEA        SI, MSG_EDT_IN    ; reinitialize message
  2670.                 CALL    PRINT
  2671.                 LEA        SI, MSG_EDT_1    ; editor specification
  2672.                 CALL    PRINT
  2673.                 MOV        AX, STR_BUF_SIZE
  2674.                 CALL    PRINT_NUM
  2675.                 LEA        SI, MSG_EDT_2
  2676.                 CALL    PRINT
  2677.                 MOV        AX, C_TBL_SIZE
  2678.                 SHR        AX, 1            ; size in bytes --> no-of-entries
  2679.                 DEC        AX                ; table-size = entries - 1
  2680.                 CALL    PRINT_NUM
  2681.                 LEA        SI, MSG_EDT_3
  2682.                 JMPS    IE_LX
  2683.  
  2684.         IE_L2:
  2685.                 LEA        SI, MSG_EDT_PR    ; already present message
  2686.  
  2687.         IE_LX:
  2688.                 CALL    PRINT            ;
  2689.  
  2690.                 POP        ES
  2691.                 RET
  2692. INSTALL_ED        ENDP
  2693.  
  2694. UNINSTALL_ED    PROC    NEAR
  2695.  
  2696.         ;*****************************************************
  2697.         ;* restore INT 21H interrupt address
  2698.         ;* if not possible, zero flag is OFF at exit
  2699.         ;*****************************************************
  2700.  
  2701.                 PUSH    ES
  2702.  
  2703.                 CMP        EDT_INST, ON
  2704.                 JNE        UE_L2
  2705.                 MOV        EDT_INST, OFF
  2706.  
  2707.                 CLR        AX
  2708.                 MOV        ES, AX
  2709.  
  2710.         ;----- check whether our address still in vector
  2711.         ;
  2712.  
  2713.                 CMP        ES: [DOS_FUNCTION_INT], OFFSET FUNCTION_INT_ENTRY
  2714.                 JNE        UE_L1
  2715.                 MOV        AX, CS
  2716.                 CMP        ES: [DOS_FUNCTION_INT + 2], AX
  2717.                 JNE        UE_L1
  2718.  
  2719.         ;----- OK, undo revectoring
  2720.         ;
  2721.  
  2722.                 MOV        AX, WORD PTR OLD_FUNCTION_INT
  2723.                 MOV        ES: [DOS_FUNCTION_INT], AX
  2724.                 MOV        AX, WORD PTR OLD_FUNCTION_INT[2]
  2725.                 MOV        ES: [DOS_FUNCTION_INT + 2], AX
  2726.  
  2727.                 MOV        EDT_INST, NOT_INST
  2728.  
  2729.         UE_L1:
  2730.                 LEA        SI, MSG_EDT_UN    ; editor-gone message
  2731.                 JMPS    UE_LX
  2732.         UE_L2:
  2733.                 LEA        SI, MSG_EDT_NOT_PR
  2734.         UE_LX:
  2735.                 CALL    PRINT            ; editor-already-gone message
  2736.  
  2737.                 POP        ES
  2738.                 RET
  2739. UNINSTALL_ED    ENDP
  2740.  
  2741.     RESET_EDT    PROC    NEAR
  2742.                 MOV        AX, C_TBL_START
  2743.                 MOV        C_TBL_HEAD, AX
  2744.                 MOV        C_TBL_TAIL, AX
  2745.                 MOV        CURRENT, AX
  2746.                 RET
  2747.     RESET_EDT    ENDP
  2748.  
  2749. INSTALL_ANSI    PROC    NEAR
  2750.                 MOV        ANSI, ON
  2751.                 MOV        MAX_COL, 80
  2752.                 RET
  2753. INSTALL_ANSI    ENDP
  2754.  
  2755. UNINSTALL_ANSI    PROC    NEAR
  2756.                 MOV        ANSI, OFF
  2757.                 RET
  2758. UNINSTALL_ANSI    ENDP
  2759.  
  2760. RECALL            PROC    NEAR
  2761.  
  2762.         ;----- display all strings in STR_BUF
  2763.         ;
  2764.  
  2765.                 CLR        DX                        ; initialize
  2766.                 MOV        DI, C_TBL_SIZE            ; DX = sequence number
  2767.                 SHR        DI, 1                    ; DI = maximum number of strings
  2768.                 DEC        DI                        ;
  2769.                 MOV        BX, C_TBL_TAIL            ; BX = pointer into C_TBL entry
  2770.                 MOV        SI, CS:[BX]                ; of string currently displayed
  2771.                 MOV        BX, C_TBL_HEAD            ;
  2772.  
  2773.      REC_L1:
  2774.                 CMP        BX, C_TBL_TAIL            ;
  2775.                 JE        REC_LX                    ; all strings done, normal exit
  2776.  
  2777.                 MOV        AL, CR
  2778.                 CALL    WRITE_CHAR
  2779.                 MOV        AL, LF
  2780.                 CALL    WRITE_CHAR
  2781.  
  2782.                 INC        DX
  2783.                 CMP        DX, DI            ; savety check, prevent endless looping
  2784.                 JA        RESET_EDT        ; this jump should not occur, error exit
  2785.  
  2786.                 MOV        AX, DX
  2787.                 CALL    PRINT_NUM
  2788.  
  2789.                 MOV        AL, '.'
  2790.                 CALL    WRITE_CHAR
  2791.                 MOV        AL, ' '
  2792.                 CALL    WRITE_CHAR
  2793.  
  2794.                 MOV        CX, CS:[BX]                ; last character of string
  2795.                 SUB        CX, SI                    ; compute length
  2796.                 JAE        REC_L2
  2797.                 ADD        CX, STR_BUF_SIZE
  2798.  
  2799.      REC_L2:
  2800.                 INC        SI                        ; next character
  2801.                 CMP        SI, STR_BUF_END
  2802.                 JNE        REC_L3                    ; wrap around if necessary
  2803.                 MOV        SI, STR_BUF_START
  2804.  
  2805.      REC_L3:
  2806.                 MOV        AL, CS:[SI]
  2807.                 CALL    DISPLAY_COMPLEX
  2808.                 LOOP    REC_L2
  2809.  
  2810.                 CALL    SCROLLDO_TBL
  2811.                 JMP        REC_L1
  2812.  
  2813.      REC_LX:
  2814.                 RET
  2815. RECALL            ENDP
  2816.  
  2817.  
  2818.  
  2819. D_OUTPUT:
  2820. D_OUTPUT_VER:
  2821.  
  2822.         ;************************************************************
  2823.         ;* Output routine.
  2824.         ;* Characters output to this device are interpreted as
  2825.         ;* control codes to switch the editor and buffer on and off.
  2826.         ;* Such control codes consist always of two characters:
  2827.         ;*         "IK" = Install Keyboard Buffer.
  2828.         ;*         "IE" = Install Keyboard Editor.
  2829.         ;*         "UK" = Uninstall Keyboard Buffer.
  2830.         ;*         "UE" = Uninstall Keyboard Editor.
  2831.         ;*         "RE" = Reset Editor
  2832.         ;*         "IA" = ANSI mode On
  2833.         ;*         "UA" = ANSI mode Off
  2834.         ;*
  2835.         ;* On entry:  ES:BX contains long pointer to Request Header
  2836.         ;************************************************************
  2837.  
  2838.                 PUSH    ES
  2839.                 PUSH    BX
  2840.                 MOV        CX, ES: [BX].COUNT        ; number of characters in CX
  2841.                 OR        CX, CX            ;
  2842.                 JZ        O_LX            ; check for a mistake
  2843.                 LES        BX, ES: [BX].BUFFER_ADR ; load address of buffer
  2844.                 MOV        AL, ES: [BX]    ; get first character from buffer
  2845.                 CMP        EXPECTSECOND, ON; second part expected?
  2846.                 JE        O_L1            ; yes: treat second part
  2847.                 MOV        FIRSTPART, AL    ; no: save this first part
  2848.                 MOV        EXPECTSECOND, ON; now we do expect the second part
  2849.                 CMP        CX, 1            ; was there more then one?
  2850.                 JBE        O_LX            ; no: wait for next arrival
  2851.                 MOV        AL, ES: [BX+1]    ; yes: get second character
  2852.  
  2853.         ;----- at this point there is a complete command
  2854.         ;       and we are ready for interpreting
  2855.         ;
  2856.  
  2857.          O_L1:
  2858.                 MOV        EXPECTSECOND, OFF
  2859.                 MOV        AH, FIRSTPART    ; AX now contains the
  2860.                                         ; two letter code
  2861.                 AND        AX, 0DFDFH        ; capitalize
  2862.                 CMP        AX, 'IK'        ;
  2863.                 JNE        O_L2
  2864.                 CALL    INSTALL_BUF        ; code = 'IK'
  2865.                 JMPS    O_LX
  2866.         O_L2:
  2867.                 CMP        AX, 'IE'        ;
  2868.                 JNE        O_L3
  2869.                 CALL    INSTALL_ED        ; code = 'IE'
  2870.                 JMPS    O_LX
  2871.         O_L3:
  2872.                 CMP        AX, 'UK'        ;
  2873.                 JNE        O_L4
  2874.                 CALL    UNINSTALL_BUF    ; code = 'UK'
  2875.                 JMPS    O_LX
  2876.         O_L4:
  2877.                 CMP        AX, 'UE'        ;
  2878.                 JNE        O_L6
  2879.                 CALL    UNINSTALL_ED    ; code = 'UE'
  2880.                 JMPS    O_LX
  2881.         O_L6:
  2882.                 CMP        AX, 'IA'        ;
  2883.                 JNE        O_L7
  2884.                 CALL    INSTALL_ANSI    ; code = 'IA'
  2885.                 JMPS    O_LX
  2886.         O_L7:
  2887.                 CMP        AX, 'UA'        ;
  2888.                 JNE        O_L8
  2889.                 CALL    UNINSTALL_ANSI    ; code = 'UA'
  2890.                 JMPS    O_LX
  2891.         O_L8:
  2892.                 CMP        AX, 'RC'        ;
  2893.                 JNE        O_L9
  2894.                 CALL    RECALL            ; code = 'UA'
  2895.                 JMPS    O_LX
  2896.         O_L9:
  2897.                 CMP        AX, 'RE'
  2898.                 JNE        O_LX
  2899.                 CALL    RESET_EDT        ; code = 'RE'
  2900.  
  2901.       ;----- otherwise invalid combination
  2902.       ;
  2903.  
  2904.         O_LX:
  2905.                 POP        BX
  2906.                 POP        ES
  2907.                 JMP        D_EXIT            ; to exit protocol
  2908.  
  2909.       ;----- round origin to paragraph boundary
  2910.       ;
  2911.  
  2912.                 ORG        ($ - START_CODE + 15) AND 0FFF0H
  2913.  
  2914. END_CODE        =        $
  2915.  
  2916.  
  2917.    ACTIVATE        DB        OFF                ; activate immediate switch
  2918.    P_CHAR_COUNT DW        ?                ; character count on parameter line
  2919.  
  2920.  MSG_INVA_SW_1    DB        ' Invalid switch at position          : ', NULL
  2921.  MSG_INVA_SW_2    DB        ' in Configuration file'
  2922.                 DB        CR, LF, LF, NULL
  2923.  
  2924.  MSG_INVA_CHR_1 DB        ' Invalid character at position          : ', NULL
  2925.  MSG_INVA_CHR_2 DB        ' in Configuration file'
  2926.                 DB        CR, LF, LF, NULL
  2927.  
  2928.  MSG_ADR_OVL    DB        ' Buffer sizes too large, reduce parameter values'
  2929.                 DB        ' in Configuration file'
  2930.                 DB        CR, LF
  2931.                 DB        ' Default values substituted'
  2932.                 DB        CR, LF, LF, NULL
  2933.  
  2934.  MSG_OVL_1        DB        ' Parameter value overflow at position: ', NULL
  2935.  MSG_OVL_2        DB        ' in Configuration file'
  2936.                 DB        CR, LF, NULL
  2937.  
  2938.  MSG_ADJUST_1    DB        '  Specified size for keyboard buffer too large,'
  2939.                 DB        '  size adjusted to : ', NULL
  2940.  MSG_ADJUST_2    DB        ' bytes', CR, LF, NULL
  2941.  
  2942.  
  2943.  GET_PARMS        PROC    NEAR
  2944.  
  2945. ;*************************************************************
  2946. ;  This procedure scans the string addressed by DS:SI for
  2947. ;  the presence of parameters to the driver.
  2948. ;
  2949. ;  Parameters must have the following format:
  2950. ;
  2951. ;     DEVICE=\path\drv_name K:nnn B:nnn C:nnn [/A] [/N]
  2952. ;
  2953. ;    where  nnn    is a decimal number.
  2954. ;
  2955. ;    K:nnn  nnn is keyboard buffer size
  2956. ;    B:nnn  nnn is buffer size for command strings
  2957. ;    C:nnn  nnn is maximum number of commands that can be stored
  2958. ;    /A       if present: activation on driver installation
  2959. ;    /N       if present: cursor control through ANSI-codes
  2960. ;
  2961. ;
  2962. ;  The code should implement the following:
  2963. ;
  2964. ;     ----------------------
  2965. ;
  2966. ;     C: CHAR;
  2967. ;     Separators = [NULL, ' ', ',', '=', ';', '+', TAB];
  2968. ;
  2969. ;     ON EndOfLine: EXIT;
  2970. ;     REPEAT GetChar(C) UNTIL C IN Separators;
  2971. ;     REPEAT
  2972. ;       WHILE (C IN Separators) DO GetChar(C);
  2973. ;       CASE C OF
  2974. ;          'K': OUT1 := GetNum;
  2975. ;          'B': OUT2 := GetNum;
  2976. ;          'C': OUT3 := GetNum;
  2977. ;          '/': [GetChar(C); IF C='A' THEN ACTIVATE := ON
  2978. ;                            ELSE IF C='N' THEN ANSI := ON
  2979. ;               ];
  2980. ;
  2981. ;     UNTIL EndOfLine;
  2982. ;
  2983. ;     GetNum:
  2984. ;       GetNum := 0;
  2985. ;       IF C = ':' THEN GetChar(C);
  2986. ;       WHILE (C IN ['0'..'9']) DO [
  2987. ;         GetNum := GetNum*10 + (Ord(C) - Ord('0'));
  2988. ;         GetChar(C)
  2989. ;       ];
  2990. ;
  2991. ;      ---------------------
  2992. ;
  2993. ;
  2994.  
  2995.                 LDS        SI, ES: [BX].PARMS
  2996.                 MOV        P_CHAR_COUNT, 7            ; assume 'DEVICE=' occupies
  2997.                                                 ; first 7 positions in CONFIG
  2998.         GP_L1:
  2999.                 CALL    GET_P_CHAR
  3000.                 JZ        GP_LX
  3001.  
  3002.                 CALL    IN_SEPARATORS
  3003.                 JNZ        GP_L1
  3004.  
  3005.       GP_NEXT:
  3006.                 CALL    GET_P_CHAR
  3007.                 JZ        GP_LX
  3008.  
  3009.                 CALL    IN_SEPARATORS
  3010.                 JZ        GP_NEXT
  3011.  
  3012.                 CMP        AL, 'K'
  3013.                 JNE        GP_LB
  3014.  
  3015.         ;----- collect keyboard buffer size
  3016.         ;
  3017.  
  3018.                 CALL    GET_NUM
  3019.                 OR        CX, CX            ; check result
  3020.                 JZ        GP_LK1            ; zero ?
  3021.                 JS        GP_LO            ; > 32K ?
  3022.                 SHL        CX, 1            ; each keystroke fills two bytes
  3023.                 MOV        KBBUFFER_SIZE, CX        ; in buffer
  3024.         GP_LK1:
  3025.                 JMP        GP_NEXT
  3026.  
  3027.         GP_LB:
  3028.                 CMP        AL, 'B'
  3029.                 JNE        GP_LC
  3030.  
  3031.         ;----- collect string buffer size
  3032.         ;
  3033.  
  3034.                 CALL    GET_NUM
  3035.                 OR        CX, CX            ; check result
  3036.                 JZ        GP_LB1
  3037.                 MOV        STR_BUF_SIZE, CX
  3038.         GP_LB1:
  3039.                 JMP        GP_NEXT
  3040.  
  3041.         GP_LC:
  3042.                 CMP        AL, 'C'
  3043.                 JNE        GP_LS
  3044.  
  3045.         ;----- collect maximum number of commands
  3046.         ;
  3047.  
  3048.                 CALL    GET_NUM
  3049.                 OR        CX, CX            ; check result
  3050.                 JZ        GP_LC1
  3051.                 INC        CX                ; table-size = no-of-entries + 1
  3052.                 JS        GP_LO            ; > 32K ?
  3053.                 SHL        CX, 1            ; CX = no-of-entries, convert to bytes
  3054.                 MOV        C_TBL_SIZE, CX
  3055.         GP_LC1:
  3056.                 JMP        GP_NEXT
  3057.  
  3058.         GP_LX:
  3059.                 RET
  3060.  
  3061.         GP_LS:
  3062.                 CMP        AL, '/'
  3063.                 JNE        GP_L6
  3064.  
  3065.         ;----- collect switches
  3066.         ;
  3067.  
  3068.                 CALL    GET_P_CHAR
  3069.                 JZ        GP_LX
  3070.                 CMP        AL, 'A'
  3071.                 JNE        GP_LS1
  3072.                 MOV        ACTIVATE, ON
  3073.                 JMP        GP_NEXT
  3074.         GP_LS1:
  3075.                 CMP        AL, 'N'
  3076.                 JNE        GP_LS2
  3077.                 MOV        ANSI, ON
  3078.                 JMP        GP_NEXT
  3079.  
  3080.         GP_LS2:
  3081.  
  3082.         ;----- invalid switch
  3083.         ;
  3084.  
  3085.                 PUSH    SI
  3086.                 LEA        SI, MSG_INVA_SW_1
  3087.                 CALL    PRINT
  3088.                 MOV        AX, P_CHAR_COUNT
  3089.                 CALL    PRINT_NUM
  3090.                 LEA        SI, MSG_INVA_SW_2
  3091.                 CALL    PRINT
  3092.                 POP        SI
  3093.                 JMP        GP_L1
  3094.  
  3095.         GP_LO:
  3096.  
  3097.         ;----- overflow
  3098.         ;
  3099.  
  3100.                 PUSH    SI
  3101.                 LEA        SI, MSG_OVL_1
  3102.                 CALL    PRINT
  3103.                 MOV        AX, P_CHAR_COUNT
  3104.                 DEC        AX
  3105.                 CALL    PRINT_NUM
  3106.                 LEA        SI, MSG_OVL_2
  3107.                 CALL    PRINT
  3108.                 POP        SI
  3109.                 JMP        GP_NEXT
  3110.  
  3111.         GP_L6:
  3112.  
  3113.         ;----- invalid character on line
  3114.         ;
  3115.  
  3116.                 PUSH    SI
  3117.                 LEA        SI, MSG_INVA_CHR_1
  3118.                 CALL    PRINT
  3119.                 MOV        AX, P_CHAR_COUNT
  3120.                 CALL    PRINT_NUM
  3121.                 LEA        SI, MSG_INVA_CHR_2
  3122.                 CALL    PRINT
  3123.                 POP        SI
  3124.                 JMP        GP_L1                    ; go on after next separator
  3125.  
  3126.  
  3127. IN_SEPARATORS    PROC    NEAR
  3128.  
  3129.         ;----- determine if character is in the separator set
  3130.         ;       in: AL: character
  3131.         ;       return: zero flag set if Al in separators
  3132.         ;       !! CR and LF are also return zero
  3133.         ;
  3134.                 CMP        AL, NULL
  3135.                 JE        IS_LX
  3136.                 CMP        AL, ' '
  3137.                 JE        IS_LX
  3138.                 CMP        AL, ','
  3139.                 JE        IS_LX
  3140.                 CMP        AL, '='
  3141.                 JE        IS_LX
  3142.                 CMP        AL, '+'
  3143.                 JE        IS_LX
  3144.                 CMP        AL, ';'
  3145.                 JE        IS_LX
  3146.                 CMP        AL, TAB
  3147.                 JE        IS_LX
  3148.                 CMP        AL, CR
  3149.                 JE        IS_LX
  3150.                 CMP        AL, LF
  3151.         IS_LX:
  3152.                 RET
  3153. IN_SEPARATORS    ENDP
  3154.  
  3155.   GET_P_CHAR    PROC    NEAR
  3156.  
  3157.         ;----- return next character from parameter-string in AL
  3158.         ;       if EndOfLine reached then zero-flag is set
  3159.         ;
  3160.                 CMP        AL, CR
  3161.                 JE        GPC_LX
  3162.                 LODSB
  3163.                 INC        P_CHAR_COUNT
  3164.                 CMP        AL, CR
  3165.                 JE        GPC_LX
  3166.                 CMP        AL, LF
  3167.         GPC_LX:
  3168.                 RET
  3169.   GET_P_CHAR    ENDP
  3170.  
  3171.   PUT_P_CHAR    PROC    NEAR
  3172.  
  3173.         ;----- reverse last action of GET_P_CHAR
  3174.         ;       AL is pushed back onto the "input-stream"
  3175.         ;
  3176.                 DEC        SI
  3177.                 DEC        P_CHAR_COUNT
  3178.                 RET
  3179.   PUT_P_CHAR    ENDP
  3180.  
  3181.   GET_NUM        PROC    NEAR
  3182.  
  3183.         ;----- read a decimal number from parameter string
  3184.         ;       out: CX contains the number
  3185.         ;       this routine reads only digits, when an other
  3186.         ;       character is read it is pushed back through
  3187.         ;       PUT_P_CHAR and the routine exits
  3188.         ;
  3189.  
  3190.                 CLR        CX
  3191.                 CALL    GET_P_CHAR
  3192.                 JZ        GN_LX
  3193.                 CMP        AL, ':'
  3194.                 JNE        GN_L2
  3195.         GN_L1:
  3196.                 CALL    GET_P_CHAR
  3197.                 JZ        GN_LX
  3198.         GN_L2:
  3199.                 CMP        AL, '9'            ; test for digit
  3200.                 JA        GN_LX
  3201.                 CMP        AL, '0'
  3202.                 JB        GN_LX
  3203.                 SUB        AL, '0'
  3204.                 XCHG    CX, AX            ; multiplication operand in AX
  3205.                 MUL        TEN                ; x 10
  3206.                 XCHG    CX, AX
  3207.                 JNC        GN_L3            ; test for overflow
  3208.                 CLR        CX                ; if so, return zero
  3209.                 JMPS    GN_LX1
  3210.         GN_L3:
  3211.                 CLR        AH                ;
  3212.                 ADD        CX, AX            ; add next digit
  3213.                 JMP        GN_L1
  3214.  
  3215.         GN_LX:
  3216.                 CALL    PUT_P_CHAR
  3217.         GN_LX1:
  3218.                 RET
  3219.   GET_NUM        ENDP
  3220.  
  3221.  GET_PARMS        ENDP
  3222.  
  3223.  
  3224.  D_INIT            PROC    NEAR
  3225.  
  3226.         ;************************************************************
  3227.         ;* Driver initialization routine.
  3228.         ;*
  3229.         ;* !! version 2.0 only installs driver at boot-time
  3230.         ;* !! NO immediate activation of buffers and editor
  3231.         ;************************************************************
  3232.  
  3233.                 PUSH    ES
  3234.                 PUSH    BX
  3235.                 MOV        BIOS_TTY_SW, ON
  3236.  
  3237.                 MOV        AX, CS
  3238.                 MOV        DS, AX                    ; tell about the instal-
  3239.                 LEA        SI, MSG_VERSION            ; lation of this driver
  3240.                 CALL    PRINT                    ;
  3241.  
  3242.                 CALL    GET_PARMS
  3243.  
  3244.         ;----- check the parameters
  3245.         ;
  3246.  
  3247.                 MOV        CL, 4
  3248.                 MOV        AX, KBBUFFER_SIZE        ; compute end of KBBUFFER
  3249.                 ADD        AX, 0FH                    ;
  3250.                 SHR        AX, CL                    ; paragraph format
  3251.                 ADD        AX, (END_CODE - START_CODE) SHR 4
  3252.                 MOV        CX, CS                    ; add segment paragraph number
  3253.                 ADD        AX, CX                    ;
  3254.                 SUB        AX, 1000H                ; must not exceed first 64K
  3255.                 JBE        D_IN_L2
  3256.                 MOV        CL, 4                    ;
  3257.                 SHL        AX, CL                    ; in bytes again
  3258.                 SUB        KBBUFFER_SIZE, AX        ; adjust KBBUFFER_SIZE
  3259.                 JNC        D_IN_L1                    ; no negative values
  3260.                 MOV        KBBUFFER_SIZE, 0
  3261.  
  3262.         D_IN_L1:
  3263.                 LEA        SI, MSG_ADJUST_1        ;
  3264.                 CALL    PRINT                    ; display message
  3265.                 MOV        AX, KBBUFFER_SIZE        ; and new size of KBBUFFER
  3266.                 CALL    PRINT_NUM                ;
  3267.                 LEA        SI, MSG_ADJUST_2        ;
  3268.                 CALL    PRINT
  3269.  
  3270.         D_IN_L2:
  3271.                 LEA        AX, END_CODE
  3272.                 MOV        KBBUFFER, AX            ; set start address of KB-buffer
  3273.  
  3274.                 ADD        AX, KBBUFFER_SIZE
  3275.                 MOV        STR_BUF_START, AX        ; initialize command string
  3276.                 MOV        STR_BUF_HEAD, AX        ; buffer data-structure
  3277.                 MOV        STR_BUF_TAIL, AX        ;
  3278.                 ADD        AX, STR_BUF_SIZE        ;
  3279.                 JC        D_IN_ERR                ; test for overflow
  3280.  
  3281.                 MOV        STR_BUF_END, AX            ;
  3282.  
  3283.                 MOV        SI, AX                    ; initialize first entry
  3284.                 MOV        CS:[SI], AX                ; in C_TBL with address of
  3285.                 DEC        WORD PTR CS:[SI]        ; last byte in STR_BUF
  3286.  
  3287.                 MOV        C_TBL_START, AX            ; start address of C_TBL
  3288.                 MOV        C_TBL_HEAD, AX            ;
  3289.                 MOV        C_TBL_TAIL, AX            ;
  3290.                 MOV        CURRENT, AX
  3291.                 ADD        AX, C_TBL_SIZE            ; now AX = end of resident code
  3292.                 JC        D_IN_ERR                ; test for overflow
  3293.                 MOV        C_TBL_END, AX            ; end of C_TBL
  3294.  
  3295.         ;----- fill in in Request Header
  3296.         ;
  3297.  
  3298.                 MOV        WORD PTR ES: [BX].END_ADR, AX
  3299.                 MOV        WORD PTR ES: [BX].END_ADR+2, CS
  3300.  
  3301.                 CMP        ACTIVATE, ON            ; /A switch present ?
  3302.                 JNE        D_IN_LX
  3303.                 CALL    INSTALL_BUF                ; if so, install now
  3304.                 CALL    INSTALL_ED                ;
  3305.  
  3306.         D_IN_LX:
  3307.                 MOV        BIOS_TTY_SW, OFF        ; display through DOS
  3308.                 POP        BX
  3309.                 POP        ES
  3310.                 JMP        D_EXIT                    ; initialization done:
  3311.                                                 ;  to exit protocol
  3312.      D_IN_ERR:
  3313.                 LEA        SI, MSG_ADR_OVL            ; address-overflow message
  3314.                 CALL    PRINT                    ;
  3315.                 MOV        C_TBL_SIZE, 32            ; set default values
  3316.                 MOV        STR_BUF_SIZE, 512        ; these values should not
  3317.                 MOV        ACTIVATE, OFF            ; cause trouble
  3318.                 JMP        D_IN_L2                    ; try again
  3319.  
  3320.  D_INIT            ENDP
  3321.  
  3322.     CODE        ENDS
  3323.                 END
  3324.  
  3325.