diff --git a/src/bin/Makefile.am b/src/bin/Makefile.am index 7fc7078ac..4410d71ea 100644 --- a/src/bin/Makefile.am +++ b/src/bin/Makefile.am @@ -64,3 +64,5 @@ ltlgrind_SOURCES = ltlgrind.cc dstar2tgba_SOURCES = dstar2tgba.cc spot_x_SOURCES = spot-x.cc ltlcross_LDADD = $(LDADD) $(LIB_GETHRXTIME) + +EXTRA_DIST = options.py diff --git a/src/bin/README b/src/bin/README new file mode 100644 index 000000000..6e3e7baf4 --- /dev/null +++ b/src/bin/README @@ -0,0 +1,52 @@ +This directory contains the source of some command-line tools that +expose some of Spot's algorithms to Unix users. + +Man pages are generated from the --help output of each tool, +supplemented by any text in the man/*.x files. Usually the extra text +contains either some bibliographical references, some formal +definitions or some examples that are too long for --help. Having a +few short examples at the end of --help is good. + +This directory also build some non-installed binaries, like spot-x, +whose purpose is just to generate a man-page with the same format as +the other man pages (this includes keeping the version number +up-to-date). + +There is also a script called 'options.py' that summerizes how the +different short options are used among the tools. + +Routines that are shared by multiple command-line tools are stored in +files called common_*.{cc,hh}. + + +Recommendations when adding new tools or features: +-------------------------------------------------- + + - Tools should be designed to work on multiple inputs (e.g., read + different outputs from multiple files, and accept many inputs from + the same file, including stdin). They should also all be designed + to produce several outputs, usually one per input. This way they + can be piped one onto the other easily. + + - When naming an option, seek inspiration from the POSIX standard, or + from GNU extensions. For instance ltlfilt and autfilt both have a + -v option to invert the filter; this is inspired from grep's -v + option. The long version of this option (--invert-match) is also + the same as in grep. + + - When adding a new option, implement only the --long-option by + default. Do not add a short version unless + (1) you are sure it will be frequently used interactively + (if it is only used in scripts, then a long option is enough) + (2) this option can be shared by multiple tools. + + - As much as possible, use the same option names across tools. Use + the script options.py in this directory to check what short options + are used. It's OK if the same short option correspond to different + long names in the various tools, as long as the intent is similar. + For instance -n has different long options depending on the tool: + autfilt -n N means --max-count=N + randltl -n N means --formulas=N + randaut -n N means --automata=N + but in all cases, the intent is to specify the number of items + to output. diff --git a/src/bin/options.py b/src/bin/options.py new file mode 100755 index 000000000..0d41562d1 --- /dev/null +++ b/src/bin/options.py @@ -0,0 +1,71 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# Copyright (C) 2014 Laboratoire de Recherche et +# Développement de l'Epita (LRDE). +# +# This file is part of Spot, a model checking library. +# +# Spot 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. +# +# Spot 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 . + + +# Run all binaries, and collect the long option associated to each +# short option for easy comparison. +# This script should work with both Python 2 and 3. + +from sys import stdout as out +import re +import subprocess + +with open('Makefile.am', 'r') as mf: + lines = mf.read() + +lines = re.sub('\s*\\\\\s*', ' ', lines) +bin_programs = re.search('bin_PROGRAMS\s*=([\w \t]*)', lines).group(1).split() + +optre = re.compile('(-\w), (--[\w=-]+)') + +d = {} + +for tool in bin_programs: + args = ('./' + tool, '--help') + try: + popen = subprocess.Popen(args, stdout=subprocess.PIPE) + except OSError: + print("Cannot execute " + tool + ", is it compiled?") + exit(1) + popen.wait() + output = popen.communicate()[0].decode('utf-8') + + for match in optre.finditer(output): + shortname, longname = match.group(1), match.group(2) + if not shortname in d: + d[shortname] = { longname: tool } + elif not longname in d[shortname]: + d[shortname][longname] = tool + else: + w = ('%29s' % '') + d[shortname][longname] + w = w[w.rfind('\n') + 1 : -1] + if len(w + ' ' + tool) < 80: + d[shortname][longname] += ' ' + tool + else: + d[shortname][longname] += '\n%29s%s' % ('', tool) + +# The lambda function works around the fact that x might be an str or +# a unicode object depending on the Python implementation. +for shortname in sorted(d, key=lambda x: x.lower()): + out.write(shortname) + first='' + for longname in sorted(d[shortname]): + out.write('%s %-24s %s\n' % (first, longname, d[shortname][longname])) + first=' '