aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/cmd-instance.c120
-rw-r--r--src/instance.c193
-rw-r--r--src/instance.h22
-rw-r--r--src/l2su.c131
-rw-r--r--src/l2su.h25
-rw-r--r--src/launcherutil.c157
-rw-r--r--src/meson.build2
-rw-r--r--src/uuid/uuid.c23
-rw-r--r--src/uuid/uuid.h5
9 files changed, 559 insertions, 119 deletions
diff --git a/src/cmd-instance.c b/src/cmd-instance.c
index 9e346e2..89494af 100644
--- a/src/cmd-instance.c
+++ b/src/cmd-instance.c
@@ -1,11 +1,126 @@
#include "commands.h"
-#include "src/command.h"
+#include "command.h"
+#include "instance.h"
+#include "l2su.h"
+
#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <stdbool.h>
unsigned cmd_instance_add(struct l2_context_node *ctx, char **args)
{
+ int res = l2_instance_load_all();
+ char *name = NULL;
+ char *path = NULL;
+ char *newpath = NULL;
+ uuid_t uuid;
+ char uuidstr[UUID_STRLEN+1];
+
+ if (res != INSTANCE_SUCCESS) {
+ if (res == INSTANCE_ERRNO) {
+ fprintf(stderr, "fatal: Error loading instances: %s", strerror(errno));
+ } else {
+ fprintf(stderr, "fatal: Error loading instances (%d)\n", res);
+ }
+ return CMD_RESULT_FAIL;
+ }
+
+ /* get the name and path (if it exists) */
+ for (struct l2_context_node *cur = ctx; cur; cur = cur->next) {
+ if (cur->node->type != CMD_NODE_TYPE_ARGUMENT) continue;
+ if (!strcmp("name", cur->node->name)) {
+ name = cur->value;
+ } else if (!strcmp("location", cur->node->name)) {
+ path = cur->value;
+ }
+ }
+
+ /* make sure the name and path make sense (path should be an absolute path, name shouldn't be empty) */
+ if (!name || !*name) {
+ fputs("fatal: The specified name is invalid\n", stderr);
+ return CMD_RESULT_FAIL;
+ }
+
+ for (char *cur = name; *cur; ++cur) {
+ if (*cur < ' ') {
+ fputs("fatal: The specified name contains invalid characters\n", stderr);
+ return CMD_RESULT_FAIL;
+ }
+ }
+
+ /* make sure there is not a profile with that name already */
+ for (struct l2_instance *cur = l2_state.instance_head; cur; cur = cur->next) {
+ if (!strcmp(cur->name, name)) {
+ fprintf(stderr, "fatal: An instance by the name '%s' already exists.\n", cur->name);
+ return CMD_RESULT_FAIL;
+ }
+ }
+
+ /* also find an unused UUID through rejection sampling */
+ bool found;
+ do {
+ found = false;
+ l2_uuid_random(&uuid);
+ for (struct l2_instance *cur = l2_state.instance_head; cur; cur = cur->next) {
+ if (!l2_uuid_compare(&cur->uuid, &uuid)) {
+ found = true;
+ break;
+ }
+ }
+ } while (found);
+
+ /* create the directory at "path" (if it isn't empty, complain) */
+ if (path && *path != '/') {
+ fputs("fatal: Specified path is not an absolute path\n", stderr);
+ return CMD_RESULT_FAIL;
+ } else if (!path) {
+ newpath = strdup(l2_state.paths.data);
+ if (!newpath) {
+ newpath_append_fail:
+ free(newpath);
+ fprintf(stderr, "fatal: Allocation failed: %s\n", strerror(errno));
+ return CMD_RESULT_FAIL;
+ }
+
+ newpath = l2_launcher_strapp(newpath, "/instances/");
+ if (!newpath) goto newpath_append_fail;
+
+ l2_uuid_to_string(&uuid, uuidstr);
+ newpath = l2_launcher_strapp(newpath, uuidstr);
+ if (!newpath) goto newpath_append_fail;
+ }
+
+ /* TODO: now create the directory for realsies */
+
+ /* add the instance */
+
+ struct l2_instance inst;
+
+ inst.uuid = uuid;
+ inst.name = name;
+ inst.path = path ? path : newpath;
+
+ if ((res = l2_instance_add_instance(&inst)) != INSTANCE_SUCCESS) {
+ fprintf(stderr, "fatal: Failed to add instance (%d)\n", res);
+ res = CMD_RESULT_FAIL;
+ goto cleanup;
+ }
+
+ if ((res = l2_instance_save_all()) != INSTANCE_SUCCESS) {
+ fprintf(stderr, "fatal: Failed to add instance (%d)\n", res);
+ res = CMD_RESULT_FAIL;
+ goto cleanup;
+ }
+
printf("add command yay\n");
- return CMD_RESULT_SUCCESS;
+
+ res = CMD_RESULT_SUCCESS;
+
+cleanup:
+ free(newpath);
+ return res;
}
unsigned cmd_instance_remove(struct l2_context_node *ctx, char **args)
@@ -22,4 +137,3 @@ unsigned cmd_instance_rename(struct l2_context_node *ctx, char **args)
{
return CMD_RESULT_SUCCESS;
}
-
diff --git a/src/instance.c b/src/instance.c
new file mode 100644
index 0000000..20c0f59
--- /dev/null
+++ b/src/instance.c
@@ -0,0 +1,193 @@
+#include "instance.h"
+#include "l2su.h"
+#include "uuid/uuid.h"
+
+#include <stdlib.h>
+#include <jansson.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <string.h>
+
+#include <errno.h>
+
+int l2_instance__load_all_from_object(json_t *obj);
+json_t *l2_instance__save_all_to_object(void);
+
+/* da main functionality */
+
+int l2_instance_load_all(void)
+{
+ /* open + openat because I am too lazy to concatenate the path with the filename */
+ int instfd = l2_launcher_open_config("instance.json", O_RDONLY, 0);
+ if (instfd < 0) {
+ return errno == ENOENT ? INSTANCE_SUCCESS : INSTANCE_ERRNO;
+ }
+
+ json_error_t jserr;
+ json_t *js = json_loadfd(instfd, JSON_REJECT_DUPLICATES, &jserr);
+
+ if (!js) {
+ fprintf(stderr, "error: JSON error in instance.json: %s (%s:%d:%d)\n", jserr.text, jserr.source, jserr.line, jserr.column);
+ return INSTANCE_EJSON;
+ }
+
+ if (!json_is_object(js)) {
+ fprintf(stderr, "error: instances.json value is not an object (is actually %d)\n", json_typeof(js));
+ json_decref(js);
+ return INSTANCE_EFORMAT;
+ }
+
+ int res = l2_instance__load_all_from_object(js);
+ json_decref(js);
+ return res;
+}
+
+int l2_instance_save_all(void)
+{
+ json_t *js = NULL;
+ int instfd = l2_launcher_open_config("instance.json", O_WRONLY | O_CREAT, 0644);
+ if (instfd < 0) return INSTANCE_ERRNO;
+
+ int retval = INSTANCE_SUCCESS;
+
+ js = l2_instance__save_all_to_object();
+ if (!js) {
+ retval = INSTANCE_EJSON;
+ goto save_done;
+ }
+
+ if (json_dumpfd(js, instfd, JSON_INDENT(4)) < 0) {
+ retval = INSTANCE_EJSON;
+ }
+
+save_done:
+ close(instfd);
+ json_decref(js);
+ return retval;
+}
+
+/* public utilities */
+
+int l2_instance_add_instance(const struct l2_instance *inst)
+{
+ char *path = strdup(inst->path);
+ if (!path) return INSTANCE_ERRNO;
+
+ char *name = strdup(inst->name);
+ if (!name) {
+ free(path);
+ return INSTANCE_ERRNO;
+ }
+
+ struct l2_instance *newinst = calloc(1, sizeof(struct l2_instance));
+ if (!newinst) {
+ free(path);
+ free(name);
+ return INSTANCE_ERRNO;
+ }
+
+ newinst->uuid = inst->uuid;
+ newinst->path = path;
+ newinst->name = name;
+
+ if (l2_state.instance_head && l2_state.instance_tail) {
+ l2_state.instance_tail->next = newinst;
+ newinst->prev = l2_state.instance_tail;
+ l2_state.instance_tail = newinst;
+ } else {
+ l2_state.instance_head = l2_state.instance_tail = newinst;
+ }
+
+ return INSTANCE_SUCCESS;
+}
+
+int l2_instance_del_instance(struct l2_instance *inst)
+{
+ if (inst->next) {
+ inst->next->prev = inst->prev;
+ } else {
+ l2_state.instance_tail = inst->prev;
+ }
+
+ if (inst->prev) {
+ inst->prev->next = inst->next;
+ } else {
+ l2_state.instance_head = inst->next;
+ }
+
+ return INSTANCE_SUCCESS;
+}
+
+/* internal utilities */
+
+int l2_instance__load_all_from_object(json_t *obj)
+{
+ const char *key;
+ json_t *val;
+ json_t *tempval;
+ int res;
+
+ struct l2_instance inst;
+
+ json_object_foreach(obj, key, val) {
+ if (!json_is_object(val)) {
+ return INSTANCE_EFORMAT;
+ }
+
+ if (!l2_uuid_from_string(&inst.uuid, key)) {
+ return INSTANCE_EFORMAT; /* invalid UUID */
+ }
+
+ tempval = json_object_get(val, "name");
+ if (!json_is_string(tempval)) {
+ return INSTANCE_EFORMAT;
+ }
+
+ /* it's okay to discard const here because add_instance duplicates the string */
+ inst.name = (char *)json_string_value(tempval);
+
+ tempval = json_object_get(val, "path");
+ if (!json_is_string(tempval)) {
+ return INSTANCE_EFORMAT;
+ }
+
+ inst.path = (char *)json_string_value(tempval);
+
+ if ((res = l2_instance_add_instance(&inst)) != INSTANCE_SUCCESS) {
+ return res;
+ }
+ }
+
+ return INSTANCE_SUCCESS;
+}
+
+json_t *l2_instance__save_all_to_object(void)
+{
+ json_t *obj = json_object();
+ json_t *jinst;
+ if (!obj) return NULL;
+
+ char uuidbuf[UUID_STRLEN + 1];
+
+ for (struct l2_instance *inst = l2_state.instance_head; inst; inst = inst->next) {
+ l2_uuid_to_string(&inst->uuid, uuidbuf);
+ if (json_object_set_new(obj, uuidbuf, jinst = json_object()) < 0) {
+ goto save_err; /* jinst is decref'd anyway (undocumented) */
+ }
+
+ if (json_object_set_new(jinst, "name", json_string(inst->name)) < 0) {
+ goto save_err;
+ }
+
+ if (json_object_set_new(jinst, "path", json_string(inst->path)) < 0) {
+ goto save_err;
+ }
+ }
+
+ return obj;
+
+save_err:
+ json_decref(obj);
+ return NULL;
+}
diff --git a/src/instance.h b/src/instance.h
index b0be665..e7e5943 100644
--- a/src/instance.h
+++ b/src/instance.h
@@ -5,12 +5,26 @@
struct l2_instance {
uuid_t uuid;
- char *name;
- char *path;
+ const char *name;
+ const char *path;
+
+ struct l2_instance *next;
+ struct l2_instance *prev;
+};
+
+enum {
+ INSTANCE_SUCCESS, /* instance operation succeeded */
+ INSTANCE_ERRNO, /* instance operation failed (error code in errno) */
+ INSTANCE_EJSON, /* instance operation failed (JSON error) */
+ INSTANCE_EFORMAT /* instance file is malformed */
};
-void l2_instance_load(void);
+/* load all instances (must be called after initialization) */
+int l2_instance_load_all(void);
+
+int l2_instance_save_all(void);
-void l2_instance_save(void);
+int l2_instance_add_instance(const struct l2_instance *inst);
+int l2_instance_del_instance(struct l2_instance *inst);
#endif /* include guard */
diff --git a/src/l2su.c b/src/l2su.c
index bd22987..c9a100b 100644
--- a/src/l2su.c
+++ b/src/l2su.c
@@ -1,135 +1,68 @@
#include "l2su.h"
+#include "command.h"
#include "macros.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <errno.h>
-char *l2_launcher__strdup(const char *);
-char *l2_launcher__strapp(char *, const char *);
-
-char *l2_launcher__find_config_path(void)
-{
- /* check for $L2SU_CONFIG */
- char *config = getenv(PROJECT_NAME_UPPER "_CONFIG");
- if (config) {
- return l2_launcher__strdup(config);
- }
-
- /* check for $XDG_CONFIG_HOME */
- config = getenv("XDG_CONFIG_HOME");
- if (config) {
- /* want to append '"/" PROJECT_NAME' to our string */
- char *ret = l2_launcher__strdup(config);
- if (!ret) return NULL;
-
- return l2_launcher__strapp(ret, "/" PROJECT_NAME);
- }
-
- /* check for $HOME/.config */
- config = getenv("HOME");
- if (config) {
- char *ret = l2_launcher__strdup(config);
- if (!ret) return NULL;
-
- return l2_launcher__strapp(ret, "/.config/" PROJECT_NAME);
- }
-
- /* fail (do NOT attempt to find home directory from passwd */
- return NULL;
-}
-
-char *l2_launcher__find_data_path(void)
-{
- /* check for $L2SU_DATA */
- char *config = getenv(PROJECT_NAME_UPPER "_DATA");
- if (config) {
- return l2_launcher__strdup(config);
- }
-
- /* check for $XDG_DATA_HOME */
- config = getenv("XDG_DATA_HOME");
- if (config) {
- char *ret = l2_launcher__strdup(config);
- if (!ret) return NULL;
-
- return l2_launcher__strapp(ret, "/" PROJECT_NAME);
- }
-
- /* check for $HOME/.local/share */
- config = getenv("HOME");
- if (config) {
- char *ret = l2_launcher__strdup(config);
- if (!ret) return NULL;
-
- return l2_launcher__strapp(ret, "/.local/share/" PROJECT_NAME);
- }
-
- return NULL;
-}
+struct tag_l2_state_t l2_state = { 0 };
int l2_launcher_init(void)
{
/* find paths (set up l2_state.paths) */
/* create folders if they don't exist */
- printf("project is " PROJECT_NAME "...\n");
-
/* look for config path */
- if (!(l2_state.paths.config = l2_launcher__find_config_path())) {
+ if (!(l2_state.paths.config = l2_launcher_find_config_path())) {
fputs("fatal: Could not decide on a configuration directory! Please define " PROJECT_NAME_UPPER "_CONFIG to a sensible value.\n", stderr);
return 1;
}
- if (!(l2_state.paths.data = l2_launcher__find_data_path())) {
+ if (!(l2_state.paths.data = l2_launcher_find_data_path())) {
fputs("fatal: Could not decide on a data directory! Please define " PROJECT_NAME_UPPER "_DATA to a sensible value.\n", stderr);
return 1;
}
- printf("config path: %s\n", l2_state.paths.config);
- printf("data path: %s\n", l2_state.paths.data);
+ printf("Using configuration path: %s\n", l2_state.paths.config);
+ printf("Using data path: %s\n", l2_state.paths.data);
- return 0;
-}
+ if (l2_launcher_mkdir_parents(l2_state.paths.config) < 0) {
+ fprintf(stderr, "fatal: Could not create config directory: %s\n", strerror(errno));
+ return 1;
+ }
-int main(void)
-{
- int status = l2_launcher_init();
- if (status != 0) return status;
+ if (l2_launcher_mkdir_parents(l2_state.paths.data) < 0) {
+ fprintf(stderr, "fatal: Could not create data directory: %s\n", strerror(errno));
+ return 1;
+ }
return 0;
}
-/* handcoded string functions
- *
- * NOTE: I am aware that this is inefficient but since these are used only a handful of times
- * during initialization, I don't think performance is really a huge deal here.
- *
- * remember that this is a Minecraft launcher, so the PC has to meet the minimum specs of that,
- * which are well above the minimum specs of this launcher */
-
-char *l2_launcher__strdup(const char *in)
+int main(int argc, char **argv)
{
- if (!in) return NULL;
+ int status = l2_launcher_init();
+ if (status != 0) return EXIT_FAILURE;
- size_t inlen = strlen(in);
- char *ret = calloc(1, inlen + 1);
+ if (argc == 0 || !argv || !*argv) {
+ fputs("weird: no program name!\n", stderr);
+ return EXIT_FAILURE;
+ }
- if (ret) memcpy(ret, in, inlen);
+ struct l2_parseinfo parseinfo;
+ unsigned parseres = l2_cmd_parse_command(argv + 1, &parseinfo);
+ if (parseres != CMD_PARSE_SUCCESS) {
+ fputs("failed to parse command\n", stderr);
+ return EXIT_FAILURE;
+ }
- return ret;
-}
+ unsigned res = (*parseinfo.proc)(parseinfo.ctx, parseinfo.argv);
-char *l2_launcher__strapp(char *buf, const char *src)
-{
- size_t buflen = strlen(buf);
- size_t srclen = strlen(src);
+ l2_cmd_free_ctx(parseinfo.ctx);
- char *ret = realloc(buf, buflen + srclen + 1);
- if (!ret) return NULL;
+ return res == CMD_RESULT_SUCCESS ? EXIT_SUCCESS : EXIT_FAILURE;
+}
- memcpy(ret + buflen, src, srclen);
- ret[buflen + srclen] = '\0';
- return ret;
-}
diff --git a/src/l2su.h b/src/l2su.h
index 13df852..1746a53 100644
--- a/src/l2su.h
+++ b/src/l2su.h
@@ -4,14 +4,33 @@
#include "command.h"
#include "instance.h"
+#include <fcntl.h>
+
struct l2_user_paths {
const char *config;
const char *data;
};
-struct {
+struct tag_l2_state_t {
struct l2_user_paths paths;
- struct l2_instance *instances;
-} l2_state;
+
+ /* eventually instances and other stuff will be stored in a hash table or something,
+ * but for now a doubly-linked list accomplishes our goals */
+ struct l2_instance *instance_head;
+ struct l2_instance *instance_tail;
+};
+
+extern struct tag_l2_state_t l2_state;
+
+/* homecooked string methods */
+char *l2_launcher_strapp(char *target, const char *src);
+
+/* launcher utilities */
+char *l2_launcher_find_config_path(void);
+char *l2_launcher_find_data_path(void);
+
+int l2_launcher_open_config(const char *path, int flags, mode_t mode);
+
+int l2_launcher_mkdir_parents(const char *path);
#endif /* include guard */
diff --git a/src/launcherutil.c b/src/launcherutil.c
new file mode 100644
index 0000000..8df4a71
--- /dev/null
+++ b/src/launcherutil.c
@@ -0,0 +1,157 @@
+#include "macros.h"
+#include "l2su.h"
+
+#include <stdlib.h>
+#include <string.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <errno.h>
+#include <sys/stat.h>
+
+/* handcoded string functions
+ *
+ * NOTE: I am aware that this is inefficient but since these are used only a handful of times
+ * during initialization, I don't think performance is really a huge deal here.
+ *
+ * remember that this is a Minecraft launcher, so the PC has to meet the minimum specs of that,
+ * which are well above the minimum specs of this launcher */
+
+char *l2_launcher_strapp(char *buf, const char *src)
+{
+ size_t buflen = strlen(buf);
+ size_t srclen = strlen(src);
+
+ char *ret = realloc(buf, buflen + srclen + 1);
+ if (!ret) return NULL;
+
+ memcpy(ret + buflen, src, srclen);
+ ret[buflen + srclen] = '\0'; /* realloc does not initialize like calloc does */
+
+ return ret;
+}
+
+char *l2_launcher_find_config_path(void)
+{
+ /* check for $L2SU_CONFIG */
+ char *config = getenv(PROJECT_NAME_UPPER "_CONFIG");
+ if (config) {
+ return strdup(config);
+ }
+
+ /* check for $XDG_CONFIG_HOME */
+ config = getenv("XDG_CONFIG_HOME");
+ if (config) {
+ /* want to append '"/" PROJECT_NAME' to our string */
+ char *ret = strdup(config);
+ if (!ret) return NULL;
+
+ return l2_launcher_strapp(ret, "/" PROJECT_NAME);
+ }
+
+ /* check for $HOME/.config */
+ config = getenv("HOME");
+ if (config) {
+ char *ret = strdup(config);
+ if (!ret) return NULL;
+
+ return l2_launcher_strapp(ret, "/.config/" PROJECT_NAME);
+ }
+
+ /* fail (do NOT attempt to find home directory from passwd */
+ return NULL;
+}
+
+char *l2_launcher_find_data_path(void)
+{
+ /* check for $L2SU_DATA */
+ char *config = getenv(PROJECT_NAME_UPPER "_DATA");
+ if (config) {
+ return strdup(config);
+ }
+
+ /* check for $XDG_DATA_HOME */
+ config = getenv("XDG_DATA_HOME");
+ if (config) {
+ char *ret = strdup(config);
+ if (!ret) return NULL;
+
+ return l2_launcher_strapp(ret, "/" PROJECT_NAME);
+ }
+
+ /* check for $HOME/.local/share */
+ config = getenv("HOME");
+ if (config) {
+ char *ret = strdup(config);
+ if (!ret) return NULL;
+
+ return l2_launcher_strapp(ret, "/.local/share/" PROJECT_NAME);
+ }
+
+ return NULL;
+}
+
+int l2_launcher_open_config(const char *path, int flags, mode_t mode)
+{
+ int conffd = open(l2_state.paths.config, O_RDONLY | O_DIRECTORY);
+ if (conffd < 0) return INSTANCE_ERRNO;
+
+ int instfd = openat(conffd, path, flags, mode);
+ int en = errno; /* back up errno because close can fail */
+
+ close(conffd);
+
+ errno = en;
+ return instfd;
+}
+
+/* NOTE: There's no portable (or otherwise - see open(2) BUGS) way to do this without race conditions. */
+int l2_launcher_mkdir_parents(const char *path)
+{
+ if (*path != '/') return -1;
+
+ int reserrno = 0;
+
+ char *pathbuf = strdup(path);
+ char *pcurelem = pathbuf;
+ if (!pathbuf) return -1;
+
+ struct stat stbuf = { 0 };
+
+ do { /* strtok is off-limits because it smells bad */
+ *pcurelem = '/';
+ pcurelem = strchr(pcurelem + 1, '/');
+
+ if (pcurelem) {
+ *pcurelem = '\0';
+ }
+
+ /* now pathbuf contains our truncated path name which may or may not exist */
+ if (mkdir(pathbuf, 0755) < 0) {
+ if (errno == EEXIST) {
+ /* racy: stat the file and continue if it is a directory */
+ if (stat(pathbuf, &stbuf) < 0) {
+ reserrno = errno;
+ goto mdcleanup;
+ }
+
+ if (!S_ISDIR(stbuf.st_mode)) {
+ reserrno = ENOTDIR;
+ goto mdcleanup;
+ }
+ } else {
+ reserrno = errno;
+ goto mdcleanup;
+ }
+ }
+ } while (pcurelem);
+
+mdcleanup:
+
+ free(pathbuf);
+ if (reserrno != 0) {
+ errno = reserrno;
+ return -1;
+ }
+
+ return 0;
+}
diff --git a/src/meson.build b/src/meson.build
index 2f675ea..000bf6b 100644
--- a/src/meson.build
+++ b/src/meson.build
@@ -1,4 +1,4 @@
-launcher_srcs = files('l2su.c', 'command.c', 'cmd-instance.c', 'uuid/uuid.c')
+launcher_srcs = files('l2su.c', 'command.c', 'cmd-instance.c', 'uuid/uuid.c', 'launcherutil.c', 'instance.c')
configure_file(input : 'config.h.in', output : 'config.h', configuration : config_data)
config_include_dir = include_directories('.')
diff --git a/src/uuid/uuid.c b/src/uuid/uuid.c
index 0d49f0b..0dfcfbd 100644
--- a/src/uuid/uuid.c
+++ b/src/uuid/uuid.c
@@ -11,8 +11,8 @@ void l2_uuid__set_version(uuid_t *id, unsigned version)
{
version &= 0x0F;
- id->halves[1] &= ~(UINT64_C(0x0F) << 12);
- id->halves[1] |= (uint64_t)version << 12;
+ id->uuid_ms &= ~(UINT64_C(0x0F) << 12);
+ id->uuid_ms |= (uint64_t)version << 12;
}
void l2_uuid__set_variant(uuid_t *id, unsigned variant, unsigned bits)
@@ -21,8 +21,8 @@ void l2_uuid__set_variant(uuid_t *id, unsigned variant, unsigned bits)
uint64_t lvariant = (uint64_t)variant << (64 - bits);
lvariant &= ~mask;
- id->halves[0] &= mask;
- id->halves[0] |= lvariant;
+ id->uuid_ls &= mask;
+ id->uuid_ls |= lvariant;
}
void l2_uuid_random(uuid_t *id)
@@ -35,11 +35,11 @@ void l2_uuid_random(uuid_t *id)
void l2_uuid_to_string(const uuid_t *id, char *out)
{
snprintf(out, UUID_STRLEN + 1, "%08" PRIx64 "-%04" PRIx64 "-%04" PRIx64 "-%04" PRIx64 "-%012" PRIx64,
- id->halves[1] >> 32, /* time-low */
- id->halves[1] >> 16 & 0xffff, /* time-mid */
- id->halves[1] & 0xffff, /* time-high-and-version */
- id->halves[0] >> 48, /* clock-seq-and-reserved, clock-seq-low */
- id->halves[0] & UINT64_C(0xffffffffffff)); /* node */
+ id->uuid_ms >> 32, /* time-low */
+ id->uuid_ms >> 16 & 0xffff, /* time-mid */
+ id->uuid_ms & 0xffff, /* time-high-and-version */
+ id->uuid_ls >> 48, /* clock-seq-and-reserved, clock-seq-low */
+ id->uuid_ls & UINT64_C(0xffffffffffff)); /* node */
}
void l2_uuid_to_string_short(const uuid_t *id, char *out)
@@ -78,6 +78,11 @@ bool l2_uuid_from_string_short(uuid_t *id, const char *str)
return true;
}
+int l2_uuid_compare(const uuid_t *c1, const uuid_t *c2)
+{
+ return memcmp(c1, c2, sizeof(uuid_t));
+}
+
/* This function exists because there's not a portable way to do this.
* Don't suggest strtoull, because uint64_t may not be a ulonglong. */
bool l2__str_to_uint64(uint64_t *out, const char *str)
diff --git a/src/uuid/uuid.h b/src/uuid/uuid.h
index 740fa17..7ddeeb4 100644
--- a/src/uuid/uuid.h
+++ b/src/uuid/uuid.h
@@ -9,6 +9,9 @@
typedef union tag_uuid_t {
uint8_t bytes[16];
uint64_t halves[2];
+
+#define uuid_ls halves[0]
+#define uuid_ms halves[1]
} uuid_t;
#define UUID_NULL_INIT { { 0 } }
@@ -24,4 +27,6 @@ void l2_uuid_to_string_short(const uuid_t *id, char *out);
bool l2_uuid_from_string(uuid_t *id, const char *str);
bool l2_uuid_from_string_short(uuid_t *id, const char *str);
+int l2_uuid_compare(const uuid_t *c1, const uuid_t *c2);
+
#endif /* include guard */