Add some changes to make ETL more suitable for Fedora:
[synfig.git] / ETL / trunk / ETL / _stringf.h
index dc450fb..22939a2 100644 (file)
@@ -1,9 +1,10 @@
 /* =========================================================================
 ** 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 <csdlib>
+#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
@@ -49,22 +70,33 @@ _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
 
@@ -79,15 +111,18 @@ _ETL_BEGIN_NAMESPACE
 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];
@@ -136,7 +171,7 @@ strscanf(const std::string &data, const char*format, ...)
 }
 #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
@@ -150,21 +185,22 @@ basename(const std::string &str)
 {
        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());
@@ -175,21 +211,51 @@ dirname(const std::string &str)
 {
        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)
 {
@@ -197,7 +263,7 @@ 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;
 }
@@ -211,7 +277,7 @@ unix_to_local_path(const std::string &path)
                switch(*iter)
                {
                case '/':
-                       ret+=ETL_DIRECTORY_SEPERATOR;
+                       ret+=ETL_DIRECTORY_SEPARATOR;
                        break;
                case '~':
                        ret+='~';
@@ -239,12 +305,12 @@ get_root_from_path(std::string path)
 
        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;
 }
 
@@ -253,7 +319,7 @@ remove_root_from_path(std::string path)
 {
        while(!path.empty())
        {
-               if(path[0]==ETL_DIRECTORY_SEPERATOR)
+               if(path[0]==ETL_DIRECTORY_SEPARATOR)
                {
                        path.erase(path.begin());
                        return path;
@@ -268,27 +334,26 @@ cleanup_path(std::string 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;
 }
 
@@ -301,8 +366,7 @@ absolute_path(std::string path)
                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
@@ -324,15 +388,11 @@ relative_path(std::string curr_path,std::string dest_path)
        // 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))
        {
@@ -342,7 +402,7 @@ relative_path(std::string curr_path,std::string dest_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);
        }