Merge commit 'upstream/23.2'
[rrq/maintain_lilo.git] / doc / t2a.pl
1 #!/usr/bin/perl
2 #
3 # Copyright 1994-1996 Werner Almesberger.
4 # All rights reserved.
5 #
6 # See file COPYING for details.
7 #
8 #-----------------------------------------------------------------------------
9 #
10 # Known bugs:
11 #
12 #   Usually doesn't check for prepended backslashes, e.g. things like
13 #   \\begin{verbatim} would be processed incorrectly.
14 #
15 #   Tokenization should be done once at the beginning, not on the fly
16 #   with cleanup and check procedures at the end of each step.
17 #
18 #-----------------------------------------------------------------------------
19 #
20 $w = 75;
21 #
22 # default macros
23 #
24 $m{"\\\\ldots"} = "...";
25 #
26 # read the file
27 #
28 print STDERR "[".length($t)."] Reading the file\n";
29 $/ = "\000";
30 $t = "\n".<>."\n";
31 #
32 # universal markers
33 #
34 $N = "\000";    # non-character
35 $X = "\007";    # generic marker
36 $Y = "\010";    # another generic marker
37 $Z = "\011";    # yet another generic marker
38 $B = "\001";    # begin
39 $E = "\002";    # end
40 $BS = "\013";   # second begin
41 $ES = "\014";   # second end
42 $CO = "\003";   # curly open
43 $CC = "\004";   # curly close
44 #
45 # commands to the output formatter
46 #
47 $SI = "\020";   # increase indentation by one
48 $SO = "\021";   # decrease indentation by one
49 $B1 = "\022";   # one blank line
50 $B2 = "\023";   # two blank lines
51
52 sub xlat
53 {
54     local ($l) = @_;
55
56     $l =~ tr/~/ /;
57     $l =~ s/\\([_~&%^\$\#\[\]|\-])/\1/g;# unescape special characters
58     $l =~ s/\\,//g;                     # remove small spaces
59     $l =~ s/\\backslash */$X/g;         # \backslash ->\
60     if ($l =~ /\\([A-Za-z]+|.)/) {
61         warn "unrecognized command $& ($l)";
62         $l = $`."\n!!! UNRECOGNIZED COMMAND: $&\n$'";
63     }
64     $l =~ s/$X/\\/g;
65     $l =~ tr/{}//d;                     # delete stray curly braces
66     $l =~ s/$CO/{/g;                    # put escaped braces back
67     $l =~ s/$CC/}/g;
68     return $l;
69 }
70
71
72 #
73 # load macros
74 #
75 print STDERR "[".length($t)."] Loading macros\n";
76 while ($t =~ /\n%%(def|cmd)([^\n]*)\n/) {
77     $t = $`."\n".$';
78     $a = $1;
79     $2 =~ /([^\\])=/ || die "= missing in $2";
80     if ($a eq "def") {
81         $m{$`.$1} = $';
82         $c{$`.$1} = "";
83     }
84     else {
85         $m{$`.$1} = "";
86         $c{$`.$1} = $';
87     }
88 }
89 #
90 # remove %%beginskip ... %%endskip pairs
91 #
92 print STDERR "[".length($t)."] Removing %%beginskip ... %%endskip pairs\n";
93 while ($t =~ /\n%%beginskip\s*\n/) { $t = $`.$B.$'; }
94 while ($t =~ /\n%%endskip\s*\n/) { $t = $`.$E.$'; }
95 while ($t =~ /$B[^$B$E]*$E/) { $t = $`."\n".$'; }
96 $t !~ /[$B$E]/ || die "%%beginskip/%%endskip mismatch";
97 #
98 #  process macros
99 #
100 print STDERR "[".length($t)."] Processing macros (may take a while)\n";
101 while (1) {
102     $none = 1;
103     for (keys %m) {
104         while ($t =~ /$_/) {
105             $none = 0;
106             if ($c{$_} eq "") {
107                 eval "\$t = \$`.\"$m{$_}\".\$';";
108             }
109             else {
110                 eval "\$t = \$`.$c{$_}.\$';";
111             }
112             die "syntax error: $@" if $@;
113         }
114     }
115     last if $none;
116     print STDERR "[".length($t)."] "."  next pass\n";
117 # perfectionist's approach:
118 #    $l = 0;
119 #    for (keys %m) {
120 #       if ($t =~ /$_/) {
121 #           if (length($&) > $l) {
122 #               $i = $_;
123 #               $l = length($&);
124 #           }
125 #       }
126 #    }
127 #    last if !$l;
128 #    $t =~ /$i/ || die "internal error";
129 #    eval "\$t = \$`.\"$m{$i}\".\$'";
130 #    die "syntax error: $@" if $@;
131 #    print STDERR "[".length($t)."] "."$i\n";
132 }
133 #
134 # handle verbatim sections (we're not trying to be perfect here)
135 #
136 print STDERR "[".length($t)."] Handling verbatim sections\n";
137 while ($t =~ /\\begin{verbatim}([ \t]*\n)?/) { $t = $`."\n\n".$B.$'; }
138 while ($t =~ /\\end{verbatim}([ \t]*\n)?/) { $t = $`.$E."\n\n".$'; }
139 while ($t =~ /\\verb([^a-zA-Z \t\n])/ && $t =~ /\\verb$1([^$1]*)$1/) {
140     $t = $`.$B.$1.$E.$';
141 }
142 while ($t =~ /$B([^$B$E]*)$E/) {
143     ($a,$b,$c) = ($`,$1,$');
144     die "no support for \\t yet, sorry" if $b =~ /\t/;
145     $b =~ s/\\/\\backslash /g;
146     $b =~ s/[~^_%#&{}\$\-]/\\$&/g;
147     $b =~ s/[`']/\\$&~/g;
148     $b =~ s/ /~/g;
149     $b =~ s/\n\n\n/$B2/g;
150     $b =~ s/\n\n/$B1/g;
151     $b =~ s/\n/\\\\/g;
152     $t = $a.$b.$c;
153 }
154 if ($t =~ /[$B$E]/) {
155     if ($t =~ /..........[$B$E]........../) { print STDERR "$&\n"; }
156     die "verbatim conflict";
157 }
158 #
159 # hide escaped curly braces
160 #
161 print STDERR "[".length($t)."] Hiding escaped curly braces\n";
162 $t =~ s/\\{/$CO/g;
163 $t =~ s/\\}/$CC/g;
164 #
165 # discard comments and italic corrections
166 #
167 print STDERR "[".length($t)."] Discarding comments and italic corrections\n";
168 while ($t =~ s/([^\\])%[^\n]*\n/$1/g) {};
169 $t =~ s|\\/||g;
170 #
171 # no math mode
172 #
173 print STDERR "[".length($t)."] No math mode\n";
174 while ($t =~ s/([^\\])\$/$1/g) {};
175 #
176 # remove tabs and massage blanks
177 #
178 print STDERR "[".length($t)."] Removing tabs and massaging blanks\n";
179 $t =~ s/\\ / /g;        # \cmd\ blah
180 $t =~ tr/ \t/ /s;
181 #
182 # various minor issues
183 #
184 print STDERR "[".length($t)."] Dealing with various minor issues\n";
185 $t =~ s/\\rightarrow\s*/->/g;
186 $t =~ s/\\quad\s*/~/g;
187 $t =~ s/\\qquad\s*/~~/g;
188 $t =~ s/\\vert/|/g;
189 $t =~ s/\\TeX/TeX/g;
190 $t =~ s/\\LaTeX/LaTeX/g;
191 $t =~ s/\\rm\s*//g;
192 $t =~ s/\\hbox{/{/g;
193 $t =~ s/\\protect//g;
194 $t =~ s/\\newpage\s*//g;
195 $t =~ tr/-/-/s;
196 $t =~ s/\n\n+/$B1/g;
197 while ($t =~ /\\cite{([^}]+)}/) {
198     $t = $`."[";
199     $after = $';
200     for (split(",",$1)) {
201         if (defined $cite{$_}) { $t .= "$cite{$_},"; }
202         else {
203             $cite{$_} = ++$citation;
204             $bibref[$citation] = $_;
205             $t .= "$citation,";
206             die "unmatched ref $_" unless $after =~ /\\bibitem{$_}/;
207             $after = $`."\\item[\[$citation\]] ".$';
208         }
209     }
210     $t =~ s/,$//;
211     $t .= "]$after";
212 }
213 $t =~
214   s/\\begin{thebibliography}{[^}]*}/\\section{References}\\begin{description}/;
215 $t =~ s/\\end{thebibliography/\\end{description}/;
216 #
217 # handle footnotes
218 #
219 print STDERR "[".length($t)."] Handling footnotes\n";
220 $t =~ s/\\footnote{/\\footnotemark\\footnotetext{/g;
221 $t =~ s/\\footnotemark/$X/g;
222 $t =~ s/\\footnotetext{/$Y/g;
223 while ($t =~ /$X([^$Y]*)$Y/) {
224     ($a,$b,$c) = ($`,$',$1);
225     $t =~ /^[^$Y]*$Y$B1/;
226     $d = $';
227     for ($s = "*"; $d =~ /$Z/; $d = $`.$Y.$') { $s .= "*"; }
228     $a = $a.$s.$c;
229     while ($b =~ /^([^}]*){([^{}]*)}/) { $b = $`.$1.$B.$2.$E.$'; }
230     $b =~ /^([^{}]*)}/ || die "{ } confusion";
231     ($b,$t) = ($1,$');
232     $b =~ s/$B/{/g;
233     $b =~ s/$E/}/g;
234     $d = "$B1$Z\\begin{description}\\item[$s] $b\\end{description}$B1";
235     if ($t =~ /$B1([^$Z][^$N]*)$/) { $t = $`.$d.$1; }
236     else { $t = $t.$d; }
237     $t = $a.$t;
238 }
239 $t =~ s/$Z//g;
240 if ($t =~ /[$X$Y$Z$B$E]/) {
241     if ($t =~ /..............[$X$Y$Z$B$E]/) { print STDERR "HEY $&\n"; }
242     die "footnote confusion";
243 }
244 #
245 # process simple tables ...
246 #
247 print STDERR "[".length($t)."] Processing simple tables\n";
248 while ($t =~ /\\begin{tabular}/) { $t = $`.$B.$'; }
249 while ($t =~ /\\end{tabular}/) { $t = $`.$E.$'; }
250 while ($t =~ /$B\{([rlc|]+)\}([^$B$E]*)$E/) {
251     ($a,$b,$c,$d) = ($`,$',$2,$1);
252     $c =~ s/\\\\/&/g;
253     $c =~ s/[\s\n]*\\hline[\s\n]*/$X&/g;
254     ($e = $d) =~ tr/|//cd;
255     @d = ();
256     while ($d =~ /^(\|*)[a-z](\|*)/) {
257         push(@d,$&);
258         $d = $';
259     }
260     @f = ();
261     while ($c =~ /([^\\])&/) {
262         push(@f,$`.$1);
263         $c = $';
264     }
265     @w = ();
266     $d =~ tr/|//d;
267     $i = 0;
268     for (@f) {
269         next if $_ eq $X;
270         $f = $i % @d;
271         $_ = &xlat($_);
272         $_ =~ s/^[\s\n]*//g;
273         $_ =~ s/[\s\n]*$//g;
274         if ($w[$f] < length($_)) { $w[$f] = length($_); }
275         $i++;
276     }
277     $l = @d+2*length($e)-1;
278     for (@w) { $l += $_; }
279     $a .= "$B1";
280     $i = 0;
281     for (@f) {
282         if ($_ eq $X) { $a .= ("-" x $l)."\\\\"; }
283         else {
284             $f = $i % @d;
285             if ($d[$f] =~ /^\|/) { $a .= "| "; }
286             $g = $w[$f]-length($_);
287             if ($d[$f] =~ /l/) { $a .= $_.("~" x $g); }
288             if ($d[$f] =~ /c/) {
289                 $a .= ("~" x int($g/2)).$_.("~" x ($g-int($g/2)));
290             }
291             if ($d[$f] =~ /r/) { $a .= ("~" x $g).$_; }
292             $a .= " ";
293             if ($d[$f] =~ /\|$/) { $a .= "| "; }
294             if ($f == $#d) { $a .= "\\\\"; }
295             $i++;
296         }
297     }
298     $t = $a.$b.$B1;
299 }
300 if ($t =~ /[$B$E$X]/) {
301     if ($t =~ /(.|\n)(.|\n)(.|\n)(.|\n)(.|\n)(.|\n)[$B$E$X](.|\n)(.|\n)(.|\n)(.|\n)(.|\n)(.|\n)/) { print STDERR "$&\n"; }
302     die "\\begin/end{tabular} mismatch";
303 }
304 #
305 # process lists
306 #
307 print STDERR "[".length($t)."] Formatting lists\n";
308 while ($t =~ /\\begin{itemize}\s*/) { $t = $`.$B.$'; }
309 while ($t =~ /\\end{itemize}\s*/) { $t = $`.$E.$'; }
310 while ($t =~ /$B[^$B$E]*$E/) {
311     ($a,$b,$c) = ($`,$&,$');
312     while ($b =~ /\\item\s*/) { $b = $`.$X.$'; }
313     while ($b =~ /$X([^$X]*)([$X$E])/) {
314         $b = $`."- ".$SI.$SI.$1.$SO.$SO."\\\\"."$2".$';
315     }
316     $b =~ /$B([^$B$E]*)$E/;
317     $t = $a.$SI.$SI.$B1.$1.$SO.$SO."$B1".$c;
318 }
319 $t !~ /[$B$E]/ || die "\\begin/\\end{itemize} mismatch";
320 while ($t =~ /\\begin{description}\s*/) { $t = $`.$B.$'; }
321 while ($t =~ /\\end{description}\s*/) { $t = $`.$E.$'; }
322 while ($t =~ /$B[^$B$E]*$E/) {
323     ($a,$b,$c) = ($`,$&,$');
324     while ($b =~ /\\item\[/) { $b = $`.$X."[".$'; }
325     while ($b =~ /$X\[/) {
326         ($d,$e) = ($`,$');
327         while ($e =~ s/\[([^\[\]]*)\]/$BS$1$ES/g) {};
328         $e =~ /^([^\[\]]*)]\s*([^$X]*)([$X$E])/ || die "\item problem (1)";
329         $b = $d.$1."~~".$SI.$SI.$2.$SO.$SO."\\\\".$3.$';
330         $b =~ s/$BS/[/g;
331         $b =~ s/$ES/]/g;
332     }
333     $b =~ /$B([^$B$E]*)$E/;
334     $t = $a.$SI.$SI.$B1.$1.$SO.$SO.$B1.$c;
335 }
336 $t !~ /[$X]/ || die "\item problem (2)";
337 $t !~ /[$B$E]/ || die "\\begin/\\end{description} mismatch";
338 #
339 # process figures
340 #
341 print STDERR "[".length($t)."] Removing figures\n";
342 while ($t =~ /\\begin{figure}\s*/) { $t = $`.$B.$'; }
343 while ($t =~ /\\end{figure}\s*/) { $t = $`.$E.$'; }
344 while ($t =~ /$B[^$B$E]*$E/) {
345     ($a,$b,$c) = ($`,$&,$');
346     $t = $a."[ Figure";
347     if ($b =~ /\\label{([^}]*)}/) {
348         $l{$1} = ++$figref;
349         $t .= " $figref";
350     }
351     if ($b =~ /\\caption{([^}]*)}/) {
352         $t .= ": $1";
353     }
354     $t .= " ]".$c;
355 }
356
357 #
358 # process sections and labels
359 #
360 print STDERR "[".length($t)."] Processing sections and labels\n";
361 $t =~ s/\\begin{abstract}/\\section{Abstract}/g;
362 $t =~ s/\\end{abstract}//g;
363 $LB = "\005";   # they don't necessarily have to be unique
364 $SC = "\006";
365 while ($t =~ /\\label{/) { $t = $`.$LB."{".$'; }
366 while ($t =~ /\\((sub)*)section\*?{/) { $t = $`.$SC.$1."{".$'; }
367 $l = "";
368 while (1) {
369     if ($t =~ /^([^$LB$SC]*)$LB\{([^{}]*)\}/) {
370         $l{$2} = '"'.$l.'"';
371         $t = $1.$';
372     }
373     if ($t =~ /$SC((sub)*){/) {
374         ($a,$b,$c) = ($`,$',$1);
375         while ($b =~ /^([^}]*){([^{}]*)}/) { $b = $`.$1.$B.$2.$E.$'; }
376         $b =~ /^([^{}]*)}\s*/ || die "{ } confusion";
377         ($b,$d) = ($1,$');
378         $b =~ s/$B/{/g;
379         $b =~ s/$E/}/g;
380         $l = $b;
381         $b = &xlat($b);
382         if (($u = ("=","-","- ","")[length($c)/3]) ne "") {
383             $u = "\\\\".substr($u x length($b),0,length($b));
384         }
385         $t = $a.$B2.$b.$u.$B1.$d;
386     }
387     else {
388         last;
389     }
390 }
391 #
392 # handle references
393 #
394 print STDERR "[".length($t)."] Handling references\n";
395 $t =~ s/[Pp]age \\pageref({[^{}]*})/\\ref$1/g;
396 $t =~ s/\\pageref{[^{}]*}/???/g;
397 while ($t =~ /\\ref{([^{}]*)}/) {
398     $t = $`.(defined($l{$1}) ? $l{$1} : "???").$';
399 }
400 #
401 # collapse whitespace
402 #
403 print STDERR "[".length($t)."] Collapsing whitespace\n";
404 $t =~ s/\\par\s*/\n\n/g;
405 $t =~ s/ *(\n+) */$1/g;
406 $t =~ tr/\n/ /;
407 $t =~ tr/ \t/ /s;       # again
408 #
409 # handle line breaks
410 #
411 print STDERR "[".length($t)."] Handling line breaks\n";
412 $t =~ tr/\n//d;
413 $t =~ s/\\\\/\n/g;
414 $t =~ s/\\par\s*/$B1/g;
415 #
416 # handle accents, umlauts, and double quotes
417 #
418 print STDERR "[".length($t)."] Handling accents, umlauts, double quotes ".
419   "and hyphens\n";
420 $t =~ s/\\[`']([AEOUaeou])/$1/g;
421 $t =~ s/\\([`'])~/$1/g;
422 $t =~ s/\\"([AOUaou])/$1e/g;
423 $t =~ s/``/"/g;
424 $t =~ s/''/"/g;
425 #
426 # apply ultimate set of fixes to newlines
427 #
428 print STDERR "[".length($t)."] Applying ultimate set of fixes to newlines\n";
429 while ($t =~ s/([\n$B1$B2]+)([$SI$SO])/$2$1/g) {};
430 $t =~ s/([\n$B1$B2]*)\s+([\n$B1$B2]+)/$1$2/g;
431 $t =~ s/\n+/\n/g;
432 $t =~ s/\n?($B1)[\n$B1]*/\n\n/g;
433 $t =~ s/\n*($B2)[\n$B2]*/\n\n\n/g;
434 #
435 # translate what's left
436 #
437 print STDERR "[".length($t)."] Final translation\n";
438 $t = &xlat($t);
439 $t =~ s/^\s*//;
440 $t =~ s/\s*$//;
441 $t .= "\n";
442 #
443 # okay, now format and print it
444 #
445 print STDERR "[".length($t)."] "."Formatting (may take a while)\n";
446 $l = "";
447 $m = 0;
448 while ($t =~ /([$SI$SO\n]| +)/) {
449     if ($` ne "" || substr($1,0,1) eq " ") {
450         if (length($l)+length($`) > $w && $l ne "") {
451             print $l."\n";
452             $l = "";
453         }
454         if ($l eq "") { $l = " " x $m; }
455         $l = $l.$`.(substr($1,0,1) eq " " ? $1 : "");
456     }
457     $t = $';
458     if ($1 eq $SI) { $m++; }
459     if ($1 eq $SO) { $m--; }
460     if ($1 eq "\n") {
461         print $l."\n";
462         $l = "";
463 #       $t = s/^ *(\S.*)/\1/;
464     }
465 }
466 print "$l\n" if $l ne "";
467 print STDERR "Done\n";