Re: Importing pg_bsd_indent into our source tree

Поиск
Список
Период
Сортировка
От Tom Lane
Тема Re: Importing pg_bsd_indent into our source tree
Дата
Msg-id 736439.1676166232@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  (Thomas Munro <thomas.munro@gmail.com>)
Re: Importing pg_bsd_indent into our source tree  (Alexander Lakhin <exclusion@gmail.com>)
Список pgsql-hackers
I wrote:
> Hmmm ... ci autoconf build is now happy, but the Windows run complains
> that none of the output files match.  I'm betting that this is a
> Windows-newline problem, since I now see that indent.c opens both the
> input and output files in default (text) mode.  I'm inclined to
> change it to open the output file in binary mode while leaving the
> input in text, which should have the effect of stripping \r if it's
> present.

So let's see if that theory is correct at all ...

            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 v4 1/5] 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 v4 2/5] 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 v4 3/5] 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

From 2395910690a0d2ada0ca6df4fe8983e268811be9 Mon Sep 17 00:00:00 2001
From: Tom Lane <tgl@sss.pgh.pa.us>
Date: Sat, 11 Feb 2023 19:28:26 -0500
Subject: [PATCH v4 4/5] Add missing test dependency.

I'd supposed there was already such a dependency for 'check',
but nope.  Per cfbot.
---
 src/tools/pg_bsd_indent/Makefile | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/tools/pg_bsd_indent/Makefile b/src/tools/pg_bsd_indent/Makefile
index ee3d494f40..b138bb8b12 100644
--- a/src/tools/pg_bsd_indent/Makefile
+++ b/src/tools/pg_bsd_indent/Makefile
@@ -41,7 +41,7 @@ clean distclean maintainer-clean:
     rm -f pg_bsd_indent$(X) $(OBJS)
     rm -rf log/ tmp_check/

-check:
+check: pg_bsd_indent
     $(prove_check)

 installcheck:
--
2.31.1

From ad1b9e767d5f13df6602f669fb5b3349e5f492bd Mon Sep 17 00:00:00 2001
From: Tom Lane <tgl@sss.pgh.pa.us>
Date: Sat, 11 Feb 2023 20:38:25 -0500
Subject: [PATCH v4 5/5] Open output file in binary mode.

This is to keep pg_bsd_indent from inserting Windows-style newlines
on Windows systems.  Per cfbot.

Discussion: https://postgr.es/m/734490.1676165550@sss.pgh.pa.us
---
 src/tools/pg_bsd_indent/indent.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/src/tools/pg_bsd_indent/indent.c b/src/tools/pg_bsd_indent/indent.c
index 34205f2ead..2fd8771083 100644
--- a/src/tools/pg_bsd_indent/indent.c
+++ b/src/tools/pg_bsd_indent/indent.c
@@ -207,7 +207,7 @@ main(int argc, char **argv)
                              * the file */
             errx(1, "input and output files must be different");
         }
-        output = fopen(out_name, "w");
+        output = fopen(out_name, "wb");
         if (output == NULL)    /* check for create error */
             err(1, "%s", out_name);
         continue;
@@ -1232,7 +1232,7 @@ bakcopy(void)
     if (input == NULL)
     err(1, "%s", bakfile);
     /* now the original input file will be the output */
-    output = fopen(in_name, "w");
+    output = fopen(in_name, "wb");
     if (output == NULL) {
     unlink(bakfile);
     err(1, "%s", in_name);
--
2.31.1


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

Предыдущее
От: Tom Lane
Дата:
Сообщение: Re: Importing pg_bsd_indent into our source tree
Следующее
От: Thomas Munro
Дата:
Сообщение: Re: Importing pg_bsd_indent into our source tree