home *** CD-ROM | disk | FTP | other *** search
CZ Help | 1992-08-15 | 213.3 KB | 3,875 lines |
- CZ_HELP!
- INDEX
- TUTORIAL_INDEX
- LICENSE_AGREEMEN
- LICENSE_A
- PRODUCT_SUPPORT
- STARTING_CZ
- USING_CZ
- USING_CZ_A
- USING_CZ_B
- ABOUT_CZ
- IS_BULLET
- IS_A_DATABASE
- IS_DBF
- IS_A_BTREE
- IS_A_NETWORK
- IS_FILE_LOCKING
- IS_NLS
- DESIGN_A_DB
- CREATE_A_DB
- ADD_TO_THE_DB
- QUERY_THE_DB
- UPDATE_THE_DB
- DELETE_A_RECORD
- BC_COMPILE_WITH
- LIB_WITH
- MAKE_A_QLB
- LINK_WITH
- CALL_BULLET
- SPECS_OVERALL
- SPECS_DBF
- SPECS_DBF_A
- SPECS_DBF_B
- SPECS_DBF_C
- SPECS_INDEX
- SPECS_INDEX_A
- SPECS_INDEX_B
- SPECS_INDEX_C
- SPECS_MEMORY
- SPECS_MEMORY_A
- SPECS_OS_CALLS
- SPECS_LANGUAGES
- SPECS_OSES
- SPECS_NETWORKS
- SPECS_PERFORMANC
- SPECS_PERF_A
- SPECS_PERF_B
- SPECS_PERF_C
- SPECS_PERF_D
- INITXB
- EXITXB
- ATEXITXB
- MEMORYXB
- BREAKXB
- BACKUPFILEXB
- STATHANDLEXB
- GETEXTERRORXB
- DVMONCXB
- CREATEDXB
- OPENDXB
- CLOSEDXB
- STATDXB
- READDHXB
- FLUSHDHXB
- COPYDHXB
- ZAPDHXB
- CREATEKXB
- CREATEKXB_A
- CREATEKXB_B
- CREATEKXB_C
- CREATEKXB_D
- CREATEKXB_E
- CREATEKXB_F
- OPENKXB
- CLOSEKXB
- STATKXB
- READKHXB
- FLUSHKHXB
- COPYKHXB
- ZAPKHXB
- GETDESCRIPTORXB
- GETRECORDXB
- ADDRECORDXB
- UPDATERECORDXB
- DELETERECORDXB
- UNDELETERECORDXB
- PACKRECORDSXB
- FIRSTKEYXB
- EQUALKEYXB
- NEXTKEYXB
- PREVKEYXB
- LASTKEYXB
- STOREKEYXB
- DELETEKEYXB
- BUILDKEYXB
- CURRENTKEYXB
- GETFIRSTXB
- GETEQUALXB
- GETNEXTXB
- GETPREVXB
- GETLASTXB
- INSERTXB
- UPDATEXB
- REINDEXXB
- LOCKXB
- UNLOCKXB
- LOCKKEYXB
- UNLOCKKEYXB
- LOCKDATAXB
- UNLOCKDATAXB
- DRIVEREMOTEXB
- FILEREMOTEXB
- SETRETRIESXB
- DELETEFILEDOS
- RENAMEFILEDOS
- CREATEFILEDOS
- ACCESSFILEDOS
- OPENFILEDOS
- SEEKFILEDOS
- READFILEDOS
- EXPANDFILEDOS
- WRITEFILEDOS
- CLOSEFILEDOS
- MAKEDIRDOS
- ACCESSPACK
- BREAKPACK
- COPYPACK
- CREATEDATAPACK
- CREATEKEYPACK
- DESCRIPTORPACK
- DOSFILEPACK
- DVMONPACK
- EXITPACK
- FIELDDESCTYPE
- HANDLEPACK
- INITPACK
- MEMORYPACK
- OPENPACK
- REMOTEPACK
- SETRETRIESPACK
- STATDATAPACK
- STATKEYPACK
- STATHANDLEPACK
- XERRORPACK
- ERRORS_BULLET
- ERRORS_BULLET_B
- ERRORS_BULLET_C
- ERRORS_BULLET_D
- ERRORS_BASIC
- ERRORS_BASIC_B
- ERRORS_DOS
- ERRORS_DOS_B
- ERRORS_DOS_C
- INITXBSRC
- EXITXBSRC
- ATEXITXBSRC
- MEMORYXBSRC
- BREAKXBSRC
- BACKUPFILEXBSRC
- STATHANDLEXBSRC
- GETEXTERRORXBSRC
- DVMONCXBSRC
- CREATEDXBSRC
- CREATEDXBSRC_A
- OPENDXBSRC
- CLOSEDXBSRC
- STATDXBSRC
- READDHXBSRC
- FLUSHDHXBSRC
- COPYDHXBSRC
- ZAPDHXBSRC
- CREATEKXBSRC
- CREATEKXBSRC_A
- OPENKXBSRC
- CLOSEKXBSRC
- STATKXBSRC
- READKHXBSRC
- FLUSHKHXBSRC
- COPYKHXBSRC
- ZAPKHXBSRC
- GETDESCRIPTORXBSt
- GETRECORDXBSRC
- ADDRECORDXBSRC
- UPDATERECORDXBSR
- DELETERECORDXBSR
- UNDELETERECORDSRT
- PACKRECORDSXBSRC%
- FIRSTKEYXBSRC
- EQUALKEYXBSRC
- NEXTKEYXBSRC
- PREVKEYXBSRC
- LASTKEYXBSRC
- STOREKEYXBSRC
- DELETEKEYXBSRC
- BUILDKEYXBSRC
- CURRENTKEYXBSRC
- GETFIRSTXBSRC
- GETEQUALXBSRC
- GETNEXTXBSRC
- GETPREVXBSRC
- GETLASTXBSRC
- INSERTXBSRC
- UPDATEXBSRC
- REINDEXXBSRC
- LOCKXBSRC
- UNLOCKXBSRC
- LOCKKEYXBSRC
- UNLOCKKEYXBSRC
- LOCKDATAXBSRC
- UNLOCKDATAXBSRC
- DRIVEREMOTEXBSRC
- FILEREMOTEXBSRC
- SETRETRIESXBSRC
- DELETEFILEDOSSRC
- RENAMEFILEDOSSRC~.
- CREATEFILEDOSSRC
- ACCESSFILEDOSSRCV2
- OPENFILEDOSSRC
- SEEKFILEDOSSRC
- READFILEDOSSRC
- EXPANDFILEDOSSRC.;
- WRITEFILEDOSSRC
- CLOSEFILEDOSSRC
- MAKEDIRDOSSRC
- ~INDEX CZ.HLP-BULLET for QB/BASIC PDS
- System
- Mid-level Record/Key Access
- InitXB
- CreateDXB CreateKXB GetDescriptorXB FirstKeyXB
- ExitXB
- OpenDXB OpenKXB GetRecordXB EqualKeyXB
- AtExitXB
- CloseDXB CloseKXB AddRecordXB NextKeyXB
- MemoryXB
- StatDXB StatKXB UpdateRecordXB PrevKeyXB
- BreakXB
- ReadDHXB ReadKHXB DeleteRecordXB LastKeyXB
- BackupFileXB
- FlushDHXB FlushKHXB UndeleteRecordXB StoreKeyXB
- StatHandleXB
- CopyDHXB CopyKHXB PackRecordsXB DeleteKeyXB
- GetExtErrorXB
- ZapDHXB ZapKHXB BuildKeyXB
- DVmonCXB
- CurrentKeyXB
- High-level Access
- Network
- GetFirstXB InsertXB
- LockXB UnlockXB LockKeyXB
- GetEqualXB UpdateXB
- UnlockKeyXB LockDataXB UnlockDataXB
- GetNextXB ReindexXB
- DriveRemoteXB FileRemoteXB SetRetriesXB
- GetPrevXB
- GetLastXB
- Low-level DOS Access
-
- DeleteFileDOS OpenFileDOS WriteFileDOS
-
- RenameFileDOS SeekFileDOS CloseFileDOS
- Move cursor to index item
- CreateFileDOS ReadFileDOS MakeDirDOS
- and press <Enter>.
- AccessFileDOS ExpandFileDOS
- See: TUTORIAL_INDEX
- ~TUTORIAL_INDEX CZ.HLP-BULLET for QB/BASIC PDS
- CZ.COM
- Using BULLET
- 1.02
- Starting_CZ
- What: How to:
- Using_CZ
- is_BULLET design_a_DB BC_compile_with
- About_CZ
- is_a_database create_a_DB LINK_with
-
- is_DBF add_to_the_DB LIB_with
- is_a_Btree query_the_DB make_a_QLB
- Error Codes
- is_a_network update_the_DB
-
- Errors_BULLET
- is_file_locking delete_a_record
- call_BULLET
-
- Errors_BASIC
- is_NLS
-
- Errors_DOS
- LICENSE_AGREEMENT Product_Support
- Structure Pack Types
- Specifications
- AccessPack DVmonPack RemotePack
- Specs_Overall
- BreakPack ExitPack SetRetriesPack
- Specs_DBF
- CopyPack FieldDescTYPE StatDataPack
- Specs_Index
- CreateDataPack HandlePack StatKeyPack
- Specs_Memory
- CreateKeyPack InitPack StatHandlePack
- Specs_OS_Calls
- DescriptorPack MemoryPack XErrorPack
- Specs_Languages
- DOSFilePack OpenPack
- Specs_OSes
-
- Specs_Networks
-
- Specs_Performance
- See: License_Agreement
- ~License_Agreement
- Before using this software you must agree to the following:
- 1. You are not allowed to operate more than one (1) copy of this software
- package at one time per license. This means that if you have 10 programmers
- that COULD possibly use the BULLET library at the same time, you must also
- have ten (10) BULLET licenses.
- 2. You are not allowed to distribute non-executable code containing BULLET
- code. This means that you are not allowed to redistribute BULLET code as
- another .LIB, for example. Also, if BULLET code is to be contained in a
- Dynamic Link Library (DLL) then it must be part of a stand-alone product.
- This means that you cannot provide a .DLL containing BULLET code if that
- .DLL is to be used as a programming library for other programmers. If you
- wish to distribute non-executable code containing BULLET code you must
- obtain written permission from the author.
- 3. This license grants you the right to use the BULLET library code on a
- royalty-free basis.
- See: License_a -MORE-
- ~License_a
- 4. BULLET is owned by the author, Cornel Huth, and is protected by United
- States copyright laws and international treaty provisions. You are not
- allowed to make copies of this software except for archival purposes.
- 5. You may not rent or lease BULLET. You may not transfer this license without
- the written permission of the author. If this software is an update or
- upgrade, you may not sell or give away previous versions.
- 6. You may not reverse engineer, decompile, or disassemble this software.
- 7. There are no expressed or implied warranties with this software.
- 8. All liabilities in the use of this software rest with the user.
- 9. U.S. Government Restricted Rights. This software is provided with
- restricted rights. Use, duplication, or disclosure by the Government is
- subject to restrictions as set forth in subparagraph (c)(1)(ii) of the
- Rights in Technical Data and Computer Software clause at 52.227-7013.
- Manufacturer is Cornel Huth/6402 Ingram Rd/San Antonio, TX 78238.
- This agreement is governed by the laws of the state of Texas.
- See: Product_Support
- ~Product_Support
- Phone support is available 7 days a week, 9AM-9PM Central Time (USA) for
- registered users. Phone support for non-registered users is not available.
- If you are a registered BULLET user you may call 1-512-684-8065 during the
- hours listed above. If I'm not available to handle your call leave a message
- on the machine briefly explaining the basis for your call. You MUST leave a
- message stating that you want the return call to be COLLECT. Calls cannot be
- returned unless you state this in your message (no exceptions).
- If you have a problem that you believe to be due to a bug in BULLET, mail a
- diskette with the program and data to recreate the problem. Include all source
- code, data files, libraries, etc. on the disk that is needed to recreate the
- problem. Do not send your entire application. Do not send only a listing. Send
- only the code that is sufficient for another person to recreate the problem.
- (No exceptions.)
- A support BBS is not currently available but is expected to be operational in
- the near future. If you would like to use a BBS to communicate you may reach me
- at NUL BBS, 1-512-615-6852 (2400-), 615-6851 and 6853 (9600+, HST, V.32bis) or
- you may contact me on FidoNet at Cornel Huth @ 1:387/800 or through Internet at
- Cornel.Huth@p8.f800.n387.z1.fidonet.org.
- See: Starting_CZ
- ~Starting_CZ
- At CZ's initial load it looks into the current directory for CZ.HLP, then in
- the directory of CZ.COM, and last it looks for the pathname specified by the
- DOS variable CZH (SET CZH=C:\DOC\CZ.HLP). Use /f: for alternate locations.
- Load CZ.COM from the DOS command line. Options are:
- /f:helpfile.ext Use other than default CZ.HLP help file
- /h# where n=1 to 4 Use alternate hot-key from default Alt-F1
- #=1 Ctrl-h
- #=2 F12
- #=3 left+right Shift
- #=4 Alt-left Shift
- /u uninstall CZ from memory (after initial load)
- /s temporarily put CZ to sleep by restoring all hooked vectors
- /r restore CZ from its sleep by rehooking vectors
- /? quick help
- E.g., C>cz /f:D:\PRG_C\CBULLET.HLP supply entire pathname when using /f:
- C>cz /h1 change hot key from Alt-F1 to Ctrl-H
- You can use the /f: at any time, even after the initial install, as all but /u.
- See: Using_CZ
- ~Using_CZ
- To activate CZ press the hot-key while the cursor is on the word you want to
- look up. Information on that word, if any, is displayed. If none is available,
- an index of help items in the dictionary is shown. Along the top-right of the
- index screens is the control bar. You can quickly move to the control bar by
- pressing <Home> or the See: line with <End>. Move the cursor to TUTORIAL_INDEX
- to select the second index screen or QUIT to return to whatever you were doing
- or over any index item. Then press <Enter> to move to that item's help entry.
- <F1> can be used as <Enter>. A mouse can also be used and is recommended.
- For example, to find out about CreateDXB, type it in your application and move
- the cursor on it. Press the hot-key. The CreateDXB screen is displayed. To see
- what pack type it uses, move to CreateDataPack (at Pack:) and press <Enter>.
- For a source example, move the cursor to Src: CreateDXBsrc. To go straight to
- the index from your application, press the hot-key with the cursor on a blank
- space. The <Esc> key returns you to your application.
- If there are more screens for the current topic the See: line has the same
- topic name plus a letter, and -MORE- at the end. Move the cursor (or mouse)
- to the topicname text (by using the <End> key) and press <Enter> (or click).
- See: Using_CZ_a -MORE-
- ~Using_CZ_a
- CZ.COM can be loaded high but it is ESSENTIAL that you have at least 15K of
- free UMB RAM available. It will load in as little as 4.5K but it will not
- operate correctly. Use MEM/c to see how much Upper Memory RAM is available.
- CZ opens the help file at installation. The help file is opened for Read-Only
- access with a Deny None sharing attribute. The file is closed when CZ is
- uninstalled (C>cz /u). CZ makes use of its own 256-byte stack.
- If you have several CZ help files, rename them to their particular application.
- For example:
- Rename the QuickBASIC BULLET CZ.HLP to QBULLET.HLP. Put QBULLET.HLP into your
- help files directory. Put SET CZH=C:\HELPFILES\QBULLET.HLP in your AUTOEXEC.BAT
- file. The next time CZ is installed it uses QBULLET.HLP from C:\HELPFILES.
- At anytime you can specify CZ.COM to use another help file. For example, if the
- current CZ help file is QBULLET.HLP but you want to use the CBULLET.HLP file,
- use C>cz /f:\helpfiles\cbullet.hlp. CBULLET.HLP then becomes the active file
- the next time you popup CZ.
- See: Using_CZ_b -MORE-
- ~Using_CZ_b
- Limitations:
- 1) The QB environment may interpret the Alt-F1 keypress after CZ has popped
- down. If this is a problem then change the hotkey, e.g., C>cz /h2 to use F12.
- 2) In the QB (and QBX) environment the keypad <Enter> key is not recognized by
- CZ. Use the main <Enter>. This occurs only in then QB 4.5 and QBX editors.
- 3) If, after returning from CZ, the QB environment's menu bar does not respond
- to Alt-keys (like an Alt-F), click the left mouse button a few times, or press
- F6 to go to the immediate window and execute a SHELL. It's unlikely that you'll
- encounter this.
- 4) CZ is a stable TSR but like all TSRs in a DOS system, unforseen events can
- take place that could conceivably cause the computer to crash. Therefore, it's
- recommended that you save your work often (you should do so whether a TSR is
- installed or not).
- 5) CZ currently doesn't reset the mouse. If you're having mouse trouble, you'll
- need to reset your mouse driver (type MOUSE at the C>). Many problems come from
- other programs not restoring the mouse cursor to its original state.
- See: About_CZ
- ~About_CZ
-
-
- CZ HELP
-
-
-
- Context-sensitive Online Help Manager
-
-
-
- for the
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- compiler libraries
-
-
-
- MS-DOS QuickBASIC/BASIC PDS version
-
- (available for most DOS compilers)
-
-
-
- Copyright 1992 Cornel Huth
-
-
-
- Ver 1.02 INT2F MuxID=C2 15-Aug-92
-
- See: Specs_Overall
- ~is_BULLET - What?
- BULLET is a program module that handles the details of putting information to
- and getting information from your hard disk using a standard data file format
- called the Xbase DBF format with very fast and efficient index file routines.
- It can be used as-is by most DOS compilers.
- BULLET is written in 100% assembly language. Why? Two reasons. First, control.
- There's no compiler code or run-time library code in between BULLET and your
- data. Second, efficiency. BULLET knows exactly what it requires from the
- operating system and when. Result: fast, small, and robust applications.
- See: is_a_database
- ~is_a_database - What?
- A database is a collection of data arranged so that the it can be accessed as
- useful information. For example, let's say we have two files. Each consists of
- two fields. The first file has codenumber and score. The second file has a
- codenumber and name. Separately, the files are merely a collection of data.
- Together, however, they tie the name to the score:
- score codenumber codenumber name
- 99 100 100 John
- 87 155 105 Paul
- 66 125 110 George
- : : : :
- Codenumber 100 is John, who scored 99. The other members scores are not in the
- abbreviated data file listing.
- A database can be a single data file but more often it is a group of related
- data files and usually these data files are indexed by keys (in the index file,
- also called key file) so that very fast, direct access is possible.
- See: is_DBF
- ~is_DBF - What?
- DBF is the file extension of dBASE III-compatible data files (filename.DBF).
- The file format is used by dBASE IV, FoxPro and many other database programs.
- Many programs can also use the file format to import/export data using it.
- The DBF format is the most common data file format used on PCs.
- A DBF-compatible data file consists 3 distinct areas. First is the data header.
- This contains information such as the number of records in the file. Second is
- the field descriptors. These descriptors define the makeup of each field in the
- record. The third is the record area. Each record is a logical unit of data.
- For example, a record, all of which are made up of the same fields but with
- different data, could (conceptually) look like this:
- field 1 field 2 field 3 field n
-
- record 1
- Johnson
- Larry
- 465310555 ...
-
- record 2
- Aberdeen
- Zara
- 465230555 ...
-
- record n
- See: is_a_Btree Specs_DBF
- ~is_a_Btree - What?
- A b-tree is a sorting method ideally suited to data structures maintained on a
- hard disk. It is very fast on retrieval and is inherently self-balancing during
- inserts and deletes. Self-balancing ensures performance remains consistent.
- The reason the b-tree is ideally suited to hard disks is that, when looking for
- a particular key, most of the time involved in accessing the key is spent by
- the hard drive moving to various locations on the disk. The task of a good
- access method is to reduce the number of seeks that the disk must perform. The
- b-tree accomplishes this by maintaining several keys (perhaps 50) on each node,
- with the necessary pointers to previous and following nodes. A b-tree of order
- 20 (19 keys per node) can find a key in a file of 1,000,000 keys in a MAXIMUM
- of 5 disk accesses, where each disk access visits a node.
- 'BASIC program to find *max* seeks needed/avg time
- Keys& = 1000000: KeysPerNode = 19: AvgSR = 25
- Order = KeysPerNode + 1
- max = (LOG((Keys& + 1) / 2) / LOG(Order / 2))
- PRINT "Max nodes accessed for"; Keys; "keys & b-tree of order"; Order;
- PRINT "is"; max; "nodes"
- PRINT "Max disk time based on avg seek+read of"; AvgSR;
- PRINT "ms is"; AvgSR / 1000 * max; "seconds"
- See: is_a_network Specs_Index
- ~is_a_network - What?
- A network is a group of computers able to communicate with one another. Often
- called a LAN (local area network), a network allows resources to be shared.
- Sharing resources can lead to problems if steps are not taken to ensure that
- two computers don't try to share the same resource at the same time. For
- example, say two computers try to change the same record in a file on a network
- drive. Let's say both users are accessing the number of widgets in inventory.
- The first user gets there a micro-second before the second and allocates the
- last widget in stock. The second user comes in right after and, since the first
- user has not yet updated the inventory, allocates the very same widget. One
- widget, two users. When the first user updates the inventory, widgets in
- inventory is changed to 0 (previous - 1). The second updates the inventory in
- the same manner and sets widgets to 1 less what it was when it started, or 0
- also. You see the problem.
- In order to successfully share a file on a network, the file must first be
- locked to a single user. Once that user has locked the file, he has sole access
- to the data within it and he will not experience the scenario above. When the
- user has completed the changes, he unlocks the file so that others may use it.
- See: is_file_locking
- ~is_file_locking - What?
- File locking is a means to obtain exclusive access to a file. This is needed in
- cases of multiple programs or users accessing a shared file at the same time.
- There are several methods to ensure only one process or user has access to a
- file. The first method is to open the file so that while the file is open only
- your program can access any part of it. This is simple to implement and the
- operating system handles the details of this. However, it requires your program
- to open/close files all the time since no other process may access the file
- while it is open.
- Another method is to use byte-level locks. Also managed by the OS, this method
- allows for restricting access to any particular region within the file. Which
- regions are to be locked is to be determined by your program, however, and it
- can be complex to perform multiple locks at the byte, field, or record level.
- Another use of the byte-level lock is to specify that all bytes within the file
- are to be locked. This greatly simplifies the process of obtaining a lock and
- has the advantage over a file access lock of not needing to open/close the file
- for each lock. It is very fast and easy to implement. BULLET offers all three
- lock types.
- See: is_NLS
- ~is_NLS - What?
- NLS stands for National Language Support. This feature is available in DOS 3.3
- and later. BULLET makes use of NLS by getting from DOS the current DOS country
- collate-sequence table. The collate table is used to properly sort mixed-case
- character strings and also foreign (or non-USA) language character strings
- according to that country's alphabet. This is an option but is recommended.
- In addition, BULLET provides for a programmer-supplied collate-sequence table.
- See: design_a_DB
- ~design_a_DB - How to
- To design a database, above all else, know what information you require from
- it. Having established what you need to know, collect the data that lets you
- formulate this into useful information.
- For example, you want to track a class of students and determine how well they
- achieve on tests. The criterion you use is the test score. You determine that
- your data is 1) students, 2) tests, and 3) test scores. Too simplify, you use
- a single 20-character field for student, a 1-character field for test number
- ("1" to the "n" tests), and a numeric field for test scores (0 to 100).
- Since the objective is to track students' scores, arrange the data so that
- output consists of each student's score in test order. Do this by specifying an
- index file containing an index based on the student's name and test number:
- KeyExpression$ = "STUDENT + TEST" 'combine two character fields
- This is the reason that field 2, test number, is a character field. It can more
- easily be combined with other character fields than a numeric field. By using
- the routines of the database langauge, you can easily create the data and index
- files, add data, list student's scores, or make changes to the database. Note:
- these How_to examples are meant only to show the basis behind an operation.
- See: create_a_DB CreateKXB
- ~create_a_DB - How to
- Having defined the database, create it. First, create the datafile based on the
- 3 fields you defined in your design. To do this, DIM an array for the field
- descriptors for the number of fields (see also CreateDataPack):
- DIM FD(1 TO 3) AS FieldDescTYPE
- FD(1).FieldName = "STUDENT" + STRING$(10,0) 'must be zero-filled
- FD(1).FieldType = "C"
- FD(1).FieldLength = CHR$(20)
- FD(1).FieldDC = CHR$(0)
- The FD() is a structure element
- FD(2).FieldName = "TEST" + STRING$(10,0)
- in CDP (CreateDataPack) as in:
- FD(2).FieldType = "C"
- CDP.Func=CREATEDXB
- FD(2).FieldLength = CHR$(1)
- : :
- FD(2).FieldDC = CHR$(0)
- CDP.FieldListPtrOff=VARPTR(FD(1))
- FD(3).FieldName = "SCORE" + STRING$(10,0)
- CDP.FieldListPtrSeg=VARSEG(FD(1))
- FD(3).FieldType = "N"
- : :
- FD(3).FieldLength = CHR$(3)
- FD(3).FieldDC = CHR$(0)
- Call CreateDXB to create the data file. To create the index file, first open
- the data file just created, then call CreateKXB to create the index file. Open
- the index file so we can use it (data file is already open).
- See: add_to_the_DB CreateDXB
- ~add_to_the_DB - How to
- Once you have the database designed and the data and key files created and open
- you can start putting the student's test data into it. Note that the DBF-format
- requires that all data in a data file be in ASCII format. This means that we
- must convert the numeric test score into its ASCII form. BASIC has the STR$()
- function to do this. In addition, numbers generally should be right-justified
- in their field. BASIC has the RSET statement to do this:
- TYPE StudentRecordTYPE 'this structure is exactly how the record is on disk
- tag AS STRING * 1 'DBF delete tag used to identify deleted records
- sname AS STRING * 20 '--the tag is always present in any DBF record
- testn AS STRING * 1 ' don't forget to include it in all your TYPEs
- score AS STRING * 3
- END TYPE '25
- DIM SR AS StudentRecordTYPE
- :
- INPUT "Student name, test number, score:",n$,t$,s%
- SR.sname = n$ : SR.testn = t$ : RSET SR.score = STR$(s%)
- status = DoInsert(SR, keyhandle)
- LOOP UNTIL LEN(n$) = 0 OR (status <> 0)
- See: query_the_DB InsertXB
- ~query_the_DB - How to
- Now that you have data in the database you want to see what's in there. Since
- the index file is in "STUDENT + TEST" order, the information we'll be getting
- out of the database is in Student name order, with each student's scores in
- test number order.
- If we want to look at all the students, we can use GetFirstXB to retrieve the
- first student's score for the first test. GetNextXB retrieves the next record
- (the first student's score for the second test), and so on. When all records
- have been retrieve GetNextXB returns an End Of File error code.
- If we want to look at a particular student's score only, we can use GetEqualXB
- to go directly to a student's first test score. GetNextXB get his next and so
- on until GetNextXB retrieves the next student's first test score. You can stop
- at this point (student names no longer match).
- We might also want to find all students who scored less than 65 on any test. To
- do this we can GetFirstXB, check SR.score for < 65 and if so print that record.
- Continue by using GetNextXB, printing each record that has a score < 65.
- See: update_the_DB GetFirstXB
- ~update_the_DB - How to
- To update a particular record in the database we must first locate and identify
- it using one of the get routines such as GetEqualXB. The Get() routine return
- the record data, and also the physical record number of the record accessed,
- into the AccessPack RecNo. Having used one of the Get() routines to read the
- data record from disk to memory, you can make any changes to the data record in
- memory. E.g., if a student's score needs to be changed from a 69 to a 96, first
- find the record (and its RecNo), then update the score field:
- INPUT "Student name, test number",n$,t$
- SR.sname = n$ : SR.testn = t$
- status = DoGetStudentTestScore(SR, keyhandle, Recno&)
- DO UNTIL status <> 200 'student as entered not found, call search routine
- status = DoFindStudentTestScore(SR, keyhandle, RecNo&)
- LOOP
- IF status = 0 THEN
- PRINT "Student:" ; SR.sname ; " old score:" ; SR.score
- INPUT "Enter new score:"; s% : RSET SR.score = STR$(val(s%))
- status = DoUpdateTestScore(SR, keyhandle, Recno&)
- ENDIF
- Any change to a key field will initiate a key file update automatically.
- See: delete_a_record UpdateXB
- ~delete_a_record - How to
- To delete a particular record in the database we must first locate it using
- one of the get routines such as GetEqualXB. These Get() routines return the
- actual record number of the data record accessed by Get() into the AccessPack
- RecNo. Having used one of the Get() routines to find the data record, make a
- call to the delete function:
- 'delete all of Student's records, 1 record for each test he's taken
- INPUT "Student name to delete",n$
- SR.sname = n$
- status = DoGetStudent(SR, keyhandle, RecNo&)
- DO UNTIL status <> 200 'student as entered not found, call search routine
- status = DoFindStudent(SR, keyhandle,RecNo&)
- LOOP
- DO
- status = DoDeleteRecord(SR, RecNo&) 'does not affect key files
- IF status = 0 THEN status = GetNextChkIfSameStudent(SR,keyhandle,RecNo&)
- LOOP UNTIL status <> 0
- The DeleteRecordXB routine does not physically remove the record from the data
- file but instead tags it as being "deleted".
- See: BC_compile_with DeleteRecordXB
- ~BC_compile_with - How to
- To create a stand-alone EXE file, compile your BASIC source as required. No
- special compiler switches are required. When your compiler is finished and has
- reported no errors during the compile, use the LINK program supplied with your
- compiler to resolve any external references in your BASIC program code that are
- dependant on the BULLET library code.
- For example, if you have a single-module BASIC source file called STUGRADE.BAS,
- compile it:
- C>bc STUGRADE /o;
- If successful, use the LINK program to build the final EXE:
- C>link STUGRADE,STUGRADE.EXE,nul,BULLET.LIB;
- If successful, link creates STUGRADE.EXE ready to be run at the DOS prompt.
- The BASIC runtime is also supported by BULLET. Just compile as you normally
- would (without the /o, of course).
- See: LIB_with
- ~LIB_with - How to
- BULLET.LIB is composed of many separate assembly language modules. All these
- modules have been combined into a single, easy-to-use .LIB library. While it
- is possible to combine, or add, other .OBJ files or even other .LIB files to
- BULLET.LIB, I do NOT, -NOT-, recommend that you do so.
- If you need to use two or more libraries with your programs, no problem, LINK
- can handle as many as you have. When LINK prompts you for a library file, just
- enter BULLET.LIB followed by any other library you need. For example:
- C>LINK
- Microsoft (R) Segmented-Executable Linker Version 5.10
- Copyright (C) Microsoft Corp 1984-1990. All rights reserved.
- Object Modules [.OBJ]: STUGRAD1+STUGRAD2+STUB
- Run File [STUGRAD1.EXE]: STUGRADE.EXE
- List File [NUL.MAP]: nul
- Libraries [.LIB]: BULLET MOUSE;
- Consult your linker programs documentation for more.
- See: make_a_QLB
- ~make_a_QLB - How to
- If you use the QuickBASIC environment to program in, you need to build a .QLB
- so that you can call the BULLET routines. While QuickBASIC can load only a
- single QLB ( C>qb /L quicklib.qlb ), you can combine many LIB and OBJ modules
- to create the QLB. For example, to make a QLB of the BULLET.LIB, MOUSE.LIB,
- and STUB.OBJ modules:
- C>link /QU BULLET.LIB+MOUSE.LIB+STUB, IDE.QLB, nul, BQLB45.LIB;
- Note the extension .LIB on the library modules. This is REQUIRED since LINK
- assumes .OBJ by default, as in the case of STUB, above. The quick library,
- BQLB45.LIB, is required for the Libraries: prompt. The exact name depends on
- the compiler version. Consult your compiler documentation for more.
- BASIC PDS note: BASIC PDS requires that all BASIC modules included into a QLB
- be compiled using the /Fs compiler switch. This instructs the compiler to
- generate code compatible with "far strings". Since BULLET is written entirely
- in assembly langauge, this is not an issue. However, if you start QBX.EXE with
- /L and get an INVALID FORMAT error, one of the modules in the .QLB file most
- likely was a BASIC module that was not compiled with the /Fs switch.
- See: LINK_with
- ~LINK_with - How to
- After successfully compiling your BASIC source code module(s), use the LINK
- program to build the EXE program file. For this example let's assume that you
- have 2 BASIC source code modules just compiled and their .OBJs available, the
- BULLET.LIB library, a stub object file called STUB.OBJ, and MOUSE.LIB.
- To build the final stand-alone EXE from this group of files, do the following:
- C>link STUGRAD1+STUGRAD2+STUB,STUGRADE.EXE,nul,BULLET+MOUSE;
- The 3 object modules, STUGRAD1, STUGRAD2, and STUB, will have their entire code
- included in the EXE program, created as STUGRADE.EXE. The 2 library files,
- BULLET.LIB and MOUSE.LIB, will have only the code that is actually referenced
- by the 3 object modules included into the EXE program.
- If successful, link creates STUGRADE.EXE ready to be run at the DOS prompt.
- See: call_BULLET AtExitXB
- ~call_BULLET - How to?
- BULLET is called through a single entry point. The only argument passed to it
- is a segmented far pointer to the control pack. The first two entries in this
- pack are the function to be performed and the function return status. BULLET
- is a FUNCTION call returning an INTEGER status value.
- Each function (or routine) uses a prescribed pack format. For example, some
- routines need only know the handle of the file, along with the function number
- itself. So, to flush a data file, for example, you would do the following:
- DIM HP AS HandlePack 'could also DIM SHARED
- HP.Func = FLUSHDHXB 'FLUSHDHXB is defined as a CONST in BULLET.BI
- HP.Handle = File2FlushHandle 'the handle as returned from the Open() routine
- stat = BULLET(HP) 'do the actual call to BULLET
- The value of stat is set to the completion code as returned by the FlushDHXB
- routine. It is the same as the value returned in HP.Stat *IN ALL BUT A FEW*
- cases: InsertXB, UpdateXB, ReindexXB, and LockXB. These routines return not
- the actual error code, but rather a transaction index number of the access
- that failed. See those routines for more information.
- See: is_BULLET FlushDHXB
- ~Specs_Overall
- BULLET is dBASE III/III+/IV .DBF-compatible. This format is compatible with a
- large base of software programs including the latest database packages such as
- dBASE IV and FoxPro. Spreadsheet packages such as Excel and 1-2-3 can directly
- import BULLET DBF data files, too. And because of BULLET's versatility, it can
- also create very non-standard data files. This may be a useful feature if data
- secrecy is of concern.
- BULLET requires MS-DOS 3.30 or above. It uses 19K of code/static data space and
- requires at least 40K of workspace. 140K of workspace is ideal.
- Overall Specifications:
- DBF (per file) INDEX
-
- Max records: 16,777,215 Max nodes: 65,535
- Record length: 2-4000 (8192) Max keys: 4,063,170
- Max fields: 128 (255) Key length: 1-64
- Field length: 1-254 (255) Max key fields: 16
- Total open index plus data files can be up to 255. Numbers in () indicate
- extended specifications.
- See: Specs_DBF
- ~Specs_DBF
- To remain compatible with other dBASE III .DBF platforms you should restrict
- your data files to the following specifications:
- File ID byte: 3 (83hex if .DBF has memo field, not currently supported)
- Max record size: 4000 bytes Max fields/rec: 128 Max field size: 254 bytes
- Allowable field name characters: A-Z and the _ (upper-case)
- Allowable field types:
- C-character, 1-254 bytes
- D-date, 8 bytes, in the format YYYYMMDD (19920531)
- L-logical, 1 byte, either space, "T" or "Y", "F" or "N"
- M-memo, 10 bytes, used as pointer into .DBT file (currently not supported)
- N-numeric, 1-19 bytes, ASCII format, uses explicit decimal if needed...
- ...decimal places may be 0, or 2 to (field size - 3) but no more than 15
- Restrict all data in .DBF fields to ASCII. This means you should convert binary
- data to the equivalent ASCII representation, e.g., if you have the binary value
- 22154, it must first be converted to the string "22154" before you can store it
- to the .DBF data file. So, while your in-program code deals with binary data,
- your I/O code must convert it to/from ASCII. This is a dBASE-compatibility
- issue only. If you can forgo these requirements you can use binary fields, any-
- character field names, record sizes to 8192 bytes, and up to 255 fields.
- See: Specs_DBF_a -MORE-
- ~Specs_DBF_a
- A dBASE III .DBF is composed of 3 sections: the header, the field descriptors,
- and the data area.
- The header structure (first 32 bytes of file):
- Name Type Offset Meaning
- FileID byte 0 data file type id, 03 standard (43,63,83,88h)
- LastYR byte 1 last update year, binary
- LastMo byte 2 last update month, binary
- LastDA byte 3 last update day, binary
- NoRecs long 4 number of records in file
- HdrLen word 8 length of header, including field descriptors, +1
- RecLen word 10 length of data record including delete tag
- internal byte 12-31 reserved
- The last update values are updated to the current date whenever the .DBF file
- is flushed or closed. Likewise, the NoRecs value is updated whenever a record
- is added to the .DBF. The FileID is specified when you create the file, HdrLen
- and RecLen are computed and stored when the file is created, too.
- See: Specs_DBF_b -MORE-
- ~Specs_DBF_b
- The field descriptor format (follows header, one per field):
- Name Type Offset Meaning
- FieldName char 0 field name 10 ASCII characters, A-Z or _ (0-filled)
- 0T byte 10 field name zero-termintor (must be 0)
- FieldType char 11 field type (C D L M N)
- internal long 12 reserved
- FieldLen byte 16 length of this field
- FieldDC byte 17 decimal count
- internal byte 18-31 reserved
-
- The unused bytes in the FieldName must be set to zeroes (CHR$(0)).
- Each field is described by a 32-byte descriptor. The first field's descriptor
- starts right after the header proper, at offset +32. After the last field
- descriptor is data byte ASCII 13. (Note: the orginal dBASE III has a 0 byte
- following this ASCII 13.) Immediately following this is the actual record data.
- See: Specs_DBF_c -MORE-
- ~Specs_DBF_c
- The data record format:
- The first record is located at offset HdrLen (from the header). The first byte
- of each record is a delete tag. This tag is maintained by the BULLET routines.
- A space, ASCII 32, means the record is not deleted; an asterisk, ASCII 42,
- means the record has been deleted (marked as deleted, often this is used as a
- method to temporarily tag records, for whatever purpose).
- Following the tag is the data for each field, not delimited (i.e., the fields
- run together without anything separating them). The second record is at offset
- HdrLen+reclen. The start offset of any record in the file can be computed as
- (recordnumber - 1) * reclen + HdrLen. All data is in ASCII form.
- An EOF marker (ASCII 26) is placed at the end of the last record.
- See: Specs_Index
- ~Specs_Index
- BULLET uses a proprietary, modified b-tree index method to manage the index
- files. The supported key types are:
- Type Length Meaning
- Character 1-64 ASCII, NLS, or user-supplied sort table
- Integer 2 signed or unsigned 16-bit value
- Long Int 4 signed or unsigned 32-bit value
- In addition to the above types, BULLET allows for unique or duplicate keys in
- the index file. If duplicates are allowed, BULLET enumerates each key with an
- enumerator word (see FirstKeyXB).
- The key may be composed of up to 16 character fields or substrings within those
- fields. Numeric fields are considered character fields by BULLET unless the key
- is set to binary (see KeyFlags). Integer or LongInt binary keys can be composed
- of a single field only. The key expression is specified in text (e.g., "LNAME+
- SUBSTR(FNAME,1,1)+MI") and is fully evaluated when the index file is created.
- A BULLET index file is composed of 3 sections: the header, the collate-sequence
- table, and the node/key entry area.
- See: Specs_Index_a -MORE-
- ~Specs_Index_a
- The header structure:
- Name Type Offset Meaning
- FileID byte 0 index file type id, 20
- RootNode word 1 root node number
- Keys 24bit 3 number of keys in index file
- AvalNode word 6 node number available for reuse
- FreeNode word 8 next free node number
- KeyLen byte 10 key length
- NodeKeys byte 11 number of keys that fit on a node
- CodePage word 12 code page ID
- CtryCode word 14 country code
- internal byte 16-21 reserved
- KeyFlags word 22 key flags
- KeyExprn byte 24-159 key expression
- internal byte 160 reserved
- KeyXFlds byte 161 number of fields used by key (1-16)
- KeyXlate byte 162-225 translated key expression
- internal byte 226-253 reserved
- CTsize word 254 collate-sequence table size
- See: Specs_Index_b -MORE-
- ~Specs_Index_b
- The collate-sequence table structure:
- table byte 256-511 sort weight table of ASCII character 0-255
- Node/key entry structure (first entry is in node #1, file offset 512):
- 2A 0A 00 KEY123 7B 00 00 12 00 KEY178 B2 00 00 0C 00 ...
- 1. 2. 3. 4. 5. 6. 7. 8. 9.
-
- 1. Key count for that node (first byte of each node)
- 2. 16-bit node back pointer (for non-leaf nodes, 0 if leaf node)
- 3. First key value, "KEY123" in this case
- 4. 24-bit data record pointer (low word/hi byte) 7Bh = DBF record number 123
- 5. 16-bit node forward ptr/back ptr (for non-leaf nodes, 0 if leaf node)
- --in this case, it indicates that the key following KEY123 is in node# 12h
- --and also that the key before KEY178 is in that node as well
- 6. Second key (here "KEY178")
- 7. 24-bit data pointer (record number in DBF)
- 8. 16-bit forward node pointer (for non-leaf nodes, 0 if leaf node)
- 9. Repeat 6 to 8 for each key on node. (node size is 512 bytes)
- See: Specs_Index_c -MORE-
- ~Specs_Index_c
- As in many b-tree implementations, BULLET's index files maintain an average
- load percentage of approximately 66%. This means that in any given node, 66% of
- the available space is in use. The free space in the node is attributable to
- the constant reshaping of the file as keys are inserted or deleted, causing the
- nodes to be split and merged. A split will occur when an insert needs to add a
- key to an already full node; a merge will occur when a neighboring node is
- small enough to be merged into a just split node. This constant prune-and-graft
- of the b-tree results in a node load of about 66% (50% in degenerate cases such
- as with already sorted data). It's this aspect of the b-tree that makes it a
- consistent performer and a widely-used method of managing index files.
- The following formula can be used to determine the number of keys that an index
- file can hold:
- MaxKeys = MaxNodes * MaxKeysPerNode * LoadFactor
- MaxKeys = 65535 * 509/(keylen+5) * .66
- The load factor can be increased to ~95% by using the ReindexXB routine. This
- load factor results in superior retrieval speeds since there are more keys on
- each node. Insertion speed will be decreased, however, since splitting will
- occur more frequently, though perhaps not noticeably.
- See: Specs_Memory
- ~Specs_Memory
- BULLET allocates memory on an as-needed basis. When linked to an executable
- program, BULLET makes use of 17.5K of code space and about 1.5K of static
- DGROUP data space. To accomodate the wide variety of compilers, BULLET's API
- structure will have the linker included all of the library into your final EXE
- program.
- All runtime memory allocations are obtained from the operating system. This
- means that if your compiler generates code to allocate all the free memory at
- startup for its far heap, you need to instruct it to free up some memory for
- BULLET's use. In QuickBASIC you can use SETMEM(). You can also use the linker
- /CP:n option to limit the amount that the compiler-generated startup code
- allocates. The EXEHDR.EXE program can also be used to modify this amount. The
- linker /CP: option and the EXEHDR program both modify the EXE header. To
- determine if you need to release memory use the MemoryXB routine. It reports
- the operating system memory available for use by BULLET.
- The amount of memory that BULLET requires is based on which routines are used.
- See the next screen for a list of the routines that make malloc calls to the
- operating system and how much memory they require.
- (Most compilers don't grab all memory as QuickBASIC when it's using $DYNAMIC).
- See: Specs_Memory_a MemoryXB -MORE-
- ~Specs_Memory_a
- Routines making dynamic memory allocations and amount (within
- 16 bytes):
- Routine Bytes Basis
- InitXB 272 permanent, released when program ends (JFTmode=1)
- BackupFileXB 32K temp, released when routine exits
- CreateDXB 48+(NF*32) temp, released when routine exits (NF=NoFields)
- CreateKXB 544 temp, released when routine exits
- OpenDXB 144+((1+NF)*32) semi-permanent, released when file closed
- OpenKXB 1264 semi-permanent, released when file closed
- PackRecordsXB RL to 64K temp, released when routine exits (RL=RecLength)
- ReindexXB 32K to 128K temp, released when routine exits
- UpdateXB 2K+RL temp, released when routine exits (RL=RecLength)
- For example, when BackupFileXB is called it attempts to allocate 32K from the
- OS. If 32K is not available, BackupFileXB returns with an error code of 8 (DOS
- error #8, not enough memory). And, for example, ReindexXB attempts to allocate
- 128K if available. If not, it continues in decrements of 32K, down to 32K.
- Needed stack space is 4K (max) for ReindexXB. Other routines can operate with
- less than 1K of stack space. In other words, stack use is minimal.
- See: Specs_OS_calls
- ~Specs_OS_calls
- BULLET makes use of the following operating system calls:
- INT21/25 DOS_setvector INT21/44/0B DOS_setsharingretrycount
- INT21/2A DOS_getdate INT21/48 DOS_malloc
- INT21/30 DOS_version INT21/49 DOS_free
- INT21/35 DOS_getvector INT21/51 DOS_getpsp
- INT21/39 DOS_makedir INT21/56 DOS_renamefile
- INT21/3D DOS_openfile INT21/59 DOS_getextendederror
- INT21/3E DOS_closefile INT21/5A DOS_createtempfile
- INT21/3F DOS_readfile INT21/5B DOS_createnewfile
- INT21/40 DOS_writefile INT21/5C DOS_lockunlockfile
- INT21/41 DOS_deletefile INT21/65/01 DOS_getextendedcountryinfo
- INT21/42 DOS_movefileptr INT21/65/06 DOS_getcollatesequencetable
- INT21/44/09 DOS_isdriveremote INT21/67 DOS_sethandlecount
- INT21/44/0A DOS_isfileremote INT2F/10/00 DOS_isshareinstalled
- No other operating system calls are made. No BIOS calls are made.
- See: Specs_Languages
- ~Specs_Languages
- BULLET is compatible with most DOS compilers. The only requirements are that
- your compiler allow you to:
- 1. Call a library routine via a FAR call using PASCAL calling convention
- 2. Pass a far pointer (of the parameter pack) on the stack, by value
- 3. Supply far pointers to the various pack parameters
- 4. Be able to return an integer value from the FAR call
- (this is optional but recommended for the transaction-based routines)
- These requirements can be met with most BASIC, C, and other-language DOS
- compilers.
- CZ online help is currently available in BASIC and C versions. Others are
- pending. You should be able to do well with either of these versions using
- other-language compilers since the only difference is the source code examples.
- See: Specs_OSes
- ~Specs_OSes
- BULLET is currently available only for MS-DOS and compatible operating systems.
- It requires DOS 3.3 or higher.
- To provide efficient memory use, BULLET uses a single-buffer cache per index
- file. The single-buffer cache also provides for very quick network access since
- a minimum amount of memory needs to be flushed when releasing control of BULLET
- files. For maximum speed, however, an external high-performance disk cache can
- be used. Hyperdisk is a good choice (shareware, $50+). A properly configured
- cache can increase BULLET's performance from 10 to 300%. The most improvement
- is with the InsertXB routine. The least is with ReindexXB and PackRecordsXB,
- which do most of their work in temporarily allocated memory. Hyperdisk is about
- the best designed disk cache available for PCs.
- If you do not use a disk cache then it's recommended that you set your BUFFERS=
- statement in CONFIG.SYS to at least 20 or 30. Even without a disk cache, BULLET
- is still very fast. Also, be sure to set your FILES= to the number of files
- that you'll be opening at any one time. If you set FILES=20 you can have BULLET
- open 14 files (CZ.COM uses 1 and DOS reserves 5 more). You can set FILES=255
- allowing BULLET to open up to 249 files at one time.
- DO NOT set FILES= to a value greater than 255.
- See: Specs_Networks
- ~Specs_Networks
- BULLET currently operates on all DOS-compatible network platforms.
- Be sure to install SHARE.EXE on the local machine. If you'll be opening many
- files you should extended the default SHARE file-sharing information space and
- the number of locks that can performed at one time. The DOS 5.0 default is
- /F:2048 and /L:20. This allocates 2K for file-sharing info space and allows 20
- consecutive locks to be active. If the F: value is too low, error 5 (extended
- error 32) is returned on an open attempt. If you extend the JFT in InitXB and
- plan to use many files, say more than 50, be sure to extend /F: by 2K for every
- 50 additional files and set the /L: to the number of files you plan on having
- open. If L: is too low, error 1 (ext err 36) is returned on a lock attempt.
- As an example, if you'll be using 100 files, set FILES=106 in CONFIG.SYS, set
- SHARE /F:4096 /L:106, and IP.JFTmode=1 for InitXB. These values are a minimum.
- If you have more than one process active, you need to account for other
- applications' needs also.
- Note that Windows always returns a "SHARE is installed" using the DOS detection
- routines used by BULLET. To determine if SHARE is actually installed, attempt
- to perform a lock using one of the LockXB routines. An error code indicates
- that SHARE is not installed.
- See: Specs_Performance
- ~Specs_Performance
- Test: Reindex 1,000 to 1,000,000 records (BB_LAI10.BAS)
- DBF: extended DBF using binary sort field
- key: LONG+SIGNED+UNIQUE Machine: 486/33 SHO
- 1Meg
- *
-
-
- *
-
- Records Time Reindex Rate
-
- * ------- ---- ------------
- 100k
- * 1000 < 1 1000+/sec
-
- 5000 2 2500
-
- * 10000 4 2500
-
- * 25000 7 3571 3500+ records indexed/second!
-
- 50000 14 3571 Times in table are in seconds
- 10k
- * 100000 28 3571
-
- 200000 81 2469
-
- * 500000 355 1408
-
- 1000000 1124 890
- 1k
-
- time (secs) 100 200 300 400 18:00 20:00 (min)
- See: Specs_Perf_a -MORE-
- ~Specs_Perf_a
- Test: Add 1,000 to 1,000,000 records (BB_LAI10.BAS)
- DBF: extended DBF using binary sort field
- key: not indexed Machine: 486/33 SHO
- 1Meg
- *
-
-
- *
-
- * Records Time Add Rate
-
- ------- ---- ------------
- 100k
- * 1000 < 1 1000+/sec
-
- 5000 2 2500
-
- * 10000 4 2500
-
- * 25000 12 2083 2000+ records added/second!
-
- 50000 24 2083 Times in table are in seconds
- 10k
- * 100000 50 2000
-
- 200000 103 1942
-
- * 500000 262 1908
-
- 1000000 529 1890
- 1k
-
- time (secs) 100 200 300 400 8:00 10:00 (min)
- See: Specs_Perf_b -MORE-
- ~Specs_Perf_b
- Test: Access 1,000 to 1,000,000 keys(*), keys+records(+) (BB_LGK10.BAS)
- DBF: extended DBF using binary sort field
- key: LONG+SIGNED+UNIQUE Machine: 486/33 SHO
- 1Meg
- * +
-
-
- * +
-
- * + Keys Time Access Rate Keys+Recs Time Access Rate
-
- ------- ---- ----------- --------- ---- ------------
- 100k
- * + 1000 < 1 1000+/sec 1000 < 1 1000+/sec
-
- 10000 1 10000 10000 6 1667
-
- 100000 22 4545 100000 68 1471
-
- 200000 49 4082 200000 144 1389
-
- 500000 147 3401 500000 427 1171
- 10k
- *+ 1000000 424 2358 1000000 948 1055
-
-
- Times for forward/reverse (Next/Prev) were similar (
-
- + Times in table are in seconds
- 1k
-
- time (secs) 100 200 300 400 15:00 17:00 (min)
- See: Specs_Perf_c -MORE-
- ~Specs_Perf_c
- Test: Insert 1,000 random records to existing data/key files (BB_LAA10.BAS)
- DBF: extended DBF using binary sort field
- key: LONG+SIGNED+UNIQUE Machine: 486/33 SHO
- Base records/keys Inserted Time / Rate
- ----------------- -------- ---- ----
- 1000 1000 15 67 records+keys inserted/second
- 10000 1000 18 56 Times in table are in seconds
- 100000 1000 19 53
- 200000 1000 20 50
- This tests the InsertXB speed. A data file containing the base records and
- an index file containing the same number of keys has inserted into it 1000
- random keys and records. The records are added to the end of the data file
- and the keys are inserted into their appropriate place in the index file.
- Typically InsertXBs would be done online. The rate of 50 inserts/second at
- 200,000 records would indicate a time of 0.02 seconds per insert on even a
- very large database (0.015 secs/insert @ 1000 records).
- See: Specs_Perf_d -MORE-
- ~Specs_Perf_d
- Test: Update 1,000 records by changing the key field (BB_LAU10.BAS)
- DBF: extended DBF using binary sort field
- key: LONG+SIGNED+UNIQUE Machine: 486/33 SHO
- Base records/keys Updated Time / Rate
- ----------------- ------- ---- ----
- 1000 1000 50 20 records+keys updated/second
- 10000 1000 59 17 Times in table are in seconds
- 100000 1000 108 9
- 200000 1000 126 8
- This tests the UpdateXB speed. A data file containing the base records and
- an index file containing the same number of keys has the first 1000 keys and
- records changed. This forces the old data record to be replaced, the old index
- key to be deleted, and a new key for the record to be inserted in the index
- file.
- Typically UpdateXBs would be done online. The rate of 8 updates/second at
- 200,000 records would indicate a time of 0.125 seconds per update on even a
- very large database (0.05 secs/update @ 1000 records).
- See: Specs_Overall
- ~InitXB
- Pack: InitPack Src: InitXBsrc Func: 0/System
- Before using any routine you must initialize the BULLET file system.
- If you want more than the standard number of file handles, set InitPack.JFTmode
- to 1. This expands the current process's Job File Table to allow 255 open files
- maximum.
- On return the DOS version (INT21/30h) is in InitPack.DOSver. Major version in
- the high byte. Minor in the low. The BULLET version (*100) is returned as is
- the address of the ExitXB routine. You can use this address to register ExitXB
- with your own _atexit function if your runtime library does not provide _atexit
- already.
- Note: _atexit is a routine available in most DOS, OS/2, and ANSI runtime
- library code and is called just prior to the program ending. See AtExitXB for
- information on what to do if your library does not have _atexit.
- See: ExitXB
- ~ExitXB
- Pack: ExitPack Src: ExitXBsrc Func: 1/System
- Before ending your program you should call ExitXB to close any open BULLET
- files. This also will release any memory still allocated to those files.
- This restores the default keyboard break handlers if they were changed.
- In normal operation you would see to closing all files yourself. However, if
- your program fails to reach the programmed end, it's very possible that files
- may still be left open. It is essential that you properly close all BULLET
- files before ending. There are two methods to achieve this:
- 1. In BASIC use ON ERROR GOTO label, where label is in the main module. The
- code at label would then call ExitXB.
- 2. Use AtExitXB to automatically register ExitXB to be executed in the normal
- shut-down code of the compiler. This method is preferred.
- In the QB environment you can easily stop and restart the executing program
- without having reached the end of the program where you call ExitXB. Previously
- opened BULLET files remain open and memory used remains allocated. Eventually
- you will run out of files or out of memory. Use AtExitXB to prevent this.
- See: AtExitXB
- ~AtExitXB
- Pack: ExitPack Src: AtExitXBsrc Func: 2/System
- Used to automatically close all BULLET files, release allocated memory, and
- restore the default Break handlers when your program ends. Your compiler
- generates specific code to be executed in the course of ending your program.
- AtExitXB registers the ExitXB routine to be performed in this compiler-
- generated code.
- This routine is standard in most DOS, OS/2, and ANSI runtime libraries. If
- yours does not have _atexit, then you must link with the supplied
- NOATEXIT.OBJ file:
-
- C>link YOURPRG + NOATEXIT, ...
- You can tell if your compiler doesn't supply _atexit at link time. LINK reports
- '_atexit' : unresolved external. Add NOATEXIT.OBJ as described above.
- Be sure that your _atexit routine is for the medium, large, or huge memory
- models since BULLET uses multiple code segments and far calls.
- See: MemoryXB ExitXB BreakXB
- ~MemoryXB
- Pack: MemoryPack Src: MemoryXBsrc Func: 3/System
- This is the only BULLET routine that can be used before InitXB. It reports the
- largest free block of memory available from the OS. This memory does not
- include fragmented memory or UMB memory that BULLET can and will use.
- Some compilers provide their own memory management and thus will use most or
- all of the contiguous memory when its program loads. BULLET, however,
- allocates memory on an as-needed basis, directly from the OS, and releases it
- back to the OS as soon as it is no longer needed. If the memory amount
- returned by MemoryXB is low, your compiler's startup code has pre-allocated
- all OS memory. If the memory available from the OS is less than your
- application needs, you need to instruct your program to release some of the
- memory back to the OS so BULLET can use it. For QuickBASIC and BASIC PDS, see
- the BASIC function SETMEM().
- With DOS able to use UMB memory, memory for BULLET requests may be provided
- from this region. You can use StatPack.HereSeg from StatXB to locate from which
- segment address the allocations are being made. Anything above C800h is UMB.
- See: BreakXB StatXB OpenDXB OpenKXB
- ~BreakXB
- Pack: BreakPack Src: BreakXBsrc Func: 4/System
- Disables system response to Control-C and Control-Break keys preventing users
- from inadvertently exiting the program without first doing a BULLET shutdown.
- It's REQUIRED that you reinstate the default break handlers with this routine
- before ending your program. ExitXB automatically reinstates the default break
- handlers.
- This routine will not disable Control-Alt-Delete (a warm-boot). If the user is
- at this point, he may prefer to exit via a warm-boot rather than reset the
- machine.
- Also, this routine does not prevent QuickBASIC and BASIC PDS from terminating
- a program at an INPUT statement. This is because these versions of BASIC are
- using their own method of INPUT aside from DOS. If AtExitXB has been issued,
- all BULLET files will be properly closed even if *User Break* occurs.
- This routine will not surpress the ^C displayed by DOS. If you don't want the
- ^C to be displayed move the cursor to a location off-screen, say, row 26.
- See: BackupFileXB ExitXB
- ~BackupFileXB
- Pack: CopyPack Src: BackupFileXBsrc Func: 5/System
- Copy an open BULLET key or data file. BULLET repacks and reindexes files in-
- place, requiring less disk space to perform the function. BackupFileXB allows
- you to safely copy a file before doing this.
- This function is recommended prior to packing a data file with PackRecordsXB
- since the data is very valuable. There is probably little need to do so when
- reindexing an index file since index files can be constructed very easily
- from the data file.
- See: StatHandleXB PackRecordsXB ReindexXB
- ~StatHandleXB
- Pack: StatHandlePack Src: StatHandleXBsrc Func: 6/System
- Get information on a DOS file handle number to determine if it is a BULLET file
- and if so, if that file is a BULLET key or data file.
- If the returned ID value is 0, the handle is to a BULLET index file. ID=1 then
- the handle is a BULLET .DBF file. ID= -1 then the handle is not a BULLET file.
- See: CreateDXB StatDXB StatKXB
- ~GetExtErrorXB
- Pack: XErrorPack Src: GetExtErrorXBsrc Func: 7/System
- Get the extended error information for the last operation. This information
- includes the extended error code, the error class, the recommended action, and
- the location of the error. See Errors_DOS for the extended error meaning an
- Errors_DOS_c for the class, action, and locus code meanings.
- Note that on fatal DOS errors, such as an open floppy drive door, the extended
- error code returned is 83 - fail on INT24. This indicates that the INT24
- handler was invoked by DOS and that the INT24 handler told DOS to ignore the
- error. (BULLET invokes its own INT24 handler each time it accesses the DOS file
- system and restores it promptly after the access.) In such cases, this extended
- error code is less informative than the standard return code and, the other
- 'extended' information should be disregarded. (In fatal DOS errors the standard
- return code IS the extended error code.)
- This routine returns the extended error information for the LAST DOS system
- error. This information remains the same until the next DOS system error.
- See: CreateDXB Errors_DOS
- ~DVmonCXB
- Pack: DVmonPack Src: DVmonCXBsrc Func: 9/DEBUG
- Control BULLET debug monitor.
- This routine is available only in the debug engine.
- The monitor displays in realtime the state of a data file handle, or an index
- and data file handle pair if an index handle is specified. DVmonCXB is best
- used on dual-display systems in which the video output is sent to the secondary
- video monitor. In any case, a 4000-byte screen image is updated in real-time.
- To use the monitor, set mode=1, handle=file to monitor, and VideoSeg=segment
- address of 4000-byte area. The typical VideoSeg would be to video memory. If
- you have a color system as the main monitor and a mono as the secondary, set
- VideoSeg=&HB000. Detail system stats are continually updated to the secondary
- monitor. If you have a single monitor with at least 2 video pages, set VideoSeg
- to your base address plus the page size\16, typically &HB800+(4096\16). If you
- have only a single-page video system, you can allocate a 4000-byte memory area
- and update the video manually by moving it to your video display (80x25).
- See: CreateDXB StatDXB StatKXB
- ~CreateDXB
- Pack: CreateDataPack Src: CreateDXBsrc Func: 10/Mid-level
- Create a new BULLET .DBF data file. Before using this routine allocate a field
- description array of TYPE FieldDescTYPE for at least as many fields as are in
- the record.
- Conventional dBASE .DBF files have a FileID=3. Other possible FileIDs that you
- may come across are (in hex):
- 43h \__ are special-use Xbase IV DBF files, BULLET can process these file IDs
- 63h / since they are similar to ID type 3
- 83h --- this DBF file has an Xbase III/III+ memo field/file
- 88h --- this DBF file has an Xbase IV memo field/file
- In creating your .DBF files, specify FileID=3 to ensure compatibility across
- Xbase versions.
- BULLET makes no special use of the FileID byte.
- See: OpenDXB FieldDescTYPE CreateKXB
- ~OpenDXB
- Pack: OpenPack Src: OpenDXBsrc Func: 11/Mid-level
- Open an existing .DBF data file for use. You need to specify two things, the
- filename and the DOS file access mode. If the open succeeds, the DOS file
- handle is returned. Use this handle for all further access to this file.
- Each .DBF data file you open allocates 144+((1 + number of fields) * 32) bytes
- for internal use. This memory is not deallocated until you close the file with
- CloseDXB or execute ExitXB.
- You must open the data file before you can open (or create) any of its index
- files.
- See: CloseDXB OpenKXB
- ~CloseDXB
- Pack: HandlePack Src: CloseDXBsrc Func: 12/Mid-level
- Close an existing .DBF data file for use. Closing the file updates the file
- header and deallocates the memory used by this file.
- You MUST close all BULLET files before ending your program or file corruption
- may occur. To ensure that all files are closed in the event of an unscheduled
- program termination, use AtExitXB.
- See: StatDXB ExitXB CloseKXB
- ~StatDXB
- Pack: StatDataPack Src: StatDXBsrc Func: 13/Mid-level
- Get basic information on the BULLET .DBF data file handle specified.
- Information returned includes the number of records in the file, the record
- length, number of fields per record, and the date the file was last updated.
- Typically, your program will keep track of whether a particular handle belongs
- to a data file or a key file. In cases where this is not possible, call the
- StatHandleXB routine to determine what file type a handle is.
- Note that a just-created data file will have the LastUpdate date set to 0/0/0.
- See: ReadDHXB StatKXB StatHandleXB
- ~ReadDHXB
- Pack: HandlePack Src: ReadDHXBsrc Func: 14/Mid-level
- Reload the disk copy of the data header for the opened .DBF data file handle
- to the internal copy.
- In single-user, single-tasking systems this routine is not needed. However, in
- a multi-user or multi-tasking system it's possible, and desirable, for two or
- more programs to use the same data file. Consider this scenario: A data file
- has 100 records. Two programs access this data file, both opening it. Program 1
- locks the file, adds a new record, then flushes and unlocks the file. Program 1
- knows that there are now 101 records in the file. However, Program 2 is not
- aware of the changes that Program 1 made--it thinks that there are still 100
- records in the file. This out-of-sync situation is easily remedied by having
- Program 2 reload the data header from the file on disk.
- How does Program 2 know that it needs to reload the header? It doesn't. Instead
- BULLET uses a simple yet effective approach when dealing with such problems.
- Whenever your program locks a file, BULLET automatically reloads the header.
- Whenever you unlock a file, BULLET automatically flushes the header.
- See: FlushDHXB ReadKHXB LockXB
- ~FlushDHXB
- Pack: HandlePack Src: FlushDHXBsrc Func: 15/Mid-level
- Write the internal copy of the data header for the opened .DBF data file handle
- to disk. The actual write occurs only if the header has been changed.
- This is to ensure that the data header on disk matches exactly the data header
- that is being maintained by BULLET. Also, this routine updates the operating
- system's directory entry for this file.
- Assume the following: A data file with 100 records. Your program opens the data
- file and adds 1 record. Physically, there are 101 records on disk. However, the
- header image of the data file on disk still reads 100 records. This isn't a
- problem, BULLET uses its internal copy of the data header and the internal copy
- does read 101 records. BUT, if there were a system failure now, the disk image
- would not get updated. After the system restart, BULLET opens the file, reads
- the header and thinks that there are 100 records. You lost a record. Now, if
- after that add above, your program issued a FlushDHXB, the header on disk is
- refreshed with the internal copy, keeping the two in-sync. Also, the routine
- updates the DOS directory entry, keeping things neat there as well. Still, it
- doesn't come without cost: flushing will take additional time, therefore, you
- may elect to flush periodically, or whenever the system is idle.
- See: CopyDHXB ReadDHXB FlushKHXB LockXB
- ~CopyDHXB
- Pack: CopyPack Src: CopyDHXBsrc Func: 16/Mid-level
- Copy the .DBF file structure of an open data file to another DOS file.
- This routine makes it easy for you to duplicate the structure of an existing
- .DBF file without having to specify all the information needed by CreateDXB.
- The resultant .DBF will be exactly like the source, including number of fields
- and field descriptions. It will contain 0 records.
-
- See: ZapDHXB CopyKHXB
- ~ZapDHXB
- Pack: HandlePack Src: ZapDHXBsrc Func: 17/Mid-level
- Delete all records for a .DBF data file.
- This routine is similar to CopyDHXB except for one major difference: ALL DATA
- RECORDS IN THE *SOURCE* FILE ARE PHYSICALLY DELETED, so be *careful*.
- If you have a .DBF file with 100 records and use ZapDHXB on it, all 100 records
- will be physically deleted and the file truncated to 0 records. There is no
- return from this routine. All data is gone.
-
-
- * C A U T I O N *
-
-
- See: CreateKXB CopyDHXB ZapKHXB
- ~CreateKXB
- Pack: CreateKeyPack Src: CreateKXBsrc Func: 20/Mid-level
- Create a new BULLET key file. Before you can create a key file, you must first
- have opened (and have created if necessary) the BULLET .DBF data file that it
- is to index. (BULLET couples index and data files tightly.)
- To create the key file, you need to provide the key expression, key flags, .DBF
- file link handle, and optionally, the code page ID, country code, and collate
- table.
- Key Expression
- The key expression is an ASCII character string composed of the elements that
- are to make up this index file's key. The key can be composed of any or all of
- the fields in the .DBF data record or sub-strings within any of those fields.
- Two functions are supported in evaluating a key expression. These are SUBSTR()
- and UPPER(). SUBSTR() is similar to BASIC's MID$() in that it extracts part of
- a string starting at a particular position for x number of characters. UPPER()
- is similar to UCASE$() in that it converts all lower-case letters to their
- upper-case equivalent. Since BULLET supports NLS, UPPER() conversion is not
- required for proper sorting of mixed-case text strings.
- See: CreateKXB_a CreateDXB -MORE-
- ~CreateKXB_a
- All names used in the key expression must be a valid field name in the DBF data
- file. Some sample key expressions given that the .DBF has the following fields:
- Fields... Valid key expressions
-
- FNAME C 25 0 kx = "LNAME"
- LNAME C 25 0 kx = "LNAME+FNAME"
- SSN C 9 0 kx = "SUBSTR(LNAME,1,4)+SUBSTR(FNAME,1,1)+SUBSTR(SSN,6,4)
- DEPT N 5 0 kx = "UPPER(LNAME+FNAME)" (for non-NLS index files)
- : : kx = "DEPT+SSN" (N- + C-type is valid for non-binary keys)
- Key Flags
- The key expression is used in conjunction with the key flags to determine the
- type of key generated.
- First, if your index file is to disallow duplicate keys, add 1 to KeyFlag.
- If you have a key composed of a character field(s) or portions thereof, you
- specify a KeyFlag = 2. This instructs BULLET that the sort order is left-to-
- right (proper mixed-case sorting is available, see code page ID).
- See: CreateKXB_b -MORE-
- ~CreateKXB_b
- If you have a key composed of a numeric field(s) or portions thereof, you can
- also specify a KeyFlag = 2. This instructs BULLET to treat the numeric field
- as a regular character field for sorting. To ensure proper sorting, you must
- decimal-align the +numeric strings in the .DBF data field, i.e., right-justify
- the numeric strings (dBASE .DBF numeric strings are stored as ASCII strings).
- These non-binary numeric fields are just like character fields to BULLET.
- In addition, if you have a key composed of a SINGLE numeric field (fld type N)
- and the field is an integer (NO DECIMAL POINT), you can specify a KeyFlag of 16
- or 32. KeyFlag=16 is for a field known to be in word/integer range; KeyFlag=32
- if the field is known to be in LongInt range. These KeyFlag values instruct
- BULLET to sort the key as a 16/32-bit BINARY value. It also stores the key as a
- 16- or 32-bit value (only 2 or 4 bytes) in the index, eventhough the data field
- is in ASCII (keyflag=16 or 32).
- Although not dBASE compatible, you may use BINARY FIELDS in your data records.
- dBASE always has ASCII data in the data fields, even if the field is numeric.
- For example, an N type field of 8.2 is stored as an ASCII text string in the
- data record, say, a string like " 1100.55". If you want dBASE compatibility
- your field data must also be ASCII. However, if you can forgo this requirement,
- you can use binary values in the fields.
- See: CreateKXB_c -MORE-
- ~CreateKXB_c
- To do this you must specify a field type of "B" (actually, anything but a "N")
- and, IF IT IS TO BE USED AS A KEY FIELD, also set the 16- or 32-bit KeyFlag.
- Unique and signed may also be flagged. The field length for a "B" field type is
- 2 or 4. Make sure the key flags match (2 if cINTEGER, 4 if cLONG).
- If you specify a binary key flag (for either N or B field types), you must also
- specify whether the field is to be treated as a signed or unsigned value. If
- values less than 0 are possible, add to KeyFlag the hex number &H8000.
- KeyFlag = cUNIQUE + cCHAR 'unique character key (NLS sort)
- KeyFlag = cINTEGER + cUNIQUE 'unique unsigned integer (binary sort)
- KeyFlag = cUNIQUE + cSIGNED + cLONG 'unique signed long
- KeyFlag = cCHAR 'character key with duplicates allowed
- KeyFlag = cCHAR + cINTEGER 'THIS IS AN INVALID KEY FLAGS!
- KeyFlag = cLONG 'unsigned long (dups allowed)
- The following values are defined in BULLET.BI (and BULLET.H):
- cUNIQUE=1, cCHAR=2, cINTEGER=&H10, cLONG=&H20, cNLS=&H4000, cSIGNED=&H8000
- The NLS flag is assigned by BULLET. StatKXB is used to query KeyFlags.
- See: CreateKXB_d -MORE-
- ~CreateKXB_d
- The key expression you specify may be up to 136 characters, and evaluate out to
- 64 bytes (62 bytes if unique key is not specified). I.e, kx$ = "SUBSTR(..." can
- be up to 136 characters, and that the actual key built from this expression can
- be no longer that 64 bytes, or 62 if you did not specify UNIQUE. In general,
- shorter keys (the key itself, not the expression) offer better performance.
- DBF File Link Handle (XBlink)
- Since BULLET evaluates the key expression at CreateKXB, it must have access to
- the DBF file to verify that the key expression is valid. You must therefore
- supply CreateKXB with the OS file handle of the opened DBF data file.
- National Language Support (NLS)
- With DOS 3.3 and later, NLS is available. BULLET uses NLS to build the collate
- sequence table that it uses to ensure proper sorting of mixed-case keys as well
- as the sorting of foreign language alphabets. In order for BULLET to use the
- proper collate table, it must know what code page ID and coutry code to use.
- This table is made part of the index file so that all subsequent access to the
- index file maintains the original sort order, even if the MIS shop is moved to
- another location/computer system using another country code/code page.
- See: CreateKXB_e -MORE-
- ~CreateKXB_e
- Code Page ID
- To use the default code page ID of the computer in use, specify a code page ID
- of -1. This instructs BULLET to use the collate-sequence table as provided by
- MS-DOS running on the machine. You may also specify the code page ID for BULLET
- to use, but only if support for the code page ID is available on your machine.
- Look in your DOS manual under CUSTOMIZING FOR INTERNATIONAL USE for specific
- code page IDs and country codes. See also the COUNTRY and NLSFUNC commands.
- You may also specify a code page ID = 0 in which case no collate table is used.
- Country Code
- To use the default country code of the computer in use, specify a country code
- of -1. This instructs BULLET to use the collate-sequence table as provided by
- MS-DOS running on the machine. You may also specify the country code for BULLET
- to use, but only if support for the country code is available on your machine.
- Look in your DOS manual under CUSTOMIZING FOR INTERNATIONAL USE for specific
- code page IDs and country codes. See also the COUNTRY and NLSFUNC commands.
- You may also specify a country code = 0 in which case no collate table is used.
- Typically, you set CodePageID = -1, CoutryCode = -1 and CollatePtr = 0.
- See: CreateKXB_f -MORE-
- ~CreateKXB_f
- User-specified Collate Table
- If you are to use a MS-DOS supplied collate table (BOTH codepage ID and country
- codes are non-zero) then you do not need to specify a collate table--DOS will.
- The option to allow a user-specified collate table is to work around some DOS
- versions supplying incorrect collate tables. If you find that the DOS-supplied
- collate table is not valid (it's stored in the second sector of the file) for
- your country, you can supply the table to be used by pointing the CollatePtr
- variables to your in-memory version of a valid collate table. If you want to
- use the DOS-supplied collate table, you MUST set the CollatePtr variables = 0.
- Note: The collate table is a 256-byte table that contains the sort value of
- each character (0-255). For example, the first byte would be 0, second would
- be 1, and so on. Values for characters up to the lower-case letters (ASCII 97)
- are usually as you would expect: "A" has a value of 65. However, the lower-case
- letters have the same value as their upper-case counterparts: "a" also has a
- value of 65. BULLET uses this collate table to ensure proper sorting.
- If you specify EITHER code page ID OR country code = 0 then no collate table
- is used or built. Instead, sorting is done by standard ASCII sort. This is
- somewhat faster but less versatile. Use UPPER() for mixed-case sort if needed.
- See: OpenKXB CreateKXB
- ~OpenKXB
- Pack: OpenPack Src: OpenKXBsrc Func: 21/Mid-level
- Open an existing key file for use.
- Each key file that you open allocates 1264 bytes for internal use. This memory
- is not deallocated until you close the file with CloseKXB or execute ExitXB.
- You must open the data file before you can open its related index file
- because you must supply the handle of the data file that this index files
- indexes.
- See: CloseKXB OpenDXB
- ~CloseKXB
- Pack: HandlePack Src: CloseKXBsrc Func: 22/Mid-level
- Close an open key file. Closing the file updates the file header and
- deallocates the memory used by this file.
- You MUST close all BULLET files before ending your program or file corruption
- may occur. To ensure that all files are closed on the event of an unscheduled
- program termination, use AtExitXB.
- See: StatKXB ExitXB CloseDXB
- ~StatKXB
- Pack: StatKeyPack Src: StatKXBsrc Func: 23/Mid-level
- Get basic information on a BULLET key file handle specified. Information
- returned includes the number of keys in the file, the key length, the data file
- handle for this key, the last accessed record number of that data file, NLS
- information, and the key flags.
- Typically, your program will keep track of whether a particular handle belongs
- to a key file or a data file. In cases where this is not possible, call the
- StatHandleXB routine to determine what file type a handle is.
- See: ReadKHXB StatDXB StatHandleXB
- ~ReadKHXB
- Pack: HandlePack Src: ReadKHXBsrc Func: 24/Mid-level
- Reload the disk copy of the key header for the opened key file handle to the
- internal copy.
- In single-user, single-tasking systems this routine is not needed. However, in
- a multi-user or multi-tasking system it's possible, and desirable, for two or
- more programs to use the same data file. Consider this scenario: A key file has
- 100 keys. Two programs access this key file, both opening it. Program 1 locks
- the file, adds a new key, then flushes and unlocks the file. Program 1 knows
- that there are now 101 keys in the file. However, Program 2 is not aware of the
- changes that Program 1 made--it thinks that there are still 100 keys in the
- file. This out-of-sync situation is easily remedied by having Program 2 reload
- the key header from the file on disk.
- How does Program 2 know that it needs to reload the header? It doesn't. Instead
- BULLET uses a simple yet effective approach when dealing with such problems.
- Whenever your program locks a file, BULLET automatically reloads the header.
- Whenever you unlock a file, BULLET automatically flushes the header.
- See: FlushKHXB ReadDHXB FlushDHXB LockXB
- ~FlushKHXB
- Pack: HandlePack Src: FlushKHXBsrc Func: 25/Mid-level
- Write the internal copy of the key header for the opened key file handle to
- disk. The actual write occurs only if the header has been changed.
- This is to ensure that the key header on disk matches exactly the key header
- that is being maintained by BULLET. Also, this routine updates the operating
- system's directory entry for this file.
-
- Assume the following: A data file with 100 keys. Your program opens the key
- file and adds 1 key. Physically, there are 101 keys on disk. However, the
- header image of the data file on disk still reads 100 keys. This isn't a
- problem, BULLET uses its internal copy of the key header and the internal copy
- does read 101 keys. BUT, if there were a system failure now, the disk image
- would not get updated. After the system restart, BULLET opens the file, reads
- the header and thinks that there are 100 keys. You lost a key. Now, if after
- that add above, your program issued a FlushKHXB, the header on disk is
- refreshed with the internal copy, keeping the two in-sync. Also, the routine
- updates the DOS directory entry, keeping things neat there as well. Still, it
- doesn't come without cost: flushing will take additional time, therefore, you
- may elect to flush periodically, or whenever the system is idle.
- See: CopyKHXB ReadKHXB FlushDHXB LockXB
- ~CopyKHXB
- Pack: CopyPack Src: CopyKHXBsrc Func: 26/Mid-level
- Copy the key file structure of an open key file to another DOS file.
- This routine makes it easy for you to duplicate the structure of an existing
- key file without having to specify all the information needed by CreateKXB.
- The resultant key file will be exactly like the source, including key flags and
- key expression. It will contain 0 keys.
-
- See: ZapKHXB CopyKHXB
- ~ZapKHXB
- Pack: HandlePack Src: ZapKHXBsrc Func: 27/Mid-level
- Delete all keys for a key file.
- This routine is similar to CopyKHXB except for one major difference: ALL KEYS
- IN THE *SOURCE* FILE ARE PHYSICALLY DELETED, so be *careful*.
- If you have a key file with 100 keys and use ZapKHXB on it, all 100 keys will
- be physically deleted and the file truncated to 0 keys. There is no return from
- this routine. All data is gone.
-
-
- * C A U T I O N *
-
-
- See: GetDescriptorXB CopyKHXB ZapDHXB
- ~GetDescriptorXB
- Pack: DescriptorPack Src: GetDescriptorXBsrc Func: 30/Mid-level
- Get the field descriptor information for a field.
- You can specifiy either the fieldname or the field number (position of the
- field within the record where the first field is #1) to get info on.
- The field descriptor contains the following information:
- FIELDNAME 10 upper-case characters, A-Z and _ allowed, unused space is
- 0-filled and is 0-terminated (11 bytes, ASCII, byte 11 always=0)
- FIELDTYPE single ASCII character where C=character, N=numeric, D=date,
- L=logical, and M=memo field (1 byte, ASCII)
- FIELDLEN length of field: C=1-254, N=1-19, D=8 (yyyymmdd), L=1 (T/F/space),
- M=10, this is total field length (1 byte, binary)
- FIELDDC places right of decimal point if N field type, minimum if not 0 is
- 2, can be up to 6 or 8, non-N fields always 0 (1 byte, binary)
- See: GetRecordXB
- ~GetRecordXB
- Pack: AccessPack Src: GetRecordXBsrc Func: 31/Mid-level
- Get the physical record from the data file into a data buffer by record number.
- The data buffer is typically a TYPEd variable defined as the .DBF record itself
- is defined. For example, if the DBF record has 2 fields, LNAME and FNAME, then
- variable would be TYPEd as:
- TYPE RecBuffer
- tag AS STRING * 1 'the Xbase DBF delete flag (must be included)
- LastName AS STRING * 25 'same field length as the .DBF LNAME field
- FirstName AS STRING * 25 'same field length as the .DBF FNAME field
- END TYPE
- This method of accessing the data file does not use any indexing. Therefore, it
- typically is not used except for special purposes. The preferred method to
- access the data is by one of the keyed Get() routines.
- See: AddRecordXB GetEqualXB
- ~AddRecordXB
- Pack: AccessPack Src: AddRecordXBsrc Func: 32/Mid-level
- Append the record in the data buffer to the end of the DBF file.
- This method of adding a record does not involve any indexing. It is typically
- used to build a data file en masse and do the indexing after the entire .DBF
- file(s) has been built.
- If you have several thousand data records to be added at once, this method of
- building the DBF first and then using the ReindexXB routine is often faster
- than using the InsertXB routine for each record to add.
- The AddRecordXB is very fast. 400 recs/sec on an AT machine is typical. Over
- 2000 recs/sec can be added on a fast 486 machine--that's 120,000 records added
- per minute.
- The record number used is determined by BULLET and it is returned in AP.RecNo.
- See: UpdateRecordXB InsertXB ReindexXB
- ~UpdateRecordXB
- Pack: AccessPack Src: UpdateRecordXBsrc Func: 33/Mid-level
- Write the updated data record to the the physical record number.
- This method of writing the updated record must not be used if any field(s) in
- the record is used as a key field(s) and has been changed.
- This method of updating a record is very fast if you know that that update is
- not going to alter any field used as a key in any index file that uses it. You
- must, of course, first get the data record into the record buffer. Then you can
- change it and write the update out to disk with this routine.
- If you need to change a field(s) that is used as a key field or part of one,
- use the UpdateXB routine. UpdateXB not only dynamically updates all related
- index files if you change a key field, it also will undo any and all changes if
- an error occurs in the transaction.
- See: DeleteRecordXB GetRecordXB UpdateXB
- ~DeleteRecordXB
- Pack: AccessPack Src: DeleteRecordXBsrc Func: 34/Mid-level
- Tag the record at the physical record number as being deleted.
- This does not tag any in-memory copies of the record so be sure to mark any
- such copies as being deleted yourself.
- The first byte of every .DBF record is reserved for the delete tag. This tag
- is a space (ASCII 32) if the record is normal, or a * (ASCII 42) if it's marked
- as being deleted. This delete tag is a reserved field in the DBF record and as
- such is not defined as a formal field with a descriptor, etc. Make sure that
- you define your in-memory buffers to reserve the first byte for the delete tag.
- The Xbase DBF standard doesn't physically remove records marked as deleted from
- the data file. It doesn't mark them as available/reusable either. To physically
- remove records marked as deleted use PackRecordsXB.
- Records can be temporarily marked as deleted then recalled to normal status.
- The Key/Get routines (GetFirstXB, etc.) return the record number needed for
- this routine after each access in AP.RecNo.
- See: UndeleteRecordXB PackRecordsXB
- ~UndeleteRecordXB
- Pack: AccessPack Src: UndeleteRecordsrc Func: 35/Mid-level
- Tag the record at the physical record number as being normal (not deleted).
- This does not tag any in-memory copies of the record so be sure to mark any
- such copies as being normal yourself.
- The first byte of every .DBF record is reserved for the delete tag. This tag
- is a space (ASCII 32) if the record is normal, or a * (ASCII 42) if it's marked
- as being deleted. This delete tag is a reserved field in the DBF record and as
- such is not defined as a formal field with a descriptor, etc. Make sure that
- you define your in-memory buffers to reserve the first byte for the delete tag.
- The Xbase DBF standard does not physically remove records marked as deleted
- from the data file so you can "recall" then back to normal status as easily as
- you marked them deleted.
- See: PackRecordsXB DeleteRecordXB
- ~PackRecordsXB
- Pack: AccessPack Src: PackRecordsXBsrc Func: 36/Mid-level
- Rebuild the open DBF file by physically removing all records marked as deleted.
- Packing occurs in place using the existing file. It's recommended that you
- use BackupFileXB to copy the current DBF file before using this routine in
- case of a failure during the pack process.
- The newly packed file is truncated to reflect the current, actual size.
- If there are index files for this .DBF file, they MUST all be reindexed after
- the pack process by using ReindexXB.
- This routine dynamically allocates at least as many bytes as the length of
- the record. More if available.
- See: FirstKeyXB DeleteRecordXB BackupFileXB ReindexXB
- ~FirstKeyXB
- Pack: AccessPack Src: FirstKeyXBsrc Func: 40/Mid-level
- Retrieve the first key in index order from the index file.
- This routine does not access the .DBF file and so does not retrieve the data
- record. What it does do is locate the first key of the index, returning it,
- and also returning the record number within the .DBF that the key indexes.
- To retrieve the data record you can use the GetRecordXB routine. The preferred
- method, however, is to use the GetFirstXB.
- The key returned includes an enumerator if a non-unique index file is involved.
- The enumerator is a little-endian 16-bit value that serves to differentiate
- up to 65535 "identical", non-unique keys. It is attached to all keys of non-
- unique index files and occupies the last two bytes of the key.
- This routine is typically used to position the index file to the first key so
- as to allow forward in-order access to the keys by using NextKeyXB.
- See: EqualKeyXB GetFirstXB GetRecordXB
- ~EqualKeyXB
- Pack: AccessPack Src: EqualKeyXBsrc Func: 41/Mid-level
- Search for the exact key in the index file.
- This routine does not access the .DBF file and so does not retrieve the data
- record. What it does do is search for the key in the index, and if found,
- returns the record number within the .DBF that the key indexes. The key must
- be an exact match, including enumerator word if a non-unqiue index file.
- To retrieve the data record you can use the GetRecordXB routine. The preferred
- method, however, is to use the GetEqualXB.
- This routine will only find EXACT matches to the specified key (including the
- enumerator if applicable). However, even if the exact key is not found in the
- index file, the index file is positioned so that the next NextKeyXB retrieves
- the key that would have followed the unmatched specified key. For example,
- if the key to match was "KINGS" (a partial key in this case), EqualKeyXB would
- return a key not found error. If you were to now do a NextKeyXB, the next key
- would be returned, let's say it is "KINGSTON".
- See: NextKeyXB GetEqualXB GetRecordXB
- ~NextKeyXB
- Pack: AccessPack Src: NextKeyXBsrc Func: 42/Mid-level
- Retrieve the next key in index order from the index file.
- This routine does not access the .DBF file and so does not retrieve the data
- record. What it does do is retreive the next key of the index, returning it,
- and also returning the record number within the .DBF that the key indexes.
- To retrieve the data record you can use the GetRecordXB routine. The preferred
- method, however, is to use the GetNextXB.
- The key returned includes an enumerator if a non-unique index file is involved.
- This routine is typically called after the index file has first been positioned
- to a known key using either FirstKeyXB or EqualKeyXB, or after a previous
- NextKeyXB or even PrevKeyXB. What it basically does is get the key following
- the current key, and then make that key the new current key.
- See: PrevKeyXB GetNextXB GetRecordXB
- ~PrevKeyXB
- Pack: AccessPack Src: PrevKeyXBsrc Func: 43/Mid-level
- Retrieve the previous key in index order from the index file.
- This routine does not access the .DBF file and so does not retrieve the data
- record. What it does do is retreive the previous key of the index, returning
- it and also returning the record number within the .DBF that the key indexes.
- To retrieve the data record you can use the GetRecordXB routine. The preferred
- method, however, is to use the GetPrevXB.
- The key returned includes an enumerator if a non-unique index file is involved.
- This routine is typically called after the index file has first been positioned
- to a known key using either LastKeyXB or EqualKeyXB, or after a previous
- PrevKeyXB or even NextKeyXB. What it basically does is to get the key previous
- the current key, and then make that key the new current key.
- See: LastKeyXB GetPrevXB GetRecordXB
- ~LastKeyXB
- Pack: AccessPack Src: LastKeyXBsrc Func: 44/Mid-level
- Retrieve the last key in index order from the index file.
- This routine does not access the .DBF file and so does not retrieve the data
- record. What it does do is locate the last key of the index, returning it,
- and also returning the record number within the .DBF that the key indexes.
- To retrieve the data record you can use the GetRecordXB routine. The preferred
- method, however, is to use the GetLastXB.
- This routine is typically used to position the index file to the last key so as
- to allow reverse in-order access to the keys by using PrevKeyXB.
- See: StoreKeyXB GetLastXB GetRecordXB
- ~StoreKeyXB
- Pack: AccessPack Src: StoreKeyXBsrc Func: 45/Mid-level
- Insert the key into the index file in proper key order.
- This routine does not add the data record to the .DBF file. It only inserts
- the key and record number into the index file. Use InsertXB, instead.
- To do a complete data record and key insert, you could use AddRecordXB to add
- the data record to the .DBF, BuildKeyXB to construct the key, then StoreKeyXB
- to insert the key and record number information into the index file. If that
- key already exists and the file allows duplicate keys, you need to attach the
- proper enumerator word and retry StoreKeyXB.
- This is much too much to do. Instead, just use InsertXB. All these details
- including adding the data record and multi-key inserts are performed
- automatically with just the single call.
- See: DeleteKeyXB InsertXB
- ~DeleteKeyXB
- Pack: AccessPack Src: DeleteKeyXBsrc Func: 46/Mid-level
- Physically remove the specified key from the index file.
- This routine requires an EXACT key match for all bytes of the key, including
- the enumerator word if a non-unique index file is involved.
- This routine would seldom be used, typically, since deleted dBASE data records
- are only physically deleted during a PackRecordsXB and the index file is
- rebuilt afterward using ReindexXB.
- See: BuildKeyXB CurrentKeyXB
- ~BuildKeyXB
- Pack: AccessPack Src: BuildKeyXBsrc Func: 47/Mid-level
- Build the key for the specifed data record based on the key expression for the
- index file. If the index file is non-unique, a 0-value enumerator is attached.
- The enumerator is a little-endian 16-bit value that serves to differentiate
- up to 65535 "identical", non-unique keys. It is attached to all keys of non-
- unique index files and occupies the last two bytes of the key.
- This routine, like most of the mid-level routines, typically would not be used
- since the high-level access routines take care of this detail automatically.
- See: CurrentKeyXB StoreKeyXB
- ~CurrentKeyXB
- Pack: AccessPack Src: CurrentKeyXBsrc Func: 48/Mid-level
- Retrieve the current key value for the specified key file handle and also the
- data record number that it indexes.
- This routine is useful in that it retrieves on demand the actual key value of
- the last accessed key in the index file (and the data record number). Most
- often you don't need this information so it would be a waste of time and space
- for your program to explicitly track each current key for each index file that
- you have open.
- See: GetFirstXB ReindexXB DeleteKeyXB
- ~GetFirstXB
- Pack: AccessPack Src: GetFirstXBsrc Func: 60/High-level
- Retrieve the first indexed key and data record.
- The key returned includes an enumerator if a non-unique index file is involved.
- This routine is typically used to process a database in index order starting at
- the first ordered key (and its data record). After processing this first entry,
- subsequent in-order access of the database is achieved by using GetNextXB until
- the end of the database is reached.
- This routine, like all the high-level Get routines, fills in the AP.RecNo of
- the record accessed. In GetFirstXB's case, it fills AP.RecNo with the record
- number pointed to by the first key. Since this is so, the AP pack is primed for
- an UpdateXB after each high-level Get. Other methods to get the record number
- are to use CurrKeyXB or any of the Key routines (KeyFirstXB, etc.).
- See: GetEqualXB FirstKeyXB UpdateXB
- ~GetEqualXB
- Pack: AccessPack Src: GetEqualXBsrc Func: 61/High-level
- Search for the exact key in the index file and return its data record.
- This routine will only find EXACT matches to the specified key (including the
- enumerator if applicable). However, even if the exact key is not found in the
- index file, the index file is positioned so that the next GetNextXB retrieves
- the key that would have followed the unmatched specified key. For example,
- if the key to match was "KINGS" (a partial key in this case), GetEqualXB would
- return a key not found error. If you were to now do a GetNextXB, the next key
- and data record would be returned, let's say the key is "KINGSTON" and its data
- record is the data record for that key. Another GetNextXB would retrieve the
- key and record after that. (GetPrevXB can be used in this fashion too.)
- This routine, like all the high-level Get routines, fills in the AP.RecNo of
- the record accessed. In GetEqualXB's case, it fills AP.RecNo with the record
- number pointed to by the matched key. Since this is so, the AP pack is primed
- for an UpdateXB after each high-level Get. Other methods to get the record
- number are to use CurrKeyXB or any of the Key routines (KeyEqualXB, etc.).
- See: GetNextXB EqualKeyXB
- ~GetNextXB
- Pack: AccessPack Src: GetNextXBsrc Func: 62/High-level
- Retrieve the next indexed key and its data record.
- The key returned includes an enumerator if a non-unique index file is involved.
- This routine is typically calld after the index file has first been positioned
- to a known key using either GetFirstXB or GetEqualXB, or after a previous
- GetNextXB or even GetPrevXB. What it basically does is get the key and data
- record following the current key, and then make that key the new current key.
- This routine, like all the high-level Get routines, fills in the AP.RecNo of
- the record accessed. In GetNextXB's case, it fills AP.RecNo with the record
- number pointed to by the next key. Since this is so, the AP pack is primed for
- an UpdateXB after each high-level Get. Other methods to get the record number
- are to use CurrKeyXB or any of the Key routines (KeyNextXB, etc.).
- See: GetPrevXB NextKeyXB
- ~GetPrevXB
- Pack: AccessPack Src: GetPrevXBsrc Func: 63/High-level
- Retrieve the previous indexed key and record.
- The key returned includes an enumerator if a non-unique index file is involved.
- This routine is typically called after the index file has first been positioned
- to a known key using either GetLastXB or GetEqualXB, or after a previous
- GetPrevXB or even GetNextXB. What it basically does is to get the key and data
- record previous the current key, and then make that key the new current key.
- This routine, like all the high-level Get routines, fills in the AP.RecNo of
- the record accessed. In GetPrevXB's case, it fills AP.RecNo with the record
- number pointed to by the previous key. Since this is so, the AP pack is primed
- for an UpdateXB after each high-level Get. Other methods to get the record
- number are to use CurrKeyXB or any of the Key routines (KeyPrevXB, etc.).
- See: GetLastXB PrevKeyXB
- ~GetLastXB
- Pack: AccessPack Src: GetLastXBsrc Func: 64/High-level
- Retrieve the last indexed key and record.
- This routine is typically used to process a database in reverse index order
- starting at the last ordered key (and its data record). After processing this
- last entry, subsequent reverse-order access of the database is achieved by
- using GetPrevXB until the top of the database is reached.
- This routine, like all the high-level Get routines, fills in the AP.RecNo of
- the record accessed. In GetLastXB's case, it fills AP.RecNo with the record
- number pointed to by the last key. Since this is so, the AP pack is primed for
- an UpdateXB after each high-level Get. Other methods to get the record number
- are to use CurrKeyXB or any of the Key routines (KeyLastXB, etc.).
- See: InsertXB LastKeyXB
- ~InsertXB
- Pack: AccessPack Src: InsertXBsrc Func: 65/High-level
- Add the data record to data file and insert the related key(s) into the linked
- index file(s).
- This routine is used to add new entries into a database, one at a time. The
- data record is first added to the data file, then for each related index file,
- a key is inserted into the appropriate index file. Up to 32 index files can be
- automatically maintained for each data file.
- This and several other routines are transaction-based. If a failure occurs
- prior to the routine's completion, all changes made to the database by the
- routine will be backed-out and the database (data and related index file(s))
- effectively restored to its original state.
-
- If the routine failed to complete, the function return value is the number of
- the pack that caused the failure. The pack's Stat is checked to determine the
- error code. If the function return value is 0, YOU MUST STILL check the first
- pack's Stat. If it's non-zero, then the failure occured with the data record.
- See: UpdateXB StoreKeyXB
- ~UpdateXB
- Pack: AccessPack Src: UpdateXBsrc Func: 66/High-level
- Modify an existing data record (identified by record number) and automatically
- perform any index file updates needed to keep the index file(s) in sync.
- If any key fields changed between the original record and the new one, this
- routine updates the appropriate index file(s) by replacing the original key(s)
- with new the key(s) based on the updated data record. Up to 32 index files can
- be automatically maintained for each data file. Get routines (GetFirstXB, etc.)
- set the AP.RecNo of the record that UpdateXB uses.
- This and several other routines are transaction-based. If a failure occurs
- prior to the routine's completion, all changes made to the database by the
- routine will be backed-out and the database (data and related index file(s))
- effectively restored to its original state.
- If the routine failed to complete, the function return value is the number of
- the pack that caused the failure. The pack's Stat is checked to determine the
- error code. If the function return value is 0, YOU MUST STILL check the first
- pack's Stat. If it's non-zero, then the failure occured with the data record.
- See: ReindexXB UpdateRecordXB
- ~ReindexXB
- Pack: AccessPack Src: ReindexXBsrc Func: 67/High-level
- Reindex all related index files for a data file.
- The index file(s) must already exist and be open. Any existing key data is
- overwritten by the new key data. In other words, if you have a 10MByte index
- file, ReindexXB uses the same file space building the news keys over the old.
- This results in a less fragmented disk and also minimizes disk space needed.
- You can also create a new, empty index file and reindex to that. This would be
- useful, for instance, if you needed to create a temporary index file--something
- that you'd use for a report, say, then delete after the report.
- This routine creates a TEMPORARY work file in either the current directory or,
- if the DOS environment variable TMP is defined, in the TMP= directory. The size
- of this file is approx. bytes = (RECORDS * (KEYLEN+6)). ReindexXB can operate
- in as little as 32K of available memory and can use up to 128K. The resultant
- index file(s) are optimized for minimum size AND maximum retrieval speed.
- If the routine failed to complete, the function return value is the number of
- the pack that caused the failure. The pack's Stat is checked to determine the
- error code. A return value of zero indicates no error occured.
- See: LockXB PackRecordsXB
- ~LockXB
- Pack: AccessPack Src: LockXBsrc Func: 80/Network
- Lock all bytes in the index file handle(s) for exclusive use by the current
- process and reload the index file header(s) from disk. Also lock all bytes in
- the related data file and reload the data file header from disk.
- The files must have been opened with the appropriate share attribute and not
- in compatibility mode. SHARE.EXE MUST be installed or DOS error 1 is issued.
- This routine is transaction-based and will lock all index files specified in
- AccessPack and the data file. If any lock fails, all previous locks by this
- routine are released. The return value indicates which access pack failed, if
- any. This value is used as the index into the AccessPack group for you to
- identify the error code. See LockXBsrc for determining this exactly.
- Use the DriveRemoteXB and/or FileRemoteXB to determine if locking is necessary.
- If the files are on a remote drive then it is best to use locking. Locking may
- also be necessary on multitasking local machines accessing shared files.
- This routine is a combination of LockKeyXB and LockDataXB.
- See: UnlockXB LockKeyXB LockDataXB DriveRemoteXB FileRemoteXB
- ~UnlockXB
- Pack: AccessPack Src: UnlockXBsrc Func: 81/Network
- Unlock all bytes in the specified file handle(s) (previously locked) and flush
- the file header(s) to disk (flush done before lock(s) released). Also unlock
- all bytes in the related data file and flush the data file header to disk.
- The files must have been opened with the appropriate share attribute and not
- in compatibility mode. SHARE.EXE MUST be installed or DOS error 1 is issued.
- This routine is transaction-based and will unlock all index files specified in
- AccessPack and the data file. If an unlock fails the routine exits with a
- return value indicating which access pack failed. This value is used as the
- index into the AccessPack group for you to identify the error code. Note that
- this routine does not attempt to re-lock those files unlocked successfully if
- an error occurs in the transaction. If an error does occur (unlikely) you will
- need to provide for unlocking the remaining files manually with the UnlockKeyXB
- and UnlockDataXB routines. You should not rely on the operating system to
- automatically unlock files when they're closed.
- This routine is a combination of UnlockKeyXB and UnlockDataXB.
- See: LockKeyXB UnlockKeyXB UnlockDataXB
- ~LockKeyXB
- Pack: AccessPack Src: LockKeyXBsrc Func: 82/Network
- Lock all bytes in the index file handle(s) for exclusive use by the current
- process and reload the index file header(s) from disk.
- The files must have been opened with the appropriate share attribute and not
- in compatibility mode. SHARE.EXE MUST be installed or DOS error 1 is issued.
- This routine is transaction-based and will lock all index files specified in
- AccessPack. If any lock fails, all previous locks by this routine are released.
- The return value indicates which access pack failed, if any. This value is used
- as the index into the AccessPack group for you to identify the error code.
- The advantage of using region locks (LockKeyXB locks the entire file region) to
- control file access is that the file does not need to be opened/closed using
- the Deny Read/Write sharing attribute. Opening the file for Deny None, and
- controlling subsequent access with region locks, allows for faster processing
- since files do not need to be constantly opened and closed, as they would if
- access were controlled by opening with Deny Read/Write.
- See: UnlockKeyXB LockXB
- ~UnlockKeyXB
- Pack: AccessPack Src: UnlockKeyXBsrc Func: 83/Network
- Unlock all bytes in the specified file handle(s) (previously locked) and flush
- the file header(s) to disk (flush done before lock(s) released).
- The files must have been opened with the appropriate share attribute and not
- in compatibility mode. SHARE.EXE MUST be installed or DOS error 1 is issued.
- This routine is transaction-based and will unlock all index files specified in
- AccessPack. If an unlock fails the routine exits with a return value indicating
- which access pack failed. This value is used as the index into the AccessPack
- group for you to identify the error code.
- All file locks should be released when exclusive access in no longer needed.
- It is not recommended that you end your program without having released active
- file locks. This is especially a valid concern for DOS versions prior to 5.0.
- DOS 5 releases locks on files that are closed.
- See: LockDataXB UnlockXB
- ~LockDataXB
- Pack: AccessPack Src: LockDataXBsrc Func: 84/Network
- Lock all bytes in the file handle's data file for exclusive use by the current
- process and reload the data file header from disk. You must set AP.RecNo=0 to
- do this. To lock a single record, set AP.RecNo=record# to lock.
- The files must have been opened with the appropriate share attribute and not
- in compatibility mode. SHARE.EXE MUST be installed or DOS error 1 is issued.
- This routine locks the specified data file. If the handle specified is that of
- an index file, that index file's related data file handle is used. For single-
- record locks, AP.Handle must have a data file handle specified. Header loading
- is not performed if locking a single record.
- The advantage of using region locks (LockDataXB locks the entire file region)
- to control file access is that the file does not need to be opened/closed using
- the Deny Read/Write sharing attribute. Opening the file for Deny None, and
- controlling subsequent access with region locks, allows for faster processing
- since files do not need to be constantly opened and closed, as they would if
- access were controlled by opening with Deny Read/Write.
- See: UnlockDataXB
- ~UnlockDataXB
- Pack: AccessPack Src: UnlockDataXBsrc Func: 85/Network
- Unlock all bytes in the specified file handle (previously locked) and flush the
- data file header to disk (flush done before lock released). To do this you must
- set AP.RecNo=0. To unlock a single record, set AP.RecNo=record# to unlock.
- The files must have been opened with the appropriate share attribute and not
- in compatibility mode. SHARE.EXE MUST be installed or DOS error 1 is issued.
- This routine unlocks the specified data file. If the handle specified is that
- of an index file that index file's related datafile handle is used. For single-
- record unlocks, AP.Handle must have a data file handle specified. Flushing is
- not performed if unlocking a single record.
- All file locks should be released when exclusive access in no longer needed.
- It is not recommended that you end your program without having released active
- file locks. This is especially a valid concern for DOS versions prior to 5.0.
- DOS 5 releases locks on files that are closed.
- See: DriveRemoteXB
- ~DriveRemoteXB
- Pack: RemotePack Src: DriveRemoteXBsrc Func: 86/Network
- Determine if specified drive is remote (default drive=0, A:=1, B=2, C=3...).
- This routine uses INT21/44/sub function 09.
- In addition to returning the IsRemote state, this routine sends back the result
- of the DX register and also the install state of SHARE.EXE.
- The meaning of the bitflags in Flags are (where IsRemote=0):
- Bit Meaning drive...
- 1 1=uses 32-bit sectoring
- 6 1=accepts Generic IOCTL (for INT21/44/0D,0E,0Fh)
- 7 1=accepts Query IOCTL Device (INT21/44/11h)
- 9 1=is local but shared by other computers in the network
- 11 1=accepts Does-Device-Use-Removable-Media (INT21/44/08)
- 13 1=requires media descriptor in FAT
- 14 1=accepts Receive/Send Control Data from Block Device (INT21/44/04,05)
- 15 1=is Substitution drive (set by the DOS SUBST command)
- (all other bits=0)
- See: FileRemoteXB LockXB
- ~FileRemoteXB
- Pack: RemotePack Src: FileRemoteXBsrc Func: 87/Network
- Determine if specified handle of file or device is remote.
- This routine uses INT21/44/sub function 0Ah.
- In addition to returning the IsRemote state, this routine sends back the result
- of the DX register and also the install state of SHARE.EXE.
- Flags bit 7=1 then handle is device, =0 then handle is file.
- Bit Meaning DEVICE... Bit Meaning DEVICE...(cont)
- 0 1=is console input device 13 1=is named pipe
- 1 1=is console output device 15 1=is remote, 0=is local
- 2 1=is null device (all other bits=0)
- 3 1=is clock device Bit Meaning FILE...
- 4 1=is special device 0-5 xxxxxx=drive number (0=A...)
- 5 1=is in binary mode, 0=in ASCII 6 1=has not been written to
- 6 0=returns EOF if device is read 12 1=is NoInherit
- 11 1=is network spooler 14 1=date/time not set at close
- 12 1=is NoInherit 15 1=is remote, 0=is local
- (all other bits=0)
- See: SetRetriesXB DriveRemoteXB LockXB
- ~SetRetriesXB
- Pack: SetRetriesPack Src: SetRetriesXBsrc Func: 88/Network
- Set the number of times DOS retries disk operations after a failure due to
- file-sharing operations (locked file regions from LockXB routines).
- This routine uses INT21/44/sub function 0Bh.
- By default DOS retries an operation 3 times (without pausing between attempts)
- before returning an error to the application.
- If you change the default values it's recommended that the default state be
- restored before your application ends (Retries=3, Pause=1).
- These values are pretty much determined by trial-and-error. You may find that
- adding a delay between retries returns fewer access-denied errors.
- See: DeleteFileDOS LockXB
- ~DeleteFileDOS
- Pack: DOSFilePack Src: DeleteFileDOSsrc Func: 100/DOS
- Delete the specified file.
- This routine uses DOS INT21/41 (interrupt 21h function 41h).
- See: RenameFileDOS
- ~RenameFileDOS
- Pack: DOSFilePack Src: RenameFileDOSsrc Func: 101/DOS
- Rename a file. May also be used to move the file to a new directory within the
- partition.
- This routine uses DOS INT21/56.
- If the specified directory differs from the file's directory, the file's
- directory entry is moved to the new directory.
- For example, if the FilenamePtr filename is C:\LP100\PROJ93A.INF and the
- NewFilenamePtr filename is C:\ARCH\PROJ93A.INA, the file is essentially
- renamed and also moved to the \ARCH directory.
- See: CreateFileDOS
- ~CreateFileDOS
- Pack: DOSFilePack Src: CreateFileDOSsrc Func: 102/DOS
- Create a new file.
- This routine uses INT21/3C.
- The specified filename/pathname must NOT already exist.
- The file created is not left open. You must OpenFileDOS to use it.
- The attribute used during the create can be:
- ATTRIBUTE VALUE MEANING
- Normal 0 normal access permitted to file
- Read-Only 1 read-only access permitted to file
- Hidden 2 file does not appear in directory listing
- System 4 file is a system file
- Volume 8 FILENAME used as volume label if no current label
- Archive 20h file is marked for archiving
- See: AccessFileDOS OpenFileDOS
- ~AccessFileDOS
- Pack: DOSFilePack Src: AccessFileDOSsrc Func: 103/DOS
- Determine if the specified file can be accessed with the specified
- access/sharing mode.
- This routine uses INT21/3D and INT21/3E.
- Basically, a Does-File-Exist routine. It uses the specified access/sharing
- attributes when trying to open the file. For example, if you specify
- DFP.Attr = &H42 (R/W access + Deny None sharing) and use AccessFileDOS on a
- Read-Only DOS file, the return value would be DOS error 5, Access Denied.
- See: OpenFileDOS
- ~OpenFileDOS
- Pack: DOSFilePack Src: OpenFileDOSsrc Func: 104/DOS
- Open the specified file with the specified access/sharing mode.
- This routine uses INT21/3D.
- ACCESS VALUE MEANING
- Read-only 0 open for read-only access
- Write-only 1 open for write-only access
- Read/Write 2 open for read/write access
- SHARE
- Compatibility 0 any process may share file (not recommended)
- Deny Read/Write 10h no other process may share file
- Deny Write 20h no other process may share file for write
- Deny Read 30h no other process may share file for read
- Deny None 40h any process may share file except in Compatibilty
- INHERIT mode
- NoInheritFlag 80h if set child processes do not inherit file handles
- (child process cannot inherit handle > 20)
- The file access mode is a combination of ACCESS + SHARE + INHERIT.
- See: SeekFileDOS OpenPack
- ~SeekFileDOS
- Pack: DOSFilePack Src: SeekFileDOSsrc Func: 105/DOS
- Position the DOS file pointer of the specified file to the specified position.
- This routine uses INT21/42.
- The position is a 32-bit value and is relative to either the start of the file,
- the current file pointer position, or the end of the file.
- Method Meaning
- 0 start move from the start of file (offset is a 32-bit unsigned value)
- 1 start move at the current position (offset a signed value)
- 2 start move at the end of file (offset a signed value)
- For example, to move to the 511th byte of a file (byte 0 being the first), set
- the offset value to 511 and use Method 0. On return, the absolute offset value
- of the new position is returned. This is useful with Method 2 since you can
- specify an offset of 0 and have the file length returned.
- Never position the file pointer to before the start of file.
- See: ReadFileDOS
- ~ReadFileDOS
- Pack: DOSFilePack Src: ReadFileDOSsrc Func: 106/DOS
- Read from the file or device the specified number of bytes into a buffer.
- This routine uses INT21/3F.
- On block devices (such as disks) input starts at the current file position and
- the file pointer is repositioned to the last byte read +1.
- It is possible to read less than the bytes specified without an error being
- generated. Compare the bytes to read with the returned bytes read value. If
- less then end of file was reached during the read, if 0 then file was at EOF.
- By using DOS's predefined handles you can read from the keyboard (STDIN) by
- using the STDIN handle, 0. The input will terminate after all specified bytes
- have been read or after a CR (ASCII 0Dh). If more bytes are entered than were
- requested, the next read will retrieve those excess bytes. Therefore, it's
- suggested that you specify 129 bytes to input (DOS will process 127+CR/LF bytes
- maximum when reading the STDIN device). Post-process the entered data by
- scanning for the CR/LF.
- See: ExpandFileDOS
- ~ExpandFileDOS
- Pack: DOSFilePack Src: ExpandFileDOSsrc Func: 107/DOS
- Expands the specified file by the specified number of bytes.
- This routine uses INT21/42 and INT21/40.
- This routine is useful in pre-allocating disk space. By reserving disk space in
- advance you can guarantee that enough disk space will be available for a future
- operation (especially if more than 1 process is running). You'll also be able
- ensure that the disk space that a file does use is as contiguous as possible.
- Database systems are dynamic and their files typically allocate new space on
- an as-needed basis. This dynamic allocation can cause parts of a file to be
- located throughout the disk system, possibly affecting performance drastically.
- By pre-allocating the disk space you can be assured of consistent throughput
- performance since the file is contiguous.
- See: WriteFileDOS
- ~WriteFileDOS
- Pack: DOSFilePack Src: WriteFileDOSsrc Func: 108/DOS
- Write to the file or device the specified number of bytes from a buffer.
- This routine uses INT21/40.
- If the number of bytes written is less than the specified bytes, this routine
- returns a -2 error code (or 65554 unsigned).
- On block devices (such as disk) output starts at the current file position, and
- the file pointer is repositioned to the last byte written +1.
- If the specified bytes to write is 0, the file is truncated at the current
- file pointer position.
- By using DOS's predefined handles you can write to the screen (STDOUT) by
- using the STDOUT handle, 1.
- See: CloseFileDOS
- ~CloseFileDOS
- Pack: DOSFilePack Src: CloseFileDOSsrc Func: 109/DOS
- Close the file flushing any internal buffers, releasing any locked regions, and
- update the directory entry to the correct size, date, and time.
- This routine uses INT21/3E.
- If you have opened a file using the DOS open routine you should close it when
- you no longer need it.
- This routine can be used to close the predefined DOS handles (0-4) and make
- those handles available for reuse. Typically handles 0 and 1 should not be
- closed by an application since they are the STDIN and STDOUT that DOS uses
- for the current application (keyboard and screen).
- Since BULLET provides for up to 250 user file handles for your applications it
- isn't necessary for you to eek 3 more file handles by closing handles 2-4.
- See: MakeDirDOS
- ~MakeDirDOS
- Pack: DOSFilePack Src: MakeDirDOSsrc Func: 110/DOS
- Create a new subdirectory.
- This routine uses INT21/39.
- See: DeleteFileDOS
- ~AccessPack
- Src: InsertXBsrc Func: InsertXB and many more
- TYPE AccessPack 'AP (AP is recommended pack name for DIM, AP.Func=)
- Func AS INTEGER 'varies
- Stat AS INTEGER 'ret:completion status
- Handle AS INTEGER 'OS handle
- RecNo AS LONG ' in:rec number to get/delete/update (if applicable)
- ' in:set to single rec# to lock or set to 0 to lock all
- 'ret:record number of data record accessed
- RecPtrOff AS INTEGER 'far pointer to record storage buffer
- RecPtrSeg AS INTEGER
- KeyPtrOff AS INTEGER 'far pointer to search key buffer
- KeyPtrSeg AS INTEGER
- NextPtrOff AS INTEGER 'far pointer to next key access pack
- NextPtrSeg AS INTEGER 'or 0:0 if end of link or if N/A
- END TYPE '22
- The NextPtr variables are only used by InsertXB, UpdateXB, ReindexXB, and the
- LockXB routines. NextPtr is used as a link to the next related access pack,
- if any. Not all entries are used by all routines. Generally, any routine that
- gets/puts user data to the database uses this pack.
- See: BreakPack
- ~BreakPack
- Src: BreakXBsrc Func: BreakXB
- TYPE BreakPack 'BP
- Func AS INTEGER '4
- Stat AS INTEGER 'ret:completion status
- Mode AS INTEGER '=0 disable Ctrl-C/Ctrl-Break, 1=restore
- END TYPE '6 bytes
- A simple pack.
- See: CopyPack
- ~CopyPack
- Src: BackupFileXBsrc Func: BackupFileXB, CopyDHXB, CopyKHXB
- TYPE CopyPack 'CP
- Func AS INTEGER '5=BackupFileXB,16=CopyDHXB,26=CopyKHXB
- Stat AS INTEGER 'ret:completion status
- Handle AS INTEGER 'handle of BULLET file
- FilenamePtrOff AS INTEGER 'far pointer to filenameZ
- FilenamePtrSeg AS INTEGER '(filename must end with a CHR$(0)))
- END TYPE '10
- See: CreateDataPack
- ~CreateDataPack
- Src: CreateDXBsrc Func: CreateDXB
- TYPE CreateDataPackTYPE 'CDP
- Func AS INTEGER '10
- Stat AS INTEGER 'ret:completion status
- FilenamePtrOff AS INTEGER 'far pointer to filenameZ to create
- FilenamePtrSeg AS INTEGER '(filename must end with a CHR$(0))
- NoFields AS INTEGER 'number of fields per record
- FieldListPtrOff AS INTEGER 'far pointer to field list
- FieldListPtrSeg AS INTEGER '(field list is of type FieldDescTYPE )
- FileID AS INTEGER 'file signature byte, usually=3
- END TYPE '16
- The filename pointed at by the FilenamePtr variables should be a fixed-length
- string (e.g., FILEN AS STRING * 80) so that VARSEG/VARPTR can be used to get
- its memory address. The filename must end with a CHR$(0) immediately following
- the last character of the filename: FILEN = YourFilename$ + CHR$(0).
- The FieldListPtr variables point to an array of type FieldDescTYPE. This array
- is dimensioned for as many fields as there are in the record and contains the
- field descriptors, one for each field.
- See: CreateKeyPack FieldDescTYPE
- ~CreateKeyPack
- Src: CreateKXBsrc Func: CreateKXB
- TYPE CreateKeyPack 'CKP
- Func AS INTEGER '20
- Stat AS INTEGER 'ret:completion status
- FilenamePtrOff AS INTEGER 'far pointer to filenameZ
- FilenamePtrSeg AS INTEGER '(filename must end with a CHR$(0))
- KeyExpPtrOff AS INTEGER 'far pointer to key expressionZ
- KeyExpPtrSeg AS INTEGER '(key expression must end with a CHR$(0))
- XBlink AS INTEGER 'BULLET XB data file handle this key file indexes
- KeyFlags AS INTEGER 'bit 0=unique,1=char,4=int,5=long,(E=NLS),F=signed
- CodePageID AS INTEGER 'code page ID for NLS, -1 to use system default
- CountryCode AS INTEGER 'country code number for NLS, -1 to use default
- CollatePtrOff AS INTEGER 'far pointer to programmer-supplied collate table
- CollatePtrSeg AS INTEGER 'or 0:0 if using system-determined NLS table
- END TYPE '24
- Bit 14 in KeyFlags (0Eh) is set by BULLET during CreateKXB if a collate table
- is present.
- See: DescriptorPack is_NLS
- ~DescriptorPack
- Src: GetDescriptorXBsrc Func: GetDescriptorXB
- TYPE DescriptorPack 'DP
- Func AS INTEGER '30
- Stat AS INTEGER 'ret:completion status
- Handle AS INTEGER 'BULLET data file handle to get information on
- FieldNumber AS INTEGER 'field number to get info on, or if 0 then...
- FD AS FieldDescTYPE '...search for DP.FD.FieldName
- END TYPE '40
- GetDescriptorXB allows you to get the field descriptor info for a particular
- field number (as in the first field, or the 10th field, etc.) or, if you don't
- know the physical field number, the routine can also get the info for a field
- by field name.
- To get the info for field number, say 5, set DP.FieldNumber = 5. The DP.FD
- structure element is filled in with field 5's information.
- To get the info for a field by fieldname, say LASTNAME, set DP.FieldNumber=0 &
- DP.FD.FieldName = "LASTNAME" + STRING$(11,0)--the fieldname must be zero-filled
- and zero-terminated--adding 11 ASCII zeroes ensures this requirement.
- See: DOSFilePack FieldDescTYPE
- ~DOSFilePack
- Src: AccessFileDOSsrc Func: AccessFileDOS
- (all routines ending with DOS)
- TYPE DOSFilePack 'DFP
- Func AS INTEGER 'varies, see DeleteFileDOS for first of DOS routines
- Stat AS INTEGER 'ret:completion status
- FilenamePtrOff AS INTEGER 'far pointer to filenameZ
- FilenamePtrSeg AS INTEGER '(filename must end with a CHR$(0))
- Handle AS INTEGER 'in: handle to access ret: handle opened
- ASmode AS INTEGER 'open access/sharing mode
- Bytes AS INTEGER 'in: bytes to read ret: bytes read
- SeekOffset AS LONG 'seek to file position
- Method AS INTEGER 'seek method
- BufferPtrOff AS INTEGER 'far pointer to read/write buffer
- BufferPtrSeg AS INTEGER
- Attr AS INTEGER 'file create directory entry attribute
- NewNamePtrOff AS INTEGER 'far pointer to new filenameZ for rename
- NewNamePtrSeg AS INTEGER '(filename must end with a CHR$(0))
- END TYPE '30
- All of the xDOS routines use this pack. Often only a few of the structure
- elements are used by any one of the routines. Set only those needed.
- See: DVmonPack
- ~DVmonPack
- Src: DVmonCXBsrc Func: DVmonCXB
- TYPE DVmonPackTYPE 'THIS ROUTINE IS AVAILABLE ONLY IN THE DEBUG ENGINE
- Func AS INTEGER '9
- Stat AS INTEGER 'ret:completion status
- Mode AS INTEGER '=0 disable montitoring, =1 enable
- Handle AS INTEGER 'file handle to monitor
- VideoSeg AS INTEGER 'segment to write screen image (e.g., &HB800)
- END TYPE '10 bytes
- This routine is supplied only in the BULLET debug engine. It displays real-time
- monitoring information of a .DBF file or index and .DBF file pair including
- searches, seeks, hits, current record number, current key, key node contents,
- key node pointers, stack state, key and record counts, and other info.
- By using the HereSeg value returned from StatKXB you can locate the searches,
- seeks, and hits data at (DEF SEG=HereSeg: Seeks&=GetLongAt&(517): DEF SEG)
- +513 Searches AS LONG ;keys searched for since open
- +517 Seeks AS LONG ;nodes seeked since open
- +521 Hits AS LONG ;seeks satisfied without disk access
- See: ExitPack
- ~ExitPack
- Src: InitXBsrc Func: ExitXB, AtExitXB
- TYPE ExitPack 'EP
- Func AS INTEGER '1=ExitXB, 2=AtExitXB
- Stat AS INTEGER 'ret:completion status
- END TYPE '4 bytes
- See: FieldDescTYPE
- ~FieldDescTYPE
- Src: CreateDXBsrc Func: CreateDXB
- TYPE FieldDescTYPE 'this TYPE is used by CreateDataPack ONLY
- FieldName AS STRING * 11 'zero-filled field name (use only ASCII 65-90,95)
- FieldType AS STRING * 1 'C-har,N-umeric,D-ate,L-ogical,M-emo
- FieldDA AS LONG '=0,reserved
- FieldLength AS STRING * 1 'C=1-254,N=1-19(varies),D=8,L=1,M=10
- FieldDC AS STRING * 1 'decimal places for FieldType=N (0,2-15)
- A1 AS INTEGER '=0,reserved
- A2 AS INTEGER '=0,reserved
- filler AS STRING * 10 '=0,reserved
- END TYPE '32
- If you can can forgo dBASE compatility you can use the B field type. This type
- is for fields that contain binary data (all dBASE fields contain ASCII text or
- numeric strings). If you specify a FieldType = "B" for, say an integer field,
- use a FieldLen = 2. If the field is a long integer, use FieldLen = 4. You can
- also use this non-standard field type for indexing. See CreateKXB for more.
- See: HandlePack CreateDataPack CreateKXB
- ~HandlePack
- Src: CloseDXBsrc Func: CloseDXB, ReadDHXB, FlushDHXB, ZapDHXB
- CloseKXB, ReadKHXB, FlushKHXB, ZapKHXB
- 'HP
- TYPE HandlePack '12=CloseDXB,14=ReadDHXB,15=FlushDHXB,17=ZapDHXB
- Func AS INTEGER '22=CloseKXB,24=ReadKHXB,25=FlushKHXB,27=ZapKHXB
- Stat AS INTEGER 'ret:completion status
- Handle AS INTEGER 'handle of BULLET file
- END TYPE '6
- See: InitPack
- ~InitPack
- Src: InitXBsrc Func: InitXB
- TYPE InitPack 'IP
- Func AS INTEGER '0
- Stat AS INTEGER 'ret:completion status
- JFTmode AS INTEGER 'expand JFT if non-zero
- DOSver AS INTEGER 'ret:DOS version
- Version AS INTEGER 'ret:BULLET version * 100
- ExitOff AS INTEGER 'ret:far pointer to ExitXB routine, offset
- ExitSeg AS INTEGER 'ret:segment of ExitXB
- END TYPE '12 bytes
-
- See: MemoryPack
- ~MemoryPack
- Src: MemoryXBsrc Func: MemoryXB
- TYPE MemoryPack 'MP
- Func AS INTEGER '3
- Stat AS INTEGER 'ret:completion status
- Memory AS LONG 'ret:largest free OS memory block
- END TYPE '8 bytes
- See: OpenPack
- ~OpenPack
- Src: OpenDXBsrc Func: OpenDXB, OpenKXB
- TYPE OpenPack 'OP
- Func AS INTEGER '11=OpenDXB,21=OpenKXB
- Stat AS INTEGER 'ret:completion status
- Handle AS INTEGER 'ret:OS handle of file opened
- FilenamePtrOff AS INTEGER 'far pointer to filenameZ to open
- FilenamePtrSeg AS INTEGER '(filename must end with a CHR$(0))
- ASmode AS INTEGER 'DOS access-sharing mode (see OpenFileDOS)
- xbHandle AS INTEGER 'if opening key file this is its related data file
- END TYPE '14 '(if opening data file xbHandle is not used)
- 'Note: you must supply xbHandle on index file opens
- See: RemotePack OpenFileDOS
- ~RemotePack
- Src: DriveRemoteXBsrc Func: DriveRemoteXB, FileRemoteXB
- TYPE RemotePack 'RP
- Func AS INTEGER '86=DriveRemoteXB,87=FileRemoteXB
- Stat AS INTEGER 'ret:completion status
- Handle AS INTEGER 'handle/drive depending on routine
- IsRemote AS INTEGER 'ret:0=local,1=remote
- Flags AS INTEGER 'ret:dx register as returned by DOS
- IsShare AS INTEGER 'ret:0=SHARE.EXE not loaded
- END TYPE '12
- See: SetRetriesPack
- ~SetRetriesPack
- Src: SetRetriesXBsrc Func: SetRetriesXB
- TYPE SetRetriesPack 'SRP
- Func AS INTEGER '88
- Stat AS INTEGER 'ret:completion status
- Mode AS INTEGER '0=set DOS default else use Pauses/Retries below
- Pause AS INTEGER '0-65535 loop counter between retries
- Retries As INTEGER '0-65535 retries to access locked file
- END TYPE '10
- The default values for Retries is 3 and Pause is 1.
- The Pause value is used as a simple loop counter used to waste time. This loop
- IS dependent on CPU power so values are not portable across different machines.
- Do not use unrealistic values. For example, don't set Retries to 30,000 unless
- you really want to wait for DOS to try 30,000 times before returning an error!
- See: StatDataPack
- ~StatDataPack
- Src: StatDXBsrc Func: StatDXB
- TYPE StatDataPackTYPE 'SDP
- Func AS INTEGER '13
- Stat AS INTEGER 'ret:completion status
- Handle AS INTEGER 'BULLET data file to get status on
- FileType AS STRING * 1 'ret:1=BULLET XB data file
- Dirty AS STRING * 1 'ret:0=not changed
- Recs AS LONG 'ret:records in file
- RecLen AS INTEGER 'ret:record length
- Fields AS INTEGER 'ret:fields per record ()
- f1 AS STRING * 1 'reserved (1=update DVmon)
- LUyear AS STRING * 1 'ret:binary, year file last updated
- LUmonth AS STRING * 1 'ret:month --LUs are 0 if DBF newly created
- LUday AS STRING * 1 'ret:day
- HereSeg AS INTEGER 'ret:this file's control segment
- filler AS STRING * 10 'reserved
- END TYPE '32
- See: StatKeyPack
- ~StatKeyPack
- Src: StatKXBsrc Func: StatKXB
- TYPE StatKeyPack 'SKP
- Func AS INTEGER '23
- Stat AS INTEGER 'ret:completion status
- Handle AS INTEGER 'BULLET key file to get status on
- FileType AS STRING * 1 'ret:0=BULLET XB key file
- Dirty AS STRING * 1 'ret:0=not changed
- Keys AS LONG 'ret:keys in file
- KeyLen AS INTEGER 'ret:key length
- XBlink AS INTEGER 'ret:related BULLET XB data file handle
- XBrecno AS LONG 'ret:record number attached to current key
- HereSeg AS INTEGER 'ret:this file's control segment
- CodePageID AS INTEGER 'ret:code page ID number of key file sort
- CountryCode AS INTEGER 'ret:country code number of key file sort
- CollateTableSize AS INTEGER 'ret: size of collate table, 0 or 256
- KeyFlags AS INTEGER 'ret:bit 0=unique,1=char,4=int,5=long,E=NLS,F=signed
- filler AS STRING * 2
- END TYPE '32
- See: StatHandlePack
- ~StatHandlePack
- Src: StatHandleXBsrc Func: StatHandleXB
- TYPE StatHandlePack 'SHP
- Func AS INTEGER '6
- Stat AS INTEGER 'ret:completion status
- Handle AS INTEGER 'file handle to get information on
- ID AS INTEGER 'ret:0=XB index,1=XB data file,-1=not BULLET handle
- END TYPE '8 bytes
- See: XErrorPack
- ~XErrorPack
- Src: GetExtErrorXBsrc Func: GetExtErrorXB
- TYPE XErrorPack 'XEP
- Func AS INTEGER '7
- Stat AS INTEGER 'ret:extended error
- Class AS INTEGER 'ret:error class
- Action AS INTEGER 'ret:suggested action
- Location AS INTEGER 'ret:error location
- END TYPE '10 bytes
- See: AccessPack Errors_DOS
- ~Errors_BULLET (200-209)
- 200 key not found - The search key for Equal was not matched exactly.
- Next/Prev routines can be used to continue search from point of mismatch.
- 201 key already exists - Attempted to add a key that already exists in the
- index file created to allow only unique keys.
- 202 end of file - A Next routine is past the last key of the index file.
- 203 top of file - A Prev routine is before the first key of the index file.
- 204 key file empty - A key access was attempted with no keys in the index file.
- 205 key type unknown - Generally indicates a corrupt index header (keyflags
- unknown at key insert).
- reserved,206-207
- 208 no more nodes - The index file has reached full capacity (32MB). ReindexXB
- can often shrink an index file by 30 to 50%.
- 209 key file corrupt - The index file is corrupt (write attempt to node 0).
- See: Errors_BULLET_b
- ~Errors_BULLET_b (210-232)
- 210 key file corrupt - The index file is corrupt (internal overflow).
- reserved,211-219
- 220 incorrect DOS version - BULLET requires DOS 3.3 or later.
- 221 invalid key length - The key is > 62 bytes (or 64 if unique specified).
- 222 file not open - The specified handle is not an open BULLET file.
-
- reserved,223
- 224 invalid record number - The specified record number is < 0, past the last
- record number in the .DBF, or is > 16,777,215.
- reserved,225-227
- 228 invalid filetype - The specified handle is not the correct type for the
- operation (i.e., specifying a data file handle for a key file operation).
- reserved,229-232
- See: Errors_BULLET_c
- ~Errors_BULLET_c (233-243)
- 233 init not active - InitXB must be called before all others except MemoryXB.
- 234 init already active - InitXB has already been called. Use ExitXB first to
- call InitXB more than once per process. (Make sure the xxP.Func <> 0.)
- 235 too many indexes - BULLET can handle up to 32 index files per transaction
- record with the InsertXB and UpdateXB routines. Contact the author if you
- need to allow for more than 32 index files/transaction record.
- reserved,236-239
- 240 invalid key expression - The CreateKXB key expression could not be
- evaluated.
- reserved,241
- 242 field not found - The fieldname was not found in the descriptor area.
- 243 invalid field count - Too many fields were specified or the specified field
- number is past the last field.
- See: Errors_BULLET_d
- ~Errors_BULLET_d (244-255)
- reserved,244-249
- 250 invalid country info - The specifed country code or code page ID is not
- valid or not installed (according to DOS).
- 251 invalid collate table size - The specified country code/code page ID uses
- a collate-sequence table > 256 bytes (2-byte characters as with Kanji).
- 252 invalid keyflags - The specified keyflags are invalid.
- reserved,253-254
- 255 evaluation mode shutdown - BULLET evaluation period has completed.
- You can reinstall to continue evaluation, though you may want to consider
- your motives for reinstalling since the original evaluation period has
- expired. This error occurs only after the evaluation period has expired.
- It is not recommended that you continue to use BULLET after the evaluation
- period. It is possible for no 255 error to be generated for quite some
- time since it occurs only under certain load conditions and then only when
- certain routine sequences are performed. The specified evaluation period of
- 21 days should be adhered to.
- See: Errors_BASIC
- ~Errors_BASIC
- 1 NEXT without FOR 24 device timeout
- 2 syntax error 25 device fault
- 3 RETURN without GOSUB 26 FOR without NEXT
- 4 out of DATA 27 out of paper
- 5 illegal function call 29 WHILE without WEND
- 6 overflow 30 WEND without WHILE
- 7 out of memory reserved,31-32
- 8 label not defined 33 duplicate label
- 9 subscript out of range reserved,34
- 10 duplicate definition 35 subprogram not defined
- 11 division by zero reserved,36
- 12 illegal in direct mode 37 argument-count mismatch
- 13 type mismatch 38 array not defined
- 14 out of string space reserved,39
- reserved,15 40 variable required
- 16 string formula too complex reserved,41-49
- 17 cannot continue 50 FIELD overflow
- 18 function not defined 51 internal error
- 19 no RESUME 52 bad file name or number
- 20 RESUME without error 53 file not found
- reserved,21-23 54 bad file mode
- See: Errors_BASIC_b
- ~Errors_BASIC_b
- 55 file already open reserved,77-79
- 56 FIELD statement active 80 feature removed
- 57 device I/O error 81 invalid name
- 58 file already exists 82 table not found
- 59 bad record length 83 index not found
- reserved,60 84 invalid column
- 61 disk full 85 no current record
- 62 input past end of file 86 duplicate value for unique index
- 63 bad record number 87 invalid operation on null index
- 64 bad file name 88 database needs repair
- reserved,65-66 89 insufficient ISAM buffers
- 67 too many files
- 68 device unavailable
- 69 communication-buffer overflow
- 70 permission denied
- 71 disk not ready
- 72 disk-media error
- 73 feature unavailable
- 74 rename across disks
- 75 path/File access error
- 76 path not found
- See: Errors_DOS
- ~Errors_DOS
- -2 disk full or unexpected end of file
- -1 bad filename
- 0 no error
- 1 function not supported 19 disk write protected
- 2 file not found 20 unknown unit
- 3 path not found 21 drive not ready
- 4 too many open files 22 unknown command
- 5 access denied (see Specs_Networks) 23 data error (CRC)
- 6 handle invalid 24 bad request structure length
- 7 MCBs destroyed 25 seek error
- 8 not enough memory 26 unknown medium type
- 9 memory block address invalid 27 sector not found
- 10 environment invalid 28 printer out of paper
- 11 format invalid 29 write fault
- 12 access code invalid 30 read fault
- 13 data invalid 31 general failure
- reserved-0Eh 32 sharing violation
- 15 disk drive invalid 33 lock violation
- 16 cannot remove current directory 34 disk change invalid/wrong disk
- 17 not same device 35 FCB unavailable
- 18 no more files 36 sharing buffer overflow
- See: Errors_DOS_b
- ~Errors_DOS_b
- 37 code page mismatched 58 incorrect response from network
- 38 handle EOF 59 unexpected network error
- 39 handle disk full 60 incompatible remote adapter
- reserved-28h 61 print queue full
- reserved-29h 62 no spool space
- reserved-2Ah 63 not enough space to print file
- reserved-2Bh 64 network name deleted
- reserved-2Ch 65 network access denied
- reserved-2Dh 66 network device type incorrect
- reserved-2Eh 67 network name not found
- reserved-2Fh 68 network name limit exceeded
- reserved-30h 69 NETBIOS session limit exceeded
- reserved-31h 70 sharing temporarily paused
- 50 network request not supported 71 network request not accepted
- 51 remote computer not listening 72 print/disk redirection paused
- 52 duplicate name on network reserved-49h
- 53 network pathname not found reserved-4Ah
- 54 network busy reserved-4Bh
- 55 network device no longer exists reserved-4Ch
- 56 NETBIOS command limit exceeded reserved-4Dh
- 57 network adapter hardware error reserved-4Eh
- See: Errors_DOS_c
- ~Errors_DOS_c
- reserved-4Fh
- DOS Class Codes
- 80 file exists
- 81 duplicate FCB 1 out of resources 7 application error
- 82 cannot make 2 temporary situation 8 not found
- 83 fail on INT24 3 authorization 9 bad format
- 84 out of structures 4 internal error 10 locked
- 85 already assigned 5 hardware failure 11 media failure
- 86 invalid password 6 system failure 12 already exists
- 87 invalid parameter 13 unknown
- 88 network write fault
- reserved-59h DOS Action Codes DOS Locus Codes
- 90 sys comp not loaded
- 1 retry immediately 1 unknown
- 2 delay and retry 2 block device
- 3 reenter input 3 network
- 4 abort ASAP 4 serial device
- 5 abort immediately 5 memory
- 6 ignore error
- 7 user intervention
- See: Errors_BULLET
- ~InitXBsrc
- Func: InitXB Pack: InitPack Func: 0/System
- DIM IP AS InitPack
- DIM EP AS ExitPack
- IP.Func = InitXB 'InitXB defined in BULLET.BI
- IP.JFTmode = 1 'expand JFT to 255 handles
- stat = BULLET(IP)
- IF stat = 0 THEN
- DOSmajor = IP.DOSver\256
- DOSminor = IP.DOSver MOD 256
- BULLETver = IP.Version
- SegExitXB = IP.ExitSeg
- OffExitXB = IP.ExitOff
- EP.Func = AtExitXB 'register ExitXB with _atexit shutdown routine
- stat = BULLET(EP)
- ENDIF
- IF stat THEN 'error
- See: ExitXBsrc
- ~ExitXBsrc
- Func: ExitXB Pack: ExitPack Func: 1/System
- DIM EP AS ExitPack
- EP.Func = ExitXB 'ExitXB defined in BULLET.BI
- stat = BULLET(EP)
- The return value from ExitXB is currently always 0.
- See: AtExitXBsrc
- ~AtExitXBsrc
- Func: AtExitXB Pack: ExitPack Func: 2/System
- DIM IP AS InitPack
- DIM EP AS ExitPack
- IP.Func = InitXB
- IP.JFTmode = 1
- stat = BULLET(IP)
- IF stat = 0 THEN
- DOSmajor = IP.DOSver\256
- DOSminor = IP.DOSver MOD 256
- SegExitXB = IP.ExitSeg
- OffExitXB = IP.ExitOff
- 'register ExitXB with _atexit shutdown routine
- EP.Func = AtExitXB 'AtExitXB defined in BULLET.BI
- stat = BULLET(EP) 'the return value is that returned from the compiler
- '_atexit routine, 0=okay, anything else is an error
- ENDIF 'indicating, for example, the _atexit register is full
- IF stat THEN 'error
- See: MemoryXBsrc
- ~MemoryXBsrc
- Func: MemoryXB Pack: MemoryPack Func: 3/System
- DIM MP AS MemoryPack
- WorkSpace& = 50000 'a value at least 40K or so
- MemoryNeeded& = WorkSpace& + (144&+ ((1+NF)*32)) * TotalOpenDataFiles _
- + (1264& * TotalOpenKeyFiles)
- MP.Func = MemoryXB
- stat = BULLET(MP)
- IF MP.Memory < MemoryNeeded& THEN
- QBheap& = SETMEM(-MemoryNeeded& + 4096) 'release what we need+QB fudge
- MP.Func = MemoryXB
- stat = BULLET(MP)
- IF MP.Memory < MemoryNeeded& THEN 'not enough memory
- END IF
- MP.Memory does not reflect memory available through DOS in the UMB area. It's
- possible that all memory requests can be satisfied by UMB RAM. Consult a DOS 5+
- programmer reference for more information on this (see DOS INT21/58 for more).
- In the QuickBASIC/BASIC PDS environment do not call SETMEM(-x) more than once.
- See: BreakXBsrc
- ~BreakXBsrc
- Func: BreakXB Pack: BreakPack Func: 4/System
- DIM BP AS BreakPack
- BP.Func = BreakXB 'BreakXB defined in BULLET.BI
- BP.Mode = 0 'disable Ctrl-C/Ctrl-BREAK (do nothing on those keys)
- stat = BULLET(BP) 'stat=0 always
- If BreakXB is called multiple times with the same BP.mode each time, only the
- first is acted on. You can set BP.mode = 1 to restore the default handlers
- (those installed originally) and then again set BP.Mode = 0 to disable them.
- ExitXB calls this routine automatically as part of the BULLET shutdown to
- restore the original default break handlers.
- See: BackupFileXBsrc
- ~BackupFileXBsrc
- Func: BackupFileXB Pack: CopyPack Func: 5/System
- DIM AP AS AccessPack
- DIM CP AS CopyPack
- DIM TempStr AS STRING * 80 'used as fixed-length string for VARPTR()
- 'so same source QB AND BASIC7 /Fs compatible
- TempStr = NewFilename$ 'assign the var-len string to fixed-len str
- CP.Func = BackupFileXB 'defined in BULLET.BI
- CP.Handle = DataHandle 'handle of data file to backup
- CP.FilenamePtrOff = VARPTR(TempStr) 'ALWAYS use VARPTR() on fixed-len string
- CP.FilenamePtrSeg = VARSEG(TempStr) 'ALWAYS use VARSEG() on fixed-len string
- stat = BULLET(CP) 'copy the data file to the file NewFilename$
- IF stat = 0 THEN
- AP.Func = PackRecordsXB
- AP.Handle = DataHandle
- stat = BULLET(AP)
- ENDIF
- IF stat THEN 'error
- See: StatHandleXBsrc
- ~StatHandleXBsrc
- Func: StatHandleXB Pack: StatHandlePack Func: 6/System
- DIM SHP AS StatHandlePack
- DIM SKP AS StatKeyPack
- DIM SDP AS StatDataPack
- SHP.Func = StatHandleXB 'defined in BULLET.BI
- SHP.Handle = TheHandleNumber
- stat = BULLET(SHP)
- IF SHP.ID = 0 THEN 'handle belongs to an index file (index file/key file)
- SKP.Func = StatKXB 'get key stats -- see StatKXB/StatDXB for more
- SKP.Handle = PassedHandleNumber ' on the SKP structure
- stat = BULLET(SKP)
- ELSEIF SHP.ID = 1 THEN '.DBF data file
- 'get DBF stats
- 'error not a BULLET file type
- ENDIF
- See: GetExtErrorXBsrc
- ~GetExtErrorXBsrc
- Func: GetExtErrorXB Pack: XErrorPack Func: 7/System
- 'an error just occured in the range 1 to 199 as returned in one of the
- 'pack.Stat variables (current max DOS error is 90 (5Ah))
- 'remember, transaction-based routines return a bad pack index in the return
- 'stat value, which you use to check the appropriate pack.Stat variable
- DIM XEP AS XErrorPack
- XEP.Func = GetExtErrorXB 'defined in BULLET.BI
- stat = BULLET(XEP)
- IF stat <> 0 THEN
- PRINT "Extended Codes --"
- PRINT " error: "; XEP.Stat
- PRINT " error class: "; XEP.Class
- PRINT "recommened action: "; XEP.Action
- PRINT " location: "; XEP.Location
- PRINT "No error"
- ENDIF
- See: DVmonCXBsrc StatKXB
- ~DVmonCXBsrc
- Func: DVmonCXB Pack: DVmonPack Func: 9/DEBUG
- 'at this point a data file and a key file have been opened
- 'kf is that key file's DOS handle
- DIM DV AS DVmonPack
- DV.Func = DVmonCXB 'defined in BULLET.BI
- DV.Mode = 1 'enable monitoring
- DV.Handle = kf 'monitor key file handle, kf (and its XBlink data file)
- DV.VideoSeg = &HB800+(4096\16) 'output to color screen, page 1 (pages 0 to ?)
- stat = BULLET(DV) 'stat=0 always even if not DEBUG ENGINE
- For two-monitor systems (with a color monitor as the main system) output should
- be directed to &HB000, the mono monitor's video memory.
- DVmonCXB stands for Dual Video Monitor Control XB.
- See: CreateDXBsrc
- ~CreateDXBsrc
- Func: CreateDXB Pack: CreateDataPack Func: 10/Mid-level
- DIM CDP AS CreateDataPack
- DIM TempStr AS STRING * 80 'used as fixed-length string for VARPTR()
- REDIM FD(1 TO 2) AS FieldDescTYPE 'field descriptions for each of the fields...
- '...in the record (record has 2 fields)
- TempStr = filename$ + CHR$(0) 'assign filename to a fixed-len string...
- '...so we can use VARSEG/VARPTR
- 'build FD first for each of the fields in the record
- FD(1).FieldName = "STUDENT" + STRING$(10,0) 'must be zero-filled
- FD(1).FieldType = "C" 'a character field type
- FD(1).FieldLength = CHR$(20) 'up to 20 characters (a byte field--use CHR$())
- FD(1).FieldDC = CHR$(0) 'non-numeric has no decimal places
- FD(2).FieldName = "SCORE" + STRING$(10,0)
- FD(2).FieldType = "N"
- FD(2).FieldLength = CHR$(3) 'dBASE numeric format, allow for "100"
- FD(2).FieldDC = CHR(0) 'no decimal places used for this field
- '(cont)
- 'for BINARY FieldType="B" see FieldDescTYPE
- See: CreateDXBsrc_a -MORE-
- ~CreateDXBsrc_a
- 'build the CDP
- CDP.Func = CreateDXB 'defined in BULLET.BI
- CDP.FilenamePtrOff = VARPTR(TempStr) 'point to filenameZ (Z=0-terminated str)
- CDP.FilenamePtrSeg = VARSEG(TempStr)
- CDP.NoFields = 2 'this example has 2 fields
- CDP.FieldListPtrOff = VARPTR(FD(1)) 'point to the first field decription...
- CDP.FieldListPtrSeg = VARPTR(FD(1)) '...defined in the previous screen
- CDP.FileID = 3 'standard dBASE file ID
- stat = BULLET(CDP) 'create the DBF data file
- IF stat THEN 'error
- Normally this code would be written as a generalized FUNCTION. The CDP could be
- a global allocation (DIM SHARED CDP AS CreateDataPack) and the FD() would also
- be (REDIM [SHARED] FD(1 TO 1) AS FieldDescTYPE) and REDIM'd to needed size when
- used. A possible header:
- DECLARE FUNCTION CreateDBF% (filename$, NoFields%, FD() AS FieldDescTYPE)
- To create a DBF you'd need just the filename, number of fields, REDIM the FD()
- array (if needed), fill in FD() array, then call the function. Look at the
- source code examples on the distribution disk for more.
- See: OpenDXBsrc CreateDXBsrc
- ~OpenDXBsrc
- Func: OpenDXB Pack: OpenPack Func: 11/Mid-level
- DIM OP AS OpenPack
- DIM TempStr AS STRING * 80 'used as fixed-length string for VARPTR()
- TempStr = filename$ + CHR$(0) 'assign filename to a fixed-len string...
- OP.Func = OpenDXB 'defined in BULLET.BI
- OP.FilenamePtrOff = VARPTR(TempStr) 'point to filenameZ (Z=0-terminated str)
- OP.FilenamePtrSeg = VARSEG(TempStr)
- OP.ASmode = ReadWrite + DenyNone 'defined in BULLET.BI
- stat = BULLET(OP)
- IF stat THEN 'error
- The ASmode (access/sharing mode) determines how the operating system controls
- access to the file. See OpenFileDOS for the meanings of the various ASmodes.
- See: CloseDXBsrc OpenFileDOS
- ~CloseDXBsrc
- Func: CloseDXB Pack: HandlePack Func: 12/Mid-level
- DIM HP AS HandlePack
- HP.Func = CloseDXB 'defined in BULLET.BI
- HP.Handle = datahandle 'handle of the file to close
- stat = BULLET(HP)
- IF stat THEN 'error
- See: StatDXBsrc
- ~StatDXBsrc
- Func: StatDXB Pack: StatDataPack Func: 13/Mid-level
- DIM SDP AS StatDataPack
- SDP.Func = StatDXB 'defined in BULLET.BI
- SDP.Handle = datahandle 'data handle to get stats on
- stat = BULLET(SDP) 'must be a data handle, use StatHandleXB if you...
- IF stat = 0 THEN '...don't know the type of file a handle's for
- 'SDP.FileType is set to 1
- 'SDP.Dirty is set to 1 if the file has changed (0=not changed)
- 'SDP.Recs = number of records in the DBF file
- 'SDP.RecLen = record length
- 'SDP.Fields = number of fields in the record
- 'SDP.f1 is reserved
- 'SDP.LUyear = year file last updated, binary (year = ASC(SDP.LUyear))
- 'SDP.LUmonth = month, binary
- 'SDP.LUday = day, binary
- 'SDP.HereSeg is set to this handle's control segment (location in memory)
- 'error
- ENDIF
- See: ReadDHXBsrc
- ~ReadDHXBsrc
- Func: ReadDHXB Pack: HandlePack Func: 14/Mid-level
- DIM HP AS HandlePack
- HP.Func = ReadDHXB 'defined in BULLET.BI
- HP.Handle = datahandle 'handle of file whose header you want to reload
- stat = BULLET(HP)
- IF stat THEN 'error
- This routine is automatically called by the network lock routines.
- See: FlushDHXBsrc LockDataXB
- ~FlushDHXBsrc
- Func: FlushDHXB Pack: HandlePack Func: 15/Mid-level
- DIM HP AS HandlePack
- HP.Func = FlushDHXB 'defined in BULLET.BI
- HP.Handle = datahandle 'handle of file you want to flush
- stat = BULLET(HP)
- IF stat THEN 'error
- Note that the physical write to disk is performed only if the file has changed
- since the open or last flush.
- This routine is automatically called by the network unlock routines.
- See: CopyDHXBsrc UnlockDataXB
- ~CopyDHXBsrc
- Func: CopyDHXBsrc Pack: CopyPack Func: 16/Mid-level
- DIM CP AS CopyPack
- DIM TempStr AS STRING * 80 'used as fixed-length string for VARPTR()
- TempStr = filename$ + CHR$(0) 'assign filename to a fixed-len string...
- CP.Func = CopyDHXB 'defined in BULLET.BI
- CP.Handle = datahandle 'handle of file to copy from (the source)
- CP.FilenamePtrOff = VARPTR(TempStr) 'far pointer to filenameZ for copy
- CP.FilenamePtrSeg = VARPTR(TempStr) '(the destination)
- stat = BULLET(CP)
- IF stat THEN 'error
- See: ZapDHXBsrc
- ~ZapDHXBsrc
- Func: ZapDHXB Pack: HandlePack Func: 17/Mid-level
- DIM HP AS HandlePack
- HP.Func = ZapDHXB 'defined in BULLET.BI
- HP.Handle = datahandle 'handle of file you want !ZAP!
- stat = BULLET(HP)
- IF stat THEN 'error
- Note that this removes ALL data records from the data file.
- See: CreateKXBsrc
- ~CreateKXBsrc
- Func: CreateKXB Pack: CreateKeyPack Func: 20/Mid-level
- 'This code assumes that the datafile was created as in CreateDXBsrc, and that
- 'the datafile was opened as in OpenDXBsrc.
- kx$ = "SUBSTR(STUDENT,1,5)" 'key expression, a non-unique, character key
- DIM CKP AS CreateKeyPack
- DIM TempStr AS STRING * 80 'used as fixed-length string for VARPTR()
- DIM TempStr2 AS STRING * 136 'used as fixed-length string for VARPTR()
- TempStr = filename$ + CHR$(0) 'assign filename to a fixed-len string
- TempStr2 = kx$ + CHR$(0) 'same for key expression string
- '(cont)
- See: CreateKXBsrc_a -MORE-
- ~CreateKXBsrc_a
- CKP.Func = CreateKXB 'defined in BULLET.BI
- CKP.FilenamePtrOff = VARPTR(TempStr) 'far pointer to filenameZ
- CKP.FilenamePtrSeg = VARSEG(TempStr)
- CKP.KeyExpPtrOff = VARPTR(TempStr2) 'far pointer to key expressionZ
- CKP.KeyExpPtrSeg = VARSEG(TempStr2)
- CKP.XBlink = datahandle 'the datafile handle returned from OpenDXB
- CKP.KeyFlags = cCHAR '-KEYFLAGS- are defined in BULLET.BI
- CKP.CodePageID = -1 'use DOS default code page ID
- CKP.CountryCode = -1 'use DOS default country code
- CKP.CollatePtrOff = 0 'no user-supplied collate table...
- CKP.CollatePtrSeg = 0 '...
- stat = BULLET(CKP)
- IF stat THEN 'error
- Normally this code would be written as a generalized FUNCTION. The CKP could be
- a global allocation (DIM SHARED CKP AS CreateKeyPack). A possible header:
- DECLARE FUNCTION CreateNewIndex% (filename$, datahandle, kx$, KeyFlags%)
- To create an index file you'd need just filename, datahandle, key expression,
- and key flags (country code info if not using default), then call the function.
- See: OpenKXBsrc CreateKXBsrc
- ~OpenKXBsrc
- Func: OpenKXB Pack: OpenPack Func: 21/Mid-level
- DIM OP AS OpenPack
- DIM TempStr AS STRING * 80 'used as fixed-length string for VARPTR()
- TempStr = filename$ + CHR$(0) 'assign filename to a fixed-len string...
- OP.Func = OpenKXB 'defined in BULLET.BI
- OP.FilenamePtrOff = VARPTR(TempStr) 'point to filenameZ (Z=0-terminated str)
- OP.FilenamePtrSeg = VARSEG(TempStr)
- OP.ASmode = ReadWrite + DenyNone 'defined in BULLET.BI
- OP.XBlink = datafilehandle 'OpenKXB needs to know the data file handle
- stat = BULLET(OP)
- IF stat THEN 'error
- The ASmode (access/sharing mode) determines how the operating system controls
- access to the file. See OpenFileDOS for the meanings of the various ASmodes.
- Before you can open an index file you must first open its associated data file.
- See: CloseKXBsrc OpenFileDOS
- ~CloseKXBsrc
- Func: CloseKXB Pack: HandlePack Func: 22/Mid-level
- DIM HP AS HandlePack
- HP.Func = CloseDXB 'defined in BULLET.BI
- HP.Handle = indexhandle 'handle of the file to close
- stat = BULLET(HP)
- IF stat THEN 'error
- See: StatKXBsrc
- ~StatKXBsrc
- Func: StatKXB Pack: StatKeyPack Func: 23/Mid-level
- DIM SKP AS StatKeyPack
- SKP.Func = StatKXB 'defined in BULLET.BI
- SKP.Handle = indexhandle 'handle to get stats on
- stat = BULLET(SKP) 'must be index handle, use StatHandleXB if you...
- IF stat = 0 THEN '...don't know the type of file a handle's for
- 'SKP.FileType is set to 0
- 'SKP.Dirty is set to 1 if the file has changed (0=not changed)
- 'SKP.Keys = number of key in the index file (index file=key file)
- 'SKP.KeyLen = physical key length (1-64 bytes)
- 'SKP.XBlink = datafile handle that this index file is associated with
- 'SKP.XBrecno is set to record number associated with last accessed key
- 'SKP.HereSeg is set to this handle's control segment (location in memory)
- 'SKP.CodePageID returns this index file's permanent code page ID
- 'SKP.CountryCode returns this index file's permanent country code
- 'SKP.CollateTableSize = 0 (no collate table present) or 256 (table present)
- 'SKP.KeyFlags = key flags specifed at CreateKXB (except NLS flag may be set)
- ELSE (NLS flag is bit 14, &H4000)
- 'error
- See: ReadKHXBsrc
- ~ReadKHXBsrc
- Func: ReadKHXB Pack: HandlePack Func: 24/Mid-level
- DIM HP AS HandlePack
- HP.Func = ReadKHXB 'defined in BULLET.BI
- HP.Handle = indexhandle 'handle of file whose header you want to reload
- stat = BULLET(HP)
- IF stat THEN 'error
- This routine is automatically called by the network lock routines.
- See: FlushKHXBsrc LockKeyXB
- ~FlushKHXBsrc
- Func: FlushKHXB Pack: HandlePack Func: 25/Mid-level
- DIM HP AS HandlePack
- HP.Func = FlushKHXB 'defined in BULLET.BI
- HP.Handle = indexhandle 'handle of file you want to flush
- stat = BULLET(HP)
- IF stat THEN 'error
- Note that the physical write to disk is performed only if the file has changed
- since the open or last flush.
- This routine is automatically called by the network unlock routines.
- See: CopyKHXBsrc UnlockKeyXB
- ~CopyKHXBsrc
- Func: CopyKHXBsrc Pack: CopyPack Func: 26/Mid-level
- DIM CP AS CopyPack
- DIM TempStr AS STRING * 80 'used as fixed-length string for VARPTR()
- TempStr = filename$ + CHR$(0) 'assign filename to a fixed-len string...
- CP.Func = CopyKHXB 'defined in BULLET.BI
- CP.Handle = indexhandle 'handle of file to copy from (the source)
- CP.FilenamePtrOff = VARPTR(TempStr) 'far pointer to filenameZ for copy
- CP.FilenamePtrSeg = VARPTR(TempStr) '(the destination)
- stat = BULLET(CP)
- IF stat THEN 'error
- See: ZapKHXBsrc
- ~ZapKHXBsrc
- Func: ZapKHXB Pack: HandlePack Func: 27/Mid-level
- DIM HP AS HandlePack
- HP.Func = ZapKHXB 'defined in BULLET.BI
- HP.Handle = indexhandle 'handle of file you want !ZAP!
- stat = BULLET(HP)
- IF stat THEN 'error
- Note that this removes ALL keys from the index file.
- See: GetDescriptorXBsrc
- ~GetDescriptorXBsrc
- Func: GetDescriptorXB Pack: DescriptorPack Func: 30/Mid-level
- DIM DP AS DescriptorPack
- DP.Func = GetDescriptorXB 'defined in BULLET.BI
- DP.Handle = datahandle 'handle of file
- IF FieldNumber > 0 THEN
- DP.FieldNumber = FieldNumber 'field number to get info on
- ELSE 'or, if 0, then
- DP.FieldNumber = 0
- DP.FD.FieldName = fieldname$ + STRING$(10,0) 'fieldname$ to get info on
- ENDIF
- stat = BULLET(DP)
- IF stat = 0 THEN
- 'DP.FD.FieldName is set to field name
- 'DP.FD.FieldType is set to field type
- 'DP.FD.FieldLen is set to field length
- 'DP.FD.FieldDC is set to field DC
- ELSE
- 'error
- The DP.FD.FieldLen (and DP.FD.FieldDC) is a byte string so you
-
- need to use a FldLen=ASC(DP.FD.FieldLen) for its integer value
-
- See: GetRecordXBsrc
- ~GetRecordXBsrc
- Func: GetRecordXB Pack: AccessPack Func: 31/Mid-level
- TYPE RecordTYPE 'simple DBF record layout
- tag AS STRING * 1 <
- code AS STRING * 4
- THE FIRST BYTE OF YOUR RECORD TYPES MUST BE TAG!
- bday AS STRING * 8
- END TYPE
- DIM RecBuff AS RecordTYPE 'record has 2 fields, code/C/4.0, bday/D/8.0
- DIM AP AS AccessPack
- AP.Func = GetRecordXB 'defined in BULLET.BI
- AP.Handle = datahandle 'handle to get record from
- AP.RecNo = RecnoToGet& 'record number to get
- AP.RecPtrOff = VARPTR(RecBuff) 'read record from disk into RecBuff
- AP.RecPtrSeg = VARSEG(RecBuff)
- stat = BULLET(AP)
- IF stat = 0 THEN
- PRINT RecBuff.code ; ", " ; RecBuff.bday 'sample output: 4321, 19331122
- 'error
- See: AddRecordXBsrc
- ~AddRecordXBsrc
- Func: AddRecordXB Pack: AccessPack Func: 32/Mid-level
- TYPE RecordTYPE 'simple DBF record layout
- tag AS STRING * 1 <
- code AS STRING * 4
- THE FIRST BYTE OF YOUR RECORD TYPES MUST BE TAG!
- bday AS STRING * 8
- END TYPE
- DIM RecBuff AS RecordTYPE 'record has 2 fields, code/C/4.0, bday/D/8.0
- DIM AP AS AccessPack
- 'be sure to init the tag field to a space (ASCII 32)
- RecBuff.tag = " " : RecBuff.code = "1234" : RecBuff.bday = "19331122"
- AP.Func = AddRecordXB 'defined in BULLET.BI
- AP.Handle = datahandle 'handle to add record to
- AP.RecPtrOff = VARPTR(RecBuff) 'write record from RecBuff to disk...
- AP.RecPtrSeg = VARSEG(RecBuff) '...at next available record number
- stat = BULLET(AP)
- IF stat = 0 THEN
- PRINT "Record number used by AddRecordXB was "; AP.RecNo
- ELSE 'error
- See: UpdateRecordXBsrc
- ~UpdateRecordXBsrc
- Func: UpdateRecordXB Pack: AccessPack Func: 33/Mid-level
- 'see GetRecordXBsrc for this source example's preliminary code
- AP.Func = GetRecordXB 'first get the record to update
- AP.Handle = datahandle
- AP.RecNo = RecnoToGet& '
- AP.RecPtrOff = VARPTR(RecBuff) '
- Do NOT use UpdateRecordXB to change
- AP.RecPtrSeg = VARSEG(RecBuff) '
- any field(s) used in a key expression.
- stat = BULLET(AP) '
- Instead use UpdateXB.
- IF stat = 0 THEN '
- RecBuff.dbay = "19591122" 'change only non-key portions of record
- AP.Func = UpdateRecordXB 'defined in BULLET.BI
- stat = BULLET(AP) 'other AP. values are already set from the Get
- IF stat THEN 'though you should reassign AP.RecPtrOff/Seg if
- 'error 'you perform any BASIC string functions between
- 'BULLET calls (none were in this case).
- NOTE: QB/PDS will move strings
- '--by this I mean to set these again
- after a user-break/Ctrl-Break
- ' AP.RecPtrOff = VARPTR(RecBuff)
- in the QB/QBX environment !!!
- ' AP.RecPtrSeg = VARSEG(RecBuff)
- ' stat = BULLET(AP) 'do the update call
- See: DeleteRecordXBsrc UpdateXB
- ~DeleteRecordXBsrc
- Func: DeleteRecordXB Pack: AccessPack Func: 34/Mid-level
- DIM AP AS AccessPack
- AP.Func = DeleteRecordXB 'defined in BULLET.BI
- AP.Handle = datahandle 'handle of record to delete
- AP.RecNo = RecnoToDelete& 'to determine which record number any record
- stat = BULLET(AP) 'is, use one of the keyed access routines
- IF stat THEN 'error
- See: UndeleteRecordsrc (XB)
- ~UndeleteRecordsrc (XB)
- Func: UndeleteRecordXB Pack: AccessPack Func: 35/Mid-level
- DIM AP AS AccessPack
- AP.Func = UndeleteRecordXB 'defined in BULLET.BI
- AP.Handle = datahandle 'handle of record to undelete
- AP.RecNo = RecnoToUndelete& 'to determine which record number any record
- stat = BULLET(AP) 'is use one of the keyed access routines
- IF stat THEN 'error
- See: PackRecordsXBsrc
- ~PackRecordsXBsrc
- Func: PackRecordsXB Pack: AccessPack Func: 36/Mid-level
- DIM AP AS AccessPack
- AP.Func = PackRecordsXB 'defined in BULLET.BI
- AP.Handle = datahandle 'handle of data file to pack
- stat = BULLET(AP)
- IF stat THEN 'error
- See: FirstKeyXBsrc
- ~FirstKeyXBsrc
- Func: FirstKeyXB Pack: AccessPack Func: 40/Mid-level
- DIM AP AS AccessPack
- DIM TempStr AS STRING * 64 'used as fixed-length string for VARPTR()
- 'needs to be at least key length (MAXKEYLEN=64)
- AP.Func = FirstKeyXB 'defined in BULLET.BI
- AP.Handle = indexhandle 'handle to index file to access key from
- AP.KeyPtrOff = VARPTR(TempStr) 'far pointer to key buffer
- AP.KeyPtrSeg = VARSEG(TempStr) '(the first key is read from disk and put here)
- stat = BULLET(AP)
- IF stat = 0 THEN
- 'TempStr is filled in with the key (for as many bytes as the key length)
- 'so, if the key is a character type, you could PRINT LEFT$(TempStr,KeyLen)
- 'or, if key is a 32-bit LONG then PRINT CVL(LEFT$(TempStr,4)). When using
- 'the key returned, be aware that if UNIQUE was NOT specified then the
- 'enumerator word is attached to the end of the key (the right two bytes).
- 'Also, AP.RecNo is set to the record number of the first key in the index.
- 'error
- See: EqualKeyXBsrc
- ~EqualKeyXBsrc
- Func: EqualKeyXB Pack: AccessPack Func: 41/Mid-level
- DIM AP AS AccessPack
- DIM TempStr AS STRING * 64 'used as fixed-length string for VARPTR()
- 'passed key to find, start with enum=0
- TempStr = FindKey$ + CHR$(0) + CHR$(0) + CHR$(0) '2 enumerator bytes + 0-term
- AP.Func = EqualKeyXB 'defined in BULLET.BI
- AP.Handle = indexfile 'handle to index file to find key from
- AP.KeyPtrOff = VARPTR(TempStr) 'far pointer to key buffer
- AP.KeyPtrSeg = VARSEG(TempStr)
- stat = BULLET(AP)
- IF stat = 0 THEN
- 'the key matched exactly (including enumerator, if present)
- 'TempStr is NOT ALTERED
- 'AP.RecNo is set to the record number of that key
- ELSEIF stat = 200 THEN
- AP.Func = NextKeyXB 'if not found, get following key and check the
- stat = BULLET(AP) 'key proper (key less the enumerator bytes)
- IF stat = 0 THEN '(i.e., it may be proper key but enumerator=1)
- 'see NextKeyXBsrc for continuation
- See: NextKeyXBsrc
- ~NextKeyXBsrc
- Func: NextKeyXB Pack: AccessPack Func: 42/Mid-level
- 'see EqualKeyXBsrc for preliminary code
- AP.Func = NextKeyXB 'defined in BULLET.BI
- stat = BULLET(AP) 'KEYLEN assumed to equal actual key length...
- IF stat = 0 THEN '...as returned by StatKXB
- IF IndexFileIsNotUnique THEN
- IF LEFT$(TempStr,KeyLen-2) = FindKey$ THEN 'the next key matches!
- '(except for the enumerator)
- This code example follows up on the EqualKeyXBsrc example. See EqualKeyXB for
- more information on finding partial keys.
- See: PrevKeyXBsrc EqualKeyXBsrc
- ~PrevKeyXBsrc
- Func: PrevKeyXB Pack: AccessPack Func: 43/Mid-level
- DIM AP AS AccessPack
- DIM TempStr AS STRING * 64 'used as fixed-length string for VARPTR()
- 'assume code has already executed to locate a key--this code then gets the key
- 'before that one
- AP.Func = PrevKeyXB 'defined in BULLET.BI
- AP.Handle = indexfile 'handle to index file to access key from
- AP.KeyPtrOff = VARPTR(TempStr) 'far pointer to key buffer
- AP.KeyPtrSeg = VARSEG(TempStr) '(the prev key is read from disk and put here)
- stat = BULLET(AP)
- IF stat = 0 THEN
- 'TempStr is filled in with the key (for as many bytes as the key length).
- 'Also, AP.RecNo is set to the record number of the key.
- 'error
- See: LastKeyXBsrc
- ~LastKeyXBsrc
- Func: LastKeyXB Pack: AccessPack Func: 44/Mid-level
- DIM AP AS AccessPack
- DIM TempStr AS STRING * 64 'used as fixed-length string for VARPTR()
- AP.Func = LastKeyXB 'defined in BULLET.BI
- AP.Handle = indexfile 'handle to index file to access key from
- AP.KeyPtrOff = VARPTR(TempStr) 'far pointer to key buffer
- AP.KeyPtrSeg = VARSEG(TempStr) '(the last key is read from disk and put here)
- stat = BULLET(AP)
- IF stat = 0 THEN
- 'TempStr is filled in with the key (for as many bytes as the key length)
- 'AP.RecNo is set to the record number of the last key.
- 'error
- See: StoreKeyXBsrc
- ~StoreKeyXBsrc
- Func: StoreKeyXB Pack: AccessPack Func: 45/Mid-level
- DIM AP AS AccessPack
- DIM TempStr AS STRING * 64 'used as fixed-length string for VARPTR()
- 'Assume record has been added to data file (AddRecordXB, returning RecNo2Use)
- 'and key has been built (BuildKeyXB returning KeyToAdd$).
-
- TempStr = KeyToAdd$ + CHR$(0) 'add the key to a UNIQUE index file
- AP.Func = StoreKeyXB 'defined in BULLET.BI
- AP.Handle = indexfile 'handle to index file to insert key into
- AP.RecNo = RecNo2Use 'associate this record number with key
- AP.KeyPtrOff = VARPTR(TempStr) 'far pointer to key buffer
- AP.KeyPtrSeg = VARSEG(TempStr) '(the last key is read from disk and put here)
- stat = BULLET(AP)
- IF stat = 0 THEN
- 'key added
- ELSEIF stat = 201 THEN
- 'key already exists, which means you need to construct a unique enumerator--
- 'provided the file wasn't created for UNIQUE keys...INSTEAD USE InsertXB!
- See: DeleteKeyXBsrc InsertXB
- ~DeleteKeyXBsrc
- Func: DeleteKeyXB Pack: AccessPack Func: 46/Mid-level
- DIM AP AS AccessPack
- DIM TempStr AS STRING * 64 'used as fixed-length string for VARPTR()
- TempStr = KeyToDelete$ + CHR$(0) 'delete the key from a UNIQUE index file
- '(else need to supply enumerator also)
- AP.Func = DeleteKeyXB 'defined in BULLET.BI
- AP.Handle = indexfile 'handle to index file of key to delete
- AP.KeyPtrOff = VARPTR(TempStr) 'far pointer to key buffer
- AP.KeyPtrSeg = VARSEG(TempStr) '(this key is searched for exactly)
- stat = BULLET(AP) 'if exact match found the key is deleted!
- IF stat = 0 THEN
- 'key deleted permanently
- ELSEIF stat = 200 THEN
- 'key as stated was not in the index file--if the index is not UNQIUE then
- 'you must supply the exact enumerator along with the key proper to delete
- '--you can use the CurrentKeyXB routine to obtain the exact current key
- 'other error
- See: BuildKeyXBsrc
- ~BuildKeyXBsrc
- Func: BuildKeyXB Pack: AccessPack Func: 47/Mid-level
- DIM AP AS AccessPack
- DIM TempStr AS STRING * 64 'used as fixed-length string for VARPTR()
- 'Assume record has been built and is ready to be added to the data file. The
- 'record is in the variable RecBuff (a fixed-length TYPE variable, typically).
- AP.Func = BuildKeyXB 'defined in BULLET.BI
- AP.Handle = indexfile 'handle to index file key is to be built for
- AP.RecPtrOff = VARPTR(RecBuff) 'far pointer to data record buffer
- AP.RecPtrSeg = VARSEG(RecBuff)
- AP.KeyPtrOff = VARPTR(TempStr) 'far pointer to key buffer
- AP.KeyPtrSeg = VARSEG(TempStr) '(the built key is put here)
- stat = BULLET(AP)
- IF stat = 0 THEN
- 'key built okay so can do a AddRecordXB followed by a StoreKeyXB
- 'but, again, InsertXB takes care of all this detail and then some--use it
- 'error
- See: CurrentKeyXBsrc
- ~CurrentKeyXBsrc
- Func: CurrentKeyXB Pack: AccessPack Func: 48/Mid-level
- DIM AP AS AccessPack
- DIM TempStr AS STRING * 64 'used as fixed-length string for VARPTR()
- AP.Func = CurrentKeyXB 'defined in BULLET.BI
- AP.Handle = indexfile 'handle to index file
- AP.KeyPtrOff = VARPTR(TempStr) 'far pointer to key buffer
- AP.KeyPtrSeg = VARSEG(TempStr) '(the current key is put here)
- stat = BULLET(AP)
- IF stat = 0 THEN
- 'TempStr set to current key (valid only for KeyLen bytes)
- 'Also, AP.RecNo is set to the record number of the key.
- 'error
- See: GetFirstXBsrc
- ~GetFirstXBsrc
- Func: GetFirstXB Pack: AccessPack Func: 60/High-level
- DIM AP AS AccessPack
- DIM TempStr AS STRING * 64 'used as fixed-length string for VARPTR()
- DIM RecBuff AS RecordTYPE 'see AddRecordXBsrc for record layout
- AP.Func = GetFirstXB 'defined in BULLET.BI
- AP.Handle = indexhandle 'handle to index file to access key from
- AP.RecPtrOff = VARPTR(RecBuff) 'far pointer to record buffer
- AP.RecPtrSeg = VARSEG(RecBuff) '(the record indexed by the key is put here)
- AP.KeyPtrOff = VARPTR(TempStr) 'far pointer to key buffer
- AP.KeyPtrSeg = VARSEG(TempStr) '(the first key is read from disk and put here)
- stat = BULLET(AP)
- IF stat = 0 THEN
- 'TempStr is filled in with the key (for as many bytes as the key length)
- 'RecBuff is filled in with the data record
- 'AP.RecNo is set to the record number of the first key in the index.
- 'error
- See: GetEqualXBsrc
- ~GetEqualXBsrc
- Func: GetEqualXB Pack: AccessPack Func: 61/High-level
- DIM AP AS AccessPack
- DIM TempStr AS STRING * 64 'used as fixed-length string for VARPTR()
- DIM RecBuff AS RecordTYPE 'see AddRecordXBsrc for record layout
- 'passed key to find, start with enum=0
- TempStr = FindKey$ + CHR$(0) + CHR$(0) + CHR$(0) '2 enumerator bytes + 0-term
- AP.Func = GetEqualXB 'defined in BULLET.BI
- AP.Handle = indexfile 'handle to index file to find key from
- AP.RecPtrOff = VARPTR(RecBuff) 'far pointer to record buffer
- AP.RecPtrSeg = VARSEG(RecBuff) '(the record indexed by the key is put here)
- AP.KeyPtrOff = VARPTR(TempStr) 'far pointer to key buffer
- AP.KeyPtrSeg = VARSEG(TempStr)
- stat = BULLET(AP)
- IF stat = 0 THEN
- 'RecBuff, and AP.RecNo filled as expected (TempStr remains the same)
- ELSEIF stat = 200 THEN
- AP.Func = GetNextXB 'if not found, can get following key--the next
- stat = BULLET(AP) 'key would logically follow the key not found
- '--this let's you search based on partial keys
- See: GetNextXBsrc
- ~GetNextXBsrc
- Func: GetNextXB Pack: AccessPack Func: 62/High-level
- DIM AP AS AccessPack
- DIM TempStr AS STRING * 64 'used as fixed-length string for VARPTR()
- DIM RecBuff AS RecordTYPE 'see AddRecordXBsrc for record layout
- AP.Func = GetFirstXB 'defined in BULLET.BI
- AP.Handle = indexhandle 'handle to index file to access key from
- AP.RecPtrOff = VARPTR(RecBuff) 'far pointer to record buffer
- AP.RecPtrSeg = VARSEG(RecBuff) '(the record indexed by the key is put here)
- AP.KeyPtrOff = VARPTR(TempStr) 'far pointer to key buffer
- AP.KeyPtrSeg = VARSEG(TempStr) '(the first key is read from disk and put here)
- stat = BULLET(AP)
- DO WHILE stat = 0 'print all records in key order
- PRINT AP.RecNo; RecBuff.code; ", "; RecBuff.bday
- AP.Func = GetNextXB
- stat = BULLET(AP)
- IF stat <> 202 THEN 'error 202 means end of file (expected)
- 'error other than expected EOF
- See: GetPrevXBsrc
- ~GetPrevXBsrc
- Func: GetPrevXB Pack: AccessPack Func: 63/High-level
- DIM AP AS AccessPack
- DIM TempStr AS STRING * 64 'used as fixed-length string for VARPTR()
- DIM RecBuff AS RecordTYPE 'see AddRecordXBsrc for record layout
- AP.Func = GetLastXB 'defined in BULLET.BI
- AP.Handle = indexhandle 'handle to index file to access key from
- AP.RecPtrOff = VARPTR(RecBuff) 'far pointer to record buffer
- AP.RecPtrSeg = VARSEG(RecBuff) '(the record indexed by the key is put here)
- AP.KeyPtrOff = VARPTR(TempStr) 'far pointer to key buffer
- AP.KeyPtrSeg = VARSEG(TempStr) '(the last key is read from disk and put here)
- stat = BULLET(AP)
- DO WHILE stat = 0 'print all records in REVERSE key order
- PRINT AP.RecNo; RecBuff.code; ", "; RecBuff.bday
- AP.Func = GetPrevXB
- stat = BULLET(AP)
- IF stat <> 203 THEN 'error 203 means top of file (expected)
- 'error other than expected TOF
- See: GetLastXBsrc
- ~GetLastXBsrc
- Func: GetLastXB Pack: AccessPack Func: 64/High-level
- DIM AP AS AccessPack
- DIM TempStr AS STRING * 64 'used as fixed-length string for VARPTR()
- DIM RecBuff AS RecordTYPE 'see AddRecordXBsrc for record layout
- AP.Func = GetLastXB 'defined in BULLET.BI
- AP.Handle = indexhandle 'handle to index file to access key from
- AP.RecPtrOff = VARPTR(RecBuff) 'far pointer to record buffer
- AP.RecPtrSeg = VARSEG(RecBuff) '(the record indexed by the key is put here)
- AP.KeyPtrOff = VARPTR(TempStr) 'far pointer to key buffer
- AP.KeyPtrSeg = VARSEG(TempStr) '(the last key is read from disk and put here)
- stat = BULLET(AP)
- IF stat = 0 THEN
- 'TempStr is filled in with the key (for as many bytes as the key length)
- 'RecBuff is filled in with the data record
- 'AP.RecNo is set to the record number of the last key in the index.
- 'error
- See: InsertXBsrc
- ~InsertXBsrc
- Func: InsertXB Pack: AccessPack Func: 65/High-level
- REDIM AP(1 TO 4) AS AccessPack 'array of 3 access packs, 1 for each index file
- 'TempStr and RecBuff previously defined
- FOR i = 1 TO 3 '3=number of related indexes to maintain
- AP(i).Func = InsertXB
- AP(i).Handle = indexhandle(i) 'each index file's handle
- AP(i).RecPtrOff = VARPTR(RecBuff)
- AP(i).RecPtrSeg = VARSEG(RecBuff)
- see AddRecordXBsrc for RecBuff TYPE
- AP(i).KeyPtrOff = VARPTR(TempStr)
- (be sure you reserved the tag field)
- AP(i).KeyPtrSeg = VARSEG(TempStr)
- AP(i).NextPtrOff = VARPTR(AP(i + 1)) 'point to NEXT access pack
- AP(i).NextPtrSeg = VARSEG(AP(i + 1)) 'AP(1 TO 4) to avoid subscript error
- AP(3).NextPtrOff = 0 'reset last access pack to end-link value
- AP(3).NextPtrSeg = 0
- stat = BULLET(AP(1))
- IF stat = 0 THEN 'if stat=0 must still check AP(1).Stat
- IF AP(1).Stat <> 0 THEN 'error when adding data record
- TrueError = AP(stat).Stat 'the returned stat is array index of bad pack
- See: UpdateXBsrc
- ~UpdateXBsrc
- Func: UpdateXB Pack: AccessPack Func: 66/High-level
- REDIM AP(1 TO 4) AS AccessPack 'array of 3 access packs, 1 for each index file
- 'TempStr and RecBuff previously defined
- FOR i = 1 TO 3 '3=number of related indexes to maintain
- AP(i).Func = UpdateXB
- AP(i).Handle = indexhandle(i) 'each index file's handle
- AP(i).RecNo = RecordNumberToUpdate& 'tell it which record to update
- AP(i).RecPtrOff = VARPTR(RecBuff) 'RecBuff has new, updated data
- AP(i).RecPtrSeg = VARSEG(RecBuff)
- AP(i).KeyPtrOff = VARPTR(TempStr)
- AP(i).KeyPtrSeg = VARSEG(TempStr)
- AP(i).NextPtrOff = VARPTR(AP(i + 1)) 'point to NEXT access pack
- AP(i).NextPtrSeg = VARSEG(AP(i + 1)) 'AP(1 TO 4) to avoid subscript error
- AP(3).NextPtrOff = 0 : AP(3).NextPtrSeg = 0 'reset last access pack to 0
- stat = BULLET(AP(1))
- IF stat = 0 THEN 'if stat=0 must still check AP(1).Stat
- IF AP(1).Stat <> 0 THEN 'error when writing data record
- TrueError = AP(stat).Stat 'the returned stat is array index of bad pack
- See: ReindexXBsrc
- ~ReindexXBsrc
- Func: ReindexXB Pack: AccessPack Func: 67/High-level
- REDIM AP(1 TO 4) AS AccessPack 'array of 3 access packs, 1 for each index file
- 'DIM'd to 4 to avoid bad subscript in loop
- FOR i = 1 TO 3 '3=number of related indexes to reindex
- AP(i).Func = ReindexXB
- AP(i).Handle = indexhandle(i) 'each index file's handle
- AP(i).NextPtrOff = VARPTR(AP(i + 1)) 'point to NEXT access pack
- AP(i).NextPtrSeg = VARSEG(AP(i + 1)) 'AP(1 TO 4) to avoid subscript error
- AP(3).NextPtrOff = 0
- AP(3).NextPtrSeg = 0 'reset last access pack to end-link value
- stat = BULLET(AP(1))
- IF stat THEN 'if stat <> 0 then the...
- TrueError = AP(stat).Stat '...returned stat is array index of bad pack
- The reason AP() is REDIM AP(1 TO 4) is so that the AP(i + 1) in the code loop
- doesn't create an invalid subscript error.
- See: LockXBsrc
- ~LockXBsrc
- Func: LockXB Pack: AccessPack Func: 80/Network
- REDIM AP(1 TO 4) AS AccessPack 'array of 3 access packs, 1 for each index file
- 'DIM'd to 4 to avoid bad subscript in loop
- FOR i = 1 TO 3 '3=number of related indexes to Lock
- AP(i).Func = LockXB
- AP(i).Handle = indexhandle(i) 'each index file's handle
- AP(i).NextPtrOff = VARPTR(AP(i + 1)) 'point to NEXT access pack
- AP(i).NextPtrSeg = VARSEG(AP(i + 1))
- NEXT 'data file handle known internally by BULLET
- AP(3).NextPtrOff = 0
- AP(3).NextPtrSeg = 0 'reset last access pack to end-link value
- stat = BULLET(AP(1))
- IF stat > 3 THEN 'if stat > 3 (> number of packs) then the...
- TrueError = AP(3).Stat '...lock failed on the data file
- ELSEIF stat <> 0 THEN (|last ReadKHXB)
- TrueError = AP(stat).Stat '...lock failed on index file # stat
- The Lock routines use a different method to identify the bad pack when the
- failure was caused by the data file. See above.
- See: UnlockXBsrc
- ~UnlockXBsrc
- Func: UnlockXB Pack: AccessPack Func: 81/Network
- REDIM AP(1 TO 4) AS AccessPack 'array of 3 access packs, 1 for each index file
- 'DIM'd to 4 to avoid bad subscript in loop
- FOR i = 1 TO 3 '3=number of related indexes to Lock
- AP(i).Func = UnlockXB
- AP(i).Handle = indexhandle(i) 'each index file's handle
- AP(i).NextPtrOff = VARPTR(AP(i + 1)) 'point to NEXT access pack
- AP(i).NextPtrSeg = VARSEG(AP(i + 1))
- NEXT 'data file handle known internally by BULLET
- AP(3).NextPtrOff = 0
- AP(3).NextPtrSeg = 0 'reset last access pack to end-link value
- stat = BULLET(AP(1))
- IF stat > 3 THEN 'if stat > 3 (> number of packs) then the...
- TrueError = AP(3).Stat '...unlock failed on the data file
- ELSEIF stat <> 0 THEN
- TrueError = AP(stat).Stat '...unlock failed on index file # stat
- The Lock routines use a different method to identify the bad pack when the
- failure was caused by the data file. See above.
- See: LockKeyXBsrc
- ~LockKeyXBsrc
- Func: LockKeyXB Pack: AccessPack Func: 82/Network
- REDIM AP(1 TO 4) AS AccessPack 'array of 3 access packs, 1 for each index file
- 'DIM'd to 4 to avoid bad subscript in loop
- FOR i = 1 TO 3 '3=number of related indexes to Lock
- AP(i).Func = LockXB
- AP(i).Handle = indexhandle(i) 'each index file's handle
- AP(i).NextPtrOff = VARPTR(AP(i + 1)) 'point to NEXT access pack
- AP(i).NextPtrSeg = VARSEG(AP(i + 1))
- AP(3).NextPtrOff = 0
- AP(3).NextPtrSeg = 0 'reset last access pack to end-link value
- stat = BULLET(AP(1))
- IF stat <> 0 THEN
- TrueError = AP(stat).Stat 'lock failed on index file # stat
- '--if stat > 3 then failed on last internal
- '--ReadKHXB...This is EXTREMELY unlikely
- See: UnlockKeyXBsrc
- ~UnlockKeyXBsrc
- Func: UnlockKeyXB Pack: AccessPack Func: 83/Network
- REDIM AP(1 TO 4) AS AccessPack 'array of 3 access packs, 1 for each index file
- 'DIM'd to 4 to avoid bad subscript in loop
- FOR i = 1 TO 3 '3=number of related indexes to Lock
- AP(i).Func = UnlockKeyXB
- AP(i).Handle = indexhandle(i) 'each index file's handle
- AP(i).NextPtrOff = VARPTR(AP(i + 1)) 'point to NEXT access pack
- AP(i).NextPtrSeg = VARSEG(AP(i + 1))
- AP(3).NextPtrOff = 0
- AP(3).NextPtrSeg = 0 'reset last access pack to end-link value
- stat = BULLET(AP(1))
- IF stat <> 0 THEN
- TrueError = AP(stat).Stat 'unlock failed on index file # stat
- See: LockDataXBsrc
- ~LockDataXBsrc
- Func: LockDataXB Pack: AccessPack Func: 84/Network
- DIM AP AS AccessPack
- AP.Func = LockDataXB 'defined in BULLET.BI
- AP.Handle = datahandle 'handle of data file to lock
- AP.RecNo = 0& '=0 to lock all or, set to actual record number
- stat = BULLET(AP) ' to lock as in AP.RecNo = lockThisRec&
- IF stat THEN 'error
- See: UnlockDataXBsrc
- ~UnlockDataXBsrc
- Func: UnlockDataXB Pack: AccessPack Func: 85/Network
- DIM AP AS AccessPack
- AP.Func = UnlockDataXB 'defined in BULLET.BI
- AP.Handle = datahandle 'handle of data file to unlock
- AP.RecNo = 0& '=0 to unlock all or, set to actual record num
- stat = BULLET(AP) ' to unlock as in AP.RecNo = lockThisRec&
- IF stat THEN 'error
- 'note: you cannot unlock parts of a file with
- '1 single unlock (where AP.RecNo=0). Instead,
- 'you must unlock each record individually--
- 'that is, if you made any single-record locks
- See: DriveRemoteXBsrc
- ~DriveRemoteXBsrc
- Func: DriveRemoteXB Pack: RemotePack Func: 86/Network
- DIM RP AS RemotePack
- RP.Func = DriveRemoteXB 'defined in BULLET.BI
- RP.Handle = drive2check 'drive to check (0=default, 1=A:,2=B:,3=C:...)
- stat = BULLET(RP)
- IF stat = 0 THEN
- 'RP.IsRemote set to 0 if drive local, 1 if remote
- 'RP.Flags set to DX register as returned by DOS
- 'RP.IsShare set to 0 if SHARE.EXE is not loaded, non-zero SHARE installed
- 'error (like invalid drive)
- See: FileRemoteXBsrc
- ~FileRemoteXBsrc
- Func: FileRemoteXB Pack: RemotePack Func: 87/Network
- DIM RP AS RemotePack
- RP.Func = FileRemoteXB 'defined in BULLET.BI
- RP.Handle = filehandle 'file handle to check
- stat = BULLET(RP)
- IF stat = 0 THEN
- 'RP.IsRemote set to 0 if file local, 1 if remote
- 'RP.Flags set to DX register as returned by DOS
- 'RP.IsShare set to 0 if SHARE.EXE is not loaded, non-zero SHARE installed
- 'error (like invalid handle)
- See: SetRetriesXBsrc
- ~SetRetriesXBsrc
- Func: SetRetriesXB Pack: SetRetriesPack Func: 88/Network
- DIM SRP AS SetRetriesPack
- SRP.Func = SetRetriesXB
- SRP.Mode = 1 '1=set to user values, 0=set DOS default
- SRP.Pause = 5000 'do 5,000 loops between retries
- SRP.Retries = 5 'try 5 times before giving up with error
- stat = BULLET(SRP)
- IF stat THEN
- 'error 'it's unlikely an error occurs
- See: DeleteFileDOSsrc
- ~DeleteFileDOSsrc
- Func: DeleteFileDOS Pack: DOSFilePack Func: 100/DOS
- DIM DFP AS DOSFilePack
- DIM TempStr AS STRING * 80
- TempStr = file2delete$ + CHR$(0)
- DFP.Func = DeleteFileDOS 'defined in BULLET.BI
- DFP.FilenamePtrOff = VARPTR(TempStr)
- DFP.FilenamePtrSeg = VARSEG(TempStr)
- stat = BULLET(DFP)
- IF stat THEN 'error
- See: RenameFileDOSsrc
- ~RenameFileDOSsrc
- Func: RenameFileDOS Pack: DOSFilePack Func: 101/DOS
- DIM DFP AS DOSFilePack
- DIM TempStr AS STRING * 80
- DIM TempStr2 AS STRING * 80
- TempStr = file2rename$ + CHR$(0)
- TempStr2 = newfilename$ + CHR$(0)
- DFP.Func = RenameFileDOS 'defined in BULLET.BI
- DFP.FilenamePtrOff = VARPTR(TempStr)
- DFP.FilenamePtrSeg = VARSEG(TempStr)
- DFP.NewNamePtrOff = VARPTR(TempStr2)
- DFP.NewNamePtrSeg = VARSEG(TempStr2)
- stat = BULLET(DFP)
- IF stat THEN 'error
- See: CreateFileDOSsrc
- ~CreateFileDOSsrc
- Func: CreateFileDOS Pack: DOSFilePack Func: 102/DOS
- DIM DFP AS DOSFilePack
- DIM TempStr AS STRING * 80
- TempStr = file2create$ + CHR$(0)
- DFP.Func = CreateFileDOS 'defined in BULLET.BI
- DFP.FilenamePtrOff = VARPTR(TempStr)
- DFP.FilenamePtrSeg = VARSEG(TempStr)
- DFP.Attr = 0 'normal file directory attribute
- stat = BULLET(DFP)
- IF stat THEN 'error
- See: AccessFileDOSsrc
- ~AccessFileDOSsrc
- Func: AccessFileDOS Pack: DOSFilePack Func: 103/DOS
- DIM DFP AS DOSFilePack
- DIM TempStr AS STRING * 80
- TempStr = file2access$ + CHR$(0)
- DFP.Func = AccessFileDOS 'defined in BULLET.BI
- DFP.FilenamePtrOff = VARPTR(TempStr)
- DFP.FilenamePtrSeg = VARSEG(TempStr)
- DFP.ASmode = &H42 'attempt R/W DENY NONE access
- stat = BULLET(DFP)
- IF stat THEN 'error
- See: OpenFileDOSsrc
- ~OpenFileDOSsrc
- Func: OpenFileDOS Pack: DOSFilePack Func: 104/DOS
- DIM DFP AS DOSFilePack
- DIM TempStr AS STRING * 80
- TempStr = file2open$ + CHR$(0)
- DFP.Func = OpenFileDOS 'defined in BULLET.BI
- DFP.FilenamePtrOff = VARPTR(TempStr)
- DFP.FilenamePtrSeg = VARSEG(TempStr)
- DFP.ASmode = &H42 'open in R/W DENY NONE access
- stat = BULLET(DFP)
- IF stat = 0 THEN
- 'DFP.Handle set to handle of open file
- 'error
- See: SeekFileDOSsrc
- ~SeekFileDOSsrc
- Func: SeekFileDOS Pack: DOSFilePack Func: 105/DOS
- DIM DFP AS DOSFilePack
- DFP.Func = SeekFileDOS 'defined in BULLET.BI
- DFP.Handle = handle
- DFP.SeekOffset = 0& 'position 0 relative EOF (get length of file)
- DFP.Method = 2 'seek from END of file
- stat = BULLET(DFP)
- IF stat = 0 THEN
- 'DFP.SeekOffset set to absolute current offset
- '--in this case, the DFP.SeekOffset equals then length of the file
- 'error
- See: ReadFileDOSsrc
- ~ReadFileDOSsrc
- Func: ReadFileDOS Pack: DOSFilePack Func: 106/DOS
- DIM DFP AS DOSFilePack
- DIM ReadBuff AS STRING * 512 'sector buffer
- DFP.Func = ReadFileDOS 'defined in BULLET.BI
- DFP.Handle = handle
- DFP.Bytes = Bytes2Read '16-bit value, in this case 512 since that's
- DFP.BufferPtrOff = VARPTR(ReadBuff) 'the size of ReadBuff
- DFP.BufferPtrSeg = VARSEG(ReadBuff)
- stat = BULLET(DFP)
- IF stat = 0 THEN
- IF DFP.Bytes <> Bytes2Read THEN 'check if EOF processed
- 'hit EOF before reading all 512 bytes
- ELSE
- 'ReadBuff filled with 512 bytes of data read from the current disk pos
- 'disk position moved to the last byte read + 1
- ENDIF
- 'error
- See: ExpandFileDOSsrc
- ~ExpandFileDOSsrc
- Func: ExpandFileDOS Pack: DOSFilePack Func: 107/DOS
- DIM DFP AS DOSFilePack
- DFP.Func = ExpandFileDOS 'defined in BULLET.BI
- DFP.Handle = handle
- DFP.SeekOffset = Bytes2ExpandBy&
- stat = BULLET(DFP)
- IF stat = 0 THEN
- 'file expanded by number of bytes specified
- 'error
- See: WriteFileDOSsrc
- ~WriteFileDOSsrc
- Func: WriteFileDOS Pack: DOSFilePack Func: 108/DOS
- DIM DFP AS DOSFilePack
- DIM WriteBuff AS STRING * 512 'sector buffer
- DFP.Func = WriteFileDOS 'defined in BULLET.BI
- DFP.Handle = handle
- DFP.Bytes = Bytes2Write '16-bit value, in this case 512 since that's
- DFP.BufferPtrOff = VARPTR(WriteBuff) 'the size of WriteBuff
- DFP.BufferPtrSeg = VARSEG(WriteBuff)
- stat = BULLET(DFP)
- IF stat = -2 THEN
- 'disk full
- ELSE IF stat THEN
- 'other error
- 'okay
- Unlike ReadFileDOS, if the number of bytes actually written does not equal
- Bytes2Write, the WriteFileDOS routine returns a DISK FULL error code (-2).
- See: CloseFileDOSsrc
- ~CloseFileDOSsrc
- Func: CloseFileDOS Pack: DOSFilePack Func: 109/DOS
- DIM DFP AS DOSFilePack
- DFP.Func = CloseFileDOS 'defined in BULLET.BI
- DFP.Handle =handle2close
- stat = BULLET(DFP)
- IF stat THEN 'error
- See: MakeDirDOSsrc
- ~MakeDirDOSsrc
- Func: MakeDirDOS Pack: DOSFilePack Func: 110/DOS
- DIM DFP AS DOSFilePack
- DIM TempStr AS STRING * 80
- TempStr = subdir2make$ + CHR$(0)
- DFP.Func = MakeDirDOS 'defined in BULLET.BI
- DFP.FilenamePtrOff = VARPTR(TempStr)
- DFP.FilenamePtrSeg = VARSEG(TempStr)
- stat = BULLET(DFP)
- IF stat THEN 'error
- See: DeleteFileDOSsrc
-