開発環境
- OS X Lion - Apple(OS)
- Emacs、BBEdit - Bare Bones Software, Inc. (Text Editor)
- プログラミング言語: C
- Clang (コンパイラ)
プログラミング言語C 第2版 ANSI規格準拠 (B.W. カーニハン D.M. リッチー (著)、 石田 晴久 (翻訳)、共立出版)の第8章(UNIXシステム・インタフェース)、8.4(ランダム・アクセス - Lseek)、8.5(例 - Fopen と Getc の実現)の演習8-3を解いてみる。
その他参考書籍
- プログラミング言語Cアンサー・ブック 第2版 (クロビス・L.トンド、スコット・E.ギンペル(著)、矢吹 道郎(翻訳))
演習 8-3.
コード
sample.c
#define NULL 0 #define EOF (-1) #define BUFSIZ 1024 #define OPEN_MAX 20 typedef struct _iobuf { int cnt; char *ptr; char *base; int flag; int fd; } FILE; FILE _iob[OPEN_MAX]; #define stdin (&_iob[0]) #define stdout (&_iob[1]) #define stderr (&_iob[2]) enum _flags { _READ = 01, _WRITE = 02, _UNBUF = 04, _EOF = 010, _ERR = 020 }; FILE _iob[OPEN_MAX] = { { 0, (char *) 0, (char *) 0, _READ, 0}, { 0, (char *) 0, (char *) 0, _WRITE, 1}, { 0, (char *) 0, (char *) 0, _WRITE | _UNBUF, 2} }; int _fillbuf(FILE *); int _flushbuf(int, FILE *); #define feof(p) (((p)->flag & _EOF) != 0) #define ferror(p) (((p)->flag & _ERR) != 0) #define fileno(p) ((p)->fd) #define getc(p) (--(p)->cnt >= 0 \ ? (unsigned char) *(p)->ptr++ : _fillbuf(p)) #define putc(x,p) (--(p)->cnt >= 0 \ ? *(p)->ptr++ = (x) : _flushbuf((x), p)) #define getchar() getc(stdin) #define putchar(x) putc((x), stdout) #include <fcntl.h> #define PERMS 0666 FILE *fopen(char *name, 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 = creat(name, PERMS); else if (*mode == 'a') { if ((fd = open(name, O_WRONLY, 0)) == -1) fd = creat(name, PERMS); lseek(fd, 0L, 2); } else fd = open(name, O_RDONLY, 0); if (fd == -1) return NULL; fp->fd = fd; fp->cnt = 0; fp->base = NULL; fp->flag = (*mode == 'r') ? _READ : _WRITE; return fp; } int _fillbuf(FILE *fp) { int bufsize; if ((fp->flag&(_READ|_EOF|_ERR)) != _READ) return EOF; bufsize = (fp->flag & _UNBUF) ? 1 : BUFSIZ; if (fp->base == NULL) if ((fp->base = (char *) malloc(bufsize)) == NULL) return EOF; fp->ptr = fp->base; fp->cnt = read(fp->fd, fp->ptr, bufsize); if (--fp->cnt < 0) { if (fp->cnt == -1) fp->flag |= _EOF; else fp->flag |= _ERR; fp->cnt = 0; return EOF; } return (unsigned char) *fp->ptr++; } int _flushbuf(int a, FILE *fp) { int bufsize; unsigned n; if (fp < _iob || fp >= _iob + OPEN_MAX) return EOF; if ((fp->flag & (_WRITE | _ERR)) != _WRITE) return EOF; bufsize = (fp->flag & _UNBUF) ? 1 : BUFSIZ; if (fp->base == NULL) { if ((fp->base = (char *) malloc(bufsize)) == NULL) fp->flag |= _ERR; return EOF; } else { n = fp->ptr - fp->base; if (write(fp->fd, fp->base, n) != n) fp->flag |= _ERR; return EOF; } fp->cnt = bufsize - 1; fp->ptr = fp->base; *fp->ptr++ = (char) a; return a; } int fclose(FILE *fp) { int rc; if((rc = fflush(fp)) != EOF) { fp->cnt = 0; fp->ptr = NULL; free(fp->base); fp->base = NULL; fp->flag &= ~(_READ | _WRITE); } close(fp->fd); return rc; } int fflush(FILE *fp) { int rc = 0; if (fp < _iob || fp >= _iob + OPEN_MAX) return EOF; if (fp->flag & _WRITE) rc = _flushbuf(0, fp); fp->cnt = (fp->flag & _UNBUF) ? 1 : BUFSIZ; fp->ptr = fp->base; return rc; } int main(int argc, char *argv[]) { FILE *fp; char error[1000] = "error"; int c; int i; if ((fp = fopen(*++argv, "r")) != NULL) { while ((c = getc(fp)) != EOF) putchar(c); fclose(fp); } else for (i = 0; error[i] != '\0'; i++) putchar(c); return 0; }
入出力結果(Terminal)
$ ./a.out sample.txt ??$ ./a.out sample.txt $ ./a.out sample.txt $ ./a.out sample.txt ??$ ./a.out sample.txt $
??と出力されたり、何も出力されなかったり、期待通りに動かなかった。getcのあたりがおかしいことは分かったけど、修正方法が分からず。。>_<
とりあえず次に進むことに!
0 コメント:
コメントを投稿