ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/common/path.C
Revision: 1.6
Committed: Sun Jul 1 05:00:17 2007 UTC (16 years, 11 months ago) by root
Content type: text/plain
Branch: MAIN
CVS Tags: rel-2_2, rel-2_3
Changes since 1.5: +11 -12 lines
Log Message:
- upgrade crossfire trt to the GPL version 3 (hopefully correctly).
- add a single file covered by the GNU Affero General Public License
  (which is not yet released, so I used the current draft, which is
  legally a bit wavy, but its likely better than nothing as it expresses
  direct intent by the authors, and we can upgrade as soon as it has been
  released).
  * this should ensure availability of source code for the server at least
    and hopefully also archetypes and maps even when modified versions
    are not being distributed, in accordance of section 13 of the agplv3.

File Contents

# Content
1 /*
2 * This file is part of Crossfire TRT, the Roguelike Realtime MORPG.
3 *
4 * Copyright (©) 2005,2006,2007 Marc Alexander Lehmann / Robin Redeker / the Crossfire TRT team
5 * Copyright (©) 2002,2007 Mark Wedel & Crossfire Development Team
6 * Copyright (©) 1992,2007 Frank Tore Johansen
7 *
8 * Crossfire TRT 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 <crossfire@schmorp.de>
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