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