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, 10 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

# User Rev Content
1 root 1.4 /*
2 root 1.6 * This file is part of Crossfire TRT, the Roguelike Realtime MORPG.
3 root 1.4 *
4 root 1.5 * 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 root 1.4 *
8 root 1.6 * 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 root 1.4 *
13 root 1.6 * 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 root 1.4 *
18 root 1.6 * 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 root 1.5 *
21     * The authors can be reached via e-mail to <crossfire@schmorp.de>
22 root 1.4 */
23    
24 elmex 1.1 #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 root 1.2
35 elmex 1.1 /**
36     * Define DEBUG_PATH to enable debug output.
37     */
38 root 1.2 # define DEBUG_PATH
39 elmex 1.1 #endif
40    
41     #if 0
42 root 1.2
43 elmex 1.1 /**
44     * Define TEST_PATH to compile this file as a stand-alone self-test application
45     * for the functions.
46     */
47 root 1.2 # define TEST_PATH
48 elmex 1.1
49 root 1.2 # define LOG fprintf
50     # define llevDebug stderr
51     # define llevError stderr
52 elmex 1.1 #endif
53    
54    
55 root 1.2 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 elmex 1.1 }
81 root 1.2 strcpy (p, dst);
82 elmex 1.1 }
83    
84     #if defined(DEBUG_PATH)
85 root 1.2 LOG (llevDebug, "path_combine(%s, %s) = %s\n", src, dst, path);
86 elmex 1.1 #endif
87 root 1.2 return (path);
88 elmex 1.1 }
89    
90 root 1.2 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 elmex 1.1
100     #if defined(DEBUG_PATH)
101 root 1.2 LOG (llevDebug, "path_normalize: input '%s'\n", path);
102 elmex 1.1 #endif
103    
104 root 1.2 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 elmex 1.1 }
116    
117 root 1.2 q = strchr (p, '/');
118     if (q == NULL)
119     q = p + strlen (p);
120     len = q - p;
121     assert (len > 0);
122 elmex 1.1
123     #if defined(DEBUG_PATH)
124 root 1.2 LOG (llevDebug, "path_normalize: checking '%.*s'\n", (int) len, p);
125 elmex 1.1 #endif
126    
127 root 1.2 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 elmex 1.1 }
151 root 1.2 }
152     else
153     {
154     /* normal component ==> add it */
155     memmove (w, p, len);
156     w += len;
157 elmex 1.1 }
158    
159 root 1.2 p = q;
160 elmex 1.1
161     #if defined(DEBUG_PATH)
162 root 1.2 LOG (llevDebug, "path_normalize: so far '%.*s'\n", (int) (w - path), path);
163 elmex 1.1 #endif
164     }
165    
166 root 1.2 /* remove trailing slashes, but keep the one at the start of the path */
167     while (w > path + 1 && w[-1] == '/')
168     {
169     w--;
170 elmex 1.1 }
171    
172 root 1.2 *w = '\0';
173 elmex 1.1
174     #if defined(DEBUG_PATH)
175 root 1.2 LOG (llevDebug, "path_normalize: result '%s'\n", path);
176 elmex 1.1 #endif
177     }
178    
179 root 1.2 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 elmex 1.1
208 root 1.2 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 elmex 1.1 }
229    
230 root 1.2 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 elmex 1.1
248 root 1.2 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 elmex 1.1
298 root 1.2 return (0);
299 elmex 1.1 }
300     #endif