From: ok@goanna.cs.rmit.oz.au (Richard A. O'Keefe)
Newsgroups: comp.lang.c
Subject: Re: Curses to write to stderr, possible?
Date: 8 Oct 92 04:26:23 GMT
Organization: Comp Sci, RMIT, Melbourne, Australia

In article <1992Oct6.034638.29275@oucsace.cs.ohiou.edu>, tswingle@oucsace.cs.ohiou.edu (Tom Swingle) writes:
> #include <stdio.h>
> #include <memory.h>
> #include <malloc.h>
> 
> main() {
> 
>   FILE *temp;
> 
>   temp=(FILE *) malloc(sizeof(FILE));
>   memcpy((char *) temp,(char *) stdout,sizeof(FILE));

There are a lot of assumptions here.  One of them is that there is nothing
else in stdout but what a FILE holds.  Consider the following implementation:

	typedef struct _FILE FILE;
	struct _FILE { .. stuff common to all files .. };

	struct _DISC {
	    struct _FILE common;
	    .. stuff for disc files ..
	};
	struct _CRT {
	    struct _FILE common;
	    ... stuff for screens ...
	};

	FILE *fopen(....) {
	    extern struct _DISC *_dfopen(....);
	    extern struct _CRT  *_cfopen(....);
	    ...
	    return @$@$@ ? &(_dfopen(....)->common) 
			 : &(_cfopen(....)->common);
	}

What we are talking about, in fact, is Object-Oriented Programming
done by hand.  "All struct pointers smell the same" and struct pointers
point to their first field, so we _can_ use this technique.  You need a
field in the common part to say which subtype you have.

Now memcpy((char*)temp, (char*)stdout, sizeof *temp);
will copy the > common < part of stdout to temp, and that will include
a field that says it is the first field of, say, a struct _CRT, but it
isn't.  So it will not work.

Another way it won't work is that a stdio implementation could perfectly
well do something like

	typedef struct { long magic; } FILE;

and then keep the _real_ information in a hash table, using the _address_
of the struct as a key.  Another related technique is for "magic" to be
an index into an array that holds the real information, and one of the
fields in that array is a copy of the address, so the first thing we
might do is

	void validate_FILE(FILE *p)
	    {
		/* check that p a valid pointer into a memory area */
		/* that _could_ hold a FILE struct. */
		/* check that p->magic is in range */
		/* check that local_table[p->magic] == p */
		/* if any check fails, kill the program */
	    }

This is a good way for a library package to hand out "tokens" to client
code that it doesn't really trust.

So there are two implementations where this would not work.

Of course, if you are willing to crack open your stdio implementation
you can easily come up with something that will work in _your_ system.
Portable it will not be.


In UNIX, of course, there is a very easy way to redirect stdin, stdout, &c
and then restore them.
	Fork off a child (which is a copy of the current program)
	The child uses freopen()
	When it is time to switch back, the child quits
	The parent waits for the child.
On the other hand, I honestly don't see why anyone would want to do this.
Follow one simple rule:

	Never use stdin, stdout, scanf, getchar, printf, or putchar
	in any code you might want to redirect.

Manage your own "currin" and "currout".  That is portable and it is usually
easy.  (In fact I count it a design error in stdio that it _doesn't_ work
from "currin", "currout" like Ada does and like BCPL (!) did.)
Newsgroups: comp.lang.c