C Object Oriented Programming Example
#include <stdio.h> | |
#include <stdlib.h> | |
#include <regex.h> | |
#include <stdbool.h> | |
#include <fnmatch.h> | |
#include <stddef.h> | |
#define container_of(ptr, type, member) \ | |
((type *)((char *)(ptr) - offsetof(type, member))) | |
/* Filter API */ | |
struct filter { | |
struct filter_vtable *vtable; | |
}; | |
struct filter_vtable { | |
bool (*match)(struct filter *, const char *); | |
void (*free)(struct filter *); | |
struct filter *(*clone)(struct filter *); | |
}; | |
bool filter_match(struct filter *filter, const char *string) | |
{ | |
return filter->vtable->match(filter, string); | |
} | |
void filter_free(struct filter *filter) | |
{ | |
return filter->vtable->free(filter); | |
} | |
struct filter *filter_clone(struct filter *filter) | |
{ | |
return filter->vtable->clone(filter); | |
} | |
/* Regex Filter */ | |
struct filter *filter_regex_create(const char *pattern); | |
struct filter_regex { | |
regex_t regex; | |
const char *pattern; | |
struct filter filter; | |
}; | |
static bool | |
method_match_regex(struct filter *f, const char *string) | |
{ | |
struct filter_regex *regex = container_of(f, struct filter_regex, filter); | |
return regexec(®ex->regex, string, 0, NULL, 0) == 0; | |
} | |
static void | |
method_free_regex(struct filter *f) | |
{ | |
struct filter_regex *regex = container_of(f, struct filter_regex, filter); | |
regfree(®ex->regex); | |
free(regex); | |
} | |
static struct filter * | |
method_clone_regex(struct filter *f) | |
{ | |
struct filter_regex *regex = container_of(f, struct filter_regex, filter); | |
return filter_regex_create(regex->pattern); | |
} | |
struct filter_vtable filter_regex_vtable = { | |
method_match_regex, method_free_regex, method_clone_regex | |
}; | |
struct filter *filter_regex_create(const char *pattern) | |
{ | |
struct filter_regex *regex = malloc(sizeof(*regex)); | |
regex->pattern = pattern; | |
regcomp(®ex->regex, pattern, REG_EXTENDED); | |
regex->filter.vtable = &filter_regex_vtable; | |
return ®ex->filter; | |
} | |
/* Glob Filter */ | |
struct filter *filter_glob_create(const char *pattern); | |
struct filter_glob { | |
const char *pattern; | |
struct filter filter; | |
}; | |
static bool | |
method_match_glob(struct filter *f, const char *string) | |
{ | |
struct filter_glob *glob = container_of(f, struct filter_glob, filter); | |
return fnmatch(glob->pattern, string, 0) == 0; | |
} | |
static void | |
method_free_glob(struct filter *f) | |
{ | |
struct filter_glob *glob = container_of(f, struct filter_glob, filter); | |
free(glob); | |
} | |
static struct filter * | |
method_clone_glob(struct filter *f) | |
{ | |
struct filter_glob *glob = container_of(f, struct filter_glob, filter); | |
return filter_glob_create(glob->pattern); | |
} | |
struct filter_vtable filter_glob_vtable = { | |
method_match_glob, method_free_glob, method_clone_glob | |
}; | |
struct filter *filter_glob_create(const char *pattern) | |
{ | |
struct filter_glob *glob = malloc(sizeof(*glob)); | |
glob->pattern = pattern; | |
glob->filter.vtable = &filter_glob_vtable; | |
return &glob->filter; | |
} | |
/* AND Filter */ | |
struct filter *filter_and(struct filter *a, struct filter *b); | |
struct filter_and { | |
struct filter *sub[2]; | |
struct filter filter; | |
}; | |
static bool | |
method_match_and (struct filter *f, const char *s) | |
{ | |
struct filter_and *and = container_of(f, struct filter_and, filter); | |
return filter_match(and->sub[0], s) && filter_match(and->sub[1], s); | |
} | |
static void | |
method_free_and(struct filter *f) | |
{ | |
struct filter_and *and = container_of(f, struct filter_and, filter); | |
filter_free(and->sub[0]); | |
filter_free(and->sub[1]); | |
free(and); | |
} | |
static struct filter * | |
method_clone_and(struct filter *f) | |
{ | |
struct filter_and *and = container_of(f, struct filter_and, filter); | |
return filter_and(filter_clone(and->sub[0]), filter_clone(and->sub[1])); | |
} | |
struct filter_vtable filter_and_vtable = { | |
method_match_and, method_free_and, method_clone_and | |
}; | |
struct filter *filter_and(struct filter *a, struct filter *b) | |
{ | |
struct filter_and *and = malloc(sizeof(*and)); | |
and->sub[0] = a; | |
and->sub[1] = b; | |
and->filter.vtable = &filter_and_vtable; | |
return &and->filter; | |
} | |
/* Constant Filters */ | |
static bool | |
method_match_any(struct filter *f, const char *string) | |
{ | |
return true; | |
} | |
static bool | |
method_match_none(struct filter *f, const char *string) | |
{ | |
return false; | |
} | |
static void | |
method_free_noop(struct filter *f) | |
{ | |
} | |
static struct | |
filter *method_clone_noop(struct filter *f) | |
{ | |
return f; | |
} | |
struct filter_vtable filter_any_vtable = { | |
method_match_any, method_free_noop, method_clone_noop | |
}; | |
struct filter_vtable filter_none_vtable = { | |
method_match_none, method_free_noop, method_clone_noop | |
}; | |
struct filter FILTER_ANY = { &filter_any_vtable }; | |
struct filter FILTER_NONE = { &filter_none_vtable }; | |
/* Test Program */ | |
void pass_match(FILE *input, FILE *output, struct filter *filter) | |
{ | |
char line[4096]; | |
while (fgets(line, sizeof(line), input)) | |
if (filter_match(filter, line)) | |
fputs(line, output); | |
} | |
int main(int argc, char **argv) | |
{ | |
struct filter *filter = &FILTER_ANY; | |
for (char **p = argv + 1; *p; p++) | |
filter = filter_and(filter, filter_glob_create(*p)); | |
pass_match(stdin, stdout, filter); | |
filter_free(filter); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
This comment has been minimized.
Fixed incorrect
free
s (need to free thestruct filter_foo
, not thestruct filter
).