From bb02608645ae4c0faff9ccd609d3fccb14850d26 Mon Sep 17 00:00:00 2001 From: Sam Hocevar Date: Mon, 8 Feb 2010 23:56:33 +0000 Subject: [PATCH] Add mygetopt.c to the project. Fixes #42. --- configure.ac | 9 +++- src/Makefile.am | 14 ++++-- src/main.c | 78 +++++++++++-------------------- src/mygetopt.c | 120 ++++++++++++++++++++++++++++++++++++++++++++++++ src/mygetopt.h | 29 ++++++++++++ 5 files changed, 192 insertions(+), 58 deletions(-) create mode 100644 src/mygetopt.c create mode 100644 src/mygetopt.h diff --git a/configure.ac b/configure.ac index 38035aa..b419599 100644 --- a/configure.ac +++ b/configure.ac @@ -27,11 +27,16 @@ fi AC_CHECK_HEADERS(getopt.h sys/ioctl.h zlib.h) +ac_cv_have_getopt_long="no" AC_CHECK_FUNCS(getopt_long, - [AC_DEFINE(HAVE_GETOPT_LONG, 1, Define to 1 if you have the `getopt_long' function.)], + [ac_cv_have_getopt_long="yes"], [AC_CHECK_LIB(gnugetopt, getopt_long, - [AC_DEFINE(HAVE_GETOPT_LONG, 1, Define to 1 if you have the `getopt_long' function.) + [ac_cv_have_getopt_long="yes" GETOPT_LIBS="${GETOPT_LIBS} -lgnugetopt"])]) +if test "$ac_cv_have_getopt_long" != "no"; then + AC_DEFINE(HAVE_GETOPT_LONG, 1, Define to 1 if you have the ‘getopt_long’ function.) +fi +AM_CONDITIONAL(NEED_GETOPT_LONG, test "$ac_cv_have_getopt_long" = "no") AC_SUBST(GETOPT_LIBS) AC_CHECK_LIB(z, gzopen, diff --git a/src/Makefile.am b/src/Makefile.am index ed154c2..8e121a1 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -2,13 +2,19 @@ bin_PROGRAMS = toilet toilet_SOURCES = main.c toilet.h \ - render.c render.h \ - filter.c filter.h \ - export.c export.h \ - term.c figlet.c + render.c render.h \ + filter.c filter.h \ + export.c export.h \ + term.c figlet.c \ + $(GETOPT) + toilet_CPPFLAGS = -DFONTDIR=\"$(datadir)/figlet\" toilet_CFLAGS = @CACA_CFLAGS@ toilet_LDADD = @CACA_LIBS@ @GETOPT_LIBS@ @ZLIB_LIBS@ +if NEED_GETOPT_LONG +GETOPT = mygetopt.c mygetopt.h +endif + echo-sources: ; echo $(SOURCES) diff --git a/src/main.c b/src/main.c index e5c11b9..8a89de5 100644 --- a/src/main.c +++ b/src/main.c @@ -21,7 +21,9 @@ #if defined HAVE_INTTYPES_H # include #endif -#if defined HAVE_GETOPT_H +#if !defined HAVE_GETOPT_LONG +# include "mygetopt.h" +#elif defined HAVE_GETOPT_H # include #endif #if defined HAVE_SYS_IOCTL_H && defined HAVE_TIOCGWINSZ @@ -37,10 +39,15 @@ #include "filter.h" #include "export.h" +#if defined HAVE_GETOPT_LONG +# define mygetopt getopt_long +# define myoptind optind +# define myoptarg optarg +# define myoption option +#endif + static void version(void); -#if defined HAVE_GETOPT_H static void usage(void); -#endif int main(int argc, char *argv[]) { @@ -60,13 +67,11 @@ int main(int argc, char *argv[]) cx->filters = NULL; cx->nfilters = 0; -#if defined HAVE_GETOPT_H for(;;) { -# ifdef HAVE_GETOPT_LONG -# define MOREINFO "Try `%s --help' for more information.\n" +#define MOREINFO "Try `%s --help' for more information.\n" int option_index = 0; - static struct option long_options[] = + static struct myoption long_options[] = { /* Long option, needs arg, flag, short option */ { "font", 1, NULL, 'f' }, @@ -85,12 +90,8 @@ int main(int argc, char *argv[]) { NULL, 0, NULL, 0 } }; - int c = getopt_long(argc, argv, "f:d:w:tsSkWoF:E:hI:v", - long_options, &option_index); -# else -# define MOREINFO "Try `%s -h' for more information.\n" - int c = getopt(argc, argv, "f:d:w:tsSkWoF:E:hI:v"); -# endif + int c = mygetopt(argc, argv, "f:d:w:tsSkWoF:E:hI:v", + long_options, &option_index); if(c == -1) break; @@ -100,21 +101,21 @@ int main(int argc, char *argv[]) usage(); return 0; case 'I': /* --infocode */ - infocode = atoi(optarg); + infocode = atoi(myoptarg); break; case 'v': /* --version */ version(); return 0; case 'f': /* --font */ - cx->font = optarg; + cx->font = myoptarg; break; case 'd': /* --directory */ - cx->dir = optarg; + cx->dir = myoptarg; break; case 'F': /* --filter */ - if(!strcmp(optarg, "list")) + if(!strcmp(myoptarg, "list")) return filter_list(); - if(filter_add(cx, optarg) < 0) + if(filter_add(cx, myoptarg) < 0) return -1; break; case 130: /* --gay */ @@ -124,7 +125,7 @@ int main(int argc, char *argv[]) filter_add(cx, "metal"); break; case 'w': /* --width */ - cx->term_width = atoi(optarg); + cx->term_width = atoi(myoptarg); break; case 't': /* --termwidth */ { @@ -154,9 +155,9 @@ int main(int argc, char *argv[]) cx->hmode = H_OVERLAP; break; case 'E': /* --export */ - if(!strcmp(optarg, "list")) + if(!strcmp(myoptarg, "list")) return export_list(); - if(export_set(cx, optarg) < 0) + if(export_set(cx, myoptarg) < 0) return -1; break; case 140: /* --irc */ @@ -174,10 +175,6 @@ int main(int argc, char *argv[]) return 1; } } -#else -# define MOREINFO "Usage: %s message...\n" - int optind = 1; -#endif switch(infocode) { @@ -205,10 +202,10 @@ int main(int argc, char *argv[]) if(render_init(cx) < 0) return -1; - if(optind >= argc) + if(myoptind >= argc) render_stdin(cx); else - render_list(cx, argc - optind, argv + optind); + render_list(cx, argc - myoptind, argv + myoptind); render_end(cx); filter_end(cx); @@ -216,17 +213,12 @@ int main(int argc, char *argv[]) return 0; } -#if defined HAVE_GETOPT_H -# define USAGE \ +#define USAGE \ "Usage: toilet [ -hkostvSW ] [ -d fontdirectory ]\n" \ " [ -f fontfile ] [ -F filter ] [ -w outputwidth ]\n" \ " [ -I infocode ] [ -E format ] [ message ]\n" -#else -# define USAGE "" -#endif -#if defined HAVE_GETOPT_LONG -# define HELP \ +#define HELP \ " -f, --font select the font\n" \ " -d, --directory specify font directory\n" \ " -s, -S, -k, -W, -o render mode (default, force smushing,\n" \ @@ -244,22 +236,6 @@ int main(int argc, char *argv[]) " -h, --help display this help and exit\n" \ " -I, --infocode print FIGlet-compatible infocode\n" \ " -v, --version output version information and exit\n" -#else -# define HELP \ - " -f select the font\n" \ - " -d specify font directory\n" \ - " -s, -S, -k, -W, -o render mode (default, force smushing,\n" \ - " kerning, full width, overlap)\n" \ - " -w set output width\n" \ - " -t adapt to terminal's width\n" \ - " -F apply one or several filters to the text\n" \ - " -F list list available filters\n" \ - " -E select export format\n" \ - " -E list list available export formats\n" \ - " -h display this help and exit\n" \ - " -I print FIGlet-compatible infocode\n" \ - " -v output version information and exit\n" -#endif static void version(void) { @@ -278,10 +254,8 @@ static void version(void) "%s", VERSION, DATE, USAGE); } -#if defined HAVE_GETOPT_H static void usage(void) { printf("%s%s", HELP, USAGE); } -#endif diff --git a/src/mygetopt.c b/src/mygetopt.c new file mode 100644 index 0000000..423739d --- /dev/null +++ b/src/mygetopt.c @@ -0,0 +1,120 @@ +/* + * TOIlet The Other Implementation’s letters + * Copyright (c) 2002-2010 Sam Hocevar + * All Rights Reserved + * + * This program is free software. It comes without any warranty, to + * the extent permitted by applicable law. You can redistribute it + * and/or modify it under the terms of the Do What The Fuck You Want + * To Public License, Version 2, as published by Sam Hocevar. See + * http://sam.zoy.org/wtfpl/COPYING for more details. + */ + +/* + * mygetopt.c: getopt_long reimplementation + */ + +#include "config.h" + +#if defined HAVE_STDINT_H +# include +#elif defined HAVE_INTTYPES_H +# include +#endif + +#include +#include + +#include "mygetopt.h" + +int myoptind = 1; +char *myoptarg = NULL; + +/* XXX: this getopt_long implementation should not be trusted for other + * applications without any serious peer reviewing. It “just works” with + * zzuf but may fail miserably in other programs. */ +int mygetopt(int argc, char * const _argv[], const char *optstring, + const struct myoption *longopts, int *longindex) +{ + char **argv = (char **)(uintptr_t)_argv; + char *flag; + int i; + + if(myoptind >= argc) + return -1; + + flag = argv[myoptind]; + + if(flag[0] == '-' && flag[1] != '-') + { + char *tmp; + int ret = flag[1]; + + if(ret == '\0') + return -1; + + tmp = strchr(optstring, ret); + if(!tmp || ret == ':') + return '?'; + + myoptind++; + if(tmp[1] == ':') + { + if(flag[2] != '\0') + myoptarg = flag + 2; + else + myoptarg = argv[myoptind++]; + return ret; + } + + if(flag[2] != '\0') + { + flag[1] = '-'; + myoptind--; + argv[myoptind]++; + } + + return ret; + } + + if(flag[0] == '-' && flag[1] == '-') + { + if(flag[2] == '\0') + return -1; + + for(i = 0; longopts[i].name; i++) + { + size_t l = strlen(longopts[i].name); + + if(strncmp(flag + 2, longopts[i].name, l)) + continue; + + switch(flag[2 + l]) + { + case '=': + if(!longopts[i].has_arg) + goto bad_opt; + if(longindex) + *longindex = i; + myoptind++; + myoptarg = flag + 2 + l + 1; + return longopts[i].val; + case '\0': + if(longindex) + *longindex = i; + myoptind++; + if(longopts[i].has_arg) + myoptarg = argv[myoptind++]; + return longopts[i].val; + default: + break; + } + } + bad_opt: + fprintf(stderr, "%s: unrecognized option `%s'\n", argv[0], flag); + return '?'; + } + + return -1; +} + diff --git a/src/mygetopt.h b/src/mygetopt.h new file mode 100644 index 0000000..254b72f --- /dev/null +++ b/src/mygetopt.h @@ -0,0 +1,29 @@ +/* + * TOIlet The Other Implementation’s letters + * Copyright (c) 2002-2010 Sam Hocevar + * All Rights Reserved + * + * This program is free software. It comes without any warranty, to + * the extent permitted by applicable law. You can redistribute it + * and/or modify it under the terms of the Do What The Fuck You Want + * To Public License, Version 2, as published by Sam Hocevar. See + * http://sam.zoy.org/wtfpl/COPYING for more details. + */ + +/* + * mygetopt.h: getopt_long reimplementation + */ + +struct myoption +{ + const char *name; + int has_arg; + int *flag; + int val; +}; + +extern int myoptind; +extern char *myoptarg; + +int mygetopt(int, char * const[], const char *, const struct myoption *, int *); +