示例#1
0
/*
 * Expand the ungetc buffer `in place'.  That is, adjust fp->_p when
 * the buffer moves, so that it points the same distance from the end,
 * and move the bytes in the buffer around as necessary so that they
 * are all at the end (stack-style).
 */
static int
__submore(FILE *fp)
{
	int i;
	unsigned char *p;

	if (_UB(fp)._base == fp->_ubuf) {
		/*
		 * Get a new buffer (rather than expanding the old one).
		 */
		if ((p = malloc((size_t)BUFSIZ)) == NULL)
			return (EOF);
		_UB(fp)._base = p;
		_UB(fp)._size = BUFSIZ;
		p += BUFSIZ - sizeof(fp->_ubuf);
		for (i = sizeof(fp->_ubuf); --i >= 0;)
			p[i] = fp->_ubuf[i];
		fp->_p = p;
		return (0);
	}
	i = _UB(fp)._size;
	p = realloc(_UB(fp)._base, i << 1);
	if (p == NULL)
		return (EOF);
	/* no overlap (hence can use memcpy) because we doubled the size */
	(void)memcpy((void *)(p + i), (void *)p, (size_t)i);
	fp->_p = p + i;
	_UB(fp)._base = p;
	_UB(fp)._size = i << 1;
	return (0);
}
示例#2
0
/*
 * Find a free FILE for fopen et al.
 */
FILE *
__sfp()
{
  FILE *fp;
  int n;
  struct glue *g;

  if (!__sdidinit)
    __sinit();

  rwlock_wrlock(&__sfp_lock);
  for (g = &__sglue;; g = g->next) {
    for (fp = g->iobs, n = g->niobs; --n >= 0; fp++)
      if (fp->_flags == 0)
        goto found;
    if (g->next == NULL && (g->next = moreglue(NDYNAMIC)) == NULL)
      break;
  }
  rwlock_unlock(&__sfp_lock);
  return (NULL);
found:
  fp->_flags = 1;   /* reserve this slot; caller sets real flags */
  fp->_p = NULL;    /* no current pointer */
  fp->_w = 0;   /* nothing to read or write */
  fp->_r = 0;
  fp->_bf._base = NULL; /* no buffer */
  fp->_bf._size = 0;
  fp->_lbfsize = 0; /* not line buffered */
  fp->_file = -1;   /* no file */
/*  fp->_cookie = <any>; */ /* caller sets cookie, _read/_write etc */
  _UB(fp)._base = NULL; /* no ungetc buffer */
  _UB(fp)._size = 0;
  fp->_lb._base = NULL; /* no line buffer */
  fp->_lb._size = 0;
  memset(WCIO_GET(fp), 0, sizeof(struct wchar_io_data));
  rwlock_unlock(&__sfp_lock);
  return (fp);
}
示例#3
0
int
__sungetc(int c, FILE *fp)
{
	if (c == EOF)
		return (EOF);
	if (!__sdidinit)
		__sinit();
	/*FLOCKFILE(fp);*/
	_SET_ORIENTATION(fp, -1);
	if ((fp->_flags & __SRD) == 0) {
		/*
		 * Not already reading: no good unless reading-and-writing.
		 * Otherwise, flush any current write stuff.
		 */
		if ((fp->_flags & __SRW) == 0) {
error:			/*FUNLOCKFILE(fp);*/
			return (EOF);
		}
		if (fp->_flags & __SWR) {
			if (__sflush(fp))
				goto error;
			fp->_flags &= ~__SWR;
			fp->_w = 0;
			fp->_lbfsize = 0;
		}
		fp->_flags |= __SRD;
	}
	c = (unsigned char)c;

	/*
	 * If we are in the middle of ungetc'ing, just continue.
	 * This may require expanding the current ungetc buffer.
	 */
	if (HASUB(fp)) {
		if (fp->_r >= _UB(fp)._size && __submore(fp))
			goto error;
		*--fp->_p = c;
inc_ret:	fp->_r++;
		/*FUNLOCKFILE(fp);*/
		return (c);
	}
	fp->_flags &= ~__SEOF;

	/*
	 * If we can handle this by simply backing up, do so,
	 * but never replace the original character.
	 * (This makes sscanf() work when scanning `const' data.)
	 */
	if (fp->_bf._base != NULL && fp->_p > fp->_bf._base &&
	    fp->_p[-1] == c) {
		fp->_p--;
		goto inc_ret;
	}

	/*
	 * Create an ungetc buffer.
	 * Initially, we will use the `reserve' buffer.
	 */
	fp->_ur = fp->_r;
	fp->_up = fp->_p;
	_UB(fp)._base = fp->_ubuf;
	_UB(fp)._size = sizeof(fp->_ubuf);
	fp->_ubuf[sizeof(fp->_ubuf) - 1] = c;
	fp->_p = &fp->_ubuf[sizeof(fp->_ubuf) - 1];
	fp->_r = 1;
	/*FUNLOCKFILE(fp);*/
	return (c);
}
示例#4
0
/*
 * Re-direct an existing, open (probably) file to some other file.
 * ANSI is written such that the original file gets closed if at
 * all possible, no matter what.
 */
FILE *
freopen(const char *file, const char *mode, FILE *fp)
{
	int f;
	int flags, isopen, oflags, sverrno, wantfd;

	if ((flags = __sflags(mode, &oflags)) == 0) {
		(void) fclose(fp);
		return (NULL);
	}

	if (!__sdidinit)
		__sinit();

	/*
	 * There are actually programs that depend on being able to "freopen"
	 * descriptors that weren't originally open.  Keep this from breaking.
	 * Remember whether the stream was open to begin with, and which file
	 * descriptor (if any) was associated with it.  If it was attached to
	 * a descriptor, defer closing it; freopen("/dev/stdin", "r", stdin)
	 * should work.  This is unnecessary if it was not a Unix file.
	 */
	if (fp->_flags == 0) {
		fp->_flags = __SEOF;	/* hold on to it */
		isopen = 0;
		wantfd = -1;
	} else {
		/* flush the stream; ANSI doesn't require this. */
		if (fp->_flags & __SWR)
			(void) __sflush(fp);
		/* if close is NULL, closing is a no-op, hence pointless */
		isopen = fp->_close != NULL;
		if ((wantfd = fp->_file) < 0 && isopen) {
			(void) (*fp->_close)(fp->_cookie);
			isopen = 0;
		}
	}

	/* Get a new descriptor to refer to the new file. */
	f = open(file, oflags, DEFFILEMODE);
	if (f < 0 && isopen) {
		/* If out of fd's close the old one and try again. */
		if (errno == ENFILE || errno == EMFILE) {
			(void) (*fp->_close)(fp->_cookie);
			isopen = 0;
			f = open(file, oflags, DEFFILEMODE);
		}
	}
	sverrno = errno;

	/*
	 * Finish closing fp.  Even if the open succeeded above, we cannot
	 * keep fp->_base: it may be the wrong size.  This loses the effect
	 * of any setbuffer calls, but stdio has always done this before.
	 */
	if (isopen && f != wantfd)
		(void) (*fp->_close)(fp->_cookie);
	if (fp->_flags & __SMBF)
		free((char *)fp->_bf._base);
	fp->_w = 0;
	fp->_r = 0;
	fp->_p = NULL;
	fp->_bf._base = NULL;
	fp->_bf._size = 0;
	fp->_lbfsize = 0;
	if (HASUB(fp))
		FREEUB(fp);
	_UB(fp)._size = 0;
	WCIO_FREE(fp);
	if (HASLB(fp))
		FREELB(fp);
	fp->_lb._size = 0;

	if (f < 0) {			/* did not get it after all */
		fp->_flags = 0;		/* set it free */
		errno = sverrno;	/* restore in case _close clobbered */
		return (NULL);
	}

	/*
	 * If reopening something that was open before on a real file, try
	 * to maintain the descriptor.  Various C library routines (perror)
	 * assume stderr is always fd STDERR_FILENO, even if being freopen'd.
	 */
	if (wantfd >= 0 && f != wantfd) {
		if (dup2(f, wantfd) >= 0) {
			(void) close(f);
			f = wantfd;
		}
	}

	fp->_flags = flags;
	fp->_file = f;
	fp->_cookie = fp;
	fp->_read = __sread;
	fp->_write = __swrite;
	fp->_seek = __sseek;
	fp->_close = __sclose;

	/*
	 * When opening in append mode, even though we use O_APPEND,
	 * we need to seek to the end so that ftell() gets the right
	 * answer.  If the user then alters the seek pointer, or
	 * the file extends, this will fail, but there is not much
	 * we can do about this.  (We could set __SAPP and check in
	 * fseek and ftell.)
	 */
	if (oflags & O_APPEND)
		(void) __sseek((void *)fp, (fpos_t)0, SEEK_END);
	return (fp);
}