/* _______________________ файл glob.h ___________________________*/
/* ПОДДЕРЖКА СПИСКА ИМЕН ФАЙЛОВ ЗАДАННОГО КАТАЛОГА */
/* ______________________________________________________________ */
#define FILF
#include <sys/types.h>
#include <sys/stat.h>
#include <dirent.h>
# define DIR_SIZE 14
extern char *malloc(unsigned); char *strdup(const char *str);
extern char *getenv();
extern char *strchr(char *, char), *strrchr(char *, char);
#define ISDIR(mode) ((mode & S_IFMT) == S_IFDIR)
#define ISDEV(mode) ((mode & S_IFMT) & (S_IFCHR|S_IFBLK))
#define ISREG(mode) ((mode & S_IFMT) == S_IFREG)
#define ISEXE(mode) ((mode & S_IFMT) == S_IFREG && (mode & 0111))
#define isdir(st) ISDIR(st.st_mode)
#define isdev(st) ISDEV(st.st_mode)
#define isreg(st) ISREG(st.st_mode)
#define isexe(st) ISEXE(st.st_mode)
#define YES 1
#define NO 0
#define I_DIR 0x01 /* это имя каталога */
#define I_EXE 0x02 /* это выполняемый файл */
#define I_NOSEL 0x04 /* строку нельзя выбрать */
#define I_SYS (I_DIR | I_EXE | I_NOSEL)
/* Скопировано из treemk.c
* Лучше просто написать #include "glob.h" в файле treemk.c
*/
#define FAILURE (-1) /* код неудачи */
#define SUCCESS 1 /* код успеха */
#define WARNING 0 /* нефатальная ошибка */
typedef struct _info { /* структура элемента каталога */
char *s; /* имя файла */
short fl; /* флаг */
union _any{
int (*act)(); /* возможно связанное действие */
char *note; /* или комментарий */
unsigned i; /* или еще какой-то параметр */
struct _info *inf;
} any; /* вспомогательное поле */
#ifdef FILF
/* дополнительные необязательные параметры, получаемые из stat(); */
long size;
int uid, gid;
unsigned short mode;
#endif
} Info;
typedef union _any Any;
extern Info NullInfo;
#define MAX_ARGV 256 /* Максимальное число имен в каталоге */
typedef struct { /* Содержимое каталога name */
time_t lastRead; /* время последнего чтения каталога */
Info *files; /* содержимое каталога */
char *name; /* имя каталога */
ino_t ino; dev_t dev; /* I-узел и устройство */
char valid; /* существует ли этот каталог вообще */
short readErrors; /* != 0, если каталог не читается */
} DirContents;
/* Виды сортировки имен в каталоге */
typedef enum { SORT_ASC, SORT_DESC, SORT_SUFX,
SORT_NOSORT, SORT_SIZE } Sort;
extern Sort sorttype; extern int in_the_root;
int gcmps (const void *p1, const void *p2);
Info *blkcpy(Info *v); void blkfree(Info *v);
Info *glob(char **patvec, char *dirname);
Info *glb(char *pattern, char *dirname);
int ReadDir(char *dirname, DirContents *d);
struct savech{ char *s, c; };
#define SAVE(sv, str) (sv).s = (str); (sv).c = *(str)
#define RESTORE(sv) if((sv).s) *(sv).s = (sv).c
/* _______________________ файл glob.c __________________________ */
#include "glob.h"
int in_the_root = NO; /* читаем корневой каталог ? */
Sort sorttype = SORT_SUFX; /* сортировка имен по суффиксу */
Info NullInfo = { NULL, 0 }; /* и прочие поля = 0 (если есть) */
char *strdup(const char *s){
char *p = malloc(strlen(s)+1); if(p)strcpy(p, s); return p; }
/* Содержится ли любой из символов в строке ? */
int any(register char *s, register char *p){
while( *s ){ if( strchr(p, *s)) return YES; s++; }
return NO;
}
/* Найти последнюю точку в имени */
static char *lastpoint (char *s)
{ register char *last; static char no[] = "";
if((last = strchr(s, '.')) == NULL) return no;
/* если имя начинается с точки - не считать ее */
return( last == s ? no : last );
}
/* Сравнение строк с учетом их суффиксов */
int strsfxcmp (register char *s1, register char *s2){
char *p1, *p2, c1, c2; int code;
p1 = lastpoint (s1); p2 = lastpoint (s2);
if (code = strcmp (p1, p2)) return code; /* суффиксы разные */
/* иначе: суффиксы равны. Сортируем по головам */
c1 = *p1; c2 = *p2; *p1 = '\0'; *p2 = '\0'; /* временно */
code = strcmp (s1, s2);
*p1 = c1; *p2 = c2; return code;
}
/* Функция сортировки */
int gcmps(const void *p1, const void *p2){
Info *s1 = (Info *) p1, *s2 = (Info *) p2;
switch( sorttype ){
default:
case SORT_ASC: return strcmp(s1->s, s2->s);
case SORT_DESC: return -strcmp(s1->s, s2->s);
case SORT_SUFX: return strsfxcmp(s1->s, s2->s);
case SORT_NOSORT: return (-1);
#ifdef FILF
case SORT_SIZE: return (s1->size < s2->size ? -1 :
s1->size == s2->size ? 0 : 1 );
#endif
}
}
/* Копирование блока */
Info *blkcpy(Info *v){
register i, len;
Info *vect = (Info *) malloc(((len=blklen(v)) + 1) * sizeof(Info));
for(i=0; i < len; i++ ) vect[i] = v[i];
vect[len] = NullInfo; return vect;
}
/* Измерение длины блока */
int blklen(Info *v){
int i = 0;
while( v->s ) i++, v++;
return i;
}
/* Очистка блока (уничтожение) */
void blkfree(Info *v){
Info *all = v;
while( v->s )
free((char *) v->s ), v++;
free((char *) all );
}
/* Сравнение двух блоков */
int blkcmp( register Info *p, register Info *q ){
while( p->s && q->s && !strcmp(p->s, q->s) &&
(p->fl & I_SYS) == (q->fl & I_SYS)){ p++; q++; }
if( p->s == NULL && q->s == NULL )
return 0; /* совпадают */
return 1; /* различаются */
}
char globchars [] = "*?[";
Info gargv[MAX_ARGV]; int gargc;
static short readErrors;
void greset() { gargc = 0; readErrors = 0; }
/* Расширить шаблон имен файлов в сами имена */
static void globone(char *pattern, char dirname[]){
extern char *strdup(); struct stat st;
DIR *dirf; struct dirent *d;
if( any(pattern, globchars) == NO ){ /* no glob */
gargv[gargc] = NullInfo;
gargv[gargc].s = strdup(pattern);
gargc++;
gargv[gargc] = NullInfo;
return;
}
if((dirf = opendir(dirname)) == NULL){ readErrors++; goto out; }
while(d = readdir(dirf)){
if(match(d->d_name, pattern)){
char fullname[512];
if( sorttype != SORT_NOSORT && !strcmp(d->d_name, "."))
continue;
/* В корневом каталоге имя ".." следует пропускать */
if( in_the_root && !strcmp(d->d_name, "..")) continue;
/* Проверка на переполнение */
if( gargc == MAX_ARGV - 1){
free(gargv[gargc-1].s);
gargv[gargc-1].s = strdup(" Слишком много файлов!!!");
gargv[gargc-1].fl = I_SYS;
break;
}
gargv[gargc] = NullInfo;
gargv[gargc].s = strdup(d->d_name);
sprintf(fullname, "%s/%s", dirname, d->d_name);
if(stat(fullname, &st) < 0) gargv[gargc].fl |= I_NOSEL;
else if(isdir(st)) gargv[gargc].fl |= I_DIR;
else if(isexe(st)) gargv[gargc].fl |= I_EXE;
#ifdef FILF
gargv[gargc].size = st.st_size;
gargv[gargc].uid = st.st_uid;
gargv[gargc].gid = st.st_gid;
gargv[gargc].mode = st.st_mode;
#endif
gargc++;
}
}
closedir(dirf);
out: gargv[ gargc ] = NullInfo;
}
/* Расширить несколько шаблонов */
Info *glob(char **patvec, char *dirname){
greset();
while(*patvec){ globone(*patvec, dirname); patvec++; }
qsort(gargv, gargc, sizeof(Info), gcmps);
return blkcpy(gargv);
}
Info *glb(char *pattern, char *dirname){ char *pv[2];
pv[0] = pattern; pv[1] = NULL; return glob(pv, dirname);
}
/* Прочесть содержимое каталога, если оно изменилось:
* Вернуть: 0 - каталог не менялся;
* 1 - изменился;
* 1000 - изменился рабочий каталог (chdir);
* -1 - каталог не существует;
*/
int ReadDir(char *dirname, DirContents *d){
struct stat st; Info *newFiles;
int save = YES; /* сохранять метки у файлов ? */
int dirchanged = NO; /* сделан chdir() ? */
/* каталог мог быть удален, а мы об этом не извещены */
if( stat(dirname, &st) < 0 ){
d->valid = NO; d->lastRead = 0L;
if(d->files) blkfree(d->files);
d->files = blkcpy( &NullInfo );
return (-1); /* не существует */
} else d->valid = YES;
/* не изменился ли адрес каталога, хранимого в *d ? */
if(d->ino != st.st_ino || d->dev != st.st_dev){ /* изменился */
d->ino = st.st_ino; d->dev = st.st_dev;
save = NO; d->lastRead = 0L; dirchanged = YES;
}
/* не изменилось ли имя каталога ? */
if( !d->name || strcmp(d->name, dirname)){
if(d->name) free(d->name); d->name = strdup(dirname);
/* save=NO; d->lastRead = 0; */
}
/* проверим, был ли модифицирован каталог ? */
if( save==YES && d->files && st.st_mtime == d->lastRead )
return 0; /* содержимое каталога не менялось */
d->lastRead = st.st_mtime;
newFiles = glb("*", d->name); /* прочесть содержимое каталога */
if(save == YES && d->files){
register Info *p, *q;
if( !blkcmp(newFiles, d->files)){
blkfree(newFiles); return 0; /* не изменилось */
} /* иначе сохранить пометки */
for(p= d->files; p->s; p++)
for(q= newFiles; q->s; ++q)
if( !strcmp(p->s, q->s)){
q->fl |= p->fl & ~I_SYS; break;
}
}
if(d->files) blkfree(d->files);
d->files = newFiles; d->readErrors = readErrors;
return 1 + (dirchanged ? 999:0);
/* каталог изменился */
}
© Copyright А. Богатырев, 1992-95
Си в UNIX
Назад | Содержание | Вперед