ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/common/path.C
Revision: 1.3
Committed: Thu Sep 14 22:34:00 2006 UTC (17 years, 8 months ago) by root
Content type: text/plain
Branch: MAIN
CVS Tags: rel-2_0
Changes since 1.2: +0 -3 lines
Log Message:
indent

File Contents

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