#include #include #include #include #include #include "stdio.h" /*for debugging*/ void putstring(const char *string) { int len; for(len = 0; string[len]; len++); _write(1, string, len); } /*foepn nameは開くファイル名 modeはファイルオープンモード "r"は読み込みのみ行うことを表わし、 "w"は書き込みのみ行うことを表わす。 "a"は追記書き込みを行うことを表わし、 ファイルシークポインタはファイルの一番後ろに設定される。 */ FILE *fopen(const char *filename, const char *mode) { int fd; FILE *fp; if(*mode != 'r' && *mode != 'w' && *mode != 'a') return NULL; for(fp = _iob; fp < _iob + OPEN_MAX; fp++) if((fp->flag & (_READ | _WRITE)) == 0) break; if(fp >= _iob + OPEN_MAX) /*空きスロットなし*/ return NULL; if(*mode == 'w') fd = _open(filename, _O_CREAT); else if(*mode == 'a'){ if ((fd = _open(filename, _O_WRONLY)) == -1) fd = _open(filename, _O_CREAT); _lseek(fd, 0L, 2); } else fd = _open(filename, _O_RDONLY); if(fd == -1) /*名前がアクセス不能*/ return NULL; fp->fd = fd; fp->counts = 0; fp->basePtr= NULL; fp->flag = (*mode == 'r') ? _READ : _WRITE; return fp; } /* fillbuf : 入力バッファーを割り当て、つめる*/ int _fillbuf(FILE *fp) { int bufsize; if ((fp->flag & (_READ | _EOF | _ERR)) != _READ) return EOF; bufsize = (fp->flag & _UNBUF) ? 1 : BUFSIZ; /*fp->basePtr == NULLならバッファーを割り当てる*/ if(fp->basePtr == NULL) if ((fp->basePtr = (char*) malloc(bufsize)) == NULL) return EOF; fp->currentPtr = fp->basePtr; fp->counts = _read(fp->fd, fp->currentPtr, bufsize); /*文字が読み込めたかチェック*/ if(--fp->counts < 0){ if(fp->counts == -1) /*fp->counts == 0だった。これはEOFになる。*/ fp->flag |= _EOF; else /*fp->counts ==-1だった。これはERRになる。*/ fp->flag |= _ERR; fp->counts = 0; return EOF; } /*バッファーの初めの文字を返し、バッファーを1つ進める。*/ return *fp->currentPtr++; } /* flushbuf : 出力バッファーを割り当て、書き込む。 putcの実装でcountsを一回デクリメントしてからこの関数が呼ばれる。 そのため、バッファーを確保したとき或いはフラッシュしたとき countをbufsizeに設定おいたら再びこの関数が呼ばれたとき 文字xはどこに入れるのかということになる。そのため、 countはバッファーの空きサイズより1つ少なくなるように設定する。 すなわち書き込む文字数はbufsize - counts - 1になる。 */ int _flushbuf(int x, FILE* fp) { int bufsize; int write_size; int cnt; if((fp->flag & (_WRITE | _EOF | _ERR)) != _WRITE) return EOF; if(fp->flag & _UNBUF) write(fp->fd, &x, 1); else bufsize = BUFSIZ; /*fp->basePtr == NULLならバッファーを割り当てる*/ if(fp->basePtr == NULL){ if ((fp->basePtr = (char*) malloc(bufsize)) == NULL) return EOF; putstring("create write BUFSIZ buffer\n"); fp->currentPtr = fp->basePtr; *fp->currentPtr++ = (unsigned char)x; fp->counts = bufsize - 2; return 0; } write_size = bufsize - fp->counts - 1; *fp->currentPtr = (unsigned char) x; fp->currentPtr = fp->basePtr; fp->counts = bufsize - 1; if (_write(fp->fd, fp->currentPtr, write_size) != write_size) fp->flag |= _ERR; } /*fflush フラッシュする。stream == NULLなら全ての出力ストリームを吐き出す。 */ int fflush(FILE *stream) { int _fflush1(FILE *stream); int bufsize, write_size; if (stream == NULL){ int i; for(i = 0; i < OPEN_MAX; i++) _fflush1(&_iob[i]); } else return _fflush1(stream); return 0; } int _fflush1(FILE *stream) { int bufsize, write_size; if ((stream->flag & _WRITE) == 0 || stream->basePtr == NULL) return 0; bufsize = ((stream->flag & _UNBUF) ? 1 : BUFSIZ); write_size = bufsize - stream->counts - 1; stream->currentPtr = stream->basePtr; stream->counts = bufsize - 1; if(_write(stream->fd, stream->currentPtr, write_size) != write_size) stream->flag |= _ERR; } /*fclose バッファーをフラッシュしてフラグをクリアする。また、確保したバッファーも クリアする。そして、フラグは0に設定する。 */ int fclose(FILE *stream) { if(stream == NULL) return 0; fflush(stream); if(stream->basePtr != NULL) free(stream->basePtr); stream->flag = 0; return 0; } /*fgetc streamの次の文字をintに変換して返す。 マクロでない、という点でgetcと同じである。 */ int fgetc(FILE *fp) { if(--fp->counts >= 0) return (int) *fp->currentPtr++; else return _fillbuf(fp); } /*fgets 最大n-1文字を配列sに読み込む。改行が来ると停止する。尚、この改行は 配列の中に収められる。この関数はs自身を返すが、ファイルの終わりに達したり、 エラーが生じるとNULLを返す。 */ char *fgets(char *s, int n, FILE *fp) { char *p = s; while(--n){ int ch; ch = getc(fp); if(ch == EOF){ break; } else if(ch == '\n'){ *p++ = ch; break; } *p++ = ch; } *p = '\0'; if(feof(fp) || ferror(fp)) return NULL; else return s; } /*fputc この関数は文字cをunsigned char型に変換してfpに書き込む。 マクロでないという点でputcと同じであるが、エラーが起こると EOFを返す。エラーが起きなければ負で無い値を返す。 */ int fputc(int c, FILE *fp) { if(--fp->counts >= 0 && c != '\n') *fp->currentPtr++ = c; else _flushbuf(c, fp); if(ferror(fp)) return EOF; else return 0; } /*fputs この関数は文字列sをfpに書き込む。エラーが起こればEOFを返し、 起きなければ負で無い値を返す。 */ int fputs(const char *s, FILE *fp) { for(; *s; s++){ putc(*s, fp); if(*s == '\n') fflush(fp); } if (ferror(fp)) return EOF; else return 0; } FILE _iob[OPEN_MAX] = { { 0, NULL, NULL, _READ, 0}, { 0, NULL, NULL, _WRITE, 1}, { 0, NULL, NULL, _WRITE | _UNBUF, 2} };