]> Projects (at) Tadryanom (dot) Me - AdrOS.git/commitdiff
feat: ulibc DOOM-ready extensions — fseek, ftell, sprintf, sscanf, strdup, etc.
authorTulio A M Mendes <[email protected]>
Thu, 12 Feb 2026 07:48:04 +0000 (04:48 -0300)
committerTulio A M Mendes <[email protected]>
Fri, 13 Feb 2026 02:44:55 +0000 (23:44 -0300)
Added missing C library functions required by the DOOM engine:

stdio: fseek, ftell, rewind, sprintf, sscanf (minimal %d/%s),
       remove, rename (stub)
stdlib: getenv (stub), abs, labs
string: strncat, strdup, strcasecmp, strncasecmp, strstr,
        memchr, strtok

user/ulibc/include/stdio.h
user/ulibc/include/stdlib.h
user/ulibc/include/string.h
user/ulibc/src/stdio.c
user/ulibc/src/stdlib.c
user/ulibc/src/string.c

index bfeaafd3e12afa53d993bdf22af6c31190f79e54..dd50fdb5b4306d1b4a2e6b7746cabd2612236c79 100644 (file)
@@ -25,10 +25,19 @@ extern FILE* stdin;
 extern FILE* stdout;
 extern FILE* stderr;
 
+#ifndef SEEK_SET
+#define SEEK_SET 0
+#define SEEK_CUR 1
+#define SEEK_END 2
+#endif
+
 FILE*   fopen(const char* path, const char* mode);
 int     fclose(FILE* fp);
 size_t  fread(void* ptr, size_t size, size_t nmemb, FILE* fp);
 size_t  fwrite(const void* ptr, size_t size, size_t nmemb, FILE* fp);
+int     fseek(FILE* fp, long offset, int whence);
+long    ftell(FILE* fp);
+void    rewind(FILE* fp);
 int     fflush(FILE* fp);
 int     fgetc(FILE* fp);
 char*   fgets(char* s, int size, FILE* fp);
@@ -43,7 +52,11 @@ int     putchar(int c);
 int     puts(const char* s);
 int     printf(const char* fmt, ...) __attribute__((format(printf, 1, 2)));
 int     vprintf(const char* fmt, va_list ap);
+int     sprintf(char* buf, const char* fmt, ...) __attribute__((format(printf, 2, 3)));
 int     snprintf(char* buf, size_t size, const char* fmt, ...) __attribute__((format(printf, 3, 4)));
 int     vsnprintf(char* buf, size_t size, const char* fmt, va_list ap);
+int     sscanf(const char* str, const char* fmt, ...);
+int     remove(const char* path);
+int     rename(const char* oldpath, const char* newpath);
 
 #endif
index 96b9c97c8160fabe01487e4db13757ac14b4c809..81f335369a2d9362ed8c2218d2f415ad29747e2c 100644 (file)
@@ -10,6 +10,10 @@ void*   realloc(void* ptr, size_t size);
 
 int     atoi(const char* s);
 char*   realpath(const char* path, char* resolved);
+char*   getenv(const char* name);
+int     abs(int x);
+long    labs(long x);
+
 void    exit(int status) __attribute__((noreturn));
 
 #ifndef NULL
index 10fe09da715870e446879d11965bb060b659e2c5..917e25e0e9832028e3158c90c8d6ddd1f5d4e8ee 100644 (file)
@@ -16,5 +16,12 @@ int     strncmp(const char* a, const char* b, size_t n);
 char*   strchr(const char* s, int c);
 char*   strrchr(const char* s, int c);
 char*   strcat(char* dst, const char* src);
+char*   strncat(char* dst, const char* src, size_t n);
+char*   strdup(const char* s);
+int     strcasecmp(const char* a, const char* b);
+int     strncasecmp(const char* a, const char* b, size_t n);
+char*   strstr(const char* haystack, const char* needle);
+void*   memchr(const void* s, int c, size_t n);
+char*   strtok(char* str, const char* delim);
 
 #endif
index 2dbf69f0e090d4ff658c4634edf62e5d2aaadd8c..fd599e67a7cad3a803feac4b96d1fe9e036cc139 100644 (file)
@@ -137,6 +137,39 @@ int fputs(const char* s, FILE* fp) {
 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 vfprintf(FILE* fp, const char* fmt, va_list ap) {
     char buf[1024];
     int n = vsnprintf(buf, sizeof(buf), fmt, ap);
@@ -309,6 +342,14 @@ done:
 #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);
@@ -317,6 +358,51 @@ int snprintf(char* buf, size_t size, const char* fmt, ...) {
     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) {
     char buf[1024];
     int n = vsnprintf(buf, sizeof(buf), fmt, ap);
index de10e2aa4b4ec31d650246424e89c156894f943a..0fa627388738d47880a4c665b00db1974ed9eb2e 100644 (file)
@@ -106,6 +106,19 @@ char* realpath(const char* path, char* resolved) {
     return resolved;
 }
 
+char* getenv(const char* name) {
+    (void)name;
+    return (char*)0;
+}
+
+int abs(int x) {
+    return x < 0 ? -x : x;
+}
+
+long labs(long x) {
+    return x < 0 ? -x : x;
+}
+
 void exit(int status) {
     _exit(status);
 }
index 1201fe29061af379a88c68bd174e15dd6abc5923..505fd3b7f4eca3f3ae68fb2b03375e96d325d353 100644 (file)
@@ -91,3 +91,72 @@ char* strcat(char* dst, const char* src) {
     *p = 0;
     return dst;
 }
+
+char* strncat(char* dst, const char* src, size_t n) {
+    char* p = dst;
+    while (*p) p++;
+    size_t i = 0;
+    while (i < n && src[i]) { *p++ = src[i++]; }
+    *p = 0;
+    return dst;
+}
+
+char* strdup(const char* s) {
+    if (!s) return (void*)0;
+    size_t len = strlen(s) + 1;
+    extern void* malloc(size_t);
+    char* d = (char*)malloc(len);
+    if (d) memcpy(d, s, len);
+    return d;
+}
+
+static int tolower_impl(int c) {
+    return (c >= 'A' && c <= 'Z') ? c + 32 : c;
+}
+
+int strcasecmp(const char* a, const char* b) {
+    while (*a && tolower_impl((unsigned char)*a) == tolower_impl((unsigned char)*b)) { a++; b++; }
+    return tolower_impl((unsigned char)*a) - tolower_impl((unsigned char)*b);
+}
+
+int strncasecmp(const char* a, const char* b, size_t n) {
+    for (size_t i = 0; i < n; i++) {
+        int ca = tolower_impl((unsigned char)a[i]);
+        int cb = tolower_impl((unsigned char)b[i]);
+        if (ca != cb) return ca - cb;
+        if (a[i] == 0) break;
+    }
+    return 0;
+}
+
+char* strstr(const char* haystack, const char* needle) {
+    if (!*needle) return (char*)haystack;
+    size_t nlen = strlen(needle);
+    while (*haystack) {
+        if (strncmp(haystack, needle, nlen) == 0) return (char*)haystack;
+        haystack++;
+    }
+    return (void*)0;
+}
+
+void* memchr(const void* s, int c, size_t n) {
+    const uint8_t* p = (const uint8_t*)s;
+    for (size_t i = 0; i < n; i++) {
+        if (p[i] == (uint8_t)c) return (void*)(p + i);
+    }
+    return (void*)0;
+}
+
+static char* strtok_state = (void*)0;
+
+char* strtok(char* str, const char* delim) {
+    if (str) strtok_state = str;
+    if (!strtok_state) return (void*)0;
+    /* skip leading delimiters */
+    while (*strtok_state && strchr(delim, *strtok_state)) strtok_state++;
+    if (!*strtok_state) return (void*)0;
+    char* start = strtok_state;
+    while (*strtok_state && !strchr(delim, *strtok_state)) strtok_state++;
+    if (*strtok_state) *strtok_state++ = 0;
+    return start;
+}