Хрестоматия по программированию на Си в Unix
#define getchar() getc(stdin)
#define fileno(fp) ((fp)->file)
#define feof(fp) (((fp)->flag & IOEOF) != 0)
#define ferror(fp) (((fp)->flag & IOERR) != 0)
#define clearerr(fp) ((void) ((fp)->flag &= ~(IOERR | IOEOF)))
#define getc(fp) (--(fp)->cnt < 0 ? \
filbuf(fp) : (int) *(fp)->ptr++)
#define putc(x, fp) (--(fp)->cnt < 0 ? \
flsbuf((uchar) (x), (fp)) : \
(int) (*(fp)->ptr++ = (uchar) (x)))
int fputc(int c, FILE *fp){ return putc(c, fp); }
int fgetc( FILE *fp){ return getc(fp); }
____________________
NULL.
____________________
[**] Ссылка на управляющий терминал процесса хранится в u-area каждого процесса:
u_ttyp, u_ttyd, поэтому ядро в состоянии определить какой настоящий терминал следует
открыть для вас. Если разные процессы открывают /dev/tty, они могут открыть в итоге
разные терминалы, т.е. одно имя приводит к разным устройствам! Смотри главу про
UNIX.
А. Богатырев, 1992-95 - 167 - Си в UNIX
/* Открытие файла */
FILE *fopen(char *name, char *how){
register FILE *fp; register i, rw;
for(fp = iob, i=0; i < _NFILE; i++, fp++)
if(fp->flag == 0) goto found;
return NULL; /* нет свободного слота */
found:
rw = how[1] == '+';
if(*how == 'r'){
if((fp->file = open(name, rw ? O_RDWR:O_RDONLY)) < 0)
return NULL;
fp->flag = IOREAD;
} else {
if((fp->file = open(name, (rw ? O_RDWR:O_WRONLY)| O_CREAT |
(*how == 'a' ? O_APPEND : O_TRUNC), 0666 )) < 0)
return NULL;
fp->flag = IOWRT;
}
if(rw) fp->flag = IORW;
fp->bufsiz = fp->cnt = 0; fp->base = fp->ptr = NULL;
return fp;
}
/* Принудительный сброс буфера */
void fflush(FILE *fp){
uchar *base; int full= 0;
if((fp->flag & (IONBF|IOWRT)) == IOWRT &&
(base = fp->base) != NULL && (full=fp->ptr - base) > 0){
fp->ptr = base; fp->cnt = fp->bufsiz;
if(write(fileno(fp), base, full) != full)
fp->flag |= IOERR;
}
}
/* Закрытие файла */
void fclose(FILE *fp){
if((fp->flag & (IOREAD|IOWRT|IORW)) == 0 ) return;
fflush(fp);
close(fileno(fp));
if(fp->flag & IOALLOC) free(fp->base);
fp->base = fp->ptr = NULL;
fp->cnt = fp->bufsiz = fp->flag = 0; fp->file = (-1);
}
/* Закрытие файлов при exit()-е */
void _cleanup(){
register i;
for(i=0; i < _NFILE; i++)
fclose(iob + i);
}
/* Завершить текущий процесс */
void exit(uchar code){
_cleanup();
_exit(code); /* Собственно системный вызов */
}
А. Богатырев, 1992-95 - 168 - Си в UNIX
/* Прочесть очередной буфер из файла */
int filbuf(FILE *fp){
static uchar smallbuf[_NFILE];
if(fp->flag & IORW){
if(fp->flag & IOWRT){ fflush(fp); fp->flag &= ~IOWRT; }
fp->flag |= IOREAD; /* операция чтения */
}
if((fp->flag & IOREAD) == 0 || feof(fp)) return EOF;
while( fp->base == NULL ) /* отвести буфер */
if( fp->flag & IONBF ){ /* небуферизованный */
fp->base = &smallbuf[fileno(fp)];
fp->bufsiz = sizeof(uchar);
} else if( fp == stdin ){ /* статический буфер */
fp->base = sibuf;
fp->bufsiz = sizeof(sibuf);
} else if((fp->base = malloc(fp->bufsiz = BUFSIZ)) == NULL)
fp->flag |= IONBF; /* не будем буферизовать */
else fp->flag |= IOALLOC; /* буфер выделен */
if( fp == stdin && (stdout->flag & IOTTY)) fflush(stdout);
fp->ptr = fp->base; /* сбросить на начало буфера */
if((fp->cnt = read(fileno(fp), fp->base, fp->bufsiz)) == 0 ){
fp->flag |= IOEOF; if(fp->flag & IORW) fp->flag &= ~IOREAD;
return EOF;
} else if( fp->cnt < 0 ){
fp->flag |= IOERR; fp->cnt = 0; return EOF;
}
return getc(fp);
}
А. Богатырев, 1992-95 - 169 - Си в UNIX
/* Вытолкнуть очередной буфер в файл */
int flsbuf(int c, FILE *fp){
uchar *base; int full, cret = c;
if( fp->flag & IORW ){
fp->flag &= ~(IOEOF|IOREAD);
fp->flag |= IOWRT; /* операция записи */
}
if((fp->flag & IOWRT) == 0) return EOF;
tryAgain:
if(fp->flag & IONBF){ /* не буферизован */
if(write(fileno(fp), &c, 1) != 1)
{ fp->flag |= IOERR; cret=EOF; }
fp->cnt = 0;
} else { /* канал буферизован */
if((base = fp->base) == NULL){ /* буфера еще нет */
if(fp == stdout){
if(isatty(fileno(stdout))) fp->flag |= IOTTY;
else fp->flag &= ~IOTTY;
fp->base = fp->ptr = sobuf; /* статический буфер */
fp->bufsiz = sizeof(sobuf);
goto tryAgain;
}
if((base = fp->base = malloc(fp->bufsiz = BUFSIZ))== NULL){
fp->bufsiz = 0; fp->flag |= IONBF; goto tryAgain;
} else fp->flag |= IOALLOC;
} else if ((full = fp->ptr - base) > 0)
if(write(fileno(fp), fp->ptr = base, full) != full)
{ fp->flag |= IOERR; cret = EOF; }
fp->cnt = fp->bufsiz - 1;
*base++ = c;
fp->ptr = base;
}
return cret;
}
/* Вернуть символ в буфер */
int ungetc(int c, FILE *fp){
if(c == EOF || fp->flag & IONBF || fp->base == NULL) return EOF;
if((fp->flag & IOREAD)==0 || fp->ptr <= fp->base)
if(fp->ptr == fp->base && fp->cnt == 0) fp->ptr++;
else return EOF;
fp->cnt++;
return(* --fp->ptr = c);
}
/* Изменить размер буфера */
void setbuffer(FILE *fp, uchar *buf, int size){
fflush(fp);
if(fp->base && (fp->flag & IOALLOC)) free(fp->base);
fp->flag &= ~(IOALLOC|IONBF);
if((fp->base = fp->ptr = buf) == NULL){
fp->flag |= IONBF; fp->bufsiz = 0;
} else fp->bufsiz = size;
fp->cnt = 0;
}
А. Богатырев, 1992-95 - 170 - Си в UNIX
/* "Перемотать" файл в начало */
void rewind(FILE *fp){
fflush(fp);
lseek(fileno(fp), 0L, 0);
fp->cnt = 0; fp->ptr = fp->base;
clearerr(fp);
if(fp->flag & IORW) fp->flag &= ~(IOREAD|IOWRT);
}
/* Позиционирование указателя чтения/записи */
#ifdef COMMENT
base ptr случай IOREAD
| |<----cnt---->|
0L |б у |ф е р |
|=======######@@@@@@@@@@@@@@======== файл file
| |<-p->|<-dl-->|
|<----pos---->| | |
|<----offset(new)-->| |
|<----RWptr---------------->|
где pos = RWptr - cnt; // указатель с поправкой
offset = pos + p = RWptr - cnt + p = lseek(file,0L,1) - cnt + p
отсюда: (для SEEK_SET)
p = offset+cnt-lseek(file,0L,1);
или (для SEEK_CUR) dl = RWptr - offset = p - cnt
lseek(file, dl, 1);
Условие, что указатель можно сдвинуть просто в буфере:
if( cnt > 0 && p <= cnt && base <= ptr + p ){
ptr += p; cnt -= p; }
#endif /*COMMENT*/
А. Богатырев, 1992-95 - 171 - Си в UNIX
int fseek(FILE *fp, long offset, int whence){
register resync, c; long p = (-1);
clearerr(fp);
if( fp->flag & (IOWRT|IORW)){
fflush(fp);
if(fp->flag & IORW){
fp->cnt = 0; fp->ptr = fp->base; fp->flag &= ~IOWRT;
}
p = lseek(fileno(fp), offset, whence);
} else if( fp->flag & IOREAD ){
if(whence < 2 && fp->base && !(fp->flag & IONBF)){
c = fp->cnt; p = offset;
if(whence == 0) /* SEEK_SET */
p += c - lseek(fileno(fp), 0L, 1);
else offset -= c;
if(!(fp->flag & IORW) &&
c > 0 && p <= c && p >= fp->base - fp->ptr
){ fp->ptr += (int) p; fp->cnt -= (int) p;
return 0; /* done */
}
resync = offset & 01;
} else resync = 0;
if(fp->flag & IORW){
fp->ptr = fp->base; fp->flag &= ~IOREAD; resync = 0;
}
p = lseek(fileno(fp), offset-resync, whence);
fp->cnt = 0; /* вынудить filbuf(); */
if(resync) getc(fp);
}
return (p== -1 ? -1 : 0);
}
/* Узнать текущую позицию указателя */
long ftell(FILE *fp){
long tres; register adjust;
if(fp->cnt < 0) fp->cnt = 0;
if(fp->flag & IOREAD) adjust = -(fp->cnt);
else if(fp->flag & (IOWRT|IORW)){ adjust = 0;
if(fp->flag & IOWRT &&
fp->base && !(fp->flag & IONBF)) /* буферизован */
adjust = fp->ptr - fp->base;
} else return (-1L);
if((tres = lseek(fileno(fp), 0L, 1)) < 0) return tres;
return (tres + adjust);
}
А. Богатырев, 1992-95 - 172 - Си в UNIX
5. Структуры данных.
Структуры ("записи") представляют собой агрегаты разнородных данных (полей раз-
ного типа); в отличие от массивов, где все элементы имеют один и тот же тип.
struct {
int x, y; /* два целых поля */
char s[10]; /* и одно - для строки */
} s1;
Структурный тип может иметь имя:
struct XYS {
int x, y; /* два целых поля */
char str[10]; /* и одно - для строки */
};
Здесь мы объявили тип, но не отвели ни одной переменной этого типа (хотя могли бы).
Теперь опишем переменную этого типа и указатель на нее:
struct XYS s2, *sptr = &s2;
Доступ к полям структуры производится по имени поля (а не по индексу, как у масси-
вов):
имя_структурной_переменной.имя_поля
указатель_на_структуру ->> имя_поля
то есть
не а
#define ВЕС 0 struct { int вес, рост; } x;
#define РОСТ 1 x.рост = 175;
int x[2]; x[РОСТ] = 175;
Например
s1.x = 13;
strcpy(s2.str, "Finish");
sptr->y = 27;
Структура может содержать структуры другого типа в качестве полей:
struct XYS_Z {
struct XYS xys;
int z;
} a1;
a1.xys.x = 71; a1.z = 12;
Структура того же самого типа не может содержаться в качестве поля - рекурсивные
определения запрещены. Зато нередко используются поля - ссылки на структуры такого
же типа (или другого). Это позволяет организовывать списки структур:
struct node {
int value;
struct node *next;
};
Очень часто используются массивы структур:
А. Богатырев, 1992-95 - 173 - Си в UNIX
struct XYS array[20]; int i = 5, j;
array[i].x = 12;
j = array[i].x;
Статические структуры можно описывать с инициализацией, перечисляя значения их полей
в {} через запятую:
extern struct node n2;
struct node n1 = { 1, &n2 },
n2 = { 2, &n1 },
n3 = { 3, NULL };
В этом примере n2 описано предварительно для того, чтобы &n2 в строке инициализации
n1 было определено.
Структуры одинакового типа можно присваивать целиком (что соответствует присваи-