AsciiCam/C/lib/nl_printf.c
2026-06-08 15:51:46 +05:30

165 lines
4 KiB
C

#include "nl_printf.h"
// #include "nolibc.h"
#include <stdarg.h>
#include <stddef.h>
static int _uint_to_dec(char *out, size_t avail, unsigned long long v) {
char tmp[24];
int len = 0;
if (v == 0) {
tmp[len++] = '0';
} else {
while (v) {
tmp[len++] = '0' + (int)(v % 10);
v /= 10;
}
}
int w = 0;
for (int i = len - 1; i >= 0 && (size_t)w < avail; i--)
out[w++] = tmp[i];
return w;
}
static int _uint_to_hex(char *out, size_t avail, unsigned long long v) {
static const char hx[] = "0123456789abcdef";
char tmp[20];
int len = 0;
if (v == 0) {
tmp[len++] = '0';
} else {
while (v) {
tmp[len++] = hx[v & 0xF];
v >>= 4;
}
}
int w = 0;
for (int i = len - 1; i >= 0 && (size_t)w < avail; i--)
out[w++] = tmp[i];
return w;
}
int nl_vsnprintf(char *buf, size_t size, const char *fmt, va_list ap) {
if (!buf || size == 0)
return 0;
size_t pos = 0;
#define PUT(c) \
do { \
if (pos + 1 < size) \
buf[pos++] = (c); \
} while (0)
while (*fmt) {
if (*fmt != '%') {
PUT(*fmt++);
continue;
}
fmt++; // skip '%'
int zero_pad = 0, left_align = 0;
while (*fmt == '0' || *fmt == '-') {
if (*fmt == '0')
zero_pad = 1;
if (*fmt == '-')
left_align = 1;
fmt++;
}
(void)zero_pad;
(void)left_align;
int width = 0;
while (*fmt >= '0' && *fmt <= '9')
width = width * 10 + (*fmt++ - '0');
switch (*fmt++) {
case 'd': {
long long v = (long long)va_arg(ap, int);
char tmp[24];
int n = 0;
if (v < 0) {
PUT('-');
v = -v;
}
n = _uint_to_dec(tmp, sizeof(tmp), (unsigned long long)v);
for (int i = n; i < width && pos + 1 < size; i++)
PUT(' ');
for (int i = 0; i < n && pos + 1 < size; i++)
PUT(tmp[i]);
break;
}
case 'u': {
unsigned long long v = (unsigned long long)va_arg(ap, unsigned int);
char tmp[24];
int n = _uint_to_dec(tmp, sizeof(tmp), v);
for (int i = n; i < width && pos + 1 < size; i++)
PUT(' ');
for (int i = 0; i < n && pos + 1 < size; i++)
PUT(tmp[i]);
break;
}
case 'x': {
unsigned long long v = (unsigned long long)va_arg(ap, unsigned int);
char tmp[20];
int n = _uint_to_hex(tmp, sizeof(tmp), v);
for (int i = 0; i < n && pos + 1 < size; i++)
PUT(tmp[i]);
break;
}
case 's': {
const char *s = va_arg(ap, const char *);
if (!s)
s = "(null)";
int slen = 0;
while (s[slen])
slen++;
for (int i = slen; i < width && pos + 1 < size; i++)
PUT(' ');
for (int i = 0; i < slen && pos + 1 < size; i++)
PUT(s[i]);
break;
}
case 'c':
PUT((char)va_arg(ap, int));
break;
case '%':
PUT('%');
break;
case 'l':
if (*fmt == 'd') {
fmt++;
long long v = va_arg(ap, long long);
char tmp[24];
int n = 0;
if (v < 0) {
PUT('-');
v = -v;
}
n = _uint_to_dec(tmp, sizeof(tmp), (unsigned long long)v);
for (int i = 0; i < n && pos + 1 < size; i++)
PUT(tmp[i]);
} else if (*fmt == 'u') {
fmt++;
unsigned long long v = va_arg(ap, unsigned long long);
char tmp[24];
int n = _uint_to_dec(tmp, sizeof(tmp), v);
for (int i = 0; i < n && pos + 1 < size; i++)
PUT(tmp[i]);
}
break;
default:
PUT('?');
break;
}
}
#undef PUT
buf[pos] = '\0';
return (int)pos;
}
int nl_snprintf(char *buf, size_t size, const char *fmt, ...) {
va_list ap;
va_start(ap, fmt);
int r = nl_vsnprintf(buf, size, fmt, ap);
va_end(ap);
return r;
}