This chapter describes some useful techniques for storing and retrieving data.
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.
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
.
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.
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.
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
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.
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
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:
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). |
ASCII
--used for general text and numeric data storage. Here
are the advantages of this type of file:
The main disadvantages of ASCII files are that:
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. |
The disadvantages are that:
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.
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.
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. |
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"
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.
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.
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:
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.
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.
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:
set group id
bit true, and group
search
(execute) bit false) or you must own the file (HP BASIC/UX
sets the bits automatically).
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:
ERROR 810 Feature not supported on BASIC/UX
.
lockf(2)
HP-UX operating system
call to place the lock. See lockf
(2) and fcntl
(2)
for additional information.
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. |
The CAT statement has the following additional capabilities:
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.
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.
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.
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.
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
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.
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.
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.
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
File buffering increases the efficiency and speed of accessing files. (Note that it is only available with files on HFS-formatted disks.)
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.
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 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:
ASSIGN @Io_path TO *
).
CONTROL @Io_path,9;0
).
sync
command from within HP BASIC/UX
(EXECUTE sync
) or from within another process on the
system.
sync
command (default period between syncs is 30 seconds).