hp.com home products and services support and drivers solutions how to buy
cd-rom home
End of Jump to page title
HP OpenVMS systems
documentation

Jump to content


HP OpenVMS Programming Concepts Manual

HP OpenVMS Programming Concepts Manual


Previous Contents Index

27.6.2.7 Specifying Output Formats at Compile Time

To specify an output format at compile time, the user must preinitialize the component LIB$K_OUTPUT_FORMAT. Two elements are associated with this output format string. One describes the date format fields, the other the time format fields. The order in which they appear in the string determines the order in which they are output. A single space is inserted into the output stream between the two elements, if the call to LIB$FORMAT_DATE_TIME specifies that both be output. For example:

"|!DB-!MAAU-!Y4|!H04:!M0:!S0.!C2|"

(These mnemonics are listed in Table 27-6.) This format string represents the format used by the $ASCTIM system service for outputting times. Note that the middle delimiter is replaced by a space in the resultant output.


13-JAN-1993 14:54:09:24 

27.6.3 Converting with the LIB$CONVERT_DATE_STRING Routine

The LIB$CONVERT_DATE_STRING routine converts an absolute date/time string into an operating system internal format date/time quadword. You can optionally specify which fields of the input string can be defaulted (using the input-flags argument), and what the default values should be (using the defaults argument). By default, the time fields can be defaulted but the date fields cannot. Table 27-7 gives some examples of these default values.

You can use the optional defaulted-fields argument to LIB$CONVERT_DATE_STRING to determine which input fields were defaulted. That is, the defaulted-fields argument is a bit mask in which each set bit indicates that the corresponding field was defaulted in the input date/time string.

If you want to use LIB$CONVERT_DATE_STRING to return the current time as well as the current date, you can call the $NUMTIM system service and pass the timbuf argument, which contains the current date and time, to LIB$CONVERT_DATE_STRING as the defaults argument. This tells the LIB$CONVERT_DATE_STRING routine to take the default values for the date and time fields from the 7-word array returned by $NUMTIM.

LIV$CONVERT_DATE_STRING specifies 2-digit years from input by selecting the current century as the default for the century portion of the date. This is true when the !Y2 format is used. This selection may not be desirable for you since 00 would be interpreted as 1900 (and as 2000 on 1/1/2000).

A new format has been added so that you can select a new behavior for LIB$CONVERT_DATE_STRING. You can use the Z format in every place the Y format is used to represent years. The Z format acts exactly like the Y format except for !Z2. Using !Z2 causes LIB$CONVERT_DATE_STRING to interpret a 2-digit year of 99 as 1999 and a 2-digit year of 01 as 2001. The transition year is on a sliding scale determined by the current year minus 43. So if the current year is 1999, the transition year is 56. A 2-digit year greater or equal to this has a century of 1900 and a 2-digit year less than this has a century of 2000. Thus, the year 60 would be 1960 and the year 50 would be 2050. You can use the !Z2 format either in the logical LIB$DT_INPUT_FORMAT, or in the init-string parameter for a call to LIB$INIT_DATE_TIME_CONTEXT to establish the input format for LIB$CONVERT_DATE_STRING. Below is a list of the new Z formats:
Date Explanation
!Z4 Year; 4 digits
!Z3 Year; 3 digits
!Z2 Year; 2 digits (New behavior for the LIB$CONVERT_DATE_STRING routine)
!Z1 Year; 1 digit

27.6.4 Retrieving with LIB$GET_DATE_FORMAT Routine

The LIB$GET_DATE_FORMAT routine enables you to retrieve information about the currently selected input format. The string returned by LIB$GET_DATE_FORMAT parallels the currently defined input format string, consisting of the format punctuation (with most white space compressed) and legible mnemonics representing the various format fields.

Based on the currently defined input date/time format, LIB$GET_DATE_FORMAT returns a string comprised of the mnemonics that represent the current format. These mnemonics are listed in Table 27-11.

Table 27-12 gives some examples of input format strings and their resultant mnemonic strings (using English as the default language).

Table 27-12 Sample Input Format Strings
Sample Format String LIB$GET_DATE_FORMAT Value
!MAU !DD, !Y4 !H04:!M0:!S0:!C2 MONTH DD, YYYY4 HH:MM:SS:CC2
!MN0-!D0-!Y2 !H04:!M0:!S0.!C2 MM-DD-YYYY2 HH:MM:SS.CC2
!MN0/!D0/!Y2 !H02:!M0:!S0.!C2 !MIU MM/DD/YYYY2 HH:MM:SS.CC2 AM/PM

27.6.4.1 Using User-Defined Output Formats

In addition to the 40 date output formats and 20 time output formats, users can define their own date and time output formats using the logical names LIB$DATE_FORMAT_nnn and LIB$TIME_FORMAT_nnn, where nnn ranges from 501 to 999. (That is, values of nnn from 001 to 500 are reserved for use by HP.) The mnemonics used to define output formats are listed in Table 27-6.

User-defined output formats must be defined as executive-mode logicals, and they must be defined in the table LNM$DT_FORMAT_TABLE. These formats are normally defined from the site-specific startup command procedure. The following example illustrates the steps the system manager must use to create a particular output format using French as the language:


$ DEFINE/EXEC/TABLE=LNM$DT_FORMAT_TABLE LIB$DATE_FORMAT_501 -
_$  "!WL, le !DD !MAL !Y4"
$ DEFINE/EXEC/TABLE=LNM$DT_FORMAT_TABLE LIB$TIME_FORMAT_501 -
_$  "!H04 heures et !M0 minutes"

After the system manager defines the desired formats, the user can access them by using the following commands:


$ DEFINE SYS$LANGUAGE FRENCH
$ DEFINE LIB$DT_FORMAT LIB$DATE_FORMAT_501, LIB$TIME_FORMAT_501
After completing these steps, a program outputting the date and time provides the following results:


mardi, le 20 janvier 1993 13 heures et 50 minutes 

In addition to creating their own date and time formats, users can also define their own language tables (provided they have the SYSNAM, SYSPRV and CMEXEC privileges). To create a language table, a user must define all the logical names required.

The following example defines a portion of the Dutch language table. This table is included in its entirety in the set of predefined languages provided with the international date/time formatting routines.


$ CREATE/NAME/PARENT=LNM$SYSTEM_DIRECTORY/EXEC/PROT=(S:RWED,G:R,W:R) -
_$  LNM$LANGUAGE_DUTCH
$ DEFINE/EXEC/TABLE=LNM$LANGUAGE_DUTCH LIB$WEEKDAYS_L -
_$  "maandag", "dinsdag", "woensdag", "donderdag", "vrijdag", -
_$  "zaterdag", "zondag"
$ DEFINE/EXEC/TABLE=LNM$LANGUAGE_DUTCH LIB$WEEKDAY_ABBREVIATIONS_L -
_$  "maa", "din", "woe", "don", "vri", "zat", "zon"
$ DEFINE/EXEC/TABLE=LNM$LANGUAGE_DUTCH LIB$MONTHS_L "januari", -
_$  "februari", "maart", "april", "mei", "juni", "juli", "augustus", -
_$  "september", "oktober", "november", "december"
$ DEFINE/EXEC/TABLE=LNM$LANGUAGE_DUTCH LIB$MONTH_ABBREVIATIONS_L -
_$  "jan", "feb", "mrt", "apr", "mei", "jun", "jul", "aug", "sep", -
_$  "okt", "nov", "dec"
$ DEFINE/EXEC/TABLE=LNM$LANGUAGE_AUSTRIAN LIB$RELATIVE_DAYS_L -
_$  "gisteren", "vandaag", "morgen"

All logical names that are used to build a language are as follows:

LIB$WEEKDAYS_[U|L|C]

These logical names supply the names of the weekdays, spelled out in full (uppercase, lowercase, or mixed case). Weekdays must be defined in order, starting with Monday.

LIB$WEEKDAY_ABBREVIATIONS_[U|L|C]

These logical names supply the abbreviated names of the weekdays (uppercase, lowercase, or mixed case). Weekday abbreviations must be defined in order, starting with Monday.

LIB$MONTHS_[U|L|C]

These logical names supply the names of the months, spelled out in full (uppercase, lowercase, or mixed case). Months must be defined in order, starting with January.

LIB$MONTH_ABBREVIATIONS_[U|L|C]

These logical names supply the abbreviated names of the months (uppercase, lowercase, or mixed case). Month abbreviations must be defined in order, starting with January.

LIB$MI_[U|L|C]

These logical names supply the spellings for the meridiem indicators (uppercase, lowercase, or mixed case). Meridiem indicators must be defined in order; the first indicator represents the hours 0:00:0.0 to 11:59:59.99, and the second indicator represents the hours 12:00:00.00 to 23:59:59.99.

LIB$RELATIVE_DAYS_[U|L|C]

These logical names supply the spellings for the relative days (uppercase, lowercase, or mixed case). Relative days must be defined in order: yesterday, today, and tomorrow, respectively.

LIB$FORMAT_MNEMONICS

This logical name supplies the abbreviations for the appropriate format mnemonics. That is, the information supplied in this logical name is used to specify a desired input format in the user-defined language. The format mnemonics, along with their English values, are listed in the order in which they must be defined.
  1. Year (YYYY)
  2. Numeric month (MM)
  3. Day of the month (DD)
  4. Hour of the day (HH)
  5. Minutes of the hour (MM)
  6. Seconds of the minute (SS)
  7. Parts of the second (CC)
  8. Meridiem indicator (AM/PM)
  9. Alphabetic month (MONTH)

The English definition of LIB$FORMAT_MNEMONIC is therefore as follows:


$ DEFINE/EXEC/TABLE=LNM$LANGUAGE_ENGLISH LIB$FORMAT_MNEMONICS -
_$  "YYYY", "MM", "DD", "HH", "MM", "SS", "CC", "AM/PM ", "MONTH"

27.7 Coordinated Universal Time Format

This section provides information about VAX systems that supply system base date and time format other than the Smithsonian base date and time system. The other base date and time format system is the Coordinated Universal Time (UTC) system. UTC time is determined by a network of atomic clocks that are maintained by standard bodies in several countries. Formerly, applications that spanned time zones often used Greenwich Mean Time (GMT) as a time reference.

UTC binary timestamps are opaque octawords of 128-bits that contain several fields. Important fields of the UTC format are an absolute time value, a time differential factor (TDF) that contains the offset of the host node's clock from UTC, and an inaccuracy, or tolerance, that can be applied to the absolute time value. Unlike UTC, the operating system binary date and timestamps in the Smithsonian base date and time format represent only the local time of the host node; they do not contain TDF values or inaccuracy values.

The UTC system services allow applications to gain the benefits of a Coordinated Universal Time reference. The UTC system services enable applications to reference a common time standard independent of the host's location and local date and time value.

By calling the UTC system services, applications can perform the following functions:

System services that implement the UTC-format date and time are:

For specific implementation information about the UTC system services, see the HP OpenVMS System Services Reference Manual.


Chapter 28
File Operations

This chapter describes file operations that support file input/output (I/O) and file I/O instructions of the operating system's high-level languages. This chapter contains the following sections:

Section 28.1 describes file attributes.

Section 28.2 describes strategies to access files.

Section 28.3 describes protection and access of files.

Section 28.4 describes file mapping.

Section 28.5 describes how to open and update a sequential file.

Section 28.6 describes using the Fortran user-open routines.

I/O statements transfer data between records in files and variables in your program. The I/O statement determines the operation to be performed; the I/O control list specifies the file, record, and format attributes; and the I/O list contains the variables to be acted upon.

Note

Some confusion might arise between records in a file and record variables. Where this chapter refers to a record variable, the term record variable is used; otherwise, record refers to a record in a file.

28.1 File Attributes

Before writing a program that accesses a data file, you must know the attributes of the file and the order of the data. To determine this information, see your language-specific programming manual.

File attributes (organization, record structure, and so on) determine how data is stored and accessed. Typically, the attributes are specified by keywords when you open the data file.

Ordering of the data within a file is not important mechanically. However, if you attempt to read data without knowing how it is ordered within the file, you are likely to read the wrong data; if you attempt to write data without knowing how it is ordered within the file, you are likely to corrupt existing data.

28.1.1 Specifying File Attributes

You can specify large sets of attributes using the File Definition Language utility (FDL). You can specify all of the file attributes using OpenVMS RMS in a user-open routine (see Section 28.6). Typically, you need only programming language file specifiers. Use FDL only when language specifiers are unavailable.

Refer to the appropriate programming language reference manual for information about the use of language specifiers.

For complete information about how to use FDL, see the OpenVMS Record Management Utilities Reference Manual.

28.2 File Access Strategies

When determining the file attributes and order of your data file, consider how you plan to access that data. File access strategies fall into the following categories:

28.3 File Protection and Access

Files are owned by the process that creates them and receive the default protection of the creating process. To create a file with ownership and protection other than the default, use the File Definition Language (FDL) attributes OWNER and PROTECTION in the file.

28.3.1 Read-Only Access

By default, the user of your program must have write access to a file in order for your program to open that file. However, if you specify use of the Fortran READONLY specifier when opening the file, the user needs only read access to the file to open it. The READONLY specifier does not set the protection on a file. The user cannot write to a file opened with the READONLY specifier.

28.3.2 Shared Access

The Fortran specifier READONLY and the SHARED specifier allow multiple processes to open the same file simultaneously, provided that each process uses one of these specifiers when opening the file. The READONLY specifier allows the process read access to the file; the SHARED specifier allows other processes read and write access to the file. If a process opens the file without specifying READONLY or SHARED, no other process can open that file even by specifying READONLY or SHARED.

In the following Fortran segment, if the read operation indicates that the record is locked, the read operation is repeated. You should not attempt to read a locked record without providing a delay (in this example, the call to ERRSNS) to allow the other process time to complete its operation and unlock the record.


! Status variables and values 
INTEGER STATUS, 
2       IOSTAT, 
2       IO_OK 
PARAMETER (IO_OK = 0) 
INCLUDE '($FORDEF)' 
! Logical unit number 
INTEGER LUN /1/ 
! Record variables 
INTEGER LEN 
CHARACTER*80 RECORD 
   .
   .
   .
READ (UNIT = LUN, 
2     FMT = '(Q,A)' 
2     IOSTAT = IOSTAT) LEN, RECORD (1:LEN) 
IF (IOSTAT .NE. IO_OK) THEN 
  CALL ERRSNS (,,,,STATUS) 
   IF (STATUS .EQ. FOR$_SPERECLOC) THEN 
     DO WHILE (STATUS .EQ. FOR$_SPERECLOC)           
     READ (UNIT = LUN, 
2          FMT = '(Q,A)' 
2          IOSTAT = IOSTAT) LEN, RECORD(1:LEN) 
     IF (IOSTAT .NE. IO_OK) THEN 
           CALL ERRSNS (,,,,STATUS) 
           IF (STATUS .NE. FOR$_SPERECLOC) THEN 
                CALL LIB$SIGNAL(%VAL(STATUS)) 
           END IF 
     END IF 
     END DO 
ELSE 
   CALL LIB$SIGNAL (%VAL(STATUS)) 
   END IF 
END IF 
   .
   .
   .

In Fortran, each time you access a record in a shared file, that record is automatically locked either until you perform another I/O operation on the same logical unit, or until you explicitly unlock the record using the UNLOCK statement. If you plan to modify a record, you should do so before unlocking it; otherwise, you should unlock the record as soon as possible.

28.4 File Access and Mapping

To copy an entire data file from the disk to program variables and back again, either use language I/O statements to read and write the data or use the Create and Map Section (SYS$CRMPSC) system service to map the data. Often times, mapping the file is faster than reading it. However, a mapped file usually uses more virtual memory than one that is read using language I/O statements. Using I/O statements, you have to store only the data that you have entered. Using SYS$CRMPSC, you have to initialize the database and store the entire structure in virtual memory including the parts that do not yet contain data.

28.4.1 Using SYS$CRMPSC

Mapping a file means associating each byte of the file with a byte of program storage. You access data in a mapped file by referencing the program storage; your program does not use I/O statements.

Note

Files created using OpenVMS RMS typically contain control information. Unless you are familiar with the structure of these files, do not attempt to map one. The best practice is to map only those files that have been created as the result of mapping.

To map a file, perform the following operations:

  1. Place the program variables for the data in a common block. Page align the common block at link time by specifying an options file containing the following link option for VAX, Alpha, and I64 systems:
    For VAX systems, specify the following:


    PSECT_ATTR = name, PAGE  
     
     
    

    For Alpha and I64 systems, specify the following:


    PSECT_ATTR = name, solitary  
     
     
     
    

    The variable name is the name of the common block.
    Within the common block, you should specify the data in order from most complex to least complex (high to low rank), with character data last. This naturally aligns the data, thus preventing troublesome page breaks in virtual memory.

  2. Open the data file using a user-open routine. The user-open routine must open the file for user I/O (as opposed to OpenVMS RMS I/O) and return the channel number on which the file is opened.
  3. Map the data file to the common block.
  4. Process the records using the program variables in the common block.
  5. Free the memory used by the common block, forcing modified data to be written back to the disk file.

Do not initialize variables in a common block that you plan to map; the initial values will be lost when SYS$CRMPSC maps the common block.

28.4.1.1 Mapping a File

The format for SYS$CRMPSC is as follows:


SYS$CRMPSC [inadr],[retadr],[acmode],[flags],[gsdnam],[ident],[relpag], 
           [chan], [pagcnt],[vbn],[prot],[pfc] 

For a complete description of the SYS$CRMPSC system service, see the HP OpenVMS System Services Reference Manual.

Starting and Ending Addresses of the Mapped Section

On VAX systems, specify the location of the first variable in the common block as the value of the first array element of the array passed by the inadr argument. Specify the location of the last variable in the common block as the value of the second array element.

On Alpha and I64 systems, specify the location of the first variable in the common block as the value of the first array element of the array passed by the inadr argument; the second array element must be the address of the last variable in the common block, which is derived by performing a logical OR with the value of the size of a memory page minus 1. The size of the memory page can be retrieved by a call to the SYS$GETSYI system service.

If the first variable in the common block is an array or string, the first variable in the common block is the first element of that array or string. If the last variable in the common block is an array or string, the last variable in the common block is the last element in that array or string.

Returning the Location of the Mapped Section

On VAX systems, SYS$CRMPSC returns the location of the first and last elements mapped in the retadr argument. The value returned as the starting virtual address should be the same as the starting address passed to the inadr argument. The value returned as the ending virtual address should be equal to or slightly more than (within 512 bytes, or 1 block) the value of the ending virtual address passed to the inadr argument.

On Alpha and I64 systems, SYS$CRMPSC returns the location of the first and last elements mapped in the retadr argument. The value returned as the starting virtual address should be the same as the starting address passed to the inadr argument. The value returned as the ending virtual address should be equal to or slightly less than (within a single page size) the value of the ending virtual address passed to the inadr argument.

If the first element is in error, you probably forgot to page-align the common block containing the mapped data.

If the second element is in error, you were probably creating a new data file and forgot to specify the size of the file in your program (see Section 28.4.1.3).

Using Private Sections

Specify SEC$M_WRT for the flags to indicate that the section is writable. If the file is new, also specify SEC$M_DZRO to indicate that the section should be initialized to zero.

Obtaining the Channel Number

You must use a user-open routine to get the channel number (see Section 28.4.1.2). Pass the channel number to the chan argument.

On VAX systems, Example 28-1 maps a data file consisting of one longword and three real arrays to the INC_DATA common block. The options file INCOME.OPT page-aligns the INC_DATA common block.

If SYS$CRMPSC returns a status of SS$_IVSECFLG and you have correctly specified the flags in the mask argument, check to see if you are passing a channel number of 0.

Example 28-1 Mapping a Data File to the Common Block on a VAX System

!INCOME.OPT 
 
PSECT_ATTR = INC_DATA, PAGE 

INCOME.FOR

! Declare variables to hold statistics 
REAL PERSONS_HOUSE (2048), 
2    ADULTS_HOUSE (2048), 
2    INCOME_HOUSE (2048) 
INTEGER TOTAL_HOUSES 
! Declare section information 
! Data area 
COMMON /INC_DATA/ PERSONS_HOUSE, 
2                 ADULTS_HOUSE, 
2                 INCOME_HOUSE, 
2                 TOTAL_HOUSES 
! Addresses 
INTEGER ADDR(2), 
2       RET_ADDR(2) 
! Section length 
INTEGER SEC_LEN 
! Channel 
INTEGER*2 CHAN, 
2         GARBAGE 
COMMON /CHANNEL/ CHAN, 
2                GARBAGE 
! Mask values 
INTEGER MASK 
INCLUDE '($SECDEF)' 
! User-open routines 
INTEGER UFO_OPEN, 
2       UFO_CREATE 
EXTERNAL UFO_OPEN, 
2        UFO_CREATE 
! Declare logical unit number 
INTEGER STATS_LUN 
! Declare status variables and values 
INTEGER STATUS, 
2       IOSTAT, 
2       IO_OK 
PARAMETER (IO_OK = 0) 
INCLUDE '($FORDEF)' 
EXTERNAL INCOME_BADMAP 
! Declare logical for INQUIRE statement 
LOGICAL EXIST 
! Declare subprograms invoked as functions 
INTEGER LIB$GET_LUN, 
2       SYS$CRMPSC, 
2       SYS$DELTVA, 
2       SYS$DASSGN 
! Get logical unit number for STATS.SAV 
STATUS = LIB$GET_LUN (STATS_LUN) 
IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL (STATUS)) 
INQUIRE (FILE = 'STATS.SAV', 
2        EXIST = EXIST) 
IF (EXIST) THEN 
  OPEN (UNIT=STATS_LUN, 
2       FILE='STATS.SAV', 
2       STATUS='OLD', 
2       USEROPEN = UFO_OPEN) 
  MASK = SEC$M_WRT 
ELSE 
  ! If STATS.SAV does not exist, create new database 
  MASK = SEC$M_WRT .OR. SEC$M_DZRO 
  SEC_LEN = 
!  (address of last - address of first + size of last + 511)/512 
2  ( (%LOC(TOTAL_HOUSES) - %LOC(PERSONS_HOUSE(1)) + 4 + 511)/512 ) 
  OPEN (UNIT=STATS_LUN, 
2       FILE='STATS.SAV', 
2       STATUS='NEW', 
2       INITIALSIZE = SEC_LEN, 
2       USEROPEN = UFO_CREATE) 
END IF 
! Free logical unit number and map section 
CLOSE (STATS_LUN) 
! ******** 
! MAP DATA 
! ******** 
! Specify first and last address of section 
ADDR(1) = %LOC(PERSONS_HOUSE(1)) 
ADDR(2) = %LOC(TOTAL_HOUSES) 
! Map the section 
STATUS = SYS$CRMPSC (ADDR, 
2                    RET_ADDR, 
2                    , 
2                    %VAL(MASK), 
2                    ,,, 
2                    %VAL(CHAN), 
2                    ,,,) 
IF (.NOT. STATUS) CALL LIB$SIGNAL(%VAL(STATUS)) 
! Check for correct mapping 
IF (ADDR(1) .NE. RET_ADDR (1)) 
 
2  CALL LIB$SIGNAL (%VAL (%LOC(INCOME_BADMAP))) 
   .
   .
   .
                     ! Reference data using the 
                     ! data structures listed 
                     ! in the common block 
   .
   .
   .
! Close and update STATS.SAV 
STATUS = SYS$DELTVA (RET_ADDR,,) 
IF (.NOT. STATUS) CALL LIB$SIGNAL(%VAL(STATUS)) 
STATUS = SYS$DASSGN (%VAL(CHAN)) 
IF (.NOT. STATUS) CALL LIB$SIGNAL(%VAL(STATUS)) 
 
END 
 
 


Previous Next Contents Index