ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/common/path.C
Revision: 1.7
Committed: Thu Nov 8 19:43:23 2007 UTC (16 years, 6 months ago) by root
Content type: text/plain
Branch: MAIN
CVS Tags: rel-2_4, rel-2_5, rel-2_52, rel-2_53, rel-2_32, rel-2_43, rel-2_42, rel-2_41
Changes since 1.6: +4 -4 lines
Log Message:
update copyrights and other minor stuff to deliantra

File Contents

# Content
1 /*
2 * This file is part of Deliantra, the Roguelike Realtime MMORPG.
3 *
4 * Copyright (©) 2005,2006,2007 Marc Alexander Lehmann / Robin Redeker / the Deliantra team
5 * Copyright (©) 2002,2007 Mark Wedel & Crossfire Development Team
6 * Copyright (©) 1992,2007 Frank Tore Johansen
7 *
8 * Deliantra is free software: you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation, either version 3 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program. If not, see <http://www.gnu.org/licenses/>.
20 *
21 * The authors can be reached via e-mail to <support@deliantra.net>
22 */
23
24 #include <assert.h>
25 #include <stdio.h>
26 #include <string.h>
27 #include <global.h>
28
29 #include "define.h"
30 #include "path.h"
31
32
33 #if 0
34
35 /**
36 * Define DEBUG_PATH to enable debug output.
37 */
38 # define DEBUG_PATH
39 #endif
40
41 #if 0
42
43 /**
44 * Define TEST_PATH to compile this file as a stand-alone self-test application
45 * for the functions.
46 */
47 # define TEST_PATH
48
49 # define LOG fprintf
50 # define llevDebug stderr
51 # define llevError stderr
52 #endif
53
54
55 char *
56 path_combine (const char *src, const char *dst)
57 {
58 char *p;
59 static char path[HUGE_BUF];
60
61 if (*dst == '/')
62 {
63 /* absolute destination path => ignore source path */
64 strcpy (path, dst);
65 }
66 else
67 {
68 /* relative destination path => add after last '/' of source */
69 strcpy (path, src);
70 p = strrchr (path, '/');
71 if (p != NULL)
72 {
73 p++;
74 }
75 else
76 {
77 p = path;
78 if (*src == '/')
79 *p++ = '/';
80 }
81 strcpy (p, dst);
82 }
83
84 #if defined(DEBUG_PATH)
85 LOG (llevDebug, "path_combine(%s, %s) = %s\n", src, dst, path);
86 #endif
87 return (path);
88 }
89
90 void
91 path_normalize (char *path)
92 {
93 char *p; /* points to the beginning of the path not yet processed; this is
94 either a path component or a path separator character */
95 char *q; /* points to the end of the path component p points to */
96 char *w; /* points to the end of the already normalized path; w <= p is
97 maintained */
98 size_t len; /* length of current component (which p points to) */
99
100 #if defined(DEBUG_PATH)
101 LOG (llevDebug, "path_normalize: input '%s'\n", path);
102 #endif
103
104 p = path;
105 w = p;
106 while (*p != '\0')
107 {
108
109 if (*p == '/')
110 {
111 if ((w == path && *path == '/') || (w > path && w[-1] != '/'))
112 *w++ = '/';
113 p++;
114 continue;
115 }
116
117 q = strchr (p, '/');
118 if (q == NULL)
119 q = p + strlen (p);
120 len = q - p;
121 assert (len > 0);
122
123 #if defined(DEBUG_PATH)
124 LOG (llevDebug, "path_normalize: checking '%.*s'\n", (int) len, p);
125 #endif
126
127 if (len == 1 && *p == '.')
128 {
129 /* remove current component */
130 }
131 else if (len == 2 && memcmp (p, "..", 2) == 0)
132 {
133 if (w == path || (w == path + 3 && memcmp (path, "../", 3) == 0))
134 {
135 /* keep ".." at beginning of relative path ("../x" => "../x") */
136 memmove (w, p, len);
137 w += len;
138 }
139 else if (w == path + 1 && *path == '/')
140 {
141 /* remove ".." at beginning of absolute path ("/../x" => "/x") */
142 }
143 else
144 {
145 /* remove both current component ".." and preceding one */
146 if (w > path && w[-1] == '/')
147 w--;
148 while (w > path && w[-1] != '/')
149 w--;
150 }
151 }
152 else
153 {
154 /* normal component ==> add it */
155 memmove (w, p, len);
156 w += len;
157 }
158
159 p = q;
160
161 #if defined(DEBUG_PATH)
162 LOG (llevDebug, "path_normalize: so far '%.*s'\n", (int) (w - path), path);
163 #endif
164 }
165
166 /* remove trailing slashes, but keep the one at the start of the path */
167 while (w > path + 1 && w[-1] == '/')
168 {
169 w--;
170 }
171
172 *w = '\0';
173
174 #if defined(DEBUG_PATH)
175 LOG (llevDebug, "path_normalize: result '%s'\n", path);
176 #endif
177 }
178
179 char *
180 path_combine_and_normalize (const char *src, const char *dst)
181 {
182 char *path;
183
184 path = path_combine (src, dst);
185 path_normalize (path);
186 return (path);
187 }
188
189 #if defined(TEST_PATH)
190 static void
191 check_combine (const char *src, const char *dst, const char *exp)
192 {
193 const char *res;
194
195 fprintf (stderr, "path_combine(%s, %s) = ", src, dst);
196 res = path_combine (src, dst);
197 fprintf (stderr, "%s", res);
198 if (strcmp (res, exp) != 0)
199 {
200 fprintf (stderr, ", should be %s\n", exp);
201 }
202 else
203 {
204 fprintf (stderr, " (OK)\n");
205 }
206 }
207
208 static void
209 check_normalize (const char *path, const char *exp0)
210 {
211 char tmp[HUGE_BUF];
212 char exp[HUGE_BUF];
213
214 strcpy (exp, exp0 == NULL ? path : exp0);
215
216 strcpy (tmp, path);
217 fprintf (stderr, "path_normalize(%s) = ", tmp);
218 path_normalize (tmp);
219 fprintf (stderr, "%s", tmp);
220 if (strcmp (tmp, exp) != 0)
221 {
222 fprintf (stderr, ", should be %s\n", exp);
223 }
224 else
225 {
226 fprintf (stderr, " (OK)\n");
227 }
228 }
229
230 static void
231 check_combine_and_normalize (const char *src, const char *dst, const char *exp)
232 {
233 const char *res;
234
235 fprintf (stderr, "path_combine_and_normalize(%s, %s) = ", src, dst);
236 res = path_combine_and_normalize (src, dst);
237 fprintf (stderr, "%s", res);
238 if (strcmp (res, exp) != 0)
239 {
240 fprintf (stderr, ", should be %s\n", exp);
241 }
242 else
243 {
244 fprintf (stderr, " (OK)\n");
245 }
246 }
247
248 int
249 main ()
250 {
251 check_combine ("/path1/file1", "/path2/file2", "/path2/file2");
252 check_combine ("path1/file1", "/path2/file2", "/path2/file2");
253 check_combine ("/path1/file1", "path2/file2", "/path1/path2/file2");
254 check_combine ("path1/file1", "path2/file2", "path1/path2/file2");
255 check_combine ("/path1", "/path2", "/path2");
256 check_combine ("path1", "/path2", "/path2");
257 check_combine ("/path1", "path2", "/path2");
258 check_combine ("path1", "path2", "path2");
259
260 check_normalize ("", NULL);
261 check_normalize ("/", NULL);
262 check_normalize ("path1/file1", NULL);
263 check_normalize ("/path1/file1", NULL);
264 check_normalize ("/path1//file1", "/path1/file1");
265 check_normalize ("//path1/file1", "/path1/file1");
266 check_normalize ("///////x////////y///////z////////", "/x/y/z");
267 check_normalize ("/a/b/../c/d/../e/../../f/g/../h", "/a/f/h");
268 check_normalize ("//a//b//..//c//d//..//e//..//..//f//g//..//h", "/a/f/h");
269 check_normalize ("../a", NULL);
270 check_normalize ("a/../../b", "../b");
271 check_normalize ("/../a", "/a");
272 check_normalize ("/a/../../b", "/b");
273 check_normalize ("./b/./c/.d/..e/./f", "b/c/.d/..e/f");
274 check_normalize ("/b/././././e", "/b/e");
275 check_normalize (".", ""); /* maybe the result should be "."? */
276 check_normalize ("/.", "/");
277 check_normalize ("./", ""); /* maybe the result should be "."? */
278 check_normalize ("/a/b/..", "/a");
279 check_normalize ("/a/b/../..", "/");
280 check_normalize ("/a/b/../../..", "/");
281 check_normalize ("a/b/..", "a");
282 check_normalize ("a/b/../..", "");
283 check_normalize ("a/b/../../..", "..");
284
285 check_combine_and_normalize ("/path1/file1", "/path2/file2", "/path2/file2");
286 check_combine_and_normalize ("path1/file1", "/path2/file2", "/path2/file2");
287 check_combine_and_normalize ("/path1/file1", "path2/file2", "/path1/path2/file2");
288 check_combine_and_normalize ("/path1", "/path2", "/path2");
289 check_combine_and_normalize ("path1", "/path2", "/path2");
290 check_combine_and_normalize ("/path1", "path2", "/path2");
291 check_combine_and_normalize ("/path1/file1/../u", "path2/x/../y/z/../a/b/..", "/path1/path2/y/a");
292 check_combine_and_normalize ("/path1/file1", "/path2//file2", "/path2/file2");
293 check_combine_and_normalize ("/path1/file1", "/..", "/");
294 check_combine_and_normalize ("/path1/file1", "../x", "/x");
295 check_combine_and_normalize ("/path1/file1", "../../../x", "/x");
296 check_combine_and_normalize ("/path1/file1", "/.x/..x/...x/x", "/.x/..x/...x/x");
297
298 return (0);
299 }
300 #endif