aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorMattias Andrée <maandree@member.fsf.org>2016-01-03 10:22:16 +0100
committerMattias Andrée <maandree@member.fsf.org>2016-01-03 10:26:20 +0100
commitd9c5b54e4f48d8e00ddba4d5b487b7557fe2a9f5 (patch)
treec668f0d0eb1d987f9afba4596dc570cc76071559 /src
parentm (diff)
downloadradharc-d9c5b54e4f48d8e00ddba4d5b487b7557fe2a9f5.tar.gz
radharc-d9c5b54e4f48d8e00ddba4d5b487b7557fe2a9f5.tar.bz2
radharc-d9c5b54e4f48d8e00ddba4d5b487b7557fe2a9f5.tar.xz
add support for +options to remove effect of -option
Signed-off-by: Mattias Andrée <maandree@member.fsf.org>
Diffstat (limited to 'src')
-rw-r--r--src/arg.h114
-rw-r--r--src/radharc.c7
-rw-r--r--src/settings.c32
3 files changed, 101 insertions, 52 deletions
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 <maandree@member.fsf.org>
+ *
+ * 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
@@ -26,6 +26,13 @@
/**
+ * The name of the process.
+ */
+char *argv0 = NULL;
+
+
+
+/**
* Exit if time the is before year 0 in J2000.
*/
#if defined(TIMETRAVELLER)
diff --git a/src/settings.c b/src/settings.c
index 0333a41..782fb59 100644
--- a/src/settings.c
+++ b/src/settings.c
@@ -32,13 +32,6 @@
/**
- * The name of the process.
- */
-char *argv0 = NULL;
-
-
-
-/**
* Print usage information and exit if a condition is met.
*
* @param condition Do no do anything iff this is zero.
@@ -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);