setmode(fileno(stdout), O_BINARY);
First, is there an equivalent to this in ANSI C?
Second, shouldn't I be able to do the exactly same as the setmode() line
with ANSI C's freopen()? I.e., if I freopen() stdout as "wb", shouldn't
this be functionally identical?
Third, if there isn't an ANSI C equivalent, is there a way to
surrepticiously do the equivalent to that setmode line in DJGPP - which uses
some combination of ANSI C functions? E.g., freopen() calls open() which
then calls setmode(). So, shouldn't there be some way to do the same the
setmode() line above using freopen()?
So far, I've tried the following with freopen():
/* fails, captures extra CR when stdout redirected to file */
freopen(NULL,"wb",stdout);
/* fails, sends to screen, but won't redirect from screen to file */
freopen("CON","wb",stdout);
/* fails, sends to screen, but won't redirect from screen to file*/
freopen("/dev/tty","wb",stdout);
/* fails, sends to file CONOUT$, not to screen */
freopen("CONOUT$","wb",stdout);
/* fails, sends to file asdf, not to screen */
freopen("asdf","wb",stdout);
How do I get both redirection capability and binary output with stdout when
using ANSI C functions such as freopen()?...
Rod Pemberton
No. ANSI C says that everything about stdin and stdout is
implementation-defined, IIRC.
> Second, shouldn't I be able to do the exactly same as the setmode() line
> with ANSI C's freopen()?
I don't think this is possible (but I didn't try hard enough, so I
could be wrong). Redirecting stdout explicitly affects file
descriptor 1 which was inherited from the parent shell, and `freopen'
closes that descriptor. The new FILE object reuses the same file
descriptor 1, but the redirection is lost when the original descriptor
is closed, because the redirection is maintained by the OS, which is
told that the file is closed.
> How do I get both redirection capability and binary output with stdout when
> using ANSI C functions such as freopen()?...
Why isn't using `setmode' good enough? That's what all applications
that need this do. Just be careful not to switch stdout to binary if
it is not redirected, since switching the console device to binary has
some unpleasant side effects in DJGPP: e.g., SIGINT is not produced by
Ctrl-C. So I'd suggest
if (!isatty (fileno (stdout)))
setmode (fileno (stdout), O_BINARY);
That was why I tried reopening the console device, "CON", as the redirected
stdout in one of the examples.
> The new FILE object reuses the same file
> descriptor 1, but the redirection is lost when the original descriptor
> is closed, because the redirection is maintained by the OS, which is
> told that the file is closed.
...
> redirection is maintained by the OS
Time for me to try to find out more about this, I guess... Of course, the
question becomes: Why would freopen() close or attempt to close stdin,
stdout, stderr? I haven't looked at what the C spec. says here, but I'm
fairly sure Harbison & Steele 3rd ed. says file closing errors in freopen()
are ignored. If correct, that would allow file close errors in freopen() by
design or intentionally for stdin, stdout, stderr.
> Why isn't using `setmode' good enough? That's what all applications
> that need this do.
It is. It works. I use it enough. But, I was really wanting ANSI C only
in this case. And, when I thought about it, I saw no reason why freopen()
shouldn't work the same way... Then, I skimmed the code and saw that
freopen() eventually called setmode(). That opened up the possibility that
freopen() could or might work the same way, or have a some method available
allowing it to work like setmode. I haven't looked at it thoroughly, but I
do recall it clearing O_BINARY, although you indicated above that really
isn't the issue.
> Just be careful not to switch stdout to binary if
> it is not redirected,
Actually, I've found switching the console to binary to be quite useful.
> since switching the console device to binary has
> some unpleasant side effects in DJGPP: e.g., SIGINT is not produced by
> Ctrl-C.
Interesting... Does this block Ctrl-C better than signal() to SIG_IGN on
SIGINT, SIGQUIT, SIGABRT inconjunction with setcbrk()? This came up a while
ago in comp.os.msdos.programmer. Unfortunately, it seems he never posted to
comp.os.msdos.djgpp. My solution apparently didn't work for him. Later, I
found out that it worked well for some of my applications, but it doesn't
work well for every application... Some still leak large numbers of
ctrl-c's.
http://groups.google.com/group/comp.os.msdos.programmer/browse_thread/thread/98a6c66a3aa291ae/c83696ed4bae0310?hl=en
> if (!isatty (fileno (stdout)))
> setmode (fileno (stdout), O_BINARY);
Hmm... Time to look at isatty().
Rod Pemberton
The main use-case for `freopen' is not to change the binary/text mode
of the file I/O, but to redirect I/O to _another_ file. If it doesn't
close the original one, it will either leak resources or unnecessarily
hit the max available handle limit (or both).
> I haven't looked at what the C spec. says here, but I'm
> fairly sure Harbison & Steele 3rd ed. says file closing errors in freopen()
> are ignored.
That's what the DJGPP library implementation of `freopen' does, please
take a look at the sources.
> If correct, that would allow file close errors in freopen() by
> design or intentionally for stdin, stdout, stderr.
Sorry, I'm not following: how would ignoring close errors help in the
matter at hand, or is relevant to what we are discussing?
> > Why isn't using `setmode' good enough? That's what all applications
> > that need this do.
>
> It is. It works. I use it enough. But, I was really wanting ANSI C only
> in this case.
ANSI C leaves the semantics of the whole binary/text issue as
implementation defined.
> > since switching the console device to binary has
> > some unpleasant side effects in DJGPP: e.g., SIGINT is not produced by
> > Ctrl-C.
>
> Interesting... Does this block Ctrl-C better than signal() to SIG_IGN on
> SIGINT, SIGQUIT, SIGABRT inconjunction with setcbrk()?
Yes, better: using SIG_IGN does not prevent the entire chain of events
triggered by Ctrl-C, whereby we reset the DJGPP application's data
segment to the null page, cause the app to GP Fault when it touches
any of its data, then catch the exception and just return without
doing anything if we see that the signal handler is SIG_IGN.
What `setmode' does when you set file descriptor 0 (stdin) to binary
mode is call `__djgpp_set_ctrl_c', which prevents the above chain of
events in the first place; instead, Ctrl-C is delivered to the
application as a normal character. This is meant for applications
that want to get all the raw input characters verbatim, and do any
processing themselves. Emacs is one example.
Note that with the latest libc, switching stdout to binary should not
have this effect, but I'd still avoid that.
> This came up a while
> ago in comp.os.msdos.programmer. Unfortunately, it seems he never posted to
> comp.os.msdos.djgpp. My solution apparently didn't work for him. Later, I
> found out that it worked well for some of my applications, but it doesn't
> work well for every application... Some still leak large numbers of
> ctrl-c's.
> http://groups.google.com/group/comp.os.msdos.programmer/browse_thread/thread/98a6c66a3aa291ae/c83696ed4bae0310?hl=en
Using `__djgpp_set_ctrl_c' is the right solution to that problem.
Is it? No offense intended, but that seems like half an implementation to
me. freopen() is supposed to implement all functionality of fopen(), which
includes opening the redirected-to-file as binary.
> but to redirect I/O to _another_ file.
Which, of course, could be the original file or character device acting like
a file, i.e., CON since there is no C restriction preventing reopening the
same file as itself but using a different mode. Again, freopen() is
supposed to implement all functionality of fopen(), which includes opening
the redirected-to-file as binary. Therefore, if I reopen stdin as binary
redirected to a file or character device which functions as stdin, e.g.,
CON, and stdin isn't actually closed by the implementation of freopen(),
since it doesn't have to be since freopen() ignores close errors, and isn't
closed by DOS, then I'd expect a mode change.
> If it doesn't
> close the original one, it will either leak resources or unnecessarily
> hit the max available handle limit (or both).
Does DOS actually close stdin, stdout, stderr, when one attempts to close
them?... My gut says no. In which case, all DJGPP is doing is forfeiting
OS redirection when it doesn't have to.
> > If correct, that would allow file close errors in freopen() by
> > design or intentionally for stdin, stdout, stderr.
>
> Sorry, I'm not following: how would ignoring close errors help in the
> matter at hand, or is relevant to what we are discussing?
>
If ignoring close errors is legitimate, then there is no need to attempt to
close stdin, stdout, or stderr. There is only a need to attempt to close
handles other than those three. In which case, freopen() with a "wb" on
stdin could also setmode O_BINARY on stdin without loosing redirection on
stdin since stdin was never actually closed.
Rod Pemberton
I said _main_ use-case, not _only_ use-case.
> freopen() is supposed to implement all functionality of fopen(), which
> includes opening the redirected-to-file as binary.
And it does, as long as you know the name of that file.
> > but to redirect I/O to _another_ file.
>
> Which, of course, could be the original file or character device acting like
> a file, i.e., CON since there is no C restriction preventing reopening the
> same file as itself but using a different mode.
Which worked for you as well, except CON is not an alias for standard
output unit, but a name of the terminal device. Calling `freopen'
for it sends output to the device, as you've discovered, not to the
(potentially redirected) standard output.
> Again, freopen() is
> supposed to implement all functionality of fopen(), which includes opening
> the redirected-to-file as binary. Therefore, if I reopen stdin as binary
> redirected to a file or character device which functions as stdin, e.g.,
> CON, and stdin isn't actually closed by the implementation of freopen(),
> since it doesn't have to be since freopen() ignores close errors, and isn't
> closed by DOS, then I'd expect a mode change.
There is no such thing as ``character device that functions as
stdin'', as far as DOS is considered. CON is just a file name, devoid
of any special meaning, for the part of DOS that deals with files.
(CON has special meaning only for the console device driver that
intercepts all file I/O and draws glyphs instead of writing data to
disk.) It is true that an interactive shell has its stdin connected
to CON, for obvious usability reasons, but that special function of
CON and stdin is something DOS does not care when it handles file I/O.
Moreover, each program running on the system has its own private stdin
handle connected to CON. Even they all reference the same device,
they are independent--which is a Good Thing, because this is how
program A can have its stdin in text mode while program B, which could
be a child process of A, can have its stdin in binary mode.
This all happens because DOS maintains handle-to-file association in a
table where each handle gets its own independent entry, even if it
refers to the same file/device as some other handle, and each process
gets its own entry even for standard handles 0, 1, and 2. Each entry
in the file handle table includes information about a file which is
open on that handle; when you close the handle, that information is
purged.
Redirection simply boils down to recording a different file as being
associated with a handle. But the associated file name is not
accessible by handle, at least not by documented DOS system calls.
> Does DOS actually close stdin, stdout, stderr, when one attempts to close
> them?...
Yes, certainly. Again, there's no special meaning DOS (or any other
OS, btw) assigns to these handles. Since their associated files or
devices are per process, there cannot be any harm in actually closing
them, except for the process on whose behalf they are closed, because
neither other processes nor the system itself are affected.
> > Sorry, I'm not following: how would ignoring close errors help in the
> > matter at hand, or is relevant to what we are discussing?
> >
>
> If ignoring close errors is legitimate, then there is no need to attempt to
> close stdin, stdout, or stderr.
As I explained, if you don't do that, you will leak descriptors and/or
get complaints from users whose programs don't need the 3 standard
ones and close them because they want to open all of the 255 available
handles to data files.
Also, if you don't close a handle, DOS does not flush its buffers, so
you can end up with unsaved data when users expect it to be safely on
disk, since they've closed the file.
Then, what is DJGPP's filename to use for stdout as the first parameter of
freopen()? NULL? I tried that too. It failed. It continued to output to
stdout in text mode.
After looking at the spec., I'm asking how to go about using freopen() to do
what is mentioned in ISO C 7.19.5.4 sub 3:
"If filename is a NULL pointer, the freopen function attempts to change the
mode of the stream to that specified by mode, as if the name of the file
currently associated with the stream had been used. It is
implementation-defined which changes of mode are permitted (if any), and
under what circumstances."
How do I change the mode of stdout to binary, just as in the setmode call,
by using freopen()?... NULL doesn't work. Is this functionality
implemented?
Previously,
> > First, is there an equivalent to this in ANSI C?
>
> No. ANSI C says that everything about stdin and stdout is
> implementation-defined, IIRC.
I think the correct answer to that question is: Yes. ANSI C specifies an
equivalent. The ANSI C equivalent is to use NULL as the first parameter to
freopen(). Sub 3 says freopen() is _required_ to *attempt* to change the
mode regardless of whether it is supported or not. Which modes are actually
*permitted* by an implementation are implementation-defined. I already know
that it seems that it isn't implemented. It is implemented somehow, by some
method, using freopen() that I'm not recognizing? Given that the setmode()
to binary for stdout for works for DJGPP, I don't understand why this
wouldn't be implemented as part of freopen() too since it is mentioned in
the spec....
Rod Pemberton
There is none, sorry.
> After looking at the spec., I'm asking how to go about using freopen() to do
> what is mentioned in ISO C 7.19.5.4 sub 3:
>
> "If filename is a NULL pointer, the freopen function attempts to change the
> mode of the stream to that specified by mode, as if the name of the file
> currently associated with the stream had been used. It is
> implementation-defined which changes of mode are permitted (if any), and
> under what circumstances."
This requirement is new with C99, it wasn't there in C89. DJGPP does
not fully support C99 yet, not even with (the unreleased) v2.04.
Patches are welcome, of course.
> How do I change the mode of stdout to binary, just as in the setmode call,
> by using freopen()?... NULL doesn't work. Is this functionality
> implemented?
No. NULL is invalid value for that argument, as C89 says, and DJGPP's
implementation fails when you do that.
Unfortunately, I suspect that the "correct" fix for the problem is to
convert DJGPP to support a single stream mode exclusively, like many POSIX
environments having a binary mode but no text mode. E.g., for DJGPP, I'd
consider:
1) eliminating text streams from DJGPP by implementing all streams as
binary, e.g., setting stdin, stdout, stderr to binary via setmode() method
upon startup
2) converting to a single character linefeed, e.g., LF only instead of CRLF,
for simpler code support of binary streams
3) installing a RM int 0x29 routine as part of execution startup which
will convert LF's to CRLF's for display, but not for file redirection
I'm sure that is far beyond what you had in mind...
Rod Pemberton
Far beyond, because I don't see any need for this complexity. All
that's needed is a single call to `dup' or `dup2' to copy the existing
handle.