C标准库stdio源码分析

时间:2021-01-19 23:58:34
//
// stdio.h
//
// Standard I/O routines
//
// Copyright (C) 2002 Michael Ringgaard. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
//
// 1. Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
// 3. Neither the name of the project nor the names of its contributors
// may be used to endorse or promote products derived from this software
// without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
// SUCH DAMAGE.
//

#if _MSC_VER > 1000
#pragma once
#endif

#ifndef STDIO_H
#define STDIO_H

#include <sys/types.h>

#ifndef _FPOS_T_DEFINED
#define _FPOS_T_DEFINED
typedef long fpos_t;
#endif

#ifndef SEEK_SET
#define SEEK_SET 0
#define SEEK_CUR 1
#define SEEK_END 2
#endif

#define L_tmpnam 256
#define FILENAME_MAX 256
#define EOF (-1)
#define BUFSIZ 512

struct _iobuf {
char *ptr; //缓冲区指针
int cnt; //流缓冲区大小
char *base; //缓冲区指针
int flag; //文件当前状态 _IORD _IOWR _IORW 等等...
handle_t file; //Unix中的文件描述符
int charbuf;
int bufsiz;
int phndl;
};

typedef struct _iobuf FILE;

#define stdin __getstdfile(0)
#define stdout __getstdfile(1)
#define stderr __getstdfile(2)

#define _IORD 0x0001 // 0000 0000 0000 0001 read
#define _IOWR 0x0002 // 0000 0000 0000 0010 write

#define _IOFBF 0x0000 // 全缓冲
#define _IOLBF 0x0040 // 行缓冲
#define _IONBF 0x0004 // 无缓冲

#define _IOOWNBUF 0x0008
#define _IOEXTBUF 0x0100
#define _IOTMPBUF 0x1000

#define _IOEOF 0x0010
#define _IOERR 0x0020
#define _IOSTR 0x0040
#define _IORW 0x0080 // 0000 0000 0000 0100

#define _IOCRLF 0x8000

#ifdef __cplusplus
extern "C" {
#endif

int filbuf(FILE *stream);
int flsbuf(int, FILE *stream);

FILE *fdopen(int fd, const char *mode);
FILE *freopen(const char *filename, const char *mode, FILE *stream);
FILE *fopen(const char *filename, const char *mode);

FILE *popen(const char *command, const char *mode);
int pclose(FILE *stream);

void clearerr(FILE *stream);
int fclose(FILE *stream);
int fflush(FILE *stream);

int fgetc(FILE *stream);
int fputc(int c, FILE *stream);

char *fgets(char *string, int n, FILE *stream);
int fputs(const char *string, FILE *stream);

char *gets(char *buf);
int puts(const char *string);

size_t fread(void *buffer, size_t size, size_t num, FILE *stream);
size_t fwrite(const void *buffer, size_t size, size_t num, FILE *stream);

int fseek(FILE *stream, long offset, int whence);
long ftell(FILE *stream);
void rewind(FILE *stream);
int fsetpos(FILE *stream, const fpos_t *pos);
int fgetpos(FILE *stream, fpos_t *pos);

void perror(const char *message);

void setbuf(FILE *stream, char *buffer);
int setvbuf(FILE *stream, char *buffer, int type, size_t size);

int ungetc(int c, FILE *stream);

int fready(FILE *stream);

int remove(const char *filename);
osapi int rename(const char *oldname, const char *newname);

FILE *tmpfile();
char *tmpnam(char *string);
char *tempnam(const char *dir, const char *prefix);

int vfprintf(FILE *stream, const char *fmt, va_list args);
int fprintf(FILE *stream, const char *fmt, ...);

int vprintf(const char *fmt, va_list args);
int printf(const char *fmt, ...);

int vsprintf(char *buf, const char *fmt, va_list args);
int sprintf(char *buf, const char *fmt, ...);

int vsnprintf(char *buf, size_t count, const char *fmt, va_list args);
int snprintf(char *buf, size_t count, const char *fmt, ...);

int fscanf(FILE *stream, const char *fmt, ...);
int scanf(const char *fmt, ...);
int sscanf(const char *buffer, const char *fmt, ...);

int vfscanf(FILE *stream, const char *fmt, va_list args);
int vscanf(const char *fmt, va_list args);
int vsscanf(const char *buffer, const char *fmt, va_list args);

FILE *__getstdfile(int n);

#ifdef __cplusplus
}
#endif

#define feof(stream) ((stream)->flag & _IOEOF)
#define ferror(stream) ((stream)->flag & _IOERR)
#define fileno(stream) ((stream)->file) //not a ISO C but POSIX.1 support

#define getc(stream) (--(stream)->cnt >= 0 ? 0xff & *(stream)->ptr++ : filbuf(stream))
#define putc(c, stream) (--(stream)->cnt >= 0 ? 0xff & (*(stream)->ptr++ = (char) (c)) : flsbuf((c), (stream)))
#define getchar() getc(stdin)
#define putchar(c) putc((c), stdout)

#endif

//
// stdio.c
//
// Standard I/O routines
//
// Copyright (C) 2002 Michael Ringgaard. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
//
// 1. Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
// 3. Neither the name of the project nor the names of its contributors
// may be used to endorse or promote products derived from this software
// without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
// SUCH DAMAGE.
//

#include <os.h>

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdarg.h>
#include <crtbase.h>
#include <atomic.h>

#define bigbuf(s) ((s)->flag & (_IOOWNBUF | _IOEXTBUF | _IOTMPBUF))
#define anybuf(s) ((s)->flag & (_IOOWNBUF | _IOEXTBUF | _IOTMPBUF | _IONBF))

/*如果文件是 _IORD |_IOWR |_IORW 三种状态任意一个 被freopen()调用*/
#define inuse(s) ((s)->flag & (_IORD |_IOWR |_IORW))

static void exit_stdio(void) {
// Flush stdout and stderr
fflush(stdout);
fflush(stderr);
}

static void init_stdio() {
struct process *proc = gettib()->proc;
struct crtbase *crtbase = (struct crtbase *) proc->crtbase;

// Only initialize on first call.
if (crtbase->stdio_initialized) return;
if (atomic_increment(&crtbase->stdio_init) == 1) {
// Set up stdin, stdout, and stderr.
crtbase->iob[0].file = proc->iob[0];
crtbase->iob[0].base = crtbase->iob[0].ptr = crtbase->stdinbuf;
crtbase->iob[0].flag = _IORD | _IOEXTBUF;
crtbase->iob[0].bufsiz = BUFSIZ;

crtbase->iob[1].file = proc->iob[1];
crtbase->iob[1].flag = _IOWR | _IONBF | _IOCRLF;

crtbase->iob[2].file = proc->iob[2];
crtbase->iob[2].flag = _IOWR | _IONBF | _IOCRLF;

atexit(exit_stdio);
crtbase->stdio_initialized = 1;
} else {
// Wait until initialization done.
while (!crtbase->stdio_initialized) msleep(0);
}
}

FILE *__getstdfile(int n) {
struct process *proc = gettib()->proc;
struct crtbase *crtbase = (struct crtbase *) proc->crtbase;

if (!crtbase->stdio_initialized) init_stdio();
return &crtbase->iob[n];
}

static void getbuf(FILE *stream) {
// Try to get a buffer
if (stream->base = malloc(BUFSIZ)) {
// Got a buffer
stream->flag |= _IOOWNBUF;
stream->bufsiz = BUFSIZ;
} else {
// Did NOT get a buffer - use single char buffering.
stream->flag |= _IONBF;
stream->base = (char *) &stream->charbuf;
stream->bufsiz = 1;
}

stream->ptr = stream->base;
stream->cnt = 0;
}

static void freebuf(FILE *stream) {
if (stream->flag & _IOOWNBUF) {
free(stream->base);
stream->flag &= ~_IOOWNBUF;
stream->base = stream->ptr = NULL;
stream->cnt = 0;
}
}

int _stbuf(FILE *stream, char *buf, int bufsiz) {
// Setup temp buffering
stream->base = stream->ptr = buf;
stream->cnt = bufsiz;
stream->flag |= (_IOWR | _IOTMPBUF | _IOEXTBUF);

return 0;
}

void _ftbuf(FILE *stream) {
if (stream->flag & _IOTMPBUF) {
// Flush the stream and tear down temp buffering
fflush(stream);
stream->flag &= ~(_IOEXTBUF | _IOTMPBUF);
stream->bufsiz = 0;
stream->base = stream->ptr = NULL;
}
}


static int write_translated(int fh, char *buf, int len) {
char *ptr = buf;
char *end = buf + len;
int written = 0;
int rc;

while (ptr < end) {
if (*ptr == '\n') {
if (buf < ptr) {
rc = write(fh, buf, ptr - buf);
if (rc < 0) return rc;
written += rc;
}

rc = write(fh, "\r", 1);
if (rc < 0) return -1;

buf = ptr;
}
ptr++;
}

if (buf < end) {
rc = write(fh, buf, end - buf);
if (rc < 0) return rc;
written += rc;
}

return written;
}

int filbuf(FILE *stream) {
if (stream->flag & _IOSTR) return EOF;

if (stream->flag & _IOWR) {
stream->flag |= _IOERR;
return EOF;
}

stream->flag |= _IORD;

// Get a buffer, if necessary.
if (!anybuf(stream)) {
getbuf(stream);
} else {
stream->ptr = stream->base;
}
stream->cnt = read(fileno(stream), stream->base, stream->bufsiz);

if (stream->cnt <= 0) {
stream->flag |= stream->cnt ? _IOERR : _IOEOF;
stream->cnt = 0;
return EOF;
}

stream->cnt--;

return *stream->ptr++ & 0xff;
}

int flsbuf(int ch, FILE *stream) {
int count;
int written;
int fh;
char chbuf;

fh = fileno(stream);

if (!(stream->flag & (_IOWR | _IORW)) || (stream->flag & _IOSTR)) {
stream->flag |= _IOERR;
return -1;
}

if (stream->flag & _IORD) {
stream->cnt = 0;
if (stream->flag & _IOEOF) {
stream->ptr = stream->base;
stream->flag &= ~_IORD;
} else {
stream->flag |= _IOERR;
return -1;
}
}

stream->flag |= _IOWR;
stream->flag &= ~_IOEOF;
written = count = stream->cnt = 0;

// Get a buffer for this stream, if necessary
if (!anybuf(stream)) getbuf(stream);

// If big buffer is assigned to stream
if (bigbuf(stream)) {
count = stream->ptr - stream->base;
stream->ptr = stream->base + 1;
stream->cnt = stream->bufsiz - 1;

if (count > 0) {
if (stream->flag & _IOCRLF) {
written = write_translated(fh, stream->base, count);
} else {
written = write(fh, stream->base, count);
}
}

*stream->base = (char) ch;
} else {
// Perform single character output (either _IONBF or no buffering)
count = 1;
chbuf = (char) ch;
if (stream->flag & _IOCRLF) {
written = write_translated(fh, &chbuf, count);
} else {
written = write(fh, &chbuf, count);
}
}

// See if the write was successful.
if (written != count) {
stream->flag |= _IOERR;
return -1;
}

return ch & 0xff;
}

/* 内部函数 open_file
* 作用:把流与文件关联

*/
static int open_file(FILE *stream, const char *filename, const char *mode) {
int oflag;
int streamflag;
handle_t handle;

switch (*mode) {
case 'r':
oflag = O_RDONLY;
streamflag = _IORD;
break;

case 'w':
oflag = O_WRONLY | O_CREAT | O_TRUNC;
streamflag = _IOWR;
break;

case 'a':
oflag = O_WRONLY | O_CREAT | O_APPEND;
streamflag = _IOWR;
break;

default:
errno = EINVAL;
return -1;
}

while (*++mode) {
switch (*mode) {
case '+':
oflag |= O_RDWR;
oflag &= ~(O_RDONLY | O_WRONLY);
streamflag |= _IORW;
streamflag &= ~(_IORD | _IOWR);
break;

case 't':
oflag &= ~(O_TEXT | O_BINARY);
oflag |= O_TEXT;
break;

case 'b':
oflag &= ~(O_TEXT | O_BINARY);
oflag |= O_BINARY;
break;

case 'c':
case 'n':
break;

case 'S':
oflag |= O_SEQUENTIAL;
break;

case 'R':
oflag |= O_RANDOM;
break;

case 'T':
oflag |= O_SHORT_LIVED;
break;

case 'D':
oflag |= O_TEMPORARY;
break;

case ' ':
// Ignore
break;

default:
errno = EINVAL;
return -1;
}
}

/* 打开或新建 一个文件 unix 系统调用 */
handle = open(filename, oflag, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
if (handle < 0) return -1;

stream->flag = streamflag;
stream->cnt = 0;
stream->base = stream->ptr = NULL;
stream->file = handle; //将open()的文件描述符传递给stream的文件描述符
stream->phndl = NOHANDLE;

return 0;
}

/* close_file 关闭流与文件的关联
*
*
*/
static int close_file(FILE *stream) {
int rc = EOF;

if (stream->flag & _IOSTR) {
stream->flag = 0;
return EOF;
}

rc = fflush(stream);
freebuf(stream);

if (close(fileno(stream)) < 0) rc = EOF;

return rc;
}

FILE *fdopen(int fd, const char *mode) {
FILE *stream;
int streamflag;

switch (*mode) {
case 'r':
streamflag = _IORD;
break;

case 'w':
streamflag = _IOWR;
break;

case 'a':
streamflag = _IOWR;
break;

default:
errno = EINVAL;
return NULL;
}

while (*++mode) {
switch (*mode) {
case '+':
streamflag |= _IORW;
streamflag &= ~(_IORD | _IOWR);
break;
}
}

stream = malloc(sizeof(FILE));
if (!stream) {
errno = ENFILE;
return NULL;
}

stream->flag = streamflag;
stream->cnt = 0;
stream->base = stream->ptr = NULL;
stream->file = fd;
stream->phndl = NOHANDLE;

return stream;
}


FILE *freopen(const char *filename, const char *mode, FILE *stream) {
if (inuse(stream)) close_file(stream); //参考46行
if (open_file(stream, filename, mode) < 0) { //参考261行 open_file()
free(stream);
return NULL;
}

return stream;
}

FILE *fopen(const char *filename, const char *mode) {
FILE *stream;

stream = malloc(sizeof(FILE)); //在堆中malloc一个流
if (!stream) {
errno = ENFILE;
return NULL;
}
/* 把流与文件关联 */
if (open_file(stream, filename, mode) < 0) {
free(stream);
return NULL;
}

return stream;
}

/* clearerr函数的作用是清除由stream
* 指向的文件流的文件尾标识和错误标识。
* 它没有返回值,也未定义任何错误。
*/
void clearerr(FILE *stream) {
// Clear flags
stream->flag &= ~(_IOERR | _IOEOF);
}

/* 关闭文件函数 */
int fclose(FILE *stream) {
int rc;

rc = close_file(stream);
free(stream);
return rc;
}

/* 清空流文件缓冲区*/
int fflush(FILE *stream) {
int rc = 0;
int count;
int written;

if (!stream) stream = stdout;
if ((stream->flag & (_IORD | _IOWR)) == _IOWR &&
bigbuf(stream) &&
(count = stream->ptr - stream->base) > 0) {
if (stream->flag & _IOCRLF) {
written = write_translated(fileno(stream), stream->base, count);
} else {
written = write(fileno(stream), stream->base, count);
}

if (written == count) {
// If this is a read/write file, clear _IOWR so that next operation can be a read
if (stream->flag & _IORW) stream->flag &= ~_IOWR;
} else {
stream->flag |= _IOERR;
rc = EOF;
}
}

stream->ptr = stream->base;
stream->cnt = 0;

return rc;
}

int fgetc(FILE *stream) {
return getc(stream);
}

int fputc(int c, FILE *stream) {
return putc(c, stream);
}

/* fgets 读进'\n' */
char *fgets(char *string, int n, FILE *stream) {
char *ptr = string;
int ch;

if (n <= 0) return NULL;

while (--n) {
if ((ch = getc(stream)) == EOF) {
if (ptr == string) return NULL;
break;
}

if ((*ptr++ = ch) == '\n') break;
}

*ptr = '\0';
return string;
}

int fputs(const char *string, FILE *stream) {
int len;
int written;

len = strlen(string);

if (stream->flag & _IONBF) {
char buf[BUFSIZ];

_stbuf(stream, buf, BUFSIZ);
written = fwrite(string, 1, len, stream);
_ftbuf(stream);
} else {
written = fwrite(string, 1, len, stream);
}

return written == len ? 0 : EOF;
}

/*从stdin流中读取字符串,
*直至接受到换行符或EOF时停止,
*并将读取的结果存放在buf指针
*所指向的字符数组中。换行符不作为
*读取串的内容,读取的换行符被转换为null值
*并由此来结束字符串。
*/

char *gets(char *buf)
{
char *p = buf;
int ch;

while (1) {
ch = getchar();
if (ch == EOF) {
if (errno == ETIMEDOUT) continue;
return NULL;
}

if (ch == 8) { // 8 ascii means backspace
if (p > buf) {
putchar('\b');
putchar(' ');
putchar('\b');
p--;
}
} else if (ch == '\r' || ch =='\n' || ch >= ' ') {
putchar(ch);
if (ch == '\r') putchar('\n');
if (ch == '\n' || ch == '\r') break;
*p++ = ch;
}
}

*p = 0;
return buf;
}

/*puts()函数用来向标准输出设备(屏幕)
*写字符串并换行
*/
int puts(const char *string) {
FILE *stream = stdout;

if (stream->flag & _IONBF) {
char buf[BUFSIZ];

_stbuf(stream, buf, BUFSIZ);

while (*string) {
if (putchar(*string) == EOF) {
_ftbuf(stream);
return EOF;
}
string++;
}

if (putchar('\n') == EOF) {
_ftbuf(stream);
return EOF;
}

_ftbuf(stream);
} else {
while (*string) {
if (putchar(*string) == EOF) return EOF;
string++;
}

if (putchar('\n') == EOF) return EOF;
}

return 0;
}

size_t fread(void *buffer, size_t size, size_t num, FILE *stream) {
char *data; // Point to where should be read next
unsigned total; // Total bytes to read
unsigned count; // Num bytes left to read
unsigned bufsize; // Size of stream buffer
unsigned nbytes; // How much to read now
unsigned nread; // How much we did read
int c; // A temp char

// Initialize local vars
data = buffer;

if ((count = total = size * num) == 0) return 0;

if (anybuf(stream)) {
// Already has buffer, use its size
bufsize = stream->bufsiz;
} else {
// Assume will get BUFSIZ buffer
bufsize = BUFSIZ;
}

// Here is the main loop -- we go through here until we're done
while (count != 0) {
// if the buffer exists and has characters, copy them to user buffer
if (anybuf(stream) && stream->cnt != 0) {
// How much do we want?
nbytes = (count < (unsigned) stream->cnt) ? count : stream->cnt;
memcpy(data, stream->ptr, nbytes);

// Update stream and amount of data read
count -= nbytes;
stream->cnt -= nbytes;
stream->ptr += nbytes;
data += nbytes;
} else if (count >= bufsize) {
// If we have more than bufsize chars to read, get data
// by calling read with an integral number of bufsiz
// blocks.

// Calc chars to read -- (count / bufsize) * bufsize
nbytes = bufsize ? count - count % bufsize : count;

nread = read(fileno(stream), data, nbytes);
if (nread == 0) {
// End of file -- out of here
stream->flag |= _IOEOF;
return (total - count) / size;
} else if ((int) nread < 0) {
// Error -- out of here
stream->flag |= _IOERR;
return (total - count) / size;
}

// Update count and data to reflect read
count -= nread;
data += nread;
} else {
// Less than bufsize chars to read, so call filbuf to fill buffer
if ((c = filbuf(stream)) == EOF) {
// Error or eof, stream flags set by filbuf
return (total - count) / size;
}

// filbuf returned a char -- store it
*data++ = (char) c;
count--;

// Update buffer size
bufsize = stream->bufsiz;
}
}

// We finished successfully, so just return num
return num;
}

size_t fwrite(const void *buffer, size_t size, size_t num, FILE *stream) {
const char *data; // Point to where data comes from next
unsigned total; // Total bytes to write
unsigned count; // Num bytes left to write
unsigned bufsize; // Size of stream buffer
unsigned nbytes; // Number of bytes to write now
unsigned nwritten; // Number of bytes written
int c; // A temp char

// Initialize local vars
data = buffer;
count = total = size * num;
if (count == 0) return 0;

if (anybuf(stream)) {
// Already has buffer, use its size
bufsize = stream->bufsiz;
} else {
// Assume will get BUFSIZ buffer
bufsize = BUFSIZ;
}

// Here is the main loop -- we go through here until we're done
while (count != 0) {
// If the buffer is big and has room, copy data to buffer
if (bigbuf(stream) && stream->cnt != 0) {
// How much do we want?
nbytes = (count < (unsigned) stream->cnt) ? count : stream->cnt;
memcpy(stream->ptr, data, nbytes);

// Update stream and amount of data written
count -= nbytes;
stream->cnt -= nbytes;
stream->ptr += nbytes;
data += nbytes;
} else if (count >= bufsize) {
// If we have more than bufsize chars to write, write
// data by calling write with an integral number of
// bufsiz blocks. If we reach here and we have a big
// buffer, it must be full so flush it.

if (bigbuf(stream)) {
if (fflush(stream)) {
// Error, stream flags set -- we're out of here
return (total - count) / size;
}
}

// Calc chars to write -- (count / bufsize) * bufsize
nbytes = bufsize ? (count - count % bufsize) : count;

if (stream->flag & _IOCRLF) {
nwritten = write_translated(fileno(stream), (char *) data, nbytes);
} else {
nwritten = write(fileno(stream), data, nbytes);
}

if ((int) nwritten < 0) {
// Error -- out of here
stream->flag |= _IOERR;
return (total - count) / size;
}

// Update count and data to reflect write
count -= nwritten;
data += nwritten;

if (nwritten < nbytes) {
// Error -- out of here
stream->flag |= _IOERR;
return (total - count) / size;
}
} else {
// Buffer full and not enough chars to do direct write, so do a flsbuf.
c = *data;
if (flsbuf(c, stream) == EOF) {
// Error or eof, stream flags set by _flsbuf
return (total - count) / size;
}

// flsbuf wrote a char -- update count
++data;
--count;

// Update buffer size
bufsize = stream->bufsiz > 0 ? stream->bufsiz : 1;
}
}

// We finished successfully, so just return num
return num;
}

int fseek(FILE *stream, long offset, int whence) {
if (whence != SEEK_SET && whence != SEEK_CUR && whence != SEEK_END) {
errno = EINVAL;
return -1;
}

// Clear EOF flag
stream->flag &= ~_IOEOF;

// Adjust for prefetched data on relative seek.
if (whence == SEEK_CUR && (stream->flag & _IORD)) offset -= stream->cnt;

// Flush buffer as necessary
fflush(stream);

// If file opened for read/write, clear flags since we don't know
// what the user is going to do next.
if (stream->flag & _IORW) stream->flag &= ~(_IOWR | _IORD);

// Seek to the desired location and return
return lseek(fileno(stream), offset, whence) < 0 ? -1 : 0;
}

long ftell(FILE *stream) {
long filepos;

if (stream->cnt < 0) stream->cnt = 0;
if ((filepos = tell(fileno(stream))) < 0L) return -1;
if (!bigbuf(stream)) return filepos - stream->cnt;

if (stream->flag & _IORD) {
filepos -= stream->cnt;
} else if (stream->flag & _IOWR) {
filepos += (stream->ptr - stream->base);
}

return filepos;
}

void rewind(FILE *stream) {
fseek(stream, 0, SEEK_SET);
clearerr(stream);
}

int fsetpos(FILE *stream, const fpos_t *pos) {
return fseek(stream, *pos, SEEK_SET);
}

int fgetpos(FILE *stream, fpos_t *pos) {
long n;

n = ftell(stream);
if (n < 0) return n;
*pos = n;
return 0;
}

void perror(const char *message) {
fputs(message, stderr);
fputs(": ", stderr);
fputs(strerror(errno), stderr);
fputs("\n", stderr);
}

void setbuf(FILE *stream, char *buffer) {
if (buffer == NULL) {
setvbuf(stream, NULL, _IONBF, 0);
} else {
setvbuf(stream, buffer, _IOFBF, BUFSIZ);
}
}

int setvbuf(FILE *stream, char *buffer, int type, size_t size) {
fflush(stream);
freebuf(stream);

stream->flag &= ~(_IOOWNBUF | _IOEXTBUF | _IONBF);

if (type & _IONBF) {
stream->flag |= _IONBF;
buffer = (char *) &stream->charbuf;
size = 1;
} else if (buffer == NULL) {
if ((buffer = malloc(size)) == NULL ) return -1;
stream->flag |= _IOOWNBUF;
} else {
stream->flag |= _IOEXTBUF;
}

stream->bufsiz = size;
stream->ptr = stream->base = buffer;
stream->cnt = 0;

return 0;
}

int ungetc(int c, FILE *stream) {
// Stream must be open for read and can NOT be currently in write mode.
// Also, ungetc() character cannot be EOF.
if (c == EOF) return EOF;
if (!((stream->flag & _IORD) || ((stream->flag & _IORW) && !(stream->flag & _IOWR)))) return EOF;

// If stream is unbuffered, get one.
if (stream->base == NULL) getbuf(stream);

// Now we know base != NULL; since file must be buffered

if (stream->ptr == stream->base) {
if (stream->cnt) return EOF;
stream->ptr++;
}

if (stream->flag & _IOSTR) {
// If stream opened by sscanf do not modify buffer
if (*--stream->ptr != (char) c) {
++stream->ptr;
return EOF;
}
} else {
*--stream->ptr = (char) c;
}

stream->cnt++;
stream->flag &= ~_IOEOF;
stream->flag |= _IORD;

return c & 0xff;
}

/* 删除文件 直接使用unlink系统调用*/
int remove(const char *filename) {
return unlink(filename);
}

int fready(FILE *stream) {
struct pollfd pfd;

// Ready for read if there is anything in the buffer
if (stream->cnt > 0) return 1;

// String streams have all data in the buffer
if (stream->flag & _IOSTR) return 0;

// Must be in read mode
if (stream->flag & _IOWR) return 0;

// Poll input file for available data
pfd.fd = fileno(stream);
pfd.events = POLLIN;
pfd.revents = 0;
return poll(&pfd, 1, 0) > 0 && (pfd.revents & POLLIN);
}