home *** CD-ROM | disk | FTP | other *** search
/ Programmer 7500 / MAX_PROGRAMMERS.iso / PASCAL / BTP20.ZIP / BTP.DOC next >
Encoding:
Text File  |  1993-06-10  |  27.8 KB  |  626 lines

  1. BTP.DOC
  2. (C) 1993 John C. Leon
  3. Documentation for BTP V2.0, 6/10/93
  4. BTP - The Btrieve Unit for Turbo Pascal 7.0
  5. (* ------------------------------------------------------------------------ *)
  6.  
  7. This product is in no way intended to teach you object-oriented programming or
  8. Btrieve programming.  It assumes you are comfortable with OOPs, using dynamic
  9. variables, and Btrieve.  Nonetheless, someone just learning OOP or Btrieve can
  10. benefit by studying the various source code modules in the product.
  11.  
  12. The best way to learn this product is to read this documentation, then
  13. examine the example programs thoroughly.  They are all fairly short, but
  14. will do far more to introduce you to using BTP than any amount of studying
  15. the unit's source code.  The example programs and unit source code are
  16. heavily commented.
  17.  
  18. INTRODUCTION TO BTP
  19. -------------------
  20.  
  21. Btrieve is a record manager sold by Novell.  Btrieve has been around a long
  22. time.  It takes many forms today...with versions for Dos, Windows, OS/2,
  23. and a "client/server" form when used with Novell Netware.  This unit has
  24. been tested only with Btrieve for Dos, Version 5.10a, with all patches
  25. available thru date of this file applied.
  26.  
  27. Btrieve files have no inherent structure to differentiate fields.  Your own
  28. code provides that functionality.  The BTP product is a programmer's toolkit
  29. at a ridiculous price that provides the Turbo/Borland Pascal programmer with
  30. an extra-ordinarily simple means of Btrieve file management, thanks to a
  31. great language (TP, of course) and object-oriented programming.
  32.  
  33. The BTP product is built on comprehensive data structures and provides a
  34. complete guide (through the example programs) to deal with Btrieve files as
  35. objects.  I suspect that the most intriguing capability for many will be the
  36. ability to use the extended calls with much greater ease; the nasty details
  37. of structuring and interpreting buffers is made much simpler with BTP (see
  38. CRUNCH2.PAS and EXAMPLE2.PAS).
  39.  
  40. The "universal" Btrieve call is made by calling a TP function supplied by
  41. Novell with the Btrieve product.  It takes six parameters.  Without a tool
  42. like BTP, Btrieve programming can be extremely verbose.  Keeping track of
  43. multiple Btrieve files and the variables for all six parameters for each
  44. file in a complex application using traditional programming techniques takes
  45. discipline and a masochistic attention to detail; I consider myself
  46. somewhat disciplined but I'm NOT masochistic.  Btrieve programming screams
  47. out for the simplification possible with object-oriented programming.
  48.  
  49. BTP includes a number of sound data structures/objects, including:
  50. TRecMgr, BFile, BFixed, BFileExt, and BSized.  TRecMgr and BFile are base
  51. objects; they are direct descendants of TP7's TObject.  BFixed, BFileExt and
  52. BSized are each direct descendants of BFile.
  53.  
  54. TRECMGR  is of limited usefulness (see the unit source code and VERSION.PAS),
  55. -------  but it does provide the ability to make non-file oriented calls
  56.          (stop, reset, version, et al).
  57.  
  58. BFILE    is what you'll use for virtually all standard, fixed length Btrieve
  59. -----    files when not using extended calls; it will probably be your
  60.          workhorse.  Requires only that your descendant add a "FIELDS" member
  61.          to provide field definitions and data/key buffers.  This is easier
  62.          than it sounds ... look at EXAMPLE1.PAS and EXAMPLE2.PAS.  Much
  63.          useful work can be done by using an object of type BFile directly,
  64.          without deriving a descendant ... look at STATS.PAS.
  65.  
  66. BFIXED   has structures to support ANY standard, fixed length Btrieve file.
  67. ------   BFixed is used in the CRUNCHx.PAS programs provided, which can 'clone
  68.          and squish' (remove dead space) from any standard, fixed length
  69.          Btrieve file.  BFixed is useful for working on standard fixed length
  70.          files of an unknown nature when you need to perform *record* oriented
  71.          functions with no care about field definitions.
  72.  
  73. BFILEEXT is used for any Btrieve file for which you'll be using extended calls
  74. -------- (note there is no specific support for the extended insert call, but
  75.          CRUNCH2.PAS is an example of how to make such calls).  BFileExt is
  76.          used in CRUNCH2.PAS and EXAMPLE2.PAS.
  77.  
  78. BSIZED   Can be useful at times for record-oriented operations where you need
  79. ------   to specify a data buffer length of your choosing, without having to
  80.          add data members to BFile.  Can be useful for variable length files.
  81.          See CRUNCH1.PAS and CRUNCH2.PAS.
  82.  
  83. Quite simply, your TYPE declarations define your Btrieve files as descendants
  84. of one of the four file-oriented objects provided in BTP and described above.
  85. Those declarations can include definitions of your file's field structures,
  86. and can provide the required data and key buffers.  These programmer-defined
  87. additions to the BTP objects are encapsulated in the descendant object, along
  88. with the data fields inherited, which include a description of the file's
  89. structure and the file's position block.  Immediately upon instantiation of a
  90. BTP descendant object, you have access to any file's structure and stats.  You
  91. also have an 'isolated' position block and the required buffers for Btrieve
  92. calls.
  93.  
  94. In the case of a BFile descendant, you override (replace) a single object
  95. method, and can make your Btrieve calls with just two parameters: the Btrieve
  96. op code and key number.  Use of the 4 get/step extended calls is only
  97. marginally more difficult.  In order to use extended calls, your object must
  98. be a descendant of BFileExt, and must override two methods: one for standard
  99. calls, and one for the extended calls.  BFileExt includes pointers to two
  100. collections, which are automatically initialized when the object's
  101. constructor is called.  The first collection is for the filter logic terms,
  102. the second is for the field extractor specs.  Your program simply inserts
  103. items into these collections.  The rest, including determining buffer lengths
  104. and structuring the outgoing buffer, is handled internally by the object's
  105. methods.
  106.  
  107.  
  108. USING THE BASE OBJECT - BFILE
  109. -----------------------------
  110.  
  111. This unit gives you a technique, a shorthand way to get into Btrieve files
  112. and manipulate them.  For example, to open a file and encapsulate its stats
  113. into your Btrieve file object, you need only do:
  114.  
  115.      ObjectName^.Init(BDosFileName, Normal, '')
  116.  
  117.      (BDosFileName is a valid Btrieve file name.  'Normal' is the open
  118.       mode.  The null string you see as the third parameter means the file
  119.       takes no owner name.  See BTP.PAS for the various constants defined.
  120.       Assuming no errors, the file is open.)
  121.  
  122. Similary, to close a file, you simply do:
  123.  
  124.      BStatus := ObJectName^.Close;  OR simply
  125.      ObjectName^.Close;
  126.  
  127.  
  128. The BFile object defined herein is the heart of this unit.  BFile is NOT an
  129. abstract object!!  It can be used as is, for example, if all you want to do
  130. is to get stats (see STATS.PAS).  However, if you wish to do any normal
  131. field-oriented functions, you will do two things in a descendant:
  132.  
  133.    1.  Add one data element, a variant record.  This record will contain your
  134.        field definitions and provide your buffers.
  135.    2.  You are *required* to override the abstract BT function.
  136.  
  137. Here's an example.  This example will compile and run.  It introduces the
  138. CreateFile function "before it's time" just to get you going.
  139.  
  140. ..............................................................................
  141. PROGRAM BTPIntro;
  142.  
  143. {$X+,N+,E+}
  144.  
  145. USES BTP;
  146.  
  147. TYPE
  148.  
  149.   MyFields  = record
  150.               case integer of
  151.               1: (Field1 : string[9];            {obviously use size and type}
  152.                   Field2 : double;               {of your fields here!       }
  153.                   {etc}
  154.                   KeyBuf : array[1..10] of char); {size to largest key length}
  155.               2: (DBuffer: array[1..18] of char); {size to record length     }
  156.               3: (Position: array[1..2] of word); {high word returned first! }
  157.                   end;                           {useful after a GET POSITION}
  158.  
  159.   PMyObject = ^MyObject;
  160.   MyObject  = object(BFile)
  161.               Fields : MyFields;
  162.               function BT(OpCode, Key: integer): integer; virtual;
  163.               end;
  164.  
  165. VAR
  166.  
  167.   MyFile    : PMyObject;
  168.   MyFileSpec: PFileSpecObj;
  169.  
  170. {This is the required override of the BT function for all standard, fixed
  171.  length files.  As the base object has no field structures, it cannot include
  172.  this function...you must override it by REPLACING it as shown here.}
  173.  
  174. function MyObject.BT(OpCode, Key:integer): integer;
  175. begin                             {DBufferLen is reset here as it may need to}
  176.    DBufferLen := Specs.RecLen;    {be changed on return from some ops.       }
  177.    BT := Btrv(OpCode, PosBlk, Fields, DBufferLen, Fields.KeyBuf, Key);
  178. end;
  179.  
  180.  
  181. BEGIN
  182.  
  183. MyFileSpec := new(PFileSpecObj, Init(18, 512, 2, 0, 0,
  184.                   NewKeySpec(1, 10, Duplicates or Modifiable or ExtType,
  185.                              BLString,
  186.                   NewKeySpec(11, 8, Duplicates or Modifiable or ExtType,
  187.                              BFloat,
  188.                   nil))));
  189.  
  190. BStatus := CreateFile('TestFile', MyFileSpec^.Specs, '', '', 0);
  191. dispose(MyFileSpec, Done);
  192.  
  193. MyFile := new(PMyObject, Init('TestFile', Normal, ''));
  194. writeln('WOW ... TestFile has ', MyFile^.NumSegs, ' segments!');
  195.  
  196. with MyFile^ do
  197. begin
  198.    Fields.Field1 := 'Lisa';
  199.    Fields.Field2 := 10000;
  200.    BT(BInsert, 0);        {Key number of 0 provided only for positioning info}
  201.    Fields.Field1 := 'John';
  202.    Fields.Field2 := 20000;
  203.    BT(BInsert, 0);
  204.    Fields.Field1 := '';   {Zap existing member data to prove the point.}
  205.    Fields.Field2 := 0;
  206.    BT(BGetFirst, 0);
  207.    writeln('Field1 of after Get First w/key 0: ', Fields.Field1);
  208.    writeln('Field2 of after Get First w/key 0: ', Fields.Field2:5:2);
  209.    MyFile^.Close;
  210. end;
  211.  
  212. dispose(MyFile, Done);
  213.  
  214. END.
  215.  
  216. ..............................................................................
  217.  
  218. The record variable itself should be used as the Btrieve data buffer
  219. parameter.  In the override of the BT function, the data buffer length is
  220. reset to the file's record length before making each call.  The KeyBuf field
  221. of the MyFields record should be used in all Btrieve calls as the key buffer.
  222.  
  223. As you can see, your BFile descendant will incorporate the universal Btrieve
  224. function call in a compact, elegant format.  Thanks to OOP and encapsulation,
  225. you are guaranteed that each descendant's own key and data buffers are used
  226. since each instantiation references its own data members.
  227.  
  228. As an aside, the .BT function cannot be fully incorporated into the base BFile
  229. object since the base object has no data fields corresponding to your file's
  230. fields, and thus cannot contain a properly sized key buffer or data buffer.
  231. The override is necessary because neither the BFile object nor Btrieve itself
  232. know anything about fields or the appropriate size for your buffers.
  233.  
  234. In fact, to assure you don't call the .BT function of BFile directly, BFile.BT
  235. includes a call to TP7's Abstract method, which will crash your program with a
  236. runtime error 211 unless you replace it, presumably with an override very
  237. similar to that used above in BTPIntro.
  238.  
  239. Examining the BTPIntro program, let's look at the object's instantiation.
  240.  
  241.      MyFile := new(PMyObject, Init('TestFile', Normal, ''));
  242.  
  243. The BFile constructor/initialization method will do a Btrieve open operation,
  244. using the open mode you provide as the second parameter to the Init call.
  245. After the open operation, a stat operation is performed.  The Btrieve
  246. filespec and key specs, retrieved by the stat call, are incorporated into
  247. BFile's data fields.  Those stats can then be read out at will simply by
  248. referencing the object's data fields in the following manner:
  249.  
  250.      MyFile^.Specs.PageSize, or MyFile^.NumRecs, etc.
  251.  
  252. The stat fields defined in the object include the number of keys, the total
  253. number of key segments, the page size, the number of records in the file
  254. when the INIT was performed, the file flags...in short, the complete Btrieve
  255. filespec.  All other stats can be derived from the object's data fields if
  256. needed.  If you ever need to refresh the stat data to refresh the record
  257. count, for example, you could simply:
  258.  
  259.      BStatus := MyFile^.Close;
  260.      dispose(MyFile, Done);
  261.      MyFile := new(PMyObject, Init('TestFile', Normal, ''));
  262.      HowMany := MyFile^.NumRecs;
  263.  
  264. Of course, you could always do a Stat call directly and deal with the
  265. results, but the BTP way is so EASY!!  MyFile^.NumRecs, a longint, is
  266. available immediately after the Init call.
  267.  
  268. Btrieve operations with BTP are performed by calling the BT function with JUST
  269. TWO PARAMETERS.  Here's a simple step next call:
  270.  
  271.   BStatus := MyFile^.BT(BStepNext, 2);
  272.  
  273.   (BStatus is a public integer var from this unit.  BStepNext is a public
  274.    constant.  A number of public constants are defined in this unit that can
  275.    help make your code more readable.)
  276.  
  277. There is some nominal overhead in the BFile object.  It allocates space for
  278. the maximum of 24 keys/segments, and for an alternate collating sequence,
  279. whether one is used in the file or not.  This simply means a maximum of 633
  280. bytes per open file could be wasted.  This maximum would apply to a standard
  281. Btrieve file that had just one unsegmented key.  The figure of 633 is derived
  282. as follows:
  283.  
  284.                  665 maximum bytes if the Btrieve max of 24 keys/
  285.                      segments and an alternate collating sequence is used
  286.                -  16 bytes to hold the Btrieve file specs (stats)
  287.                -  16 bytes for the minimum required 1 Btrieve key spec for
  288.                      a standard (not data-only and not key-only) file
  289.                  ---
  290.                  633 bytes maximum possible waste
  291.  
  292. In addition, my convention of supplying the BFile descendant with a built-in
  293. key-buffer, arbitrarily sized to the length of the largest size key, could be
  294. overhead. I don't mind that a bit, and I don't think you should.  In my
  295. opinion, the code/data overhead introduced of necessity with this unit
  296. is more than offset by the benefits.
  297.  
  298. Your app's code is responsible for stuffing key values into the key buffer,
  299. getting or setting the data buffer, et al, as usual.  However, you gain the
  300. ease of accessing all Btrieve ops in a distinct shorthand, accessing those
  301. buffers and fields by name, and can rest assured that all parameters are
  302. passed and filled.  See EXAMPLE1.PAS for a full working model of this
  303. technique.
  304.  
  305. You will note that the examples sometimes break one of OOP's rules by
  306. accessing data fields directly.  In my own apps I will typically have at
  307. least a couple of additional methods in my BFile descendants for getting and
  308. setting the key buffers and data buffers.  How you handle your own code
  309. is up to you.
  310.  
  311.  
  312. USING THE BFILEEXT OBJECT
  313. -------------------------
  314.  
  315. There were several assumptions coded into the BTP unit to make a working
  316. structure for the get/step extended calls (see the declaration of data types
  317. for BFileExt in the unit's source code):
  318.  
  319.   1. That the required data buffer will never be more than 32767 bytes.
  320.   2. That values used for a filter's logic terms will never be longer
  321.      than 255 bytes.
  322.  
  323. Beyond these assumptions, which you can change if necessary by changing the
  324. unit's source or by defining your own descendants, BTP enables you to make any
  325. of the four get/step extended calls with ease.  Examples of doing so are in
  326. example programs CRUNCH2.PAS and EXAMPLE2.PAS.
  327.  
  328. Admittedly, constructing outgoing buffers for Btrieve's extended calls can
  329. be frustrating.  Btrieve is hostile in this regard.  BTP reduces this
  330. drudgery to a couple of additional setup statements!
  331.  
  332. Recall that the outgoing buffer for these extended calls requires several
  333. data structures occupying contiguous bytes in the buffer:  a header, a
  334. filter, optional filter logic terms, an extractor, and at least one field
  335. extractor spec.  After initializing the data buffer, you must calculate
  336. the buffer length for the Btrieve call to be the larger of the outgoing or
  337. incoming buffers!  SHEESH!  The BTP way of dealing with this is as follows:
  338.  
  339.    1:  HEADER is handled internally.  Don't mess with it.  Yes, even setting
  340.        the buffer length in the header is handled internally.
  341.    2:  FILTER's fields MUST be assigned by your program.
  342.    3:  FILTERSPEC is a TP collection that may or may not hold any objects,
  343.        depending on your program's needs.
  344.    4:  EXTRACTOR's fields MUST be assigned by your program.
  345.    5:  EXTRACTORSPEC is a TP collection that must hold at least one object.
  346.    6:  EXTDBUFFER, the data buffer for these 4 extended calls, is handled
  347.        internally.  Don't mess with it, except to use it as shown below and in
  348.        EXAMPLE2.PAS when you override BFileExt.BTExt.
  349.    7.  Buffer structuring is totally transparent to your program.  Simply
  350.        override the BFileExt.BTExt function as shown in the examples, and
  351.        you're there!  Believe me, this took some work!  The standard TP7
  352.        'ForEach' iterator is used to take every item in the two collections
  353.        and account for them in structuring the outgoing data buffer.
  354.  
  355. The BFileExt.BTExt method must be overridden, with the override calling the
  356. ancestor; i.e. your override must be of a standard form, and must *first* call
  357. BFileExt.BTExt.  This is because BFileExt.BTExt is what sets the buffer length
  358. and constructs the buffer.  This is in contrast to BFile.BT or BFileExt.BT,
  359. which must be overridden by REPLACING them.
  360.  
  361. Since Btrieve's get/step extended calls permit use of filters based on field
  362. values or on a user (program) supplied value, there are two constructors for
  363. the logic term object: INITF (initialize to compare with field) and,
  364.                        INITV (initialize to compare with value).
  365. Refer to the BTP source code for a list of the parameters required by these
  366. two constructors.
  367.  
  368. I strongly urge you to review EXAMPLE2.PAS for a full working model of using
  369. extended calls with BTP.  It's a much easier task to review the example than
  370. to peruse the source code and this documentation.  The following is a skeletal
  371. example, which will compile and run as is ... it assumes the file from
  372. program BTPIntro above exists in the current directory.  This example is
  373. silly in the sense that the file you're working on has only two records and
  374. doesn't warrant use of extended calls, but we're just illustrating technique.
  375.  
  376. .............................................................................
  377. PROGRAM BTPExtIntro;
  378.  
  379. {$X+}
  380.  
  381. USES BTP;
  382.  
  383. TYPE
  384.   MyFields  = record
  385.               case integer of
  386.               1: (Field1 : string[9];            {obviously use size and type}
  387.                   Field2 : double;               {of your fields here!       }
  388.                   {etc}
  389.                   KeyBuf : array[1..10] of char); {size to largest key length}
  390.               2: (DBuffer: array[1..18] of char); {size to record length     }
  391.               3: (Position: array[1..2] of word); {high word returned first! }
  392.                   end;                           {useful after a GET POSITION}
  393.  
  394.   PMyObject = ^MyObject;
  395.   MyObject  = object(BFileExt)
  396.               Fields : MyFields;
  397.               function BT(OpCode, Key: integer): integer; virtual;
  398.               function BTExt(OpCode, Key: integer): integer; virtual;
  399.               end;
  400.  
  401. VAR
  402.  
  403.   MyFile    : PMyObject;
  404.   Counter   : integer;
  405.   X         : string;
  406.   Value     : TByteArray;  {TByteArray is a data type in BTP...an array of
  407.                             255 bytes.}
  408.  
  409. function MyObject.BT(OpCode, Key: integer): integer;
  410. begin
  411.    DBufferLen := Specs.RecLen;
  412.    BT := Btrv(OpCode, PosBlk, Fields, DBufferLen, Fields.KeyBuf, Key);
  413. end;
  414.  
  415. function MyObject.BTExt(OpCode, Key: integer): integer;
  416. begin
  417.    BStatus := BFileExt.BTExt(OpCode, Key);   {MUST call ancestor method!!!}
  418.    BTExt   := Btrv(OpCode, PosBlk, ExtDBuffer^.Entire, DBufferLen,
  419.                    Fields.KeyBuf, Key);
  420. end;
  421.  
  422. BEGIN
  423.  
  424. MyFile := new(PMyObject, Init('TestFile', ReadOnly, ''));
  425.  
  426. {Set up some data members: maximum number of records to skip, number of logic
  427.  terms, number of records to return on each call, number of fields to return.
  428.  This one call sets up the filter and extractor.}
  429.  
  430. MyFile^.SetTerms(50, 1, 5, 1);
  431.  
  432. {Now specify filter logic terms.  We'll setup filter to use 'Lisa' as a value
  433.  for filtering.  Tell Btrieve to look for it in positions 1 thru 10.  Add 1
  434.  pointer to a FilterSpec object to the FilterSpec collection, using the value
  435.  placed in the required array of byte.}
  436.  
  437. X := 'Lisa';
  438. move(X, Value, sizeof(X)+1);
  439. with MyFile^.FilterSpec^ do
  440.    insert(new(PFilterSpec, InitV(BLString, 1, 10, Equal, LastTerm, Value)));
  441.  
  442. {Let's set up to extract an entire record, not just particular fields.  This
  443.  implies placing just one pointer to an extractor spec object in the
  444.  ExtractorSpec collection.  The first parameter to that object's constructor
  445.  is the length of the item to extract (here the entire record length).  The
  446.  second parameter is the zero-based offset from which to begin extraction.
  447.  This is 0, of course, if extracting the entire record.}
  448.  
  449. with MyFile^.ExtractorSpec^ do
  450.    insert(new(PExtSpec, Init(MyFile^.Specs.RecLen, 0)));
  451.  
  452. {Oh, yea...need to establish a position before using these calls, so let's do
  453.  a Get First before the extended call!}
  454.  
  455. BStatus := MyFile^.BT(BGetFirst, Zero);
  456.  
  457. {Now let's get on with it and make the extended call...}
  458.  
  459. BStatus := MyFile^.BTExt(BGetNextExt, 0);
  460.  
  461. {Take advantage of the data types provided in BTP to see how many records were
  462.  returned in this call.}
  463.  
  464. writeln(#13,#10,'Number of records returned with Field1 of ''Lisa'' is ',
  465.         MyFile^.ExtDBuffer^.NumRecs);
  466.  
  467. {Don't forget to close the file and dispose of the dynamic object.  The
  468.  object's Done destructor will dispose of the collections for you.}
  469.  
  470. BStatus := MyFile^.Close;
  471. dispose(MyFile, Done);
  472.  
  473. END.
  474.  
  475. .............................................................................
  476.  
  477.  
  478. USING THE CLONEFILE FUNCTION
  479. ----------------------------
  480.  
  481. While the standard BTP style of making Btrieve calls and defining your data
  482. types has hopefully been made clear, a few words about the invaluable
  483. CloneFile function may be helpful.
  484.  
  485. With this single function call you can clone any standard Btrieve file.  It
  486. is not intended for data only or key only files, and has not been tested with
  487. them, SO BE WARNED.
  488.  
  489. The syntax for this call is:
  490.  
  491.    CloneFile(sourcefile, newfile, 'supplemental index handling', ownername),
  492.    where 'supplemental index handling' is one of: Drop, Retain, None
  493.  
  494.    For example, an existing standard Btrieve file having no owner name, with
  495.    1 permanent index and two supplemental indexes (regardless of # segments
  496.    in each) is named ORIGINAL.  You wish to create a clone named DUPE, with
  497.    only the permanent indexes retained.  The call would be:
  498.  
  499.    BStatus := CloneFile('Original', 'Dupe', Drop, '');
  500.  
  501. CloneFile readily handles supplemental indexes.  Its syntax permits you to
  502. specify whether or not you wish to retain such supplemental indexes in your
  503. cloned file, to drop them and keep only the permanent indexes, or to specify
  504. 'None' if there are none to begin with.
  505.  
  506. If you specify 'Drop' or 'Retain', and there are in fact no supplemental
  507. indexes, no harm is done...the file is properly cloned anyway.
  508.  
  509. HOWEVER, if you specify 'None' and there are indeed supplemental indexes,
  510. the supplemental indexes will be retained as permanent indexes.
  511.  
  512.  
  513. USING THE CREATEFILE FUNCTION
  514. -----------------------------
  515. There is no easier way to create a file than with the technique in BTP.  All
  516. it takes are two program statements.  Given a variable of type PFileSpecObj,
  517. you simply instantiate the object, and pass its spec to the CreateFile
  518. function.  The CreateFile function can perform multiple Btrieve calls; i.e.
  519. if you wish to create a file to have an owner name, you simply pass the
  520. owner name as a parameter to CreateFile.  After the file is created, the owner
  521. name is added in a second Btrieve op automatically.  Examine the following
  522. brief example, which will compile and run:
  523.  
  524. PROGRAM BTPCreate;
  525.  
  526. USES BTP;
  527.  
  528. VAR
  529.    MyFileSpec : PFileSpecObj;
  530.  
  531. BEGIN
  532. MyFileSpec := new(PFileSpecObj, Init(100, 512, 1, 0, 0,
  533.                   NewKeySpec(1, 10, Duplicates or Modifiable or ExtType,
  534.                              BLString, nil)));
  535.  
  536. CreateFile('Test', MyFileSpec^.Specs, '', '', 0);
  537.  
  538. dispose(MyFileSpec, Done);
  539. END.
  540.  
  541. The FileSpecObj constructor guarantees proper assembly of the buffers required
  542. for the Btrieve Create operation.  The constructor's parameters are:
  543.  
  544.    1. Record length
  545.    2. Page size
  546.    3. # keys
  547.    4. File flags
  548.    5. # pages to pre-allocate
  549.    6. Pointer to head of a linked list of pointers to key specifications
  550.  
  551. Of these 6, all but #6 should be obvious.  The easiest way to build the
  552. linked list of key specs is to let BTP handle it in the fashion shown.
  553. The NewKeySpec function creates a pointer to a key spec.  Its parameters are:
  554.  
  555.    1. Position
  556.    2. Length
  557.    3. Key flags  {ALWAYS include ExtType in the list of OR'd flags!}
  558.    4. Key type
  559.    5. Pointer to next key spec, if any, else nil.
  560.  
  561. In the BTPCreate program above, parameter #5 is simply nil.  You can nest
  562. as many calls to NewKeySpec as required to complete the filespec.  The file
  563. spec object's destructor will destroy the list of key specs on the heap.
  564. Here's an example of nesting:
  565.  
  566.    MyFileSpec := new(PFileSpecObj, Init(100, 2048, 2, 0, 0,
  567.                      NewKeySpec(1, 10, Duplicates or Modifiable or
  568.                                 Segmented or ExtType, BLString,
  569.                      NewKeySpec(11, 20, Duplicates or Modifiable or
  570.                                 ExtType, BLString,
  571.                      NewKeySpec(50, 10, Modifiable or ExtType, BFloat,
  572.                                 nil)))));
  573.  
  574. Now that you understand building the file spec, let's examine the CreateFile
  575. function.  It takes 5 parameters:
  576.  
  577.     1. File name
  578.     2. Pointer to a file spec of type PFileSpec
  579.     3. Name of alternate collating sequence file to be incorporated into the
  580.        file, if any, else null string.  The alternate collating sequence file
  581.        MUST reside in the current directory.  Internally, CreateFile takes
  582.        advantage of another BTP object, TAltColSeq, when incorporating an
  583.        alternate collating sequence into the file.
  584.     4. Owner name, if any, else null string
  585.     5. Owner name security level, if any, else 0
  586.  
  587. WARNING: If a file by the name you specify in parameter #1 already exists on
  588.          disk, it will be overwritten by CreateFile!
  589.  
  590.  
  591. ABOUT THE EXAMPLE PROGRAMS
  592. --------------------------
  593.  
  594. The README.1ST file contains a list and description of the example programs.
  595. They should be extremely helpful in getting you up to speed with the BTP
  596. product.  Several of them are utility programs you can use "out of the box"!
  597.  
  598.  
  599. PARTING SHOTS
  600. -------------
  601.  
  602. ENJOY BTP PROGRAMMING!  BTP is not free...it is shareware.  Yours with no
  603. obligation for a 30 day trial period, you are expected to remit the $25
  604. registration fee if you use BTP.  Please refer to the README.1ST file for
  605. license terms and remittance instructions.
  606.  
  607. The most current version of BTP can usually be found in 3 places on Compu-
  608. serve if not available to you through your favorite BBS or shareware catalog:
  609.  
  610.   Borland's Pascal Forum (go BPASCAL), in download library 7 (DOS PROGRAMMING)
  611.   IBM Programmer's Forum (go IBMPRO), in download library 5  (OTHER LANGUAGES)
  612.   Novell Netwire         (go NOVLIB), in download library 15 (SHAREWARE/DEMO),
  613.  
  614. Even if you choose not to register your copy of BTP, I would like to hear
  615. from you about your experiences with and reaction to using this unit.  In
  616. addition, of course, constructive criticism and suggestions are always
  617. welcome.
  618.  
  619.    John C. Leon
  620.    3807 Wood Gardens Court
  621.    Kingwood, TX  77339
  622.  
  623.    713-359-3641 (residence)
  624.    CIS #72426,2077
  625.  
  626.