xref: /aoo4110/main/solenv/bin/modules/pre2par/work.pm (revision b1cdbd2c)
1*b1cdbd2cSJim Jagielski#**************************************************************
2*b1cdbd2cSJim Jagielski#
3*b1cdbd2cSJim Jagielski#  Licensed to the Apache Software Foundation (ASF) under one
4*b1cdbd2cSJim Jagielski#  or more contributor license agreements.  See the NOTICE file
5*b1cdbd2cSJim Jagielski#  distributed with this work for additional information
6*b1cdbd2cSJim Jagielski#  regarding copyright ownership.  The ASF licenses this file
7*b1cdbd2cSJim Jagielski#  to you under the Apache License, Version 2.0 (the
8*b1cdbd2cSJim Jagielski#  "License"); you may not use this file except in compliance
9*b1cdbd2cSJim Jagielski#  with the License.  You may obtain a copy of the License at
10*b1cdbd2cSJim Jagielski#
11*b1cdbd2cSJim Jagielski#    http://www.apache.org/licenses/LICENSE-2.0
12*b1cdbd2cSJim Jagielski#
13*b1cdbd2cSJim Jagielski#  Unless required by applicable law or agreed to in writing,
14*b1cdbd2cSJim Jagielski#  software distributed under the License is distributed on an
15*b1cdbd2cSJim Jagielski#  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16*b1cdbd2cSJim Jagielski#  KIND, either express or implied.  See the License for the
17*b1cdbd2cSJim Jagielski#  specific language governing permissions and limitations
18*b1cdbd2cSJim Jagielski#  under the License.
19*b1cdbd2cSJim Jagielski#
20*b1cdbd2cSJim Jagielski#**************************************************************
21*b1cdbd2cSJim Jagielski
22*b1cdbd2cSJim Jagielski
23*b1cdbd2cSJim Jagielski
24*b1cdbd2cSJim Jagielski
25*b1cdbd2cSJim Jagielskipackage pre2par::work;
26*b1cdbd2cSJim Jagielski
27*b1cdbd2cSJim Jagielskiuse pre2par::exiter;
28*b1cdbd2cSJim Jagielskiuse pre2par::remover;
29*b1cdbd2cSJim Jagielskiuse pre2par::pathanalyzer;
30*b1cdbd2cSJim Jagielski
31*b1cdbd2cSJim Jagielski############################################
32*b1cdbd2cSJim Jagielski# pre2par working module
33*b1cdbd2cSJim Jagielski############################################
34*b1cdbd2cSJim Jagielski
35*b1cdbd2cSJim Jagielski############################################
36*b1cdbd2cSJim Jagielski# procedure to split a line, that contains
37*b1cdbd2cSJim Jagielski# more than one par file lines
38*b1cdbd2cSJim Jagielski############################################
39*b1cdbd2cSJim Jagielski
40*b1cdbd2cSJim Jagielskisub split_line
41*b1cdbd2cSJim Jagielski{
42*b1cdbd2cSJim Jagielski	my ($line, $parfile) = @_;
43*b1cdbd2cSJim Jagielski
44*b1cdbd2cSJim Jagielski	while ( $line =~ /^((?:[^"]|\"(?:[^"\\]|\\.)*\")*?\;\s+)\s*(.*)$/ )
45*b1cdbd2cSJim Jagielski	{
46*b1cdbd2cSJim Jagielski		my $oneline = $1;
47*b1cdbd2cSJim Jagielski		$line = $2;
48*b1cdbd2cSJim Jagielski		pre2par::remover::remove_leading_and_ending_whitespaces(\$oneline);
49*b1cdbd2cSJim Jagielski		$oneline = $oneline . "\n";
50*b1cdbd2cSJim Jagielski		push(@{$parfile}, $oneline);
51*b1cdbd2cSJim Jagielski
52*b1cdbd2cSJim Jagielski		if ( $line =~ /^\s*End\s+(\w+.*$)/i )
53*b1cdbd2cSJim Jagielski		{
54*b1cdbd2cSJim Jagielski			$line = $1;
55*b1cdbd2cSJim Jagielski			push(@{$parfile}, "End\n\n");
56*b1cdbd2cSJim Jagielski		}
57*b1cdbd2cSJim Jagielski	}
58*b1cdbd2cSJim Jagielski
59*b1cdbd2cSJim Jagielski	# the last line
60*b1cdbd2cSJim Jagielski
61*b1cdbd2cSJim Jagielski	pre2par::remover::remove_leading_and_ending_whitespaces(\$line);
62*b1cdbd2cSJim Jagielski	$line = $line . "\n";
63*b1cdbd2cSJim Jagielski	push(@{$parfile}, $line);
64*b1cdbd2cSJim Jagielski
65*b1cdbd2cSJim Jagielski	if ( $line =~ /^\s*End\s*$/i ) { push(@{$parfile}, "\n"); }
66*b1cdbd2cSJim Jagielski}
67*b1cdbd2cSJim Jagielski
68*b1cdbd2cSJim Jagielski###################################################################
69*b1cdbd2cSJim Jagielski# Preprocessing the pre file to split all lines with semicolon
70*b1cdbd2cSJim Jagielski###################################################################
71*b1cdbd2cSJim Jagielski
72*b1cdbd2cSJim Jagielskisub preprocess_macros
73*b1cdbd2cSJim Jagielski{
74*b1cdbd2cSJim Jagielski	my ($prefile) = @_;
75*b1cdbd2cSJim Jagielski
76*b1cdbd2cSJim Jagielski	my @newprefile = ();
77*b1cdbd2cSJim Jagielski
78*b1cdbd2cSJim Jagielski	for ( my $i = 0; $i <= $#{$prefile}; $i++ )
79*b1cdbd2cSJim Jagielski	{
80*b1cdbd2cSJim Jagielski		my $oneline = ${$prefile}[$i];
81*b1cdbd2cSJim Jagielski		if ( $oneline =~ /\;\s*\w+/ )
82*b1cdbd2cSJim Jagielski		{
83*b1cdbd2cSJim Jagielski			split_line($oneline, \@newprefile);
84*b1cdbd2cSJim Jagielski		}
85*b1cdbd2cSJim Jagielski		else
86*b1cdbd2cSJim Jagielski		{
87*b1cdbd2cSJim Jagielski			push(@newprefile, $oneline);
88*b1cdbd2cSJim Jagielski		}
89*b1cdbd2cSJim Jagielski	}
90*b1cdbd2cSJim Jagielski
91*b1cdbd2cSJim Jagielski	return \@newprefile;
92*b1cdbd2cSJim Jagielski}
93*b1cdbd2cSJim Jagielski
94*b1cdbd2cSJim Jagielski############################################
95*b1cdbd2cSJim Jagielski# main working procedure
96*b1cdbd2cSJim Jagielski############################################
97*b1cdbd2cSJim Jagielski
98*b1cdbd2cSJim Jagielskisub convert
99*b1cdbd2cSJim Jagielski{
100*b1cdbd2cSJim Jagielski	my ($prefile) = @_;
101*b1cdbd2cSJim Jagielski
102*b1cdbd2cSJim Jagielski	my @parfile = ();
103*b1cdbd2cSJim Jagielski
104*b1cdbd2cSJim Jagielski	my $iscodesection = 0;
105*b1cdbd2cSJim Jagielski	my $ismultiliner = 0;
106*b1cdbd2cSJim Jagielski	my $globalline = "";
107*b1cdbd2cSJim Jagielski
108*b1cdbd2cSJim Jagielski	# Preprocessing the pre file to split all lines with semicolon
109*b1cdbd2cSJim Jagielski	$prefile = preprocess_macros($prefile);
110*b1cdbd2cSJim Jagielski
111*b1cdbd2cSJim Jagielski	for ( my $i = 0; $i <= $#{$prefile}; $i++ )
112*b1cdbd2cSJim Jagielski	{
113*b1cdbd2cSJim Jagielski		my $oneline = ${$prefile}[$i];
114*b1cdbd2cSJim Jagielski
115*b1cdbd2cSJim Jagielski		if ($iscodesection)
116*b1cdbd2cSJim Jagielski		{
117*b1cdbd2cSJim Jagielski			if ( $oneline =~ /^\s*\}\;\s*$/ )
118*b1cdbd2cSJim Jagielski			{
119*b1cdbd2cSJim Jagielski				$iscodesection = 0;
120*b1cdbd2cSJim Jagielski			}
121*b1cdbd2cSJim Jagielski			else	# nothing to do for code inside a code section
122*b1cdbd2cSJim Jagielski			{
123*b1cdbd2cSJim Jagielski				push(@parfile, $oneline);
124*b1cdbd2cSJim Jagielski				next;
125*b1cdbd2cSJim Jagielski			 }
126*b1cdbd2cSJim Jagielski		}
127*b1cdbd2cSJim Jagielski
128*b1cdbd2cSJim Jagielski		if ( $oneline =~ /^\s*$/ ) { next; }
129*b1cdbd2cSJim Jagielski
130*b1cdbd2cSJim Jagielski		if ( $oneline =~ /^\s*Code\s+\=\s+\{/ )
131*b1cdbd2cSJim Jagielski		{
132*b1cdbd2cSJim Jagielski			$iscodesection = 1;
133*b1cdbd2cSJim Jagielski		}
134*b1cdbd2cSJim Jagielski
135*b1cdbd2cSJim Jagielski		pre2par::remover::remove_leading_and_ending_whitespaces(\$oneline);
136*b1cdbd2cSJim Jagielski
137*b1cdbd2cSJim Jagielski		my $insertemptyline = 0;
138*b1cdbd2cSJim Jagielski
139*b1cdbd2cSJim Jagielski		if ( $oneline =~ /^\s*End\s*$/i ) { $insertemptyline = 1; }
140*b1cdbd2cSJim Jagielski
141*b1cdbd2cSJim Jagielski		# Sometimes the complete file is in one line, then the gid line has to be separated
142*b1cdbd2cSJim Jagielski
143*b1cdbd2cSJim Jagielski		if ( $oneline =~ /^\s*(\w+\s+\w+)\s+(\w+\s+\=.*$)/ )	# three words before the equal sign
144*b1cdbd2cSJim Jagielski		{
145*b1cdbd2cSJim Jagielski			my $gidline = $1;
146*b1cdbd2cSJim Jagielski			$oneline = $2;
147*b1cdbd2cSJim Jagielski			$gidline = $gidline . "\n";
148*b1cdbd2cSJim Jagielski
149*b1cdbd2cSJim Jagielski			push(@parfile, $gidline);
150*b1cdbd2cSJim Jagielski		}
151*b1cdbd2cSJim Jagielski
152*b1cdbd2cSJim Jagielski		if ( $oneline =~ /\;\s*\w+/ )
153*b1cdbd2cSJim Jagielski		{
154*b1cdbd2cSJim Jagielski			split_line($oneline, \@parfile);
155*b1cdbd2cSJim Jagielski			next;
156*b1cdbd2cSJim Jagielski		}
157*b1cdbd2cSJim Jagielski
158*b1cdbd2cSJim Jagielski		# searching for lines with brackets, like Customs = { ..., which can be parted above several lines
159*b1cdbd2cSJim Jagielski
160*b1cdbd2cSJim Jagielski		if ( $oneline =~ /^\s*\w+\s+\=\s*\(.*\)\s*\;\s*$/ )		# only one line
161*b1cdbd2cSJim Jagielski		{
162*b1cdbd2cSJim Jagielski			if (( ! ( $oneline =~ /^\s*Assignment\d+\s*\=/ )) && ( ! ( $oneline =~ /^\s*PatchAssignment\d+\s*\=/ )))
163*b1cdbd2cSJim Jagielski			{
164*b1cdbd2cSJim Jagielski				$oneline =~ s/\s//g;		# removing whitespaces in lists
165*b1cdbd2cSJim Jagielski				$oneline =~ s/\=/\ \=\ /;	# adding whitespace around equals sign
166*b1cdbd2cSJim Jagielski			}
167*b1cdbd2cSJim Jagielski		}
168*b1cdbd2cSJim Jagielski
169*b1cdbd2cSJim Jagielski		if ( $oneline =~ /^\s*\w+\s+\=\s*$/ )
170*b1cdbd2cSJim Jagielski		{
171*b1cdbd2cSJim Jagielski			$oneline =~ s/\s*$//;
172*b1cdbd2cSJim Jagielski			pre2par::exiter::exit_program("Error: Illegal syntax, no line break after eqals sign allowed. Line: \"$oneline\"", "convert");
173*b1cdbd2cSJim Jagielski		}
174*b1cdbd2cSJim Jagielski
175*b1cdbd2cSJim Jagielski		if (( $oneline =~ /^\s*\w+\s+\=\s*\(/ ) && (!( $oneline =~ /\)\s*\;\s*$/ )))	 # several lines
176*b1cdbd2cSJim Jagielski		{
177*b1cdbd2cSJim Jagielski			$ismultiliner = 1;
178*b1cdbd2cSJim Jagielski			$oneline =~ s/\s//g;
179*b1cdbd2cSJim Jagielski			$globalline .= $oneline;
180*b1cdbd2cSJim Jagielski			next;						# not including yet
181*b1cdbd2cSJim Jagielski		}
182*b1cdbd2cSJim Jagielski
183*b1cdbd2cSJim Jagielski		if ( $ismultiliner )
184*b1cdbd2cSJim Jagielski		{
185*b1cdbd2cSJim Jagielski			$oneline =~ s/\s//g;
186*b1cdbd2cSJim Jagielski			$globalline .= $oneline;
187*b1cdbd2cSJim Jagielski
188*b1cdbd2cSJim Jagielski			if ( $oneline =~ /\)\s*\;\s*$/ ) {	$ismultiliner = 0; }
189*b1cdbd2cSJim Jagielski
190*b1cdbd2cSJim Jagielski			if (! ( $ismultiliner ))
191*b1cdbd2cSJim Jagielski			{
192*b1cdbd2cSJim Jagielski				$globalline =~ s/\=/\ \=\ /;	# adding whitespace around equals sign
193*b1cdbd2cSJim Jagielski				$globalline .= "\n";
194*b1cdbd2cSJim Jagielski				push(@parfile, $globalline);
195*b1cdbd2cSJim Jagielski				$globalline = "";
196*b1cdbd2cSJim Jagielski			}
197*b1cdbd2cSJim Jagielski
198*b1cdbd2cSJim Jagielski			next;
199*b1cdbd2cSJim Jagielski		}
200*b1cdbd2cSJim Jagielski
201*b1cdbd2cSJim Jagielski		$oneline = $oneline . "\n";
202*b1cdbd2cSJim Jagielski
203*b1cdbd2cSJim Jagielski		$oneline =~ s/\s*\=\s*/ \= /;	# nice, to have only one whitespace around equal signs
204*b1cdbd2cSJim Jagielski
205*b1cdbd2cSJim Jagielski        # Concatenate adjacent string literals:
206*b1cdbd2cSJim Jagielski        while ($oneline =~
207*b1cdbd2cSJim Jagielski               s/^((?:[^"]*
208*b1cdbd2cSJim Jagielski                      \"(?:[^\\"]|\\.)*\"
209*b1cdbd2cSJim Jagielski                      (?:[^"]*[^[:blank:]"][^"]*\"(?:[^\\"]|\\.)*\")*)*
210*b1cdbd2cSJim Jagielski                   [^"]*
211*b1cdbd2cSJim Jagielski                   \"(?:[^\\"]|\\.)*)
212*b1cdbd2cSJim Jagielski                 \"[[:blank:]]*\"
213*b1cdbd2cSJim Jagielski                 ((?:[^\\"]|\\.)*\")
214*b1cdbd2cSJim Jagielski                /\1\2/x)
215*b1cdbd2cSJim Jagielski        {}
216*b1cdbd2cSJim Jagielski
217*b1cdbd2cSJim Jagielski		push(@parfile, $oneline);
218*b1cdbd2cSJim Jagielski
219*b1cdbd2cSJim Jagielski		if ($insertemptyline) { push(@parfile, "\n"); }
220*b1cdbd2cSJim Jagielski
221*b1cdbd2cSJim Jagielski	}
222*b1cdbd2cSJim Jagielski
223*b1cdbd2cSJim Jagielski	return \@parfile;
224*b1cdbd2cSJim Jagielski}
225*b1cdbd2cSJim Jagielski
226*b1cdbd2cSJim Jagielski############################################
227*b1cdbd2cSJim Jagielski# formatting the par file
228*b1cdbd2cSJim Jagielski############################################
229*b1cdbd2cSJim Jagielski
230*b1cdbd2cSJim Jagielskisub formatter
231*b1cdbd2cSJim Jagielski{
232*b1cdbd2cSJim Jagielski	my ($parfile) = @_;
233*b1cdbd2cSJim Jagielski
234*b1cdbd2cSJim Jagielski	my $iscodesection = 0;
235*b1cdbd2cSJim Jagielski
236*b1cdbd2cSJim Jagielski	my $tabcounter = 0;
237*b1cdbd2cSJim Jagielski	my $isinsideitem = 0;
238*b1cdbd2cSJim Jagielski	my $currentitem;
239*b1cdbd2cSJim Jagielski
240*b1cdbd2cSJim Jagielski	for ( my $i = 0; $i <= $#{$parfile}; $i++ )
241*b1cdbd2cSJim Jagielski	{
242*b1cdbd2cSJim Jagielski		my $oneline = ${$parfile}[$i];
243*b1cdbd2cSJim Jagielski		my $isitemline = 0;
244*b1cdbd2cSJim Jagielski
245*b1cdbd2cSJim Jagielski		if (! $isinsideitem )
246*b1cdbd2cSJim Jagielski		{
247*b1cdbd2cSJim Jagielski			for ( my $j = 0; $j <= $#pre2par::globals::allitems; $j++ )
248*b1cdbd2cSJim Jagielski			{
249*b1cdbd2cSJim Jagielski				if ( $oneline =~ /^\s*$pre2par::globals::allitems[$j]\s+\w+\s*$/ )
250*b1cdbd2cSJim Jagielski				{
251*b1cdbd2cSJim Jagielski					$currentitem = $pre2par::globals::allitems[$j];
252*b1cdbd2cSJim Jagielski					$isitemline = 1;
253*b1cdbd2cSJim Jagielski					$isinsideitem = 1;
254*b1cdbd2cSJim Jagielski					$tabcounter = 0;
255*b1cdbd2cSJim Jagielski					last;
256*b1cdbd2cSJim Jagielski				}
257*b1cdbd2cSJim Jagielski			}
258*b1cdbd2cSJim Jagielski		}
259*b1cdbd2cSJim Jagielski
260*b1cdbd2cSJim Jagielski		if ( $isitemline )
261*b1cdbd2cSJim Jagielski		{
262*b1cdbd2cSJim Jagielski			next;	# nothing to do
263*b1cdbd2cSJim Jagielski		}
264*b1cdbd2cSJim Jagielski
265*b1cdbd2cSJim Jagielski		if ( $oneline =~ /^\s*end\s*$/i )
266*b1cdbd2cSJim Jagielski		{
267*b1cdbd2cSJim Jagielski			$isinsideitem = 0;
268*b1cdbd2cSJim Jagielski			$tabcounter--;
269*b1cdbd2cSJim Jagielski		}
270*b1cdbd2cSJim Jagielski
271*b1cdbd2cSJim Jagielski		if ( $isinsideitem )
272*b1cdbd2cSJim Jagielski		{
273*b1cdbd2cSJim Jagielski			$oneline = "\t" . $oneline;
274*b1cdbd2cSJim Jagielski			${$parfile}[$i] = $oneline;
275*b1cdbd2cSJim Jagielski		}
276*b1cdbd2cSJim Jagielski	}
277*b1cdbd2cSJim Jagielski}
278*b1cdbd2cSJim Jagielski
279*b1cdbd2cSJim Jagielski###################################################
280*b1cdbd2cSJim Jagielski# Returning the language file name
281*b1cdbd2cSJim Jagielski###################################################
282*b1cdbd2cSJim Jagielski
283*b1cdbd2cSJim Jagielskisub getlangfilename
284*b1cdbd2cSJim Jagielski{
285*b1cdbd2cSJim Jagielski	return $pre2par::globals::langfilename;
286*b1cdbd2cSJim Jagielski}
287*b1cdbd2cSJim Jagielski
288*b1cdbd2cSJim Jagielski###################################################
289*b1cdbd2cSJim Jagielski# Creating the ulf file name from the
290*b1cdbd2cSJim Jagielski# corresponding pre file name
291*b1cdbd2cSJim Jagielski###################################################
292*b1cdbd2cSJim Jagielski
293*b1cdbd2cSJim Jagielskisub getulffilename
294*b1cdbd2cSJim Jagielski{
295*b1cdbd2cSJim Jagielski	my ($prefilename) = @_;
296*b1cdbd2cSJim Jagielski
297*b1cdbd2cSJim Jagielski	my $ulffilename = $prefilename;
298*b1cdbd2cSJim Jagielski	$ulffilename =~ s/\.pre\s*$/\.ulf/;
299*b1cdbd2cSJim Jagielski	pre2par::pathanalyzer::make_absolute_filename_to_relative_filename(\$ulffilename);
300*b1cdbd2cSJim Jagielski
301*b1cdbd2cSJim Jagielski	return $ulffilename;
302*b1cdbd2cSJim Jagielski}
303*b1cdbd2cSJim Jagielski
304*b1cdbd2cSJim Jagielski############################################
305*b1cdbd2cSJim Jagielski# Checking if a file exists
306*b1cdbd2cSJim Jagielski############################################
307*b1cdbd2cSJim Jagielski
308*b1cdbd2cSJim Jagielskisub fileexists
309*b1cdbd2cSJim Jagielski{
310*b1cdbd2cSJim Jagielski	my ($langfilename) = @_;
311*b1cdbd2cSJim Jagielski
312*b1cdbd2cSJim Jagielski	my $fileexists = 0;
313*b1cdbd2cSJim Jagielski
314*b1cdbd2cSJim Jagielski	if( -f $langfilename ) { $fileexists = 1; }
315*b1cdbd2cSJim Jagielski
316*b1cdbd2cSJim Jagielski	return $fileexists;
317*b1cdbd2cSJim Jagielski}
318*b1cdbd2cSJim Jagielski
319*b1cdbd2cSJim Jagielski############################################
320*b1cdbd2cSJim Jagielski# Checking the existence of ulf and
321*b1cdbd2cSJim Jagielski# jlf/mlf files
322*b1cdbd2cSJim Jagielski############################################
323*b1cdbd2cSJim Jagielski
324*b1cdbd2cSJim Jagielskisub check_existence_of_langfiles
325*b1cdbd2cSJim Jagielski{
326*b1cdbd2cSJim Jagielski	my ($langfilename, $ulffilename) = @_;
327*b1cdbd2cSJim Jagielski
328*b1cdbd2cSJim Jagielski	my $do_localize = 0;
329*b1cdbd2cSJim Jagielski
330*b1cdbd2cSJim Jagielski	if (( fileexists($ulffilename) ) && ( ! fileexists($langfilename) )) { pre2par::exiter::exit_program("Error: Did not find language file $langfilename", "check_existence_of_langfiles"); }
331*b1cdbd2cSJim Jagielski	if (( fileexists($ulffilename) ) && ( fileexists($langfilename) )) { $do_localize = 1; }
332*b1cdbd2cSJim Jagielski
333*b1cdbd2cSJim Jagielski	return $do_localize;
334*b1cdbd2cSJim Jagielski}
335*b1cdbd2cSJim Jagielski
336*b1cdbd2cSJim Jagielski############################################
337*b1cdbd2cSJim Jagielski# Checking that the pre file has content
338*b1cdbd2cSJim Jagielski############################################
339*b1cdbd2cSJim Jagielski
340*b1cdbd2cSJim Jagielskisub check_content
341*b1cdbd2cSJim Jagielski{
342*b1cdbd2cSJim Jagielski	my ($filecontent, $filename) = @_;
343*b1cdbd2cSJim Jagielski
344*b1cdbd2cSJim Jagielski	if ( $#{$filecontent} < 0 ) { pre2par::exiter::exit_program("Error: $filename has no content!", "check_content"); }
345*b1cdbd2cSJim Jagielski}
346*b1cdbd2cSJim Jagielski
347*b1cdbd2cSJim Jagielski############################################
348*b1cdbd2cSJim Jagielski# Checking content of par files.
349*b1cdbd2cSJim Jagielski# Currently only size.
350*b1cdbd2cSJim Jagielski############################################
351*b1cdbd2cSJim Jagielski
352*b1cdbd2cSJim Jagielskisub diff_content
353*b1cdbd2cSJim Jagielski{
354*b1cdbd2cSJim Jagielski	my ($content1, $content2, $filename) = @_;
355*b1cdbd2cSJim Jagielski
356*b1cdbd2cSJim Jagielski	if ( $#{$content1} != $#{$content2} ) { pre2par::exiter::exit_program("Error: $filename was not saved correctly!", "diff_content"); }
357*b1cdbd2cSJim Jagielski}
358*b1cdbd2cSJim Jagielski
359*b1cdbd2cSJim Jagielski1;
360