1#!/usr/bin/perl -w 2# Fixes various things within tex files. 3 4use strict; 5 6my %args; 7 8 9sub get_includes { 10 # Get a list of include files from the top-level tex file. 11 my (@list,$file); 12 13 foreach my $filename (@_) { 14 $filename or next; 15 # Start with the top-level latex file so it gets checked too. 16 push (@list,$filename); 17 18 # Get a list of all the html files in the directory. 19 open IF,"<$filename" or die "Cannot open input file $filename"; 20 while (<IF>) { 21 chomp; 22 push @list,"$1.tex" if (/\\include\{(.*?)\}/); 23 } 24 25 close IF; 26 } 27 return @list; 28} 29 30sub convert_files { 31 my (@files) = @_; 32 my ($linecnt,$filedata,$output,$itemcnt,$indentcnt,$cnt); 33 34 $cnt = 0; 35 foreach my $file (@files) { 36 # Open the file and load the whole thing into $filedata. A bit wasteful but 37 # easier to deal with, and we don't have a problem with speed here. 38 $filedata = ""; 39 open IF,"<$file" or die "Cannot open input file $file"; 40 while (<IF>) { 41 $filedata .= $_; 42 } 43 close IF; 44 45 # We look for a line that starts with \item, and indent the two next lines (if not blank) 46 # by three spaces. 47 my $linecnt = 3; 48 $indentcnt = 0; 49 $output = ""; 50 # Process a line at a time. 51 foreach (split(/\n/,$filedata)) { 52 $_ .= "\n"; # Put back the return. 53 # If this line is less than the third line past the \item command, 54 # and the line isn't blank and doesn't start with whitespace 55 # add three spaces to the start of the line. Keep track of the number 56 # of lines changed. 57 if ($linecnt < 3 and !/^\\item/) { 58 if (/^[^\n\s]/) { 59 $output .= " " . $_; 60 $indentcnt++; 61 } else { 62 $output .= $_; 63 } 64 $linecnt++; 65 } else { 66 $linecnt = 3; 67 $output .= $_; 68 } 69 /^\\item / and $linecnt = 1; 70 } 71 72 73 # This is an item line. We need to process it too. If inside a \begin{description} environment, convert 74 # \item {\bf xxx} to \item [xxx] or \item [{xxx}] (if xxx contains '[' or ']'. 75 $itemcnt = 0; 76 $filedata = $output; 77 $output = ""; 78 my ($before,$descrip,$this,$between); 79 80 # Find any \begin{description} environment 81 while ($filedata =~ /(\\begin[\s\n]*\{[\s\n]*description[\s\n]*\})(.*?)(\\end[\s\n]*\{[\s\n]*description[\s\n]*\})/s) { 82 $output .= $` . $1; 83 $filedata = $3 . $'; 84 $descrip = $2; 85 86 # Search for \item {\bf xxx} 87 while ($descrip =~ /\\item[\s\n]*\{[\s\n]*\\bf[\s\n]*/s) { 88 $descrip = $'; 89 $output .= $`; 90 ($between,$descrip) = find_matching_brace($descrip); 91 if (!$descrip) { 92 $linecnt = $output =~ tr/\n/\n/; 93 print STDERR "Missing matching curly brace at line $linecnt in $file\n" if (!$descrip); 94 } 95 96 # Now do the replacement. 97 $between = '{' . $between . '}' if ($between =~ /\[|\]/); 98 $output .= "\\item \[$between\]"; 99 $itemcnt++; 100 } 101 $output .= $descrip; 102 } 103 $output .= $filedata; 104 105 # If any hyphens or \item commnads were converted, save the file. 106 if ($indentcnt or $itemcnt) { 107 open OF,">$file" or die "Cannot open output file $file"; 108 print OF $output; 109 close OF; 110 print "$indentcnt indent", ($indentcnt == 1) ? "" : "s"," added in $file\n"; 111 print "$itemcnt item", ($itemcnt == 1) ? "" : "s"," Changed in $file\n"; 112 } 113 114 $cnt += $indentcnt + $itemcnt; 115 } 116 return $cnt; 117} 118 119sub find_matching_brace { 120 # Finds text up to the next matching brace. Assumes that the input text doesn't contain 121 # the opening brace, but we want to find text up to a matching closing one. 122 # Returns the text between the matching braces, followed by the rest of the text following 123 # (which does not include the matching brace). 124 # 125 my $str = shift; 126 my ($this,$temp); 127 my $cnt = 1; 128 129 while ($cnt) { 130 # Ignore verbatim constructs involving curly braces, or if the character preceding 131 # the curly brace is a backslash. 132 if ($str =~ /\\verb\*?\{.*?\{|\\verb\*?\}.*?\}|\{|\}/s) { 133 $this .= $`; 134 $str = $'; 135 $temp = $&; 136 137 if ((substr($this,-1,1) eq '\\') or 138 $temp =~ /^\\verb/) { 139 $this .= $temp; 140 next; 141 } 142 143 $cnt += ($temp eq '{') ? 1 : -1; 144 # If this isn't the matching curly brace ($cnt > 0), include the brace. 145 $this .= $temp if ($cnt); 146 } else { 147 # No matching curly brace found. 148 return ($this . $str,''); 149 } 150 } 151 return ($this,$str); 152} 153 154sub check_arguments { 155 # Checks command-line arguments for ones starting with -- puts them into 156 # a hash called %args and removes them from @ARGV. 157 my $args = shift; 158 my $i; 159 160 for ($i = 0; $i < $#ARGV; $i++) { 161 $ARGV[$i] =~ /^\-+/ or next; 162 $ARGV[$i] =~ s/^\-+//; 163 $args{$ARGV[$i]} = ""; 164 delete ($ARGV[$i]); 165 166 } 167} 168 169################################################################## 170# MAIN #### 171################################################################## 172 173my @includes; 174my $cnt; 175 176check_arguments(\%args); 177die "No Files given to Check\n" if ($#ARGV < 0); 178 179# Examine the file pointed to by the first argument to get a list of 180# includes to test. 181@includes = get_includes(@ARGV); 182 183$cnt = convert_files(@includes); 184print "No lines changed\n" unless $cnt; 185