]> git.sur5r.net Git - i3/i3/commitdiff
Implement variables in configfile.
authorMichael Stapelberg <michael@stapelberg.de>
Mon, 1 Jun 2009 14:19:06 +0000 (16:19 +0200)
committerMichael Stapelberg <michael@stapelberg.de>
Mon, 1 Jun 2009 14:19:06 +0000 (16:19 +0200)
This implements ticket #42.

Syntax is "set $key value". All further instances of $key will be
replaced with value before parsing each line of the configfile.

include/config.h
src/config.c

index 4ed73a3da4e6dd004360d1126d11cccef58ffc32..330b194cd3feadb503d145a0cb46a84b7591b2a6 100644 (file)
@@ -15,6 +15,8 @@
 #ifndef _CONFIG_H
 #define _CONFIG_H
 
+#include "queue.h"
+
 typedef struct Config Config;
 extern Config config;
 
@@ -24,6 +26,13 @@ struct Colortriple {
         uint32_t text;
 };
 
+struct Variable {
+        char *key;
+        char *value;
+
+        SLIST_ENTRY(Variable) variables;
+};
+
 struct Config {
         const char *terminal;
         const char *font;
index 3dec073d296e3feb73ec3bc90df6567717362692..a9e90ab3b56f5bb7e2b0677d60e723d918d67122 100644 (file)
@@ -34,6 +34,28 @@ static char *glob_path(const char *path) {
         return result;
 }
 
+/*
+ * This function does a very simple replacement of each instance of key with value.
+ *
+ */
+static void replace_variable(char *buffer, const char *key, const char *value) {
+        char *pos;
+        /* To prevent endless recursions when the user makes an error configuring,
+         * we stop after 100 replacements. That should be vastly more than enough. */
+        int c = 0;
+        LOG("Replacing %s with %s\n", key, value);
+        while ((pos = strcasestr(buffer, key)) != NULL && c++ < 100) {
+                LOG("replacing variable %s in \"%s\" with \"%s\"\n", key, buffer, value);
+                char *rest = pos + strlen(key);
+                *pos = '\0';
+                char *replaced;
+                asprintf(&replaced, "%s%s%s", buffer, value, rest);
+                /* Hm, this is a bit ugly, but sizeof(buffer) = 4, as it’s just a pointer.
+                 * So we need to hard-code the dimensions here. */
+                strncpy(buffer, replaced, 1026);
+                free(replaced);
+        }
+}
 
 /*
  * Reads the configuration from ~/.i3/config or /etc/i3/config if not found.
@@ -43,6 +65,8 @@ static char *glob_path(const char *path) {
  *
  */
 void load_configuration(xcb_connection_t *conn, const char *override_configpath) {
+        SLIST_HEAD(variables_head, Variable) variables;
+
 #define OPTION_STRING(name) \
         if (strcasecmp(key, #name) == 0) { \
                 config.name = sstrdup(value); \
@@ -75,6 +99,8 @@ void load_configuration(xcb_connection_t *conn, const char *override_configpath)
         /* Clear the old config or initialize the data structure */
         memset(&config, 0, sizeof(config));
 
+        SLIST_INIT(&variables);
+
         /* Initialize default colors */
         config.client.focused.border = get_colorpixel(conn, "#4c7899");
         config.client.focused.background = get_colorpixel(conn, "#285577");
@@ -118,6 +144,14 @@ void load_configuration(xcb_connection_t *conn, const char *override_configpath)
                         die("Could not read configuration file\n");
                 }
 
+                if (config.terminal != NULL)
+                        replace_variable(buffer, "$terminal", config.terminal);
+
+                /* Replace all custom variables */
+                struct Variable *current;
+                SLIST_FOREACH(current, &variables, variables)
+                        replace_variable(buffer, current->key, current->value);
+
                 /* sscanf implicitly strips whitespace. Also, we skip comments and empty lines. */
                 if (sscanf(buffer, "%s %[^\n]", key, value) < 1 ||
                     key[0] == '#' || strlen(key) < 3)
@@ -219,6 +253,26 @@ void load_configuration(xcb_connection_t *conn, const char *override_configpath)
                         continue;
                 }
 
+                /* set a custom variable */
+                if (strcasecmp(key, "set") == 0) {
+                        if (value[0] != '$')
+                                die("Malformed variable assignment, name has to start with $\n");
+
+                        /* get key/value for this variable */
+                        char *v_key = value, *v_value;
+                        if ((v_value = strstr(value, " ")) == NULL)
+                                die("Malformed variable assignment, need a value\n");
+
+                        *(v_value++) = '\0';
+
+                        struct Variable *new = scalloc(sizeof(struct Variable));
+                        new->key = sstrdup(v_key);
+                        new->value = sstrdup(v_value);
+                        SLIST_INSERT_HEAD(&variables, new, variables);
+                        LOG("Got new variable %s = %s\n", v_key, v_value);
+                        continue;
+                }
+
                 die("Unknown configfile option: %s\n", key);
         }
         fclose(handle);