0

I'm trying to make a C program to select options. It works if I run it this way:

./select choice{1..5}
☐ choice1  ☐ choice3  ☐ choice5
☐ choice2  ☐ choice4

# outputs "choice1 choice2" on stdout

But if I run it between backticks, it's a hell

`./select choice{1..5}` > choices.txt
☐ choice1☐ choice2☐ choice3☐ choice4☐ choice5

# Write "choice1 choice2" in `choices.txt`

I need to be able to retrieve selected options. That is why I've done all my outputs to a file I've opened with

int tty = open("/dev/tty", O_RDWR);
/* Do my program using outputs on fd `tty` */
printf("%s\n", get_results());

I think this is related with the use of tgoto in my code, to move the writing cursor on the screen.

if ((cm = tgetstr("cm", NULL)) == NULL)
    return (-1);
tputs(tgoto(cm, x, y), fd, &my_putchar);
return (0);

I've seen that using isatty(1) returns 0 when executed between backticks, and 1 if executed directly... So, is there a way for me to move the cursor and keep my formating in both situations?

Thank you for your time

  • 1
    Is it just me, or the question is absolutely unclear? How the invocation of the compiled binary in the shell related to the code itself? – Eugene Sh. Jun 23 '17 at 13:57
  • Because it changes somehow a context, that changes the behaviour of the program. It then outputs differently, which is problematic for me. – Alexandre Germain Jun 23 '17 at 14:00
  • It doesn't change the behavior of the program. The only thing that is changed is the way you output. You filter it through whatever the shell is doing with it when you assign it to variable and then `echo`. – Eugene Sh. Jun 23 '17 at 14:01
  • Okay, in fact, the use case I showed between backticks was ambiguous, I fix it – Alexandre Germain Jun 23 '17 at 14:04
  • `tputs()` will just output an escape sequence (a sequence of characters starting with an escape character) and your terminal interprets this by moving the cursor. Of course this won't work as expected when you capture the output yourself. If you need a plain text containing your structure, you have to find a way to generate it without "cursor movements". –  Jun 23 '17 at 14:21
  • Okay, so this isn't possible at all (as I thought). Thank you for the confirmation – Alexandre Germain Jun 23 '17 at 14:26
  • Perhaps ordinary stdio (printf etc) in conjunction with [ansi escape codes](https://en.wikipedia.org/wiki/ANSI_escape_code) might help? – Aconcagua Jun 23 '17 at 14:41
  • I don't think it would work. Last time I tried, it just poluted my stdout. I need stdout to only contains my choices at the end of the program. – Alexandre Germain Jun 23 '17 at 14:47
  • You could output to standard error, similarly to how the `dialog` program is used: `dialog --no-tags --checklist "Checklist" 0 0 0 choice1 "Choice 1" off choice2 "Choice 2" off choice3 "Choice 3" off choice4 "Choice 4" off choice5 "Choice 5" off 2> choices.txt`. – Ian Abbott Jun 23 '17 at 15:36
  • Curses programs write to standard output. You want to capture the standard output of your program in a shell variable. This is a problem. You'd have to do quite a lot of work to rig things so they don't break. Curses programs and running in shell scripts are almost contradictory choices. Don't try running `vim` in backticks, for example. – Jonathan Leffler Jun 23 '17 at 15:46
  • Further to what I wrote above, `dialog` isn't run in back ticks -- for the reasons stated by @JonathanLeffler. That's why it outputs the results to standard error by default (although you can specify a different file descriptor for the results). – Ian Abbott Jun 23 '17 at 15:49
  • But I have to find a workaround: I must be able to handle execution between backticks, keeping a working interface – Alexandre Germain Jun 23 '17 at 16:21

1 Answers1

0

The fragment of code shown in the question is using the termcap interface (not curses). It uses

tputs(tgoto(cm, x, y), fd, &my_putchar);

where my_putchar is likely writing to the standard output, like the rest of the program (using printf). If the program were altered to write all of its screen output to the standard error, then at the end it could write its result to the standard output, simplifying scripting.

There is no need to open /dev/tty; rather, replacing

printf("choice%d", n);

by

fprintf(stderr, "choice%d", n);

and of course changing my_putchar to something like

int my_putchar(int c) { return fputc(c, stderr); }

is the way to go.

If this were a curses application, one would change the output streams using newterm rather than initscr. dialog uses newterm, of course.

Thomas Dickey
  • 51,086
  • 7
  • 70
  • 105