#include "cx/printf.h"
#include <stdio.h>
#include <string.h>
#ifndef CX_PRINTF_SBO_SIZE
#define CX_PRINTF_SBO_SIZE 512
#endif
unsigned const cx_printf_sbo_size =
CX_PRINTF_SBO_SIZE;
int cx_fprintf(
void *stream,
cx_write_func wfc,
char const *fmt,
...
) {
int ret;
va_list ap;
va_start(ap, fmt);
ret = cx_vfprintf(stream, wfc, fmt, ap);
va_end(ap);
return ret;
}
int cx_vfprintf(
void *stream,
cx_write_func wfc,
char const *fmt,
va_list ap
) {
char buf[
CX_PRINTF_SBO_SIZE];
va_list ap2;
va_copy(ap2, ap);
int ret = vsnprintf(buf,
CX_PRINTF_SBO_SIZE, fmt, ap);
if (ret <
0) {
va_end(ap2);
return ret;
}
else if (ret <
CX_PRINTF_SBO_SIZE) {
va_end(ap2);
return (
int) wfc(buf,
1, ret, stream);
}
else {
int len = ret +
1;
char *newbuf = malloc(len);
if (!newbuf) {
va_end(ap2);
return -
1;
}
ret = vsnprintf(newbuf, len, fmt, ap2);
va_end(ap2);
if (ret >
0) {
ret = (
int) wfc(newbuf,
1, ret, stream);
}
free(newbuf);
}
return ret;
}
cxmutstr cx_asprintf_a(
CxAllocator
const *allocator,
char const *fmt,
...
) {
va_list ap;
va_start(ap, fmt);
cxmutstr ret = cx_vasprintf_a(allocator, fmt, ap);
va_end(ap);
return ret;
}
cxmutstr cx_vasprintf_a(
CxAllocator
const *a,
char const *fmt,
va_list ap
) {
cxmutstr s;
s.ptr =
NULL;
s.length =
0;
char buf[
CX_PRINTF_SBO_SIZE];
va_list ap2;
va_copy(ap2, ap);
int ret = vsnprintf(buf,
CX_PRINTF_SBO_SIZE, fmt, ap);
if (ret >=
0 && ret <
CX_PRINTF_SBO_SIZE) {
s.ptr = cxMalloc(a, ret +
1);
if (s.ptr) {
s.length = (
size_t) ret;
memcpy(s.ptr, buf, ret);
s.ptr[s.length] =
'\0';
}
}
else {
int len = ret +
1;
s.ptr = cxMalloc(a, len);
if (s.ptr) {
ret = vsnprintf(s.ptr, len, fmt, ap2);
if (ret <
0) {
free(s.ptr);
s.ptr =
NULL;
}
else {
s.length = (
size_t) ret;
}
}
}
va_end(ap2);
return s;
}
int cx_sprintf_a(CxAllocator *alloc,
char **str,
size_t *len,
const char *fmt, ... ) {
va_list ap;
va_start(ap, fmt);
int ret = cx_vsprintf_a(alloc, str, len, fmt, ap);
va_end(ap);
return ret;
}
int cx_vsprintf_a(CxAllocator *alloc,
char **str,
size_t *len,
const char *fmt, va_list ap) {
va_list ap2;
va_copy(ap2, ap);
int ret = vsnprintf(*str, *len, fmt, ap);
if ((
unsigned) ret >= *len) {
unsigned newlen = ret +
1;
char *ptr = cxRealloc(alloc, *str, newlen);
if (ptr) {
int newret = vsnprintf(ptr, newlen, fmt, ap2);
if (newret <
0) {
cxFree(alloc, ptr);
}
else {
*len = newlen;
*str = ptr;
ret = newret;
}
}
}
va_end(ap2);
return ret;
}
int cx_sprintf_sa(CxAllocator *alloc,
char *buf,
size_t *len,
char **str,
const char *fmt, ... ) {
va_list ap;
va_start(ap, fmt);
int ret = cx_vsprintf_sa(alloc, buf, len, str, fmt, ap);
va_end(ap);
return ret;
}
int cx_vsprintf_sa(CxAllocator *alloc,
char *buf,
size_t *len,
char **str,
const char *fmt, va_list ap) {
va_list ap2;
va_copy(ap2, ap);
int ret = vsnprintf(buf, *len, fmt, ap);
*str = buf;
if ((
unsigned) ret >= *len) {
unsigned newlen = ret +
1;
char *ptr = cxMalloc(alloc, newlen);
if (ptr) {
int newret = vsnprintf(ptr, newlen, fmt, ap2);
if (newret <
0) {
cxFree(alloc, ptr);
}
else {
*len = newlen;
*str = ptr;
ret = newret;
}
}
}
va_end(ap2);
return ret;
}