/* =========================================================================
** Extended Template and Library
-** stringf Prodecure Implementation
+** stringf Procedure Implementation
** $Id$
**
** Copyright (c) 2002 Robert B. Quattlebaum Jr.
+** Copyright (c) 2007 Chris Moore
**
** This package is free software; you can redistribute it and/or
** modify it under the terms of the GNU General Public License as
/* === H E A D E R S ======================================================= */
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE
+#endif
+
#include <string>
#include <cstdarg>
#include <cstdlib>
+#include <cstdio>
/* === M A C R O S ========================================================= */
#define ETL_STRPRINTF_MAX_LENGTH (800)
#endif
+#ifdef WIN32
+#define POPEN_BINARY_READ_TYPE "rb"
+#define POPEN_BINARY_WRITE_TYPE "wb"
+#else
+#define POPEN_BINARY_READ_TYPE "r"
+#define POPEN_BINARY_WRITE_TYPE "w"
+#endif
+
+#ifdef __ETL_HAS__VSNPRINTF
+#ifndef __ETL_HAS_VSNPRINTF
+#define vnsprintf _vnsprintf
+#define __ETL_HAS_VSNPRINTF
+#endif
+#endif
+
/* === T Y P E D E F S ===================================================== */
_ETL_BEGIN_CDECLS
#define ETL_NO_THROW throw()
#endif
-#ifdef HAVE_VASPRINTF // This is the prefered method
- extern int vasprintf(char **,const char *,va_list)ETL_NO_THROW;
+// Prefer prototypes from glibc headers, since defining them ourselves
+// works around glibc security mechanisms
+
+#ifdef __ETL_HAS_VASPRINTF // This is the preferred method
+ #ifndef __GLIBC__
+ extern int vasprintf(char **,const char *,va_list)ETL_NO_THROW;
+ #endif
#else
-# ifdef HAVE_VSNPRINTF // This is the secondary method
- extern int vsnprintf(char *,size_t,const char*,va_list)ETL_NO_THROW;
+# ifdef __ETL_HAS_VSNPRINTF // This is the secondary method
+ #ifndef __GLIBC__
+ extern int vsnprintf(char *,size_t,const char*,va_list)ETL_NO_THROW;
+ #endif
# endif
#endif
-#ifdef HAVE_VSSCANF
-extern int vsscanf(const char *,const char *,va_list)ETL_NO_THROW;
+#ifdef __ETL_HAS_VSSCANF
+ #ifndef __GLIBC__
+ extern int vsscanf(const char *,const char *,va_list)ETL_NO_THROW;
+ #endif
#else
#define ETL_NO_VSTRSCANF
-#ifdef HAVE_SSCANF
-extern int sscanf(const char *buf, const char *format, ...)ETL_NO_THROW;
+#ifdef __ETL_HAS_SSCANF
+ #ifndef __GLIBC__
+ extern int sscanf(const char *buf, const char *format, ...)ETL_NO_THROW;
+ #endif
#endif
#endif
inline std::string
vstrprintf(const char *format, va_list args)
{
-#ifdef HAVE_VASPRINTF // This is the prefered method (and safest)
+#ifdef __ETL_HAS_VASPRINTF // This is the preferred method (and safest)
char *buffer;
std::string ret;
- vasprintf(&buffer,format,args);
- ret=buffer;
- free(buffer);
+ int i=vasprintf(&buffer,format,args);
+ if (i>-1)
+ {
+ ret=buffer;
+ free(buffer);
+ }
return ret;
#else
-#ifdef HAVE_VSNPRINTF // This is the secondary method (Safe, but bulky)
+#ifdef __ETL_HAS_VSNPRINTF // This is the secondary method (Safe, but bulky)
#warning etl::vstrprintf() has a maximum size of ETL_STRPRINTF_MAX_LENGTH in this configuration.
#ifdef ETL_THREAD_SAFE
char buffer[ETL_STRPRINTF_MAX_LENGTH];
}
#else
-#if defined (HAVE_SSCANF) && defined (__GNUC__)
+#if defined (__ETL_HAS_SSCANF) && defined (__GNUC__)
#define strscanf(data,format,...) sscanf(data.c_str(),format,__VA_ARGS__)
#endif
#endif
{
std::string::const_iterator iter;
- if(str.end()[-1]==ETL_DIRECTORY_SEPERATOR)
+ if(str.size() == 1 && str[0] == ETL_DIRECTORY_SEPARATOR)
+ return str;
+
+ if(str.end()[-1]==ETL_DIRECTORY_SEPARATOR)
iter=str.end()-2;
else
iter=str.end()-1;
for(;iter!=str.begin();iter--)
- if(*iter==ETL_DIRECTORY_SEPERATOR)
+ if(*iter==ETL_DIRECTORY_SEPARATOR)
break;
- if(iter==str.begin())
- return str;
-
- iter++;
+ if (*iter==ETL_DIRECTORY_SEPARATOR)
+ iter++;
- if(str.end()[-1]==ETL_DIRECTORY_SEPERATOR)
+ if(str.end()[-1]==ETL_DIRECTORY_SEPARATOR)
return std::string(iter,str.end()-1);
return std::string(iter,str.end());
{
std::string::const_iterator iter;
- if(str.end()[-1]==ETL_DIRECTORY_SEPERATOR)
+ if(str.size() == 1 && str[0] == ETL_DIRECTORY_SEPARATOR)
+ return str;
+
+ if(str.end()[-1]==ETL_DIRECTORY_SEPARATOR)
iter=str.end()-2;
else
iter=str.end()-1;
for(;iter!=str.begin();iter--)
- if(*iter==ETL_DIRECTORY_SEPERATOR)
+ if(*iter==ETL_DIRECTORY_SEPARATOR)
break;
if(iter==str.begin())
- return ".";
+ {
+ if (*iter==ETL_DIRECTORY_SEPARATOR)
+ return "/";
+ else
+ return ".";
+ }
return std::string(str.begin(),iter);
}
+// filename_extension("/f.e/d.c") => ".c"
+inline std::string
+filename_extension(const std::string &str)
+{
+ std::string base = basename(str);
+ std::string::size_type pos = base.find_last_of('.');
+ if (pos == std::string::npos) return std::string();
+ return base.substr(pos);
+}
+
+// filename_sans_extension("/f.e/d.c") => "/f.e/d"
+inline std::string
+filename_sans_extension(const std::string &str)
+{
+ std::string base = basename(str);
+ std::string::size_type pos = base.find_last_of('.');
+ if (pos == std::string::npos) return str;
+ std::string dir = dirname(str);
+ if (dir == ".") return base.substr(0,pos);
+ return dir + ETL_DIRECTORY_SEPARATOR + base.substr(0,pos);
+}
+
inline bool
is_absolute_path(const std::string &path)
{
if(path.size()>=3 && path[1]==':' && (path[2]=='\\' || path[2]=='/'))
return true;
#endif
- if(!path.empty() && path[0]==ETL_DIRECTORY_SEPERATOR)
+ if(!path.empty() && path[0]==ETL_DIRECTORY_SEPARATOR)
return true;
return false;
}
switch(*iter)
{
case '/':
- ret+=ETL_DIRECTORY_SEPERATOR;
+ ret+=ETL_DIRECTORY_SEPARATOR;
break;
case '~':
ret+='~';
for(iter=path.begin();iter!=path.end();++iter)
{
- if(*iter==ETL_DIRECTORY_SEPERATOR)
+ if(*iter==ETL_DIRECTORY_SEPARATOR)
break;
ret+=*iter;
}
//if(iter!=path.end())
- ret+=ETL_DIRECTORY_SEPERATOR;
+ ret+=ETL_DIRECTORY_SEPARATOR;
return ret;
}
{
while(!path.empty())
{
- if(path[0]==ETL_DIRECTORY_SEPERATOR)
+ if(path[0]==ETL_DIRECTORY_SEPARATOR)
{
path.erase(path.begin());
return path;
{
std::string ret;
- while(basename(path)==".")path=dirname(path);
+ while(basename(path)=="."&&path.size()!=1)path=dirname(path);
while(!path.empty())
{
std::string dir(get_root_from_path(path));
if((dir=="../" || dir=="..\\") && ret.size())
{
- ret=dirname(ret)+ETL_DIRECTORY_SEPERATOR;
+ ret=dirname(ret);
+ if (*(ret.end()-1)!=ETL_DIRECTORY_SEPARATOR)
+ ret+=ETL_DIRECTORY_SEPARATOR;
}
else if((dir!="./" && dir!=".\\") && dir!=".")
- {
ret+=dir;
- }
path=remove_root_from_path(path);
}
+ if (ret.size()==0)ret+='.';
- // Remove any trailing directory seperators
- if(ret.size() && ret[ret.size()-1]==ETL_DIRECTORY_SEPERATOR)
- {
+ // Remove any trailing directory separators
+ if(ret.size() && ret[ret.size()-1]==ETL_DIRECTORY_SEPARATOR)
ret.erase(ret.begin()+ret.size()-1);
- }
return ret;
}
return cleanup_path(ret);
if(is_absolute_path(path))
return cleanup_path(path);
- // TODO: This needs to be written
- return cleanup_path(ret+ETL_DIRECTORY_SEPERATOR+path);
+ return cleanup_path(ret+ETL_DIRECTORY_SEPARATOR+path);
}
inline std::string
// If we are on windows and the dest path is on a different drive,
// then there is no way to make a relative path to it.
if(dest_path.size()>=3 && dest_path[1]==':' && dest_path[0]!=curr_path[0])
- {
return dest_path;
- }
#endif
if(curr_path==dirname(dest_path))
- {
return basename(dest_path);
- }
while(!dest_path.empty() && !curr_path.empty() && get_root_from_path(dest_path)==get_root_from_path(curr_path))
{
while(!curr_path.empty())
{
- dest_path=std::string("..")+ETL_DIRECTORY_SEPERATOR+dest_path;
+ dest_path=std::string("..")+ETL_DIRECTORY_SEPARATOR+dest_path;
curr_path=remove_root_from_path(curr_path);
}