/* * Copyright (c) 1987, 1989 University of Maryland * Department of Computer Science. All rights reserved. * Permission to copy for any purpose is hereby granted * so long as this copyright notice remains intact. */ #ifndef lint static char rcsid[] = "$Header: /usr/src/local/tex/local/mctex/lib/RCS/seek.c,v 3.1 89/08/22 21:59:04 chris Exp $"; #endif /* * SeekFile copies an input stdio file, if necessary, so that * it produces a stdio file on which fseek() works properly. * It returns NULL if this cannot be done; in that case, the * input file is closed (or otherwise rendered worthless). * * CopyFile copies an input file unconditionally. (On non-Unix * machines, it might `accidentally' not copy it.) * * On Unix machines, this means `if the input is a pipe or tty, * copy it to a temporary file'. On other systems, all stdio files * might happen to be seekable. */ #include #include "types.h" /* for BSD_FILE_SYSTEM */ #include "seek.h" #ifdef EASY_BUT_NOT_GOOD FILE *CopyFile(f) FILE *f; { return (f); } FILE *SeekFile(f) FILE *f; { return (f); } #else #include #ifdef BSD_FILE_SYSTEM #include /* want MAXBSIZE */ #else #include #endif #include long lseek(); char *malloc(); extern int errno; /* * Make and return a version of `f' on which fseek works (unconditionally). * This code is somewhat Unix-specific. */ FILE * CopyFile(f) FILE *f; { register int tf, n, ifd, w; register char *p, *buf; register int blksize; struct stat st; int e; #ifdef MAXBSIZE #define BSIZE MAXBSIZE #else #define BSIZE BUFSIZ #endif char stackbuf[BSIZE]; /* get a read/write temp file which will vanish when closed */ if ((tf = MakeRWTempFile(stackbuf)) < 0) { e = errno; (void) fclose(f); errno = e; return (NULL); } /* compute buffer size and choose buffer */ ifd = fileno(f); buf = stackbuf; blksize = sizeof stackbuf; #ifdef BSD_FILE_SYSTEM if (fstat(tf, &st) == 0 && st.st_blksize > blksize) { /* * The output block size is the important one, * but the input block size is not irrelevant. * * This should actually compute the lcm, but we * will rely on block sizes being powers of two * (so that the larger is the lcm). */ blksize = st.st_blksize; if (fstat(ifd, &st) == 0 && st.st_blksize > blksize) blksize = st.st_blksize; if ((buf = malloc((unsigned)blksize)) == NULL) { buf = stackbuf; blksize = sizeof stackbuf; } } #endif /* copy from input file to temp file */ (void) lseek(ifd, 0L, 0); /* paranoia */ while ((n = read(ifd, p = buf, blksize)) > 0) { do { if ((w = write(tf, p, n)) < 0) { (void) close(tf); (void) fclose(f); return (NULL); } p += w; } while ((n -= w) > 0); } e = errno; /* in case n < 0 */ if (buf != stackbuf) free(buf); if (n < 0) { (void) close(tf); (void) fclose(f); errno = e; return (NULL); } /* discard the input file, and rewind and open the temporary */ (void) fclose(f); (void) lseek(tf, 0L, 0); errno = 0; if ((f = fdopen(tf, "r")) == NULL) { if (errno == 0) e = EMFILE; (void) close(tf); errno = e; } return (f); } /* * Copy an input file, but only if necessary. */ FILE *SeekFile(f) FILE *f; { int fd = fileno(f); return (lseek(fd, 0L, 1) >= 0 && !isatty(fd) ? f : CopyFile(f)); } #endif /* EASY_BUT_NOT_GOOD */