www.delorie.com/archives/browse.cgi   search  
Mail Archives: djgpp-workers/1999/04/06/05:26:11

Message-ID: <B0FEA00E82A7D1118BFB00A0CC990278213235@ARGON>
From: Michel de Ruiter <Michel AT smr DOT nl>
To: "'DJGPP workers'" <djgpp-workers AT delorie DOT com>
Subject: setmode problem
Date: Tue, 6 Apr 1999 11:27:45 +0200
X-Mailer: Internet Mail Service (5.5.2448.0)
Reply-To: djgpp-workers AT delorie DOT com

Let me first note that I run MS-DOS 7.10 (Win98 without GUI). And that
this is quite a long message.

I noticed a problem with setting stdin (or stdout) to binary, if stdin
is connected to the terminal. It happened for instance with `zip':

C> zip > temp

A minimal C program having this problem is:

#include <stdio.h>
#include <io.h>
#include <fcntl.h>

int main(void)
{
  setmode(0, O_BINARY);	/* From (libc)setmode */
  return getchar();
}

I know some programs first check isatty(stdin), but someone might want
to be able to type binary data (C-z, C-c, C-m and such) on the
terminal.

The computer freezes when getchar (or any other DOS input function) is
called, C-BREAK does not work, only C-M-DEL. Using 1 (stdout) or 2
(stderr) instead of 0 (stdin) shows exactly the same behaviour, as DOS
just changes the mode of the same `console' if no redirection is used.

I dug all the inner details out of libc, but at first it turned out to
be a problem in DOS itself. After translating things into assembly, I
was convinced it was DOS' fault. It just showed a blinking cursor
waiting for input, but reacted on nothing but C-M-DEL.

A bit more digging (also under the Win98 GUI, which has the same
problem), showed that it might be correct behaviour. The computer did
not `hang', but just waited for 512 key presses (the default buffer
size `_fillsize' in DJGPP).

Those keypresses were not echoed, and C-BREAK was not handled in a
special way (except that it emptied the input buffer, it seems).
Although libc.inf says "`Ctrl-Break' will still cause `SIGINT'", this
is not very useful as it is not delivered until DOS returns...

All problems disappeared when I set stdin to _IONBF (not buffered)
instead of _IOLBF (line buffered). At least, just one key press is
enough to let the C-BREAK through. Nothing is echoed, but should it?

So, to make a long story short, I would like to suggest the following
patch (please correct me if I am wrong!):

--- src/libc/dos/io/setmode.old	Sun Apr  4 20:22:40 1999
+++ src/libc/dos/io/setmode.c	Sun Apr  4 20:33:16 1999
@@ -6,6 +6,7 @@
 #include <errno.h>
 #include <fcntl.h>
 #include <io.h>
+#include <stdio.h>
 
 #include <libc/dosio.h>
 #include <libc/ttyprvt.h>
@@ -47,6 +48,13 @@
     {
       errno = __doserr_to_errno(regs.x.ax);
       return -1;
+    }
+    if ((newmode & 0x83) == 0x83 && isatty(0)) {	/* Indicates console
*/
+      stdin->_flag &= ~(_IOFBF|_IOLBF|_IONBF);
+      if (newmode & 0x20)
+	stdin->_flag |= _IONBF;
+      else
+	stdin->_flag |= _IOLBF;
     }
     if (handle == 0)
       __djgpp_set_ctrl_c(!(mode & O_BINARY));

This way, a user can type real binary data on the terminal and still
interrupt with C-BREAK, followed by another key. One thing that I do
not understand is why typing C-@ still prints "^C\r\n" in this mode,
most of the time to stdout. I think it is DOS as I can not find
anything in libc...

Hope this helps.

--
*Groeten, Michel* _http://www.cs.vu.nl/~mdruiter_
   ____________ 
   \  /====\  /   "You know, Beavis, you need things that suck,
    \/      \/     to have things that are cool", Butt-Head.

- Raw text -


  webmaster     delorie software   privacy  
  Copyright © 2019   by DJ Delorie     Updated Jul 2019