/*------------------------------------------- | Name:fputc | Description: | Parameters: | Return Type: | Comments: | See: ---------------------------------------------*/ int __fputc(int ch, FILE *fp){ register int v; __thr_safe_lock(fp); Inline_init; v = fp->mode; /* If last op was a read ... */ if ((v & __MODE_READING) && __fflush(fp)) { __thr_safe_unlock(fp); return EOF; } /* Can't write or there's been an EOF or error then return EOF */ if ((v & (__MODE_WRITE | __MODE_EOF | __MODE_ERR)) != __MODE_WRITE) { __thr_safe_unlock(fp); return EOF; } /* In MSDOS translation mode */ #if __MODE_IOTRAN if (ch == '\n' && (v & __MODE_IOTRAN) && fputc('\r', fp) == EOF) { __thr_safe_unlock(fp); return EOF; } #endif /* Buffer is full */ if (fp->bufpos >= fp->bufend && __fflush(fp)) { __thr_safe_unlock(fp); return EOF; } /* Right! Do it! */ *(fp->bufpos++) = ch; fp->mode |= __MODE_WRITING; /* Unbuffered or Line buffered and end of line */ if (((ch == '\n' && (v & _IOLBF)) || (v & _IONBF)) && __fflush(fp)) { __thr_safe_unlock(fp); return EOF; } /* Can the macro handle this by itself ? */ if (v & (__MODE_IOTRAN | _IOLBF | _IONBF)) fp->bufwrite = fp->bufstart; /* Nope */ else fp->bufwrite = fp->bufend; /* Yup */ __thr_safe_unlock(fp); /* Correct return val */ return (unsigned char) ch; }
/*------------------------------------------- | Name:__stdio_close_all | Description: | Parameters: | Return Type: | Comments: | See: ---------------------------------------------*/ void __stdio_close_all(pid_t pid){ FILE *fp; __fflush(stdout); __fflush(stderr); for (fp = __IO_list; fp; fp = fp->next) { __fflush(fp); close(fp->fd); /* Note we're not de-allocating the memory */ /* There doesn't seem to be much point :-) */ fp->fd = -1; } }
int __srget(FILE *stream) /* Get next input block */ { if(stream->flags&(__SERR|__SEOF)) /* Error on stream / EOF */ { stream->incount=0; errno=EPERM; return EOF; } if(stream->flags&__SWR) { if(__fflush(stream)) return EOF; }else if(stream->tmpp!=NULL) /* File is in ungetc mode */ { stream->p=stream->tmpp; stream->incount=stream->tmpinc; stream->tmpp=NULL; if(--stream->incount>=0) return *stream->p++; } if(stream->flags&__SSTR) /* it's a sscanf buffer */ return EOF; if(stream->flags&(__SNBF|__SLBF)) /* Before reading from line- or unbuffered input file */ { /* fflush all line buffered output files (ANSI) */ struct filenode *fp=(struct filenode *)__filelist.mlh_Head; while(fp->node.mln_Succ) { if((fp->FILE.flags&(__SWR|__SLBF))==(__SWR|__SLBF)) __fflush(&fp->FILE); /* Don't return EOF if this fails */ fp=(struct filenode *)fp->node.mln_Succ; } } stream->flags|=__SRD; stream->incount=read(stream->file,stream->buffer,stream->bufsize); if(!stream->incount) /* EOF found */ { stream->flags|=__SEOF; return EOF; }else if(stream->incount<0) /* Error */ { stream->incount=0; stream->flags|=__SERR; return EOF; } stream->incount--; stream->p=stream->buffer; return *stream->p++; }
/* * Helper function for `fprintf to unbuffered unix file': creates a * temporary buffer. We only work on write-only files; this avoids * worries about ungetc buffers and so forth. */ static int __sbprintf(FILE *fp, const char *fmt, va_list ap) { int ret; FILE fake = FAKE_FILE; unsigned char buf[BUFSIZ]; /* XXX This is probably not needed. */ if (prepwrite(fp) != 0) return (EOF); /* copy the important variables */ fake._flags = fp->_flags & ~__SNBF; fake._file = fp->_file; fake._cookie = fp->_cookie; fake._write = fp->_write; fake._orientation = fp->_orientation; fake._mbstate = fp->_mbstate; /* set up the buffer */ fake._bf._base = fake._p = buf; fake._bf._size = fake._w = sizeof(buf); fake._lbfsize = 0; /* not actually used, but Just In Case */ /* do the work, then copy any error status */ ret = __vfprintf(&fake, fmt, ap); if (ret >= 0 && __fflush(&fake)) ret = EOF; if (fake._flags & __SERR) fp->_flags |= __SERR; return (ret); }
int __swbuf(int c,FILE *stream) /* Get next output block */ { int out,lbs; if(stream->flags&(__SSTR|__SERR)) /* sprintf buffer | error on stream */ { stream->outcount=0; errno=EPERM; return EOF; }else if(stream->flags&__SRD) { stream->incount=0; /* throw away input buffer */ stream->tmpp=NULL; stream->flags&=~__SRD; } lbs=stream->flags&__SLBF?-stream->bufsize:0; out=(stream->flags&__SNBF?0:stream->bufsize-1)+lbs; if(!(stream->flags&__SWR)) /* File wasn't in write mode */ { stream->p=stream->buffer; /* set buffer */ stream->outcount=--out; /* and buffercount */ stream->flags|=__SWR; } /* and write mode */ *stream->p++=c; /* put this character */ if(stream->outcount<0&&(stream->outcount<lbs||(char)c=='\n')) { if(__fflush(stream)) /* Buffer full */ return EOF; stream->p=stream->buffer; /* Set new buffer */ } stream->linebufsize=lbs; stream->outcount=out; stream->flags|=__SWR; return c; }
/*------------------------------------------- | Name:setvbuf | Description: | Parameters: | Return Type: | Comments: | See: ---------------------------------------------*/ int __setvbuf(FILE * fp,char * buf,int mode,size_t size){ __thr_safe_lock(fp); __fflush(fp); if( fp->mode & __MODE_FREEBUF ) free(fp->bufstart); fp->mode &= ~(__MODE_FREEBUF|__MODE_BUF); fp->bufstart = fp->unbuf; fp->bufend = fp->unbuf + sizeof(fp->unbuf); fp->mode |= _IONBF; if( mode == _IOFBF || mode == _IOLBF ) { if( size <= 0 ) size = BUFSIZ; if( buf == 0 ) buf = malloc(size); if( buf == 0 ) { __thr_safe_unlock(fp); return EOF; } fp->bufstart = buf; fp->bufend = buf+size; fp->mode |= mode; } fp->bufpos = fp->bufread = fp->bufwrite = fp->bufstart; __thr_safe_unlock(fp); return 0; }
/* * Write the given character into the (probably full) buffer for * the given file. Flush the buffer out if it is or becomes full, * or if c=='\n' and the file is line buffered. * * Non-MT-safe */ int __swbuf(int c, FILE *fp) { int n; /* * In case we cannot write, or longjmp takes us out early, * make sure _w is 0 (if fully- or un-buffered) or -_bf._size * (if line buffered) so that we will get called again. * If we did not do this, a sufficient number of putc() * calls might wrap _w from negative to positive. */ fp->_w = fp->_lbfsize; if (prepwrite(fp) != 0) return (EOF); c = (unsigned char)c; ORIENT(fp, -1); /* * If it is completely full, flush it out. Then, in any case, * stuff c into the buffer. If this causes the buffer to fill * completely, or if c is '\n' and the file is line buffered, * flush it (perhaps a second time). The second flush will always * happen on unbuffered streams, where _bf._size==1; fflush() * guarantees that putc() will always call wbuf() by setting _w * to 0, so we need not do anything else. */ n = fp->_p - fp->_bf._base; if (n >= fp->_bf._size) { if (__fflush(fp)) return (EOF); n = 0; } fp->_w--; *fp->_p++ = c; if (++n == fp->_bf._size || (fp->_flags & __SLBF && c == '\n')) if (__fflush(fp)) return (EOF); return (c); }
/*------------------------------------------- | Name:fread | Description: | Parameters: | Return Type: | Comments:fread will often be used to read in | large chunks of data calling read() | directly can be a big win in this case. | Beware also fgetc calls this function to fill the buffer. | This ignores __MODE__IOTRAN; | probably exactly what you want. (It _is_ whatfgetc wants) | See: ---------------------------------------------*/ int __fread(char *buf,int size,int nelm,FILE *fp){ int len, v; unsigned bytes, got = 0; __thr_safe_lock(fp); Inline_init; v = fp->mode; /* Want to do this to bring the file pointer up to date */ if (v & __MODE_WRITING) __fflush(fp); /* Can't read or there's been an EOF or error then return zero */ if ((v & (__MODE_READ | __MODE_EOF | __MODE_ERR)) != __MODE_READ) { __thr_safe_unlock(fp); return 0; } /* This could be long, doesn't seem much point tho */ bytes = size * nelm; len = fp->bufread - fp->bufpos; if ( (unsigned)len >= bytes) /* Enough buffered */ { memcpy(buf, fp->bufpos, (unsigned) bytes); fp->bufpos += bytes; __thr_safe_unlock(fp); return bytes; } else if (len > 0) /* Some buffered */ { memcpy(buf, fp->bufpos, len); fp->bufpos += len; got = len; } /* Need more; do it with a direct read */ len = read(fp->fd, buf + got, (unsigned) (bytes - got)); /* Possibly for now _or_ later */ if (len < 0) { fp->mode |= __MODE_ERR; len = 0; } else if (len == 0) fp->mode |= __MODE_EOF; __thr_safe_unlock(fp); return (got + len) / size; }
/*@ requires file == \null || file == &(stdio_pvt(file)->pub); requires valid_IO_file_pvt(stdio_pvt(file)); assigns stdio_pvt(file)->ibytes, stdio_pvt(file)->pub._IO_eof, stdio_pvt(file)->pub._IO_error, stdio_pvt(file)->obytes, errno; @*/ int fflush(FILE *file) { struct _IO_file_pvt *f; if (__likely(file)) { f = stdio_pvt(file); return __fflush(f); } else { int err = 0; /*@ loop invariant valid_IO_file_pvt(f); loop invariant f != &__stdio_headnode; loop assigns f, err; */ for (f = __stdio_headnode.next; f != &__stdio_headnode; f = f->next) { if (f->obytes) err |= __fflush(f); } return err; } }
static size_t fwrite_noflush(const void *buf, size_t count, struct _IO_file_pvt *f) { size_t bytes = 0; size_t nb; const char *p = buf; ssize_t rv; while (count) { if (f->ibytes || f->obytes >= f->bufsiz || (f->obytes && count >= f->bufsiz)) if (__fflush(f)) break; if (count >= f->bufsiz) { /* * The write is large, so bypass * buffering entirely. */ rv = write(f->pub._IO_fileno, p, count); if (rv == -1) { if (errno == EINTR || errno == EAGAIN) continue; f->pub._IO_error = true; break; } else if (rv == 0) { /* EOF on output? */ f->pub._IO_eof = true; break; } p += rv; bytes += rv; count -= rv; } else { nb = f->bufsiz - f->obytes; nb = (count < nb) ? count : nb; if (nb) { memcpy(f->buf+f->obytes, p, nb); p += nb; f->obytes += nb; count -= nb; bytes += nb; } } } return bytes; }
/*------------------------------------------- | Name:ftell | Description: | Parameters: | Return Type: | Comments: | See: ---------------------------------------------*/ long __ftell(FILE * fp){ int pos; __thr_safe_lock(fp); if (__fflush(fp) == EOF) { __thr_safe_unlock(fp); return EOF; } pos=lseek(fp->fd, 0L, SEEK_CUR); __thr_safe_unlock(fp); return pos; }
static int __vfprintf(FILE *stream,const char *format,va_list args) { unsigned char buf[((BUFSIZ/4)+3)&~3]; FILE fp; int ret; fp.outcount = 0; fp.flags = stream->flags&~(__SWO|__SWR|__SNBF); fp.file = stream->file; fp.buffer = buf; fp.bufsize = sizeof(buf); fp.linebufsize = 0; if(((ret=vfprintf(&fp,format,args))>=0) && __fflush(&fp)) ret = -1; if(fp.flags&__SERR) stream->flags|=__SERR; return ret; }
int fseek(FILE *stream,long int offset,int whence) { if(stream->flags&__SERR) /* Error on stream */ { errno=EPERM; return EOF; } if(stream->flags&__SWR) if(__fflush(stream)) return EOF; if(whence==SEEK_CUR) offset-=stream->incount+(stream->tmpp!=NULL?stream->tmpinc:0); stream->incount=0; stream->tmpp=NULL; stream->flags&=~(__SEOF|__SRD); if(lseek(stream->file,offset,whence)==EOF) { stream->flags|=__SERR; return EOF; } return 0; }
/*------------------------------------------- | Name:fclose | Description: | Parameters: | Return Type: | Comments: | See: ---------------------------------------------*/ int __fclose(FILE *fp){ int rv = 0; //int errno; if (fp == 0) { errno = EINVAL; return EOF; } if (__fflush(fp)) return EOF; if (close(fp->fd)) rv = EOF; fp->fd = -1; if (fp->mode & __MODE_FREEBUF) { free(fp->bufstart); fp->mode &= ~__MODE_FREEBUF; fp->bufstart = fp->bufend = 0; } if (fp->mode & __MODE_FREEFIL) { FILE *prev = 0, *ptr; fp->mode = 0; for (ptr = __IO_list; ptr && ptr != fp; ptr = ptr->next) ; if (ptr == fp) { if (prev == 0) __IO_list = fp->next; else prev->next = fp->next; } free(fp); } else fp->mode = 0; return rv; }
/*------------------------------------------- | Name:fseek | Description: | Parameters: | Return Type: | Comments: | See: ---------------------------------------------*/ int __fseek(FILE *fp,long offset,int ref) { __thr_safe_lock(fp); #if 1 /* if __MODE_READING and no ungetc ever done can just move pointer */ /* This needs testing! */ if ( (fp->mode &(__MODE_READING | __MODE_UNGOT)) == __MODE_READING && ( ref == SEEK_SET || ref == SEEK_CUR )) { long fpos = lseek(fp->fd, 0L, SEEK_CUR); if( fpos == -1 ) { __thr_safe_unlock(fp); return EOF; } if( ref == SEEK_CUR ) { ref = SEEK_SET; offset = fpos + offset + fp->bufpos - fp->bufread; } if( ref == SEEK_SET ) { if ( offset < fpos && offset >= fpos + fp->bufstart - fp->bufread ) { fp->bufpos = offset - fpos + fp->bufread; __thr_safe_unlock(fp); return 0; } } } #endif /* Use fflush to sync the pointers */ if (__fflush(fp) == EOF) { __thr_safe_unlock(fp); return EOF; } if (lseek(fp->fd, (off_t)offset, ref) < 0) { __thr_safe_unlock(fp); return EOF; } __thr_safe_unlock(fp); return 0; }
size_t _fwrite(const void *buf, size_t count, FILE *file) { struct _IO_file_pvt *f = stdio_pvt(file); size_t bytes = 0; size_t pf_len, pu_len; const char *p = buf; const char *q; /* We divide the data into two chunks, flushed (pf) and unflushed (pu) depending on buffering mode and contents. */ switch (f->bufmode) { case _IOFBF: pf_len = 0; break; case _IOLBF: q = memrchr(p, '\n', count); pf_len = q ? q - p + 1 : 0; break; case _IONBF: default: pf_len = count; break; } if (pf_len) { bytes = fwrite_noflush(p, pf_len, f); p += bytes; if (__fflush(f) || bytes != pf_len) return bytes; } pu_len = count - pf_len; if (pu_len) bytes += fwrite_noflush(p, pu_len, f); return bytes; }
/*------------------------------------------- | Name:fgetc | Description: | Parameters: | Return Type: | Comments: | See: ---------------------------------------------*/ int __fgetc(FILE *fp){ int ch; __thr_safe_lock(fp); if (fp->mode & __MODE_WRITING) __fflush(fp); #if __MODE_IOTRAN try_again: #endif /* Can't read or there's been an EOF or error then return EOF */ if ((fp->mode & (__MODE_READ | __MODE_EOF | __MODE_ERR)) != __MODE_READ) { __thr_safe_unlock(fp); return EOF; } /* Nothing in the buffer - fill it up */ if (fp->bufpos >= fp->bufread) { fp->bufpos = fp->bufread = fp->bufstart; ch = __fread(fp->bufpos, 1, fp->bufend - fp->bufstart, fp); if (ch == 0) { __thr_safe_unlock(fp); return EOF; } fp->bufread += ch; fp->mode |= __MODE_READING; fp->mode &= ~__MODE_UNGOT; } ch = *(fp->bufpos++); #if __MODE_IOTRAN /* In MSDOS translation mode; WARN: Doesn't work with UNIX macro */ if (ch == '\r' && (fp->mode & __MODE_IOTRAN)) goto try_again; #endif __thr_safe_unlock(fp); return ch; }
/*------------------------------------------- | Name:setbuffer | Description: | Parameters: | Return Type: | Comments: | See: ---------------------------------------------*/ void __setbuffer(FILE * fp,char * buf,int size){ __thr_safe_lock(fp); __fflush(fp); if( fp->mode & __MODE_FREEBUF ) free(fp->bufstart); fp->mode &= ~(__MODE_FREEBUF|__MODE_BUF); if( buf == 0 ) { fp->bufstart = fp->unbuf; fp->bufend = fp->unbuf + sizeof(fp->unbuf); fp->mode |= _IONBF; } else { fp->bufstart = buf; fp->bufend = buf+size; fp->mode |= _IOFBF; } fp->bufpos = fp->bufread = fp->bufwrite = fp->bufstart; __thr_safe_unlock(fp); }
/*@ requires 0 <= count; requires \separated(((char*)buf)+(0..count-1), stdio_pvt(file)->next, stdio_pvt(file)->prev, stdio_pvt(file)->buf+(0..(stdio_pvt(file)->bufsiz+32-1))); requires file == &(stdio_pvt(file)->pub); requires valid_IO_file_pvt(stdio_pvt(file)); requires \valid(((char*)buf)+(0..count-1)); @*/ size_t _fread(void *buf, size_t count, FILE *file) { struct _IO_file_pvt *f = stdio_pvt(file); size_t bytes = 0; size_t nb; char *p = buf; char *rdptr; ssize_t rv; bool bypass; if (!count) return 0; if (f->obytes) /* User error! */ __fflush(f); /*@ loop invariant \base_addr(p) == \base_addr(buf); loop invariant 0 <= bytes; loop invariant \base_addr(rdptr) == \base_addr(f->data); loop invariant f->data <= rdptr <= f->data + f->bufsiz + 32; loop invariant (char*)buf <= p <= (char*)buf + \at(count, Pre); loop invariant 0 <= count; loop assigns rv, bypass, rdptr, nb, f->pub._IO_error, f->pub._IO_eof, p, bytes, count, f->ibytes, f->data; loop variant count; @*/ while (count) { while (f->ibytes == 0) { /* * The buffer is empty, we have to read */ bypass = (count >= f->bufsiz); if (bypass) { /* Large read, bypass buffer */ rdptr = p; nb = count; } else { rdptr = f->buf + _IO_UNGET_SLOP; nb = f->bufsiz; } rv = read(f->pub._IO_fileno, rdptr, nb); if (rv == -1) { if (errno == EINTR || errno == EAGAIN) continue; f->pub._IO_error = true; return bytes; } else if (rv == 0) { f->pub._IO_eof = true; return bytes; } if (bypass) { p += rv; bytes += rv; count -= rv; } else { f->ibytes = rv; f->data = rdptr; } if (!count) return bytes; } /* If we get here, the buffer is non-empty */ nb = f->ibytes; nb = (count < nb) ? count : nb; if (nb) { memcpy(p, f->data, nb); p += nb; bytes += nb; count -= nb; f->data += nb; f->ibytes -= nb; } } return bytes; }
/*------------------------------------------- | Name:fwrite | Description: | Parameters: | Return Type: | Comments: Like fread, fwrite will often be used | to write out large chunks of data; | calling write() directly can be a big | win in this case. | But first we check to see if there's | space in the buffer. | Again this ignores __MODE__IOTRAN. | See: ---------------------------------------------*/ int __fwrite(char *buf,int size,int nelm,FILE *fp){ register int v; int len; unsigned bytes, put; //int errno; __thr_safe_lock(fp); v = fp->mode; /* If last op was a read ... */ if ((v & __MODE_READING) && __fflush(fp)) { __thr_safe_unlock(fp); return 0; } /* Can't write or there's been an EOF or error then return 0 */ if ((v & (__MODE_WRITE | __MODE_EOF | __MODE_ERR)) != __MODE_WRITE) { __thr_safe_unlock(fp); return 0; } /* This could be long, doesn't seem much point tho */ bytes = size * nelm; len = fp->bufend - fp->bufpos; /* Flush the buffer if not enough room */ if (bytes > (unsigned)len) if (__fflush(fp)) { __thr_safe_unlock(fp); return 0; } len = fp->bufend - fp->bufpos; if (bytes <= (unsigned)len) /* It'll fit in the buffer ? */ { fp->mode |= __MODE_WRITING; memcpy(fp->bufpos, buf, bytes); fp->bufpos += bytes; /* If we're not fully buffered */ if (v & (_IOLBF | _IONBF)) __fflush(fp); __thr_safe_unlock(fp); return nelm; } else /* Too big for the buffer */ { put = bytes; do { len = write(fp->fd, buf, bytes); if( len > 0 ) { buf+=len; bytes-=len; } } while (len > 0 || (len != -1 /*&& errno == EINTR*/)); //to do: (len==-1 && errno == EINTR) test. if (len < 0) fp->mode |= __MODE_ERR; put -= bytes; } __thr_safe_unlock(fp); return put / size; }
/*------------------------------------------- | Name:fflush | Description: | Parameters: | Return Type: | Comments: | See: ---------------------------------------------*/ int __fflush(FILE *fp){ int len, cc, rv=0; char * bstart; //int errno; __thr_safe_lock(fp); if (fp == NULL) /* On NULL flush the lot. */ { if (__fflush(stdin)) { __thr_safe_unlock(fp); return EOF; } if (__fflush(stdout)) { __thr_safe_unlock(fp); return EOF; } if (__fflush(stderr)) { __thr_safe_unlock(fp); return EOF; } for (fp = __IO_list; fp; fp = fp->next) if (__fflush(fp)) { __thr_safe_unlock(fp); return EOF; } __thr_safe_unlock(fp); return 0; } /* If there's output data pending */ if (fp->mode & __MODE_WRITING) { len = fp->bufpos - fp->bufstart; if (len) { bstart = fp->bufstart; /* * The loop is so we don't get upset by signals or partial writes. */ do { cc = write(fp->fd, bstart, len); if( cc > 0 ) { bstart+=cc; len-=cc; } } while ( cc>0 || (cc != -1 /*&& errno == EINTR*/)); //to do: (cc == -1 && errno == EINTR) test. /* * If we get here with len!=0 there was an error, exactly what to * do about it is another matter ... * * I'll just clear the buffer. */ if (len) { fp->mode |= __MODE_ERR; rv = EOF; } } } /* If there's data in the buffer sychronise the file positions */ else if (fp->mode & __MODE_READING) { /* Humm, I think this means sync the file like fpurge() ... */ /* Anyway the user isn't supposed to call this function when reading */ len = fp->bufread - fp->bufpos; /* Bytes buffered but unread */ /* If it's a file, make it good */ if (len > 0 && (lseek(fp->fd, (off_t)-len, 1) < 0)) { /* Hummm - Not certain here, I don't think this is reported */ /* * fp->mode |= __MODE_ERR; return EOF; */ } } /* All done, no problem */ fp->mode &= (~(__MODE_READING|__MODE_WRITING|__MODE_EOF|__MODE_UNGOT)); fp->bufread = fp->bufwrite = fp->bufpos = fp->bufstart; __thr_safe_unlock(fp); return rv; }