From 678610624cbcef303b9dd5ebe134135030449474 Mon Sep 17 00:00:00 2001 From: mstsirkin Date: Mon, 25 Nov 2013 12:25:46 +0000 Subject: txt2latex.pl: script to convert text to latex The result compiles and looks kind of OK. This reverse-engineers our txt format to generate the initial latex file. Tables are included in verbatim sections. Code is included in listing sections. Math is escaped with $$. TODO (possibly manually): - remove extra sections at the beginning of the document - format tales using tabular or similar environment - format lists using itemize/enumerate/description - prevent hyphenation in the middle of identifiers Signed-off-by: Michael S. Tsirkin git-svn-id: https://tools.oasis-open.org/version-control/svn/virtio@111 0c8fb4dd-22a2-4bb5-bc14-6c75a5f43652 --- txt2latex.pl | 182 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 182 insertions(+) create mode 100755 txt2latex.pl diff --git a/txt2latex.pl b/txt2latex.pl new file mode 100755 index 0000000..5e04ef1 --- /dev/null +++ b/txt2latex.pl @@ -0,0 +1,182 @@ +#!/usr/bin/perl + +use strict; + +my @depth2latex = ( + '\chapter', + '\section', + '\subsection', + '\subsubsection', + '\paragraph', + '\subparagraph' +); + +my $skip_depth = 1; + +sub find_footnotes { + my @text = @_; + my @notes = (); + my $found = 0; + my $l; + + for ($l = 0; $l <= $#text; $l++) { + if ($text[$l] =~ m/^FOOTNOTES:$/) { + $found = 1; + } + next unless $found; + if ($text[$l] =~ m/^\[[0-9]+\]\s/) { + push @notes, $l; + } + } + return @notes; +}; + +sub find_sections { + my @text = @_; + my @sections = (); + my $l; + + for ($l = 0; $l <= $#text - 1; $l++) { + next unless (($text[$l + 1] =~ m/^=======*$/) or + ($text[$l + 1] =~ m/^-------*$/)); + + next unless ($text[$l] =~ m/^(([0-9]+\.)+) /); + + push @sections, $l; + + } + return @sections; +}; + +my @text = (); +while (<>) { + push @text, $_; +} + +my @footnotes = find_footnotes(@text); +my @sections = find_sections(@text); + +#Format footnotes +my %footnote_by_number = (); +my $f; +for ($f = 0; $f <= $#footnotes; $f++) { + my $l = $footnotes[$f]; + die unless ($text[$l] =~ m/^\[([0-9]+)\]\s+(.*)/); + my $footnote = $1; + my $text = $2; + die "duplicate footnote number $footnote" if defined($footnote_by_number{$footnote}); + $footnote_by_number{$footnote} = "$text\n"; + my $next; + if ($f < $#footnotes) { + $next = $footnotes[$f + 1]; + } else { + $next = $#text + 1; + } + for ($l = $footnotes[$f] + 1; $l < $next; $l++) { + next if ($text[$l] =~ m/^$/); + $footnote_by_number{$footnote} .= $text[$l]; + } +} + +#Format sections +my %label_by_section = (); +my $s; + +my %latest_by_depth = (); + +for ($s = 0; $s <= $#sections; $s++) { + my $l = $sections[$s]; + die unless ($text[$l] =~ m/^(([0-9]+\.)+)\s+(.+)\s*/); + my $section = $1; + my $name = $3; + my @path = split(/\./, $section); + my $depth = $#path - $skip_depth; + if ($depth < 0) { + $depth = 0; + } + if ($depth > $#depth2latex) { + $depth = $#depth2latex; + } + $latest_by_depth{$#path} = $name; + my $type = $depth2latex[$depth]; + my $label = $name; + #Prepend hierarchical path to make name unique + for (my $i = 1; $i <= $#path - $skip_depth; $i++) { + last if (not defined $latest_by_depth{$#path - $i}); + $label = "$latest_by_depth{$#path - $i} / $label"; + } + $text[$l] = $type . "{$name}\\label{sec:$label}\n"; + $label_by_section{$section} = $label; +} + +my $ifndef = 0; +my $listing = 0; +my $table = 0; +my $buffer = ""; +for my $line (@text) { + last if ($line =~ m/^FOOTNOTES:$/); + next if (($line =~ m/^=======*$/) or + ($line =~ m/^-------*$/)); + + if ($line =~ m/^#if/) { + print "\\begin{lstlisting}\n"; + $ifndef++; + } + if ($ifndef) { + if ($line =~ m/^#endif/) { + $ifndef--; + } + $buffer .= $line; + if (not $ifndef) { + print $buffer; + print "\\end{lstlisting}\n"; + $buffer = ""; + } + next; + } + if (not $table and $line =~ m/^\+\-/) { + print "\\begin{verbatim}\n"; + $table = 1; + } + if ($table and not $line =~ m/^(\+\-|\|)/) { + print "\\end{verbatim}\n"; + $table = 0; + } + if (not $listing and $line =~ m/^\t/) { + print "\\begin{lstlisting}\n"; + $listing = 1; + } + if ($listing and $line =~ m/^$/) { + $buffer .= $line; + next; + } + if ($listing and not $line =~ m/^\t/) { + print "\\end{lstlisting}\n"; + $listing = 0; + } + + if (not $table and not $listing) { + if ($line =~ m/\S+\s*\^\s*\S+/) { + $line =~ s/(\S+\s*\^\s*)(\S+)/\$$1\{$2\}\$/g; + } else { + $line =~ s/\^/\\^/go; + } + $line =~ s/#/\\#/go; + $line =~ s/&/\\&/go; + if ($line =~ m/\[[0-9]+\]/) { #premature optimization + for my $n (keys(%footnote_by_number)) { + my $txt = $footnote_by_number{$n}; + $line =~ s/\[$n\]/\n\\footnote{$txt}/g; + } + } + } + if ($line =~ m/"(([0-9]+\.)+)[^"]*"/) { + my $section = $1; + $line =~ s/"(([0-9]+\.)+)[^"]*"/\\ref{sec:$label_by_section{$section}}~\\nameref{sec:$label_by_section{$section}}/g; + } + print $buffer; + $buffer = ""; + print $line; +} + + -- cgit v1.2.3