diff --git a/src/filter.c b/src/filter.c index 8c6c6b0..827ffed 100644 --- a/src/filter.c +++ b/src/filter.c @@ -20,11 +20,84 @@ #if defined(HAVE_INTTYPES_H) # include #endif +#include +#include +#include #include +#include "toilet.h" #include "filter.h" -void filter_autocrop(cucul_canvas_t *cv) +static void filter_crop(cucul_canvas_t *); +static void filter_gay(cucul_canvas_t *); +static void filter_metal(cucul_canvas_t *); +static void filter_flip(cucul_canvas_t *); +static void filter_flop(cucul_canvas_t *); +static void filter_rotate(cucul_canvas_t *); + +struct +{ + char const *name; + void (*function)(cucul_canvas_t *); +} +const lookup[] = +{ + { "crop", filter_crop }, + { "gay", filter_gay }, + { "metal", filter_metal }, + { "flip", filter_flip }, + { "flop", filter_flop }, + { "rotate", filter_rotate }, +}; + +int filter_add(context_t *cx, char const *filter) +{ + unsigned int n; + int i; + + for(;;) + { + while(*filter == ':') + filter++; + + if(*filter == '\0') + break; + + for(i = sizeof(lookup) / sizeof(lookup[0]); i--; ) + if(!strncmp(filter, lookup[i].name, strlen(lookup[i].name))) + break; + + n = strlen(lookup[i].name); + + if(i == -1 || (filter[n] != ':' && filter[n] != '\0')) + { + fprintf(stderr, "unknown filter near `%s'\n", filter); + return -1; + } + + if((cx->nfilters % 16) == 0) + cx->filters = realloc(cx->filters, (cx->nfilters + 16) + * sizeof(lookup[0].function)); + cx->filters[cx->nfilters] = lookup[i].function; + cx->nfilters++; + + filter += n; + } + + return 0; +} + +int filter_do(context_t *cx) +{ + unsigned int i; + + for(i = 0; i < cx->nfilters; i++) + cx->filters[i](cx->cv); + + return 0; +} + +static void filter_crop(cucul_canvas_t *cv) { unsigned int x, y, w, h; unsigned int xmin, xmax, ymin, ymax; @@ -58,7 +131,7 @@ void filter_autocrop(cucul_canvas_t *cv) xmax - xmin + 1, ymax - ymin + 1); } -void filter_metal(cucul_canvas_t *cv) +static void filter_metal(cucul_canvas_t *cv) { static unsigned char const palette[] = { @@ -88,7 +161,7 @@ void filter_metal(cucul_canvas_t *cv) } } -void filter_gay(cucul_canvas_t *cv) +static void filter_gay(cucul_canvas_t *cv) { static unsigned char const rainbow[] = { @@ -117,3 +190,18 @@ void filter_gay(cucul_canvas_t *cv) } } +static void filter_flip(cucul_canvas_t *cv) +{ + cucul_flip(cv); +} + +static void filter_flop(cucul_canvas_t *cv) +{ + cucul_flop(cv); +} + +static void filter_rotate(cucul_canvas_t *cv) +{ + cucul_rotate(cv); +} + diff --git a/src/filter.h b/src/filter.h index b9071bd..86cc8fa 100644 --- a/src/filter.h +++ b/src/filter.h @@ -15,7 +15,6 @@ * This header defines post-processing filter functions. */ -extern void filter_autocrop(cucul_canvas_t *); -extern void filter_metal(cucul_canvas_t *); -extern void filter_gay(cucul_canvas_t *); +extern int filter_add(context_t *, char const *); +extern int filter_do(context_t *); diff --git a/src/io.c b/src/io.c index 6fd6692..2b7b0e3 100644 --- a/src/io.c +++ b/src/io.c @@ -45,7 +45,7 @@ struct toifile FILE *f; }; -TOIFILE *toiopen(const char *path, const char *mode) +TOIFILE *toiopen(char const *path, const char *mode) { TOIFILE *toif = malloc(sizeof(*toif)); diff --git a/src/main.c b/src/main.c index 3be335c..3e06646 100644 --- a/src/main.c +++ b/src/main.c @@ -50,8 +50,6 @@ int main(int argc, char *argv[]) int i, j, ret; - unsigned int flag_gay = 0; - unsigned int flag_metal = 0; int infocode = -1; cx->export = "utf8"; @@ -60,6 +58,9 @@ int main(int argc, char *argv[]) cx->term_width = 80; + cx->filters = NULL; + cx->nfilters = 0; + #if defined(HAVE_GETOPT_H) for(;;) { @@ -73,6 +74,7 @@ int main(int argc, char *argv[]) { "directory", 1, NULL, 'd' }, { "width", 1, NULL, 'w' }, { "termwidth", 0, NULL, 't' }, + { "filter", 1, NULL, 'F' }, { "gay", 0, NULL, 'g' }, { "metal", 0, NULL, 'm' }, { "irc", 0, NULL, 'i' }, @@ -82,11 +84,11 @@ int main(int argc, char *argv[]) { NULL, 0, NULL, 0 } }; - int c = getopt_long(argc, argv, "d:f:I:w:ghimtv", + int c = getopt_long(argc, argv, "f:d:w:tF:gmihI:v", long_options, &option_index); # else # define MOREINFO "Try `%s -h' for more information.\n" - int c = getopt(argc, argv, "d:f:I:w:ghimtv"); + int c = getopt(argc, argv, "f:d:w:tF:gmihI:v"); # endif if(c == -1) break; @@ -108,11 +110,15 @@ int main(int argc, char *argv[]) case 'd': /* --directory */ cx->dir = optarg; break; + case 'F': /* --filter */ + if(filter_add(cx, optarg)) + return -1; + break; case 'g': /* --gay */ - flag_gay = 1; + filter_add(cx, "gay"); break; case 'm': /* --metal */ - flag_metal = 1; + filter_add(cx, "metal"); break; case 'w': /* --width */ cx->term_width = atoi(optarg); @@ -220,12 +226,7 @@ int main(int argc, char *argv[]) cx->end(cx); /* Apply optional effects to our string */ - if(!strcasecmp(cx->font, "mono9")) - filter_autocrop(cx->cv); - if(flag_metal) - filter_metal(cx->cv); - if(flag_gay) - filter_gay(cx->cv); + filter_do(cx); /* Output char */ buffer = cucul_export_canvas(cx->cv, cx->export); @@ -240,7 +241,7 @@ int main(int argc, char *argv[]) #if defined(HAVE_GETOPT_H) # define USAGE \ - "Usage: toilet [ -ghimtv ] [ -d fontdirectory ]\n" \ + "Usage: toilet [ -ghimtvF ] [ -d fontdirectory ]\n" \ " [ -f fontfile ] [ -w outputwidth ]\n" \ " [ -I infocode ] [ message ]\n" #else @@ -274,6 +275,7 @@ static void usage(void) printf(" -d, --directory specify font directory\n"); printf(" -w, --width set output width\n"); printf(" -t, --termwidth adapt to terminal's width\n"); + printf(" -F, --filter apply one or several filters to the text\n"); printf(" -g, --gay add a rainbow effect to the text\n"); printf(" -m, --metal add a metal effect to the text\n"); printf(" -i, --irc output IRC colour codes\n"); @@ -285,6 +287,7 @@ static void usage(void) printf(" -d specify font directory\n"); printf(" -w set output width\n"); printf(" -t adapt to terminal's width\n"); + printf(" -F apply one or several filters to the text\n"); printf(" -g add a rainbow effect to the text\n"); printf(" -m add a metal effect to the text\n"); printf(" -i output IRC colour codes\n"); diff --git a/src/toilet.h b/src/toilet.h index db51061..6139c04 100644 --- a/src/toilet.h +++ b/src/toilet.h @@ -26,7 +26,7 @@ struct toilet_context cucul_canvas_t *cv; unsigned int w, h, ew, eh, x, y; - /* Methods */ + /* Render methods */ int (*feed)(struct toilet_context *, uint32_t); int (*end)(struct toilet_context *); @@ -43,6 +43,10 @@ struct toilet_context unsigned int glyphs; cucul_canvas_t *image; unsigned int *lookup; + + /* Render filters */ + void (**filters)(cucul_canvas_t *); + unsigned int nfilters; }; typedef struct toilet_context context_t;