Skip to content

Commit

Permalink
Add libc
Browse files Browse the repository at this point in the history
  • Loading branch information
luka177 committed May 4, 2021
0 parents commit 8a60de9
Show file tree
Hide file tree
Showing 2 changed files with 325 additions and 0 deletions.
297 changes: 297 additions & 0 deletions libc.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,297 @@
#include "libc.h"

#include <stdarg.h>

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;
}
28 changes: 28 additions & 0 deletions libc.h
Original file line number Diff line number Diff line change
@@ -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);

0 comments on commit 8a60de9

Please sign in to comment.