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