X-Git-Url: http://git.tuebingen.mpg.de/?p=paraslash.git;a=blobdiff_plain;f=string.c;h=701448e041cfa9ff86dc1a6cccf37cd088b76c20;hp=b844fb381dc25eb50c47fa04c1c60a9d91f6ff0c;hb=f23669d91a09066b7ecd7b07a74bea8fad61ad39;hpb=a946afda2284a7b7f5f6020b27027fd543c054b2 diff --git a/string.c b/string.c index b844fb38..701448e0 100644 --- a/string.c +++ b/string.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004-2012 Andre Noll + * Copyright (C) 2004 Andre Noll * * Licensed under the GPL v2. For licencing details see COPYING. */ @@ -8,7 +8,6 @@ #define _GNU_SOURCE -#include /* gettimeofday */ #include #include /* uname() */ @@ -32,12 +31,12 @@ * 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 newly allocated memory, which is suitably aligned - * for any kind of variable and may be different from \a p. + * \return A pointer to newly allocated memory which is suitably aligned for + * any kind of variable and may be different from \a p. * * \sa realloc(3). */ -__must_check __malloc void *para_realloc(void *p, size_t size) +__must_check void *para_realloc(void *p, size_t size) { /* * No need to check for NULL pointers: If p is NULL, the call @@ -143,15 +142,18 @@ __must_check __malloc char *para_strdup(const char *s) __printf_2_0 unsigned xvasprintf(char **result, const char *fmt, va_list ap) { int ret; - size_t size; + size_t size = 150; va_list aq; + *result = para_malloc(size + 1); va_copy(aq, ap); - ret = vsnprintf(NULL, 0, fmt, aq); + ret = vsnprintf(*result, size, fmt, aq); va_end(aq); assert(ret >= 0); + if (ret < size) /* OK */ + return ret; size = ret + 1; - *result = para_malloc(size); + *result = para_realloc(*result, size); va_copy(aq, ap); ret = vsnprintf(*result, size, fmt, aq); va_end(aq); @@ -296,24 +298,6 @@ __must_check char *para_basename(const char *name) return ret; } -/** - * Cut trailing newline. - * - * \param buf The string to be chopped. - * - * Replace the last character in \p buf by zero if it is equal to - * the newline character. - */ -void chop(char *buf) -{ - int n = strlen(buf); - - if (!n) - return; - if (buf[n - 1] == '\n') - buf[n - 1] = '\0'; -} - /** * Get the logname of the current user. * @@ -357,19 +341,35 @@ __malloc char *para_hostname(void) } /** - * Used to distinguish between read-only and read-write mode. + * Call a custom function for each complete line. + * + * \param flags Any combination of flags defined in \ref for_each_line_flags. + * \param buf The buffer containing data separated by newlines. + * \param size The number of bytes in \a buf. + * \param line_handler The custom function. + * \param private_data Pointer passed to \a line_handler. + * + * For each complete line in \p buf, \p line_handler is called. The first + * argument to \p line_handler is (a copy of) the current line, and \p + * private_data is passed as the second argument. If the \p FELF_READ_ONLY + * flag is unset, a pointer into \a buf is passed to the line handler, + * otherwise a pointer to a copy of the current line is passed instead. This + * copy is freed immediately after the line handler returns. + * + * The function returns if \p line_handler returns a negative value or no more + * lines are in the buffer. The rest of the buffer (last chunk containing an + * incomplete line) is moved to the beginning of the buffer if FELF_READ_ONLY is + * unset. + * + * \return On success this function returns the number of bytes not handled to + * \p line_handler. The only possible error is a negative return value from the + * line handler. In this case processing stops and the return value of the line + * handler is returned to indicate failure. * - * \sa for_each_line(), for_each_line_ro(). + * \sa \ref for_each_line_flags. */ -enum for_each_line_modes{ - /** Activate read-only mode. */ - LINE_MODE_RO, - /** Activate read-write mode. */ - LINE_MODE_RW -}; - -static int for_each_complete_line(enum for_each_line_modes mode, char *buf, - size_t size, line_handler_t *line_handler, void *private_data) +int for_each_line(unsigned flags, char *buf, size_t size, + line_handler_t *line_handler, void *private_data) { char *start = buf, *end; int ret, i, num_lines = 0; @@ -380,95 +380,38 @@ static int for_each_complete_line(enum for_each_line_modes mode, char *buf, char *next_cr; next_cr = memchr(start, '\n', buf + size - start); - next_null = memchr(start, '\0', buf + size - start); + next_null = memchr(start, '\0', next_cr? + next_cr - start : buf + size - start); if (!next_cr && !next_null) break; - if (next_cr && next_null) { - end = next_cr < next_null? next_cr : next_null; - } else if (next_null) { + if (next_null) end = next_null; - } else + else end = next_cr; num_lines++; - if (!line_handler) { - start = ++end; - continue; - } - if (mode == LINE_MODE_RO) { - size_t s = end - start; - char *b = para_malloc(s + 1); - memcpy(b, start, s); - b[s] = '\0'; -// PARA_NOTICE_LOG("b: %s, start: %s\n", b, start); - ret = line_handler(b, private_data); - free(b); - } else { - *end = '\0'; - ret = line_handler(start, private_data); + if (!(flags & FELF_DISCARD_FIRST) || start != buf) { + if (flags & FELF_READ_ONLY) { + size_t s = end - start; + char *b = para_malloc(s + 1); + memcpy(b, start, s); + b[s] = '\0'; + ret = line_handler(b, private_data); + free(b); + } else { + *end = '\0'; + ret = line_handler(start, private_data); + } + if (ret < 0) + return ret; } - if (ret < 0) - return ret; start = ++end; } - if (!line_handler || mode == LINE_MODE_RO) - return num_lines; i = buf + size - start; - if (i && i != size) + if (i && i != size && !(flags & FELF_READ_ONLY)) memmove(buf, start, i); return i; } -/** - * Call a custom function for each complete line. - * - * \param buf The buffer containing data separated by newlines. - * \param size The number of bytes in \a buf. - * \param line_handler The custom function. - * \param private_data Pointer passed to \a line_handler. - * - * If \p line_handler is \p NULL, the function returns the number of complete - * lines in \p buf. Otherwise, \p line_handler is called for each complete - * line in \p buf. The first argument to \p line_handler is the current line, - * and \p private_data is passed as the second argument. The function returns - * if \p line_handler returns a negative value or no more lines are in the - * buffer. The rest of the buffer (last chunk containing an incomplete line) - * is moved to the beginning of the buffer. - * - * \return If \p line_handler is not \p NULL, this function returns the number - * of bytes not handled to \p line_handler on success, or the negative return - * value of the \p line_handler on errors. - * - * \sa for_each_line_ro(). - */ -int for_each_line(char *buf, size_t size, line_handler_t *line_handler, - void *private_data) -{ - return for_each_complete_line(LINE_MODE_RW, buf, size, line_handler, - private_data); -} - -/** - * Call a custom function for each complete line. - * - * \param buf Same meaning as in \p for_each_line(). - * \param size Same meaning as in \p for_each_line(). - * \param line_handler Same meaning as in \p for_each_line(). - * \param private_data Same meaning as in \p for_each_line(). - * - * This function behaves like \p for_each_line(), but \a buf is left unchanged. - * - * \return On success, the function returns the number of complete lines in \p - * buf, otherwise the (negative) return value of \p line_handler is returned. - * - * \sa for_each_line(). - */ -int for_each_line_ro(char *buf, size_t size, line_handler_t *line_handler, - void *private_data) -{ - return for_each_complete_line(LINE_MODE_RO, buf, size, line_handler, - private_data); -} - /** Return the hex characters of the lower 4 bits. */ #define hex(a) (hexchar[(a) & 15]) @@ -619,10 +562,18 @@ int para_atoi64(const char *str, int64_t *value) tmp = strtoll(str, &endptr, 10); if (errno == ERANGE && (tmp == LLONG_MAX || tmp == LLONG_MIN)) return -E_ATOI_OVERFLOW; - if (errno != 0 && tmp == 0) /* other error */ - return -E_STRTOLL; + /* + * If there were no digits at all, strtoll() stores the original value + * of str in *endptr. + */ if (endptr == str) return -E_ATOI_NO_DIGITS; + /* + * The implementation may also set errno and return 0 in case no + * conversion was performed. + */ + if (errno != 0 && tmp == 0) + return -E_ATOI_NO_DIGITS; if (*endptr != '\0') /* Further characters after number */ return -E_ATOI_JUNK_AT_END; *value = tmp; @@ -682,7 +633,7 @@ int get_loglevel_by_name(const char *txt) return LL_CRIT; if (loglevel_equal(txt, "emerg")) return LL_EMERG; - return -1; + return -E_BAD_LL; } static int get_next_word(const char *buf, const char *delim, char **word) @@ -1122,7 +1073,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 * sizeof(*dest)); + dest = para_malloc((num_wchars + 1) * sizeof(*dest)); src = s; memset(&state, 0, sizeof(state)); num_wchars = mbsrtowcs(dest, &src, num_wchars, &state);