UNIX (SysV) XMODEM wanted.
Frank Whaley
frank at sagan.UUCP
Thu Oct 3 06:12:19 AEST 1985
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
More information about the Comp.sources.bugs
mailing list