1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
|
/* filepath.c
*
* Copyright (c) 2014 Tharre
*
* This software may be modified and distributed under the terms
* of the MIT license. See the LICENSE file for details.
*/
#include <stdbool.h>
#include <assert.h>
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>
#include "util.h"
#define _FILENAME "build.c"
#include "dbg.h"
/* Check if the given path is absolute. */
bool is_absolute(const char* path) {
return path[0] == '/';
}
/* Returns a new copy of str with the extension removed, where the extension is
everything behind the last dot, including the dot. */
char *remove_ext(const char *str) {
assert(str);
size_t len;
char *ret, *dot = NULL;
for (len = 0; str[len]; ++len)
if (str[len] == '.')
dot = (char*) &str[len];
if (dot) /* recalculate length to only reach just before the last dot */
len = dot - str;
ret = xmalloc(len+1);
memcpy(ret, str, len);
ret[len] = '\0';
return ret;
}
/* Returns the extension of the target or the empty string if none was found. */
char *take_extension(const char *target) {
assert(target);
char *temp = strrchr(target, '.');
if (temp)
return temp;
else
return "";
}
/* Returns a pointer to a relative path to `path` from `start`. This pointer may
be pointing to either of it's arguments, or to the statically allocated
string "." should both paths match. Both paths must be canonicalized.
A few examples:
relpath("/abc/de", "/abc/de") => "."
relpath("some/path/a/b/c", "some/path") => "a/b/c"
relpath("some/path", "some/path/a/b/c") => "some/path/a/b/c"
relpath("/", "/") => "."
relpath("/abc", "/") => "abc"
*/
char *relpath(char *path, char *start) {
int i;
for (i = 0; path[i] && start[i]; ++i) {
if (path[i] != start[i])
return path; /* paths share nothing */
}
if (!path[i] && start[i])
return start; /* path is above start */
if (!path[i] && !start[i])
return "."; /* paths match completely */
if (path[i] == '/')
++i;
return &path[i];
}
/* Sane and portable basename implementation. */
char *xbasename(const char *path) {
assert(path);
char *ptr = strrchr(path, '/');
return ptr? ptr+1 : (char*) path;
}
/* Checks if target exists and prints a debug message if access() failed
except if it failed with ENOENT. */
bool fexists(const char *target) {
assert(target);
if (!access(target, F_OK))
return true;
if (errno != ENOENT)
debug("Failed to access %s: %s\n", target, strerror(errno));
return false;
}
/* Returns the size of fn, or -1 if the file doesn't exist. */
off_t fsize(const char *fn) {
struct stat st;
if (stat(fn, &st)) {
if (errno != ENOENT)
fatal("redo: failed to aquire stat() information about %s", fn);
return -1;
}
return st.st_size;
}
/* Create the target directory recursively much like `mkdir -p` */
void mkpath(char *path, mode_t mode) {
assert(path && *path);
char *p;
for (p=strchr(path+1, '/'); p; p=strchr(p+1, '/')) {
*p = '\0';
if (mkdir(path, mode) == -1)
if (errno != EEXIST)
fatal("redo: failed to mkdir() '%s'", path);
*p = '/';
}
}
|