int dwim_ref(const char *str, int len, unsigned char *sha1, char **ref) { char *last_branch = substitute_branch_name(&str, &len); const char **p, *r; int refs_found = 0; *ref = NULL; for (p = ref_rev_parse_rules; *p; p++) { char fullref[PATH_MAX]; unsigned char sha1_from_ref[20]; unsigned char *this_result; int flag; this_result = refs_found ? sha1_from_ref : sha1; mksnpath(fullref, sizeof(fullref), *p, len, str); r = resolve_ref_unsafe(fullref, RESOLVE_REF_READING, this_result, &flag); if (r) { if (!refs_found++) *ref = xstrdup(r); if (!warn_ambiguous_refs) break; } else if ((flag & REF_ISSYMREF) && strcmp(fullref, "HEAD")) { warning("ignoring dangling symref %s.", fullref); } else if ((flag & REF_ISBROKEN) && strchr(fullref, '/')) { warning("ignoring broken ref %s.", fullref); } } free(last_branch); return refs_found; }
int dwim_log(const char *str, int len, unsigned char *sha1, char **log) { char *last_branch = substitute_branch_name(&str, &len); const char **p; int logs_found = 0; *log = NULL; for (p = ref_rev_parse_rules; *p; p++) { unsigned char hash[20]; char path[PATH_MAX]; const char *ref, *it; mksnpath(path, sizeof(path), *p, len, str); ref = resolve_ref_unsafe(path, RESOLVE_REF_READING, hash, NULL); if (!ref) continue; if (reflog_exists(path)) it = path; else if (strcmp(ref, path) && reflog_exists(ref)) it = ref; else continue; if (!logs_found++) { *log = xstrdup(it); hashcpy(sha1, hash); } if (!warn_ambiguous_refs) break; } free(last_branch); return logs_found; }
int git_config_early(config_fn_t fn, void *data, const char *repo_config) { int ret = 0, found = 0; const char *home = NULL; /* Setting $GIT_CONFIG makes git read _only_ the given config file. */ if (config_exclusive_filename) return git_config_from_file(fn, config_exclusive_filename, data); if (git_config_system() && !access(git_etc_gitconfig(), R_OK)) { ret += git_config_from_file(fn, git_etc_gitconfig(), data); found += 1; } home = getenv("HOME"); if (home) { char buf[PATH_MAX]; char *user_config = mksnpath(buf, sizeof(buf), "%s/.gitconfig", home); if (!access(user_config, R_OK)) { ret += git_config_from_file(fn, user_config, data); found += 1; } } if (repo_config && !access(repo_config, R_OK)) { ret += git_config_from_file(fn, repo_config, data); found += 1; } switch (git_config_from_parameters(fn, data)) { case -1: /* error */ die("unable to parse command-line config"); break; case 0: /* found nothing */ break; default: /* found at least one item */ found++; break; } return ret == 0 ? found : ret; }
char *shorten_unambiguous_ref(const char *ref, int strict) { int i; static char **scanf_fmts; static int nr_rules; char *short_name; /* pre generate scanf formats from ref_rev_parse_rules[] */ if (!nr_rules) { size_t total_len = 0; /* the rule list is NULL terminated, count them first */ for (; ref_rev_parse_rules[nr_rules]; nr_rules++) /* no +1 because strlen("%s") < strlen("%.*s") */ total_len += strlen(ref_rev_parse_rules[nr_rules]); scanf_fmts = xmalloc(nr_rules * sizeof(char *) + total_len); total_len = 0; for (i = 0; i < nr_rules; i++) { scanf_fmts[i] = (char *)&scanf_fmts[nr_rules] + total_len; gen_scanf_fmt(scanf_fmts[i], ref_rev_parse_rules[i]); total_len += strlen(ref_rev_parse_rules[i]); } } /* bail out if there are no rules */ if (!nr_rules) return xstrdup(ref); /* buffer for scanf result, at most ref must fit */ short_name = xstrdup(ref); /* skip first rule, it will always match */ for (i = nr_rules - 1; i > 0 ; --i) { int j; int rules_to_fail = i; int short_name_len; if (1 != sscanf(ref, scanf_fmts[i], short_name)) continue; short_name_len = strlen(short_name); /* * in strict mode, all (except the matched one) rules * must fail to resolve to a valid non-ambiguous ref */ if (strict) rules_to_fail = nr_rules; /* * check if the short name resolves to a valid ref, * but use only rules prior to the matched one */ for (j = 0; j < rules_to_fail; j++) { const char *rule = ref_rev_parse_rules[j]; unsigned char short_objectname[20]; char refname[PATH_MAX]; /* skip matched rule */ if (i == j) continue; /* * the short name is ambiguous, if it resolves * (with this previous rule) to a valid ref * read_ref() returns 0 on success */ mksnpath(refname, sizeof(refname), rule, short_name_len, short_name); if (!read_ref(refname, short_objectname)) break; } /* * short name is non-ambiguous if all previous rules * haven't resolved to a valid ref */ if (j == rules_to_fail) return short_name; } free(short_name); return xstrdup(ref); }
char *shorten_unambiguous_ref(const char *refname, int strict) { int i; static char **scanf_fmts; static int nr_rules; char *short_name; if (!nr_rules) { /* * Pre-generate scanf formats from ref_rev_parse_rules[]. * Generate a format suitable for scanf from a * ref_rev_parse_rules rule by interpolating "%s" at the * location of the "%.*s". */ size_t total_len = 0; size_t offset = 0; /* the rule list is NULL terminated, count them first */ for (nr_rules = 0; ref_rev_parse_rules[nr_rules]; nr_rules++) /* -2 for strlen("%.*s") - strlen("%s"); +1 for NUL */ total_len += strlen(ref_rev_parse_rules[nr_rules]) - 2 + 1; scanf_fmts = xmalloc(st_add(st_mult(sizeof(char *), nr_rules), total_len)); offset = 0; for (i = 0; i < nr_rules; i++) { assert(offset < total_len); scanf_fmts[i] = (char *)&scanf_fmts[nr_rules] + offset; offset += snprintf(scanf_fmts[i], total_len - offset, ref_rev_parse_rules[i], 2, "%s") + 1; } } /* bail out if there are no rules */ if (!nr_rules) return xstrdup(refname); /* buffer for scanf result, at most refname must fit */ short_name = xstrdup(refname); /* skip first rule, it will always match */ for (i = nr_rules - 1; i > 0 ; --i) { int j; int rules_to_fail = i; int short_name_len; if (1 != sscanf(refname, scanf_fmts[i], short_name)) continue; short_name_len = strlen(short_name); /* * in strict mode, all (except the matched one) rules * must fail to resolve to a valid non-ambiguous ref */ if (strict) rules_to_fail = nr_rules; /* * check if the short name resolves to a valid ref, * but use only rules prior to the matched one */ for (j = 0; j < rules_to_fail; j++) { const char *rule = ref_rev_parse_rules[j]; char refname[PATH_MAX]; /* skip matched rule */ if (i == j) continue; /* * the short name is ambiguous, if it resolves * (with this previous rule) to a valid ref * read_ref() returns 0 on success */ mksnpath(refname, sizeof(refname), rule, short_name_len, short_name); if (ref_exists(refname)) break; } /* * short name is non-ambiguous if all previous rules * haven't resolved to a valid ref */ if (j == rules_to_fail) return short_name; } free(short_name); return xstrdup(refname); }