@@ -190,6 +190,61 @@ jobs:
190190 grep kal_random syms.txt; exit 1; }
191191 echo " ok kal_random_fill is weak, kal_time_sleep is strong"
192192
193+ # ⭐⭐ ASKING WHETHER A STREAM IS A TERMINAL GETS THE RIGHT ANSWER.
194+ #
195+ # musl's `isatty' asks with TIOCGWINSZ; this port answered only TCGETS,
196+ # so every `isatty' returned 0 — for a real terminal as readily as for a
197+ # pipe. Nothing failed: `std::print' simply never took its terminal path,
198+ # and a program deciding on colour or on line buffering decided wrongly
199+ # and in silence.
200+ #
201+ # ⭐ THE CRITERION IS A RELATION, NOT A VALUE. `isatty` under a pipe and
202+ # under a pseudo-terminal must DIFFER, and must differ the same way the
203+ # system's own C library does. A test asserting "0 in a pipe" alone would
204+ # have passed throughout the defect.
205+ - name : Asking whether a stream is a terminal is answered, not refused
206+ if : runner.os == 'Linux' && matrix.target == ''
207+ run : |
208+ d="$(mktemp -d)"; mkdir -p "$d/src"
209+ cat > "$d/mcpp.toml" <<TOML
210+ [package]
211+ name = "isattyprobe"
212+ version = "0.1.0"
213+
214+ [dependencies]
215+ openkal-musl = { path = "$PWD" }
216+
217+ [targets.isattyprobe]
218+ kind = "bin"
219+ main = "src/main.c"
220+
221+ [build]
222+ cxx_runtime = "host-coupled"
223+ TOML
224+ sed -i 's/^ //' "$d/mcpp.toml"
225+ printf '#include <unistd.h>\n#include <stdio.h>\nint main(void){ printf("%%d\\n", isatty(1)); return 0; }\n' > "$d/src/main.c"
226+ ( cd "$d" && "$MCPP" build --toolchain '${{ matrix.toolchain }}' )
227+ bin="$(find "$d/target" -name isattyprobe -type f | head -1)"
228+ test -n "$bin" || { echo "::error::the probe did not build"; exit 1; }
229+
230+ # The control: the system's own C library, through the same harness.
231+ # Without it a `script` that fails to allocate a pty would make the
232+ # port look broken.
233+ printf '#include <unistd.h>\n#include <stdio.h>\nint main(void){ printf("%%d\\n", isatty(1)); return 0; }\n' > "$d/ctrl.c"
234+ cc "$d/ctrl.c" -o "$d/ctrl"
235+ ctrl_pipe="$("$d/ctrl" | cat | tr -d '\r')"
236+ ctrl_tty="$(script -qec "$d/ctrl" /dev/null | tr -d '\r' | head -1)"
237+ [ "$ctrl_pipe" = 0 ] && [ "$ctrl_tty" = 1 ] \
238+ || { echo "::error::the harness cannot tell a pty from a pipe (control gave $ctrl_pipe/$ctrl_tty) — this check would prove nothing"
239+ exit 1; }
240+
241+ port_pipe="$("$bin" | cat | tr -d '\r')"
242+ port_tty="$(script -qec "$bin" /dev/null | tr -d '\r' | head -1)"
243+ echo " control: pipe=$ctrl_pipe tty=$ctrl_tty port: pipe=$port_pipe tty=$port_tty"
244+ [ "$port_pipe" = "$ctrl_pipe" ] && [ "$port_tty" = "$ctrl_tty" ] \
245+ || { echo "::error::isatty over this port disagrees with the system's own C library"; exit 1; }
246+ echo " ok isatty answers the same as the system's own C library"
247+
193248 # ⭐⭐ THE INTERNAL OVERLAY STOPS AT THIS PACKAGE'S BOUNDARY.
194249 #
195250 # musl reaches its own declarations through `src/include`, whose headers
0 commit comments