summaryrefslogtreecommitdiffstats
path: root/doxygen/build_man.sh
blob: 0d3be4c06b016632df1294cd252496140c2d0201 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
#!/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