summaryrefslogtreecommitdiff
path: root/src/user/lib/fwik/io/Node.cpp
blob: 5585aa89a99e094b053e81745800670465154e9f (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
#include <IO/Node.h>

Node::Node(FILE f) {
	fd = f;
	error = libc::statf(f, &info);
}

Node::Node(const char* filename, int mode) {
	fd = libc::open(filename, mode);
	if (fd < 0) {
		if (fd != E_NOT_FOUND) error = libc::stat(filename, &info);
	} else {
		int i = libc::statf(fd, &info);
		error = i;
		if (error < 0) libc::close(fd);
	}
}

Node::Node(FILE parent, const char* filename, int mode) {
	fd = libc::open_relative(parent, filename, mode);
	if (fd < 0) {
		if (fd != E_NOT_FOUND) error = libc::stat_relative(parent, filename, &info);
	} else {
		int i = libc::statf(fd, &info);
		error = i;
		if (error < 0) libc::close(fd);
	}
}

void Node::close() {
	if (error == 0) libc::close(fd);
	error = E_INVALID_FD;
}

////////

static void simplify_path(char* p) {
	char *it = p;
	char *member = it;
	while (*it != 0) {
		if (*it == '/') {
			if (it == member && it != p) {
				// two consecutive slashes
				char *i = member;
				while (1) {
					i[0] = i[1];
					if (i[0] == 0) break;
					i++;
				}
			} else {
				*it = 0;
				if (libc::strcmp(member, ".") == 0) {
					char *i = member;
					while (1) {
						i[0] = i[2];
						if (i[0] == 0) break;
						i++;
					}
				} else if (libc::strcmp(member, "..") == 0) {
					*it = '/';
					char* start = member - 2;
					char* next = member + 3;
					while (start > p && *start != '/') {
						start--;
					}
					start++;
					it = member = start;
					while (1) {
						*start = *next;
						if (*start == 0) break;
						start++;
						next++;
					}
				} else {
					*it = '/';
					it++;
					member = it;
				}
			}
		} else {
			it++;
		}
	}
}

String path_cat(const String &a, const String &b, bool trailing_slash) {
	int len, la = a.size(), lb = b.size();
	if (b[0] == '/') {
		len = lb + 2;
	} else {
		len = la + lb + 3;
	}
	char buf[len];
	if (b[0] == '/') {
		libc::memcpy(buf, b.c_str(), lb);
		if (buf[lb-1] != '/') {
			buf[lb++] = '/';
		}
		buf[lb] = 0;
	} else {
		libc::memcpy(buf, a.c_str(), la);
		if (buf[la-1] != '/') {
			buf[la++] = '/';
		}
		libc::memcpy(buf + la, b.c_str(), lb);
		if (buf[la + lb - 1] != '/') {
			buf[la + lb] = '/';
			lb++;
		}
		buf[la + lb] = 0;
	}
	simplify_path(buf);
	if (!trailing_slash) {
		int l = libc::strlen(buf);
		if (buf[l-1] == '/') buf[l-1] = 0;
	}
	return String(buf);
}