// C runtime stubs for freestanding Nim #include void *memcpy(void *dest, const void *src, size_t n) { unsigned char *d = dest; const unsigned char *s = src; while (n--) *d++ = *s++; return dest; } void *memset(void *s, int c, size_t n) { unsigned char *p = s; while (n--) *p++ = (unsigned char)c; return s; } void *memmove(void *dest, const void *src, size_t n) { unsigned char *d = dest; const unsigned char *s = src; if (d < s) { while (n--) *d++ = *s++; } else { d += n; s += n; while (n--) *--d = *--s; } return dest; } int memcmp(const void *s1, const void *s2, size_t n) { const unsigned char *p1 = s1, *p2 = s2; while (n--) { if (*p1 != *p2) return *p1 - *p2; p1++; p2++; } return 0; } size_t strlen(const char *s) { size_t len = 0; while (*s++) len++; return len; } char *strcpy(char *dest, const char *src) { char *d = dest; while ((*d++ = *src++)); return dest; } int strcmp(const char *s1, const char *s2) { while (*s1 && (*s1 == *s2)) { s1++; s2++; } return *(unsigned char*)s1 - *(unsigned char*)s2; } int strncmp(const char *s1, const char *s2, size_t n) { while (n && *s1 && (*s1 == *s2)) { s1++; s2++; n--; } if (n == 0) return 0; return *(unsigned char*)s1 - *(unsigned char*)s2; } char *strncpy(char *dest, const char *src, size_t n) { char *d = dest; while (n && (*d++ = *src++)) n--; while (n--) *d++ = '\0'; return dest; } // abort is used by Nim panic void abort(void) { /* Call Nim panic */ extern void panic(const char*); panic("abort() called"); while(1) {} } /* Stdio stubs - these call into Zig UART */ extern void console_write(const char*, unsigned long); int puts(const char *s) { if (s) { unsigned long len = strlen(s); console_write(s, len); console_write("\n", 1); } return 0; } int putchar(int c) { char buf[1] = {(char)c}; console_write(buf, 1); return c; } #include void itoa(int n, char s[]) { int i, sign; if ((sign = n) < 0) n = -n; i = 0; do { s[i++] = n % 10 + '0'; } while ((n /= 10) > 0); if (sign < 0) s[i++] = '-'; s[i] = '\0'; // reverse for (int j = 0, k = i-1; j < k; j++, k--) { char temp = s[j]; s[j] = s[k]; s[k] = temp; } } int printf(const char *format, ...) { va_list args; va_start(args, format); while (*format) { if (*format == '%' && *(format + 1)) { format++; if (*format == 's') { char *s = va_arg(args, char *); if (s) console_write(s, strlen(s)); } else if (*format == 'd') { int d = va_arg(args, int); char buf[16]; itoa(d, buf); console_write(buf, strlen(buf)); } else { putchar('%'); putchar(*format); } } else { putchar(*format); } format++; } va_end(args); return 0; } int fprintf(void *stream, const char *format, ...) { return printf(format); } int vsnprintf(char *str, size_t size, const char *format, va_list args) { size_t count = 0; if (size == 0) return 0; while (*format && count < size - 1) { if (*format == '%' && *(format + 1)) { format++; if (*format == 's') { char *s = va_arg(args, char *); if (s) { while (*s && count < size - 1) { str[count++] = *s++; } } } else if (*format == 'd' || *format == 'i') { int d = va_arg(args, int); char buf[16]; itoa(d, buf); char *b = buf; while (*b && count < size - 1) { str[count++] = *b++; } } else { str[count++] = '%'; if (count < size - 1) str[count++] = *format; } } else { str[count++] = *format; } format++; } str[count] = '\0'; return count; } int snprintf(char *str, size_t size, const char *format, ...) { va_list args; va_start(args, format); int ret = vsnprintf(str, size, format, args); va_end(args); return ret; } int fflush(void *stream) { return 0; } unsigned long fwrite(const void *ptr, unsigned long size, unsigned long nmemb, void *stream) { console_write(ptr, size * nmemb); return nmemb; } /* Signal stubs - no signals in freestanding */ typedef void (*sighandler_t)(int); sighandler_t signal(int signum, sighandler_t handler) { (void)signum; (void)handler; return (sighandler_t)0; } int raise(int sig) { (void)sig; return 0; } /* Exit stubs */ void exit(int status) { extern void panic(const char*); panic("exit() called - system halt"); while(1) {} } void _Exit(int status) { exit(status); } int atoi(const char *nptr) { int res = 0; while (*nptr >= '0' && *nptr <= '9') { res = res * 10 + (*nptr - '0'); nptr++; } return res; } int sprintf(char *str, const char *format, ...) { va_list args; va_start(args, format); // Unsafe sprintf limit int ret = vsnprintf(str, 2048, format, args); va_end(args); return ret; } double strtod(const char *nptr, char **endptr) { if (endptr) *endptr = (char*)nptr + strlen(nptr); // Fake endptr return (double)atoi(nptr); } // qsort uses existing memcpy void qsort(void *base, size_t nmemb, size_t size, int (*compar)(const void *, const void *)) { // Bubble sort for simplicity (O(n^2)) if (nmemb < 2) return; char *b = (char *)base; char tmp[256]; // Max item size 256 bytes for swap // Verify size? If size > 256, we fail or use loop. // mu_Container* is pointer size (8). for (size_t i = 0; i < nmemb - 1; i++) { for (size_t j = 0; j < nmemb - i - 1; j++) { char *p1 = b + j * size; char *p2 = b + (j + 1) * size; if (compar(p1, p2) > 0) { // Swap if (size <= 256) { memcpy(tmp, p1, size); memcpy(p1, p2, size); memcpy(p2, tmp, size); } } } } } int errno = 0;