From 8a60de9747976c044e4c4b4df939d4484e283be6 Mon Sep 17 00:00:00 2001 From: luka177 Date: Tue, 4 May 2021 19:11:40 +0300 Subject: [PATCH] Add libc --- libc.c | 297 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ libc.h | 28 ++++++ 2 files changed, 325 insertions(+) create mode 100644 libc.c create mode 100644 libc.h diff --git a/libc.c b/libc.c new file mode 100644 index 0000000..13fe4b3 --- /dev/null +++ b/libc.c @@ -0,0 +1,297 @@ +#include "libc.h" + +#include + +void _putchar(char character); + +/** \brief Division result + * \sa uidiv + */ +typedef struct uidiv_result { + u32_t quo; ///< Quotient + u32_t rem; ///< Remainder +} uidiv_result_t; + +/********************************************//** + * \brief Unsigned integer division + * + * ARM does not have native division support + * \returns Result of operation or zero if + * dividing by zero. + ***********************************************/ +uidiv_result_t +uidiv (u32_t num, ///< Numerator + u32_t dem) ///< Denominator +{ + u32_t tmp = dem; + uidiv_result_t ans = {0}; + + if (dem == 0) + { + // TODO: Somehow make error + return ans; + } + + while (tmp <= num >> 1) + { + tmp <<= 1; + } + + do + { + if (num >= tmp) + { + num -= tmp; + ans.quo++; + } + ans.quo <<= 1; + tmp >>= 1; + } while (tmp >= dem); + ans.quo >>= 1; + ans.rem = num; + + return ans; +} + +void* memset(void* dst, int c, u32_t n) +{ + char* q = dst; + char* end = q + n; + + for (;;) { + if (q >= end) break; *q++ = (char) c; + if (q >= end) break; *q++ = (char) c; + if (q >= end) break; *q++ = (char) c; + if (q >= end) break; *q++ = (char) c; + } + + return dst; +} + +u32_t +strlen(const char *str) +{ + const char *s; + + for (s = str; *s; ++s) + ; + return (s - str); +} + +// thanks naehrwert for the tiny printf +static void _putn(char **p_str, u32_t x, u32_t base, char fill, int fcnt, int upper) +{ + char buf[65]; + char *digits; + char *p; + int c = fcnt; + uidiv_result_t div_res; + + if (upper) + digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + else + digits = "0123456789abcdefghijklmnopqrstuvwxyz"; + + if(base > 36) + return; + + p = buf + 64; + *p = 0; + do + { + c--; + div_res = uidiv (x, base); + *--p = digits[div_res.rem]; + x = div_res.quo; + }while(x); + + if(fill != 0) + { + while(c > 0) + { + *--p = fill; + c--; + } + } + + for(; *p != '\0'; *((*p_str)++) = *(p++)); +} + +/********************************************//** + * \brief Simple @c vsprintf + * + * Only supports %c, %s, %u, %x, %X with + * optional zero padding. + * Always returns zero. + ***********************************************/ +int vsprintf (char *str, const char *fmt, va_list ap) +{ + char *s; + char c, fill; + int fcnt; + u32_t n; + + while(*fmt) + { + if(*fmt == '%') + { + fmt++; + fill = 0; + fcnt = 0; + if((*fmt >= '0' && *fmt <= '9') || *fmt == ' ') + if(*(fmt+1) >= '0' && *(fmt+1) <= '9') + { + fill = *fmt; + fcnt = *(fmt+1) - '0'; + fmt++; + fmt++; + } + switch(*fmt) + { + case 'c': + c = va_arg(ap, u32_t); + *(str++) = c; + break; + case 's': + s = va_arg(ap, char *); + for(; *s != '\0'; *(str++) = *(s++)); + break; + case 'u': + n = va_arg(ap, u32_t); + _putn(&str, n, 10, fill, fcnt, 0); + break; + case 'x': + n = va_arg(ap, u32_t); + _putn(&str, n, 16, fill, fcnt, 0); + break; + case 'X': + n = va_arg(ap, u32_t); + _putn(&str, n, 16, fill, fcnt, 1); + break; + case '%': + *(str++) = '%'; + break; + case '\0': + goto out; + default: + *(str++) = '%'; + *(str++) = *fmt; + break; + } + } + else + *(str++) = *fmt; + fmt++; + } + + out: + *str = '\0'; + return 0; +} + +/********************************************//** + * \brief Simple @c sprintf + * + * Only supports %c, %s, %u, %x, %X with + * optional zero padding. + * Always returns zero. + ***********************************************/ +int sprintf (char *str, const char *format, ...) +{ + va_list arg; + + va_start (arg, format); + vsprintf (str, format, arg); + va_end (arg); + return 0; +} + +int putchar(int c) { + _putchar(c); + return 0; +} + +int printf(const char *format, ...) { + char line[512] = {0}; + va_list arg; + + va_start (arg, format); + vsprintf (line, format, arg); + va_end (arg); + + for (char *c = line; *c; ++c) { + putchar(*c); + } + + return 0; +} + +int puts(const char *line) { + for (const char *c = line; *c; ++c) { + putchar(*c); + } + putchar('\n'); + return 0; +} + +char * +strcpy(char *to, const char *from) +{ + char *save = to; + + for (; (*to = *from) != '\0'; ++from, ++to); + return(save); +} + +char * +strcat(char *dest, const char *src) +{ + strcpy(dest + strlen(dest), src); + return dest; +} + +/* + * Compare strings. + */ +int +strcmp(const char *s1, const char *s2) +{ + while (*s1 == *s2++) + if (*s1++ == 0) + return (0); + return (*(unsigned char *)s1 - *(unsigned char *)--s2); +} + +int +strncmp(const char *s1, const char *s2, u32_t n) +{ + if (n == 0) + return (0); + do { + if (*s1 != *s2++) + return (*(unsigned char *)s1 - *(unsigned char *)--s2); + if (*s1++ == 0) + break; + } while (--n != 0); + return (0); +} + +void *memcpy(void *dest, const void *src, size_t n) +{ + char *dp = dest; + const char *sp = src; + while (n--) + *dp++ = *sp++; + 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; + else + p1++,p2++; + return 0; +} diff --git a/libc.h b/libc.h new file mode 100644 index 0000000..7b60a92 --- /dev/null +++ b/libc.h @@ -0,0 +1,28 @@ +#pragma once + +/** \name Fixed width integers + * @{ + */ +typedef unsigned char u8_t; ///< Unsigned 8-bit type +typedef unsigned short int u16_t; ///< Unsigned 16-bit type +typedef unsigned int u32_t; ///< Unsigned 32-bit type +typedef unsigned long long u64_t; ///< Unsigned 64-bit type + +typedef u64_t u64; +typedef u32_t u32; +typedef u16_t u16; +typedef u8_t u8; + +typedef unsigned size_t; + +size_t strlen(const char *str); +int printf(const char *format, ...); +int sprintf (char *str, const char *format, ...); +char *strcpy(char *to, const char *from); +int strncmp(const char *s1, const char *s2, u32_t n); +void* memset(void* dst, int c, u32_t n); +void *memcpy(void *dest, const void *src, size_t n); +int strcmp(const char *s1, const char *s2); + +int puts(const char *line); +int memcmp(const void* s1, const void* s2,size_t n);