The jBASE BASIC language provides an intrinsic function called IOCTL that behaves in a similar manner to the C function ioctl(). It's purpose is to allow commands to be sent to the database driver for a particular file, and then to receive a reply from the database driver.
As with the C function ioctl, the use of IOCTL is highly dependent upon the database driver it is talking to. Each database driver may choose to provide certain common functionality, or may add its own commands and so on. This is especially true of user-written database drivers.
The IOCTL function can be used to manipulate sequential files using these Sequential File Extensions.
First, an example of a source program that opens a file and finds the type of file:
If the ELSE clause is taken, it does not necessarily mean there is an error, it only means that the database driver for file "MD" does not support the command that was requested from it. The file JBC.h is supplied with jBASE in the directory JBCRELEASEDIR sub directory include. If the source is compiled with the jbc or BASIC command, this directory is automatically included in the search path and no special action is needed by the programmer for the "INCLUDE JBC.h" statement.
The format of the IOCTL function is:
IOCTL( Filevar, Command, Parameter)
Filevar Is a variable that has had a file opened against it using the OPEN statement. However, if you want to use the default file variable, use -1 in this position. For example:
Command Can be any numeric value (or variable containing a numeric). However, it is up to the database driver to support that particular command number. The remainder of this chapter describes the common IOCTL command numbers supported by the jBASE database drivers provided.
Status Pass here a jBC variable. The use of this variable depends upon the command parameter, and will be described later for each command supported.
The return value is 0 for failure, or 1 for success. A value of -1 generally shows the command has not been recognized.
The remainder of this chapter will deal with the IOCTL commands that are supported by the provided jBASE database drivers, and the JBC_COMMAND_GETFILENAME command that is supported for all database drivers.
Using this command to the IOCTL function, you can determine the exact file name that was used to open the file. This is helpful because jEDI uses Q pointers, F pointers and the JEDIFILEPATH environment variable to actually open the file, and the application can never be totally sure where the resultant file was really opened. Normally of course, this is of no concern to the application.
Open the file CUSTOMERS and find out the exact path that was used to open the file.
This command is executed by the jBC library code rather than the jEDI library code or the database drivers, so it can be run against a file descriptor for any file type.
Some of the jBC database drivers will perform an automatic conversion of the input and output record when performing reads and writes.
An example of this is when writing to a directory. In this case, the attribute marks will be converted to new-line characters and a trailing new-line character added. Similarly for reading from a directory the new-line characters will be replaced with attribute marks, and the trailing new-line character will be deleted.
The above example is what happens for the database driver for directories. It assumes by default that the record being read or written is a text file and that the conversion is necessary. It tries to apply some intelligence to reading files, as text files always have a trailing new-line character. Therefore, if a file is read without a trailing new-line character, the database driver assumes the file must be a binary file rather than a text file, and no conversion takes place.
This conversion of data works in most cases and usually requires no special intervention from the programmer.
There are cases however, when this conversion needs to be controlled and interrogated, and the IOCTL function call with the JIOCTL_COMMAND_CONVERT command provides the jBASE database drivers that support this conversion with commands to control it.
The call to IOCTL, if successful, will only affect file operations that use the same file descriptor. Consider the following code:
In the above example, any future file operations using variable FILEVAR1 will be controlled by the change forced in the IOCTL request. Any file operations using variable FILEVAR2 will not be affected and will use the default file operation.
Input to the IOCTL is a string of controls delimited by a comma that tell the database driver what to do. The output from the IOCTL can optionally be a string to show the last conversion that the driver performed on the file.
The description of the available controls that can be passed as input to this IOCTL function are:
The application wants to open a file, and to ensure that all reads and writes to that file are in binary, and that no translation such as new-lines to attribute marks are performed.
Read a record from a file, and find out if the last record read was in text format (were new-lines converted to attribute marks and the trailing new-line deleted), or in binary format (with no conversion at all).
The JIOCTL_COMMAND_FILESTATUS command will return an attribute delimited list of the status of the file to the caller.
Open a file and see if the file type is a directory.
Open a file ready to perform file operations in a transaction against it. Make sure the file has not been removed as a transaction type file by a previous invocation of the command "jchmod -T CUSTOMERS".
This command will find out if a record exists on a file without the need to actually read in the record. This can provide large performance gains in certain circumstances.
Before writing out a control record, make sure it doesn't already exist. As the control record is quite large, it will provide performance gains to simply test if the output record already exists, rather than reading it in using the READ statement to see if it exists.
This command to the IOCTL function returns the record size and the time and date the record was last updated. If the record does not exist, null is returned. The time/date stamp is returned in UTC format.
Print the time and data of last update for each record in filename.
For jBASE hashed files such as j3 and j4 each record is pseudo-randomly written to one of the buckets (or groups) of the hashed file. The actual bucket it is written to depends upon two factors:
This IOCTL command shows which bucket number the record would be found in, given the input record key. The bucket number is in the range 0 to (b-1) where b is the number of buckets in the file specified when the file was created (probably using CREATE-FILE).
The command only returns the expected bucket number, as is no indication that the record actually exists in the file.
Two attributes are returned by this command. The first is the hash value that the record key has hashed to, and the second attribute is the bucket number.
Open a file, and find out what bucket number the record "PIPE&SLIPPER" would be found in.
The jEDI locking mechanism for records in jEDI provided database drivers is not strictly a 100% record locking mechanism. Instead, it uses the hashed value of the record key to give a value from 0 to 230-1 to describe the record key. The IOCTL command can be used to determine how a record key would be converted into a hashed value for use by the locking mechanism.
Lock a record in a file and find out what the lock id of the record key is. The example then calls the jRLA locking demon and the display of locks taken should include the lock taken by this program.