summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/atox.c30
-rw-r--r--lib/blkmov.c57
-rw-r--r--lib/bound.c30
-rw-r--r--lib/btoa.c43
-rw-r--r--lib/ctoi.c14
-rw-r--r--lib/cvtdec.c44
-rw-r--r--lib/cvtdec0.c45
-rw-r--r--lib/cvthex.c50
-rw-r--r--lib/cvtoct.c54
-rw-r--r--lib/cvtuns.c38
-rw-r--r--lib/cvtuns0.c40
-rw-r--r--lib/delay.c8
-rw-r--r--lib/entry.S25
-rw-r--r--lib/isdigit.c6
-rw-r--r--lib/isspace.c16
-rw-r--r--lib/itoc.c10
-rw-r--r--lib/klibc.c111
-rw-r--r--lib/memclr.c38
-rw-r--r--lib/memcmp.c9
-rw-r--r--lib/memcpy.c46
-rw-r--r--lib/memmove.c55
-rw-r--r--lib/memset.c43
-rw-r--r--lib/pad.c36
-rw-r--r--lib/padstr.c62
-rw-r--r--lib/printf.c537
-rw-r--r--lib/sprint.c132
-rw-r--r--lib/stpcpy.c9
-rw-r--r--lib/stpncpy.c10
-rw-r--r--lib/str2int.c52
-rw-r--r--lib/strcat.c40
-rw-r--r--lib/strcmp.c32
-rw-r--r--lib/strcpy.c37
-rw-r--r--lib/strlen.c34
-rw-r--r--lib/strncmp.c11
-rw-r--r--lib/strncpy.c10
-rw-r--r--lib/strtoux.c44
-rw-r--r--lib/strtox.c53
-rw-r--r--lib/ulibc.c170
-rw-r--r--lib/ulibs.S93
-rw-r--r--lib/uxtoa.c27
-rw-r--r--lib/xtoa.c31
41 files changed, 911 insertions, 1321 deletions
diff --git a/lib/atox.c b/lib/atox.c
new file mode 100644
index 0000000..c4bef59
--- /dev/null
+++ b/lib/atox.c
@@ -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)
diff --git a/lib/blkmov.c b/lib/blkmov.c
deleted file mode 100644
index 6423810..0000000
--- a/lib/blkmov.c
+++ /dev/null
@@ -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
diff --git a/lib/bound.c b/lib/bound.c
index b1b67da..072a41a 100644
--- a/lib/bound.c
+++ b/lib/bound.c
@@ -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
diff --git a/lib/btoa.c b/lib/btoa.c
new file mode 100644
index 0000000..fe5e275
--- /dev/null
+++ b/lib/btoa.c
@@ -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;
+}
diff --git a/lib/ctoi.c b/lib/ctoi.c
new file mode 100644
index 0000000..efe4fec
--- /dev/null
+++ b/lib/ctoi.c
@@ -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;
+ }
+}
diff --git a/lib/cvtdec.c b/lib/cvtdec.c
deleted file mode 100644
index e95e910..0000000
--- a/lib/cvtdec.c
+++ /dev/null
@@ -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
diff --git a/lib/cvtdec0.c b/lib/cvtdec0.c
deleted file mode 100644
index 2f89ad2..0000000
--- a/lib/cvtdec0.c
+++ /dev/null
@@ -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
diff --git a/lib/cvthex.c b/lib/cvthex.c
deleted file mode 100644
index 8faf853..0000000
--- a/lib/cvthex.c
+++ /dev/null
@@ -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
diff --git a/lib/cvtoct.c b/lib/cvtoct.c
deleted file mode 100644
index 0e03cad..0000000
--- a/lib/cvtoct.c
+++ /dev/null
@@ -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
diff --git a/lib/cvtuns.c b/lib/cvtuns.c
deleted file mode 100644
index b535b34..0000000
--- a/lib/cvtuns.c
+++ /dev/null
@@ -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
diff --git a/lib/cvtuns0.c b/lib/cvtuns0.c
deleted file mode 100644
index 090f00d..0000000
--- a/lib/cvtuns0.c
+++ /dev/null
@@ -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
diff --git a/lib/delay.c b/lib/delay.c
new file mode 100644
index 0000000..ff5ccc4
--- /dev/null
+++ b/lib/delay.c
@@ -0,0 +1,8 @@
+#include <stdlib.h>
+
+void delay(int count)
+{
+ while (count-- > 0)
+ for (int i = 0; i < 100000; i++)
+ ;
+}
diff --git a/lib/entry.S b/lib/entry.S
deleted file mode 100644
index 87ad9c7..0000000
--- a/lib/entry.S
+++ /dev/null
@@ -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
diff --git a/lib/isdigit.c b/lib/isdigit.c
new file mode 100644
index 0000000..aa93ced
--- /dev/null
+++ b/lib/isdigit.c
@@ -0,0 +1,6 @@
+#include <ctype.h>
+
+int isdigit(int c)
+{
+ return c >= '0' && c <= '9';
+}
diff --git a/lib/isspace.c b/lib/isspace.c
new file mode 100644
index 0000000..9e89d76
--- /dev/null
+++ b/lib/isspace.c
@@ -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;
+ }
+}
diff --git a/lib/itoc.c b/lib/itoc.c
new file mode 100644
index 0000000..c19d814
--- /dev/null
+++ b/lib/itoc.c
@@ -0,0 +1,10 @@
+#include <stdlib.h>
+
+char itoc(int i)
+{
+ if (i < 10) {
+ return '0' + i;
+ } else {
+ return 'a' + (i - 10);
+ }
+}
diff --git a/lib/klibc.c b/lib/klibc.c
deleted file mode 100644
index 6a06a96..0000000
--- a/lib/klibc.c
+++ /dev/null
@@ -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");
-}
diff --git a/lib/memclr.c b/lib/memclr.c
deleted file mode 100644
index e839382..0000000
--- a/lib/memclr.c
+++ /dev/null
@@ -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
diff --git a/lib/memcmp.c b/lib/memcmp.c
new file mode 100644
index 0000000..7f3dc01
--- /dev/null
+++ b/lib/memcmp.c
@@ -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;
+}
diff --git a/lib/memcpy.c b/lib/memcpy.c
index 020cc68..ec56537 100644
--- a/lib/memcpy.c
+++ b/lib/memcpy.c
@@ -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
diff --git a/lib/memmove.c b/lib/memmove.c
index e674c49..81f00fe 100644
--- a/lib/memmove.c
+++ b/lib/memmove.c
@@ -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;
+}
diff --git a/lib/memset.c b/lib/memset.c
index cb378ff..ddf42f8 100644
--- a/lib/memset.c
+++ b/lib/memset.c
@@ -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
diff --git a/lib/pad.c b/lib/pad.c
deleted file mode 100644
index 03a352b..0000000
--- a/lib/pad.c
+++ /dev/null
@@ -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
diff --git a/lib/padstr.c b/lib/padstr.c
deleted file mode 100644
index 5806704..0000000
--- a/lib/padstr.c
+++ /dev/null
@@ -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
diff --git a/lib/printf.c b/lib/printf.c
new file mode 100644
index 0000000..3da3906
--- /dev/null
+++ b/lib/printf.c
@@ -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);
+}
diff --git a/lib/sprint.c b/lib/sprint.c
deleted file mode 100644
index 05ddfb5..0000000
--- a/lib/sprint.c
+++ /dev/null
@@ -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
diff --git a/lib/stpcpy.c b/lib/stpcpy.c
new file mode 100644
index 0000000..1586a37
--- /dev/null
+++ b/lib/stpcpy.c
@@ -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;
+}
diff --git a/lib/stpncpy.c b/lib/stpncpy.c
new file mode 100644
index 0000000..4e0def6
--- /dev/null
+++ b/lib/stpncpy.c
@@ -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;
+}
diff --git a/lib/str2int.c b/lib/str2int.c
deleted file mode 100644
index ce28a7a..0000000
--- a/lib/str2int.c
+++ /dev/null
@@ -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
diff --git a/lib/strcat.c b/lib/strcat.c
index f7823bf..33f749b 100644
--- a/lib/strcat.c
+++ b/lib/strcat.c
@@ -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
diff --git a/lib/strcmp.c b/lib/strcmp.c
deleted file mode 100644
index d829b95..0000000
--- a/lib/strcmp.c
+++ /dev/null
@@ -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
diff --git a/lib/strcpy.c b/lib/strcpy.c
index e2c76d7..70cd1ca 100644
--- a/lib/strcpy.c
+++ b/lib/strcpy.c
@@ -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
diff --git a/lib/strlen.c b/lib/strlen.c
index 4687a8a..6c4cc86 100644
--- a/lib/strlen.c
+++ b/lib/strlen.c
@@ -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
diff --git a/lib/strncmp.c b/lib/strncmp.c
new file mode 100644
index 0000000..e890517
--- /dev/null
+++ b/lib/strncmp.c
@@ -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;
+}
diff --git a/lib/strncpy.c b/lib/strncpy.c
new file mode 100644
index 0000000..264fd9d
--- /dev/null
+++ b/lib/strncpy.c
@@ -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;
+}
diff --git a/lib/strtoux.c b/lib/strtoux.c
new file mode 100644
index 0000000..7c2d7ee
--- /dev/null
+++ b/lib/strtoux.c
@@ -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)
diff --git a/lib/strtox.c b/lib/strtox.c
new file mode 100644
index 0000000..5f786f1
--- /dev/null
+++ b/lib/strtox.c
@@ -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)
diff --git a/lib/ulibc.c b/lib/ulibc.c
deleted file mode 100644
index 38aa7df..0000000
--- a/lib/ulibc.c
+++ /dev/null
@@ -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));
-}
diff --git a/lib/ulibs.S b/lib/ulibs.S
deleted file mode 100644
index 46fcb89..0000000
--- a/lib/ulibs.S
+++ /dev/null
@@ -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
diff --git a/lib/uxtoa.c b/lib/uxtoa.c
new file mode 100644
index 0000000..8d4e0e1
--- /dev/null
+++ b/lib/uxtoa.c
@@ -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)
diff --git a/lib/xtoa.c b/lib/xtoa.c
new file mode 100644
index 0000000..bf02236
--- /dev/null
+++ b/lib/xtoa.c
@@ -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)