src/printf.c

Fri, 12 Apr 2024 21:48:12 +0200

author
Mike Becker <universe@uap-core.de>
date
Fri, 12 Apr 2024 21:48:12 +0200
changeset 849
edb9f875b7f9
parent 813
aba6d37b78bd
permissions
-rw-r--r--

improves interface of cx_sprintf() variants

     1 /*
     2  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
     3  *
     4  * Copyright 2021 Mike Becker, Olaf Wintermann All rights reserved.
     5  *
     6  * Redistribution and use in source and binary forms, with or without
     7  * modification, are permitted provided that the following conditions are met:
     8  *
     9  *   1. Redistributions of source code must retain the above copyright
    10  *      notice, this list of conditions and the following disclaimer.
    11  *
    12  *   2. Redistributions in binary form must reproduce the above copyright
    13  *      notice, this list of conditions and the following disclaimer in the
    14  *      documentation and/or other materials provided with the distribution.
    15  *
    16  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
    17  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
    18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
    19  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
    20  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
    21  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
    22  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
    23  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
    24  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
    25  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
    26  * POSSIBILITY OF SUCH DAMAGE.
    27  */
    29 #include "cx/printf.h"
    31 #include <stdio.h>
    32 #include <string.h>
    34 #ifndef CX_PRINTF_SBO_SIZE
    35 #define CX_PRINTF_SBO_SIZE 512
    36 #endif
    37 unsigned const cx_printf_sbo_size = CX_PRINTF_SBO_SIZE;
    39 int cx_fprintf(
    40         void *stream,
    41         cx_write_func wfc,
    42         char const *fmt,
    43         ...
    44 ) {
    45     int ret;
    46     va_list ap;
    47     va_start(ap, fmt);
    48     ret = cx_vfprintf(stream, wfc, fmt, ap);
    49     va_end(ap);
    50     return ret;
    51 }
    53 int cx_vfprintf(
    54         void *stream,
    55         cx_write_func wfc,
    56         char const *fmt,
    57         va_list ap
    58 ) {
    59     char buf[CX_PRINTF_SBO_SIZE];
    60     va_list ap2;
    61     va_copy(ap2, ap);
    62     int ret = vsnprintf(buf, CX_PRINTF_SBO_SIZE, fmt, ap);
    63     if (ret < 0) {
    64         va_end(ap2);
    65         return ret;
    66     } else if (ret < CX_PRINTF_SBO_SIZE) {
    67         va_end(ap2);
    68         return (int) wfc(buf, 1, ret, stream);
    69     } else {
    70         int len = ret + 1;
    71         char *newbuf = malloc(len);
    72         if (!newbuf) {
    73             va_end(ap2);
    74             return -1;
    75         }
    77         ret = vsnprintf(newbuf, len, fmt, ap2);
    78         va_end(ap2);
    79         if (ret > 0) {
    80             ret = (int) wfc(newbuf, 1, ret, stream);
    81         }
    82         free(newbuf);
    83     }
    84     return ret;
    85 }
    87 cxmutstr cx_asprintf_a(
    88         CxAllocator const *allocator,
    89         char const *fmt,
    90         ...
    91 ) {
    92     va_list ap;
    93     va_start(ap, fmt);
    94     cxmutstr ret = cx_vasprintf_a(allocator, fmt, ap);
    95     va_end(ap);
    96     return ret;
    97 }
    99 cxmutstr cx_vasprintf_a(
   100         CxAllocator const *a,
   101         char const *fmt,
   102         va_list ap
   103 ) {
   104     cxmutstr s;
   105     s.ptr = NULL;
   106     s.length = 0;
   107     char buf[CX_PRINTF_SBO_SIZE];
   108     va_list ap2;
   109     va_copy(ap2, ap);
   110     int ret = vsnprintf(buf, CX_PRINTF_SBO_SIZE, fmt, ap);
   111     if (ret >= 0 && ret < CX_PRINTF_SBO_SIZE) {
   112         s.ptr = cxMalloc(a, ret + 1);
   113         if (s.ptr) {
   114             s.length = (size_t) ret;
   115             memcpy(s.ptr, buf, ret);
   116             s.ptr[s.length] = '\0';
   117         }
   118     } else {
   119         int len = ret + 1;
   120         s.ptr = cxMalloc(a, len);
   121         if (s.ptr) {
   122             ret = vsnprintf(s.ptr, len, fmt, ap2);
   123             if (ret < 0) {
   124                 free(s.ptr);
   125                 s.ptr = NULL;
   126             } else {
   127                 s.length = (size_t) ret;
   128             }
   129         }
   130     }
   131     va_end(ap2);
   132     return s;
   133 }
   135 int cx_sprintf_a(CxAllocator *alloc, char **str, size_t *len, const char *fmt, ... ) {
   136     va_list ap;
   137     va_start(ap, fmt);
   138     int ret = cx_vsprintf_a(alloc, str, len, fmt, ap);
   139     va_end(ap);
   140     return ret;
   141 }
   143 int cx_vsprintf_a(CxAllocator *alloc, char **str, size_t *len, const char *fmt, va_list ap) {
   144     va_list ap2;
   145     va_copy(ap2, ap);
   146     int ret = vsnprintf(*str, *len, fmt, ap);
   147     if ((unsigned) ret >= *len) {
   148         unsigned newlen = ret + 1;
   149         char *ptr = cxRealloc(alloc, *str, newlen);
   150         if (ptr) {
   151             int newret = vsnprintf(ptr, newlen, fmt, ap2);
   152             if (newret < 0) {
   153                 cxFree(alloc, ptr);
   154             } else {
   155                 *len = newlen;
   156                 *str = ptr;
   157                 ret = newret;
   158             }
   159         }
   160     }
   161     va_end(ap2);
   162     return ret;
   163 }
   165 int cx_sprintf_sa(CxAllocator *alloc, char *buf, size_t *len, char **str, const char *fmt, ... ) {
   166     va_list ap;
   167     va_start(ap, fmt);
   168     int ret = cx_vsprintf_sa(alloc, buf, len, str, fmt, ap);
   169     va_end(ap);
   170     return ret;
   171 }
   173 int cx_vsprintf_sa(CxAllocator *alloc, char *buf, size_t *len, char **str, const char *fmt, va_list ap) {
   174     va_list ap2;
   175     va_copy(ap2, ap);
   176     int ret = vsnprintf(buf, *len, fmt, ap);
   177     *str = buf;
   178     if ((unsigned) ret >= *len) {
   179         unsigned newlen = ret + 1;
   180         char *ptr = cxMalloc(alloc, newlen);
   181         if (ptr) {
   182             int newret = vsnprintf(ptr, newlen, fmt, ap2);
   183             if (newret < 0) {
   184                 cxFree(alloc, ptr);
   185             } else {
   186                 *len = newlen;
   187                 *str = ptr;
   188                 ret = newret;
   189             }
   190         }
   191     }
   192     va_end(ap2);
   193     return ret;
   194 }

mercurial