X-Git-Url: http://git.tuebingen.mpg.de/?p=paraslash.git;a=blobdiff_plain;f=string.c;h=51985404817d032261d0f19ba2ebce35682156dd;hp=bd53e8d24462d1bbde5045f7b0b80de939460588;hb=299df142bb50bacebc0b3050768f941bc95b5b6f;hpb=df743de3c09a9f02c95bd3ff50e19a401b957efe diff --git a/string.c b/string.c index bd53e8d2..51985404 100644 --- a/string.c +++ b/string.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004-2008 Andre Noll + * Copyright (C) 2004-2009 Andre Noll * * Licensed under the GPL v2. For licencing details see COPYING. */ @@ -33,7 +33,7 @@ __must_check __malloc void *para_realloc(void *p, size_t size) { /* - * No need to check for NULL pointers: If p is NULL, the call + * No need to check for NULL pointers: If p is NULL, the call * to realloc is equivalent to malloc(size) */ assert(size); @@ -59,11 +59,12 @@ __must_check __malloc void *para_realloc(void *p, size_t size) */ __must_check __malloc void *para_malloc(size_t size) { - assert(size); - void *p = malloc(size); + void *p; + assert(size); + p = malloc(size); if (!p) { - PARA_EMERG_LOG("malloc failed (size = %zu), aborting\n", + PARA_EMERG_LOG("malloc failed (size = %zu), aborting\n", size); exit(EXIT_FAILURE); } @@ -98,7 +99,7 @@ __must_check __malloc void *para_calloc(size_t size) * 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. * - * \return A pointer to the duplicated string. If \p s was the NULL pointer, + * \return A pointer to the duplicated string. If \a s was the \p NULL pointer, * an pointer to an empty string is returned. * * \sa strdup(3) @@ -199,15 +200,15 @@ __must_check __malloc char *para_dirname(const char *name) * ends with a slash. Otherwise, a pointer within \a name is returned. Caller * must not free the result. */ -__must_check const char *para_basename(const char *name) +__must_check char *para_basename(const char *name) { - const char *ret; + char *ret; if (!name || !*name) return NULL; ret = strrchr(name, '/'); if (!ret) - return name; + return (char *)name; ret++; return ret; } @@ -217,44 +218,24 @@ __must_check const char *para_basename(const char *name) * * \param buf The string to be chopped. * - * Replace the last character in \p buf by zero if it is euqal to + * 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 a random filename. - * - * This is by no means a secure way to create temporary files in a hostile - * direcory like \p /tmp. However, it is OK to use for temp files, fifos, - * sockets that are created in ~/.paraslash. Result must be freed by the - * caller. - * - * \return A pointer to a random filename. - */ -__must_check __malloc char *para_tmpname(void) -{ - struct timeval now; - unsigned int seed; - - gettimeofday(&now, NULL); - seed = now.tv_usec; - srand(seed); - return make_message("%08i", rand()); -} - /** * Get the logname of the current user. * - * \return A dynammically allocated string that must be freed by the caller. On - * errors, the string "unknown user" is returned, i.e. this function never + * \return A dynamically allocated string that must be freed by the caller. On + * errors, the string "unknown_user" is returned, i.e. this function never * returns \p NULL. * * \sa getpwuid(3). @@ -268,7 +249,7 @@ __must_check __malloc char *para_logname(void) /** * Get the home directory of the current user. * - * \return A dynammically allocated string that must be freed by the caller. If + * \return A dynamically allocated string that must be freed by the caller. If * the home directory could not be found, this function returns "/tmp". */ __must_check __malloc char *para_homedir(void) @@ -284,16 +265,16 @@ __must_check __malloc char *para_homedir(void) * \param argv_ptr Pointer to the list of substrings. * \param delim Delimiter. * - * This function modifies \a args by replacing each occurance of \a delim by + * This function modifies \a args by replacing each occurrence of \a delim by * zero. A \p NULL-terminated array of pointers to char* is allocated dynamically * and these pointers are initialized to point to the broken-up substrings * within \a args. A pointer to this array is returned via \a argv_ptr. * * \return The number of substrings found in \a args. */ -__must_check unsigned split_args(char *args, char *** const argv_ptr, const char *delim) +unsigned split_args(char *args, char *** const argv_ptr, const char *delim) { - char *p = args; + char *p; char **argv; size_t n = 0, i, j; @@ -327,31 +308,10 @@ __must_check unsigned split_args(char *args, char *** const argv_ptr, const char return n; } -/** - * Ensure that file descriptors 0, 1, and 2 are valid. - * - * Common approach that opens /dev/null until it gets a file descriptor greater - * than two. - * - * \sa okir's Black Hats Manual. - */ -void valid_fd_012(void) -{ - while (1) { - int fd = open("/dev/null", O_RDWR); - if (fd < 0) - exit(EXIT_FAILURE); - if (fd > 2) { - close(fd); - break; - } - } -} - /** * Get the own hostname. * - * \return A dynammically allocated string containing the hostname. + * \return A dynamically allocated string containing the hostname. * * \sa uname(2). */ @@ -428,7 +388,7 @@ static int for_each_complete_line(enum for_each_line_modes mode, char *buf, /** * Call a custom function for each complete line. * - * \param buf The buffer containing data seperated by newlines. + * \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. @@ -476,15 +436,58 @@ int for_each_line_ro(char *buf, size_t size, line_handler_t *line_handler, private_data); } +#define hex(a) (hexchar[(a) & 15]) +static void write_size_header(char *buf, int n) +{ + static char hexchar[] = "0123456789abcdef"; + + buf[0] = hex(n >> 12); + buf[1] = hex(n >> 8); + buf[2] = hex(n >> 4); + buf[3] = hex(n); + buf[4] = ' '; +} + +int read_size_header(const char *buf) +{ + int i, len = 0; + + for (i = 0; i < 4; i++) { + unsigned char c = buf[i]; + len <<= 4; + if (c >= '0' && c <= '9') { + len += c - '0'; + continue; + } + if (c >= 'a' && c <= 'f') { + len += c - 'a' + 10; + continue; + } + return -E_SIZE_PREFIX; + } + if (buf[4] != ' ') + return -E_SIZE_PREFIX; + return len; +} + /** - * Safely print into a buffer at a given offset + * Safely print into a buffer at a given offset. * * \param b Determines the buffer, its size, and the offset. * \param fmt The format string. * * This function prints into the buffer given by \a b at the offset which is * also given by \a b. If there is not enough space to hold the result, the - * buffer size is doubled until the underlying call to vsnprintf() succeeds. + * buffer size is doubled until the underlying call to vsnprintf() succeeds + * or the size of the buffer exceeds the maximal size specified in \a b. + * + * In the latter case the unmodified \a buf and \a offset values as well as the + * private_data pointer of \a b are passed to the \a max_size_handler of \a b. + * If this function succeeds, i.e. returns a non-negative value, the offset of + * \a b is reset to zero and the given data is written to the beginning of the + * buffer. If \a max_size_handler() returns a negative value, this value is + * returned by \a para_printf(). + * * Upon return, the offset of \a b is adjusted accordingly so that subsequent * calls to this function append data to what is already contained in the * buffer. @@ -493,38 +496,52 @@ int for_each_line_ro(char *buf, size_t size, line_handler_t *line_handler, * initial buffer is allocated. * * \return The number of bytes printed into the buffer (not including the - * therminating \p NULL byte). + * terminating \p NULL byte) on success, negative on errors. If there is no + * size-bound on \a b, i.e. if \p b->max_size is zero, this function never + * fails. * * \sa make_message(), vsnprintf(3). */ __printf_2_3 int para_printf(struct para_buffer *b, const char *fmt, ...) { - int ret; + int ret, sz_off = (b->flags & PBF_SIZE_PREFIX)? 5 : 0; if (!b->buf) { b->buf = para_malloc(128); b->size = 128; b->offset = 0; - } else if (b->size <= b->offset + 1) { - b->size *= 2; - b->buf = para_realloc(b->buf, b->size); } while (1) { char *p = b->buf + b->offset; size_t size = b->size - b->offset; va_list ap; - va_start(ap, fmt); - ret = vsnprintf(p, size, fmt, ap); - va_end(ap); - if (ret > -1 && ret < size) { /* success */ - b->offset += ret; - break; + + if (size > sz_off) { + va_start(ap, fmt); + ret = vsnprintf(p + sz_off, size - sz_off, fmt, ap); + va_end(ap); + if (ret > -1 && ret < size - sz_off) { /* success */ + b->offset += ret + sz_off; + if (sz_off) + write_size_header(p, ret); + return ret + sz_off; + } + } + /* check if we may grow the buffer */ + if (!b->max_size || 2 * b->size < b->max_size) { /* yes */ + /* try again with more space */ + b->size *= 2; + b->buf = para_realloc(b->buf, b->size); + continue; } - /* try again with more space */ - b->size *= 2; - b->buf = para_realloc(b->buf, b->size); + /* can't grow buffer */ + if (!b->offset || !b->max_size_handler) /* message too large */ + return -ERRNO_TO_PARA_ERROR(ENOSPC); + ret = b->max_size_handler(b->buf, b->offset, b->private_data); + if (ret < 0) + return ret; + b->offset = 0; } - return ret; } /** \cond LLONG_MAX and LLONG_LIN might not be defined. */ @@ -589,3 +606,34 @@ int para_atoi32(const char *str, int32_t *value) *value = tmp; 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 -1; +}