diff options
Diffstat (limited to 'src/utils/grog')
-rw-r--r-- | src/utils/grog/grog.1.man | 628 | ||||
-rw-r--r-- | src/utils/grog/grog.am | 50 | ||||
-rw-r--r-- | src/utils/grog/grog.pl | 721 | ||||
-rwxr-xr-x | src/utils/grog/tests/PF-does-not-start-pic-region.sh | 33 | ||||
-rwxr-xr-x | src/utils/grog/tests/avoid-refer-fakeout.sh | 34 | ||||
-rw-r--r-- | src/utils/grog/tests/foo.man | 146 | ||||
-rwxr-xr-x | src/utils/grog/tests/preserve-groff-options.sh | 30 | ||||
-rwxr-xr-x | src/utils/grog/tests/recognize-perl-pod.sh | 31 | ||||
-rwxr-xr-x | src/utils/grog/tests/smoke-test.sh | 153 |
9 files changed, 1826 insertions, 0 deletions
diff --git a/src/utils/grog/grog.1.man b/src/utils/grog/grog.1.man new file mode 100644 index 0000000..efcd728 --- /dev/null +++ b/src/utils/grog/grog.1.man @@ -0,0 +1,628 @@ +.TH grog @MAN1EXT@ "@MDATE@" "groff @VERSION@" +.SH Name +grog \- \(lqgroff guess\(rq\(eminfer the +.I groff +command a document requires +. +. +.\" ==================================================================== +.\" Legal Terms +.\" ==================================================================== +.\" +.\" Copyright (C) 1989-2021 Free Software Foundation, Inc. +.\" +.\" This file is part of grog, which is part of groff, a free software +.\" project. You can redistribute it and/or modify it under the terms +.\" of the GNU General Public License version 2 (GPL2) as published by +.\" the Free Software Foundation. +.\" +.\" groff 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. +.\" +.\" The text for GPL2 is available in the internet at +.\" <http://www.gnu.org/licenses/gpl2.0.txt>. +. +. +.\" Save and disable compatibility mode (for, e.g., Solaris 10/11). +.do nr *groff_grog_1_man_C \n[.cp] +.cp 0 +. +.\" Define fallback for groff 1.23's MR macro if the system lacks it. +.nr do-fallback 0 +.if !\n(.f .nr do-fallback 1 \" mandoc +.if \n(.g .if !d MR .nr do-fallback 1 \" older groff +.if !\n(.g .nr do-fallback 1 \" non-groff *roff +.if \n[do-fallback] \{\ +. de MR +. ie \\n(.$=1 \ +. I \%\\$1 +. el \ +. IR \%\\$1 (\\$2)\\$3 +. . +.\} +.rr do-fallback +. +. +.\" ==================================================================== +.SH Synopsis +.\" ==================================================================== +. +.SY grog +.RB [ \-\-run ] +.RB [ \-\-ligatures ] +.RI [ groff-option\~ .\|.\|.\&] +.RB [ \-\- ] +.RI [ file\~ .\|.\|.] +.YS +. +. +.SY grog +.B \-h +. +.SY grog +.B \-\-help +.YS +. +. +.SY grog +.B \-v +. +.SY grog +.B \-\-version +.YS +. +. +.\" ==================================================================== +.SH Description +.\" ==================================================================== +. +.I grog +reads its input +and guesses which +.MR groff @MAN1EXT@ +options are needed to render it. +. +If no operands are given, +or if +.I file +is +.RB \[lq] \- \[rq], +.I grog +reads the standard input stream. +. +The corresponding +.I groff +command is normally written to the standard output stream. +. +With the option +.BR \-\-run , +the inferred command is written to the standard error stream and then +executed. +. +. +.\" ==================================================================== +.SH Options +.\" ==================================================================== +. +.B \-h +and +.B \-\-help +display a usage message, +whereas +.B \-v +and +.B \-\-version +display version information; +all exit afterward. +. +. +.TP +.B \-\-ligatures +includes the arguments +.B \-P\-y \-PU +in the inferred +.I groff +command. +. +These are supported only by the +.B pdf +output device. +. +. +.TP +.B \-\-run +writes the inferred command to the standard error stream and then +executes it. +. +. +.P +All other specified short options +(that is, +arguments beginning with a minus sign +.RB \[lq] \- \[rq] +followed by a letter) +are interpreted as +.I groff +options or option clusters with or without an option argument. +. +Such options are included in the constructed +.I groff +command line. +. +. +.\" ==================================================================== +.SH Details +.\" ==================================================================== +. +.I grog +reads each +.I file +operand, +pattern-matching strings that are statistically likely to be +characteristic of +.MR roff @MAN7EXT@ +documents. +. +It tries to guess which of the following +.I groff +options are required to correctly render the input: +.BR \-e , +.BR \-g , +.BR \-G , +.BR \-j , +.\" gideal is not implemented yet. +.\" .BR \-J , +.BR \-p , +.BR \-R , +.\".BR \-s , +.B \-t +(preprocessors); +and +.BR \-man , +.BR \-mdoc , +.BR \-mdoc\-old , +.BR \-me , +.BR \-mm , +.BR \-mom , +and +.B \-ms +(macro packages). +. +The inferred +.I groff +command including these options and any +.I file +parameters is written to the standard output stream. +. +. +.P +It is possible to specify arbitrary +.I groff +options on the command line. +. +These are included in the inferred command without change. +. +Choices of +.I groff +options include +.B \-C +to enable AT&T +.I troff +compatibility mode and +.B \-T +to select a non-default output device. +. +If the input is not encoded in US-ASCII, +ISO 8859-1, +or IBM code page 1047, +specification of a +.I groff +option to run the +.MR preconv @MAN1EXT@ +preprocessor is advised; +see the +.BR \-D , +.BR \-k , +and +.B \-K +options of +.MR groff @MAN1EXT@ . +. +For UTF-8 input, +.B \-k +is a good choice. +. +. +.P +.I groff +may issue diagnostic messages when an inappropriate +.B \-m +option, +or multiple conflicting ones, +are specified. +. +Consequently, +it is best to specify no +.B \-m +options to +.I grog +unless it cannot correctly infer all of the +.B \-m +arguments a document requires. +. +A +.I roff +document can also be written without recourse to any macro package. +. +In such cases, +.I grog +will infer a +.I groff +command without an +.B \-m +option. +. +. +.\" ==================================================================== +.SS Limitations +.\" ==================================================================== +. +.I grog +presumes that the input does not change the escape, +control, +or no-break control characters. +. +.I grog +does not parse +.I roff +input line continuation or control structures +(brace escape sequences and the +.RB \[lq] if \[rq], +.RB \[lq] ie \[rq], +and +.RB \[lq] el \[rq] +requests) +nor +.IR groff 's +.RB \[lq] while \[rq]. +. +Thus the input +. +.RS +.EX +\&.if \[rs] +t .NH 1 +\&.if n .SH +Introduction +.EE +.RE +. +will conceal the use of the +.I ms +macros +.B NH +and +.B SH +from +.IR grog . +. +Such constructions are regarded by +.IR grog 's +implementors as insufficiently common to cause many inference problems. +. +Preprocessors can be even stricter when matching macro calls that +bracket the regions of an input file they replace. +. +.IR pic , +for example, +requires +.BR PS , +.BR PE , +and +.B PF +calls to immediately follow the default control character at the +beginning of a line. +. +. +.P +Detection of the +.B \-s +option +(the +.MR @g@soelim @MAN1EXT@ +preprocessor) +is tricky; +to correctly infer its necessity would require +.I grog +to recursively open all files given as arguments to the +.B .so +request under the same conditions that +.I @g@soelim +itself does so; +see its man page. +. +Recall that +.I @g@soelim +is necessary only if sourced files need to be preprocessed. +. +Therefore, +as a workaround, +you may want to run the input through +.I @g@soelim +manually, +piping it to +.IR grog , +and compare the output to running +.I grog +on the input directly. +. +If the +.RI \[lq] @g@soelim \[rq]ed +input causes +.I grog +to infer additional preprocessor options, +then +.B \-s +is likely necessary. +. +. +.RS +.P +.EX +$ \c +.B printf \[dq].TS\[rs]nl.\[rs]nI\[aq]m a table.\[rs]n.TE\[rs]n\[dq] > \ +3.roff +$ \c +.B printf \[dq].so 3.roff\[rs]n\[dq] > 2.roff +$ \c +.B printf \[dq].XP\[rs]n.so 2.roff\[rs]n\[dq] > 1.roff +$ \c +.B grog 1.roff +groff \-ms 1.roff +$ \c +.B @g@soelim 1.roff | grog +groff \-t \-ms \- +.EE +.RE +. +. +.P +In the foregoing example, +we see that this procedure enabled +.I grog +to detect +.MR @g@tbl @MAN1EXT@ +macros, +so we would add +.B \-s +as well as the detected +.B \-t +option to a revised +.I grog +or +.I groff +command. +. +. +.RS +.P +.EX +$ \c +.B grog \-st 1.roff +groff \-st \-ms 1.roff +.EE +.RE +. +. +.\" ==================================================================== +.SH "Exit status" +.\" ==================================================================== +. +.I grog +exits with error status +.B 1 +if a macro package appears to be in use by the input document, +but +.I grog +was unable to infer which one, +or +.B 2 +if there were problems handling an option or operand. +. +It otherwise exits with status +.BR 0 . +. +(If the +.B \-\-run +option is specified, +.IR groff 's +exit status is discarded.) +. +Inferring no preprocessors or macro packages is not an error condition; +a valid +.I roff +document need not use either. +. +Even plain text is valid input, +if one is mindful of the syntax of the control and escape characters. +. +. +.\" ==================================================================== +.SH Examples +.\" ==================================================================== +. +Running +. +.RS +.EX +.B grog @DOCDIR@/meintro.me +.EE +.RE +at the command line results in +.RS +.EX +groff \-me @DOCDIR@/meintro.me +.EE +.RE +. +because +.I grog +recognizes that the file +.I meintro.me +is written using macros from the +.I me +package. +. +The command +. +.RS +.EX +.B grog @DOCDIR@/pic.ms +.EE +.RE +. +outputs +. +.RS +.EX +groff \-e \-p \-t \-ms @DOCDIR@/pic.ms +.EE +.RE +. +on the other hand. +. +Besides discerning the +.I ms +macro package, +.I grog +recognizes that the file +.I pic.ms +additionally needs the combination of +.B \-t +for +.IR tbl , +.B \-e +for +.IR eqn , +and +.B \-p +for +.IR pic . +. +. +.\" XXX: grog no longer (June 2021) attempts to detect this scenario. +.\" It's also not a practical one; full-service macro packages don't +.\" generally support being "unloaded" for subsequent processing of +.\" another document using a different one. We do achieve it, with +.\" care, in groff with man(7) and mdoc(7) (see andoc.tmac). +.\" .P +.\" If both of the former example files are combined in the command +.\" . +.\" .RS +.\" .EX +.\" .B grog meintro.me pic.ms +.\" .EE +.\" .RE +.\" . +.\" a diagnostic message is sent to the standard error stream because +.\" some macro packages cannot be combined. +.\" . +.\" Nevertheless the corresponding output with the wrong options is +.\" written to standard output: +.\" . +.\" .RS +.\" .EX +.\" groff \-t \-e \-p \-ms meintro.me pic.ms +.\" .EE +.\" .RE +.\" . +.\" and +.\" .I grog +.\" terminates with an error exit status. +. +. +.P +Consider a file +.IR \%doc/\:\%grnexampl.me , +which uses the +.I @g@grn +preprocessor to include a +.MR gremlin 1 +picture file in an +.I me \" generic +document. +. +Let's say we want to suppress color output, +produce a DVI file, +and get backtraces for any errors that +.I @g@troff +encounters. +. +The command +. +.RS +.EX +.B grog \-bc \-Idoc \-Tdvi doc/grnexmpl.me +.EE +.RE +. +is processed by +.I grog +into +. +.RS +.EX +groff \-bc \-Idoc \-Tdvi \-e \-g \-me doc/grnexmpl.me +.EE +.RE +. +where we can see that +.I grog +has inferred the +.I me \" generic +macro package along with the +.I eqn \" generic +and +.I grn \" generic +preprocessors. +. +(The input file is located in +.I @DOCDIR@ +if you'd like to try this example yourself.) +. +. +.\" ==================================================================== +.SH Authors +.\" ==================================================================== +. +.I grog +was originally written in Bourne shell by James Clark. +. +The current implementation in Perl was written by +.MT groff\-bernd\:.warken\-72@\:web\:.de +Bernd Warken +.ME +and heavily revised by +.MT g.branden\:.robinson@\:gmail\:.com +G.\& Branden Robinson +.ME . +. +. +.\" ==================================================================== +.SH "See also" +.\" ==================================================================== +. +.MR groff @MAN1EXT@ +. +. +.\" Restore compatibility mode (for, e.g., Solaris 10/11). +.cp \n[*groff_grog_1_man_C] +.do rr *groff_grog_1_man_C +. +. +.\" Local Variables: +.\" fill-column: 72 +.\" mode: nroff +.\" End: +.\" vim: set filetype=groff textwidth=72: diff --git a/src/utils/grog/grog.am b/src/utils/grog/grog.am new file mode 100644 index 0000000..f7ca5eb --- /dev/null +++ b/src/utils/grog/grog.am @@ -0,0 +1,50 @@ +# Copyright (C) 1993-2021 Free Software Foundation, Inc. +# +# This file is part of groff. +# +# groff 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. +# +# groff 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 <http://www.gnu.org/licenses/>. + +grog_srcdir = $(top_srcdir)/src/utils/grog +bin_SCRIPTS += grog +man1_MANS += src/utils/grog/grog.1 +EXTRA_DIST += \ + src/utils/grog/grog.1.man \ + src/utils/grog/grog.pl \ + src/utils/grog/tests/foo.man + +grog: $(grog_srcdir)/grog.pl $(SH_DEPS_SED_SCRIPT) + $(AM_V_GEN)$(RM) $@ \ + && sed -f "$(SH_DEPS_SED_SCRIPT)" \ + -e "s|[@]PERL[@]|$(PERL)|" \ + -e "s|[@]VERSION[@]|$(VERSION)|" \ + -e "$(SH_SCRIPT_SED_CMD)" \ + $(grog_srcdir)/grog.pl \ + >$@ \ + && chmod +x $@ + +grog_TESTS = \ + src/utils/grog/tests/PF-does-not-start-pic-region.sh \ + src/utils/grog/tests/avoid-refer-fakeout.sh \ + src/utils/grog/tests/preserve-groff-options.sh \ + src/utils/grog/tests/recognize-perl-pod.sh \ + src/utils/grog/tests/smoke-test.sh +TESTS += $(grog_TESTS) +EXTRA_DIST += $(grog_TESTS) + + +# Local Variables: +# mode: makefile-automake +# fill-column: 72 +# End: +# vim: set autoindent filetype=automake textwidth=72: diff --git a/src/utils/grog/grog.pl b/src/utils/grog/grog.pl new file mode 100644 index 0000000..28973c5 --- /dev/null +++ b/src/utils/grog/grog.pl @@ -0,0 +1,721 @@ +#!@PERL@ +# grog - guess options for groff command +# Inspired by doctype script in Kernighan & Pike, Unix Programming +# Environment, pp 306-8. + +# Copyright (C) 1993-2021 Free Software Foundation, Inc. +# Written by James Clark. +# Rewritten in Perl by Bernd Warken <groff-bernd.warken-72@web.de>. +# Hacked up by G. Branden Robinson, 2021. + +# This file is part of 'grog', which is part of 'groff'. + +# 'groff' 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 2 of the License, or +# (at your option) any later version. + +# 'groff' 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 +# <http://www.gnu.org/licenses/gpl-2.0.html>. + +use warnings; +use strict; + +use File::Spec; + +my $groff_version = 'DEVELOPMENT'; + +my @command = (); # the constructed groff command +my @requested_package = (); # arguments to '-m' grog options +my @inferred_preprocessor = (); # preprocessors the document uses +my @inferred_main_package = (); # full-service package(s) detected +my $main_package; # full-service package we go with +my $do_run = 0; # run generated 'groff' command +my $use_compatibility_mode = 0; # is -C being passed to groff? + +my %preprocessor_for_macro = ( + 'EQ', 'eqn', + 'G1', 'grap', + 'GS', 'grn', + 'PS', 'pic', + '[', 'refer', + #'so', 'soelim', # Can't be inferred this way; see grog man page. + 'TS', 'tbl', + 'cstart', 'chem', + 'lilypond', 'glilypond', + 'Perl', 'gperl', + 'pinyin', 'gpinyin', +); + +my $program_name = $0; +{ + my ($v, $d, $f) = File::Spec->splitpath($program_name); + $program_name = $f; +} + +my %user_macro; +my %score = (); + +my @input_file; + +# .TH is both a man(7) macro and often used with tbl(1). We expect to +# find .TH in ms(7) documents only between .TS and .TE calls, and in +# man(7) documents only as the first macro call. +my $have_seen_first_macro_call = 0; +# man(7) and ms(7) use many of the same macro names; do extra checking. +my $man_score = 0; +my $ms_score = 0; + +my $had_inference_problem = 0; +my $had_processing_problem = 0; +my $have_any_valid_arguments = 0; + + +sub fail { + my $text = shift; + print STDERR "$program_name: error: $text\n"; + $had_processing_problem = 1; +} + + +sub warn { + my $text = shift; + print STDERR "$program_name: warning: $text\n"; +} + + +sub process_arguments { + my $no_more_options = 0; + my $delayed_option = ''; + my $was_minus = 0; + my $optarg = 0; + my $pdf_with_ligatures = 0; + + foreach my $arg (@ARGV) { + if ( $optarg ) { + push @command, $arg; + $optarg = 0; + next; + } + + if ($no_more_options) { + push @input_file, $arg; + next; + } + + if ($delayed_option) { + if ($delayed_option eq '-m') { + push @requested_package, $arg; + $arg = ''; + } else { + push @command, $delayed_option; + } + + push @command, $arg if $arg; + $delayed_option = ''; + next; + } + + unless ( $arg =~ /^-/ ) { # file name, no opt, no optarg + push @input_file, $arg; + next; + } + + # now $arg starts with '-' + + if ($arg eq '-') { + unless ($was_minus) { + push @input_file, $arg; + $was_minus = 1; + } + next; + } + + if ($arg eq '--') { + $no_more_options = 1; + next; + } + + # Handle options that cause an early exit. + &version() if ($arg eq '-v' || $arg eq '--version'); + &usage(0) if ($arg eq '-h' || $arg eq '--help'); + + if ($arg =~ '^--.') { + if ($arg =~ '^--(run|with-ligatures)$') { + $do_run = 1 if ($arg eq '--run'); + $pdf_with_ligatures = 1 if ($arg eq '--with-ligatures'); + } else { + &fail("unrecognized grog option '$arg'; ignored"); + &usage(1); + } + next; + } + + # Handle groff options that take an argument. + + # Handle the option argument being separated by whitespace. + if ($arg =~ /^-[dfFIKLmMnoPrTwW]$/) { + $delayed_option = $arg; + next; + } + + # Handle '-m' option without subsequent whitespace. + if ($arg =~ /^-m/) { + my $package = $arg; + $package =~ s/-m//; + push @requested_package, $package; + next; + } + + # Treat anything else as (possibly clustered) groff options that + # take no arguments. + + # Our do_line() needs to know if it should do compatibility parsing. + $use_compatibility_mode = 1 if ($arg =~ /C/); + + push @command, $arg; + } + + if ($pdf_with_ligatures) { + push @command, '-P-y'; + push @command, '-PU'; + } + + @input_file = ('-') unless (@input_file); +} # process_arguments() + + +sub process_input { + foreach my $file (@input_file) { + unless ( open(FILE, $file eq "-" ? $file : "< $file") ) { + &fail("cannot open '$file': $!"); + next; + } + + $have_any_valid_arguments = 1; + + while (my $line = <FILE>) { + chomp $line; + &do_line($line); + } + + close(FILE); + } # end foreach +} # process_input() + + +# Push item onto inferred full-service list only if not already present. +sub push_main_package { + my $pkg = shift; + if (!grep(/^$pkg/, @inferred_main_package)) { + push @inferred_main_package, $pkg; + } +} # push_main_package() + + +sub do_line { + my $command; # request or macro name + my $args; # request or macro arguments + + my $line = shift; + + # Check for a Perl Pod::Man comment. + # + # An alternative to this kludge is noted below: if a "standard" macro + # is redefined, we could delete it from the relevant lists and + # hashes. + if ($line =~ /\\\" Automatically generated by Pod::Man/) { + $man_score += 100; + } + + # Strip comments. + $line =~ s/\\".*//; + $line =~ s/\\#.*// unless $use_compatibility_mode; + + return unless ($line =~ /^[.']/); # Ignore text lines. + + # Perform preprocessor checks; they scan their inputs using a rump + # interpretation of roff(7) syntax that requires the default control + # character and no space between it and the macro name. In AT&T + # compatibility mode, no space (or newline!) is required after the + # macro name, either. We mimic the preprocessors themselves; eqn(1), + # for instance, does not recognize '.EN' if '.EQ' has not been seen. + my $boundary = '\\b'; + $boundary = '' if ($use_compatibility_mode); + + if ($line =~ /^\.(\S\S)$boundary/ || $line =~ /^\.(\[)/) { + my $macro = $1; + # groff identifiers can have extremely weird characters in them. + # The ones we care about are conventionally named, but me(7) + # documents can call macros like '+c', so quote carefully. + if (grep(/^\Q$macro\E$/, keys %preprocessor_for_macro)) { + my $preproc = $preprocessor_for_macro{$macro}; + if (!grep(/$preproc/, @inferred_preprocessor)) { + push @inferred_preprocessor, $preproc; + } + } + } + + # Normalize control lines; convert no-break control character to the + # regular one and remove unnecessary whitespace. + $line =~ s/^['.]\s*/./; + $line =~ s/\s+$//; + + return if ($line =~ /^\.$/); # Ignore empty request. + return if ($line =~ /^\.\\?\.$/); # Ignore macro definition ends. + + # Split control line into a request or macro call and its arguments. + + # Handle single-letter macro names. + if ($line =~ /^\.(\S)(\s+(.*))?$/) { + $command = $1; + $args = $2; + # Handle two-letter macro/request names in compatibility mode. + } elsif ($use_compatibility_mode) { + $line =~ /^\.(\S\S)\s*(.*)$/; + $command = $1; + $args = $2; + # Handle multi-letter macro/request names in groff mode. + } else { + $line =~ /^\.(\S+)(\s+(.*))?$/; + $command = $1; + $args = $3; + } + + $command = '' unless ($command); + $args = '' unless ($args); + + ###################################################################### + # user-defined macros + + # If the line calls a user-defined macro, skip it. + return if (exists $user_macro{$command}); + + # These are all requests supported by groff 1.23.0. + my @request = ('ab', 'ad', 'af', 'aln', 'als', 'am', 'am1', 'ami', + 'ami1', 'as', 'as1', 'asciify', 'backtrace', 'bd', + 'blm', 'box', 'boxa', 'bp', 'br', 'brp', 'break', 'c2', + 'cc', 'ce', 'cf', 'cflags', 'ch', 'char', 'chop', + 'class', 'close', 'color', 'composite', 'continue', + 'cp', 'cs', 'cu', 'da', 'de', 'de1', 'defcolor', 'dei', + 'dei1', 'device', 'devicem', 'di', 'do', 'ds', 'ds1', + 'dt', 'ec', 'ecr', 'ecs', 'el', 'em', 'eo', 'ev', + 'evc', 'ex', 'fam', 'fc', 'fchar', 'fcolor', 'fi', + 'fp', 'fschar', 'fspecial', 'ft', 'ftr', 'fzoom', + 'gcolor', 'hc', 'hcode', 'hla', 'hlm', 'hpf', 'hpfa', + 'hpfcode', 'hw', 'hy', 'hym', 'hys', 'ie', 'if', 'ig', + 'in', 'it', 'itc', 'kern', 'lc', 'length', 'linetabs', + 'lf', 'lg', 'll', 'lsm', 'ls', 'lt', 'mc', 'mk', 'mso', + 'msoquiet', 'na', 'ne', 'nf', 'nh', 'nm', 'nn', 'nop', + 'nr', 'nroff', 'ns', 'nx', 'open', 'opena', 'os', + 'output', 'pc', 'pev', 'pi', 'pl', 'pm', 'pn', 'pnr', + 'po', 'ps', 'psbb', 'pso', 'ptr', 'pvs', 'rchar', 'rd', + 'return', 'rfschar', 'rj', 'rm', 'rn', 'rnn', 'rr', + 'rs', 'rt', 'schar', 'shc', 'shift', 'sizes', 'so', + 'soquiet', 'sp', 'special', 'spreadwarn', 'ss', + 'stringdown', 'stringup', 'sty', 'substring', 'sv', + 'sy', 'ta', 'tc', 'ti', 'tkf', 'tl', 'tm', 'tm1', + 'tmc', 'tr', 'trf', 'trin', 'trnt', 'troff', 'uf', + 'ul', 'unformat', 'vpt', 'vs', 'warn', 'warnscale', + 'wh', 'while', 'write', 'writec', 'writem'); + + # Add user-defined macro names to %user_macro. + # + # Macros can also be defined with .dei{,1}, ami{,1}, but supporting + # that would be a heavy lift for the benefit of users that probably + # don't require grog's help. --GBR + if ($command =~ /^(de|am)1?$/) { + my $name = $args; + # Strip off any end macro. + $name =~ s/\s+.*$//; + # Handle special cases of macros starting with '[' or ']'. + if ($name =~ /^[][]/) { + delete $preprocessor_for_macro{'['}; + } + # XXX: If the macro name shadows a standard macro name, maybe we + # should delete the latter from our lists and hashes. This might + # depend on whether the document is trying to remain compatible + # with an existing interface, or simply colliding with names they + # don't care about (consider a raw roff document that defines 'PP'). + # --GBR + $user_macro{$name} = 0 unless (exists $user_macro{$name}); + return; + } + + # XXX: Handle .rm as well? + + # Ignore all other requests. Again, macro names can contain Perl + # regex metacharacters, so be careful. + return if (grep(/^\Q$command\E$/, @request)); + # What remains must be a macro name. + my $macro = $command; + + $have_seen_first_macro_call = 1; + $score{$macro}++; + + + ###################################################################### + # macro package (tmac) + ###################################################################### + + # man and ms share too many macro names for the following approach to + # be fruitful for many documents; see &infer_man_or_ms_package. + # + # We can put one thumb on the scale, however. + if ((!$have_seen_first_macro_call) && ($macro eq 'TH')) { + # TH as the first call in a document screams man(7). + $man_score += 100; + } + + ########## + # mdoc + if ($macro =~ /^Dd$/) { + &push_main_package('doc'); + return; + } + + ########## + # old mdoc + if ($macro =~ /^(Tp|Dp|De|Cx|Cl)$/) { + &push_main_package('doc-old'); + return; + } + + ########## + # me + + if ($macro =~ /^( + [ilnp]p| + n[12]| + sh + )$/x) { + &push_main_package('e'); + return; + } + + + ############# + # mm and mmse + + if ($macro =~ /^( + H| + MULB| + LO| + LT| + NCOL| + PH| + SA + )$/x) { + if ($macro =~ /^LO$/) { + if ( $args =~ /^(DNAMN|MDAT|BIL|KOMP|DBET|BET|SIDOR)/ ) { + &push_main_package('mse'); + return; + } + } elsif ($macro =~ /^LT$/) { + if ( $args =~ /^(SVV|SVH)/ ) { + &push_main_package('mse'); + return; + } + } + &push_main_package('m'); + return; + } + + ########## + # mom + + if ($macro =~ /^( + ALD| + AUTHOR| + CHAPTER_TITLE| + CHAPTER| + COLLATE| + DOCHEADER| + DOCTITLE| + DOCTYPE| + DOC_COVER| + FAMILY| + FAM| + FT| + LEFT| + LL| + LS| + NEWPAGE| + NO_TOC_ENTRY| + PAGENUMBER| + PAGE| + PAGINATION| + PAPER| + PRINTSTYLE| + PT_SIZE| + START| + TITLE| + TOC_AFTER_HERE + TOC| + T_MARGIN| + )$/x) { + &push_main_package('om'); + return; + } +} # do_line() + +my @preprocessor = (); + + +sub infer_preprocessors { + my %option_for_preprocessor = ( + 'eqn', '-e', + 'grap', '-G', + 'grn', '-g', + 'pic', '-p', + 'refer', '-R', + #'soelim', '-s', # Can't be inferred this way; see grog man page. + 'tbl', '-t', + 'chem', '-j' + ); + + # Use a temporary list we can sort later. We want the options to show + # up in a stable order for testing purposes instead of the order their + # macros turn up in the input. groff doesn't care about the order. + my @opt = (); + + foreach my $preproc (@inferred_preprocessor) { + my $preproc_option = $option_for_preprocessor{$preproc}; + + if ($preproc_option) { + push @opt, $preproc_option; + } else { + push @preprocessor, $preproc; + } + } + push @command, sort @opt; +} # infer_preprocessors() + + +# Return true (1) if either the man or ms package is inferred. +sub infer_man_or_ms_package { + my @macro_ms = ('RP', 'TL', 'AU', 'AI', 'DA', 'ND', 'AB', 'AE', + 'QP', 'QS', 'QE', 'XP', + 'NH', + 'R', + 'CW', + 'BX', 'UL', 'LG', 'NL', + 'KS', 'KF', 'KE', 'B1', 'B2', + 'DS', 'DE', 'LD', 'ID', 'BD', 'CD', 'RD', + 'FS', 'FE', + 'OH', 'OF', 'EH', 'EF', 'P1', + 'TA', '1C', '2C', 'MC', + 'XS', 'XE', 'XA', 'TC', 'PX', + 'IX', 'SG'); + + my @macro_man = ('BR', 'IB', 'IR', 'RB', 'RI', 'P', 'TH', 'TP', 'SS', + 'HP', 'PD', + 'AT', 'UC', + 'SB', + 'EE', 'EX', + 'OP', + 'MT', 'ME', 'SY', 'YS', 'TQ', 'UR', 'UE'); + + my @macro_man_or_ms = ('B', 'I', 'BI', + 'DT', + 'RS', 'RE', + 'SH', + 'SM', + 'IP', 'LP', 'PP'); + + for my $key (@macro_man_or_ms, @macro_man, @macro_ms) { + $score{$key} = 0 unless exists $score{$key}; + } + + # Compute a score for each package by counting occurrences of their + # characteristic macros. + foreach my $key (@macro_man_or_ms) { + $man_score += $score{$key}; + $ms_score += $score{$key}; + } + + foreach my $key (@macro_man) { + $man_score += $score{$key}; + } + + foreach my $key (@macro_ms) { + $ms_score += $score{$key}; + } + + if (!$ms_score && !$man_score) { + # The input may be a "raw" roff document; this is not a problem, + # but it does mean no package was inferred. + return 0; + } elsif ($ms_score == $man_score) { + # If there was no TH call, it's not a (valid) man(7) document. + if (!$score{'TH'}) { + &push_main_package('s'); + } else { + &warn("document ambiguous; disambiguate with -man or -ms option"); + $had_inference_problem = 1; + } + return 0; + } elsif ($ms_score > $man_score) { + &push_main_package('s'); + } else { + &push_main_package('an'); + } + + return 1; +} # infer_man_or_ms_package() + + +sub construct_command { + my @main_package = ('an', 'doc', 'doc-old', 'e', 'm', 'om', 's'); + my $file_args_included; # file args now only at 1st preproc + unshift @command, 'groff'; + if (@preprocessor) { + my @progs; + $progs[0] = shift @preprocessor; + push(@progs, @input_file); + for (@preprocessor) { + push @progs, '|'; + push @progs, $_; + } + push @progs, '|'; + unshift @command, @progs; + $file_args_included = 1; + } else { + $file_args_included = 0; + } + + foreach (@command) { + next unless /\s/; + # when one argument has several words, use accents + $_ = "'" . $_ . "'"; + } + + my $have_ambiguous_main_package = 0; + my $inferred_main_package_count = scalar @inferred_main_package; + + # Did we infer multiple full-service packages? + if ($inferred_main_package_count > 1) { + $have_ambiguous_main_package = 1; + # For each one the user explicitly requested... + for my $pkg (@requested_package) { + # ...did it resolve the ambiguity for us? + if (grep(/$pkg/, @inferred_main_package)) { + @inferred_main_package = ($pkg); + $have_ambiguous_main_package = 0; + last; + } + } + } elsif ($inferred_main_package_count == 1) { + $main_package = shift @inferred_main_package; + } + + if ($have_ambiguous_main_package) { + # TODO: Alphabetical is probably not the best ordering here. We + # should tally up scores on a per-package basis generally, not just + # for an and s. + for my $pkg (@main_package) { + if (grep(/$pkg/, @inferred_main_package)) { + $main_package = $pkg; + &warn("document ambiguous (choosing '$main_package'" + . " from '@inferred_main_package'); disambiguate with -m" + . " option"); + $had_inference_problem = 1; + last; + } + } + } + + # If a full-service package was explicitly requested, warn if the + # inference differs from the request. This also ensures that all -m + # arguments are placed in the same order that the user gave them; + # caveat dictator. + my @auxiliary_package_argument = (); + for my $pkg (@requested_package) { + my $is_auxiliary_package = 1; + if (grep(/$pkg/, @main_package)) { + $is_auxiliary_package = 0; + if ($pkg ne $main_package) { + &warn("overriding inferred package '$main_package'" + . " with requested package '$pkg'"); + $main_package = $pkg; + } + } + if ($is_auxiliary_package) { + push @auxiliary_package_argument, "-m" . $pkg; + } + } + + push @command, '-m' . $main_package if ($main_package); + push @command, @auxiliary_package_argument; + push @command, @input_file unless ($file_args_included); + + ######### + # execute the 'groff' command here with option '--run' + if ( $do_run ) { # with --run + print STDERR "@command\n"; + my $cmd = join ' ', @command; + system($cmd); + } else { + print "@command\n"; + } +} # construct_command() + + +sub usage { + my $stream = *STDOUT; + my $had_error = shift; + $stream = *STDERR if $had_error; + my $grog = $program_name; + print $stream "usage: $grog [--ligatures] [--run]" . + " [groff-option ...] [--] [file ...]\n" . + "usage: $grog {-v | --version}\n" . + "usage: $grog {-h | --help}\n"; + unless ($had_error) { + print $stream "\n" . +"Read each roff(7) input FILE and attempt to infer an appropriate\n" . +"groff(1) command to format it. See the grog(1) manual page.\n"; + } + exit $had_error; +} + + +sub version { + print "GNU $program_name (groff) $groff_version\n"; + exit 0; +} # version() + + +# initialize + +my $in_unbuilt_source_tree = 0; +{ + my $at = '@'; + $in_unbuilt_source_tree = 1 if ('@VERSION@' eq "${at}VERSION${at}"); +} + +$groff_version = '@VERSION@' unless ($in_unbuilt_source_tree); + +&process_arguments(); +&process_input(); + +if ($have_any_valid_arguments) { + &infer_preprocessors(); + &infer_man_or_ms_package() if (scalar @inferred_main_package != 1); + &construct_command(); +} + +exit 2 if ($had_processing_problem); +exit 1 if ($had_inference_problem); +exit 0; + +# Local Variables: +# fill-column: 72 +# mode: CPerl +# End: +# vim: set cindent noexpandtab shiftwidth=2 softtabstop=2 textwidth=72: diff --git a/src/utils/grog/tests/PF-does-not-start-pic-region.sh b/src/utils/grog/tests/PF-does-not-start-pic-region.sh new file mode 100755 index 0000000..d3b871f --- /dev/null +++ b/src/utils/grog/tests/PF-does-not-start-pic-region.sh @@ -0,0 +1,33 @@ +#!/bin/sh +# +# Copyright (C) 2021 Free Software Foundation, Inc. +# +# This file is part of groff. +# +# groff 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. +# +# groff 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 <http://www.gnu.org/licenses/>. +# + +grog="${abs_top_builddir:-.}/grog" + +# Regression test Savannah #60772. +# +# .PF does not _start_ a pic(1) region; it ends one. + +DOC='.PF +.PE' + +echo "$DOC" | "$grog" \ + | grep -Fqx 'groff -' + +# vim:set ai et sw=4 ts=4 tw=72: diff --git a/src/utils/grog/tests/avoid-refer-fakeout.sh b/src/utils/grog/tests/avoid-refer-fakeout.sh new file mode 100755 index 0000000..f163bed --- /dev/null +++ b/src/utils/grog/tests/avoid-refer-fakeout.sh @@ -0,0 +1,34 @@ +#!/bin/sh +# +# Copyright (C) 2021 Free Software Foundation, Inc. +# +# This file is part of groff. +# +# groff 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. +# +# groff 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 <http://www.gnu.org/licenses/>. +# + +grog="${abs_top_builddir:-.}/grog" + +# Regression-test Savannah #61520. +# +# Don't be fooled by documents (like xterm's ctlseqs.ms) that define +# macros with names that start with '[' or ']'. + +input=".de [] +.. +.[] foo" + +echo "$input" | "$grog" | grep -Fqx 'groff -' + +# vim:set ai et sw=4 ts=4 tw=72: diff --git a/src/utils/grog/tests/foo.man b/src/utils/grog/tests/foo.man new file mode 100644 index 0000000..28e9fe6 --- /dev/null +++ b/src/utils/grog/tests/foo.man @@ -0,0 +1,146 @@ +.\" Automatically generated by Pod::Man 4.10 (Pod::Simple 3.35) +.\" +.\" Standard preamble: +.\" ======================================================================== +.de Sp \" Vertical space (when we can't use .PP) +.if t .sp .5v +.if n .sp +.. +.de Vb \" Begin verbatim text +.ft CW +.nf +.ne \\$1 +.. +.de Ve \" End verbatim text +.ft R +.fi +.. +.\" Set up some character translations and predefined strings. \*(-- will +.\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left +.\" double quote, and \*(R" will give a right double quote. \*(C+ will +.\" give a nicer C++. Capital omega is used to do unbreakable dashes and +.\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff, +.\" nothing in troff, for use with C<>. +.tr \(*W- +.ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p' +.ie n \{\ +. ds -- \(*W- +. ds PI pi +. if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch +. if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch +. ds L" "" +. ds R" "" +. ds C` "" +. ds C' "" +'br\} +.el\{\ +. ds -- \|\(em\| +. ds PI \(*p +. ds L" `` +. ds R" '' +. ds C` +. ds C' +'br\} +.\" +.\" Escape single quotes in literal strings from groff's Unicode transform. +.ie \n(.g .ds Aq \(aq +.el .ds Aq ' +.\" +.\" If the F register is >0, we'll generate index entries on stderr for +.\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index +.\" entries marked with X<> in POD. Of course, you'll have to process the +.\" output yourself in some meaningful fashion. +.\" +.\" Avoid warning from groff about undefined register 'F'. +.de IX +.. +.nr rF 0 +.if \n(.g .if rF .nr rF 1 +.if (\n(rF:(\n(.g==0)) \{\ +. if \nF \{\ +. de IX +. tm Index:\\$1\t\\n%\t"\\$2" +.. +. if !\nF==2 \{\ +. nr % 0 +. nr F 2 +. \} +. \} +.\} +.rr rF +.\" +.\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2). +.\" Fear. Run. Save yourself. No user-serviceable parts. +. \" fudge factors for nroff and troff +.if n \{\ +. ds #H 0 +. ds #V .8m +. ds #F .3m +. ds #[ \f1 +. ds #] \fP +.\} +.if t \{\ +. ds #H ((1u-(\\\\n(.fu%2u))*.13m) +. ds #V .6m +. ds #F 0 +. ds #[ \& +. ds #] \& +.\} +. \" simple accents for nroff and troff +.if n \{\ +. ds ' \& +. ds ` \& +. ds ^ \& +. ds , \& +. ds ~ ~ +. ds / +.\} +.if t \{\ +. ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u" +. ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u' +. ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u' +. ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u' +. ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u' +. ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u' +.\} +. \" troff and (daisy-wheel) nroff accents +.ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V' +.ds 8 \h'\*(#H'\(*b\h'-\*(#H' +.ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#] +.ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H' +.ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u' +.ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#] +.ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#] +.ds ae a\h'-(\w'a'u*4/10)'e +.ds Ae A\h'-(\w'A'u*4/10)'E +. \" corrections for vroff +.if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u' +.if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u' +. \" for low resolution devices (crt and lpr) +.if \n(.H>23 .if \n(.V>19 \ +\{\ +. ds : e +. ds 8 ss +. ds o a +. ds d- d\h'-1'\(ga +. ds D- D\h'-1'\(hy +. ds th \o'bp' +. ds Th \o'LP' +. ds ae ae +. ds Ae AE +.\} +.rm #[ #] #H #V #F C +.\" ======================================================================== +.\" +.IX Title "FOO 1" +.TH FOO 1 "2021-06-30" "perl v5.28.1" "User Contributed Perl Documentation" +.\" For nroff, turn off justification. Always turn off hyphenation; it makes +.\" way too many mistakes in technical documents. +.if n .ad l +.nh +.SH "Name" +.IX Header "Name" +foo \- a frobnicator +.SH "Description" +.IX Header "Description" +This is my program. diff --git a/src/utils/grog/tests/preserve-groff-options.sh b/src/utils/grog/tests/preserve-groff-options.sh new file mode 100755 index 0000000..3290798 --- /dev/null +++ b/src/utils/grog/tests/preserve-groff-options.sh @@ -0,0 +1,30 @@ +#!/bin/sh +# +# Copyright (C) 2021 Free Software Foundation, Inc. +# +# This file is part of groff. +# +# groff 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. +# +# groff 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 <http://www.gnu.org/licenses/>. +# + +grog="${abs_top_builddir:-.}/grog" + +# Regression test Savannah #57873. +# +# Don't mangle groff options. + +echo | "$grog" -ww -fN -P-pa5 -ra5=0 \ + | grep -Fqx 'groff -ww -fN -P-pa5 -ra5=0 -' + +# vim:set ai et sw=4 ts=4 tw=72: diff --git a/src/utils/grog/tests/recognize-perl-pod.sh b/src/utils/grog/tests/recognize-perl-pod.sh new file mode 100755 index 0000000..bc13ece --- /dev/null +++ b/src/utils/grog/tests/recognize-perl-pod.sh @@ -0,0 +1,31 @@ +#!/bin/sh +# +# Copyright (C) 2021 Free Software Foundation, Inc. +# +# This file is part of groff. +# +# groff 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. +# +# groff 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 <http://www.gnu.org/licenses/>. +# + +grog="${abs_top_builddir:-.}/grog" +doc="${abs_top_srcdir:-..}/src/utils/grog/tests/foo.man" + +# Regression test Savannah #59622. +# +# Recognize the strongly-accented dialect of man(7) produced by +# pod2man(1). + +"$grog" "$doc" | grep '^groff -man .*/src/utils/grog/tests/foo\.man' + +# vim:set ai et sw=4 ts=4 tw=72: diff --git a/src/utils/grog/tests/smoke-test.sh b/src/utils/grog/tests/smoke-test.sh new file mode 100755 index 0000000..2da1fc4 --- /dev/null +++ b/src/utils/grog/tests/smoke-test.sh @@ -0,0 +1,153 @@ +#!/bin/sh +# +# Copyright (C) 2021 Free Software Foundation, Inc. +# +# This file is part of groff. +# +# groff 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. +# +# groff 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 <http://www.gnu.org/licenses/>. +# + +set -e + +grog="${abs_top_builddir:-.}/grog" +src="${abs_top_srcdir:-..}" + +doc=src/preproc/eqn/neqn.1 +echo "testing simple man(7) page $doc" >&2 +"$grog" "$doc" | \ + grep -Fqx 'groff -man '"$doc" + +doc=src/preproc/tbl/tbl.1 +echo "testing tbl(1)-using man(7) page $doc" >&2 +"$grog" "$doc" | \ + grep -Fqx 'groff -t -man '"$doc" + +doc=man/groff_diff.7 +echo "testing eqn(1)-using man(7) page $doc" >&2 +"$grog" "$doc" | \ + grep -Fqx 'groff -e -man '"$doc" + +# BUG: grog doesn't yet handle .if, .ie, .while. +#doc=src/preproc/soelim/soelim.1 +#echo "testing pic(1)-using man(7) page $doc" >&2 +#"$grog" "$doc" | \ +# grep -Fqx 'groff -p -man '"$doc" + +doc=tmac/groff_mdoc.7 +echo "testing tbl(1)-using mdoc(7) page $doc" >&2 +"$grog" "$doc" | \ + grep -Fqx 'groff -t -mdoc '"$doc" + +doc=$src/doc/meintro.me.in +echo "testing me(7) document $doc" >&2 +"$grog" "$doc" | \ + grep -Fqx 'groff -me '"$doc" + +doc=$src/doc/meintro_fr.me.in +echo "testing tbl(1)-using me(7) document $doc" >&2 +"$grog" "$doc" | \ + grep -Fqx 'groff -t -me '"$doc" + +doc=$src/doc/meref.me.in +echo "testing me(7) document $doc" >&2 +"$grog" "$doc" | \ + grep -Fqx 'groff -me '"$doc" + +doc=$src/doc/grnexmpl.me +echo "testing grn(1)- and eqn(1)-using me(7) document $doc" >&2 +"$grog" "$doc" | \ + grep -Fqx 'groff -e -g -me '"$doc" + +doc=$src/contrib/mm/examples/letter.mm +echo "testing mm(7) document $doc" >&2 +"$grog" "$doc" | \ + grep -Fqx 'groff -mm '"$doc" + +doc=$src/contrib/mom/examples/copyright-chapter.mom +echo "testing mom(7) document $doc" >&2 +"$grog" "$doc" | \ + grep -Fqx 'groff -mom '"$doc" + +doc=$src/contrib/mom/examples/copyright-default.mom +echo "testing mom(7) document $doc" >&2 +"$grog" "$doc" | \ + grep -Fqx 'groff -mom '"$doc" + +doc=$src/contrib/mom/examples/letter.mom +echo "testing mom(7) document $doc" >&2 +"$grog" "$doc" | \ + grep -Fqx 'groff -mom '"$doc" + +doc=$src/contrib/mom/examples/mom-pdf.mom +echo "testing mom(7) document $doc" >&2 +"$grog" "$doc" | \ + grep -Fqx 'groff -mom '"$doc" + +doc=$src/contrib/mom/examples/mon_premier_doc.mom +echo "testing mom(7) document $doc" >&2 +"$grog" "$doc" | \ + grep -Fqx 'groff -mom '"$doc" + +doc=$src/contrib/mom/examples/sample_docs.mom +echo "testing mom(7) document $doc" >&2 +"$grog" "$doc" | \ + grep -Fqx 'groff -mom '"$doc" + +doc=$src/contrib/mom/examples/slide-demo.mom +echo "testing mom(7) document $doc" >&2 +"$grog" "$doc" | \ + grep -Fqx 'groff -e -p -t -mom '"$doc" + +doc=$src/contrib/mom/examples/typesetting.mom +echo "testing mom(7) document $doc" >&2 +"$grog" "$doc" | \ + grep -Fqx 'groff -mom '"$doc" + +doc=$src/contrib/pdfmark/cover.ms +echo "testing ms(7) document $doc" >&2 +"$grog" "$doc" | \ + grep -Fqx 'groff -ms '"$doc" + +doc=$src/contrib/pdfmark/pdfmark.ms +echo "testing ms(7) document $doc" >&2 +"$grog" "$doc" | \ + grep -Fqx 'groff -ms '"$doc" + +doc=$src/doc/ms.ms +echo "testing eqn(1)- and tbl(1)-using ms(7) document $doc" >&2 +"$grog" "$doc" | \ + grep -Fqx 'groff -e -t -ms '"$doc" + +doc=$src/doc/pic.ms +echo "testing tbl(1)-, eqn(1)-, and pic(1)-using ms(7) document $doc" \ + >&2 +"$grog" "$doc" | \ + grep -Fqx 'groff -e -p -t -ms '"$doc" + +doc=$src/doc/webpage.ms +echo "testing ms(7) document $doc" >&2 +# BUG: Should detect -mwww (and -mpspic?) too. +"$grog" "$doc" | \ + grep -Fqx 'groff -ms '"$doc" + +# Test manual specification of auxiliary macro packages. +echo "testing ms(7) document $doc with '-m www' option" >&2 +"$grog" "$doc" -m www | \ + grep -Fqx 'groff -ms -mwww '"$doc" + +echo "testing ms(7) document $doc with '-mwww' option" >&2 +"$grog" "$doc" -mwww | \ + grep -Fqx 'groff -ms -mwww '"$doc" + +# vim:set ai et sw=4 ts=4 tw=72: |