home *** CD-ROM | disk | FTP | other *** search
/ Hall of Fame / HallofFameCDROM.cdr / util2 / zansi.lzh / ZANSI.ASM < prev    next >
Assembly Source File  |  1986-11-29  |  33KB  |  950 lines

  1. ;--- zansi.asm ----------------------------------------------------------
  2. ; Zephyr ANSI terminal driver.
  3. ;    Copyright (C) 1986, Thomas Hanlin III, Springfield VA.
  4. ;    Based on original code for NANSI by Daniel Kegel, Pasadena, CA.
  5. ;------------------------------------------------------------------------
  6.  
  7.         ; from zansi_f.asm
  8.         extrn   f_escape:near, f_in_escape:near
  9.  
  10.         ; from zansi_p.asm
  11.         extrn   param_end:word, redef_end:word
  12.  
  13.         ; from zansi_i.asm
  14.         extrn   dosfn0:near
  15.  
  16.         ; to zansi_p.asm
  17.         public  f_loopdone
  18.         public  f_not_ansi
  19.         public  f_ansi_exit
  20.  
  21.         ; to both zansi_p.asm and zansi_f.asm
  22.         public  cur_x, cur_y, max_x, cur_attrib
  23.  
  24.         ; to zansi_f.asm
  25.         public  xy_to_regs, get_blank_attrib
  26.         public  port_6845
  27.         public  wrap_flag
  28.         public  cur_parm_ptr
  29.         public  cur_coords, saved_coords, max_y
  30.         public  escvector, string_term
  31.         public  cpr_esc, cprseq
  32.         public  video_mode
  33.         public  lookup
  34.  
  35.         ; to zansi_i.asm
  36.         public  req_ptr, break_handler
  37.         public  int_29
  38.  
  39.         ; to all modules
  40.  
  41. keybuf  struc                           ; Used in getchar
  42. len     dw      ?
  43. adr     dw      ?
  44. keybuf  ends
  45.  
  46.  
  47. ABS40   segment at 40h
  48.         org     1ah
  49. buffer_head     dw      ?       ; Used in 'flush input buffer' dos call.
  50. buffer_tail     dw      ?
  51.  
  52.         org     49h
  53. crt_mode        db      ?
  54. crt_cols        dw      ?
  55. crt_len         dw      ?
  56. crt_start       dw      ?
  57. cursor_posn     dw      8 dup (?)
  58. cursor_mode     dw      ?
  59. active_page     db      ?
  60. addr_6845       dw      ?
  61. crt_mode_set    db      ?       ; = 7 only if monochrome display adaptor
  62. crt_palette     db      ?
  63.         org     6ch
  64. timer_low       dw      ?       ; low word of time-of-day counter (18.2 hz)
  65.  
  66. ABS40   ends
  67.  
  68.  
  69. CODE    segment byte public 'CODE'
  70. assume  cs:code, ds:code
  71.  
  72.         ; Device Driver Header
  73.  
  74.         org     0
  75.  
  76.         dd      -1                      ; next device
  77.         dw      8013h                   ; attributes
  78.         dw      strategy                ; request header pointer entry
  79.         dw      interrupt               ; request entry point
  80.         db      'CON', 5 dup(' ')       ; device name (8 char)
  81.  
  82.  
  83. ;----- variable area --------------------
  84. req_ptr label   dword
  85. req_off dw      ?
  86. req_seg dw      ?
  87.  
  88. wrap_flag       db      1       ; 0 = no wrap past line end
  89. escvector       dw      0       ; state vector of ESCape sequencer
  90. video_mode      db      3       ; ROM BIOS video mode (2=BW, 3=color)
  91. max_y           db      24
  92. max_cur_x       label   word    ; used to get both max & cur at once
  93. max_x           db      79      ; line width (79 for 80x25 modes)
  94. cur_coords      label   word
  95. cur_x           db      0       ; cursor position (0 = left edge)
  96. cur_y           db      0       ;                 (0 = top edge)
  97. saved_coords    dw      ?       ; holds XY after a SCP escape sequence
  98. string_term     db      0       ; either escape or double quote
  99. cur_attrib      db      7       ; current char attributes
  100. cur_page        db      0       ; current display page
  101. video_seg       dw      ?       ; segment of video card
  102. f_cptr_seg      dw      ?       ; part of fastout write buffer pointer
  103. cur_parm_ptr    dw      ?       ; last byte of parm area now used
  104. port_6845       dw      ?       ; port address of 6845 card
  105.  
  106. brkkeybuf       db      3       ; control C
  107. fnkeybuf        db      ?       ; holds second byte of fn key codes
  108. cpr_buf         db      8 dup (?), '['
  109. cpr_esc         db      1bh     ; descending buffer for cpr function
  110.  
  111. ; following four keybufs hold information about input
  112. ; Storage order determines priority- since the characters making up a function
  113. ; key code must never be separated (say, by a Control-Break), they have the
  114. ; highest priority, and so on.  Keyboard keys (except ctrl-break) have the
  115. ; lowest priority.
  116.  
  117. fnkey   keybuf  <0, fnkeybuf>   ; fn key string (0 followed by scan code)
  118. cprseq  keybuf  <0>             ; CPR string (ESC [ y;x R)
  119. brkkey  keybuf  <0, brkkeybuf>  ; ^C
  120. xlatseq keybuf  <0>             ; keyboard reassignment string
  121.  
  122. ;------ xy_to_regs --------------------------------------------
  123. ; on entry: x in cur_x, y in cur_y
  124. ; on exit:  dx = chars left on line, di = address
  125. ; Alters ax, bx.
  126. xy_to_regs      proc    near
  127.         ; Find number of chars til end of line, keep in DX
  128.         mov     ax,max_cur_x
  129.         mov     bl,ah
  130.         xor     bh,bh
  131.         cbw
  132.         mov     dx,ax
  133.         sub     dx,bx
  134.         inc     dx                      ; DX is # of chars till EOL
  135.         ; Calculate DI = current address in text buffer
  136.         inc     ax                      ; AL = max_x
  137.         mul     cur_y
  138.         add     ax,bx                   ; AX is # of chars into buffer
  139.         shl     ax,1
  140.         mov     di,ax                   ; DI is now offset of cursor.
  141.         ret
  142. xy_to_regs      endp
  143.  
  144.  
  145. ;------- dos_fn_tab -------------
  146. ; This table is used in "interrupt" to call the routine that handles
  147. ; the requested function.
  148.  
  149. max_cmd equ     12
  150. dos_fn_tab:
  151.         dw      dosfn0, nopcmd, nopcmd, badcmd, dosfn4, dosfn5, dosfn6
  152.         dw      dosfn7, dosfn8, dosfn8, nopcmd, nopcmd
  153.  
  154. ;------- strategy ----------------------------------------------------
  155. ; DOS calls strategy with a request which is to be executed later.
  156. ; Strategy just saves the request.
  157.  
  158. strategy        proc    far
  159.         mov     cs:req_off,BX
  160.         mov     cs:req_seg,ES
  161.         ret
  162. strategy        endp
  163.  
  164. ;------ interrupt -----------------------------------------------------
  165. ; This is where the request handed us during "strategy" is
  166. ; actually carried out.
  167. ; Calls one of 12 subroutines depending on the function requested.
  168. ; Each subroutine returns with exit status in AX.
  169.  
  170. interrupt       proc    far
  171.         sti
  172.         push    ax
  173.         push    cx
  174.         push    dx
  175.         push    bx
  176.         push    bp
  177.         push    si
  178.         push    di
  179.         push    ds
  180.         push    es
  181.  
  182.         ; Read requested function information into registers
  183.         lds     bx,cs:req_ptr
  184.         mov     al,2[BX]                ; al = function code
  185.         les     si,14[BX]               ; ES:SI = input/output buffer addr
  186.         mov     cx,18[BX]               ; cx = input/output byte count
  187.  
  188.         cmp     al,max_cmd
  189.         ja      unk_command             ; too big, exit with error code
  190.  
  191.         mov     bx,ax
  192.         shl     bx,1                    ; form index to table of words
  193.         mov     ax,cs
  194.         mov     ds,ax
  195.         call    word ptr dos_fn_tab[bx]
  196. int_done:
  197.         lds     bx,cs:req_ptr           ; report status
  198.         or      ax,100h                 ; (always set done bit upon exit)
  199.         mov     3[bx],ax
  200.  
  201.         pop     ES                      ; restore caller's registers
  202.         pop     DS
  203.         pop     di
  204.         pop     si
  205.         pop     bp
  206.         pop     bx
  207.         pop     dx
  208.         pop     cx
  209.         pop     ax
  210.         ret                             ; return to DOS.
  211.  
  212. unk_command:
  213.         call    badcmd
  214.         jmp     int_done
  215.  
  216. interrupt       endp
  217.  
  218. ;----- BIOS break handler -----------------------------------------
  219. ; Called by BIOS when Control-Break is hit (vector was set up in Init).
  220. ; Simply notes that a break was hit.  Flag is checked during input calls.
  221.  
  222. break_handler   proc
  223.         mov     cs:brkkey.len, 1
  224.         iret
  225. break_handler   endp
  226.  
  227.  
  228. ;------ badcmd -------------------------------------------------------
  229. ; Invalid function request by DOS.
  230. badcmd  proc    near
  231.         mov     ax, 813h                ; return "Error: invalid cmd"
  232.         ret
  233. badcmd  endp
  234.  
  235.  
  236. ;------ nopcmd -------------------------------------------------------
  237. ; Unimplemented or dummy function request by DOS.
  238. nopcmd  proc    near
  239.         xor     ax, ax                  ; No error, not busy.
  240.         ret
  241. nopcmd  endp
  242.  
  243. ;------- dos function #4 -----------------------------------------------
  244. ; Reads CX characters from the keyboard, places them in buffer at ES:SI.
  245. dosfn4  proc    near
  246.         jcxz    dos4done
  247.         mov     di,si
  248. dos4lp: push    cx
  249.         call    getchar
  250.         pop     cx
  251.         stosb
  252.         loop    dos4lp
  253. dos4done:
  254.         xor     ax,ax                   ; No error, not busy.
  255.         ret
  256. dosfn4  endp
  257.  
  258. ;-------- dos function #5: non-destructive input, no wait ------
  259. ; One-character lookahead into the keyboard buffer.
  260. ; If no characters in buffer, return BUSY; otherwise, get value of first
  261. ; character of buffer, stuff into request header, return DONE.
  262. dosfn5  proc    near
  263.         call    peekchar
  264.         jz      dos5_busy
  265.         lds     bx,req_ptr
  266.         mov     [bx+0Dh], al
  267.         xor     ax, ax                  ; No error, not busy.
  268.         ret
  269. dos5_busy:
  270.         mov     ax, 200h                ; No error, busy.
  271.         ret
  272.  
  273. dosfn5  endp
  274.  
  275. ;-------- dos function #6: input status --------------------------
  276. ; Returns "busy" if no characters waiting to be read.
  277. dosfn6  proc    near
  278.         call    peekchar
  279.         mov     ax, 200h                ; No error, busy.
  280.         jz      dos6_exit
  281.         xor     ax, ax                  ; No error, not busy.
  282. dos6_exit:
  283.         ret
  284. dosfn6  endp
  285.  
  286. ;-------- dos function #7: flush input buffer --------------------
  287. ; Clears the IBM keyboard input buffer.  Since it is a circular
  288. ; queue, we can do this without knowing the beginning and end
  289. ; of the buffer; all we need to do is set the tail of the queue
  290. ; equal to the head (as if we had read the entire queue contents).
  291. ; Also resets all the device driver's stuffahead buffers.
  292. dosfn7  proc    near
  293.         mov     ax, abs40
  294.         mov     es, ax
  295.         mov     ax, es:buffer_head      ; clear queue by making the tail
  296.         mov     es:buffer_tail, ax      ; equal to the head
  297.         xor     ax, ax                  ; no error, not busy
  298.         mov     fnkey.len, ax           ; Reset the stuffahead buffers.
  299.         mov     cprseq.len, ax
  300.         mov     brkkey.len, ax
  301.         mov     xlatseq.len, ax
  302.         ret
  303. dosfn7  endp
  304.  
  305. ;------ int_29 ----------------------------------------------
  306. ; Int 29 handles DOS quick-access putchar.
  307. ; Last device loaded with attribute bit 4 set gets accessed for
  308. ; single-character writes via int 29h instead of via interrupt.
  309. ; Must preserve all registers.
  310. ; Installed as int 29h by dosfn0 (init).
  311. int_29_buf      db      ?
  312.  
  313. int_29  proc    near
  314.         sti
  315.         push    ds
  316.         push    es
  317.         push    ax
  318.         push    cx
  319.         push    dx
  320.         push    bx
  321.         push    bp
  322.         push    si
  323.         push    di
  324.         mov     cx,1
  325.         mov     bx,cs
  326.         mov     es,bx
  327.         mov     ds,bx
  328.         mov     si,offset int_29_buf
  329.         mov     [si],al
  330.         call    dosfn8
  331.         pop     di
  332.         pop     si
  333.         pop     bp
  334.         pop     bx
  335.         pop     dx
  336.         pop     cx
  337.         pop     ax
  338.         pop     es
  339.         pop     ds
  340.         iret
  341. int_29  endp
  342.  
  343. ;------ dosfn8 -------------------------------------------------------
  344. ; Handles writes to the device (with or without verify).
  345. ; Called with
  346. ;  CX    = number of bytes to write
  347. ;  ES:SI = transfer buffer
  348. ;  DS    = CS, so we can access local variables.
  349.  
  350. dosfn8  proc    near
  351.  
  352.         mov     f_cptr_seg, es  ; save segment of char ptr
  353.  
  354.         ; Read the BIOS buffer address/cursor position variables.
  355.         mov     ax,abs40
  356.         mov     ds,ax
  357.         assume  ds:abs40
  358.  
  359.         ; Find current video mode and screen size.
  360.         mov     ax,word ptr crt_mode    ; al = crt mode; ah = # of columns
  361.         mov     cs:video_mode, al
  362.         dec     ah                      ; ah = max column
  363.         mov     cs:max_x, ah
  364.  
  365.         ; Find current cursor coordinates.
  366.         mov     al,active_page
  367.         cbw
  368.         shl     ax,1
  369.         mov     bx,ax
  370.         mov     ax,cursor_posn[bx]
  371.         mov     cs:cur_coords,AX
  372.  
  373.         ; Find video buffer segment address; adjust so ofs is 0; return in AX.
  374.         ; DS is abs40.
  375.         mov     ax,addr_6845            ; 6845 address
  376.         mov     cs:port_6845,ax
  377.  
  378.         mov     ax,cs
  379.         mov     ds,ax
  380.         assume  ds:code
  381.  
  382.         mov     ax,0B000h               ; assume it's a monochrome card...
  383.         CMP     video_mode,7
  384.         jz      d8_gots
  385.         mov     ah,0B8h                 ; but if not mode 7, it's color.
  386. d8_gots:
  387.         mov     video_seg,ax
  388.         mov     es,ax
  389.         call    xy_to_regs              ; Set DX, DI according to cur_coords.
  390.  
  391.         ; | If in graphics mode, clear old pseudocursor
  392.         cmp     cs:video_mode, 4
  393.         jb      d8_no_cp
  394.         cmp     cs:video_mode, 7
  395.         jz      d8_no_cp
  396.         call    pseudocursor            ; write block in xor
  397. d8_no_cp:
  398.         mov     ah, cur_attrib
  399.         mov     ds, f_cptr_seg          ; get segment of char ptr
  400.         assume  ds:nothing
  401.         cld                             ; make sure we'll increment
  402.  
  403.         ; Get a character, put it on the screen, repeat 'til end of line
  404.         ; or no more characters.
  405.         jcxz    f_loopdone              ; if count = 0, we're already done.
  406.         cmp     cs:escvector, 0         ; If in middle of an escape sequence,
  407.         jnz     f_in_escapex            ; jump to escape sequence handler.
  408.  
  409. f_tloop: ; If not in graphics mode, jump to alternate loop
  410.          ; What a massive kludge!  A better approach would have been
  411.          ; to collect characters for a "write n chars" routine
  412.          ; which would handle both text and graphics modes.
  413.         cmp     cs:video_mode, 4
  414.         jb      f_t_cloop
  415.         cmp     cs:video_mode, 7
  416.         jz      f_t_cloop
  417.  
  418.  
  419. f_g_cloop:
  420.         lodsb                           ; get char! (al = ds:[si++])
  421.         cmp     al,28                   ; is it a control char?
  422.         jb      f_control               ;  maybe...
  423. f_g_nctl:
  424.         call    putchar
  425.         dec     dx                      ; count down to end of line
  426.         loopnz  f_g_cloop               ; and go back for more.
  427.         jmp     short f_t_at_eol
  428.  
  429. f_t_cloop:
  430.         lodsb                           ; get char! (al = ds:[si++])
  431.         cmp     al,28                   ; is it a control char?
  432.         jb      f_control               ;  maybe...
  433. f_t_nctl:
  434.         stosw                           ; Put Char! (es:[di++] = ax)
  435.         dec     dx                      ; count down to end of line
  436.         loopnz  f_t_cloop               ; and go back for more.
  437.         jz      f_at_eol                ; at end of line; maybe do a crlf.
  438.         jmp     short f_loopdone
  439.  
  440. f_looploop:
  441. f_ansi_exit:                            ; in case we switched into
  442.         loopnz  f_tloop                 ; a graphics mode
  443. f_t_at_eol:
  444.         jz      f_at_eol
  445.  
  446. f_loopdone:
  447.  
  448.         ;--------- All done with write request -----------
  449.         ; DI is cursor address; cursor position in cur_y, dl.
  450.         mov     ax, cs
  451.         mov     ds, ax                  ; get our segment back
  452.         assume  ds:code
  453.  
  454.         ; Restore cur_x = max_x - dx + 1.
  455.         mov     al, max_x
  456.         inc     al
  457.         sub     al, dl
  458.         mov     cur_x, al
  459.         ; Set cursor position; cursor adr in DI; cursor pos in cur_x,cur_y
  460.         call    set_pseudocursor
  461.         ; Return to DOS.
  462.         xor     ax, ax                  ; No error, not busy.
  463.         ret
  464.  
  465.         ;---- handle control characters ----
  466.         ; Note: cur_x is not kept updated in memory, but can be
  467.         ; computed from max_x and dx.
  468.         ; Cur_y is kept updated in memory.
  469. f_control:
  470.         cmp     al,13                   ; carriage return?
  471.         jz      f_cr
  472.         cmp     al,10                   ; line feed?
  473.         jz      f_lf
  474.         cmp     al,27                   ; Is it an escape?
  475.         jz      f_escapex
  476.         cmp     al,8                    ; backspace?
  477.         jz      f_bs
  478.         cmp     al,9                    ; tab?
  479.         jz      f_tabx
  480.         cmp     al,7                    ; bell?
  481.         jz      f_bell
  482. f_not_ansi:                             ; not a control char
  483.         cmp     cs:video_mode, 4
  484.         jb      f_t_nctl
  485.         cmp     cs:video_mode, 7
  486.         jz      f_t_nctl
  487.         jmp     f_g_nctl
  488.  
  489. f_tabx: jmp     f_tab
  490. f_escapex:
  491.         jmp     f_escape
  492. f_in_escapex:
  493.         jmp     f_in_escape
  494.  
  495. f_bs:   ;----- Handle backspace -----------------
  496.         ; Moves cursor back one space without erasing.  No wraparound.
  497.         cmp     dl, cs:max_x            ; wrap around to previous line?
  498.         ja      fbs_wrap                ; yep; disallow it.
  499.         dec     di                      ; back up one char & attrib
  500.         dec     di
  501.         inc     dx                      ; and note one more char left on line.
  502. fbs_wrap:
  503.         jmp     f_looploop
  504.  
  505. f_bell: ;----- Handle bell ----------------------
  506.         call    beep
  507.         or      al, al                  ; clear z
  508.         jmp     f_looploop              ; Let main loop decrement cx.
  509.  
  510. f_cr:   ;----- Handle carriage return -----------
  511.         ; di -= cur_x<<1;               set di= address of start of line
  512.         ; dx=max_x+1;                   set bx= chars left in line
  513.         mov     al, cs:max_x
  514.         cbw
  515.         inc     ax
  516.         sub     al,dl                   ; Get cur_x into ax.
  517.         sub     di,ax
  518.         sub     di,ax
  519.         mov     dl,cs:max_x             ; Full line ahead of us.
  520.         inc     dx
  521.         mov     ah,cs:cur_attrib        ; restore current attribute
  522.         or      al,1                    ; clear z
  523.         jmp     f_looploop              ; and let main loop decrement cx
  524.  
  525. f_at_eol:
  526.         ;----- Handle overrunning right end of screen -------
  527.         ; cx++;                         compensate for double loop
  528.         ; if (!wrap_flag) { dx++; di-=2; }
  529.         ; else do_crlf;
  530.         inc     cx
  531.         test    cs:wrap_flag, 1
  532.         jnz     feol_wrap
  533.         dec     di
  534.         dec     di
  535.         inc     dx
  536.         jmp     f_looploop
  537. feol_wrap:
  538.         ; dx=max_x+1;                   set bx= chars left in line
  539.         ; di -= 2*(max_x+1);
  540.         ; do_lf
  541.         mov     dl, cs:max_x
  542.         inc     dx
  543.         sub     di, dx
  544.         sub     di, dx
  545.         ; fall thru to line feed routine
  546.  
  547. f_lf:   ;----- Handle line feed -----------------
  548.         ; if (cur_y >= max_y) scroll;           scroll screen up if needed
  549.         ; else { cur_y++; di += max_x<<1;       else increment Y
  550.  
  551.         mov     al, cs:max_y
  552.         cmp     cs:cur_y, al
  553.         jb      flf_noscroll
  554.         call    scroll_up               ; preserves bx,cx,dx,si,di
  555.         jmp     short flf_done
  556. flf_noscroll:
  557.         inc     cs:cur_y
  558.         mov     al, cs:max_x
  559.         cbw
  560.         inc     ax
  561.         shl     ax,1
  562.         add     di, ax
  563. flf_done:
  564.         mov     ah, cs:cur_attrib       ; restore current attribute
  565.         or      al,1                    ; clear z
  566.         jmp     f_looploop              ; and let main loop decrement cx
  567.  
  568. f_tab:  ;----- Handle tab expansion -------------
  569.         ; Get cur_x into al.
  570.         mov     al, cs:max_x
  571.         inc     al
  572.         sub     al, dl
  573.         ; Calculate number of spaces to output.
  574.         push    cx                      ; save cx
  575.         mov     cl, al                  ; get zero based x coordinate
  576.         and     cx,7
  577.         neg     cl
  578.         add     cl,8                    ; 0 -> 8, 1 -> 8, ... 7 -> 1
  579.         sub     dx, cx                  ; update chars-to-eol, maybe set z
  580.         pushf                           ; || save Z for main loop
  581.         ; ah is still current attribute.  Move CX spaces to the screen.
  582.         mov     al, ' '
  583.         cmp     cs:video_mode, 4
  584.         jb      F_SPC_MV
  585.         cmp     cs:video_mode, 7
  586.         jnz     f_tab_putc
  587. F_SPC_MV:
  588.         REP     STOSW
  589.         popf                            ; || restore Z flag for main loop test
  590.         pop     cx                      ; restore cx
  591.         jmp     f_looploop              ; Let main loop decrement cx.
  592.  
  593. ;--------------- graphics mode support -----------------------
  594.  
  595. f_tab_putc:     ; graphics mode- call putc to put the char
  596.         add     dx, cx                  ; move back to start of tab
  597. f_tp_lp:
  598.         call    putchar
  599.         dec     dx                      ; go to next cursor position
  600.         loop    f_tp_lp
  601.         popf                            ; Z set if wrapped around EOL
  602.         pop     cx
  603.         jmp     f_looploop
  604.  
  605.  
  606. ;---- putchar ------------------------------------------------
  607. ; Writes char AL, attribute AH to screen at (max_x+1-dl), cur_y.
  608. ; On entry, registers set up as per xy_to_regs.
  609. ; Preserves all registers.
  610. putchar proc    near
  611.         push    dx
  612.         push    cx
  613.         push    bx
  614.         push    ax
  615.         ; 1. Set cursor position.
  616.         mov     al, cs:max_x
  617.         inc     al
  618.         sub     al,dl
  619.         mov     cs:cur_x, al
  620.         mov     dx, cs:cur_coords       ; get X & Y into DX
  621.         xor     bx, bx                  ; choose dpy page 0
  622.         mov     ah, 2                   ; chose "Set Cursor Position"
  623.         int     10h                     ; call ROM BIOS
  624.         ; 2. Write char & attribute.
  625.         mov     cx,1
  626.         pop     ax                      ; get char in AL
  627.         push    ax
  628.         mov     bl,ah                   ; attribute in BL
  629.         xor     bh,bh
  630.         mov     ah,9
  631.         int     10h
  632.         pop     ax
  633.         pop     bx
  634.         pop     cx
  635.         pop     dx
  636.         ret
  637. putchar endp
  638.  
  639. ;---- set_pseudocursor ------------
  640. ; If in graphics mode, set pseudocursor, else set real cursor.
  641. ; Destroys DS!!!!
  642.  
  643. set_pseudocursor        proc    near
  644.         cmp     cs:video_mode, 4
  645.         jb      SET_CURS
  646.         cmp     cs:video_mode, 7
  647.         jnz     pseudocursor
  648.  
  649. SET_CURS:    ; Write directly to 6845 cursor address register.
  650.         mov     bx,di
  651.         shr     bx,1                   ; convert word index to byte index
  652.  
  653.         mov     dx,Port_6845
  654.         mov     al,0Eh
  655.         out     dx,al
  656.  
  657.         jmp     $+2
  658.         inc     dx
  659.         mov     al, bh
  660.         out     dx, al
  661.  
  662.         jmp     $+2
  663.         dec     dx
  664.         mov     al, 0fh
  665.         out     dx, al
  666.  
  667.         jmp     $+2
  668.         inc     dx
  669.         mov     al, bl
  670.         out     dx, al
  671.  
  672.         ; Set cursor position in low memory.
  673.         assume  ds:abs40
  674.         mov     ax, abs40
  675.         mov     ds, ax
  676.         mov     ax, cs:cur_coords
  677.         mov     cursor_posn,ax
  678.         ret
  679.  
  680.         assume  ds:code
  681. set_pseudocursor        endp
  682.  
  683.  
  684. ;---- pseudocursor --------------------------------------------------
  685. ; Writes a color 15 block in XOR at the current cursor location.
  686. ; Preserves DS, ES, BX, CX, DX, SI, DI.
  687. ; Should be disableable- the pseudocursor slows down single-char
  688. ; writes by a factor of three.
  689. pseudocursor    proc    near
  690.         mov     ax, 8f16h       ; xor, color 15, ^V (small block)
  691.         call    putchar
  692.         ret
  693. pseudocursor    endp
  694.  
  695. ;--------------- end of graphics mode support --------------------
  696.  
  697. dosfn8  endp
  698.  
  699. ;--- get_blank_attrib ------------------------------------------------
  700. ; Determine new attribute and character for a new blank region.
  701. ; Use current attribute, just disallow blink and underline.
  702. ; (Pretty strange way to do it.  Might want to disallow rev vid, too.)
  703. ; Returns result in AH, preserves all other registers.
  704. get_blank_attrib        proc    near
  705.         xor     ah,ah
  706.         cmp     cs:video_mode, 4
  707.         jb      GB_TX
  708.         cmp     cs:video_mode, 7
  709.         jnz     gb_aok                  ; if graphics mode, 0 is bkgnd
  710. GB_TX:
  711.         mov     ah, cs:cur_attrib
  712.         and     ah,7fh                  ; disallow blink
  713.         cmp     cs:video_mode,7         ; monochrome?
  714.         jne     gb_aok
  715.         cmp     ah,1                    ; underline?
  716.         jne     gb_aok
  717.         mov     ah,7                    ; yep- set it to normal.
  718. gb_aok: ret
  719. get_blank_attrib        endp
  720.  
  721.  
  722. ;---- scroll_up ---------------------------------------------------
  723. ; Scroll screen up- preserves ax, bx, cx, dx, si, di, ds, es.
  724. ; Moves screen up 1 line, fills the last line with blanks.
  725. ; Attribute of blanks is the current attribute sans blink and underline.
  726.  
  727. scroll_up       proc    near
  728.         push    ax
  729.         push    bx
  730.         push    cx
  731.         push    dx
  732.  
  733.         call    get_blank_attrib
  734.         mov     bh,ah                   ; color to use on new blank areas
  735.         mov     al,1                    ; AL is number of lines to scroll.
  736.         mov     ah,6                    ; BIOS: scroll up
  737.         xor     cx,cx
  738.         mov     dl,cs:max_x
  739.         mov     dh,cs:max_y
  740.         int     10h                     ; call BIOS to scroll a rectangle.
  741.  
  742.         pop     dx
  743.         pop     cx
  744.         pop     bx
  745.         pop     ax
  746.         ret
  747. scroll_up       endp
  748.  
  749. ;---- lookup -----------------------------------------------
  750. ; Called by getchar, peekchar, and key to see if a given key has
  751. ; been redefined.
  752. ; Sets AH to zero if AL is not zero (i.e. if AX is not a function key).
  753. ; Returns with Z cleared if no redefinition; otherwise,
  754. ; Z is set, SI points to redefinition string, CX is its length.
  755. ; Preseves AL, all but CX and SI.
  756. ; Redefinition table organization:
  757. ;  Strings are stored in reversed order, first char last.
  758. ;  The word following the string is the character to be replaced;
  759. ;  the next word is the length of the string sans header.
  760. ; param_end points to the last byte used by the parameter buffer;
  761. ; redef_end points to the last word used by the redef table.
  762.  
  763. lookup  proc    near
  764.         mov     si, redef_end           ; Start at end of table, move down.
  765.         or      al, al
  766.         jz      lu_lp
  767.         xor     ah,ah                   ; clear extraneous scan code
  768. lu_lp:  cmp     si, param_end
  769.         jbe     lu_notfound             ; If below redef table, exit.
  770.         mov     cx,[si]
  771.         cmp     ax,[si-2]               ; are you my mommy?
  772.         jz      lu_gotit
  773.         sub     si,4
  774.         sub     si,cx                   ; point to next header
  775.         jmp     lu_lp
  776. lu_notfound:
  777.         or      si,si                   ; clear Z
  778.         ret
  779. lu_gotit:
  780.         sub     si,2
  781.         sub     si,cx                   ; point to lowest char in memory
  782.         cmp     al,al                   ; set Z
  783.         ret
  784. lookup  endp
  785.  
  786. ;---- searchbuf --------------------------------------------
  787. ; Called by getchar and peekchar to see if any characters are
  788. ; waiting to be gotten from sources other than BIOS.
  789. ; Returns with Z set if no chars found, BX=keybuf & SI=keybuf.len otherwise.
  790. searchbuf       proc    near
  791.         ; Search the stuffahead buffers.
  792.         mov     cx, 4                   ; number of buffers to check for chars
  793.         mov     bx, offset fnkey - 4
  794. sbloop: add     bx, 4                   ; point to next buffer record
  795.         mov     si, [bx].len
  796.         or      si, si                  ; empty?
  797.         loopz   sbloop                  ; if so, loop.
  798.         ret
  799. searchbuf       endp
  800.  
  801. ;---- getchar -----------------------------------------------
  802. ; Returns AL = next char.
  803. ; Trashes AX, BX, CX, BP, SI.
  804. getchar proc    near
  805. gc_searchbuf:
  806.         ; See if any chars are waiting in stuffahead buffers.
  807.         call    searchbuf
  808.         jz      gc_trykbd               ; No chars?  Try the keyboard.
  809.         ; A nonempty buffer was found.
  810.         dec     [bx].len
  811.         dec     si
  812.         mov     bp, [bx].adr            ; get pointer to string
  813.         mov     al, byte ptr ds:[bp][si]; get the char
  814.         ; Recognize function key sequences, move them to highest priority
  815.         ; queue.
  816.         sub     si, 1                   ; set carry if si=0
  817.         jc      gc_nofnkey              ; no chars left -> nothing to protect.
  818.         cmp     bx, offset fnkey
  819.         jz      gc_nofnkey              ; already highest priority -> done.
  820.         or      al, al
  821.         jnz     gc_nofnkey              ; nonzero first byte -> not fnkey.
  822.         ; Found a function key; move it to highest priority queue.
  823.         dec     [bx].len
  824.         mov     ah, byte ptr ds:[bp][si]; get the second byte of fn key code
  825. gc_fnkey:
  826.         mov     fnkey.len, 1
  827.         mov     fnkeybuf, ah            ; save it.
  828. gc_nofnkey:
  829.         ; Valid char in AL.  Return with it.
  830.         ret
  831.  
  832. gc_trykbd:
  833.         ; Actually get a character from the keyboard.
  834.         xor     ah,ah
  835.         int     16h                     ; BIOS returns with char in AX
  836.         ; If it's Ctrl-break, it has already been taken care of.
  837.         or      ax, ax
  838.         jz      gc_trykbd
  839.  
  840.         ; Look in the reassignment table to see if it needs translation.
  841.         call    lookup                  ; Z=found; CX=length; SI=ptr
  842.         jnz     gc_noredef
  843.         ; Okay; set up the reassignment, and run thru the translation code.
  844.         mov     xlatseq.len, cx
  845.         mov     xlatseq.adr, si
  846.         jmp     gc_searchbuf
  847. gc_noredef:
  848.         ; Is it a function key?
  849.         or      al,al
  850.         jz      gc_fnkey                ; yep- special treatment.
  851. gcdone: ret     ; with character in AL.
  852.  
  853. getchar endp
  854.  
  855. ;---- peekchar -----------------------------------------------
  856. ; Returns Z if no character ready, AL=char otherwise.
  857. ; Trashes AX, BX, CX, BP, SI.
  858. peekchar        proc    near
  859. pc_searchbuf:
  860.         call    searchbuf
  861.         jz      pc_trykbd               ; No chars?  Try the keyboard.
  862.         ; A nonempty buffer was found.
  863.         dec     si
  864.         mov     bp, [bx].adr            ; get pointer to string
  865.         mov     al, byte ptr ds:[bp][si]; get the char
  866.         ; Valid char from buffer in AL.  Return with it.
  867.         jmp     short pcdone
  868.  
  869. pc_brk: int     16h                     ; get rid of control-break in buffer
  870.  
  871. pc_trykbd:
  872.         ; Actually peek at the keyboard.
  873.         mov     ah,1
  874.         int     16h                     ; BIOS returns with char in AX
  875.         jz      pcexit
  876.  
  877.         or      ax,ax
  878.         jz      pc_brk  ; If ctl-brk, it's already been taken care of- kill it.
  879.  
  880.         ; Look in the reassignment table to see if it needs translation.
  881.         call    lookup                  ; Z=found; CX=length; SI=ptr
  882.         jnz     pcdone                  ; Nope; just return the char.
  883.         ; Okay; get the first code to be returned.
  884.         add     si, cx
  885.         mov     al, [si-1]
  886. pcdone: or      ah,1                    ; NZ; char ready!
  887. pcexit: ret     ; with character in AL, Z true if no char waiting.
  888. peekchar        endp
  889.  
  890. ;---- beep ------------------------------------------------------
  891. ; Beep speaker; period given by beep_div, duration by beep_len.
  892. ; Preserves all registers.
  893.  
  894. beep_div        dw      1300            ; fairly close to IBM beep
  895. beep_len        dw      3               ; 3/18 sec- shorter than IBM
  896.  
  897. beep    proc    near
  898.         push    ax
  899.         push    cx
  900.         push    dx
  901.         push    bx
  902.         push    bp
  903.         push    si
  904.         push    di
  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, cs: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    es
  922.         mov     ax,abs40
  923.         mov     es,ax
  924.         assume  es:abs40
  925.         mov     bx,timer_low
  926.         add     bx,cs:beep_len
  927.         mov     cx, -1                  ; emergency, in case clock dead
  928.  
  929. beeplp: mov     ax, timer_low
  930.         cmp     ax,bx
  931.         loopne  beeplp
  932.  
  933.         pop     es
  934.         assume  es:code
  935.         pop     ax
  936.         and     al,0FCh                 ; turn speaker off
  937.         out     dx,al
  938.         pop     di
  939.         pop     si
  940.         pop     bp
  941.         pop     bx
  942.         pop     dx
  943.         pop     cx
  944.         pop     ax
  945.         ret
  946. beep    endp
  947.  
  948. CODE    ends
  949.         end
  950.