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...

Google