ucx update
[uwplayer.git] / ucx / printf.c
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  */
28
29 #include "cx/printf.h"
30
31 #include <stdio.h>
32 #include <string.h>
33
34 #ifndef CX_PRINTF_SBO_SIZE
35 #define CX_PRINTF_SBO_SIZE 512
36 #endif
37
38 int cx_fprintf(
39         void *stream,
40         cx_write_func wfc,
41         char const *fmt,
42         ...
43 ) {
44     int ret;
45     va_list ap;
46     va_start(ap, fmt);
47     ret = cx_vfprintf(stream, wfc, fmt, ap);
48     va_end(ap);
49     return ret;
50 }
51
52 int cx_vfprintf(
53         void *stream,
54         cx_write_func wfc,
55         char const *fmt,
56         va_list ap
57 ) {
58     char buf[CX_PRINTF_SBO_SIZE];
59     va_list ap2;
60     va_copy(ap2, ap);
61     int ret = vsnprintf(buf, CX_PRINTF_SBO_SIZE, fmt, ap);
62     if (ret < 0) {
63         return ret;
64     } else if (ret < CX_PRINTF_SBO_SIZE) {
65         return (int) wfc(buf, 1, ret, stream);
66     } else {
67         int len = ret + 1;
68         char *newbuf = malloc(len);
69         if (!newbuf) {
70             return -1;
71         }
72
73         ret = vsnprintf(newbuf, len, fmt, ap2);
74         if (ret > 0) {
75             ret = (int) wfc(newbuf, 1, ret, stream);
76         }
77         free(newbuf);
78     }
79     return ret;
80 }
81
82 cxmutstr cx_asprintf_a(
83         CxAllocator *allocator,
84         char const *fmt,
85         ...
86 ) {
87     va_list ap;
88     cxmutstr ret;
89     va_start(ap, fmt);
90     ret = cx_vasprintf_a(allocator, fmt, ap);
91     va_end(ap);
92     return ret;
93 }
94
95 cxmutstr cx_vasprintf_a(
96         CxAllocator *a,
97         char const *fmt,
98         va_list ap
99 ) {
100     cxmutstr s;
101     s.ptr = NULL;
102     s.length = 0;
103     char buf[CX_PRINTF_SBO_SIZE];
104     va_list ap2;
105     va_copy(ap2, ap);
106     int ret = vsnprintf(buf, CX_PRINTF_SBO_SIZE, fmt, ap);
107     if (ret > 0 && ret < CX_PRINTF_SBO_SIZE) {
108         s.ptr = cxMalloc(a, ret + 1);
109         if (s.ptr) {
110             s.length = (size_t) ret;
111             memcpy(s.ptr, buf, ret);
112             s.ptr[s.length] = '\0';
113         }
114     } else {
115         int len = ret + 1;
116         s.ptr = cxMalloc(a, len);
117         if (s.ptr) {
118             ret = vsnprintf(s.ptr, len, fmt, ap2);
119             if (ret < 0) {
120                 free(s.ptr);
121                 s.ptr = NULL;
122             } else {
123                 s.length = (size_t) ret;
124             }
125         }
126     }
127     return s;
128 }
129