diff options
Diffstat (limited to 'lib')
-rw-r--r-- | lib/atox.c | 30 | ||||
-rw-r--r-- | lib/blkmov.c | 57 | ||||
-rw-r--r-- | lib/bound.c | 30 | ||||
-rw-r--r-- | lib/btoa.c | 43 | ||||
-rw-r--r-- | lib/ctoi.c | 14 | ||||
-rw-r--r-- | lib/cvtdec.c | 44 | ||||
-rw-r--r-- | lib/cvtdec0.c | 45 | ||||
-rw-r--r-- | lib/cvthex.c | 50 | ||||
-rw-r--r-- | lib/cvtoct.c | 54 | ||||
-rw-r--r-- | lib/cvtuns.c | 38 | ||||
-rw-r--r-- | lib/cvtuns0.c | 40 | ||||
-rw-r--r-- | lib/delay.c | 8 | ||||
-rw-r--r-- | lib/entry.S | 25 | ||||
-rw-r--r-- | lib/isdigit.c | 6 | ||||
-rw-r--r-- | lib/isspace.c | 16 | ||||
-rw-r--r-- | lib/itoc.c | 10 | ||||
-rw-r--r-- | lib/klibc.c | 111 | ||||
-rw-r--r-- | lib/memclr.c | 38 | ||||
-rw-r--r-- | lib/memcmp.c | 9 | ||||
-rw-r--r-- | lib/memcpy.c | 46 | ||||
-rw-r--r-- | lib/memmove.c | 55 | ||||
-rw-r--r-- | lib/memset.c | 43 | ||||
-rw-r--r-- | lib/pad.c | 36 | ||||
-rw-r--r-- | lib/padstr.c | 62 | ||||
-rw-r--r-- | lib/printf.c | 537 | ||||
-rw-r--r-- | lib/sprint.c | 132 | ||||
-rw-r--r-- | lib/stpcpy.c | 9 | ||||
-rw-r--r-- | lib/stpncpy.c | 10 | ||||
-rw-r--r-- | lib/str2int.c | 52 | ||||
-rw-r--r-- | lib/strcat.c | 40 | ||||
-rw-r--r-- | lib/strcmp.c | 32 | ||||
-rw-r--r-- | lib/strcpy.c | 37 | ||||
-rw-r--r-- | lib/strlen.c | 34 | ||||
-rw-r--r-- | lib/strncmp.c | 11 | ||||
-rw-r--r-- | lib/strncpy.c | 10 | ||||
-rw-r--r-- | lib/strtoux.c | 44 | ||||
-rw-r--r-- | lib/strtox.c | 53 | ||||
-rw-r--r-- | lib/ulibc.c | 170 | ||||
-rw-r--r-- | lib/ulibs.S | 93 | ||||
-rw-r--r-- | lib/uxtoa.c | 27 | ||||
-rw-r--r-- | lib/xtoa.c | 31 |
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) |