void __libc_init_stdio(void) { stdin = fdopen(0, NULL); stdout = fdopen(1, NULL); stderr = fdopen(2, NULL); stdio_pvt(stderr)->bufmode = _IONBF; }
/*@ requires file == &(stdio_pvt(file)->pub); requires valid_IO_file_pvt(stdio_pvt(file)); requires -128 <= c <= 127; behavior fail: assumes stdio_pvt(file)->obytes || stdio_pvt(file)->data <= stdio_pvt(file)->buf; assigns \nothing; ensures \result == EOF; behavior success: assumes stdio_pvt(file)->obytes == 0 && !(stdio_pvt(file)->data <= stdio_pvt(file)->buf); //assumes \valid(stdio_pvt(file)->data - 1); assigns stdio_pvt(file)->ibytes, stdio_pvt(file)->data, *(\at(stdio_pvt(file)->data, Pre)-1); ensures stdio_pvt(file)->ibytes == \at(stdio_pvt(file)->ibytes, Pre) + 1; ensures stdio_pvt(file)->data == \at(stdio_pvt(file)->data, Pre) -1; ensures *(stdio_pvt(file)->data) == c; ensures \result == c; complete behaviors; disjoint behaviors; @*/ int ungetc(int c, FILE *file) { struct _IO_file_pvt *f = stdio_pvt(file); if (f->obytes || f->data <= f->buf) return EOF; *(--f->data) = c; f->ibytes++; return c; }
int fgetc_orig(FILE *file) { struct _IO_file_pvt *f = stdio_pvt(file); unsigned char ch; if (__likely(f->ibytes)) { f->ibytes--; return (unsigned char) *f->data++; } else { return _fread(&ch, 1, file) == 1 ? ch : EOF; } }
off_t ftell(FILE *file) { #ifdef KLIBC_STREAMS_ORIG struct _IO_file_pvt *f = stdio_pvt(file); off_t pos = lseek(f->pub._IO_fileno, 0, SEEK_CUR); if (pos >= 0) pos += (int)f->obytes - (int)f->ibytes; return pos; #else return lseek(file->_IO_fileno, 0, SEEK_CUR); #endif }
/*@ requires file == &(stdio_pvt(file)->pub); requires valid_IO_file_pvt(stdio_pvt(file)); assigns stdio_pvt(file)->next->prev, stdio_pvt(file)->prev->next, stdio_pvt(file)->ibytes, stdio_pvt(file)->pub._IO_eof, stdio_pvt(file)->pub._IO_error, stdio_pvt(file)->obytes, errno; ensures \result == 0 || \result -1; @*/ int fclose(FILE *file) { struct _IO_file_pvt *f = stdio_pvt(file); int rv; fflush(file); rv = close(f->pub._IO_fileno); /* Remove from linked list */ f->next->prev = f->prev; f->prev->next = f->next; free(f); return rv; }
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; }
/*@ 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; } }
/*@ 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; }