├── COPYING ├── Changelog ├── Makefile ├── README ├── bookman ├── runtest ├── src2man ├── test ├── t000.txt ├── t000.wanted ├── t001.txt └── t001.wanted └── txt2man /COPYING: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 2, June 1991 3 | 4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc. 5 | 675 Mass Ave, Cambridge, MA 02139, USA 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | Preamble 10 | 11 | The licenses for most software are designed to take away your 12 | freedom to share and change it. By contrast, the GNU General Public 13 | License is intended to guarantee your freedom to share and change free 14 | software--to make sure the software is free for all its users. This 15 | General Public License applies to most of the Free Software 16 | Foundation's software and to any other program whose authors commit to 17 | using it. (Some other Free Software Foundation software is covered by 18 | the GNU Library General Public License instead.) You can apply it to 19 | your programs, too. 20 | 21 | When we speak of free software, we are referring to freedom, not 22 | price. Our General Public Licenses are designed to make sure that you 23 | have the freedom to distribute copies of free software (and charge for 24 | this service if you wish), that you receive source code or can get it 25 | if you want it, that you can change the software or use pieces of it 26 | in new free programs; and that you know you can do these things. 27 | 28 | To protect your rights, we need to make restrictions that forbid 29 | anyone to deny you these rights or to ask you to surrender the rights. 30 | These restrictions translate to certain responsibilities for you if you 31 | distribute copies of the software, or if you modify it. 32 | 33 | For example, if you distribute copies of such a program, whether 34 | gratis or for a fee, you must give the recipients all the rights that 35 | you have. You must make sure that they, too, receive or can get the 36 | source code. And you must show them these terms so they know their 37 | rights. 38 | 39 | We protect your rights with two steps: (1) copyright the software, and 40 | (2) offer you this license which gives you legal permission to copy, 41 | distribute and/or modify the software. 42 | 43 | Also, for each author's protection and ours, we want to make certain 44 | that everyone understands that there is no warranty for this free 45 | software. If the software is modified by someone else and passed on, we 46 | want its recipients to know that what they have is not the original, so 47 | that any problems introduced by others will not reflect on the original 48 | authors' reputations. 49 | 50 | Finally, any free program is threatened constantly by software 51 | patents. We wish to avoid the danger that redistributors of a free 52 | program will individually obtain patent licenses, in effect making the 53 | program proprietary. To prevent this, we have made it clear that any 54 | patent must be licensed for everyone's free use or not licensed at all. 55 | 56 | The precise terms and conditions for copying, distribution and 57 | modification follow. 58 | 59 | GNU GENERAL PUBLIC LICENSE 60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 61 | 62 | 0. This License applies to any program or other work which contains 63 | a notice placed by the copyright holder saying it may be distributed 64 | under the terms of this General Public License. The "Program", below, 65 | refers to any such program or work, and a "work based on the Program" 66 | means either the Program or any derivative work under copyright law: 67 | that is to say, a work containing the Program or a portion of it, 68 | either verbatim or with modifications and/or translated into another 69 | language. (Hereinafter, translation is included without limitation in 70 | the term "modification".) Each licensee is addressed as "you". 71 | 72 | Activities other than copying, distribution and modification are not 73 | covered by this License; they are outside its scope. The act of 74 | running the Program is not restricted, and the output from the Program 75 | is covered only if its contents constitute a work based on the 76 | Program (independent of having been made by running the Program). 77 | Whether that is true depends on what the Program does. 78 | 79 | 1. You may copy and distribute verbatim copies of the Program's 80 | source code as you receive it, in any medium, provided that you 81 | conspicuously and appropriately publish on each copy an appropriate 82 | copyright notice and disclaimer of warranty; keep intact all the 83 | notices that refer to this License and to the absence of any warranty; 84 | and give any other recipients of the Program a copy of this License 85 | along with the Program. 86 | 87 | You may charge a fee for the physical act of transferring a copy, and 88 | you may at your option offer warranty protection in exchange for a fee. 89 | 90 | 2. You may modify your copy or copies of the Program or any portion 91 | of it, thus forming a work based on the Program, and copy and 92 | distribute such modifications or work under the terms of Section 1 93 | above, provided that you also meet all of these conditions: 94 | 95 | a) You must cause the modified files to carry prominent notices 96 | stating that you changed the files and the date of any change. 97 | 98 | b) You must cause any work that you distribute or publish, that in 99 | whole or in part contains or is derived from the Program or any 100 | part thereof, to be licensed as a whole at no charge to all third 101 | parties under the terms of this License. 102 | 103 | c) If the modified program normally reads commands interactively 104 | when run, you must cause it, when started running for such 105 | interactive use in the most ordinary way, to print or display an 106 | announcement including an appropriate copyright notice and a 107 | notice that there is no warranty (or else, saying that you provide 108 | a warranty) and that users may redistribute the program under 109 | these conditions, and telling the user how to view a copy of this 110 | License. (Exception: if the Program itself is interactive but 111 | does not normally print such an announcement, your work based on 112 | the Program is not required to print an announcement.) 113 | 114 | These requirements apply to the modified work as a whole. If 115 | identifiable sections of that work are not derived from the Program, 116 | and can be reasonably considered independent and separate works in 117 | themselves, then this License, and its terms, do not apply to those 118 | sections when you distribute them as separate works. But when you 119 | distribute the same sections as part of a whole which is a work based 120 | on the Program, the distribution of the whole must be on the terms of 121 | this License, whose permissions for other licensees extend to the 122 | entire whole, and thus to each and every part regardless of who wrote it. 123 | 124 | Thus, it is not the intent of this section to claim rights or contest 125 | your rights to work written entirely by you; rather, the intent is to 126 | exercise the right to control the distribution of derivative or 127 | collective works based on the Program. 128 | 129 | In addition, mere aggregation of another work not based on the Program 130 | with the Program (or with a work based on the Program) on a volume of 131 | a storage or distribution medium does not bring the other work under 132 | the scope of this License. 133 | 134 | 3. You may copy and distribute the Program (or a work based on it, 135 | under Section 2) in object code or executable form under the terms of 136 | Sections 1 and 2 above provided that you also do one of the following: 137 | 138 | a) Accompany it with the complete corresponding machine-readable 139 | source code, which must be distributed under the terms of Sections 140 | 1 and 2 above on a medium customarily used for software interchange; or, 141 | 142 | b) Accompany it with a written offer, valid for at least three 143 | years, to give any third party, for a charge no more than your 144 | cost of physically performing source distribution, a complete 145 | machine-readable copy of the corresponding source code, to be 146 | distributed under the terms of Sections 1 and 2 above on a medium 147 | customarily used for software interchange; or, 148 | 149 | c) Accompany it with the information you received as to the offer 150 | to distribute corresponding source code. (This alternative is 151 | allowed only for noncommercial distribution and only if you 152 | received the program in object code or executable form with such 153 | an offer, in accord with Subsection b above.) 154 | 155 | The source code for a work means the preferred form of the work for 156 | making modifications to it. For an executable work, complete source 157 | code means all the source code for all modules it contains, plus any 158 | associated interface definition files, plus the scripts used to 159 | control compilation and installation of the executable. However, as a 160 | special exception, the source code distributed need not include 161 | anything that is normally distributed (in either source or binary 162 | form) with the major components (compiler, kernel, and so on) of the 163 | operating system on which the executable runs, unless that component 164 | itself accompanies the executable. 165 | 166 | If distribution of executable or object code is made by offering 167 | access to copy from a designated place, then offering equivalent 168 | access to copy the source code from the same place counts as 169 | distribution of the source code, even though third parties are not 170 | compelled to copy the source along with the object code. 171 | 172 | 4. You may not copy, modify, sublicense, or distribute the Program 173 | except as expressly provided under this License. Any attempt 174 | otherwise to copy, modify, sublicense or distribute the Program is 175 | void, and will automatically terminate your rights under this License. 176 | However, parties who have received copies, or rights, from you under 177 | this License will not have their licenses terminated so long as such 178 | parties remain in full compliance. 179 | 180 | 5. You are not required to accept this License, since you have not 181 | signed it. However, nothing else grants you permission to modify or 182 | distribute the Program or its derivative works. These actions are 183 | prohibited by law if you do not accept this License. Therefore, by 184 | modifying or distributing the Program (or any work based on the 185 | Program), you indicate your acceptance of this License to do so, and 186 | all its terms and conditions for copying, distributing or modifying 187 | the Program or works based on it. 188 | 189 | 6. Each time you redistribute the Program (or any work based on the 190 | Program), the recipient automatically receives a license from the 191 | original licensor to copy, distribute or modify the Program subject to 192 | these terms and conditions. You may not impose any further 193 | restrictions on the recipients' exercise of the rights granted herein. 194 | You are not responsible for enforcing compliance by third parties to 195 | this License. 196 | 197 | 7. If, as a consequence of a court judgment or allegation of patent 198 | infringement or for any other reason (not limited to patent issues), 199 | conditions are imposed on you (whether by court order, agreement or 200 | otherwise) that contradict the conditions of this License, they do not 201 | excuse you from the conditions of this License. If you cannot 202 | distribute so as to satisfy simultaneously your obligations under this 203 | License and any other pertinent obligations, then as a consequence you 204 | may not distribute the Program at all. For example, if a patent 205 | license would not permit royalty-free redistribution of the Program by 206 | all those who receive copies directly or indirectly through you, then 207 | the only way you could satisfy both it and this License would be to 208 | refrain entirely from distribution of the Program. 209 | 210 | If any portion of this section is held invalid or unenforceable under 211 | any particular circumstance, the balance of the section is intended to 212 | apply and the section as a whole is intended to apply in other 213 | circumstances. 214 | 215 | It is not the purpose of this section to induce you to infringe any 216 | patents or other property right claims or to contest validity of any 217 | such claims; this section has the sole purpose of protecting the 218 | integrity of the free software distribution system, which is 219 | implemented by public license practices. Many people have made 220 | generous contributions to the wide range of software distributed 221 | through that system in reliance on consistent application of that 222 | system; it is up to the author/donor to decide if he or she is willing 223 | to distribute software through any other system and a licensee cannot 224 | impose that choice. 225 | 226 | This section is intended to make thoroughly clear what is believed to 227 | be a consequence of the rest of this License. 228 | 229 | 8. If the distribution and/or use of the Program is restricted in 230 | certain countries either by patents or by copyrighted interfaces, the 231 | original copyright holder who places the Program under this License 232 | may add an explicit geographical distribution limitation excluding 233 | those countries, so that distribution is permitted only in or among 234 | countries not thus excluded. In such case, this License incorporates 235 | the limitation as if written in the body of this License. 236 | 237 | 9. The Free Software Foundation may publish revised and/or new versions 238 | of the General Public License from time to time. Such new versions will 239 | be similar in spirit to the present version, but may differ in detail to 240 | address new problems or concerns. 241 | 242 | Each version is given a distinguishing version number. If the Program 243 | specifies a version number of this License which applies to it and "any 244 | later version", you have the option of following the terms and conditions 245 | either of that version or of any later version published by the Free 246 | Software Foundation. If the Program does not specify a version number of 247 | this License, you may choose any version ever published by the Free Software 248 | Foundation. 249 | 250 | 10. If you wish to incorporate parts of the Program into other free 251 | programs whose distribution conditions are different, write to the author 252 | to ask for permission. For software which is copyrighted by the Free 253 | Software Foundation, write to the Free Software Foundation; we sometimes 254 | make exceptions for this. Our decision will be guided by the two goals 255 | of preserving the free status of all derivatives of our free software and 256 | of promoting the sharing and reuse of software generally. 257 | 258 | NO WARRANTY 259 | 260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS 266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE 267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, 268 | REPAIR OR CORRECTION. 269 | 270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, 273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING 274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED 275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY 276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER 277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE 278 | POSSIBILITY OF SUCH DAMAGES. 279 | 280 | END OF TERMS AND CONDITIONS 281 | 282 | Appendix: How to Apply These Terms to Your New Programs 283 | 284 | If you develop a new program, and you want it to be of the greatest 285 | possible use to the public, the best way to achieve this is to make it 286 | free software which everyone can redistribute and change under these terms. 287 | 288 | To do so, attach the following notices to the program. It is safest 289 | to attach them to the start of each source file to most effectively 290 | convey the exclusion of warranty; and each file should have at least 291 | the "copyright" line and a pointer to where the full notice is found. 292 | 293 | 294 | Copyright (C) 19yy 295 | 296 | This program is free software; you can redistribute it and/or modify 297 | it under the terms of the GNU General Public License as published by 298 | the Free Software Foundation; either version 2 of the License, or 299 | (at your option) any later version. 300 | 301 | This program is distributed in the hope that it will be useful, 302 | but WITHOUT ANY WARRANTY; without even the implied warranty of 303 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 304 | GNU General Public License for more details. 305 | 306 | You should have received a copy of the GNU General Public License 307 | along with this program; if not, write to the Free Software 308 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 309 | 310 | Also add information on how to contact you by electronic and paper mail. 311 | 312 | If the program is interactive, make it output a short notice like this 313 | when it starts in an interactive mode: 314 | 315 | Gnomovision version 69, Copyright (C) 19yy name of author 316 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 317 | This is free software, and you are welcome to redistribute it 318 | under certain conditions; type `show c' for details. 319 | 320 | The hypothetical commands `show w' and `show c' should show the appropriate 321 | parts of the General Public License. Of course, the commands you use may 322 | be called something other than `show w' and `show c'; they could even be 323 | mouse-clicks or menu items--whatever suits your program. 324 | 325 | You should also get your employer (if you work as a programmer) or your 326 | school, if any, to sign a "copyright disclaimer" for the program, if 327 | necessary. Here is a sample; alter the names: 328 | 329 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program 330 | `Gnomovision' (which makes passes at compilers) written by James Hacker. 331 | 332 | , 1 April 1989 333 | Ty Coon, President of Vice 334 | 335 | This General Public License does not permit incorporating your program into 336 | proprietary programs. If your program is a subroutine library, you may 337 | consider it more useful to permit linking proprietary applications with the 338 | library. If this is what you want to do, use the GNU Library General 339 | Public License instead of this License. 340 | -------------------------------------------------------------------------------- /Changelog: -------------------------------------------------------------------------------- 1 | txt2man-1.7.1 28-jun-2020 2 | 3 | * txt2man: remove ksh check (@eribertomota) 4 | * src2man: make it compliant with gawk >= 5.0.1 (@eribertomota) 5 | * txt2man: allow punctuation characters in section names 6 | * txt2man: allow display blocks starting with a number 7 | * *man: check for dependencies (@eribertomota) 8 | * build: make build reproducible 9 | 10 | txt2man-1.7.0 03-jun-2020 11 | 12 | * bookman: added missing space (@marxst) 13 | * txt2man: remove redundant escapes causing gawk warnings (@jolmg) 14 | * *man: Fix usage of the date command on BSD systems (@ismaell) 15 | * txt2man: fix -B option (@bgstack15) 16 | * src2man: Print names of manuals to stdout (@ldorau) 17 | 18 | txt2man-1.6.0 15-aug-2016 19 | 20 | * txt2man: Format date with C locale (by @Vogtinator) 21 | * txt2man: Do not overwrite manually specified release with 22 | autoprobe (by @Vogtinator) 23 | * txt2man: man page spelling fixes (by @eribertomota) 24 | * bookman: Fix bashisms (by @eribertomota) 25 | * bookman, src2man, txt2man: support timestamps from environment 26 | (by @reinerh) 27 | 28 | txt2man-1.5.6 16-mar-2011 29 | 30 | * txt2man: Better control of 3 letters regexp, by Robin Cornelius. 31 | * txt2man: Fix header comment generation, by Robin Cornelius. 32 | * txt2man: Better handle ticks, by Thomas Moschny. 33 | * src2man: Fix header comment generation. 34 | * src2man: more robust comment delimiter handling. 35 | * src2man: support C prototypes with newline after type, by Diego Cena. 36 | * bookman: Posix shell syntax. 37 | 38 | txt2man-1.5.5 21-mar-2007 39 | 40 | * txt2man: correct layout of C structures in synopsis 41 | * src2man: genrate manpages for C types/struct definitions 42 | 43 | txt2man-1.5.4 16-mar-2007 44 | 45 | * bookman: Added copyright 46 | * src2man: Added copyright. Fix cover page handling. Add origin 47 | comment in generated manpages. 48 | 49 | txt2man-1.5.3 15-mar-2007 50 | 51 | * bookman: better handling of header and footers of cover page. 52 | * src2man: date can now be set. 53 | * txt2man: date can now be set. Better handling of C function prototypes. 54 | 55 | txt2man-1.5.2 28-feb-2007 56 | 57 | * txt2man: fix synopsis handling. 58 | 59 | txt2man-1.5.1 25-oct-2006 60 | 61 | * src2man: search if the function prototype is defined in corresponding 62 | '.h' include file, and if yes, add a '#include "file.h"' 63 | statement in synopsis. 64 | * src2man: allow to force SYNOPSIS sections in comment blocks. 65 | * bookman: reads the file list from stdin in no arg is supplied. 66 | * Makefile: specify commands path (in current dir) when generating doc. 67 | 68 | txt2man-1.5 16-oct-2006 69 | 70 | * txt2man: fix indentation. 71 | * bookman: new command to generate a book from manpages. 72 | * src2man: new command to extract manpages from source files. 73 | * Makefile: update and fix rules. 74 | 75 | txt2man-1.4.8 07-jul-2003 76 | 77 | * txt2man: fix a bug in tag list parsing (bug discovered by Fredrik Steen) 78 | * txt2man: fix a bug in parsing spaces in empty lines 79 | * Makefile: Create install target directories, if not there 80 | 81 | txt2man-1.4.7 06-jan-2003 82 | 83 | * fix gawk --lint warnings (from Eric Moors) 84 | * fix a warning for an escape sequence (from Juergen Daubert) 85 | 86 | txt2man-1.4.6 16-dec-2002 87 | Changelog starts from here! 88 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # Makefile 2 | prefix ?= /usr/local 3 | version = txt2man-1.7.1 4 | date = 2020-06-28 5 | BIN = src2man bookman txt2man 6 | MAN1 = src2man.1 txt2man.1 bookman.1 7 | 8 | all: $(MAN1) 9 | 10 | .PHONY: install test clean 11 | 12 | install: $(MAN1) 13 | mkdir -p $(prefix)/bin $(prefix)/share/man/man1 14 | cp $(BIN) $(prefix)/bin/ 15 | cp $(MAN1) $(prefix)/share/man/man1 16 | 17 | test: 18 | ./runtest 19 | 20 | clean: 21 | rm -f *.1 *.txt *.ps *.pdf *.html 22 | 23 | %.1:%.txt; ./txt2man -s 1 -t $* -r $(version) -d $(date) $< > $@ 24 | %.txt:%; ./$< -h 2>&1 > $@ 25 | %.html:%.1; rman -f HTML $< > $@ 26 | %.ps:%.1; groff -man $< > $@ 27 | %.pdf:%.ps; ps2pdf $< > $@ 28 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | NAME 2 | txt2man 3 | 4 | DESCRIPTION 5 | Txt2man converts flat ASCII text to man page format. It is a shell 6 | script using gnu awk, that should run on any Unix like system. 7 | 8 | help: txt2man -h 9 | 10 | INSTALL 11 | make install (to install under /usr/local) 12 | or 13 | make install prefix=path 14 | 15 | Issues and pull requests should be opened at https://github.com/mvertes/txt2man. 16 | 17 | -- Marc Vertes 18 | -------------------------------------------------------------------------------- /bookman: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # Generate a book from man pages. 3 | 4 | # Copyright (C) 2006 Marc Vertes 5 | 6 | # This program is free software; you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation; either version 2, or (at your option) 9 | # any later version. 10 | 11 | # This program is distributed in the hope that it will be useful, 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | # GNU General Public License for more details. 15 | 16 | # You should have received a copy of the GNU General Public License 17 | # along with this program; if not, write to the Free Software 18 | # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 19 | # 02111-1307, USA. 20 | 21 | # release 1.7.1 22 | 23 | man() { 24 | cat << \EOT 25 | NAME 26 | bookman - Generate a book from man pages 27 | SYNOPSIS 28 | bookman [-pPxn] [-o outfile] [-a author] [-d date] [-r release] 29 | [-t title] [-v volume] [-c coverfile] [manfile] 30 | DESCRIPTION 31 | bookman compiles a set of man pages files specified by manfile 32 | arguments, or if no manfile is given, filenames are read from standard 33 | input. 34 | OPTIONS 35 | -p PDF output format. 36 | -P Postscript output format. 37 | -x X11 previewing, using gxditview(1). 38 | -n no format, output is direct gtroff intermediate format. 39 | -o outfile Output in file outfile. Default is standard output. 40 | -a author Set the author, on the cover page. 41 | -d date Set the date on the cover page. 42 | -r release Set the book name and release on the cover page. 43 | -t title Set the title on the cover page. 44 | -v volume Specify the name of the volume. 45 | -c coverfile Uses the file coverfile to generate the cover page, 46 | i.e. all pages preceding the table of content. coverfile 47 | must be in groff_ms(7) format. 48 | ENVIRONMENT 49 | SOURCE_DATE_EPOCH Unix timestamp that is used for date in header instead 50 | of current date. 51 | 52 | EXAMPLE 53 | To build a reference manual from section 2 man, do: 54 | 55 | $ cd /usr/share/man/man2 56 | $ bookman -p -t 'Unix Reference Manual' * >book.pdf 57 | 58 | SEE ALSO 59 | man(1), mandoc(7), groff_ms(7), groff(1), troff(1), grops(1), 60 | gxditview(1), ps2pdf(1). 61 | AUTHOR 62 | Marc Vertes 63 | EOT 64 | } 65 | 66 | post="grops" 67 | 68 | while getopts :a:c:d:mno:pPr:t:v:x opt 69 | do 70 | case $opt in 71 | (a) author=$OPTARG;; 72 | (c) cover=$OPTARG;; 73 | (d) date=$OPTARG;; 74 | (m) man; exit;; 75 | (n) post=cat;; 76 | (o) outfile=$OPTARG;; 77 | (p) post='grops | ps2pdf -';; 78 | (P) post=grops;; 79 | (x) post='gxditview -';; 80 | (r) release=$OPTARG;; 81 | (t) title=$OPTARG;; 82 | (v) volume=$OPTARG;; 83 | (*) man; exit;; 84 | esac 85 | done 86 | shift $(($OPTIND - 1)) 87 | 88 | # Check for dependencies 89 | groff -ms /dev/null || { 90 | printf "ERROR: You need install groff.\n" >&2 91 | exit 1 92 | } 93 | 94 | ps2pdf 2>&1 | grep -q Usage || { 95 | printf "ERROR: You need install ghostscript.\n" >&2 96 | exit 1 97 | } 98 | 99 | # Compatibility wrapper for BSD/GNU date, for parsing dates 100 | if date -j >/dev/null 2>&1; then 101 | pdate() { date -u -j -f '@%s' "$@"; } 102 | else 103 | pdate() { date -u -d "$@"; } 104 | fi 105 | 106 | if [ -n "$SOURCE_DATE_EPOCH" ]; then 107 | date=$(LC_ALL=C pdate "@$SOURCE_DATE_EPOCH" +'%d %B %Y') 108 | fi 109 | date=${date:-$(LC_ALL=C date -u +'%d %B %Y')} 110 | 111 | [ $1 ] || set -- $(while read REPLY; do echo "$REPLY"; done) 112 | 113 | [ $outfile ] && post="$post >$outfile" 114 | 115 | { 116 | # Compute table of content from postscript output. 117 | # Generate output in gtroff intermediate format, so 118 | # it can be merged with content. 119 | { 120 | [ -f "$cover" ] && cat "$cover" || { 121 | printf ".af %% i\n.P1\n" 122 | printf ".OH ||%s||\n" "$volume" 123 | printf ".EH ||%s||\n" "$volume" 124 | printf ".OF |%s|%s|%%|\n" "$release" "$date" 125 | printf ".EF |%s|%s|%%|\n" "$release" "$date" 126 | printf ".TL\n%s\n" "$title" 127 | printf ".AU\n%s\n.AB no\n.AE\n" "$author" 128 | } 129 | for f 130 | do 131 | case $f in 132 | (*.Z|*.gz) zcat $f;; 133 | (*.bz2) bzcat $f;; 134 | (*) cat $f;; 135 | esac 136 | done | groff -man -rC1 -Tps | awk ' 137 | $1 == "%%Page:" {page = $2} 138 | /%%EndPageSetup/ { 139 | getline l; getline; $0 = l $0 140 | # extract first word (disgard everything 141 | # outside braces). 142 | sub(/^[^\(]*\(/, "") 143 | gsub(/\)[^\(]*\(/, "") 144 | gsub(/\\214/, "fi") 145 | gsub(/\\215/, "fl") 146 | sub(/\)[^\(]*/, "") 147 | sub(/\\\(.*/, "") 148 | if (name != $0) { 149 | print (page == 1) ? ".XS 1" : ".XA " page 150 | print $0 151 | } 152 | name = $0 153 | } 154 | END {print ".XE"; print ".PX"}' 155 | } | groff -Z -ms | head --lines=-1 156 | 157 | # Output content, in gtroff intermediate format. 158 | for f 159 | do 160 | case $f in 161 | (*.Z|*.gz) zcat $f;; 162 | (*.bz2) bzcat $f;; 163 | (*) cat $f;; 164 | esac 165 | done | groff -Z -man -rC1 | awk 'NR >3' 166 | 167 | } | eval $post 168 | -------------------------------------------------------------------------------- /runtest: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | run() { 4 | ./txt2man -d "May 2025" "$1" >out 5 | diff -u "${1%.txt}.wanted" out 6 | } 7 | 8 | trap "rm -f out" EXIT 9 | nerr=0 10 | 11 | for t in test/*.txt; do 12 | if run "$t"; then 13 | echo "$t: PASS" 14 | else 15 | echo "$t: FAIL" 16 | nerr=$((nerr + 1)) 17 | fi 18 | done 19 | 20 | if [ $nerr != 0 ]; then 21 | echo "$nerr tests FAIL" 22 | exit 1 23 | fi 24 | 25 | -------------------------------------------------------------------------------- /src2man: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # Extract manpages from C source files. 3 | 4 | # Copyright (C) 2006 Marc Vertes 5 | 6 | # This program is free software; you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation; either version 2, or (at your option) 9 | # any later version. 10 | 11 | # This program is distributed in the hope that it will be useful, 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | # GNU General Public License for more details. 15 | 16 | # You should have received a copy of the GNU General Public License 17 | # along with this program; if not, write to the Free Software 18 | # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 19 | # 02111-1307, USA. 20 | 21 | # release 1.7.1 22 | 23 | man() { 24 | cat << \EOT 25 | NAME 26 | src2man - extract man pages from source files. 27 | SYNOPSIS 28 | src2man [-n][-d date][-v volume][-r release] [srcfile ...] 29 | DESCRIPTION 30 | src2man scans source file srcfile. Only C source files are supported 31 | for now. Comments blocks starting by "/** num", where num is a section 32 | number, are converted into a man file, using txt2man(1). 33 | 34 | The first line of the comment block must contain the name of the 35 | manpage, usually the function name, followed by a "-" and a short 36 | description. The following lines are the "DESCRIPTION" section 37 | content, except if they are in upper case, in which case they define 38 | a new section. 39 | 40 | If the next line after a comment block is empty, Then no "SYNOPSIS" 41 | section will be generated. Otherwise, src2man will look in the following 42 | source lines for a function prototype or a type definion (struct, 43 | union, typedef, ...) matching the manpage name, and include it in a 44 | "SYNOPSIS" section. This avoids to duplicate the type or function 45 | prototype in the comment block. 46 | 47 | The best place for code documentation is in the source file, where 48 | the body is implemented, not the header file which only contains 49 | the prototype. src2man automatically searches for the presence of a 50 | prototype in the corresponding header file, and if found, will print a 51 | "#include" statement in the synopsis. 52 | 53 | OPTIONS 54 | -d date Set the date of the man pages. Defaults to current date. 55 | -n No man page is created. The name of the manpages that would 56 | be created are printed. 57 | -v volume Specify the name of the volume to be printed in center header 58 | of generated manpages. 59 | -r release Specify the project name and release number for the generated 60 | manpage. 61 | ENVIRONMENT 62 | SOURCE_DATE_EPOCH Unix timestamp that is used for date in header instead 63 | of current date. 64 | EXAMPLE 65 | The following example displays C code and comments to generate a manpage 66 | foobar.3: 67 | 68 | /** 3 69 | * foobar - a sample dummy function 70 | * This line is now the first of the description section. 71 | * Note that function parameters parm1 and parm2 are highlighted 72 | * in the generated man page. 73 | */ 74 | int foobar(char *parm1, int parm2) 75 | { 76 | ... 77 | return 0; 78 | } 79 | 80 | SEE ALSO 81 | txt2man(1), bookman(1). 82 | AUTHOR 83 | Marc Vertes 84 | EOT 85 | } 86 | 87 | nogen=0 88 | release=unknown 89 | while getopts :d:hnr:v: opt 90 | do 91 | case $opt in 92 | (d) date="$OPTARG";; 93 | (n) nogen=1;; 94 | (v) volume="$OPTARG";; 95 | (r) release="$OPTARG";; 96 | (*) man; exit;; 97 | esac 98 | done 99 | shift $(($OPTIND - 1)) 100 | 101 | # Compatibility wrapper for BSD/GNU date, for parsing dates 102 | if date -j >/dev/null 2>&1; then 103 | pdate() { date -u -j -f '@%s' "$@"; } 104 | else 105 | pdate() { date -u -d "$@"; } 106 | fi 107 | 108 | if [ -n "$SOURCE_DATE_EPOCH" ]; then 109 | date=$(LC_ALL=C pdate "@$SOURCE_DATE_EPOCH" +'%d %B %Y') 110 | fi 111 | date=${date:-$(LC_ALL=C date -u +'%d %B %Y')} 112 | 113 | # 114 | # Extract manpages from source files. Man page content is enclosed in 115 | # commment blocks starting by "/** sectnum" 116 | # 117 | awk -v release="$release" -v volume="$volume" -v nogen=$nogen ' 118 | $1 == "/**" && $2 ~ /^[0-9]/ { 119 | sect = $2 120 | getline 121 | sub(/^ *\* */, " ") 122 | title = $1 123 | line1_after_comment = 0 124 | in_struct = 0 125 | name = $0 126 | inc = FILENAME 127 | sub(/.[cS]$/, ".h", inc) 128 | found = "" 129 | grep_cmd = "test -f " inc " && grep -wq " title " " inc " \ 130 | 2>/dev/null && echo ok || echo nok" 131 | grep_cmd | getline found 132 | # description section extraction. 133 | in_synop = 0 134 | synop = "" 135 | while (getline) { 136 | if ($0 ~ / *\*\//) { # end of comment block 137 | sub(/ *\*\//, "") 138 | line1_after_comment = 1 139 | break 140 | } 141 | sub(/^ \* /, "") 142 | sub(/^ \*/, "") 143 | if ($1 ~ /^[A-Z ]+$/ && $1 != "SYNOPSIS") 144 | in_synop = 0 145 | if ($1 == "SYNOPSIS") { 146 | in_synop = 1 147 | continue 148 | } 149 | if ($1 == "DESCRIPTION") 150 | continue 151 | if (in_synop) 152 | synop = synop (synop ? "\n" : "") $0 153 | else 154 | desc = desc (desc ? "\n" : "") $0 155 | } 156 | # function prototype or struct extraction for synopsis. 157 | if (! synop) { 158 | while (getline) { 159 | if (line1_after_comment) { 160 | line1_after_comment = 0 161 | if (NF == 0) 162 | break 163 | split(name, tname) 164 | } 165 | if ((!in_struct && $1 == "struct" && $2 == tname[1]) || 166 | (!in_struct && $2 == "struct" && $3 == tname[1])) { 167 | in_struct = 1 168 | synop = synop (synop ? "\n" : "") $0 169 | continue 170 | } 171 | synop = synop (synop ? "\n" : "") $0 172 | if (in_struct) { 173 | if ($0 ~ " *" tname[1] "[; ][*]*") break 174 | continue 175 | } 176 | if ($0 !~ /\)$/) { 177 | getline 178 | synop = synop " " $0 179 | } 180 | if ($0 ~/\)[ \t{};]*$/) { 181 | sub(/{[^}]}/, "", synop) 182 | sub(/[ \t]*$/, "", synop) 183 | if (found == "ok") 184 | synop = "#include \"" inc "\"\n" synop 185 | if (synop !~ /;$/) 186 | synop = synop ";" 187 | break 188 | } 189 | } 190 | } 191 | print title "." sect > "/dev/stdout" 192 | if (nogen) { 193 | name = synop = desc = sect = "" 194 | next 195 | } 196 | print "NAME\n" name (synop ? "\nSYNOPSIS\n " synop : "") \ 197 | "\nDESCRIPTION\n" desc "\nFILE\n " FILENAME | \ 198 | "{ echo '\''.\\\" Extracted by src2man from " FILENAME "'\''; \ 199 | txt2man -d \"$date\" -v \"" volume "\" -r " release \ 200 | " -s " sect " -t " title "; } >" title "." sect 201 | name = synop = desc = sect = "" 202 | } 203 | ' $* 204 | -------------------------------------------------------------------------------- /test/t000.txt: -------------------------------------------------------------------------------- 1 | NAME 2 | txt2man - convert flat ASCII text to man page format 3 | SYNOPSIS 4 | txt2man [-hpTX] [-t mytitle] [-P pname] [-r rel] [-s sect] 5 | [-v vol] [-I txt] [-B txt] [-d date] [ifile] 6 | DESCRIPTION 7 | txt2man converts the input text into nroff/troff standard man(7) 8 | macros used to format Unix manual pages. Nice pages can be generated 9 | specially for commands (section 1 or 8) or for C functions reference 10 | (sections 2, 3), with the ability to recognize and format command and 11 | function names, flags, types and arguments. 12 | 13 | txt2man is also able to recognize and format sections, paragraphs, 14 | lists (standard, numbered, description, nested), cross references and 15 | literal display blocks. 16 | 17 | If input file ifile is omitted, standard input is used. Result is 18 | displayed on standard output. 19 | 20 | Here is how text patterns are recognized and processed: 21 | Sections These headers are defined by a line in upper case, starting 22 | column 1. If there is one or more leading spaces, a 23 | sub-section will be generated instead. Optionally, the 24 | Section name can be preceded by a blank line. This is useful 25 | for a better visualization of the source text to be used to 26 | generate the manpage. 27 | Paragraphs They must be separated by a blank line, and left aligned. 28 | Alternatively two blank spaces can be used to produce the 29 | same result. This option will provide a better visualization 30 | of the source text to be used to generate the manpage. 31 | Tag list The item definition is separated from the item description 32 | by at least 2 blank spaces, even before a new line, if 33 | definition is too long. Definition will be emphasized 34 | by default. 35 | Bullet list 36 | Bullet list items are defined by the first word being "-" 37 | or "*" or "o". 38 | Enumerated list 39 | The first word must be a number followed by a dot. 40 | Literal display blocks 41 | This paragraph type is used to display unmodified text, 42 | for example source code. It must be separated by a blank 43 | line and be indented by a TAB. It is primarily used to format 44 | unmodified source code. It will be printed using fixed font 45 | whenever possible (troff). 46 | Cross references 47 | A cross reference (another man page) is defined by a word 48 | followed by a number in parenthesis. 49 | 50 | Special sections: 51 | NAME The function or command name and short description are set in 52 | this section. 53 | SYNOPSIS This section receives a special treatment to identify command 54 | name, flags and arguments, and propagate corresponding 55 | attributes later in the text. If a C like function is recognized 56 | (word immediately followed by an open parenthesis), txt2man will 57 | print function name in bold font, types in normal font, and 58 | variables in italic font. The whole section will be printed using 59 | a fixed font family (courier) whenever possible (troff). 60 | 61 | It is a good practice to embed documentation into source code, by using 62 | comments or constant text variables. txt2man allows one to do that, keeping 63 | the document source readable, usable even without further formatting 64 | (i.e. for online help) and easy to write. The result is high quality 65 | and standard complying document. 66 | OPTIONS 67 | -h The option -h displays help. 68 | -d date Set date in header. Defaults to current date. 69 | -P pname Set pname as project name in header. Default to uname -s. 70 | -p Probe title, section name and volume. 71 | -t mytitle Set mytitle as title of generated man page. 72 | -r rel Set rel as project name and release. 73 | -s sect Set sect as section in heading, usually a value from 1 to 8. 74 | -v vol Set vol as volume name, i.e. "Unix user 's manual". 75 | -I txt Italicize txt in output. Can be specified more than once. 76 | -B txt Emphasize (bold) txt in output. Can be specified more than once. 77 | -T Text result previewing using PAGER, usually more(1). 78 | -X X11 result previewing using gxditview(1). 79 | ENVIRONMENT 80 | PAGER name of paging command, usually more(1), or less(1). If not set 81 | falls back to more(1). 82 | SOURCE_DATE_EPOCH Unix timestamp that is used for date in header instead 83 | of current date. 84 | EXAMPLES 85 | Try this command to format this text itself: 86 | 87 | $ txt2man -h 2>&1 | txt2man -T 88 | 89 | The following command will generate a manpage level 1 to foo-1.1.0 program, 90 | from foo.txt file, used as source code to previously mentioned manpage: 91 | 92 | $ txt2man -d "15 May 2016" -t foo -r foo-1.1.0 -s 1 -v "show stars on screen" foo.txt > foo.1 93 | HINTS 94 | To obtain an overall good formatting of output document, keep paragraphs 95 | indented correctly. If you have unwanted bold sections, search for 96 | multiple spaces between words, which are used to identify a tag list 97 | (term followed by a description). Choose also carefully the name of 98 | command line or function parameters, as they will be emphasized each 99 | time they are encountered in the document. 100 | SEE ALSO 101 | man(1), mandoc(7), rman(1), groff(1), more(1), gxditview(1), troff(1). 102 | BUGS 103 | - Automatic probe (-p option) works only if input is a regular file (i.e. 104 | not stdin). 105 | AUTHOR 106 | Marc Vertes 107 | -------------------------------------------------------------------------------- /test/t000.wanted: -------------------------------------------------------------------------------- 1 | .\" Text automatically generated by txt2man 2 | .TH untitled "May 2025" "" "" 3 | .SH NAME 4 | \fBtxt2man \fP- convert flat ASCII text to man page format 5 | .SH SYNOPSIS 6 | .nf 7 | .fam C 8 | \fBtxt2man\fP [\fB-hpTX\fP] [\fB-t\fP \fImytitle\fP] [\fB-P\fP \fIpname\fP] [\fB-r\fP \fIrel\fP] [\fB-s\fP \fIsect\fP] 9 | [\fB-v\fP \fIvol\fP] [\fB-I\fP \fItxt\fP] [\fB-B\fP \fItxt\fP] [\fB-d\fP \fIdate\fP] [\fIifile\fP] 10 | .fam T 11 | .fi 12 | .fam T 13 | .fi 14 | .SH DESCRIPTION 15 | \fBtxt2man\fP converts the input text into nroff/troff standard \fBman\fP(7) 16 | macros used to format Unix manual pages. Nice pages can be generated 17 | specially for commands (section 1 or 8) or for C functions reference 18 | (sections 2, 3), with the ability to recognize and format command and 19 | function names, flags, types and arguments. 20 | .PP 21 | \fBtxt2man\fP is also able to recognize and format sections, paragraphs, 22 | lists (standard, numbered, description, nested), cross references and 23 | literal display blocks. 24 | .PP 25 | If input file \fIifile\fP is omitted, standard input is used. Result is 26 | displayed on standard output. 27 | .PP 28 | Here is how text patterns are recognized and processed: 29 | .TP 30 | .B 31 | Sections 32 | These headers are defined by a line in upper case, starting 33 | column 1. If there is one or more leading spaces, a 34 | sub-section will be generated instead. Optionally, the 35 | Section name can be preceded by a blank line. This is useful 36 | for a better visualization of the source text to be used to 37 | generate the manpage. 38 | .TP 39 | .B 40 | Paragraphs 41 | They must be separated by a blank line, and left aligned. 42 | Alternatively two blank spaces can be used to produce the 43 | same result. This option will provide a better visualization 44 | of the source text to be used to generate the manpage. 45 | .TP 46 | .B 47 | Tag list 48 | The item definition is separated from the item description 49 | by at least 2 blank spaces, even before a new line, if 50 | definition is too long. Definition will be emphasized 51 | by default. 52 | .TP 53 | .B 54 | Bullet list 55 | Bullet list items are defined by the first word being "-" 56 | or "*" or "o". 57 | .TP 58 | .B 59 | Enumerated list 60 | The first word must be a number followed by a dot. 61 | .TP 62 | .B 63 | Literal display blocks 64 | This paragraph type is used to display unmodified text, 65 | for example source code. It must be separated by a blank 66 | line and be indented by a TAB. It is primarily used to format 67 | unmodified source code. It will be printed using fixed font 68 | whenever possible (troff). 69 | .TP 70 | .B 71 | Cross references 72 | A cross reference (another man page) is defined by a word 73 | followed by a number in parenthesis. 74 | .PP 75 | Special sections: 76 | .TP 77 | .B 78 | NAME 79 | The function or command name and short description are set in 80 | this section. 81 | .TP 82 | .B 83 | SYNOPSIS 84 | This section receives a special treatment to identify command 85 | name, flags and arguments, and propagate corresponding 86 | attributes later in the text. If a C like function is recognized 87 | (word immediately followed by an open parenthesis), \fBtxt2man\fP will 88 | print function name in bold font, types in normal font, and 89 | variables in italic font. The whole section will be printed using 90 | a fixed font family (courier) whenever possible (troff). 91 | .PP 92 | It is a good practice to embed documentation into source code, by using 93 | comments or constant text variables. \fBtxt2man\fP allows one to do that, keeping 94 | the document source readable, usable even without further formatting 95 | (i.e. for online help) and easy to write. The result is high quality 96 | and standard complying document. 97 | .SH OPTIONS 98 | .TP 99 | .B 100 | \fB-h\fP 101 | The option \fB-h\fP displays help. 102 | .TP 103 | .B 104 | \fB-d\fP \fIdate\fP 105 | Set \fIdate\fP in header. Defaults to current \fIdate\fP. 106 | .TP 107 | .B 108 | \fB-P\fP \fIpname\fP 109 | Set \fIpname\fP as project name in header. Default to uname \fB-s\fP. 110 | .TP 111 | .B 112 | \fB-p\fP 113 | Probe title, section name and volume. 114 | .TP 115 | .B 116 | \fB-t\fP \fImytitle\fP 117 | Set \fImytitle\fP as title of generated man page. 118 | .TP 119 | .B 120 | \fB-r\fP \fIrel\fP 121 | Set \fIrel\fP as project name and release. 122 | .TP 123 | .B 124 | \fB-s\fP \fIsect\fP 125 | Set \fIsect\fP as section in heading, usually a value from 1 to 8. 126 | .TP 127 | .B 128 | \fB-v\fP \fIvol\fP 129 | Set \fIvol\fP as volume name, i.e. "Unix user 's manual". 130 | .TP 131 | .B 132 | \fB-I\fP \fItxt\fP 133 | Italicize \fItxt\fP in output. Can be specified more than once. 134 | .TP 135 | .B 136 | \fB-B\fP \fItxt\fP 137 | Emphasize (bold) \fItxt\fP in output. Can be specified more than once. 138 | .TP 139 | .B 140 | \fB-T\fP 141 | Text result previewing using PAGER, usually \fBmore\fP(1). 142 | .TP 143 | .B 144 | \fB-X\fP 145 | X11 result previewing using \fBgxditview\fP(1). 146 | .SH ENVIRONMENT 147 | .TP 148 | .B 149 | PAGER 150 | name of paging command, usually \fBmore\fP(1), or \fBless\fP(1). If not set 151 | falls back to \fBmore\fP(1). 152 | .TP 153 | .B 154 | SOURCE_DATE_EPOCH 155 | Unix timestamp that is used for \fIdate\fP in header instead 156 | of current \fIdate\fP. 157 | .SH EXAMPLES 158 | Try this command to format this text itself: 159 | .PP 160 | .nf 161 | .fam C 162 | $ txt2man -h 2>&1 | txt2man -T 163 | 164 | .fam T 165 | .fi 166 | The following command will generate a manpage level 1 to foo-1.1.0 program, 167 | from foo.txt file, used as source code to previously mentioned manpage: 168 | .PP 169 | .nf 170 | .fam C 171 | $ txt2man -d "15 May 2016" -t foo -r foo-1.1.0 -s 1 -v "show stars on screen" foo.txt > foo.1 172 | .fam T 173 | .fi 174 | .SH HINTS 175 | To obtain an overall good formatting of output document, keep paragraphs 176 | indented correctly. If you have unwanted bold sections, search for 177 | multiple spaces between words, which are used to identify a tag list 178 | (term followed by a description). Choose also carefully the name of 179 | command line or function parameters, as they will be emphasized each 180 | time they are encountered in the document. 181 | .SH SEE ALSO 182 | \fBman\fP(1), \fBmandoc\fP(7), \fBrman\fP(1), \fBgroff\fP(1), \fBmore\fP(1), \fBgxditview\fP(1), \fBtroff\fP(1). 183 | .SH BUGS 184 | .IP \(bu 3 185 | Automatic probe (\fB-p\fP option) works only if input is a regular file (i.e. 186 | not stdin). 187 | .SH AUTHOR 188 | Marc Vertes 189 | -------------------------------------------------------------------------------- /test/t001.txt: -------------------------------------------------------------------------------- 1 | INITIAL 2 | A test only 3 | OPTIONS 4 | option1 this is an option 5 | option2 this is an option 6 | EXAMPLE 7 | A block: 8 | 9 | ORD DAY WHAT 10 | --------------------- 11 | 1 15 Do anything 12 | 2 30 Do nothing 13 | 14 | The end 15 | is here. 16 | -------------------------------------------------------------------------------- /test/t001.wanted: -------------------------------------------------------------------------------- 1 | .\" Text automatically generated by txt2man 2 | .TH untitled "May 2025" "" "" 3 | .SH INITIAL 4 | A test only 5 | .SH OPTIONS 6 | .TP 7 | .B 8 | option1 9 | this is an option 10 | .TP 11 | .B 12 | option2 13 | this is an option 14 | .SH EXAMPLE 15 | A block: 16 | .PP 17 | .nf 18 | .fam C 19 | ORD DAY WHAT 20 | --------------------- 21 | 1 15 Do anything 22 | 2 30 Do nothing 23 | 24 | .fam T 25 | .fi 26 | The end 27 | is here. 28 | -------------------------------------------------------------------------------- /txt2man: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # Copyright (C) 2001, 2002, 2003 Marc Vertes 4 | 5 | # This program is free software; you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation; either version 2, or (at your option) 8 | # any later version. 9 | 10 | # This program is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | 15 | # You should have received a copy of the GNU General Public License 16 | # along with this program; if not, write to the Free Software 17 | # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 18 | # 02111-1307, USA. 19 | 20 | # release 1.7.1 21 | 22 | usage() 23 | { 24 | cat << EOT 25 | NAME 26 | txt2man - convert flat ASCII text to man page format 27 | SYNOPSIS 28 | txt2man [-hpTX] [-t mytitle] [-P pname] [-r rel] [-s sect] 29 | [-v vol] [-I txt] [-B txt] [-d date] [ifile] 30 | DESCRIPTION 31 | txt2man converts the input text into nroff/troff standard man(7) 32 | macros used to format Unix manual pages. Nice pages can be generated 33 | specially for commands (section 1 or 8) or for C functions reference 34 | (sections 2, 3), with the ability to recognize and format command and 35 | function names, flags, types and arguments. 36 | 37 | txt2man is also able to recognize and format sections, paragraphs, 38 | lists (standard, numbered, description, nested), cross references and 39 | literal display blocks. 40 | 41 | If input file ifile is omitted, standard input is used. Result is 42 | displayed on standard output. 43 | 44 | Here is how text patterns are recognized and processed: 45 | Sections These headers are defined by a line in upper case, starting 46 | column 1. If there is one or more leading spaces, a 47 | sub-section will be generated instead. Optionally, the 48 | Section name can be preceded by a blank line. This is useful 49 | for a better visualization of the source text to be used to 50 | generate the manpage. 51 | Paragraphs They must be separated by a blank line, and left aligned. 52 | Alternatively two blank spaces can be used to produce the 53 | same result. This option will provide a better visualization 54 | of the source text to be used to generate the manpage. 55 | Tag list The item definition is separated from the item description 56 | by at least 2 blank spaces, even before a new line, if 57 | definition is too long. Definition will be emphasized 58 | by default. 59 | Bullet list 60 | Bullet list items are defined by the first word being "-" 61 | or "*" or "o". 62 | Enumerated list 63 | The first word must be a number followed by a dot. 64 | Literal display blocks 65 | This paragraph type is used to display unmodified text, 66 | for example source code. It must be separated by a blank 67 | line and be indented by a TAB. It is primarily used to format 68 | unmodified source code. It will be printed using fixed font 69 | whenever possible (troff). 70 | Cross references 71 | A cross reference (another man page) is defined by a word 72 | followed by a number in parenthesis. 73 | 74 | Special sections: 75 | NAME The function or command name and short description are set in 76 | this section. 77 | SYNOPSIS This section receives a special treatment to identify command 78 | name, flags and arguments, and propagate corresponding 79 | attributes later in the text. If a C like function is recognized 80 | (word immediately followed by an open parenthesis), txt2man will 81 | print function name in bold font, types in normal font, and 82 | variables in italic font. The whole section will be printed using 83 | a fixed font family (courier) whenever possible (troff). 84 | 85 | It is a good practice to embed documentation into source code, by using 86 | comments or constant text variables. txt2man allows one to do that, keeping 87 | the document source readable, usable even without further formatting 88 | (i.e. for online help) and easy to write. The result is high quality 89 | and standard complying document. 90 | OPTIONS 91 | -h The option -h displays help. 92 | -d date Set date in header. Defaults to current date. 93 | -P pname Set pname as project name in header. Default to uname -s. 94 | -p Probe title, section name and volume. 95 | -t mytitle Set mytitle as title of generated man page. 96 | -r rel Set rel as project name and release. 97 | -s sect Set sect as section in heading, usually a value from 1 to 8. 98 | -v vol Set vol as volume name, i.e. "Unix user 's manual". 99 | -I txt Italicize txt in output. Can be specified more than once. 100 | -B txt Emphasize (bold) txt in output. Can be specified more than once. 101 | -T Text result previewing using PAGER, usually more(1). 102 | -X X11 result previewing using gxditview(1). 103 | ENVIRONMENT 104 | PAGER name of paging command, usually more(1), or less(1). If not set 105 | falls back to more(1). 106 | SOURCE_DATE_EPOCH Unix timestamp that is used for date in header instead 107 | of current date. 108 | EXAMPLES 109 | Try this command to format this text itself: 110 | 111 | $ txt2man -h 2>&1 | txt2man -T 112 | 113 | The following command will generate a manpage level 1 to foo-1.1.0 program, 114 | from foo.txt file, used as source code to previously mentioned manpage: 115 | 116 | $ txt2man -d "15 May 2016" -t foo -r foo-1.1.0 -s 1 -v "show stars on screen" foo.txt > foo.1 117 | HINTS 118 | To obtain an overall good formatting of output document, keep paragraphs 119 | indented correctly. If you have unwanted bold sections, search for 120 | multiple spaces between words, which are used to identify a tag list 121 | (term followed by a description). Choose also carefully the name of 122 | command line or function parameters, as they will be emphasized each 123 | time they are encountered in the document. 124 | SEE ALSO 125 | man(1), mandoc(7), groff(1), more(1), gxditview(1), troff(1). 126 | BUGS 127 | - Automatic probe (-p option) works only if input is a regular file (i.e. 128 | not stdin). 129 | AUTHOR 130 | Marc Vertes 131 | EOT 132 | } 133 | 134 | sys=$(uname -s) 135 | rel= 136 | volume= 137 | section= 138 | title=untitled 139 | doprobe= 140 | itxt= 141 | btxt= 142 | post=cat 143 | while getopts :d:hpTXr:s:t:v:P:I:B: opt 144 | do 145 | case $opt in 146 | (d) date=$OPTARG;; 147 | (r) rel=$OPTARG;; 148 | (t) title=$OPTARG;; 149 | (s) section=$OPTARG;; 150 | (v) volume=$OPTARG;; 151 | (P) sys=$OPTARG;; 152 | (p) doprobe=1;; 153 | (I) itxt="$OPTARG§$itxt";; 154 | (B) btxt="$OPTARG§$btxt";; 155 | (T) post="groff -mandoc -Tlatin1 | ${PAGER:-more}";; 156 | (X) post="groff -mandoc -TX100-12 -rS12";; 157 | (*) usage; exit;; 158 | esac 159 | done 160 | shift $(($OPTIND - 1)) 161 | 162 | # Compatibility wrapper for BSD/GNU date, for parsing dates 163 | if date -j >/dev/null 2>&1; then 164 | pdate() { date -u -j -f '@%s' "$@"; } 165 | else 166 | pdate() { date -u -d "$@"; } 167 | fi 168 | 169 | if [ -n "$SOURCE_DATE_EPOCH" ]; then 170 | date=$(LC_ALL=C pdate "@$SOURCE_DATE_EPOCH" +'%d %B %Y') 171 | fi 172 | date=${date:-$(LC_ALL=C date -u +'%d %B %Y')} 173 | 174 | if test "$doprobe" 175 | then 176 | title=${1##*/}; title=${title%.txt} 177 | if grep -q '#include ' $1 178 | then 179 | section=${section:-3} 180 | volume=${volume:-"$sys Programmer's Manual"} 181 | else 182 | section=${section:-1} 183 | volume=${volume:-"$sys Reference Manual"} 184 | fi 185 | # get release from path 186 | rel=${rel:-"$(pwd | sed 's:/.*[^0-9]/::g; s:/.*::g')"} 187 | fi 188 | 189 | head="\" Text automatically generated by txt2man 190 | .TH $title $section \"$date\" \"$rel\" \"$volume\"" 191 | 192 | # All tabs converted to spaces 193 | expand $* | 194 | # gawk is needed because use of non standard regexp 195 | gawk --re-interval -v head="$head" -v itxt="$itxt" -v btxt="$btxt" ' 196 | BEGIN { 197 | print ".\\" head 198 | avar[1] = btxt; avar[2] = itxt 199 | for (k in avar) { 200 | mark = (k == 1) ? "\\fB" : "\\fI" 201 | split(avar[k], tt, "§") 202 | for (i in tt) 203 | if (tt[i] != "") 204 | subwords["\\<" tt[i] "\\>"] = mark tt[i] "\\fP" 205 | for (i in tt) 206 | delete tt[i] 207 | } 208 | for (k in avar) 209 | delete avar[k] 210 | } 211 | { 212 | # to avoid some side effects in regexp 213 | gsub(/\.\.\./, "\\.\\.\\.") 214 | # remove spaces in empty lines 215 | sub(/^ +$/,"") 216 | } 217 | /^[[:upper:][:digit:]]+[[:upper:][:space:][:digit:][:punct:]]+$/ { 218 | # Section header 219 | if ((in_bd + 0) == 1) { 220 | in_bd = 0 221 | print ".fam T\n.fi" 222 | } 223 | if (section == "SYNOPSIS") { 224 | print ".fam T\n.fi" 225 | type["SYNOPSIS"] = "" 226 | } 227 | if ($0 ~/^[^[:space:]]/) 228 | print ".SH " $0 229 | else 230 | print ".SS" $0 231 | sub(/^ +/, "") 232 | section = $0 233 | if (section == "SYNOPSIS") { 234 | print ".nf\n.fam C" 235 | in_bd = 1 236 | } 237 | ls = 0 # line start index 238 | pls = 0 # previous line start index 239 | pnzls = 0 # previous non zero line start index 240 | ni = 0 # indent level 241 | ind[0] = 0 # indent offset table 242 | prevblankline = 0 243 | next 244 | } 245 | { 246 | # Compute line start index, handle start of example display block 247 | pls = ls 248 | if (ls != 0) 249 | pnzls = ls 250 | match($0, /[^ ]/) 251 | ls = RSTART 252 | if (in_bd == 0 && pls == 0 && pnzls > 0 && ls > pnzls && $1 !~ /^[\-\*o]$|^[0-9]+\.$/) { 253 | # example display block 254 | if (prevblankline == 1) { 255 | print ".PP" 256 | prevblankline = 0 257 | } 258 | print ".nf\n.fam C" 259 | in_bd = 1 260 | eoff = ls 261 | } 262 | if (ls > 0 && ind[0] == 0) 263 | ind[0] = ls 264 | } 265 | (in_bd + 0) == 1 { 266 | # In block display 267 | if (section == "SYNOPSIS") 268 | ; 269 | else if (ls != 0 && ls < eoff) { 270 | # End of literal display block 271 | in_bd = 0 272 | print ".fam T\n.fi" 273 | } else { print; next } 274 | } 275 | section == "NAME" { 276 | $1 = "\\fB" $1 277 | sub(/ \- /, " \\fP- ") 278 | } 279 | section == "SYNOPSIS" { 280 | # Identify arguments of fcts and cmds 281 | if (type["SYNOPSIS"] == "") { 282 | if ($0 ~ /\(/) 283 | type["SYNOPSIS"] = "fct" 284 | else if ($1 == "struct" || $2 == "struct") 285 | type["SYNOPSIS"] = "struct" 286 | else if ($1 && $1 !~ /^#|typedef|struct|union|enum/) 287 | type["SYNOPSIS"] = "cmd" 288 | } 289 | if (type["SYNOPSIS"] == "cmd") { 290 | # Line is a command line 291 | if ($1 !~ /^\[/) { 292 | b = $1 293 | sub(/^\*/, "", b) 294 | subwords["\\<" b "\\>"] = "\\fB" b "\\fP" 295 | } 296 | for (i = 2; i <= NF; i++) { 297 | a = $i 298 | gsub(/[\[\]\|]/, "", a) 299 | if (a ~ /^[^\-]/) 300 | subwords["\\<" a "\\>"] = "\\fI" a "\\fP" 301 | } 302 | } else if (type["SYNOPSIS"] == "fct") { 303 | # Line is a C function definition 304 | if ($1 == "typedef") { 305 | if ($0 !~ /\(\*/) 306 | subwords["\\<" $2 "\\>"] = "\\fI" $2 "\\fP" 307 | } else if ($1 == "#define") 308 | subwords["\\<" $2 "\\>"] = "\\fI" $2 "\\fP" 309 | for (i = 1; i <= NF; i++) { 310 | if ($i ~ /[,\)];*$/) { 311 | a = $i 312 | sub(/.*\(/, "", a) 313 | gsub(/\W/, "", a) 314 | subwords["\\<" a "\\>"] = "\\fI" a "\\fP" 315 | } 316 | } 317 | } 318 | } 319 | { 320 | # protect dots inside words 321 | while ($0 ~ /\w\.\w/) 322 | sub(/\./, "_dOt_") 323 | # identify func calls and cross refs 324 | for (i = 1; i <= NF; i++) { 325 | b = $i 326 | sub(/^\*/, "", b) 327 | if ((a = index(b, ")(")) > 3) { 328 | w = substr(b, 3, a - 3) 329 | subwords["\\<" w "\\>"] = "\\fI" w "\\fP" 330 | } 331 | if ((a = index(b, "(")) > 1) { 332 | w = substr(b, 1, a - 1) 333 | subwords["\\<" w "\\("] = "\\fB" w "\\fP(" 334 | } 335 | } 336 | # word attributes 337 | n = asorti(subwords, indices) 338 | for (i = 1; i <= n; i++) 339 | gsub(indices[i], subwords[indices[i]]) 340 | # shell options 341 | gsub(/\B\-+\w+(\-\w+)*/, "\\fB&\\fP") 342 | # unprotect dots inside words 343 | gsub(/_dOt_/, ".") 344 | 345 | if (section == "SYNOPSIS") { 346 | sub(/^ /, "") 347 | print 348 | next 349 | } 350 | if (match($0, /[^ ] +/) > 0) { 351 | # tag list item 352 | adjust_indent() 353 | tag = substr($0, 1, RSTART) 354 | sub(/^ */, "", tag) 355 | if (RSTART+RLENGTH < length()) 356 | $0 = substr($0, RSTART + RLENGTH) 357 | else 358 | $0 = "" 359 | print ".TP\n.B" 360 | print tag 361 | prevblankline = 0 362 | if (NF == 0) 363 | next 364 | } else if ($1 == "-"||$1 == "o"||$1 == "*") { 365 | # bullet list item 366 | adjust_indent() 367 | print ".IP \\(bu 3" 368 | prevblankline = 0 369 | $1 = "" 370 | } else if ($1 ~ /^[0-9]+[\).]$/) { 371 | # enum list item 372 | adjust_indent() 373 | print ".IP " $1 " 4" 374 | prevblankline = 0 375 | $1 = "" 376 | } else if (pls == 0) { 377 | # new paragraph 378 | adjust_indent() 379 | } else if (NF == 0) { 380 | # blank line 381 | prevblankline = 1 382 | next 383 | } else 384 | prevblankline = 0 385 | # flush vertical space 386 | if (prevblankline == 1) { 387 | print ".PP" 388 | prevblankline = 0 389 | } 390 | if (section != "SYNOPSIS" || $0 ~ /^ {1,4}/) 391 | sub(/ */,"") 392 | # Protect lines starting by simple quotes 393 | sub(/^'\''/, "\\(cq") 394 | print 395 | } 396 | 397 | function adjust_indent() 398 | { 399 | if (ls > ind[ni]) { 400 | ind[++ni] = ls 401 | print ".RS" 402 | } else if (ls < ind[ni]) { 403 | while (ls < ind[ni]) { 404 | ni-- 405 | print ".RE" 406 | } 407 | } 408 | } 409 | ' | eval $post 410 | --------------------------------------------------------------------------------