1

I have read that Ctrl-J sends '\n', Ctrl-M sends '\r' and Ctrl-D sends EOF, but either this is incorrect or I'm simply not understanding what's happening. This simple program illustrates:

const size_t SIZE = 100;

int main() { char str[SIZE]; printf("Enter string: "); size_t len = 0; char ch; while ((ch = getchar()) != '\r' && ch != '\n' && ch != EOF && len < SIZE -1) { str[len++] = ch; printf("ch is %i\n",ch); } printf("ch is %i\n",ch); str[len] = '\0'; printf("%s\n",str);

return 0;

}

When I enter: hello(Ctrl-j) the output is exactly what I would expect:

ch is 104
ch is 101
ch is 108
ch is 108
ch is 111
ch is 10
hello

but when I enter: hello(Ctrl-m) the output is exactly the same - i.e., the last ch is still 10, rather than the 13 that I was expecting.

And when I enter: hello(Ctrl-d) the output stops at the beginning of the line following "ch is 111" (the 'o'):

ch is 101
ch is 108
ch is 108
ch is 111

and waits there until I press Ctrl-d a second time after which it finishes with:

ch is -1
hello

or, if instead of a second Ctrl-D, I press Ctrl-J or Enter. In this case it finishes with

[blank line]
ch is 10
hello

losing the -1 and printing the 10 for '\n' instead.

I've tried this on a desktop running Arch Linux as well as a notebook running Ubuntu -- same results with both.

So, is there actually a way to send a CR from a keyboard under Linux, and why does the EOF need to be sent twice?

Jackdaw
  • 1,834
joelk
  • 13

1 Answers1

3

So, is there actually a way to send a CR from a keyboard under Linux

You are sending a CR, but the tty layer will translate it to a LF by default, so the program cannot receive a CR. Use tcsetattr() to disable the ICRNL mode if you want to avoid this. (But don't forget to save the old settings first, and reset them on exit.)

Search also for raw/cooked/cbreak modes.

and why does the EOF need to be sent twice?

There is actually no such thing as an EOF result at OS level – instead, whenever the read() system call returns 0 bytes, then libc functions report it as an EOF.

So Ctrl+D actually just tells the OS to immediately finish the read() call (that is, without waiting for a newline), and it only becomes an EOF indicator if it causes that read() call to return no data at all. That only happens if you press it immediately after a newline or after a previous Ctrl+D.

You'll see this happening in other programs too. Run strace -e read cat or strace -e read ./myprogram to see it happening in more detail.

grawity
  • 501,077