[comp.sys.ti] a vt100 emulator in Turbo C

pkern@csri.toronto.edu (pkern) (06/07/88)

Here's something I put together to try to get some "real" use out
of the TI Professional sitting on my desk. It seems to be fairly reliable.
It only causes the Pro to hang about once out of every 15 tries. (1/2 :-)
I'm hoping that's because of the Turbo C 1.0 bugs I keep hearing about.

Duck! Here it comes.
----------------------------------------------------------------------------
#! /bin/sh
# This is a shell archive, meaning:
# 1. Remove everything above the #! /bin/sh line.
# 2. Save the resulting text in a file.
# 3. Execute the file with /bin/sh (not csh) to create the files:
#	README
#	DOC
#	Makefile
#	screen.c
#	ports.c
#	keybrd.c
#	gfx.c
#	tipro.h
# This archive created: Tue Jun  7 11:19:24 1988
# By:	pkern ()
export PATH; PATH=/bin:$PATH
echo shar: extracting "'README'" '(5460 characters)'
if test -f 'README'
then
	echo shar: will not over-write existing file "'README'"
else
sed 's/^X//' << \SHAR_EOF > 'README'
X	Cterm  -  a vt100 emulator written in Turbo C.
X
XCterm is actually more of an XT100+ emulator since it includes some
XLanpar extensions. Cterm was written mainly because there weren't
Xany easily available, *solid* vt100 emulators for TI Professionals.
X
XCterm is currently configured for the TI Professional.
XIt should be relatively easy to port it to the IBM PC & clones.
XSuch a port would most likekly involve re-editing screen.c and keybrd.c
Xand overhauling ports.c. Also, it might be necessary to tweak term.c.
X
XFeatures:
X- eats vt100/vt52 codes and acts on most of them (see below)
X- simulates both user and remote XON/XOFF flow control
X- emulates vt100 cursor key and keypad codes and modes
X- implements most xt100+ setup options
X- implements local mode operations
X- executes commands to DOS
X- includes kermit, xmodem and raw text transfers
X- includes primitive graphics support
X- written in C
X
XNot supported:
X132 columns, printer support, reverse video, smooth scrolling,
Xdouble width & double height characters, screen saver, margin bell,
Xkeyclick, pound sign, 2-page operation, diagnostic status line,
Xbuilt-in confidence tests.
X
X
XReference material:
X
XTI Professional Computer Technical Reference Manual
X	Texas Instruments Inc.
X	(a decent machine ... so where did they go wrong?)
XZilog Z8530 SCC Product Specification
X	Zilog databook
XLanpar Limited XT-100 Plus Operating Manual
X	Lanpar Technologies Inc, 35 Riviera Dr, Markham Ont.
X	Lanpar part number B79820104
X	(they also make a pretty good vt220 clone)
XTurbo C 1.0 User's Guide and Reference Guide
X	Borland International
X	(Hmm, maybe it's time to get version 1.5)
XQkermit
X	kermit and vt100 emulation for IBM-PCs written in
X	Turbo Pascal by Victor Lee at Queen's Univ., Kingston Ont.
X	Obtained from KERMSRV@CUVMA.BITNET.
Xmsxtip.asm
X	TI Pro serial port module for MS-Kermit written by Dan Smith
X	and Joe Smith. Obtained from KERMSRV@CUVMA.BITNET.
XBYTE, March/88
X	Bresenham's line algorithm, p. 252 (see gfx.c)
X
X
XExternal source code:
Xvttest
X	vt100 validation program by Per Lindberg at Stockholm Univ.
X	(see vttest/main.c)
XC-Kermit 1.0
X	(see kermit.c)
Xxmodem 1.0
X	(see xmodem.c)
X
X
XManifest:
X
Xfile		blurb
X----		-----
XDOC		basic user information.
XREADME		you are.
Xcommon.h	definitions common to all except kermit and xmodem
Xcterm.ini	cterm startup config file
Xdefs.c		read/write setups from/to file (ie. cterm.ini)
Xesc.c		vt100(ansi) and vt52 support
Xgfx.c		simple TI graphics support (pixels, palettes and lines)
Xkermit.c	antique ckermit. chosen because it was only one file and
X		therefore easy to make all its global variables static
X		so that there wouldn't be any potential name conflicts.
Xkeybrd.c	TI Pro keyboard support.
Xmain.c		misc startup steps and some misc functions.
Xmakefile	written for Turbo's Make.
Xmisc.c		misc strings.
Xports.c		TI Pro serial port support.
Xprinter.c	phantom printer support.
Xscreen.c	TI Pro text screen support.
Xsetup.c		implements xt100-like setup screens.
X		DOS commands & file transfers take place here.
Xterm.c		main loop and local mode support.
Xtext.c		raw text transfer support.
Xtipro.h		definitions common to all TI Pro support modules.
Xtypes.h		needed to compile xmodem.c
Xxmodem.c	antique xmodem. chosen for the same reason as kermit.
X
Xvttest/*	vt100 testing. compile and run it on another system.
X
X
XNotes:
X
XWith the included makefile and source code, Turbo C 1.0 creates
Xa cterm.exe which is just under 50K. This leaves 14K breathing
Xspace before it's necessary to change memory models (probably
Xthe medium model (large code, small data)). If kermit and xmodem are
Xnot included, cterm.exe is about 30K bytes. If one protocol is used
Xexclusively it might be a good idea to drop one and hack & link in an
Xupdated version of the other in order to remain in small-model range.
X
XVttest is strictly a unix program. It's included as a testing tool.
XIf it's been ported to PCs it might make a dandy ANSI.SYS tester.
X
XKermit.c and xmodem.c are ancient self-contained UNIX programs which
Xwere re-edited to run on DOS. Any unix system should be able to compile
Xeach file as-is and then run them, without any extra work.
XThe DOS modifications involved #ifdef-swapping code in the needed areas.
XTurbo C and it's near-unix library compatibility helped a great deal.
XUnix-based kermits and xmodems with multiple modules may require a bit
Xmore re-editing before they can be "plugged in" to cterm, but it's still
Xprobably easier than trying to build in kermit and xmodem from scratch.
XThe versions included here are marginal in their ability to work with
Xtheir later generations.  They both work OK on ordinary text transfers.
XBinaries are another matter altogether. Xmodem.c will work OK with
Xitself (ie. xmodem 1.0 running on the SUN). Binaries transfers don't
Xseem to work with xmodem 3.4 on a SUN. Kermit.c seems to need 8-bit
Xprefixing added before it hack binaries.  However since binary transfers
Xare not a priority around here this doesn't cause too many problems.
XActually, forthcoming cterm versions (if there are any more) will likely
Xinclude a stripped down ckermit 4E (ie. without interactive commands).
X
X
XDOC and README were edited with vi on a SUN using cterm to connect a
XTI Pro to a DevelCon terminal switch at 9600 baud.
X
XFeedback of any kind would be most appreciated.
X
XPaul Kern		  | pkern@csri.toronto.edu
XDept of Computer Science  | ..!{cbosgd, uunet!attcan}!utgpu!utcsri!pkern
XUniversity of Toronto	  | ..!{ihnp4, utzoo, utai}!utcsri!pkern
X(416) 978-4488
SHAR_EOF
fi # end of overwriting check
echo shar: extracting "'DOC'" '(3818 characters)'
if test -f 'DOC'
then
	echo shar: will not over-write existing file "'DOC'"
else
sed 's/^X//' << \SHAR_EOF > 'DOC'
XCterm usage guide
X-----------------
X
XFunction key definitions:
X
Xvt100		TI Pro equivalent
X-----		-----------------
X(Exit program)	SHIFT-BRK (in terminal mode only)
X
XSetup		F1	or F2
XBreak		F3
XBackspace	F4
X
XDelete		Ctrl-BACKSPACE
XNo Scroll	PAUS
X
XCursor up	Up-key		or F9
X  "    down	Down-key	or F10
X  "    left     Left-key	or F11
X  "    right	Right-key	or F12
X
XPF1		Keypad =	or Alt-F1
XPF2		Keypad +	or Alt-F2
XPF3		Keypad SPAC	or Alt-F3
XPF4		Keypad TAB	or Alt-F4
X
XKeypad 0	Keypad 0	or Alt-Z	or Alt-X
XKeypad 1	Keypad 1	or Alt-A
XKeypad 2	Keypad 2	or Alt-S
XKeypad 3	Keypad 3	or Alt-D
XKeypad 4	Keypad 4	or Alt-Q
XKeypad 5	Keypad 5	or Alt-W
XKeypad 6	Keypad 6	or Alt-E
XKeypad 7	Keypad 7	or Alt-1
XKeypad 8	Keypad 8	or Alt-2
XKeypad 9	Keypad 9	or Alt-3
XKeypad .	Keypad .	or Alt-C
XKeypad -	Keypad -	or Alt-4
XKeypad '	Keypad '	or Alt-R	
XKeypad ENTER	Keypad ENTER	or Alt-F	or Alt-V
X
X
X
XCterm can be executed with or without arguments.
XWithout arguments, cterm will attempt to read "cterm.ini"
Xand then it will go immediately on-line in terminal mode.
XThe only arguments currently recognized are "-i <filename>" which
Xreplaces the default "cterm.ini" file with <filename>.
X
X
XDumb graphics:
X
XGraphics functions can be accessed via a few ANSI-like escape sequences.
XAll the sequences begin with Esc @ (^[@).  For motion sequences, upper
Xcase final characters indicate "pen up" moves and lower case means
X"draw a line."  The TI Pro graphics screen is 720 by 300 pixels.
XGraphics consists of 3 bit-planes and 3 corresponding attribute
Xlatches which allow the TI to display up to 8 colours.
XEach attribute latch is 8 bits wide (ie. a byte).
X
XThe "Interlace" option in setup B is used to control
Xwhether the graphics screen can be seen or not.
X
Xsequence	meaning		(possible range) [startup default]
X--------	-------
XEsc@Pnm		change to colour Pn (0-7) [7]
X
XEsc@Pb;Pr;PbL	set blue  attribute latch to Pb (0-255)	[170 (0xAA)]
X		 "  red       "       "   to Pr (0-255)	[204 (0xCC)]
X		 "  green     "       "   to Pg (0-255)	[240 (0xF0)]
X
XEsc@Py;PxH	goto (Px,Py) (0-719, 0-299)	[0, 0]
XEsc@Py;Pxh	draw line from current position to (Px,Py)
X
XEsc@Py;Px@	goto (Px,Py) and light the pixel (ie. boink it)
X
XEsc@PnA		go up	Pn pixels
XEsc@PnB		"  down  "   "
XEsc@PnC		"  right "   "
XEsc@PnD		"  left  "   "
X
XEsc@Pna		draw line up	Pn pixels long
XEsc@Pnb		 "    "   down  "    "     "
XEsc@Pnc		 "    "   right "    "     "
XEsc@Pnd		 "    "   left  "    "     "
X
X
X
XSetups, extensions:
X
XCterm has three setup screens. Setup A handles tabs and file transfers.
XSetup B handles most of the main terminal options. Setup C contains some
Xremaining terminal options and all the printer options. Setup key labels
Xnormally found on strip on the keyboard are now displayed on the screen.
XCterm setups work in much the same way as they do on VT100s and XT100s.
XSpace bar and TAB will move the cursor forward.
XBackspace and the Left-key will move the cursor back.
XHitting RETURN returns the cursor to the left margin.
X
XTo execute a DOS command, type '!' and then the command. Finish with
Xa RETURN. COMMAND.COM will be called to try to execute the command.
XWhen the command is done, cterm will wait for a keyhit before
Xreturning to the setup screen.  DOS can be "called" from any setup.
X
XFile transfers, however, can only be initiated while in setup A.
XTo run kermit, hit 'k' and then type in the appropriate arguments.
XTo run xmodem, hit 'x' and then type in the appropriate arguments.
XTo capture or send raw text, hit 'c' followed by the appropriate
Xarguments.  In all cases, always finish with a RETURN.  If no
Xarguments are given or if they're used incorrectly, each protocol
Xwill display the proper usage. When the transfer is done, cterm will
Xwait for a keyhit before returning to the setup screen.
X
X
XP. Kern		pkern@csri.toronto.edu, pkern@utcsri.uucp
XDCS, U of Toronto
SHAR_EOF
fi # end of overwriting check
echo shar: extracting "'Makefile'" '(305 characters)'
if test -f 'Makefile'
then
	echo shar: will not over-write existing file "'Makefile'"
else
sed 's/^X//' << \SHAR_EOF > 'Makefile'
X#
X#
XCC=	tcc
X# CFLAGS= -Ddebug -DFINIT="cterm.ini"
XCFLAGS=	-O
XEXE=	cterm
X
XOBJ=	esc.obj keybrd.obj main.obj misc.obj ports.obj  \
X	printer.obj screen.obj term.obj  \
X	setup.obj defs.obj gfx.obj  \
X	kermit.obj xmodem.obj text.obj
X
Xterm:	$(OBJ)
X	$(CC) $(CFLAGS) -e$(EXE) *.obj
X
X.c.obj:
X	$(CC) $(CFLAGS) -c $<
SHAR_EOF
fi # end of overwriting check
echo shar: extracting "'screen.c'" '(7778 characters)'
if test -f 'screen.c'
then
	echo shar: will not over-write existing file "'screen.c'"
else
sed 's/^X//' << \SHAR_EOF > 'screen.c'
X/*
X * screen handling routines for TI Professional
X *
X *  Notes:
X *    - the attribute information for individual positions on the screen
X *	can only be accessed through AH=0x08 (as far as I can tell).
X *	This would take too long when saving the screen image so
X *	attributes are lost when switching save_scr() to restore_scr().
X *
X *    -	it seems necessary to assert the status line after each CLEANing
X *	(a minor annoyance, if we want to enforce a status line)
X *
X * copyright (c) University of Toronto, 1988.
X */
X#include <dos.h>
X#include "common.h"
X#include "tipro.h"
X
X#define BLANK	0x0f
X
X#define SCRSIZE	(80*24)
X/* #define SCR_MEM (0xde000000)	/* screen location */
X#define SCR_MEM (0xde00)	/* screen location segment */
X#define L_ATTR	*((char far *)0xdf000800)	/* attribute latch */
X
X#define CRSR_BLK	0x600c	/* slow-blinking block cursor code */
X#define CRSR_UL		0x4b0b	/* fast-blinking underline cursor */
X
Xstatic union REGS r;
Xstatic struct SREGS sr;
Xstatic int xattr=0x0f;	/* attribute storage */
X
Xstatic char o_scrn[SCRSIZE];	/* screen memory storage */
Xstatic int o_xy;		/* cursor position memory */
Xstatic char far *scrn;		/* screen position memory */
X
X/* macros for frequently used code */
X#define crtint		int86(CRT_INT, &r, &r)
X#define GO_HOME		r.h.ah=2; r.x.dx=0; crtint;
X#define DO_STAT		r.h.ah=0x15; r.x.cx=24; crtint;
X#define GO_XY(a,b)	\
X	r.h.ah=2; r.h.dh=(a); r.h.dl=(b); crtint;
X#define CLEAN(n)	\
X	r.x.ax=0x0920; r.h.bl=BLANK; r.x.cx=(n); \
X	crtint; L_ATTR = xattr;
X
X/* set status region on 25th line */
Xinit_scr()
X{
X	DO_STAT
X	segread(&sr);
X}
X
X/* eliminate status region, reset attributes */
Xreset_scr()
X{
X	r.h.ah = 0x15;
X	r.x.cx = 0;
X	crtint;
X	L_ATTR = BLANK;
X}
X
Xcurs_xy(x, y)
Xuchar x, y;
X{
X	GO_XY(x-1, y-1)
X}
X
Xxypos(xp, yp)
Xuchar *xp, *yp;
X{
X	r.h.ah = 3;
X	crtint;
X	*xp = r.h.dh+1;
X	*yp = r.h.dl+1;
X}
X
X
X/* scroll up n lines between min_y and max_y */
Xscrl_up(n, min_y, max_y, x, y)
Xuchar n, min_y, max_y, x, y;
X{
X	r.h.ah = 6; r.h.al = 1;
X	r.h.dh = 0; r.h.dl = min_y-1+n;
X	r.h.bh = 0; r.h.bl = min_y-1;
X	r.h.ch = 80; r.h.cl = max_y - (min_y-1) - n;
X	crtint;
X	GO_XY(0, max_y-n)
X	CLEAN(80 * n)
X	GO_XY(x-1, y-1)
X	DO_STAT
X}
X
X/* scroll down n lines between min_y and max_y */
Xscrl_down(n, min_y, max_y, x, y)
Xuchar n, min_y, max_y, x, y;
X{
X	r.h.ah = 7; r.h.al = 1;
X	r.h.dh = 0; r.h.dl = min_y-1;
X	r.h.bh = 0; r.h.bl = min_y-1+n;
X	r.h.ch = 80; r.h.cl = max_y - (min_y-1) - n;
X	crtint;
X	GO_XY(0, min_y-1)
X	CLEAN(80 * n)
X	GO_XY(x-1, y-1)
X	DO_STAT
X}
X
X
X/* eol : erase to end of line */
Xeol_erase(x, y)  
Xuchar x, y;
X{
X	if (x > 80) return;
X	CLEAN(80-(x-1))
X	DO_STAT
X}
X
X/*
X * bol : erase from beginning of line to cursor pos.
X * ie. goto head of line, erase chars, return to original pos
X */
Xbol_erase(x, y)
Xuchar x, y;
X{
X	GO_XY(0, y-1)
X	CLEAN(x)
X	GO_XY(x-1, y-1)
X	DO_STAT
X}
X
X/* eos : erase to end of line and to end of screen */
Xeos_erase(x, y)
Xuchar x, y;
X{
X	CLEAN( (24-y) * 80 + (80-(x-1)) )
X	DO_STAT
X}
X
X/*
X * bos : erase from beginning of screen (home) to cursor pos.
X * ie. goto head of screen, erase to original pos, return to position
X */
Xbos_erase(x, y)
Xuchar x, y;
X{
X	GO_HOME
X	CLEAN(80 * (y-1) + x)
X	GO_XY(x-1, y-1)
X	DO_STAT
X}
X
X/* goto head of line, erase line, return to original pos */
Xline_erase(x, y)
Xuchar x, y;
X{
X	GO_XY(0, y-1)
X	CLEAN(80)
X	GO_XY(x-1, y-1)
X	DO_STAT
X}
X
X/* goto head of screen, erase all, return to pos */
X/* could've used AH=0x13 but it also erases the status line */
Xall_erase(x, y)
Xuchar x, y;
X{
X	GO_HOME
X	CLEAN(80*24)
X	GO_XY(x-1, y-1)
X	DO_STAT
X}
X
X
X/*
X * insert line(s) :
X * scroll down n lines, goto head of original line, erase empty space
X */
Xline_ins(n, x, y, max_y)
Xuchar n, x, y, max_y;
X{
X	if (y-1+n < max_y) {
X		r.h.ah = 6; r.h.al = 1;
X		r.h.dh = 0; r.h.dl = y-1;
X		r.h.bh = 0; r.h.bl = y-1+n;
X		r.h.ch = 80; r.h.cl = max_y-(y-1)-n;
X		crtint;
X	}
X	else
X		n = max_y - (y-1);
X	GO_XY(0, y-1)
X	CLEAN(80 * n)
X	DO_STAT
X}
X
X/*
X * delete line(s) :
X * scroll up n lines, goto new empty line, erase lines,
X * return to head of original line
X */
Xline_del(n, x, y, max_y)
Xuchar n, x, y, max_y;
X{
X	if (y-1+n < max_y) {
X		r.h.ah = 6; r.h.al = 1;
X		r.h.dh = 0; r.h.dl = y-1+n;
X		r.h.bh = 0; r.h.bl = y-1;
X		r.h.ch = 80; r.h.cl = max_y-(y-1)-n;
X		crtint;
X	}
X	else
X		n = max_y - (y-1);
X	GO_XY(0, max_y-n)
X	CLEAN(80 * n)
X	GO_XY(0, y-1)
X	DO_STAT
X}
X
X/*
X * delete char(s) :
X * ie. scroll rest of line to the left, goto line-end, erase n chars
X * and return to original cursor pos
X */
Xchar_del(n, x, y)
Xuchar n, x, y;
X{
X	if (x-1+n < 80) {
X		r.h.ah = 6; r.h.al = 1;
X		r.h.dh = x-1+n; r.h.dl = y-1;
X		r.h.bh = x-1; r.h.bl = y-1;
X		r.h.ch = 80-(x-1)-n; r.h.cl = 1;
X		crtint;
X	}
X	else
X		n = 80-(x-1);
X	GO_XY(80-n, y-1)
X	CLEAN(n)
X	GO_XY(x-1, y-1)
X	DO_STAT
X}
X
X/*
X * insert char(s) :
X * ie. scroll rest of line to right and clean out new space(s)
X */
Xchar_ins(n, x, y)
Xuchar n, x, y;
X{
X	if (x-1+n < 80) {
X		r.h.ah = 6; r.h.al = 1;
X		r.h.dh = x-1; r.h.dl = y-1;
X		r.h.bh = x-1+n; r.h.bl = y-1;
X		r.h.ch = 80-(x-1)-n; r.h.cl = 1;
X		crtint;
X	}
X	else
X		n = 80-(x-1);
X	CLEAN(n)
X	DO_STAT
X}
X
X/* set attributes
X * "bold" = 2 levels dimmer
X * reverse video also = 2 levels dimmer.
X * (so reverse and bold is 4 levels dimmer)
X */
Xattribs(attr)
Xuchar attr;
X{
X	r.h.ah = 0x16;
X	r.h.bl = 0x0f;	/* char enable, max intensity */
X	if (attr & AT_BOLD) {	r.h.bl -= 2; attr &= 0x07; }
X	if (attr & AT_REV)	r.h.bl -= 2;
X	r.h.bl |= (attr << 4);
X	L_ATTR = r.h.bl;
X	xattr = r.h.bl;
X/*	crtint;	*/
X}
X
X/*
X * screen alignment test :
X * home cursor and write a screen of E's in normal attrib mode.
X * previous attribs are not forgotten.
X */
Xe_screen()
X{
X	GO_HOME
X	r.h.ah = 0x0a;
X	r.h.al = 'E';
X	r.h.bl = 0x1d;	/* ordinary attribs */
X	r.x.cx = 80 * 24;
X	crtint;	/* screen of E's */
X	L_ATTR = xattr;
X	DO_STAT
X}
X
X/* basic single-char output */
Xburpc(c, x, y)
Xint c, x, y;
X{
X	r.h.ah = 0x0e;
X	r.h.al = c;
X	crtint;
X}
X
X/* insert mode burpc() */
X/* move line right, deposit char */
Xinsurpc(c, x, y)
Xint c, x, y;
X{
X	if (x < 80) {
X		r.h.ah = 6; r.h.al = 1;
X		r.h.bh = x; r.h.bl = y-1;
X		r.h.ch = 80-x; r.h.cl = 1;
X		r.h.dh = x-1; r.h.dl = y-1;
X		crtint;
X	}
X	r.h.ah = 0x0e;
X	r.h.al = c;
X	crtint;
X}
X
X/*  output string at x,y with attr */
Xburps(s, x, y, at)
Xchar *s;
Xuchar x, y, at;
X{
X	GO_XY(x-1, y-1)
X	r.h.ah = 0x10;
X	r.h.al = 0x0f;
X	if (at & AT_BOLD) {	r.h.al -= 2; at &= 0x07; }
X	if (at & AT_REV)	r.h.al -= 2;
X	r.h.al |= (at << 4);
X	xattr = r.h.al;
X	r.x.bx = (int)s;
X	r.x.cx = strlen(s);
X	r.x.dx = sr.ds;
X	crtint;
X}
X
X/* set cursor type */
Xcurs_type(sw)
Xuchar sw;
X{
X	r.h.ah = 1;
X	r.x.cx = (sw) ? CRSR_BLK : CRSR_UL;
X	crtint;
X}
X
X/* save screen image & cursor position */
Xsave_scr()
X{
X	register int n;
X	register char *os;
X	register char far *s;
X
X	r.h.ah = 3;
X	crtint;
X	o_xy = r.x.dx;
X	r.h.ah = 0x17;
X	crtint;
X/*	scrn = SCR_MEM | r.x.dx;	*/
X	scrn = (char far *) MK_FP(SCR_MEM, r.x.dx);
X
X	n = SCRSIZE;
X	s = scrn; os = o_scrn;
X	while (n--) *os++ = *s++;
X}
X
X/* restore screen image & cursor position */
Xrestore_scr()
X{
X	register int n;
X	register char *os;
X	register char far *s;
X
X	r.h.ah = 0x17;
X	crtint;
X/*	scrn = SCR_MEM | r.x.dx;	*/
X	scrn = (char far *) MK_FP(SCR_MEM, r.x.dx);
X
X	n = SCRSIZE;
X	s = scrn; os = o_scrn;
X	while (n--) *s++ = *os++;
X
X	r.h.ah = 2;
X	r.x.dx = o_xy;
X	crtint;
X}
X
X/* write string to status line */
Xsturp(s, x, y)
Xchar *s;
Xint x, y;
X{
X	GO_XY(0, 24)
X	r.h.ah = 0x10;
X	r.h.al = 0x1b;
X	r.x.bx = (int)s;
X	r.x.cx = strlen(s);
X	r.x.dx = sr.ds;
X	crtint;
X	GO_XY(x-1, y-1)
X	L_ATTR = xattr;
X}
X
X
X/* delay for n milliseconds */
X
Xdsleep(n)
Xunsigned int n;
X{
X	r.h.ah = 5;
X	r.x.cx = n;
X	int86(0x48, &r, &r);
X}
X
X
X/* bios -- Clear Text Screen And Home the Cursor */
X
Xclr_home()
X{
X	r.h.ah = 0x13;
X	crtint;
X}
X
X
X/* dburp -- put debug message on status line */
X
Xdburp(s)
Xchar *s;
X{
X	uchar x, y;
X
X	xypos(&x, &y);
X	sturp(s, x, y);
X}
X
X
X/* erase graphics screen */
X
Xgfx_erase()
X{
X	r.h.ah = 0x14;
X	crtint;
X}
SHAR_EOF
fi # end of overwriting check
echo shar: extracting "'ports.c'" '(9944 characters)'
if test -f 'ports.c'
then
	echo shar: will not over-write existing file "'ports.c'"
else
sed 's/^X//' << \SHAR_EOF > 'ports.c'
X/*
X * ports.c:
X *	serial port stuff for TI Professionals
X *
X * copyright (c) University of Toronto, 1988.
X */
X/*
X * layout based in part on modempro.pas from Qkermit and msxtip.asm.
X * TI Pro serial port information obtained from msxtip.asm, the
X * TI Pro Technical Manual, and the Zilog Z8530 SCC product spec.
X */
X
X#include <dos.h>
X#include "common.h"
X#include "tipro.h"
X
Xextern int nbaud, n_port;
Xextern uchar flowctl, bpc, stopbits, parity, m_prty;
X
Xstatic uchar buffer[BUFMAX];
Xstatic int xout=0, xin=0, n_intr=0;
Xstatic int a_cmd=0, b_cmd=0, a_data=0, b_data=0;
Xstatic int bufovfl=BUFMAX/2,	/* flow control XOFF trigger */
X	bufmpty=BUFMAX/8;	/* flow control XON trigger */
Xstatic uchar flxoff=0;	/* flowctl XOFF-sent flag */
X
X#define BUFC(a,b)	((a<b)?(a+BUFMAX-b):(a-b))
X
X#ifdef debug
Xint regs[16];
X#endif
X
X
X/* 8259 Interrupt Controller port addresses */
X#define IC8259r1	0x18 
X#define IC8259r2	0x19 
X
X/* Sync-Async Comm board port addresses */
Xstruct port_dat {
X	uchar base;	/* intr acknowledge */
X	uchar enable;	/* intr enable mask */
X	uchar disable;	/* intr reset mask */
X	uchar vect;	/* intr vector */
X} ports[NPORTS] = {
X	{ 0xE0, 0xFE, 0x01, 0x40 },
X	{ 0xE8, 0xFD, 0x02, 0x41 },
X	{ 0xF0, 0xFB, 0x04, 0x42 },
X	{ 0xF8, 0xEF, 0x10, 0x44 }
X};
X/* Comm board channel offsets */
X#define A_CMD	6
X#define A_DATA	7
X#define B_CMD	4
X#define B_DATA	5
X
X		/* Channel A initialization table */
Xstatic uchar init_a[] = {
X	0x09, 0xC0,	/* WR9 : reset 8530 */
X	0x0B, 0x50,	/* WR11: no XTAL, RxC=BRG=TxC, TRxC pin input */
X	0x0E, 0x03,	/* WR14: BRG source is PLCK pin, enable BRG */
X	0x0F, 0x0,	/* WR15: disable external status interrupts */
X	0x04, 0x44,	/* WR4 : x16 clock, 1 stop bit, no parity */
X	0x05, 0xEA,	/* WR5 : raise DTR+RTS, 8 bits, Tx enable */
X	0x03, 0xC1,	/* WR3 : 8 bits, enable receiver */
X	/* WR1 : interrupt on all received chars & special conditions */
X	0x01, 0x10,
X	0x09, 0x08,	/* WR9 : master interrupt enable */
X	0xFF, 0xFF
X };
X
X		/* Channel B initialization table */
Xstatic uchar init_b[] = {
X	0x0F, 0x0,	/* WR15: disable external status interrupts */
X	0x01, 0x0,	/* WR1 : disable all other interrupts */
X	0x05, 0x02,	/* WR5 : raise internal modem RTSB (RCNTRL) */
X	0xFF, 0xFF
X };
X
X/* bits-per-char table (bitwise-OR masks for WR5) */
Xstatic uchar bpctab[4] = { 0x0, 0x40, 0x20, 0x60 };
X
X
X	/* Baud tables */
X
X#define BRClkPeriod 15360 /* BR Clock Period / 10 (see Z8530 specs) */
X/* divisors for Z8530 at 4.9152 Mhz */
Xstatic int bdivs[EXTB+1] = {
X	 0x0696,  0x05FE,  0x03FE,  0x02B8,  0x0239,
X	 0x01FE,  0x017E,  0x00FE,  0x007E,  0x003E,
X	 0x0029,  0x0024,  0x001E,  0x0013,  0x000E,
X	 0x0009,  0x0006,  0x0002,  0x0000
X};
X
Xstatic unsigned int spdtab[] = {
X	45, B0,		46, B0,		50, B50,
X	75, B75,	110, B110,	134, B134,
X	135, B134,	150, B150,	200, B200,
X	300, B300,	600, B600,	1200, B1200,
X	1800, B1800,	2000, B2000,	2400, B2400,
X	3600, B3600,	4800, B4800,	7200, B7200,
X	9600, B9600,	19200, EXTA,	38400, EXTB,
X	0, B9600
X};
X
X/* speed strings used in setups() */
Xchar *bauds[EXTB+1] = {
X	" 45.5", "   50", "   75", "  110", "134.5",
X	"  150", "  200", "  300", "  600", " 1200",
X	" 1800", " 2000", " 2400", " 3600", " 4800",
X	" 7200", " 9600", "19200", "38400"
X};
X
X/*
X * Z8530 baudrate divisor table	(from the TI Pro's tech manual)
X *	divisor		baud
X *
X *	 0x0696		45.5   
X *	 0x05FE		50.0   
X *	 0x03FE		75.0   
X *	 0x02B8		110.0  	( +0.03% )
X *	 0x0239		134.5  	( Selectric )
X *	 0x01FE		150.0  
X *	 0x017E		200.0  
X *	 0x00FE		300.0  
X *	 0x007E		600.0  
X *	 0x003E		1200.0 
X *	 0x0029		1800.0 	( -0.78% )
X *	 0x0024		2000.0 	( +1.05% )
X *	 0x001E		2400.0 
X *	 0x0013		3600.0 	( +1.59% )
X *	 0x000E		4800.0 
X *	 0x0009		7200.0 	( -3.03% )
X *	 0x0006		9600.0 
X *	 0x0002		19200.0
X *	 0x0000		38400.0	( unsupported )
X */
X     
X/*	
X * port_isr -- serial port interrupt service routine
X */
X
Xvoid interrupt (*o_portisr)();	/* old intr storage */
X
Xvoid interrupt
X#ifdef debug
Xport_isr(bp,di,si,ds,es,dx,cx,bx,ax,ip,cs,flags)
Xunsigned int bp,di,si,ds,es,dx,cx,bx,ax,ip,cs,flags;
X{
Xregs[1]=ax; regs[2]=bx; regs[3]=cx; regs[4]=dx;
Xregs[5] = ip; regs[6] = cs; regs[7] = flags;
Xregs[8] = bp; regs[9] = di; regs[10] = si;
Xregs[11] = ds; regs[12] = es; regs[0] = 1;
X#else
Xport_isr()
X{
X#endif
X	if (inportb(a_cmd) & 0x01) {
X		/* then put char in buffer */
X		buffer[xin++] = inportb(a_data);
X		xin %= BUFMAX;
X		/* check buffer overflow, send XOFF if needed */
X		if (flowctl && BUFC(xin,xout) > bufovfl)
X			{ xmit_chr(XOFF); flxoff=1; }
X	}
X	enable();
X	outportb(IC8259r1, 0x20);	/* 8259 : End-of-interrupt */
X}
X     
X/*
X * set_prt  -  Set the baud rate, parity and stop bits for serial port.
X */
Xset_prt()
X{
X	int i;
X
X	if (!a_cmd) return(-1);
X
X	if (nbaud > EXTA)
X		nbaud = B9600;
X	
X	i = nbaud;
X		
X	/* WR13 : baud rate time const upper byte */
X	outportb(a_cmd, 13);
X	outportb(a_cmd, bdivs[i] >> 8);
X
X	/* WR12 : baud rate time const lower byte */
X	outportb(a_cmd, 12);
X	outportb(a_cmd, bdivs[i] & 0xff);
X
X	/* WR4 : x16 clock mode, 1 or 2 stopbits, parity */
X	i = 0x40;	/* x16 clock mode */
X	i |= (stopbits) ? 0x0c : 0x04;	/* stop bits  ?  2 : 1 */
X	i |= (parity << 1) | m_prty;	/* parity type & mode */
X	outportb(a_cmd, 4);
X	outportb(a_cmd, i);
X
X	bufovfl = BUFMAX/2;
X	bufmpty =  BUFMAX/8;
X
X#ifdef debug
X	regs[13] = BUFMAX; regs[14] = bufovfl; regs[15] = bufmpty;
X#endif
X
X	i = (7 + bpc) - 5;
X	/* WR5 : DTR, RTS, bpc, Tx enable */
X	outportb(a_cmd, 5);
X	outportb(a_cmd, 0x8A | bpctab[i]);
X
X	/* WR3 : bpc, Rx enable */
X	outportb(a_cmd, 3);
X	outportb(a_cmd, 0x01 | (bpctab[i]<<1));
X}
X
X/*
X * init_prt - Initialize the port and install the port ISR.
X */
Xinit_prt()
X{
X	int i, x;
X
X	if (n_port < 0 || n_port > NPORTS-1) return(-1);
X
X	n_intr = ports[n_port].vect;
X	a_cmd = ports[n_port].base + A_CMD;
X	b_cmd = ports[n_port].base + B_CMD;
X	a_data = ports[n_port].base + A_DATA;
X	b_data = ports[n_port].base + B_DATA;
X     
X 		/* clrbuf */
X	for (i=0; i<8; i++) x = inportb(a_data);
X	x = inportb(a_cmd);	/* makes it point to WR0 */
X		/* serina */
X	for (i=0; !(init_a[i] & 0x80); i+=2) {
X		outportb(a_cmd, init_a[i]);
X		outportb(a_cmd, init_a[i+1]);
X	}
X	x = inportb(b_cmd);	/* makes it point to WR0 */
X		/* serinb */
X	for (i=0; !(init_b[i] & 0x80); i+=2) {
X		outportb(b_cmd, init_b[i]);
X		outportb(b_cmd, init_b[i+1]);
X	}
X
X	xin = xout = 0;	/* initialize buffer indices */
X
X	/* save old intr vector to another spot */
X	o_portisr = getvect(n_intr);
X	/* install the new interrupt routine */
X	disable();
X	setvect(n_intr, port_isr);
X	enable();
X
X		/* enable IR0, IR1, IR2, or IR4 */
X	outportb(IC8259r2, inportb(IC8259r2) & ports[n_port].enable);
X/*	outportb(IC8259r1, ports[n_port].disable);	*/
X     
X	set_prt();
X}
X     
X/*
X *  reset_prt - restore the original interrupt, drop DTR and RTS
X */
Xreset_prt()
X{
X	if (!n_intr || !a_cmd) return(-1);
X
X	/* WR9 : disable 8530 interrupts */
X	outportb(a_cmd, 9);
X	outportb(a_cmd, 0);
X	/* WR5 : no DTR, no RTS, Tx enable, bpc */
X	outportb(a_cmd, 5);
X	outportb(a_cmd, 0x64 & bpctab[(7+bpc)-5]);
X
X	/* disable interrupts */
X	outportb(IC8259r2, inportb(IC8259r2) | ports[n_port].disable);
X	/* restore the old interrupt vector */
X	setvect(n_intr, o_portisr);
X}
X     
X/*
X *  conn_prt - checks DCD and CTS.
X * (a historical relic, no longer used)
X */
Xconn_prt()
X{
X	int i;
X
X	i = ((inportb(a_cmd) & 0x24) != 0x24);
X	return(i);
X}
X     
X/*
X * recv_chr - Receive a Character from the serial port.
X * returns:   c     - if there is a character in the buffer.
X *            -1    - if no character found.
X */
Xrecv_chr()
X{
X	uchar c;
X
X	if (flxoff && BUFC(xin,xout) < bufmpty)
X		{ xmit_chr(XON); flxoff=0; }
X
X	if (BUFC(xin,xout) > 0) { /* get char from buffer */
X		c = buffer[xout++] & 0x7f;
X		xout %= BUFMAX;
X		return(c);
X	}
X	return(-1);
X}
X     
Xrecv_byt()
X{
X	uchar c;
X
X	if (BUFC(xin,xout) > 0) {
X		c = buffer[xout++];
X		xout %= BUFMAX;
X		return(c);
X	}
X	return(-1);
X}
X     
X/*
X * xmit_chr - Send a character thru the serial port.
X *           It waits for the previous character to be sent before
X *           sending the current character.
X */
Xxmit_chr(c)
Xint c;
X{
X	while (!(inportb(a_cmd) & 0x04)) ;
X	outportb(a_data, c & 0xff);
X}
X
X/*
X * xmit_str - Same as xmit_chr() except a string is sent instead.
X */
Xxmit_str(p)
Xchar *p;
X{
X	int c;
X
X	while (c = *p++) {
X		while (!(inportb(a_cmd) & 0x04)) ;
X		outportb(a_data, c & 0xff);
X	}
X}
X     
X/*
X * send_brk- Send a long break via the comm port.
X */
Xsend_brk(sw)
Xint sw;
X{
X
X	if (sw) return;		/* ie. in local mode */
X	if (!a_cmd) return(-1);
X
X	/* WR5 : no DTR, no RTS, send break, Tx enable, bpc */
X	outportb(a_cmd, 0x05);
X	outportb(a_cmd, 0x18 | bpctab[(7+bpc)-5]);
X
X	dsleep(250);	/* 1/4 sec. delay */
X
X	/* WR5 : DTR, RTS, Tx enable, bpc */
X	outportb(a_cmd, 0x05);
X	outportb(a_cmd, 0x8A | bpctab[(7+bpc)-5]);
X
X}
X
X/* put char into incoming data buffer (ie. simulate echo) */
Xloop_chr(c)
Xint c;
X{
X	disable();
X	buffer[xin++] = c;
X	xin %= BUFMAX;
X	enable();
X}
X
X/*
X * trns_chr: same as recv_chr but translate control chars
X */
Xtrns_chr()
X{
X	uchar c;
X
X	if (flxoff && BUFC(xin,xout) < bufmpty)
X		{ xmit_chr(XON); flxoff=0; }
X
X	if (BUFC(xin,xout) > 0) { /* get char from buffer */
X		c = buffer[xout] & 0x7F;
X		if (c & 0x60) {
X			xout = (++xout) % BUFMAX;
X			return(c);
X		}
X		else {
X			buffer[xout] = c | '@';
X			return('^');
X		}
X	}
X	return(-1);
X}
X
X/* return vt100 speed number */
Xvtspeed(x)
Xint x;
X{
X/*
X	switch (x) {
X	case B0: case B50: x=0; break;
X	case B75: x=8; break;		case B110: x=16; break;
X	case B134: x=24; break;		case B150: x=32; break;
X	case B200: x=40; break;		case B300: x=48; break;
X	case B600: x=56; break;		case B1200: x=64; break;
X	case B1800: x=72; break;	case B2000: x=80; break;
X	case B2400: x=88; break;	case B3600: x=96; break;
X	case B4800: x=104; break;	case EXTA: x=120; break;
X	case B9600:
X	default: x=112; break;
X	}
X */
X	if (x < B75)
X		return(0);
X	else if (x > B4800)
X		return(112);	/* default 9600 */
X	return((x-1)*8);
X}
X
X/* return bdivs index for speed n */
Xprtspd(n)
Xunsigned int n;
X{
X	int i;
X
X	for (i=0; spdtab[i]; i+=2)
X		if (spdtab[i] == n)
X			return(spdtab[i+1]);
X	return(nbaud);
X}
SHAR_EOF
fi # end of overwriting check
echo shar: extracting "'keybrd.c'" '(5744 characters)'
if test -f 'keybrd.c'
then
	echo shar: will not over-write existing file "'keybrd.c'"
else
sed 's/^X//' << \SHAR_EOF > 'keybrd.c'
X/*
X * keybrd.c:
X *	functions, maps and interrupt routines for TI Pro keyboards
X *	(see TI Technical Manual for nitty gritty details)
X *
X * copyright (c) University of Toronto, 1988.
X */
X#include <dos.h>
X#include "common.h"
X#include "tipro.h"
X
Xuchar keyhit=0, keyboom=0;
X
Xstatic union REGS r;
Xstatic uchar f_map=0, f_vec=0;
X
Xextern int zip();
Xextern uchar flowctl, local, xoff;
X
X/* bios check for queued keys */
Xkbdhit()
X{
X	r.h.ah = 1;
X	int86(KBD_INT, &r, &r);
X	return (!(r.x.flags & Zflag));	/* ie. ! Z-flag */
X}
X
X/* flush keyboard type-ahead queue */
Xkbflush()
X{
X	r.h.ah = 3;
X	int86(KBD_INT, &r, &r);
X	keyhit = 0;
X}
X
X/* toggle keyboard autorepeat */
Xkbautorep(sw)
Xint sw;	/* switch : 1 = on, 0 = off */
X{
X	r.h.ah = 4;
X	r.h.al = (sw) ? 1 : 2;
X	int86(KBD_INT, &r, &r);
X}
X
X/* get keyboard word */
Xunsigned int
Xkbdget()
X{
X	r.h.ah = 0;
X	int86(KBD_INT, &r, &r);
X	keyhit--;
X	return((unsigned int) r.x.ax);
X}
X
X/* return a keypadv[] offset */
Xkbdfn(kn)
Xunsigned int kn;
X{
X	extern keymap[];
X
X	return(keymap[kn>>8]);
X}
X
X/*
X *  keypad map (aN == alt N)
X * +-----+-----+-----+-----+
X * | PF1 | PF2 | PF3 | PF4 |		cursor code offsets:
X * | aF1 | aF2 | aF3 | aF4 |			UP - 0
X * +-----+-----+-----+-----+		      DOWN - 1
X * |  7  |  8  |  9  |  -  |		     RIGHT - 2
X * | a1  | a2  | a3  | a4  |		      LEFT - 3
X * +-----+-----+-----+-----+
X * |  4  |  5  |  6  |  ,  |	keypad code string offsets:
X * | aQ  | aW  | aE  | aR  |	8 - "0"	 10 - "8"	18 - "F3"
X * +-----+-----+-----+-----+	9 - "1"  11 - "9"	19 - "F4"
X * |  1  |  2  |  3  |     |	A - "2"  12 - "-"	1A - "\200"
X * | aA  | aS  | aD  |Enter|	B - "3"  13 - ","	1B - "\b"
X * +-----+-----+-----+     |	C - "4"  14 - "."	1C - "\003"
X * |     0     |  .  | aF  |	D - "5"  15 - "ENTER"	1D - "\r\n"
X * | aZ    aX  | aC  | aV  |	E - "6"  16 - "F1"	1E --> ansback
X * +-----------+-----+-----+	F - "7"  17 - "F2"	1F - ""	 (empty)
X */
X
X
X/*
X * keymap:
X *	keypadv[] offsets for all possible
X *	(ie. 90H) extended function-key codes
X */
Xint keymap[0x90] = {
X/* 0x0_ */	0x1f, 0x1f, 0x1f, 0x1a, 0x1f, 0x1f, 0x1f, 0x1f,
X		0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x1f, 0x1f,
X/* 0x1_ */	0x0c, 0x0d, 0x0e, 0x13, 0x1f, 0x1f, 0x1f, 0x1f,
X		0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x09, 0x0a,
X/* 0x2_ */	0x0b, 0x15, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f,
X		0x1f, 0x1f, 0x1f, 0x1f, 0x08, 0x08, 0x14, 0x15,
X/* 0x3_ */	0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f,
X		0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1b, 0x1f,
X/* 0x4_ */	0x1f, 0x1f, 0x1f, 0x00, 0x01, 0x03, 0x02, 0x1f,
X		0x00, 0x00, 0x1f, 0x03, 0x03, 0x02, 0x02, 0x1f,
X/* 0x5_ */	0x01, 0x01, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f,
X		0x1f, 0x1f, 0x1f, 0x1f, 0x00, 0x01, 0x1f, 0x1f,
X/* 0x6_ */	0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x00, 0x01,
X		0x16, 0x17, 0x18, 0x19, 0x1f, 0x1f, 0x1f, 0x1f,
X/* 0x7_ */	0x00, 0x01, 0x1f, 0x03, 0x02, 0x1f, 0x01, 0x1f,
X		0x0f, 0x10, 0x11, 0x12, 0x1f, 0x1f, 0x1f, 0x1f,
X/* 0x8_ */	0x1f, 0x1f, 0x1f, 0x1f, 0x00, 0x1f, 0x1f, 0x1f,
X		0x00, 0x01, 0x02, 0x03, 0x16, 0x17, 0x18, 0x19
X};
X
X/* k_brk -- intercept SHIFT BRK/PAUS interrupt */
Xvoid interrupt
Xk_brk(bp,di,si,ds,es,dx,cx,bx,ax,ip,cs,flags)
Xunsigned int bp,di,si,ds,es,dx,cx,bx,ax,ip,cs,flags;
X{
X	send_brk();
X	flags |= Cflag;		/* ie. don't queue it */
X	keyboom++;
X}	
X
X/* k_paus -- intercept PAUS key interrupt */
Xvoid interrupt
Xk_paus(bp,di,si,ds,es,dx,cx,bx,ax,ip,cs,flags)
Xunsigned int bp,di,si,ds,es,dx,cx,bx,ax,ip,cs,flags;
X{
X	if (flowctl && !local)
X		if (xoff)
X			{ xmit(XON); recv = o_recv; xoff = 0; }
X		else
X			{ xmit(XOFF); recv = zip; xoff++; }
X	flags |= Cflag;		/* don't queue it */
X}
X
X/* k_que -- take note of new keystroke in buffer */
Xvoid interrupt
Xk_que()
X{
X	keyhit++;
X/*	outport(0,7);	/* simple but pathetic-sounding keyclick */
X}
X
X/*
X * remap: table of scan codes for remapping TI Pro keypad
X *	- new scan values for scan codes 23 -> 44
X * 0 = scan code unused (ie. it should never occur)
X */
Xstatic uchar remap[22] = {
X	 23,  24,  25,  26,
X	 66,   0,  82,  69,
X	 50,  51,  11,  12,
X	 67,   0,   0,   0,
X	  9,  10,  52,  53,
X	 68,  84
X};
X
X/* k_map -- remap keypad scan codes */
Xvoid interrupt
Xk_map(bp,di,si,ds,es,dx,cx,bx,ax,ip,cs,flags)
Xunsigned int bp,di,si,ds,es,dx,cx,bx,ax,ip,cs,flags;
X{
X	uchar al, ah;
X
X	al = ax & 0xff;	ah = (ax >> 8) | 0x02;
X	if (al < 45 && al > 22)
X		/* force ALT-key bit & remap key code */
X		ax = (ah << 8) + remap[al-23];
X}
X
X/*
X * o_brk, o_paus, o_que, o_map:
X *	temp storage for old interrupt vectors
X */
Xvoid interrupt (*o_brk)();
Xvoid interrupt (*o_paus)();
Xvoid interrupt (*o_que)();
Xvoid interrupt (*o_map)();
X
Xinit_kbd()
X{
X	if (f_vec) return(0);
X
X	kbflush();
X
X	/* remember old intr vectors */
X	o_brk = getvect(KEYBRK);
X	o_paus = getvect(KEYPAUS);
X	o_que = getvect(KBDQUE);
X	o_map = getvect(KBDMAP);
X	/* install new ones */
X	disable();
X	setvect(KEYBRK, k_brk);
X	setvect(KEYPAUS, k_paus);
X	setvect(KBDQUE, k_que);
X	setvect(KBDMAP, k_map);
X	enable();
X
X	f_vec = 1;	/* vectors installed */
X
X	/* some important key mappings */
X	keymap[K_SETUP >> 8] = 0x80;	/* flag the SETUP key */
X	keymap[(K_SETUP >> 8)+1] = 0x80;	/* ditto on F2 */
X	keymap[K_shBRK >> 8] = 0x40;	/* shiftBrk - send BRK */
X	keymap[K_NUL >> 8] = 0x41;	/* ctrl-2@  - send NUL */
X	keymap[K_BKSP >> 8] = 0x1b;	/* backsp keypadv[] position */
X	keymap[K_BREAK >> 8] = 0x1c;	/* break keypadv[] position */
X	keymap[K_cBRK >> 8] = 0x1e;	/* ctrlBrk keypadv[] position */
X	keyboom = 0;
X}
X
Xreset_kbd()
X{
X	if (!f_vec) return;	/* no vectors to reset, yet */
X
X	kbflush();
X
X	/* restore old intr vectors */
X	disable();
X	setvect(KEYBRK, o_brk);
X	setvect(KEYPAUS, o_paus);
X	setvect(KBDQUE, o_que);
X	setvect(KBDMAP, o_map);
X	enable();
X
X	f_vec = 0;	/* vectors reset */
X}
X
Xnlmod(sw)	/* switch newline mode */
Xuchar sw;
X{
X	/* shift ENTER offset, if needed */
X	keymap[0x21] = keymap[0x2f] = ((sw) ? 0x1d : 0x15);
X}
SHAR_EOF
fi # end of overwriting check
echo shar: extracting "'gfx.c'" '(5928 characters)'
if test -f 'gfx.c'
then
	echo shar: will not over-write existing file "'gfx.c'"
else
sed 's/^X//' << \SHAR_EOF > 'gfx.c'
X/*
X * gfx.c: simple access for TI Pro graphics
X *
X * copyright (c) University of Toronto, 1988.
X */
X
X#ifdef dbgfx
X#include <fcntl.h>
Xstatic int fd=0;
Xstatic char buf[256];
X#endif
X
Xtypedef unsigned char uchar;
X
X#define GMAX_X	720
X#define GMAX_Y	300
X
Xstatic int gx=0, gy=0;
Xstatic uchar gcolour=7;
X
X/* graphics palette attribute latches */
X#define L_BLU	*((char far *)0xdf000010)
X#define L_GRN	*((char far *)0xdf000020)
X#define L_RED	*((char far *)0xdf000030)
X
Xstatic uchar l_blu=0xAA, l_red=0xCC, l_grn=0xF0;
X
X#define L_SYNC	L_BLU=l_blu; L_RED=l_red; L_GRN=l_grn;
X
Xextern uchar interlace;
X
X/*
X * gfx -- simple (dumb?) graphics access
X * expects "^[@<ANSI-style cmd>"
X *	upper case cmd	-> do move "with pen up"
X *	lower case cmd	-> draw line to new position
X */
Xgfx(s, slen)
Xchar *s;
Xint slen;
X{
X	char *p, c;
X	int i, n, pnc, pn[8];
X
X	/* get parameter numbers */
X	pn[0] = pn[1] = pn[2] = pn[3] = 0;
X	pn[4] = pn[5] = pn[6] = pn[7] = 0;
X	for (i=2, pnc=0; i<slen; i++) {
X		n = s[i] - '0';
X		if (n>=0 && n<=9)
X			pn[pnc] = pn[pnc] * 10 + n;
X		else	/* it's ';' or it's the final char */
X			pn[++pnc] = 0;
X	}
X	c = s[i-1];
X#ifdef dbgfx
Xif (fd) write(fd, "@", 1);
Xfor (n=0; n<pnc-1; n++) {
X	sprintf(buf, "%d;", pn[n]);
X	if (fd) write(fd, buf, strlen(buf));
X}
Xsprintf(buf, "%d%c", pn[pnc-1], c);
Xif (fd) write(fd, buf, strlen(buf));
X#endif
X	switch (c) {
X	case 'H': case 'h':	/* goto position */
X	case '@':	/* & boink (ie. goto with pen up & drop pen) */
X		if (pn[1] > GMAX_X) pn[1] = GMAX_X;
X		if (pn[0] > GMAX_Y) pn[0] = GMAX_Y;
X		if (c & 040) bline(gx, gy, pn[1], pn[0], gcolour);
X		gx = pn[1]; gy = pn[0];
X		if (c == '@') boink(gx, gy, gcolour);
X		break;
X	case 'A': case 'a':	/* "cursor" up */
X		if (!pn[0]) pn[0] = 1;
X		if ((pn[0] = (gy - pn[0])) < 0) pn[0] = 0;
X		if (c & 040) vline(gx, pn[0], gy-pn[0]+1, gcolour);
X		gy = pn[0];
X		break;
X	case 'B': case 'b':	/* down */
X		if (!pn[0]) pn[0] = 1;
X		if ((pn[0] = (gy + pn[0])) > GMAX_Y) pn[0] = GMAX_Y;
X		if (c & 040) vline(gx, gy, pn[0]-gy+1, gcolour);
X		gy = pn[0];
X		break;
X	case 'C': case 'c':	/* right */
X		if (!pn[0]) pn[0] = 1;
X		if ((pn[0] = (gx + pn[0])) > GMAX_X) pn[0] = GMAX_X;
X		if (c & 040) hline(gx, gy, pn[0]-gx+1, gcolour);
X		gx = pn[0];
X		break;
X	case 'D': case 'd':	/* left */
X		if (!pn[0]) pn[0] = 1;
X		if ((pn[0] = (gx - pn[0])) < 0) pn[0] = 0;
X		if (c & 040) hline(pn[0], gy, gx-pn[0]+1, gcolour);
X		gx = pn[0];
X		break;
X	case 'L': case 'l':	/* access palette latches */
X		if (c & 040) {	/* relative palette changes */
X			l_blu += pn[0];	l_red += pn[1];	l_grn += pn[2];
X			l_blu %= 0xFF;	l_red %= 0xFF;	l_grn %= 0xFF;
X		}
X		else {		/* absolute palette changes */
X			l_blu = pn[0] % 0xFF;
X			l_red = pn[1] % 0xFF;
X			l_grn = pn[2] % 0xFF;
X		}
X		L_SYNC
X		break;
X	case 'J':	/* erase */
X		gfx_erase();
X		break;
X	case 'm':	/* change current colour */
X		gcolour = pn[pnc-1] % 8;
X		break;
X	default:
X		break;
X	}
X}
X
X#define GBa(i)	*((int far *)0xc0000000+i)
X#define GBb(i)	*((int far *)0xc8000000+i)
X#define GBc(i)	*((int far *)0xd0000000+i)
X
X#define GBOFS(a,b)	(((b)*46)+((a)/16))
X#define GMASK(a)	(0x8000 >> ((a)%16))
X
Xinit_gfx()
X{
X#ifdef dbgfx
Xif (fd > 0) close(fd);
Xfd = open("gfx.log", O_WRONLY|O_CREAT|O_APPEND, 0664);
Xif (fd < 0) fd = 0;
X#endif
X	L_BLU = L_RED = L_GRN = 0;
X
X	if (interlace) {
X		gcolour = 7;
X		L_SYNC
X	}
X}
X
Xstatic unsigned int ofs, msk;
X#define BOINK(o,m,n)	\
X	GBa(o) = ((n & 1) ? (GBa(o) | m) : (GBb(o) & ~m)); \
X	GBb(o) = ((n & 4) ? (GBb(o) | m) : (GBb(o) & ~m)); \
X	GBc(o) = ((n & 2) ? (GBc(o) | m) : (GBb(o) & ~m));
X
Xstatic
Xboink(x,y,c)
Xint x, y;
Xuchar c;
X{
X	msk = GMASK(x);
X	ofs = GBOFS(x,y);
X	BOINK(ofs, msk, c)
X}
X
X/*
X * draw line from (x0,y0) to (x1,y1) with colour clr.
X *	using Bresenham's Line Algorithm (BYTE, Mar/88, p.252)
X */
Xstatic
Xbline(x0,y0,x1,y1,clr)
Xint x0,y0,x1,y1;
Xuchar clr;
X{
X	int	x, y,		/* current x,y coords */
X		d, i,		/* decision variable / utility */
X		a, b,		/* line displacements in x, y */
X		dx_d, dy_d,	/* diagonal x/y steps for next point */
X		dx_nd, dy_nd,	/* nondiag. x/y steps for next point */
X		d_inc, nd_inc;	/* "d" inc for diag/nondiag steps */
X
X	x = x0; y = y0;		/* start point */
X
X	a = x1 - x0;	dx_d = 1;
X	b = y1 - y0;	dy_d = 1;
X
X	/* if vert or horiz lines, use custom routines instead */
X	if (b == 0) { hline(x, y, a, clr);	return; }
X	if (a == 0) { vline(x, y, b, clr);	return; }
X
X	if (a < 0) { a = -a; dx_d = -1; }
X	if (b < 0) { b = -b; dy_d = -1; }
X
X		/* identify end-point octant */
X	if (a < b) {
X		i = a; a = b; b = i;	/* swap a and b */
X		dx_nd = 0;	/* larger y-diff means x won't change */
X		dy_nd = dy_d;	/* on nondiag steps, but y will */
X	}
X	else {
X		dx_nd = dx_d;	/* x changes every step; y changes */
X		dy_nd = 0;	/* only on the diag steps */
X	}
X
X	d = b + b - a;
X	nd_inc = b + b;
X	d_inc = b + b - a - a;
X
X	for (i=0; i <= a; i++) {	/* draw a+1 points */
X	/*	boink(x,y,clr);		*/
X		msk = GMASK(x);
X		ofs = GBOFS(x,y);
X		BOINK(ofs, msk, clr)
X
X		/* if midpoint is above the line ... */
X		if (d < 0)	/* then step nondiagonally */
X			{ x += dx_nd;	y += dy_nd;	d += nd_inc; }
X		else		/* else step diagonally */
X			{ x += dx_d;	y += dy_d;	d += d_inc; }
X	}
X}
X
X/*
X * hline -- only does horizontal lines (union regulations :-)
X *	use solid(ie. multi bit) masks and increment the offset
X */
Xstatic
Xhline(x,y,n,c)
Xint x,y,n;
Xuchar c;
X{
X	if (n < 0) {
X		n = -n; x -= n;
X		if (x < 0)
X			{ n += x; x = 0; }
X	}
X	msk = 0xffff >> (x%16);	/* make mask go to end of 16bit word */
X	for(ofs=GBOFS(x,y); ofs < GBOFS(x+n, y); ofs++) {
X		BOINK(ofs, msk, c)
X		msk = 0xffff;	/* ie. solid while between end-points */
X	}
X	msk &= ~(0xffff >> ((x+n)%16));	/* remainder word mask */
X	BOINK(ofs, msk, c)
X}
X
X/*
X * vline -- vertical lines only
X *	get bit mask once then move it up or down
X *	by changing only the offset +/- 46.
X */
Xstatic
Xvline(x,y,n,c)
Xint x,y,n;
Xuchar c;
X{
X	if (n < 0) {
X		n = -n; y -= n;
X		if (y < 0)
X			{ n += y; y = 0; }
X	}
X	msk = GMASK(x);
X	ofs = GBOFS(x,y);
X	for (; n; n--, ofs+=46) {
X		BOINK(ofs, msk, c)
X	}
X}
SHAR_EOF
fi # end of overwriting check
echo shar: extracting "'tipro.h'" '(1788 characters)'
if test -f 'tipro.h'
then
	echo shar: will not over-write existing file "'tipro.h'"
else
sed 's/^X//' << \SHAR_EOF > 'tipro.h'
X/*
X * tipro.h: TI Pro-specific definitions
X *
X * copyright (c) University of Toronto, 1988.
X */
X#define CRT_INT	0x49	/* crt dsr interface */
X#define KBD_INT	0x4a	/* keyboard interface */
X
X#define TICKER	0x58	/* system timing, 25 ms. */
X#define TIMER	0x5a	/* system timing, 100 ms. */
X#define KBDMAP	0x5b	/* kbd mapping vector */
X#define KEYPAUS	0x5c	/* kbd program pause key vector */
X#define KEYBRK	0x5d	/* kbd program break key vector */
X#define KEYPRNT	0x5e	/* kbd print screen vector */
X#define KBDQUE	0x5f	/* kbd queueing vector */
X
X#define Zflag	0x40
X#define Cflag	0x01
X
X#define NOPARITY	0
X#define O_PARITY	1
X#define E_PARITY	3
X
X
X	/* function key codes */
X#define K_UP	0x4800
X#define K_DOWN	0x5000
X#define K_RIGHT	0x4d00
X#define K_LEFT	0x4b00
X
X#define K_INS	0x5200
X#define K_DEL	0x5300
X#define K_sDEL	0x3800	/* shift DELETE */
X#define K_HOME	0x4700
X
X#define K_F1	0x3b00
X#define K_F2	0x3c00
X#define K_F3	0x3d00
X#define K_F4	0x3e00
X
X#define K_F5	0x3f00
X#define K_F6	0x4000
X#define K_F7	0x4100
X#define K_F8	0x4200
X
X#define K_F9	0x4300
X#define K_F10	0x4400
X#define K_F11	0x4500
X#define K_F12	0x4600
X
X#define K_sF3	0x5600
X#define K_cF3	0x6000
X
X#define K_NUL	0x0300	/* Fnul, ctrl-2@ */
X
X#define K_SETUP	K_F1	/* and K_F2, when not in setup mode */
X#define K_BREAK	K_F3
X#define K_BKSP	K_F4
X
X#define K_shBRK	K_sF3
X#define K_cBRK	K_cF3
X
X
X#define NPORTS	4
X
X/* speeds (see <sys/ttydev.h> on a unix system) */
X/* (corresponds to table position in ports.c) */
X#define B0	0
X#define B50	1
X#define B75	2
X#define B110	3
X#define B134	4
X#define B150	5
X#define B200	6
X#define B300	7
X#define B600	8
X#define B1200	9
X#define B1800	10
X#define B2000	11
X#define B2400	12
X#define B3600	13
X#define B4800	14
X#define B7200	15
X#define B9600	16
X#define EXTA	17	/* 19200 */
X#define EXTB	18	/* 38400 (unsupported) */
SHAR_EOF
fi # end of overwriting check
#	End of shell archive
exit 0

pkern@csri.toronto.edu (pkern) (06/07/88)

#! /bin/sh
# This is a shell archive, meaning:
# 1. Remove everything above the #! /bin/sh line.
# 2. Save the resulting text in a file.
# 3. Execute the file with /bin/sh (not csh) to create the files:
#	common.h
#	cterm.ini
#	defs.c
#	esc.c
#	main.c
#	misc.c
#	printer.c
#	setup.c
#	term.c
#	text.c
# This archive created: Tue Jun  7 11:27:25 1988
# By:	pkern ()
export PATH; PATH=/bin:$PATH
echo shar: extracting "'common.h'" '(1599 characters)'
if test -f 'common.h'
then
	echo shar: will not over-write existing file "'common.h'"
else
sed 's/^X//' << \SHAR_EOF > 'common.h'
X/*
X * common.h: main common definitions
X *
X * copyright (c) University of Toronto, 1988.
X */
X	/* ascii control char names */
X#define NUL	000	/* ^@ */
X#define SOH	001	/* ^A */
X#define STX	002	/* ^B */
X#define ETX	003	/* ^C */
X#define EOT	004	/* ^D */
X#define ENQ	005	/* ^E */
X#define ACK	006	/* ^F */
X#define BEL	007	/* ^G */
X#define BS	010	/* ^H */
X#define HT	011	/* ^I */
X#define LF	012	/* ^J */
X#define VT	013	/* ^K */
X#define FF	014	/* ^L */
X#define CR	015	/* ^M */
X#define SO	016	/* ^N */
X#define SI	017	/* ^O */
X#define DLE	020	/* ^P */
X#define DC1	021	/* ^Q */
X#define DC2	022	/* ^R */
X#define DC3	023	/* ^S */
X#define DC4	024	/* ^T */
X#define NAK	025	/* ^U */
X#define SYN	026	/* ^V */
X#define ETB	027	/* ^W */
X#define CAN	030	/* ^X */
X#define EM	031	/* ^Y */
X#define SUB	032	/* ^Z */
X#define ESC	033	/* ^[ */
X#define FS	034	/* ^\ */
X#define GS	035	/* ^] */
X#define RS	036	/* ^^ */
X#define US	037	/* ^_ */
X#define SP	040	/* ' ' */
X#define DEL	0177	/* ^? */
X
X#define XON	DC1	/* ^Q */
X#define XOFF	DC3	/* ^S */
X
X#ifndef FINIT
X#define FINIT	"cterm.ini"	/* setups init file */
X#endif
X
X#ifndef NARGS
X#define NARGS	32	/* max args allowed */
X#endif
X
X	/* attribute bits */
X#define AT_MASK		0x0f
X#define AT_REV		0x01
X#define AT_UL		0x02
X#define AT_BLINK	0x04
X#define AT_BOLD		0x08
X
X#define UP	0
X#define DOWN	1
X#define RIGHT	2
X#define LEFT	3
X
X#define VT52	0
X#define ANSI	1
X#define OFS52	0
X#define ANSOFS	0x40
X#define KEYNORM 0
X#define KEYAPPL	0x20
X
X#define BUFMAX	512
X
X
Xtypedef unsigned char uchar;
X
Xextern int (*xmit)(), (*recv)();
Xextern int (*o_xmit)(), (*o_recv)();
Xextern int (*burp)(), (*esc)();
X
SHAR_EOF
fi # end of overwriting check
echo shar: extracting "'cterm.ini'" '(265 characters)'
if test -f 'cterm.ini'
then
	echo shar: will not over-write existing file "'cterm.ini'"
else
sed 's/^X//' << \SHAR_EOF > 'cterm.ini'
X# -- cterm.ini setups --
X# setup A: tabs
XA: 1 9 17 25 33 41 49 57 65 73 89 97 105 113 121 129
X#
X# setup B: main terminal options
XB: 0 1 0 0  0 0 1 1  0 1 0 1  0 0 1 0   2 9600 9600
X#
X# setup C: printer & misc. options
XC: 0 0 0 0  0 0 1 0  0 0 0 0  0 0 0 0   4 1200
SHAR_EOF
fi # end of overwriting check
echo shar: extracting "'defs.c'" '(3313 characters)'
if test -f 'defs.c'
then
	echo shar: will not over-write existing file "'defs.c'"
else
sed 's/^X//' << \SHAR_EOF > 'defs.c'
X/*
X * defs.c: init file(s) read or write handling.
X *
X * copyright (c) University of Toronto, 1988.
X */
X#include <stdio.h>
X#include <dir.h>
X#include <ctype.h>
X#include "common.h"
X
Xextern char tabs[];
X
Xextern uchar *sB[16], *sC[16];
Xextern int *sBi[3], *sCi[2];
X
Xextern int nbaud, pbaud, t_spd, pr_spd;
X
Xstatic char *svfl = FINIT;	/* saved setups filename */
Xstatic char fnbuf[80];
X
X/*
X * getdef -- retrieve setup configuration from a file.
X *	- reads from fnam instead of FINIT, if fnam not null.
X */
Xgetdefs(fnam)
Xchar *fnam;
X{
X	FILE *fp;
X	char *p, *bp, buf[128];
X	int n=0, na=0, nb=0, nc=0, nt=0;
X
X
X	nbaud = prtspd(t_spd);
X	pbaud = prtspd(pr_spd);
X
X	if (fnam && *fnam)	/* ... then use another setups file */
X		{ strcpy(fnbuf, fnam); svfl = fnbuf; }
X	if ((fp = fopen(svfl, "r")) == NULL)
X		return(-1);
X
X	/* read the saved setups and initialize */
X	while(bp = fgets(buf, 127, fp)) {
X		p = bp;	bp += strlen(bp);
X		switch(buf[0]) {
X		case 'A':	/* set some tabs */
X			nb = nc = 0;
X			do {
X				while (p<bp && !isdigit(*p)) p++;
X				if (p<bp && (n = atoi(p)))
X					{ tabs[n-1] = 't'; nt++; }
X				while (p<bp && isdigit(*p)) p++;
X			} while (p < bp);
X			break;
X		case 'B':	/* setup B */
X			na = nc = 0;
X			/*
X			 * get the 4 block of 4 1/0 flags and
X			 * the port and transmit and receive speeds
X			 */
X			while (p < bp && nb < 19) {
X				if (!isdigit(*p)) {
X					if (*p == '#') break;
X					p++; continue;
X				}
X				if (nb > 15)
X					*(sBi[nb-16]) = atoi(p);
X				else
X					*(sB[nb]) = atoi(p) % 2;
X				nb++;
X				while (p < bp && isdigit(*p)) p++;
X			}
X			break;
X		case 'C':	/* setup C */
X			na = nb = 0;
X			/*
X			 * get the 4 block of 4 1/0 flags and
X			 * the printer port number and speed
X			 */
X			while (p < bp && nc < 18) {
X				if (!isdigit(*p)) {
X					if (*p == '#') break;
X					p++; continue;
X				}
X				if (nc > 15)
X					*(sCi[nc-16]) = atoi(p);
X				else
X					*(sC[nc]) = atoi(p) % 2;
X				nc++;
X				while (p < bp && isdigit(*p)) p++;
X			}
X			break;
X		default:	/* notes, junk, ... etc. */
X			break;
X		}
X	}
X
X	fclose(fp);
X
X	/* set new tabs */
X	if (nt) for(na=0; na<132; na++) 
X		tabs[na] = (tabs[na] == 't') ? 'T' : SP;
X
X	/* adjustments */
X	*(sBi[0]) -= 1; *(sCi[0]) -= 1;	/* n_port--; p_port--; */
X
X#ifdef debug
Xcputs("B: ");
Xfor(n=0; n<16; n++)
X	cprintf(" %d%s", *sB[n], ((n+1)%4)?"":" ");
Xcprintf(" %d %d %d\r\n", *sBi[0], *sBi[1], *sBi[2]);
Xcputs("C: ");
Xfor(n=0; n<16; n++)
X	cprintf(" %d%s", *sC[n], ((n+1)%4)?"":" ");
Xcprintf(" %d %d\r\n", *sCi[0], *sCi[1]);
X
Xn = getch();
X#endif
X}
X
X/*
X * putdefs -- write current setup configuration to file svfl
X */
Xputdefs()
X{
X	FILE *fp;
X	int i, n;
X
X	if ((fp = fopen(svfl, "a")) == NULL)
X		return(-1);
X
X	/* save tabs */
X	fprintf(fp, "# -- terminal setups --\n# setup A: tabs\nA:");
X	for (i=n=0; i<132; i++) {
X		if (tabs[i] == 'T') {
X			fprintf(fp, " %d", i+1);
X			n += 2 + (i > 8) + (i > 98);
X		}
X		if (n > 72)
X			fprintf(fp, "\nA:");
X	}
X
X	fprintf(fp, "\n#\n# setup B: main terminal options\nB:");
X	for (i=0; i<16; i++)
X		fprintf(fp, " %d%s", *sB[i], ((i+1)%4)?"":" ");
X	/* n_port, t_spd, r_spd */
X	fprintf(fp, "  %d %d %d\n", *sBi[0]+1, *sBi[1], *sBi[2]);
X
X	fprintf(fp, "#\n# setup C: printer & misc. options\nC:");
X	for (i=0; i<16; i++)
X		fprintf(fp, " %d%s", *sC[i], ((i+1)%4)?"":" ");
X	/* p_port, pr_spd */
X	fprintf(fp, "  %d %d\n", *sCi[0]+1, *sCi[1]);
X	fclose(fp);
X}
SHAR_EOF
fi # end of overwriting check
echo shar: extracting "'esc.c'" '(11542 characters)'
if test -f 'esc.c'
then
	echo shar: will not over-write existing file "'esc.c'"
else
sed 's/^X//' << \SHAR_EOF > 'esc.c'
X/*
X * esc.c:
X *	Escape sequence handling routines. The "guts" of vt100-ness.
X *
X * copyright (c) University of Toronto, 1988.
X */
X/*
X * layout based in part on connect.inc from Qkermit.
X */
X#include "common.h"
X
X	/* some xt100 modes (and their default) */
Xuchar m_ansi = ANSI;	/* ANSI/VT52 mode (ANSI) */
Xuchar m_newline = 0;	/* linefeed/newline (linefeed) */
Xuchar m_repeat = 1;	/* auto repeat (on) */
Xuchar m_wrap = 1;	/* wraparound (on) */
Xuchar m_smooth = 0;	/* scrolling mode (jump) */
Xuchar m_print = 0;	/* printer controller mode (exit) */
Xuchar m_autopr = 0;	/* auto print mode (exit) */
Xuchar m_prxtent = 1;	/* print extent (full page) */
Xuchar m_prterm = 0;	/* print termintation (none) */
Xuchar m_origin = 0;	/* origin mode (absolute) */
Xuchar m_reverse = 0;	/* screen mode (normal) */
Xuchar m_insert = 0;	/* insertion/replacement (replacement) */
Xuchar m_columns = 80;	/* column mode (80 cols) */
Xuchar m_crskey = KEYNORM;	/* cursor key mode (cursor) */
Xuchar m_keypad = KEYNORM;	/* keypad mode (numeric) */
X
Xuchar srgn_top=1, srgn_bot=24;	/* scroll region markers */
X
Xstatic int attrb, o_attr, o_x, o_y=0;	/* storage */
Xstatic char *o_cset;	/* more storage */
X	
Xextern uchar cx, cy;
Xextern char tabs[], led[];
Xextern char *cset, *g0, *g1;
Xextern char *ukascii, *usascii;
Xextern int nbaud;
Xextern uchar parity, bpc, m_prty;
Xextern int avofs;
Xextern char *vt100ids[];
Xextern uchar vtidnum;
X
X#define EBMAX	256
Xchar ebuf[EBMAX];	/* escape sequence buffer: place to collect */
X			/* chars for potential future post-mortems */
X
X/*
X * EGETC():
X *	- get next byte from input buffer.
X *	- return(0) if it's CAN or return(1) if it's ESC.
X *	- execute if it's a control char.
X */
X#define EGETC(a)	\
X	while((a=recv())<SP) switch(a){\
X		case ESC: return(1); break;\
X		case CAN: case -2: return(0); break;\
X		default: doctrl(a); break;}
X
Xint (*esc)();
X
X/*
X * gather and process an ANSI escape sequence
X */
Xansi()		/* VT100 */
X{
X	char *p;
X	int vt52();
X	uchar qmark;
X	int n, pn[11], pnc;
X	register int ebi, c, i;
X	int insurpc(), burpc();
X
X	ebi = 0;
X	ebuf[ebi++] = ESC;
X	EGETC(c)
X	ebuf[ebi++] = c;
X
X	switch (c) {
X	case '#':	/* misc. special screen commands */
X		EGETC(c)
X		ebuf[ebi++] = c;
X		switch (c) {
X		case '3': /* double size, top half */
X		case '4': /* double size, bottom half */
X		case '5': /* single width, single height */
X		case '6': /* double width, single height */
X			break;
X		case '8': /* alignment test */
X			m_reverse = 0;
X			e_screen();	/* homes cursor, too */
X			srgn_top = cx = cy = 1;
X			srgn_bot = 24;
X			break;
X		}
X		break;
X	case '(': case ')':	/* select character set */
X/*	case '*': case '+':	/* vt200 extensions */
X		EGETC(c)
X		ebuf[ebi++] = c;
X		switch (c) {
X		case 'A': case '0':
X			p = ukascii; break;
X		case 'B':
X		default:
X			p = usascii; break;
X		}
X		if (ebuf[1] == '(')
X			g0 = p;
X		else
X			g1 = p;
X		break;
X	case 'D': case 'E':	/* index, newline */
X		if (c == 'E')
X			burpc(CR, cx=1, cy);
X		if (cy == srgn_bot)
X			if (srgn_top-1 || cy < 24)
X				scrl_up(1, srgn_top, srgn_bot, cx, cy);
X			else
X				burpc(LF, cx, cy);
X		else if (cy < 24)
X			burpc(LF, cx, ++cy);
X		break;
X	case 'M':	/* reverse index */
X		if (cy == srgn_top)
X			scrl_down(1, srgn_top, srgn_bot, cx, cy);
X		else if (cy > 1)
X			curs_xy(cx, --cy);
X		break;
X	case '7':	/* save cursor & attributes */
X		o_x = cx, o_y = cy, o_attr = attrb; o_cset = cset;
X		break;
X	case '8':	/* restore cursor & attributes */
X		if (!o_y) break;	/* nothing saved yet */
X		curs_xy(cx=o_x, cy=o_y);
X		attribs(o_attr);
X		cset = o_cset;
X		break;
X	case 'H':	/* set tab stop */
X		tabs[cx-1] = 'T';
X		break;
X	case '=': m_keypad = KEYAPPL; break;
X	case '>': m_keypad = KEYNORM; break;
X	case '@':	/* NB: this ain't ANSI ! */
X		/* an extension to access graphics screens for */
X		/* those too lazy to emulate Tektronix (ie. me) */
X		do {
X			EGETC(c)
X			ebuf[ebi++] = c;
X		} while ((c >= '0' && c <= '9') || c == ';');
X		ebuf[ebi] = NUL;
X		gfx(ebuf, ebi);
X		break;
X	case '[':	/* CSI (command sequence introducer) */
X		qmark = 0;
X		EGETC(c)
X		if (c == '?') {
X			qmark = 1;
X			EGETC(c)
X		}
X		while ((c >= '0' && c <= '9') || c == ';') {
X			ebuf[ebi++] = c;
X			EGETC(c)
X		}
X		ebuf[ebi++] = c;
X		/* get parameter numbers */
X		pn[0] = pn[1] = pn[2] = pn[3] = pn[4] = 0;
X		pn[5] = pn[6] = pn[7] = pn[8] = pn[9] = pn[10] = 0;
X		for (i=2, pnc=0; i<ebi; i++) {
X			n = ebuf[i] - '0';
X			if (n>=0 && n<=9)
X				pn[pnc] = pn[pnc] * 10 + n;
X			else	/* it's ';' or it's the final char */
X				pn[++pnc] = 0;
X		}
X		switch (c) {
X		case 'A':	/* cursor up */
X			if (!pn[0]) pn[0] = 1;
X			while (cy>1 && pn[0]-- && cy != srgn_top) cy--;
X			curs_xy(cx, cy);
X			break;
X		case 'B':	/* cursor down */
X			if (!pn[0]) pn[0] = 1;
X			while (cy<24 && pn[0]-- && cy != srgn_bot) cy++;
X			curs_xy(cx, cy);
X			break;
X		case 'C':	/* cursor right */
X			if (!pn[0]) pn[0] = 1;
X			if ((cx += pn[0]) > m_columns) cx = m_columns;
X			curs_xy(cx, cy);
X			break;
X		case 'D':	/* cursor left */
X			if (!pn[0]) pn[0] = 1;
X			cx = (cx > pn[0]) ? (cx - pn[0]) : 1;
X			curs_xy(cx, cy);
X			break;
X		case 'H': case 'f':	/* direct cursor address */
X			if (!(cx = pn[1])) cx = 1;
X			if (!(cy = pn[0])) cy = 1;
X			if (m_origin) {
X				cy += (srgn_top-1);
X				if (cy > srgn_bot) cy = srgn_bot;
X			}
X			if (cx > m_columns) cx = m_columns;
X			if (cy > 24) cy = 24;
X			curs_xy(cx, cy);
X			break;
X		case 'K':	/* line erase */
X			switch (pn[0]) {
X			case 0: eol_erase(cx, cy); break;
X			case 1: bol_erase(cx, cy); break;
X			case 2: line_erase(cx, cy); break;
X			}
X			break;
X		case 'J':	/* screen erase */
X			switch (pn[0]) {
X			case 0: eos_erase(cx, cy); break;
X			case 1: bos_erase(cx, cy); break;
X			case 2: all_erase(cx, cy); break;
X			}
X			break;
X		case 'L':	/* insert line */
X			if (cy < srgn_top || cy > srgn_bot) break;
X			if (!pn[0]) pn[0] = 1;
X			cx = 1;
X			line_ins(pn[0], cx, cy, srgn_bot);
X			break;
X		case 'M':	/* delete line */
X			if (cy < srgn_top || cy > srgn_bot) break;
X			if (!pn[0]) pn[0] = 1;
X			cx = 1;
X			line_del(pn[0], cx, cy, srgn_bot);
X			break;
X		case '@':	/* insert char */
X			if (!pn[0]) pn[0] = 1;
X			char_ins(pn[0], cx, cy); break;
X		case 'P':	/* delete char */
X			if (!pn[0]) pn[0] = 1;
X			char_del(pn[0], cx, cy); break;
X		case 'm':	/* attributes */
X			for (i=0; i<pnc; i++)
X				switch (pn[i]) {
X				case 0: attrb &= ~AT_MASK; break;
X				case 1:	attrb |= AT_BOLD; break;
X				case 4: attrb |= AT_UL; break;
X				case 5: attrb |= AT_BLINK; break;
X				case 7: attrb |= AT_REV; break;
X				}
X			attribs(attrb);
X			break;
X		case 'r':	/* set scroll region */
X			if (!pn[0]) pn[0] = 1;
X			if (!pn[1]) pn[1] = 24;
X			if (pn[0] < pn[1]) {
X				srgn_top = (pn[0]) ? pn[0] : 1;
X				srgn_bot = (pn[1]) ? pn[1] : 24;
X				cy = (m_origin) ? srgn_top : 1;
X				curs_xy(cx=1, cy);
X			}
X			break;
X		case 'g':	/* clear tabstop(s) */
X			switch (pn[0]) {
X			case 0:
X				tabs[cx-1] = SP;
X				break;
X			case 3:
X				for (i=0; i < m_columns; i++)
X					tabs[i] = SP;
X				break;
X			}
X			break;
X		case 'q':	/* program LEDs */
X			for (i=0; i<pnc; i++)
X				if (!pn[i])
X					led[0]=led[1]=led[2]=led[3]=SP;
X				else if (pn[i] < 5)
X					led[pn[i]-1] = '*';
X			genstat(cx, cy);	/* refresh LEDs */
X			break;
X		case 'h':	/* set modes */
X			switch (pn[0]) {
X			case 1: if (qmark) m_crskey = KEYAPPL; break;
X/* nb: fake entry	case 2: if (qmark) m_ansi = ANSI; break; */
X/*			case 3: if (qmark) m_columns = 132; break;  */
X			case 3: if (qmark) m_columns = 80; break;
X			case 4: if (qmark)	m_smooth = 1;
X				else	{ m_insert = 1;	burp = insurpc; }
X				break;
X			case 5: if (qmark) m_reverse = 1; break;
X			case 6: if (!qmark) break;
X				m_origin = 1;
X				curs_xy(cx=1, cy=srgn_top);
X				break;
X			case 7: if (qmark) m_wrap = 1; break;
X			case 8: if (qmark) {
X					m_repeat = 1;
X					kbautorep(1);
X				}
X				break;
X			case 18: if (!qmark) m_prterm = 1; break;
X			case 19: if (!qmark) m_prxtent = 1; break;
X			case 20: if (!qmark) nlmod(m_newline=1); break;
X			}
X			break;
X		case 'i':	/* printing */
X			switch (pn[0]) {
X			case 0: if (!qmark) pr_page(); break;
X			case 1: if (qmark) pr_line(); break;
X			case 4: if (qmark)	m_autopr = 0;
X				else		m_print = 0;
X				break;
X			case 5:	if (qmark)	m_autopr = 1;
X				else		m_print = 1;
X				break;
X			}
X			break;
X
X		case 'l':	/* reset modes */
X			switch (pn[0]) {
X			case 1: if (qmark) m_crskey = KEYNORM; break;
X			case 2: if (!qmark) break;
X				m_ansi = VT52; avofs = OFS52;
X				esc = vt52;
X				break;
X			case 3: if (qmark) m_columns = 80; break;
X			case 4: if (qmark)	m_smooth = 0;
X				else	{ m_insert = 0;	burp = burpc; }
X				break;
X			case 5: if (qmark) m_reverse = 0; break;
X			case 6: if (!qmark) break;
X				m_origin = 0; 
X				curs_xy(cx=1, cy=1);
X				break;
X			case 7: if (qmark) m_wrap = 0; break;
X			case 8: if (qmark) {
X					m_repeat = 0;
X					kbautorep(0);
X				}
X				break;
X			case 18: if (!qmark) m_prterm = 0; break;
X			case 19: if (!qmark) m_prxtent = 0; break;
X			case 20: if (!qmark) nlmod(m_newline=0); break;
X			}
X			break;
X		case 'n':	/* reports */
X			p = "";
X			switch (pn[0]) {
X			case 6:		/* cursor position */
X				p = "X[nnn;nnnR";
X				sprintf(p, "\033[%d;%dR", cy, cx);
X				break;
X			case 5:		/* terminal status */
X				/* reponses:
X				 *	"\033[0n" = terminal OK
X				 *	"\033[3n" = terminal not OK
X				 */
X				p = "\033[0n";
X				break;
X			case 15:	/* printer status */
X				if (qmark) switch(pr_stat()) {
X					case 1:		/* ready */
X						p = "\033[?10n"; break;
X					case 0:		/* not ready */
X						p = "\033[?11n"; break;
X					case -1:	/* no printer */
X					default:
X						p = "\033[?13n"; break;
X				}
X				break;
X			}
X			while (*p) xmit(*p++);
X			break;
X		case 'c':	/* identify */
X			if (!pn[0]) p = vt100ids[vtidnum];
X			while (*p) xmit(*p++);
X			break;
X/*		case 'y': break; /* Lanpar self test code */
X		case 'x':	/* report terminal parameters */
X			p = "X[.;.;.;...;...;1;0x";
X			n = vtspeed(nbaud);
X			sprintf(p, "\033[%d;%d;%d;%d;%d;1;0x", pn[0]+2,
X				(m_prty * (parity + 3)) + 1,
X				((bpc)? 1 : 2), n, n);
X			while (*p) xmit(*p++);
X			break;
X		}
X		break;
X	}
X	ebuf[ebi] = '\0';
X	return(0);
X}
X
X/*
X * gather and process a VT52 escape sequence
X */
Xvt52()
X{
X	char *p;
X	int ansi();
X	uchar qmark;
X	int n, pn[11], pnc;
X	register int ebi, c, i;
X
X	ebi = 0;
X	ebuf[ebi++] = ESC;
X	EGETC(c)
X	ebuf[ebi++] = c;
X
X	switch (c) {
X	case 'A': if (cy>1 && cy != srgn_top) curs_xy(cx, --cy); break;
X	case 'B': if (cy<24 && cy != srgn_bot) curs_xy(cx, ++cy); break;
X	case 'C': if (cx < 80) curs_xy(++cx, cy); break;
X	case 'D': if (cx > 1) curs_xy(--cx, cy); break;
X	case 'F':	/* UK ASCII */
X		cset = ukascii;
X		break;
X	case 'G':	/* US ASCII */
X		cset = usascii;
X		break;
X	case 'H': curs_xy(cx=1, cy=1); break;
X	case 'I':	/* reverse line feed */
X		if (cy == srgn_top)
X			scrl_down(1, srgn_top, srgn_bot, cx, cy);
X		else if (cy > 1)
X			curs_xy(cx, --cy);
X		break;
X	case 'J': eos_erase(cx, cy); break;
X	case 'K': eol_erase(cx, cy); break;
X	case 'Y':	/* cursor addressing */
X		EGETC(c)
X		ebuf[ebi++] = c;
X		EGETC(c)
X		ebuf[ebi++] = c;
X		/* ignore address if it's out of bounds */
X		if (ebuf[2] > '7' || ebuf[3] > 'o') break;
X		cy = ebuf[2] - SP;
X		cx = ebuf[3] - SP;
X		curs_xy(++cx, ++cy);
X		break;
X	case 'Z':	/* vt52 identify */
X		p = "\033/Z";
X		while (*p) xmit(*p++);
X		break;
X	case '=': m_keypad = KEYAPPL; break;
X	case '>': m_keypad = KEYNORM; break;
X	case '<':
X		m_ansi = ANSI; avofs = ANSOFS;
X		cset = usascii; esc = ansi;
X		break;
X	/* printer commands */
X	case 'W':	/* enter printer mode */
X	case 'X': 	/* exit printer mode */
X	case '^':	/* auto print mode on */
X	case '_':	/* auto print mode off */
X	case 'V':	/* print line */
X	case ']':	/* print page */
X		break;
X	}
X	ebuf[ebi] = '\0';
X	return(0);
X}
SHAR_EOF
fi # end of overwriting check
echo shar: extracting "'main.c'" '(2812 characters)'
if test -f 'main.c'
then
	echo shar: will not over-write existing file "'main.c'"
else
sed 's/^X//' << \SHAR_EOF > 'main.c'
X/*
X * main.c:
X *	main() and some misc. routines
X *
X * copyright (c) University of Toronto, 1988.
X */
X#include <stdio.h>
X#include <fcntl.h>
X#include <process.h>
X#include <dos.h>
X#include <dir.h>
X
X#include "common.h"
X#include "tipro.h"
X
Xstatic uchar iflag=0;
X
X/*
X * initialize the world and run the terminal ...
X * ... then reset the world and exit.
X */
Xmain(argc, argv)
Xint argc;
Xchar *argv[];
X{
X	char *s;
X	int n, boom();
X
X	while (--argc) {
X		argv++;
X		if (argv[0][0] == '-')
X			switch (argv[0][1]) {
X			case 'i':
X				if (getdefs(argv[1]) < 0) {
X					perror(argv[1]);
X					exit(1);
X				}
X				argv++;
X				iflag++;
X				break;
X			default:
X				break;
X			}
X	}
X
X	if (!iflag)
X		getdefs(FINIT);
X	ctrlbrk(boom);	/* for safety sake */
X	init_kbd();
X	init_scr();
X	curs_xy(1, 1); eos_erase(1, 1);
X	init_prt();
X	term();
X	boom(1);
X}
X
Xboom(sw)
Xint sw;
X{
X	reset_prt();
X	reset_kbd();
X	reset_scr();
X	if (sw) cputs("**ZAP**");
X	return(0);
X}
X
X
X/*
X * some misc. routines
X */
X
X
X/*
X * counter(), cntdn, timer_int():
X *	attempt to simulate time-outs (eg. signals on UNIX)
X */
Xunsigned int cntdn=0;
X
Xvoid interrupt (*o_timer)();
X
Xvoid interrupt
Xtimer_int()
X{
X	if (cntdn) cntdn--;
X}
X
X/*
X * install or reset timer_int ISR
X *	allows cntdn to be used as a count-down clock.
X *	(see tipro.h for difference between TIMER and TICKER)
X *	(see kermit.c or xmodem.c for counter/cntdn usage examples)
X */
Xcounter(sw)
Xint sw;
X{
X	if (sw) {	/* install timer_int ISR */
X		o_timer = getvect(TIMER);
X		disable();
X		setvect(TIMER, timer_int);
X		enable();
X	}
X	else {		/* restore old ISR */
X		disable();
X		setvect(TIMER, o_timer);
X		enable();
X	}
X}
X
X
X/* run cmd in dos */
X/*
X * please excuse the tortured code but both system() and
X * spawnl() refused to exit properly (version 1.0 Turbo C)
X */
Xdocmd(cmd)
Xchar *cmd;
X{
X	int i;
X	union REGS r;
X	char *av[] = { "", "", (char *)0 };
X	char buf[128], cpath[128];
X
X	strcpy(cpath, getenv("COMSPEC"));
X	for(i=strlen(cpath)-1; i>0; i--)
X		if (cpath[i]=='\\' || cpath[i]=='/' || cpath[i]==':')
X			{ i++; break; }
X	strcpy(buf, &cpath[i]);
X	av[0] = buf; av[1] = buf + strlen(buf);
X	r.x.ax = 0x3700; intdos(&r, &r);	/* get switchar */
X	sprintf(av[1], "%cC %s", r.h.dl, cmd);
X
X	/* phew! ok, now do it */
X	if (spawnv(P_WAIT, cpath, av) < 0)
X		perror(cmd);
X}
X
X/* doxpnd: expand name if it contains glob chars */
X/* (lazy version ... uses Turbo C's findfirst/findnext routines) */
Xstatic char *ap, abuf[NARGS*16];
X
Xdoxpnd(ac, av)
Xint ac;
Xchar *av[];
X{
X	struct ffblk ff;
X
X	if (ac < 2) ap = abuf;
X#ifdef debug
Xcprintf("%d: %s\r\n", ac, av[ac]);
X#endif
X	if (findfirst(av[ac], &ff, ~FA_LABEL) < 0) return(ac);
X	do {
X		strcpy(ap, ff.ff_name);
X		av[ac] = ap;
X		ap += strlen(ap); *ap++ = NUL;
X#ifdef debug
Xcprintf("%d: %s\r\n", ac, av[ac]);
X#endif
X	} while (!findnext(&ff) && ac++ < NARGS);
X	return(ac);	/* return new arg count */
X}		
SHAR_EOF
fi # end of overwriting check
echo shar: extracting "'misc.c'" '(4202 characters)'
if test -f 'misc.c'
then
	echo shar: will not over-write existing file "'misc.c'"
else
sed 's/^X//' << \SHAR_EOF > 'misc.c'
X/*
X * misc.c:
X *	misc. strings including keypadv[] and vt100ids[]
X *
X * copyright (c) University of Toronto, 1988.
X */
X#include "common.h"
X
Xchar ansback[33];		/* answerback message */
X
Xchar *keypadv[0x80] = {		/* cursor key & keypad strings */
X/* vt52 */
X		/* normal mode */
X	/* cursor keys */
X	"\033A", "\033B", "\033C", "\033D", "", "", "", "",
X	/* keypad */
X	"0", "1", "2", "3", "4", "5", "6", "7",
X	"8", "9", "-", ",", ".", "\r", "\033P", "\033Q",
X	"\033R", "\033S", "\200", "\b", "\003", "\r\n", ansback, "",
X	
X		/* application mode */
X	/* cursor keys */
X	"\033A", "\033B", "\033C", "\033D", "", "", "", "",
X	/* keypad */
X	"\033?p", "\033?q", "\033?r", "\033?s",
X	"\033?t", "\033?u", "\033?v", "\033?w",
X	"\033?x", "\033?y", "\033?m", "\033?l",
X	"\033?n", "\033?M", "\033P", "\033Q",
X	"\033R", "\033S", "\200", "\b",
X	"\003", "\033?M", ansback, "",
X
X/* ansi */
X		/* normal mode */
X	/* cursor keys */
X	"\033[A", "\033[B", "\033[C", "\033[D", "", "", "", "",
X	/* keypad */
X	"0", "1", "2", "3", "4", "5", "6", "7",
X	"8", "9", "-", ",", ".", "\r", "\033OP", "\033OQ",
X	"\033OR", "\033OS", "\200", "\b", "\003", "\r\n", ansback, "",
X
X		/* application mode */
X	/* cursor keys */
X	"\033OA", "\033OB", "\033OC", "\033OD", "", "", "", "",
X	/* keypad */
X	"\033Op", "\033Oq", "\033Or", "\033Os",
X	"\033Ot", "\033Ou", "\033Ov", "\033Ow",
X	"\033Ox", "\033Oy", "\033Om", "\033Ol",
X	"\033On", "\033OM", "\033OP", "\033OQ",
X	"\033OR", "\033OS", "\200", "\b",
X	"\003", "\033OM", ansback, ""
X};
X
X
Xuchar vtidnum = 9;	/* vt100ids index (see below) */
X
Xchar *vt100ids[] = {	/* device report terminal ID strings */
X		/*
X		 * strings lifted from vttest's main.c
X		 *   STP = processor option
X		 *   PP  = printer port
X		 *   AVO = advanced video option
X		 *   GPO = graphics processor option
X		 */
X	"\033[?1;0c",	/* No options (vanilla VT100)		*/
X/*	"\033[?1;1c",	/* VT100 with STP			*/
X	"\033[?1;2c",	/* VT100 with AVO (could be a VT102)	*/
X/*	"\033[?1;3c",	/* VT100 with STP and AVO		*/
X/*	"\033[?1;4c",	/* VT100 with GPO			*/
X/*	"\033[?1;5c",	/* VT100 with STP and GPO		*/
X/*	"\033[?1;6c",	/* VT100 with AVO and GPO		*/
X/*	"\033[?1;7c",	/* VT100 with STP, AVO and GPO		*/
X	"\033[?1;11c",	/* VT100 with PP and AVO		*/
X	"\033[?1;15c",	/* VT100 with PP, GPO and AVO		*/
X/*	"\033[?4;2c",	/* VT132 with AVO			*/
X/*	"\033[?4;3c",	/* VT132 with AVO and STP		*/
X/*	"\033[?4;6c",	/* VT132 with GPO and AVO		*/
X/*	"\033[?4;7c",	/* VT132 with GPO, AVO, and STP		*/
X/*	"\033[?4;11c",	/* VT132 with PP and AVO		*/
X/*	"\033[?4;15c",	/* VT132 with PP, GPO and AVO		*/
X/*	"\033[?7c",	/* VT131				*/
X/*	"\033[?12;5c",	/* VT125				*/
X/*	"\033[?12;7c",	/* VT125 with AVO			*/
X/*	"\033[?5;0c",	/* VK100 (GIGI)				*/
X/*	"\033[?5c",	/* VK100 (GIGI)				*/
X	""
X};
X
Xchar led[4] = { SP, SP, SP, SP};	/* simulated LEDs */
X
Xchar *cset, *g0, *g1;		/* character set pointers */
X	/* simulated US ASCII char set */
Xchar *usascii = "\
X\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\
X\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037\
X !\"#$%&'()*+,-./0123456789:;<=>\
X?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^\
X_`abcdefghijklmnopqrstuvwxyz{|}~\177";
X
X	/* simulated UK ASCII set */
Xchar *ukascii = "\
X\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\
X\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037\
X !\"#$%&'()*+,-./0123456789:;<=>\
X?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^\
X\040\004\261....\370\361..\331\277\332\300\305\304\
X\304\304\304_\303\264\301\302\263\363\362\343\330\234\371\177";
X
X/* tab string */
Xchar tabs[133] = {
X	'T',SP,SP,SP,SP,SP,SP,SP,'T',SP,SP,SP,SP,SP,SP,SP,
X	'T',SP,SP,SP,SP,SP,SP,SP,'T',SP,SP,SP,SP,SP,SP,SP,
X	'T',SP,SP,SP,SP,SP,SP,SP,'T',SP,SP,SP,SP,SP,SP,SP,
X	'T',SP,SP,SP,SP,SP,SP,SP,'T',SP,SP,SP,SP,SP,SP,SP,
X	'T',SP,SP,SP,SP,SP,SP,SP,'T',SP,SP,SP,SP,SP,SP,SP,
X	'T',SP,SP,SP,SP,SP,SP,SP,'T',SP,SP,SP,SP,SP,SP,SP,
X	'T',SP,SP,SP,SP,SP,SP,SP,'T',SP,SP,SP,SP,SP,SP,SP,
X	'T',SP,SP,SP,SP,SP,SP,SP,'T',SP,SP,SP,SP,SP,SP,SP,
X	'T',SP,SP,SP,NUL};
X
Xextern uchar m_columns;
X
X/*
X * tab -- return next tab-stop column position (x == current column).
X */
Xtab(x)
Xint x;
X{
X	register int i;
X
X	i = x-1;
X	if (tabs[i] != SP) i++;
X	while (i+1 < m_columns && tabs[i] == SP) ++i;
X	return(i+1);
X}
SHAR_EOF
fi # end of overwriting check
echo shar: extracting "'printer.c'" '(414 characters)'
if test -f 'printer.c'
then
	echo shar: will not over-write existing file "'printer.c'"
else
sed 's/^X//' << \SHAR_EOF > 'printer.c'
X/*
X * printer.c:
X *	printer related (dummy) functions.
X *
X * copyright (c) University of Toronto, 1988.
X */
X#include "common.h"
X
X/* send current page to printer */
Xpr_page() { }
X
X/* send curent line to printer */
Xpr_line() { }
X
X/*
X * send printer status to host
X *  possible responses:
X *	 1 = printer ready
X *	 0 = printer not ready
X *	-1 = no printer
X */
Xpr_stat() { return(-1); }
X
Xpr_init() { }
X
Xpr_reset() { }
SHAR_EOF
fi # end of overwriting check
echo shar: extracting "'setup.c'" '(14100 characters)'
if test -f 'setup.c'
then
	echo shar: will not over-write existing file "'setup.c'"
else
sed 's/^X//' << \SHAR_EOF > 'setup.c'
X/*
X * setup.c:
X *	setups(): simulate XT100+ setup screens.
X *	(beware! code in setups() is not pretty)
X *	genstat(): put general status bar on line 25.
X *
X * copyright (c) University of Toronto, 1988.
X */
X#include "common.h"
X#include "tipro.h"
X	
X#define TOGGLE(a)	a=((a)+1)%2	/* toggle between 0 and 1 */
X#define SWAP(a,b,x)	x=a;a=b;b=x;
X
Xextern int keyhit;
Xextern char tabs[], ansback[];
Xextern uchar m_ansi, m_wrap, m_newline;
Xextern uchar m_smooth, m_repeat, m_reverse;
X
Xextern char *bauds[];
X
X/* main port parameters */
Xint n_port=1, nbaud=B9600, t_spd=9600, r_spd=9600;
Xuchar bpc=1, parity=0, stopbits=0, m_prty=0;
X
X/* printer port parameters */
Xint p_port=3, pbaud=B1200, pr_spd=1200;
Xuchar p_bpc=1, p_prty=0, p_sbits=0, pm_pty=0;
X
Xuchar cursor=1;	/* block or underline cursor (block) */
Xuchar echo=0;	/* local echo (none) */
Xuchar transparent=0;	/* control chars (interpret) */
Xuchar local=0;	/* connect (on line) */
Xuchar flowctl=1, xoff=0;	/* auto xon/xoff, ready to receive */
Xuchar interlace=0;	/* graphics display */
Xuchar ignrflow=0;	/* don't ignore remote xon/xoff */
Xuchar rxoff=0;		/* no remote XOFF yet */
Xuchar devrep=1;	/* device report */
X
Xextern char *ukascii;
Xuchar pt, zilch=0;
X
Xuchar *sB[16] = { /* setup B related variables */
X	&m_smooth,	/* scroll mode */
X	&m_repeat,	/* autorepeat */
X	&m_reverse,	/* screen mode */
X	&cursor,	/* cursor type */
X	&zilch,	/* margin bell (NA) (off) */
X	&zilch,	/* keyclick (NA) (off) */
X	&m_ansi,	/* ansi/vt52 */
X	&flowctl,	/* auto xon/xoff */
X	&zilch,	/* #/pound sign (NA) (#) */
X	&m_wrap,	/* wraparound */
X	&m_newline,	/* newline */
X	&interlace,	/* interlace */
X	&parity,	/* parity sense */
X	&m_prty,	/* parity */
X	&bpc,		/* bits per char */
X/*	&zilch;	/* power (NA) (60 Hz) */
X	&stopbits	/* stop bits */
X};
X
Xuchar *sC[16] = {
X	&zilch,	/* printer => host */
X	&zilch,	/* printer test */
X	&zilch,	/* print termination */
X	&zilch,	/* print extent */
X	&p_prty,	/* printer parity sense */
X	&pm_pty,	/* printer parity */
X	&p_bpc,		/* printer bits per char */
X	&echo,	/* local echo */
X	&zilch,	/* screen saver */
X	&zilch,	/* diagnostic mode */
X	&zilch,	/* two page operation */
X	&zilch,	/* smooth scroll speed */
X	&transparent,	/* transparency mode */
X	&ignrflow,	/* discard xon/xoff from host */
X	&zilch,	/* character rate to host */
X	&devrep	/* identification */
X};
X
Xint *sBi[3] = {
X	&n_port,	/* comm port number */
X	&t_spd,		/* Tx speed */
X	&r_spd		/* Rx speed */
X};
X
Xint *sCi[2] = {
X	&p_port,	/* printer port */
X	&pr_spd		/* printer speed */
X};
X
Xstatic char *sBs[48] = {	/* setup B label strings */
X	"SCROLL: ",	"jump",	"smooth",
X	"AUTOREPEAT: ",	"off",	"on",
X	"SCREEN BACKGROUND: ",	"dark",	"light",
X	"CURSOR: ",	"underline",	"block",
X	"MARGIN BELL: ",	"off",	"on",
X	"KEYCLICK: ",	"off",	"on",
X	"ANSI/VT52: ",	"vt52",	"ansi",
X	"AUTO XON XOFF: ",	"off",	"on",
X	"SHIFTED \"3\": ",	"#",	"\234",
X	"WRAP AROUND: ",	"off",	"on",
X	"NEW LINE: ",	"off",	"on",
X	"INTERLACE: ",	"off",	"on",
X	"PARITY SENSE: ",	"odd",	"even",
X	"PARITY: ",	"disabled",	"enabled",
X	"BITS PER CHAR: ",	"7",	"8",
X/*	"POWER (HZ): ",	"60",	"50",	*/
X	"STOPBITS: ",	"1",	"2",
X};
X
Xstatic char *sCs[48] = {	/* setup C label strings */
X	"PRINTER => HOST: ",	"disabled",	"enabled",
X	"PRINTER TEST: ",	"disabled",	"enabled",
X	"PRINT TERMINATION: ",	"none",	"form feed",
X	"PRINT EXTENT: ",	"scroll window",	"all",
X	"PARITY SENSE: ",	"odd",	"even",
X	"PARITY: ",	"disabled",	"enabled",
X	"BITS PER CHAR: ",	"7",	"8",
X	"LOCAL ECHO: ",	"disabled",	"enabled",
X	"SCREEN SAVER: ",	"disabled",	"enabled",
X	"DIAGNOSTIC MODE: ",	"disabled",	"enabled",
X	"TWO PAGE OPERATION (80 COL): ", "disabled",	"enabled",
X	"SMOOTH SCROLL SPEED: ",	"slow",	"fast",
X	"TRANSPARENCY MODE: ",	"disabled",	"enabled",
X	"DO NOT PROCESS \"XOFF/XON\": ", "disabled",	"enabled",
X	"CHARACTER RATE TO HOST: ", "unlimited", "limited to 60 cps",
X	"DEVICE REPORT: ",	"Esc[?1;11c",	"Esc[?1;2c",
X};
X
X/* display setup screens, set modes/parameters */
Xsetups()
X{
X	int ac;
X	char *av[NARGS];
X	int (*proto)(), kermit(), xmodem(), text();
X
X	char b, pb, nbuf[256], *p, *s;
X	int c, i, n, n0, x, ox, togl, pnum, ppn;
X
X	/* restore kb interrupts */
X	reset_kbd();
X	/* save screen image */
X	save_scr();
X		
X	pt = *(ukascii+'l');
X	pnum = n_port;	ppn = p_port;
X	b = nbaud; pb = pbaud;
X	togl = 0;
X	av[0] = (char *)0;
X
Xset_up:		/* re-entry ... refreshes info screen */
X	curs_xy(1, 1);
X	eos_erase(1, 1);
X	genstat(1, 1);
X	burps("SET-UP", 2, 2, AT_BLINK);
X	burps("TO EXIT PRESS \"SETUP\"", 2, 4, AT_UL);
X	burps("\
X  F1      F2      F3       F4     \
X              F9      F10     F11     F12     \
X SETUP  (SETUP)  Break   Backspace\
X              Up      Down    Left   Right    ", 1, 8, 0);
X	burps("\
X clear/    clear    line/   setups\
X  toggle  transmit  receive    80/132  reset  \
Xset tabs  all tabs   local   a/b/c\
X   1/0     speed     speed     (port)         \
X   2@        3#       4$      5%  \
X    6^       7&        8*        9(      0)   ", 1, 14, 0);
X
Xset_a:
X	burps("A", 9, 2, AT_BLINK);
X	for (i=0; i<80; i+=20) {
X		burps("1234567890", i+1, 24, 0);
X		burps("1234567890", i+11, 24, AT_REV);
X	}
X	tabs[80] = NUL;
X	burps(tabs, 1, 23, 0);
X	for(x=1;;) switch(c=kbdget()) {
X		case K_SETUP:
X		case K_F2:	goto done;
X
X		case '0':
Xfresh:		/* reset terminal configuration */
X			getdefs("");
X			devset();
X			pnum = n_port;	ppn = p_port;
X			b = nbaud; pb = pbaud;
X			goto set_up; break;
X
X		case SP:
X		case K_F12:
X		case K_RIGHT:	x=(x<80)?x+1:80; curs_xy(x, 23); break;
X
X		case BS:
X		case K_F11:
X		case K_LEFT:	x=(x>1)?x-1:1; curs_xy(x, 23); break;
X
X		case CR:	curs_xy(x=1, 23); break;
X
X		case HT:	curs_xy(x=tab(x), 23); break;
X
X		case '5':
X		case K_DOWN:	goto set_b; break;
X
X		case K_UP:	goto set_c; break;
X
X		case '4':		/* toggle connect mode */
X			TOGGLE(local);
X			genstat(x, 23);
X			break;
X
X		case '2':		/* toggle tab */
X			if (tabs[x-1] == 'T')
X				tabs[x-1] = SP;
X			else
X				tabs[x-1] = 'T';
X			burpc(tabs[x-1]); burpc(BS);
X			break;
X
X		case K_INS:		/* set tab */
X			tabs[x-1] = 'T';
X			burpc(tabs[x-1]); burpc(BS);
X			break;
X
X		case K_DEL:		/* erase tab */
X			tabs[x-1] = SP;
X			burpc(tabs[x-1]); burpc(BS);
X			break;
X
X		case 'T':	/* set default tabs */
X			curs_xy(1, 23);
X			for(i=0; i<80; i++) {
X				tabs[i] = SP;
X				if (i && !(i%8)) tabs[i] = 'T';
X				burpc(tabs[i]);
X			}
X			curs_xy(x, 23);
X			break;
X
X		case '3':		/* clear all tabs */
X			for(i=0; i<80; i++) tabs[i] = SP;
X			burps(tabs, x=1, 23, 0);
X			break;
X
X		case 'S':	/* save setup */
Xdumpit:
X			all_erase();
X			burps("  PLEASE   WAIT  ", 31, 6, AT_REV | AT_BLINK);
X			curs_xy(48,6);
X			t_spd = r_spd = atoi(bauds[b]);
X			pr_spd = atoi(bauds[pb]);
X			sBi[0] = &pnum; sCi[0] = &ppn;
X
X			sleep(3);	/* pretend churning :-) */
X			putdefs();
X
X			sBi[0] = &n_port; sCi[0] = &p_port;
X			goto set_up;
X			break;
X
X		case '!':	/* execute a command in dos */
Xcmd:
X			burps("! ", 1, 21, 0); curs_xy(3,21);
X			nbuf[0] = 80; s = cgets(nbuf);
X			if (nbuf[1]) {
X				reset_scr();
X				clr_home();
X				docmd(s);
X				kbflush();
X				burps(s, 1, 25, AT_REV);
X				curs_xy(nbuf[1]+1, 25);
X				c = kbdget();
X				init_scr();
X				goto set_up;
X			}
X			curs_xy(1, 21); eol_erase(1, 21);
X			curs_xy(x, 23);
X			break;
X
X		/*
X		 * file transfer:
X		 *	k - kermit
X		 *	x - xmodem
X		 *	c - text ("cat")
X		 */
X		case 'k':
X			av[0] = "kermit";
X			proto = kermit;
X		case 'c':
X			if (!av[0]) {
X				av[0] = "cat";
X				proto = text;
X			}
X		case 'x':
X			if (!av[0]) {
X				av[0] = "xmodem";
X				proto = xmodem;
X			}
X			burps("$ ", 1, 21, 0);
X			burps(av[0], 3, 21, 0);
X			curs_xy(4+strlen(av[0]),21);
X			nbuf[0] = 80; s = cgets(nbuf);
X			reset_scr();
X			clr_home();
X			for(ac=1, n=*s; *s && n && ac<NARGS; ac++) {
X				while (*s && *s == SP) *s++ = NUL;
X				if (!*s) break;
X				av[ac] = s;
X				while (*s && *s != SP) s++;
X				n = *s; *s++ = NUL;
X				ac = doxpnd(ac,av);
X			}
X			av[ac] = (char *)0;
X#ifdef debug
Xcprintf("argc = %d\r\n", ac);
Xfor(i=0; av[i]; i++)
X	cprintf(" %s", av[i]);
Xcputs("\r\n");
X#endif
X			n = proto(ac,av);
X
X			kbflush();
X			sprintf(nbuf, "%s returned %d", av[0], n);
X			burps(nbuf, 1, 25, AT_REV);
X			curs_xy(strlen(nbuf)+1, 25);
X			c = kbdget();
X			init_scr();
X			av[0] = (char *)0;
X			goto set_up;
X			break;
X
X		default:
X			break;
X		}
X	goto done;
X
Xset_b:
X	curs_xy(1, 23); eos_erase(1, 23);
X	burps("B", 9, 2, AT_BLINK);
X	for (i=0; i<16; i++)
X		nbuf[i] = (*sB[i]) + '0';
X
X	burps("1 ....  2 ....  3 ....  4 ....", 1, 24, 0);
X	for(i=16, n=27; i; i-=4, n-=8) {
X		nbuf[i] = NUL;
X		burps(nbuf+i-4, n, 24, AT_REV);
X	}
X	burps("PORT .      T SPEED .....   R SPEED .....", 36, 24, 0);
X	s = "0"; *s = '1'+pnum; burps(s, 41, 24, 0);
X	burps(bauds[b], 56, 24, 0); burps(bauds[b], 72, 24, 0);
X	curs_xy(1, 23);
X	for(ox=x=1, togl=0;; togl=0) {
X		switch(c=kbdget()) {
X		case K_SETUP:
X		case K_F2:	goto done;
X
X		case '0':	goto fresh; break;
X
X		case SP:
X		case K_F12:
X		case K_RIGHT:	x=(x<80)?x+1:80; break;
X
X		case BS:
X		case K_F11:
X		case K_LEFT:	x=(x>1)?x-1:1; break;
X
X		case K_UP:	goto set_a; break;
X
X		case '4':		/* toggle connect mode */
X			TOGGLE(local);
X			genstat(x, 23);
X			break;
X
X		case '5':
X		case K_DOWN:	goto set_c; break;
X
X		case CR: x = 1; break;
X
X		case HT: x = tab(x); break;
X
X		case '6':	togl++; break;
X
X		case 'A':	/* answer back message */
X			burps("A = ", 1, 21, 0); curs_xy(5, 21);
X			i = 0;
X			c = (n0 = kbdget()) & 0xff;
X			if (c<SP) { burpc('^'); c+=0100; }
X			burpc(c);
X			while (i<20 && (n=kbdget()) != n0) {
X				ansback[i++] = c = n & 0xff;
X				if (c<SP) { burpc('^'); c+=0100; }
X				burpc(c);
X			}
X			ansback[i] = NUL;
X			curs_xy(1, 21); eol_erase(1, 21);
X			curs_xy(x, 23);
X			break;
X
X		/* speeds */
X		case '7': case '8':
X		case 'r': case 'R':
X		case 't': case 'T':
X			b = (b+1) % (EXTB+1);
X			burps(bauds[b], 56, 24, 0);
X			burps(bauds[b], 72, 24, 0);
X			curs_xy(x, 23);
X			break;
X
X		case '9':	/* was 80/132 col toggle */
X		case 'p': case 'P':
X			pnum = (pnum+1) % NPORTS;
X			s = "0"; *s = '1'+pnum; burps(s, 41, 24, 0);
X			curs_xy(x, 23);
X			break;
X
X		case 'S':	/* save setup */
X			goto dumpit;
X			break;
X
X		case '!':	/* dos command */
X			goto cmd;
X			break;
X
X		default:
X			break;
X		}
X
X		if (x != ox)
X			{ eol_erase(ox, 23); curs_xy(x, 23); }
X
X		ox = x;
X		i = x-3;
X		if (i > 27 || i & 4) continue;
X		i = (i & 3) | ((i & 24) >> 1);
X		n = i * 3;
X		if (togl) switch (i) {
X		/* block 1 */
X		case 1:
X			TOGGLE(m_repeat);
X			kbautorep(m_repeat);
X			break;
X		case 3:
X			TOGGLE(cursor);
X			curs_type(cursor);
X			break;
X
X/*
X *		case 6: case 7: case 9: case 10:
X *		case 12: case 13: case 14: case 15:
X *			TOGGLE(*sB[i]); break;
X */
X		/* block 2 */
X		case 6: TOGGLE(m_ansi);		break;
X		case 7: TOGGLE(flowctl);	break;
X
X		/* block 3 */
X		case 9: TOGGLE(m_wrap);		break;
X		case 10: TOGGLE(m_newline);	break;
X		case 11:
X			TOGGLE(interlace);
X			init_gfx();
X			break;
X
X		/* block 4 */
X		case 12: TOGGLE(parity);	break;
X		case 13: TOGGLE(m_prty);	break;
X		case 14: TOGGLE(bpc); 		break;
X		case 15: TOGGLE(stopbits);	break;
X
X		default:
X			break;
X		}
X		sdisp(x, *sB[i], sBs[n], sBs[n+1], sBs[n+2]);
X	}
X	goto done;
X
Xset_c:		/* mostly printer-related */
X	curs_xy(1, 23); eos_erase(1, 23);
X	burps("C", 9, 2, AT_BLINK);
X	for (i=0; i<16; i++)
X		nbuf[i] = (*sC[i]) + '0';
X
X	burps("1 ....  2 ....  3 ....  4 ....", 1, 24, 0);
X	for(i=16, n=27; i; i-=4, n-=8) {
X		nbuf[i] = NUL;
X		burps(nbuf+i-4, n, 24, AT_REV);
X	}
X
X	burps("PRINTER PORT  .", 49, 24, 0);
X	s = "0"; *s = '1'+ppn; burps(s, 63, 24, 0);
X	burps("SPEED .....   ", 66, 24, 0);
X	burps(bauds[pb], 72, 24, 0);
X	curs_xy(1, 23);
X
X	for(ox=x=1, togl=0;; togl=0) {
X		switch(c=kbdget()) {
X		case K_SETUP:
X		case K_F2:	goto done;
X
X		case '0':	goto fresh; break;
X
X		case SP:
X		case K_F12:
X		case K_LEFT:	x=(x>1)?x-1:1; break;
X
X		case BS:
X		case K_F11:
X		case K_RIGHT:	x=(x<80)?x+1:80; break;
X
X		case K_UP:	goto set_b; break;
X
X		case '4':		/* toggle connect mode */
X			TOGGLE(local);
X			genstat(x, 23);
X			break;
X
X		case '5':
X		case K_DOWN:	goto set_a; break;
X
X		case CR: x = 1; break;
X
X		case HT: x = tab(x); break;
X
X		case '6':	togl++; break;
X
X		case '7': case '8':	/* printer speed */
X			pb = (pb+1) % (EXTB+1);
X			burps(bauds[pb], 72, 24, 0);
X			curs_xy(x, 23);
X			break;
X
X		case '9':	/* was 80/132 toggle */
X		case 'p': case 'P':	/* printer port */
X			ppn = (ppn+1) % NPORTS;
X			s = "0"; *s = '1'+ppn; burps(s, 63, 24, 0);
X			curs_xy(x, 23);
X			break;
X
X		case 'S':	/* save setups */
X			goto dumpit;
X			break;
X
X		case '!':	/* dos command */
X			goto cmd;
X			break;
X
X		default:
X			break;
X		}
X
X		if (x != ox)
X			{ eol_erase(ox, 23); curs_xy(x, 23); }
X
X
X		ox = x;
X		i = x-3;
X		if (i > 27 || i & 4) continue;
X		i = (i & 3) | ((i & 24) >> 1);
X		n = i * 3;
X		if (togl) switch (i) {
X/*
X *		case 4: case 5: case 6: case 7: case 12:
X *			TOGGLE(*sC[i]); break;
X */
X		case 4:	TOGGLE(p_prty);	break;
X		case 5:	TOGGLE(pm_pty);	break;
X		case 6:	TOGGLE(p_bpc);	break;
X		case 7: TOGGLE(echo);	break;
X
X		/* block 4 */
X		case 12: TOGGLE(transparent);	break;
X		case 13: TOGGLE(ignrflow);	break;
X		case 15: TOGGLE(devrep);	break;
X
X		default:
X			break;
X		}
X		sdisp(x, *sC[i], sCs[n], sCs[n+1], sCs[n+2]);
X	}
Xdone:
X	pbaud = pb;
X	pr_reset();
X	p_port = ppn;
X	pr_init();
X
X	nbaud = b;
X	if (pnum != n_port) {
X		reset_prt();
X		n_port = pnum;
X		init_prt();
X	}
X	restore_scr();
X	init_kbd();
X	set_prt();
X	devset();
X}
X
X/* display a setup option, underline current selection */
X
Xsdisp(x, sw, label, off, on)
Xint x, sw;
Xchar *label, *off, *on;
X{
X	char *p;
X	int l, n, f;
X
X	l = strlen(label); n = strlen(on);
X	f = x+2+l+n; n = x+1+l;
X	p = "0"; *p = '0' + (sw>0);
X	burps(p, x, 24, AT_REV);
X	burps(label, x+1, 23, 0);
X	burps(on, n, 23, (sw)? AT_UL : 0);
X	*p = '/'; burps(p, f-1, 23, 0);
X	burps(off, f, 23, (sw)? 0 : AT_UL);
X	*p = pt; burps(p, x, 23, 0);
X}
X
Xchar stbuf[81];		/* status line buffer */
Xextern char led[];
X
X/* general status line */
Xgenstat(x, y)
Xuchar x, y;
X{
X	/* comm information */
X	sprintf(stbuf, "port:%d data:%d%c%d speed:%5s        ",
X		n_port+1, bpc+7,
X		((m_prty) ? ((parity) ? 'E' : 'O') : 'N'),
X		stopbits+1, bauds[nbaud]);
X	/* connect mode "leds" */
X	sprintf(&stbuf+35, "on line %c  local %c       ",
X		(local) ? SP : '*', (local) ? '*' : SP);
X	/* programmable "leds" */
X	sprintf(&stbuf+60, "1 %c  2 %c  3 %c  4 %c  ",
X		led[0], led[1], led[2], led[3]);
X	sturp(stbuf, x, y);
X}
SHAR_EOF
fi # end of overwriting check
echo shar: extracting "'term.c'" '(7801 characters)'
if test -f 'term.c'
then
	echo shar: will not over-write existing file "'term.c'"
else
sed 's/^X//' << \SHAR_EOF > 'term.c'
X/*
X * term.c:
X *	term(): the terminal.
X *	rloop(), xloop(): local mode recv & xmit routines
X *	devset(): assigns xmit & recv and
X *		  handles other setings and "devices."
X * note: some code gets repeated here and there.
X *	 this may not be pretty but it keeps the
X *	 main loops from getting bogged down.
X *
X * copyright (c) University of Toronto, 1988.
X */
X#include "common.h"
X
Xuchar cx=1, cy=1;	/* current cursor position */
Xuchar tx=0, ty=0;	/* cursor "memory" (for wrap, scroll, etc.) */
X
Xextern char ansback[];
Xextern char *cset, *g0, *g1;
Xextern char *usascii, *ukascii;
Xextern char *keypadv[];
X
Xextern uchar keyboom, keyhit;
Xextern uchar m_insert, m_repeat;
Xextern uchar m_ansi, m_crskey, m_keypad;
Xextern uchar m_columns, m_wrap, m_newline;
Xextern uchar srgn_bot, srgn_top;
Xextern uchar local, transparent, echo, xoff, cursor;
Xextern uchar ignrflow, rxoff, devrep, vtidnum, txtxfr;
X
Xextern int xmit_chr(), recv_chr(), trns_chr();
Xextern int burpc(), insurpc(), ansi(), vt52();
Xextern int kbdget();
X
Xint avofs = ANSOFS;	/* ansi/vt52 keypadv "offset" bits */
Xint (*xmit)(), (*recv)();	/* xmit = output to "comm port" */
Xint (*o_xmit)(), (*o_recv)();	/* recv = input from "comm port" */
Xint (*burp)();			/* output to "screen" */
Xint (*keyg)(), (*o_keyg)();	/* input from "keyboard" */
X
X/*
X * term -- the main loop, the guts, "where the action is"
X *	"key" input has priority. Only after the "key type-ahead"
X *	buffer is emptied does it check the input buffer.
X *	(except when rxoff is high (ie. a remote XOFF request))
X */
Xterm()
X{
X	char *p;
X	int zip();
X	register int c;
X
X	cset = g0 = g1 = usascii;
X
X	devset();
X
X	while (!keyboom) {
X		while (keyhit) {	/* drain key buffer(s) */
X			if ((c = keyg()) & 0xff) {	/* ascii keys */
X				xmit(c);
X				if (c < SP) switch (c) {
X					case CR:
X						if (m_newline) xmit(LF);
X						break;
X					case XOFF:
X						xoff++; recv=zip;
X						break;
X					case XON:
X						xoff=0; recv=o_recv;
X						break;
X					default:
X						break;
X				}
X			}
X			else if ((c = kbdfn(c)) & 0x80)	/* setup keys */
X				setups();
X			else if (c & 0x40) {	/* send BREAK or NUL */
X				if (c & 1) xmit(NUL);
X				else send_brk(local);
X			}
X			else {			/* function "keys" */
X				c |= (c & 0x18) ? m_keypad : m_crskey;
X				p = keypadv[c | avofs];
X				while (*p) xmit(*p++ & 0x7f);
X				if (rxoff) break;
X			}
X		}
X
X		/* check incoming buffer(s) */
X		if ((c = recv()) < 0) continue;
X
X		if (c & 0x60) {		/* visible ascii */
Xsplat:
X			/*
X			 * wraparound handling: tx indicates a visible
X			 * char was last placed in the final column.
X			 * if our line position (cy) hasn't changed
X			 * and if m_wrap then if we're at the end of a
X			 * scroll region, scroll else move down 1 line.
X			 */
X			if (tx && ty == cy && m_wrap) {
X				tx = ty = 0;
X				curs_xy(cx=1, cy);	/* CR */
X				if (cy == srgn_bot)	/* scroll it */
X				/*	scrl_up(1, srgn_top, srgn_bot, cx, cy);	 */
X					/*
X					 * seems TI bios scrolls faster
X					 * when burping LF than with
X					 * scrl_up(1,1,24), so let's try
X					 * to take advantage of that.
X					 */
X					if (srgn_top-1 || cy < 24)
X						scrl_up(1, srgn_top, srgn_bot, cx, cy);
X					else
X						burpc(LF, cx, cy);
X				else if (cy < 24)
X					curs_xy(cx, ++cy);
X			}
X
X			burp(*(cset+c), cx++, cy);	/* screen it */
X
X			if (cx > m_columns) {	/* at last column? */
X				/* next char might wraparound */
X				ty = cy;
X				curs_xy(cx=tx=m_columns, cy);
X			}
X			continue;
X		}
X
X		switch (c) {		/* control chars */
X		case CR: tx = 0; curs_xy(cx=1, cy); break;
X		case LF: case VT: case FF:
X			tx = 0;
X			if (cy == srgn_bot)	/* scroll it */
X				if (cy < 24 || srgn_top-1)
X					scrl_up(1, srgn_top, srgn_bot, cx, cy);
X				else
X					burpc(LF, cx, cy);
X			else if (cy < 24)
X				curs_xy(cx, ++cy);
X			break;
X		case ESC:
X			while (esc()) ;
X			if (tx && !(ty == cy && tx == cx)) tx = 0;
X			break;
X		case HT: tx = 0; curs_xy(cx=tab(cx), cy); break;
X		case BS:
X			tx = 0;
X			if (cx > 1) curs_xy(--cx, cy);
X			break;
X		case SO: cset = g1; break;
X		case SI: cset = g0; break;
X/*		case DC1: kbunlck(); break; 	/* XON */
X/*		case DC3: kblock(); break;	/* XOFF */
X		case DC1: rxoff = 0; break;
X		case DC3: if (!ignrflow) rxoff++; break;
X		case BEL:
X			/* might want to have another BEL.
X			 * in the meantime let bios handle it */
X			burpc(c, cx, cy); break;
X		case ENQ: p = ansback; while (*p) xmit(*p++); break;
X		case NUL: break;
X		default:	/* not a special ctrl char? */
X				/* ok burp it, lessee what happens */
X			goto splat;
X			break;	/* not reached */
X		}
X	}
X}
X
X/* handle ctrl chars (from EGETC in esc.c) */
Xdoctrl(c)
Xregister int c;
X{
X	char *p;
X
X	switch (c) {
X	case CR: tx = 0; curs_xy(cx=1, cy); break;
X	case LF: case VT: case FF:
X		tx = 0;
X		if (cy == srgn_bot)
X			if (cy < 24 || srgn_top-1)
X				scrl_up(1, srgn_top, srgn_bot, cx, cy);
X			else
X				burpc(LF, cx, cy);
X		else if (cy < 24)
X			curs_xy(cx, ++cy);
X		break;
X/* NB:	case ESC:  	... not handled here. */
X	case ENQ: p = ansback; while (*p) xmit(*p++); break;
X	case BS:
X		tx = 0;
X		if (cx > 1) curs_xy(--cx, cy);
X		break;
X	case HT: tx = 0; curs_xy(cx=tab(cx), cy); break;
X	case SO: cset = g1; break;
X	case SI: cset = g0; break;
X/*	case DC1: kbunlck(); break; 	/* XON */
X/*	case DC3: kblock(); break;	/* XOFF */
X	case DC1: rxoff = 0; break;
X	case DC3: if (!ignrflow) rxoff++; break;
X	case BEL: /* see BEL comment in term() */
X		burpc(c, cx, cy); break;
X	default:
X		break;
X	}
X}
X
X/*
X * local mode:
X *	"key" output is placed into local input buffer
X *	where it's received and read as "comm" input.
X *	(see devset() for xmit/recv assignments)
X */
X
X/* get more chars into lbuf buffer (called from rloop()) */
Xxtract()
X{
X	int c;
X	char *p;
X
X	while (keyhit) {
X		if ((c = keyg()) & 0xff) {	/* ascii keys */
X			xmit(c);
X			if (m_newline && c == CR)	xmit(LF);
X		}
X		else if ((c = kbdfn(c)) & 0x80) {	/* setup key */
X			setups();
X			if (!local) return(-2);
X		}
X		else if (c & 0x40) {	/* send BREAK or NUL */
X			if (c & 1) xmit(NUL);
X			else send_brk(local);
X		}
X		else {			/* "function" keys */
X			c |= (c & 0x18) ? m_keypad : m_crskey;
X			p = keypadv[c | avofs];
X			while (*p) xmit(*p++);
X			if (rxoff) break;
X		}
X	}
X	return(-1);
X}
X
X/* local mode buffer + buffer indices */
Xint lin, lout;
Xchar lbuf[BUFMAX];
X#define BUFC(a,b)	((a<b)?(a+BUFMAX-b):(a-b))
X
X/* local mode "xmit" -- send typed chars to local input buffer */
Xxloop(c)
Xint c;
X{
X	if (!rxoff &&
X	    BUFC(lin,lout) > BUFMAX-8) {	/* buffer almost full */
X		rxoff++;		/* probably due to stxt() */
X		lbuf[lin++] = DC1;
X		lin %= BUFMAX;
X	}
X
X	if (transparent && c < SP) {
X		lbuf[lin++] = '^';
X		lin %= BUFMAX;
X		c |= '@';
X	}
X	lbuf[lin++] = c & 0x7f;
X	lin %= BUFMAX;
X}
X
X/* local mode "recv" -- get chars from local input buffer */
Xrloop()
X{
X	int c;
X
X	if (BUFC(lin,lout) > 0) {
X		c = lbuf[lout++];
X		lout %= BUFMAX;
X		return(c);
X	}
X	/* buffer empty so check for more key input */
X	return(xtract());
X}
X
X/* echo mode "xmit" (not used when "local") */
Xxsplit(c)
X{
X	loop_chr(c);	/* insert char into incoming data buffer */
X	xmit_chr(c);	/* send char to host */
X}
X
X
X/*
X * choose devices(ie. procedures) according to current options.
X */
Xdevset()
X{
X	xypos(&cx, &cy);
X	curs_type(cursor);
X	kbautorep(m_repeat);
X	nlmod(m_newline);
X	genstat(cx, cy);
X	init_gfx();
X	if (ignrflow) rxoff = 0;
X	vtidnum = (devrep) ? 1 : 2;	/* see misc.c */
X
X	xmit = (echo) ? xsplit : xmit_chr;
X	recv = (transparent) ? trns_chr : recv_chr;
X
X	if (local) {
X		recv = rloop;
X		xmit = xloop;
X	}
X
X	burp = (m_insert) ? insurpc : burpc;
X	esc = (m_ansi) ? ansi : vt52;
X	keyg = kbdget;
X
X	avofs = (m_ansi) ? ANSOFS : OFS52;
X
X	o_xmit = xmit;
X	o_recv = recv;
X	o_keyg = keyg;
X
X	if (txtxfr)	/* ... then reassign keyg() */
X		txtset();
X}
X
X/*
X * zip -- dummy comm port input function
X * used when XOFF hit (or PAUS (see keybrd.c)) to "freeze" the screen.
X * (depends on flow control to take care of incoming comm data)
X */
Xzip()
X{
X	return(-1);
X}
SHAR_EOF
fi # end of overwriting check
echo shar: extracting "'text.c'" '(3105 characters)'
if test -f 'text.c'
then
	echo shar: will not over-write existing file "'text.c'"
else
sed 's/^X//' << \SHAR_EOF > 'text.c'
X/*
X * text.c:
X *	raw ascii text transfer functions
X *
X * copyright (c) University of Toronto, 1988.
X */
X#include <fcntl.h>
X
Xstatic int xfd=0;
X
Xunsigned char txtxfr=0;
X
X#define LSZ	255
X	
X#ifdef debug
Xstatic int dfd;
Xstatic char *dp, dbuf[LSZ];
X#endif
X
Xstatic int ln = 0;
Xstatic char *lp, lbuf[LSZ];
Xstatic char prog[16], *opt, fnam[16];
Xstatic int oparms;
Xstatic int sflag, rflag, fdone, bflag, tflag, errflg;
X
X/*
X * text -- text transfer "interface" called from setups()
X *	sets local flags needed by txtset().
X *	checks argument options and the filename.
X */
Xtext(ac, av)
Xint ac;
Xchar *av[];
X{
X	char *p;
X
X	strcpy(prog, av[0]);
X	sflag = rflag = fdone = bflag = tflag = errflg = 0;
X
X	if (ac < 2 || ac > 3)
X		goto usage;
X
X	opt = av[1];
X
X	for (p = opt; *p; p++)
X		switch (*p) {
X		case '$': fdone++; break;
X		case 's': sflag++; break;
X		case 'r': rflag++; break;
X		case 't': tflag++; break;
X		case 'b': bflag++; break;
X		default: errflg++; break;
X		}
X
X	if (errflg || (sflag+rflag) != 1 || (bflag+tflag+fdone) != 1) {
Xusage:
X		cprintf("\
XUsage: %s {st|sb|s$|rt|rb|r$} filename\r\n", prog);
X		cputs("\
X\tst - send text\r\n\
X\tsb - send binary\r\n\
X\ts$ - terminate send (close file)\r\n\
X\trt - receive text\r\n\
X\trb - receive binary\r\n\
X\tr$ - terminate receive\r\n");
X		return(-1);
X	}
X
X	if (fdone) {	/* shutdown rtxt() or stxt() */
X		if (xfd > 0) {
X			if (rflag && ln > 0)
X				write(xfd, lbuf, ln);
X			close(xfd);
X		}
X		txtxfr = xfd = 0;
X		return(0);
X	}
X
X	if (sflag)
X		oparms = O_RDONLY | ((bflag) ? O_BINARY : 0);
X	else
X		oparms = O_WRONLY|O_BINARY|O_CREAT;
X
X	strcpy(fnam, av[2]);
X	if (xfd > 0) close(xfd);
X	if ((xfd = open(fnam, oparms, 0664)) < 0) {
X		perror(fnam);
X		txtxfr = xfd = 0;
X		return(-1);
X	}
X	close(xfd);	/* only wanted to test fnam */
X	cprintf("\r\n%s transfer of %s will begin on exit from setups.\r\n",
X		(tflag) ? "Ascii text" : "Raw data", fnam);
X	txtxfr++;
X	return(0);
X}
X
Xextern unsigned char keyhit, rxoff;
Xextern int (*recv)(), (*o_recv)();
Xextern int (*keyg)(), (*xmit)();
X
X/* prepare files and routines for text transfer */
Xtxtset()
X{
X	int stxt();
X	int rtxt();
X	extern int recv_byt();
X	extern unsigned char local, transparent;
X
X	lp = lbuf; ln = 0;
X
X	if (sflag) {
X		xfd = open(fnam, oparms);
X		ln = read(xfd, lp, LSZ);
X		if (ln < 1 || keyhit) {
X			txtxfr = 0;
X			return;
X		}
X		keyg = stxt;
X		keyhit = ln;
X	}
X	else if (rflag) {
X		recv = rtxt;
X		xfd = open(fnam, oparms, 0664);
X		if (bflag && !(local || transparent))
X			o_recv = recv_byt;	/* was recv_chr */
X	}
X
X	txtxfr = 0;
X}
X
X/* send text */
Xstxt()
X{
X	int n;
X
X	if (rxoff)	/* remote XOFF? ok, take a break */
X		return(0);	
X
X	n = *lp++;
X	if (n == '\n' && tflag) n = '\r';
X
X	if (keyhit != ln) {	/* user hit a key? */
X		close(xfd);
X		xfd = keyhit = 0;
X		devset();
X		return(n);
X	}
X
X	ln--;
X	if (keyhit) keyhit--;
X
X	if (ln < 1) {
X		lp = lbuf;
X		keyhit = ln = read(xfd, lp, LSZ);
X		if (ln < 1) {
X			close(xfd);
X			xfd = keyhit = 0;
X			devset();
X		}
X	}
X	return(n);
X}
X
X/* receive text */
Xrtxt()
X{
X	int n;
X	char c;
X
X	if ((n = o_recv()) < 0)
X		return(n);
X	lbuf[ln] = n; ln++;
X	if (ln >= LSZ) {
X		write(xfd, lbuf, ln);
X		ln = 0;
X	}
X	return(n);
X}
SHAR_EOF
fi # end of overwriting check
#	End of shell archive
exit 0

pkern@csri.toronto.edu (pkern) (06/07/88)

#! /bin/sh
# This is a shell archive, meaning:
# 1. Remove everything above the #! /bin/sh line.
# 2. Save the resulting text in a file.
# 3. Execute the file with /bin/sh (not csh) to create the files:
#	types.h
#	kermit.c
#	xmodem.c
# This archive created: Tue Jun  7 11:28:14 1988
# By:	pkern ()
export PATH; PATH=/bin:$PATH
echo shar: extracting "'types.h'" '(139 characters)'
if test -f 'types.h'
then
	echo shar: will not over-write existing file "'types.h'"
else
sed 's/^X//' << \SHAR_EOF > 'types.h'
X/*
X * types.h: useful compatibility info
X */
Xtypedef unsigned long	u_long;
Xtypedef u_long	ino_t;
Xtypedef short	dev_t;
Xtypedef long	time_t;
SHAR_EOF
fi # end of overwriting check
echo shar: extracting "'kermit.c'" '(38899 characters)'
if test -f 'kermit.c'
then
	echo shar: will not over-write existing file "'kermit.c'"
else
sed 's/^X//' << \SHAR_EOF > 'kermit.c'
X/*
X *  K e r m i t	 File Transfer Utility
X *
X *  UNIX Kermit, Columbia University, 1981, 1982, 1983
X *	Bill Catchings, Bob Cattani, Chris Maio, Frank da Cruz, Alan Crosswell
X *
X *  Also:   Jim Guyton, Rand Corporation
X *	    Walter Underwood, Ford Aerospace
X *
X *  usage:  kermit c [lbe line baud escapechar]		to connect
X *	    kermit s [d..iflb line baud] file ...	to send files
X *	    kermit r [d..iflb line baud]		to receive files
X *
X *  where   c=connect, s=send, r=receive,
X *	    d=debug, i=image mode, f=no filename conversion, l=tty line,
X *	    b=baud rate, e=escape char.
X *
X *  For remote Kermit, format is either:
X *	    kermit r					to receive files
X *  or	    kermit s file ...				to send files
X *
X */
X
X/*
X *  Modification History:
X *
X *  Oct. 17 Included fixes from Alan Crosswell (CUCCA) for IBM_UTS:
X *	    - Changed MYEOL character from \n to \r.
X *	    - Change char to int in bufill so getc would return -1 on
X *	      EOF instead of 255 (-1 truncated to 8 bits)
X *	    - Added read() in rpack to eat the EOL character
X *	    - Added fflush() call in printmsg to force the output
X *	    NOTE: The last three changes are not conditionally compiled
X *		  since they should work equally well on any system.
X *
X *	    Changed Berkeley 4.x conditional compilation flag from
X *		UNIX4X to UCB4X.
X *	    Added support for error packets and cleaned up the printing
X *		routines.
X */
X
X#include <stdio.h>	    /* Standard UNIX definitions */
X
X/* Conditional compilation for different machines/operating systems */
X/* One and only one of the following lines should be 1 */
X
X#define UCB4X	    0	    /* Berkeley 4.x UNIX */
X#define TOPS_20	    0	    /* TOPS-20 */
X#define IBM_UTS	    0	    /* Amdahl UTS on IBM systems */
X#define VAX_VMS	    0	    /* VAX/VMS (not yet implemented) */
X
X/* Conditional compilation for the different Unix variants */
X/* 0 means don't compile it, nonzero means do */
X
X#if UCB4X
X#define V6_LIBS	    0	    /* Dont't use retrofit libraries */
X#define NO_FIONREAD 0	    /* We have ioctl(FIONREAD,...) for flushinput() */
X#define NO_TANDEM   0	    /* We have TANDEM line discipline (xon/xoff) */
X#endif
X
X#if IBM_UTS
X#define V6_LIBS	    0	    /* Don't use retrofit libraries */
X#define NO_FIONREAD 1	    /* No ioctl(FIONREAD,...) for flushinput() */
X#define NO_TANDEM   1	    /* No TANDEM line discipline (xon/xoff) */
X#endif
X
X#if V6_LIBS
X#include <retrofit/sgtty.h>
X#include <retrofit/signal.h>
X#include <retrofit/setjmp.h>
X#else
X#ifdef unix
X#include <sgtty.h>
X#include <signal.h>
X#else
X#include <fcntl.h>
X#endif
X#include <setjmp.h>
X#endif
X
X#if NO_TANDEM
X#define TANDEM	    0	    /* define it to be nothing if it's unsupported */
X#endif
X
X
X/* Symbol Definitions */
X
X#define MAXPACKSIZ  94	    /* Maximum packet size */
X#define SOH	    1	    /* Start of header */
X#define CR	    13	    /* ASCII Carriage Return */
X#define SP	    32	    /* ASCII space */
X#define DEL	    127	    /* Delete (rubout) */
X#define ESCCHR	    '^'	    /* Default escape character for CONNECT */
X
X#define MAXTRY	    10	    /* Times to retry a packet */
X#define MYQUOTE	    '#'	    /* Quote character I will use */
X#define MYPAD	    0	    /* Number of padding characters I will need */
X#define MYPCHAR	    0	    /* Padding character I need (NULL) */
X
X#if IBM_UTS
X#define MYEOL	    '\r'    /* End-Of-Line character for UTS systems */
X#else
X#define MYEOL	    '\n'    /* End-Of-Line character I need */
X#endif
X
X#define MYTIME	    10	    /* Seconds after which I should be timed out */
X#define MAXTIM	    60	    /* Maximum timeout interval */
X#define MINTIM	    2	    /* Minumum timeout interval */
X
X#define TRUE	    -1	    /* Boolean constants */
X#define FALSE	    0
X
X
X/* Macro Definitions */
X
X/*
X * tochar: converts a control character to a printable one by adding a space.
X *
X * unchar: undoes tochar.
X *
X * ctl:	   converts between control characters and printable characters by
X *	   toggling the control bit (ie. ^A becomes A and A becomes ^A).
X */
X#define tochar(ch)  ((ch) + ' ')
X#define unchar(ch)  ((ch) - ' ')
X#define ctl(ch)	    ((ch) ^ 64 )
X
X
X/* Global Variables */
X
X#ifndef unix
Xstatic
X#endif
Xint	size,		    /* Size of present data */
X	rpsiz,		    /* Maximum receive packet size */
X	spsiz,		    /* Maximum send packet size */
X	pad,		    /* How much padding to send */
X	timint,		    /* Timeout for foreign host on sends */
X	n,		    /* Packet number */
X	numtry,		    /* Times this packet retried */
X	oldtry,		    /* Times previous packet retried */
X	ttyfd,		    /* File descriptor of tty for I/O, 0 if remote */
X	remote,		    /* -1 means we're a remote kermit */
X	image,		    /* -1 means 8-bit mode */
X	debug,		    /* indicates level of debugging output (0=none) */
X	filnamcnv,	    /* -1 means do file name case conversions */
X	filecount;	    /* Number of files left to send */
X
X#ifndef unix
Xstatic
X#endif
Xchar	state,		    /* Present state of the automaton */
X	padchar,	    /* Padding character to send */
X	eol,		    /* End-Of-Line character to send */
X	escchr,		    /* Connect command escape character */
X	quote,		    /* Quote character in incoming data */
X	**filelist,	    /* List of files to be sent */
X	*filnam,	    /* Current file name */
X	recpkt[MAXPACKSIZ], /* Receive packet buffer */
X	packet[MAXPACKSIZ]; /* Packet buffer */
X
X#ifndef unix
Xstatic
X#endif
XFILE	*fp,		    /* File pointer for current disk file */
X	*log;		    /* File pointer for Logfile */
X
X#ifdef unix
Xjmp_buf env;		    /* Environment ptr for timeout longjump */
X#else
X
X#define exit(a)	longjmp(xjmp,a)
Xstatic jmp_buf env, xjmp;
Xextern unsigned int cntdn;
X#endif
X
X
X/*
X *  m a i n
X *
X *  Main routine - parse command and options, set up the
X *  tty lines, and dispatch to the appropriate routine.
X */
X
X#ifdef unix
Xmain(argc,argv)
X#else
Xkermit(argc,argv)
X#endif
Xint argc;			    /* Character pointers to and count of */
Xchar **argv;				/* command line arguments */
X{
X    char *ttyname,			/* tty name for LINE argument */
X	*cp;				/* char pointer */
X    int speed,				/* speed of assigned tty, */
X	cflg, rflg, sflg;		/* flags for CONNECT, RECEIVE, SEND */
X
X#ifdef unix
X    struct sgttyb
X	rawmode,			/* Controlling tty raw mode */
X	cookedmode,			/* Controlling tty cooked mode */
X	ttymode;			/* mode of tty line in LINE option */
X#else
X    int o_n, o_fmode, boom(), xboom();
X
X    counter(1);
X    o_fmode = _fmode;
X    _fmode = O_BINARY;
X    debug = 0;
X    if (o_n = setjmp(xjmp)) {
X	counter(0);
X	if (fp != NULL) {
X	    fclose(fp);
X	    fp = NULL;
X	}
X	_fmode = o_fmode;
X	ctrlbrk(boom);
X	return(o_n);
X    }
X    else
X	ctrlbrk(xboom);
X#endif
X
X    if (argc < 2) usage();		/* Make sure there's a command line */
X
X    cp = *++argv; argv++; argc -= 2;	/* Set up pointers to args */
X
X/*  Initialize these values and hope the first packet will get across OK */
X
X    eol = CR;				/* EOL for outgoing packets */
X    quote = '#';			/* Standard control-quote char "#" */
X    pad = 0;				/* No padding */
X    padchar = NULL;			/* Use null if any padding wanted */
X
X    speed = cflg = sflg = rflg = 0;	/* Turn off all parse flags */
X    ttyname = 0;			/* Default is remote mode */
X
X#if UCB4X				/* Default to 7-bit masking, CRLF */
X    image = FALSE;			/* translation and filename case */
X    filnamcnv = TRUE;			/* conversion for UNIX systems */
X#else
X    image = TRUE;			/* Default to no processing for */
X    filnamcnv = FALSE;			/* non-UNIX systems */
X#endif
X
X    escchr = ESCCHR;			/* Default escape character */
X
X    while ((*cp) != NULL)		/* Parse characters in first arg. */
X	switch (*cp++)
X	{
X	    case 'c': cflg++; break;	/* C = Connect command */
X	    case 's': sflg++; break;	/* S = Send command */
X	    case 'r': rflg++; break;	/* R = Receive command */
X
X	    case 'd':			/* D = Increment debug mode count */
X		debug++; break;
X		
X	    case 'f':
X		filnamcnv = FALSE;	/* F = don't do case conversion */
X		break;			/*     on filenames */
X
X	    case 'i':			/* I = Image (8-bit) mode */
X#ifdef unix
X		image = TRUE; break;	/* (this is default for non-UNIX) */
X#else
X		image = FALSE; break;
X#endif
X
X#ifdef unix
X	    case 'l':			/* L = specify tty line to use */
X		if (argc--) ttyname = *argv++;
X		else usage();
X		if (debug) printf("Line to remote host is %s\n",ttyname);
X		break;
X		
X	    case 'e':			/* E = specify escape char */
X		if (argc--) escchr = **argv++;
X		else usage();
X		if (debug) printf("Escape char is \"%c\"\n",escchr);
X		break;
X		
X	    case 'b':			/* B = specify baud rate */
X#if UCB4X
X		if (argc--) speed = atoi(*argv++);
X		else usage();
X		if (debug) printf("Line speed to remote host is %d\n",speed);
X		break;
X#else
X		printmsg("Speed setting implemented for Unix only.");
X		exit(1);
X#endif
X#endif
X	}
X
X/* Done parsing */
X
X    if ((cflg+sflg+rflg) != 1)		/* Only one command allowed */
X	usage();
X
X
X#ifdef unix
X    if (ttyname)			/* If LINE was specified, we */
X    {					/* operate in local mode */
X	ttyfd = open(ttyname,2);	/* Open the tty line */
X	if (ttyfd < 0)
X	{
X	    printmsg("Cannot open %s",ttyname);
X	    exit(1);
X	}
X	remote = FALSE;			/* Indicate we're in local mode */
X    }
X    else				/* No LINE specified so we operate */
X    {					/* in remote mode (ie. controlling */
X	ttyfd = 0;			/* tty is the communications line) */
X	remote = TRUE;
X    }
X
X
X/* Put the proper tty into the correct mode */
X
X    if (remote)				/* If remote, use controlling tty */
X    {
X	gtty(0,&cookedmode);		/* Save current mode so we can */
X	gtty(0,&rawmode);		/* restore it later */
X	rawmode.sg_flags |= (RAW|TANDEM);
X	rawmode.sg_flags &= ~(ECHO|CRMOD);
X	stty(0,&rawmode);		/* Put tty in raw mode */
X    }
X    else				/* Local, use assigned line */
X    {
X	gtty(ttyfd,&ttymode);
X	ttymode.sg_flags |= (RAW|TANDEM);
X	ttymode.sg_flags &= ~(ECHO|CRMOD);
X
X#if UCB4X				/* Speed changing for UNIX only */
X	if (speed)			/* User specified a speed? */
X	{
X	    switch(speed)		/* Get internal system code */
X	    {
X		case 110: speed = B110; break;
X		case 150: speed = B150; break;
X		case 300: speed = B300; break;
X		case 1200: speed = B1200; break;
X		case 2400: speed = B2400; break;
X		case 4800: speed = B4800; break;
X		case 9600: speed = B9600; break;
X
X		default:
X		    printmsg("Bad line speed.");
X		    exit(1);
X	    }
X	    ttymode.sg_ispeed = speed;
X	    ttymode.sg_ospeed = speed;
X	}
X#endif /* UCB4X */
X
X	stty(ttyfd,&ttymode);		/* Put asg'd tty in raw mode */
X    }	
X#else
X    remote = FALSE;
X#endif
X
X
X/* All set up, now execute the command that was given. */
X
X    if (debug)
X    {
X	printf("Debugging level = %d\n\n",debug);
X
X	if (cflg) printf("Connect command\n\n");
X	if (sflg) printf("Send command\n\n");
X	if (rflg) printf("Receive command\n\n");
X    }
X
X    if (cflg) connect();		/* Connect command */
X
X    if (sflg)				/* Send command */
X    {
X	if (argc--) filnam = *argv++;	/* Get file to send */
X	else
X#ifdef unix
X	{   if (remote)
X		stty(0,&cookedmode);	/* Restore controlling tty's modes */
X	    usage();			/* and give error */
X	}
X#else
X	    usage();
X#endif
X	fp = NULL;			/* Indicate no file open yet */
X	filelist = argv;		/* Set up the rest of the file list */
X	filecount = argc;		/* Number of files left to send */
X	if (sendsw() == FALSE)		/* Send the file(s) */
X	    printmsg("Send failed.");	/* Report failure */
X	else				/*  or */
X	    printmsg("done.");		/* success */
X    }
X
X    if (rflg)				/* Receive command */
X    {
X	if (recsw() == FALSE)		/* Receive the file(s) */
X	    printmsg("Receive failed.");
X	else				/* Report failure */
X	    printmsg("done.");		/* or success */
X    }
X
X#ifdef unix
X    if (remote) stty(0,&cookedmode);	/* Restore controlling tty's modes */
X#endif
X}
X
X
X/*
X *  s e n d s w
X *
X *  Sendsw is the state table switcher for sending files.  It loops until
X *  either it finishes, or an error is encountered.  The routines called
X *  by sendsw are responsible for changing the state.
X *
X */
X
X#ifndef unix
Xstatic
X#endif
Xsendsw()
X{
X    char sinit(), sfile(), sdata(), seof(), sbreak();
X
X    state = 'S';			/* Send initiate is the start state */
X    n = 0;				/* Initialize message number */
X    numtry = 0;				/* Say no tries yet */
X    while(TRUE)				/* Do this as long as necessary */
X    {
X	if (debug) printf("sendsw state: %c\n",state);
X	switch(state)
X	{
X	    case 'S':	state = sinit();  break; /* Send-Init */
X	    case 'F':	state = sfile();  break; /* Send-File */
X	    case 'D':	state = sdata();  break; /* Send-Data */
X	    case 'Z':	state = seof();	  break; /* Send-End-of-File */
X	    case 'B':	state = sbreak(); break; /* Send-Break */
X	    case 'C':	return (TRUE);		 /* Complete */
X	    case 'A':	return (FALSE);		 /* "Abort" */
X	    default:	return (FALSE);		 /* Unknown, fail */
X	}
X    }
X}
X
X
X/*
X *  s i n i t
X *
X *  Send Initiate: send this host's parameters and get other side's back.
X */
X
X#ifndef unix
Xstatic
X#endif
Xchar sinit()
X{
X    int num, len;			/* Packet number, length */
X
X    if (numtry++ > MAXTRY) return('A'); /* If too many tries, give up */
X    spar(packet);			/* Fill up init info packet */
X
X    flushinput();			/* Flush pending input */
X
X    spack('S',n,6,packet);		/* Send an S packet */
X    switch(rpack(&len,&num,recpkt))	/* What was the reply? */
X    {
X	case 'N':  return(state);	/* NAK, try it again */
X
X	case 'Y':			/* ACK */
X	    if (n != num)		/* If wrong ACK, stay in S state */
X		return(state);		/* and try again */
X	    rpar(recpkt);		/* Get other side's init info */
X
X	    if (eol == 0) eol = '\n';	/* Check and set defaults */
X	    if (quote == 0) quote = '#';
X
X	    numtry = 0;			/* Reset try counter */
X	    n = (n+1)%64;		/* Bump packet count */
X	    return('F');		/* OK, switch state to F */
X
X	case 'E':			/* Error packet received */
X	    prerrpkt(recpkt);		/* Print it out and */
X	    return('A');		/* abort */
X
X	case FALSE: return(state);	/* Receive failure, try again */
X
X	default: return('A');		/* Anything else, just "abort" */
X   }
X }
X
X
X/*
X *  s f i l e
X *
X *  Send File Header.
X */
X
X#ifndef unix
Xstatic
X#endif
Xchar sfile()
X{
X    int num, len;			/* Packet number, length */
X    char filnam1[50],			/* Converted file name */
X	*newfilnam,			/* Pointer to file name to send */
X	*cp;				/* char pointer */
X
X    if (numtry++ > MAXTRY) return('A'); /* If too many tries, give up */
X
X    if (fp == NULL)			/* If not already open, */
X    {	if (debug) printf("   Opening %s for sending.\n",filnam);
X	fp = fopen(filnam,"r");		/* open the file to be sent */
X	if (fp == NULL)			/* If bad file pointer, give up */
X	{
X	    error("Cannot open file %s",filnam);
X	    return('A');
X	}
X    }
X
X    strcpy(filnam1, filnam);		/* Copy file name */
X    newfilnam = cp = filnam1;
X    while (*cp != '\0')			/* Strip off all leading directory */
X	if (*cp++ == '/')		/* names (ie. up to the last /). */
X	    newfilnam = cp;
X
X    if (filnamcnv)			/* Convert lower case to upper	*/
X	for (cp = newfilnam; *cp != '\0'; cp++)
X	    if (*cp >= 'a' && *cp <= 'z')
X		*cp ^= 040;
X
X    len = cp - newfilnam;		/* Compute length of new filename */
X
X    printmsg("Sending %s as %s",filnam,newfilnam);
X
X    spack('F',n,len,newfilnam);		/* Send an F packet */
X    switch(rpack(&len,&num,recpkt))	/* What was the reply? */
X    {			
X	case 'N':			/* NAK, just stay in this state, */
X	    num = (--num<0 ? 63:num);	/* unless it's NAK for next packet */
X	    if (n != num)		/* which is just like an ACK for */
X		return(state);		/* this packet so fall thru to... */
X
X	case 'Y':			/* ACK */
X	    if (n != num) return(state); /* If wrong ACK, stay in F state */
X	    numtry = 0;			/* Reset try counter */
X	    n = (n+1)%64;		/* Bump packet count */
X	    size = bufill(packet);	/* Get first data from file */
X	    return('D');		/* Switch state to D */
X
X	case 'E':			/* Error packet received */
X	    prerrpkt(recpkt);		/* Print it out and */
X	    return('A');		/* abort */
X
X	case FALSE: return(state);	/* Receive failure, stay in F state */
X
X	default:    return('A');	/* Something else, just "abort" */
X    }
X}
X
X
X/*
X *  s d a t a
X *
X *  Send File Data
X */
X
X#ifndef unix
Xstatic
X#endif
Xchar sdata()
X{
X    int num, len;			/* Packet number, length */
X
X    if (numtry++ > MAXTRY) return('A'); /* If too many tries, give up */
X
X    spack('D',n,size,packet);		/* Send a D packet */
X    switch(rpack(&len,&num,recpkt))	/* What was the reply? */
X    {		
X	case 'N':			/* NAK, just stay in this state, */
X	    num = (--num<0 ? 63:num);	/* unless it's NAK for next packet */
X	    if (n != num)		/* which is just like an ACK for */
X		return(state);		/* this packet so fall thru to... */
X		
X	case 'Y':			/* ACK */
X	    if (n != num) return(state); /* If wrong ACK, fail */
X	    numtry = 0;			/* Reset try counter */
X	    n = (n+1)%64;		/* Bump packet count */
X	    if ((size = bufill(packet)) == EOF) /* Get data from file */
X		return('Z');		/* If EOF set state to that */
X	    return('D');		/* Got data, stay in state D */
X
X	case 'E':			/* Error packet received */
X	    prerrpkt(recpkt);		/* Print it out and */
X	    return('A');		/* abort */
X
X	case FALSE: return(state);	/* Receive failure, stay in D */
X
X	default:    return('A');	/* Anything else, "abort" */
X    }
X}
X
X
X/*
X *  s e o f
X *
X *  Send End-Of-File.
X */
X
X#ifndef unix
Xstatic
X#endif
Xchar seof()
X{
X    int num, len;			/* Packet number, length */
X    if (numtry++ > MAXTRY) return('A'); /* If too many tries, "abort" */
X
X    spack('Z',n,0,packet);		/* Send a 'Z' packet */
X    switch(rpack(&len,&num,recpkt))	/* What was the reply? */
X    {
X	case 'N':			/* NAK, just stay in this state, */
X	    num = (--num<0 ? 63:num);	/* unless it's NAK for next packet, */
X	    if (n != num)		/* which is just like an ACK for */
X		return(state);		/* this packet so fall thru to... */
X
X	case 'Y':			/* ACK */
X	    if (n != num) return(state); /* If wrong ACK, hold out */
X	    numtry = 0;			/* Reset try counter */
X	    n = (n+1)%64;		/* and bump packet count */
X	    if (debug) printf("	  Closing input file %s, ",filnam);
X	    fclose(fp);			/* Close the input file */
X	    fp = NULL;			/* Set flag indicating no file open */
X
X	    if (debug) printf("looking for next file...\n");
X	    if (gnxtfl() == FALSE)	/* No more files go? */
X		return('B');		/* if not, break, EOT, all done */
X	    if (debug) printf("	  New file is %s\n",filnam);
X	    return('F');		/* More files, switch state to F */
X
X	case 'E':			/* Error packet received */
X	    prerrpkt(recpkt);		/* Print it out and */
X	    return('A');		/* abort */
X
X	case FALSE: return(state);	/* Receive failure, stay in Z */
X
X	default:    return('A');	/* Something else, "abort" */
X    }
X}
X
X
X/*
X *  s b r e a k
X *
X *  Send Break (EOT)
X */
X
X#ifndef unix
Xstatic
X#endif
Xchar sbreak()
X{
X    int num, len;			/* Packet number, length */
X    if (numtry++ > MAXTRY) return('A'); /* If too many tries "abort" */
X
X    spack('B',n,0,packet);		/* Send a B packet */
X    switch (rpack(&len,&num,recpkt))	/* What was the reply? */
X    {
X	case 'N':			/* NAK, just stay in this state, */
X	    num = (--num<0 ? 63:num);	/* unless NAK for previous packet, */
X	    if (n != num)		/* which is just like an ACK for */
X		return(state);		/* this packet so fall thru to... */
X
X	case 'Y':			/* ACK */
X	    if (n != num) return(state); /* If wrong ACK, fail */
X	    numtry = 0;			/* Reset try counter */
X	    n = (n+1)%64;		/* and bump packet count */
X	    return('C');		/* Switch state to Complete */
X
X	case 'E':			/* Error packet received */
X	    prerrpkt(recpkt);		/* Print it out and */
X	    return('A');		/* abort */
X
X	case FALSE: return(state);	/* Receive failure, stay in B */
X
X	default:    return ('A');	/* Other, "abort" */
X   }
X}
X
X
X/*
X *  r e c s w
X *
X *  This is the state table switcher for receiving files.
X */
X
X#ifndef unix
Xstatic
X#endif
Xrecsw()
X{
X    char rinit(), rfile(), rdata();	/* Use these procedures */
X
X    state = 'R';			/* Receive-Init is the start state */
X    n = 0;				/* Initialize message number */
X    numtry = 0;				/* Say no tries yet */
X
X    while(TRUE)
X    {
X	if (debug) printf(" recsw state: %c\n",state);
X	switch(state)			/* Do until done */
X	{
X	    case 'R':	state = rinit(); break; /* Receive-Init */
X	    case 'F':	state = rfile(); break; /* Receive-File */
X	    case 'D':	state = rdata(); break; /* Receive-Data */
X	    case 'C':	return(TRUE);		/* Complete state */
X	    case 'A':	return(FALSE);		/* "Abort" state */
X	}
X    }
X}
X
X
X/*
X *  r i n i t
X *
X *  Receive Initialization
X */
X
X#ifndef unix
Xstatic
X#endif
Xchar rinit()
X{
X    int len, num;			/* Packet length, number */
X
X    if (numtry++ > MAXTRY) return('A'); /* If too many tries, "abort" */
X
X    switch(rpack(&len,&num,packet))	/* Get a packet */
X    {
X	case 'S':			/* Send-Init */
X	    rpar(packet);		/* Get the other side's init data */
X	    spar(packet);		/* Fill up packet with my init info */
X	    spack('Y',n,6,packet);	/* ACK with my parameters */
X	    oldtry = numtry;		/* Save old try count */
X	    numtry = 0;			/* Start a new counter */
X	    n = (n+1)%64;		/* Bump packet number, mod 64 */
X	    return('F');		/* Enter File-Receive state */
X
X	case 'E':			/* Error packet received */
X	    prerrpkt(recpkt);		/* Print it out and */
X	    return('A');		/* abort */
X
X	case FALSE:			/* Didn't get packet */
X	    spack('N',n,0,0);		/* Return a NAK */
X	    return(state);		/* Keep trying */
X
X	default:     return('A');	/* Some other packet type, "abort" */
X    }
X}
X
X
X/*
X *  r f i l e
X *
X *  Receive File Header
X */
X
X#ifndef unix
Xstatic
X#endif
Xchar rfile()
X{
X    int num, len;			/* Packet number, length */
X    char filnam1[50];			/* Holds the converted file name */
X
X    if (numtry++ > MAXTRY) return('A'); /* "abort" if too many tries */
X
X    switch(rpack(&len,&num,packet))	/* Get a packet */
X    {
X	case 'S':			/* Send-Init, maybe our ACK lost */
X	    if (oldtry++ > MAXTRY) return('A'); /* If too many tries "abort" */
X	    if (num == ((n==0) ? 63:n-1)) /* Previous packet, mod 64? */
X	    {				/* Yes, ACK it again with  */
X		spar(packet);		/* our Send-Init parameters */
X		spack('Y',num,6,packet);
X		numtry = 0;		/* Reset try counter */
X		return(state);		/* Stay in this state */
X	    }
X	    else return('A');		/* Not previous packet, "abort" */
X
X	case 'Z':			/* End-Of-File */
X	    if (oldtry++ > MAXTRY) return('A');
X	    if (num == ((n==0) ? 63:n-1)) /* Previous packet, mod 64? */
X	    {				/* Yes, ACK it again. */
X		spack('Y',num,0,0);
X		numtry = 0;
X		return(state);		/* Stay in this state */
X	    }
X	    else return('A');		/* Not previous packet, "abort" */
X
X	case 'F':			/* File Header (just what we want) */
X	    if (num != n) return('A');	/* The packet number must be right */
X	    strcpy(filnam1, packet);	/* Copy the file name */
X
X	    if (filnamcnv)		/* Convert upper case to lower */
X		for (filnam=filnam1; *filnam != '\0'; filnam++)
X		    if (*filnam >= 'A' && *filnam <= 'Z')
X			*filnam |= 040;
X
X	    if ((fp=fopen(filnam1,"w"))==NULL) /* Try to open a new file */
X	    {
X		error("Cannot create %s",filnam1); /* Give up if can't */
X		return('A');
X	    }
X	    else			/* OK, give message */
X		printmsg("Receiving %s as %s",packet,filnam1);
X
X	    spack('Y',n,0,0);		/* Acknowledge the file header */
X	    oldtry = numtry;		/* Reset try counters */
X	    numtry = 0;			/* ... */
X	    n = (n+1)%64;		/* Bump packet number, mod 64 */
X	    return('D');		/* Switch to Data state */
X
X	case 'B':			/* Break transmission (EOT) */
X	    if (num != n) return ('A'); /* Need right packet number here */
X	    spack('Y',n,0,0);		/* Say OK */
X	    return('C');		/* Go to complete state */
X
X	case 'E':			/* Error packet received */
X	    prerrpkt(recpkt);		/* Print it out and */
X	    return('A');		/* abort */
X
X	case FALSE:			/* Didn't get packet */
X	    spack('N',n,0,0);		/* Return a NAK */
X	    return(state);		/* Keep trying */
X
X	default:    return ('A');	/* Some other packet, "abort" */
X    }
X}
X
X
X/*
X *  r d a t a
X *
X *  Receive Data
X */
X
X#ifndef unix
Xstatic
X#endif
Xchar rdata()
X{
X    int num, len;			/* Packet number, length */
X    if (numtry++ > MAXTRY) return('A'); /* "abort" if too many tries */
X
X    switch(rpack(&len,&num,packet))	/* Get packet */
X    {
X	case 'D':			/* Got Data packet */
X	    if (num != n)		/* Right packet? */
X	    {				/* No */
X		if (oldtry++ > MAXTRY)
X		    return('A');	/* If too many tries, abort */
X		if (num == ((n==0) ? 63:n-1)) /* Else check packet number */
X		{			/* Previous packet again? */
X		    spack('Y',num,6,packet); /* Yes, re-ACK it */
X		    numtry = 0;		/* Reset try counter */
X		    return(state);	/* Don't write out data! */
X		}
X		else return('A');	/* sorry, wrong number */
X	    }
X	    /* Got data with right packet number */
X	    bufemp(packet,len);		/* Write the data to the file */
X	    spack('Y',n,0,0);		/* Acknowledge the packet */
X	    oldtry = numtry;		/* Reset the try counters */
X	    numtry = 0;			/* ... */
X	    n = (n+1)%64;		/* Bump packet number, mod 64 */
X	    return('D');		/* Remain in data state */
X
X	case 'F':			/* Got a File Header */
X	    if (oldtry++ > MAXTRY)
X		return('A');		/* If too many tries, "abort" */
X	    if (num == ((n==0) ? 63:n-1)) /* Else check packet number */
X	    {				/* It was the previous one */
X		spack('Y',num,0,0);	/* ACK it again */
X		numtry = 0;		/* Reset try counter */
X		return(state);		/* Stay in Data state */
X	    }
X	    else return('A');		/* Not previous packet, "abort" */
X
X	case 'Z':			/* End-Of-File */
X	    if (num != n) return('A');	/* Must have right packet number */
X	    spack('Y',n,0,0);		/* OK, ACK it. */
X	    fclose(fp);			/* Close the file */
X#ifndef unix
X	    fp = NULL;
X#endif
X	    n = (n+1)%64;		/* Bump packet number */
X	    return('F');		/* Go back to Receive File state */
X
X	case 'E':			/* Error packet received */
X	    prerrpkt(recpkt);		/* Print it out and */
X	    return('A');		/* abort */
X
X	case FALSE:			/* Didn't get packet */
X	    spack('N',n,0,0);		/* Return a NAK */
X	    return(state);		/* Keep trying */
X
X	default:     return('A');	/* Some other packet, "abort" */
X    }
X}
X
X/*
X *  c o n n e c t
X *
X *  Establish a virtual terminal connection with the remote host, over an
X *  assigned tty line.
X */
X
X#ifndef unix
Xstatic
X#endif
Xconnect()
X{
X#ifdef unix
X    int pid,				/* Holds process id of child */
X	connected;			/* Boolean connect flag */
X    char bel = '\07',
X	c;
X
X    struct sgttyb
X	rawmode,			/* Controlling tty raw mode */
X	cookedmode;			/* Controlling tty cooked mode */
X
X    if (remote)				/* Nothing to connect to in remote */
X    {					/* mode, so just return */
X	printmsg("No line specified for connection.");
X	return;
X    }
X
X    gtty(0,&cookedmode);		/* Save current mode so we can */
X    gtty(0,&rawmode);			/* restore it later */
X    rawmode.sg_flags |= (RAW|TANDEM);
X    rawmode.sg_flags &= ~(ECHO|CRMOD);
X    stty(0,&rawmode);			/* Put tty in raw mode */
X
X    pid = fork();	    /* Start fork to get typeout from remote host */
X
X    if (pid)			    /* Parent: send type-in to remote host */
X    {
X	printmsg("connected...\r");
X	connected = TRUE;		/* Put us in "connect mode" */
X	while (connected)
X	{
X	    read(0,&c,1);		/* Get a character */
X	    if ((c&0177) == escchr)	/* Check for escape character */
X	    {
X		read(0,&c,1);
X		if ((c&0177) == escchr)
X		    write(ttyfd,&c,1);
X		else
X		switch (c&0177)
X		{
X		    case 'c':
X		    case 'C':
X			connected = FALSE;
X			write(0,"\r\n",2);
X			break;
X
X		    case 'h':
X		    case 'H':
X			write(0,"\r\nYes, I'm still here...\r\n",26);
X			break;
X
X		    default:
X			write(0,&bel,1);
X			break;
X		}
X	    }
X	    else
X	    {				/* If not escape charater, */
X		write(ttyfd,&c,1);	/* write it out */
X		c = NULL;		/* Nullify it (why?) */
X	    }
X	}
X	kill(pid,9);			/* Done, kill the child */
X	wait(0);			/* and bury him */
X	stty(0,&cookedmode);		/* Restore tty mode */
X	printmsg("disconnected.");
X	return;				/* Done */
X    }
X    else		  /* Child does the reading from the remote host */
X    {
X	while(1)			/* Do this forever */
X	{
X	    read(ttyfd,&c,1);
X	    write(1,&c,1);
X	}
X    }
X#endif
X}
X
X/*
X *	KERMIT utilities.
X */
X
X#ifndef unix
Xstatic
X#endif
Xclkint()				/* Timer interrupt handler */
X{
X    longjmp(env,TRUE);			/* Tell rpack to give up */
X}
X
X
X/*
X *  s p a c k
X *
X *  Send a Packet
X */
X
X#ifndef unix
Xstatic
X#endif
Xspack(type,num,len,data)
Xchar type, *data;
Xint num, len;
X{
X    int i;				/* Character loop counter */
X    char chksum, buffer[100];		/* Checksum, packet buffer */
X    register char *bufp;		/* Buffer pointer */
X
X    if (debug>1)			/* Display outgoing packet */
X    {
X	if (data != NULL)
X	    data[len] = '\0';		/* Null-terminate data to print it */
X	printf("  spack type: %c\n",type);
X	printf("	 num:  %d\n",num);
X	printf("	 len:  %d\n",len);
X	if (data != NULL)
X	    printf("	    data: \"%s\"\n",data);
X    }
X
X    bufp = buffer;			/* Set up buffer pointer */
X    for (i=1; i<=pad; i++) 
X#ifdef unix
X	write(ttyfd,&padchar,1); /* Issue any padding */
X#else
X	xwrite(&padchar,1);
X#endif
X
X    *bufp++ = SOH;			/* Packet marker, ASCII 1 (SOH) */
X    *bufp++ = tochar(len+3);		/* Send the character count */
X    chksum  = tochar(len+3);		/* Initialize the checksum */
X    *bufp++ = tochar(num);		/* Packet number */
X    chksum += tochar(num);		/* Update checksum */
X    *bufp++ = type;			/* Packet type */
X    chksum += type;			/* Update checksum */
X
X    for (i=0; i<len; i++)		/* Loop for all data characters */
X    {
X	*bufp++ = data[i];		/* Get a character */
X	chksum += data[i];		/* Update checksum */
X    }
X    chksum = (((chksum&0300) >> 6)+chksum)&077; /* Compute final checksum */
X    *bufp++ = tochar(chksum);		/* Put it in the packet */
X    *bufp = eol;			/* Extra-packet line terminator */
X#ifdef unix
X    write(ttyfd, buffer,bufp-buffer+1); /* Send the packet */
X#else
X    xwrite( buffer,bufp-buffer+1);
X#endif
X}
X
X/*
X *  r p a c k
X *
X *  Read a Packet
X */
X
X#ifndef unix
Xstatic
X#endif
Xrpack(len,num,data)
Xint *len, *num;				/* Packet length, number */
Xchar *data;				/* Packet data */
X{
X    int i, done;			/* Data character number, loop exit */
X    char t,				/* Current input character */
X	type,				/* Packet type */
X	cchksum,			/* Our (computed) checksum */
X	rchksum;			/* Checksum received from other host */
X
X#ifdef unix
X#if UCB4X				/* TOPS-20 can't handle timeouts... */
X    if (setjmp(env)) return FALSE;	/* Timed out, fail */
X    signal(SIGALRM,clkint);		/* Setup the timeout */
X    if ((timint > MAXTIM) || (timint < MINTIM)) timint = MYTIME;
X    alarm(timint);
X#endif /* UCB4X */
X#else
X
X    if (setjmp(env)) return FALSE;
X    if ((timint > MAXTIM) || (timint < MINTIM)) timint = MYTIME;
X    cntdn = timint * 10;
X
X#define read(a,b,c)	xread(b,c)
X
X#endif
X
X    while (t != SOH)			/* Wait for packet header */
X    {
X	read(ttyfd,&t,1);
X	t &= 0177;			/* Handle parity */
X    }
X
X    done = FALSE;			/* Got SOH, init loop */
X    while (!done)			/* Loop to get a packet */
X    {
X	read(ttyfd,&t,1);		/* Get character */
X	if (!image) t &= 0177;		/* Handle parity */
X	if (t == SOH) continue;		/* Resynchronize if SOH */
X	cchksum = t;			/* Start the checksum */
X	*len = unchar(t)-3;		/* Character count */
X
X	read(ttyfd,&t,1);		/* Get character */
X	if (!image) t &= 0177;		/* Handle parity */
X	if (t == SOH) continue;		/* Resynchronize if SOH */
X	cchksum = cchksum + t;		/* Update checksum */
X	*num = unchar(t);		/* Packet number */
X
X	read(ttyfd,&t,1);		/* Get character */
X	if (!image) t &= 0177;		/* Handle parity */
X	if (t == SOH) continue;		/* Resynchronize if SOH */
X	cchksum = cchksum + t;		/* Update checksum */
X	type = t;			/* Packet type */
X
X	for (i=0; i<*len; i++)		/* The data itself, if any */
X	{				/* Loop for character count */
X	    read(ttyfd,&t,1);		/* Get character */
X	    if (!image) t &= 0177;	/* Handle parity */
X	    if (t == SOH) continue;	/* Resynch if SOH */
X	    cchksum = cchksum + t;	/* Update checksum */
X	    data[i] = t;		/* Put it in the data buffer */
X	}
X	data[*len] = 0;			/* Mark the end of the data */
X
X	read(ttyfd,&t,1);		/* Get last character (checksum) */
X	rchksum = unchar(t);		/* Convert to numeric */
X	read(ttyfd,&t,1);		/* get EOL character and toss it */
X	if (!image) t &= 0177;		/* Handle parity */
X	if (t == SOH) continue;		/* Resynchronize if SOH */
X	done = TRUE;			/* Got checksum, done */
X    }
X
X#ifdef unix
X#if UCB4X
X    alarm(0);				/* Disable the timer interrupt */
X#endif
X#else
X    cntdn = 0;
X#undef read
X#endif
X
X    if (debug>1)			/* Display incoming packet */
X    {
X	if (data != NULL)
X	    data[*len] = '\0';		/* Null-terminate data to print it */
X	printf("  rpack type: %c\n",type);
X	printf("	 num:  %d\n",*num);
X	printf("	 len:  %d\n",*len);
X	if (data != NULL)
X	    printf("	    data: \"%s\"\n",data);
X    }
X					/* Fold in bits 7,8 to compute */
X    cchksum = (((cchksum&0300) >> 6)+cchksum)&077; /* final checksum */
X
X    if (cchksum != rchksum) return(FALSE);
X
X    return(type);			/* All OK, return packet type */
X}
X
X
X/*
X *  b u f i l l
X *
X *  Get a bufferful of data from the file that's being sent.
X *  Only control-quoting is done; 8-bit & repeat count prefixes are
X *  not handled.
X */
X
X#ifndef unix
Xstatic
X#endif
Xbufill(buffer)
Xchar buffer[];				/* Buffer */
X{
X    int i,				/* Loop index */
X	t;				/* Char read from file */
X    char t7;				/* 7-bit version of above */
X
X    i = 0;				/* Init data buffer pointer */
X    while((t = getc(fp)) != EOF)	/* Get the next character */
X    {
X	t7 = t & 0177;			/* Get low order 7 bits */
X
X	if (t7 < SP || t7==DEL || t7==quote) /* Does this char require */
X	{				    /* special handling? */
X#ifdef unix
X	    if (t=='\n' && !image)
X	    {				/* Do LF->CRLF mapping if !image */
X		buffer[i++] = quote;
X		buffer[i++] = ctl('\r');
X	    }
X#endif
X	    buffer[i++] = quote;	/* Quote the character */
X	    if (t7 != quote)
X	    {
X		t = ctl(t);		/* and uncontrolify */
X		t7 = ctl(t7);
X	    }
X	}
X	if (image)
X	    buffer[i++] = t;		/* Deposit the character itself */
X	else
X	    buffer[i++] = t7;
X
X	if (i >= spsiz-8) return(i);	/* Check length */
X    }
X    if (i==0) return(EOF);		/* Wind up here only on EOF */
X    return(i);				/* Handle partial buffer */
X}
X
X
X/*
X *	b u f e m p
X *
X *  Put data from an incoming packet into a file.
X */
X
X#ifndef unix
Xstatic
X#endif
Xbufemp(buffer,len)
Xchar  buffer[];				/* Buffer */
Xint   len;				/* Length */
X{
X    int i;				/* Counter */
X    char t;				/* Character holder */
X
X    for (i=0; i<len; i++)		/* Loop thru the data field */
X    {
X	t = buffer[i];			/* Get character */
X	if (t == MYQUOTE)		/* Control quote? */
X	{				/* Yes */
X	    t = buffer[++i];		/* Get the quoted character */
X	    if ((t & 0177) != MYQUOTE)	/* Low order bits match quote char? */
X		t = ctl(t);		/* No, uncontrollify it */
X	}
X#ifdef unix
X	if (t==CR && !image)		/* Don't pass CR if in image mode */
X	    continue;
X#endif
X
X	putc(t,fp);
X    }
X}
X
X
X/*
X *  g n x t f l
X *
X *  Get next file in a file group
X */
X
X#ifndef unix
Xstatic
X#endif
Xgnxtfl()
X{
X    if (debug) printf("	  gnxtfl: filelist = \"%s\"\n",*filelist);
X    filnam = *(filelist++);
X    if (filecount-- == 0) return FALSE; /* If no more, fail */
X    else return TRUE;			/* else succeed */
X}
X
X
X/*
X *  s p a r
X *
X *  Fill the data array with my send-init parameters
X *
X */
X
X#ifndef unix
Xstatic
X#endif
Xspar(data)
Xchar data[];
X{
X    data[0] = tochar(MAXPACKSIZ);	   /* Biggest packet I can receive */
X    data[1] = tochar(MYTIME);		/* When I want to be timed out */
X    data[2] = tochar(MYPAD);		/* How much padding I need */
X    data[3] = ctl(MYPCHAR);		/* Padding character I want */
X    data[4] = tochar(MYEOL);		/* End-Of-Line character I want */
X    data[5] = MYQUOTE;			/* Control-Quote character I send */
X}
X
X
X/*  r p a r
X *
X *  Get the other host's send-init parameters
X *
X */
X
X#ifndef unix
Xstatic
X#endif
Xrpar(data)
Xchar data[];
X{
X    spsiz = unchar(data[0]);		/* Maximum send packet size */
X    timint = unchar(data[1]);		/* When I should time out */
X    pad = unchar(data[2]);		/* Number of pads to send */
X    padchar = ctl(data[3]);		/* Padding character to send */
X    eol = unchar(data[4]);		/* EOL character I must send */
X    quote = data[5];			/* Incoming data quote character */
X}
X
X
X/*
X *  f l u s h i n p u t
X *
X *  Dump all pending input to clear stacked up NACK's.
X *  (Implemented only for Berkeley Unix at this time).
X */
X
X#if UCB4X&(~NO_FIONREAD)
Xflushinput()
X{
X    long int count;			/* Number of bytes ready to read */
X    long int i;				/* Number of bytes to read in loop */
X
X    ioctl(ttyfd, FIONREAD, &count);	/* See how many bytes pending read */
X    if (!count) return;			/* If zero, then no input to flush */
X
X    while (count)			/* Loop till all are flushed */
X    {
X	i = (count<sizeof(recpkt)) ?	/* Read min of count and size of */
X	    count : sizeof(recpkt);	/*  the read buffer */
X	read(ttyfd, recpkt, i);		/* Read a bunch */
X	count -= i;			/* Subtract from amount to read */
X    }
X}
X#else
X#ifndef unix
Xstatic
X#endif
Xflushinput()		/* Null version for non-Berkeley Unix */
X{}
X#endif /* UCB4X&(~FIONREAD) */
X
X
X/*
X *  Kermit printing routines:
X *
X *  usage - print command line options showing proper syntax
X *  printmsg -	like printf with "Kermit: " prepended
X *  error - like printmsg if local kermit; sends a error packet if remote
X *  prerrpkt - print contents of error packet received from remote host
X */
X
X/*
X *  u s a g e
X *
X *  Print summary of usage info and quit
X */
X
X#ifndef unix
Xstatic
X#endif
Xusage()
X{
X#ifdef unix
X#if UCB4X
X    printf("Usage: kermit c[lbe line baud esc.char]	 (connect mode)\n");
X    printf("or:	   kermit s[diflb line baud] file ...	 (send mode)\n");
X    printf("or:	   kermit r[diflb line baud]		 (receive mode)\n");
X#else
X    printf("Usage: kermit c[le line esc.char]		 (connect mode)\n");
X    printf("or:	   kermit s[difl line] file ...		 (send mode)\n");
X    printf("or:	   kermit r[difl line]			 (receive mode)\n");
X#endif
X#else
X    cputs("\
XUsage: kermit s[dif] file ...	 (send mode)\r\n\
Xor:    kermit r[dif]		 (receive mode)\r\n\
X(where d=debug, i=image mode, f=no filename conversion)\r\n");
X#endif
X    exit(1);
X}
X
X/*
X *  p r i n t m s g
X *
X *  Print message on standard output if not remote.
X */
X
X/*VARARGS1*/
X#ifndef unix
Xstatic
X#endif
Xprintmsg(fmt, a1, a2, a3, a4, a5)
Xchar *fmt;
X{
X    if (!remote)
X    {
X	printf("Kermit: ");
X	printf(fmt,a1,a2,a3,a4,a5);
X	printf("\n");
X	fflush(stdout);			/* force output (UTS needs it) */
X    }
X}
X
X/*
X *  e r r o r
X *
X *  Print error message.
X *
X *  If local, print error message with printmsg.
X *  If remote, send an error packet with the message.
X */
X
X/*VARARGS1*/
X#ifndef unix
Xstatic
X#endif
Xerror(fmt, a1, a2, a3, a4, a5)
Xchar *fmt;
X{
X    char msg[80];
X    int len;
X
X    if (remote)
X    {
X	sprintf(msg,fmt,a1,a2,a3,a4,a5); /* Make it a string */
X	len = strlen(msg);
X	spack('E',n,len,msg);		/* Send the error packet */
X    }
X    else
X	printmsg(fmt, a1, a2, a3, a4, a5);
X
X    return;
X}
X
X/*
X *  p r e r r p k t
X *
X *  Print contents of error packet received from remote host.
X */
X#ifndef unix
Xstatic
X#endif
Xprerrpkt(msg)
Xchar *msg;
X{
X    printf("Kermit aborting with following error from remote host:\n%s\n",msg);
X    return;
X}
X
X#ifndef unix
Xstatic
Xxread(p,n)
Xchar *p;
Xint n;
X{
X	int c;
X	extern int recv_byt();
X	extern unsigned int cntdn;
X
X	while (n--) {
X		do c = recv_byt(); while (c < 0 && cntdn);
X		if (c < 0) clkint();  /* timed out */
X		*p++ = c;
X	}
X}
X
Xstatic
Xxwrite(p,n)
Xchar *p;
Xint n;
X{
X	extern int xmit_chr();
X
X	while (n--)
X		xmit_chr(*p++);
X}
X
Xstatic
Xxboom()
X{
X	char msg[80];
X	int len;
X
X	strcpy(msg,"user break");
X	len = strlen(msg);
X	spack('E',n,len,msg);
X	exit(-1);
X}
X#endif
SHAR_EOF
fi # end of overwriting check
echo shar: extracting "'xmodem.c'" '(23279 characters)'
if test -f 'xmodem.c'
then
	echo shar: will not over-write existing file "'xmodem.c'"
else
sed 's/^X//' << \SHAR_EOF > 'xmodem.c'
X/*
X *  XMODEM Version 1.0  - by Brian Kantor, UCSD
X *
X *  XMODEM -- Implements the "CP/M User's Group XMODEM" protocol, 
X *            for packetized file up/downloading.    
X *
X *	This version is designed for 4.2BSD ONLY!  It won't work
X *	ANYWHERE else - uses the 'select' system call to replace
X *	the old alarm handlers.
X *
X *   -- Based on UMODEM 3.5 by Lauren Weinstein, Richard Conn, and others.
X *
X */
X
X#include <ctype.h>
X#include <stdio.h>
X#include <sys/types.h>
X#include <sys/stat.h>
X
X#ifdef unix
X#include <sys/time.h>
X#include <sgtty.h>
X#include <signal.h>
X#else
X#include <fcntl.h>
X#include <setjmp.h>
X#endif
X
X/* log default define */
X#ifndef LOGDEFAULT
X#define LOGDEFAULT	1
X#endif
X
X/* Delete logfile define.  Useful on small systems with limited
X * filesystem space and careless users.
X */
X#ifndef DELDEFAULT
X#define DELDEFAULT	1
X#endif
X
X#define	     VERSION	10	/* Version Number */
X#define      FALSE      0
X#define      TRUE       1
X
X
X/*  ASCII Constants  */
X#define      SOH  	001 
X#define	     STX	002
X#define	     ETX	003
X#define      EOT	004
X#define	     ENQ	005
X#define      ACK  	006
X#define	     LF		012   /* Unix LF/NL */
X#define	     CR		015  
X#define      NAK  	025
X#define	     SYN	026
X#define	     CAN	030
X#define	     ESC	033
X#define	     CTRLZ	032   /* CP/M EOF for text (usually!) */
X
X/*  XMODEM Constants  */
X#define      TIMEOUT  	-1
X#define      ERRORMAX  	10    /* maximum errors tolerated */
X#define      RETRYMAX  	10    /* maximum retries to be made */
X#define	     BBUFSIZ	128   /* buffer size -- do not change! */
X
X/*  Mode for Created Files  */
X#define      CREATMODE	0644  /* mode for created files */
X
X#ifdef unix
Xstruct sgttyb  ttys, ttysnew, ttystemp;    /* for stty terminal mode calls */
X
Xstruct stat statbuf;  	/* for terminal message on/off control */
Xchar *strcat();
XFILE *LOGFP, *fopen();
Xchar buff[BBUFSIZ];
Xint nbchr;  /* number of chars read so far for buffered read */
X
Xint wason;
X
Xint pagelen;
Xchar *ttyname();  /* forward declaration for C */
Xchar *tty;
Xchar XMITTYPE;
Xint CRCMODE, RECVFLAG, SENDFLAG, PMSG, DELFLAG, LOGFLAG, MUNGMODE;
Xint FILTER, DEBUG;
Xint STATDISP;
Xchar filename[256];
X#else
Xstatic struct stat statbuf;  	
Xstatic FILE *LOGFP;
Xstatic char buff[BBUFSIZ];
Xstatic int nbchr;  
X
Xstatic int wason;
X
Xstatic int pagelen;
Xstatic char *tty;
Xstatic char XMITTYPE;
Xstatic int CRCMODE, RECVFLAG, SENDFLAG, PMSG, DELFLAG, LOGFLAG;
Xstatic int FILTER, DEBUG, MUNGMODE;
Xstatic int STATDISP;
Xstatic char filename[256];
X
X#define exit(a)	longjmp(xjmp, a)
Xstatic jmp_buf xjmp;
X
X#endif
X
X#ifdef unix
Xmain(argc, argv)
X#else
Xxmodem(argc, argv)
X#endif
Xint argc;
Xchar **argv;
X{
X	char *getenv();
X	char *fname = filename;
X	char *logfile;
X	int index;
X	char flag;
X#ifndef unix
X	int boom(), xboom();
X
X	counter(1);	/* setup timeout counter */
X	if (index = setjmp(xjmp)) {
X		counter(0);	/* decommission timeout counter */
X		ctrlbrk(boom);
X		return(index);
X	}
X	else
X		ctrlbrk(xboom);
X#endif
X
X	logfile = "xmodem.log";  /* Name of LOG File */
X
X	printf("\nXMODEM Version %d.%d", VERSION/10, VERSION%10);
X	printf(" -- UNIX-CP/M Remote File Transfer Facility\n");
X
X	if (argc < 3)
X		{
X		help(FALSE);
X		exit(-1);
X		}
X
X	index = 0;  /* set index for loop */
X	PMSG = FALSE;  /* turn off flags */
X	DEBUG = FALSE;
X	RECVFLAG = FALSE;  /* not receive */
X	SENDFLAG = FALSE;  /* not send either */
X	FILTER = FALSE;		/* assume literal mode */
X	CRCMODE = FALSE;	/* use checksums for now */
X	XMITTYPE = 't';  /* assume text */
X
X	DELFLAG = DELDEFAULT;
X	LOGFLAG = LOGDEFAULT;
X	if (LOGFLAG) 
X		LOGFLAG = TRUE;
X	   else
X		LOGFLAG = FALSE;  
X
X	MUNGMODE = FALSE; /* protect files from overwriting */
X
X	while ((flag = argv[1][index++]) != '\0')
X	    switch (flag) {
X		case '-' : break;
X		case 'x' : DEBUG = TRUE;
X			   break;
X/* no crc mode yet
X		case 'c' : CRCMODE = TRUE;
X			   xmdebug("CRC mode selected");
X			   break;
X*/
X		case 'd' : DELFLAG = !DELDEFAULT;  /* delete log file ? */
X			   xmdebug("delete log toggled");
X			   break;
X		case 'l' : LOGFLAG = !LOGDEFAULT;  /* turn off log ? */
X			   xmdebug("write log toggled");
X			   break;
X		case 'm' : MUNGMODE = TRUE; /* allow overwriting of files */
X			   xmdebug("munge mode selected");
X			   break;
X		case 'r' : RECVFLAG = TRUE;  /* receive file */
X			   XMITTYPE = gettype(argv[1][index++]);  /* get t/b */
X			   xmdebug("receive mode selected");
X			   break;
X		case 's' : SENDFLAG = TRUE;  /* send file */
X			   XMITTYPE = gettype(argv[1][index++]);
X			   xmdebug("send mode selected");
X			   break;
X		case 'f' : FILTER = TRUE;
X			   xmdebug("filter selected");
X			   break;
X		default  : error("Invalid Flag", FALSE);
X		}
X
X	if (LOGFLAG)
X	   { 
X#ifdef unix
X	     if ((fname = getenv("HOME")) == 0)	/* Get HOME variable */
X		error("Can't get Environment!", FALSE);
X	     fname = strcat(fname, "/");
X	     fname = strcat(fname, logfile);
X#else
X	     fname = logfile;
X#endif
X	     if (!DELFLAG)
X		LOGFP = fopen(fname, "a");  /* append to LOG file */
X	     else
X		LOGFP = fopen(fname, "w");  /* new LOG file */
X	     if (!LOGFP)
X		error("Can't Open Log File", FALSE);
X	     fprintf(LOGFP,"\n\n++++++++\n");
X	     fprintf(LOGFP,"\nXMODEM Version %d.%d\n", VERSION/10, VERSION%10);
X	     printf("\nXMODEM:  LOG File '%s' is Open\n", fname);
X	   }
X
X
X	if (RECVFLAG && SENDFLAG)
X		error("Both Send and Receive Functions Specified", FALSE);
X
X	if (!RECVFLAG && !SENDFLAG)
X		error("Either Send or Receive Function must be chosen!",FALSE);
X	
X	if (FILTER && (!RECVFLAG || XMITTYPE != 't'))
X		error("Filter is only valid in text receive mode!",FALSE);
X
X	if (RECVFLAG)
X		{  
X		if(open(argv[2], 0) != -1)  /* possible abort if file exists */
X	   		{	
X			printf("\nXMODEM:  Warning -- Target File Exists\n");
X			if( MUNGMODE == FALSE )
X				error("Fatal - Can't overwrite file\n",FALSE);
X			printf("XMODEM:  Overwriting Target File\n");
X	   		}
X	   	rfile(argv[2]);  /* receive file */
X		}
X
X	if (SENDFLAG) 
X		sfile(argv[2]);  /* send file */
X	
X	xmdebug("done");
X	if (LOGFLAG) fclose(LOGFP);
X	exit(0);
X}
X
X/*  Print Help Message  */
X#ifndef unix
Xstatic
X#endif
Xhelp()
X	{
X	xmdebug("help:");
X#ifdef unix
X	printf("\nUsage:  \n\txmodem ");
X	printf("-[rb!rt!sb!st][options] filename\n");
X	printf("\nMajor Commands --");
X	printf("\n\trb <-- Receive Binary");
X	printf("\n\trt <-- Receive Text");
X	printf("\n\tsb <-- Send Binary");
X	printf("\n\tst <-- Send Text");
X	printf("\nOptions --");
X#if DELDEFAULT == 1
X	printf("\n\td  <-- Do not delete umodem.log file before starting");
X#else
X	printf("\n\td  <-- Delete umodem.log file before starting");
X#endif
X
X#if LOGDEFAULT == 1
X	printf("\n\tl  <-- (ell) Turn OFF LOG File Entries");
X#else
X	printf("\n\tl  <-- (ell) Turn ON LOG File Entries");
X#endif
X
X/* no crc mode yet
X	printf("\n\tc  <-- Select CRC mode on receive");
X*/
X	printf("\n\tf  <-- Filter 8-bit chars on receive - use with WordStar files");
X	printf("\n");
X#else
X	cprintf("\r\n\
XUsage:  \r\n\txmodem -[rb!rt!sb!st][options] filename\r\n\
X\r\nMajor Commands --\
X\r\n\trb <-- Receive Binary\
X\r\n\trt <-- Receive Text\
X\r\n\tsb <-- Send Binary\
X\r\n\tst <-- Send Text\
X\r\nOptions --\
X\r\n\td  <-- %s\
X\r\n\tl  <-- (ell) %s%s\
X\r\n\tf  <-- Filter 8-bit chars on receive - use with WordStar files\n",
X#if DELDEFAULT == 1
X	"Do not delete xmodem.log file before starting",
X#else
X	"Delete xmodem.log file before starting",
X#endif
X#if LOGDEFAULT == 1
X	"Turn OFF LOG File Entries",
X#else
X	"Turn ON LOG File Entries",
X#endif
X/* no crc mode yet
X	"\r\n\tc  <-- Select CRC mode on receive");
X*/
X	"");
X		
X#endif
X	}
X
X/* get type of transmission requested (text or binary) */
X#ifndef unix
Xstatic
X#endif
Xgettype(ichar)
Xchar ichar;
X	{
X	xmdebug("gettype:");
X	if (ichar == 't') return(ichar);
X	if (ichar == 'b') return(ichar);
X	error("Invalid Send/Receive Parameter - not t or b", FALSE);
X	return;
X	}
X
X/* set tty modes for XMODEM transfers */
X#ifndef unix
Xstatic
X#endif
Xsetmodes()
X	{
X	xmdebug("setmodes:");
X#ifdef unix
X	if (ioctl(0,TIOCGETP,&ttys)<0)  /* get tty params [V7] */
X		error("Can't get TTY Parameters", TRUE);
X
X	tty = ttyname(0);  /* identify current tty */
X	
X	/* transfer current modes to new structure */
X	ttysnew.sg_ispeed = ttys.sg_ispeed;	/* copy input speed */
X	ttysnew.sg_ospeed = ttys.sg_ospeed;	/* copy output speed */
X	ttysnew.sg_erase  = ttys.sg_erase;	/* copy erase flags */
X	ttysnew.sg_flags  = ttys.sg_flags;	/* copy flags */
X 	ttysnew.sg_kill   = ttys.sg_kill;	/* copy std terminal flags */
X
X	ttysnew.sg_flags |= RAW;    /* set for RAW Mode */
X			/* This ORs in the RAW mode value, thereby
X			   setting RAW mode and leaving the other
X			   mode settings unchanged */
X
X	ttysnew.sg_flags &= ~ECHO;  /* set for no echoing */
X			/* This ANDs in the complement of the ECHO
X			   setting (for NO echo), thereby leaving all
X			   current parameters unchanged and turning
X			   OFF ECHO only */
X
X	ttysnew.sg_flags &= ~XTABS;  /* set for no tab expansion */
X	ttysnew.sg_flags &= ~LCASE;  /* set for no upper-to-lower case xlate */
X	ttysnew.sg_flags |= ANYP;  /* set for ANY Parity */
X	ttysnew.sg_flags &= ~NL3;  /* turn off ALL 3s - new line */
X	ttysnew.sg_flags &= ~TAB2; /* turn off tab 3s */
X	ttysnew.sg_flags &= ~CR3;  /* turn off CR 3s */
X	ttysnew.sg_flags &= ~FF1;  /* turn off FF 3s */
X	ttysnew.sg_flags &= ~BS1;  /* turn off BS 3s */
X	ttysnew.sg_flags &= ~TANDEM;  /* turn off flow control */
X
X	/* set new paramters */
X	if (ioctl(0,TIOCSETP,&ttysnew) < 0)
X		error("Can't set new TTY Parameters", TRUE);
X
X	if (stat(tty, &statbuf) < 0)  /* get tty status */ 
X		error("Can't get your TTY Status", TRUE);
X
X	if (statbuf.st_mode & 022)	/* Need to turn messages off */
X		if (chmod(tty, statbuf.st_mode & ~022) < 0)
X			error("Can't change  TTY mode", TRUE);
X		else 
X			wason = TRUE;
X	else 
X		wason = FALSE;
X#endif
X	xmdebug("tty modes set");
X	}
X
X/* restore normal tty modes */
X#ifndef unix
Xstatic
X#endif
Xrestoremodes(errcall)
Xint errcall;
X	{
X	xmdebug("restoremodes:");
X#ifdef unix
X	if (wason)
X		if (chmod(tty, statbuf.st_mode | 022) < 0)
X			error("Can't change TTY mode", FALSE);
X	if (ioctl(0,TIOCSETP,&ttys) < 0)
X		{ if (!errcall)
X		   error("RESET - Can't restore normal TTY Params", FALSE);
X		else
X		   { printf("XMODEM:  ");
X		     printf("RESET - Can't restore normal TTY Params\n");
X		   }
X		}
X#endif
X	xmdebug("tty modes reset");
X	return;
X	}
X
X/* print error message and exit; if mode == TRUE, restore normal tty modes */
X#ifndef unix
Xstatic
X#endif
Xerror(msg, mode)
Xchar *msg;
Xint mode;
X	{
X	xmdebug("error:");
X	if (mode)
X		restoremodes(TRUE);  /* put back normal tty modes */
X	printf("\r\nXMODEM:  %s\n", msg);
X#ifdef unix
X	if ((LOGFLAG || DEBUG) & (int)LOGFP)
X#else
X	if (LOGFLAG || DEBUG)
X#endif
X		{   
X		fprintf(LOGFP, "XMODEM Fatal Error:  %s\n", msg);
X	    	fclose(LOGFP);
X		}
X	exit(-1);
X	}
X
X/**  print status (size) of a file  **/
X#ifndef unix
Xstatic
X#endif
Xyfile(name)
Xchar *name;
X	{
X	xmdebug("yfile:");
X	printf("\nXMODEM File Status Display for %s\n", name);
X
X#ifdef unix
X	if (open(name,0) < 0) 
X#else
X	if (open(name,O_RDONLY|O_BINARY) < 0) 
X#endif
X		{
X		printf("File %s does not exist\n", name);
X		return;
X		}
X	prfilestat(name);  /* print status */
X	printf("\n");
X	}
X
X/*
X *
X *	Get a byte from the specified file.  Buffer the read so we don't
X *	have to use a system call for each character.
X *
X */
X#ifndef unix
Xstatic
X#endif
Xgetbyte(fildes, ch)				/* Buffered disk read */
Xint fildes;
Xchar *ch;
X
X	{
X	static char buf[BUFSIZ];	/* Remember buffer */
X	static char *bufp = buf;	/* Remember where we are in buffer */
X	
X	xmdebug("getbyte:");
X	if (nbchr == 0)			/* Buffer exausted; read some more */
X		{
X		if ((nbchr = read(fildes, buf, BUFSIZ)) < 0)
X			error("File Read Error", TRUE);
X		bufp = buf;		/* Set pointer to start of array */
X		}
X	if (--nbchr >= 0)
X		{
X		*ch = *bufp++;
X		return(0);
X		}
X	else
X		return(EOF);
X	}
X
X/**  receive a file  **/
X#ifndef unix
Xstatic
X#endif
Xrfile(name)
Xchar *name;
X	{
X	register int bufctr, checksum;
X	register int c;
X	char mode;
X	int fd, j, firstchar, sectnum, sectcurr, tmode;
X	int sectcomp, errors, errorflag, recfin;
X	int errorchar, fatalerror, startstx, inchecksum, endetx, endenq;
X	long recvsectcnt;
X
X	xmdebug("rfile:");
X	mode = XMITTYPE;  /* set t/b mode */
X
X#ifdef unix
X	if ((fd = creat(name, CREATMODE)) < 0)
X#else
X	if ((fd = open(name, O_WRONLY|O_BINARY|O_CREAT, CREATMODE)) < 0)
X#endif
X	  	error("Can't create file for receive", FALSE);
X
X	printf("XMODEM:  Ready to RECEIVE File %s\n", name);
X	puts("Control-X to cancel.\n");
X
X	if (LOGFLAG)
X		{    
X		fprintf(LOGFP, "\n----\nXMODEM Receive Function\n");
X	     	fprintf(LOGFP, "File Name: %s\n", name);
X		}
X
X	setmodes();  /* setup tty modes for xfer */
X
X	recfin = FALSE;
X	sectnum = errors = 0;
X	fatalerror = FALSE;  /* NO fatal errors */
X	recvsectcnt = 0;  /* number of received sectors */
X
X	if (mode == 't')
X		tmode = TRUE;
X	else
X		tmode = FALSE;
X
X	if (CRCMODE)
X		{
X		xmdebug("crc mode request sent");
X		sendbyte('C');	/* CRC request for first block */
X		}
X	else
X		{
X		xmdebug("NAK sent");
X		sendbyte(NAK);  /* Start up the sender's first block */
X		}
X
X        do
X        	{   
X		errorflag = FALSE;
X            	do 
X			{
X                  	firstchar = readbyte(6);
X            		} 
X			while ((firstchar != SOH) 
X				&& (firstchar != EOT) 
X				&& (firstchar != TIMEOUT) 
X				&& ((firstchar & 0x7f) != CAN));
X
X            	if (firstchar == TIMEOUT)
X	    		{  
X			xmdebug("first char was timeout");
X			if (LOGFLAG)
X				fprintf(LOGFP, "Timeout on Sector %d\n", sectnum);
X               		errorflag = TRUE;
X	    		}
X
X            	if ((firstchar & 0x7f) == CAN)
X	    		{  
X			xmdebug("CAN received");
X			if (LOGFLAG)
X				fprintf(LOGFP, "Reception canceled at user's request.\n");
X			error("Reception canceled at user's request",TRUE);
X	    		}
X
X            	if (firstchar == SOH)
X	   		{
X			xmdebug("SOH received");
X               		sectcurr = readbyte(3);
X               		sectcomp = readbyte(3);
X               		if ((sectcurr + sectcomp) == 0xff)
X               			{  
X				if (sectcurr == ((sectnum+1) & 0xff))
X		 			{  
X					checksum = 0;
X		     			for (j = bufctr = 0; j < BBUFSIZ; j++)
X	      	     				{  
X						buff[bufctr] = c = readbyte(3);
X		        			checksum = ((checksum+c) & 0xff);
X						if (!tmode)  /* binary mode */
X							{  
X							bufctr++;
X		           				continue;
X		        				}
X						if (FILTER)	/* bit 8 */
X							buff[bufctr] &= 0x7f;
X						if (c == CR)
X			   				continue;  /* skip CR's */
X						if (c == CTRLZ)  /* CP/M EOF char */
X							{  
X							recfin = TRUE;  /* flag EOF */
X		           				continue;
X		        				}
X		        			if (!recfin)
X			   				bufctr++;
X		     				}
X		     			inchecksum = readbyte(3);  /* get checksum */
X		    			if (checksum == inchecksum)  /* good checksum */
X		     				{  
X						xmdebug("checksum ok");
X						errors = 0;
X						recvsectcnt++;
X		        			sectnum = sectcurr; 
X						if (write(fd, buff, bufctr) < 0)
X			   				error("File Write Error", TRUE);
X		        			else
X			   				sendbyte(ACK);
X		     				}
X		     			else
X		     				{  
X						xmdebug("checksum bad");
X						if (LOGFLAG)
X							fprintf(LOGFP, "Checksum Error on Sector %d\n",
X								sectnum);
X		        			errorflag = TRUE;
X		     				}
X                  			}
X                  		else
X                  			{ 
X					if (sectcurr == sectnum)
X                    				{  
X						xmdebug("dup sector flushed");
X						while(readbyte(3) != TIMEOUT)
X							;
X            	       				sendbyte(ACK);
X                    				}
X                    			else
X		    				{  
X						xmdebug("sector out of seq");
X						if (LOGFLAG)
X							{ 
X							fprintf(LOGFP, "Phase Error - Received Sector is ");
X			  				fprintf(LOGFP, "%d while Expected Sector is %d\n",
X			   					sectcurr, ((sectnum+1) & 0xff));
X							}
X						errorflag = TRUE;
X						fatalerror = TRUE;
X						sendbyte(CAN);
X		    				}
X	          			}
X           			}
X			else
X	   			{  
X				if (DEBUG)
X					fprintf(LOGFP,"DEBUG: bad sector# sectcurr=%02xH, sectcomp=%02xH\n",sectcurr,sectcomp);
X				if (LOGFLAG)
X					fprintf(LOGFP, "Header Sector Number Error on Sector %d\n",
X		   				sectnum);
X               			errorflag = TRUE;
X	   			}
X        		}
X	
X        	if (errorflag)
X        		{  
X			xmdebug("flushing bad sector");
X			errors++;
X	   		while (readbyte(3) != TIMEOUT)
X				;
X			sendbyte(NAK);
X        		}
X  		}
X  		while ((firstchar != EOT) && (errors < ERRORMAX) && !fatalerror);
X
X  	if ((firstchar == EOT) && (errors < ERRORMAX))
X  		{
X		xmdebug("EOT received");
X     		close(fd);
X		sendbyte(ACK);
X     		restoremodes(FALSE);  /* restore normal tty modes */
X#ifdef unix
X     		sleep(5);  /* give other side time to return to terminal mode */
X#endif
X     		if (LOGFLAG)
X     			{  
X			fprintf(LOGFP, "\nReceive Complete\n");
X			fprintf(LOGFP,"Number of Received CP/M Records is %ld\n", recvsectcnt);
X     			}
X     		printf("\n");
X  		}
X  	else
X  		{ 
X		sendbyte(CAN);
X		xmdebug("error limit exceeded");
X     		error("\r\nABORTED -- Too Many Errors", TRUE);
X  		}
X	}
X
X/**  send a file  **/
X#ifndef unix
Xstatic
X#endif
Xsfile(name)
Xchar *name;
X	{
X	register int bufctr, checksum, sectnum;
X	char blockbuf[134];
X	char mode;
X	int fd, attempts;
X	int nlflag, sendfin, tmode;
X	int bbufcnt;
X	int firstchar;
X	char c;
X	int sendresp;  /* response char to sent block */
X
X	xmdebug("sfile:");
X	nbchr = 0;  /* clear buffered read char count */
X	mode = XMITTYPE;  /* set t/b mode */
X		
X#ifdef unix
X	if ((fd = open(name, 0)) < 0)
X#else
X	if ((fd = open(name, O_RDONLY|O_BINARY)) < 0)
X#endif
X		{  
X		if (LOGFLAG) fprintf(LOGFP, "Can't Open File\n");
X     	   	error("Can't open file for send", FALSE);
X		}
X
X
X	printf("XMODEM:  File %s Ready to SEND\n", name);
X	prfilestat(name);  /* print file size statistics */
X	puts("\nControl-X to cancel.\n");
X
X	if (LOGFLAG)
X		{   
X		fprintf(LOGFP, "\n----\nXMODEM Send Function\n");
X	    	fprintf(LOGFP, "File Name: %s\n", name);
X		}
X
X	if (mode == 't')
X	   tmode = TRUE;
X	else
X	   tmode = FALSE;
X
X        sendfin = nlflag = FALSE;
X  	attempts = 0;
X
X	setmodes();  /* setup tty modes for xfer */	
X
X	while (((firstchar=readbyte(30)) != NAK)
X/* no crc mode yet
X	&& (firstchar != 'C') 
X*/
X	&& (firstchar != CAN))
X		{
X		if (++attempts > RETRYMAX)
X			error("Remote System Not Responding", TRUE);
X		}
X
X	if ((firstchar & 0x7f) == CAN)
X		{
X#ifndef unix
Xcanned:
X#endif
X		xmdebug("can received");
X		error("\nSend cancelled at user's request.\n",TRUE);
X		exit(-1);
X		}
X
X	sectnum = 1;  /* first sector number */
X	attempts = 0;
X
X        do 
X		{   
X		for (bufctr=0; bufctr < BBUFSIZ;)
X	    		{
X			if (nlflag)
X	        		{  
X				buff[bufctr++] = LF;  /* leftover newline */
X	           		nlflag = FALSE;
X	        		}
X			if (getbyte(fd, &c) == EOF)
X				{ 
X				sendfin = TRUE;  /* this is the last sector */
X		   		if (!bufctr)  /* if EOF on sector boundary */
X		      			break;  /* avoid sending extra sector */
X		   		if (tmode)
X		      			buff[bufctr++] = CTRLZ;  /* Control-Z for CP/M EOF */
X	           		else
X#ifdef unix
X		      			bufctr++;
X#else
X		      			buff[bufctr++] = '\0';
X#endif
X		   		continue;
X		      		}
X
X#ifdef unix
X			if (tmode && c == LF)  /* text mode & Unix newline? */
X	    			{
X				buff[bufctr++] = CR;  /* insert carriage return */
X		     		if (bufctr < BBUFSIZ)
X	                		buff[bufctr++] = LF;  /* insert LF */
X	 	      		else
X		        		nlflag = TRUE;  /* insert on next sector */
X	   			}	
X			else
X				buff[bufctr++] = c;  /* copy the char without change */
X#else
X			buff[bufctr++] = c;
X#endif
X	    		}
X
X            	attempts = 0;
X	
X	    	if (!bufctr)  /* if EOF on sector boundary */
X   	       		break;  /* avoid sending empty sector */
X
X            	do
X            		{
X			bbufcnt = 0;		/* start building block to be sent */
X			blockbuf[bbufcnt++] = SOH;	    /* start of packet char */
X			blockbuf[bbufcnt++] = sectnum;	    /* current sector # */
X			blockbuf[bbufcnt++] = -sectnum-1;   /* and its complement */
X
X                	checksum = 0;  /* init checksum */
X                	for (bufctr=0; bufctr < BBUFSIZ; bufctr++)
X               			{
X				blockbuf[bbufcnt++] = buff[bufctr];
X                 		checksum = ((checksum+buff[bufctr]) & 0xff);
X	         		}
X
X			blockbuf[bbufcnt++] = checksum;
X#ifdef unix
X			write(1, blockbuf, 132);  /* write the block */
X#else
X			if (DEBUG)
X				cprintf(" %d", sectnum);
X			xwrite(blockbuf, 132);
X#endif
X
X                	attempts++;
X			sendresp = readbyte(10);  /* get response */
X			if ((sendresp != ACK) && LOGFLAG)
X		   		{
X		   		fprintf(LOGFP, "Non-ACK (%2x) Received on Sector %d\n",sendresp,sectnum);
X		   		if (sendresp == TIMEOUT)
X					fprintf(LOGFP, "This Non-ACK was a TIMEOUT\n");
X				if (sendresp == CAN)	goto canned;
X		   		}
X            		}
X			while((sendresp != ACK) && (attempts < RETRYMAX));
X
X       		sectnum++;  /* increment to next sector number */
X    		}
X		while (!sendfin && (attempts < RETRYMAX));
X
X    	if (attempts >= RETRYMAX)
X		error("Remote System Not Responding", TRUE);
X
X    	attempts = 0;
X    	sendbyte(EOT);  /* send 1st EOT */
X	
X    	while ((readbyte(15) != ACK) && (attempts++ < RETRYMAX))
X	   	sendbyte(EOT);
X
X    	if (attempts >= RETRYMAX)
X	   	error("Remote System Not Responding on Completion", TRUE);
X
X    	close(fd);
X    	restoremodes(FALSE);  
X#ifdef unix
X    	sleep(15);  /* give other side time to return to terminal mode */
X#endif
X
X    	if (LOGFLAG)
X    		fprintf(LOGFP, "\nSend Complete\n");
X    	printf("\n");
X
X	}
X
X/*  print file size status information  */
X#ifndef unix
Xstatic
X#endif
Xprfilestat(name)
Xchar *name;
X	{
X	struct stat filestatbuf; /* file status info */
X
X	xmdebug("prfilestat:");
X	stat(name, &filestatbuf);  /* get file status bytes */
X	printf("  Estimated File Size %ldK, %ld Records, %ld Bytes",
X	  	(filestatbuf.st_size/1024)+1, (filestatbuf.st_size/128)+1,
X	  	filestatbuf.st_size);
X	if (LOGFLAG)
X	  	fprintf(LOGFP,"Estimated File Size %ldK, %ld Records, %ld Bytes\n",
X	  	(filestatbuf.st_size/1024)+1, (filestatbuf.st_size/128)+1,
X	  	filestatbuf.st_size);
X		return;
X	}
X
X/* get a byte from data stream -- timeout if "seconds" elapses */
X#ifdef unix
Xint readbyte(seconds)
X#else
Xstatic int
Xreadbyte(seconds)
X#endif
Xint seconds;
X	{
X#ifdef unix
X	char c;
X	int i, readfd;
X	struct timeval tmout;
X
X	tmout.tv_sec = seconds;
X	tmout.tv_usec = 0;
X
X	readfd = 1;
X
X	if ((i=select(1, &readfd, 0, 0, &tmout)) == 0)
X		{
X		xmdebug("readbyte timeout");
X		return(TIMEOUT);
X		}
X	if (DEBUG)
X		fprintf(LOGFP,"DEBUG: readbyte select returned %d\n",i);
X
X	read(0, &c, 1);
X#else
X	int c;
X	extern int recv_byt();
X	extern unsigned int cntdn;
X
X	cntdn = seconds * 10;	/* cntdn == 100 ms decrements */
X
X	do { c = recv_byt(); } while (c < 0 && cntdn);
X
X	cntdn = 0;
X
X	if (c < 0) return(TIMEOUT);
X#endif
X
X	if (DEBUG)
X		fprintf(LOGFP,"DEBUG: readbyte %02xh\n",c);
X
X	return(c & 0xff);  /* return the char */
X	}
X
X/* send a byte to data stream */
X#ifndef unix
Xstatic
X#endif
Xsendbyte(data)
Xchar data;
X	{
X#ifdef unix
X	if (DEBUG)
X		fprintf(LOGFP,"DEBUG: sendbyte %02xh\n",data);
X	write(1, &data, 1);  	/* write the byte */
X	ioctl(1,TIOCFLUSH,0);	/* flush so it really happens now! */
X#else
X	extern int xmit_chr();
X
X	if (DEBUG)
X		fprintf(LOGFP,"DEBUG: sendbyte %02xh\n",data);
X	xmit_chr(data);
X#endif
X	return;
X	}
X
X/* type out debugging info */
X#ifndef unix
Xstatic
X#endif
Xxmdebug(str)
Xchar *str;
X	{
X	if (DEBUG)
X		fprintf(LOGFP,"DEBUG: '%s'\n",str);
X	}
X
X#ifndef unix
Xstatic 
Xxwrite(p, n)
Xchar *p;
Xint n;
X{
X	if (DEBUG)
X		fprintf(LOGFP,"DEBUG: xwrite %d bytes\n",n);
X	while(n--)
X		xmit_chr(*p++);
X}
X
Xstatic
Xxboom()
X{
X	error("user break");
X}
X#endif
SHAR_EOF
fi # end of overwriting check
#	End of shell archive
exit 0

pkern@csri.toronto.edu (pkern) (06/07/88)

Things I forgot until after I hit RETURN ...

My switchar is set to '-' (but that shouldn't cause any problems (?)).

The TURBOC.CFG file I use is 1 line long and looks like ...
	-w- -Le:\turboc\lib -Ie:\turboc\include
This file is a necessity since our TI Pros are at MSDOS 2.11
and since without the -w- option, the code will cause pages of warnings.

Types.h should be installed in e:\turboc\include\sys, or
wherever files for "#include <sys/.....>" can be found.

Other than that, just download the files into an empty directory,
and assuming Turbo is properly installed, just type "make" and sit back.
On the system here, it takes about 15-20 minutes to compile and link.

If there are any problems (no doubt) and you think
the code is too cryptic (not hard to imagine), tell me about it
and I'll try to figure a bug fix.

Paul Kern		  | pkern@csri.toronto.edu
Dept of Computer Science  | ..!{cbosgd, uunet!attcan}!utgpu!utcsri!pkern
University of Toronto	  | ..!{ihnp4, utzoo, utai}!utcsri!pkern
(416) 978-4488