Fix 1818856: External application render targets seem to be broken. We can't use...
[synfig.git] / ETL / trunk / 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_WRITE_TYPE "wb"
45 #else
46 #define POPEN_BINARY_WRITE_TYPE "w"
47 #endif
48
49 /* === T Y P E D E F S ===================================================== */
50
51 _ETL_BEGIN_CDECLS
52
53 #if defined(__APPLE__) || defined(__CYGWIN__) || defined(_WIN32)
54 #define ETL_NO_THROW
55 #else
56 #define ETL_NO_THROW throw()
57 #endif
58
59 #ifdef HAVE_VASPRINTF   // This is the preferred method
60  extern int vasprintf(char **,const char *,va_list)ETL_NO_THROW;
61 #else
62
63 # ifdef HAVE_VSNPRINTF  // This is the secondary method
64  extern int vsnprintf(char *,size_t,const char*,va_list)ETL_NO_THROW;
65 # endif
66
67 #endif
68
69 #ifdef HAVE_VSSCANF
70 extern int vsscanf(const char *,const char *,va_list)ETL_NO_THROW;
71 #else
72 #define ETL_NO_VSTRSCANF
73 #ifdef HAVE_SSCANF
74 extern int sscanf(const char *buf, const char *format, ...)ETL_NO_THROW;
75 #endif
76 #endif
77
78 #include <unistd.h>
79
80 _ETL_END_CDECLS
81
82 /* === C L A S S E S & S T R U C T S ======================================= */
83
84 _ETL_BEGIN_NAMESPACE
85
86 inline std::string
87 vstrprintf(const char *format, va_list args)
88 {
89 #ifdef HAVE_VASPRINTF   // This is the preferred method (and safest)
90         char *buffer;
91         std::string ret;
92         vasprintf(&buffer,format,args);
93         ret=buffer;
94         free(buffer);
95         return ret;
96 #else
97 #ifdef HAVE_VSNPRINTF   // This is the secondary method (Safe, but bulky)
98 #warning etl::vstrprintf() has a maximum size of ETL_STRPRINTF_MAX_LENGTH in this configuration.
99 #ifdef ETL_THREAD_SAFE
100         char buffer[ETL_STRPRINTF_MAX_LENGTH];
101 #else
102         static char buffer[ETL_STRPRINTF_MAX_LENGTH];
103 #endif
104         vsnprintf(buffer,sizeof(buffer),format,args);
105         return buffer;
106 #else                                   // This is the worst method (UNSAFE, but "works")
107 #warning Potential for Buffer-overflow bug using vsprintf
108 #define ETL_UNSAFE_STRPRINTF    (true)
109 // Here, we are doubling the size of the buffer to make this case
110 // slightly more safe.
111 #ifdef ETL_THREAD_SAFE
112         char buffer[ETL_STRPRINTF_MAX_LENGTH*2];
113 #else
114         static char buffer[ETL_STRPRINTF_MAX_LENGTH*2];
115 #endif
116         vsprintf(buffer,format,args);
117         return buffer;
118 #endif
119 #endif
120 }
121
122 inline std::string
123 strprintf(const char *format, ...)
124 {
125         va_list args;
126         va_start(args,format);
127         return vstrprintf(format,args);
128 }
129
130 #ifndef ETL_NO_VSTRSCANF
131 inline int
132 vstrscanf(const std::string &data, const char*format, va_list args)
133 {
134     return vsscanf(data.c_str(),format,args);
135 }
136
137 inline int
138 strscanf(const std::string &data, const char*format, ...)
139 {
140         va_list args;
141         va_start(args,format);
142         return vstrscanf(data, format,args);
143 }
144 #else
145
146 #if defined (HAVE_SSCANF) && defined (__GNUC__)
147 #define strscanf(data,format,...) sscanf(data.c_str(),format,__VA_ARGS__)
148 #endif
149 #endif
150
151
152 #define stratof(X) (atof((X).c_str()))
153 #define stratoi(X) (atoi((X).c_str()))
154
155 inline std::string
156 basename(const std::string &str)
157 {
158         std::string::const_iterator iter;
159
160         if(str.size() == 1 && str[0] == ETL_DIRECTORY_SEPARATOR)
161                 return str;
162
163         if(str.end()[-1]==ETL_DIRECTORY_SEPARATOR)
164                 iter=str.end()-2;
165         else
166                 iter=str.end()-1;
167
168         for(;iter!=str.begin();iter--)
169                 if(*iter==ETL_DIRECTORY_SEPARATOR)
170                         break;
171
172         if (*iter==ETL_DIRECTORY_SEPARATOR)
173                 iter++;
174
175         if(str.end()[-1]==ETL_DIRECTORY_SEPARATOR)
176                 return std::string(iter,str.end()-1);
177
178         return std::string(iter,str.end());
179 }
180
181 inline std::string
182 dirname(const std::string &str)
183 {
184         std::string::const_iterator iter;
185
186         if(str.size() == 1 && str[0] == ETL_DIRECTORY_SEPARATOR)
187                 return str;
188
189         if(str.end()[-1]==ETL_DIRECTORY_SEPARATOR)
190                 iter=str.end()-2;
191         else
192                 iter=str.end()-1;
193
194         for(;iter!=str.begin();iter--)
195                 if(*iter==ETL_DIRECTORY_SEPARATOR)
196                         break;
197
198         if(iter==str.begin())
199            if (*iter==ETL_DIRECTORY_SEPARATOR)
200                    return "/";
201            else
202                    return ".";
203
204         return std::string(str.begin(),iter);
205 }
206
207 // filename_extension("/f.e/d.c") => ".c"
208 inline std::string
209 filename_extension(const std::string &str)
210 {
211         std::string base = basename(str);
212         std::string::size_type pos = base.find_last_of('.');
213         if (pos == std::string::npos) return std::string();
214         return base.substr(pos);
215 }
216
217 // filename_sans_extension("/f.e/d.c") => "/f.e/d"
218 inline std::string
219 filename_sans_extension(const std::string &str)
220 {
221         std::string base = basename(str);
222         std::string::size_type pos = base.find_last_of('.');
223         if (pos == std::string::npos) return str;
224         std::string dir = dirname(str);
225         if (dir == ".") return base.substr(0,pos);
226         return dir + ETL_DIRECTORY_SEPARATOR + base.substr(0,pos);
227 }
228
229 inline bool
230 is_absolute_path(const std::string &path)
231 {
232 #ifdef WIN32
233         if(path.size()>=3 && path[1]==':' && (path[2]=='\\' || path[2]=='/'))
234                 return true;
235 #endif
236         if(!path.empty() && path[0]==ETL_DIRECTORY_SEPARATOR)
237                 return true;
238         return false;
239 }
240
241 inline std::string
242 unix_to_local_path(const std::string &path)
243 {
244         std::string ret;
245         std::string::const_iterator iter;
246         for(iter=path.begin();iter!=path.end();iter++)
247                 switch(*iter)
248                 {
249                 case '/':
250                         ret+=ETL_DIRECTORY_SEPARATOR;
251                         break;
252                 case '~':
253                         ret+='~';
254                         break;
255                 default:
256                         ret+=*iter;
257                         break;
258                 }
259         return ret;
260 }
261
262 inline std::string
263 current_working_directory()
264 {
265         char dir[256];
266         std::string ret(getcwd(dir,sizeof(dir)));
267         return ret;
268 }
269
270 inline std::string
271 get_root_from_path(std::string path)
272 {
273         std::string ret;
274         std::string::const_iterator iter;
275
276         for(iter=path.begin();iter!=path.end();++iter)
277         {
278                 if(*iter==ETL_DIRECTORY_SEPARATOR)
279                         break;
280                 ret+=*iter;
281         }
282         //if(iter!=path.end())
283                 ret+=ETL_DIRECTORY_SEPARATOR;
284         return ret;
285 }
286
287 inline std::string
288 remove_root_from_path(std::string path)
289 {
290         while(!path.empty())
291         {
292                 if(path[0]==ETL_DIRECTORY_SEPARATOR)
293                 {
294                         path.erase(path.begin());
295                         return path;
296                 }
297                 path.erase(path.begin());
298         }
299         return path;
300 }
301
302 inline std::string
303 cleanup_path(std::string path)
304 {
305         std::string ret;
306
307         while(basename(path)=="."&&path.size()!=1)path=dirname(path);
308
309         while(!path.empty())
310         {
311                 std::string dir(get_root_from_path(path));
312                 if((dir=="../" || dir=="..\\") && ret.size())
313                 {
314                         ret=dirname(ret);
315                         if (*(ret.end()-1)!=ETL_DIRECTORY_SEPARATOR)
316                                 ret+=ETL_DIRECTORY_SEPARATOR;
317                 }
318                 else if((dir!="./" && dir!=".\\") && dir!=".")
319                         ret+=dir;
320                 path=remove_root_from_path(path);
321         }
322         if (ret.size()==0)ret+='.';
323
324         // Remove any trailing directory separators
325         if(ret.size() && ret[ret.size()-1]==ETL_DIRECTORY_SEPARATOR)
326                 ret.erase(ret.begin()+ret.size()-1);
327         return ret;
328 }
329
330 inline std::string
331 absolute_path(std::string path)
332 {
333         std::string ret(current_working_directory());
334
335         if(path.empty())
336                 return cleanup_path(ret);
337         if(is_absolute_path(path))
338                 return cleanup_path(path);
339         return cleanup_path(ret+ETL_DIRECTORY_SEPARATOR+path);
340 }
341
342 inline std::string
343 relative_path(std::string curr_path,std::string dest_path)
344 {
345         // If dest_path is already a relative path,
346         // then there is no need to do anything.
347         if(!is_absolute_path(dest_path))
348                 dest_path=absolute_path(dest_path);
349         else
350                 dest_path=cleanup_path(dest_path);
351
352         if(!is_absolute_path(curr_path))
353                 curr_path=absolute_path(curr_path);
354         else
355                 curr_path=cleanup_path(curr_path);
356
357 #ifdef WIN32
358         // If we are on windows and the dest path is on a different drive,
359         // then there is no way to make a relative path to it.
360         if(dest_path.size()>=3 && dest_path[1]==':' && dest_path[0]!=curr_path[0])
361                 return dest_path;
362 #endif
363
364         if(curr_path==dirname(dest_path))
365                 return basename(dest_path);
366
367         while(!dest_path.empty() && !curr_path.empty() && get_root_from_path(dest_path)==get_root_from_path(curr_path))
368         {
369                 dest_path=remove_root_from_path(dest_path);
370                 curr_path=remove_root_from_path(curr_path);
371         }
372
373         while(!curr_path.empty())
374         {
375                 dest_path=std::string("..")+ETL_DIRECTORY_SEPARATOR+dest_path;
376                 curr_path=remove_root_from_path(curr_path);
377         }
378
379         return dest_path;
380 }
381
382 _ETL_END_NAMESPACE
383
384 /* === E N D =============================================================== */
385
386 #endif