]> git.ipfire.org Git - thirdparty/man-pages.git/blob - scripts/add_parens_for_own_funcs.sh
Allow multiple directory command-line arguments
[thirdparty/man-pages.git] / scripts / add_parens_for_own_funcs.sh
1 #!/bin/sh
2 #
3 # add_parens_for_own_funcs.sh
4 #
5 # This script is designed to fix inconsistencies in the use of
6 # parentheses after function names in the manual pages.
7 # It changes manual pages to add these parentheses.
8 # The problem is how to determine what is a "function name".
9 # The approach this script takes is the following:
10 #
11 # For each manual page named in the command line that contains
12 # more than one line (i.e., skip man-page link files)
13 # Create a set of names taken from the .SH section of the
14 # page and from grepping all pages for names that
15 # have .so links to this page
16 # For each name obtained above
17 # If we can find something that looks like a prototype on
18 # the page, then
19 # Try to substitute instances of that name on the page.
20 # (instances are considered to be words formatted
21 # using ^.[BI] or \f[BI]...\f[PR] -- this script
22 # ignores unformatted instances on function names.)
23 # fi
24 # done
25 # done
26 #
27 # The rationale of the above is that the most likely function names
28 # that appear on a page are those that the manual page is describing.
29 # It doesn't fix everything, but it catches many instances.
30 # The rest will have to be done manually.
31 #
32 # This script is rather verbose because it provides a computer-assisted
33 # solution, rather than one that is fully automated. When running it,
34 # pipe the output through
35 #
36 # ... 2>&1 | less
37 #
38 # and take a good look at the output. In particular, you can scan
39 # the output for *possible* problems by looking for the pattern: /^%%%/
40 # The script's output should be enough to help you determine if the
41 # problem is real or not.
42 #
43 # Suggested usage (in this case to fix pages in Section 2):
44 #
45 # cd man2
46 # sh add_parens_for_own_funcs.sh *.2 2>&1 | tee changes.log | less
47 #
48 # Use the "-n" option for a dry run, in order to see what would be
49 # done, without actually doing it.
50 #
51 # (And, yes, there are many ways that this script could probably be
52 # made to work faster...)
53 #
54 ######################################################################
55 #
56 #
57
58 file_base="tmp.$(basename $0)"
59
60 work_dst_file="$file_base.dst"
61 work_src_file="$file_base.src"
62
63 matches_for_all_names="$file_base.all_match"
64 matches_for_this_name="$file_base.this_match"
65
66 all_files="$work_dst_file $work_src_file $matches_for_all_names \
67 $matches_for_this_name"
68
69 rm -f $all_files
70
71 # Command-line option processing
72
73 really_do_it=1
74 while getopts "n" optname; do
75 case "$optname" in
76 n) really_do_it=0;
77 ;;
78 *) echo "Unknown option: $OPTARG"
79 exit 1
80 ;;
81 esac
82 done
83
84 shift $(( OPTIND - 1 ))
85
86 # Only process files with > 1 line -- single-line files are link files
87
88 for page in $(wc $* 2> /dev/null | awk '$1 > 1 {print $4}'| \
89 grep -v '^total'); do
90
91 echo ">>>>>>>>>>>>>>>>>>>>>>>>>" $page "<<<<<<<<<<<<<<<<<<<<<<<<<"
92 echo ">>>>>>>>>>>>>>>>>>>>>>>>>" $page "<<<<<<<<<<<<<<<<<<<<<<<<<" 1>&2
93
94 # Extract names that follow the ".SH NAME" directive -- these will
95 # be our guesses about function names to look for
96
97 sh_nlist=$(cat $page | \
98 awk 'BEGIN { p = 0 }
99 /^\.SH NAME/ { p = NR }
100 /^.SH/ && NR > p { p = 0 } # Stop at the next .SH directive
101 p > 0 && NR > p {print $0} # These are the lines between
102 # the two .SH directives
103 ')
104 sh_nlist=$(echo $sh_nlist | sed -e 's/ *\\-.*//' -e 's/, */ /g')
105 echo "### .SH name list:" $sh_nlist
106
107 # Some pages like msgop.2 don't actually list the function names in
108 # the .SH section -- but we can try using link pages to give us
109 # another guess at the right function names to look for
110
111 so_nlist=$(grep -l "^\\.so.*/$(echo $page| \
112 sed -e 's/\.[1-8]$//')\\." $* | \
113 sed -e 's/\.[1-8]$//g')
114
115 echo "### .so name list:" $so_nlist
116
117 # Combine the two lists, eliminate duplicates
118
119 nlist=$(echo $sh_nlist $so_nlist | tr ' ' '\012' | sort -u)
120
121 maybechanged=0
122
123 cp $page $work_dst_file
124 rm -f $matches_for_all_names; # touch $matches_for_all_names
125
126 for rname in $nlist; do # try each name from out list for this page
127
128 # A very few names in .SH sections contain regexp characters!
129
130 name=$(echo $rname | sed -e 's/\*/\\*/g' -e 's/\./\\./g' \
131 -e 's/\[/\\[/g' -e 's/\+/\\+/g')
132
133 echo "########## trying $rname ##########"
134
135 rm -f $matches_for_this_name
136
137 grep "^.BR* $name *$" $page | \
138 >> $matches_for_this_name
139 grep "^.BR $name [^(\"]$" $page | \
140 >> $matches_for_this_name
141 grep '\\fB'"$name"'\\f[PR][ .,;:]' $page | \
142 >> $matches_for_this_name
143 grep '\\fB'"$name"'\\f[PR]$' $page | \
144 >> $matches_for_this_name
145
146 cat $matches_for_this_name | sed -e 's/^/### MATCH: /'
147 cat $matches_for_this_name >> $matches_for_all_names
148
149 # Only process a page if we can see something that looks
150 # like a function prototype for this name in the page
151
152 if grep -q "$name *(" $page || \
153 grep -q "$name\\\\f.[\\ ]*(" $page; then
154
155 # '.B name$'
156 # '.BR name [^("]*$
157 # (The use of [^"] in the above eliminates lines
158 # like: .BR func " and " func
159 # Those lines better be done manually.)
160 cp $work_dst_file $work_src_file
161 cat $work_src_file | \
162 sed \
163 -e "s/^.BR* $name *\$/.BR $name ()/" \
164 -e "/^.BR *$name [^(\"]*\$/s/^.BR *$name /.BR $name ()/" \
165 > $work_dst_file
166
167 # '\fBname\fP[ .,;:]'
168 # '\fBname\fP$'
169 cp $work_dst_file $work_src_file
170 cat $work_src_file | \
171 sed \
172 -e 's/\\fB'$name'\\fP /\\fB'$name'\\fP() /g' \
173 -e 's/\\fB'$name'\\fP\./\\fB'$name'\\fP()./g' \
174 -e 's/\\fB'$name'\\fP,/\\fB'$name'\\fP(),/g' \
175 -e 's/\\fB'$name'\\fP;/\\fB'$name'\\fP();/g' \
176 -e 's/\\fB'$name'\\fP:/\\fB'$name'\\fP():/g' \
177 -e 's/\\fB'$name'\\fP$/\\fB'$name'\\fP()/g' \
178 > $work_dst_file
179
180 # '\fBname\fR[ .,;:]'
181 # '\fBname\fR$'
182 cp $work_dst_file $work_src_file
183 cat $work_src_file | \
184 sed \
185 -e 's/\\fB'$name'\\fR /\\fB'$name'\\fR() /g' \
186 -e 's/\\fB'$name'\\fR\./\\fB'$name'\\fR()./g' \
187 -e 's/\\fB'$name'\\fR,/\\fB'$name'\\fR(),/g' \
188 -e 's/\\fB'$name'\\fR;/\\fB'$name'\\fR();/g' \
189 -e 's/\\fB'$name'\\fR:/\\fB'$name'\\fR():/g' \
190 -e 's/\\fB'$name'\\fR$/\\fB'$name'\\fR()/g' \
191 > $work_dst_file
192
193 maybechanged=1
194 else
195 echo "%%%%%%%%%% WARNING: NO PROTOTYPE MATCHES FOR: $name"
196 fi
197 done
198
199 # If the file was changed, then:
200 # show "diff -U" output to user;
201 # and count number of changed lines and compare it with what
202 # we expected, displaying a warning if it wasn't what was expected
203
204 if test $maybechanged -ne 0 && ! cmp -s $page $work_dst_file; then
205 diff -u $page $work_dst_file
206
207 made_matches=$(diff -U 0 $page $work_dst_file | grep '^\+[^+]' | \
208 wc -l | awk '{print $1}')
209
210 # The following line makes the changes -- comment it out if you
211 # just want to do a dry run to see what changes would be made.
212
213 if test $really_do_it -ne 0; then
214 cat $work_dst_file > $page
215 fi
216
217 else
218 echo "### NOTHING CHANGED"
219 made_matches=0
220 fi
221
222 min_match=$(cat $matches_for_all_names | \
223 sort -u | wc -l | awk '{print $1}')
224
225 echo "### Expected matches >= $min_match"
226 echo "### Made matches $made_matches"
227
228 if test $made_matches -lt $min_match; then
229 echo "%%%%%%%%%% WARNING: NOT ENOUGH MATCHES: " \
230 "$made_matches < $min_match"
231 fi
232
233 done
234
235 # clean up
236
237 rm -f $all_files
238 exit 0