0

Due to my dissatisfaction with std iostream and stdio, I decided to create my own io library. And it is good for my education.

But I have a slight problem. Linux read(), when operating on a terminal file descriptor, won't return until new line. So if I ask it for 10 bytes, Even if I type 20 bytes it won't return. To make matters worse, those 10 extra bytes are not recorded in the buffer I pass it.

What happened to those 10 extra bytes? Does Linux have a buffer it uses for reads? Can I access this buffer instead of providing my own?

  • There is an `ioctl()` to modify this behaviour. – user207421 Feb 25 '19 at 00:15
  • 3
    _"Linux read(), when operating on a terminal file descriptor, won't return until new line."_ That is not true. Rather, it is that the terminal doesn't _send_ those bytes until it's got a whole line. If you e.g. use PuTTY and just turn off line buffering in its options, you'll see. – Lightness Races in Orbit Feb 25 '19 at 00:24
  • @Lightness Races in Orbit I thank you for your response, but what you said is same thing. Whether or not the terminal decides to send the buffer, at the end of the day, read did not return. –  Feb 25 '19 at 00:40
  • 2
    @JaveneCPPMcGowan It is not at all the same thing, and it has a _massive_ consequence on the set of ways you can "fix" it, _if_ the sending terminal is withholding data pending newline. If being the operative word. – Lightness Races in Orbit Feb 25 '19 at 00:44
  • @Lightness Races I did manage to do some more research. When you have been coding all day and night you get too tired so forgive me if I ask a lazy question. Man7.org is my go to for Linux, where I read fcntl and termios docs. There are canonical and non canonical terminal behaviour. I need line editing behaviour in most cases but still want an immediate return upon buffer size limit. But it seems that Linux terminal won't give you more than 4096 bytes anyhow, so I will just use that for my buffer size. –  Feb 25 '19 at 00:48
  • 1
    Fortunately, there are [platform-specific and sometimes unreliable] ways to get some way towards that goal, which are mentioned in the dupe. Ultimately though that sort of fine control is generally required only for graphical-style applications, for which nowadays we have, well, graphics. – Lightness Races in Orbit Feb 25 '19 at 00:51
  • @Lightness Races in Orbit, you marked my question as duplicate but I don't see a link to the questions that are similar. I just want to edit my question or remove it in case. –  Feb 25 '19 at 01:00
  • 1
    It's right there, in a big banner, at the top of the question. – Lightness Races in Orbit Feb 25 '19 at 01:04
  • @Lightness Races. Yep that is the kind of application I am trying to make. I was comfortable making graphical applications on my desktop with SFML and DirectX and OpenGL, when my desktop died. Now I am stuck practicing on my android, via CxxDroid and C4Droid. I am trying to make couple serious application, one being an accounts software, and I want nicer output than usual. On a sidenote, C4Droid is dope! You can write your code in CPP and export an installable apk. That is definitely good for business! –  Feb 25 '19 at 01:09
  • Accounts software that runs on text-based, line-based console interfaces should be relegated to the annals of history back in 1970 where they belong. Although sadly many organisations still do use legacy line-based software. – Lightness Races in Orbit Feb 25 '19 at 01:14
  • I also wanted to add that I am amazed by the graphical ability of the terminal. Thought it was black and white and boring, but you can change color of text, texts can have a flavour of colors, cursor can move, etc etc. –  Feb 25 '19 at 01:14
  • Well as I said I am stuck with limited technology now. Even though C4Droid has an SDL plugin, it is crashing. But I think the main thing is the capability of the software. And I feel that with ANSI Escape strings, and my html console concept, I can produce an attractive enough display. Imagine seeing div sections, tables, underlines, animated actions, input box, cursor only displays in input box, pop up menu, folder and file seek prompt. This is going to be nice. When am done I send you the apk! –  Feb 25 '19 at 01:21

1 Answers1

-1

So, the default behavior of a Linux terminal is line buffered. Something like this answer could be adapted to read one character at a time (if that is what you want).

To answer your question about getting the other 10 bytes, if you do another read, it will return the rest of those bytes. The following example demonstrates multiple sequential reads. If you enter more than 10 characters at the prompt, the second read will occur without blocking and return characters starting at 10 and up to 19. Characters beyond the 0-based index of 19 will not be printed.

#include <unistd.h>
#include <stdio.h>

int main(int argc, char** argv)
{
  int read1Count = 0;
  int read2Count = 0;
  char pBuffer[20];
  printf("Provide input: ");
  // flush stdout because buffering...
  fflush(NULL)
  read1Count = read(1, pBuffer, 10);

  // flush stdout because buffering...
  fflush(NULL)
  printf("Provide input: ");
  read2Count = read(1, pBuffer + 10, 10);

  printf("\nRead 1: '");
  if (read1Count < 0)
  {
    perror("Error on first read");
  }

  for (int i = 0; i < read1Count; i++)
  {
    printf("%c", pBuffer[i]);
  }

  printf("'\nRead 2: '");
  if (read2Count < 0)
  {
    perror("Error on second read");
  }

  for (int i = 0; i< read2Count; i++)
  {
    // We started the second read at pBuffer[10]
    printf("%c", pBuffer[i + 10]);
  }

  printf("'\n");
}

Compiling and running this I see this

Provide input: 12345678910 Provide input: Read 1: '1234567891' Read 2: '0 '

Jonathon K
  • 339
  • 2
  • 6
  • Not necessarily. Never read without storing the result into a variable. You have to test it two ways for error and end of steam, and hen in the default case use it as a count. – user207421 Feb 25 '19 at 00:16
  • The default behaviour of the terminal providing the bytes is line buffered. Not of `read`. `read` is not buffered at all. – Lightness Races in Orbit Feb 25 '19 at 00:23
  • 1
    Your example is syntactically invalid and ignores the return value of `read` – Lightness Races in Orbit Feb 25 '19 at 00:24
  • My example was simply to illustrate that multiple reads can be performed if the input is longer than the count provided to read – Jonathon K Feb 25 '19 at 00:52
  • @Jonathon thank you for putting your life on the line to help me. That is why I implore you to edit your answer to keep Admin happy. For example read isn't line buffered and C functions cannot overload, read only takes 3 arguments. But I must say I tried a similar example and I didn't get the rest of the input. –  Feb 25 '19 at 00:54
  • @Lightness Races in Orbit, does the terminal have a buffer, or is it just a cache? –  Feb 25 '19 at 00:55
  • @Jonathon k I just wanted to notify you that I look at your link, which is a link that I saw before, and was a huge help for me. –  Feb 25 '19 at 00:58
  • 1
    _"thank you for putting your life on the line to help me. That is why I implore you to edit your answer to keep Admin happy"_ No need for that. The comments section is specifically provided for critiquing answers, so that we keep things factually accurate. It's not personal. – Lightness Races in Orbit Feb 25 '19 at 00:58
  • 1
    @JaveneCPPMcGowan Yes, the terminal has a buffer. Not sure where a cache would come into it. – Lightness Races in Orbit Feb 25 '19 at 00:58
  • OK. As long as it OK. –  Feb 25 '19 at 01:02
  • @Lightness Races well what I read mentioned cache couple times. If the terminal has a buffer how do you access it. Even though I hear system calls are a bit slow. –  Feb 25 '19 at 01:25
  • 1
    You don't. The terminal could be on the other side of the world, or in space. That's the whole point. – Lightness Races in Orbit Feb 25 '19 at 01:25
  • @JaveneCPPMcGowan I updated the example to fully demonstrate two subsequent calls to read. Would you be willing to do a sanity check on me and tell me if it does not behave the same for you? – Jonathon K Feb 25 '19 at 14:46
  • @Jonathon K This is why I am afraid of C/C++. I ran your example and got the behaviour documented at Man7.org. So I am very confused why I didn't get that behaviour on the example I initially tried. Any how thank you again. –  Feb 25 '19 at 16:45
  • I am also confused as to why printf won't flush until flush is explicitly called. –  Feb 25 '19 at 16:47
  • @JaveneCPPMcGowan I used flush to ensure that the input and output were on the same line see https://stackoverflow.com/a/1716621/8723329 – Jonathon K Feb 26 '19 at 14:50