[net.sources] Need Non-Blocking Terminal Input Function For Berkeley 4.2

tom@puff.wisc.edu (Thomas Scott Christiansen) (01/24/86)

> Does anyone know of a way to do read from a terminal under Berkeley 4.2 UNIX
> so that after a specified number of seconds control is returned to the
> program if there is no response?  Right now I'm forking off of the main
> program, and having the child process do the read, with the parent setting
> an alarm to interrupt the child after a certain number of seconds.  This
> works, but it's devilishly difficult to debug using dbx.  Alternate 
> techniques would be appreciated.

Yes the read will restart, *IF* you return to it.  The trick is not
to return to it.  You should use setjmp() to remember where you were.
The following module should do what you want.  It contains the function
readt() which works just as read does except that it accepts a fourth
argument indicating the number of seconds at which a timeout is to be
triggered.  If this does occur, errno will contain EINTR.

A sample main() is included to test the function.   I have tested it
on a Gould under 4.2, a Pyramid under 4.2/SYSV, and a Vax 780 under 4.3.
-----------------------------------------------------------------------

#include <setjmp.h>
#include <signal.h>
#include <errno.h>

#define reg     register
#define global
#define local   static
#define ERROR   (-1)

local  jmp_buf  Context;
local  int      timetrap();
extern int      alarm();
extern int      errno;

/*
 *  readt(): a read function that accepts a
 *           fourth parm indicating the number of seconds 
 *           at which to trigger the timeout.  other parms are 
 *           the same as read.
 *  
 *           returns number of bytes read or -1 on error.
 *           a timeout causes errno to be set to EINTR.
 */
global int
readt ( channel, buffer, count, timeout )
    reg int channel, count;
    reg unsigned timeout;
    reg char *buffer;
{
    reg int retval;
    reg int (*alrm_vec)();

    alrm_vec = signal (SIGALRM, timetrap);
    (void) alarm ( timeout );
    retval   = setjmp (Context)
                ? (errno = EINTR, ERROR)
                : read ( channel, buffer, count );
    (void) alarm ( 0 );
    (void) signal (SIGALRM, alrm_vec);
    return retval;
}

local int
timetrap() {
    longjmp ( Context, 1 );
}

#include <stdio.h>
#define TIMEOUT 3
main() {
    char line[100];

    printf ("string (no timeout): ");
    fflush (stdout);
    if ( read (fileno(stdin), line, sizeof(line)) < 0)
        perror("read");
    else
        printf ( "The string was %s",line);

    printf ("string (timeout == %d): ",TIMEOUT);
    fflush (stdout);

    if ( readt (fileno(stdin), line, sizeof(line), TIMEOUT) < 0)
        perror("readt");
    else
        printf ( "The string was %s",line);
}

/* lint output:
/usr/staff/tom/src/readt.c:
fflush returns value which is always ignored
*/