You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
239 lines
4.5 KiB
239 lines
4.5 KiB
#ifndef H_FILTER
|
|
#define H_FILTER
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <unistd.h>
|
|
#include <dirent.h>
|
|
#include <string.h>
|
|
#include <limits.h>
|
|
|
|
#define MIN(a, b) (a > b? b : a)
|
|
#define MAX(a, b) (a > b? a : b)
|
|
|
|
struct filter
|
|
{
|
|
struct {
|
|
char** ptr;
|
|
size_t len;
|
|
} tags;
|
|
|
|
struct {
|
|
struct {
|
|
char** ptr;
|
|
int* in;
|
|
size_t len;
|
|
} included;
|
|
struct {
|
|
char** ptr;
|
|
size_t len;
|
|
} excluded;
|
|
} files;
|
|
};
|
|
|
|
static inline int
|
|
filter_include_count(struct filter* filter)
|
|
{
|
|
int count = 0;
|
|
|
|
for (size_t i = 0; i < filter->tags.len; ++i) {
|
|
if (filter->tags.ptr[i][0] != '@')
|
|
count++;
|
|
}
|
|
|
|
return count;
|
|
}
|
|
|
|
static inline int
|
|
filter_exclude_count(struct filter* filter)
|
|
{
|
|
int count = 0;
|
|
|
|
for (size_t i = 0; i < filter->tags.len; ++i) {
|
|
if (filter->tags.ptr[i][0] == '@')
|
|
count++;
|
|
}
|
|
|
|
return count;
|
|
}
|
|
|
|
static inline void
|
|
filter_free(struct filter* filter)
|
|
{
|
|
if (filter->tags.ptr) {
|
|
for (size_t i = 0; i < filter->tags.len; ++i) {
|
|
free(filter->tags.ptr[i]);
|
|
}
|
|
free(filter->tags.ptr);
|
|
}
|
|
|
|
if (filter->files.included.ptr) {
|
|
for (size_t i = 0; i < filter->files.included.len; ++i) {
|
|
free(filter->files.included.ptr[i]);
|
|
}
|
|
free(filter->files.included.ptr);
|
|
free(filter->files.included.in);
|
|
}
|
|
|
|
if (filter->files.excluded.ptr) {
|
|
for (size_t i = 0; i < filter->files.excluded.len; ++i) {
|
|
free(filter->files.excluded.ptr[i]);
|
|
}
|
|
free(filter->files.excluded.ptr);
|
|
}
|
|
}
|
|
|
|
static inline int
|
|
load_filter_files(struct filter* filter, struct dirinfo* tagdir)
|
|
{
|
|
memset(&filter->files, 0, sizeof filter->files);
|
|
|
|
for (size_t i = 0; i < filter->tags.len; ++i) {
|
|
const char* tag = filter->tags.ptr[i];
|
|
|
|
int excluded = (*tag == '@');
|
|
int fd = openat(tagdir->fd, tag + (excluded? 1 : 0), O_DIRECTORY|O_RDONLY);
|
|
|
|
if (fd == -1)
|
|
return 0;
|
|
|
|
DIR* dp = fdopendir(fd);
|
|
struct dirent* ent;
|
|
while ((ent = readdir(dp))) {
|
|
if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0)
|
|
continue;
|
|
|
|
char name[PATH_MAX];
|
|
if (readlinkat(fd, ent->d_name, name, sizeof name) == -1) {
|
|
closedir(dp);
|
|
close(fd);
|
|
return 0;
|
|
}
|
|
|
|
const char* p = strrchr(name, '/') + 1;
|
|
|
|
if (excluded) {
|
|
size_t size = ++filter->files.excluded.len * sizeof *filter->files.excluded.ptr;
|
|
void* ptr = realloc(filter->files.excluded.ptr, size);
|
|
|
|
if (ptr == NULL) {
|
|
closedir(dp);
|
|
close(fd);
|
|
return 0;
|
|
}
|
|
|
|
filter->files.excluded.ptr = ptr;
|
|
|
|
char** str = &filter->files.excluded.ptr[filter->files.excluded.len - 1];
|
|
size = MIN(strlen(p), NAME_MAX);
|
|
*str = malloc(size + 1);
|
|
|
|
if (*str == NULL) {
|
|
closedir(dp);
|
|
close(fd);
|
|
return 0;
|
|
}
|
|
|
|
strncpy(*str, p, size);
|
|
(*str)[size] = '\0';
|
|
}
|
|
else {
|
|
int skip = 0;
|
|
|
|
for (size_t j = 0; j < filter->files.included.len; ++j) {
|
|
if (strcmp(filter->files.included.ptr[j], p) == 0) {
|
|
skip = 1;
|
|
filter->files.included.in[j] += 1;
|
|
}
|
|
}
|
|
|
|
if (skip)
|
|
continue;
|
|
|
|
size_t size = ++filter->files.included.len * sizeof *filter->files.included.ptr;
|
|
void* ptr = realloc(filter->files.included.ptr, size);
|
|
|
|
if (ptr == NULL) {
|
|
closedir(dp);
|
|
close(fd);
|
|
return 0;
|
|
}
|
|
|
|
filter->files.included.ptr = ptr;
|
|
|
|
size = filter->files.included.len * sizeof *filter->files.included.in;
|
|
ptr = realloc(filter->files.included.in, size);
|
|
|
|
if (ptr == NULL) {
|
|
closedir(dp);
|
|
close(fd);
|
|
return 0;
|
|
}
|
|
|
|
filter->files.included.in = ptr;
|
|
filter->files.included.in[filter->files.included.len - 1] = 1;
|
|
|
|
char** str = &filter->files.included.ptr[filter->files.included.len - 1];
|
|
size = MIN(strlen(p), NAME_MAX);
|
|
*str = malloc(size + 1);
|
|
|
|
if (*str == NULL) {
|
|
closedir(dp);
|
|
close(fd);
|
|
return 0;
|
|
}
|
|
|
|
strncpy(*str, p, size);
|
|
(*str)[size] = '\0';
|
|
}
|
|
}
|
|
|
|
closedir(dp);
|
|
close(fd);
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
static inline int
|
|
load_filter_tags(int fd, struct filter* filter)
|
|
{
|
|
FILE* fp = fdopen(fd, "r");
|
|
char tag[TAG_MAX + 1];
|
|
|
|
memset(&filter->tags, 0, sizeof filter->tags);
|
|
|
|
while (fgets(tag, sizeof tag, fp)) {
|
|
size_t size = ++filter->tags.len * sizeof *filter->tags.ptr;
|
|
void* ptr = realloc(filter->tags.ptr, size);
|
|
|
|
if (ptr == NULL) {
|
|
fclose(fp);
|
|
return 0;
|
|
}
|
|
|
|
filter->tags.ptr = ptr;
|
|
|
|
char** str = &filter->tags.ptr[filter->tags.len - 1];
|
|
size = MIN(strlen(tag), TAG_MAX);
|
|
*str = malloc(size + 1);
|
|
|
|
if (*str == NULL) {
|
|
fclose(fp);
|
|
return 0;
|
|
}
|
|
|
|
if (tag[size - 1] == '\n')
|
|
tag[size - 1] = '\0';
|
|
|
|
strncpy(*str, tag, size);
|
|
(*str)[size] = '\0';
|
|
}
|
|
|
|
fclose(fp);
|
|
return 1;
|
|
}
|
|
|
|
#endif
|
|
|