svn commit: r202635 - head/usr.bin/unifdef

Tony Finch fanf at FreeBSD.org
Tue Jan 19 18:13:54 UTC 2010


Author: fanf
Date: Tue Jan 19 18:13:54 2010
New Revision: 202635
URL: http://svn.freebsd.org/changeset/base/202635

Log:
  Add a -o outfile option, which can be used to specify an output file.  The
  file can safely be the same as the input file.  Idea from IRIX unifdef(1).
  This version fixes a bug in the NetBSD unifdef which refuses to
  write to a -o outfile which does not exist.
  
  Obtained from: NetBSD

Modified:
  head/usr.bin/unifdef/unifdef.1
  head/usr.bin/unifdef/unifdef.c

Modified: head/usr.bin/unifdef/unifdef.1
==============================================================================
--- head/usr.bin/unifdef/unifdef.1	Tue Jan 19 17:20:34 2010	(r202634)
+++ head/usr.bin/unifdef/unifdef.1	Tue Jan 19 18:13:54 2010	(r202635)
@@ -1,6 +1,6 @@
 .\" Copyright (c) 1985, 1991, 1993
 .\"	The Regents of the University of California.  All rights reserved.
-.\" Copyright (c) 2002 - 2009 Tony Finch <dot at dotat.at>.  All rights reserved.
+.\" Copyright (c) 2002 - 2010 Tony Finch <dot at dotat.at>.  All rights reserved.
 .\"
 .\" This code is derived from software contributed to Berkeley by
 .\" Dave Yost. It was rewritten to support ANSI C by Tony Finch.
@@ -30,10 +30,10 @@
 .\" SUCH DAMAGE.
 .\"
 .\"     @(#)unifdef.1	8.2 (Berkeley) 4/1/94
-.\"	$dotat: unifdef/unifdef.1,v 1.60 2009/11/25 00:11:02 fanf2 Exp $
+.\"	$dotat: unifdef/unifdef.1,v 1.62 2010/01/19 17:33:53 fanf2 Exp $
 .\" $FreeBSD$
 .\"
-.Dd September 24, 2002
+.Dd January 19, 2010
 .Dt UNIFDEF 1
 .Os
 .Sh NAME
@@ -48,7 +48,8 @@
 .Op Fl iD Ns Ar sym Ns Op = Ns Ar val
 .Op Fl iU Ns Ar sym
 .Ar ...
-.Op Ar file
+.Op Fl o Ar outfile
+.Op Ar infile
 .Nm unifdefall
 .Op Fl I Ns Ar path
 .Ar ...
@@ -254,6 +255,18 @@ directives to the output following any d
 so that errors produced when compiling the output file correspond to
 line numbers in the input file.
 .Pp
+.It Fl o Ar outfile
+Write output to the file
+.Ar outfile
+instead of the standard output.
+If
+.Ar outfile
+is the same as the input file,
+the output is written to a temporary file
+which is renamed into place when
+.Nm
+completes successfully.
+.Pp
 .It Fl s
 Instead of processing the input file as usual,
 this option causes

Modified: head/usr.bin/unifdef/unifdef.c
==============================================================================
--- head/usr.bin/unifdef/unifdef.c	Tue Jan 19 17:20:34 2010	(r202634)
+++ head/usr.bin/unifdef/unifdef.c	Tue Jan 19 18:13:54 2010	(r202635)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2002 - 2009 Tony Finch <dot at dotat.at>
+ * Copyright (c) 2002 - 2010 Tony Finch <dot at dotat.at>
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -24,27 +24,14 @@
  */
 
 /*
+ * unifdef - remove ifdef'ed lines
+ *
  * This code was derived from software contributed to Berkeley by Dave Yost.
  * It was rewritten to support ANSI C by Tony Finch. The original version
  * of unifdef carried the 4-clause BSD copyright licence. None of its code
  * remains in this version (though some of the names remain) so it now
  * carries a more liberal licence.
  *
- * The latest version is available from http://dotat.at/prog/unifdef
- */
-
-#include <sys/cdefs.h>
-
-#ifdef __IDSTRING
-__IDSTRING(dotat, "$dotat: unifdef/unifdef.c,v 1.190 2009/11/27 17:21:26 fanf2 Exp $");
-#endif
-#ifdef __FBSDID
-__FBSDID("$FreeBSD$");
-#endif
-
-/*
- * unifdef - remove ifdef'ed lines
- *
  *  Wishlist:
  *      provide an option which will append the name of the
  *        appropriate symbol after #else's and #endif's
@@ -56,8 +43,12 @@ __FBSDID("$FreeBSD$");
  *     also make it possible to handle all "dodgy" directives correctly.
  */
 
+#include <sys/types.h>
+#include <sys/stat.h>
+
 #include <ctype.h>
 #include <err.h>
+#include <errno.h>
 #include <stdarg.h>
 #include <stdbool.h>
 #include <stdio.h>
@@ -65,6 +56,13 @@ __FBSDID("$FreeBSD$");
 #include <string.h>
 #include <unistd.h>
 
+#ifdef __IDSTRING
+__IDSTRING(dotat, "$dotat: unifdef/unifdef.c,v 1.193 2010/01/19 18:03:02 fanf2 Exp $");
+#endif
+#ifdef __FBSDID
+__FBSDID("$FreeBSD$");
+#endif
+
 /* types of input lines: */
 typedef enum {
 	LT_TRUEI,		/* a true #if with ignore flag */
@@ -157,6 +155,11 @@ static char const * const linestate_name
 #define	EDITSLOP        10
 
 /*
+ * For temporary filenames
+ */
+#define TEMPLATE        "unifdef.XXXXXX"
+
+/*
  * Globals.
  */
 
@@ -179,6 +182,10 @@ static int              nsyms;			/* numb
 static FILE            *input;			/* input file pointer */
 static const char      *filename;		/* input file name */
 static int              linenum;		/* current line number */
+static FILE            *output;			/* output file pointer */
+static const char      *ofilename;		/* output file name */
+static bool             overwriting;		/* output overwrites input */
+static char             tempname[FILENAME_MAX];	/* used when overwriting */
 
 static char             tline[MAXLINE+EDITSLOP];/* input buffer plus space */
 static char            *keyword;		/* used for editing #elif's */
@@ -197,6 +204,7 @@ static bool             constexpr;		/* c
 static int              exitstat;		/* program exit status */
 
 static void             addsym(bool, bool, char *);
+static void             closeout(void);
 static void             debug(const char *, ...);
 static void             done(void);
 static void             error(const char *);
@@ -227,7 +235,7 @@ main(int argc, char *argv[])
 {
 	int opt;
 
-	while ((opt = getopt(argc, argv, "i:D:U:I:BbcdeKklnst")) != -1)
+	while ((opt = getopt(argc, argv, "i:D:U:I:o:BbcdeKklnst")) != -1)
 		switch (opt) {
 		case 'i': /* treat stuff controlled by these symbols as text */
 			/*
@@ -277,6 +285,9 @@ main(int argc, char *argv[])
 		case 'n': /* add #line directive after deleted lines */
 			lnnum = true;
 			break;
+		case 'o': /* output to a file */
+			ofilename = optarg;
+			break;
 		case 's': /* only output list of symbols that control #ifs */
 			symlist = true;
 			break;
@@ -301,6 +312,43 @@ main(int argc, char *argv[])
 		filename = "[stdin]";
 		input = stdin;
 	}
+	if (ofilename == NULL) {
+		output = stdout;
+	} else {
+		struct stat ist, ost;
+		memset(&ist, 0, sizeof(ist));
+		memset(&ost, 0, sizeof(ost));
+
+		if (fstat(fileno(input), &ist) != 0)
+			err(2, "can't fstat %s", filename);
+		if (stat(ofilename, &ost) != 0 && errno != ENOENT)
+			warn("can't stat %s", ofilename);
+
+		overwriting = (ist.st_dev == ost.st_dev
+		            && ist.st_ino == ost.st_ino);
+		if (overwriting) {
+			const char *dirsep;
+			int ofd;
+
+			dirsep = strrchr(ofilename, '/');
+			if (dirsep != NULL)
+				snprintf(tempname, sizeof(tempname),
+				    "%.*s/" TEMPLATE,
+				    dirsep - ofilename, ofilename);
+			else
+				strlcpy(tempname, TEMPLATE, sizeof(tempname));
+			ofd = mkstemp(tempname);
+			if (ofd != -1)
+				output = fdopen(ofd, "w+");
+			if (output == NULL)
+				err(2, "can't create temporary file");
+			fchmod(ofd, ist.st_mode & ACCESSPERMS);
+		} else {
+			output = fopen(ofilename, "w");
+			if (output == NULL)
+				err(2, "can't open %s", ofilename);
+		}
+	}
 	process();
 	abort(); /* bug */
 }
@@ -435,13 +483,6 @@ static state_fn * const trans_table[IS_C
  * State machine utility functions
  */
 static void
-done(void)
-{
-	if (incomment)
-		error("EOF in comment");
-	exit(exitstat);
-}
-static void
 ignoreoff(void)
 {
 	if (depth == 0)
@@ -498,13 +539,13 @@ flushline(bool keep)
 		} else {
 			if (lnnum && delcount > 0)
 				printf("#line %d\n", linenum);
-			fputs(tline, stdout);
+			fputs(tline, output);
 			delcount = 0;
 			blankmax = blankcount = blankline ? blankcount + 1 : 0;
 		}
 	} else {
 		if (lnblank)
-			putc('\n', stdout);
+			putc('\n', output);
 		exitstat = 1;
 		delcount += 1;
 		blankcount = 0;
@@ -533,6 +574,40 @@ process(void)
 }
 
 /*
+ * Flush the output and handle errors.
+ */
+static void
+closeout(void)
+{
+	if (fclose(output) == EOF) {
+		warn("couldn't write to output");
+		if (overwriting) {
+			unlink(tempname);
+			errx(2, "%s unchanged", filename);
+		} else {
+			exit(2);
+		}
+	}
+}
+
+/*
+ * Clean up and exit.
+ */
+static void
+done(void)
+{
+	if (incomment)
+		error("EOF in comment");
+	closeout();
+	if (overwriting && rename(tempname, filename) == -1) {
+		warn("couldn't rename temporary file");
+		unlink(tempname);
+		errx(2, "%s unchanged", filename);
+	}
+	exit(exitstat);
+}
+
+/*
  * Parse a line and determine its type. We keep the preprocessor line
  * parser state between calls in the global variable linestate, with
  * help from skipcomment().
@@ -1097,5 +1172,6 @@ error(const char *msg)
 	else
 		warnx("%s: %d: %s (#if line %d depth %d)",
 		    filename, linenum, msg, stifline[depth], depth);
+	closeout();
 	errx(2, "output may be truncated");
 }


More information about the svn-src-all mailing list