[comp.unix.xenix] Unbufferred file I/O

cline@pnet01.cts.com (Ben Humphreys) (05/14/88)

As I have not been able to get any versions of talk to run on my SCO system, I
was forced to use write.  But write is a bummer because it is bufferred.  You
end up typing over top of each other.  With program bundle.c in hand, I fig-
ured it wouldn't be too hard to make it write one character at a time to the
tty and stay in interactive mode until EOF.  Boy was I wrong.  I ended up 
using read() and write() to read from the local terminal and write to the 
remote terminal.  But, as far as I can tell, write() doesn't actually write
until it receives a newline / carriage return.  Even if I close() and re
open() the /dev/ttynn file, it still won't flush it's buffer.  Is there a way
for force write() to flush the buffer without requiring a newline / carriage
return.  Or, optionally, is there a way to get one character from the local
terminal (unbufferred) and write said character to the local terminal (again, 
unbufferred)?  

Anyone got a version of talk.c to run under SCO 2.1.3???  
UUCP: {cbosgd, hplabs!hp-sdd, sdcsvax, nosc}!crash!cline01!benh
ARPA: crash!cline01!benh@nosc.mil
INET: cline@pnet01.CTS.COM

ben@idsnh.UUCP (Ben Smith) (05/15/88)

In article <2961@crash.cts.com> cline@pnet01.cts.com (Ben Humphreys) writes:
| As I have not been able to get any versions of talk to run on my SCO system, I
| was forced to use write.  But write is a bummer because it is bufferred.  

The I/O has to be set to "cbreak" mode. See the termio  & ioctl sections of your
UNIX manual.  The following program demonstrates the use of "cbreak":

/* 1ch - sets terminal echo off and does decimal code echo of each keypress
   until newline is received  - ben smith (uunet!idsnh!ben) - this program
   is being placed in the public domain by the author (bss) */

#include <stdio.h>
#include <termio.h>

char *descr[33] /* control character descriptions */
	=	{
		"   NULL",
		"^A SOH ",
		"^B STX ",
		"^C ETX ",
		"^D EOT ",
		"^E ENQ ",
		"^F ACK ",
		"^G BEL ",
		"^H BS  ",
		"^I HT  ",
		"^J LF  ",
		"^K VT  ",
		"^L FF  ",
		"^M CR  ",
		"^N SO  ",
		"^O SI  ",
		"^P DLE ",
		"^Q DC1 ",
		"^R DC2 ",
		"^S DC3 ",
		"^T DC4 ",
		"^U NAK ",
		"^V SYN ",
		"^W ETB ",
		"^X CAN ",
		"^Y EM  ",
		"^Z SUB ",
		"^[ ESC ",
		"^\\ FS  ",
		"^] GS  ",
		"^^ RS  ",
		"   SP  "
		};

main()
{
int inchar, c;
struct termio old, new;

/* save old terminal config */
ioctl(0,TCGETA,&old);

/* set up new terminal config */
/* first make a copy to modify */
ioctl(0,TCGETA,&new);
/* then AND the controls */
new.c_lflag &= !(ICANON);
new.c_cc[4] = new.c_cc[5] = '\01';  /* delay and buffer size */
/* and send out new config */
ioctl(0,TCSETAW,&new);

/* now for the real part of the program - processing the keypresses */
do
	{
	c = getchar();
	if ((c > 32 && c < 127) || (c > 160 && c < 255))
		printf("decimal %3d   octal %3o   hex %2X = %c\n",c,c,c,c);
	else if (c >= 0 && c <= 32)
		printf("decimal %3d   octal %3o   hex %2X = %s\n",c,c,c,descr[c]);
	else if (c >= 128 && c <= 160)
		printf("decimal %3d   octal %3o   hex %2X = %s\n",
			c,c,c,descr[c-128]);
	else if (c == 127 || c == 255)
		printf("decimal %3d   octal %3o   hex %2X = DEL\n",c,c,c);
	}while (c != '\n');

/* reinstate old parameters before leaving */
ioctl(0,TCSETAW,&old);
}

haugj@pigs.UUCP (John F. Haugh II) (05/16/88)

In article <2961@crash.cts.com>, cline@pnet01.UUCP writes:
> As I have not been able to get any versions of talk to run on my SCO system, I
> was forced to use write.

[ much deleted ]

> Anyone got a version of talk.c to run under SCO 2.1.3???  

no, i have managed to get talk running under 2.2.1 on a 386.  it's even
been tested ;-)

- john.
-- 
 The Beach Bum                                 Big "D" Home for Wayward Hackers
 UUCP: ...!killer!rpp386!jfh                            jfh@rpp386.uucp :DOMAIN

 "You are in a twisty little maze of UUCP connections, all alike" -- fortune

abcscnge@csuna.UUCP (Scott "The Pseudo-Hacker" Neugroschl) (05/20/88)

In article <2961@crash.cts.com> cline@pnet01.cts.com (Ben Humphreys) writes:

    [ stuff about how write is buffered, and wants to go unbuffered input ]

Use ioctl().  Set the terminal flags to:

#include <sys/types.h>
#include <sys/ioctl.h>
#include <termio.h>

	struct termio ttyold, ttynew;
		
	/* get the terminal params twice */
	if (ioctl(0,TCGETA,&ttyold) == -1 || ioctl(0,TCGETA,&ttynew) == -1)
	{
		perror("program");
		exit(-1);
	}

	/* set up for unbuffered I/O */
	ttynew.c_cc[VMIN] = 1;
	ttynew.c_cc[VTIME] = 0;
	ttynew.c_lflags &= ~ICANON;
	if (ioctl(0,TCSETAW,&ttynew) == -1)
	{
		perror("program");
		exit(-1);
	}

	/* Stuff to talk to other user here */


	/* clean up when done */
	ioctl(0,TCSETAW,&ttyold);
	exit(0);				/* done */


Note that you should catch SIGINT and probably SIGQUIT too, so that you 
can clean up gracefully before dropping dead.


-- 
Scott "The Pseudo-Hacker" Neugroschl
UUCP:  ...!ihnp4!csun!csuna!abcscnge
-- "They also surf who stand on waves"
-- Disclaimers?  We don't need no stinking disclaimers!!!