5.10. Determining the Current Position

Standard REXX does not have any seek call that returns the current
position in a stream. Instead, it provides two calls that returns
the amount of data remaining on a stream. These two built-in
functions are LINES() and CHARS().

·    The LINES() built-in function returns the number of complete
  lines left on the stream given as its first parameter.  The term
  “complete lines” does not really matter much, since an
  implementation can assume the end-of-file to implicitly mean an
  end-of-line.

·    The CHARS() built-in function returns the number of character
  left in the stream given as its first parameter.

This is one of the concepts where REXX I/O does not map very well
to C I/O and vice versa. While REXX reports the amount of data
from the current read position to the end of stream, C reports the
amount of data from the start of the file to the current position.
Further, the REXX method only works for input streams, while the C
method works for both input and output files. On the other hand, C
has no basic constructs for counting remaining or reposition at
lines of a file.

Example: Retrieving current position

So, how does one find the current position in a file, when only
allowed to do normal repositioning? The trick is to reposition
twice, as shown in the code below.

     ftell: procedure
          parse arg filename
          now = chars(filename)
          call charin filename, 0, 1
          total = chars(filename)
          call charin filename, 0, total-now
          return total-now

Unfortunately, there are many potential problems with this code.
First, it only works for input files, since there is no equivalent
to CHARS() for output files. Second, if the file is empty, none of
the repositioning work, since it is illegal to reposition at or
after end-of-file for input files—-and the end-of-file is the
first position of the file. Third, if the current read position of
the file is at the end of file (e.g. all characters have been
read) it will not work for similar reasons as for the second case.
And fourth, it only works for persistent files, since transient
files do not allow repositioning.

Example: Improved ftell function

An improved version of the code for the ftell routine (given
above), which tries to handle these problems is:

     ftell: procedure
          parse arg filename
          signal on notready name not_persist
          now = chars(filename)
          signal on notready name is_empty
          call charin filename, 0, 1
          total = chars()
          if now>0 then
               call charin filename, 0, total-now+1
          else if total>0 then
               call charin filename, 1, total
          else
               nop /* empty file, should have raised NOTREADY */
          return total-now+1
     
     not_presist: say filename ‘is not persistent’; return 0
     
     is_empty: say filename ‘is empty’; return 0

The same method can be used for line-oriented I/O too, in order to
return the current line number of an input file. However, a
potential problem in that case is that the routine leaves the
stream repositioned at the start of the current line, even if it
was initially positioned to the middle of a line. In addition, the
line-oriented version of this ftell routine may prove to be fairly
inefficient, since the interpreter may have to scan the whole file
twice for end-of-line character sequences.




PREV NEXT