home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / cslio205.zip / DOC / MANUAL.TXT < prev    next >
Text File  |  1997-01-21  |  212KB  |  6,088 lines

  1.  
  2.  
  3.  
  4.  
  5.  
  6.  
  7.                     The CS-Libraries
  8.  
  9.                      A Database Kit
  10.  
  11.  
  12.  
  13.                        ComBits
  14.                     P.O. Box 3303
  15.                     2280 GH Rijswijk
  16.                     The Netherlands
  17.  
  18.  
  19.  
  20.  
  21.  
  22.  
  23.     Copyright (c) 1994-1996 by ComBits, the Netherlands.
  24.         All Rights Reserved.
  25.  
  26.  
  27.  
  28.  
  29.                           1    Contents
  30.  
  31.  
  32.  
  33.  
  34. 1    Contents. . . . . . . . . . . . . . . . . . . . . . . . .
  35.  
  36. 2    Preface . . . . . . . . . . . . . . . . . . . . . . . . .
  37.     2.1 Contacting ComBits . . . . . . . . . . . . . . . . . .
  38.     2.2 Legal Matters. . . . . . . . . . . . . . . . . . . . .
  39.         2.2.1 Disclaimer . . . . . . . . . . . . . . . . . . .
  40.         2.2.2 Royalties and runtime limitations. . . . . . . .
  41.         2.2.3 Trademarks . . . . . . . . . . . . . . . . . . .
  42.  
  43. 3 Introduction . . . . . . . . . . . . . . . . . . . . . . . .
  44.  
  45. 4 Overview . . . . . . . . . . . . . . . . . . . . . . . . . .
  46.  
  47. 5 Debugging. . . . . . . . . . . . . . . . . . . . . . . . . .
  48.  
  49. 6 Runtime Libraries. . . . . . . . . . . . . . . . . . . . . .
  50.  
  51. 7 Compiler Options . . . . . . . . . . . . . . . . . . . . . .
  52.     7.1 Hardware . . . . . . . . . . . . . . . . . . . . . . .
  53.     7.2 Floating point . . . . . . . . . . . . . . . . . . . .
  54.     7.3 Watcom . . . . . . . . . . . . . . . . . . . . . . . .
  55.     7.4 Borland. . . . . . . . . . . . . . . . . . . . . . . .
  56.     7.5 Visual C++ . . . . . . . . . . . . . . . . . . . . . .
  57.  
  58. 8 Standard Types & Definitions . . . . . . . . . . . . . . . .
  59.  
  60. 9 Runtime Errors and Messages. . . . . . . . . . . . . . . . .
  61.     9.1 What to expect?. . . . . . . . . . . . . . . . . . . .
  62.     9.2 Changing the way messages are displayed. . . . . . . .
  63.     9.3 Message related functions. . . . . . . . . . . . . . .
  64.     9.4 Database class messages. . . . . . . . . . . . . . . .
  65.  
  66. 10 Temporary files . . . . . . . . . . . . . . . . . . . . . .
  67.  
  68. 11 Buffering . . . . . . . . . . . . . . . . . . . . . . . . .
  69.  
  70. 12 PAGE-Class. . . . . . . . . . . . . . . . . . . . . . . . .
  71.     12.1 Introduction. . . . . . . . . . . . . . . . . . . . .
  72.     12.2 Storing data in the header-page . . . . . . . . . . .
  73.  
  74. 13 Lock files. . . . . . . . . . . . . . . . . . . . . . . . .
  75.     13.1 Name of a lock file . . . . . . . . . . . . . . . . .
  76.     13.2 Controlling lock files. . . . . . . . . . . . . . . .
  77.  
  78. 14 Read-Only databases . . . . . . . . . . . . . . . . . . . .
  79.     14.1 Class member functions. . . . . . . . . . . . . . . .
  80.  
  81. 15 TBASE-class . . . . . . . . . . . . . . . . . . . . . . . .
  82.     15.1 Introduction. . . . . . . . . . . . . . . . . . . . .
  83.     15.2 Using TBASE . . . . . . . . . . . . . . . . . . . . .
  84.     15.3 Creating a Database . . . . . . . . . . . . . . . . .
  85.     15.4 Opening . . . . . . . . . . . . . . . . . . . . . . .
  86.     15.5 Closing . . . . . . . . . . . . . . . . . . . . . . .
  87.     15.6 Appending Records . . . . . . . . . . . . . . . . . .
  88.     15.7 Deleting Records. . . . . . . . . . . . . . . . . . .
  89.     15.8 Page Utilization. . . . . . . . . . . . . . . . . . .
  90.     15.9 Locating Records. . . . . . . . . . . . . . . . . . .
  91.     15.10 Functions in alphabetical order. . . . . . . . . . .
  92.  
  93. 16 BTREE-class . . . . . . . . . . . . . . . . . . . . . . . .
  94.     16.1 Introduction. . . . . . . . . . . . . . . . . . . . .
  95.     16.2 BTREEx Classes. . . . . . . . . . . . . . . . . . . .
  96.     16.3 Multiple Keys . . . . . . . . . . . . . . . . . . . .
  97.     16.4 Current Pointer . . . . . . . . . . . . . . . . . . .
  98.     16.5 Using Btrees. . . . . . . . . . . . . . . . . . . . .
  99.         16.5.1 Creating. . . . . . . . . . . . . . . . . . . .
  100.         16.5.2 Opening . . . . . . . . . . . . . . . . . . . .
  101.         16.5.3 Inserting . . . . . . . . . . . . . . . . . . .
  102.         16.5.4 Searching . . . . . . . . . . . . . . . . . . .
  103.         16.5.5 Current . . . . . . . . . . . . . . . . . . . .
  104.         16.5.6 Deleting. . . . . . . . . . . . . . . . . . . .
  105.         16.5.7 Closing . . . . . . . . . . . . . . . . . . . .
  106.     16.6 Functions in alphabetical order.. . . . . . . . . . .
  107.  
  108. 17 CSDBGEN . . . . . . . . . . . . . . . . . . . . . . . . . .
  109.     17.1 Introduction. . . . . . . . . . . . . . . . . . . . .
  110.     17.2 Overview. . . . . . . . . . . . . . . . . . . . . . .
  111.     17.3 Features. . . . . . . . . . . . . . . . . . . . . . .
  112.     17.4 Limitations . . . . . . . . . . . . . . . . . . . . .
  113.     17.5 Definition file . . . . . . . . . . . . . . . . . . .
  114.     17.6 Tokenizing. . . . . . . . . . . . . . . . . . . . . .
  115.         17.6.1 How does it work? . . . . . . . . . . . . . . .
  116.     17.7 When is a substring indexed?. . . . . . . . . . . . .
  117.     17.8 Compound indexes. . . . . . . . . . . . . . . . . . .
  118.         17.8.1 A simple example. . . . . . . . . . . . . . . .
  119.         17.8.2 A more complex example. . . . . . . . . . . . .
  120.         17.8.3 Compound & Tokenizing Indexes . . . . . . . . .
  121.         17.8.4 Locating an Entry . . . . . . . . . . . . . . .
  122.     17.9 Export to dBASE . . . . . . . . . . . . . . . . . . .
  123.     17.10 Importing from dBASE . . . . . . . . . . . . . . . .
  124.     17.11 Exporting/Importing to/from ASCII. . . . . . . . . .
  125.     17.12 Starting a new database. . . . . . . . . . . . . . .
  126.     17.13 Opening a database . . . . . . . . . . . . . . . . .
  127.     17.14 Current Record . . . . . . . . . . . . . . . . . . .
  128.     17.15 Accessing fields . . . . . . . . . . . . . . . . . .
  129.     17.16 DATE fields. . . . . . . . . . . . . . . . . . . . .
  130.     17.17 Changing the record layout.. . . . . . . . . . . . .
  131.     17.18 Member functions in alphabetical order . . . . . . .
  132.     17.19 Warning. . . . . . . . . . . . . . . . . . . . . . .
  133.     17.20 A Large Example. . . . . . . . . . . . . . . . . . .
  134.  
  135. 18 VRAM  . . . . . . . . . . . . . . . . . . . . . . . . . . .
  136.     18.1 Introduction. . . . . . . . . . . . . . . . . . . . .
  137.     18.2 Creating. . . . . . . . . . . . . . . . . . . . . . .
  138.     18.3 Opening & Closing . . . . . . . . . . . . . . . . . .
  139.     18.4 VRAM Pointers . . . . . . . . . . . . . . . . . . . .
  140.     18.5 Fragmentation . . . . . . . . . . . . . . . . . . . .
  141.     18.6 Root. . . . . . . . . . . . . . . . . . . . . . . . .
  142.     18.7 Functions in Alphabetical order.. . . . . . . . . . .
  143.  
  144. 19 VBASE . . . . . . . . . . . . . . . . . . . . . . . . . . .
  145.     19.1 Introduction. . . . . . . . . . . . . . . . . . . . .
  146.     19.2 Using VBASE.. . . . . . . . . . . . . . . . . . . . .
  147.     19.3 Relocating records. . . . . . . . . . . . . . . . . .
  148.     19.4 Limitations.. . . . . . . . . . . . . . . . . . . . .
  149.     19.5 Functions in alphabetical order.. . . . . . . . . . .
  150.  
  151. 20 VBAXE . . . . . . . . . . . . . . . . . . . . . . . . . . .
  152.     20.1 Introduction. . . . . . . . . . . . . . . . . . . . .
  153.     20.2 Working.. . . . . . . . . . . . . . . . . . . . . . .
  154.     20.3 Files . . . . . . . . . . . . . . . . . . . . . . . .
  155.     20.4 Prototypes. . . . . . . . . . . . . . . . . . . . . .
  156.  
  157. 21 OLAY. . . . . . . . . . . . . . . . . . . . . . . . . . . .
  158.     21.1 Introduction & Overview . . . . . . . . . . . . . . .
  159.     21.2 Buffering . . . . . . . . . . . . . . . . . . . . . .
  160.     21.3 Performance . . . . . . . . . . . . . . . . . . . . .
  161.     21.4 Core Functions. . . . . . . . . . . . . . . . . . . .
  162.         21.4.1 Creating. . . . . . . . . . . . . . . . . . . .
  163.         21.4.2 Opening . . . . . . . . . . . . . . . . . . . .
  164.         21.4.3 Reading and Writing . . . . . . . . . . . . . .
  165.         21.4.4 Insert & Delete . . . . . . . . . . . . . . . .
  166.         21.4.5 Filesize & bottom . . . . . . . . . . . . . . .
  167.         21.4.6 Closing . . . . . . . . . . . . . . . . . . . .
  168.     21.5 Additional functions. . . . . . . . . . . . . . . . .
  169.     21.6 Import & Export . . . . . . . . . . . . . . . . . . .
  170.     21.7 Sequential functions. . . . . . . . . . . . . . . . .
  171.         21.7.1 Sequential functions in alphabetical order. . .
  172.         21.7.2 Miscellanious functions . . . . . . . . . . . .
  173.  
  174. 22 DLAY. . . . . . . . . . . . . . . . . . . . . . . . . . . .
  175.     22.1 Performance . . . . . . . . . . . . . . . . . . . . .
  176.     22.2 Member functions. . . . . . . . . . . . . . . . . . .
  177.  
  178. 23 IBASE . . . . . . . . . . . . . . . . . . . . . . . . . . .
  179.     23.1 Introduction. . . . . . . . . . . . . . . . . . . . .
  180.     23.2 Using IBASE . . . . . . . . . . . . . . . . . . . . .
  181.     23.3 Using IBASE . . . . . . . . . . . . . . . . . . . . .
  182.         23.3.1 Creating. . . . . . . . . . . . . . . . . . . .
  183.         23.3.2 Opening . . . . . . . . . . . . . . . . . . . .
  184.         23.3.3 Appending Records . . . . . . . . . . . . . . .
  185.         23.3.4 Reading . . . . . . . . . . . . . . . . . . . .
  186.         23.3.5 Writing . . . . . . . . . . . . . . . . . . . .
  187.         23.3.6 Inserting . . . . . . . . . . . . . . . . . . .
  188.         23.3.7 Deleting. . . . . . . . . . . . . . . . . . . .
  189.         23.3.8 Closing . . . . . . . . . . . . . . . . . . . .
  190.         23.3.9 Miscellaneous functions . . . . . . . . . . . .
  191.  
  192. 24 CSDIR . . . . . . . . . . . . . . . . . . . . . . . . . . .
  193.  
  194. 25 CSINFO. . . . . . . . . . . . . . . . . . . . . . . . . . .
  195.  
  196. 26 CSERROR . . . . . . . . . . . . . . . . . . . . . . . . . .
  197.  
  198. 27 CS4DBASE. . . . . . . . . . . . . . . . . . . . . . . . . .
  199.     27.1 Introduction. . . . . . . . . . . . . . . . . . . . .
  200.     27.2 Converting. . . . . . . . . . . . . . . . . . . . . .
  201.     27.3 Example . . . . . . . . . . . . . . . . . . . . . . .
  202.     27.4 Importing large databases . . . . . . . . . . . . . .
  203.  
  204. 28 CSTOOLS . . . . . . . . . . . . . . . . . . . . . . . . . .
  205.     28.1 Introduction  . . . . . . . . . . . . . . . . . . . .
  206.  
  207. 29 CSKEYS. . . . . . . . . . . . . . . . . . . . . . . . . . .
  208.     29.1 CSKEYS.exe. . . . . . . . . . . . . . . . . . . . . .
  209.  
  210. 30 DATE. . . . . . . . . . . . . . . . . . . . . . . . . . . .
  211.     30.1 Example . . . . . . . . . . . . . . . . . . . . . . .
  212.     30.2 Initialising. . . . . . . . . . . . . . . . . . . . .
  213.     30.3 Converting Strings. . . . . . . . . . . . . . . . . .
  214.     30.4 Obtaining date info . . . . . . . . . . . . . . . . .
  215.     30.5 Comparing dates . . . . . . . . . . . . . . . . . . .
  216.     30.6 Arithmetic. . . . . . . . . . . . . . . . . . . . . .
  217.     30.7 Miscellaneous . . . . . . . . . . . . . . . . . . . .
  218.  
  219. 31 HEAP. . . . . . . . . . . . . . . . . . . . . . . . . . . .
  220.     31.1 Purpose . . . . . . . . . . . . . . . . . . . . . . .
  221.     31.2 When to use it? . . . . . . . . . . . . . . . . . . .
  222.     31.3 Using HEAP. . . . . . . . . . . . . . . . . . . . . .
  223.     31.4 Functions in alphabetical order.. . . . . . . . . . .
  224.  
  225. 32 Alloc-Logging . . . . . . . . . . . . . . . . . . . . . . .
  226.     32.1 Introduction. . . . . . . . . . . . . . . . . . . . .
  227.     32.2 Replacements. . . . . . . . . . . . . . . . . . . . .
  228.     32.3 Logging . . . . . . . . . . . . . . . . . . . . . . .
  229.     32.4 Memory Leaks. . . . . . . . . . . . . . . . . . . . .
  230.  
  231. 33 csSTR . . . . . . . . . . . . . . . . . . . . . . . . . . .
  232.  
  233.  
  234.  
  235.  
  236.                           2    Preface
  237.  
  238.  
  239. Nowhere days even the simplest of applications seems to need some
  240. sort of database. Despite this, C++ and consequently most
  241. compilers, have very little, if any, support for it. Roughly speaking you
  242. have the choice between the very basic file IO as defined by the ANSI
  243. standard, or resort to the other extreme and use one of the truly colossul
  244. DataBase Management Systems (DBMS).
  245.  
  246. Neither option is very appealing.  Basic file IO' is so basic, it will take a
  247. yéár to come up with a database application. And despite its simple
  248. design it's still not all that easy to use. In particular newcomers seem to
  249. struggle with it.
  250. On the other hand, using a DBMS is often even less fun. From our own
  251. experience we recall having written a 400 KB application but having to
  252. ship a 15 MB package due to the large X database used.
  253. Apart from that, DBMS's have their roots firmly in the late sixties and
  254. early seventies. They were designed with a mainframe in mind, and are
  255. indeed equipped with all the flexibilty and user-friendly-ness which has
  256. made the mainframe a dying species.
  257.  
  258. With this library we believe we are offering a third option. One that is
  259. easy to use, poweful and still produces small, fast stand-alone
  260. executables.
  261.  
  262.  
  263.  
  264.  
  265. 2.1 Contacting ComBits
  266.  
  267. You can reach us, preferably, by E-mail.
  268. The address is: CSLIB@ComBits.nl.
  269.  
  270. If you don't have E-mail access you can reach us by traditional mail:
  271.         COMBITS
  272.         P.O. Box 3303
  273.         2280 GH Rijswijk
  274.         The Netherlands
  275.  
  276. Or FAX: +31703960172
  277. Voice:  +31703932300
  278.  
  279. Please remember, it is GMT +100 over here!
  280.  
  281.  
  282. 2.2 Legal Matters
  283.  
  284. 2.2.1 Disclaimer
  285.  
  286. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
  287. HOLDER AND/OR OTHER PARTIES PROVIDE THIS SOFTWARE "AS
  288. IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR
  289. IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  290. WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
  291. PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY
  292. AND PERFORMANCE OF THE SOFTWARE IS WITH YOU.  SHOULD
  293. THE SOFTWARE PROVE DEFECTIVE, YOU ASSUME THE COST OF
  294. ALL NECESSARY SERVICING, REPAIR OR CORRECTION. IN NO
  295. EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO
  296. IN WRITING WILL THE COPYRIGHT HOLDER BE LIABLE TO YOU
  297. FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL
  298. OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR
  299. INABILITY TO USE THE SOFTWARE (INCLUDING BUT NOT LIMITED
  300. TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR
  301. LOSSES SUSTAINED BY YOU OR THIRD PARTIES), EVEN IF SUCH
  302. HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
  303. POSSIBILITY OF SUCH DAMAGES.
  304.  
  305. 2.2.2 Royalties and runtime limitations
  306.  
  307. The CS-Libraries can be used in a commercial software product without
  308. any royalties as long as the number of copies sold annually does not
  309. exceed 10.000.
  310.  
  311. No part of these libraries may be used in a product which is in any way a
  312. competitor of the CS-Libraries.
  313.  
  314.  
  315. 2.2.3 Trademarks
  316.  
  317. IBM and OS/2 are registered trademarks of International Business
  318. Machines Corporation.
  319. MS-DOS and Windows are registered trademarks of Microsoft
  320. Corporation.
  321. Borland C/C++ and dBASE are registered trademarks of Borland
  322. International Inc.
  323. WATCOM is a trademark of WATCOM International Corp.
  324.  
  325.  
  326.  
  327.  
  328.  
  329.  
  330.  
  331.  
  332.  
  333.  
  334.  
  335.  
  336.  
  337.  
  338.                                 Part
  339.  
  340.  
  341.                                 One
  342.  
  343.  
  344.  
  345.  
  346.  
  347.  
  348.  
  349.  
  350.  
  351.  
  352.  
  353.  
  354.  
  355.  
  356.  
  357.  
  358.  
  359.  
  360.  
  361.  
  362.  
  363.  
  364.  
  365.  
  366.  
  367.  The next part of the documentation presents an introduction and
  368.              discusses  topics of general interest.
  369.  
  370.  
  371.  
  372.  
  373.  
  374.                           3 Introduction
  375.  
  376.  
  377. Both for historical and practical reasons this library is presented as two
  378. distinct, independent sections. The database part is called CSDB
  379. which is short for Combits Software DataBases, the other section, CSA,
  380. contains general purpose, and portability functions.
  381.  
  382. This library concentrates on supplying a C++ software developper with
  383. the means to quickly implement database and database-alike
  384. functionality in his/her applications. This is done by supplying a set of
  385. easy-to-use C++ classes. There are classes for fixed lenght records,
  386. variable length records, indexes and so fort.
  387.  
  388. In addition, a program generator, CSDBGEN, is available, which uses
  389. the database classes in this library as building blocks for other, more
  390. complex and powerful, databases.
  391.  
  392. There are also classes in CSDB which operate in the grey area betweeen
  393.  file-extensions' and  databases'. Because these classes tackle the
  394. limitations of standard file IO on a very low level, they are very flexible
  395. and can therefore be of great value when the approach of the traditional
  396. database proves too rigid.
  397.  
  398. This library does not pretend to compete with the multi-user Database
  399. Management systems. Its purpose is to supply a rich set of tools to
  400. overcome the disk-storage problems occurring in single-user
  401. applications.
  402.  
  403.  
  404.                             4 Overview
  405.  
  406.  
  407. This chapter will give a quick overview of the contents of the package.
  408.  
  409. The CSDB section contains (mainly) the following classes:
  410.     TBASE:      A class for reading and writing fixed length records.
  411.     BTREE:      A btree+ to be used as an index.
  412.     VRAM:       A 'database' organized as a heap.
  413.     VBASE:      A database class for variable length records.
  414.     VBAXE:      As VBASE but for very large databases.
  415.     OLAY:       A file system which can insert and delete!
  416.     DLAY:       As OLAY but for large files.
  417.     IBASE:      Fixed length records but with the ability to insert or
  418.                 delete a record anywhere in the database.
  419.  
  420. The CSA section contains general-purpose functions and classes.
  421. Among others, the following classes are included:
  422.     csDATE:     To store and manipulate dates.
  423.     csTIME:     To represent the time.
  424.     csSTR:      Strings.
  425.     CSDIR:      To traverse a directory.
  426.     QALLOC:     Quick and dirty way to do dynamic memory
  427.                 allocations.
  428.     HEAP:       To efficiently allocate many small blocks from the
  429.                 heap.
  430.  
  431. Command line utilities (DOS, NT, OS/2, Linux):
  432.  
  433.     CSDIR:      Lists the CS-databases in a directory.
  434.     CSINFO:     Displays information about a CS-database.
  435.     CSDBGEN:    Important program generator.
  436.     CSERROR:    Utility to convert the error file to C++ source.
  437.     CSKEYS:     Displays the return value of the cskey() function.
  438.     CSMALLOC:   Tests the allocation log for memory leaks.
  439.     CS4DBASE:   Conversion utiltity to read dBASE files.
  440.  
  441.  
  442.  
  443.  
  444.                             5 Debugging
  445.  
  446.  
  447. Of each library two versions exist, one to be used during debugging
  448. and one intended for normal 'production'. The difference is that in
  449. the debug-version a lot more tests are done, and so many more errors
  450. are reported.
  451.  
  452. The idea is to use the debug version during development and recompile
  453. with the production version when ready. The debug version is identical to
  454. the production version, but with additional tests. The 'working code' is
  455. 100% identical. This means there are no subtle differences between the
  456. two versions.
  457.  
  458. The production version however can be substantial faster, up to two
  459. times, depending on the circumstances.
  460.  
  461. To give an example:
  462.     The TBASE class has a function to read a record from the database.
  463.     For this function to operate properly, the class/database needs to be
  464.     'opened'. In the debug version this is tested with every call to the
  465.     read function. In the production version it is never tested.
  466.     Note that in a decently written and tested application this error
  467.     should not occur.  Forgetting' to call the open function should be
  468.     corrected in the debugging fase and if the open function fails it
  469.     should be trapped well before the call to the read function.
  470.  
  471. There are many more errors like this. Errors that should not occur when
  472. the application is tested and (almost) ready but which can easily emerge
  473. in the development stage.
  474.  
  475.  
  476.  
  477.  
  478.                         6 Runtime Libraries
  479.  
  480.  
  481. There are many libraries included in the package but only one has to
  482. be linked in at any given time. They indeed have to be linked in
  483. because they are  static libraries', not  dynamic libraries'.
  484.  
  485.  
  486. The name of a library is build up according to the next syntax:
  487. Meaning:
  488.     - The first two characters are always  cs'
  489.     - The third character indicates the compiler:
  490.         B:  The Borland C++ compiler
  491.         W:  The Watcom C++ compiler
  492.         V:  The Visual C++ (Microsoft) compiler
  493.         G:  The GNU C compiler
  494.     - The fourth character indicates the platform:
  495.         D:  Dos
  496.         W:  Windows 16 bit
  497.         N:  NT, Windows95, Win32s
  498.         O:  OS/2
  499.         L:  Linux
  500.     - The fifth character indicates the memory model:
  501.         M:  Memory model (Dos, 16 bits Windows)
  502.         C:  Compact model (Dos, 16 bits Windows)
  503.         L:  Large model (Dos, 16 bits Windows)
  504.         H   Huge model (Dos, 16 bits Windows)
  505.         F:  Flat model (NT, OS/2, Linux)
  506.     - The sixth characters indicates debug or production version:
  507.         P:  Production
  508.         D:  Debugging
  509.     - The extension is always: .lib
  510.  
  511.  
  512.  
  513. Example:
  514.  
  515.    csBWCD.lib
  516.  
  517. This the 16 bits Windows library for Borland, using the Compact memory
  518. model and the Debug version.
  519.  
  520.  
  521. Of course not all combinations do exist. Not all plataforms are supported
  522. by all compilers and vice versa.
  523.     -   Linux is only supported by the GNU compiler.
  524.     -   The GNU compiler is only supported under Linux.
  525.     -   OS/2 is only supported by the Borland- and Watcom compilers.
  526.     -   The Compact, Large and Huge memory models are only
  527.         available under DOS and 16 bits Windows.
  528.     -   The flat memory model is only available under NT,OS/2 and
  529.         Linux.
  530.  
  531.  
  532.  
  533.                         7 Compiler Options
  534.  
  535.  
  536. With the ever growing number of compiler options it becomes
  537. increasingly harder to keep everybody happy. As a rule we take the
  538. compiler defaults, even if we know it isn't the fastest.
  539.  
  540. This chapter shows which options were used while compiling the
  541. CS Libraries. Some of the options are really  options', but a few others
  542. are crucial.
  543. In particular the  alignment' option can spell disaster. Some
  544. structures in the CSDB header files are alignment dependent
  545. and if the appropriate alignment option isn't used, the resulting
  546. executable will simple crash while no compiler-  or linker-error will ever
  547. be generated!
  548.  
  549.  
  550. 7.1 Hardware
  551.  
  552. Because the debug version isn't compiled for speed any way, we
  553. grasped the opportunity to assume  worst case' hardware. By doing so, it
  554. can be used to support out-dated hardware like the ancient 8086
  555. processor. Because we have this escape route, the production version
  556. can make reasonable assumptions about the available CPU. As a rule
  557. the DOS libraries are compiled for a 80286 CPU, 16 bits Windows
  558. libraries for a 80386 CPU and the 32 bits libraries for a 80486 CPU.
  559.  
  560.  
  561. 7.2 Floating point
  562.  
  563. There is almost no floating point arithmetic used in the CS-Libraries.
  564. However, a few functions use julian-date routines to e.g. calculate the
  565. number of days between two dates. If this is the case, this documentation
  566. will clearly mention it.
  567. Because floating point is used so rarely, we make very conservative
  568. assumptions about the available hardware support.
  569.  
  570.  
  571. 7.3 Watcom
  572.  
  573. Next the options used with the Watcom C++ compiler.
  574.  
  575. Debug version, 32 bits:
  576.     -3r -zld -otexn -zp1 -fpi -fp2 -bt=nt
  577.  
  578. Prodution version, 32 bits:
  579.     -5r -zld -otexn -zp1 -fpi -fp2 -s -bt=nt
  580.  
  581. Debug version, DOS:
  582.     -0 -zld -otexn -zp1 -fpi  -bt=dos
  583.  
  584. Prodution version, DOS:
  585.     -2 -zld -otexn -zp1 -fpi -s -bt=dos
  586.  
  587. Debug version, 16 bits Windows:
  588.     -3 -zw -zld -otexn -zp1 -fpi -bt=windows
  589.  
  590. Prodution version, 16 bits Windows:
  591.     -3 -zw -zld -otexn -zp1 -fpi  -s -bt=windows
  592.  
  593.  
  594. Explanation:
  595.     -0      8086 instructions.
  596.     -2      80286 instructions
  597.     -3      80386 instructions.
  598.     -3r     Register calling, assuming 80386 or better.
  599.     -5r     Register calling, optimized for pentium but runs on 386 or
  600.             better.
  601.     -zld    Suppress generation of library file names.
  602.     -otexn  Use all optimizations, except  no pointer aliasing'.
  603.     -zp1    1 byte packing of structures. (default) CRUCIAL!
  604.     -fpi    Support both emulation and 80x87, depending on how you
  605.             link.
  606.     -fp2    Use 80287 instructions.
  607.     -s      Don't check stack overflow.
  608.  
  609.  
  610. 7.4 Borland
  611.  
  612. Next the options used with the Borland C++ compiler.
  613.  
  614. Debug version, 32 bits:
  615.     -3 -N -G -O2 -k -f
  616.  
  617. Prodution version, 32 bits:
  618.     -4 -G -N- -O2 -k- -ff
  619.  
  620. Debug version, DOS:
  621.     -1- -N -f  -O2 -k -Ff
  622.  
  623. Prodution version, DOS:
  624.     -2 -N- -f -O2 -G -k- -Ff
  625.  
  626. Debug version, 16 bits Windows:
  627.     -3 -N -f -O2 -G -k -Ff -WSE
  628.  
  629. Prodution version, 16 bits Windows:
  630.     -3 -N- -f -ff -O2 -G -k- -Ff -WSE
  631.  
  632.  
  633. Explanation:
  634.     -1-     8086 instructions.
  635.     -2      80286 instructions
  636.     -3      80386 instructions.
  637.     -4      80486 instructions.
  638.     -f      Emulate floating point.
  639.     -ff     Fast floating point.
  640.     -O2     Fastest code.
  641.     -G      Optimize for speed.
  642.     -Ff     Automatic far data.
  643.     -k      Standard stack frame.
  644.     -k-     No standard stack frame.
  645.     -N      Check stack overflow.
  646.     -N-     Don't check stack overflow.
  647.  
  648. Defaults:   Signed characters.
  649.  
  650.  
  651. 7.5 Visual C++
  652.  
  653. Next the options used with the Visual C++ compiler.
  654.  
  655. Debug version, 32 bits:
  656.     -Og -Oi -Ot -Oy -Ob1 -Gf -Gy -GB -DWIN32
  657.  
  658. Prodution version, 32 bits:
  659.     -Gs -Og -Oi -Ot -Oy -Ob2 -Gf -Gy -GB -DWIN32
  660.  
  661. Debug version, DOS:
  662.     -f- -G0 -Ot -Ob1 -On -Oc -Oe -Og -Ol -Oo -Gf -Gy -D_DOS -Ge
  663.  
  664. Prodution version, DOS:
  665.     -f- -Gs -G3 -Ot -Ob2 -OV9 -On -Oc -Oe -Og -Ol -Oo -Gf -Gy
  666.     -D_DOS
  667.  
  668. Debug version, 16 bits Windows:
  669.     -f- -Oc -Oe -Og -Oi -Ol -On -Oo -Ot -Ob1 -G3 -Gf -Gy -Gw -Ge
  670.  
  671. Prodution version, 16 bits Windows:
  672.     -f- -Oc -Oe -Og -Oi -Ol -On -Oo -Ot -Ob2 -OV9 -G3 -Gf -Gy -Gw -Gs
  673.  
  674.  
  675. Explanation:
  676.     -Oc     Common subexpression optimization.
  677.     -Oe     Enable register allocation.
  678.     -Ol     Loop optimization.
  679.     -On     Disable  unsafe' optimizations.
  680.     -Oo     Post code optimization.
  681.     -Og     Global optimizations.
  682.     -Oi     Enable intrinsic functions.
  683.     -Ot     Favor code speed.
  684.     -Oy     Enable frame pointer omission.
  685.     -Ob1    Expand only  __inline' functions.
  686.     -Ob2    Expand inline  any suitable' function.
  687.     -OV9    Expand even  large' inline functions.
  688.     -Gf     String pooling.
  689.     -Gy     Separate functions.
  690.     -GB     'Blended' CPU.
  691.     -Gs     No stack checking.
  692.     -Ge     Enable stack checking.
  693.     -f-     Select optimizing compiler.
  694.     -G0     8086 instructions
  695.     -G2     80286 instructions
  696.     -G3     80386 instructions.
  697.  
  698.  
  699.                   8 Standard Types & Definitions
  700.  
  701. This chapter describes some types and definitions used throughout
  702. this library. They are platform independent and therefore portable.
  703.  
  704. Defined in cstools.h:
  705.  
  706.     FALSE       0
  707.     TRUE        1
  708.  
  709. Types defined in cstypes.h:
  710.  
  711.     S8:         Singed 8 bit,
  712.     U8:         Unsigned 8 bit,
  713.     S16:        Singed 16 bit
  714.     U16:        Unsigned 16 bit
  715.     S32:        Singed 32 bit
  716.     U32:        Unsigned 32 bit
  717.     csCHAR:     Signed character
  718.  
  719. These definitions are used extensively in the function prototypes.
  720.  
  721. However, on many occasions (particularly function returns) the range of
  722. the variable is not (all that) important. In these cases int s are used
  723. because that's normally the fastest.
  724.  
  725.  
  726. The accompanying max & min values are also defined:
  727.  
  728.  
  729.     S8_MIN:     -128
  730.     S8_MAX:      127
  731.     U8_MAX:      255
  732.     S16_MIN:    -32768
  733.     S16_MAX:     32767
  734.     U16_MAX:     65535
  735.     S32_MIN:    -2147483648
  736.     S32_MAX:     2147483647
  737.     U32_MAX:     4294967295
  738.  
  739.  
  740.  
  741.                    9 Runtime Errors and Messages
  742.  
  743.  
  744. As a rule, errors are signaled by a return value of FALSE, rather then
  745. by a visible message. In this way controle over runtime messages is
  746. placed in the hands of the developer using our libraries.
  747. On the other hand, we try to strike a balance between ease-of-use and
  748. controle. Having to check the return value of each and every function to
  749. trap highly unlikely errors, rapidly becomes very cumbersome.
  750.  
  751.  
  752. 9.1 What to expect?
  753.  
  754. The main rule is to expect a return value of TRUE on success and a
  755. value of FALSE in case of failure.
  756. However, sometimes a message is displayed and there are even cases
  757. where the exit() function is called.
  758.  
  759.  
  760. We distinguish a few categories of errors:
  761.     - Extremely Improbable Error
  762.         Normally meaning hardware failure. Because it's so unlike, you
  763.         will be tempted to  forget' testing the return value because  it will
  764.         never go wrong'.
  765.         A visible message is generated.
  766.     - Misuse of Functions
  767.         Calling functions in the wrong order, calling functions with wrong
  768.         parameters, etc.. Because this type of error should only occur in
  769.         the earliest development stage, during debugging, we think it's
  770.         justified to display a message or even exit the program.
  771.         It is typical for the debug versions of the libraries to test for this
  772.         type of error.
  773.     - Irrecoverable Error
  774.         The kind of error that occurs many function calls deep. In
  775.         particular the dreaded  out of memory' error (often) falls in this
  776.         category. Only event-handling can deal with this type of error
  777.         but we don't use it because of its considerable drawbacks.
  778.         A message is displayed and the exit() function is called.
  779.  
  780.  
  781. 9.2 Changing the way messages are displayed
  782.  
  783. All the message functions eventually display their messages through a
  784. call to csmess_disp(char *). Under DOS, this function writes the
  785. message to the screen by using the standard puts() function. With
  786. Windows (16 & 32 bits) a standard message box is called.
  787.  
  788. Fortunate, this function can easily be altered!
  789. Before being displayed by the csmess_disp() function, every message is
  790. converted into a single string. This makes changing the message
  791. function very easy. Only a single function, which accepts a character
  792. pointer, needs to be supplied.
  793.  
  794. The next function is intended to do that:
  795.  
  796. void csmess_set_fun( void (* fun)(char *));
  797.  
  798.  
  799. //  Example (Dos):
  800.  
  801.     #include "csmess.h"
  802.       void display(char *s)
  803.       {
  804.          //  This function is going to be used
  805.          //  to display messages.
  806.          printf("%s",s);
  807.       }
  808.       void main(void)
  809.       {
  810.           csmess_set_fun(display);
  811.           //  From now on, all the messages are
  812.           //  displayed by calling the  'display()' function.
  813.      }
  814.  
  815.  
  816.  
  817. To restore the default, the next function can be used:
  818.  
  819. void csmess_reset_fun(void);
  820.  
  821.  
  822. //  Example:
  823.  
  824.       void main(void)
  825.       {
  826.           csmess_reset_fun();
  827.           // Restores the default
  828.           // Display function.
  829.       }
  830.  
  831.  
  832. Function prototypes are in csmess.h.
  833.  
  834.  
  835. 9.3 Message related functions
  836.  
  837. The entire mechanisme of displaying messages can be switched on and
  838. off with the a few (global) functions. To avoid confusion: these are normal
  839. C-type functions, not C++ class member functions.
  840.  
  841. Function prototypes are in csmess.h.
  842.  
  843. void csmess_off(void);
  844.                 With this function, messages can be suppressed.
  845.                 Whether you are using the standard message function
  846.                 or has it replaced with your own, after a call to this
  847.                 function no message will be displayed.
  848.  
  849. void csmess_on(void);
  850.                 To be used in conjunction with the csmess_off()
  851.                 function. After a call to 'csmess_on()' messages will be
  852.                 displayed again.
  853.  
  854. int csmess_onoff(void);
  855.                 Returns TRUE if message displaying is switched on,
  856.                 FALSE otherwise.
  857.  
  858. void csmess_onoff(int sw);
  859.                 If called with sw unequal zero, messages will be
  860.                 displayed. Otherwise not.
  861.  
  862.  
  863. //  Example (DOS):
  864.  
  865. #include "csmess.h"
  866.  
  867.       void work(void)
  868.       {
  869.         // Switch messages off.
  870.           csmess_off();
  871.         // Execute some critical code.
  872.           csmess_on();
  873.             // Switch messages back on.
  874.       }
  875.  
  876.       void main(void)
  877.       {
  878.                work();
  879.       }
  880.  
  881.  
  882.  
  883.  
  884. 9.4 Database class messages
  885.  
  886. Sofar we have been discussing the global message functions. On top of
  887. that, all database classes have a few message functions too.
  888.  
  889. If a functions fails, it returns a value of FALSE, but it also sets the value
  890. of a local error variable. Each class instance has its own error variable
  891. and a member function to set, and to read it.
  892.  
  893. U16 error_nr(void);
  894.                 This function returns the value of the error variable.
  895.                 After the function call, the value is reset to zero. All the
  896.                 database classes from the CSDB-Library have this
  897.                 member functions.
  898.  
  899.  
  900.  
  901.  
  902.  
  903. //  Example (DOS):
  904.  
  905.     #include "iostream.h"
  906.     #include "cstbase.h"
  907.  
  908.       int main(void)
  909.       {
  910.  
  911.         TBASE tb;   // A database for fixed length records.
  912.                 // Documented in chapter 15.
  913.         if(!tb.open("example.dbf"))
  914.         {
  915.             cout<<"Error nr: "<<tb.error_nr()<<endl;
  916.             return 1;
  917.         }
  918.  
  919.         return 0;
  920.       }
  921.  
  922.  
  923.  
  924. void error_nr(U16 ErrNr);
  925.                 Sets the value of the error variable. All the database
  926.                 classes from the CSDB-Library have this member
  927.                 functions. (Mainly intended for internal use.)
  928.  
  929.  
  930. U16 display_error(void);
  931.                 Obtains the latest error by calling  error_nr()'. This
  932.                 error number is then converted into a string by reading
  933.                 the  error.err' message file. Finally, it's displayed by
  934.                 using the global message functions described in the
  935.                 first part of this chapter. If the obtained error number is
  936.                 zero, no message is displayed. The return value is the
  937.                 error number. On return, the value of the error variable
  938.                 will be  reset to zero.
  939.                 All the database classes from the CSDB-Library have
  940.                 this member functions.
  941.  
  942.  
  943.  
  944.  
  945. //  Example (DOS):
  946.  
  947.     #include "iostream.h"
  948.     #include "cstbase.h"
  949.  
  950.       int main(void)
  951.       {
  952.         TBASE tb; // A database for fixed length records.
  953.         if(!tb.open("example.dbf"))
  954.         {
  955.             tb.display_error();
  956.             return 1;
  957.         }
  958.         return 0;
  959.       }
  960.  
  961.  
  962.                         10 Temporary files
  963.  
  964.  
  965. Temporary files are created through the use of the cstmpname()
  966. function, discussed in the CSTOOLS chapter 28.
  967. This means, the environment variables TEMP and TMP are checked  to
  968. determine which subdirectory has to be used. TMP is checked first and if
  969. it doesn't exist, TEMP is checked.
  970. Temporary files can be as large as the databases they are belonging to.
  971. So, make sure the environment variables don' t point to some small ram-disk or an insufficiently large partition.
  972.  
  973.  
  974.  
  975.  
  976.  
  977.  
  978.  
  979.  
  980.  
  981.  
  982.  
  983.  
  984.  
  985.  
  986.  
  987.  
  988.  
  989.  
  990.  
  991.  
  992.  
  993.  
  994.  
  995.  
  996.  
  997.  
  998.  
  999.                                Part
  1000.  
  1001.                                Two
  1002.  
  1003.  
  1004.  
  1005.  
  1006.  
  1007.  
  1008.  
  1009.  
  1010.  
  1011. Part Two of the documentation starts with a few chapters that apply
  1012. to all database classes. Further on, it will explain how this library
  1013.      can be used to build traditional relational databases.
  1014. To do so, it uses a TBASE class to store records and a BTREE class
  1015.                           for indexes.
  1016.   A program generator, CSDBGEN, is discussed which 'automates'
  1017.  the process of building more complex databases out of TBASE and
  1018.                              BTREE.
  1019. These two classes can also be used seperately. In particular the
  1020. BTREE class is very useful. It is really easy expandable and can be
  1021. tailored to a specific purpose by supplying one single function.
  1022. Simple databases with only one index can be build with just the
  1023.                            BTREE class.
  1024.  
  1025.  
  1026.  
  1027.                            11 Buffering
  1028.  
  1029.  
  1030. Except for RBASE, all database classes are build on top of a very
  1031. solid buffer system. This buffer system lets you control how much
  1032. memory can to be used for buffering. All the database classes offer the
  1033. opportunity to specify this amount with the call to the open() function.
  1034. This implies that the buffer size can be specified for every class instance
  1035. individually!
  1036.  
  1037. Buffers are allocated on the fly, up to the maximum specified. The
  1038. advantage is that the maximum may never be reached, saving valuable
  1039. memory for other purposes.
  1040.  
  1041. The buffering-system itself will stop allocating memory when the
  1042. heap is exhausted, but if dynamic memory allocation is used
  1043. somewhere further on, your program may still terminate with a
  1044. message of the type 'out of memory'.
  1045.  
  1046. It should be noted that this is only a problem with the MS-DOS operating
  1047. system. Any other (real) operating system uses virtual memory which
  1048. makes sure that your program will work with any reasonable assumption
  1049. about the available amount of memory.
  1050.  
  1051. For performance reasons, however, it is better not to rely on virtual
  1052. memory. If you allocate more buffers then the OS is capable of holding in
  1053. physical memory, performance will drop dramatically. Buffers which are
  1054. paged out, are far worse then no buffers at all!
  1055.  
  1056.                            12 PAGE-Class
  1057.  
  1058. 12.1 Introduction
  1059.  
  1060. The PAGE-class constitutes a  kind of 'foundation'  for most of the
  1061. other classes in the CSDB library.  It is derived from a class 'BUFF'
  1062. which takes care of the required buffering. (Described in chapter 11.)
  1063.  
  1064. The idea is to do disk IO in chunks of 2 Kb. This is close to the optimal
  1065. size for the average harddisk. These blocks are kept aligned with the
  1066. sectors of the harddisk, which improves speed considerablely.
  1067. A harddisk always reads an entire sector, even if you only need, let's say,
  1068. 10 bytes. Things become even worse if the 10 bytes you are requesting
  1069. just happen to cross a sector boundary. In that case the harddisk will
  1070. read 2 entire sectors. Assuming a sector is 1024 bytes, this means that
  1071. 2*1024=2048 bytes are read just to obtain your 10 bytes!
  1072.  
  1073. To avoid this kind of inefficiency, the PAGE-class does its disk IO in
  1074. pages of 2048 bytes while making sure every page is aligned with the
  1075. harddisk sectors. This also means that the indispensable file-header has
  1076. to be at least one sector. To avoid complications, a file-header is used
  1077. which has the same size as a page, 2048 bytes by default.
  1078.  
  1079. It should be noted that this entire scene is undone by using a
  1080. disk compression utility, like double space, stacker and the
  1081. alike.
  1082.  
  1083. Therefore, if you are concerned about performance, it is better not to use
  1084. these utilities. More over, a disk compressor will slow down your
  1085. application considerably when several files are used heavily 'at the same
  1086. time'.  This situation will almost inevitably arise with any serious
  1087. application which uses more then one database, or even a single
  1088. database with many indexes.
  1089.  
  1090.  
  1091. 12.2 Storing data in the header-page
  1092.  
  1093. As explained above, the header page is quite large. This page is used to
  1094. store al kind of important variables. However, there is still much space
  1095. left. Of the 2048 bytes, only about 170 are used.
  1096.  
  1097. An application using databases is like to have some variables of his own
  1098. which need to be saved between close/open sequences. It seems the
  1099. remaining space in the header page is a convenient place store such
  1100. data. This can save you an additional configuration file and all the error
  1101. trapping involved.
  1102.  
  1103. To aid in this, three functions are made public:
  1104.     int data_2_header(void * ptr,U16 length);
  1105.     int header_2_data(void * ptr,U16 length);
  1106.     U16 max_data_in_header(void);
  1107.  
  1108. U16 max_data_in_header(void);
  1109.                 This function returns the maximum number of bytes
  1110.                 which will still fit in the header page. This is simply the
  1111.                 size of the header-page minus what is used to store
  1112.                 the variables of the class.
  1113.                 The class needs to be open.
  1114.  
  1115. int data_2_header(void * buffer,U16 length);
  1116.                 Copies data from buffer 'buffer' to the empty space in
  1117.                 the header page. The variable 'length' indicates the
  1118.                 number of bytes to be copied. This figure is not stored
  1119.                 anywhere. It is the programmers' responsibility to
  1120.                 retrieve the right number of bytes later on.
  1121.                 The class needs to be open. TRUE is returned on
  1122.                 success, FALSE otherwise.
  1123.  
  1124. int header_2_data(void * buffer,U16 length);
  1125.                 The counterpart of the previous function. This function
  1126.                 copies 'length' number of bytes from the header page
  1127.                 to 'buffer'.
  1128.                 The class needs to be open. TRUE is returned on
  1129.                 success, FALSE otherwise.
  1130.  
  1131.  
  1132.                            13 Lock files
  1133.  
  1134.  
  1135.  
  1136. To prevent multiple applications from accesing the same database,
  1137. lock files are created whenever a database is opened for writing. The
  1138. lock files are removed when the database is closed again. If a database
  1139. is opened in read-only mode, no lock file will be generated.
  1140.  
  1141. When an attempt is made to open a database while the lock file exists,
  1142. an error is generated.
  1143.  
  1144.  
  1145. 13.1 Name of a lock file
  1146.  
  1147. The name of the lock file is derived from the database name by replacing
  1148. the first two characters of the extension by exclamation marks. Under
  1149. Linux, everything after the last dot is considered the  extension'. If no
  1150. extension exists, an extension consisting of two exclamation marks will
  1151. be added to the database name to form the name of the lock file.
  1152.  
  1153.  
  1154.  
  1155.  Example:
  1156.  
  1157.     Database name               Lock file name
  1158.     -------------               --------------
  1159.  
  1160.     database.dbf                database.!!f
  1161.     db.strings.index            db.strings.!!dex
  1162.     data                        data.!!
  1163.  
  1164.  
  1165.  
  1166. csCHAR *lock_file_name(csCHAR *DBName,csCHAR *LockName);
  1167.                 This global C function can be used to obtain the name
  1168.                 of a lock file.  DBName' is the name of the database,
  1169.                  LockName' must be a pointer to a buffer large
  1170.                 enough to hold the name of the lock file.  The function
  1171.                 fills the  LockName' buffer with the name of the lock file
  1172.                 corresponding with database  DBName'.
  1173.                 The return value is the  LockName' pointer.
  1174.  
  1175.  
  1176. 13.2 Controlling lock files
  1177.  
  1178. Next is a set of member functions, common to every database class,
  1179. which can be used to control lock files.
  1180.  
  1181. void use_lock_file(int TrueOrFalse);
  1182.                 When called with FALSE, the use of lock files is
  1183.                 switched off. When called with TRUE, the use of lock
  1184.                 files is switched on. The class default is to use locking.
  1185. int use_lock_file(void);
  1186.                 Returns TRUE if the use of lock files is switched on,
  1187.                 FALSE otherwise.
  1188. int lock_file_exist(csCHAR *DBNAME);
  1189.                 This function accepts the name of a database file and
  1190.                 returns TRUE if the corresponding lock file exists.
  1191.                 Otherwise it returns FALSE.
  1192.                 At least one class in this library uses two files to store
  1193.                 its data. Therefore checking for lock files is a process
  1194.                 which depends on the type of database used. This is
  1195.                 why this is a class member function rather then a
  1196.                 global C function.
  1197. int remove_lock_file(csCHAR *DBNAME);
  1198.                 This function takes the name of a database, calculates
  1199.                 the corresponding lock file name and tries to remove
  1200.                 that. If the lock file doesn't exist or couldn't be
  1201.                 removed, the function returns FALSE. Otherwise it
  1202.                 returns TRUE.
  1203.  
  1204.  
  1205.  
  1206. // Example:
  1207. // Error checking omitted for conciseness.
  1208.  
  1209.     #include "iostream.h"
  1210.     #include "csvbaxe.h"
  1211.  
  1212.       void main(void)
  1213.       {
  1214.         VBAXE vb;
  1215.  
  1216.         if(vb.lock_file_exist("example.dbf"))
  1217.         {
  1218.             cout<<"The lock file exists"<<endl;
  1219.             vb.remove_lock_file("example.dbf"))
  1220.             cout<<"The lock file is removed"<<endl;
  1221.         }
  1222.  
  1223.         vb.open("example.dbf");
  1224.             //
  1225.             // Use the database.
  1226.             //
  1227.         vb.close();
  1228.  
  1229.       }
  1230.  
  1231.  
  1232.  
  1233.                       14 Read-Only databases
  1234.  
  1235. It is possible to open a database in read-only mode. If done so, no
  1236. changes can be made and no time-stamps will be updated. On the
  1237. level of the operating system the database file is also openend  read-only'
  1238. which makes it possible to use static databases on read-only
  1239. devices like CD-ROMS.
  1240.  
  1241. It is valid to open an database in read-only mode while it is already in use
  1242. by another program. That is, the existence of lock files will not result in an
  1243. runtime error.
  1244.  
  1245.  
  1246. Trying to add, delete or write records while in read-only mode is
  1247. considered an error and therefore should be avoided. Still, with
  1248. the current implementation, writing an record is simply ignored
  1249. while adding or deleting result in a runtime error. This behaviour may
  1250. change with future releases, please do not rely on it!
  1251.  
  1252.  
  1253. 14.1 Class member functions
  1254.  
  1255. Next a set of class member function, common to all database classes,
  1256. which control the application of the  read-only' mode.
  1257.  
  1258. int read_only(int TrueOrFalse);
  1259.                 When called with TRUE, the database is opened in
  1260.                 read-only mode. Otherwise the database is opened for
  1261.                 writing. The function has to be called before the
  1262.                 database is opened! It is an error to call read_only()
  1263.                 while the database is already open.
  1264.                 The function returns TRUE on success, FALSE
  1265.                 otherwise.
  1266. int read_only(void);
  1267.                 Same as read_only(TRUE);
  1268. int is_read_only(void);
  1269.                 The function returns TRUE if the database is opened
  1270.                 in read-only mode, FALSE otherwise.
  1271.  
  1272.  
  1273.  
  1274. //  Example:
  1275. // Error checking omitted for conciseness.
  1276.  
  1277.     #include "iostream.h"
  1278.     #include "csdlay.h"
  1279.  
  1280.       void main(void)
  1281.       {
  1282.         DLAY vb;                // The miracle class.
  1283.  
  1284.         char some_data[100];
  1285.  
  1286.         vb.define("example.dbf");   // Create database.
  1287.  
  1288.         vb.read_only();         // Before open().
  1289.         vb.open("example.dbf");     // Open database
  1290.  
  1291.         // Test for read-only mode and append some data.
  1292.         if(!vb.is_read_only()) vb.append(some_data,7);
  1293.         else                   cout<<"Read only, cannot append data."<<endl;
  1294.  
  1295.         vb.close();             // Close database.
  1296.       }
  1297.  
  1298.  
  1299.  
  1300.  
  1301.                           15 TBASE-class
  1302.  
  1303.  
  1304. 15.1 Introduction
  1305.  
  1306. The TBASE class is intended as a simple, fast way to access records
  1307. on disk. It assumes a fixed record size and does its IO on a record-by-record basis (contrary to field-by-field).
  1308.  
  1309. This means:
  1310.     1) TBASE is unaware of something like 'fields'. The idea is to use  a
  1311.         C structure as record and to do all the accessing of fields with
  1312.         the standard C operators. This approach is undoubtedly faster
  1313.         then supporting access on a field-by-field basis as done by
  1314.         dBASE.
  1315.     2) No indexes. TBASE just reads or writes records, nothing else.
  1316.  
  1317. NOTE:   From this it is clear that with the TBASE class alone no decent
  1318.         database application can be build. Therefore, a separate
  1319.         BTREE class is supplied which can be used as an index.
  1320.  
  1321.  
  1322. 15.2 Using TBASE
  1323.  
  1324. The next small example gives an impression of how to use the class.
  1325.  
  1326. As can be seen from this example, there is no 'record pointer' as in
  1327. dBASE. The functions to read and write a record, simply take an
  1328. additional parameter indicating the record number.
  1329.  
  1330.  
  1331.  
  1332. // A very simple example.
  1333. // Error checking omitted for conciseness.
  1334.  
  1335.   # include "CSTBASE.H"
  1336.  
  1337.    void main(void)
  1338.    {
  1339.        typedef struct
  1340.        {
  1341.         char name[20];          // The field 'name'
  1342.         char street[40];        // The field 'street'
  1343.         long salary;            // The field 'salary'
  1344.         // All the other fields you may require.
  1345.        }record;                 // The record layout is now defined.
  1346.  
  1347.        TBASE db;
  1348.        record rec;
  1349.  
  1350.        db.open("demo.dbf",110);  // Assuming the file is already created.
  1351.                                  // Use 110 Kb for buffering.
  1352.        db.read_rec(9,&rec);      // Read record number 9 into
  1353.                                  // variable 'rec'.
  1354.        rec.salary=0;             // Change salary.
  1355.        db.write_rec(9,&rec);     // Write the record back to position 9.
  1356.                             // (Any other existing position is also possible.)
  1357.        db.close();          // Is also done automatically
  1358.                             // by the class destructor.
  1359.     }
  1360.  
  1361.  
  1362.  
  1363.  
  1364.  
  1365. 15.3 Creating a Database
  1366.  
  1367. Before a database can be used it has to be 'created'. This is done
  1368. through a call to the 'define()' function. Of course this is needed only
  1369. once.
  1370. Because TBASE doesn't use fields, the function takes only two
  1371. parameters: the filename of the database, and the record size.
  1372.  
  1373. Syntax: int define(char * name,U16 reclen);
  1374.  
  1375.  
  1376. //   This example creates a database 'demo.dbf'.
  1377.  
  1378.     #include "iostream.h"
  1379.     #include "CSTBASE.H"
  1380.     void main(void)
  1381.     {
  1382.        typedef struct
  1383.        {
  1384.           char name[20];
  1385.           char street[40];
  1386.           char city[25];
  1387.        } record;
  1388.  
  1389.        TBASE db;
  1390.        if(!db.define("demo.dbf",sizeof(record)))
  1391.        {       // Return value FALSE: display the error.
  1392.            db.display_error();
  1393.        }
  1394.  
  1395.    }
  1396.  
  1397.  
  1398.  
  1399. 15.4 Opening
  1400.  
  1401. Before a record can be read, the database has to be opened through a
  1402. call to the open() function.
  1403.  
  1404. This open() function also takes a parameter indicating the amount of
  1405. memory to be used for buffering. The memory for the buffers is NOT
  1406. allocated at the moment of the call to open(), but during the use of the
  1407. database. Memory is allocated when needed, up to this maximum.
  1408.  
  1409. As explained in chapter 11 about buffering, using up too much
  1410. memory for buffering is dangerous on an operating system
  1411. without virtual memory like MS-DOS.
  1412.  
  1413. Syntax: int open(char *name, S16 kb=32);
  1414.  
  1415.  
  1416.   // Example:
  1417.   // Opening the existing database 'demo.dbf' with 40 Kb for buffers.
  1418.  
  1419.    #include "CSTBASE.H"
  1420.    void main(void)
  1421.    {
  1422.        TBASE db;
  1423.        if(!db.open("demo.dbf",40)) db.display_error();
  1424.    }
  1425.  
  1426.  
  1427.  
  1428. 15.5 Closing
  1429.  
  1430. Closing the database involves writing all the buffered data back to disk
  1431. and freeing all allocated memory. The close() function is intended for this
  1432. purpose. If the close() function is not explicitly called in the application,
  1433. the class destructor will call it.
  1434.  
  1435. Because there can be a long interval between the last time the database
  1436. is used and the moment where the destructor is reached, it still makes
  1437. sense to call the close() function 'by hand'.
  1438.  
  1439. Syntax: int close(void);
  1440.  
  1441.  
  1442. // Example:
  1443. // Error checking omitted for conciseness.
  1444.  
  1445.     #include "CSTBASE.H"
  1446.     void main(void)
  1447.     {
  1448.        TBASE db;
  1449.  
  1450.        db.open("demo.dbf",40);
  1451.        db.close();
  1452.     }
  1453.  
  1454.  
  1455.  
  1456. 15.6 Appending Records
  1457.  
  1458. A special function is needed to add a record to a database: the
  1459. append_rec() function.
  1460. Note: The write_rec() can only overwrite an already existing record.
  1461.  
  1462. Syntax: S32 append_rec(void *data);
  1463.                 'data' is a pointer to a record.
  1464.  
  1465. Syntax: S32 append_rec(void);
  1466.                 This function can be used to add a record to the
  1467.                 database without instantly filling it with a record. For
  1468.                 the time being, this record will contain 'garbage'.
  1469.  
  1470. // Example:
  1471. // Error checking omitted for conciseness.
  1472.  
  1473.     #include "CSTBASE.H"
  1474.     void main(void)
  1475.     {
  1476.       typedef struct
  1477.       {
  1478.          char name[20];
  1479.          char street[40];
  1480.          char city[25];
  1481.       } record;
  1482.  
  1483.       TBASE db;
  1484.       record rec;
  1485.  
  1486.       db.define("demo.dbf",sizeof(record));   //Create new database
  1487.  
  1488.       db.open("demo.dbf",40);
  1489.  
  1490.       strcpy(rec.name,"J.Q. Querlis ");
  1491.       strcpy(rec.street,"Avenue 120");
  1492.       strcpy(rec.city,"Bombay");
  1493.  
  1494.       db.append_rec(&rec);            // The database now contains 1 record.
  1495.       db.close();
  1496.    }
  1497.  
  1498.  
  1499.  
  1500. 15.7 Deleting Records
  1501.  
  1502. Deleting a record cannot be accomplished instantaneously. A 'delete bit'
  1503. is used to distinguish deleted records.
  1504.  
  1505. Deleting a record by setting the 'delete bit' doesn't alter much. E.g. record
  1506. 9 remains record 9 if you delete record 8.
  1507. The function 'is_delet()' has to be called to detect whether-or-not a record
  1508. is 'deleted'.
  1509.  
  1510. The 'pack()' function can be used to physically remove all the deleted
  1511. records from the file.
  1512.  
  1513. int is_delet(long r);
  1514.                 Returns 0 if the record 'r' is not deleted, and 1
  1515.                 otherwise.
  1516.  
  1517. void delet(long r);
  1518.                 Sets the delete bit for record 'r'.
  1519.  
  1520. void undelet(long r );
  1521.                 Resets the delete bit for record 'r'.
  1522.  
  1523. void pack(void);
  1524.                 Removes all the records with the delete bit set from the
  1525.                 database. This is done without the use of temporary
  1526.                 files.
  1527.  
  1528.  
  1529. 15.8 Page Utilization
  1530.  
  1531. Normally the TBASE class does its IO in pages of 2 Kb. It fits an integer
  1532. number of records on these pages. This approach can lead to a large
  1533. chunk of unused space on the pages, particularly if you are using large
  1534. records. On average the slack will be a half record.
  1535.  
  1536. Solution:
  1537.     This waste of disk space can be avoided by using pages which have
  1538.     the same size as the record. This means that the pages will no
  1539.     longer be aligned with the sectors of your harddisk!
  1540.  
  1541. The function to accomplish this is:  smallest_page().
  1542.  
  1543. The define() function of TBASE considers slacks up to 30% acceptable. If
  1544. it doesn't manage to find a page size which produces a slack of less then
  1545. 30%, it calls smallest_page().
  1546.  
  1547. void smallest_page(void);
  1548.                 The function has to be called before the define()
  1549.                 function. Because this changes the entire layout of the
  1550.                 database file, this cannot be altered once the
  1551.                 database is created.
  1552.  
  1553.  
  1554. // Example:
  1555. // Error checking omitted for conciseness.
  1556.  
  1557.     #include "CSTBASE.H"
  1558.  
  1559.     void main(void)
  1560.     {
  1561.  
  1562.        typedef struct
  1563.        {
  1564.           char name[20];
  1565.           char street[40];
  1566.           char city[25];
  1567.        } record;
  1568.  
  1569.        TBASE db;
  1570.  
  1571.        db.smallest_page();                 //Before the define!
  1572.  
  1573.        db.define("demo.dbf",sizeof(record));
  1574.  
  1575.    }
  1576.  
  1577.  
  1578.  
  1579. 15.9 Locating Records
  1580.  
  1581. In the examples given so far, a record is first read into a local variable
  1582. and, after being altered, written back to disk. It seems there is room for
  1583. improvement here. After the record is copied into the local variable it is in
  1584. memory twice, once in the variable and again in the database buffers.
  1585.  
  1586. If you know what you are doing, some performance increase can be
  1587. gained from obtaining a pointer directly into the buffer system.
  1588. The 'locate_rec()' function does just that.
  1589.  
  1590. When you are working in the database buffers through a pointer, there is
  1591. no way the buffer system can tell if data is altered. Therefore, it's the
  1592. programmers' responsibility to indicate whether or not modifications are
  1593. going to take place.
  1594.  
  1595. char *locate_rec(long rec);
  1596.                 This function returns a pointer to record 'rec'. It
  1597.                 assumes that no alterations are going to take place.
  1598.                 This means that the buffer is not written back to disk!
  1599.  
  1600. char *locate_rec_d(long rec);
  1601.                 The additional '_d' stands for dirty buffer. The function
  1602.                 returns a pointer to record 'rec'. It is assumed
  1603.                 alterations ARE going to take place. The buffer is
  1604.                 marked  dirty' and is therefore written back to disk
  1605.                 when memory is needed to store another page.
  1606.  
  1607.  
  1608. IMPORTANT!!
  1609. The locate functions return a pointer directly into the buffer
  1610. system. Nothing less and nothing more. Any member function
  1611. of the same class instance which MAY cause disk IO, can therefore alter
  1612. the contents of the buffers, making your pointer 'point' to an entirely
  1613. different record! When using these functions, it is highly advisable to do
  1614. all the reading or writing to the record before calling any other TBASE
  1615. member function.
  1616.  
  1617.  
  1618.  
  1619.  
  1620.  
  1621. // Example, of the locate_ function.
  1622. // Error checking omitted for conciseness.
  1623.  
  1624.     #include "CSTBASE.H"
  1625.  
  1626.     void main(void)
  1627.     {
  1628.  
  1629.        typedef struct
  1630.        {
  1631.           char name[20];
  1632.           int age;
  1633.        } record;
  1634.  
  1635.        TBASE db;
  1636.        record *rec;
  1637.  
  1638.        db.define("demo.dbf",sizeof(record));
  1639.        db.open("demo.dbf");                // Use default 32 Kb for buffers.
  1640.  
  1641.        for(int i=1;i<=12;i++) db.append_rec(); // Append 12 records.
  1642.  
  1643.        rec=(record *)db.locate_rec_d(7);       // Obtain pointer to record 7.
  1644.                                    // '_d' because we will 'write'.
  1645.  
  1646.        rec->age=34;                // That's all it takes to make an
  1647.                                    // alteration. No need for a
  1648.                                    // 'write' function.
  1649.        db.close();                 // Not strictly necessary.
  1650.  
  1651.    }
  1652.  
  1653.  
  1654.  
  1655. 15.10 Functions in alphabetical order.
  1656.  
  1657. Function prototypes are in 'cstbase.h'.
  1658.  
  1659. S32 append_rec(void *data);
  1660.                 Append a record to the database. The newly created
  1661.                 record is filled with the data from buffer 'data'. The
  1662.                 function returns the number of the new record (which is
  1663.                 equal to the number of records in the database).
  1664. S32 append_rec(void);
  1665.                 Same as the previous function, only this time the new
  1666.                 record is filled with binary zero's.
  1667. int close(void);    Closes the database. If the database is already closed,
  1668.                     nothing happens. TRUE is returned on success,
  1669.                     FALSE otherwise.
  1670. int define(char *name,U16  reclen);
  1671.                 Creates a TBASE file named 'name'. The parameter
  1672.                 'reclen' indicates the size of the records. TRUE is
  1673.                 returned on success, FALSE otherwise.
  1674. void delet(S32  rec);
  1675.                 Sets the delete bit of record 'rec'.
  1676. int empty(void);    Removes all the records from the database.
  1677.                     Afterwards there will be zero records left, but the
  1678.                     database will still be open. TRUE is returned on
  1679.                     success, FALSE otherwise.
  1680. int is_delet(S32  rec);
  1681.                 Returns the value of the delete bit of record 'rec'.
  1682.                 TRUE means the delete bit is set, FALSE means the
  1683.                 bit is not set.
  1684. U16 lengthrec(void);
  1685.                 Returns the length of a record. Because TBASE works
  1686.                 with fixed length records, this value is the same for all
  1687.                 records. It's the same value used in the call to define().
  1688. char *locate_rec(S32  rec);
  1689. char *locate_rec_d(S32  rec);
  1690.                 Functions to return a pointer to record 'rec' directly into
  1691.                 the buffer system. Please read the paragraph 15.9
  1692.                 about this topic before using these functions.
  1693. S32 numrec(void);
  1694.                 Returns the number of records currently in the
  1695.                 database. Whether or not a record is marked for
  1696.                 deletion makes no difference.
  1697. int open(char *name,S16 kb=32);
  1698.                 Opens the existing database 'name' while using 'kb Kb
  1699.                 ram for buffering. TRUE is returned on success,
  1700.                 FALSE otherwise.
  1701. int open(void);     Returns TRUE if the database is open, FALSE
  1702.                     otherwise.
  1703. int pack(void); Removes all the records with the delete bit set from the
  1704.                 database. This is done without the use of temporary
  1705.                 files. TRUE is returned on success, FALSE otherwise.
  1706. void read_rec(S32 rec, void *buff);
  1707.                 Copies the contents of record 'rec' into buffer 'buff'.
  1708. int save(void); Writes all buffered data back to disk. The database
  1709.                 header block is also updated. The database remains
  1710.                 open. TRUE is returned on success, FALSE otherwise.
  1711. void set_delet(S32  rec,int ToF);
  1712.                 Changes the value of the delet bit of record 'rec'. If
  1713.                 'ToF' is TRUE, the delete bit is set, otherwise it is
  1714.                 reset.
  1715. void smallest_page(void);
  1716.                 Set the page size to the smallest value possible. That
  1717.                 is, a page will have the same size as a record. This
  1718.                 means pages will no longer be alligned with the
  1719.                 harddisk sectors. The function has to be called before
  1720.                 the define() function. It changes the entire layout of the
  1721.                 database file so it cannot be changed once the file is
  1722.                 created.
  1723. void undelet(S32  rec);
  1724.                 Resets the delete bit of record 'rec'.
  1725. void write_rec(S32 rec, void *buff);
  1726.                 Overwrites the contents of record 'rec' with the data
  1727.                 from buffer 'buff'. Record 'rec' needs to exist, the
  1728.                 function cannot be used to append a record.
  1729.  
  1730.  
  1731.                           16 BTREE-class
  1732.  
  1733.  
  1734. 16.1 Introduction
  1735.  
  1736. A btree is a system, developed several decades ago, to store data in
  1737. some predetermined order. The btree is capable of maintaining this
  1738. order even under insertions and deletions.
  1739. Btrees are capable of locating, inserting or deleting a specific record with
  1740. only a few disk-IOs, even when very large.
  1741.  
  1742. Of course there is a price to be payed for this: the disk space occupied by
  1743. the btree is not fully utilized. Worst case, only 50% of the space is used,
  1744. but on average 75% is used.
  1745.  
  1746. Btrees are convenient as indexes on a database. Of each record in the
  1747. main database, the key field and the corresponding record number are
  1748. stored together in the btree. Whenever a record with a certain key value
  1749. has to be located, the btree is capable of quickly ( without much disk IO)
  1750. finding the required entry. Once this is done it is also clear which record
  1751. from the main database has to be read, because this record number is
  1752. stored together with the key value in the btree.
  1753.  
  1754. There are several 'flavours' of btrees. The one implemented in this library
  1755. is known as a 'btree+'.
  1756.  
  1757.  
  1758. 16.2 BTREEx Classes
  1759.  
  1760. Unfortunate it's a little bit cumbersome to use one BTREE class for every
  1761. type of data. Therefore, there are several minor variations on the main
  1762. BTREE class to account for the different variable types supported by C.
  1763. Each type has its own class.
  1764.  
  1765. Classes:
  1766.     BTREEb  For binary data.
  1767.     BTREEi  For integers.
  1768.     BTREEl  For longs.
  1769.     BTREEc  For characters.
  1770.     BTREEf  For floats.
  1771.     BTREEd  For doubles.
  1772.     BTREEa  For ASCII data. (Strings)
  1773.  
  1774. All these classes are derived from the BTREE class. Mainly, they only
  1775. differ in one function. This is the function needed to compare keys.
  1776.  
  1777. You can easily define a new BTREE class for a new type of variable. The
  1778. only thing to do is to define a int t_key(void *a,void *b) function which
  1779. returns:
  1780.  
  1781.         >0    if  a>b
  1782.          0    if  a==b
  1783.         <0    if  a<b
  1784.  
  1785. with 'a' and 'b' pointers to the new type of variables.
  1786.  
  1787.  
  1788. // Example:
  1789. // Say, you have your data stored in a C structure.
  1790.  
  1791. // Something like:
  1792.  
  1793.       typedef struct
  1794.       {
  1795.         char name[20];
  1796.         int  number;
  1797.       }
  1798.  
  1799. // Which you want to have sorted on the 'number' field.
  1800.  
  1801. class BTREEnew: public BTREE
  1802. {
  1803.     virtual int t_key(void *a,void *b)
  1804.     {
  1805.        return ((record *)a)->number-((record *)b)->number;
  1806.     }
  1807.     virtual int class_ID(void)  { return -100; }
  1808.  };
  1809.  
  1810.  
  1811. That's all!
  1812. The value '-100' in the class_ID() function is not all that important. Its
  1813. purpose is to give other library functions the opportunity to distinguish
  1814. between the classes. The value just has to be different from any value
  1815. the other classes have. This can be accomplished by choosing any
  1816. negative number.
  1817.  
  1818.  
  1819. 16.3 Multiple Keys
  1820.  
  1821. Because of its nature you would expect a 'key' to appear only once in a
  1822. btree. However, on many occasions it turns out there is a need for storing
  1823. the same key more then once, but with a different data part. E.g. this
  1824. happens when you use a btree as an index on a database and in  the
  1825. field  you are indexing a certain value appears more then once. In that
  1826. case, you want to store the key value several times but with a different
  1827. data part, namely the record number in the database.
  1828.  
  1829. By default a key value can appear only once in the btree. If you try to
  1830. insert a second entry with the same key value, it will simply replace the
  1831. existing one. The option 'multiple_keys()' can be set  to alter that.
  1832.  
  1833. Syntax: void multiple_keys(int  YesNo);
  1834.         void multiple_keys_YES(void);
  1835.         void multiple_keys_NO(void);
  1836.  
  1837.  
  1838. When the function 'multiple_keys()' is called with the argument set to
  1839. TRUE, the btree will store a key value more then once.
  1840.  
  1841. It is important to realize that the btree only keeps the key values
  1842. sorted, NOT the data values. This means that when you are
  1843. searching for a particular key/data value, the btree is capable of quickly
  1844. locating the required key but has to find the correct data value by
  1845. sequentially traversing all the inserted data belonging to that particular
  1846. key.
  1847.  
  1848. Btrees are intended to give quick access to key values by keeping them
  1849. sorted, this does not apply to data values. Expecting anything else is
  1850. misusing the btree. If you want quick access to a large number of
  1851. different data values, all belonging to the same key, you need a different
  1852. approach. The best thing to do is to construct a new btree and use a key
  1853. which is a concatenation of the original key and the original data part.
  1854.  
  1855. Setting the multiple_keys option has to take place before the 'define'.
  1856.  
  1857.  
  1858. // Example
  1859. // Error checking omitted for conciseness.
  1860.  
  1861. #include "csbtree.h"
  1862.  
  1863. void main(void)
  1864. {
  1865.  
  1866.     typedef struct
  1867.     {
  1868.         char name[20];
  1869.         int  age;
  1870.     } record;
  1871.  
  1872.     BTREE bt;
  1873.  
  1874.     bt.multiple_keys_YES(); // Must be called before 'define'
  1875.     bt.define("btree.dat",sizeof(record),sizeof(long));
  1876.  
  1877.     // By now a btree 'btree.dat' is created in the current working
  1878.     // directory with the multiple-keys option switched on.
  1879.  
  1880. }
  1881.  
  1882.  
  1883.  
  1884.  
  1885. 16.4 Current Pointer
  1886.  
  1887. Contrary to TBASE, the btree class does use a 'current' pointer. When
  1888. using btrees, the need to obtain the next (or previous) entry arises so
  1889. often, it's inevitable.
  1890.  
  1891. The btree class spends as little time as possible on maintaining this
  1892. current  pointer. Therefore you should assume it is NOT set, unless you
  1893. have strong reasons to believe otherwise.
  1894.  
  1895. A limited set of functions can be used to set the current pointer. After
  1896. that, the 'next()' and the 'previous()' functions can be used to move to the
  1897. next resp. the previous entry.
  1898. When these functions 'fail', which can be noticed from their return value,
  1899. you should assume the current pointer is not set (any more).
  1900.  
  1901. The next functions can be used to set the current pointer:
  1902. - all the search functions.
  1903.     E.g.  search_gt(),  find() etc.
  1904. - all the min() and max() functions.
  1905.     E.g. max_key(), min() etc.
  1906. - the insert() function.
  1907.  
  1908. The current pointer can be moved back and forth with the next() and
  1909. previous() functions.
  1910.  
  1911. Once the current pointer is set, the 'current()' functions can be used to
  1912. obtain the key value and/or the data part.
  1913.  
  1914. Any other function can, and probably will, render the value
  1915. of the current pointer undefined!
  1916.  
  1917.  
  1918.  
  1919. // Example
  1920. // The next example displays the contents of a btree with
  1921. // 'strings' as key fields.
  1922. // It assumes that the btree 'demo.dbf' exists and that the
  1923. // key fields are less then 100 bytes.
  1924.  
  1925. // Error checking omitted for conciseness.
  1926.  
  1927. #include "iostream.h"
  1928. #include "csbtree.h"
  1929.  
  1930. void main(void)
  1931. {
  1932.      char  buffer[100];
  1933.      BTREEa bt;
  1934.  
  1935.      bt.open("demo.dbf",250);  // Does not set the current pointer.
  1936.  
  1937.                       // Make the first entry the 'current'.
  1938.      if(bt.min())     // This returns FALSE only if the btree is empty.
  1939.      do
  1940.      {
  1941.         bt.current_key(buffer);  // Read the 'current' key value.
  1942.         cout<<buffer<<endl;      // Display it.
  1943.       } while(bt.next());        // Move the current pointer 1 position.
  1944.  
  1945.       bt.close();
  1946. }
  1947.  
  1948.  
  1949.  
  1950. 16.5 Using Btrees
  1951.  
  1952. The next paragraph will try to sort the public member functions according
  1953. to  purpose.
  1954.  
  1955. 16.5.1 Creating
  1956.  
  1957.     void multiple_keys_YES(void);
  1958.     void define(char *name,int key_length, int data_length);
  1959.  
  1960. 16.5.2 Opening
  1961.  
  1962.     int open(char *name, int kb_buffer);
  1963.  
  1964. 16.5.3 Inserting
  1965.  
  1966.     void insert(void *key,void *data);
  1967.  
  1968. 16.5.4 Searching
  1969.  
  1970.     int   search(void *key,void *Data);
  1971.     int   search_gt(void *key,void *Key,void *Data);
  1972.     int   search_ge(void *key,void *Key,void *Data);
  1973.     int   search_lt(void *key,void *Key,void *Data);
  1974.     int   search_le(void *key,void *Key,void *Data);
  1975.     int   search_dat_..(void *key,void *Data);
  1976.     int   search_key_..(void *key,void *Key);
  1977.     int   find(void *key,void *data);
  1978.     int   find(void *key);
  1979.     int   max(void *Key,void *Data);
  1980.     int   min(void *Key,void *Data);
  1981.  
  1982. 16.5.5 Current
  1983.  
  1984.     int   current(void *Key,void *Data);
  1985.     int   current_key(void *Key);
  1986.     int   current_dat(void *Data);
  1987.     int   tBOF(void);
  1988.     int   tEOF(void);
  1989.  
  1990. 16.5.6 Deleting
  1991.  
  1992.     int   delet(void *delete_key);
  1993.     int   delet(void *delete_key,void *data_value);
  1994.  
  1995. 16.5.7 Closing
  1996.  
  1997.     void  close(void);
  1998. 16.6 Functions in alphabetical order.
  1999.  
  2000. The function prototypes are in "CSBTREE.H".
  2001.  
  2002. void  close(void);
  2003.                 Closes the btree after use. All buffers are flushed and
  2004.                 all the allocated memory is freed. This function is also
  2005.                 called by the class destructor if needed.
  2006. int   current(void *Key,void *Data);
  2007. int   current_key(void *Key);
  2008. int   current_dat(void *Data);
  2009.                 Returns the key and/or data part of the entry the
  2010.                 current pointer is pointing at.
  2011.                 Parameters:
  2012.                 Key     Pointer to the buffer to which the key value
  2013.                         has to be copied.
  2014.                 Data    Pointer to the buffer to which the data part
  2015.                         has to be copied.
  2016.                 If the current pointer has not been set, the functions
  2017.                 return FALSE and no data is written into the buffers. If
  2018.                 the current pointer is set, the functions return TRUE
  2019.                 and the appropriate data is copied into the buffers.
  2020. void define(char *name, int key_length,int dat_length);
  2021.                 This function is needed to initially create the file on
  2022.                 disk. This is only needed once, before the first call to
  2023.                 open().
  2024.                 Parameters:
  2025.                 name        The filename of the new BTREE.
  2026.                 key_length  The number of bytes in the key. This
  2027.                             parameter is even needed when its value
  2028.                             is 'obvious' from the btree type.
  2029.                 dat_length  The number of bytes in the data part.
  2030.  
  2031.     Example:
  2032.  
  2033.     If you want to use a btree as index on a string field
  2034.     you will need:
  2035.     - a btree of type ASCII: BTREEa.
  2036.     - a key_length equal to the length of the string field
  2037.       in the database record.
  2038.     - a data part which is capable of holding the number
  2039.       of the record in the database. This will normally be
  2040.       a 'long'.
  2041.  
  2042.     #include "cstbase.h"
  2043.     #include "csbtree.h"
  2044.  
  2045.     void main(void)
  2046.     {
  2047.         typedef struct
  2048.         {
  2049.            char   name[30];
  2050.            float   income;
  2051.         }record;
  2052.  
  2053.         TBASE  db;
  2054.         BTREEa index;
  2055.  
  2056.         db.define("demo.dbf",sizeof(record));
  2057.         index.define("demo.ndx",30,sizeof(long));
  2058.         // By now the database and its index are created.
  2059.  
  2060.     }
  2061.  
  2062.  
  2063.  
  2064. int   delet(void *delete_key);
  2065.                 Searches for key 'delete_key' and, if present, removes
  2066.                 it from the btree. If the option multiple_keys is set to
  2067.                 'yes' there can be more then one entry with the
  2068.                 specified key. Under that circumstances, all these
  2069.                 entries will be removed. The function delet() can also
  2070.                 accept a parameter with the value of the data part.
  2071.                 That function should be used for deleting when
  2072.                 multiple keys are used.
  2073.                 The function returns TRUE is something is deleted,
  2074.                 FALSE otherwise.
  2075. int   delet(void *delete_key,void *data_value);
  2076.                 The same as the previous delete function but this time
  2077.                 the value of the data part is also specified. Only the
  2078.                 entry which matches both the key and the data part is
  2079.                 removed from the btree.
  2080. void  empty(void);
  2081.                 Removes all the entries in the btree. The btree needs
  2082.                 to be open. Upon return, the btree will contain zero
  2083.                 keys and will still be open.
  2084. int   find(void *key,void *data);
  2085. int   find(void *key);
  2086.                 These functions 'test' if a certain key value is present in
  2087.                 the btree. When a btree is used with multiple keys, it
  2088.                 can be necessary to specify the data part to uniquely
  2089.                 identify an entry.
  2090.                 TRUE is returned when the required entry is found,
  2091.                 FALSE otherwise.
  2092. void  insert(void *key,void *data);
  2093.                 Inserts a new entry in the btree. 'key' is a pointer to the
  2094.                 key field and 'data' is a pointer to the data part.
  2095.  
  2096. // Example:
  2097. // Error checking omitted for conciseness.
  2098.  
  2099.     void main(void)
  2100.     {
  2101.  
  2102.         typedef struct
  2103.         {
  2104.            char   name[30];
  2105.            float   income;
  2106.         }record;
  2107.  
  2108.         TBASE  db;
  2109.         BTREEa index;
  2110.  
  2111.         db.define("demo.dbf",sizeof(record));       //Creating.
  2112.         index.define("demo.ndx",30,sizeof(long));   //Creating.
  2113.  
  2114.         db.open("demo.dbf",30);         // Opening the database with 30 Kb buffers
  2115.         index.open("demo.ndx",80);      // Opening the index with 80 Kb buffers.
  2116.  
  2117.         record rec;
  2118.  
  2119.         strcpy(rec.name,"John Wayne");
  2120.         rec.income=7000;                // Filling the record.
  2121.  
  2122.         long recnr=db.append_rec(&rec);     // Insert in the database.
  2123.         index.insert(rec.name,&recnr);      // Update the index.
  2124.  
  2125.         db.close();                 // Close the database.
  2126.         index.close();              // Close the index.
  2127.  
  2128.     }
  2129.  
  2130.  
  2131. int   max(void *Key,void *Data);
  2132. int   max_dat(void *Data);
  2133. int   max_key(void *Key);
  2134. int   max(void);
  2135.                 These functions return the last (highest) entry in the
  2136.                 btree. The parameters 'Key' and 'Data'  have to be
  2137.                 pointers to respectively a buffer for the key part and a
  2138.                 buffer for the data part. These buffers will be filled with
  2139.                 the appropriate data upon function return.
  2140.                 The functions max_dat() and max_key() can be used
  2141.                 when only one of the two items is required.
  2142.                 TRUE is returned on success, FALSE otherwise.
  2143. int   min(void *Key,void *Data);
  2144. int   min_dat(void *Data);
  2145. int   min_key(void *Key);
  2146. int   min(void);
  2147.                 These functions return the first (lowest) entry in the
  2148.                 btree. The parameters 'Key' and 'Data' have to be
  2149.                 pointers to respectively a buffer for the key part and a
  2150.                 buffer for the data part. These buffers will be filled with
  2151.                 the appropriate data upon function return.
  2152.                 The functions min_dat() and min_key() can be used
  2153.                 when just one of the two items is required.
  2154.                 TRUE is returned on success, FALSE otherwise.
  2155. void  multiple_keys(int TrueOrFalse);
  2156.                 With this function the use of multiple keys is controlled.
  2157.                 Multiple_keys(TRUE) will allow for multiple keys.
  2158.                 Multiple_keys(FALSE) will not allow for multiple keys.
  2159.                 Important:
  2160.                 This function has to be called before the define()
  2161.                 function is invoked. It is not possible to alter the setting
  2162.                 of the multiple key parameter later on.
  2163.                 For more information about multiple keys please read
  2164.                 paragraph 16.3.
  2165. int   multiple_keys_YES(void);
  2166.                 Same as multiple_keys(TRUE);
  2167. int   multiple_keys_NO(void);
  2168.                 Same as multiple_keys(FALSE);
  2169. int   multiple_keys(void);
  2170.                 This function returns TRUE if multiple keys is set to
  2171.                 'YES' and FALSE otherwise.
  2172. int   next(int n);
  2173. int   next_key(int n,void *Key);
  2174. int   next_dat(int n,void *Data);
  2175. int   next(int n,void *Key,void *Data);
  2176.                 A set of functions to move the current pointer closer to
  2177.                 the 'end' of the btree.
  2178.                 Apart from that, they are similar to the prev() funtions.
  2179.                 For more information, please see over there.
  2180. int     next(void);
  2181.                 Same as next(1); but more efficient.
  2182. long  numkey(void);
  2183.                 This function returns the number of different keys
  2184.                 which is in the btree.
  2185. int   open(char *name, int kb_buff);
  2186.                 Opens an existing btree 'name'. The parameter
  2187.                 'kb_buff' indicates how many Kb ram has to be used
  2188.                 for buffering.
  2189.                 The function returns TRUE on success, FALSE
  2190.                 otherwise.
  2191.  
  2192. // Example:
  2193.  
  2194.     #include "iostream.h"
  2195.     #include "csbtree.h"
  2196.  
  2197.     void main(void)
  2198.     {
  2199.  
  2200.        BTREEa index;
  2201.        if(!index.open("demo.ndx",100))
  2202.        {
  2203.         cout<<"Error"<<end;
  2204.        }
  2205.  
  2206.     }
  2207.  
  2208.                 This will open the btree 'demo.ndx' and will, at most,
  2209.                 use 100 Kb ram for buffering.
  2210.                 NOTE:   read the chapter 11 about buffering, before
  2211.                         using really large amounts of buffers.
  2212. void  pack(void);
  2213.                 A function which optimizes disk usage. Due to many
  2214.                 insertions and deletions it is possible for blocks with
  2215.                 zero keys to emerge. There are no pointers to these
  2216.                 blocks but they will still be part of the btree because
  2217.                 they can not be removed unless they are the last block
  2218.                 in the file. These blocks will be used as soon as the
  2219.                 need for a new block arises.
  2220.                 The pack function will remove these empty blocks and
  2221.                 rearrange all the keys. This is done by writing all the
  2222.                 data to a temporary file and reload the btree.
  2223. int   prev(void);
  2224. int   prev(int n);
  2225. int   prev_key(int n,void *Key);
  2226. int   prev_dat(int n,void *Data);
  2227. int   prev(int n,void *Key,void *Data);
  2228.                 A set of functions to move the current pointer closer to
  2229.                 the 'beginning' of the btree.
  2230.                 Parameters:
  2231.                 n       The number of entries the current pointer
  2232.                         needs to be moved.
  2233.                 Key     A pointer to the buffer which is going to be
  2234.                         filled with the value of the key field.
  2235.                 Data    A pointer to the buffer which is going to be
  2236.                         filled with the value of the data part.
  2237.                 If the current pointer is NOT moved, the key and data
  2238.                 buffers will not be filled. Otherwise they will be filled
  2239.                 with the values of the entry to which the current pointer
  2240.                 is moved.
  2241.                 The key field, the data field, or both can be obtained by
  2242.                 selecting the appropriate function.
  2243.                 The prev(void) function is a more efficient version of
  2244.                 the prev(1) function.
  2245.                 Important:
  2246.                 This current pointer needs to be set first. Please, read
  2247.                 paragraph 16.4 about the 'current pointer' for more
  2248.                 information.
  2249.                 When one of the prev() functions is called while the
  2250.                 current pointer is not set, the function will return 0. The
  2251.                 current pointer can not be moved before the beginning
  2252.                 of the btree, therefore the number of positions moved
  2253.                 can differ from the number requested.
  2254.                 The return value is the number of positions the current
  2255.                 pointer has actually moved.
  2256. int   search(void *key,void *Data);
  2257.                 Searches for 'key' and fills buffer 'Data' with the
  2258.                 corresponding data part if 'key' is found.
  2259.                 The function returns TRUE if found, FALSE otherwise.
  2260. int   search_gt(void *key,void *Key,void *Data);
  2261. int   search_ge(void *key,void *Key,void *Data);
  2262. int   search_lt(void *key,void *Key,void *Data);
  2263. int   search_le(void *key,void *Key,void *Data);
  2264.                 The purpose of this set of functions is to search for a
  2265.                 key value close to a given value. 'key' is the key value
  2266.                 searched for while 'Key' is the key value actually found.
  2267.                 'Data' is the data part belonging to 'Key'.
  2268.                 The suffix '_xx' has a meaning conform the
  2269.                 corresponding FORTRAN operators:
  2270.                 gt: Greater Then        >
  2271.                 ge: Greater Equal       >=
  2272.                 lt: Less Then           <
  2273.                 le: Less Equal          <=
  2274.                 The functions return TRUE if such a key could be
  2275.                 found, FALSE if not.
  2276.  
  2277.      Example:
  2278.      Assume the next table represents a btree.
  2279.  
  2280.          Entry    Key value      Data value
  2281.  
  2282.           1         Blue            123
  2283.           2         Green           45
  2284.           3         Red             678
  2285.  
  2286.        search_gt("Blue",Key,Data)
  2287.         Return value:   TRUE
  2288.         Key:            Green
  2289.         Data:           45
  2290.  
  2291.        search_ge("Blue",Key,Data)
  2292.         Return value:   TRUE
  2293.         Key:            Blue
  2294.         Data:           123
  2295.  
  2296.        search_lt("Blue",Key,Data)
  2297.         Return value:   FALSE
  2298.         Key:            undefined
  2299.         Data:           undefined
  2300.  
  2301.        search_ge("Orange",Key,Data)
  2302.         Return value:   TRUE
  2303.         Key:            Red
  2304.         Data:           678
  2305.  
  2306.  
  2307. int   search_dat_..(void *key,void *Data);
  2308. int   search_key_..(void *key,void *Key);
  2309.                 The previously described functions return both the key
  2310.                 value and the data value.
  2311.                 In some cases this will be a waste of memory,
  2312.                 therefore there are two similar sets of functions, which
  2313.                 either return the found key value or the data part.
  2314.                 search_dat_..() returns only the found data value.
  2315.                 search_key_..() returns only the found key value.
  2316.  
  2317.     Example:
  2318.  
  2319.     With the same btree as in the previous example
  2320.  
  2321.  
  2322.        search_dat_gt("Blue",Data)
  2323.         Return value:   TRUE
  2324.         Data:           45
  2325.  
  2326.        search_key_ge("Blue",Key)
  2327.         Return value:   TRUE
  2328.         Key:            Blue
  2329.  
  2330.  
  2331. int   skip(int n);
  2332. int   skip(int n,void *Key,void *Data);
  2333. int   skip_key(int n,void *Key);
  2334. int   skip_dat(int n,void *Dat);
  2335.                 A set of functions to move the current pointer. These
  2336.                 functions are front ends for the next() and prev()
  2337.                 functions. E.g. this is how the skip_key() function is   implemented:
  2338.  
  2339.  
  2340.                 int skip_key(int n,void *Key)
  2341.                     {  if(n>0) return  next_key( n,Key);
  2342.                        else    return -prev_key(-n,Key); }
  2343.  
  2344.  
  2345.                 So, with these functions the argument 'n' may be
  2346.                 positive or negative.
  2347.                 With 'n' positive the current pointer is moved to the
  2348.                 'end' of the btree. This is done by calling next(n). With
  2349.                 'n' negative the current pointer is moved to the
  2350.                 'beginning' of the btree. This is done by calling
  2351.                 -prev(-n).
  2352.                 The return value can be either positive or negative
  2353.                 depending on the value of 'n'. When 0 is returned, the
  2354.                 current pointer has not been moved or was not set.
  2355.                 See also the prev() functions for more information.
  2356. int   tBOF(void);   Returns TRUE if 'current' is pointing to the first entry of
  2357.                     the btree, FALSE otherwise. Behaviour is undefined in
  2358.                     case 'current' is NOT set!
  2359. int   tEOF(void);   Returns TRUE if 'current' is pointing to the last entry of
  2360.                     the btree, FALSE otherwise. Behaviour is undefined in
  2361.                     case 'current' is NOT set!
  2362.  
  2363.  
  2364.  
  2365.  
  2366.                             17 CSDBGEN
  2367.  
  2368.  
  2369. This chapter describes the CSDBGEN program generator.
  2370.  
  2371.  
  2372. 17.1 Introduction
  2373.  
  2374. So far we have discussed the TBASE class which is capable of
  2375. reading and writing records and the BTREE class which can be used
  2376. as an index.
  2377. CSDBGEN can aid in building an indexed database out of this. A
  2378. database which is capable of manipulating fields, maintaining indexes
  2379. and the alike.
  2380.  
  2381. As input it takes a 'definition file' which describes the fields and the
  2382. indexes. From this, it produces the source for a new C++ class. Member
  2383. functions of this newly created class are used to access the fields.
  2384.  
  2385. CSDBGEN does not generate a user-interface.
  2386.  
  2387. There are several good reasons for using a program generator.
  2388. - The TBASE class can concentrate on manipulating records rather then
  2389.     fields. Because of that, it remains a universal and efficient way to
  2390.     read and write blocks of data.
  2391. - With this approach it is easier to deal with field types that are not
  2392.     supported by the C programming language, particularly dates.
  2393. - It is relatively easy for the program generator to convert to dBASE
  2394.     format because it has all the required knowledge at hand. Figuring
  2395.     out this conversion during runtime is a lot more complicated and will
  2396.     also make your executable larger because the knowledge to do the
  2397.     conversion is in the application instead of in the program generator.
  2398. - Or more in general: everything the program generator does, can be left
  2399.     out from the application, making the executable smaller.
  2400. - Without a program generator, the differences between the field types
  2401.     have to be dealt with runtime, perhaps even with every call
  2402.     accessing a field. Doing so, will inevitable result in some sort of an
  2403.     interpreter.
  2404.  
  2405.  
  2406. 17.2 Overview
  2407.  
  2408. Using CSDBGEN starts off with creating a database definition file. This
  2409. file describes the layout of a record, the indexes, the name of the new
  2410. class and the name of the files.
  2411.  
  2412. When this file is created, CSDBGEN is called with this filename as a
  2413. parameter. In return it produces the source for a brand new C++ class.
  2414. This source is ready to compile, without the need for manual editing.
  2415.  
  2416. This new class has public member functions for reading a field, setting
  2417. the active index, exporting to ASCII, exporting to dBASE, reindexing,
  2418. packing and so on.
  2419. These member functions are very easy to use because they take very
  2420. few, and often none, parameters. This is possible because a lot of the
  2421. information which is specific for the database is already in the source of
  2422. the functions.
  2423.  
  2424. The generated class controls one database and all the indexes that
  2425. come with it. If you need more then one database you have to repeat this
  2426. procedure for the other databases as well.
  2427.  
  2428. An elaborate example is at the end of this chapter.
  2429.  
  2430.  
  2431. 17.3 Features
  2432.  
  2433. - Indexes with more then one reference to a record!
  2434.     This is an innovation! It creates the possibility to locate a record by
  2435.     searching for a substring of the field, rather then the entire field. This
  2436.     topic is discussed in more detail in paragraph 17.6 called
  2437.     'tokenizing'.
  2438. - Conversion to-and-from ASCII.
  2439.     This is convenient for backups, conversions to other systems and
  2440.     also for making changes in the record layout.
  2441. - Export to dBASE compatible file format.
  2442.     CSDBGEN generates a function (member of the new class) capable
  2443.     of writing the contents of the database to a file in the dBASE format.
  2444. - Import from dBASE.
  2445.     There is no direct way to import a dBASE file, but the command-line
  2446.     utility CS4DBASE can be used to convert a dBASE file into an ASCII
  2447.     file which can be read by the import() function.
  2448. - Can manage very large databases.
  2449.     The design of the libraries has been keen on avoiding limitations. As
  2450.     a result, databases up to 2 billion records are theoretically feasible.
  2451. - No overhead.
  2452.     Due to the use of a program generator, the overhead involved in
  2453.     accessing fields is next to none.
  2454. - Large buffers.
  2455.     This system is capable of effectively using large amounts of RAM for
  2456.     buffering.
  2457. - Fast.
  2458.     The previous two points, together with the efficient BTREEs
  2459.     guarantee a very fast database.
  2460.  
  2461.  
  2462. 17.4 Limitations
  2463.  
  2464. - No record locking.
  2465. - No multi-user support.
  2466.     This system was designed to be used in single user applications.
  2467.     Time being, there is no support for network/shared databases.
  2468.     Perhaps there will be in the future but if so, it will take the form of a
  2469.     new series of classes.
  2470.  
  2471.  
  2472. 17.5 Definition file
  2473.  
  2474. The information needed to generate the new class is obtained from a
  2475. 'definition file'. To get started, CSDBGEN is capable of generating an
  2476. example.
  2477.  
  2478.  
  2479. example
  2480.  
  2481. c:\borlandc>csdbgen /example>example.def
  2482.  
  2483. Something like this will generate an example definition file 'example.def'.
  2484.  
  2485.  
  2486.  
  2487.  
  2488. To get acquainted, let's look what's in it.
  2489.  
  2490. Example database definition file:
  2491.  
  2492.     class:  NAM
  2493.     record: NAM_record
  2494.     file:   demo
  2495.     field:  name        s   30  Y
  2496.     field:  city        s   20
  2497.     field:  birthday    d       Y
  2498.     field:  salary      f
  2499.  
  2500.  
  2501.  
  2502. Explanation:
  2503.  
  2504.     line 1: class:  NAM
  2505.         The program generator generates a class, which of course has
  2506.         to have a name. In this example 'NAM' .
  2507.  
  2508.     line 2: record: NAM_record
  2509.         As explained before, we use a C structure as a record. The
  2510.         name of this structure is defined in the second line.
  2511.         In the generated header file the following (among others) will
  2512.         appear:
  2513.  
  2514.  
  2515.          #define NAME_LENGTH      30
  2516.          #define CITY_LENGTH      20
  2517.  
  2518.          typedef struct
  2519.          {
  2520.             char   _name[NAME_LENGTH+1];
  2521.             char   _city[CITY_LENGTH+1];
  2522.             long   __birthday;
  2523.             float  _salary;
  2524.          } NAM_record;
  2525.  
  2526.  
  2527.     line 3: file:   demo
  2528.         This line indicates the name of the files the database system will
  2529.         use. In this example three files will be used:
  2530.             - demo.dbf, the TBASE database file.
  2531.             - demo01.idx, the BTREE index file on field 'name'.
  2532.             - demo02.idx, the BTREE index file on field 'birthday'.
  2533.  
  2534.  
  2535.     line 4/7:
  2536.         Field definitions.
  2537.         The syntax for a field definition is:
  2538.         field: <field_name> <field_type> [length] [format] [index]
  2539.         With:
  2540.             field_name, the name of the field.
  2541.             field_type, the type of the field which can be:
  2542.                 i:  integer
  2543.                 l:  long
  2544.                 f:  float
  2545.                 F:  double
  2546.                 c:  character
  2547.                 s:  string
  2548.             length, only for strings.
  2549.                 Indicates the number of characters the field needs to
  2550.                 be able to store. One additional byte is reserved to
  2551.                 store the null terminator.
  2552.             format, only for date fields.
  2553.                 Please, see the documentation on DATE fields.
  2554.                 To give a quick example: MDY4 means, Month, Day
  2555.                 and 4 positions for the Year.
  2556.             index,
  2557.                 'Y' means a normal index.
  2558.                 'T' means a 'tokenized' index.
  2559.                  Nothing means no index at all.
  2560.                 See also the documentation on 'tokenizing' further on.
  2561.  
  2562. In the example:
  2563.  
  2564.     field:  name    s   30  Y
  2565.         A field 'name' of type string. 31 Bytes are reserved, 30 for the
  2566.         characters and 1 for the null terminator. An index is maintained
  2567.         for this field because of the additional 'Y'.
  2568.  
  2569.     field:  city    s   20
  2570.         A field 'city' of type string with a length of 20 characters. There is
  2571.         NO index on this field.
  2572.  
  2573.     field:  birthday    d   Y
  2574.         A field 'birthday' of type DATE. An index is placed on this field.
  2575.  
  2576.     field:  salary  f
  2577.         A field 'salary' of type float, without an index.
  2578.  
  2579.  
  2580. 17.6 Tokenizing
  2581.  
  2582. This is a new concept!
  2583.  
  2584. Let's explain things with an example.
  2585.  
  2586. Say you have a database with a record for the 'World Health
  2587. Organization'. Normally, the only way to locate this record would be by
  2588. entering a search string starting of with  'World ....'. But now, with
  2589. tokenizing, this record could also be located by searching for  'Healt..' or
  2590. 'Organization..'.
  2591. It's important to know that this is not implemented by traversing the entire
  2592. database from the first record to the last, as is done by some toy-applications, but through maintaining an extensive index.
  2593.  
  2594.  
  2595. 17.6.1 How does it work?
  2596.  
  2597. Traditionally, the index stores the entire field. In this example that would
  2598. mean 'World Health Organization' is stored in the index together with a
  2599. reference to the record number in the main database.
  2600. With tokenizing, the index will store 3 entries, namely 'World', 'Health'
  2601. and 'Organization'. This approach means that there will be a lot more
  2602. entries in the btree then there are records in TBASE.
  2603.  
  2604. In other words, an index is maintained on every suitable substring, rather
  2605. then the entire field.
  2606.  
  2607. To save disk space, the length of the key field in the BTREE is
  2608. only half of the field length in the main database.
  2609.  
  2610.  
  2611. 17.7 When is a substring indexed?
  2612.  
  2613. First of all: tokenizing only applies for string fields. E.g. 'Tokenizing' a
  2614. float field seems pointless.
  2615.  
  2616. Whether or not a substring is placed in the index is controlled by two
  2617. things:
  2618. - the way it is separated from the rest of the field.
  2619. - the length of the substring.
  2620.  
  2621. For every field  tokenized', CSDBGEN generates two symbolic constants:
  2622. one for the token delimeters and a second for the minimal token length.
  2623.  
  2624.  
  2625. // Example:
  2626. // Suppose you use tokenizing on a field  NAME'.
  2627. // In the generated .cpp file two #defines will appear:
  2628.  
  2629.  
  2630. #define TD_NAME "\t(),- "  // Token delimiters for field 'name'.
  2631. #define TL_NAME 4          // Minimal Token length for field 'name'.
  2632.  
  2633.  
  2634.  
  2635. The tokenize function separates the field into substrings according to the
  2636. characters in the TD_????? string. Notice that the '.' is not a delimiter.
  2637. This is to prevent abbreviations from being split up.
  2638. A substring has to be at least TL_????? bytes long to appear in an index.
  2639. By default this will be four bytes, that's not too long for most cases but it
  2640. means that three letter abbreviations like 'IRS' are not indexed.
  2641.  
  2642. Of course you can alter these two defines when needed.
  2643.  
  2644.  
  2645. Example definition file:
  2646.  
  2647.   class:    NAM
  2648.   record:   NAM_record
  2649.   file:     demo
  2650.   field:    name        s   30  T
  2651.   field:    city        s   20
  2652.   field:    birthday    d
  2653.   field:    salary      f
  2654.  
  2655.  
  2656. Notice the 'T' behind the 'name' field. This is short for 'tokenize'. The
  2657. generated class will apply tokenizing on the  name' field.
  2658.  
  2659.  
  2660. 17.8 Compound indexes
  2661.  
  2662. On several occasions there is a need for an index on a concatenation of
  2663. fields, rather then on one single field. E.g. the combination of a string
  2664. field and a date field is very popular.
  2665.  
  2666. Example:
  2667.     Suppose you are building a database for sport events. Some events
  2668.     like 'Heavy Weight Champion Match' may appear more then once.
  2669.     Therefore, you want the events listed first by alphabet, and second
  2670.     by date. In this way all the heavy weight champion matches appear
  2671.     together and in order of their scheduled date.
  2672.  
  2673. CSDBGEN can generate indexes on a concatenation of fields. For that, it
  2674. requires an 'index' line in the database definition file.
  2675.  
  2676. 17.8.1 A simple example
  2677.  
  2678.  
  2679.     class:  NAM
  2680.     record: NAM_record
  2681.     file:   demo
  2682.     field:  name            s   30  Y
  2683.     field:  city            s   20
  2684.     field:  birthday        d       Y
  2685.     index:  nabi a:name+a:birthday
  2686.  
  2687.  
  2688. Note the last line. This will generate the index nabi, which is an index on
  2689. the concatenation of the name field and the birthday. The a: indicates
  2690. 'ascending'. In case you need 'descending', use d:.
  2691.  
  2692. There is no need to limit the indexes to a concatenation of just two fields.
  2693. Many more fields can be used, and the same field may even appear
  2694. more then once. Also, there is no reason why a field which already has a
  2695. 'normal' index, shouldn't be used in a compound index.
  2696. E.g. in the example, the name field is already indexed because the 'Y'
  2697. behind its definition, despite that it's also used in the nabi index.
  2698.  
  2699.  
  2700. 17.8.2 A more complex example
  2701.  
  2702.  
  2703.     class:  NAM
  2704.     record: NAM_record
  2705.     file:   demo
  2706.     field:  name            s   30  T
  2707.     field:  city            s   20
  2708.     field:  birthday        d   MDY2
  2709.     index:  nabi    d:name+a:birthday
  2710.     index:  binaci  a:birthday+d:name+a:city
  2711.  
  2712.  
  2713. This will generate a NAM class with a tokenized index on the name field
  2714. and two compound indexes, nabi and binaci.
  2715. The nabi index sorts the name descending and the birthday ascending,
  2716. binaci sorts first ascending on the birthday, secondly descending on the
  2717. name and last ascending on city.
  2718.  
  2719. Example:
  2720.  
  2721.  
  2722. #include "iostream.h"
  2723. #include "nam.h"
  2724.  
  2725. void main(void)
  2726. {
  2727.     NAM nam;
  2728.  
  2729.     nam.open();             // Opening
  2730.     nam.order(NAME_INDEX);  // Use the name index.
  2731.         ....                // Do something
  2732.     nam.order(NABI_INDEX);      // Use the nabi index.
  2733.         ....                    // Do something
  2734.     nam.order(BINACI_INDEX);    // Use the binaci index.
  2735.  
  2736.     nam.top();              // Display the records in order
  2737.     do                      // of the binaci index.
  2738.     {
  2739.         cout<<nam.birthday()<<" ";
  2740.         cout<<nam.name()<<" ";
  2741.         cout<<nam.city()<<endl;
  2742.     } while(nam.skip(1));
  2743.  
  2744.     nam.close();
  2745. }
  2746.  
  2747.  
  2748.  
  2749. 17.8.3 Compound & Tokenizing Indexes
  2750.  
  2751. It's also possible to use a compound index while a tokenizing techique is
  2752. applied on one of more of its fields. The syntax to generate such an index
  2753. can be seen in the next example.
  2754. Example database definition file:
  2755.  
  2756.  
  2757.     class:  NAM
  2758.     record: NAM_record
  2759.     file:   demo
  2760.     field:  name        s   30
  2761.     field:  birthday    d   MDY2
  2762.     index:  nabi    aT:name+a:birthday
  2763.  
  2764.  
  2765. Notice the 'T' in the last line.
  2766. The nabi index will now 'tokenize' the name field, concatenate the
  2767. birthday and use this as a reference for the record.
  2768.  
  2769. Example:
  2770.  
  2771. Record 1:
  2772.     Bjorn Esverald
  2773.     04/07/70
  2774.  
  2775. Record 2:
  2776.     Bjorn Gensjeng
  2777.     03/23/55
  2778.  
  2779. Record 3:
  2780.     Gata Esverald
  2781.     05/11/93
  2782.  
  2783.  
  2784. Assume the above three records resemble the database.
  2785. Which references will the nabi index contain?
  2786.  
  2787.  
  2788.  
  2789.     Entry nr:           Key:            Record pointed to:
  2790.      ──────────────────────────────────────────────────────
  2791.  
  2792.     1           Bjorn       03/23/55        2
  2793.     2           Bjorn       04/07/70        1
  2794.     3           Esverald    04/07/70        1
  2795.     4           Esverlad    05/11/93        3
  2796.     5           Gata        05/11/93        3
  2797.     6           Gensjeng    03/23/55        2
  2798.  
  2799.  
  2800.  
  2801.  
  2802. Just as with the ordinary tokenized fields, the length of the
  2803. token placed in the index, is at most half of that of the original
  2804. field.
  2805.  
  2806. Although it's not easy to come up with an application in which it is useful,
  2807. it's possible to have a compound index on the concatenation of more
  2808. then one tokenized field:
  2809.  
  2810. Example:
  2811.  
  2812.     class:  NAM
  2813.     record: NAM_record
  2814.     file:   demo
  2815.     field:  name            s   60
  2816.     field:  interests       s   50
  2817.     index:  nabi    aT:name+dT:interests
  2818.  
  2819.  
  2820. This creates a vast index because a reference is generated for
  2821. every possible combination of a token in the name field and a
  2822. token in the interests field. Let's say the name field contains three
  2823. tokens and the interest field four. Then there will be 3*4=12 references in
  2824. the index, just for this single record!
  2825.  
  2826. Example:
  2827.  
  2828.  
  2829. Record 1:
  2830.     Roger Sander Barkakati
  2831.     Bonsai Trees
  2832.  
  2833.  
  2834.  
  2835. Suppose this is the only record in the database. Then the nabi index will
  2836. contain the following 6 references:
  2837.  
  2838.  
  2839.  
  2840.  
  2841.  
  2842.     Entry nr:           Key:            Record pointed to:
  2843.     ──────────────────────────────────────────────────────
  2844.  
  2845.     1           Barkakati Trees         1
  2846.     2           Barkakati Bonsai        1
  2847.     3           Roger     Trees         1
  2848.     4           Roger     Bonsai        1
  2849.     5           Snder     Trees         1
  2850.     6           Sander    Bonsai        1
  2851.  
  2852.  
  2853.  
  2854. Note:   'Trees' appear before 'Bonsai' because the interests field is
  2855.         tokenized descending.
  2856.  
  2857.  
  2858. 17.8.4 Locating an Entry
  2859.  
  2860. With a compound index, locating a specific entry is not all that easy.
  2861. Normally, supplying a pointer to the search argument is sufficient, but this
  2862. time the pointer needs to point to the concatenation of two or more
  2863. values which don't even have to be of the same type.
  2864.  
  2865. Therefore, CSDBGEN typedefs a record structure for every compound
  2866. index.
  2867. Example:
  2868.  
  2869.     class:  NAM
  2870.     record: NAM_record
  2871.     file:   demo
  2872.     field:  name        s   60
  2873.     field:  interests   s   50
  2874.     index:  nabi aT:name+dT:interests
  2875.  
  2876. // This defintion file will generate a header file
  2877. // which, among others, contains the following lines:
  2878.  
  2879.     #define NAME_LENGTH     60
  2880.     #define INTERESTS_LENGTH    50
  2881.  
  2882.     #define UNSORTED        0
  2883.     #define NABI_INDEX  1
  2884.  
  2885.     typedef struct
  2886.     {
  2887.        char  name[NAME_LENGTH/2];
  2888.        char  interests[INTERESTS_LENGTH/2];
  2889.     }NAM_rec_nabi;
  2890.  
  2891.  
  2892.  
  2893. Note that the field lengths in the NAM_rec_nabi structure are only half of
  2894. the database field lengths.
  2895.  
  2896. NAM_rec_nabi is the structure which can be used to search for an entry
  2897. in  the compound index nabi.
  2898.  
  2899. Example:
  2900.  
  2901. #include ....
  2902.  
  2903. void main(void)
  2904. {
  2905.     NAM_rec_nabi nrn;
  2906.     NAM nam;
  2907.     nam.open();
  2908.  
  2909.     nam.order(NABI_INDEX);      // Make the NABI index active.
  2910.  
  2911.     strcpy(nrn.name,"Gandalf");
  2912.     strcpy(nrn.interests,"Witchcraft");
  2913.  
  2914.     // Locate. Case INsensitive.
  2915.  
  2916.     if(nam.find(&nrn)) cout<<" Found ";
  2917.     else               cout<<" Not Found ";
  2918.  
  2919.     nam.close();
  2920.  
  2921. }
  2922.  
  2923.  
  2924.  
  2925. 17.9 Export to dBASE
  2926.  
  2927. The program generator also produces a  member function:
  2928.  
  2929.     int to_DBASE(char *filename);
  2930.  
  2931. When called, this function produces a file 'filename' which can be read by
  2932. dBASE. Index files are NOT written.
  2933.  
  2934.  
  2935. 17.10 Importing from dBASE
  2936.  
  2937. CSDBGEN does not generate a function to directly import a dBASE file.
  2938. However, the CS4DBASE utility, discussed in chapter 27 of this
  2939. documentation, can read a dBASE file. It produces an ASCII file which is
  2940. formatted to be read by the import() function.
  2941. The next paragraph explains how to read ASCII files using the import()
  2942. function.
  2943.  
  2944.  
  2945. 17.11 Exporting/Importing to/from ASCII
  2946.  
  2947.     int export(char *filename);
  2948.  
  2949. This writes out the contents of the database to an ASCII file 'filename'.
  2950. That file will also contain information about the fields. In this way the
  2951. import() function knows how to process this data, even after changes in
  2952. the record layout.
  2953.  
  2954.     int import(char *filename);
  2955.  
  2956. This member function reads the ASCII file 'filename' and appends the
  2957. data to the current database. It is meant to be used in conjunction with
  2958. the export() function. The export function starts of with writing the entire
  2959. definition file. The import function uses this information to skip fields
  2960. which are not in the database and to read fields in the right order. (Only
  2961. 'familiar' fields are read, the others are ignored.) This mechanism can be
  2962. used to make changes in the record layout.
  2963. Note: Because it's an ASCII file, the names of the fields can be changed
  2964. with a normal editor.
  2965.  
  2966.  
  2967. 17.12 Starting a new database
  2968.  
  2969. A member function
  2970.  
  2971.     int define(void);
  2972.  
  2973. is available to create a new database. If the database already exists, it is
  2974. overwritten!
  2975.  
  2976.  
  2977. 17.13 Opening a database
  2978.  
  2979. The member function
  2980.  
  2981.     int open(void);
  2982.  
  2983. opens an existing database.
  2984. Index files are automatically rebuilt if they don't exist.
  2985.  
  2986.  
  2987. 17.14 Current Record
  2988.  
  2989. At any moment there is always a record the 'current record'. The
  2990. functions to read and write fields all work with this current record.
  2991.  
  2992. - After opening, the first record becomes the current record.
  2993. - The go_to(), skip(), top(), bottom() and the search()  functions can be
  2994.     used to make another record 'current'.
  2995.  
  2996.  
  2997. 17.15 Accessing fields
  2998.  
  2999. CSDBGEN generates two member functions for each field. One to read
  3000. the field, and a second to write the field. The names are the same but the
  3001. arguments differ.
  3002.  
  3003.  
  3004.  
  3005. Example:
  3006.  
  3007. // A part of the definition file:
  3008.       class:  NAM
  3009.       record: nam_record
  3010.       file:   dbtest
  3011.       field:  name s 40
  3012.       field:  number i
  3013.  
  3014. // We have a 'name' field consisting of a string with 40 characters
  3015. // and a 'number' field which is an integer.
  3016. // Among others, the next member functions are generated by CSDBGEN:
  3017.  
  3018. class NAM
  3019. {
  3020. public:
  3021. // For reading
  3022.       char  *name(void);
  3023.       int   number(void);
  3024. // For writing
  3025.       void   name(char *s);
  3026.       void   number(int i);
  3027. };
  3028.  
  3029.  
  3030. The next example gives an impression of how the generated class could
  3031. be used.
  3032.  
  3033.  
  3034. Example:
  3035.  
  3036.    void main(void)
  3037.    {
  3038.       NAM db;               // We now have a class 'NAM'.
  3039.  
  3040.       if(!db.open())        // Opens database, assuming it already exists.
  3041.       {                     // No file names have to be entered.
  3042.         cout<<"error";      // All the indexes are opened automatically.
  3043.       }
  3044.       puts(db.name());      // Displays the name field of the first record.
  3045.                             // After 'open' the first record is 'current'.
  3046.  
  3047.       db.name("Pjotr Idaho");   // Changes the contents of the 'name' field to
  3048.                         // 'Pjotr Idaho'. Indexes are updated automatically.
  3049.  
  3050.       if(!db.close())       // Close database.
  3051.       { cout<<"error"; }
  3052.    }
  3053.  
  3054.  
  3055.  
  3056.  
  3057. 17.16 DATE fields
  3058.  
  3059. Standard C doesn't support date variables. Therefore, this library has its
  3060. own DATE class.
  3061.  
  3062. The functions to read and write date-fields are using a string
  3063. representation of a date. These strings can represent a date in several
  3064. formats. CSDBGEN uses a default of DMY4. This means 2 positions for
  3065. the Day, 2 positions for the Month and 4 positions for the Year.
  3066.  
  3067.  
  3068. Example:
  3069.  
  3070.    "02/04/1994"    // By default interpreted as:  April the 2th 1994.
  3071.  
  3072.  
  3073. When a two position representation of the year is wanted, use Y2 instead
  3074. of Y4.
  3075. Roughly speaking: Every sensible order of M,D,Y2 or Y4 is accepted.
  3076.  
  3077.  
  3078. Example:
  3079.     If you want "02/04/94"  to be interpreted as February the 4th 1994, use the format
  3080.     MDY2. The line in the database definition file has to be:
  3081.  
  3082.     field: birthday d MDY2
  3083.  
  3084.     If you want the field to be indexed, add an additional 'Y':
  3085.  
  3086.     field: birthday d MDY2 Y
  3087.  
  3088.  
  3089. On disk, dates are stored as longs. The sem_jul() function of the DATE
  3090. class is used to convert a date to a long.
  3091. For more information about the date formats and the DATE class, please
  3092. see chapter 30.
  3093.  
  3094.  
  3095. 17.17 Changing the record layout.
  3096.  
  3097. Even when the database is already in use, the need to make changes in
  3098. the record layout may occur. With the next procedure this can be
  3099. accomplished quite easily, without to the need to reenter any data
  3100. manually.
  3101.  
  3102. To put it in a nut shell: save your data to an ASCII file with the old
  3103. export() function and reload with the new import() function.
  3104.  
  3105. Or in more detail:
  3106.  
  3107.     a) Export with the 'old' export() function.
  3108.         This will produce an ASCII file which fully resembles the
  3109.         database.
  3110.     b) Make a new definition file or alter the old one.
  3111.     c) Generate a new Class with CSDBGEN.
  3112.     d) Compile & link.
  3113.         The last three steps are simply the procedure for creating a
  3114.         database using CSDBGEN.
  3115.     e) Use the new import() function to reload the data.
  3116.         Import the ASCII file created with step 'a'. The import() function
  3117.         is doing the actual conversion. It can do this because it has
  3118.         knowledge of both the old and the new definition file. The old
  3119.         one is on top of the ASCII file and knowledge about the new one
  3120.         is hard coded in the import() function by CSDBGEN.
  3121.  
  3122.  
  3123. 17.18 Member functions in alphabetical order
  3124.  
  3125. Next is a list of the public member functions as they appear in the
  3126. generated class.
  3127. With the sole exception of open() and define(), the database needs to be
  3128. open for these functions to work properly.
  3129.  
  3130. void append_blank(void);
  3131.                 Appends an additional record to the database. The
  3132.                 record is filled with binary zeros and becomes the
  3133.                 current record.
  3134. int bottom(void);
  3135.                 The current record is set to the last record according to
  3136.                 the active index. The function returns FALSE if the
  3137.                 database is empty, otherwise TRUE is returned.
  3138. int close(void);
  3139.                 Closes the open files. All buffers are flushed and all
  3140.                 allocated memory is released. This function is called
  3141.                 automatically by the class destructor if needed. The
  3142.                 function always returns TRUE.
  3143. long curr_rec(void);
  3144.                 Returns the number of the current record. The first
  3145.                 record is number 1.
  3146. int define(void);
  3147.                 Creates a new database. Files are generated for the
  3148.                 database and all the indexes.
  3149.                 If a file already exists, it's overwritten.
  3150.                 TRUE is returned on success. Otherwise FALSE is
  3151.                 returned and the error_nr() function will return the error
  3152.                 generated.
  3153. void delet(void);
  3154.                 Marks the current record for deletion. When the pack()
  3155.                 function is called all the marked records are removed
  3156.                 from the database.
  3157. int export(char *filename);
  3158.                 Writes the contents of the database to an ASCII file
  3159.                 'filename'. This file is meant to be read back by the
  3160.                 import() function. The exported file contains a header
  3161.                 which resembles the 'database definition file'. The
  3162.                 function returns TRUE on succes, FALSE otherwise.
  3163. int go_to(long rec_nr);
  3164.                 The record 'rec_nr' becomes the current record.
  3165.                 Whether or not the record is marked for deletion
  3166.                 makes no difference.The function returns TRUE on
  3167.                 succes, FALSE otherwise.
  3168. int import(char *filename);
  3169.                 Reads records from an ASCII file 'filename' generated
  3170.                 by the export() function and appends these records to
  3171.                 the database. TRUE is returned on success, FALSE
  3172.                 otherwise.
  3173. int is_delet(void);
  3174.                 This function returns TRUE if the current record is
  3175.                 marked for deletion, FALSE otherwise.
  3176. long numrec(void);
  3177.                 Returns the number of records currently in the
  3178.                 database. The records marked for deletion are also
  3179.                 counted.
  3180. int open(void);
  3181.                 Opens the database for use. The define() function has
  3182.                 to be called, that is, the database file needs to exist.
  3183.                 Index files are automatically generated if they are
  3184.                 missing. TRUE is returned on success. Otherwise
  3185.                 FALSE is returned and the error_nr() function will
  3186.                 return the error generated.
  3187. int order(void);    Returns the number of the current active index.
  3188. int order(int index_number);
  3189.                 This function controls the use of indexes. The variable
  3190.                 'index_number' indicates which index has to become
  3191.                 the active index. All the indexes however, are updated
  3192.                 when a record is altered. In the header file a
  3193.                 preprocessor constant is defined for each index. The
  3194.                 name of this constant is generated by converting the
  3195.                 field name to upper case and adding _INDEX.
  3196.  
  3197.     Example:
  3198.        An index on field:       Street
  3199.        Preprocessor constant:   STREET_INDEX
  3200.        <Class>.order(STREET_INDEX);
  3201.        will make the index on the street field the active index.
  3202.        <Class>.order(UNSORTED);
  3203.        makes all the indexes inactive.
  3204.  
  3205.                 Changing the active index does not alter the current
  3206.                 record. The preprocessor constant UNSORTED can
  3207.                 be used to render all the indexes inactive. The
  3208.                 database will be browsed in its 'natural' order.
  3209.                 The function returns TRUE on succes, FALSE
  3210.                 otherwise.
  3211. int pack(void);
  3212.                 Removes all the records marked for deletion. No
  3213.                 temporary files are used!
  3214.                 The function returns TRUE on succes, FALSE
  3215.                 otherwise.
  3216. int reindex(void);
  3217.                 Rebuilds all the indexes of the database. The function
  3218.                 returns TRUE on succes, FALSE otherwise.
  3219. int search(void *key);
  3220.                 The active index is searched for value 'key'. The
  3221.                 current record becomes the first record which matches
  3222.                 the search value. The function accepts a pointer to
  3223.                 the search argument. When the search argument is
  3224.                 not exactly matched, the current record becomes the
  3225.                 record with next  higher' value. In this case the funtion
  3226.                 will return TRUE.
  3227.                 If no  higher' value is available, the last record
  3228.                 becomes the current and the function returns FALSE.
  3229.                 This strategy proofs to work fine when searching for
  3230.                 names etc..
  3231. int skip(int delta=1);
  3232.                 Moves the current record pointer delta positions.
  3233.  
  3234.     Examples:
  3235.        skip(1); // The next record becomes the current record.
  3236.        skip(-1);// The previous record becomes the current record.
  3237.        skip(0); // Nothing happens.
  3238.        skip(10);// The record 10 positions to the end becomes
  3239.                 // the current record.
  3240.        skip();  // Same as skip(1);
  3241.  
  3242.                 If an attempt is made to go 'before' the first record,
  3243.                 record number 1 becomes the current record. Similar,
  3244.                 the last record becomes the current record if an
  3245.                 attempt is made to pass beyond the last record. The
  3246.                 order in which the records are traversed is controlled
  3247.                 by the current active index. The function returns the
  3248.                 number of positions actually moved.
  3249. int tBOF(void); Test for Beginning Of File.
  3250. int tEOF(void); Test for End Of File.
  3251.                 The functions return TRUE if the end is reached,
  3252.                 (according to the active index) FALSE is returned
  3253.                 otherwise.
  3254. int to_DBASE(char *filename);
  3255.                 Exports the database to a file 'filename', which can be
  3256.                 read by dBASE. Index files (for dBASE) are NOT
  3257.                 generated. The function returns TRUE on succes,
  3258.                 FALSE otherwise.
  3259. int top(void);
  3260.                 The current record is set to the first record according to
  3261.                 the active index. The function returns TRUE on
  3262.                 succes, FALSE otherwise.
  3263. void undelet(void);
  3264.                 If the current record is marked for deletion, this
  3265.                 function removes the marker.
  3266.  
  3267.  
  3268. 17.19 Warning
  3269.  
  3270. The program generator is not 'fool proof'. This means that you
  3271. should avoid using names which already are reserved C++ key
  3272. words. E.g. if you try to define a field with the name 'delete' the resulting
  3273. source will not compile.
  3274.  
  3275.  
  3276. 17.20 A Large Example
  3277.  
  3278. Let's say we want to build a database with stores a person's name and
  3279. his/hers birthday.
  3280.  
  3281. Step 1
  3282.  
  3283. First we need to construct a definition file. Next is a working example.
  3284.  
  3285.  
  3286. class:  BIRTH
  3287. record: BRecord
  3288. file:   bdays
  3289. field:  name    s 30 T
  3290. field:  birthday    d Y4MD Y
  3291.  
  3292.  
  3293. Assume the name of this definition file is 'birth.def'.
  3294.  
  3295. Step 2
  3296.  
  3297. From the definition file we have to generate the source for the database.
  3298. We do that by calling CSDBGEN.
  3299.  
  3300.  
  3301. c:\borlandc\csutil\test> csdbgen birth.def
  3302.  
  3303.  
  3304.  
  3305. This produces two output files: 'birth.cpp' and 'birth.h'.
  3306. These names are derived from the name of the definition file. Not from
  3307. the class name as one might expect from this example.
  3308.  
  3309.  
  3310. Step 3
  3311.  
  3312. We are now ready to start compiling. Normally, creating the database will
  3313. be an option in the main menu of the application, but because this is a
  3314. demonstration we do things differently.
  3315.  
  3316.  
  3317. #include "iostream.h"
  3318. #include "birth.h"
  3319.  
  3320. void main(void)
  3321. {
  3322.  
  3323.    BIRTH db;            // Declare an instance of the new BIRTH class.
  3324.  
  3325.    if(!db.define()) // Create the database and its indexes.
  3326.    { cout<<"Error "<<endl; }
  3327.  
  3328. }
  3329.  
  3330.  
  3331. Compile this together with the 'birth.cpp' file and link it.
  3332.  
  3333. When ran, it should create three files:
  3334. - 'bdays.dbf'   The TBASE main database file.
  3335. - 'bdays01.idx' The BTREEa index on the field name.
  3336. - 'bdays02.idx' The BTREEl index on the field birthday. Remember,
  3337.                 dates are stored as longs.
  3338.  
  3339. If you run CSDIR in the same directory it will show something like this:
  3340.  
  3341.  
  3342.  
  3343. Directory C:\BORLANDC\CSUTIL\TEST\
  3344.  
  3345. Name                Size      Type      Entries     Created      Updated
  3346. --------------------------------------------------------------------------
  3347. BDAYS.DBF            174      TBASE           0   Nov 01 1994  Nov 01 1994
  3348. BDAYS01.IDX          174      BTREEa          0   Nov 01 1994  Nov 01 1994
  3349. BDAYS02.IDX          174      BTREEl          0   Nov 01 1994  Nov 01 1994
  3350. --------------------------------------------------------------------------
  3351. Total:               522 bytes in   3 files.
  3352.  
  3353.  
  3354.  
  3355.  
  3356. Step 4
  3357.  
  3358. By now, we have created the database files and we have the class to
  3359. work with it. In other words, we are ready to write an 'application'.
  3360.  
  3361.  
  3362. // Some error checking omitted for conciseness.
  3363.  
  3364.  
  3365. #include "iostream.h"
  3366. #include "birth.h"
  3367.  
  3368. void main(void)
  3369. {
  3370.  
  3371.    BIRTH db;            // Declare an instance of the new BIRTH class.
  3372.  
  3373.    if(!db.open())       // Open it.
  3374.    { cout<<" Error "<<endl; exit(1); }
  3375.  
  3376.    db.append_blank();   // Because it's empty, add a blank record
  3377.  
  3378.    db.name("Luke Skywalker");   // Modify the name.
  3379.    db.birthday("2015/07/03");   // Modify the birthday.
  3380.  
  3381.    db.append_blank();           // Add a new record. Becomes the current.
  3382.  
  3383.    db.name("Al Bundy");         // Modify the name.
  3384.    db.birthday("1945/11/30");   // Modify the birthday.
  3385.  
  3386.    db.reindex();                // Reindexing. For demonstration purposes.
  3387.                                 // Shouldn't be necessary.
  3388.  
  3389.    db.order(BIRTHDAY_INDEX);    // Make BIRTHDAY the active index.
  3390.    db.top();                    // Go to the oldest person.
  3391.    do
  3392.    { cout<<db.name()<<endl; }   // Display his name.
  3393.    while(db.skip());            // Skip to the next.
  3394.  
  3395.  
  3396.    db.go_to(1);                 // Make record 1 the current record.
  3397.                                 // Index INdependent!
  3398.    db.delet();                  // Mark it for deletion.
  3399.    db.pack();                   // Remove it from the database.
  3400.  
  3401.    db.close();                  // Close database and indexes.
  3402. }
  3403.  
  3404.  
  3405.  
  3406. If you run CSDIR again afterwards, you will see something like this:
  3407.  
  3408.  
  3409.  
  3410. Directory C:\BORLANDC\CSUTIL\TEST\
  3411.  
  3412. Name                Size      Type      Entries     Created      Updated
  3413. --------------------------------------------------------------------------
  3414. BDAYS.DBF           4096      TBASE           1   Nov 01 1994  Nov 01 1994
  3415. BDAYS01.IDX         3072      BTREEa          1   Nov 01 1994  Nov 01 1994
  3416. BDAYS02.IDX         3072      BTREEl          1   Nov 01 1994  Nov 01 1994
  3417. --------------------------------------------------------------------------
  3418. Total:             10240 bytes in   3 files.
  3419.  
  3420.  
  3421.  
  3422.  
  3423.  
  3424.  
  3425.  
  3426.  
  3427.  
  3428.  
  3429.  
  3430.  
  3431.  
  3432.  
  3433.  
  3434.  
  3435.  
  3436.  
  3437.  
  3438.  
  3439.  
  3440.  
  3441.  
  3442.  
  3443.                                Part
  3444.  
  3445.  
  3446.                                Three
  3447.  
  3448.  
  3449.  
  3450.  
  3451.  
  3452.  
  3453.   Next are some classes which can be used where the traditional
  3454.                       database will not do.
  3455.   A VRAM class is discussed which makes it possible to maintain
  3456.                    pointer structures on disk.
  3457.   Two other classes, VBASE and VBAXE, are presented which deal
  3458.                   with variable length records.
  3459.  
  3460.  
  3461.  
  3462.  
  3463.  
  3464.  
  3465.                              18 VRAM
  3466.  
  3467. 18.1 Introduction
  3468.  
  3469. VRAM is without any doubt the most flexible and versatile class in this
  3470. library. Contrary to the traditional database, this one doesn't suffer
  3471. from fixed record sizes and doesn't have problems with deletions.
  3472. In other words: it isn't a database at all!
  3473.  
  3474. Assuming a C++ programmer has a good understanding of a 'heap', it
  3475. shouldn't take long to explain this class. In one sentence, VRAM mimics
  3476. a 'heap on disk'.
  3477.  
  3478. The idea is simple: use functions like 'malloc' and 'free' to manipulate the
  3479. necessary space, just like with an ordinary heap, only this time the heap
  3480. is in fact a file. In this way the data is not lost when the program exits
  3481. while all the flexibility of a heap is still there!
  3482.  
  3483.  
  3484. 18.2 Creating
  3485.  
  3486.         int define(char *name,U16 struclen);
  3487.  
  3488. This is the function needed to create a VRAM system.
  3489. Contrary to what you might have expected, it takes two parameters. The
  3490. first is as usual the file name, the second however, is the maximum size
  3491. you are planning to allocate.
  3492.  
  3493. This differs from the ordinary heap which simply accepts allocations of
  3494. any size right from the start. (Which also explains why the ordinary  heap
  3495. allocations are so amazingly inefficient.)
  3496.  
  3497. In a way, the second parameter 'struclen' is a performance parameter. If
  3498. you like, you can always use the maximum, which is 32 Kb, but this would
  3499. yield a highly inefficient VRAM. The VRAM system will perform better the
  3500. more accurate 'struclen' reflects the true state of affairs. However,
  3501. performance option or not, 'struclen' is a upper limit to what you are
  3502. allowed to allocate. Any attempt to allocate more, will be answered with a
  3503. runtime error.
  3504.  
  3505.  
  3506. // Example VRAM define()
  3507. // Error checking omitted for conciseness.
  3508.  
  3509. #include "CSVRAM.H"
  3510.  
  3511. void main(void)
  3512. {
  3513.  
  3514.     VRAM vr;
  3515.     vr.define("VRAM.TST",614);  // Allocating at most 614 bytes.
  3516.  
  3517. }
  3518.  
  3519.  
  3520.  
  3521. The CSDIR utility recognizes VRAM files. When the example program
  3522. has run, it will display something like:
  3523.  
  3524.  
  3525. Directory C:\BORLANDC\TEST\VRAM\
  3526.  
  3527. Name                Size      Type      Entries     Created      Updated
  3528. --------------------------------------------------------------------------
  3529. VRAM.TST             174      VRAM            0   Nov 18 1994  Nov 18 1994
  3530. --------------------------------------------------------------------------
  3531. Total:               174 bytes in   1 files.
  3532.  
  3533.  
  3534.  
  3535. 18.3 Opening & Closing
  3536.  
  3537. Like all the databases classes in this library, VRAM needs to be 'opened'
  3538. before it can be used and, consequently, 'closed' afterwards.
  3539.  
  3540. syntax: int open(char *name,U16 kb_buf);
  3541.  
  3542. This opens the vram file 'name' and uses 'kb_buf' Kb for buffering.
  3543.  
  3544. syntax: int close(void);
  3545.  
  3546. This closes the VRAM system. This function is also called by the class
  3547. destructor when needed.
  3548.  
  3549.  
  3550. // Example VRAM
  3551. // Error checking omitted for conciseness.
  3552.  
  3553. #include "CSVRAM.H"
  3554.  
  3555. void main(void)
  3556. {
  3557.  
  3558.     VRAM vr;
  3559.     vr.define("VRAM.TST",614);  // Allocating at most 614 bytes.
  3560.  
  3561.     vr.open("VRAM.TST",300);    // Opens VRAM.TST using 300 Kb buffers.
  3562.  
  3563.     // Doing something interesting.
  3564.  
  3565.     vr.close();             // Close VRAM system.
  3566. }
  3567.  
  3568.  
  3569.  
  3570.  
  3571. 18.4 VRAM Pointers
  3572.  
  3573. The normal malloc() function returns a void pointer, unfortunate VRAM
  3574. cannot do that. It uses its own type of pointer: VPOI which is short for
  3575. Virtual POInter. VPOI is a simple 32 bit unsigned long, defined in
  3576. 'CSVRAM.H'. The VPOI also limits the size of a VRAM system to 4 Gb.
  3577. ( Of course you can always use more then one VRAM... )
  3578.  
  3579.  
  3580. There is another important difference between VRAM and a normal
  3581. heap. VRAM distinguishes between reading and writing. The buffer
  3582. system used, cannot tell whether you are making changes. Therefore,
  3583. the programmer need to supply that information by calling different
  3584. functions for reading and writing.
  3585.  
  3586. Reading:    char *R(VPOI p);
  3587. Writing:    char *W(VPOI p);
  3588.  
  3589.  
  3590. // Example
  3591. // Error checking omitted for conciseness.
  3592.  
  3593. #include "CSVRAM.H"
  3594.  
  3595. void main(void)
  3596. {
  3597.  
  3598.     VRAM vr;                // A VRAM system.
  3599.     VPOI vp;                // A VRAM pointer.
  3600.     char *cp;               // A normal character pointer.
  3601.  
  3602.     vr.define("VRAM.TST",614);  // Initially create it.
  3603.  
  3604.     vr.open("VRAM.TST",50); // Opening with 50 Kb buffers.
  3605.  
  3606.     vp=vr.malloc(20);       // Allocate 20 bytes from the virtual heap.
  3607.  
  3608.     cp=vr.W(vp);            // Obtaining a character pointer to
  3609.                         // the allocated space. We are planning to
  3610.                         // write, so the 'W' function is used.
  3611.  
  3612.     strcpy(cp,"Some Data"); // Write data into it.
  3613.  
  3614.     vr.close();         // Close the VRAM system.
  3615.                         // "Some Data" is now on disk!
  3616.  
  3617. }
  3618.  
  3619.  
  3620.  
  3621. From the above example it becomes clear how the VPOI pointers can be
  3622. used. The method is simple: convert them into normal pointers and apply
  3623. standard C++ programming technique.
  3624.  
  3625. Only the last 2 converted VPOI pointers are guaranteed to be
  3626. valid. VRAM has a limited number of buffers, so you cannot
  3627. expect all data to be in ram forever.
  3628. Every time you convert a VPOI pointer into a character pointer by using
  3629. the W() or the R() function, VRAM calculates the corresponding position
  3630. in the file and loads the required page in ram. The pointer returned,
  3631. points directly into this page. Because only the last two pages are
  3632. guaranteed to be in ram under all circumstances, the third time you
  3633. convert a VPOI pointer, it can overwrite a previously loaded page.
  3634.  
  3635. Because at least two pointers are valid, you can copy data from one
  3636. VRAM position to another without using temporary storage.
  3637.  
  3638. With the W() function, the loaded page is marked 'dirty' which makes
  3639. sure it's written back to disk when the page is removed from the buffer
  3640. system. This is not so for the R() function. In that case the page is simply
  3641. discarded.
  3642.  
  3643.  
  3644. // Example, copying between two VPOI pointers.
  3645. // Error checking omitted for conciseness.
  3646.  
  3647. #include "CSVRAM.H"
  3648. void main(void)
  3649. {
  3650.  
  3651.     VRAM vr;
  3652.     VPOI vp1,vp2;
  3653.  
  3654.     vr.open("VRAM.TST",50); // Opening with 50 Kb buffers.
  3655.  
  3656.     strcpy(vr.W(vp1=vr.malloc(20)),"Some Data");    // Allocate and fill
  3657.                                             // one VPOI.
  3658.  
  3659.     vp2=vr.malloc(100);                     // Allocate a second.
  3660.  
  3661.     memcpy(vr.W(vp2),vr.R(vp1),20);         // Copy!
  3662.  
  3663.     vr.close();         // Close the VRAM system.
  3664. }
  3665.  
  3666.  
  3667.  
  3668. 18.5 Fragmentation
  3669.  
  3670. Just as with an ordinary heap, VRAM can suffer from fragmentation. The
  3671. normal heap can become prematurely exhausted because of
  3672. fragmentation while for the VRAM system it only means the file  becomes
  3673. larger then strictly necessary.
  3674. On the other hand: the normal heap gets a fresh start every time the
  3675. program is run while the VRAM files may be in use for years.
  3676.  
  3677. Therefore a defrag() function is available. If you decide to use it, it is best
  3678. to use it regularly. It mainly does three things:
  3679. a)  Joining free space wherever possible.
  3680.     This is not done during normal operation because it may involve
  3681.     additional IO.
  3682. b)  Sorting the empty-data-chains.
  3683.     When space is needed, its taken from the beginning of a empty-
  3684.     chain. After sorting the chains, the empty blocks at the beginning of
  3685.     the file will also be at the beginning of the chain. Eventually this
  3686.     leads to pages at the end becoming completely free and pages at
  3687.     the beginning (almost) full.
  3688. c)  Empty pages above the highest used location are stripped from the
  3689.     file.
  3690.  
  3691. The defrag() function links in a lot of code, it uses an entire
  3692. btree and a temporary file. In a way this makes the defrag()
  3693. function 'bigger' then the rest of the VRAM class combined!
  3694.  
  3695. 18.6 Root
  3696.  
  3697. Under some circumstances you may need a 'starting point' in the VRAM.
  3698. Example:
  3699.     Let's say you are writing some flowcharting program and you have
  3700.     decided that VRAM is a great help in storing and manipulating a
  3701.     flowchart. The flowchart probably consists of several independent
  3702.     parts pointered together. Once in it, each part can be reached by the
  3703.     VPOI's stored in the data structure. This leaves you with just one
  3704.     problem: where does the flowchart start?
  3705.     It takes just one VPOI to store that location and it would be a shame
  3706.     if you needed an additional configuration file for that.
  3707.  
  3708. Therefore two very simple functions are implemented to store and
  3709. retrieve a 'special' VPOI.
  3710.  
  3711. void root(VPOI p);      Stores VPOI 'p'.
  3712. VPOI root(void);        Obtains the VPOI stored with the previous
  3713.                         function.
  3714.  
  3715. These functions just manipulate this single VPOI. They have absolutely
  3716. no effect on the rest of the VRAM system.
  3717.  
  3718. 18.7 Functions in Alphabetical order.
  3719.  
  3720. Prototypes are in 'csvram.h'. With the exception of the define(). open()
  3721. and zap() functions, the class needs to be opened for the functions to
  3722. work.
  3723.  
  3724. U16 alloc(VPOI p);
  3725. U16 alloc(void *p);
  3726.                 Returns the number of allocated bytes at a certain
  3727.                 location. The pointer may be either a VPOI pointer or a
  3728.                 normal pointer to the same location.
  3729. int close(void);    Closes the VRAM system. Returns TRUE on success,
  3730.                     FALSE otherwise.
  3731. int define(char *name,U16 struclen);
  3732.                 Creates the VRAM system 'name' with 'struclen' being
  3733.                 the maximum size of any allocation. Returns TRUE on
  3734.                 success, FALSE otherwise.
  3735. int defrag(void);   Defragments the virtual heap. Returns TRUE on
  3736.                     success, FALSE otherwise.
  3737. int empty(void);    Makes the VRAM system empty. The class remains
  3738.                     open but all allocations will be undone. Returns TRUE
  3739.                     on success, FALSE otherwise.
  3740. U32 number(void);
  3741.                 Returns the number of allocations currently done. This
  3742.                 is the number of malloc()'s minus the number of
  3743.                 free()'s.
  3744. int open(char *name,S16 kb_buf);
  3745.                 Opens VRAM 'name' using 'kb_buf' Kb ram for
  3746.                 buffering. Returns TRUE on success, FALSE
  3747.                 otherwise.
  3748. char *R(VPOI p);
  3749.                 Converts a VPOI pointer into a character pointer. It is
  3750.                 assumed no modifications are going to take place.
  3751. void  root(VPOI p);
  3752.                 Stores VPOI 'p'.
  3753. VPOI root(void);    Obtains the VPOI stored with the previous functions.
  3754. int save(void); Safes all buffered data to disk. All the buffers are
  3755.                 flushed and the header page is updated. Returns
  3756.                 TRUE on success, FALSE otherwise.
  3757. void free(VPOI p);
  3758.                 Frees the VPOI p.
  3759. VPOI malloc(U16  size);
  3760.                 Allocates 'size' amount of bytes from the virtual heap.
  3761.                 The corresponding VPOI is returned.
  3762. char *W(VPOI p);
  3763.                 Converts a VPOI pointer into a character pointer. It is
  3764.                 assumed modifications are going to take place.
  3765. int zap(void);  Closes the VRAM system when needed and restores
  3766.                 all class defaults. Returns TRUE on success, FALSE
  3767.                 otherwise.
  3768.  
  3769.  
  3770.  
  3771.                              19 VBASE
  3772.  
  3773.  
  3774. 19.1 Introduction
  3775.  
  3776. The use and purpose of the VBASE class are much similar to that of
  3777. the TBASE class. There is however, one huge difference, VBASE
  3778. supports variable length records! The 'V' in VBASE stands for 'variable'.
  3779.  
  3780. Compared with TBASE, the differences in the public member functions
  3781. are minimal. The append() function now takes an additional parameter
  3782. indicating the length of the record. The same goes for the write_rec()
  3783. function. Apart from the 'normal' read_rec() function there is now an
  3784. additional read_rec() which returns the length of the obtained record.
  3785.  
  3786. VBASE is a 'stand alone' class. It has nothing to do with the
  3787. databases produced by CSDBGEN.
  3788.  
  3789.  
  3790. 19.2 Using VBASE.
  3791.  
  3792. Using VBASE is very straightforward.
  3793.  
  3794. - Initially create the VBASE system by calling define().
  3795. - Open it through a call to open().
  3796. - Read, write and append records.
  3797. - Close VBASE by calling close().
  3798.  
  3799. That's all!
  3800.  
  3801.  
  3802. // Example
  3803. // Error checking omitted for conciseness.
  3804.  
  3805. #include "csvbase.h"
  3806.  
  3807. void main(void)
  3808. {
  3809.  
  3810.     VBASE vb;
  3811.  
  3812.     vb.relocate_when_shrunk(TRUE);  // Move the record to a better
  3813.                                     // fitting position when shrunk.
  3814.     vb.define("VBASE.dbf",1230);    // Maximum record length 1230 bytes.
  3815.  
  3816.     vb.open("VBASE.dbf", 200);      // Open with 200 Kb buffers.
  3817.  
  3818.     char *s="Some chunk of data. ";
  3819.  
  3820.     vb.append_rec(s,strlen(s)+1);   // Append a record. Notice the length
  3821.                                     // parameter which is not needed with
  3822.                                     // TBASE.
  3823.     char d[200];
  3824.     vb.read_rec(1,d);               // Read record 1 into array 'd'.
  3825.  
  3826.     strcpy(d,"New Data");
  3827.  
  3828.     vb.write_rec(1,d,strlen(d)+1);  // Overwrite record 1 with a new
  3829.                                 // block of data. This does not have
  3830.                                 // to have the same length!
  3831.  
  3832.     vb.close();                 // Ready. Close VBASE. Also called by
  3833.                                 // the class destructor if needed.
  3834.  
  3835. }
  3836.  
  3837.  
  3838. For more information, please read the documentation on the TBASE
  3839. class. (Chapter 15. )
  3840.  
  3841.  
  3842. 19.3 Relocating records
  3843.  
  3844. When an existing record is overwritten with a new bigger record, it no
  3845. longer fits in its original slot, which means the record has to be relocated.
  3846. This is not necessarily so when the record shrinks. In that case you have
  3847. the choice between relocating, which saves disk space but is relatively
  3848. slow or leaving the record where it is and waste some disk space.
  3849.  
  3850. The function 'relocate_when_shrunk()' is there to choose between these
  3851. two strategies. It has to be called before 'define()'.
  3852. Calling 'relocate_when_shrunk(TRUE);' will relocate a record when it
  3853. becomes smaller. 'Relocate_when_shrunk(FALSE);' will leave the
  3854. records in place when possible.
  3855. The default is set to: relocate_when_shrunk(TRUE).
  3856.  
  3857. The function has to be called before 'define()' and its setting
  3858. cannot be altered afterwards.
  3859.  
  3860.  
  3861.  
  3862. 19.4 Limitations.
  3863.  
  3864. VBASE was designed for databases up to around a million records. This
  3865. is not a 'hard' limit, its possible to add many more records but under
  3866. some unfavourable conditions memory utilization can get out of control.
  3867. The way the class uses the available ram is controlled by the open()
  3868. function. Therefore, adding a huge number of records in one go, poses a
  3869. problem. If the records are not appended all at once but with several
  3870. close/open sequences in between, VBASE can easily store 16 million
  3871. records.
  3872.  
  3873. So:
  3874. - Under worst case conditions 1 million records.
  3875. - Under favourable conditions 16 million records.
  3876. - Avoid more then 16 million records.
  3877.  
  3878. The above limitations stem from ram utilization. For those drowning in
  3879. memory, there are also software limitations:
  3880. - maximum file size 4 Gb.
  3881. - 4 billion records.
  3882.  
  3883.  
  3884. Because there are so many 'buts' and 'ifs', there is another class VBAXE,
  3885. discussed in the next chapter, to deal with the larger databases.
  3886.  
  3887. As a rule of thumb, use VBASE for databases up to 1 million
  3888. records and VBAXE for more then 1 million records.
  3889.  
  3890. 19.5 Functions in alphabetical order.
  3891.  
  3892. The function prototypes are in csvbase.h.
  3893.  
  3894.  
  3895. U32 append_rec(void *data,U16 len);
  3896.                 Append a record to the database. 'data' is a pointer to
  3897.                 the data and 'len' is the number of bytes data. The
  3898.                 function returns the number of the newly created
  3899.                 record.
  3900. int close(void);
  3901.                 Closes the database. All buffers are flushed and all
  3902.                 allocated memory is freed. TRUE is returned on
  3903.                 success, FALSE otherwise.
  3904. int define(char *name,U16 struclen);
  3905.                 Creates a new database. 'name' is the name of the file
  3906.                 and 'struclen' is the maximum length of a record. Do
  3907.                 not make 'struclen' unnecessary large because its
  3908.                 value controls space efficiency. The maximum value of
  3909.                 struclen is 32767. TRUE is returned on success,
  3910.                 FALSE otherwise.
  3911. void delet(U32 record);
  3912.                 Marks record 'record' for deletion. Only the 'delete bit'
  3913.                 is set. The pack() function needs to be called to
  3914.                 actually remove the record from the file.
  3915. void empty(void);
  3916.                 Removes all records from the database. Upon return
  3917.                 the database will contain zero records but will still be
  3918.                 'open'.
  3919. int is_delet(U32 record);
  3920.                 Returns TRUE if record 'record' is marked for deletion.
  3921.                 FALSE otherwise.
  3922. char *locate_rec(U32  rec);
  3923. char *locate_rec_d(U32  rec);
  3924.                 Functions to return a pointer to record 'rec' directly into
  3925.                 the buffer system. The returned pointer can be used to
  3926.                 change the contents of a record but not the length.
  3927.                 Please, read paragraph 15.8.2 about locating before
  3928.                 using these functions.
  3929. U32 numvrec(void);
  3930.                 Returns the number of records currently in the
  3931.                 database.
  3932. int open(char *name,U16 kb_buf);
  3933.                 Opens database 'name', using 'kb_buf' Kb ram for
  3934.                 buffering. Returns TRUE on success, FALSE
  3935.                 otherwise.
  3936. int pack(void); Removes all records marked for deletion. A temporary
  3937.                 file is used. TRUE is returned on success, FALSE
  3938.                 otherwise.
  3939. void read_rec(U32 rec,void *ptr,U16  &length);
  3940.                 Reads record 'rec' and copies it into the buffer 'ptr' is
  3941.                 pointing at. The variable 'length' is set to the length of
  3942.                 the retrieved record.
  3943. void read_rec(U32 pos,U16  maxlen,void *ptr,U16  &length);
  3944.                 The same as the precious function but with an
  3945.                 additional parameter 'maxlen' specifying the maximum
  3946.                 number of bytes that can be copied into the buffer 'ptr'.
  3947.                 If the record proofs to be longer then 'maxlen', only
  3948.                 'maxlen' bytes will be copied to 'ptr'.
  3949. U16 rec_len(U32 rec);
  3950.                 Returns the length of record 'rec'.
  3951. void relocate_when_shrunk(int TrueOrFalse);
  3952.                 When called with 'TrueOrFalse' set to TRUE, records
  3953.                 will be relocated when shrunk. When called with
  3954.                 FALSE the records will stay at the same place. The
  3955.                 function has to be called before define(). For more
  3956.                 information, please see the paragraph about this topic.
  3957. int save(void); As a precaution measure, all 'dirty' buffers are written
  3958.                 to disk and the header page is updated. The database
  3959.                 remains open. Returns TRUE on success and FALSE
  3960.                 otherwise.
  3961. void undelet(U32 rec);
  3962.                 Removes the 'delete' marking from record 'rec'.
  3963. void write_rec(U32 rec,void *data,U16 len);
  3964.                 Overwrites the existing record 'rec'. 'len' bytes are
  3965.                 copied from 'data'. Afterwards the record will be of
  3966.                 length 'len'.
  3967.  
  3968.                              20 VBAXE
  3969.  
  3970. 20.1 Introduction
  3971.  
  3972. As explained in the previous chapter, VBAXE is similar to VBASE but
  3973. is intended for larger databases. That is, more then 1 million records.
  3974.  
  3975. The public member functions of the classes are 100% identical. The
  3976. inner workings however are completely different. VBAXE uses two files
  3977. for a database where as VBASE uses only one. VBAXE is build from two
  3978. other classes namely TBASE and VRAM.
  3979.  
  3980. Building a class for variable length records is not easy, but writing one
  3981. that can store millions of records, is fast, uses little ram, doesn't use
  3982. unnecessary disk space and still stores everything in one file is next to
  3983. impossible.
  3984. So, rather then coming up with something slow & clumsy, VBAXE gives
  3985. up on storing everything in one file.
  3986.  
  3987.  
  3988. 20.2 Working.
  3989.  
  3990. The working of VBAXE is very simple. It allocates the necessary space
  3991. from VRAM and stores the VRAM pointer together with the length in a
  3992. TBASE record.
  3993. E.g. to obtain record 714 it starts with retrieving record 714 from TBASE.
  3994. Because TBASE uses fixed size records, the position of record 714 can
  3995. easily be calculated. Once this record is obtained, the VRAM pointer to
  3996. the data of record 714 is known. From this pointer the position in the
  3997. VRAM file can again be easily calculated. If nothing is in the buffers, it
  3998. takes two IO's to obtain the data, but at least no searching is done. The
  3999. positions in the files are always known through simple arithmetic.
  4000. ( Which, btw., also holds for the VBASE class.)
  4001.  
  4002.  
  4003. 20.3 Files
  4004.  
  4005. As explained above there are two files to every VBAXE database. The
  4006. TBASE part stores it's data in a file with extension '.vbi'. The VRAM part
  4007. uses extension '.vbd'. If define() or open() is called with with a name
  4008. which already has an extension, that extension will be removed.
  4009.  
  4010. The CSDIR utility recognizes these files and will display the TBASE class
  4011. as VBASEi and VRAM as VBASEd.
  4012.  
  4013.  
  4014. // Example
  4015. // Error checking omitted for conciseness.
  4016.  
  4017. #include "csvbaxe.h"
  4018.  
  4019. void main(void)
  4020. {
  4021.     char buf[1000];
  4022.  
  4023.     VBAXE vb;
  4024.     vb.define("demo",390);      // Max record length 390 bytes.
  4025.  
  4026.     vb.open("demo",200);        // 200 Kb buffers.
  4027.  
  4028.     for(int i=1;i<=100;i++)
  4029.     {
  4030.       vb.append_rec(buf,1+random(390));   // Append 100 records
  4031.                                           // with random length
  4032.                                           // and random contents.
  4033.     }
  4034.  
  4035.     vb.close();             // Close database.
  4036. }
  4037.  
  4038.  
  4039. Afterwards CSDIR will display something like:
  4040.  
  4041.  
  4042.  
  4043. Directory C:\BORLANDC\DEMO
  4044.  
  4045. Name                Size      Type      Entries       Created      Updated
  4046. --------------------------------------------------------------------------
  4047. DEMO.VBI            4096      VBASEi        100   Dec 14 1994  Dec 14 1994
  4048. DEMO.VBD           26624      VBASEd        100   Dec 14 1994  Dec 14 1994
  4049. --------------------------------------------------------------------------
  4050. Total:             30720 bytes in   2 files.
  4051.  
  4052.  
  4053.  
  4054. However, CSINFO will still say DEMO.vbi is a TBASE file and DEMO.vbd
  4055. a VRAM file.
  4056.  
  4057.  
  4058. 20.4 Prototypes.
  4059.  
  4060. The class defintion and it's function prototypes are in "CSVBAXE.H".
  4061.  
  4062.  
  4063.  
  4064.  
  4065.  
  4066.  
  4067.  
  4068.  
  4069.  
  4070.  
  4071.  
  4072.  
  4073.  
  4074.  
  4075.  
  4076.  
  4077.  
  4078.  
  4079.  
  4080.  
  4081.  
  4082.  
  4083.                                Part
  4084.  
  4085.  
  4086.                                Four
  4087.  
  4088.  
  4089.  
  4090.  
  4091.  
  4092.  
  4093.  
  4094.     Part  four discusses the low-level OLAY and DLAY classes.
  4095.             Basically, these classes work as a normal
  4096.         sequential file but with two whopping differences:
  4097.                    insertions and deletions!!
  4098.  
  4099.         It also covers IBASE, which implements a database
  4100.           class with the ability to insert and delete
  4101.                   records anywhere in its file.
  4102.  
  4103.  
  4104.  
  4105.  
  4106.                               21 OLAY
  4107.  
  4108.  
  4109.  
  4110. 21.1 Introduction & Overview
  4111.  
  4112. The OLAY class performs the same functions as a normal sequential
  4113. file but with two major additions: insertions and deletions!
  4114. This makes it possible to insert or delete data anywhere in the file. This is
  4115. not done by copying the entire file, but by moving data 'around' inside.
  4116.  
  4117. It takes a while to realise the potential of such a system!
  4118.  
  4119. It seems to us that several, very basic, problems in computer
  4120. programming are related to the limitations of the filesystem. E.g.
  4121. wordprocessing would be a lot easier if you could simply add or delete
  4122. every character/sentence directly into the file. In databases it would also
  4123. be a great help, making it possible to delete a record strait away, instead
  4124. of using a tag/pack technique.
  4125.  
  4126. The OLAY class encapsulates the standard file system and adds insert &
  4127. delete functionality. Still, through the public member functions, the data
  4128. will appear as an contingious stream of bytes.
  4129.  
  4130.  
  4131.  
  4132. 21.2 Buffering
  4133.  
  4134. Just as the (other) database classes in this library, the OLAY class is
  4135. derived from the PAGE class. This means it has a build in buffering
  4136. system.
  4137.  
  4138.  
  4139. 21.3 Performance
  4140.  
  4141. Due to its build-in-buffering, the OLAY system normally outperfoms the
  4142. traditional file system.
  4143. However, the OLAY files are not 100% full. It depends on the type of
  4144. application, but 70% effectively used disk space seems a typical value.
  4145.  
  4146.  
  4147. 21.4 Core Functions
  4148.  
  4149. The features of the OLAY class are implemented through a small set of
  4150. functions called "core functions". Several more functions are discussed in
  4151. the remaining parts of the chapter but these functions are not strictly
  4152. necessary for using the OLAY class. They are merely implemented for
  4153. convenience.
  4154. The core functions produce the smallest and fastest code.
  4155.  
  4156. This section will only discuss the core functions.
  4157.  
  4158. These functions are:
  4159.  
  4160. int define()    To create an OLAY file.
  4161. int open()      To open it.
  4162. U32 read()      To read from it.
  4163. int write()     To overwrite existing data.
  4164. int delet()     To delete data.
  4165. int insert()    To insert data.
  4166. int append()    To append data.
  4167. int close()     To close the file.
  4168. U32 filesize()  To return the file size.
  4169. U32 bottom()    To return the last position in the file.
  4170.  
  4171. The function prototypes are in "CSOLAY.H".
  4172. First a working example.
  4173.  
  4174.  
  4175. // Error checking omitted for conciseness.
  4176.  
  4177.  
  4178. #inlude  "iostream.h"
  4179. #include "CSOLAY.H"
  4180.  
  4181. void main(void)
  4182. {
  4183.     char buf[100];          // A text buffer.
  4184.     OLAY db;                // An instance of the OLAY class.
  4185.  
  4186.     db.define("demo.fil");  // Creating the file.
  4187.  
  4188.     db.open("demo.fil",100);// Open the file.
  4189.                             // Use 100 Kb ram for buffering.
  4190.  
  4191.     strcpy(buf,"Some chunk of data");
  4192.     db.append(buf,strlen(buf)+1); // The file is empty.
  4193.                                   // Append some data.
  4194.  
  4195.     db.insert(5," larger",7);  // Insert 7 bytes at position '5'.
  4196.                                // (The first byte is at position '1'.)
  4197.  
  4198.  
  4199.     db.read(1,buf,db.filesize());
  4200.                             // Read everything back.
  4201.  
  4202.     cout<<buf;              // Displays: Some larger chunk of data
  4203.  
  4204. }
  4205.  
  4206.  
  4207.  
  4208. This program will create the file 'demo.fil' on your harddisk. Only the
  4209. OLAY class can make sense out of it. E.g. the DOS command 'type' will
  4210. only produce garbage. The OLAY files have to be treated as any other
  4211. database file. That is: use them with the application they belong to,
  4212. nothing else. 21.4.1 Creating
  4213. The OLAY class requires a file to be explicitely created before it can be
  4214. opened.
  4215.  
  4216. int  define(char *name);
  4217.                 This creates the file 'name' on your harddisk and
  4218.                 inserts the correct header block. If the file already
  4219.                 exists, it is overwritten! The function returns TRUE on
  4220.                 success and FALSE otherwise.
  4221.  
  4222. 21.4.2 Opening
  4223. Before an OLAY file can be used it has to be opened. The open function
  4224. does not distinguish between reading, writing or appending.
  4225.  
  4226. int  open(char *name,U16 kb_buf=30);
  4227.                 This opens the file 'name' using 'kb_buf' Kb ram for
  4228.                 buffering. 'kb_buf' has a default value of 30 Kb. The
  4229.                 function returns TRUE on success and FALSE
  4230.                 otherwise.
  4231.  
  4232. 21.4.3 Reading and Writing
  4233. If you like, you can think of the OLAY class as a database with records of
  4234. only one byte. The first record/byte is, as always, at position 1. Fortunate,
  4235. we are not forced to read and write only one byte at the time.
  4236.  
  4237. U32 read(U32 pos,void *p,U32 length);
  4238.                 Reads 'length' bytes, starting of from position 'pos'.
  4239.                 The data is copied to pointer 'p', which should be
  4240.                 pointing to a buffer large enough to hold 'length' bytes.
  4241.                 If the end of file is reached before 'length' bytes are
  4242.                 read, the copying process stops without an error. The
  4243.                 function returns the number of bytes actually copied to
  4244.                 'p'.
  4245.  
  4246. int write(U32 pos,void *p,U32 length);
  4247.                 This function writes, or to be more precise, overwrites
  4248.                 'length' bytes starting off from position 'pos'. The data
  4249.                 is copied from 'p'. The already present data is
  4250.                 overwritten. Write() can not append data to the file.
  4251.                 Trying to write more data then exists between 'pos' and
  4252.                 end-of-file is an error. The function returns TRUE on
  4253.                 success, FALSE otherwise.
  4254.  
  4255. 21.4.4 Insert & Delete
  4256. The beauty of the OLAY class lays in its ability to instantly insert or
  4257. delete data in/from its file. Inserting and deleting also implies the
  4258. remaining data in the file changes position. E.g. if you insert 10 bytes at
  4259. position 5 the data which was originally at position 120 is now at 130!
  4260.  
  4261. S32 delet(U32 pos,S32 length)
  4262.                 Deletes from position 'pos' 'length' number of bytes.
  4263.                 The position 'pos' itself is also deleted. Remember: the
  4264.                 first byte is postition 1. If 'length' is less then or equal to
  4265.                 0 the function returns 0. When an attempt is made to
  4266.                 delete more data then is left in the file, all the remaing
  4267.                 data will be deleted. The function returns the number
  4268.                 of bytes actually deleted.
  4269.  
  4270. int insert(U32 pos,void *buffer,U32 len)
  4271.                 The insert() function insert 'len' number of bytes copied
  4272.                 from 'buffer' at position 'pos'. The byte at position 'pos'
  4273.                 itself is also moved. This means that a call to insert()
  4274.                 with 'pos' equal to 1 inserts new data before ALL other  data.
  4275.  
  4276. // Example
  4277. // Error checking omitted for conciseness.
  4278.  
  4279.     // This program will display the string
  4280.     // 'Led Zeppelin' on the screen.
  4281.  
  4282. void main(void)
  4283. {
  4284.     char buff[200];
  4285.     OLAY db;
  4286.  
  4287.     db.define("test.dbf");
  4288.     db.open("test.dbf",40);
  4289.  
  4290.     strcpy(buff,"Zeppelin");
  4291.     db.append(buffer,strlen(buffer)+1); //Write terminating zero also.
  4292.  
  4293.     strcpy(buff,"Led ");
  4294.     db.insert(1,buffer,strlen(buffer)); //Insert before everything.
  4295.  
  4296.     db.read(1,buff,db.filesize());      //Read it all back.
  4297.     puts(buff);
  4298.  
  4299. }
  4300.  
  4301.  
  4302.  
  4303. 21.4.5 Filesize & bottom
  4304.  
  4305. U32 bottom(void);
  4306.                 The function returns the position directly after the last
  4307.                 byte in the file: the first 'free' position. If the OLAY file is
  4308.                 empty, bottom() will return 1.
  4309.  
  4310. U32 filesize(void);
  4311.                 This function returns the number of bytes in the OLAY
  4312.                 file. This is not the size of the file on disk, but the
  4313.                 number of bytes that can be read by the 'read()'
  4314.                 function.  This value is equal to bottom()-1.
  4315.  
  4316. 21.4.6 Closing
  4317.  
  4318. The OLAY class does a lot of buffering. A close() function is needed to
  4319. safe all the data to disk.
  4320.  
  4321. int  close(void);   Closes the class and the associated file. All buffers are
  4322.                     flushed and all allocated memory is freed. When
  4323.                     needed, the function is automatically called by the
  4324.                     class destructor. The function returns TRUE on
  4325.                     success and FALSE otherwise.
  4326. 21.5 Additional functions
  4327.  
  4328. Next are some functions to 'make live easy'. They are not essential for
  4329. working with the OLAY class.
  4330.  
  4331. int  writea(U32 pos,void *p,U32 len);
  4332.                 The normal write() function cannot append data. This
  4333.                 function can. It uses the write() function to overwrite
  4334.                 excisting data and calls the append() function when
  4335.                 data has to be added to the file. It (over)writes 'len'
  4336.                 bytes starting of from position 'pos'. The data is copied
  4337.                 from pointer 'p'. The function returns TRUE on
  4338.                 success, FALSE otherwise.
  4339.  
  4340.  
  4341. // Example
  4342. // Error checking omitted for conciseness.
  4343.  
  4344. void main(void)
  4345. {
  4346.     OLAY db;
  4347.     int  i=3;
  4348.     long l=4;
  4349.  
  4350.     db.define("example.dbf");       //Create an empty file.
  4351.     db.open("example.dbf",100);     //Use 100 Kb for buffering.
  4352.     db.append(&i,sizeof(int));      //Append 'i'. (2 bytes)
  4353.     db.writea(1,&l,sizeof(long));   //Overwrite 'i' with 'l'. (4 bytes)
  4354.                                     //The normal write() cannot do this,
  4355.                                     //because data has to be appended!
  4356.     db.close();
  4357. }
  4358.  
  4359.  
  4360. int replace(U32 pos,U32 old_len,void *buffer,U32 new_len);
  4361.                 This function makes it possible the replace a block of
  4362.                 data with a new block data of different size. (The new
  4363.                 block can be smaller or bigger.)
  4364.                 'pos':      the position of the first byte which is to be
  4365.                             replaced.
  4366.                 'old_len':  length of the chunck which needs to be
  4367.                             replaced.
  4368.                 'buffer':   pointer to the buffer which holds the new
  4369.                             data.
  4370.                 'new_len':  number of bytes which has to replace the
  4371.                             original 'old_len' bytes.
  4372.                 TRUE is returned on success, FALSE otherwise.
  4373.  
  4374. int  inserta(U32   pos,void *p,U32 len);
  4375.                 An inline function which calls insert() or append()
  4376.                 depending on the value of pos. Its purpose is to
  4377.                 overcome a limitation of the basic insert() function
  4378.                 which cannot properly handle inserts beyond the end
  4379.                 of the file (which of course are in fact appends).
  4380.                 The function inserts or appends data at position 'pos'.
  4381.                 If 'pos' is equal to 'bottom()' it calls append(),
  4382.                 otherwise insert(). 'len' bytes are copied from
  4383.                 pointer 'p'.
  4384.                 TRUE is returned on success, FALSE otherwise.
  4385.  
  4386. 21.6 Import & Export
  4387.  
  4388. The OLAY class stores its data in a format that is not compatible with
  4389. anything else. Therefore two sets of functions are available to convert to-and-from a normal sequential file.
  4390.  
  4391. int  export_bin(char *name);
  4392. int  export_asc(char *name);
  4393. int  export(char *name,int bin_mode=TRUE);
  4394.                 Exports all data to the file 'name'. 'Name' will be a
  4395.                 normal sequential file. If it already exists it will be
  4396.                 overwritten. If not, it is created. The variable
  4397.                 'bin_mode' controls the mode in which 'name' is
  4398.                 opened. 'Bin_mode' equal to TRUE, as is the default,
  4399.                 will open the export file in binary mode. A value of
  4400.                 FALSE opens it in ascii mode. In addition, two inline
  4401.                 functions are defined, export_bin() and export_asc(),
  4402.                 which call import with bin_mode set to respectively
  4403.                 TRUE and FALSE.
  4404.                 The status of the OLAY class will remain unchanged.
  4405.                 TRUE is returned on success, FALSE otherwise.
  4406.  
  4407. int  import_asc(char *name);
  4408. int  import_bin(char *name);
  4409. int  import(char *name,int bin_mode=TRUE);
  4410.                 The import function appends the data from the file
  4411.                 'name' to the current OLAY system. The file 'name' can
  4412.                 be opened in binary or in ascii mode, controlled by the
  4413.                 parameter 'bin_mode'. 'Bin_mode' equal to TRUE, as
  4414.                 is the default, will open the export file in binary mode.
  4415.                 A value of FALSE opens it in ascii mode. Two inline
  4416.                 functions are defined, import_asc() and import_bin(),
  4417.                 which call the import() function with 'bin_mode' set to
  4418.                 respectively FALSE and TRUE.
  4419.                 TRUE is returned on success, FALSE otherwise.
  4420.  
  4421.  
  4422. // Example
  4423. // Error checking omitted for conciseness.
  4424.  
  4425.     OLAY db;
  4426.     db.define("example.bin");   // Start off with a new file.
  4427.                                 // (Not a prerequisite for applying
  4428.                                 // the import() function.)
  4429.     db.open("example.bin",300); // Open the file.
  4430.     db.import_bin("somefile.bin");  // Load it with the data from
  4431.                                 // 'somefile.bin', assuming this
  4432.                                 // exists.
  4433.     db.close();                 // Close the OLAY class.
  4434.  
  4435.  
  4436.  
  4437. 21.7 Sequential functions
  4438.  
  4439. Completely independent of the functions discussed sofar, another set of
  4440. functions is implemented which follows, as closely as possible, the
  4441. standards set by the ANSI committee. Again, these functions are not
  4442. strictly necessary to use the OLAY class, but they have some advantages
  4443. when traversing a file sequentially. Therefore they are called 'sequential
  4444. functions'.
  4445. These functions are build around  file pointer'. This file pointer is
  4446. automatically moved forward with the amount of data read or written.
  4447. The OLAY class itself doesn't use a file pointer, it has no need for it. To
  4448. implement the sequential functions, a file pointer is simulated by a
  4449. variable. This variable is referred to as  VFP', which is short for  virtual file
  4450. pointer'. However, the OLAY class is capable of using the VFP to
  4451. optimize the process of locating a particular byte. In other words. ( E.g. it
  4452. is easier for the OLAY class to locate position 'p' if it already knows where
  4453. position 'p-1' is. )
  4454.  
  4455. Only the sequential functions use the VFP. All the other
  4456. functions DO NOT use it and consequently don't update it!
  4457. Because of this, it's propably best not to try mixing the sequential
  4458. functions with the others. But if you do, you have to reposition the VFP by
  4459. calls to the fseek() function every time you have called a function which
  4460. does not belong to the set of sequential functions!
  4461.  
  4462.  
  4463.  
  4464. The sequential functions are:
  4465.  
  4466. int  fseek()        // To position the VFP.
  4467. long ftell()        // To return the position in the file.
  4468. int  feof()         // To test for end-of-file.
  4469. int  fgetc()        // To read a character.
  4470. int  fputc()        // To write a character
  4471. int  fread()        // To read blocks of data.
  4472. int  fwrite()       // To write blocks of data.
  4473. char *fgets()       // To read strings.
  4474. int  fputs()        // To write strings.
  4475. long fdelete()      // To delete data.
  4476. int  finsert()      // To insert data.
  4477. void fflush()       // To flush the buffers.
  4478.  
  4479. There are no sequential functions for opening, closing or
  4480. creating the file. You still have to use the 'normal' open(),
  4481. close() and define() functions for that.
  4482.  
  4483. 21.7.1 Sequential functions in alphabetical order
  4484.  
  4485. long fdelete(long amount);
  4486.                 Its working is fully equivalent to the 'delet()' function,
  4487.                 except in this case the position from which the data is
  4488.                 deleted is controlled by the virtual file pointer.
  4489.                 The first byte deleted, is the one pointed at by the VFP.
  4490.                 The VFP remains unchanged. The function returns the
  4491.                 number of bytes actually deleted.
  4492.  
  4493. int feof(void); Inline function which returns TRUE if the VFP is
  4494.                 beyond the last byte, and FALSE otherwise. Because
  4495.                 moving the VFP beyond 'bottom()' produces a runtime
  4496.                 error, this can only mean that the VFP points exactly to
  4497.                 'bottom()'.
  4498.  
  4499.  
  4500. // Example
  4501. // Error checking omitted for conciseness.
  4502.  
  4503.     OLAY db;
  4504.     char c;
  4505.  
  4506.     db.open("example.dbf");     // Accept the default 30 Kb for buffering.
  4507.     db.fseek(0);                // Don't assume the VFP is set.
  4508.     while(!db.feof())           // Read until the end.
  4509.     {
  4510.        c=db.fgetc();
  4511.        putchar(c);
  4512.     }
  4513.  
  4514.     db.close()      // If omitted, called by the class destructor.
  4515.  
  4516.  
  4517.  
  4518. void fflush(void);
  4519.                 All dirty buffers are written back to disk. It is important
  4520.                 to understand that this is all it does. Afterwards the file
  4521.                 on disk is still in an undefined state. Only the close()
  4522.                 function produces a disk file which is valid input for the
  4523.                 next call to open(). Mainly implemented for
  4524.                 completeness.
  4525.  
  4526. int fgetc(void);    The function reads an unsigned char and returns this
  4527.                     as an integer. If the end of the file is reached, fgetc()
  4528.                     returns -1. NOT EOF.
  4529.  
  4530. char *fgets(char *str,int num);
  4531.                 The function reads up to 'num'-1 characters and copies
  4532.                 them to 'str'. Bytes are read until a newline character is
  4533.                 encountered or end-of-file reached. Upon success 'str'
  4534.                 is returned, otherwise a NULL pointer is returned. The
  4535.                 VFP is increased with the number of bytes read.
  4536.  
  4537. int finsert(void *buf,long amount);
  4538.                 Its working is fully equivalent to the 'insert()' function,
  4539.                 except the position at which the data is inserted is
  4540.                 controlled by the virtual file pointer. The VFP will be
  4541.                 increased with the number of bytes inserted.
  4542.                 TRUE is returned on success, FALSE otherwise.
  4543.  
  4544. int fputc(int character);
  4545.                 The function accepts an integer which is converted into
  4546.                 an unsigned character and written to the position
  4547.                 indicated by the VFP. (So, only one byte is written.) If
  4548.                 the VFP points beyond the last byte the character is
  4549.                 appended, otherwise it overwrites the existing value.
  4550.                 The VFP is increased with one byte. The return value
  4551.                 is the value written.
  4552.  
  4553. int fputs(char *str);
  4554.                 It is an inline function which calls fwrite(). The contents
  4555.                 of string 'str' is written to disk. The terminating zero
  4556.                 however is NOT written. The VFP is increased with
  4557.                 strlen(str). TRUE is returned on success, FALSE
  4558.                 otherwise.
  4559.  
  4560. int fread( void *buf,int size,int count)
  4561.                 It reads 'count' number of blocks, each of size 'size'.
  4562.                 The data is copied into 'buf'. The function returns the
  4563.                 number of blocks actually read. This differs from 'count'
  4564.                 when an error has occurred or the end of file was
  4565.                 reached. The total amount of data read can exceed
  4566.                 64Kb. The VFP is increased with the amount of data
  4567.                 copied to 'buf'.
  4568.                 TRUE is returned on success, FALSE otherwise.
  4569.  
  4570. int fseek(long offset,int origin=SEEK_SET);
  4571.                 Its purpose is to position the VFP. Depending on the
  4572.                 value of 'origin' offset is taken from:
  4573.                     a) the beginning; origin=SEEK_SET
  4574.                     b) the current position; origin=SEEK_CUR
  4575.                     c) the end; origin=SEEK_END
  4576.                 Fseek() has a default value for 'origin' of SEEK_SET.
  4577.                 Note that 'offset' indeed means offset and NOT
  4578.                 position. Fseek(2) makes the VFP points to the third
  4579.                 byte!
  4580.                 The next two examples both read the first 10 bytes.
  4581.  
  4582.     Example 1:
  4583.  
  4584.        db.fseek(0);
  4585.        db.fread(buffer,10,1);
  4586.  
  4587.     Example 2:
  4588.        db.read(1,buffer,10);
  4589.  
  4590.  
  4591.  
  4592.                 Fseek may be used to move the VFP one byte beyond
  4593.                 the end. This makes the VFP points precisely to
  4594.                 'bottom()'. Trying to move beyond that is an error. Also,
  4595.                 the VFP can not be positioned before the beginning of
  4596.                 the file. When 'origin' is set to SEEK_END the value of
  4597.                 'offset' needs to be positive. Fseek(0,SEEK_END)
  4598.                 makes the VFP points to 'bottom()'.
  4599.                 TRUE is returned on success, FALSE otherwise.
  4600.  
  4601. long ftell(void);   It is an inline function which returns the number of
  4602.                     bytes the VFP is removed from the beginning of the
  4603.                     file.
  4604.                 E.g.:   If the VFP points to the very first byte, ftell will
  4605.                         return zero.
  4606.  
  4607. int fwrite(void *buf,int size,int count);
  4608.                 It writes 'count' number of blocks, each of size 'size'.
  4609.                 The function returns the number of blocks actually
  4610.                 written. This differs from 'count' only when an error has
  4611.                 occurred. The total amount of data written can exceed
  4612.                 64K. The VFP is increased with the amount of data
  4613.                 written to disk.
  4614.  
  4615.  
  4616. 21.7.2 Miscellanious functions
  4617.  
  4618. int already_open(void);
  4619.                 This function returns 1 if the class is 'open' and 0
  4620.                 otherwise.
  4621.  
  4622. int data_2_header(void * ptr,U16 length);
  4623.                 Inherited function.
  4624.  
  4625. int empty(void);    Makes the file empty. The class needs to be open and will still be open afterwards. Upon return the system
  4626.                     will contain 0 bytes data and bottom() points to 1.
  4627.                     TRUE is returned on success, FALSE otherwise.
  4628.  
  4629. int header_2_data(void * ptr,U16 length)
  4630.                 Inherited function.
  4631.  
  4632. void header_page_size(U16 n)
  4633.                 Inherited function.
  4634.  
  4635.  
  4636. U16 max_data_in_header(void)
  4637.                 Inherited function.
  4638.  
  4639. int pack(void)  After a long serie of insert's and/or delete's the data in
  4640.                 the OLAY file can become scattered. Some pages
  4641.                 will contain relatively few data while other pages are
  4642.                 still 100% filled. To put everything back in order it is
  4643.                 adviseable (although not strictly necessary) to call the
  4644.                 pack() function once in a while. The pack() function
  4645.                 uses a temporary file. This file will be about the same
  4646.                 size as the OLAY file. So, make sure sufficient free
  4647.                 disk space is available. If the free space is inadequate,
  4648.                 the function will return 0, the temporary file is removed,
  4649.                 and the OLAY file will be unaltered.
  4650.  
  4651. void page_size(U16 t);
  4652.                 Inherited function.
  4653.  
  4654.  
  4655.  
  4656.  
  4657.                               22 DLAY
  4658.  
  4659.  
  4660. The DLAY class performs the same functions as the previously
  4661. discussed OLAY class. DLAY however, is meant for far larger files.
  4662. Both classes need a complex datastructure to locate a specific byte in the
  4663. file. The OLAY class is keeping this datastructure in ram while DLAY is
  4664. storing it on disk in the same file it uses for the data.
  4665. As a consequence DLAY can handle files of 'unlimited' size where as
  4666. OLAY files should be kept below 5 Mb.
  4667. Because it has its datastructure in ram, OLAY is somewhat faster then
  4668. DLAY.
  4669.  
  4670. So:
  4671. - Use OLAY for files below 5 Mb.
  4672. - Use DLAY for files above 5 Mb.
  4673. - If you are short on ram, use DLAY.
  4674. - If you are not sure, use DLAY.
  4675.  
  4676.  
  4677. 22.1 Performance
  4678.  
  4679. DLAY perfoms quite well. To test its usefulness as 'datastructure' for an
  4680. editor or wordprocessor, the class has been tested on a 100 Mb file. No
  4681. matter the typing speed, the DLAY class was able to individually insert
  4682. every typed character in the middle of his file!
  4683. (Tests done on a 486DX2 66Mhz.)
  4684.  
  4685. 22.2 Member functions
  4686.  
  4687. The public member functions of the DLAY class are 100% indentical to
  4688. those of the OLAY class. Please, refer to the the documentation of the
  4689. OLAY class for more details.
  4690. The function prototypes are in: CSDLAY.H.
  4691.  
  4692.  
  4693.  
  4694.  
  4695.  
  4696.  
  4697.  
  4698.  
  4699.                              23 IBASE
  4700.  
  4701.  
  4702. 23.1 Introduction
  4703.  
  4704. IBASE is a class similar to TBASE. That is: a easy to use class for
  4705. reading and writing records, without indexes. The 'I' in IBASE stands for
  4706. 'insert'. Contrary to TBASE which can only append a record, IBASE can
  4707. insert a record anywhere in its file.
  4708.  
  4709. The IBASE class is derived from DLAY, which explains why it is in this
  4710. section of the documentation. If you have a file-system which can insert
  4711. and delete, then a database system which can insert and delete records
  4712. is all at a sudden easy to implement!
  4713.  
  4714. Deleting records no longer requires the dreaded tag/pack sequence, but
  4715. can be accomplished instantaneously.
  4716.  
  4717.  
  4718. 23.2 Using IBASE
  4719.  
  4720. Using IBASE very much follows the same lines as using TBASE. Deleting
  4721. is now instantaneous, and records can be inserted.
  4722.  
  4723. The performance of IBASE is nowhere near that of TBASE. If
  4724. speed is an issue, you should consider using TBASE.
  4725.  
  4726. 23.3 Using IBASE
  4727.  
  4728. IBASE works very much like TBASE. Please, read the documentation on
  4729. TBASE (chapter 15 ) also. Because the classes are so much alike,
  4730. IBASE will be discussed in far less detail.
  4731.  
  4732. 23.3.1 Creating
  4733.  
  4734. int define(CSCHAR *name,U16  reclen);
  4735.                 Creates the IBASE file 'name' for use of records with
  4736.                 length 'reclen'. TRUE is returned on success, FALSE
  4737.                 otherwise.
  4738.  
  4739. 23.3.2 Opening
  4740.  
  4741. int open(CSCHAR *name,S16 kb=32);
  4742.                 Opens the IBASE file 'name' for use. It will use at most
  4743.                 'kb' Kb ram for buffering. 'kb' has a default value of 32.
  4744.                 TRUE is returned on success, FALSE otherwise.
  4745. int open(void); This function returns TRUE if the class is already
  4746.                 opened. FALSE otherwise.
  4747.  
  4748. 23.3.3 Appending Records
  4749.  
  4750. S32 append_rec(void *data);
  4751.                 Appends record 'data' to the database. The function
  4752.                 returns the record number of the newly added record.
  4753.                 E.g. if a record is added to an empty database the
  4754.                 function will return 1. Don't forget; the first record is
  4755.                 record '1'.
  4756. S32 append_rec(void);
  4757.                 Extends the database with one record. Contrary to the
  4758.                 previous function this one doesn't fill the new record
  4759.                 with data. Time being, the record will contain garbage.
  4760.  
  4761. 23.3.4 Reading
  4762.  
  4763. Contrary to TBASE, IBASE doesn't have 'locate' functions. The reason is
  4764. that a record can now be scattered over two (or even more) different
  4765. database pages. When such a record is in the buffer system it will no
  4766. longer be laying on contingious memory addresses, making it impossible
  4767. to access the record through a single pointer.
  4768.  
  4769. void read_rec(  S32 rec, void *data);
  4770.                 Reads record 'rec' into 'data'. 'data' should be a buffer
  4771.                 large enough to hold the record.
  4772.  
  4773. 23.3.5 Writing
  4774.  
  4775. void write_rec(  S32    rec, void *data);
  4776.                 Overwrites the existing record 'rec' with the record
  4777.                 pointed to by 'data'. Record 'rec' must already exist.
  4778.                 The function can not be used to add records.
  4779.  
  4780. 23.3.6 Inserting
  4781.  
  4782. Inserting a record means just that. A record is inserted between two
  4783. existing records. Let's say you already have a record '2' and a record '3'
  4784. but want a new record in between, because that's where it should be
  4785. according to the alphabet.
  4786. The traditional approach is to add the record at the end of the database
  4787. and to maintain an index for the alphabetical order.
  4788.  
  4789. But now, thanks to the DLAY class, we can do without the index. The
  4790. record can directly be inserted at its correct position.
  4791.  
  4792. int insert_rec_b(S32  rec,void *p);
  4793.                 Insert a new record before record 'rec'. That is: the
  4794.                 new record will become record number 'rec' and the
  4795.                 old record 'rec' becomes record number 'rec'+1. The
  4796.                 pointer 'p' points to the data of the new record. TRUE
  4797.                 is returned on success, FALSE otherwise.
  4798. int insert_rec_a(S32  rec,void *p);
  4799.                 Insert a new record after record 'rec'. That is: the new
  4800.                 record will become record number 'rec'+1. The old
  4801.                 record 'rec' will stay at its place. The pointer 'p' points
  4802.                 to the data of the new record. TRUE is returned on
  4803.                 success, FALSE otherwise.
  4804.  
  4805. 23.3.7 Deleting
  4806.  
  4807. Deleting records is now done instantaniously. E.g. the moment you
  4808. delete record '8', the old record '9' will become the new record '8' and so
  4809. on. In IBASE, there is no such thing as a 'delete bit'.
  4810.  
  4811. void delet(S32  rec);
  4812.                 Deletes record 'rec'. No consecutive 'pack()' is needed.
  4813.  
  4814. 23.3.8 Closing
  4815.  
  4816. int close(void);    Closing the database. All buffers are written back to
  4817.                     disk, all allocated memory is freed. TRUE is returned
  4818.                     on success, FALSE otherwise.
  4819.  
  4820. 23.3.9 Miscellaneous functions
  4821.  
  4822. For the next functions to work properly, the database has to be opened.
  4823.  
  4824. U16 lengthrec(void);
  4825.                 Returns the length of a record. This is the same value
  4826.                 as used in the call to the define() function, when the
  4827.                 database was created.
  4828.  
  4829. S32 numrec(void);
  4830.                 Returns the number of records currently in the
  4831.                 database.
  4832.  
  4833. int pack(void); This is the pack() function inherited from the DLAY
  4834.                 class! This function has nothing to do with deleting
  4835.                 records. Its purpose is to compress the file DLAY uses
  4836.                 to store its data. TRUE is returned on success, FALSE
  4837.                 otherwise.
  4838.  
  4839. int empty(void);    Makes the database empty. Upon function return the
  4840.                     database will contain zero records but the database is
  4841.                     still open. TRUE is returned on success, FALSE
  4842.                     otherwise.
  4843.  
  4844.  
  4845.  
  4846.  
  4847.  
  4848.  
  4849.  
  4850.  
  4851.  
  4852.  
  4853.  
  4854.  
  4855.  
  4856.  
  4857.  
  4858.  
  4859.  
  4860.  
  4861.  
  4862.  
  4863.  
  4864.  
  4865.  
  4866.  
  4867.                                Part
  4868.  
  4869.                                Five
  4870.  
  4871.  
  4872.  
  4873.  
  4874.  
  4875.  
  4876.         Part Five will present some command-line utilities.
  4877.     Most noticeable CSDIR, which gives a quick survey of the
  4878.                databases in the current directory.
  4879.      It also discusses the demonstration application CSADD.
  4880.           CSADD is a DOS application to store addresses.
  4881.  
  4882.  
  4883.  
  4884.  
  4885.                              24 CSDIR
  4886.  
  4887.  
  4888. CSDIR is a command-line utility similar to the well-known MS-DOS dir.
  4889. It's purpose is to list the CS-databases. By default it ignores all other
  4890. files.
  4891.  
  4892.         SYNTAX: csdir [filename] [/A] [/?]
  4893.  
  4894.         filename: the file(s) to be listed. Wildcards allowed.
  4895.         /A  List all files.
  4896.         /?  Display help.
  4897.  
  4898. Example of its output:
  4899.  
  4900.  
  4901. c:\bin\address>csdir
  4902.  
  4903.  
  4904. Directory C:\BIN\ADDRESS\
  4905.  
  4906. Name                Size      Type      Entries     Created      Updated
  4907. --------------------------------------------------------------------------
  4908. CSADR.DBF          98382      TBASE         298   Sep 20 1994  Oct 31 1994
  4909. CSADR01.IDX        40960      BTREEa        403   Oct 29 1994  Oct 31 1994
  4910. CSADR02.IDX        10752      BTREEa        104   Oct 29 1994  Oct 31 1994
  4911. CSADR03.IDX         4608      BTREEl         28   Oct 29 1994  Oct 31 1994
  4912. CSADR04.IDX         5120      BTREEa         22   Oct 29 1994  Oct 31 1994
  4913. --------------------------------------------------------------------------
  4914. Total:            159822 bytes in   5 files.
  4915.  
  4916.  
  4917.  
  4918. As can be seen from this example, CSDIR displays:
  4919.     - the name of the class involved.
  4920.     - the number of entries in the database.
  4921.     - in case of a btree, the number of different keys. If the same key is
  4922.         entered twice, it is counted as one entry.
  4923.     - date of creation.
  4924.     - date of last update.
  4925.  
  4926. Example of the /a option.
  4927.  
  4928.  
  4929. c:\bin\adres>csdir /a
  4930.  
  4931.  
  4932. Directory C:\BIN\ADRES\
  4933.  
  4934. Name                Size      Type      Entries     Created      Updated
  4935. --------------------------------------------------------------------------
  4936. ADRES.EXE         137872       DOS                             Oct 29 1994
  4937. CSDEMIO.DEF          277       DOS                             Apr 17 1994
  4938. BACKUP.TXT         34478       DOS                             Oct 29 1994
  4939. CSADR.DBF          98382      TBASE         298   Sep 20 1994  Oct 31 1994
  4940. CSADR01.IDX        40960      BTREEa        403   Oct 29 1994  Oct 31 1994
  4941. CSADR02.IDX        10752      BTREEa        104   Oct 29 1994  Oct 31 1994
  4942. CSADR03.IDX         4608      BTREEl         28   Oct 29 1994  Oct 31 1994
  4943. CSADR04.IDX         5120      BTREEa         22   Oct 29 1994  Oct 31 1994
  4944. ERROR.ERR          12964       DOS                             Oct 27 1994
  4945. --------------------------------------------------------------------------
  4946. Database files:   159822 bytes in   5 files.
  4947. Other files:      185591 bytes in   4 files.
  4948.                 -------- +        --- +
  4949. Total:            345413 bytes in   9 files.
  4950.  
  4951.  
  4952.  
  4953.  
  4954. Another example:
  4955.  
  4956.  
  4957. c:\bin\adres>csdir cs*.* /a
  4958.  
  4959.  
  4960. Directory C:\BIN\ADRES\
  4961.  
  4962. Name                Size      Type      Entries     Created      Updated
  4963. --------------------------------------------------------------------------
  4964. CSDEMIO.DEF          277       DOS                             Apr 17 1994
  4965. CSADR.DBF          98382      TBASE         298   Sep 20 1994  Oct 31 1994
  4966. CSADR01.IDX        40960      BTREEa        403   Oct 29 1994  Oct 31 1994
  4967. CSADR02.IDX        10752      BTREEa        104   Oct 29 1994  Oct 31 1994
  4968. CSADR03.IDX         4608      BTREEl         28   Oct 29 1994  Oct 31 1994
  4969. CSADR04.IDX         5120      BTREEa         22   Oct 29 1994  Oct 31 1994
  4970. --------------------------------------------------------------------------
  4971. Database files:   159822 bytes in   5 files.
  4972. Other files:         277 bytes in   1 files.
  4973.                 -------- +        --- +
  4974. Total:            160099 bytes in   6 files.
  4975.  
  4976.  
  4977.  
  4978.  
  4979.  
  4980.                              25 CSINFO
  4981.  
  4982.  
  4983. CSINFO is a command-line utility to display information about a
  4984. particular database.
  4985. It only recognizes the databases made with the CSDB-library.
  4986.  
  4987. An example of its output:
  4988.  
  4989.  
  4990.  
  4991. c:\adres>csinfo csadr01.idx
  4992.  
  4993.  
  4994.   Information about database: csadr01.idx.
  4995.  
  4996.    Type..................:  BTREEa
  4997.    Version...............:  1.1.b
  4998.    Class compiled at.....:  Apr 25 1994, 04:28:24
  4999.    With..................:  Borland C++ 3.1
  5000.  
  5001.  NOTE: The above information refers to the version of the
  5002.        class used during the CREATION of the database file.
  5003.  
  5004.    Btree created at......:  September 20 1994, 10:02:11,47
  5005.    Btree last updated at.:  September 26 1994, 23:25:19,96
  5006.    Multiple keys allowed.:  YES
  5007.    Number of keys........:  622
  5008.    Number of blocks......:  111
  5009.    Block size............:  511 bytes
  5010.    Key size..............:  41 bytes
  5011.    Data size.............:  4 bytes
  5012.    Data degree...........:  10
  5013.    Index degree..........:  10
  5014.    Number of levels......:  4
  5015.  
  5016.  
  5017.  
  5018.                             26 CSERROR
  5019.  
  5020.  
  5021. Normally all the errors are read from the file 'error.err'. It has to be in
  5022. the current working directory or it cannot be found.
  5023.  
  5024. Using a runtime error file produces smaller executables because the
  5025. error messages are not linked in.
  5026. However, the error file is not kept open all the time and for opening a file,
  5027. some dynamic memory allocations have to be done.
  5028. This can lead to problems when the error message that has to be
  5029. displayed results from an 'out of memory' condition.
  5030. (It needs memory to say 'there is no more memory'.)
  5031.  
  5032. To overcome this, and other problems, the command-line util CSERROR
  5033. can be used.
  5034. It generates a C source file which, when compiled and linked in, makes
  5035. the runtime error file redundant.
  5036.  
  5037.  
  5038. Example:
  5039. c:\borlandc>cserror error.err
  5040.  
  5041.  
  5042. This will produce a file 'error.cpp' in the current directory. Compile this
  5043. and link it in with the rest of your application. Make sure it's linked in
  5044. before the libraries.
  5045. In this way the csmess_read() function which is in the 'error.obj', will
  5046. replace the one in the library.
  5047.  
  5048.  
  5049. // Example of how the resulting 'error.cpp' file could look:
  5050. // Many errors are left out.
  5051.  
  5052.  
  5053. #include "csmess.h"
  5054.  
  5055. char *_csa_error[]=
  5056.      {
  5057.        "Error 9370: TBASE: %s Can't write report file %s. Disk full?",
  5058.        "Error 9390: TBASE: %s Out of memory during pack().",
  5059.        "Fatal Error 9545: PAGE: %s Header_2_data(): can't perform fseek.",
  5060.        "Fatal Error 9550: PAGE: %s Write_header: can't perform fwrite.",
  5061.        "Fatal Error 9555: PAGE: %s Header_2_data(): can't perform fread.",
  5062.        "Fatal Error 9560: PAGE: %s Can't open file during definition.",
  5063.        "Error 9562: PAGE: %s Can't open report file %s.",
  5064.        "TheEnd"  //THIS HAS TO BE THE LAST LINE!!
  5065.      };
  5066.  
  5067. /////////////////////////////////////////////////////////////////////
  5068.  
  5069. char *csmess_read(long error)
  5070. {
  5071.    char tmp[25];
  5072.    ltoa(error,tmp,10);
  5073.    char **p=_csa_error;
  5074.    for(;;)
  5075.    {
  5076.       if(strstr(*p,tmp)) return *p;
  5077.       if(!strcmp(*p,"TheEnd")) return NULL;
  5078.       p++;
  5079.    }
  5080.  
  5081.  
  5082.  
  5083. Notice the 'TheEnd' line, which was not in the original 'error.err'
  5084. file. Never remove that line!
  5085.  
  5086.                             27 CS4DBASE
  5087.  
  5088.  
  5089. 27.1 Introduction
  5090.  
  5091. The database classes generated by CSDBGEN cannot import a dBASE
  5092. file directly. However, they do have a function to import an ASCII file. This
  5093. function is called import(), and it expects its input file to be in a specific
  5094. format.
  5095.  
  5096. CS4DBASE is a command-line utility which is able to convert a dBASE
  5097. file into a format required by the import() function.
  5098.  
  5099. The generated intermediate ascii file can be manually edited to adjust
  5100. field names.
  5101.  
  5102.  
  5103. 27.2 Converting
  5104.  
  5105. Example:
  5106.  
  5107.  
  5108. c:\bin\dbase> cs4dbase  person.dbf
  5109.  
  5110.  
  5111.  
  5112. Assuming there is a dBASE file 'person.dbf', this will produce the ascii
  5113. file 'person.txt'.
  5114. On top of the file are some lines indicating field names and types. The
  5115. import() function need this information to correctly parse the remainder of
  5116. the file.
  5117.  
  5118. In the example ('person.txt') it looked like this:
  5119.  
  5120.  
  5121. Class:  CONV
  5122. Record: CONV_rec
  5123. File:   conver.dbf
  5124. field:  NAME s 40
  5125. field:  ADRE s 32
  5126. field:  CITY s 35
  5127. field:  UPDATED d
  5128.  
  5129. Museum Langeveld
  5130. Langevelderweg 27
  5131. Noordwijkerhout
  5132. 1994/02/18
  5133.  
  5134. The Truck Giant
  5135. Goeverneurlaan 471
  5136. Den Haag
  5137. 1993/02/16
  5138.  
  5139.  
  5140. The lines before the first   resemble a 'database definition file'. The
  5141. import() function ignores the first three lines but it uses the 'field' lines.
  5142. They have to match the names of the fields in the database definition file
  5143. which generated the import() function, or these fields will be skipped.
  5144.  
  5145. If these names do not match, it maybe necessary to manually edit the
  5146. field names in the ASCII file. The order of the fields never matters.
  5147.  
  5148.  
  5149. 27.3 Example
  5150.  
  5151. Suppose the next database definition file, 'person.def', is used to
  5152. generate the class PERSON.
  5153.  
  5154.  
  5155. Class:  PERSON
  5156. Record: PERSON_rec
  5157. File:   pers.dbf
  5158. field:  NAME    s 40 T
  5159. field:  HOBBY   s 32 Y
  5160. field:  PHONE   s 15
  5161. field:  UPDATED d MDY2
  5162.  
  5163.  
  5164.  
  5165. From this you created a PERSON class by calling CSDBGEN.
  5166.  
  5167.  
  5168. c:\test> CSDBGEN person.def
  5169.  
  5170.  
  5171.  
  5172. Now you want to import some data from an old dBASE database called
  5173. 'member.dbf'.
  5174. However, 'member.dbf' has different fields.
  5175.  
  5176. The dBASE 'display structure' command reveals something like this:
  5177.  
  5178.  
  5179. Structure for database : C:member.dbf
  5180. Number of data records :       3
  5181. Date of last update    : 04/19/95
  5182. Field  Field name  Type       Width    Dec
  5183.     1  MEMBER      Character     30
  5184.     2  TELEPHONE   Character     13
  5185.     3  INTERESTS   Character     50
  5186. ** Total **                      94
  5187.  
  5188.  
  5189.  
  5190. Despite the differences, call CS4DBASE.
  5191.  
  5192.  
  5193. c:\test>CS4DBASE member.dbf
  5194.  
  5195.  
  5196.  
  5197. This produces the file 'member.txt'.
  5198.  
  5199. Class:  CONV
  5200. Record: CONV_rec
  5201. File:   conver.dbf
  5202. field:  MEMBER s 30
  5203. field:  TELEPHONE s 13
  5204. field:  INTERESTS s 50
  5205.  
  5206. Rudolf Mandrake
  5207. 0592-24-2379
  5208. Ancient Building Techniques
  5209.  
  5210. Rachel Labrosse
  5211. 913-814-1378
  5212. Extraterrestrial Encounters
  5213.  
  5214. Victor Plauger
  5215. 312-241-2808
  5216. Home Gardening
  5217.  
  5218.  
  5219. It doesn't make much sense to import this file. All the field names are
  5220. different so the import() function will skip each and every line.
  5221. To alter all that, 'import.txt' has to be edited to make the field names
  5222. match those in 'person.def'.
  5223.  
  5224. After editing it should resemble something like:
  5225. Class:  CONV
  5226. Record: CONV_rec
  5227. File:   conver.dbf
  5228. field:  NAME   s 30
  5229. field:  PHONE  s 13
  5230. field:  HOBBY  s 50
  5231.  
  5232. Rudolf Mandrake
  5233. 0592-24-2379
  5234. Ancient Building Techniques
  5235.  
  5236. Rachel Labrosse
  5237. 913-814-1378
  5238. Extraterrestrial Encounters
  5239.  
  5240. Victor Plauger
  5241. 312-241-2808
  5242. Home Gardening
  5243.  
  5244.  
  5245. Note that de order of the fields is still not the same. However, import() is
  5246. smart enough to overcome that obstacle.
  5247.  
  5248. Now, 'import.txt' can be savely loaded.
  5249.  
  5250. The following code could be used for that.
  5251.  
  5252. #include "person.h"
  5253.  
  5254. void main(void)
  5255. {
  5256.     PERSON pers;
  5257.  
  5258. //  pers.define();  // Uncomment this to create the database.
  5259.  
  5260.     pers.open();
  5261.     pers.import("import.txt");
  5262.     pers.close();
  5263. }
  5264.  
  5265. 27.4 Importing large databases
  5266.  
  5267. As can be seen from the previous example, it is sometimes required to
  5268. load the entire ASCII file in an editor to change the field names. This is
  5269. fine for small databases, but when the number of records increases the
  5270. ASCII file can become too large.
  5271.  
  5272. Solution:
  5273.  
  5274.  
  5275. c:\test>CS4DBASE member.dbf /2
  5276.  
  5277.  
  5278.  
  5279. Note the '/2' at the end of the command.
  5280. This instructs CS4DBASE to generate two files instead of one, namely
  5281. 'member.def' and 'member.txt'.
  5282.  
  5283. 'member.def' will contain:
  5284.  
  5285. Class:  CONV
  5286. Record: CONV_rec
  5287. File:   conver.dbf
  5288. field:  MEMBER s 30
  5289. field:  TELEPHONE s 13
  5290. field:  INTERESTS s 50
  5291.  
  5292.  
  5293. and 'member.txt':
  5294.  
  5295.  
  5296. Rudolf Mandrake
  5297. 0592-24-2379
  5298. Ancient Building Techniques
  5299.  
  5300. Rachel Labrosse
  5301. 913-814-1378
  5302. Extraterrestrial Encounters
  5303.  
  5304. Victor Plauger
  5305. 312-241-2808
  5306. Home Gardening
  5307.  
  5308.  
  5309. The only things which need editing are the field names, and they are
  5310. conveniently placed together in one small ASCII file!
  5311. When the editing is done, the two files have to be joined again to create
  5312. valid input for the import() function.
  5313.  
  5314. Like this:
  5315.  
  5316.  
  5317. c:\test>copy member.def+member.txt member.asc
  5318.  
  5319.  
  5320.  
  5321. 'member.asc' can now be read by the import() function!
  5322.  
  5323.  
  5324.  
  5325.  
  5326.  
  5327.  
  5328.  
  5329.  
  5330.  
  5331.  
  5332.  
  5333.  
  5334.  
  5335.  
  5336.  
  5337.  
  5338.  
  5339.  
  5340.  
  5341.  
  5342.  
  5343.  
  5344.  
  5345.  
  5346.  
  5347.  
  5348.  
  5349.  
  5350.                                Part
  5351.  
  5352.                                 Six
  5353.  
  5354.  
  5355.  
  5356.  
  5357.  
  5358.  
  5359.   Part Six discusses the classes and functions implemented in the
  5360.                           CSA-library.
  5361.  They have nothing to do with databases so you can use or ignore
  5362.                           them at will.
  5363.         However, two chapters may require some attention.
  5364. Alloc-logging which deals with heap corruption and memory leaks.
  5365. The HEAP class for efficiently allocating large numbers of small
  5366.                              blocks.
  5367.  
  5368.  
  5369.  
  5370.  
  5371.                             28 CSTOOLS
  5372.  
  5373.  
  5374. 28.1 Introduction
  5375.  
  5376. Cstools is a collection of odds & ends, merely intended to support the
  5377. other classes, but if you see something to your liking, please feel
  5378. free to use it.
  5379.  
  5380. The function prototypes are in cstools.h.
  5381.  
  5382. int add_path(char *filen,char *path);
  5383.                 Adds path 'path' to filename 'filen'. Afterwards 'filen'
  5384.                 contains the new name. It returns TRUE if successful,
  5385.                 FALSE otherwise.
  5386. int  csrand(int amount);
  5387. U32 csrand(U32 amount);
  5388.                 Returns a VERY random number in the range
  5389.                 0..(amount-1), including both 0 and (amount-1).
  5390. int cstmpname(char *name);
  5391.                 Generates the name of a non-existing file in the 'temp'
  5392.                 directory. It first searches for the environment variable
  5393.                 'TMP' and if not found for 'TEMP'. A filename is
  5394.                 generated which does not already exist in this
  5395.                 directory. The function has to be called with a
  5396.                 parameter 'name' pointing to a buffer large enough to
  5397.                 hold the complete drive, path and filename. If non of
  5398.                 the evironment variables exist, a filename for the
  5399.                 current directory is produced. It only generates a
  5400.                 filename, no file is actually created. The function
  5401.                 returns TRUE if a unique filename was found, FALSE
  5402.                 otherwise.
  5403. int disk(char *s);
  5404.                 Sets the current drive and path as indicated by string
  5405.                 's'. If 's' is the empty string, 's' is set to the current drive
  5406.                 and path! It returns TRUE if successful, FALSE
  5407.                 otherwise.
  5408. void empty_kb(void);
  5409.                 Empties the keyboard buffer.
  5410. int file_exist(char *fnaam);
  5411.                 Returns TRUE if file 'fnaam' exists.
  5412. char *file_ext(char *name,char *ext);
  5413.                 Adds an extension to filename 'name'. It returns a
  5414.                 pointer to an internal buffer which contains the new
  5415.                 name. If 'name' already has an extension, it is
  5416.                 overwritten. The string 'name' itself is not changed!
  5417. long filesize(char *name);
  5418.                 Returns the size of file 'name'.
  5419. void filter_string(char *source,char *allowed);
  5420.                 All the characters in 'source' which are not in 'allowed'
  5421.                 are removed from 'source'.
  5422. void lower_upper(char *ptr);
  5423.                 Converts the entire string to upper case.
  5424. long lrandom(long amount);
  5425.                 Returns a long random number in the range
  5426.                 0..(amount-1), including both 0 and (amount-1).
  5427. size_t next_prime(size_t pri);
  5428.                 Calculates next higher prime number.
  5429. char *notabs(char *s);
  5430.                 Replaces every occurrence of a tab character in 's'
  5431.                 with a single space. That is: tabs are not expanded,
  5432.                 but simply removed.
  5433. char *remove_space(char *s);
  5434.                 Removes ALL the blanks from the string 's'. It returns
  5435.                 character pointer 's'.
  5436. unsigned int  sqrti(unsigned int n);
  5437. unsigned long sqrtl(unsigned long n);
  5438.                 Calculates the sqrt from n WITHOUT USING
  5439.                 FLOATING POINT arithmetic.
  5440. void str_split(char *source,char ch,char *first,char *last);
  5441.                 Split 'string' source at the first occurrence of character
  5442.                 'ch'. Ch is included in neither the 'first' nor the 'last'
  5443.                 string.
  5444. void str_strip(char *source,char *remove);
  5445.                 Characters in 'source' which are also in 'remove' are
  5446.                 removed from 'source'.
  5447. int str_equal(char *s1, char *s2);
  5448.                 Returns TRUE if 's1' is equal to 's2', discriminating
  5449.                 between upper and lower case.
  5450. void str_left(char *source,char *dest,int len);
  5451.                 Copies at most 'len' number of characters from the left
  5452.                 of 'source' to 'dest'.
  5453. char *string_replace_ones(char *source,char *d,char *r);
  5454.                 Replaces the first occurrence of 'd' in 'source' with 'r'.
  5455. int string_replace(char *s,char *d,char *r);
  5456.                 Replaces every occurrence of 'd' in 'source' with 'r'. It
  5457.                 returns an integer number indicating the number of
  5458.                 times a substitution was made.
  5459. long time_stamp(void);
  5460.                 Returns a higher long number on each successive call,
  5461.                 starting with zero again when MAXLONG is reached.
  5462. void trim_string(char *s);
  5463.                 Removes heading and trailing blanks from string 's'.
  5464. void wait(long msec);
  5465.                 Waits 'msec' milliseconds.
  5466. void waitkb(long msec);
  5467.                 Waits 'msec' milliseconds or until the next keyboard
  5468.                 hit.
  5469.  
  5470.                              29 CSKEYS
  5471.  
  5472.  
  5473. Almost all the input for the library functions is done through the cskey()
  5474. function.
  5475.  
  5476. Syntax:
  5477.     int cskey(void);
  5478.  
  5479. The return value can be one of the following symbolic constants: (defined
  5480. in CSKEYS.H )
  5481.  
  5482.      CTRL_A    KEY_A    KEY_a     ALT_A     DELETE      CURSOR_UP
  5483.      CTRL_B    KEY_B    KEY_b     ALT_B     END         CURSOR_DOWN
  5484.      CTRL_C    KEY_C    KEY_c     ALT_C     HOME        CURSOR_RIGHT
  5485.      CTRL_D    KEY_D    KEY_d     ALT_D     PAGE_UP     CURSOR_LEFT
  5486.      CTRL_E    KEY_E    KEY_e     ALT_E     PAGE_DOWN
  5487.      CTRL_F    KEY_F    KEY_f     ALT_F     INSERT
  5488.      CTRL_G    KEY_G    KEY_g     ALT_G     BACKSPACE
  5489.      CTRL_H    KEY_H    KEY_h     ALT_H     TAB
  5490.      CTRL_I    KEY_I    KEY_i     ALT_I     SHIFT_TAB
  5491.      CTRL_J    KEY_J    KEY_j     ALT_J     ENTER
  5492.      CTRL_K    KEY_K    KEY_k     ALT_K     ESC
  5493.      CTRL_L    KEY_L    KEY_l     ALT_L     SPACE
  5494.      CTRL_M    KEY_M    KEY_m     ALT_M
  5495.      CTRL_N    KEY_N    KEY_n     ALT_N     CTRL_DELETE
  5496.      CTRL_O    KEY_O    KEY_o     ALT_O     CTRL_HOME
  5497.      CTRL_P    KEY_P    KEY_p     ALT_P     CTRL_CURSOR_UP
  5498.      CTRL_Q    KEY_Q    KEY_q     ALT_Q     CTRL_CURSOR_DOWN
  5499.      CTRL_R    KEY_R    KEY_r     ALT_R     CTRL_CURSOR_RIGHT
  5500.      CTRL_S    KEY_S    KEY_s     ALT_S     CTRL_CURSOR_LEFT
  5501.      CTRL_T    KEY_T    KEY_t     ALT_T     CTRL_PAGE_UP
  5502.      CTRL_U    KEY_U    KEY_u     ALT_U     CTRL_PAGE_DOWN
  5503.      CTRL_V    KEY_V    KEY_v     ALT_V     CTRL_END
  5504.      CTRL_W    KEY_W    KEY_w     ALT_W
  5505.      CTRL_X    KEY_X    KEY_x     ALT_X
  5506.      CTRL_Y    KEY_Y    KEY_y     ALT_Y
  5507.      CTRL_Z    KEY_Z    KEY_z     ALT_Z
  5508.  
  5509.      F1     SHIFT_F1    CTRL_F1   ALT_F1    KEY_1   ALT_DELETE
  5510.      F2     SHIFT_F2    CTRL_F2   ALT_F2    KEY_2   ALT_HOME
  5511.      F3     SHIFT_F3    CTRL_F3   ALT_F3    KEY_3   ALT_CURSOR_UP
  5512.      F4     SHIFT_F4    CTRL_F4   ALT_F4    KEY_4   ALT_CURSOR_DOWN
  5513.      F5     SHIFT_F5    CTRL_F5   ALT_F5    KEY_5   ALT_CURSOR_RIGHT
  5514.      F6     SHIFT_F6    CTRL_F6   ALT_F6    KEY_6   ALT_CURSOR_LEFT
  5515.      F7     SHIFT_F7    CTRL_F7   ALT_F7    KEY_7   ALT_PAGE_UP
  5516.      F8     SHIFT_F8    CTRL_F8   ALT_F8    KEY_8   ALT_PAGE_DOWN
  5517.      F9     SHIFT_F9    CTRL_F9   ALT_F9    KEY_9   ALT_END
  5518.      F10    SHIFT_F10   CTRL_F10  ALT_F10   KEY_0
  5519.      F11    SHIFT_F11   CTRL_F11  ALT_F11
  5520.      F12    SHIFT_F12   CTRL_F12  ALT_F12
  5521.  
  5522. The predefined values for the 'normal' keys like 'A', 'a' or '1' are
  5523. the same as the ASCII values. This means you are not forced
  5524. the type things like
  5525.  
  5526.             if( KEY_A==cskey() ) ....
  5527.  
  5528.         but can also use:
  5529.  
  5530.             if( 'A'==cskey() )  ......
  5531.  
  5532.  
  5533. 29.1 CSKEYS.exe
  5534.  
  5535. This simple command-line utility displays an integer value corresponding
  5536. to the pressed key. It is the same value the cskey() funtion returns and
  5537. can therefore be used to make additions to het list of symbolic constants.
  5538.  
  5539. also a simple utility to test the return value of the cskeys() function.
  5540.  
  5541.  
  5542. Syntax:
  5543.  
  5544.  
  5545. c:\tmp>cskey
  5546.  
  5547.  
  5548.  
  5549. To exit the program press CTRL-END.
  5550.  
  5551.                               30 DATE
  5552.  
  5553. The csDATE class is implemented to aid in dealing with dates.
  5554. It has build-in functions to convert from-and-to julian dates.
  5555. There are also functions to read and write dates as strings.
  5556. The julian-date routines require floating point, therefore the csDATE
  5557. class tries to avoid these routines whenever possible. As a consequence,
  5558. using the csDATE class doesn't necessarally means a floating point
  5559. library has to be linked in, but it depends on the functions used.
  5560.  
  5561.  
  5562. 30.1 Example
  5563.  
  5564. A quick example to show where we are talking about:
  5565.  
  5566.  
  5567. #include "iostream.h"
  5568. #include "date.h"
  5569.  
  5570. void main(void)
  5571. {
  5572.     csDATE d;
  5573.  
  5574.     d.format(Y4MD); // Choose the Year/Month/Day format.
  5575.     d="1967/04/23"; // Set 'd' to April 23th 1967
  5576.  
  5577.     d+=100;         // Add 100 days. (Requires floating point)
  5578.  
  5579.     DATE e;         // A new instance of the DATE class.
  5580.  
  5581.     e.now();        // Set 'e' to the system date.
  5582.  
  5583.     cout<<endl<<e-d;// Print the number of days in between.
  5584.                     // (Requires floating point)
  5585.  
  5586.     cout<<endl<<(char *)e;  // Print 'e'.
  5587. }
  5588.  
  5589.  
  5590.  
  5591.  
  5592. 30.2 Initialising
  5593.  
  5594. The next function can be used to initialise a DATE instance:
  5595.  
  5596. void month(int m);   Sets the month to 'm'. Januari is 1, Februari is 2, etc..
  5597. void year(int y);    Sets the year, using a 4 digit format.
  5598. void day(int d);     Sets the day.
  5599. void now(void);      Sets the date to the system clock.
  5600. void julian(long j); Sets the date to the julian date 'j'.
  5601.  
  5602.  
  5603. 30.3 Converting Strings
  5604.  
  5605. The assignment operator is overloaded to be able to assign a string to
  5606. the date instance. For this to work properly, the class has to know the
  5607. format in which the date is represented.
  5608.  
  5609. The format used has to be indicated by a call to the format() function.
  5610.  
  5611. Example:
  5612.  
  5613. void main(void)
  5614. {
  5615.     csDATE date;
  5616.     date.format(DMY4);
  5617.     date="27/02/1994";   // Februari, 27th 1994
  5618.  
  5619. }
  5620.  
  5621.  
  5622.  
  5623. In the header file 'CSDATE.H', constants are defined for the following
  5624. formats:
  5625.  
  5626.     MDY2    MY2D
  5627.     Y2MD    Y2DM
  5628.     DMY2    DY2M
  5629.     MDY4    MY4D
  5630.     Y4MD    Y4DM
  5631.     DMY4    DY4M
  5632.  
  5633.  
  5634. There is logic behind these formats!
  5635. 'M'         means Month
  5636. 'D'         means Day
  5637. 'Y4'        means Year with 4 positions
  5638. 'Y2'        means Year with 2 positions
  5639.  
  5640. So:     Y2MD means: Two positions for the year/month/day.
  5641.         MDY4 means: month/day/year four positions.
  5642.  
  5643. When 'Y2' is used, years >75 are interpreted as 20th century, years<=75
  5644. as the 21st century!
  5645.  
  5646. Example:
  5647.  
  5648. #include "csdate.h"
  5649.  
  5650. void main(void)
  5651. {
  5652.     csDATE date;
  5653.     date.format(Y2MD);
  5654.  
  5655.     date="80/04/15";        // April 15th, 1980
  5656.     date="20/04/15";        // April 15th, 2020
  5657.  
  5658. }
  5659.  
  5660.  
  5661. The default format is DMY4.
  5662.  
  5663.  
  5664. 30.4 Obtaining date info
  5665.  
  5666. The next functions can be used to 'read out' information about the DATE
  5667. instance.
  5668.  
  5669. int week_day(void);
  5670.                 Returns the day of the week. Monday=1, Tuesday=2,
  5671.                 etc..
  5672. int month(void);    Returns the month [1..12].
  5673. int month(csCHAR *);
  5674.                 Returns also the name of the calendar month,
  5675.                 [January,February...December]
  5676. int year(void); Returns the year in 2 or 4 digits, depending on the
  5677.                 format used. Remember, the default format is DMY4,
  5678.                 which implies 4 digits.
  5679. int year4(void);    Returns the year with 4 digits, independent of the
  5680.                     format chosen.
  5681. long julian(void);
  5682.                 Returns the julian date.
  5683. operator char*();
  5684.                 Casts the date to a string with respect to the format
  5685.                 used.
  5686. Example:
  5687.  
  5688.  
  5689. void main(void)
  5690. {
  5691.     csDATE date;
  5692.     date.now();
  5693.     date.format(DMY2)
  5694.     cout<<(char *)date<<endl;   // Displays 25/04/95
  5695.  
  5696. }
  5697.  
  5698.  
  5699.  
  5700. 30.5 Comparing dates
  5701.  
  5702. All the comparison operators like, <=, != etc. are overloaded to compare
  5703. instances of the csDATE class. The csDATE instances do NOT have to
  5704. use the same formats for the comparison operators to work properly.
  5705.  
  5706. Example:
  5707.  
  5708.  
  5709. #include "iostream.h"
  5710. #include "csdate.h"
  5711.  
  5712. void main(void)
  5713. {
  5714.     csDATE d1,d2;
  5715.  
  5716.     d1.now();
  5717.  
  5718.     d2.format(MDY4);
  5719.     d2="01/01/2000";
  5720.  
  5721.     if(d1>=d2)  cout<<" The turn of the century!"<<endl;
  5722.  
  5723. }
  5724.  
  5725.  
  5726.  
  5727. 30.6 Arithmetic
  5728.  
  5729. It is possible to apply simple arithmetic to the dates. That is, adding or
  5730. subtracting days and subtracting one date from the other.
  5731. This requires the use of julian dates and consequently the use
  5732. of floating point.
  5733.  
  5734. Example:
  5735.  
  5736.  
  5737.  
  5738. #include "iostream.h"
  5739. #include "csdate.h"
  5740.  
  5741. void main(void)
  5742. {
  5743.     csDATE d1,d2;
  5744.  
  5745.     d1.now();
  5746.     d1+=100;        // Add 100 days
  5747.     d1-=300;        // Subtract 300 days.
  5748.  
  5749.     d2.format(Y4MD);
  5750.     d2="1999/04/20";
  5751.  
  5752.     cout<<d2-d1<<endl; // Display the number of days in between.
  5753.  
  5754. }
  5755.  
  5756.  
  5757.  
  5758. 30.7 Miscellaneous
  5759.  
  5760. int format(void);   Returns the format used.
  5761. int leap_year(void);
  5762.                 Returns TRUE if the date is a leap-year, FALSE
  5763.                 otherwise.
  5764. int long_year(void);
  5765.                 Returns TRUE if 4 positions are used to represent the
  5766.                 year, FALSE otherwise.
  5767. S32 sem_jul(void);
  5768.                 'sem_jul' is short for 'semi julian'. It converts each date
  5769.                 into an unique 32 bits number, using the formula:
  5770.                 year*512+month*32+day. This number is convenient
  5771.                 for storing or comparing dates.
  5772. void sem_jul(S32 l);
  5773.                 The reverse of the previous function. It sets the DATE
  5774.                 instance according to the 'sem_jul' number 'l'.
  5775. int valid(void);    Returns TRUE if the date is a valid calendar date,
  5776.                     FALSE otherwise.
  5777.  
  5778.  
  5779.  
  5780.  
  5781.  
  5782.                               31 HEAP
  5783.  
  5784.  
  5785. 31.1 Purpose
  5786.  
  5787. Some type of applications allocate numberous small blocks from the
  5788. heap. This is inefficient in terms of ram uitlization, can lead to heap
  5789. fragmentation and is also slow.
  5790. To overcome these problems this library contains  a special HEAP class.
  5791.  
  5792. The idea is to do allocations in chunks of about 2Kb and take the small
  5793. amounts from that, when needed.
  5794.  
  5795. This approach has considerable advantages.
  5796.     - You can release all allocated memory with just one function call
  5797.         instead of freeing many small blocks separately.
  5798.     - It is a lot faster because normal heap operations are relatively slow.
  5799.     - Heap efficiency is also improved. It is much easier for the heap to
  5800.         deal with relatively few allocations of about 2Kb then it is to deal
  5801.         with numerous small allocations.
  5802.     - It can save valuable memory. There is considerable overhead
  5803.         involved in using the heap. Apart from what you need, several
  5804.         additional bytes are used to 'pointer' the allocated blocks
  5805.         together. In addition, allocations are done in multiples of 16
  5806.         bytes. This can lead to a situation where you need only 13 bytes
  5807.         while 32 bytes are used!
  5808.  
  5809.  
  5810. 31.2 When to use it?
  5811.  
  5812. The HEAP class is particularly useful when dealing with pointer
  5813. structures in ram. Pointer structures are small, all of the same size and
  5814. an application will probably use a lot of them.
  5815. The BUFFER class described earlier in this documentation also uses the
  5816. HEAP class. This means you can use it without enlarging your
  5817. application.
  5818. The HEAP class assumes allocations of a fixed size. This limits its
  5819. usefulness but improves efficiency. It is very well possible to use more
  5820. then one instance of the HEAP class in an application. It is feasible to
  5821. use a different HEAP for every size of allocation needed.
  5822. The class was designed with small allocations in mind, something below
  5823. 50 bytes. It is doubtful whether the HEAP class still makes sense for
  5824. allocations above 100 bytes.
  5825.  
  5826. Summarizing:
  5827. - Allocations have to be of a fixed size.
  5828. - Allocations have to be small, below 50 bytes.
  5829. - Many allocations of this type are going to take place.
  5830.  
  5831.  
  5832. 31.3 Using HEAP.
  5833.  
  5834. Using the HEAP class starts off with an initialization, stating the size of
  5835. the allocations. Afterwards the class has to be 'opened'. From there on
  5836. allocations can be made, and blocks can be free-ed again. When the
  5837. work is done, the close or the zap function can be called to free all
  5838. allocated memory.
  5839.  
  5840.  
  5841.  
  5842. // Example
  5843.  
  5844. #include "csheap.h"
  5845.  
  5846. void main(void)
  5847. {
  5848.     typedef struct
  5849.     {
  5850.         void *next;
  5851.         void *prev;
  5852.         int  number;
  5853.     } pStruct;          // A typical pointer structure.
  5854.  
  5855.     HEAP heap;          // HEAP class instance.
  5856.  
  5857.     heap.init(sizeof(pStruct)); // Initialize it for the size of the
  5858.                             // pointer structure.
  5859.  
  5860.     heap.open();            // Open the class so it can be used.
  5861.  
  5862.     pStruct *p,*q;
  5863.  
  5864.     p=(pStruct *)heap.malloc(); // Allocation.
  5865.     q=(pStruct *)heap.malloc(); // Allocation.
  5866.  
  5867.     p.next=q.prev=NULL; // Doing something.
  5868.  
  5869.     // Doing much more.
  5870.  
  5871.     heap.free(q);       // Freeing q.
  5872.  
  5873.     heap.close();       // Finally finished.
  5874.                         // Freeing all allocated memory.
  5875.  
  5876. }
  5877.  
  5878.  
  5879.  
  5880.  
  5881. 31.4 Functions in alphabetical order.
  5882.  
  5883. The function prototypes are in CSHEAP.H.
  5884.  
  5885. void close(void);
  5886.                 Closes the class. All allocated memory is freed. The
  5887.                 initialisation parameters are retained, which makes it
  5888.                 possible to reopen the class without calling init(). This
  5889.                 function is also called by the class destructor.
  5890. void empty(void );
  5891.                 Frees all allocated memory, but the class remains
  5892.                 open.
  5893. void init(U16 alloc_size,U16 page_size=2048);
  5894.                 Initializes the class. 'Alloc_size' is the size of the
  5895.                 allocations needed. 'Page_size' is the size of the
  5896.                 chunks which are going to be allocated from the heap.
  5897.                 This parameter has a default value of 2048 bytes.
  5898. int open(void); Opens the class. The 'init()' function has to be called
  5899.                 first. The function returns TRUE on success and
  5900.                 FALSE otherwise.
  5901. void free(void *p);
  5902.                 Frees the previously allocated block 'p' is pointing at.
  5903. void *malloc(void);
  5904.                 Allocates a block and returns a pointer to it. If no
  5905.                 memory is available, a NULL pointer is returned.
  5906. void zap(void); Frees all allocated memory and closes the class. The
  5907.                 initialization parameters set by the init() function are
  5908.                 reset. This means the class has to be initialized again
  5909.                 before it can be reopened.
  5910.  
  5911.  
  5912.  
  5913.  
  5914.                          32 Alloc-Logging
  5915.  
  5916. 32.1 Introduction
  5917.  
  5918. Dynamic memory allocations can create problems which are difficult
  5919. to trace. Therefore, this library contains a set of functions which can
  5920. be used to replace the normal malloc() and free() functions. The
  5921. replacements can be made to write a record to a log. This log can be
  5922. used later to check for memory leaks.
  5923.  
  5924. The replacements also test for things like freeing a NULL pointer or a
  5925. malloc which returns NULL.
  5926.  
  5927. Replacements are preprocessor commands which can be switched on
  5928. and off with the preprocessor variable CS_DEBUG.
  5929. If CS_DEBUG is not defined, the normal functions are called.
  5930.  
  5931.  
  5932. 32.2 Replacements
  5933.  
  5934. Replacements are available for the following functions:
  5935. Prototypes in csmalloc.h.
  5936.  
  5937.    Function:                Replacement:
  5938.     malloc                   csmalloc
  5939.     calloc                   cscalloc
  5940.     realloc                  csrealloc
  5941.     free                     csfree
  5942.     farmalloc                csfarmalloc
  5943.     farcalloc                csfarcalloc
  5944.     farrealloc               csfarrealloc
  5945.     farfree                  csfarfree
  5946.  
  5947. The use of the replacements is fully equivalent to the original.
  5948.  
  5949. The allocations in the CS-libraries are always done by calling the
  5950. replacements. The production version of the libraries was compiled
  5951. without CS_DEBUG being defined, so the normal functions are used and
  5952. are called without any additional overhead. When the debug version was
  5953. compiled, CS_DEBUG was defined and as a result all the allocations
  5954. done by the library functions can be logged!
  5955.  
  5956.  
  5957. 32.3 Logging
  5958.  
  5959. Logging of allocations can be switched on and off through the use of two
  5960. functions.
  5961.  
  5962. void alloc_logging(int TrueFalse);
  5963.                 After a call to alloc_logging(TRUE) all the allocations
  5964.                 are logged in the ASCII file 'malloc.log'. Calling
  5965.                 alloc_logging(FALSE) switches the logging off.
  5966. void alloc_logging(int TrueFalse,char *name);
  5967.                 This is basically the same as the previous function but
  5968.                 has the additional option of specifying the name of the
  5969.                 log file.
  5970.  
  5971. The next example displays a part of an allocation log.
  5972.  
  5973.  
  5974.  
  5975.  4E79:0004         file csedst30.cpp    line 8:  malloc()   8 bytes
  5976.  4E7A:0004         file csedst30.cpp    line 8:  malloc()   8 bytes
  5977.  4E78:0004         file csedst30.cpp    line 23: free()
  5978.  4E78:0004         file csedst30.cpp    line 8:  malloc()   9 bytes
  5979.  4E79:0004         file csedst30.cpp    line 23: free()
  5980.  4E7B:0004         file csedst30.cpp    line 8:  malloc()   22 bytes
  5981.  4E7B:0004         file csedst28.cpp    line 12: realloc  free()
  5982.  4E7B:0004         file csedst28.cpp    line 12: realloc  malloc()
  5983.  4E7A:0004         file csedstr.cpp     line 15: free()
  5984.  4E7B:0004         file csedstr.cpp     line 15: free()
  5985.  
  5986.  
  5987.  
  5988.  
  5989. As can be seen, the first column displays the pointer involved, the second
  5990. and third display the file and the line where the call was made. When an
  5991. allocation is concerned its size is also displayed. Reallocs appear as two
  5992. lines.
  5993.  
  5994.  
  5995. 32.4 Memory Leaks.
  5996.  
  5997. With a log like this it is easy to check for memory leaks. In fact, a
  5998. command-line utility is supplied to check for that. It is called CSMALLOC.
  5999. Only one parameter needs to be supplied: the name of the allocation log.
  6000.  
  6001. Example
  6002.  
  6003. c:\test>CSMALLOC malloc.log
  6004.  
  6005.  
  6006.  
  6007.  
  6008. If it encounters a malloc which is not matched by a free, it displays the
  6009. pointer involved.
  6010. Like:
  6011.  
  6012.  
  6013.  
  6014.  UNMATCHED address: 29CC:0004
  6015.  
  6016.  
  6017.  
  6018. If all malloc's are matched by a free it says something like this:
  6019.  
  6020.  
  6021.  
  6022.   NO ERRORS encountered!!
  6023.  
  6024.  
  6025.   Number of addresses: 23
  6026.   Lowest address:  29CC:0004
  6027.   Highest address: 2EAE:0004
  6028.  
  6029.  
  6030.  
  6031. If malloc logging is kept on for longer periods, the log file can become
  6032. extremely large. However, this poses no problem for CSMALLOC.
  6033.  
  6034. If you are planning to use this method to detect memory leaks,
  6035. it is essential to switch on the logging before the first allocation
  6036. is done. Don't forget class constructors do allocations as well!                              33 csSTR
  6037.  
  6038.  
  6039. The class for manipulating strings. Instead of providing the formal
  6040. syntax we will clarify things by supplying a large number of examples.
  6041.  
  6042. Class name: csSTR.  Prototypes are in CSSTR.H.
  6043.  
  6044.  
  6045.    #include "csstr.h"
  6046.  
  6047.    main(void)
  6048.    {
  6049.       csSTR str;
  6050.  
  6051.       str=" A test ";       // Assign a string
  6052.       str.upper();          // Convert to upper case
  6053.       str.lower();          // Convert to lower case
  6054.       str.trim();           // Remove all leading and trailing blanks
  6055.                             // str contains now: "a test";
  6056.       str+=" At the end ";  // APPEND at the end
  6057.                             // str contains now: "a test At the end"
  6058.       int i=-345;
  6059.       str=i;                // Convert the integer value to string
  6060.                             // str contains now: "-345";
  6061.       str="1001";
  6062.       i=str;                // Assign string to integer
  6063.       str="A line";
  6064.       str.strip("ijkl");    // Stripping the characters i,j,k,l from
  6065.                             // str.
  6066.                             // Str now contains: "A ne";
  6067.       str="A line";
  6068.       str.filter("ijkl");   // Allow only the characters i,j,k,l in
  6069.                             // str.
  6070.                             // Str now contains: "li";
  6071.       str="The quick brown fox";
  6072.       str[4]='Q';           // Str now contains: "The Quick brown fox"
  6073.  
  6074.       csSTR str2="by C++ !";
  6075.       str="Made possible ";
  6076.       str=str+str2;         // Str: "Made possible by C++ !";
  6077.  
  6078.       if( str<str2)   ..
  6079.       if( str>str2)   ..
  6080.       if( str<=str2)  ..
  6081.       if( str>=str2)  ..
  6082.       if( str==str2)  ..    // Comparisons are possible.
  6083.  
  6084.   }
  6085.  
  6086.  
  6087.  
  6088.