string: few improvements
authorMarko Kreen <markokr@gmail.com>
Wed, 3 Mar 2010 06:49:45 +0000 (08:49 +0200)
committerMarko Kreen <markokr@gmail.com>
Wed, 3 Mar 2010 07:50:23 +0000 (09:50 +0200)
- new functions: memrchr, dirname

- dirname, basename: return either user path or static buffer,
  never modify user buffer.

- strerror_r: always define our own version, to avoid problems
  it system def changes (_GNU_SOURCE)

m4/usual.m4
usual/string.c
usual/string.h

index 8f15364e122f5d3bfabea98ccefab174a8575157..e75185a4eafabe3de85a7df7c55fb1633c38093a 100644 (file)
@@ -131,8 +131,8 @@ dnl  AC_USUAL_FUNCTION_CHECK:  Basic functions
 dnl
 AC_DEFUN([AC_USUAL_FUNCTION_CHECK], [
 ### Functions provided if missing
-AC_CHECK_FUNCS(basename strlcpy strlcat getpeereid sigaction)
-AC_CHECK_FUNCS(inet_ntop poll getline)
+AC_CHECK_FUNCS(basename dirname strlcpy strlcat getpeereid sigaction)
+AC_CHECK_FUNCS(inet_ntop poll getline memrchr)
 AC_CHECK_FUNCS(err errx warn warnx getprogname setprogname)
 AC_CHECK_FUNCS(posix_memalign memalign valloc)
 ### Functions provided only on win32
index 376046d559199b705dad6d884b7e8719ab9d4883..74d12ab9566b1007b507fb02db09149dcaa6f7cb 100644 (file)
@@ -210,12 +210,27 @@ size_t strlcat(char *dst, const char *src, size_t n)
 }
 #endif
 
+#ifndef HAVE_MEMRCHR
+void *memrchr(const void *s, int c, size_t n)
+{
+       const uint8_t *p = s;
+       while (n--) {
+               if (p[n] == c)
+                       return (void *)(p + n);
+       }
+       return NULL;
+}
+#endif
+
 #ifndef HAVE_BASENAME
-char *basename(char *path)
+const char *basename(const char *path)
 {
-       char *p, *p2;
+       const char *p, *p2;
+       static char buf[256];
+       unsigned len;
+
        if (path == NULL || path[0] == 0)
-               return ".";
+               return memcpy(buf, ".", 2);
        if ((p = strrchr(path, '/')) == NULL)
                return path;
        if (p[1])
@@ -224,8 +239,12 @@ char *basename(char *path)
        /* last char is '/' */
        for (p2 = p; p2 > path; p2--) {
                if (p2[-1] != '/') {
-                       *p2 = 0;
-                       return basename(path);
+                       len = p2 - path;
+                       if (len > sizeof(buf) - 1)
+                               len = sizeof(buf) - 1;
+                       memcpy(buf, p2 - len, len);
+                       buf[len] = 0;
+                       return basename(buf);
                }
        }
        /* path contains only '/' chars */
@@ -233,31 +252,72 @@ char *basename(char *path)
 }
 #endif
 
+#ifndef HAVE_DIRNAME
+const char *dirname(const char *path)
+{
+       const char *p;
+       size_t len;
+       static char buf[1024];
+
+       if (path == NULL || path[0] == 0)
+               return memcpy(buf, ".", 2);
+
+       /* ignore tailing '/' */
+       len = strlen(path);
+       while (len && path[len - 1] == '/')
+               len--;
+       if (!len)
+               return memcpy(buf, "/", 2);
+
+       /* find end of dirname, strip '/' */
+       if ((p = memrchr(path, '/', len)) == NULL)
+               return memcpy(buf, ".", 2);
+       len = p - path;
+       while (len && path[len - 1] == '/')
+               len--;
+       if (!len)
+               return memcpy(buf, "/", 2);
+
+       /* return it */
+       if (len > sizeof(buf) - 1) {
+               errno = ENAMETOOLONG;
+               return NULL;
+       }
+       memcpy(buf, path, len);
+       buf[len] = 0;
+       return buf;
+}
+#endif
+
 #ifdef WIN32
 const char *win32_strerror(int e)
 {
        static char buf[1024];
        return strerror_r(e, buf, sizeof(buf));
 }
-const char *win32_strerror_r(int e, char *dst, size_t dstlen)
+#endif
+
+/* restore original strerror_r() */
+#undef strerror_r
+
+const char *usual_strerror_r(int e, char *dst, size_t dstlen)
 {
+#ifdef WIN32
        FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, e,
                      MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
                      dst, dstlen, NULL);
-       return dst;
-}
-#else
-const char *wrap_strerror_r(int e, char *dst, size_t dstlen)
-{
-#undef strerror_r
+#else /* !WIN32 */
+
 #ifdef STRERROR_R_CHAR_P
-       return strerror_r(e, dst, dstlen);
+       dst = strerror_r(e, dst, dstlen);
 #else
        if (strerror_r(e, dst, dstlen) != 0)
                strlcpy(dst, "ERR", dstlen);
-       return dst;
 #endif
+
+#endif /* !WIN32 */
+
+       return dst;
 }
-#endif
 
 
index e59964b48eb3d0d8dd97734eb4461cf6e32b4f45..db9c8931a8c1cbe3665b444002ed5a905ca3101a 100644 (file)
@@ -37,6 +37,11 @@ size_t strlcpy(char *dst, const char *src, size_t n);
 size_t strlcat(char *dst, const char *src, size_t n);
 #endif
 
+#ifndef HAVE_MEMRCHR
+#define memrchr(a,b,c) usual_memrchr(a,b,c)
+void *memrchr(const void *s, int c, size_t n);
+#endif
+
 typedef bool (*str_cb)(void *arg, const char *s);
 
 struct StrList;
@@ -83,23 +88,27 @@ static inline int flsll(long long x) { _FLS(ll, long long); }
 
 
 #ifndef HAVE_BASENAME
-#define basename(a) compat_basename(a)
-char *basename(char *path);
+#define basename(a) usual_basename(a)
+const char *basename(const char *path);
+#endif
+
+#ifndef HAVE_DIRNAME
+#define dirname(a) usual_dirname(a)
+const char *dirname(const char *path);
 #endif
 
 /*
  * strerror, strerror_r
  */
+
 #ifdef WIN32
 const char *win32_strerror(int e);
 #define strerror(x) win32_strerror(x)
-const char *win32_strerror_r(int e, char *dst, size_t dstlen);
-#define strerror_r(a,b,c) win32_strerror_r(a,b,c)
-#else
-/* otherwise convert native strerror_r() to GNU signature */
-const char *wrap_strerror_r(int e, char *dst, size_t dstlen);
-#define strerror_r(a,b,c) wrap_strerror_r(a,b,c)
 #endif
 
+/* convert native strerror_r() to GNU signature */
+const char *usual_strerror_r(int e, char *dst, size_t dstlen);
+#define strerror_r(a,b,c) usual_strerror_r(a,b,c)
+
 #endif