[comp.os.vms] a couple of random questions

terry@wsccs.UUCP (Every system needs one) (04/30/88)

In article <2736@bsu-cs.UUCP>, dhesi@bsu-cs.UUCP (Rahul Dhesi) writes:
> [my observation that ftell() on VMS gives different values for
> the same file position reached in different ways]
> 
> My thinking was affected by my VMS C manual, which says that "With
> record files, ftell returns the starting position of the current
> record, not the current byte offset."  What I observed seems to
> illustrate that VMS C's idea of "the current record" depends on how you
> reached end-of-file.

Another soul relegated to NL: by a buggy ftell()!  The specific problem you
get is this:  when reading a record oriented file using fgetc() (and also
fgets(), for all I know), you read a record [read...read...read].  This
record stops at the end of the record, where VMS kindly supplies a '\n',
pretending it's a stream file (as a record seperator).  The problem is
that say you are bouncing around in a file, so you want to fseek() to
reposition the pointer to the record following the one you just read...
logically, you ftell(), and store the result (which is the record number,
not the byte offset into the file).  The problem you run into is that
you fseek() to the location later AND IT PUTS YOU AT THE START OF THE RECORD
YOU JUST DID THE FTELL FROM!  What's going on?!? You KNOW you read the
full record!

The problem is that the record pointer is not advanced to the next record
until you read the first character of that record, even after VMS has gone
and faked up the '\n' for you!  The proper operation would be to go and
advance the record pointer after faking the '\n' record terminator.  After
all, the next thing you read will be the first byte of that record, so one
would assume that if you are pointing at the front of a record and did an
fseek(ftell()), you would still be there, instead of the previous record!

Here is a fix that will be portable when this bug is finally fixed in a
future revision of the VMS libraries, God willing.  It makes the assumption
that you are using the standard C calls to do I/O and haven't done any of
the weird stuff required to talk to strange files.  Making the argument's
match is your own problem... the following code took 5 days:

[Should I declare this shareware and demand $5.00 or a first born male child?]

#define ftell() dftell()	/* Hi.  I live in a global include and*/
				/* come to visit all your .c files!*/

....		/* some unreasonably large amount of normal code*/
....
....

/* this must be the last thing in some poor .c file*/
#undef ftell()		/* so we can use the real one. UGH.*/
dftell()
{
	ungetc( getc());		/* force record pointer update*/
	return( ftell());		/* return updated position*/
}

This is damned ugly, but will save you doing it everywhere or changing all
ftell()'s everywhere.  It also has the advantage of allowing you to say

#ifdef VMS
	/* code that is otherwise reasonable*/
#endif

instead of carrying it all over.  Never tried it under ANSI-C becuase there
isn't one yet until the standard lands on my head.  Probably bomb if they see
it, and become an example of "unallowable code" (volatile dftell()?).


| Terry Lambert           UUCP: ...{ decvax, ihnp4 } ...utah-cs!century!terry |
| @ Century Software        OR: ...utah-cs!uplherc!sp7040!obie!wsccs!terry    |
| SLC, Utah                                                                   |
|                   These opinions are not my companies, but if you find them |
|                   useful, send a $20.00 donation to Brisbane Australia...   |
| 'Admit it!  You're just harrasing me because of the quote in my signature!' |