:: commit b5808884a317dadca8ef7fac076811bb9d114fdd

mintsuki <mintsuki@protonmail.com> — 2021-12-15 18:29

parents: 4cb616bcad

config: Implement macros

diff --git a/CONFIG.md b/CONFIG.md
index aa241376..ae2c5591 100644
--- a/CONFIG.md
+++ b/CONFIG.md
@@ -8,8 +8,8 @@ of either a `/limine.cfg`, `/boot/limine.cfg`, or a `/EFI/BOOT/limine.cfg` file,
 
 If no config file is found in the aforementioned locations, Limine looks for the file on the fw_cfg
 interface called `opt/org.limine-bootloader.config`. If that is not present and the kernel is found at
-`opt/org.limine-bootloader.kernel`, Limine enters the so-called "simple mode", where the kernel is loaded from 
-`opt/org.limine-bootloader.kernel`, and, (if present), the background is loaded from 
+`opt/org.limine-bootloader.kernel`, Limine enters the so-called "simple mode", where the kernel is loaded from
+`opt/org.limine-bootloader.kernel`, and, (if present), the background is loaded from
 `opt/org.limine-bootloader.background`.
 
 Once the file is located, Limine will use it as its config file. Other possible
@@ -161,3 +161,18 @@ A resource can be one of the following:
 A URI can optionally be prefixed by a `$` character to indicate that the file
 pointed to be the URI is a gzip-compressed payload to be uncompressed on the
 fly. E.g.: `$boot:///somemodule.gz`.
+
+## Macros
+
+Macros are strings that can be arbitrarily assigned to represent other strings. For example:
+```
+${MY_MACRO}=Some text
+```
+
+Now, whenever `${MY_MACRO}` is used in the config file (except for an assignment as above), it will
+be replaced by the text `Some text`. For example:
+```
+CMDLINE=something before ${MY_MACRO} something after
+```
+
+Macros must always be placed inside `${...}` where `...` is the arbitrary macro name.
diff --git a/stage23/lib/config.c b/stage23/lib/config.c
index 3ae11a58..24526d86 100644
--- a/stage23/lib/config.c
+++ b/stage23/lib/config.c
@@ -138,6 +138,14 @@ static struct menu_entry *create_menu_tree(struct menu_entry *parent,
 
 struct menu_entry *menu_tree = NULL;
 
+struct macro {
+    char name[1024];
+    char value[2048];
+    struct macro *next;
+};
+
+static struct macro *macros = NULL;
+
 int init_config(size_t config_size) {
     // remove windows carriage returns, if any
     for (size_t i = 0; i < config_size; i++) {
@@ -148,6 +156,105 @@ int init_config(size_t config_size) {
         }
     }
 
+    // Load macros
+    for (size_t i = 0; i < config_size;) {
+        if ((config_size - i >= 3 && memcmp(config_addr + i, "\n${", 3) == 0)
+         || (config_size - i >= 2 && i == 0 && memcmp(config_addr, "${", 2) == 0)) {
+            struct macro *macro = ext_mem_alloc(sizeof(struct macro));
+
+            i += i ? 3 : 2;
+            size_t j;
+            for (j = 0; config_addr[i] != '}' && config_addr[i] != '\n' && config_addr[i] != 0; j++, i++) {
+                macro->name[j] = config_addr[i];
+            }
+
+            if (config_addr[i] == '\n' || config_addr[i] == 0 || config_addr[i+1] != '=') {
+                bad_config = true;
+                panic(true, "config: Malformed macro definition");
+            }
+            i += 2;
+
+            macro->name[j] = 0;
+
+            for (j = 0; config_addr[i] != '\n' && config_addr[i] != 0; j++, i++) {
+                macro->value[j] = config_addr[i];
+            }
+            macro->value[j] = 0;
+
+            macro->next = macros;
+            macros = macro;
+
+            continue;
+        }
+
+        i++;
+    }
+
+    // Expand macros
+    if (macros != NULL) {
+        char *new_config = ext_mem_alloc(config_size * 4);
+
+        size_t i, in;
+        for (i = 0, in = 0; i < config_size;) {
+            if ((config_size - i >= 3 && memcmp(config_addr + i, "\n${", 3) == 0)
+             || (config_size - i >= 2 && i == 0 && memcmp(config_addr, "${", 2) == 0)) {
+                i += i ? 3 : 2;
+                while (config_addr[i] != '\n' && config_addr[i] != 0) {
+                    i++;
+                }
+                continue;
+            }
+
+            if (config_size - i >= 2 && memcmp(config_addr + i, "${", 2) == 0) {
+                char *macro_name = ext_mem_alloc(1024);
+                i += 2;
+                size_t j;
+                for (j = 0; config_addr[i] != '}' && config_addr[i] != '\n' && config_addr[i] != 0; j++, i++) {
+                    macro_name[j] = config_addr[i];
+                }
+                if (config_addr[i] != '}') {
+                    bad_config = true;
+                    panic(true, "config: Malformed macro usage");
+                }
+                i++;
+                macro_name[j] = 0;
+                char *macro_value = "";
+                struct macro *macro = macros;
+                for (;;) {
+                    if (macro == NULL) {
+                        break;
+                    }
+                    if (strcmp(macro->name, macro_name) == 0) {
+                        macro_value = macro->value;
+                        break;
+                    }
+                    macro = macro->next;
+                }
+                pmm_free(macro_name, 1024);
+                for (j = 0; macro_value[j] != 0; j++, in++) {
+                    new_config[in] = macro_value[j];
+                }
+                continue;
+            }
+
+            new_config[in++] = config_addr[i++];
+        }
+
+        config_addr = new_config;
+        config_size = in;
+
+        // Free macros
+        struct macro *macro = macros;
+        for (;;) {
+            if (macro == NULL) {
+                break;
+            }
+            struct macro *next = macro->next;
+            pmm_free(macro, sizeof(struct macro));
+            macro = next;
+        }
+    }
+
     config_ready = true;
 
     menu_tree = create_menu_tree(NULL, 1, 0);
tab: 248 wrap: offon