home *** CD-ROM | disk | FTP | other *** search
/ Frostbyte's 1980s DOS Shareware Collection / floppyshareware.zip / floppyshareware / WLAX / ZAVT11.ZIP / ZAVT.ASM < prev    next >
Assembly Source File  |  1990-05-28  |  25KB  |  948 lines

  1. page    58,132
  2. ;--- zavt.asm ----------------------------------------------------------
  3. ; Zephyr Avatar terminal driver.
  4. ;    Copyright (C) 1989-1990, Luns Tee, Toronto Ontario
  5. ;    Based on original code for ZANSI by Thomas Hanlin III, Alexandria VA.
  6. ;    and original code for NANSI by Daniel Kegel, Pasadena CA.
  7. ;
  8. ; Revision History:
  9. ;------------------------------------------------------------------------
  10. ; Luns Tee, Toronto Ontario
  11. ; 19 Dec 1988:    Replaced code to set 43 lines with code to check
  12. ;        number of lines on screen through bios and then
  13. ;        set internal paramaters accordingly
  14. ;
  15. ; 8 Mar 1989:    Removed forementioned code completely and placed it
  16. ;        with the code that determines screen size and video
  17. ;        mode at each write. Also added routines for automatic
  18. ;        support of different video pages and tidied up the
  19. ;        TTY scroll
  20. ;
  21. ; 24 Mar 1989:    Added code to enable/disable pseudocursor. Similar to
  22. ;        enabling/disabling end of line wrap but with 45 instead
  23. ;        i.e. esc[45l disables pseudocursor, esc[45h reenables
  24. ;
  25. ; 15 Apr 1989:    Removed all the JMP $+2 from the cursor set routines as
  26. ;        nobody could give a reason for their being there aside
  27. ;        from them being artifacts from compiling a higher level
  28. ;        language
  29. ;
  30. ; 17 Aug 1989;    Added code to allow backspace across left margin as
  31. ;        is required for upcoming (?) command line editor
  32. ;        enhancement TSR
  33. ;
  34. ; 23 Aug 1989;    Put in faster *10 code in parsing, fixed bug involving
  35. ;        backspace after wraparound on screens of width >128
  36. ;        and general maniacal cleaning up
  37. ;
  38. ; 26 Aug 1989;    Fixed minor bug in beep routine as addressed in NANSI 22c
  39. ;        and made the darned bell shorter
  40. ;
  41. ; 20 Sep 1989;    added restriction that DSR paramater must be 6 (as
  42. ;        mentioned inconsistently between sources) and centralized
  43. ;        graphics mode checking to balance Mono and Color system
  44. ;        speeds
  45. ;
  46. ; 29 Sep 1989;    made max_x one based and saved 10 bytes, reversed
  47. ;        strategy for HVP_SET and changed BYTEOUT to support
  48. ;        screens up to 255x255 in size
  49. ;
  50. ; 16 Nov 1989;    removed redundant code between getchar/peekchar as well as
  51. ;        the interrupt functions, word aligned everything relevant,
  52. ;        made check for non EGA screens part of init rather than
  53. ;        part of normally resident interrupt routine, tightened
  54. ;        backspace, reordered code to make for more jmp short rather
  55. ;        than jmp near, rewrote parse routines so a colon not
  56. ;         preceeded by a number acts as predicted, removed all KKR and
  57. ;        kb remapping artifacts, fixed bug involving tabs over the
  58. ;        right margin on screens of widths not a multiple of 8,
  59. ;        referred byte requests for 0 to dh instead of a constant,
  60. ;        put everything not needed as a word variable into equates,
  61. ;        put register saving and compilation paramaters into macros
  62. ;        in an include file ZANSI_D.ASM and rewrote SM/RM
  63. ;
  64. ;  26 Nov 1989;    Modified scroll routine to better handle situations
  65. ;        where screen lengths change leaving cursor off screen
  66. ;        - formerly scrolled screen while writing outside of it - now
  67. ;        scrolls region from start of screen to cursor bringing
  68. ;        active screen area into view
  69. ;
  70. ;  27 Dec 1989;    Added support for AVATAR/0 except for ^Y RLE (being planned)
  71. ;        and added switches in ZANSI_D for AVATAR, direct scroll
  72. ;        override (for back-scroll users), and left margin wrap
  73. ;
  74. ;  4 Feb 1990;    Finished off RLE support, commented all code not in ZANSI12
  75. ;        and renamed to ZAVT.
  76. ;
  77. ;  21 Feb 1990;    Put 'hold's into cursor set routine for driver compiled for
  78. ;        286 as it is on the faster machines (wish I had one) that
  79. ;        they are needed to give the system time to catch up
  80. ;
  81. ;  28 Feb 1990;    Took code from PC-Mag's DOS-EDIT as grounds for a full-screen
  82. ;        editor for DOS input. Effect is the similar, but code is now
  83. ;        where it belongs saving some TSR conflicts
  84. ;
  85. ;  23 May 1990;    Dug up NANSI code and replace keyboard remapping. Also
  86. ;        reversed keybuf logic - strings are no longer stored
  87. ;        inverted - to simplify code
  88. ;------------------------------------------------------------------------
  89.  
  90.     include    zavt_d.asm        ; get equates
  91.  
  92.     ; from zavt_p.asm
  93.     extrn    f_escape:near, f_in_escape:near
  94.  
  95.     if    avatar
  96.     extrn    avt_cls:near, f_avatar:near
  97.     extrn    dle:near, rle:near
  98.     endif
  99.  
  100.     ; from zavt_i.asm
  101.     extrn    dosfn0:near
  102.     if    fullscreen
  103.     extrn    linebufend:word
  104.     endif
  105.  
  106.     ; to zavt_p.asm
  107.     public    f_loopdone
  108.     public    f_control
  109.     public    f_looploop
  110.     public    cur_parm_ptr
  111.     public    escvector, string_term
  112.  
  113.     if    avatar
  114.     public    f_nctl
  115.     public    f_loop_nocheck
  116.     public    gmode_flag
  117.     public    putchar
  118.     endif
  119.  
  120.     ; to both zavt_p.asm and zavt_f.asm
  121.     public    cur_x, cur_y, max_x, max_y, cur_attrib,string_attrib
  122.  
  123.     ; to zavt_f.asm
  124.     public    pseudo_flag
  125.     public    wrap_flag
  126.     public    gmode_flag
  127.     public    xy_to_regs, get_blank_attrib
  128.     public    port_6845
  129.     public    cur_coords, saved_coords
  130.     public    max_coords
  131.     public    cpr_esc, cpr_buf, cprseq
  132.     public    video_mode
  133.     public    screen_len
  134.     public    cur_page
  135.     public    video_off
  136.  
  137.     ; to zavt_i.asm
  138.     public    hdrseg
  139.     public    req_ptr, break_handler
  140.     public    int_29
  141.  
  142.  
  143.     ; from zavt_k.asm
  144.     extrn    screenedit:near
  145.     extrn    getchar:near, peekchar:near
  146.  
  147.     ; to zavt_k.asm
  148.     if    fullscreen
  149.     public    scrnbuf, pseudocursor
  150.     endif
  151.  
  152.     if    xlate
  153.     public    xlatseq
  154.     endif
  155.     public    fnkey, fnkeybuf
  156.  
  157.  
  158. CODE    segment byte public 'CODE'
  159. assume    cs:code, ds:code
  160.  
  161.     ; Device Driver Header
  162.  
  163.     org    0
  164.  
  165.     if    two_handlers
  166.     dw    header2
  167.     else
  168.     dw    -1
  169.     endif
  170. hdrseg    dw    -1            ; next device
  171.     dw    8013h            ; attributes
  172.     dw    strategy        ; request header pointer entry
  173.     dw    interrupt        ; request entry point
  174.     db    'CON', 5 dup(' ')    ; device name (8 char)
  175. header2:
  176.     if    two_handlers
  177.     dd    -1            ; next device
  178.     dw    8013h            ; attributes
  179.     dw    strategy        ; request header pointer entry
  180.     dw    interrupt        ; request entry point
  181.     db    'KEYB', 4 dup(' ')    ; device name (8 char)
  182.     endif
  183.  
  184. ; following three keybufs hold information about input
  185. ; Storage order determines priority- since the characters making up a function
  186. ; key code must never be separated (say, by a Control-Break), they have the
  187. ; highest priority, and so on.    Keyboard keys (except ctrl-break) have the
  188. ; lowest priority.
  189.  
  190. fnkey    keybuf    <0, fnkeybuf>    ; fn key string (0 followed by scan code)
  191. cprseq    keybuf    <0>        ; CPR string (ESC [ y;x R)
  192. brkkey    keybuf    <0, brkkeybuf>    ; ^C
  193.     if    fullscreen
  194. scrnbuf    keybuf    <0>        ; line from full-screen editor
  195.     endif
  196.     if    xlate
  197. xlatseq    keybuf    <0>        ; keyboard reassignment string
  198.     endif
  199.  
  200.  
  201. ;------- dos_fn_tab -------------
  202. ; This table is used in "interrupt" to call the routine that handles
  203. ; the requested function.
  204.  
  205. max_cmd equ    12
  206. dos_fn_tab:
  207.     dw    dosfn0, nopcmd, nopcmd, badcmd, dosfn4, dosfn5, dosfn6
  208.     dw    dosfn7, dosfn8, dosfn8, nopcmd, nopcmd
  209.  
  210. ;----- variable area --------------------
  211. req_ptr label    dword
  212. req_off dw    ?
  213. req_seg dw    ?
  214.  
  215. escvector    dw    0    ; state vector of ESCape sequencer
  216. pseudo_flag    db    1    ; 1 = simulate cursor in graphics modes
  217. wrap_flag    db    1    ; 0 = no wrap past line end
  218. video_mode    db    3    ; ROM BIOS video mode (2=BW, 3=color)
  219. gmode_flag    db    0    ; 0 = text mode
  220. max_coords    label    word
  221. max_y        db    24
  222. max_cur_x    label    word    ; used to get both max & cur at once
  223. max_x        db    80    ; line width (80 for 80x25 modes)
  224. cur_coords    label    word
  225. cur_x        db    0    ; cursor position (0 = left edge)
  226. cur_y        db    0    ;          (0 = top edge)
  227. saved_coords    dw    ?    ; holds XY after a SCP escape sequence
  228. video_off    dw    0    ; offset of current page into video buffer
  229. screen_len    dw    ?    ; bytes on screen (w attributes)
  230. f_cptr_seg    dw    ?    ; part of fastout write buffer pointer
  231. cur_parm_ptr    dw    ?    ; last byte of parm area now used
  232. port_6845    dw    ?    ; port address of 6845 card
  233. string_attrib    label    word    ; to get the attribute pronto
  234. string_term    db    0    ; either escape or double quote
  235. cur_attrib    db    7    ; current char attributes
  236. cur_page    db    0    ; current display page
  237.  
  238.  
  239. brkkeybuf    db    3    ; control C
  240. fnkeybuf    db    ?    ; holds second byte of fn key codes
  241. cpr_esc     db    27,'['    ; descending buffer for cpr function
  242. cpr_buf     db    9 dup (?)
  243.  
  244. ;------ xy_to_regs --------------------------------------------
  245. ; on entry: x in cur_x, y in cur_y
  246. ; on exit:  dx = chars left on line, di = address
  247. ; Alters ax, bx.
  248. xy_to_regs    proc    near
  249.     ; Find number of chars til end of line, keep in DX
  250.     mov    ax,max_cur_x
  251.     xor    bx,bx            ; BX = cur_x
  252.     xchg    bl,ah            ; AX = max_x
  253.     mov    dx,ax
  254.     sub    dx,bx            ; DX is # of chars till EOL
  255.     ; Calculate DI = current address in text buffer
  256.     mul    cur_y
  257.     add    ax,bx            ; AX is # of chars into buffer
  258.     shl    ax,1
  259.     add    ax,[video_off]
  260.     mov    di,ax            ; DI is now offset of cursor.
  261.     ret
  262. xy_to_regs    endp
  263.  
  264.  
  265. ;------- strategy ----------------------------------------------------
  266. ; DOS calls strategy with a request which is to be executed later.
  267. ; Strategy just saves the request.
  268.  
  269. strategy    proc    far
  270.     mov    cs:req_off,BX
  271.     mov    cs:req_seg,ES
  272.     ret
  273. strategy    endp
  274.  
  275. ;------ interrupt -----------------------------------------------------
  276. ; This is where the request handed us during "strategy" is
  277. ; actually carried out.
  278. ; Calls one of 12 subroutines depending on the function requested.
  279. ; Each subroutine returns with exit status in AX.
  280.  
  281. interrupt    proc    far
  282.     sti
  283.     push_all
  284.  
  285.     ; Read requested function information into registers
  286.     lds    bx,cs:req_ptr
  287.     mov    al,2[BX]        ; al = function code
  288.     les    si,14[BX]        ; ES:SI = input/output buffer addr
  289.     mov    cx,18[BX]        ; cx = input/output byte count
  290.  
  291.     cmp    al,max_cmd
  292.     ja    unk_command        ; too big, exit with error code
  293.  
  294.     mov    bx,ax
  295.     shl    bx,1            ; form index to table of words
  296.     mov    ax,cs
  297.     mov    ds,ax
  298.     call    word ptr dos_fn_tab[bx]
  299. int_done:
  300.     lds    bx,cs:req_ptr        ; report status
  301.     or    ax,100h            ; (always set done bit upon exit)
  302.     mov    3[bx],ax
  303.  
  304.     pop_all                ; restore caller's registers
  305.     ret                ; return to DOS.
  306.  
  307. unk_command:
  308.     call    badcmd
  309.     jmp    int_done
  310.  
  311. interrupt    endp
  312.  
  313. ;----- BIOS break handler -----------------------------------------
  314. ; Called by BIOS when Control-Break is hit (vector was set up in Init).
  315. ; Simply notes that a break was hit.  Flag is checked during input calls.
  316.  
  317. break_handler    proc
  318.     mov    cs:brkkey.len, 1
  319.     iret
  320. break_handler    endp
  321.  
  322.  
  323. ;------ badcmd -------------------------------------------------------
  324. ; Invalid function request by DOS.
  325. badcmd    proc    near
  326.     mov    ax, 813h        ; return "Error: invalid cmd"
  327.     ret
  328. badcmd    endp
  329.  
  330.  
  331. ;------- dos function #4 -----------------------------------------------
  332. ; Reads CX characters from the keyboard, places them in buffer at ES:SI.
  333. dosfn4    proc    near
  334.     jcxz    nopcmd
  335.     mov    di,si
  336. dos4lp: push    cx
  337.     call    getchar
  338.     pop    cx
  339.     stosb
  340.     loop    dos4lp
  341. dosfn4    endp
  342.  
  343. ;------ nopcmd -------------------------------------------------------
  344. ; Unimplemented or dummy function request by DOS.
  345. ; also used as a central not-busy exit for othere functions
  346. nopcmd    proc    near
  347.     xor    ax, ax            ; No error, not busy.
  348.     ret
  349. nopcmd    endp
  350.  
  351. ;-------- dos function #5: non-destructive input, no wait ------
  352. ; One-character lookahead into the keyboard buffer.
  353. ; If no characters in buffer, return BUSY; otherwise, get value of first
  354. ; character of buffer, stuff into request header, return DONE.
  355. dosfn5    proc    near
  356.     call    peekchar
  357.     jz    busy
  358.     lds    bx,req_ptr
  359.     mov    [bx+0Dh], al
  360.     jmp    nopcmd            ; No error, not busy.
  361. dosfn5    endp
  362.  
  363. ;-------- dos function #6: input status --------------------------
  364. ; Returns "busy" if no characters waiting to be read.
  365. dosfn6    proc    near
  366.     call    peekchar
  367.     jnz    nopcmd            ; No error, not busy.
  368. dosfn6    endp
  369.  
  370. ;------ busy --------------------------------------------------------
  371. ; corollary to nopcmd
  372. busy    proc    near
  373.     mov    ax, 200h        ; No error, busy.
  374.     ret
  375. busy    endp
  376.  
  377. ;-------- dos function #7: flush input buffer --------------------
  378. ; Clears the IBM keyboard input buffer.  Since it is a circular
  379. ; queue, we can do this without knowing the beginning and end
  380. ; of the buffer; all we need to do is set the tail of the queue
  381. ; equal to the head (as if we had read the entire queue contents).
  382. ; Also resets all the device driver's stuffahead buffers.
  383. dosfn7    proc    near
  384.     mov    ax, abs40
  385.     mov    es, ax
  386.     mov    ax, es:buffer_head    ; clear queue by making the tail
  387.     mov    es:buffer_tail, ax    ; equal to the head
  388.     xor    ax, ax            ; No error, not busy
  389.     mov    fnkey.len, ax        ; Reset the stuffahead buffers.
  390.     mov    cprseq.len, ax
  391.     mov    brkkey.len, ax
  392.     if    fullscreen
  393.     mov    scrnbuf.len, ax
  394.     endif
  395.  
  396.     ret
  397. dosfn7    endp
  398.  
  399.  
  400. ;------ int_29 ----------------------------------------------
  401. ; Int 29 handles DOS quick-access putchar.
  402. ; Last device loaded with attribute bit 4 set gets accessed for
  403. ; single-character writes via int 29h instead of via interrupt.
  404. ; Must preserve all registers.
  405. ; Installed as int 29h by dosfn0 (init).
  406. int_29_buf    db    ?
  407.  
  408. int_29    proc    near
  409.     sti
  410.     push_all
  411.     mov    cx,1
  412.     mov    bx,cs
  413.     mov    es,bx
  414.     mov    ds,bx
  415.     mov    si,offset int_29_buf
  416.     mov    [si],al
  417.     call    dosfn8
  418.     pop_all
  419.     iret
  420. int_29    endp
  421.  
  422. ;------ dosfn8 -------------------------------------------------------
  423. ; Handles writes to the device (with or without verify).
  424. ; Called with
  425. ;  CX     = number of bytes to write
  426. ;  ES:SI = transfer buffer
  427. ;  DS     = CS, so we can access local variables.
  428.  
  429. dosfn8    proc    near
  430.  
  431.     mov    f_cptr_seg, es    ; save segment of char ptr
  432.  
  433.     ; Read the BIOS buffer address/cursor position variables.
  434.     mov    ax,abs40
  435.     mov    ds,ax
  436.     assume    ds:abs40
  437.  
  438.     ; Find current video mode and screen size.
  439.     mov    ax, crt_len
  440.     mov    cs:screen_len, ax
  441.  
  442.     mov    ax,word ptr crt_mode    ; al = crt mode; ah = # of columns
  443.     mov    cs:video_mode, al
  444.     mov    al, crt_rows
  445.     mov    cs:max_coords,ax    ; one based
  446.  
  447.     ; Find current cursor coordinates.
  448.     mov    al,active_page
  449.     mov    cs:cur_page,al
  450.     cbw
  451.     shl    ax,1
  452.     mov    bx,ax
  453.     mov    ax,cursor_posn[bx]
  454.     mov    cs:cur_coords,ax
  455.  
  456.     ; Find video buffer segment address; adjust so ofs is 0; return in AX.
  457.     mov    ax,crt_start
  458.     mov    cs:video_off,ax
  459.     mov    ax,addr_6845        ; 6845 address
  460.  
  461.     mov    dx,cs
  462.     mov    ds,dx
  463.     assume    ds:code
  464.  
  465.     mov    port_6845,ax
  466.     call    xy_to_regs        ; Set DX, DI according to cur_coords.
  467.  
  468.     ; | If in graphics mode, clear old pseudocursor
  469.     ; and set graphics mode flag
  470.     mov    bx,0B800h        ; segment for colour text
  471.     mov    al,video_mode
  472.     cbw
  473.     cmp    al, 4
  474.     jb    d8_no_cp
  475.     mov    bh,0B0h            ; if text, it's a monochrome card..
  476.     cmp    al, 7
  477.     jz    d8_no_cp
  478.     call    pseudocursor        ; write block in xor, make al nonzero
  479. d8_no_cp:
  480.     mov    es,bx
  481.     mov    word ptr video_mode,ax        ; store zero if text mode
  482.     mov    ax, string_attrib
  483.     mov    ds, f_cptr_seg        ; get segment of char ptr
  484.     assume    ds:nothing
  485.     cld                ; make sure we'll increment
  486.  
  487.     ; Get a character, put it on the screen, repeat 'til end of line
  488.     ; or no more characters.
  489.     jcxz    f_loopdone        ; if count = 0, we're already done.
  490.  
  491.     cmp    cs:escvector, 0        ; If in middle of an escape sequence,
  492.     jnz    f_in_escapex        ; jump to escape sequence handler.
  493.  
  494. f_tloop:
  495.  
  496.         ; If not in graphics mode, jump to alternate loop
  497.         ; What a massive kludge!  A better approach would have been
  498.         ; to collect characters for a "write n chars" routine
  499.         ; which would handle both text and graphics modes.
  500.     cmp    cs:gmode_flag,dh
  501.     jnz    f_g_cloop
  502.  
  503. f_t_cloop:
  504.     lodsb                ; get char! (al = ds:[si++])
  505.     cmp    al,28            ; is it a control char?
  506.     jb    f_control        ;  maybe...
  507. f_t_nctl:
  508.     stosw                ; Put Char! (es:[di++] = ax)
  509.     dec    dx            ; count down to end of line
  510.     loopnz    f_t_cloop        ; and go back for more.
  511.     jnz    f_loopdone
  512.  
  513. f_at_eol:                ; at end of line; maybe do a crlf.
  514.     ;----- Handle overrunning right end of screen -------
  515.     ; cx++;             compensate for double loop
  516.     ; if (!wrap_flag) { dx++; di-=2; }
  517.     ; else do_crlf;
  518.     inc    cx
  519.     cmp    cs:wrap_flag, dh
  520.     jz    reverse
  521. feol_wrap:
  522.     ; dx=max_x;            set bx= chars left in line
  523.     ; di -= 2*(max_x);
  524.     ; do_lf
  525.     mov    dl, cs:max_x
  526.     sub    di, dx
  527.     sub    di, dx
  528.     jmp    f_lf
  529.  
  530. f_g_cloop:
  531.     lodsb                ; get char! (al = ds:[si++])
  532.     cmp    al,28            ; is it a control char?
  533.     jb    f_control        ;  maybe...
  534. f_g_nctl:
  535.     call    putchar
  536.     dec    dx            ; count down to end of line
  537.     loopnz    f_g_cloop        ; and go back for more.
  538.     jmp    short f_t_at_eol
  539.  
  540. f_looploop:
  541.     or    dx,dx
  542. f_loop_nocheck:                ; in case we switched into
  543.     loopnz    f_tloop            ; a graphics mode
  544. f_t_at_eol:
  545.     jz    f_at_eol
  546. f_loopdone:
  547.  
  548.     ;--------- All done with write request -----------
  549.     ; DI is cursor address; cursor position in cur_y, dl.
  550.     mov    ax, cs
  551.     mov    ds, ax            ; get our segment back
  552.     assume    ds:code
  553.  
  554.     ; Restore cur_x = max_x - dx
  555.     mov    al, max_x
  556.     sub    al, dl
  557.     mov    cur_x, al
  558.     ; Set cursor position; cursor adr in DI; cursor pos in cur_x,cur_y
  559.     call    set_pseudocursor
  560.     ; Return to DOS.
  561.     xor    ax, ax            ; No error, not busy.
  562.     ret
  563.  
  564. f_in_escapex:
  565.     jmp    f_in_escape
  566.  
  567.  
  568. f_bs:    ;----- Handle backspace -----------------
  569.     ; Moves cursor back one space without erasing.    No wraparound.
  570.     cmp    dl, cs:max_x        ; wrap around to previous line?
  571.     jb    reverse            ; if not, back up
  572.  
  573.     if    wrap_left
  574. fbs_wrap:                ; else do some checks
  575.     cmp    cs:wrap_flag,dh        ; do we want a wrap?
  576.     jz    f_looploop        ; no; leave
  577.     cmp    cs:cur_y,dh        ; top left corner?
  578.     jz    f_looploop        ; if so, ditto
  579.     dec    cs:cur_y
  580.     mov    dl,dh            ; else 0 char left on line
  581.     else
  582.     jmp    f_looploop
  583.     endif
  584. reverse:
  585.     dec    di            ; back up one char & attrib
  586.     dec    di
  587.     inc    dx            ; and note one more char left on line.
  588.     jmp    f_loop_nocheck
  589.  
  590.     assume    ds:nothing
  591.     ;---- handle control characters ----
  592.     ; Note: cur_x is not kept updated in memory, but can be
  593.     ; computed from max_x and dx.
  594.     ; Cur_y is kept updated in memory.
  595. f_control:
  596.     cmp    al,13            ; carriage return?
  597.     jz    f_cr
  598.     cmp    al,10            ; line feed?
  599.     jz    f_lf
  600.     cmp    al,27            ; Is it an escape?
  601.     jz    f_escapex
  602.     cmp    al,8            ; backspace?
  603.     jz    f_bs
  604.     cmp    al,9            ; tab?
  605.     jz    f_tabx
  606.     cmp    al,7            ; bell?
  607.     jz    f_bell
  608.  
  609.     if    avatar
  610.     cmp    al,12            ; AVT clearscreen?
  611.     jz    avt_clsx
  612.     cmp    al,22            ; AVT escape?
  613.     jz    f_avatarx
  614.     cmp    al,16            ; DLE?
  615.     jz    dlex
  616.     cmp    al,25            ; RLE?
  617.     jz    rlex
  618. f_nctl:
  619.     endif
  620.                     ; not a control char
  621.     cmp    cs:gmode_flag,dh
  622.     jnz    f_g_nctl
  623.     jmp    f_t_nctl
  624.  
  625. f_escapex:
  626.     jmp    f_escape
  627.  
  628.     if    avatar
  629. avt_clsx:
  630.     jmp    avt_cls
  631. f_avatarx:
  632.     jmp    f_avatar
  633. dlex:
  634.     jmp    dle
  635. rlex:
  636.     jmp    rle
  637.  
  638.     endif
  639.  
  640. f_bell:    ;----- Handle bell ----------------------
  641.     call    beep            ; >DING<
  642.     jmp    f_looploop        ; Let main loop decrement cx.
  643.  
  644. f_cr:    ;----- Handle carriage return -----------
  645.     ; di -= cur_x<<1;        set di= address of start of line
  646.     ; dx=max_x;            set bx= chars left in line
  647.     mov    al, cs:max_x
  648.     mov    ah,dh
  649.     sub    ax,dx            ; Get cur_x into ax.
  650.     sub    di,ax
  651.     sub    di,ax
  652.     add    dx,ax
  653.     mov    ax,cs:string_attrib    ; restore current attribute
  654.     jmp    f_loop_nocheck        ; and let main loop decrement cx
  655.  
  656. f_tabx:    jmp    f_tab
  657.  
  658.  
  659. f_lf:    ;----- Handle line feed -----------------
  660.     ; if (cur_y >= max_y) scroll;        scroll screen up if needed
  661.     ; else { cur_y++; di += max_x;        else increment Y
  662.  
  663.     mov    al,cs:Cur_y
  664.     sub    al,cs:Max_y        ; do we need to scroll screen?
  665.     jb    flf_noscroll        ;   yes, do it
  666.  
  667.     sub    cs:cur_y,al
  668.     inc    ax
  669.     push    cx
  670.     push    dx
  671.     call    get_blank_attrib    ; ah is attribute to use
  672.     mov    bh,ah            ; color to use on new blank areas
  673.     xor    cx,cx
  674.  
  675.     if    direct_scroll
  676.     cmp    cs:gmode_flag,dh
  677.     jnz    flf_scrollit
  678.  
  679.     mov    ah,dh            ; ax has count of lines to scroll
  680.     mov    cl,cs:max_x        ; cx
  681.     shl    cx,1            ; counted in bytes
  682.     mul    cx            ; multiply it by the overflow
  683.     mov    dx,cx            ; save our screen width
  684.     sub    di,ax            ; bring back pointer scrolled distance
  685.     add    di,dx            ; then add one blank line
  686.     xchg    bx,ax            ; and save it for later
  687.  
  688.     push    ds
  689.     push    si
  690.     push    di
  691.     mov    cx,es
  692.     mov    ds,cx            ; set DS to video segment
  693.     mov    di,cs:[video_off]    ; and SI and DI to start of screen
  694.     mov    si,di
  695.     add    si,bx
  696.     mov    cx,cs:[screen_len]    ; get the length of the screen
  697.     sub    cx,dx            ; less however many lines
  698.     shr    cx,1            ; in words
  699.     rep    movsw            ; scroll it
  700.     mov    cx,bx            ; CX is chars per line
  701.     shr    cx,1
  702.     mov    al," "            ; AH still blank attribute
  703.     rep    stosw            ; clear the bottom line
  704.     pop    di
  705.     pop    si
  706.     pop    ds
  707.     else
  708.     jmp    short flf_scrollit
  709.     endif
  710.     
  711. flf_scroll_done:
  712.     pop    dx
  713.     pop    cx
  714.     mov    ax,cs:string_attrib    ; restore current attribute
  715.     jmp    f_looploop        ; and let main loop decrement cx
  716.  
  717. flf_scrollit:
  718.     mov    dl,al
  719.     add    dx,cs:max_coords
  720.     dec    dx
  721.     xchg    dl,dh
  722.     dec    dx
  723.     mov    ah,06            ; BIOS scroll al lines.
  724.     int    10h            ; call BIOS to scroll a rectangle.
  725.     jmp    short flf_scroll_done
  726.  
  727. flf_noscroll:
  728.     inc    cs:cur_y
  729.     mov    al,cs:Max_x
  730.     mov    ah,dh
  731.     shl    ax,1
  732.     add    di,ax
  733.     mov    ax,cs:string_attrib    ; restore current attribute
  734.     jmp    f_looploop        ; and let main loop decrement cx
  735.  
  736.  
  737. f_tab:    ;----- Handle tab expansion -------------
  738.     push    cx            ; save cx
  739.     ; Calculate number of spaces to output.
  740.     mov    cx,dx
  741.     sub    cl,cs:max_x        ; cx=0-cur_x
  742.     dec    cx            ; raise floor and ceiling
  743.     and    cx,7            ; 0-7
  744.     inc    cx            ; 1-8
  745.  
  746.     ; ah is still current attribute.  Move CX spaces to the screen.
  747.     mov    al, ' '
  748.     cmp    cs:gmode_flag,dh
  749.     jnz    f_tp_lp
  750.     sub    dx, cx            ; update chars-to-eol, maybe set z
  751.     jae    nochop            ; in case width is not a multiple of 8
  752.     add    cx,dx            ; chop the tab so we don't get a neg DX
  753.     xor    dx,dx
  754. nochop:    rep    stosw
  755.     pop    cx            ; restore cx
  756.     jmp    f_loop_nocheck        ; Let main loop decrement cx.
  757.  
  758. ;--------------- graphics mode support -----------------------
  759.  
  760. f_tp_lp:        ; graphics mode- call putc to put the char
  761.     call    putchar
  762.     dec    dx            ; go to next cursor position
  763.     loopnz    f_tp_lp
  764.     pop    cx
  765.     jmp    f_loop_nocheck
  766.  
  767.  
  768. ;---- set_pseudocursor ------------
  769. ; If in graphics mode, set pseudocursor, else set real cursor.
  770. ; Destroys DS!!!!
  771.     assume    ds:code
  772.  
  773. set_pseudocursor      proc      near
  774.     cmp    gmode_flag,dh
  775.     jnz    pseudocursor
  776.  
  777. SET_CURS:    ; Write directly to 6845 cursor address register.
  778.     mov    bx,di
  779.     shr    bx,1            ; convert word index to byte index
  780.  
  781.     mov    dx,Port_6845
  782.     mov    al,0Eh
  783.     out    dx,al
  784.     hold
  785.  
  786.     inc    dx
  787.     mov    al, bh
  788.     out    dx, al
  789.     hold
  790.  
  791.     dec    dx
  792.     mov    al, 0fh
  793.     out    dx, al
  794.     hold
  795.  
  796.     inc    dx
  797.     mov    al, bl
  798.     out    dx, al
  799.  
  800.     mov    al,cur_page
  801.     cbw
  802.     shl    ax,1
  803.     mov    bx,ax
  804.     mov    ax,cur_coords
  805.  
  806.     ; Set cursor position in low memory.
  807.     mov    dx, abs40
  808.     mov    ds, dx
  809.     assume    ds:abs40
  810.  
  811.     mov    cursor_posn[bx],ax
  812.     ret
  813.  
  814. set_pseudocursor      endp
  815.  
  816.     assume    ds:code
  817.  
  818. ;---- pseudocursor --------------------------------------------------
  819. ; If pseudo_flag is true, writes a color 15 block in XOR at the
  820. ; current cursor location, and sets cursor position.
  821. ; Otherwise, just sets cursor position.
  822.  
  823. pseudocursor    proc    near
  824.     cmp    pseudo_flag, 0
  825.     jnz    psc_pseudo
  826.     push    dx            ; flag off - don't draw
  827.     mov    dx, cur_coords        ; get X & Y into DX
  828.     mov    bh, cur_page        ; supposed to be zero in graph modes?
  829.     mov    ah, 2            ; chose "Set Cursor Position"
  830.     int    10h            ; call ROM BIOS
  831.     pop    dx
  832.     ret
  833.  
  834. psc_pseudo:
  835.     mov    ax, 8F16h    ; xor, color 15, ^V (small block)
  836.                 ; fall through to putchar
  837. pseudocursor    endp
  838.  
  839.  
  840. ;---- putchar ------------------------------------------------
  841. ; Writes char AL, attribute AH to screen at (max_x+1-dl), cur_y.
  842. ; On entry, registers set up as per xy_to_regs.
  843. ; Preserves all registers.
  844.     assume    ds:nothing
  845.  
  846. putchar proc    near
  847.     push    ax
  848.     push    bx
  849.     push    cx
  850.     push    dx
  851.     ; 1. Set cursor position.
  852.  
  853.     sub    dl, cs:max_x
  854.     neg    dx
  855.  
  856.     mov    dh, cs:cur_y        ; get X & Y into DX
  857.     mov    bh, cs:cur_page        ; choose page
  858.     mov    bl,ah            ; attribute in BL for part 2.
  859.     mov    ah, 2            ; chose "Set Cursor Position"
  860.     int    10h            ; call ROM BIOS
  861.     ; 2. Write char & attribute.
  862.     mov    cx,1
  863.     mov    ah,9
  864.     int    10h
  865.     pop    dx
  866.     pop    cx
  867.     pop    bx
  868.     pop    ax
  869.     ret
  870. putchar endp
  871.  
  872. ;--------------- end of graphics mode support --------------------
  873.  
  874. dosfn8    endp
  875.  
  876. ;--- get_blank_attrib ------------------------------------------------
  877. ; Determine new attribute and character for a new blank region.
  878. ; Use current attribute, just disallow blink and underline.
  879. ; (Pretty strange way to do it.  Might want to disallow rev vid, too.)
  880. ; Returns result in AH, preserves all other registers.
  881. get_blank_attrib    proc    near
  882.     xor    ah,ah
  883.     cmp    cs:gmode_flag,ah
  884.     jnz    gb_aok            ; if graphics mode, 0 is bkgnd
  885.     mov    ah, cs:cur_attrib
  886.     and    ah,7fh            ; disallow blink
  887.     cmp    cs:video_mode,7        ; monochrome?
  888.     jne    gb_aok
  889.     cmp    ah,1            ; underline?
  890.     jne    gb_aok
  891.     mov    ah,7            ; yep- set it to normal.
  892. gb_aok: ret
  893. get_blank_attrib    endp
  894.  
  895. ;---- beep ------------------------------------------------------
  896. ; Beep speaker; period given by beep_div, duration by beep_len.
  897. ; Preserves CX and DX
  898.  
  899. beep_div    equ    1300        ; fairly close to IBM beep
  900. beep_len    equ    2        ; 2/18 sec- shorter than IBM
  901.  
  902. beep    proc    near
  903.     push    cx
  904.     push    dx
  905.  
  906.     mov    al,10110110b        ; select 8253
  907.     mov    dx,43h            ; control port address
  908.     out    dx,al
  909.     dec    dx            ; timer 2 address
  910.     mov    ax, beep_div
  911.     out    dx,al            ; low byte of divisor
  912.     mov    al,ah
  913.     out    dx,al            ; high byte of divisor
  914.     mov    dx,61h
  915.     in    al,dx            ; get current value of control bits
  916.     push    ax
  917.     or    al, 3
  918.     out    dx,al            ; turn speaker on
  919.  
  920.     ; Wait for desired duration by monitoring time-of-day 18 Hz clock
  921.     push    ds
  922.     mov    ax,abs40
  923.     mov    ds,ax
  924.     assume    ds:abs40
  925.  
  926.     mov    bx, timer_low
  927.     mov    cx, -1            ; emergency, in case clock dead
  928.  
  929. beeplp: mov    ax, timer_low
  930.     sub    ax,bx
  931.     cmp    ax, beep_len
  932.     jg    beepover
  933.     loop    beeplp
  934. beepover:
  935.  
  936.     pop    ds
  937.     assume    ds:nothing
  938.     pop    ax
  939.     and    al, not 3        ; turn speaker off
  940.     out    dx,al
  941.     pop    dx
  942.     pop    cx
  943.     ret
  944. beep    endp
  945.  
  946. CODE    ends
  947.     end
  948.