Example of Writing to an ASA File

EDCXGAS1

Figure 1. ASA Example
 /* EDCXGAS1
    This example shows how to write to an ASA file
  */

#include <stdio.h>
#define MAX_LEN 80

int main(void) {
   FILE *fp;
   char s[MAX_LEN+1];

   fp = fopen("asa.file", "w,recfm=fba");
   if (fp != NULL) {
      fputs("\n\nabcdef\f\r345\n\n", fp);
      fputs("\n\n9034\n", fp);
      fclose(fp);
   }
   fp = fopen("asa.file", "rb,recfm=fb,type=record");
   if (fp != NULL) {
      fread(s, 1, MAX_LEN, fp);
      while (!feof(fp)) {
         printf("record=%s\n", s);
         fread(s, 1, MAX_LEN, fp);
      }
      fclose(fp);
   }
}
This program writes five records to the file asa.file, as follows:
record=0abcdef
record=1
record=+345
record=-
record= 9034

Note that the last record is " 9034". The last single '\n' does not create a record with a single control character (' '). If this same file is opened for read, and the getc() function is called to read the file 1 byte at a time, the same characters as those that were written out by fputs() in the first program are read.

ASA files are treated as follows:
  • If the first record written does not begin with a control character, then a single newline is written and then followed by data; that is, the ASA character defaults to a space when none is specified.
  • In ASA files, control characters are treated the same way that they are treated in other text files, with the following exceptions:
    '\f' — form feed
    Defines a record boundary and determines the ASA character of the following record. Refer to Table 1.
    '\n' — newline
    Does either of these:
    • Defines a record boundary and determines the ASA character of the following record (see translation table above).
    • Modifies the preceding ASA character if the current position is directly after an ASA character of ' ' or '0' (see translation table above).
    '\r' — carriage return
    Defines a record boundary and determines the ASA character of the following record (see translation table above).
  • Records are terminated by writing a newline ('\n'), carriage return ('\r'), or form feed ('\f') character.
  • An ASA character can be updated to any other ASA character.

    Updates made to any of the C control characters that make up an ASA cause the ASA character to change.

    If the file is positioned directly after a ' ' or '0' ASA character, writing a '\n' character changes the ASA character to a '0' or '-' respectively. However, if the ASA character is a '-', '1' or '+', the '\n' truncates the record (that is, it adds blank padding to the end of the record), and causes the following record's ASA character to be written as a ' '. Writing a '\f' or '\r' terminates the record and start a new one, but writing a normal data character simply overwrites the first data character of the record.

  • You cannot overwrite the ASA character with a normal data character. The position at the start of a record (at the ASA character) is the logical end of the previous record. If you write normal data there, you are writing to the end of the previous record. LE/VSE C Run-Time truncates data for the following files, except when they are standard streams:
    • Variable-format files
    • Undefined-format files
    • Fixed-format files in which the previous record is full of data

    When truncation occurs, LE/VSE C Run-Time raises SIGIOERR and sets both errno and the error flag.

  • Even when you update an ASA print-control character, seeking to a previously recorded position still succeeds. If the recorded position was at a control character that no longer exists (because of an update), the reposition is to the next character. Often, this is the first data character of the record. For example, if you have the following string:
      \n\n\nHELLO WORLD
          ↑
       x = ftell()
    you have saved the position of the third newline. If you then update the ASA character to a form feed ('\f'), the logical ASA position x no longer exists.
         \fHELLO WORLD
    If you call fseek() with the logical position x, it repositions to the next valid character, which is the letter 'H'.
      \fHELLO WORLD
        ↑
       fseek() to pos x
  • If you try to shorten a record when you are updating it, LE/VSE C Run-Time adds enough blank padding to fill the record.
  • The ASA character can represent up to three newlines, which can increase the logical record length by 1 or 2 bytes.
  • Extending a fixed logical record on update implies that the logical end of the line follows the last written non-blank character.
  • If an undefined text record is updated, the length of the physical records does not change. If the replacement record is:
    • Longer - data characters beyond the record boundary are truncated. At the point of truncation, the User error flag is set and SIGIOERR is raised (if the signal is not set up to be ignored). Truncation continues until you do one of these:
      1. write a newline character, carriage return, or form feed to complete the current record
      2. close the file explicitly or implicitly at termination
      3. reposition to another position in the file.
    • Shorter - the blank character is used to overwrite the rest of the record.
  • If you close an ASA file that has a newline as its last character, LE/VSE C Run-Time does not write the newline to the physical file. The next time you read from the file or update it, LE/VSE C Run-Time returns the newline to the end of the file. An exception to this rule happens when you write only a newline to a new file. In this case, LE/VSE C Run-Time does not truncate the newline; it writes a single blank to the file. On input, however, you will read two newlines.
  • Using ASA format to read a file that contains zero-length records results in undefined behavior.
  • You may have trouble updating a file if two ASA characters are next to each other in the file. For example, if there is a single-byte record (containing only an ASA character) immediately followed by the ASA character of the next record, you are positioned at or within the first ASA character. If you then write a sequence of '\n' characters intended to update both ASA characters, the '\n's will be absorbed by the first ASA character before overflowing to the next record. This absorption may affect the crossing of record boundaries and cause truncation or corruption of data.
    At least one normal intervening data character (for example, a space) is required between '\n' and '\n' to differentiate record boundaries.
    Note: Be careful when you update an ASA file with data containing more than one consecutive newline—the result of the update depends on how the original ASA records were structured.
  • If you are writing data to a non-blocked file without intervening flush or reposition requests, each record is written to the system on completion (that is, when a '\n', '\r' or '\f' character is written or when the file is closed).

    If you are writing data to a blocked file without intervening flush or reposition requests, and the file is opened in full buffering mode, the block is written to the system on completion of the record that fills the block. If the blocked file is line buffered, each record is written to the system on completion.

    If you are writing data to a spanned file without intervening flush or reposition requests, and the record spans multiple blocks, each block is written to the system once it is full and the user writes an additional byte of data.

  • If a flush occurs while an ASA character indicating more than one newline is being updated, the remaining newlines will be discarded and a read will continue at the first data character. For example, if '\n\n\n' is updated to be '\n\n' and a flush occurs, then a '0' will be written out in the ASA character position.