[comp.unix.wizards] End-of-file character

ok@quintus.uucp (Richard A. O'Keefe) (10/05/88)

In article <4975@saturn.ucsc.edu> haynes@saturn.ucsc.edu (Jim Haynes - Computer Center) writes:
>So - I'm thinking of sticking in something along the lines of
>	if (!isatty(1))
>		fprintf(stderr, "Redirecting output may not be what
>		you have in mind.  Type a ctrl-D if you want to start
>		over.\n");

Please, anyone who is thinking of doing something like that, DON'T
hardwire "ctrl-D" into your program.  Mention the end-of-file character
the user has assigned, whatever that is.  Just to make life easier
for people who would like to extend this elementary courtesy to the
users of their programs, here's some source code:

: execute this with sh
cat >eofchar.c <<'ENDOFFILE'
/*  File   : eofchar.c
    Author : Richard A. O'Keefe @ Quintus Computer Systems, Inc
    Purpose: Return name of user's end-of-file character

    Compile: cc -DBSD -c eofchar.c		# on 4.x BSD
	     cc -DUSG -c eofchar.c		# on System V
	     cc -DTEST -DBSD eofchar.c		# to test it

    Usage:   eofchar()
	     returns a string which identifies the user's end-of-file
	     character.  A static buffer is used, but this value is not
	     likely to change, so that's no problem.  It is possible that
	     no end-of-file character may be assigned, in which case the
	     value shown is "exit", which is what you type to a shell to
	     stop it.

    Error:   if the end-of-file character cannot be determined, NULL is
	     returned.  (This is distinct from it being determined that
	     there is no end-of-file character.)
*/

#include <stdio.h>
#ifdef	BSD

#include <sgtty.h>

#define	TIO_GET_CHARS	TIOCGETC
#define	TIO_CHR_STRUCT	tchars
#define	TIO_CHR_FIELD	t_eofc

#endif

#ifdef	USG

#include <termio.h>

#define	TIO_GET_CHARS	TCGETA
#define	TIO_CHR_STRUCT	termio
#define	TIO_CHR_FIELD	c_cc[VEOF]

#endif

#ifndef	TIO_GET_CHARS

ERROR: either BSD or USG must be defined;

#endif


char *eofchar()
    {
	int fd;
	struct TIO_CHR_STRUCT info;
	int ch;
	static char buffer[12];

	if (!(isatty(fd=2) || isatty(fd=1) || isatty(fd=0))) {
	    fd = open("/dev/tty", 0);
	    if (fd < 0) {
		perror("Cannot open /dev/tty");
		return NULL;
	    }
	}
	if (ioctl(fd, TIO_GET_CHARS, &info) < 0) {
	    perror("Cannot obtain terminal characters");
	    if (fd > 2) (void) close(fd);
	    return NULL;
	}
	if (fd > 2) (void) close(fd);
	ch = info.TIO_CHR_FIELD;
	if (ch == 127) return "DELETE";
	if (ch == -1)  return "exit";
	if (ch >= 32)  (void) sprintf(buffer, "%c", ch); 
	else	       (void) sprintf(buffer, "Control-%c", ch+64);
	return buffer;
    }

#ifdef	TEST
main()
    {
	printf("Your end-of-file character is %s\n", eofchar());
	exit(0);
    }
#endif

ENDOFFILE

maart@cs.vu.nl (Maarten Litmaath) (10/11/88)

In article <503@quintus.UUCP> ok@quintus.UUCP (Richard A. O'Keefe) writes:
\... here's some source code:
[C source deleted]

People, what happened to good old shell script programming?

BSD:
sh -c 'stty all 2> /tmp/stty.$$; set `tail -1 /tmp/stty.$$`;
	shift; shift; echo $9; /bin/rm /tmp/stty.$$'
----------------------------------------------------------------------------
SysV:
sh -c 'stty -a | sed -e "s/.*eof = \([^;]*\).*/\1/" -e q'
----------------------------------------------------------------------------

BTW, this shows the SysV stty(1) command is favorable in one way: if stdout
isn't a tty, try stderr or stdin! (So we won't need the stupid temp file.)
-- 
Hippic sport:                         |Maarten Litmaath @ Free U Amsterdam:
             a contradiction in terms.|maart@cs.vu.nl, mcvax!botter!maart

maart@cs.vu.nl (Maarten Litmaath) (10/11/88)

In article <1503@fireball.cs.vu.nl> I goofed. Sorry.
-- 
Hippic sport:                         |Maarten Litmaath @ Free U Amsterdam:
             a contradiction in terms.|maart@cs.vu.nl, mcvax!botter!maart

bsy@PLAY.MACH.CS.CMU.EDU (Bennet Yee) (10/12/88)

In article <1503@fireball.cs.vu.nl> maart@cs.vu.nl (Maarten Litmaath) writes:
>In article <503@quintus.UUCP> ok@quintus.UUCP (Richard A. O'Keefe) writes:
>\... here's some source code:
>[C source deleted]
>
>People, what happened to good old shell script programming?
>
>BSD:
>sh -c 'stty all 2> /tmp/stty.$$; set `tail -1 /tmp/stty.$$`;
>	shift; shift; echo $9; /bin/rm /tmp/stty.$$'
>SysV:
>sh -c 'stty -a | sed -e "s/.*eof = \([^;]*\).*/\1/" -e q'
>
>BTW, this shows the SysV stty(1) command is favorable in one way: if stdout
>isn't a tty, try stderr or stdin! (So we won't need the stupid temp file.)


No no no no.  With even BSD stty, you can do it all in one line w/o stupid
tmp files:

  sh -c 'set `stty all 2>&1 >/dev/tty | tail -1`; shift; shift; echo $9'

or, if you don't like the tail, you could also use

  sh -c 'stty all 2>&1 > /dev/tty | awk "{ last = \$NF } END { print last }"'

What _did_ happen to good olde shell programming?

-bsy








-- 
Internet:	bsy@cs.cmu.edu		Bitnet:	bsy%cs.cmu.edu%smtp@interbit
CSnet:	bsy%cs.cmu.edu@relay.cs.net	Uucp:	...!seismo!cs.cmu.edu!bsy
USPS:	Bennet Yee, CS Dept, CMU, Pittsburgh, PA 15213-3890
Voice:	(412) 268-7571

ok@quintus.uucp (Richard A. O'Keefe) (10/12/88)

In article <1503@fireball.cs.vu.nl> maart@cs.vu.nl (Maarten Litmaath) writes:
>In article <503@quintus.UUCP> ok@quintus.UUCP (Richard A. O'Keefe) writes:
>\... here's some source code:
>[C source deleted]
>
>People, what happened to good old shell script programming?

Well, it's very simple.  I wanted my __C__ programs to be able to remind
their users what to type to get an end-of-file.  So I wrote a C function.
The main() in that file was enclosed in #ifdef TEST, remember!
(I have received some mail pointing out problems, esp. with System V.)

>BSD:
>sh -c 'stty all 2> /tmp/stty.$$; set `tail -1 /tmp/stty.$$`;
>	shift; shift; echo $9; /bin/rm /tmp/stty.$$'

It is very easy to break this (took me 2 minutes),
and in any case on the system I am using I get the answer "^Z/^[",
which is wrong (it should be "^Z").

>SysV:
>sh -c 'stty -a | sed -e "s/.*eof = \([^;]*\).*/\1/" -e q'

It is also easy to break this (took me 5 minutes; I don't know SysV well).

Forking off three programs (sh, stty, rm or sed) would be a very odd thing
to do in a C program when you can get the same information with a few
system calls.

While we're on the subject, I have read the SVID termio(ba_env) section
several times, and cannot tell whether there is any general way of
disabling individual elements of c_cc[] or not.  Setting c_cc[VEOL] to
ASCII NUL appears to disable that feature.  In DYNIX V3.0.12 NFS,
SunOS 3.2, and UNIX System V/386 Release 3.0, setting c_cc[VKILL] to
ASCII NUL merely makes ^@ the kill character.  Does anyone know which
elements of c_cc[] can be suppressed and which can't?

jc@minya.UUCP (John Chambers) (10/18/88)

> While we're on the subject, I have read the SVID termio(ba_env) section
> several times, and cannot tell whether there is any general way of
> disabling individual elements of c_cc[] or not.  Setting c_cc[VEOL] to
> ASCII NUL appears to disable that feature.  In DYNIX V3.0.12 NFS,
> SunOS 3.2, and UNIX System V/386 Release 3.0, setting c_cc[VKILL] to
> ASCII NUL merely makes ^@ the kill character.  Does anyone know which
> elements of c_cc[] can be suppressed and which can't?

My Sys/V  manual here says "These functions may be disabled 
individually by changing the value of the control character 
to an unlikely or impossible value (e.g., 0377)."  In other 
words, the answer to your question is "No, there is no way
guaranteed to disable individual elements of c_cc[]."   

Don't you love it when they phrase things in such a way as
to give the impression that something works, when in fact
it doesn't, and they know it?  (:-{(>

(That's a bald hacker with a moustache, a frown, and a goatee. ;-)

-- 
John Chambers <{adelie,ima,maynard,mit-eddie}!minya!{jc,root}> (617/484-6393)

[Any errors in the above are due to failures in the logic of the keyboard,
not in the fingers that did the typing.]