ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/common/path.C
(Generate patch)

Comparing deliantra/server/common/path.C (file contents):
Revision 1.1 by elmex, Sun Aug 13 17:16:00 2006 UTC vs.
Revision 1.7 by root, Thu Nov 8 19:43:23 2007 UTC

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

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines