-
-
Save louisswarren/c470954bc67e5481b9b3ab05d87de857 to your computer and use it in GitHub Desktop.
C Object Oriented Programming Example
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
CFLAGS = -std=c99 -Wall | |
main : main.o | |
.PHONY : test clean | |
test : main | |
./$^ "*regex*" "*vtable*" < main.c | |
clean : | |
$(RM) main *.o |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Fixed incorrect
free
s (need to free thestruct filter_foo
, not thestruct filter
).