Merge pull request #193 from carlosmn/config A couple of config improvements
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155
diff --git a/include/git2/config.h b/include/git2/config.h
index 3ebbe64..9ae54f1 100644
--- a/include/git2/config.h
+++ b/include/git2/config.h
@@ -51,7 +51,21 @@ GIT_EXTERN(int) git_config_new(git_config **out);
GIT_EXTERN(int) git_config_open_bare(git_config **cfg_out, const char *path);
/**
+ * Open the global configuration file at $HOME/.gitconfig
*
+ * @param cfg pointer to the configuration
+ */
+GIT_EXTERN(int) git_config_open_global(git_config **cfg);
+
+/**
+ * Add a config backend to an existing instance
+ *
+ * Note that the configuration will call the backend's ->free()
+ * function.
+ *
+ * @param cfg the configuration to add the backend to
+ * @param backend the backend to add
+ * @param priority the priority the backend should have
*/
GIT_EXTERN(int) git_config_add_backend(git_config *cfg, git_config_backend *backend, int priority);
diff --git a/src/config.c b/src/config.c
index cd0a73c..0ade5cf 100644
--- a/src/config.c
+++ b/src/config.c
@@ -70,6 +70,40 @@ int git_config_open_bare(git_config **out, const char *path)
return error;
}
+int git_config_open_global(git_config **out)
+{
+ char *home = NULL, *filename = NULL;
+ const char *gitconfig = ".gitconfig";
+ int filename_len, ret, error;
+
+ home = git__strdup(getenv("HOME"));
+ if (home == NULL)
+ return GIT_ENOMEM;
+
+ filename_len = strlen(home) + strlen(gitconfig) + 1;
+ filename = git__malloc(filename_len + 1);
+ if (filename == NULL) {
+ error = GIT_ENOMEM;
+ goto out;
+ }
+
+ ret = snprintf(filename, filename_len, "%s/%s", home, gitconfig);
+ if (ret < 0) {
+ error = git__throw(GIT_EOSERR, "Failed to build global filename. OS err: %s", strerror(errno));
+ goto out;
+ } else if (ret >= filename_len) {
+ error = git__throw(GIT_ERROR, "Failed to build global filename. Length calulation wrong");
+ goto out;
+ }
+
+ error = git_config_open_bare(out, filename);
+
+ out:
+ free(home);
+ free(filename);
+ return error;
+}
+
void git_config_free(git_config *cfg)
{
unsigned int i;
diff --git a/src/config_file.c b/src/config_file.c
index 75319a6..40829eb 100644
--- a/src/config_file.c
+++ b/src/config_file.c
@@ -197,36 +197,49 @@ static cvar_t *cvar_list_find(cvar_t_list *list, const char *name)
return NULL;
}
-static int cvar_name_normalize(const char *input, char **output)
+static int cvar_normalize_name(cvar_t *var, char **output)
{
- char *input_sp = strchr(input, ' ');
- char *quote, *str;
- int i;
+ char *section_sp = strchr(var->section, ' ');
+ char *quote, *name;
+ int len, ret;
- /* We need to make a copy anyway */
- str = git__strdup(input);
- if (str == NULL)
+ /*
+ * The final string is going to be at most one char longer than
+ * the input
+ */
+ len = strlen(var->section) + strlen(var->name) + 1;
+ name = git__malloc(len + 1);
+ if (name == NULL)
return GIT_ENOMEM;
- *output = str;
+ /* If there aren't any spaces in the section, it's easy */
+ if (section_sp == NULL) {
+ ret = snprintf(name, len + 1, "%s.%s", var->section, var->name);
+ if (ret < 0)
+ return git__throw(GIT_EOSERR, "Failed to normalize name. OS err: %s", strerror(errno));
- /* If there aren't any spaces, we don't need to do anything */
- if (input_sp == NULL)
+ *output = name;
return GIT_SUCCESS;
+ }
/*
- * If there are spaces, we replace the space by a dot, move the
- * variable name so that the dot before it replaces the last
- * quotation mark and repeat so that the first quotation mark
- * disappears.
+ * If there are spaces, we replace the space by a dot, move
+ * section name so it overwrites the first quotation mark and
+ * replace the last quotation mark by a dot. We then append the
+ * variable name.
*/
- str[input_sp - input] = '.';
-
- for (i = 0; i < 2; ++i) {
- quote = strrchr(str, '"');
- memmove(quote, quote + 1, strlen(quote));
- }
-
+ strcpy(name, var->section);
+ section_sp = strchr(name, ' ');
+ *section_sp = '.';
+ /* Remove first quote */
+ quote = strchr(name, '"');
+ memmove(quote, quote+1, strlen(quote+1));
+ /* Remove second quote */
+ quote = strchr(name, '"');
+ *quote = '.';
+ strcpy(quote+1, var->name);
+
+ *output = name;
return GIT_SUCCESS;
}
@@ -276,7 +289,7 @@ static int file_foreach(git_config_backend *backend, int (*fn)(const char *, voi
file_backend *b = (file_backend *)backend;
CVAR_LIST_FOREACH(&b->var_list, var) {
- ret = cvar_name_normalize(var->name, &normalized);
+ ret = cvar_normalize_name(var, &normalized);
if (ret < GIT_SUCCESS)
return ret;