/**
 * prelude_string_vprintf:
 * @string: Pointer to a #prelude_string_t object.
 * @fmt: Format string to use.
 * @ap: Variable argument list.
 *
 * Produce output according to @fmt, storing argument provided in @ap
 * variable argument list, and write the output to the given @string.
 * See sprintf(3) for more information on @fmt format.
 *
 * Returns: The number of characters written, or a negative value if an error occured.
 */
int prelude_string_vprintf(prelude_string_t *string, const char *fmt, va_list ap)
{
        int ret;
        va_list bkp;

        prelude_return_val_if_fail(string, prelude_error(PRELUDE_ERROR_ASSERTION));
        prelude_return_val_if_fail(fmt, prelude_error(PRELUDE_ERROR_ASSERTION));

        if ( ! (string->flags & PRELUDE_STRING_OWN_DATA) ) {

                ret = allocate_more_chunk_if_needed(string, 0);
                if ( ret < 0 )
                        return ret;
        }

        PRELUDE_VA_COPY(bkp, ap);
        ret = vsnprintf(string->data.rwbuf + string->index, string->size - string->index, fmt, ap);

        /*
         * From sprintf(3) on GNU/Linux:
         *
         * snprintf  and vsnprintf do not write more than
         * size bytes (including the trailing '\0'), and return -1 if
         * the  output  was truncated due to this limit.  (Thus until
         * glibc 2.0.6. Since glibc 2.1 these  functions  follow  the
         * C99  standard and return the number of characters (exclud-
         * ing the trailing '\0') which would have  been  written  to
         * the final string if enough space had been available.)
         */
        if ( ret >= 0 && (size_t) ret < string->size - string->index ) {
                string->index += ret;
                goto end;
        }

        ret = allocate_more_chunk_if_needed(string, (ret < 0) ? 0 : ret + 1);
        if ( ret < 0 )
                goto end;

        ret = prelude_string_vprintf(string, fmt, bkp);

 end:
        va_end(bkp);
        return ret;
}
Exemple #2
0
static void do_log_v(prelude_log_t level, const char *file,
                     const char *function, int line, const char *fmt, va_list ap)
{
        int ret;
        va_list bkp;
        char buf[1024];
        ssize_t len = 0;

        if ( global_log_cb == do_log_print || global_log_cb == do_log_syslog ) {
                len = get_header(level, buf, sizeof(buf));
                if ( len < 0 )
                        return;
        }

        PRELUDE_VA_COPY(bkp, ap);

        ret = vsnprintf(buf + len, sizeof(buf) - len, fmt, ap);
        if ( ret < 0 || (size_t) ret >= (sizeof(buf) - len) )
                goto out;

        if ( level <= PRELUDE_LOG_ERR || level >= PRELUDE_LOG_DEBUG ) {
                for ( len += ret; buf[len - 1] == '\n' ; len-- );
                snprintf(buf + len, sizeof(buf) - len, " (%s:%d %s)\n", file, line, function);
        }

        if ( need_to_log(level, log_level) || need_to_log(level, debug_level) ) {
                ret = global_log_cb(level, buf);
                if ( ret < 0 && global_log_cb == do_log_print ) {
                        prelude_log_set_flags(PRELUDE_LOG_FLAGS_SYSLOG);
                        do_log_v(level, file, function, line, fmt, bkp);
                        goto out;
                }

                if ( debug_logfile )
                        fprintf(debug_logfile, "%s", buf);
        }

out:
        va_end(bkp);
}