Google
 

Trailing-Edge - PDP-10 Archives - SRI_NIC_PERM_FS_1_19910112 - c/lib/stdio/ftell.c
There are 8 other files named ftell.c in the archive. Click here to see a list.
/*
**	FTELL - tell position within file
**
**	(c) Copyright Ken Harrenstien 1989
**		for all changes after v.24, 1-Apr-1989
**	(c) Copyright Ian Macky, SRI International 1986
**	Revised 1987, 1988 by Ken Harrenstien for new I/O ptr scheme
*/

/*	For reading:
 *
 * _SIOP_BITS method:
 *	For an unconverted file (_SIOF_CONVERTED off), the I/O ptr is
 *		the real physical position.
 *	For a converted file (_SIOF_CONVERTED on), the I/O ptr is:
 *		<real phys pos of beg of buff><offset in buff>
 *		where the <offset> is kept in the low _SIOP_BITS bits.
 *
 * Alternative method:
 *	I/O ptr is the real physical position, whether converted or not.
 *	Simply re-reads the file from last known physical position, up to
 *	the current point, finds phys position there, then restores pointer.
 *	Advantages: same pointer format, whether converted or unconverted.
 *	Disadvantages: slower (must re-read and do seeks).
 */

#include <stdio.h>
#include <sys/file.h>

int fgetpos(f, pos)
FILE *f;
fpos_t *pos;
{
    long ptr = ftell(f);
    if (ptr == -1)
	return -1;
    *pos = ptr;
    return 0;
}

long ftell(f)
FILE *f;
{
    long pos;
    int cur_cnt;				/* current count */

    if (f->siocheck != _SIOF_OPEN)		/* validate FILE block */
	return -1;
    switch (f->sioflgs & (_SIOF_READ | _SIOF_WRITE)) {
	case _SIOF_READ:
/*
 *	if ungetc's have been done then siocnt now has the # of ungetc'd
 *	characters, and sio2cnt has the old siocnt from before the first
 *	ungetc.  ANSI says pushed-back chars should be included for binary
 *	streams, though the pointer value is unspecified if you ungetc
 *	at position 0.  For text streams the behavior is unspecified; we
 *	try to do the same thing as for binary (because that's simplest) but
 *	the results will probably not be useful.
 */
	    cur_cnt = (f->sioflgs & _SIOF_PBC)
			? f->sio2cnt + f->siocnt	/* Include pushback */
			: f->siocnt;
	    if (f->sioflgs & _SIOF_CONVERTED)
#ifdef _SIOP_BITS
		pos = (f->siofdoff << _SIOP_BITS(f)) + (f->sioocnt - cur_cnt);
#else
		{   static long fdpos();
		    pos = fdpos(f, f->sioocnt - cur_cnt);
		}
#endif
	    else pos = f->siofdoff + (f->sioocnt - cur_cnt);
	    return pos;

	case _SIOF_WRITE:
	    cur_cnt = (f->sioflgs & _SIOF_LINEBUF) ? f->siolcnt : f->siocnt;
	    if (f->sioflgs & _SIOF_CONVERTED) {
		fflush(f);			/* Ensure output forced out */
#ifdef _SIOP_BITS
		pos = (f->siofdoff << _SIOP_BITS(f));	/* so need no offset */
#else
	        pos = f->siofdoff;
#endif
	    }
	    else pos = f->siofdoff + (f->siolbuf - cur_cnt);
	    return pos;

	case 0:
	    if (f->sioflgs & _SIOF_UPDATE) {
		if (f->sioflgs & _SIOF_CONVERTED)
		    return -1;		/* Cannot handle this case yet */
		return f->siofdoff;
	    }
	    /* Not updating, return failure */

	default:
	    return -1;
    }
}

#ifndef _SIOP_BITS
/* FDPOS - finds real physical position corresponding to a given
**	phys position plus some offset # of STDIO-buffered chars.
*/
static long
fdpos(f, boff)
FILE *f;
int boff;			/* Offset within current buffer */
{
    long savoff, retoff;

    if (boff <= 0
      || boff > f->siolbuf
      || !f->siopbuf)
	return f->siofdoff + boff;	/* No offset or buffer */

    if ((savoff = lseek(f->siofd, (long)0, L_INCR)) == -1)
	return -1;
    if (lseek(f->siofd, f->siofdoff, L_SET) == -1)
	return -1;
    if (boff == read(f->siofd, f->siopbuf, boff))	/* Read that many */
	retoff = lseek(f->siofd, (long)0, L_INCR);	/* Find phys pos! */
    else retoff = -1;
    if (lseek(f->siofd, savoff, L_SET) == -1)		/* Restore prev pos */
	return -1;
    return retoff;
}
#endif