aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--build.c58
1 files changed, 50 insertions, 8 deletions
diff --git a/build.c b/build.c
index b430fb2..621daa7 100644
--- a/build.c
+++ b/build.c
@@ -17,9 +17,10 @@
fprintf(stderr, __VA_ARGS__); } while(0);
#define MAXBUF 1024
-#define MAXCMDS 32 /* Maximum number of commands across all files. */
#define MAXCMD 1024
+#define MAXCMDS 32 /* Maximum number of commands across all files. */
#define MAXDEP 1024
+#define MAXPATH 1024
#define MAXTGT 64
extern char *optarg;
@@ -27,12 +28,13 @@ extern int optind;
void cleandep(char **);
void cleantgt(char **);
+char *dirname(char *);
char *nextdep(char **);
int
main(int argc, char *argv[])
{
- char *b, buf[MAXBUF], *cmd[MAXCMDS], *d, *dep, *name, *tgt;
+ char *b, buf[MAXBUF], *cmd[MAXCMDS], *d, *dep, *name, *tgt, wd[MAXPATH];
FILE *fp;
int c, dflag, fflag, i, icmd, j, s;
struct stat sb, ssb;
@@ -48,6 +50,13 @@ main(int argc, char *argv[])
tgt[0] = dep[0] = 0;
+ /*
+ * The original working directory is saved. (When acting on the
+ * build information in a file, the program temporarily moves into
+ * its directory.)
+ */
+ getcwd(wd, MAXPATH);
+
/* Process command-line flags (debug, force). */
name = argv[0];
dflag = fflag = 0;
@@ -72,8 +81,12 @@ main(int argc, char *argv[])
/* Process dependencies and commands in each file. */
for(i = icmd = 0; i < argc; i++, icmd = 0){
+
+ /* Return to original directory. */
+ chdir(wd);
+
if(!(fp = fopen(argv[i], "r")))
- err(1, "fopen");
+ err(1, "fopen(%s)", argv[i]);
/* Read line by line, at most twenty. */
for(j = 0; j < 20 && fgets(buf, MAXBUF, fp); j++){
@@ -115,21 +128,33 @@ main(int argc, char *argv[])
}
/* Build immediately if forced or no target found. */
- if(fflag || !*tgt)
+ if(fflag || !*tgt){
+ chdir(dirname(argv[i]));
goto build;
+ }
/* Trim shell meta-characters and whitespace. */
cleantgt(&tgt);
cleandep(&dep);
- /* Build immediately if source is newer than target. */
dd("%s: target '%s'\n", argv[i], tgt);
+
+ /* Get information about source. */
if(stat(argv[i], &sb))
- err(1, argv[i]);
+ err(1, "stat(%s)", argv[i]);
+
+ /*
+ * Subsequent operations should take place inside the
+ * directory of the source, as command lines and dependency
+ * lines may refer to relative paths.
+ */
+ chdir(dirname(argv[i]));
+
+ /* Build immediately if source is newer than target. */
if(stat(tgt, &ssb)){
if(errno == ENOENT)
goto build;
- err(1, tgt);
+ err(1, "stat(%s)", tgt);
}
if(sb.st_mtime > ssb.st_mtime){
d("%s: %s is modified, building\n",
@@ -154,7 +179,7 @@ main(int argc, char *argv[])
"does not exist\n", argv[i], d);
continue;
}
- err(1, d);
+ err(1, "stat(%s)", d);
}
if(sb.st_mtime > ssb.st_mtime){
d("%s: %s is modified, building\n", argv[i], d);
@@ -240,6 +265,23 @@ cleantgt(char **tgt)
}
char *
+dirname(char *file)
+{
+ char *dir;
+ int i;
+
+ if(!(dir = malloc(strlen(file)+1)))
+ err(1, "malloc");
+
+ for(i = strlen(file); i >= 0; i--)
+ if(file[i] == '/') break;
+ for(dir[i--] = 0; i >= 0; i--)
+ dir[i] = file[i];
+
+ return dir[0] ? dir : ".";
+}
+
+char *
nextdep(char **dep)
{
char *d;