Special file handling ------- ---- -------- routines -------- Author: Richard Neitzel 312 Laveta Pass Golden,CO 80401 Time after time in my applications three items reappeared. First, I often need to run through a series of files from a program. Second, I often need to know the size, record type, etc. of a file. Lastly, the number of free blocks and file headers on a disk is needed from inside a program. Finally I sat down and wrote routines to perform these. I hope others find them as useful as I do. Wildcards and Fortran --------- --- ------- In the normal course of events Fortran (or macro) programmers do not have a simple means of moving through a series of files. Therefore a series of routines, found in the library module FILES, has been written to allow the user to open files with wildcard specifications and to allow the user to determine the exact file specifcation of the currently open file. All the routines are in macro, for obvious reasons. This set of subroutines allows the caller to do the following: 1> Open a file with a wildcard filespec. The following are legal types - x.x;* x.*;* *.x;* *.*;* 2> Retrieve the name and version number of the currently open file. 3> Move through a list of files by using the wildcard filespecs. 4> Return to the first file of a wildcard set. To use these routines the subroutine pcaini must be used first. This subroutine creates the data set block used to open the file by name. The F77 call is: CALL PCAINI([d],[ds],[u],[us],[f],[fs]) where d is the device name, ds the number of characters in the device name, u the UIC (form:[xxx,xxx]), us the number of characters in u, f the file name and fs the number of characters in f. To open a file use the routine pcaopn. This routine is accessed via the USEROPEN option within the F77 OPEN statement. pcaopn must be declared as an EXTERNAL function. This will open the next file type that matches the one used in pcaini. If this is the first use of pcaopn the file with the lowest version number of the first file in the directory that matches will be used. When coding the open statement you must give some file name, however, this need not be that of an existing file (and certainly not your true file if you are using wildcards). Further, the status of the file must be 'OLD'. The F77 call is: ........ EXTERNAL PCAOPN ........ ........ OPEN(UNIT=LUN,file='DUMMY',...,STATUS='OLD',USEROPEN=PCAOPN) You may open a series of files simply by repeating the calling to pcaopn. To determine when the end of the list is reached use the system routine ERRSET to allow transfer of control to a specified ERR line when the code IE.NSF is returned. To return to the first file of a list call pcarst. The call is: CALL PCARST To get the name and version number of the currently open file use pcanam. This will give you the device name and number as well. This routine must not be called until AFTER opening a file using pcaopn or you will get garbage. The F77 call is: CALL PCANAM ([ds],[dn],[fn],[ft],[v]) where ds is a 2 byte buffer for the ASCII device name, dn a 3 byte buffer for the ASCII device number (octal notation), fn an 9 byte buffer for the file name, ft a 3 byte buffer for the file type and v a 3 byte buffer for the ASCII version number (octal notation). Note that the old familar '.' and ';' are not returned. If you want the device and/or version numbers as numbers use pcanm2. This will return the actual values. Follow the warning for pcanam. The F77 call is: CALL PCANM2 ([dn],[vn]) where dn is a word variable for the device number and vn is a word variable for the version number. File Attributes ---- ---------- Fortran programmers have no easy way of determining such things as how many records exist in a fixed record file, the maximum record size in a file, or even what is the record type of a given file. A routine called FILSIZ, found in library module FILSIZ, was written to remedy the situtation. Actually there are two routines that allow determination of various file characteristics. These are: record type (fixed, variable or segmented), record size, number of bytes used and the number of records in the file. The first is for use with all files while the second is for files using NOSPANBLOCKS. The first routine is called FILSIZ. No knowledge about the file's structure is required to obtain the following: record type, record size, number of bytes in file and number of records in file. The F77 call is: CALL FILSIZ (lun, itype, isize, ibytes, irec) where lun is the file's LUN number, itype is the returned value of the record type (1 for fixed, 2 for variable and 3 for segmented, however see note below), isize is the size of the record in bytes, ibytes is the size of the data area in bytes and irec is the number of records in the file. All are integer*2 variables except for ibytes and irec, which are integer*4 variables. This routine has been tested on direct access and sequential files, with the latter using fixed and variable record lengths. It must be noted that isize for a variable length file returns the size of the largest record in the file, while the ibytes and irec values are meaningless. Another interesting quirk is the fact that the number of bytes returned for a fixed length file with an odd record size will not match the predicted number. Instead the returned value will be greater by the number of records in the file. This is due to padding to preserve even byte starting addresses. This is why odd sizes are rounded up. The second routine is called NOSPAN. The F77 call is: CALL NOSPAN (lun, itype, isize, iblocks, ilast) where lun is the LUN of the file, itype the record type (as described above), isize the record size in bytes, iblocks the number of blocks in the file minus one (since the last block may not be fully used) and ilast is the last byte used in the last block. All are integer*2 variables but iblocks which is integer*4. In using the results remember that files with odd record sizes actually allocate one more byte per record then indicated. Again both direct and sequential files have been tested, and the block count and last byte for variable length files, while correct, are meaningless. The FILSIZ routine may also be used for files that use NOSPANBLOCKS. This is especially useful for opening a file when the attributes are unknown. In this case the itype variable will be 9, 10 or 11, the addition of 8 being the mark of the nospan attribute. In this case ibytes will be the same as iblocks and irec as ilast in NOSPAN. However, if the value of irec is greater then the the integer*2 maximum prior to the call you will get garbage, so if you are uncertain about span/nospan clear irec first. Actually, with a little effort one could also determine the number of records in a variable record file, but this would entail reading in each block exactly as it is on disk and then extracting the records, obtaining their locations from the field length data embedded in them. I have no need for this, so I leave it to some other inventive soul for now. Free space ---- ----- From within a program there does not exist a simple means of determining how many blocks and/or file headers are available on a given disk. Such information can be crucial to determining if data output will overflow the disk capacity. In response the two routines DSKSPC and HEADER where written. They are found in the library modules DSKSPC and HEADER. Note that these routines must use the TKB option MAXBUF with a value of at least 512. Both routines are in Fortran to allow easier understanding and to make modifications easier for the user. NOTE: The macro routine make4.mac is found in both MACLIB.ULB and MACLIB.OLB. DSKSPC allows a Fortran user to determine both the total block count and the number of free blocks on a disk drive. This is done by reading the BITMAP.SYS file for the disk. The high byte of the second word in the first virtual block contains the number of blocks used to map the disk. From this an offset is calculated to the two word value that yields the total number of blocks on the disk. Each map block is then read in turn and the number of 0 bits is counted to determine the number of blocks in use. When the number of bits tested is equal to or greater than the total number of blocks the routine ends. The F77 call is: CALL HEADER (cdrive, ilen, ilun, ltotal, lfree, ierr) where cdrive is the ASCII name of the drive to check, ilen is the number of bytes in cdrive (5 max), ilun is the LUN to be assigned to the drive, ltotal the total number of headers on the drive, lfree the number of free headers and ierror a returned status code. ltotal and lfree are i*4 variables, the rest are i*2. HEADER allows a Fortran user to determine both the total header count and the number of free headers on a disk drive. This is done by reading the INDEXF.SYS file for the disk. The second virtual block of the file is the home block. This block contains all the pertinent information. The first word contains the number of blocks used to map the number of headers. The fourth word contains the maximum number of headers available on the disk. The index file bitmap starts at virtual block 3. Each set bit in the block means that the corresponding file header is in use. The F77 call is: CALL HEADER (cdrive, ilen, ilun, itotal, ifree, ierr) where cdrive is the ASCII name of the drive to check, ilen is the number of bytes in cdrive (5 max), ilun is the LUN to be assigned to the drive, itotal the total number of headers on the drive, ifree the number of free headers and ierror a returned status code. All are i*2 variables.