This commit is contained in:
Murphy 2025-04-03 12:30:34 -04:00
parent 4d0603e8e5
commit ec3c37d1d4
Signed by: freya
GPG key ID: 9FBC6FFD6D2DBF17
41 changed files with 911 additions and 1321 deletions

30
lib/atox.c Normal file
View file

@ -0,0 +1,30 @@
#include <stdlib.h>
#include <ctype.h>
#define ATOX(name, type) \
type name(const char *s) \
{ \
for (; isspace(*s); s++) \
; \
int neg = 0; \
switch (*s) { \
case '-': \
neg = 1; \
/* fallthrough */ \
case '+': \
s++; \
break; \
} \
type num = 0; \
for (; *s == '0'; s++) \
; \
for (; isdigit(*s); s++) { \
num *= 10; \
num += *s - '0'; \
} \
return num * (neg ? -1 : 1); \
}
ATOX(atoi, int)
ATOX(atol, long int)
ATOX(atoll, long long int)

View file

@ -1,57 +0,0 @@
/**
** @file blkmov.c
**
** @author Numerous CSCI-452 classes
**
** @brief C implementations of common library functions
*/
#ifndef BLKMOV_SRC_INC
#define BLKMOV_SRC_INC
#include <common.h>
#include <lib.h>
/**
** blkmov(dst,src,len)
**
** Copy a word-aligned block from src to dst. Deals with overlapping
** buffers.
**
** @param dst Destination buffer
** @param src Source buffer
** @param len Buffer size (in bytes)
*/
void blkmov(void *dst, const void *src, register uint32_t len)
{
// verify that the addresses are aligned and
// the length is a multiple of four bytes
if ((((uint32_t)dst) & 0x3) != 0 || (((uint32_t)src) & 0x3) != 0 ||
(len & 0x3) != 0) {
// something isn't aligned, so just use memmove()
memmove(dst, src, len);
return;
}
// everything is nicely aligned, so off we go
register uint32_t *dest = dst;
register const uint32_t *source = src;
// now copying 32-bit values
len /= 4;
if (source < dest && (source + len) > dest) {
source += len;
dest += len;
while (len-- > 0) {
*--dest = *--source;
}
} else {
while (len--) {
*dest++ = *source++;
}
}
}
#endif

View file

@ -1,30 +1,6 @@
/**
** @file bound.c
**
** @author Numerous CSCI-452 classes
**
** @brief C implementations of common library functions
*/
#include <stdlib.h>
#ifndef BOUND_SRC_INC
#define BOUND_SRC_INC
#include <common.h>
#include <lib.h>
/**
** bound(min,value,max)
**
** This function confines an argument within specified bounds.
**
** @param min Lower bound
** @param value Value to be constrained
** @param max Upper bound
**
** @return The constrained value
*/
uint32_t bound(uint32_t min, uint32_t value, uint32_t max)
unsigned int bound(unsigned int min, unsigned int value, unsigned int max)
{
if (value < min) {
value = min;
@ -34,5 +10,3 @@ uint32_t bound(uint32_t min, uint32_t value, uint32_t max)
}
return value;
}
#endif

43
lib/btoa.c Normal file
View file

@ -0,0 +1,43 @@
#include <stdlib.h>
static char suffixes[] = { 'K', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y', 'R', 'Q' };
char *btoa(size_t bytes, char *buf)
{
// no suffix if under 1K, print up to four digits
if (bytes < 1024) {
ultoa(bytes, buf, 10);
return buf;
}
// store one digit of remainder for decimal
unsigned int remainder;
// power of 1024
int power = 0;
// iterate until remaining bytes fits in three digits
while (bytes >= 1000) {
remainder = (bytes % 1024) * 10 / 1024;
bytes /= 1024;
power += 1;
}
// end of number
char *end;
if (bytes >= 10) {
// no decimal
end = ultoa(bytes, buf, 10);
} else {
// decimal
end = ultoa(bytes, buf, 10);
end[0] = '.';
end = ultoa(remainder, end + 1, 10);
}
// add suffix
end[0] = suffixes[power - 1];
end[1] = '\0';
return buf;
}

14
lib/ctoi.c Normal file
View file

@ -0,0 +1,14 @@
#include <stdlib.h>
int ctoi(char c)
{
if (c >= '0' && c <= '9') {
return c - '0';
} else if (c >= 'A' && c <= 'Z') {
return c - 'A' + 10;
} else if (c >= 'a' && c <= 'z') {
return c - 'a' + 10;
} else {
return -1;
}
}

View file

@ -1,44 +0,0 @@
/**
** @file cvtdec.c
**
** @author Numerous CSCI-452 classes
**
** @brief C implementations of common library functions
*/
#ifndef CVTDEC_SRC_INC
#define CVTDEC_SRC_INC
#include <common.h>
#include <lib.h>
/**
** cvtdec(buf,value)
**
** convert a 32-bit signed value into a NUL-terminated character string
**
** @param buf Destination buffer
** @param value Value to convert
**
** @return The number of characters placed into the buffer
** (not including the NUL)
**
** NOTE: assumes buf is large enough to hold the resulting string
*/
int cvtdec(char *buf, int32_t value)
{
char *bp = buf;
if (value < 0) {
*bp++ = '-';
value = -value;
}
bp = cvtdec0(bp, value);
*bp = '\0';
return (bp - buf);
}
#endif

View file

@ -1,45 +0,0 @@
/**
** @file cvtdec0.c
**
** @author Numerous CSCI-452 classes
**
** @brief C implementations of common library functions
*/
#ifndef CVTDEC0_SRC_INC
#define CVTDEC0_SRC_INC
#include <common.h>
#include <lib.h>
/**
** cvtdec0(buf,value) - local support routine for cvtdec()
**
** convert a 32-bit unsigned integer into a NUL-terminated character string
**
** @param buf Destination buffer
** @param value Value to convert
**
** @return The number of characters placed into the buffer
** (not including the NUL)
**
** NOTE: assumes buf is large enough to hold the resulting string
*/
char *cvtdec0(char *buf, int value)
{
int quotient;
quotient = value / 10;
if (quotient < 0) {
quotient = 214748364;
value = 8;
}
if (quotient != 0) {
buf = cvtdec0(buf, quotient);
}
*buf++ = value % 10 + '0';
return buf;
}
#endif

View file

@ -1,50 +0,0 @@
/**
** @file cvthex.c
**
** @author Numerous CSCI-452 classes
**
** @brief C implementations of common library functions
*/
#ifndef CVTHEX_SRC_INC
#define CVTHEX_SRC_INC
#include <common.h>
#include <lib.h>
/**
** cvthex(buf,value)
**
** convert a 32-bit unsigned value into a minimal-length (up to
** 8-character) NUL-terminated character string
**
** @param buf Destination buffer
** @param value Value to convert
**
** @return The number of characters placed into the buffer
** (not including the NUL)
**
** NOTE: assumes buf is large enough to hold the resulting string
*/
int cvthex(char *buf, uint32_t value)
{
const char hexdigits[] = "0123456789ABCDEF";
int chars_stored = 0;
for (int i = 0; i < 8; i += 1) {
uint32_t val = value & 0xf0000000;
if (chars_stored || val != 0 || i == 7) {
++chars_stored;
val = (val >> 28) & 0xf;
*buf++ = hexdigits[val];
}
value <<= 4;
}
*buf = '\0';
return (chars_stored);
}
#endif

View file

@ -1,54 +0,0 @@
/**
** @file cvtoct.c
**
** @author Numerous CSCI-452 classes
**
** @brief C implementations of common library functions
*/
#ifndef CVTOCT_SRC_INC
#define CVTOCT_SRC_INC
#include <common.h>
#include <lib.h>
/**
** cvtoct(buf,value)
**
** convert a 32-bit unsigned value into a mininal-length (up to
** 11-character) NUL-terminated character string
**
** @param buf Destination buffer
** @param value Value to convert
**
** @return The number of characters placed into the buffer
** (not including the NUL)
**
** NOTE: assumes buf is large enough to hold the resulting string
*/
int cvtoct(char *buf, uint32_t value)
{
int i;
int chars_stored = 0;
char *bp = buf;
uint32_t val;
val = (value & 0xc0000000);
val >>= 30;
for (i = 0; i < 11; i += 1) {
if (i == 10 || val != 0 || chars_stored) {
chars_stored = 1;
val &= 0x7;
*bp++ = val + '0';
}
value <<= 3;
val = (value & 0xe0000000);
val >>= 29;
}
*bp = '\0';
return bp - buf;
}
#endif

View file

@ -1,38 +0,0 @@
/**
** @file cvtuns.c
**
** @author Numerous CSCI-452 classes
**
** @brief C implementations of common library functions
*/
#ifndef CVTUNS_SRC_INC
#define CVTUNS_SRC_INC
#include <common.h>
#include <lib.h>
/**
** cvtuns(buf,value)
**
** Convert a 32-bit unsigned value into a NUL-terminated character string
**
** @param buf Result buffer
** @param value Value to be converted
**
** @return Length of the resulting buffer
**
** NOTE: assumes buf is large enough to hold the resulting string
*/
int cvtuns(char *buf, uint32_t value)
{
char *bp = buf;
bp = cvtuns0(bp, value);
*bp = '\0';
return bp - buf;
}
#endif

View file

@ -1,40 +0,0 @@
/**
** @file cvtuns0.c
**
** @author Numerous CSCI-452 classes
**
** @brief C implementations of common library functions
*/
#ifndef CVTUNS0_SRC_INC
#define CVTUNS0_SRC_INC
#include <common.h>
#include <lib.h>
/**
** cvtuns0(buf,value) - local support routine for cvtuns()
**
** Convert a 32-bit unsigned value into a NUL-terminated character string
**
** @param buf Result buffer
** @param value Value to be converted
**
** @return Pointer to the first unused byte in the buffer
**
** NOTE: assumes buf is large enough to hold the resulting string
*/
char *cvtuns0(char *buf, uint32_t value)
{
uint32_t quotient;
quotient = value / 10;
if (quotient != 0) {
buf = cvtdec0(buf, quotient);
}
*buf++ = value % 10 + '0';
return buf;
}
#endif

8
lib/delay.c Normal file
View file

@ -0,0 +1,8 @@
#include <stdlib.h>
void delay(int count)
{
while (count-- > 0)
for (int i = 0; i < 100000; i++)
;
}

View file

@ -1,25 +0,0 @@
//
// user-level startup routine
//
.text
.globl _start
.globl main
.globl exit
// entry point - this is where the kernel starts us running
_start:
// we immediately call main()
call main
// if we come back from that, it means the user
// program didn't call exit(), in which case the
// value returned from main() is the exit status
// push that value onto the stack and call exit()
subl $12, %esp
pushl %eax
call exit
// if we come back from that, something bad has
// happened, so we just lock up
1: jmp 1b

6
lib/isdigit.c Normal file
View file

@ -0,0 +1,6 @@
#include <ctype.h>
int isdigit(int c)
{
return c >= '0' && c <= '9';
}

16
lib/isspace.c Normal file
View file

@ -0,0 +1,16 @@
#include <ctype.h>
int isspace(int c)
{
switch (c) {
case ' ':
case '\t':
case '\v':
case '\f':
case '\r':
case '\n':
return 1;
default:
return 0;
}
}

10
lib/itoc.c Normal file
View file

@ -0,0 +1,10 @@
#include <stdlib.h>
char itoc(int i)
{
if (i < 10) {
return '0' + i;
} else {
return 'a' + (i - 10);
}
}

View file

@ -1,111 +0,0 @@
/*
** @file klibc.c
**
** @author Warren R. Carithers
**
** Additional support functions for the kernel.
**
*/
#define KERNEL_SRC
#include <klib.h>
#include <cio.h>
#include <procs.h>
#include <support.h>
/**
** Name: put_char_or_code( ch )
**
** Description: Prints a character on the console, unless it
** is a non-printing character, in which case its hex code
** is printed
**
** @param ch The character to be printed
*/
void put_char_or_code(int ch)
{
if (ch >= ' ' && ch < 0x7f) {
cio_putchar(ch);
} else {
cio_printf("\\x%02x", ch);
}
}
/**
** Name: backtrace
**
** Perform a stack backtrace
**
** @param ebp Initial EBP to use
** @param args Number of function argument values to print
*/
void backtrace(uint32_t *ebp, uint_t args)
{
cio_puts("Trace: ");
if (ebp == NULL) {
cio_puts("NULL ebp, no trace possible\n");
return;
} else {
cio_putchar('\n');
}
while (ebp != NULL) {
// get return address and report it and EBP
uint32_t ret = ebp[1];
cio_printf(" ebp %08x ret %08x args", (uint32_t)ebp, ret);
// print the requested number of function arguments
for (uint_t i = 0; i < args; ++i) {
cio_printf(" [%u] %08x", i + 1, ebp[2 + i]);
}
cio_putchar('\n');
// follow the chain
ebp = (uint32_t *)*ebp;
}
}
/**
** kpanic - kernel-level panic routine
**
** usage: kpanic( msg )
**
** Prefix routine for panic() - can be expanded to do other things
** (e.g., printing a stack traceback)
**
** @param msg[in] String containing a relevant message to be printed,
** or NULL
*/
void kpanic(const char *msg)
{
cio_puts("\n\n***** KERNEL PANIC *****\n\n");
if (msg) {
cio_printf("%s\n", msg);
}
delay(DELAY_5_SEC); // approximately
// dump a bunch of potentially useful information
// dump the contents of the current PCB
pcb_dump("Current", current, true);
// dump the basic info about what's in the process table
ptable_dump_counts();
// dump information about the queues
pcb_queue_dump("R", ready, true);
pcb_queue_dump("W", waiting, true);
pcb_queue_dump("S", sleeping, true);
pcb_queue_dump("Z", zombie, true);
pcb_queue_dump("I", sioread, true);
// perform a stack backtrace
backtrace((uint32_t *)r_ebp(), 3);
// could dump other stuff here, too
panic("KERNEL PANIC");
}

View file

@ -1,38 +0,0 @@
/**
** @file memclr.c
**
** @author Numerous CSCI-452 classes
**
** @brief C implementations of common library functions
*/
#ifndef MEMCLR_SRC_INC
#define MEMCLR_SRC_INC
#include <common.h>
#include <lib.h>
/**
** memclr(buf,len)
**
** Initialize all bytes of a block of memory to zero
**
** @param buf The buffer to initialize
** @param len Buffer size (in bytes)
*/
void memclr(void *buf, register uint32_t len)
{
register uint8_t *dest = buf;
/*
** We could speed this up by unrolling it and clearing
** words at a time (instead of bytes).
*/
while (len--) {
*dest++ = 0;
}
}
#endif

9
lib/memcmp.c Normal file
View file

@ -0,0 +1,9 @@
#include <string.h>
int memcmp(const void *restrict vl, const void *restrict vr, size_t n)
{
const unsigned char *l = vl, *r = vr;
for (; n && *l == *r; n--, l++, r++)
;
return n ? *l - *r : 0;
}

View file

@ -1,42 +1,10 @@
/**
** @file memcpy.c
**
** @author Numerous CSCI-452 classes
**
** @brief C implementations of common library functions
*/
#include <string.h>
#ifndef MEMCPY_SRC_INC
#define MEMCPY_SRC_INC
#include <common.h>
#include <lib.h>
/**
** memcpy(dst,src,len)
**
** Copy a block from one place to another
**
** May not correctly deal with overlapping buffers
**
** @param dst Destination buffer
** @param src Source buffer
** @param len Buffer size (in bytes)
*/
void memcpy(void *dst, register const void *src, register uint32_t len)
void *memcpy(void *restrict dest, const void *restrict src, size_t n)
{
register uint8_t *dest = dst;
register const uint8_t *source = src;
/*
** We could speed this up by unrolling it and copying
** words at a time (instead of bytes).
*/
while (len--) {
*dest++ = *source++;
}
char *d = dest;
const char *s = src;
for (; n; n--)
*d++ = *s++;
return dest;
}
#endif

View file

@ -1,49 +1,20 @@
/**
** @file memmove.c
**
** @author Numerous CSCI-452 classes
**
** @brief C implementations of common library functions
*/
#include <string.h>
#ifndef MEMMOVE_SRC_INC
#define MEMMOVE_SRC_INC
#include <common.h>
#include <lib.h>
/**
** memmove(dst,src,len)
**
** Copy a block from one place to another. Deals with overlapping
** buffers.
**
** @param dst Destination buffer
** @param src Source buffer
** @param len Buffer size (in bytes)
*/
void memmove(void *dst, const void *src, register uint32_t len)
void *memmove(void *dest, const void *src, size_t n)
{
register uint8_t *dest = dst;
register const uint8_t *source = src;
char *d = dest;
const char *s = src;
/*
** We could speed this up by unrolling it and copying
** words at a time (instead of bytes).
*/
if (d == s)
return d;
if (source < dest && (source + len) > dest) {
source += len;
dest += len;
while (len-- > 0) {
*--dest = *--source;
}
if (d < s) {
for (; n; n--)
*d++ = *s++;
} else {
while (len--) {
*dest++ = *source++;
}
while (n)
n--, d[n] = s[n];
}
}
#endif
return dest;
}

View file

@ -1,39 +1,10 @@
/**
** @file memset.c
**
** @author Numerous CSCI-452 classes
**
** @brief C implementations of common library functions
*/
#include <string.h>
#ifndef MEMSET_SRC_INC
#define MEMSET_SRC_INC
#include <common.h>
#include <lib.h>
/**
** memset(buf,len,value)
**
** initialize all bytes of a block of memory to a specific value
**
** @param buf The buffer to initialize
** @param len Buffer size (in bytes)
** @param value Initialization value
*/
void memset(void *buf, register uint32_t len, register uint32_t value)
void *memset(void *dest, int c, size_t n)
{
register uint8_t *bp = buf;
/*
** We could speed this up by unrolling it and copying
** words at a time (instead of bytes).
*/
while (len--) {
*bp++ = value;
}
unsigned char *d = dest;
for (; n; n--) {
*d++ = c;
};
return dest;
}
#endif

View file

@ -1,36 +0,0 @@
/**
** @file pad.c
**
** @author Numerous CSCI-452 classes
**
** @brief C implementations of common library functions
*/
#ifndef PAD_SRC_INC
#define PAD_SRC_INC
#include <common.h>
#include <lib.h>
/**
** pad(dst,extra,padchar) - generate a padding string
**
** @param dst Pointer to where the padding should begin
** @param extra How many padding bytes to add
** @param padchar What character to pad with
**
** @return Pointer to the first byte after the padding
**
** NOTE: does NOT NUL-terminate the buffer
*/
char *pad(char *dst, int extra, int padchar)
{
while (extra > 0) {
*dst++ = (char)padchar;
extra -= 1;
}
return dst;
}
#endif

View file

@ -1,62 +0,0 @@
/**
** @file padstr.c
**
** @author Numerous CSCI-452 classes
**
** @brief C implementations of common library functions
*/
#ifndef PADSTR_SRC_INC
#define PADSTR_SRC_INC
#include <common.h>
#include <lib.h>
/**
** padstr(dst,str,len,width,leftadjust,padchar - add padding characters
** to a string
**
** @param dst The destination buffer
** @param str The string to be padded
** @param len The string length, or -1
** @param width The desired final length of the string
** @param leftadjust Should the string be left-justified?
** @param padchar What character to pad with
**
** @return Pointer to the first byte after the padded string
**
** NOTE: does NOT NUL-terminate the buffer
*/
char *padstr(char *dst, char *str, int len, int width, int leftadjust,
int padchar)
{
int extra;
// determine the length of the string if we need to
if (len < 0) {
len = strlen(str);
}
// how much filler must we add?
extra = width - len;
// add filler on the left if we're not left-justifying
if (extra > 0 && !leftadjust) {
dst = pad(dst, extra, padchar);
}
// copy the string itself
for (int i = 0; i < len; ++i) {
*dst++ = str[i];
}
// add filler on the right if we are left-justifying
if (extra > 0 && leftadjust) {
dst = pad(dst, extra, padchar);
}
return dst;
}
#endif

537
lib/printf.c Normal file
View file

@ -0,0 +1,537 @@
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
#include <stdint.h>
#define PRINTF_NUMERIC_BUF_LEN 50
/// options that can be set inside a specifier
/// flags, width, precision, length, and data type
typedef struct {
/* flags */
/// left justify content
uint8_t left : 1;
/// force sign (+/-) on numeric output
uint8_t sign : 1;
/// leave space if no printed sign on numeric output
uint8_t space : 1;
/// preceed hex/octal output with '0x'
uint8_t hash : 1;
/// left pads numeric output with zeros
uint8_t zero : 1;
uint8_t : 3;
/* width & precision */
/// minimum number of characters to be printed (padding if origonal is less)
int width;
/// digit precision used when printing numerical answers
int precision;
/// if a fixed minimum width has been provided
uint8_t width_set : 1;
/// if the provided minimum width is in the next variable argument
uint8_t width_varies : 1;
/// if a fixed digit precision has been provided
uint8_t precision_set : 1;
/// if the provided digit precision is in the next variable argument
uint8_t precision_varies : 1;
uint8_t : 4;
/* length */
/// what size to read argument as
enum printf_len {
PRINTF_LEN_CHAR,
PRINTF_LEN_SHORT_INT,
PRINTF_LEN_INT,
PRINTF_LEN_LONG_INT,
PRINTF_LEN_LONG_LONG_INT,
PRINTF_LEN_SIZE_T,
} len;
/* other */
/// radix to print the numerical answers as
uint8_t radix;
/// case to print hexadecimal values as
bool is_uppercase;
} options_t;
typedef struct {
/* input */
/// the origonal format string
const char *format;
/// variable args passed in
va_list *args;
/// maximum allowed output length
size_t max_len;
/// if a maximum output length is set
bool has_max_len;
/* output */
size_t written_len;
bool to_file;
union {
FILE *file;
char *buf;
} out;
/* pass 2 */
char *output;
} context_t;
static void printf_putc(context_t *ctx, char c)
{
// bounds check
if (ctx->has_max_len)
if (ctx->written_len >= ctx->max_len)
return;
// write to correct
if (ctx->to_file)
fputc(ctx->out.file, c);
else
*(ctx->out.buf++) = c;
ctx->written_len++;
}
static int parse_flag(const char **res, options_t *opts)
{
const char *fmt = *res;
switch (*(fmt++)) {
case '-':
opts->left = 1;
break;
case '+':
opts->sign = 1;
break;
case ' ':
opts->space = 1;
break;
case '#':
opts->zero = 1;
break;
default:
return 0;
}
*res = fmt;
return 1;
}
static void parse_width(const char **res, options_t *opts)
{
const char *fmt = *res;
char *end = NULL;
// check varies
if (*fmt == '*') {
opts->width_varies = true;
*res = fmt++;
return;
}
// parse num
long width = strtol(fmt, &end, 10);
if (end != NULL) {
opts->width_set = 1;
opts->width = width;
*res = end;
return;
}
}
static void parse_precision(const char **res, options_t *opts)
{
const char *fmt = *res;
char *end = NULL;
// check for dot
if (*(fmt++) != '.')
return;
// check varies
if (*fmt == '*') {
opts->precision_varies = true;
*res = fmt++;
return;
}
// parse num
long precision = strtol(fmt, &end, 10);
if (end != NULL) {
opts->precision_set = 1;
opts->precision = precision;
*res = end;
return;
}
}
static void parse_length(const char **res, options_t *opts)
{
const char *fmt = *res;
switch (*(fmt++)) {
// half
case 'h':
if (*fmt == 'h') {
opts->len = PRINTF_LEN_CHAR;
fmt++;
} else {
opts->len = PRINTF_LEN_SHORT_INT;
}
break;
// long
case 'l':
if (*fmt == 'l') {
opts->len = PRINTF_LEN_LONG_LONG_INT;
fmt++;
} else {
opts->len = PRINTF_LEN_LONG_INT;
}
break;
// size_t
case 'z':
opts->len = PRINTF_LEN_SIZE_T;
break;
default:
opts->len = PRINTF_LEN_INT;
return;
}
*res = fmt;
}
static void get_radix(char spec, options_t *opts)
{
switch (spec) {
case 'x':
case 'X':
opts->radix = 16;
break;
case 'o':
opts->radix = 8;
break;
default:
opts->radix = 10;
break;
}
}
static void get_case(char spec, options_t *opts)
{
if (spec == 'X')
opts->is_uppercase = 1;
}
static char printf_itoc(int uppercase, int i)
{
// decimal
if (i < 10) {
return i + '0';
}
// hex
if (uppercase) {
return (i - 10) + 'A';
} else {
return (i - 10) + 'a';
}
}
static int printf_lltoa(char *buf, options_t *opts, bool is_neg,
unsigned long long int num)
{
int precision = 0;
char *start = buf;
// sign
if (is_neg) {
*(buf++) = '-';
} else if (opts->sign) {
*(buf++) = '+';
} else if (opts->space) {
*(buf++) = ' ';
}
// radix specifier
if (opts->hash) {
if (opts->radix == 8) {
*(buf++) = '0';
*(buf++) = 'x';
}
if (opts->radix == 16) {
*(buf++) = '0';
*(buf++) = 'o';
}
}
// write number
if (num == 0) {
*(buf++) = '0';
}
while (num) {
if (opts->precision_set && precision++ >= opts->precision)
break;
*(buf++) = printf_itoc(opts->is_uppercase, num & opts->radix);
num /= opts->radix;
}
*(buf++) = '\0';
return buf - start;
}
static void handle_int_specifier(context_t *ctx, options_t *const opts,
bool has_sign_bit)
{
union {
unsigned long long int u;
signed long long int i;
} num;
bool is_neg = false;
// read number from arg
switch (opts->len) {
case PRINTF_LEN_CHAR:
num.u = va_arg(*ctx->args, unsigned int); // char
break;
case PRINTF_LEN_SHORT_INT:
num.u = va_arg(*ctx->args, unsigned int); // short int
break;
case PRINTF_LEN_INT:
num.u = va_arg(*ctx->args, unsigned int);
break;
case PRINTF_LEN_LONG_INT:
num.u = va_arg(*ctx->args, unsigned long int);
break;
case PRINTF_LEN_LONG_LONG_INT:
num.u = va_arg(*ctx->args, unsigned long long int);
break;
case PRINTF_LEN_SIZE_T:
num.u = va_arg(*ctx->args, size_t);
break;
}
// get sign if possible neg
if (has_sign_bit) {
if (num.i < 0) {
num.i = -num.i;
is_neg = true;
}
}
// get length of number and number
char buf[PRINTF_NUMERIC_BUF_LEN];
int buf_len = printf_lltoa(buf, opts, is_neg, num.u);
// get needed padding
int padding = 0;
if (opts->width_set && (buf_len < opts->width))
padding = opts->width - buf_len;
/* print */
// left padding
if (opts->left == 0) {
for (int i = 0; i < padding; i++)
printf_putc(ctx, opts->zero ? '0' : ' ');
}
// number
for (int i = 0; i < buf_len; i++)
printf_putc(ctx, buf[i]);
// right padding
if (opts->left == 1) {
for (int i = 0; i < padding; i++)
printf_putc(ctx, opts->zero ? '0' : ' ');
}
}
static void handle_char_specifier(context_t *ctx)
{
char c = va_arg(*ctx->args, int);
printf_putc(ctx, c);
}
static void handle_string_specifier(context_t *ctx, options_t *opts)
{
char *str = va_arg(*ctx->args, char *);
int str_len = 0;
// get length of string
if (opts->precision_set)
str_len = opts->precision;
else
str_len = strlen(str);
// get needed padding
int padding = 0;
if (opts->width_set && (str_len < opts->width))
padding = opts->width - str_len;
/* print */
// left padding
if (opts->left == 0) {
for (int i = 0; i < padding; i++)
printf_putc(ctx, ' ');
}
// string
for (int i = 0; i < str_len; i++)
printf_putc(ctx, str[i]);
// right padding
if (opts->left == 1) {
for (int i = 0; i < padding; i++)
printf_putc(ctx, ' ');
}
}
static void do_printf(context_t *ctx)
{
const char *fmt = ctx->format;
char c = *(fmt++);
while (c != '\0') {
// save start of fmt for current iteration
const char *start = fmt;
// ignore if not %
if (c != '%') {
printf_putc(ctx, c);
continue;
}
// read opts
options_t opts = { 0 };
while (parse_flag(&fmt, &opts))
;
parse_width(&fmt, &opts);
parse_precision(&fmt, &opts);
parse_length(&fmt, &opts);
// read specifier
char spec = *(fmt++);
get_radix(spec, &opts);
get_case(spec, &opts);
// read varied width / precision
if (opts.width_varies) {
opts.width_set = 1;
opts.width = va_arg(*ctx->args, int);
}
if (opts.precision_varies) {
opts.precision_set = 1;
opts.precision = va_arg(*ctx->args, int);
}
switch (spec) {
// signed int
case 'd':
case 'i':
handle_int_specifier(ctx, &opts, true);
break;
// unsigned int
case 'u':
case 'o':
case 'x':
case 'X':
handle_int_specifier(ctx, &opts, false);
break;
// character
case 'c':
handle_char_specifier(ctx);
break;
// string
case 's':
handle_string_specifier(ctx, &opts);
break;
// unknown
default:
// print from % to current
for (; start < fmt; start++)
printf_putc(ctx, *start);
return;
}
}
}
void printf(const char *format, ...)
{
va_list args;
va_start(args, format);
vprintf(format, args);
va_end(args);
}
size_t sprintf(char *restrict s, const char *format, ...)
{
va_list args;
size_t amt;
va_start(args, format);
amt = vsprintf(s, format, args);
va_end(args);
return amt;
}
size_t snprintf(char *restrict s, size_t maxlen, const char *format, ...)
{
va_list args;
size_t amt;
va_start(args, format);
amt = vsnprintf(s, maxlen, format, args);
va_end(args);
return amt;
}
void vprintf(const char *format, va_list args)
{
vfprintf(stdout, format, args);
}
size_t vsprintf(char *restrict s, const char *format, va_list args)
{
// create context
context_t ctx = { 0 };
ctx.format = format;
ctx.args = &args;
// sprintf buffer
ctx.out.buf = s;
ctx.to_file = 0;
// print
do_printf(&ctx);
return ctx.written_len;
}
size_t vsnprintf(char *restrict s, size_t maxlen, const char *format,
va_list args)
{
// create context
context_t ctx = { 0 };
ctx.format = format;
ctx.args = &args;
// sprintf buffer
ctx.out.buf = s;
ctx.to_file = 0;
// sprintf max_len
ctx.has_max_len = 1;
ctx.max_len = maxlen;
// print
do_printf(&ctx);
return ctx.written_len;
}
void fprintf(FILE *stream, const char *format, ...)
{
va_list args;
va_start(args, format);
vfprintf(stream, format, args);
va_end(args);
}
void vfprintf(FILE *stream, const char *format, va_list args)
{
// create context
context_t ctx = { 0 };
ctx.format = format;
ctx.args = &args;
// fprintf stream
ctx.out.file = stream;
ctx.to_file = 1;
// print
do_printf(&ctx);
}

View file

@ -1,132 +0,0 @@
/**
** @file sprint.c
**
** @author Numerous CSCI-452 classes
**
** @brief C implementations of common library functions
*/
#ifndef SPRINT_SRC_INC
#define SPRINT_SRC_INC
#include <common.h>
#include <lib.h>
/**
** sprint(dst,fmt,...) - formatted output into a string buffer
**
** @param dst The string buffer
** @param fmt Format string
**
** The format string parameter is followed by zero or more additional
** parameters which are interpreted according to the format string.
**
** NOTE: assumes the buffer is large enough to hold the result string
**
** NOTE: relies heavily on the x86 parameter passing convention
** (parameters are pushed onto the stack in reverse order as
** 32-bit values).
*/
void sprint(char *dst, char *fmt, ...)
{
int32_t *ap;
char buf[12];
char ch;
char *str;
int leftadjust;
int width;
int len;
int padchar;
/*
** Get characters from the format string and process them
**
** We use the "old-school" method of handling variable numbers
** of parameters. We assume that parameters are passed on the
** runtime stack in consecutive longwords; thus, if the first
** parameter is at location 'x', the second is at 'x+4', the
** third at 'x+8', etc. We use a pointer to a 32-bit thing
** to point to the next "thing", and interpret it according
** to the format string.
*/
// get the pointer to the first "value" parameter
ap = (int *)(&fmt) + 1;
// iterate through the format string
while ((ch = *fmt++) != '\0') {
/*
** Is it the start of a format code?
*/
if (ch == '%') {
/*
** Yes, get the padding and width options (if there).
** Alignment must come at the beginning, then fill,
** then width.
*/
leftadjust = 0;
padchar = ' ';
width = 0;
ch = *fmt++;
if (ch == '-') {
leftadjust = 1;
ch = *fmt++;
}
if (ch == '0') {
padchar = '0';
ch = *fmt++;
}
while (ch >= '0' && ch <= '9') {
width *= 10;
width += ch - '0';
ch = *fmt++;
}
/*
** What data type do we have?
*/
switch (ch) {
case 'c': // characters are passed as 32-bit values
ch = *ap++;
buf[0] = ch;
buf[1] = '\0';
dst = padstr(dst, buf, 1, width, leftadjust, padchar);
break;
case 'd':
len = cvtdec(buf, *ap++);
dst = padstr(dst, buf, len, width, leftadjust, padchar);
break;
case 's':
str = (char *)(*ap++);
dst = padstr(dst, str, -1, width, leftadjust, padchar);
break;
case 'x':
len = cvthex(buf, *ap++);
dst = padstr(dst, buf, len, width, leftadjust, padchar);
break;
case 'o':
len = cvtoct(buf, *ap++);
dst = padstr(dst, buf, len, width, leftadjust, padchar);
break;
case 'u':
len = cvtuns(buf, *ap++);
dst = padstr(dst, buf, len, width, leftadjust, padchar);
break;
}
} else {
// no, it's just an ordinary character
*dst++ = ch;
}
}
// NUL-terminate the result
*dst = '\0';
}
#endif

9
lib/stpcpy.c Normal file
View file

@ -0,0 +1,9 @@
#include <string.h>
char *stpcpy(char *restrict dest, const char *restrict src)
{
char *d = dest;
for (; (*d = *src); d++, src++)
;
return d;
}

10
lib/stpncpy.c Normal file
View file

@ -0,0 +1,10 @@
#include <string.h>
char *stpncpy(char *restrict dest, const char *restrict src, size_t n)
{
char *d = dest;
for (; (*d = *src) && n; d++, src++, n--)
;
memset(d, 0, n);
return d;
}

View file

@ -1,52 +0,0 @@
/**
** @file str2int.c
**
** @author Numerous CSCI-452 classes
**
** @brief C implementations of common library functions
*/
#ifndef STR2INT_SRC_INC
#define STR2INT_SRC_INC
#include <common.h>
#include <lib.h>
/**
** str2int(str,base) - convert a string to a number in the specified base
**
** @param str The string to examine
** @param base The radix to use in the conversion
**
** @return The converted integer
*/
int str2int(register const char *str, register int base)
{
register int num = 0;
register char bchar = '9';
int sign = 1;
// check for leading '-'
if (*str == '-') {
sign = -1;
++str;
}
if (base != 10) {
bchar = '0' + base - 1;
}
// iterate through the characters
while (*str) {
if (*str < '0' || *str > bchar)
break;
num = num * base + *str - '0';
++str;
}
// return the converted value
return (num * sign);
}
#endif

View file

@ -1,39 +1,7 @@
/**
** @file strcat.c
**
** @author Numerous CSCI-452 classes
**
** @brief C implementations of common library functions
*/
#include <string.h>
#ifndef STRCAT_SRC_INC
#define STRCAT_SRC_INC
#include <common.h>
#include <lib.h>
/**
** strcat(dst,src) - append one string to another
**
** @param dst The destination buffer
** @param src The source buffer
**
** @return The dst parameter
**
** NOTE: assumes dst is large enough to hold the resulting string
*/
char *strcat(register char *dst, register const char *src)
char *strcat(char *restrict dest, const char *restrict src)
{
register char *tmp = dst;
while (*dst) // find the NUL
++dst;
while ((*dst++ = *src++)) // append the src string
;
return (tmp);
strcpy(dest + strlen(dest), src);
return dest;
}
#endif

View file

@ -1,32 +0,0 @@
/**
** @file strcmp.c
**
** @author Numerous CSCI-452 classes
**
** @brief C implementations of common library functions
*/
#ifndef STRCMP_SRC_INC
#define STRCMP_SRC_INC
#include <common.h>
#include <lib.h>
/**
** strcmp(s1,s2) - compare two NUL-terminated strings
**
** @param s1 The first source string
** @param s2 The second source string
**
** @return negative if s1 < s2, zero if equal, and positive if s1 > s2
*/
int strcmp(register const char *s1, register const char *s2)
{
while (*s1 != 0 && (*s1 == *s2))
++s1, ++s2;
return (*s1 - *s2);
}
#endif

View file

@ -1,36 +1,9 @@
/**
** @file strcpy.c
**
** @author Numerous CSCI-452 classes
**
** @brief C implementations of common library functions
*/
#include <string.h>
#ifndef STRCPY_SRC_INC
#define STRCPY_SRC_INC
#include <common.h>
#include <lib.h>
/**
** strcpy(dst,src) - copy a NUL-terminated string
**
** @param dst The destination buffer
** @param src The source buffer
**
** @return The dst parameter
**
** NOTE: assumes dst is large enough to hold the copied string
*/
char *strcpy(register char *dst, register const char *src)
char *strcpy(char *restrict dest, const char *restrict src)
{
register char *tmp = dst;
while ((*dst++ = *src++))
char *d = dest;
for (; (*d = *src); d++, src++)
;
return (tmp);
return dest;
}
#endif

View file

@ -1,33 +1,9 @@
/**
** @file strlen.c
**
** @author Numerous CSCI-452 classes
**
** @brief C implementations of common library functions
*/
#include <string.h>
#ifndef STRLEN_SRC_INC
#define STRLEN_SRC_INC
#include <common.h>
#include <lib.h>
/**
** strlen(str) - return length of a NUL-terminated string
**
** @param str The string to examine
**
** @return The length of the string, or 0
*/
uint32_t strlen(register const char *str)
size_t strlen(const char *str)
{
register uint32_t len = 0;
while (*str++) {
++len;
const char *p;
for (p = str; *p != 0; p++) {
}
return (len);
return p - str;
}
#endif

11
lib/strncmp.c Normal file
View file

@ -0,0 +1,11 @@
#include <string.h>
int strncmp(const char *restrict lhs, const char *restrict rhs, size_t n)
{
const unsigned char *l = (void *)lhs, *r = (void *)rhs;
if (!n--)
return 0;
for (; *l && *r && n && *l == *r; l++, r++, n--)
;
return *l - *r;
}

10
lib/strncpy.c Normal file
View file

@ -0,0 +1,10 @@
#include <string.h>
char *strncpy(char *restrict dest, const char *restrict src, size_t n)
{
char *d = dest;
for (; (*d = *src) && n; d++, src++, n--)
;
memset(d, 0, n);
return dest;
}

44
lib/strtoux.c Normal file
View file

@ -0,0 +1,44 @@
#include <stdlib.h>
#include <ctype.h>
#define STRTOUX(name, type) \
type name(const char *restrict s, char **restrict endptr, int radix) \
{ \
const char *s_start = s; \
for (; isspace(*s); s++) \
; \
\
if ((radix == 0 || radix == 16) && \
(s[0] == '0' && (s[1] == 'x' || s[1] == 'X'))) { \
radix = 16; \
s += 2; \
} else if (radix == 0) { \
if (*s == '0') { \
radix = 8; \
s++; \
} else { \
radix = 10; \
} \
} \
\
type num = 0; \
int has_digit = 0; \
\
while (1) { \
int n = ctoi(*s++); \
if (n < 0 || n >= radix) \
break; \
has_digit = 1; \
num = num * radix + n; \
} \
\
if (endptr != NULL) { \
*endptr = has_digit ? (char *)(s - 1) : (char *)s_start; \
} \
\
return num; \
}
STRTOUX(strtoui, unsigned int)
STRTOUX(strtoul, unsigned long int)
STRTOUX(strtoull, unsigned long long int)

53
lib/strtox.c Normal file
View file

@ -0,0 +1,53 @@
#include <stdlib.h>
#include <ctype.h>
#define STRTOX(name, type) \
type name(const char *restrict s, char **restrict endptr, int radix) \
{ \
const char *s_start = s; \
for (; isspace(*s); s++) \
; \
\
int sign = 0; \
switch (*s) { \
case '-': \
sign = 1; /* fallthrough */ \
case '+': \
s++; \
break; \
} \
\
if ((radix == 0 || radix == 16) && \
(s[0] == '0' && (s[1] == 'x' || s[1] == 'X'))) { \
radix = 16; \
s += 2; \
} else if (radix == 0) { \
if (*s == '0') { \
radix = 8; \
s++; \
} else { \
radix = 10; \
} \
} \
\
type num = 0; \
int has_digit = 0; \
\
while (1) { \
int n = ctoi(*s++); \
if (n < 0 || n >= radix) \
break; \
has_digit = 1; \
num = num * radix + n; \
} \
\
if (endptr != NULL) { \
*endptr = has_digit ? (char *)(s - 1) : (char *)s_start; \
} \
\
return sign ? -num : num; \
}
STRTOX(strtoi, int)
STRTOX(strtol, long int)
STRTOX(strtoll, long long int)

View file

@ -1,170 +0,0 @@
/**
** @file ulibc.c
**
** @author CSCI-452 class of 20245
**
** @brief C implementations of user-level library functions
*/
#include <common.h>
/*
** PRIVATE DEFINITIONS
*/
/*
** PRIVATE DATA TYPES
*/
/*
** PRIVATE GLOBAL VARIABLES
*/
/*
** PUBLIC GLOBAL VARIABLES
*/
/*
** PRIVATE FUNCTIONS
*/
/*
** PUBLIC FUNCTIONS
*/
/*
**********************************************
** CONVENIENT "SHORTHAND" VERSIONS OF SYSCALLS
**********************************************
*/
/**
** wait - wait for any child to exit
**
** usage: pid = wait(&status)
**
** Calls waitpid(0,status)
**
** @param status Pointer to int32_t into which the child's status is placed,
** or NULL
**
** @returns The PID of the terminated child, or an error code
*/
int wait(int32_t *status)
{
return (waitpid(0, status));
}
/**
** spawn - create a new process running a different program
**
** usage: pid = spawn(what,args);
**
** Creates a new process and then execs 'what'
**
** @param what The program table index of the program to spawn
** @param args The command-line argument vector for the new process
**
** @returns PID of the new process, or an error code
*/
int32_t spawn(uint_t what, char **args)
{
int32_t pid;
char buf[256];
pid = fork();
if (pid != 0) {
// failure, or we are the parent
return (pid);
}
// we are the child
pid = getpid();
// child inherits parent's priority level
exec(what, args);
// uh-oh....
sprint(buf, "Child %d exec() #%u failed\n", pid, what);
cwrites(buf);
exit(EXIT_FAILURE);
return (0); // shut the compiler up
}
/**
** cwritech(ch) - write a single character to the console
**
** @param ch The character to write
**
** @returns The return value from calling write()
*/
int cwritech(char ch)
{
return (write(CHAN_CIO, &ch, 1));
}
/**
** cwrites(str) - write a NUL-terminated string to the console
**
** @param str The string to write
**
*/
int cwrites(const char *str)
{
int len = strlen(str);
return (write(CHAN_CIO, str, len));
}
/**
** cwrite(buf,size) - write a sized buffer to the console
**
** @param buf The buffer to write
** @param size The number of bytes to write
**
** @returns The return value from calling write()
*/
int cwrite(const char *buf, uint32_t size)
{
return (write(CHAN_CIO, buf, size));
}
/**
** swritech(ch) - write a single character to the SIO
**
** @param ch The character to write
**
** @returns The return value from calling write()
*/
int swritech(char ch)
{
return (write(CHAN_SIO, &ch, 1));
}
/**
** swrites(str) - write a NUL-terminated string to the SIO
**
** @param str The string to write
**
** @returns The return value from calling write()
*/
int swrites(const char *str)
{
int len = strlen(str);
return (write(CHAN_SIO, str, len));
}
/**
** swrite(buf,size) - write a sized buffer to the SIO
**
** @param buf The buffer to write
** @param size The number of bytes to write
**
** @returns The return value from calling write()
*/
int swrite(const char *buf, uint32_t size)
{
return (write(CHAN_SIO, buf, size));
}

View file

@ -1,93 +0,0 @@
/**
** @file ulibs.S
**
** @author CSCI-452 class of 20245
**
** @brief assembly-language user-level library functions
*/
#define ASM_SRC
// get the system call codes
#include <syscalls.h>
/**
** System call stubs
**
** All have the same structure:
**
** move a code into EAX
** generate the interrupt
** return to the caller
**
** As these are simple "leaf" routines, we don't use
** the standard enter/leave method to set up a stack
** frame - that takes time, and we don't really need it.
**
** Could be modified to use the UNIX/Linux convention of
** having the syscall code set the 'C' flag to indicate that
** the value being returned in %EAX is an error code:
**
** ...
** int $VEC_SYSCALL
** jc set_errno
** ret
** ...
**
** .globl errno
** set_errno:
** movl %eax, errno
** movl $-1, %eax
** ret
*/
#define SYSCALL(name) \
.globl name ; \
name: ; \
movl $SYS_##name, %eax ; \
int $VEC_SYSCALL ; \
ret
/*
** "real" system calls
*/
SYSCALL(exit)
SYSCALL(waitpid)
SYSCALL(fork)
SYSCALL(exec)
SYSCALL(read)
SYSCALL(write)
SYSCALL(getpid)
SYSCALL(getppid)
SYSCALL(gettime)
SYSCALL(getprio)
SYSCALL(setprio)
SYSCALL(kill)
SYSCALL(sleep)
/*
** This is a bogus system call; it's here so that we can test
** our handling of out-of-range syscall codes in the syscall ISR.
*/
SYSCALL(bogus)
/*
** Other library functions
*/
/**
** fake_exit()
**
** Dummy "startup" function
**
** calls exit(%eax) - serves as the "return to" code for
** main() functions, in case they don't call exit() themselves
*/
.globl fake_exit
fake_exit:
// alternate: could push a "fake exit" status
pushl %eax // termination status returned by main()
call exit // terminate this process

27
lib/uxtoa.c Normal file
View file

@ -0,0 +1,27 @@
#include <stdlib.h>
#define UXTOA(type, name) \
char *name(unsigned type n, char *buffer, int radix) \
{ \
if (n == 0) { \
buffer[0] = '0'; \
buffer[1] = '\0'; \
return buffer + 1; \
} \
char *start = buffer; \
for (; n; n /= radix) { \
*buffer++ = itoc(n % radix); \
} \
char *buf_end = buffer; \
*buffer-- = '\0'; \
while (buffer > start) { \
char tmp = *start; \
*start++ = *buffer; \
*buffer-- = tmp; \
} \
return buf_end; \
}
UXTOA(int, utoa)
UXTOA(long int, ultoa)
UXTOA(long long int, ulltoa)

31
lib/xtoa.c Normal file
View file

@ -0,0 +1,31 @@
#include <stdlib.h>
#define XTOA(type, name) \
char *name(type n, char *buffer, int radix) \
{ \
if (n == 0) { \
buffer[0] = '0'; \
buffer[1] = '\0'; \
return buffer + 1; \
} \
if (n < 0) { \
*buffer++ = '-'; \
n = -n; \
} \
char *start = buffer; \
for (; n; n /= radix) { \
*buffer++ = itoc(n % radix); \
} \
char *buf_end = buffer; \
*buffer-- = '\0'; \
while (buffer > start) { \
char tmp = *start; \
*start++ = *buffer; \
*buffer-- = tmp; \
} \
return buf_end; \
}
XTOA(int, itoa)
XTOA(long int, ltoa)
XTOA(long long int, lltoa)