aboutsummaryrefslogtreecommitdiffstats
path: root/src/filepath.c
blob: b8b217a79f4e5ee1042df229b6f2c85201cbc75a (plain) (blame)
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
#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 = safe_malloc(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 "";
}

/* Make one path relative to another i.e. some/path to some/path/a/b/c would
   yield a/b/c as result. Prints '.' if the 2 paths match */
// TODO: nameing, requires absolute paths, doesn't MALLOC
const char *make_relative(const char *target, const char *to) {
    int i;
    for (i = 0; target[i] && to[i]; ++i)
        if (target[i] != to[i]) {
            /* the paths do not match */
            return to;
        }

    if (!target[i] && !to[i]) {
        /* both paths match completely */
        return ".";
    }

    /* skip any leading seperators */
    while (to[i] == '/')
        ++i;

    return &to[i];
}

/* Transforms target into a safe filename, replacing all '/' with '!' */
char *transform_path(const char *target) {
    char *ptr = (char*) target;
    size_t escape = 0, i = 0;
    while (*ptr++)
        if (*ptr == '!') escape++;

    ptr = safe_malloc((ptr-target) + escape + 1);
    do {
        if (*target == '/')
            ptr[i++] = '!';
        else if (*target == '!') {
            ptr[i++] = '!';
            ptr[i++] = '!';
        } else
            ptr[i++] = *target;
    } while (*target++);

    ptr[i] = '\0';
    return ptr;
}

/* 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(ERRM_STAT, fn);
        return -1;
    }

    return st.st_size;
}