#!/usr/bin/python3 # -*- coding: utf-8 -*- app_svnid = '$HeadURL$ $LastChangedRevision$' import sys import subprocess # python3's subprocess.Popen() returns a byte sequence, so to append the string '/include' we need to convert # one to the other. sys.path.append() expects a list of strings, not byte sequences. Therefore it makes most # sense to convert subprocess.Popen()'s output to a string or to get it to return a string directly. The latter # can be done by use of 'universal_newlines=True' sys.path.append(subprocess.Popen(["ade-config", "ade_share_prefix"], stdout=subprocess.PIPE, universal_newlines=True).communicate()[0][:-1] + '/include') import ade import os import re import getpass import socket import time ademan2html_defined_errors = { "ademan2html_err_misc":{"fmt":"%s"}, } # Instantiate option variables # Other globals url_regex = r'(?:mailto|http|https)://(?:www\.)?[-a-zA-Z0-9@:%._\+~#=]{2,256}\.[a-z]{2,6}\b(?:[-a-zA-Z0-9@:%_\+.~#?&//=]*)' # Colon-separated list of directories not already in $PATH that might contain zsoelim command. zsoelim_path = '/usr/lib/man-db:/usr/libexec/man-db' def ademan2html(errstack): global opt_full # Register application-specific errors ade.register_error_types(ademan2html_defined_errors) # Defaults for options opt_full = False # Register options ade.debug(errstack, 10, "ademan2html: registering options ...") rc = ade.register_options(errstack, "", "full", globals(), 'handle_option_%s') if rc != ade.ok: return rc # Register handler functions ade.debug(errstack, 10, "ademan2html: registering message handlers ...") rc = ade.set_callbacks(errstack, ademan2html_usage_help, ademan2html_version, ademan2html_paths) if rc != ade.ok: return rc # Process options ade.debug(errstack, 10, "ademan2html: processing options ...") rc = ade.process_options(errstack) if rc != ade.ok: return rc # Process arguments if len(sys.argv) not in [0, 1]: ade.show_bad_usage(errstack) if len(sys.argv) == 0: filename = '' in_handle = sys.stdin else: filename = sys.argv[0] try: in_handle = open(filename, 'r') except: ade.error(errstack, 'ademan2html_err_misc', '%s: failed to open' % (filename)) return ade.fail # Guts rc = process_handle(errstack, in_handle, sys.stdout, filename, opt_full) if rc != ade.ok: return rc return ade.ok def ademan2html_version(errstack): return ade.extract_version(errstack, app_svnid) def ademan2html_paths(errstack): return ade.ok, None def ademan2html_usage_help(errstack): return ade.ok, '[ ]', ' --full write HTML prologue and epilogue' def process_handle(errstack, in_handle, out_handle, filename, full_flag): if full_flag: out_handle.write('\n') out_handle.write('\n') out_handle.write('\n') # 'a,_,c' is a widely recognised way to discard parts of a tuple. See # https://stackoverflow.com/questions/9532576/ignore-part-of-a-python-tuple rc,_ = write_auto_generated(errstack, out_handle, '') if rc != ade.ok: return rc out_handle.write('
')
    #  nroff on its own is not intelligent enough to find .so'd files.
    #  The man command can do it but then there's no way to prevent
    #  it stripping bold/underline control characters when it's writing
    #  to a non-tty. The solution is that we call zsoelim ourselves.
    for line in subprocess.Popen('zsoelim | nroff -man', env={'PATH': os.environ['PATH'] + os.pathsep + os.pathsep.join(zsoelim_path.split(os.pathsep))}, stdin=in_handle, stdout=subprocess.PIPE, universal_newlines=True, shell=True).communicate()[0].split('\n'):
        ade.debug(errstack, 10, 'process_handle: line=[%s]' % (line))
        rc, outline = process_line(errstack, line, filename)
        if rc != ade.ok:
            return rc
        out_handle.write(outline + '\n')
    out_handle.write('
\n') if full_flag: out_handle.write('\n') out_handle.write('\n') return ade.ok def process_line(errstack, inline, filename): outline = '' state = 'n' while True: if len(inline) == 0: break # Leading spaces m = re.search(r'^( +)', inline) if m: outline += m.group(1) inline = inline[len(m.group(1)):] continue # Check for bold at beginning m = re.search(r'^((?:(.)\2)+)', inline) if m: rc, html, state = switch_if_needed(errstack, 'b', state) if rc != ade.ok: return rc outline += html rc, f = fix_gtlt_and_urls(errstack, ''.join([ c for (i,c) in enumerate(m.group(1)) if (i%3)==0 ])) if rc != ade.ok: return rc outline += f inline = inline[len(m.group(1)):] continue # Check for italic at beginning m = re.search(r'^((?:_.)+)', inline) if m: rc, html, state = switch_if_needed(errstack, 'i', state) if rc != ade.ok: return rc outline += html rc, f = fix_gtlt_and_urls(errstack, ''.join([ c for (i,c) in enumerate(m.group(1)) if i%3==2 ])) if rc != ade.ok: return rc outline += f inline = inline[len(m.group(1)):] continue # Other (not spaces and not something-immediately-followed-by-ctrl-h) m = re.search(r'^(.+?)(?: |.|$)', inline) if m: rc, html, state = switch_if_needed(errstack, 'n', state) if rc != ade.ok: return rc outline += html rc, f = fix_gtlt_and_urls(errstack, m.group(1)) if rc != ade.ok: return rc outline += f inline = inline[len(m.group(1)):] continue rc, html, state = switch_if_needed(errstack, 'n', state) if rc != ade.ok: return rc outline += html return ade.ok, outline def fix_gtlt_and_urls(errstack, s): global url_regex s = re.sub('<', '<', s) s = re.sub('>', '>', s) s = re.sub('(%s)' % (url_regex), r'\1', s) return ade.ok, s def switch_if_needed(errstack, new_state, old_state): html = '' if new_state == old_state: pass else: if old_state == 'i': html += '' elif old_state == 'b': html += '' if new_state == 'i': html += '' elif new_state == 'b': html += '' return ade.ok, html, new_state def handle_option_full(errstack): global opt_full opt_full = True return ade.ok def write_auto_generated(errstack, out_handle, first_line_comment_start, first_line_comment_end, mid_line_comment_start, mid_line_comment_end, last_line_comment_start, last_line_comment_end): ade.debug(errstack, 10, 'write_auto_generated: sof (FLCS=%s, FLCE=%s, MLCS=%s, MLCE=%s, LLCS=%s, LLCE=%s)' % (first_line_comment_start, first_line_comment_end, mid_line_comment_start, mid_line_comment_end, last_line_comment_start, last_line_comment_end)) user = getpass.getuser() unamen = socket.gethostname() rc, progname = ade.get_progname(errstack) if rc != ade.ok: return rc linelength = 78 date = time.asctime() textlength = linelength - (len(first_line_comment_start) + len(first_line_comment_end)) out_handle.write('%s%-*s%s' % (first_line_comment_start, textlength, '=' * textlength, first_line_comment_end)) out_handle.write('%s%-*s%s' % (mid_line_comment_start, textlength, '', mid_line_comment_end)) out_handle.write('%s%-*s%s' % (mid_line_comment_start, textlength, ' T H I S I S A G E N E R A T E D F I L E', mid_line_comment_end)) out_handle.write('%s%-*s%s' % (mid_line_comment_start, textlength, '', mid_line_comment_end)) out_handle.write('%s%-*s%s' % (mid_line_comment_start, textlength, ' M A N U A L E D I T S M A Y B E L O S T', mid_line_comment_end)) out_handle.write('%s%-*s%s' % (mid_line_comment_start, textlength, '', mid_line_comment_end)) out_handle.write('%s%-*s%s' % (mid_line_comment_start, textlength, ' Generated by: %s' % (user), mid_line_comment_end)) out_handle.write('%s%-*s%s' % (mid_line_comment_start, textlength, ' Generated with: %s' % (progname), mid_line_comment_end)) out_handle.write('%s%-*s%s' % (mid_line_comment_start, textlength, ' Generated on host: %s' % (unamen), mid_line_comment_end)) out_handle.write('%s%-*s%s' % (mid_line_comment_start, textlength, ' Generated on date: %s' % (date), mid_line_comment_end)) out_handle.write('%s%-*s%s' % (mid_line_comment_start, textlength, '', mid_line_comment_end)) out_handle.write('%s%-*s%s' % (last_line_comment_start, textlength, '=' * textlength, last_line_comment_end)) # 12 is the number if lines we just wrote. return ade.ok, 12 ade.main(ademan2html)