From: scs@adam.mit.edu (Steve Summit)
Subject: Re: Curses to write to stderr, possible?
Summary: probably not
Keywords: stdio, freopen
Organization: none, at the moment
	<9227705.8627@mulga.cs.mu.OZ.AU> <1992Oct2.83859.1153@ms.uky.edu>
	<1414@pacsoft.com> <1992Oct3.005624.28680@netcom.com>
	<375@ulogic.UUCP> <1992Oct6.034638.29275@oucsace.cs.ohiou.edu>
Date: Tue, 6 Oct 1992 17:51:55 GMT

In article <1992Sep30.224314.17911@athena.mit.edu>, M. Saggaf (alsaggaf@athena.mit.edu) writes:
> I have a need to write a program that uses curses to write to stderr
> (since stdout is redirected to a device). Is that possible?

In this case, probably not.  Read on for some ideas that don't work:

In article <364@ulogic.UUCP>, Richard M. Hartman (hartman@ulogic.UUCP) writes:
> If you can isolate the curses stuff in subroutines you could
> always play games w/ the file pointers....
>
> 	FILE *old = stdout;
> 	stdout = stderr;
> 	....
> 	stdout = old;
> 
> (very important to restore stdout when you get done!)

, but in articles <9227705.8627@mulga.cs.mu.OZ.AU>,
<1992Oct2.83859.1153@ms.uky.edu>, and <1414@pacsoft.com>,
Fergus James HENDERSON (fjh@munta.cs.mu.OZ.AU),
Kenneth Herron (kherron@ms.uky.edu), and Mike Stefanik (mike@pacsoft.com)
correctly point out that stdin and stdout may not be directly reassigned.

The ANSI C Standard, X3.159-1989, section 4.9.1, page 126, lines
9-13 state that stderr, stdin, and stdout are "expressions of
type `pointer to FILE' that point to the FILE objects associated,
respectively, with the standard error, input, and output
streams."  Footnote 116 in section 4.9.5.4 on page 131 reiterates
that they "need not be modifiable lvalues to which the value
returned by the fopen function may be assigned."  Section 4.9.5.4
happens to be about the freopen function, which we turn to next:

In article <1992Oct3.005624.28680@netcom.com>, John Steele (jsteele@netcom.com) writes:
> True.  This is what freopen() is usally used for.

Indeed.  However, freopen will neither help M. Saggaf, who wanted
essentially to redirect stdout (for the purposes of curses only)
to whatever stream stderr pointed to (but freopen only lets you
redirect to a file), nor Richard M. Hartman, whose code fragment
wanted to be able to redirect stdout and then restore it, as he
admits and inquires in article <375@ulogic.UUCP>:
> Yeah, my suggestion has a portability problem -- anywhere that stdin
> and stdout are macros instead of FILE * variables you've got problems.
> 
> On the other hand freopen() only solves half the problem, redirecting
> stdout to where you want.  The other half, RESTORING it afterwards, has
> no portable solution that I am aware of.  Or even a common one.  At least
> my suggestion works where the stdin & stdout are variables.  Does anyone
> know how to "reconnect" stdin/stdout to their original sources after
> haveing been freopened()?

This is, as it happens, a Frequently Asked Question.
In article <1992Oct6.034638.29275@oucsace.cs.ohiou.edu>, Tom Swingle
(tswingle@oucsace.cs.ohiou.edu) comes up with one of the
frequent answers:

> Would there be any problem with using memcpy instead of assignments?  I got
> the following program to work...
> 
>   FILE *temp;
>   temp=(FILE *) malloc(sizeof(FILE));
>   memcpy((char *) temp,(char *) stdout,sizeof(FILE));
>   memcpy((char *) stdout,(char *) stderr,sizeof(FILE));
>   fputs("Hello there, this is stdout changed to be stderr\n",stdout);
>   memcpy((char *) stdout,(char *) temp,sizeof(FILE));
>   fputs("Hello there, this is stdout back to its old self again\n",stdout);
>
> ...I can't think of any problems that might arise by directly manipulating 
> them, it doesn't mean there aren't any.  Can anyone think of such problems?

This is indeed likely to work on some systems, although it is
more verbose than it has to be.  The invocations of memcpy are
actually implementing simple structure assignment, so the code
could be simplified and clarified by making the structure
assignments explicit (and also by letting the compiler allocate
the temporary FILE struct):

	FILE temp;
	temp = *stdout;
	*stdout = *stderr;
	fputs("Hello there, this is stdout changed to be stderr\n", stdout);
	*stdout = temp;
	fputs("Hello there, this is stdout back to its old self again\n",
								stdout);

This code happens to work on my system, too, and if you can
understand how it works you may think that it really ought to
work everywhere.  It will not, for two reasons.

First of all, and more generally, it is always risky to pry open
the black box surrounding a modular interface and peek inside --
in this case, by playing with the contents of FILE structs (even
though they are simply being copied, without interpretation).
We might paraphrase dmr and call this "unwarranted chumminess
with stdio internals."  Even if you can't think of a way for it
to break, skating on thin ice and mixing metaphors in this way
will get you into hot water eventually.

Secondly, and more specifically, some systems do not have a
single __iob array which holds the various FILE structs in use.
They have two parallel arrays, using gunky code like this:

	FILE	_iob[FOPEN_MAX];
	__FILE2	_iob2[FOPEN_MAX];

	_flsbuf(c, fp)
	int c;
	FILE *fp;
	{
	FILE *fp2 = &_iob2[fp - _iob];

, where _flsbuf is some internal routine which accepts a FILE *
and actually has to do something with it.  _flsbuf computes a
pointer to the slot in the parallel _iob2 array corresponding to
the slot in _iob pointed to by the "primary" FILE pointer fp.
For various reasons [note 1], some of the information the stdio
implementation needs is in the primary FILE struct (_iob), and
some of it is in the secondary __FILE2 struct (_iob2).

Therefore, whether or not you or I might have implemented stdio
using two parallel arrays, it is legal for another implementor to
do so (as long as all user-visible semantics are guaranteed to be
correct).  If it isn't obvious by now, user-level copying of the
FILE structs pointed to by FILE *'s (including stdout and stderr)
will hopelessly confuse a parallel array implementation, because
the corresponding entries in the secondary array will not be
swapped, and the implementation will end up trying to use, during
a single operation, some information for stdout and other
information for stderr.  (It might still just happen to work, but
I wouldn't bet the farm on it.)

Since some implementations have already been using this
technique, and since it (presumably) didn't seem to be worth
allowing users to play with the contents of FILE's, but since
some users are notoriously inclined to do such things anyway, and
to claim that they should be allowed to, and to point at language
in standards documents which they claim supports their position
(or at least to point at the absence of language which disallows
it), the ANSI C Standard states explicitly that

	The address of a FILE object used to control a stream may
	be significant; a copy of a FILE object may not
	necessarily serve in place of the original.
	[ANSI X3.159-1989 section 4.9.3, page 127, lines 35-36.]

Returning to M. Saggaf's original curses problem, I doubt that
there is a portable solution.  The redirection would have to be
both reversible (since it must apply only during curses calls; it
is stated that "stdout is redirected to a device," implying that
other stdio calls do print to stdout and should not be
re-redirected), and to another stream (not a file).  freopen
cannot do either of these things.

I would suggest that M. Saggaf try to rewrite the stdio calls
which are currently writing to stdout and thence to the device,
to instead write to some unique stream which can be managed
separately, leaving stdout free and clear for use by curses.

Finally, for those who missed it, the question of undoing an
freopen was just added to the comp.lang.c FAQ list:

  11.6:	Once I've used freopen, how can I get the original stdout (or
	stdin) back?

  A:	If you need to switch back and forth, the best all-around
	solution is not to use freopen in the first place.  Try using
	your own explicit output (or input) stream variable, which you
	can reassign at will, while leaving the original stdout (or
	stdin) undisturbed.

The even longer version of the FAQ list (don't worry, you haven't
missed it, it's not ready for release yet) continues with

	It is barely possible to save away e.g. stdout before freopening
	some file in its place, such that the original stdout can later
	be used, but the methods involve system-specific calls such as
	dup(), and/or copying or inspecting the contents of a FILE
	struct, which is exceedingly unportable and unreliable.

	You can, under some systems, explicitly re-open the controlling
	terminal (on Unix it is named /dev/tty), but this isn't
	necessarily what you want, since the input or output could have
	been redirected from the command line (to something other than
	the terminal).

					Steve Summit
					scs@adam.mit.edu

Note 1.  Why would an implementation use two parallel arrays of
structures, playing games to coordinate the indices, rather than
putting all of the fields into a single struct and using a single
array?  I can think of two reasons.

Reason 1: Backwards binary compatibility.  If a field is ever
added to an implementor's internal version of a FILE struct, all
user code that explicitly references stdout and stderr will have
to be recompiled.  Normally, when a new version of a standard
library is released, all the user has to do is re-link against
it.  Recompiling the universe can be arbitrarily hard (especially
if third-party libraries without source are involved), so it can
be important to try to keep the size of a FILE struct constant
(i.e. the same as it was in the very first release of the
library).  Keeping it constant can also help to keep broken, but
presumably important, user software which performs certain other
unportable manipulations upon the _iob array working.

Reason 2: Information hiding.  By putting certain extended FILE
struct members off in the parallel _iob2 array, it makes it even
harder for user programs to make injudicious use of them.

I am fairly certain that reason 1 has been the primary impetus
behind the implementation of these parallel FILE arrays; no one
seems to be too interested in enforced information hiding.
(Indeed, when the idea was first introduced to me in my software
engineering class (6.170), I laughed at it; it was so obvious to
me that information hiding was an unmitigated Good Thing that any
attempts to enforce it, through memory protection or encryption
or other expensive techniques, seemed like ridiculous overkill.
I still think it's overkill, but not quite so ridiculous as I
used to...)