2 # $Cambridge: exim/doc/doc-scripts/g2t,v 1.1 2004/10/07 15:04:35 ph10 Exp $
4 # A Perl script to turn the SGCAL source of the Exim documentation into
5 # Texinfo input, more or less...
7 # Supply the source file names as arguments.
8 # The output goes to the standard output.
11 ##################################################
12 # Ensure unique node name #
13 ##################################################
15 # Node names must be unique. Occasionally in the Exim spec there are duplicate
16 # section names, and it's become too much of a hassle to keep them distinct
17 # manually. So it is now automated.
19 ########### Never really got this working. Abandoned ###############
23 if (defined $node_names{$node})
25 $node_names{$node} += 1;
26 $node = "$node ($node_names{$node})";
28 print STDERR "+++ $node\n";
33 $node_names{$node} = 0;
40 ##################################################
41 # De-comma a node name #
42 ##################################################
44 # Commas, colons, and apostrophes are not permitted in Texinfo
45 # node names. I find this incredible, but it is clearly documented.
46 # The Exim manual has been re-organized not to have colons or
47 # apostrophes in any chapter or section titles, but I can't manage
48 # without commas. This function turns "," into " and", which is
49 # the best that can be done; we can use some clever Perlery to
50 # just take out commas before "and".
52 # Sigh. The Sendmail option -p<rval>:<sval> now means that there's a colon
53 # in the node name for that option. Turn the colon into <colon>. This is also
56 # Another thing that causes problems in node names in some versions of
57 # Texinfo is the use of @sc{xxx} for small caps. Just turn these all into
58 # real caps. This is also done for menus.
61 $_[0] =~ s/,(?!\sand)/ and/g;
63 $_[0] =~ s/\@sc\{([^}]*)\}/\U$1/g;
64 $_[0] =~ s/:/<colon>/g;
70 ##################################################
72 ##################################################
74 # @x is turned into x, except when x=@, or when asis is set,
75 # in which case single @ must turn into @@. A single substitute
76 # doesn't work in the non-asis case, because of the problems of
77 # handling things like @@@$, so we do it the hard way.
80 if ($asis) { $_[0] =~ s/@/@@/g; } else
83 $_[0] =~ s/@([^@])/$1/g;
90 ##################################################
92 ##################################################
94 # Called from handle_directive, to get the next source line
98 if ($processing_subsection)
99 { return $_ = shift @SUBBUFFER; }
106 ##################################################
107 # Handle text lines #
108 ##################################################
110 # This function is handed whole paragraphs, and we assume that
111 # SGCAL font changing markup is always complete within a paragraph.
112 # We have to replace escaped versions of significant characters with
113 # some magic before performing general transformations, and then
114 # put them back afterwards. The character & is not common in the text,
115 # and && is unknown, so we use that.
130 ($name) = $' =~ /^(\w+)/;
133 $value = $references{$name};
134 $value = "" if !defined($value);
136 if ($value =~ /\*\*\*\*/)
138 $value = ($` eq $current_chapter)? "\"$'\"" :
139 "\"$'\" in chapter \"$`\"";
140 $value = "" if $value eq "\"\"";
142 elsif ($value !~ /^[0-9]+\.[0-9]+$/) # quote unless version number
144 $value = "\"$value\"";
147 $_ = "${left}${value}${right}";
158 # Now remove all other @'s
162 # Convert SGCAL markup
164 s/#/ /g; # turn # into a space
165 s/\$~//g; # turn $~ into nothing
166 s/__/_/g; # turn __ into _
167 s/\$sm\{//g; # turn $sm{ into nothing
168 s/\$sc\{([^\}]*?)\}/$1/g; # turn $sc{xxx} into xxx
169 s/\$st\{([^\}]*?)\}/$1/g; # turn $st{xxx} into xxx
170 s/\$si\{([^\}]*?)\}/$1/g; # turn $si{xxx} into xxx
171 s/\$tt\{([^\}]*?)\}/$1/g; # turn $tt{xxx} into xxx
173 s/\$it\{([^\}]*?)\}/$1/g; # turn $it{xxx} into xxx
175 s/\$bf\{([^\}]*?)\}/$1/g; # turn $bf{xxx} into xxx
176 s/\$rm\{([^\}]*?)\}/$1/g; # turn $rm{xxx} into xxx
177 s/\$cb\{([^\}]*?)\}/$1/g; # turn $cb{xxx} into xxx
179 # This is a fudge for some specific usages of $<; can't just do a global
180 # is it occurs in things like $<variable name> as well.
182 s/\[\$<\]/[]/g; # turn [$<] into []
183 s/&&b\$<\./&&b./g; # turn \$<. into \. (\ == &&b by now)
184 s/(\d)\$<-/$1-/g; # turn 0$<- into 0-
186 # There is one case where the terminating } of an escape sequence is
187 # in another paragraph - this follows $sm{ - it can be fixed by
188 # removing any stray } in a paragraph that contains no { chars.
192 # Any remaining {} must be escaped to prevent Texinfo from complaining
196 # Now to conversions that put {} into the file.
197 # Change <<..>> from @var to just <...> as the caps that Texinfo
198 # uses look far too shouty.
200 s/\\\\([^\\]*?)\\\\/\@sc\{\L$1\}/g; # turn \\xxx\\ into @sc{xxx}
201 s/\\\(([^)]*?)\)\\/\@file\{$1\}/g; # turn \(xxx)\ into @file{xxx}
202 s/\\\"([^\"]*?)\"\\/\@file\{$1\}/g; # turn \"xxx"\ into @file{xxx}
204 s/\\\?([^?]*?)\?\\/$1/g; # turn \?URL?\ into URL
205 s/<<([^>]*?)>>/<$1>/g; # turn <<xxx>> into <xxx>
206 s/\\\$([^\$]*?)\$\\/\$$1/g; # turn \$xxx$\ into $xxx
207 s/\\\-([^-]*?)\-\\/\-$1/g; # turn \-xxx-\ into -xxx
208 s/\\\*\*([^*]*?)\*\*\\/$1/g; # turn \**xxx**\ into xxx
209 s/\[\(([\w\/]*)\)\]//g; # remove inline HTML
211 s/\\\*([^*]*?)\*\\/\@dfn\{$1\}/g; # turn \*xxx*\ into @dfn{xxx}
212 s/\\%([^*]*?)%\\/\@dfn\{$1\}/g; # turn \%xxx%\ into @dfn{xxx}
213 s/:::([^:]*?)::/\@dfn\{:$1:\}/g; # turn :::xxx:: into @dfn{:xxx:}
214 s/::([^:]*?)::/\@dfn\{$1:\}/g; # turn ::xxx:: into @dfn{xxx:}
215 s/\\([^\\]*?)\\/\@dfn\{$1\}/g; # turn \xxx\ into @dfn{xxx}
216 s/\$\*\$/\*/g; # turn $*$ into *
218 # Put back escaped SGCAL specials
230 # Remove any null flags ($$)
234 # If the paragraph starts with $c\b, change this into @center. Assume
235 # we don't ever get two of these in a row.
239 # If the paragraph starts with $e\b, stuff some tabs in there, as
240 # Texinfo can't do this on its own (as far as I can see). They must
241 # tabs; Texinfo treats them as different to spaces. Sigh.
243 s/^\$e\b/\t\t\t\t\t\t\t/;
245 # Handle $t. The Exim spec only ever has one tab per line. Er, not
246 # quite true, but a good enough assumption. $t is always followed
247 # by a non-word character.
249 # The .tabs directive has stashed the value in the $tab variable.
250 # Don't count Texinfo font chars.
252 while (/(^|.+?\n)(.+?)\$t(\W.*\n)/)
263 $plainleft =~ s/\@[a-z]+\{([^}]+?)\}/$1/g;
264 $plainleft =~ s/\@//g;
266 $_ = $before . $left . (" " x ($tab - length($plainleft))) . $right . $after;
268 # Fudge for the one case where there are two tabs
278 # Return the new line (paragraph)
285 ##################################################
286 # Handle directive lines #
287 ##################################################
289 # Use get_next_line() instead of <> because this is called to process
290 # stacked up subsection lines
292 sub handle_directive {
294 my($new_lastwasitem) = 0;
296 # Chapter directives just require . => @; however, dequoting the
297 # line thereafter will remove the first @, so just force it back
298 # afterwards. If the chapter is is one describing a driver, set
304 push(@ONESECTION, "@" . &dequote("$_\n"));
305 $driver_name = (/The\s+(\S+)\s+(director|router|transport|authenticator)/)? $1 :
306 (/Generic options common to both directors and routers/)?
307 "director or router" :
308 (/[Gg]eneric\s+options for (\S+)s/)? $1 : "";
309 $driver_name = &dequote($driver_name);
312 # Section directives just require . => @; however, dequoting the
313 # line thereafter will remove the first @, so just force it back
314 # afterwards. Remove any colons in section titles as they cause
315 # Texinfo trouble. Also remove any \\ (small caps) markup, which
316 # appears in a couple of cases.
323 push(@ONESECTION, "@" . &dequote("$_\n"));
325 # Horrible magic fudge to cope with the fact that exim_lock has
326 # -v and -q options, just like the main program.
328 $driver_name = "exim_lock" if /Mailbox maintenance/;
330 # Similar magic for exiqgrep, which also duplicates options
332 $driver_name = "exiqgrep" if /Selective queue listing/;
335 # .newline must put @* on the end of the previous line, if any, except
336 # inside a display, where it causes trouble.
340 if (@ONESECTION > 0 && ! $indisplay)
342 $_ = pop(@ONESECTION);
344 push(@ONESECTION, $_);
348 # .blank turns into @sp, adding 1 if no argument
352 s/\.blank\s+(\d+)/\@sp $1/;
354 push(@ONESECTION, $_);
357 # .rule turns into a line of hyphens
361 push(@ONESECTION, ("-" x ($in_itemize? 68 : 73)) . "\@*\n");
364 # There's one explicit .tabset setting for two tab stops
366 elsif (/\.tabset\s*/)
369 ($first,$second) = $rest =~ /(\d+)em\s+(\d+)em/;
370 $tab = ($first * 7)/6;
371 $tab2 = $tab + ($second * 7)/6;
374 # .tabs remembers the first (and only) tab setting
382 # .tempindent is used only to align some of the expansion stuff nicely;
383 # just ignore it. It is used in conjunction with .push/.pop.
385 elsif (/\.(tempindent|push|pop)\s*/)
389 # There are some instances of .if ~~sys.fancy in the source. Some of these
390 # are two-part things, in which case we just keep the non-fancy. For diagrams,
391 # however, they are in three parts:
394 # <aspic drawing stuff>
396 # <ascii art for txt and Texinfo>
398 # <HTML instructions for including a gif>
401 elsif (/\.if \~\~sys\.fancy/)
403 while (&get_next_line())
404 { last if /\.else\b/ || /\.elif\s+\~\~nothtml/ || /\.fi\b/; }
412 # There are occasional requirements to do things differently for
413 # Texinfo/HTML and the PS/txt versions, and there are also some
414 # HTML-specific things.
416 elsif (/\.if\s+~~sgcal/ || /\.if\s+~~html/)
418 while (&get_next_line()) { last if /\.else\b/ || /\.fi\b/; }
421 # We may also have Texinfo-specific bits
423 elsif (/^\.if\s+~~texinfo/)
428 # Ignore any other .if directives
432 # Skip else part if flag set
434 elsif (/\.else/ && $skip_else)
436 while (&get_next_line()) { last if /\.fi\b/; }
440 # Ignore other .fi and .else as any .if directives are handled specially
442 elsif (/\.fi/ || /\.else/) {}
446 elsif (/\.indent/) {}
448 # Plain .index goes to @cindex - the "concept" index. Also, there
449 # are some calls to vindex and findex in the SGCAL source - treated
450 # as synonymous with .index - which are split into the equivalent
453 elsif (/\.(.?)index/)
456 $letter = ($1 eq "")? "c" : $1;
457 tr/./@/; # .index -> @index
459 $rest =~ s/\\\(//g; # Remove markup
472 $rest =~ tr/\\//d; # Remove \
474 $rest =~ s/\@\$/\$/g; # @$ -> $
475 $rest =~ s/\@_/_/g; # @_ -> _
476 $rest =~ s/\@\+/+/g; # @+ -> +
477 $rest =~ s/\$\*\$/\*/g; # $*$ -> *
478 $rest =~ s/\$([^\$]+)\$/\$$1/g; # $x$ -> $x
480 $rest =~ s/^\s+//; # Remove leading spaces
481 $rest =~ s/\s+$//; # Remove trailing spaces
482 $rest =~ s/\|\|/:/; # || -> :
483 push(@ONESECTION, "\@${letter}index $rest\n");
485 # Duplicate entries for things that were listed as "x see y"
487 if (defined $indirections{$rest})
489 push(@ONESECTION, "\@${letter}index $indirections{$rest}\n");
493 # Various flavours of numberpars map to itemize and enumerate.
494 # Haven't found a way of having a blank space 'bullet' yet, so
495 # currently using minus.
497 elsif (/\.numberpars/)
503 if ($rest =~ /\$\./) { $flag = " \@bullet"; $type = "itemize" }
504 elsif ($rest =~ /\" \"/) { $flag = " \@minus"; $type = "itemize"; }
505 elsif ($rest =~ /roman/) { $flag = " a"; $type = "enumerate"; }
507 push(@ONESECTION, "\n\@$type$flag\n\n\@item\n");
508 push(@ENDLIST, $type);
514 push(@ONESECTION, "\n\@item\n");
519 $endname = pop(@ENDLIST);
520 push(@ONESECTION, "\@end $endname\n\n");
524 # The normal .display (typewriter font) => @example, while the rm
525 # form goes to @display (no change of font). For Texinfo we need a
526 # blank line after @display.
530 $type = /rm/? "display" : "example";
533 push(@ONESECTION, "\@$type\n\n");
534 push(@ENDLIST, $type);
541 $endname = pop(@ENDLIST);
542 push(@ONESECTION, "\@end $endname\n\n");
547 ($option, $type, $default) =
548 /\.conf\s+(\S+)\s+("(?:[^"]|"")+"|\S+)\s+("(?:[^"]|"")+"|.*)/;
550 $option = &dequote($option);
552 # If $type ends with $**$ (turned into a dagger for PS version),
553 # replace with ", expanded". Remove any surrounding quotes.
555 $type =~ s/^"([^"]+)"/$1/;
556 $type =~ s/\$\*\*\$/, expanded/;
558 # Default may be quoted, and it may also have quotes that are required,
561 $default =~ s/^"(.*)"$/$1/;
562 $default =~ s/""/"/g;
563 $default = &handle_text($default);
565 push(@ONESECTION, "\nType: $type\@*\nDefault: $default\n\n");
568 # Handle .startitems, .enditems, and .item
570 elsif (/\.startitem/ || /\.enditem/) {}
577 $arg = &dequote($arg);
578 $arg = &handle_text("\\**$arg**\\");
580 # If there are two .items in a row, we don't want to put in the
583 # push(@ONESECTION, "\n\@example\n");
584 push(@ONESECTION, "\n");
587 push(@ONESECTION, "_" x 75, "\n\n");
589 # push(@ONESECTION, "$arg\n\@end example\n\n");
590 push(@ONESECTION, "$arg\n\n");
591 $new_lastwasitem = 1;
598 $arg = &dequote("-$arg");
599 $arg = &handle_text($arg);
602 # Texinfo has no facility for emphasis bars.
607 # Just ignore any .(r)set directives pro tem (or maybe always!)
611 # Ignore .space, .linelength, and .justify
613 elsif (/\.space/ || /\.justify/ || /\.linelength/) {}
615 # Found an SGCAL directive that isn't dealt with. Oh dear.
616 # Turn the embarrassing characters into question marks and
617 # output it in an emphasized way.
622 push(@ONESECTION, "\n\>>>>>>> $_\n") if ! /^\.( |$)/;
625 $lastwasitem = $new_lastwasitem;
630 ##################################################
632 ##################################################
634 # $section_name is the name of the next section.
635 # $current_section is the name of the one we have buffered up.
636 # If it is unset, we are at the first section of a chapter.
637 # $previous_node is the section we last flushed if it was a node.
641 # If there is no text in the section, omit it entirely. However, it
642 # will have had a pointer set up at the start of the previous section.
643 # Remember what to replace this with when the chapter gets flushed.
646 foreach $s (@ONESECTION)
648 if ($s !~ /^(\@cindex|\@section|\s*$)/) { $skip = 0; last }
654 $rewrite{$current_section} = $section_name;
659 # There is data in the section: write it out to the chapter file
661 if ($current_section)
663 printf ONECHAPTER ("\@node %s, %s, %s, %s\n",
664 &decomma($current_section), &decomma($section_name),
665 &decomma($previous_node), &decomma($current_up));
666 $previous_node = $current_section;
667 while(scalar(@ONESECTION))
668 { print ONECHAPTER shift(@ONESECTION); }
672 while(scalar(@ONESECTION))
673 { push(@TOPSECTION, shift(@ONESECTION)); }
679 ##################################################
680 # Handle a "subsection" #
681 ##################################################
683 # A "subsection" is a set of options that must have their own
684 # local menu. Do two passes; the first just collects the names
685 # for the menu. This is called for .conf and .option items.
687 sub handle_subsection{
689 my($save_up) = $current_up;
691 $current_up = $current_section? $current_section : $current_chapter;
698 last if /^\.end$type/;
699 push(@SUBBUFFER, $_);
701 # .conf takes the first non-space string as the name, but as there are
702 # duplicate confs in various parts of the spec, use the driver name to
703 # de-duplicate; .option takes the entire rest of arg as the name, but
704 # removes any sequence of ... because this disturbs TexInfo. Also, it
707 if (/^\.$type\s+(\S+)(.*)/)
711 $name = &handle_text($1);
712 $name .= " ($driver_name)" if ($driver_name ne "");
716 chomp($name = &handle_text("-$1$2"));
717 $name =~ s/\s*\.\.\.//g;
719 $name .= " ($driver_name)" if ($driver_name ne "");
721 # There seems to be a major problem in texinfo with the string "--".
722 # In the text it gets turned into a single hyphen. This happens if it
723 # is used as a menu item, but *not* as a node name. Exim has a command
724 # line option "--". With no special action, this appears in the menu
725 # as "-", but then the info software complains there is no node called
726 # "-". If we triple it in the menu it gets displayed OK, but building
727 # software complains about non-existent cross references etc.
729 # I have gone for the horrid kludge of turning it into "-<hyhen>"
730 # in the menus and nodes.
732 # Exim 4 has added --help, which has the same problem.
734 $name = "-<hyphen>" if ($name eq "--");
735 $name = "-<hyphen>help" if ($name eq "--help");
737 push(@sublist, $name);
741 push (@ONESECTION, "\n\@sp 2\n\@menu\n");
742 for ($i = 0; $i < scalar(@sublist); $i++)
744 $mitem = $sublist[$i];
745 $mitem =~ s/\@sc\{([^}]*)\}/\U$1/g; # Get rid of small caps
746 $mitem =~ s/:/<colon>/g; # Get rid of colons
747 push (@ONESECTION, "* ${mitem}::\n");
749 push (@ONESECTION, "\@end menu\n\n");
751 $prevsub = $current_up;
752 $processing_subsection = 1;
753 while ($_ = shift(@SUBBUFFER))
755 if (/^\.$type\s+(\S+)/)
757 $name = shift @sublist;
758 $next = (scalar(@sublist))? $sublist[0] : "";
759 push @ONESECTION, sprintf("\@node %s, %s, %s, %s\n",
760 &decomma($name), &decomma($next), &decomma($prevsub),
761 &decomma($current_up));
763 if ($name eq "-<hyphen>") # Fudge for Texinfo
767 "\@unnumberedsubsec --- option\n");
769 "This option consists of two consecutive hyphens. It appears in\n",
770 "the menu as \"-<hyphen>\" because otherwise Texinfo gets\n",
771 "confused with its cross-referencing.\n");
773 elsif ($name eq "-<hyphen>help") # Fudge for Texinfo
777 "\@unnumberedsubsec ---help option\n");
779 "This option consists of \"help\" preceded by two consecutive\n" .
780 "hyphens. It appears in the menu as \"-<hyphen>help\" because\n" .
781 "otherwise Texinfo gets confused with its cross-referencing.\n");
787 "\@unnumberedsubsec $name option\n");
793 # Then handle as text or directive
795 if (substr($_, 0, 1) eq ".")
796 { handle_directive(); }
799 while($nextline = shift(@SUBBUFFER))
801 last if $nextline =~ /^(\.|\s*$)/;
804 push(@ONESECTION, handle_text($_));
806 last if !defined($_);
811 $processing_subsection = 0;
812 $section_pending = 1;
813 $current_up = $save_up;
819 ##################################################
820 # Handle a single chapter #
821 ##################################################
825 ($current_chapter) = /^\.chapter (.*)/;
826 $current_chapter = &dequote($current_chapter);
828 $current_chapter = $current_chapter;
830 my($tmp) = $current_chapter;
831 $tmp =~ s/\[\[\[\]\]\]/./;
832 print STDERR "processing chapter: $tmp\n";
834 # Remember the chapter name for the top-level menu
836 push(@chapter_list, $current_chapter);
838 # Open a temporary file to hold the chapter's text while collecting
839 # all its sections for a chapter-level menu.
841 $ONECHAPTER = "/tmp/ONECHAPTER.$$";
842 open(ONECHAPTER, ">$ONECHAPTER") || die "Can't open $ONECHAPTER for writing";
844 # Initialize for handling sections
850 undef $current_section;
853 $processing_subsection = 0;
855 $previous_node = $current_up = $current_chapter;
856 $section_pending = 0;
858 # Handle the .chapter directive as the first text of a section without
863 # Loop, handling each section. Assume they are sufficiently short that
864 # we can buffer the text in store, in an array called ONESECTION, instead
865 # of thrashing yet another file.
869 last if /^\.chapter /;
871 # Handle a new section, preserving $_ (handle_text flattens it).
872 # It seems we cannot get a fullstop into a Texinfo node name; use a magic
873 # character string that gets turned back into a dot by the post-processing.
879 $section_name =~ s/(\s|\n)+$//;
880 $section_name =~ s/://;
881 $section_name = &handle_text($section_name);
883 push(@section_list, $section_name);
884 $current_section = $section_name;
885 $next_node = $section_name if !$next_node;
886 $section_pending = 0;
890 # The .startconf macro introduces a set of .conf's which must have
891 # their own local set of menus. Suspend processing the section while
892 # we sort out the menu and copy their data. This is all done in a
893 # subroutine that is shared with options.
895 elsif (/^\.startconf/)
897 handle_subsection("conf");
901 elsif (/^\.startoption/)
903 handle_subsection("option");
907 # Deal with the actual data lines; if there's a section pending
908 # start a new section on hitting some text. We hope this happens
909 # only once per chapter...
911 if (substr($_, 0, 1) eq ".")
917 while($nextline = <>)
919 last if $nextline =~ /^(\.|\s*$)/;
922 if ($section_pending && !/^\s*$/)
924 $section_name = (defined $current_section)?
925 "$current_section (continued)" :
926 "$current_chapter (continued)" ;
928 push(@section_list, $section_name);
929 $current_section = $section_name;
930 $next_node = $section_name if !$next_node;
931 $section_pending = 0;
934 push(@ONESECTION, handle_text($_));
936 last if !defined($_);
941 # Flush any pending text, making its next field null.
942 # and fudging section_name for the final section of the previous.
947 # Set up section name as the start of the next chapter
949 $section_name = "Concept Index" if (!$doing_filter);
951 if (defined $_ && /^\.chapter (.*)/)
954 $section_name = &dequote($section_name);
956 $next_node = $section_name;
958 # Write out the chapter to the CHAPTERS file, sticking the chapter
959 # menu after the text that came before the first section heading. This
960 # will always at least contain the chapter title.
962 printf CHAPTERS ("\@node %s, %s, %s, Top\n",
963 &decomma($current_chapter), &decomma($next_node),
964 &decomma($previous_chapter));
966 # The pre-section stuff; if we hit an @end menu line, it is the menu of
967 # a "subsection" before the first section. In that case, we need to put
968 # the chapter's menu one the end of it, and then resume with the rest of
969 # the TOPSECTION data afterwards. We also need to thread together this
970 # "subsection"s nodes because they are all at the same level under the
974 while(scalar(@TOPSECTION))
976 $s = shift(@TOPSECTION);
977 if ($s =~ /^\@end menu/)
987 undef $next_actual_section;
990 if (scalar(@section_list))
992 print CHAPTERS "\n\@sp 2\n\@menu\n" if ! $in_menu;
993 $next_actual_section = $section_list[0];
994 for ($i = 0; $i < scalar(@section_list); $i++)
996 $section_name = $section_list[$i];
997 $section_name =~ s/\@sc\{([^}]*)\}/\U$1/g;
998 print CHAPTERS "* ${section_name}::\n";
1002 print CHAPTERS "\@end menu\n\n" if $in_menu;
1004 # Remainder of topsection; we must arrange that the final @node in
1005 # it (which will have a blank "next" field) actually points on to
1006 # the next section, if any. If this happens, then the next section
1007 # must point back to the final @node.
1009 while(scalar(@TOPSECTION))
1011 $s = shift(@TOPSECTION);
1012 if ($next_actual_section && $s =~
1013 /^\@node\s+([^,]+),\s*,\s*([^,]*),\s*(.*)/)
1015 my($t1, $t2, $t3) = ($1, $2, $3); # So can be decomma'd
1016 printf CHAPTERS ("\@node %s, %s, %s, %s\n", &decomma($t1),
1017 &decomma($next_actual_section), &decomma($t2), &decomma($t3));
1020 else { print CHAPTERS $s; }
1024 open(ONECHAPTER, "$ONECHAPTER") || die "Can't open $ONECHAPTER for reading";
1026 # While copying the chapter data, check for node references to empty
1027 # sections that got omitted and correct them, and correct the prev pointer
1028 # in the first node if necessary.
1030 while ($buff = <ONECHAPTER>)
1032 foreach $key (keys %rewrite)
1034 $buff =~ s/$key/$rewrite{$key}/;
1036 if ($point_back && $buff =~ /^\@node\s+([^,]+),\s*([^,]*),\s*([^,]*),\s*(.*)/)
1038 my($t1, $t2, $t4) = ($1, $2, $4); # so can be decomma'd
1039 printf CHAPTERS ("\@node %s, %s, %s, %s\n", &decomma($t1),
1040 &decomma($t2), &decomma($point_back), &decomma($t4));
1043 else { print CHAPTERS $buff; }
1046 $previous_chapter = $current_chapter;
1049 unlink($ONECHAPTER);
1054 ##################################################
1056 ##################################################
1058 # This is a two-pass algorithm. The first pass goes through and gets the
1059 # variable names for cross references. The second pass does the real work,
1060 # but we can't just read through doing the translation in one pass. We need
1061 # to know the list of chapters in order to build a top-level menu, and for
1062 # each chapter we need to know the sections in order to build a section
1063 # menu. Consequently, make use of temporary files to buffer things.
1065 # This script is used for the filter document and the overview as well;
1066 # flags tell it if it is doing one of them.
1073 $chapter_number = 0;
1074 $section_number = 0;
1076 if ($#ARGV >= 0 && $ARGV[0] eq "-filter")
1082 # First pass: Just fish out variable settings. Save the arguments so that
1083 # they can be reinstated for a second pass.
1085 print STDERR "Scanning for references\n";
1088 # Pick up any .set directives right at the very start
1092 last if ! /^\.set\s+(\S+)\s+(.+)$/;
1095 $value =~ s/^\"?(.*?)\"?\s*$/$1/;
1096 $references{$name} = $value;
1099 # Now skip everything before the first .chapter except for
1100 # .index lines that set up indirections. Save these so that
1101 # the relevant index entries can be duplicated.
1105 if (/^\.chapter\s+(.+)$/)
1108 $section_number = 0;
1109 $current_chapter = $1;
1110 $current_chapter = $current_chapter;
1111 $current_section = "";
1115 if (/^\.index\s+([^\$]+)\s+\$it\{see\s+([^}]+)\}\s*$/)
1117 $indirections{"$2"} = $1;
1125 if (/^\.chapter\s+(.+)$/)
1127 $current_chapter = $1;
1128 $current_chapter = &dequote($current_chapter);
1129 $current_section = "";
1131 elsif (/^\.section\s+(.+)$/)
1133 $current_section = $1;
1134 $current_section = &dequote($current_section);
1135 $current_section =~ s/://;
1137 elsif (/^\.r?set\s+(\S+)\s+(.+)$/ && $1 ne "runningfoot")
1142 # Only set the first time. This handles a few special cases in part2
1143 # which is included in the filter text as well.
1145 if (!exists($references{$name}))
1147 $value =~ s/^\"?(.*?)\"?\s*$/$1/;
1148 $value =~ s/~~chapter\./~~chapter****/;
1149 $value =~ s/~~chapter/$current_chapter/;
1150 $value =~ s/~~section/$current_section/;
1151 $references{$name} = $value;
1156 $final_chapter = defined($current_chapter)? $current_chapter : "";
1158 # Reinstate ARGV with the list of files and proceed to the main pass
1162 # $asis is set true when processing .display asis blocks, to stop
1163 # characters getting interpreted.
1167 # $indisplay is set true while processing .display blocks, to stop
1168 # .newlines being handled therein (adding @* wrecks alignment)
1172 # $tab is set to the value of the tab stop - only one stop is ever used
1173 # in the Exim source.
1177 # Current driver name, for disambiguating nodes
1181 # $section_pending is set if a new section is to be started on hitting
1184 $section_pending = 0;
1186 # Open a file to buffer up the entire set of chapters
1188 $CHAPTERS = "/tmp/CHAPTERS.$$";
1189 open(CHAPTERS, ">$CHAPTERS") || die "Can't open $CHAPTERS for writing";
1191 # Skip everything before the first .chapter
1193 while (<>) { last if /^\.chapter /; }
1195 # Loop, handling each chapter
1198 $previous_chapter = "Top";
1199 $previous_node = "Top";
1201 $chapter_number = 0;
1202 $section_number = 0;
1204 while (defined ($_) && /^\.chapter /)
1209 # Output the stuff at the start of the file
1211 print "\\input texinfo\n";
1213 print "\@set{wmYear} 2003\n";
1214 print "\@set{wmAuthor} Philip Hazel\n";
1215 print "\@set{wmAuthor_email} <ph10\@\@cus.cam.ac.uk>\n";
1216 print "\@set{COPYRIGHT1} Copyright \@copyright{} \@value{wmYear} University of Cambridge\n";
1218 print "\@c %**start of header\n";
1222 print "\@setfilename spec.info\n";
1223 print "\@settitle Exim Specification\n";
1227 print "\@setfilename filter.info\n";
1228 print "\@settitle Exim Filter Specification\n";
1231 print "\@paragraphindent 0\n";
1232 print "\@c %**end of header\n\n";
1235 print "\@titlepage\n";
1236 print "\@title The Exim Mail Transfer Agent\n";
1237 print "\@author \@value{wmAuthor}\n";
1240 print "\@vskip 0pt plus 1filll\n";
1242 print "Permission is granted to make and distribute verbatim copies of this manual provided the\n";
1243 print "copyright notice and this permission notice are preserved on all copies.\n";
1246 print "\@value{COPYRIGHT1}\@*\n";
1248 print "\@end titlepage\n\n";
1250 # Output the top-level node and its introductory blurb
1252 print "\@node Top, $chapter_list[0], (dir), (dir)\n";
1258 The Exim Mail Transfer Agent\@*
1259 ****************************
1261 The specification of the Exim Mail Transfer Agent is converted mechanically
1262 into Texinfo format from its original marked-up source. Some typographic
1263 representations are changed, chapters and sections cannot be numbered, and
1264 Texinfo lacks the ability to mark updated parts of the specification with
1267 Because the chapters and sections are unnumbered, cross references are set to
1268 their names. This makes the English a bit odd, with phrases like \`see chapter
1269 \"Retry configuration\"\' but it seemed very cumbersome to change this to \`see
1270 the chapter entitled \"Retry configuration\"\' each time.
1272 Each chapter, section, and configuration option has been placed in a separate
1273 Texinfo node. Texinfo doesn\'t allow commas, colons, or apostrophes in node
1274 names, which is a rather nasty restriction. I have arranged not to use colons
1275 or apostrophes in section titles, but cannot bring myself to omit them from
1276 titles such as \"The foo, bar and baz commands\". For the corresponding node
1277 names I have just used multiple occurrences of \"and\", though it looks very
1280 If a chapter or section continues after a list of configuration options that is
1281 not in a new section, a new node is started, using the chapter\'s or section\'s
1282 name plus \`(continued)\'. The \`Up\' operation from a section or configuration
1283 option returns to the start of the current chapter; the \`Up\' operation at a
1284 chapter start returns to the top of the document; the \`Up\' in a list of
1285 configuration options within a section returns to the top of that section.
1287 A number of drivers have options with the same name, so they have been
1288 disambiguated by adding the name of the driver to its option names in order to
1289 create node names. Thus, for example, the specification of the \`command\'
1290 options of the \`lmtp\' and \`pipe\' transports are in nodes called \`command
1291 (lmtp)\' and \`command (pipe)\', respectively.
1299 Filtering with the Exim Mail Transfer Agent\@*
1300 *******************************************
1302 The specifications of the Exim Mail Transfer Agent\'s filtering facility is
1303 converted mechanically into Texinfo format from its original marked-up source.
1304 Some typographic representations are changed, chapters and sections cannot be
1305 numbered, and Texinfo lacks the ability to mark updated parts of the
1306 specification with change bars.
1308 Because the chapters and sections are unnumbered, cross references are set to
1309 their names. This makes the English a bit odd, with phrases like \`see section
1310 \"Multiple personal mailboxes\"\' but it seemed very cumbersome to change this to
1311 \`see the section entitled \"Multiple personal mailboxes\"\' each time.
1316 # Output the top-level menu
1320 while (scalar(@chapter_list))
1322 $name = &decomma(shift(@chapter_list));
1323 print "* ${name}::\n";
1325 print "* Concept Index::\n" if (!$doing_filter);
1326 print "\@end menu\n\n";
1328 # Copy the chapters, then delete the temporary file
1331 open(CHAPTERS, "$CHAPTERS") || die "Can't open $CHAPTERS for reading";
1332 print $buff while($buff = <CHAPTERS>);
1336 # Output the finishing off stuff
1340 print "\@node Concept Index, , $final_chapter, Top\n";
1341 print "\@chapter Concept Index\n\@printindex cp\n";
1342 print "\@chapter Function Index\n\@printindex fn\n";
1344 print "\@contents\n";