From d9c5b54e4f48d8e00ddba4d5b487b7557fe2a9f5 Mon Sep 17 00:00:00 2001 From: Mattias Andrée Date: Sun, 3 Jan 2016 10:22:16 +0100 Subject: add support for +options to remove effect of -option MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Mattias Andrée --- README | 7 ++++ src/arg.h | 114 +++++++++++++++++++++++++++++++++++++++------------------ src/radharc.c | 7 ++++ src/settings.c | 32 ++++++++-------- 4 files changed, 108 insertions(+), 52 deletions(-) diff --git a/README b/README index 7dad85e..4260b90 100644 --- a/README +++ b/README @@ -103,6 +103,13 @@ OPTIONS a screen or graphic card. The later is for when not inside a graphics environment. + All options also have a '+' variant, for example '+n'. + These undo the affect of previous '-' variant. + '+d', '+e', and '+m' all undo the affect of all previous + '-d', '-e', and '-m' options (not respectively). + Additionally, with the exception of '-d', '-e', '-m', + subsequent options override the previous of the the option. + SIGNALS SIGHUP Perform an online update to a newer version. diff --git a/src/arg.h b/src/arg.h index 8d235ba..3fe5145 100644 --- a/src/arg.h +++ b/src/arg.h @@ -1,41 +1,83 @@ -/* - * Copy me if you can. - * by 20h +/** + * Copyright © 2016 Mattias Andrée + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. */ -#ifndef ARG_H__ -#define ARG_H__ + +/** + * The name of the process. + */ extern char *argv0; -/* use main(int argc, char *argv[]) */ -#define ARGBEGIN for (argv0 = *argv, argv++, argc--;\ - argv[0] && argv[0][1]\ - && argv[0][0] == '-';\ - argc--, argv++) {\ - char argc_;\ - char **argv_;\ - int brk_;\ - if (argv[0][1] == '-' && argv[0][2] == '\0') {\ - argv++;\ - argc--;\ - break;\ - }\ - for (brk_ = 0, argv[0]++, argv_ = argv;\ - argv[0][0] && !brk_;\ - argv[0]++) {\ - if (argv_ != argv)\ - break;\ - argc_ = argv[0][0];\ - switch (argc_) - -#define ARGEND }\ - } - -#define ARGF() ((argv[0][1] == '\0' && argv[1] == NULL)?\ - (char *)0 :\ - (brk_ = 1, (argv[0][1] != '\0')?\ - (&argv[0][1]) :\ - (argc--, argv++, argv[0]))) - -#endif + + +/** + * Start command line parsing. + * + * `argv` and `argc` must be available as given to `main`. + * The global variable `argv0` must be declare (not necessary + * the the same file) and will be set to `argv[0]`. + * + * Only short options and "--" are supported. Short options + * may start with a '+', in which case `plus` will be 1. + * + * @example + * ARGBEGIN { + * case 'a': printf("%s\n", plus ? "+a" : "-a"); break; + * case 'b': if (plus) usage(1); printf("-b\n"); break; + * case 'c': if (plus) printf("+c\n"); else printf("-c %s\n", ARGF()); break; + * default: usage(1); break; + * } ARGEND; + */ +#define ARGBEGIN \ +do { \ + for (argv0 = *argv++, argc -= !!argv0; *argv; argv++, argc--) { \ + int plus = argv[0][0] == '+', next__ = 0; \ + if (((argv[0][0] != '-') && !plus) || (argv[0][1] == (plus ? '+' : '-'))) { \ + if ((argv[0][0] == argv[0][1]) && (argv[0][1] == '-') && (argv[0][2] == '\0')) \ + argc--, argv++; \ + break; \ + } \ + for (argv[0]++; argv[0][0] && !next__;) { \ + switch (*(argv[0])++) + +/** + * End of command line parsing, + */ +#define ARGEND \ + } \ + } \ +} while (0) + +/** + * Get the argument of the current option. + * Do not use more once per option. + * + * The function `noreturn void usage(int)` must be available. + * `usage` shall exit if its argument is `1`. + * + * @return The argument of the current option. + */ +#define ARGF() \ + (next__ = 1, argv[0][0] ? (argv[0]) \ + : (argv++, (argv[0] ? (argc--, argv[0]) \ + : (usage(1), NULL)))) + diff --git a/src/radharc.c b/src/radharc.c index 2c5e8c6..c47bbaf 100644 --- a/src/radharc.c +++ b/src/radharc.c @@ -25,6 +25,13 @@ +/** + * The name of the process. + */ +char *argv0 = NULL; + + + /** * Exit if time the is before year 0 in J2000. */ diff --git a/src/settings.c b/src/settings.c index 0333a41..782fb59 100644 --- a/src/settings.c +++ b/src/settings.c @@ -31,13 +31,6 @@ -/** - * The name of the process. - */ -char *argv0 = NULL; - - - /** * Print usage information and exit if a condition is met. * @@ -179,14 +172,17 @@ parse_command_line(int argc, char *argv[], struct settings *settings) settings->night_temp = 3500; settings->trans_speed = 50; +#define PLUS(...) (plus ? (__VA_ARGS__) : 0) ARGBEGIN { case 'l': + PLUS(location_set = 0); usage(!(p = strchr(arg = ARGF(), ':'))); *p++ = '\0', location_set = 1; usage(parse_location(arg, &(settings->latitude), 90.0)); usage(parse_location(arg, &(settings->longitude), 180.0)); break; case 't': + PLUS(settings->day_temp = 5500, settings->night_temp = 3500); settings->temp = settings->day_temp = settings->night_temp = 0; settings->temp_direction = 0; if ((p = strchr(arg = ARGF(), ':'))) { @@ -198,36 +194,40 @@ parse_command_line(int argc, char *argv[], struct settings *settings) } break; case 'T': + PLUS(settings->natural_temp = 6500); usage(parse_temperature(ARGF(), &(settings->natural_temp), NULL, 1000)); break; case 's': + PLUS(settings->trans_speed = 50); settings->trans_speed = 0; usage(parse_timespec(ARGF(), &(settings->transition))); break; case 'S': + PLUS(settings->trans_speed = 0); usage(parse_temperature(ARGF(), &(settings->trans_speed), NULL, 1)); break; case 'h': - usage(!(settings->hookpath = ARGF())); + settings->hookpath = (plus ? NULL : ARGF()); break; case 'd': c++; /* Fall though. */ case 'e': c++; /* Fall though. */ case 'm': c++; #define REALLOC(VAR, N) !(VAR = realloc(VAR, (N) * sizeof(*VAR))) + PLUS(settings->monitors_n = 0, free(settings->monitors_id), free(settings->monitors_arg)); settings->monitors_n++; if (REALLOC(settings->monitors_id, settings->monitors_n)) goto fail; if (REALLOC(settings->monitors_arg, settings->monitors_n)) goto fail; settings->monitors_id[settings->monitors_n - 1] = ARGF(); settings->monitors_arg[settings->monitors_n - 1] = (c == 3 ? 'm' : c == 2 ? 'e' : 'd'), c = 0; break; - case 'p': settings->print_status = 1; break; - case 'n': settings->panic_start = 1; break; - case 'N': settings->panic_else = 1; break; - case 'o': settings->set_and_exit = 1; break; - case 'x': settings->ignore_calib = 1; break; - case 'i': settings->negative = 1; break; - case 'b': settings->use_bus = 1; break; - default: usage(1); break; + case 'p': settings->print_status = !plus; break; + case 'n': settings->panic_start = !plus; break; + case 'N': settings->panic_else = !plus; break; + case 'o': settings->set_and_exit = !plus; break; + case 'x': settings->ignore_calib = !plus; break; + case 'i': settings->negative = !plus; break; + case 'b': settings->use_bus = !plus; break; + default: usage(1); break; } ARGEND; usage(argc); -- cgit v1.2.3-70-g09d2