WPrefs: sort alphabetically the key shortcut actions and expert options
[wmaker-crm.git] / script / generate-html-from-man.sh
blob1a921724a26befdaabb5d866aa607af67e019b14
1 #!/bin/sh
2 ###########################################################################
4 # Window Maker window manager
6 # Copyright (c) 2021 Christophe CURIS
7 # Copyright (c) 2021 Window Maker Team
9 # This program is free software; you can redistribute it and/or modify
10 # it under the terms of the GNU General Public License as published by
11 # the Free Software Foundation; either version 2 of the License, or
12 # (at your option) any later version.
14 # This program is distributed in the hope that it will be useful,
15 # but WITHOUT ANY WARRANTY; without even the implied warranty of
16 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 # GNU General Public License for more details.
19 # You should have received a copy of the GNU General Public License along
20 # with this program. If not, see <http://www.gnu.org/licenses/>.
22 ###########################################################################
24 # generate-html-from-man.sh:
25 # Convert a man page into HTML using Groff, then post-process it to make
26 # it fit the Window Maker site's theme and install it into the website
27 # Git repository.
29 # The pages are generated as xhtml because that's the most convenient
30 # format at current time that Groff can provide. The post-processing of the
31 # page includes:
33 # - the basic style sheet included by groff is replaced by a call to "manpage.css";
35 # - if a menu list is provided with "--with-menu", then it is added at the
36 # beginning of the <body> inside an "ul" with class="menu";
38 # - the list of sections at the beginning is enclosed in a div with class="toc";
40 # - emails addresses in the form "<name@example.com>" are obfuscated (to
41 # not help spambots) and a mailto: link is added;
43 # - a link is added when an url of the form "http://..." is encountered;
45 # - when a man-page reference is found, in the form "name(section)", a link
46 # is added, either to a local page if in the "--local-pages" list or to the
47 # external url provided in "--external-url";
49 # - if the package name and version is provided with "--package", then a div with
50 # class="footer" is added at the end of the <body>.
52 ###########################################################################
54 # For portability, we stick to the same sh+awk constraint as Autotools to
55 # limit problems, see for example:
56 # http://www.gnu.org/software/autoconf/manual/autoconf-2.69/html_node/Portable-Shell.html
58 ###########################################################################
60 # Report an error on stderr and exit with status 2 to tell make that we could
61 # not do what we were asked
62 arg_error() {
63 echo "`basename $0`: $@" >&2
64 exit 2
67 # print help and exit with success status
68 print_help() {
69 echo "$0: convert man page into HTML"
70 echo "Usage: $0 options... man-page-file"
71 echo "valid options are:"
72 echo " --external-url tmpl : use tmpl as URL template for non-local man pages"
73 echo " --groff name : name of groff binary to use"
74 echo " --local-pages names : list of man pages that are available locally"
75 echo " --output filename : name of the HTML file to generate"
76 echo " --with-menu code : insert the specified code to add a navigation menu"
77 echo " --package name : name of package, added in the footer of page"
78 exit 0
81 # Sets the default values
82 GROFF=groff
84 # Extract command line arguments
85 while [ $# -gt 0 ]; do
86 case $1 in
87 --external-url)
88 shift
89 [ "x$external_template" = "x" ] || arg_error "only 1 template for URL can be specified (option: --external-url)"
90 external_template=$1
93 --groff)
94 shift
95 GROFF=$1
98 --local-pages)
99 shift
100 local_pages="$local_pages $1 "
103 --output)
104 shift
105 [ -z "$output_file" ] || arg_error "only 1 target file can be specified (option: --output)"
106 output_file="$1"
109 --with-menu)
110 shift
111 [ -z "$menu_line" ] || arg_error "only 1 code for the menu can be specified (option: --with-menu)"
112 menu_line=`echo "$1" | sed -e 's/"/\\\"/g' `
115 --package)
116 shift
117 [ -z "$package_line" ] || arg_error "package name can be specified only once (option: --package)"
118 package_line="$1"
121 -h|-help|--help) print_help ;;
122 -*) arg_error "unknow option '$1'" ;;
125 [ -z "$input_file" ] || arg_error "only 1 man page can be specified"
126 input_file=$1
128 esac
129 shift
130 done
132 # Check consistency of command-line
133 [ -z "$input_file" ] && arg_error "no source man page given"
134 [ -f "$input_file" ] || arg_error "man page \"$input_file\" cannot be read"
136 if [ -n "$external_template" ]; then
137 echo "$external_template" | grep '%[plu]' > /dev/null \
138 || arg_error "no marker %p, %l or %u for the page name in the URL template (option: --external-url)"
141 # Generate the name of the output file from the man page file name
142 if [ -z "$output_file" ]; then
143 output_file=`echo "$input_file" | sed 's,^.*/,,g ; s/\.[^.]*$//' `.html
146 ###########################################################################
148 # Pass the configuration to the AWK script; remove the path information
149 awk_init="BEGIN {
150 external_template = \"$external_template\";
151 known_pages = \" $local_pages \";
152 menu_code = \"$menu_line\";
153 package_line = \"$package_line\";
154 source_name = \"`basename "$input_file" `\";
157 # This AWK script is post-processing the HTML generated by Groff
158 awk_process_html='
159 /<html>/ {
160 print;
161 $0 = "<!-- This file is generated automatically by a script, do not edit -->";
164 # Groff is generating a title with the name of the command, followed by a table of content
165 # We detect all this and embed it into a <div> section for presentation purpose
166 /<h1/ {
167 header = gensub(/<h1[^>]*>([^<]*)<\/h1>/, "\\1", 1);
168 print " <div class=\"toc\">";
169 print " <label for=\"toc-checkbutton\">" header "</label>";
170 print " <input type=\"checkbox\" id=\"toc-checkbutton\" checked=\"true\">";
171 print " <div id=\"toc-list\">";
172 getline;
173 while (!/<hr>/) {
174 if (length($0) > 0) {
175 print " " $0;
177 getline;
179 print " <hr>";
180 print " <a href=\".\" class=\"return\">Return to list</a><br>";
181 print " </div>";
182 print " </div>";
183 print "";
184 $0 = "<article>";
187 # Groff is adding an horizontal line at the end of the page, we remove it;
188 # we take the opportunity to close the <article> that we opened after the toc
189 /<hr>/ {
190 $0 = "</article>"
193 # Groff includes a basic CSS style, we want to replace it with our own to be consitent with
194 # the general website style
195 /<style/ {
196 while (!/<\/style>/) {
197 getline;
199 print "<link rel=\"stylesheet\" type=\"text/css\" href=\"/style.css\">";
200 $0 = "<link rel=\"stylesheet\" type=\"text/css\" href=\"/manpage.css\">"
203 # Detect the email address and add a link; take the opportunity to conceal it the same way it is
204 # done for the mailing list, to make spammers work less easy
205 /&lt;[^@ ]*@[^<@> ]*&gt;/ && inside_body {
206 line = "";
207 while (1) {
208 idx_start = match($0, /&lt;[^@ ]*@[^<@> ]*&gt;/);
209 if (idx_start == 0) break;
211 email = substr($0, idx_start + 4, RLENGTH - 8);
212 gsub(/@/, " (at) ", email);
213 gsub(/\./, " (dot) ", email);
215 line = line substr($0, 1, idx_start - 1) "&lt;";
216 line = line "<a href=\"mailto:" email "\">" email "</a>&gt;";
217 $0 = substr($0, idx_start + RLENGTH);
219 $0 = line $0;
222 # Detect urls and add a link
223 /http:\/\// && inside_body {
224 line = "";
225 while (1) {
226 idx_start = index($0, "http://");
227 if (idx_start == 0) break;
229 line = line substr($0, 1, idx_start - 1);
230 $0 = substr($0, idx_start);
231 idx_end = match($0, /[ \t&]/);
232 if (idx_end == 0) idx_end = length($0) + 1;
234 line = line "<a href=\"" substr($0, 1, idx_end - 1) "\">";
235 line = line substr($0, 1, idx_end - 1) "</a>";
237 $0 = substr($0, idx_end);
239 $0 = line $0;
242 # Detect references to other man pages and add a link
243 /<b>[A-Za-z_0-9]*<\/b>\([1-9][a-z]*\)/ {
244 line = "";
245 while (1) {
246 idx_start = match($0, /<b>[A-Za-z_0-9]*<\/b>\([1-9][a-z]*\)/);
247 if (idx_start == 0) break;
249 line = line substr($0, 1, idx_start - 1);
250 split(substr($0, idx_start + 3), elements, /<\/b>\(|\)/);
251 # elements[1] contains the name of the man-page
252 # elements[2] contains the section
253 $0 = substr($0, idx_start + RLENGTH);
255 idx_known = match(known_pages, " ([^ ]*/)*" elements[1] "\\." elements[2]);
256 if (idx_known == 0) {
257 if (external_template == "") {
258 print "Error: no URL provided for external man page, needed for \"" elements[1] "(" elements[2] ")\" at line " NR > "/dev/stderr";
259 exit(2);
261 url = gensub(/%s/, elements[2], "g", external_template);
262 url = gensub(/%p/, elements[1], "g", url);
263 url = gensub(/%l/, tolower(elements[1]), "g", url);
264 url = gensub(/%u/, toupper(elements[1]), "g", url);
265 } else {
266 # When it is a known page, use the data from known_pages to have possible path information
267 url = substr(known_pages, idx_known + 1, RLENGTH - length(elements[2]) - 2) ".html";
270 line = line "<a href=\"" url "\"><tt>" elements[1] "</tt>(" elements[2] ")</a>";
272 $0 = line $0;
275 # Detect the start of the page to insert the navigation menu code
276 /<body>/ {
277 inside_body = 1;
278 print;
279 print "<div id=\"wrapper\">";
280 if (menu_code) {
281 while (getline < menu_code) {
282 print;
285 next;
287 /<\/body>/ {
288 if (package_line) {
289 print "<div class=\"footer\">"
290 print " This man page is part of <div id=\"pkgname\">" package_line "</div>";
291 print "</div>"
293 print " <div id=\"titlebar\">";
294 print " <div id=\"minimize\"></div>";
295 print " <div id=\"titlebar-inner\">Window Maker Manual: " gensub(/\.(.*)$/, "(\\1)", 1, source_name) "</div>";
296 print " <div id=\"close\"></div>";
297 print " </div>";
298 print " <div id=\"resizebar\">";
299 print " <div id=\"resizel\"></div>";
300 print " <div id=\"resizebar-inner\"></div>";
301 print " <div id=\"resizer\"></div>";
302 print " </div>";
303 print "</div>"; # close "wrapper"
304 inside_body = 0;
307 { print }
310 ###########################################################################
311 $GROFF -man -Dutf8 -Thtml < "$input_file" | \
312 awk "$awk_init$awk_process_html" > "$TARGET/$output_file" \
313 || exit $?