]> git.cworth.org Git - apitrace/blob - common/os_path.hpp
More os::Path fixes.
[apitrace] / common / os_path.hpp
1 /**************************************************************************
2  *
3  * Copyright 2011 Jose Fonseca
4  * All Rights Reserved.
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a copy
7  * of this software and associated documentation files (the "Software"), to deal
8  * in the Software without restriction, including without limitation the rights
9  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10  * copies of the Software, and to permit persons to whom the Software is
11  * furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be included in
14  * all copies or substantial portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22  * THE SOFTWARE.
23  *
24  **************************************************************************/
25
26 /*
27  * Path manipulation.
28  */
29
30 #ifndef _OS_PATH_HPP_
31 #define _OS_PATH_HPP_
32
33
34 #include <assert.h>
35 #include <stdarg.h>
36 #include <stdio.h>
37 #include <stddef.h>
38
39 #ifdef __MINGW32__
40 // Some versions of are missing _vscprintf's decleration, although still
41 // provide the symbol in the import library.
42 extern "C" _CRTIMP int _vscprintf(const char *format, va_list argptr);
43 #endif
44
45 #ifndef va_copy
46 #ifdef __va_copy
47 #define va_copy(dest, src) __va_copy((dest), (src))
48 #else
49 #define va_copy(dest, src) (dest) = (src)
50 #endif
51 #endif
52
53 #include <vector>
54
55 #include "os.hpp"
56
57
58 #ifdef _WIN32
59 #define OS_DIR_SEP '\\'
60 #else /* !_WIN32 */
61 #define OS_DIR_SEP '/'
62 #endif /* !_WIN32 */
63
64
65 namespace os {
66
67
68 class Path {
69 protected:
70     typedef std::vector<char> Buffer;
71     Buffer buffer;
72
73     Buffer::iterator rfind(char c) {
74         Buffer::iterator it = buffer.end();
75         assert(it != buffer.begin());
76         --it; // skill null
77         while (it != buffer.begin()) {
78             --it;
79             if (*it == c) {
80                 return it;
81             }
82         }
83         return buffer.end();
84     }
85
86     Path(size_t size) :
87         buffer(size) {
88     }
89
90     char *buf(void) {
91         return &buffer[0];
92     }
93
94 public:
95     Path() {
96         buffer.push_back(0);
97     }
98
99     Path(const char *s) :
100         buffer(s, s + strlen(s) + 1)
101     {}
102
103     template <class InputIterator>
104     Path(InputIterator first, InputIterator last) :
105         buffer(first, last)
106     {
107         buffer.push_back(0);
108     }
109
110     char *buf(size_t size) {
111         buffer.resize(size);
112         return &buffer[0];
113     }
114
115     void trimDirectory(void) {
116         Buffer::iterator sep = rfind(OS_DIR_SEP);
117         if (sep != buffer.end()) {
118             buffer.erase(buffer.begin(), sep + 1);
119         }
120     }
121
122     void trimExtension(void) {
123         Buffer::iterator dot = rfind('.');
124         if (dot != buffer.end()) {
125             buffer.erase(dot, buffer.end() - 1);
126         }
127     }
128
129     size_t length(void) const {
130         size_t size = buffer.size();
131         assert(size > 0);
132         assert(buffer[size - 1] == 0);
133         return size - 1;
134     }
135
136     void truncate(size_t length) {
137         assert(length < buffer.size());
138         buffer[length] = 0;
139         buffer.resize(length + 1);
140     }
141
142     void truncate(void) {
143         truncate(strlen(str()));
144     }
145
146     const char *str(void) const {
147         assert(buffer[buffer.size() - 1] == 0);
148         return &buffer[0];
149     }
150
151     operator const char *(void) const {
152         return str();
153     }
154
155     void join(const Path & other) {
156         size_t len = length();
157         if (len > 0 && buffer[len - 1] != OS_DIR_SEP) {
158             buffer.insert(buffer.begin() + len++, OS_DIR_SEP);
159         }
160         buffer.insert(buffer.begin() + len, other.buffer.begin(), other.buffer.end() - 1);
161     }
162
163     /**
164      * Create a path from a printf-like format string
165      */
166     static Path
167     format(const char *format, ...)
168 #ifdef __GNUC__
169     __attribute__ ((format (printf, 1, 2)))
170 #endif
171     {
172
173         va_list args;
174
175         va_start(args, format);
176
177         int length;
178         va_list args_copy;
179         va_copy(args_copy, args);
180 #ifdef _WIN32
181         /* We need to use _vcsprintf to calculate the length as vsnprintf returns -1
182          * if the number of characters to write is greater than count.
183          */
184         length = _vscprintf(format, args_copy);
185 #else
186         char dummy;
187         length = vsnprintf(&dummy, sizeof dummy, format, args_copy);
188 #endif
189         va_end(args_copy);
190
191         assert(length >= 0);
192         size_t size = length + 1;
193
194         Path path(size);
195
196         va_start(args, format);
197         vsnprintf(path.buf(), size, format, args);
198         va_end(args);
199
200         return path;
201     }
202 };
203
204
205 Path getProcessName();
206 Path getCurrentDir();
207
208
209 } /* namespace os */
210
211 #endif /* _OS_PATH_HPP_ */