This commit is contained in:
Anish Athalye
2018-08-30 15:17:20 -04:00
commit 1a83673424
46 changed files with 5904 additions and 0 deletions

300
lib/printfmt.c Normal file
View File

@@ -0,0 +1,300 @@
// Stripped-down primitive printf-style formatting routines,
// used in common by printf, sprintf, fprintf, etc.
// This code is also used by both the kernel and user programs.
#include <inc/types.h>
#include <inc/stdio.h>
#include <inc/string.h>
#include <inc/stdarg.h>
#include <inc/error.h>
/*
* Space or zero padding and a field width are supported for the numeric
* formats only.
*
* The special format %e takes an integer error code
* and prints a string describing the error.
* The integer may be positive or negative,
* so that -E_NO_MEM and E_NO_MEM are equivalent.
*/
static const char * const error_string[MAXERROR] =
{
[E_UNSPECIFIED] = "unspecified error",
[E_BAD_ENV] = "bad environment",
[E_INVAL] = "invalid parameter",
[E_NO_MEM] = "out of memory",
[E_NO_FREE_ENV] = "out of environments",
[E_FAULT] = "segmentation fault",
};
/*
* Print a number (base <= 16) in reverse order,
* using specified putch function and associated pointer putdat.
*/
static void
printnum(void (*putch)(int, void*), void *putdat,
unsigned long long num, unsigned base, int width, int padc)
{
// first recursively print all preceding (more significant) digits
if (num >= base) {
printnum(putch, putdat, num / base, base, width - 1, padc);
} else {
// print any needed pad characters before first digit
while (--width > 0)
putch(padc, putdat);
}
// then print this (the least significant) digit
putch("0123456789abcdef"[num % base], putdat);
}
// Get an unsigned int of various possible sizes from a varargs list,
// depending on the lflag parameter.
static unsigned long long
getuint(va_list *ap, int lflag)
{
if (lflag >= 2)
return va_arg(*ap, unsigned long long);
else if (lflag)
return va_arg(*ap, unsigned long);
else
return va_arg(*ap, unsigned int);
}
// Same as getuint but signed - can't use getuint
// because of sign extension
static long long
getint(va_list *ap, int lflag)
{
if (lflag >= 2)
return va_arg(*ap, long long);
else if (lflag)
return va_arg(*ap, long);
else
return va_arg(*ap, int);
}
// Main function to format and print a string.
void printfmt(void (*putch)(int, void*), void *putdat, const char *fmt, ...);
void
vprintfmt(void (*putch)(int, void*), void *putdat, const char *fmt, va_list ap)
{
register const char *p;
register int ch, err;
unsigned long long num;
int base, lflag, width, precision, altflag;
char padc;
while (1) {
while ((ch = *(unsigned char *) fmt++) != '%') {
if (ch == '\0')
return;
putch(ch, putdat);
}
// Process a %-escape sequence
padc = ' ';
width = -1;
precision = -1;
lflag = 0;
altflag = 0;
reswitch:
switch (ch = *(unsigned char *) fmt++) {
// flag to pad on the right
case '-':
padc = '-';
goto reswitch;
// flag to pad with 0's instead of spaces
case '0':
padc = '0';
goto reswitch;
// width field
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
for (precision = 0; ; ++fmt) {
precision = precision * 10 + ch - '0';
ch = *fmt;
if (ch < '0' || ch > '9')
break;
}
goto process_precision;
case '*':
precision = va_arg(ap, int);
goto process_precision;
case '.':
if (width < 0)
width = 0;
goto reswitch;
case '#':
altflag = 1;
goto reswitch;
process_precision:
if (width < 0)
width = precision, precision = -1;
goto reswitch;
// long flag (doubled for long long)
case 'l':
lflag++;
goto reswitch;
// character
case 'c':
putch(va_arg(ap, int), putdat);
break;
// error message
case 'e':
err = va_arg(ap, int);
if (err < 0)
err = -err;
if (err >= MAXERROR || (p = error_string[err]) == NULL)
printfmt(putch, putdat, "error %d", err);
else
printfmt(putch, putdat, "%s", p);
break;
// string
case 's':
if ((p = va_arg(ap, char *)) == NULL)
p = "(null)";
if (width > 0 && padc != '-')
for (width -= strnlen(p, precision); width > 0; width--)
putch(padc, putdat);
for (; (ch = *p++) != '\0' && (precision < 0 || --precision >= 0); width--)
if (altflag && (ch < ' ' || ch > '~'))
putch('?', putdat);
else
putch(ch, putdat);
for (; width > 0; width--)
putch(' ', putdat);
break;
// (signed) decimal
case 'd':
num = getint(&ap, lflag);
if ((long long) num < 0) {
putch('-', putdat);
num = -(long long) num;
}
base = 10;
goto number;
// unsigned decimal
case 'u':
num = getuint(&ap, lflag);
base = 10;
goto number;
// (unsigned) octal
case 'o':
// Replace this with your code.
putch('X', putdat);
putch('X', putdat);
putch('X', putdat);
break;
// pointer
case 'p':
putch('0', putdat);
putch('x', putdat);
num = (unsigned long long)
(uintptr_t) va_arg(ap, void *);
base = 16;
goto number;
// (unsigned) hexadecimal
case 'x':
num = getuint(&ap, lflag);
base = 16;
number:
printnum(putch, putdat, num, base, width, padc);
break;
// escaped '%' character
case '%':
putch(ch, putdat);
break;
// unrecognized escape sequence - just print it literally
default:
putch('%', putdat);
for (fmt--; fmt[-1] != '%'; fmt--)
/* do nothing */;
break;
}
}
}
void
printfmt(void (*putch)(int, void*), void *putdat, const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
vprintfmt(putch, putdat, fmt, ap);
va_end(ap);
}
struct sprintbuf {
char *buf;
char *ebuf;
int cnt;
};
static void
sprintputch(int ch, struct sprintbuf *b)
{
b->cnt++;
if (b->buf < b->ebuf)
*b->buf++ = ch;
}
int
vsnprintf(char *buf, int n, const char *fmt, va_list ap)
{
struct sprintbuf b = {buf, buf+n-1, 0};
if (buf == NULL || n < 1)
return -E_INVAL;
// print the string to the buffer
vprintfmt((void*)sprintputch, &b, fmt, ap);
// null terminate the buffer
*b.buf = '\0';
return b.cnt;
}
int
snprintf(char *buf, int n, const char *fmt, ...)
{
va_list ap;
int rc;
va_start(ap, fmt);
rc = vsnprintf(buf, n, fmt, ap);
va_end(ap);
return rc;
}

38
lib/readline.c Normal file
View File

@@ -0,0 +1,38 @@
#include <inc/stdio.h>
#include <inc/error.h>
#define BUFLEN 1024
static char buf[BUFLEN];
char *
readline(const char *prompt)
{
int i, c, echoing;
if (prompt != NULL)
cprintf("%s", prompt);
i = 0;
echoing = iscons(0);
while (1) {
c = getchar();
if (c < 0) {
cprintf("read error: %e\n", c);
return NULL;
} else if ((c == '\b' || c == '\x7f') && i > 0) {
if (echoing)
cputchar('\b');
i--;
} else if (c >= ' ' && i < BUFLEN-1) {
if (echoing)
cputchar(c);
buf[i++] = c;
} else if (c == '\n' || c == '\r') {
if (echoing)
cputchar('\n');
buf[i] = 0;
return buf;
}
}
}

285
lib/string.c Normal file
View File

@@ -0,0 +1,285 @@
// Basic string routines. Not hardware optimized, but not shabby.
#include <inc/string.h>
// Using assembly for memset/memmove
// makes some difference on real hardware,
// but it makes an even bigger difference on bochs.
// Primespipe runs 3x faster this way.
#define ASM 1
int
strlen(const char *s)
{
int n;
for (n = 0; *s != '\0'; s++)
n++;
return n;
}
int
strnlen(const char *s, size_t size)
{
int n;
for (n = 0; size > 0 && *s != '\0'; s++, size--)
n++;
return n;
}
char *
strcpy(char *dst, const char *src)
{
char *ret;
ret = dst;
while ((*dst++ = *src++) != '\0')
/* do nothing */;
return ret;
}
char *
strcat(char *dst, const char *src)
{
int len = strlen(dst);
strcpy(dst + len, src);
return dst;
}
char *
strncpy(char *dst, const char *src, size_t size) {
size_t i;
char *ret;
ret = dst;
for (i = 0; i < size; i++) {
*dst++ = *src;
// If strlen(src) < size, null-pad 'dst' out to 'size' chars
if (*src != '\0')
src++;
}
return ret;
}
size_t
strlcpy(char *dst, const char *src, size_t size)
{
char *dst_in;
dst_in = dst;
if (size > 0) {
while (--size > 0 && *src != '\0')
*dst++ = *src++;
*dst = '\0';
}
return dst - dst_in;
}
int
strcmp(const char *p, const char *q)
{
while (*p && *p == *q)
p++, q++;
return (int) ((unsigned char) *p - (unsigned char) *q);
}
int
strncmp(const char *p, const char *q, size_t n)
{
while (n > 0 && *p && *p == *q)
n--, p++, q++;
if (n == 0)
return 0;
else
return (int) ((unsigned char) *p - (unsigned char) *q);
}
// Return a pointer to the first occurrence of 'c' in 's',
// or a null pointer if the string has no 'c'.
char *
strchr(const char *s, char c)
{
for (; *s; s++)
if (*s == c)
return (char *) s;
return 0;
}
// Return a pointer to the first occurrence of 'c' in 's',
// or a pointer to the string-ending null character if the string has no 'c'.
char *
strfind(const char *s, char c)
{
for (; *s; s++)
if (*s == c)
break;
return (char *) s;
}
#if ASM
void *
memset(void *v, int c, size_t n)
{
char *p;
if (n == 0)
return v;
if ((int)v%4 == 0 && n%4 == 0) {
c &= 0xFF;
c = (c<<24)|(c<<16)|(c<<8)|c;
asm volatile("cld; rep stosl\n"
:: "D" (v), "a" (c), "c" (n/4)
: "cc", "memory");
} else
asm volatile("cld; rep stosb\n"
:: "D" (v), "a" (c), "c" (n)
: "cc", "memory");
return v;
}
void *
memmove(void *dst, const void *src, size_t n)
{
const char *s;
char *d;
s = src;
d = dst;
if (s < d && s + n > d) {
s += n;
d += n;
if ((int)s%4 == 0 && (int)d%4 == 0 && n%4 == 0)
asm volatile("std; rep movsl\n"
:: "D" (d-4), "S" (s-4), "c" (n/4) : "cc", "memory");
else
asm volatile("std; rep movsb\n"
:: "D" (d-1), "S" (s-1), "c" (n) : "cc", "memory");
// Some versions of GCC rely on DF being clear
asm volatile("cld" ::: "cc");
} else {
if ((int)s%4 == 0 && (int)d%4 == 0 && n%4 == 0)
asm volatile("cld; rep movsl\n"
:: "D" (d), "S" (s), "c" (n/4) : "cc", "memory");
else
asm volatile("cld; rep movsb\n"
:: "D" (d), "S" (s), "c" (n) : "cc", "memory");
}
return dst;
}
#else
void *
memset(void *v, int c, size_t n)
{
char *p;
int m;
p = v;
m = n;
while (--m >= 0)
*p++ = c;
return v;
}
void *
memmove(void *dst, const void *src, size_t n)
{
const char *s;
char *d;
s = src;
d = dst;
if (s < d && s + n > d) {
s += n;
d += n;
while (n-- > 0)
*--d = *--s;
} else
while (n-- > 0)
*d++ = *s++;
return dst;
}
#endif
void *
memcpy(void *dst, const void *src, size_t n)
{
return memmove(dst, src, n);
}
int
memcmp(const void *v1, const void *v2, size_t n)
{
const uint8_t *s1 = (const uint8_t *) v1;
const uint8_t *s2 = (const uint8_t *) v2;
while (n-- > 0) {
if (*s1 != *s2)
return (int) *s1 - (int) *s2;
s1++, s2++;
}
return 0;
}
void *
memfind(const void *s, int c, size_t n)
{
const void *ends = (const char *) s + n;
for (; s < ends; s++)
if (*(const unsigned char *) s == (unsigned char) c)
break;
return (void *) s;
}
long
strtol(const char *s, char **endptr, int base)
{
int neg = 0;
long val = 0;
// gobble initial whitespace
while (*s == ' ' || *s == '\t')
s++;
// plus/minus sign
if (*s == '+')
s++;
else if (*s == '-')
s++, neg = 1;
// hex or octal base prefix
if ((base == 0 || base == 16) && (s[0] == '0' && s[1] == 'x'))
s += 2, base = 16;
else if (base == 0 && s[0] == '0')
s++, base = 8;
else if (base == 0)
base = 10;
// digits
while (1) {
int dig;
if (*s >= '0' && *s <= '9')
dig = *s - '0';
else if (*s >= 'a' && *s <= 'z')
dig = *s - 'a' + 10;
else if (*s >= 'A' && *s <= 'Z')
dig = *s - 'A' + 10;
else
break;
if (dig >= base)
break;
s++, val = (val * base) + dig;
// we don't properly detect overflow!
}
if (endptr)
*endptr = (char *) s;
return (neg ? -val : val);
}