diff options
author | Michael Kerrisk (man-pages) <mtk.manpages@gmail.com> | 2020-08-06 15:20:22 +0200 |
---|---|---|
committer | Michael Kerrisk (man-pages) <mtk.manpages@gmail.com> | 2020-11-04 15:32:34 +0100 |
commit | c19e5f608b26269ea003e0c5a2c21e11d321345a (patch) | |
tree | 5b3e8d32d1b802d0cbe318ce33ab757617734e10 | |
download | man-pages-posix-c19e5f608b26269ea003e0c5a2c21e11d321345a.tar.gz |
Add files written by Felix Janda for the POSIX.1-2008 TC1 conversion
Signed-off-by: Michael Kerrisk (man-pages) <mtk.manpages@gmail.com>
-rwxr-xr-x | ,xref.1.awk | 27 | ||||
-rwxr-xr-x | ,xref.py | 95 | ||||
-rw-r--r-- | README | 126 | ||||
-rwxr-xr-x | _strings.sed | 32 | ||||
-rwxr-xr-x | posix.py | 354 |
5 files changed, 634 insertions, 0 deletions
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) @@ -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() |