Хрестоматия по программированию на Си в Unix
int MEMcheck_consistency(AllocFrame *ptr){
MemFileRecord mr_found;
int nrecords, i, found = 0;
size_t size;
MEMopenFd();
/* Ищем запись в таблице указателей */
lseek(mem_fd, 0L, SEEK_SET); /* перемотать в начало */
for(;;){
size = read(mem_fd, memrecords, sizeof memrecords);
nrecords = size / sizeof(memrecords[0]);
if(nrecords <= 0) break;
for(i=0; i < nrecords; i++)
if(memrecords[i].ptr == ptr){
/* Мы ищем последнюю запись про память
* с таким адресом, поэтому
* вынуждены прочитать ВЕСЬ файл.
*/
mr_found = memrecords[i];
found++;
}
}
if(found) {
return MEMcheckRecord(&mr_found);
} else {
printf("%p -- запись в таблице отсутствует.\n", ptr);
return NOTHERE;
}
}
/* Уничтожить все прежние записи про ptr, прописывая их adjsize=0 */
void MEMerasePreviousRecords(AllocFrame *ptr){
int nrecords, i, found;
size_t size;
MEMopenFd();
lseek(mem_fd, 0L, SEEK_SET); /* перемотать в начало */
for(;;){
found = 0;
size = read(mem_fd, memrecords, sizeof memrecords);
nrecords = size / sizeof(memrecords[0]);
if(nrecords <= 0) break;
for(i=0; i < nrecords; i++)
if(memrecords[i].ptr == ptr){
memrecords[i].adjsize = 0;
/* memrecords[i].size = 0; */
found++;
}
if(found){
lseek(mem_fd, -size, SEEK_CUR); /* шаг назад */
write(mem_fd, memrecords, size); /* перезаписать */
}
}
}
void MEMcheckAll(){
#ifdef CHECKALL
int nrecords, i;
size_t size;
printf("Проверка всех указателей -------------\n");
MEMopenFd();
lseek(mem_fd, 0L, SEEK_SET); /* перемотать в начало */
for(;;){
size = read(mem_fd, memrecords, sizeof memrecords);
nrecords = size / sizeof(memrecords[0]);
if(nrecords <= 0) break;
for(i=0; i < nrecords; i++)
if(memrecords[i].adjsize != 0)
MEMcheckRecord(&memrecords[i]);
}
printf("Проверка всех указателей завершена ---\n");
#endif
}
/* ============================================================= */
/* Заполнение пограничных зон образцом - "следовой дорожкой" */
void MEMmakeRedZones(char *cptr, size_t size, size_t adjsize){
register i;
for(i=0; i < adjsize; i++){
if(i < RedZoneTypeSize || i >= RedZoneTypeSize + size ){
/* головная погранзона ИЛИ
* хвостовая погранзона + дополнение
* до целого числа RedZoneType-ов
*/
cptr[i] = red_table[ i % RedZoneTypeSize ];
}
}
}
/* ============================================================= */
/* Функция выделения памяти */
void *MEMmalloc(size_t size){
AllocFrame *retptr;
int fullRedZoneTypes =
(size + RedZoneTypeSize - 1) / RedZoneTypeSize;
size_t adjustedSize =
sizeof(retptr->red_zone) * 2 + /* две погранзоны */
fullRedZoneTypes * RedZoneTypeSize;
retptr = (AllocFrame *) malloc(adjustedSize);
if(retptr == NULL) return NULL;
MEMmakeRedZones ((char *) retptr, size, adjustedSize);
MEMputTableRecord(retptr, retptr, size, adjustedSize);
return &retptr->stuff[0];
/* вернуть указатель на зону данных */
}
void *MEMrealloc(void *ptr, size_t size){
AllocFrame *retptr;
char *cptr = (char *)ptr - RedZoneTypeSize; /* прежний AllocFrame */
AllocFrame *oldptr = (AllocFrame *) cptr;
int fullRedZoneTypes =
(size + RedZoneTypeSize - 1) / RedZoneTypeSize;
size_t adjustedSize =
sizeof(retptr->red_zone) * 2 +
fullRedZoneTypes * RedZoneTypeSize;
/* Проверить сохранность того, что мы сейчас будем realloc-ить */
MEMcheck_consistency(oldptr);
retptr = (AllocFrame *) realloc((void *)oldptr, adjustedSize);
if(retptr == NULL) return NULL;
MEMmakeRedZones ((char *) retptr, size, adjustedSize);
MEMputTableRecord(retptr, oldptr, size, adjustedSize);
return &retptr->stuff[0];
}
void *MEMcalloc(size_t n, size_t size){
size_t newsize = n * size;
void *ptr = MEMmalloc(newsize);
memset(ptr, '\0', newsize);
return ptr;
}
/* Очистка отведенной памяти.
* ptr - это указатель не на AllocFrame,
* а на данные - то есть на stuff[0].
*/
void MEMfree(void *ptr){
char *cptr = (char *)ptr - RedZoneTypeSize;
int i, code;
code = MEMcheck_consistency((AllocFrame *) cptr);
for(i=0; i < RedZoneTypeSize; i++)
cptr[i] = free_table[i];
if(code != FREED) free((void *) cptr);
MEMputTableRecordKilled((AllocFrame *) cptr);
}
/* ============================================================= */
/* Тестовый пример */
/* ============================================================= */
#define MAXPTRS 512
char *testtable[MAXPTRS];
/* Сгенерировать строку случайной длины со случайным содержимым */
char *wildstring(int c){
#define N 1024
char teststring[N + 1];
int len, i;
char *ptr;
len = rand() % N;
for(i=0; i < len; i++)
teststring[i] = c;
teststring[len] = '\0';
ptr = (char *) MEMmalloc(len + 1);
if(ptr){
strcpy(ptr, teststring);
} else printf("NULL wildstring()\n");
return ptr;
}
int main(int ac, char *av[]){
int ilen, len, n, i;
srand(time(NULL));
for(n=0; n < MAXPTRS; n++)
testtable[n] = wildstring('A');
#define DAMAGE (MAXPTRS/3*2-1)
#ifdef DAMAGE
/* Навести порчу */
len = strlen(testtable[DAMAGE]);
testtable[DAMAGE][len+1] = 'x';
testtable[DAMAGE][-2] = 'y';
printf("ptr=%p len=%d\n", testtable[DAMAGE], len);
#endif
for(n=0; n < MAXPTRS/2; n++){
char *p = wildstring('B');
int length = strlen(p);
char *ptr;
i = rand() % MAXPTRS;
/* Не забыть присвоить возвращенное realloc() значение
* обратно в testtable[i] !!!
*/
testtable[i] = ptr =
(char *) MEMrealloc(testtable[i], length + 1);
if(ptr == NULL) printf("Не могу сделать realloc()\n");
else strcpy(ptr, p);
#ifdef DAMAGE
/* Порча */
if(n == MAXPTRS/3){
ptr[length+2] = 'z';
}
#endif
MEMfree(p);
}
for(n=0; n < MAXPTRS; n++){
if(testtable[n]) MEMfree(testtable[n]);
}
#ifdef DAMAGE
MEMfree(testtable[DAMAGE]);
#endif
return 0;
}
/* Пример 12 */
/* Программа, совмещающая команды mv и cp. Иллюстрация работы с файлами.
* Пример того, как программа может выбирать род работы
* по своему названию.
* Компиляция:
* cc cpmv.c -o copy ; ln copy move
* По мотивам книги М.Дансмура и Г.Дейвиса.
*/
#include /* буферизованный ввод/вывод */
#include /* системные типы данных */
#include /* struct stat */
#include /* O_RDONLY */
#include /* системные коды ошибок */
/* #define strrchr rindex /* для версии ДЕМОС (BSD) */
extern char *strrchr(char *, char); /* из библиотеки libc.a */
extern int errno;
char MV[] = "move"; char CP[] = "copy";
#define OK 1 /* success - успех */
#define FAILED 0 /* failure - неудача */
#define YES OK
#define NO 0
/* Выделить базовое имя файла:
* ../wawa/xxx --> xxx
* zzz --> zzz
* / --> /
*/
char *basename( char *name ){
char *s = strrchr( name , '/' );
return (s == NULL) ? name : /* нет слэшей */
(s[1] == '\0') ? name : /* корневой каталог */
s + 1;
}
#define ECANTSTAT (-1) /* файл не существует */
struct ftype {
unsigned type; /* тип файла */
dev_t dev; /* код устройства, содержащего файл */
ino_t ino; /* индексный узел файла на этом устройстве */
};
/* Получение типа файла */
struct ftype filetype( char *name /* имя файла */ )
{
struct stat st; struct ftype f;
if( stat( name, &st ) < 0 ){
f.type = ECANTSTAT; f.dev = f.ino = 0;
} else { f.type = st.st_mode & S_IFMT;
f.dev = st.st_dev; f.ino = st.st_ino;
}
return f;
}
/* Удаляет файлы, кроме устройств */
int unlinkd( char *name, unsigned type )
{
if( type == S_IFBLK || type == S_IFCHR || type == S_IFDIR)
return 0;
return unlink( name );
}
/* Функция нижнего уровня: копирование информации большими порциями */
int copyfile( int from, int to )
/* from - дескриптор откуда */
/* to - дескриптор куда */
{
char buffer[ BUFSIZ ];
int n; /* число прочитанных байт */
while(( n = read( from, buffer, BUFSIZ )) > 0 )
/* read возвращает число прочитанных байт,
* 0 в конце файла
*/
if( write( to, buffer, n ) != n ){
printf( "Write error.\n" );
return FAILED;
}
return OK;
}
/* Копирование файла */
int docopy(char *src, char *dst, unsigned typefrom, unsigned typeto)
{ int retc; int fdin, fdout;
printf( "copy %s --> %s\n", src, dst );
if((fdin = open( src, O_RDONLY )) < 0 ){
printf( "Сan't read %s\n", src );
return FAILED;
}
if((fdout = creat( dst, 0644 )) < 0 ){ /* rw-r--r-- */
printf( "Can't create %s\n", dst );
return FAILED;
}
retc = copyfile( fdin, fdout );
close( fdin ); close( fdout );
return retc;
}
/* Переименование файла. Вернуть OK, если удачно, FAILED - неудачно */
int mlink(char *src, char *dst, unsigned typefrom, unsigned typeto)
{
switch( typefrom ){
case S_IFDIR: /* переименование каталога */
printf( "rename directory %s --> %s\n", src, dst );
if( access( dst, 0 ) == 0 ){
/* 0 - проверить существование файла */
printf( "%s exists already\n", dst );
/* файл уже существует */
return FAILED;
}
if( link( src, dst ) < 0 ){
printf( "Can't link to directory %s\n", dst );
perror( "link" );
/* Возможно, что для выполнения link() для каталогов,