/*
* This file is part of libplacebo.
*
* libplacebo is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* libplacebo is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with libplacebo. If not, see .
*/
#include
#include "common.h"
void pl_str_append_asprintf_c(void *alloc, pl_str *str, const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
pl_str_append_vasprintf_c(alloc, str, fmt, ap);
va_end(ap);
}
void pl_str_append_vasprintf_c(void *alloc, pl_str *str, const char *fmt,
va_list ap)
{
for (const char *c; (c = strchr(fmt, '%')) != NULL; fmt = c + 1) {
// Append the preceding string literal
pl_str_append_raw(alloc, str, fmt, c - fmt);
c++; // skip '%'
char buf[32];
int len;
// The format character follows the % sign
switch (c[0]) {
case '%':
pl_str_append_raw(alloc, str, c, 1);
continue;
case 's': {
const char *arg = va_arg(ap, const char *);
pl_str_append_raw(alloc, str, arg, strlen(arg));
continue;
}
case '.': { // only used for %.*s
assert(c[1] == '*');
assert(c[2] == 's');
len = va_arg(ap, int);
pl_str_append_raw(alloc, str, va_arg(ap, char *), len);
c += 2; // skip '*s'
continue;
}
case 'c':
buf[0] = (char) va_arg(ap, int);
len = 1;
break;
case 'd':
len = pl_str_print_int(buf, sizeof(buf), va_arg(ap, int));
break;
case 'h': ; // only used for %hx
assert(c[1] == 'x');
len = pl_str_print_hex(buf, sizeof(buf), (unsigned short) va_arg(ap, unsigned int));
c++;
break;
case 'u':
len = pl_str_print_uint(buf, sizeof(buf), va_arg(ap, unsigned int));
break;
case 'l':
assert(c[1] == 'l');
switch (c[2]) {
case 'u':
len = pl_str_print_uint64(buf, sizeof(buf), va_arg(ap, unsigned long long));
break;
case 'd':
len = pl_str_print_int64(buf, sizeof(buf), va_arg(ap, long long));
break;
default: pl_unreachable();
}
c += 2;
break;
case 'z':
assert(c[1] == 'u');
len = pl_str_print_uint64(buf, sizeof(buf), va_arg(ap, size_t));
c++;
break;
case 'f':
len = pl_str_print_double(buf, sizeof(buf), va_arg(ap, double));
break;
default:
fprintf(stderr, "Invalid conversion character: '%c'!\n", c[0]);
abort();
}
pl_str_append_raw(alloc, str, buf, len);
}
// Append the remaining string literal
pl_str_append(alloc, str, pl_str0(fmt));
}
size_t pl_str_append_memprintf_c(void *alloc, pl_str *str, const char *fmt,
const void *args)
{
const uint8_t *ptr = args;
for (const char *c; (c = strchr(fmt, '%')) != NULL; fmt = c + 1) {
pl_str_append_raw(alloc, str, fmt, c - fmt);
c++;
char buf[32];
int len;
#define LOAD(var) \
do { \
memcpy(&(var), ptr, sizeof(var)); \
ptr += sizeof(var); \
} while (0)
switch (c[0]) {
case '%':
pl_str_append_raw(alloc, str, c, 1);
continue;
case 's': {
len = strlen((const char *) ptr);
pl_str_append_raw(alloc, str, ptr, len);
ptr += len + 1; // also skip \0
continue;
}
case '.': {
assert(c[1] == '*');
assert(c[2] == 's');
LOAD(len);
pl_str_append_raw(alloc, str, ptr, len);
ptr += len; // no trailing \0
c += 2;
continue;
}
case 'c':
LOAD(buf[0]);
len = 1;
break;
case 'd': ;
int d;
LOAD(d);
len = pl_str_print_int(buf, sizeof(buf), d);
break;
case 'h': ;
assert(c[1] == 'x');
unsigned short hx;
LOAD(hx);
len = pl_str_print_hex(buf, sizeof(buf), hx);
c++;
break;
case 'u': ;
unsigned u;
LOAD(u);
len = pl_str_print_uint(buf, sizeof(buf), u);
break;
case 'l':
assert(c[1] == 'l');
switch (c[2]) {
case 'u': ;
long long unsigned llu;
LOAD(llu);
len = pl_str_print_uint64(buf, sizeof(buf), llu);
break;
case 'd': ;
long long int lld;
LOAD(lld);
len = pl_str_print_int64(buf, sizeof(buf), lld);
break;
default: pl_unreachable();
}
c += 2;
break;
case 'z': ;
assert(c[1] == 'u');
size_t zu;
LOAD(zu);
len = pl_str_print_uint64(buf, sizeof(buf), zu);
c++;
break;
case 'f': ;
double f;
LOAD(f);
len = pl_str_print_double(buf, sizeof(buf), f);
break;
default:
fprintf(stderr, "Invalid conversion character: '%c'!\n", c[0]);
abort();
}
pl_str_append_raw(alloc, str, buf, len);
}
#undef LOAD
pl_str_append(alloc, str, pl_str0(fmt));
return (uintptr_t) ptr - (uintptr_t) args;
}