]> git.cworth.org Git - apitrace/blob - common/os_string.hpp
Fix Win64 build.
[apitrace] / common / os_string.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  * String manipulation.
28  */
29
30 #ifndef _OS_STRING_HPP_
31 #define _OS_STRING_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 MinGW are missing _vscprintf's declaration, although they
41 // still 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 /**
69  * Vector based zero-terminate string, suitable for passing strings or paths
70  * to/from OS calls.
71  */
72 class String {
73 protected:
74     typedef std::vector<char> Buffer;
75
76     /**
77      * The buffer's last element is always the '\0' character, therefore the
78      * buffer must never be empty.
79      */
80     Buffer buffer;
81
82     Buffer::iterator find(char c) {
83         Buffer::iterator it = buffer.begin();
84         assert(it != buffer.end());
85         while (it != buffer.end()) {
86             if (*it == c) {
87                 return it;
88             }
89             ++it;
90         }
91         return buffer.end();
92     }
93
94     Buffer::iterator rfind(char c) {
95         Buffer::iterator it = buffer.end();
96         while (it != buffer.begin()) {
97             --it;
98             if (*it == c) {
99                 return it;
100             }
101         }
102         return buffer.end();
103     }
104
105     String(size_t size) :
106         buffer(size) {
107     }
108
109     char *buf(void) {
110         return &buffer[0];
111     }
112
113 public:
114
115     /*
116      * Constructors
117      */
118
119     String() {
120         buffer.push_back(0);
121     }
122
123     String(const char *s) :
124         buffer(s, s + strlen(s) + 1)
125     {}
126
127     String(const String &other) :
128         buffer(other.buffer)
129     {}
130
131     template <class InputIterator>
132     String(InputIterator first, InputIterator last) :
133         buffer(first, last)
134     {
135         buffer.push_back(0);
136     }
137
138     /**
139      * From a printf-like format string
140      */
141     static String
142     format(const char *format, ...)
143 #ifdef __GNUC__
144     __attribute__ ((format (printf, 1, 2)))
145 #endif
146     {
147
148         va_list args;
149
150         va_start(args, format);
151
152         int length;
153         va_list args_copy;
154         va_copy(args_copy, args);
155 #ifdef _WIN32
156         /* We need to use _vcsprintf to calculate the length as vsnprintf returns -1
157          * if the number of characters to write is greater than count.
158          */
159         length = _vscprintf(format, args_copy);
160 #else
161         char dummy;
162         length = vsnprintf(&dummy, sizeof dummy, format, args_copy);
163 #endif
164         va_end(args_copy);
165
166         assert(length >= 0);
167         size_t size = length + 1;
168
169         String path(size);
170
171         va_start(args, format);
172         vsnprintf(path.buf(), size, format, args);
173         va_end(args);
174
175         return path;
176     }
177
178     /*
179      * Conversion to ordinary C strings.
180      */
181
182     const char *str(void) const {
183         assert(buffer.back() == 0);
184         return &buffer[0];
185     }
186
187     operator const char *(void) const {
188         return str();
189     }
190
191     /*
192      * Iterators
193      */
194
195     typedef Buffer::const_iterator const_iterator;
196     typedef Buffer::iterator iterator;
197
198     const_iterator begin(void) const {
199         return buffer.begin();
200     }
201
202     iterator begin(void) {
203         return buffer.begin();
204     }
205
206     const_iterator end(void) const {
207         const_iterator it = buffer.end();
208         assert(it != buffer.begin());
209         --it; // skip null
210         return it;
211     }
212
213     iterator end(void) {
214         iterator it = buffer.end();
215         assert(it != buffer.begin());
216         --it; // skip null
217         return it;
218     }
219
220     /*
221      * Operations
222      */
223
224     void insert(iterator position, char c) {
225         buffer.insert(position, c);
226     }
227
228     template <class InputIterator>
229     void insert(iterator position, InputIterator first, InputIterator last) {
230         buffer.insert(position, first, last);
231     }
232
233     void insert(iterator position, const char *s) {
234         assert(s);
235         insert(position, s, s + strlen(s));
236     }
237
238     void insert(iterator position, const String & other) {
239         insert(position, other.begin(), other.end());
240     }
241
242     void append(char c) {
243         insert(end(), c);
244     }
245
246     template <class InputIterator>
247     void append(InputIterator first, InputIterator last) {
248         insert(end(), first, last);
249     }
250
251     void append(const char *s) {
252         insert(end(), s);
253     }
254
255     void append(const String & other) {
256         insert(end(), other);
257     }
258
259     char *buf(size_t size) {
260         buffer.resize(size);
261         return &buffer[0];
262     }
263
264     size_t length(void) const {
265         size_t size = buffer.size();
266         assert(size > 0);
267         assert(buffer[size - 1] == 0);
268         return size - 1;
269     }
270
271     void truncate(size_t length) {
272         assert(length < buffer.size());
273         buffer[length] = 0;
274         buffer.resize(length + 1);
275     }
276
277     void truncate(void) {
278         truncate(strlen(str()));
279     }
280
281
282     /*
283      * String manipulation
284      */
285
286     bool
287     exists(void) const;
288
289     void trimDirectory(void) {
290         iterator sep = rfind(OS_DIR_SEP);
291         if (sep != buffer.end()) {
292             buffer.erase(buffer.begin(), sep + 1);
293         }
294     }
295
296     /* Trim filename component (leaving containing directory).
297      *
298      * This function removes everything after the final path
299      * separator, as well as that separator itself if it is not the
300      * only remaining separator.
301      *
302      * Some specific consequences of the above:
303      *
304      * 1. A path with no separator at all is unchanged.
305      * 2. A path with a trailing separator has only that separator removed
306      * 3. A path of just the root directory is unchaged.
307      */
308     void trimFilename(void) {
309         iterator first = find(OS_DIR_SEP);
310         iterator last = rfind(OS_DIR_SEP);
311         if (last == buffer.end()) {
312             return;
313         }
314         if (last == first) {
315             buffer.erase(first + 1, end());
316         } else {
317             buffer.erase(last, end());
318         }
319     }
320
321     void trimExtension(void) {
322         iterator dot = rfind('.');
323         if (dot != buffer.end()) {
324             buffer.erase(dot, end());
325         }
326     }
327
328     void join(const String & other) {
329         if (length() && end()[-1] != OS_DIR_SEP) {
330             append(OS_DIR_SEP);
331         }
332         append(other.begin(), other.end());
333     }
334 };
335
336
337 String getProcessName();
338 String getCurrentDir();
339
340
341 } /* namespace os */
342
343 #endif /* _OS_STRING_HPP_ */