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