519fecfee4cd7344b538528f7fa923b7fda280d2
   1
   2#include "cache.h"
   3
   4#define MAXNAME (256)
   5
   6static FILE *config_file;
   7static int config_linenr;
   8static int get_next_char(void)
   9{
  10        int c;
  11        FILE *f;
  12
  13        c = '\n';
  14        if ((f = config_file) != NULL) {
  15                c = fgetc(f);
  16                if (c == '\n')
  17                        config_linenr++;
  18                if (c == EOF) {
  19                        config_file = NULL;
  20                        c = '\n';
  21                }
  22        }
  23        return c;
  24}
  25
  26static char *parse_value(void)
  27{
  28        static char value[1024];
  29        int quote = 0, comment = 0, len = 0, space = 0;
  30
  31        for (;;) {
  32                int c = get_next_char();
  33                if (len >= sizeof(value))
  34                        return NULL;
  35                if (c == '\n') {
  36                        if (quote)
  37                                return NULL;
  38                        value[len] = 0;
  39                        return value;
  40                }
  41                if (comment)
  42                        continue;
  43                if (isspace(c) && !quote) {
  44                        space = 1;
  45                        continue;
  46                }
  47                if (space) {
  48                        if (len)
  49                                value[len++] = ' ';
  50                        space = 0;
  51                }
  52                if (c == '\\') {
  53                        c = get_next_char();
  54                        switch (c) {
  55                        case '\n':
  56                                continue;
  57                        case 't':
  58                                c = '\t';
  59                                break;
  60                        case 'b':
  61                                c = '\b';
  62                                break;
  63                        case 'n':
  64                                c = '\n';
  65                                break;
  66                        /* Some characters escape as themselves */
  67                        case '\\': case '"':
  68                                break;
  69                        /* Reject unknown escape sequences */
  70                        default:
  71                                return NULL;
  72                        }
  73                        value[len++] = c;
  74                        continue;
  75                }
  76                if (c == '"') {
  77                        quote = 1-quote;
  78                        continue;
  79                }
  80                if (!quote) {
  81                        if (c == ';' || c == '#') {
  82                                comment = 1;
  83                                continue;
  84                        }
  85                }
  86                value[len++] = c;
  87        }
  88}
  89
  90static int get_value(config_fn_t fn, char *name, unsigned int len)
  91{
  92        int c;
  93        char *value;
  94
  95        /* Get the full name */
  96        for (;;) {
  97                c = get_next_char();
  98                if (c == EOF)
  99                        break;
 100                if (!isalnum(c))
 101                        break;
 102                name[len++] = tolower(c);
 103                if (len >= MAXNAME)
 104                        return -1;
 105        }
 106        name[len] = 0;
 107        while (c == ' ' || c == '\t')
 108                c = get_next_char();
 109
 110        value = NULL;
 111        if (c != '\n') {
 112                if (c != '=')
 113                        return -1;
 114                value = parse_value();
 115                if (!value)
 116                        return -1;
 117        }
 118        return fn(name, value);
 119}
 120
 121static int get_base_var(char *name)
 122{
 123        int baselen = 0;
 124
 125        for (;;) {
 126                int c = get_next_char();
 127                if (c == EOF)
 128                        return -1;
 129                if (c == ']')
 130                        return baselen;
 131                if (!isalnum(c))
 132                        return -1;
 133                if (baselen > MAXNAME / 2)
 134                        return -1;
 135                name[baselen++] = tolower(c);
 136        }
 137}
 138
 139static int git_parse_file(config_fn_t fn)
 140{
 141        int comment = 0;
 142        int baselen = 0;
 143        static char var[MAXNAME];
 144
 145        for (;;) {
 146                int c = get_next_char();
 147                if (c == '\n') {
 148                        /* EOF? */
 149                        if (!config_file)
 150                                return 0;
 151                        comment = 0;
 152                        continue;
 153                }
 154                if (comment || isspace(c))
 155                        continue;
 156                if (c == '#' || c == ';') {
 157                        comment = 1;
 158                        continue;
 159                }
 160                if (c == '[') {
 161                        baselen = get_base_var(var);
 162                        if (baselen <= 0)
 163                                break;
 164                        var[baselen++] = '.';
 165                        var[baselen] = 0;
 166                        continue;
 167                }
 168                if (!isalpha(c))
 169                        break;
 170                var[baselen] = tolower(c);
 171                if (get_value(fn, var, baselen+1) < 0)
 172                        break;
 173        }
 174        die("bad config file line %d", config_linenr);
 175}
 176
 177int git_config_int(const char *name, const char *value)
 178{
 179        if (value && *value) {
 180                char *end;
 181                int val = strtol(value, &end, 0);
 182                if (!*end)
 183                        return val;
 184        }
 185        die("bad config value for '%s'", name);
 186}
 187
 188int git_config_bool(const char *name, const char *value)
 189{
 190        if (!value)
 191                return 1;
 192        if (!*value)
 193                return 0;
 194        if (!strcasecmp(value, "true"))
 195                return 1;
 196        if (!strcasecmp(value, "false"))
 197                return 0;
 198        return git_config_int(name, value) != 0;
 199}
 200
 201int git_default_config(const char *var, const char *value)
 202{
 203        /* This needs a better name */
 204        if (!strcmp(var, "core.filemode")) {
 205                trust_executable_bit = git_config_bool(var, value);
 206                return 0;
 207        }
 208
 209        if (!strcmp(var, "user.name")) {
 210                strncpy(git_default_name, value, sizeof(git_default_name));
 211                return 0;
 212        }
 213
 214        if (!strcmp(var, "user.email")) {
 215                strncpy(git_default_email, value, sizeof(git_default_email));
 216                return 0;
 217        }
 218
 219        /* Add other config variables here.. */
 220        return 0;
 221}
 222
 223int git_config(config_fn_t fn)
 224{
 225        int ret;
 226        FILE *f = fopen(git_path("config"), "r");
 227
 228        ret = -1;
 229        if (f) {
 230                config_file = f;
 231                config_linenr = 1;
 232                ret = git_parse_file(fn);
 233                fclose(f);
 234        }
 235        return ret;
 236}