[GiNaC-list] Making ginsh interactive when the input is not a TTY

Vitaly Magerya vmagerya at gmail.com
Mon Jun 12 10:51:20 CEST 2023


Hi, all. I've been trying to use ginsh as a subprocess: send some
input to it, have it evaluate it, read the result back, repeat.
I've found that this is impossible: in ginsh/ginsh_lexer.lpp:161
if yy_is_interactive (=isatty(0)) is false, ginsh uses fread()
to read the input, which means it will not stop after end of
the line -- it will instead wait until the whole buffer is
filled, and will only proceed to parse and evaluate afterwards.
This means I can not send "1+2\n" and expect an answer,
ginsh will wait for more input. This of course is unlike the
interactive mode (yy_is_interactive == 1), where the input is
read character-by-character until the end of line.

So, basically, I'd like ginsh to use the interactive(-ish) mode
even when the input stream is not a TTY.

Now, just forcing yy_is_interactive to 1 will work, but is not
a good solution: the interactive mode prints the prompt after
each line, so using it when the input stream is not a TTY will
break backward compatibility. Instead, something like this will
work for me:

diff --git a/ginsh/ginsh_lexer.lpp b/ginsh/ginsh_lexer.lpp
index 8692b1ac..a8d571dd 100644
--- a/ginsh/ginsh_lexer.lpp
+++ b/ginsh/ginsh_lexer.lpp
@@ -203,9 +203,16 @@ static int ginsh_input(char *buf, int max_size)
                        YY_FATAL_ERROR("input in flex scanner failed");
                result = n;
 #endif
-       } else if (((result = fread(buf, 1, max_size, yyin)) == 0) &&
ferror(yyin))
-               YY_FATAL_ERROR("input in flex scanner failed");
-
+       } else {
+               int c = '*', n;
+               for (n = 0; n < max_size && (c = getc(yyin)) != EOF &&
c != '\n'; ++n)
+                       buf[n] = (char)c;
+               if (c == '\n')
+                       buf[n++] = (char)c;
+               if (c == EOF && ferror(yyin))
+                       YY_FATAL_ERROR("input in flex scanner failed");
+               result = n;
+       }
        return result;
 }

This will preserve backward compatibility.

There is however a concern that such a change will affect
the parsing performance, so I've run tests: when evaluating
some of my multi-MB expression files with mixed arithmetic,
there is no statistically visible performance difference. For
a synthetic test of a product of 10^6 of single-digit numbers
with 6 white-space characters per digit per -- no change. For a
sum of 10^6 single-digit integers with 6 spaces per integer I
see a 9% runtime regression; if the whitespace is removed, the
regression disappears. In short, I think the performance impact
in practice is zero.

Can I ask for this change to be applied?


More information about the GiNaC-list mailing list