sed: save the last regex for use later with s///
[git/pclouds.git] / exec_cmd.c
blob8a0857ece93d85c01441a777224206b6c5e91718
1 #include "cache.h"
2 #include "exec_cmd.h"
3 #include "quote.h"
4 #include "spawn-pipe.h"
5 #define MAX_ARGS 32
7 extern char **environ;
8 static const char *current_exec_path;
10 static const char *builtin_exec_path(void)
12 #ifndef __MINGW32__
13 return GIT_EXEC_PATH;
14 #else
15 int len;
16 char *p, *q, *sl;
17 static char *ep;
18 if (ep)
19 return ep;
21 len = strlen(_pgmptr);
22 if (len < 2)
23 return ep = ".";
25 p = ep = xmalloc(len+1);
26 q = _pgmptr;
27 sl = NULL;
28 /* copy program name, turn '\\' into '/', skip last part */
29 while ((*p = *q)) {
30 if (*q == '\\' || *q == '/') {
31 *p = '/';
32 sl = p;
34 p++, q++;
36 if (sl)
37 *sl = '\0';
38 else
39 ep[0] = '.', ep[1] = '\0';
40 return ep;
41 #endif
44 void git_set_exec_path(const char *exec_path)
46 current_exec_path = exec_path;
50 /* Returns the highest-priority, location to look for git programs. */
51 const char *git_exec_path(void)
53 const char *env;
55 if (current_exec_path)
56 return current_exec_path;
58 env = getenv(EXEC_PATH_ENVIRONMENT);
59 if (env && *env) {
60 return env;
63 return builtin_exec_path();
67 int execv_git_cmd(const char **argv)
69 char git_command[PATH_MAX + 1];
70 int i;
71 const char *paths[] = { current_exec_path,
72 getenv(EXEC_PATH_ENVIRONMENT),
73 builtin_exec_path() };
75 for (i = 0; i < ARRAY_SIZE(paths); ++i) {
76 size_t len;
77 int rc;
78 const char *exec_dir = paths[i];
79 const char *tmp;
81 if (!exec_dir || !*exec_dir) continue;
83 #ifdef __MINGW32__
84 if (*exec_dir != '/' && exec_dir[1] != ':') {
85 #else
86 if (*exec_dir != '/') {
87 #endif
88 if (!getcwd(git_command, sizeof(git_command))) {
89 fprintf(stderr, "git: cannot determine "
90 "current directory: %s\n",
91 strerror(errno));
92 break;
94 len = strlen(git_command);
96 /* Trivial cleanup */
97 while (!prefixcmp(exec_dir, "./")) {
98 exec_dir += 2;
99 while (*exec_dir == '/')
100 exec_dir++;
103 rc = snprintf(git_command + len,
104 sizeof(git_command) - len, "/%s",
105 exec_dir);
106 if (rc < 0 || rc >= sizeof(git_command) - len) {
107 fprintf(stderr, "git: command name given "
108 "is too long.\n");
109 break;
111 } else {
112 if (strlen(exec_dir) + 1 > sizeof(git_command)) {
113 fprintf(stderr, "git: command name given "
114 "is too long.\n");
115 break;
117 strcpy(git_command, exec_dir);
120 len = strlen(git_command);
121 rc = snprintf(git_command + len, sizeof(git_command) - len,
122 "/git-%s", argv[0]);
123 if (rc < 0 || rc >= sizeof(git_command) - len) {
124 fprintf(stderr,
125 "git: command name given is too long.\n");
126 break;
129 /* argv[0] must be the git command, but the argv array
130 * belongs to the caller, and my be reused in
131 * subsequent loop iterations. Save argv[0] and
132 * restore it on error.
135 tmp = argv[0];
136 argv[0] = git_command;
138 trace_argv_printf(argv, -1, "trace: exec:");
140 /* execve() can only ever return if it fails */
141 execve(git_command, (char **)argv, environ);
143 trace_printf("trace: exec failed: %s\n", strerror(errno));
145 argv[0] = tmp;
147 return -1;
151 #ifdef __MINGW32__
152 /* EVIL: copy/paste from execv_git_cmd */
153 void execv_git_sh_cmd(int argc, const char **argv)
155 char git_command[PATH_MAX + 1];
156 int i;
157 const char *paths[] = { current_exec_path,
158 getenv(EXEC_PATH_ENVIRONMENT),
159 builtin_exec_path() };
160 struct stat st;
161 char **box_argv;
163 box_argv = malloc(sizeof(char *)*(argc+1+3)); /* git, box, sh and null */
164 box_argv[0] = "box";
165 box_argv[1] = "sh";
166 memcpy(&box_argv[3],&argv[1],sizeof(char*)*argc);
168 for (i = 0; i < ARRAY_SIZE(paths); ++i) {
169 size_t len;
170 int rc;
171 const char *exec_dir = paths[i];
172 const char *tmp;
174 if (!exec_dir || !*exec_dir) continue;
176 #ifdef __MINGW32__
177 if (*exec_dir != '/' && exec_dir[1] != ':') {
178 #else
179 if (*exec_dir != '/') {
180 #endif
181 if (!getcwd(git_command, sizeof(git_command))) {
182 fprintf(stderr, "git: cannot determine "
183 "current directory: %s\n",
184 strerror(errno));
185 break;
187 len = strlen(git_command);
189 /* Trivial cleanup */
190 while (!prefixcmp(exec_dir, "./")) {
191 exec_dir += 2;
192 while (*exec_dir == '/')
193 exec_dir++;
196 rc = snprintf(git_command + len,
197 sizeof(git_command) - len, "/%s",
198 exec_dir);
199 if (rc < 0 || rc >= sizeof(git_command) - len) {
200 fprintf(stderr, "git: command name given "
201 "is too long.\n");
202 break;
204 } else {
205 if (strlen(exec_dir) + 1 > sizeof(git_command)) {
206 fprintf(stderr, "git: command name given "
207 "is too long.\n");
208 break;
210 strcpy(git_command, exec_dir);
213 len = strlen(git_command);
214 rc = snprintf(git_command + len, sizeof(git_command) - len,
215 "/git-%s", argv[0]);
216 if (rc < 0 || rc >= sizeof(git_command) - len) {
217 fprintf(stderr,
218 "git: command name given is too long.\n");
219 break;
222 #ifdef STRIP_EXTENSION
223 i = strlen(git_command) - strlen(STRIP_EXTENSION);
224 if (i > 0 && !strcmp(git_command + i, STRIP_EXTENSION))
225 git_command[i] = '\0';
226 #endif
228 /* such script does not exist, go on */
229 if (stat(git_command,&st) < 0)
230 continue;
232 box_argv[2] = git_command;
233 execv_git_cmd(box_argv);
235 return -1;
237 #endif
240 int execl_git_cmd(const char *cmd,...)
242 int argc;
243 const char *argv[MAX_ARGS + 1];
244 const char *arg;
245 va_list param;
247 va_start(param, cmd);
248 argv[0] = cmd;
249 argc = 1;
250 while (argc < MAX_ARGS) {
251 arg = argv[argc++] = va_arg(param, char *);
252 if (!arg)
253 break;
255 va_end(param);
256 if (MAX_ARGS <= argc)
257 return error("too many args to run %s", cmd);
259 argv[argc] = NULL;
260 return execv_git_cmd(argv);
263 int spawnve_git_cmd(const char **argv, int pin[2], int pout[2], char **envp)
265 char cmd[100];
266 int i, rc;
267 pid_t pid;
268 const char *paths[] = { current_exec_path,
269 getenv(EXEC_PATH_ENVIRONMENT),
270 builtin_exec_path() };
271 char p[3][PATH_MAX + 1];
272 char *usedpaths[4], **up = usedpaths;
273 const char *tmp;
275 for (i = 0; i < ARRAY_SIZE(paths); ++i) {
276 size_t len;
277 const char *exec_dir = paths[i];
279 if (!exec_dir || !*exec_dir) continue;
281 #ifdef __MINGW32__
282 if (*exec_dir != '/' && exec_dir[1] != ':') {
283 #else
284 if (*exec_dir != '/') {
285 #endif
286 if (!getcwd(p[i], sizeof(p[i]))) {
287 fprintf(stderr, "git: cannot determine "
288 "current directory: %s\n",
289 strerror(errno));
290 return -1;
292 len = strlen(p[i]);
294 /* Trivial cleanup */
295 while (!strncmp(exec_dir, "./", 2)) {
296 exec_dir += 2;
297 while (*exec_dir == '/')
298 exec_dir++;
301 rc = snprintf(p[i] + len,
302 sizeof(p[i]) - len, "/%s",
303 exec_dir);
304 if (rc < 0 || rc >= sizeof(p[i]) - len) {
305 fprintf(stderr, "git: command name given "
306 "is too long.\n");
307 return -1;
309 } else {
310 if (strlen(exec_dir) + 1 > sizeof(p[i])) {
311 fprintf(stderr, "git: command name given "
312 "is too long.\n");
313 return -1;
315 strcpy(p[i], exec_dir);
317 *up++ = p[i];
319 *up = NULL;
321 rc = snprintf(cmd, sizeof(cmd), "git-%s", argv[0]);
322 if (rc < 0 || rc >= sizeof(cmd)) {
323 fprintf(stderr,
324 "git: command name given is too long.\n");
325 return -1;
328 /* argv[0] must be the git command, but the argv array
329 * belongs to the caller. Save argv[0] and
330 * restore it later.
333 tmp = argv[0];
334 argv[0] = cmd;
336 trace_argv_printf(argv, -1, "trace: exec:");
338 pid = spawnvppe_pipe(cmd, argv, envp, usedpaths,
339 pin, pout);
341 argv[0] = tmp;
342 return pid;
346 int spawnv_git_cmd(const char **argv, int pin[2], int pout[2])
348 return spawnve_git_cmd(argv, pin, pout, environ);