Refactor headers
[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/paths.h"
29 #include "wimlib/util.h"
30
31 #include <string.h>
32
33 /* Like the basename() function, but does not modify @path; it just returns a
34  * pointer to it. */
35 const tchar *
36 path_basename(const tchar *path)
37 {
38         return path_basename_with_len(path, tstrlen(path));
39 }
40
41 /* Like path_basename(), but take an explicit string length. */
42 const tchar *
43 path_basename_with_len(const tchar *path, size_t len)
44 {
45         const tchar *p = &path[len] - 1;
46
47         /* Trailing slashes. */
48         while (1) {
49                 if (p == path - 1)
50                         return T("");
51                 if (*p != T('/'))
52                         break;
53                 p--;
54         }
55
56         while ((p != path - 1) && *p != T('/'))
57                 p--;
58
59         return p + 1;
60 }
61
62
63 /*
64  * Returns a pointer to the part of @path following the first colon in the last
65  * path component, or NULL if the last path component does not contain a colon.
66  */
67 const tchar *
68 path_stream_name(const tchar *path)
69 {
70         const tchar *base = path_basename(path);
71         const tchar *stream_name = tstrchr(base, T(':'));
72         if (!stream_name)
73                 return NULL;
74         else
75                 return stream_name + 1;
76 }
77
78
79 /* Translate backslashes to forward slashes in-place. */
80 void
81 zap_backslashes(tchar *s)
82 {
83         if (s) {
84                 while (*s != T('\0')) {
85                         if (*s == T('\\'))
86                                 *s = T('/');
87                         s++;
88                 }
89         }
90 }
91
92 /* Duplicate a path, with backslashes translated into forward slashes; return
93  * empty string for NULL input. */
94 tchar *
95 canonicalize_fs_path(const tchar *fs_path)
96 {
97         tchar *canonical_path;
98
99         if (!fs_path)
100                 fs_path = T("");
101         canonical_path = TSTRDUP(fs_path);
102         zap_backslashes(canonical_path);
103         return canonical_path;
104 }
105
106 /* Duplicate a path, with backslashes translated into forward slashes; return
107  * empty string for NULL input;  also strip leading and trailing slashes. */
108 tchar *
109 canonicalize_wim_path(const tchar *wim_path)
110 {
111         tchar *p;
112         tchar *canonical_path;
113
114         if (wim_path == NULL) {
115                 wim_path = T("");
116         } else {
117                 while (*wim_path == T('/') || *wim_path == T('\\'))
118                         wim_path++;
119         }
120         canonical_path = TSTRDUP(wim_path);
121         if (canonical_path) {
122                 zap_backslashes(canonical_path);
123                 for (p = tstrchr(canonical_path, T('\0')) - 1;
124                      p >= canonical_path && *p == T('/');
125                      p--)
126                 {
127                         *p = T('\0');
128                 }
129         }
130         return canonical_path;
131 }