# -*- coding: utf-8 -*- #+---------------------------------------------------------------------------+ #| 01001110 01100101 01110100 01111010 01101111 01100010 | #| | #| Netzob : Inferring communication protocols | #+---------------------------------------------------------------------------+ #| Copyright (C) 2011-2017 Georges Bossert and Frédéric Guihéry | #| This program is free software: you can redistribute it and/or modify | #| it under the terms of the GNU General Public License as published by | #| the Free Software Foundation, either version 3 of the License, or | #| (at your option) any later version. | #| | #| This program is distributed in the hope that it will be useful, | #| but WITHOUT ANY WARRANTY; without even the implied warranty of | #| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | #| GNU General Public License for more details. | #| | #| You should have received a copy of the GNU General Public License | #| along with this program. If not, see . | #+---------------------------------------------------------------------------+ #| @url : http://www.netzob.org | #| @contact : contact@netzob.org | #| @sponsors : Amossys, http://www.amossys.fr | #| Supélec, http://www.rennes.supelec.fr/ren/rd/cidre/ | #+---------------------------------------------------------------------------+ #+---------------------------------------------------------------------------+ #| Inspiration was taken from Andi Albrecht solution #+---------------------------------------------------------------------------+ #+---------------------------------------------------------------------------- #| Global Imports #+---------------------------------------------------------------------------- from distutils.command.build import build from distutils.core import Command from distutils.errors import DistutilsOptionError import optparse import datetime #+---------------------------------------------------------------------------+ #| manpage_command: #| generates the man page for Netzob #+---------------------------------------------------------------------------+ class manpage_command(Command): description = "Generates Netzob's man page" user_options = [ ('output=', 'O', 'output file'), ('parser=', None, 'module path to optparser (e.g. mymod:func'), ] def initialize_options(self): self.output = None self.parser = None def configureCommandLine(self): """Retrieve and instantiate Netzob's CommandLine manager in order to get its usage""" # First we find the commandLine class (its name is provided through setup.cfg) mod_name, class_name = self.parser.split(':') fromlist = mod_name.split('.') try: mod = __import__(mod_name, fromlist=fromlist) cmdLineClass = getattr(mod, class_name) # Instantiate the retrieved class cmdLine = cmdLineClass() self._parser = cmdLine.getConfiguredParser() except ImportError as err: raise def finalize_options(self): if self.output is None: raise DistutilsOptionError('\'output\' option is required') if self.parser is None: raise DistutilsOptionError('\'parser\' option is required') self.configureCommandLine() self._parser.formatter = ManPageFormatter() self._parser.formatter.set_parser(self._parser) self.announce('Writing man page %s' % self.output) self._today = datetime.date.today() def _markup(self, txt): return txt.replace('-', '\\-') def _write_header(self): appname = self.distribution.get_name() ret = [] ret.append('.TH %s 1 %s\n' % (self._markup(appname), self._today.strftime('%Y\\-%m\\-%d'))) description = self.distribution.get_description() if description: name = self._markup('%s - %s' % (self._markup(appname), description.splitlines()[0])) else: name = self._markup(appname) ret.append('.SH NAME\n%s\n' % name) synopsis = self._parser.get_usage() if synopsis: synopsis = synopsis.replace('%s ' % appname, '') ret.append('.SH SYNOPSIS\n.B %s\n%s\n' % (self._markup(appname), synopsis)) long_desc = self.distribution.get_long_description() if long_desc: ret.append('.SH DESCRIPTION\n%s\n' % self._markup(long_desc)) return ''.join(ret) def _write_options(self): ret = ['.SH OPTIONS\n'] ret.append(self._parser.format_option_help()) return ''.join(ret) def _write_footer(self): ret = [] appname = self.distribution.get_name() author = '%s <%s>' % (self.distribution.get_author(), self.distribution.get_author_email()) ret.append(('.SH AUTHORS\n.B %s\nwas written by %s.\n' % (self._markup(appname), self._markup(author)))) homepage = self.distribution.get_url() ret.append(('.SH DISTRIBUTION\nThe latest version of %s may ' 'be downloaded from\n' '.UR %s\n.UE\n' % (self._markup(appname), self._markup(homepage),))) return ''.join(ret) def run(self): manpage = [] manpage.append(self._write_header()) manpage.append(self._write_options()) manpage.append(self._write_footer()) stream = open(self.output, 'w') stream.write(''.join(manpage)) stream.close() class ManPageFormatter(optparse.HelpFormatter): def __init__(self, indent_increment=2, max_help_position=24, width=None, short_first=1): optparse.HelpFormatter.__init__(self, indent_increment, max_help_position, width, short_first) def _markup(self, txt): return txt.replace('-', '\\-') def format_usage(self, usage): return self._markup(usage) def format_heading(self, heading): if self.level == 0: return '' return '.TP\n%s\n' % self._markup(heading.upper()) def format_option(self, option): result = [] opts = self.option_strings[option] result.append('.TP\n.B %s\n' % self._markup(opts)) if option.help: help_text = '%s\n' % self._markup(self.expand_default(option)) result.append(help_text) return ''.join(result) build.sub_commands.append(('build_manpage', None))