Add CMake-Po4a-based infrastructure to allow po-based translation of Colobot help- and scene-description (level) files

dev-ui
Didier 'OdyX' Raboud 2013-10-25 15:18:18 +02:00
parent d5a1f10057
commit 37f5fd7689
8 changed files with 537 additions and 0 deletions

114
levels-i18n/CMakeLists.txt Normal file
View File

@ -0,0 +1,114 @@
cmake_minimum_required(VERSION 2.8)
# Meta-infrastructure to allow po-based translation of Colobot help files and scene-description (level) files.
# set(LEVELS_I18N_PATH ${CMAKE_CURRENT_SOURCE_DIR})
# set(LEVEL_CODENAME "scene100")
# set(SCENEFILE "scene100/scene.txt")
# set(SCENEDEST "scene101.txt") # If unset , use the same name as SCENEFILE
# set(PODIR "scene100/po/")
# set(HELPDIR "scene100/help/")
# set(HELPDEST "")
project(colobot-level-${LEVEL_CODENAME} NONE)
if(NOT DEFINED COLOBOT_INSTALL_DATA_DIR)
set(COLOBOT_INSTALL_DATA_DIR ${CMAKE_INSTALL_PREFIX}/share/games/colobot CACHE PATH "Colobot shared data directory")
endif()
set(LEVEL_INSTALL_DATA_DIR ${COLOBOT_INSTALL_DATA_DIR}/levels/)
set(HELP_INSTALL_DATA_DIR ${COLOBOT_INSTALL_DATA_DIR}/help/)
# Translate translatable material
find_program(PO4A po4a)
### STEP 3 # Inject translations in levels
set(_levels_i18n_target "levels_i18n")
file(GLOB levelfiles "${CMAKE_CURRENT_SOURCE_DIR}/${SCENEFILE}")
foreach(levelfile ${levelfiles})
if(DEFINED SCENEDEST)
get_filename_component(_scenedest ${SCENEDEST} NAME)
else()
get_filename_component(_scenedest ${levelfile} NAME)
endif()
get_filename_component(_levelfile ${levelfile} NAME_WE)
if(PO4A AND EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/${PODIR}")
add_custom_command(OUTPUT ${_levels_i18n_target}/${_scenedest}
COMMAND mkdir -p ${CMAKE_CURRENT_BINARY_DIR}/${_levels_i18n_target}
COMMAND ${LEVELS_I18N_PATH}/scripts/03_inject_translations.sh ${levelfile} ${CMAKE_CURRENT_BINARY_DIR}/${LEVEL_CODENAME}/${_levelfile} ${PODIR} > ${CMAKE_CURRENT_BINARY_DIR}/${_levels_i18n_target}/${_scenedest}
DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/po4a-ran-${LEVEL_CODENAME}
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
COMMENT "${LEVEL_CODENAME}: Inject translation in ${_scenedest}"
)
else()
add_custom_command(OUTPUT ${_levels_i18n_target}/${_scenedest}
COMMAND mkdir -p ${CMAKE_CURRENT_BINARY_DIR}/${_levels_i18n_target}
COMMAND cp ${levelfile} ${CMAKE_CURRENT_BINARY_DIR}/${_levels_i18n_target}/${_scenedest}
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
COMMENT "${LEVEL_CODENAME}: Move untranslatable ${_scenedest}"
)
endif()
add_custom_target(level_i18n-${LEVEL_CODENAME}_${_levelfile} ALL DEPENDS ${_levels_i18n_target}/${_scenedest})
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${_levels_i18n_target}/${_scenedest}
DESTINATION ${LEVEL_INSTALL_DATA_DIR})
endforeach()
file(GLOB helpfiles "${CMAKE_CURRENT_SOURCE_DIR}/${HELPDIR}/E/*.txt")
list(SORT helpfiles)
if(PO4A AND EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/${PODIR}")
foreach(helpfile ${helpfiles})
get_filename_component(_helpfile_we ${helpfile} NAME_WE)
get_filename_component(_helpfile ${helpfile} NAME)
### STEP 4 # Put translated help files in the correct place
set(_help_i18n_target "help_i18n_${LEVEL_CODENAME}_${_helpfile_we}")
add_custom_command(OUTPUT moved-all-${LEVEL_CODENAME}-${_helpfile}
COMMAND mkdir -p ${CMAKE_CURRENT_BINARY_DIR}/${_help_i18n_target}
COMMAND ${LEVELS_I18N_PATH}/scripts/04_move_helpfiles_to_paths.sh ${LEVEL_CODENAME} ${LEVEL_CODENAME}-help/${_helpfile} ${_help_i18n_target} '${HELPDIR}' '${HELPDEST}' ${CMAKE_CURRENT_SOURCE_DIR} > moved-all-${LEVEL_CODENAME}-${_helpfile}
DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/po4a-ran-${LEVEL_CODENAME}
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
COMMENT "${LEVEL_CODENAME}: Move ${_helpfile} translations around"
)
add_custom_target(help_i18n-${LEVEL_CODENAME}_${_helpfile_we} ALL DEPENDS moved-all-${LEVEL_CODENAME}-${_helpfile})
install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/${_help_i18n_target}/
DESTINATION ${HELP_INSTALL_DATA_DIR})
endforeach()
elseif(DEFINED HELPDIR AND EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/${HELPDIR}")
set(_help_i18n_target "help_i18n_${LEVEL_CODENAME}")
add_custom_command(OUTPUT moved-all-${LEVEL_CODENAME}
COMMAND mkdir -p ${CMAKE_CURRENT_BINARY_DIR}/${_help_i18n_target}
COMMAND ${LEVELS_I18N_PATH}/scripts/05_move_untranslated_helpfiles_to_paths.sh '${_help_i18n_target}' '${HELPDEST}' '${CMAKE_CURRENT_SOURCE_DIR}/${HELPDIR}' > moved-all-${LEVEL_CODENAME}-${_helpfile}
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
COMMENT "${LEVEL_CODENAME}: Move untranslatable help files"
)
add_custom_target(help_i18n-${LEVEL_CODENAME} ALL DEPENDS moved-all-${LEVEL_CODENAME})
install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/${_help_i18n_target}/
DESTINATION ${HELP_INSTALL_DATA_DIR})
endif()
#### STEP 1 # Create po4a.cfg file out of the list of files
add_custom_command(OUTPUT po4a-${LEVEL_CODENAME}.cfg
COMMAND ${LEVELS_I18N_PATH}/scripts/01_create_po4a_file.sh ${CMAKE_CURRENT_SOURCE_DIR} ${PODIR} ${LEVEL_CODENAME} '${SCENEFILE}' '${HELPDIR}/E' > ${CMAKE_CURRENT_BINARY_DIR}/po4a-${LEVEL_CODENAME}.cfg
COMMENT "${LEVEL_CODENAME}: Create po4a configuration file"
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
)
if(PO4A AND EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${PODIR})
#### STEP 2 # Run po4a
add_custom_command(OUTPUT po4a-ran-${LEVEL_CODENAME}
COMMAND ${LEVELS_I18N_PATH}/scripts/02_run_po4a.sh ${LEVELS_I18N_PATH} ${CMAKE_CURRENT_BINARY_DIR}/po4a-${LEVEL_CODENAME}.cfg
COMMAND touch po4a-ran-${LEVEL_CODENAME}
DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/po4a-${LEVEL_CODENAME}.cfg
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
COMMENT "${LEVEL_CODENAME}: Run po4a to generate the translated files out of the .po files")
add_custom_target(po4a-${LEVEL_CODENAME} DEPENDS po4a-ran-${LEVEL_CODENAME})
else()
message(STATUS "${LEVEL_CODENAME}: No translation needed or possible")
file(GLOB levelfiles "${CMAKE_CURRENT_SOURCE_DIR}/levels/*.txt")
install(FILES ${levelfiles} DESTINATION ${LEVEL_INSTALL_DATA_DIR}/)
endif()

View File

@ -0,0 +1,42 @@
#!/bin/sh
set -e
# MUST be run from ${CMAKE_CURRENT_BINARY_DIR}
srcdir=$1 # absolute
PODIR=$2 # relative
LEVEL_CODENAME=$3 # relative
SCENEFILE=$4 # relative
HELPDIR=$5 # relative
rm -Rf $LEVEL_CODENAME-po
ln -s $srcdir/$PODIR $LEVEL_CODENAME-po
echo "[po_directory] $LEVEL_CODENAME-po"
# Create a pseudo file for the translation of the language code
echo "[type:text] ${LEVEL_CODENAME}.languagecode \$lang:${LEVEL_CODENAME}.\$lang.languagecode"
echo "E" > ${LEVEL_CODENAME}.languagecode
# Create symlink for relative paths in po4a
mkdir -p $LEVEL_CODENAME
if [ -n "$SCENEFILE" ]; then
# Levels are precompiled, they are already in the current dir
for scene in $(cd $srcdir/; ls $SCENEFILE); do
scene_=$(basename $scene .txt)
$(cd $LEVEL_CODENAME; ln -s $srcdir/$scene $scene_.txt)
echo "[type:colobotlevel] $LEVEL_CODENAME/$scene_.txt \$lang:$LEVEL_CODENAME/$scene_.\$lang.txt"
done
fi
# Create symlink for relative paths in po4a
mkdir -p $LEVEL_CODENAME-help
if [ -d $srcdir/$HELPDIR ]; then
for helpfile in $(cd $srcdir/$HELPDIR; ls *.txt); do
helpfile_=$(basename $helpfile .txt)
$(cd $LEVEL_CODENAME-help; ln -s $srcdir/$HELPDIR/$helpfile $helpfile_.txt)
echo "[type:colobothelp] $LEVEL_CODENAME-help/$helpfile_.txt \$lang:$LEVEL_CODENAME-help/$helpfile_.\$lang.txt"
done
fi

View File

@ -0,0 +1,10 @@
#!/bin/sh
set -e
LEVELS_I18N_PATH=$1
PO4A_FILE=$2
export PERLLIB=${LEVELS_I18N_PATH}/scripts/perllib
po4a -k100 -v -f $PO4A_FILE

View File

@ -0,0 +1,28 @@
#!/bin/sh
set -e
levelfile=$1
translations_prefix=$2
PODIR=$3
rootfilename=$(basename $translations_prefix)
# Autodetect translated languages
script_path=$(dirname $0)
linguas=$(cd $PODIR/; ls *.po | sed -e 's/\.po$//g')
# Make sure we take english (first, but it's not really important)
for lang in en $linguas; do
dotlang=".$lang"
if [ "$lang" = "en" ]; then
dotlang="";
fi
i18nfile=$translations_prefix$dotlang.txt
if [ -f $i18nfile ]; then
sed -n '/^Title/p;/^Resume/p;/^ScriptName/p' $i18nfile
fi
done
echo "// End of level headers translations"
echo ""
sed -e '/^Title/d;/^Resume/d;/^ScriptName/d' $levelfile

View File

@ -0,0 +1,42 @@
#!/bin/sh
set -e
codename=$1
orig_file=$2
dest_dir=$3
HELPDIR=$4
HELPDEST=$5
CMAKE_CURRENT_SOURCE_DIR=$6
orig_l10n_file=$(basename $orig_file .txt)
orig_l10n_dir=$(dirname $orig_file)
# Get all language codes
for lcodef in $(ls ${codename}.*.languagecode); do
# Get the one-letter language code
LCODE=$(cat $lcodef)
lang=$(echo $lcodef | sed -e 's/.*\.\(.*\)\.languagecode/\1/')
# Foreach, rename the source files
mkdir -p $dest_dir/$LCODE/$HELPDEST
orig_trans=$CMAKE_CURRENT_SOURCE_DIR/$HELPDIR/$LCODE/$orig_l10n_file.txt
# Copy the translated file to the correct pathi
if [ -e $orig_l10n_dir/$orig_l10n_file.$lang.txt ]; then
cp -Lf $orig_l10n_dir/$orig_l10n_file.$lang.txt $dest_dir/$LCODE/$HELPDEST/$orig_l10n_file.txt
# Mark the source file that the translation is supposed to replace # Replace false by true to make it happen
if [ -e $orig_trans ] && false; then
sed -e '/Obsoleted translation/d;/This translated file/d' $orig_trans >$orig_trans.temp
echo "\\\\b; Obsoleted translation\nThis translated file has been replaced by it's PO-based counterpart and should be removed.\n" > $orig_trans
cat $orig_trans.temp >> $orig_trans
rm $orig_trans.temp
fi
elif [ -e $orig_trans ]; then
cp -Lf $orig_trans $dest_dir/$LCODE/$HELPDEST/$orig_l10n_file.txt
fi
done
mkdir -p $dest_dir/E/$HELPDEST
# Copy the english file to the correct path too
cp -Lf $orig_file $dest_dir/E/$HELPDEST/$orig_l10n_file.txt

View File

@ -0,0 +1,14 @@
#!/bin/sh
set -e
HELP_I18N_TARGET=$1
HELPDEST=$2
HELPDIR_FULL=$3
for langdir in $(ls ${HELPDIR_FULL}); do
if [ "$langdir" != "po" ]; then
mkdir -p ${HELP_I18N_TARGET}/$langdir/${HELPDEST}
cp ${HELPDIR_FULL}/$langdir/* ${HELP_I18N_TARGET}/$langdir/${HELPDEST}/
fi
done

View File

@ -0,0 +1,194 @@
# Locale::Po4a::Colobothelp -- Convert Colobot help files
#
# This program is free software; you may redistribute it and/or modify it
# under the terms of GPLv3.
#
use Locale::Po4a::TransTractor qw(process new);
use Locale::Po4a::Common;
use Locale::Po4a::Text;
package Locale::Po4a::Colobothelp;
use 5.006;
use strict;
use warnings;
require Exporter;
use vars qw(@ISA @EXPORT $AUTOLOAD);
@ISA = qw(Locale::Po4a::TransTractor);
@EXPORT = qw();
my @comments = ();
sub initialize {}
sub parse {
my $self = shift;
my ($line,$ref);
my $paragraph="";
my $wrapped_mode = 1;
my $s_mode = 0;
my $expect_header = 1;
my $end_of_paragraph = 0;
($line,$ref)=$self->shiftline();
while (defined($line)) {
chomp($line);
$self->{ref}="$ref";
($paragraph,$wrapped_mode,$s_mode,$expect_header,$end_of_paragraph) = parse_colobothelp($self,$line,$ref,$paragraph,$wrapped_mode,$s_mode,$expect_header,$end_of_paragraph);
if ($end_of_paragraph) {
do_paragraph($self,offlink($paragraph),$wrapped_mode);
$paragraph="";
$wrapped_mode = 1;
$end_of_paragraph = 0;
}
($line,$ref)=$self->shiftline();
}
if (length $paragraph) {
$paragraph =~ s/\n$//;
do_paragraph($self,$paragraph,$wrapped_mode);
$self->pushline("\n");
}
}
sub parse_colobothelp {
my ($self,$line,$ref,$paragraph,$wrapped_mode,$s_mode,$expect_header,$end_of_paragraph) = @_;
if (($s_mode == 1) and ($line !~ /^\\s;/)) {
# Process the end of \s; blocks
$s_mode = 0;
# substr removes the last superfluous \n
my $s_block = onlink($self->translate(substr(offlink($paragraph),0,-1),$ref,"\\s; block (usually verbatim code)"));
$s_block =~ s/(\n|^)/$1\\s;/g;
$self->pushline($s_block."\n");
$paragraph="";
$wrapped_mode = 0;
}
if ( $line =~ /^\s*$/
or $line =~ m/^\\[nctr];$/) {
# Break paragraphs on lines containing only spaces or any of \n; \c; \t; \r; (alone)
# Drop the latest EOL to avoid having it in the translation
my $dropped_eol = ($paragraph =~ s/\n$//);
do_paragraph($self,$paragraph,$wrapped_mode);
$self->pushline("\n") if $dropped_eol; # Therefore only add it back if it was removed
$paragraph="";
$wrapped_mode = 0;
$self->pushline($line."\n");
} elsif ($line =~ s/^(\\s;)//) {
# Lines starting with \s; are special (yellow-background, usually code-block)
# Break paragraph before them
if($s_mode == 0) {
$s_mode = 1;
my $dropped_eol = ($paragraph =~ s/\n$//);
do_paragraph($self,$paragraph,$wrapped_mode);
$self->pushline("\n") if $dropped_eol; # Therefore only add it back if it was removed
$paragraph="";
$wrapped_mode = 0;
}
$paragraph .= $line."\n";
} elsif ($line =~ s/^(\\[bt];)//) {
# Break paragraphs on \b; or \t; headers
do_paragraph($self,$paragraph,$wrapped_mode);
$paragraph="";
$wrapped_mode = 1;
$self->pushline($1.onlink($self->translate(offlink($line),$ref,"$1 header")."\n"));
} elsif ($line =~ /^\\image (.*) (\d*) (\d*);$/) {
# Discard lines with \image name lx ly; tags
do_paragraph($self,$paragraph,$wrapped_mode);
$paragraph="";
$wrapped_mode = 1;
$self->pushline("\\image ".$self->translate($1,$ref,'Image filename')." $2 $3;\n");
} elsif ( $line =~ /^=+$/
or $line =~ /^_+$/
or $line =~ /^-+$/) {
$wrapped_mode = 0;
$paragraph .= $line."\n";
do_paragraph($self,$paragraph,$wrapped_mode);
$paragraph="";
$wrapped_mode = 1;
} elsif ($line =~ s/^(\s*)([0-9]\)|[o-])(\s*)//) {
# Break paragraphs on lines starting with either number + parenthesis or any of o- + space
do_paragraph($self,$paragraph,$wrapped_mode);
$paragraph="";
$wrapped_mode = 1;
$self->pushline("$1$2$3".onlink($self->translate(offlink($line),$ref,"Bullet: '$2'")."\n"));
} else {
# All paragraphs are non-wrap paragraphs by default
$wrapped_mode = 0;
undef $self->{bullet};
undef $self->{indent};
$paragraph .= $line."\n";
}
return ($paragraph,$wrapped_mode,$s_mode,$expect_header,$end_of_paragraph);
}
sub offlink {
my ($paragraph) = @_;
# Put \const;Code\norm; sequences into pseudo-HTML <format const> tags
$paragraph =~ s#\\(const|type|token);([^\\;]*?)\\norm;#<format $1>$2</format>#g;
# Transform CBot links \l;text\u target; into pseudo-HTML <a target>text</a>
$paragraph =~ s#\\l;(.*?)\\u ([^;]*?);#<a $2>$1</a>#g;
# Cleanup pseudo-html targets separated by \\ to have a single character |
$paragraph =~ s#<a (.*?)\\(.*?)>#<a $1|$2>#g;
# Put \c;Code\n; sequences into pseudo-HTML <code> tags
$paragraph =~ s#\\c;([^\\;]*?)\\n;#<code>$1</code>#g;
# Replace remnants of \s; \c; \b; or \n; as pseudo xHTML <s/> tags
$paragraph =~ s#\\([scbn]);#<$1/>#g;
# Replace remnants of \const; \type; \token or \norm; as pseudo xHTML <const/> tags
$paragraph =~ s#\\(const|type|token|norm);#<$1/>#g;
# Replace \button $id; as pseudo xHTML <button $id/> tags
$paragraph =~ s#\\button ([^;]*?);#<button $1/>#g;
return ($paragraph);
}
sub onlink {
my ($paragraph) = @_;
# Invert the replace of \button $id; as pseudo xHTML <button $id/> tags
$paragraph =~ s#<button ([^;]*?)/>#\\button $1;#g;
# Invert the replace remnants of \const; \type; \token or \norm; as pseudo xHTML <const/> tags
$paragraph =~ s#<(const|type|token|norm)/>#\\$1;#g;
# Invert the replace remnants of \s; \c; \b; or \n; as pseudo xHTML <s/> tagsyy
$paragraph =~ s#<([scbn])/>#\\$1;#g;
# Inverse the put of \c;Code\n; sequences into pseudo-HTML <code> tags
$paragraph =~ s#<code>([^\\;]*?)</code>#\\c;$1\\n;#g;
# Inverse of the cleanup of pseudo-html targets separated by \\ to have a single character |
$paragraph =~ s#<a (.*?)\|(.*?)>#<a $1\\$2>#g;
# Inverse of the transform of CBot links \l;text\u target; into pseudo-HTML <a target>text</a>
$paragraph =~ s#<a (.*?)>(.*?)</a>#\\l;$2\\u $1;#g;
# Invert the put \const;Code\norm; sequences into pseudo-HTML <format const> tags
$paragraph =~ s#<format (const|type|token)>([^\\;]*?)</format>#\\$1;$2\\norm;#g;
return ($paragraph);
}
sub do_paragraph {
my ($self, $paragraph, $wrap) = (shift, shift, shift);
my $type = shift || $self->{type} || "Plain text";
return if ($paragraph eq "");
my $end = "";
if ($wrap) {
$paragraph =~ s/^(.*?)(\n*)$/$1/s;
$end = $2 || "";
}
my $t = onlink($self->translate(offlink($paragraph),
$self->{ref},
$type,
"wrap" => $wrap));
if (defined $self->{bullet}) {
my $bullet = $self->{bullet};
my $indent1 = $self->{indent};
my $indent2 = $indent1.(' ' x length($bullet));
$t =~ s/^/$indent1$bullet/s;
$t =~ s/\n(.)/\n$indent2$1/sg;
}
$self->pushline( $t.$end );
}
1;
__END__

View File

@ -0,0 +1,93 @@
# Locale::Po4a::ColobotLevels -- Convert Colobot levels
#
# This program is free software; you may redistribute it and/or modify it
# under the terms of GPLv3.
#
use Locale::Po4a::TransTractor qw(process new);
use Locale::Po4a::Common;
package Locale::Po4a::Colobotlevel;
use 5.006;
use strict;
use warnings;
require Exporter;
use vars qw(@ISA @EXPORT $AUTOLOAD);
@ISA = qw(Locale::Po4a::TransTractor);
@EXPORT = qw();
my $debug=0;
sub initialize {}
sub parse {
my $self=shift;
my ($line,$ref);
my $parE;
LINE:
($line,$ref)=$self->shiftline();
while (defined($line)) {
chomp($line);
if ($line =~ /^(Title|Resume|ScriptName)/) {
# Text before the first dot
$line =~ m/(^[^"\r\n]*)\./;
my $type = $1;
# One char just after the .
$line =~ m/\.(.)/;
my $E = $1;
if( not $parE ) {
# Take this one-char only once
$parE = $self->translate($E, '', 'One-char language identifier');
}
# The text between .E and first quote
$line =~ m/\.$E([^\r\n"]*?)(text|resume)="([^\r\n"]*?)"([^\r\n"]*)((text|resume)="([^\r\n"]*?)"([^\r\n"]*))?$/;
my $spacing_1 = $1;
my $subtype_1 = $2;
my $quoted_1 = $3;
my $spacing_2 = $4;
my $secondpart = $5;
my $subtype_2 = $6;
my $quoted_2 = $7;
my $spacing_3 = $8;
$ref =~ m#^(.*)/(.*)\.txt.*$#;
my $code;
if( $2 eq 'scene' ) {
$code = $1;
} else {
$code = $2;
}
my $par_1 = $self->translate($code.":".$quoted_1, $ref, $type."-".$subtype_1);
$par_1 =~ s/^\D*\d*://;
if( $secondpart ) {
my $par_2 = $self->translate($code.":".$quoted_2, $ref, $type."-".$subtype_2);
$par_2 =~ s/^\D*\d*://;
# This is awkward, but works
$spacing_2 = $spacing_2.$subtype_2.'="'.$par_2.'"'.$spacing_3;
}
$par_1 =~ s/\n/\\n/g;
$spacing_2 =~ s/\n/\\n/g;
# Now push the result
$self->pushline($type.'.'.$parE.$spacing_1.$subtype_1.'="'.$par_1.'"'.$spacing_2."\n");
}
else
{
$self->pushline("$line\n");
}
# Reinit the loop
($line,$ref)=$self->shiftline();
}
}
1;
__END__