push
This commit is contained in:
@@ -0,0 +1,252 @@
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
extern uint64_t __cervus_strtod_bits(const char *s, char **endptr);
|
||||
|
||||
static int __is_space(int c)
|
||||
{
|
||||
return c == ' ' || c == '\t' || c == '\n' || c == '\r' || c == '\f' || c == '\v';
|
||||
}
|
||||
|
||||
int vsscanf(const char *str, const char *fmt, va_list ap)
|
||||
{
|
||||
if (!str || !fmt) return -1;
|
||||
const char *s = str;
|
||||
const char *f = fmt;
|
||||
int matched = 0;
|
||||
int saw_anything = 0;
|
||||
|
||||
while (*f) {
|
||||
if (__is_space((unsigned char)*f)) {
|
||||
while (__is_space((unsigned char)*s)) s++;
|
||||
f++;
|
||||
continue;
|
||||
}
|
||||
if (*f != '%') {
|
||||
if (*s != *f) return saw_anything ? matched : (matched ? matched : -1);
|
||||
s++; f++;
|
||||
continue;
|
||||
}
|
||||
f++;
|
||||
|
||||
int suppress = 0;
|
||||
if (*f == '*') { suppress = 1; f++; }
|
||||
|
||||
int width = 0;
|
||||
int has_width = 0;
|
||||
while (*f >= '0' && *f <= '9') {
|
||||
width = width * 10 + (*f - '0');
|
||||
has_width = 1;
|
||||
f++;
|
||||
}
|
||||
if (!has_width) width = 0;
|
||||
|
||||
int len_mod = 0;
|
||||
if (*f == 'h') { f++; if (*f == 'h') { f++; len_mod = 2; } else len_mod = 1; }
|
||||
else if (*f == 'l') { f++; if (*f == 'l') { f++; len_mod = 4; } else len_mod = 3; }
|
||||
else if (*f == 'z') { f++; len_mod = 5; }
|
||||
else if (*f == 'j' || *f == 't') { f++; len_mod = 4; }
|
||||
|
||||
char conv = *f;
|
||||
if (!conv) break;
|
||||
f++;
|
||||
|
||||
if (conv == '%') {
|
||||
if (*s != '%') return matched ? matched : -1;
|
||||
s++;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (conv == 'n') {
|
||||
if (!suppress) {
|
||||
int read = (int)(s - str);
|
||||
if (len_mod == 3 || len_mod == 5) *va_arg(ap, long *) = read;
|
||||
else if (len_mod == 4) *va_arg(ap, long long *) = read;
|
||||
else *va_arg(ap, int *) = read;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (conv == 'c') {
|
||||
int w = has_width ? width : 1;
|
||||
char *out = suppress ? NULL : va_arg(ap, char *);
|
||||
for (int i = 0; i < w; i++) {
|
||||
if (!*s) return matched ? matched : -1;
|
||||
if (out) out[i] = *s;
|
||||
s++;
|
||||
}
|
||||
if (!suppress) matched++;
|
||||
saw_anything = 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (conv != '[') {
|
||||
while (__is_space((unsigned char)*s)) s++;
|
||||
}
|
||||
|
||||
if (conv == 's') {
|
||||
int w = has_width ? width : 0x7FFFFFFF;
|
||||
char *out = suppress ? NULL : va_arg(ap, char *);
|
||||
int wrote = 0;
|
||||
if (!*s) return matched ? matched : -1;
|
||||
while (*s && !__is_space((unsigned char)*s) && wrote < w) {
|
||||
if (out) out[wrote] = *s;
|
||||
s++; wrote++;
|
||||
}
|
||||
if (out) out[wrote] = '\0';
|
||||
if (!suppress) matched++;
|
||||
saw_anything = 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (conv == '[') {
|
||||
int negate = 0;
|
||||
if (*f == '^') { negate = 1; f++; }
|
||||
char set[256];
|
||||
memset(set, 0, sizeof(set));
|
||||
if (*f == ']') { set[(unsigned char)']'] = 1; f++; }
|
||||
while (*f && *f != ']') { set[(unsigned char)*f] = 1; f++; }
|
||||
if (*f == ']') f++;
|
||||
int w = has_width ? width : 0x7FFFFFFF;
|
||||
char *out = suppress ? NULL : va_arg(ap, char *);
|
||||
int wrote = 0;
|
||||
while (*s && wrote < w) {
|
||||
int in = set[(unsigned char)*s] != 0;
|
||||
if (negate) in = !in;
|
||||
if (!in) break;
|
||||
if (out) out[wrote] = *s;
|
||||
s++; wrote++;
|
||||
}
|
||||
if (out) out[wrote] = '\0';
|
||||
if (wrote == 0) return matched ? matched : -1;
|
||||
if (!suppress) matched++;
|
||||
saw_anything = 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (conv == 'd' || conv == 'i' || conv == 'u' ||
|
||||
conv == 'o' || conv == 'x' || conv == 'X')
|
||||
{
|
||||
int base = 10;
|
||||
int allow_neg = (conv == 'd' || conv == 'i');
|
||||
if (conv == 'o') base = 8;
|
||||
else if (conv == 'x' || conv == 'X') base = 16;
|
||||
|
||||
const char *start = s;
|
||||
int neg = 0;
|
||||
if (allow_neg && (*s == '+' || *s == '-')) { neg = (*s == '-'); s++; }
|
||||
else if (conv == 'u' && (*s == '+')) s++;
|
||||
if (conv == 'i' || conv == 'x' || conv == 'X') {
|
||||
if (s[0] == '0' && (s[1] == 'x' || s[1] == 'X')) {
|
||||
base = 16; s += 2;
|
||||
} else if (conv == 'i' && s[0] == '0' && s[1] >= '0' && s[1] <= '7') {
|
||||
base = 8; s++;
|
||||
}
|
||||
}
|
||||
unsigned long long val = 0;
|
||||
int got_digit = 0;
|
||||
int wleft = has_width ? width - (int)(s - start) : 0x7FFFFFFF;
|
||||
while (*s && wleft > 0) {
|
||||
int d = -1;
|
||||
if (*s >= '0' && *s <= '9') d = *s - '0';
|
||||
else if (*s >= 'a' && *s <= 'f') d = *s - 'a' + 10;
|
||||
else if (*s >= 'A' && *s <= 'F') d = *s - 'A' + 10;
|
||||
if (d < 0 || d >= base) break;
|
||||
val = val * base + (unsigned)d;
|
||||
s++; wleft--;
|
||||
got_digit = 1;
|
||||
}
|
||||
if (!got_digit) return matched ? matched : -1;
|
||||
if (!suppress) {
|
||||
if (allow_neg && neg) {
|
||||
long long sv = -(long long)val;
|
||||
if (len_mod == 4) *va_arg(ap, long long *) = sv;
|
||||
else if (len_mod == 3 || len_mod == 5) *va_arg(ap, long *) = (long)sv;
|
||||
else if (len_mod == 1) *va_arg(ap, short *) = (short)sv;
|
||||
else if (len_mod == 2) *va_arg(ap, signed char *) = (signed char)sv;
|
||||
else *va_arg(ap, int *) = (int)sv;
|
||||
} else {
|
||||
if (len_mod == 4) *va_arg(ap, unsigned long long *) = val;
|
||||
else if (len_mod == 3 || len_mod == 5) *va_arg(ap, unsigned long *) = (unsigned long)val;
|
||||
else if (len_mod == 1) *va_arg(ap, unsigned short *) = (unsigned short)val;
|
||||
else if (len_mod == 2) *va_arg(ap, unsigned char *) = (unsigned char)val;
|
||||
else *va_arg(ap, unsigned int *) = (unsigned int)val;
|
||||
}
|
||||
matched++;
|
||||
}
|
||||
saw_anything = 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (conv == 'f' || conv == 'e' || conv == 'g' ||
|
||||
conv == 'E' || conv == 'G' || conv == 'a' || conv == 'A')
|
||||
{
|
||||
char *endp;
|
||||
uint64_t bits = __cervus_strtod_bits(s, &endp);
|
||||
if (endp == s) return matched ? matched : -1;
|
||||
if (!suppress) {
|
||||
if (len_mod == 3) {
|
||||
double v;
|
||||
__builtin_memcpy(&v, &bits, sizeof(double));
|
||||
*va_arg(ap, double *) = v;
|
||||
} else {
|
||||
double dv;
|
||||
__builtin_memcpy(&dv, &bits, sizeof(double));
|
||||
*va_arg(ap, float *) = (float)dv;
|
||||
}
|
||||
matched++;
|
||||
}
|
||||
s = endp;
|
||||
saw_anything = 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
return matched ? matched : -1;
|
||||
}
|
||||
return matched;
|
||||
}
|
||||
|
||||
int sscanf(const char *str, const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
int n = vsscanf(str, fmt, ap);
|
||||
va_end(ap);
|
||||
return n;
|
||||
}
|
||||
|
||||
int vscanf(const char *fmt, va_list ap)
|
||||
{
|
||||
char buf[1024];
|
||||
if (!fgets(buf, (int)sizeof(buf), stdin)) return EOF;
|
||||
return vsscanf(buf, fmt, ap);
|
||||
}
|
||||
|
||||
int scanf(const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
int n = vscanf(fmt, ap);
|
||||
va_end(ap);
|
||||
return n;
|
||||
}
|
||||
|
||||
int vfscanf(FILE *stream, const char *fmt, va_list ap)
|
||||
{
|
||||
char buf[1024];
|
||||
if (!fgets(buf, (int)sizeof(buf), stream)) return EOF;
|
||||
return vsscanf(buf, fmt, ap);
|
||||
}
|
||||
|
||||
int fscanf(FILE *stream, const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
int n = vfscanf(stream, fmt, ap);
|
||||
va_end(ap);
|
||||
return n;
|
||||
}
|
||||
@@ -0,0 +1,430 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/cervus.h>
|
||||
|
||||
extern int __cervus_errno;
|
||||
|
||||
struct __cervus_FILE {
|
||||
int fd;
|
||||
int eof;
|
||||
int err;
|
||||
int flags;
|
||||
char *buf;
|
||||
size_t buf_size;
|
||||
size_t buf_pos;
|
||||
};
|
||||
|
||||
static struct __cervus_FILE __stdin_s = { 0, 0, 0, 0, NULL, 0, 0 };
|
||||
static struct __cervus_FILE __stdout_s = { 1, 0, 0, 0, NULL, 0, 0 };
|
||||
static struct __cervus_FILE __stderr_s = { 2, 0, 0, 0, NULL, 0, 0 };
|
||||
|
||||
FILE *stdin = &__stdin_s;
|
||||
FILE *stdout = &__stdout_s;
|
||||
FILE *stderr = &__stderr_s;
|
||||
|
||||
int fileno(FILE *s) { return s ? s->fd : -1; }
|
||||
int feof(FILE *s) { return s ? s->eof : 1; }
|
||||
int ferror(FILE *s) { return s ? s->err : 1; }
|
||||
void clearerr(FILE *s) { if (s) { s->eof = 0; s->err = 0; } }
|
||||
|
||||
FILE *fopen(const char *path, const char *mode)
|
||||
{
|
||||
if (!path || !mode) return NULL;
|
||||
int flags = 0;
|
||||
int has_plus = 0;
|
||||
for (const char *m = mode + 1; *m; m++) if (*m == '+') has_plus = 1;
|
||||
switch (mode[0]) {
|
||||
case 'r': flags = has_plus ? O_RDWR : O_RDONLY; break;
|
||||
case 'w': flags = (has_plus ? O_RDWR : O_WRONLY) | O_CREAT | O_TRUNC; break;
|
||||
case 'a': flags = (has_plus ? O_RDWR : O_WRONLY) | O_CREAT | O_APPEND; break;
|
||||
default: return NULL;
|
||||
}
|
||||
int fd = open(path, flags, 0644);
|
||||
if (fd < 0) return NULL;
|
||||
FILE *f = (FILE *)malloc(sizeof(FILE));
|
||||
if (!f) { close(fd); return NULL; }
|
||||
f->fd = fd;
|
||||
f->eof = 0;
|
||||
f->err = 0;
|
||||
f->flags = 1;
|
||||
f->buf = NULL;
|
||||
f->buf_size = 0;
|
||||
f->buf_pos = 0;
|
||||
return f;
|
||||
}
|
||||
|
||||
int fclose(FILE *s)
|
||||
{
|
||||
if (!s) return EOF;
|
||||
int fd = s->fd;
|
||||
int owned = s->flags & 1;
|
||||
close(fd);
|
||||
if (owned) free(s);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int fflush(FILE *s) { (void)s; return 0; }
|
||||
|
||||
size_t fread(void *buf, size_t size, size_t nmemb, FILE *s)
|
||||
{
|
||||
if (!s || size == 0 || nmemb == 0) return 0;
|
||||
size_t total = size * nmemb;
|
||||
size_t got = 0;
|
||||
while (got < total) {
|
||||
ssize_t r = read(s->fd, (char *)buf + got, total - got);
|
||||
if (r < 0) { s->err = 1; break; }
|
||||
if (r == 0) { s->eof = 1; break; }
|
||||
got += (size_t)r;
|
||||
}
|
||||
return got / size;
|
||||
}
|
||||
|
||||
size_t fwrite(const void *buf, size_t size, size_t nmemb, FILE *s)
|
||||
{
|
||||
if (!s || size == 0 || nmemb == 0) return 0;
|
||||
size_t total = size * nmemb;
|
||||
size_t sent = 0;
|
||||
while (sent < total) {
|
||||
ssize_t w = write(s->fd, (const char *)buf + sent, total - sent);
|
||||
if (w < 0) { s->err = 1; break; }
|
||||
if (w == 0) break;
|
||||
sent += (size_t)w;
|
||||
}
|
||||
return sent / size;
|
||||
}
|
||||
|
||||
int fseek(FILE *s, long off, int whence)
|
||||
{
|
||||
if (!s) return -1;
|
||||
off_t r = lseek(s->fd, (off_t)off, whence);
|
||||
if (r == (off_t)-1) { s->err = 1; return -1; }
|
||||
s->eof = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
long ftell(FILE *s)
|
||||
{
|
||||
if (!s) return -1;
|
||||
return (long)lseek(s->fd, 0, SEEK_CUR);
|
||||
}
|
||||
|
||||
int fputc(int c, FILE *s)
|
||||
{
|
||||
unsigned char ch = (unsigned char)c;
|
||||
if (fwrite(&ch, 1, 1, s) != 1) return EOF;
|
||||
return (int)ch;
|
||||
}
|
||||
|
||||
int fgetc(FILE *s)
|
||||
{
|
||||
unsigned char ch;
|
||||
if (fread(&ch, 1, 1, s) != 1) return EOF;
|
||||
return (int)ch;
|
||||
}
|
||||
|
||||
int fputs(const char *str, FILE *s)
|
||||
{
|
||||
if (!str) return EOF;
|
||||
size_t n = strlen(str);
|
||||
if (fwrite(str, 1, n, s) != n) return EOF;
|
||||
return 0;
|
||||
}
|
||||
|
||||
char *fgets(char *str, int n, FILE *s)
|
||||
{
|
||||
if (!str || n <= 0 || !s) return NULL;
|
||||
int i = 0;
|
||||
while (i < n - 1) {
|
||||
int c = fgetc(s);
|
||||
if (c == EOF) {
|
||||
if (i == 0) return NULL;
|
||||
break;
|
||||
}
|
||||
str[i++] = (char)c;
|
||||
if (c == '\n') break;
|
||||
}
|
||||
str[i] = '\0';
|
||||
return str;
|
||||
}
|
||||
|
||||
int putchar(int c) { return fputc(c, stdout); }
|
||||
int getchar(void) { return fgetc(stdin); }
|
||||
|
||||
int puts(const char *s)
|
||||
{
|
||||
if (fputs(s, stdout) == EOF) return EOF;
|
||||
if (fputc('\n', stdout) == EOF) return EOF;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void __u64_to_str(uint64_t v, char *out, int base, int upper)
|
||||
{
|
||||
char tmp[32];
|
||||
int i = 0;
|
||||
const char *digs = upper ? "0123456789ABCDEF" : "0123456789abcdef";
|
||||
if (v == 0) { out[0] = '0'; out[1] = 0; return; }
|
||||
while (v) { tmp[i++] = digs[v % (uint64_t)base]; v /= (uint64_t)base; }
|
||||
int j = 0;
|
||||
while (i > 0) out[j++] = tmp[--i];
|
||||
out[j] = 0;
|
||||
}
|
||||
|
||||
int vsnprintf(char *buf, size_t sz, const char *fmt, va_list ap)
|
||||
{
|
||||
size_t pos = 0;
|
||||
#define __PUT(s, n) do { \
|
||||
size_t __n = (n); const char *__s = (s); \
|
||||
for (size_t __i = 0; __i < __n; __i++) { \
|
||||
if (pos + 1 < sz) buf[pos] = __s[__i]; \
|
||||
pos++; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
while (*fmt) {
|
||||
if (*fmt != '%') { __PUT(fmt, 1); fmt++; continue; }
|
||||
fmt++;
|
||||
int pad_zero = 0, left_align = 0, plus_flag = 0;
|
||||
while (*fmt == '0' || *fmt == '-' || *fmt == '+' || *fmt == ' ' || *fmt == '#') {
|
||||
if (*fmt == '0') pad_zero = 1;
|
||||
else if (*fmt == '-') left_align = 1;
|
||||
else if (*fmt == '+') plus_flag = 1;
|
||||
fmt++;
|
||||
}
|
||||
int width = 0;
|
||||
if (*fmt == '*') { width = va_arg(ap, int); if (width < 0) { left_align = 1; width = -width; } fmt++; }
|
||||
else while (*fmt >= '0' && *fmt <= '9') { width = width * 10 + (*fmt - '0'); fmt++; }
|
||||
int prec = -1;
|
||||
if (*fmt == '.') {
|
||||
fmt++;
|
||||
prec = 0;
|
||||
if (*fmt == '*') { prec = va_arg(ap, int); if (prec < 0) prec = 0; fmt++; }
|
||||
else while (*fmt >= '0' && *fmt <= '9') { prec = prec * 10 + (*fmt - '0'); fmt++; }
|
||||
}
|
||||
int is_long = 0, is_size_t = 0;
|
||||
while (*fmt == 'l') { is_long++; fmt++; }
|
||||
if (*fmt == 'z') { is_size_t = 1; fmt++; }
|
||||
if (*fmt == 'h') { fmt++; }
|
||||
|
||||
char nb[40];
|
||||
switch (*fmt) {
|
||||
case 's': {
|
||||
const char *s = va_arg(ap, const char *);
|
||||
if (!s) s = "(null)";
|
||||
size_t l = strlen(s);
|
||||
if (prec >= 0 && (size_t)prec < l) l = (size_t)prec;
|
||||
int pad = (int)(width > (int)l ? width - (int)l : 0);
|
||||
if (!left_align) for (int i = 0; i < pad; i++) __PUT(" ", 1);
|
||||
__PUT(s, l);
|
||||
if (left_align) for (int i = 0; i < pad; i++) __PUT(" ", 1);
|
||||
break;
|
||||
}
|
||||
case 'd': case 'i': {
|
||||
int64_t v;
|
||||
if (is_long >= 2) v = va_arg(ap, long long);
|
||||
else if (is_long) v = va_arg(ap, long);
|
||||
else if (is_size_t) v = (int64_t)va_arg(ap, size_t);
|
||||
else v = va_arg(ap, int);
|
||||
int neg = v < 0;
|
||||
uint64_t u = neg ? (uint64_t)(-v) : (uint64_t)v;
|
||||
__u64_to_str(u, nb, 10, 0);
|
||||
int numlen = (int)strlen(nb) + (neg || plus_flag ? 1 : 0);
|
||||
int pad = width > numlen ? width - numlen : 0;
|
||||
if (!left_align && !pad_zero) for (int i = 0; i < pad; i++) __PUT(" ", 1);
|
||||
if (neg) __PUT("-", 1);
|
||||
else if (plus_flag) __PUT("+", 1);
|
||||
if (!left_align && pad_zero) for (int i = 0; i < pad; i++) __PUT("0", 1);
|
||||
__PUT(nb, strlen(nb));
|
||||
if (left_align) for (int i = 0; i < pad; i++) __PUT(" ", 1);
|
||||
break;
|
||||
}
|
||||
case 'u': {
|
||||
uint64_t v;
|
||||
if (is_long >= 2) v = va_arg(ap, unsigned long long);
|
||||
else if (is_long) v = va_arg(ap, unsigned long);
|
||||
else if (is_size_t) v = va_arg(ap, size_t);
|
||||
else v = va_arg(ap, unsigned);
|
||||
__u64_to_str(v, nb, 10, 0);
|
||||
int numlen = (int)strlen(nb);
|
||||
int pad = width > numlen ? width - numlen : 0;
|
||||
if (!left_align) for (int i = 0; i < pad; i++) __PUT(pad_zero ? "0" : " ", 1);
|
||||
__PUT(nb, strlen(nb));
|
||||
if (left_align) for (int i = 0; i < pad; i++) __PUT(" ", 1);
|
||||
break;
|
||||
}
|
||||
case 'x': case 'X': {
|
||||
uint64_t v;
|
||||
if (is_long >= 2) v = va_arg(ap, unsigned long long);
|
||||
else if (is_long) v = va_arg(ap, unsigned long);
|
||||
else if (is_size_t) v = va_arg(ap, size_t);
|
||||
else v = va_arg(ap, unsigned);
|
||||
__u64_to_str(v, nb, 16, *fmt == 'X');
|
||||
int numlen = (int)strlen(nb);
|
||||
int pad = width > numlen ? width - numlen : 0;
|
||||
if (!left_align) for (int i = 0; i < pad; i++) __PUT(pad_zero ? "0" : " ", 1);
|
||||
__PUT(nb, strlen(nb));
|
||||
if (left_align) for (int i = 0; i < pad; i++) __PUT(" ", 1);
|
||||
break;
|
||||
}
|
||||
case 'o': {
|
||||
uint64_t v;
|
||||
if (is_long >= 2) v = va_arg(ap, unsigned long long);
|
||||
else if (is_long) v = va_arg(ap, unsigned long);
|
||||
else v = va_arg(ap, unsigned);
|
||||
__u64_to_str(v, nb, 8, 0);
|
||||
__PUT(nb, strlen(nb));
|
||||
break;
|
||||
}
|
||||
case 'p': {
|
||||
uint64_t v = (uint64_t)(uintptr_t)va_arg(ap, void *);
|
||||
__PUT("0x", 2);
|
||||
__u64_to_str(v, nb, 16, 0);
|
||||
__PUT(nb, strlen(nb));
|
||||
break;
|
||||
}
|
||||
case 'c': {
|
||||
char c = (char)va_arg(ap, int);
|
||||
__PUT(&c, 1);
|
||||
break;
|
||||
}
|
||||
case '%': __PUT("%", 1); break;
|
||||
default: {
|
||||
char c = *fmt;
|
||||
__PUT("%", 1);
|
||||
__PUT(&c, 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
fmt++;
|
||||
}
|
||||
if (sz > 0) buf[pos < sz ? pos : sz - 1] = '\0';
|
||||
#undef __PUT
|
||||
return (int)pos;
|
||||
}
|
||||
|
||||
int snprintf(char *buf, size_t sz, const char *fmt, ...)
|
||||
{
|
||||
va_list ap; va_start(ap, fmt);
|
||||
int n = vsnprintf(buf, sz, fmt, ap);
|
||||
va_end(ap);
|
||||
return n;
|
||||
}
|
||||
|
||||
int sprintf(char *buf, const char *fmt, ...)
|
||||
{
|
||||
va_list ap; va_start(ap, fmt);
|
||||
int n = vsnprintf(buf, (size_t)-1, fmt, ap);
|
||||
va_end(ap);
|
||||
return n;
|
||||
}
|
||||
|
||||
int vsprintf(char *buf, const char *fmt, va_list ap)
|
||||
{
|
||||
return vsnprintf(buf, (size_t)-1, fmt, ap);
|
||||
}
|
||||
|
||||
int vfprintf(FILE *s, const char *fmt, va_list ap)
|
||||
{
|
||||
char small[512];
|
||||
va_list ap2;
|
||||
va_copy(ap2, ap);
|
||||
int needed = vsnprintf(small, sizeof(small), fmt, ap2);
|
||||
va_end(ap2);
|
||||
if (needed < (int)sizeof(small)) {
|
||||
fwrite(small, 1, (size_t)needed, s);
|
||||
return needed;
|
||||
}
|
||||
char *big = (char *)malloc((size_t)needed + 1);
|
||||
if (!big) {
|
||||
fwrite(small, 1, sizeof(small) - 1, s);
|
||||
return (int)sizeof(small) - 1;
|
||||
}
|
||||
vsnprintf(big, (size_t)needed + 1, fmt, ap);
|
||||
fwrite(big, 1, (size_t)needed, s);
|
||||
free(big);
|
||||
return needed;
|
||||
}
|
||||
|
||||
int fprintf(FILE *s, const char *fmt, ...)
|
||||
{
|
||||
va_list ap; va_start(ap, fmt);
|
||||
int n = vfprintf(s, fmt, ap);
|
||||
va_end(ap);
|
||||
return n;
|
||||
}
|
||||
|
||||
int vprintf(const char *fmt, va_list ap) { return vfprintf(stdout, fmt, ap); }
|
||||
|
||||
int printf(const char *fmt, ...)
|
||||
{
|
||||
va_list ap; va_start(ap, fmt);
|
||||
int n = vfprintf(stdout, fmt, ap);
|
||||
va_end(ap);
|
||||
return n;
|
||||
}
|
||||
|
||||
void perror(const char *msg)
|
||||
{
|
||||
if (msg && *msg) { fputs(msg, stderr); fputs(": ", stderr); }
|
||||
fputs(strerror(__cervus_errno), stderr);
|
||||
fputc('\n', stderr);
|
||||
}
|
||||
|
||||
int remove(const char *path) { return unlink(path); }
|
||||
|
||||
int mkstemp(char *template)
|
||||
{
|
||||
if (!template) { __cervus_errno = EINVAL; return -1; }
|
||||
size_t len = strlen(template);
|
||||
if (len < 6) { __cervus_errno = EINVAL; return -1; }
|
||||
char *suf = template + len - 6;
|
||||
for (int i = 0; i < 6; i++) {
|
||||
if (suf[i] != 'X') { __cervus_errno = EINVAL; return -1; }
|
||||
}
|
||||
static uint64_t __mkstemp_seq = 0;
|
||||
uint64_t pid = (uint64_t)getpid();
|
||||
for (int attempt = 0; attempt < 100; attempt++) {
|
||||
uint64_t seed = (cervus_uptime_ns() ^ (pid << 32)) + (__mkstemp_seq++);
|
||||
const char *alpha = "0123456789abcdefghijklmnopqrstuvwxyz";
|
||||
for (int i = 0; i < 6; i++) {
|
||||
suf[i] = alpha[seed % 36];
|
||||
seed /= 36;
|
||||
}
|
||||
struct stat st;
|
||||
if (stat(template, &st) == 0) continue;
|
||||
int fd = open(template, O_RDWR | O_CREAT, 0600);
|
||||
if (fd >= 0) return fd;
|
||||
}
|
||||
__cervus_errno = EEXIST;
|
||||
return -1;
|
||||
}
|
||||
|
||||
FILE *tmpfile(void)
|
||||
{
|
||||
char tmpl[64];
|
||||
strcpy(tmpl, "/mnt/tmp/tmpXXXXXX");
|
||||
int fd = mkstemp(tmpl);
|
||||
if (fd < 0) {
|
||||
strcpy(tmpl, "/tmp/tmpXXXXXX");
|
||||
fd = mkstemp(tmpl);
|
||||
if (fd < 0) return NULL;
|
||||
}
|
||||
unlink(tmpl);
|
||||
FILE *f = (FILE *)malloc(sizeof(FILE));
|
||||
if (!f) { close(fd); return NULL; }
|
||||
f->fd = fd;
|
||||
f->eof = 0;
|
||||
f->err = 0;
|
||||
f->flags = 1;
|
||||
f->buf = NULL;
|
||||
f->buf_size = 0;
|
||||
f->buf_pos = 0;
|
||||
return f;
|
||||
}
|
||||
Reference in New Issue
Block a user