Fix bugs in previous commit that caused FTBFS in synfig and ETL FTBFS with older...
[synfig.git] / ETL / tags / 0.04.12 / ETL / _stringf.h
1 /* =========================================================================
2 ** Extended Template and Library
3 ** stringf Procedure Implementation
4 ** $Id$
5 **
6 ** Copyright (c) 2002 Robert B. Quattlebaum Jr.
7 ** Copyright (c) 2007 Chris Moore
8 **
9 ** This package is free software; you can redistribute it and/or
10 ** modify it under the terms of the GNU General Public License as
11 ** published by the Free Software Foundation; either version 2 of
12 ** the License, or (at your option) any later version.
13 **
14 ** This package is distributed in the hope that it will be useful,
15 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
16 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17 ** General Public License for more details.
18 **
19 ** === N O T E S ===========================================================
20 **
21 ** This is an internal header file, included by other ETL headers.
22 ** You should not attempt to use it directly.
23 **
24 ** ========================================================================= */
25
26 /* === S T A R T =========================================================== */
27
28 #ifndef __ETL__STRINGF_H
29 #define __ETL__STRINGF_H
30
31 /* === H E A D E R S ======================================================= */
32
33 #include <string>
34 #include <cstdarg>
35 #include <cstdlib>
36
37 /* === M A C R O S ========================================================= */
38
39 #ifndef ETL_STRPRINTF_MAX_LENGTH
40 #define ETL_STRPRINTF_MAX_LENGTH        (800)
41 #endif
42
43 #ifdef WIN32
44 #define POPEN_BINARY_READ_TYPE "rb"
45 #define POPEN_BINARY_WRITE_TYPE "wb"
46 #else
47 #define POPEN_BINARY_READ_TYPE "r"
48 #define POPEN_BINARY_WRITE_TYPE "w"
49 #endif
50
51 /* === T Y P E D E F S ===================================================== */
52
53 _ETL_BEGIN_CDECLS
54
55 #if defined(__APPLE__) || defined(__CYGWIN__) || defined(_WIN32)
56 #define ETL_NO_THROW
57 #else
58 #define ETL_NO_THROW throw()
59 #endif
60
61 #ifdef HAVE_VASPRINTF   // This is the preferred method
62  extern int vasprintf(char **,const char *,va_list)ETL_NO_THROW;
63 #else
64
65 # ifdef HAVE_VSNPRINTF  // This is the secondary method
66  extern int vsnprintf(char *,size_t,const char*,va_list)ETL_NO_THROW;
67 # endif
68
69 #endif
70
71 #ifdef HAVE_VSSCANF
72 extern int vsscanf(const char *,const char *,va_list)ETL_NO_THROW;
73 #else
74 #define ETL_NO_VSTRSCANF
75 #ifdef HAVE_SSCANF
76 extern int sscanf(const char *buf, const char *format, ...)ETL_NO_THROW;
77 #endif
78 #endif
79
80 #include <unistd.h>
81
82 _ETL_END_CDECLS
83
84 /* === C L A S S E S & S T R U C T S ======================================= */
85
86 _ETL_BEGIN_NAMESPACE
87
88 inline std::string
89 vstrprintf(const char *format, va_list args)
90 {
91 #ifdef HAVE_VASPRINTF   // This is the preferred method (and safest)
92         char *buffer;
93         std::string ret;
94         vasprintf(&buffer,format,args);
95         ret=buffer;
96         free(buffer);
97         return ret;
98 #else
99 #ifdef HAVE_VSNPRINTF   // This is the secondary method (Safe, but bulky)
100 #warning etl::vstrprintf() has a maximum size of ETL_STRPRINTF_MAX_LENGTH in this configuration.
101 #ifdef ETL_THREAD_SAFE
102         char buffer[ETL_STRPRINTF_MAX_LENGTH];
103 #else
104         static char buffer[ETL_STRPRINTF_MAX_LENGTH];
105 #endif
106         vsnprintf(buffer,sizeof(buffer),format,args);
107         return buffer;
108 #else                                   // This is the worst method (UNSAFE, but "works")
109 #warning Potential for Buffer-overflow bug using vsprintf
110 #define ETL_UNSAFE_STRPRINTF    (true)
111 // Here, we are doubling the size of the buffer to make this case
112 // slightly more safe.
113 #ifdef ETL_THREAD_SAFE
114         char buffer[ETL_STRPRINTF_MAX_LENGTH*2];
115 #else
116         static char buffer[ETL_STRPRINTF_MAX_LENGTH*2];
117 #endif
118         vsprintf(buffer,format,args);
119         return buffer;
120 #endif
121 #endif
122 }
123
124 inline std::string
125 strprintf(const char *format, ...)
126 {
127         va_list args;
128         va_start(args,format);
129         return vstrprintf(format,args);
130 }
131
132 #ifndef ETL_NO_VSTRSCANF
133 inline int
134 vstrscanf(const std::string &data, const char*format, va_list args)
135 {
136     return vsscanf(data.c_str(),format,args);
137 }
138
139 inline int
140 strscanf(const std::string &data, const char*format, ...)
141 {
142         va_list args;
143         va_start(args,format);
144         return vstrscanf(data, format,args);
145 }
146 #else
147
148 #if defined (HAVE_SSCANF) && defined (__GNUC__)
149 #define strscanf(data,format,...) sscanf(data.c_str(),format,__VA_ARGS__)
150 #endif
151 #endif
152
153
154 #define stratof(X) (atof((X).c_str()))
155 #define stratoi(X) (atoi((X).c_str()))
156
157 inline std::string
158 basename(const std::string &str)
159 {
160         std::string::const_iterator iter;
161
162         if(str.size() == 1 && str[0] == ETL_DIRECTORY_SEPARATOR)
163                 return str;
164
165         if(str.end()[-1]==ETL_DIRECTORY_SEPARATOR)
166                 iter=str.end()-2;
167         else
168                 iter=str.end()-1;
169
170         for(;iter!=str.begin();iter--)
171                 if(*iter==ETL_DIRECTORY_SEPARATOR)
172                         break;
173
174         if (*iter==ETL_DIRECTORY_SEPARATOR)
175                 iter++;
176
177         if(str.end()[-1]==ETL_DIRECTORY_SEPARATOR)
178                 return std::string(iter,str.end()-1);
179
180         return std::string(iter,str.end());
181 }
182
183 inline std::string
184 dirname(const std::string &str)
185 {
186         std::string::const_iterator iter;
187
188         if(str.size() == 1 && str[0] == ETL_DIRECTORY_SEPARATOR)
189                 return str;
190
191         if(str.end()[-1]==ETL_DIRECTORY_SEPARATOR)
192                 iter=str.end()-2;
193         else
194                 iter=str.end()-1;
195
196         for(;iter!=str.begin();iter--)
197                 if(*iter==ETL_DIRECTORY_SEPARATOR)
198                         break;
199
200         if(iter==str.begin())
201         {
202            if (*iter==ETL_DIRECTORY_SEPARATOR)
203                    return "/";
204            else
205                    return ".";
206         }
207
208         return std::string(str.begin(),iter);
209 }
210
211 // filename_extension("/f.e/d.c") => ".c"
212 inline std::string
213 filename_extension(const std::string &str)
214 {
215         std::string base = basename(str);
216         std::string::size_type pos = base.find_last_of('.');
217         if (pos == std::string::npos) return std::string();
218         return base.substr(pos);
219 }
220
221 // filename_sans_extension("/f.e/d.c") => "/f.e/d"
222 inline std::string
223 filename_sans_extension(const std::string &str)
224 {
225         std::string base = basename(str);
226         std::string::size_type pos = base.find_last_of('.');
227         if (pos == std::string::npos) return str;
228         std::string dir = dirname(str);
229         if (dir == ".") return base.substr(0,pos);
230         return dir + ETL_DIRECTORY_SEPARATOR + base.substr(0,pos);
231 }
232
233 inline bool
234 is_absolute_path(const std::string &path)
235 {
236 #ifdef WIN32
237         if(path.size()>=3 && path[1]==':' && (path[2]=='\\' || path[2]=='/'))
238                 return true;
239 #endif
240         if(!path.empty() && path[0]==ETL_DIRECTORY_SEPARATOR)
241                 return true;
242         return false;
243 }
244
245 inline std::string
246 unix_to_local_path(const std::string &path)
247 {
248         std::string ret;
249         std::string::const_iterator iter;
250         for(iter=path.begin();iter!=path.end();iter++)
251                 switch(*iter)
252                 {
253                 case '/':
254                         ret+=ETL_DIRECTORY_SEPARATOR;
255                         break;
256                 case '~':
257                         ret+='~';
258                         break;
259                 default:
260                         ret+=*iter;
261                         break;
262                 }
263         return ret;
264 }
265
266 inline std::string
267 current_working_directory()
268 {
269         char dir[256];
270         std::string ret(getcwd(dir,sizeof(dir)));
271         return ret;
272 }
273
274 inline std::string
275 get_root_from_path(std::string path)
276 {
277         std::string ret;
278         std::string::const_iterator iter;
279
280         for(iter=path.begin();iter!=path.end();++iter)
281         {
282                 if(*iter==ETL_DIRECTORY_SEPARATOR)
283                         break;
284                 ret+=*iter;
285         }
286         //if(iter!=path.end())
287                 ret+=ETL_DIRECTORY_SEPARATOR;
288         return ret;
289 }
290
291 inline std::string
292 remove_root_from_path(std::string path)
293 {
294         while(!path.empty())
295         {
296                 if(path[0]==ETL_DIRECTORY_SEPARATOR)
297                 {
298                         path.erase(path.begin());
299                         return path;
300                 }
301                 path.erase(path.begin());
302         }
303         return path;
304 }
305
306 inline std::string
307 cleanup_path(std::string path)
308 {
309         std::string ret;
310
311         while(basename(path)=="."&&path.size()!=1)path=dirname(path);
312
313         while(!path.empty())
314         {
315                 std::string dir(get_root_from_path(path));
316                 if((dir=="../" || dir=="..\\") && ret.size())
317                 {
318                         ret=dirname(ret);
319                         if (*(ret.end()-1)!=ETL_DIRECTORY_SEPARATOR)
320                                 ret+=ETL_DIRECTORY_SEPARATOR;
321                 }
322                 else if((dir!="./" && dir!=".\\") && dir!=".")
323                         ret+=dir;
324                 path=remove_root_from_path(path);
325         }
326         if (ret.size()==0)ret+='.';
327
328         // Remove any trailing directory separators
329         if(ret.size() && ret[ret.size()-1]==ETL_DIRECTORY_SEPARATOR)
330                 ret.erase(ret.begin()+ret.size()-1);
331         return ret;
332 }
333
334 inline std::string
335 absolute_path(std::string path)
336 {
337         std::string ret(current_working_directory());
338
339         if(path.empty())
340                 return cleanup_path(ret);
341         if(is_absolute_path(path))
342                 return cleanup_path(path);
343         return cleanup_path(ret+ETL_DIRECTORY_SEPARATOR+path);
344 }
345
346 inline std::string
347 relative_path(std::string curr_path,std::string dest_path)
348 {
349         // If dest_path is already a relative path,
350         // then there is no need to do anything.
351         if(!is_absolute_path(dest_path))
352                 dest_path=absolute_path(dest_path);
353         else
354                 dest_path=cleanup_path(dest_path);
355
356         if(!is_absolute_path(curr_path))
357                 curr_path=absolute_path(curr_path);
358         else
359                 curr_path=cleanup_path(curr_path);
360
361 #ifdef WIN32
362         // If we are on windows and the dest path is on a different drive,
363         // then there is no way to make a relative path to it.
364         if(dest_path.size()>=3 && dest_path[1]==':' && dest_path[0]!=curr_path[0])
365                 return dest_path;
366 #endif
367
368         if(curr_path==dirname(dest_path))
369                 return basename(dest_path);
370
371         while(!dest_path.empty() && !curr_path.empty() && get_root_from_path(dest_path)==get_root_from_path(curr_path))
372         {
373                 dest_path=remove_root_from_path(dest_path);
374                 curr_path=remove_root_from_path(curr_path);
375         }
376
377         while(!curr_path.empty())
378         {
379                 dest_path=std::string("..")+ETL_DIRECTORY_SEPARATOR+dest_path;
380                 curr_path=remove_root_from_path(curr_path);
381         }
382
383         return dest_path;
384 }
385
386 _ETL_END_NAMESPACE
387
388 /* === E N D =============================================================== */
389
390 #endif