#!/bin/sh [ -n "$BASH" ] || exec bash -p $0 # Script to process man pages output by doxygen. # We need to use bash for its associative array facility. # (`bash -p` prevents import of functions from the environment). declare -A renamed_page main(){ set -e cd man/man3; rm -f _* count_real_pages rename_real_pages make_symlinks post_process } count_real_pages(){ page_count=0 # # Count "real" man pages (i.e. not generated by MAN_LINKS) # MAN_LINKS pages are 1-liners starting .so # Method: list files in descending order of size, # looking for the first 1-liner # for i in $(ls -S) do head -n1 $i | grep -E -q '^\.so' && break page_count=$(($page_count + 1)) done first_link=$(($page_count + 1)) } rename_real_pages(){ for i in $(ls -S | head -n$page_count) do for j in $(ls -S | tail -n+$first_link) do grep -E -q $i$ $j && break done mv -f $i $j renamed_page[$i]=$j done } make_symlinks(){ for j in $(ls -S | tail -n+$first_link) do ln -sf ${renamed_page[$(cat $j | cut -f2 -d/)]} $j done } post_process(){ make_temp_files # # DIAGNOSTIC / DEVELOPMENT CODE # set -x and restrict processing to keep_me: un-comment to activate # Change keep_me as required # #keep_me=nfq_icmp_get_hdr.3;\ #do_diagnostics;\ # # Work through the "real" man pages for target in $(ls -S | head -n$page_count) do mygrep "^\\.SH \"Function Documentation" $target # Next file if this isn't a function page [ $linnum -ne 0 ] || continue del_modules del_bogus_synopsis fix_name_line move_synopsis del_empty_det_desc del_def_at_lines fix_double_blanks # Fix rendering of verbatim "\n" (in code snippets) sed -i 's/\\n/\\\\n/' $target done remove_temp_files } fix_double_blanks(){ linnum=1 # # Older versions of man display a blank line on encountering "\fB\fP"; # newer versions of man do not. # doxygen emits "\fB\fP" on seeing "\par" on a line by itself. # "\par" gives us double-spacing in the web doc, which we want, but double- # spacing looks odd in a man page so remove "\fB\fP". # while [ $linnum -ne 0 ] do mygrep \\\\fB\\\\fP $target [ $linnum -eq 0 ] || delete_lines $linnum $linnum done } del_def_at_lines(){ linnum=1 while [ $linnum -ne 0 ] do mygrep '^Definition at line (\\fB)?[[:digit:]]*(\\fP)? of file' $target [ $linnum -eq 0 ] || delete_lines $(($linnum - 1)) $linnum done } # Only invoked if you un-comment the 2 diagnostic / development lines above do_diagnostics(){ mv $keep_me xxx rm *.3 mv xxx $keep_me page_count=1 set -x } del_empty_det_desc(){ mygrep "^\\.SH \"Function Documentation" $target i=$linnum mygrep "^\\.SH \"Detailed Description" $target [ $linnum -ne 0 ] || return 0 [ $(($i - $linnum)) -eq 3 ] || return 0 # A 1-line Detailed Description is also 3 lines long, # but the 3rd line is not empty i=$(($i -1)) [ $(tail -n+$i $target | head -n1 | wc -c) -le 2 ] || return 0 delete_lines $linnum $i } move_synopsis(){ mygrep "SH SYNOPSIS" $target [ $linnum -ne 0 ] || return 0 i=$linnum # If this is a doxygen-created synopsis, leave it. # (We haven't inserted our own one in the source yet) mygrep "^\\.SS \"Functions" $target [ $i -gt $linnum ] || return 0 mygrep "^\\.SH \"Function Documentation" $target j=$(($linnum - 1)) head -n$(($j - 1)) $target | tail -n$(($linnum - $i - 1)) >$fileC delete_lines $i $j mygrep "^\\.SS \"Functions" $target head -n$(($linnum - 1)) $target >$fileA tail -n+$(($linnum + 1)) $target >$fileB cat $fileA $fileC $fileB >$target } fix_name_line(){ all_funcs="" # Search a shortened version of the page in case there are .RI lines later mygrep "^\\.SH \"Function Documentation" $target head -n$linnum $target >$fileC while : do mygrep ^\\.RI $fileC [ $linnum -ne 0 ] || break # Discard this entry tail -n+$(($linnum + 1)) $fileC >$fileB cp $fileB $fileC func=$(cat $fileG | cut -f2 -d\\ | cut -c3-) [ -z "$all_funcs" ] && all_funcs=$func ||\ all_funcs="$all_funcs, $func" done # For now, assume name is at line 5 head -n4 $target >$fileA desc=$(head -n5 $target | tail -n1 | cut -f3- -d" ") tail -n+6 $target >$fileB cat $fileA >$target echo "$all_funcs \\- $desc" >>$target cat $fileB >>$target } del_modules(){ mygrep "^\.SS \"Modules" $target [ $linnum -ne 0 ] || return 0 i=$linnum mygrep "^\\.SS \"Functions" $target delete_lines $i $(($linnum - 1)) } del_bogus_synopsis(){ mygrep "SH SYNOPSIS" $target # # doxygen 1.8.20 inserts its own SYNOPSIS line but there is no mention # in the documentation or git log what to do with it. # So get rid of it # [ $linnum -ne 0 ] || return 0 i=$linnum # Look for the next one tail -n+$(($i + 1)) $target >$fileC;\ mygrep "SH SYNOPSIS" $fileC [ $linnum -ne 0 ] || return 0 mygrep "^\\.SS \"Functions" $target delete_lines $i $(($linnum - 1)) } # Delete lines $1 through $2 from $target delete_lines(){ head -n$(($1 - 1)) $target >$fileA tail -n+$(($2 +1)) $target >$fileB cat $fileA $fileB >$target } mygrep(){ set +e grep -En "$1" $2 2>/dev/null >$fileH [ $? -ne 0 ] && linnum=0 ||\ { head -n1 $fileH >$fileG; linnum=$(cat $fileG | cut -f1 -d:); } set -e } make_temp_files(){ temps="A B C G H" for i in $temps do declare -g file$i=$(mktemp) done } remove_temp_files(){ for i in $temps do j=file$i rm ${!j} done } main