home *** CD-ROM | disk | FTP | other *** search
/ World of Shareware - Software Farm 2 / wosw_2.zip / wosw_2 / PASCAL / TBTREE16.ZIP / TBTREE16.DOC < prev    next >
Text File  |  1989-07-15  |  85KB  |  1,849 lines

  1.  
  2.     TBTREE16             Copyright (c)  1988,1989  Dean H. Farwell II
  3.  
  4.  
  5.  
  6.  
  7.  
  8.  
  9.  
  10.  
  11.  
  12.  
  13.  
  14.  
  15.  
  16.  
  17.  
  18.  
  19.                                    TBTREE16
  20.  
  21.                           ( Turbo BTree version 1.6 )
  22.  
  23.  
  24.  
  25.        Yet another implementation of BTrees for Turbo Pascal 4.0/5.0/5.5
  26.  
  27.  
  28.                    Copyright (c)  1988,1989    Dean H. Farwell II
  29.  
  30.  
  31.  
  32.  All source code and documentation are considered to be shareware and are
  33.  copyrighted.  The following rules of engagement apply to all documentation and
  34.  code which make up TBTREE16:
  35.  
  36.  All users can and are encouraged to distribute this software freely. This
  37.  includes the uploading of this software onto applicable Bulletin Boards etc.
  38.  The entire TBTREE16 product must be distributed as a complete product.  Pieces
  39.  can not be distributed individually.  The documentation must be distributed
  40.  with the source code.  No copyright statements may be modified.
  41.  
  42.  All users can and are encouraged to use these utilities to develop and/or
  43.  enhance their private, shareware, or commercial software applications.
  44.  
  45.  All users are encouraged to suggest enhancements, make suggestions and
  46.  generally lead to the development of a better product to the benefit of all.
  47.  Users may change the code and documentation as desired for their own use but
  48.  may not then distribute those changes.
  49.  
  50.  Users may distribute these routines as part of another SHAREWARE package.  For
  51.  instance, a user could develop a DBMS using this as a basis and can freely
  52.  distribute the source code provided that:
  53.  
  54.       1.  None of this documentation or code is changed
  55.       2.  ALL code and documentation is distributed (not just parts)
  56.       3.  The user is not selling or distributing this for profit
  57.       4.  The user be registered.
  58.  
  59.  The restriction that the code and documentation not be changed is to ensure
  60.  that I can maintain some control over version releases.  I do not want several
  61.  versions running around that I had nothing to do with.
  62.  
  63.  
  64.                                         1
  65.  
  66.  
  67.  
  68.     TBTREE16             Copyright (c)  1988,1989  Dean H. Farwell II
  69.  
  70.  
  71.  The bottom line is that you can not sell this or distribute it for profit
  72.  (except for a small fee not to exceed $10 to cover cost of mailing,
  73.  duplication and handling).  A user developing a commercial application can not
  74.  distribute the SOURCE code or documentation but a user can use these routines
  75.  to compile a commercial application.
  76.  
  77.  Users are encouraged to register their copy of this software.  The
  78.  registration fee is a very nominal $25.  You may be aware that this is an
  79.  increase in my earlier $15 fee.  The justification I use is that the product
  80.  has greatly matured and I honestly believe that you are getting a good bang
  81.  for the buck.  Also, for the $25 you will get all future upgrades mailed FREE.
  82.  I am no longer charging a $5 shipping and handling fee for each upgrade.
  83.  
  84.  Anyone using this software to develop a commercial application must register
  85.  and state their intentions to use it in a commercial application.  I will not
  86.  charge royalties (except for the registration fee).  I just want to know what
  87.  people are doing with it.  Also, if someone is distributing it as part of a
  88.  shareware product, the same restrictions apply.
  89.  
  90.  Most of all I want any feedback that you have the time and desire to submit.
  91.  Suggestions, complaints, etc. are welcome.  I especially want feedback on
  92.  errors.  I do not know of any bugs (or I'd fix them) but I probably missed an
  93.  item or two.  Send me notice immediately so that I can distribute a fix if
  94.  required.  Since you have the source code, do your best to isolate the
  95.  problem.  I'll try to take it from there.
  96.  
  97.  To reach me use CompuServe ID - 73240,3335 or drop me a line at:
  98.  
  99.                              P.O. Box 4731
  100.                              San Bernardino, CA 92409
  101.  
  102.                              (zip code is essential!!!!!)
  103.  
  104.  My phone number is:
  105.  
  106.                                  714-887-9847
  107.  
  108.  For hopefully obvious reasons, I will not accept collect calls. Otherwise,
  109.  feel free to call as I enjoy hearing from users.
  110.  
  111.  As a final motivation to register, all registered users will receive future
  112.  upgrades free (via mail - no postage due or anything!).  I will normally mail
  113.  these well before I put the version out on CompuServe or anywhere else.  The
  114.  registered users will, in effect, become beta testers to make sure that all is
  115.  well before I release to the world.  By registering you will ensure that you
  116.  always have the latest version and is probably less than the cost to download
  117.  off of a bulletin board.  I will do my best to not release trivial changes but
  118.  only significant upgrades.
  119.  
  120.  Liability:
  121.  
  122.  This software is not warranted.  There are no warranties expressed or implied
  123.  as to the quality, correctness, or applicability of this software.  The author
  124.  is not responsible for any loss or damages due to the use of any software or
  125.  documentation distributed as TBTREE16.
  126.  
  127.  
  128.  
  129.  
  130.                                         2
  131.  
  132.  
  133.  
  134.     TBTREE16             Copyright (c)  1988,1989  Dean H. Farwell II
  135.  
  136.  
  137.                               Product Description
  138.  
  139.  TBTREE16 is version 1.6 of a shareware btree and database product for use with
  140.  Turbo Pascal 4.0, Turbo Pascal 5.0 and Turbo Pascal 5.5.  It is intended to
  141.  give a user the capabilities to develop pascal applications for the creation
  142.  and manipulation of databases.  This product is extremely powerful and FAST!!!
  143.  However, it is not the easiest thing to get a grasp on.  If you understand the
  144.  concept of btrees or at least indexing then this will not be complicated to
  145.  use.  I can just about guarantee that it is the best product of its type for
  146.  the money and maybe the best period.  If you have any feedback on how I can
  147.  take the mystery out of using this please let me know.  I also solicit any
  148.  feedback which will enhance the quality of the product.
  149.  
  150.  I am presently working on a second product (albeit at a much more leisurely
  151.  pace than I had anticipated) which will be called TBASE and will use these
  152.  routines as the database engine but will have a much easier to understand
  153.  interface for code developers. It will use SQL like calls instead of those
  154.  used in this product.  All registered users of TBTREE16 will be shipped a beta
  155.  version of TBASE as soon as one becomes available and will get the first whack
  156.  at using it.  This in itself is worth the $25.
  157.  
  158.  Although this product provides many of the same general database capabilities
  159.  as Borland's Turbo Pascal Database Toolbox it is not intended to be
  160.  compatible.  There are several reasons for this.  First, I do not want to
  161.  create any impression of any type of copyright infringement.  Secondly, I
  162.  needed to implement things differently than they were implemented in Borland's
  163.  product to be able to do the enhancements I am planning.  Thirdly, I wanted to
  164.  implement things that Borland does not.  For instance, I support data types in
  165.  my indexes.  Other differences will be more apparent as you read through this
  166.  documentation.  Lastly, I did not have a copy of Borland's product when I was
  167.  doing this.  This really started out as more of an academic exercise than
  168.  something that I was going to release for others.  This turned out to be a
  169.  more extensive job than I thought (big surprise there, huh?).  I figured that
  170.  I might as well make it available for others.
  171.  
  172.  This product has been greatly enhanced since version 1.0 was released. As it
  173.  presently stands, it has the following features:
  174.  
  175.  1. The ability to create data files and indexes for those files.
  176.  
  177.  2. Any number of indexes can be used for a single data file.
  178.  
  179.  3. Any number of data files can be used.
  180.  
  181.  4. All data files and index files use a virtual memory scheme in which the
  182.     most recently used pages are kept in memory using the heap.  This is
  183.     different than many other implementations which use a buffer or stack only
  184.     for index pages.  The buffer is shared by all files.  In this way separate
  185.     space does not need to be set aside for different files.  Space utilization
  186.     is maximized and performance is enhanced.
  187.  
  188.  5. All management of pages in memory is automatically controlled although the
  189.     user can exercise limited control if desired.
  190.  
  191.  6. Routines are provided to dump the page buffer to the printer to facilitate
  192.     viewing pages if a user is curious or masochistic.
  193.  
  194.  7. The size of the buffer is determined by the user and can be changed
  195.  
  196.                                         3
  197.  
  198.  
  199.  
  200.     TBTREE16             Copyright (c)  1988,1989  Dean H. Farwell II
  201.  
  202.  
  203.     dynamically as the program runs.  For example a 128K buffer could be used
  204.     initially.  If a user had a large heap requirement the buffer size could be
  205.     reduced.  The buffer size could later be increased if desired.  This can
  206.     all be done while the application is running.
  207.  
  208.  8. Problems related to keeping track of numbers of open files are alleviated.
  209.     The user initially specifies the maximum number of files allowed to be open
  210.     at once and never has to address it again.  Routines are provided to manage
  211.     the opening and closing of files dynamically.  This increases performance
  212.     because files do not have to be continually opened and closed
  213.     unnecessarily.
  214.  
  215.  9. All data types supported by Turbo Pascal are explicitly supported. In other
  216.     words, values do not have to be converted to strings.  This is a great
  217.     improvement over previous systems (MY UNBIASED OPINION). For example an
  218.     index can be set up for type Byte, another for type ShortInt, another of
  219.     type String and even for type Real (but wait you say .. Reals in an
  220.     index?).  See next note!
  221.  
  222.  10. Indexes can be searched for equality, inequality, greater than, greater
  223.      than or equal to, less than, less than or equal to, and existence.  In
  224.      other words you can ask for a list of all records for which some field of
  225.      type real is LE (less than or equal to) XXX where XXX is a var of type
  226.      real and XXX := 3.141592 etc.  An index can also searched on a range of
  227.      values.  For instance an index of type byte can be checked for a range >=
  228.      10 and < 20 etc.  Indexes containing strings can be searched for partial
  229.      string matches.  Partial string matches can be done three ways: find a
  230.      string which is at the beginning of a string, anywhere in the string, or
  231.      at the end of a string.
  232.  
  233.  11.  As physical records are deleted space is reused automatically on future
  234.       inserts.  Files should never have to be reorganized to recover space
  235.       (unless a large number of deletes were performed without any inserts and
  236.       even in this case there is not really a good reason to reorganize unless
  237.       your disk is filling up).
  238.  
  239.  12.  Included with the package is a very crude but effective source code
  240.       printing routine which can be used to dump the code in a more usable
  241.       format.  Specifically, it handles page breaks and prints a header of
  242.       useful information.  It will also only print out the interface section if
  243.       you instruct it to do so.
  244.  
  245.  13.  The user does not need to perform any calculations or make any estimates
  246.       prior to data file or index creation.
  247.  
  248.  14.  Code was designed using an Object Oriented Design approach to a large
  249.       extent (Turbo 4.0 and Turbo 5.0 lend themselves to this approach much
  250.       more than Turbo Pascal 3.0 did).  This is one reason that there are so
  251.       many units.  Much of the code is reusable for other applications.
  252.  
  253.  15.  Sorts can be accomplished using any number of fields in any order of
  254.       precedence as determined by you.  A Quicksort algorithm is used to give
  255.       high performance.  Sort fields can be any type supported (Byte, Real,
  256.       Integer, String etc.).
  257.  
  258.  16.  Added the following set operations: Union, Intersection and Difference.
  259.       These allow easy queries on multiple fields.  For example, retrieving all
  260.       personnel who have a last name starting with 'N' and who's job is
  261.  
  262.                                         4
  263.  
  264.  
  265.  
  266.     TBTREE16             Copyright (c)  1988,1989  Dean H. Farwell II
  267.  
  268.  
  269.       'MANAGER', etc. is greatly simplified.  This enhancement is a definite
  270.       plus and not available in many other products.
  271.  
  272.  17.  Error handling added for trapping I/O errors
  273.  
  274.  18.  Capability to handle files with fixed size records and files with
  275.       variable sized records
  276.  
  277.                                  List Of Files
  278.  
  279.  The following files are provided as part of the TBTREE16 product:
  280.  
  281.       Units - Source Code For All Units
  282.  
  283.            BTREE.PAS - This unit contains the interface and implementation for
  284.            the btrees themselves.  Although the implementation is fairly
  285.            complex, only a few routines are visible to the user and give the
  286.            user all the functionality required.  The actual working of the
  287.            btree unit itself is not critical to the user.  The user is provided
  288.            with routines to add an entry to an index, delete one entry from an
  289.            index, delete all entries with a matching key value from an index
  290.            and retrieve record numbers which match some selection criterion.
  291.            The ability to create an index is also provided.  To delete an index
  292.            just delete the file using a routine provided in BTREE.PAS.  The
  293.            BTREE unit is different than any other unit in the product in that
  294.            it consists of not one but four source files.  See entry for
  295.            BTREE1.INC, BTREE2.INC and BTREE3.INC.
  296.  
  297.            BTREE1.INC, BTREE2.INC and BTREE3.INC - These are additional source
  298.            files needed for the BTREE unit.  I split up the source code for the
  299.            unit because the source code ended up greater than 64K bytes.  The
  300.            three additional files are include files and will automatically be
  301.            compiled when BTREE.PAS is compiled.
  302.  
  303.            BYTEDATA.PAS - This unit was added to version 1.4 for use with a
  304.            future product.  It can be used to create concatenated indexes,
  305.            although I am still working on the specifics.
  306.  
  307.            COMPARE.PAS - This unit contains no inherent object although a
  308.            couple of types are declared and put in the interface.  It is made
  309.            of several routines which give the capability of comparing two
  310.            values of the same type or searching for a substring within a
  311.            string. This routine alleviates the need for the user to develop a
  312.            routine which can be used for comparisons. All Turbo Pascal 4.0
  313.            scaler types are handled.  Strings and ByteArrays are the only
  314.            structured (composite) types handled.  Several routines are used to
  315.            handle partial string searches.
  316.  
  317.            FILEBUFF.PAS - This unit contains the interface and implementation
  318.            for a files open list.  This list will contain information on all
  319.            files opened (using this unit). A user can specify how many files
  320.            can be on the list at once (how many the unit can allow to be open).
  321.            The unit takes it from there.  From then on all requests to use a
  322.            file must be preceded by a call to the unit.  The unit will
  323.            determine if the file is open and will open it if it is not. The
  324.            routine is exceptionally useful for alleviating the need to open and
  325.            close files for every operation.  Continually opening and closing
  326.            files causes unacceptable performance problems. The file types
  327.  
  328.                                         5
  329.  
  330.  
  331.  
  332.     TBTREE16             Copyright (c)  1988,1989  Dean H. Farwell II
  333.  
  334.  
  335.            handled are only Untyped files and Text files. Typed files are not
  336.            currently handled.  This is due to the fact that strong type
  337.            checking precludes the use of typed files (or at least I couldn't
  338.            break the code and figure out how to make it work.  If anyone can
  339.            figure out how to make it work, it would make this even more
  340.            useful).
  341.  
  342.            FILEDECS.PAS - This unit is nothing more than a collection of
  343.            declarations required to support several of the other units.  There
  344.            is no code in the implementation section.
  345.  
  346.            FILES.PAS - This unit contains the interface and implementation for
  347.            the manipulation of files.  This fulfills the role of file manager
  348.            (mid level management of files as opposed to the low level
  349.            management found in FILEBUFF.PAS). It is the place where files are
  350.            created, deleted and where the existence of a file is checked.  Most
  351.            of the routines are for internal use only.  There are several
  352.            exceptions, however.  See the unit documentation for details.
  353.  
  354.            HEX.PAS - This unit contains the interface and implementation for
  355.            dealing with a hex array which is a 2 byte array used for storing a
  356.            hex character (such as 7F).  A couple of routines are provided for
  357.            converting bytes and bits to hex array representations.  It is
  358.            intended for internal use, but may prove useful for your specific
  359.            application, as well.
  360.  
  361.            LOGICAL.PAS - This unit contains the interface and implementation
  362.            for dealing with logical (data) files and records.  It also handles
  363.            the conversion between logical and physical records.  In TBTREE16
  364.            all physical records (records stored on disk) are the same size (512
  365.            bytes).  This is how all files can share the same page buffer (See
  366.            PAGE.PAS).  However, the logical records (data records in the data
  367.            files) can be any size from one byte up to 65520 (although they will
  368.            not be that large in practice).  This unit takes the user's data
  369.            records stored in a variable and puts them in the number of physical
  370.            records required. It also takes the appropriate data from physical
  371.            record(s) and puts it in the variable of the users choice.  A great
  372.            deal of flexibility is available here.  One caution however!
  373.            This unit only handles FIXED LENGTH LOGICAL RECORDS.  All data
  374.            records (within one data file) must be of the same size (obviously
  375.            each data file can have a different logical record size). If
  376.            variable length data is required then the size of the logical record
  377.            is the largest number of bytes required as determined by the user.
  378.            A good example of this is a record containing a string declared as
  379.            String[20].  The logical record size is 21 bytes (one byte for the
  380.            length). 21 bytes should be stored and retrieved even though a
  381.            string such as 'howdy' is stored (howdy uses 6 bytes). Most products
  382.            of this nature work in the same way.  This unit handles the creation
  383.            and deletion of data files as well.  See unit for details.  See also
  384.            the VLOGICAL unit information below.  VLOGICAL is the other unit
  385.            which handles data records.  It is an alternative to this unit and
  386.            is designed specifically for records of varying size.
  387.  
  388.            LRECLIST.PAS - This unit contains the interface and implementation
  389.            to handle logical record lists.  A logical record list is a concept
  390.            which is different than you will find in most other implementations
  391.            of btrees.  When a query is done on an index, most btrees set a
  392.            cursor to the node where the first matching value is found
  393.  
  394.                                         6
  395.  
  396.  
  397.  
  398.     TBTREE16             Copyright (c)  1988,1989  Dean H. Farwell II
  399.  
  400.  
  401.            (equality).  This is very efficient but does not lead to the
  402.            flexibility of my system.  TBTREE16 builds a list of logical record
  403.            numbers corresponding to the logical records which meet the criteria
  404.            of the query.  TBTREE16 can handle all boolean operations such as
  405.            equality, inequality, greater than, greater than or equal to, etc.
  406.            Therefore, you can get a list of all logical records which meet some
  407.            criteria and deal with that list independently of the btree.  Once
  408.            you have the list you can compare it to other lists and do
  409.            intersections, unions, joins, etc.  This gives you some of the power
  410.            of a real database management system.  You can relate a file to
  411.            itself or to other files.  This system is the basis of my future
  412.            work to bring true relational capabilities to programs written in
  413.            Turbo Pascal. It gives the capability to do set at a time
  414.            processing.  Unfortunately, nothing is free.  A query on a database
  415.            of 10000 logical records on existence will give a list of 10000
  416.            logical records numbers (40000 bytes required to store the list).
  417.            Lists like this take time to build.  A fact of life is that it takes
  418.            time to process a lot of data in a large database. The user is
  419.            cautioned to structure queries in such a way that lists are not
  420.            huge.  Queries on equality are not normally a problem (unless the
  421.            index provides little selectivity).  Queries on inequality will be
  422.            faster if a range is used.  No matter what type of query is used,
  423.            the page buffer alleviates a great deal of performance problems.  An
  424.            alternative to using these logical record lists can be found in
  425.            BTREE3.INC.
  426.  
  427.            MATH.PAS - This unit contains the interface and implementation to
  428.            manipulate bytes at the bit level.  Only two routines are visible as
  429.            that is all that is required in TBTREE16.  This unit has been redone
  430.            in assembly language to enhance performance.  See the source listing
  431.            for further details.
  432.  
  433.            MYPRINT.PAS - This routine is a collection of printer codes and
  434.            routines to print the codes.  This is sufficient for my purposes and
  435.            is included only because I needed a couple of routines for
  436.            TP4PRINT.PAS and PAGE.PAS.  This unit is not very elegant and will
  437.            need to be modified if it does not support your printer.
  438.  
  439.            NUMBERS.PAS - This unit contains no code in the implementation. It
  440.            is simply a repository for often used types which are not part of
  441.            the original Turbo Pascal product.
  442.  
  443.            PAGE.PAS - This unit contains the interface and implementation to
  444.            manipulate the page buffer.  The page buffer is stored internally
  445.            on the heap and is used to temporarily hold physical records.  The
  446.            buffer greatly enhances up the performance of the product.  As the
  447.            program runs, physical records are created or are read in from disk.
  448.            As this happens, they are stored in the buffer.  Therefore, the
  449.            buffer grows and shrinks as the demand for pages grows.  You can set
  450.            the maximum size of the buffer.  By doing this, you can ensure that
  451.            the buffer does not eat up all of the heap and leave nothing for you
  452.            own needs.  To function the buffer can be set to as small as one
  453.            page (512 bytes).  However, performance is going to be dismal.  The
  454.            amount of buffer space to allocate is dependent on many factors and
  455.            the size needs to be played with to see what works best.  One rule
  456.            stands though .. bigger is better!  One interesting note - routines
  457.            are provided to change the size (both increase and decrease)
  458.            dynamically as often as desired.  There are other routines available
  459.  
  460.                                         7
  461.  
  462.  
  463.  
  464.     TBTREE16             Copyright (c)  1988,1989  Dean H. Farwell II
  465.  
  466.  
  467.            as well.  For example, a routine is provided to allow the user to
  468.            force a page to be written to disk immediately when it is changed
  469.            (stored in the buffer) as opposed to waiting until it gets swapped
  470.            out or all pages are written to disk. Immediately writing to disk
  471.            ensures that nothing gets lost on a system or program crash but it
  472.            has severe performance implications.  Use of this is not normally
  473.            required, but the option is there and usable.
  474.  
  475.            SETOPS.PAS - This unit contains routines that support set
  476.            operations.  They facilitate queries using multiple fields from one
  477.            data file.  This greatly reduces the workload on the programmer.
  478.  
  479.            SORT.PAS - This unit contains three procedures for sorting.  This
  480.            unit was was created in version 1.2 and completely reworked in
  481.            version 1.5.  It uses a quicksort algorithm to provide good
  482.            performance.  Just as importantly, it supports all data types
  483.            supported by TBTREE16 and is extremely easy to use.
  484.  
  485.            STRINGS.PAS - This unit contains routines to manipulate strings.
  486.            They are for internal use, but may prove useful for your specific
  487.            applications, as well.
  488.  
  489.            TIME.PAS - This unit contains the implementation and interface to
  490.            manipulate a time counter which will keep track of a sequence of
  491.            events.  It is really intended for internal use only, although you
  492.            can use it if you find a need.
  493.  
  494.            VLOGICAL.PAS - This unit is much the same as the LOGICAL unit except
  495.            that it is designed to handle variable length record files.  In
  496.            other words, each record can have a different number of bytes
  497.            associated with it.
  498.  
  499.       Programs - Source Code For All Programs
  500.  
  501.            TP4PRINT.PAS - This program is provided merely to permit my source
  502.            code to be printed out in a better format than provided by the DOS
  503.            Print command.  It looks for page control codes embedded in my
  504.            source (my control codes are comments to the compiler) and controls
  505.            paging.  It puts a header which includes file name, page, print time
  506.            and file creation time.  It provides top and bottom margins as well.
  507.            Give it a try by printing out one of the source code files to see if
  508.            you want to use it or another source code printer. Syntax is :
  509.  
  510.                  TP4PRINT  filename   where filename includes path if source is
  511.                  not in the current directory
  512.  
  513.            After the file name, a an optional parameter can be used. Only a
  514.            small i or capital I will be recognized.  If this is present, only
  515.            the opening comments and the entire interface section will be
  516.            printed.  The implementation section will not be printed.  This
  517.            allows you to look at what you need without printing out everything.
  518.            An example of this follows:
  519.  
  520.                          TP4Print   logical.pas I
  521.  
  522.  
  523.            IFACE.BAT - A batch file which will print out the comments and
  524.            interface section of every unit in TBTREE16.  This is the easiest
  525.  
  526.                                         8
  527.  
  528.  
  529.  
  530.     TBTREE16             Copyright (c)  1988,1989  Dean H. Farwell II
  531.  
  532.  
  533.            way to print out what you need from the code without printing out
  534.            stuff you probably don't need (implementation sections).  One word
  535.            of warning though, over 80 pages will be printed.  Of course, you
  536.            can go in an modify the batch file to only print the ones you want.
  537.  
  538.            BUILDTPU.PAS - When this program is compiled, all units associated
  539.            with TBTREE16 will also be compiled. This simply provides a
  540.            convenient way to build all the units at once without compiling them
  541.            individually.
  542.  
  543.            EXAM0.PAS - This is really a unit that is used a global section for
  544.            the other examples.  It contains the record declaration for the test
  545.            record used for all examples.
  546.  
  547.                      EXAM1.PAS thru EXAM3.PAS and EXAM5.PAS thru EXAM11.PAS
  548.                      demonstrate the capabilities of TBTREE16 to handle fixed
  549.                      length data records
  550.  
  551.                      EXAM4.PAS has nothing to do with data records and is
  552.                      explained below
  553.  
  554.                      EXAM51.PAS thru EXAM54.PAS demonstrate the capabilities of
  555.                      TBTREE16 to handle variable length records
  556.  
  557.            EXAM1.PAS - This example program demonstrates how to create a data
  558.            file and a couple of indexes.  It then demonstrates how to insert
  559.            data into the data file and the indexes. Several other routines are
  560.            demonstrated as well.  Important to note is that this program has
  561.            been changed from version 1.2 and prior.  It now uses
  562.            StoreNewLogicalRecord to store the record as opposed to using
  563.            StoreALocicalRecord.  Look at the source and this may make sense.
  564.  
  565.            EXAM2.PAS - This program shows how to perform retrievals using both
  566.            the logical record lists and the internal cursor.  The files created
  567.            in EXAM1.PAS are used.
  568.  
  569.            EXAM3.PAS - This program shows how to do deletes and updates.  The
  570.            files created in EXAM1.PAS are used.
  571.  
  572.            EXAM4.PAS - This program shows how to use routines in FILEBUFF.PAS
  573.            with text files.
  574.  
  575.            EXAM5.PAS - This program shows how to use the retrieval on range
  576.            routine.  The files created in EXAM1.PAS are used.
  577.  
  578.            EXAM6.PAS - This program shows how to use the retrieval on partial
  579.            string match routine.  The files created in EXAM1.PAS are used.
  580.  
  581.            EXAM7.PAS - This program shows how to build/rebuild indexes from an
  582.            existing data file.  The files created in EXAM1.PAS are used.
  583.  
  584.            EXAM8.PAS - This program shows use of routines to delete entries
  585.            from a logical records list.  The files created in EXAM1.PAS are
  586.            used.
  587.  
  588.            EXAM9.PAS - This program shows an example of sorting using the SORT
  589.            unit.   The files created in EXAM1.PAS are used.
  590.  
  591.  
  592.                                         9
  593.  
  594.  
  595.  
  596.     TBTREE16             Copyright (c)  1988,1989  Dean H. Farwell II
  597.  
  598.  
  599.            EXAM10.PAS - This program shows an example of using one of the set
  600.            operations found in the SETOPS unit.  The files created in EXAM1.PAS
  601.            are used.
  602.  
  603.            EXAM11.PAS - This program shows an example of the use of the
  604.            internal cursor.  Of note is the fact that the cursor keeps track of
  605.            its position in the index even after inserts and deletes have been
  606.            done in the index.  The files created in EXAM1.PAS are used.
  607.  
  608.            EXAM51.PAS - This routine is the direct counterpart to EXAM1.PAS
  609.            except that it creates variable length records.
  610.  
  611.            EXAM52.PAS - This shows how to do retrievals using the variable
  612.            length records.  Notice that the use of indexes is the same as in
  613.            EXAM2.PAS.  I did not use the cursor in this example, but they work
  614.            the same as in EXAM2.PAS.
  615.  
  616.            EXAM53.PAS - This is an example of doing a delete using variable
  617.            length records.  Notice that it is not really very fast.  I am
  618.            working on improving the speed of deletes for variable length
  619.            records.
  620.  
  621.            EXAM54.PAS - This is a direct counterpart to EXAM9.PAS except that
  622.            it sorts variable length records.
  623.  
  624.  
  625.  
  626.  
  627.  
  628.  
  629.  
  630.  
  631.  
  632.  
  633.  
  634.  
  635.  
  636.  
  637.  
  638.  
  639.  
  640.  
  641.  
  642.  
  643.  
  644.  
  645.  
  646.  
  647.  
  648.  
  649.  
  650.  
  651.  
  652.  
  653.  
  654.  
  655.  
  656.  
  657.  
  658.                                         10
  659.  
  660.  
  661.  
  662.     TBTREE16             Copyright (c)  1988,1989  Dean H. Farwell II
  663.  
  664.  
  665.                        Instructions For Use of TBTREE16
  666.  
  667.  The only way to truly understand how TBTREE works is to look through the
  668.  Interface sections of the various units.  As noted above, I have supplied a
  669.  batch file which can be used to print all of the Interface sections at once.
  670.  The first two units to try to figure out are the LOGICAL unit and the BTREE
  671.  unit.  These really are the heart of TBTREE16.  Then look over the PAGE unit
  672.  (concentrate on the few routines which are used to set parameters such as
  673.  buffer size etc.  Also try to understand the buffer and why it is important to
  674.  TBTREE16.  Then glance over the FILEDECS unit.  You will need to use a couple of the
  675.  routines in the FILEBUFF unit as well.  Once you grasp these units, you are
  676.  well on your way to understanding TBTREE16.  The following provides a short
  677.  set of instructions for performing the more common database type operations
  678.  using TBTREE16.  The Quick Reference guide, which is provided in a separate
  679.  file, will also prove helpful.
  680.  
  681.       Uses Statements - All of the units were compiled with the appropriate
  682.       uses statement included.  Therefore, the user does not need to be
  683.       concerned about order when specifying units in the uses statements in the
  684.       user's programs.  As you can see in my examples, I put the units in
  685.       alphabetical order.  The user only needs to put the units which have
  686.       type statements and/or routine calls which must be visible within the
  687.       user's program.  My example programs demonstrate which ones are probably
  688.       required.  One method which actually works is to not include any
  689.       initially and let the compiler find the syntax errors.  When an error is
  690.       found because a type or routine is not found then see which unit it's in
  691.       and put that unit in the uses statement.  It's not a great way to do it,
  692.       but it works.
  693.  
  694.       Setting Initial Parameters - Several parameters should be set by the user
  695.       although they have defaults if a value is not set by the user.  All of
  696.       the parameters are only accessible by calling routines supplied to check
  697.       and set values.  The variables themselves are not global, so they are not
  698.       visible to the user. The following parameters can be set by the user:
  699.  
  700.            Open Files Allowed - Contained in FILEBUFF.PAS.  Determines number
  701.            of open files allowed exclusively for use within TBTREE16.  TBTREE16
  702.            will never have more that this number of files open at a time.
  703.            However, if TBTREE16 needs to deal with more files than this, it
  704.            will open and close its files and function properly.  See
  705.            FILEBUFF.PAS for details.  To set the parameter to a value of 5 do
  706.            the following:
  707.  
  708.                 SetMaxOpenFiles(5);
  709.  
  710.            Maximum Buffer Pages Allowed - Contained in PAGE.PAS.  Determines
  711.            the maximum number of 512 byte pages to keep in memory at one time.
  712.            Set this to something that makes sense for your machine (memory size
  713.            available).  Since this is set at run time, you can set this after
  714.            you determine how much memory is available.  You can reset this at
  715.            any time to a higher or lower value, and it will handle it properly.
  716.            To set this parameter to 50 pages (25K bytes) use the following:
  717.  
  718.                 SetMaxBufferPages(50);
  719.  
  720.            One note is that the buffer is initialized to 128K bytes which may
  721.            be too large for your application.  You should reset the default to
  722.            whatever you want.
  723.  
  724.                                         11
  725.  
  726.  
  727.  
  728.     TBTREE16             Copyright (c)  1988,1989  Dean H. Farwell II
  729.  
  730.  
  731.  
  732.            Immediate Disk Write - This parameter if set to TRUE will force a
  733.            write of a page to disk immediately after it is stored in the page
  734.            buffer.  Otherwise, the page will only be written when it gets
  735.            swapped out or is explicitly forced out by the user (all pages for a
  736.            file or all pages).  To set this value to TRUE use:
  737.  
  738.                 SetImmediateDiskWrite(TRUE);
  739.  
  740.       Creating Data Files - One of the first things we would want to do is
  741.       create data files to hold our data.  This is extremely simple.  We only
  742.       need to make one call for each data file.  The following statements would
  743.       create a data file with fixed length records (LOGICAL unit).  Using the
  744.       VLOGICAL unit is very similar.
  745.  
  746.       type
  747.           MyRecord = record
  748.                      field1 : Byte;       (* for this example this
  749.                                              is the only field
  750.                                              indexed (Index1) although
  751.                                              you could index all fields
  752.                                              if desired.             *)
  753.                      field2 : Word;
  754.                      field3 : String[10];
  755.                      end;
  756.  
  757.            var
  758.                xxx : FnString;   (* holds name of data file *)
  759.  
  760.            begin
  761.            xxx := 'MYFILE';                       (* name of file *)
  762.            CreateDataFile(xxx,SizeOf(MyRecord));  (* create the file *)
  763.            end;
  764.  
  765.       Notice that the xxx is not a file type but an 80 character string type
  766.       which holds the name of the file including path (if desired).
  767.  
  768.       Creating Index Files - The next step is to create one or more index files
  769.       for each data file.  You will not normally have a data file with no
  770.       indexes (although for small files, you may want to).  To create an index
  771.       file the user must know the type and size of the key (item to be stored
  772.       in the index).  The following statements will create an index file for
  773.       the data file created above.  The index will hold Byte values (values
  774.       from 0 - 255).
  775.  
  776.            var
  777.                yyy : FnString;
  778.  
  779.            begin
  780.            yyy := 'Index1';
  781.            CreateIndexFile(yyy,SizeOf(Byte),BYTEVALUE);
  782.            end;
  783.  
  784.       Notice use of the SizeOf routine to pass in the size of the item to be
  785.       stored in the index.  This is usually more accurate than passing in a
  786.       constant value.  This will especially help avoid errors when using
  787.       strings.  Remember, strings use one extra byte for the length.
  788.  
  789.  
  790.                                         12
  791.  
  792.  
  793.  
  794.     TBTREE16             Copyright (c)  1988,1989  Dean H. Farwell II
  795.  
  796.  
  797.       Inserting Data - Once files and indexes exist we can insert data.
  798.       Inserting data consists of two separate steps.  The first step is to
  799.       insert the data into the data file.  The second step is to insert the
  800.       applicable data into each index which is associated with that data file.
  801.       To insert data we first need to have the data record stored in memory
  802.       somewhere.  The most logical place to have the data record is in a
  803.       variable which is of type record of some kind.  For example, the
  804.       declaration of a data record (MyRecord) as defined above will suffice.
  805.  
  806.       var
  807.           thisRec : MyRecord;
  808.           lrNum : LrNumber;
  809.  
  810.       We could use the following sequence to insert a record in the data file
  811.       and the index associated with this data file:
  812.  
  813.            thisRec.field1 := 20;
  814.            thisRec.field2 := 60000;
  815.            thisRec.field3 := 'Hi Mom';
  816.  
  817.            lrNum := StoreNewLogicalRecord(xxx,thisRec);
  818.  
  819.            InsertValueInBTree(yyy,lrNum,thisRec.field1);
  820.  
  821.       Notice that StoreNewLogicalRecord was used because it will find an unused
  822.       logical record number and assign it to this new record. This logical
  823.       record number is the one inserted (along with the associated value) into
  824.       the BTree.  This is a change from versions prior to version 1.3.  This
  825.       simplifies things and makes storing much more straightforward. Hopefully,
  826.       it is obvious that data records are not stored sequentially or in any
  827.       other ordered manner.  In other words, there is not a relationship
  828.       between logical record 1 and logical record 2.  To ensure order, you can
  829.       either retrieve using the indexes or create a logical record list and
  830.       sort it.
  831.  
  832.       Retrieving Data - Retrieving consists of getting the data for one or more
  833.       logical records from a data file.  To determine which logical records are
  834.       needed, one or more indexes are normally used.  TBTREE supports two
  835.       different methods for performing a retrieval using an index.  The first
  836.       and most powerful is to build a logical record list and the traverse that
  837.       list.  Routines to do the retrieval are found in the file BTREE2.INC
  838.       (part of the BTREE unit).  The routines to traverse the list are found in
  839.       the FILEBUFF unit.  The second method is to use a cursor which is built
  840.       into each index. This method is more traditional and has the advantage of
  841.       being dynamic but is not as powerful/flexible.  Saying that the second
  842.       method is dynamic refers to the fact that as index entries are inserted
  843.       and deleted, the cursor continues to point to the same entry, unless that
  844.       entry is deleted.  The routines to support this type of retrieval are
  845.       found in the BTREE3.INC file.  Both methods are discussed further below:
  846.  
  847.       Method 1 - Using the logical record lists - Retrieving data consists of
  848.       making a query to an index. The query is a procedure call which will
  849.       build and return a list of logical records which match the selection
  850.       criteria.  The query conditions are defined in NUMBERS.PAS and are of
  851.       type Condition. Once the list is retrieved, the user can step through the
  852.       list starting at either end and going in either direction.  The logical
  853.       record numbers are stored in the index in such a way that their
  854.       corresponding key values (values in the index) are in ascending order.  A
  855.  
  856.                                         13
  857.  
  858.  
  859.  
  860.     TBTREE16             Copyright (c)  1988,1989  Dean H. Farwell II
  861.  
  862.  
  863.       logical record list created using an index will reflect this order.  If
  864.       there are multiple occurrences of the same key then the last one added is
  865.       in the front.  The list can be traversed front to back (ascending) or
  866.       back to front (descending).  A cursor is kept internally in the list (not
  867.       to be confused with the cursor used in the other method) to keep track of
  868.       where the user is in the list.  The user can not get to the cursor but
  869.       can set it to the front or back and move it forward or backward (by
  870.       retrieving values from the list).  Normally, to traverse the list, set
  871.       the cursor to the front of the list and then set up a loop which will
  872.       traverse the list and terminate when a logical record number of 0 is
  873.       returned.  The list is not disturbed as you move through it. It will
  874.       exist until you destroy it or until the program ends. If the program ends
  875.       before the list is destroyed explicitly by the user then there may or may
  876.       not be a file on disk with an extension of '.lrl'.  If you terminate and
  877.       find any of this type of file laying around then you did not destroy it
  878.       prior to ending the program (shame on you).  You should fix this since
  879.       leaving a list hanging around just takes up space and does nothing
  880.       productive.  If you find files with this extension ('lrl') hanging around
  881.       after your program terminates, you can delete them.  An example of a data
  882.       retrieval follows:
  883.  
  884.            var
  885.                key : Byte;
  886.                lrLst : LrList;
  887.                lrNum : LRNumber;
  888.  
  889.            begin
  890.            key := 20;
  891.            GetValuesFromBTree(yyy,key,LE,lrLst);  (* retrieve all record
  892.                                                      numbers for records
  893.                                                      having an index entry less
  894.                                                      than or equal to 20.     *)
  895.  
  896.            (* lrLst is the newly created list *)
  897.            lrNum := GetFirstLr(lrLst);       (* set cursor to front *)
  898.            while lrNum <> 0 do                    (* traversal loop *)
  899.                begin
  900.                GetALogicalRecord(xxx,lrNum,thisRec,);
  901.                (* we can do whatever with the record *)
  902.                                    .
  903.                                    .
  904.                                    .
  905.                lrNum := GetNextLr(lrLst);
  906.                end;                  (* this will continue until end of list *)
  907.  
  908.       You can also do a retrieval for a range of values or retrieve records on
  909.       a partial string match.  An example of each follows:
  910.  
  911.            var
  912.                key1,
  913.                key2 : Byte;
  914.                lrLst : LrList;
  915.                lrNum : LRNumber;
  916.  
  917.            begin
  918.            key1 := 10;
  919.            key2 := 75;
  920.            GetRangeFromBTree(yyy,key1,GE,key2,LE,lrLst);
  921.  
  922.                                         14
  923.  
  924.  
  925.  
  926.     TBTREE16             Copyright (c)  1988,1989  Dean H. Farwell II
  927.  
  928.  
  929.                                                    (* build list of logical
  930.                                                       record numbers which
  931.                                                       are between 10 and 75  *)
  932.  
  933.            (* list is in lrLst *)
  934.            lrNum := GetFirstLr(lrLst);
  935.            while lrNum <> 0 do
  936.                begin
  937.                GetALogicalRecord(xxx,lrNum,thisRec,);
  938.                (* we can now print the record or look at it or whatever it is
  939.                   that you would want to do with it                          *)
  940.                                    .
  941.                                    .
  942.                                    .
  943.                lrNum := GetNextLr(lrLst);
  944.                end;                  (* this will continue until end of list *)
  945.  
  946.       One note about the above example is in order.  The first Condition must
  947.       be either GE or GT and the second Condition must be LE or LT.  If they
  948.       are reversed, the retrieval will not work properly.  Also, one of the
  949.       conditions can not be NE or EQ or EX.  This should make sense and is not
  950.       really a restriction.  This routine is designed to handle ranges, not all
  951.       query types.  If you have a query such as LE 10 and EQ 88 then you must
  952.       do two queries and perform an Intersection.  See the SETOPS unit for
  953.       details.
  954.  
  955.           ------------------------------
  956.  
  957.            var
  958.                keyString : String[10];
  959.                lrLst : LrList;
  960.                lrNum : LRNumber;
  961.  
  962.            begin
  963.            keyString := 'C';
  964.            (* assume zzz is an index holding values of type STRINGVALUE *)
  965.            GetSubstringFromBTree(zzz,keyString,ST,lrLst);
  966.                                                    (* build list of logical
  967.                                                       record which start with
  968.                                                       'C'                    *)
  969.            (* list is in lrLst *)
  970.            lrNum := GetFirstLr(lrLst);
  971.            while lrNum <> 0 do
  972.                begin
  973.                GetALogicalRecord(xxx,lrNum,thisRec,);
  974.                (* we can do whatever with the record *)
  975.                                    .
  976.                                    .
  977.                                    .
  978.                lrNum := GetNextLr(lrLst);
  979.                end;                  (* this will continue until end of list *)
  980.  
  981.  
  982.       Method 2 - Using the cursor internal to the index - Each index contains
  983.       one internal cursor.  The cursor can be set to the beginning or the end
  984.       of the index.  It can also be set to a specific place in the index (first
  985.       occurrence of a value).  Once the cursor is in place, it can be moved in
  986.       either direction retrieving logical record numbers along the way.
  987.  
  988.                                         15
  989.  
  990.  
  991.  
  992.     TBTREE16             Copyright (c)  1988,1989  Dean H. Farwell II
  993.  
  994.  
  995.       Although it is not nearly as powerful as the logical record list
  996.       approach, it has the advantage of simplicity as well the fact that the
  997.       cursor stays valid even after inserts and deletes are performed on the
  998.       index.  Rather than presenting the expanded discussion here, refer to the
  999.       BTREE3.INC file.
  1000.  
  1001.       Retrieving Data Records - As noted in the examples above, once the
  1002.       logical record number for the desired logical record is determined, use
  1003.       the GetALogicalRecord routine found in the LOGICAL unit to perform the
  1004.       retrieval.  It should be noted that you do not need to use and index to
  1005.       retrieve a data record.  You can retrieve all records by building a
  1006.       logical record list of all valid record number.  Use the
  1007.       GetValidLogicalRecords routine for this.
  1008.  
  1009.       Deleting Data - Deleting data is the inverse of inserting data.  There
  1010.       are three steps involved.  The first step is to retrieve the record.
  1011.       This is only required if you do not know the values for all fields which
  1012.       have a corresponding index.  Once we have the record we can delete the
  1013.       entries from the index(es).  The last step is to delete the logical
  1014.       record from the data file.  For the following example assume that the
  1015.       same definitions used above apply but that field2 also has an index with
  1016.       the file name residing in a variable zzz.  Also assume that we know that
  1017.       we want to delete logical record number 24:
  1018.  
  1019.            GetALogicalRecord(xxx,24,thisRec);
  1020.  
  1021.            DeleteValueFromBTree(yyy,24,thisRec.field1);
  1022.            DeleteValueFromBTree(zzz,24,thisRec.field2);
  1023.  
  1024.            DeleteDataRecord(xxx,24);    (* delete value from data record *)
  1025.  
  1026.       Updating Data - There are no separate commands to update data. Updating
  1027.       is a two step process.   The first step is to fetch the appropriate data
  1028.       record(s).  Once this is accomplished, the appropriate fields can be
  1029.       updated and the data file can be stored.  A third step may be required.
  1030.       If any indexed fields (fields which have an index associated with them)
  1031.       are changed then the old value will have to be deleted and then the new
  1032.       value will have to be inserted into the index.  Rather than show an
  1033.       example here, I refer you to EXAMPLE3.PAS.  You may notice that in that
  1034.       example, I store the updated data record after updating the index rather
  1035.       than before.  The order of these two operations is not important.
  1036.  
  1037.       Deleting Files - The operation of deleting a file is not going to be done
  1038.       very often but will be necessary from time to time.  The following is an
  1039.       example:
  1040.  
  1041.            DeleteDataFile(xxx);
  1042.            DeleteIndexFile(yyy);
  1043.  
  1044.       Notice that there is a separate routine for data and index files.  Also,
  1045.       deleting a data file will not automatically delete the associated index
  1046.       files.  You must do this explicitly as appropriate.
  1047.  
  1048.       Sorting - Sorting can be done on any number of fields as you desire.
  1049.       Sorting requires two steps.  The first is to build a sort field list, a
  1050.       list containing information on each of the fields to sort on.  The second
  1051.       step is to use this sort field list to sort a logical records list.
  1052.       After sorting is completed, the user should destroy the sort field list
  1053.  
  1054.                                         16
  1055.  
  1056.  
  1057.  
  1058.     TBTREE16             Copyright (c)  1988,1989  Dean H. Farwell II
  1059.  
  1060.  
  1061.       using the provided routine unless the list will be required later.  An
  1062.       example follows:
  1063.  
  1064.       type
  1065.           MyRecord = record
  1066.                      field1 : Byte;
  1067.                      field2 : Word;
  1068.                      field3 : String[10];
  1069.                      end;
  1070.  
  1071.       var
  1072.           lrLst : LrList;
  1073.           sPtr : SortFieldList;
  1074.           success : Boolean;
  1075.  
  1076.           begin
  1077.           GetValidLogicalRecords(xxx,lrLst);   (* list of all records *)
  1078.  
  1079.           sPtr := NIL;  (* EXTREMELY CRITICAL !!! - you must pass in a
  1080.                            pointer variable whose value is NIL.  If
  1081.                            you forget this little step all kinds of
  1082.                            bad things will probably happen!!!         *)
  1083.  
  1084.           AddFieldToSortList(sPtr,4,STRINGVALUE);
  1085.           AddFieldToSortList(sPtr,2,WORDVALUE);
  1086.           SortList(lrLst,xxx,sPtr,success);
  1087.           if not success then
  1088.               begin
  1089.               (* there was not enough heap space to facilitate the sort.  Free
  1090.                  up some space and try again if desired                       *)
  1091.               end;
  1092.           DestroySortList(sPtr);           (* retrieve the heap space *)
  1093.           end;
  1094.  
  1095.       Notice that the second parameter is the BYTE position of the sort field
  1096.       within the data record.  It is not the field number.  This is extremely
  1097.       important!!  See the SORT unit for details.
  1098.  
  1099.       Building/Rebuilding Indexes - Once in awhile you may manage to wipe out
  1100.       an index or in some other way cause it to be out of whack with your data
  1101.       file.  Or, you may want to add an index to a field which previously did
  1102.       not have an index.  This can easily be accomplished using a routine added
  1103.       in version 1.1.  Rather than repeating the example here, please refer to
  1104.       EXAMPLE7.PAS which will show how to build a list of existing records and
  1105.       rebuild an index from that list.  The added routine will also allow you
  1106.       to build a list of all logical records associated with a data file
  1107.       without using an index.  To check out an index to be sure that certain
  1108.       logical record numbers are in fact in the index, you can use the
  1109.       FindLrNumInBTree routine.
  1110.  
  1111.       Viewing Status Information - I have included several routines for
  1112.       checking on the values of certain parameters and for allowing the user to
  1113.       delve into the depths if desired.  The first routine to discuss is one
  1114.       which allows you to find out how many entries are in a logical record
  1115.       list once it has been created.  To accomplish this the following call is
  1116.       used:
  1117.  
  1118.            cnt := GetCountLr(lrLst);   (* lrLst is your variable where
  1119.  
  1120.                                         17
  1121.  
  1122.  
  1123.  
  1124.     TBTREE16             Copyright (c)  1988,1989  Dean H. Farwell II
  1125.  
  1126.  
  1127.                                           the list resides *)
  1128.  
  1129.       A second valuable utility is a routine which will return the number of
  1130.       files which are presently open using the FILEBUFF unit. In other words
  1131.       this returns the number of files which are on the files open list.  This
  1132.       is not necessarily the number of files which DOS thinks is open.  Only
  1133.       files opened using the create file or open file routines provided in
  1134.       FILEBUFF.PAS will be included in this number.  Not included will be other
  1135.       files opened by the user and the files such as standard input and output
  1136.       etc. An example of a call is below:
  1137.  
  1138.            cnt := GetNumberOpenFiles;
  1139.  
  1140.       Several routines are provided in FILES.PAS which have not been discussed
  1141.       yet.  The first is FileExists which will determine the existence of any
  1142.       file.  Another routine of use is SaveUserDataArray.  This will store a
  1143.       256 byte array in the parameter record for a data or index file.  This
  1144.       can be used to store whatever the user desires.  FetchUserDataArray will
  1145.       retrieve the 256 byte array for the user.  Another routine of use is
  1146.       FetchFileVersion which will return a 6 character string which determines
  1147.       which version was used to create the index or data file.
  1148.  
  1149.       The largest number of utilities lies in PAGE.PAS.  The first routines of
  1150.       interest are the ones for writing part or all of the buffer to disk.  The
  1151.       demand paging used in the PAGE.PAS unit is critical to the performance of
  1152.       TBTREE16.  Since a large number of pages are in the memory buffer, the
  1153.       need to constantly go out to disk is reduced.  Disk seeks (head movement)
  1154.       is what slows down most database operations.  The secret is to do
  1155.       everything you can to alleviate the need to go out to disk.  Memory is
  1156.       many times faster than external storage.  However, if changes are made to
  1157.       pages in the buffer we want to ensure that they do not get lost.  We need
  1158.       to write them to disk at some point.  Normally, a page will stay in
  1159.       memory until another page needs the space. The unit uses a least recently
  1160.       used algorithm which in nothing earth shattering (but it works).  When a
  1161.       page needs to be swapped out, a check is made to see if it is dirty
  1162.       (changes have been made since it was read in or last written to disk).
  1163.       If it is clean no problem.  If it is dirty it is written to disk prior to
  1164.       allowing the page to be reused.  The user can force pages to be written
  1165.       out at any time.  One method is to set a parameter which forces a write
  1166.       to disk anytime a page is written to in memory. Essentially, a page will
  1167.       never be dirty this way.  To accomplish this the SetImmediateDiskWrite
  1168.       routine is used.  The user can set this parameter to TRUE or FALSE.
  1169.       FALSE is the default, but the user should probably make an explicit call
  1170.       anyway on initialization so there is no doubt or confusion.  If FALSE is
  1171.       set, the user may still want to periodically write pages to disk. The
  1172.       user can write all pages for a given file or all pages in the buffer.
  1173.       For example:
  1174.  
  1175.            WriteEntireBufferToDisk;
  1176.  
  1177.                      or
  1178.  
  1179.            WriteBufferToDisk(xxx);        where xxx is a file name
  1180.  
  1181.       The user should always write all pages to disk prior to termination.
  1182.       Otherwise, changes made to pages still in memory will be lost.  A handy
  1183.       way to do this is to call it from an exit procedure.  See EXAMPLE2.PAS
  1184.       for an example.
  1185.  
  1186.                                         18
  1187.  
  1188.  
  1189.  
  1190.     TBTREE16             Copyright (c)  1988,1989  Dean H. Farwell II
  1191.  
  1192.  
  1193.  
  1194.       A second set of routines are provided to get rid of (release) pages in
  1195.       the buffer.  The pages should be written to disk prior to release.  These
  1196.       routines can be dangerous.  I need them internally for operations such as
  1197.       changing the size of the buffer dynamically and also for deleting a file.
  1198.       They are visible and free to use, but understand what you're doing first.
  1199.       If you're looking for a convenient way to wreck havoc with your data
  1200.       these two are perfect candidates.  The only reason I can foresee why you
  1201.       would want to attempt to use these is to release some pages for files you
  1202.       won't need for a while in order to free up heap space (such as for a
  1203.       sort).  Before releasing, write the affected pages to disk!!  Except for
  1204.       freeing up heap space, there is not really a need to micro manage the
  1205.       resources like this and these routines can lead to problems if misused.
  1206.       Accidentally, losing a node (page) in the middle of an index will leave
  1207.       it in an unrepairable state and will ruin your whole day.
  1208.  
  1209.       A third set of routines are much friendlier and I can stay off my soap
  1210.       box.  These routines manipulate and check the size of the buffer.  All
  1211.       values are in terms of pages.  A page is 512 bytes. To digress slightly,
  1212.       512 worked well because a smaller number caused inefficiency in the least
  1213.       recently used page algorithm and also meant that index keys had to be
  1214.       smaller.  A larger number means that less pages can be in memory at once.
  1215.       Do not try to change this constant as a lot of things are affected.  Just
  1216.       changing the constant will not work properly.  This is due to the fact
  1217.       that a constant declaration can not be declared using a simple
  1218.       expression (version 4.0).  For example:
  1219.  
  1220.            const
  1221.                xxx = 10;
  1222.                yyy = xxx/2;  (* illegal in Turbo Pascal version 4.0 *)
  1223.  
  1224.       Therefore, other constants that depend on xxx have to be set explicitly.
  1225.       In the above, yyy would have to be set to 5.  Anyway, back to the matters
  1226.       at hand.  To set the size of the buffer the following call should be
  1227.       made:
  1228.  
  1229.            SetMaxBufferPages(50);  (* 25K bytes *)
  1230.  
  1231.       If a user does not set the page limit explicitly, the value will default
  1232.       to one page.  Everything still works, but performance will be extremely
  1233.       poor.  A minimum of 10 pages is required to have this work well at all.
  1234.       One hundred or so pages is preferred.  A great deal depends on your
  1235.       application as well!  A user can check this value at any time by doing
  1236.       the following:
  1237.  
  1238.            cnt := CheckMaxBufferPages;
  1239.  
  1240.       The user can check the number actually in use by doing the following:
  1241.  
  1242.            cnt := CheckPagesInUse;
  1243.  
  1244.       One routine not mentioned earlier is CheckImmediateDiskWrite which
  1245.       returns TRUE if dirty pages will be immediately written to disk, FALSE
  1246.       otherwise.
  1247.  
  1248.       One interesting routine is PrintPagebuffer.  This routine is one that I
  1249.       developed for my own debugging purposes and is included to allow you to
  1250.       see what the page buffer looks like.  One warning though, if the page
  1251.  
  1252.                                         19
  1253.  
  1254.  
  1255.  
  1256.     TBTREE16             Copyright (c)  1988,1989  Dean H. Farwell II
  1257.  
  1258.  
  1259.       buffer is large, the output will be quite lengthy.
  1260.  
  1261.       The PrintBufferStats routine is more for curiosity's sake and for tuning
  1262.       the size of the buffer.  A call to this routine will print the statistics
  1263.       for buffer use.  The number of pages in use, the maximum number of pages
  1264.       allowed, the number of requests for a page (fetches), the number of
  1265.       fetches in which the page was in the buffer (hits) and the ratio of hits
  1266.       to fetches will be output.  A hit ratio of much below 95% could signal a
  1267.       requirement to increase the buffer size.  You really need to keep this
  1268.       number in perspective though.  If you are waltzing through a file in
  1269.       which none of the records are in the buffer, the hit ratio will be poor.
  1270.       Other operations will have higher hit ratios.  At least it's there to use
  1271.       as desired.
  1272.  
  1273.       A recently added routine contained in the BTREE unit is
  1274.       NumberOfBTreeLevels which returns the number of levels currently in an
  1275.       index.  If that number gets above 10 you are doing something rather
  1276.       strange and may run into stack problems.  The cause of such an occurrence
  1277.       is that you have a huge number of index entries (many many thousands) or
  1278.       your index entries are large.  The only entries over 4 bytes are strings
  1279.       or arrays of type ByteData.  These types of indexes should use entries as
  1280.       small as possible.  Don't use first name, last name, and middle initial
  1281.       as all one indexed filed unless there is a really good reason to
  1282.       (doubtful). Any string index entry over about 30 bytes is suspect.
  1283.       Remember what an index is for .. to store something to allow quick
  1284.       retrievals.  The index is not designed to be the data file.  A deep index
  1285.       will simply not be as fast as a shallow index.  The smaller the index
  1286.       entry size, the shallower the index.
  1287.  
  1288.       Another new routine is the FindLrNumInBTree which can be used for
  1289.       debugging and checking the consistency of an index file.
  1290.  
  1291.       Other Routines - I discussed above the routines which are directly
  1292.       applicable to a user who wants to use the indexing and data manipulation
  1293.       capabilities of TBTREE16.   There are some lower level general routines
  1294.       such as those found in FASTMOVE.PAS, MATH.PAS and STRINGS.PAS which are
  1295.       used internally.  Since they are fairly general in nature,  they may have
  1296.       applicability for your other applications.  I won't go into details on
  1297.       their inner workings here, but you have the source code, so you can look
  1298.       in the units to see if there is anything else useful for whatever you
  1299.       happen to be doing.  The quick reference will provide assistance as well.
  1300.  
  1301.       Error Handling - In version 1.5 I have added a unit (ERROR unit) which is
  1302.       designed to handle I/O errors.  This unit handles only I/O errors and
  1303.       allows these errors to be trapped.  TBTREE16 I/O is now accomplished with
  1304.       I/O checking off.  If an I/O error occurs, the ERROR unit comes into
  1305.       play.  A routine is called with pertinent information being passed to it.
  1306.       The routine should be modified by the user, as desired, to handle the
  1307.       error.  As written, if an I/O error occurs, the program will terminate
  1308.       after an error message is written.  This parallels what would happen in
  1309.       versions prior to TBTREE15.  However, as stated above, you are encouraged
  1310.       to change the routine to handle the error as desired.
  1311.  
  1312.  
  1313.  
  1314.  
  1315.  
  1316.  
  1317.  
  1318.                                         20
  1319.  
  1320.  
  1321.  
  1322.     TBTREE16             Copyright (c)  1988,1989  Dean H. Farwell II
  1323.  
  1324.  
  1325.                                 Inner Workings
  1326.  
  1327.  I am trying to avoid bogging you down with too much detail concerning the
  1328.  inner workings of this product.  However, there are a few things which you may
  1329.  need to be aware of.  One important area is how TBTREE16 manages the heap. 
  1330.  Turbo Pascal has two different methods for heap management.  TBTREE16 uses
  1331.  New, GetMem, FreeMem and Dispose exclusively.  Mark and Release are not used
  1332.  and CAN NOT be used in your application if TBTREE16 is used.  Mark and/or
  1333.  Release will cause a disaster!!!  Also, TBTREE16 handles the heap well, but
  1334.  you need to provide it with a sufficient amount of heap to operate with.  Heap
  1335.  is needed by the page buffer (PAGE unit), it is needed for sorting (SORT unit)
  1336.  and it greatly enhances the speed of set operations (SETOPS unit).  If your
  1337.  application hogs all of the heap, sorts may be impossible and disk I/O caused
  1338.  by a small buffer will greatly reduce throughput.  Also, set operations will
  1339.  slow down considerably.  One more note - If the heap is almost full, an error
  1340.  can occur since there will not be room for the free list to expand when
  1341.  FreeMem is used (which is done extensively throughout TBTREE16).  To preclude
  1342.  this from happening, you can set the freeMin variable (internal to TURBO
  1343.  PASCAL and has nothing to do with TBTREE) to a value which will reserve some
  1344.  number of bytes for the free list.  Set freeMin to some multiple of 8 bytes to
  1345.  reserve space.  The Turbo Pascal manual discusses this in depth in the section
  1346.  concerning the FREE LIST (p 198 of the version 5.0 manual).  Again, this error
  1347.  has nothing to do with TBTREE (but it does affect it) and occurs in Turbo
  1348.  Pascal programs which use the whole heap and then try to dispose of space.
  1349.  
  1350.  You need to be aware of the tradeoff of using the LOGICAL unit versus the
  1351.  VLOGICAL unit.  VLOGICAL obviously provides flexibility.  However, there is a
  1352.  cost in performance and file size.  There is an overhead of 10 bytes per
  1353.  logical record associated with variable record length files whereas there is
  1354.  an overhead of only one bit (not byte) for each record in a fixed length data
  1355.  file.  The same holds true for records which have been deleted.  This overhead
  1356.  is not as significant if the size of the records themselves is large.  In the
  1357.  area of performance, you will find the variable length record routines to be a
  1358.  little slower.  Which way to go is up to you.  Remember, you can use both
  1359.  types in a single application,  But once a file is declared to be of one type,
  1360.  you must not use the other type's routines with it.  Doing that will cause
  1361.  problems.
  1362.  
  1363.  
  1364.  
  1365.  
  1366.  
  1367.  
  1368.  
  1369.  
  1370.  
  1371.  
  1372.  
  1373.  
  1374.  
  1375.  
  1376.  
  1377.  
  1378.  
  1379.  
  1380.  
  1381.  
  1382.  
  1383.  
  1384.                                         21
  1385.  
  1386.  
  1387.  
  1388.     TBTREE16             Copyright (c)  1988,1989  Dean H. Farwell II
  1389.  
  1390.  
  1391.                           Current Product Limitations
  1392.  
  1393.  The following limitations apply to TBTREE16.  Only limitations inherent to
  1394.  TBTREE16 are discussed.  DOS limits and practical limits like disk drive
  1395.  capacity are not discussed.  These limitations may change (become less
  1396.  restrictive) in future additions.
  1397.  
  1398.  
  1399.          Number of Data Files - No Limit
  1400.  
  1401.          Number of Index Files Per Data File - No Limit
  1402.  
  1403.          Size of Data File - MAXLONGINT (2,147,483,647) Logical or Physical
  1404.                              Records (whichever comes first) or disk space (the
  1405.                              real limit!!)
  1406.  
  1407.          Size of Index File - MAXLONGINT Physical Records. The real restriction
  1408.                               is going to be stack size.  I use a recursive
  1409.                               routine to traverse the BTrees.  Recursion is
  1410.                               very efficient for this but has the problem that
  1411.                               each level keeps a couple of thousand bytes on
  1412.                               the stack.  It is very important to use a large
  1413.                               stack size if indexes are going to be deep. Most
  1414.                               indexes will not be more than 4 or 5 levels deep
  1415.                               unless a HUGE number of records are involved or
  1416.                               the keys in the indexes are large. Large is
  1417.                               relative, but you need to try to keep entries
  1418.                               below 30 bytes or so.  This really only affects
  1419.                               strings presently.  I would like to know if
  1420.                               anyone is running into problems with this as I
  1421.                               can handle this iteratively rather than
  1422.                               recursively which will make the problem disappear
  1423.                               at the expense of some added coding complexity.
  1424.                               I recently did a test to see to see how critical
  1425.                               this is.  I did a test using an index entry size
  1426.                               of 100 bytes (100 byte strings).  I entered over
  1427.                               27000 records before running out of disk space
  1428.                               (took over one day on my archaic 4.77 MHz
  1429.                               computer!).  I had somewhere in the area of 15
  1430.                               levels which is more than you should reasonably
  1431.                               have.  I also used a 32K stack (64K being the
  1432.                               maximum allowed).  Anyway, I couldn't blow it up
  1433.                               so I don't think you will either!
  1434.  
  1435.          Size of Page Buffer - Limited by heap space.  I have not used this
  1436.                                with any type of heap extender or other program
  1437.                                which uses other memory (extended, expanded) for
  1438.                                the heap.  I would enjoy seeing feedback if
  1439.                                anyone tries it.  If I need to do something to
  1440.                                facilitate use of a heap extender let me know
  1441.                                and I'll try to accommodate.
  1442.  
  1443.          Number of Files Open At Once - Actual number set by user, but user
  1444.                                         does not have to worry about keeping
  1445.                                         track of files used by TBTREE16 since
  1446.                                         it opens and closes files as required.
  1447.  
  1448.          Size of Key (Index Entry) - 245 bytes.  Versions prior to 1.6 had a
  1449.  
  1450.                                         22
  1451.  
  1452.  
  1453.  
  1454.     TBTREE16             Copyright (c)  1988,1989  Dean H. Farwell II
  1455.  
  1456.  
  1457.                                      higher number.  However, no version ever
  1458.                                      worked for values higher than 245.  I
  1459.                                      apparently missed that during testing.
  1460.                                      245 is still much higher than you can
  1461.                                      practically use anyway.
  1462.  
  1463.          Size of Data Record - 65520 bytes since this is the limit for
  1464.          structured (composite) types in Turbo Pascal.
  1465.  
  1466.          Max File Name Length - 80 characters including drive designator, path,
  1467.          file name and extension.
  1468.  
  1469.          Logical List Limit - Unlimited
  1470.  
  1471.          Number Of Sort Fields - Unlimited
  1472.  
  1473.  
  1474.  
  1475.  
  1476.  
  1477.  
  1478.  
  1479.  
  1480.  
  1481.  
  1482.  
  1483.  
  1484.  
  1485.  
  1486.  
  1487.  
  1488.  
  1489.  
  1490.  
  1491.  
  1492.  
  1493.  
  1494.  
  1495.  
  1496.  
  1497.  
  1498.  
  1499.  
  1500.  
  1501.  
  1502.  
  1503.  
  1504.  
  1505.  
  1506.  
  1507.  
  1508.  
  1509.  
  1510.  
  1511.  
  1512.  
  1513.  
  1514.  
  1515.  
  1516.                                         23
  1517.  
  1518.  
  1519.  
  1520.     TBTREE16             Copyright (c)  1988,1989  Dean H. Farwell II
  1521.  
  1522.  
  1523.                        Future Enhancements / Directions
  1524.  
  1525.  One of the advantages of using the shareware concept to distribute this
  1526.  software is that I can be very flexible and can tailor this product to the
  1527.  needs of users.  I am soliciting as much feedback as possible.  I need to know
  1528.  what is really important to users.  I hope to be able to accomplish the
  1529.  following in the future:
  1530.  
  1531.      I may change the delete routines in the BTREE.PAS unit to force the
  1532.      combining of nodes when each is half full or less. Presently, a node is
  1533.      not deleted until the last entry is deleted. This will slightly increase
  1534.      performance on queries and will reduce the size of the indexes if deletes
  1535.      are done often, but will otherwise be transparent.
  1536.  
  1537.      I may pursue adding multitasking capabilities.
  1538.  
  1539.      The most significant change for the future will be an abandonment of Turbo
  1540.      Pascal 4.0 support.  Version 5.0 has some nice features which I can not
  1541.      use yet because I wanted this version to support Turbo Pascal 4.0.  If I
  1542.      do not get negative feedback, future versions will support only version 5
  1543.      (and later when there is one) of Turbo Pascal.  I would like to get
  1544.      feedback concerning peoples feelings on this (registered and nonregistered
  1545.      alike).  I also need feedback to determine if most people are moving to
  1546.      version 5.5.  Mine is still in the mail, so I need to see what good
  1547.      things that will do for me before I make any determinations.
  1548.  
  1549.                          Version Release Notes
  1550.  
  1551.  Version 1.1
  1552.  
  1553.  1.  Added capability to do a search of an index on a range of values.
  1554.  
  1555.  2.  Added capability to do partial string match searches (strings only).
  1556.      Added one routine to the BTREE unit and several routines to the COMPARE
  1557.      unit and one type declaration to the NUMBERS unit to facilitate this
  1558.      change.
  1559.  
  1560.  3.  Corrected bug in BTREE unit.  Documentation stated that duplicate entries
  1561.      for a given logical record number and field value were prevented from
  1562.      being entered.  This was not previously the case although that is now
  1563.      true.
  1564.  
  1565.  4.  Added a routine (LOGICAL unit) to build a list of all current records for
  1566.      a file (all valid ie not deleted records).  This is essential for
  1567.      rebuilding indexes or accessing data without an index. In actuality, a
  1568.      user could have built this routine, but it was not intuitively obvious.
  1569.  
  1570.  5.  Added the capability to delete an entry from an existing logical record
  1571.      list.
  1572.  
  1573.  6.  Divided BTREE.PAS into BTREE.PAS and two include files : BTREE1.INC and
  1574.      BTREE2.INC.
  1575.  
  1576.  7.  Added several more examples.
  1577.  
  1578.  Version 1.2
  1579.  
  1580.  1.  Added Sorting capabilities.
  1581.  
  1582.                                         24
  1583.  
  1584.  
  1585.  
  1586.     TBTREE16             Copyright (c)  1988,1989  Dean H. Farwell II
  1587.  
  1588.  
  1589.  
  1590.  2.  Added several routines to LRECLIST.PAS to facilitate sorting.  I also made
  1591.      a couple of internal cosmetic changes to LRECLIST.PAS.
  1592.  
  1593.  3.  Added one example.
  1594.  
  1595.  4.  Removed CalculateRecordSize and several unused data types from
  1596.      LOGICAL.PAS.  These were for future projects and now are now targeted for
  1597.      TBASE.
  1598.  
  1599.  Version 1.3
  1600.  
  1601.  1.  Added SETOPS unit which provides Intersection, Union and Difference.
  1602.  
  1603.  2.  Added one example.
  1604.  
  1605.  3.  MATH.PAS redone in assemble language.  See listing for details and credit
  1606.      to the author.
  1607.  
  1608.  4.  Added one routine (FindLrInList) to LRECLIST.PAS.
  1609.  
  1610.  5.  In LOGICAL.PAS changed MAXDATASIZE to 65520 since this is the maximum size
  1611.      for a structured type in Turbo Pascal 4.0.
  1612.  
  1613.  6.  TP4PRINT.PAS now prints the file creation date as part of the header.
  1614.  
  1615.  7.  Added NumberOfBTreeLevels routine to the BTREE unit.
  1616.  
  1617.  8.  Added StoreNewLogicalRecord routine to LOGICAL.PAS.  This makes it easier
  1618.      to store new records.  You no longer need to find the next available
  1619.      logical record number using the FirstUnUsedRecord routine located in
  1620.      FILES.PAS. StoreNewLogicalRecord does this for you and returns the
  1621.      associated logical record number.
  1622.  
  1623.  
  1624.  Version 1.4
  1625.  
  1626.  1.  Biggest change is a redesign of the data and index files.  Both file types
  1627.      have a parameter record (previously only the index files did).  There is
  1628.      more information contained in the parameter records, including a place for
  1629.      you to store 256 bytes of user data for your own requirements.  I also did
  1630.      away with the bitmap files.  Bitmaps are contained in the individual
  1631.      files.  Adds some speed and cuts in half the number of files floating
  1632.      around.  However, all files that were created using previous versions will
  1633.      not work with this new version of software.  You will need to rebuild all
  1634.      data and index files. I realize that this will cause some problems.  The
  1635.      index files will be easy, as EXAM7.PAS shows you how.  However, the data
  1636.      files will be tough.  The easiest method will be to write a small
  1637.      application using the old software and dump the data to to a flat file.
  1638.      Then you can create an application with the new version and read in the
  1639.      old data to the new files.  Make sure you have a backup of your old files
  1640.      before doing anything!!!
  1641.  
  1642.  2.  Many routine calls have been changed because of the above changes.
  1643.      Specifically, stores and retrievals of logical records no longer require
  1644.      the size of the data record to be passed in.  However, the size is needed
  1645.      when the file is created.  Specific routines were developed for creating
  1646.      and deleting the data files and other routines were developed for creating
  1647.  
  1648.                                         25
  1649.  
  1650.  
  1651.  
  1652.     TBTREE16             Copyright (c)  1988,1989  Dean H. Farwell II
  1653.  
  1654.  
  1655.      and deleting the index files.
  1656.  
  1657.  3.  The ByteData unit was added, although at this point it is of limited
  1658.      value.  It is really for work I am doing on TBASE.  It is available for
  1659.      your use, however.
  1660.  
  1661.  4.  Corrected several errors.  Specifically, logical record sizes > 512 bytes
  1662.      did not work properly and the previous size limit for an index entry was
  1663.      really 255.  This has been corrected.  The limit is now 494 bytes as
  1664.      specified in the documentation.
  1665.  
  1666.  5.  Added a second way to perform retrievals of logical record numbers from an
  1667.      index.  See the BTREE unit for details.
  1668.  
  1669.  6.  Added GetSubstringAtPosition routine.
  1670.  
  1671.  7.  GetSubstringFromBTree routine did not work as advertised because of an
  1672.      error in the COMPARE unit which has been fixed.
  1673.  
  1674.  8.  Added ByteData unit
  1675.  
  1676.  9.  Moved ValueType to NUMBERS unit and added BYTEARRAYVALUE
  1677.  
  1678.  10. Corrected EndsWithSubstring routine
  1679.  
  1680.  11. Added ContainsSubstringAtPosition routine
  1681.  
  1682.  12. Now use {$IFOPT N+} conditional compilation directive to handle 8087 types
  1683.  
  1684.  13. All INDEX and DATA files now contain the version used to create the file.
  1685.      This is contained in the index.
  1686.  
  1687.  14. Changed definition for RecordNumber and FileTypes type
  1688.  
  1689.  15. Added UserDataArray type
  1690.  
  1691.  16. Added FileExists routine
  1692.  
  1693.  17. Redesigned entire FILES unit.  See unit for details.
  1694.  
  1695.  18. Many changes to LOGICAL unit.  See unit for details.
  1696.  
  1697.  19. Deleted PowerInt from MATH unit.
  1698.  
  1699.  20. Changed SortList procedure call so that size is no longer required.
  1700.  
  1701.  21. Added MAXSTRINGLENGTH constant and StringLengthRange type to STRINGS unit
  1702.  
  1703.  22. Redesigned TIME unit.  See unit for details.
  1704.  
  1705.  23. Many changes in BTREE unit.  See unit for details.
  1706.  
  1707.  24. Updated the examples to implement the changes.  One note - I had an error
  1708.      in the MyExit routine in the examples.  I forgot to to reinstall the value
  1709.      of ExitProc which essentially broke the chain for calling exit routines.
  1710.      Examples are now correct.
  1711.  
  1712.  Version 1.5
  1713.  
  1714.                                         26
  1715.  
  1716.  
  1717.  
  1718.     TBTREE16             Copyright (c)  1988,1989  Dean H. Farwell II
  1719.  
  1720.  
  1721.  
  1722.  1.  Fixed documentation errors in the examples.
  1723.  
  1724.  2.  Cleared up documentation in the FILEBUFF unit.
  1725.  
  1726.  3.  Added FASTMOVE unit to speed up moves.
  1727.  
  1728.  4.  Made internal changes to use Inc and Dec to increase performance
  1729.  
  1730.  5.  Completely reworked the SORT unit.  Performance has increased threefold.
  1731.  
  1732.  6.  Added ERROR unit to trap I/O errors.  See error unit for details.
  1733.  
  1734.  7.  Changed the PAGE unit and FILEBUFF units to keep heap allocation errors
  1735.      from ever occurring.  Units now reserve a minimum amount of space during
  1736.      initialization to ensure that there is always at least some minimum amount
  1737.      of space available.  See units for details.
  1738.  
  1739.  8.  Added FindLrNumInBTree and UsingCursorAndGEValueGetLr routine to BTREE
  1740.      unit.
  1741.  
  1742.  9.  Changed way records are added as data and index files grow.  As files grow
  1743.      larger, the number of records added at one time increases.  This will
  1744.      speed up the insert process.
  1745.  
  1746.  10. Reworked FILEBUFF unit to handle Text files better.
  1747.  
  1748.  11. Changed problems in LOGICAL unit associated with calling routines with
  1749.      logical record number equal to 0.  See LOGICAL unit for details.
  1750.  
  1751.  12. Added LastDataRecord to LOGICAL unit.
  1752.  
  1753.  13. Added CopyLrList routine to LRECLIST unit.
  1754.  
  1755.  14. Changed definition of SortList routine.  See SORT unit for details.
  1756.  
  1757.  15. Added Asciiz2Str routine to STRINGS unit.
  1758.  
  1759.  16. Rewrote TotalString routine to increase performance.
  1760.  
  1761.  17. Parts of TIME unit redone using INLINE statements to increase performance.
  1762.  
  1763.  18. Fixed error in GetEqualsFromBTree routine which would cause random
  1764.      failures on queries where the Condition was EQ
  1765.  
  1766.  19. Fixed error in GetRangeFromBTree routine which caused problems when the
  1767.      upper range and lower range were the same
  1768.  
  1769.  Version 1.6
  1770.  
  1771.  1.  Fixed an error which caused the wrong entries to be deleted from an index
  1772.      when using DeleteValueFromBTree
  1773.  
  1774.  2.  Changed the value of MAXVALSIZE to 245 which is the correct limit on the
  1775.      maximum size of an index entry
  1776.  
  1777.  3.  Added VLRDATA to the FileTypes enumerated type
  1778.  
  1779.  
  1780.                                         27
  1781.  
  1782.  
  1783.  
  1784.     TBTREE16             Copyright (c)  1988,1989  Dean H. Farwell II
  1785.  
  1786.  
  1787.  4.  Added FetchFileType routine
  1788.  
  1789.  5.  Corrected error in LOGICAL unit which caused an error when dealing with
  1790.      records larger than 512 bytes
  1791.  
  1792.  6.  Added VLOGICAL unit.  This unit is an alternative to the LOGICAL unit and
  1793.      it handles variable length records
  1794.  
  1795.  7.  Fixed error in the SORT unit which would lead to an infinite loop when the
  1796.      heap became full and memory was being allocated for a sort
  1797.  
  1798.  8.  Changed SORT unit to facilitate sorting variable length record data files
  1799.  
  1800.  9.  Fixed an error in the SORT unit which caused the sort field list to be
  1801.      modified upon completion of the sort.  The sort field list is now returned
  1802.      unmodified which allows it to be used again to sort on the same fields
  1803.  
  1804.  10. Fixed a major error in the SORT unit which caused logical record numbers
  1805.      to be lost from a logical record list when that list was sorted
  1806.  
  1807.  
  1808.  
  1809.  
  1810.  
  1811.  Turbo Pascal is a registered trademark of Borland International
  1812.  CompuServe is a registered trademark of CompuServe Incorporated
  1813.  
  1814.  
  1815.  
  1816.  
  1817.  
  1818.  
  1819.  
  1820.  
  1821.  
  1822.  
  1823.  
  1824.  
  1825.  
  1826.  
  1827.  
  1828.  
  1829.  
  1830.  
  1831.  
  1832.  
  1833.  
  1834.  
  1835.  
  1836.  
  1837.  
  1838.  
  1839.  
  1840.  
  1841.  
  1842.  
  1843.  
  1844.  
  1845.  
  1846.                                         28
  1847.  
  1848.  
  1849.