sws@holin.ATT.COM (Steve Spear) (03/09/90)
Can someone please explain to me why the code below can read every character except NULL from a terminal or serial port? I'm primarily using this on Xenix but it failed on Unix also. I'm using it for an Xmodem receiver and it drops any block with a NULL ( ascii 0 ) in it. Since the last xmodem block is full of zeros for padding the last block always fails. Somehow it only gets half the nulls in the block and then times out. This is the simplest case I have for the problem - please excuse the sloppy code - just hacking it up to get an idea of whats going on. I've been porting a multiuser bbs from dos to Xenix and everything seems to be working but receiving NULL's - argh!!! I've read all I can in the Xenix and Unix manuals and no mention of a problem with NULL - thanks steve spear #include <stdio.h> #include <fcntl.h> #include <sys/types.h> #include <sys/stat.h> #include <memory.h> #include <string.h> #include <ctype.h> #include <stdlib.h> #include <math.h> #include <malloc.h> #include <time.h> #include <signal.h> #include <errno.h> static char *portname = "/dev/tty"; static int termfd; static struct termio tio, oldtio; typedef int bool; #define TRUE 1 #define FALSE 0 #define XENIX TRUE static struct termio tiosave; void setblock( int fd, bool on ) { static int blockf, nonblockf; static bool first = TRUE; int flags; if ( first ) { first = FALSE; if ( ( flags = fcntl( fd, F_GETFL, 0 ) ) == -1 ) printf( "setblock error" ); blockf = flags & O_NDELAY; nonblockf = flags | O_NDELAY; } ( void ) fcntl( fd, F_SETFL, on ? blockf : nonblockf ); } static int readcond( int fd, char *buf, unsigned nbytes, bool block ) { int retval; #ifdef XENIX if ( !block && rdchk( fd ) == 0 ) return( 0 ); #else setblock( fd, block ); #endif retval = read( fd, buf, nbytes ); return( retval ); } #define EMPTY '\0' static char cbuf = EMPTY; bool cready() { if ( cbuf != EMPTY ) return( TRUE ); switch( readcond( termfd, &cbuf, 1, FALSE ) ) { case -1 : printf( "read error" ); break; case 0 : return( FALSE ); default : return( TRUE ); } } int cget() { int retval; char c; if ( cbuf != EMPTY ) { c = cbuf; cbuf = EMPTY; return( c & 0377 ); } retval = readcond( termfd, &c, 1, TRUE ); switch( retval ) { case -1 : printf( "read 2 error" ); case 0 : return( -1 ); default : return( c & 0377 ); } } void termopen( void ) { int fd2; termfd = open( portname, O_RDWR | O_NDELAY ); if ( termfd != -1 ) { ioctl( termfd, TCGETA, &oldtio ); /* get orig modem settings*/ ioctl( termfd, TCGETA, &tio ); /* get orig modem settings*/ tio.c_lflag &= ~(ISIG|ICANON|ECHO); tio.c_iflag |= (BRKINT|IGNPAR); tio.c_iflag &= ~(IGNBRK|INLCR|IGNCR|ICRNL|IUCLC|IXON|IXANY|IXOFF |INPCK|ISTRIP); tio.c_oflag &= ~OPOST; tio.c_cc[ VMIN ] = 1; tio.c_cc[ VTIME ] = 10; ioctl( termfd, TCSETAW, &tio ); /* set the new settings */ } fd2 = open( portname, O_RDWR ); close( termfd ); termfd = fd2; } void termclose( void ) { unsetraw(); } void main() { int k; termopen(); while ( TRUE ) { k = cget(); if ( k == 'q' ) break; printf( "%c", k ); if ( !cready() ) printf( "\r\n" ); } termclose(); }