aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMattias Andrée <m@maandree.se>2025-03-27 19:54:15 +0100
committerMattias Andrée <m@maandree.se>2025-03-27 19:54:15 +0100
commit92f400215ebb28d9a4cc97095d9c4d1a57f7092f (patch)
tree221114f48bc2676ca2cee171dcd6aa01b478fe02
parentAdd tests and some fixes (diff)
downloadlibgeome-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--Makefile5
-rw-r--r--README3
-rw-r--r--TODO1
-rw-r--r--libgeome.h124
-rw-r--r--libgeome_get_from_command.c4
-rw-r--r--libgeome_get_from_netservice.c12
-rw-r--r--libgeome_get_from_patterned_command.c164
-rw-r--r--libgeome_get_portability.c12
8 files changed, 314 insertions, 11 deletions
diff --git a/Makefile b/Makefile
index e5926ac..f86cb27 100644
--- a/Makefile
+++ b/Makefile
@@ -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 =\
diff --git a/README b/README
index 4047077..54660f2 100644
--- a/README
+++ b/README
@@ -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
diff --git a/TODO b/TODO
index ced7b6c..1ad9a60 100644
--- a/TODO
+++ b/TODO
@@ -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
diff --git a/libgeome.h b/libgeome.h
index 1e81494..da9b216 100644
--- a/libgeome.h
+++ b/libgeome.h
@@ -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;
+}