views:

1718

answers:

4

I am using the following conditional statement to read from standard input.

if ((n = read(0,buf,sizeof(buf))) != 0)

When inputting data from standard input, generally the user presses enter when done. But read() considers '\n' as input too in which case n = 1 and the conditional doesn't evaluate to false. Is there a way to make the conditional evaluate to false when the user presses enter (without entering anything) on standard input apart from checking the contents of buf. Is there any other function other than read() that I might use for this purpose??

For that matter, what can be a way for read to determine end of input when the input comes from standard input (stdin)?

A: 

You better use fgets() for your task (catching user input), but even fgets() stores newline character in buffer.

However if newline is there, you can be sure it is last character in the string so it is easy to strip it.

qrdl
You can't be sure that the last character in the buffer is a newline since fgets() will only store the newline if there is one in the file. May not be if the last line doesn't include one.
Inshallah
@Inshalla I meant that if newline is in buffer, it is surely last character. I'll edit my post to make it explicit.
qrdl
First, I am working with file descriptors here and not file pointers. fgets() takes file pointers. And what i want to be able to do is to make the conditional evaulate to false when user presses enter. I can offcourse determeine here also if newline was the last character entered or not.
s_itbhu
You said you are reading from standard input so it doesn't matter whether you use read(0, ..) or fread(..., stdin) or fgets(..., stdin). My post was based on the information you have provided in your question. If you want to stop on empty line, you can do it like "if ('\n' != *fgets(buf, sizeof(buf)-1, stdin))"
qrdl
@qrdl, which of course is examining the buffer as well, but may be preferable to other solutions for aestetical reasons.
Inshallah
A: 

I'm quite positive there's no way to do it without examining the buffer contents. Even readline() does just that. Why are you opposed to it, anyways?

Michael Foukarakis
A: 

You have to check the buffer yourself. e.g.

while((n = read(0,buf,sizeof(buf))) > 0) {
  if(buf[0] == '\n') // won't handle pressing 9 spaces and then enter
    continue;
  ... process input

}

or use e.g. fgets, and just strip off the \n

while(fgets(buf,sizeof buf,stdin) != NULL) {
  char *ptr;
  size_t len;

  if((ptr = strchr(buf,'\n')) != NULL) //strip newline
    *ptr = 0; 
  len = strlen(buf);
  if(len == 0)
   continue;
  ... process input 
}
nos
+2  A: 

You ask:

When inputting data from standard input, generally the user presses enter when done. But read() considers '\n' as input too in which case n = 1 and the conditional doesn't evaluate to false.

The first point is certainly true. The enter key is equivalent to the newline key, so when the user presses enter, the keyboard generates a newline character, and the read() function therefore returns that character. It is crucial that it does do that.

Therefore, your condition is misguided - an empty line will include the newline and therefore the byte count will be one. Indeed, there's only one way to get the read() call to return 0 when the standard input is the keyboard, and that's to type the 'EOF' character - typically control-D on Unix, control-Z on DOS. On Unix, that character is interpreted by the terminal driver as 'send the previous input data to the program even if there is no newline yet'. And if the user has typed nothing else on the line, then the return from read() will be zero. If the input is coming from a file, then after the last data is read, subsequent reads will return 0 bytes.

If the input is coming from a pipe, then after all the data in the pipe is read, the read() call will block until the last file descriptor that can write to the pipe is closed; if that file descriptor is in the current process, then the read() will hang forever, even though the hung process will never be able to write() to the file descriptor - assuming a single-threaded process, of course.

Jonathan Leffler
Critical that you educate why the return value of 0 from read()/recv() is distinct from an empty line. If you get 0 from read()/recv() it means you are at the end of all input (i.e. it is closed, no new input can be added).
Will
NB: there are devices where getting `read()` returning zero does not mean no more input can be added. Showing my antiquitiy - mag tape devices were one such. Currently, terminals are another. With esoteric options on `open()` (such as O_NONBLOCK) you can get that behaviour on other devices. But an empty line is by definition a line containing only a newline character - the end of line marker (aka newline character) is part of the data. If you don't want that in your program, you have to remove it. Only `gets()` removes the newline for you, but you should *never* use it in production code.
Jonathan Leffler