8 ŚRODOWISKO SYSTEMU UNIX
#define stdin (&_iob[0])
#define stdout (&_iob[1])
#define stderr (&_iob[2])
enum _flags {
_READ =01, /* plik otwarty do czytania */
_WRITE = 02, I* plik otwarty do pisania */
_UNBUF = 04, /* plik niebuforowany */
_EOF = 010, I* napotkano koniec pliku */
_ERR = 020 I* wystąpił błąd przy obsłudze pliku */
int _fillbuf(FILE *); /* wypełnij bufor */
int _flushbuf(int, FILE *); /* wypisz bufor */
fdefine feof(p) (((p)->flag & _EOF) != 0)
#define ferror(p) (((p)->flag & _ERR) != 0)
#define fileno(p) ((p)—>fd) /* deskryptor pliku */
#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)
Makro getc zazwyczaj zmniejsza licznik znaków, przesuwa wskaźnik i daje znak. (Przypominamy, że zbyt długi wiersz #define jest kontynuowany za pomocą znaku \.) Jeżeli jednak licznik znaków stanie się ujemny, to getc wywoła funkcję _fillbuf, która ponownie wypełni bufor, zainicjuje zawartość struktury i zwróci znak. Znaki otrzymywane za pomocą makra getc są zrzutowane do unsigned char, co gwarantuje, źe każdy znak będzie dodatni.
Definicję makra putc zamieściliśmy po to, aby pokazać (bez zagłębiania się w szczegóły), że działa prawie w ten sam sposób co getc, wywołując funkcję -flushbuf, kiedy bufor jest pełny. Dołączyliśmy także makra udostępniające deskryptor pliku oraz takie informacje o stanie programu, jak wartość znacznika końca pliku czy znacznika błędów.
Teraz możemy już napisać funkcję fopen. Jej działanie polega przede wszystkim na dostarczeniu otwartego pliku, określeniu prawidłowej pozycji w tym pliku i ustawieniu bitowych znaczników opisujących jego właściwy stan. Funkcja fopen nie przy-8.5 PRZYKŁAD - REALIZACJA FUNKCJI FOPEN I GETC
powered by
Mi siol
dzieła pamięci na bufor; robi to funkcja -fillbuf wtedy, kiedy plik jesl pierwszy.
#include <stdio.h>
#include <fcntl.h>
#include "syscalls.h”
#define PERMS 0666 /* czytanie i pisanie dla wszystkich */
I* fopen: otwórz plik, daj wskaźnik pliku */
FILE *fopen(char *name, char *mode)
{
int fd;
FILE *fp;
if (*mode != Y && *mode != ’w’ && *mode != ’a’) return NULL;
for (fp = Job; fp < Job + OPEN_MAX; ff>++) if ((fp—>flag & (_READ | _WRITE)) == 0)
break; /* wolne miejsce w tablicy plików */ if (fp >= Job + OPEN_MAX)
return NULL; /* nie ma wolnego miejsca */
if (*mode == ’w')
fd = creat(name, PERMS); else if (*mode == ’a’) {
if ((fd = open(name, 0_WRONLY, 0)) == -1) fd = creat(name, PERMS); lseek(fd, OL, 2);
} else
fd = open(name, O-RDONLY, 0); if (fd == -1) i* nie ma dostępu do pliku */ return NULL; fp->fd = fd; fp->cnt = 0; fp->base = NULL;
fp—>flag = (*mode == Y) ? _READ : _WRITE; return fp;
Ta wersja funkcji fopen nie obsługuje wszystkich możliwych sposobów dostępu do Pliku, jakie opisano w standardzie, chociaż dodanie ich nie wymaga specjalnie dużego
235