1 #!/usr/bin/perl 2 3 use 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; 28 getopts("fv"); 29 30 die "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 37 sub 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 59 sub 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 $block =~ s/</</g; 95 $block =~ s/>/>/g; 96 $block =~ s/<sup>/^/g; 97 $block =~ s;</sup>;;g; 98 99 # Peep-hole optimizer. 100 $block =~ s/^\s+//g; 101 $block =~ s/\s+\n/\n/g; 102 $block =~ s/^\n//g; 103 $block =~ s/\.IP ""\n(\.sp\n)+/.IP ""\n/g; 104 $block =~ s/\.IP ""\n(\.[A-Z][A-Z])/\1/g; 105 $block =~ s/(.IP ""\n)+$//; 106 $block =~ s/^(\.(PP|sp)\n)+//; 107 #$wantpp = !($block =~ /^\.(SH|IP)/); 108 109 # Boldify man page references. 110 $block =~ s/([_a-zA-Z0-9-]+)(\([0-9]\))/\\fB\1\\fR\2/g; 111 112 # Encapsulate as C code comment. 113 $block =~ s/^([^.])/$delim\t\1/; 114 $block =~ s/^\./$delim ./; 115 $block =~ s/\n([^.])/\n$delim\t\1/g; 116 $block =~ s/\n\./\n$delim ./g; 117 118 print $block; 119 } else { 120 print "$delim .IP \"\\fB$name ($defval)\\fR\"\n"; 121 print $text; 122 } 123 $name = ""; 124 } 125 126 # Read the whole file even if we want to print only one parameter. 127 128 open(POSTCONF, $protofile) || die " cannot open $protofile: $!\n"; 129 130 while(<POSTCONF>) { 131 132 next if /^#/; 133 next unless ($name || /\S/); 134 135 if (/^%(PARAM|CLASS)/) { 136 137 # Save the accumulated text. 138 139 if ($name && $text) { 140 save_text(); 141 } 142 143 # Reset the parameter name and accumulated text. 144 145 $name = $text = ""; 146 $category = $1; 147 148 # Accumulate the parameter name and default value. 149 150 do { 151 $text .= $_; 152 } while(($_ = <POSTCONF>) && /\S/); 153 ($junk, $name, $defval) = split(/\s+/, $text, 3); 154 155 $defval =~ s/\s+/ /g; 156 $defval =~ s/\s+$//; 157 $defval =~ s/≤/<=/g; 158 $defval =~ s/≥/>=/g; 159 $defval =~ s/</</g; 160 $defval =~ s/>/>/g; 161 $defval =~ s/"/'/g; 162 $text = ""; 163 next; 164 } 165 166 # Accumulate the text in the class or parameter definition. 167 168 $text .= $_; 169 170 } 171 172 # Save the last definition. 173 174 if ($name && $text) { 175 save_text(); 176 } 177 178 # Process source file with embedded text. For now, hard-coded for C & sh. 179 180 while(<>) { 181 182 if (/^(\/\*|#)\+\+/) { 183 $incomment = 1; 184 $name = ""; 185 print; 186 next; 187 } 188 189 if (/^(\/\*|#)--/) { 190 emit_text($1) if ($name ne ""); 191 $incomment = 0; 192 print; 193 next; 194 } 195 196 if (!$incomment) { 197 print; 198 next; 199 } 200 201 if (/(\/\*|#) +CONFIGURATION +PARAM/) { 202 $incomment = 2; 203 } 204 205 # Delete text after nested itemized list. 206 if ($incomment == 2 && /^(\/\*|#) +\.IP ""/) { 207 $text .= $_; 208 while (<>) { 209 last if /^(\/\*|#) +([A-Z][A-Z][A-Z]+|\.[A-Z][A-Z])/; 210 $text .= $_; 211 } 212 } 213 214 # Delete nested itemized list. 215 if ($incomment == 2 && /^(\/\*|#) +\.RS/) { 216 $text .= $_; 217 $rsnest++; 218 while (<>) { 219 $text .= $_; 220 $rsnest++ if /^(\/\*|#) +\.RS/; 221 $rsnest-- if /(\/\*|#) +\.RE/; 222 last if $rsnest == 0; 223 } 224 next; 225 } 226 227 if ($incomment == 2 && /^(\/\*|#) +\.IP +"?\\fB([a-zA-Z0-9_]+)( +\((.*)\))?/) { 228 emit_text($1) if ($name ne ""); 229 $name = $2; 230 $defval = $4; 231 $text = ""; 232 next; 233 } 234 235 if ($incomment == 2 && /^(\/\*|#) +\.IP +"?\\fI([a-zA-Z0-9_]+)\\fB([a-zA-Z0-9_]+)( +\((.*)\))?/) { 236 emit_text($1) if ($name ne ""); 237 $name = "$2$3"; 238 $defval = $4; 239 $text = ""; 240 next; 241 } 242 243 if ($incomment == 2 && /^(\/\*|#) +([A-Z][A-Z][A-Z]+|\.[A-Z][A-Z])/) { 244 emit_text($1) if ($name ne ""); 245 $incomment = 0 if /^(\/\*|#) +(SEE +ALSO|README +FILES|LICENSE|AUTHOR)/; 246 print; 247 next; 248 } 249 250 if ($name ne "") { 251 $text .= $_; 252 next; 253 } 254 255 print; 256 next; 257 } 258 259 die "Unterminated comment\n" if $incomment; 260