1#!/usr/bin/perl 2 3use Getopt::Std; 4 5# Usage: fixman [-f] postconf.proto filename.c >filename.c.new 6 7# fixman - fix parameter text in embedded man pages 8 9# Basic operation: 10# 11# - Read definitions fron postconf.proto like file 12# 13# - Read source file with embedded manual page 14# 15# - Write to stdout the updated source file. 16# 17 18#use Getopt::Std; 19 20#$opt_h = undef; 21#$opt_v = undef; 22#getopts("hv"); 23 24#push @ARGV, "/dev/null"; # XXX 25 26$opt_f = undef; 27$opt_v = undef; 28getopts("fv"); 29 30die "Usage: $0 [-fv] protofile [sourcefile...] 31-f: include full parameter description instead of one-line summary 32-v: verbose mode\n" 33 unless $protofile = shift(@ARGV); 34 35# Save one definition. 36 37sub save_text 38{ 39 if ($category eq "PARAM") { 40 $text =~ s/\.\s.*/.\n/s unless $opt_f; 41 $param_text{$name} = $text; 42 $defval = "empty" unless $defval ne ""; 43 $defval_text{$name} = $defval; 44 if ($opt_v) { 45 printf "saving entry %s %.20s..\n", $name, $text; 46 } 47 } elsif ($category eq "CLASS") { 48 $class_text{$name} = $text; 49 if ($opt_v) { 50 printf "saving class %s %.20s..\n", $name, $text; 51 } 52 } else { 53 die "Unknown category: $category. Need PARAM or CLASS.\n"; 54 } 55} 56 57# Emit one parameter name and text 58 59sub emit_text 60{ 61 my ($delim) = @_; 62 if ($block = $param_text{$name}) { 63 print "$delim .IP \"\\fB$name ($defval_text{$name})\\fR\"\n"; 64 $wantpp = 0; 65 $block =~ s/<a [^>]*>//g; 66 $block =~ s/<\/a>//g; 67 $block =~ s/<b>/\\fB/g; 68 $block =~ s/<i>/\\fI/g; 69 $block =~ s/<\/b>/\\fR/g; 70 $block =~ s/<\/i>/\\fR/g; 71 $block =~ s/\n(<p(re)?>)/\n.sp\n\1/g ; # if ($wantpp); 72 $block =~ s/^(<p(re)?>)/.sp\n\1/ ; # if ($wantpp); 73 $block =~ s/<p> */\n/g; 74 $block =~ s/<\/p>/\n/g; 75 $block =~ s/<pre>/\n.nf\n.na\n.ft C\n/g; 76 $block =~ s/<\/pre>/\n.fi\n.ad\n.ft R\n/g; 77 $block =~ s/<dl[^>]*>/\n.RS\n/g; 78 $block =~ s/<ul>/\n.RS\n/g; 79 #$block =~ s/<\/dl>/\n.PP\n/g; 80 #$block =~ s/<\/ul>/\n.PP\n/g; 81 $block =~ s/<\/dl>/\n.RE\n.IP ""\n/g; 82 $block =~ s/<\/ul>/\n.RE\n.IP ""\n/g; 83 $block =~ s/<dd>/\n/g; 84 $block =~ s/<\/dd>/\n/g; 85 $block =~ s/<li>\s*/\n.IP \\(bu\n/g; 86 $block =~ s/<dt>\s*/\n.IP "/g; 87 $block =~ s/\s*<\/dt>/"/g; 88 $block =~ s/<blockquote>/\n.na\n.nf\n.in +4\n/g; 89 $block =~ s/<\/blockquote>/\n.in -4\n.fi\n.ad\n/g; 90 $block =~ s/\n<br>/\n.br\n/g; 91 $block =~ s/<br>\s*/\n.br\n/g; 92 $block =~ s/</</g; 93 $block =~ s/>/>/g; 94 95 # Peep-hole optimizer. 96 $block =~ s/^\s+//g; 97 $block =~ s/\s+\n/\n/g; 98 $block =~ s/^\n//g; 99 $block =~ s/\.IP ""\n(\.sp\n)+/.IP ""\n/g; 100 $block =~ s/\.IP ""\n(\.[A-Z][A-Z])/\1/g; 101 $block =~ s/(.IP ""\n)+$//; 102 $block =~ s/^(\.(PP|sp)\n)+//; 103 #$wantpp = !($block =~ /^\.(SH|IP)/); 104 105 # Boldify man page references. 106 $block =~ s/([_a-zA-Z0-9-]+)(\([0-9]\))/\\fB\1\\fR\2/g; 107 108 # Encapsulate as C code comment. 109 $block =~ s/^([^.])/$delim\t\1/; 110 $block =~ s/^\./$delim ./; 111 $block =~ s/\n([^.])/\n$delim\t\1/g; 112 $block =~ s/\n\./\n$delim ./g; 113 114 print $block; 115 } else { 116 print "$delim .IP \"\\fB$name ($defval)\\fR\"\n"; 117 print $text; 118 } 119 $name = ""; 120} 121 122# Read the whole file even if we want to print only one parameter. 123 124open(POSTCONF, $protofile) || die " cannot open $protofile: $!\n"; 125 126while(<POSTCONF>) { 127 128 next if /^#/; 129 next unless ($name || /\S/); 130 131 if (/^%(PARAM|CLASS)/) { 132 133 # Save the accumulated text. 134 135 if ($name && $text) { 136 save_text(); 137 } 138 139 # Reset the parameter name and accumulated text. 140 141 $name = $text = ""; 142 $category = $1; 143 144 # Accumulate the parameter name and default value. 145 146 do { 147 $text .= $_; 148 } while(($_ = <POSTCONF>) && /\S/); 149 ($junk, $name, $defval) = split(/\s+/, $text, 3); 150 151 $defval =~ s/\s+/ /g; 152 $defval =~ s/\s+$//; 153 $defval =~ s/</</g; 154 $defval =~ s/>/>/g; 155 $defval =~ s/"/'/g; 156 $text = ""; 157 next; 158 } 159 160 # Accumulate the text in the class or parameter definition. 161 162 $text .= $_; 163 164} 165 166# Save the last definition. 167 168if ($name && $text) { 169 save_text(); 170} 171 172# Process source file with embedded text. For now, hard-coded for C & sh. 173 174while(<>) { 175 176 if (/^(\/\*|#)\+\+/) { 177 $incomment = 1; 178 $name = ""; 179 print; 180 next; 181 } 182 183 if (/^(\/\*|#)--/) { 184 emit_text($1) if ($name ne ""); 185 $incomment = 0; 186 print; 187 next; 188 } 189 190 if (!$incomment) { 191 print; 192 next; 193 } 194 195 if (/(\/\*|#) +CONFIGURATION +PARAM/) { 196 $incomment = 2; 197 } 198 199 # Delete text after nested itemized list. 200 if ($incomment == 2 && /^(\/\*|#) +\.IP ""/) { 201 $text .= $_; 202 while (<>) { 203 last if /^(\/\*|#) +([A-Z][A-Z][A-Z]+|\.[A-Z][A-Z])/; 204 $text .= $_; 205 } 206 } 207 208 # Delete nested itemized list. 209 if ($incomment == 2 && /^(\/\*|#) +\.RS/) { 210 $text .= $_; 211 $rsnest++; 212 while (<>) { 213 $text .= $_; 214 $rsnest++ if /^(\/\*|#) +\.RS/; 215 $rsnest-- if /(\/\*|#) +\.RE/; 216 last if $rsnest == 0; 217 } 218 next; 219 } 220 221 if ($incomment == 2 && /^(\/\*|#) +\.IP +"?\\fB([a-zA-Z0-9_]+)( +\((.*)\))?/) { 222 emit_text($1) if ($name ne ""); 223 $name = $2; 224 $defval = $4; 225 $text = ""; 226 next; 227 } 228 229 if ($incomment == 2 && /^(\/\*|#) +([A-Z][A-Z][A-Z]+|\.[A-Z][A-Z])/) { 230 emit_text($1) if ($name ne ""); 231 $incomment = 0 if /^(\/\*|#) +(SEE +ALSO|README +FILES|LICENSE|AUTHOR)/; 232 print; 233 next; 234 } 235 236 if ($name ne "") { 237 $text .= $_; 238 next; 239 } 240 241 print; 242 next; 243} 244 245die "Unterminated comment\n" if $incomment; 246