Re: Importing pg_bsd_indent into our source tree

Поиск
Список
Период
Сортировка
От Tom Lane
Тема Re: Importing pg_bsd_indent into our source tree
Дата
Msg-id 718245.1676159640@sss.pgh.pa.us
обсуждение исходный текст
Ответ на Re: Importing pg_bsd_indent into our source tree  (Tom Lane <tgl@sss.pgh.pa.us>)
Ответы Re: Importing pg_bsd_indent into our source tree  (Tom Lane <tgl@sss.pgh.pa.us>)
Re: Importing pg_bsd_indent into our source tree  (Andres Freund <andres@anarazel.de>)
Список pgsql-hackers
Here's a v3 of this patchset, incorporating your meson fixes as
well as patches for the portability problems you noted.

I ended up converting the test infrastructure into a TAP test,
which kind of feels like overkill; but the Meson system doesn't
seem to provide any lower-overhead way to run a test.

I've not touched the issue of whether and where to install
pg_bsd_indent; for now, neither build system will do so.

Also, for now both build systems *will* run tests on it,
although I'm not sure if plugging it into "make check-world"
is enough to cause the cfbot to do so, and I'm pretty sure
that the buildfarm won't notice that.

I'll let the cfbot loose on this, and if it runs the tests
successfully I plan to go ahead and push.  We can resolve
the installation question later.  We might want to back off
testing too once we're satisfied about portability.

(I left out the 0004 declaration-formatting patch for now, btw.)

            regards, tom lane

From 55d1373fb0f7df6745ef8c34274bc82cb84d15d0 Mon Sep 17 00:00:00 2001
From: Tom Lane <tgl@sss.pgh.pa.us>
Date: Sat, 11 Feb 2023 14:06:36 -0500
Subject: [PATCH v3 1/3] Import pg_bsd_indent sources.

This brings in an exact copy of the pg_bsd_indent repo as of
commit d301442799cea44e5ccb04331afc537764ec77c5 (2020-12-28).

Discussion: https://postgr.es/m/20200812223409.6di3y2qsnvynao7a@alap3.anarazel.de
---
 src/tools/pg_bsd_indent/.gitignore            |   10 +
 src/tools/pg_bsd_indent/Makefile              |   35 +
 src/tools/pg_bsd_indent/README                |  100 ++
 src/tools/pg_bsd_indent/README.pg_bsd_indent  |   30 +
 src/tools/pg_bsd_indent/args.c                |  354 +++++
 src/tools/pg_bsd_indent/err.c                 |   67 +
 src/tools/pg_bsd_indent/err.h                 |   45 +
 src/tools/pg_bsd_indent/indent.1              |  618 ++++++++
 src/tools/pg_bsd_indent/indent.c              | 1279 +++++++++++++++++
 src/tools/pg_bsd_indent/indent.h              |   51 +
 src/tools/pg_bsd_indent/indent_codes.h        |   75 +
 src/tools/pg_bsd_indent/indent_globs.h        |  343 +++++
 src/tools/pg_bsd_indent/io.c                  |  608 ++++++++
 src/tools/pg_bsd_indent/lexi.c                |  724 ++++++++++
 src/tools/pg_bsd_indent/parse.c               |  342 +++++
 src/tools/pg_bsd_indent/pr_comment.c          |  358 +++++
 src/tools/pg_bsd_indent/tests/binary.0        |    9 +
 src/tools/pg_bsd_indent/tests/binary.0.stdout |   11 +
 src/tools/pg_bsd_indent/tests/comments.0      |   52 +
 .../pg_bsd_indent/tests/comments.0.stdout     |   60 +
 src/tools/pg_bsd_indent/tests/comments.pro    |    1 +
 src/tools/pg_bsd_indent/tests/cppelsecom.0    |    7 +
 .../pg_bsd_indent/tests/cppelsecom.0.stdout   |    7 +
 src/tools/pg_bsd_indent/tests/declarations.0  |   79 +
 .../pg_bsd_indent/tests/declarations.0.stdout |   73 +
 src/tools/pg_bsd_indent/tests/elsecomment.0   |   42 +
 .../pg_bsd_indent/tests/elsecomment.0.stdout  |   47 +
 src/tools/pg_bsd_indent/tests/elsecomment.pro |    1 +
 src/tools/pg_bsd_indent/tests/enum.0          |    6 +
 src/tools/pg_bsd_indent/tests/enum.0.stdout   |    5 +
 src/tools/pg_bsd_indent/tests/f_decls.0       |   27 +
 .../pg_bsd_indent/tests/f_decls.0.stdout      |   30 +
 src/tools/pg_bsd_indent/tests/float.0         |    6 +
 src/tools/pg_bsd_indent/tests/float.0.stdout  |    8 +
 src/tools/pg_bsd_indent/tests/label.0         |   13 +
 src/tools/pg_bsd_indent/tests/label.0.stdout  |   14 +
 src/tools/pg_bsd_indent/tests/label.pro       |    1 +
 src/tools/pg_bsd_indent/tests/list_head.0     |   15 +
 .../pg_bsd_indent/tests/list_head.0.stdout    |   13 +
 src/tools/pg_bsd_indent/tests/nsac.0          |    4 +
 src/tools/pg_bsd_indent/tests/nsac.0.stdout   |    6 +
 src/tools/pg_bsd_indent/tests/nsac.pro        |    1 +
 src/tools/pg_bsd_indent/tests/offsetof.0      |    5 +
 .../pg_bsd_indent/tests/offsetof.0.stdout     |    7 +
 src/tools/pg_bsd_indent/tests/parens.0        |   26 +
 src/tools/pg_bsd_indent/tests/parens.0.stdout |   26 +
 src/tools/pg_bsd_indent/tests/parens.pro      |    1 +
 src/tools/pg_bsd_indent/tests/sac.0           |    4 +
 src/tools/pg_bsd_indent/tests/sac.0.stdout    |    6 +
 src/tools/pg_bsd_indent/tests/sac.pro         |    1 +
 src/tools/pg_bsd_indent/tests/struct.0        |   21 +
 src/tools/pg_bsd_indent/tests/struct.0.stdout |   23 +
 src/tools/pg_bsd_indent/tests/surplusbad.0    |    9 +
 .../pg_bsd_indent/tests/surplusbad.0.stdout   |    9 +
 src/tools/pg_bsd_indent/tests/surplusbad.pro  |    1 +
 .../pg_bsd_indent/tests/types_from_file.0     |    3 +
 .../tests/types_from_file.0.stdout            |    3 +
 .../pg_bsd_indent/tests/types_from_file.list  |    2 +
 .../pg_bsd_indent/tests/types_from_file.pro   |    1 +
 src/tools/pg_bsd_indent/tests/wchar.0         |    6 +
 src/tools/pg_bsd_indent/tests/wchar.0.stdout  |    6 +
 61 files changed, 5737 insertions(+)
 create mode 100644 src/tools/pg_bsd_indent/.gitignore
 create mode 100644 src/tools/pg_bsd_indent/Makefile
 create mode 100644 src/tools/pg_bsd_indent/README
 create mode 100644 src/tools/pg_bsd_indent/README.pg_bsd_indent
 create mode 100644 src/tools/pg_bsd_indent/args.c
 create mode 100644 src/tools/pg_bsd_indent/err.c
 create mode 100644 src/tools/pg_bsd_indent/err.h
 create mode 100644 src/tools/pg_bsd_indent/indent.1
 create mode 100644 src/tools/pg_bsd_indent/indent.c
 create mode 100644 src/tools/pg_bsd_indent/indent.h
 create mode 100644 src/tools/pg_bsd_indent/indent_codes.h
 create mode 100644 src/tools/pg_bsd_indent/indent_globs.h
 create mode 100644 src/tools/pg_bsd_indent/io.c
 create mode 100644 src/tools/pg_bsd_indent/lexi.c
 create mode 100644 src/tools/pg_bsd_indent/parse.c
 create mode 100644 src/tools/pg_bsd_indent/pr_comment.c
 create mode 100644 src/tools/pg_bsd_indent/tests/binary.0
 create mode 100644 src/tools/pg_bsd_indent/tests/binary.0.stdout
 create mode 100644 src/tools/pg_bsd_indent/tests/comments.0
 create mode 100644 src/tools/pg_bsd_indent/tests/comments.0.stdout
 create mode 100644 src/tools/pg_bsd_indent/tests/comments.pro
 create mode 100644 src/tools/pg_bsd_indent/tests/cppelsecom.0
 create mode 100644 src/tools/pg_bsd_indent/tests/cppelsecom.0.stdout
 create mode 100644 src/tools/pg_bsd_indent/tests/declarations.0
 create mode 100644 src/tools/pg_bsd_indent/tests/declarations.0.stdout
 create mode 100644 src/tools/pg_bsd_indent/tests/elsecomment.0
 create mode 100644 src/tools/pg_bsd_indent/tests/elsecomment.0.stdout
 create mode 100644 src/tools/pg_bsd_indent/tests/elsecomment.pro
 create mode 100644 src/tools/pg_bsd_indent/tests/enum.0
 create mode 100644 src/tools/pg_bsd_indent/tests/enum.0.stdout
 create mode 100644 src/tools/pg_bsd_indent/tests/f_decls.0
 create mode 100644 src/tools/pg_bsd_indent/tests/f_decls.0.stdout
 create mode 100644 src/tools/pg_bsd_indent/tests/float.0
 create mode 100644 src/tools/pg_bsd_indent/tests/float.0.stdout
 create mode 100644 src/tools/pg_bsd_indent/tests/label.0
 create mode 100644 src/tools/pg_bsd_indent/tests/label.0.stdout
 create mode 100644 src/tools/pg_bsd_indent/tests/label.pro
 create mode 100644 src/tools/pg_bsd_indent/tests/list_head.0
 create mode 100644 src/tools/pg_bsd_indent/tests/list_head.0.stdout
 create mode 100644 src/tools/pg_bsd_indent/tests/nsac.0
 create mode 100644 src/tools/pg_bsd_indent/tests/nsac.0.stdout
 create mode 100644 src/tools/pg_bsd_indent/tests/nsac.pro
 create mode 100644 src/tools/pg_bsd_indent/tests/offsetof.0
 create mode 100644 src/tools/pg_bsd_indent/tests/offsetof.0.stdout
 create mode 100644 src/tools/pg_bsd_indent/tests/parens.0
 create mode 100644 src/tools/pg_bsd_indent/tests/parens.0.stdout
 create mode 100644 src/tools/pg_bsd_indent/tests/parens.pro
 create mode 100644 src/tools/pg_bsd_indent/tests/sac.0
 create mode 100644 src/tools/pg_bsd_indent/tests/sac.0.stdout
 create mode 100644 src/tools/pg_bsd_indent/tests/sac.pro
 create mode 100644 src/tools/pg_bsd_indent/tests/struct.0
 create mode 100644 src/tools/pg_bsd_indent/tests/struct.0.stdout
 create mode 100644 src/tools/pg_bsd_indent/tests/surplusbad.0
 create mode 100644 src/tools/pg_bsd_indent/tests/surplusbad.0.stdout
 create mode 100644 src/tools/pg_bsd_indent/tests/surplusbad.pro
 create mode 100644 src/tools/pg_bsd_indent/tests/types_from_file.0
 create mode 100644 src/tools/pg_bsd_indent/tests/types_from_file.0.stdout
 create mode 100644 src/tools/pg_bsd_indent/tests/types_from_file.list
 create mode 100644 src/tools/pg_bsd_indent/tests/types_from_file.pro
 create mode 100644 src/tools/pg_bsd_indent/tests/wchar.0
 create mode 100644 src/tools/pg_bsd_indent/tests/wchar.0.stdout

diff --git a/src/tools/pg_bsd_indent/.gitignore b/src/tools/pg_bsd_indent/.gitignore
new file mode 100644
index 0000000000..4c5d8dc691
--- /dev/null
+++ b/src/tools/pg_bsd_indent/.gitignore
@@ -0,0 +1,10 @@
+# Global excludes across all subdirectories
+*.o
+*.obj
+*.exe
+
+# Local excludes in root directory
+/pg_bsd_indent
+/*.out
+/*.list
+/tests.diff
diff --git a/src/tools/pg_bsd_indent/Makefile b/src/tools/pg_bsd_indent/Makefile
new file mode 100644
index 0000000000..ee046f36f0
--- /dev/null
+++ b/src/tools/pg_bsd_indent/Makefile
@@ -0,0 +1,35 @@
+#-------------------------------------------------------------------------
+#
+# Makefile for pg_bsd_indent
+#
+# Copyright (c) 2017, PostgreSQL Global Development Group
+#
+#-------------------------------------------------------------------------
+
+PGFILEDESC = "pg_bsd_indent - indent C code nicely"
+PGAPPICON = win32
+
+PROGRAM = pg_bsd_indent
+OBJS    = args.o err.o indent.o io.o lexi.o parse.o pr_comment.o $(WIN32RES)
+
+# clean junk left behind by "make test"
+EXTRA_CLEAN = *.out *.list tests.diff
+
+PG_CONFIG = pg_config
+PGXS := $(shell $(PG_CONFIG) --pgxs)
+include $(PGXS)
+
+# pgxs.mk assumes too much about what "make check" means, so call it "test"
+.PHONY: test
+
+test: $(PROGRAM)
+    @rm -f tests.diff
+    @cp $(srcdir)/tests/*.list .
+    @for testsrc in $(srcdir)/tests/*.0; do \
+        test=`basename "$$testsrc" .0`; \
+        ./$(PROGRAM) $$testsrc $$test.out -P$(srcdir)/tests/$$test.pro || echo FAILED >>$$test.out; \
+        diff -u $$testsrc.stdout $$test.out >>tests.diff 2>&1 || true; \
+    done
+    @cat tests.diff
+    @test '!' -s tests.diff
+    @echo Tests complete.
diff --git a/src/tools/pg_bsd_indent/README b/src/tools/pg_bsd_indent/README
new file mode 100644
index 0000000000..33d016db62
--- /dev/null
+++ b/src/tools/pg_bsd_indent/README
@@ -0,0 +1,100 @@
+
+  $FreeBSD: head/usr.bin/indent/README 105244 2002-10-16 13:58:39Z charnier $
+
+This is the C indenter, it originally came from the University of Illinois
+via some distribution tape for PDP-11 Unix.  It has subsequently been
+hacked upon by James Gosling @ CMU.  It isn't very pretty, and really needs
+to be completely redone, but it is probably the nicest C pretty printer
+around.
+
+Further additions to provide "Kernel Normal Form" were contributed
+by the folks at Sun Microsystems.
+
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+> From mnetor!yunexus!oz@uunet.UU.NET Wed Mar  9 15:30:55 1988
+> Date: Tue, 8 Mar 88 18:36:25 EST
+> From: yunexus!oz@uunet.UU.NET (Ozan Yigit)
+> To: bostic@okeeffe.berkeley.edu
+> Cc: ccvaxa!willcox@uunet.UU.NET, jag@sun.com, rsalz@uunet.UU.NET
+> In-Reply-To: Keith Bostic's message of Tue, 16 Feb 88 16:09:06 PST
+> Subject: Re: Indent...
+
+Thank you for your response about indent. I was wrong in my original
+observation (or mis-observation :-). UCB did keep the Illinois
+copyright intact.
+
+The issue still is whether we can distribute indent, and if we can, which
+version. David Willcox (the author) states that:
+
+| Several people have asked me on what basis I claim that indent is in
+| the public domain.  I knew I would be sorry I made that posting.
+|
+| Some history.  Way back in 1976, the project I worked on at the
+| University of Illinois Center for Advanced Computation had a huge
+| battle about how to format C code.  After about a week of fighting, I
+| got disgusted and wrote a program, which I called indent, to reformat C
+| code.  It had a bunch of different options that would let you format
+| the output the way you liked.  In particular, all of the different
+| formats being championed were supported.
+|
+| It was my first big C program.  It was ugly.  It wasn't designed, it
+| just sort of grew.  But it pretty much worked, and it stopped most of
+| the fighting.
+|
+| As a matter of form, I included a University of Illinois Copyright
+| notice.  However, my understanding was that, since the work was done
+| on an ARPA contract, it was in the public domain.
+|
+| Time passed.  Some years later, indent showed up on one of the early
+| emacs distributions.
+|
+| Later still, someone from UC Berkeley called the UofI and asked if
+| indent was in the public domain.  They wanted to include it in their
+| UNIX distributions, along with the emacs stuff.  I was no longer at the
+| UofI, but Rob Kolstad, who was, asked me about it.  I told him I didn't
+| care if they used it, and since then it has been on the BSD distributions.
+|
+| Somewhere along the way, several other unnamed people have had their
+| hands in it.  It was converted to understand version 7 C.  (The
+| original was version 6.)  It was converted from its original filter
+| interface to its current "blow away the user's file" interface.
+| The $HOME/.indent.pro file parsing was added.  Some more formatting
+| options were added.
+|
+| The source I have right now has two copyright notices.  One is the
+| original from the UofI.  One is from Berkeley.
+|
+| I am not a lawyer, and I certainly do not understand copyright law.  As
+| far as I am concerned, the bulk of this program, everything covered by
+| the UofI copyright, is in the public domain, and worth every penny.
+| Berkeley's copyright probably should only cover their changes, and I
+| don't know their feelings about sending it out.
+
+In any case, there appears to be none at UofI to clarify/and change
+that copyright, but I am confident (based on the statements of its
+author) that the code, as it stands with its copyright, is
+distributable, and will not cause any legal problems.
+
+Hence, the issue reduces to *which* one to distribute through
+comp.sources.unix. I would suggest that with the permission of you
+folks (given that you have parts copyrighted), we distribute the 4.3
+version of indent, which appears to be the most up-to-date version. I
+happen to have just about every known version of indent, including the
+very original submission from the author to a unix tape, later the
+G-Emacs version, any 4.n version, sun version and the Unipress
+version.  I still think we should not have to "go-back-in-time" and
+re-do all the work you people have done.
+
+I hope to hear from you as to what you think about this. You may of
+course send 4.3 version to the moderator directly, or you can let me
+know of your permission, and I will send the sources, or you can let
+me know that 4.3 version is off-limits, in which case we would probably
+have to revert to an older version. One way or another, I hope to get
+a version of indent to comp.sources.unix.
+
+regards..    oz
+
+cc: ccvaxa!willcox
+    sun.com!jar
+    uunet!rsalz
+
diff --git a/src/tools/pg_bsd_indent/README.pg_bsd_indent b/src/tools/pg_bsd_indent/README.pg_bsd_indent
new file mode 100644
index 0000000000..85c3dcac1c
--- /dev/null
+++ b/src/tools/pg_bsd_indent/README.pg_bsd_indent
@@ -0,0 +1,30 @@
+pg_bsd_indent
+
+This is a lightly modified version of the "indent" program maintained
+by the FreeBSD project.  The modifications are mostly to make it portable
+to non-BSD-ish platforms, though we do have one formatting switch we
+couldn't convince upstream to take.
+
+To build it, you will need a Postgres installation, version 9.5 or newer.
+(Once built, the program doesn't depend on that installation.)
+
+To build, just say "make"; or if pg_config from your Postgres installation
+isn't in your PATH, say
+    make PG_CONFIG=path/to/pg_config
+Optionally, run "make test" for some simple sanity checks.
+
+To install, copy pg_bsd_indent to somewhere in your usual PATH.
+(If you say "make install", it will try to put it in your Postgres
+installation directory, which is most likely not what you want for
+long-term use.)
+
+TODO: add build support and instructions for Windows
+
+
+If you happen to be hacking upon the indent source code, the closest
+approximation to the existing indentation style seems to be
+
+    ./pg_bsd_indent -i4 -l79 -di12 -nfc1 -nlp -sac somefile.c
+
+although this has by no means been rigorously adhered to.
+(What was that saw about the shoemaker's children?)
diff --git a/src/tools/pg_bsd_indent/args.c b/src/tools/pg_bsd_indent/args.c
new file mode 100644
index 0000000000..1c83f57049
--- /dev/null
+++ b/src/tools/pg_bsd_indent/args.c
@@ -0,0 +1,354 @@
+/*-
+ * Copyright (c) 1985 Sun Microsystems, Inc.
+ * Copyright (c) 1980, 1993
+ *    The Regents of the University of California.  All rights reserved.
+ * 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. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *    This product includes software developed by the University of
+ *    California, Berkeley and its contributors.
+ * 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.
+ */
+
+#if 0
+#ifndef lint
+static char sccsid[] = "@(#)args.c    8.1 (Berkeley) 6/6/93";
+#endif /* not lint */
+#endif
+
+#include "c.h"
+
+/*
+ * Argument scanning and profile reading code.  Default parameters are set
+ * here as well.
+ */
+
+#include <ctype.h>
+#include <err.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "indent_globs.h"
+#include "indent.h"
+
+#define INDENT_VERSION    "2.1.1"
+
+/* profile types */
+#define    PRO_SPECIAL    1    /* special case */
+#define    PRO_BOOL    2    /* boolean */
+#define    PRO_INT        3    /* integer */
+
+/* profile specials for booleans */
+#define    ON        1    /* turn it on */
+#define    OFF        0    /* turn it off */
+
+/* profile specials for specials */
+#define    IGN        1    /* ignore it */
+#define    CLI        2    /* case label indent (float) */
+#define    STDIN        3    /* use stdin */
+#define    KEY        4    /* type (keyword) */
+
+static void scan_profile(FILE *);
+
+#define    KEY_FILE        5    /* only used for args */
+#define VERSION            6    /* only used for args */
+
+const char *option_source = "?";
+
+void add_typedefs_from_file(const char *str);
+
+/*
+ * N.B.: because of the way the table here is scanned, options whose names are
+ * substrings of other options must occur later; that is, with -lp vs -l, -lp
+ * must be first.  Also, while (most) booleans occur more than once, the last
+ * default value is the one actually assigned.
+ */
+struct pro {
+    const char *p_name;        /* name, e.g. -bl, -cli */
+    int         p_type;        /* type (int, bool, special) */
+    int         p_default;    /* the default value (if int) */
+    int         p_special;    /* depends on type */
+    int        *p_obj;        /* the associated variable */
+}           pro[] = {
+
+    {"T", PRO_SPECIAL, 0, KEY, 0},
+    {"U", PRO_SPECIAL, 0, KEY_FILE, 0},
+    {"-version", PRO_SPECIAL, 0, VERSION, 0},
+    {"P", PRO_SPECIAL, 0, IGN, 0},
+    {"bacc", PRO_BOOL, false, ON, &blanklines_around_conditional_compilation},
+    {"badp", PRO_BOOL, false, ON, &blanklines_after_declarations_at_proctop},
+    {"bad", PRO_BOOL, false, ON, &blanklines_after_declarations},
+    {"bap", PRO_BOOL, false, ON, &blanklines_after_procs},
+    {"bbb", PRO_BOOL, false, ON, &blanklines_before_blockcomments},
+    {"bc", PRO_BOOL, true, OFF, &ps.leave_comma},
+    {"bl", PRO_BOOL, true, OFF, &btype_2},
+    {"br", PRO_BOOL, true, ON, &btype_2},
+    {"bs", PRO_BOOL, false, ON, &Bill_Shannon},
+    {"cdb", PRO_BOOL, true, ON, &comment_delimiter_on_blankline},
+    {"cd", PRO_INT, 0, 0, &ps.decl_com_ind},
+    {"ce", PRO_BOOL, true, ON, &cuddle_else},
+    {"ci", PRO_INT, 0, 0, &continuation_indent},
+    {"cli", PRO_SPECIAL, 0, CLI, 0},
+    {"cp", PRO_INT, 0, 0, &else_endif_com_ind},
+    {"c", PRO_INT, 33, 0, &ps.com_ind},
+    {"di", PRO_INT, 16, 0, &ps.decl_indent},
+    {"dj", PRO_BOOL, false, ON, &ps.ljust_decl},
+    {"d", PRO_INT, 0, 0, &ps.unindent_displace},
+    {"eei", PRO_BOOL, false, ON, &extra_expression_indent},
+    {"ei", PRO_BOOL, true, ON, &ps.else_if},
+    {"fbs", PRO_BOOL, true, ON, &function_brace_split},
+    {"fc1", PRO_BOOL, true, ON, &format_col1_comments},
+    {"fcb", PRO_BOOL, true, ON, &format_block_comments},
+    {"ip", PRO_BOOL, true, ON, &ps.indent_parameters},
+    {"i", PRO_INT, 8, 0, &ps.ind_size},
+    {"lc", PRO_INT, 0, 0, &block_comment_max_col},
+    {"ldi", PRO_INT, -1, 0, &ps.local_decl_indent},
+    {"lpl", PRO_BOOL, false, ON, &lineup_to_parens_always},
+    {"lp", PRO_BOOL, true, ON, &lineup_to_parens},
+    {"l", PRO_INT, 78, 0, &max_col},
+    {"nbacc", PRO_BOOL, false, OFF, &blanklines_around_conditional_compilation},
+    {"nbadp", PRO_BOOL, false, OFF, &blanklines_after_declarations_at_proctop},
+    {"nbad", PRO_BOOL, false, OFF, &blanklines_after_declarations},
+    {"nbap", PRO_BOOL, false, OFF, &blanklines_after_procs},
+    {"nbbb", PRO_BOOL, false, OFF, &blanklines_before_blockcomments},
+    {"nbc", PRO_BOOL, true, ON, &ps.leave_comma},
+    {"nbs", PRO_BOOL, false, OFF, &Bill_Shannon},
+    {"ncdb", PRO_BOOL, true, OFF, &comment_delimiter_on_blankline},
+    {"nce", PRO_BOOL, true, OFF, &cuddle_else},
+    {"ndj", PRO_BOOL, false, OFF, &ps.ljust_decl},
+    {"neei", PRO_BOOL, false, OFF, &extra_expression_indent},
+    {"nei", PRO_BOOL, true, OFF, &ps.else_if},
+    {"nfbs", PRO_BOOL, true, OFF, &function_brace_split},
+    {"nfc1", PRO_BOOL, true, OFF, &format_col1_comments},
+    {"nfcb", PRO_BOOL, true, OFF, &format_block_comments},
+    {"nip", PRO_BOOL, true, OFF, &ps.indent_parameters},
+    {"nlpl", PRO_BOOL, false, OFF, &lineup_to_parens_always},
+    {"nlp", PRO_BOOL, true, OFF, &lineup_to_parens},
+    {"npcs", PRO_BOOL, false, OFF, &proc_calls_space},
+    {"npro", PRO_SPECIAL, 0, IGN, 0},
+    {"npsl", PRO_BOOL, true, OFF, &procnames_start_line},
+    {"nsac", PRO_BOOL, false, OFF, &space_after_cast},
+    {"nsc", PRO_BOOL, true, OFF, &star_comment_cont},
+    {"nsob", PRO_BOOL, false, OFF, &swallow_optional_blanklines},
+    {"ntpg", PRO_BOOL, false, OFF, &postgres_tab_rules},
+    {"nut", PRO_BOOL, true, OFF, &use_tabs},
+    {"nv", PRO_BOOL, false, OFF, &verbose},
+    {"pcs", PRO_BOOL, false, ON, &proc_calls_space},
+    {"psl", PRO_BOOL, true, ON, &procnames_start_line},
+    {"sac", PRO_BOOL, false, ON, &space_after_cast},
+    {"sc", PRO_BOOL, true, ON, &star_comment_cont},
+    {"sob", PRO_BOOL, false, ON, &swallow_optional_blanklines},
+    {"st", PRO_SPECIAL, 0, STDIN, 0},
+    {"ta", PRO_BOOL, false, ON, &auto_typedefs},
+    {"tpg", PRO_BOOL, false, ON, &postgres_tab_rules},
+    {"ts", PRO_INT, 8, 0, &tabsize},
+    {"ut", PRO_BOOL, true, ON, &use_tabs},
+    {"v", PRO_BOOL, false, ON, &verbose},
+    /* whew! */
+    {0, 0, 0, 0, 0}
+};
+
+/*
+ * set_profile reads $HOME/.indent.pro and ./.indent.pro and handles arguments
+ * given in these files.
+ */
+void
+set_profile(const char *profile_name)
+{
+    FILE *f;
+    char fname[PATH_MAX];
+    static char prof[] = ".indent.pro";
+
+    if (profile_name == NULL)
+    snprintf(fname, sizeof(fname), "%s/%s", getenv("HOME"), prof);
+    else
+    snprintf(fname, sizeof(fname), "%s", profile_name + 2);
+    if ((f = fopen(option_source = fname, "r")) != NULL) {
+    scan_profile(f);
+    (void) fclose(f);
+    }
+    if ((f = fopen(option_source = prof, "r")) != NULL) {
+    scan_profile(f);
+    (void) fclose(f);
+    }
+    option_source = "Command line";
+}
+
+static void
+scan_profile(FILE *f)
+{
+    int        comment, i;
+    char    *p;
+    char        buf[BUFSIZ];
+
+    while (1) {
+    p = buf;
+    comment = 0;
+    while ((i = getc(f)) != EOF) {
+        if (i == '*' && !comment && p > buf && p[-1] == '/') {
+        comment = p - buf;
+        *p++ = i;
+        } else if (i == '/' && comment && p > buf && p[-1] == '*') {
+        p = buf + comment - 1;
+        comment = 0;
+        } else if (isspace((unsigned char)i)) {
+        if (p > buf && !comment)
+            break;
+        } else {
+        *p++ = i;
+        }
+    }
+    if (p != buf) {
+        *p++ = 0;
+        if (verbose)
+        printf("profile: %s\n", buf);
+        set_option(buf);
+    }
+    else if (i == EOF)
+        return;
+    }
+}
+
+static const char *
+eqin(const char *s1, const char *s2)
+{
+    while (*s1) {
+    if (*s1++ != *s2++)
+        return (NULL);
+    }
+    return (s2);
+}
+
+/*
+ * Set the defaults.
+ */
+void
+set_defaults(void)
+{
+    struct pro *p;
+
+    /*
+     * Because ps.case_indent is a float, we can't initialize it from the
+     * table:
+     */
+    ps.case_indent = 0.0;    /* -cli0.0 */
+    for (p = pro; p->p_name; p++)
+    if (p->p_type != PRO_SPECIAL)
+        *p->p_obj = p->p_default;
+}
+
+void
+set_option(char *arg)
+{
+    struct    pro *p;
+    const char    *param_start;
+
+    arg++;            /* ignore leading "-" */
+    for (p = pro; p->p_name; p++)
+    if (*p->p_name == *arg && (param_start = eqin(p->p_name, arg)) != NULL)
+        goto found;
+    errx(1, "%s: unknown parameter \"%s\"", option_source, arg - 1);
+found:
+    switch (p->p_type) {
+
+    case PRO_SPECIAL:
+    switch (p->p_special) {
+
+    case IGN:
+        break;
+
+    case CLI:
+        if (*param_start == 0)
+        goto need_param;
+        ps.case_indent = atof(param_start);
+        break;
+
+    case STDIN:
+        if (input == NULL)
+        input = stdin;
+        if (output == NULL)
+        output = stdout;
+        break;
+
+    case KEY:
+        if (*param_start == 0)
+        goto need_param;
+        add_typename(param_start);
+        break;
+
+    case KEY_FILE:
+        if (*param_start == 0)
+        goto need_param;
+        add_typedefs_from_file(param_start);
+        break;
+
+    case VERSION:
+        printf("pg_bsd_indent %s (based on FreeBSD indent)\n", INDENT_VERSION);
+        exit(0);
+
+    default:
+        errx(1, "set_option: internal error: p_special %d", p->p_special);
+    }
+    break;
+
+    case PRO_BOOL:
+    if (p->p_special == OFF)
+        *p->p_obj = false;
+    else
+        *p->p_obj = true;
+    break;
+
+    case PRO_INT:
+    if (!isdigit((unsigned char)*param_start)) {
+    need_param:
+        errx(1, "%s: ``%s'' requires a parameter", option_source, p->p_name);
+    }
+    *p->p_obj = atoi(param_start);
+    break;
+
+    default:
+    errx(1, "set_option: internal error: p_type %d", p->p_type);
+    }
+}
+
+void
+add_typedefs_from_file(const char *str)
+{
+    FILE *file;
+    char line[BUFSIZ];
+
+    if ((file = fopen(str, "r")) == NULL) {
+    fprintf(stderr, "indent: cannot open file %s\n", str);
+    exit(1);
+    }
+    while ((fgets(line, BUFSIZ, file)) != NULL) {
+    /* Remove trailing whitespace */
+    line[strcspn(line, " \t\n\r")] = '\0';
+    add_typename(line);
+    }
+    fclose(file);
+}
diff --git a/src/tools/pg_bsd_indent/err.c b/src/tools/pg_bsd_indent/err.c
new file mode 100644
index 0000000000..807319334b
--- /dev/null
+++ b/src/tools/pg_bsd_indent/err.c
@@ -0,0 +1,67 @@
+/*-
+ * 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.
+ * 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.
+ */
+
+/*
+ * This is cut down to just the minimum that we need to build indent.
+ */
+#include "c.h"
+
+#include <err.h>
+#include <errno.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+void
+err(int eval, const char *fmt, ...)
+{
+    int code = errno;
+    va_list ap;
+    va_start(ap, fmt);
+    if (fmt != NULL) {
+        vfprintf(stderr, fmt, ap);
+        fprintf(stderr, ": ");
+    }
+    fprintf(stderr, "%s\n", strerror(code));
+    va_end(ap);
+    exit(eval);
+}
+
+void
+errx(int eval, const char *fmt, ...)
+{
+    va_list ap;
+    va_start(ap, fmt);
+    if (fmt != NULL)
+        vfprintf(stderr, fmt, ap);
+    fprintf(stderr, "\n");
+    va_end(ap);
+    exit(eval);
+}
diff --git a/src/tools/pg_bsd_indent/err.h b/src/tools/pg_bsd_indent/err.h
new file mode 100644
index 0000000000..a3e8f97825
--- /dev/null
+++ b/src/tools/pg_bsd_indent/err.h
@@ -0,0 +1,45 @@
+/*-
+ * 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.
+ * 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.
+ *
+ *    @(#)err.h    8.1 (Berkeley) 6/2/93
+ * $FreeBSD: stable/11/include/err.h 203964 2010-02-16 19:39:50Z imp $
+ */
+
+#ifndef _ERR_H_
+#define    _ERR_H_
+
+/*
+ * This is cut down to just the minimum that we need to build indent.
+ */
+
+void    err(int, const char *, ...)
+  pg_attribute_noreturn() pg_attribute_printf(2, 3);
+void    errx(int, const char *, ...)
+  pg_attribute_noreturn() pg_attribute_printf(2, 3);
+
+#endif /* !_ERR_H_ */
diff --git a/src/tools/pg_bsd_indent/indent.1 b/src/tools/pg_bsd_indent/indent.1
new file mode 100644
index 0000000000..131abfe70b
--- /dev/null
+++ b/src/tools/pg_bsd_indent/indent.1
@@ -0,0 +1,618 @@
+.\" Copyright (c) 1980, 1990, 1993
+.\"    The Regents of the University of California.  All rights reserved.
+.\" Copyright (c) 1976 Board of Trustees of the University of Illinois.
+.\" 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.
+.\"
+.\"    @(#)indent.1    8.1 (Berkeley) 7/1/93
+.\" $FreeBSD: head/usr.bin/indent/indent.1 309524 2016-12-04 03:10:25Z pfg $
+.\"
+.Dd December 2, 2016
+.Dt INDENT 1
+.Os
+.Sh NAME
+.Nm indent
+.Nd indent and format C program source
+.Sh SYNOPSIS
+.Nm
+.Op Ar input-file Op Ar output-file
+.Op Fl bacc | Fl nbacc
+.Op Fl bad | Fl nbad
+.Op Fl badp | Fl nbadp
+.Op Fl bap | Fl nbap
+.Op Fl bbb | Fl nbbb
+.Op Fl \&bc | Fl nbc
+.Op Fl \&bl | Fl \&br
+.Op Fl bs | Fl nbs
+.Op Fl c Ns Ar n
+.Op Fl cp Ns Ar n
+.Op Fl \&cd Ns Ar n
+.Bk -words
+.Op Fl cdb | Fl ncdb
+.Ek
+.Op Fl \&ce | Fl nce
+.Op Fl \&ci Ns Ar n
+.Op Fl cli Ns Ar n
+.Op Fl d Ns Ar n
+.Op Fl \&di Ns Ar n
+.Op Fl dj | Fl ndj
+.Bk -words
+.Op Fl ei | Fl nei
+.Op Fl eei | Fl neei
+.Ek
+.Bk -words
+.Op Fl fbs | Fl nfbs
+.Op Fl fc1 | Fl nfc1
+.Op Fl fcb | Fl nfcb
+.Ek
+.Op Fl i Ns Ar n
+.Op Fl \&ip | Fl nip
+.Op Fl l Ns Ar n
+.Op Fl \&lc Ns Ar n
+.Op Fl \&ldi Ns Ar n
+.Op Fl \&lp | Fl nlp
+.Op Fl \&lpl | Fl nlpl
+.Op Fl npro
+.Op Fl P Ns Ar file
+.Op Fl pcs | Fl npcs
+.Op Fl psl | Fl npsl
+.Op Fl sac | Fl nsac
+.Op Fl \&sc | Fl nsc
+.Bk -words
+.Op Fl sob | Fl nsob
+.Ek
+.Op Fl \&st
+.Op Fl \&ta
+.Op Fl T Ns Ar typename
+.Op Fl tpg | Fl ntpg
+.Op Fl ts Ns Ar n
+.Op Fl U Ns Ar file
+.Op Fl ut | Fl nut
+.Op Fl v | Fl \&nv
+.Op Fl -version
+.Sh DESCRIPTION
+The
+.Nm
+utility is a
+.Em C
+program formatter.
+It reformats the
+.Em C
+program in the
+.Ar input-file
+according to the switches.
+The switches which can be
+specified are described below.
+They may appear before or after the file
+names.
+.Pp
+.Sy NOTE :
+If you only specify an
+.Ar input-file ,
+the formatting is
+done `in-place', that is, the formatted file is written back into
+.Ar input-file
+and a backup copy of
+.Ar input-file
+is written in the current directory.
+If
+.Ar input-file
+is named
+.Sq Pa /blah/blah/file ,
+the backup file is named
+.Sq Pa file.BAK .
+.Pp
+If
+.Ar output-file
+is specified,
+.Nm
+checks to make sure that it is different from
+.Ar input-file .
+.Pp
+The options listed below control the formatting style imposed by
+.Nm .
+.Bl -tag -width Op
+.It Fl bacc , nbacc
+If
+.Fl bacc
+is specified, a blank line is forced around every conditional
+compilation block.
+For example, in front of every #ifdef and after every #endif.
+Other blank lines surrounding such blocks will be swallowed.
+Default:
+.Fl nbacc  .
+.It Fl bad , nbad
+If
+.Fl bad
+is specified, a blank line is forced after every block of
+declarations.
+Default:
+.Fl nbad .
+.It Fl badp , nbadp
+This is vaguely similar to
+.Fl bad
+except that it only applies to the first set of declarations
+in a procedure (just after the first `{') and it causes a blank
+line to be generated even if there are no declarations.
+The default is
+.Fl nbadp.
+.It Fl bap , nbap
+If
+.Fl bap
+is specified, a blank line is forced after every procedure body.
+Default:
+.Fl nbap .
+.It Fl bbb , nbbb
+If
+.Fl bbb
+is specified, a blank line is forced before every block comment.
+Default:
+.Fl nbbb .
+.It Fl \&bc , nbc
+If
+.Fl \&bc
+is specified, then a newline is forced after each comma in a declaration.
+.Fl nbc
+turns off this option.
+Default:
+.Fl \&nbc .
+.It Fl \&bl , \&br
+Specifying
+.Fl \&bl
+lines up compound statements like this:
+.Bd -literal -offset indent
+if (...)
+{
+  code
+}
+.Ed
+.Pp
+Specifying
+.Fl \&br
+(the default) makes them look like this:
+.Bd -literal -offset indent
+if (...) {
+  code
+}
+.Ed
+.It Fl bs , nbs
+Whether a blank should always be inserted after sizeof.
+The default is
+.Fl nbs.
+.It Fl c Ns Ar n
+The column in which comments on code start.
+The default is 33.
+.It Fl cp Ns Ar n
+The column in which comments on #else and #endif start.
+The default is 0, which effectively separates the directives from comments by
+a single space.
+.It Fl cd Ns Ar n
+The column in which comments on declarations start.
+The default
+is for these comments to start in the same column as those on code.
+.It Fl cdb , ncdb
+Enables (disables) the placement of comment delimiters on blank lines.
+With
+this option enabled, comments look like this:
+.Bd -literal -offset indent
+    /*
+     * this is a comment
+     */
+.Ed
+.Pp
+Rather than like this:
+.Bd -literal -offset indent
+    /* this is a comment */
+.Ed
+.Pp
+This only affects block comments, not comments to the right of
+code.
+The default is
+.Fl cdb .
+.It Fl ce , nce
+Enables (disables) forcing of `else's to cuddle up to the immediately preceding
+`}'.
+The default is
+.Fl \&ce .
+.It Fl \&ci Ns Ar n
+Sets the continuation indent to be
+.Ar n .
+Continuation
+lines will be indented that far from the beginning of the first line of the
+statement.
+Parenthesized expressions have extra indentation added to
+indicate the nesting, unless
+.Fl \&lp
+is in effect
+or the continuation indent is exactly half of the main indent.
+.Fl \&ci
+defaults to the same value as
+.Fl i .
+.It Fl cli Ns Ar n
+Causes case labels to be indented
+.Ar n
+tab stops to the right of the containing
+.Ic switch
+statement.
+.Fl cli0.5
+causes case labels to be indented half a tab stop.
+The
+default is
+.Fl cli0 .
+.It Fl d Ns Ar n
+Controls the placement of comments which are not to the
+right of code.
+For example,
+.Fl \&d\&1
+means that such comments are placed one indentation level to the
+left of code.
+Specifying the default
+.Fl \&d\&0
+lines up these comments with the code.
+See the section on comment
+indentation below.
+.It Fl \&di Ns Ar n
+Specifies the indentation, in character positions,
+of global variable names and all struct/union member names
+relative to the beginning of their type declaration.
+The default is
+.Fl di16 .
+.It Fl dj , ndj
+.Fl \&dj
+left justifies declarations.
+.Fl ndj
+indents declarations the same as code.
+The default is
+.Fl ndj .
+.It Fl \&ei , nei
+Enables (disables) special
+.Ic else-if
+processing.
+If it is enabled, an
+.Ic if
+following an
+.Ic else
+will have the same indentation as the preceding
+.Ic \&if
+statement.
+The default is
+.Fl ei .
+.It Fl eei , neei
+Enables (disables) extra indentation on continuation lines of
+the expression part of
+.Ic if
+and
+.Ic while
+statements.
+These continuation lines will be indented one extra level.
+The default is
+.Fl neei .
+.It Fl fbs , nfbs
+Enables (disables) splitting the function declaration and opening brace
+across two lines.
+The default is
+.Fl fbs .
+.It Fl fc1 , nfc1
+Enables (disables) the formatting of comments that start in column 1.
+Often, comments whose leading `/' is in column 1 have been carefully
+hand formatted by the programmer.
+In such cases,
+.Fl nfc1
+should be
+used.
+The default is
+.Fl fc1 .
+.It Fl fcb , nfcb
+Enables (disables) the formatting of block comments (ones that begin
+with `/*\\n').
+Often, block comments have been not so carefully hand formatted by the
+programmer, but reformatting that would just change the line breaks is not
+wanted.
+In such cases,
+.Fl nfcb
+should be used.
+Block comments are then handled like box comments.
+The default is
+.Fl fcb .
+.It Fl i Ns Ar n
+The number of columns for one indentation level.
+The default is 8.
+.It Fl \&ip , nip
+Enables (disables) the indentation of parameter declarations from the left
+margin.
+The default is
+.Fl \&ip .
+.It Fl l Ns Ar n
+Maximum length of an output line.
+The default is 78.
+.It Fl lc Ns Ar n
+Maximum length of an output line in a block comment.
+The default is 0, which means to limit block comment lines in accordance with
+.Fl l.
+.It Fl \&ldi Ns Ar n
+Specifies the indentation, in character positions,
+of local variable names
+relative to the beginning of their type declaration.
+The default is for local variable names to be indented
+by the same amount as global ones.
+.It Fl \&lp , nlp
+Lines up code surrounded by parentheses in continuation lines.
+With
+.Fl \&lp ,
+if a line
+has a left paren which is not closed on that line, then continuation lines
+will be lined up to start at the character position just after the left
+paren.
+For example, here is how a piece of continued code looks with
+.Fl nlp
+in effect:
+.Bd -literal -offset indent
+p1 = first_procedure(second_procedure(p2, p3),
+\ \ third_procedure(p4, p5));
+.Ed
+.Pp
+With
+.Fl lp
+in effect (the default) the code looks somewhat clearer:
+.Bd -literal -offset indent
+p1\ =\ first_procedure(second_procedure(p2,\ p3),
+\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ third_procedure(p4,\ p5));
+.Ed
+.Pp
+Inserting two more newlines we get:
+.Bd -literal -offset indent
+p1\ =\ first_procedure(second_procedure(p2,
+\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ p3),
+\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ third_procedure(p4,
+\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ p5));
+.Ed
+.It Fl \&lpl , nlpl
+With
+.Fl \&lpl ,
+code surrounded by parentheses in continuation lines is lined up even if it
+would extend past the right margin.
+With
+.Fl \&nlpl
+(the default), such a line that would extend past the right margin is moved
+left to keep it within the margin, if that does not require placing it to
+the left of the prevailing indentation level.
+These switches have no effect if
+.Fl nlp
+is selected.
+.It Fl npro
+Causes the profile files,
+.Sq Pa ./.indent.pro
+and
+.Sq Pa ~/.indent.pro ,
+to be ignored.
+.It Fl P Ns Ar file
+Read profile from
+.Ar file .
+.It Fl pcs , npcs
+If true
+.Pq Fl pcs
+all procedure calls will have a space inserted between
+the name and the `('.
+The default is
+.Fl npcs .
+.It Fl psl , npsl
+If true
+.Pq Fl psl
+the names of procedures being defined are placed in
+column 1 \- their types, if any, will be left on the previous lines.
+The
+default is
+.Fl psl .
+.It Fl sac , nsac
+Control whether parenthesized type names in casts are followed by a space or
+not.
+The default is
+.Fl nsac .
+.It Fl \&sc , nsc
+Enables (disables) the placement of asterisks (`*'s) at the left edge of all
+comments.
+The default is
+.Fl sc .
+.It Fl sob , nsob
+If
+.Fl sob
+is specified, indent will swallow optional blank lines.
+You can use this to
+get rid of blank lines after declarations.
+Default:
+.Fl nsob .
+.It Fl \&st
+Causes
+.Nm
+to take its input from stdin and put its output to stdout.
+.It Fl ta
+Automatically add all identifiers ending in "_t" to the list
+of type keywords.
+.It Fl T Ns Ar typename
+Adds
+.Ar typename
+to the list of type keywords.
+Names accumulate:
+.Fl T
+can be specified more than once.
+You need to specify all the typenames that
+appear in your program that are defined by
+.Ic typedef
+\- nothing will be
+harmed if you miss a few, but the program will not be formatted as nicely as
+it should.
+This sounds like a painful thing to have to do, but it is really
+a symptom of a problem in C:
+.Ic typedef
+causes a syntactic change in the
+language and
+.Nm
+cannot find all
+instances of
+.Ic typedef .
+.It Fl tpg , ntpg
+If
+.Fl tpg
+is specified, follow Postgres rules about when to use spaces versus
+tabs for indentation, that is, use a space instead of a tab if the
+tab would move only one column and no tab will follow it.
+Default:
+.Fl ntpg .
+.It Fl ts Ns Ar n
+Assumed distance between tab stops.
+The default is 8.
+.It Fl U Ns Ar file
+Adds type names from
+.Ar file
+to the list of type keywords.
+.It Fl ut , nut
+Enables (disables) the use of tab characters in the output.
+The default is
+.Fl ut .
+.It Fl v , \&nv
+.Fl v
+turns on `verbose' mode;
+.Fl \&nv
+turns it off.
+When in verbose mode,
+.Nm
+reports when it splits one line of input into two or more lines of output,
+and gives some size statistics at completion.
+The default is
+.Fl \&nv .
+.It Fl -version
+Causes
+.Nm
+to print its version number and exit.
+.El
+.Pp
+You may set up your own `profile' of defaults to
+.Nm
+by creating a file called
+.Pa .indent.pro
+in your login directory and/or the current directory and including
+whatever switches you like.
+A `.indent.pro' in the current directory takes
+precedence over the one in your login directory.
+If
+.Nm
+is run and a profile file exists, then it is read to set up the program's
+defaults.
+Switches on the command line, though, always override profile
+switches.
+The switches should be separated by spaces, tabs or newlines.
+.Pp
+.Ss Comments
+.Sq Em Box
+.Em comments .
+The
+.Nm
+utility
+assumes that any comment with a dash or star immediately after the start of
+comment (that is, `/*\-' or `/**') is a comment surrounded by a box of stars.
+Each line of such a comment is left unchanged, except that its indentation
+may be adjusted to account for the change in indentation of the first line
+of the comment.
+.Pp
+.Em Straight text .
+All other comments are treated as straight text.
+The
+.Nm
+utility fits as many words (separated by blanks, tabs, or newlines) on a
+line as possible.
+Blank lines break paragraphs.
+.Ss Comment indentation
+If a comment is on a line with code it is started in the `comment column',
+which is set by the
+.Fl c Ns Ns Ar n
+command line parameter.
+Otherwise, the comment is started at
+.Ar n
+indentation levels less than where code is currently being placed, where
+.Ar n
+is specified by the
+.Fl d Ns Ns Ar n
+command line parameter.
+If the code on a line extends past the comment
+column, the comment starts further to the right, and the right margin may be
+automatically extended in extreme cases.
+.Ss Preprocessor lines
+In general,
+.Nm
+leaves preprocessor lines alone.
+The only
+reformatting that it will do is to straighten up trailing comments.
+It
+leaves embedded comments alone.
+Conditional compilation
+.Pq Ic #ifdef...#endif
+is recognized and
+.Nm
+attempts to correctly
+compensate for the syntactic peculiarities introduced.
+.Ss C syntax
+The
+.Nm
+utility understands a substantial amount about the syntax of C, but it
+has a `forgiving' parser.
+It attempts to cope with the usual sorts of
+incomplete and malformed syntax.
+In particular, the use of macros like:
+.Pp
+.Dl #define forever for(;;)
+.Pp
+is handled properly.
+.Sh ENVIRONMENT
+The
+.Nm
+utility uses the
+.Ev HOME
+environment variable.
+.Sh FILES
+.Bl -tag -width "./.indent.pro" -compact
+.It Pa ./.indent.pro
+profile file
+.It Pa ~/.indent.pro
+profile file
+.El
+.Sh HISTORY
+The
+.Nm
+command appeared in
+.Bx 4.2 .
+.Sh BUGS
+The
+.Nm
+utility has even more switches than
+.Xr ls 1 .
+.Pp
+A common mistake is to try to indent all the
+.Em C
+programs in a directory by typing:
+.Pp
+.Dl indent *.c
+.Pp
+This is probably a bug, not a feature.
diff --git a/src/tools/pg_bsd_indent/indent.c b/src/tools/pg_bsd_indent/indent.c
new file mode 100644
index 0000000000..d3a0ecefe9
--- /dev/null
+++ b/src/tools/pg_bsd_indent/indent.c
@@ -0,0 +1,1279 @@
+/*-
+ * Copyright (c) 1985 Sun Microsystems, Inc.
+ * Copyright (c) 1976 Board of Trustees of the University of Illinois.
+ * Copyright (c) 1980, 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.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *    This product includes software developed by the University of
+ *    California, Berkeley and its contributors.
+ * 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.
+ */
+
+#if 0
+#ifndef lint
+static char sccsid[] = "@(#)indent.c    5.17 (Berkeley) 6/7/93";
+#endif /* not lint */
+#endif
+
+#include "c.h"
+
+#include <sys/param.h>
+#include <err.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+
+/* Tell indent_globs.h to define our global variables here */
+#define DECLARE_INDENT_GLOBALS 1
+
+#include "indent_globs.h"
+#include "indent_codes.h"
+#include "indent.h"
+
+static void bakcopy(void);
+static void indent_declaration(int, int);
+
+const char *in_name = "Standard Input";    /* will always point to name of input
+                     * file */
+const char *out_name = "Standard Output";    /* will always point to name
+                         * of output file */
+char        bakfile[MAXPATHLEN] = "";
+
+int
+main(int argc, char **argv)
+{
+    int         dec_ind;    /* current indentation for declarations */
+    int         di_stack[20];    /* a stack of structure indentation levels */
+    int         force_nl;    /* when true, code must be broken */
+    int         hd_type = 0;    /* used to store type of stmt for if (...),
+                 * for (...), etc */
+    int        i;        /* local loop counter */
+    int         scase;        /* set to true when we see a case, so we will
+                 * know what to do with the following colon */
+    int         sp_sw;        /* when true, we are in the expression of
+                 * if(...), while(...), etc. */
+    int         squest;        /* when this is positive, we have seen a ?
+                 * without the matching : in a <c>?<s>:<s>
+                 * construct */
+    const char *t_ptr;        /* used for copying tokens */
+    int        tabs_to_var;    /* true if using tabs to indent to var name */
+    int         type_code;    /* the type of token, returned by lexi */
+
+    int         last_else = 0;    /* true iff last keyword was an else */
+    const char *profile_name = NULL;
+    struct parser_state transient_state; /* a copy for lookup */
+
+
+    /*-----------------------------------------------*\
+    |              INITIALIZATION              |
+    \*-----------------------------------------------*/
+
+    found_err = 0;
+
+    ps.p_stack[0] = stmt;    /* this is the parser's stack */
+    ps.last_nl = true;        /* this is true if the last thing scanned was
+                 * a newline */
+    ps.last_token = semicolon;
+    combuf = (char *) malloc(bufsize);
+    if (combuf == NULL)
+    err(1, NULL);
+    labbuf = (char *) malloc(bufsize);
+    if (labbuf == NULL)
+    err(1, NULL);
+    codebuf = (char *) malloc(bufsize);
+    if (codebuf == NULL)
+    err(1, NULL);
+    tokenbuf = (char *) malloc(bufsize);
+    if (tokenbuf == NULL)
+    err(1, NULL);
+    alloc_typenames();
+    l_com = combuf + bufsize - 5;
+    l_lab = labbuf + bufsize - 5;
+    l_code = codebuf + bufsize - 5;
+    l_token = tokenbuf + bufsize - 5;
+    combuf[0] = codebuf[0] = labbuf[0] = ' ';    /* set up code, label, and
+                         * comment buffers */
+    combuf[1] = codebuf[1] = labbuf[1] = '\0';
+    ps.else_if = 1;        /* Default else-if special processing to on */
+    s_lab = e_lab = labbuf + 1;
+    s_code = e_code = codebuf + 1;
+    s_com = e_com = combuf + 1;
+    s_token = e_token = tokenbuf + 1;
+
+    in_buffer = (char *) malloc(10);
+    if (in_buffer == NULL)
+    err(1, NULL);
+    in_buffer_limit = in_buffer + 8;
+    buf_ptr = buf_end = in_buffer;
+    line_no = 1;
+    had_eof = ps.in_decl = ps.decl_on_line = break_comma = false;
+    sp_sw = force_nl = false;
+    ps.in_or_st = false;
+    ps.bl_line = true;
+    dec_ind = 0;
+    di_stack[ps.dec_nest = 0] = 0;
+    ps.want_blank = ps.in_stmt = ps.ind_stmt = false;
+
+    scase = ps.pcase = false;
+    squest = 0;
+    sc_end = NULL;
+    bp_save = NULL;
+    be_save = NULL;
+
+    output = NULL;
+    tabs_to_var = 0;
+
+    /*--------------------------------------------------*\
+    |           COMMAND LINE SCAN         |
+    \*--------------------------------------------------*/
+
+#ifdef undef
+    max_col = 78;        /* -l78 */
+    lineup_to_parens = 1;    /* -lp */
+    lineup_to_parens_always = 0;    /* -nlpl */
+    ps.ljust_decl = 0;        /* -ndj */
+    ps.com_ind = 33;        /* -c33 */
+    star_comment_cont = 1;    /* -sc */
+    ps.ind_size = 8;        /* -i8 */
+    verbose = 0;
+    ps.decl_indent = 16;    /* -di16 */
+    ps.local_decl_indent = -1;    /* if this is not set to some nonnegative value
+                 * by an arg, we will set this equal to
+                 * ps.decl_ind */
+    ps.indent_parameters = 1;    /* -ip */
+    ps.decl_com_ind = 0;    /* if this is not set to some positive value
+                 * by an arg, we will set this equal to
+                 * ps.com_ind */
+    btype_2 = 1;        /* -br */
+    cuddle_else = 1;        /* -ce */
+    ps.unindent_displace = 0;    /* -d0 */
+    ps.case_indent = 0;        /* -cli0 */
+    format_block_comments = 1;    /* -fcb */
+    format_col1_comments = 1;    /* -fc1 */
+    procnames_start_line = 1;    /* -psl */
+    proc_calls_space = 0;    /* -npcs */
+    comment_delimiter_on_blankline = 1;    /* -cdb */
+    ps.leave_comma = 1;        /* -nbc */
+#endif
+
+    for (i = 1; i < argc; ++i)
+    if (strcmp(argv[i], "-npro") == 0)
+        break;
+    else if (argv[i][0] == '-' && argv[i][1] == 'P' && argv[i][2] != '\0')
+        profile_name = argv[i];    /* non-empty -P (set profile) */
+    set_defaults();
+    if (i >= argc)
+    set_profile(profile_name);
+
+    for (i = 1; i < argc; ++i) {
+
+    /*
+     * look thru args (if any) for changes to defaults
+     */
+    if (argv[i][0] != '-') {/* no flag on parameter */
+        if (input == NULL) {    /* we must have the input file */
+        in_name = argv[i];    /* remember name of input file */
+        input = fopen(in_name, "r");
+        if (input == NULL)    /* check for open error */
+            err(1, "%s", in_name);
+        continue;
+        }
+        else if (output == NULL) {    /* we have the output file */
+        out_name = argv[i];    /* remember name of output file */
+        if (strcmp(in_name, out_name) == 0) {    /* attempt to overwrite
+                             * the file */
+            errx(1, "input and output files must be different");
+        }
+        output = fopen(out_name, "w");
+        if (output == NULL)    /* check for create error */
+            err(1, "%s", out_name);
+        continue;
+        }
+        errx(1, "unknown parameter: %s", argv[i]);
+    }
+    else
+        set_option(argv[i]);
+    }                /* end of for */
+    if (input == NULL)
+    input = stdin;
+    if (output == NULL) {
+    if (input == stdin)
+        output = stdout;
+    else {
+        out_name = in_name;
+        bakcopy();
+    }
+    }
+
+    if (ps.com_ind <= 1)
+    ps.com_ind = 2;        /* dont put normal comments before column 2 */
+    if (block_comment_max_col <= 0)
+    block_comment_max_col = max_col;
+    if (ps.local_decl_indent < 0)    /* if not specified by user, set this */
+    ps.local_decl_indent = ps.decl_indent;
+    if (ps.decl_com_ind <= 0)    /* if not specified by user, set this */
+    ps.decl_com_ind = ps.ljust_decl ? (ps.com_ind <= 10 ? 2 : ps.com_ind - 8) : ps.com_ind;
+    if (continuation_indent == 0)
+    continuation_indent = ps.ind_size;
+    fill_buffer();        /* get first batch of stuff into input buffer */
+
+    parse(semicolon);
+    {
+    char *p = buf_ptr;
+    int col = 1;
+
+    while (1) {
+        if (*p == ' ')
+        col++;
+        else if (*p == '\t')
+        col = tabsize * (1 + (col - 1) / tabsize) + 1;
+        else
+        break;
+        p++;
+    }
+    if (col > ps.ind_size)
+        ps.ind_level = ps.i_l_follow = col / ps.ind_size;
+    }
+
+    /*
+     * START OF MAIN LOOP
+     */
+
+    while (1) {            /* this is the main loop.  it will go until we
+                 * reach eof */
+    int comment_buffered = false;
+
+    type_code = lexi(&ps);    /* lexi reads one token.  The actual
+                 * characters read are stored in "token". lexi
+                 * returns a code indicating the type of token */
+
+    /*
+     * The following code moves newlines and comments following an if (),
+     * while (), else, etc. up to the start of the following stmt to
+     * a buffer. This allows proper handling of both kinds of brace
+     * placement (-br, -bl) and cuddling "else" (-ce).
+     */
+
+    while (ps.search_brace) {
+        switch (type_code) {
+        case newline:
+        if (sc_end == NULL) {
+            save_com = sc_buf;
+            save_com[0] = save_com[1] = ' ';
+            sc_end = &save_com[2];
+        }
+        *sc_end++ = '\n';
+        /*
+         * We may have inherited a force_nl == true from the previous
+         * token (like a semicolon). But once we know that a newline
+         * has been scanned in this loop, force_nl should be false.
+         *
+         * However, the force_nl == true must be preserved if newline
+         * is never scanned in this loop, so this assignment cannot be
+         * done earlier.
+         */
+        force_nl = false;
+        case form_feed:
+        break;
+        case comment:
+        if (sc_end == NULL) {
+            /*
+             * Copy everything from the start of the line, because
+             * pr_comment() will use that to calculate original
+             * indentation of a boxed comment.
+             */
+            memcpy(sc_buf, in_buffer, buf_ptr - in_buffer - 4);
+            save_com = sc_buf + (buf_ptr - in_buffer - 4);
+            save_com[0] = save_com[1] = ' ';
+            sc_end = &save_com[2];
+        }
+        comment_buffered = true;
+        *sc_end++ = '/';    /* copy in start of comment */
+        *sc_end++ = '*';
+        for (;;) {    /* loop until we get to the end of the comment */
+            *sc_end = *buf_ptr++;
+            if (buf_ptr >= buf_end)
+            fill_buffer();
+            if (*sc_end++ == '*' && *buf_ptr == '/')
+            break;    /* we are at end of comment */
+            if (sc_end >= &save_com[sc_size]) {    /* check for temp buffer
+                             * overflow */
+            diag2(1, "Internal buffer overflow - Move big comment from right after if, while, or whatever");
+            fflush(output);
+            exit(1);
+            }
+        }
+        *sc_end++ = '/';    /* add ending slash */
+        if (++buf_ptr >= buf_end)    /* get past / in buffer */
+            fill_buffer();
+        break;
+        case lbrace:
+        /*
+         * Put KNF-style lbraces before the buffered up tokens and
+         * jump out of this loop in order to avoid copying the token
+         * again under the default case of the switch below.
+         */
+        if (sc_end != NULL && btype_2) {
+            save_com[0] = '{';
+            /*
+             * Originally the lbrace may have been alone on its own
+             * line, but it will be moved into "the else's line", so
+             * if there was a newline resulting from the "{" before,
+             * it must be scanned now and ignored.
+             */
+            while (isspace((unsigned char)*buf_ptr)) {
+            if (++buf_ptr >= buf_end)
+                fill_buffer();
+            if (*buf_ptr == '\n')
+                break;
+            }
+            goto sw_buffer;
+        }
+        /* FALLTHROUGH */
+        default:        /* it is the start of a normal statement */
+        {
+            int remove_newlines;
+
+            remove_newlines =
+            /* "} else" */
+            (type_code == sp_nparen && *token == 'e' &&
+                e_code != s_code && e_code[-1] == '}')
+            /* "else if" */
+            || (type_code == sp_paren && *token == 'i' &&
+                last_else && ps.else_if);
+            if (remove_newlines)
+            force_nl = false;
+            if (sc_end == NULL) {    /* ignore buffering if
+                         * comment wasn't saved up */
+            ps.search_brace = false;
+            goto check_type;
+            }
+            while (sc_end > save_com && isblank((unsigned char)sc_end[-1])) {
+            sc_end--;
+            }
+            if (swallow_optional_blanklines ||
+            (!comment_buffered && remove_newlines)) {
+            force_nl = !remove_newlines;
+            while (sc_end > save_com && sc_end[-1] == '\n') {
+                sc_end--;
+            }
+            }
+            if (force_nl) {    /* if we should insert a nl here, put
+                     * it into the buffer */
+            force_nl = false;
+            --line_no;    /* this will be re-increased when the
+                     * newline is read from the buffer */
+            *sc_end++ = '\n';
+            *sc_end++ = ' ';
+            if (verbose)    /* print error msg if the line was
+                     * not already broken */
+                diag2(0, "Line broken");
+            }
+            for (t_ptr = token; *t_ptr; ++t_ptr)
+            *sc_end++ = *t_ptr;
+
+        sw_buffer:
+            ps.search_brace = false;    /* stop looking for start of
+                         * stmt */
+            bp_save = buf_ptr;    /* save current input buffer */
+            be_save = buf_end;
+            buf_ptr = save_com;    /* fix so that subsequent calls to
+                     * lexi will take tokens out of
+                     * save_com */
+            *sc_end++ = ' ';/* add trailing blank, just in case */
+            buf_end = sc_end;
+            sc_end = NULL;
+            break;
+        }
+        }            /* end of switch */
+        /*
+         * We must make this check, just in case there was an unexpected
+         * EOF.
+         */
+        if (type_code != 0) {
+        /*
+         * The only intended purpose of calling lexi() below is to
+         * categorize the next token in order to decide whether to
+         * continue buffering forthcoming tokens. Once the buffering
+         * is over, lexi() will be called again elsewhere on all of
+         * the tokens - this time for normal processing.
+         *
+         * Calling it for this purpose is a bug, because lexi() also
+         * changes the parser state and discards leading whitespace,
+         * which is needed mostly for comment-related considerations.
+         *
+         * Work around the former problem by giving lexi() a copy of
+         * the current parser state and discard it if the call turned
+         * out to be just a look ahead.
+         *
+         * Work around the latter problem by copying all whitespace
+         * characters into the buffer so that the later lexi() call
+         * will read them.
+         */
+        if (sc_end != NULL) {
+            while (*buf_ptr == ' ' || *buf_ptr == '\t') {
+            *sc_end++ = *buf_ptr++;
+            if (sc_end >= &save_com[sc_size]) {
+                errx(1, "input too long");
+            }
+            }
+            if (buf_ptr >= buf_end) {
+            fill_buffer();
+            }
+        }
+        transient_state = ps;
+        type_code = lexi(&transient_state);    /* read another token */
+        if (type_code != newline && type_code != form_feed &&
+            type_code != comment && !transient_state.search_brace) {
+            ps = transient_state;
+        }
+        }
+    }            /* end of while (search_brace) */
+    last_else = 0;
+check_type:
+    if (type_code == 0) {    /* we got eof */
+        if (s_lab != e_lab || s_code != e_code
+            || s_com != e_com)    /* must dump end of line */
+        dump_line();
+        if (ps.tos > 1)    /* check for balanced braces */
+        diag2(1, "Stuff missing from end of file");
+
+        if (verbose) {
+        printf("There were %d output lines and %d comments\n",
+               ps.out_lines, ps.out_coms);
+        printf("(Lines with comments)/(Lines with code): %6.3f\n",
+               (1.0 * ps.com_lines) / code_lines);
+        }
+        fflush(output);
+        exit(found_err);
+    }
+    if (
+        (type_code != comment) &&
+        (type_code != newline) &&
+        (type_code != preesc) &&
+        (type_code != form_feed)) {
+        if (force_nl &&
+            (type_code != semicolon) &&
+            (type_code != lbrace || !btype_2)) {
+        /* we should force a broken line here */
+        if (verbose)
+            diag2(0, "Line broken");
+        dump_line();
+        ps.want_blank = false;    /* dont insert blank at line start */
+        force_nl = false;
+        }
+        ps.in_stmt = true;    /* turn on flag which causes an extra level of
+                 * indentation. this is turned off by a ; or
+                 * '}' */
+        if (s_com != e_com) {    /* the turkey has embedded a comment
+                     * in a line. fix it */
+        int len = e_com - s_com;
+
+        CHECK_SIZE_CODE(len + 3);
+        *e_code++ = ' ';
+        memcpy(e_code, s_com, len);
+        e_code += len;
+        *e_code++ = ' ';
+        *e_code = '\0';    /* null terminate code sect */
+        ps.want_blank = false;
+        e_com = s_com;
+        }
+    }
+    else if (type_code != comment)    /* preserve force_nl thru a comment */
+        force_nl = false;    /* cancel forced newline after newline, form
+                 * feed, etc */
+
+
+
+    /*-----------------------------------------------------*\
+    |       do switch on type of token scanned        |
+    \*-----------------------------------------------------*/
+    CHECK_SIZE_CODE(3);    /* maximum number of increments of e_code
+                 * before the next CHECK_SIZE_CODE or
+                 * dump_line() is 2. After that there's the
+                 * final increment for the null character. */
+    switch (type_code) {    /* now, decide what to do with the token */
+
+    case form_feed:    /* found a form feed in line */
+        ps.use_ff = true;    /* a form feed is treated much like a newline */
+        dump_line();
+        ps.want_blank = false;
+        break;
+
+    case newline:
+        if (ps.last_token != comma || ps.p_l_follow > 0
+            || !ps.leave_comma || ps.block_init || !break_comma || s_com != e_com) {
+        dump_line();
+        ps.want_blank = false;
+        }
+        ++line_no;        /* keep track of input line number */
+        break;
+
+    case lparen:        /* got a '(' or '[' */
+        /* count parens to make Healy happy */
+        if (++ps.p_l_follow == nitems(ps.paren_indents)) {
+        diag3(0, "Reached internal limit of %d unclosed parens",
+            nitems(ps.paren_indents));
+        ps.p_l_follow--;
+        }
+        if (*token == '[')
+        /* not a function pointer declaration or a function call */;
+        else if (ps.in_decl && !ps.block_init && !ps.dumped_decl_indent &&
+        ps.procname[0] == '\0' && ps.paren_level == 0) {
+        /* function pointer declarations */
+        indent_declaration(dec_ind, tabs_to_var);
+        ps.dumped_decl_indent = true;
+        }
+        else if (ps.want_blank &&
+            ((ps.last_token != ident && ps.last_token != funcname) ||
+            /* offsetof (1) is never allowed a space; sizeof (2) gets
+             * one iff -bs; all other keywords (>2) always get a space
+             * before lparen */
+            ps.keyword + Bill_Shannon > 2))
+        *e_code++ = ' ';
+        ps.want_blank = false;
+        *e_code++ = token[0];
+        ps.paren_indents[ps.p_l_follow - 1] = count_spaces_until(1, s_code, e_code) - 1;
+        if (sp_sw && ps.p_l_follow == 1 && extra_expression_indent
+            && ps.paren_indents[0] < 2 * ps.ind_size)
+        ps.paren_indents[0] = 2 * ps.ind_size;
+        if (ps.in_or_st && *token == '(' && ps.tos <= 2) {
+        /*
+         * this is a kluge to make sure that declarations will be
+         * aligned right if proc decl has an explicit type on it, i.e.
+         * "int a(x) {..."
+         */
+        parse(semicolon);    /* I said this was a kluge... */
+        ps.in_or_st = false;    /* turn off flag for structure decl or
+                     * initialization */
+        }
+        /*
+         * parenthesized type following sizeof or offsetof is not a cast,
+         * and we assume the same for any other non-keyword identifier,
+         * to support macros that take types
+         */
+        if (ps.last_token == ident &&
+        (ps.keyword == 0 || ps.keyword == 1 || ps.keyword == 2))
+        ps.not_cast_mask |= 1 << ps.p_l_follow;
+        break;
+
+    case rparen:        /* got a ')' or ']' */
+        if (ps.cast_mask & (1 << ps.p_l_follow) & ~ps.not_cast_mask) {
+        ps.last_u_d = true;
+        ps.cast_mask &= (1 << ps.p_l_follow) - 1;
+        ps.want_blank = space_after_cast;
+        } else
+        ps.want_blank = true;
+        ps.not_cast_mask &= (1 << ps.p_l_follow) - 1;
+        if (--ps.p_l_follow < 0) {
+        ps.p_l_follow = 0;
+        diag3(0, "Extra %c", *token);
+        }
+        if (e_code == s_code)    /* if the paren starts the line */
+        ps.paren_level = ps.p_l_follow;    /* then indent it */
+
+        *e_code++ = token[0];
+
+        if (sp_sw && (ps.p_l_follow == 0)) {    /* check for end of if
+                             * (...), or some such */
+        sp_sw = false;
+        force_nl = true;/* must force newline after if */
+        ps.last_u_d = true;    /* inform lexi that a following
+                     * operator is unary */
+        ps.in_stmt = false;    /* dont use stmt continuation
+                     * indentation */
+
+        parse(hd_type);    /* let parser worry about if, or whatever */
+        }
+        ps.search_brace = btype_2;    /* this should insure that constructs
+                     * such as main(){...} and int[]{...}
+                     * have their braces put in the right
+                     * place */
+        break;
+
+    case unary_op:        /* this could be any unary operation */
+        if (!ps.dumped_decl_indent && ps.in_decl && !ps.block_init &&
+        ps.procname[0] == '\0' && ps.paren_level == 0) {
+        /* pointer declarations */
+
+        /*
+         * if this is a unary op in a declaration, we should indent
+         * this token
+         */
+        for (i = 0; token[i]; ++i)
+            /* find length of token */;
+        indent_declaration(dec_ind - i, tabs_to_var);
+        ps.dumped_decl_indent = true;
+        }
+        else if (ps.want_blank)
+        *e_code++ = ' ';
+
+        {
+        int len = e_token - s_token;
+
+        CHECK_SIZE_CODE(len);
+        memcpy(e_code, token, len);
+        e_code += len;
+        }
+        ps.want_blank = false;
+        break;
+
+    case binary_op:    /* any binary operation */
+        {
+        int len = e_token - s_token;
+
+        CHECK_SIZE_CODE(len + 1);
+        if (ps.want_blank)
+            *e_code++ = ' ';
+        memcpy(e_code, token, len);
+        e_code += len;
+        }
+        ps.want_blank = true;
+        break;
+
+    case postop:        /* got a trailing ++ or -- */
+        *e_code++ = token[0];
+        *e_code++ = token[1];
+        ps.want_blank = true;
+        break;
+
+    case question:        /* got a ? */
+        squest++;        /* this will be used when a later colon
+                 * appears so we can distinguish the
+                 * <c>?<n>:<n> construct */
+        if (ps.want_blank)
+        *e_code++ = ' ';
+        *e_code++ = '?';
+        ps.want_blank = true;
+        break;
+
+    case casestmt:        /* got word 'case' or 'default' */
+        scase = true;    /* so we can process the later colon properly */
+        goto copy_id;
+
+    case colon:        /* got a ':' */
+        if (squest > 0) {    /* it is part of the <c>?<n>: <n> construct */
+        --squest;
+        if (ps.want_blank)
+            *e_code++ = ' ';
+        *e_code++ = ':';
+        ps.want_blank = true;
+        break;
+        }
+        if (ps.in_or_st) {
+        *e_code++ = ':';
+        ps.want_blank = false;
+        break;
+        }
+        ps.in_stmt = false;    /* seeing a label does not imply we are in a
+                 * stmt */
+        /*
+         * turn everything so far into a label
+         */
+        {
+        int len = e_code - s_code;
+
+        CHECK_SIZE_LAB(len + 3);
+        memcpy(e_lab, s_code, len);
+        e_lab += len;
+        *e_lab++ = ':';
+        *e_lab = '\0';
+        e_code = s_code;
+        }
+        force_nl = ps.pcase = scase;    /* ps.pcase will be used by
+                         * dump_line to decide how to
+                         * indent the label. force_nl
+                         * will force a case n: to be
+                         * on a line by itself */
+        scase = false;
+        ps.want_blank = false;
+        break;
+
+    case semicolon:    /* got a ';' */
+        if (ps.dec_nest == 0)
+        ps.in_or_st = false;/* we are not in an initialization or
+                     * structure declaration */
+        scase = false;    /* these will only need resetting in an error */
+        squest = 0;
+        if (ps.last_token == rparen)
+        ps.in_parameter_declaration = 0;
+        ps.cast_mask = 0;
+        ps.not_cast_mask = 0;
+        ps.block_init = 0;
+        ps.block_init_level = 0;
+        ps.just_saw_decl--;
+
+        if (ps.in_decl && s_code == e_code && !ps.block_init &&
+        !ps.dumped_decl_indent && ps.paren_level == 0) {
+        /* indent stray semicolons in declarations */
+        indent_declaration(dec_ind - 1, tabs_to_var);
+        ps.dumped_decl_indent = true;
+        }
+
+        ps.in_decl = (ps.dec_nest > 0);    /* if we were in a first level
+                         * structure declaration, we
+                         * arent any more */
+
+        if ((!sp_sw || hd_type != forstmt) && ps.p_l_follow > 0) {
+
+        /*
+         * This should be true iff there were unbalanced parens in the
+         * stmt.  It is a bit complicated, because the semicolon might
+         * be in a for stmt
+         */
+        diag2(1, "Unbalanced parens");
+        ps.p_l_follow = 0;
+        if (sp_sw) {    /* this is a check for an if, while, etc. with
+                 * unbalanced parens */
+            sp_sw = false;
+            parse(hd_type);    /* dont lose the if, or whatever */
+        }
+        }
+        *e_code++ = ';';
+        ps.want_blank = true;
+        ps.in_stmt = (ps.p_l_follow > 0);    /* we are no longer in the
+                         * middle of a stmt */
+
+        if (!sp_sw) {    /* if not if for (;;) */
+        parse(semicolon);    /* let parser know about end of stmt */
+        force_nl = true;/* force newline after an end of stmt */
+        }
+        break;
+
+    case lbrace:        /* got a '{' */
+        ps.in_stmt = false;    /* dont indent the {} */
+        if (!ps.block_init)
+        force_nl = true;/* force other stuff on same line as '{' onto
+                 * new line */
+        else if (ps.block_init_level <= 0)
+        ps.block_init_level = 1;
+        else
+        ps.block_init_level++;
+
+        if (s_code != e_code && !ps.block_init) {
+        if (!btype_2) {
+            dump_line();
+            ps.want_blank = false;
+        }
+        else if (ps.in_parameter_declaration && !ps.in_or_st) {
+            ps.i_l_follow = 0;
+            if (function_brace_split) {    /* dump the line prior to the
+                         * brace ... */
+            dump_line();
+            ps.want_blank = false;
+            } else    /* add a space between the decl and brace */
+            ps.want_blank = true;
+        }
+        }
+        if (ps.in_parameter_declaration)
+        prefix_blankline_requested = 0;
+
+        if (ps.p_l_follow > 0) {    /* check for preceding unbalanced
+                     * parens */
+        diag2(1, "Unbalanced parens");
+        ps.p_l_follow = 0;
+        if (sp_sw) {    /* check for unclosed if, for, etc. */
+            sp_sw = false;
+            parse(hd_type);
+            ps.ind_level = ps.i_l_follow;
+        }
+        }
+        if (s_code == e_code)
+        ps.ind_stmt = false;    /* dont put extra indentation on line
+                     * with '{' */
+        if (ps.in_decl && ps.in_or_st) {    /* this is either a structure
+                         * declaration or an init */
+        di_stack[ps.dec_nest] = dec_ind;
+        if (++ps.dec_nest == nitems(di_stack)) {
+            diag3(0, "Reached internal limit of %d struct levels",
+            nitems(di_stack));
+            ps.dec_nest--;
+        }
+        /* ?        dec_ind = 0; */
+        }
+        else {
+        ps.decl_on_line = false;    /* we can't be in the middle of
+                         * a declaration, so don't do
+                         * special indentation of
+                         * comments */
+        if (blanklines_after_declarations_at_proctop
+            && ps.in_parameter_declaration)
+            postfix_blankline_requested = 1;
+        ps.in_parameter_declaration = 0;
+        ps.in_decl = false;
+        }
+        dec_ind = 0;
+        parse(lbrace);    /* let parser know about this */
+        if (ps.want_blank)    /* put a blank before '{' if '{' is not at
+                 * start of line */
+        *e_code++ = ' ';
+        ps.want_blank = false;
+        *e_code++ = '{';
+        ps.just_saw_decl = 0;
+        break;
+
+    case rbrace:        /* got a '}' */
+        if (ps.p_stack[ps.tos] == decl && !ps.block_init)    /* semicolons can be
+                                 * omitted in
+                                 * declarations */
+        parse(semicolon);
+        if (ps.p_l_follow) {/* check for unclosed if, for, else. */
+        diag2(1, "Unbalanced parens");
+        ps.p_l_follow = 0;
+        sp_sw = false;
+        }
+        ps.just_saw_decl = 0;
+        ps.block_init_level--;
+        if (s_code != e_code && !ps.block_init) {    /* '}' must be first on
+                             * line */
+        if (verbose)
+            diag2(0, "Line broken");
+        dump_line();
+        }
+        *e_code++ = '}';
+        ps.want_blank = true;
+        ps.in_stmt = ps.ind_stmt = false;
+        if (ps.dec_nest > 0) {    /* we are in multi-level structure
+                     * declaration */
+        dec_ind = di_stack[--ps.dec_nest];
+        if (ps.dec_nest == 0 && !ps.in_parameter_declaration)
+            ps.just_saw_decl = 2;
+        ps.in_decl = true;
+        }
+        prefix_blankline_requested = 0;
+        parse(rbrace);    /* let parser know about this */
+        ps.search_brace = cuddle_else && ps.p_stack[ps.tos] == ifhead
+        && ps.il[ps.tos] >= ps.ind_level;
+        if (ps.tos <= 1 && blanklines_after_procs && ps.dec_nest <= 0)
+        postfix_blankline_requested = 1;
+        break;
+
+    case swstmt:        /* got keyword "switch" */
+        sp_sw = true;
+        hd_type = swstmt;    /* keep this for when we have seen the
+                 * expression */
+        goto copy_id;    /* go move the token into buffer */
+
+    case sp_paren:        /* token is if, while, for */
+        sp_sw = true;    /* the interesting stuff is done after the
+                 * expression is scanned */
+        hd_type = (*token == 'i' ? ifstmt :
+               (*token == 'w' ? whilestmt : forstmt));
+
+        /*
+         * remember the type of header for later use by parser
+         */
+        goto copy_id;    /* copy the token into line */
+
+    case sp_nparen:    /* got else, do */
+        ps.in_stmt = false;
+        if (*token == 'e') {
+        if (e_code != s_code && (!cuddle_else || e_code[-1] != '}')) {
+            if (verbose)
+            diag2(0, "Line broken");
+            dump_line();/* make sure this starts a line */
+            ps.want_blank = false;
+        }
+        force_nl = true;/* also, following stuff must go onto new line */
+        last_else = 1;
+        parse(elselit);
+        }
+        else {
+        if (e_code != s_code) {    /* make sure this starts a line */
+            if (verbose)
+            diag2(0, "Line broken");
+            dump_line();
+            ps.want_blank = false;
+        }
+        force_nl = true;/* also, following stuff must go onto new line */
+        last_else = 0;
+        parse(dolit);
+        }
+        goto copy_id;    /* move the token into line */
+
+    case type_def:
+    case storage:
+        prefix_blankline_requested = 0;
+        goto copy_id;
+
+    case structure:
+        if (ps.p_l_follow > 0)
+        goto copy_id;
+        /* FALLTHROUGH */
+    case decl:        /* we have a declaration type (int, etc.) */
+        parse(decl);    /* let parser worry about indentation */
+        if (ps.last_token == rparen && ps.tos <= 1) {
+        if (s_code != e_code) {
+            dump_line();
+            ps.want_blank = 0;
+        }
+        }
+        if (ps.in_parameter_declaration && ps.indent_parameters && ps.dec_nest == 0) {
+        ps.ind_level = ps.i_l_follow = 1;
+        ps.ind_stmt = 0;
+        }
+        ps.in_or_st = true;    /* this might be a structure or initialization
+                 * declaration */
+        ps.in_decl = ps.decl_on_line = true;
+        if ( /* !ps.in_or_st && */ ps.dec_nest <= 0)
+        ps.just_saw_decl = 2;
+        prefix_blankline_requested = 0;
+        for (i = 0; token[i++];);    /* get length of token */
+
+        if (ps.ind_level == 0 || ps.dec_nest > 0) {
+        /* global variable or struct member in local variable */
+        dec_ind = ps.decl_indent > 0 ? ps.decl_indent : i;
+        tabs_to_var = (use_tabs ? ps.decl_indent > 0 : 0);
+        } else {
+        /* local variable */
+        dec_ind = ps.local_decl_indent > 0 ? ps.local_decl_indent : i;
+        tabs_to_var = (use_tabs ? ps.local_decl_indent > 0 : 0);
+        }
+        goto copy_id;
+
+    case funcname:
+    case ident:        /* got an identifier or constant */
+        if (ps.in_decl) {
+        if (type_code == funcname) {
+            ps.in_decl = false;
+            if (procnames_start_line && s_code != e_code) {
+            *e_code = '\0';
+            dump_line();
+            }
+            else if (ps.want_blank) {
+            *e_code++ = ' ';
+            }
+            ps.want_blank = false;
+        }
+        else if (!ps.block_init && !ps.dumped_decl_indent &&
+            ps.paren_level == 0) { /* if we are in a declaration, we
+                        * must indent identifier */
+            indent_declaration(dec_ind, tabs_to_var);
+            ps.dumped_decl_indent = true;
+            ps.want_blank = false;
+        }
+        }
+        else if (sp_sw && ps.p_l_follow == 0) {
+        sp_sw = false;
+        force_nl = true;
+        ps.last_u_d = true;
+        ps.in_stmt = false;
+        parse(hd_type);
+        }
+    copy_id:
+        {
+        int len = e_token - s_token;
+
+        CHECK_SIZE_CODE(len + 1);
+        if (ps.want_blank)
+            *e_code++ = ' ';
+        memcpy(e_code, s_token, len);
+        e_code += len;
+        }
+        if (type_code != funcname)
+        ps.want_blank = true;
+        break;
+
+    case strpfx:
+        {
+        int len = e_token - s_token;
+
+        CHECK_SIZE_CODE(len + 1);
+        if (ps.want_blank)
+            *e_code++ = ' ';
+        memcpy(e_code, token, len);
+        e_code += len;
+        }
+        ps.want_blank = false;
+        break;
+
+    case period:        /* treat a period kind of like a binary
+                 * operation */
+        *e_code++ = '.';    /* move the period into line */
+        ps.want_blank = false;    /* dont put a blank after a period */
+        break;
+
+    case comma:
+        ps.want_blank = (s_code != e_code);    /* only put blank after comma
+                         * if comma does not start the
+                         * line */
+        if (ps.in_decl && ps.procname[0] == '\0' && !ps.block_init &&
+        !ps.dumped_decl_indent && ps.paren_level == 0) {
+        /* indent leading commas and not the actual identifiers */
+        indent_declaration(dec_ind - 1, tabs_to_var);
+        ps.dumped_decl_indent = true;
+        }
+        *e_code++ = ',';
+        if (ps.p_l_follow == 0) {
+        if (ps.block_init_level <= 0)
+            ps.block_init = 0;
+        if (break_comma && (!ps.leave_comma ||
+            count_spaces_until(compute_code_target(), s_code, e_code) >
+            max_col - tabsize))
+            force_nl = true;
+        }
+        break;
+
+    case preesc:        /* got the character '#' */
+        if ((s_com != e_com) ||
+            (s_lab != e_lab) ||
+            (s_code != e_code))
+        dump_line();
+        CHECK_SIZE_LAB(1);
+        *e_lab++ = '#';    /* move whole line to 'label' buffer */
+        {
+        int         in_comment = 0;
+        int         com_start = 0;
+        char        quote = 0;
+        int         com_end = 0;
+
+        while (*buf_ptr == ' ' || *buf_ptr == '\t') {
+            buf_ptr++;
+            if (buf_ptr >= buf_end)
+            fill_buffer();
+        }
+        while (*buf_ptr != '\n' || (in_comment && !had_eof)) {
+            CHECK_SIZE_LAB(2);
+            *e_lab = *buf_ptr++;
+            if (buf_ptr >= buf_end)
+            fill_buffer();
+            switch (*e_lab++) {
+            case BACKSLASH:
+            if (!in_comment) {
+                *e_lab++ = *buf_ptr++;
+                if (buf_ptr >= buf_end)
+                fill_buffer();
+            }
+            break;
+            case '/':
+            if (*buf_ptr == '*' && !in_comment && !quote) {
+                in_comment = 1;
+                *e_lab++ = *buf_ptr++;
+                com_start = e_lab - s_lab - 2;
+            }
+            break;
+            case '"':
+            if (quote == '"')
+                quote = 0;
+            break;
+            case '\'':
+            if (quote == '\'')
+                quote = 0;
+            break;
+            case '*':
+            if (*buf_ptr == '/' && in_comment) {
+                in_comment = 0;
+                *e_lab++ = *buf_ptr++;
+                com_end = e_lab - s_lab;
+            }
+            break;
+            }
+        }
+
+        while (e_lab > s_lab && (e_lab[-1] == ' ' || e_lab[-1] == '\t'))
+            e_lab--;
+        if (e_lab - s_lab == com_end && bp_save == NULL) {
+            /* comment on preprocessor line */
+            if (sc_end == NULL) {    /* if this is the first comment,
+                         * we must set up the buffer */
+            save_com = sc_buf;
+            sc_end = &save_com[0];
+            }
+            else {
+            *sc_end++ = '\n';    /* add newline between
+                         * comments */
+            *sc_end++ = ' ';
+            --line_no;
+            }
+            if (sc_end - save_com + com_end - com_start > sc_size)
+            errx(1, "input too long");
+            memmove(sc_end, s_lab + com_start, com_end - com_start);
+            sc_end += com_end - com_start;
+            e_lab = s_lab + com_start;
+            while (e_lab > s_lab && (e_lab[-1] == ' ' || e_lab[-1] == '\t'))
+            e_lab--;
+            bp_save = buf_ptr;    /* save current input buffer */
+            be_save = buf_end;
+            buf_ptr = save_com;    /* fix so that subsequent calls to
+                     * lexi will take tokens out of
+                     * save_com */
+            *sc_end++ = ' ';    /* add trailing blank, just in case */
+            buf_end = sc_end;
+            sc_end = NULL;
+        }
+        CHECK_SIZE_LAB(1);
+        *e_lab = '\0';    /* null terminate line */
+        ps.pcase = false;
+        }
+
+        if (strncmp(s_lab, "#if", 3) == 0) { /* also ifdef, ifndef */
+        if ((size_t)ifdef_level < nitems(state_stack)) {
+            match_state[ifdef_level].tos = -1;
+            state_stack[ifdef_level++] = ps;
+        }
+        else
+            diag2(1, "#if stack overflow");
+        }
+        else if (strncmp(s_lab, "#el", 3) == 0) { /* else, elif */
+        if (ifdef_level <= 0)
+            diag2(1, s_lab[3] == 'i' ? "Unmatched #elif" : "Unmatched #else");
+        else {
+            match_state[ifdef_level - 1] = ps;
+            ps = state_stack[ifdef_level - 1];
+        }
+        }
+        else if (strncmp(s_lab, "#endif", 6) == 0) {
+        if (ifdef_level <= 0)
+            diag2(1, "Unmatched #endif");
+        else
+            ifdef_level--;
+        } else {
+        struct directives {
+            int size;
+            const char *string;
+        }
+        recognized[] = {
+            {7, "include"},
+            {6, "define"},
+            {5, "undef"},
+            {4, "line"},
+            {5, "error"},
+            {6, "pragma"}
+        };
+        int d = nitems(recognized);
+        while (--d >= 0)
+            if (strncmp(s_lab + 1, recognized[d].string, recognized[d].size) == 0)
+            break;
+        if (d < 0) {
+            diag2(1, "Unrecognized cpp directive");
+            break;
+        }
+        }
+        if (blanklines_around_conditional_compilation) {
+        postfix_blankline_requested++;
+        n_real_blanklines = 0;
+        }
+        else {
+        postfix_blankline_requested = 0;
+        prefix_blankline_requested = 0;
+        }
+        break;        /* subsequent processing of the newline
+                 * character will cause the line to be printed */
+
+    case comment:        /* we have gotten a / followed by * this is a biggie */
+        pr_comment();
+        break;
+    }            /* end of big switch stmt */
+
+    *e_code = '\0';        /* make sure code section is null terminated */
+    if (type_code != comment && type_code != newline && type_code != preesc)
+        ps.last_token = type_code;
+    }                /* end of main while (1) loop */
+}
+
+/*
+ * copy input file to backup file if in_name is /blah/blah/blah/file, then
+ * backup file will be ".Bfile" then make the backup file the input and
+ * original input file the output
+ */
+static void
+bakcopy(void)
+{
+    int         n,
+                bakchn;
+    char        buff[8 * 1024];
+    const char *p;
+
+    /* construct file name .Bfile */
+    for (p = in_name; *p; p++);    /* skip to end of string */
+    while (p > in_name && *p != '/')    /* find last '/' */
+    p--;
+    if (*p == '/')
+    p++;
+    sprintf(bakfile, "%s.BAK", p);
+
+    /* copy in_name to backup file */
+    bakchn = creat(bakfile, 0600);
+    if (bakchn < 0)
+    err(1, "%s", bakfile);
+    while ((n = read(fileno(input), buff, sizeof(buff))) > 0)
+    if (write(bakchn, buff, n) != n)
+        err(1, "%s", bakfile);
+    if (n < 0)
+    err(1, "%s", in_name);
+    close(bakchn);
+    fclose(input);
+
+    /* re-open backup file as the input file */
+    input = fopen(bakfile, "r");
+    if (input == NULL)
+    err(1, "%s", bakfile);
+    /* now the original input file will be the output */
+    output = fopen(in_name, "w");
+    if (output == NULL) {
+    unlink(bakfile);
+    err(1, "%s", in_name);
+    }
+}
+
+static void
+indent_declaration(int cur_dec_ind, int tabs_to_var)
+{
+    int pos = e_code - s_code;
+    char *startpos = e_code;
+
+    /*
+     * get the tab math right for indentations that are not multiples of tabsize
+     */
+    if ((ps.ind_level * ps.ind_size) % tabsize != 0) {
+    pos += (ps.ind_level * ps.ind_size) % tabsize;
+    cur_dec_ind += (ps.ind_level * ps.ind_size) % tabsize;
+    }
+    if (tabs_to_var) {
+    int tpos;
+
+    CHECK_SIZE_CODE(cur_dec_ind / tabsize);
+    while ((tpos = tabsize * (1 + pos / tabsize)) <= cur_dec_ind) {
+        *e_code++ = (!postgres_tab_rules ||
+             tpos != pos + 1 ||
+             cur_dec_ind >= tpos + tabsize) ? '\t' : ' ';
+        pos = tpos;
+    }
+    }
+    CHECK_SIZE_CODE(cur_dec_ind - pos + 1);
+    while (pos < cur_dec_ind) {
+    *e_code++ = ' ';
+    pos++;
+    }
+    if (e_code == startpos && ps.want_blank) {
+    *e_code++ = ' ';
+    ps.want_blank = false;
+    }
+}
diff --git a/src/tools/pg_bsd_indent/indent.h b/src/tools/pg_bsd_indent/indent.h
new file mode 100644
index 0000000000..1708dbc19f
--- /dev/null
+++ b/src/tools/pg_bsd_indent/indent.h
@@ -0,0 +1,51 @@
+/*-
+ * Copyright (c) 2001 Jens Schweikhardt
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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.
+ */
+
+#if 0
+__FBSDID("$FreeBSD: head/usr.bin/indent/indent.h 303746 2016-08-04 15:27:09Z pfg $");
+#endif
+
+#define nitems(array) (sizeof (array) / sizeof (array[0]))
+
+void    add_typename(const char *);
+void    alloc_typenames(void);
+int    compute_code_target(void);
+int    compute_label_target(void);
+int    count_spaces(int, char *);
+int    count_spaces_until(int, char *, char *);
+int    lexi(struct parser_state *);
+void    diag2(int, const char *);
+void    diag3(int, const char *, int);
+void    diag4(int, const char *, int, int);
+void    dump_line(void);
+int    lookahead(void);
+void    lookahead_reset(void);
+void    fill_buffer(void);
+void    parse(int);
+void    pr_comment(void);
+void    set_defaults(void);
+void    set_option(char *);
+void    set_profile(const char *);
diff --git a/src/tools/pg_bsd_indent/indent_codes.h b/src/tools/pg_bsd_indent/indent_codes.h
new file mode 100644
index 0000000000..24c43fa420
--- /dev/null
+++ b/src/tools/pg_bsd_indent/indent_codes.h
@@ -0,0 +1,75 @@
+/*-
+ * Copyright (c) 1985 Sun Microsystems, Inc.
+ * Copyright (c) 1980, 1993
+ *    The Regents of the University of California.  All rights reserved.
+ * 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. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *    This product includes software developed by the University of
+ *    California, Berkeley and its contributors.
+ * 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.
+ *
+ *    @(#)indent_codes.h    8.1 (Berkeley) 6/6/93
+ * $FreeBSD: head/usr.bin/indent/indent_codes.h 309380 2016-12-02 01:25:51Z pfg $
+ */
+
+#define newline        1
+#define lparen        2
+#define rparen        3
+#define unary_op    4
+#define binary_op    5
+#define postop        6
+#define question    7
+#define casestmt    8
+#define colon        9
+#define semicolon    10
+#define lbrace        11
+#define rbrace        12
+#define ident        13
+#define comma        14
+#define comment        15
+#define swstmt        16
+#define preesc        17
+#define form_feed    18
+#define decl        19
+#define sp_paren    20
+#define sp_nparen    21
+#define ifstmt        22
+#define whilestmt    23
+#define forstmt        24
+#define stmt        25
+#define stmtl        26
+#define elselit        27
+#define dolit        28
+#define dohead        29
+#define ifhead        30
+#define elsehead    31
+#define period        32
+#define strpfx        33
+#define storage        34
+#define funcname    35
+#define type_def    36
+#define structure    37
diff --git a/src/tools/pg_bsd_indent/indent_globs.h b/src/tools/pg_bsd_indent/indent_globs.h
new file mode 100644
index 0000000000..398784b3f4
--- /dev/null
+++ b/src/tools/pg_bsd_indent/indent_globs.h
@@ -0,0 +1,343 @@
+/*-
+ * Copyright (c) 1985 Sun Microsystems, Inc.
+ * Copyright (c) 1980, 1993
+ *    The Regents of the University of California.  All rights reserved.
+ * 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. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *    This product includes software developed by the University of
+ *    California, Berkeley and its contributors.
+ * 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.
+ *
+ *    @(#)indent_globs.h    8.1 (Berkeley) 6/6/93
+ * $FreeBSD: head/usr.bin/indent/indent_globs.h 303735 2016-08-03 22:08:07Z pfg $
+ */
+
+#define BACKSLASH '\\'
+#define bufsize 200        /* size of internal buffers */
+#define sc_size 5000        /* size of save_com buffer */
+#define label_offset 2        /* number of levels a label is placed to left
+                 * of code */
+
+
+#ifndef false
+#define false 0
+#endif
+#ifndef true
+#define true  1
+#endif
+
+/*
+ * Exactly one calling file should define this symbol.  The global variables
+ * will be defined in that file, and just referenced elsewhere.
+ */
+#ifdef DECLARE_INDENT_GLOBALS
+#define extern
+#endif
+
+extern FILE *input;        /* the fid for the input file */
+extern FILE *output;        /* the output file */
+
+#define CHECK_SIZE_CODE(desired_size) \
+    if (e_code + (desired_size) >= l_code) { \
+        int nsize = l_code-s_code + 400 + desired_size; \
+        int code_len = e_code-s_code; \
+        codebuf = (char *) realloc(codebuf, nsize); \
+        if (codebuf == NULL) \
+        err(1, NULL); \
+        e_code = codebuf + code_len + 1; \
+        l_code = codebuf + nsize - 5; \
+        s_code = codebuf + 1; \
+    }
+#define CHECK_SIZE_COM(desired_size) \
+    if (e_com + (desired_size) >= l_com) { \
+        int nsize = l_com-s_com + 400 + desired_size; \
+        int com_len = e_com - s_com; \
+        int blank_pos; \
+        if (last_bl != NULL) \
+        blank_pos = last_bl - combuf; \
+        else \
+        blank_pos = -1; \
+        combuf = (char *) realloc(combuf, nsize); \
+        if (combuf == NULL) \
+        err(1, NULL); \
+        e_com = combuf + com_len + 1; \
+        if (blank_pos > 0) \
+        last_bl = combuf + blank_pos; \
+        l_com = combuf + nsize - 5; \
+        s_com = combuf + 1; \
+    }
+#define CHECK_SIZE_LAB(desired_size) \
+    if (e_lab + (desired_size) >= l_lab) { \
+        int nsize = l_lab-s_lab + 400 + desired_size; \
+        int label_len = e_lab - s_lab; \
+        labbuf = (char *) realloc(labbuf, nsize); \
+        if (labbuf == NULL) \
+        err(1, NULL); \
+        e_lab = labbuf + label_len + 1; \
+        l_lab = labbuf + nsize - 5; \
+        s_lab = labbuf + 1; \
+    }
+#define CHECK_SIZE_TOKEN(desired_size) \
+    if (e_token + (desired_size) >= l_token) { \
+        int nsize = l_token-s_token + 400 + desired_size; \
+        int token_len = e_token - s_token; \
+        tokenbuf = (char *) realloc(tokenbuf, nsize); \
+        if (tokenbuf == NULL) \
+        err(1, NULL); \
+        e_token = tokenbuf + token_len + 1; \
+        l_token = tokenbuf + nsize - 5; \
+        s_token = tokenbuf + 1; \
+    }
+
+extern char *labbuf;        /* buffer for label */
+extern char *s_lab;        /* start ... */
+extern char *e_lab;        /* .. and end of stored label */
+extern char *l_lab;        /* limit of label buffer */
+
+extern char *codebuf;        /* buffer for code section */
+extern char *s_code;        /* start ... */
+extern char *e_code;        /* .. and end of stored code */
+extern char *l_code;        /* limit of code section */
+
+extern char *combuf;        /* buffer for comments */
+extern char *s_com;        /* start ... */
+extern char *e_com;        /* ... and end of stored comments */
+extern char *l_com;        /* limit of comment buffer */
+
+#define token s_token
+extern char *tokenbuf;        /* the last token scanned */
+extern char *s_token;
+extern char *e_token;
+extern char *l_token;
+
+extern char *in_buffer;        /* input buffer */
+extern char *in_buffer_limit;    /* the end of the input buffer */
+extern char *buf_ptr;        /* ptr to next character to be taken from
+                 * in_buffer */
+extern char *buf_end;        /* ptr to first after last char in in_buffer */
+
+extern char  sc_buf[sc_size];    /* input text is saved here when looking for
+                 * the brace after an if, while, etc */
+extern char *save_com;        /* start of the comment stored in sc_buf */
+extern char *sc_end;        /* pointer into save_com buffer */
+
+extern char *bp_save;        /* saved value of buf_ptr when taking input
+                 * from save_com */
+extern char *be_save;        /* similarly saved value of buf_end */
+
+
+extern int   found_err;
+extern int   blanklines_after_declarations;
+extern int   blanklines_before_blockcomments;
+extern int   blanklines_after_procs;
+extern int   blanklines_around_conditional_compilation;
+extern int   swallow_optional_blanklines;
+extern int   n_real_blanklines;
+extern int   prefix_blankline_requested;
+extern int   postfix_blankline_requested;
+extern int   break_comma;    /* when true and not in parens, break after a
+                 * comma */
+extern int   btype_2;        /* when true, brace should be on same line as
+                 * if, while, etc */
+extern float case_ind;        /* indentation level to be used for a "case
+                 * n:" */
+extern int   code_lines;    /* count of lines with code */
+extern int   had_eof;        /* set to true when input is exhausted */
+extern int   line_no;        /* the current line number. */
+extern int   max_col;        /* the maximum allowable line length */
+extern int   verbose;        /* when true, non-essential error messages are
+                 * printed */
+extern int   cuddle_else;    /* true if else should cuddle up to '}' */
+extern int   star_comment_cont;    /* true iff comment continuation lines should
+                 * have stars at the beginning of each line. */
+extern int   comment_delimiter_on_blankline;
+extern int   troff;        /* true iff were generating troff input */
+extern int   procnames_start_line;    /* if true, the names of procedures
+                     * being defined get placed in column
+                     * 1 (ie. a newline is placed between
+                     * the type of the procedure and its
+                     * name) */
+extern int   proc_calls_space;    /* If true, procedure calls look like:
+                 * foo(bar) rather than foo (bar) */
+extern int   format_block_comments;    /* true if comments beginning with
+                     * `/ * \n' are to be reformatted */
+extern int   format_col1_comments;    /* If comments which start in column 1
+                     * are to be magically reformatted
+                     * (just like comments that begin in
+                     * later columns) */
+extern int   inhibit_formatting;    /* true if INDENT OFF is in effect */
+extern int   suppress_blanklines;/* set iff following blanklines should be
+                 * suppressed */
+extern int   continuation_indent;/* set to the indentation between the edge of
+                 * code and continuation lines */
+extern int   lineup_to_parens;    /* if true, continued code within parens will
+                 * be lined up to the open paren */
+extern int   lineup_to_parens_always;    /* if true, do not attempt to keep
+                     * lined-up code within the margin */
+extern int   Bill_Shannon;    /* true iff a blank should always be inserted
+                 * after sizeof */
+extern int   blanklines_after_declarations_at_proctop;    /* This is vaguely
+                             * similar to
+                             * blanklines_after_decla
+                             * rations except that
+                             * it only applies to
+                             * the first set of
+                             * declarations in a
+                             * procedure (just after
+                             * the first '{') and it
+                             * causes a blank line
+                             * to be generated even
+                             * if there are no
+                             * declarations */
+extern int   block_comment_max_col;
+extern int   extra_expression_indent;    /* true if continuation lines from the
+                     * expression part of "if(e)",
+                     * "while(e)", "for(e;e;e)" should be
+                     * indented an extra tab stop so that
+                     * they don't conflict with the code
+                     * that follows */
+extern int   function_brace_split;    /* split function declaration and
+                     * brace onto separate lines */
+extern int   use_tabs;            /* set true to use tabs for spacing,
+                     * false uses all spaces */
+extern int   auto_typedefs;        /* set true to recognize identifiers
+                     * ending in "_t" like typedefs */
+extern int   space_after_cast;        /* "b = (int) a" vs "b = (int)a" */
+extern int   postgres_tab_rules;    /* use Postgres tab-vs-space rules */
+extern int   tabsize;            /* the size of a tab */
+extern int   else_endif_com_ind;    /* the column in which comments to
+                     * the right of #else and #endif
+                     * should start */
+
+extern int   ifdef_level;
+
+struct parser_state {
+    int         last_token;
+    int         p_stack[256];    /* this is the parsers stack */
+    int         il[64];        /* this stack stores indentation levels */
+    float       cstk[32];    /* used to store case stmt indentation levels */
+    int         box_com;    /* set to true when we are in a "boxed"
+                 * comment. In that case, the first non-blank
+                 * char should be lined up with the / in / followed by * */
+    int         comment_delta;    /* used to set up indentation for all lines
+                 * of a boxed comment after the first one */
+    int         n_comment_delta;/* remembers how many columns there were
+                 * before the start of a box comment so that
+                 * forthcoming lines of the comment are
+                 * indented properly */
+    int         cast_mask;    /* indicates which close parens potentially
+                 * close off casts */
+    int         not_cast_mask;    /* indicates which close parens definitely
+                 * close off something else than casts */
+    int         block_init;    /* true iff inside a block initialization */
+    int         block_init_level;    /* The level of brace nesting in an
+                     * initialization */
+    int         last_nl;    /* this is true if the last thing scanned was
+                 * a newline */
+    int         in_or_st;    /* Will be true iff there has been a
+                 * declarator (e.g. int or char) and no left
+                 * paren since the last semicolon. When true,
+                 * a '{' is starting a structure definition or
+                 * an initialization list */
+    int         bl_line;    /* set to 1 by dump_line if the line is blank */
+    int         col_1;        /* set to true if the last token started in
+                 * column 1 */
+    int         com_col;    /* this is the column in which the current
+                 * comment should start */
+    int         com_ind;    /* the column in which comments to the right
+                 * of code should start */
+    int         com_lines;    /* the number of lines with comments, set by
+                 * dump_line */
+    int         dec_nest;    /* current nesting level for structure or init */
+    int         decl_com_ind;    /* the column in which comments after
+                 * declarations should be put */
+    int         decl_on_line;    /* set to true if this line of code has part
+                 * of a declaration on it */
+    int         i_l_follow;    /* the level to which ind_level should be set
+                 * after the current line is printed */
+    int         in_decl;    /* set to true when we are in a declaration
+                 * stmt.  The processing of braces is then
+                 * slightly different */
+    int         in_stmt;    /* set to 1 while in a stmt */
+    int         ind_level;    /* the current indentation level */
+    int         ind_size;    /* the size of one indentation level */
+    int         ind_stmt;    /* set to 1 if next line should have an extra
+                 * indentation level because we are in the
+                 * middle of a stmt */
+    int         last_u_d;    /* set to true after scanning a token which
+                 * forces a following operator to be unary */
+    int         leave_comma;    /* if true, never break declarations after
+                 * commas */
+    int         ljust_decl;    /* true if declarations should be left
+                 * justified */
+    int         out_coms;    /* the number of comments processed, set by
+                 * pr_comment */
+    int         out_lines;    /* the number of lines written, set by
+                 * dump_line */
+    int         p_l_follow;    /* used to remember how to indent following
+                 * statement */
+    int         paren_level;    /* parenthesization level. used to indent
+                 * within statements */
+    short       paren_indents[20];    /* column positions of each paren */
+    int         pcase;        /* set to 1 if the current line label is a
+                 * case.  It is printed differently from a
+                 * regular label */
+    int         search_brace;    /* set to true by parse when it is necessary
+                 * to buffer up all info up to the start of a
+                 * stmt after an if, while, etc */
+    int         unindent_displace;    /* comments not to the right of code
+                     * will be placed this many
+                     * indentation levels to the left of
+                     * code */
+    int         use_ff;        /* set to one if the current line should be
+                 * terminated with a form feed */
+    int         want_blank;    /* set to true when the following token should
+                 * be prefixed by a blank. (Said prefixing is
+                 * ignored in some cases.) */
+    int         else_if;    /* True iff else if pairs should be handled
+                 * specially */
+    int         decl_indent;    /* column to indent declared identifiers to */
+    int         local_decl_indent;    /* like decl_indent but for locals */
+    int         keyword;    /* the type of a keyword or 0 */
+    int         dumped_decl_indent;
+    float       case_indent;    /* The distance to indent case labels from the
+                 * switch statement */
+    int         in_parameter_declaration;
+    int         indent_parameters;
+    int         tos;        /* pointer to top of stack */
+    char        procname[100];    /* The name of the current procedure */
+    int         just_saw_decl;
+};
+
+extern struct parser_state ps;
+extern struct parser_state state_stack[5];
+extern struct parser_state match_state[5];
+
+/* Undo previous hackery */
+#ifdef DECLARE_INDENT_GLOBALS
+#undef extern
+#endif
diff --git a/src/tools/pg_bsd_indent/io.c b/src/tools/pg_bsd_indent/io.c
new file mode 100644
index 0000000000..3ce8bfb70c
--- /dev/null
+++ b/src/tools/pg_bsd_indent/io.c
@@ -0,0 +1,608 @@
+/*-
+ * Copyright (c) 1985 Sun Microsystems, Inc.
+ * Copyright (c) 1980, 1993
+ *    The Regents of the University of California.  All rights reserved.
+ * 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. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *    This product includes software developed by the University of
+ *    California, Berkeley and its contributors.
+ * 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.
+ */
+
+#if 0
+#ifndef lint
+static char sccsid[] = "@(#)io.c    8.1 (Berkeley) 6/6/93";
+#endif /* not lint */
+#endif
+
+#include "c.h"
+
+#include <ctype.h>
+#include <err.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "indent_globs.h"
+#include "indent.h"
+
+int         comment_open;
+static int  paren_target;
+
+static char *lookahead_buf;    /* malloc'd buffer, or NULL initially */
+static char *lookahead_buf_end;    /* end+1 of allocated space */
+static char *lookahead_start;    /* => next char for fill_buffer() to fetch */
+static char *lookahead_ptr;    /* => next char for lookahead() to fetch */
+static char *lookahead_end;    /* last+1 valid char in lookahead_buf */
+static char *lookahead_bp_save;    /* lookahead position in bp_save, if any */
+
+static int pad_output(int current, int target);
+
+void
+dump_line(void)
+{                /* dump_line is the routine that actually
+                 * effects the printing of the new source. It
+                 * prints the label section, followed by the
+                 * code section with the appropriate nesting
+                 * level, followed by any comments */
+    int cur_col,
+                target_col = 1;
+    static int  not_first_line;
+
+    if (ps.procname[0]) {
+    ps.ind_level = 0;
+    ps.procname[0] = 0;
+    }
+    if (s_code == e_code && s_lab == e_lab && s_com == e_com) {
+    if (suppress_blanklines > 0)
+        suppress_blanklines--;
+    else {
+        ps.bl_line = true;
+        n_real_blanklines++;
+    }
+    }
+    else if (!inhibit_formatting) {
+    suppress_blanklines = 0;
+    ps.bl_line = false;
+    if (prefix_blankline_requested && not_first_line) {
+        if (swallow_optional_blanklines) {
+        if (n_real_blanklines == 1)
+            n_real_blanklines = 0;
+        }
+        else {
+        if (n_real_blanklines == 0)
+            n_real_blanklines = 1;
+        }
+    }
+    while (--n_real_blanklines >= 0)
+        putc('\n', output);
+    n_real_blanklines = 0;
+    if (ps.ind_level == 0)
+        ps.ind_stmt = 0;    /* this is a class A kludge. dont do
+                 * additional statement indentation if we are
+                 * at bracket level 0 */
+
+    if (e_lab != s_lab || e_code != s_code)
+        ++code_lines;    /* keep count of lines with code */
+
+
+    if (e_lab != s_lab) {    /* print lab, if any */
+        if (comment_open) {
+        comment_open = 0;
+        fprintf(output, ".*/\n");
+        }
+        while (e_lab > s_lab && (e_lab[-1] == ' ' || e_lab[-1] == '\t'))
+        e_lab--;
+        *e_lab = '\0';
+        cur_col = pad_output(1, compute_label_target());
+        if (s_lab[0] == '#' && (strncmp(s_lab, "#else", 5) == 0
+                    || strncmp(s_lab, "#endif", 6) == 0)) {
+        char *s = s_lab;
+        if (e_lab[-1] == '\n') e_lab--;
+        do putc(*s++, output);
+        while (s < e_lab && 'a' <= *s && *s<='z');
+        while ((*s == ' ' || *s == '\t') && s < e_lab)
+            s++;
+        if (s < e_lab)
+            fprintf(output, s[0]=='/' && s[1]=='*' ? "\t%.*s" : "\t/* %.*s */",
+                (int)(e_lab - s), s);
+        }
+        else fprintf(output, "%.*s", (int)(e_lab - s_lab), s_lab);
+        cur_col = count_spaces(cur_col, s_lab);
+    }
+    else
+        cur_col = 1;    /* there is no label section */
+
+    ps.pcase = false;
+
+    if (s_code != e_code) {    /* print code section, if any */
+        char *p;
+
+        if (comment_open) {
+        comment_open = 0;
+        fprintf(output, ".*/\n");
+        }
+        target_col = compute_code_target();
+        {
+        int i;
+
+        for (i = 0; i < ps.p_l_follow; i++)
+            if (ps.paren_indents[i] >= 0)
+            ps.paren_indents[i] = -(ps.paren_indents[i] + target_col);
+        }
+        cur_col = pad_output(cur_col, target_col);
+        for (p = s_code; p < e_code; p++)
+        if (*p == (char) 0200)
+            fprintf(output, "%d", target_col * 7);
+        else
+            putc(*p, output);
+        cur_col = count_spaces(cur_col, s_code);
+    }
+    if (s_com != e_com) {        /* print comment, if any */
+        int target = ps.com_col;
+        char *com_st = s_com;
+
+        target += ps.comment_delta;
+        while (*com_st == '\t')    /* consider original indentation in
+                     * case this is a box comment */
+        com_st++, target += tabsize;
+        while (target <= 0)
+        if (*com_st == ' ')
+            target++, com_st++;
+        else if (*com_st == '\t')
+            target = tabsize * (1 + (target - 1) / tabsize) + 1, com_st++;
+        else
+            target = 1;
+        if (cur_col > target) {    /* if comment can't fit on this line,
+                     * put it on next line */
+        putc('\n', output);
+        cur_col = 1;
+        ++ps.out_lines;
+        }
+        while (e_com > com_st && isspace((unsigned char)e_com[-1]))
+        e_com--;
+        (void)pad_output(cur_col, target);
+        fwrite(com_st, e_com - com_st, 1, output);
+        ps.comment_delta = ps.n_comment_delta;
+        ++ps.com_lines;    /* count lines with comments */
+    }
+    if (ps.use_ff)
+        putc('\014', output);
+    else
+        putc('\n', output);
+    ++ps.out_lines;
+    if (ps.just_saw_decl == 1 && blanklines_after_declarations) {
+        prefix_blankline_requested = 1;
+        ps.just_saw_decl = 0;
+    }
+    else
+        prefix_blankline_requested = postfix_blankline_requested;
+    postfix_blankline_requested = 0;
+    }
+    ps.decl_on_line = ps.in_decl;    /* if we are in the middle of a
+                     * declaration, remember that fact for
+                     * proper comment indentation */
+    ps.ind_stmt = ps.in_stmt & ~ps.in_decl;    /* next line should be
+                         * indented if we have not
+                         * completed this stmt and if
+                         * we are not in the middle of
+                         * a declaration */
+    ps.use_ff = false;
+    ps.dumped_decl_indent = 0;
+    *(e_lab = s_lab) = '\0';    /* reset buffers */
+    *(e_code = s_code) = '\0';
+    *(e_com = s_com = combuf + 1) = '\0';
+    ps.ind_level = ps.i_l_follow;
+    ps.paren_level = ps.p_l_follow;
+    if (ps.paren_level > 0)
+    paren_target = -ps.paren_indents[ps.paren_level - 1];
+    not_first_line = 1;
+}
+
+int
+compute_code_target(void)
+{
+    int target_col = ps.ind_size * ps.ind_level + 1;
+
+    if (ps.paren_level)
+    if (!lineup_to_parens)
+        target_col += continuation_indent
+        * (2 * continuation_indent == ps.ind_size ? 1 : ps.paren_level);
+    else if (lineup_to_parens_always)
+        target_col = paren_target;
+    else {
+        int w;
+        int t = paren_target;
+
+        if ((w = count_spaces(t, s_code) - max_col) > 0
+            && count_spaces(target_col, s_code) <= max_col) {
+        t -= w + 1;
+        if (t > target_col)
+            target_col = t;
+        }
+        else
+        target_col = t;
+    }
+    else if (ps.ind_stmt)
+    target_col += continuation_indent;
+    return target_col;
+}
+
+int
+compute_label_target(void)
+{
+    return
+    ps.pcase ? (int) (case_ind * ps.ind_size) + 1
+    : *s_lab == '#' ? 1
+    : ps.ind_size * (ps.ind_level - label_offset) + 1;
+}
+
+/*
+ * Read data ahead of what has been collected into in_buffer.
+ *
+ * Successive calls get further and further ahead, until we hit EOF.
+ * Call lookahead_reset() to rescan from just beyond in_buffer.
+ *
+ * Lookahead is automatically reset whenever fill_buffer() reads beyond
+ * the lookahead buffer, i.e., you can't use this for "look behind".
+ *
+ * The standard pattern for potentially multi-line lookahead is to call
+ * lookahead_reset(), then enter a loop that scans forward from buf_ptr
+ * to buf_end, then (if necessary) calls lookahead() to read additional
+ * characters from beyond the end of the current line.
+ */
+int
+lookahead(void)
+{
+    /* First read whatever's in bp_save area */
+    if (lookahead_bp_save != NULL && lookahead_bp_save < be_save)
+    return (unsigned char) *lookahead_bp_save++;
+    /* Else, we have to examine and probably fill the main lookahead buffer */
+    while (lookahead_ptr >= lookahead_end) {
+    int        i = getc(input);
+
+    if (i == EOF)
+        return i;
+    if (i == '\0')
+        continue;        /* fill_buffer drops nulls, and so do we */
+
+    if (lookahead_end >= lookahead_buf_end) {
+        /* Need to allocate or enlarge lookahead_buf */
+        char       *new_buf;
+        size_t    req;
+
+        if (lookahead_buf == NULL) {
+        req = 64;
+        new_buf = malloc(req);
+        } else {
+        req = (lookahead_buf_end - lookahead_buf) * 2;
+        new_buf = realloc(lookahead_buf, req);
+        }
+        if (new_buf == NULL)
+        errx(1, "too much lookahead required");
+        lookahead_start = new_buf + (lookahead_start - lookahead_buf);
+        lookahead_ptr = new_buf + (lookahead_ptr - lookahead_buf);
+        lookahead_end = new_buf + (lookahead_end - lookahead_buf);
+        lookahead_buf = new_buf;
+        lookahead_buf_end = new_buf + req;
+    }
+
+    *lookahead_end++ = i;
+    }
+    return (unsigned char) *lookahead_ptr++;
+}
+
+/*
+ * Reset so that lookahead() will again scan from just beyond what's in
+ * in_buffer.
+ */
+void
+lookahead_reset(void)
+{
+    /* Reset the main lookahead buffer */
+    lookahead_ptr = lookahead_start;
+    /* If bp_save isn't NULL, we need to scan that first */
+    lookahead_bp_save = bp_save;
+}
+
+/*
+ * Copyright (C) 1976 by the Board of Trustees of the University of Illinois
+ *
+ * All rights reserved
+ *
+ *
+ * NAME: fill_buffer
+ *
+ * FUNCTION: Reads one line of input into in_buffer,
+ * sets up buf_ptr and buf_end to point to the line's start and end+1.
+ * (Note that the buffer does not get null-terminated.)
+ *
+ * HISTORY: initial coding     November 1976    D A Willcox of CAC 1/7/77 A
+ * Willcox of CAC    Added check for switch back to partly full input
+ * buffer from temporary buffer
+ *
+ */
+void
+fill_buffer(void)
+{                /* this routine reads stuff from the input */
+    char *p;
+    int i;
+    FILE *f = input;
+
+    if (bp_save != NULL) {    /* there is a partly filled input buffer left */
+    buf_ptr = bp_save;    /* do not read anything, just switch buffers */
+    buf_end = be_save;
+    bp_save = be_save = NULL;
+    lookahead_bp_save = NULL;
+    if (buf_ptr < buf_end)
+        return;        /* only return if there is really something in
+                 * this buffer */
+    }
+    for (p = in_buffer;;) {
+    if (p >= in_buffer_limit) {
+        int size = (in_buffer_limit - in_buffer) * 2 + 10;
+        int offset = p - in_buffer;
+        in_buffer = realloc(in_buffer, size);
+        if (in_buffer == NULL)
+        errx(1, "input line too long");
+        p = in_buffer + offset;
+        in_buffer_limit = in_buffer + size - 2;
+    }
+    if (lookahead_start < lookahead_end) {
+        i = (unsigned char) *lookahead_start++;
+    } else {
+        lookahead_start = lookahead_ptr = lookahead_end = lookahead_buf;
+        if ((i = getc(f)) == EOF) {
+        *p++ = ' ';
+        *p++ = '\n';
+        had_eof = true;
+        break;
+        }
+    }
+    if (i != '\0')
+        *p++ = i;
+    if (i == '\n')
+        break;
+    }
+    buf_ptr = in_buffer;
+    buf_end = p;
+    if (p - in_buffer > 2 && p[-2] == '/' && p[-3] == '*') {
+    if (in_buffer[3] == 'I' && strncmp(in_buffer, "/**INDENT**", 11) == 0)
+        fill_buffer();    /* flush indent error message */
+    else {
+        int         com = 0;
+
+        p = in_buffer;
+        while (*p == ' ' || *p == '\t')
+        p++;
+        if (*p == '/' && p[1] == '*') {
+        p += 2;
+        while (*p == ' ' || *p == '\t')
+            p++;
+        if (p[0] == 'I' && p[1] == 'N' && p[2] == 'D' && p[3] == 'E'
+            && p[4] == 'N' && p[5] == 'T') {
+            p += 6;
+            while (*p == ' ' || *p == '\t')
+            p++;
+            if (*p == '*')
+            com = 1;
+            else if (*p == 'O') {
+            if (*++p == 'N')
+                p++, com = 1;
+            else if (*p == 'F' && *++p == 'F')
+                p++, com = 2;
+            }
+            while (*p == ' ' || *p == '\t')
+            p++;
+            if (p[0] == '*' && p[1] == '/' && p[2] == '\n' && com) {
+            if (s_com != e_com || s_lab != e_lab || s_code != e_code)
+                dump_line();
+            if (!(inhibit_formatting = com - 1)) {
+                n_real_blanklines = 0;
+                postfix_blankline_requested = 0;
+                prefix_blankline_requested = 0;
+                suppress_blanklines = 1;
+            }
+            }
+        }
+        }
+    }
+    }
+    if (inhibit_formatting) {
+    p = in_buffer;
+    do
+        putc(*p, output);
+    while (*p++ != '\n');
+    }
+}
+
+/*
+ * Copyright (C) 1976 by the Board of Trustees of the University of Illinois
+ *
+ * All rights reserved
+ *
+ *
+ * NAME: pad_output
+ *
+ * FUNCTION: Writes tabs and spaces to move the current column up to the desired
+ * position.
+ *
+ * ALGORITHM: Put tabs and/or blanks into pobuf, then write pobuf.
+ *
+ * PARAMETERS: current        integer        The current column
+ *             target        integer        The desired column
+ *
+ * RETURNS: Integer value of the new column.  (If current >= target, no action is
+ * taken, and current is returned.
+ *
+ * GLOBALS: None
+ *
+ * CALLS: write (sys)
+ *
+ * CALLED BY: dump_line
+ *
+ * HISTORY: initial coding     November 1976    D A Willcox of CAC
+ *
+ */
+static int
+pad_output(int current, int target)
+                    /* writes tabs and blanks (if necessary) to
+                 * get the current output position up to the
+                 * target column */
+    /* current: the current column value */
+    /* target: position we want it at */
+{
+    int curr;            /* internal column pointer */
+
+    if (current >= target)
+    return (current);    /* line is already long enough */
+    curr = current;
+    if (use_tabs) {
+    int tcur;
+
+    while ((tcur = tabsize * (1 + (curr - 1) / tabsize) + 1) <= target) {
+        putc((!postgres_tab_rules ||
+          tcur != curr + 1 ||
+          target >= tcur + tabsize) ? '\t' : ' ', output);
+        curr = tcur;
+    }
+    }
+    while (curr++ < target)
+    putc(' ', output);    /* pad with final blanks */
+
+    return (target);
+}
+
+/*
+ * Copyright (C) 1976 by the Board of Trustees of the University of Illinois
+ *
+ * All rights reserved
+ *
+ *
+ * NAME: count_spaces
+ *
+ * FUNCTION: Find out where printing of a given string will leave the current
+ * character position on output.
+ *
+ * ALGORITHM: Run thru input string and add appropriate values to current
+ * position.
+ *
+ * RETURNS: Integer value of position after printing "buffer" starting in column
+ * "current".
+ *
+ * HISTORY: initial coding     November 1976    D A Willcox of CAC
+ *
+ */
+int
+count_spaces_until(int cur, char *buffer, char *end)
+/*
+ * this routine figures out where the character position will be after
+ * printing the text in buffer starting at column "current"
+ */
+{
+    char *buf;        /* used to look thru buffer */
+
+    for (buf = buffer; *buf != '\0' && buf != end; ++buf) {
+    switch (*buf) {
+
+    case '\n':
+    case 014:        /* form feed */
+        cur = 1;
+        break;
+
+    case '\t':
+        cur = tabsize * (1 + (cur - 1) / tabsize) + 1;
+        break;
+
+    case 010:        /* backspace */
+        --cur;
+        break;
+
+    default:
+        ++cur;
+        break;
+    }            /* end of switch */
+    }                /* end of for loop */
+    return (cur);
+}
+
+int
+count_spaces(int cur, char *buffer)
+{
+    return (count_spaces_until(cur, buffer, NULL));
+}
+
+void
+diag4(int level, const char *msg, int a, int b)
+{
+    if (level)
+    found_err = 1;
+    if (output == stdout) {
+    fprintf(stdout, "/**INDENT** %s@%d: ", level == 0 ? "Warning" : "Error", line_no);
+    fprintf(stdout, msg, a, b);
+    fprintf(stdout, " */\n");
+    }
+    else {
+    fprintf(stderr, "%s@%d: ", level == 0 ? "Warning" : "Error", line_no);
+    fprintf(stderr, msg, a, b);
+    fprintf(stderr, "\n");
+    }
+}
+
+void
+diag3(int level, const char *msg, int a)
+{
+    if (level)
+    found_err = 1;
+    if (output == stdout) {
+    fprintf(stdout, "/**INDENT** %s@%d: ", level == 0 ? "Warning" : "Error", line_no);
+    fprintf(stdout, msg, a);
+    fprintf(stdout, " */\n");
+    }
+    else {
+    fprintf(stderr, "%s@%d: ", level == 0 ? "Warning" : "Error", line_no);
+    fprintf(stderr, msg, a);
+    fprintf(stderr, "\n");
+    }
+}
+
+void
+diag2(int level, const char *msg)
+{
+    if (level)
+    found_err = 1;
+    if (output == stdout) {
+    fprintf(stdout, "/**INDENT** %s@%d: ", level == 0 ? "Warning" : "Error", line_no);
+    fprintf(stdout, "%s", msg);
+    fprintf(stdout, " */\n");
+    }
+    else {
+    fprintf(stderr, "%s@%d: ", level == 0 ? "Warning" : "Error", line_no);
+    fprintf(stderr, "%s", msg);
+    fprintf(stderr, "\n");
+    }
+}
+
diff --git a/src/tools/pg_bsd_indent/lexi.c b/src/tools/pg_bsd_indent/lexi.c
new file mode 100644
index 0000000000..f01596a870
--- /dev/null
+++ b/src/tools/pg_bsd_indent/lexi.c
@@ -0,0 +1,724 @@
+/*-
+ * Copyright (c) 1985 Sun Microsystems, Inc.
+ * Copyright (c) 1980, 1993
+ *    The Regents of the University of California.  All rights reserved.
+ * 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. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *    This product includes software developed by the University of
+ *    California, Berkeley and its contributors.
+ * 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.
+ */
+
+#if 0
+#ifndef lint
+static char sccsid[] = "@(#)lexi.c    8.1 (Berkeley) 6/6/93";
+#endif /* not lint */
+#endif
+
+#include "c.h"
+
+/*
+ * Here we have the token scanner for indent.  It scans off one token and puts
+ * it in the global variable "token".  It returns a code, indicating the type
+ * of token scanned.
+ */
+
+#include <err.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+#include "indent_globs.h"
+#include "indent_codes.h"
+#include "indent.h"
+
+#define alphanum 1
+#ifdef undef
+#define opchar 3
+#endif
+
+struct templ {
+    const char *rwd;
+    int         rwcode;
+};
+
+/*
+ * This table has to be sorted alphabetically, because it'll be used in binary
+ * search. For the same reason, string must be the first thing in struct templ.
+ */
+struct templ specials[] =
+{
+    {"_Bool", 4},
+    {"_Complex", 4},
+    {"_Imaginary", 4},
+    {"auto", 10},
+    {"bool", 4},
+    {"break", 9},
+    {"case", 8},
+    {"char", 4},
+    {"complex", 4},
+    {"const", 4},
+    {"continue", 12},
+    {"default", 8},
+    {"do", 6},
+    {"double", 4},
+    {"else", 6},
+    {"enum", 3},
+    {"extern", 10},
+    {"float", 4},
+    {"for", 5},
+    {"global", 4},
+    {"goto", 9},
+    {"if", 5},
+    {"imaginary", 4},
+    {"inline", 12},
+    {"int", 4},
+    {"long", 4},
+    {"offsetof", 1},
+    {"register", 10},
+    {"restrict", 12},
+    {"return", 9},
+    {"short", 4},
+    {"signed", 4},
+    {"sizeof", 2},
+    {"static", 10},
+    {"struct", 3},
+    {"switch", 7},
+    {"typedef", 11},
+    {"union", 3},
+    {"unsigned", 4},
+    {"void", 4},
+    {"volatile", 4},
+    {"while", 5}
+};
+
+const char **typenames;
+int         typename_count;
+int         typename_top = -1;
+
+char        chartype[128] =
+{                /* this is used to facilitate the decision of
+                 * what type (alphanumeric, operator) each
+                 * character is */
+    0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0,
+    0, 3, 0, 0, 1, 3, 3, 0,
+    0, 0, 3, 3, 0, 3, 0, 3,
+    1, 1, 1, 1, 1, 1, 1, 1,
+    1, 1, 0, 0, 3, 3, 3, 3,
+    0, 1, 1, 1, 1, 1, 1, 1,
+    1, 1, 1, 1, 1, 1, 1, 1,
+    1, 1, 1, 1, 1, 1, 1, 1,
+    1, 1, 1, 0, 0, 0, 3, 1,
+    0, 1, 1, 1, 1, 1, 1, 1,
+    1, 1, 1, 1, 1, 1, 1, 1,
+    1, 1, 1, 1, 1, 1, 1, 1,
+    1, 1, 1, 0, 3, 0, 3, 0
+};
+
+static int
+strcmp_type(const void *e1, const void *e2)
+{
+    return (strcmp(e1, *(const char * const *)e2));
+}
+
+/*
+ * Decide whether "foo(..." is a function definition or declaration.
+ *
+ * At call, we are looking at the '('.  Look ahead to find the first
+ * '{', ';' or ',' that is not within parentheses or comments; then
+ * it's a definition if we found '{', otherwise a declaration.
+ * Note that this rule is fooled by K&R-style parameter declarations,
+ * but telling the difference between those and function attributes
+ * seems like more trouble than it's worth.  This code could also be
+ * fooled by mismatched parens or apparent comment starts within string
+ * literals, but that seems unlikely in the context it's used in.
+ */
+static int
+is_func_definition(char *tp)
+{
+    int        paren_depth = 0;
+    int        in_comment = false;
+    int        in_slash_comment = false;
+    int        lastc = 0;
+
+    /* We may need to look past the end of the current buffer. */
+    lookahead_reset();
+    for (;;) {
+    int        c;
+
+    /* Fetch next character. */
+    if (tp < buf_end)
+        c = *tp++;
+    else {
+        c = lookahead();
+        if (c == EOF)
+        break;
+    }
+    /* Handle comments. */
+    if (in_comment) {
+        if (lastc == '*' && c == '/')
+        in_comment = false;
+    } else if (lastc == '/' && c == '*' && !in_slash_comment)
+        in_comment = true;
+    else if (in_slash_comment) {
+        if (c == '\n')
+        in_slash_comment = false;
+    } else if (lastc == '/' && c == '/')
+        in_slash_comment = true;
+    /* Count nested parens properly. */
+    else if (c == '(')
+        paren_depth++;
+    else if (c == ')') {
+        paren_depth--;
+        /*
+         * If we find unbalanced parens, we must have started inside a
+         * declaration.
+         */
+        if (paren_depth < 0)
+        return false;
+    } else if (paren_depth == 0) {
+        /* We are outside any parentheses or comments. */
+        if (c == '{')
+        return true;
+        else if (c == ';' || c == ',')
+        return false;
+    }
+    lastc = c;
+    }
+    /* Hit EOF --- for lack of anything better, assume "not a definition". */
+    return false;
+}
+
+int
+lexi(struct parser_state *state)
+{
+    int         unary_delim;    /* this is set to 1 if the current token
+                 * forces a following operator to be unary */
+    int         code;        /* internal code to be returned */
+    char        qchar;        /* the delimiter character for a string */
+
+    e_token = s_token;        /* point to start of place to save token */
+    unary_delim = false;
+    state->col_1 = state->last_nl;    /* tell world that this token started
+                     * in column 1 iff the last thing
+                     * scanned was a newline */
+    state->last_nl = false;
+
+    while (*buf_ptr == ' ' || *buf_ptr == '\t') {    /* get rid of blanks */
+    state->col_1 = false;    /* leading blanks imply token is not in column
+                 * 1 */
+    if (++buf_ptr >= buf_end)
+        fill_buffer();
+    }
+
+    /* Scan an alphanumeric token */
+    if (chartype[*buf_ptr & 127] == alphanum ||
+    (buf_ptr[0] == '.' && isdigit((unsigned char)buf_ptr[1]))) {
+    /*
+     * we have a character or number
+     */
+    struct templ *p;
+
+    if (isdigit((unsigned char)*buf_ptr) ||
+        (buf_ptr[0] == '.' && isdigit((unsigned char)buf_ptr[1]))) {
+        int         seendot = 0,
+                    seenexp = 0,
+            seensfx = 0;
+
+        /*
+         * base 2, base 8, base 16:
+         */
+        if (buf_ptr[0] == '0' && buf_ptr[1] != '.') {
+        int len;
+
+        if (buf_ptr[1] == 'b' || buf_ptr[1] == 'B')
+            len = strspn(buf_ptr + 2, "01") + 2;
+        else if (buf_ptr[1] == 'x' || buf_ptr[1] == 'X')
+            len = strspn(buf_ptr + 2, "0123456789ABCDEFabcdef") + 2;
+        else
+            len = strspn(buf_ptr + 1, "012345678") + 1;
+        if (len > 0) {
+            CHECK_SIZE_TOKEN(len);
+            memcpy(e_token, buf_ptr, len);
+            e_token += len;
+            buf_ptr += len;
+        }
+        else
+            diag2(1, "Unterminated literal");
+        }
+        else        /* base 10: */
+        while (1) {
+            if (*buf_ptr == '.') {
+            if (seendot)
+                break;
+            else
+                seendot++;
+            }
+            CHECK_SIZE_TOKEN(3);
+            *e_token++ = *buf_ptr++;
+            if (!isdigit((unsigned char)*buf_ptr) && *buf_ptr != '.') {
+            if ((*buf_ptr != 'E' && *buf_ptr != 'e') || seenexp)
+                break;
+            else {
+                seenexp++;
+                seendot++;
+                *e_token++ = *buf_ptr++;
+                if (*buf_ptr == '+' || *buf_ptr == '-')
+                *e_token++ = *buf_ptr++;
+            }
+            }
+        }
+
+        while (1) {
+        CHECK_SIZE_TOKEN(2);
+        if (!(seensfx & 1) && (*buf_ptr == 'U' || *buf_ptr == 'u')) {
+            *e_token++ = *buf_ptr++;
+            seensfx |= 1;
+            continue;
+        }
+        if (!(seensfx & 2) && (strchr("fFlL", *buf_ptr) != NULL)) {
+            if (buf_ptr[1] == buf_ptr[0])
+                *e_token++ = *buf_ptr++;
+            *e_token++ = *buf_ptr++;
+            seensfx |= 2;
+            continue;
+        }
+        break;
+        }
+    }
+    else
+        while (chartype[*buf_ptr & 127] == alphanum || *buf_ptr == BACKSLASH) {
+        /* fill_buffer() terminates buffer with newline */
+        if (*buf_ptr == BACKSLASH) {
+            if (*(buf_ptr + 1) == '\n') {
+            buf_ptr += 2;
+            if (buf_ptr >= buf_end)
+                fill_buffer();
+            } else
+                break;
+        }
+        CHECK_SIZE_TOKEN(1);
+        /* copy it over */
+        *e_token++ = *buf_ptr++;
+        if (buf_ptr >= buf_end)
+            fill_buffer();
+        }
+    *e_token = '\0';
+
+    if (s_token[0] == 'L' && s_token[1] == '\0' &&
+          (*buf_ptr == '"' || *buf_ptr == '\''))
+        return (strpfx);
+
+    while (*buf_ptr == ' ' || *buf_ptr == '\t') {    /* get rid of blanks */
+        if (++buf_ptr >= buf_end)
+        fill_buffer();
+    }
+    state->keyword = 0;
+    if (state->last_token == structure && !state->p_l_follow) {
+                /* if last token was 'struct' and we're not
+                 * in parentheses, then this token
+                 * should be treated as a declaration */
+        state->last_u_d = true;
+        return (decl);
+    }
+    /*
+     * Operator after identifier is binary unless last token was 'struct'
+     */
+    state->last_u_d = (state->last_token == structure);
+
+    p = bsearch(s_token,
+        specials,
+        sizeof(specials) / sizeof(specials[0]),
+        sizeof(specials[0]),
+        strcmp_type);
+    if (p == NULL) {    /* not a special keyword... */
+        char *u;
+
+        /* ... so maybe a type_t or a typedef */
+        if ((auto_typedefs && ((u = strrchr(s_token, '_')) != NULL) &&
+            strcmp(u, "_t") == 0) || (typename_top >= 0 &&
+          bsearch(s_token, typenames, typename_top + 1,
+            sizeof(typenames[0]), strcmp_type))) {
+        state->keyword = 4;    /* a type name */
+        state->last_u_d = true;
+            goto found_typename;
+        }
+    } else {            /* we have a keyword */
+        state->keyword = p->rwcode;
+        state->last_u_d = true;
+        switch (p->rwcode) {
+        case 7:        /* it is a switch */
+        return (swstmt);
+        case 8:        /* a case or default */
+        return (casestmt);
+
+        case 3:        /* a "struct" */
+        /* FALLTHROUGH */
+        case 4:        /* one of the declaration keywords */
+        found_typename:
+        if (state->p_l_follow) {
+            /* inside parens: cast, param list, offsetof or sizeof */
+            state->cast_mask |= (1 << state->p_l_follow) & ~state->not_cast_mask;
+        }
+        if (state->last_token == period || state->last_token == unary_op) {
+            state->keyword = 0;
+            break;
+        }
+        if (p != NULL && p->rwcode == 3)
+            return (structure);
+        if (state->p_l_follow)
+            break;
+        return (decl);
+
+        case 5:        /* if, while, for */
+        return (sp_paren);
+
+        case 6:        /* do, else */
+        return (sp_nparen);
+
+        case 10:        /* storage class specifier */
+        return (storage);
+
+        case 11:        /* typedef */
+        return (type_def);
+
+        default:        /* all others are treated like any other
+                 * identifier */
+        return (ident);
+        }            /* end of switch */
+    }            /* end of if (found_it) */
+    if (*buf_ptr == '(' && state->tos <= 1 && state->ind_level == 0 &&
+        state->in_parameter_declaration == 0 && state->block_init == 0) {
+        if (is_func_definition(buf_ptr)) {
+        strncpy(state->procname, token, sizeof state->procname - 1);
+        if (state->in_decl)
+            state->in_parameter_declaration = 1;
+        return (funcname);
+        }
+    }
+    /*
+     * The following hack attempts to guess whether or not the current
+     * token is in fact a declaration keyword -- one that has been
+     * typedefd
+     */
+    else if (!state->p_l_follow && !state->block_init &&
+        !state->in_stmt &&
+        ((*buf_ptr == '*' && buf_ptr[1] != '=') ||
+        isalpha((unsigned char)*buf_ptr)) &&
+        (state->last_token == semicolon || state->last_token == lbrace ||
+        state->last_token == rbrace)) {
+        state->keyword = 4;    /* a type name */
+        state->last_u_d = true;
+        return decl;
+    }
+    if (state->last_token == decl)    /* if this is a declared variable,
+                     * then following sign is unary */
+        state->last_u_d = true;    /* will make "int a -1" work */
+    return (ident);        /* the ident is not in the list */
+    }                /* end of processing for alphanum character */
+
+    /* Scan a non-alphanumeric token */
+
+    CHECK_SIZE_TOKEN(3);        /* things like "<<=" */
+    *e_token++ = *buf_ptr;        /* if it is only a one-character token, it is
+                 * moved here */
+    *e_token = '\0';
+    if (++buf_ptr >= buf_end)
+    fill_buffer();
+
+    switch (*token) {
+    case '\n':
+    unary_delim = state->last_u_d;
+    state->last_nl = true;    /* remember that we just had a newline */
+    code = (had_eof ? 0 : newline);
+
+    /*
+     * if data has been exhausted, the newline is a dummy, and we should
+     * return code to stop
+     */
+    break;
+
+    case '\'':            /* start of quoted character */
+    case '"':            /* start of string */
+    qchar = *token;
+    do {            /* copy the string */
+        while (1) {        /* move one character or [/<char>]<char> */
+        if (*buf_ptr == '\n') {
+            diag2(1, "Unterminated literal");
+            goto stop_lit;
+        }
+        CHECK_SIZE_TOKEN(2);
+        *e_token = *buf_ptr++;
+        if (buf_ptr >= buf_end)
+            fill_buffer();
+        if (*e_token == BACKSLASH) {    /* if escape, copy extra char */
+            if (*buf_ptr == '\n')    /* check for escaped newline */
+            ++line_no;
+            *++e_token = *buf_ptr++;
+            ++e_token;    /* we must increment this again because we
+                 * copied two chars */
+            if (buf_ptr >= buf_end)
+            fill_buffer();
+        }
+        else
+            break;    /* we copied one character */
+        }            /* end of while (1) */
+    } while (*e_token++ != qchar);
+stop_lit:
+    code = ident;
+    break;
+
+    case ('('):
+    case ('['):
+    unary_delim = true;
+    code = lparen;
+    break;
+
+    case (')'):
+    case (']'):
+    code = rparen;
+    break;
+
+    case '#':
+    unary_delim = state->last_u_d;
+    code = preesc;
+    break;
+
+    case '?':
+    unary_delim = true;
+    code = question;
+    break;
+
+    case (':'):
+    code = colon;
+    unary_delim = true;
+    break;
+
+    case (';'):
+    unary_delim = true;
+    code = semicolon;
+    break;
+
+    case ('{'):
+    unary_delim = true;
+
+    /*
+     * if (state->in_or_st) state->block_init = 1;
+     */
+    /* ?    code = state->block_init ? lparen : lbrace; */
+    code = lbrace;
+    break;
+
+    case ('}'):
+    unary_delim = true;
+    /* ?    code = state->block_init ? rparen : rbrace; */
+    code = rbrace;
+    break;
+
+    case 014:            /* a form feed */
+    unary_delim = state->last_u_d;
+    state->last_nl = true;    /* remember this so we can set 'state->col_1'
+                 * right */
+    code = form_feed;
+    break;
+
+    case (','):
+    unary_delim = true;
+    code = comma;
+    break;
+
+    case '.':
+    unary_delim = false;
+    code = period;
+    break;
+
+    case '-':
+    case '+':            /* check for -, +, --, ++ */
+    code = (state->last_u_d ? unary_op : binary_op);
+    unary_delim = true;
+
+    if (*buf_ptr == token[0]) {
+        /* check for doubled character */
+        *e_token++ = *buf_ptr++;
+        /* buffer overflow will be checked at end of loop */
+        if (state->last_token == ident || state->last_token == rparen) {
+        code = (state->last_u_d ? unary_op : postop);
+        /* check for following ++ or -- */
+        unary_delim = false;
+        }
+    }
+    else if (*buf_ptr == '=')
+        /* check for operator += */
+        *e_token++ = *buf_ptr++;
+    else if (*buf_ptr == '>') {
+        /* check for operator -> */
+        *e_token++ = *buf_ptr++;
+        unary_delim = false;
+        code = unary_op;
+        state->want_blank = false;
+    }
+    break;            /* buffer overflow will be checked at end of
+                 * switch */
+
+    case '=':
+    if (state->in_or_st)
+        state->block_init = 1;
+#ifdef undef
+    if (chartype[*buf_ptr & 127] == opchar) {    /* we have two char assignment */
+        e_token[-1] = *buf_ptr++;
+        if ((e_token[-1] == '<' || e_token[-1] == '>') && e_token[-1] == *buf_ptr)
+        *e_token++ = *buf_ptr++;
+        *e_token++ = '=';    /* Flip =+ to += */
+        *e_token = 0;
+    }
+#else
+    if (*buf_ptr == '=') {/* == */
+        *e_token++ = '=';    /* Flip =+ to += */
+        buf_ptr++;
+        *e_token = 0;
+    }
+#endif
+    code = binary_op;
+    unary_delim = true;
+    break;
+    /* can drop thru!!! */
+
+    case '>':
+    case '<':
+    case '!':            /* ops like <, <<, <=, !=, etc */
+    if (*buf_ptr == '>' || *buf_ptr == '<' || *buf_ptr == '=') {
+        *e_token++ = *buf_ptr;
+        if (++buf_ptr >= buf_end)
+        fill_buffer();
+    }
+    if (*buf_ptr == '=')
+        *e_token++ = *buf_ptr++;
+    code = (state->last_u_d ? unary_op : binary_op);
+    unary_delim = true;
+    break;
+
+    case '*':
+    unary_delim = true;
+    if (!state->last_u_d) {
+        if (*buf_ptr == '=')
+        *e_token++ = *buf_ptr++;
+        code = binary_op;
+        break;
+    }
+    while (*buf_ptr == '*' || isspace((unsigned char)*buf_ptr)) {
+        if (*buf_ptr == '*') {
+        CHECK_SIZE_TOKEN(1);
+        *e_token++ = *buf_ptr;
+        }
+        if (++buf_ptr >= buf_end)
+        fill_buffer();
+    }
+    code = unary_op;
+    break;
+
+    default:
+    if (token[0] == '/' && *buf_ptr == '*') {
+        /* it is start of comment */
+        *e_token++ = '*';
+
+        if (++buf_ptr >= buf_end)
+        fill_buffer();
+
+        code = comment;
+        unary_delim = state->last_u_d;
+        break;
+    }
+    while (*(e_token - 1) == *buf_ptr || *buf_ptr == '=') {
+        /*
+         * handle ||, &&, etc, and also things as in int *****i
+         */
+        CHECK_SIZE_TOKEN(1);
+        *e_token++ = *buf_ptr;
+        if (++buf_ptr >= buf_end)
+        fill_buffer();
+    }
+    code = (state->last_u_d ? unary_op : binary_op);
+    unary_delim = true;
+
+
+    }                /* end of switch */
+    if (buf_ptr >= buf_end)    /* check for input buffer empty */
+    fill_buffer();
+    state->last_u_d = unary_delim;
+    CHECK_SIZE_TOKEN(1);
+    *e_token = '\0';        /* null terminate the token */
+    return (code);
+}
+
+void
+alloc_typenames(void)
+{
+
+    typenames = (const char **)malloc(sizeof(typenames[0]) *
+        (typename_count = 16));
+    if (typenames == NULL)
+    err(1, NULL);
+}
+
+void
+add_typename(const char *key)
+{
+    int comparison;
+    const char *copy;
+
+    if (typename_top + 1 >= typename_count) {
+    typenames = realloc((void *)typenames,
+        sizeof(typenames[0]) * (typename_count *= 2));
+    if (typenames == NULL)
+        err(1, NULL);
+    }
+    if (typename_top == -1)
+    typenames[++typename_top] = copy = strdup(key);
+    else if ((comparison = strcmp(key, typenames[typename_top])) >= 0) {
+    /* take advantage of sorted input */
+    if (comparison == 0)    /* remove duplicates */
+        return;
+    typenames[++typename_top] = copy = strdup(key);
+    }
+    else {
+    int p;
+
+    for (p = 0; (comparison = strcmp(key, typenames[p])) > 0; p++)
+        /* find place for the new key */;
+    if (comparison == 0)    /* remove duplicates */
+        return;
+    memmove(&typenames[p + 1], &typenames[p],
+        sizeof(typenames[0]) * (++typename_top - p));
+    typenames[p] = copy = strdup(key);
+    }
+
+    if (copy == NULL)
+    err(1, NULL);
+}
diff --git a/src/tools/pg_bsd_indent/parse.c b/src/tools/pg_bsd_indent/parse.c
new file mode 100644
index 0000000000..bf6b1697f9
--- /dev/null
+++ b/src/tools/pg_bsd_indent/parse.c
@@ -0,0 +1,342 @@
+/*-
+ * Copyright (c) 1985 Sun Microsystems, Inc.
+ * Copyright (c) 1980, 1993
+ *    The Regents of the University of California.  All rights reserved.
+ * 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. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *    This product includes software developed by the University of
+ *    California, Berkeley and its contributors.
+ * 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.
+ */
+
+#if 0
+#ifndef lint
+static char sccsid[] = "@(#)parse.c    8.1 (Berkeley) 6/6/93";
+#endif /* not lint */
+#endif
+
+#include "c.h"
+
+#include <err.h>
+#include <stdio.h>
+#include "indent_globs.h"
+#include "indent_codes.h"
+#include "indent.h"
+
+static void reduce(void);
+
+void
+parse(int tk) /* tk: the code for the construct scanned */
+{
+    int         i;
+
+#ifdef debug
+    printf("%2d - %s\n", tk, token);
+#endif
+
+    while (ps.p_stack[ps.tos] == ifhead && tk != elselit) {
+    /* true if we have an if without an else */
+    ps.p_stack[ps.tos] = stmt;    /* apply the if(..) stmt ::= stmt
+                     * reduction */
+    reduce();        /* see if this allows any reduction */
+    }
+
+
+    switch (tk) {        /* go on and figure out what to do with the
+                 * input */
+
+    case decl:            /* scanned a declaration word */
+    ps.search_brace = btype_2;
+    /* indicate that following brace should be on same line */
+    if (ps.p_stack[ps.tos] != decl) {    /* only put one declaration
+                         * onto stack */
+        break_comma = true;    /* while in declaration, newline should be
+                 * forced after comma */
+        ps.p_stack[++ps.tos] = decl;
+        ps.il[ps.tos] = ps.i_l_follow;
+
+        if (ps.ljust_decl) {/* only do if we want left justified
+                 * declarations */
+        ps.ind_level = 0;
+        for (i = ps.tos - 1; i > 0; --i)
+            if (ps.p_stack[i] == decl)
+            ++ps.ind_level;    /* indentation is number of
+                     * declaration levels deep we are */
+        ps.i_l_follow = ps.ind_level;
+        }
+    }
+    break;
+
+    case ifstmt:        /* scanned if (...) */
+    if (ps.p_stack[ps.tos] == elsehead && ps.else_if)    /* "else if ..." */
+        /*
+         * Note that the stack pointer here is decremented, effectively
+         * reducing "else if" to "if". This saves a lot of stack space
+         * in case of a long "if-else-if ... else-if" sequence.
+         */
+        ps.i_l_follow = ps.il[ps.tos--];
+    /* the rest is the same as for dolit and forstmt */
+    /* FALLTHROUGH */
+    case dolit:        /* 'do' */
+    case forstmt:        /* for (...) */
+    ps.p_stack[++ps.tos] = tk;
+    ps.il[ps.tos] = ps.ind_level = ps.i_l_follow;
+    ++ps.i_l_follow;    /* subsequent statements should be indented 1 */
+    ps.search_brace = btype_2;
+    break;
+
+    case lbrace:        /* scanned { */
+    break_comma = false;    /* don't break comma in an initial list */
+    if (ps.p_stack[ps.tos] == stmt || ps.p_stack[ps.tos] == decl
+        || ps.p_stack[ps.tos] == stmtl)
+        ++ps.i_l_follow;    /* it is a random, isolated stmt group or a
+                 * declaration */
+    else {
+        if (s_code == e_code) {
+        /*
+         * only do this if there is nothing on the line
+         */
+        --ps.ind_level;
+        /*
+         * it is a group as part of a while, for, etc.
+         */
+        if (ps.p_stack[ps.tos] == swstmt && ps.case_indent >= 1)
+            --ps.ind_level;
+        /*
+         * for a switch, brace should be two levels out from the code
+         */
+        }
+    }
+
+    ps.p_stack[++ps.tos] = lbrace;
+    ps.il[ps.tos] = ps.ind_level;
+    ps.p_stack[++ps.tos] = stmt;
+    /* allow null stmt between braces */
+    ps.il[ps.tos] = ps.i_l_follow;
+    break;
+
+    case whilestmt:        /* scanned while (...) */
+    if (ps.p_stack[ps.tos] == dohead) {
+        /* it is matched with do stmt */
+        ps.ind_level = ps.i_l_follow = ps.il[ps.tos];
+        ps.p_stack[++ps.tos] = whilestmt;
+        ps.il[ps.tos] = ps.ind_level = ps.i_l_follow;
+    }
+    else {            /* it is a while loop */
+        ps.p_stack[++ps.tos] = whilestmt;
+        ps.il[ps.tos] = ps.i_l_follow;
+        ++ps.i_l_follow;
+        ps.search_brace = btype_2;
+    }
+
+    break;
+
+    case elselit:        /* scanned an else */
+
+    if (ps.p_stack[ps.tos] != ifhead)
+        diag2(1, "Unmatched 'else'");
+    else {
+        ps.ind_level = ps.il[ps.tos];    /* indentation for else should
+                         * be same as for if */
+        ps.i_l_follow = ps.ind_level + 1;    /* everything following should
+                         * be in 1 level */
+        ps.p_stack[ps.tos] = elsehead;
+        /* remember if with else */
+        ps.search_brace = btype_2 | ps.else_if;
+    }
+    break;
+
+    case rbrace:        /* scanned a } */
+    /* stack should have <lbrace> <stmt> or <lbrace> <stmtl> */
+    if (ps.tos > 0 && ps.p_stack[ps.tos - 1] == lbrace) {
+        ps.ind_level = ps.i_l_follow = ps.il[--ps.tos];
+        ps.p_stack[ps.tos] = stmt;
+    }
+    else
+        diag2(1, "Statement nesting error");
+    break;
+
+    case swstmt:        /* had switch (...) */
+    ps.p_stack[++ps.tos] = swstmt;
+    ps.cstk[ps.tos] = case_ind;
+    /* save current case indent level */
+    ps.il[ps.tos] = ps.i_l_follow;
+    case_ind = ps.i_l_follow + ps.case_indent;    /* cases should be one
+                             * level down from
+                             * switch */
+    ps.i_l_follow += ps.case_indent + 1;    /* statements should be two
+                         * levels in */
+    ps.search_brace = btype_2;
+    break;
+
+    case semicolon:        /* this indicates a simple stmt */
+    break_comma = false;    /* turn off flag to break after commas in a
+                 * declaration */
+    ps.p_stack[++ps.tos] = stmt;
+    ps.il[ps.tos] = ps.ind_level;
+    break;
+
+    default:            /* this is an error */
+    diag2(1, "Unknown code to parser");
+    return;
+
+
+    }                /* end of switch */
+
+    if (ps.tos >= nitems(ps.p_stack) - 1)
+    errx(1, "Parser stack overflow");
+
+    reduce();            /* see if any reduction can be done */
+
+#ifdef debug
+    for (i = 1; i <= ps.tos; ++i)
+    printf("(%d %d)", ps.p_stack[i], ps.il[i]);
+    printf("\n");
+#endif
+
+    return;
+}
+
+/*
+ * NAME: reduce
+ *
+ * FUNCTION: Implements the reduce part of the parsing algorithm
+ *
+ * ALGORITHM: The following reductions are done.  Reductions are repeated
+ *    until no more are possible.
+ *
+ * Old TOS        New TOS
+ * <stmt> <stmt>    <stmtl>
+ * <stmtl> <stmt>    <stmtl>
+ * do <stmt>        "dostmt"
+ * if <stmt>        "ifstmt"
+ * switch <stmt>    <stmt>
+ * decl <stmt>        <stmt>
+ * "ifelse" <stmt>    <stmt>
+ * for <stmt>        <stmt>
+ * while <stmt>        <stmt>
+ * "dostmt" while    <stmt>
+ *
+ * On each reduction, ps.i_l_follow (the indentation for the following line)
+ * is set to the indentation level associated with the old TOS.
+ *
+ * PARAMETERS: None
+ *
+ * RETURNS: Nothing
+ *
+ * GLOBALS: ps.cstk ps.i_l_follow = ps.il ps.p_stack = ps.tos =
+ *
+ * CALLS: None
+ *
+ * CALLED BY: parse
+ *
+ * HISTORY: initial coding     November 1976    D A Willcox of CAC
+ *
+ */
+/*----------------------------------------------*\
+|   REDUCTION PHASE                    |
+\*----------------------------------------------*/
+static void
+reduce(void)
+{
+    int i;
+
+    for (;;) {            /* keep looping until there is nothing left to
+                 * reduce */
+
+    switch (ps.p_stack[ps.tos]) {
+
+    case stmt:
+        switch (ps.p_stack[ps.tos - 1]) {
+
+        case stmt:
+        case stmtl:
+        /* stmtl stmt or stmt stmt */
+        ps.p_stack[--ps.tos] = stmtl;
+        break;
+
+        case dolit:    /* <do> <stmt> */
+        ps.p_stack[--ps.tos] = dohead;
+        ps.i_l_follow = ps.il[ps.tos];
+        break;
+
+        case ifstmt:
+        /* <if> <stmt> */
+        ps.p_stack[--ps.tos] = ifhead;
+        for (i = ps.tos - 1;
+            (
+             ps.p_stack[i] != stmt
+             &&
+             ps.p_stack[i] != stmtl
+             &&
+             ps.p_stack[i] != lbrace
+             );
+            --i);
+        ps.i_l_follow = ps.il[i];
+        /*
+         * for the time being, we will assume that there is no else on
+         * this if, and set the indentation level accordingly. If an
+         * else is scanned, it will be fixed up later
+         */
+        break;
+
+        case swstmt:
+        /* <switch> <stmt> */
+        case_ind = ps.cstk[ps.tos - 1];
+        /* FALLTHROUGH */
+        case decl:        /* finish of a declaration */
+        case elsehead:
+        /* <<if> <stmt> else> <stmt> */
+        case forstmt:
+        /* <for> <stmt> */
+        case whilestmt:
+        /* <while> <stmt> */
+        ps.p_stack[--ps.tos] = stmt;
+        ps.i_l_follow = ps.il[ps.tos];
+        break;
+
+        default:        /* <anything else> <stmt> */
+        return;
+
+        }            /* end of section for <stmt> on top of stack */
+        break;
+
+    case whilestmt:    /* while (...) on top */
+        if (ps.p_stack[ps.tos - 1] == dohead) {
+        /* it is termination of a do while */
+        ps.tos -= 2;
+        break;
+        }
+        else
+        return;
+
+    default:        /* anything else on top */
+        return;
+
+    }
+    }
+}
diff --git a/src/tools/pg_bsd_indent/pr_comment.c b/src/tools/pg_bsd_indent/pr_comment.c
new file mode 100644
index 0000000000..b0eacac1bb
--- /dev/null
+++ b/src/tools/pg_bsd_indent/pr_comment.c
@@ -0,0 +1,358 @@
+/*-
+ * Copyright (c) 1985 Sun Microsystems, Inc.
+ * Copyright (c) 1980, 1993
+ *    The Regents of the University of California.  All rights reserved.
+ * 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. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *    This product includes software developed by the University of
+ *    California, Berkeley and its contributors.
+ * 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.
+ */
+
+#if 0
+#ifndef lint
+static char sccsid[] = "@(#)pr_comment.c    8.1 (Berkeley) 6/6/93";
+#endif /* not lint */
+#endif
+
+#include "c.h"
+
+#include <err.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "indent_globs.h"
+#include "indent_codes.h"
+#include "indent.h"
+/*
+ * NAME:
+ *    pr_comment
+ *
+ * FUNCTION:
+ *    This routine takes care of scanning and printing comments.
+ *
+ * ALGORITHM:
+ *    1) Decide where the comment should be aligned, and if lines should
+ *       be broken.
+ *    2) If lines should not be broken and filled, just copy up to end of
+ *       comment.
+ *    3) If lines should be filled, then scan thru input_buffer copying
+ *       characters to com_buf.  Remember where the last blank, tab, or
+ *       newline was.  When line is filled, print up to last blank and
+ *       continue copying.
+ *
+ * HISTORY:
+ *    November 1976    D A Willcox of CAC    Initial coding
+ *    12/6/76        D A Willcox of CAC    Modification to handle
+ *                        UNIX-style comments
+ *
+ */
+
+/*
+ * this routine processes comments.  It makes an attempt to keep comments from
+ * going over the max line length.  If a line is too long, it moves everything
+ * from the last blank to the next comment line.  Blanks and tabs from the
+ * beginning of the input line are removed
+ */
+
+void
+pr_comment(void)
+{
+    int         now_col;    /* column we are in now */
+    int         adj_max_col;    /* Adjusted max_col for when we decide to
+                 * spill comments over the right margin */
+    char       *last_bl;    /* points to the last blank in the output
+                 * buffer */
+    char       *t_ptr;        /* used for moving string */
+    int         break_delim = comment_delimiter_on_blankline;
+    int         l_just_saw_decl = ps.just_saw_decl;
+    adj_max_col = max_col;
+    ps.just_saw_decl = 0;
+    last_bl = NULL;        /* no blanks found so far */
+    ps.box_com = false;        /* at first, assume that we are not in
+                     * a boxed comment or some other
+                     * comment that should not be touched */
+    ++ps.out_coms;        /* keep track of number of comments */
+
+    /* Figure where to align and how to treat the comment */
+
+    if (ps.col_1 && !format_col1_comments) {    /* if comment starts in column
+                         * 1 it should not be touched */
+    ps.box_com = true;
+    break_delim = false;
+    ps.com_col = 1;
+    }
+    else {
+    if (*buf_ptr == '-' || *buf_ptr == '*' ||
+        (*buf_ptr == '\n' && !format_block_comments)) {
+        ps.box_com = true;    /* A comment with a '-' or '*' immediately
+                 * after the /+* is assumed to be a boxed
+                 * comment. A comment with a newline
+                 * immediately after the /+* is assumed to
+                 * be a block comment and is treated as a
+                 * box comment unless format_block_comments
+                 * is nonzero (the default). */
+        break_delim = false;
+    }
+    if ( /* ps.bl_line && */ (s_lab == e_lab) && (s_code == e_code)) {
+        /* klg: check only if this line is blank */
+        /*
+         * If this (*and previous lines are*) blank, dont put comment way
+         * out at left
+         */
+        ps.com_col = (ps.ind_level - ps.unindent_displace) * ps.ind_size + 1;
+        adj_max_col = block_comment_max_col;
+        if (ps.com_col <= 1)
+        ps.com_col = 1 + !format_col1_comments;
+    }
+    else {
+        int target_col;
+        break_delim = false;
+        if (s_code != e_code)
+        target_col = count_spaces(compute_code_target(), s_code);
+        else {
+        target_col = 1;
+        if (s_lab != e_lab)
+            target_col = count_spaces(compute_label_target(), s_lab);
+        }
+        if (s_lab != e_lab && s_lab[1] == 'e' &&
+        (strncmp(s_lab, "#endif", 6) == 0 ||
+        strncmp(s_lab, "#else", 5) == 0))
+        ps.com_col = else_endif_com_ind <= target_col
+            ? target_col + 1 : else_endif_com_ind;
+        else
+        ps.com_col = ps.decl_on_line || ps.ind_level == 0
+            ? ps.decl_com_ind : ps.com_ind;
+        if (ps.com_col <= target_col)
+        ps.com_col = tabsize * (1 + (target_col - 1) / tabsize) + 1;
+        if (ps.com_col + 24 > adj_max_col)
+        adj_max_col = ps.com_col + 24;
+    }
+    }
+    if (ps.box_com) {
+    /*
+     * Find out how much indentation there was originally, because that
+     * much will have to be ignored by pad_output() in dump_line(). This
+     * is a box comment, so nothing changes -- not even indentation.
+     *
+     * The comment we're about to read usually comes from in_buffer,
+     * unless it has been copied into save_com.
+     */
+    char *start;
+
+    start = buf_ptr >= save_com && buf_ptr < save_com + sc_size ?
+        sc_buf : in_buffer;
+    ps.n_comment_delta = 1 - count_spaces_until(1, start, buf_ptr - 2);
+    }
+    else {
+    ps.n_comment_delta = 0;
+    while (*buf_ptr == ' ' || *buf_ptr == '\t')
+        buf_ptr++;
+    }
+    ps.comment_delta = 0;
+    *e_com++ = '/';        /* put '/' followed by '*' into buffer */
+    *e_com++ = '*';
+    if (*buf_ptr != ' ' && !ps.box_com)
+    *e_com++ = ' ';
+
+    /*
+     * Don't put a break delimiter if this is a one-liner that won't wrap.
+     */
+    if (break_delim)
+    for (t_ptr = buf_ptr; *t_ptr != '\0' && *t_ptr != '\n'; t_ptr++) {
+        if (t_ptr >= buf_end)
+        fill_buffer();
+        if (t_ptr[0] == '*' && t_ptr[1] == '/') {
+        if (adj_max_col >= count_spaces_until(ps.com_col, buf_ptr, t_ptr + 2))
+            break_delim = false;
+        break;
+        }
+    }
+
+    if (break_delim) {
+    char       *t = e_com;
+    e_com = s_com + 2;
+    *e_com = 0;
+    if (blanklines_before_blockcomments && ps.last_token != lbrace)
+        prefix_blankline_requested = 1;
+    dump_line();
+    e_com = s_com = t;
+    if (!ps.box_com && star_comment_cont)
+        *e_com++ = ' ', *e_com++ = '*', *e_com++ = ' ';
+    }
+
+    /* Start to copy the comment */
+
+    while (1) {            /* this loop will go until the comment is
+                 * copied */
+    switch (*buf_ptr) {    /* this checks for various spcl cases */
+    case 014:        /* check for a form feed */
+        CHECK_SIZE_COM(3);
+        if (!ps.box_com) {    /* in a text comment, break the line here */
+        ps.use_ff = true;
+        /* fix so dump_line uses a form feed */
+        dump_line();
+        last_bl = NULL;
+        if (!ps.box_com && star_comment_cont)
+            *e_com++ = ' ', *e_com++ = '*', *e_com++ = ' ';
+        while (*++buf_ptr == ' ' || *buf_ptr == '\t')
+            ;
+        }
+        else {
+        if (++buf_ptr >= buf_end)
+            fill_buffer();
+        *e_com++ = 014;
+        }
+        break;
+
+    case '\n':
+        if (had_eof) {    /* check for unexpected eof */
+        printf("Unterminated comment\n");
+        dump_line();
+        return;
+        }
+        last_bl = NULL;
+        CHECK_SIZE_COM(4);
+        if (ps.box_com || ps.last_nl) {    /* if this is a boxed comment,
+                         * we dont ignore the newline */
+        if (s_com == e_com)
+            *e_com++ = ' ';
+        if (!ps.box_com && e_com - s_com > 3) {
+            dump_line();
+            if (star_comment_cont)
+            *e_com++ = ' ', *e_com++ = '*', *e_com++ = ' ';
+        }
+        dump_line();
+        if (!ps.box_com && star_comment_cont)
+            *e_com++ = ' ', *e_com++ = '*', *e_com++ = ' ';
+        }
+        else {
+        ps.last_nl = 1;
+        if (*(e_com - 1) == ' ' || *(e_com - 1) == '\t')
+            last_bl = e_com - 1;
+        /*
+         * if there was a space at the end of the last line, remember
+         * where it was
+         */
+        else {        /* otherwise, insert one */
+            last_bl = e_com;
+            *e_com++ = ' ';
+        }
+        }
+        ++line_no;        /* keep track of input line number */
+        if (!ps.box_com) {
+        int         nstar = 1;
+        do {        /* flush any blanks and/or tabs at start of
+                 * next line */
+            if (++buf_ptr >= buf_end)
+            fill_buffer();
+            if (*buf_ptr == '*' && --nstar >= 0) {
+            if (++buf_ptr >= buf_end)
+                fill_buffer();
+            if (*buf_ptr == '/')
+                goto end_of_comment;
+            }
+        } while (*buf_ptr == ' ' || *buf_ptr == '\t');
+        }
+        else if (++buf_ptr >= buf_end)
+        fill_buffer();
+        break;        /* end of case for newline */
+
+    case '*':        /* must check for possibility of being at end
+                 * of comment */
+        if (++buf_ptr >= buf_end)    /* get to next char after * */
+        fill_buffer();
+        CHECK_SIZE_COM(4);
+        if (*buf_ptr == '/') {    /* it is the end!!! */
+    end_of_comment:
+        if (++buf_ptr >= buf_end)
+            fill_buffer();
+        if (break_delim) {
+            if (e_com > s_com + 3) {
+            dump_line();
+            }
+            else
+            s_com = e_com;
+            *e_com++ = ' ';
+        }
+        if (e_com[-1] != ' ' && e_com[-1] != '\t' && !ps.box_com)
+            *e_com++ = ' ';    /* ensure blank before end */
+        *e_com++ = '*', *e_com++ = '/', *e_com = '\0';
+        ps.just_saw_decl = l_just_saw_decl;
+        return;
+        }
+        else        /* handle isolated '*' */
+        *e_com++ = '*';
+        break;
+    default:        /* we have a random char */
+        now_col = count_spaces_until(ps.com_col, s_com, e_com);
+        do {
+        CHECK_SIZE_COM(1);
+        *e_com = *buf_ptr++;
+        if (buf_ptr >= buf_end)
+            fill_buffer();
+        if (*e_com == ' ' || *e_com == '\t')
+            last_bl = e_com;    /* remember we saw a blank */
+        ++e_com;
+        now_col++;
+        } while (!memchr("*\n\r\b\t", *buf_ptr, 6) &&
+        (now_col <= adj_max_col || !last_bl));
+        ps.last_nl = false;
+        if (now_col > adj_max_col && !ps.box_com && e_com[-1] > ' ') {
+        /*
+         * the comment is too long, it must be broken up
+         */
+        if (last_bl == NULL) {
+            dump_line();
+            if (!ps.box_com && star_comment_cont)
+            *e_com++ = ' ', *e_com++ = '*', *e_com++ = ' ';
+            break;
+        }
+        *e_com = '\0';
+        e_com = last_bl;
+        dump_line();
+        if (!ps.box_com && star_comment_cont)
+            *e_com++ = ' ', *e_com++ = '*', *e_com++ = ' ';
+        for (t_ptr = last_bl + 1; *t_ptr == ' ' || *t_ptr == '\t';
+            t_ptr++)
+            ;
+        last_bl = NULL;
+        /*
+         * t_ptr will be somewhere between e_com (dump_line() reset)
+         * and l_com. So it's safe to copy byte by byte from t_ptr
+         * to e_com without any CHECK_SIZE_COM().
+         */
+        while (*t_ptr != '\0') {
+            if (*t_ptr == ' ' || *t_ptr == '\t')
+            last_bl = e_com;
+            *e_com++ = *t_ptr++;
+        }
+        }
+        break;
+    }
+    }
+}
diff --git a/src/tools/pg_bsd_indent/tests/binary.0 b/src/tools/pg_bsd_indent/tests/binary.0
new file mode 100644
index 0000000000..0c5ebf7e8f
--- /dev/null
+++ b/src/tools/pg_bsd_indent/tests/binary.0
@@ -0,0 +1,9 @@
+#define b00101010 -1
+void t(void) {
+    unsigned a[] = {0b00101010, 0x00005678, 02, 17U};
+    float x[] = {.7f, 0.7f};
+    unsigned long ul[] = {0b00001111UL, 0x01010101UL, 02UL, 17UL};
+
+    if (0 b00101010)
+        return;
+}
diff --git a/src/tools/pg_bsd_indent/tests/binary.0.stdout b/src/tools/pg_bsd_indent/tests/binary.0.stdout
new file mode 100644
index 0000000000..6118ac5055
--- /dev/null
+++ b/src/tools/pg_bsd_indent/tests/binary.0.stdout
@@ -0,0 +1,11 @@
+#define b00101010 -1
+void
+t(void)
+{
+    unsigned    a[] = {0b00101010, 0x00005678, 02, 17U};
+    float        x[] = {.7f, 0.7f};
+    unsigned long    ul[] = {0b00001111UL, 0x01010101UL, 02UL, 17UL};
+
+    if (0 b00101010)
+        return;
+}
diff --git a/src/tools/pg_bsd_indent/tests/comments.0 b/src/tools/pg_bsd_indent/tests/comments.0
new file mode 100644
index 0000000000..7b65c2eb55
--- /dev/null
+++ b/src/tools/pg_bsd_indent/tests/comments.0
@@ -0,0 +1,52 @@
+/* $FreeBSD$ */
+typedef enum x {
+    aaaaaaaaaaaaaaaaaaaaaa = 1 << 0,    /* test a */
+    bbbbbbbbbbbbbbbbb = 1 << 1,    /* test b */
+    cccccccccccccc = 1 << 1,    /* test c */
+    dddddddddddddddddddddddddddddd = 1 << 2    /* test d */
+} x;
+
+/* See r303597, r303598, r309219, and r309343 */
+void t(void) {
+    /*
+     * Old indent wrapped the URL near where this sentence ends.
+     *
+     *
https://www.freebsd.org/cgi/man.cgi?query=indent&apropos=0&sektion=0&manpath=FreeBSD+12-current&arch=default&format=html
+     */
+
+    /*
+     * Old indent did not wrap to column 78
+     *
+     * aaaaaa bbbbbb cccccc dddddd eeeeee ffffff ggggg hhhhh iiiii jjjj kk
+     */
+
+    /*
+     * Old indent unnecessarily removed the star comment continuation on the next line.
+     *
+     * *test*
+     */
+
+    /* r309219 Go through linked list, freeing from the malloced (t[-1]) address. */
+
+    /* r309343    */
+}
+
+int c(void)
+{
+    if (1) { /*- a christmas tree  *
+                      ***
+                     ***** */
+            /*- another one *
+                   ***
+                  ***** */
+        7;
+    }
+
+    if (1) /*- a christmas tree  *
+                    ***
+                   ***** */
+            /*- another one *
+                   ***
+                  ***** */
+        1;
+}
diff --git a/src/tools/pg_bsd_indent/tests/comments.0.stdout b/src/tools/pg_bsd_indent/tests/comments.0.stdout
new file mode 100644
index 0000000000..8ca5aa518c
--- /dev/null
+++ b/src/tools/pg_bsd_indent/tests/comments.0.stdout
@@ -0,0 +1,60 @@
+/* $FreeBSD$ */
+typedef enum x {
+    aaaaaaaaaaaaaaaaaaaaaa = 1 << 0,    /* test a */
+    bbbbbbbbbbbbbbbbb = 1 << 1,    /* test b */
+    cccccccccccccc = 1 << 1,    /* test c */
+    dddddddddddddddddddddddddddddd = 1 << 2    /* test d */
+} x;
+
+/* See r303597, r303598, r309219, and r309343 */
+void
+t(void)
+{
+    /*
+     * Old indent wrapped the URL near where this sentence ends.
+     *
+     *
https://www.freebsd.org/cgi/man.cgi?query=indent&apropos=0&sektion=0&manpath=FreeBSD+12-current&arch=default&format=html
+     */
+
+    /*
+     * Old indent did not wrap to column 78
+     *
+     * aaaaaa bbbbbb cccccc dddddd eeeeee ffffff ggggg hhhhh iiiii jjjj
+     * kk
+     */
+
+    /*
+     * Old indent unnecessarily removed the star comment continuation on
+     * the next line.
+     *
+     * *test*
+     */
+
+    /*
+     * r309219 Go through linked list, freeing from the malloced (t[-1])
+     * address.
+     */
+
+    /* r309343    */
+}
+
+int
+c(void)
+{
+    if (1) {        /*- a christmas tree  *
+                                 ***
+                                ***** */
+        /*- another one *
+                   ***
+                  ***** */
+        7;
+    }
+
+    if (1)            /*- a christmas tree  *
+                             ***
+                            ***** */
+        /*- another one *
+                   ***
+                  ***** */
+        1;
+}
diff --git a/src/tools/pg_bsd_indent/tests/comments.pro b/src/tools/pg_bsd_indent/tests/comments.pro
new file mode 100644
index 0000000000..0959711b3d
--- /dev/null
+++ b/src/tools/pg_bsd_indent/tests/comments.pro
@@ -0,0 +1 @@
+-bbb
\ No newline at end of file
diff --git a/src/tools/pg_bsd_indent/tests/cppelsecom.0 b/src/tools/pg_bsd_indent/tests/cppelsecom.0
new file mode 100644
index 0000000000..79aed65115
--- /dev/null
+++ b/src/tools/pg_bsd_indent/tests/cppelsecom.0
@@ -0,0 +1,7 @@
+#if 1 /* if */
+
+#elif defined(test)        /* elif */
+
+#else /* else */
+
+#endif /* endif */
diff --git a/src/tools/pg_bsd_indent/tests/cppelsecom.0.stdout b/src/tools/pg_bsd_indent/tests/cppelsecom.0.stdout
new file mode 100644
index 0000000000..047fc3d951
--- /dev/null
+++ b/src/tools/pg_bsd_indent/tests/cppelsecom.0.stdout
@@ -0,0 +1,7 @@
+#if 1                /* if */
+
+#elif defined(test)        /* elif */
+
+#else /* else */
+
+#endif /* endif */
diff --git a/src/tools/pg_bsd_indent/tests/declarations.0 b/src/tools/pg_bsd_indent/tests/declarations.0
new file mode 100644
index 0000000000..8419494989
--- /dev/null
+++ b/src/tools/pg_bsd_indent/tests/declarations.0
@@ -0,0 +1,79 @@
+/* $FreeBSD$ */
+/* See r303570 */
+
+typedef void     (*voidptr) (int *);
+
+static const struct
+{
+    double        x;
+    double        y, z;
+} n[m + 1] =
+{
+    {
+        .0,
+        .9,
+        5
+    }
+};
+
+typedef struct Complex
+{
+    double        x;
+    double        y;
+}    Complex;
+
+void
+t1 (char *a, int b,
+    void (*fn)(void))
+{}
+
+void t2 (char *x, int y)
+{
+    int a,
+    b,
+    c;
+    int
+    *d,
+    *e,
+    *f;
+    int (*g)(),
+    (*h)(),
+    (*i)();
+    int j,
+    k,
+    l;
+    int m
+    ,n
+    ,o
+    ;
+    int        chars[ /* push the comma beyond column 74 .... */ ], x;
+}
+
+const int    int_minimum_size =
+MAXALIGN(offsetof(int, test)) + MAXIMUM_ALIGNOF;
+
+int *int_create(void)
+{
+
+}
+
+static
+_attribute_printf(1, 2)
+void
+print_error(const char *fmt,...)
+{
+
+}
+
+static LIST_HEAD(, alq) ald_active;
+static int ald_shutingdown = 0;
+struct thread *ald_thread;
+
+static int
+do_execve(
+struct thread *td,
+struct image_args *args,
+struct mac *mac_p)
+{
+
+}
diff --git a/src/tools/pg_bsd_indent/tests/declarations.0.stdout b/src/tools/pg_bsd_indent/tests/declarations.0.stdout
new file mode 100644
index 0000000000..ab5a447a8b
--- /dev/null
+++ b/src/tools/pg_bsd_indent/tests/declarations.0.stdout
@@ -0,0 +1,73 @@
+/* $FreeBSD$ */
+/* See r303570 */
+
+typedef void    (*voidptr) (int *);
+
+static const struct {
+    double        x;
+    double        y, z;
+}        n[m + 1] =
+{
+    {
+        .0,
+        .9,
+        5
+    }
+};
+
+typedef struct Complex {
+    double        x;
+    double        y;
+}        Complex;
+
+void
+t1(char *a, int b,
+   void (*fn) (void))
+{
+}
+
+void
+t2(char *x, int y)
+{
+    int        a, b, c;
+    int
+               *d, *e, *f;
+    int        (*g) (), (*h) (), (*i) ();
+    int        j, k, l;
+    int        m
+               ,n
+               ,o
+               ;
+    int        chars[ /* push the comma beyond column 74 .... */ ],
+            x;
+}
+
+const int    int_minimum_size =
+MAXALIGN(offsetof(int, test)) + MAXIMUM_ALIGNOF;
+
+int           *
+int_create(void)
+{
+
+}
+
+static
+_attribute_printf(1, 2)
+void
+print_error(const char *fmt,...)
+{
+
+}
+
+static LIST_HEAD(, alq) ald_active;
+static int    ald_shutingdown = 0;
+struct thread  *ald_thread;
+
+static int
+do_execve(
+      struct thread *td,
+      struct image_args *args,
+      struct mac *mac_p)
+{
+
+}
diff --git a/src/tools/pg_bsd_indent/tests/elsecomment.0 b/src/tools/pg_bsd_indent/tests/elsecomment.0
new file mode 100644
index 0000000000..61066c22b5
--- /dev/null
+++ b/src/tools/pg_bsd_indent/tests/elsecomment.0
@@ -0,0 +1,42 @@
+/* $FreeBSD$ */
+/* See r303484 and r309342 */
+void t(void) {
+    /* The two if statements below excercise two different code paths. */
+
+    if (1) /* a */ int a; else /* b */ int b;
+
+    if (1) /* a */
+        int a;
+    else /* b */
+        int b;
+
+    if (1) {
+
+    }
+
+
+
+    /* Old indent would remove the 3 blank lines above, awaiting "else". */
+
+    if (1) {
+        int a;
+    }
+
+
+    else if (0) {
+        int b;
+    }
+    /* test */
+    else
+        ;
+
+    if (1)
+        ;
+    else /* Old indent would get very confused here */
+    /* We also mustn't assume that there's only one comment */
+    /* before the left brace. */
+    {
+
+
+    }
+}
diff --git a/src/tools/pg_bsd_indent/tests/elsecomment.0.stdout b/src/tools/pg_bsd_indent/tests/elsecomment.0.stdout
new file mode 100644
index 0000000000..7de23be089
--- /dev/null
+++ b/src/tools/pg_bsd_indent/tests/elsecomment.0.stdout
@@ -0,0 +1,47 @@
+/* $FreeBSD$ */
+/* See r303484 and r309342 */
+void
+t(void)
+{
+    /* The two if statements below excercise two different code paths. */
+
+    if (1)            /* a */
+        int        a;
+    else            /* b */
+        int        b;
+
+    if (1)            /* a */
+        int        a;
+    else            /* b */
+        int        b;
+
+    if (1)
+    {
+
+    }
+
+
+
+    /* Old indent would remove the 3 blank lines above, awaiting "else". */
+
+    if (1)
+    {
+        int        a;
+    } else if (0)
+    {
+        int        b;
+    }
+    /* test */
+    else
+        ;
+
+    if (1)
+        ;
+    else            /* Old indent would get very confused here */
+        /* We also mustn't assume that there's only one comment */
+        /* before the left brace. */
+    {
+
+
+    }
+}
diff --git a/src/tools/pg_bsd_indent/tests/elsecomment.pro b/src/tools/pg_bsd_indent/tests/elsecomment.pro
new file mode 100644
index 0000000000..115c4768e7
--- /dev/null
+++ b/src/tools/pg_bsd_indent/tests/elsecomment.pro
@@ -0,0 +1 @@
+-bl
\ No newline at end of file
diff --git a/src/tools/pg_bsd_indent/tests/enum.0 b/src/tools/pg_bsd_indent/tests/enum.0
new file mode 100644
index 0000000000..15057dc464
--- /dev/null
+++ b/src/tools/pg_bsd_indent/tests/enum.0
@@ -0,0 +1,6 @@
+typedef enum
+{
+PREWARM_PREFETCH,                /* comment */
+PREWARM_READ,                    /* more comment */
+PREWARM_BUFFER                    /* more comment */
+} PrewarmType;
diff --git a/src/tools/pg_bsd_indent/tests/enum.0.stdout b/src/tools/pg_bsd_indent/tests/enum.0.stdout
new file mode 100644
index 0000000000..fd4653b854
--- /dev/null
+++ b/src/tools/pg_bsd_indent/tests/enum.0.stdout
@@ -0,0 +1,5 @@
+typedef enum {
+    PREWARM_PREFETCH,    /* comment */
+    PREWARM_READ,        /* more comment */
+    PREWARM_BUFFER        /* more comment */
+}        PrewarmType;
diff --git a/src/tools/pg_bsd_indent/tests/f_decls.0 b/src/tools/pg_bsd_indent/tests/f_decls.0
new file mode 100644
index 0000000000..aeef03b704
--- /dev/null
+++ b/src/tools/pg_bsd_indent/tests/f_decls.0
@@ -0,0 +1,27 @@
+char * x(void)
+{
+    type identifier;
+    type *pointer;
+    unused * value;
+    (void)unused * value;
+
+    dmax = (double)3 * 10.0;
+    dmin = (double)dmax * 10.0;
+    davg = (double)dmax * dmin;
+
+    return NULL;
+}
+
+int *
+y(void) {
+
+}
+
+int
+z(void) {
+
+}
+
+int x;
+int *y;
+int * * * * z;
diff --git a/src/tools/pg_bsd_indent/tests/f_decls.0.stdout b/src/tools/pg_bsd_indent/tests/f_decls.0.stdout
new file mode 100644
index 0000000000..bc21248552
--- /dev/null
+++ b/src/tools/pg_bsd_indent/tests/f_decls.0.stdout
@@ -0,0 +1,30 @@
+char           *
+x(void)
+{
+    type        identifier;
+    type           *pointer;
+    unused           *value;
+    (void)unused * value;
+
+    dmax = (double)3 * 10.0;
+    dmin = (double)dmax * 10.0;
+    davg = (double)dmax * dmin;
+
+    return NULL;
+}
+
+int           *
+y(void)
+{
+
+}
+
+int
+z(void)
+{
+
+}
+
+int        x;
+int           *y;
+int        ****z;
diff --git a/src/tools/pg_bsd_indent/tests/float.0 b/src/tools/pg_bsd_indent/tests/float.0
new file mode 100644
index 0000000000..91f017fc1c
--- /dev/null
+++ b/src/tools/pg_bsd_indent/tests/float.0
@@ -0,0 +1,6 @@
+/* $FreeBSD$ */
+/* See r303499 */
+void t(void) {
+    unsigned long x = 314UL;
+    float y = 3.14f;
+}
diff --git a/src/tools/pg_bsd_indent/tests/float.0.stdout b/src/tools/pg_bsd_indent/tests/float.0.stdout
new file mode 100644
index 0000000000..0f213182ff
--- /dev/null
+++ b/src/tools/pg_bsd_indent/tests/float.0.stdout
@@ -0,0 +1,8 @@
+/* $FreeBSD$ */
+/* See r303499 */
+void
+t(void)
+{
+    unsigned long    x = 314UL;
+    float        y = 3.14f;
+}
diff --git a/src/tools/pg_bsd_indent/tests/label.0 b/src/tools/pg_bsd_indent/tests/label.0
new file mode 100644
index 0000000000..7798a4d5c2
--- /dev/null
+++ b/src/tools/pg_bsd_indent/tests/label.0
@@ -0,0 +1,13 @@
+/* $FreeBSD$ */
+/* See r303489 */
+void t(void) {
+    switch (1)
+    {
+        case 1:    /* test */
+        case 2:        /* test */
+    }
+CLEANUP:
+    ;
+V: ;
+U: ;
+}
diff --git a/src/tools/pg_bsd_indent/tests/label.0.stdout b/src/tools/pg_bsd_indent/tests/label.0.stdout
new file mode 100644
index 0000000000..22ec12272a
--- /dev/null
+++ b/src/tools/pg_bsd_indent/tests/label.0.stdout
@@ -0,0 +1,14 @@
+/* $FreeBSD$ */
+/* See r303489 */
+void
+t(void)
+{
+        switch (1) {
+        case 1:                 /* test */
+        case 2:                 /* test */
+        }
+CLEANUP:
+        ;
+V:      ;
+U:      ;
+}
diff --git a/src/tools/pg_bsd_indent/tests/label.pro b/src/tools/pg_bsd_indent/tests/label.pro
new file mode 100644
index 0000000000..75d1fe1a12
--- /dev/null
+++ b/src/tools/pg_bsd_indent/tests/label.pro
@@ -0,0 +1 @@
+-nut
\ No newline at end of file
diff --git a/src/tools/pg_bsd_indent/tests/list_head.0 b/src/tools/pg_bsd_indent/tests/list_head.0
new file mode 100644
index 0000000000..35874ebc4e
--- /dev/null
+++ b/src/tools/pg_bsd_indent/tests/list_head.0
@@ -0,0 +1,15 @@
+/* $FreeBSD$ */
+/* See r309380 */
+static int
+do_execve(struct thread *td,
+struct image_args *args,
+struct mac *mac_p)
+{
+
+}
+
+static LIST_HEAD(, alq) ald_active;
+static int ald_shuttingdown = 0;
+struct thread *ald_thread;
+
+
diff --git a/src/tools/pg_bsd_indent/tests/list_head.0.stdout b/src/tools/pg_bsd_indent/tests/list_head.0.stdout
new file mode 100644
index 0000000000..2ebcca5730
--- /dev/null
+++ b/src/tools/pg_bsd_indent/tests/list_head.0.stdout
@@ -0,0 +1,13 @@
+/* $FreeBSD$ */
+/* See r309380 */
+static int
+do_execve(struct thread *td,
+      struct image_args *args,
+      struct mac *mac_p)
+{
+
+}
+
+static LIST_HEAD(, alq) ald_active;
+static int    ald_shuttingdown = 0;
+struct thread  *ald_thread;
diff --git a/src/tools/pg_bsd_indent/tests/nsac.0 b/src/tools/pg_bsd_indent/tests/nsac.0
new file mode 100644
index 0000000000..449eadf3ae
--- /dev/null
+++ b/src/tools/pg_bsd_indent/tests/nsac.0
@@ -0,0 +1,4 @@
+/* $FreeBSD$ */
+void t(void) {
+    int a = (double) 8;
+}
diff --git a/src/tools/pg_bsd_indent/tests/nsac.0.stdout b/src/tools/pg_bsd_indent/tests/nsac.0.stdout
new file mode 100644
index 0000000000..78f3b28757
--- /dev/null
+++ b/src/tools/pg_bsd_indent/tests/nsac.0.stdout
@@ -0,0 +1,6 @@
+/* $FreeBSD$ */
+void
+t(void)
+{
+    int        a = (double)8;
+}
diff --git a/src/tools/pg_bsd_indent/tests/nsac.pro b/src/tools/pg_bsd_indent/tests/nsac.pro
new file mode 100644
index 0000000000..6bcbd2b1ff
--- /dev/null
+++ b/src/tools/pg_bsd_indent/tests/nsac.pro
@@ -0,0 +1 @@
+-nsac
\ No newline at end of file
diff --git a/src/tools/pg_bsd_indent/tests/offsetof.0 b/src/tools/pg_bsd_indent/tests/offsetof.0
new file mode 100644
index 0000000000..078db19c29
--- /dev/null
+++ b/src/tools/pg_bsd_indent/tests/offsetof.0
@@ -0,0 +1,5 @@
+/* $FreeBSD$ */
+/* See r303718 */
+void t(void) {
+    int n = malloc(offsetof(struct s, f) + 1);
+}
diff --git a/src/tools/pg_bsd_indent/tests/offsetof.0.stdout b/src/tools/pg_bsd_indent/tests/offsetof.0.stdout
new file mode 100644
index 0000000000..199bf0fa07
--- /dev/null
+++ b/src/tools/pg_bsd_indent/tests/offsetof.0.stdout
@@ -0,0 +1,7 @@
+/* $FreeBSD$ */
+/* See r303718 */
+void
+t(void)
+{
+    int        n = malloc(offsetof(struct s, f) + 1);
+}
diff --git a/src/tools/pg_bsd_indent/tests/parens.0 b/src/tools/pg_bsd_indent/tests/parens.0
new file mode 100644
index 0000000000..366536ce82
--- /dev/null
+++ b/src/tools/pg_bsd_indent/tests/parens.0
@@ -0,0 +1,26 @@
+typedef void (*pgstat_page) (pgstattuple_type *, Relation, BlockNumber,
+                                         BufferAccessStrategy);
+
+typedef char (*get_relation_stats_hook_type) (int *root,
+                                                          unsigned *rte,
+                                                          char attnum,
+                                                  float *vardata);
+
+void similarity_dist(int m)
+{
+    char        chars[BIGGEST(BIGGEST(TZ_MAX_CHARS + 1, 3 /* sizeof gmt */ ),
+                                      *here)];
+
+    float4        res = DatumGetFloat4(FunctionCall2(similarity,
+                                                   (here),
+                                                   here));
+
+    if (es->verbose)
+    {
+        char       *sql = strVal(list_nth(fdw_private,
+                                          here));
+    }
+
+    rb->allocfunc(1);
+    rb2.allocfunc(7);
+}
diff --git a/src/tools/pg_bsd_indent/tests/parens.0.stdout b/src/tools/pg_bsd_indent/tests/parens.0.stdout
new file mode 100644
index 0000000000..2258f8d2f0
--- /dev/null
+++ b/src/tools/pg_bsd_indent/tests/parens.0.stdout
@@ -0,0 +1,26 @@
+typedef void (*pgstat_page) (pgstattuple_type *, Relation, BlockNumber,
+                             BufferAccessStrategy);
+
+typedef char (*get_relation_stats_hook_type) (int *root,
+                                              unsigned *rte,
+                                              char attnum,
+                                              float *vardata);
+
+void
+similarity_dist(int m)
+{
+    char        chars[BIGGEST(BIGGEST(TZ_MAX_CHARS + 1, 3 /* sizeof gmt */ ),
+                              *here)];
+
+    float4        res = DatumGetFloat4(FunctionCall2(similarity,
+                                                   (here),
+                                                   here));
+
+    if (es->verbose) {
+        char       *sql = strVal(list_nth(fdw_private,
+                                          here));
+    }
+
+    rb->allocfunc(1);
+    rb2.allocfunc(7);
+}
diff --git a/src/tools/pg_bsd_indent/tests/parens.pro b/src/tools/pg_bsd_indent/tests/parens.pro
new file mode 100644
index 0000000000..e860911a11
--- /dev/null
+++ b/src/tools/pg_bsd_indent/tests/parens.pro
@@ -0,0 +1 @@
+-ts4 -i4 -di12 -Tallocfunc
diff --git a/src/tools/pg_bsd_indent/tests/sac.0 b/src/tools/pg_bsd_indent/tests/sac.0
new file mode 100644
index 0000000000..449eadf3ae
--- /dev/null
+++ b/src/tools/pg_bsd_indent/tests/sac.0
@@ -0,0 +1,4 @@
+/* $FreeBSD$ */
+void t(void) {
+    int a = (double) 8;
+}
diff --git a/src/tools/pg_bsd_indent/tests/sac.0.stdout b/src/tools/pg_bsd_indent/tests/sac.0.stdout
new file mode 100644
index 0000000000..1849b28337
--- /dev/null
+++ b/src/tools/pg_bsd_indent/tests/sac.0.stdout
@@ -0,0 +1,6 @@
+/* $FreeBSD$ */
+void
+t(void)
+{
+    int        a = (double) 8;
+}
diff --git a/src/tools/pg_bsd_indent/tests/sac.pro b/src/tools/pg_bsd_indent/tests/sac.pro
new file mode 100644
index 0000000000..2b21505c72
--- /dev/null
+++ b/src/tools/pg_bsd_indent/tests/sac.pro
@@ -0,0 +1 @@
+-sac
\ No newline at end of file
diff --git a/src/tools/pg_bsd_indent/tests/struct.0 b/src/tools/pg_bsd_indent/tests/struct.0
new file mode 100644
index 0000000000..83142bfb19
--- /dev/null
+++ b/src/tools/pg_bsd_indent/tests/struct.0
@@ -0,0 +1,21 @@
+/* $FreeBSD$ */
+
+int f(struct x *a);
+
+/* See r303485 */
+void
+t(void)
+{
+    static const struct {
+        int    a;
+        int    b;
+    } c[] = {
+        { D, E },
+        { F, G }
+    };
+}
+
+void u(struct x a) {
+    int b;
+    struct y c = (struct y *)&a;
+}
diff --git a/src/tools/pg_bsd_indent/tests/struct.0.stdout b/src/tools/pg_bsd_indent/tests/struct.0.stdout
new file mode 100644
index 0000000000..3861312865
--- /dev/null
+++ b/src/tools/pg_bsd_indent/tests/struct.0.stdout
@@ -0,0 +1,23 @@
+/* $FreeBSD$ */
+
+int        f(struct x *a);
+
+/* See r303485 */
+void
+t(void)
+{
+    static const struct {
+        int        a;
+        int        b;
+    }        c[] = {
+        {D, E},
+        {F, G}
+    };
+}
+
+void
+u(struct x a)
+{
+    int        b;
+    struct y    c = (struct y *)&a;
+}
diff --git a/src/tools/pg_bsd_indent/tests/surplusbad.0 b/src/tools/pg_bsd_indent/tests/surplusbad.0
new file mode 100644
index 0000000000..07d07026db
--- /dev/null
+++ b/src/tools/pg_bsd_indent/tests/surplusbad.0
@@ -0,0 +1,9 @@
+/* $FreeBSD$ */
+/* See r303599 */
+#if defined(__i386__)
+int a;
+#elif defined(__amd64__)
+int b;
+#else
+#error "Port me"
+#endif
diff --git a/src/tools/pg_bsd_indent/tests/surplusbad.0.stdout b/src/tools/pg_bsd_indent/tests/surplusbad.0.stdout
new file mode 100644
index 0000000000..b288970fb9
--- /dev/null
+++ b/src/tools/pg_bsd_indent/tests/surplusbad.0.stdout
@@ -0,0 +1,9 @@
+/* $FreeBSD$ */
+/* See r303599 */
+#if defined(__i386__)
+int        a;
+#elif defined(__amd64__)
+int        b;
+#else
+#error "Port me"
+#endif
diff --git a/src/tools/pg_bsd_indent/tests/surplusbad.pro b/src/tools/pg_bsd_indent/tests/surplusbad.pro
new file mode 100644
index 0000000000..e828c8191c
--- /dev/null
+++ b/src/tools/pg_bsd_indent/tests/surplusbad.pro
@@ -0,0 +1 @@
+-bad
\ No newline at end of file
diff --git a/src/tools/pg_bsd_indent/tests/types_from_file.0 b/src/tools/pg_bsd_indent/tests/types_from_file.0
new file mode 100644
index 0000000000..6efca24fe1
--- /dev/null
+++ b/src/tools/pg_bsd_indent/tests/types_from_file.0
@@ -0,0 +1,3 @@
+/* $FreeBSD$ */
+/* See r303735 */
+void t(a *x, b *y, c *z);
diff --git a/src/tools/pg_bsd_indent/tests/types_from_file.0.stdout
b/src/tools/pg_bsd_indent/tests/types_from_file.0.stdout
new file mode 100644
index 0000000000..8776ca6ba8
--- /dev/null
+++ b/src/tools/pg_bsd_indent/tests/types_from_file.0.stdout
@@ -0,0 +1,3 @@
+/* $FreeBSD$ */
+/* See r303735 */
+void        t(a *x, b *y, c * z);
diff --git a/src/tools/pg_bsd_indent/tests/types_from_file.list b/src/tools/pg_bsd_indent/tests/types_from_file.list
new file mode 100644
index 0000000000..5f733616b1
--- /dev/null
+++ b/src/tools/pg_bsd_indent/tests/types_from_file.list
@@ -0,0 +1,2 @@
+b
+a
\ No newline at end of file
diff --git a/src/tools/pg_bsd_indent/tests/types_from_file.pro b/src/tools/pg_bsd_indent/tests/types_from_file.pro
new file mode 100644
index 0000000000..39eb911980
--- /dev/null
+++ b/src/tools/pg_bsd_indent/tests/types_from_file.pro
@@ -0,0 +1 @@
+-Utypes_from_file.list
\ No newline at end of file
diff --git a/src/tools/pg_bsd_indent/tests/wchar.0 b/src/tools/pg_bsd_indent/tests/wchar.0
new file mode 100644
index 0000000000..9910e77857
--- /dev/null
+++ b/src/tools/pg_bsd_indent/tests/wchar.0
@@ -0,0 +1,6 @@
+/* $FreeBSD$ */
+/* See r309220 */
+#include <wchar.h>
+
+wchar_t *x = L"test";
+wchar_t y = L't';
diff --git a/src/tools/pg_bsd_indent/tests/wchar.0.stdout b/src/tools/pg_bsd_indent/tests/wchar.0.stdout
new file mode 100644
index 0000000000..92774abfdd
--- /dev/null
+++ b/src/tools/pg_bsd_indent/tests/wchar.0.stdout
@@ -0,0 +1,6 @@
+/* $FreeBSD$ */
+/* See r309220 */
+#include <wchar.h>
+
+wchar_t           *x = L"test";
+wchar_t        y = L't';
--
2.31.1

From da770680de94ba589cb29310f42f71c2373e81cf Mon Sep 17 00:00:00 2001
From: Tom Lane <tgl@sss.pgh.pa.us>
Date: Sat, 11 Feb 2023 14:08:57 -0500
Subject: [PATCH v3 2/3] Sync pg_bsd_indent's copyright notices with Postgres
 practice.

To avoid confusion, make the copyright notices in these files
match the 3-clause form of the BSD license, per the blanket
policy update that UC Berkeley issued years ago.

Discussion: https://postgr.es/m/20230123011002.fzcaa3krql3mqsfn@awork3.anarazel.de
---
 src/tools/pg_bsd_indent/README         | 37 ++++++++++++++++++++++++++
 src/tools/pg_bsd_indent/args.c         |  6 +----
 src/tools/pg_bsd_indent/indent.c       |  6 +----
 src/tools/pg_bsd_indent/indent_codes.h |  6 +----
 src/tools/pg_bsd_indent/indent_globs.h |  6 +----
 src/tools/pg_bsd_indent/io.c           |  6 +----
 src/tools/pg_bsd_indent/lexi.c         |  6 +----
 src/tools/pg_bsd_indent/parse.c        |  6 +----
 src/tools/pg_bsd_indent/pr_comment.c   |  6 +----
 9 files changed, 45 insertions(+), 40 deletions(-)

diff --git a/src/tools/pg_bsd_indent/README b/src/tools/pg_bsd_indent/README
index 33d016db62..846855d318 100644
--- a/src/tools/pg_bsd_indent/README
+++ b/src/tools/pg_bsd_indent/README
@@ -1,3 +1,40 @@
+The FreeBSD originals of the files in this directory bear the
+"4-clause" version of the BSD license.  We have removed the
+"advertising" clauses, as per UC Berkeley's directive here:
+ftp://ftp.cs.berkeley.edu/pub/4bsd/README.Impt.License.Change
+which reads:
+
+July 22, 1999
+
+To All Licensees, Distributors of Any Version of BSD:
+
+As you know, certain of the Berkeley Software Distribution ("BSD") source
+code files require that further distributions of products containing all or
+portions of the software, acknowledge within their advertising materials
+that such products contain software developed by UC Berkeley and its
+contributors.
+
+Specifically, the provision reads:
+
+"     * 3. All advertising materials mentioning features or use of this software
+      *    must display the following acknowledgement:
+      *    This product includes software developed by the University of
+      *    California, Berkeley and its contributors."
+
+Effective immediately, licensees and distributors are no longer required to
+include the acknowledgement within advertising materials.  Accordingly, the
+foregoing paragraph of those BSD Unix files containing it is hereby deleted
+in its entirety.
+
+William Hoskins
+Director, Office of Technology Licensing
+University of California, Berkeley
+
+----------
+
+What follows is the README file as maintained by FreeBSD indent.
+
+----------

   $FreeBSD: head/usr.bin/indent/README 105244 2002-10-16 13:58:39Z charnier $

diff --git a/src/tools/pg_bsd_indent/args.c b/src/tools/pg_bsd_indent/args.c
index 1c83f57049..b18eab5d39 100644
--- a/src/tools/pg_bsd_indent/args.c
+++ b/src/tools/pg_bsd_indent/args.c
@@ -12,11 +12,7 @@
  * 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. All advertising materials mentioning features or use of this software
- *    must display the following acknowledgement:
- *    This product includes software developed by the University of
- *    California, Berkeley and its contributors.
- * 4. Neither the name of the University nor the names of its contributors
+ * 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.
  *
diff --git a/src/tools/pg_bsd_indent/indent.c b/src/tools/pg_bsd_indent/indent.c
index d3a0ecefe9..0024993844 100644
--- a/src/tools/pg_bsd_indent/indent.c
+++ b/src/tools/pg_bsd_indent/indent.c
@@ -12,11 +12,7 @@
  * 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. All advertising materials mentioning features or use of this software
- *    must display the following acknowledgement:
- *    This product includes software developed by the University of
- *    California, Berkeley and its contributors.
- * 4. Neither the name of the University nor the names of its contributors
+ * 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.
  *
diff --git a/src/tools/pg_bsd_indent/indent_codes.h b/src/tools/pg_bsd_indent/indent_codes.h
index 24c43fa420..6576bef75d 100644
--- a/src/tools/pg_bsd_indent/indent_codes.h
+++ b/src/tools/pg_bsd_indent/indent_codes.h
@@ -12,11 +12,7 @@
  * 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. All advertising materials mentioning features or use of this software
- *    must display the following acknowledgement:
- *    This product includes software developed by the University of
- *    California, Berkeley and its contributors.
- * 4. Neither the name of the University nor the names of its contributors
+ * 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.
  *
diff --git a/src/tools/pg_bsd_indent/indent_globs.h b/src/tools/pg_bsd_indent/indent_globs.h
index 398784b3f4..917961bd3d 100644
--- a/src/tools/pg_bsd_indent/indent_globs.h
+++ b/src/tools/pg_bsd_indent/indent_globs.h
@@ -12,11 +12,7 @@
  * 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. All advertising materials mentioning features or use of this software
- *    must display the following acknowledgement:
- *    This product includes software developed by the University of
- *    California, Berkeley and its contributors.
- * 4. Neither the name of the University nor the names of its contributors
+ * 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.
  *
diff --git a/src/tools/pg_bsd_indent/io.c b/src/tools/pg_bsd_indent/io.c
index 3ce8bfb70c..4149424294 100644
--- a/src/tools/pg_bsd_indent/io.c
+++ b/src/tools/pg_bsd_indent/io.c
@@ -12,11 +12,7 @@
  * 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. All advertising materials mentioning features or use of this software
- *    must display the following acknowledgement:
- *    This product includes software developed by the University of
- *    California, Berkeley and its contributors.
- * 4. Neither the name of the University nor the names of its contributors
+ * 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.
  *
diff --git a/src/tools/pg_bsd_indent/lexi.c b/src/tools/pg_bsd_indent/lexi.c
index f01596a870..943bf7ce6b 100644
--- a/src/tools/pg_bsd_indent/lexi.c
+++ b/src/tools/pg_bsd_indent/lexi.c
@@ -12,11 +12,7 @@
  * 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. All advertising materials mentioning features or use of this software
- *    must display the following acknowledgement:
- *    This product includes software developed by the University of
- *    California, Berkeley and its contributors.
- * 4. Neither the name of the University nor the names of its contributors
+ * 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.
  *
diff --git a/src/tools/pg_bsd_indent/parse.c b/src/tools/pg_bsd_indent/parse.c
index bf6b1697f9..e707da639c 100644
--- a/src/tools/pg_bsd_indent/parse.c
+++ b/src/tools/pg_bsd_indent/parse.c
@@ -12,11 +12,7 @@
  * 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. All advertising materials mentioning features or use of this software
- *    must display the following acknowledgement:
- *    This product includes software developed by the University of
- *    California, Berkeley and its contributors.
- * 4. Neither the name of the University nor the names of its contributors
+ * 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.
  *
diff --git a/src/tools/pg_bsd_indent/pr_comment.c b/src/tools/pg_bsd_indent/pr_comment.c
index b0eacac1bb..a9572b39ff 100644
--- a/src/tools/pg_bsd_indent/pr_comment.c
+++ b/src/tools/pg_bsd_indent/pr_comment.c
@@ -12,11 +12,7 @@
  * 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. All advertising materials mentioning features or use of this software
- *    must display the following acknowledgement:
- *    This product includes software developed by the University of
- *    California, Berkeley and its contributors.
- * 4. Neither the name of the University nor the names of its contributors
+ * 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.
  *
--
2.31.1

From 3d6bd52162c733bf68e702efae569a945a630e3d Mon Sep 17 00:00:00 2001
From: Tom Lane <tgl@sss.pgh.pa.us>
Date: Sat, 11 Feb 2023 18:38:14 -0500
Subject: [PATCH v3 3/3] Integrate pg_bsd_indent into our build/test
 infrastructure.

Update the Makefile and build directions for in-tree build,
and add Meson build infrastructure.  Also convert the ad-hoc
test target into a TAP test.

Currently, the Make build system will not build pg_bsd_indent
by default, while the Meson system will.  Both will test it
during "make check-world" or "ninja test".  Neither will install
it automatically.  (We might change some of these decisions later.)

Also fix a couple of portability nits noted during early testing.

Also, exclude pg_bsd_indent from pgindent's purview; at least for
now, we'll leave it formatted similarly to the FreeBSD original.

Tom Lane and Andres Freund

Discussion: https://postgr.es/m/20200812223409.6di3y2qsnvynao7a@alap3.anarazel.de
---
 GNUmakefile.in                                |  2 +-
 src/Makefile                                  |  2 +
 src/meson.build                               |  2 +
 src/tools/pg_bsd_indent/.gitignore            | 12 +---
 src/tools/pg_bsd_indent/Makefile              | 62 ++++++++++++-------
 src/tools/pg_bsd_indent/README                | 37 +++++++++++
 src/tools/pg_bsd_indent/README.pg_bsd_indent  | 30 ---------
 src/tools/pg_bsd_indent/args.c                |  2 +-
 src/tools/pg_bsd_indent/indent.c              |  2 +-
 src/tools/pg_bsd_indent/indent.h              |  2 +-
 src/tools/pg_bsd_indent/meson.build           | 40 ++++++++++++
 .../pg_bsd_indent/t/001_pg_bsd_indent.pl      | 53 ++++++++++++++++
 src/tools/pgindent/exclude_file_patterns      |  4 ++
 13 files changed, 186 insertions(+), 64 deletions(-)
 delete mode 100644 src/tools/pg_bsd_indent/README.pg_bsd_indent
 create mode 100644 src/tools/pg_bsd_indent/meson.build
 create mode 100644 src/tools/pg_bsd_indent/t/001_pg_bsd_indent.pl

diff --git a/GNUmakefile.in b/GNUmakefile.in
index 5434467381..9c18c56233 100644
--- a/GNUmakefile.in
+++ b/GNUmakefile.in
@@ -68,7 +68,7 @@ check check-tests installcheck installcheck-parallel installcheck-tests: CHECKPR
 check check-tests installcheck installcheck-parallel installcheck-tests: submake-generated-headers
     $(MAKE) -C src/test/regress $@

-$(call recurse,check-world,src/test src/pl src/interfaces contrib src/bin,check)
+$(call recurse,check-world,src/test src/pl src/interfaces contrib src/bin src/tools/pg_bsd_indent,check)
 $(call recurse,checkprep,  src/test src/pl src/interfaces contrib src/bin)

 $(call recurse,installcheck-world,src/test src/pl src/interfaces contrib src/bin,installcheck)
diff --git a/src/Makefile b/src/Makefile
index 79e274a476..94649c36c7 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -66,11 +66,13 @@ clean:
     $(MAKE) -C test $@
     $(MAKE) -C tutorial NO_PGXS=1 $@
     $(MAKE) -C test/isolation $@
+    $(MAKE) -C tools/pg_bsd_indent $@

 distclean maintainer-clean:
     $(MAKE) -C test $@
     $(MAKE) -C tutorial NO_PGXS=1 $@
     $(MAKE) -C test/isolation $@
+    $(MAKE) -C tools/pg_bsd_indent $@
     rm -f Makefile.port Makefile.global


diff --git a/src/meson.build b/src/meson.build
index 80fd2823a9..bceeca70f9 100644
--- a/src/meson.build
+++ b/src/meson.build
@@ -13,6 +13,8 @@ subdir('pl')

 subdir('interfaces')

+subdir('tools/pg_bsd_indent')
+

 ### Generate a Makefile.global that's complete enough for PGXS to work.
 #
diff --git a/src/tools/pg_bsd_indent/.gitignore b/src/tools/pg_bsd_indent/.gitignore
index 4c5d8dc691..b27e3610d5 100644
--- a/src/tools/pg_bsd_indent/.gitignore
+++ b/src/tools/pg_bsd_indent/.gitignore
@@ -1,10 +1,4 @@
-# Global excludes across all subdirectories
-*.o
-*.obj
-*.exe
-
-# Local excludes in root directory
 /pg_bsd_indent
-/*.out
-/*.list
-/tests.diff
+# Generated by test suite
+/log/
+/tmp_check/
diff --git a/src/tools/pg_bsd_indent/Makefile b/src/tools/pg_bsd_indent/Makefile
index ee046f36f0..ee3d494f40 100644
--- a/src/tools/pg_bsd_indent/Makefile
+++ b/src/tools/pg_bsd_indent/Makefile
@@ -1,35 +1,55 @@
 #-------------------------------------------------------------------------
 #
-# Makefile for pg_bsd_indent
+# src/tools/pg_bsd_indent/Makefile
 #
-# Copyright (c) 2017, PostgreSQL Global Development Group
+# Copyright (c) 2017-2023, PostgreSQL Global Development Group
 #
 #-------------------------------------------------------------------------

 PGFILEDESC = "pg_bsd_indent - indent C code nicely"
 PGAPPICON = win32

-PROGRAM = pg_bsd_indent
-OBJS    = args.o err.o indent.o io.o lexi.o parse.o pr_comment.o $(WIN32RES)
+subdir = src/tools/pg_bsd_indent
+top_builddir = ../../..
+include $(top_builddir)/src/Makefile.global

-# clean junk left behind by "make test"
-EXTRA_CLEAN = *.out *.list tests.diff
+OBJS = \
+    $(WIN32RES) \
+    args.o \
+    err.o \
+    indent.o \
+    io.o \
+    lexi.o \
+    parse.o \
+    pr_comment.o

-PG_CONFIG = pg_config
-PGXS := $(shell $(PG_CONFIG) --pgxs)
-include $(PGXS)
+all: pg_bsd_indent

-# pgxs.mk assumes too much about what "make check" means, so call it "test"
+pg_bsd_indent: $(OBJS) | submake-libpgport
+    $(CC) $(CFLAGS) $^ $(LDFLAGS) $(LDFLAGS_EX) $(LIBS) -o $@$(X)
+
+install: all installdirs
+    $(INSTALL_PROGRAM) pg_bsd_indent$(X) '$(DESTDIR)$(bindir)/pg_bsd_indent$(X)'
+
+installdirs:
+    $(MKDIR_P) '$(DESTDIR)$(bindir)'
+
+uninstall:
+    rm -f '$(DESTDIR)$(bindir)/pg_bsd_indent$(X)'
+
+clean distclean maintainer-clean:
+    rm -f pg_bsd_indent$(X) $(OBJS)
+    rm -rf log/ tmp_check/
+
+check:
+    $(prove_check)
+
+installcheck:
+    $(prove_installcheck)
+
+# Provide this alternate test name to allow testing pg_bsd_indent
+# without building all of the surrounding Postgres installation.
 .PHONY: test

-test: $(PROGRAM)
-    @rm -f tests.diff
-    @cp $(srcdir)/tests/*.list .
-    @for testsrc in $(srcdir)/tests/*.0; do \
-        test=`basename "$$testsrc" .0`; \
-        ./$(PROGRAM) $$testsrc $$test.out -P$(srcdir)/tests/$$test.pro || echo FAILED >>$$test.out; \
-        diff -u $$testsrc.stdout $$test.out >>tests.diff 2>&1 || true; \
-    done
-    @cat tests.diff
-    @test '!' -s tests.diff
-    @echo Tests complete.
+test: pg_bsd_indent
+    $(prove_installcheck)
diff --git a/src/tools/pg_bsd_indent/README b/src/tools/pg_bsd_indent/README
index 846855d318..992d4fce61 100644
--- a/src/tools/pg_bsd_indent/README
+++ b/src/tools/pg_bsd_indent/README
@@ -1,3 +1,40 @@
+src/tools/pg_bsd_indent/README
+
+This is a lightly modified version of the "indent" program maintained
+by the FreeBSD project.  The modifications are mostly to make it portable
+to non-BSD-ish platforms, though we do have one formatting switch we
+couldn't convince upstream to take.
+
+To build it, configure the surrounding Postgres source tree,
+then run "make" in this directory.
+Optionally, run "make test" for some simple tests.
+
+You'll need to install pg_bsd_indent somewhere in your PATH before
+using it.  Most likely, if you're a developer, you don't want to
+put it in the same place as where the surrounding Postgres build
+gets installed.  Therefore, do this part with something like
+
+    make install prefix=/usr/local
+
+If you are using Meson to build, the standard build targets will
+build pg_bsd_indent and also test it, but there is not currently
+provision for installing it anywhere.  Manually copy the built
+executable from build/src/tools/pg_bsd_indent/pg_bsd_indent to
+wherever you want to put it.
+
+
+If you happen to be hacking upon the indent source code, the closest
+approximation to the existing indentation style seems to be
+
+    ./pg_bsd_indent -i4 -l79 -di12 -nfc1 -nlp -sac somefile.c
+
+although this has by no means been rigorously adhered to.
+(What was that saw about the shoemaker's children?)
+We're not planning to re-indent to Postgres style, because that
+would make it difficult to compare to the FreeBSD sources.
+
+----------
+
 The FreeBSD originals of the files in this directory bear the
 "4-clause" version of the BSD license.  We have removed the
 "advertising" clauses, as per UC Berkeley's directive here:
diff --git a/src/tools/pg_bsd_indent/README.pg_bsd_indent b/src/tools/pg_bsd_indent/README.pg_bsd_indent
deleted file mode 100644
index 85c3dcac1c..0000000000
--- a/src/tools/pg_bsd_indent/README.pg_bsd_indent
+++ /dev/null
@@ -1,30 +0,0 @@
-pg_bsd_indent
-
-This is a lightly modified version of the "indent" program maintained
-by the FreeBSD project.  The modifications are mostly to make it portable
-to non-BSD-ish platforms, though we do have one formatting switch we
-couldn't convince upstream to take.
-
-To build it, you will need a Postgres installation, version 9.5 or newer.
-(Once built, the program doesn't depend on that installation.)
-
-To build, just say "make"; or if pg_config from your Postgres installation
-isn't in your PATH, say
-    make PG_CONFIG=path/to/pg_config
-Optionally, run "make test" for some simple sanity checks.
-
-To install, copy pg_bsd_indent to somewhere in your usual PATH.
-(If you say "make install", it will try to put it in your Postgres
-installation directory, which is most likely not what you want for
-long-term use.)
-
-TODO: add build support and instructions for Windows
-
-
-If you happen to be hacking upon the indent source code, the closest
-approximation to the existing indentation style seems to be
-
-    ./pg_bsd_indent -i4 -l79 -di12 -nfc1 -nlp -sac somefile.c
-
-although this has by no means been rigorously adhered to.
-(What was that saw about the shoemaker's children?)
diff --git a/src/tools/pg_bsd_indent/args.c b/src/tools/pg_bsd_indent/args.c
index b18eab5d39..d08b086a88 100644
--- a/src/tools/pg_bsd_indent/args.c
+++ b/src/tools/pg_bsd_indent/args.c
@@ -176,7 +176,7 @@ void
 set_profile(const char *profile_name)
 {
     FILE *f;
-    char fname[PATH_MAX];
+    char fname[MAXPGPATH];
     static char prof[] = ".indent.pro";

     if (profile_name == NULL)
diff --git a/src/tools/pg_bsd_indent/indent.c b/src/tools/pg_bsd_indent/indent.c
index 0024993844..34205f2ead 100644
--- a/src/tools/pg_bsd_indent/indent.c
+++ b/src/tools/pg_bsd_indent/indent.c
@@ -60,7 +60,7 @@ const char *in_name = "Standard Input";    /* will always point to name of input
                      * file */
 const char *out_name = "Standard Output";    /* will always point to name
                          * of output file */
-char        bakfile[MAXPATHLEN] = "";
+char        bakfile[MAXPGPATH] = "";

 int
 main(int argc, char **argv)
diff --git a/src/tools/pg_bsd_indent/indent.h b/src/tools/pg_bsd_indent/indent.h
index 1708dbc19f..d9fff8ccd6 100644
--- a/src/tools/pg_bsd_indent/indent.h
+++ b/src/tools/pg_bsd_indent/indent.h
@@ -28,7 +28,7 @@
 __FBSDID("$FreeBSD: head/usr.bin/indent/indent.h 303746 2016-08-04 15:27:09Z pfg $");
 #endif

-#define nitems(array) (sizeof (array) / sizeof (array[0]))
+#define    nitems(x)    (sizeof((x)) / sizeof((x)[0]))

 void    add_typename(const char *);
 void    alloc_typenames(void);
diff --git a/src/tools/pg_bsd_indent/meson.build b/src/tools/pg_bsd_indent/meson.build
new file mode 100644
index 0000000000..5545c097bf
--- /dev/null
+++ b/src/tools/pg_bsd_indent/meson.build
@@ -0,0 +1,40 @@
+# Copyright (c) 2022-2023, PostgreSQL Global Development Group
+
+pg_bsd_indent_sources = files(
+  'args.c',
+  'err.c',
+  'indent.c',
+  'io.c',
+  'lexi.c',
+  'parse.c',
+  'pr_comment.c',
+)
+
+if host_system == 'windows'
+  pg_bsd_indent_sources += rc_bin_gen.process(win32ver_rc, extra_args: [
+    '--NAME', 'pg_bsd_indent',
+    '--FILEDESC', 'pg_bsd_indent - indent C code nicely'])
+endif
+
+pg_bsd_indent = executable('pg_bsd_indent',
+  pg_bsd_indent_sources,
+  dependencies: [frontend_code],
+  include_directories: include_directories('.'),
+  kwargs: default_bin_args + {
+    'install': false,
+# possibly at some point do this:
+#   'install_dir': dir_pgxs / 'src/tools/pg_bsd_indent',
+  },
+)
+bin_targets += pg_bsd_indent
+
+tests += {
+  'name': 'pg_bsd_indent',
+  'sd': meson.current_source_dir(),
+  'bd': meson.current_build_dir(),
+  'tap': {
+    'tests': [
+      't/001_pg_bsd_indent.pl',
+    ],
+  },
+}
diff --git a/src/tools/pg_bsd_indent/t/001_pg_bsd_indent.pl b/src/tools/pg_bsd_indent/t/001_pg_bsd_indent.pl
new file mode 100644
index 0000000000..b40b3fdbbf
--- /dev/null
+++ b/src/tools/pg_bsd_indent/t/001_pg_bsd_indent.pl
@@ -0,0 +1,53 @@
+# pg_bsd_indent: some simple tests
+
+# The test cases come from FreeBSD upstream, but this test scaffolding is ours.
+# Copyright (c) 2017-2023, PostgreSQL Global Development Group
+
+use strict;
+use warnings;
+
+use Cwd qw(getcwd);
+use File::Copy "cp";
+use File::Spec;
+
+use PostgreSQL::Test::Utils;
+use Test::More;
+
+# We expect to be started in the source directory (even in a VPATH build);
+# we want to run pg_bsd_indent in the tmp_check directory to reduce clutter.
+# (Also, it's caller's responsibility that pg_bsd_indent be in the PATH.)
+my $src_dir = getcwd;
+chdir ${PostgreSQL::Test::Utils::tmp_check};
+
+# Basic tests: pg_bsd_indent knows --version but not much else.
+program_version_ok('pg_bsd_indent');
+
+# Run pg_bsd_indent on pre-fab test cases.
+# Any diffs in the generated files will be accumulated here.
+my $diff_file = "tests.diff";
+
+# Copy support files to current dir, so *.pro files don't need to know path.
+while (my $file = glob("$src_dir/tests/*.list"))
+{
+    cp($file, ".") || die "cp $file failed: $!";
+}
+
+while (my $test_src = glob("$src_dir/tests/*.0"))
+{
+    # extract test basename
+    my ($volume, $directories, $test) = File::Spec->splitpath($test_src);
+    $test =~ s/\.0$//;
+    # run pg_bsd_indent
+    command_ok(
+        [
+            'pg_bsd_indent', $test_src,
+            "$test.out",     "-P$src_dir/tests/$test.pro"
+        ],
+        "pg_bsd_indent succeeds on $test");
+    # check result matches, adding any diff to $diff_file
+    my $result = run_log([ 'diff', '-upd', "$test_src.stdout", "$test.out" ],
+        '>>', $diff_file);
+    ok($result, "pg_bsd_indent output matches for $test");
+}
+
+done_testing();
diff --git a/src/tools/pgindent/exclude_file_patterns b/src/tools/pgindent/exclude_file_patterns
index f5c8857e31..6405a00511 100644
--- a/src/tools/pgindent/exclude_file_patterns
+++ b/src/tools/pgindent/exclude_file_patterns
@@ -47,6 +47,10 @@ src/pl/plperl/ppport\.h$
 src/pl/plperl/SPI\.c$
 src/pl/plperl/Util\.c$
 #
+# pg_bsd_indent has its own, idiosyncratic indentation style.
+# We'll stick to that to permit comparison with the FreeBSD upstream.
+src/tools/pg_bsd_indent/.*
+#
 # Exclude any temporary installations that may be in the tree.
 /tmp_check/
 /tmp_install/
--
2.31.1


В списке pgsql-hackers по дате отправления:

Предыдущее
От: Andres Freund
Дата:
Сообщение: Re: Use pg_pwritev_with_retry() instead of write() in dir_open_for_write() to avoid partial writes?
Следующее
От: Tom Lane
Дата:
Сообщение: Re: Importing pg_bsd_indent into our source tree