git/list[1] front-page[2] threads[3] people[4] search[5] about
 

[PATCH] Allow config files to be included

From
Alex Riesen <raa.lkml@gmail.com>
Date
Feb 16, 2007, 14:42 UTC
Message-ID
<81b0412b0702160642h69b632f0w6c1decc4ec04c24a@mail.gmail.com>
In-Reply-To
<20070216143952.GA2478@steel.home>
The syntax is:
    [include "filename"]
which is somewhat branch/remote-alike. There are a few differences, though:
filenames happen to be long, so a backslash is supported to split the
names into multiple lines. No bare LF allowed, so this is illegal:
    [include "path/
    name"]
On the other hand, this is allowed:
    [include "path/\
    name"]

Backslash is just to quote characters (as in shell). Only one quoted string allowed, so this is bad too:

    [include "path/" "name"]
Signed-off-by: Alex Riesen <raa.lkml@gmail.com>
---

This is a resend, I have no idea what happened to original, but it never appeared on vger. And this will probably horribly garbled by gmail. Will see.

Alex Riesen, Thu, Feb 15, 2007 12:35:57 +0100:
> I suggest to ignore /etc/gitconfig completely if ~/.gitconfig exists,
> but allow inclusion of /etc/gitconfig from ~/.gitconfig (there are
> very singular and preciuos exceptions).
 config.c |  103 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
 1 files changed, 100 insertions(+), 3 deletions(-)
diff --git a/config.c b/config.c
index d821071..b42a7ea 100644
--- a/config.c
+++ b/config.c
@@ -12,6 +12,57 @@
 static FILE *config_file;
 static const char *config_file_name;
 static int config_linenr;
+
+struct fileinfo
+{
+       char *name;
+       int linenr;
+       FILE *file;
+       struct fileinfo *prev;
+};
+static struct fileinfo *config_stack = NULL;
+
+static void include_file(const char *filename)
+{
+       struct fileinfo *prev;
+       FILE *file;
+       file = fopen(filename, "r");
+       if (!file) {
+               error("ignored \"%s\": %s", filename, strerror(errno));
+               return;
+       }
+       prev = malloc(sizeof(*prev));
+       prev->name = (char *)config_file_name;
+       prev->linenr = config_linenr;
+       prev->file = config_file;
+       prev->prev = config_stack;
+       config_stack = prev;
+
+       config_file = file;
+       config_file_name = xstrdup(filename);
+       config_linenr = 0;
+}
+
+static FILE *pop_file(void)
+{
+       struct fileinfo *prev;
+
+       if (!config_stack)
+               /* The last file on stack does not belong to us.
+                * Free the names and close all included files. */
+               return NULL;
+
+       free((void*)config_file_name);
+       fclose(config_file);
+       config_file = config_stack->file;
+       config_file_name = config_stack->name;
+       config_linenr = 0;
+       prev = config_stack->prev;
+       free(config_stack);
+       config_stack = prev;
+       return config_file;
+}
+
 static int get_next_char(void)
 {
        int c;
@@ -31,13 +82,51 @@ static int get_next_char(void)
                if (c == '\n')
                        config_linenr++;
                if (c == EOF) {
-                       config_file = NULL;
+                       config_file = pop_file();
                        c = '\n';
                }
        }
        return c;
 }

+static int parse_include(void)
+{
+       char name[PATH_MAX];
+       int quote = 0, len = 0;
+
+       for (;;) {
+               int c = get_next_char();
+               if (len >= sizeof(name))
+                       return -1;
+               if (c == '"') {
+                       quote++;
+                       continue;
+               }
+               if (c == '\n')
+                       /* do not allow bare \n anywhere in path */
+                       return -1;
+               if (quote == 1) {
+                       if (c == '\\') {
+                               c = get_next_char();
+                               if (c == '\n')
+                                       continue;
+                       }
+                       name[len++] = c;
+               }
+               if (quote == 2 && c == ']') {
+                       do
+                               c = get_next_char();
+                       while (c != '\n');
+                       break;
+               }
+               if ((quote < 1 || quote >= 2) && !isspace(c) )
+                       return -1;
+       }
+       name[len] = '\0';
+       include_file(name);
+       return 0;
+}
+
 static char *parse_value(void)
 {
        static char value[1024];
@@ -181,8 +270,13 @@ static int get_base_var(char *name)
                int c = get_next_char();
                if (c == EOF)
                        return -1;
+               if (!isalpha(c) && !strncmp(name, "include", baselen) &&
+                   config_file) {
+                       ungetc(c, config_file);
+                       return parse_include();
+               }
                if (c == ']')
-                       return baselen;
+                       return baselen ? baselen: -1;
                if (isspace(c))
                        return get_extended_base_var(name, baselen, c);
                if (!iskeychar(c) && c != '.')
@@ -216,8 +310,11 @@ static int git_parse_file(config_fn_t fn)
                }
                if (c == '[') {
                        baselen = get_base_var(var);
-                       if (baselen <= 0)
+                       if (baselen < 0)
                                break;
+                       if (!baselen)
+                               /* [include "..."]*/
+                               continue;
                        var[baselen++] = '.';
                        var[baselen] = 0;
                        continue;
--
1.5.0.138.g36f81
Previous: Uwe Kleine-KönigNext: Alex Riesen
Message 29 of 30 in “/etc/gitconfig”
  1. Andy ParkinsFeb 14, 2007
  2. Peter BaumannFeb 14, 2007
  3. config: read system-wide defaults from /etc/gitconfigJohannes Schindelin, Feb 14, 2007
  4. Junio C HamanoFeb 14, 2007
  5. Johannes SchindelinFeb 14, 2007
  6. Junio C HamanoFeb 14, 2007
  7. Johannes SchindelinFeb 14, 2007
  8. Junio C HamanoFeb 14, 2007
  9. Nicolas PitreFeb 14, 2007
  10. Junio C HamanoFeb 14, 2007
  11. Andy ParkinsFeb 15, 2007
  12. Junio C HamanoFeb 15, 2007
  13. Han-Wen NienhuysFeb 14, 2007
  14. Junio C HamanoFeb 14, 2007
  15. Johannes SchindelinFeb 14, 2007
  16. Junio C HamanoFeb 14, 2007
  17. Johannes SchindelinFeb 14, 2007
  18. Johannes SchindelinFeb 14, 2007
  19. Junio C HamanoFeb 15, 2007
  20. Junio C HamanoFeb 15, 2007
  21. Eric WongFeb 15, 2007
  22. Eric WongFeb 15, 2007
  23. Junio C HamanoFeb 15, 2007
  24. Johannes SchindelinFeb 15, 2007
  25. Junio C HamanoFeb 15, 2007
  26. Johannes SchindelinFeb 15, 2007
  27. Jakub NarebskiFeb 19, 2007
  28. Uwe Kleine-KönigFeb 14, 2007
  29. Allow config files to be includedAlex Riesen, Feb 16, 2007
  30. Alex RiesenFeb 16, 2007

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.