]> git.cworth.org Git - apitrace/blob - common/os_path.hpp
Fix os::Path::format on MinwGW.
[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         while (it != buffer.begin()) {
76             --it;
77             if (*it == c) {
78                 return it;
79             }
80         }
81         return buffer.end();
82     }
83
84     Path(size_t size) :
85         buffer(size) {
86     }
87
88     char *buf(void) {
89         return &buffer[0];
90     }
91
92 public:
93     Path() {
94         buffer.push_back(0);
95     }
96
97     Path(const char *s) :
98         buffer(s, s + strlen(s) + 1)
99     {}
100
101     template <class InputIterator>
102     Path(InputIterator first, InputIterator last) :
103         buffer(first, last)
104     {
105         buffer.push_back(0);
106     }
107
108     char *buf(size_t size) {
109         buffer.resize(size);
110         return &buffer[0];
111     }
112
113     void trimDirectory(void) {
114         Buffer::iterator sep = rfind(OS_DIR_SEP);
115         if (sep != buffer.end()) {
116             buffer.erase(buffer.begin(), sep + 1);
117         }
118     }
119
120     void trimExtension(void) {
121         Buffer::iterator dot = rfind('.');
122         if (dot != buffer.end()) {
123             buffer.erase(dot, buffer.end());
124         }
125     }
126
127     size_t length(void) const {
128         size_t size = buffer.size();
129         assert(size > 0);
130         assert(buffer[size - 1] == 0);
131         return size - 1;
132     }
133
134     void truncate(size_t length) {
135         assert(length < buffer.size());
136         buffer[length] = 0;
137         buffer.resize(length + 1);
138     }
139
140     void truncate(void) {
141         truncate(strlen(str()));
142     }
143
144     const char *str(void) const {
145         assert(buffer[buffer.size() - 1] == 0);
146         return &buffer[0];
147     }
148
149     operator const char *(void) const {
150         return str();
151     }
152
153     void join(const Path & other) {
154         size_t len = length();
155         if (len > 0 && buffer[len - 1] != OS_DIR_SEP) {
156             buffer.insert(buffer.begin() + len++, OS_DIR_SEP);
157         }
158         buffer.insert(buffer.begin() + len, other.buffer.begin(), other.buffer.end() - 1);
159     }
160
161     /**
162      * Create a path from a printf-like format string
163      */
164     static Path
165     format(const char *format, ...)
166 #ifdef __GNUC__
167     __attribute__ ((format (printf, 1, 2)))
168 #endif
169     {
170
171         va_list args;
172
173         va_start(args, format);
174
175         int length;
176         va_list args_copy;
177         va_copy(args_copy, args);
178 #ifdef _WIN32
179         /* We need to use _vcsprintf to calculate the length as vsnprintf returns -1
180          * if the number of characters to write is greater than count.
181          */
182         length = _vscprintf(format, args_copy);
183 #else
184         char dummy;
185         length = vsnprintf(&dummy, sizeof dummy, format, args_copy);
186 #endif
187         va_end(args_copy);
188
189         assert(length >= 0);
190         size_t size = length + 1;
191
192         Path path(size);
193
194         va_start(args, format);
195         vsnprintf(path.buf(), size, format, args);
196         va_end(args);
197
198         return path;
199     }
200 };
201
202
203 Path getProcessName();
204 Path getCurrentDir();
205
206
207 } /* namespace os */
208
209 #endif /* _OS_PATH_HPP_ */