#include "stdio.h"
#include "unistd.h"
#include "string.h"
#include "stdlib.h"
#include <stdarg.h>
static FILE _stdin_file = { .fd = 0, .flags = _STDIO_READ };
static FILE _stdout_file = { .fd = 1, .flags = _STDIO_WRITE | _STDIO_LBUF };
static FILE _stderr_file = { .fd = 2, .flags = _STDIO_WRITE | _STDIO_UNBUF };
FILE* stdin = &_stdin_file;
FILE* stdout = &_stdout_file;
FILE* stderr = &_stderr_file;
static FILE _file_pool[FOPEN_MAX];
static int _file_pool_used[FOPEN_MAX];
FILE* fopen(const char* path, const char* mode) {
int flags = 0;
int stdio_flags = 0;
if (mode[0] == 'r') {
flags = 0; /* O_RDONLY */
stdio_flags = _STDIO_READ;
} else if (mode[0] == 'w') {
flags = 1 | 0x40 | 0x200; /* O_WRONLY | O_CREAT | O_TRUNC */
stdio_flags = _STDIO_WRITE;
} else if (mode[0] == 'a') {
flags = 1 | 0x40 | 0x400; /* O_WRONLY | O_CREAT | O_APPEND */
stdio_flags = _STDIO_WRITE;
} else {
return (FILE*)0;
}
int fd = open(path, flags);
if (fd < 0) return (FILE*)0;
for (int i = 0; i < FOPEN_MAX; i++) {
if (!_file_pool_used[i]) {
_file_pool_used[i] = 1;
_file_pool[i].fd = fd;
_file_pool[i].flags = stdio_flags;
_file_pool[i].buf_pos = 0;
_file_pool[i].buf_len = 0;
return &_file_pool[i];
}
}
close(fd);
return (FILE*)0;
}
int fflush(FILE* fp) {
if (!fp) return EOF;
if ((fp->flags & _STDIO_WRITE) && fp->buf_pos > 0) {
write(fp->fd, fp->buf, (size_t)fp->buf_pos);
fp->buf_pos = 0;
}
return 0;
}
int fclose(FILE* fp) {
if (!fp) return EOF;
fflush(fp);
int rc = close(fp->fd);
for (int i = 0; i < FOPEN_MAX; i++) {
if (&_file_pool[i] == fp) { _file_pool_used[i] = 0; break; }
}
return rc;
}
size_t fread(void* ptr, size_t size, size_t nmemb, FILE* fp) {
if (!fp || !ptr || size == 0 || nmemb == 0) return 0;
size_t total = size * nmemb;
size_t done = 0;
char* dst = (char*)ptr;
while (done < total) {
if (fp->buf_pos >= fp->buf_len) {
int r = read(fp->fd, fp->buf, BUFSIZ);
if (r <= 0) { fp->flags |= _STDIO_EOF; break; }
fp->buf_pos = 0;
fp->buf_len = r;
}
int avail = fp->buf_len - fp->buf_pos;
int want = (int)(total - done);
int chunk = avail < want ? avail : want;
memcpy(dst + done, fp->buf + fp->buf_pos, (size_t)chunk);
fp->buf_pos += chunk;
done += (size_t)chunk;
}
return done / size;
}
size_t fwrite(const void* ptr, size_t size, size_t nmemb, FILE* fp) {
if (!fp || !ptr || size == 0 || nmemb == 0) return 0;
size_t total = size * nmemb;
const char* src = (const char*)ptr;
size_t done = 0;
/* Unbuffered: write directly, bypass buffer */
if (fp->flags & _STDIO_UNBUF) {
while (done < total) {
int w = write(fp->fd, src + done, total - done);
if (w <= 0) break;
done += (size_t)w;
}
return done / size;
}
while (done < total) {
int space = BUFSIZ - fp->buf_pos;
int want = (int)(total - done);
int chunk = space < want ? space : want;
memcpy(fp->buf + fp->buf_pos, src + done, (size_t)chunk);
fp->buf_pos += chunk;
done += (size_t)chunk;
if (fp->buf_pos >= BUFSIZ) fflush(fp);
}
/* Line-buffered: flush if the written data contains a newline */
if ((fp->flags & _STDIO_LBUF) && fp->buf_pos > 0) {
for (size_t i = 0; i < total; i++) {
if (src[i] == '\n') {
fflush(fp);
break;
}
}
}
return done / size;
}
int fgetc(FILE* fp) {
unsigned char c;
if (fread(&c, 1, 1, fp) != 1) return EOF;
return (int)c;
}
char* fgets(char* s, int size, FILE* fp) {
if (!s || size <= 0 || !fp) return (char*)0;
int i = 0;
while (i < size - 1) {
int c = fgetc(fp);
if (c == EOF) { if (i == 0) return (char*)0; break; }
s[i++] = (char)c;
if (c == '\n') break;
}
s[i] = '\0';
return s;
}
int fputc(int c, FILE* fp) {
unsigned char ch = (unsigned char)c;
if (fwrite(&ch, 1, 1, fp) != 1) return EOF;
return (int)ch;
}
int fputs(const char* s, FILE* fp) {
size_t len = strlen(s);
if (fwrite(s, 1, len, fp) != len) return EOF;
return 0;
}
int feof(FILE* fp) { return fp ? (fp->flags & _STDIO_EOF) : 0; }
int ferror(FILE* fp) { return fp ? (fp->flags & _STDIO_ERR) : 0; }
int fseek(FILE* fp, long offset, int whence) {
if (!fp) return -1;
fflush(fp);
fp->buf_pos = 0;
fp->buf_len = 0;
fp->flags &= ~_STDIO_EOF;
int rc = lseek(fp->fd, (int)offset, whence);
return (rc < 0) ? -1 : 0;
}
long ftell(FILE* fp) {
if (!fp) return -1;
long pos = (long)lseek(fp->fd, 0, 1 /* SEEK_CUR */);
if (pos < 0) return -1;
if (fp->flags & _STDIO_READ) {
pos -= (long)(fp->buf_len - fp->buf_pos);
}
return pos;
}
void rewind(FILE* fp) {
if (fp) fseek(fp, 0, 0 /* SEEK_SET */);
}
int remove(const char* path) {
return unlink(path);
}
int rename(const char* oldpath, const char* newpath) {
(void)oldpath; (void)newpath;
return -1;
}
int setvbuf(FILE* fp, char* buf, int mode, size_t size) {
(void)buf; (void)size; /* we use internal buffer only */
if (!fp) return -1;
fp->flags &= ~(_STDIO_LBUF | _STDIO_UNBUF);
if (mode == 1 /* _IOLBF */) fp->flags |= _STDIO_LBUF;
else if (mode == 2 /* _IONBF */) fp->flags |= _STDIO_UNBUF;
/* _IOFBF (0): fully buffered — no extra flag needed */
return 0;
}
void setbuf(FILE* fp, char* buf) {
if (!buf) setvbuf(fp, (char*)0, 2 /* _IONBF */, 0);
else setvbuf(fp, buf, 0 /* _IOFBF */, BUFSIZ);
}
int vfprintf(FILE* fp, const char* fmt, va_list ap) {
char buf[1024];
int n = vsnprintf(buf, sizeof(buf), fmt, ap);
if (n > 0) {
int w = n;
if (w > (int)(sizeof(buf) - 1)) w = (int)(sizeof(buf) - 1);
fwrite(buf, 1, (size_t)w, fp);
}
return n;
}
int fprintf(FILE* fp, const char* fmt, ...) {
va_list ap;
va_start(ap, fmt);
int r = vfprintf(fp, fmt, ap);
va_end(ap);
return r;
}
int putchar(int c) {
unsigned char ch = (unsigned char)c;
fwrite(&ch, 1, 1, stdout);
return c;
}
int puts(const char* s) {
int len = (int)strlen(s);
fwrite(s, 1, (size_t)len, stdout);
fwrite("\n", 1, 1, stdout);
return len + 1;
}
/* Minimal vsnprintf supporting: %d %i %u %x %X %s %c %p %% */
int vsnprintf(char* buf, size_t size, const char* fmt, va_list ap) {
size_t pos = 0;
#define PUTC(c) do { if (pos + 1 < size) buf[pos] = (c); pos++; } while(0)
if (size == 0) {
/* Cannot write anything; return 0 */
return 0;
}
while (*fmt) {
if (*fmt != '%') {
PUTC(*fmt);
fmt++;
continue;
}
fmt++; /* skip '%' */
/* Flags */
int pad_zero = 0;
int left_align = 0;
while (*fmt == '0' || *fmt == '-') {
if (*fmt == '0') pad_zero = 1;
if (*fmt == '-') left_align = 1;
fmt++;
}
if (left_align) pad_zero = 0;
/* Width */
int width = 0;
while (*fmt >= '0' && *fmt <= '9') {
width = width * 10 + (*fmt - '0');
fmt++;
}
/* Specifier */
char tmp[32];
int tmplen = 0;
const char* str = 0;
switch (*fmt) {
case 'd':
case 'i': {
int v = va_arg(ap, int);
int neg = 0;
unsigned int uv;
if (v < 0) { neg = 1; uv = (unsigned int)(-(v + 1)) + 1; }
else { uv = (unsigned int)v; }
if (uv == 0) { tmp[tmplen++] = '0'; }
else { while (uv) { tmp[tmplen++] = (char)('0' + uv % 10); uv /= 10; } }
if (neg) tmp[tmplen++] = '-';
/* reverse */
for (int i = 0; i < tmplen / 2; i++) {
char t = tmp[i]; tmp[i] = tmp[tmplen-1-i]; tmp[tmplen-1-i] = t;
}
str = tmp;
break;
}
case 'u': {
unsigned int v = va_arg(ap, unsigned int);
if (v == 0) { tmp[tmplen++] = '0'; }
else { while (v) { tmp[tmplen++] = (char)('0' + v % 10); v /= 10; } }
for (int i = 0; i < tmplen / 2; i++) {
char t = tmp[i]; tmp[i] = tmp[tmplen-1-i]; tmp[tmplen-1-i] = t;
}
str = tmp;
break;
}
case 'x':
case 'X':
case 'p': {
const char* hex = (*fmt == 'X') ? "0123456789ABCDEF" : "0123456789abcdef";
unsigned int v;
if (*fmt == 'p') {
v = (unsigned int)(uintptr_t)va_arg(ap, void*);
tmp[tmplen++] = '0';
tmp[tmplen++] = 'x';
} else {
v = va_arg(ap, unsigned int);
}
int start = tmplen;
if (v == 0) { tmp[tmplen++] = '0'; }
else { while (v) { tmp[tmplen++] = hex[v & 0xF]; v >>= 4; } }
/* reverse the hex digits only */
for (int i = start; i < start + (tmplen - start) / 2; i++) {
int j = start + (tmplen - start) - 1 - (i - start);
char t = tmp[i]; tmp[i] = tmp[j]; tmp[j] = t;
}
str = tmp;
break;
}
case 's': {
str = va_arg(ap, const char*);
if (!str) str = "(null)";
tmplen = (int)strlen(str);
break;
}
case 'c': {
tmp[0] = (char)va_arg(ap, int);
tmplen = 1;
str = tmp;
break;
}
case '%':
PUTC('%');
fmt++;
continue;
case '\0':
goto done;
default:
PUTC('%');
PUTC(*fmt);
fmt++;
continue;
}
fmt++;
if (str && tmplen == 0) tmplen = (int)strlen(str);
/* Padding */
int pad = width - tmplen;
if (!left_align && pad > 0) {
char pc = pad_zero ? '0' : ' ';
for (int i = 0; i < pad; i++) PUTC(pc);
}
for (int i = 0; i < tmplen; i++) PUTC(str[i]);
if (left_align && pad > 0) {
for (int i = 0; i < pad; i++) PUTC(' ');
}
}
done:
if (pos < size) buf[pos] = '\0';
else if (size > 0) buf[size - 1] = '\0';
return (int)pos;
#undef PUTC
}
int sprintf(char* buf, const char* fmt, ...) {
va_list ap;
va_start(ap, fmt);
int r = vsnprintf(buf, (size_t)0x7FFFFFFF, fmt, ap);
va_end(ap);
return r;
}
int snprintf(char* buf, size_t size, const char* fmt, ...) {
va_list ap;
va_start(ap, fmt);
int r = vsnprintf(buf, size, fmt, ap);
va_end(ap);
return r;
}
int sscanf(const char* str, const char* fmt, ...) {
/* Minimal sscanf: only supports %d and %s */
va_list ap;
va_start(ap, fmt);
int count = 0;
const char* s = str;
const char* f = fmt;
while (*f && *s) {
if (*f == '%') {
f++;
if (*f == 'd' || *f == 'i') {
f++;
int* out = va_arg(ap, int*);
int neg = 0;
while (*s == ' ') s++;
if (*s == '-') { neg = 1; s++; }
else if (*s == '+') { s++; }
if (*s < '0' || *s > '9') break;
int val = 0;
while (*s >= '0' && *s <= '9') { val = val * 10 + (*s - '0'); s++; }
*out = neg ? -val : val;
count++;
} else if (*f == 's') {
f++;
char* out = va_arg(ap, char*);
while (*s == ' ') s++;
int i = 0;
while (*s && *s != ' ' && *s != '\n' && *s != '\t') out[i++] = *s++;
out[i] = '\0';
count++;
} else {
break;
}
} else if (*f == ' ') {
f++;
while (*s == ' ') s++;
} else {
if (*f != *s) break;
f++; s++;
}
}
va_end(ap);
return count;
}
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 r = vprintf(fmt, ap);
va_end(ap);
return r;
}
void clearerr(FILE* fp) {
if (fp) fp->flags &= ~(_STDIO_EOF | _STDIO_ERR);
}
int ungetc(int c, FILE* fp) {
if (!fp || c == EOF) return EOF;
/* Simple 1-byte pushback: store in buf_pos-1 if possible */
if (fp->buf_pos > 0) {
fp->buf_pos--;
fp->buf[fp->buf_pos] = (char)c;
} else if (fp->buf_len < (int)sizeof(fp->buf)) {
/* Shift buffer right by 1 */
for (int i = fp->buf_len; i > 0; i--)
fp->buf[i] = fp->buf[i - 1];
fp->buf[0] = (char)c;
fp->buf_len++;
} else {
return EOF;
}
fp->flags &= ~_STDIO_EOF;
return (unsigned char)c;
}
int getc(FILE* fp) { return fgetc(fp); }
int putc(int c, FILE* fp) { return fputc(c, fp); }
ssize_t getdelim(char** lineptr, size_t* n, int delim, FILE* stream) {
if (!lineptr || !n || !stream) { return -1; }
if (!*lineptr || *n == 0) {
*n = 128;
*lineptr = (char*)malloc(*n);
if (!*lineptr) return -1;
}
size_t pos = 0;
int c;
while ((c = fgetc(stream)) != EOF) {
if (pos + 2 > *n) {
size_t newn = *n * 2;
char* tmp = (char*)realloc(*lineptr, newn);
if (!tmp) return -1;
*lineptr = tmp;
*n = newn;
}
(*lineptr)[pos++] = (char)c;
if (c == delim) break;
}
if (pos == 0 && c == EOF) return -1;
(*lineptr)[pos] = '\0';
return (ssize_t)pos;
}
ssize_t getline(char** lineptr, size_t* n, FILE* stream) {
return getdelim(lineptr, n, '\n', stream);
}
FILE* popen(const char* command, const char* type) {
int fds[2];
extern int pipe(int[2]);
extern int fork(void);
extern int execl(const char*, const char*, ...);
extern int dup2(int, int);
extern int close(int);
extern void _exit(int);
if (pipe(fds) < 0) return (FILE*)0;
int pid = fork();
if (pid < 0) {
close(fds[0]);
close(fds[1]);
return (FILE*)0;
}
if (pid == 0) {
/* Child */
if (type[0] == 'r') {
close(fds[0]);
dup2(fds[1], 1);
close(fds[1]);
} else {
close(fds[1]);
dup2(fds[0], 0);
close(fds[0]);
}
execl("/bin/sh", "sh", "-c", command, (char*)0);
_exit(127);
}
/* Parent */
if (type[0] == 'r') {
close(fds[1]);
return fdopen(fds[0], "r");
} else {
close(fds[0]);
return fdopen(fds[1], "w");
}
}
int pclose(FILE* fp) {
extern int waitpid(int, int*, int);
if (!fp) return -1;
int fd = fileno(fp);
(void)fd;
fclose(fp);
int status = 0;
waitpid(-1, &status, 0);
return status;
}
FILE* tmpfile(void) {
static int tmpcount = 0;
char name[32];
extern int getpid(void);
snprintf(name, sizeof(name), "/tmp/.tmpf_%d_%d", getpid(), tmpcount++);
return fopen(name, "w+");
}
char* tmpnam(char* s) {
static char buf[32];
static int count = 0;
snprintf(buf, sizeof(buf), "/tmp/tmp_%d", count++);
if (s) { strcpy(s, buf); return s; }
return buf;
}
int fscanf(FILE* fp, const char* fmt, ...) {
/* Read a line, then delegate to sscanf */
char line[512];
if (!fgets(line, (int)sizeof(line), fp)) return EOF;
va_list ap;
va_start(ap, fmt);
/* We can't pass va_list to sscanf directly, so use a manual approach
* that matches sscanf's minimal implementation for %d and %s */
int count = 0;
const char* s = line;
const char* f = fmt;
while (*f && *s) {
if (*f == '%') {
f++;
if (*f == 'd' || *f == 'i') {
f++;
int* out = va_arg(ap, int*);
int neg = 0;
while (*s == ' ') s++;
if (*s == '-') { neg = 1; s++; }
else if (*s == '+') { s++; }
if (*s < '0' || *s > '9') break;
int val = 0;
while (*s >= '0' && *s <= '9') { val = val * 10 + (*s - '0'); s++; }
*out = neg ? -val : val;
count++;
} else if (*f == 's') {
f++;
char* out = va_arg(ap, char*);
while (*s == ' ') s++;
int i = 0;
while (*s && *s != ' ' && *s != '\n' && *s != '\t') out[i++] = *s++;
out[i] = '\0';
count++;
} else if (*f == 'c') {
f++;
char* out = va_arg(ap, char*);
*out = *s++;
count++;
} else {
break;
}
} else if (*f == ' ') {
f++;
while (*s == ' ') s++;
} else {
if (*f != *s) break;
f++; s++;
}
}
va_end(ap);
return count;
}
int scanf(const char* fmt, ...) {
char line[512];
if (!fgets(line, (int)sizeof(line), stdin)) return EOF;
va_list ap;
va_start(ap, fmt);
int count = 0;
const char* s = line;
const char* f = fmt;
while (*f && *s) {
if (*f == '%') {
f++;
if (*f == 'd' || *f == 'i') {
f++;
int* out = va_arg(ap, int*);
int neg = 0;
while (*s == ' ') s++;
if (*s == '-') { neg = 1; s++; }
else if (*s == '+') { s++; }
if (*s < '0' || *s > '9') break;
int val = 0;
while (*s >= '0' && *s <= '9') { val = val * 10 + (*s - '0'); s++; }
*out = neg ? -val : val;
count++;
} else if (*f == 's') {
f++;
char* out = va_arg(ap, char*);
while (*s == ' ') s++;
int i = 0;
while (*s && *s != ' ' && *s != '\n' && *s != '\t') out[i++] = *s++;
out[i] = '\0';
count++;
} else {
break;
}
} else if (*f == ' ') {
f++;
while (*s == ' ') s++;
} else {
if (*f != *s) break;
f++; s++;
}
}
va_end(ap);
return count;
}