diff options
author | Mattias Andrée <m@maandree.se> | 2025-03-27 19:54:15 +0100 |
---|---|---|
committer | Mattias Andrée <m@maandree.se> | 2025-03-27 19:54:15 +0100 |
commit | 92f400215ebb28d9a4cc97095d9c4d1a57f7092f (patch) | |
tree | 221114f48bc2676ca2cee171dcd6aa01b478fe02 | |
parent | Add tests and some fixes (diff) | |
download | libgeome-92f400215ebb28d9a4cc97095d9c4d1a57f7092f.tar.gz libgeome-92f400215ebb28d9a4cc97095d9c4d1a57f7092f.tar.bz2 libgeome-92f400215ebb28d9a4cc97095d9c4d1a57f7092f.tar.xz |
Add patterns for commands (breaks backwards compatbility because libgeome_get_from_netservice was inlined) + add libgeome_get_portability
Signed-off-by: Mattias Andrée <m@maandree.se>
-rw-r--r-- | Makefile | 5 | ||||
-rw-r--r-- | README | 3 | ||||
-rw-r--r-- | TODO | 1 | ||||
-rw-r--r-- | libgeome.h | 124 | ||||
-rw-r--r-- | libgeome_get_from_command.c | 4 | ||||
-rw-r--r-- | libgeome_get_from_netservice.c | 12 | ||||
-rw-r--r-- | libgeome_get_from_patterned_command.c | 164 | ||||
-rw-r--r-- | libgeome_get_portability.c | 12 |
8 files changed, 314 insertions, 11 deletions
@@ -10,7 +10,7 @@ OS = linux include mk/$(OS).mk -LIB_MAJOR = 1 +LIB_MAJOR = 2 LIB_MINOR = 0 LIB_VERSION = $(LIB_MAJOR).$(LIB_MINOR) LIB_NAME = geome @@ -19,10 +19,13 @@ LIB_NAME = geome OBJ =\ libgeome_netservices.o\ libgeome_basic_context.o\ + libgeome_get_portability.o\ libgeome_get_from_time.o\ libgeome_get_from_timezone.o\ libgeome_get_from_file.o\ libgeome_get_from_command.o\ + libgeome_get_from_patterned_command.o\ + libgeome_get_from_netservice.o\ util.o HDR =\ @@ -37,6 +37,7 @@ SYNOPSIS unsigned int alarm_seconds; const char *path; const char *const *args; + unsigned patterned : 1; }; extern const struct libgeome_netservice libgeome_netservices[]; @@ -52,6 +53,8 @@ SYNOPSIS int libgeome_get_from_netservice(struct libgeome_context *, struct libgeome_data *, const struct libgeome_netservice *); + /* less fundament features omitted */ + Link with -lgeome -lm. DESCRIPTION @@ -15,3 +15,4 @@ Add support for more automatic location determination Add geome utility Add support for detecting WiFi and cell towers, using a location service to get a location Add support for detecting changes in nearby WiFi and cell towers +Make default file for libgeome_get_from_file visible to application @@ -25,6 +25,67 @@ /** + * Machine portability class + */ +enum libgeome_portability { + /** + * No data available about the machine's + * portability class + */ + LIBGEOME_UNKNOWN_PORTABILITY, + + /** + * libgeome guesses that the machine is + * stationary (e.g. desktop computer) + */ + LIBGEOME_GUESSED_STATIONARY, + + /** + * libgeome guesses that the machine is + * movable but is usually not moving around + * while in use, or that these movement do + * not need to be closely tracked (e.g. + * laptop computer) + */ + LIBGEOME_GUESSED_PORTABLE, + + /** + * libgeome guesses that the machine is + * frequently on the move even when in use + * and that it may be desirable to keep + * the location updated with short intervals + * (e.g. mobile telephone) + */ + LIBGEOME_GUESSED_MOBILE, + + /** + * The user has specified that the machine + * is only being moved, a significant distance, + * in exceptional circumstances and only when + * powered off + */ + LIBGEOME_STATIONARY, + + /** + * The user has specified that the machine + * is at moved from time to time, regardless + * of whether it is powered on or off, but it + * is not usually useful to keep the location + * up to date with short intervals + */ + LIBGEOME_PORTABLE, + + /** + * The user hsa specified that the is often + * on the move when in use and that it is + * useful to keep the locations updated with + * short intervals + */ + LIBGEOME_MOBILE +}; + + +/** * Geolocation data */ struct libgeome_data { @@ -158,6 +219,15 @@ struct libgeome_netservice { * and an URL) */ const char *const *args; + + /** + * Whether `.path` or `.args` contain %-patterns + * + * See `libgeome_get_from_patterned_command` for more information + * + * @since 2.0 + */ + unsigned patterned : 1; }; @@ -198,6 +268,17 @@ extern const size_t libgeome_netservices_count; void libgeome_basic_context(struct libgeome_context *ctx_out, const char *procname); /** + * Get the machine's partability class + * + * @param ctx Library context + * @param out Output parameter + * @return 0 on success, -1 on failure + * + * @since 2.0 + */ +int libgeome_get_portability(struct libgeome_context *ctx, enum libgeome_portability *out); + +/** * Get a very rough location guess based on * the current timezone's offset from UTC * @@ -269,18 +350,49 @@ int libgeome_get_from_command(struct libgeome_context *ctx, struct libgeome_data * Spawn a program and read it's standard output * to get the user's location data * + * `path` and elements of `argv` are subject to %-substitution + * using the following rules: + * + * - The string is parsed from left to right + * - Any '%' trigger substitutation + * - If the next character is not '%', the "%%" is replaced with a literal "%" + * - Otherwise the next character character must be '{' and '%' marks the beginning + * of a %-pattern. + * - Within a %-pattern "%%" is replaced with "%" and "%}" with "}", and no other + * use of "%" is invalid (nested patterns are disallowed). + * - A %-pattern ends with the first other occurance of a '}' + * - Each %-pattern shall be on one of the two forms: + * - "%%{%u:%s}", <feature set>, <text> + * - "%%{!%u:%s}", <feature set>, <text> + * The if the first pattern is used the pattern is deleted and only replaced with + * <text> if `out->requested_data & <feature set>` is non-zero. + * The if the second pattern is used the pattern is deleted and only replaced with + * <text> if `out->requested_data & <feature set>` is zero. + * <feature set> must be positive. + * + * @param ctx Library context + * @param out Output parameter, `out->requested_data` must be set + * @param limit Number of bytes to stop reading output after, zero for default + * @param alarm_sec If non-zero, the number of seconds to let the subprocess live + * @param path Path to command to spawn + * @param argv Command line arguments for the process, including the name of the command + * @return 0 if data could be retrieved, even if none of the requested data + * could be retrieved, -1 otherwise + */ +int libgeome_get_from_patterned_command(struct libgeome_context *ctx, struct libgeome_data *out, size_t limit, + unsigned int alarm_sec, const char *path, const char *const *argv); + +/** + * Spawn a program and read it's standard output + * to get the user's location data + * * @param ctx Library context * @param out Output parameter, `out->requested_data` must be set * @param svc Parameters for the command to run * @return 0 if data could be retrieved, even if none of the requested data * could be retrieved, -1 otherwise */ -inline int -libgeome_get_from_netservice(struct libgeome_context *ctx, struct libgeome_data *out, - const struct libgeome_netservice *svc) -{ - return libgeome_get_from_command(ctx, out, svc->limit, svc->alarm_seconds, svc->path, svc->args); -} +int libgeome_get_from_netservice(struct libgeome_context *ctx, struct libgeome_data *out, const struct libgeome_netservice *svc); #endif diff --git a/libgeome_get_from_command.c b/libgeome_get_from_command.c index 8e224b6..9b5c338 100644 --- a/libgeome_get_from_command.c +++ b/libgeome_get_from_command.c @@ -94,7 +94,3 @@ libgeome_get_from_command(struct libgeome_context *ctx, struct libgeome_data *ou return 0; } - - -extern inline int libgeome_get_from_netservice(struct libgeome_context *ctx, struct libgeome_data *out, - const struct libgeome_netservice *svc); diff --git a/libgeome_get_from_netservice.c b/libgeome_get_from_netservice.c new file mode 100644 index 0000000..39abc87 --- /dev/null +++ b/libgeome_get_from_netservice.c @@ -0,0 +1,12 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" + + +int +libgeome_get_from_netservice(struct libgeome_context *ctx, struct libgeome_data *out, const struct libgeome_netservice *svc) +{ + if (svc->patterned) + return libgeome_get_from_patterned_command(ctx, out, svc->limit, svc->alarm_seconds, svc->path, svc->args); + else + return libgeome_get_from_command(ctx, out, svc->limit, svc->alarm_seconds, svc->path, svc->args); +} diff --git a/libgeome_get_from_patterned_command.c b/libgeome_get_from_patterned_command.c new file mode 100644 index 0000000..7490dbb --- /dev/null +++ b/libgeome_get_from_patterned_command.c @@ -0,0 +1,164 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" + + +static char * +substitute(struct libgeome_context *ctx, const char *text, uint64_t features) +{ + size_t len = 0, sublen; + size_t i; + int negative, include; + uint64_t if_features, digit; + char *ret, *p; + + for (i = 0; text[i];) { + if (text[i] != '%') { + i += 1U; + len += 1U; + } else if (text[i + 1U] == '%') { + i += 2U; + len += 1U; + } else if (text[i + 1U] == '{') { + i += 2U; + negative = text[i] == '!'; + i += (size_t)negative; + if_features = 0; + for (; isdigit(text[i]); i++) { + digit = (uint64_t)(text[i] & 15); + if (if_features > (UINT64_MAX - digit) / 10U) + goto invalid; + if_features = if_features * 10U + digit; + } + if (!if_features || text[i++] != ':') + goto invalid; + include = !!(if_features & features); + include ^= negative; + sublen = 0; + for (;;) { + if (text[i] == '}') { + i += 1U; + break; + } else if (!text[i]) { + goto invalid; + } else if (text[i] != '%') { + i += 1U; + sublen += 1U; + } else if (text[i + 1U] == '%') { + i += 1U; + sublen += 2U; + } else if (text[i + 1U] == '}') { + i += 1U; + sublen += 2U; + } else { + goto invalid; + } + } + if (include ^ negative) + len += sublen; + } else { + invalid: + ctx->print_error(ctx, "invalid %-pattern in `%s'\n", text); + return NULL; + } + } + + p = ret = malloc(len + 1U); + if (!ret) { + ctx->print_error(ctx, "malloc: %s\n", strerror(errno)); + return NULL; + } + + while (*text) { + if (*text != '%') { + *p++ = *text++; + } else if (text[i + 1U] == '%') { + text = &text[2]; + *p++ = '%'; + } else if (text[i + 1U] == '{') { + text = &text[2]; + negative = *text == '!'; + text = &text[negative]; + if_features = 0; + while (isdigit(*text)) { + digit = (uint64_t)(*text++ & 15); + if_features = if_features * 10U + digit; + } + text++; + include = !!(if_features & features); + include ^= negative; + for (; *text != '}'; text++) { + if (include) + *p++ = text[*text == '%']; + if (*text == '%') + text++; + } + text++; + } + } + *p = '\0'; + + return ret; +} + + +int +libgeome_get_from_patterned_command(struct libgeome_context *ctx, struct libgeome_data *out, size_t limit, /* TODO test */ + unsigned int alarm_sec, const char *path, const char *const *argv) +{ + const char **argv_new = NULL; + char **array; + size_t count = 0; + size_t index = 0; + size_t i, argc = 0; + int ret = -1; + + if (strchr(path, '%')) + count += 1U; + + for (i = 0; argv[i]; i++) + if (strchr(argv[i], '%')) + count += 1U; + argc = i; + + if (!count) + return libgeome_get_from_patterned_command(ctx, out, limit, alarm_sec, path, argv); + + array = calloc(count, sizeof(*array)); + if (!array) { + ctx->print_error(ctx, "calloc: %s\n", strerror(errno)); + return -1; + } + + if (strchr(path, '%')) { + path = array[index++] = substitute(ctx, path, out->requested_data); + if (!path) + goto out; + } + + if (index != count) { + argv_new = calloc(argc + 1U, sizeof(*argv_new)); + if (!argv_new) { + ctx->print_error(ctx, "calloc: %s\n", strerror(errno)); + goto out; + } + argv_new[argc] = NULL; + for (i = 0; argv[i]; i++) { + if (strchr(argv[i], '%')) { + argv_new[i] = array[index++] = substitute(ctx, argv[i], out->requested_data); + if (!argv_new[i]) + goto out; + } else { + argv_new[i] = argv[i]; + } + } + argv = argv_new; + } + + ret = libgeome_get_from_patterned_command(ctx, out, limit, alarm_sec, path, argv); +out: + for (i = 0; i < count; i++) + free(array[i]); + free(array); + free(argv_new); + return ret; +} diff --git a/libgeome_get_portability.c b/libgeome_get_portability.c new file mode 100644 index 0000000..26b6477 --- /dev/null +++ b/libgeome_get_portability.c @@ -0,0 +1,12 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" + + +int +libgeome_get_portability(struct libgeome_context *ctx, enum libgeome_portability *out) +{ + /* TODO implement function */ + (void) ctx; + *out = LIBGEOME_UNKNOWN_PORTABILITY; + return 0; +} |