Get Info Demo Program
version 4.0

In version 3, we added the ability to load files, and created a small program to generate
test input files.  Now that we can have enough data that requires some searching, we
will implement the name index we had first prototyped back in version 2.

The collection itself is stored in a ProdPtrList in the same order as they appear in
the input file.  In order to search for a name, we would have to look at each entry.
To make this search more efficient, we will create an alphabetized list.

The routine index_name loops through the ProdPtrList collection and inserts each entry
into the Linked List name_ndx.  The routine insert_name does a sequential search for
the insertion point.  As soon as the new entry is less than the current entry, we
should add the new entry before the current entry.  A special case is if the list
is empty, where we should simply add the entry to the list.  Normally, I would add
it to the head, but the tail works just as well, and if we run off the end of the list
when searching for the insertion point, then we add it to the tail then.  So, rather
than test for if the list is empty so we can add to the head, we just add to the tail
in either case.  Since the first entry is both the head and tail, there is no problem.

For debugging, we add an undocumented option 23 which will list the names from the
alphabetical list.  If you look at the code for list_names, you will see that it
just does a loop through the list and calls display_stuff for each entry.

Once we have the name insertion working, we can build an index so we don't have to
do sequential searches.  We can implement an index by using either a full index or
a partial index.  Normally, you would do one or the other, but we will do both so
you can see how they are done.

To create the full index, we use the ProdAPtrList structure, that has a built-in
binary search method.  The ProdAPtrList doesn't support multiple keys, and we could
have more than one entry with the same name, so we have to allow for that.  We can
build any key that we want, based on fields from the record.  Since we are using an
index to locate names, we want to use the first occurance of a name.  If we were to
use bupdate_aptr_prodlist to see if the entry exists, a later occurance would replace
the previous occurance.  Of course, we could detect when that happened, and do another
update with the one that was deleted, but that would be more complicated.

We wrote a debugging routine to list the full index.  This routine loops through
through the ProdAPtrList and displays all of the keys.  This should list all of the
last names that are stored in the collection.

The partial index is an array of Link structures.  There is one entry for each letter
of the alphabet, plus two other entries: one for anything before the alphabet, and 
one for anything after the alphabet.  Neither of these index entries should ever have
any data associated with them, but just in case.  The entries for the alphabet point
to the first link structure that has a last name starting with that letter.  If no
names starting with a letter, then the currensponding entry will be NULL.

The debugging routine to display partial index entries loops through the array
looking for non-null entries.  If any are found, then the first letter is displayed
and the first entry starting with that letter.  Notice the function get_first_char,
that returns the index for the specified name.  The letter 'A' will return 1, 'B'
will return 2, etc.  If something is less than 'A', it will return zero; if bigger
than 'Z', then it will return 27.
