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