Left: | ||
Right: |
OLD | NEW |
---|---|
(Empty) | |
1 // Copyright 2012 The Go Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style | |
3 // license that can be found in the LICENSE file. | |
4 | |
5 // These #ifdefs are being used as a substitute for | |
6 // build configuration, so that on any system, this | |
7 // tool can be built with the local equivalent of | |
8 // cc *.c | |
9 // | |
10 #ifndef WIN32 | |
11 #ifndef PLAN9 | |
12 | |
13 #include "a.h" | |
14 #include <unistd.h> | |
15 #include <dirent.h> | |
16 #include <sys/stat.h> | |
17 #include <sys/wait.h> | |
18 #include <sys/param.h> | |
19 #include <fcntl.h> | |
20 #include <string.h> | |
21 #include <stdio.h> | |
22 #include <stdlib.h> | |
23 #include <errno.h> | |
24 #include <stdarg.h> | |
25 | |
26 // breadfrom appends to b all the data that can be read from fd. | |
27 static void | |
28 breadfrom(Buf *b, int fd) | |
29 { | |
30 int n; | |
31 | |
32 for(;;) { | |
33 bgrow(b, 4096); | |
34 n = read(fd, b->p+b->len, 4096); | |
35 if(n <= 0) | |
bradfitz
2012/02/02 00:53:11
be fatal on non-EOF errors?
| |
36 break; | |
37 b->len += n; | |
38 } | |
39 } | |
40 | |
41 // xgetenv replaces b with the value of the named environment variable. | |
42 void | |
43 xgetenv(Buf *b, char *name) | |
44 { | |
45 char *p; | |
46 ········ | |
47 breset(b); | |
48 p = getenv(name); | |
49 if(p != NULL) | |
50 bwritestr(b, p); | |
51 } | |
52 | |
53 // run runs the command named by cmd. | |
54 // If b is not nil, run replaces b with the output of the command. | |
55 // If dir is not nil, run runs the command in that directory. | |
56 // If mode is CheckExit, run calls fatal if the command is not successful. | |
57 void | |
58 run(Buf *b, char *dir, int mode, char *cmd, ...) | |
59 { | |
60 va_list arg; | |
61 Vec argv; | |
62 char *p; | |
63 ········ | |
64 vinit(&argv); | |
65 vadd(&argv, cmd); | |
66 va_start(arg, cmd); | |
67 while((p = va_arg(arg, char*)) != nil) | |
68 vadd(&argv, p); | |
69 va_end(arg); | |
70 ········ | |
71 runv(b, dir, mode, &argv); | |
72 ········ | |
73 vfree(&argv); | |
74 } | |
75 | |
76 | |
77 // runv is like run but takes a vector. | |
78 void | |
79 runv(Buf *b, char *dir, int mode, Vec *argv) | |
80 { | |
81 int i, p[2], pid, status; | |
82 Buf cmd; | |
83 char *q; | |
84 | |
85 binit(&cmd); | |
86 for(i=0; i<argv->len; i++) { | |
87 if(i > 0) | |
88 bwritestr(&cmd, " "); | |
89 q = argv->p[i]; | |
90 if(workdir != nil && hasprefix(q, workdir)) { | |
91 bwritestr(&cmd, "$WORK"); | |
iant
2012/02/02 01:53:26
What is this about?
| |
92 q += strlen(workdir); | |
93 } | |
94 bwritestr(&cmd, q); | |
95 } | |
96 printf("%s\n", bstr(&cmd)); | |
97 bfree(&cmd); | |
98 | |
99 if(b != nil) { | |
100 breset(b); | |
101 if(pipe(p) < 0) | |
102 fatal("pipe: %s", strerror(errno)); | |
103 } | |
104 | |
105 switch(pid = fork()) { | |
106 case -1: | |
107 fatal("fork: %s", strerror(errno)); | |
108 case 0: | |
109 if(b != nil) { | |
110 close(0); | |
111 close(p[0]); | |
112 dup2(p[1], 1); | |
113 dup2(p[1], 2); | |
114 if(p[1] > 2) | |
115 close(p[1]); | |
116 } | |
117 if(dir != nil) { | |
118 if(chdir(dir) < 0) { | |
119 fprintf(stderr, "chdir %s: %s\n", dir, strerror( errno)); | |
120 _exit(1); | |
121 } | |
122 } | |
123 vadd(argv, nil); | |
124 execvp(argv->p[0], argv->p); | |
125 fprintf(stderr, "exec %s: %s\n", argv->p[0], strerror(errno)); | |
126 _exit(1); | |
127 } | |
128 if(b != nil) { | |
129 close(p[1]); | |
130 breadfrom(b, p[0]); | |
131 close(p[0]); | |
132 } | |
133 wait: | |
134 errno = 0; | |
135 if(waitpid(pid, &status, 0) != pid) { | |
136 if(errno == EINTR) | |
137 goto wait; | |
138 fatal("waitpid: %s", strerror(errno)); | |
139 } | |
140 if(mode==CheckExit && (!WIFEXITED(status) || WEXITSTATUS(status) != 0)) { | |
141 if(b != nil) | |
142 fwrite(b->p, b->len, 1, stderr); | |
143 fatal("%s failed", argv->p[0]); | |
144 } | |
145 } | |
146 | |
147 // xgetwd replaces b with the current directory. | |
148 void | |
149 xgetwd(Buf *b) | |
150 { | |
151 char buf[MAXPATHLEN]; | |
ality
2012/02/02 17:43:21
Should this be PATH_MAX? I never know which to use
| |
152 ········ | |
153 breset(b); | |
154 if(getcwd(buf, MAXPATHLEN) == nil) | |
ality
2012/02/02 17:43:21
s/MAXPATHLEN/sizeof buf/
| |
155 fatal("getcwd: %s", strerror(errno)); | |
156 bwritestr(b, buf);······ | |
157 } | |
158 | |
159 // xrealwd replaces b with the 'real' name for the given path. | |
160 // real is defined as what getcwd returns in that directory. | |
161 void | |
162 xrealwd(Buf *b, char *path) | |
ality
2012/02/02 17:43:21
This appears to be unused.
| |
163 { | |
164 int fd; | |
165 ········ | |
166 fd = open(".", 0); | |
167 if(fd < 0) | |
168 fatal("open .: %s", strerror(errno)); | |
169 if(chdir(path) < 0) | |
170 fatal("chdir %s: %s", path, strerror(errno)); | |
171 xgetwd(b); | |
172 if(fchdir(fd) < 0) | |
173 fatal("fchdir: %s", strerror(errno)); | |
174 close(fd); | |
175 } | |
176 | |
177 // isdir reports whether p names an existing directory. | |
178 bool | |
179 isdir(char *p) | |
180 { | |
181 struct stat st; | |
182 ········ | |
183 return stat(p, &st) >= 0 && S_ISDIR(st.st_mode); | |
184 } | |
185 | |
186 // isfile reports whether p names an existing file. | |
187 bool | |
188 isfile(char *p) | |
189 { | |
190 struct stat st; | |
191 ········ | |
192 return stat(p, &st) >= 0 && S_ISREG(st.st_mode); | |
193 } | |
194 | |
195 // mtime returns the modification time of the file p. | |
196 Time | |
197 mtime(char *p) | |
198 { | |
199 struct stat st; | |
200 ········ | |
201 if(stat(p, &st) < 0) | |
202 return 0; | |
203 return (Time)st.st_mtime*1000000000LL; | |
204 } | |
205 | |
206 // isabs reports whether p is an absolute path. | |
207 bool | |
208 isabs(char *p) | |
209 { | |
210 return hasprefix(p, "/"); | |
211 } | |
212 | |
213 // readfile replaces b with the content of the named file. | |
214 void | |
215 readfile(Buf *b, char *file) | |
216 { | |
217 int fd; | |
218 ········ | |
219 breset(b); | |
220 fd = open(file, 0); | |
221 if(fd < 0) | |
222 fatal("open %s: %s", file, strerror(errno)); | |
223 breadfrom(b, fd); | |
224 close(fd); | |
225 } | |
226 | |
227 // writefile writes b to the named file, creating it if needed. | |
228 void | |
229 writefile(Buf *b, char *file) | |
230 { | |
231 int fd; | |
232 ········ | |
233 fd = creat(file, 0666); | |
234 if(fd < 0) | |
235 fatal("create %s: %s", file, strerror(errno)); | |
236 if(write(fd, b->p, b->len) != b->len) | |
237 fatal("short write: %s", strerror(errno)); | |
238 close(fd); | |
239 } | |
240 ········ | |
241 // xmkdir creates the directory p. | |
242 void | |
243 xmkdir(char *p) | |
244 { | |
245 if(mkdir(p, 0777) < 0) | |
246 fatal("mkdir %s: %s", p, strerror(errno)); | |
247 } | |
248 | |
249 // xmkdirall creates the directory p and its parents, as needed. | |
250 void | |
251 xmkdirall(char *p) | |
252 { | |
253 char *q; | |
254 | |
255 if(isdir(p)) | |
256 return; | |
257 q = strrchr(p, '/'); | |
258 if(q != nil) { | |
259 *q = '\0'; | |
260 xmkdirall(p); | |
261 *q = '/'; | |
262 } | |
263 xmkdir(p); | |
264 } | |
265 | |
266 // xremove removes the file p. | |
267 void | |
268 xremove(char *p) | |
269 { | |
270 unlink(p); | |
271 } | |
272 | |
273 // xremoveall removes the file or directory tree rooted at p. | |
274 void | |
275 xremoveall(char *p) | |
276 { | |
277 int i; | |
278 Buf b; | |
279 Vec dir; | |
280 | |
281 binit(&b); | |
282 vinit(&dir); | |
283 | |
284 if(isdir(p)) { | |
285 xreaddir(&dir, p); | |
286 for(i=0; i<dir.len; i++) { | |
287 bprintf(&b, "%s/%s", p, dir.p[i]); | |
288 xremoveall(bstr(&b)); | |
289 } | |
290 rmdir(p); | |
291 } else { | |
292 unlink(p); | |
293 } | |
294 ········ | |
295 bfree(&b); | |
296 vfree(&dir);···· | |
297 } | |
298 | |
299 // xreaddir replaces dst with a list of the names of the files in dir. | |
300 // The names are relative to dir; they are not full paths. | |
301 void | |
302 xreaddir(Vec *dst, char *dir) | |
303 { | |
304 DIR *d; | |
305 struct dirent *dp; | |
306 ········ | |
307 vreset(dst); | |
308 d = opendir(dir); | |
309 if(d == nil) | |
310 fatal("opendir %s: %s", dir, strerror(errno)); | |
311 while((dp = readdir(d)) != nil) { | |
312 if(strcmp(dp->d_name, ".") == 0 || strcmp(dp->d_name, "..") == 0 ) | |
313 continue; | |
314 vadd(dst, dp->d_name); | |
315 } | |
316 closedir(d); | |
317 } | |
318 | |
319 // xworkdir creates a new temporary directory to hold object files | |
320 // and returns the name of that directory. | |
321 char* | |
322 xworkdir(void) | |
323 { | |
324 Buf b; | |
325 char *p; | |
326 ········ | |
327 binit(&b); | |
328 | |
329 xgetenv(&b, "TMPDIR"); | |
330 if(b.len == 0) | |
331 bwritestr(&b, "/var/tmp"); | |
332 bwritestr(&b, "/go-cbuild-XXXXXX"); | |
333 if(mkdtemp(bstr(&b)) == nil) | |
334 fatal("mkdtemp: %s", strerror(errno)); | |
335 p = btake(&b); | |
336 | |
337 bfree(&b); | |
338 | |
339 return p; | |
340 } | |
341 | |
342 // fatal prints an error message to standard error and exits. | |
343 void | |
344 fatal(char *msg, ...) | |
345 { | |
346 va_list arg; | |
347 ········ | |
348 fprintf(stderr, "go tool dist: "); | |
349 va_start(arg, msg); | |
350 vfprintf(stderr, msg, arg); | |
351 va_end(arg); | |
352 fprintf(stderr, "\n"); | |
353 exit(1); | |
354 } | |
355 | |
356 // xmalloc returns a newly allocated zeroed block of n bytes of memory. | |
357 // It calls fatal if it runs out of memory. | |
358 void* | |
359 xmalloc(int n) | |
360 { | |
361 void *p; | |
362 ········ | |
363 p = malloc(n); | |
364 if(p == nil) | |
365 fatal("out of memory"); | |
366 memset(p, 0, n); | |
367 return p; | |
368 } | |
369 | |
370 // xstrdup returns a newly allocated copy of p. | |
371 // It calls fatal if it runs out of memory. | |
372 char* | |
373 xstrdup(char *p) | |
374 { | |
375 p = strdup(p); | |
376 if(p == nil) | |
377 fatal("out of memory"); | |
378 return p; | |
379 } | |
380 | |
381 // xrealloc grows the allocation p to n bytes and | |
382 // returns the new (possibly moved) pointer. | |
383 // It calls fatal if it runs out of memory. | |
384 void* | |
385 xrealloc(void *p, int n) | |
386 { | |
387 p = realloc(p, n); | |
388 if(p == nil) | |
389 fatal("out of memory"); | |
390 return p; | |
391 } | |
392 | |
393 // xfree frees the result returned by xmalloc, xstrdup, or xrealloc. | |
394 void | |
395 xfree(void *p) | |
396 { | |
397 free(p); | |
398 } | |
399 | |
400 // hassuffix reports whether p ends with suffix. | |
401 bool | |
402 hassuffix(char *p, char *suffix) | |
403 { | |
404 int np, ns; | |
405 ········ | |
406 np = strlen(p); | |
407 ns = strlen(suffix); | |
408 return np >= ns && strcmp(p+np-ns, suffix) == 0; | |
409 } | |
410 | |
411 // hasprefix reports whether p begins wtih prefix. | |
412 bool | |
413 hasprefix(char *p, char *prefix) | |
414 { | |
415 return strncmp(p, prefix, strlen(prefix)) == 0; | |
416 } | |
417 | |
418 // contains reports whether sep appears in p. | |
419 bool | |
420 contains(char *p, char *sep) | |
421 { | |
422 return strstr(p, sep) != nil; | |
423 } | |
424 | |
425 // streq reports whether p and q are the same string. | |
426 bool | |
427 streq(char *p, char *q) | |
428 { | |
429 return strcmp(p, q) == 0; | |
430 } | |
431 | |
432 // lastelem returns the final path element in p. | |
433 char* | |
434 lastelem(char *p) | |
435 { | |
436 char *out; | |
437 | |
438 out = p; | |
439 for(; *p; p++) | |
440 if(*p == '/') | |
441 out = p+1; | |
442 return out; | |
443 } | |
444 | |
445 // xmemmove copies n bytes from src to dst. | |
446 void | |
447 xmemmove(void *dst, void *src, int n) | |
448 { | |
449 memmove(dst, src, n); | |
450 } | |
451 | |
452 // xmemcmp compares the n-byte regions starting at a and at b. | |
453 int | |
454 xmemcmp(void *a, void *b, int n) | |
455 { | |
456 return memcmp(a, b, n); | |
457 } | |
458 | |
459 // xstrlen returns the length of the NUL-terminated string at p. | |
460 int | |
461 xstrlen(char *p) | |
462 { | |
463 return strlen(p); | |
464 } | |
465 | |
466 // xexit exits the process with return code n. | |
467 void | |
468 xexit(int n) | |
469 { | |
470 exit(n); | |
471 } | |
472 | |
473 // xatexit schedules the exit-handler f to be run when the program exits. | |
474 void | |
475 xatexit(void (*f)(void)) | |
476 { | |
477 atexit(f); | |
478 } | |
479 | |
480 // xprintf prints a message to standard output. | |
481 void | |
482 xprintf(char *fmt, ...) | |
483 { | |
484 va_list arg; | |
485 ········ | |
486 va_start(arg, fmt); | |
487 vprintf(fmt, arg); | |
488 va_end(arg); | |
489 } | |
490 | |
491 // xsetenv sets the environment variable $name to the given value. | |
492 void | |
493 xsetenv(char *name, char *value) | |
494 { | |
495 setenv(name, value, 1); | |
ality
2012/02/02 17:43:21
I'm not sure if setenv is available everywhere.
Yo
| |
496 } | |
497 | |
498 // main takes care of OS-specific startup and dispatches to xmain. | |
499 int | |
500 main(int argc, char **argv) | |
501 { | |
502 char *p; | |
503 | |
504 p = argv[0]; | |
505 if(hassuffix(p, "bin/go-tool/dist")) { | |
506 default_goroot = xstrdup(p); | |
507 default_goroot[strlen(p)-strlen("bin/go-tool/dist")] = '\0'; | |
508 } | |
509 ········ | |
510 slash = "/"; | |
511 | |
512 #if defined(__APPLE__) | |
513 gohostos = "darwin"; | |
514 #elif defined(__linux__) | |
515 gohostos = "linux"; | |
516 #else | |
ality
2012/02/02 13:07:43
This will fail on Plan 9 since the #else
correspon
| |
517 fatal("unknown operating system"); | |
518 #endif | |
519 xprintf("hostos %s\n", gohostos); | |
iant
2012/02/02 01:53:26
Remove debug print.
| |
520 | |
521 init(); | |
522 xmain(argc, argv); | |
523 return 0; | |
524 } | |
525 | |
526 // xqsort is a wrapper for the C standard qsort. | |
527 void | |
528 xqsort(void *data, int n, int elemsize, int (*cmp)(const void*, const void*)) | |
529 { | |
530 qsort(data, n, elemsize, cmp); | |
531 } | |
532 | |
533 // xstrcmp compares the NUL-terminated strings a and b. | |
534 int | |
535 xstrcmp(char *a, char *b) | |
536 { | |
537 return strcmp(a, b); | |
538 } | |
539 | |
540 // xstrstr returns a pointer to the first occurrence of b in a. | |
541 char* | |
542 xstrstr(char *a, char *b) | |
543 { | |
544 return strstr(a, b); | |
545 } | |
546 | |
547 // xstrrchr returns a pointer to the FINAL occurrence of c in p. | |
548 char* | |
549 xstrrchr(char *p, int c) | |
550 { | |
551 char *ep; | |
552 ········ | |
553 ep = p+strlen(p); | |
ality
2012/02/02 17:43:21
Duplicated initialization of ep.
| |
554 for(ep=p+strlen(p); ep >= p; ep--) | |
555 if(*ep == c) | |
556 return ep; | |
557 return nil; | |
558 } | |
559 | |
560 #endif // PLAN9 | |
561 #endif // __WINDOWS__ | |
OLD | NEW |