int nc, nl, np, nxo, na;
#ifdef XIFY
-char **ilist;
-int ni;
-
-/*char in_path[BUFSIZ];*/
+/* When we run "xify" as a child process, it will output to us on stderr a */
+/* list of dependencies as it encounters them. We receive this list via a */
+/* pipe, and as each dependency is received, we search the include path for */
+/* it, using special rules for "file.h" vs <file.h>, and then check if the */
+/* resolved path is already encountered (xified, or queued for xification). */
+/* If so, we ignore it. Otherwise we queue it. When we queue it, we save two */
+/* further pieces of information. If the path stem came from the include */
+/* path (other than being a relative path from a current file), and the */
+/* remaining path contained at least one directory, we have to "mkdir" the */
+/* path stem plus "/.xify". This is because the "-Idirectory" passed to to */
+/* gcc must exist, even if it is empty. This can occur if the remaining path */
+/* contains ".." elements. So, the first piece of information is which path */
+/* stem was used, or -1 if no extra "mkdir" is necessary (noting that we */
+/* will also "mkdir" the directory containing the xified source). It'd be */
+/* fine to "mkdir" the path stem at the time of queueing, or to "mkdir" all */
+/* path stems whether anything is found through them or not, but this way is */
+/* more consistent if we get an error and abort with things still enqueued. */
+/* The second piece of information is the mtime, so that we do not have to */
+/* "stat" it again when it comes to the head of the queue. When it comes to */
+/* the head of the queue we check for a previous xification of the same file */
+/* left in ".xify" underneath the directory containing the file, since this */
+/* will occur a lot for system includes and if not stale it saves much work. */
+
+#define IN_QUEUE_SIZE 0x100 /* fix this later and make it dynamic */
+
+struct {
+ char *path;
+ struct timespec mtime;
+ int mkdir;
+} in_queue[IN_QUEUE_SIZE];
+int in_queue_head;
+int in_queue_tail;
+
+char in_path[BUFSIZ];
char out_path[BUFSIZ];
#endif
int getsuf __P((char as[]));
char *setsuf __P((char *as, int ch));
#ifdef XIFY
-int xify_include __P((char *in_name));
-int xify_file __P((char *in_name, struct stat *in_statbuf));
+int xify_include __P((char *in_name, char *prev_name));
+int xify_file __P((char *in_name, struct timespec *in_mtime));
#endif
int callsys __P((char *f, char **v));
int nodup __P((char **l, char *os));
if (plist[i][2] == '/')
plist[i] = strspl("-I", strspl(t, plist[i] + 2));
}
- ilist = (char **)calloc(0x100, sizeof (char **));
#else
if (pflag==0)
sprintf(tmp0, "/tmp/ctm%05.5d", getpid());
error("not found: %s", clist[i]);
goto nogood;
}
- if (xify_file(clist[i], &statbuf)) {
- nogood:
- cflag++;
- eflag++;
- continue;
- }
+ if (xify_file(clist[i], &statbuf.st_mtim))
+ goto nogood;
clist[i] = savestr(out_path);
+
+ while (in_queue_head < in_queue_tail) {
+ if (
+ xify_file(
+ in_queue[in_queue_head].path,
+ &in_queue[in_queue_head].mtime
+ )
+ )
+ goto nogood;
+ if (
+ in_queue[in_queue_head].mkdir >= 0 &&
+ mkdir(plist[in_queue[in_queue_head].mkdir] + 2, 0777) &&
+ errno != EEXIST
+ )
+ goto nogood;
+ ++in_queue_head;
+ }
}
av[0] = "gcc"; av[1] = "-o";
na = 2;
av[na++] = clist[i];
av[na] = 0;
if (callsys(gcc, av)) {
+ nogood:
cflag++;
eflag++;
continue;
}
#ifdef XIFY
-int xify_file(in_name, in_statbuf) char *in_name; struct stat *in_statbuf; {
+int xify_file(in_name, in_mtime) char *in_name; struct timespec *in_mtime; {
int i;
struct stat out_statbuf;
+ int t, status;
+ char **cpp;
+ int fds[3];
+ FILE *err_fp;
+ char err_line[BUFSIZ];
+ int e;
/* note: out_path is an output parameter on success */
for (i = strlen(in_name); i > 0 && in_name[i - 1] != '/'; --i)
strcat(out_path + i, in_name + i);
if (
stat(out_path, &out_statbuf) == 0 && (
- out_statbuf.st_mtim.tv_sec > in_statbuf->st_mtim.tv_sec || (
- out_statbuf.st_mtim.tv_sec == in_statbuf->st_mtim.tv_sec &&
- out_statbuf.st_mtim.tv_nsec >= in_statbuf->st_mtim.tv_nsec
+ out_statbuf.st_mtim.tv_sec > in_mtime->tv_sec || (
+ out_statbuf.st_mtim.tv_sec == in_mtime->tv_sec &&
+ out_statbuf.st_mtim.tv_nsec >= in_mtime->tv_nsec
)
)
out_path[i + 5] = '/';
av[0] = "xify"; av[1] = in_name; av[2] = out_path; av[3] = 0;
- return callsys(xify, av);
+ /*return callsys(xify, av);*/
+
+ if (debug) {
+ fprintf(stderr, "%s:", xify);
+ for (cpp = av; *cpp != 0; cpp++)
+ fprintf(stderr, " %s", *cpp);
+ fprintf(stderr, "\n");
+ }
+ if (
+ pipe(fds) ||
+ (err_fp = fdopen(fds[0], "r")) == 0 ||
+ (fds[2] = dup(2)) == -1
+ ) {
+ fprintf(stderr, "Can't create pipe\n");
+ return (100);
+ }
+ dup2(fds[1], 2);
+ close(fds[1]);
+ t = vfork();
+ if (t == -1) {
+ printf("No more processes\n");
+ return (100);
+ }
+ if (t == 0) {
+ execv(xify, av);
+ printf("Can't find %s\n", xify);
+ fflush(stdout);
+ _exit(100);
+ }
+ dup2(fds[2], 2);
+ close(fds[2]);
+ while (fgets(err_line, BUFSIZ, err_fp))
+ if (err_line[0] == '"') {
+ e = '"';
+ goto include;
+ }
+ else if (err_line[0] == '<') {
+ e = '>';
+ include:
+ for (i = 1; err_line[i] != e; ++i) {
+ if (err_line[i] == 0)
+ goto garbage;
+ }
+ err_line[i] = 0;
+ if (xify_include(err_line + 1, err_line[0] == '"' ? in_name : 0))
+ break;
+ }
+ else {
+ garbage:
+ fprintf(stderr, "Garbage from filter\n");
+ break;
+ }
+ fclose(err_fp);
+ while (t != wait(&status))
+ ;
+ if ((t=(status&0377)) != 0 && t!=14) {
+ if (t!=2) {
+ printf("Fatal error in %s\n", xify);
+ eflag = 8;
+ }
+ dexit();
+ }
+ return ((status>>8) & 0377);
+}
+
+int xify_include(in_name, prev_name) char *in_name; char *prev_name; {
+ int i, j;
+ struct stat statbuf;
+
+ if (prev_name) {
+ for (i = strlen(prev_name); i > 0 && prev_name[i - 1] != '/'; --i)
+ ;
+ bcopy(prev_name, in_path, i);
+ strcpy(in_path + i, in_name);
+ if (stat(in_path, &statbuf) == 0) {
+ i = -1;
+ goto found_local;
+ }
+ }
+ for (int i = 0; i < np; ++i)
+ if (/*plist[i][0] == '-' &&*/ plist[i][1] == 'I') {
+ j = strlen(plist[i] + 2) - 5; /* remove ".xify" */
+ bcopy(plist[i] + 2, in_path, j);
+ strcpy(in_path + j, in_name);
+ if (stat(in_path, &statbuf) == 0)
+ goto found_system;
+ }
+ error("not found: %s\n", in_name);
+ return 1;
+
+found_system:
+ /* see if it requires extra mkdir */
+ for (; in_path[j]; ++j)
+ if (in_path[j] == '/')
+ goto found_local;
+
+ /* it does not require extra mkdir */
+ i = -1;
+
+found_local:
+ for (j = 0; j < in_queue_tail; ++j)
+ if (strcmp(in_queue[j].path, in_path) == 0)
+ return 0;
+
+ if (in_queue_tail >= IN_QUEUE_SIZE) {
+ error("in queue full: %s\n", in_path);
+ return 1;
+ }
+
+ in_queue[in_queue_tail].path = savestr(in_path);
+ in_queue[in_queue_tail].mtime = statbuf.st_mtim;
+ in_queue[in_queue_tail].mkdir = i;
+ ++in_queue_tail;
+ return 0;
}
#endif