home *** CD-ROM | disk | FTP | other *** search
Text File | 1990-01-24 | 38.4 KB | 1,214 lines |
- Newsgroups: comp.sources.misc
- subject: v10i042: PC-MAIL release 2, 10/11
- from: wswietse@lso.win.tue.nl (Wietse Venema)
- Sender: allbery@uunet.UU.NET (Brandon S. Allbery - comp.sources.misc)
-
- Posting-number: Volume 10, Issue 42
- Submitted-by: wswietse@lso.win.tue.nl (Wietse Venema)
- Archive-name: pcmail2/part10
-
- #! /bin/sh
- # This is a shell archive. Remove anything before this line, then unpack
- # it by saving it into a file and typing "sh file". To overwrite existing
- # files, type "sh file -c". You can also feed this as standard input via
- # unshar, or by typing "sh <file", e.g.. If this archive is complete, you
- # will see the following message at the end:
- # "End of archive 10 (of 11)."
- # Contents: main/comport.asm main/kbdinp.c
- # Wrapped by wswietse@tuewsa on Mon Jan 22 17:27:22 1990
- PATH=/bin:/usr/bin:/usr/ucb ; export PATH
- if test -f main/comport.asm -a "${1}" != "-c" ; then
- echo shar: Will not over-write existing file \"main/comport.asm\"
- else
- echo shar: Extracting \"main/comport.asm\" \(20373 characters\)
- sed "s/^X//" >main/comport.asm <<'END_OF_main/comport.asm'
- Xtitle IBM PC Communications I/O Routines
- X;
- X; @(#) comport.asm Version hoptoad-1.3 87/03/24
- X;
- X; Orginal code -- Curt Klinsing
- X;
- X; Changes and updates -- Copyright (c) 1987 Tim Pozar
- X; Anyone can use this code for anything, but it is copyright by Tim
- X; and you must leave his copyright in the code.
- X;
- X; ver: 0
- X; rev: 2
- X; March 13th 1987
- X; This code is in a very early stage and should not be let out.
- X; Several other extensive functions are planned as well as changes
- X; to the current code.
- X;
- X; 2/20/87
- X; Changed segment declarations and function names (eg. _function)
- X; to fit Microsoft C 4.0 and linker requirements.
- X;
- X; FUNCTIONS CHANGED/ADDED --
- X; set_tty(port_number)
- X; Function to find current settings of the port and set up serial
- X; port for 'baud' and 'lcbyte', and enable DTR. This will set up the
- X; port number base addressed passed to it (eg. 3F8h) and all functions
- X; will use this port until the function is used again. (NOT READY FOR USE)
- X;
- X; reset_tty()
- X; Function to put the port back into the state it was when it was
- X; first found by set_tty(). If set_tty() was not called it will not
- X; change the settings of the port. (NOT READY FOR USE)
- X;
- X; 3/13/87
- X; get_msr()
- X; Function to read (get) the byte located in the Modem Status
- X; Register (3FEh). The table below describes the byte returned.
- X; bit description
- X; 0 Delta Clear to Send (DCTS)
- X; Indicates that the !CTS input to the chip has changed state
- X; since the last time it was read by the processor.
- X; 1 Delta Data Set Ready (DDSR)
- X; Indicates that the !DRS input to the chip has changed since
- X; last time it was read by the processor.
- X; 2 Trailing Edge Ring Indicator (TERI)
- X; Indicates that the !RI input to the chip has changed from
- X; an on (logical 1) to an off (logical 0) condition.
- X; 3 Delta Rx Line Signal detect (DRLSD)
- X; Indicates that the !RLSD input to the chip has changed state.
- X; NOTE: Whenever bit 0, 1, 2, or 3 is set to a logical 1, a modem status
- X; interrupt is generated.
- X;
- X; 4 Clear to Send (CTS)
- X; This bit is the complement of the clear to send (!CTS) input.
- X; If bit 4 (LOOP) of the MCR is set to a logical 1, this is
- X; equivalent to RTS in the MCR.
- X; 5 Data Set Ready (DSR)
- X; This bit is the complement of the data set ready (!DSR) input.
- X; If bit 4 (LOOP) of the MCR is set to a logical 1, this is
- X; equivalent to DTR in the MCR.
- X; 6 Ring Indicator (RI)
- X; This bit is the complement of the ring indicator (!RI) input.
- X; If bit 4 (LOOP) of the MCR is set to a logical 1, this is
- X; equivalent to OUT 1 in the MCR.
- X; 7 Receive Line Signal Detect (RLSD).
- X; This bit is the complement of the received line signal detect
- X; (!RLSD) input. If bit 4 (LOOP) of the MCR is set to a logical 1,
- X; this is equivalent to OUT 2 in the MCR.
- X;
- X; Currently this driver is set up for COM1 (3f8h).
- X; If you are using the interupt driven buffer, take out the code
- X; that enables the DTR so that it doesn't get raised until the vectors
- X; are initilized.
- X;
- X; 22/04/1987 W.Z. Venema
- X; set_tty() baud rate parameter (values as the "baud" macro below)
- X;
- X; 19/05/1987 W.Z. Venema
- X; outp_char() made it check for Xon/Xoff from other system
- X
- X_TEXT SEGMENT BYTE PUBLIC 'CODE'
- X_TEXT ENDS
- X_DATA SEGMENT BYTE PUBLIC 'DATA'
- X_DATA ENDS
- XCONST SEGMENT BYTE PUBLIC 'CONST'
- XCONST ENDS
- X_BBS SEGMENT BYTE PUBLIC 'BBS'
- X_BBS ENDS
- X
- XDGROUP GROUP CONST, _BBS, _DATA
- X ASSUME CS: _TEXT, DS: DGROUP, SS: DGROUP, ES: DGROUP
- X
- X_TEXT SEGMENT
- X;
- X;A set of Lattice C and MSC callable functions to support
- X;interrupt driven character I/O on the IBM PC. Input
- X;is buffered, output is polled.
- X;
- X;added functions (TMP) --
- Xpublic _set_tty ;find current settings, and initialize
- X ;comm port to 8 bits and set DTR
- Xpublic _reset_tty ;reset to settings that set_tty() found
- Xpublic _get_msr ;get MSR byte from port.
- X;
- X;original functions --
- Xpublic _init_comm ;initialize the comm port interupts,
- Xpublic _uninit_comm ;remove initialization,
- Xpublic _set_xoff ;enable/disable XON/XOFF,
- Xpublic _get_xoff ;read XON/XOFF state,
- Xpublic _rcvd_xoff ;returns true if XOFF rcvd,
- Xpublic _sent_xoff ;true if XOFF sent,
- Xpublic _inp_cnt ;returns count of rcv chars,
- Xpublic _inp_char ;get one char from buffer,
- Xpublic _inp_flush ;flush input buffer,
- Xpublic _outp_char ;output a character,
- X;
- X;A better description can be found in the comment
- X;block in each function.
- X;
- X; assume cs:pgroup
- X;
- XFALSE EQU 0
- XTRUE EQU NOT FALSE
- X;
- XBASE EQU 03F8H ;BASE FOR SERIAL BOARD
- X;
- XLCR equ BASE+3 ; Line control register
- XIER equ BASE+1 ; Interrup Enable Register
- XMCR EQU BASE+4 ;modem control register
- XMDMSTA EQU BASE+5 ;line status register
- XMDMMSR EQU BASE+6 ;modem status register
- XMDMBAD EQU BASE ;lsb baud resgister
- XEnblDRdy equ 01H ; enable 'data-ready' interrupt bit
- XIntCtlr EQU 21H ;OCW 1 FOR 8259 CONTROLLER
- XEnblIRQ4 EQU 0EFH ;Enable COMMUNICATIONS (IRQ4)
- Xdataport EQU BASE ;transmit/receive data port
- XMaskIRQ4 EQU 10H ;BIT TO DISABLE COMM INTERRUPT (IRQ4)
- X
- XMDMCD EQU 80H ;mask for carrier dectect
- XSETBAU EQU 80H ;code for Divisor Latch Access Bit
- XMDMTBE EQU 20H ;8250 tbe flag
- XMDMBRK EQU 40H ;command code for 8250 break
- XLINMOD EQU 03H ;line mode=8 bit, no parity
- XMDMMOD EQU 0BH ;modem mode = DTR and RTS HIGH
- XSTOP2 EQU 04H ;BIT FOR TWO STOP BITS IF BAUD<300
- XRS8259 EQU 20H ;OCW 3 FOR 8259
- XRSTINT EQU 64H ;SPECIFIC EOI FOR COMM INTERRUPT
- XXOFF EQU 13H ;XOFF character
- XXON EQU 11H ;XON character
- X;
- X; MISCELLANEOUS EQUATES
- X;
- XCR EQU 13
- XLF EQU 10
- XDosCall EQU 33 ;INTERRUPT NUMBER FOR DOS CALL
- XCNSTAT EQU 11 ;FUNCTION NUMBER FOR CONSOLE STATUS
- XCNIN EQU 1 ;FUNCTION NUMBER FOR CONSOLE INPUT
- XBUFSIZ EQU 512 ;Max NUMBER OF CHARS
- XSetIntVect EQU 25H ;SET INTERRUPT VECTOR FUNCTION NUMBER
- X
- X;
- X; Communication parameters --
- X;
- Xbaud equ 12 ; 1047 = 110 (are you kidding?)
- X ; 384 = 300
- X ; 96 = 1200
- X ; 48 = 2400
- X ; 24 = 4800
- X ; 12 = 9600
- Xparity equ 00000b ;00000 = none
- X ;01000 = odd
- X ;11000 = even
- Xstopbit equ 000b ; 000 = 1 bit
- X ; 100 = 2 bits
- Xwordlth equ 11b ; 10 = 7 bits
- X ; 11 = 8 bits
- Xlcbyte equ parity+stopbit+wordlth ;line control byte
- Xdiv_on equ 80h ;divisor latch access bit (DLAB)
- X
- X;
- X; DUMP BUFFER, COUNT AND POINTER.
- X;
- XCIRC_BUF DB BUFSIZ DUP(?) ;ALLOW 512 MaxIMUM BUFFERED CHARACTERS
- XBUF_TOP EQU $ - 1 ;KEEP TRACK OF THE TOP OF THE BUFFER
- XCIRC_TOP DW BUF_TOP ;
- X;
- XCIRC_IN DW OFFSET CIRC_BUF ;POINTER TO LAST CHAR. PLACED IN BUFFER
- XCIRC_CUR DW OFFSET CIRC_BUF ;POINTER TO NEXT CHAR. TO BE RETRIEVED FROM
- X ; BUFFER
- XCIRC_CT DW 0 ;COUNT OF CHARACTERS USED IN BUFFER
- XSNT_XOFF DB FALSE ;FLAG TO CHECK IF AN XOFF HAS BEEN SEND
- XGOT_XOFF DB FALSE ;FLAG TO CHECK IF AN XOFF HAS BEEN RECEIVED
- XSEE_XOFF DB FALSE ;FLAT TO SEE IF WE ARE INTERESTED IN XON/XOFF
- X;
- X;
- X; set_tty()
- X;
- X_set_tty proc near
- X push bp
- X mov bp,sp ; wzv C calling standard
- X; mov dx,mcr
- X; in al,dx ; get modem parameters
- X; mov MCR_BYTE,al ; save them
- X mov dx,lcr
- X; in al,dx ; get line parameters
- X; mov LCR_BYTE,al ; save them
- X mov al,div_on
- X out dx,al ; set 8250 for baud rate selection
- X ; can the baud rate divisor be read to save the settings?
- X ; if so, stick the code here.
- X mov ax,[bp+4] ; was mov ax,baud /wzv
- X mov dx,mdmbad
- X out dx,al ; low byte divisor
- X mov al,ah
- X inc dx
- X out dx,al ; high byte divisor
- X mov dx,lcr
- X mov al,lcbyte
- X out dx,al ; set line control reg.
- X mov dx,mcr
- X in al,dx
- X or al,mdmmod
- X out dx,al ; set DTR high
- Xflsh: mov dx,dataport
- X in al,dx
- X mov dx,mdmsta
- X in al,dx
- X and al,1
- X jnz flsh
- X
- X pop bp
- X ret
- X
- X_set_tty endp
- X
- X
- X_reset_tty proc near
- X push bp
- X
- X pop bp
- X ret
- X
- X_reset_tty endp
- X
- X_get_msr proc near
- X push bp
- X push ds ; save data segment
- X push cs
- X pop ds
- X
- X xor ax,ax
- X mov dx,MDMMSR
- X in al,dx
- X
- X pop ds
- X pop bp
- X ret
- X
- X_get_msr endp
- X
- X;
- X; set_xoff(flag) Enable (flag != 0) or disable
- X;int flag; (flag == 0) XON/ XOFF protocol
- X; for the character input stream.
- X;If enabled, an XOFF will be sent when the buffer
- X;reaches 3/4 full. NOTE: an XON will not be sent auto-
- X;matically. Your program must do it when it sees
- X;the _rcvd_xoff() flag, and ready for more chars.
- X;
- X_set_xoff proc near
- X push bp
- X mov bp,sp ; wzv C calling standard
- X PUSH DS ;SAVE DATA SEGMENT
- X mov bx,[bp+4] ; wzv C calling standard
- X push cs
- X pop ds ; move code seg addr to data seg reg.
- X cmp bx,0
- X jnz to_on
- X mov see_xoff,FALSE
- X jmp done1
- Xto_on: mov see_xoff,TRUE
- Xdone1: pop ds
- X pop bp
- X ret
- X_set_xoff endp
- X;
- X;flag = get_xoff() Returns the current setting
- X; of the XON/ XOFF flag set
- X;by set_xoff(), above.
- X;
- X_get_xoff proc near
- X push bp
- X push ds ; save data reg
- X push cs
- X pop ds ; move code seg addr to data seg reg.
- X xor ax,ax
- X mov al,see_xoff
- X pop ds
- X pop bp
- X ret
- X_get_xoff endp
- X;
- X;flag = sent_xoff(); Returns true if an XOFF
- X; character was sent, indicating
- X;the receive buffer is 3/4 full.
- X;
- X_sent_xoff proc near
- X push bp
- X push ds ; save data reg
- X push cs
- X pop ds ; move code seg addr to data seg reg.
- X xor ax,ax
- X mov al,snt_xoff
- X pop ds
- X pop bp
- X ret
- X_sent_xoff endp
- X;
- X; rcvd_xoff() Returns true if an XOFF was
- X; received; will return false as
- X;soon as an XON is received. Does not effect data output,
- X;only indicates the above. (Obviously useless for binary
- X;data.)
- X;
- X_rcvd_xoff proc near
- X push bp
- X push ds ; save data reg
- X push cs
- X pop ds ; move code seg addr to data seg reg.
- X xor ax,ax
- X mov al,got_xoff
- X pop ds ; restore data reg
- X pop bp
- X ret
- X_rcvd_xoff endp
- X;
- X;count = inp_cnt() Returns the number of characters
- X; available in the input buffer.
- X;
- X
- X_inp_cnt proc near
- X push bp
- X push ds ; save data segment
- X push cs
- X pop ds ; move code seg addr to data seg reg
- X mov ax,circ_ct
- X pop ds
- X pop bp
- X ret
- X_inp_cnt endp
- X;
- X; inp_flush() Flush the input buffer.
- X;
- X_inp_flush proc near
- X push bp
- X push ds ; save data reg
- X push cs
- X pop ds ; move code seg addr to data seg reg.
- X mov bx,offset circ_buf
- X mov circ_in,bx
- X mov circ_cur,bx
- X xor ax,ax
- X mov circ_ct,ax
- X pop ds
- X pop bp
- X ret
- X_inp_flush endp
- X
- X; --------- Init -----------------------------------
- X; Program initialization:
- X; -- Set up vector for RS232 interrupt (0CH)
- X; -- Enbl IRQ4
- X; -- Enbl RS232 interrupt on data ready
- X;
- X; ---------------------------------------------------
- X
- X_init_comm proc near
- X push bp
- X cli
- X
- X; ---- Set up INT x'0C' for IRQ4
- X
- X push ds
- X push cs
- X pop ds ;cs to ds
- X mov dx,offset IntHdlr ;relative adddres of interrupt handler
- X mov al,0cH ;interrupt number for comm.
- X mov ah,SetIntVect ;function number for setting int vector
- X int DosCall ;set interrupt in 8086 table
- X pop ds ;restore DS
- X
- X; ---- Enbl IRQ4 on 8259 interrupt controller
- X
- X cli
- X
- X in al,IntCtlr ; get current masks
- X and al,EnblIRQ4 ; Reset IRQ4 mask
- X out IntCtlr,al ; And restore to IMR
- X
- X; --- Enbl 8250 data ready interrupt
- X
- X mov dx,LCR ; DX ==> LCR
- X in al,dx ; Reset DLAB for IER access
- X and al,7FH
- X out dx,al
- X mov dx,IER ; Interrupt Enbl Register
- X mov al,EnblDRdy ; Enable 'data-ready' interrupt
- X out dx,al
- X
- X; --- Enbl OUT2 on 8250
- X
- X mov dx,MCR ; modem control register
- X in al,dx ; Enable OUT2
- X or al,08h ; find out what is in there and
- X out dx,al ; enable the DTR
- X
- X sti
- X
- X pop bp
- X ret
- X_init_comm endp
- X;
- X; uninit_comm() Removes the interrupt structure
- X; installed by _init_comm(). Must be
- X;done before passing control to the DOS, else chars received
- X;will be stored into the next program loaded!
- X;
- X_uninit_comm proc near
- X push bp
- X; --- Disable IRQ4 on 8259
- X
- X cli
- X in al,IntCtlr ;GET OCW1 FROM 8259
- X or al,MaskIRQ4 ;DISABLE COMMUNICATIONS INTERRUPT
- X out IntCtlr,al
- X
- X; --- Disable 8250 data ready interrupt
- X
- X mov dx,LCR ; DX ==> LCR
- X in al,dx ; Reset DLAB for IER access
- X and al,7FH
- X out dx,al
- X mov dx,IER ; Interrupt Enbl Register
- X mov al,0 ; Disable all 8250 interrupts
- X out dx,al
- X
- X; --- Disable OUT2 on 8250
- X
- X mov dx,MCR ; modem control register
- X mov al,0 ; drop DTR
- X out dx,al
- X
- X sti
- X pop bp
- X ret
- X_uninit_comm endp
- X;
- X;char inp_char() Return a character from the input
- X; buffer. Assumes you have called
- X;inp_cnt() to see if theres any characters to get.
- X;
- X_inp_char proc near
- X push bp
- X push ds ; save data reg
- X push cs
- X pop ds ; move code seg addr to data seg reg.
- X mov bx,circ_cur
- X xor ax,ax
- X mov al,[bx] ;get next char from circ_buf
- X DEC circ_ct ;decrement circ_buf COUNT
- X CMP bx,circ_top ;ARE WE AT THE TOP OF THE circ_buf?
- X JZ reset_cur ;JUMP IF SO
- X INC bx ;ELSE, BUMP PTR
- X JMP SHORT upd_cur
- Xreset_cur:
- X mov bx,OFFSET circ_buf ;RESET circ_in TO BOTTOM OF BUF.
- Xupd_cur:
- X mov circ_cur,bx ;SAVE NEW PTR
- X xor cx,cx
- X mov cl,see_xoff ;check if interested in xon/xoff
- X cmp cl,TRUE
- X jnz clnup2 ;not interested, so goto return
- X cmp snt_xoff,TRUE ;have we sent an xoff?
- X jnz clnup2 ;no, so return
- X cmp circ_ct,80h ;yes, so see in buf is now emptying
- X jg clnup2 ;not empty enuf to send xon, jump to ret
- X mov snt_xoff,FALSE
- X mov cl,XON
- X push ax ; save char
- X call comout
- X pop ax
- Xclnup2: pop DS ;GET BACK ENTERING DS
- X pop bp
- X ret
- X_inp_char endp
- X;
- X; outp_char(c) Output the character to the
- X;char c; serial port. This is not buffered
- X; or interrupt driven.
- X;
- X_outp_char proc near
- X push bp
- X mov bp,sp
- X push ds ; save data segment register /wzv
- X push cs ; copy code segment register /wzv
- X pop ds ; to data segment register /wzv
- Xw_Xon: test got_Xoff,TRUE ; shut up if Xoff received / wzv
- X jnz w_Xon
- X mov cl,[bp+4]
- X sti
- X call comout
- X pop ds ; restore data segment register / wzv
- X pop bp
- X ret
- X_outp_char endp
- X;
- X;Local subroutine: output CL to the port.
- X;
- Xcomout: mov dx,MDMSTA
- X in al,dx ; get 8250 status
- X and al,MDMTBE ; check for transmitter ready
- X jz comout ; jump if not to wait
- X mov al,cl ; get char to al
- X mov dx,dataport
- X out dx,al ; output char to 8251
- X ret
- X;
- X; RECEIVE INTERRUPT HANDLER (CHANGED TO PLACE CHARACTERS IN A
- X; CIRCULAR circ_buf AND TO SEND AN XOFF IF THE circ_buf IS MORE THAN
- X; 3/4 FULL - S.G.)
- X;
- XIntHdlr:
- X CLI
- X push cx
- X push dx
- X push bx
- X push ax
- X push ds
- X mov ax,cs ;get cur code segment
- X mov ds,ax ;and set it as data segment
- X mov bx,circ_in ;GET circ_buf IN PTR
- X mov DX,dataport ;GET DATA PORT NUMBER
- X IN AL,DX ;GET RECEIVED CHARACTER
- X; push ax
- X; push dx
- X; xor ax,ax
- X; xor dx,dx
- X; mov dl,al
- X; mov ah,2
- X; int DosCall
- X; pop dx
- X; pop ax
- X xor cx,cx
- X mov cl,see_xoff ;check if interested in xon/xoff
- X cmp cl,TRUE
- X jnz ck_full ;not interested goto ck if buf full
- X mov cl,al ;put char in cl for testing
- X and cl,7fh ;turn off any parity bits
- X cmp cl,XOFF ;see if we got an xoff
- X jnz ck_xon
- X mov got_Xoff,TRUE ; code for handling xon/xoff from remote
- X jmp clnup
- Xck_xon: cmp cl,XON
- X jnz reg_ch
- X mov got_Xoff,FALSE
- X jmp clnup
- X;
- X;Normal character; not XON/XOFF, or XON/XOFF disabled.
- X;
- Xreg_ch: test snt_Xoff,TRUE ;SEE IF sentXoff IS SET
- X jnz ck_full ;IF SO, DON'T SEND ANOTHER XOFF
- X CMP circ_ct,(BUFSIZ * 3)/4 ;ALLOW BUF TO BECOME 3/4 FULL BEFORE
- X ; SENDING XOFF
- X jb savch ;IF IT'S OK, CONTINUE
- X push ax ;SAVE CHARACTER
- X mov CL,XOFF ;GET XOFF CHARACTER
- X mov snt_Xoff,TRUE ;RESET sentXoff
- X call comout ; AND SEND IT
- X pop ax ;RETRIEVE CHARACTER
- X JMP SHORT savch ;IF WE'RE HERE, THE circ_buf HAS BUFSIZ-80H
- X ; CHARACTERS
- Xck_full:
- X CMP circ_ct,BUFSIZ ;SEE IF circ_buf ALREADY FULL
- X JZ clnup ; JUMP IF SO, DO NOT PLACE CHARACTER IN BFR
- Xsavch:
- X mov [bx],AL ;SAVE NEW CHARACTER IN circ_buf
- X inc circ_ct ;BUMP circ_buf COUNT
- X CMP bx,circ_top ;ARE WE AT THE TOP OF THE circ_buf?
- X JZ reset_in ;JUMP IF SO
- X inc bx ;ELSE, BUMP PTR
- X JMP SHORT into_buf
- Xreset_in:
- X mov bx,OFFSET circ_buf ;RESET circ_in TO BOTTOM OF BUF.
- Xinto_buf:
- X mov circ_in,bx ;SAVE NEW PTR
- Xclnup:
- X mov AL,RSTINT
- X OUT RS8259,AL ;ISSUE SPECIFIC EOI FOR 8259
- X pop ds ;GET BACK ENTERING DS
- X pop ax
- X pop bx
- X pop dx
- X pop cx
- X sti
- X iret
- X
- X_TEXT ENDS
- X
- Xend
- END_OF_main/comport.asm
- if test 20373 -ne `wc -c <main/comport.asm`; then
- echo shar: \"main/comport.asm\" unpacked with wrong size!
- fi
- # end of overwriting check
- fi
- if test -f main/kbdinp.c -a "${1}" != "-c" ; then
- echo shar: Will not over-write existing file \"main/kbdinp.c\"
- else
- echo shar: Extracting \"main/kbdinp.c\" \(15738 characters\)
- sed "s/^X//" >main/kbdinp.c <<'END_OF_main/kbdinp.c'
- X/*++
- X/* NAME
- X/* kbdinp 3
- X/* SUMMARY
- X/* keyboard interpreter
- X/* PROJECT
- X/* pc-mail
- X/* PACKAGE
- X/* mail
- X/* SYNOPSIS
- X/* void kbdinp(screen)
- X/* Screen *screen;
- X/*
- X/* void kbdinit()
- X/*
- X/* void kbdrest()
- X/*
- X/* int getkey()
- X/* DESCRIPTION
- X/* The keyboard interpreter is the machine that executes the program
- X/* that is recorded in the form of Screen data structures.
- X/* Its task is to interpret keyboard input and to
- X/* invoke the appropriate action functions.
- X/*
- X/* Depending on the return value of an action function
- X/* the keyboard interpreter i) returns (S_BREAK), ii) repaints the
- X/* screen (S_REDRAW), or iii) just waits for more keyboard
- X/* input. Error handling is entirely up to the action functions.
- X/*
- X/* The routines in this module are responsible for what appears in the
- X/* top (function-key labels) and bottom sections (command dialogue)
- X/* of the tty screen.
- X/*
- X/* The middle screen section is handled by the pager (except when
- X/* help info is displayed).
- X/*
- X/* kbdinit() sets the tty driver and keypad modes (no echo,
- X/* punctual input).
- X/*
- X/* kbrest() restores the modes to what they were when kbdinit() was
- X/* invoked.
- X/*
- X/* getkey() returns the next keypress (see screen.h for function-key
- X/* codes) and maps lower case to upper case.
- X/*
- X/* Terminal-specific codes for function keys and keypad are borrowed
- X/* from window.c.
- X/* FUNCTIONS AND MACROS
- X/* printcl(), printat(), wputc(), wputs(), beep(), winout()
- X/* SEE ALSO
- X/* window(3) window management routines, function key codes
- X/* window(5) window definitions
- X/* screen(3) command key tables for each screen
- X/* screen(5) structure of command key tables
- X/* DIAGNOSTICS
- X/* It beeps when an illegal key is pressed. Otherwise, no error
- X/* handling at all.
- X/* AUTHOR(S)
- X/* W.Z. Venema
- X/* Eindhoven University of Technology
- X/* Department of Mathematics and Computer Science
- X/* Den Dolech 2, P.O. Box 513, 5600 MB Eindhoven, The Netherlands
- X/* CREATION DATE
- X/* Thu Apr 2 18:43:12 GMT+1:00 1987
- X/* LAST MODIFICATION
- X/* 90/01/22 13:01:51
- X/* VERSION/RELEASE
- X/* 2.1
- X/*--*/
- X
- X#include <stdio.h>
- X#include <signal.h>
- X#include <ctype.h>
- X
- X#include "defs.h"
- X#include "mail.h"
- X#include "screen.h"
- X#include "window.h"
- X
- X#ifdef unix
- X#if (SIII||SYSV) /* AT&T */
- X#include <termio.h>
- Xstruct termio oldmode;
- X#else /* V7 or Berkeley */
- X#include <sgtty.h>
- Xstruct sgttyb oldmode;
- X# endif
- X#endif
- X
- X/* How to generate a brief delay when the user presses ESC */
- X
- X#ifdef MSDOS
- X#define sleep(x) { unsigned i; for (i = 1; i > 0; i++) ; }
- X#endif
- X
- X/* Forward declarations */
- X
- Xhidden void kb_help(); /* Display context-sensitive help */
- Xhidden void kb_pause(); /* Press any key to continue */
- Xhidden int kb_paint(); /* Screen update routine */
- Xhidden int kb_str(); /* Read an arbitrary string */
- Xhidden int kb_key(); /* Read single-key input */
- Xhidden int kb_cr(); /* Allow ESC or ENTER as input */
- Xhidden int kb_edt(); /* String input with default */
- Xhidden int kb_yn(); /* Yes/no input */
- Xhidden char *kb_read(); /* Basic input function */
- Xhidden int input(); /* Read one key stroke */
- Xhidden int isempty(); /* String is all blanks */
- X
- X/* Various strings */
- X
- X#define QUEST "? " /* prompt for input */
- Xhidden char sect[] = "=========================================================\
- X======================";
- X
- X/* The maximal length of string input; depends on the window size */
- X
- Xhidden int maxstr;
- X
- X/* kbdinp - recursively interpret screen descriptions */
- X
- Xpublic int kbdinp(screen)
- XScreen *screen;
- X{
- X kb_paint(screen);
- X
- X if (iskey(screen->key))
- X return (kb_key(screen)); /* single-key commands */
- X else if (screen->key == STRING)
- X return (kb_str(screen)); /* string input screen */
- X else if (screen->key == EDIT)
- X return (kb_edt(screen)); /* string edit screen */
- X else if (screen->key == YESNO)
- X return (kb_yn(screen)); /* yes/no screen */
- X else if (screen->key == ESCCR)
- X return (kb_cr(screen)); /* confirm/cancel screen */
- X else
- X fatal("kbdinp"); /* unexpected screen type */
- X /* NOTREACHED */
- X}
- X
- X/* kb_paint - paint the screen (clean up this function) */
- X
- Xhidden int kb_paint(p)
- Xregister Screen *p;
- X{
- X char topline[BUFSIZ]; /* key label line */
- X register int k; /* loop control variable */
- X int stat = 0; /* status from mid window */
- X int promptloc; /* where prompt "?" goes */
- X
- X /*
- X * The top section of the screen consists of one line with key labels (in
- X * case of single-key input screen) and a bar that separates this section
- X * from the middle screen section.
- X *
- X * We always add a Help and ? label. Thus, the interpreter preempts the
- X * use of the H and ? characters.
- X */
- X
- X for (topline[0] = 0; p->key; p++) { /* start top window */
- X if (iskey(p->key)) { /* keystroke input ? */
- X strcat(topline, p->name); /* append key label */
- X strcat(topline, " "); /* and some blanks */
- X } else if (topline[0]) { /* leak if first entry */
- X fatal("mixed single-key and string input");
- X }
- X }
- X printcl(topwin, 0, topline); /* display key labels */
- X if (topline[0]) /* if there are labels */
- X wputs("Help ?"); /* display help key labels */
- X printcl(topwin, 1, sect); /* finish top window with bar */
- X
- X /*
- X * The bottom section of the screen consists of a bar that separates us
- X * from the middle section, followed by the "help" string in the last
- X * entry of the current screen definition, followed by (if not a
- X * single-key input screen) a prompting question mark.
- X */
- X
- X printcl(botwin, 0, sect); /* start lower window */
- X promptloc = printcl(botwin, 1, p->help ? p->help : "") + 1;
- X for (k = promptloc; k < botwin->size; k++) /* clear rest of lower window */
- X printcl(botwin, k, ""); /* lower window done */
- X
- X if (p->action) /* fill middle window */
- X stat = CALL(p->action) (); /* middle window done */
- X
- X /*
- X * We leave the focus on the middle window, in case of single-key input,
- X * and move the focus to the bottom window in case of prompted input.
- X */
- X
- X if (topline[0] == 0) /* prompted input screen? */
- X printat(botwin, promptloc, QUEST); /* output "?" prompt */
- X
- X /* Determine maximal length of string input */
- X
- X maxstr = MAX(((botwin->size - 1) * CO - sizeof(QUEST) - 2), BUFSIZ - 1);
- X
- X return (stat); /* from middle window filler */
- X}
- X
- X/* kb_str - handle string input without defaults */
- X
- Xhidden int kb_str(p)
- Xregister Screen *p;
- X{
- X char string[BUFSIZ]; /* a character buffer */
- X register int stat;
- X
- X for (;;) {
- X string[0] = '\0'; /* no default input */
- X if (kb_read(string) == 0) { /* command cancelled? */
- X return (0); /* quit */
- X } else if ((stat = CALL(p->action) (string)) & S_BREAK) {
- X return (stat); /* we're done here */
- X } else if (stat & S_REDRAW) { /* screen was changed */
- X kb_paint(p); /* restore display */
- X }
- X }
- X}
- X
- X/* kb_yn - handle yes/no input */
- X
- Xhidden int kb_yn(p)
- Xregister Screen *p;
- X{
- X char string[BUFSIZ]; /* a character buffer */
- X register int stat; /* return status */
- X static char yn[] = "nNyY"; /* input is not mapped to upper case */
- X char *in;
- X
- X for (string[0] = '\0';;) { /* clear input */
- X if (kb_read(string) == 0) { /* command cancelled? */
- X return (0); /* quit */
- X } else if ((in = index(yn, string[0])) == 0) { /* validate */
- X beep(); /* complain */
- X kb_paint(p); /* restore display */
- X } else if ((stat = CALL(p->action) (in - yn > 1)) & S_BREAK) {
- X return (stat); /* we're done here */
- X } else if (stat & S_REDRAW) { /* screen was changed */
- X kb_paint(p); /* restore display */
- X string[0] = '\0'; /* clear input */
- X }
- X }
- X}
- X
- X/* kb_edt - handle string input with default */
- X
- Xhidden int kb_edt(p)
- Xregister Screen *p;
- X{
- X char string[BUFSIZ]; /* user input */
- X register int stat; /* return status */
- X
- X for (;;) {
- X (void) strncpy(string, p->help, BUFSIZ);/* stuff default input */
- X if (kb_read(string) == 0) { /* command cancelled */
- X return (0); /* quit */
- X } else if ((stat = CALL(p->action) (string)) & S_BREAK) {
- X return (stat); /* we're done here */
- X } else if (stat & S_REDRAW) { /* screen was changed */
- X kb_paint(p); /* restore display */
- X }
- X }
- X}
- X
- X/* kb_read - general string edit/input routine */
- X
- Xhidden char *kb_read(string)
- Xchar string[BUFSIZ];
- X{
- X register char *cp; /* a character pointer */
- X register int c; /* a character */
- X
- X cp = string + strlen(string); /* update buffer pointer */
- X wputs(string); /* show input to be edited */
- X
- X for (;;) {
- X if (!isascii(c = input())) { /* ignore non-ascii codes */
- X beep(); /* complain */
- X } else if (c == ESC) { /* ESC means don't do it */
- X wputs(" (ESC)"); /* confirm input */
- X sleep(1);
- X return (0); /* nothing left here to do */
- X } else if (c == ENTER && (*cp = 0, !isempty(string))) {
- X wputc(c); /* echo */
- X return (string); /* we're done here */
- X } else if (c == BS || c == DEL) {
- X if (cp > string)
- X cp--, wputs("\b \b"); /* remove one character */
- X } else if (c == CTLU) { /* line erase */
- X while (cp > string)
- X cp--, wputs("\b \b");
- X } else if ((c == ' ' || isprint(c)) && (cp - string) < maxstr) {
- X wputc(*cp++ = c); /* accept and echo */
- X } else {
- X beep(); /* complain */
- X }
- X }
- X}
- X
- X/* kb_key - handle single-key input */
- X
- Xhidden int kb_key(p)
- XScreen *p;
- X{
- X register int c; /* a character */
- X register Screen *q; /* a screen (eh?) */
- X register int stat; /* a status */
- X
- X for (;;) {
- X if ((c = getkey()) == '?' || c == 'H') {/* is it a help request */
- X kb_help(p); /* yes, display key info */
- X continue; /* skip rest of loop */
- X }
- X for (q = p; q->key && q->key != c; q++) /* look key up in table */
- X /* void */
- X ;
- X if (q->key == 0) { /* unrecognized key */
- X beep(); /* complain */
- X } else if (q->action == 0) { /* action-less key */
- X return (0); /* we are done here */
- X } else if ((stat = CALL(q->action) ()) & S_BREAK) { /* do action */
- X return (stat); /* we are done here */
- X } else if (stat & S_REDRAW) { /* screen was changed */
- X kb_paint(p); /* restore screen */
- X }
- X }
- X}
- X
- X/* kb_cr - handle escape/enter input */
- X
- Xhidden int kb_cr(p)
- XScreen *p;
- X{
- X register int c;
- X register int stat;
- X
- X for (;;) {
- X if ((c = input()) == ESC) { /* don't do it */
- X wputs(" (ESC)"); /* confirm input */
- X sleep(1);
- X return (0); /* we are done */
- X } else if (c == ENTER) { /* do the action */
- X stat = CALL(p->action) (); /* execute action */
- X if (stat & S_BREAK) { /* child kills parent */
- X return (stat); /* we are done */
- X } else if (stat & S_REDRAW) { /* screen was changed */
- X kb_paint(p); /* restore screen */
- X }
- X } else { /* unacceptable input */
- X beep(); /* complain */
- X }
- X }
- X}
- X
- X/* kb_help - display per-key help info; redraw screen when done */
- X
- Xhidden void kb_help(p)
- Xregister Screen *p;
- X{
- X register int k;
- X
- X for (k = 0; k < midwin->size; k++) /* erase middle window */
- X printcl(midwin, k, "");
- X for (k = 0; p[k].key; k++) /* display key info */
- X printcl(midwin, k + 1, strcons(" %-10s %s", isascii(p[k].key) &&
- X isprint(p[k].key) ? p[k].name[1] ? strcons("%c(%s)", p[k].key,
- X p[k].name + 1) : strcons("%c", p[k].key) : p[k].name, p[k].help));
- X for (k = 1; k < botwin->size - 1; k++) /* erase bottom window */
- X printcl(botwin, k, "");
- X printcl(botwin, 1, anykey); /* press any key to continue */
- X getkey();
- X kb_paint(p); /* redraw screen */
- X}
- X
- X/* structure that associates token value with function-key strings */
- X
- Xstruct keydef {
- X char **strval; /* key string */
- X int tokval; /* key value */
- X};
- X
- Xhidden struct keydef keys[] = {
- X &KU, UP, /* key strings are set */
- X &KD, DOWN, /* in window.c */
- X &KL, LEFT,
- X &KR, RIGHT,
- X &PU, PGUP,
- X &PD, PGDN,
- X 0, 0,
- X};
- X
- X/* getkey - get key stroke, detect function keys, ignore case otherwise */
- X
- Xpublic int getkey()
- X{
- X register int c;
- X register struct keydef *kp;
- X char kstr[BUFSIZ];
- X register int len;
- X
- X /*
- X * We assume that all function keys produce strings that start with the
- X * same lead-in character, and that those strings all have the same
- X * length. This is a reasonable assumption for cursor-control keys on
- X * most terminals.
- X */
- X
- X if ((c = input()) == **(keys->strval)) { /* lead-in character */
- X
- X /*
- X * Read a number of characters equal to the length of the strings
- X * generated by function keys.
- X */
- X
- X for (len = 1; len < strlen(*(keys[0].strval)); len++)
- X kstr[len] = c = input();
- X kstr[len] = '\0';
- X
- X /* Compare what we just read with known function-key strings. */
- X
- X for (kp = keys; kp->tokval; kp++)
- X if (strcmp(*(kp->strval) + 1, kstr + 1) == 0)
- X return (kp->tokval); /* return token value */
- X }
- X /* Return the last read character. */
- X
- X return ((isascii(c) && islower(c)) ? toupper(c) : c);
- X}
- X
- X/* input - read one character without echoing or waiting for carriage return */
- X
- Xhidden int input()
- X{
- X
- X#ifdef unix
- X
- X /*
- X * On unix systems, the terminal driver has been instructed to not echo
- X * and to return one character as soon as it comes available. Also the
- X * stdio routines have been instructed to process input in an unbuffered
- X * fashion. See kbdinit().
- X */
- X
- X return (getchar());
- X#endif
- X
- X#ifdef MSDOS
- X
- X /*
- X * On IBM-PC machines a function key produces a null character followed
- X * by a scan code. We translate the null prefix to an escape character
- X * since that is more like normal terminals do. The trick is to find out
- X * when we read a null character whether it was produced by pressing a
- X * real function-key or by pressing ctrl-@.
- X */
- X
- X register int c;
- X
- X return ((c = getch()) ? c : kbhit() ? ESC : 0);
- X#endif
- X
- X#if (!defined(unix) && !defined(MSDOS))
- X "You should either define unix or MSDOS, or add support for another OS"
- X#endif
- X}
- X
- X/* kbdinit - set input mode, turn keypad on */
- X
- Xpublic void kbdinit()
- X{
- X
- X#ifdef MSDOS
- X (void) signal(SIGINT, SIG_IGN); /* ignore control-c */
- X#endif
- X
- X#ifdef unix
- X
- X /*
- X * On unix systems, instruct the terminal driver to not echo terminal
- X * input, and to return from a read as soon as one character comes
- X * available.
- X */
- X
- X# if (SIII||SYSV)
- X struct termio newmode; /* AT&T */
- X
- X (void) ioctl(0, TCGETA, &oldmode); /* save terminal mode */
- X (void) ioctl(0, TCGETA, &newmode); /* get terminal mode */
- X newmode.c_iflag &= ~(ICRNL | BRKINT);
- X newmode.c_oflag &= ~OPOST;
- X newmode.c_lflag &= ~(ICANON | ISIG | ECHO);
- X newmode.c_cc[VMIN] = 1;
- X newmode.c_cc[VTIME] = 0;
- X (void) ioctl(0, TCSETAF, &newmode); /* set terminal mode */
- X# else
- X struct sgttyb newmode; /* V7 or Berkeley */
- X
- X (void) gtty(0, &oldmode); /* save terminal mode */
- X (void) gtty(0, &newmode); /* get terminal mode */
- X newmode.sg_flags |= RAW;
- X newmode.sg_flags &= ~(ECHO | CRMOD);
- X (void) stty(0, &newmode); /* set terminal mode */
- X# endif
- X
- X setbuf(stdin, (char *) 0); /* select unbuffered input */
- X
- X if (KS && *KS) /* if there is a keypad */
- X tputs(KS, 1, fputchar); /* enable it */
- X#endif
- X}
- X
- X/* kbdrest - reset terminal driver to previous state, turn keypad off */
- X
- Xpublic void kbdrest()
- X{
- X#ifdef unix
- X
- X /* Restore tty modes, either the AT&T way or the BSD+V7 way */
- X
- X# if (SIII||SYSV)
- X ioctl(0, TCSETAF, &oldmode);
- X# else
- X stty(0, &oldmode);
- X# endif
- X
- X /* Disable keypad if there is one */
- X
- X if (KE && *KE)
- X tputs(KE, 1, fputchar);
- X#endif
- X}
- X
- X/* isempty - check a string is all blanks or empty */
- X
- Xhidden int isempty(s)
- Xregister char *s;
- X{
- X while (*s && isspace(*s))
- X s++;
- X return (*s == 0);
- X}
- END_OF_main/kbdinp.c
- if test 15738 -ne `wc -c <main/kbdinp.c`; then
- echo shar: \"main/kbdinp.c\" unpacked with wrong size!
- fi
- # end of overwriting check
- fi
- echo shar: End of archive 10 \(of 11\).
- cp /dev/null ark10isdone
- MISSING=""
- for I in 1 2 3 4 5 6 7 8 9 10 11 ; do
- if test ! -f ark${I}isdone ; then
- MISSING="${MISSING} ${I}"
- fi
- done
- if test "${MISSING}" = "" ; then
- echo You have unpacked all 11 archives.
- rm -f ark[1-9]isdone ark[1-9][0-9]isdone
- else
- echo You still need to unpack the following archives:
- echo " " ${MISSING}
- fi
- ## End of shell archive.
- exit 0
-
-