X-Git-Url: http://git.buserror.net/cgi-bin/gitweb.cgi?p=polintos%2Fscott%2Fpriv.git;a=blobdiff_plain;f=kernel%2Flib%2Flibc.cc;h=8d9685a5a309eebc23b27d4d0c1c38cd0983df9d;hp=f03c17c00f8163551b8a5aa6e5846dced70ddc62;hb=371d6008c5366f424e4bf8889febe3cc495d0d3e;hpb=2e0cf58da9949572c6e334a07bba6774fdb749f9 diff --git a/kernel/lib/libc.cc b/kernel/lib/libc.cc index f03c17c..8d9685a 100644 --- a/kernel/lib/libc.cc +++ b/kernel/lib/libc.cc @@ -2,527 +2,24 @@ // // This software is copyright (c) 2006 Scott Wood . // -// Permission is hereby granted, free of charge, to any person obtaining a copy of -// this software and associated documentation files (the "Software"), to deal with -// the Software without restriction, including without limitation the rights to -// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies -// of the Software, and to permit persons to whom the Software is furnished to do -// so, subject to the following condition: +// This software is provided 'as-is', without any express or implied warranty. +// In no event will the authors or contributors be held liable for any damages +// arising from the use of this software. // -// The above copyright notice and this permission notice shall be -// included in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS -// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE -// SOFTWARE. +// Permission is hereby granted to everyone, free of charge, to use, copy, +// modify, prepare derivative works of, publish, distribute, perform, +// sublicense, and/or sell copies of the Software, provided that the above +// copyright notice and disclaimer of warranty be included in all copies or +// substantial portions of this software. #include #include +#include #include #include -// FIXME: Move printf to lib/kernel - -static const int alt_form = 0x0001; -static const int zero_pad = 0x0002; -static const int neg_field = 0x0004; -static const int leave_blank = 0x0008; -static const int always_sign = 0x0010; -static const int group_thousands = 0x0020; // FIXME -- unimplemented -static const int long_arg = 0x0040; -static const int long_long_arg = 0x0080; -static const int short_arg = 0x0100; -static const int short_short_arg = 0x0200; -static const int intmax_arg = 0x0400; -static const int ptrdiff_arg = 0x0800; -static const int size_t_arg = 0x1000; -static const int capital_hex = 0x2000; -static const int num_signed = 0x4000; -static const int has_precision = 0x8000; - -static void printf_string(char *buf, size_t &opos, size_t limit, - char *src, size_t len) -{ - if (opos < limit) { - size_t olen = opos + len <= limit ? len : limit - opos; - memcpy(buf + opos, src, olen); - } - - opos += len; -} - -static void printf_fill(char *buf, size_t &opos, size_t limit, - char ch, int len) -{ - if (opos < limit) { - size_t olen = opos + len <= limit ? len : limit - opos; - memset(buf + opos, ch, olen); - } - - opos += len; -} - -static void printf_num(char *obuf, size_t &opos, size_t limit, - s64 value, long radix, int fieldwidth, - int precision, int flags) -{ - char buf[65]; - int pos = 64; - int letter = (flags & capital_hex) ? 'A' - 10 : 'a' - 10; - u64 uval; - - if (flags & num_signed) - uval = value < 0 ? -value : value; - else - uval = value; - - // An explicit precision of 0 suppresses all output if the value - // is zero. Otherwise, the output size is not limited by precision - // or field width. - - if (uval != 0 || !(flags & has_precision) || precision != 0) do { - int ch = uval % radix; - - if (ch < 10) - buf[pos] = ch + '0'; - else - buf[pos] = ch + letter; - - uval /= radix; - pos--; - } while (uval); - - int len = 64 - pos; - - // length which counts against fieldwidth but not precision - int extralen = 0; - - if (flags & num_signed) { - if (value < 0) { - printf_fill(obuf, opos, limit, '-', 1); - extralen += 1; - } else if (flags & always_sign) { - printf_fill(obuf, opos, limit, '+', 1); - extralen += 1; - } else if (flags & leave_blank) { - printf_fill(obuf, opos, limit, ' ', 1); - extralen += 1; - } - } - - if ((flags & alt_form) && value != 0) { - if (radix == 8 && (!(flags & has_precision) || precision <= len)) { - flags |= has_precision; - precision = len + 1; - } - - if (radix == 16) { - printf_string(obuf, opos, limit, "0x", 2); - extralen += 2; - } - } - - if ((flags & has_precision) && len < precision) { - precision -= len; - len += precision; - } else { - precision = 0; - } - - len += extralen; - - if (!(flags & neg_field) && len < fieldwidth) { - char padchar = (flags & zero_pad) ? '0' : ' '; - printf_fill(obuf, opos, limit, padchar, fieldwidth - len); - len = fieldwidth; - } - - if (precision != 0) { - printf_fill(obuf, opos, limit, '0', precision); - len += precision; - } - - printf_string(obuf, opos, limit, buf + pos + 1, 64 - pos); - - if ((flags & neg_field) && len < fieldwidth) - printf_fill(obuf, opos, limit, ' ', fieldwidth - len); -} - -size_t vsnprintf(char *buf, size_t size, const char *str, va_list args) -{ - size_t opos = 0; // position in the output string - unsigned int flags = 0; - int radix = 10; - int state = 0; - int fieldwidth = 0; - int precision = 0; - - for (size_t pos = 0; str[pos]; pos++) switch (state) { - case 0: - if (str[pos] == '%') { - flags = 0; - radix = 10; - state = 1; - fieldwidth = 0; - precision = 0; - break; - } - - if (opos < size) - buf[opos] = str[pos]; - - opos++; - break; - - case 1: // A percent has been seen; read in format characters - switch (str[pos]) { - case '#': - flags |= alt_form; - break; - - case '0': - if (!(flags & has_precision)) { - flags |= zero_pad; - break; - } - - // else fall through - - case '1' ... '9': - if (flags & has_precision) - goto default_case; - - do { - fieldwidth *= 10; - fieldwidth += str[pos++] - '0'; - } while (str[pos] >= '0' && str[pos] <= '9'); - - pos--; - break; - - case '*': - if (fieldwidth || (flags & has_precision)) - goto default_case; - - fieldwidth = va_arg(args, int); - break; - - case '.': - flags |= has_precision; - - if (str[pos + 1] == '*') { - pos++; - precision = va_arg(args, int); - } else while (str[pos + 1] >= '0' && str[pos + 1] <= '9') { - precision *= 10; - precision += str[++pos] - '0'; - } - - break; - - case '-': - flags |= neg_field; - break; - - case ' ': - flags |= leave_blank; - break; - - case '+': - flags |= always_sign; - break; - - case '\'': - flags |= group_thousands; - break; - - case 'l': - if (flags & long_arg) - flags |= long_long_arg; - else - flags |= long_arg; - - break; - - case 'h': - if (flags & long_arg) - flags |= short_short_arg; - else - flags |= short_arg; - - break; - - case 'j': - flags |= intmax_arg; - break; - - case 't': - flags |= ptrdiff_arg; - break; - - // Note that %z and other such "new" format characters are - // basically useless because some GCC coder actually went out - // of their way to make the compiler reject C99 format - // strings in C++ code, with no way of overriding it that I - // can find (the source code comments suggest the checking is - // only when using -pedantic, but I wasn't using -pedantic). - // - // Thus, we have the choice of either avoiding %z and friends - // (and possibly needing to insert hackish casts to silence - // the compiler's warnings if different architectures define - // types like size_t in different ways), or not using the - // format warnings at all. - // - // To mitigate this, 32-bit architectures should define - // pointer-sized special types as "long" rather than "int", - // so that %lx/%ld can always be used with them. Fixed-size - // 32-bit types should be declared as "int" rather than - // "long" for the same reason. - - case 'z': - flags |= size_t_arg; - break; - - case 'd': - case 'i': { - s64 arg; - - if ((flags & intmax_arg) || (flags & long_long_arg)) - arg = va_arg(args, long long); - else if (flags & size_t_arg) - arg = va_arg(args, ssize_t); - else if (flags & ptrdiff_arg) - arg = va_arg(args, ptrdiff_t); - else if (flags & long_arg) - arg = va_arg(args, long); - else if (flags & short_short_arg) - arg = (signed char)va_arg(args, int); - else if (flags & short_arg) - arg = (short)va_arg(args, int); - else - arg = va_arg(args, int); - - flags |= num_signed; - printf_num(buf, opos, size, arg, 10, - fieldwidth, precision, flags); - state = 0; - break; - } - - case 'X': - flags |= capital_hex; - // fall-through - - case 'x': - radix = 18; - // fall-through - - case 'o': - radix -= 2; - // fall-through - - case 'u': { - u64 arg; - - if ((flags & intmax_arg) || (flags & long_long_arg)) - arg = va_arg(args, unsigned long long); - else if (flags & size_t_arg) - arg = va_arg(args, size_t); - else if (flags & ptrdiff_arg) - arg = va_arg(args, intptr_t); - else if (flags & long_arg) - arg = va_arg(args, unsigned long); - else if (flags & short_short_arg) - arg = (unsigned char)va_arg(args, unsigned int); - else if (flags & short_arg) - arg = (unsigned short)va_arg(args, unsigned int); - else if (flags & short_short_arg) - arg = (signed char)va_arg(args, int); - else if (flags & short_arg) - arg = (short)va_arg(args, int); - else - arg = va_arg(args, unsigned int); - - printf_num(buf, opos, size, arg, radix, - fieldwidth, precision, flags); - state = 0; - break; - } - - case 'c': - if (opos < size) - buf[opos] = va_arg(args, int); - - opos++; - state = 0; - break; - - case 's': { - char *arg = va_arg(args, char *); - - if (!arg) - arg = "(null)"; - - size_t len = strlen(arg); - printf_string(buf, opos, size, arg, len); - state = 0; - break; - } - - case 'p': { - void *arg = va_arg(args, void *); - - printf_num(buf, opos, size, (ulong)arg, 16, - fieldwidth, precision, flags); - - state = 0; - break; - } - - case 'n': { - if ((flags & intmax_arg) || (flags & long_long_arg)) - *va_arg(args, unsigned long long *) = opos; - else if (flags & size_t_arg) - *va_arg(args, ssize_t *) = opos; - else if (flags & ptrdiff_arg) - *va_arg(args, ptrdiff_t *) = opos; - else if (flags & long_arg) - *va_arg(args, long *) = opos; - else if (flags & short_short_arg) - *va_arg(args, signed char *) = opos; - else if (flags & short_arg) - *va_arg(args, short *) = opos; - else - *va_arg(args, int *) = opos; - - state = 0; - break; - } - - default_case: // label for goto - default: - if (opos < size) - buf[opos] = str[pos]; - - opos++; - state = 0; - break; - } - } - - if (size > 0 && opos >= size) - buf[size - 1] = 0; - - return opos; -} - -size_t snprintf(char *buf, size_t size, const char *str, ...) -{ - va_list args; - va_start(args, str); - int ret = vsnprintf(buf, size, str, args); - va_end(args); - return ret; -} - -size_t sprintf(char *buf, const char *str, ...) -{ - va_list args; - va_start(args, str); - int ret = vsnprintf(buf, ULONG_MAX, str, args); - va_end(args); - return ret; -} - -void *memcpy(void *dest, const void *src, size_t len) -{ - const char *cs = static_cast(src); - char *cd = static_cast(dest); - - for (size_t i = 0; i < len; i++) - cd[i] = cs[i]; - - return dest; -} - -void *memmove(void *dest, const void *src, size_t len) -{ - if (dest < src) - return memcpy(dest, src, len); - - const char *cs = static_cast(src); - char *cd = static_cast(dest); - - for (size_t i = len - 1; i >= 0; i--) - cd[i] = cs[i]; - - return dest; -} - -int memcmp(const void *b1, const void *b2, size_t len) -{ - size_t pos; - const char *c1 = static_cast(b1); - const char *c2 = static_cast(b2); - - for (pos = 0; pos < len; pos++) { - if (c1[pos] != c2[pos]) - return c1[pos] - c2[pos]; - - pos++; - } - - return 0; -} - -size_t strnlen(const char *s, size_t n) -{ - size_t pos = 0; - while (pos < n && *s++) - pos++; - return pos; -} - -size_t strlen(const char *s) -{ - size_t pos = 0; - while (*s++) - pos++; - return pos; -} - -char *strcpy(char *dest, const char *src) -{ - char *orig = dest; - - do { - *dest = *src++; - } while (*dest++); - - return orig; -} - -char *strncpy(char *dest, const char *src, size_t len) -{ - char *orig = dest; - - while (len--) { - *dest = *src++; - - if (!*dest++) - break; - } - - bzero(dest, len); - return orig; -} - void bzero(void *b, size_t len) { char *c = static_cast(b); @@ -531,22 +28,15 @@ void bzero(void *b, size_t len) *c++ = 0; } -void *memset(void *b, int ch, size_t len) -{ - char *c = static_cast(b); - - while (len--) - *c++ = ch; - - return b; -} - #include // Temporary hack until slab allocator is added void *malloc(size_t len) { + if (len > Arch::page_size - sizeof(size_t)) + return NULL; + len = (len + sizeof(size_t) + Arch::page_size - 1) / Arch::page_size; Mem::Page *page = Mem::PageAlloc::alloc(len); @@ -559,8 +49,7 @@ void *malloc(size_t len) void free(void *addr) { if (addr) { - size_t *ptr = (size_t *)addr; - ptr--; + size_t *ptr = (size_t *)addr - 1; size_t len = *ptr; Mem::Page *page = Mem::kvirt_to_page(addr); Mem::PageAlloc::free(page, len);