diff options
author | Freya Murphy <freya@freyacat.org> | 2025-04-08 10:39:48 -0400 |
---|---|---|
committer | Freya Murphy <freya@freyacat.org> | 2025-04-08 10:39:48 -0400 |
commit | 8a19547957a86bed3f58c9abc1ac218d04698faf (patch) | |
tree | ed7ccc6f3a8902915dfe6c9bf763fc45d752b3c4 /user/lib | |
parent | fmt (diff) | |
download | comus-8a19547957a86bed3f58c9abc1ac218d04698faf.tar.gz comus-8a19547957a86bed3f58c9abc1ac218d04698faf.tar.bz2 comus-8a19547957a86bed3f58c9abc1ac218d04698faf.zip |
break apart c libaray
Diffstat (limited to 'user/lib')
-rw-r--r-- | user/lib/alloc.c | 215 | ||||
-rw-r--r-- | user/lib/atox.c | 30 | ||||
-rw-r--r-- | user/lib/bound.c | 12 | ||||
-rw-r--r-- | user/lib/btoa.c | 43 | ||||
-rw-r--r-- | user/lib/ctoi.c | 14 | ||||
-rw-r--r-- | user/lib/delay.c | 8 | ||||
-rw-r--r-- | user/lib/entry.S | 25 | ||||
-rw-r--r-- | user/lib/isdigit.c | 6 | ||||
-rw-r--r-- | user/lib/isspace.c | 16 | ||||
-rw-r--r-- | user/lib/itoc.c | 10 | ||||
-rw-r--r-- | user/lib/memcmp.c | 9 | ||||
-rw-r--r-- | user/lib/memcpy.c | 10 | ||||
-rw-r--r-- | user/lib/memmove.c | 20 | ||||
-rw-r--r-- | user/lib/memset.c | 10 | ||||
-rw-r--r-- | user/lib/printf.c | 602 | ||||
-rw-r--r-- | user/lib/spawn.c | 32 | ||||
-rw-r--r-- | user/lib/stpcpy.c | 9 | ||||
-rw-r--r-- | user/lib/stpncpy.c | 10 | ||||
-rw-r--r-- | user/lib/strcat.c | 7 | ||||
-rw-r--r-- | user/lib/strcpy.c | 9 | ||||
-rw-r--r-- | user/lib/strlen.c | 9 | ||||
-rw-r--r-- | user/lib/strncmp.c | 11 | ||||
-rw-r--r-- | user/lib/strncpy.c | 10 | ||||
-rw-r--r-- | user/lib/strtoux.c | 44 | ||||
-rw-r--r-- | user/lib/strtox.c | 53 | ||||
-rw-r--r-- | user/lib/syscall.S | 93 | ||||
-rw-r--r-- | user/lib/timetostr.c | 143 | ||||
-rw-r--r-- | user/lib/uxtoa.c | 27 | ||||
-rw-r--r-- | user/lib/xtoa.c | 31 |
29 files changed, 1518 insertions, 0 deletions
diff --git a/user/lib/alloc.c b/user/lib/alloc.c new file mode 100644 index 0000000..49c762b --- /dev/null +++ b/user/lib/alloc.c @@ -0,0 +1,215 @@ +#include <stdint.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#define MAGIC 0xBEEFCAFE +#define PAGE_SIZE 4096 + +struct page_header { + struct page_header *next; + struct page_header *prev; + size_t + node_number; // all headers on the same page alloc have the same node number (so they can be merged) + size_t + free; // free space after the node (if its the last node in the alloc block) + size_t used; // how much space this allocation is using + uint64_t magic; +}; + +static const size_t header_len = sizeof(struct page_header); +static struct page_header *start_header = NULL; +static struct page_header *end_header = NULL; + +static struct page_header *get_header(void *ptr) +{ + struct page_header *header = + (struct page_header *)((uintptr_t)ptr - header_len); + + // PERF: do we want to make sure this pointer is paged + // before reading it??? + if (header->magic != MAGIC) { + return NULL; // invalid pointer + } + + return header; +} + +static void *alloc_new(size_t size) +{ + size_t pages = ((size + header_len) / PAGE_SIZE) + 1; + + // FIXME: use brk/sbrk + void *addr = alloc_pages(pages); + void *mem = (char *)addr + header_len; + + size_t total = pages * PAGE_SIZE; + size_t free = total - (size + header_len); + + if (addr == NULL) { + return NULL; + } + + size_t node; + if (end_header != NULL) { + node = end_header->node_number + 1; + } else { + node = 0; + } + + struct page_header *header = addr; + header->magic = 0xBEEFCAFE; + header->used = size; + header->free = free; + header->prev = end_header; + header->next = NULL; + header->node_number = node; + + if (start_header == NULL) { + start_header = header; + } + + if (end_header != NULL) { + end_header->next = header; + } else { + end_header = header; + } + + return mem; +} + +static void *alloc_block(size_t size, struct page_header *block) +{ + struct page_header *header = + (struct page_header *)((char *)block + block->used + header_len); + + size_t free = block->free - (size + header_len); + block->free = 0; + + header->magic = MAGIC; + header->used = size; + header->free = free; + header->prev = block; + header->next = block->next; + block->next = header; + header->node_number = block->node_number; + + void *mem = (char *)header + header_len; + + return mem; +} + +void *malloc(size_t size) +{ + struct page_header *header = start_header; + + for (; header != NULL; header = header->next) { + size_t free = header->free; + if (free < header_len) + continue; + if (size <= + (free - header_len)) { // we must be able to fit data + header + break; + } + } + + if (header != NULL) { + return alloc_block(size, header); + } else { + return alloc_new(size); + } +} + +void *realloc(void *src, size_t dst_len) +{ + struct page_header *header; + size_t src_len; + void *dst; + + // realloc of 0 means free pointer + if (dst_len == 0) { + free(src); + return NULL; + } + + // NULL src means allocate ptr + if (src == NULL) { + dst = malloc(dst_len); + return dst; + } + + header = get_header(src); + + if (header == NULL) + return NULL; + + src_len = header->used; + + if (src_len == 0) + return NULL; + + dst = malloc(dst_len); + + if (dst == NULL) + return NULL; // allocation failed + + if (dst_len < src_len) + src_len = dst_len; + + memcpy(dst, src, src_len); + free(src); + + return dst; +} + +void free(void *ptr) +{ + struct page_header *header; + + if (ptr == NULL) + return; + + header = get_header(ptr); + + if (header == NULL) + return; + + header->free += header->used; + header->used = 0; + + struct page_header *neighbor; + + // merge left + for (neighbor = header->prev; neighbor != NULL; neighbor = neighbor->prev) { + if (neighbor->node_number != header->node_number) + break; + if (neighbor->used && header->used) + break; + neighbor->free += header->free + header_len; + neighbor->next = header->next; + header = neighbor; + } + + // merge right + for (neighbor = header->next; neighbor != NULL; neighbor = neighbor->next) { + if (neighbor->node_number != header->node_number) + break; + if (neighbor->used) + break; + header->free += neighbor->free + header_len; + header->next = neighbor->next; + } + + if ((header->next == NULL || + header->next->node_number != header->node_number) && + (header->prev == NULL || + header->prev->node_number != header->node_number) && + header->used == 0) { + if (header->next) + header->next->prev = header->prev; + if (header->prev) + header->prev->next = header->next; + // FIXME: use brk/sbrk + free_pages(header); + } +} diff --git a/user/lib/atox.c b/user/lib/atox.c new file mode 100644 index 0000000..c4bef59 --- /dev/null +++ b/user/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/user/lib/bound.c b/user/lib/bound.c new file mode 100644 index 0000000..072a41a --- /dev/null +++ b/user/lib/bound.c @@ -0,0 +1,12 @@ +#include <stdlib.h> + +unsigned int bound(unsigned int min, unsigned int value, unsigned int max) +{ + if (value < min) { + value = min; + } + if (value > max) { + value = max; + } + return value; +} diff --git a/user/lib/btoa.c b/user/lib/btoa.c new file mode 100644 index 0000000..fe5e275 --- /dev/null +++ b/user/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/user/lib/ctoi.c b/user/lib/ctoi.c new file mode 100644 index 0000000..efe4fec --- /dev/null +++ b/user/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/user/lib/delay.c b/user/lib/delay.c new file mode 100644 index 0000000..ff5ccc4 --- /dev/null +++ b/user/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/user/lib/entry.S b/user/lib/entry.S new file mode 100644 index 0000000..87ad9c7 --- /dev/null +++ b/user/lib/entry.S @@ -0,0 +1,25 @@ +// +// 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/user/lib/isdigit.c b/user/lib/isdigit.c new file mode 100644 index 0000000..aa93ced --- /dev/null +++ b/user/lib/isdigit.c @@ -0,0 +1,6 @@ +#include <ctype.h> + +int isdigit(int c) +{ + return c >= '0' && c <= '9'; +} diff --git a/user/lib/isspace.c b/user/lib/isspace.c new file mode 100644 index 0000000..9e89d76 --- /dev/null +++ b/user/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/user/lib/itoc.c b/user/lib/itoc.c new file mode 100644 index 0000000..c19d814 --- /dev/null +++ b/user/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/user/lib/memcmp.c b/user/lib/memcmp.c new file mode 100644 index 0000000..7f3dc01 --- /dev/null +++ b/user/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/user/lib/memcpy.c b/user/lib/memcpy.c new file mode 100644 index 0000000..ec56537 --- /dev/null +++ b/user/lib/memcpy.c @@ -0,0 +1,10 @@ +#include <string.h> + +void *memcpy(void *restrict dest, const void *restrict src, size_t n) +{ + char *d = dest; + const char *s = src; + for (; n; n--) + *d++ = *s++; + return dest; +} diff --git a/user/lib/memmove.c b/user/lib/memmove.c new file mode 100644 index 0000000..81f00fe --- /dev/null +++ b/user/lib/memmove.c @@ -0,0 +1,20 @@ +#include <string.h> + +void *memmove(void *dest, const void *src, size_t n) +{ + char *d = dest; + const char *s = src; + + if (d == s) + return d; + + if (d < s) { + for (; n; n--) + *d++ = *s++; + } else { + while (n) + n--, d[n] = s[n]; + } + + return dest; +} diff --git a/user/lib/memset.c b/user/lib/memset.c new file mode 100644 index 0000000..ddf42f8 --- /dev/null +++ b/user/lib/memset.c @@ -0,0 +1,10 @@ +#include <string.h> + +void *memset(void *dest, int c, size_t n) +{ + unsigned char *d = dest; + for (; n; n--) { + *d++ = c; + }; + return dest; +} diff --git a/user/lib/printf.c b/user/lib/printf.c new file mode 100644 index 0000000..4a85956 --- /dev/null +++ b/user/lib/printf.c @@ -0,0 +1,602 @@ +#include <stddef.h> +#include <stdio.h> +#include <stdlib.h> +#include <stdbool.h> +#include <string.h> +#include <stdint.h> + +#define PRINTF_NUMERIC_BUF_LEN 50 + +typedef union { + unsigned long long int u; + signed long long int i; + char *str; + char c; +} data_t; + +/// 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; + /// 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->hash = 1; + break; + case '0': + 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; + + // get width of number + int len = 0; + unsigned long long int temp = num; + if (temp == 0) + len = 1; + while (temp) { + if (opts->precision_set && precision++ >= opts->precision) + break; + temp /= opts->radix; + len++; + } + precision = 0; + + // 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++) = 'o'; + } + if (opts->radix == 16) { + *(buf++) = '0'; + *(buf++) = 'x'; + } + } + + // print zeros if needed + if (opts->width_set && len < opts->width && opts->zero) { + while (len++ < opts->width) + *(buf++) = '0'; + } + + // 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, data_t num) +{ + bool is_neg = false; + + // 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, data_t c) +{ + printf_putc(ctx, c.c); +} + +static void handle_string_specifier(context_t *ctx, options_t *opts, + data_t data) +{ + char *str = data.str; + 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, va_list args) +{ + const char *fmt = ctx->format; + + char c; + while (c = *fmt++, c != '\0') { + // save start of fmt for current iteration + const char *start = fmt - 1; + + // 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(args, int); + } + if (opts.precision_varies) { + opts.precision_set = 1; + opts.precision = va_arg(args, int); + } + // read data from args + data_t data; + switch (spec) { + case 'p': + opts.len = PRINTF_LEN_SIZE_T; + opts.width_set = true; + opts.radix = 16; + opts.hash = true; + opts.zero = true; + case 'd': + case 'i': + case 'u': + case 'o': + case 'x': + case 'X': + // read number from arg + switch (opts.len) { + case PRINTF_LEN_CHAR: + data.u = va_arg(args, unsigned int); // char + break; + case PRINTF_LEN_SHORT_INT: + data.u = va_arg(args, unsigned int); // short int + break; + case PRINTF_LEN_INT: + data.u = va_arg(args, unsigned int); + break; + case PRINTF_LEN_LONG_INT: + data.u = va_arg(args, unsigned long int); + break; + case PRINTF_LEN_LONG_LONG_INT: + data.u = va_arg(args, unsigned long long int); + break; + case PRINTF_LEN_SIZE_T: + data.u = va_arg(args, size_t); + break; + } + break; + // end int + case 's': + // read string + data.str = va_arg(args, void *); + break; + // end string + case 'c': + // read char + data.c = va_arg(args, int); + break; + // end char + } + + switch (spec) { + // signed int + case 'd': + case 'i': + handle_int_specifier(ctx, &opts, true, data); + break; + // unsigned int + case 'p': + case 'u': + case 'o': + case 'x': + case 'X': + handle_int_specifier(ctx, &opts, false, data); + break; + // character + case 'c': + handle_char_specifier(ctx, data); + break; + // string + case 's': + handle_string_specifier(ctx, &opts, data); + break; + // unknown + default: + // print from % to current + for (; start < fmt; start++) + printf_putc(ctx, *start); + break; + } + } +} + +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; + // sprintf buffer + ctx.out.buf = s; + ctx.to_file = 0; + // print + do_printf(&ctx, args); + 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; + // 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, args); + 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; + // fprintf stream + ctx.out.file = stream; + ctx.to_file = 1; + // print + do_printf(&ctx, args); +} + +void putc(char c) +{ + fputc(stdout, c); +} + +void puts(const char *str) +{ + fputs(stdout, str); +} + +void fputs(FILE *stream, const char *s) +{ + while (*s) + fputc(stream, *s++); +} diff --git a/user/lib/spawn.c b/user/lib/spawn.c new file mode 100644 index 0000000..78b1a53 --- /dev/null +++ b/user/lib/spawn.c @@ -0,0 +1,32 @@ +#include <stdio.h> +#include <error.h> +#include <unistd.h> + +int wait(int32_t *status) +{ + return (waitpid(0, status)); +} + +int spawn(uint_t prog, char **args) +{ + int32_t pid; + + 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(prog, args); + + // uh-oh.... + + fprintf(stderr, "Child %d exec() #%u failed\n", pid, prog); + + exit(EXIT_FAILURE); +} diff --git a/user/lib/stpcpy.c b/user/lib/stpcpy.c new file mode 100644 index 0000000..1586a37 --- /dev/null +++ b/user/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/user/lib/stpncpy.c b/user/lib/stpncpy.c new file mode 100644 index 0000000..4e0def6 --- /dev/null +++ b/user/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/user/lib/strcat.c b/user/lib/strcat.c new file mode 100644 index 0000000..33f749b --- /dev/null +++ b/user/lib/strcat.c @@ -0,0 +1,7 @@ +#include <string.h> + +char *strcat(char *restrict dest, const char *restrict src) +{ + strcpy(dest + strlen(dest), src); + return dest; +} diff --git a/user/lib/strcpy.c b/user/lib/strcpy.c new file mode 100644 index 0000000..70cd1ca --- /dev/null +++ b/user/lib/strcpy.c @@ -0,0 +1,9 @@ +#include <string.h> + +char *strcpy(char *restrict dest, const char *restrict src) +{ + char *d = dest; + for (; (*d = *src); d++, src++) + ; + return dest; +} diff --git a/user/lib/strlen.c b/user/lib/strlen.c new file mode 100644 index 0000000..6c4cc86 --- /dev/null +++ b/user/lib/strlen.c @@ -0,0 +1,9 @@ +#include <string.h> + +size_t strlen(const char *str) +{ + const char *p; + for (p = str; *p != 0; p++) { + } + return p - str; +} diff --git a/user/lib/strncmp.c b/user/lib/strncmp.c new file mode 100644 index 0000000..e890517 --- /dev/null +++ b/user/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/user/lib/strncpy.c b/user/lib/strncpy.c new file mode 100644 index 0000000..264fd9d --- /dev/null +++ b/user/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/user/lib/strtoux.c b/user/lib/strtoux.c new file mode 100644 index 0000000..7c2d7ee --- /dev/null +++ b/user/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/user/lib/strtox.c b/user/lib/strtox.c new file mode 100644 index 0000000..5f786f1 --- /dev/null +++ b/user/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/user/lib/syscall.S b/user/lib/syscall.S new file mode 100644 index 0000000..46fcb89 --- /dev/null +++ b/user/lib/syscall.S @@ -0,0 +1,93 @@ +/** +** @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/user/lib/timetostr.c b/user/lib/timetostr.c new file mode 100644 index 0000000..fa77362 --- /dev/null +++ b/user/lib/timetostr.c @@ -0,0 +1,143 @@ +#include <lib.h> +#include <time.h> + +static char *ABB_WEEKDAY[7] = { + "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" +}; + +static char *FULL_WEEKDAY[7] = { "Sunday", "Monday", "Tuesday", "Wednesday", + "Thursday", "Friday", "Saturady" }; + +static char *ABB_MONTH[12] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", + "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; + +static char *FULL_MONTH[12] = { + "January", "Feburary", "March", "April", "May", "June", + "July", "August", "September", "October", "November", "December" +}; + +static char *write_num(unsigned int num, unsigned int pad, char *buf, size_t n) +{ + size_t digits = 1; + unsigned int x = num; + + while (x /= 10, x > 0) + digits++; + if (pad == 0) + pad = digits; + + for (size_t i = 0; i < pad; i++) { + size_t digit; + if (i >= digits) { + digit = 0; + } else { + digit = num % 10; + num /= 10; + } + + if (pad - i - 1 >= n) + continue; + buf[pad - i - 1] = '0' + digit; + } + + if (pad > n) + pad = n; + + return buf + pad; +} + +void timetostr(time_t *time, char *format, char *buf, size_t n) +{ + char *index = buf; + char c; + int space; + + while (c = *format++, space = (buf + n) - index, c != '\0' && space > 0) { + if (c != '%') { + *index++ = c; + continue; + } else { + c = *format++; + } + + switch (c) { + case '%': + *index++ = '%'; + break; + case 'a': + index = strncpy(index, ABB_WEEKDAY[time->wday], space); + break; + case 'A': + index = strncpy(index, FULL_WEEKDAY[time->wday], space); + break; + case 'b': + case 'h': + index = strncpy(index, ABB_MONTH[time->mon], space); + break; + case 'B': + index = strncpy(index, FULL_MONTH[time->mon], space); + break; + case 'C': + index = write_num(time->cen, 0, index, space); + break; + case 'd': + index = write_num(time->mday, 2, index, space); + break; + case 'H': + index = write_num(time->hour, 2, index, space); + break; + case 'I': + index = write_num((time->hour + 12) % 12 + 1, 2, index, space); + break; + case 'j': + index = write_num(time->yday, 3, index, space); + break; + case 'm': + index = write_num(time->mon + 1, 2, index, space); + break; + case 'M': + index = write_num(time->min, 2, index, space); + break; + case 'n': + *index++ = '\n'; + break; + case 'p': + index = strncpy(index, time->hour > 11 ? "PM" : "AM", space); + break; + case 'P': + index = strncpy(index, time->hour > 11 ? "pm" : "am", space); + break; + case 'q': + index = write_num((time->mon + 3) / 3, 0, index, space); + break; + case 'S': + index = write_num(time->sec, 2, index, space); + break; + case 't': + *index++ = '\t'; + break; + case 'u': + index = write_num(((time->wday + 1) % 7) + 1, 0, index, space); + break; + case 'w': + index = write_num(time->wday, 0, index, space); + break; + case 'y': + index = write_num(time->yn, 2, index, space); + break; + case 'Y': + index = write_num(time->year + 1900, 0, index, space); + break; + default: { + char b[3] = { '%', c, '\0' }; + index = strncpy(index, b, space); + break; + } + } + } + + if (space < 1) + buf[n - 1] = '\0'; + else + *index = '\0'; +} diff --git a/user/lib/uxtoa.c b/user/lib/uxtoa.c new file mode 100644 index 0000000..8d4e0e1 --- /dev/null +++ b/user/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/user/lib/xtoa.c b/user/lib/xtoa.c new file mode 100644 index 0000000..bf02236 --- /dev/null +++ b/user/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) |