[comp.unix.wizards] Writing to A NON-Existing File in C

drears@ardec.arpa (Dennis G. Rears (FSAC)) (04/10/88)

  ok. ok.  After over 20 messages I admit I f*cked up on my posting
and program.  The errors pointed out were:

	1) comment should have ended in "*/" not "*?"
	2) The declaration #define NULL  "/dev/null/"
	should not have used NUll and the / after null was wrong
	3) I use the word FILE instead of FILENAME in my stat(2) call
	
Next time I will not send a program while sleeping.  Please no more
messages about this.


Here is a corrected version of it:

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#define FILENAME  "/usr/foobar"      /*  not a trademark of AT&T */
#define DEVNULL	  "dev/null"
main(a,b)
int a;
char *b[];
{
	struct stat buf;
	FILE	*fopen(), *fp;


	if(stat(FILENAME,&buf)){

		if ( (fp=fopen(DEVNULL,"a")) == NULL ) { 
			/* or use perror() */
			(void)fprintf (stderr, 
			"%s: Can not open /dev/null file\n",b[0]);
			exit(-1);
		}
	}
	else
		if ( (fp=fopen(FILENAME,"a")) == NULL ) { 
			(void)fprintf (stderr, 
			"%s: Can not open %sfile\n",b[0],FILENAME);
			exit(-1);

		}
/*   go on writing to filepointer fp */
}
------------------------------------------------------------
ARPA:		drears@ardec-ac4.arpa
UUCP:   	...!uunet!ardec-ac4.arpa!drears
AT&T:		201-724-6639
Snailmail:	Box 210, Wharton, NJ 07885
Govt Nonmail:	US Army ARDEC, ATTN SMCAR-FSS-E, Dennis Rears
		Bldg 94, Picatinny Arsenal, NJ 07806
Flames:		/dev/null
------------------------------------------------------------

daveb@laidbak.UUCP (Dave Burton) (04/10/88)

In article <12895@brl-adm.ARPA> drears@ardec.arpa (Dennis G. Rears (FSAC)) writes:
|  ok. ok.  After over 20 messages I admit I ------ up on my posting
|and program.  The errors pointed out were:
|...
|	2) The declaration #define NULL  "/dev/null/"
|	should not have used NUll and the / after null was wrong
|...	
|Here is a corrected version of it:
|
|#include <stdio.h>
|#include <sys/types.h>
|#include <sys/stat.h>
|#define FILENAME  "/usr/foobar"      /*  not a trademark of AT&T */
|#define DEVNULL	  "dev/null"
			   ^
Oops - that extra slash belongs here, right? :-)

|main(a,b)
|int a;
|char *b[];
|{
|	struct stat buf;
|	FILE	*fopen(), *fp;
|
|	if(stat(FILENAME,&buf)){
|		if ( (fp=fopen(DEVNULL,"a")) == NULL ) { 
|			/* or use perror() */
|			(void)fprintf (stderr, 
|			"%s: Can not open /dev/null file\n",b[0]);
|			exit(-1);
|		}
|	}
|	else
|		if ( (fp=fopen(FILENAME,"a")) == NULL ) { 
|			(void)fprintf (stderr, 
|			"%s: Can not open %sfile\n",b[0],FILENAME);
|			exit(-1);
|
|		}
|/*   go on writing to filepointer fp */
|}
|...
|Flames:		/dev/null
			^
But we know you know what you're trying to say. :-)

At the risk of beating this topic to death, (oops, too late),
a slight reorganization of your code will
	. centralize error exits
	. standardize message text (one format string, not two)
	. enhance code clarity
	. use less string space, at least with some compilers
	. provide the correct filename for later error messages
	. provide another target for flamers
One alternate is:

	filename = FILENAME;
	if (!stat(filename, &buf))
		filename = DEVNULL;
	if ((fp = fopen(filename, "a")) == NULL) {
		perror(filename);
		exit(1);
	}

Note that both versions have a problem. If the problem definition
is "write data to FILENAME if it exists _and_ is writable, else use
the bit bucket", then stat() is not the proper operation. A fix:

	filename = FILENAME;
        if ((fd = open(filename, O_WRONLY|O_APPEND)) != -1) /* available? */
                if ((fp = fdopen(fd, "a")) == NULL)
			close(fd);

	if (fp == NULL) {				/* if not available */
                filename = DEVNULL;
                if ((fp = fopen(filename, "a")) == NULL) {
                        perror(filename);
                        exit(1);
                }
        }

To the Original Poster:
Generally, it is best to write all error/warning messages to stderr
and allow the invoking entity (now that's non-sexist ;-) to redirect
any unwanted output to /dev/null from the command line. This will also
remove the need for the above code.
-- 
--------------------"Well, it looked good when I wrote it"---------------------
 Verbal: Dave Burton                        Net: ...!ihnp4!laidbak!daveb
 V-MAIL: (312) 505-9100 x325            USSnail: 1901 N. Naper Blvd.
#include <disclaimer.h>                          Naperville, IL  60540

karish@denali.UUCP (karish) (04/15/88)

Is there a pressing reason to actually WRITE to the bit-bucket,
instead of not writing at all?  My answer:  No, unless the task
is to wrap a canned program into a new interface.

My solution, which has already been posted (by someone whose
mailer screwed up, killing the second partr of the message)
is to use a special function to do the output.  If a disk
file is available, write to it; otherwise, call a null function
that doesn't write at all.

This can be done either with the C preprocessor (wire in the
behavior at compile time) or with pointers to functions.


My employer is not so foolish as to agree with all of my opinions.

Chuck Karish		ARPA:	karish@denali.stanford.edu
			UUCP:	{decvax,hplabs!hpda}!mindcrf!karish
			paper:	1825 California St. #5
				Mountain View, CA  94041