]> wimlib.net Git - wimlib/blob - src/paths.c
Adjust path matching
[wimlib] / src / paths.c
1 /*
2  * paths.c - Path manipulation routines
3  */
4
5 /*
6  * Copyright (C) 2012, 2013 Eric Biggers
7  *
8  * This file is part of wimlib, a library for working with WIM files.
9  *
10  * wimlib is free software; you can redistribute it and/or modify it under the
11  * terms of the GNU General Public License as published by the Free
12  * Software Foundation; either version 3 of the License, or (at your option)
13  * any later version.
14  *
15  * wimlib is distributed in the hope that it will be useful, but WITHOUT ANY
16  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
17  * A PARTICULAR PURPOSE. See the GNU General Public License for more
18  * details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with wimlib; if not, see http://www.gnu.org/licenses/.
22  */
23
24 #ifdef HAVE_CONFIG_H
25 #  include "config.h"
26 #endif
27
28 #include "wimlib.h"
29 #include "wimlib/paths.h"
30 #include "wimlib/util.h"
31
32 #include <string.h>
33
34 /* Like the basename() function, but does not modify @path; it just returns a
35  * pointer to it.  This assumes the path separator is the
36  * OS_PREFERRED_PATH_SEPARATOR.  */
37 const tchar *
38 path_basename(const tchar *path)
39 {
40         return path_basename_with_len(path, tstrlen(path));
41 }
42
43 /* Like path_basename(), but take an explicit string length.  */
44 const tchar *
45 path_basename_with_len(const tchar *path, size_t len)
46 {
47         const tchar *p = &path[len];
48
49         do {
50                 if (p == path)
51                         return &path[len];
52         } while (*--p == OS_PREFERRED_PATH_SEPARATOR);
53
54         do {
55                 if (p == path)
56                         return &path[0];
57         } while (*--p != OS_PREFERRED_PATH_SEPARATOR);
58
59         return ++p;
60 }
61
62
63 /* Returns a pointer to the part of @path following the first colon in the last
64  * path component, or NULL if the last path component does not contain a colon
65  * or has no characters following the first colon.  */
66 const tchar *
67 path_stream_name(const tchar *path)
68 {
69         const tchar *base = path_basename(path);
70         const tchar *stream_name = tstrchr(base, T(':'));
71         if (stream_name == NULL || *(stream_name + 1) == T('\0'))
72                 return NULL;
73         else
74                 return stream_name + 1;
75 }
76
77 /* Duplicate a path; return empty string for NULL input.  */
78 tchar *
79 canonicalize_fs_path(const tchar *fs_path)
80 {
81         if (fs_path == NULL)
82                 fs_path = T("");
83         return TSTRDUP(fs_path);
84 }
85
86 /* Collapse and translate path separators, and strip trailing slashes.  Doesn't
87  * add or delete a leading slash.
88  *
89  * @in may alias @out.
90  */
91 void
92 do_canonicalize_path(const tchar *in, tchar *out)
93 {
94         tchar *orig_out = out;
95
96         while (*in) {
97                 if (is_any_path_separator(*in)) {
98                         /* Collapse multiple path separators into one  */
99                         *out++ = WIM_PATH_SEPARATOR;
100                         do {
101                                 in++;
102                         } while (is_any_path_separator(*in));
103                 } else {
104                         /* Copy non-path-separator character  */
105                         *out++ = *in++;
106                 }
107         }
108
109         /* Remove trailing slash if existent  */
110         if (out - orig_out > 1 && *(out - 1) == WIM_PATH_SEPARATOR)
111                 --out;
112
113         *out = T('\0');
114 }
115
116 /*
117  * canonicalize_wim_path() - Given a user-provided path to a file within a WIM
118  * image, translate it into a "canonical" path.
119  *
120  * - Translate both types of slash into a consistent type (WIM_PATH_SEPARATOR).
121  * - Collapse path separators.
122  * - Add leading slash if missing.
123  * - Strip trailing slashes.
124  *
125  * Examples (with WIM_PATH_SEPARATOR == '/'):
126  *
127  *              => /            [ either NULL or empty string ]
128  * /            => /
129  * \            => /
130  * hello        => /hello
131  * \hello       => /hello
132  * \hello       => /hello
133  * /hello/      => /hello
134  * \hello/      => /hello
135  * /hello//1    => /hello/1
136  * \\hello\\1\\ => /hello/1
137  */
138 tchar *
139 canonicalize_wim_path(const tchar *wim_path)
140 {
141         const tchar *in;
142         tchar *out;
143         tchar *result;
144
145         in = wim_path;
146         if (!in)
147                 in = T("");
148
149         result = MALLOC((1 + tstrlen(in) + 1) * sizeof(result[0]));
150         if (!result)
151                 return NULL;
152
153         out = result;
154
155         /* Add leading slash if missing  */
156         if (!is_any_path_separator(*in))
157                 *out++ = WIM_PATH_SEPARATOR;
158
159         do_canonicalize_path(in, out);
160
161         return result;
162 }