[comp.unix.xenix] NEED HELP: fread, fwrite, fseek, ftell

itkin@mrspoc.UUCP (Steven M. List) (05/02/89)

I am trying to write a simple little program to swap bytes and/or words
in a file.  The program works great except for one little problem.  When
I try to do it in place, the file just keeps growing and growing and...

The following fragment is the functional piece of code.  When I've run
it under sdb, I find that when the program should be reading zero bytes
it is still returning 1024 in bytesread.  It then writes out that 1k
chunk and apparently thinks that it's read in another 1k block.  From
what I've been able to tell, the block that it locks in on is the first
block in the file!  That is, it keeps reading and writing the first 1k
block in the file indefinitely.  When I commented out the fseeks and ftells
and changed it to write to stdout (as you see here), it worked great.

This, needless to say, is happening on XENIX 2.3.1 with the 2.2.3 development
system.  I haven't a clue.  fread appears to work properly under all
other circumstances.  I don't appear to be doing anything wrong with the
ftell and fseek calls (I've checked as far as I can in sdb).  Hmmmmm...

Any suggestions?  Please?
------------------------------------------------------------------------------
do_byte_swap (swabfile)
register FILE *swabfile;
{
	extern long ftell ();
	extern int  fseek ();

	long	startpos;

	char	inbuf[1024];
	char	outbuf[1024];

	int	bytesread;
	int	byteswritten;

	register int blocknum = 0;
	register int rc;

	rewind (swabfile);
/* 	startpos = ftell (swabfile); */

	bytesread = fread (inbuf, sizeof (char), sizeof inbuf, swabfile);
	while (bytesread > 0)
	{
		swab (inbuf, outbuf, bytesread);
/* 		if ((rc = fseek (swabfile, startpos, 0)) != 0) */
/* 		{ */
/* 			fprintf (stderr, "file seek error, status = %d\n", rc); */
/* 			exit (1); */
/* 		} */
/*		byteswritten = fwrite (outbuf, sizeof (char), bytesread, swabfile); */
		byteswritten = fwrite (outbuf, sizeof (char), bytesread, stdout);
		if (byteswritten != bytesread)
		{
			fprintf (stderr,
				"swabbit: write error: read %ld bytes, wrote %ld bytes\n",
				bytesread, byteswritten);
			fprintf (stderr,
				"         restore file from backup - probably corrupted!\n");
			exit (1);
		}
/* 		fflush (swabfile); */
/* 		startpos = ftell (swabfile); */
		bytesread = fread (inbuf, sizeof (char), sizeof inbuf, swabfile);
		fprintf (stderr, "%d", ++blocknum);
		if ((blocknum % 70) == 0) fprintf (stderr, "\n");
	}

	fprintf (stderr, "\n");

	return 0;
}
-- 
:  Steven List @ Transact Software, Inc. :^>~
:  Chairman, Unify User Group of Northern California
:  {apple,coherent,limbo,mips,pyramid,ubvax}!mrspoc!itkin
:  Voice: (415) 961-6112

maart@cs.vu.nl (Maarten Litmaath) (05/03/89)

itkin@mrspoc.UUCP (Steven M. List) writes:
\...
\	byteswritten = fwrite (outbuf, sizeof (char), bytesread, swabfile);
\...
\	bytesread = fread (inbuf, sizeof (char), sizeof inbuf, swabfile);

RTFM (fopen(3s)):

     When a file is opened for update, both input and output  may
     be done on the resulting stream.  However, output may not be
				       ^^^^^^^^^^^^^^^^^^^^^^^^^^
     directly followed by input without an intervening  fseek [...] :-(
     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Solution: insert

	fseek(swabfile, ftell(swabfile), 0);

At first sight this looks like a no-op, but there are some `interesting'
side-effects...
What to do if you f*ck things up? Just put it in the FM: it's a feature!
(Which will live on forever.)
BTW, whom can we sue for this? :-)
-- 
 "If it isn't aesthetically pleasing, |Maarten Litmaath @ VU Amsterdam:
  it's probably wrong." (jim@bilpin)  |maart@cs.vu.nl, mcvax!botter!maart

chapman@sco.COM (Brian Chapman) (05/04/89)

In article <7327@mrspoc.UUCP> itkin@mrspoc.UUCP (Steven List) writes:
>I am trying to write a simple little program to swap bytes and/or words
>in a file.  The program works great except for one little problem.  When
>I try to do it in place, the file just keeps growing and growing and...

I think I can guess your problem.  [ Although your code fragment was
not sufficent to be sure ].

The old V7 and or BSD trick of opening a file for appending
(eg. fopen(....."a");)  and then rewinding it;  doesn't work
on System V compatibile systems.

Open for appending inforces an implied seek() to EOF on writes.
So you read from the front of the file and your writes get added
to the end, to be read again and added as yet more data at the
end of file to be read again....

Try just opening the file read|write.  (fopen(....."r+");)

[ I once chased this "feature" all the way to the exact line in	]
[ in the kernel, and was about to report it as a bug.  Until a	]
[ co-worked pointed it out in the SVID.	:-)			]
-- 
	Pay no attention to the man behind the curtain.
Brian Chapman		uunet!sco!chapman	SCO UNIX 3.2 Development

davidsen@sungod.steinmetz (William Davidsen) (05/04/89)

In article <2445@solo3.cs.vu.nl> maart@cs.vu.nl (Maarten Litmaath) writes:

|Solution: insert
|
|	fseek(swabfile, ftell(swabfile), 0);
|
|At first sight this looks like a no-op, but there are some `interesting'
|side-effects...

  I wasn't going to say anything, but this is a real kludge solution
(it works, however). If you do
	fseek(swabfile, 0L, 1);
It avoids the call to ftell. There's no reason to "tell me where I am
and then seek back there," when "move me zero bytes from where I am"
will suffice.

det@hawkmoon.MN.ORG (Derek E. Terveer) (05/12/89)

In article <7327@mrspoc.UUCP>, itkin@mrspoc.UUCP (Steven M. List) writes:
> I am trying to write a simple little program to swap bytes and/or words
> in a file.

I'm not sure if this will do what you want, but you might want to check out the
command:

	dd if=file_name conv=swab

which swaps every pair of bytes in the input stream.  dd(1m)

derek
-- 
Derek Terveer 	    det@hawkmoon.MN.ORG || ..!uunet!rosevax!elric!hawkmoon!det
		    w(612)681-6986   h(612)688-0667

"A proper king is crowned" -- Thomas B. Costain