Use the C99 bool type and not that of ncurses
[tig.git] / src / repo.c
blobfabea294f64d638c90beda2c2ca431c6195969e7
1 /* Copyright (c) 2006-2015 Jonas Fonseca <jonas.fonseca@gmail.com>
3 * This program is free software; you can redistribute it and/or
4 * modify it under the terms of the GNU General Public License as
5 * published by the Free Software Foundation; either version 2 of
6 * the License, or (at your option) any later version.
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
14 #include "tig/tig.h"
15 #include "tig/repo.h"
16 #include "tig/io.h"
17 #include "tig/refdb.h"
18 #include "tig/git.h"
20 #define REPO_INFO_GIT_DIR "--git-dir"
21 #define REPO_INFO_WORK_TREE "--is-inside-work-tree"
22 #define REPO_INFO_SHOW_CDUP "--show-cdup"
23 #define REPO_INFO_SHOW_PREFIX "--show-prefix"
24 #define REPO_INFO_SYMBOLIC_HEAD "--symbolic-full-name"
25 #define REPO_INFO_RESOLVED_HEAD "HEAD"
27 struct repo_info_state {
28 const char **argv;
31 static enum status_code
32 read_repo_info(char *name, size_t namelen, char *value, size_t valuelen, void *data)
34 struct repo_info_state *state = data;
35 const char *arg = *state->argv ? *state->argv++ : "";
37 if (!strcmp(arg, REPO_INFO_GIT_DIR)) {
38 string_ncopy(repo.git_dir, name, namelen);
40 } else if (!strcmp(arg, REPO_INFO_WORK_TREE)) {
41 /* This can be 3 different values depending on the
42 * version of git being used. If git-rev-parse does not
43 * understand --is-inside-work-tree it will simply echo
44 * the option else either "true" or "false" is printed.
45 * Default to true for the unknown case. */
46 repo.is_inside_work_tree = strcmp(name, "false") ? true : false;
48 } else if (!strcmp(arg, REPO_INFO_SHOW_CDUP)) {
49 string_ncopy(repo.cdup, name, namelen);
51 } else if (!strcmp(arg, REPO_INFO_SHOW_PREFIX)) {
52 /* Some versions of Git does not emit anything for --show-prefix
53 * when the user is in the repository root directory. Try to detect
54 * this special case by looking at the emitted value. If it looks
55 * like a commit ID and there's no cdup path assume that no value
56 * was emitted. */
57 if (!*repo.cdup && namelen == 40 && iscommit(name))
58 return read_repo_info(name, namelen, value, valuelen, data);
60 string_ncopy(repo.prefix, name, namelen);
62 } else if (!strcmp(arg, REPO_INFO_RESOLVED_HEAD)) {
63 string_ncopy(repo.head_id, name, namelen);
65 } else if (!strcmp(arg, REPO_INFO_SYMBOLIC_HEAD)) {
66 if (!prefixcmp(name, "refs/heads/")) {
67 const char *head = name + STRING_SIZE("refs/heads/");
69 string_ncopy(repo.head, head, strlen(head) + 1);
70 add_ref(repo.head_id, name, repo.remote, repo.head);
72 state->argv++;
75 return SUCCESS;
78 static enum status_code
79 reload_repo_info(const char **rev_parse_argv)
81 struct repo_info_state state = { rev_parse_argv + 2 };
83 return io_run_load(rev_parse_argv, "=", read_repo_info, &state);
86 enum status_code
87 load_repo_info(void)
89 const char *rev_parse_argv[] = {
90 "git", "rev-parse", REPO_INFO_GIT_DIR, REPO_INFO_WORK_TREE,
91 REPO_INFO_SHOW_CDUP, REPO_INFO_SHOW_PREFIX, \
92 REPO_INFO_RESOLVED_HEAD, REPO_INFO_SYMBOLIC_HEAD, "HEAD",
93 NULL
96 memset(&repo, 0, sizeof(repo));
97 return reload_repo_info(rev_parse_argv);
100 enum status_code
101 load_repo_head(void)
103 const char *rev_parse_argv[] = {
104 "git", "rev-parse", REPO_INFO_RESOLVED_HEAD,
105 REPO_INFO_SYMBOLIC_HEAD, "HEAD", NULL
108 memset(repo.head, 0, sizeof(repo.head));
109 memset(repo.head_id, 0, sizeof(repo.head_id));
110 return reload_repo_info(rev_parse_argv);
113 struct repo_info repo;
116 * Git index utils.
119 bool
120 update_index(void)
122 const char *update_index_argv[] = {
123 "git", "update-index", "-q", "--unmerged", "--refresh", NULL
126 return io_run_bg(update_index_argv, repo.cdup);
129 bool
130 index_diff(struct index_diff *diff, bool untracked, bool count_all)
132 const char *untracked_arg = !untracked ? "--untracked-files=no" :
133 count_all ? "--untracked-files=all" :
134 "--untracked-files=normal";
135 const char *status_argv[] = {
136 "git", "status", "--porcelain", "-z", untracked_arg, NULL
138 struct io io;
139 struct buffer buf;
140 bool ok = true;
142 memset(diff, 0, sizeof(*diff));
144 if (!io_run(&io, IO_RD, repo.cdup, NULL, status_argv))
145 return false;
147 while (io_get(&io, &buf, 0, true) && (ok = buf.size > 3)) {
148 if (buf.data[0] == '?')
149 diff->untracked++;
150 /* Ignore staged but unmerged entries. */
151 else if (buf.data[0] != ' ' && buf.data[0] != 'U')
152 diff->staged++;
153 if (buf.data[1] != ' ')
154 diff->unstaged++;
155 if (!count_all && diff->staged && diff->unstaged &&
156 (!untracked || diff->untracked))
157 break;
160 if (io_error(&io))
161 ok = false;
163 io_done(&io);
164 return ok;
167 /* vim: set ts=8 sw=8 noexpandtab: */