-1

I am trying to draw a black box on terminal at top left corner with stdin nonblocking mode turned on. The black box has size 10 cols and 5 rows. I am using the following code to draw it.

#include <sys/fcntl.h>
#include <unistd.h>
#include <wchar.h>

int main() {
    int flags = fcntl(STDIN_FILENO, F_GETFL, 0);
    fcntl(STDIN_FILENO, F_SETFL, flags | O_NONBLOCK);

    char s[] = "\e[1;1H\e[1;1H\e[38;5;0m\e[48;5;0m▀\e[38;5;0m\e[48;5;0m▀\e[38;5;0m\e[48;5;0m▀\e[38;5;0m\e[48;5;0m▀\e[38;5;0m\e[48;5;0m▀\e[38;5;0m\e[48;5;0m▀\e[38;5;0m\e[48;5;0m▀\e[38;5;0m\e[48;5;0m▀\e[38;5;0m\e[48;5;0m▀\e[38;5;0m\e[48;5;0m▀\e[E\e[38;5;0m\e[48;5;0m▀\e[38;5;0m\e[48;5;0m▀\e[38;5;0m\e[48;5;0m▀\e[38;5;0m\e[48;5;0m▀\e[38;5;0m\e[48;5;0m▀\e[38;5;0m\e[48;5;0m▀\e[38;5;0m\e[48;5;0m▀\e[38;5;0m\e[48;5;0m▀\e[38;5;0m\e[48;5;0m▀\e[38;5;0m\e[48;5;0m▀\e[E\e[38;5;0m\e[48;5;0m▀\e[38;5;0m\e[48;5;0m▀\e[38;5;0m\e[48;5;0m▀\e[38;5;0m\e[48;5;0m▀\e[38;5;0m\e[48;5;0m▀\e[38;5;0m\e[48;5;0m▀\e[38;5;0m\e[48;5;0m▀\e[38;5;0m\e[48;5;0m▀\e[38;5;0m\e[48;5;0m▀\e[38;5;0m\e[48;5;0m▀\e[E\e[38;5;0m\e[48;5;0m▀\e[38;5;0m\e[48;5;0m▀\e[38;5;0m\e[48;5;0m▀\e[38;5;0m\e[48;5;0m▀\e[38;5;0m\e[48;5;0m▀\e[38;5;0m\e[48;5;0m▀\e[38;5;0m\e[48;5;0m▀\e[38;5;0m\e[48;5;0m▀\e[38;5;0m\e[48;5;0m▀\e[38;5;0m\e[48;5;0m▀\e[E\e[38;5;0m\e[48;5;0m▀\e[38;5;0m\e[48;5;0m▀\e[38;5;0m\e[48;5;0m▀\e[38;5;0m\e[48;5;0m▀\e[38;5;0m\e[48;5;0m▀\e[38;5;0m\e[48;5;0m▀\e[38;5;0m\e[48;5;0m▀\e[38;5;0m\e[48;5;0m▀\e[38;5;0m\e[48;5;0m▀\e[38;5;0m\e[48;5;0m▀";
    // char s1[] = "\e[1;1H\e[1;1H▀▀▀▀▀▀▀▀▀▀\e[E▀▀▀▀▀▀▀▀▀▀\e[E▀▀▀▀▀▀▀▀▀▀\e[E▀▀▀▀▀▀▀▀▀▀\e[E▀▀▀▀▀▀▀▀▀▀\e[E";

    write(1, s, sizeof(s)-1);
    fflush(stdout);
    return 0;
}

However what I get is an incomplete box:

▀▀▀▀▀▀▀▀▀▀
▀▀▀▀▀▀▀▀▀▀
▀▀▀▀▀▀▀▀▀▀
▀▀▀▀▀▀▀▀▀▀
▀▀▀▀▀▀▀

The printed string is produced by inserting \e[38;5;0m\e[48;5;0m before each half block character.

What I tried didn't work are

  • using different shell
  • using different terminal emulators (Alacritty, Terminal.app, iTerm2)

What I tried that worked but not what I wanted

  • printing in blocking mode
  • remove code that changes color (\e[38;5;0m\e[48;5;0m)
  • changing half block character to normal printable ASCII character

Why is this and how can I fix it?

Austin
  • 9
  • 2
  • I get a black box on konsole. Could be your shell prompt is removing characters. What happens when you add a sleep before `return 0`. – KamilCuk Jul 21 '23 at 10:19
  • Still the same incomplete black box on alacritty. – Austin Jul 21 '23 at 10:39
  • So, did you check what `write` returns? Since it's non-blocking I think there's a higher probability that it writes fewer bytes than requested. Why don't you want to print in blocking mode? Sidenote: `\e` is not a standard escape sequence. `\033` would be ESC. – Ted Lyngmo Jul 21 '23 at 11:01
  • `write` returns 1024 and `s` as length 1075. Also I can't print the return value of `write` to stdout. I had to write it to a file. – Austin Jul 21 '23 at 11:08
  • Ok, then that's the explanation. You need to write the rest of the bytes until all 1075 have been written. – Ted Lyngmo Jul 21 '23 at 11:28

1 Answers1

1

So it turns out write is not writing all data to stdout. Use a while loop to write all data to stdout.

#include <sys/fcntl.h>
#include <unistd.h>
#include <wchar.h>

int main() {
    int flags = fcntl(STDIN_FILENO, F_GETFL, 0);
    fcntl(STDIN_FILENO, F_SETFL, flags | O_NONBLOCK);

    char s[] = "\e[1;1H\e[1;1H\e[38;5;0m\e[48;5;0m▀\e[38;5;0m\e[48;5;0m▀\e[38;5;0m\e[48;5;0m▀\e[38;5;0m\e[48;5;0m▀\e[38;5;0m\e[48;5;0m▀\e[38;5;0m\e[48;5;0m▀\e[38;5;0m\e[48;5;0m▀\e[38;5;0m\e[48;5;0m▀\e[38;5;0m\e[48;5;0m▀\e[38;5;0m\e[48;5;0m▀\e[E\e[38;5;0m\e[48;5;0m▀\e[38;5;0m\e[48;5;0m▀\e[38;5;0m\e[48;5;0m▀\e[38;5;0m\e[48;5;0m▀\e[38;5;0m\e[48;5;0m▀\e[38;5;0m\e[48;5;0m▀\e[38;5;0m\e[48;5;0m▀\e[38;5;0m\e[48;5;0m▀\e[38;5;0m\e[48;5;0m▀\e[38;5;0m\e[48;5;0m▀\e[E\e[38;5;0m\e[48;5;0m▀\e[38;5;0m\e[48;5;0m▀\e[38;5;0m\e[48;5;0m▀\e[38;5;0m\e[48;5;0m▀\e[38;5;0m\e[48;5;0m▀\e[38;5;0m\e[48;5;0m▀\e[38;5;0m\e[48;5;0m▀\e[38;5;0m\e[48;5;0m▀\e[38;5;0m\e[48;5;0m▀\e[38;5;0m\e[48;5;0m▀\e[E\e[38;5;0m\e[48;5;0m▀\e[38;5;0m\e[48;5;0m▀\e[38;5;0m\e[48;5;0m▀\e[38;5;0m\e[48;5;0m▀\e[38;5;0m\e[48;5;0m▀\e[38;5;0m\e[48;5;0m▀\e[38;5;0m\e[48;5;0m▀\e[38;5;0m\e[48;5;0m▀\e[38;5;0m\e[48;5;0m▀\e[38;5;0m\e[48;5;0m▀\e[E\e[38;5;0m\e[48;5;0m▀\e[38;5;0m\e[48;5;0m▀\e[38;5;0m\e[48;5;0m▀\e[38;5;0m\e[48;5;0m▀\e[38;5;0m\e[48;5;0m▀\e[38;5;0m\e[48;5;0m▀\e[38;5;0m\e[48;5;0m▀\e[38;5;0m\e[48;5;0m▀\e[38;5;0m\e[48;5;0m▀\e[38;5;0m\e[48;5;0m▀";
    // char s[] = "\e[1;1H\e[1;1H▀▀▀▀▀▀▀▀▀▀\e[E▀▀▀▀▀▀▀▀▀▀\e[E▀▀▀▀▀▀▀▀▀▀\e[E▀▀▀▀▀▀▀▀▀▀\e[E▀▀▀▀▀▀▀▀▀▀\e[E";

    int i = 0;
    while (sizeof(s) - i > 0) {
        int l = write(1, s + i, sizeof(s) - i);
        if (l == -1) {
            continue;
        }
        i += l;
    }

    return 0;
}
Austin
  • 9
  • 2
  • You should also check if `write` returns -1 meaning an error has occurred. For non-blocking writes, you should at least expect to get return values of `-1` with `errno` set to `EAGAIN` (or either `EAGAIN` or `EWOULDBLOCK` when writing to a socket). – Ian Abbott Jul 21 '23 at 12:30