diff options
-rw-r--r-- | Documentation/git-repo-config.txt | 12 | ||||
-rw-r--r-- | blame.c | 4 | ||||
-rw-r--r-- | builtin-read-tree.c | 3 | ||||
-rw-r--r-- | config.c | 43 | ||||
-rw-r--r-- | diff-delta.c | 3 | ||||
-rw-r--r-- | diff-lib.c | 41 | ||||
-rw-r--r-- | diff.c | 79 | ||||
-rw-r--r-- | diff.h | 3 | ||||
-rwxr-xr-x | gitweb/gitweb.cgi | 149 | ||||
-rw-r--r-- | gitweb/gitweb.css | 230 | ||||
-rw-r--r-- | http-fetch.c | 13 | ||||
-rw-r--r-- | http-push.c | 13 | ||||
-rw-r--r-- | imap-send.c | 2 | ||||
-rw-r--r-- | pager.c | 2 | ||||
-rw-r--r-- | quote.c | 9 | ||||
-rw-r--r-- | repo-config.c | 39 | ||||
-rw-r--r-- | t/Makefile | 2 | ||||
-rwxr-xr-x | t/t1300-repo-config.sh | 24 |
18 files changed, 548 insertions, 123 deletions
diff --git a/Documentation/git-repo-config.txt b/Documentation/git-repo-config.txt index d5142e0dc..803c0d5ca 100644 --- a/Documentation/git-repo-config.txt +++ b/Documentation/git-repo-config.txt @@ -73,6 +73,18 @@ OPTIONS List all variables set in .git/config. +ENVIRONMENT +----------- + +GIT_CONFIG:: + Take the configuration from the given file instead of .git/config. + +GIT_CONFIG_LOCAL:: + Currently the same as $GIT_CONFIG; when Git will support global + configuration files, this will cause it to take the configuration + from the global configuration file in addition to the given file. + + EXAMPLE ------- @@ -301,9 +301,9 @@ static void fill_line_map(struct commit *commit, struct commit *other, if (DEBUG) printf("map: i1: %d %d %p i2: %d %d %p\n", i1, map[i1], - i1 != -1 ? blame_lines[map[i1]] : NULL, + (void *) (i1 != -1 ? blame_lines[map[i1]] : NULL), i2, map2[i2], - i2 != -1 ? blame_lines[map2[i2]] : NULL); + (void *) (i2 != -1 ? blame_lines[map2[i2]] : NULL)); if (map2[i2] != -1 && blame_lines[map[i1]] && !blame_lines[map2[i2]]) diff --git a/builtin-read-tree.c b/builtin-read-tree.c index 04506da89..9a2099d73 100644 --- a/builtin-read-tree.c +++ b/builtin-read-tree.c @@ -31,8 +31,7 @@ static int merge_size = 0; static struct object_list *trees = NULL; -static struct cache_entry df_conflict_entry = { -}; +static struct cache_entry df_conflict_entry; struct tree_entry_list { struct tree_entry_list *next; @@ -317,7 +317,33 @@ int git_config_from_file(config_fn_t fn, const char *filename) int git_config(config_fn_t fn) { - return git_config_from_file(fn, git_path("config")); + int ret = 0; + char *repo_config = NULL; + const char *home = NULL, *filename; + + /* $GIT_CONFIG makes git read _only_ the given config file, + * $GIT_CONFIG_LOCAL will make it process it in addition to the + * global config file, the same way it would the per-repository + * config file otherwise. */ + filename = getenv("GIT_CONFIG"); + if (!filename) { + home = getenv("HOME"); + filename = getenv("GIT_CONFIG_LOCAL"); + if (!filename) + filename = repo_config = strdup(git_path("config")); + } + + if (home) { + char *user_config = strdup(mkpath("%s/.gitconfig", home)); + if (access(user_config, R_OK) > 0) + ret = git_config_from_file(fn, user_config); + free(user_config); + } + + ret += git_config_from_file(fn, filename); + if (repo_config) + free(repo_config); + return ret; } /* @@ -490,10 +516,19 @@ int git_config_set_multivar(const char* key, const char* value, int i, dot; int fd = -1, in_fd; int ret; - char* config_filename = strdup(git_path("config")); - char* lock_file = strdup(git_path("config.lock")); + char* config_filename; + char* lock_file; const char* last_dot = strrchr(key, '.'); + config_filename = getenv("GIT_CONFIG"); + if (!config_filename) { + config_filename = getenv("GIT_CONFIG_LOCAL"); + if (!config_filename) + config_filename = git_path("config"); + } + config_filename = strdup(config_filename); + lock_file = strdup(mkpath("%s.lock", config_filename)); + /* * Since "key" actually contains the section name and the real * key name separated by a dot, we have to know where the dot is. @@ -600,7 +635,7 @@ int git_config_set_multivar(const char* key, const char* value, * As a side effect, we make sure to transform only a valid * existing config file. */ - if (git_config(store_aux)) { + if (git_config_from_file(store_aux, config_filename)) { fprintf(stderr, "invalid config file\n"); free(store.key); if (store.value_regex != NULL) { diff --git a/diff-delta.c b/diff-delta.c index 25a798d05..74486b1b8 100644 --- a/diff-delta.c +++ b/diff-delta.c @@ -22,6 +22,7 @@ #include <string.h> #include "delta.h" +#include "git-compat-util.h" /* maximum hash entry list for the same hash bucket */ #define HASH_LIMIT 64 @@ -131,7 +132,7 @@ struct delta_index { const void *src_buf; unsigned long src_size; unsigned int hash_mask; - struct index_entry *hash[0]; + struct index_entry *hash[FLEX_ARRAY]; }; struct delta_index * create_delta_index(const void *buf, unsigned long bufsize) diff --git a/diff-lib.c b/diff-lib.c index 2183b41b0..fdc11732d 100644 --- a/diff-lib.c +++ b/diff-lib.c @@ -34,21 +34,23 @@ int run_diff_files(struct rev_info *revs, int silent_on_removed) continue; if (ce_stage(ce)) { - struct { - struct combine_diff_path p; - struct combine_diff_parent filler[5]; - } combine; + struct combine_diff_path *dpath; int num_compare_stages = 0; + size_t path_len; - combine.p.next = NULL; - combine.p.len = ce_namelen(ce); - combine.p.path = xmalloc(combine.p.len + 1); - memcpy(combine.p.path, ce->name, combine.p.len); - combine.p.path[combine.p.len] = 0; - combine.p.mode = 0; - memset(combine.p.sha1, 0, 20); - memset(&combine.p.parent[0], 0, - sizeof(combine.filler)); + path_len = ce_namelen(ce); + + dpath = xmalloc (combine_diff_path_size (5, path_len)); + dpath->path = (char *) &(dpath->parent[5]); + + dpath->next = NULL; + dpath->len = path_len; + memcpy(dpath->path, ce->name, path_len); + dpath->path[path_len] = '\0'; + dpath->mode = 0; + memset(dpath->sha1, 0, 20); + memset(&(dpath->parent[0]), 0, + sizeof(struct combine_diff_parent)*5); while (i < entries) { struct cache_entry *nce = active_cache[i]; @@ -64,11 +66,11 @@ int run_diff_files(struct rev_info *revs, int silent_on_removed) if (2 <= stage) { int mode = ntohl(nce->ce_mode); num_compare_stages++; - memcpy(combine.p.parent[stage-2].sha1, + memcpy(dpath->parent[stage-2].sha1, nce->sha1, 20); - combine.p.parent[stage-2].mode = + dpath->parent[stage-2].mode = canon_mode(mode); - combine.p.parent[stage-2].status = + dpath->parent[stage-2].status = DIFF_STATUS_MODIFIED; } @@ -83,13 +85,14 @@ int run_diff_files(struct rev_info *revs, int silent_on_removed) i--; if (revs->combine_merges && num_compare_stages == 2) { - show_combined_diff(&combine.p, 2, + show_combined_diff(dpath, 2, revs->dense_combined_merges, revs); - free(combine.p.path); + free(dpath); continue; } - free(combine.p.path); + free(dpath); + dpath = NULL; /* * Show the diff for the 'ce' if we found the one @@ -25,6 +25,20 @@ int git_diff_config(const char *var, const char *value) return git_default_config(var, value); } +enum color_diff { + DIFF_PLAIN = 0, + DIFF_METAINFO = 1, + DIFF_FILE_OLD = 2, + DIFF_FILE_NEW = 3, +}; + +static const char *diff_colors[] = { + "\033[0;0m", + "\033[1;35m", + "\033[1;31m", + "\033[1;34m", +}; + static char *quote_one(const char *str) { int needlen; @@ -177,23 +191,54 @@ static int fill_mmfile(mmfile_t *mf, struct diff_filespec *one) } struct emit_callback { + struct xdiff_emit_state xm; + int nparents, color_diff; const char **label_path; }; -static int fn_out(void *priv, mmbuffer_t *mb, int nbuf) +static inline void color_diff(int diff_use_color, enum color_diff ix) +{ + if (diff_use_color) + fputs(diff_colors[ix], stdout); +} + +static void fn_out_consume(void *priv, char *line, unsigned long len) { int i; struct emit_callback *ecbdata = priv; if (ecbdata->label_path[0]) { + color_diff(ecbdata->color_diff, DIFF_METAINFO); printf("--- %s\n", ecbdata->label_path[0]); + color_diff(ecbdata->color_diff, DIFF_METAINFO); printf("+++ %s\n", ecbdata->label_path[1]); ecbdata->label_path[0] = ecbdata->label_path[1] = NULL; } - for (i = 0; i < nbuf; i++) - if (!fwrite(mb[i].ptr, mb[i].size, 1, stdout)) - return -1; - return 0; + + /* This is not really necessary for now because + * this codepath only deals with two-way diffs. + */ + for (i = 0; i < len && line[i] == '@'; i++) + ; + if (2 <= i && i < len && line[i] == ' ') { + ecbdata->nparents = i - 1; + color_diff(ecbdata->color_diff, DIFF_METAINFO); + } + else if (len < ecbdata->nparents) + color_diff(ecbdata->color_diff, DIFF_PLAIN); + else { + int nparents = ecbdata->nparents; + int color = DIFF_PLAIN; + for (i = 0; i < nparents && len; i++) { + if (line[i] == '-') + color = DIFF_FILE_OLD; + else if (line[i] == '+') + color = DIFF_FILE_NEW; + } + color_diff(ecbdata->color_diff, color); + } + fwrite(line, len, 1, stdout); + color_diff(ecbdata->color_diff, DIFF_PLAIN); } static char *pprint_rename(const char *a, const char *b) @@ -549,25 +594,35 @@ static void builtin_diff(const char *name_a, b_two = quote_two("b/", name_b); lbl[0] = DIFF_FILE_VALID(one) ? a_one : "/dev/null"; lbl[1] = DIFF_FILE_VALID(two) ? b_two : "/dev/null"; + color_diff(o->color_diff, DIFF_METAINFO); printf("diff --git %s %s\n", a_one, b_two); if (lbl[0][0] == '/') { /* /dev/null */ + color_diff(o->color_diff, DIFF_METAINFO); printf("new file mode %06o\n", two->mode); - if (xfrm_msg && xfrm_msg[0]) + if (xfrm_msg && xfrm_msg[0]) { + color_diff(o->color_diff, DIFF_METAINFO); puts(xfrm_msg); + } } else if (lbl[1][0] == '/') { printf("deleted file mode %06o\n", one->mode); - if (xfrm_msg && xfrm_msg[0]) + if (xfrm_msg && xfrm_msg[0]) { + color_diff(o->color_diff, DIFF_METAINFO); puts(xfrm_msg); + } } else { if (one->mode != two->mode) { + color_diff(o->color_diff, DIFF_METAINFO); printf("old mode %06o\n", one->mode); + color_diff(o->color_diff, DIFF_METAINFO); printf("new mode %06o\n", two->mode); } - if (xfrm_msg && xfrm_msg[0]) + if (xfrm_msg && xfrm_msg[0]) { + color_diff(o->color_diff, DIFF_METAINFO); puts(xfrm_msg); + } /* * we do not run diff between different kind * of objects. @@ -575,6 +630,7 @@ static void builtin_diff(const char *name_a, if ((one->mode ^ two->mode) & S_IFMT) goto free_ab_and_return; if (complete_rewrite) { + color_diff(o->color_diff, DIFF_PLAIN); emit_rewrite_diff(name_a, name_b, one, two); goto free_ab_and_return; } @@ -602,7 +658,9 @@ static void builtin_diff(const char *name_a, xdemitcb_t ecb; struct emit_callback ecbdata; + memset(&ecbdata, 0, sizeof(ecbdata)); ecbdata.label_path = lbl; + ecbdata.color_diff = o->color_diff; xpp.flags = XDF_NEED_MINIMAL; xecfg.ctxlen = o->context; xecfg.flags = XDL_EMIT_FUNCNAMES; @@ -612,8 +670,9 @@ static void builtin_diff(const char *name_a, xecfg.ctxlen = strtoul(diffopts + 10, NULL, 10); else if (!strncmp(diffopts, "-u", 2)) xecfg.ctxlen = strtoul(diffopts + 2, NULL, 10); - ecb.outf = fn_out; + ecb.outf = xdiff_outf; ecb.priv = &ecbdata; + ecbdata.xm.consume = fn_out_consume; xdl_diff(&mf1, &mf2, &xpp, &xecfg, &ecb); } @@ -1456,6 +1515,8 @@ int diff_opt_parse(struct diff_options *options, const char **av, int ac) else if (40 < options->abbrev) options->abbrev = 40; } + else if (!strcmp(arg, "--color")) + options->color_diff = 1; else return 0; return 1; @@ -32,7 +32,8 @@ struct diff_options { full_index:1, silent_on_remove:1, find_copies_harder:1, - summary:1; + summary:1, + color_diff:1; int context; int break_opt; int detect_rename; diff --git a/gitweb/gitweb.cgi b/gitweb/gitweb.cgi index 5eabe06da..fa90c51a4 100755 --- a/gitweb/gitweb.cgi +++ b/gitweb/gitweb.cgi @@ -38,10 +38,22 @@ my $home_link = $my_uri; # html text to include at home page my $home_text = "indextext.html"; +# URI of default stylesheet +my $stylesheet = "gitweb.css"; + # source of projects list #my $projects_list = $projectroot; my $projects_list = "index/index.aux"; +# default blob_plain mimetype and default charset for text/plain blob +my $default_blob_plain_mimetype = 'text/plain'; +my $default_text_plain_charset = undef; + +# file to use for guessing MIME types before trying /etc/mime.types +# (relative to the current git repository) +my $mimetypes_file = undef; + + # input validation and dispatch my $action = $cgi->param('a'); if (defined $action) { @@ -260,68 +272,9 @@ sub git_header_html { <head> <meta http-equiv="content-type" content="text/html; charset=utf-8"/> <meta name="robots" content="index, nofollow"/> +<link rel="stylesheet" href="$stylesheet"/> <title>$title</title> $rss_link -<style type="text/css"> -body { - font-family: sans-serif; font-size: 12px; border:solid #d9d8d1; border-width:1px; - margin:10px; background-color:#ffffff; color:#000000; -} -a { color:#0000cc; } -a:hover, a:visited, a:active { color:#880000; } -div.page_header { height:25px; padding:8px; font-size:18px; font-weight:bold; background-color:#d9d8d1; } -div.page_header a:visited, a.header { color:#0000cc; } -div.page_header a:hover { color:#880000; } -div.page_nav { padding:8px; } -div.page_nav a:visited { color:#0000cc; } -div.page_path { padding:8px; border:solid #d9d8d1; border-width:0px 0px 1px} -div.page_footer { height:17px; padding:4px 8px; background-color: #d9d8d1; } -div.page_footer_text { float:left; color:#555555; font-style:italic; } -div.page_body { padding:8px; } -div.title, a.title { - display:block; padding:6px 8px; - font-weight:bold; background-color:#edece6; text-decoration:none; color:#000000; -} -a.title:hover { background-color: #d9d8d1; } -div.title_text { padding:6px 0px; border: solid #d9d8d1; border-width:0px 0px 1px; } -div.log_body { padding:8px 8px 8px 150px; } -span.age { position:relative; float:left; width:142px; font-style:italic; } -div.log_link { - padding:0px 8px; - font-size:10px; font-family:sans-serif; font-style:normal; - position:relative; float:left; width:136px; -} -div.list_head { padding:6px 8px 4px; border:solid #d9d8d1; border-width:1px 0px 0px; font-style:italic; } -a.list { text-decoration:none; color:#000000; } -a.list:hover { text-decoration:underline; color:#880000; } -a.text { text-decoration:none; color:#0000cc; } -a.text:visited { text-decoration:none; color:#880000; } -a.text:hover { text-decoration:underline; color:#880000; } -table { padding:8px 4px; } -th { padding:2px 5px; font-size:12px; text-align:left; } -tr.light:hover { background-color:#edece6; } -tr.dark { background-color:#f6f6f0; } -tr.dark:hover { background-color:#edece6; } -td { padding:2px 5px; font-size:12px; vertical-align:top; } -td.link { padding:2px 5px; font-family:sans-serif; font-size:10px; } -div.pre { font-family:monospace; font-size:12px; white-space:pre; } -div.diff_info { font-family:monospace; color:#000099; background-color:#edece6; font-style:italic; } -div.index_include { border:solid #d9d8d1; border-width:0px 0px 1px; padding:12px 8px; } -div.search { margin:4px 8px; position:absolute; top:56px; right:12px } -a.linenr { color:#999999; text-decoration:none } -a.rss_logo { - float:right; padding:3px 0px; width:35px; line-height:10px; - border:1px solid; border-color:#fcc7a5 #7d3302 #3e1a01 #ff954e; - color:#ffffff; background-color:#ff6600; - font-weight:bold; font-family:sans-serif; font-size:10px; - text-align:center; text-decoration:none; -} -a.rss_logo:hover { background-color:#ee5500; } -span.tag { - padding:0px 4px; font-size:10px; font-weight:normal; - background-color:#ffffaa; border:1px solid; border-color:#ffffcc #ffee00 #ffee00 #ffffcc; -} -</style> </head> <body> EOF @@ -1538,15 +1491,85 @@ sub git_blob { git_footer_html(); } +sub mimetype_guess_file { + my $filename = shift; + my $mimemap = shift; + -r $mimemap or return undef; + + my %mimemap; + open(MIME, $mimemap) or return undef; + while (<MIME>) { + my ($mime, $exts) = split(/\t+/); + my @exts = split(/\s+/, $exts); + foreach my $ext (@exts) { + $mimemap{$ext} = $mime; + } + } + close(MIME); + + $filename =~ /\.(.*?)$/; + return $mimemap{$1}; +} + +sub mimetype_guess { + my $filename = shift; + my $mime; + $filename =~ /\./ or return undef; + + if ($mimetypes_file) { + my $file = $mimetypes_file; + $file =~ m#^/# or $file = "$projectroot/$path/$file"; + $mime = mimetype_guess_file($filename, $file); + } + $mime ||= mimetype_guess_file($filename, '/etc/mime.types'); + return $mime; +} + +sub git_blob_plain_mimetype { + my $fd = shift; + my $filename = shift; + + # just in case + return $default_blob_plain_mimetype unless $fd; + + if ($filename) { + my $mime = mimetype_guess($filename); + $mime and return $mime; + } + + if (-T $fd) { + return 'text/plain' . + ($default_text_plain_charset ? '; charset='.$default_text_plain_charset : ''); + } elsif (! $filename) { + return 'application/octet-stream'; + } elsif ($filename =~ m/\.png$/i) { + return 'image/png'; + } elsif ($filename =~ m/\.gif$/i) { + return 'image/gif'; + } elsif ($filename =~ m/\.jpe?g$/i) { + return 'image/jpeg'; + } else { + return 'application/octet-stream'; + } +} + sub git_blob_plain { - my $save_as = "$hash.txt"; + open my $fd, "-|", "$gitbin/git-cat-file blob $hash" or return; + my $type = git_blob_plain_mimetype($fd, $file_name); + + # save as filename, even when no $file_name is given + my $save_as = "$hash"; if (defined $file_name) { $save_as = $file_name; + } elsif ($type =~ m/^text\//) { + $save_as .= '.txt'; } - print $cgi->header(-type => "text/plain", -charset => 'utf-8', '-content-disposition' => "inline; filename=\"$save_as\""); - open my $fd, "-|", "$gitbin/git-cat-file blob $hash" or return; + + print $cgi->header(-type => "$type", '-content-disposition' => "inline; filename=\"$save_as\""); undef $/; + binmode STDOUT, ':raw'; print <$fd>; + binmode STDOUT, ':utf8'; # as set at the beginning of gitweb.cgi $/ = "\n"; close $fd; } diff --git a/gitweb/gitweb.css b/gitweb/gitweb.css new file mode 100644 index 000000000..4378067d3 --- /dev/null +++ b/gitweb/gitweb.css @@ -0,0 +1,230 @@ +body { + font-family: sans-serif; + font-size: 12px; + border:solid #d9d8d1; + border-width: 1px; + margin: 10px; + background-color: #ffffff; + color: #000000; +} + +a { + color: #0000cc; +} + +a:hover, a:visited, a:active { + color: #880000; +} + +div.page_header { + height: 25px; + padding: 8px; + font-size: 18px; + font-weight: bold; + background-color: #d9d8d1; +} + +div.page_header a:visited, a.header { + color: #0000cc; +} + +div.page_header a:hover { + color: #880000; +} + +div.page_nav { + padding:8px; +} + +div.page_nav a:visited { + color: #0000cc; +} + +div.page_path { + padding: 8px; + border: solid #d9d8d1; + border-width: 0px 0px 1px; +} + +div.page_footer { + height: 17px; + padding: 4px 8px; + background-color: #d9d8d1; +} + +div.page_footer_text { + float: left; + color: #555555; + font-style: italic; +} + +div.page_body { + padding: 8px; +} + +div.title, a.title { + display: block; + padding: 6px 8px; + font-weight: bold; + background-color: #edece6; + text-decoration: none; + color: #000000; +} + +a.title:hover { + background-color: #d9d8d1; +} + +div.title_text { + padding: 6px 0px; + border: solid #d9d8d1; + border-width: 0px 0px 1px; +} + +div.log_body { + padding: 8px 8px 8px 150px; +} + +span.age { + position: relative; + float: left; + width: 142px; + font-style:italic; +} + +div.log_link { + padding: 0px 8px; + font-size: 10px; + font-family: sans-serif; + font-style:normal; + position: relative; + float: left; + width: 136px; +} + +div.list_head { + padding: 6px 8px 4px; + border: solid #d9d8d1; + border-width: 1px 0px 0px; + font-style: italic; +} + +a.list { + text-decoration: none; + color: #000000; +} + +a.list:hover { + text-decoration: underline; + color: #880000; +} + +a.text { + text-decoration: none; + color: #0000cc; +} + +a.text:visited { + text-decoration: none; + color: #880000; +} + +a.text:hover { + text-decoration: underline; + color: #880000; +} + +table { + padding: 8px 4px; +} + +th { + padding: 2px 5px; + font-size: 12px; + text-align: left; +} + +tr.light:hover { + background-color: #edece6; +} + +tr.dark { + background-color: #f6f6f0; +} + +tr.dark:hover { + background-color: #edece6; +} + + +td { + padding: 2px 5px; + font-size: 12px; + vertical-align:top; +} + +td.link { + padding: 2px 5px; + font-family: sans-serif; + font-size: 10px; +} + +div.pre { + font-family: monospace; + font-size: 12px; + white-space: pre; +} + +div.diff_info { + font-family: monospace; + color: #000099; + background-color: #edece6; + font-style: italic; +} + +div.index_include { + border: solid #d9d8d1; + border-width: 0px 0px 1px; + padding: 12px 8px; +} + +div.search { + margin: 4px 8px; + position: absolute; + top: 56px; + right: 12px +} + +a.linenr { + color: #999999; + text-decoration: none +} + +a.rss_logo { + float: right; + padding: 3px 0px; + width: 35px; + line-height: 10px; + border: 1px solid; + border-color: #fcc7a5 #7d3302 #3e1a01 #ff954e; + color: #ffffff; + background-color: #ff6600; + font-weight: bold; + font-family: sans-serif; + font-size: 10px; + text-align: center; + text-decoration: none; +} + +a.rss_logo:hover { + background-color: #ee5500; +} + +span.tag { + padding: 0px 4px; + font-size: 10px; + font-weight: normal; + background-color: #ffffaa; + border: 1px solid; + border-color: #ffffcc #ffee00 #ffee00 #ffffcc; +} diff --git a/http-fetch.c b/http-fetch.c index da1a7f541..3a2cb5e1f 100644 --- a/http-fetch.c +++ b/http-fetch.c @@ -1136,13 +1136,14 @@ int fetch(unsigned char *sha1) static inline int needs_quote(int ch) { - switch (ch) { - case '/': case '-': case '.': - case 'A'...'Z': case 'a'...'z': case '0'...'9': + if (((ch >= 'A') && (ch <= 'Z')) + || ((ch >= 'a') && (ch <= 'z')) + || ((ch >= '0') && (ch <= '9')) + || (ch == '/') + || (ch == '-') + || (ch == '.')) return 0; - default: - return 1; - } + return 1; } static inline int hex(int v) diff --git a/http-push.c b/http-push.c index ba64f8fff..aaf155c5b 100644 --- a/http-push.c +++ b/http-push.c @@ -1077,13 +1077,14 @@ static int fetch_indices(void) static inline int needs_quote(int ch) { - switch (ch) { - case '/': case '-': case '.': - case 'A'...'Z': case 'a'...'z': case '0'...'9': + if (((ch >= 'A') && (ch <= 'Z')) + || ((ch >= 'a') && (ch <= 'z')) + || ((ch >= '0') && (ch <= '9')) + || (ch == '/') + || (ch == '-') + || (ch == '.')) return 0; - default: - return 1; - } + return 1; } static inline int hex(int v) diff --git a/imap-send.c b/imap-send.c index 285ad29af..94e39cd94 100644 --- a/imap-send.c +++ b/imap-send.c @@ -93,7 +93,7 @@ typedef struct { char *data; int len; unsigned char flags; - unsigned char crlf:1; + unsigned int crlf:1; } msg_data_t; #define DRV_OK 0 @@ -46,7 +46,7 @@ void setup_pager(void) close(fd[0]); close(fd[1]); - setenv("LESS", "-S", 0); + setenv("LESS", "-RS", 0); run_pager(pager); die("unable to execute pager '%s'", pager); exit(255); @@ -206,7 +206,14 @@ char *unquote_c_style(const char *quoted, const char **endp) case '\\': case '"': break; /* verbatim */ - case '0'...'7': + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': /* octal */ ac = ((ch - '0') << 6); if ((ch = *sp++) < '0' || '7' < ch) diff --git a/repo-config.c b/repo-config.c index 08fc4cc57..03f108fe2 100644 --- a/repo-config.c +++ b/repo-config.c @@ -64,7 +64,22 @@ static int show_config(const char* key_, const char* value_) static int get_value(const char* key_, const char* regex_) { + int ret = -1; char *tl; + char *global = NULL, *repo_config = NULL; + const char *local; + + local = getenv("GIT_CONFIG"); + if (!local) { + const char *home = getenv("HOME"); + local = getenv("GIT_CONFIG_LOCAL"); + if (!local) + local = repo_config; + else + local = repo_config = strdup(git_path("config")); + if (home) + global = strdup(mkpath("%s/.gitconfig", home)); + } key = strdup(key_); for (tl=key+strlen(key)-1; tl >= key && *tl != '.'; --tl) @@ -76,7 +91,7 @@ static int get_value(const char* key_, const char* regex_) key_regexp = (regex_t*)malloc(sizeof(regex_t)); if (regcomp(key_regexp, key, REG_EXTENDED)) { fprintf(stderr, "Invalid key pattern: %s\n", key_); - return -1; + goto free_strings; } } @@ -89,11 +104,16 @@ static int get_value(const char* key_, const char* regex_) regexp = (regex_t*)malloc(sizeof(regex_t)); if (regcomp(regexp, regex_, REG_EXTENDED)) { fprintf(stderr, "Invalid pattern: %s\n", regex_); - return -1; + goto free_strings; } } - git_config(show_config); + if (do_all && global) + git_config_from_file(show_config, global); + git_config_from_file(show_config, local); + if (!do_all && !seen && global) + git_config_from_file(show_config, global); + free(key); if (regexp) { regfree(regexp); @@ -101,9 +121,16 @@ static int get_value(const char* key_, const char* regex_) } if (do_all) - return !seen; - - return (seen == 1) ? 0 : 1; + ret = !seen; + else + ret = (seen == 1) ? 0 : 1; + +free_strings: + if (repo_config) + free(repo_config); + if (global) + free(global); + return ret; } int main(int argc, const char **argv) diff --git a/t/Makefile b/t/Makefile index 549598575..632c55f6d 100644 --- a/t/Makefile +++ b/t/Makefile @@ -19,7 +19,7 @@ endif all: $(T) clean $(T): - @echo "*** $@ ***"; '$(SHELL_PATH_SQ)' $@ $(GIT_TEST_OPTS) + @echo "*** $@ ***"; GIT_CONFIG=.git/config '$(SHELL_PATH_SQ)' $@ $(GIT_TEST_OPTS) clean: rm -fr trash diff --git a/t/t1300-repo-config.sh b/t/t1300-repo-config.sh index 8260d57b6..0de249774 100755 --- a/t/t1300-repo-config.sh +++ b/t/t1300-repo-config.sh @@ -309,5 +309,29 @@ EOF test_expect_success 'new variable inserts into proper section' 'cmp .git/config expect' +cat > other-config << EOF +[ein] + bahn = strasse +EOF + +cat > expect << EOF +ein.bahn=strasse +EOF + +GIT_CONFIG=other-config git-repo-config -l > output + +test_expect_success 'alternative GIT_CONFIG' 'cmp output expect' + +GIT_CONFIG=other-config git-repo-config anwohner.park ausweis + +cat > expect << EOF +[ein] + bahn = strasse +[anwohner] + park = ausweis +EOF + +test_expect_success '--set in alternative GIT_CONFIG' 'cmp other-config expect' + test_done |