Add files written by Felix Janda for the POSIX.1-2008 TC1 conversion

Signed-off-by: Michael Kerrisk (man-pages) <mtk.manpages@gmail.com>
diff --git a/,xref.1.awk b/,xref.1.awk
new file mode 100755
index 0000000..92515d6
--- /dev/null
+++ b/,xref.1.awk
@@ -0,0 +1,27 @@
+#!/usr/bin/awk -f
+# ,xref.1.awk - convert ,xref.6 to ,xref.1
+#
+# Copyright (C) 2013 Felix Janda
+#
+# Permission is hereby granted, free of charge, to any person
+# obtaining a copy of this software and associated documentation files
+# (the "Software"), to deal in the Software without restriction,
+# including without limitation the rights to use, copy, modify, merge,
+# publish, distribute, sublicense, and/or sell copies of the Software,
+# and to permit persons to whom the Software is furnished to do so,
+# subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be
+# included in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+# SOFTWARE.
+#
+# delete first, third and fourth field in each line
+{$1="";$3="";$4=$2;$2=""; print}
diff --git a/,xref.py b/,xref.py
new file mode 100755
index 0000000..3cfd531
--- /dev/null
+++ b/,xref.py
@@ -0,0 +1,95 @@
+#!/usr/bin/env python3
+# ,xref.py - Collect xrefs from HTML version of POSIX standard
+#
+# Copyright (C) 2013 Felix Janda
+#
+# Permission is hereby granted, free of charge, to any person
+# obtaining a copy of this software and associated documentation files
+# (the "Software"), to deal in the Software without restriction,
+# including without limitation the rights to use, copy, modify, merge,
+# publish, distribute, sublicense, and/or sell copies of the Software,
+# and to permit persons to whom the Software is furnished to do so,
+# subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be
+# included in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+# SOFTWARE.
+
+import re
+import sys
+import fileinput
+from glob import glob
+from html.entities import entitydefs
+
+sections = [["basedefs"], ["functions"], ["utilities"], ["xrat"]]
+re1 = re.compile('^.*<a name="tag_*|</.*>\n$| Table: | Figure: ')
+re2 = re.compile('">[^>]*</a>')
+re3 = re.compile('^.*>  |\..*\n$')
+
+htmlrefs=[] # will be filled with lists of the form ["Chapter 1", "Introduction"]
+files = [] # all V*_chap*.html files
+for s in sections:
+    l = glob(sys.argv[1] + "/" + s[0] + "/V*_chap*.html")
+    l.sort()
+    files = files + l
+for line in fileinput.input(files):
+    if '<a name="tag' in line and not "_foot_" in line:
+        new = [] # To be added to entityrefs
+        prefix = "Section"
+        if "<h2>" in line:
+            prefix = "Chapter"
+            chapter = re3.sub("", line, count=2)
+            table = 1
+            figure = 1
+        elif "Table:" in line:
+            prefix = "Table"
+            new.append(prefix + " " + chapter + "-" + str(table))
+            table += 1
+        elif "Figure:" in line:
+            prefix = "Figure"
+            new.append(prefix + " " + chapter + "-" + str(figure))
+            figure += 1
+
+        line = re1.sub("", re2.sub(" ", line), count=3)
+
+        # Let python deal with the html entities
+        for ent in entitydefs:
+            line = line.replace("&" + ent + ";", entitydefs[ent])
+
+        part = line.partition(" ")
+
+        # Deal with the Sections
+        if not len(new):
+            partpart = part[0].split("_")
+            s = chapter
+            for i in range(1, len(partpart)):
+                s = s + "." + str(int(partpart[i]))
+            new.append(prefix + " " + s)
+
+        new.append(part[2])
+        htmlrefs.append(new)
+
+# Get the label names from ,xref.1 and print the results to stdout
+re4 = re.compile('Chapter|Section|Table|Figure')
+i = 0
+for line in open(",xref.1").readlines():
+    line = line.lstrip(" ").strip("\n")
+    part = line.partition(" ")
+    if re4.match(part[2]):
+        for j in range(i, len(htmlrefs)):
+            if part[2] == htmlrefs[j][0]:
+                print(line + ", " + htmlrefs[j][1])
+                i = j
+                break
+        else:
+            print(line)
+    else:
+         print(line)
diff --git a/README b/README
new file mode 100644
index 0000000..d94b204
--- /dev/null
+++ b/README
@@ -0,0 +1,126 @@
+Conversion of Open Group's troff sources to POSIX man pages
+===========================================================
+
+1. Necessary data:
+==================
+
+- obtainable from The Open Group
+  - directory with the troff sources
+  - file ,xref.6 containing information to crossreferences
+  - file _strings.def containing information to references to other
+    standards
+- obtainable online
+  - the HTML version of the standard
+
+
+The directory of troff sources contains four directories: "Builtins",
+"Commands", "Functions", "Headers". (Some of these contain
+subdirectories with "LEGACY" interfaces.) The directories contain .mm
+and .h files containing groff_mm files with extensions by The Open
+Group. Upon request one can also obtain a file defining their custom
+macros but this file is not necessary for the scripts.
+
+A relevant line in ,xref.6 could look like
+
+gropdf-info:href workdir page 104 Section 3.441
+
+It contains a label ("workdir"), the page number and the
+section number.
+
+A line in _strings.def might look like
+
+.ds Z5 ISO\ POSIX\(hy1 standard
+
+This tells us how to translate the escape sequence \*(Z5 .
+
+The HTML version of the standard can be obtained at
+
+http://pubs.opengroup.org/onlinepubs/9699919799/download/index.html
+
+The relevant files for the scripts are basedefs/V1_chap*.html,
+functions/V2_chap*.html, utilities/V3_chap*.html and
+xrat/V4_*_chap*.html. These are parts of the standard we do not
+have the sources for.
+
+2. Procedure to generate the man pages
+======================================
+
+Change your directory to the directory containing the conversion
+scripts. Type
+
+./,xref.1.awk < ,xref.6 > ,xref.1
+./,xref.py /path/to/HTML_version_of_standard > ,xref
+
+to generate ,xref and
+
+sed -f _strings.sed _strings.def > _strings.
+
+to generate _strings. With this done you can start generating
+individual man pages. To generate all pages use:
+
+./posix.py 0p /path/to/troff_sources/Headers/*.h
+./posix.py 1p /path/to/troff_sources/Built-Ins/*.mm
+./posix.py 1p /path/to/troff_sources/Commands/*.mm
+./posix.py 3p /path/to/troff_sources/Functions/*.mm
+
+You can now find the converted pages in your current working
+directory.
+
+3. Description of the included scripts
+======================================
+
+,xref.1.awk takes ,xref.6 from its standard input, strips
+irrelevant lines and transforms lines of the form
+
+gropdf-info:href whitespace page 103 Section 3.436
+
+to
+
+   whitespace Section 3.436
+
+,xref.1.py expects ,xref.1 generated from ,xref.1.awk in the
+current working directory and the path to the HTML version of
+the standard as its first argument. It extracts section, table
+and figure names for parts of the standard we do not have sources
+for, adds them to the xrefs and writes them to standard output.
+For the example, inside
+
+/path/to/HTML_version_of_standard/basedefs/V1_chap03.html
+
+it finds a line
+
+class; see also <a href="#tag_03_436">White Space</a>.</p>
+
+and therefore outputs
+
+whitespace Section 3.436, White Space
+
+to ,xref.
+
+The sed script _strings.sed does a simple conversion of lines of
+the form
+
+.ds Z5 ISO\ POSIX\(hy1 standard
+
+to
+
+\*(Z5	ISO\ POSIX\(hy1 standard
+
+The main script is posix.py. It takes the name of the man section
+as its first argument and the names of the pages to be converted
+as its other arguments. Furthermore, it expects the data files
+,xref and _strings in its current working directory. It outputs
+converted man pages to its current working directory.
+
+Notes:
+
+A final processing of the xrefs happens in posix.py: On the one
+hand the section names for cross-references internal to the
+current page are added.  On the other hand the references to
+other man pages are correctly formatted. The order of the entries
+in ,xref is used to deduce the right section number. This could
+also be achieved by careful examining the source directory.
+
+The code in posix.py to get the indentation right by inserting
+".RS ..." and ".RE" in the right places is very hacky and might
+fail with pages with a slightly more complex structure then now.
diff --git a/_strings.sed b/_strings.sed
new file mode 100755
index 0000000..ba4ca47
--- /dev/null
+++ b/_strings.sed
@@ -0,0 +1,32 @@
+# _strings.sed - convert _strings.def to _strings
+#
+# Copyright (C) 2013 Felix Janda
+#
+# Permission is hereby granted, free of charge, to any person
+# obtaining a copy of this software and associated documentation files
+# (the "Software"), to deal in the Software without restriction,
+# including without limitation the rights to use, copy, modify, merge,
+# publish, distribute, sublicense, and/or sell copies of the Software,
+# and to permit persons to whom the Software is furnished to do so,
+# subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be
+# included in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+# SOFTWARE.
+#
+# reformat lines starting with .ds
+/^\.ds .* .*$/{
+s/^\.ds /\\*(/;
+s/ /\t/;
+p
+}
+# delete everything else
+d
diff --git a/posix.py b/posix.py
new file mode 100755
index 0000000..a20bc69
--- /dev/null
+++ b/posix.py
@@ -0,0 +1,354 @@
+#!/usr/bin/env python
+# posix.py - Convert The Open Group troff sources to posix man pages
+#
+# Copyright (C) 2013 Felix Janda
+#
+# Permission is hereby granted, free of charge, to any person
+# obtaining a copy of this software and associated documentation files
+# (the "Software"), to deal in the Software without restriction,
+# including without limitation the rights to use, copy, modify, merge,
+# publish, distribute, sublicense, and/or sell copies of the Software,
+# and to permit persons to whom the Software is furnished to do so,
+# subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be
+# included in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+# SOFTWARE.
+
+import sys
+import os.path
+import re
+
+# Helper for troff()
+def quote(arg):
+    if " " in arg or "\\" in arg: return '"{}"'.format(arg)
+    else: return arg
+
+# troff(".BL", "some text", ",") --> '.B "some text" ,\n'
+def troff(macro, *args):
+    if len(args) == 1 and type(args[0]) is list:
+        args = args[0]
+    args = [quote(arg) for arg in args]
+    s = ".{} {}".format(macro, " ".join(args))
+    return s.strip(" ") + "\n"
+
+# For first processing
+# Replace a macro by a string
+brepl = {"mH":".SH",
+         "Cm":".I",
+         "Ev":".I",
+         "Ar":".I",
+         "yS":".LP\n.nf",
+         "yE":".fi",
+         "Cs":".sp\n.RS 4\n.nf\n\\fB",
+         "Ce":".fi \\fR\n.P\n.RE",
+         "HU":".SS",
+         "cV":".B",
+         "Fi":".B",
+         "rS":'.LP\n.I "The following sections are informative."',
+         "Cd":".I"}
+# Surround the argument of a macro by two strings.
+sur = {"LM":["{", "}"],
+       "Hd":[".I <", "> "],
+       "tK":["<", ">"],
+       "cH":[".B '", "' "],
+       "sG":[".B \\(dq", "\\(dq "],
+       "Fn":["\\fI","\\fR()"],
+       "Er":[".B [", "] "]}
+# Delete a macro
+delete = {"xR",
+          "iX",
+          "sS",
+          "sE",
+          "sP",
+          "TH",
+          "SK",
+          "sT",
+          "mS",
+          "mE",
+          "rE",
+          "po",
+          "if",
+          "ne",
+          "nr",
+          "tr",
+          "in"}
+# Places where we might need to insert .RS to get indentation right
+indentpoint = {"P", "BL", "DL", "VL", "AL", "Cs", "Ns"}
+# Places where we might need to insert .RE to get indentation right
+indentend = {"LE", "LI", "Ne"}
+# Generic replacements in the seconds processing
+repl = {"\\f1":"\\fR",
+        "\\f2":"\\fI",
+        "\\f3":"\\fB",
+        "\\f5":"\\fR",
+        "\\f6":"\\fI",
+        "\\f7":"\\fB",
+        "XBD\n":"the \\*(Zz,\n",
+        "XSH\n":"the \\*(Zy,\n",
+        "XCU\n":"the \\*(Zx,\n",
+        "XRAT\n":"the \\*(zj,\n",
+        "\\*(x":"",
+        "\\*(z!":"",
+        "\\*(z?":"",
+        ".TS H":".TS",
+        "\\(*D":" ",
+        ".B ":".BR ",
+        ".I ":".IR ",
+        '" "$':"$"}
+
+# Here it starts
+
+if len(sys.argv) == 1:
+    progname = os.path.basename(sys.argv[0])
+    sys.stderr.write("Usage: {} SECTION [FILE...]\n".format(progname))
+    exit(2)
+section = sys.argv[1]
+
+# Add the escape sequences from _strings to the repl dictionary
+lines=open("_strings").readlines()
+for l in lines:
+    p = l.partition("\t")
+    repl[p[0]] = p[2].strip("\n")
+
+# Generate refdictorig from the ,xref file. It will be later extended to
+# the refdict dictionary with table and figure names from the current man
+# page
+refdictregs = [[r'\\fB<([a-zA-Z0-9\._/]*)>\\fP$', r'.BR \1 ({}p)'],
+               [r'\\fI([a-zA-Z0-9_]*)\\fR\\\^\(\\\|\)$', r'.BR \1 ({}p)'],
+               [r'\\fI([a-zA-Z0-9]*)\\fR\\\^$', r'.BR \1 ({}p)']]
+refdictorig = dict()
+lines = open(",xref").readlines()
+nsec = -1 # current section
+for l in lines:
+    if l.startswith("intro_"): nsec += 1
+    p = l.partition(" ")
+    s = p[2].strip("\n").replace(', ', '" ", " "')
+    for reg in refdictregs: # Format references to other man pages
+        s = re.sub(reg[0], reg[1].format([0, 3, 1][nsec]), s)
+    if s[0] != ".": # Otherwise make it italic
+        s = '.I "{}"'.format(s)
+    if ".h" in s: s = s.replace("/", "_") # for <sys/types.h>
+    refdictorig[p[0]] = s
+
+for file in sys.argv[2:]:
+    input = open(file)
+    lines = input.readlines()
+    input.close()
+
+    # Complete the ref descriptions
+    refdict = refdictorig
+    for i, l in enumerate(lines):
+        l = l.strip("\n")
+        if l.startswith(".xR ") and l[4] in ["6", "7"]:
+            key = l.split(" ")[2]
+            # Add numbers to tables and figures in current page
+            lines[i - 1] += ' " ' + refdict[key].split(" ")[2]
+            refdict[key] = '{}, {}"'.format(refdict[key].strip('"'),
+                                            prev.split(' "')[1].strip('"'))
+        prev = l
+
+    in_DSI = 0 # Are we in a display?
+    list_stack = [["BL"]] # stack of groff_mm lists we are in
+    list_num_stack = [] # stack of current list item numbers
+    needindent = 0 # do we need to insert .RS before the next paragraph?
+
+    # First processing
+    for i, l in enumerate(lines):
+        # only consider lines with macros
+        if not l or l[0] != ".": continue
+
+        # read out macro name with its arguments
+        macro = l.strip("\n").partition(" ")[0][1:]
+        args = ["".join(t) for t in re.findall(r'([^\s"][^\s]*"*)|"([^"]*)"',
+                                                             l.strip("\n"))][1:]
+
+        # strip comments
+        if macro.startswith('\\"'): lines[i] = ""
+
+        insert = "" # string to be inserted in front of current line
+        if needindent > 0:
+            if macro in indentpoint:
+                insert = ".RS {} \n".format(needindent)
+                needindent = -1
+        if needindent == -1 and macro in indentend:
+            insert = ".RE\n"
+
+        # "Note:" macros
+        if macro == "Ns":
+            lines[i] = ".TP 10\n.B Note"
+            if args: lines[i] += "s"
+            lines[i] += ":\n"
+            needindent = 10
+        if macro == "Ne":
+            lines[i] = troff("P")
+            needindent = -1
+
+        # Read the name of the current man page from the mS macro
+        if macro == "mS": name = args[0]
+
+        # mm display macros
+        if macro == "DS":
+            if "I" in args:
+                lines[i] = ".sp\n.RS\n"
+                in_DSI = 1
+            else: lines[i] = ""
+        elif macro == "DE":
+            if in_DSI: lines[i] = troff("RE")
+            else: lines[i] = ""
+            in_DSI = 0
+
+        # Fix table and figure captions
+        if macro == "TB":
+            if len(args) == 1: args.append("")
+            lines[i] = ".sp\n.ce 1\n\\fBTable{}: {}\\fR\n".format(args[1], args[0])
+        elif macro == "FG":
+            if len(args) == 1: args.append("")
+            lines[i] = ".sp\n.ce 1\n\\fBFigure{}: {}\\fR\n".format(args[1], args[0])
+        # strip unecessary macros around figures
+        elif macro == "F+":
+            lines[i] = lines[i + 1] = lines[i + 2] = ""
+
+        # mm list macro processing
+        elif macro in {"BL", "DL", "VL", "AL"}: # start of a list
+            needindent = 0
+            list_stack.insert(0, [macro, args])
+            if list_stack[0][0] == "AL":
+                list_num_stack.insert(0, 1)
+            lines[i] = ""
+        elif macro == "LI": # list item
+            # Strip some unecessary escape sequences to make the regexes for
+            # formatting the ERRORS section happy
+            if args: args[0] = args[0].replace("\\*!", "")
+
+            needindent = 4
+            if list_stack[0][0] == "BL": # bullet list
+                li_args = [" *", "4"]
+            elif list_stack[0][0] == "DL": # dashed list
+                li_args = ["--", "4"]
+            elif list_stack[0][0] == "VL": # variable item list
+                needindent = (int(list_stack[0][1][0]) - 8) // 2 + 8
+                li_args = [args[0], str(needindent)]
+            elif list_stack[0][0] == "AL": # advanced list
+                num = list_num_stack[0]
+                s = ""
+                if not list_stack[0][1]: # 1. 2. 3.
+                     s = str(num)
+                elif list_stack[0][1][0] == "a": # a. b. c.
+                     s = chr(num + 96)
+                elif list_stack[0][1][0] == "i": # i. ii. iii.
+                     needindent += 1
+                     s = "".join(["i" for j in range(num)])
+                li_args = ["{:>2s}.".format(s), str(needindent)]
+                list_num_stack[0] += 1
+            lines[i] = troff("IP", li_args)
+        elif macro == "LE": # list end
+            if list_stack[0][0] == "AL":
+                del list_num_stack[0]
+            del list_stack[0]
+            lines[i] = ""
+            needindent = -1
+            if len(list_stack) >= 2:
+                 lines[i] = troff("LE") + troff("RE")
+
+        # References
+        elif macro == "cX":
+            key = args[0]
+            if key in refdict: s = refdict[key]
+            else: s = key
+            if len(args) > 1: s += args[1]
+            lines[i] = s + "\n"
+
+        # Generic replacements
+        if macro in delete:
+            lines[i] = ""
+        elif macro in brepl:
+            lines[i] = l.replace("." + macro, brepl[macro], 1)
+        elif macro in sur:
+            lines[i] = sur[macro][0] + args[0] + sur[macro][1] + " ".join(args[1:]) + "\n"
+
+        lines[i] = insert + lines[i]
+
+    # Second processing
+    in_SEE_ALSO = 0 # Are we in the SEE ALSO section?
+    in_EQ = 0 # Are we in a displayed equation?
+    for i, l in enumerate(lines):
+        if l == ".SH \"SEE ALSO\"\n":
+            in_SEE_ALSO = 1
+        elif l == ".SH \"CHANGE HISTORY\"\n":
+            lines = lines[:i] # We are not allowed to include the CHANGE HISTORY
+            break
+        elif l == ".EQ\n":
+            in_EQ = 1
+        elif l == ".EN\n":
+            in_EQ = 0
+        # hack the equations to be a bit better readable on terminals
+        if in_EQ or '$' in l:
+            l = re.sub(r' sup ([a-zA-Z0-9\\\(]*)', "\"^\" \\1\" \"", l)
+            l = re.sub(r' sub ([a-zA-Z0-9\\\(]*)', "_ \\1\" \"", l)
+            l = l.replace("left { ~\n", "")
+            l = l.replace("~", ' " " ')
+        # reformat the error codes in the ERRORS section
+        l = re.sub(r'.IP \[(E[0-9A-Z]*)\] [0-9]*\n', ".TP\n.B \\1\n", l)
+        l = re.sub(r'.IP "\[(E[0-9A-Z]*)\] or \[(E[0-9A-Z]*)\]" [0-9]*\n',
+                                    ".TP\n.BR \\1 \" or \" \\2\n", l)
+        # Strip some extra space in the beginning of lines
+        l = re.sub(r'^\\ ', "", l)
+        # Generic replacements
+        for me in repl:
+            l = l.replace(me, repl[me])
+        for me in repl: # To be sure...
+            l = l.replace(me, repl[me])
+        if in_SEE_ALSO: l = re.sub(r'^the', "The", l)
+        lines[i] = l
+
+    name = re.sub(r'^<|>$', r'', name).replace("/", "_")
+    # name printed on the top of the man page
+    if section != "0p": NAME = name.upper()
+    else: NAME = name
+    lines.insert(0,
+      "'\\\" et\n"
+      ".TH {} \"{}\" 2013 \"IEEE/The Open Group\" \"POSIX Programmer's Manual\"\n"
+      ".SH PROLOG\n"
+      "This manual page is part of the POSIX Programmer's Manual.\n"
+      "The Linux implementation of this interface may differ (consult\n"
+      "the corresponding Linux manual page for details of Linux behavior),\n"
+      "or the interface may not be implemented on Linux.\n"
+      "\n"
+      "".format(NAME, section.upper()))
+    lines.append(
+      ".SH COPYRIGHT\n"
+      "Portions of this text are reprinted and reproduced in electronic form\n"
+      "from IEEE Std 1003.1, 2013 Edition, Standard for Information Technology\n"
+      "-- Portable Operating System Interface (POSIX), The Open Group Base\n"
+      "Specifications Issue 7, Copyright (C) 2013 by the Institute of\n"
+      "Electrical and Electronics Engineers, Inc and The Open Group.\n"
+      "(This is POSIX.1-2008 with the 2013 Technical Corrigendum 1 applied.) In the\n"
+      "event of any discrepancy between this version and the original IEEE and\n"
+      "The Open Group Standard, the original IEEE and The Open Group Standard\n"
+      "is the referee document. The original Standard can be obtained online at\n"
+      "http://www.unix.org/online.html .\n"
+      "\n"
+      "Any typographical or formatting errors that appear\n"
+      "in this page are most likely\n"
+      "to have been introduced during the conversion of the source files to\n"
+      "man page format. To report such errors, see\n"
+      "https://www.kernel.org/doc/man-pages/reporting_bugs.html .\n"
+      )
+
+    text = "".join(lines)
+    # Final hacks for the indentation
+    for i in [[".LE\n.RE\n.P", ".P"], [".LE\n.RE\n.RE", ".RE"],
+              [".RE\n.LE\n.RE", ".RE"], ["\n.LE\n", "\n"]]:
+        text = text.replace(i[0], i[1])
+    output = open(name + "." + section, 'w')
+    output.write(text)
+    output.close()