Files
alexvoste 1a9fd27a31 push
2026-05-07 02:22:25 +03:00

430 lines
13 KiB
C

#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;
}