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.4 by root, Thu May 17 21:32:08 2007 UTC

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

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines