[comp.protocols.tcp-ip.ibmpc] Ethernet Printer driver using KA9Q code

asjoshi@phoenix.Princeton.EDU (Amit S. Joshi) (07/18/88)

Hi,
 
Some people had requested a small printer driver that I had written
using the KA9Q code as the interface to the ethernet. Here it is.
Unshar it and compile. I only know that it compiles using Turbo C v1.5
It also need the KA9Q TCP/IP code. ( I know that it works with my port
to Turbo C of Ver 870829.6).
 
Have fun
 

Amit Joshi	BITNET	|	Q3696@PUCC.BITNET
		USENET	| {seismo, rutgers}\!princeton\!phoenix\!asjoshi
"There's a pleasure in being mad... which none but madmen know!" - St.Dryden
 

#! /bin/sh
# This is a shell archive.  Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file".  To overwrite existing
# files, type "sh file -c".  You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g..  If this archive is complete, you
# will see the following message at the end:
#		"End of shell archive."
# Contents:  EPRINT.C EPRINT.DOC EPRINT.SH GENERIC.C GENERIC.H MAKE.LIB
#   MAKEFILE READ.ME SYSTEM.RC TICK.C TICK.H
# Wrapped by ibmpc@laphroig.UUCP on Sun Jul 17 14:15:33 1988
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f EPRINT.C -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"EPRINT.C\"
else
echo shar: Extracting \"EPRINT.C\" \(6794 characters\)
sed "s/^X//" >EPRINT.C <<'END_OF_EPRINT.C'
X/*	eprint.c -  a simple print utility  Author: Amit Joshi */
X
X/**
X
X	This is a sample demo program to show how the use of
X	the generic connections simplifies connecting to the 
X	net. You need Phil Karn's KA9Q TCP/IP package, and the 
X	4 files "generic.c", "generic.h", "tick.c" and "tick.h"
X	which have the interface functions.
X	
X	January 1988
X	Amit Joshi
X**/
X
X/** 
X	Revision History:
X	v1.1	March 1988 - added query on printfile option.
X			   - no longer have to perform netservice
X			   - ^C works properly now.
X	v2.0    July 1988  - added wildcards support.
X			   - added recursive directory printing support.
X**/
X
X#define	VERSION	"2.00"
X
X#include <stdio.h>
X#include <stdlib.h>
X#include <string.h>
X#include <dir.h>
X#include <dos.h>
X#include <errno.h>
X#include <sys\stat.h>
X#include <string.h>
X#include <net\generic.h>
X
X#define	PAGEFEED	'\f'
X
X#define	NULLCHAR	(char)NULL
X#define	YES		1
X#define	NO		0
X#define	MAXNAME		80
X
Xextern int errno;
X
Xchar printfailed[] = "Couldn't connect to printer\r\n";
Xint done = 0,closed =1,opened = 0;
Xstatic char **files;
Xstatic int nfiles = 0;
Xstruct generic *gn, *open_generic();	
Xchar next = '\0';
Xint opt[] = {0,0,0,0 };
Xint skip = 0;
Xchar *default_printer = "otto";
X
Xvoid prt_dir();
Xvoid prt_file();
Xvoid print_file();
X
Xvoid
Xpout(gn,bp,cnt)
Xstruct generic *gn;
Xstruct mbuf *bp;
Xint16 cnt;
X{
X	int c;
X	FILE *fd;
X	char *cp;
X	
X	cp = bp->data;
X
X	if ((fd = (FILE *)gn->user) == NULLFILE)  {
X		if (closed == YES) exit(1);
X		else return;
X	}
X	
X	while (cnt != 0) {
X		/* while there is buffer space get characters */
X		if ((c = getc(fd)) == EOF) {
X			/* done current file - flush page */
X			*cp++ = PAGEFEED;
X			bp->cnt++;
X			cnt--;
X			/* check for more files */
X			done = 1;
X			gn->user = (int *)NULLFILE;
X			return;			
X		} else {
X			*cp++ = c;
X			bp->cnt++;
X			cnt--;
X		}
X	}
X}
X
Xpsend() {
X	char *buf[BUFSIZ];
X	struct mbuf *bp, *qdata();
X	FILE *fd;
X	int cnt;
X	
X	if ((fd = (FILE *)gn->user) == NULLFILE)  {
X		if (closed == YES) exit(1);
X		else return;
X	}
X	
X	if ((cnt = sizeof(char)*fread(buf,sizeof(char),BUFSIZ,fd)) != 0) {
X		bp = qdata(buf,(int16)cnt);
X		send_tcp((struct tcb *)gn->tcb,bp);
X	}
X	
X}
X
X/* State change upcall routine */
Xvoid
Xpstate(gn,new)
Xstruct generic *gn;
Xchar new;
X{
X	/* Only interested if connection has been closed */
X	switch (new) {
X#ifdef	DEBUG
X		case LISTEN: printf("\nlistening\n");break;
X		case SYN_SENT: printf("\nsyn sent\n"); break;
X		case SYN_RECEIVED: printf("\nsyn received\n"); break;
X#endif	DEBUG
X		case ESTABLISHED: 
X			printf("connected\n"); 
X			opened = YES;
X			break;
X		case CLOSED:
X			closed = 1;
X#ifdef  DEBUG		
X			printf("Debug: closed\n");
X#endif  DEBUG	
X			break;
X		default: 
X#ifdef  DEBUG
X			printf("pstate, default : new = %d\n",new);
X#endif  DEBUG		
X			break;
X	}
X}
X
Xpopen(char *prtname) {
X	/* open a connection to the printer */
X	gn = open_generic(NULLPORT,PRINTER_PORT,prtname,NULLVFP,pout,pstate);
X	if (gn == NULLGN) {
X		printf("Couldn't connect to printer %s\n", prtname);
X		exit(1);
X	}
X	printf("Opening connection to printer %s ...",prtname);
X	fflush(stdout);
X	opened = NO;
X	closed = NO;
X	while(opened == NO && closed == NO) ;
X	if (closed == YES) exit(1);
X
X}
X
Xpclose() {
X	
X	if (closed == YES) return;
X	
X	close_generic(gn);
X	
X	printf("Done: Waiting to close connection to printer\n");
X	fflush(stdout);
X	
X	while(closed == NO) ;
X	
X}
X
Xvoid
Xprint_file(char *f){
X	
X	char dr[MAXDRIVE],dir[MAXDIR],fn[MAXFILE],fe[MAXEXT],dum[MAXPATH+5];
X	int done;
X	struct ffblk ffblk;
X	
X	fnsplit(f,dr,dir,fn,fe);
X	
X#define	FERR	"ERROR: Path or file name = %s not found\n"
X
X	done = findfirst(f,&ffblk,FA_DIREC);
X	if (done && (errno == ENOENT) && (!opt[1])) {
X		printf(FERR,f);
X	}
X		
X	while (!done) {
X		fnsplit(ffblk.ff_name,dum,dum,fn,fe);
X		fnmerge(dum,dr,dir,fn,fe);
X		if (ffblk.ff_attrib & FA_DIREC) {
X			prt_dir(dum,ffblk.ff_name);
X		} else {
X			prt_file(dum);
X		}
X		done = findnext(&ffblk);
X	}
X}
X
Xvoid
Xprt_file(char *fn)
X{	
X	char c;
X	FILE *file;
X	
X	/* Make sure we have the printer */
X	if (closed == YES) popen(default_printer);
X	
X	if (fn == NULL) {
X		file = stdin;
X	} else 	{
X		/* Do we want to print this file */
X		if (opt[1]) {
X			printf("print %s (y/n) ?",fn); fflush(stdout);
X			while (((c=getch()) != 'y') && (c != 'n'));
X			printf("%c\n",c); fflush(stdout);
X		} else c = 'y';
X		if (c != 'y') return; /* Don't print this file */
X		if ((file = fopen(fn,"r")) == NULL) {
X			if (!opt[3]) {
X				printf("Couldn't open %s\n",fn);
X         			exit(1);
X		        }
X		}
X	}
X
X	gn->user = (int *)file;	
X	if (fn != NULL) printf("Printing file: %s ...",fn);
X	fflush(stdout);
X	psend();
X	while (!done) ;
X	done = 0;
X	if (fn != NULL) {
X		printf(" \n");
X		fclose(file);
X	}
X}
X
Xvoid
Xprt_dir(char *f, char *fn){
X
X	int c;
X	char *temp;
X	void print_file();
X
X	if (!strcmp(fn,".")) return;
X	if (!strcmp(fn,"..")) return;
X	
X	if (!opt[2]) {
X		if (!opt[3]) {
X			printf("%s is a directory, print anyway (y/n) ?",f);
X			while (((c=getch()) != 'y') && (c != 'n'));
X			printf("%c\n",c);
X		} else c = 'y';
X	} else c = 'y';
X	if (c == 'y') {
X		c = strlen(f);
X		strcat(f,"\\*.*");
X		print_file(f);
X		f[c] = NULLCHAR;
X	}
X	
X}
X
Xparseopt(char *f) {
X	
X	if ((*f == '-') && (!skip)) {
X		if (*(++f) == NULLCHAR) {
X			skip = 1;
X		} else while (*f != NULLCHAR) {
X			switch(*f) {
X				case '?': usage('?');
X				case 'p':
X					if (*++f == NULLCHAR) {
X						next = 'p';
X					}  else {
X						if (closed == NO) pclose();
X						popen(f);
X					}
X					return;
X				case 'i':opt[0] = 1;opt[1] = 1;break; 
X				case 'r':opt[0] = 2;opt[2] = 1;break;
X				case 'f':opt[0] = 3;opt[3] = 1;break;
X				case '-':opt[opt[0]] = 0;opt[0] = 0;break;
X				default: if (!opt[1]) usage(*f);
X			}
X			f++;
X		}
X	} else {
X		if (next) {
X			switch(next) {
X				case 'p': 
X					if (closed == NO) pclose();
X					popen(f);
X				default:
X			}
X			next = 0;
X		} else {
X			nfiles++;
X			print_file(f);
X		}
X	}
X}
X
Xusage(char c) {
X	if (c != '?') printf("Unknown option : \"%c\n\"",c);
X	printf("Usage:eprint [-?] [-p<printer>] [-i[-]] [-] <files>\n");
X	printf("\t-?\tPrint this message\n");
X	printf("\t-i[-]\tQuery every file\n");
X	printf("\t-r[-]\tRecursively print contents of directories\n");
X/*	printf("\t-f[-]\tPrint quietly\n");*/
X	printf("\t-\tUse next argument as a file name\n");
X	printf("\t-p <printername>\t Printer to use\n");
X	printf("\t\t\t\t Default  printer is %s\n",default_printer);
X	printf("\t<files>\t files to print. No files => use stdin\n");
X	printf("\nv%s (c) Princeton LCA\n",VERSION);
X	exit(0);
X}
X
Xmain (int argc, char *argv[]) {
X	
X	char *f,*prtopt;
X	int i;
X	
X	(void)remove_cbrk(NULLVFP);   /* NEVER use ^C with the net BAD */
X	prtopt = getenv("PRTOPT");
X	for (f = strtok(prtopt," ");f != NULL; f = strtok(NULL," ")) {
X		parseopt(f);
X	}
X	
X	for (i = 1; i < argc; i++) {
X		f = argv[i];
X		parseopt(f);
X	} 
X	if (!nfiles) {
X		parseopt("-i-");	/* turn off interactive mode */
X		prt_file(NULL);
X	}
X	pclose();
X}
X 
END_OF_EPRINT.C
echo shar: Missing newline added to \"EPRINT.C\"
if test 6794 -ne `wc -c <EPRINT.C`; then
    echo shar: \"EPRINT.C\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f EPRINT.DOC -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"EPRINT.DOC\"
else
echo shar: Extracting \"EPRINT.DOC\" \(4833 characters\)
sed "s/^X//" >EPRINT.DOC <<'END_OF_EPRINT.DOC'
XNAME
X	eprint - print files over the ethernet.
X
XVERSION
X	2.0 July 1988
X
XSYNOPSIS
X	eprint [-?] [-ri[-]] [-pprintername] <files>
X
XDESCIRPTION
X	Eprint prints named files or directories. Unless the '-r' option is
X	specified it asks before printing directories. Options can be stacked
X        and can turned off and on for selective portions of the command line
X        using the turn on/off feature
X
X	Eprint depends links in all the TCP/IP routines from the KA9Q package
X	that it needs and is standalone. It however requires a file called
X	"system.rc" to be located in the root directory in order to resolve
X	host names and certain other TCP/IP setup information. The contents
X	of the "system.rc" file are similar to the "autoexec.net" file
X	in the KA9Q TCP/IP package.
X	
X	An evironment variable lookup is available. Set the environment
X	variable "PRTOPT" from DOS to your favourite settings.The DOS command:
X		set PRTOPT=arguments
X	will set the environment string to the arguments, which are exactly
X	like those by the command itself (including filenames). First the
X	environment options are evaluated, filenames given there are printed
X	and then the usual command string is parsed. A typical use would be 
X	to put the following command in the autoexec.bat file
X
X		set PRTOPT=-i
X
X	A generic option line would look like:
X
X		eprint options files option- files option2- files option files
X
X	The options apply to files following the options and can be turned
X	off by using '-' after the option (see examples).
X       
X
X	-?	Give a short usage note. 
X
X	-r[-]	Print directories recursively. If a directory is encountered 
X		it is printed and all its contents (including subdirectories)
X		are printed. '-r' turns the option on and '-r-' turns the 
X		option off.
X
X	-i[-]	Print interactively. Queries before printing every file.
X		'-i' turns the option on and '-i-' turns the option off.
X	
X	-[-]	Use the next argument as a filename. This is to allow use
X		of file names which begin with a '-'. '-' turns the option
X		on and '--' turns the option off (can't think of any use of
X		'--' since it is a noop!).
X
X	<files>	Names of files to be printed. Wild cards are allowed. For 
X		names begining with '-' see option '-'. Directories are
X		not deleted unless '-r' option is specified. NOTE: If no
X		file name is specified the standard input is used. However
X		since it does not about EOF's from the keyboard (^D or ^Z)
X		this is useful only for pipes and redirected output.
X
XEXAMPLES
X	All examples assume that PRTOPT is not set to anything.
X
X		eprint a *.opt
X	will print the file "a" and all files "*.opt". Directories will not
X        be printed.
X
X		eprint -r dirname
X	will print "dirname" even if it is a directory.
X
X		eprint -r dirs1 -r- dirs2 
X	will print "dirs1" even if it is a directory but will not print 
X	"dirs2" if it is a directory. The option '-r-' is read as follows
X		'-' + 'r-'  => option symbol + don't print directories
X
X		eprint - -r
X	will print a file "-r". Note here because of the '-' option "-r"
X	is used as a filename rather than as an option.
X
XNOTES
X	The option on/off feature is not available in Unix(tm).
X	The environment option is not available in Unix(tm).
X	This version fixes a bug in v1.00 :
X		When a nonexistent single file was asked to be deleted
X		the program correctly found there was no file but then
X		tried to delete the file as if it were read-only.
X	This version fixes a bug in v1.10 :
X		When a multiple directory deletion was attempted the
X		entire disk was wiped out. 
X
XBUGS
X	1. ^C does not work. It may abort the program but will not
X	   reset interrupt vectors and so should not be used. It is
X	   an inherent problem with the KA9Q TCP/IP package.
X	2. When the amount of data to be printed is a lot and the 
X	   printer buffer is full then sometimes the program will 
X	   hang. This is because typically when the printer is 
X	   processing data it does not reply to queries and causes
X	   it's own TCP/IP to time out while the eprint program
X	   does not know this and so it keeps tyring (since it started
X	   the whole thing). One way around is not to use the collated
X	   mode. This bug has been seen on the Imagen 2308 printer using
X	   v3.2 TCP/IP software.
X	Notify all bugs to Q3696@PUCC.BITNET or 
X	{seismo, rutgers}\!princeton\!phoenix\!asjoshi.
X
XACKNOWLEDGEMENTS
X	The program was written using Turbo C v1.5. The command is based on
X	the idea of "iprint", a very basic ethernet printer driver for
X	imagen printers available in binary with the MIT TCP/IP package.
X	This version has been written using the KA9Q TCP/IP package.
X	The program and this manual page are completly written by me.
X	Thanks go to Phil Karn for the great TCP/IP package and very
X	readable code.
X	Thanks also to Borland for the inexpensive, fast C compiler.
X	Thanks to Dennis Linse for pointing some serious shortcomings
X	in v1.1.
END_OF_EPRINT.DOC
if test 4833 -ne `wc -c <EPRINT.DOC`; then
    echo shar: \"EPRINT.DOC\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f EPRINT.SH -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"EPRINT.SH\"
else
echo shar: Extracting \"EPRINT.SH\" \(0 character\)
sed "s/^X//" >EPRINT.SH <<'END_OF_EPRINT.SH'
END_OF_EPRINT.SH
if test 0 -ne `wc -c <EPRINT.SH`; then
    echo shar: \"EPRINT.SH\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f GENERIC.C -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"GENERIC.C\"
else
echo shar: Extracting \"GENERIC.C\" \(7890 characters\)
sed "s/^X//" >GENERIC.C <<'END_OF_GENERIC.C'
X/* Main network program - provides both client and server functions */
X#ifdef	TURBOC	/* The length of the command line causes problems */
X#include "tcdefs.h"
X#endif
X#ifndef	CLEAN
X#define	NSESSIONS	10	/* Maximum interactive client sessions */
X#endif
X#ifndef	STARTUP
X#define	STARTUP	"/system.rc"	/* File to read startup commands from */
X#endif
X
X#ifdef	TURBOC
X#include <stdlib.h>
X#include <alloc.h>
X#endif
X
X#include <stdio.h>
X#include "generic.h"
X
Xextern struct interface *ifaces;
Xextern char major_rev[], minor_rev[];
Xextern struct mbuf *loopq;
X
Xint mode;
XFILE *logfp;
Xchar badhost[] = "Unknown host %s\r\n";
Xint32 gateway;
X
X#ifdef	TRACE
X#include "trace.h"
Xint32 trace;
X#endif
X
X/* Command lookup and branch table */
Xint 	doipaddr(),doexit(),dohostname(),
X	dowindow(),doroute(),
X	domss(),doattach(),
X	dottl(),go(),
X	dogateway();
X
Xstatic struct cmds cmds[] = {
X	/* The "go" command must be first */
X	"",		go,		0, NULLCHAR,	NULLCHAR,
X	"attach",	doattach,	2,
X		"attach <hardware> <hw specific options>", NULLCHAR,
X	"exit",		doexit,		0, NULLCHAR,	NULLCHAR,
X	"gateway",	dogateway,	0, NULLCHAR,	NULLCHAR,
X	"hostname",	dohostname,	0, NULLCHAR,	NULLCHAR,
X	"ipaddr",	doipaddr,	0, NULLCHAR,	NULLCHAR,
X	"mss",		domss,		0, NULLCHAR,	NULLCHAR,
X	"route",	doroute,	0, NULLCHAR,	NULLCHAR,
X	"ttl",		dottl,		0, NULLCHAR,	NULLCHAR,
X	"window",	dowindow,	0, NULLCHAR,	NULLCHAR,
X	NULLCHAR,	NULLFP,		0,
X		"Unknown command; type \"?\" for list",   NULLCHAR, 
X};
X
Xchar hostname[HOSTNAMELEN];	
Xint32 resolve();
Xint16 lportavail = 1001;
Xchar net_inited = 0;
Xchar prompt[] = "net> ";
Xchar nospace[] = "No space!!\r\n";	/* Generic malloc fail message */
Xchar notval[] = "Not a valid TCB\r\n";
Xchar finished = 0,wait_to_close = 0;
Xstruct generic *session;
X	
Xstruct generic *
Xopen_generic(lport,fport,fhost,in,out,state)
Xint16 lport,fport;	/* local and foreign ports */
Xchar *fhost;		/* foreign host name */
Xvoid (*in)();		/* called when ready to process data */
Xvoid (*out)();		/* called when ready to send data */
Xvoid (*state)();	/* called when state changes */
X{
X	void g_state(),grcv_char(),gsend_char();
X	char *inet_ntoa();
X#ifdef	TURBOC
X	void *calloc(),*malloc();
X#else
X	char *calloc(),*malloc();
X#endif
X	int32 resolve();
X	struct generic *gn;
X	struct tcb *tcb;
X	struct socket lsocket,fsocket;
X	
X	if (!net_inited) 
X		if (net_init())
X			return NULLGN;
X	
X	lsocket.address = ip_addr;
X	if (lport == NULLPORT) lsocket.port = lportavail++;
X	else lsocket.port = lport;
X	if ((fsocket.address = resolve(fhost)) == 0) {
X		printf(badhost,fhost);
X		return NULLGN;
X	}
X	
X	if (fport == NULLPORT) {
X		printf("badport %d",fport);
X		return	NULLGN;
X	} else fsocket.port = fport;
X		
X		/* Allocate a session descriptor */
X	if((gn = (struct generic *)calloc(1,sizeof(struct generic))) == NULLGN){
X		printf(nospace);
X		return NULLGN;
X	}
X	gn->in = in;
X	gn->out = out;
X	gn->state = state;
X	
X	tcb = open_tcp(&lsocket,&fsocket,TCP_ACTIVE,0,
X		grcv_char,gsend_char,g_state,0,(int *)gn);
X	gn->tcb = tcb;
X	session = gn;
X	return gn;
X}
X
Xint
Xclose_generic(gn)
Xstruct generic *gn;
X{
X	if (gn != NULLGN)
X		close_tcp(gn->tcb);
X}
X
Xint
Xsend_generic(gn,bp)
Xstruct generic *gn;
Xstruct mbuf *bp;
X{
X	if (gn != NULLGN)
X		if (gn->tcb != NULLTCB)
X			send_tcp(gn->tcb,bp);
X}
X
X/* Generic receiver upcall routine */
Xvoid
Xgrcv_char(tcb,cnt)
Xregister struct tcb *tcb;
Xint16 cnt;
X{
X	struct mbuf *bp;
X	struct generic *gn;
X	
X	if((gn = (struct generic *)tcb->user) == NULLGN){
X		/* Unknown connection; ignore it */
X		return;
X	}
X
X	if(recv_tcp(tcb,&bp,cnt) > 0)
X		if (gn->in != NULLVFP) gn->in(gn,bp,cnt);
X}
X
X/* State change upcall routine */
Xvoid
Xg_state(tcb,old,new)
Xregister struct tcb *tcb;
Xchar old,new;
X{
X	struct generic *gn;
X	char notify = 0;
X	extern char *tcpstates[];
X	extern char *reasons[];
X	extern char *unreach[];
X	extern char *exceed[];
X	void (*state)();
X
X	/* Can't add a check for unknown connection here, it would loop
X	 * on a close upcall! We're just careful later on.
X	 */
X	gn = (struct generic *)tcb->user;
X	if ((state = gn->state) != NULLVFP) notify = 1;
X	
X	switch(new){
X	case CLOSE_WAIT:
X		close_tcp(tcb);
X		break;
X	case CLOSED:	/* court adjourned */
X		if(tcb->reason == NETWORK){
X			printf("%s (%s",tcpstates[new],reasons[tcb->reason]);
X			switch(tcb->type){
X			case DEST_UNREACH:
X				printf(": %s unreachable",unreach[tcb->code]);
X				break;
X			case TIME_EXCEED:
X				printf(": %s time exceeded",exceed[tcb->code]);
X				break;
X			}	
X			printf(")\r\n");
X			fflush(stdout);
X		}
X		del_tcp(tcb);
X		if(gn != NULLGN)
X		free_generic(gn);
X	break;
X	default:
X		break;
X	}	
X	if(notify) state(gn,new);
X}
X
X/* Delete generic structure */
Xstatic
Xfree_generic(gn)
Xstruct generic *gn;
X{
X	if(gn != NULLGN) {
X		free((char *)gn);
X	}
X}
X
Xvoid
Xgsend_char(tcb,cnt)
Xstruct tcb *tcb;
Xint16 cnt;
X{
X	struct generic *gn;
X	struct mbuf *bp;
X	char *cp;
X	int c;
X	
X	if ((gn = (struct generic *)tcb->user) == NULLGN) {
X		/* Unknown connection */
X		return;
X	}
X		
X	if ((bp = alloc_mbuf(cnt)) == NULLBUF) {
X		/* just don't do a thing here */
X		return;
X	}
X	
X	if (gn->out != NULLVFP) 
X		gn->out(gn,bp,cnt);
X	
X	if(bp->cnt != 0)
X		send_tcp(tcb,bp);
X	else
X		free_p(bp);
X}
X
Xint
Xnet_init()
X{
X	static char inbuf[BUFSIZ];	/* keep it off the stack */
X	int cmdparse();
X	FILE *fp;
X	struct mbuf *bp;
X
X#ifdef	TURBOC
X#define	INITERR	"Can't initialize network: %s\n"
X	void c_break();		/* clean up on system abort */
X	void net_exit();	/* clean up on exit */
X	void net_service();	/* net background service routine */
X
X#if	(INSTALL_TIMER != 0)
X	if (install_timer(net_service)) {
X		printf(INITERR, "can't install timer");
X		return 1;
X	}
X#endif	INSTALL_TIMER
X	if (install_cbrk(c_break)) {
X		printf(INITERR,"can't install ctrl brk function");
X		return 1;
X	}
X	if (atexit(net_exit)) {
X		printf(INITERR,"too many exit functions\n");
X		return 1;
X	}
X#endif	TURBOC
X	ioinit();
X	if((fp = fopen(STARTUP,"r")) != NULLFILE){
X		while(fgets(inbuf,BUFSIZ,fp) != NULLCHAR){
X			cmdparse(cmds,inbuf);
X		}
X		fclose(fp);
X	}
X	net_inited = 1;
X	return 0;
X}
X
X/* Clean up everthing before exiting or else pay the price */
Xvoid
Xnet_exit() {
X	net_inited = 0;		/* I'm pessimistic */
X	iostop(0);
X}
X
Xvoid
Xnet_service() {
X	static int n_ticks = 0;
X	struct mbuf *bp;
X	struct interface *ifp;
X
X#if	(INSTALL_TIMER != 0)
X	/* Service net every INSTALL_TIMER ticks to avoid  */
X	/* DOS stack failiures */
X	if (n_ticks++ <= INSTALL_TIMER) return; else n_ticks = 0;
X#endif	INSTALL_TIMER
X
X	/* Service the loopback queue */
X	while((bp = dequeue(&loopq)) != NULLBUF)
X		ip_recv(bp,0);
X	
X	/* Service the interfaces */
X	for(ifp = ifaces; ifp != NULLIF; ifp = ifp->next){
X		if(ifp->recv != NULLFP)
X			(*ifp->recv)(ifp);
X	}
X	
X	grcv_char(session->tcb,0);	/* get any pending input */
X
X	/* Service the clock if it has ticked */
X	check_time();
X}
X
Xgo(){}	/* This needed by the command parser routine! */
X
X#ifdef	TURBOC
Xvoid
Xc_break(void)
X{
X	fprintf(stderr,"Aborting : wait for cleanup ...\n");
X	net_inited = 0;
X	iostop(1); /* clean up dos only */
X}
X#endif
X
X
Xstatic
Xdogateway(argc,argv)
Xint argc;
Xchar *argv[];
X{
X	char *inet_ntoa();
X	int32 n;
X
X	if(argc < 2){
X		printf("%s\r\n",inet_ntoa(gateway));
X	} else if((n = resolve(argv[1])) == 0){
X		printf(badhost,argv[1]);
X		return 1;
X	} else
X		gateway = n;
X	return 0;
X}
Xstatic
Xdoexit(argc,argv)
Xint argc;
Xchar *argv[];
X{
X	iostop();
X	exit(0);
X}
Xstatic
Xdohostname(argc,argv)
Xint argc;
Xchar *argv[];
X{
X	char *strncpy();
X
X	if(argc < 2)
X		printf("%s\r\n",hostname);
X	else 
X		strncpy(hostname,argv[1],HOSTNAMELEN);
X	return 0;
X}
X/* List of supported hardware devices */
Xint ec_attach();
X
Xstruct cmds attab[] = {
X#ifdef	PC_EC
X	/* 3-Com Ethernet interface */
X	"3c500", ec_attach, 7, 
X	"attach 3c500 <address> <vector> arpa <label> <buffers> <mtu>",
X	"Could not attach 3c500",
X#endif
X	NULLCHAR, NULLFP, 0,
X	"Unknown device",
X	NULLCHAR,
X};
X
X/* Attach an interface
X * Syntax: attach <hw type> <I/O address> <vector> <mode> <label> <bufsize> [<speed>]
X */
Xdoattach(argc,argv)
Xint argc;
Xchar *argv[];
X{
X	return subcmd(attab,argc,argv);
X}
END_OF_GENERIC.C
if test 7890 -ne `wc -c <GENERIC.C`; then
    echo shar: \"GENERIC.C\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f GENERIC.H -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"GENERIC.H\"
else
echo shar: Extracting \"GENERIC.H\" \(887 characters\)
sed "s/^X//" >GENERIC.H <<'END_OF_GENERIC.H'
X#ifndef	__GENERIC_H__
X#define	__GENERIC_H__
X
X#include "machdep.h"
X#include "mbuf.h"
X#include "netuser.h"
X#include "timer.h"
X#include "internet.h"
X#include "icmp.h"
X#include "iface.h"
X#include "ip.h"
X#include "tcp.h"
X#include "cmdparse.h"
X#include "pc.h"
X#ifdef	TURBOC
X#include "tick.h"
X#endif
X
X#define	GENERIC_PORT	1024
X#define	NULLPORT	(int16)NULL	
X#define HOSTNAMELEN 32		/* changed from 16 by Bdale 860812 */
X
Xstruct generic {
X	struct tcb *tcb;
X	void (*in)();		/* called when ready to process data */
X	void (*out)();		/* called when ready to send data */
X	void (*state)();	/* called when state changes */
X	
X	int *user;		/* pointer for use by the user */
X};
X#define	NULLGN	(struct generic *)NULL
X
X/* This is a list of the standard internet ports using TCP */
X#define	PRINTER_PORT	35
X
X/* Set netservice rate : 0 => don't use clock ticks  */
X#define	INSTALL_TIMER	2
X
X#endif	__GENERIC_H__
END_OF_GENERIC.H
echo shar: Missing newline added to \"GENERIC.H\"
if test 887 -ne `wc -c <GENERIC.H`; then
    echo shar: \"GENERIC.H\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f MAKE.LIB -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"MAKE.LIB\"
else
echo shar: Extracting \"MAKE.LIB\" \(7174 characters\)
sed "s/^X//" >MAKE.LIB <<'END_OF_MAKE.LIB'
X#	
X#	Makefile for KA9Q TCP/IP package for PC clones with Aztec C
X#
X#	Modified by Amit Joshi to suit Turboc C v1.0
X#
X#	-	Moved all switches to the "tcdefs.h" to handle the
X#		long commandline problem.
X#
X# switches:
X#	define the ones you want in the CFLAGS definition...
X#
X#	TRACE		- turn on tracing/debugging code
X#	SERVERS		- include code for application servers
X#	AMIGA		- include Amiga specific code
X#	MSDOS		- include Messy-Dos specific code
X#	ETHER		- include ethernet specific code
X#	UNIX		- Use UNIX file format conventions
X#	CPM		- Use CP/M file format conventions
X#
X# Hardware driver flags:
X#
X#	SLIP		- include serial line IP stuff
X#	PC_EC		- include 3Com Ethernet board driver for IBM-PC
X#	AX25		- include AX.25 stuff
X#	HAPN		- include HAPN stuff
X#	EAGLE		- include Eagle card driver
X#	PC100		- include PC-100 board driver (incomplete ??)
X#	AMIGA_AE100	- include Ameristar AE-100 Ethernet board driver
X#	AMIGA_ARCNET	- include Ameristar Arcnet board driver
X#
X#	DATE            - include code to datestamp FTP and SMTP actions
X
X#
X# CFLAGS for typical IBM-PC installation
X#
X# OPTFLAGS=-DSERVERS -DMSDOS -DPC_EC -DAX25 -DTRACE -DETHER -DSLIP -DHAPN -DDATE -DEAGLE -DTURBOC
X
X#
X#	CLEAN		- do not include ftp or telnet code but just make a 
X#			  generic TCP/IP utility library.
XMODEL=l
XCFLAGS=-DCLEAN -O
X#
X# CFLAGS for typical Amiga installation
X#
X# CFLAGS= -DSTARTUP="\"S:net.start\"" -DSERVERS -DAMIGA -DAMIGA_AE100 -DTRACE -DETHER  -I../../include
X#
X#	Removed alloc.obj from  NETOBJS since using Turbo C routines -ASJ
X#	Moved ec*.obj from NETOBJS to PCOBJS to avoid double declarations -ASJ
X#
XNETOBJS= ax25cmd.obj ax25.obj ax25dump.obj \
X	slip.obj kiss.obj \
X	arpcmd.obj arp.obj \
X	ipcmd.obj ip.obj iproute.obj \
X	icmpcmd.obj icmp.obj \
X	udpcmd.obj udp.obj \
X	tcpcmd.obj tcpuser.obj tcptimer.obj tcpout.obj tcpin.obj tcpsubr.obj \
X	trace.obj enetdump.obj \
X	ax25dump.obj arpdump.obj ipdump.obj \
X	icmpdump.obj udpdump.obj tcpdump.obj \
X	timer.obj ttydriv.obj cmdparse.obj mbuf.obj netuser.obj \
X	misc.obj pathname.obj generic.obj
X
XPCOBJS= pc.obj dirutil.obj eccmd.obj enet.obj \
X	ec.obj ecvec.obj pc100.obj pc100vec.obj hapn.obj hapnvec.obj \
X	asyvec.obj pcgen.obj eagle.obj eaglevec.obj tick.obj
X
XAPPOBJS= ftpserv.obj ftpcli.obj ftp.obj smtpserv.obj smtpcli.obj \
X	telnet.obj tnserv.obj smisc.obj 
X
XNLIB= $(LIB)\net
X
Xall:	net.lib pc.lib app.lib
X
Xnet.exe:  pc.lib net.lib makefile main.obj version.obj app.lib
X	$(LINK) $(STDOBJFILES) main version,net,,pc net app $(STDLIBFILES) $(LFLAGS)
X
Xinstall: $(NLIB)\net.lib $(NLIB)\pc.lib $(NLIB)\app.lib
X        @echo $(MODEL) > $(NLIB)\model
X	@copy *.lib $(NLIB)
X
Xapp.lib: $(APPOBJS)
X	$(LB) $@ -+ $? ;
X
Xnet.lib: $(NETOBJS)
X	$(LB) $@ -+ $? ;
X
Xpc.lib: $(PCOBJS)
X	$(LB) $@ -+ $? ;
X
Xlibka9q.a: $(NETOBJS) $(APPOBJS)
X	ar rv libka9q.a $(NETOBJS) $(APPOBJS)
X	ranlib libka9q.a
X
Xnet.amiga: makefile $(NETOBJS) $(APPOBJS) amiga.o
X	ld -r -d -o net.amiga $(NETOBJS) $(APPOBJS) amiga.0 ../../lib/alib.a
X
X$(NLIB)\pc.lib: pc.lib
X$(NLIB)\net.lib: net.lib
X$(NLIB)\app.lib: app.lib
X
Xclean:	
X	rm -f *.obj *.exe *.sym *.map *.bak -i *.lib
X
Xarp.obj: arp.c machdep.h mbuf.h timer.h iface.h enet.h ax25.h arp.h tcdefs.h
Xarpcmd.obj: arpcmd.c machdep.h mbuf.h timer.h enet.h ax25.h arp.h cmdparse.h tcdefs.h
Xarpdump.obj: arpdump.c machdep.h mbuf.h timer.h arp.h tcdefs.h
Xasyvec.obj: asyvec.c tcdefs.h
Xax25.obj: ax25.c machdep.h mbuf.h iface.h timer.h arp.h slip.h ax25.h tcdefs.h
Xax25cmd.obj: ax25cmd.c machdep.h mbuf.h ax25.h tcdefs.h
Xax25dump.obj: machdep.h mbuf.h ax25.h trace.h tcdefs.h
Xcmdparse.obj: cmdparse.c machdep.h trace.h cmdparse.h tcdefs.h
Xeagle.obj: eagle.c machdep.h mbuf.h iface.h eagle.h ax25.h tcdefs.h
X#	cc -E300 eagle.c
Xeaglevec.obj: eaglevec.c tcdefs.h
Xec.obj: ec.c machdep.h mbuf.h enet.h ec.h iface.h timer.h pc.h arp.h trace.h tcdefs.h
Xeccmd.obj: eccmd.c machdep.h mbuf.h ec.h tcdefs.h
Xecvec.obj: ecvec.c tcdefs.h
Xenet.obj: enet.c machdep.h mbuf.h enet.h tcdefs.h
Xenetdump.obj: enetdump.c machdep.h mbuf.h enet.h trace.h tcdefs.h
Xftp.obj: ftp.c machdep.h mbuf.h netuser.h timer.h tcp.h ftp.h session.h tcdefs.h
Xftpcli.obj: ftpcli.c machdep.h mbuf.h netuser.h icmp.h timer.h tcp.h ftp.h session.h cmdparse.h tcdefs.h
Xftpserv.obj: ftpserv.c machdep.h mbuf.h netuser.h timer.h tcp.h ftp.h tcdefs.h
Xtelnet.obj: telnet.c machdep.h mbuf.h timer.h internet.h icmp.h netuser.h tcp.h telnet.h session.h tcdefs.h
Xgeneric.obj: generic.c machdep.h mbuf.h netuser.h timer.h internet.h icmp.h iface.h ip.h tcp.h ftp.h telnet.h session.h cmdparse.h pc.h trace.h tcdefs.h generic.h
Xhapn.obj: hapn.c machdep.h mbuf.h iface.h hapn.h ax25.h trace.h tcdefs.h
Xhapnvec.obj: hapnvec.c tcdefs.h
Xicmp.obj: icmp.c machdep.h mbuf.h internet.h timer.h iface.h ip.h icmp.h tcdefs.h
Xicmpdump.obj: icmpdump.c machdep.h mbuf.h internet.h icmp.h trace.h tcdefs.h
Xip.obj: ip.c machdep.h mbuf.h timer.h internet.h iface.h ip.h icmp.h tcdefs.h
Xipcmd.obj: ipcmd.c machdep.h mbuf.h internet.h timer.h netuser.h iface.h ip.h cmdparse.h tcdefs.h
Xipdump.obj: ipdump.c machdep.h mbuf.h internet.h timer.h iface.h ip.h trace.h netuser.h tcdefs.h
Xiproute.obj: iproute.c machdep.h mbuf.h internet.h timer.h netuser.h ip.h icmp.h iface.h trace.h tcdefs.h
Xkiss.obj: kiss.c machdep.h mbuf.h iface.h kiss.h tcdefs.h
Xmain.obj: main.c machdep.h mbuf.h netuser.h timer.h icmp.h iface.h ip.h tcp.h ftp.h telnet.h session.h cmdparse.h pc.h trace.h tcdefs.h
Xmbuf.obj: mbuf.c machdep.h mbuf.h tcdefs.h
Xnetuser.obj: netuser.c machdep.h netuser.h tcdefs.h
Xpc.obj: pc.c machdep.h mbuf.h internet.h iface.h pc.h cmdparse.h tcdefs.h
Xpcgen.obj: pcgen.c tcdefs.h
Xpc100.obj: pc100.c machdep.h mbuf.h iface.h pc100.h ax25.h trace.h tcdefs.h
Xpc100vec.obj: pc100vec.c tcdefs.h
Xslip.obj: slip.c machdep.h mbuf.h iface.h ax25.h slip.h pc.h trace.h tcdefs.h
Xsmisc.obj: smisc.c machdep.h mbuf.h netuser.h timer.h tcp.h tcdefs.h
Xsmtpcli.obj: smtpcli.c machdep.h netuser.h mbuf.h timer.h tcp.h smtp.h trace.h tcdefs.h
Xsmtpserv.obj: smtpserv.c machdep.h mbuf.h netuser.h timer.h tcp.h smtp.h tcdefs.h
Xtcpcmd.obj: tcpsubr.c machdep.h timer.h mbuf.h netuser.h internet.h tcp.h tcdefs.h
Xtcpdump.obj: tcpdump.c machdep.h mbuf.h netuser.h internet.h timer.h tcp.h trace.h tcdefs.h
Xtcpin.obj: tcpin.c machdep.h timer.h mbuf.h netuser.h internet.h tcp.h icmp.h iface.h ip.h tcdefs.h
Xtcpout.obj: tcpout.c machdep.h timer.h mbuf.h netuser.h internet.h tcp.h tcdefs.h
Xtcpsubr.obj: tcpsubr.c machdep.h timer.h mbuf.h netuser.h internet.h tcp.h tcdefs.h
Xtcptimer.obj: tcptimer.c machdep.h timer.h mbuf.h netuser.h internet.h ip.h tcp.h tcdefs.h
Xtcpuser.obj: tcpuser.c machdep.h timer.h mbuf.h netuser.h internet.h tcp.h tcdefs.h
Xtelnet.obj: telnet.c machdep.h mbuf.h timer.h internet.h icmp.h netuser.h tcp.h telnet.h session.h tcdefs.h
Xtnserv.obj: tnserv.c machdep.h mbuf.h timer.h internet.h icmp.h netuser.h tcp.h telnet.h session.h tcdefs.h
Xtrace.obj: machdep.h mbuf.h trace.h tcdefs.h
Xtick.obj: tick.c tick.h 
Xtimer.obj: timer.c machdep.h timer.h tcdefs.h
Xudp.obj: udp.c machdep.h mbuf.h netuser.h udp.h internet.h tcdefs.h
Xudpcmd.obj: udpcmd.c machdep.h mbuf.h netuser.h udp.h internet.h tcdefs.h
Xudpdump.obj: udpdump.c machdep.h mbuf.h netuser.h internet.h udp.h tcdefs.h
Xversion.obj: version.c tcdefs.h
END_OF_MAKE.LIB
if test 7174 -ne `wc -c <MAKE.LIB`; then
    echo shar: \"MAKE.LIB\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f MAKEFILE -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"MAKEFILE\"
else
echo shar: Extracting \"MAKEFILE\" \(180 characters\)
sed "s/^X//" >MAKEFILE <<'END_OF_MAKEFILE'
X# use the LIBS definition to compile eprint.c
XLIBS= $(LIB)\net\pc.lib $(LIB)\net\net.lib
XCFLAGS= -G -r -Z 
X#CFLAGS=-DDEBUG -M -y
XMODEL=l
X
Xall: eprint.exe
X
Xeprint.exe: eprint.c
X###
END_OF_MAKEFILE
if test 180 -ne `wc -c <MAKEFILE`; then
    echo shar: \"MAKEFILE\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f READ.ME -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"READ.ME\"
else
echo shar: Extracting \"READ.ME\" \(2309 characters\)
sed "s/^X//" >READ.ME <<'END_OF_READ.ME'
X
XI needed an ethernet driver for some of my research work here 
XThe only compiler I had was Turbo C and so a long time ago
XI ported the KA9Q codeto Turbo C. This is an old version 
X(major ver = 870829, minor = 6). To use it in a more straight
Xforward manner I wrote a small "generic" interface. To test it
Xout I wrote a small printer driver for our imagen. As it was used
Xin the lab it got more features and became bigger. Some time ago
XI thought it might be of some use to others. So here it is:
X
XThis package has the files needed to compile the eprint program.
XIt does not have the KA9Q TCP/IP code. You will have to get it 
Xfrom some other place. It contains:
X	generic.c	- interface code to the TCP/IP package.
X	generic.h	- include file for interface code.
X	tick.c		- background timer and ^C handler.	
X	tick.h		- include file for tick.c
X	eprint.c	- the printer driver code.	
X	make.lib	- the make file for the TCP/IP package. (see note). 
X	makefile	- the makefile for the eprint program.
X	eprint.doc	- manual page for the eprint program.
X	read.me		- this file.
X	system.rc	- sample system setup file.
X
XThe generic.* files are written to simplyfy interfacing to the KA9Q TCP/IP
Xpackage.
XRather than keep in a loop to service the network a small set of functions
Xwas written to install and start a timer that ran installed functions. The 
Xsame package also installs ^C (cbrk) handlers in a fashion similar to the 
Xatexit() function for exits. These functions are available in the files 
Xtick.* . These functions are completely Turbo C dependent and are completely
Xindependent of the rest of the package.
XThere is a file 'make.lib' which is provided to give an idea of which KA9Q
XTCP/IP code goes into which libraries - my arrangement is slightly different.
X'eprint.c' is the code for the printer driver routines, and 'makefile' is the 
Xmakefile for the program.
XThis program has been tested and is running fine on IBM PC/AT's (8 and 10 Mhz)
XIBM PC/XT's . It does not work with the fast mode with an Orchid turbo board
Xfor the XT.
X
XThere are I'm sure bugs - i'll be happy to try to fix those that I can.
XThe usual caveats apply - it is supplied strictly AS IS with no warranties
Xfor any purpose.
X 
XHave fun
XAmit Joshi	INTERNET | ...{seismo, rutgers}\!princeton\!phoenix\!asjoshi
X		BITNET   | Q696@PUCC.BITNET
X 
END_OF_READ.ME
if test 2309 -ne `wc -c <READ.ME`; then
    echo shar: \"READ.ME\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f SYSTEM.RC -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"SYSTEM.RC\"
else
echo shar: Extracting \"SYSTEM.RC\" \(351 characters\)
sed "s/^X//" >SYSTEM.RC <<'END_OF_SYSTEM.RC'
X# Attach interfaces
X# Syntax: attach <hw type> <I/O address> <vector> <mode> <label>
X#                <bufsize> <mtu> [<speed>]
X#
X# attach to the ethernet board
Xattach 3c500 0x300 3 arpa ec0 5 1500
X#
X# 	Remainder of configuration
X#
Xhostname amelia.princeton.edu
Xttl 16
Xipaddr [128.112.30.6]
Xroute add default ec0
Xgateway leonardo
Xwindow 1500
Xmss 256
X
END_OF_SYSTEM.RC
if test 351 -ne `wc -c <SYSTEM.RC`; then
    echo shar: \"SYSTEM.RC\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f TICK.C -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"TICK.C\"
else
echo shar: Extracting \"TICK.C\" \(5922 characters\)
sed "s/^X//" >TICK.C <<'END_OF_TICK.C'
X/*	tick.c - installs a function which is called every clock tick */
X/*	(c) - Amit Joshi, Princeton University
X
X	This code may be used freely for any noncommercial use. It may NOT
X	be used in any commercial package without written permission from
X	the author. This clause is to protect me from legal hassles with
X	the university about code developed here. This code is supplied
X	"AS IS" i.e. with no warranty. Do not remove this notice. Any
X	modifications should be clearly noted before redistribution.
X**/
X
X/**	Amit Joshi
X	MAE Dept., Engg. Quad.
X	Princeton University
X	December 1987
X**/
X
X/**
X	The __tick__() and dosbusy() functions have been stolen from the
X	"rdir.c" code by Dean D. McCrory. The __tick__() has been
X	rewritten (and renamed from timer_handler()) to be more general.
X	Amit Joshi
X	January 1988
X**/
X
X/**     Most recent version, including stack stuff
X        June 1988
X**/
X
X#include <stdlib.h>
X#include <stdio.h>
X#include "tick.h"
X
X/*
X *
X * Fred's rad "own stack" stuff
X *
X */
X
X#define  STACKSIZE	10000
X
X	char	my_stack[STACKSIZE];
Xconst	char	*stp = my_stack + STACKSIZE - 10;
X
Xvolatile static unsigned	oldss, oldsp;
X
X#define	set_stack()	{	disable();		\
X				oldss = _SS;		\
X				oldsp = _SP;		\
X				_SS = FP_SEG(stp);	\
X				_SP = FP_OFF(stp);	\
X				enable();		\
X			}
X
X#define	reset_stack()	{	disable();		\
X				_SS = oldss;		\
X				_SP = oldsp;		\
X				enable();		\
X			}
X
X
X/* Stuff for to handle the ctrl break functions */
Xstatic int __nc_brks = 0;
Xstatic char _abort = 1;
Xstatic void (* __c_brks[NCBRKS])(void);
X
X/* Stuff to run timers */
Xstatic void interrupt (* __otimer)(void) = NULLIVFP;
Xstatic int __ntimers = 0;
Xstatic void (* __timers[NTIMERS])(void);
Xstatic char far * dosbusy_fl;    /* dos maintains this */
X
X/* The functions used in this file */
Xstatic int __cbrk(void);
Xstatic void __clean_timer(void);
Xstatic void interrupt __tick__(void);
Xstatic char far * getdosbusy(void);
X
Xstatic int __cbrk(void) {
X	int nf;
X
X	if (_abort) {
X		for (nf = 0; nf < __nc_brks; ++nf) (* __c_brks[nf] ) ();
X		return(0);
X	} else return(1);
X}
X
Xstatic void __clean_timer(void) {
X	if (__otimer == NULLIVFP) return;	 /* nothing set yet */
X	setvect(TIMER_INT,__otimer);
X}
X
X
X
X
X
X/* __tick__ ()
X *
X * This function intercepts the hardware timer interrupt.  It checks the
X * dosbusy flag and runs through a list of timer driven functions if safe
X * to do so.
X */
X
Xvolatile	int	in_fl = 0;
X
Xstatic void interrupt __tick__(void)
X{
X	int	timer;
X
X/* if the following statement is NOT coded, the 8259 blocks all hardware
X * interrupts including the keyboard interrupt.  Since we wait for a key
X * in list_directory(), this causes the PC to lock up.  This one took
X * a while to figure out
X */
X	outportb (0x20, 0x20);	/*	send eoi to 8259	*/
X
X	(*__otimer) ();		/* chain to previous timer handler */
X
X	if (! in_fl && ! *dosbusy_fl) {
X		in_fl = 1;                 /* we are in our ISR */
X/*
X *
X * run through the list of timers
X *
X */
X
X		set_stack();	/* use our own big gnarly stack	*/
X
X		for (timer = 0; timer < __ntimers; ++timer) {
X			if (__timers[timer] != NULLVFP) {
X				(*__timers[timer]) ();
X			}
X		}
X
X		reset_stack();	/* give back wimpy stack	*/
X
X		in_fl = 0;
X	}
X	return;                    /* return from ISR */
X}
X
X/* getdosbusy ()
X *
X * Gets the Dos busy flag through interrupt 34h.  This Dos function returns
X * the busy flag address in es:bx.  This is an UNDOCUMENTED feature of Dos,
X * however it has worked in Dos versions 2.11 - 3.30 for me - Dean McCrory.
X */
Xstatic char far * getdosbusy (void)
X{
X   struct SREGS sregs;        /* segment registers */
X   union REGS regs;           /* normal registers */
X
X   regs.h.ah = 0x34;          /* get dos busy flag address (UNDOCUMENTED) */
X   intdosx (&regs, &regs, &sregs);
X   return (MK_FP (sregs.es, regs.x.bx));
X}
X
Xint	install_timer(void (*func)(void))
X{
X	int i = 0;
X	void __clean_timer();
X	void interrupt __tick__();
X
X	/* check if the function is already installed */
X
X	if (!__ntimers) {
X		__otimer = getvect(TIMER_INT);
X
X		/* Get address of DOS busy flag. */
X
X		dosbusy_fl = getdosbusy();
X
X		if (atexit(__clean_timer)) return 2;
X		install_cbrk(NULLVFP);
X		setvect(TIMER_INT,__tick__);
X	}
X
X	/* are we already installed ? */
X
X	for (i=0; i < __ntimers; i++) if (__timers[i] == func) return(0);
X
X	/* enough space for another function ? */
X
X	if (__ntimers >= NTIMERS) return(1);
X	__timers[__ntimers++] = func;
X	return(0);
X}
X
Xint remove_timer(void (*func)(void))
X{
X	int i = 0;
X
X	if (func == NULLVFP) {
X		__clean_timer();
X		__ntimers = 0;
X		return(0);
X	}
X
X	if (!__ntimers) return(1);	/* No timers return func not there */
X
X	do {
X		/* have we found the function ? */
X		if (__timers[i] == func) {
X			/* is it the last one in the chain ? */
X			if (i++ == __ntimers) {
X				__timers[i-1] = NULLVFP;
X			} else {
X				/* move the chain backwards */
X				do {
X					__timers[i-1] = __timers[i]; i++;
X				} while(i <= __ntimers);
X			}
X			__ntimers--;
X			return(0);
X		} else i++;
X	} while (i < __ntimers);
X	return(1);
X}
X
Xint install_cbrk (void (* func)(void))
X{
X	int i = 0;
X
X	if (!__nc_brks) {
X		setcbrk(1);	/* ensure that ctrl break is enabled */
X		ctrlbrk(__cbrk);
X		_abort = 1;
X	}
X
X	if (func == NULLVFP) {
X		_abort = 1;
X		return(0);
X	}
X
X	for (i = 0; i < __nc_brks; i++)	if (__c_brks[i] == func) return(0);
X
X	/* enough space for another function ? */
X
X	if (__nc_brks >= NCBRKS) return(1);
X	__c_brks[__nc_brks++] = func;
X	return(0);
X}
X
Xint remove_cbrk (void (* func)(void))
X{
X	int i = 0;
X
X	if (func == NULLVFP) {
X		_abort = 0;
X		return(0);
X	}
X
X	if (!__nc_brks) return(1);	/* No timers return func not there */
X
X	do {
X		/* have we found the function ? */
X		if (__c_brks[i] == func) {
X			/* is it the last one in the chain ? */
X			if (i++ == __nc_brks) {
X				__c_brks[i-1] = NULLVFP;
X			} else {
X				/* move the chain backwards */
X				do {
X					__c_brks[i-1] = __c_brks[i]; i++;
X				} while(i <= __nc_brks);
X			}
X			__nc_brks--;
X			return(0);
X		} else i++;
X	} while (i < __nc_brks);
X	return(1);
X}
END_OF_TICK.C
echo shar: Missing newline added to \"TICK.C\"
if test 5922 -ne `wc -c <TICK.C`; then
    echo shar: \"TICK.C\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f TICK.H -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"TICK.H\"
else
echo shar: Extracting \"TICK.H\" \(1464 characters\)
sed "s/^X//" >TICK.H <<'END_OF_TICK.H'
X/*	tick.h - the include file for timer and c_brk function installation */
X/*	(c) - Amit Joshi, Princeton University 
X
X	This code may be used freely for any noncommercial use. It may NOT
X	be used in any commercial package without written permission from
X	the author. This clause is to protect me from legal hassles with
X	the university about code developed here. This code is supplied
X	"AS IS" i.e. with no warranty. Do not remove this notice. Any 
X	modifications should be clearly noted before redistribution.
X**/
X
X/**	Amit Joshi
X	MAE Dept., Engg. Quad.
X	Princeton University
X	December 1987
X**/
X
X/**
X	Change the values defined for NTIMERS and NCBRKS to increase 
X	number of timer and cbrk functions installed.
X
X	Amit Joshi
X	January 1988
X**/
X
X#ifndef	__TICK_H__
X#define	__TICK_H__
X
X#include <dos.h>
X
X/* Change the following definitions to increase number of timers and cbrks */
X#define	NTIMERS	3	/* number of timers installable */
X#define	NCBRKS	3	/* number of cbrks installable */
X
X#define NULLIVFP	(void interrupt (*)())NULL
X#define	NULLVFP		(void (*)())NULL
X#define NULLFP		(int (*)())NULL 
X
X/* The hardware interrupt works in all models. */
X#define	HARDTIMER	1	 
X
X#ifdef	HARDTIMER
X#define	TIMER_INT	0x08
X#else
X#define TIMER_INT	0x1C 	
X#endif
X
X/* user callable functions */
Xint	_Cdecl		install_timer(void (*func)());	
Xint	_Cdecl		install_cbrk(void (*func)());
Xint	_Cdecl		remove_timer(void (*func)());
Xint	_Cdecl		remove_cbrk(void (*func)());
X
X#endif	__TICK_H__
END_OF_TICK.H
if test 1464 -ne `wc -c <TICK.H`; then
    echo shar: \"TICK.H\" unpacked with wrong size!
fi
# end of overwriting check
fi
echo shar: End of shell archive.
exit 0
-- 
Amit Joshi	BITNET	|	Q3696@PUCC.BITNET
		USENET	| {seismo, rutgers}\!princeton\!phoenix\!asjoshi
"There's a pleasure in being mad... which none but madmen know!" - St.Dryden