ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/common/path.C
Revision: 1.2
Committed: Sun Sep 10 16:00:23 2006 UTC (17 years, 8 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.1: +216 -171 lines
Log Message:
indent

File Contents

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