1 // lib/libc.cc -- Standard C-library functions
3 // This software is copyright (c) 2006 Scott Wood <scott@buserror.net>.
5 // Permission is hereby granted, free of charge, to any person obtaining a copy of
6 // this software and associated documentation files (the "Software"), to deal with
7 // the Software without restriction, including without limitation the rights to
8 // use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
9 // of the Software, and to permit persons to whom the Software is furnished to do
10 // so, subject to the following conditions:
12 // * Redistributions of source code must retain the above copyright notice,
13 // this list of conditions and the following disclaimers.
15 // * Redistributions in binary form must reproduce the above copyright notice,
16 // this list of conditions and the following disclaimers in the
17 // documentation and/or other materials provided with the distribution.
19 // * The names of the Software's authors and/or contributors
20 // may not be used to endorse or promote products derived from
21 // this Software without specific prior written permission.
23 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
25 // FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
26 // CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
28 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE
32 #include <kern/types.h>
33 #include <kern/libc.h>
38 // FIXME: Move printf to lib/kernel
40 static const int alt_form = 0x0001;
41 static const int zero_pad = 0x0002;
42 static const int neg_field = 0x0004;
43 static const int leave_blank = 0x0008;
44 static const int always_sign = 0x0010;
45 static const int group_thousands = 0x0020; // FIXME -- unimplemented
46 static const int long_arg = 0x0040;
47 static const int long_long_arg = 0x0080;
48 static const int short_arg = 0x0100;
49 static const int short_short_arg = 0x0200;
50 static const int intmax_arg = 0x0400;
51 static const int ptrdiff_arg = 0x0800;
52 static const int size_t_arg = 0x1000;
53 static const int capital_hex = 0x2000;
54 static const int num_signed = 0x4000;
55 static const int has_precision = 0x8000;
57 static void printf_string(char *buf, size_t &opos, size_t limit,
58 char *src, size_t len)
61 size_t olen = opos + len <= limit ? len : limit - opos;
62 memcpy(buf + opos, src, olen);
68 static void printf_fill(char *buf, size_t &opos, size_t limit,
72 size_t olen = opos + len <= limit ? len : limit - opos;
73 memset(buf + opos, ch, olen);
79 static void printf_num(char *obuf, size_t &opos, size_t limit,
80 s64 value, long radix, int fieldwidth,
81 int precision, int flags)
85 int letter = (flags & capital_hex) ? 'A' - 10 : 'a' - 10;
88 if (flags & num_signed)
89 uval = value < 0 ? -value : value;
93 // An explicit precision of 0 suppresses all output if the value
94 // is zero. Otherwise, the output size is not limited by precision
97 if (uval != 0 || !(flags & has_precision) || precision != 0) do {
98 int ch = uval % radix;
103 buf[pos] = ch + letter;
111 // length which counts against fieldwidth but not precision
114 if (flags & num_signed) {
116 printf_fill(obuf, opos, limit, '-', 1);
118 } else if (flags & always_sign) {
119 printf_fill(obuf, opos, limit, '+', 1);
121 } else if (flags & leave_blank) {
122 printf_fill(obuf, opos, limit, ' ', 1);
127 if ((flags & alt_form) && value != 0) {
128 if (radix == 8 && (!(flags & has_precision) || precision <= len)) {
129 flags |= has_precision;
134 printf_string(obuf, opos, limit, "0x", 2);
139 if ((flags & has_precision) && len < precision) {
148 if (!(flags & neg_field) && len < fieldwidth) {
149 char padchar = (flags & zero_pad) ? '0' : ' ';
150 printf_fill(obuf, opos, limit, padchar, fieldwidth - len);
154 if (precision != 0) {
155 printf_fill(obuf, opos, limit, '0', precision);
159 printf_string(obuf, opos, limit, buf + pos + 1, 64 - pos);
161 if ((flags & neg_field) && len < fieldwidth)
162 printf_fill(obuf, opos, limit, ' ', fieldwidth - len);
165 size_t vsnprintf(char *buf, size_t size, const char *str, va_list args)
167 size_t opos = 0; // position in the output string
168 unsigned int flags = 0;
174 for (size_t pos = 0; str[pos]; pos++) switch (state) {
176 if (str[pos] == '%') {
186 buf[opos] = str[pos];
191 case 1: // A percent has been seen; read in format characters
198 if (!(flags & has_precision)) {
206 if (flags & has_precision)
211 fieldwidth += str[pos++] - '0';
212 } while (str[pos] >= '0' && str[pos] <= '9');
218 if (fieldwidth || (flags & has_precision))
221 fieldwidth = va_arg(args, int);
225 flags |= has_precision;
227 if (str[pos + 1] == '*') {
229 precision = va_arg(args, int);
230 } else while (str[pos + 1] >= '0' && str[pos + 1] <= '9') {
232 precision += str[++pos] - '0';
242 flags |= leave_blank;
246 flags |= always_sign;
250 flags |= group_thousands;
254 if (flags & long_arg)
255 flags |= long_long_arg;
262 if (flags & long_arg)
263 flags |= short_short_arg;
274 flags |= ptrdiff_arg;
277 // Note that %z and other such "new" format characters are
278 // basically useless because some GCC coder actually went out
279 // of their way to make the compiler reject C99 format
280 // strings in C++ code, with no way of overriding it that I
281 // can find (the source code comments suggest the checking is
282 // only when using -pedantic, but I wasn't using -pedantic).
284 // Thus, we have the choice of either avoiding %z and friends
285 // (and possibly needing to insert hackish casts to silence
286 // the compiler's warnings if different architectures define
287 // types like size_t in different ways), or not using the
288 // format warnings at all.
290 // To mitigate this, 32-bit architectures should define
291 // pointer-sized special types as "long" rather than "int",
292 // so that %lx/%ld can always be used with them. Fixed-size
293 // 32-bit types should be declared as "int" rather than
294 // "long" for the same reason.
304 if ((flags & intmax_arg) || (flags & long_long_arg))
305 arg = va_arg(args, long long);
306 else if (flags & size_t_arg)
307 arg = va_arg(args, ssize_t);
308 else if (flags & ptrdiff_arg)
309 arg = va_arg(args, ptrdiff_t);
310 else if (flags & long_arg)
311 arg = va_arg(args, long);
312 else if (flags & short_short_arg)
313 arg = (signed char)va_arg(args, int);
314 else if (flags & short_arg)
315 arg = (short)va_arg(args, int);
317 arg = va_arg(args, int);
320 printf_num(buf, opos, size, arg, 10,
321 fieldwidth, precision, flags);
327 flags |= capital_hex;
341 if ((flags & intmax_arg) || (flags & long_long_arg))
342 arg = va_arg(args, unsigned long long);
343 else if (flags & size_t_arg)
344 arg = va_arg(args, size_t);
345 else if (flags & ptrdiff_arg)
346 arg = va_arg(args, intptr_t);
347 else if (flags & long_arg)
348 arg = va_arg(args, unsigned long);
349 else if (flags & short_short_arg)
350 arg = (unsigned char)va_arg(args, unsigned int);
351 else if (flags & short_arg)
352 arg = (unsigned short)va_arg(args, unsigned int);
353 else if (flags & short_short_arg)
354 arg = (signed char)va_arg(args, int);
355 else if (flags & short_arg)
356 arg = (short)va_arg(args, int);
358 arg = va_arg(args, unsigned int);
360 printf_num(buf, opos, size, arg, radix,
361 fieldwidth, precision, flags);
368 buf[opos] = va_arg(args, int);
375 char *arg = va_arg(args, char *);
380 size_t len = strlen(arg);
381 printf_string(buf, opos, size, arg, len);
387 void *arg = va_arg(args, void *);
389 printf_num(buf, opos, size, (ulong)arg, 16,
390 fieldwidth, precision, flags);
397 if ((flags & intmax_arg) || (flags & long_long_arg))
398 *va_arg(args, unsigned long long *) = opos;
399 else if (flags & size_t_arg)
400 *va_arg(args, ssize_t *) = opos;
401 else if (flags & ptrdiff_arg)
402 *va_arg(args, ptrdiff_t *) = opos;
403 else if (flags & long_arg)
404 *va_arg(args, long *) = opos;
405 else if (flags & short_short_arg)
406 *va_arg(args, signed char *) = opos;
407 else if (flags & short_arg)
408 *va_arg(args, short *) = opos;
410 *va_arg(args, int *) = opos;
416 default_case: // label for goto
419 buf[opos] = str[pos];
427 if (size > 0 && opos >= size)
433 size_t snprintf(char *buf, size_t size, const char *str, ...)
437 int ret = vsnprintf(buf, size, str, args);
442 size_t sprintf(char *buf, const char *str, ...)
446 int ret = vsnprintf(buf, ULONG_MAX, str, args);
451 void *memcpy(void *dest, const void *src, size_t len)
453 const char *cs = static_cast<const char *>(src);
454 char *cd = static_cast<char *>(dest);
456 for (size_t i = 0; i < len; i++)
462 void *memmove(void *dest, const void *src, size_t len)
465 return memcpy(dest, src, len);
467 const char *cs = static_cast<const char *>(src);
468 char *cd = static_cast<char *>(dest);
470 for (size_t i = len - 1; i >= 0; i--)
476 int memcmp(const void *b1, const void *b2, size_t len)
479 const char *c1 = static_cast<const char *>(b1);
480 const char *c2 = static_cast<const char *>(b2);
482 for (pos = 0; pos < len; pos++) {
483 if (c1[pos] != c2[pos])
484 return c1[pos] - c2[pos];
492 size_t strnlen(const char *s, size_t n)
495 while (pos < n && *s++)
500 size_t strlen(const char *s)
508 char *strcpy(char *dest, const char *src)
519 char *strncpy(char *dest, const char *src, size_t len)
534 void bzero(void *b, size_t len)
536 char *c = static_cast<char *>(b);
542 void *memset(void *b, int ch, size_t len)
544 char *c = static_cast<char *>(b);
552 #include <kern/pagealloc.h>
554 // Temporary hack until slab allocator is added
556 void *malloc(size_t len)
558 len = (len + sizeof(size_t) + Arch::page_size - 1) / Arch::page_size;
559 Mem::Page *page = Mem::PageAlloc::alloc(len);
561 size_t *ptr = (size_t *)Mem::page_to_kvirt(page);
567 void free(void *addr)
570 size_t *ptr = (size_t *)addr;
573 Mem::Page *page = Mem::kvirt_to_page(addr);
574 Mem::PageAlloc::free(page, len);
578 void *operator new(size_t len)
583 void *operator new[](size_t len)
588 void operator delete(void *addr)
593 void operator delete[](void *addr)
598 extern "C" void __cxa_pure_virtual()
606 printf("abort() called in kernel\n");