[net.sources.bugs] UNIX

frank@sagan.UUCP (Frank Whaley) (10/02/85)

The following shar archive contains rb.c and sb.c -- a pair I found on some
bulletin board.  No comments other than they seem to work for me from an
IBMPC running Qmodem v1.09.
Watch for signature.

----------cut here----------cut here----------cut here----------
#!/bin/sh
#
#	This is a shell archive.  Remove anything before the "!/bin/sh"
#	 line above and run the rest of this file through the "sh" command
#	 (as "sh yourfile"), or use the "unshar" program.
#
echo x - rb.c
sed 's/^X//' >rb.c <<'*-*-END-of-rb.c-*-*'
X#define VERSION "rb 0.05 7-19-82"
X
X/*
X * rb.c By Chuck Forsberg
X *
X * A program for Unix which can receive
X *  files from computers running YAM or MODEM.
X *  If no filename is given, YAM batch mode is assumed.
X *
X *  Supports the CRC option or regular checksum.
X *  Received pathnames containing no lowercase letters will be changed to lower
X *  case unless -u option is given.
X *
X *  Unless the -b (binary) option is given, \r is discarded and
X *  ^Z (which is also discarded) acts as end of file.
X *
X *  Any slashes in the pathname are changed to underscore.
X *  If the raw pathname ends in .MSG, .TXT or .DOC, any existing file will
X *  be appended to rather than replaced. Trailing periods are eliminated.
X *
X *  If the raw pathname ends in
X *   .COM .CMD .DAT .O .REL .PAG .CRL .OBJ .SAV
X *   or .?Q* (squeezed file), or if the parity bit of the first or second bytes
X *   of the file is set,
X *   that file will be received in binary mode.
X *
X *
X * a log of activities is appended to "rblog"
X *
X * rb is derived from yam2.c and sb.c
X * rb should use Unix System III buffered input to reduce CPU time.
X *  USG UNIX (3.0) ioctl conventions courtesy  Jeff Martin
X * 	cc -O -DV7  rb.c -o rb		vanilla Unix version 7
X *	cc -O -DUSG rb.c -o rb		USG (3.0) Unix
X *  Unix is a trademark of Western Electric Company
X */
X
X#include <stdio.h>
X#include <signal.h>
X#include <ctype.h>
X#ifdef USG
X#include <termio.h>
X#include <sys/ioctl.h>
X#else
X#include <sgtty.h>
X#endif
X
Xchar *substr();
XFILE *fout;
XFILE *logfile;
X
X#define OK 0
X#define FALSE 0
X#define TRUE 1
X#define ERROR (-1)
X
X/* Ward Christensen / CP/M parameters - Don't change these! */
X#define ENQ 005
X#define CAN ('X'&037)
X#define XOFF ('s'&037)
X#define XON ('q'&037)
X#define SOH 1
X#define STX 2
X#define EOT 4
X#define ACK 6
X#define NAK 025
X#define CPMEOF 032
X#define WANTCRC 0103	/* send C not NAK to get crc not checksum */
X#define TIMEOUT (-2)
X#define ERRORMAX 5
X#define RETRYMAX 5
X#define WCEOT (-10)
X#define SECSIZ 128	/* cp/m's Magic Number record size */
X#define KSIZE 1024	/* record size with k option */
X
Xint Lastrx;
Xint Crcflg;
Xint Firstsec;
Xint Eofseen;		/* indicates cpm eof (^Z) has been received */
Xint totblocks;		/* total number of blocks received */
Xint errors;
X
Xint Batch;
Xint MakeLCPathname=TRUE;	/* make received pathname lower case */
Xint Verbose=FALSE;
Xint Rxbinary=FALSE;	/* receive all files in bin mode */
Xint Thisbinary;		/* current file is to be received in bin mode */
Xint blklen;		/* record length of received packets */
Xchar secbuf[KSIZE];
Xchar linbuf[KSIZE];
Xint lleft=0;		/* number of characters in linbuf */
Xint llorig;
Xchar *cdq;		/* pointer for removing chars from linbuf */
X
X
X#ifdef USG
Xstruct termio oldtty, tty;
X#else
Xstruct sgttyb oldtty, tty;
X#endif
X
Xunsigned updcrc();
X
Xmain(argc, argv)
Xchar *argv[];
X{
X	register char *cp;
X	register npats=0;
X	char **patts;
X	int exitcode;
X
X	while (--argc) {
X		cp = *++argv;
X		if(*cp == '-') {
X			while( *++cp) {
X				switch(*cp) {
X				case 'b':
X					Rxbinary=TRUE; break;
X				case 'k':
X				case 'c':
X					Crcflg=TRUE; break;
X				case 'u':
X					MakeLCPathname=FALSE; break;
X				case 'v':
X					Verbose=TRUE; break;
X				default:
X					usage();
X				}
X			}
X		}
X		else if( !npats && argc>0) {
X			if(argv[0][0]) {
X				npats=argc;
X				patts=argv;
X			}
X		}
X	}
X#ifdef USG
X	(void) ioctl(0, TCGETA, &oldtty);
X	tty = oldtty;
X	tty.c_lflag &= ~(ECHO | ICANON | ISIG); /* No echo, crlf mapping, INTR
X	or QUIT chars, no crlf delays,
X	no erase/kill processing */
X	tty.c_iflag = IGNBRK;	/* Ignore break, disable parity check, no
X	stripping, no crnl mapping or ^S^Q */
X	tty.c_oflag = 0;	/* Transparent output, no delays, no crlf
X	mapping */
X	tty.c_cflag &= ~PARENB;	/* Leave baud rate alone, disable parity
X	generation and checking */
X	tty.c_cflag |= CS8;	/* Set character size = 8 */
X	tty.c_cc[VMIN] = 20;	/* Satisfy reads when this many chars in */
X	tty.c_cc[VTIME] = 1;	/* ... or in this many tenths of seconds */
X	(void) ioctl(0, TCSETA, &tty);
X#else
X	ioctl(1, TIOCEXCL, 0);
X	ioctl(1, TIOCGETP, &oldtty);
X	tty = oldtty;
X	tty.sg_flags |= RAW;
X	tty.sg_flags &= ~ECHO;
X	ioctl(1, TIOCSETP, &tty);
X#endif
X	logfile=fopen("rblog", "a");
X	if(wcreceive(npats, patts)==ERROR) {
X		exitcode=0200;
X		sendline(CAN);
X		sendline(CAN);
X		sendline(CAN);
X		sendline(CAN);
X	}
X	fclose(logfile);
X#ifdef USG
X	(void) ioctl(0, TCSBRK, 1);	/* Wait for output to drain */
X	(void) ioctl(0, TCFLSH, 1);	/* Flush input queue */
X	(void) ioctl(0, TCSETAW, &oldtty);	/* Restore original modes */
X	(void) ioctl(0, TCXONC,1);	/* Restart output */
X#else
X	ioctl(1, TIOCSETP, &oldtty);
X	ioctl(1, TIOCNXCL, 0);
X#endif
X	exit(exitcode);
X}
X
Xusage()
X{
X	fprintf(stderr,"%s by Chuck Forsberg\n", VERSION);
X	fprintf(stderr,"Usage: rb [-bcuv]\n");
X	exit(1);
X}
X
Xwcreceive(argc, argp)
Xchar **argp;
X{
X	if(Batch || argc==0) {
X		Crcflg=TRUE; fprintf(stderr, "Receiving in batch mode ");
X		for(;;) {
X			totblocks=0;
X			if(wcrxpn(secbuf)== ERROR)
X				goto fubar;
X			if(secbuf[0]==0)
X				return OK;
X			if(wcrx(secbuf)==ERROR)
X				goto fubar;
X		}
X	}
X	else
X		for(; --argc>=0;) {
X			totblocks=0;
X			if(wcrx(*argp++)==ERROR)
X				goto fubar;
X		}
X	return OK;
Xfubar:
X	sendline(CAN);sendline(CAN);sendline(CAN);
X	if(fout)
X		fclose(fout);
X	return ERROR;
X}
X
X
X/*
X * Fetch a pathname from the other end as a C ctyle ASCIZ string.
X * Length is indeterminate as long as less than blklen
X * a null string represents no more files
X */
Xwcrxpn(rpn)
Xchar *rpn;	/* receive a pathname */
X{
X	purgeline();
X	Firstsec=TRUE;
X	sendline(Crcflg?WANTCRC:NAK);
X	if(wcgetsec(rpn, 100) != 0) {
X		log( "Pathname fetch failed\n");
X		return ERROR;
X	}
X	sendline(ACK);
X	return OK;
X}
X
X/*
X * Adapted from CMODEM13.C, written by
X * Jack M. Wierda and Roderick W. Hart
X */
X
Xwcrx(name)
Xchar *name;
X{
X	register int sectnum, sectcurr;
X	register char sendchar;
X	register char *filemode, *p;
X
X	for(p=name; *p; ++p)		/* change / to _ */
X		if( *p == '/')
X			*p = '_';
X	if ( *--p == '.')		/* zap trailing period */
X		*p = 0;
X	filemode = "w";
X	Thisbinary=Rxbinary;
X	if (substr(name, ".COM") || substr(name, ".CRL")
X	  || substr(name, ".REL") || substr(name, ".PAG")
X	  || substr(name, ".CMD")
X	  || substr(name, ".SAV")
X	  || substr(name, ".O")
X	  || substr(name, ".DAT")
X	  || substr(name, ".OBJ")
X	  || ((p=substr(name, ".")) && p[2] == 'Q' )
X	  || ((p=substr(name, ".")) && p[2] == 'q' ))
X		Thisbinary = TRUE;
X	if(substr(name, ".TXT")
X	  || substr(name, ".MSG")
X	  || substr(name, ".DOC"))
X		filemode = "a";
X	if(MakeLCPathname && !IsAnyLower(name))
X		uncaps(name);
X	fprintf(logfile,  "Receiving %s %s %s\n",
X	  name, Thisbinary?"BIN":"", filemode);
X	if ((fout=fopen(name, filemode)) == NULL)
X		return ERROR;
X	Firstsec=TRUE;sectnum=0; Eofseen=FALSE;
X	sendchar=Crcflg?WANTCRC:NAK;
X
X	for(;;) {
X/*
X		purgeline();
X*/
X		sendline(sendchar);	/* send it now, we're ready! */
X		sectcurr=wcgetsec(secbuf, (sectnum&0177)?50:130);
X		if(sectcurr==(sectnum+1 &0377)) {
X
X			if(sectnum==0 && ((secbuf[0]&0200) | (secbuf[1]&0200)))
X				Thisbinary++;
X			sectnum++;
X			if(putsec(secbuf, blklen)==ERROR)
X				return ERROR;
X			sendchar=ACK;
X		}
X		else if(sectcurr==(sectnum&0377)) {
X			log( "Received dup Sector\n");
X			sendchar=ACK;
X		}
X		else if(sectcurr==WCEOT) {
X			sendline(ACK);
X			/* don't pad the file any more than it already is */
X			if(fclose(fout)==ERROR)
X				return ERROR;
X			return OK;
X		}
X		else if(sectcurr==ERROR)
X			return ERROR;
X		else {
X			log( "Sync Error\n");
X			return ERROR;
X		}
X	}
X}
X
X/*
X * wcgetsec fetches a Ward Christensen type sector.
X * Returns sector number encountered or ERROR if valid sector not received,
X * or CAN CAN received
X * or WCEOT if eot sector
X * time is timeout for first char, set to 4 seconds thereafter
X ***************** NO ACK IS SENT IF SECTOR IS RECEIVED OK **************
X *    (Caller must do that when he is good and ready to get next sector)
X */
X
Xwcgetsec(rxbuf, time)
Xchar *rxbuf;
Xint time;
X{
X	register checksum, wcj, firstch;
X	register unsigned oldcrc;
X	register char *p;
X	int sectcurr;
X
X	for(Lastrx=errors=0; errors<RETRYMAX; errors++) {
X
X		if ((firstch=readline(time))==STX) {
X			blklen=KSIZE; goto get2;
X		}
X		if (firstch==SOH) {
X			blklen=SECSIZ;
Xget2:
X			sectcurr=readline(1);
X			if((sectcurr+readline(1))==255) {
X				oldcrc=checksum=0;
X				for(p=rxbuf,wcj=blklen; --wcj>=0; ) {
X					if((firstch=readline(1)) < 0)
X						goto bilge;
X					oldcrc=updcrc(firstch, oldcrc);
X					checksum += (*p++ = firstch);
X				}
X				if((firstch=readline(1)) < 0)
X					goto bilge;
X				if(Crcflg) {
X					oldcrc=updcrc(firstch, oldcrc);
X					if((firstch=readline(1)) < 0)
X						goto bilge;
X					oldcrc=updcrc(firstch, oldcrc);
X					if(oldcrc)
X						log("CRC=0%o\n", oldcrc);
X					else {
X						Firstsec=FALSE;
X						return sectcurr;
X					}
X				}
X				else if(((checksum-firstch)&0377)==0) {
X					Firstsec=FALSE;
X					return sectcurr;
X				}
X				else
X					log( "Checksum Error\n");
X			}
X			else
X				log( "Sector number garbled\n");
X		}
X		/* make sure eot really is eot and not just mixmash */
X		else if(firstch==EOT && readline(1)==TIMEOUT)
X			return WCEOT;
X		else if(firstch==CAN) {
X			if(Lastrx==CAN) {
X				log( "Sender CANcelled\n");
X				return ERROR;
X			} else {
X				Lastrx=CAN;
X				continue;
X			}
X		}
X		else if(firstch==TIMEOUT) {
X			if (Firstsec)
X				goto humbug;
Xbilge:
X			log( "Timeout\n");
X		}
X		else
X			log( "Got 0%o sector header\n", firstch);
X
Xhumbug:
X		Lastrx=0;
X		while(readline(1)!=TIMEOUT)
X			;
X		if(Firstsec)
X			sendline(Crcflg?WANTCRC:NAK);
X		else {
X			time=40; sendline(NAK);
X		}
X	}
X	/* try to stop the bubble machine. */
X	sendline(CAN); sendline(CAN); sendline(CAN);
X	return ERROR;
X}
X
X/*
X * This version of readline is not so well suited for
X * reading many characters.
X *
X * timeout is in tenths of seconds
X */
Xreadline(timeout)
Xint timeout;
X{
X	if(--lleft>=0)
X		return (*cdq++ & 0377);
X	settimeout(timeout);
X	if((llorig=lleft=read(1, cdq=linbuf, KSIZE))<1)
X		return TIMEOUT;
X	alarm(0);
X	--lleft;
X	return (*cdq++ & 0377);
X}
X
X
Xalrm()
X{
X/* does nothing; actual effect is to give an error return on read */
X}
X
X/*
X * timeout is in tenths of seconds
X */
Xsettimeout(timeout)
X{
X	register int c;
X
X	signal(SIGALRM, alrm);
X	if((c = timeout/10)<2)
X		c=2;
X	alarm(c);
X}
Xpurgeline()
X{
X	lleft=0;
X	lseek(1, 0L, 2);
X}
X
X/* update CRC */
Xunsigned updcrc(c, crc)
Xregister c;
Xregister unsigned crc;
X{
X	register count;
X
X	for(count=8; --count>=0;) {
X		if(crc & 0x8000) {
X			crc <<= 1;
X			crc += (((c<<=1) & 0400)  !=  0);
X			crc ^= 0x1021;
X		}
X		else {
X			crc <<= 1;
X			crc += (((c<<=1) & 0400)  !=  0);
X		}
X	}
X	return crc;	
X}
X
X/* make string s lower case */
Xuncaps(s)
Xregister char *s;
X{
X	for( ; *s; ++s)
X		if(isupper(*s))
X			*s = tolower(*s);
X}
X
X
X/*
X * IsAnyLower returns TRUE if string s has lower case letters.
X */
XIsAnyLower(s)
Xregister char *s;
X{
X	for( ; *s; ++s)
X		if (islower(*s))
X			return TRUE;
X	return FALSE;
X}
X/*
X * putsec writes the n characters of buf to receive file fout.
X *  If not in binary mode, carriage returns, and all characters
X *  starting with CPMEOF are discarded.
X */
Xputsec(buf, n)
Xchar *buf;
Xregister n;
X{
X	register char *p;
X
X	++totblocks;
X	if(Thisbinary)
X	{
X		for (p=buf; --n>=0; )
X			putc( *p++, fout);
X	}
X	else {
X		if(Eofseen)
X			return OK;
X		for (p=buf; --n>=0; ++p ) {
X			if( *p == '\r')
X				continue;
X			if (*p == CPMEOF) {
X				Eofseen=TRUE; return OK;
X			}
X			putc(*p ,fout);
X		}
X	}
X	return OK;
X}
Xsendline(c)
X{
X	putchar(c);
X	fflush(stdout);
X}
X
X
X/*
X * substr(string, token) searches for token in string s
X * returns pointer to token within string if found, NULL otherwise
X */
Xchar *substr(s, t)
Xregister char *s,*t;
X{
X	register char *ss,*tt;
X	/* search for first char of token */
X	for(ss=s; *s; s++)
X		if(*s == *t)
X			/* compare token with substring */
X			for(ss=s,tt=t; ;) {
X				if(*tt == 0)
X					return s;
X				if(*ss++ != *tt++)
X					break;
X			}
X	return NULL;
X}
Xlog(s,p)
Xchar *s, *p;
X{
X	fprintf(logfile, "error %d: ", errors);
X	fprintf(logfile, s,p);
X}
*-*-END-of-rb.c-*-*
echo x - sb.c
sed 's/^X//' >sb.c <<'*-*-END-of-sb.c-*-*'
X#define VERSION "sb 1.01 12-21-81"
X
X/*
X * sb.c By Chuck Forsberg
X *
X * A small program for Unix which can send 1 or more
X * files in Batch mode to computers running YAM. (Use "rb" in yam.)
X * Supports the CRC option or regular checksum.
X * There are no messages of any sort (except incorrect usage).
X * sb is derived from yam2.c
X * Uses buffered i/o to reduce the CPU time compared to UMODEM.
X *  USG UNIX (3.0) ioctl conventions courtesy  Jeff Martin
X * 	cc -O -DV7  sb.c -o sb		vanilla Unix version 7
X *	cc -O -DUSG sb.c -o sb		USG (3.0) Unix
X *  Unix is a trademark of Western Electric Company
X */
X
X#include <stdio.h>
X#include <signal.h>
X#ifdef USG
X#include <termio.h>
X#include <sys/ioctl.h>
X#else
X#include <sgtty.h>
X#endif
X
XFILE *in;
X
X#define OK 0
X#define FALSE 0
X#define TRUE 1
X#define ERROR (-1)
X
X/* Ward Christensen / CP/M parameters - Don't change these! */
X#define ENQ 005
X#define CAN ('X'&037)
X#define XOFF ('s'&037)
X#define XON ('q'&037)
X#define SOH 1
X#define EOT 4
X#define ACK 6
X#define NAK 025
X#define CPMEOF 032
X#define WANTCRC 0103	/* send C not NAK to get crc not checksum */
X#define TIMEOUT (-2)
X#define ERRORMAX 5
X#define RETRYMAX 5
X#define WCEOT (-10)
X#define SECSIZ 128	/* cp/m's Magic Number record size */
X
Xchar Lastrx;
Xchar Crcflg;
Xchar firstsec;
X#ifdef USG
Xstruct termio oldtty, tty;
X#else
Xstruct sgttyb oldtty, tty;
X#endif
X
Xunsigned updcrc();
X
Xmain(argc, argv)
Xchar *argv[];
X{
X	register char *cp;
X	register npats=0;
X	char **patts;
X	int exitcode;
X	char xXbuf[BUFSIZ];
X
X	if(argc<2)
X		goto usage;
X	setbuf(stdout, xXbuf);		
X	while (--argc) {
X		cp = *++argv;
X		if(*cp == '-') {
X			while( *++cp) {
X				switch(*cp) {
X				default:	
X					goto usage;
X				}
X			}
X		}
X		else if( !npats && argc>0) {
X			if(argv[0][0]) {
X				npats=argc;
X				patts=argv;
X			}
X		}
X	}
X	if(npats < 1) {
Xusage:
X		fprintf(stderr,"%s by Chuck Forsberg\n", VERSION);
X		fprintf(stderr,"Usage: sb file ...\n");
X		exit(1);
X	}
X#ifdef USG
X	(void) ioctl(0, TCGETA, &oldtty);
X	tty = oldtty;
X	tty.c_lflag &= ~(ECHO | ICANON | ISIG); /* No echo, crlf mapping, INTR
X						or QUIT chars, no crlf delays,
X						no erase/kill processing */
X	tty.c_iflag = IGNBRK;	/* Ignore break, disable parity check, no
X				stripping, no crnl mapping or ^S^Q */
X	tty.c_oflag = 0;	/* Transparent output, no delays, no crlf
X				mapping */
X	tty.c_cflag &= ~PARENB;	/* Leave baud rate alone, disable parity
X				generation and checking */
X	tty.c_cflag |= CS8;	/* Set character size = 8 */
X	tty.c_cc[VMIN] = 20;	/* Satisfy reads when this many chars in */
X	tty.c_cc[VTIME] = 1;	/* ... or in this many tenths of seconds */
X	(void) ioctl(0, TCSETA, &tty);
X#else
X	ioctl(1, TIOCEXCL, 0);
X	ioctl(1, TIOCGETP, &oldtty);
X	tty = oldtty;
X	tty.sg_flags |= RAW;
X	tty.sg_flags &= ~ECHO;
X	ioctl(1, TIOCSETP, &tty);
X#endif
X	if(wcsend(npats, patts)==ERROR) {
X		exitcode=128;
X		sendline(CAN);
X		sendline(CAN);
X		sendline(CAN);
X		sendline(CAN);
X	}
X	fflush(stdout);
X#ifdef USG
X	(void) ioctl(0, TCSBRK, 1);	/* Wait for output to drain */
X	(void) ioctl(0, TCFLSH, 1);	/* Flush input queue */
X	(void) ioctl(0, TCSETAW, &oldtty);	/* Restore original modes */
X	(void) ioctl(0, TCXONC,1);	/* Restart output */
X#else
X	ioctl(1, TIOCSETP, &oldtty);
X	ioctl(1, TIOCNXCL, 0);
X#endif
X	exit(exitcode);
X}
X
X
X
X
Xwcsend(argc, argp)
Xchar *argp[];
X{
X	register n;
X
X	Crcflg=FALSE;
X	firstsec=TRUE;
X	for(n=0; n<argc; ++n)
X		if(wcs(argp[n])==ERROR)
X			goto fubar;
X	if(wctxpn("")==ERROR)
X		goto fubar;
X	return OK;
Xfubar:
X	fclose(in);
X	sendline(CAN);sendline(CAN);sendline(CAN);
X	return ERROR;
X}
X
Xwcs(name)
Xchar *name;
X{
X	if((in=fopen(name, "r"))==NULL)
X		return ERROR;
X	if(wctxpn(name)!= ERROR)
X		return wctx();
X	else {
X		return ERROR;
X	}
X}
X
X
Xwctxpn(name)
Xchar *name;
X{
X	register firstch;
X	register char *p, *q;
X	char lname[SECSIZ];
X
X	if((firstch=readline(400))==TIMEOUT)
X		return ERROR;
X	if(firstch==WANTCRC)
X		Crcflg=TRUE;
X	for(p=name, q=lname ; *p; )
X		if((*q++ = *p++) == '/')
X			q = lname;
X	while(q < lname + SECSIZ)
X		*q++ = 0;
X	if(wcputsec(lname, 0)==ERROR)
X		return ERROR;
X	return OK;
X}
X
Xwctx()
X{
X	int sectnum, attempts, firstch;
X	char txbuf[SECSIZ];
X
X	firstsec=TRUE;
X
X	while((firstch=readline(400))!=NAK && firstch != WANTCRC
X	  && firstch!=TIMEOUT && firstch!=CAN)
X		;
X	if(firstch==CAN)
X		return ERROR;
X	if(firstch==WANTCRC)
X		Crcflg=TRUE;
X	sectnum=1;
X	while(filbuf(txbuf, SECSIZ)) {
X		if(wcputsec(txbuf, sectnum)==ERROR) {
X			return ERROR;
X		} else
X			sectnum++;
X	}
X	fclose(in);
X	attempts=0;
X	do {
X		sendline(EOT);
X		purgeline();
X		attempts++;
X	}
X		while((firstch=(readline(100)) != ACK) && attempts < RETRYMAX);
X	if(attempts == RETRYMAX)
X		return ERROR;
X	else
X		return OK;
X}
X
Xwcputsec(txbuf, sectnum)
Xchar *txbuf;
X{
X	register checksum, wcj;
X	register char *cp;
X	unsigned oldcrc;
X	int firstch;
X	int attempts;
X
X	firstch=0;	/* part of logic to detect CAN CAN */
X
X	for(attempts=0; attempts <= RETRYMAX; attempts++) {
X		Lastrx= firstch;
X		sendline(SOH);
X		sendline(sectnum);
X		sendline(-sectnum-1);
X		oldcrc=checksum=0;
X		for(wcj=SECSIZ,cp=txbuf; --wcj>=0; ) {
X			sendline(*cp);
X			oldcrc=updcrc(*cp, oldcrc);
X			checksum += *cp++;
X		}
X		if(Crcflg) {
X			oldcrc=updcrc(0,updcrc(0,oldcrc));
X			sendline(oldcrc>>8);sendline(oldcrc);
X		}
X		else
X			sendline(checksum);
X		purgeline();
X
X		firstch=readline(100);
X		if(firstch==CAN && Lastrx==CAN)
X			return ERROR;
X
X		else if(firstch==ACK) {
X			firstsec=FALSE;
X			return OK;
X		}
X		else if(firstch==TIMEOUT)
X			;
X		else {
X			if(firstsec && firstch==WANTCRC)
X				Crcflg=TRUE;
X			for(;;) {
X				Lastrx=firstch;
X
X				if((firstch=readline(1))==TIMEOUT)
X					break;
X				if(firstch==CAN && Lastrx==CAN)
X					return ERROR;
X			}
X		}
X	}
X	return ERROR;
X
X}
X
X
X/* fill buf with count chars padding with ^Z for CPM */
Xfilbuf(buf, count)
Xchar *buf;
X{
X	register c, m;
X	m=count;
X	while((c=getc(in))!=EOF) {
X		*buf++ =c;
X		if(--m == 0)
X			break;
X	}
X	if(m==count)
X		return 0;
X	else
X		while(--m>=0)
X			*buf++ = CPMEOF;
X	return count;
X}
X
Xsendline(c)
X{
X	putchar(c);
X}
X
Xalrm()
X{
X/* does nothing; actual effect is to give an error return on read */
X}
X
X
X/*
X * This version of readline is not so well suited for
X * reading many characters.  Fortunately, it doesn't
X * have to.
X * timeout is in tenths of seconds
X */
Xreadline(timeout)
X{
X	char byt;
X	register int c;
X	fflush(stdout);
X	signal(SIGALRM, alrm);
X	c = timeout/10;
X	if(c==0)
X		++c;
X	alarm(c);
X	if(read(1, &byt, 1)<1)
X		return TIMEOUT;
X	alarm(0);
X
X	return byt&0377;
X}
X
Xpurgeline()
X{
X	lseek(1, 0L, 2);
X}
X
X/* update CRC */
Xunsigned updcrc(c, crc)
Xregister c;
Xregister unsigned crc;
X{
X	register count;
X
X	for(count=8; --count>=0;) {
X		if(crc & 0x8000) {
X			crc <<= 1;
X			crc += (((c<<=1) & 0400)  !=  0);
X			crc ^= 0x1021;
X		}
X		else {
X			crc <<= 1;
X			crc += (((c<<=1) & 0400)  !=  0);
X		}
X	}
X	return crc;	
X}
*-*-END-of-sb.c-*-*
exit
-- 
frank
... Frank Whaley, MicroPro Product Development
{dual,hplabs,glacier,lll-crg}!well!micropro!sagan!frank

	"The heights by great men reached and kept,
	 were not attained by sudden flight.
	 But they, while their companions slept,
	 were toiling upward in the night."
			-Longfellow