v03i002: uucp mail for pc's (1 of 8)
Wietse Venema
wswietse at eutrc3.UUCP
Thu Apr 21 02:40:21 AEST 1988
comp.sources.misc: Volume 3, Issue 2
Submitted-By: "Wietse Venema" <wswietse at eutrc3.UUCP>
Archive-Name: pcmail/Part1
These programs turn a pc into a (non-routing) uucp node. The
programs run under MS-DOS and various flavours of UNIX. Porting
to other OSes should not be difficult.
#! /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 1 (of 8)."
# Contents: README termcap comport.s hsearch.c hsearch.h pager.c
# Wrapped by wietse at eutwc1 on Wed Apr 20 16:45:03 1988
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f README -a "${1}" != "-c" ; then
echo shar: Will not over-write existing file \"README\"
else
echo shar: Extracting \"README\" \(2251 characters\)
sed "s/^X//" >README <<'END_OF_README'
XGENERAL
X
XThe pc-mail software provides a single user with facilities for
Xcreating, sending and receiving electronic mail messages via the
Xuucp network. The programs were developed under UNIX but also run
Xwith MS-DOS. Porting to other OSes should be relatively easy.
X
XFor the non-technical user there is a menu-driven shell that au-
Xtomatically invokes various utility programs, e.g. an editor of
Xthe user's choice for editing or creating messages, a program
Xthat logs in on a UNIX host to exchange files and so on. Any edi-
Xtor that produces clean ASCII files can be used (wordstar files
Xare also handled correctly). Other facilities: alias data base,
Xbatch-mode operation.
X
XMore technically oriented users will want to avoid the interac-
Xtive shell and use the mail data base and utility programs
Xdirectly. The necessary information can be found in the implemen-
Xtation documentation. In adition, almost every source file has a
Xbuilt-in manual page. The latter can be extracted with the
Xsrctoman.sh shell script.
X
XThe programs have been tested under MS-DOS on XT and AT clones
X(MicroSoft V4 C compiler), and with Microport System-V. For the
Xinteractive shell, a tiny MS-DOS termcap library is provided. It
Xrequires the ANSI.SYS tty driver (or better) to work sucessfully.
XIn order to run the software under UNIX (for testing purposes)
Xone needs a C library with the System-V library functions
X(strtok(), memcpy() et al.). Morever, the directory scanning
Xfunctions only work with file systems that use fixed-size direc-
Xtory entries (i.e. not BSD).
X
XThe programs support the sending and receiving of electronic mail
Xonly; no transfer of files by name and no message routing. In
Xfact the pc side treats each data file it receives as a mail mes-
Xsage, irrespective of its actual destination. The reason for
Xthese limitations are (besides uucp security problems) that all
Xfiles can be sent as mail, and that a pc does not provide multi-
Xuser support anyway.
X
XYou can do anything with the source, but not ask money for it nor
Xremove references to the original authors. Complaints, feedback,
Xsuggestions are welcome.
X
X Wietse Venema uucp: mcvax!eutrc3!wswietse
X bitnet: wswietse at heitue5
END_OF_README
if test 2251 -ne `wc -c <README`; then
echo shar: \"README\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test ! -d termcap ; then
echo shar: Creating directory \"termcap\"
mkdir termcap
fi
if test -f comport.s -a "${1}" != "-c" ; then
echo shar: Will not over-write existing file \"comport.s\"
else
echo shar: Extracting \"comport.s\" \(20454 characters\)
sed "s/^X//" >comport.s <<'END_OF_comport.s'
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; uninit_comm() don't drop DTR when done
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,1 ; Disable OUT2 /wzv use 1 instead of 0
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
X
X
END_OF_comport.s
if test 20454 -ne `wc -c <comport.s`; then
echo shar: \"comport.s\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f hsearch.c -a "${1}" != "-c" ; then
echo shar: Will not over-write existing file \"hsearch.c\"
else
echo shar: Extracting \"hsearch.c\" \(15412 characters\)
sed "s/^X//" >hsearch.c <<'END_OF_hsearch.c'
X#include <ctype.h> /* for case-insensitive version */
X#include "hsearch.h" /* join the parts that were broken up */
X
X#define strcmp istrcmp /* for case-insensitive version */
X
Xstatic ELEMENT **Table = NULL; /* pointer to dynamicly allocated table */
Xstatic int Num_elem = -1; /* number of elements */
X
Xextern char *calloc();
X
Xextern void hdestroy();
Xextern int hcreate();
Xextern ENTRY *hsearch();
X
Xstatic int hashit();
X
X/*
X * table of first 1900 or so primes, for use in finding the right prime
X * number to be the table size. this table may be generally useful...
X */
X
Xstatic unsigned short primetab[] = {
X/*
X * comment these out, so that table will always have a minimal size...
X1, 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71,
X*/
X73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151,
X157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227, 229, 233,
X239, 241, 251, 257, 263, 269, 271, 277, 281, 283, 293, 307, 311, 313, 317,
X331, 337, 347, 349, 353, 359, 367, 373, 379, 383, 389, 397, 401, 409, 419,
X421, 431, 433, 439, 443, 449, 457, 461, 463, 467, 479, 487, 491, 499, 503,
X509, 521, 523, 541, 547, 557, 563, 569, 571, 577, 587, 593, 599, 601, 607,
X613, 617, 619, 631, 641, 643, 647, 653, 659, 661, 673, 677, 683, 691, 701,
X709, 719, 727, 733, 739, 743, 751, 757, 761, 769, 773, 787, 797, 809, 811,
X821, 823, 827, 829, 839, 853, 857, 859, 863, 877, 881, 883, 887, 907, 911,
X919, 929, 937, 941, 947, 953, 967, 971, 977, 983, 991, 997, 1009, 1013, 1019,
X1021, 1031, 1033, 1039, 1049, 1051, 1061, 1063, 1069, 1087, 1091, 1093, 1097,
X1103, 1109, 1117, 1123, 1129, 1151, 1153, 1163, 1171, 1181, 1187, 1193, 1201,
X1213, 1217, 1223, 1229, 1231, 1237, 1249, 1259, 1277, 1279, 1283, 1289, 1291,
X1297, 1301, 1303, 1307, 1319, 1321, 1327, 1361, 1367, 1373, 1381, 1399, 1409,
X1423, 1427, 1429, 1433, 1439, 1447, 1451, 1453, 1459, 1471, 1481, 1483, 1487,
X1489, 1493, 1499, 1511, 1523, 1531, 1543, 1549, 1553, 1559, 1567, 1571, 1579,
X1583, 1597, 1601, 1607, 1609, 1613, 1619, 1621, 1627, 1637, 1657, 1663, 1667,
X1669, 1693, 1697, 1699, 1709, 1721, 1723, 1733, 1741, 1747, 1753, 1759, 1777,
X1783, 1787, 1789, 1801, 1811, 1823, 1831, 1847, 1861, 1867, 1871, 1873, 1877,
X1879, 1889, 1901, 1907, 1913, 1931, 1933, 1949, 1951, 1973, 1979, 1987, 1993,
X1997, 1999, 2003, 2011, 2017, 2027, 2029, 2039, 2053, 2063, 2069, 2081, 2083,
X2087, 2089, 2099, 2111, 2113, 2129, 2131, 2137, 2141, 2143, 2153, 2161, 2179,
X2203, 2207, 2213, 2221, 2237, 2239, 2243, 2251, 2267, 2269, 2273, 2281, 2287,
X2293, 2297, 2309, 2311, 2333, 2339, 2341, 2347, 2351, 2357, 2371, 2377, 2381,
X2383, 2389, 2393, 2399, 2411, 2417, 2423, 2437, 2441, 2447, 2459, 2467, 2473,
X2477, 2503, 2521, 2531, 2539, 2543, 2549, 2551, 2557, 2579, 2591, 2593, 2609,
X2617, 2621, 2633, 2647, 2657, 2659, 2663, 2671, 2677, 2683, 2687, 2689, 2693,
X2699, 2707, 2711, 2713, 2719, 2729, 2731, 2741, 2749, 2753, 2767, 2777, 2789,
X2791, 2797, 2801, 2803, 2819, 2833, 2837, 2843, 2851, 2857, 2861, 2879, 2887,
X2897, 2903, 2909, 2917, 2927, 2939, 2953, 2957, 2963, 2969, 2971, 2999, 3001,
X3011, 3019, 3023, 3037, 3041, 3049, 3061, 3067, 3079, 3083, 3089, 3109, 3119,
X3121, 3137, 3163, 3167, 3169, 3181, 3187, 3191, 3203, 3209, 3217, 3221, 3229,
X3251, 3253, 3257, 3259, 3271, 3299, 3301, 3307, 3313, 3319, 3323, 3329, 3331,
X3343, 3347, 3359, 3361, 3371, 3373, 3389, 3391, 3407, 3413, 3433, 3449, 3457,
X3461, 3463, 3467, 3469, 3491, 3499, 3511, 3517, 3527, 3529, 3533, 3539, 3541,
X3547, 3557, 3559, 3571, 3581, 3583, 3593, 3607, 3613, 3617, 3623, 3631, 3637,
X3643, 3659, 3671, 3673, 3677, 3691, 3697, 3701, 3709, 3719, 3727, 3733, 3739,
X3761, 3767, 3769, 3779, 3793, 3797, 3803, 3821, 3823, 3833, 3847, 3851, 3853,
X3863, 3877, 3881, 3889, 3907, 3911, 3917, 3919, 3923, 3929, 3931, 3943, 3947,
X3967, 3989, 4001, 4003, 4007, 4013, 4019, 4021, 4027, 4049, 4051, 4057, 4073,
X4079, 4091, 4093, 4099, 4111, 4127, 4129, 4133, 4139, 4153, 4157, 4159, 4177,
X4201, 4211, 4217, 4219, 4229, 4231, 4241, 4243, 4253, 4259, 4261, 4271, 4273,
X4283, 4289, 4297, 4327, 4337, 4339, 4349, 4357, 4363, 4373, 4391, 4397, 4409,
X4421, 4423, 4441, 4447, 4451, 4457, 4463, 4481, 4483, 4493, 4507, 4513, 4517,
X4519, 4523, 4547, 4549, 4561, 4567, 4583, 4591, 4597, 4603, 4621, 4637, 4639,
X4643, 4649, 4651, 4657, 4663, 4673, 4679, 4691, 4703, 4721, 4723, 4729, 4733,
X4751, 4759, 4783, 4787, 4789, 4793, 4799, 4801, 4813, 4817, 4831, 4861, 4871,
X4877, 4889, 4903, 4909, 4919, 4931, 4933, 4937, 4943, 4951, 4957, 4967, 4969,
X4973, 4987, 4993, 4999, 5003, 5009, 5011, 5021, 5023, 5039, 5051, 5059, 5077,
X5081, 5087, 5099, 5101, 5107, 5113, 5119, 5147, 5153, 5167, 5171, 5179, 5189,
X5197, 5209, 5227, 5231, 5233, 5237, 5261, 5273, 5279, 5281, 5297, 5303, 5309,
X5323, 5333, 5347, 5351, 5381, 5387, 5393, 5399, 5407, 5413, 5417, 5419, 5431,
X5437, 5441, 5443, 5449, 5471, 5477, 5479, 5483, 5501, 5503, 5507, 5519, 5521,
X5527, 5531, 5557, 5563, 5569, 5573, 5581, 5591, 5623, 5639, 5641, 5647, 5651,
X5653, 5657, 5659, 5669, 5683, 5689, 5693, 5701, 5711, 5717, 5737, 5741, 5743,
X5749, 5779, 5783, 5791, 5801, 5807, 5813, 5821, 5827, 5839, 5843, 5849, 5851,
X5857, 5861, 5867, 5869, 5879, 5881, 5897, 5903, 5923, 5927, 5939, 5953, 5981,
X5987, 6007, 6011, 6029, 6037, 6043, 6047, 6053, 6067, 6073, 6079, 6089, 6091,
X6101, 6113, 6121, 6131, 6133, 6143, 6151, 6163, 6173, 6197, 6199, 6203, 6211,
X6217, 6221, 6229, 6247, 6257, 6263, 6269, 6271, 6277, 6287, 6299, 6301, 6311,
X6317, 6323, 6329, 6337, 6343, 6353, 6359, 6361, 6367, 6373, 6379, 6389, 6397,
X6421, 6427, 6449, 6451, 6469, 6473, 6481, 6491, 6521, 6529, 6547, 6551, 6553,
X6563, 6569, 6571, 6577, 6581, 6599, 6607, 6619, 6637, 6653, 6659, 6661, 6673,
X6679, 6689, 6691, 6701, 6703, 6709, 6719, 6733, 6737, 6761, 6763, 6779, 6781,
X6791, 6793, 6803, 6823, 6827, 6829, 6833, 6841, 6857, 6863, 6869, 6871, 6883,
X6899, 6907, 6911, 6917, 6947, 6949, 6959, 6961, 6967, 6971, 6977, 6983, 6991,
X6997, 7001, 7013, 7019, 7027, 7039, 7043, 7057, 7069, 7079, 7103, 7109, 7121,
X7127, 7129, 7151, 7159, 7177, 7187, 7193, 7207, 7211, 7213, 7219, 7229, 7237,
X7243, 7247, 7253, 7283, 7297, 7307, 7309, 7321, 7331, 7333, 7349, 7351, 7369,
X7393, 7411, 7417, 7433, 7451, 7457, 7459, 7477, 7481, 7487, 7489, 7499, 7507,
X7517, 7523, 7529, 7537, 7541, 7547, 7549, 7559, 7561, 7573, 7577, 7583, 7589,
X7591, 7603, 7607, 7621, 7639, 7643, 7649, 7669, 7673, 7681, 7687, 7691, 7699,
X7703, 7717, 7723, 7727, 7741, 7753, 7757, 7759, 7789, 7793, 7817, 7823, 7829,
X7841, 7853, 7867, 7873, 7877, 7879, 7883, 7901, 7907, 7919, 7927, 7933, 7937,
X7949, 7951, 7963, 7993, 8009, 8011, 8017, 8039, 8053, 8059, 8069, 8081, 8087,
X8089, 8093, 8101, 8111, 8117, 8123, 8147, 8161, 8167, 8171, 8179, 8191, 8209,
X8219, 8221, 8231, 8233, 8237, 8243, 8263, 8269, 8273, 8287, 8291, 8293, 8297,
X8311, 8317, 8329, 8353, 8363, 8369, 8377, 8387, 8389, 8419, 8423, 8429, 8431,
X8443, 8447, 8461, 8467, 8501, 8513, 8521, 8527, 8537, 8539, 8543, 8563, 8573,
X8581, 8597, 8599, 8609, 8623, 8627, 8629, 8641, 8647, 8663, 8669, 8677, 8681,
X8689, 8693, 8699, 8707, 8713, 8719, 8731, 8737, 8741, 8747, 8753, 8761, 8779,
X8783, 8803, 8807, 8819, 8821, 8831, 8837, 8839, 8849, 8861, 8863, 8867, 8887,
X8893, 8923, 8929, 8933, 8941, 8951, 8963, 8969, 8971, 8999, 9001, 9007, 9011,
X9013, 9029, 9041, 9043, 9049, 9059, 9067, 9091, 9103, 9109, 9127, 9133, 9137,
X9151, 9157, 9161, 9173, 9181, 9187, 9199, 9203, 9209, 9221, 9227, 9239, 9241,
X9257, 9277, 9281, 9283, 9293, 9311, 9319, 9323, 9337, 9341, 9343, 9349, 9371,
X9377, 9391, 9397, 9403, 9413, 9419, 9421, 9431, 9433, 9437, 9439, 9461, 9463,
X9467, 9473, 9479, 9491, 9497, 9511, 9521, 9533, 9539, 9547, 9551, 9587, 9601,
X9613, 9619, 9623, 9629, 9631, 9643, 9649, 9661, 9677, 9679, 9689, 9697, 9719,
X9721, 9733, 9739, 9743, 9749, 9767, 9769, 9781, 9787, 9791, 9803, 9811, 9817,
X9829, 9833, 9839, 9851, 9857, 9859, 9871, 9883, 9887, 9901, 9907, 9923, 9929,
X9931, 9941, 9949, 9967, 9973, 10007, 10009, 10037, 10039, 10061, 10067, 10069,
X10079, 10091, 10093, 10099, 10103, 10111, 10133, 10139, 10141, 10151, 10159,
X10163, 10169, 10177, 10181, 10193, 10211, 10223, 10243, 10247, 10253, 10259,
X10267, 10271, 10273, 10289, 10301, 10303, 10313, 10321, 10331, 10333, 10337,
X10343, 10357, 10369, 10391, 10399, 10427, 10429, 10433, 10453, 10457, 10459,
X10463, 10477, 10487, 10499, 10501, 10513, 10529, 10531, 10559, 10567, 10589,
X10597, 10601, 10607, 10613, 10627, 10631, 10639, 10651, 10657, 10663, 10667,
X10687, 10691, 10709, 10711, 10723, 10729, 10733, 10739, 10753, 10771, 10781,
X10789, 10799, 10831, 10837, 10847, 10853, 10859, 10861, 10867, 10883, 10889,
X10891, 10903, 10909, 10937, 10939, 10949, 10957, 10973, 10979, 10987, 10993,
X11003, 11027, 11047, 11057, 11059, 11069, 11071, 11083, 11087, 11093, 11113,
X11117, 11119, 11131, 11149, 11159, 11161, 11171, 11173, 11177, 11197, 11213,
X11239, 11243, 11251, 11257, 11261, 11273, 11279, 11287, 11299, 11311, 11317,
X11321, 11329, 11351, 11353, 11369, 11383, 11393, 11399, 11411, 11423, 11437,
X11443, 11447, 11467, 11471, 11483, 11489, 11491, 11497, 11503, 11519, 11527,
X11549, 11551, 11579, 11587, 11593, 11597, 11617, 11621, 11633, 11657, 11677,
X11681, 11689, 11699, 11701, 11717, 11719, 11731, 11743, 11777, 11779, 11783,
X11789, 11801, 11807, 11813, 11821, 11827, 11831, 11833, 11839, 11863, 11867,
X11887, 11897, 11903, 11909, 11923, 11927, 11933, 11939, 11941, 11953, 11959,
X11969, 11971, 11981, 11987, 12007, 12011, 12037, 12041, 12043, 12049, 12071,
X12073, 12097, 12101, 12107, 12109, 12113, 12119, 12143, 12149, 12157, 12161,
X12163, 12197, 12203, 12211, 12227, 12239, 12241, 12251, 12253, 12263, 12269,
X12277, 12281, 12289, 12301, 12323, 12329, 12343, 12347, 12373, 12377, 12379,
X12391, 12401, 12409, 12413, 12421, 12433, 12437, 12451, 12457, 12473, 12479,
X12487, 12491, 12497, 12503, 12511, 12517, 12527, 12539, 12541, 12547, 12553,
X12569, 12577, 12583, 12589, 12601, 12611, 12613, 12619, 12637, 12641, 12647,
X12653, 12659, 12671, 12689, 12697, 12703, 12713, 12721, 12739, 12743, 12757,
X12763, 12781, 12791, 12799, 12809, 12821, 12823, 12829, 12841, 12853, 12889,
X12893, 12899, 12907, 12911, 12917, 12919, 12923, 12941, 12953, 12959, 12967,
X12973, 12979, 12983, 13001, 13003, 13007, 13009, 13033, 13037, 13043, 13049,
X13063, 13093, 13099, 13103, 13109, 13121, 13127, 13147, 13151, 13159, 13163,
X13171, 13177, 13183, 13187, 13217, 13219, 13229, 13241, 13249, 13259, 13267,
X13291, 13297, 13309, 13313, 13327, 13331, 13337, 13339, 13367, 13381, 13397,
X13399, 13411, 13417, 13421, 13441, 13451, 13457, 13463, 13469, 13477, 13487,
X13499, 13513, 13523, 13537, 13553, 13567, 13577, 13591, 13597, 13613, 13619,
X13627, 13633, 13649, 13669, 13679, 13681, 13687, 13691, 13693, 13697, 13709,
X13711, 13721, 13723, 13729, 13751, 13757, 13759, 13763, 13781, 13789, 13799,
X13807, 13829, 13831, 13841, 13859, 13873, 13877, 13879, 13883, 13901, 13903,
X13907, 13913, 13921, 13931, 13933, 13963, 13967, 13997, 13999, 14009, 14011,
X14029, 14033, 14051, 14057, 14071, 14081, 14083, 14087, 14107, 14143, 14149,
X14153, 14159, 14173, 14177, 14197, 14207, 14221, 14243, 14249, 14251, 14281,
X14293, 14303, 14321, 14323, 14327, 14341, 14347, 14369, 14387, 14389, 14401,
X14407, 14411, 14419, 14423, 14431, 14437, 14447, 14449, 14461, 14479, 14489,
X14503, 14519, 14533, 14537, 14543, 14549, 14551, 14557, 14561, 14563, 14591,
X14593, 14621, 14627, 14629, 14633, 14639, 14653, 14657, 14669, 14683, 14699,
X14713, 14717, 14723, 14731, 14737, 14741, 14747, 14753, 14759, 14767, 14771,
X14779, 14783, 14797, 14813, 14821, 14827, 14831, 14843, 14851, 14867, 14869,
X14879, 14887, 14891, 14897, 14923, 14929, 14939, 14947, 14951, 14957, 14969,
X14983, 15013, 15017, 15031, 15053, 15061, 15073, 15077, 15083, 15091, 15101,
X15107, 15121, 15131, 15137, 15139, 15149, 15161, 15173, 15187, 15193, 15199,
X15217, 15227, 15233, 15241, 15259, 15263, 15269, 15271, 15277, 15287, 15289,
X15299, 15307, 15313, 15319, 15329, 15331, 15349, 15359, 15361, 15373, 15377,
X15383, 15391, 15401, 15413, 15427, 15439, 15443, 15451, 15461, 15467, 15473,
X15493, 15497, 15511, 15527, 15541, 15551, 15559, 15569, 15581, 15583, 15601,
X15607, 15619, 15629, 15641, 15643, 15647, 15649, 15661, 15667, 15671, 15679,
X15683, 15727, 15731, 15733, 15737, 15739, 15749, 15761, 15767, 15773, 15787,
X15791, 15797, 15803, 15809, 15817, 15823, 15859, 15877, 15881, 15887, 15889,
X15901, 15907, 15913, 15919, 15923, 15937, 15959, 15971, 15973, 15991, 16001,
X16007, 16033, 16057, 16061, 16063, 16067, 16069, 16073, 16087, 16091, 16097,
X16103, 16111, 16127, 16139, 16141, 16183, 16187, 16189, 16193, 16217, 16223,
X16229, 16231, 16249, 16253, 16267, 16273, 16301, 16319, 16333, 16339, 16349,
X16361, 16363, 16369, 16381
X};
X
X/* hcreate --- create a hash table at least howmany big */
X
Xint hcreate (howmany)
Xregister unsigned int howmany;
X{
X register int i, j;
X
X /*
X * find first prime number >= howmany, and use it for table size
X */
X
X if (Num_elem != -1) /* already a table out there */
X hdestroy(); /* remove it */
X
X j = sizeof (primetab) / sizeof (primetab[0]);
X for (i = 0; i < j; i++)
X if (primetab[i] >= howmany)
X break;
X
X if (i >= j) /* howmany bigger than any prime we have, use it */
X Num_elem = howmany;
X else
X Num_elem = primetab[i];
X
X if ((Table = (ELEMENT **) calloc (Num_elem, sizeof (ELEMENT *))) == NULL)
X return (0);
X else
X return (1);
X}
X
X/* idestroy --- destroy a single element on a chain */
X
Xstatic void idestroy (elem)
XELEMENT *elem;
X{
X if (elem != NULL)
X {
X idestroy (elem->next);
X free ((char *) elem);
X }
X}
X
X/* hdestroy --- nuke the existing hash table */
X
Xvoid hdestroy()
X{
X register unsigned int i;
X
X if (Table != NULL)
X {
X /* free all the chains */
X for (i = 0; i < Num_elem; i++)
X idestroy (Table[i]);
X
X /* now the table itself */
X free ((char *) Table);
X Num_elem = -1;
X Table = NULL;
X }
X}
X
X/* hsearch --- lookup or enter an item in the hash table */
X
XENTRY *hsearch (entry, action)
XENTRY entry;
XACTION action;
X{
X ELEMENT e;
X ELEMENT *ep = NULL;
X ELEMENT *ep2 = NULL;
X int index;
X
X if (Table == NULL)
X return (NULL);
X
X index = hashit (entry.key);
X if (Table[index] == NULL) /* nothing there */
X {
X if (action == FIND)
X return (NULL);
X else
X {
X /* add it to the table */
X e.item = entry;
X e.next = NULL;
X if ((Table[index] = (ELEMENT *) calloc (1, sizeof (ELEMENT))) == NULL)
X return (NULL);
X *Table[index] = e;
X return (& Table[index]->item);
X }
X }
X else
X {
X /* something in bucket, see if already on chain */
X for (ep = Table[index]; ep != NULL; ep = ep->next)
X {
X if (strcmp (ep->item.key, entry.key) == 0)
X {
X if (action == ENTER)
X ep->item.data = entry.data;
X /* already there, just change data */
X /* or action was just find it */
X return (& ep->item);
X }
X else
X ep2 = ep;
X }
X /* at this point, item was not in table */
X /* ep2 points at last element on the list */
X if (action == ENTER)
X {
X if ((ep2->next = (ELEMENT *) calloc (1, sizeof (ELEMENT))) == NULL)
X return (NULL);
X ep2->next->item = entry;
X ep2->next->next = NULL;
X return (& ep2->next->item);
X }
X else
X return (NULL);
X }
X /*NOTREACHED*/
X}
X
X/* hashit --- do the hashing algorithm */
X
X/*
X * algorithm is sum of string elements, plus string length
X * mod table size.
X *
X * made case insensitive for hyphenation program
X */
X
Xstatic int hashit (text)
Xregister char *text;
X{
X register long int sum = 0;
X register int i;
X register int kludge;
X
X for (i = 0; (kludge = text[i]) != '\0'; i++)
X sum += (isupper(kludge) ? tolower(kludge) : kludge);
X sum += i;
X
X return (sum % Num_elem);
X}
X
END_OF_hsearch.c
if test 15412 -ne `wc -c <hsearch.c`; then
echo shar: \"hsearch.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f hsearch.h -a "${1}" != "-c" ; then
echo shar: Will not over-write existing file \"hsearch.h\"
else
echo shar: Extracting \"hsearch.h\" \(445 characters\)
sed "s/^X//" >hsearch.h <<'END_OF_hsearch.h'
X/* hsearch.c --- PD simple implementation of System V hsearch(3c) routine */
X
X/*
X* All I (WZV) changed was:
X* put this part of the original hsearch.c in a separate file
X* make the lookup and hashing algorithms case-insensitive
X*/
X
X#include <stdio.h>
X
Xtypedef struct entry {
X char *key;
X char *data;
X } ENTRY;
X
Xtypedef enum {
X FIND,
X ENTER
X } ACTION;
X
Xtypedef struct element {
X ENTRY item;
X struct element *next;
X } ELEMENT;
X
XENTRY *hsearch();
END_OF_hsearch.h
if test 445 -ne `wc -c <hsearch.h`; then
echo shar: \"hsearch.h\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f pager.c -a "${1}" != "-c" ; then
echo shar: Will not over-write existing file \"pager.c\"
else
echo shar: Extracting \"pager.c\" \(14137 characters\)
sed "s/^X//" >pager.c <<'END_OF_pager.c'
X/*++
X/* NAME
X/* pager 3
X/* SUMMARY
X/* pager for text files
X/* PROJECT
X/* pc-mail
X/* PACKAGE
X/* mailsh
X/* SYNOPSIS
X/* #include "pager.h"
X/*
X/* File *open_pager()
X/*
X/* void close_pager(p)
X/* File *p;
X/*
X/* void set_pager(p)
X/* File *p;
X/*
X/* void app_pager(p,s)
X/* File *p;
X/* char *s;
X/*
X/* void del_pager(p)
X/* File *p;
X/*
X/* void mesg_pager(p,m)
X/* File *p;
X/* char *m[];
X/*
X/* int scan_pager(p,fmt[,args])
X/* File *p;
X/*
X/* void sort_pager(p,dir)
X/* File *p;
X/*
X/* int cp_pager(path)
X/* char *path;
X/*
X/* int pr_pager()
X/*
X/* int rd_pager(p,path)
X/* File *p;
X/* char *path;
X/*
X/* char *gets_pager();
X/*
X/* void puts_pager(s);
X/* char *s;
X/*
X/* int ds_pager()
X/*
X/* int pr_pager()
X/*
X/* int up_pager()
X/*
X/* int dn_pager()
X/*
X/* int pu_pager()
X/*
X/* int pd_pager()
X/* DESCRIPTION
X/* The pager provides acces to a pager file which is displayed
X/* on the screen in the middle window. Some functions operate
X/* on what is called the "current" pager file. All functions
X/* have access to the contents of the middle screen window only.
X/*
X/* open_pager() creates a new (empty) pager file. The return value
X/* should be used in subsequent accesses to the file. Sets the
X/* current file.
X/*
X/* close_pager() releases storage for a pager file. Sets the
X/* current file to none if that is the one being deleted.
X/*
X/* app_pager() appends a new line of text to the end of a pager file.
X/* Sets the current file.
X/*
X/* del_pager() deletes the line at the current cursor position. Sets the
X/* current file.
X/*
X/* mesg_pager() invokes app_pager() to copy a null-terminated array of
X/* strings to a pager file. Since it invokes app_pager(), the current
X/* pager file is set as well. Pager files filled by mesg-pager()
X/* will not be displayed with an '-- end of display --' line at their end.
X/*
X/* ins_pager() inserts a line at the current cursor position. Sets the
X/* current file.
X/*
X/* scan_pager() takes similar arguments as scanf(3), reads from the
X/* line at the current cursor position and returns the number of
X/* successfull conversions done. Does not set the current file.
X/*
X/* sort_pager() sorts a file alphabetically. Sets the current file.
X/* The dir argument selects the direction of sort (FORW_SORT, BACK_SORT).
X/*
X/* set_pager() sets the current file.
X/*
X/* gets_pager() returns a pointer to the current line in the
X/* current file, or a null pointer is there is none.
X/*
X/* puts_pager() replaces the current line in the current file.
X/*
X/* cp_pager() copies the contents of current pager file
X/* to a normal (external) file. It returns a nonzero status if
X/* an error occurred (bad path, write error,...).
X/*
X/* pr_pager() copies the current pager file to the printer.
X/*
X/* rd_pager() appends a permanent file to the current pager file.
X/* It returns a nonzero status if an error occurred. Sets the current file.
X/* rd_pager() reads through the ascf(3) ascii filter, so that it is
X/* suitable for viewing word-processor files.
X/*
X/* up_pager() moves the cursor one line up, if there is one. The
X/* screen is scrolled when the cursor was at the top of the screen.
X/*
X/* dn_pager moves the cursor one line down, if there is one. The
X/* screen is scrolled when the cursor was at the bottom of the screen.
X/*
X/* pu_pager() displays a page of text that precedes the one on the
X/* screen, or as much as there is.
X/*
X/* pd_pager() displays the next page of text, or as much as there is.
X/* FUNCTIONS AND MACROS
X/* printcl(), printat(), beep(), propen(), prclose(),ascopen(),
X/* ascclose(), ascget()
X/* SEE ALSO
X/* path(3), window(3), window(5), asc(3)
X/* DIAGNOSTICS
X/* The buzzer makes noise when attempt is made to move the
X/* cursor beyond the beginning or end of the pager file.
X/* The program aborts with an error message if references are made
X/* to the "current file" or "current line" if there is none.
X/* BUGS
X/* It looks a lot like an editor, but it isn't.
X/*
X/* No optimization. It just overwrites the whole middle window.
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/* Fri Apr 3 22:06:00 GMT+1:00 1987
X/* LAST MODIFICATION
X/* Mon Apr 4 23:46:06 MET 1988
X/* VERSION/RELEASE
X/* 1.3
X/*--*/
X
X#include "defs.h"
X#include "window.h"
X#include "pager.h"
X#include "path.h"
X#include "ascf.h"
X
Xhidden File *curfile = NULL; /* head of the current file */
X
X/* open_pager - create pager file and set current file */
X
Xpublic File *open_pager()
X{
X register File *p = curfile = (File *) myalloc(sizeof(File));
X
X p->top = p->curr = p->head = p->last = NULL;
X p->opts = 0;
X return(p);
X}
X
X/* close_pager - release memory in a pager file */
X
Xpublic void close_pager(p)
Xregister File *p;
X{
X register Line *q;
X
X if (p) {
X for (q = p->head; q; q = q->next) /* release lines */
X free((char *)q);
X if (curfile == p) /* unset current file */
X curfile = 0;
X free((char *)p); /* release header */
X }
X}
X
X/* app_pager - append line at end of file and set current file */
X
Xpublic app_pager(p,s)
Xregister File *p;
Xchar *s;
X{
X register Line *l = (Line *) myalloc(sizeof(Line)+strlen(s));
X
X if (p->head == 0) { /* first line in the file */
X p->head = p->top = p->curr = l;
X } else { /* real append */
X p->last->next = l;
X }
X l->next = NULL; /* since it is last */
X l->prev = p->last; /* since it is last */
X p->last = l; /* since it is last */
X
X strcpy(l->line,s); /* copy the line */
X
X curfile = p; /* set current file */
X}
X
X/* del_pager - delete line at cursor and set current file (untested!) */
X
Xpublic void del_pager(p)
Xregister File *p;
X{
X register Line *l = p->curr;
X
X if (l) {
X if (l->prev)
X l->prev->next = l->next;
X if (l->next)
X l->next->prev = l->prev;
X if (l == p->head)
X p->curr = p->head = l->next;
X if (l == p->top)
X p->curr = p->top = l->next ? l->next : l->prev;
X if (l == p->last)
X p->curr = p->last = l->prev;
X if (l == p->curr)
X p->curr = l->next;
X free((char *) l);
X }
X curfile = p;
X}
X
X/* scan_pager - read from line at cursor and set current file */
X
X/* VARARGS2 */
X
Xpublic int scan_pager(p,fmt,a1,a2,a3,a4)
XFile *p;
Xchar *fmt;
Xlong a1,a2,a3,a4;
X{
X return(p && p->curr ? sscanf(p->curr->line,fmt,a1,a2,a3,a4) : 0);
X}
X
X/* set_pager - set the current file; use with care */
X
Xpublic void set_pager(p)
XFile *p;
X{
X curfile = p;
X}
X
X/*
X* The following functions provide an easy interface to the keyboard
X* interpreter routines. The keyboard driver just associates a key stroke
X* with a function call, does not care what a function does and has
X* almost no facility for passing function arguments.
X* Although the keyboard interpreter manipulates cursor and page coordinates
X* when the some keys are hit, it never knows which keys affect what
X* the user sees on the screen.
X* That explains why the following functions rely on the above ones
X* for setting the "current file".
X* It may also explain why the above routines do not immediately update
X* the terminal screen, whereas the routines below do.
X*/
X
X/* ds_pager - display a page of the current pager file */
X
Xpublic int ds_pager()
X{
X static char endline[] = "-- end of display --";
X
X if (curfile && curfile->curr) {
X register Line *p;
X register int k;
X
X for (p = curfile->top,k = 0; p && k < wsize[MID]; p = p->next)
X k += p->llen = printcl(MID,p->lineno = k,p->line);
X if (k < wsize[MID])
X printcl(MID,k++,(curfile->opts & PG_NOEND) ? "" : endline);
X while (k < wsize[MID])
X printcl(MID,k++,"");
X printat(MID,curfile->curr->lineno,"");
X } else {
X register int k;
X
X printcl(MID,0,(curfile->opts & PG_NOEND) ? "" : endline);
X for (k = 1; k < wsize[MID]; k++)
X printcl(MID,k,"");
X printat(MID,0,"");
X }
X return(0); /* screen up-to-date */
X}
X
X/* up_pager - up-arrow key hit. check cursor position */
X
Xpublic int up_pager()
X{
X register Line *p = curfile ? curfile->curr : 0;
X
X if (p == 0 || p->prev == 0) {
X beep();
X } else {
X if (p->lineno == 0)
X pu_pager();
X printat(MID,(curfile->curr = p->prev)->lineno,"");
X }
X return(0);
X}
X
X/* dn_pager - down-arrow key hit. check cursor position */
X
Xpublic int dn_pager()
X{
X register Line *p = curfile ? curfile->curr : 0;
X
X if (p == 0 || p->next == 0) {
X beep();
X } else {
X if (p->lineno+p->llen >= wsize[MID])
X pd_pager();
X printat(MID,(curfile->curr = p->next)->lineno,"");
X }
X return(0);
X}
X
X/* pu_pager - display preceding page of info */
X
Xpublic int pu_pager()
X{
X register Line *p;
X register int k;
X
X if (curfile && (p = curfile->top) && curfile->top->prev) {
X for (k = 0; k < wsize[MID] && p; k += p->llen,p = p->prev)
X curfile->top = p;
X curfile->curr = curfile->top;
X ds_pager();
X } else {
X beep();
X }
X return(0);
X}
X
X/* pd_pager - display next page of info */
X
Xpublic int pd_pager()
X{
X register Line *p = curfile ? curfile->top : 0;
X register int k;
X register Line *dummy;
X
X for (k = 0; k < wsize[MID] && p; k += p->llen,p = p->next)
X dummy = p;
X if (p) {
X curfile->curr = curfile->top = dummy;
X ds_pager();
X } else {
X beep();
X }
X return(0);
X}
X
X/*
X* The following functions copy permanent files to pager file
X* and vice-versa. There is a limited error detection facility
X* in the form of nonzero return values.
X*/
X
X/* cp_pager - copy current pager file to permanent file */
X
Xpublic int cp_pager(path)
Xchar *path;
X{
X register FILE *fp;
X
X if (curfile && (fp = fopen(path,"w"))) {
X register Line *pp;
X int err;
X for (pp = curfile->head; pp; pp = pp->next)
X fputs(pp->line,fp),putc('\n',fp);
X err = ferror(fp);
X fclose(fp);
X return(err);
X } else {
X return(-1);
X }
X}
X
X/* pr_pager - print pager file on default printer */
X
Xpublic int pr_pager()
X{
X register FILE *fp;
X
X if (curfile && (fp = propen())) {
X register Line *pp;
X int err;
X for (pp = curfile->head; pp; pp = pp->next)
X fputs(pp->line,fp),putc('\n',fp);
X err = ferror(fp);
X prclose(fp);
X return(err);
X } else {
X return(-1);
X }
X}
X
X/* rd_pager - copy ordinary file via filter to pager file */
X
Xpublic int rd_pager(p,path)
XFile *p;
Xchar *path;
X{
X register FILE *fp;
X
X if (p && (fp = ascopen(path,"r"))) { /* init the filter */
X char buf[BUFSIZ];
X char *cp = buf;
X register int c;
X int err;
X
X while ((c = ascget(fp)) != EOF) { /* copy to pager file */
X if (c == '\n' || cp == buf+BUFSIZ-1) {
X *cp = 0;
X app_pager(p,cp = buf); /* line by line */
X } else {
X *cp++ = c;
X }
X }
X if (cp > buf) { /* anything left? */
X *cp = '\0';
X app_pager(p,buf);
X }
X err = ferror(fp); /* check for errors */
X ascclose(fp);
X return(err);
X } else {
X return(-1);
X }
X}
X
X/* fwdcmp, revcmp - compare lexical order of lines */
X
Xhidden int fwdcmp(l1,l2)
XLine **l1,**l2;
X{
X return(strcmp((*l1)->line,(*l2)->line));
X}
X
Xhidden int revcmp(l1,l2)
XLine **l1,**l2;
X{
X return(strcmp((*l2)->line,(*l1)->line));
X}
X
X/* sort_pager - sort a pager file, a boring thing */
X
Xpublic void sort_pager(pp,dir)
XFile *pp;
Xint dir;
X{
X register Line *l;
X register int i;
X int lines;
X Line **lvec;
X
X for (i = 0,l = pp->head; l; l = l->next) /* count nbr of lines */
X i++;
X
X if (i <= 1) /* no work */
X return;
X
X lvec = (Line **) myalloc((lines = i)*sizeof(*lvec));/* allocate vector */
X
X for (i = 0,l = pp->head; l; l = l->next) /* fill vector */
X lvec[i++] = l;
X
X qsort((char *) lvec,lines,sizeof(*lvec),dir == FORW_SORT ? fwdcmp : revcmp);
X
X for (i = 0; i < lines-1; i++) /* fix forward links */
X lvec[i]->next = lvec[i+1];
X lvec[i]->next = NULL;
X
X lvec[0]->prev = NULL; /* fix backward links */
X for (i = 1; i < lines; i++)
X lvec[i]->prev = lvec[i-1];
X
X pp->head = pp->top = pp->curr = lvec[0]; /* fix file header */
X pp->last = lvec[lines-1];
X
X free((char *) lvec); /* release vector */
X
X curfile = pp; /* set current file */
X}
X
X/* gets_pager - return current line in current file */
X
Xpublic char *gets_pager()
X{
X return(curfile && curfile->curr ? curfile->curr->line : 0);
X}
X
X/* puts_pager - replace line (cleanup this mess) */
X
Xpublic void puts_pager(s)
Xchar *s;
X{
X if (curfile == 0 || curfile->curr == 0) { /* no-no if there is no line */
X fatal("puts_pager: no current file");
X } else {
X register Line *old = curfile->curr; /* get current line */
X register Line *new = (Line *) myalloc(sizeof(Line)+strlen(s));
X new->prev = old->prev; /* fill it in */
X new->next = old->next;
X new->lineno = old->lineno;
X strcpy(new->line,s);
X if (new->next) /* check next line */
X new->next->prev = new;
X if (new->prev) /* check previous line */
X new->prev->next = new;
X if (old == curfile->head) /* check file head */
X curfile->head = new;
X if (old == curfile->top) /* check file display */
X curfile->top = new;
X if (old == curfile->last) /* check file tail */
X curfile->last = new;
X free((char *) curfile->curr); /* release old line */
X curfile->curr = new; /* set current line */
X }
X}
X
X/* mesg_pager - copy null-terminated array of strings to pager file */
X
Xpublic void mesg_pager(pp,msg)
Xregister File *pp;
Xregister char **msg;
X{
X pp->opts |= PG_NOEND; /* suppress end marker */
X
X while (*msg)
X app_pager(pp,*msg++);
X}
END_OF_pager.c
if test 14137 -ne `wc -c <pager.c`; then
echo shar: \"pager.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
echo shar: End of archive 1 \(of 8\).
cp /dev/null ark1isdone
MISSING=""
for I in 1 2 3 4 5 6 7 8 ; do
if test ! -f ark${I}isdone ; then
MISSING="${MISSING} ${I}"
fi
done
if test "${MISSING}" = "" ; then
echo You have unpacked all 8 archives.
rm -f ark[1-9]isdone
else
echo You still need to unpack the following archives:
echo " " ${MISSING}
fi
## End of shell archive.
exit 0
--
uucp: mcvax!eutrc3!wswietse | Eindhoven University of Technology
bitnet: wswietse at heithe5 | Dept. of Mathematics and Computer Science
surf: tuerc5::wswietse | Eindhoven, The Netherlands.
More information about the Comp.sources.misc
mailing list