kcw@beach.cis.ufl.edu (Ken Whedbee) (10/16/90)
Hello Continent - I m looking for example code (bsd derivative .. SunOS perferably) that reads characters one at a time instead of buffering the chars until a newline like the read() system call. I understand that ioctl() can do this by setting the terminal into raw mode such that no pre-processing of the input takes place. There's example code of how to do this on pg. 340 in Bach's book. But alas, this is system V code. Does anyone know of or can give me an example in bsd ? many thanx! -- Ken Whedbee Internet: kcw@beach.cis.ufl.edu University of Florida UUCP: ..!uflorida!beach.cis.ufl.edu!kcw "C Code. C code run. Run, code, run... PLEASE!!!" -- Barbara Toungue
felps@convex.com (Robert Felps) (10/16/90)
In <24905@uflorida.cis.ufl.EDU> kcw@beach.cis.ufl.edu (Ken Whedbee) writes: >I m looking for example code (bsd derivative .. SunOS perferably) that >reads characters one at a time instead of buffering the chars until a >newline like the read() system call. >I understand that ioctl() can do this by setting the terminal into >raw mode such that no pre-processing of the input takes place. There's >example code of how to do this on pg. 340 in Bach's book. But alas, >this is system V code. >Does anyone know of or can give me an example in bsd ? This should do BSD or SV single character input. --------------------------------------------------------------------------- /* This program resets the tty driver to allow single character input. It provides for single character input in shell scripts. Usage: ANSWER=`getsks` To compile and install: cc -D[BSD|SV] getsinglekey.c -o getsks chmod 555 getsks cp getsks /usr/local/bin */ #include <sys/types.h> #include <signal.h> #ifdef BSD #include <sgtty.h> /* include the BSD terminal handling header file. */ struct sgttyb new, old; /* BSD term-info structure */ #else /* include the System V terminal handling header file. */ #include <termio.h> struct termio new, old; /* SYSV term-info structure */ #define gtty(fd,arg) (ioctl(fd, TCGETA, arg)) #define stty(fd,arg) (ioctl(fd, TCSETA, arg)) #endif main() { int c; gtty(0,&old); gtty(0,&new); #ifdef BSD /* set "raw" mode for BSD */ new.sg_flags &= ~(ECHO|CRMOD); new.sg_flags |= RAW; #else new.c_iflag &= ~(INLCR|ICRNL|IUCLC|ISTRIP|IXON|BRKINT); new.c_oflag &= ~OPOST; new.c_lflag &= ~(ICANON|ISIG|ECHO); new.c_cc[VMIN] = 1; new.c_cc[VTIME] = 1; #endif stty(0,&new); if (c=getchar()) { stty(0,&old); putchar(c); exit(0); } } --------------------------------------------------------------------------- Hope it helps, Robert Felps felps@convex.com Convex Computer Corp OS System Specialist 3000 Waterview Parkway Tech. Assistant Ctr Richardson, Tx. 75083 1(800) 952-0379
brister@decwrl.dec.com (James Brister) (10/16/90)
On 15 Oct 90 20:31:15 GMT, kcw@beach.cis.ufl.edu (Ken Whedbee) said: > I m looking for example code (bsd derivative .. SunOS perferably) that > reads characters one at a time instead of buffering the chars until a > newline like the read() system call. Here's my (very old) version of the "pick" program from Kernighan and Ritchie's UNIX programming book. It uses CBREAK mode, and it runs on Ultrix--but I doubt porting would be a problem. #! /bin/sh # This is a shell archive. Remove anything before this line, then unpack # it by saving it into a file and typing "sh file". To overwrite existing # files, type "sh file -c". You can also feed this as standard input via # unshar, or by typing "sh <file", e.g.. If this archive is complete, you # will see the following message at the end: # "End of shell archive." # Contents: pick.c # Wrapped by brister@westworld on Tue Oct 16 09:51:57 1990 PATH=/bin:/usr/bin:/usr/ucb ; export PATH if test -f 'pick.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'pick.c'\" else echo shar: Extracting \"'pick.c'\" \(1018 characters\) sed "s/^X//" >'pick.c' <<'END_OF_FILE' X#include <sgtty.h> X#include <stdio.h> X char *progname ; /* name of program for error message */ int pipeout ; X main (argc,argv) X int argc ; X char *argv [] ; X{ X int i ; X struct sgttyb oldmode, newmode ; X X X if (argc == 1) X { X fprintf (stderr,"%s [-] [files...]\n",progname) ; X exit (1) ; X } X X pipeout = isatty (0) ; X progname = argv [0] ; X if ( gtty (0,&oldmode) == -1 ) X { perror ("gtty") ;} X newmode = oldmode ; X newmode.sg_flags |= CBREAK ; X if ( stty (0,&newmode) == -1 ) X { perror ("stty") ; } X X i = 1 ; X while ( i < argc && pick (argv [i]) == 1 ) X i++ ; X X stty (0,&oldmode) ; X exit (0) ; X} X pick (s) X char *s ; X{ X int c ; X X fprintf (stderr, "%s? ",s) ; X c = ttyin () ; X fprintf (stderr,"\n\r") ; X if ( c == 'y' ) X { X printf ("%s\n",s) ; X return 1 ; X } X else if ( c == 'q' ) X return 0 ; X else X return 1 ; X} X int ttyin () X{ X char c ; X if ( ! read (0,&c,sizeof (c)) ) X { perror ("read") ; return 'q' ; } X else X return c ; X} X X END_OF_FILE if test 1018 -ne `wc -c <'pick.c'`; then echo shar: \"'pick.c'\" unpacked with wrong size! fi # end of 'pick.c' fi echo shar: End of shell archive. exit 0 James -- James Brister brister@decwrl.dec.com DEC Western Software Lab., Palo Alto, CA {uunet,sun,pyramid}!decwrl!brister
guy@auspex.auspex.com (Guy Harris) (10/19/90)
>This should do BSD or SV single character input.
It does, but it may be overkill. The problem is that the term "raw
mode" is used to refer both to the mode that, in the older V7-based tty
drivers such as the one in BSD, is actually called RAW mode, *and* to
any mode that gives you characters as they're typed.
RAW mode does a *lot* more than just give you characters as they're
typed. It also:
puts the line in 8 bits, no parity, mode;
turns off all output processing;
turns off special handling of all input characters, including
the interrupt, quit, suspend (if you have job control), ^S, and
^Q characters;
etc..
Not all applications that want to read characters one at a time
necessarily want to do all that.
In the older tty driver, you can turn CBREAK mode on, which will only
put the driver in "character at a time" mode and, as such, disable the
line-editing characters; it won't turn off the signal-generating
characters nor ^S nor ^Q, nor will it affect output processing or change
the parity mode of the line. In the newer tty driver, you can turn
ICANON mode off, which has the same effect.
This does, of course, mean that you now have to *catch* signals such as
SIGINT and, if you have job control, SIGTSTP, and handle them
appropriately; otherwise, if you abort the program by typing your
interrupt character, or stop it by typing the suspend character if you
have job control, the tty will still be in character-at-a-time mode.
It also means you can't use ^S, ^Q, etc. as input characters; you'd
have to disable those as well. Individual control characters can
sort-of be disabled in the older driver by setting them to '\377', as
the older driver usually strips input characters to 7 bits before
comparing them with those special characters. (As of 4.3BSD, though, if
you turn PASS8 on, it won't strip it, so if somebody happens to have a
key that generates, say, the ISO Latin 1 "y with a diaresis" character,
whose character code happens to *be* '\377', you may be in for a
surprise if you set one of those characters to '\377'. You might try
'\200' instead, as it's a less-likely character to get as input.)
The newer driver lets you disable the signal-generating characters
(interrupt, quit, suspend if you have job control) by turning ISIG off,
and disable ^S and ^Q by turning IXON off.
If you want 8-bit input - e.g., if your terminal has a META key that
turns the 8th bit on, and you want to be able to use it - PASS8 mode
works with the 4.3BSD and later versions of the older driver; it puts
the tty port into 8 bits, no parity mode, and prevents characters from
being stripped to 7 bits on input. In the newer driver, you have to
turn the ISTRIP bit off (to prevent characters from being stripped to 7
bits on input), and set the "c_cflag" field to include CS8 and turn off
PARENB (for 8 bits, no parity).
guy@auspex.auspex.com (Guy Harris) (10/31/90)
>A much simpler way to guarantee that program X will not mess up your tty >modes is to run it under pty. pty is totally transparent to job control, >but will restore your tty modes properly on stop or exit. Does it restore my screen as well? I.e., if it's a full-screen program, when I hit ^Z, will it either clear the screen or put the cursor at the bottom of the screen, and when I continue the program will it redraw the screen? If not, I'm not interested.
brnstnd@kramden.acf.nyu.edu (Dan Bernstein) (10/31/90)
In article <4214@auspex.auspex.com> guy@auspex.auspex.com (Guy Harris) writes: > >A much simpler way to guarantee that program X will not mess up your tty > >modes is to run it under pty. pty is totally transparent to job control, > >but will restore your tty modes properly on stop or exit. > Does it restore my screen as well? I.e., if it's a full-screen program, > when I hit ^Z, will it either clear the screen or put the cursor at the > bottom of the screen, and when I continue the program will it redraw the > screen? If that's what your program does, yes. One of my first design criteria was that pty vi should feel *exactly* like a normal vi. (And it's amazing how many roadblocks POSIX throws in the way of this goal.) It's certainly not pty's responsibility to redraw the screen if your program doesn't. Virtual terminal management does not fall under pseudo-tty session management. If you want this feature, make it into a separate program. Okay, okay, I just spent a few minutes and did the work. Enclosed is a sloppy fullscreen.c. You might invoke it as pty -pcE fullscreen nastyprog nastyprog will run in a full-screen curses window, in character mode with echo off. Terminal stop characters will affect pty rather than going through to nastyprog. Your tty will be restored to its original mode upon ^Z or nastyprog exit. curses will do what you asked for. Any other requests? > If not, I'm not interested. What a productive attitude. ---Dan #include <sys/wait.h> #include <sys/time.h> #include <sys/resource.h> #include <signal.h> #include <curses.h> #define SIZ 1024 int f; int pi[2]; char buf[SIZ]; int r; int i; sigchld() { union wait w; int x; int y; if (wait3(&w,WUNTRACED | WNOHANG,(struct rusage *) 0) <= 0) return; if (w.w_stopval == WSTOPPED) kill(f,SIGCONT); else { r = read(pi[0],buf,SIZ); if (r > 0) for (i = 0;i < r;i++) addch(buf[i]); refresh(); move(23,0); refresh(); getyx(stdscr,y,x); mvcur(y,x,23,0); endwin(); resetty(); exit(w.w_retcode & 127); } } main(argc,argv) int argc; char *argv[]; { signal(SIGCHLD,sigchld); pipe(pi); switch(f = fork()) { case -1: break; case 0: close(pi[0]); dup2(pi[1],1); close(pi[1]); execvp(argv[1],argv + 1); break; default: close(pi[1]); close(0); savetty(); initscr(); refresh(); scrollok(stdscr,1); for (;;) { r = read(pi[0],buf,SIZ); if (r == 0) break; if (r > -1) for (i = 0;i < r;i++) addch(buf[i]); refresh(); } sigpause(0); } exit(0); }