Data Storage and Retrieval

This chapter describes some useful techniques for storing and retrieving data.

Storing Data in Programs

This section describes a number of ways to store values in memory. In general, these techniques involve using program variables to store data. The data are kept with the program when it is stored on a mass storage device (with STORE and SAVE). These techniques allow extremely fast access of the data. They provide good use of the computer's memory for storing relatively small amounts of data.

Storing Data in Variables

The easiest method of storing data is to use a simple assignment, such as the following LET statements:

 
100   LET Cm_per_inch=2.54
110   Inch_per_cm=1/Cm_per_inch
 

This technique works well when there are only a relatively few items to be stored or when several data values are to be computed from the value of a few items. The program will execute faster when variables are used than when expressions containing constants are used; for instance, using the variable Inch_per_cm in the preceding example would be faster than using the constant expression 1/2.54.

Data Input by the User

You also can assign values to variables at run-time with the INPUT and LINPUT statements as shown in the following examples.

 
100   INPUT "Type in the value of X, please.",Id
  .
  .
  .
200   DISP "Enter the value of X, Y, and Z.";
210   LINPUT "",Response$
 

Note that with this type of storage, the values assigned to the corresponding variables are not kept with the program when it is stored; they must be entered each time the program is run.

Using DATA and READ Statements

The DATA and READ statements provide another technique for storing and retrieving data from the computer's memory. The DATA statement allows you to store a stream of data items in memory, and the READ statement allows you retrieve data items from the stream.

You can have any number of READ and DATA statements in a program in any order you want. When you RUN a program, the system concatenates all DATA statements in the same context into a single "data stream." Each subprogram has its own data stream.

For example:

 
100 DATA 1,A,50
      .
      .
      .
200 DATA "BB",20,45
      .
      .
      .
300 DATA X,Y,77
 

As you can see, a data stream can contain both numeric and string data items; however, each item is stored as if it were a string.

Each data item must be separated by a comma and can be enclosed in optional quotes. Strings that contain a comma, exclamation mark, or quote mark must be enclosed in quotes. In addition, you must enter two quote marks for every one you want in the string. For example, to enter the string QUOTE"QUO"TE into a data stream, you would write:

 
100 DATA "QUOTE""QUO""TE"  
 

To retrieve a data item, assign it to a variable with the READ statement. For example:

 
100 READ X,Y,Z$ 
 

would read three data items from the data stream into the three variables. Note that the first two items are numeric and the third is a string variable.

Numeric data items can be READ into either numeric or string variables. If the numeric data item is of a different type than the numeric variable, the item is converted (i.e., REALs are converted to INTEGERs, and INTEGERs to REALs). If the conversion cannot be made, an error is returned. A READ into a COMPLEX variable is satisfied with two REAL DATA values. Strings that contain non-numeric characters must be READ into string variables. If the string variable has not been dimensioned to a size large enough to hold the entire data item, the data item is truncated.

The system keeps track of which data item to READ next by using a "data pointer." Every data stream has its own data pointer which points to the next data item to be assigned to the next variable in a READ statement. When you run a program segment, the data pointer is placed initially at the first item of the data stream. Every time you READ an item from the stream, the pointer is moved to the next data item. If a subprogram is called by a context, the position of the data pointer is recorded and then restored when you return to the calling context.

Starting from the position of the data pointer, data items are assigned to variables one by one until all variables in a READ statement have been given values. The exception is when a COMPLEX variable is read -- two numeric data items are consumed. If there are more variables than data items, the system returns an error, and the data pointer is moved back to the position it occupied before the READ statement was executed.

Examples

The following example shows how data is stored in a data stream and then retrieved. Note that DATA statements can come after READ statements even though they contain the data being READ. This is because DATA statements are linked during program pre-run, whereas READ statements aren't executed until the program actually runs.

 
10  DATA November,26
20  READ Month$,Day,Year$
30  DATA 1981,"The date is"
40  READ Str$
50  Print Str$;Month$,Day,Year$
60  END

  The date is November 26 1981
 

Storage and Retrieval of Arrays

In addition to using READ to assign values to string and numeric variables, you can also READ data into arrays. The system will match data items with variables one at a time until it has filled a row. The next data item then becomes the first element in the next row. You must have enough data items to fill the array or you will get an error. In the examples below, we show how REAL and COMPLEX DATA values can be assigned to elements of a 3-by-3 numeric array.

 
10    OPTION BASE 1
20    DIM Example1(3,3)
30    DATA 1,2,3,4,5,6,7,8,9,10,11
40    READ Example1(*)
50    PRINT USING "3(K,X),/";Example1(*)
60    END

 1 2 3
 4 5 6
 7 8 9
 
 
10    OPTION BASE 1
20    COMPLEX Example2(3,3)
30    DATA 23,-2,-1,10,-6,-7,4,5,-8,10,1,1,34,2,9,17,-12,-14
40    READ Example2(*)
50    PRINT USING "3(3D,X,3D,3X),/";Example2(*)
60    END

23  -2    -1  10    -6  -7
 4   5    -8  10     1   1
34   2     9  17   -12 -14
 

In the first example, the data pointer is left at item 10; thus, items 10 and 11 are saved for the next READ statement. In the second example, there are just enough items to fill each element of the complex array.

Moving the Data Pointer

In some programs, you will want to assign the same data items to different variables. To do this, you have to move the data pointer so that it is pointing at the desired data item. You can accomplish this with the RESTORE statement. If you don't specify a line number or label, RESTORE returns the data pointer to the first data item in the data stream. If you do include a line identifier in the RESTORE statement, the data pointer is moved to the first data item in the first DATA statement at or after the identified line.

 
100   DIM Array1(1:3)   ! Dimensions a 3-element array.
110   DIM Array2(0:4)   ! Dimensions a 5-element array.
120   DATA 1,2,3,4      ! Places 4 items in stream.
130   DATA 5,6,7        ! Places 3 items in stream.
140   READ A,B,C        ! Reads first 3 items in stream.
150   READ Array2(*)    ! Reads next 5 items in stream.
160   DATA 8,9          ! Places 2 items in stream.
170                     !
180   RESTORE           ! Re-positions pointer to 1st item.
190   READ Array1(*)    ! Reads first 3 items in stream.
200   RESTORE 140       ! Moves data pointer to item "8".
210   READ D            ! Reads "8".
220                     !
230   PRINT "Array1 contains:";Array1(*);" "
240   PRINT "Array2 contains:";Array2(*);" "
250   PRINT "A,B,C,D equal:";A;B;C;D
260   END

Array1 contains: 1 2 3
Array2 contains: 4 5 6 7 8
A,B,C,D equal: 1 2 3 8
 

File Input and Output (I/O)

This section describes the second general class of data storage and retrieval--mass storage files. It presents an overview of the available file types, and the BASIC programming techniques for accessing files. For a more detailed discussion of file I/O topics — including the internal data representation in files, the effect of record length, and end-of-file pointers — refer to "A Closer Look at File I/O" in the HP BASIC Advanced Programming Techniques manual.

For background information about files and mass storage organization, refer to one of the following manuals, depending on the implementation of BASIC you are using:

Brief Comparison of Available File Types

HP BASIC provides four different types of files in which you can store and retrieve data.
NOTE
File type is essentially independent of volume and directory type. ASCII and BDAT files can exist in LIF, HFS, SRM, SRM/UX, or DFS volumes and directories (for HP 9000 computers or for the HP Measurement Coprocessor). DOS files can exist only in a DFS directory (for the HP Measurement Coprocessor).

NOTE
You can, however, format the data to be sent to an ASCII file by first sending it to a string variable with OUTPUT...USING. You can then OUTPUT the string's formatted contents to a data file. Refer to the HP BASIC Advanced Programming Techniques manual for details.

In brief, choose a BDAT file for speed and compact data storage. Choose an ASCII, HP-UX, or DOS file for compatibility with operating systems and other computers.

Overview of File I/O

Storing data in files requires a few simple steps. The following program segment shows a simple example of placing several items in a data file.

 
100  REAL Real_array1(1:50,1:25),Real_array2(1:50,1:25)
110  INTEGER Integer_var
120  DIM String$[100]
       .
       .
390  ! Specify default mass storage.
400  MASS STORAGE IS ":,700,1"
410  !
420  ! Create BDAT data file with ten (256-byte) records
430  ! on the specified mass storage device (:,700,1).
440  CREATE BDAT "File_1",10
450  !
460  ! Assign (open) an I/O path name to the file.
470  ASSIGN @Path_1 TO "File_1"
480  !
490  ! Write various data items into the file.
500  OUTPUT @Path_1;"Literal"       ! String literal.
510  OUTPUT @Path_1;Real_array1(*)  ! REAL array.
520  OUTPUT @Path_1;255             ! Single INTEGER.
530  !
540  ! Close the I/O path.
550  ASSIGN @Path_1 TO *
     .
     .
     .
790  ! Open another I/O path to the file (assume same default drive).
800  ASSIGN @F_1 TO "File_1"
810  !
820  ! Read data into another array (same size and type).
830  ENTER @F_1;String_var$         ! Must be same data types
840  ENTER @F_1;Real_array2(*)      ! used to write the file.
850  ENTER @F_1;Integer_var         ! "Read it like you wrote it."
860  !
870  ! Close I/O path.
880  ASSIGN @F_1 TO *
 

Line 400 specifies the default mass storage device, which is to be used whenever a mass storage device is not explicitly specified during subsequent mass storage operations. The term mass storage volume specifier (msvs) describes the string expression used to uniquely identify which device is to be the mass storage. In this case, ":,700,1" is the msvs.

In order to store data in mass storage, a data file must be created (or already exist) on the mass storage media. In this case, line 440 creates a BDAT file (later sections describe using HP-UX and ASCII files); the file created contains 10 defined records of 256 bytes each. (Defined records and record size are discussed in the HP BASIC Advanced Programming Techniques manual.)

The term file specifier describes the string expression used to uniquely identify the file. In this example, the file specifier is simply File_1, which is the file's name. If the file is to be created (or already exists) on a mass storage device other than the default mass storage, the appropriate msus must be appended to the file name. If that device has a hierarchical directory format (such as HFS or SRM disks), then you may also have to specify a directory path (such as /USERS/MARK/PROJECT_1).

Then, in order to store data in (or retrieve data from) the file, you must assign an I/O path name to the file. Line 470 shows an example of assigning an I/O path name to the file (also called opening an I/O path to the file). Lines 500 through 520 show data items of various types being written into the file through the I/O path name.

The I/O path name is closed after all data have been sent to the file. In this instance, closing the I/O path may have been optional, because a different I/O path name is assigned to the file later in the program. (All I/O path names are automatically closed by the system at the end of the program.) Closing an I/O path to a file updates the file pointers.

Since these data items are to be retrieved from the file, another ASSIGN statement is executed to open the file (line 800). Notice that a different I/O path name was arbitrarily chosen. Opening this I/O path name to the file sets the file pointer to the beginning of the file. (Re-opening the I/O path name @File_1 would have also reset the file pointer.)

Notice also that the msvs is not included with the file name. This shows that the current default mass storage device, here ":,700,1", is assumed when a mass storage device is not specified.

The subsequent ENTER statements read the data items into variables; with BDAT and HP-UX files (when using the BASIC internal (FORMAT OFF) data representation), the data type of each variable must match the data type type of each data item. (This topic is discussed in the HP BASIC Advanced Programming Techniques manual.) With ASCII files, for instance, you can read INTEGER items into REAL variables and not have problems.

This is a fairly simple example; however, it shows the general steps you must take to access files.

A Closer Look at General File Access

Before you can access a data file, you must assign an I/O path name to the file. Assigning an I/O path name to the file sets up a table in computer memory that contains various information describing the file, such as its type, which mass storage device it is stored on, and its location on the media. The I/O path name is then used in I/O statements (OUTPUT, ENTER, and TRANSFER) which move the data to and from the file. I/O path names are also used to transfer data to and from devices. Data transfers with devices and general I/O techniques are covered later in this manual. However, in this chapter we deal mostly with I/O paths to files.

Every I/O path to a file maintains the following information:
Validity Flag Tells whether the path is currently opened (assigned) or closed (not assigned).
Type of Resource Holds the file type: ASCII, BDAT, or HP-UX.
Device Selector Stores the device selector of the drive. (I/O paths can also be associated with devices and buffers. See chapters 17 and 19 for further details.)
Attributes Such as FORMAT OFF and FORMAT ON, BYTE, and PARITY ODD.
File Pointer There is a file pointer that points to the place in the file where the next data item will be read or written. The file pointer is updated whenever the file is accessed.
End-Of-File Pointer An I/O path has an EOF pointer that points to the byte that follows the last byte of the file.

Opening an I/O Path

I/O path names are similar to other variable names, except that I/O path names are preceded by the "@" character. When an I/O path name is used in a statement, the system looks up the contents of the I/O path name and uses them as required by the situation.

To open an I/O path to a file, assign the I/O path name to a file specifier by using an ASSIGN statement. For example, executing the following statement:

 
ASSIGN @Path1 TO "Example" 
 

assigns an I/O path name called @Path1 to the file Example. The file that you open must already exist and must be a data file. If the file does not satisfy one of these requirements, the system will return an error. If you do not use an msus in the file specifier, the system will look for the file on the current MASS STORAGE IS device. If you want to access a different device, use the msus syntax described earlier. For instance, the statement:

 
ASSIGN @Path2 TO "Example:HP9122,700" 
 

opens an I/O path to the file Example on an HP 9122 disk drive, interface select code 7 and primary address 0. You must include the protect code or password, if the LIF or SRM file has one, respectively.

ASSIGNing an I/O path name to a file has the following effect on the I/O path table:

Once an I/O path has been opened to a file, you always use the path name to access the file. An I/O path name is only valid in the context in which it is opened, unless you pass it as a parameter or put it in the COM area. To place a path name in the COM area, simply specify the path name in a COM statement before you ASSIGN it. For instance the two statements below would declare an I/O path name in an unnamed COM area and then open it:

 
100   COM @Path3
110   ASSIGN @Path3 TO "File1"
 

Assigning Attributes

When you open an I/O path, certain attributes are assigned to it which define the way data is to be read and written. There are two attributes which control how data items are represented: FORMAT ON and FORMAT OFF.

Additional attributes are available, which provide control of such functions as parity generation and checking, converting characters, and changing end-of-line (EOL) sequences. See ASSIGN in the HP BASIC Language Reference, or "I/O Path Attributes" (chapter 19) in this manual for further details.

As mentioned in the tutorial section, BDAT files can use either data representation; however, ASCII files permit only ASCII-data format. Therefore, if you specify FORMAT OFF for an I/O path to an ASCII file, the system ignores it. The following ASSIGN statement specifies a FORMAT attribute:

 
ASSIGN @Path1 TO "File1";FORMAT OFF 
 

If File1 is a BDAT or HP-UX file, the FORMAT OFF attribute specifies that the internal data formats are to be used when sending and receiving data through the I/O path. If the file is of type ASCII, the attribute will be ignored. Note that FORMAT OFF is the default FORMAT attribute for BDAT and HP-UX files.

Executing the following statement directs the system to use the ASCII data representation when sending and receiving data through the I/O path:

 
ASSIGN @Path2 TO "File2";FORMAT ON 
 

If File2 is a BDAT or HP-UX file, data will be written using ASCII format, and data read from it will be interpreted as being in ASCII format. For an ASCII file, this attribute is redundant since ASCII-data format is the only data representation allowed anyway.

If you want to change the attribute of an I/O path, you can do so by specifying the I/O path name and attribute in an ASSIGN statement while excluding the file specifier. For instance, if you wanted to change the attribute of @Path2 to FORMAT OFF, you could execute:

 
ASSIGN @Path2;FORMAT OFF 
 

Alternatively, you could re-enter the entire statement:

 
ASSIGN @Path2 TO "File2";FORMAT OFF 
 

These two statements, however, are not identical. The first one only changes the FORMAT attribute. The second statement resets the entire I/O path table (e.g., resets the file pointer to the beginning of the file).

It is important to note that once a file is written, changing the FORMAT attribute of an I/O path to the file should only be attempted by experienced programmers. In general, data should always be read in the same manner as it was written. For instance, data written to a BDAT or HP-UX file with FORMAT OFF should also be read with FORMAT OFF, and vice versa. In addition, the same data types should be used to write the file as to read the file. For instance, if data items were written as INTEGERs, they should also be read as INTEGERs (this is mandatory with FORMAT OFF, but not always necessary with FORMAT ON).

In theory, there is no limit to the number of I/O paths you can ASSIGN to the same file. Each I/O path, however, has its own file pointer and EOF pointer, so that in practice it can become exceedingly difficult to keep track of where you are in a file if you use more than one I/O path. We recommend that you use only one I/O path at any one time for each file.

Closing I/O Paths

I/O path names not in the COM area are closed whenever the system moves into a stopped state (e.g., STOP, END, SCRATCH, EDIT, etc.). I/O path names local to a context are closed when control is returned to the calling context. Re-ASSIGNing an I/O path name will also cancel its previous association.

You can also explicitly cancel an I/O path by ASSIGNing the path name to an * (asterisk). For instance, the statement:

 
ASSIGN @Path2 TO * 
 

closes @Path2 (sets the validity flag to Closed). @Path2 cannot be used again until it is re-assigned. You can re-assign a path name to the same file or to a different file.

Locking Files

Although sharing files between people saves disk space, it introduces the danger of several people trying to access a file at the same time. For instance, one person may read a file while another person is writing to it, and the file's contents may be inaccurate.

LOCK establishes exclusive access to a file: it can only be accessed from the workstation where the LOCK was executed. The typical procedure is:

  1. LOCK all critical files.
  2. Read data from files.
  3. Update the data.
  4. Write the data into the files.
  5. UNLOCK all critical files to permit shared access again.

Example Locking and Unlocking of an SRM File

In this example, a critical operation must be performed on the file named File_a, and you do not want other people accessing the file during that operation.

 
1000   ASSIGN @File TO "File_a:REMOTE"
1010   LOCK @File;CONDITIONAL Result_code
1020   IF Result_code THEN GOTO 1010  ! Try again
1030   !  Begin critical process
       .
       .
       .
2000   !  End critical process
2010   UNLOCK @File
 

The numeric variable called Result_code is used to determine the result of the LOCK operation. If the LOCK operation is successful, the variable contains 0. If the LOCK is not successful, the variable contains the numeric error code generated by attempting to lock the file.

HP BASIC/UX Specifics on Locking SRM Files

NOTE
Locking and Unlocking SRM files is not supported on HP BASIC/UX Series 700 computers.

HP BASIC/UX allows several instances of HP BASIC to be run on the same system. However, the SRM server assumes that each client is running on a different system. Because of this, the semantics of LOCK are different if more than one HP BASIC/UX process is trying to access the same file at the same time. An ENTER normally hangs until the file is unlocked. If the file is locked by another HP BASIC/UX process on the same system, however, the ENTER returns error 481.

Locking HFS Files (HP BASIC/UX ONLY)

HP BASIC/UX supports locking and unlocking of HFS files in addition to SRM files. In general, the behavior of LOCK and UNLOCK for HFS is similar to the behavior for SRM. HFS LOCK attempts to exclusively lock the whole file, if possible. It also keeps track of nested locks, and all locks are released when the file is closed. In addition, if the file is already locked, the LOCK command does not block.

However, there are some differences due to the locking mechanism in the HP-UX operating system.

To exclusively lock a file, the following conditions must be met:

Unless the first condition is met, the file will not be locked. If the second condition is not met, an advisory mode lock will be placed instead of an enforced mode lock.

In addition, the following limitations apply to HFS locking:

NOTE
For more advanced file I/O programming techniques, refer to "A Closer Look at File I/O" in the HP BASIC Advanced Programming Techniques manual.

Extended Access of Directories

The CAT statement has the following additional capabilities:

Cataloging to a String Array

The following example program segment shows an example of directing the catalog of mass storage file entries to the CRT and then to a string array.

 
100   PRINT "          CAT to CRT."
110   PRINT "-----------------------------------"
120   CAT TO #CRT;COUNT Files_and_headr  ! Includes 5-line header.
130   PRINT "Number of files=";Files_and_headr-5
140   PRINT
150   !
160   PRINT "     CAT to a string array."
170   PRINT "-----------------------------------"
180   Array_size=Files_and_headr+2  ! Allow for 7-line header.
190   ALLOCATE Catalog$(1:Array_size)[80]
200   CAT TO Catalog$(*)
210   FOR Entry=1 TO Array_size
220     PRINT Catalog$(Entry)
230   NEXT Entry
240   PRINT "Number of files=";Array_size-7
250   PRINT
260   !
270   END
 

The program produces the following output.

 

          CAT to CRT.
-----------------------------------
:INTERNAL
VOLUME LABEL: B9836
FILE NAME PRO TYPE  REC/FILE BYTE/REC   ADDRESS    DATE     TIME
Data1         ASCII        3      256        16  12-Jan-87  12:30
Chap1         BDAT         3      256        20  13-Jan-87   8:00
Prog1         PROG         2      256        23  14-Jan-87   9:10
Chap2         BDAT         7      256        26  14-Jan-87  10:15
Prog2         PROG         2      256        33  14-Jan-87  12:30
Data2         ASCII        9      256        35   3-Mar-87   6:45
Number of files= 6 
 
 

     CAT to a string array.
-----------------------------------
:INTERNAL, 4
LABEL:  B9826
FORMAT: LIF
AVAILABLE SPACE:   892
                           SYS  FILE   NUMBER   RECORD     MODIFIED     PUB
OPEN
FILE NAME             LEV TYPE  TYPE  RECORDS   LENGTH DATE        TIME ACC
STAT
===================== === ==== ===== ======== ======== ================ ===
====
Data1                   1      ASCII        3      256 12-Jan-87  12:30 MRW
Chap1                   1 98X6 BDAT         3      256 13-Jan-87   8:00 MRW
Prog1                   1 98X6 PROG         2      256 14-Jan-87   9:10 MRW
Chap2                   1 98X6 BDAT         7      256 14-Jan-87  10:15 MRW
Prog2                   1 98X6 PROG         2      256 14-Jan-87  12:30 MRW
Data2                   1      ASCII        9      256  3-Mar-87   6:45 MRW
Number of files= 6
 

You may have noticed that the format for catalogs sent to string arrays (the second catalog listing) is different from catalogs sent to the PRINTER IS device. The format for catalogs sent to string arrays is the SRM catalog format, which requires that each array element must be dimensioned to hold at least 80 characters with this type of CAT operation. Again, the header contains 7 lines, not 5 as with catalogs sent to devices.

Getting an "Extended" Catalog of a LIF, HFS Disk, or SRM/UX Volume

When you are cataloging an HFS or LIF directory to a string array, the catalog format is normally that of an SRM catalog. However, you can also specify an HFS- or LIF-format catalog listing with the following syntax:

 
100   CAT TO String_array$(*); EXTEND 
 

For an explanation of the HFS catalog listing, see the HP BASIC Language Reference description of CAT.

Getting a Count of Files Cataloged

Including the keyword COUNT followed by a numeric variable returns the total number of file entries plus header lines to that variable; in the preceding example program, the variable Files_and_headr is used:

 
20   CAT TO #CRT;COUNT Files_and_headr ! Includes 5-line header.
 

In the above example, line 180 adds 2 to the variable Files_and_headr to compensate for the 7-line header which is sent instead of the usual 5-line header (the next section shows how to suppress the header) and stores the result in Array_size. Array_size is then used to direct the computer to ALLOCATE just enough space in a string-array variable to hold the directory listing. The program can then search the directory listing for further information, if desired.

If the CAT operation would not have filled the string array, the unused array elements would have been set to the null string (i.e., strings of length 0). If there are more catalog lines than string-array elements, the operation stops when the array is filled. No indication of the "overflow" is reported; the count returned is equal to the number of array elements.

Suppressing the Catalog Header

To suppress the catalog header, use the following syntax:

 
CAT;NO HEADER
CAT TO String_array$(*);NO HEADER
CAT "Prog_2";NO HEADER
 

Using NO HEADER suppresses the 5-line heading of a LIF catalog format or 7-line heading of an SRM or HFS catalog format. The catalog listing of a PROG file would be 4 lines shorter. The first line of each catalog listing contains the first directory entry, the second element contains the second entry, and so forth.

If the COUNT option is included, the count returned is the total number of selected files.

Cataloging Selected Files

The directory entries for files can be selectively obtained either by using the secondary keyword SELECT or by using wildcards. An example will be given using both methods. For both examples, assume that the directory contains the following entries:

 

:INTERNAL
VOLUME LABEL: B9836
FILE NAME PRO TYPE  REC/FILE BYTE/REC   ADDRESS    DATE     TIME
Data1         ASCII        3      256        16  12-Jan-87  12:30
Chap1         BDAT         3      256        20  13-Jan-87   8:00
Prog1         PROG         2      256        23  14-Jan-87   9:10
Chap2         BDAT         7      256        26  14-Jan-87  10:15
Prog2         PROG         2      256        33  14-Jan-87  12:30
Data2         ASCII        9      256        35   3-Mar-87   6:45
Chap3         BDAT         6      256        45   3-Mar-87   7:15
Number of files= 7
 

CAT with the SELECT Secondary

Suppose that you want to catalog only files beginning with the letters "Prog". The following examples show how this may be accomplished. Notice that this is not the same operation as getting a catalog of a PROG-type file.

 

 Beginning_chars$="Prog"
 CAT;SELECT Beginning_chars$

 CAT;SELECT "Prog",COUNT Files_and_headr
 

Result:

 

:INTERNAL, 4
VOLUME LABEL: B9836
FILE NAME PRO TYPE  REC/FILE BYTE/REC   ADDRESS    DATE     TIME
Prog1         PROG         2      256        23  12-Jan-87  12:30
Prog2         PROG         2      256        33  13-Jan-87   8:00
 

The directory entries of the files beginning with the letters "Prog" are sent to the PRINTER IS device. In the second CAT statement above, the variable Files_and_headr is filled with the number of selected files found on the current default mass storage device plus 5 or 7 header lines. Both CAT statements above go to the PRINTER IS device (or file).

SELECT may also be used to get the catalog of an individual file entry by selecting the entire file name, as shown in the following statement:

 
CAT;SELECT "Chap3" 
 

Note that if any other files begin with the letters "Chap3", they will also be listed.

CAT with Wildcards

Suppose that you wanted to catalog only files which began with the letters "C" or "D" and did not end with the digit "3". The following examples show how this might be accomplished when HP-UX style wildcards are enabled. First, enable wildcard recognition using:

 
WILDCARDS UX;ESCAPE"\"
 

Then catalog the directory using:

 
CAT "[CD]*[!3]"

CAT "[CD]*[!3]",COUNT Files_and_headr
 

Only 4 entries in the directory match this wildcard argument. The directory entries of the 4 entries are sent to the PRINTER IS device. In the second CAT above, the variable Files_and_headr is filled with the number of files on the current default mass storage device that match the wildcard argument plus 5 or 7 header lines. Both CAT statements above go to the PRINTER IS device (or file).

The following result would be sent to the system printing device.

 
:INTERNAL, 4
VOLUME LABEL: B9836
FILE NAME PRO TYPE  REC/FILE BYTE/REC    ADDRESS    DATE     TIME
Data1         ASCII        3      256         16  12-Jan-87  12:30
Chap1         BDAT         3      256         20  13-Jan-87   8:00
Chap2         BDAT         7      256         26  14-Jan-87  10:15
Data2         ASCII        9      256         35   3-Mar-87   6:45
 

Using wildcards with CAT is much more powerful than using the SELECT secondary.

Getting a Count of Selected Files

It is often desirable to determine the total number of files on a disk or the number that begin with a certain character or march a certain wildcard argument. The COUNT option directs the computer to return the number of selected files in the variable that follows the COUNT keyword.

 

CAT;COUNT Files_and_headr
CAT;SELECT "Data",COUNT Selected_files,NO HEADER
CAT"*[0-9]",COUNT Selected_files,NO HEADER
 

The first CAT operation returns a count of all files in the directory plus 5 or 7 header lines, since not including SELECT defaults to "select all files". The second operation returns a count of the specifically selected files. If HP-UX style wildcards are enabled, the third operation returns a count of all the files having names which end in a digit. Keep in mind that the number of selected files includes the number of files sent to the destination plus the number of files skipped, if any.

Catalogs sent to external devices in the LIF format have a five-line header; in SRM and HFS formats they have seven-line headers. Catalogs to string arrays are SRM format unless EXTEND is added. Catalogs of individual PROG-type files have a three-line header and a one-line trailer. If an "overflow" of a string array occurs, the count is set to the number of string-array elements plus the number of files skipped. If no entries are sent to the destination (because the directory is empty, or because no entries were selected, or because all selected entries were skipped), the value returned depends on whether there is a header. If there is no header, then zero (0) is returned. If there is a header, then the value returned is the size of the header plus the number following the skip option (the number requested to be skipped).

If an option is given more than once, only the last instance is used.

Skipping Selected Files

If there are many files that begin with the same characters, it is often useful to be able to skip some of the directory entries so that the catalog is not as long. This may be especially useful when using a drive such as an HP 7912, which has the capability of storing more than 10 000 files.

The following statement shows an example of skipping file entries before sending selected entries to the destination.

 

   CAT;SELECT "BCD",SKIP 5

:INTERNAL, 4
VOLUME LABEL: B9836
FILE NAME PRO TYPE  REC/FILE BYTE/REC   ADDRESS    DATE     TIME
BCD_ENTFMT    ASCII       10      256        73  13-Jan-87   8:00
 

The first five "selected" files (that begin with the specified characters) are "skipped" (i.e., not sent with the rest of the catalog information).

Including COUNT in the previous CAT operation (as shown below) returns a count of the selected files (plus header lines), not just the catalog lines sent to the destination. Remember that selected files includes all files skipped, if any. In this case, a value of 11 is returned, not 1 (or 6) as might be expected.

 
CAT;SELECT "BCD",SKIP 5,COUNT Catalog_lines 
 

Note that if SKIP is included, the count remains the same (as long as at least one file is cataloged). If the number of files to be skipped equals the number of files selected, COUNT returns a value of zero.

 
CAT;SELECT "BCD",SKIP 6,COUNT Files_and_headr 
 

The following program shows an example of looking at the files in a catalog by viewing a small "window" of files at one time. The technique is useful for decreasing the amount of memory required to hold a catalog listing in a string array.

 
100   ! Declare a small string array (7 elements).
110   DIM Array$(1:7)[80]
120   !
130   ! Send header to the array.
140   CAT TO Array$(*)
150   ! Print header.
160   FOR Element=1 TO 7
170     PRINT Array$(Element)[1,45]
180   NEXT Element
190   !
200   ! Now get 7-line "windows" and print files therein.
210   First_file=1  ! Begin with first file in directory.
220   REPEAT  ! Send file entries to Array$ until last file sent.
230     !
240     ! Send files to Array$; SKIP files already printed;
250     ! return index (with COUNT) of last file sent to Array$.
260     CAT TO Array$(*);SKIP First_file-1,COUNT Last_file,NO HEADER
270     DISP "First file=";First_file;"; Last file=";Last_file
280     !
290     ! Print file entries (no entry printed when Last_file=0).
300     FOR Element=1 TO (Last_file-First_file)+1  ! (6 or less)+1.
310       PRINT Array$(Element)[1,45]
320     NEXT Element
330     !
340     First_file=Last_file+1  ! Point to next "window."
350     !
360   UNTIL Last_file=0  ! Until SKIP >= number of files.
370   !
380   END
 

HFS File Buffering (HP BASIC/UX only)

File buffering increases the efficiency and speed of accessing files. (Note that it is only available with files on HFS-formatted disks.)

What Is File Buffering?

File buffering means temporarily storing data to be sent to or received from a file in a memory buffer (instead of immediately writing to or reading from the disk). HP BASIC/UX puts data that is to be sent to a file in HP-UX's large cache buffer (in computer memory). Each file currently open has a portion of the buffer space in this cache. BASIC keeps putting data into the buffer cache until it is full, and then sends it to the disk all at once.
NOTE
The buffer is also "flushed" at other times; for instance, when a file is closed or when a program ends. The above explanation has been simplified for clarity. A complete list of situations when buffers are flushed is described in the subsequent section called "Flushing the File Buffer".

This buffering process saves time and disk wear by consolidating several small disk-write operations into a larger one. However, there is a risk that you may lose data if power fails before data in the buffer has been written to the disk. You can also lose data if the system is shut down improperly.

Turning File Buffering On and Off

Use CONTROL register 9 to turn HFS file buffering on and off. For example:

 
ASSIGN @Io_path to "file" must assign an I/O path
CONTROL @Io_path,9;1  turn buffering on

CONTROL @Io_path,9;0 turn buffering off

STATUS @Io_path,9;Status_var check status of file buffering
 

If the value returned in Status_var is 1, then file buffering is on; if the value is 0, then file buffering is off.

Flushing the File Buffer

Flushing the buffer means updating the physical disk with all of the data in the file buffer. File buffers are flushed to the system's physical disk whenever you: