/* * Replacements for common but usually nonstandard functions that aren't * supplied by all platforms. * * Copyright (C) 2009 by Dan Fandrich <dan@coneharvesters.com>, et. al. * * Licensed under GPLv2, see file LICENSE in this source tree. */ #include "libbb.h" #ifndef HAVE_STRCHRNUL char* FAST_FUNC strchrnul(const char *s, int c) { while (*s != '\0' && *s != c) s++; return (char*)s; } #endif #ifndef HAVE_USLEEP int FAST_FUNC usleep(unsigned usec) { struct timespec ts; ts.tv_sec = usec / 1000000u; ts.tv_nsec = (usec % 1000000u) * 1000u; /* * If a signal has non-default handler, nanosleep returns early. * Our version of usleep doesn't return early * if interrupted by such signals: * */ while (nanosleep(&ts, &ts) != 0) continue; return 0; } #endif #ifndef HAVE_VASPRINTF int FAST_FUNC vasprintf(char **string_ptr, const char *format, va_list p) { int r; va_list p2; char buf[128]; va_copy(p2, p); r = vsnprintf(buf, 128, format, p); va_end(p); /* Note: can't use xstrdup/xmalloc, they call vasprintf (us) on failure! */ if (r < 128) { va_end(p2); *string_ptr = strdup(buf); return (*string_ptr ? r : -1); } *string_ptr = malloc(r+1); r = (*string_ptr ? vsnprintf(*string_ptr, r+1, format, p2) : -1); va_end(p2); return r; } #endif #ifndef HAVE_DPRINTF /* dprintf is now part of POSIX.1, but was only added in 2008 */ int dprintf(int fd, const char *format, ...) { va_list p; int r; char *string_ptr; va_start(p, format); r = vasprintf(&string_ptr, format, p); va_end(p); if (r >= 0) { r = full_write(fd, string_ptr, r); free(string_ptr); } return r; } #endif #ifndef HAVE_MEMRCHR /* Copyright (C) 2005 Free Software Foundation, Inc. * memrchr() is a GNU function that might not be available everywhere. * It's basically the inverse of memchr() - search backwards in a * memory block for a particular character. */ void* FAST_FUNC memrchr(const void *s, int c, size_t n) { const char *start = s, *end = s; end += n - 1; while (end >= start) { if (*end == (char)c) return (void *) end; end--; } return NULL; } #endif #ifndef HAVE_MKDTEMP /* This is now actually part of POSIX.1, but was only added in 2008 */ char* FAST_FUNC mkdtemp(char *template) { if (mktemp(template) == NULL || mkdir(template, 0700) != 0) return NULL; return template; } #endif #ifndef HAVE_STRCASESTR /* Copyright (c) 1999, 2000 The ht://Dig Group */ char* FAST_FUNC strcasestr(const char *s, const char *pattern) { int length = strlen(pattern); while (*s) { if (strncasecmp(s, pattern, length) == 0) return (char *)s; s++; } return 0; } #endif #ifndef HAVE_STRSEP /* Copyright (C) 2004 Free Software Foundation, Inc. */ char* FAST_FUNC strsep(char **stringp, const char *delim) { char *start = *stringp; char *ptr; if (!start) return NULL; if (!*delim) ptr = start + strlen(start); else { ptr = strpbrk(start, delim); if (!ptr) { *stringp = NULL; return start; } } *ptr = '\0'; *stringp = ptr + 1; return start; } #endif #ifndef HAVE_STPCPY char* FAST_FUNC stpcpy(char *p, const char *to_add) { while ((*p = *to_add) != '\0') { p++; to_add++; } return p; } #endif #ifndef HAVE_GETLINE ssize_t FAST_FUNC getline(char **lineptr, size_t *n, FILE *stream) { int ch; char *line = *lineptr; size_t alloced = *n; size_t len = 0; do { ch = fgetc(stream); if (ch == EOF) break; if (len + 1 >= alloced) { alloced += alloced/4 + 64; line = xrealloc(line, alloced); } line[len++] = ch; } while (ch != '\n'); if (len == 0) return -1; line[len] = '\0'; *lineptr = line; *n = alloced; return len; } #endif #ifndef HAVE_TTYNAME_R int ttyname_r(int fd, char *buf, size_t buflen) { int r; char path[sizeof("/proc/self/fd/%d") + sizeof(int)*3]; if (!isatty(fd)) return errno == EINVAL ? ENOTTY : errno; sprintf(path, "/proc/self/fd/%d", fd); r = readlink(path, buf, buflen); if (r < 0) return errno; if (r >= buflen) return ERANGE; buf[r] = '\0'; return 0; } #endif