Lab 1
This commit is contained in:
300
lib/printfmt.c
Normal file
300
lib/printfmt.c
Normal 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
38
lib/readline.c
Normal 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
285
lib/string.c
Normal 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);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user