summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDag-Erling Smørgrav <des@FreeBSD.org>2023-08-21 19:33:26 +0200
committerDag-Erling Smørgrav <des@FreeBSD.org>2023-08-21 19:33:26 +0200
commit9b3517a49d4e15b97a68bf9e9d68ddda104bf79d (patch)
tree4673aad9f1a0a0ac19089f22aaa91d7c0b62a50e
Import unifdef 2.11vendor/unifdef/2.11
-rw-r--r--.gitignore7
-rw-r--r--.travis.yml35
-rw-r--r--COPYING85
-rw-r--r--FreeBSD/err.c138
-rw-r--r--FreeBSD/getopt.c118
-rw-r--r--INSTALL36
-rw-r--r--Makefile58
-rw-r--r--README52
-rw-r--r--scripts/authors.svn15
-rwxr-xr-xscripts/copycheck.sh21
-rwxr-xr-xscripts/fixtests.sh9
-rw-r--r--scripts/git.config10
-rwxr-xr-xscripts/gitlog2changelog.sh8
-rwxr-xr-xscripts/release.sh18
-rwxr-xr-xscripts/reversion.sh41
-rwxr-xr-xscripts/runtests.sh33
-rwxr-xr-xscripts/svnup.sh12
-rwxr-xr-xscripts/upload.sh19
-rw-r--r--tests/NetBSD-42628.c25
-rw-r--r--tests/NetBSD-42628.experr0
-rw-r--r--tests/NetBSD-42628.expout6
-rw-r--r--tests/NetBSD-42628.exprc1
-rw-r--r--tests/NetBSD-42628.sh1
-rw-r--r--tests/NetBSD-47068.c2
-rw-r--r--tests/NetBSD-47068.experr0
-rw-r--r--tests/NetBSD-47068.expout2
-rw-r--r--tests/NetBSD-47068.exprc1
-rw-r--r--tests/NetBSD-47068.sh1
-rw-r--r--tests/args1.c3
-rw-r--r--tests/args1.experr0
-rw-r--r--tests/args1.expout1
-rw-r--r--tests/args1.exprc1
-rw-r--r--tests/args1.sh1
-rw-r--r--tests/args2.c3
-rw-r--r--tests/args2.experr0
-rw-r--r--tests/args2.expout3
-rw-r--r--tests/args2.exprc1
-rw-r--r--tests/args2.sh1
-rw-r--r--tests/blank0d.c25
-rw-r--r--tests/blank0d.experr0
-rw-r--r--tests/blank0d.expout23
-rw-r--r--tests/blank0d.exprc1
-rw-r--r--tests/blank0d.sh1
-rw-r--r--tests/blank0u.c25
-rw-r--r--tests/blank0u.experr0
-rw-r--r--tests/blank0u.expout22
-rw-r--r--tests/blank0u.exprc1
-rw-r--r--tests/blank0u.sh1
-rw-r--r--tests/blank1d.c25
-rw-r--r--tests/blank1d.experr0
-rw-r--r--tests/blank1d.expout23
-rw-r--r--tests/blank1d.exprc1
-rw-r--r--tests/blank1d.sh1
-rw-r--r--tests/blank1u.c25
-rw-r--r--tests/blank1u.experr0
-rw-r--r--tests/blank1u.expout21
-rw-r--r--tests/blank1u.exprc1
-rw-r--r--tests/blank1u.sh1
-rw-r--r--tests/blank2d.c25
-rw-r--r--tests/blank2d.experr0
-rw-r--r--tests/blank2d.expout23
-rw-r--r--tests/blank2d.exprc1
-rw-r--r--tests/blank2d.sh1
-rw-r--r--tests/blank2u.c25
-rw-r--r--tests/blank2u.experr0
-rw-r--r--tests/blank2u.expout20
-rw-r--r--tests/blank2u.exprc1
-rw-r--r--tests/blank2u.sh1
-rw-r--r--tests/blank3d.c25
-rw-r--r--tests/blank3d.experr0
-rw-r--r--tests/blank3d.expout23
-rw-r--r--tests/blank3d.exprc1
-rw-r--r--tests/blank3d.sh1
-rw-r--r--tests/blank3u.c25
-rw-r--r--tests/blank3u.experr0
-rw-r--r--tests/blank3u.expout19
-rw-r--r--tests/blank3u.exprc1
-rw-r--r--tests/blank3u.sh1
-rw-r--r--tests/blank4d.c25
-rw-r--r--tests/blank4d.experr0
-rw-r--r--tests/blank4d.expout23
-rw-r--r--tests/blank4d.exprc1
-rw-r--r--tests/blank4d.sh1
-rw-r--r--tests/blank4u.c25
-rw-r--r--tests/blank4u.experr0
-rw-r--r--tests/blank4u.expout18
-rw-r--r--tests/blank4u.exprc1
-rw-r--r--tests/blank4u.sh1
-rw-r--r--tests/broken2.h1
-rw-r--r--tests/broken3.h1
-rw-r--r--tests/broken4.h2
-rw-r--r--tests/crlf-a.experr0
-rw-r--r--tests/crlf-a.expout10
-rw-r--r--tests/crlf-a.exprc1
-rw-r--r--tests/crlf-a.sh1
-rw-r--r--tests/crlf-b.experr0
-rw-r--r--tests/crlf-b.expout14
-rw-r--r--tests/crlf-b.exprc1
-rw-r--r--tests/crlf-b.sh1
-rw-r--r--tests/crlf-c.experr0
-rw-r--r--tests/crlf-c.expout16
-rw-r--r--tests/crlf-c.exprc1
-rw-r--r--tests/crlf-c.sh1
-rw-r--r--tests/crlf-d.experr0
-rw-r--r--tests/crlf-d.expout18
-rw-r--r--tests/crlf-d.exprc1
-rw-r--r--tests/crlf-d.sh1
-rw-r--r--tests/crlf.c20
-rw-r--r--tests/debian-603860.c8
-rw-r--r--tests/debian-603860.experr0
-rw-r--r--tests/debian-603860.expout2
-rw-r--r--tests/debian-603860.exprc1
-rw-r--r--tests/debian-603860.sh1
-rw-r--r--tests/defundef-broken2.experr2
-rw-r--r--tests/defundef-broken2.expout0
-rw-r--r--tests/defundef-broken2.exprc1
-rw-r--r--tests/defundef-broken2.sh1
-rw-r--r--tests/defundef-broken3.experr2
-rw-r--r--tests/defundef-broken3.expout0
-rw-r--r--tests/defundef-broken3.exprc1
-rw-r--r--tests/defundef-broken3.sh1
-rw-r--r--tests/defundef-broken4.experr2
-rw-r--r--tests/defundef-broken4.expout0
-rw-r--r--tests/defundef-broken4.exprc1
-rw-r--r--tests/defundef-broken4.sh1
-rw-r--r--tests/defundef-funlike.experr0
-rw-r--r--tests/defundef-funlike.expout13
-rw-r--r--tests/defundef-funlike.exprc1
-rw-r--r--tests/defundef-funlike.sh1
-rw-r--r--tests/defundef-undefdef.experr0
-rw-r--r--tests/defundef-undefdef.expout1
-rw-r--r--tests/defundef-undefdef.exprc1
-rw-r--r--tests/defundef-undefdef.sh1
-rw-r--r--tests/div.c3
-rw-r--r--tests/div.experr0
-rw-r--r--tests/div.expout10
-rw-r--r--tests/div.exprc1
-rw-r--r--tests/div.sh10
-rw-r--r--tests/empty.c0
-rw-r--r--tests/empty.experr0
-rw-r--r--tests/empty.expout0
-rw-r--r--tests/empty.exprc1
-rw-r--r--tests/empty.sh1
-rw-r--r--tests/error.c4
-rw-r--r--tests/error.experr0
-rw-r--r--tests/error.expout2
-rw-r--r--tests/error.exprc1
-rw-r--r--tests/error.sh1
-rw-r--r--tests/exitmode0a.experr0
-rw-r--r--tests/exitmode0a.expout16
-rw-r--r--tests/exitmode0a.exprc1
-rw-r--r--tests/exitmode0a.sh1
-rw-r--r--tests/exitmode0b.experr0
-rw-r--r--tests/exitmode0b.expout26
-rw-r--r--tests/exitmode0b.exprc1
-rw-r--r--tests/exitmode0b.sh1
-rw-r--r--tests/exitmode1a.experr0
-rw-r--r--tests/exitmode1a.expout16
-rw-r--r--tests/exitmode1a.exprc1
-rw-r--r--tests/exitmode1a.sh1
-rw-r--r--tests/exitmode1b.experr0
-rw-r--r--tests/exitmode1b.expout26
-rw-r--r--tests/exitmode1b.exprc1
-rw-r--r--tests/exitmode1b.sh1
-rw-r--r--tests/exitmode2a.experr0
-rw-r--r--tests/exitmode2a.expout16
-rw-r--r--tests/exitmode2a.exprc1
-rw-r--r--tests/exitmode2a.sh1
-rw-r--r--tests/exitmode2b.experr0
-rw-r--r--tests/exitmode2b.expout26
-rw-r--r--tests/exitmode2b.exprc1
-rw-r--r--tests/exitmode2b.sh1
-rw-r--r--tests/exitstat.c3
-rw-r--r--tests/exitstat.experr0
-rw-r--r--tests/exitstat.expout3
-rw-r--r--tests/exitstat.exprc1
-rw-r--r--tests/exitstat.sh1
-rw-r--r--tests/funlike.h1
-rw-r--r--tests/if1-a.experr0
-rw-r--r--tests/if1-a.expout16
-rw-r--r--tests/if1-a.exprc1
-rw-r--r--tests/if1-a.sh1
-rw-r--r--tests/if1-f.experr0
-rw-r--r--tests/if1-f.expout16
-rw-r--r--tests/if1-f.exprc1
-rw-r--r--tests/if1-f.sh1
-rw-r--r--tests/if1-k.c38
-rw-r--r--tests/if1-k.experr0
-rw-r--r--tests/if1-k.expout30
-rw-r--r--tests/if1-k.exprc1
-rw-r--r--tests/if1-k.sh1
-rw-r--r--tests/if1-kDU.c38
-rw-r--r--tests/if1-kDU.experr0
-rw-r--r--tests/if1-kDU.expout20
-rw-r--r--tests/if1-kDU.exprc1
-rw-r--r--tests/if1-kDU.sh1
-rw-r--r--tests/if1.c26
-rw-r--r--tests/if1.experr0
-rw-r--r--tests/if1.expout16
-rw-r--r--tests/if1.exprc1
-rw-r--r--tests/if1.h3
-rw-r--r--tests/if1.sh1
-rw-r--r--tests/if1a.experr0
-rw-r--r--tests/if1a.expout24
-rw-r--r--tests/if1a.exprc1
-rw-r--r--tests/if1a.sh1
-rw-r--r--tests/if2-a.experr0
-rw-r--r--tests/if2-a.expout13
-rw-r--r--tests/if2-a.exprc1
-rw-r--r--tests/if2-a.sh1
-rw-r--r--tests/if2-k.c29
-rw-r--r--tests/if2-k.experr0
-rw-r--r--tests/if2-k.expout21
-rw-r--r--tests/if2-k.exprc1
-rw-r--r--tests/if2-k.sh1
-rw-r--r--tests/if2-kDU.c29
-rw-r--r--tests/if2-kDU.experr0
-rw-r--r--tests/if2-kDU.expout17
-rw-r--r--tests/if2-kDU.exprc1
-rw-r--r--tests/if2-kDU.sh1
-rw-r--r--tests/if2.c17
-rw-r--r--tests/if2.experr0
-rw-r--r--tests/if2.expout13
-rw-r--r--tests/if2.exprc1
-rw-r--r--tests/if2.sh1
-rw-r--r--tests/if3-a.experr0
-rw-r--r--tests/if3-a.expout13
-rw-r--r--tests/if3-a.exprc1
-rw-r--r--tests/if3-a.sh1
-rw-r--r--tests/if3-k.c29
-rw-r--r--tests/if3-k.experr0
-rw-r--r--tests/if3-k.expout21
-rw-r--r--tests/if3-k.exprc1
-rw-r--r--tests/if3-k.sh1
-rw-r--r--tests/if3-kDU.c29
-rw-r--r--tests/if3-kDU.experr0
-rw-r--r--tests/if3-kDU.expout17
-rw-r--r--tests/if3-kDU.exprc1
-rw-r--r--tests/if3-kDU.sh1
-rw-r--r--tests/if3.c17
-rw-r--r--tests/if3.experr0
-rw-r--r--tests/if3.expout13
-rw-r--r--tests/if3.exprc1
-rw-r--r--tests/if3.sh1
-rw-r--r--tests/if4-a.experr0
-rw-r--r--tests/if4-a.expout22
-rw-r--r--tests/if4-a.exprc1
-rw-r--r--tests/if4-a.sh1
-rw-r--r--tests/if4-k.c50
-rw-r--r--tests/if4-k.experr0
-rw-r--r--tests/if4-k.expout42
-rw-r--r--tests/if4-k.exprc1
-rw-r--r--tests/if4-k.sh1
-rw-r--r--tests/if4-kDU.c50
-rw-r--r--tests/if4-kDU.experr0
-rw-r--r--tests/if4-kDU.expout26
-rw-r--r--tests/if4-kDU.exprc1
-rw-r--r--tests/if4-kDU.sh1
-rw-r--r--tests/if4.c38
-rw-r--r--tests/if4.experr0
-rw-r--r--tests/if4.expout22
-rw-r--r--tests/if4.exprc1
-rw-r--r--tests/if4.sh1
-rw-r--r--tests/if5-a.experr0
-rw-r--r--tests/if5-a.expout40
-rw-r--r--tests/if5-a.exprc1
-rw-r--r--tests/if5-a.sh1
-rw-r--r--tests/if5-k.c64
-rw-r--r--tests/if5-k.experr0
-rw-r--r--tests/if5-k.expout56
-rw-r--r--tests/if5-k.exprc1
-rw-r--r--tests/if5-k.sh1
-rw-r--r--tests/if5-kDU.c64
-rw-r--r--tests/if5-kDU.experr0
-rw-r--r--tests/if5-kDU.expout32
-rw-r--r--tests/if5-kDU.exprc1
-rw-r--r--tests/if5-kDU.sh1
-rw-r--r--tests/if5.c80
-rw-r--r--tests/if5.experr0
-rw-r--r--tests/if5.expout40
-rw-r--r--tests/if5.exprc1
-rw-r--r--tests/if5.sh1
-rw-r--r--tests/if6.c11
-rw-r--r--tests/if6.h2
-rw-r--r--tests/if6a.experr0
-rw-r--r--tests/if6a.expout1
-rw-r--r--tests/if6a.exprc1
-rw-r--r--tests/if6a.sh1
-rw-r--r--tests/if6b.experr0
-rw-r--r--tests/if6b.expout5
-rw-r--r--tests/if6b.exprc1
-rw-r--r--tests/if6b.sh1
-rw-r--r--tests/if6c.experr0
-rw-r--r--tests/if6c.expout7
-rw-r--r--tests/if6c.exprc1
-rw-r--r--tests/if6c.sh1
-rw-r--r--tests/if6d.experr0
-rw-r--r--tests/if6d.expout9
-rw-r--r--tests/if6d.exprc1
-rw-r--r--tests/if6d.sh1
-rw-r--r--tests/if7.c94
-rw-r--r--tests/if7.experr0
-rw-r--r--tests/if7.expout46
-rw-r--r--tests/if7.exprc1
-rw-r--r--tests/if7.sh1
-rw-r--r--tests/indirect.experr0
-rw-r--r--tests/indirect.expout16
-rw-r--r--tests/indirect.exprc1
-rw-r--r--tests/indirect.sh1
-rw-r--r--tests/multi-generic-sh15
-rw-r--r--tests/multi.experr0
-rw-r--r--tests/multi.expout36
-rw-r--r--tests/multi.exprc1
-rw-r--r--tests/multi.sh3
-rw-r--r--tests/multilnnum.experr0
-rw-r--r--tests/multilnnum.expout42
-rw-r--r--tests/multilnnum.exprc1
-rw-r--r--tests/multilnnum.sh3
-rw-r--r--tests/multimissing.experr4
-rw-r--r--tests/multimissing.expout22
-rw-r--r--tests/multimissing.exprc1
-rw-r--r--tests/multimissing.sh3
-rw-r--r--tests/multinewline.experr0
-rw-r--r--tests/multinewline.expout39
-rw-r--r--tests/multinewline.exprc1
-rw-r--r--tests/multinewline.sh3
-rw-r--r--tests/none.c5
-rw-r--r--tests/none.experr0
-rw-r--r--tests/none.expout5
-rw-r--r--tests/none.exprc1
-rw-r--r--tests/none.sh1
-rw-r--r--tests/outdir.experr0
-rw-r--r--tests/outdir.expout16
-rw-r--r--tests/outdir.exprc1
-rw-r--r--tests/outdir.sh6
-rw-r--r--tests/outeperm.experr1
-rw-r--r--tests/outeperm.expout0
-rw-r--r--tests/outeperm.exprc1
-rw-r--r--tests/outeperm.sh6
-rw-r--r--tests/outfile.experr0
-rw-r--r--tests/outfile.expout16
-rw-r--r--tests/outfile.exprc1
-rw-r--r--tests/outfile.sh5
-rw-r--r--tests/outperms.experr1
-rw-r--r--tests/outperms.expout16
-rw-r--r--tests/outperms.exprc1
-rw-r--r--tests/outperms.sh7
-rw-r--r--tests/overdir.experr0
-rw-r--r--tests/overdir.expout16
-rw-r--r--tests/overdir.exprc1
-rw-r--r--tests/overdir.sh7
-rw-r--r--tests/overenoent.experr1
-rw-r--r--tests/overenoent.expout0
-rw-r--r--tests/overenoent.exprc1
-rw-r--r--tests/overenoent.sh5
-rw-r--r--tests/overin.experr0
-rw-r--r--tests/overin.expout16
-rw-r--r--tests/overin.exprc1
-rw-r--r--tests/overin.sh6
-rw-r--r--tests/overlnnum.experr0
-rw-r--r--tests/overlnnum.expout20
-rw-r--r--tests/overlnnum.exprc1
-rw-r--r--tests/overlnnum.sh6
-rw-r--r--tests/overperms.experr2
-rw-r--r--tests/overperms.expout16
-rw-r--r--tests/overperms.exprc1
-rw-r--r--tests/overperms.sh9
-rw-r--r--tests/overunchanged.experr0
-rw-r--r--tests/overunchanged.expout0
-rw-r--r--tests/overunchanged.exprc1
-rw-r--r--tests/overunchanged.sh8
-rw-r--r--tests/overwrite.experr0
-rw-r--r--tests/overwrite.expout16
-rw-r--r--tests/overwrite.exprc1
-rw-r--r--tests/overwrite.sh6
-rw-r--r--tests/recursive.experr120
-rw-r--r--tests/recursive.expout26
-rw-r--r--tests/recursive.exprc1
-rw-r--r--tests/recursive.sh1
-rw-r--r--tests/small1.c17
-rw-r--r--tests/small1.experr0
-rw-r--r--tests/small1.expout13
-rw-r--r--tests/small1.exprc1
-rw-r--r--tests/small1.sh1
-rw-r--r--tests/small2.c17
-rw-r--r--tests/small2.experr0
-rw-r--r--tests/small2.expout13
-rw-r--r--tests/small2.exprc1
-rw-r--r--tests/small2.sh1
-rw-r--r--tests/spaces1.c17
-rw-r--r--tests/spaces1.experr0
-rw-r--r--tests/spaces1.expout13
-rw-r--r--tests/spaces1.exprc1
-rw-r--r--tests/spaces1.sh1
-rw-r--r--tests/spaces2.c17
-rw-r--r--tests/spaces2.experr0
-rw-r--r--tests/spaces2.expout13
-rw-r--r--tests/spaces2.exprc1
-rw-r--r--tests/spaces2.sh1
-rw-r--r--tests/spaces3.c17
-rw-r--r--tests/spaces3.experr0
-rw-r--r--tests/spaces3.expout13
-rw-r--r--tests/spaces3.exprc1
-rw-r--r--tests/spaces3.sh1
-rw-r--r--tests/spaces4.c17
-rw-r--r--tests/spaces4.experr0
-rw-r--r--tests/spaces4.expout13
-rw-r--r--tests/spaces4.exprc1
-rw-r--r--tests/spaces4.sh1
-rw-r--r--tests/whitespace-1.experr2
-rw-r--r--tests/whitespace-1.expout1
-rw-r--r--tests/whitespace-1.exprc1
-rw-r--r--tests/whitespace-1.sh1
-rw-r--r--tests/whitespace-2.experr0
-rw-r--r--tests/whitespace-2.expout5
-rw-r--r--tests/whitespace-2.exprc1
-rw-r--r--tests/whitespace-2.sh1
-rw-r--r--tests/whitespace.c7
-rw-r--r--tests/xterm.experr3
-rw-r--r--tests/xterm.expout83
-rw-r--r--tests/xterm.exprc1
-rw-r--r--tests/xterm.sh35
-rw-r--r--unifdef.1514
-rw-r--r--unifdef.c1661
-rw-r--r--unifdef.h50
-rwxr-xr-xunifdefall.sh58
-rw-r--r--win32/Makefile.mingw14
-rw-r--r--win32/unifdef.h78
-rw-r--r--win32/unifdef.sln20
-rw-r--r--win32/unifdef.vcxproj96
-rw-r--r--win32/win32.c87
431 files changed, 6408 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 000000000000..55ca2f341b7c
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,7 @@
+Changelog
+unifdef
+unifdef.exe
+unifdef.txt
+unifdef-*
+version.h
+version.sh
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 000000000000..eea1217fed50
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,35 @@
+language: c
+
+compiler:
+ - gcc
+ - clang
+
+matrix:
+ include:
+ - compiler: i586-mingw32msvc-gcc
+ env: BUILD_MINGW="yes"
+
+before_install:
+ - sudo apt-get -qq update
+
+install:
+ - if test "${BUILD_MINGW}" = "yes"; then sudo apt-get -qq install wine; fi
+
+script:
+ - if test "${BUILD_MINGW}" != "yes"; then
+ make &&
+ make test &&
+ make release;
+ else
+ export CC=i586-mingw32msvc-gcc;
+ echo -e '#!/bin/bash\nexec wine $0.exe "$@"' > unifdef;
+ chmod ugo+x unifdef;
+ make version.h &&
+ make -f win32/Makefile.mingw test;
+ fi
+
+## whitelist
+branches:
+ only:
+ - master
+ - tmp
diff --git a/COPYING b/COPYING
new file mode 100644
index 000000000000..21bc00b7d439
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,85 @@
+unifdef copyright licence
+-------------------------
+
+All files in this package are distributed under the two-clause BSD
+copyright licence, except for the manual page unifdef.1 and the
+portability support code in the FreeBSD subdirectory, which all have
+a three-clause BSD copyright licence.
+
+Unifdef 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.c carried the four-clause BSD copyright licence.
+None of its code remains in this version (though some of the names
+remain) so it now carries the more liberal two-clause licence.
+
+Unless otherwise stated, the files in this package are:
+
+ Copyright (c) 2002 - 2015 Tony Finch <dot@dotat.at>
+
+unifdefall.sh is:
+
+ Copyright (c) 2002 - 2013 Tony Finch <dot@dotat.at>
+ Copyright (c) 2009 - 2010 Jonathan Nieder <jrnieder@gmail.com>
+
+Some files in the tests directory are:
+
+ Copyright 2004, 2008 Bob Proulx <bob@proulx.com>
+
+The two-clause BSD copyright licence applying to all the above files is:
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ SUCH DAMAGE.
+
+The three-clause BSD copyright licence for the manual page unifdef.1
+and the portability support code from FreeBSD is below. The fourth
+advertising clause that used to appear between clauses 2 and 3 was
+rescinded by the University of California Berkeley in 1999.
+ftp://ftp.cs.berkeley.edu/pub/4bsd/README.Impt.License.Change
+
+ Copyright (c) 1985 - 1994
+ The Regents of the University of California. All rights reserved.
+ Copyright (c) 2002 - 2012 Tony Finch <dot@dotat.at>. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ 3. Neither the name of the University nor the names of its contributors
+ may be used to endorse or promote products derived from this software
+ without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ SUCH DAMAGE.
+
+- end -
diff --git a/FreeBSD/err.c b/FreeBSD/err.c
new file mode 100644
index 000000000000..9589fced5b26
--- /dev/null
+++ b/FreeBSD/err.c
@@ -0,0 +1,138 @@
+/*-
+ * Copyright (c) 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "unifdef.h"
+
+void
+err(int eval, const char *fmt, ...)
+{
+ va_list ap;
+ va_start(ap, fmt);
+ verrc(eval, errno, fmt, ap);
+ va_end(ap);
+}
+
+void
+verr(int eval, const char *fmt, va_list ap)
+{
+ verrc(eval, errno, fmt, ap);
+}
+
+void
+errc(int eval, int code, const char *fmt, ...)
+{
+ va_list ap;
+ va_start(ap, fmt);
+ verrc(eval, code, fmt, ap);
+ va_end(ap);
+}
+
+void
+verrc(int eval, int code, const char *fmt, va_list ap)
+{
+ fprintf(stderr, "%s: ", _getprogname());
+ if (fmt != NULL) {
+ vfprintf(stderr, fmt, ap);
+ fprintf(stderr, ": ");
+ }
+ fprintf(stderr, "%s\n", strerror(code));
+ exit(eval);
+}
+
+void
+errx(int eval, const char *fmt, ...)
+{
+ va_list ap;
+ va_start(ap, fmt);
+ verrx(eval, fmt, ap);
+ va_end(ap);
+}
+
+void
+verrx(int eval, const char *fmt, va_list ap)
+{
+ fprintf(stderr, "%s: ", _getprogname());
+ if (fmt != NULL)
+ vfprintf(stderr, fmt, ap);
+ fprintf(stderr, "\n");
+ exit(eval);
+}
+
+void
+warn(const char *fmt, ...)
+{
+ va_list ap;
+ va_start(ap, fmt);
+ vwarnc(errno, fmt, ap);
+ va_end(ap);
+}
+
+void
+vwarn(const char *fmt, va_list ap)
+{
+ vwarnc(errno, fmt, ap);
+}
+
+void
+warnc(int code, const char *fmt, ...)
+{
+ va_list ap;
+ va_start(ap, fmt);
+ vwarnc(code, fmt, ap);
+ va_end(ap);
+}
+
+void
+vwarnc(int code, const char *fmt, va_list ap)
+{
+ fprintf(stderr, "%s: ", _getprogname());
+ if (fmt != NULL) {
+ vfprintf(stderr, fmt, ap);
+ fprintf(stderr, ": ");
+ }
+ fprintf(stderr, "%s\n", strerror(code));
+}
+
+void
+warnx(const char *fmt, ...)
+{
+ va_list ap;
+ va_start(ap, fmt);
+ vwarnx(fmt, ap);
+ va_end(ap);
+}
+
+void
+vwarnx(const char *fmt, va_list ap)
+{
+ fprintf(stderr, "%s: ", _getprogname());
+ if (fmt != NULL)
+ vfprintf(stderr, fmt, ap);
+ fprintf(stderr, "\n");
+}
diff --git a/FreeBSD/getopt.c b/FreeBSD/getopt.c
new file mode 100644
index 000000000000..eb9b0c507875
--- /dev/null
+++ b/FreeBSD/getopt.c
@@ -0,0 +1,118 @@
+/*
+ * Copyright (c) 1987, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "unifdef.h"
+
+int opterr = 1, /* if error message should be printed */
+ optind = 1, /* index into parent argv vector */
+ optopt, /* character checked for validity */
+ optreset; /* reset getopt */
+char *optarg; /* argument associated with option */
+
+#define BADCH (int)'?'
+#define BADARG (int)':'
+
+static char EMSG[] = "";
+
+/*
+ * getopt --
+ * Parse argc/argv argument vector.
+ */
+int
+getopt(int nargc, char *nargv[], const char *ostr)
+{
+ static char *place = EMSG; /* option letter processing */
+ const char *oli; /* option letter list index */
+
+ if (optreset || *place == 0) { /* update scanning pointer */
+ optreset = 0;
+ place = nargv[optind];
+ if (optind >= nargc || *place++ != '-') {
+ /* Argument is absent or is not an option */
+ place = EMSG;
+ return (-1);
+ }
+ optopt = *place++;
+ if (optopt == '-' && *place == 0) {
+ /* "--" => end of options */
+ ++optind;
+ place = EMSG;
+ return (-1);
+ }
+ if (optopt == 0) {
+ /* Solitary '-', treat as a '-' option
+ if the program (eg su) is looking for it. */
+ place = EMSG;
+ if (strchr(ostr, '-') == NULL)
+ return (-1);
+ optopt = '-';
+ }
+ } else
+ optopt = *place++;
+
+ /* See if option letter is one the caller wanted... */
+ if (optopt == ':' || (oli = strchr(ostr, optopt)) == NULL) {
+ if (*place == 0)
+ ++optind;
+ if (opterr && *ostr != ':')
+ (void)fprintf(stderr,
+ "%s: illegal option -- %c\n", _getprogname(),
+ optopt);
+ return (BADCH);
+ }
+
+ /* Does this option need an argument? */
+ if (oli[1] != ':') {
+ /* don't need argument */
+ optarg = NULL;
+ if (*place == 0)
+ ++optind;
+ } else {
+ /* Option-argument is either the rest of this argument or the
+ entire next argument. */
+ if (*place)
+ optarg = place;
+ else if (nargc > ++optind)
+ optarg = nargv[optind];
+ else {
+ /* option-argument absent */
+ place = EMSG;
+ if (*ostr == ':')
+ return (BADARG);
+ if (opterr)
+ (void)fprintf(stderr,
+ "%s: option requires an argument -- %c\n",
+ _getprogname(), optopt);
+ return (BADCH);
+ }
+ place = EMSG;
+ ++optind;
+ }
+ return (optopt); /* return option letter */
+}
diff --git a/INSTALL b/INSTALL
new file mode 100644
index 000000000000..03d7488588ab
--- /dev/null
+++ b/INSTALL
@@ -0,0 +1,36 @@
+unifdef installation instructions
+---------------------------------
+
+Dependencies:
+ * unifdef is mostly ANSI C, with a few unixisms
+ * unifdefall is a Unix shell script
+ * the manual uses the nroff mdoc macros
+ * the support and test scripts are Unix shell scripts
+
+To build on Unix, type `make`. You can adjust the compilation options
+using the POSIX standard CFLAGS and LDFLAGS make variables.
+
+To install in your home directory, type `make install`
+or to install in /usr type `make prefix=/usr install`.
+See the start of the Makefile for the install location
+variables.
+
+The win32 subdirectory contains build files for MinGW and Visual
+Studio 2010 which make use of the FreeBSD code plus some other
+portability wrappers.
+
+To build with MinGW, type `mingw32-make -f win32/Makefile.mingw`.
+
+Unlike the Unix Makefile, the Windows builds do not automatically
+create or update version.h. The release tar and zip files include a
+pre-generated version.h but the git repository does not. To build from
+a git clone you need a Unix shell environment, which you can get as
+part of GitHub for Windows - http://windows.github.com/
+To update version.h, right-click on the fanf2/unifdef repository and
+select "open a shell here", then type `sh scripts\reversion.sh`.
+
+We assume Unix provides the BSD err.h functions and C99 stdbool.h. The
+FreeBSD subdirectory has copies of err.c and getopt.c for systems such
+as Windows that don't have them built in.
+
+- end -
diff --git a/Makefile b/Makefile
new file mode 100644
index 000000000000..36c70283c1b7
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,58 @@
+# Makefile for unifdef
+
+prefix = ${HOME}
+bindir = ${prefix}/bin
+mandir = ${prefix}/share/man
+man1dir= ${mandir}/man1
+
+bindest= ${DESTDIR}${bindir}
+man1dest= ${DESTDIR}${man1dir}
+
+all: unifdef
+
+unifdef: unifdef.c unifdef.h version.h
+ ${CC} ${CFLAGS} ${LDFLAGS} -o unifdef unifdef.c
+
+version.h: version.sh
+version.sh::
+ scripts/reversion.sh
+
+test: unifdef
+ scripts/runtests.sh tests
+
+install: unifdef unifdefall.sh unifdef.1
+ : commands
+ install -m 755 -d ${bindest}
+ install -m 755 unifdef ${bindest}/
+ install -m 755 unifdefall.sh ${bindest}/unifdefall
+ : manual
+ install -m 755 -d ${man1dest}
+ install -m 644 unifdef.1 ${man1dest}/
+ ln -s unifdef.1 ${man1dest}/unifdefall.1
+
+clean:
+ rm -f unifdef version.h
+ rm -f tests/*.out tests/*.err tests/*.rc
+
+realclean: clean
+ rm -f unifdef.txt
+ [ ! -d .git ] || rm -f Changelog version.sh
+ find . -name .git -prune -o \( \
+ -name '*~' -o -name '.#*' -o \
+ -name '*.orig' -o -name '*.core' -o \
+ -name 'xterm-*' -o -name 'xterm.tar.gz' \
+ \) -delete
+
+DISTEXTRA= version.h version.sh unifdef.txt Changelog
+
+release: ${DISTEXTRA}
+ scripts/copycheck.sh
+ scripts/release.sh ${DISTEXTRA}
+
+unifdef.txt: unifdef.1
+ nroff -Tascii -mdoc unifdef.1 | col -bx >unifdef.txt
+
+Changelog: version.sh scripts/gitlog2changelog.sh
+ scripts/gitlog2changelog.sh >Changelog
+
+# eof
diff --git a/README b/README
new file mode 100644
index 000000000000..b40426c53708
--- /dev/null
+++ b/README
@@ -0,0 +1,52 @@
+unifdef - selectively remove C preprocessor conditionals
+
+Written by Tony Finch <dot@dotat.at> - http://dotat.at/prog/unifdef/
+
+The unifdef utility selectively processes conditional C preprocessor
+#if and #ifdef directives. It removes from a file both the directives
+and the additional text that they delimit, while otherwise leaving the
+file alone.
+
+Please see the INSTALL file for installation instructions.
+
+Pre-formatted documentation can be found in unifdef.txt
+
+You can subscribe to release announcements at:
+ http://freecode.com/projects/unifdef
+
+You can download the latest release tar and zip files from:
+ http://dotat.at/prog/unifdef
+
+You can clone the development repository using:
+ git clone http://dotat.at/git/unifdef.git
+
+I also maintain a copy at http://github.com/fanf2/unifdef
+(Warning: GitHub's zip download is incomplete and unusable.)
+
+Please send bug reports and patches to me. Unless you state otherwise,
+I will assume that any contributions are under the two-clause BSD
+licence. See the COPYING file for details.
+
+Thanks to the following people for their contributions:
+
+Bob Proulx <bob@proulx.com>
+ - test suite
+
+Jonathan Nieder <jrnieder@gmail.com>
+ - bug fixes, improved unifdefall
+
+Anders H Kaseorg <andersk@mit.edu>
+ - bug fixes and other improvements
+
+Ben Hutchings at Solarflare Communications
+ - lenient evaluation of && and ||
+
+Steve Underwood <steveu@coppice.org>
+ - read #define and #undef directives from a file
+
+Brian Ginsbach <ginsbach@netbsd.org>
+ - improved expression evaluator
+
+Other contributions are listed in the Changelog.
+
+- end -
diff --git a/scripts/authors.svn b/scripts/authors.svn
new file mode 100644
index 000000000000..7df117e2d355
--- /dev/null
+++ b/scripts/authors.svn
@@ -0,0 +1,15 @@
+charnier = Philippe Charnier <charnier@FreeBSD.org>
+dd = Dima Dorfman <dd@FreeBSD.org>
+ed = Ed Schouten <ed@FreeBSD.org>
+fanf = Tony Finch <fanf@FreeBSD.org>
+hrs = Hiroki Sato <hrs@FreeBSD.org>
+imp = Warner Losh <imp@FreeBSD.org>
+jmallett = Juli Mallett <jmallett@FreeBSD.org>
+joel = Joel Dahl <joel@FreeBSD.org>
+markm = Mark Murray <markm@FreeBSD.org>
+nik = Nik Clayton <nik@FreeBSD.org>
+obrien = David E. O'Brien <obrien@FreeBSD.org>
+peter = Peter Wemm <peter@FreeBSD.org>
+rgrimes = Rodney W. Grimes <rgrimes@FreeBSD.org>
+ru = Ruslan Ermilov <ru@FreeBSD.org>
+schweikh = Jens Schweikhardt <schweikh@FreeBSD.org>
diff --git a/scripts/copycheck.sh b/scripts/copycheck.sh
new file mode 100755
index 000000000000..c55cd1a22548
--- /dev/null
+++ b/scripts/copycheck.sh
@@ -0,0 +1,21 @@
+#!/bin/sh
+
+me=$(git config user.name || echo WHO-AM-I)
+now=$(date +%Y)
+
+! git grep -l "Copyright .* $me" |
+grep -v 'tests/.*[.]exp[a-z]*' |
+( while read f
+ do git log --format="%ci $f" -1 -- $f
+ done;
+ git log --format="%ci COPYING" -1
+) |
+grep ^$now |
+while read d t z f
+do grep -H -m 1 "Copyright .* $me" $f
+done |
+grep -v $now
+
+grep ^[.]Dd unifdef.1 | grep -v "$(date +'%B [0-9]*, %Y')"
+
+exit 0
diff --git a/scripts/fixtests.sh b/scripts/fixtests.sh
new file mode 100755
index 000000000000..a4d6a33b1cf3
--- /dev/null
+++ b/scripts/fixtests.sh
@@ -0,0 +1,9 @@
+#!/bin/sh
+
+for ext in err out rc
+do
+ for f in tests/*.$ext
+ do
+ mv $f ${f%.$ext}.exp$ext
+ done
+done
diff --git a/scripts/git.config b/scripts/git.config
new file mode 100644
index 000000000000..557c2200ba41
--- /dev/null
+++ b/scripts/git.config
@@ -0,0 +1,10 @@
+[core]
+ repositoryformatversion = 0
+[svn-remote "svn"]
+ rewriteRoot = svn://svn.FreeBSD.org/base/head/usr.bin/unifdef
+ url = svn+ssh://fanf@svn.FreeBSD.org/base/head/usr.bin/unifdef
+ fetch = :refs/remotes/git-svn
+[remote "github"]
+ url = git@github.com:fanf2/unifdef.git
+ fetch = +refs/heads/*:refs/remotes/github/*
+ fetch = +refs/pull/*/head:refs/remotes/github/pull/*
diff --git a/scripts/gitlog2changelog.sh b/scripts/gitlog2changelog.sh
new file mode 100755
index 000000000000..8d9e68f418b5
--- /dev/null
+++ b/scripts/gitlog2changelog.sh
@@ -0,0 +1,8 @@
+#!/bin/sh
+
+line="---------------------------------------------------"
+
+git log --no-merges --decorate -M --stat --pretty=format:"$line%n%ai %an <%ae>%d%n%n%s%n%n%b" |
+uniq | fold -s
+echo
+echo $line
diff --git a/scripts/release.sh b/scripts/release.sh
new file mode 100755
index 000000000000..bfdd4fc3a1e7
--- /dev/null
+++ b/scripts/release.sh
@@ -0,0 +1,18 @@
+#!/bin/sh
+
+. ./version.sh
+
+for f in $@ $(git ls-files | egrep -v '^web/|^[.]git$')
+do
+ mkdir -p web/$V/$(dirname $f)
+ cp $f web/$V/$f
+done
+
+cd web
+zip -qr $V.zip $V
+tar cf $V.tar $V
+xz -k9 $V.tar
+gzip -9 $V.tar
+rm -R $V
+
+ls -l $V.*
diff --git a/scripts/reversion.sh b/scripts/reversion.sh
new file mode 100755
index 000000000000..5098d8ad5c6f
--- /dev/null
+++ b/scripts/reversion.sh
@@ -0,0 +1,41 @@
+#!/bin/sh
+
+if [ ! -f version.sh ] && [ ! -d .git ]
+then
+ echo Your copy of unifdef is incomplete 1>&2
+ exit 1
+fi
+
+[ -f version.sh ] && . ./version.sh
+
+if [ -d .git ]
+then
+ GV=$(git describe | sed 's|-g*|.|g;s|[.]|-|')
+ git update-index -q --refresh
+ if git diff-index --quiet HEAD
+ then
+ GD="$(git show --pretty=format:%ai -s HEAD)"
+ else
+ GD="$(date +'%Y-%m-%d %H:%M:%S %z')"
+ GV=$GV.XX
+ fi
+ [ unifdef -nt unifdef.c ] &&
+ [ unifdef -nt unifdef.h ] &&
+ GD="$D"
+ if [ "$GV $GD" != "$V $D" ]
+ then
+ echo "version $V $D" 1>&2
+ echo " -> $GV $GD" 1>&2
+ V="$GV"
+ D="$GD"
+ echo "V=\"$V\"" >version.sh
+ echo "D=\"$D\"" >>version.sh
+ rm -f version.h
+ fi
+fi
+
+if [ ! -f version.h ]
+then
+ printf '"@(#) $Version: %s $\\n"\n' "$V" >version.h
+ printf '"@(#) $Date: %s $\\n"\n' "$D" >>version.h
+fi
diff --git a/scripts/runtests.sh b/scripts/runtests.sh
new file mode 100755
index 000000000000..6a2682fa4b7b
--- /dev/null
+++ b/scripts/runtests.sh
@@ -0,0 +1,33 @@
+#!/bin/sh
+
+export PATH="$(pwd):${PATH}"
+${1:+cd} ${1:-:}
+for cmd in *.sh
+do
+ printf .
+ t=${cmd%.sh}
+
+ sh ./${cmd} >${t}.out 2>${t}.err
+ echo $? >${t}.rc
+
+ ok=true
+ for e in out err rc
+ do
+ exp=${t}.exp${e}
+ got=${t}.${e}
+ if ! cmp -s ${exp} ${got}
+ then
+ echo
+ echo FAILED: ${got}: $(cat ${cmd})
+ diff -u ${exp} ${got}
+ ok=false
+ fi
+ done
+
+ if ${ok}
+ then rm -f ${t}.out ${t}.err ${t}.rc
+ else rc=1
+ fi
+done
+echo
+exit ${rc}
diff --git a/scripts/svnup.sh b/scripts/svnup.sh
new file mode 100755
index 000000000000..51702df18633
--- /dev/null
+++ b/scripts/svnup.sh
@@ -0,0 +1,12 @@
+#!/bin/sh -e
+
+git svn fetch -A scripts/authors.svn
+
+git checkout FreeBSD
+
+case "$(git merge --no-commit git-svn)" in
+"Already up-to-date.")
+ exit 0
+esac
+
+git commit -m 'Merge back from svn'
diff --git a/scripts/upload.sh b/scripts/upload.sh
new file mode 100755
index 000000000000..b55616d03f02
--- /dev/null
+++ b/scripts/upload.sh
@@ -0,0 +1,19 @@
+#!/bin/sh -e
+
+make unifdef.txt
+cp unifdef.txt web
+
+git gc --aggressive
+git update-server-info
+git push --all github
+git push --tags github
+
+# for gitweb
+echo "selectively remove C preprocessor conditionals" >.git/description
+echo "Homepage: <a href='http://dotat.at/prog/unifdef'>http://dotat.at/prog/unifdef</a>" >.git/README.html
+
+touch .git/git-daemon-export-ok
+rsync --recursive --links --delete .git/ chiark:public-git/unifdef.git/
+rsync --recursive --links web/ chiark:public-html/prog/unifdef/
+
+exit
diff --git a/tests/NetBSD-42628.c b/tests/NetBSD-42628.c
new file mode 100644
index 000000000000..9de6a94a0773
--- /dev/null
+++ b/tests/NetBSD-42628.c
@@ -0,0 +1,25 @@
+#if defined(__FreeBSD__)
+#include <netinet/if_fddi.h>
+#else
+#include <net/if_fddi.h>
+#endif
+
+#if defined(__FreeBSD__)
+ #include <stdbool.h>
+ #include <stdbool.h>
+ #include <stdbool.h>
+ #include <stdbool.h>
+ #include <stdbool.h>
+ #include <stdbool.h>
+#else
+#include <stdint.h>
+#endif
+
+#if defined(__FreeBSD__)
+#endif
+
+#ifdef __FreeBSD__
+#include <unistd.h>
+#else
+#include <inttypes.h>
+#endif
diff --git a/tests/NetBSD-42628.experr b/tests/NetBSD-42628.experr
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/tests/NetBSD-42628.experr
diff --git a/tests/NetBSD-42628.expout b/tests/NetBSD-42628.expout
new file mode 100644
index 000000000000..2d52e9e7ae29
--- /dev/null
+++ b/tests/NetBSD-42628.expout
@@ -0,0 +1,6 @@
+#include <net/if_fddi.h>
+
+#include <stdint.h>
+
+
+#include <inttypes.h>
diff --git a/tests/NetBSD-42628.exprc b/tests/NetBSD-42628.exprc
new file mode 100644
index 000000000000..d00491fd7e5b
--- /dev/null
+++ b/tests/NetBSD-42628.exprc
@@ -0,0 +1 @@
+1
diff --git a/tests/NetBSD-42628.sh b/tests/NetBSD-42628.sh
new file mode 100644
index 000000000000..87ac1aa9c4e8
--- /dev/null
+++ b/tests/NetBSD-42628.sh
@@ -0,0 +1 @@
+unifdef -U__FreeBSD__ NetBSD-42628.c
diff --git a/tests/NetBSD-47068.c b/tests/NetBSD-47068.c
new file mode 100644
index 000000000000..515f50b6eafd
--- /dev/null
+++ b/tests/NetBSD-47068.c
@@ -0,0 +1,2 @@
+#ifdef foo
+#endif \ No newline at end of file
diff --git a/tests/NetBSD-47068.experr b/tests/NetBSD-47068.experr
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/tests/NetBSD-47068.experr
diff --git a/tests/NetBSD-47068.expout b/tests/NetBSD-47068.expout
new file mode 100644
index 000000000000..1fb9d525074e
--- /dev/null
+++ b/tests/NetBSD-47068.expout
@@ -0,0 +1,2 @@
+#ifdef foo
+#endif
diff --git a/tests/NetBSD-47068.exprc b/tests/NetBSD-47068.exprc
new file mode 100644
index 000000000000..573541ac9702
--- /dev/null
+++ b/tests/NetBSD-47068.exprc
@@ -0,0 +1 @@
+0
diff --git a/tests/NetBSD-47068.sh b/tests/NetBSD-47068.sh
new file mode 100644
index 000000000000..2ec1bbef00a1
--- /dev/null
+++ b/tests/NetBSD-47068.sh
@@ -0,0 +1 @@
+unifdef -Ubar NetBSD-47068.c
diff --git a/tests/args1.c b/tests/args1.c
new file mode 100644
index 000000000000..1cb554688c37
--- /dev/null
+++ b/tests/args1.c
@@ -0,0 +1,3 @@
+#if defined(DUMMY) || FOO(arg)
+hello
+#endif
diff --git a/tests/args1.experr b/tests/args1.experr
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/tests/args1.experr
diff --git a/tests/args1.expout b/tests/args1.expout
new file mode 100644
index 000000000000..ce013625030b
--- /dev/null
+++ b/tests/args1.expout
@@ -0,0 +1 @@
+hello
diff --git a/tests/args1.exprc b/tests/args1.exprc
new file mode 100644
index 000000000000..d00491fd7e5b
--- /dev/null
+++ b/tests/args1.exprc
@@ -0,0 +1 @@
+1
diff --git a/tests/args1.sh b/tests/args1.sh
new file mode 100644
index 000000000000..051baf41118a
--- /dev/null
+++ b/tests/args1.sh
@@ -0,0 +1 @@
+unifdef -DFOO=1 -DFOOB=42 -UBAR args1.c
diff --git a/tests/args2.c b/tests/args2.c
new file mode 100644
index 000000000000..8fe476b18ee2
--- /dev/null
+++ b/tests/args2.c
@@ -0,0 +1,3 @@
+#if defined(FOO) || BAR(arg)
+hello
+#endif
diff --git a/tests/args2.experr b/tests/args2.experr
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/tests/args2.experr
diff --git a/tests/args2.expout b/tests/args2.expout
new file mode 100644
index 000000000000..8fe476b18ee2
--- /dev/null
+++ b/tests/args2.expout
@@ -0,0 +1,3 @@
+#if defined(FOO) || BAR(arg)
+hello
+#endif
diff --git a/tests/args2.exprc b/tests/args2.exprc
new file mode 100644
index 000000000000..573541ac9702
--- /dev/null
+++ b/tests/args2.exprc
@@ -0,0 +1 @@
+0
diff --git a/tests/args2.sh b/tests/args2.sh
new file mode 100644
index 000000000000..19fb26136b0b
--- /dev/null
+++ b/tests/args2.sh
@@ -0,0 +1 @@
+unifdef -DFOO=1 -DFOOB=42 -UBAR args2.c
diff --git a/tests/blank0d.c b/tests/blank0d.c
new file mode 100644
index 000000000000..c435ac5b6224
--- /dev/null
+++ b/tests/blank0d.c
@@ -0,0 +1,25 @@
+#ifdef FOO4
+four
+#endif
+
+
+
+
+#ifdef FOO3
+three
+#endif
+
+
+
+#ifdef FOO2
+two
+#endif
+
+
+#ifdef FOO1
+one
+#endif
+
+#ifdef FOO0
+zero
+#endif
diff --git a/tests/blank0d.experr b/tests/blank0d.experr
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/tests/blank0d.experr
diff --git a/tests/blank0d.expout b/tests/blank0d.expout
new file mode 100644
index 000000000000..9c2261485ba5
--- /dev/null
+++ b/tests/blank0d.expout
@@ -0,0 +1,23 @@
+#ifdef FOO4
+four
+#endif
+
+
+
+
+#ifdef FOO3
+three
+#endif
+
+
+
+#ifdef FOO2
+two
+#endif
+
+
+#ifdef FOO1
+one
+#endif
+
+zero
diff --git a/tests/blank0d.exprc b/tests/blank0d.exprc
new file mode 100644
index 000000000000..d00491fd7e5b
--- /dev/null
+++ b/tests/blank0d.exprc
@@ -0,0 +1 @@
+1
diff --git a/tests/blank0d.sh b/tests/blank0d.sh
new file mode 100644
index 000000000000..f0af220989d1
--- /dev/null
+++ b/tests/blank0d.sh
@@ -0,0 +1 @@
+unifdef -B -DFOO0 blank0d.c
diff --git a/tests/blank0u.c b/tests/blank0u.c
new file mode 100644
index 000000000000..c435ac5b6224
--- /dev/null
+++ b/tests/blank0u.c
@@ -0,0 +1,25 @@
+#ifdef FOO4
+four
+#endif
+
+
+
+
+#ifdef FOO3
+three
+#endif
+
+
+
+#ifdef FOO2
+two
+#endif
+
+
+#ifdef FOO1
+one
+#endif
+
+#ifdef FOO0
+zero
+#endif
diff --git a/tests/blank0u.experr b/tests/blank0u.experr
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/tests/blank0u.experr
diff --git a/tests/blank0u.expout b/tests/blank0u.expout
new file mode 100644
index 000000000000..165d0a903525
--- /dev/null
+++ b/tests/blank0u.expout
@@ -0,0 +1,22 @@
+#ifdef FOO4
+four
+#endif
+
+
+
+
+#ifdef FOO3
+three
+#endif
+
+
+
+#ifdef FOO2
+two
+#endif
+
+
+#ifdef FOO1
+one
+#endif
+
diff --git a/tests/blank0u.exprc b/tests/blank0u.exprc
new file mode 100644
index 000000000000..d00491fd7e5b
--- /dev/null
+++ b/tests/blank0u.exprc
@@ -0,0 +1 @@
+1
diff --git a/tests/blank0u.sh b/tests/blank0u.sh
new file mode 100644
index 000000000000..22a8360282c2
--- /dev/null
+++ b/tests/blank0u.sh
@@ -0,0 +1 @@
+unifdef -B -UFOO0 blank0u.c
diff --git a/tests/blank1d.c b/tests/blank1d.c
new file mode 100644
index 000000000000..c435ac5b6224
--- /dev/null
+++ b/tests/blank1d.c
@@ -0,0 +1,25 @@
+#ifdef FOO4
+four
+#endif
+
+
+
+
+#ifdef FOO3
+three
+#endif
+
+
+
+#ifdef FOO2
+two
+#endif
+
+
+#ifdef FOO1
+one
+#endif
+
+#ifdef FOO0
+zero
+#endif
diff --git a/tests/blank1d.experr b/tests/blank1d.experr
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/tests/blank1d.experr
diff --git a/tests/blank1d.expout b/tests/blank1d.expout
new file mode 100644
index 000000000000..05f6bc538b88
--- /dev/null
+++ b/tests/blank1d.expout
@@ -0,0 +1,23 @@
+#ifdef FOO4
+four
+#endif
+
+
+
+
+#ifdef FOO3
+three
+#endif
+
+
+
+#ifdef FOO2
+two
+#endif
+
+
+one
+
+#ifdef FOO0
+zero
+#endif
diff --git a/tests/blank1d.exprc b/tests/blank1d.exprc
new file mode 100644
index 000000000000..d00491fd7e5b
--- /dev/null
+++ b/tests/blank1d.exprc
@@ -0,0 +1 @@
+1
diff --git a/tests/blank1d.sh b/tests/blank1d.sh
new file mode 100644
index 000000000000..4820efd723b9
--- /dev/null
+++ b/tests/blank1d.sh
@@ -0,0 +1 @@
+unifdef -B -DFOO1 blank1d.c
diff --git a/tests/blank1u.c b/tests/blank1u.c
new file mode 100644
index 000000000000..c435ac5b6224
--- /dev/null
+++ b/tests/blank1u.c
@@ -0,0 +1,25 @@
+#ifdef FOO4
+four
+#endif
+
+
+
+
+#ifdef FOO3
+three
+#endif
+
+
+
+#ifdef FOO2
+two
+#endif
+
+
+#ifdef FOO1
+one
+#endif
+
+#ifdef FOO0
+zero
+#endif
diff --git a/tests/blank1u.experr b/tests/blank1u.experr
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/tests/blank1u.experr
diff --git a/tests/blank1u.expout b/tests/blank1u.expout
new file mode 100644
index 000000000000..f79337918e0e
--- /dev/null
+++ b/tests/blank1u.expout
@@ -0,0 +1,21 @@
+#ifdef FOO4
+four
+#endif
+
+
+
+
+#ifdef FOO3
+three
+#endif
+
+
+
+#ifdef FOO2
+two
+#endif
+
+
+#ifdef FOO0
+zero
+#endif
diff --git a/tests/blank1u.exprc b/tests/blank1u.exprc
new file mode 100644
index 000000000000..d00491fd7e5b
--- /dev/null
+++ b/tests/blank1u.exprc
@@ -0,0 +1 @@
+1
diff --git a/tests/blank1u.sh b/tests/blank1u.sh
new file mode 100644
index 000000000000..1dbd849b018f
--- /dev/null
+++ b/tests/blank1u.sh
@@ -0,0 +1 @@
+unifdef -B -UFOO1 blank1u.c
diff --git a/tests/blank2d.c b/tests/blank2d.c
new file mode 100644
index 000000000000..c435ac5b6224
--- /dev/null
+++ b/tests/blank2d.c
@@ -0,0 +1,25 @@
+#ifdef FOO4
+four
+#endif
+
+
+
+
+#ifdef FOO3
+three
+#endif
+
+
+
+#ifdef FOO2
+two
+#endif
+
+
+#ifdef FOO1
+one
+#endif
+
+#ifdef FOO0
+zero
+#endif
diff --git a/tests/blank2d.experr b/tests/blank2d.experr
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/tests/blank2d.experr
diff --git a/tests/blank2d.expout b/tests/blank2d.expout
new file mode 100644
index 000000000000..ba127f52e4f1
--- /dev/null
+++ b/tests/blank2d.expout
@@ -0,0 +1,23 @@
+#ifdef FOO4
+four
+#endif
+
+
+
+
+#ifdef FOO3
+three
+#endif
+
+
+
+two
+
+
+#ifdef FOO1
+one
+#endif
+
+#ifdef FOO0
+zero
+#endif
diff --git a/tests/blank2d.exprc b/tests/blank2d.exprc
new file mode 100644
index 000000000000..d00491fd7e5b
--- /dev/null
+++ b/tests/blank2d.exprc
@@ -0,0 +1 @@
+1
diff --git a/tests/blank2d.sh b/tests/blank2d.sh
new file mode 100644
index 000000000000..a38cb0cee808
--- /dev/null
+++ b/tests/blank2d.sh
@@ -0,0 +1 @@
+unifdef -B -DFOO2 blank2d.c
diff --git a/tests/blank2u.c b/tests/blank2u.c
new file mode 100644
index 000000000000..c435ac5b6224
--- /dev/null
+++ b/tests/blank2u.c
@@ -0,0 +1,25 @@
+#ifdef FOO4
+four
+#endif
+
+
+
+
+#ifdef FOO3
+three
+#endif
+
+
+
+#ifdef FOO2
+two
+#endif
+
+
+#ifdef FOO1
+one
+#endif
+
+#ifdef FOO0
+zero
+#endif
diff --git a/tests/blank2u.experr b/tests/blank2u.experr
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/tests/blank2u.experr
diff --git a/tests/blank2u.expout b/tests/blank2u.expout
new file mode 100644
index 000000000000..cee6dd72eb9a
--- /dev/null
+++ b/tests/blank2u.expout
@@ -0,0 +1,20 @@
+#ifdef FOO4
+four
+#endif
+
+
+
+
+#ifdef FOO3
+three
+#endif
+
+
+
+#ifdef FOO1
+one
+#endif
+
+#ifdef FOO0
+zero
+#endif
diff --git a/tests/blank2u.exprc b/tests/blank2u.exprc
new file mode 100644
index 000000000000..d00491fd7e5b
--- /dev/null
+++ b/tests/blank2u.exprc
@@ -0,0 +1 @@
+1
diff --git a/tests/blank2u.sh b/tests/blank2u.sh
new file mode 100644
index 000000000000..70b5440fe28c
--- /dev/null
+++ b/tests/blank2u.sh
@@ -0,0 +1 @@
+unifdef -B -UFOO2 blank2u.c
diff --git a/tests/blank3d.c b/tests/blank3d.c
new file mode 100644
index 000000000000..c435ac5b6224
--- /dev/null
+++ b/tests/blank3d.c
@@ -0,0 +1,25 @@
+#ifdef FOO4
+four
+#endif
+
+
+
+
+#ifdef FOO3
+three
+#endif
+
+
+
+#ifdef FOO2
+two
+#endif
+
+
+#ifdef FOO1
+one
+#endif
+
+#ifdef FOO0
+zero
+#endif
diff --git a/tests/blank3d.experr b/tests/blank3d.experr
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/tests/blank3d.experr
diff --git a/tests/blank3d.expout b/tests/blank3d.expout
new file mode 100644
index 000000000000..31a633a0ea57
--- /dev/null
+++ b/tests/blank3d.expout
@@ -0,0 +1,23 @@
+#ifdef FOO4
+four
+#endif
+
+
+
+
+three
+
+
+
+#ifdef FOO2
+two
+#endif
+
+
+#ifdef FOO1
+one
+#endif
+
+#ifdef FOO0
+zero
+#endif
diff --git a/tests/blank3d.exprc b/tests/blank3d.exprc
new file mode 100644
index 000000000000..d00491fd7e5b
--- /dev/null
+++ b/tests/blank3d.exprc
@@ -0,0 +1 @@
+1
diff --git a/tests/blank3d.sh b/tests/blank3d.sh
new file mode 100644
index 000000000000..8e71cbec759f
--- /dev/null
+++ b/tests/blank3d.sh
@@ -0,0 +1 @@
+unifdef -B -DFOO3 blank3d.c
diff --git a/tests/blank3u.c b/tests/blank3u.c
new file mode 100644
index 000000000000..c435ac5b6224
--- /dev/null
+++ b/tests/blank3u.c
@@ -0,0 +1,25 @@
+#ifdef FOO4
+four
+#endif
+
+
+
+
+#ifdef FOO3
+three
+#endif
+
+
+
+#ifdef FOO2
+two
+#endif
+
+
+#ifdef FOO1
+one
+#endif
+
+#ifdef FOO0
+zero
+#endif
diff --git a/tests/blank3u.experr b/tests/blank3u.experr
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/tests/blank3u.experr
diff --git a/tests/blank3u.expout b/tests/blank3u.expout
new file mode 100644
index 000000000000..d90cca9c6168
--- /dev/null
+++ b/tests/blank3u.expout
@@ -0,0 +1,19 @@
+#ifdef FOO4
+four
+#endif
+
+
+
+
+#ifdef FOO2
+two
+#endif
+
+
+#ifdef FOO1
+one
+#endif
+
+#ifdef FOO0
+zero
+#endif
diff --git a/tests/blank3u.exprc b/tests/blank3u.exprc
new file mode 100644
index 000000000000..d00491fd7e5b
--- /dev/null
+++ b/tests/blank3u.exprc
@@ -0,0 +1 @@
+1
diff --git a/tests/blank3u.sh b/tests/blank3u.sh
new file mode 100644
index 000000000000..c1e8f20d2bc8
--- /dev/null
+++ b/tests/blank3u.sh
@@ -0,0 +1 @@
+unifdef -B -UFOO3 blank3u.c
diff --git a/tests/blank4d.c b/tests/blank4d.c
new file mode 100644
index 000000000000..c435ac5b6224
--- /dev/null
+++ b/tests/blank4d.c
@@ -0,0 +1,25 @@
+#ifdef FOO4
+four
+#endif
+
+
+
+
+#ifdef FOO3
+three
+#endif
+
+
+
+#ifdef FOO2
+two
+#endif
+
+
+#ifdef FOO1
+one
+#endif
+
+#ifdef FOO0
+zero
+#endif
diff --git a/tests/blank4d.experr b/tests/blank4d.experr
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/tests/blank4d.experr
diff --git a/tests/blank4d.expout b/tests/blank4d.expout
new file mode 100644
index 000000000000..782ff9d74faf
--- /dev/null
+++ b/tests/blank4d.expout
@@ -0,0 +1,23 @@
+four
+
+
+
+
+#ifdef FOO3
+three
+#endif
+
+
+
+#ifdef FOO2
+two
+#endif
+
+
+#ifdef FOO1
+one
+#endif
+
+#ifdef FOO0
+zero
+#endif
diff --git a/tests/blank4d.exprc b/tests/blank4d.exprc
new file mode 100644
index 000000000000..d00491fd7e5b
--- /dev/null
+++ b/tests/blank4d.exprc
@@ -0,0 +1 @@
+1
diff --git a/tests/blank4d.sh b/tests/blank4d.sh
new file mode 100644
index 000000000000..9471b63f06f5
--- /dev/null
+++ b/tests/blank4d.sh
@@ -0,0 +1 @@
+unifdef -B -DFOO4 blank4d.c
diff --git a/tests/blank4u.c b/tests/blank4u.c
new file mode 100644
index 000000000000..c435ac5b6224
--- /dev/null
+++ b/tests/blank4u.c
@@ -0,0 +1,25 @@
+#ifdef FOO4
+four
+#endif
+
+
+
+
+#ifdef FOO3
+three
+#endif
+
+
+
+#ifdef FOO2
+two
+#endif
+
+
+#ifdef FOO1
+one
+#endif
+
+#ifdef FOO0
+zero
+#endif
diff --git a/tests/blank4u.experr b/tests/blank4u.experr
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/tests/blank4u.experr
diff --git a/tests/blank4u.expout b/tests/blank4u.expout
new file mode 100644
index 000000000000..72f0fa7987fd
--- /dev/null
+++ b/tests/blank4u.expout
@@ -0,0 +1,18 @@
+#ifdef FOO3
+three
+#endif
+
+
+
+#ifdef FOO2
+two
+#endif
+
+
+#ifdef FOO1
+one
+#endif
+
+#ifdef FOO0
+zero
+#endif
diff --git a/tests/blank4u.exprc b/tests/blank4u.exprc
new file mode 100644
index 000000000000..d00491fd7e5b
--- /dev/null
+++ b/tests/blank4u.exprc
@@ -0,0 +1 @@
+1
diff --git a/tests/blank4u.sh b/tests/blank4u.sh
new file mode 100644
index 000000000000..16065df4669f
--- /dev/null
+++ b/tests/blank4u.sh
@@ -0,0 +1 @@
+unifdef -B -UFOO4 blank4u.c
diff --git a/tests/broken2.h b/tests/broken2.h
new file mode 100644
index 000000000000..4221f04abf3b
--- /dev/null
+++ b/tests/broken2.h
@@ -0,0 +1 @@
+#define /* nothing */
diff --git a/tests/broken3.h b/tests/broken3.h
new file mode 100644
index 000000000000..c7c82c1bd8bf
--- /dev/null
+++ b/tests/broken3.h
@@ -0,0 +1 @@
+#undef &%^$&%$##@^$
diff --git a/tests/broken4.h b/tests/broken4.h
new file mode 100644
index 000000000000..138cf65b583a
--- /dev/null
+++ b/tests/broken4.h
@@ -0,0 +1,2 @@
+#define FOO \
+ bar
diff --git a/tests/crlf-a.experr b/tests/crlf-a.experr
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/tests/crlf-a.experr
diff --git a/tests/crlf-a.expout b/tests/crlf-a.expout
new file mode 100644
index 000000000000..29e1b63ab239
--- /dev/null
+++ b/tests/crlf-a.expout
@@ -0,0 +1,10 @@
+int f1() { return 0; }
+\/
+/\
+comment
+/\
+*\
+comment
+*\
+/\
+eof
diff --git a/tests/crlf-a.exprc b/tests/crlf-a.exprc
new file mode 100644
index 000000000000..d00491fd7e5b
--- /dev/null
+++ b/tests/crlf-a.exprc
@@ -0,0 +1 @@
+1
diff --git a/tests/crlf-a.sh b/tests/crlf-a.sh
new file mode 100644
index 000000000000..2acc2bfa0488
--- /dev/null
+++ b/tests/crlf-a.sh
@@ -0,0 +1 @@
+unifdef -DF1 crlf.c
diff --git a/tests/crlf-b.experr b/tests/crlf-b.experr
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/tests/crlf-b.experr
diff --git a/tests/crlf-b.expout b/tests/crlf-b.expout
new file mode 100644
index 000000000000..011b81a6cedd
--- /dev/null
+++ b/tests/crlf-b.expout
@@ -0,0 +1,14 @@
+#if F1
+int f1() { return 0; }
+#else
+int f2() { return 0; }
+#endif
+\/
+/\
+comment
+/\
+*\
+comment
+*\
+/\
+eof
diff --git a/tests/crlf-b.exprc b/tests/crlf-b.exprc
new file mode 100644
index 000000000000..d00491fd7e5b
--- /dev/null
+++ b/tests/crlf-b.exprc
@@ -0,0 +1 @@
+1
diff --git a/tests/crlf-b.sh b/tests/crlf-b.sh
new file mode 100644
index 000000000000..57d9de5f7c34
--- /dev/null
+++ b/tests/crlf-b.sh
@@ -0,0 +1 @@
+unifdef -DF2 crlf.c
diff --git a/tests/crlf-c.experr b/tests/crlf-c.experr
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/tests/crlf-c.experr
diff --git a/tests/crlf-c.expout b/tests/crlf-c.expout
new file mode 100644
index 000000000000..f9fdaf832c7f
--- /dev/null
+++ b/tests/crlf-c.expout
@@ -0,0 +1,16 @@
+#if F1
+int f1() { return 0; }
+#elif F2
+int f2() { return 0; }
+#else
+int f3() { return 0; }
+#endif
+\/
+/\
+comment
+/\
+*\
+comment
+*\
+/\
+eof
diff --git a/tests/crlf-c.exprc b/tests/crlf-c.exprc
new file mode 100644
index 000000000000..d00491fd7e5b
--- /dev/null
+++ b/tests/crlf-c.exprc
@@ -0,0 +1 @@
+1
diff --git a/tests/crlf-c.sh b/tests/crlf-c.sh
new file mode 100644
index 000000000000..ad6f131379bb
--- /dev/null
+++ b/tests/crlf-c.sh
@@ -0,0 +1 @@
+unifdef -DF3 crlf.c
diff --git a/tests/crlf-d.experr b/tests/crlf-d.experr
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/tests/crlf-d.experr
diff --git a/tests/crlf-d.expout b/tests/crlf-d.expout
new file mode 100644
index 000000000000..295d337d5c74
--- /dev/null
+++ b/tests/crlf-d.expout
@@ -0,0 +1,18 @@
+#if F1
+int f1() { return 0; }
+#elif F2
+int f2() { return 0; }
+#elif F3
+int f3() { return 0; }
+#else
+int f4() { return 0; }
+#endif
+\/
+/\
+comment
+/\
+*\
+comment
+*\
+/\
+eof
diff --git a/tests/crlf-d.exprc b/tests/crlf-d.exprc
new file mode 100644
index 000000000000..d00491fd7e5b
--- /dev/null
+++ b/tests/crlf-d.exprc
@@ -0,0 +1 @@
+1
diff --git a/tests/crlf-d.sh b/tests/crlf-d.sh
new file mode 100644
index 000000000000..719c05b6df46
--- /dev/null
+++ b/tests/crlf-d.sh
@@ -0,0 +1 @@
+unifdef -DF4 crlf.c
diff --git a/tests/crlf.c b/tests/crlf.c
new file mode 100644
index 000000000000..ad911dc63a32
--- /dev/null
+++ b/tests/crlf.c
@@ -0,0 +1,20 @@
+#if F1
+int f1() { return 0; }
+#elif F2
+int f2() { return 0; }
+#elif F3
+int f3() { return 0; }
+#elif F4
+int f4() { return 0; }
+#else
+int f() { return 0; }
+#endif
+\/
+/\
+comment
+/\
+*\
+comment
+*\
+/\
+eof
diff --git a/tests/debian-603860.c b/tests/debian-603860.c
new file mode 100644
index 000000000000..ae40ce1809c1
--- /dev/null
+++ b/tests/debian-603860.c
@@ -0,0 +1,8 @@
+#ifdef FOO
+int a;
+#endif
+char foo[] = "rm -rf /*";
+#ifdef FOO
+int b;
+#endif
+/* baz */
diff --git a/tests/debian-603860.experr b/tests/debian-603860.experr
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/tests/debian-603860.experr
diff --git a/tests/debian-603860.expout b/tests/debian-603860.expout
new file mode 100644
index 000000000000..e04772cc230b
--- /dev/null
+++ b/tests/debian-603860.expout
@@ -0,0 +1,2 @@
+char foo[] = "rm -rf /*";
+/* baz */
diff --git a/tests/debian-603860.exprc b/tests/debian-603860.exprc
new file mode 100644
index 000000000000..d00491fd7e5b
--- /dev/null
+++ b/tests/debian-603860.exprc
@@ -0,0 +1 @@
+1
diff --git a/tests/debian-603860.sh b/tests/debian-603860.sh
new file mode 100644
index 000000000000..b77ae9cc10e3
--- /dev/null
+++ b/tests/debian-603860.sh
@@ -0,0 +1 @@
+unifdef -UFOO debian-603860.c
diff --git a/tests/defundef-broken2.experr b/tests/defundef-broken2.experr
new file mode 100644
index 000000000000..fdfd6e237c23
--- /dev/null
+++ b/tests/defundef-broken2.experr
@@ -0,0 +1,2 @@
+unifdef: broken2.h: 1: Missing macro name in #define
+unifdef: Output may be truncated
diff --git a/tests/defundef-broken2.expout b/tests/defundef-broken2.expout
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/tests/defundef-broken2.expout
diff --git a/tests/defundef-broken2.exprc b/tests/defundef-broken2.exprc
new file mode 100644
index 000000000000..0cfbf08886fc
--- /dev/null
+++ b/tests/defundef-broken2.exprc
@@ -0,0 +1 @@
+2
diff --git a/tests/defundef-broken2.sh b/tests/defundef-broken2.sh
new file mode 100644
index 000000000000..16c7384d8cdd
--- /dev/null
+++ b/tests/defundef-broken2.sh
@@ -0,0 +1 @@
+unifdef -f broken2.h if1.c
diff --git a/tests/defundef-broken3.experr b/tests/defundef-broken3.experr
new file mode 100644
index 000000000000..0b0b63a4b71c
--- /dev/null
+++ b/tests/defundef-broken3.experr
@@ -0,0 +1,2 @@
+unifdef: broken3.h: 1: Missing macro name in #undef
+unifdef: Output may be truncated
diff --git a/tests/defundef-broken3.expout b/tests/defundef-broken3.expout
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/tests/defundef-broken3.expout
diff --git a/tests/defundef-broken3.exprc b/tests/defundef-broken3.exprc
new file mode 100644
index 000000000000..0cfbf08886fc
--- /dev/null
+++ b/tests/defundef-broken3.exprc
@@ -0,0 +1 @@
+2
diff --git a/tests/defundef-broken3.sh b/tests/defundef-broken3.sh
new file mode 100644
index 000000000000..123e725715dd
--- /dev/null
+++ b/tests/defundef-broken3.sh
@@ -0,0 +1 @@
+unifdef -f broken3.h if1.c
diff --git a/tests/defundef-broken4.experr b/tests/defundef-broken4.experr
new file mode 100644
index 000000000000..65c0ad5ad240
--- /dev/null
+++ b/tests/defundef-broken4.experr
@@ -0,0 +1,2 @@
+unifdef: broken4.h: 1: Obfuscated preprocessor control line
+unifdef: Output may be truncated
diff --git a/tests/defundef-broken4.expout b/tests/defundef-broken4.expout
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/tests/defundef-broken4.expout
diff --git a/tests/defundef-broken4.exprc b/tests/defundef-broken4.exprc
new file mode 100644
index 000000000000..0cfbf08886fc
--- /dev/null
+++ b/tests/defundef-broken4.exprc
@@ -0,0 +1 @@
+2
diff --git a/tests/defundef-broken4.sh b/tests/defundef-broken4.sh
new file mode 100644
index 000000000000..1c85536f7c58
--- /dev/null
+++ b/tests/defundef-broken4.sh
@@ -0,0 +1 @@
+unifdef -f broken4.h if1.c
diff --git a/tests/defundef-funlike.experr b/tests/defundef-funlike.experr
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/tests/defundef-funlike.experr
diff --git a/tests/defundef-funlike.expout b/tests/defundef-funlike.expout
new file mode 100644
index 000000000000..b64cfc265bd2
--- /dev/null
+++ b/tests/defundef-funlike.expout
@@ -0,0 +1,13 @@
+/* Copyright 2004 Bob Proulx <bob@proulx.com>
+Distributed under the two-clause BSD licence;
+see the COPYING file for details. */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+int foo() { return 0; }
+
+int main()
+{
+ foo();
+}
diff --git a/tests/defundef-funlike.exprc b/tests/defundef-funlike.exprc
new file mode 100644
index 000000000000..d00491fd7e5b
--- /dev/null
+++ b/tests/defundef-funlike.exprc
@@ -0,0 +1 @@
+1
diff --git a/tests/defundef-funlike.sh b/tests/defundef-funlike.sh
new file mode 100644
index 000000000000..91c91af4cd0b
--- /dev/null
+++ b/tests/defundef-funlike.sh
@@ -0,0 +1 @@
+unifdef -f funlike.h small1.c
diff --git a/tests/defundef-undefdef.experr b/tests/defundef-undefdef.experr
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/tests/defundef-undefdef.experr
diff --git a/tests/defundef-undefdef.expout b/tests/defundef-undefdef.expout
new file mode 100644
index 000000000000..c51d7a6bec42
--- /dev/null
+++ b/tests/defundef-undefdef.expout
@@ -0,0 +1 @@
+int f1() { return 0; }
diff --git a/tests/defundef-undefdef.exprc b/tests/defundef-undefdef.exprc
new file mode 100644
index 000000000000..d00491fd7e5b
--- /dev/null
+++ b/tests/defundef-undefdef.exprc
@@ -0,0 +1 @@
+1
diff --git a/tests/defundef-undefdef.sh b/tests/defundef-undefdef.sh
new file mode 100644
index 000000000000..4af30c7f1eba
--- /dev/null
+++ b/tests/defundef-undefdef.sh
@@ -0,0 +1 @@
+unifdef -f if6.h if6.c
diff --git a/tests/div.c b/tests/div.c
new file mode 100644
index 000000000000..f825bec5effd
--- /dev/null
+++ b/tests/div.c
@@ -0,0 +1,3 @@
+#if 10 / DENOM
+DIVISION
+#endif
diff --git a/tests/div.experr b/tests/div.experr
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/tests/div.experr
diff --git a/tests/div.expout b/tests/div.expout
new file mode 100644
index 000000000000..769481fd8910
--- /dev/null
+++ b/tests/div.expout
@@ -0,0 +1,10 @@
+undef
+#if 10 / DENOM
+DIVISION
+#endif
+one
+DIVISION
+zero
+#if 10 / DENOM
+DIVISION
+#endif
diff --git a/tests/div.exprc b/tests/div.exprc
new file mode 100644
index 000000000000..573541ac9702
--- /dev/null
+++ b/tests/div.exprc
@@ -0,0 +1 @@
+0
diff --git a/tests/div.sh b/tests/div.sh
new file mode 100644
index 000000000000..f526f9f1a1ca
--- /dev/null
+++ b/tests/div.sh
@@ -0,0 +1,10 @@
+echo undef
+if ! unifdef div.c
+then unifdef -d div.c
+fi
+echo one
+unifdef -DDENOM div.c
+echo zero
+if ! unifdef -UDENOM div.c
+then unifdef -d -UDENOM div.c
+fi
diff --git a/tests/empty.c b/tests/empty.c
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/tests/empty.c
diff --git a/tests/empty.experr b/tests/empty.experr
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/tests/empty.experr
diff --git a/tests/empty.expout b/tests/empty.expout
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/tests/empty.expout
diff --git a/tests/empty.exprc b/tests/empty.exprc
new file mode 100644
index 000000000000..573541ac9702
--- /dev/null
+++ b/tests/empty.exprc
@@ -0,0 +1 @@
+0
diff --git a/tests/empty.sh b/tests/empty.sh
new file mode 100644
index 000000000000..c2dd1671d623
--- /dev/null
+++ b/tests/empty.sh
@@ -0,0 +1 @@
+unifdef -DFOO=1 -DFOOB=42 -UBAR empty.c
diff --git a/tests/error.c b/tests/error.c
new file mode 100644
index 000000000000..7cd15e7d966a
--- /dev/null
+++ b/tests/error.c
@@ -0,0 +1,4 @@
+#if FOO != 5
+#error
+#endif
+bar
diff --git a/tests/error.experr b/tests/error.experr
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/tests/error.experr
diff --git a/tests/error.expout b/tests/error.expout
new file mode 100644
index 000000000000..274284345ca2
--- /dev/null
+++ b/tests/error.expout
@@ -0,0 +1,2 @@
+#error
+bar
diff --git a/tests/error.exprc b/tests/error.exprc
new file mode 100644
index 000000000000..d00491fd7e5b
--- /dev/null
+++ b/tests/error.exprc
@@ -0,0 +1 @@
+1
diff --git a/tests/error.sh b/tests/error.sh
new file mode 100644
index 000000000000..1267f0f0d603
--- /dev/null
+++ b/tests/error.sh
@@ -0,0 +1 @@
+unifdef -DFOO=1 error.c
diff --git a/tests/exitmode0a.experr b/tests/exitmode0a.experr
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/tests/exitmode0a.experr
diff --git a/tests/exitmode0a.expout b/tests/exitmode0a.expout
new file mode 100644
index 000000000000..56ae03cc38de
--- /dev/null
+++ b/tests/exitmode0a.expout
@@ -0,0 +1,16 @@
+/* Copyright 2004 Bob Proulx <bob@proulx.com>
+Distributed under the two-clause BSD licence;
+see the COPYING file for details. */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+int foo() { return 0; }
+
+int bar() { return 0; }
+
+int main()
+{
+ foo();
+ bar();
+}
diff --git a/tests/exitmode0a.exprc b/tests/exitmode0a.exprc
new file mode 100644
index 000000000000..d00491fd7e5b
--- /dev/null
+++ b/tests/exitmode0a.exprc
@@ -0,0 +1 @@
+1
diff --git a/tests/exitmode0a.sh b/tests/exitmode0a.sh
new file mode 100644
index 000000000000..6c171732a6cf
--- /dev/null
+++ b/tests/exitmode0a.sh
@@ -0,0 +1 @@
+unifdef -DFOO=1 -DFOOB=42 -UBAR -x0 if1.c
diff --git a/tests/exitmode0b.experr b/tests/exitmode0b.experr
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/tests/exitmode0b.experr
diff --git a/tests/exitmode0b.expout b/tests/exitmode0b.expout
new file mode 100644
index 000000000000..9e588c22791c
--- /dev/null
+++ b/tests/exitmode0b.expout
@@ -0,0 +1,26 @@
+/* Copyright 2004 Bob Proulx <bob@proulx.com>
+Distributed under the two-clause BSD licence;
+see the COPYING file for details. */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#if FOO
+int foo() { return 0; }
+#else
+#error FOO not defined
+#endif
+
+#if BAR
+int foo() { return 0; }
+#elif FOO
+int bar() { return 0; }
+#else
+#error FOO not defined
+#endif
+
+int main()
+{
+ foo();
+ bar();
+}
diff --git a/tests/exitmode0b.exprc b/tests/exitmode0b.exprc
new file mode 100644
index 000000000000..573541ac9702
--- /dev/null
+++ b/tests/exitmode0b.exprc
@@ -0,0 +1 @@
+0
diff --git a/tests/exitmode0b.sh b/tests/exitmode0b.sh
new file mode 100644
index 000000000000..339bb3e4149d
--- /dev/null
+++ b/tests/exitmode0b.sh
@@ -0,0 +1 @@
+unifdef -x0 if1.c
diff --git a/tests/exitmode1a.experr b/tests/exitmode1a.experr
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/tests/exitmode1a.experr
diff --git a/tests/exitmode1a.expout b/tests/exitmode1a.expout
new file mode 100644
index 000000000000..56ae03cc38de
--- /dev/null
+++ b/tests/exitmode1a.expout
@@ -0,0 +1,16 @@
+/* Copyright 2004 Bob Proulx <bob@proulx.com>
+Distributed under the two-clause BSD licence;
+see the COPYING file for details. */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+int foo() { return 0; }
+
+int bar() { return 0; }
+
+int main()
+{
+ foo();
+ bar();
+}
diff --git a/tests/exitmode1a.exprc b/tests/exitmode1a.exprc
new file mode 100644
index 000000000000..573541ac9702
--- /dev/null
+++ b/tests/exitmode1a.exprc
@@ -0,0 +1 @@
+0
diff --git a/tests/exitmode1a.sh b/tests/exitmode1a.sh
new file mode 100644
index 000000000000..4d40a13f69db
--- /dev/null
+++ b/tests/exitmode1a.sh
@@ -0,0 +1 @@
+unifdef -DFOO=1 -DFOOB=42 -UBAR -x1 if1.c
diff --git a/tests/exitmode1b.experr b/tests/exitmode1b.experr
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/tests/exitmode1b.experr
diff --git a/tests/exitmode1b.expout b/tests/exitmode1b.expout
new file mode 100644
index 000000000000..9e588c22791c
--- /dev/null
+++ b/tests/exitmode1b.expout
@@ -0,0 +1,26 @@
+/* Copyright 2004 Bob Proulx <bob@proulx.com>
+Distributed under the two-clause BSD licence;
+see the COPYING file for details. */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#if FOO
+int foo() { return 0; }
+#else
+#error FOO not defined
+#endif
+
+#if BAR
+int foo() { return 0; }
+#elif FOO
+int bar() { return 0; }
+#else
+#error FOO not defined
+#endif
+
+int main()
+{
+ foo();
+ bar();
+}
diff --git a/tests/exitmode1b.exprc b/tests/exitmode1b.exprc
new file mode 100644
index 000000000000..d00491fd7e5b
--- /dev/null
+++ b/tests/exitmode1b.exprc
@@ -0,0 +1 @@
+1
diff --git a/tests/exitmode1b.sh b/tests/exitmode1b.sh
new file mode 100644
index 000000000000..19bf1c196660
--- /dev/null
+++ b/tests/exitmode1b.sh
@@ -0,0 +1 @@
+unifdef -x1 if1.c
diff --git a/tests/exitmode2a.experr b/tests/exitmode2a.experr
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/tests/exitmode2a.experr
diff --git a/tests/exitmode2a.expout b/tests/exitmode2a.expout
new file mode 100644
index 000000000000..56ae03cc38de
--- /dev/null
+++ b/tests/exitmode2a.expout
@@ -0,0 +1,16 @@
+/* Copyright 2004 Bob Proulx <bob@proulx.com>
+Distributed under the two-clause BSD licence;
+see the COPYING file for details. */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+int foo() { return 0; }
+
+int bar() { return 0; }
+
+int main()
+{
+ foo();
+ bar();
+}
diff --git a/tests/exitmode2a.exprc b/tests/exitmode2a.exprc
new file mode 100644
index 000000000000..573541ac9702
--- /dev/null
+++ b/tests/exitmode2a.exprc
@@ -0,0 +1 @@
+0
diff --git a/tests/exitmode2a.sh b/tests/exitmode2a.sh
new file mode 100644
index 000000000000..42db886dc5da
--- /dev/null
+++ b/tests/exitmode2a.sh
@@ -0,0 +1 @@
+unifdef -DFOO=1 -DFOOB=42 -UBAR -x2 if1.c
diff --git a/tests/exitmode2b.experr b/tests/exitmode2b.experr
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/tests/exitmode2b.experr
diff --git a/tests/exitmode2b.expout b/tests/exitmode2b.expout
new file mode 100644
index 000000000000..9e588c22791c
--- /dev/null
+++ b/tests/exitmode2b.expout
@@ -0,0 +1,26 @@
+/* Copyright 2004 Bob Proulx <bob@proulx.com>
+Distributed under the two-clause BSD licence;
+see the COPYING file for details. */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#if FOO
+int foo() { return 0; }
+#else
+#error FOO not defined
+#endif
+
+#if BAR
+int foo() { return 0; }
+#elif FOO
+int bar() { return 0; }
+#else
+#error FOO not defined
+#endif
+
+int main()
+{
+ foo();
+ bar();
+}
diff --git a/tests/exitmode2b.exprc b/tests/exitmode2b.exprc
new file mode 100644
index 000000000000..573541ac9702
--- /dev/null
+++ b/tests/exitmode2b.exprc
@@ -0,0 +1 @@
+0
diff --git a/tests/exitmode2b.sh b/tests/exitmode2b.sh
new file mode 100644
index 000000000000..30bdd3ba33b9
--- /dev/null
+++ b/tests/exitmode2b.sh
@@ -0,0 +1 @@
+unifdef -x2 if1.c
diff --git a/tests/exitstat.c b/tests/exitstat.c
new file mode 100644
index 000000000000..5413a07a46fc
--- /dev/null
+++ b/tests/exitstat.c
@@ -0,0 +1,3 @@
+#if FALSE
+#elif TRUE
+#endif
diff --git a/tests/exitstat.experr b/tests/exitstat.experr
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/tests/exitstat.experr
diff --git a/tests/exitstat.expout b/tests/exitstat.expout
new file mode 100644
index 000000000000..e08e8fb49178
--- /dev/null
+++ b/tests/exitstat.expout
@@ -0,0 +1,3 @@
+#if FALSE
+#else
+#endif
diff --git a/tests/exitstat.exprc b/tests/exitstat.exprc
new file mode 100644
index 000000000000..d00491fd7e5b
--- /dev/null
+++ b/tests/exitstat.exprc
@@ -0,0 +1 @@
+1
diff --git a/tests/exitstat.sh b/tests/exitstat.sh
new file mode 100644
index 000000000000..df0060f73638
--- /dev/null
+++ b/tests/exitstat.sh
@@ -0,0 +1 @@
+unifdef -DTRUE=1 exitstat.c
diff --git a/tests/funlike.h b/tests/funlike.h
new file mode 100644
index 000000000000..5e657946e36b
--- /dev/null
+++ b/tests/funlike.h
@@ -0,0 +1 @@
+#define FOO(a,b,c) a+b+c
diff --git a/tests/if1-a.experr b/tests/if1-a.experr
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/tests/if1-a.experr
diff --git a/tests/if1-a.expout b/tests/if1-a.expout
new file mode 100644
index 000000000000..56ae03cc38de
--- /dev/null
+++ b/tests/if1-a.expout
@@ -0,0 +1,16 @@
+/* Copyright 2004 Bob Proulx <bob@proulx.com>
+Distributed under the two-clause BSD licence;
+see the COPYING file for details. */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+int foo() { return 0; }
+
+int bar() { return 0; }
+
+int main()
+{
+ foo();
+ bar();
+}
diff --git a/tests/if1-a.exprc b/tests/if1-a.exprc
new file mode 100644
index 000000000000..d00491fd7e5b
--- /dev/null
+++ b/tests/if1-a.exprc
@@ -0,0 +1 @@
+1
diff --git a/tests/if1-a.sh b/tests/if1-a.sh
new file mode 100644
index 000000000000..57b7cd5b7a56
--- /dev/null
+++ b/tests/if1-a.sh
@@ -0,0 +1 @@
+unifdefall.sh -DFOO=1 -DFOOB=42 -UBAR if1.c
diff --git a/tests/if1-f.experr b/tests/if1-f.experr
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/tests/if1-f.experr
diff --git a/tests/if1-f.expout b/tests/if1-f.expout
new file mode 100644
index 000000000000..56ae03cc38de
--- /dev/null
+++ b/tests/if1-f.expout
@@ -0,0 +1,16 @@
+/* Copyright 2004 Bob Proulx <bob@proulx.com>
+Distributed under the two-clause BSD licence;
+see the COPYING file for details. */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+int foo() { return 0; }
+
+int bar() { return 0; }
+
+int main()
+{
+ foo();
+ bar();
+}
diff --git a/tests/if1-f.exprc b/tests/if1-f.exprc
new file mode 100644
index 000000000000..d00491fd7e5b
--- /dev/null
+++ b/tests/if1-f.exprc
@@ -0,0 +1 @@
+1
diff --git a/tests/if1-f.sh b/tests/if1-f.sh
new file mode 100644
index 000000000000..4a9698c08d3c
--- /dev/null
+++ b/tests/if1-f.sh
@@ -0,0 +1 @@
+unifdef -f if1.h if1.c
diff --git a/tests/if1-k.c b/tests/if1-k.c
new file mode 100644
index 000000000000..712350f9c13c
--- /dev/null
+++ b/tests/if1-k.c
@@ -0,0 +1,38 @@
+/* Copyright 2004, 2008 Bob Proulx <bob@proulx.com>
+Distributed under the two-clause BSD licence;
+see the COPYING file for details. */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#if 0
+/* This code is commented out. "#if 0 then" */
+#else
+/* This code is passed through. "#if 0 else" */
+#endif
+
+#if 1
+/* This code is passed through. "#if 1 then" */
+#else
+/* This code is commented out. "#if 1 else" */
+#endif
+
+#if FOO
+int foo() { return 0; }
+#else
+#error FOO not defined
+#endif
+
+#if BAR
+int foo() { return 0; }
+#elif FOO
+int bar() { return 0; }
+#else
+#error FOO not defined
+#endif
+
+int main()
+{
+ foo();
+ bar();
+}
diff --git a/tests/if1-k.experr b/tests/if1-k.experr
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/tests/if1-k.experr
diff --git a/tests/if1-k.expout b/tests/if1-k.expout
new file mode 100644
index 000000000000..2be8567b970c
--- /dev/null
+++ b/tests/if1-k.expout
@@ -0,0 +1,30 @@
+/* Copyright 2004, 2008 Bob Proulx <bob@proulx.com>
+Distributed under the two-clause BSD licence;
+see the COPYING file for details. */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+/* This code is passed through. "#if 0 else" */
+
+/* This code is passed through. "#if 1 then" */
+
+#if FOO
+int foo() { return 0; }
+#else
+#error FOO not defined
+#endif
+
+#if BAR
+int foo() { return 0; }
+#elif FOO
+int bar() { return 0; }
+#else
+#error FOO not defined
+#endif
+
+int main()
+{
+ foo();
+ bar();
+}
diff --git a/tests/if1-k.exprc b/tests/if1-k.exprc
new file mode 100644
index 000000000000..d00491fd7e5b
--- /dev/null
+++ b/tests/if1-k.exprc
@@ -0,0 +1 @@
+1
diff --git a/tests/if1-k.sh b/tests/if1-k.sh
new file mode 100644
index 000000000000..dc33e1afbda0
--- /dev/null
+++ b/tests/if1-k.sh
@@ -0,0 +1 @@
+unifdef -k if1-k.c
diff --git a/tests/if1-kDU.c b/tests/if1-kDU.c
new file mode 100644
index 000000000000..712350f9c13c
--- /dev/null
+++ b/tests/if1-kDU.c
@@ -0,0 +1,38 @@
+/* Copyright 2004, 2008 Bob Proulx <bob@proulx.com>
+Distributed under the two-clause BSD licence;
+see the COPYING file for details. */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#if 0
+/* This code is commented out. "#if 0 then" */
+#else
+/* This code is passed through. "#if 0 else" */
+#endif
+
+#if 1
+/* This code is passed through. "#if 1 then" */
+#else
+/* This code is commented out. "#if 1 else" */
+#endif
+
+#if FOO
+int foo() { return 0; }
+#else
+#error FOO not defined
+#endif
+
+#if BAR
+int foo() { return 0; }
+#elif FOO
+int bar() { return 0; }
+#else
+#error FOO not defined
+#endif
+
+int main()
+{
+ foo();
+ bar();
+}
diff --git a/tests/if1-kDU.experr b/tests/if1-kDU.experr
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/tests/if1-kDU.experr
diff --git a/tests/if1-kDU.expout b/tests/if1-kDU.expout
new file mode 100644
index 000000000000..c308e43b5a09
--- /dev/null
+++ b/tests/if1-kDU.expout
@@ -0,0 +1,20 @@
+/* Copyright 2004, 2008 Bob Proulx <bob@proulx.com>
+Distributed under the two-clause BSD licence;
+see the COPYING file for details. */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+/* This code is passed through. "#if 0 else" */
+
+/* This code is passed through. "#if 1 then" */
+
+int foo() { return 0; }
+
+int bar() { return 0; }
+
+int main()
+{
+ foo();
+ bar();
+}
diff --git a/tests/if1-kDU.exprc b/tests/if1-kDU.exprc
new file mode 100644
index 000000000000..d00491fd7e5b
--- /dev/null
+++ b/tests/if1-kDU.exprc
@@ -0,0 +1 @@
+1
diff --git a/tests/if1-kDU.sh b/tests/if1-kDU.sh
new file mode 100644
index 000000000000..49231b7a4d9a
--- /dev/null
+++ b/tests/if1-kDU.sh
@@ -0,0 +1 @@
+unifdef -k -DFOO=1 -DFOOB=42 -UBAR if1-kDU.c
diff --git a/tests/if1.c b/tests/if1.c
new file mode 100644
index 000000000000..9e588c22791c
--- /dev/null
+++ b/tests/if1.c
@@ -0,0 +1,26 @@
+/* Copyright 2004 Bob Proulx <bob@proulx.com>
+Distributed under the two-clause BSD licence;
+see the COPYING file for details. */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#if FOO
+int foo() { return 0; }
+#else
+#error FOO not defined
+#endif
+
+#if BAR
+int foo() { return 0; }
+#elif FOO
+int bar() { return 0; }
+#else
+#error FOO not defined
+#endif
+
+int main()
+{
+ foo();
+ bar();
+}
diff --git a/tests/if1.experr b/tests/if1.experr
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/tests/if1.experr
diff --git a/tests/if1.expout b/tests/if1.expout
new file mode 100644
index 000000000000..56ae03cc38de
--- /dev/null
+++ b/tests/if1.expout
@@ -0,0 +1,16 @@
+/* Copyright 2004 Bob Proulx <bob@proulx.com>
+Distributed under the two-clause BSD licence;
+see the COPYING file for details. */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+int foo() { return 0; }
+
+int bar() { return 0; }
+
+int main()
+{
+ foo();
+ bar();
+}
diff --git a/tests/if1.exprc b/tests/if1.exprc
new file mode 100644
index 000000000000..d00491fd7e5b
--- /dev/null
+++ b/tests/if1.exprc
@@ -0,0 +1 @@
+1
diff --git a/tests/if1.h b/tests/if1.h
new file mode 100644
index 000000000000..3441c1bd8b85
--- /dev/null
+++ b/tests/if1.h
@@ -0,0 +1,3 @@
+#define FOO 1
+#define FOOB 42
+#undef BAR
diff --git a/tests/if1.sh b/tests/if1.sh
new file mode 100644
index 000000000000..36a1cef8285a
--- /dev/null
+++ b/tests/if1.sh
@@ -0,0 +1 @@
+unifdef -DFOO=1 -DFOOB=42 -UBAR if1.c
diff --git a/tests/if1a.experr b/tests/if1a.experr
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/tests/if1a.experr
diff --git a/tests/if1a.expout b/tests/if1a.expout
new file mode 100644
index 000000000000..956eea0b20b2
--- /dev/null
+++ b/tests/if1a.expout
@@ -0,0 +1,24 @@
+/* Copyright 2004 Bob Proulx <bob@proulx.com>
+Distributed under the two-clause BSD licence;
+see the COPYING file for details. */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#if FOO
+int foo() { return 0; }
+#else
+#error FOO not defined
+#endif
+
+#if FOO
+int bar() { return 0; }
+#else
+#error FOO not defined
+#endif
+
+int main()
+{
+ foo();
+ bar();
+}
diff --git a/tests/if1a.exprc b/tests/if1a.exprc
new file mode 100644
index 000000000000..d00491fd7e5b
--- /dev/null
+++ b/tests/if1a.exprc
@@ -0,0 +1 @@
+1
diff --git a/tests/if1a.sh b/tests/if1a.sh
new file mode 100644
index 000000000000..ac54227c7502
--- /dev/null
+++ b/tests/if1a.sh
@@ -0,0 +1 @@
+unifdef -UBAR if1.c
diff --git a/tests/if2-a.experr b/tests/if2-a.experr
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/tests/if2-a.experr
diff --git a/tests/if2-a.expout b/tests/if2-a.expout
new file mode 100644
index 000000000000..b64cfc265bd2
--- /dev/null
+++ b/tests/if2-a.expout
@@ -0,0 +1,13 @@
+/* Copyright 2004 Bob Proulx <bob@proulx.com>
+Distributed under the two-clause BSD licence;
+see the COPYING file for details. */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+int foo() { return 0; }
+
+int main()
+{
+ foo();
+}
diff --git a/tests/if2-a.exprc b/tests/if2-a.exprc
new file mode 100644
index 000000000000..d00491fd7e5b
--- /dev/null
+++ b/tests/if2-a.exprc
@@ -0,0 +1 @@
+1
diff --git a/tests/if2-a.sh b/tests/if2-a.sh
new file mode 100644
index 000000000000..acefce8f833c
--- /dev/null
+++ b/tests/if2-a.sh
@@ -0,0 +1 @@
+unifdefall.sh -DFOO=1 -DFOOB=42 -UBAR if2.c
diff --git a/tests/if2-k.c b/tests/if2-k.c
new file mode 100644
index 000000000000..b5a9109d6ff9
--- /dev/null
+++ b/tests/if2-k.c
@@ -0,0 +1,29 @@
+/* Copyright 2004, 2008 Bob Proulx <bob@proulx.com>
+Distributed under the two-clause BSD licence;
+see the COPYING file for details. */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#if 0
+/* This code is commented out. "#if 0 then" */
+#else
+/* This code is passed through. "#if 0 else" */
+#endif
+
+#if 1
+/* This code is passed through. "#if 1 then" */
+#else
+/* This code is passed through. "#if 1 else" */
+#endif
+
+#if defined(FOO)
+int foo() { return 0; }
+#else
+#error FOO not defined
+#endif
+
+int main()
+{
+ foo();
+}
diff --git a/tests/if2-k.experr b/tests/if2-k.experr
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/tests/if2-k.experr
diff --git a/tests/if2-k.expout b/tests/if2-k.expout
new file mode 100644
index 000000000000..6a173a4e0a3b
--- /dev/null
+++ b/tests/if2-k.expout
@@ -0,0 +1,21 @@
+/* Copyright 2004, 2008 Bob Proulx <bob@proulx.com>
+Distributed under the two-clause BSD licence;
+see the COPYING file for details. */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+/* This code is passed through. "#if 0 else" */
+
+/* This code is passed through. "#if 1 then" */
+
+#if defined(FOO)
+int foo() { return 0; }
+#else
+#error FOO not defined
+#endif
+
+int main()
+{
+ foo();
+}
diff --git a/tests/if2-k.exprc b/tests/if2-k.exprc
new file mode 100644
index 000000000000..d00491fd7e5b
--- /dev/null
+++ b/tests/if2-k.exprc
@@ -0,0 +1 @@
+1
diff --git a/tests/if2-k.sh b/tests/if2-k.sh
new file mode 100644
index 000000000000..5875af3227cd
--- /dev/null
+++ b/tests/if2-k.sh
@@ -0,0 +1 @@
+unifdef -k if2-k.c
diff --git a/tests/if2-kDU.c b/tests/if2-kDU.c
new file mode 100644
index 000000000000..b5a9109d6ff9
--- /dev/null
+++ b/tests/if2-kDU.c
@@ -0,0 +1,29 @@
+/* Copyright 2004, 2008 Bob Proulx <bob@proulx.com>
+Distributed under the two-clause BSD licence;
+see the COPYING file for details. */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#if 0
+/* This code is commented out. "#if 0 then" */
+#else
+/* This code is passed through. "#if 0 else" */
+#endif
+
+#if 1
+/* This code is passed through. "#if 1 then" */
+#else
+/* This code is passed through. "#if 1 else" */
+#endif
+
+#if defined(FOO)
+int foo() { return 0; }
+#else
+#error FOO not defined
+#endif
+
+int main()
+{
+ foo();
+}
diff --git a/tests/if2-kDU.experr b/tests/if2-kDU.experr
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/tests/if2-kDU.experr
diff --git a/tests/if2-kDU.expout b/tests/if2-kDU.expout
new file mode 100644
index 000000000000..7cf0ddc9c796
--- /dev/null
+++ b/tests/if2-kDU.expout
@@ -0,0 +1,17 @@
+/* Copyright 2004, 2008 Bob Proulx <bob@proulx.com>
+Distributed under the two-clause BSD licence;
+see the COPYING file for details. */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+/* This code is passed through. "#if 0 else" */
+
+/* This code is passed through. "#if 1 then" */
+
+int foo() { return 0; }
+
+int main()
+{
+ foo();
+}
diff --git a/tests/if2-kDU.exprc b/tests/if2-kDU.exprc
new file mode 100644
index 000000000000..d00491fd7e5b
--- /dev/null
+++ b/tests/if2-kDU.exprc
@@ -0,0 +1 @@
+1
diff --git a/tests/if2-kDU.sh b/tests/if2-kDU.sh
new file mode 100644
index 000000000000..567ca0af4ac9
--- /dev/null
+++ b/tests/if2-kDU.sh
@@ -0,0 +1 @@
+unifdef -k -DFOO=1 -DFOOB=42 -UBAR if2-kDU.c
diff --git a/tests/if2.c b/tests/if2.c
new file mode 100644
index 000000000000..44fdae070f3e
--- /dev/null
+++ b/tests/if2.c
@@ -0,0 +1,17 @@
+/* Copyright 2004 Bob Proulx <bob@proulx.com>
+Distributed under the two-clause BSD licence;
+see the COPYING file for details. */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#if defined(FOO)
+int foo() { return 0; }
+#else
+#error FOO not defined
+#endif
+
+int main()
+{
+ foo();
+}
diff --git a/tests/if2.experr b/tests/if2.experr
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/tests/if2.experr
diff --git a/tests/if2.expout b/tests/if2.expout
new file mode 100644
index 000000000000..b64cfc265bd2
--- /dev/null
+++ b/tests/if2.expout
@@ -0,0 +1,13 @@
+/* Copyright 2004 Bob Proulx <bob@proulx.com>
+Distributed under the two-clause BSD licence;
+see the COPYING file for details. */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+int foo() { return 0; }
+
+int main()
+{
+ foo();
+}
diff --git a/tests/if2.exprc b/tests/if2.exprc
new file mode 100644
index 000000000000..d00491fd7e5b
--- /dev/null
+++ b/tests/if2.exprc
@@ -0,0 +1 @@
+1
diff --git a/tests/if2.sh b/tests/if2.sh
new file mode 100644
index 000000000000..e10159a1f9f5
--- /dev/null
+++ b/tests/if2.sh
@@ -0,0 +1 @@
+unifdef -DFOO=1 -DFOOB=42 -UBAR if2.c
diff --git a/tests/if3-a.experr b/tests/if3-a.experr
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/tests/if3-a.experr
diff --git a/tests/if3-a.expout b/tests/if3-a.expout
new file mode 100644
index 000000000000..b64cfc265bd2
--- /dev/null
+++ b/tests/if3-a.expout
@@ -0,0 +1,13 @@
+/* Copyright 2004 Bob Proulx <bob@proulx.com>
+Distributed under the two-clause BSD licence;
+see the COPYING file for details. */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+int foo() { return 0; }
+
+int main()
+{
+ foo();
+}
diff --git a/tests/if3-a.exprc b/tests/if3-a.exprc
new file mode 100644
index 000000000000..d00491fd7e5b
--- /dev/null
+++ b/tests/if3-a.exprc
@@ -0,0 +1 @@
+1
diff --git a/tests/if3-a.sh b/tests/if3-a.sh
new file mode 100644
index 000000000000..f6b1500a2d2c
--- /dev/null
+++ b/tests/if3-a.sh
@@ -0,0 +1 @@
+unifdefall.sh -DFOO=1 -DFOOB=42 -UBAR if3.c
diff --git a/tests/if3-k.c b/tests/if3-k.c
new file mode 100644
index 000000000000..c90102155f4d
--- /dev/null
+++ b/tests/if3-k.c
@@ -0,0 +1,29 @@
+/* Copyright 2004, 2008 Bob Proulx <bob@proulx.com>
+Distributed under the two-clause BSD licence;
+see the COPYING file for details. */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#if 0
+/* This code is commented out. "#if 0 then" */
+#else
+/* This code is passed through. "#if 0 else" */
+#endif
+
+#if 1
+/* This code is passed through. "#if 1 then" */
+#else
+/* This code is passed through. "#if 1 else" */
+#endif
+
+#if ! defined(BAR)
+int foo() { return 0; }
+#else
+#error BAR defined
+#endif
+
+int main()
+{
+ foo();
+}
diff --git a/tests/if3-k.experr b/tests/if3-k.experr
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/tests/if3-k.experr
diff --git a/tests/if3-k.expout b/tests/if3-k.expout
new file mode 100644
index 000000000000..e0e23867de64
--- /dev/null
+++ b/tests/if3-k.expout
@@ -0,0 +1,21 @@
+/* Copyright 2004, 2008 Bob Proulx <bob@proulx.com>
+Distributed under the two-clause BSD licence;
+see the COPYING file for details. */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+/* This code is passed through. "#if 0 else" */
+
+/* This code is passed through. "#if 1 then" */
+
+#if ! defined(BAR)
+int foo() { return 0; }
+#else
+#error BAR defined
+#endif
+
+int main()
+{
+ foo();
+}
diff --git a/tests/if3-k.exprc b/tests/if3-k.exprc
new file mode 100644
index 000000000000..d00491fd7e5b
--- /dev/null
+++ b/tests/if3-k.exprc
@@ -0,0 +1 @@
+1
diff --git a/tests/if3-k.sh b/tests/if3-k.sh
new file mode 100644
index 000000000000..4bd48da7c5b7
--- /dev/null
+++ b/tests/if3-k.sh
@@ -0,0 +1 @@
+unifdef -k if3-k.c
diff --git a/tests/if3-kDU.c b/tests/if3-kDU.c
new file mode 100644
index 000000000000..c90102155f4d
--- /dev/null
+++ b/tests/if3-kDU.c
@@ -0,0 +1,29 @@
+/* Copyright 2004, 2008 Bob Proulx <bob@proulx.com>
+Distributed under the two-clause BSD licence;
+see the COPYING file for details. */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#if 0
+/* This code is commented out. "#if 0 then" */
+#else
+/* This code is passed through. "#if 0 else" */
+#endif
+
+#if 1
+/* This code is passed through. "#if 1 then" */
+#else
+/* This code is passed through. "#if 1 else" */
+#endif
+
+#if ! defined(BAR)
+int foo() { return 0; }
+#else
+#error BAR defined
+#endif
+
+int main()
+{
+ foo();
+}
diff --git a/tests/if3-kDU.experr b/tests/if3-kDU.experr
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/tests/if3-kDU.experr
diff --git a/tests/if3-kDU.expout b/tests/if3-kDU.expout
new file mode 100644
index 000000000000..7cf0ddc9c796
--- /dev/null
+++ b/tests/if3-kDU.expout
@@ -0,0 +1,17 @@
+/* Copyright 2004, 2008 Bob Proulx <bob@proulx.com>
+Distributed under the two-clause BSD licence;
+see the COPYING file for details. */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+/* This code is passed through. "#if 0 else" */
+
+/* This code is passed through. "#if 1 then" */
+
+int foo() { return 0; }
+
+int main()
+{
+ foo();
+}
diff --git a/tests/if3-kDU.exprc b/tests/if3-kDU.exprc
new file mode 100644
index 000000000000..d00491fd7e5b
--- /dev/null
+++ b/tests/if3-kDU.exprc
@@ -0,0 +1 @@
+1
diff --git a/tests/if3-kDU.sh b/tests/if3-kDU.sh
new file mode 100644
index 000000000000..795e54f25c5f
--- /dev/null
+++ b/tests/if3-kDU.sh
@@ -0,0 +1 @@
+unifdef -k -DFOO=1 -DFOOB=42 -UBAR if3-kDU.c
diff --git a/tests/if3.c b/tests/if3.c
new file mode 100644
index 000000000000..2a87102fab5a
--- /dev/null
+++ b/tests/if3.c
@@ -0,0 +1,17 @@
+/* Copyright 2004 Bob Proulx <bob@proulx.com>
+Distributed under the two-clause BSD licence;
+see the COPYING file for details. */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#if ! defined(BAR)
+int foo() { return 0; }
+#else
+#error BAR defined
+#endif
+
+int main()
+{
+ foo();
+}
diff --git a/tests/if3.experr b/tests/if3.experr
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/tests/if3.experr
diff --git a/tests/if3.expout b/tests/if3.expout
new file mode 100644
index 000000000000..b64cfc265bd2
--- /dev/null
+++ b/tests/if3.expout
@@ -0,0 +1,13 @@
+/* Copyright 2004 Bob Proulx <bob@proulx.com>
+Distributed under the two-clause BSD licence;
+see the COPYING file for details. */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+int foo() { return 0; }
+
+int main()
+{
+ foo();
+}
diff --git a/tests/if3.exprc b/tests/if3.exprc
new file mode 100644
index 000000000000..d00491fd7e5b
--- /dev/null
+++ b/tests/if3.exprc
@@ -0,0 +1 @@
+1
diff --git a/tests/if3.sh b/tests/if3.sh
new file mode 100644
index 000000000000..9345010283ff
--- /dev/null
+++ b/tests/if3.sh
@@ -0,0 +1 @@
+unifdef -DFOO=1 -DFOOB=42 -UBAR if3.c
diff --git a/tests/if4-a.experr b/tests/if4-a.experr
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/tests/if4-a.experr
diff --git a/tests/if4-a.expout b/tests/if4-a.expout
new file mode 100644
index 000000000000..55dfe32d1272
--- /dev/null
+++ b/tests/if4-a.expout
@@ -0,0 +1,22 @@
+/* Copyright 2004 Bob Proulx <bob@proulx.com>
+Distributed under the two-clause BSD licence;
+see the COPYING file for details. */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+int foo1() { return 0; }
+
+int foo2() { return 0; }
+
+int foo3() { return 0; }
+
+int foo4() { return 0; }
+
+int main()
+{
+ foo1();
+ foo2();
+ foo3();
+ foo4();
+}
diff --git a/tests/if4-a.exprc b/tests/if4-a.exprc
new file mode 100644
index 000000000000..d00491fd7e5b
--- /dev/null
+++ b/tests/if4-a.exprc
@@ -0,0 +1 @@
+1
diff --git a/tests/if4-a.sh b/tests/if4-a.sh
new file mode 100644
index 000000000000..888f9014f0a5
--- /dev/null
+++ b/tests/if4-a.sh
@@ -0,0 +1 @@
+unifdefall.sh -DFOO=1 -DFOOB=42 -UBAR if4.c
diff --git a/tests/if4-k.c b/tests/if4-k.c
new file mode 100644
index 000000000000..b31bca49c443
--- /dev/null
+++ b/tests/if4-k.c
@@ -0,0 +1,50 @@
+/* Copyright 2004, 2008 Bob Proulx <bob@proulx.com>
+Distributed under the two-clause BSD licence;
+see the COPYING file for details. */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#if 0
+/* This code is commented out. "#if 0 then" */
+#else
+/* This code is passed through. "#if 0 else" */
+#endif
+
+#if 1
+/* This code is passed through. "#if 1 then" */
+#else
+/* This code is passed through. "#if 1 else" */
+#endif
+
+#if defined(FOO) || defined(FOOB)
+int foo1() { return 0; }
+#else
+#error FOO or FOOB not defined
+#endif
+
+#if defined(FOOB) || defined(FOO)
+int foo2() { return 0; }
+#else
+#error FOO or FOOB not defined
+#endif
+
+#if defined(FOO) && defined(FOOB)
+int foo3() { return 0; }
+#else
+#error FOO and FOOB not defined
+#endif
+
+#if defined(FOOB) && defined(FOO)
+int foo4() { return 0; }
+#else
+#error FOO and FOOB not defined
+#endif
+
+int main()
+{
+ foo1();
+ foo2();
+ foo3();
+ foo4();
+}
diff --git a/tests/if4-k.experr b/tests/if4-k.experr
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/tests/if4-k.experr
diff --git a/tests/if4-k.expout b/tests/if4-k.expout
new file mode 100644
index 000000000000..bb94d6a14e64
--- /dev/null
+++ b/tests/if4-k.expout
@@ -0,0 +1,42 @@
+/* Copyright 2004, 2008 Bob Proulx <bob@proulx.com>
+Distributed under the two-clause BSD licence;
+see the COPYING file for details. */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+/* This code is passed through. "#if 0 else" */
+
+/* This code is passed through. "#if 1 then" */
+
+#if defined(FOO) || defined(FOOB)
+int foo1() { return 0; }
+#else
+#error FOO or FOOB not defined
+#endif
+
+#if defined(FOOB) || defined(FOO)
+int foo2() { return 0; }
+#else
+#error FOO or FOOB not defined
+#endif
+
+#if defined(FOO) && defined(FOOB)
+int foo3() { return 0; }
+#else
+#error FOO and FOOB not defined
+#endif
+
+#if defined(FOOB) && defined(FOO)
+int foo4() { return 0; }
+#else
+#error FOO and FOOB not defined
+#endif
+
+int main()
+{
+ foo1();
+ foo2();
+ foo3();
+ foo4();
+}
diff --git a/tests/if4-k.exprc b/tests/if4-k.exprc
new file mode 100644
index 000000000000..d00491fd7e5b
--- /dev/null
+++ b/tests/if4-k.exprc
@@ -0,0 +1 @@
+1
diff --git a/tests/if4-k.sh b/tests/if4-k.sh
new file mode 100644
index 000000000000..277d248a1328
--- /dev/null
+++ b/tests/if4-k.sh
@@ -0,0 +1 @@
+unifdef -k if4-k.c
diff --git a/tests/if4-kDU.c b/tests/if4-kDU.c
new file mode 100644
index 000000000000..b31bca49c443
--- /dev/null
+++ b/tests/if4-kDU.c
@@ -0,0 +1,50 @@
+/* Copyright 2004, 2008 Bob Proulx <bob@proulx.com>
+Distributed under the two-clause BSD licence;
+see the COPYING file for details. */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#if 0
+/* This code is commented out. "#if 0 then" */
+#else
+/* This code is passed through. "#if 0 else" */
+#endif
+
+#if 1
+/* This code is passed through. "#if 1 then" */
+#else
+/* This code is passed through. "#if 1 else" */
+#endif
+
+#if defined(FOO) || defined(FOOB)
+int foo1() { return 0; }
+#else
+#error FOO or FOOB not defined
+#endif
+
+#if defined(FOOB) || defined(FOO)
+int foo2() { return 0; }
+#else
+#error FOO or FOOB not defined
+#endif
+
+#if defined(FOO) && defined(FOOB)
+int foo3() { return 0; }
+#else
+#error FOO and FOOB not defined
+#endif
+
+#if defined(FOOB) && defined(FOO)
+int foo4() { return 0; }
+#else
+#error FOO and FOOB not defined
+#endif
+
+int main()
+{
+ foo1();
+ foo2();
+ foo3();
+ foo4();
+}
diff --git a/tests/if4-kDU.experr b/tests/if4-kDU.experr
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/tests/if4-kDU.experr
diff --git a/tests/if4-kDU.expout b/tests/if4-kDU.expout
new file mode 100644
index 000000000000..919bd63a8eda
--- /dev/null
+++ b/tests/if4-kDU.expout
@@ -0,0 +1,26 @@
+/* Copyright 2004, 2008 Bob Proulx <bob@proulx.com>
+Distributed under the two-clause BSD licence;
+see the COPYING file for details. */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+/* This code is passed through. "#if 0 else" */
+
+/* This code is passed through. "#if 1 then" */
+
+int foo1() { return 0; }
+
+int foo2() { return 0; }
+
+int foo3() { return 0; }
+
+int foo4() { return 0; }
+
+int main()
+{
+ foo1();
+ foo2();
+ foo3();
+ foo4();
+}
diff --git a/tests/if4-kDU.exprc b/tests/if4-kDU.exprc
new file mode 100644
index 000000000000..d00491fd7e5b
--- /dev/null
+++ b/tests/if4-kDU.exprc
@@ -0,0 +1 @@
+1
diff --git a/tests/if4-kDU.sh b/tests/if4-kDU.sh
new file mode 100644
index 000000000000..57c3e93d1c8b
--- /dev/null
+++ b/tests/if4-kDU.sh
@@ -0,0 +1 @@
+unifdef -k -DFOO=1 -DFOOB=42 -UBAR if4-kDU.c
diff --git a/tests/if4.c b/tests/if4.c
new file mode 100644
index 000000000000..a8be34883d02
--- /dev/null
+++ b/tests/if4.c
@@ -0,0 +1,38 @@
+/* Copyright 2004 Bob Proulx <bob@proulx.com>
+Distributed under the two-clause BSD licence;
+see the COPYING file for details. */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#if defined(FOO) || defined(FOOB)
+int foo1() { return 0; }
+#else
+#error FOO or FOOB not defined
+#endif
+
+#if defined(FOOB) || defined(FOO)
+int foo2() { return 0; }
+#else
+#error FOO or FOOB not defined
+#endif
+
+#if defined(FOO) && defined(FOOB)
+int foo3() { return 0; }
+#else
+#error FOO and FOOB not defined
+#endif
+
+#if defined(FOOB) && defined(FOO)
+int foo4() { return 0; }
+#else
+#error FOO and FOOB not defined
+#endif
+
+int main()
+{
+ foo1();
+ foo2();
+ foo3();
+ foo4();
+}
diff --git a/tests/if4.experr b/tests/if4.experr
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/tests/if4.experr
diff --git a/tests/if4.expout b/tests/if4.expout
new file mode 100644
index 000000000000..55dfe32d1272
--- /dev/null
+++ b/tests/if4.expout
@@ -0,0 +1,22 @@
+/* Copyright 2004 Bob Proulx <bob@proulx.com>
+Distributed under the two-clause BSD licence;
+see the COPYING file for details. */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+int foo1() { return 0; }
+
+int foo2() { return 0; }
+
+int foo3() { return 0; }
+
+int foo4() { return 0; }
+
+int main()
+{
+ foo1();
+ foo2();
+ foo3();
+ foo4();
+}
diff --git a/tests/if4.exprc b/tests/if4.exprc
new file mode 100644
index 000000000000..d00491fd7e5b
--- /dev/null
+++ b/tests/if4.exprc
@@ -0,0 +1 @@
+1
diff --git a/tests/if4.sh b/tests/if4.sh
new file mode 100644
index 000000000000..efbdbcfacc33
--- /dev/null
+++ b/tests/if4.sh
@@ -0,0 +1 @@
+unifdef -DFOO=1 -DFOOB=42 -UBAR if4.c
diff --git a/tests/if5-a.experr b/tests/if5-a.experr
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/tests/if5-a.experr
diff --git a/tests/if5-a.expout b/tests/if5-a.expout
new file mode 100644
index 000000000000..ffacc5e5a97f
--- /dev/null
+++ b/tests/if5-a.expout
@@ -0,0 +1,40 @@
+/* Copyright 2004 Bob Proulx <bob@proulx.com>
+Distributed under the two-clause BSD licence;
+see the COPYING file for details. */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+int foo1() { return 0; }
+
+int foo2() { return 0; }
+
+int foo3() { return 0; }
+
+int foo4() { return 0; }
+
+int foo5() { return 0; }
+
+int foo6() { return 0; }
+
+int foo7() { return 0; }
+
+int foo8() { return 0; }
+
+int foo9() { return 0; }
+
+int foo10() { return 0; }
+
+int main()
+{
+ foo1();
+ foo2();
+ foo3();
+ foo4();
+ foo5();
+ foo6();
+ foo7();
+ foo8();
+ foo9();
+ foo10();
+}
diff --git a/tests/if5-a.exprc b/tests/if5-a.exprc
new file mode 100644
index 000000000000..d00491fd7e5b
--- /dev/null
+++ b/tests/if5-a.exprc
@@ -0,0 +1 @@
+1
diff --git a/tests/if5-a.sh b/tests/if5-a.sh
new file mode 100644
index 000000000000..6c30b1f6d8cc
--- /dev/null
+++ b/tests/if5-a.sh
@@ -0,0 +1 @@
+unifdefall.sh -DFOO=1 -DFOOB=42 -UBAR if5.c
diff --git a/tests/if5-k.c b/tests/if5-k.c
new file mode 100644
index 000000000000..2be184790ce8
--- /dev/null
+++ b/tests/if5-k.c
@@ -0,0 +1,64 @@
+/* Copyright 2004, 2008 Bob Proulx <bob@proulx.com>
+Distributed under the two-clause BSD licence;
+see the COPYING file for details. */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#if 0
+/* This code is commented out. "#if 0 then" */
+#else
+/* This code is passed through. "#if 0 else" */
+#endif
+
+#if 1
+/* This code is passed through. "#if 1 then" */
+#else
+/* This code is passed through. "#if 1 else" */
+#endif
+
+#if FOOB == 42
+int foo1() { return 0; }
+#else
+#error FOOB not 42
+#endif
+
+#if FOOB != 42
+#error FOO is 2
+#else
+int foo2() { return 0; }
+#endif
+
+#if FOOB == 42 || FOO == 1
+intx foo3() { return 0; }
+#else
+#error FOO not 1 or BAR not 1
+#endif
+
+#if FOOB != 42 && FOO != 1
+#error FOOB not 42 and FOO not 1
+#else
+int foo4() { return 0; }
+#endif
+
+#if FOOB == 42 || FOO != 1
+int foo5() { return 0; }
+#else
+#error FOOB is 42 or FOO is not 1
+#endif
+
+#if FOO != 1 || FOOB != 42
+#error FOO is 1 or FOOB is 42
+#else
+int foo6() { return 0; }
+#endif
+
+int main()
+{
+ foo1();
+ foo2();
+ foo3();
+ foo4();
+ foo5();
+ foo6();
+}
diff --git a/tests/if5-k.experr b/tests/if5-k.experr
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/tests/if5-k.experr
diff --git a/tests/if5-k.expout b/tests/if5-k.expout
new file mode 100644
index 000000000000..4ae22c63d84a
--- /dev/null
+++ b/tests/if5-k.expout
@@ -0,0 +1,56 @@
+/* Copyright 2004, 2008 Bob Proulx <bob@proulx.com>
+Distributed under the two-clause BSD licence;
+see the COPYING file for details. */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+/* This code is passed through. "#if 0 else" */
+
+/* This code is passed through. "#if 1 then" */
+
+#if FOOB == 42
+int foo1() { return 0; }
+#else
+#error FOOB not 42
+#endif
+
+#if FOOB != 42
+#error FOO is 2
+#else
+int foo2() { return 0; }
+#endif
+
+#if FOOB == 42 || FOO == 1
+intx foo3() { return 0; }
+#else
+#error FOO not 1 or BAR not 1
+#endif
+
+#if FOOB != 42 && FOO != 1
+#error FOOB not 42 and FOO not 1
+#else
+int foo4() { return 0; }
+#endif
+
+#if FOOB == 42 || FOO != 1
+int foo5() { return 0; }
+#else
+#error FOOB is 42 or FOO is not 1
+#endif
+
+#if FOO != 1 || FOOB != 42
+#error FOO is 1 or FOOB is 42
+#else
+int foo6() { return 0; }
+#endif
+
+int main()
+{
+ foo1();
+ foo2();
+ foo3();
+ foo4();
+ foo5();
+ foo6();
+}
diff --git a/tests/if5-k.exprc b/tests/if5-k.exprc
new file mode 100644
index 000000000000..d00491fd7e5b
--- /dev/null
+++ b/tests/if5-k.exprc
@@ -0,0 +1 @@
+1
diff --git a/tests/if5-k.sh b/tests/if5-k.sh
new file mode 100644
index 000000000000..01d92be152b3
--- /dev/null
+++ b/tests/if5-k.sh
@@ -0,0 +1 @@
+unifdef -k if5-k.c
diff --git a/tests/if5-kDU.c b/tests/if5-kDU.c
new file mode 100644
index 000000000000..2be184790ce8
--- /dev/null
+++ b/tests/if5-kDU.c
@@ -0,0 +1,64 @@
+/* Copyright 2004, 2008 Bob Proulx <bob@proulx.com>
+Distributed under the two-clause BSD licence;
+see the COPYING file for details. */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#if 0
+/* This code is commented out. "#if 0 then" */
+#else
+/* This code is passed through. "#if 0 else" */
+#endif
+
+#if 1
+/* This code is passed through. "#if 1 then" */
+#else
+/* This code is passed through. "#if 1 else" */
+#endif
+
+#if FOOB == 42
+int foo1() { return 0; }
+#else
+#error FOOB not 42
+#endif
+
+#if FOOB != 42
+#error FOO is 2
+#else
+int foo2() { return 0; }
+#endif
+
+#if FOOB == 42 || FOO == 1
+intx foo3() { return 0; }
+#else
+#error FOO not 1 or BAR not 1
+#endif
+
+#if FOOB != 42 && FOO != 1
+#error FOOB not 42 and FOO not 1
+#else
+int foo4() { return 0; }
+#endif
+
+#if FOOB == 42 || FOO != 1
+int foo5() { return 0; }
+#else
+#error FOOB is 42 or FOO is not 1
+#endif
+
+#if FOO != 1 || FOOB != 42
+#error FOO is 1 or FOOB is 42
+#else
+int foo6() { return 0; }
+#endif
+
+int main()
+{
+ foo1();
+ foo2();
+ foo3();
+ foo4();
+ foo5();
+ foo6();
+}
diff --git a/tests/if5-kDU.experr b/tests/if5-kDU.experr
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/tests/if5-kDU.experr
diff --git a/tests/if5-kDU.expout b/tests/if5-kDU.expout
new file mode 100644
index 000000000000..a8de2a19e987
--- /dev/null
+++ b/tests/if5-kDU.expout
@@ -0,0 +1,32 @@
+/* Copyright 2004, 2008 Bob Proulx <bob@proulx.com>
+Distributed under the two-clause BSD licence;
+see the COPYING file for details. */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+/* This code is passed through. "#if 0 else" */
+
+/* This code is passed through. "#if 1 then" */
+
+int foo1() { return 0; }
+
+int foo2() { return 0; }
+
+intx foo3() { return 0; }
+
+int foo4() { return 0; }
+
+int foo5() { return 0; }
+
+int foo6() { return 0; }
+
+int main()
+{
+ foo1();
+ foo2();
+ foo3();
+ foo4();
+ foo5();
+ foo6();
+}
diff --git a/tests/if5-kDU.exprc b/tests/if5-kDU.exprc
new file mode 100644
index 000000000000..d00491fd7e5b
--- /dev/null
+++ b/tests/if5-kDU.exprc
@@ -0,0 +1 @@
+1
diff --git a/tests/if5-kDU.sh b/tests/if5-kDU.sh
new file mode 100644
index 000000000000..71f1677ee424
--- /dev/null
+++ b/tests/if5-kDU.sh
@@ -0,0 +1 @@
+unifdef -k -DFOO=1 -DFOOB=42 -UBAR if5-kDU.c
diff --git a/tests/if5.c b/tests/if5.c
new file mode 100644
index 000000000000..5edba56817dc
--- /dev/null
+++ b/tests/if5.c
@@ -0,0 +1,80 @@
+/* Copyright 2004 Bob Proulx <bob@proulx.com>
+Distributed under the two-clause BSD licence;
+see the COPYING file for details. */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#if FOOB == 42
+int foo1() { return 0; }
+#else
+#error FOOB not 42
+#endif
+
+#if FOOB != 42
+#error FOO is 2
+#else
+int foo2() { return 0; }
+#endif
+
+#if FOOB == 42 || FOO == 1
+int foo3() { return 0; }
+#else
+#error FOO not 1 or BAR not 1
+#endif
+
+#if FOOB != 42 && FOO != 1
+#error FOOB not 42 and FOO not 1
+#else
+int foo4() { return 0; }
+#endif
+
+#if FOOB == 42 || FOO != 1
+int foo5() { return 0; }
+#else
+#error FOOB is 42 or FOO is not 1
+#endif
+
+#if FOO != 1 || FOOB != 42
+#error FOO is 1 or FOOB is 42
+#else
+int foo6() { return 0; }
+#endif
+
+#if FOO > FOOB
+#error FOO is greater than FOOB
+#else
+int foo7() { return 0; }
+#endif
+
+#if FOOB < FOO
+#error FOOB is less than FOO
+#else
+int foo8() { return 0; }
+#endif
+
+#if FOO >= FOOB
+#error FOO is greater than or equal FOOB
+#else
+int foo9() { return 0; }
+#endif
+
+#if FOOB <= FOO
+#error FOOB is less than or equal FOO
+#else
+int foo10() { return 0; }
+#endif
+
+int main()
+{
+ foo1();
+ foo2();
+ foo3();
+ foo4();
+ foo5();
+ foo6();
+ foo7();
+ foo8();
+ foo9();
+ foo10();
+}
diff --git a/tests/if5.experr b/tests/if5.experr
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/tests/if5.experr
diff --git a/tests/if5.expout b/tests/if5.expout
new file mode 100644
index 000000000000..ffacc5e5a97f
--- /dev/null
+++ b/tests/if5.expout
@@ -0,0 +1,40 @@
+/* Copyright 2004 Bob Proulx <bob@proulx.com>
+Distributed under the two-clause BSD licence;
+see the COPYING file for details. */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+int foo1() { return 0; }
+
+int foo2() { return 0; }
+
+int foo3() { return 0; }
+
+int foo4() { return 0; }
+
+int foo5() { return 0; }
+
+int foo6() { return 0; }
+
+int foo7() { return 0; }
+
+int foo8() { return 0; }
+
+int foo9() { return 0; }
+
+int foo10() { return 0; }
+
+int main()
+{
+ foo1();
+ foo2();
+ foo3();
+ foo4();
+ foo5();
+ foo6();
+ foo7();
+ foo8();
+ foo9();
+ foo10();
+}
diff --git a/tests/if5.exprc b/tests/if5.exprc
new file mode 100644
index 000000000000..d00491fd7e5b
--- /dev/null
+++ b/tests/if5.exprc
@@ -0,0 +1 @@
+1
diff --git a/tests/if5.sh b/tests/if5.sh
new file mode 100644
index 000000000000..e9417fbc800c
--- /dev/null
+++ b/tests/if5.sh
@@ -0,0 +1 @@
+unifdef -DFOO=1 -DFOOB=42 -UBAR if5.c
diff --git a/tests/if6.c b/tests/if6.c
new file mode 100644
index 000000000000..6abadb1106e2
--- /dev/null
+++ b/tests/if6.c
@@ -0,0 +1,11 @@
+#if F1
+int f1() { return 0; }
+#elif F2
+int f2() { return 0; }
+#elif F3
+int f3() { return 0; }
+#elif F4
+int f4() { return 0; }
+#else
+int f() { return 0; }
+#endif
diff --git a/tests/if6.h b/tests/if6.h
new file mode 100644
index 000000000000..5c2faa2d6223
--- /dev/null
+++ b/tests/if6.h
@@ -0,0 +1,2 @@
+#undef gruntfuttock
+#define F1 1
diff --git a/tests/if6a.experr b/tests/if6a.experr
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/tests/if6a.experr
diff --git a/tests/if6a.expout b/tests/if6a.expout
new file mode 100644
index 000000000000..c51d7a6bec42
--- /dev/null
+++ b/tests/if6a.expout
@@ -0,0 +1 @@
+int f1() { return 0; }
diff --git a/tests/if6a.exprc b/tests/if6a.exprc
new file mode 100644
index 000000000000..d00491fd7e5b
--- /dev/null
+++ b/tests/if6a.exprc
@@ -0,0 +1 @@
+1
diff --git a/tests/if6a.sh b/tests/if6a.sh
new file mode 100644
index 000000000000..fec1e5f9ff27
--- /dev/null
+++ b/tests/if6a.sh
@@ -0,0 +1 @@
+unifdef -DF1 if6.c
diff --git a/tests/if6b.experr b/tests/if6b.experr
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/tests/if6b.experr
diff --git a/tests/if6b.expout b/tests/if6b.expout
new file mode 100644
index 000000000000..0b7aa04243fb
--- /dev/null
+++ b/tests/if6b.expout
@@ -0,0 +1,5 @@
+#if F1
+int f1() { return 0; }
+#else
+int f2() { return 0; }
+#endif
diff --git a/tests/if6b.exprc b/tests/if6b.exprc
new file mode 100644
index 000000000000..d00491fd7e5b
--- /dev/null
+++ b/tests/if6b.exprc
@@ -0,0 +1 @@
+1
diff --git a/tests/if6b.sh b/tests/if6b.sh
new file mode 100644
index 000000000000..bc46c0065c66
--- /dev/null
+++ b/tests/if6b.sh
@@ -0,0 +1 @@
+unifdef -DF2 if6.c
diff --git a/tests/if6c.experr b/tests/if6c.experr
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/tests/if6c.experr
diff --git a/tests/if6c.expout b/tests/if6c.expout
new file mode 100644
index 000000000000..03341d93d850
--- /dev/null
+++ b/tests/if6c.expout
@@ -0,0 +1,7 @@
+#if F1
+int f1() { return 0; }
+#elif F2
+int f2() { return 0; }
+#else
+int f3() { return 0; }
+#endif
diff --git a/tests/if6c.exprc b/tests/if6c.exprc
new file mode 100644
index 000000000000..d00491fd7e5b
--- /dev/null
+++ b/tests/if6c.exprc
@@ -0,0 +1 @@
+1
diff --git a/tests/if6c.sh b/tests/if6c.sh
new file mode 100644
index 000000000000..996a50dae773
--- /dev/null
+++ b/tests/if6c.sh
@@ -0,0 +1 @@
+unifdef -DF3 if6.c
diff --git a/tests/if6d.experr b/tests/if6d.experr
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/tests/if6d.experr
diff --git a/tests/if6d.expout b/tests/if6d.expout
new file mode 100644
index 000000000000..76d70116976d
--- /dev/null
+++ b/tests/if6d.expout
@@ -0,0 +1,9 @@
+#if F1
+int f1() { return 0; }
+#elif F2
+int f2() { return 0; }
+#elif F3
+int f3() { return 0; }
+#else
+int f4() { return 0; }
+#endif
diff --git a/tests/if6d.exprc b/tests/if6d.exprc
new file mode 100644
index 000000000000..d00491fd7e5b
--- /dev/null
+++ b/tests/if6d.exprc
@@ -0,0 +1 @@
+1
diff --git a/tests/if6d.sh b/tests/if6d.sh
new file mode 100644
index 000000000000..a9f180788cce
--- /dev/null
+++ b/tests/if6d.sh
@@ -0,0 +1 @@
+unifdef -DF4 if6.c
diff --git a/tests/if7.c b/tests/if7.c
new file mode 100644
index 000000000000..1f86f8f598ea
--- /dev/null
+++ b/tests/if7.c
@@ -0,0 +1,94 @@
+/*
+Distributed under the two-clause BSD licence;
+see the COPYING file for details. */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#if (FOOB | FOO) == 43
+int foo1() { return 0; }
+#else
+#error FOOB bitwise-or FOO is not 43
+#endif
+
+#if (FOO ^ FOO) == 0
+int foo2() { return 0; }
+#else
+#error FOO bitwise-xor FOO is not 0
+#endif
+
+#if (FOOB & 2) == 2
+int foo3() { return 0; }
+#else
+#error FOOB bitwise-and 2 is not 2
+#endif
+
+#if (FOO << 1) == 2
+int foo4() { return 0; }
+#else
+#error FOO left-shift 2 is not 2
+#endif
+
+#if (FOOB >> 4) == 2
+int foo5() { return 0; }
+#else
+#error FOOB right-shift 2 is not 2
+#endif
+
+#if (FOOB + FOO) == 43
+int foo6() { return 0; }
+#else
+#error FOOB add FOO is not 43
+#endif
+
+#if (FOOB - FOO) == 41
+int foo7() { return 0; }
+#else
+#error FOOB subtract FOO is not 41
+#endif
+
+#if (FOOB * 2) == 84
+int foo8() { return 0; }
+#else
+#error FOOB multiply 2 is not 84
+#endif
+
+#if (FOOB / 2) == 21
+int foo9() { return 0; }
+#else
+#error FOOB divided 2 is not 21
+#endif
+
+#if (FOOB % FOO) == 0
+int foo10() { return 0; }
+#else
+#error FOOB modulo FOO is not 0
+#endif
+
+#if ~(FOOB) == -43
+int foo11() { return 0; }
+#else
+#error bitwise-not FOOB is not -43
+#endif
+
+#if -(FOOB) == -42
+int foo12() { return 0; }
+#else
+#error negate FOOB is not -42
+#endif
+
+int main()
+{
+ foo1();
+ foo2();
+ foo3();
+ foo4();
+ foo5();
+ foo6();
+ foo7();
+ foo8();
+ foo9();
+ foo10();
+ foo11();
+ foo12();
+}
diff --git a/tests/if7.experr b/tests/if7.experr
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/tests/if7.experr
diff --git a/tests/if7.expout b/tests/if7.expout
new file mode 100644
index 000000000000..136a82a41bf6
--- /dev/null
+++ b/tests/if7.expout
@@ -0,0 +1,46 @@
+/*
+Distributed under the two-clause BSD licence;
+see the COPYING file for details. */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+int foo1() { return 0; }
+
+int foo2() { return 0; }
+
+int foo3() { return 0; }
+
+int foo4() { return 0; }
+
+int foo5() { return 0; }
+
+int foo6() { return 0; }
+
+int foo7() { return 0; }
+
+int foo8() { return 0; }
+
+int foo9() { return 0; }
+
+int foo10() { return 0; }
+
+int foo11() { return 0; }
+
+int foo12() { return 0; }
+
+int main()
+{
+ foo1();
+ foo2();
+ foo3();
+ foo4();
+ foo5();
+ foo6();
+ foo7();
+ foo8();
+ foo9();
+ foo10();
+ foo11();
+ foo12();
+}
diff --git a/tests/if7.exprc b/tests/if7.exprc
new file mode 100644
index 000000000000..d00491fd7e5b
--- /dev/null
+++ b/tests/if7.exprc
@@ -0,0 +1 @@
+1
diff --git a/tests/if7.sh b/tests/if7.sh
new file mode 100644
index 000000000000..107d5ed739ed
--- /dev/null
+++ b/tests/if7.sh
@@ -0,0 +1 @@
+unifdef -DFOO=1 -DFOOB=42 -UBAR if7.c
diff --git a/tests/indirect.experr b/tests/indirect.experr
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/tests/indirect.experr
diff --git a/tests/indirect.expout b/tests/indirect.expout
new file mode 100644
index 000000000000..56ae03cc38de
--- /dev/null
+++ b/tests/indirect.expout
@@ -0,0 +1,16 @@
+/* Copyright 2004 Bob Proulx <bob@proulx.com>
+Distributed under the two-clause BSD licence;
+see the COPYING file for details. */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+int foo() { return 0; }
+
+int bar() { return 0; }
+
+int main()
+{
+ foo();
+ bar();
+}
diff --git a/tests/indirect.exprc b/tests/indirect.exprc
new file mode 100644
index 000000000000..d00491fd7e5b
--- /dev/null
+++ b/tests/indirect.exprc
@@ -0,0 +1 @@
+1
diff --git a/tests/indirect.sh b/tests/indirect.sh
new file mode 100644
index 000000000000..32fdee059b22
--- /dev/null
+++ b/tests/indirect.sh
@@ -0,0 +1 @@
+unifdef -DFOO=ZIG -DZIG -DFOOB=42 -UBAR if1.c
diff --git a/tests/multi-generic-sh b/tests/multi-generic-sh
new file mode 100644
index 000000000000..80e568a72c30
--- /dev/null
+++ b/tests/multi-generic-sh
@@ -0,0 +1,15 @@
+mfiles=""
+for f in $files
+do
+ rm -f m$f
+ [ -f $f ] && cp $f m$f
+ mfiles="$mfiles m$f"
+done
+unifdef -M~ $opts $mfiles
+e=$?
+for f in $mfiles
+do
+ diff -u $f~ $f | sed '/^[+-]\{3\} /s/ .*//'
+ rm -f $f~ $f
+done
+exit $e
diff --git a/tests/multi.experr b/tests/multi.experr
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/tests/multi.experr
diff --git a/tests/multi.expout b/tests/multi.expout
new file mode 100644
index 000000000000..c05227749e20
--- /dev/null
+++ b/tests/multi.expout
@@ -0,0 +1,36 @@
+--- mif1.c~
++++ mif1.c
+@@ -5,19 +5,9 @@
+ #include <stdio.h>
+ #include <stdlib.h>
+
+-#if FOO
+ int foo() { return 0; }
+-#else
+-#error FOO not defined
+-#endif
+
+-#if BAR
+-int foo() { return 0; }
+-#elif FOO
+ int bar() { return 0; }
+-#else
+-#error FOO not defined
+-#endif
+
+ int main()
+ {
+--- mif2.c~
++++ mif2.c
+@@ -5,11 +5,7 @@
+ #include <stdio.h>
+ #include <stdlib.h>
+
+-#if defined(FOO)
+ int foo() { return 0; }
+-#else
+-#error FOO not defined
+-#endif
+
+ int main()
+ {
diff --git a/tests/multi.exprc b/tests/multi.exprc
new file mode 100644
index 000000000000..d00491fd7e5b
--- /dev/null
+++ b/tests/multi.exprc
@@ -0,0 +1 @@
+1
diff --git a/tests/multi.sh b/tests/multi.sh
new file mode 100644
index 000000000000..b0553ffea051
--- /dev/null
+++ b/tests/multi.sh
@@ -0,0 +1,3 @@
+opts="-DFOO=1 -DFOOB=42 -UBAR"
+files="if1.c if2.c"
+. ./multi-generic-sh
diff --git a/tests/multilnnum.experr b/tests/multilnnum.experr
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/tests/multilnnum.experr
diff --git a/tests/multilnnum.expout b/tests/multilnnum.expout
new file mode 100644
index 000000000000..628b359512f0
--- /dev/null
+++ b/tests/multilnnum.expout
@@ -0,0 +1,42 @@
+--- mif1.c~
++++ mif1.c
+@@ -5,19 +5,13 @@
+ #include <stdio.h>
+ #include <stdlib.h>
+
+-#if FOO
++#line 9 "mif1.c"
+ int foo() { return 0; }
+-#else
+-#error FOO not defined
+-#endif
++#line 13 "mif1.c"
+
+-#if BAR
+-int foo() { return 0; }
+-#elif FOO
++#line 17 "mif1.c"
+ int bar() { return 0; }
+-#else
+-#error FOO not defined
+-#endif
++#line 21 "mif1.c"
+
+ int main()
+ {
+--- mif2.c~
++++ mif2.c
+@@ -5,11 +5,9 @@
+ #include <stdio.h>
+ #include <stdlib.h>
+
+-#if defined(FOO)
++#line 9 "mif2.c"
+ int foo() { return 0; }
+-#else
+-#error FOO not defined
+-#endif
++#line 13 "mif2.c"
+
+ int main()
+ {
diff --git a/tests/multilnnum.exprc b/tests/multilnnum.exprc
new file mode 100644
index 000000000000..d00491fd7e5b
--- /dev/null
+++ b/tests/multilnnum.exprc
@@ -0,0 +1 @@
+1
diff --git a/tests/multilnnum.sh b/tests/multilnnum.sh
new file mode 100644
index 000000000000..df0953ebc2ef
--- /dev/null
+++ b/tests/multilnnum.sh
@@ -0,0 +1,3 @@
+opts="-DFOO=1 -DFOOB=42 -UBAR -n"
+files="if1.c if2.c"
+. ./multi-generic-sh
diff --git a/tests/multimissing.experr b/tests/multimissing.experr
new file mode 100644
index 000000000000..d31b29f67d00
--- /dev/null
+++ b/tests/multimissing.experr
@@ -0,0 +1,4 @@
+unifdef: can't open mifmissing.c: No such file or directory
+diff: mifmissing.c~: No such file or directory
+diff: mifmissing.c: No such file or directory
+diff: mif2.c~: No such file or directory
diff --git a/tests/multimissing.expout b/tests/multimissing.expout
new file mode 100644
index 000000000000..e130b731ac79
--- /dev/null
+++ b/tests/multimissing.expout
@@ -0,0 +1,22 @@
+--- mif1.c~
++++ mif1.c
+@@ -5,19 +5,9 @@
+ #include <stdio.h>
+ #include <stdlib.h>
+
+-#if FOO
+ int foo() { return 0; }
+-#else
+-#error FOO not defined
+-#endif
+
+-#if BAR
+-int foo() { return 0; }
+-#elif FOO
+ int bar() { return 0; }
+-#else
+-#error FOO not defined
+-#endif
+
+ int main()
+ {
diff --git a/tests/multimissing.exprc b/tests/multimissing.exprc
new file mode 100644
index 000000000000..0cfbf08886fc
--- /dev/null
+++ b/tests/multimissing.exprc
@@ -0,0 +1 @@
+2
diff --git a/tests/multimissing.sh b/tests/multimissing.sh
new file mode 100644
index 000000000000..9c51147863b9
--- /dev/null
+++ b/tests/multimissing.sh
@@ -0,0 +1,3 @@
+opts="-DFOO=1 -DFOOB=42 -UBAR"
+files="if1.c ifmissing.c if2.c"
+. ./multi-generic-sh
diff --git a/tests/multinewline.experr b/tests/multinewline.experr
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/tests/multinewline.experr
diff --git a/tests/multinewline.expout b/tests/multinewline.expout
new file mode 100644
index 000000000000..ff6118e57b6f
--- /dev/null
+++ b/tests/multinewline.expout
@@ -0,0 +1,39 @@
+--- mcrlf.c~
++++ mcrlf.c
+@@ -1,14 +1,4 @@
+-#if F1
+ int f1() { return 0; }
+-#elif F2
+-int f2() { return 0; }
+-#elif F3
+-int f3() { return 0; }
+-#elif F4
+-int f4() { return 0; }
+-#else
+-int f() { return 0; }
+-#endif
+ \/
+ /\
+ comment
+--- mif1.c~
++++ mif1.c
+@@ -5,18 +5,12 @@
+ #include <stdio.h>
+ #include <stdlib.h>
+
+-#if FOO
+ int foo() { return 0; }
+-#else
+-#error FOO not defined
+-#endif
+
+ #if BAR
+ int foo() { return 0; }
+-#elif FOO
+-int bar() { return 0; }
+ #else
+-#error FOO not defined
++int bar() { return 0; }
+ #endif
+
+ int main()
diff --git a/tests/multinewline.exprc b/tests/multinewline.exprc
new file mode 100644
index 000000000000..d00491fd7e5b
--- /dev/null
+++ b/tests/multinewline.exprc
@@ -0,0 +1 @@
+1
diff --git a/tests/multinewline.sh b/tests/multinewline.sh
new file mode 100644
index 000000000000..19287a6340f6
--- /dev/null
+++ b/tests/multinewline.sh
@@ -0,0 +1,3 @@
+opts="-DFOO -DF1"
+files="crlf.c if1.c"
+. ./multi-generic-sh
diff --git a/tests/none.c b/tests/none.c
new file mode 100644
index 000000000000..09d66b69ba9f
--- /dev/null
+++ b/tests/none.c
@@ -0,0 +1,5 @@
+/* Copyright 2004 Bob Proulx <bob@proulx.com>
+Distributed under the two-clause BSD licence;
+see the COPYING file for details. */
+
+int foo() { return 0; }
diff --git a/tests/none.experr b/tests/none.experr
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/tests/none.experr
diff --git a/tests/none.expout b/tests/none.expout
new file mode 100644
index 000000000000..09d66b69ba9f
--- /dev/null
+++ b/tests/none.expout
@@ -0,0 +1,5 @@
+/* Copyright 2004 Bob Proulx <bob@proulx.com>
+Distributed under the two-clause BSD licence;
+see the COPYING file for details. */
+
+int foo() { return 0; }
diff --git a/tests/none.exprc b/tests/none.exprc
new file mode 100644
index 000000000000..573541ac9702
--- /dev/null
+++ b/tests/none.exprc
@@ -0,0 +1 @@
+0
diff --git a/tests/none.sh b/tests/none.sh
new file mode 100644
index 000000000000..622f53b28434
--- /dev/null
+++ b/tests/none.sh
@@ -0,0 +1 @@
+unifdef -DFOO=1 -DFOOB=42 -UBAR none.c
diff --git a/tests/outdir.experr b/tests/outdir.experr
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/tests/outdir.experr
diff --git a/tests/outdir.expout b/tests/outdir.expout
new file mode 100644
index 000000000000..56ae03cc38de
--- /dev/null
+++ b/tests/outdir.expout
@@ -0,0 +1,16 @@
+/* Copyright 2004 Bob Proulx <bob@proulx.com>
+Distributed under the two-clause BSD licence;
+see the COPYING file for details. */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+int foo() { return 0; }
+
+int bar() { return 0; }
+
+int main()
+{
+ foo();
+ bar();
+}
diff --git a/tests/outdir.exprc b/tests/outdir.exprc
new file mode 100644
index 000000000000..d00491fd7e5b
--- /dev/null
+++ b/tests/outdir.exprc
@@ -0,0 +1 @@
+1
diff --git a/tests/outdir.sh b/tests/outdir.sh
new file mode 100644
index 000000000000..c2de8547e646
--- /dev/null
+++ b/tests/outdir.sh
@@ -0,0 +1,6 @@
+mkdir -p outdir
+unifdef -DFOO=1 -DFOOB=42 -UBAR -ooutdir/outfile.c if1.c
+e=$?
+cat outdir/outfile.c
+rm -r outdir
+exit $e
diff --git a/tests/outeperm.experr b/tests/outeperm.experr
new file mode 100644
index 000000000000..bed245174cf6
--- /dev/null
+++ b/tests/outeperm.experr
@@ -0,0 +1 @@
+unifdef: can't create outdir/outfile.c: Permission denied
diff --git a/tests/outeperm.expout b/tests/outeperm.expout
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/tests/outeperm.expout
diff --git a/tests/outeperm.exprc b/tests/outeperm.exprc
new file mode 100644
index 000000000000..0cfbf08886fc
--- /dev/null
+++ b/tests/outeperm.exprc
@@ -0,0 +1 @@
+2
diff --git a/tests/outeperm.sh b/tests/outeperm.sh
new file mode 100644
index 000000000000..5f5abf0e41bd
--- /dev/null
+++ b/tests/outeperm.sh
@@ -0,0 +1,6 @@
+mkdir -p outdir
+chmod 555 outdir
+unifdef -DFOO=1 -DFOOB=42 -UBAR -ooutdir/outfile.c if1.c
+e=$?
+rmdir outdir
+exit $e
diff --git a/tests/outfile.experr b/tests/outfile.experr
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/tests/outfile.experr
diff --git a/tests/outfile.expout b/tests/outfile.expout
new file mode 100644
index 000000000000..56ae03cc38de
--- /dev/null
+++ b/tests/outfile.expout
@@ -0,0 +1,16 @@
+/* Copyright 2004 Bob Proulx <bob@proulx.com>
+Distributed under the two-clause BSD licence;
+see the COPYING file for details. */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+int foo() { return 0; }
+
+int bar() { return 0; }
+
+int main()
+{
+ foo();
+ bar();
+}
diff --git a/tests/outfile.exprc b/tests/outfile.exprc
new file mode 100644
index 000000000000..d00491fd7e5b
--- /dev/null
+++ b/tests/outfile.exprc
@@ -0,0 +1 @@
+1
diff --git a/tests/outfile.sh b/tests/outfile.sh
new file mode 100644
index 000000000000..cdae73da9a44
--- /dev/null
+++ b/tests/outfile.sh
@@ -0,0 +1,5 @@
+unifdef -DFOO=1 -DFOOB=42 -UBAR -ooutfile.c if1.c
+e=$?
+cat outfile.c
+rm outfile.c
+exit $e
diff --git a/tests/outperms.experr b/tests/outperms.experr
new file mode 100644
index 000000000000..a2ef92c4c82d
--- /dev/null
+++ b/tests/outperms.experr
@@ -0,0 +1 @@
+-rw-r-----
diff --git a/tests/outperms.expout b/tests/outperms.expout
new file mode 100644
index 000000000000..56ae03cc38de
--- /dev/null
+++ b/tests/outperms.expout
@@ -0,0 +1,16 @@
+/* Copyright 2004 Bob Proulx <bob@proulx.com>
+Distributed under the two-clause BSD licence;
+see the COPYING file for details. */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+int foo() { return 0; }
+
+int bar() { return 0; }
+
+int main()
+{
+ foo();
+ bar();
+}
diff --git a/tests/outperms.exprc b/tests/outperms.exprc
new file mode 100644
index 000000000000..d00491fd7e5b
--- /dev/null
+++ b/tests/outperms.exprc
@@ -0,0 +1 @@
+1
diff --git a/tests/outperms.sh b/tests/outperms.sh
new file mode 100644
index 000000000000..9d134620aecd
--- /dev/null
+++ b/tests/outperms.sh
@@ -0,0 +1,7 @@
+umask 027
+unifdef -DFOO=1 -DFOOB=42 -UBAR -ooutfile.c if1.c
+e=$?
+ls -l outfile.c | cut -d' ' -f1 1>&2
+cat outfile.c
+rm outfile.c
+exit $e
diff --git a/tests/overdir.experr b/tests/overdir.experr
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/tests/overdir.experr
diff --git a/tests/overdir.expout b/tests/overdir.expout
new file mode 100644
index 000000000000..56ae03cc38de
--- /dev/null
+++ b/tests/overdir.expout
@@ -0,0 +1,16 @@
+/* Copyright 2004 Bob Proulx <bob@proulx.com>
+Distributed under the two-clause BSD licence;
+see the COPYING file for details. */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+int foo() { return 0; }
+
+int bar() { return 0; }
+
+int main()
+{
+ foo();
+ bar();
+}
diff --git a/tests/overdir.exprc b/tests/overdir.exprc
new file mode 100644
index 000000000000..d00491fd7e5b
--- /dev/null
+++ b/tests/overdir.exprc
@@ -0,0 +1 @@
+1
diff --git a/tests/overdir.sh b/tests/overdir.sh
new file mode 100644
index 000000000000..44124272f6f4
--- /dev/null
+++ b/tests/overdir.sh
@@ -0,0 +1,7 @@
+mkdir -p overdir
+cp if1.c overdir/overwrite.c
+unifdef -DFOO=1 -DFOOB=42 -UBAR -ooverdir/overwrite.c overdir/overwrite.c
+e=$?
+cat overdir/overwrite.c
+rm -r overdir
+exit $e
diff --git a/tests/overenoent.experr b/tests/overenoent.experr
new file mode 100644
index 000000000000..f4e962f30651
--- /dev/null
+++ b/tests/overenoent.experr
@@ -0,0 +1 @@
+unifdef: can't create outfile.c: No such file or directory
diff --git a/tests/overenoent.expout b/tests/overenoent.expout
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/tests/overenoent.expout
diff --git a/tests/overenoent.exprc b/tests/overenoent.exprc
new file mode 100644
index 000000000000..0cfbf08886fc
--- /dev/null
+++ b/tests/overenoent.exprc
@@ -0,0 +1 @@
+2
diff --git a/tests/overenoent.sh b/tests/overenoent.sh
new file mode 100644
index 000000000000..9cbf2ab332ac
--- /dev/null
+++ b/tests/overenoent.sh
@@ -0,0 +1,5 @@
+ln -s nonexistent/path outfile.c
+unifdef -DFOO=1 -DFOOB=42 -UBAR -ooutfile.c if1.c
+e=$?
+rm -f outfile.c
+exit $e
diff --git a/tests/overin.experr b/tests/overin.experr
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/tests/overin.experr
diff --git a/tests/overin.expout b/tests/overin.expout
new file mode 100644
index 000000000000..56ae03cc38de
--- /dev/null
+++ b/tests/overin.expout
@@ -0,0 +1,16 @@
+/* Copyright 2004 Bob Proulx <bob@proulx.com>
+Distributed under the two-clause BSD licence;
+see the COPYING file for details. */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+int foo() { return 0; }
+
+int bar() { return 0; }
+
+int main()
+{
+ foo();
+ bar();
+}
diff --git a/tests/overin.exprc b/tests/overin.exprc
new file mode 100644
index 000000000000..d00491fd7e5b
--- /dev/null
+++ b/tests/overin.exprc
@@ -0,0 +1 @@
+1
diff --git a/tests/overin.sh b/tests/overin.sh
new file mode 100644
index 000000000000..78eb75ab4b80
--- /dev/null
+++ b/tests/overin.sh
@@ -0,0 +1,6 @@
+cp if1.c overin.c
+unifdef -DFOO=1 -DFOOB=42 -UBAR -ooverin.c <overin.c
+e=$?
+cat overin.c
+rm overin.c
+exit $e
diff --git a/tests/overlnnum.experr b/tests/overlnnum.experr
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/tests/overlnnum.experr
diff --git a/tests/overlnnum.expout b/tests/overlnnum.expout
new file mode 100644
index 000000000000..c3f5787a98c4
--- /dev/null
+++ b/tests/overlnnum.expout
@@ -0,0 +1,20 @@
+/* Copyright 2004 Bob Proulx <bob@proulx.com>
+Distributed under the two-clause BSD licence;
+see the COPYING file for details. */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#line 9 "overwrite.c"
+int foo() { return 0; }
+#line 13 "overwrite.c"
+
+#line 17 "overwrite.c"
+int bar() { return 0; }
+#line 21 "overwrite.c"
+
+int main()
+{
+ foo();
+ bar();
+}
diff --git a/tests/overlnnum.exprc b/tests/overlnnum.exprc
new file mode 100644
index 000000000000..d00491fd7e5b
--- /dev/null
+++ b/tests/overlnnum.exprc
@@ -0,0 +1 @@
+1
diff --git a/tests/overlnnum.sh b/tests/overlnnum.sh
new file mode 100644
index 000000000000..f6090bdc0018
--- /dev/null
+++ b/tests/overlnnum.sh
@@ -0,0 +1,6 @@
+cp if1.c overwrite.c
+unifdef -DFOO=1 -DFOOB=42 -UBAR -n -ooverwrite.c overwrite.c
+e=$?
+cat overwrite.c
+rm overwrite.c
+exit $e
diff --git a/tests/overperms.experr b/tests/overperms.experr
new file mode 100644
index 000000000000..9fc8473109d5
--- /dev/null
+++ b/tests/overperms.experr
@@ -0,0 +1,2 @@
+-rw-r-----
+-rw-r-----
diff --git a/tests/overperms.expout b/tests/overperms.expout
new file mode 100644
index 000000000000..56ae03cc38de
--- /dev/null
+++ b/tests/overperms.expout
@@ -0,0 +1,16 @@
+/* Copyright 2004 Bob Proulx <bob@proulx.com>
+Distributed under the two-clause BSD licence;
+see the COPYING file for details. */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+int foo() { return 0; }
+
+int bar() { return 0; }
+
+int main()
+{
+ foo();
+ bar();
+}
diff --git a/tests/overperms.exprc b/tests/overperms.exprc
new file mode 100644
index 000000000000..d00491fd7e5b
--- /dev/null
+++ b/tests/overperms.exprc
@@ -0,0 +1 @@
+1
diff --git a/tests/overperms.sh b/tests/overperms.sh
new file mode 100644
index 000000000000..6de7e5341bb4
--- /dev/null
+++ b/tests/overperms.sh
@@ -0,0 +1,9 @@
+cp if1.c outfile.c
+chmod 640 outfile.c
+ls -l outfile.c | cut -d' ' -f1 1>&2
+unifdef -DFOO=1 -DFOOB=42 -UBAR -m outfile.c
+e=$?
+ls -l outfile.c | cut -d' ' -f1 1>&2
+cat outfile.c
+rm outfile.c
+exit $e
diff --git a/tests/overunchanged.experr b/tests/overunchanged.experr
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/tests/overunchanged.experr
diff --git a/tests/overunchanged.expout b/tests/overunchanged.expout
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/tests/overunchanged.expout
diff --git a/tests/overunchanged.exprc b/tests/overunchanged.exprc
new file mode 100644
index 000000000000..573541ac9702
--- /dev/null
+++ b/tests/overunchanged.exprc
@@ -0,0 +1 @@
+0
diff --git a/tests/overunchanged.sh b/tests/overunchanged.sh
new file mode 100644
index 000000000000..a4a4c790ee14
--- /dev/null
+++ b/tests/overunchanged.sh
@@ -0,0 +1,8 @@
+cp if1.c overunchanged.c
+ls -i overunchanged.c >overunchanged-before
+unifdef -DWEASEL=1 -ooverunchanged.c overunchanged.c
+e=$?
+ls -i overunchanged.c >overunchanged-after
+diff overunchanged-before overunchanged-after
+rm -f overunchanged-before overunchanged-after overunchanged.c
+exit $e
diff --git a/tests/overwrite.experr b/tests/overwrite.experr
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/tests/overwrite.experr
diff --git a/tests/overwrite.expout b/tests/overwrite.expout
new file mode 100644
index 000000000000..56ae03cc38de
--- /dev/null
+++ b/tests/overwrite.expout
@@ -0,0 +1,16 @@
+/* Copyright 2004 Bob Proulx <bob@proulx.com>
+Distributed under the two-clause BSD licence;
+see the COPYING file for details. */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+int foo() { return 0; }
+
+int bar() { return 0; }
+
+int main()
+{
+ foo();
+ bar();
+}
diff --git a/tests/overwrite.exprc b/tests/overwrite.exprc
new file mode 100644
index 000000000000..d00491fd7e5b
--- /dev/null
+++ b/tests/overwrite.exprc
@@ -0,0 +1 @@
+1
diff --git a/tests/overwrite.sh b/tests/overwrite.sh
new file mode 100644
index 000000000000..8d9a9c7d7ecf
--- /dev/null
+++ b/tests/overwrite.sh
@@ -0,0 +1,6 @@
+cp if1.c overwrite.c
+unifdef -DFOO=1 -DFOOB=42 -UBAR -ooverwrite.c overwrite.c
+e=$?
+cat overwrite.c
+rm overwrite.c
+exit $e
diff --git a/tests/recursive.experr b/tests/recursive.experr
new file mode 100644
index 000000000000..bcb00f76d094
--- /dev/null
+++ b/tests/recursive.experr
@@ -0,0 +1,120 @@
+unifdef: addsym FOO=BAR
+unifdef: addsym BAR=ZIG
+unifdef: addsym ZIG=BAR
+unifdef: addsym QUX=QUX
+unifdef: findsym BAR=ZIG
+unifdef: indir... FOO=BAR
+unifdef: ...ectsym FOO=ZIG
+unifdef: findsym ZIG=BAR
+unifdef: indir... BAR=ZIG
+unifdef: ...ectsym BAR=BAR
+unifdef: findsym BAR=BAR
+unifdef: findsym QUX=QUX
+unifdef: findsym ZIG=BAR
+unifdef: indir... FOO=ZIG
+unifdef: ...ectsym FOO=BAR
+unifdef: findsym BAR=BAR
+unifdef: findsym BAR=BAR
+unifdef: findsym QUX=QUX
+unifdef: findsym BAR=BAR
+unifdef: findsym BAR=BAR
+unifdef: findsym BAR=BAR
+unifdef: findsym QUX=QUX
+unifdef: parser line 1 state C comment START line
+unifdef: process line 1 PLAIN -> OUTSIDE depth 0
+unifdef: parser line 2 state C comment START line
+unifdef: process line 2 PLAIN -> OUTSIDE depth 0
+unifdef: parser line 3 state NO comment START line
+unifdef: process line 3 PLAIN -> OUTSIDE depth 0
+unifdef: parser line 4 state NO comment START line
+unifdef: process line 4 PLAIN -> OUTSIDE depth 0
+unifdef: parser line 5 state NO comment START line
+unifdef: process line 5 PLAIN -> OUTSIDE depth 0
+unifdef: parser line 6 state NO comment START line
+unifdef: process line 6 PLAIN -> OUTSIDE depth 0
+unifdef: parser line 7 state NO comment START line
+unifdef: process line 7 PLAIN -> OUTSIDE depth 0
+unifdef: eval FOO
+
+unifdef: eval0
+unifdef: eval1
+unifdef: eval2
+unifdef: eval3
+unifdef: eval4
+unifdef: eval5
+unifdef: eval6
+unifdef: eval7
+unifdef: eval8
+unifdef: eval9
+unifdef: eval10 symbol
+unifdef: findsym FOO=BAR
+unifdef: eval = 0
+unifdef: parser line 8 state NO comment START line
+unifdef: process line 8 IF -> PASS_MIDDLE depth 1
+unifdef: parser line 9 state NO comment START line
+unifdef: process line 9 PLAIN -> PASS_MIDDLE depth 1
+unifdef: parser line 10 state NO comment START line
+unifdef: process line 10 ELSE -> PASS_ELSE depth 1
+unifdef: parser line 11 state NO comment START line
+unifdef: process line 11 PLAIN -> PASS_ELSE depth 1
+unifdef: parser line 12 state NO comment START line
+unifdef: process line 12 ENDIF -> OUTSIDE depth 0
+unifdef: parser line 13 state NO comment START line
+unifdef: process line 13 PLAIN -> OUTSIDE depth 0
+unifdef: eval BAR
+
+unifdef: eval0
+unifdef: eval1
+unifdef: eval2
+unifdef: eval3
+unifdef: eval4
+unifdef: eval5
+unifdef: eval6
+unifdef: eval7
+unifdef: eval8
+unifdef: eval9
+unifdef: eval10 symbol
+unifdef: findsym BAR=BAR
+unifdef: eval = 0
+unifdef: parser line 14 state NO comment START line
+unifdef: process line 14 IF -> PASS_MIDDLE depth 1
+unifdef: parser line 15 state NO comment START line
+unifdef: process line 15 PLAIN -> PASS_MIDDLE depth 1
+unifdef: eval FOO
+
+unifdef: eval0
+unifdef: eval1
+unifdef: eval2
+unifdef: eval3
+unifdef: eval4
+unifdef: eval5
+unifdef: eval6
+unifdef: eval7
+unifdef: eval8
+unifdef: eval9
+unifdef: eval10 symbol
+unifdef: findsym FOO=BAR
+unifdef: eval = 0
+unifdef: parser line 16 state NO comment START line
+unifdef: process line 16 ELIF -> PASS_MIDDLE depth 1
+unifdef: parser line 17 state NO comment START line
+unifdef: process line 17 PLAIN -> PASS_MIDDLE depth 1
+unifdef: parser line 18 state NO comment START line
+unifdef: process line 18 ELSE -> PASS_ELSE depth 1
+unifdef: parser line 19 state NO comment START line
+unifdef: process line 19 PLAIN -> PASS_ELSE depth 1
+unifdef: parser line 20 state NO comment START line
+unifdef: process line 20 ENDIF -> OUTSIDE depth 0
+unifdef: parser line 21 state NO comment START line
+unifdef: process line 21 PLAIN -> OUTSIDE depth 0
+unifdef: parser line 22 state NO comment START line
+unifdef: process line 22 PLAIN -> OUTSIDE depth 0
+unifdef: parser line 23 state NO comment START line
+unifdef: process line 23 PLAIN -> OUTSIDE depth 0
+unifdef: parser line 24 state NO comment START line
+unifdef: process line 24 PLAIN -> OUTSIDE depth 0
+unifdef: parser line 25 state NO comment START line
+unifdef: process line 25 PLAIN -> OUTSIDE depth 0
+unifdef: parser line 26 state NO comment START line
+unifdef: process line 26 PLAIN -> OUTSIDE depth 0
+unifdef: process line 27 EOF -> OUTSIDE depth 0
diff --git a/tests/recursive.expout b/tests/recursive.expout
new file mode 100644
index 000000000000..9e588c22791c
--- /dev/null
+++ b/tests/recursive.expout
@@ -0,0 +1,26 @@
+/* Copyright 2004 Bob Proulx <bob@proulx.com>
+Distributed under the two-clause BSD licence;
+see the COPYING file for details. */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#if FOO
+int foo() { return 0; }
+#else
+#error FOO not defined
+#endif
+
+#if BAR
+int foo() { return 0; }
+#elif FOO
+int bar() { return 0; }
+#else
+#error FOO not defined
+#endif
+
+int main()
+{
+ foo();
+ bar();
+}
diff --git a/tests/recursive.exprc b/tests/recursive.exprc
new file mode 100644
index 000000000000..573541ac9702
--- /dev/null
+++ b/tests/recursive.exprc
@@ -0,0 +1 @@
+0
diff --git a/tests/recursive.sh b/tests/recursive.sh
new file mode 100644
index 000000000000..eb857de7e133
--- /dev/null
+++ b/tests/recursive.sh
@@ -0,0 +1 @@
+unifdef -d -DFOO=BAR -DBAR=ZIG -DZIG=BAR -DQUX=QUX if1.c
diff --git a/tests/small1.c b/tests/small1.c
new file mode 100644
index 000000000000..eb1c26d0851c
--- /dev/null
+++ b/tests/small1.c
@@ -0,0 +1,17 @@
+/* Copyright 2004 Bob Proulx <bob@proulx.com>
+Distributed under the two-clause BSD licence;
+see the COPYING file for details. */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#ifdef FOO
+int foo() { return 0; }
+#else
+#error FOO not defined
+#endif
+
+int main()
+{
+ foo();
+}
diff --git a/tests/small1.experr b/tests/small1.experr
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/tests/small1.experr
diff --git a/tests/small1.expout b/tests/small1.expout
new file mode 100644
index 000000000000..b64cfc265bd2
--- /dev/null
+++ b/tests/small1.expout
@@ -0,0 +1,13 @@
+/* Copyright 2004 Bob Proulx <bob@proulx.com>
+Distributed under the two-clause BSD licence;
+see the COPYING file for details. */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+int foo() { return 0; }
+
+int main()
+{
+ foo();
+}
diff --git a/tests/small1.exprc b/tests/small1.exprc
new file mode 100644
index 000000000000..d00491fd7e5b
--- /dev/null
+++ b/tests/small1.exprc
@@ -0,0 +1 @@
+1
diff --git a/tests/small1.sh b/tests/small1.sh
new file mode 100644
index 000000000000..b948726042ec
--- /dev/null
+++ b/tests/small1.sh
@@ -0,0 +1 @@
+unifdef -DFOO=1 -DFOOB=42 -UBAR small1.c
diff --git a/tests/small2.c b/tests/small2.c
new file mode 100644
index 000000000000..4a5c813cb0f4
--- /dev/null
+++ b/tests/small2.c
@@ -0,0 +1,17 @@
+/* Copyright 2004 Bob Proulx <bob@proulx.com>
+Distributed under the two-clause BSD licence;
+see the COPYING file for details. */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#ifndef BAR
+int bar() { return 0; }
+#else
+#error BAR not defined
+#endif
+
+int main()
+{
+ bar();
+}
diff --git a/tests/small2.experr b/tests/small2.experr
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/tests/small2.experr
diff --git a/tests/small2.expout b/tests/small2.expout
new file mode 100644
index 000000000000..5c1f8b4f23f0
--- /dev/null
+++ b/tests/small2.expout
@@ -0,0 +1,13 @@
+/* Copyright 2004 Bob Proulx <bob@proulx.com>
+Distributed under the two-clause BSD licence;
+see the COPYING file for details. */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+int bar() { return 0; }
+
+int main()
+{
+ bar();
+}
diff --git a/tests/small2.exprc b/tests/small2.exprc
new file mode 100644
index 000000000000..d00491fd7e5b
--- /dev/null
+++ b/tests/small2.exprc
@@ -0,0 +1 @@
+1
diff --git a/tests/small2.sh b/tests/small2.sh
new file mode 100644
index 000000000000..fdedd7d88f2e
--- /dev/null
+++ b/tests/small2.sh
@@ -0,0 +1 @@
+unifdef -DFOO=1 -DFOOB=42 -UBAR small2.c
diff --git a/tests/spaces1.c b/tests/spaces1.c
new file mode 100644
index 000000000000..947dacf55fa1
--- /dev/null
+++ b/tests/spaces1.c
@@ -0,0 +1,17 @@
+/* Copyright 2004 Bob Proulx <bob@proulx.com>
+Distributed under the two-clause BSD licence;
+see the COPYING file for details. */
+
+# include <stdio.h>
+# include <stdlib.h>
+
+# ifdef FOO
+int foo() { return 0; }
+# else
+# error FOO not defined
+# endif
+
+int main()
+{
+ foo();
+}
diff --git a/tests/spaces1.experr b/tests/spaces1.experr
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/tests/spaces1.experr
diff --git a/tests/spaces1.expout b/tests/spaces1.expout
new file mode 100644
index 000000000000..766f2358b55e
--- /dev/null
+++ b/tests/spaces1.expout
@@ -0,0 +1,13 @@
+/* Copyright 2004 Bob Proulx <bob@proulx.com>
+Distributed under the two-clause BSD licence;
+see the COPYING file for details. */
+
+# include <stdio.h>
+# include <stdlib.h>
+
+int foo() { return 0; }
+
+int main()
+{
+ foo();
+}
diff --git a/tests/spaces1.exprc b/tests/spaces1.exprc
new file mode 100644
index 000000000000..d00491fd7e5b
--- /dev/null
+++ b/tests/spaces1.exprc
@@ -0,0 +1 @@
+1
diff --git a/tests/spaces1.sh b/tests/spaces1.sh
new file mode 100644
index 000000000000..e5ef62bc65bb
--- /dev/null
+++ b/tests/spaces1.sh
@@ -0,0 +1 @@
+unifdef -DFOO=1 -DFOOB=42 -UBAR spaces1.c
diff --git a/tests/spaces2.c b/tests/spaces2.c
new file mode 100644
index 000000000000..f5a250a1ee69
--- /dev/null
+++ b/tests/spaces2.c
@@ -0,0 +1,17 @@
+/* Copyright 2004 Bob Proulx <bob@proulx.com>
+Distributed under the two-clause BSD licence;
+see the COPYING file for details. */
+
+# include <stdio.h>
+# include <stdlib.h>
+
+# ifndef BAR
+int bar() { return 0; }
+# else
+# error BAR defined
+# endif
+
+int main()
+{
+ bar();
+}
diff --git a/tests/spaces2.experr b/tests/spaces2.experr
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/tests/spaces2.experr
diff --git a/tests/spaces2.expout b/tests/spaces2.expout
new file mode 100644
index 000000000000..7d377599b7c3
--- /dev/null
+++ b/tests/spaces2.expout
@@ -0,0 +1,13 @@
+/* Copyright 2004 Bob Proulx <bob@proulx.com>
+Distributed under the two-clause BSD licence;
+see the COPYING file for details. */
+
+# include <stdio.h>
+# include <stdlib.h>
+
+int bar() { return 0; }
+
+int main()
+{
+ bar();
+}
diff --git a/tests/spaces2.exprc b/tests/spaces2.exprc
new file mode 100644
index 000000000000..d00491fd7e5b
--- /dev/null
+++ b/tests/spaces2.exprc
@@ -0,0 +1 @@
+1
diff --git a/tests/spaces2.sh b/tests/spaces2.sh
new file mode 100644
index 000000000000..cb80f89d5b75
--- /dev/null
+++ b/tests/spaces2.sh
@@ -0,0 +1 @@
+unifdef -DFOO=1 -DFOOB=42 -UBAR spaces2.c
diff --git a/tests/spaces3.c b/tests/spaces3.c
new file mode 100644
index 000000000000..7284634a2968
--- /dev/null
+++ b/tests/spaces3.c
@@ -0,0 +1,17 @@
+/* Copyright 2004 Bob Proulx <bob@proulx.com>
+Distributed under the two-clause BSD licence;
+see the COPYING file for details. */
+
+# include <stdio.h>
+ # include <stdlib.h>
+
+ # ifndef BAR
+int bar() { return 0; }
+ # else
+ # error BAR defined
+ # endif
+
+int main()
+{
+ bar();
+}
diff --git a/tests/spaces3.experr b/tests/spaces3.experr
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/tests/spaces3.experr
diff --git a/tests/spaces3.expout b/tests/spaces3.expout
new file mode 100644
index 000000000000..60aceee7571d
--- /dev/null
+++ b/tests/spaces3.expout
@@ -0,0 +1,13 @@
+/* Copyright 2004 Bob Proulx <bob@proulx.com>
+Distributed under the two-clause BSD licence;
+see the COPYING file for details. */
+
+# include <stdio.h>
+ # include <stdlib.h>
+
+int bar() { return 0; }
+
+int main()
+{
+ bar();
+}
diff --git a/tests/spaces3.exprc b/tests/spaces3.exprc
new file mode 100644
index 000000000000..d00491fd7e5b
--- /dev/null
+++ b/tests/spaces3.exprc
@@ -0,0 +1 @@
+1
diff --git a/tests/spaces3.sh b/tests/spaces3.sh
new file mode 100644
index 000000000000..0bce1847ab0c
--- /dev/null
+++ b/tests/spaces3.sh
@@ -0,0 +1 @@
+unifdef -DFOO=1 -DFOOB=42 -UBAR spaces3.c
diff --git a/tests/spaces4.c b/tests/spaces4.c
new file mode 100644
index 000000000000..6fbc6f239891
--- /dev/null
+++ b/tests/spaces4.c
@@ -0,0 +1,17 @@
+/* Copyright 2004 Bob Proulx <bob@proulx.com>
+Distributed under the two-clause BSD licence;
+see the COPYING file for details. */
+
+# include <stdio.h>
+ # include <stdlib.h>
+
+ # ifdef FOO
+int foo() { return 0; }
+ # else
+ # error FOO defined
+ # endif
+
+int main()
+{
+ foo();
+}
diff --git a/tests/spaces4.experr b/tests/spaces4.experr
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/tests/spaces4.experr
diff --git a/tests/spaces4.expout b/tests/spaces4.expout
new file mode 100644
index 000000000000..fbf0d3cba46b
--- /dev/null
+++ b/tests/spaces4.expout
@@ -0,0 +1,13 @@
+/* Copyright 2004 Bob Proulx <bob@proulx.com>
+Distributed under the two-clause BSD licence;
+see the COPYING file for details. */
+
+# include <stdio.h>
+ # include <stdlib.h>
+
+int foo() { return 0; }
+
+int main()
+{
+ foo();
+}
diff --git a/tests/spaces4.exprc b/tests/spaces4.exprc
new file mode 100644
index 000000000000..d00491fd7e5b
--- /dev/null
+++ b/tests/spaces4.exprc
@@ -0,0 +1 @@
+1
diff --git a/tests/spaces4.sh b/tests/spaces4.sh
new file mode 100644
index 000000000000..1390ab7870ac
--- /dev/null
+++ b/tests/spaces4.sh
@@ -0,0 +1 @@
+unifdef -DFOO=1 -DFOOB=42 -UBAR spaces4.c
diff --git a/tests/whitespace-1.experr b/tests/whitespace-1.experr
new file mode 100644
index 000000000000..6c7d2adb314a
--- /dev/null
+++ b/tests/whitespace-1.experr
@@ -0,0 +1,2 @@
+unifdef: whitespace.c: 3: Obfuscated preprocessor control line (#if line 1 depth 1)
+unifdef: Output may be truncated
diff --git a/tests/whitespace-1.expout b/tests/whitespace-1.expout
new file mode 100644
index 000000000000..257cc5642cb1
--- /dev/null
+++ b/tests/whitespace-1.expout
@@ -0,0 +1 @@
+foo
diff --git a/tests/whitespace-1.exprc b/tests/whitespace-1.exprc
new file mode 100644
index 000000000000..0cfbf08886fc
--- /dev/null
+++ b/tests/whitespace-1.exprc
@@ -0,0 +1 @@
+2
diff --git a/tests/whitespace-1.sh b/tests/whitespace-1.sh
new file mode 100644
index 000000000000..51ad39bc1768
--- /dev/null
+++ b/tests/whitespace-1.sh
@@ -0,0 +1 @@
+unifdef -DFOO whitespace.c
diff --git a/tests/whitespace-2.experr b/tests/whitespace-2.experr
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/tests/whitespace-2.experr
diff --git a/tests/whitespace-2.expout b/tests/whitespace-2.expout
new file mode 100644
index 000000000000..84cabfea1056
--- /dev/null
+++ b/tests/whitespace-2.expout
@@ -0,0 +1,5 @@
+#ifdef FOO
+foo
+#endif //spong
+
+bar
diff --git a/tests/whitespace-2.exprc b/tests/whitespace-2.exprc
new file mode 100644
index 000000000000..d00491fd7e5b
--- /dev/null
+++ b/tests/whitespace-2.exprc
@@ -0,0 +1 @@
+1
diff --git a/tests/whitespace-2.sh b/tests/whitespace-2.sh
new file mode 100644
index 000000000000..1aa178b5e071
--- /dev/null
+++ b/tests/whitespace-2.sh
@@ -0,0 +1 @@
+unifdef -DBAR whitespace.c
diff --git a/tests/whitespace.c b/tests/whitespace.c
new file mode 100644
index 000000000000..de0b9e4be176
--- /dev/null
+++ b/tests/whitespace.c
@@ -0,0 +1,7 @@
+#ifdef FOO
+foo
+#endif //spong
+
+#ifdef BAR
+bar
+#endif \ No newline at end of file
diff --git a/tests/xterm.experr b/tests/xterm.experr
new file mode 100644
index 000000000000..7938dcdde861
--- /dev/null
+++ b/tests/xterm.experr
@@ -0,0 +1,3 @@
+0
+1
+0
diff --git a/tests/xterm.expout b/tests/xterm.expout
new file mode 100644
index 000000000000..d05d26545dbb
--- /dev/null
+++ b/tests/xterm.expout
@@ -0,0 +1,83 @@
+#define RES_OFFSET(field) XtOffsetOf(XTERM_RESOURCE, field)
+#include <xterm.h>
+#include <version.h>
+#include <X11/cursorfont.h>
+#include <X11/Xlocale.h>
+#include <pwd.h>
+#include <ctype.h>
+#include <data.h>
+#include <error.h>
+#include <menu.h>
+#include <main.h>
+#include <xstrings.h>
+#include <xtermcap.h>
+#include <xterm_io.h>
+#include <sys/stat.h>
+#include <sys/resource.h>
+#define HAS_BSD_GROUPS
+#include <sys/param.h> /* for NOFILE */
+#define WTMP
+#include <stdio.h>
+#define UTMP_STR utmp
+#include <libutil.h> /* openpty() */
+#include <signal.h>
+#include <sys/wait.h>
+#define TERMCAP_ERASE "kb"
+#define VAL_INITIAL_ERASE A2E(8)
+#define VAL_LINE_SPEED B38400
+#define TERMIO_STRUCT struct termios
+#define ttySetAttr(fd, datap) tcsetattr(fd, TCSANOW, datap)
+#define ttyGetAttr(fd, datap) tcgetattr(fd, datap)
+#define ttyFlush(fd) tcflush(fd, TCOFLUSH)
+#define TTYMODE(name) { name, sizeof(name)-1, 0, 0 }
+#define XTTYMODE_intr 0
+#define XTTYMODE_quit 1
+#define XTTYMODE_erase 2
+#define XTTYMODE_kill 3
+#define XTTYMODE_eof 4
+#define XTTYMODE_eol 5
+#define XTTYMODE_swtch 6
+#define XTTYMODE_start 7
+#define XTTYMODE_stop 8
+#define XTTYMODE_brk 9
+#define XTTYMODE_susp 10
+#define XTTYMODE_dsusp 11
+#define XTTYMODE_rprnt 12
+#define XTTYMODE_flush 13
+#define XTTYMODE_weras 14
+#define XTTYMODE_lnext 15
+#define XTTYMODE_status 16
+#define XTTYMODE_erase2 17
+#define XTTYMODE_eol2 18
+#define validTtyChar(data, n) \
+#define TMODE(ind,var) if (ttymodelist[ind].set) var = (cc_t) ttymodelist[ind].value
+#include <X11/Xmu/SysUtil.h> /* XmuGetHostname */
+#define MIT_CONSOLE_LEN 12
+#define MIT_CONSOLE "MIT_CONSOLE_"
+#define SetUtmpHost(dst, screen) \
+{"#", ".iconGeometry",XrmoptionStickyArg, (XPointer) NULL},
+{ "#geom", "icon window geometry" },
+ TRACE(("...decode_keyvalue %#x\n", value));
+#define isOption(string) (Boolean)((string)[0] == '-' || (string)[0] == '+')
+#define DATA(option,kind) { option, NULL, kind, (XtPointer) NULL }
+#undef DATA
+#define ITEM(n) ((Cardinal)(n) < XtNumber(optionDescList) \
+#undef ITEM
+#define disableSetUid() /* nothing */
+#define disableSetGid() /* nothing */
+#define DATA(name) { #name, es##name }
+#undef DATA
+#define USE_OPENPTY 1
+#define NO_FDS {-1, -1}
+#define TRACE_HANDSHAKE(tag, data) /* nothing */
+ TRACE(("set_owner(%s, uid=%d, gid=%d, mode=%#o\n",
+ TRACE(("...stat uid=%d, gid=%d, mode=%#o\n",
+#define close_fd(fd) close(fd), fd = -1
+#define USE_NO_DEV_TTY 1
+ if ((ptr1 = x_strindex(oldtc, "co#")) == NULL) {
+ strcat(oldtc, "co#80:");
+ ptr1 = x_strindex(oldtc, "co#");
+ if ((ptr2 = x_strindex(oldtc, "li#")) == NULL) {
+ strcat(oldtc, "li#24:");
+ ptr2 = x_strindex(oldtc, "li#");
+ TRACE(("...parsed #%d: %s=%#x\n", count, mp->name, c));
diff --git a/tests/xterm.exprc b/tests/xterm.exprc
new file mode 100644
index 000000000000..573541ac9702
--- /dev/null
+++ b/tests/xterm.exprc
@@ -0,0 +1 @@
+0
diff --git a/tests/xterm.sh b/tests/xterm.sh
new file mode 100644
index 000000000000..88c856bceef4
--- /dev/null
+++ b/tests/xterm.sh
@@ -0,0 +1,35 @@
+# hacks so we don't have to distribute huge chunks of XTerm
+
+if [ ! -f xterm-really ]
+then
+ cat xterm.expout
+ cat xterm.experr 1>&2
+ exit $(cat xterm.exprc)
+fi
+if [ -f xterm-clean ]
+then
+ rm xterm.tar.gz xterm-defs.h xterm-main.c
+fi
+
+if [ ! -f xterm.tar.gz ]
+then
+ wget -q http://invisible-island.net/datafiles/release/xterm.tar.gz
+fi
+if [ ! -f xterm-main.c ]
+then
+ tar xf xterm.tar.gz
+ cd xterm-[0-9][0-9][0-9]
+ gcc -I/usr/X11R6/include -I. -E -dM \
+ main.c > ../xterm-defs.h
+ cat main.c > ../xterm-main.c
+ cd ..
+ rm -r xterm-[0-9][0-9][0-9]
+fi
+
+unifdef -s xterm-main.c | sed 's/^/#undef /' >xterm-undefs.h
+echo $? 1>&2
+unifdef -f xterm-undefs.h -f xterm-defs.h xterm-main.c >xterm-out.c
+echo $? 1>&2
+grep '#' xterm-out.c
+echo $? 1>&2
+rm -f xterm-undefs.h xterm-out.c
diff --git a/unifdef.1 b/unifdef.1
new file mode 100644
index 000000000000..646a2b9792d6
--- /dev/null
+++ b/unifdef.1
@@ -0,0 +1,514 @@
+.\" Copyright (c) 1985, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\" Copyright (c) 2002 - 2015 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.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.Dd December 3, 2015
+.Dt UNIFDEF 1 PRM
+.Os " "
+.Sh NAME
+.Nm unifdef , unifdefall
+.Nd remove preprocessor conditionals from code
+.Sh SYNOPSIS
+.Nm
+.Op Fl bBcdehKkmnsStV
+.Op Fl I Ns Ar path
+.Op Fl [i]D Ns Ar sym Ns Op = Ns Ar val
+.Op Fl [i]U Ns Ar sym
+.Ar ...
+.Op Fl f Ar defile
+.Op Fl x Bro Ar 012 Brc
+.Op Fl M Ar backext
+.Op Fl o Ar outfile
+.Op Ar infile ...
+.Nm unifdefall
+.Op Fl I Ns Ar path
+.Ar ...
+.Ar file
+.Sh DESCRIPTION
+The
+.Nm
+utility selectively processes conditional
+.Xr cpp 1
+directives.
+It removes from a file
+both the directives
+and any additional text that they specify should be removed,
+while otherwise leaving the file alone.
+.Pp
+The
+.Nm
+utility acts on
+.Ic #if , #ifdef , #ifndef ,
+.Ic #elif , #else ,
+and
+.Ic #endif
+lines,
+using macros specified in
+.Fl D
+and
+.Fl U
+command line options or in
+.Fl f
+definitions files.
+A directive is processed
+if the macro specifications are sufficient to provide
+a definite value for its control expression.
+If the result is false,
+the directive and the following lines under its control are removed.
+If the result is true,
+only the directive is removed.
+An
+.Ic #ifdef
+or
+.Ic #ifndef
+directive is passed through unchanged
+if its controlling macro is not specified.
+Any
+.Ic #if
+or
+.Ic #elif
+control expression that has an unknown value or that
+.Nm
+cannot parse is passed through unchanged.
+By default,
+.Nm
+ignores
+.Ic #if
+and
+.Ic #elif
+lines with constant expressions;
+it can be told to process them by specifying the
+.Fl k
+flag on the command line.
+.Pp
+It understands a commonly-used subset
+of the expression syntax for
+.Ic #if
+and
+.Ic #elif
+lines:
+integer constants,
+integer values of macros defined on the command line,
+the
+.Fn defined
+operator,
+the operators
+.Ic \&! , ~ , -
+(unary),
+.Ic * , / , % , + , - ,
+.Ic < , <= , > , >= , == , != , & , ^ , \&| ,
+.Ic && , || ,
+and parenthesized expressions.
+Division by zero is treated as an unknown value.
+A kind of
+.Dq "short circuit"
+evaluation is used for the
+.Ic &&
+operator:
+if either operand is definitely false then the result is false,
+even if the value of the other operand is unknown.
+Similarly,
+if either operand of
+.Ic ||
+is definitely true then the result is true.
+.Pp
+When evaluating an expression,
+.Nm
+does not expand macros first.
+The value of a macro must be a simple number,
+not an expression.
+A limited form of indirection is allowed,
+where one macro's value is the name of another.
+.Pp
+In most cases,
+.Nm
+does not distinguish between object-like macros
+(without arguments) and function-like macros (with arguments).
+A function-like macro invocation can appear in
+.Ic #if
+and
+.Ic #elif
+control expressions.
+If the macro is not explicitly defined,
+or is defined with the
+.Fl D
+flag on the command-line,
+or with
+.Ic #define
+in a
+.Fl f
+definitions file,
+its arguments are ignored.
+If a macro is explicitly undefined on the command line with the
+.Fl U
+flag,
+or with
+.Ic #undef
+in a
+.Fl f
+definitions file,
+it may not have any arguments since this leads to a syntax error.
+.Pp
+The
+.Nm
+utility understands just enough about C
+to know when one of the directives is inactive
+because it is inside
+a comment,
+or affected by a backslash-continued line.
+It spots unusually-formatted preprocessor directives
+and knows when the layout is too odd for it to handle.
+.Pp
+A script called
+.Nm unifdefall
+can be used to remove all conditional
+.Xr cpp 1
+directives from a file.
+It uses
+.Nm Fl s
+and
+.Nm cpp Fl dM
+to get lists of all the controlling macros
+and their definitions (or lack thereof),
+then invokes
+.Nm
+with appropriate arguments to process the file.
+.Sh OPTIONS
+.Bl -tag -width indent -compact
+.It Fl D Ns Ar sym Ns = Ns Ar val
+Specify that a macro is defined to a given value.
+.Pp
+.It Fl D Ns Ar sym
+Specify that a macro is defined to the value 1.
+.Pp
+.It Fl U Ns Ar sym
+Specify that a macro is undefined.
+.Pp
+If the same macro appears in more than one argument,
+the last occurrence dominates.
+.Pp
+.It Fl iD Ns Ar sym Ns Op = Ns Ar val
+.It Fl iU Ns Ar sym
+C strings, comments,
+and line continuations
+are ignored within
+.Ic #ifdef
+and
+.Ic #ifndef
+blocks
+controlled by macros
+specified with these options.
+.Pp
+.It Fl f Ar defile
+The file
+.Ar defile
+contains
+.Ic #define
+and
+.Ic #undef
+preprocessor directives,
+which have the same effect as the corresponding
+.Fl D
+and
+.Fl U
+command-line arguments.
+You can have multiple
+.Fl f
+arguments and mix them with
+.Fl D
+and
+.Fl U
+arguments;
+later options override earlier ones.
+.Pp
+Each directive must be on a single line.
+Object-like macro definitions (without arguments)
+are set to the given value.
+Function-like macro definitions (with arguments)
+are treated as if they are set to 1.
+.Pp
+.Em Warning:
+string literals and character constants are not parsed correctly in
+.Fl f
+files.
+.Pp
+.It Fl b
+Replace removed lines with blank lines
+instead of deleting them.
+Mutually exclusive with the
+.Fl B
+option.
+.Pp
+.It Fl B
+Compress blank lines around a deleted section.
+Mutually exclusive with the
+.Fl b
+option.
+.Pp
+.It Fl c
+Complement,
+i.e., lines that would have been removed or blanked
+are retained and vice versa.
+.Pp
+.It Fl d
+Turn on printing of debugging messages.
+.Pp
+.It Fl e
+By default,
+.Nm
+will report an error if it needs to remove
+a preprocessor directive that spans more than one line,
+for example, if it has a multi-line
+comment hanging off its right hand end.
+The
+.Fl e
+flag makes it ignore the line instead.
+.Pp
+.It Fl h
+Print help.
+.Pp
+.It Fl I Ns Ar path
+Specifies to
+.Nm unifdefall
+an additional place to look for
+.Ic #include
+files.
+This option is ignored by
+.Nm
+for compatibility with
+.Xr cpp 1
+and to simplify the implementation of
+.Nm unifdefall .
+.Pp
+.It Fl K
+Always treat the result of
+.Ic &&
+and
+.Ic ||
+operators as unknown if either operand is unknown,
+instead of short-circuiting when unknown operands can't affect the result.
+This option is for compatibility with older versions of
+.Nm .
+.Pp
+.It Fl k
+Process
+.Ic #if
+and
+.Ic #elif
+lines with constant expressions.
+By default, sections controlled by such lines are passed through unchanged
+because they typically start
+.Dq Li "#if 0"
+and are used as a kind of comment to sketch out future or past development.
+It would be rude to strip them out, just as it would be for normal comments.
+.Pp
+.It Fl m
+Modify one or more input files in place.
+If an input file is not modified,
+the original is preserved instead of being overwritten with an identical copy.
+.Pp
+.It Fl M Ar backext
+Modify input files in place, and keep backups of the original files by
+appending the
+.Ar backext
+to the input filenames.
+A zero length
+.Ar backext
+behaves the same as the
+.Fl m
+option.
+.Pp
+.It Fl n
+Add
+.Li #line
+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 when processing a single file.
+.Pp
+.It Fl s
+Instead of processing an input file as usual,
+this option causes
+.Nm
+to produce a list of macros that are used in
+preprocessor directive controlling expressions.
+.Pp
+.It Fl S
+Like the
+.Fl s
+option, but the nesting depth of each macro is also printed.
+This is useful for working out the number of possible combinations
+of interdependent defined/undefined macros.
+.Pp
+.It Fl t
+Disables parsing for C strings, comments,
+and line continuations,
+which is useful
+for plain text.
+This is a blanket version of the
+.Fl iD
+and
+.Fl iU
+flags.
+.Pp
+.It Fl V
+Print version details.
+.Pp
+.It Fl x Bro Ar 012 Brc
+Set exit status mode to zero, one, or two.
+See the
+.Sx EXIT STATUS
+section below for details.
+.El
+.Pp
+The
+.Nm
+utility takes its input from
+.Em stdin
+if there are no
+.Ar file
+arguments.
+You must use the
+.Fl m
+or
+.Fl M
+options if there are multiple input files.
+You can specify inut from stdin or output to stdout with
+.Ql - .
+.Pp
+The
+.Nm
+utility works nicely with the
+.Fl D Ns Ar sym
+option of
+.Xr diff 1 .
+.Sh EXIT STATUS
+In normal usage the
+.Nm
+utility's exit status depends on the mode set using the
+.Fl x
+option.
+.Pp
+If the exit mode is zero (the default) then
+.Nm
+exits with status 0 if the output is an exact copy of the input,
+or with status 1 if the output differs.
+.Pp
+If the exit mode is one,
+.Nm
+exits with status 1 if the output is unmodified
+or 0 if it differs.
+.Pp
+If the exit mode is two,
+.Nm
+exits with status zero in both cases.
+.Pp
+In all exit modes,
+.Nm
+exits with status 2 if there is an error.
+.Pp
+The exit status is 0 if the
+.Fl h
+or
+.Fl V
+command line options are given.
+.Sh DIAGNOSTICS
+.Bl -item
+.It
+.Tn EOF
+in comment
+.It
+Inappropriate
+.Ic #elif ,
+.Ic #else
+or
+.Ic #endif
+.It
+Missing macro name in #define or #undef
+.It
+Obfuscated preprocessor control line
+.It
+Premature
+.Tn EOF
+(with the line number of the most recent unterminated
+.Ic #if )
+.It
+Too many levels of nesting
+.It
+Unrecognized preprocessor directive
+.It
+Unterminated char or string literal
+.El
+.Sh SEE ALSO
+.Xr cpp 1 ,
+.Xr diff 1
+.Pp
+The unifdef home page is
+.Pa http://dotat.at/prog/unifdef
+.Sh HISTORY
+The
+.Nm
+command appeared in
+.Bx 2.9 .
+.Tn ANSI\~C
+support was added in
+.Fx 4.7 .
+.Sh AUTHORS
+The original implementation was written by
+.An Dave Yost Aq Dave@Yost.com .
+.An Tony Finch Aq dot@dotat.at
+rewrote it to support
+.Tn ANSI\~C .
+.Sh BUGS
+Expression evaluation is very limited.
+.Pp
+Character constants are not evaluated.
+String literals and character constants in
+.Fl f
+definition files are ignored rather than parsed as
+part of a macro's replacement tokens.
+.Pp
+Handling one line at a time means
+preprocessor directives split across more than one physical line
+(because of comments or backslash-newline)
+cannot be handled in every situation.
+.Pp
+Trigraphs are not recognized.
+.Pp
+There is no support for macros with different definitions at
+different points in the source file.
+.Pp
+The text-mode and ignore functionality does not correspond to modern
+.Xr cpp 1
+behaviour.
diff --git a/unifdef.c b/unifdef.c
new file mode 100644
index 000000000000..9a16fc941c21
--- /dev/null
+++ b/unifdef.c
@@ -0,0 +1,1661 @@
+/*
+ * Copyright (c) 2002 - 2015 Tony Finch <dot@dotat.at>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * 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.
+ *
+ * Wishlist:
+ * provide an option which will append the name of the
+ * appropriate symbol after #else's and #endif's
+ * provide an option which will check symbols after
+ * #else's and #endif's to see that they match their
+ * corresponding #ifdef or #ifndef
+ *
+ * These require better buffer handling, which would also make
+ * it possible to handle all "dodgy" directives correctly.
+ */
+
+#include "unifdef.h"
+
+static const char copyright[] =
+ #include "version.h"
+ "@(#) $Author: Tony Finch (dot@dotat.at) $\n"
+ "@(#) $URL: http://dotat.at/prog/unifdef $\n"
+;
+
+/* types of input lines: */
+typedef enum {
+ LT_TRUEI, /* a true #if with ignore flag */
+ LT_FALSEI, /* a false #if with ignore flag */
+ LT_IF, /* an unknown #if */
+ LT_TRUE, /* a true #if */
+ LT_FALSE, /* a false #if */
+ LT_ELIF, /* an unknown #elif */
+ LT_ELTRUE, /* a true #elif */
+ LT_ELFALSE, /* a false #elif */
+ LT_ELSE, /* #else */
+ LT_ENDIF, /* #endif */
+ LT_DODGY, /* flag: directive is not on one line */
+ LT_DODGY_LAST = LT_DODGY + LT_ENDIF,
+ LT_PLAIN, /* ordinary line */
+ LT_EOF, /* end of file */
+ LT_ERROR, /* unevaluable #if */
+ LT_COUNT
+} Linetype;
+
+static char const * const linetype_name[] = {
+ "TRUEI", "FALSEI", "IF", "TRUE", "FALSE",
+ "ELIF", "ELTRUE", "ELFALSE", "ELSE", "ENDIF",
+ "DODGY TRUEI", "DODGY FALSEI",
+ "DODGY IF", "DODGY TRUE", "DODGY FALSE",
+ "DODGY ELIF", "DODGY ELTRUE", "DODGY ELFALSE",
+ "DODGY ELSE", "DODGY ENDIF",
+ "PLAIN", "EOF", "ERROR"
+};
+
+#define linetype_if2elif(lt) ((Linetype)(lt - LT_IF + LT_ELIF))
+#define linetype_2dodgy(lt) ((Linetype)(lt + LT_DODGY))
+
+/* state of #if processing */
+typedef enum {
+ IS_OUTSIDE,
+ IS_FALSE_PREFIX, /* false #if followed by false #elifs */
+ IS_TRUE_PREFIX, /* first non-false #(el)if is true */
+ IS_PASS_MIDDLE, /* first non-false #(el)if is unknown */
+ IS_FALSE_MIDDLE, /* a false #elif after a pass state */
+ IS_TRUE_MIDDLE, /* a true #elif after a pass state */
+ IS_PASS_ELSE, /* an else after a pass state */
+ IS_FALSE_ELSE, /* an else after a true state */
+ IS_TRUE_ELSE, /* an else after only false states */
+ IS_FALSE_TRAILER, /* #elifs after a true are false */
+ IS_COUNT
+} Ifstate;
+
+static char const * const ifstate_name[] = {
+ "OUTSIDE", "FALSE_PREFIX", "TRUE_PREFIX",
+ "PASS_MIDDLE", "FALSE_MIDDLE", "TRUE_MIDDLE",
+ "PASS_ELSE", "FALSE_ELSE", "TRUE_ELSE",
+ "FALSE_TRAILER"
+};
+
+/* state of comment parser */
+typedef enum {
+ NO_COMMENT = false, /* outside a comment */
+ C_COMMENT, /* in a comment like this one */
+ CXX_COMMENT, /* between // and end of line */
+ STARTING_COMMENT, /* just after slash-backslash-newline */
+ FINISHING_COMMENT, /* star-backslash-newline in a C comment */
+ CHAR_LITERAL, /* inside '' */
+ STRING_LITERAL /* inside "" */
+} Comment_state;
+
+static char const * const comment_name[] = {
+ "NO", "C", "CXX", "STARTING", "FINISHING", "CHAR", "STRING"
+};
+
+/* state of preprocessor line parser */
+typedef enum {
+ LS_START, /* only space and comments on this line */
+ LS_HASH, /* only space, comments, and a hash */
+ LS_DIRTY /* this line can't be a preprocessor line */
+} Line_state;
+
+static char const * const linestate_name[] = {
+ "START", "HASH", "DIRTY"
+};
+
+/*
+ * Minimum translation limits from ISO/IEC 9899:1999 5.2.4.1
+ */
+#define MAXDEPTH 64 /* maximum #if nesting */
+#define MAXLINE 4096 /* maximum length of line */
+#define MAXSYMS 16384 /* maximum number of symbols */
+
+/*
+ * Sometimes when editing a keyword the replacement text is longer, so
+ * we leave some space at the end of the tline buffer to accommodate this.
+ */
+#define EDITSLOP 10
+
+/*
+ * Globals.
+ */
+
+static bool compblank; /* -B: compress blank lines */
+static bool lnblank; /* -b: blank deleted lines */
+static bool complement; /* -c: do the complement */
+static bool debugging; /* -d: debugging reports */
+static bool inplace; /* -m: modify in place */
+static bool iocccok; /* -e: fewer IOCCC errors */
+static bool strictlogic; /* -K: keep ambiguous #ifs */
+static bool killconsts; /* -k: eval constant #ifs */
+static bool lnnum; /* -n: add #line directives */
+static bool symlist; /* -s: output symbol list */
+static bool symdepth; /* -S: output symbol depth */
+static bool text; /* -t: this is a text file */
+
+static const char *symname[MAXSYMS]; /* symbol name */
+static const char *value[MAXSYMS]; /* -Dsym=value */
+static bool ignore[MAXSYMS]; /* -iDsym or -iUsym */
+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 const char *linefile; /* file name for #line */
+static FILE *output; /* output file pointer */
+static const char *ofilename; /* output file name */
+static const char *backext; /* backup extension */
+static char *tempname; /* avoid splatting input */
+
+static char tline[MAXLINE+EDITSLOP];/* input buffer plus space */
+static char *keyword; /* used for editing #elif's */
+
+/*
+ * When processing a file, the output's newline style will match the
+ * input's, and unifdef correctly handles CRLF or LF endings whatever
+ * the platform's native style. The stdio streams are opened in binary
+ * mode to accommodate platforms whose native newline style is CRLF.
+ * When the output isn't a processed input file (when it is error /
+ * debug / diagnostic messages) then unifdef uses native line endings.
+ */
+
+static const char *newline; /* input file format */
+static const char newline_unix[] = "\n";
+static const char newline_crlf[] = "\r\n";
+
+static Comment_state incomment; /* comment parser state */
+static Line_state linestate; /* #if line parser state */
+static Ifstate ifstate[MAXDEPTH]; /* #if processor state */
+static bool ignoring[MAXDEPTH]; /* ignore comments state */
+static int stifline[MAXDEPTH]; /* start of current #if */
+static int depth; /* current #if nesting */
+static int delcount; /* count of deleted lines */
+static unsigned blankcount; /* count of blank lines */
+static unsigned blankmax; /* maximum recent blankcount */
+static bool constexpr; /* constant #if expression */
+static bool zerosyms; /* to format symdepth output */
+static bool firstsym; /* ditto */
+
+static int exitmode; /* exit status mode */
+static int exitstat; /* program exit status */
+static bool altered; /* was this file modified? */
+
+static void addsym1(bool, bool, char *);
+static void addsym2(bool, const char *, const char *);
+static char *astrcat(const char *, const char *);
+static void cleantemp(void);
+static void closeio(void);
+static void debug(const char *, ...);
+static void debugsym(const char *, int);
+static bool defundef(void);
+static void defundefile(const char *);
+static void done(void);
+static void error(const char *);
+static int findsym(const char **);
+static void flushline(bool);
+static void hashline(void);
+static void help(void);
+static Linetype ifeval(const char **);
+static void ignoreoff(void);
+static void ignoreon(void);
+static void indirectsym(void);
+static void keywordedit(const char *);
+static const char *matchsym(const char *, const char *);
+static void nest(void);
+static Linetype parseline(void);
+static void process(void);
+static void processinout(const char *, const char *);
+static const char *skipargs(const char *);
+static const char *skipcomment(const char *);
+static const char *skiphash(void);
+static const char *skipline(const char *);
+static const char *skipsym(const char *);
+static void state(Ifstate);
+static void unnest(void);
+static void usage(void);
+static void version(void);
+static const char *xstrdup(const char *, const char *);
+
+#define endsym(c) (!isalnum((unsigned char)c) && c != '_')
+
+/*
+ * The main program.
+ */
+int
+main(int argc, char *argv[])
+{
+ int opt;
+
+ while ((opt = getopt(argc, argv, "i:D:U:f:I:M:o:x:bBcdehKklmnsStV")) != -1)
+ switch (opt) {
+ case 'i': /* treat stuff controlled by these symbols as text */
+ /*
+ * For strict backwards-compatibility the U or D
+ * should be immediately after the -i but it doesn't
+ * matter much if we relax that requirement.
+ */
+ opt = *optarg++;
+ if (opt == 'D')
+ addsym1(true, true, optarg);
+ else if (opt == 'U')
+ addsym1(true, false, optarg);
+ else
+ usage();
+ break;
+ case 'D': /* define a symbol */
+ addsym1(false, true, optarg);
+ break;
+ case 'U': /* undef a symbol */
+ addsym1(false, false, optarg);
+ break;
+ case 'I': /* no-op for compatibility with cpp */
+ break;
+ case 'b': /* blank deleted lines instead of omitting them */
+ case 'l': /* backwards compatibility */
+ lnblank = true;
+ break;
+ case 'B': /* compress blank lines around removed section */
+ compblank = true;
+ break;
+ case 'c': /* treat -D as -U and vice versa */
+ complement = true;
+ break;
+ case 'd':
+ debugging = true;
+ break;
+ case 'e': /* fewer errors from dodgy lines */
+ iocccok = true;
+ break;
+ case 'f': /* definitions file */
+ defundefile(optarg);
+ break;
+ case 'h':
+ help();
+ break;
+ case 'K': /* keep ambiguous #ifs */
+ strictlogic = true;
+ break;
+ case 'k': /* process constant #ifs */
+ killconsts = true;
+ break;
+ case 'm': /* modify in place */
+ inplace = true;
+ break;
+ case 'M': /* modify in place and keep backup */
+ inplace = true;
+ if (strlen(optarg) > 0)
+ backext = optarg;
+ break;
+ 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;
+ case 'S': /* list symbols with their nesting depth */
+ symlist = symdepth = true;
+ break;
+ case 't': /* don't parse C comments */
+ text = true;
+ break;
+ case 'V':
+ version();
+ break;
+ case 'x':
+ exitmode = atoi(optarg);
+ if(exitmode < 0 || exitmode > 2)
+ usage();
+ break;
+ default:
+ usage();
+ }
+ argc -= optind;
+ argv += optind;
+ if (compblank && lnblank)
+ errx(2, "-B and -b are mutually exclusive");
+ if (symlist && (ofilename != NULL || inplace || argc > 1))
+ errx(2, "-s only works with one input file");
+ if (argc > 1 && ofilename != NULL)
+ errx(2, "-o cannot be used with multiple input files");
+ if (argc > 1 && !inplace)
+ errx(2, "multiple input files require -m or -M");
+ if (argc == 0 && inplace)
+ errx(2, "-m requires an input file");
+ if (argc == 0)
+ argc = 1;
+ if (argc == 1 && !inplace && ofilename == NULL)
+ ofilename = "-";
+ indirectsym();
+
+ atexit(cleantemp);
+ if (ofilename != NULL)
+ processinout(*argv, ofilename);
+ else while (argc-- > 0) {
+ processinout(*argv, *argv);
+ argv++;
+ }
+ switch(exitmode) {
+ case(0): exit(exitstat);
+ case(1): exit(!exitstat);
+ case(2): exit(0);
+ default: abort(); /* bug */
+ }
+}
+
+/*
+ * File logistics.
+ */
+static void
+processinout(const char *ifn, const char *ofn)
+{
+ struct stat st;
+
+ if (ifn == NULL || strcmp(ifn, "-") == 0) {
+ filename = "[stdin]";
+ linefile = NULL;
+ input = fbinmode(stdin);
+ } else {
+ filename = ifn;
+ linefile = ifn;
+ input = fopen(ifn, "rb");
+ if (input == NULL)
+ err(2, "can't open %s", ifn);
+ }
+ if (strcmp(ofn, "-") == 0) {
+ output = fbinmode(stdout);
+ process();
+ return;
+ }
+ if (stat(ofn, &st) < 0) {
+ output = fopen(ofn, "wb");
+ if (output == NULL)
+ err(2, "can't create %s", ofn);
+ process();
+ return;
+ }
+
+ tempname = astrcat(ofn, ".XXXXXX");
+ output = mktempmode(tempname, st.st_mode);
+ if (output == NULL)
+ err(2, "can't create %s", tempname);
+
+ process();
+
+ if (backext != NULL) {
+ char *backname = astrcat(ofn, backext);
+ if (rename(ofn, backname) < 0)
+ err(2, "can't rename \"%s\" to \"%s\"", ofn, backname);
+ free(backname);
+ }
+ /* leave file unmodified if unifdef made no changes */
+ if (!altered && backext == NULL) {
+ if (remove(tempname) < 0)
+ warn("can't remove \"%s\"", tempname);
+ } else if (replace(tempname, ofn) < 0)
+ err(2, "can't rename \"%s\" to \"%s\"", tempname, ofn);
+ free(tempname);
+ tempname = NULL;
+}
+
+/*
+ * For cleaning up if there is an error.
+ */
+static void
+cleantemp(void)
+{
+ if (tempname != NULL)
+ remove(tempname);
+}
+
+/*
+ * Self-identification functions.
+ */
+
+static void
+version(void)
+{
+ const char *c = copyright;
+ for (;;) {
+ while (*++c != '$')
+ if (*c == '\0')
+ exit(0);
+ while (*++c != '$')
+ putc(*c, stderr);
+ putc('\n', stderr);
+ }
+}
+
+static void
+synopsis(FILE *fp)
+{
+ fprintf(fp,
+ "usage: unifdef [-bBcdehKkmnsStV] [-x{012}] [-Mext] [-opath] \\\n"
+ " [-[i]Dsym[=val]] [-[i]Usym] [-fpath] ... [file] ...\n");
+}
+
+static void
+usage(void)
+{
+ synopsis(stderr);
+ exit(2);
+}
+
+static void
+help(void)
+{
+ synopsis(stdout);
+ printf(
+ " -Dsym=val define preprocessor symbol with given value\n"
+ " -Dsym define preprocessor symbol with value 1\n"
+ " -Usym preprocessor symbol is undefined\n"
+ " -iDsym=val \\ ignore C strings and comments\n"
+ " -iDsym ) in sections controlled by these\n"
+ " -iUsym / preprocessor symbols\n"
+ " -fpath file containing #define and #undef directives\n"
+ " -b blank lines instead of deleting them\n"
+ " -B compress blank lines around deleted section\n"
+ " -c complement (invert) keep vs. delete\n"
+ " -d debugging mode\n"
+ " -e ignore multiline preprocessor directives\n"
+ " -h print help\n"
+ " -Ipath extra include file path (ignored)\n"
+ " -K disable && and || short-circuiting\n"
+ " -k process constant #if expressions\n"
+ " -Mext modify in place and keep backups\n"
+ " -m modify input files in place\n"
+ " -n add #line directives to output\n"
+ " -opath output file name\n"
+ " -S list #if control symbols with nesting\n"
+ " -s list #if control symbols\n"
+ " -t ignore C strings and comments\n"
+ " -V print version\n"
+ " -x{012} exit status mode\n"
+ );
+ exit(0);
+}
+
+/*
+ * A state transition function alters the global #if processing state
+ * in a particular way. The table below is indexed by the current
+ * processing state and the type of the current line.
+ *
+ * Nesting is handled by keeping a stack of states; some transition
+ * functions increase or decrease the depth. They also maintain the
+ * ignore state on a stack. In some complicated cases they have to
+ * alter the preprocessor directive, as follows.
+ *
+ * When we have processed a group that starts off with a known-false
+ * #if/#elif sequence (which has therefore been deleted) followed by a
+ * #elif that we don't understand and therefore must keep, we edit the
+ * latter into a #if to keep the nesting correct. We use memcpy() to
+ * overwrite the 4 byte token "elif" with "if " without a '\0' byte.
+ *
+ * When we find a true #elif in a group, the following block will
+ * always be kept and the rest of the sequence after the next #elif or
+ * #else will be discarded. We edit the #elif into a #else and the
+ * following directive to #endif since this has the desired behaviour.
+ *
+ * "Dodgy" directives are split across multiple lines, the most common
+ * example being a multi-line comment hanging off the right of the
+ * directive. We can handle them correctly only if there is no change
+ * from printing to dropping (or vice versa) caused by that directive.
+ * If the directive is the first of a group we have a choice between
+ * failing with an error, or passing it through unchanged instead of
+ * evaluating it. The latter is not the default to avoid questions from
+ * users about unifdef unexpectedly leaving behind preprocessor directives.
+ */
+typedef void state_fn(void);
+
+/* report an error */
+static void Eelif (void) { error("Inappropriate #elif"); }
+static void Eelse (void) { error("Inappropriate #else"); }
+static void Eendif(void) { error("Inappropriate #endif"); }
+static void Eeof (void) { error("Premature EOF"); }
+static void Eioccc(void) { error("Obfuscated preprocessor control line"); }
+/* plain line handling */
+static void print (void) { flushline(true); }
+static void drop (void) { flushline(false); }
+/* output lacks group's start line */
+static void Strue (void) { drop(); ignoreoff(); state(IS_TRUE_PREFIX); }
+static void Sfalse(void) { drop(); ignoreoff(); state(IS_FALSE_PREFIX); }
+static void Selse (void) { drop(); state(IS_TRUE_ELSE); }
+/* print/pass this block */
+static void Pelif (void) { print(); ignoreoff(); state(IS_PASS_MIDDLE); }
+static void Pelse (void) { print(); state(IS_PASS_ELSE); }
+static void Pendif(void) { print(); unnest(); }
+/* discard this block */
+static void Dfalse(void) { drop(); ignoreoff(); state(IS_FALSE_TRAILER); }
+static void Delif (void) { drop(); ignoreoff(); state(IS_FALSE_MIDDLE); }
+static void Delse (void) { drop(); state(IS_FALSE_ELSE); }
+static void Dendif(void) { drop(); unnest(); }
+/* first line of group */
+static void Fdrop (void) { nest(); Dfalse(); }
+static void Fpass (void) { nest(); Pelif(); }
+static void Ftrue (void) { nest(); Strue(); }
+static void Ffalse(void) { nest(); Sfalse(); }
+/* variable pedantry for obfuscated lines */
+static void Oiffy (void) { if (!iocccok) Eioccc(); Fpass(); ignoreon(); }
+static void Oif (void) { if (!iocccok) Eioccc(); Fpass(); }
+static void Oelif (void) { if (!iocccok) Eioccc(); Pelif(); }
+/* ignore comments in this block */
+static void Idrop (void) { Fdrop(); ignoreon(); }
+static void Itrue (void) { Ftrue(); ignoreon(); }
+static void Ifalse(void) { Ffalse(); ignoreon(); }
+/* modify this line */
+static void Mpass (void) { memcpy(keyword, "if ", 4); Pelif(); }
+static void Mtrue (void) { keywordedit("else"); state(IS_TRUE_MIDDLE); }
+static void Melif (void) { keywordedit("endif"); state(IS_FALSE_TRAILER); }
+static void Melse (void) { keywordedit("endif"); state(IS_FALSE_ELSE); }
+
+static state_fn * const trans_table[IS_COUNT][LT_COUNT] = {
+/* IS_OUTSIDE */
+{ Itrue, Ifalse,Fpass, Ftrue, Ffalse,Eelif, Eelif, Eelif, Eelse, Eendif,
+ Oiffy, Oiffy, Fpass, Oif, Oif, Eelif, Eelif, Eelif, Eelse, Eendif,
+ print, done, abort },
+/* IS_FALSE_PREFIX */
+{ Idrop, Idrop, Fdrop, Fdrop, Fdrop, Mpass, Strue, Sfalse,Selse, Dendif,
+ Idrop, Idrop, Fdrop, Fdrop, Fdrop, Mpass, Eioccc,Eioccc,Eioccc,Eioccc,
+ drop, Eeof, abort },
+/* IS_TRUE_PREFIX */
+{ Itrue, Ifalse,Fpass, Ftrue, Ffalse,Dfalse,Dfalse,Dfalse,Delse, Dendif,
+ Oiffy, Oiffy, Fpass, Oif, Oif, Eioccc,Eioccc,Eioccc,Eioccc,Eioccc,
+ print, Eeof, abort },
+/* IS_PASS_MIDDLE */
+{ Itrue, Ifalse,Fpass, Ftrue, Ffalse,Pelif, Mtrue, Delif, Pelse, Pendif,
+ Oiffy, Oiffy, Fpass, Oif, Oif, Pelif, Oelif, Oelif, Pelse, Pendif,
+ print, Eeof, abort },
+/* IS_FALSE_MIDDLE */
+{ Idrop, Idrop, Fdrop, Fdrop, Fdrop, Pelif, Mtrue, Delif, Pelse, Pendif,
+ Idrop, Idrop, Fdrop, Fdrop, Fdrop, Eioccc,Eioccc,Eioccc,Eioccc,Eioccc,
+ drop, Eeof, abort },
+/* IS_TRUE_MIDDLE */
+{ Itrue, Ifalse,Fpass, Ftrue, Ffalse,Melif, Melif, Melif, Melse, Pendif,
+ Oiffy, Oiffy, Fpass, Oif, Oif, Eioccc,Eioccc,Eioccc,Eioccc,Pendif,
+ print, Eeof, abort },
+/* IS_PASS_ELSE */
+{ Itrue, Ifalse,Fpass, Ftrue, Ffalse,Eelif, Eelif, Eelif, Eelse, Pendif,
+ Oiffy, Oiffy, Fpass, Oif, Oif, Eelif, Eelif, Eelif, Eelse, Pendif,
+ print, Eeof, abort },
+/* IS_FALSE_ELSE */
+{ Idrop, Idrop, Fdrop, Fdrop, Fdrop, Eelif, Eelif, Eelif, Eelse, Dendif,
+ Idrop, Idrop, Fdrop, Fdrop, Fdrop, Eelif, Eelif, Eelif, Eelse, Eioccc,
+ drop, Eeof, abort },
+/* IS_TRUE_ELSE */
+{ Itrue, Ifalse,Fpass, Ftrue, Ffalse,Eelif, Eelif, Eelif, Eelse, Dendif,
+ Oiffy, Oiffy, Fpass, Oif, Oif, Eelif, Eelif, Eelif, Eelse, Eioccc,
+ print, Eeof, abort },
+/* IS_FALSE_TRAILER */
+{ Idrop, Idrop, Fdrop, Fdrop, Fdrop, Dfalse,Dfalse,Dfalse,Delse, Dendif,
+ Idrop, Idrop, Fdrop, Fdrop, Fdrop, Dfalse,Dfalse,Dfalse,Delse, Eioccc,
+ drop, Eeof, abort }
+/*TRUEI FALSEI IF TRUE FALSE ELIF ELTRUE ELFALSE ELSE ENDIF
+ TRUEI FALSEI IF TRUE FALSE ELIF ELTRUE ELFALSE ELSE ENDIF (DODGY)
+ PLAIN EOF ERROR */
+};
+
+/*
+ * State machine utility functions
+ */
+static void
+ignoreoff(void)
+{
+ if (depth == 0)
+ abort(); /* bug */
+ ignoring[depth] = ignoring[depth-1];
+}
+static void
+ignoreon(void)
+{
+ ignoring[depth] = true;
+}
+static void
+keywordedit(const char *replacement)
+{
+ snprintf(keyword, tline + sizeof(tline) - keyword,
+ "%s%s", replacement, newline);
+ altered = true;
+ print();
+}
+static void
+nest(void)
+{
+ if (depth > MAXDEPTH-1)
+ abort(); /* bug */
+ if (depth == MAXDEPTH-1)
+ error("Too many levels of nesting");
+ depth += 1;
+ stifline[depth] = linenum;
+}
+static void
+unnest(void)
+{
+ if (depth == 0)
+ abort(); /* bug */
+ depth -= 1;
+}
+static void
+state(Ifstate is)
+{
+ ifstate[depth] = is;
+}
+
+/*
+ * The last state transition function. When this is called,
+ * lineval == LT_EOF, so the process() loop will terminate.
+ */
+static void
+done(void)
+{
+ if (incomment)
+ error("EOF in comment");
+ closeio();
+}
+
+/*
+ * Write a line to the output or not, according to command line options.
+ * If writing fails, closeio() will print the error and exit.
+ */
+static void
+flushline(bool keep)
+{
+ if (symlist)
+ return;
+ if (keep ^ complement) {
+ bool blankline = tline[strspn(tline, " \t\r\n")] == '\0';
+ if (blankline && compblank && blankcount != blankmax) {
+ delcount += 1;
+ blankcount += 1;
+ } else {
+ if (lnnum && delcount > 0)
+ hashline();
+ if (fputs(tline, output) == EOF)
+ closeio();
+ delcount = 0;
+ blankmax = blankcount = blankline ? blankcount + 1 : 0;
+ }
+ } else {
+ if (lnblank && fputs(newline, output) == EOF)
+ closeio();
+ altered = true;
+ delcount += 1;
+ blankcount = 0;
+ }
+ if (debugging && fflush(output) == EOF)
+ closeio();
+}
+
+/*
+ * Format of #line directives depends on whether we know the input filename.
+ */
+static void
+hashline(void)
+{
+ int e;
+
+ if (linefile == NULL)
+ e = fprintf(output, "#line %d%s", linenum, newline);
+ else
+ e = fprintf(output, "#line %d \"%s\"%s",
+ linenum, linefile, newline);
+ if (e < 0)
+ closeio();
+}
+
+/*
+ * Flush the output and handle errors.
+ */
+static void
+closeio(void)
+{
+ /* Tidy up after findsym(). */
+ if (symdepth && !zerosyms)
+ printf("\n");
+ if (output != NULL && (ferror(output) || fclose(output) == EOF))
+ err(2, "%s: can't write to output", filename);
+ fclose(input);
+}
+
+/*
+ * The driver for the state machine.
+ */
+static void
+process(void)
+{
+ Linetype lineval = LT_PLAIN;
+ /* When compressing blank lines, act as if the file
+ is preceded by a large number of blank lines. */
+ blankmax = blankcount = 1000;
+ zerosyms = true;
+ newline = NULL;
+ linenum = 0;
+ altered = false;
+ while (lineval != LT_EOF) {
+ lineval = parseline();
+ trans_table[ifstate[depth]][lineval]();
+ debug("process line %d %s -> %s depth %d",
+ linenum, linetype_name[lineval],
+ ifstate_name[ifstate[depth]], depth);
+ }
+ exitstat |= altered;
+}
+
+/*
+ * 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().
+ */
+static Linetype
+parseline(void)
+{
+ const char *cp;
+ int cursym;
+ Linetype retval;
+ Comment_state wascomment;
+
+ wascomment = incomment;
+ cp = skiphash();
+ if (cp == NULL)
+ return (LT_EOF);
+ if (newline == NULL) {
+ if (strrchr(tline, '\n') == strrchr(tline, '\r') + 1)
+ newline = newline_crlf;
+ else
+ newline = newline_unix;
+ }
+ if (*cp == '\0') {
+ retval = LT_PLAIN;
+ goto done;
+ }
+ keyword = tline + (cp - tline);
+ if ((cp = matchsym("ifdef", keyword)) != NULL ||
+ (cp = matchsym("ifndef", keyword)) != NULL) {
+ cp = skipcomment(cp);
+ if ((cursym = findsym(&cp)) < 0)
+ retval = LT_IF;
+ else {
+ retval = (keyword[2] == 'n')
+ ? LT_FALSE : LT_TRUE;
+ if (value[cursym] == NULL)
+ retval = (retval == LT_TRUE)
+ ? LT_FALSE : LT_TRUE;
+ if (ignore[cursym])
+ retval = (retval == LT_TRUE)
+ ? LT_TRUEI : LT_FALSEI;
+ }
+ } else if ((cp = matchsym("if", keyword)) != NULL)
+ retval = ifeval(&cp);
+ else if ((cp = matchsym("elif", keyword)) != NULL)
+ retval = linetype_if2elif(ifeval(&cp));
+ else if ((cp = matchsym("else", keyword)) != NULL)
+ retval = LT_ELSE;
+ else if ((cp = matchsym("endif", keyword)) != NULL)
+ retval = LT_ENDIF;
+ else {
+ cp = skipsym(keyword);
+ /* no way can we deal with a continuation inside a keyword */
+ if (strncmp(cp, "\\\r\n", 3) == 0 ||
+ strncmp(cp, "\\\n", 2) == 0)
+ Eioccc();
+ cp = skipline(cp);
+ retval = LT_PLAIN;
+ goto done;
+ }
+ cp = skipcomment(cp);
+ if (*cp != '\0') {
+ cp = skipline(cp);
+ if (retval == LT_TRUE || retval == LT_FALSE ||
+ retval == LT_TRUEI || retval == LT_FALSEI)
+ retval = LT_IF;
+ if (retval == LT_ELTRUE || retval == LT_ELFALSE)
+ retval = LT_ELIF;
+ }
+ /* the following can happen if the last line of the file lacks a
+ newline or if there is too much whitespace in a directive */
+ if (linestate == LS_HASH) {
+ long len = cp - tline;
+ if (fgets(tline + len, MAXLINE - len, input) == NULL) {
+ if (ferror(input))
+ err(2, "can't read %s", filename);
+ /* append the missing newline at eof */
+ strcpy(tline + len, newline);
+ cp += strlen(newline);
+ linestate = LS_START;
+ } else {
+ linestate = LS_DIRTY;
+ }
+ }
+ if (retval != LT_PLAIN && (wascomment || linestate != LS_START)) {
+ retval = linetype_2dodgy(retval);
+ linestate = LS_DIRTY;
+ }
+done:
+ debug("parser line %d state %s comment %s line", linenum,
+ comment_name[incomment], linestate_name[linestate]);
+ return (retval);
+}
+
+/*
+ * These are the binary operators that are supported by the expression
+ * evaluator.
+ */
+static Linetype op_strict(long *p, long v, Linetype at, Linetype bt) {
+ if(at == LT_IF || bt == LT_IF) return (LT_IF);
+ return (*p = v, v ? LT_TRUE : LT_FALSE);
+}
+static Linetype op_lt(long *p, Linetype at, long a, Linetype bt, long b) {
+ return op_strict(p, a < b, at, bt);
+}
+static Linetype op_gt(long *p, Linetype at, long a, Linetype bt, long b) {
+ return op_strict(p, a > b, at, bt);
+}
+static Linetype op_le(long *p, Linetype at, long a, Linetype bt, long b) {
+ return op_strict(p, a <= b, at, bt);
+}
+static Linetype op_ge(long *p, Linetype at, long a, Linetype bt, long b) {
+ return op_strict(p, a >= b, at, bt);
+}
+static Linetype op_eq(long *p, Linetype at, long a, Linetype bt, long b) {
+ return op_strict(p, a == b, at, bt);
+}
+static Linetype op_ne(long *p, Linetype at, long a, Linetype bt, long b) {
+ return op_strict(p, a != b, at, bt);
+}
+static Linetype op_or(long *p, Linetype at, long a, Linetype bt, long b) {
+ if (!strictlogic && (at == LT_TRUE || bt == LT_TRUE))
+ return (*p = 1, LT_TRUE);
+ return op_strict(p, a || b, at, bt);
+}
+static Linetype op_and(long *p, Linetype at, long a, Linetype bt, long b) {
+ if (!strictlogic && (at == LT_FALSE || bt == LT_FALSE))
+ return (*p = 0, LT_FALSE);
+ return op_strict(p, a && b, at, bt);
+}
+static Linetype op_blsh(long *p, Linetype at, long a, Linetype bt, long b) {
+ return op_strict(p, a << b, at, bt);
+}
+static Linetype op_brsh(long *p, Linetype at, long a, Linetype bt, long b) {
+ return op_strict(p, a >> b, at, bt);
+}
+static Linetype op_add(long *p, Linetype at, long a, Linetype bt, long b) {
+ return op_strict(p, a + b, at, bt);
+}
+static Linetype op_sub(long *p, Linetype at, long a, Linetype bt, long b) {
+ return op_strict(p, a - b, at, bt);
+}
+static Linetype op_mul(long *p, Linetype at, long a, Linetype bt, long b) {
+ return op_strict(p, a * b, at, bt);
+}
+static Linetype op_div(long *p, Linetype at, long a, Linetype bt, long b) {
+ if (bt != LT_TRUE) {
+ debug("eval division by zero");
+ return (LT_ERROR);
+ }
+ return op_strict(p, a / b, at, bt);
+}
+static Linetype op_mod(long *p, Linetype at, long a, Linetype bt, long b) {
+ return op_strict(p, a % b, at, bt);
+}
+static Linetype op_bor(long *p, Linetype at, long a, Linetype bt, long b) {
+ return op_strict(p, a | b, at, bt);
+}
+static Linetype op_bxor(long *p, Linetype at, long a, Linetype bt, long b) {
+ return op_strict(p, a ^ b, at, bt);
+}
+static Linetype op_band(long *p, Linetype at, long a, Linetype bt, long b) {
+ return op_strict(p, a & b, at, bt);
+}
+
+/*
+ * An evaluation function takes three arguments, as follows: (1) a pointer to
+ * an element of the precedence table which lists the operators at the current
+ * level of precedence; (2) a pointer to an integer which will receive the
+ * value of the expression; and (3) a pointer to a char* that points to the
+ * expression to be evaluated and that is updated to the end of the expression
+ * when evaluation is complete. The function returns LT_FALSE if the value of
+ * the expression is zero, LT_TRUE if it is non-zero, LT_IF if the expression
+ * depends on an unknown symbol, or LT_ERROR if there is a parse failure.
+ */
+struct ops;
+
+typedef Linetype eval_fn(const struct ops *, long *, const char **);
+
+static eval_fn eval_table, eval_unary;
+
+/*
+ * The precedence table. Expressions involving binary operators are evaluated
+ * in a table-driven way by eval_table. When it evaluates a subexpression it
+ * calls the inner function with its first argument pointing to the next
+ * element of the table. Innermost expressions have special non-table-driven
+ * handling.
+ *
+ * The stop characters help with lexical analysis: an operator is not
+ * recognized if it is followed by one of the stop characters because
+ * that would make it a different operator.
+ */
+struct op {
+ const char *str;
+ Linetype (*fn)(long *, Linetype, long, Linetype, long);
+ const char *stop;
+};
+struct ops {
+ eval_fn *inner;
+ struct op op[5];
+};
+static const struct ops eval_ops[] = {
+ { eval_table, { { "||", op_or } } },
+ { eval_table, { { "&&", op_and } } },
+ { eval_table, { { "|", op_bor, "|" } } },
+ { eval_table, { { "^", op_bxor } } },
+ { eval_table, { { "&", op_band, "&" } } },
+ { eval_table, { { "==", op_eq },
+ { "!=", op_ne } } },
+ { eval_table, { { "<=", op_le },
+ { ">=", op_ge },
+ { "<", op_lt, "<=" },
+ { ">", op_gt, ">=" } } },
+ { eval_table, { { "<<", op_blsh },
+ { ">>", op_brsh } } },
+ { eval_table, { { "+", op_add },
+ { "-", op_sub } } },
+ { eval_unary, { { "*", op_mul },
+ { "/", op_div },
+ { "%", op_mod } } },
+};
+
+/* Current operator precedence level */
+static long prec(const struct ops *ops)
+{
+ return (ops - eval_ops);
+}
+
+/*
+ * Function for evaluating the innermost parts of expressions,
+ * viz. !expr (expr) number defined(symbol) symbol
+ * We reset the constexpr flag in the last two cases.
+ */
+static Linetype
+eval_unary(const struct ops *ops, long *valp, const char **cpp)
+{
+ const char *cp;
+ char *ep;
+ int sym;
+ bool defparen;
+ Linetype lt;
+
+ cp = skipcomment(*cpp);
+ if (*cp == '!') {
+ debug("eval%d !", prec(ops));
+ cp++;
+ lt = eval_unary(ops, valp, &cp);
+ if (lt == LT_ERROR)
+ return (LT_ERROR);
+ if (lt != LT_IF) {
+ *valp = !*valp;
+ lt = *valp ? LT_TRUE : LT_FALSE;
+ }
+ } else if (*cp == '~') {
+ debug("eval%d ~", prec(ops));
+ cp++;
+ lt = eval_unary(ops, valp, &cp);
+ if (lt == LT_ERROR)
+ return (LT_ERROR);
+ if (lt != LT_IF) {
+ *valp = ~(*valp);
+ lt = *valp ? LT_TRUE : LT_FALSE;
+ }
+ } else if (*cp == '-') {
+ debug("eval%d -", prec(ops));
+ cp++;
+ lt = eval_unary(ops, valp, &cp);
+ if (lt == LT_ERROR)
+ return (LT_ERROR);
+ if (lt != LT_IF) {
+ *valp = -(*valp);
+ lt = *valp ? LT_TRUE : LT_FALSE;
+ }
+ } else if (*cp == '(') {
+ cp++;
+ debug("eval%d (", prec(ops));
+ lt = eval_table(eval_ops, valp, &cp);
+ if (lt == LT_ERROR)
+ return (LT_ERROR);
+ cp = skipcomment(cp);
+ if (*cp++ != ')')
+ return (LT_ERROR);
+ } else if (isdigit((unsigned char)*cp)) {
+ debug("eval%d number", prec(ops));
+ *valp = strtol(cp, &ep, 0);
+ if (ep == cp)
+ return (LT_ERROR);
+ lt = *valp ? LT_TRUE : LT_FALSE;
+ cp = ep;
+ } else if (matchsym("defined", cp) != NULL) {
+ cp = skipcomment(cp+7);
+ if (*cp == '(') {
+ cp = skipcomment(cp+1);
+ defparen = true;
+ } else {
+ defparen = false;
+ }
+ sym = findsym(&cp);
+ cp = skipcomment(cp);
+ if (defparen && *cp++ != ')') {
+ debug("eval%d defined missing ')'", prec(ops));
+ return (LT_ERROR);
+ }
+ if (sym < 0) {
+ debug("eval%d defined unknown", prec(ops));
+ lt = LT_IF;
+ } else {
+ debug("eval%d defined %s", prec(ops), symname[sym]);
+ *valp = (value[sym] != NULL);
+ lt = *valp ? LT_TRUE : LT_FALSE;
+ }
+ constexpr = false;
+ } else if (!endsym(*cp)) {
+ debug("eval%d symbol", prec(ops));
+ sym = findsym(&cp);
+ if (sym < 0) {
+ lt = LT_IF;
+ cp = skipargs(cp);
+ } else if (value[sym] == NULL) {
+ *valp = 0;
+ lt = LT_FALSE;
+ } else {
+ *valp = strtol(value[sym], &ep, 0);
+ if (*ep != '\0' || ep == value[sym])
+ return (LT_ERROR);
+ lt = *valp ? LT_TRUE : LT_FALSE;
+ cp = skipargs(cp);
+ }
+ constexpr = false;
+ } else {
+ debug("eval%d bad expr", prec(ops));
+ return (LT_ERROR);
+ }
+
+ *cpp = cp;
+ debug("eval%d = %d", prec(ops), *valp);
+ return (lt);
+}
+
+/*
+ * Table-driven evaluation of binary operators.
+ */
+static Linetype
+eval_table(const struct ops *ops, long *valp, const char **cpp)
+{
+ const struct op *op;
+ const char *cp;
+ long val = 0;
+ Linetype lt, rt;
+
+ debug("eval%d", prec(ops));
+ cp = *cpp;
+ lt = ops->inner(ops+1, valp, &cp);
+ if (lt == LT_ERROR)
+ return (LT_ERROR);
+ for (;;) {
+ cp = skipcomment(cp);
+ for (op = ops->op; op->str != NULL; op++) {
+ if (strncmp(cp, op->str, strlen(op->str)) == 0) {
+ /* assume only one-char operators have stop chars */
+ if (op->stop != NULL && cp[1] != '\0' &&
+ strchr(op->stop, cp[1]) != NULL)
+ continue;
+ else
+ break;
+ }
+ }
+ if (op->str == NULL)
+ break;
+ cp += strlen(op->str);
+ debug("eval%d %s", prec(ops), op->str);
+ rt = ops->inner(ops+1, &val, &cp);
+ if (rt == LT_ERROR)
+ return (LT_ERROR);
+ lt = op->fn(valp, lt, *valp, rt, val);
+ }
+
+ *cpp = cp;
+ debug("eval%d = %d", prec(ops), *valp);
+ debug("eval%d lt = %s", prec(ops), linetype_name[lt]);
+ return (lt);
+}
+
+/*
+ * Evaluate the expression on a #if or #elif line. If we can work out
+ * the result we return LT_TRUE or LT_FALSE accordingly, otherwise we
+ * return just a generic LT_IF.
+ */
+static Linetype
+ifeval(const char **cpp)
+{
+ Linetype ret;
+ long val = 0;
+
+ debug("eval %s", *cpp);
+ constexpr = killconsts ? false : true;
+ ret = eval_table(eval_ops, &val, cpp);
+ debug("eval = %d", val);
+ return (constexpr ? LT_IF : ret == LT_ERROR ? LT_IF : ret);
+}
+
+/*
+ * Read a line and examine its initial part to determine if it is a
+ * preprocessor directive. Returns NULL on EOF, or a pointer to a
+ * preprocessor directive name, or a pointer to the zero byte at the
+ * end of the line.
+ */
+static const char *
+skiphash(void)
+{
+ const char *cp;
+
+ linenum++;
+ if (fgets(tline, MAXLINE, input) == NULL) {
+ if (ferror(input))
+ err(2, "can't read %s", filename);
+ else
+ return (NULL);
+ }
+ cp = skipcomment(tline);
+ if (linestate == LS_START && *cp == '#') {
+ linestate = LS_HASH;
+ return (skipcomment(cp + 1));
+ } else if (*cp == '\0') {
+ return (cp);
+ } else {
+ return (skipline(cp));
+ }
+}
+
+/*
+ * Mark a line dirty and consume the rest of it, keeping track of the
+ * lexical state.
+ */
+static const char *
+skipline(const char *cp)
+{
+ const char *pcp;
+ if (*cp != '\0')
+ linestate = LS_DIRTY;
+ while (*cp != '\0') {
+ cp = skipcomment(pcp = cp);
+ if (pcp == cp)
+ cp++;
+ }
+ return (cp);
+}
+
+/*
+ * Skip over comments, strings, and character literals and stop at the
+ * next character position that is not whitespace. Between calls we keep
+ * the comment state in the global variable incomment, and we also adjust
+ * the global variable linestate when we see a newline.
+ * XXX: doesn't cope with the buffer splitting inside a state transition.
+ */
+static const char *
+skipcomment(const char *cp)
+{
+ if (text || ignoring[depth]) {
+ for (; isspace((unsigned char)*cp); cp++)
+ if (*cp == '\n')
+ linestate = LS_START;
+ return (cp);
+ }
+ while (*cp != '\0')
+ /* don't reset to LS_START after a line continuation */
+ if (strncmp(cp, "\\\r\n", 3) == 0)
+ cp += 3;
+ else if (strncmp(cp, "\\\n", 2) == 0)
+ cp += 2;
+ else switch (incomment) {
+ case NO_COMMENT:
+ if (strncmp(cp, "/\\\r\n", 4) == 0) {
+ incomment = STARTING_COMMENT;
+ cp += 4;
+ } else if (strncmp(cp, "/\\\n", 3) == 0) {
+ incomment = STARTING_COMMENT;
+ cp += 3;
+ } else if (strncmp(cp, "/*", 2) == 0) {
+ incomment = C_COMMENT;
+ cp += 2;
+ } else if (strncmp(cp, "//", 2) == 0) {
+ incomment = CXX_COMMENT;
+ cp += 2;
+ } else if (strncmp(cp, "\'", 1) == 0) {
+ incomment = CHAR_LITERAL;
+ linestate = LS_DIRTY;
+ cp += 1;
+ } else if (strncmp(cp, "\"", 1) == 0) {
+ incomment = STRING_LITERAL;
+ linestate = LS_DIRTY;
+ cp += 1;
+ } else if (strncmp(cp, "\n", 1) == 0) {
+ linestate = LS_START;
+ cp += 1;
+ } else if (strchr(" \r\t", *cp) != NULL) {
+ cp += 1;
+ } else
+ return (cp);
+ continue;
+ case CXX_COMMENT:
+ if (strncmp(cp, "\n", 1) == 0) {
+ incomment = NO_COMMENT;
+ linestate = LS_START;
+ }
+ cp += 1;
+ continue;
+ case CHAR_LITERAL:
+ case STRING_LITERAL:
+ if ((incomment == CHAR_LITERAL && cp[0] == '\'') ||
+ (incomment == STRING_LITERAL && cp[0] == '\"')) {
+ incomment = NO_COMMENT;
+ cp += 1;
+ } else if (cp[0] == '\\') {
+ if (cp[1] == '\0')
+ cp += 1;
+ else
+ cp += 2;
+ } else if (strncmp(cp, "\n", 1) == 0) {
+ if (incomment == CHAR_LITERAL)
+ error("Unterminated char literal");
+ else
+ error("Unterminated string literal");
+ } else
+ cp += 1;
+ continue;
+ case C_COMMENT:
+ if (strncmp(cp, "*\\\r\n", 4) == 0) {
+ incomment = FINISHING_COMMENT;
+ cp += 4;
+ } else if (strncmp(cp, "*\\\n", 3) == 0) {
+ incomment = FINISHING_COMMENT;
+ cp += 3;
+ } else if (strncmp(cp, "*/", 2) == 0) {
+ incomment = NO_COMMENT;
+ cp += 2;
+ } else
+ cp += 1;
+ continue;
+ case STARTING_COMMENT:
+ if (*cp == '*') {
+ incomment = C_COMMENT;
+ cp += 1;
+ } else if (*cp == '/') {
+ incomment = CXX_COMMENT;
+ cp += 1;
+ } else {
+ incomment = NO_COMMENT;
+ linestate = LS_DIRTY;
+ }
+ continue;
+ case FINISHING_COMMENT:
+ if (*cp == '/') {
+ incomment = NO_COMMENT;
+ cp += 1;
+ } else
+ incomment = C_COMMENT;
+ continue;
+ default:
+ abort(); /* bug */
+ }
+ return (cp);
+}
+
+/*
+ * Skip macro arguments.
+ */
+static const char *
+skipargs(const char *cp)
+{
+ const char *ocp = cp;
+ int level = 0;
+ cp = skipcomment(cp);
+ if (*cp != '(')
+ return (cp);
+ do {
+ if (*cp == '(')
+ level++;
+ if (*cp == ')')
+ level--;
+ cp = skipcomment(cp+1);
+ } while (level != 0 && *cp != '\0');
+ if (level == 0)
+ return (cp);
+ else
+ /* Rewind and re-detect the syntax error later. */
+ return (ocp);
+}
+
+/*
+ * Skip over an identifier.
+ */
+static const char *
+skipsym(const char *cp)
+{
+ while (!endsym(*cp))
+ ++cp;
+ return (cp);
+}
+
+/*
+ * Skip whitespace and take a copy of any following identifier.
+ */
+static const char *
+getsym(const char **cpp)
+{
+ const char *cp = *cpp, *sym;
+
+ cp = skipcomment(cp);
+ cp = skipsym(sym = cp);
+ if (cp == sym)
+ return NULL;
+ *cpp = cp;
+ return (xstrdup(sym, cp));
+}
+
+/*
+ * Check that s (a symbol) matches the start of t, and that the
+ * following character in t is not a symbol character. Returns a
+ * pointer to the following character in t if there is a match,
+ * otherwise NULL.
+ */
+static const char *
+matchsym(const char *s, const char *t)
+{
+ while (*s != '\0' && *t != '\0')
+ if (*s != *t)
+ return (NULL);
+ else
+ ++s, ++t;
+ if (*s == '\0' && endsym(*t))
+ return(t);
+ else
+ return(NULL);
+}
+
+/*
+ * Look for the symbol in the symbol table. If it is found, we return
+ * the symbol table index, else we return -1.
+ */
+static int
+findsym(const char **strp)
+{
+ const char *str;
+ int symind;
+
+ str = *strp;
+ *strp = skipsym(str);
+ if (symlist) {
+ if (*strp == str)
+ return (-1);
+ if (symdepth && firstsym)
+ printf("%s%3d", zerosyms ? "" : "\n", depth);
+ firstsym = zerosyms = false;
+ printf("%s%.*s%s",
+ symdepth ? " " : "",
+ (int)(*strp-str), str,
+ symdepth ? "" : "\n");
+ /* we don't care about the value of the symbol */
+ return (0);
+ }
+ for (symind = 0; symind < nsyms; ++symind) {
+ if (matchsym(symname[symind], str) != NULL) {
+ debugsym("findsym", symind);
+ return (symind);
+ }
+ }
+ return (-1);
+}
+
+/*
+ * Resolve indirect symbol values to their final definitions.
+ */
+static void
+indirectsym(void)
+{
+ const char *cp;
+ int changed, sym, ind;
+
+ do {
+ changed = 0;
+ for (sym = 0; sym < nsyms; ++sym) {
+ if (value[sym] == NULL)
+ continue;
+ cp = value[sym];
+ ind = findsym(&cp);
+ if (ind == -1 || ind == sym ||
+ *cp != '\0' ||
+ value[ind] == NULL ||
+ value[ind] == value[sym])
+ continue;
+ debugsym("indir...", sym);
+ value[sym] = value[ind];
+ debugsym("...ectsym", sym);
+ changed++;
+ }
+ } while (changed);
+}
+
+/*
+ * Add a symbol to the symbol table, specified with the format sym=val
+ */
+static void
+addsym1(bool ignorethis, bool definethis, char *symval)
+{
+ const char *sym, *val;
+
+ sym = symval;
+ val = skipsym(sym);
+ if (definethis && *val == '=') {
+ symval[val - sym] = '\0';
+ val = val + 1;
+ } else if (*val == '\0') {
+ val = definethis ? "1" : NULL;
+ } else {
+ usage();
+ }
+ addsym2(ignorethis, sym, val);
+}
+
+/*
+ * Add a symbol to the symbol table.
+ */
+static void
+addsym2(bool ignorethis, const char *sym, const char *val)
+{
+ const char *cp = sym;
+ int symind;
+
+ symind = findsym(&cp);
+ if (symind < 0) {
+ if (nsyms >= MAXSYMS)
+ errx(2, "too many symbols");
+ symind = nsyms++;
+ }
+ ignore[symind] = ignorethis;
+ symname[symind] = sym;
+ value[symind] = val;
+ debugsym("addsym", symind);
+}
+
+static void
+debugsym(const char *why, int symind)
+{
+ debug("%s %s%c%s", why, symname[symind],
+ value[symind] ? '=' : ' ',
+ value[symind] ? value[symind] : "undef");
+}
+
+/*
+ * Add symbols to the symbol table from a file containing
+ * #define and #undef preprocessor directives.
+ */
+static void
+defundefile(const char *fn)
+{
+ filename = fn;
+ input = fopen(fn, "rb");
+ if (input == NULL)
+ err(2, "can't open %s", fn);
+ linenum = 0;
+ while (defundef())
+ ;
+ if (ferror(input))
+ err(2, "can't read %s", filename);
+ else
+ fclose(input);
+ if (incomment)
+ error("EOF in comment");
+}
+
+/*
+ * Read and process one #define or #undef directive
+ */
+static bool
+defundef(void)
+{
+ const char *cp, *kw, *sym, *val, *end;
+
+ cp = skiphash();
+ if (cp == NULL)
+ return (false);
+ if (*cp == '\0')
+ goto done;
+ /* strip trailing whitespace, and do a fairly rough check to
+ avoid unsupported multi-line preprocessor directives */
+ end = cp + strlen(cp);
+ while (end > tline && strchr(" \t\n\r", end[-1]) != NULL)
+ --end;
+ if (end > tline && end[-1] == '\\')
+ Eioccc();
+
+ kw = cp;
+ if ((cp = matchsym("define", kw)) != NULL) {
+ sym = getsym(&cp);
+ if (sym == NULL)
+ error("Missing macro name in #define");
+ if (*cp == '(') {
+ val = "1";
+ } else {
+ cp = skipcomment(cp);
+ val = (cp < end) ? xstrdup(cp, end) : "";
+ }
+ debug("#define");
+ addsym2(false, sym, val);
+ } else if ((cp = matchsym("undef", kw)) != NULL) {
+ sym = getsym(&cp);
+ if (sym == NULL)
+ error("Missing macro name in #undef");
+ cp = skipcomment(cp);
+ debug("#undef");
+ addsym2(false, sym, NULL);
+ } else {
+ error("Unrecognized preprocessor directive");
+ }
+ skipline(cp);
+done:
+ debug("parser line %d state %s comment %s line", linenum,
+ comment_name[incomment], linestate_name[linestate]);
+ return (true);
+}
+
+/*
+ * Concatenate two strings into new memory, checking for failure.
+ */
+static char *
+astrcat(const char *s1, const char *s2)
+{
+ char *s;
+ int len;
+ size_t size;
+
+ len = snprintf(NULL, 0, "%s%s", s1, s2);
+ if (len < 0)
+ err(2, "snprintf");
+ size = (size_t)len + 1;
+ s = (char *)malloc(size);
+ if (s == NULL)
+ err(2, "malloc");
+ snprintf(s, size, "%s%s", s1, s2);
+ return (s);
+}
+
+/*
+ * Duplicate a segment of a string, checking for failure.
+ */
+static const char *
+xstrdup(const char *start, const char *end)
+{
+ size_t n;
+ char *s;
+
+ if (end < start) abort(); /* bug */
+ n = (size_t)(end - start) + 1;
+ s = malloc(n);
+ if (s == NULL)
+ err(2, "malloc");
+ snprintf(s, n, "%s", start);
+ return (s);
+}
+
+/*
+ * Diagnostics.
+ */
+static void
+debug(const char *msg, ...)
+{
+ va_list ap;
+
+ if (debugging) {
+ va_start(ap, msg);
+ vwarnx(msg, ap);
+ va_end(ap);
+ }
+}
+
+static void
+error(const char *msg)
+{
+ if (depth == 0)
+ warnx("%s: %d: %s", filename, linenum, msg);
+ else
+ warnx("%s: %d: %s (#if line %d depth %d)",
+ filename, linenum, msg, stifline[depth], depth);
+ closeio();
+ errx(2, "Output may be truncated");
+}
diff --git a/unifdef.h b/unifdef.h
new file mode 100644
index 000000000000..2cd706d986ab
--- /dev/null
+++ b/unifdef.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2012 - 2013 Tony Finch <dot@dotat.at>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/stat.h>
+
+#include <ctype.h>
+#include <err.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+/* portability stubs */
+
+#define fbinmode(fp) (fp)
+
+#define replace(old,new) rename(old,new)
+
+static FILE *
+mktempmode(char *tmp, int mode)
+{
+ int fd = mkstemp(tmp);
+ if (fd < 0) return (NULL);
+ fchmod(fd, mode & (S_IRWXU|S_IRWXG|S_IRWXO));
+ return (fdopen(fd, "wb"));
+}
diff --git a/unifdefall.sh b/unifdefall.sh
new file mode 100755
index 000000000000..0755d9fb719f
--- /dev/null
+++ b/unifdefall.sh
@@ -0,0 +1,58 @@
+#!/bin/sh
+#
+# unifdefall: remove all the #if's from a source file
+#
+# Copyright (c) 2002 - 2013 Tony Finch <dot@dotat.at>
+# Copyright (c) 2009 - 2010 Jonathan Nieder <jrnieder@gmail.com>
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
+
+set -e
+
+unifdef="$(dirname "$0")/unifdef"
+if [ ! -e "$unifdef" ]
+then
+ unifdef=unifdef
+fi
+
+case "$@" in
+"-d "*) echo DEBUGGING 1>&2
+ debug=-d
+ shift
+esac
+
+tmp=$(mktemp -d "${TMPDIR:-/tmp}/${0##*/}.XXXXXXXXXX") || exit 2
+trap 'rm -r "$tmp" || exit 2' EXIT
+
+export LC_ALL=C
+
+# list of all controlling macros; assume these are undefined
+"$unifdef" $debug -s "$@" | sort -u | sed 's/^/#undef /' >"$tmp/undefs"
+# list of all macro definitions
+cc -E -dM "$@" | sort >"$tmp/defs"
+
+case $debug in
+-d) cat "$tmp/undefs" "$tmp/defs" 1>&2
+esac
+
+# order of -f arguments means definitions override undefs
+"$unifdef" $debug -k -f "$tmp/undefs" -f "$tmp/defs" "$@"
diff --git a/win32/Makefile.mingw b/win32/Makefile.mingw
new file mode 100644
index 000000000000..63e0411d737d
--- /dev/null
+++ b/win32/Makefile.mingw
@@ -0,0 +1,14 @@
+# To build, run:
+# mingw32-make -f win32/Makefile.mingw
+
+all: unifdef.exe
+
+unifdef.exe: unifdef.c win32/win32.c FreeBSD/getopt.c FreeBSD/err.c
+ cd win32 && \
+ cp ../unifdef.c ../version.h . && \
+ $(CC) $(CFLAGS) $(LDFLAGS) -I. -o ../unifdef.exe unifdef.c \
+ win32.c ../FreeBSD/getopt.c ../FreeBSD/err.c && \
+ rm -f unifdef.c version.h
+
+test: unifdef.exe
+ scripts/runtests.sh tests
diff --git a/win32/unifdef.h b/win32/unifdef.h
new file mode 100644
index 000000000000..bebf7381e832
--- /dev/null
+++ b/win32/unifdef.h
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2012 - 2015 Tony Finch <dot@dotat.at>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/* Stop being stupid about POSIX functions */
+#define _CRT_SECURE_NO_WARNINGS
+#define _SCL_SECURE_NO_WARNINGS
+#define _CRT_NONSTDC_NO_WARNINGS
+
+#include <ctype.h>
+#include <errno.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+
+/* Windows POSIX-flavoured headers */
+
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <io.h>
+
+#define stat _stat
+
+/* fake stdbool.h */
+#define true 1
+#define false 0
+#define bool int
+
+/* used by err.c and getopt.c */
+#define _getprogname() "unifdef"
+
+/* win32.c */
+int replace(const char *old, const char *new);
+FILE *mktempmode(char *tmp, int mode);
+FILE *fbinmode(FILE *fp);
+int snprintf(char *buf, size_t buflen, const char *format, ...);
+
+/* err.c */
+void err(int, const char *, ...);
+void verr(int, const char *, va_list);
+void errc(int, int, const char *, ...);
+void verrc(int, int, const char *, va_list);
+void errx(int, const char *, ...);
+void verrx(int, const char *, va_list);
+void warn(const char *, ...);
+void vwarn(const char *, va_list);
+void warnc(int, const char *, ...);
+void vwarnc(int, const char *, va_list);
+void warnx(const char *, ...);
+void vwarnx(const char *, va_list);
+
+/* getopt.c */
+int getopt(int nargc, char *nargv[], const char *ostr);
+extern int opterr, optind, optopt, optreset;
+extern char *optarg;
diff --git a/win32/unifdef.sln b/win32/unifdef.sln
new file mode 100644
index 000000000000..ae2053f00387
--- /dev/null
+++ b/win32/unifdef.sln
@@ -0,0 +1,20 @@
+
+Microsoft Visual Studio Solution File, Format Version 11.00
+# Visual Studio 2010
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "unifdef", "unifdef.vcxproj", "{52450E07-855E-4522-BD4C-7B1E84D8D592}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Win32 = Debug|Win32
+ Release|Win32 = Release|Win32
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {52450E07-855E-4522-BD4C-7B1E84D8D592}.Debug|Win32.ActiveCfg = Debug|Win32
+ {52450E07-855E-4522-BD4C-7B1E84D8D592}.Debug|Win32.Build.0 = Debug|Win32
+ {52450E07-855E-4522-BD4C-7B1E84D8D592}.Release|Win32.ActiveCfg = Release|Win32
+ {52450E07-855E-4522-BD4C-7B1E84D8D592}.Release|Win32.Build.0 = Release|Win32
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+EndGlobal
diff --git a/win32/unifdef.vcxproj b/win32/unifdef.vcxproj
new file mode 100644
index 000000000000..7f79e4dd7a1d
--- /dev/null
+++ b/win32/unifdef.vcxproj
@@ -0,0 +1,96 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup Label="ProjectConfigurations">
+ <ProjectConfiguration Include="Debug|Win32">
+ <Configuration>Debug</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|Win32">
+ <Configuration>Release</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ </ItemGroup>
+ <PropertyGroup Label="Globals">
+ <ProjectGuid>{52450E07-855E-4522-BD4C-7B1E84D8D592}</ProjectGuid>
+ <Keyword>Win32Proj</Keyword>
+ <RootNamespace>unifdef</RootNamespace>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
+ <ConfigurationType>Application</ConfigurationType>
+ <UseDebugLibraries>true</UseDebugLibraries>
+ <CharacterSet>MultiByte</CharacterSet>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
+ <ConfigurationType>Application</ConfigurationType>
+ <UseDebugLibraries>false</UseDebugLibraries>
+ <WholeProgramOptimization>true</WholeProgramOptimization>
+ <CharacterSet>MultiByte</CharacterSet>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+ <ImportGroup Label="ExtensionSettings">
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <PropertyGroup Label="UserMacros" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <LinkIncremental>true</LinkIncremental>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <LinkIncremental>false</LinkIncremental>
+ </PropertyGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <ClCompile>
+ <PrecompiledHeader>Use</PrecompiledHeader>
+ <WarningLevel>Level3</WarningLevel>
+ <Optimization>Disabled</Optimization>
+ <PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
+ <AdditionalIncludeDirectories>.\</AdditionalIncludeDirectories>
+ <PrecompiledHeaderFile>unifdef.h</PrecompiledHeaderFile>
+ </ClCompile>
+ <Link>
+ <SubSystem>Console</SubSystem>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <ClCompile>
+ <WarningLevel>Level3</WarningLevel>
+ <PrecompiledHeader>Use</PrecompiledHeader>
+ <Optimization>MaxSpeed</Optimization>
+ <FunctionLevelLinking>true</FunctionLevelLinking>
+ <IntrinsicFunctions>true</IntrinsicFunctions>
+ <PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
+ <AdditionalIncludeDirectories>.\</AdditionalIncludeDirectories>
+ <PrecompiledHeaderFile>unifdef.h</PrecompiledHeaderFile>
+ </ClCompile>
+ <Link>
+ <SubSystem>Console</SubSystem>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <EnableCOMDATFolding>true</EnableCOMDATFolding>
+ <OptimizeReferences>true</OptimizeReferences>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemGroup>
+ <ClInclude Include="..\version.h" />
+ <ClInclude Include="..\win32\unifdef.h" />
+ </ItemGroup>
+ <ItemGroup>
+ <ClCompile Include="..\unifdef.c" />
+ <ClCompile Include="..\FreeBSD\err.c" />
+ <ClCompile Include="..\FreeBSD\getopt.c" />
+ <ClCompile Include="win32.c">
+ <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Create</PrecompiledHeader>
+ <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Create</PrecompiledHeader>
+ </ClCompile>
+ </ItemGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+ <ImportGroup Label="ExtensionTargets">
+ </ImportGroup>
+</Project>
diff --git a/win32/win32.c b/win32/win32.c
new file mode 100644
index 000000000000..168f7e7cc041
--- /dev/null
+++ b/win32/win32.c
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 2012 - 2014 Tony Finch <dot@dotat.at>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "unifdef.h"
+
+/*
+ * The Windows implementation of rename() fails if the new filename
+ * already exists. Atomic replacement is not really needed, so just
+ * remove anything that might be in the way before renaming.
+ */
+int
+replace(const char *old, const char *new)
+{
+ if (remove(new) < 0)
+ warn("can't remove \"%s\"", new);
+ return (rename(old, new));
+}
+
+FILE *
+mktempmode(char *tmp, int mode)
+{
+ mode = mode;
+ return (fopen(_mktemp(tmp), "wb"));
+}
+
+FILE *
+fbinmode(FILE *fp)
+{
+ _setmode(_fileno(fp), _O_BINARY);
+ return (fp);
+}
+
+/*
+ * Windows has _snprintf() but it does not work like real snprintf().
+ */
+int snprintf(char *buf, size_t buflen, const char *format, ...)
+{
+ va_list ap;
+ int outlen, cpylen, tmplen;
+ char *tmp;
+
+ va_start(ap, format);
+ outlen = _vscprintf(format, ap);
+ va_end(ap);
+ if (buflen == 0 || outlen < 0)
+ return outlen;
+ if (buflen > outlen)
+ cpylen = outlen;
+ else
+ cpylen = buflen - 1;
+ /* Paranoia about off-by-one errors in _snprintf() */
+ tmplen = outlen + 2;
+
+ tmp = malloc(tmplen);
+ if (tmp == NULL)
+ err(2, "malloc");
+ va_start(ap, format);
+ _vsnprintf(tmp, tmplen, format, ap);
+ va_end(ap);
+ memcpy(buf, tmp, cpylen);
+ buf[cpylen] = '\0';
+ free(tmp);
+
+ return outlen;
+}