FreeCalypso > hg > fc-selenite
changeset 86:425ab6d987f3
src/libsys: pieced together from Citrine
author | Mychaela Falconia <falcon@freecalypso.org> |
---|---|
date | Fri, 20 Jul 2018 20:36:19 +0000 |
parents | 4ef6808ea50e |
children | 727aad1c308f |
files | src/libsys/bzero.S src/libsys/rand.c src/libsys/sprintf/defs.h src/libsys/sprintf/float.c src/libsys/sprintf/integer.c src/libsys/sprintf/sprintf.c src/libsys/sprintf/vspcore.c src/libsys/strtok.c |
diffstat | 8 files changed, 639 insertions(+), 0 deletions(-) [+] |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/libsys/bzero.S Fri Jul 20 20:36:19 2018 +0000 @@ -0,0 +1,56 @@ +/* + * This ARM implementation of bzero() has been derived from: + * + * linux/arch/arm/lib/memzero.S + * + * Copyright (C) 1995-2000 Russell King + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + + .text + .code 32 + .globl bzero + +/* + * Align the pointer in r0. r3 contains the number of bytes that we are + * mis-aligned by, and r1 is the number of bytes. If r1 < 4, then we + * don't bother; we use byte stores instead. + */ +1: subs r1, r1, #4 @ 1 do we have enough + blt 5f @ 1 bytes to align with? + cmp r3, #2 @ 1 + strltb r2, [r0], #1 @ 1 + strleb r2, [r0], #1 @ 1 + strb r2, [r0], #1 @ 1 + add r1, r1, r3 @ 1 (r1 = r1 - (4 - r3)) +/* + * The pointer is now aligned and the length is adjusted. Try doing the + * bzero again. + */ + +bzero: + mov r2, #0 @ 1 + ands r3, r0, #3 @ 1 unaligned? + bne 1b @ 1 +/* + * r3 = 0, and we know that the pointer in r0 is aligned to a word boundary. + */ +3: subs r1, r1, #4 + strge r2, [r0], #4 + bgt 3b @ 1 + bxeq lr @ 1/2 quick exit +/* + * No need to correct the count; we're only testing bits from now on + * + * When we get here, we've got less than 4 bytes to zero. We + * may have an unaligned pointer as well. + */ +5: tst r1, #2 @ 1 2 bytes or more? + strneb r2, [r0], #1 @ 1 + strneb r2, [r0], #1 @ 1 + tst r1, #1 @ 1 a byte left over + strneb r2, [r0], #1 @ 1 + bx lr @ 1
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/libsys/rand.c Fri Jul 20 20:36:19 2018 +0000 @@ -0,0 +1,32 @@ +/* + * This version of rand() has been lifted from Ancient UNIX, and modified + * to match the version used in TI's TCS211 GSM firmware, as revealed by + * disassembly of rand.obj in the rts16le_flash.lib binary library used + * by that semi-src package. TI's version (most likely from their compiler + * tools group, rather than the GSM fw group, but who knows) uses the + * same trivial implementation of rand() as the original Ancient UNIX libc, + * but with one change: TI's return value is right-shifted by 16 bits + * compared to what the Ancient UNIX rand() would have returned. + * The caller thus gets back only 15 pseudo-random bits rather than 31, + * but then the lower bits of the original rand() return value are + * known to be pretty bad. + * + * rand() is used by some FFS code in reclaim.c. If we don't provide our + * own version of rand() and let the linker pull the version from newlib, + * the link fails because the latter uses malloc. This ancient implementation + * of rand() is quite poor, but my plan is to look into possibly adopting + * some better PRNG after we get the basic TI GSM firmware reintegrated. + */ + +static long randx = 1; + +srand(x) +unsigned x; +{ + randx = x; +} + +rand() +{ + return ((randx = randx * 1103515245 + 12345) & 0x7fffffff) >> 16; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/libsys/sprintf/defs.h Fri Jul 20 20:36:19 2018 +0000 @@ -0,0 +1,20 @@ +/* + * Embedded [v]sprintf() implementation by Mychaela Falconia, + * loosely based on the 4.3BSD-Tahoe version. + * + * This header file contains some internal definitions used by + * different pieces of what used to be one giant _doprnt() + * function/module. + */ + +#define todigit(c) ((c) - '0') +#define tochar(n) ((n) + '0') + +#define LONGINT 0x01 /* long integer */ +#define LONGDBL 0x02 /* long double; unimplemented */ +#define SHORTINT 0x04 /* short integer */ +#define ALT 0x08 /* alternate form */ +#define LADJUST 0x10 /* left adjustment */ +#define ZEROPAD 0x20 /* zero (as opposed to blank) pad */ +#define HEXPREFIX 0x40 /* add 0x or 0X prefix */ +#define UPPERCASE 0x80 /* uppercase forms */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/libsys/sprintf/float.c Fri Jul 20 20:36:19 2018 +0000 @@ -0,0 +1,122 @@ +/* + * Embedded [v]sprintf() implementation by Mychaela Falconia, + * loosely based on the 4.3BSD-Tahoe version. + * + * This module contains the floating point conversion functions. + */ + +#include <sys/types.h> +#include <ctype.h> +#include "defs.h" + +extern double modf(); + +extern u_char * _sprintf_field(u_char *op, int width, int flags, int sign, + u_char *body, int size, int dprec, int fpprec); + +#define MAX_INT_DIGITS 10 /* 2^32-1 in decimal */ +#define MAXFRACT 16 /* max sensible for 64-bit double */ +#define DEFPREC 6 + +static char * +emit_integer_portion(unsigned number, char *endp) +{ + char *t = endp; + + do { + *--t = tochar(number % 10); + number /= 10; + } while (number); + return (t); +} + +static int +f_round(double fract, char *start, char *end, int sign) +{ + double tmp; + + (void)modf(fract * 10, &tmp); + if (tmp > 4) + for (;; --end) { + if (*end == '.') + --end; + if (++*end <= '9') + break; + *end = '0'; + if (end == start) { + *--end = '1'; + return(1); + } + } + /* ``"%.3f", (double)-0.0004'' gives you a negative 0. */ + else if (sign == '-') + for (;; --end) { + if (*end == '.') + --end; + if (*end != '0') + break; + if (end == start) + return(-1); /* clear the -ve */ + } + return(0); +} + +u_char * +_sprintf_percent_f(u_char *op, int width, int flags, int sign, + double number, int prec) +{ + char buf[MAX_INT_DIGITS + 1 + MAXFRACT]; + int extra_prec = 0; + int origsign = sign; + int round_stat; + double fract, tmp; + char *start, *t; + + /* first order of business: weed out infinities and NaNs */ + if (isinf(number)) { + if (number < 0) + sign = '-'; + return _sprintf_field(op, width, flags, sign, "Inf", 3, 0, 0); + } + if (isnan(number)) + return _sprintf_field(op, width, flags, sign, "NaN", 3, 0, 0); + /* OK, we know it's a valid real like in the good old VAX days */ + if (number < 0) { + sign = '-'; + number = -number; + } + fract = modf(number, &tmp); + if (tmp > (double) 0xFFFFFFFF) + return _sprintf_field(op, width, flags, sign, "Toobig", 6, + 0, 0); + start = emit_integer_portion((unsigned) tmp, buf + MAX_INT_DIGITS); + if (prec > MAXFRACT) { + extra_prec = prec - MAXFRACT; + prec = MAXFRACT; + } else if (prec == -1) + prec = DEFPREC; + t = buf + MAX_INT_DIGITS; + /* + * if precision required or alternate flag set, add in a + * decimal point. + */ + if (prec || flags&ALT) + *t++ = '.'; + /* if requires more precision and some fraction left */ + if (fract) { + if (prec) + do { + fract = modf(fract * 10, &tmp); + *t++ = tochar((int)tmp); + } while (--prec && fract); + if (fract) { + round_stat = f_round(fract, start, t - 1, sign); + if (round_stat == 1) + start--; + else if (round_stat == -1) + sign = origsign; + } + } + return _sprintf_field(op, width, flags, sign, start, t - start, + 0, prec + extra_prec); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/libsys/sprintf/integer.c Fri Jul 20 20:36:19 2018 +0000 @@ -0,0 +1,54 @@ +/* + * Embedded [v]sprintf() implementation by Mychaela Falconia, + * loosely based on the 4.3BSD-Tahoe version. + * + * This module contains the integer conversion functions. + */ + +#include <sys/types.h> +#include <ctype.h> +#include "defs.h" + +extern u_char * _sprintf_field(u_char *op, int width, int flags, int sign, + u_char *body, int size, int dprec, int fpprec); + +static const char lcdigits[] = "0123456789abcdef"; +static const char ucdigits[] = "0123456789ABCDEF"; + +u_char * +_sprintf_integer(u_char *op, int width, int flags, int sign, + unsigned number, int base, int prec) +{ + const char *digits; + char buf[12]; + char *t, *endp; + + /* + * ``... diouXx conversions ... if a precision is + * specified, the 0 flag will be ignored.'' + * -- ANSI X3J11 + */ + if (prec >= 0) + flags &= ~ZEROPAD; + + if (flags & UPPERCASE) + digits = ucdigits; + else + digits = lcdigits; + + /* + * ``The result of converting a zero value with an + * explicit precision of zero is no characters.'' + * -- ANSI X3J11 + */ + t = endp = buf + sizeof(buf); + if (number != 0 || prec != 0) { + do { + *--t = digits[number % base]; + number /= base; + } while (number); + if (flags & ALT && base == 8 && *t != '0') + *--t = '0'; /* octal leading 0 */ + } + return _sprintf_field(op, width, flags, sign, t, endp - t, prec, 0); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/libsys/sprintf/sprintf.c Fri Jul 20 20:36:19 2018 +0000 @@ -0,0 +1,13 @@ +#include <stdarg.h> + +int +sprintf(char *strdest, char *fmt, ...) +{ + va_list ap; + int len; + + va_start(ap, fmt); + len = vsprintf(strdest, fmt, ap); + va_end(ap); + return(len); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/libsys/sprintf/vspcore.c Fri Jul 20 20:36:19 2018 +0000 @@ -0,0 +1,285 @@ +/* + * Embedded [v]sprintf() implementation by Mychaela Falconia, + * loosely based on the 4.3BSD-Tahoe version. + * + * This module contains the core of the vsprintf() function, which may + * be either used directly by user code or called by the sprintf() + * trivial wrapper. + */ + +#include <sys/types.h> +#include <ctype.h> +#include <stdarg.h> +#include "defs.h" + +extern u_char * _sprintf_integer(u_char *op, int width, int flags, int sign, + unsigned number, int base, int prec); +extern u_char * _sprintf_percent_f(u_char *op, int width, int flags, int sign, + double number, int prec); + +u_char * +_sprintf_field(u_char *op, int width, int flags, int sign, + u_char *body, int size, int dprec, int fpprec) +{ + int fieldsz; /* field size expanded by sign, etc */ + int realsz; /* field size expanded by decimal precision */ + int n; /* scratch */ + + /* + * All reasonable formats wind up here. At this point, + * `body' points to a string which (if not flags&LADJUST) + * should be padded out to `width' places. If + * flags&ZEROPAD, it should first be prefixed by any + * sign or other prefix; otherwise, it should be blank + * padded before the prefix is emitted. After any + * left-hand padding and prefixing, emit zeroes + * required by a decimal [diouxX] precision, then print + * the string proper, then emit zeroes required by any + * leftover floating precision; finally, if LADJUST, + * pad with blanks. + */ + + /* + * compute actual size, so we know how much to pad + * fieldsz excludes decimal prec; realsz includes it + */ + fieldsz = size + fpprec; + if (sign) + fieldsz++; + if (flags & HEXPREFIX) + fieldsz += 2; + realsz = dprec > fieldsz ? dprec : fieldsz; + + /* right-adjusting blank padding */ + if ((flags & (LADJUST|ZEROPAD)) == 0 && width) + for (n = realsz; n < width; n++) + *op++ = ' '; + /* prefix */ + if (sign) + *op++ = sign; + if (flags & HEXPREFIX) { + *op++ = '0'; + *op++ = (flags & UPPERCASE) ? 'X' : 'x'; + } + /* right-adjusting zero padding */ + if ((flags & (LADJUST|ZEROPAD)) == ZEROPAD) + for (n = realsz; n < width; n++) + *op++ = '0'; + /* leading zeroes from decimal precision */ + for (n = fieldsz; n < dprec; n++) + *op++ = '0'; + + /* the string or number proper */ + bcopy(body, op, size); + op += size; + /* trailing f.p. zeroes */ + while (--fpprec >= 0) + *op++ = '0'; + /* left-adjusting padding (always blank) */ + if (flags & LADJUST) + for (n = realsz; n < width; n++) + *op++ = ' '; + + return(op); +} + +int +vsprintf(buf0, fmt0, argp) + u_char *buf0, *fmt0; + va_list argp; +{ + u_char *op; /* output buffer working ptr */ + u_char *fmt; /* format string working ptr */ + int ch; /* character from fmt */ + int n; /* scratch integer */ + char *t; /* scratch pointer */ + int flags; /* flags as above */ + int prec; /* precision from format (%.3d), or -1 */ + int width; /* width from format (%8d), or 0 */ + char sign; /* sign prefix (' ', '+', '-', or \0) */ + unsigned un; /* unsigned number for conversion */ + + op = buf0; + for (fmt = fmt0; ; ++fmt) { + for (; (ch = *fmt) && ch != '%'; ++fmt) + *op++ = ch; + if (!ch) { +out: *op = '\0'; + return (op - buf0); + } + + flags = 0; width = 0; + prec = -1; + sign = '\0'; + +rflag: switch (*++fmt) { + case ' ': + /* + * ``If the space and + flags both appear, the space + * flag will be ignored.'' + * -- ANSI X3J11 + */ + if (!sign) + sign = ' '; + goto rflag; + case '#': + flags |= ALT; + goto rflag; + case '*': + /* + * ``A negative field width argument is taken as a + * - flag followed by a positive field width.'' + * -- ANSI X3J11 + * They don't exclude field widths read from args. + */ + if ((width = va_arg(argp, int)) >= 0) + goto rflag; + width = -width; + /* FALLTHROUGH */ + case '-': + flags |= LADJUST; + goto rflag; + case '+': + sign = '+'; + goto rflag; + case '.': + if (*++fmt == '*') + n = va_arg(argp, int); + else { + n = 0; + while (isascii(*fmt) && isdigit(*fmt)) + n = 10 * n + todigit(*fmt++); + --fmt; + } + prec = n < 0 ? -1 : n; + goto rflag; + case '0': + /* + * ``Note that 0 is taken as a flag, not as the + * beginning of a field width.'' + * -- ANSI X3J11 + */ + flags |= ZEROPAD; + goto rflag; + case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + n = 0; + do { + n = 10 * n + todigit(*fmt); + } while (isascii(*++fmt) && isdigit(*fmt)); + width = n; + --fmt; + goto rflag; + case 'L': + flags |= LONGDBL; + goto rflag; + case 'h': + flags |= SHORTINT; + goto rflag; + case 'l': + flags |= LONGINT; + goto rflag; + case 'c': + /* + * XXX reusing a variable of type char + * for an unrelated purpose + */ + sign = (char) va_arg(argp, int); + op = _sprintf_field(op, width, flags, 0, &sign, 1, + 0, 0); + break; + case 'D': + flags |= LONGINT; + /*FALLTHROUGH*/ + case 'd': + case 'i': + n = va_arg(argp, int); + if (n < 0) { + un = -n; + sign = '-'; + } else + un = n; + op = _sprintf_integer(op, width, flags, sign, un, 10, + prec); + break; + case 'f': + op = _sprintf_percent_f(op, width, flags, sign, + va_arg(argp, double), prec); + break; + case 'n': + n = op - buf0; + if (flags & LONGINT) + *va_arg(argp, long *) = n; + else if (flags & SHORTINT) + *va_arg(argp, short *) = n; + else + *va_arg(argp, int *) = n; + break; + case 'O': + flags |= LONGINT; + /*FALLTHROUGH*/ + case 'o': + un = va_arg(argp, unsigned); + op = _sprintf_integer(op, width, flags, 0, un, 8, prec); + break; + case 'p': + /* + * ``The argument shall be a pointer to void. The + * value of the pointer is converted to a sequence + * of printable characters, in an implementation- + * defined manner.'' + * -- ANSI X3J11 + */ + /* NOSTRICT */ + un = (unsigned)va_arg(argp, void *); + op = _sprintf_integer(op, width, flags | HEXPREFIX, 0, + un, 16, prec); + break; + case 's': + if (!(t = va_arg(argp, char *))) + t = "(null)"; + if (prec >= 0) { + /* + * can't use strlen; can only look for the + * NUL in the first `prec' characters, and + * strlen() will go further. + */ + char *p, *memchr(); + + if (p = memchr(t, 0, prec)) { + n = p - t; + if (n > prec) + n = prec; + } else + n = prec; + } else + n = strlen(t); + op = _sprintf_field(op, width, flags, 0, t, n, 0, 0); + break; + case 'U': + flags |= LONGINT; + /*FALLTHROUGH*/ + case 'u': + un = va_arg(argp, unsigned); + op = _sprintf_integer(op, width, flags, 0, un, 10, + prec); + break; + case 'X': + flags |= UPPERCASE; + /* FALLTHROUGH */ + case 'x': + un = va_arg(argp, unsigned); + /* leading 0x/X only if non-zero */ + if (flags & ALT && un != 0) + flags |= HEXPREFIX; + op = _sprintf_integer(op, width, flags, 0, un, 16, + prec); + break; + case '\0': /* "%?" prints ?, unless ? is NULL */ + goto out; + default: + *op++ = *fmt; + } + } + /* NOTREACHED */ +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/libsys/strtok.c Fri Jul 20 20:36:19 2018 +0000 @@ -0,0 +1,57 @@ +/* + * Copyright (c) 1985 Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms are permitted + * provided that the above copyright notice and this paragraph are + * duplicated in all such forms and that any documentation, + * advertising materials, and other materials related to such + * distribution and use acknowledge that the software was developed + * by the University of California, Berkeley. The name of the + * University may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)strtok.c 5.4 (Berkeley) 6/27/88"; +#endif /* LIBC_SCCS and not lint */ + +char * +strtok(s, sep) + register char *s, *sep; +{ + register char *p; + register c; + static char *lasts; + + if (s == 0) + s = lasts; + if (s == 0) + return (0); + + while (c = *s) { + if (!index(sep, c)) + break; + s++; + } + + if (c == '\0') { + lasts = 0; + return (0); + } + + for (p = s; c = *++p; ) + if (index(sep, c)) + break; + + if (c == '\0') + lasts = 0; + else { + *p++ = '\0'; + lasts = p; + } + return (s); +}