From 3cf51083a8c01db53b9cf67d39f1f3d309eaac2c Mon Sep 17 00:00:00 2001 From: Marko Kreen Date: Wed, 3 Mar 2010 08:49:45 +0200 Subject: [PATCH] string: few improvements - 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 | 4 +-- usual/string.c | 90 +++++++++++++++++++++++++++++++++++++++++--------- usual/string.h | 25 +++++++++----- 3 files changed, 94 insertions(+), 25 deletions(-) diff --git a/m4/usual.m4 b/m4/usual.m4 index 8f15364..e75185a 100644 --- a/m4/usual.m4 +++ b/m4/usual.m4 @@ -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 diff --git a/usual/string.c b/usual/string.c index 376046d..74d12ab 100644 --- a/usual/string.c +++ b/usual/string.c @@ -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 diff --git a/usual/string.h b/usual/string.h index e59964b..db9c893 100644 --- a/usual/string.h +++ b/usual/string.h @@ -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 -- 2.39.5