Path: utzoo!lsuc!hcr!larry From: larry@hcr.UUCP (Larry Philps) Newsgroups: comp.unix.questions Subject: Re: Timed reading in C (?) Message-ID: <3116@hcr.UUCP> Date: Wed, 17-Feb-88 09:37:55 EST Article-I.D.: hcr.3116 Posted: Wed Feb 17 09:37:55 1988 References: <469@mv02.ecf.toronto.edu> Reply-To: larry@hcr.UUCP (Larry Philps) Distribution: world Organization: HCR Corporation, Toronto Lines: 131 In article <469@mv02.ecf.toronto.edu> ip@mv02.ecf.UUCP (Bevis Ip) writes: >>What I want my program to do is wait a short while (like, say, 5 seconds >>or so) for an user to type in something. If the user doesn't type in >>anything after that time period, the program goes ahead and does something >>else. But if the user has already started to type, the program waits and >>lets him finish typing. >> >>What I'd like to know is how to do this in C. (By the way, I'm on BSD >>Unix 4.3.) I want the user's terminal to stay in the canonical mode, >>if possible. > >Took me a while to crank the following program up, seems like it's doing >what you've asked. There're probably better ways in doing this, and I'm >open for criticism. The code is pretty straight forward (I hope), so >comments are minimal. > >bevis > > Program using signals, setjmp, longjmp ... This can be done a little easier. The following two incomplete programs should show you how. Since I did not write complete programs, I have obviously not tested them, but you should get the idea. /* * Solution 1: Use select to wait for a specified period for input. * When select returns, either the timeout has expired, or there is * data to read. React appropriately. */ int fd, nbytes, nfound; char buf[BUFFER_SIZE]; fdset readfds; struct timeval timeout; /* * either this if reading standard input, or * open the appropriate file and get a file * descriptor for it. */ fd = 0; FD_ZERO(&readfds); FD_SET(fd, &readfds); timeout.tv_sec = SLEEP_TIME; timeout.tv_usec = 0; nbytes = 1; while (nbytes != 0) { /* End of File test */ nfound = select (1, &readfds, (int *)0, (int *)0, &timeout); if (nfound < 0) { perror("select"); exit(1); } if (nfound == 0) { /* * The timeout expired. There is no data to read * so do what needs to be done in this case. */ ..... continue; } /* * Select did not return an error, and the timeout did not * expire. There must be data to read on the only file * descriptor we told it to watch. */ ASSERT(FD_ISSET(fd, &readfds)); nbytes = read(fd, buf, sizeof(buf)); /* * We have the data. Do something. */ ... } /* * Solution 2: Use non-blocking I/O so that the reads never hang. * This has the disadvantage that if there is no data to read, then * you sleep before trying again, thus creating a possible lag time * between the time that the user types his input and the program sees * it. The advantage is that it does not use select (an advantage you say!) * and thus should even work on System V. */ int fd, nbytes; char buf[BUFFER_SIZE]; /* * either this if reading standard input, or * open the appropriate file and get a file * descriptor for it. */ fd = 0; if (fcntl (fd, F_SETFL, FNDELAY) < 0) { perror("fcntl: F_SETFL"); exit(1); } /* * Give the user a chance to type something first. * This is grotty. */ sleep(SLEEP_TIME); /* * Now non-blocking I/O is enabled on the file descriptor. * Reads will not hang, so try one and if there is no data * just sleep for a bit, then try again. */ while ((nbytes = read(fd, buf, sizeof(buf)) != 0) { if (nbytes < 0 && errno == EWOULDBLOCK) { /* * No data for us now, do what needs to be done * when the user has entered no input, then * try again later. */ ... sleep(SLEEP_TIME); continue; } /* * We have the data. Do something. */ ... } ---- Larry Philps HCR Corporation 130 Bloor St. West, 10th floor Toronto, Ontario. M5S 1N5 (416) 922-1937 {utzoo,utcsri,decvax,ihnp4}!hcr!larry