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
This commit is contained in:
Tony Finch 2010-01-19 18:13:54 +00:00
parent 13c18821fa
commit 4992d459a5
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=202635
2 changed files with 119 additions and 30 deletions

View File

@ -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@dotat.at>. All rights reserved.
.\" Copyright (c) 2002 - 2010 Tony Finch <dot@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 deleted lines,
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

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2002 - 2009 Tony Finch <dot@dotat.at>
* Copyright (c) 2002 - 2010 Tony Finch <dot@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 */
@ -156,6 +154,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; /* number of symbols */
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; /* constant #if expression */
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_COUNT][LT_COUNT] = {
* 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;
@ -532,6 +573,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
@ -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");
}