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);
+}