X-Git-Url: http://git.tuebingen.mpg.de/?p=paraslash.git;a=blobdiff_plain;f=string.c;h=e5de147c65975c21018b3e0b6d30eb932e52edf1;hp=3bddd5e80896e843470687671a05cb0ef09051e2;hb=24758c5f;hpb=ef1f130a1f9ac61a51da10ee56c5bd9ef1b52366 diff --git a/string.c b/string.c index 3bddd5e8..e5de147c 100644 --- a/string.c +++ b/string.c @@ -1,12 +1,11 @@ /* - * Copyright (C) 2004-2011 Andre Noll + * Copyright (C) 2004-2013 Andre Noll * * Licensed under the GPL v2. For licencing details see COPYING. */ /** \file string.c Memory allocation and string handling functions. */ -#include /* gettimeofday */ #include #include /* uname() */ #include @@ -114,6 +113,65 @@ __must_check __malloc char *para_strdup(const char *s) exit(EXIT_FAILURE); } +/** + * Print a formated message to a dynamically allocated string. + * + * \param result The formated string is returned here. + * \param fmt The format string. + * \param ap Initialized list of arguments. + * + * This function is similar to vasprintf(), a GNU extension which is not in C + * or POSIX. It allocates a string large enough to hold the output including + * the terminating null byte. The allocated string is returned via the first + * argument and must be freed by the caller. However, unlike vasprintf(), this + * function calls exit() if insufficient memory is available, while vasprintf() + * returns -1 in this case. + * + * \return Number of bytes written, not including the terminating \p NULL + * character. + * + * \sa printf(3), vsnprintf(3), va_start(3), vasprintf(3), \ref xasprintf(). + */ +__printf_2_0 unsigned xvasprintf(char **result, const char *fmt, va_list ap) +{ + int ret; + size_t size; + va_list aq; + + va_copy(aq, ap); + ret = vsnprintf(NULL, 0, fmt, aq); + va_end(aq); + assert(ret >= 0); + size = ret + 1; + *result = para_malloc(size); + va_copy(aq, ap); + ret = vsnprintf(*result, size, fmt, aq); + va_end(aq); + assert(ret >= 0 && ret < size); + return ret; +} + +/** + * Print to a dynamically allocated string, variable number of arguments. + * + * \param result See \ref xvasprintf(). + * \param fmt Usual format string. + * + * \return The return value of the underlying call to \ref xvasprintf(). + * + * \sa \ref xvasprintf() and the references mentioned there. + */ +__printf_2_3 unsigned xasprintf(char **result, const char *fmt, ...) +{ + va_list ap; + unsigned ret; + + va_start(ap, fmt); + ret = xvasprintf(result, fmt, ap); + va_end(ap); + return ret; +} + /** * Allocate a sufficiently large string and print into it. * @@ -125,13 +183,16 @@ __must_check __malloc char *para_strdup(const char *s) * \return This function either returns a pointer to a string that must be * freed by the caller or aborts without returning. * - * \sa printf(3). + * \sa printf(3), xasprintf(). */ __must_check __printf_1_2 __malloc char *make_message(const char *fmt, ...) { char *msg; + va_list ap; - PARA_VSPRINTF(fmt, msg); + va_start(ap, fmt); + xvasprintf(&msg, fmt, ap); + va_end(ap); return msg; } @@ -738,7 +799,7 @@ int compute_word_num(const char *buf, const char *delim, int point) } /** - * Free an array of words created by create_argv(). + * Free an array of words created by create_argv() or create_shifted_argv(). * * \param argv A pointer previously obtained by \ref create_argv(). */ @@ -753,6 +814,35 @@ void free_argv(char **argv) free(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 *)); + const char *p; + int i, ret; + + for (i = 0; i < offset; i++) + argv[i] = NULL; + for (p = buf; p && *p; p += ret, i++) { + ret = get_next_word(p, delim, &word); + if (ret < 0) + goto err; + if (!ret) + break; + argv = para_realloc(argv, (i + 2) * sizeof(char*)); + argv[i] = word; + } + argv[i] = NULL; + *result = argv; + return i; +err: + while (i > 0) + free(argv[--i]); + free(argv); + *result = NULL; + return ret; +} + /** * Split a buffer into words. * @@ -769,28 +859,47 @@ void free_argv(char **argv) */ int create_argv(const char *buf, const char *delim, char ***result) { - char *word, **argv = para_malloc(2 * sizeof(char *)); - const char *p; - int ret, num_words; + return create_argv_offset(0, buf, delim, result); +} - for (p = buf, num_words = 0; ; p += ret, num_words++) { - ret = get_next_word(p, delim, &word); - if (ret < 0) - goto err; - if (!ret) - break; - argv = para_realloc(argv, (num_words + 2) * sizeof(char*)); - argv[num_words] = word; - } - argv[num_words] = NULL; - *result = argv; - return num_words; -err: - while (num_words > 0) - free(argv[--num_words]); - free(argv); - *result = NULL; - return ret; +/** + * Split a buffer into words, offset one. + * + * This is similar to \ref create_argv() but the returned array is one element + * larger, words start at index one and element zero is initialized to \p NULL. + * Callers must set element zero to a non-NULL value before calling free_argv() + * on the returned array to avoid a memory leak. + * + * \param buf See \ref create_argv(). + * \param delim See \ref create_argv(). + * \param result See \ref create_argv(). + * + * \return Number of words plus one on success, negative on errors. + */ +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; } /**