os-workshop

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs

commit 21ef5111f4ced2aa63a2c18c97d47750b966e3dc
parent 7b0c6311f7d2357b5fc79bfe918700f47e300389
Author: Brian Swetland <swetland@frotz.net>
Date:   Fri, 22 Apr 2022 11:13:26 -0700

libc: import minimal subset of lk libc

as of lk at ad246760ff47ca4f1f8484ec0726849e0360e600  2019.07.13

- pick up s*printf(), atoi() and friends, ctype utils, and
  the common mem*() and str*() functions
- disable long long and float support in printf
- WITH_PRINTF_LL and WITH_PRINTF_FP can re-enable
- use stdint.h instead of sys/types.h

Diffstat:
Alibc/inc/assert.h | 8++++++++
Alibc/inc/ctype.h | 16++++++++++++++++
Alibc/inc/errno.h | 0
Alibc/inc/stdio.h | 10++++++++++
Alibc/inc/stdlib.h | 0
Alibc/inc/string.h | 49+++++++++++++++++++++++++++++++++++++++++++++++++
Alibc/src/atoi.c | 172+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Alibc/src/ctype.c | 69+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Alibc/src/printf-engine.h | 22++++++++++++++++++++++
Alibc/src/printf.c | 622+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Alibc/src/string/memchr.c | 29+++++++++++++++++++++++++++++
Alibc/src/string/memcmp.c | 24++++++++++++++++++++++++
Alibc/src/string/memcpy.c | 53+++++++++++++++++++++++++++++++++++++++++++++++++++++
Alibc/src/string/memmove.c | 77+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Alibc/src/string/memset.c | 47+++++++++++++++++++++++++++++++++++++++++++++++
Alibc/src/string/strcat.c | 26++++++++++++++++++++++++++
Alibc/src/string/strchr.c | 21+++++++++++++++++++++
Alibc/src/string/strcmp.c | 25+++++++++++++++++++++++++
Alibc/src/string/strcpy.c | 23+++++++++++++++++++++++
Alibc/src/string/strlen.c | 25+++++++++++++++++++++++++
Alibc/src/string/strncat.c | 32++++++++++++++++++++++++++++++++
Alibc/src/string/strncmp.c | 26++++++++++++++++++++++++++
Alibc/src/string/strncpy.c | 27+++++++++++++++++++++++++++
Alibc/src/string/strnlen.c | 22++++++++++++++++++++++
Alibc/src/string/strpbrk.c | 28++++++++++++++++++++++++++++
Alibc/src/string/strrchr.c | 29+++++++++++++++++++++++++++++
Alibc/src/string/strspn.c | 32++++++++++++++++++++++++++++++++
Alibc/src/string/strstr.c | 30++++++++++++++++++++++++++++++
Alibc/src/string/strtok.c | 35+++++++++++++++++++++++++++++++++++
29 files changed, 1579 insertions(+), 0 deletions(-)

diff --git a/libc/inc/assert.h b/libc/inc/assert.h @@ -0,0 +1,8 @@ +#pragma once + +#ifdef __cplusplus +// static_assert(a, b) already exists +#else +#define static_assert(a, b) _Static_assert(a, b) +#endif + diff --git a/libc/inc/ctype.h b/libc/inc/ctype.h @@ -0,0 +1,16 @@ +#pragma once + +int isblank(int c); +int isspace(int c); +int islower(int c); +int isupper(int c); +int isdigit(int c); +int isalpha(int c); +int isalnum(int c); +int isxdigit(int c); +int isgraph(int c); +int iscntrl(int c); +int isprint(int c); +int ispunct(int c); +int tolower(int c); +int toupper(int c); diff --git a/libc/inc/errno.h b/libc/inc/errno.h diff --git a/libc/inc/stdio.h b/libc/inc/stdio.h @@ -0,0 +1,10 @@ +#pragma once + +#include <stdarg.h> +#include <stddef.h> + +int vsprintf(char *str, const char *format, va_list ap); +int vsnprintf(char *str, size_t size, const char *format, va_list ap); + +int sprintf(char *str, const char *fmt, ...); +int snprintf(char *str, size_t len, const char *fmt, ...); diff --git a/libc/inc/stdlib.h b/libc/inc/stdlib.h diff --git a/libc/inc/string.h b/libc/inc/string.h @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2008 Travis Geiselbrecht + * + * Use of this source code is governed by a MIT-style + * license that can be found in the LICENSE file or at + * https://opensource.org/licenses/MIT + */ +#pragma once + +#include <stddef.h> + +#define __PURE +#define __CONST +#define __MALLOC + +void *memchr (void const *, int, size_t) __PURE; +int memcmp (void const *, const void *, size_t) __PURE; +void *memcpy (void *, void const *, size_t); +void *memmove(void *, void const *, size_t); +void *memset (void *, int, size_t); + +char *strcat(char *, char const *); +char *strchr(char const *, int) __PURE; +int strcmp(char const *, char const *) __PURE; +char *strcpy(char *, char const *); +char const *strerror(int) __CONST; +size_t strlen(char const *) __PURE; +char *strncat(char *, char const *, size_t); +int strncmp(char const *, char const *, size_t) __PURE; +char *strncpy(char *, char const *, size_t); +char *strpbrk(char const *, char const *) __PURE; +char *strrchr(char const *, int) __PURE; +size_t strspn(char const *, char const *) __PURE; +size_t strcspn(const char *s, const char *) __PURE; +char *strstr(char const *, char const *) __PURE; +char *strtok(char *, char const *); +int strcoll(const char *s1, const char *s2) __PURE; +size_t strxfrm(char *dest, const char *src, size_t n) __PURE; +char *strdup(const char *str) __MALLOC; + +/* non standard */ +void bcopy(void const *, void *, size_t); +void bzero(void *, size_t); +size_t strlcat(char *, char const *, size_t); +size_t strlcpy(char *, char const *, size_t); +int strncasecmp(char const *, char const *, size_t) __PURE; +int strnicmp(char const *, char const *, size_t) __PURE; +size_t strnlen(char const *s, size_t count) __PURE; + diff --git a/libc/src/atoi.c b/libc/src/atoi.c @@ -0,0 +1,172 @@ +/* +** Copyright 2001, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ +/* + * Copyright (c) 2008 Travis Geiselbrecht + * + * Use of this source code is governed by a MIT-style + * license that can be found in the LICENSE file or at + * https://opensource.org/licenses/MIT + */ + +#include <limits.h> +#include <stdlib.h> +#include <ctype.h> +#include <errno.h> + +#define LONG_IS_INT 1 + +static int hexval(char c) { + if (c >= '0' && c <= '9') + return c - '0'; + else if (c >= 'a' && c <= 'f') + return c - 'a' + 10; + else if (c >= 'A' && c <= 'F') + return c - 'A' + 10; + + return 0; +} + +int atoi(const char *num) { +#if !LONG_IS_INT + // XXX fail +#else + return atol(num); +#endif +} + +unsigned int atoui(const char *num) { +#if !LONG_IS_INT + // XXX fail +#else + return atoul(num); +#endif +} + +long atol(const char *num) { + long value = 0; + int neg = 0; + + if (num[0] == '0' && num[1] == 'x') { + // hex + num += 2; + while (*num && isxdigit(*num)) + value = value * 16 + hexval(*num++); + } else { + // decimal + if (num[0] == '-') { + neg = 1; + num++; + } + while (*num && isdigit(*num)) + value = value * 10 + *num++ - '0'; + } + + if (neg) + value = -value; + + return value; +} + +unsigned long atoul(const char *num) { + unsigned long value = 0; + if (num[0] == '0' && num[1] == 'x') { + // hex + num += 2; + while (*num && isxdigit(*num)) + value = value * 16 + hexval(*num++); + } else { + // decimal + while (*num && isdigit(*num)) + value = value * 10 + *num++ - '0'; + } + + return value; +} + +unsigned long long atoull(const char *num) { + unsigned long long value = 0; + if (num[0] == '0' && num[1] == 'x') { + // hex + num += 2; + while (*num && isxdigit(*num)) + value = value * 16 + hexval(*num++); + } else { + // decimal + while (*num && isdigit(*num)) + value = value * 10 + *num++ - '0'; + } + + return value; +} + +unsigned long strtoul(const char *nptr, char **endptr, int base) { + int neg = 0; + unsigned long ret = 0; + + if (base < 0 || base == 1 || base > 36) { + errno = EINVAL; + return 0; + } + + while (isspace(*nptr)) { + nptr++; + } + + if (*nptr == '+') { + nptr++; + } else if (*nptr == '-') { + neg = 1; + nptr++; + } + + if ((base == 0 || base == 16) && nptr[0] == '0' && nptr[1] == 'x') { + base = 16; + nptr += 2; + } else if (base == 0 && nptr[0] == '0') { + base = 8; + nptr++; + } else if (base == 0) { + base = 10; + } + + for (;;) { + char c = *nptr; + int v = -1; + unsigned long new_ret; + + if (c >= 'A' && c <= 'Z') { + v = c - 'A' + 10; + } else if (c >= 'a' && c <= 'z') { + v = c - 'a' + 10; + } else if (c >= '0' && c <= '9') { + v = c - '0'; + } + + if (v < 0 || v >= base) { + if (endptr) { + *endptr = (char *) nptr; + } + break; + } + + new_ret = ret * base; + if (new_ret / base != ret || + new_ret + v < new_ret || + ret == ULONG_MAX) { + ret = ULONG_MAX; + errno = ERANGE; + } else { + ret = new_ret + v; + } + + nptr++; + } + + if (neg && ret != ULONG_MAX) { + ret = -ret; + } + + return ret; +} diff --git a/libc/src/ctype.c b/libc/src/ctype.c @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2008 Travis Geiselbrecht + * + * Use of this source code is governed by a MIT-style + * license that can be found in the LICENSE file or at + * https://opensource.org/licenses/MIT + */ +#include <ctype.h> + +int isblank(int c) { + return (c == ' ' || c == '\t'); +} + +int isspace(int c) { + return (c == ' ' || c == '\f' || c == '\n' || c == '\r' || c == '\t' || c == '\v'); +} + +int islower(int c) { + return ((c >= 'a') && (c <= 'z')); +} + +int isupper(int c) { + return ((c >= 'A') && (c <= 'Z')); +} + +int isdigit(int c) { + return ((c >= '0') && (c <= '9')); +} + +int isalpha(int c) { + return isupper(c) || islower(c); +} + +int isalnum(int c) { + return isalpha(c) || isdigit(c); +} + +int isxdigit(int c) { + return isdigit(c) || ((c >= 'a') && (c <= 'f')) || ((c >= 'A') && (c <= 'F')); +} + +int isgraph(int c) { + return ((c > ' ') && (c < 0x7f)); +} + +int iscntrl(int c) { + return ((c < ' ') || (c == 0x7f)); +} + +int isprint(int c) { + return ((c >= 0x20) && (c < 0x7f)); +} + +int ispunct(int c) { + return isgraph(c) && (!isalnum(c)); +} + +int tolower(int c) { + if ((c >= 'A') && (c <= 'Z')) + return c + ('a' - 'A'); + return c; +} + +int toupper(int c) { + if ((c >= 'a') && (c <= 'z')) + return c + ('A' - 'a'); + return c; +} + diff --git a/libc/src/printf-engine.h b/libc/src/printf-engine.h @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2008 Travis Geiselbrecht + * + * Use of this source code is governed by a MIT-style + * license that can be found in the LICENSE file or at + * https://opensource.org/licenses/MIT + */ +#pragma once + +#include <stdarg.h> +#include <stddef.h> + +/* printf engine that parses the format string and generates output */ + +/* function pointer to pass the printf engine, called back during the formatting. + * input is a string to output, length bytes to output, + * return code is number of characters that would have been written, or error code (if negative) + */ +typedef int (*_printf_engine_output_func)(const char *str, size_t len, void *state); + +int _printf_engine(_printf_engine_output_func out, void *state, const char *fmt, va_list ap); + diff --git a/libc/src/printf.c b/libc/src/printf.c @@ -0,0 +1,622 @@ +/* + * Copyright (c) 2008-2014 Travis Geiselbrecht + * + * Use of this source code is governed by a MIT-style + * license that can be found in the LICENSE file or at + * https://opensource.org/licenses/MIT + */ +#include <assert.h> +#include <limits.h> +#include <stdarg.h> +#include <stdbool.h> +#include <stdint.h> +#include <stdio.h> +#include <string.h> + +#include "printf-engine.h" + +#define __NO_INLINE __attribute((noinline)) + +#ifndef WITH_PRINTF_FP +#define WITH_PRINTF_FP 0 +#endif +#ifndef WITH_PRINTF_LL +#define WITH_PRINTF_LL 0 +#endif + +int sprintf(char *str, const char *fmt, ...) { + int err; + + va_list ap; + va_start(ap, fmt); + err = vsprintf(str, fmt, ap); + va_end(ap); + + return err; +} + +int snprintf(char *str, size_t len, const char *fmt, ...) { + int err; + + va_list ap; + va_start(ap, fmt); + err = vsnprintf(str, len, fmt, ap); + va_end(ap); + + return err; +} + +int vsprintf(char *str, const char *fmt, va_list ap) { + return vsnprintf(str, INT_MAX, fmt, ap); +} + +struct _output_args { + char *outstr; + size_t len; + size_t pos; +}; + +static int _vsnprintf_output(const char *str, size_t len, void *state) { + struct _output_args *args = state; + + size_t count = 0; + while (count < len) { + if (args->pos < args->len) { + args->outstr[args->pos++] = *str; + } + + str++; + count++; + } + + return count; +} + +int vsnprintf(char *str, size_t len, const char *fmt, va_list ap) { + struct _output_args args; + int wlen; + + args.outstr = str; + args.len = len; + args.pos = 0; + + wlen = _printf_engine(&_vsnprintf_output, (void *)&args, fmt, ap); + if (args.pos >= len) + str[len-1] = '\0'; + else + str[wlen] = '\0'; + return wlen; +} + +#define LONGFLAG 0x00000001 +#define LONGLONGFLAG 0x00000002 +#define HALFFLAG 0x00000004 +#define HALFHALFFLAG 0x00000008 +#define SIZETFLAG 0x00000010 +#define INTMAXFLAG 0x00000020 +#define PTRDIFFFLAG 0x00000040 +#define ALTFLAG 0x00000080 +#define CAPSFLAG 0x00000100 +#define SHOWSIGNFLAG 0x00000200 +#define SIGNEDFLAG 0x00000400 +#define LEFTFORMATFLAG 0x00000800 +#define LEADZEROFLAG 0x00001000 +#define BLANKPOSFLAG 0x00002000 + +#if WITH_PRINTF_LL +typedef unsigned long long x_ull_t; +typedef long long x_ll_t; +#else +typedef unsigned long x_ull_t; +typedef long x_ll_t; +#endif + +__NO_INLINE static char *longlong_to_string(char *buf, x_ull_t n, size_t len, unsigned flag, char *signchar) { + size_t pos = len; + int negative = 0; + + if ((flag & SIGNEDFLAG) && (x_ll_t)n < 0) { + negative = 1; + n = -n; + } + + buf[--pos] = 0; + + /* only do the math if the number is >= 10 */ + while (n >= 10) { + int digit = n % 10; + + n /= 10; + + buf[--pos] = digit + '0'; + } + buf[--pos] = n + '0'; + + if (negative) + *signchar = '-'; + else if ((flag & SHOWSIGNFLAG)) + *signchar = '+'; + else if ((flag & BLANKPOSFLAG)) + *signchar = ' '; + else + *signchar = '\0'; + + return &buf[pos]; +} + +static const char hextable[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' }; +static const char hextable_caps[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; + +__NO_INLINE static char *longlong_to_hexstring(char *buf, x_ull_t u, size_t len, unsigned flag) { + size_t pos = len; + const char *table = (flag & CAPSFLAG) ? hextable_caps : hextable; + + buf[--pos] = 0; + do { + unsigned int digit = u % 16; + u /= 16; + + buf[--pos] = table[digit]; + } while (u != 0); + + return &buf[pos]; +} + +#if WITH_PRINTF_FP +union double_int { + double d; + uint64_t i; +}; + +#define OUT(c) buf[pos++] = (c) +#define OUTSTR(str) do { for (size_t i = 0; (str)[i] != 0; i++) OUT((str)[i]); } while (0) + +/* print up to a 4 digit exponent as string, with sign */ +__NO_INLINE static size_t exponent_to_string(char *buf, int32_t exponent) { + size_t pos = 0; + + /* handle sign */ + if (exponent < 0) { + OUT('-'); + exponent = -exponent; + } else { + OUT('+'); + } + + /* see how far we need to bump into the string to print from the right */ + if (exponent >= 1000) pos += 4; + else if (exponent >= 100) pos += 3; + else if (exponent >= 10) pos += 2; + else pos++; + + /* print decimal string, from the right */ + unsigned i = pos; + do { + unsigned digit = (uint32_t)exponent % 10; + + buf[--i] = digit + '0'; + + exponent /= 10; + } while (exponent != 0); + + /* return number of characters printed */ + return pos; +} + +__NO_INLINE static char *double_to_string(char *buf, size_t len, double d, unsigned flag) { + size_t pos = 0; + union double_int u = { d }; + + uint32_t exponent = (u.i >> 52) & 0x7ff; + uint64_t fraction = (u.i & ((1ULL << 52) - 1)); + bool neg = !!(u.i & (1ULL << 63)); + + /* start constructing the string */ + if (neg) { + OUT('-'); + d = -d; + } + + /* longest: + * 179769313486231570814527423731704356798070567525844996598917476803157260780028538760589558632766878171540458953514382464234321326889464182768467546703537516986049910576551282076245490090389328944075868508455133942304583236903222948165808559332123348274797826204144723168738177180919299881250404026184124858368.000000o + */ + + /* look for special cases */ + if (exponent == 0x7ff) { + if (fraction == 0) { + /* infinity */ + if (flag & CAPSFLAG) OUTSTR("INF"); + else OUTSTR("inf"); + } else { + /* NaN */ + if (flag & CAPSFLAG) OUTSTR("NAN"); + else OUTSTR("nan"); + } + } else if (exponent == 0) { + if (fraction == 0) { + /* zero */ + OUTSTR("0.000000"); + } else { + /* denormalized */ + /* XXX does not handle */ + if (flag & CAPSFLAG) OUTSTR("DEN"); + else OUTSTR("den"); + } + } else { + /* see if it's in the range of floats we can easily print */ + int exponent_signed = exponent - 1023; + if (exponent_signed < -52 || exponent_signed > 52) { + OUTSTR("<range>"); + } else { + /* start by walking backwards through the string */ +#define OUTREV(c) do { if (&buf[pos] == buf) goto done; else buf[--pos] = (c); } while (0) + pos = len; + OUTREV(0); + + /* reserve space for the fractional component first */ + for (int i = 0; i <= 6; i++) + OUTREV('0'); + size_t decimal_spot = pos; + + /* print the integer portion */ + uint64_t u; + if (exponent_signed >= 0) { + u = fraction; + u |= (1ULL<<52); + u >>= (52 - exponent_signed); + + char *s = longlong_to_string(buf, u, pos + 1, flag, &(char) {0}); + + pos = s - buf; + } else { + /* exponent is negative */ + u = 0; + OUTREV('0'); + } + + buf[decimal_spot] = '.'; + + /* handle the fractional part */ + uint32_t frac = ((d - u) * 1000000) + .5; + + unsigned i = decimal_spot + 6 + 1; + while (frac != 0) { + unsigned digit = frac % 10; + + buf[--i] = digit + '0'; + + frac /= 10; + } + + if (neg) + OUTREV('-'); + +done: + /* separate return path, since we've been walking backwards through the string */ + return &buf[pos]; + } +#undef OUTREV + } + + buf[pos] = 0; + return buf; +} + +__NO_INLINE static char *double_to_hexstring(char *buf, size_t len, double d, unsigned flag) { + size_t pos = 0; + union double_int u = { d }; + + uint32_t exponent = (u.i >> 52) & 0x7ff; + uint64_t fraction = (u.i & ((1ULL << 52) - 1)); + bool neg = !!(u.i & (1ULL << 63)); + + /* start constructing the string */ + if (neg) { + OUT('-'); + } + + /* look for special cases */ + if (exponent == 0x7ff) { + if (fraction == 0) { + /* infinity */ + if (flag & CAPSFLAG) OUTSTR("INF"); + else OUTSTR("inf"); + } else { + /* NaN */ + if (flag & CAPSFLAG) OUTSTR("NAN"); + else OUTSTR("nan"); + } + } else if (exponent == 0) { + if (fraction == 0) { + /* zero */ + if (flag & CAPSFLAG) OUTSTR("0X0P+0"); + else OUTSTR("0x0p+0"); + } else { + /* denormalized */ + /* XXX does not handle */ + if (flag & CAPSFLAG) OUTSTR("DEN"); + else OUTSTR("den"); + } + } else { + /* regular normalized numbers: + * 0x1p+1 + * 0x1.0000000000001p+1 + * 0X1.FFFFFFFFFFFFFP+1023 + * 0x1.FFFFFFFFFFFFFP+1023 + */ + int exponent_signed = exponent - 1023; + + /* implicit 1. */ + if (flag & CAPSFLAG) OUTSTR("0X1"); + else OUTSTR("0x1"); + + /* select the appropriate hex case table */ + const char *table = (flag & CAPSFLAG) ? hextable_caps : hextable; + + int zero_count = 0; + bool output_dot = false; + for (int i = 52 - 4; i >= 0; i -= 4) { + unsigned digit = (fraction >> i) & 0xf; + + if (digit == 0) { + zero_count++; + } else { + /* output a . the first time we output a char */ + if (!output_dot) { + OUT('.'); + output_dot = true; + } + /* if we have a non zero digit, see if we need to output a string of zeros */ + while (zero_count > 0) { + OUT('0'); + zero_count--; + } + buf[pos++] = table[digit]; + } + } + + /* handle the exponent */ + buf[pos++] = (flag & CAPSFLAG) ? 'P' : 'p'; + pos += exponent_to_string(&buf[pos], exponent_signed); + } + + buf[pos] = 0; + return buf; +} + +#undef OUT +#undef OUTSTR + +#endif + +int _printf_engine(_printf_engine_output_func out, void *state, const char *fmt, va_list ap) { + int err = 0; + char c; + unsigned char uc; + const char *s; + size_t string_len; + x_ull_t n; + void *ptr; + int flags; + unsigned int format_num; + char signchar; + size_t chars_written = 0; + char num_buffer[32]; + +#define OUTPUT_STRING(str, len) do { err = out(str, len, state); if (err < 0) { goto exit; } else { chars_written += err; } } while(0) +#define OUTPUT_CHAR(c) do { char __temp[1] = { c }; OUTPUT_STRING(__temp, 1); } while (0) + + for (;;) { + /* reset the format state */ + flags = 0; + format_num = 0; + signchar = '\0'; + + /* handle regular chars that aren't format related */ + s = fmt; + string_len = 0; + while ((c = *fmt++) != 0) { + if (c == '%') + break; /* we saw a '%', break and start parsing format */ + string_len++; + } + + /* output the string we've accumulated */ + OUTPUT_STRING(s, string_len); + + /* make sure we haven't just hit the end of the string */ + if (c == 0) + break; + +next_format: + /* grab the next format character */ + c = *fmt++; + if (c == 0) + break; + + switch (c) { + case '0'...'9': + if (c == '0' && format_num == 0) + flags |= LEADZEROFLAG; + format_num *= 10; + format_num += c - '0'; + goto next_format; + case '.': + /* XXX for now eat numeric formatting */ + goto next_format; + case '%': + OUTPUT_CHAR('%'); + break; + case 'c': + uc = va_arg(ap, unsigned int); + OUTPUT_CHAR(uc); + break; + case 's': + s = va_arg(ap, const char *); + if (s == 0) + s = "<null>"; + flags &= ~LEADZEROFLAG; /* doesn't make sense for strings */ + goto _output_string; + case '-': + flags |= LEFTFORMATFLAG; + goto next_format; + case '+': + flags |= SHOWSIGNFLAG; + goto next_format; + case ' ': + flags |= BLANKPOSFLAG; + goto next_format; + case '#': + flags |= ALTFLAG; + goto next_format; + case 'l': + if (flags & LONGFLAG) + flags |= LONGLONGFLAG; + flags |= LONGFLAG; + goto next_format; + case 'h': + if (flags & HALFFLAG) + flags |= HALFHALFFLAG; + flags |= HALFFLAG; + goto next_format; + case 'z': + flags |= SIZETFLAG; + goto next_format; + case 'j': + flags |= INTMAXFLAG; + goto next_format; + case 't': + flags |= PTRDIFFFLAG; + goto next_format; + case 'i': + case 'd': + n = (flags & LONGLONGFLAG) ? va_arg(ap, long long) : + (flags & LONGFLAG) ? va_arg(ap, long) : + (flags & HALFHALFFLAG) ? (signed char)va_arg(ap, int) : + (flags & HALFFLAG) ? (short)va_arg(ap, int) : + //(flags & SIZETFLAG) ? va_arg(ap, ssize_t) : // no ssize_t available + (flags & INTMAXFLAG) ? va_arg(ap, intmax_t) : + (flags & PTRDIFFFLAG) ? va_arg(ap, ptrdiff_t) : + va_arg(ap, int); + flags |= SIGNEDFLAG; + s = longlong_to_string(num_buffer, n, sizeof(num_buffer), flags, &signchar); + goto _output_string; + case 'u': + n = (flags & LONGLONGFLAG) ? va_arg(ap, unsigned long long) : + (flags & LONGFLAG) ? va_arg(ap, unsigned long) : + (flags & HALFHALFFLAG) ? (unsigned char)va_arg(ap, unsigned int) : + (flags & HALFFLAG) ? (unsigned short)va_arg(ap, unsigned int) : + (flags & SIZETFLAG) ? va_arg(ap, size_t) : + (flags & INTMAXFLAG) ? va_arg(ap, uintmax_t) : + (flags & PTRDIFFFLAG) ? (uintptr_t)va_arg(ap, ptrdiff_t) : + va_arg(ap, unsigned int); + s = longlong_to_string(num_buffer, n, sizeof(num_buffer), flags, &signchar); + goto _output_string; + case 'p': + flags |= LONGFLAG | ALTFLAG; + goto hex; + case 'X': + flags |= CAPSFLAG; + /* fallthrough */ +hex: + case 'x': + n = (flags & LONGLONGFLAG) ? va_arg(ap, unsigned long long) : + (flags & LONGFLAG) ? va_arg(ap, unsigned long) : + (flags & HALFHALFFLAG) ? (unsigned char)va_arg(ap, unsigned int) : + (flags & HALFFLAG) ? (unsigned short)va_arg(ap, unsigned int) : + (flags & SIZETFLAG) ? va_arg(ap, size_t) : + (flags & INTMAXFLAG) ? va_arg(ap, uintmax_t) : + (flags & PTRDIFFFLAG) ? (uintptr_t)va_arg(ap, ptrdiff_t) : + va_arg(ap, unsigned int); + s = longlong_to_hexstring(num_buffer, n, sizeof(num_buffer), flags); + if (flags & ALTFLAG) { + OUTPUT_CHAR('0'); + OUTPUT_CHAR((flags & CAPSFLAG) ? 'X': 'x'); + } + goto _output_string; + case 'n': + ptr = va_arg(ap, void *); + if (flags & LONGLONGFLAG) + *(long long *)ptr = chars_written; + else if (flags & LONGFLAG) + *(long *)ptr = chars_written; + else if (flags & HALFHALFFLAG) + *(signed char *)ptr = chars_written; + else if (flags & HALFFLAG) + *(short *)ptr = chars_written; + else if (flags & SIZETFLAG) + *(size_t *)ptr = chars_written; + else + *(int *)ptr = chars_written; + break; +#if WITH_PRINTF_FP + case 'F': + flags |= CAPSFLAG; + /* fallthrough */ + case 'f': { + double d = va_arg(ap, double); + s = double_to_string(num_buffer, sizeof(num_buffer), d, flags); + goto _output_string; + } + case 'A': + flags |= CAPSFLAG; + /* fallthrough */ + case 'a': { + double d = va_arg(ap, double); + s = double_to_hexstring(num_buffer, sizeof(num_buffer), d, flags); + goto _output_string; + } +#endif + default: + OUTPUT_CHAR('%'); + OUTPUT_CHAR(c); + break; + } + + /* move on to the next field */ + continue; + + /* shared output code */ +_output_string: + string_len = strlen(s); + + if (flags & LEFTFORMATFLAG) { + /* left justify the text */ + OUTPUT_STRING(s, string_len); + unsigned written = err; + + /* pad to the right (if necessary) */ + for (; format_num > written; format_num--) + OUTPUT_CHAR(' '); + } else { + /* right justify the text (digits) */ + + /* if we're going to print a sign digit, + it'll chew up one byte of the format size */ + if (signchar != '\0' && format_num > 0) + format_num--; + + /* output the sign char before the leading zeros */ + if (flags & LEADZEROFLAG && signchar != '\0') + OUTPUT_CHAR(signchar); + + /* pad according to the format string */ + for (; format_num > string_len; format_num--) + OUTPUT_CHAR(flags & LEADZEROFLAG ? '0' : ' '); + + /* if not leading zeros, output the sign char just before the number */ + if (!(flags & LEADZEROFLAG) && signchar != '\0') + OUTPUT_CHAR(signchar); + + /* output the string */ + OUTPUT_STRING(s, string_len); + } + continue; + } + +#undef OUTPUT_STRING +#undef OUTPUT_CHAR + +exit: + return (err < 0) ? err : (int)chars_written; +} diff --git a/libc/src/string/memchr.c b/libc/src/string/memchr.c @@ -0,0 +1,29 @@ +/* +** Copyright 2001, Manuel J. Petit. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ +/* + * Copyright (c) 2008 Travis Geiselbrecht + * + * Use of this source code is governed by a MIT-style + * license that can be found in the LICENSE file or at + * https://opensource.org/licenses/MIT + */ +#include <string.h> +#include <stdint.h> + +void * +memchr(void const *buf, int c, size_t len) { + size_t i; + unsigned char const *b= buf; + unsigned char x= (c&0xff); + + for (i= 0; i< len; i++) { + if (b[i]== x) { + return (void *)(b+i); + } + } + + return NULL; +} + diff --git a/libc/src/string/memcmp.c b/libc/src/string/memcmp.c @@ -0,0 +1,24 @@ +/* +** Copyright 2001, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ +/* + * Copyright (c) 2008 Travis Geiselbrecht + * + * Use of this source code is governed by a MIT-style + * license that can be found in the LICENSE file or at + * https://opensource.org/licenses/MIT + */ +#include <string.h> +#include <stdint.h> + +int +memcmp(const void *cs, const void *ct, size_t count) { + const unsigned char *su1, *su2; + signed char res = 0; + + for (su1 = cs, su2 = ct; 0 < count; ++su1, ++su2, count--) + if ((res = *su1 - *su2) != 0) + break; + return res; +} diff --git a/libc/src/string/memcpy.c b/libc/src/string/memcpy.c @@ -0,0 +1,53 @@ +/* +** Copyright 2001, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ +/* + * Copyright (c) 2008 Travis Geiselbrecht + * + * Use of this source code is governed by a MIT-style + * license that can be found in the LICENSE file or at + * https://opensource.org/licenses/MIT + */ +#include <string.h> +#include <stdint.h> + + +#if !_ASM_MEMCPY + +typedef long word; + +#define lsize sizeof(word) +#define lmask (lsize - 1) + +void *memcpy(void *dest, const void *src, size_t count) { + char *d = (char *)dest; + const char *s = (const char *)src; + int len; + + if (count == 0 || dest == src) + return dest; + + if (((long)d | (long)s) & lmask) { + // src and/or dest do not align on word boundary + if ((((long)d ^ (long)s) & lmask) || (count < lsize)) + len = count; // copy the rest of the buffer with the byte mover + else + len = lsize - ((long)d & lmask); // move the ptrs up to a word boundary + + count -= len; + for (; len > 0; len--) + *d++ = *s++; + } + for (len = count / lsize; len > 0; len--) { + *(word *)d = *(word *)s; + d += lsize; + s += lsize; + } + for (len = count & lmask; len > 0; len--) + *d++ = *s++; + + return dest; +} + +#endif diff --git a/libc/src/string/memmove.c b/libc/src/string/memmove.c @@ -0,0 +1,77 @@ +/* +** Copyright 2001, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ +/* + * Copyright (c) 2008 Travis Geiselbrecht + * + * Use of this source code is governed by a MIT-style + * license that can be found in the LICENSE file or at + * https://opensource.org/licenses/MIT + */ +#include <string.h> +#include <stdint.h> + +#if !_ASM_MEMMOVE + +typedef long word; + +#define lsize sizeof(word) +#define lmask (lsize - 1) + +void * +memmove(void *dest, void const *src, size_t count) { + char *d = (char *)dest; + const char *s = (const char *)src; + int len; + + if (count == 0 || dest == src) + return dest; + + if ((long)d < (long)s) { + if (((long)d | (long)s) & lmask) { + // src and/or dest do not align on word boundary + if ((((long)d ^ (long)s) & lmask) || (count < lsize)) + len = count; // copy the rest of the buffer with the byte mover + else + len = lsize - ((long)d & lmask); // move the ptrs up to a word boundary + + count -= len; + for (; len > 0; len--) + *d++ = *s++; + } + for (len = count / lsize; len > 0; len--) { + *(word *)d = *(word *)s; + d += lsize; + s += lsize; + } + for (len = count & lmask; len > 0; len--) + *d++ = *s++; + } else { + d += count; + s += count; + if (((long)d | (long)s) & lmask) { + // src and/or dest do not align on word boundary + if ((((long)d ^ (long)s) & lmask) || (count <= lsize)) + len = count; + else + len = ((long)d & lmask); + + count -= len; + for (; len > 0; len--) + *--d = *--s; + } + for (len = count / lsize; len > 0; len--) { + d -= lsize; + s -= lsize; + *(word *)d = *(word *)s; + } + for (len = count & lmask; len > 0; len--) + *--d = *--s; + } + + return dest; +} + +#endif + diff --git a/libc/src/string/memset.c b/libc/src/string/memset.c @@ -0,0 +1,47 @@ +/* +** Copyright 2005, Michael Noisternig. All rights reserved. +** Copyright 2001, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ +/* + * Copyright (c) 2008 Travis Geiselbrecht + * + * Use of this source code is governed by a MIT-style + * license that can be found in the LICENSE file or at + * https://opensource.org/licenses/MIT + */ +#include <string.h> +#include <stdint.h> + +void * +memset(void *s, int c, size_t count) { + char *xs = (char *) s; + size_t len = (-(size_t)s) & (sizeof(size_t)-1); + size_t cc = c & 0xff; + + if ( count > len ) { + count -= len; + cc |= cc << 8; + cc |= cc << 16; + if (sizeof(size_t) == 8) + cc |= (uint64_t)cc << 32; // should be optimized out on 32 bit machines + + // write to non-aligned memory byte-wise + for ( ; len > 0; len-- ) + *xs++ = c; + + // write to aligned memory dword-wise + for ( len = count/sizeof(size_t); len > 0; len-- ) { + *((size_t *)xs) = (size_t)cc; + xs += sizeof(size_t); + } + + count &= sizeof(size_t)-1; + } + + // write remaining bytes + for ( ; count > 0; count-- ) + *xs++ = c; + + return s; +} diff --git a/libc/src/string/strcat.c b/libc/src/string/strcat.c @@ -0,0 +1,26 @@ +/* +** Copyright 2001, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ +/* + * Copyright (c) 2008 Travis Geiselbrecht + * + * Use of this source code is governed by a MIT-style + * license that can be found in the LICENSE file or at + * https://opensource.org/licenses/MIT + */ +#include <string.h> +#include <stdint.h> + +char * +strcat(char *dest, char const *src) { + char *tmp = dest; + + while (*dest) + dest++; + while ((*dest++ = *src++) != '\0') + ; + + return tmp; +} + diff --git a/libc/src/string/strchr.c b/libc/src/string/strchr.c @@ -0,0 +1,21 @@ +/* +** Copyright 2001, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ +/* + * Copyright (c) 2008 Travis Geiselbrecht + * + * Use of this source code is governed by a MIT-style + * license that can be found in the LICENSE file or at + * https://opensource.org/licenses/MIT + */ +#include <string.h> +#include <stdint.h> + +char * +strchr(const char *s, int c) { + for (; *s != (char) c; ++s) + if (*s == '\0') + return NULL; + return (char *) s; +} diff --git a/libc/src/string/strcmp.c b/libc/src/string/strcmp.c @@ -0,0 +1,25 @@ +/* +** Copyright 2001, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ +/* + * Copyright (c) 2008 Travis Geiselbrecht + * + * Use of this source code is governed by a MIT-style + * license that can be found in the LICENSE file or at + * https://opensource.org/licenses/MIT + */ +#include <string.h> +#include <stdint.h> + +int +strcmp(char const *cs, char const *ct) { + signed char __res; + + while (1) { + if ((__res = *cs - *ct++) != 0 || !*cs++) + break; + } + + return __res; +} diff --git a/libc/src/string/strcpy.c b/libc/src/string/strcpy.c @@ -0,0 +1,23 @@ +/* +** Copyright 2001, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ +/* + * Copyright (c) 2008 Travis Geiselbrecht + * + * Use of this source code is governed by a MIT-style + * license that can be found in the LICENSE file or at + * https://opensource.org/licenses/MIT + */ +#include <string.h> +#include <stdint.h> + +char * +strcpy(char *dest, char const *src) { + char *tmp = dest; + + while ((*dest++ = *src++) != '\0') + ; + return tmp; +} + diff --git a/libc/src/string/strlen.c b/libc/src/string/strlen.c @@ -0,0 +1,25 @@ +/* +** Copyright 2001, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ +/* + * Copyright (c) 2008 Travis Geiselbrecht + * + * Use of this source code is governed by a MIT-style + * license that can be found in the LICENSE file or at + * https://opensource.org/licenses/MIT + */ +#include <string.h> +#include <stdint.h> + +size_t +strlen(char const *s) { + size_t i; + + i= 0; + while (s[i]) { + i+= 1; + } + + return i; +} diff --git a/libc/src/string/strncat.c b/libc/src/string/strncat.c @@ -0,0 +1,32 @@ +/* +** Copyright 2001, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ +/* + * Copyright (c) 2008 Travis Geiselbrecht + * + * Use of this source code is governed by a MIT-style + * license that can be found in the LICENSE file or at + * https://opensource.org/licenses/MIT + */ +#include <string.h> +#include <stdint.h> + +char * +strncat(char *dest, char const *src, size_t count) { + char *tmp = dest; + + if (count > 0) { + while (*dest) + dest++; + while ((*dest++ = *src++)) { + if (--count == 0) { + *dest = '\0'; + break; + } + } + } + + return tmp; +} + diff --git a/libc/src/string/strncmp.c b/libc/src/string/strncmp.c @@ -0,0 +1,26 @@ +/* +** Copyright 2001, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ +/* + * Copyright (c) 2008 Travis Geiselbrecht + * + * Use of this source code is governed by a MIT-style + * license that can be found in the LICENSE file or at + * https://opensource.org/licenses/MIT + */ +#include <string.h> +#include <stdint.h> + +int +strncmp(char const *cs, char const *ct, size_t count) { + signed char __res = 0; + + while (count > 0) { + if ((__res = *cs - *ct++) != 0 || !*cs++) + break; + count--; + } + + return __res; +} diff --git a/libc/src/string/strncpy.c b/libc/src/string/strncpy.c @@ -0,0 +1,27 @@ +/* +** Copyright 2001, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ +/* + * Copyright (c) 2008 Travis Geiselbrecht + * + * Use of this source code is governed by a MIT-style + * license that can be found in the LICENSE file or at + * https://opensource.org/licenses/MIT + */ +#include <string.h> +#include <stdint.h> + +char * +strncpy(char *dest, char const *src, size_t count) { + char *tmp = dest; + + size_t i; + for (i = 0; i < count && (*dest++ = *src++) != '\0'; i++) + ; + for (; i < count; i++) + *dest++ = '\0'; + + return tmp; +} + diff --git a/libc/src/string/strnlen.c b/libc/src/string/strnlen.c @@ -0,0 +1,22 @@ +/* +** Copyright 2001, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ +/* + * Copyright (c) 2008 Travis Geiselbrecht + * + * Use of this source code is governed by a MIT-style + * license that can be found in the LICENSE file or at + * https://opensource.org/licenses/MIT + */ +#include <string.h> +#include <stdint.h> + +size_t +strnlen(char const *s, size_t count) { + const char *sc; + + for (sc = s; count-- && *sc != '\0'; ++sc) + ; + return sc - s; +} diff --git a/libc/src/string/strpbrk.c b/libc/src/string/strpbrk.c @@ -0,0 +1,28 @@ +/* +** Copyright 2001, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ +/* + * Copyright (c) 2008 Travis Geiselbrecht + * + * Use of this source code is governed by a MIT-style + * license that can be found in the LICENSE file or at + * https://opensource.org/licenses/MIT + */ +#include <string.h> +#include <stdint.h> + +char * +strpbrk(char const *cs, char const *ct) { + const char *sc1; + const char *sc2; + + for (sc1 = cs; *sc1 != '\0'; ++sc1) { + for (sc2 = ct; *sc2 != '\0'; ++sc2) { + if (*sc1 == *sc2) + return (char *)sc1; + } + } + + return NULL; +} diff --git a/libc/src/string/strrchr.c b/libc/src/string/strrchr.c @@ -0,0 +1,29 @@ +/* +** Copyright 2001, Manuel J. Petit. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ +/* + * Copyright (c) 2008 Travis Geiselbrecht + * + * Use of this source code is governed by a MIT-style + * license that can be found in the LICENSE file or at + * https://opensource.org/licenses/MIT + */ +#include <string.h> +#include <stdint.h> + +char * +strrchr(char const *s, int c) { + char const *last= c?0:s; + + + while (*s) { + if (*s== c) { + last= s; + } + + s+= 1; + } + + return (char *)last; +} diff --git a/libc/src/string/strspn.c b/libc/src/string/strspn.c @@ -0,0 +1,32 @@ +/* +** Copyright 2001, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ +/* + * Copyright (c) 2008 Travis Geiselbrecht + * + * Use of this source code is governed by a MIT-style + * license that can be found in the LICENSE file or at + * https://opensource.org/licenses/MIT + */ +#include <string.h> +#include <stdint.h> + +size_t +strspn(char const *s, char const *accept) { + const char *p; + const char *a; + size_t count = 0; + + for (p = s; *p != '\0'; ++p) { + for (a = accept; *a != '\0'; ++a) { + if (*p == *a) + break; + } + if (*a == '\0') + return count; + ++count; + } + + return count; +} diff --git a/libc/src/string/strstr.c b/libc/src/string/strstr.c @@ -0,0 +1,30 @@ +/* +** Copyright 2001, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ +/* + * Copyright (c) 2008 Travis Geiselbrecht + * + * Use of this source code is governed by a MIT-style + * license that can be found in the LICENSE file or at + * https://opensource.org/licenses/MIT + */ +#include <string.h> +#include <stdint.h> + +char * +strstr(char const *s1, char const *s2) { + int l1, l2; + + l2 = strlen(s2); + if (!l2) + return (char *)s1; + l1 = strlen(s1); + while (l1 >= l2) { + l1--; + if (!memcmp(s1,s2,l2)) + return (char *)s1; + s1++; + } + return NULL; +} diff --git a/libc/src/string/strtok.c b/libc/src/string/strtok.c @@ -0,0 +1,35 @@ +/* +** Copyright 2001, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ +/* + * Copyright (c) 2008 Travis Geiselbrecht + * + * Use of this source code is governed by a MIT-style + * license that can be found in the LICENSE file or at + * https://opensource.org/licenses/MIT + */ +#include <string.h> +#include <stdint.h> + +static char *___strtok = NULL; + +char * +strtok(char *s, char const *ct) { + char *sbegin, *send; + + sbegin = s ? s : ___strtok; + if (!sbegin) { + return NULL; + } + sbegin += strspn(sbegin,ct); + if (*sbegin == '\0') { + ___strtok = NULL; + return ( NULL ); + } + send = strpbrk( sbegin, ct); + if (send && *send != '\0') + *send++ = '\0'; + ___strtok = send; + return (sbegin); +}