ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/common/path.c
Revision: 1.2
Committed: Sun Aug 13 17:16:00 2006 UTC (17 years, 9 months ago) by elmex
Content type: text/plain
Branch: MAIN
CVS Tags: HEAD
Changes since 1.1: +1 -1 lines
State: FILE REMOVED
Log Message:
Made server compile with C++.
Removed cfanim plugin and crossedit.
C++ here we come.

File Contents

# Content
1 /* $Id$ */
2
3 #include <assert.h>
4 #include <stdio.h>
5 #include <string.h>
6 #include <global.h>
7
8 #include "define.h"
9 #include "path.h"
10
11
12 #if 0
13 /**
14 * Define DEBUG_PATH to enable debug output.
15 */
16 #define DEBUG_PATH
17 #endif
18
19 #if 0
20 /**
21 * Define TEST_PATH to compile this file as a stand-alone self-test application
22 * for the functions.
23 */
24 #define TEST_PATH
25
26 #define LOG fprintf
27 #define llevDebug stderr
28 #define llevError stderr
29 #endif
30
31
32 char *path_combine(const char *src, const char *dst) {
33 char *p;
34 static char path[HUGE_BUF];
35
36 if (*dst == '/') {
37 /* absolute destination path => ignore source path */
38 strcpy(path, dst);
39 } else {
40 /* relative destination path => add after last '/' of source */
41 strcpy(path, src);
42 p = strrchr(path, '/');
43 if (p != NULL) {
44 p++;
45 } else {
46 p = path;
47 if (*src == '/')
48 *p++ = '/';
49 }
50 strcpy(p, dst);
51 }
52
53 #if defined(DEBUG_PATH)
54 LOG(llevDebug, "path_combine(%s, %s) = %s\n", src, dst, path);
55 #endif
56 return(path);
57 }
58
59 void path_normalize(char *path) {
60 char *p; /* points to the beginning of the path not yet processed; this is
61 either a path component or a path separator character */
62 char *q; /* points to the end of the path component p points to */
63 char *w; /* points to the end of the already normalized path; w <= p is
64 maintained */
65 size_t len; /* length of current component (which p points to) */
66
67 #if defined(DEBUG_PATH)
68 LOG(llevDebug, "path_normalize: input '%s'\n", path);
69 #endif
70
71 p = path;
72 w = p;
73 while (*p != '\0') {
74
75 if (*p == '/') {
76 if ((w == path && *path == '/') || (w > path && w[-1] != '/'))
77 *w++ = '/';
78 p++;
79 continue;
80 }
81
82 q = strchr(p, '/');
83 if (q == NULL)
84 q = p+strlen(p);
85 len = q-p;
86 assert(len > 0);
87
88 #if defined(DEBUG_PATH)
89 LOG(llevDebug, "path_normalize: checking '%.*s'\n", (int)len, p);
90 #endif
91
92 if (len == 1 && *p == '.') {
93 /* remove current component */
94 } else if (len == 2 && memcmp(p, "..", 2) == 0) {
95 if (w == path || (w == path+3 && memcmp(path, "../", 3) == 0)) {
96 /* keep ".." at beginning of relative path ("../x" => "../x") */
97 memmove(w, p, len);
98 w += len;
99 } else if (w == path+1 && *path == '/') {
100 /* remove ".." at beginning of absolute path ("/../x" => "/x") */
101 } else {
102 /* remove both current component ".." and preceding one */
103 if (w > path && w[-1] == '/')
104 w--;
105 while (w > path && w[-1] != '/')
106 w--;
107 }
108 } else {
109 /* normal component ==> add it */
110 memmove(w, p, len);
111 w += len;
112 }
113
114 p = q;
115
116 #if defined(DEBUG_PATH)
117 LOG(llevDebug, "path_normalize: so far '%.*s'\n", (int)(w-path), path);
118 #endif
119 }
120
121 /* remove trailing slashes, but keep the one at the start of the path */
122 while (w > path+1 && w[-1] == '/') {
123 w--;
124 }
125
126 *w = '\0';
127
128 #if defined(DEBUG_PATH)
129 LOG(llevDebug, "path_normalize: result '%s'\n", path);
130 #endif
131 }
132
133 char *path_combine_and_normalize(const char *src, const char *dst) {
134 char *path;
135
136 path = path_combine(src, dst);
137 path_normalize(path);
138 return(path);
139 }
140
141 #if defined(TEST_PATH)
142 static void check_combine(const char *src, const char *dst, const char *exp) {
143 const char *res;
144
145 fprintf(stderr, "path_combine(%s, %s) = ", src, dst);
146 res = path_combine(src, dst);
147 fprintf(stderr, "%s", res);
148 if (strcmp(res, exp) != 0) {
149 fprintf(stderr, ", should be %s\n", exp);
150 } else {
151 fprintf(stderr, " (OK)\n");
152 }
153 }
154
155 static void check_normalize(const char *path, const char *exp0) {
156 char tmp[HUGE_BUF];
157 char exp[HUGE_BUF];
158
159 strcpy(exp, exp0 == NULL ? path : exp0);
160
161 strcpy(tmp, path);
162 fprintf(stderr, "path_normalize(%s) = ", tmp);
163 path_normalize(tmp);
164 fprintf(stderr, "%s", tmp);
165 if (strcmp(tmp, exp) != 0) {
166 fprintf(stderr, ", should be %s\n", exp);
167 } else {
168 fprintf(stderr, " (OK)\n");
169 }
170 }
171
172 static void check_combine_and_normalize(const char *src, const char *dst, const char *exp) {
173 const char *res;
174
175 fprintf(stderr, "path_combine_and_normalize(%s, %s) = ", src, dst);
176 res = path_combine_and_normalize(src, dst);
177 fprintf(stderr, "%s", res);
178 if (strcmp(res, exp) != 0) {
179 fprintf(stderr, ", should be %s\n", exp);
180 } else {
181 fprintf(stderr, " (OK)\n");
182 }
183 }
184
185 int main() {
186 check_combine("/path1/file1", "/path2/file2", "/path2/file2");
187 check_combine("path1/file1", "/path2/file2", "/path2/file2");
188 check_combine("/path1/file1", "path2/file2", "/path1/path2/file2");
189 check_combine("path1/file1", "path2/file2", "path1/path2/file2");
190 check_combine("/path1", "/path2", "/path2");
191 check_combine("path1", "/path2", "/path2");
192 check_combine("/path1", "path2", "/path2");
193 check_combine("path1", "path2", "path2");
194
195 check_normalize("", NULL);
196 check_normalize("/", NULL);
197 check_normalize("path1/file1", NULL);
198 check_normalize("/path1/file1", NULL);
199 check_normalize("/path1//file1", "/path1/file1");
200 check_normalize("//path1/file1", "/path1/file1");
201 check_normalize("///////x////////y///////z////////", "/x/y/z");
202 check_normalize("/a/b/../c/d/../e/../../f/g/../h", "/a/f/h");
203 check_normalize("//a//b//..//c//d//..//e//..//..//f//g//..//h", "/a/f/h");
204 check_normalize("../a", NULL);
205 check_normalize("a/../../b", "../b");
206 check_normalize("/../a", "/a");
207 check_normalize("/a/../../b", "/b");
208 check_normalize("./b/./c/.d/..e/./f", "b/c/.d/..e/f");
209 check_normalize("/b/././././e", "/b/e");
210 check_normalize(".", ""); /* maybe the result should be "."? */
211 check_normalize("/.", "/");
212 check_normalize("./", ""); /* maybe the result should be "."? */
213 check_normalize("/a/b/..", "/a");
214 check_normalize("/a/b/../..", "/");
215 check_normalize("/a/b/../../..", "/");
216 check_normalize("a/b/..", "a");
217 check_normalize("a/b/../..", "");
218 check_normalize("a/b/../../..", "..");
219
220 check_combine_and_normalize("/path1/file1", "/path2/file2", "/path2/file2");
221 check_combine_and_normalize("path1/file1", "/path2/file2", "/path2/file2");
222 check_combine_and_normalize("/path1/file1", "path2/file2", "/path1/path2/file2");
223 check_combine_and_normalize("/path1", "/path2", "/path2");
224 check_combine_and_normalize("path1", "/path2", "/path2");
225 check_combine_and_normalize("/path1", "path2", "/path2");
226 check_combine_and_normalize("/path1/file1/../u", "path2/x/../y/z/../a/b/..", "/path1/path2/y/a");
227 check_combine_and_normalize("/path1/file1", "/path2//file2", "/path2/file2");
228 check_combine_and_normalize("/path1/file1", "/..", "/");
229 check_combine_and_normalize("/path1/file1", "../x", "/x");
230 check_combine_and_normalize("/path1/file1", "../../../x", "/x");
231 check_combine_and_normalize("/path1/file1", "/.x/..x/...x/x", "/.x/..x/...x/x");
232
233 return(0);
234 }
235 #endif