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