Browse Source

docs: ascii version of manpage without nroff

Create ASCII version of manpage without nroff

 - build src/tool_hugegelp.c from the ascii manpage
 - move the the manpage and the ascii version build to docs/cmdline-opts
 - remove all use of nroff from the build process
 - should make the build entirely reproducible (by avoiding nroff)

 - partly reverts 2620aa9 to build libcurl option man pages one by one
   in cmake because the appveyor builds got all crazy until I did

The ASCII version of the manpage

 - is built with gen.pl, just like the manpage is
 - has a right-justified column making the appearance similar to the previous
   version
 - uses a 4-space indent per level (instead of the old version's 7)
 - does not do hyphenation of words (which nroff does)

History

  We first made the curl build use nroff for building the hugehelp file in
  December 1998, for curl 5.2.

Closes #13047
Daniel Stenberg 1 month ago
parent
commit
f03c85635f

+ 0 - 29
CMake/Macros.cmake

@@ -68,35 +68,6 @@ macro(curl_internal_test CURL_TEST)
   endif()
 endmacro()
 
-macro(curl_nroff_check)
-  find_program(NROFF NAMES gnroff nroff)
-  if(NROFF)
-    # Need a way to write to stdin, this will do
-    file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/nroff-input.txt" "test")
-    # Tests for a valid nroff option to generate a manpage
-    foreach(_MANOPT "-man" "-mandoc")
-      execute_process(COMMAND "${NROFF}" ${_MANOPT}
-        OUTPUT_VARIABLE NROFF_MANOPT_OUTPUT
-        INPUT_FILE "${CMAKE_CURRENT_BINARY_DIR}/nroff-input.txt"
-        ERROR_QUIET)
-      # Save the option if it was valid
-      if(NROFF_MANOPT_OUTPUT)
-        message("Found *nroff option: -- ${_MANOPT}")
-        set(NROFF_MANOPT ${_MANOPT})
-        set(NROFF_USEFUL ON)
-        break()
-      endif()
-    endforeach()
-    # No need for the temporary file
-    file(REMOVE "${CMAKE_CURRENT_BINARY_DIR}/nroff-input.txt")
-    if(NOT NROFF_USEFUL)
-      message(WARNING "Found no *nroff option to get plaintext from man pages")
-    endif()
-  else()
-    message(WARNING "Found no *nroff program")
-  endif()
-endmacro()
-
 macro(optional_dependency DEPENDENCY)
   set(CURL_${DEPENDENCY} AUTO CACHE STRING "Build curl with ${DEPENDENCY} support (AUTO, ON or OFF)")
   set_property(CACHE CURL_${DEPENDENCY} PROPERTY STRINGS AUTO ON OFF)

+ 2 - 5
CMakeLists.txt

@@ -312,13 +312,10 @@ option(ENABLE_CURL_MANUAL "to build the man page for curl and enable its -M/--ma
 
 if(ENABLE_CURL_MANUAL OR BUILD_LIBCURL_DOCS)
   if(PERL_FOUND)
-    curl_nroff_check()
-    if(NROFF_USEFUL)
-      set(HAVE_MANUAL_TOOLS ON)
-    endif()
+    set(HAVE_MANUAL_TOOLS ON)
   endif()
   if(NOT HAVE_MANUAL_TOOLS)
-    message(WARNING "Perl not found, or nroff not useful. Will not build manuals.")
+    message(WARNING "Perl not found. Will not build manuals.")
   endif()
 endif()
 

+ 5 - 5
GIT-INFO

@@ -36,9 +36,9 @@ following software installed:
  o libtool  1.4.2 (or later)
  o GNU m4 (required by autoconf)
 
- o nroff + perl
+ o perl
 
-   If you don't have nroff and perl and you for some reason don't want to
-   install them, you can rename the source file src/tool_hugehelp.c.cvs to
-   src/tool_hugehelp.c and avoid having to generate this file. This will
-   give you a stubbed version of the file that doesn't contain actual content.
+   If you don't have perl and don't want to install it, you can rename the
+   source file src/tool_hugehelp.c.cvs to src/tool_hugehelp.c and avoid having
+   to generate this file. This will give you a stubbed version of the file
+   that doesn't contain actual content.

+ 1 - 1
Makefile.am

@@ -134,7 +134,7 @@ CLEANFILES = $(VC14_LIBVCXPROJ) $(VC14_SRCVCXPROJ) \
 
 bin_SCRIPTS = curl-config
 
-SUBDIRS = lib src scripts
+SUBDIRS = lib docs src scripts
 DIST_SUBDIRS = $(SUBDIRS) tests packages scripts include docs
 
 pkgconfigdir = $(libdir)/pkgconfig

+ 0 - 38
configure.ac

@@ -3826,10 +3826,6 @@ AC_CHECK_DECL([fseeko],
 
 CURL_CHECK_NONBLOCKING_SOCKET
 
-dnl ************************************************************
-dnl nroff tool stuff
-dnl
-
 AC_PATH_PROG( PERL, perl, ,
   $PATH:/usr/local/bin/perl:/usr/bin/:/usr/local/bin )
 AC_SUBST(PERL)
@@ -3844,40 +3840,6 @@ fi
 dnl set variable for use in automakefile(s)
 AM_CONDITIONAL(BUILD_DOCS, test x"$BUILD_DOCS" = x1)
 
-AC_PATH_PROGS( NROFF, gnroff nroff, ,
-  $PATH:/usr/bin/:/usr/local/bin )
-AC_SUBST(NROFF)
-
-if test -n "$NROFF"; then
-  dnl only check for nroff options if an nroff command was found
-
-  AC_MSG_CHECKING([how to use *nroff to get plain text from man pages])
-  MANOPT="-man"
-  mancheck=`echo foo | $NROFF $MANOPT 2>/dev/null`
-  if test -z "$mancheck"; then
-    MANOPT="-mandoc"
-   mancheck=`echo foo | $NROFF $MANOPT 2>/dev/null`
-    if test -z "$mancheck"; then
-      MANOPT=""
-      AC_MSG_RESULT([failed])
-      AC_MSG_WARN([found no *nroff option to get plaintext from man pages])
-    else
-      AC_MSG_RESULT([$MANOPT])
-    fi
-  else
-    AC_MSG_RESULT([$MANOPT])
-  fi
-  AC_SUBST(MANOPT)
-fi
-
-if test -z "$MANOPT"
-then
-  dnl if no nroff tool was found, or no option that could convert man pages
-  dnl was found, then disable the built-in manual stuff
-  AC_MSG_WARN([disabling built-in manual])
-  USE_MANUAL="no";
-fi
-
 dnl *************************************************************************
 dnl If the manual variable still is set, then we go with providing a built-in
 dnl manual

+ 0 - 1
docs/INTERNALS.md

@@ -43,7 +43,6 @@ versions of libs and build tools.
  - GNU M4       1.4
  - perl         5.6
  - roffit       0.5
- - nroff        any version that supports `-man [in] [out]`
  - cmake        3.7
 
 Library Symbols

+ 2 - 21
docs/Makefile.am

@@ -30,16 +30,14 @@ MK_CA_DOCS = mk-ca-bundle.1
 CURLCONF_DOCS = curl-config.1
 endif
 
-man_MANS = $(abs_builddir)/curl.1 curl-config.1
+man_MANS = curl-config.1
 CURLPAGES = curl-config.md mk-ca-bundle.md
 
-# Build targets in this file (.) before cmdline-opts to ensure that
-# the curl.1 rule below runs first
 SUBDIRS = . cmdline-opts libcurl
 DIST_SUBDIRS = $(SUBDIRS) examples
 
 if BUILD_DOCS
-CLEANFILES = curl.1 mk-ca-bundle.1 curl-config.1
+CLEANFILES = mk-ca-bundle.1 curl-config.1
 endif
 
 EXTRA_DIST =                                    \
@@ -112,20 +110,6 @@ SUFFIXES = .1 .md
 
 all: $(MK_CA_DOCS)
 
-# $(abs_builddir) is to disable VPATH when searching for this file, which
-# would otherwise find the copy in $(srcdir) which breaks the $(HUGE)
-# rule in src/Makefile.am in out-of-tree builds that references the file in the
-# build directory.
-#
-# First, seed the used copy of curl.1 with the prebuilt copy (in an out-of-tree
-# build), then run make recursively to rebuild it only if its dependencies
-# have changed.
-$(abs_builddir)/curl.1:
-	if test "$(top_builddir)x" != "$(top_srcdir)x" -a -e "$(srcdir)/curl.1"; then \
-		$(INSTALL_DATA) "$(srcdir)/curl.1" $@ \
-		&& touch -r "$(srcdir)/curl.1" $@; fi
-	cd cmdline-opts && $(MAKE)
-
 .md.1:
 	$(CD2)$(CD2NROFF)
 
@@ -135,6 +119,3 @@ mk-ca-bundle.1: mk-ca-bundle.md
 
 distclean:
 	rm -f $(CLEANFILES)
-
-dist-hook:
-	cp $(builddir)/curl.1 $(builddir)/curl.1.dist

+ 0 - 9
docs/TODO

@@ -177,7 +177,6 @@
  18.29 --retry and transfer timeouts
 
  19. Build
- 19.1 avoid nroff
  19.2 Enable PIE and RELRO by default
  19.3 Do not use GNU libtool on OpenBSD
  19.4 Package curl for Windows in a signed installer
@@ -1291,14 +1290,6 @@
 
 19. Build
 
-19.1 avoid nroff
-
- With the switch to the markdown-like documentation format since curl 8.6.0,
- it should (with a manageable amount of work) be possible to render an ASCII
- version of the man page without involving nroff and thus remove that
- dependency for building the hugehelp file, used to build in the man page into
- the curl command line tool.
-
 19.2 Enable PIE and RELRO by default
 
  Especially when having programs that execute curl via the command line, PIE

+ 3 - 1
docs/cmdline-opts/CMakeLists.txt

@@ -21,7 +21,8 @@
 # SPDX-License-Identifier: curl
 #
 ###########################################################################
-set(MANPAGE "${CURL_BINARY_DIR}/docs/curl.1")
+set(MANPAGE "${CURL_BINARY_DIR}/docs/cmdline-opts/curl.1")
+set(ASCIIPAGE "${CURL_BINARY_DIR}/docs/cmdline-opts/curl.txt")
 
 # Load DPAGES and OTHERPAGES from shared file
 transform_makefile_inc("Makefile.inc" "${CMAKE_CURRENT_BINARY_DIR}/Makefile.inc.cmake")
@@ -29,6 +30,7 @@ include("${CMAKE_CURRENT_BINARY_DIR}/Makefile.inc.cmake")
 
 add_custom_command(OUTPUT "${MANPAGE}"
   COMMAND cd ${CMAKE_CURRENT_SOURCE_DIR} && "${PERL_EXECUTABLE}" "./gen.pl" mainpage ${DPAGES} > "${MANPAGE}"
+  COMMAND cd ${CMAKE_CURRENT_SOURCE_DIR} && "${PERL_EXECUTABLE}" "./gen.pl" ascii ${DPAGES} > "${ASCIIPAGE}"
   VERBATIM
 )
 add_custom_target(generate-curl.1 ALL DEPENDS "${MANPAGE}")

+ 17 - 3
docs/cmdline-opts/Makefile.am

@@ -24,7 +24,10 @@
 
 AUTOMAKE_OPTIONS = foreign no-dependencies
 
-MANPAGE = $(top_builddir)/docs/curl.1
+MANPAGE = curl.1
+ASCIIPAGE = curl.txt
+
+man_MANS = $(MANPAGE)
 
 include Makefile.inc
 
@@ -35,10 +38,21 @@ GN_0 = @echo "  GENERATE" $@;
 GN_1 =
 GN_ = $(GN_0)
 
-all: $(MANPAGE)
+if BUILD_DOCS
+CLEANFILES = $(MANPAGE) $(ASCIIPAGE)
+
+all: $(MANPAGE) $(ASCIIPAGE)
+
+endif
 
 $(MANPAGE): $(DPAGES) $(SUPPORT) mainpage.idx Makefile.inc gen.pl
-	$(GEN)(rm -f $(MANPAGE) && cd $(srcdir) && @PERL@ ./gen.pl mainpage $(DPAGES) > $(builddir)/manpage.tmp.$$$$ && mv $(builddir)/manpage.tmp.$$$$ $(MANPAGE))
+	$(GEN)(rm -f $(MANPAGE) && (cd $(srcdir) && @PERL@ ./gen.pl mainpage $(DPAGES)) > manpage.tmp.$$$$ && mv manpage.tmp.$$$$ $(MANPAGE))
+
+$(ASCIIPAGE): $(DPAGES) $(SUPPORT) mainpage.idx Makefile.inc gen.pl
+	$(GEN)(rm -f $(ASCIIPAGE) && (cd $(srcdir) && @PERL@ ./gen.pl ascii $(DPAGES)) > asciipage.tmp.$$$$ && mv asciipage.tmp.$$$$ $(ASCIIPAGE))
 
 listhelp:
 	./gen.pl listhelp $(DPAGES) > $(top_builddir)/src/tool_listhelp.c
+
+dist-hook: $(MANPAGE)
+	cp $(MANPAGE) $(MANPAGE).dist

+ 1 - 1
docs/cmdline-opts/_PROGRESS.md

@@ -1,6 +1,6 @@
 <!-- Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al. -->
 <!-- SPDX-License-Identifier: curl -->
-# "PROGRESS METER"
+# PROGRESS METER
 
 curl normally displays a progress meter during operations, indicating the
 amount of transferred data, transfer speeds and estimated time left, etc. The

+ 221 - 70
docs/cmdline-opts/gen.pl

@@ -93,11 +93,115 @@ sub manpageify {
     return $l;
 }
 
+
+my $colwidth=78; # max number of columns
+
+sub justline {
+    my ($lvl, @line) = @_;
+    my $w = -1;
+    my $spaces = -1;
+    my $width = $colwidth - ($lvl * 4);
+    for(@line) {
+        $w += length($_);
+        $w++;
+        $spaces++;
+    }
+    my $inject = $width - $w;
+    my $ratio = 0; # stay at zero if no spaces at all
+    if($spaces) {
+        $ratio = $inject / $spaces;
+    }
+    my $spare = 0;
+    print ' ' x ($lvl * 4);
+    my $prev;
+    for(@line) {
+        while($spare >= 0.90) {
+            print " ";
+            $spare--;
+        }
+        printf "%s%s", $prev?" ":"", $_;
+        $prev = 1;
+        $spare += $ratio;
+    }
+    print "\n";
+}
+
+sub lastline {
+    my ($lvl, @line) = @_;
+    print ' ' x ($lvl * 4);
+    my $prev = 0;
+    for(@line) {
+        printf "%s%s", $prev?" ":"", $_;
+        $prev = 1;
+    }
+    print "\n";
+}
+
+sub outputpara {
+    my ($lvl, $f) = @_;
+    $f =~ s/\n/ /g;
+
+    my $w = 0;
+    my @words = split(/  */, $f);
+    my $width = $colwidth - ($lvl * 4);
+
+    my @line;
+    for my $e (@words) {
+        my $l = length($e);
+        my $spaces = scalar(@line);
+        if(($w + $l + $spaces) >= $width) {
+            justline($lvl, @line);
+            undef @line;
+            $w = 0;
+        }
+
+        push @line, $e;
+        $w += $l; # new width
+    }
+    if($w) {
+        lastline($lvl, @line);
+        print "\n";
+    }
+}
+
 sub printdesc {
-    my @desc = @_;
-    my $exam = 0;
-    for my $d (@desc) {
-        print $d;
+    my ($manpage, $baselvl, @desc) = @_;
+
+    if($manpage) {
+        for my $d (@desc) {
+            print $d;
+        }
+    }
+    else {
+        my $p = -1;
+        my $para;
+        for my $l (@desc) {
+            my $lvl;
+            if($l !~ /^[\n\r]+/) {
+                # get the indent level off the string
+                $l =~ s/^\[([0-9q]*)\]//;
+                $lvl = $1;
+            }
+            if(($p =~ /q/) && ($lvl !~ /q/)) {
+                # the previous was quoted, this is not
+                print "\n";
+            }
+            if($lvl != $p) {
+                outputpara($baselvl + $p, $para);
+                $para = "";
+            }
+            if($lvl =~ /q/) {
+                # quoted, do not right-justify
+                chomp $l;
+                lastline($baselvl + $lvl + 1, $l);
+            }
+            else {
+                $para .= $l;
+            }
+
+            $p = $lvl;
+        }
+        outputpara($baselvl + $p, $para);
     }
 }
 
@@ -123,12 +227,13 @@ sub overrides {
 }
 
 sub protocols {
-    my ($standalone, $data)=@_;
+    my ($manpage, $standalone, $data)=@_;
     if($standalone) {
         return ".SH \"PROTOCOLS\"\n$data\n";
     }
     else {
-        return "($data) ";
+        return " ($data) " if($manpage);
+        return "[1]($data) " if(!$manpage);
     }
 }
 
@@ -164,13 +269,14 @@ sub added {
 }
 
 sub render {
-    my ($fh, $f, $line) = @_;
+    my ($manpage, $fh, $f, $line) = @_;
     my @desc;
     my $tablemode = 0;
     my $header = 0;
     # if $top is TRUE, it means a top-level page and not a command line option
     my $top = ($line == 1);
     my $quote;
+    my $level;
     $start = 0;
 
     while(<$fh>) {
@@ -196,7 +302,8 @@ sub render {
                 $blankline++;
                 next;
             }
-            push @desc, ".SH $1\n";
+            push @desc, ".SH $1\n" if($manpage);
+            push @desc, "[0]$1\n" if(!$manpage);
             next;
         }
         elsif(/^###/) {
@@ -211,19 +318,24 @@ sub render {
             # remove backticks from headers
             $words =~ s/\`//g;
 
-            # if there is a space, it needs quotes
-            if($word =~ / /) {
+            # if there is a space, it needs quotes for man page
+            if(($word =~ / /) && $manpage) {
                 $word = "\"$word\"";
             }
+            $level = 1;
             if($top == 1) {
-                push @desc, ".IP $word\n";
+                push @desc, ".IP $word\n" if($manpage);
+                push @desc, "\n" if(!$manpage);
+                push @desc, "[1]$word\n" if(!$manpage);
             }
             else {
                 if(!$tablemode) {
-                    push @desc, ".RS\n";
+                    push @desc, ".RS\n" if($manpage);
                     $tablemode = 1;
                 }
-                push @desc, ".IP $word\n";
+                push @desc, ".IP $word\n" if($manpage);
+                push @desc, "\n" if(!$manpage);
+                push @desc, "[1]$word\n" if(!$manpage);
             }
             $header = 1;
             next;
@@ -236,7 +348,7 @@ sub render {
             if($tablemode) {
                 # end of table
                 push @desc, ".RE\n.IP\n";
-                $tablmode = 0;
+                $tablemode = 0;
             }
             $header = 1;
             next;
@@ -253,7 +365,7 @@ sub render {
         }
         elsif($d =~ /^    (.*)/) {
             my $word = $1;
-            if(!$quote) {
+            if(!$quote && $manpage) {
                 push @desc, ".nf\n";
             }
             $quote = 1;
@@ -261,7 +373,7 @@ sub render {
         }
         elsif($quote && ($d !~ /^    (.*)/)) {
             # end of quote
-            push @desc, ".fi\n";
+            push @desc, ".fi\n" if($manpage);
             $quote = 0;
         }
 
@@ -293,40 +405,50 @@ sub render {
         # convert backslash-'<' or '> to just the second character
         $d =~ s/\\([><])/$1/g;
         # convert single backslash to double-backslash
-        $d =~ s/\\/\\\\/g;
+        $d =~ s/\\/\\\\/g if($manpage);
 
-        if(!$quote && $d =~ /--/) {
-            $d =~ s/--([a-z0-9.-]+)/manpageify($1)/ge;
-        }
 
-        # quote minuses in the output
-        $d =~ s/([^\\])-/$1\\-/g;
-        # replace single quotes
-        $d =~ s/\'/\\(aq/g;
-        # handle double quotes or periods first on the line
-        $d =~ s/^([\.\"])/\\&$1/;
-        # **bold**
-        $d =~ s/\*\*(\S.*?)\*\*/\\fB$1\\fP/g;
-        # *italics*
-        $d =~ s/\*(\S.*?)\*/\\fI$1\\fP/g;
+        if($manpage) {
+            if(!$quote && $d =~ /--/) {
+                $d =~ s/--([a-z0-9.-]+)/manpageify($1)/ge;
+            }
 
+            # quote minuses in the output
+            $d =~ s/([^\\])-/$1\\-/g;
+            # replace single quotes
+            $d =~ s/\'/\\(aq/g;
+            # handle double quotes or periods first on the line
+            $d =~ s/^([\.\"])/\\&$1/;
+            # **bold**
+            $d =~ s/\*\*(\S.*?)\*\*/\\fB$1\\fP/g;
+            # *italics*
+            $d =~ s/\*(\S.*?)\*/\\fI$1\\fP/g;
+        }
+        else {
+            # **bold**
+            $d =~ s/\*\*(\S.*?)\*\*/$1/g;
+            # *italics*
+            $d =~ s/\*(\S.*?)\*/$1/g;
+        }
         # trim trailing spaces
         $d =~ s/[ \t]+\z//;
         push @desc, "\n" if($blankline && !$header);
         $blankline = 0;
-        push @desc, $d;
+        push @desc, $d if($manpage);
+        my $qstr = $quote ? "q": "";
+        push @desc, "[".(1 + $level)."$qstr]$d" if(!$manpage);
         $header = 0;
 
     }
     if($tablemode) {
         # end of table
-        push @desc, ".RE\n.IP\n";
+        push @desc, ".RE\n.IP\n" if($manpage);
     }
     return @desc;
 }
 
 sub single {
-    my ($f, $standalone)=@_;
+    my ($manpage, $f, $standalone)=@_;
     my $fh;
     open($fh, "<:crlf", "$f") ||
         return 1;
@@ -476,7 +598,7 @@ sub single {
         return 2;
     }
 
-    my @desc = render($fh, $f, $line);
+    my @desc = render($manpage, $fh, $f, $line);
     close($fh);
     if($tablemode) {
         # end of table
@@ -499,17 +621,21 @@ sub single {
     }
 
     # quote "bare" minuses in opt
-    $opt =~ s/-/\\-/g;
+    $opt =~ s/-/\\-/g if($manpage);
     if($standalone) {
         print ".TH curl 1 \"30 Nov 2016\" \"curl 7.52.0\" \"curl manual\"\n";
         print ".SH OPTION\n";
         print "curl $opt\n";
     }
-    else {
+    elsif($manpage) {
         print ".IP \"$opt\"\n";
     }
+    else {
+        lastline(1, $opt);
+    }
+    my @leading;
     if($protocols) {
-        print protocols($standalone, $protocols);
+        push @leading, protocols($manpage, $standalone, $protocols);
     }
 
     if($standalone) {
@@ -517,15 +643,15 @@ sub single {
     }
 
     if($experimental) {
-        print "**WARNING**: this option is experimental. Do not use in production.\n\n";
+        push @leading, "**WARNING**: this option is experimental. Do not use in production.\n\n";
     }
 
-    printdesc(@desc);
-    undef @desc;
+    my $pre = $manpage ? "\n": "[1]";
 
     if($scope) {
         if($scope eq "global") {
-            print "\nThis option is global and does not need to be specified for each use of --next.\n";
+            push @desc, "\n" if(!$manpage);
+            push @desc, "${pre}This option is global and does not need to be specified for each use of --next.\n";
         }
         else {
             print STDERR "$f:$line:1:ERROR: unrecognized scope: '$scope'\n";
@@ -533,13 +659,16 @@ sub single {
         }
     }
 
+    printdesc($manpage, 2, (@leading, @desc));
+    undef @desc;
+
     my @extra;
     if($multi eq "single") {
-        push @extra, "\nIf --$long is provided several times, the last set ".
+        push @extra, "${pre}If --$long is provided several times, the last set ".
             "value is used.\n";
     }
     elsif($multi eq "append") {
-        push @extra, "\n--$long can be used several times in a command line\n";
+        push @extra, "${pre}--$long can be used several times in a command line\n";
     }
     elsif($multi eq "boolean") {
         my $rev = "no-$long";
@@ -549,13 +678,14 @@ sub single {
             $rev = $long;
             $rev =~ s/^no-//;
         }
+        my $dashes = $manpage ? "\\-\\-" : "--";
         push @extra,
-            "\nProviding --$long multiple times has no extra effect.\n".
-            "Disable it again with \\-\\-$rev.\n";
+            "${pre}Providing --$long multiple times has no extra effect.\n".
+            "Disable it again with $dashes$rev.\n";
     }
     elsif($multi eq "mutex") {
         push @extra,
-            "\nProviding --$long multiple times has no extra effect.\n";
+            "${pre}Providing --$long multiple times has no extra effect.\n";
     }
     elsif($multi eq "custom") {
         ; # left for the text to describe
@@ -565,7 +695,7 @@ sub single {
         return 2;
     }
 
-    printdesc(@extra);
+    printdesc($manpage, 2, @extra);
 
     my @foot;
 
@@ -581,7 +711,7 @@ sub single {
         if(!$helplong{$k}) {
             print STDERR "$f:$line:1:WARN: see-also a non-existing option: $k\n";
         }
-        my $l = manpageify($k);
+        my $l = $manpage ? manpageify($k) : "--$k";
         my $sep = " and";
         if($and && ($i < $and)) {
             $sep = ",";
@@ -592,7 +722,7 @@ sub single {
     push @foot, seealso($standalone, $mstr);
 
     if($requires) {
-        my $l = manpageify($long);
+        my $l = $manpage ? manpageify($long) : "--$long";
         push @foot, "$l requires that the underlying libcurl".
             " was built to support $requires. ";
     }
@@ -603,7 +733,7 @@ sub single {
             if(!$helplong{$k}) {
                 print STDERR "WARN: $f mutexes a non-existing option: $k\n";
             }
-            my $l = manpageify($k);
+            my $l = $manpage ? manpageify($k) : "--$k";
             $mstr .= sprintf "%s$l", $mstr?" and ":"";
         }
         push @foot, overrides($standalone,
@@ -612,16 +742,26 @@ sub single {
     if($examples[0]) {
         my $s ="";
         $s="s" if($examples[1]);
-        print "\nExample$s:\n.nf\n";
-        foreach my $e (@examples) {
-            $e =~ s!\$URL!https://example.com!g;
-            #$e =~ s/-/\\-/g;
-            #$e =~ s/\'/\\(aq/g;
-            # convert single backslahes to doubles
-            $e =~ s/\\/\\\\/g;
-            print " curl $e\n";
+        if($manpage) {
+            print "\nExample$s:\n";
+            print ".nf\n";
+            foreach my $e (@examples) {
+                $e =~ s!\$URL!https://example.com!g;
+                # convert single backslahes to doubles
+                $e =~ s/\\/\\\\/g;
+                print " curl $e\n";
+            }
+            print ".fi\n";
+        }
+        else {
+            my @ex;
+            push @ex, "[0q]Example$s:\n";
+            foreach my $e (@examples) {
+                $e =~ s!\$URL!https://example.com!g;
+                push @ex, "[0q] curl $e\n";
+            }
+            printdesc($manpage, 2, @ex);
         }
-        print ".fi\n";
     }
     if($added) {
         push @foot, added($standalone, $added);
@@ -629,8 +769,13 @@ sub single {
     if($foot[0]) {
         print "\n";
         my $f = join("", @foot);
-        $f =~ s/ +\z//; # remove trailing space
-        print "$f\n";
+        if($manpage) {
+            $f =~ s/ +\z//; # remove trailing space
+            print "$f\n";
+        }
+        else {
+            printdesc($manpage, 2, "[1]$f");
+        }
     }
     return 0;
 }
@@ -695,12 +840,12 @@ sub indexoptions {
 }
 
 sub header {
-    my ($f)=@_;
+    my ($manpage, $f)=@_;
     my $fh;
     open($fh, "<:crlf", "$f");
-    my @d = render($fh, $f, 1);
+    my @d = render($manpage, $fh, $f, 1);
     close($fh);
-    printdesc(@d);
+    printdesc($manpage, 0, @d);
 }
 
 sub listhelp {
@@ -854,7 +999,8 @@ sub sortnames {
 }
 
 sub mainpage {
-    my (@files) = @_;
+    my ($manpage, @files) = @_;
+    # $manpage is 1 for nroff, 0 for ASCII
     my $ret;
     my $fh;
     open($fh, "<:crlf", "mainpage.idx") ||
@@ -889,7 +1035,7 @@ sub mainpage {
 .\\"
 .TH curl 1 "$date" "curl $version" "curl Manual"
 HEADER
-        ;
+        if ($manpage);
 
     while(<$fh>) {
         my $f = $_;
@@ -901,12 +1047,12 @@ HEADER
         if(/^%options/) {
             # output docs for all options
             foreach my $f (sort sortnames @files) {
-                $ret += single($f, 0);
+                $ret += single($manpage, $f, 0);
             }
         }
         else {
             # render the file
-            header($f);
+            header($manpage, $f);
         }
     }
     close($fh);
@@ -937,7 +1083,12 @@ sub getargs {
     my ($f, @s) = @_;
     if($f eq "mainpage") {
         listglobals(@s);
-        mainpage(@s);
+        mainpage(1, @s);
+        return;
+    }
+    elsif($f eq "ascii") {
+        listglobals(@s);
+        mainpage(0, @s);
         return;
     }
     elsif($f eq "listhelp") {
@@ -957,7 +1108,7 @@ sub getargs {
         return;
     }
 
-    print "Usage: gen.pl <mainpage/listhelp/single FILE/protos/listcats> [files]\n";
+    print "Usage: gen.pl <mainpage/ascii/listhelp/single FILE/protos/listcats> [files]\n";
 }
 
 #------------------------------------------------------------------------

+ 7 - 12
docs/libcurl/CMakeLists.txt

@@ -26,26 +26,21 @@ transform_makefile_inc("Makefile.inc" "${CMAKE_CURRENT_BINARY_DIR}/Makefile.inc.
 include("${CMAKE_CURRENT_BINARY_DIR}/Makefile.inc.cmake")
 
 function(add_manual_pages _listname)
-  unset(_rofffiles)
-  unset(_mdfiles)
   foreach(_file IN LISTS ${_listname})
-    list(APPEND _rofffiles "${CMAKE_CURRENT_BINARY_DIR}/${_file}")
+    set(_rofffile "${CMAKE_CURRENT_BINARY_DIR}/${_file}")
     if(_file STREQUAL "libcurl-symbols.3")
       # Special case, an auto-generated file.
       string(REPLACE ".3" ".md" _mdfile "${CMAKE_CURRENT_BINARY_DIR}/${_file}")
     else()
-      string(REPLACE ".3" ".md" _mdfile "${_file}")
+      string(REPLACE ".3" ".md" _mdfile "${CMAKE_CURRENT_SOURCE_DIR}/${_file}")
     endif()
-    list(APPEND _mdfiles "${_mdfile}")
+    add_custom_command(OUTPUT "${_rofffile}"
+      COMMAND "${PERL_EXECUTABLE}" ${PROJECT_SOURCE_DIR}/scripts/cd2nroff ${_mdfile} > ${_rofffile}
+      DEPENDS "${_mdfile}"
+      VERBATIM
+    )
   endforeach()
 
-  add_custom_command(OUTPUT ${_rofffiles}
-    WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
-    COMMAND ${PROJECT_SOURCE_DIR}/scripts/cd2nroff -k -d "${CMAKE_CURRENT_BINARY_DIR}" ${_mdfiles}
-    DEPENDS ${_mdfiles}
-    VERBATIM
-  )
-
 endfunction()
 
 add_custom_command(OUTPUT libcurl-symbols.md

+ 3 - 0
scripts/Makefile.am

@@ -77,3 +77,6 @@ if USE_FISH_COMPLETION
   fi
 endif
 endif
+
+distclean:
+	rm -f $(CLEANFILES)

+ 1 - 1
scripts/cd2nroff

@@ -113,7 +113,7 @@ sub single {
 
     if(defined($f)) {
         if(!open($fh, "<:crlf", "$f")) {
-            print STDERR "Failed to open $f : $!\n";
+            print STDERR "cd2nroff failed to open '$f' for reading: $!\n";
             return 1;
         }
     }

+ 4 - 9
src/CMakeLists.txt

@@ -26,23 +26,18 @@ add_definitions(-DBUILDING_CURL)
 
 if(ENABLE_CURL_MANUAL AND HAVE_MANUAL_TOOLS)
   add_definitions("-DUSE_MANUAL")
-  # Use the C locale to ensure that only ASCII characters appear in the
-  # embedded text. NROFF and MANOPT are set in the parent CMakeLists.txt
   add_custom_command(
     OUTPUT tool_hugehelp.c
     COMMAND ${CMAKE_COMMAND} -E echo "#include \"tool_setup.h\"" > tool_hugehelp.c
     COMMAND ${CMAKE_COMMAND} -E echo "#ifndef HAVE_LIBZ" >> tool_hugehelp.c
-    COMMAND env LC_ALL=C "${NROFF}" ${NROFF_MANOPT}
-            "${CURL_BINARY_DIR}/docs/curl.1" |
-            "${PERL_EXECUTABLE}" "${CMAKE_CURRENT_SOURCE_DIR}/mkhelp.pl" >> tool_hugehelp.c
+    COMMAND "${PERL_EXECUTABLE}" "${CMAKE_CURRENT_SOURCE_DIR}/mkhelp.pl" < "${CURL_BINARY_DIR}/docs/cmdline-opts/curl.txt" >> tool_hugehelp.c
+
     COMMAND ${CMAKE_COMMAND} -E echo "#else" >> tool_hugehelp.c
-    COMMAND env LC_ALL=C "${NROFF}" ${NROFF_MANOPT}
-            "${CURL_BINARY_DIR}/docs/curl.1" |
-            "${PERL_EXECUTABLE}" "${CMAKE_CURRENT_SOURCE_DIR}/mkhelp.pl" -c >> tool_hugehelp.c
+    COMMAND "${PERL_EXECUTABLE}" "${CMAKE_CURRENT_SOURCE_DIR}/mkhelp.pl" -c < "${CURL_BINARY_DIR}/docs/cmdline-opts/curl.txt" >> tool_hugehelp.c
     COMMAND ${CMAKE_COMMAND} -E echo "#endif /* HAVE_LIBZ */" >> tool_hugehelp.c
     DEPENDS
       generate-curl.1
-      "${CURL_BINARY_DIR}/docs/curl.1"
+      "${CURL_BINARY_DIR}/docs/cmdline-opts/curl.1"
       "${CMAKE_CURRENT_SOURCE_DIR}/mkhelp.pl"
       "${CMAKE_CURRENT_SOURCE_DIR}/tool_hugehelp.h"
     VERBATIM)

+ 7 - 7
src/Makefile.am

@@ -96,7 +96,7 @@ EXTRA_DIST = mkhelp.pl \
  Makefile.mk curl.rc Makefile.inc CMakeLists.txt .checksrc
 
 # Use absolute directory to disable VPATH
-MANPAGE=$(abs_top_builddir)/docs/curl.1
+ASCIIPAGE=$(abs_top_builddir)/docs/cmdline-opts/curl.txt
 MKHELP=$(top_srcdir)/src/mkhelp.pl
 HUGE=tool_hugehelp.c
 
@@ -113,24 +113,24 @@ CS_ = $(CS_0)
 if USE_MANUAL
 # Here are the stuff to create a built-in manual
 
-$(MANPAGE):
+$(ASCIIPAGE):
 	cd $(top_builddir)/docs && $(MAKE)
 
 if HAVE_LIBZ
 # This generates the tool_hugehelp.c file in both uncompressed and
 # compressed formats.
-$(HUGE): $(MANPAGE) $(MKHELP)
+$(HUGE): $(ASCIIPAGE) $(MKHELP)
 	$(HUGECMD) (echo '#include "tool_setup.h"' > $(HUGE);   \
 	echo '#ifndef HAVE_LIBZ' >> $(HUGE);                    \
-	$(NROFF) $(MANPAGE) | $(PERL) $(MKHELP) >> $(HUGE);     \
+	$(PERL) $(MKHELP) < $(ASCIIPAGE) >> $(HUGE);     \
 	echo '#else' >> $(HUGE);                                \
-	$(NROFF) $(MANPAGE) | $(PERL) $(MKHELP) -c >> $(HUGE);  \
+	$(PERL) $(MKHELP) -c < $(ASCIIPAGE) >> $(HUGE);  \
 	echo '#endif /* HAVE_LIBZ */' >> $(HUGE) )
 else # HAVE_LIBZ
 # This generates the tool_hugehelp.c file uncompressed only
-$(HUGE): $(MANPAGE) $(MKHELP)
+$(HUGE): $(ASCIIPAGE) $(MKHELP)
 	$(HUGECMD)(echo '#include "tool_setup.h"' > $(HUGE);    \
-	$(NROFF) $(MANPAGE) | $(PERL) $(MKHELP) >> $(HUGE) )
+	$(PERL) $(MKHELP) < $(ASCIIPAGE) >> $(HUGE) )
 endif
 
 else # USE_MANUAL

+ 0 - 37
src/mkhelp.pl

@@ -44,45 +44,8 @@ push @out, "                             \\___|\\___/|_| \\_\\_____|\n";
 my $olen=0;
 while (<STDIN>) {
     my $line = $_;
-
-    # this should be removed:
-    $line =~ s/(.|_)//g;
-
-    # remove trailing CR from line. msysgit checks out files as line+CRLF
-    $line =~ s/\r$//;
-
-    $line =~ s/\x1b\x5b[0-9]+m//g; # escape sequence
-    if($line =~ /^([ \t]*\n|curl)/i) {
-        # cut off headers and empty lines
-        $wline++; # count number of cut off lines
-        next;
-    }
-
-    my $text = $line;
-    $text =~ s/^\s+//g; # cut off preceding...
-    $text =~ s/\s+$//g; # and trailing whitespaces
-
-    $tlen = length($text);
-
-    if($wline && ($olen == $tlen)) {
-        # if the previous line with contents was exactly as long as
-        # this line, then we ignore the newlines!
-
-        # We do this magic because a header may abort a paragraph at
-        # any line, but we don't want that to be noticed in the output
-        # here
-        $wline=0;
-    }
-    $olen = $tlen;
-
-    if($wline) {
-        # we only make one empty line max
-        $wline = 0;
-        push @out, "\n";
-    }
     push @out, $line;
 }
-push @out, "\n"; # just an extra newline
 
 print <<HEAD
 /*

+ 0 - 1
tests/README.md

@@ -52,7 +52,6 @@ SPDX-License-Identifier: curl
   - stunnel (for HTTPS and FTPS tests)
   - OpenSSH or SunSSH (for SCP and SFTP tests)
   - nghttpx (for HTTP/2 and HTTP/3 tests)
-  - nroff (for --manual tests)
   - An available `en_US.UTF-8` locale
 
 ### Installation of python-impacket

+ 1 - 1
tests/data/test1140

@@ -15,7 +15,7 @@ none
 </server>
 
 <name>
-Verify the nroff of man pages
+Verify the nroff of manpages
 </name>
 
 <command type="perl">

+ 2 - 2
tests/test1139.pl

@@ -220,8 +220,8 @@ close($r);
 #########################################################################
 # parse the curl.1 man page, extract all documented command line options
 # The man page may or may not be rebuilt, so check both possible locations
-open($r, "<", "$buildroot/docs/curl.1") || open($r, "<", "$root/docs/curl.1") ||
-    die "no input file";
+open($r, "<", "$buildroot/docs/cmdline-opts/curl.1") || open($r, "<", "$root/docs/cmdline-opts/curl.1") ||
+    die "failed getting curl.1";
 my @manpage; # store all parsed parameters
 while(<$r>) {
     chomp;

+ 2 - 2
tests/test1140.pl

@@ -23,13 +23,13 @@
 #
 ###########################################################################
 #
-# scan nroff pages to find basic syntactic problems such as unbalanced \f
+# scan manpages to find basic syntactic problems such as unbalanced \f
 # codes or references to non-existing curl man pages.
 
 my $docsroot = $ARGV[0];
 
 if(!$docsroot || ($docsroot eq "-g")) {
-    print "Usage: nroff-scan.pl <docs root dir> [nroff files]\n";
+    print "Usage: test1140.pl <docs root dir> [manpages]\n";
     exit;
 }