]> Dogcows Code - chaz/githead/blob - githead.c
add escaping for non-printable characters
[chaz/githead] / githead.c
1
2 /*
3 * Get the name of the current git branch (pointed to by HEAD) and print it
4 * out, color-coded to show if any working files are dirty. This would
5 * ideally be implemented as a shell script, but I wrote it in C because it
6 * needs to be fast! And we all know C is fast, amiright?
7 *
8 * Also reads in regular expressions (one per line) matching paths that
9 * should be ignored. Each regex is matched against the top-level
10 * directory path of the repository. If it matches, nothing is printed.
11 * It is a good idea to ignore repositories on slow (remote) disks.
12 *
13 * Example usage (bash):
14 * PS1='\u@\h \w$(githead <~/.nogitprompt) $ '
15 *
16 * Written 04 June 2012 by Charles McGarvey.
17 */
18
19 const char* format = "\ 1\e[%sm\ 2 %s\ 1\e[0m\ 2";
20 const char* ansi_codes = "0;36";
21 const char* ansi_codes_dirty = "0;31";
22
23 const int short_hash_length = 7;
24
25 #include <errno.h>
26 #include <regex.h>
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <unistd.h>
31
32 #include <sys/types.h>
33 #include <sys/wait.h>
34
35 int main(int argc, char* argv[])
36 {
37 char buf[4096];
38 char* ref = NULL;
39 int dirty = 0;
40
41 fclose(stderr); // usually do not want any extra junk printed
42
43 int p[2];
44 if (pipe(p) == -1) {
45 fprintf(stderr, "pipe failed: %s\n", strerror(errno));
46 return 1;
47 }
48
49 pid_t pid1 = fork();
50 if (pid1 == -1) {
51 fprintf(stderr, "fork failed: %s\n", strerror(errno));
52 return 1;
53 }
54 if (pid1 == 0) {
55 char* args[] = {"git", "rev-parse", "--show-toplevel", NULL};
56 if (dup2(p[1], 1) == -1) {
57 fprintf(stderr, "dup2 failed: %s\n", strerror(errno));
58 }
59 execvp(args[0], args);
60 return 0;
61 }
62
63 close(p[1]);
64
65 int status;
66 while (waitpid(pid1, &status, 0) < 0) {
67 if (errno != EINTR) {
68 fprintf(stderr, "waitpid failed: %s\n", strerror(errno));
69 return 1;
70 }
71 }
72 if (WEXITSTATUS(status) == 0) {
73 ssize_t bytes = read(p[0], buf, sizeof(buf));
74 if (bytes < 0) {
75 fprintf(stderr, "read failed: %s\n", strerror(errno));
76 return 1;
77 }
78 buf[bytes-1] = '\0';
79
80 char regbuf[4096];
81 while (gets(regbuf)) {
82 char errbuf[4096];
83 regex_t re;
84 int err = regcomp(&re, regbuf, REG_EXTENDED | REG_ICASE | REG_NOSUB);
85 if (err != 0) {
86 regerror(err, &re, errbuf, sizeof(errbuf));
87 fprintf(stderr, "regcomp failed: %s\n", errbuf);
88 continue;
89 }
90 if (regexec(&re, buf, 0, NULL, 0) == 0) {
91 return 0;
92 }
93 regfree(&re);
94 }
95 }
96 else {
97 fprintf(stderr, "git failed; bailing out...\n");
98 return 1;
99 }
100
101 pid_t pid2 = fork();
102 if (pid2 == -1) {
103 fprintf(stderr, "fork failed: %s\n", strerror(errno));
104 return 1;
105 }
106 if (pid2 == 0) {
107 char* args[] = {"git", "diff", "--no-ext-diff", "--quiet", "--exit-code", NULL};
108 execvp(args[0], args);
109 return 0;
110 }
111
112 if (pipe(p) == -1) {
113 fprintf(stderr, "pipe failed: %s\n", strerror(errno));
114 return 1;
115 }
116
117 pid_t pid3 = fork();
118 if (pid3 == -1) {
119 fprintf(stderr, "fork failed: %s\n", strerror(errno));
120 return 1;
121 }
122 if (pid3 == 0) {
123 char* args[] = {"git", "symbolic-ref", "HEAD", NULL};
124 if (dup2(p[1], 1) == -1) {
125 fprintf(stderr, "dup2 failed: %s\n", strerror(errno));
126 }
127 execvp(args[0], args);
128 return 1;
129 }
130
131 close(p[1]);
132
133 while (waitpid(pid3, &status, 0) < 0) {
134 if (errno != EINTR) {
135 fprintf(stderr, "waitpid failed: %s\n", strerror(errno));
136 return 1;
137 }
138 }
139 if (WEXITSTATUS(status) == 0) {
140 ssize_t bytes = read(p[0], buf, sizeof(buf));
141 if (bytes < 0) {
142 fprintf(stderr, "read failed: %s\n", strerror(errno));
143 return 1;
144 }
145 buf[bytes-1] = '\0';
146 ref = buf + 11;
147 } else {
148 if (pipe(p) == -1) {
149 fprintf(stderr, "pipe failed: %s\n", strerror(errno));
150 return 1;
151 }
152
153 pid_t pid4 = fork();
154 if (pid4 == -1) {
155 fprintf(stderr, "fork failed: %s\n", strerror(errno));
156 return 1;
157 }
158 if (pid4 == 0) {
159 char* args[] = {"git", "rev-parse", "HEAD", NULL};
160 if (dup2(p[1], 1) == -1) {
161 fprintf(stderr, "dup2 failed: %s\n", strerror(errno));
162 }
163 execvp(args[0], args);
164 return 1;
165 }
166
167 close(p[1]);
168
169 while (waitpid(pid4, &status, 0) < 0) {
170 if (errno != EINTR) {
171 fprintf(stderr, "waitpid failed: %s\n", strerror(errno));
172 return 1;
173 }
174 }
175 if (WEXITSTATUS(status) == 0) {
176 ssize_t bytes = read(p[0], buf, sizeof(buf));
177 if (bytes < 0) {
178 fprintf(stderr, "read failed: %s\n", strerror(errno));
179 return 1;
180 }
181 buf[short_hash_length] = '\0';
182 ref = buf;
183 }
184 }
185
186 while (waitpid(pid2, &status, 0) < 0) {
187 if (errno != EINTR) {
188 fprintf(stderr, "waitpid failed: %s\n", strerror(errno));
189 return 1;
190 }
191 }
192 dirty = (WEXITSTATUS(status) != 0);
193
194 if (ref) {
195 if (dirty) {
196 printf(format, ansi_codes_dirty, ref);
197 }
198 else {
199 printf(format, ansi_codes, ref);
200 }
201 }
202
203 return 0;
204 }
205
This page took 0.035776 seconds and 4 git commands to generate.