//
// 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);
}