Writing to A NON-Existing File in C

Dave Burton daveb at laidbak.UUCP
Sun Apr 10 14:48:08 AEST 1988


In article <12895 at brl-adm.ARPA> drears at 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



More information about the Comp.unix.wizards mailing list