--- /dev/null
+#ifndef CONFIG_DIR_H
+#define CONFIG_DIR_H
+
+char *config_dir(void);
+
+#endif /* CONFIG_DIR_H */
--- /dev/null
+/*
+ * Find the labwc configuration directory
+ *
+ * Copyright Johan Malm 2020
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <stdbool.h>
+#include <glib.h>
+
+#include "config/config-dir.h"
+
+struct dir {
+ const char *prefix;
+ const char *path;
+};
+
+/* clang-format off */
+static struct dir config_dirs[] = {
+ { "XDG_CONFIG_HOME", "labwc" },
+ { "HOME", ".config/labwc" },
+ { "XDG_CONFIG_DIRS", "labwc" },
+ { NULL, "/etc/xdg/labwc" },
+ { "XDG_CONFIG_HOME", "openbox" },
+ { "HOME", ".config/openbox" },
+ { "XDG_CONFIG_DIRS", "openbox" },
+ { NULL, "/etc/xdg/openbox" },
+ { NULL, NULL }
+};
+/* clang-format on */
+
+static bool isdir(const char *path)
+{
+ struct stat st;
+ return (!stat(path, &st) && S_ISDIR(st.st_mode));
+}
+
+char *config_dir(void)
+{
+ static char buf[4096] = { 0 };
+ if (buf[0] != '\0')
+ return buf;
+
+ for (int i = 0; config_dirs[i].path; i++) {
+ struct dir d = config_dirs[i];
+ if (!d.prefix) {
+ /* handle /etc/xdg... */
+ snprintf(buf, sizeof(buf), "%s", d.path);
+ if (isdir(buf))
+ return buf;
+ } else {
+ /* handle $HOME/.config/... and $XDG_* */
+ char *prefix = getenv(d.prefix);
+ if (!prefix)
+ continue;
+ gchar **prefixes = g_strsplit(prefix, ":", -1);
+ for (gchar **p = prefixes; *p; p++) {
+ snprintf(buf, sizeof(buf), "%s/%s", *p, d.path);
+ if (isdir(buf))
+ return buf;
+ }
+ }
+ }
+ /* no config directory was found */
+ buf[0] = '.';
+ buf[1] = '\0';
+ return buf;
+}
labwc_sources += files(
+ 'config-dir.c',
'rcxml.c',
'keybind.c',
)
#include <wayland-server-core.h>
#include "rcxml.h"
+#include "config/config-dir.h"
static bool in_keybind = false;
static bool is_attribute = false;
}
}
+static void rcxml_path(char *buf, size_t len, const char *filename)
+{
+ if (filename)
+ snprintf(buf, len, "%s", filename);
+ else
+ snprintf(buf, len, "%s/rc.xml", config_dir());
+}
+
void rcxml_read(const char *filename)
{
FILE *stream;
char *line = NULL;
size_t len = 0;
struct buf b;
+ char rcxml[4096];
rcxml_init();
wl_list_init(&rc.keybinds);
- /* Read <filename> into buffer and then call rcxml_parse_xml() */
- stream = fopen(filename, "r");
+ /*
+ * Reading file into buffer before parsing makes it easier to write
+ * unit tests.
+ */
+ rcxml_path(rcxml, sizeof(rcxml), filename);
+ fprintf(stderr, "info: read config file (%s)\n", rcxml);
+ stream = fopen(rcxml, "r");
if (!stream) {
- fprintf(stderr, "warn: cannot read '%s'\n", filename);
+ fprintf(stderr, "warn: cannot read '%s'\n", rcxml);
goto out;
}
buf_init(&b);
struct theme theme = { 0 };
static const char labwc_usage[] =
-"Usage: labwc [-h] [-s <command>]\n";
+"Usage: labwc [-h] [-s <startup-command>] [-c <config-file>]\n";
static void usage(void)
{
int main(int argc, char *argv[])
{
char *startup_cmd = NULL;
+ char *config_file = NULL;
wlr_log_init(WLR_ERROR, NULL);
int c;
- while ((c = getopt(argc, argv, "s:h")) != -1) {
+ while ((c = getopt(argc, argv, "s:c:h")) != -1) {
switch (c) {
case 's':
startup_cmd = optarg;
break;
+ case 'c':
+ config_file = optarg;
+ break;
default:
usage();
}
if (optind < argc)
usage();
- rcxml_read("data/rc.xml");
+ rcxml_read(config_file);
/* Wayland requires XDG_RUNTIME_DIR to be set */
if (!getenv("XDG_RUNTIME_DIR")) {