X-Git-Url: http://git.tuebingen.mpg.de/?a=blobdiff_plain;f=string.c;h=46b346235f17ffb696f43d22d3dcfde4c75ba4ca;hb=be5daec66f163725489f42d512659a8af5c3fd59;hp=6033a008dbf154953de673f85048eb78812d1722;hpb=94802b02fadd65ac1704fe9fcbcf0a2b023d2fa4;p=paraslash.git diff --git a/string.c b/string.c index 6033a008..46b34623 100644 --- a/string.c +++ b/string.c @@ -1,8 +1,4 @@ -/* - * Copyright (C) 2004 Andre Noll - * - * Licensed under the GPL v2. For licencing details see COPYING. - */ +/* Copyright (C) 2004 Andre Noll , see file COPYING. */ /** \file string.c Memory allocation and string handling functions. */ @@ -10,7 +6,6 @@ #include #include /* uname() */ -#include #include #include #include @@ -20,78 +15,124 @@ #include "error.h" /** - * Paraslash's version of realloc(). + * Reallocate an array, abort on failure or bugs. * - * \param p Pointer to the memory block, may be \p NULL. - * \param size The desired new size. + * \param ptr Pointer to the memory block, may be NULL. + * \param nmemb Number of elements. + * \param size The size of one element in bytes. * - * A wrapper for realloc(3). It calls \p exit(\p EXIT_FAILURE) on errors, - * i.e. there is no need to check the return value in the caller. + * A wrapper for realloc(3) which aborts on invalid arguments or integer + * overflow. The wrapper also terminates the current process on allocation + * errors, so the caller does not need to check for failure. * * \return A pointer to newly allocated memory which is suitably aligned for - * any kind of variable and may be different from \a p. + * any kind of variable and may be different from ptr. * * \sa realloc(3). */ -__must_check void *para_realloc(void *p, size_t size) +__must_check void *arr_realloc(void *ptr, size_t nmemb, size_t size) +{ + size_t pr; + + assert(size > 0); + assert(nmemb > 0); + assert(!__builtin_mul_overflow(nmemb, size, &pr)); + assert(pr != 0); + ptr = realloc(ptr, pr); + assert(ptr); + return ptr; +} + +/** + * Allocate an array, abort on failure or bugs. + * + * \param nmemb See \ref arr_realloc(). + * \param size See \ref arr_realloc(). + * + * Like \ref arr_realloc(), this aborts on invalid arguments, integer overflow + * and allocation errors. + * + * \return A pointer to newly allocated memory which is suitably aligned for + * any kind of variable. + * + * \sa See \ref arr_realloc(). + */ +__must_check __malloc void *arr_alloc(size_t nmemb, size_t size) +{ + return arr_realloc(NULL, nmemb, size); +} + +/** + * Allocate and initialize an array, abort on failure or bugs. + * + * \param nmemb See \ref arr_realloc(). + * \param size See \ref arr_realloc(). + * + * This calls \ref arr_alloc() and zeroes-out the array. + * + * \return See \ref arr_alloc(). + */ +__must_check __malloc void *arr_zalloc(size_t nmemb, size_t size) { + void *ptr = arr_alloc(nmemb, size); + /* - * No need to check for NULL pointers: If p is NULL, the call - * to realloc is equivalent to malloc(size) + * This multiplication can not overflow because the above call to \ref + * arr_alloc() aborts on overflow. */ - assert(size); - if (!(p = realloc(p, size))) { - PARA_EMERG_LOG("realloc failed (size = %zu), aborting\n", - size); - exit(EXIT_FAILURE); - } - return p; + memset(ptr, 0, nmemb * size); + return ptr; } /** - * Paraslash's version of malloc(). + * Allocate and initialize memory. * * \param size The desired new size. * - * A wrapper for malloc(3) which exits on errors. - * - * \return A pointer to the allocated memory, which is suitably aligned for any - * kind of variable. + * \return A pointer to the allocated and zeroed-out memory, which is suitably + * aligned for any kind of variable. * - * \sa malloc(3). + * \sa \ref alloc(), calloc(3). */ -__must_check __malloc void *para_malloc(size_t size) +__must_check void *zalloc(size_t size) { - void *p; - - assert(size); - p = malloc(size); - if (!p) { - PARA_EMERG_LOG("malloc failed (size = %zu), aborting\n", - size); - exit(EXIT_FAILURE); - } - return p; + return arr_zalloc(1, size); } /** - * Paraslash's version of calloc(). + * Paraslash's version of realloc(). * + * \param p Pointer to the memory block, may be \p NULL. * \param size The desired new size. * - * A wrapper for calloc(3) which exits on errors. + * A wrapper for realloc(3). It calls \p exit(\p EXIT_FAILURE) on errors, + * i.e. there is no need to check the return value in the caller. * - * \return A pointer to the allocated and zeroed-out memory, which is suitably - * aligned for any kind of variable. + * \return A pointer to newly allocated memory which is suitably aligned for + * any kind of variable and may be different from \a p. * - * \sa calloc(3) + * \sa realloc(3). */ -__must_check __malloc void *para_calloc(size_t size) +__must_check void *para_realloc(void *p, size_t size) { - void *ret = para_malloc(size); + return arr_realloc(p, 1, size); +} - memset(ret, 0, size); - return ret; +/** + * Paraslash's version of malloc(). + * + * \param size The desired new size. + * + * A wrapper for malloc(3) which exits on errors. + * + * \return A pointer to the allocated memory, which is suitably aligned for any + * kind of variable. + * + * \sa malloc(3). + */ +__must_check __malloc void *alloc(size_t size) +{ + return arr_alloc(1, size); } /** @@ -99,28 +140,29 @@ __must_check __malloc void *para_calloc(size_t size) * * \param s The string to be duplicated. * - * A wrapper for strdup(3). It calls \p exit(EXIT_FAILURE) on errors, i.e. - * there is no need to check the return value in the caller. + * A strdup(3)-like function which aborts if insufficient memory was available + * to allocate the duplicated string, absolving the caller from the + * responsibility to check for failure. * - * \return A pointer to the duplicated string. If \a s was the \p NULL pointer, - * an pointer to an empty string is returned. + * \return A pointer to the duplicated string. Unlike strdup(3), the caller may + * pass NULL, in which case the function returns a pointer to an empty string. + * Regardless of whether or not NULL was passed, the returned string is + * allocated on the heap and has to be freed by the caller. * - * \sa strdup(3) + * \sa strdup(3). */ __must_check __malloc char *para_strdup(const char *s) { - char *ret; + char *dupped_string = strdup(s? s: ""); - if ((ret = strdup(s? s: ""))) - return ret; - PARA_EMERG_LOG("strdup failed, aborting\n"); - exit(EXIT_FAILURE); + assert(dupped_string); + return dupped_string; } /** - * Print a formated message to a dynamically allocated string. + * Print a formatted message to a dynamically allocated string. * - * \param result The formated string is returned here. + * \param result The formatted string is returned here. * \param fmt The format string. * \param ap Initialized list of arguments. * @@ -142,7 +184,7 @@ __printf_2_0 unsigned xvasprintf(char **result, const char *fmt, va_list ap) size_t size = 150; va_list aq; - *result = para_malloc(size + 1); + *result = alloc(size + 1); va_copy(aq, ap); ret = vsnprintf(*result, size, fmt, aq); va_end(aq); @@ -190,7 +232,7 @@ __printf_2_3 unsigned xasprintf(char **result, const char *fmt, ...) * \return This function either returns a pointer to a string that must be * freed by the caller or aborts without returning. * - * \sa printf(3), xasprintf(). + * \sa printf(3), \ref xasprintf(). */ __must_check __printf_1_2 __malloc char *make_message(const char *fmt, ...) { @@ -204,17 +246,22 @@ __must_check __printf_1_2 __malloc char *make_message(const char *fmt, ...) } /** - * Free the content of a pointer and set it to \p NULL. + * Free the content of a pointer and set it to NULL. * - * This is equivalent to "free(*arg); *arg = NULL;". + * \param arg A pointer to the pointer whose content should be freed. * - * \param arg The pointer whose content should be freed. + * If arg is NULL, the function returns immediately. Otherwise it frees the + * memory pointed to by *arg and sets *arg to NULL. Hence callers have to pass + * the *address* of the pointer variable that points to the memory which should + * be freed. */ void freep(void *arg) { - void **ptr = (void **)arg; - free(*ptr); - *ptr = NULL; + if (arg) { + void **ptr = arg; + free(*ptr); + *ptr = NULL; + } } /** @@ -230,7 +277,7 @@ void freep(void *arg) * return \a a without making a copy of \a a. Otherwise, construct the * concatenation \a c, free \a a (but not \a b) and return \a c. * - * \sa strcat(3) + * \sa strcat(3). */ __must_check __malloc char *para_strcat(char *a, const char *b) { @@ -245,56 +292,6 @@ __must_check __malloc char *para_strcat(char *a, const char *b) return tmp; } -/** - * Paraslash's version of dirname(). - * - * \param name Pointer to the full path. - * - * Compute the directory component of \p name. - * - * \return If \a name is \p NULL or the empty string, return \p NULL. - * Otherwise, Make a copy of \a name and return its directory component. Caller - * is responsible to free the result. - */ -__must_check __malloc char *para_dirname(const char *name) -{ - char *p, *ret; - - if (!name || !*name) - return NULL; - ret = para_strdup(name); - p = strrchr(ret, '/'); - if (!p) - *ret = '\0'; - else - *p = '\0'; - return ret; -} - -/** - * Paraslash's version of basename(). - * - * \param name Pointer to the full path. - * - * Compute the filename component of \a name. - * - * \return \p NULL if (a) \a name is the empty string or \p NULL, or (b) name - * ends with a slash. Otherwise, a pointer within \a name is returned. Caller - * must not free the result. - */ -__must_check char *para_basename(const char *name) -{ - char *ret; - - if (!name || !*name) - return NULL; - ret = strrchr(name, '/'); - if (!ret) - return (char *)name; - ret++; - return ret; -} - /** * Get the logname of the current user. * @@ -389,7 +386,7 @@ int for_each_line(unsigned flags, char *buf, size_t size, if (!(flags & FELF_DISCARD_FIRST) || start != buf) { if (flags & FELF_READ_ONLY) { size_t s = end - start; - char *b = para_malloc(s + 1); + char *b = alloc(s + 1); memcpy(b, start, s); b[s] = '\0'; ret = line_handler(b, private_data); @@ -493,7 +490,7 @@ __printf_2_3 int para_printf(struct para_buffer *b, const char *fmt, ...) int ret, sz_off = (b->flags & PBF_SIZE_PREFIX)? 5 : 0; if (!b->buf) { - b->buf = para_malloc(128); + b->buf = alloc(128); b->size = 128; b->offset = 0; } @@ -548,7 +545,7 @@ __printf_2_3 int para_printf(struct para_buffer *b, const char *fmt, ...) * * \return Standard. * - * \sa para_atoi32(), strtol(3), atoi(3). + * \sa \ref para_atoi32(), strtol(3), atoi(3). */ int para_atoi64(const char *str, int64_t *value) { @@ -585,7 +582,7 @@ int para_atoi64(const char *str, int64_t *value) * * \return Standard. * - * \sa para_atoi64(). + * \sa \ref para_atoi64(). */ int para_atoi32(const char *str, int32_t *value) { @@ -602,37 +599,6 @@ int para_atoi32(const char *str, int32_t *value) return 1; } -static inline int loglevel_equal(const char *arg, const char * const ll) -{ - return !strncasecmp(arg, ll, strlen(ll)); -} - -/** - * Compute the loglevel number from its name. - * - * \param txt The name of the loglevel (debug, info, ...). - * - * \return The numeric representation of the loglevel name. - */ -int get_loglevel_by_name(const char *txt) -{ - if (loglevel_equal(txt, "debug")) - return LL_DEBUG; - if (loglevel_equal(txt, "info")) - return LL_INFO; - if (loglevel_equal(txt, "notice")) - return LL_NOTICE; - if (loglevel_equal(txt, "warning")) - return LL_WARNING; - if (loglevel_equal(txt, "error")) - return LL_ERROR; - if (loglevel_equal(txt, "crit")) - return LL_CRIT; - if (loglevel_equal(txt, "emerg")) - return LL_EMERG; - return -E_BAD_LL; -} - static int get_next_word(const char *buf, const char *delim, char **word) { enum line_state_flags {LSF_HAVE_WORD = 1, LSF_BACKSLASH = 2, @@ -641,7 +607,7 @@ static int get_next_word(const char *buf, const char *delim, char **word) char *out; int ret, state = 0; - out = para_malloc(strlen(buf) + 1); + out = alloc(strlen(buf) + 1); *out = '\0'; *word = out; for (in = buf; *in; in++) { @@ -773,7 +739,7 @@ void free_argv(char **argv) static int create_argv_offset(int offset, const char *buf, const char *delim, char ***result) { - char *word, **argv = para_malloc((offset + 1) * sizeof(char *)); + char *word, **argv = arr_alloc(offset + 1, sizeof(char *)); const char *p; int i, ret; @@ -785,7 +751,7 @@ static int create_argv_offset(int offset, const char *buf, const char *delim, goto err; if (!ret) break; - argv = para_realloc(argv, (i + 2) * sizeof(char*)); + argv = arr_realloc(argv, i + 2, sizeof(char*)); argv[i] = word; } argv[i] = NULL; @@ -840,27 +806,6 @@ int create_shifted_argv(const char *buf, const char *delim, char ***result) return create_argv_offset(1, buf, delim, result); } -/** - * Find out if the given string is contained in the arg vector. - * - * \param arg The string to look for. - * \param argv The array to search. - * - * \return The first index whose value equals \a arg, or \p -E_ARG_NOT_FOUND if - * arg was not found in \a argv. - */ -int find_arg(const char *arg, char **argv) -{ - int i; - - if (!argv) - return -E_ARG_NOT_FOUND; - for (i = 0; argv[i]; i++) - if (strcmp(arg, argv[i]) == 0) - return i; - return -E_ARG_NOT_FOUND; -} - /** * Compile a regular expression. * @@ -881,7 +826,7 @@ int para_regcomp(regex_t *preg, const char *regex, int cflags) if (ret == 0) return 1; size = regerror(ret, preg, NULL, 0); - buf = para_malloc(size); + buf = alloc(size); regerror(ret, preg, buf, size); PARA_ERROR_LOG("%s\n", buf); free(buf); @@ -907,7 +852,7 @@ char *safe_strdup(const char *src, size_t len) char *p; assert(len < (size_t)-1); - p = para_malloc(len + 1); + p = alloc(len + 1); if (len > 0) memcpy(p, src, len); p[len] = '\0'; @@ -1061,7 +1006,7 @@ __must_check int strwidth(const char *s, size_t *result) return -ERRNO_TO_PARA_ERROR(errno); if (num_wchars == 0) return 0; - dest = para_malloc((num_wchars + 1) * sizeof(*dest)); + dest = arr_alloc(num_wchars + 1, sizeof(*dest)); src = s; memset(&state, 0, sizeof(state)); num_wchars = mbsrtowcs(dest, &src, num_wchars, &state); @@ -1116,7 +1061,7 @@ __must_check int sanitize_str(const char *src, size_t max_width, num_wchars = mbsrtowcs(NULL, &src, 0, &state); if (num_wchars == (size_t)-1) return -ERRNO_TO_PARA_ERROR(errno); - wcs = para_malloc((num_wchars + 1) * sizeof(*wcs)); + wcs = arr_alloc(num_wchars + 1, sizeof(*wcs)); memset(&state, 0, sizeof(state)); num_wchars = mbsrtowcs(wcs, &src, num_wchars + 1, &state); assert(num_wchars != (size_t)-1); @@ -1127,7 +1072,7 @@ __must_check int sanitize_str(const char *src, size_t max_width, } wcs[n] = L'\0'; n = wcstombs(NULL, wcs, 0) + 1; - *result = para_malloc(n); + *result = alloc(n); num_wchars = wcstombs(*result, wcs, n); assert(num_wchars != (size_t)-1); free(wcs);