A Help
File Display Subsystem in Perl
Perl can
be used in GUIs with the appropriate libraries but it's
far more often used from the command line.
That being
the case, a
method of providing on-line help is a useful card to hide up your
sleeve.
The
following two sub-routines (NextHelpSection and ShowHelp) are all
that's required to provide a
reasonably
comprehensive online manual.
Additions, such as a string search facility, I leave as an excercise
for the
reader.
The first
routine handles the nitty-gritty of page movement while the
second drives the whole thing.
The
sub-routines are presented with
their full inline documentation which should make it clear how they
work.
Page down
to the start of the second routine (ShowHelp) for a
full description of what a help file should look like.
You'll
probably find it easier to read the code if you highlight it and
copy it into your favourite editor.
#
=================================================
# Read forward to a specified section of help file.
# -------------------------------------------------
# $_[0] Help file name
# $_[1] Section number to read to
# H_HELP_FILE is used as a global variable
# -------------------------------------------------
# Returns <number> the last section read.
# -------------------------------------------------
# If the requested section is not found,
# this routine goes to the last readable section.
#
# The header for the subroutine ShowHelp describes
# details of the help file format.
# =================================================
sub NextHelpSection
{
my $P_FILENAME = $_[0];
my $V_TARGET_SECTION = trim $_[1];
my $V_NO_SHOW_LINE;
my $V_THIS_SECTION = -1;
my $V_LAST_SECTION = 1;
# ---------------------------------------
# Get the target section number.
# If it's blank, go back straight away...
# ---------------------------------------
if($V_TARGET_SECTION == 0)
{
return;
}
# -----------------------------------------
# Still here? Close and re-open the file...
# -----------------------------------------
close(H_HELP_FILE);
open(H_HELP_FILE, "<$P_FILENAME");
# ---------------------------------------
# Now read, without showing, until
# the required header is in the buffer...
# ---------------------------------------
while($V_THIS_SECTION != $V_TARGET_SECTION)
{
$V_NO_SHOW_LINE =
readline(H_HELP_FILE);
$V_TEST_STRING =
GetCsvElement(1, $V_NO_SHOW_LINE);
if($V_TEST_STRING eq
"!!SECTION")
{
# ---------------------------------------
# We've found a header, get the number...
# ---------------------------------------
$V_THIS_SECTION = GetCsvElement(2, $V_NO_SHOW_LINE);
# --------------------------------
# Have we hit the end of the file?
# --------------------------------
if($V_THIS_SECTION == 999999)
{
# ------------------------------------------
# Yes: so go to the last readable section...
# ------------------------------------------
close(H_HELP_FILE);
open(H_HELP_FILE, "<$P_FILENAME");
$V_TARGET_SECTION = $V_LAST_SECTION;
$V_NO_SHOW_LINE = readline(H_HELP_FILE);
next;
}
# -----------------------------------
# Store this section number
# in case we need to go back to it...
# -----------------------------------
$V_LAST_SECTION = $V_THIS_SECTION;
# ------------------------------------------------
# If we've passed the target address, stop here...
# ------------------------------------------------
if($V_THIS_SECTION > $V_TARGET_SECTION)
{
$V_TARGET_SECTION = $V_THIS_SECTION;
}
}
}
return($V_THIS_SECTION);
}
#
========================================================================
# Reads a help file and displays it.
# ----------------------------------
# $_[0] file to read
# H_HELP_FILE is used as a global variable.
#
------------------------------------------------------------------------
# returns nothing
#
------------------------------------------------------------------------
# Responds to the following keyboard commands...
# B goes to beginning of file
# C goes to contents page
# N displays next page
# P displays previous page
# n goes to section number n (n may be a
number up to 999998)
# Q closes file and exits
#
------------------------------------------------------------------------
# A helpfile is a text file consisting of the following elements...
#
# !!SECTION, 1
# <Any amount of text>
# !!END
# !!SECTION, 2
# <Contents description with
section numbers>
# !!END
# !!SECTION, 3
# <Any amount of text>
# !!END
# :
# : The above repeated any number of times
# :
# !!SECTION, 999999
#
# Apart from the section seperators, everything is pretty much optional.
# Section 2, though has the special meaning of 'contents page' so it
makes
# sense to use it as such. '!!SECTION, 999999' is required to enable the
# viewer to navigate correctly (see sub NextHelpSection to understand
this)
#
# The last section is ALWAYS 999999
#
# Note that section numbers need not be consecutive and there are
distinct
# advantages to leaving gaps for later expansion. Section 2 is the
default
# contents page but if you have non-consecutive pages you would be
advised
# to start each group with a contents page for that group.
#
========================================================================
sub ShowHelp
{
my $P_FILENAME = $_[0];
my $V_COMMAND;
my $V_SHOW_LINE;
my $V_TEST_STRING;
my $V_THIS_SECTION;
my $V_PREVIOUS_SECTION;
# -------------------------------------------------
# Open the file. Exit with a complaint if cannot...
# -------------------------------------------------
if(! open(H_HELP_FILE, "<$P_FILENAME"))
{
TraceScript 0,
"ShowHelp", "Cannot open file [" . $P_FILENAME . "]";
return;
}
# ---------------------------
# Clear the screen on a PC...
# ---------------------------
system("cls");
# -----------------------------------------------
# Loop continues until user deliberately exits...
# -----------------------------------------------
while($V_COMMAND ne "Q")
{
#
--------------------------
# Get a line and
parse it...
#
--------------------------
$V_SHOW_LINE =
readline(H_HELP_FILE);
$V_TEST_STRING =
GetCsvElement(1, $V_SHOW_LINE);
if($V_TEST_STRING eq
"!!SECTION")
{
# -----------------------------------------------------
# It's a section header, retrieve the section number...
# -----------------------------------------------------
$V_THIS_SECTION = GetCsvElement(3, $V_SHOW_LINE);
}
elsif($V_TEST_STRING
eq "!!END")
# ------------------------------------------
# It's a tail, so get user's instructions...
# ------------------------------------------
print
"-------------------------------------------------------------------------------\n";
print "<B>eginning, <C>ontents,
<N>ext, <P>revious, <section
number> <Q>uit [N]: ";
$V_COMMAND = <>;
$V_COMMAND = uc trim($V_COMMAND);
# ---------------------------------------------------
# This clears the screen on a Windows machine.
# If running on a Unix machine, a utility with
# the same name will be required for compatibility...
# ---------------------------------------------------
system("cls");
# ---------------------------------------
# Default case is 'go to next section'...
# ---------------------------------------
if($V_COMMAND eq "")
{
$V_COMMAND = "N";
}
# ---------------------------------------
# If it's a number, go to that section...
# ---------------------------------------
if(IsNumber($V_COMMAND))
{
$V_THIS_SECTION = NextHelpSection $P_FILENAME, $V_COMMAND;
}
else
{
# -----------------------------
# Check the command is valid...
# -----------------------------
if((length($V_COMMAND) == 1) && (index("BCNP",
$V_COMMAND) != -1))
{
# ---------------------
# Go to next section...
# ---------------------
if($V_COMMAND eq "N")
{
$V_THIS_SECTION = NextHelpSection $P_FILENAME, $V_THIS_SECTION + 1;
}
# -----------------------
# Does user wish to quit?
# -----------------------
if($V_COMMAND eq "Q")
{
last;
}
# --------------------------------------------------
# Does user wish to go to the beginning of the file?
# --------------------------------------------------
if($V_COMMAND eq "B")
{
$V_THIS_SECTION = NextHelpSection $P_FILENAME, 1;
}
# ---------------------------------------------
# Does user wish to go to the previous section?
# (Obviously can't go back past section 1)
# ---------------------------------------------
if($V_COMMAND eq "P")
{
$V_THIS_SECTION = NextHelpSection $P_FILENAME,
$V_THIS_SECTION == 1 ? 1
: $V_THIS_SECTION - 1;
}
# ---------------------------------------------
# Does user wish to go to the contents section?
# ---------------------------------------------
if($V_COMMAND eq "C")
{
$V_THIS_SECTION = NextHelpSection $P_FILENAME, 2;
}
}
else
{
# --------------------------------------------
# Un-recognised command - stay where we are...
# --------------------------------------------
$V_THIS_SECTION = NextHelpSection $P_FILENAME, $V_THIS_SECTION;
}
}
}
else
{
# ---------------------------------
# Not a control line, so show it...
# ---------------------------------
print $V_SHOW_LINE;
}
}
# ------------------------------------------
# Out of the loop, tidy up before exiting...
# ------------------------------------------
close(H_HELP_FILE);
}
Find out more
by searching Google here...
|