blob: 358448645bf255da384d16251cb7830a5d50d922 [file] [log] [blame]
#!/usr/bin/perl
#########################################################################
#**************************************************************
#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
#
#**************************************************************
####################################################################
# File Name: converterlib.pm
# Version : 1.0
# Project : XMerge
# Author : Brian Cameron
# Date : 5th Sept. 2001
#
# This script enters text at position x,y on screen.
#
# Parameter
# x-coordinate
# y-coordinate
# Text to enter
#
##########################################################################
use EmRPC; # EmRPC::OpenConnection, CloseConnection
use EmFunctions;
use EmUtils;
# Set global_debug flag
#
$global_debug = $ENV{'ZENDEBUG'};
#$em_script_home = "/export/home/test/qadir/bin";
$em_script_home = $ENV{'EM_SCRIPT_HOME'};
#$qa_script_home = "/export/home/test/qadir/qa-new/bin";
$qa_script_home = $ENV{'QA_SCRIPT_HOME'};
#
# CONVERT FUNCTIONS
#
# convert_to_pdb
# directory - directory containing the xml-orig and pdb-orig
# subdirectories.
# file - file to convert
# extension - extension of file to convert (sxw or sxc)
# convert_to - what PDB format to convert into.
#
# Returns 0 if success, -1 otherwise.
#
# Converts file from XML to PDB
#
sub convert_to_pdb
{
my $directory = $_[0];
my $file = $_[1];
my $extension = $_[2];
my $convert_to = $_[3];
my $pdb_directory = $_[4];
my $rc = 0;
my $xmlfile = "$directory/$file.$extension";
my $pdbdir = "$pdb_directory";
&enter_func("convert_to_pdb");
if (! -f "$xmlfile")
{
print "\nERROR, file $xmlfile does not exist\n";
$rc = -1;
}
if (! -d "$pdbdir")
{
print "\nERROR, directory $directory/pdb-orig does not exist\n";
$rc = -1;
}
if ($rc != -1)
{
if ("$convert_to" eq "application/x-minicalc")
{
# Move all files over.
#
my $i = 1;
while (-f "$pdbdir/$file-Sheet$i.pdb")
{
my $pdbfile = "$pdbdir/$file-Sheet$i.pdb";
print "\n";
if (-f "$pdbfile.old")
{
print "Removing $pdbfile.old\n";
`/bin/rm -f $pdbfile.old`;
}
print "Moving $pdbfile file to $pdbfile.old\n";
`mv "$pdbfile" "$pdbfile.old"`;
$i++;
}
}
else
{
if (-f "$pdbdir/$file.pdb")
{
print "\n";
if (-f "$pdbdir/$file.pdb.old")
{
print "Removing $pdbdir/$file.pdb.old\n";
`/bin/rm -f $pdbdir/$file.pdb.old`;
}
print "Moving $pdbdir/$file.pdb file to $pdbdir/$file.pdb.old\n";
`mv "$pdbdir/$file.pdb" "$pdbdir/$file.pdb.old"`
}
}
&start_rd($extension, $convert_to, $xmlfile, "");
if ("$convert_to" eq "application/x-minicalc")
{
# Must handle minicalc separately since it can
# convert to multiple files with this file name
# convention.
#
print "Moving $file-Sheet*.pdb files to $pdbdir\n";
`mv $file-Sheet*.pdb $pdbdir`;
`chmod 666 $pdbdir/$file-*.pdb`;
}
else
{
print "Moving $file.pdb file to $pdbdir\n";
`mv $file.pdb $pdbdir`;
`chmod 666 $pdbdir/$file.pdb`;
}
}
&leave_func("convert_to_pdb");
return $rc;
}
# convert_to_xml
# xmldir - directory to contain the xml output.
# xmlorigdir - directory to contain the xml input (used for merge)
# pdbfile - file to convert
# convert_from - what PDB format to convert from.
# extension - extension of file to convert (sxw or sxc)
# output - output filename to create
# merge_opt - 1 if convert and merge, 0 if convert only
#
# Returns 0 if success, -1 otherwise.
#
# Converts file from PDB to XML
#
sub convert_to_xml
{
my $xmldir = $_[0];
my $xmlorigdir = $_[1];
my $pdbfile = $_[2];
my $convert_from = $_[3];
my $extension = $_[4];
my $output = $_[5];
my $merge_opt = $_[6];
my $rc = 0;
&enter_func("convert_to_xml");
my @args = split(/ /,$pdbfile);
for ($i=0;$i <= $#args; $i++)
{
if (! -f "@args[$i]")
{
print "\nERROR, file $pdbfile does not exist\n";
$rc = -1;
}
}
if (! -f "$xmlorigdir/$output.$extension")
{
print "\nERROR, file $xmlorigdir/$output.$extension does not exist\n";
$rc = -1;
}
if (! -d "$xmldir")
{
print "\nERROR, directory $xmlorigdir does not exist\n";
$rc = -1;
}
if (! -d "$xmlorigdir")
{
print "\nERROR, directory $xmldir does not exist\n";
$rc = -1;
}
if ($rc != -1)
{
if ($merge_opt == 1)
{
print "Copying <$xmlorigdir/$output.$extension> to <$xmldir>\n";
`cp $xmlorigdir/$output.$extension $xmldir/`;
my $check_stamp = (stat("$xmldir/$output.$extension"))[9];
&start_rd($convert_from, $extension, $pdbfile,
"$xmldir/$output.$extension");
# No need to move the file to the $xmldir since the merge
# argument specifies the output file.
my $check_stamp_update = (stat("$xmldir/$output.$extension"))[9];
if ($check_stamp eq $check_stamp_update)
{
print "\nERROR, Problem while merging <$xmldir/$output.$extension>\n";
`mv $xmldir/$output.$extension $xmldir/$output.$extension.err`;
}
}
else
{
&start_rd($convert_from, $extension, $pdbfile, "");
print "Moving $output.$extension to $xmldir\n";
`mv $output.$extension $xmldir`;
`chmod 666 $xmldir/$output.$extension`;
}
}
&leave_func("convert_to_xml");
return $rc;
}
# start_rd
# from - format to convert from
# to - format to convert to
# file - file to convert
# merge - merge filename ("" indicates convert-only with no merge)
#
# converts file from/to the specified formats.
#
sub start_rd
{
my $from = $_[0];
my $to = $_[1];
my $file = $_[2];
my $merge = $_[3];
print "\nConverting from $from to $to.\n";
if ($global_debug)
{
&print_debug ("rd command is:\n");
}
if ($merge eq "")
{
&print_debug (" $em_script_home/rd -from $from -to $to $file\n");
print "\nConverting from $from to $to with no merge.\n";
`$em_script_home/rd -from $from -to $to $file`;
}
else
{
&print_debug (" $em_script_home/rd -from $from -to $to -merge $merge $file\n");
print "\nConverting from $from to $to with merge.\n";
`$em_script_home/rd -from $from -to $to -merge $merge $file`;
}
print "Done converting.\n\n";
}
#
# POSE INTERACTION FUNCTIONS
#
# open_connection
# display_debug - debug will be displayed if not 0
#
# Opens the connection to pose.
#
sub open_connection
{
my $display_debug = $_[0];
my $rc;
EmRPC::OpenConnection(6415, "localhost");
if ($display_debug && $global_debug)
{
print "\nPose Connection Opened\n";
}
}
# close_connection
# display_debug - debug will be displayed if not 0
#
# Closes the connection to pose.
#
sub close_connection
{
my $display_debug = $_[0];
EmRPC::CloseConnection();
if ($display_debug && $global_debug)
{
print "\nPose Connection Closed\n";
}
}
# start_pose
# pose_exe - name of pose executable.
# apps_load - The PRC files to load into pose, can be a comma
# separated list.
# run_prog - Program to run at startup.
# timeout - Timeout value to use when starting pose.
#
# Starts the Palm OS Emulator, loads PRC files, and starts
# a program.
#
sub start_pose
{
my $pose_exe = $_[0];
my $sessionfile = $ENV{'EM_SESSION_FILE'};
my $romfile = $ENV{'EM_ROM_FILE'};
my $apps_load = $_[1];
my $run_prog = $_[2];
my $timeout = $_[3];
my $stay_in_loop = 1;
my $address;
my $title;
my $form;
my $label_id;
my $num_objects;
my $i;
my $ii;
my $rc = 1;
my $pose_cmd = "$pose_exe ";
$pose_cmd .= " -psf $sessionfile ";
$pose_cmd .= "-load_apps $apps_load ";
$pose_cmd .= "-run_app $run_prog";
# It is more effective to use the -psf argument to
# set these values.
#
# $pose_cmd .= -rom $romfile ";
# $pose_cmd .= "-ram_size 8192 ";
# $pose_cmd .= "-device PalmVx ";
&enter_func("start_pose");
if ($global_debug)
{
&print_debug("\n");
&print_debug("pose command is:\n");
&print_debug(" $pose_cmd\n");
}
print "\nLaunching pose...\n";
system ("$pose_cmd &");
# Give time for pose to get started...
#
for ($i=0; $i < $timeout; $i++)
{
$tmp = $i + 1;
print "$tmp\n";
# Do not use pose_sleep here
#
sleep(1);
}
# Verify pose started successfully, and fail otherwise...
#
$rc = &verify_pose(5);
if ($rc != 0)
{
$stay_in_loop = 0;
}
else
{
# Sleep before opening the connection again, after testing in
# the verify_pose function.
#
pose_sleep(2);
&open_connection(1);
print "\nChecking if the appropriate window is on screen...\n";
}
# Stop looping when the specified window has started.
#
for ($i=0; $i < $timeout && $stay_in_loop == 1; $i++)
{
$form = FrmGetActiveForm();
$num_objects = FrmGetNumberOfObjects($form);
for $ii (0..$num_objects - 1)
{
my ($object_type) = FrmGetObjectType($form, $ii);
if ("$run_prog" eq "Quickword")
{
if ($object_type == frmTitleObj)
{
($address, $title) = FrmGetTitle($form,);
# Display count and title.
#
$tmp = $i + 1;
print "$tmp - title is $title\n";
if ("$title" eq "Quickword")
{
$stay_in_loop = 0;
$rc = 0;
last;
}
}
}
elsif ("$run_prog" eq "MiniCalc")
{
if ($object_type == frmLabelObj)
{
$label_id = FrmGetObjectId ($form, $ii);
($address, $label) = FrmGetLabel($form, $label_id);
# Display count and label.
#
$tmp = $i + 1;
print "$tmp - label is $label\n";
if ("$label" =~ "Solutions In Hand")
{
$stay_in_loop = 0;
$rc = 0;
last;
}
}
}
}
# Do not use pose_sleep here
#
sleep(1);
}
# Do not use pose_sleep here
#
sleep(1);
&leave_func("start_pose");
return($rc);
}
# kill_pose
#
# Kills all pose processes
#
sub kill_pose
{
if ($global_debug)
{
print "Stopping pose process...\n";
}
`pkill pose`;
}
# verify_pose
# timeout - timeout to wait for pose
#
# Tries to do a connect/close to Pose to see if
# it is working okay.
#
sub verify_pose
{
my $timeout = $_[0];
my $rc = 0;
$rc = system("$em_script_home/verify_sane.pl $timeout");
return $rc;
}
# db_export
# dbname - Name of database to export
#
# Exports a palmdb file to /tmp
#
sub db_export
{
my $dbname = $_[0];
&enter_func("db_export");
print "\nExporting PDB file <$dbname> from pose\n";
&pose_tap_pen(22, 20, 2);
&pose_tap_pen (15, 85, 2);
&enter_string($dbname, 1);
&pose_tap_pen (15, 126, 1);
&enter_string("/tmp/", 1);
&pose_tap_button("OK", 4);
&tap_applications(3);
print "Export of PDB file <$dbname> completed.\n";
&leave_func("db_export");
}
#
# QUICKWORD SPECIFIC
#
# start_quickword
#
# Assuming pose was launched with the -run_app flag to launch
# QuickWord on startup, this starts up QuickWord with the first
# file in the list and turns off write-protect.
#
sub start_quickword
{
&enter_func("start_quickword");
# This will open the first file in the list.
# Assuming this will always be the case.
#
&pose_tap_pen(20, 18, 1);
&quickword_press_write_protect();
&leave_func("start_quickword");
}
# quickword_press_write_protect
#
# Useful function for pressing the write protect button
# to allow changes to be made.
#
sub quickword_press_write_protect
{
&enter_func("quickword_press_write_protect");
my ($form) = FrmGetActiveForm();
my ($num_objects) = FrmGetNumberOfObjects($form);
for $ii (0..$num_objects - 1)
{
my ($object_type) = FrmGetObjectType($form, $ii);
# The write protect button is the only frmGadgetObj
# on the QuickWord screen.
#
if ($object_type == frmGadgetObj)
{
my (%bounds) = FrmGetObjectBounds($form, $ii);
if ($global_debug)
{
&print_debug(" Found QuickWord WriteProtect button\n");
&print_debug(" left = $bounds{left}\n");
&print_debug(" right = $bounds{right}\n");
&print_debug(" top = $bounds{top}\n");
&print_debug(" bottom = $bounds{bottom}\n");
}
# For some reason, the tapping of the write-protect button
# doesn't work unless you tap somewhere else first.
#
&pose_sleep(1);
&pose_tap_pen($bounds{left} + 2, $bounds{top} + 2, 1);
last;
}
}
&leave_func("quickword_press_write_protect");
}
# quickword_find_replace
# from_string - string to replace
# to_string - string to replace with
#
# Uses QuickWord's find/replace utility to replace
# one string with another.
#
sub quickword_find_replace
{
my $from_string = $_[0];
my $to_string = $_[1];
&enter_func("quickword_find_replace");
# Move cursor to beginning...
#
&quickword_tap_at_top(1);
# Move to "Find" field:
# Triple-click to highlight all the text in the field,
# so it is removed when the string is entered...
#
&pose_tap_button("Find", 2);
&pose_tap_pen(50, 100, 0);
&pose_tap_pen(50, 100, 0);
&pose_tap_pen(50, 100, 1);
# sleep for 2 seconds to avoid double click after moving
# to replace field
#
&enter_string("$from_string", 2);
# Move to "Replace" field:
# Triple-click to highlight all the text in the field,
# so it is removed when the string is entered...
#
&pose_tap_pen(50, 120, 0);
&pose_tap_pen(50, 120, 0);
&pose_tap_pen(50, 120, 1);
&enter_string("$to_string", 1);
# Do find, then replace...
#
&pose_tap_button("Find", 1);
&pose_tap_button("Replace", 1);
&pose_tap_button("Cancel", 1);
&leave_func("quickword_find_replace");
}
# quickword_tap_at_top
# secs - seconds to sleep after the tap
#
# Tap's at the top of the QuickWord document.
#
sub quickword_tap_at_top
{
my $secs = $_[0];
&enter_func("quickword_tap_at_top");
# Sleep for a second to avoid any double-clicks
# from happening.
#
&pose_sleep(1);
&pose_tap_pen(0, 15, $secs);
&leave_func("quickword_tap_at_top");
}
# Saves file and returns to the Application list.
#
sub close_quickword
{
&enter_func("close_quickword");
&pose_tap_button("Done", 2);
&tap_applications(2);
&leave_func("close_quickword");
}
#
# MINICALC SPECIFIC
#
# start_minicalc
#
# Assuming pose was launched with the -run_app flag to launch
# Minicalc on startup, this starts up Minicalc with the first
# file in the list.
#
sub start_minicalc
{
&enter_func("start_minicalc");
&pose_tap_button("OK", 1);
# For now just tap on the first spreadsheet. Add support
# for multiple sheets later.
#
&pose_tap_pen(10, 40, 5);
&leave_func("start_minicalc");
}
# close_minicalc
#
# Returns to the Application list (no need to save).
#
sub close_minicalc
{
&enter_func("close_minicalc");
&tap_applications(3);
&leave_func("close_minicalc");
}
# minicalc_enter_cell
# row - row to enter value, starting with 1
# col - column to enter value, starting with 1
# val - value to enter
#
# Only valid for minicalc.
#
# This only works if the val passed in has a '\n' at the
# end.
#
sub minicalc_enter_cell
{
my $row = $_[0];
my $col = $_[1];
my $val = $_[2];
my $i;
my $j;
&enter_func("minicalc_enter_cell");
if ($global_debug)
{
&print_debug (" tapping to cell row=<$row> col=<$col>\n");
}
# Tap pen on home button to start with row=1, col=A
# at top left.
#
pose_tap_pen(1, 1, 3);
# Now the cell should be in the top-left corner,
# so click there. However we must first click
# in another cell or pose doesn't acknowledge the
# click.
#
# pose_tap_pen(120, 95, 1);
# pose_tap_pen(21, 9, 1);
# Click the down button once for each row.
# Must pause 3 seconds each time, otherwise MiniCalc
# will not keep up.
#
for ($i=0; $i < $row; $i++)
{
if ($global_debug)
{
&print_debug (" Typing carrage return to go down\n");
}
enter_string("\n", 1);
}
# Click the right button once for each col.
# Must pause 3 seconds each time, otherwise MiniCalc
# will not keep up.
#
for ($i=0; $i < $col; $i++)
{
if ($global_debug)
{
&print_debug (" Typing tab to go right\n");
}
enter_string("\t", 1);
}
# enter string
#
&enter_string($val, 1);
&leave_func("minicalc_enter_cell");
}
#
# GENERIC UTILIIES (pose)
#
# tap_applications
# secs - seconds to sleep after the tap
#
# taps pen on the Applications button.
#
sub tap_applications
{
my $secs = $_[0];
&enter_func("tap_applications");
&pose_tap_pen(15, 170, 1);
&pose_tap_pen(155, 10, 1);
&pose_tap_pen(155, 10, $secs);
&leave_func("tap_applications");
}
# enter_string_at_location
# x - x-location to enter string
# y - y-location to enter string
# in_string - string to enter
# application - appliation (QUICKWORD or MINICALC)
#
# Enters a string at the specified x,y position.
#
sub enter_string_at_location
{
my $x_val = $_[0];
my $y_val = $_[1];
my $in_string = $_[2];
my $application = $_[3];
my $x;
my $y;
&enter_func("enter_string_at_location");
$x = $x_val;
$y = $y_val;
if ($application eq "QUICKWORD")
{
# Allow users to specify TOP/BOTTOM/LEFT/RIGHT
# for QuickWord.
#
if ($y_val eq "TOP")
{
if ($global_debug)
{
&print_debug(" Converting TOP to 15\n");
}
$y = 15;
}
if ($y_val eq "BOTTOM")
{
if ($global_debug)
{
&print_debug(" Converting BOTTOM to 144\n");
}
$y = 144;
}
if ($x_val eq "LEFT")
{
if ($global_debug)
{
&print_debug(" Converting LEFT to 0\n");
}
$x = 0;
}
if ($x_val eq "RIGHT")
{
if ($global_debug)
{
&print_debug(" Converting RIGHT to 152\n");
}
$x = 152;
}
}
# Just to make sure the offset isn't outside the
# proper area.
#
if ($x >= 100)
{
$offset = -2;
}
else
{
$offset = 2;
}
&off_tap_pen($x, $y, $offset);
&enter_string($in_string, 1);
&leave_func("enter_string_at_location");
}
# off_tap_pen
# x - x-location to tap
# y - y-location to tap
# offset - x-offset to use for first tap.
#
# For some reason, pose does not register a single
# pen tap if the last single pen tap was also
# at the same x,y coordinate (even if the last tap
# was a while ago). So this function does two
# slightly different pen taps to ensure then pen
# tap happens.
#
sub off_tap_pen
{
my $x = $_[0];
my $y = $_[1];
my $offset = $_[2];
&enter_func("off_tap_pen");
# sleep for 2 seconds to avoid double-click.
#
&pose_tap_pen_hard($x + $offset, $y, 2);
&pose_tap_pen_hard($x, $y, 1);
&leave_func("off_tap_pen");
}
# enter_string
# in_string - string to enter
# secs - seconds to sleep after entering the string
#
# Enters a string
#
sub enter_string
{
my $in_string = $_[0];
my $secs = $_[1];
my $j;
&enter_func("enter_string");
if ($global_debug)
{
# Display in_string so \n and \t values
# show up as normal ASCII.
#
if ($in_string eq "\n")
{
&print_debug(" Entering string : <\\n>\n");
}
elsif ($in_string eq "\t")
{
&print_debug(" Entering string : <\\t>\n");
}
else
{
&print_debug(" Entering string : <$in_string>\n");
}
}
# Replace "\n" with real carrage returns.
#
my $string_val = $in_string;
$string_val =~ s#\\n#\n#g;
# Replace "\t" with a real tab.
#
$string_val =~ s#\\t#\t#g;
# Convert string to ASCII numeric values
#
my @array = unpack("C*", $string_val);
# Enter string one key at a time.
#
for ($j=0; $j <= $#array; $j++)
{
$queue_size = EnterKey($array[$j], 0, 0);
}
if ($secs > 0)
{
pose_sleep($secs);
}
&leave_func("enter_string");
}
#
# GENERIC UTILIIES (non pose)
#
# get_date_string
#
# Returns a timestampe string in yyyymmddHHMM format, where:
# yyyy = year
# mm = month
# dd = day
# HH = hour
# MM = minute
#
# This sort of datestamp is used to create the output directory
# names, so it used in various places.
#
sub get_date_string
{
my $cur_secs = time;
my @lu = localtime $cur_secs;
my $lu_secs = $lu[1];
my $lu_hours = $lu[2];
my $lu_day = $lu[3];
my $lu_mon = $lu[4] + 1;
my $lu_year = $lu[5] + 1900;
my $lu_str = $lu_year;
if ($lu_mon < 10)
{
$lu_str .= "0";
}
$lu_str .= $lu_mon;
if ($lu_day < 10)
{
$lu_str .= "0";
}
$lu_str .= $lu_day;
if ($lu_hours < 10)
{
$lu_str .= "0";
}
$lu_str .= $lu_hours;
if ($lu_secs < 10)
{
$lu_str .= "0";
}
$lu_str .= $lu_secs;
return $lu_str;
}
#
# DEBUG FUNCTIONS - Wrapper functions
#
# pose_tap_pen
# x - x-position of pen tap
# y - y-position of pen tap
# secs - seconds to sleep after the tap
#
# Taps pen at specified position and displays debug info
#
sub pose_tap_pen
{
my $x = $_[0];
my $y = $_[1];
my $secs = $_[2];
if ($global_debug)
{
&print_debug(" Tapping pen at : $x,$y\n");
}
TapPen($x, $y);
if ($secs > 0)
{
pose_sleep($secs);
}
}
# pose_tap_pen_hard
# x - x-position of pen tap
# y - y-position of pen tap
# secs - seconds to sleep after the tap
#
# Taps pen at specified position and displays debug info
# This function works more effectively in situations where
# pose_tap_pen is flakey. This function is not good for
# double/triple click situations since it is slow.
#
sub pose_tap_pen_hard
{
my $x = $_[0];
my $y = $_[1];
my $secs = $_[2];
if ($global_debug)
{
&print_debug(" Tapping pen hard at : $x,$y\n");
}
`$qa_script_home/tappen.pl $x $y`;
if ($secs > 0)
{
pose_sleep($secs);
}
}
# pose_tap_button
# button - button to press
# secs - seconds to sleep after the button press
#
# Presses specified button and displays debug info
#
sub pose_tap_button
{
my $button = $_[0];
my $secs = $_[1];
if ($global_debug)
{
&print_debug(" Tapping button : $button\n");
}
TapButton($button);
if ($secs > 0)
{
pose_sleep($secs);
}
}
# pose_sleep
# secs - seconds to sleep
#
# Sleeps the specified amount of time and displays debug info
#
sub pose_sleep
{
my $secs = $_[0];
if ($global_debug)
{
&print_debug(" Sleeping : $secs seconds\n");
}
sleep($secs);
}
# enter_func
# func - function name
#
# Displays debug info about entering specified function.
#
sub enter_func
{
my $func = $_[0];
if ($global_debug)
{
&print_debug("Function enter : $func\n");
}
}
# leave_func
# func - function name
#
# Displays debug info about leaving specified function.
#
sub leave_func
{
my $func = $_[0];
if ($global_debug)
{
&print_debug("Function exit : $func\n");
}
}
# print_debug
# string - string to print
#
# Displays debug message with a # at the beginning of the line.
#
sub print_debug
{
my $string = $_[0];
print "# $string";
}
1;