1 // lib/libc.cc -- Standard C-library functions
3 // This software is copyright (c) 2006 Scott Wood <scott@buserror.net>.
5 // This software is provided 'as-is', without any express or implied warranty.
6 // In no event will the authors or contributors be held liable for any damages
7 // arising from the use of this software.
9 // Permission is hereby granted to everyone, free of charge, to use, copy,
10 // modify, prepare derivative works of, publish, distribute, perform,
11 // sublicense, and/or sell copies of the Software, provided that the above
12 // copyright notice and disclaimer of warranty be included in all copies or
13 // substantial portions of this software.
16 #include <kern/types.h>
17 #include <kern/libc.h>
18 #include <kern/console.h>
23 // FIXME: Move printf to lib/kernel
25 static const int alt_form = 0x0001;
26 static const int zero_pad = 0x0002;
27 static const int neg_field = 0x0004;
28 static const int leave_blank = 0x0008;
29 static const int always_sign = 0x0010;
30 static const int group_thousands = 0x0020; // FIXME -- unimplemented
31 static const int long_arg = 0x0040;
32 static const int long_long_arg = 0x0080;
33 static const int short_arg = 0x0100;
34 static const int short_short_arg = 0x0200;
35 static const int intmax_arg = 0x0400;
36 static const int ptrdiff_arg = 0x0800;
37 static const int size_t_arg = 0x1000;
38 static const int capital_hex = 0x2000;
39 static const int num_signed = 0x4000;
40 static const int has_precision = 0x8000;
42 static void printf_string(char *buf, size_t &opos, size_t limit,
43 const char *src, size_t len)
46 size_t olen = opos + len <= limit ? len : limit - opos;
47 memcpy(buf + opos, src, olen);
53 static void printf_fill(char *buf, size_t &opos, size_t limit,
57 size_t olen = opos + len <= limit ? len : limit - opos;
58 memset(buf + opos, ch, olen);
64 static void printf_num(char *obuf, size_t &opos, size_t limit,
65 s64 value, long radix, int fieldwidth,
66 int precision, int flags)
70 int letter = (flags & capital_hex) ? 'A' - 10 : 'a' - 10;
73 if (flags & num_signed)
74 uval = value < 0 ? -value : value;
78 // An explicit precision of 0 suppresses all output if the value
79 // is zero. Otherwise, the output size is not limited by precision
82 if (uval != 0 || !(flags & has_precision) || precision != 0) do {
83 int ch = uval % radix;
88 buf[pos] = ch + letter;
96 // length which counts against fieldwidth but not precision
99 if (flags & num_signed) {
101 printf_fill(obuf, opos, limit, '-', 1);
103 } else if (flags & always_sign) {
104 printf_fill(obuf, opos, limit, '+', 1);
106 } else if (flags & leave_blank) {
107 printf_fill(obuf, opos, limit, ' ', 1);
112 if ((flags & alt_form) && value != 0) {
113 if (radix == 8 && (!(flags & has_precision) || precision <= len)) {
114 flags |= has_precision;
119 printf_string(obuf, opos, limit, "0x", 2);
124 if ((flags & has_precision) && len < precision) {
133 if (!(flags & neg_field) && len < fieldwidth) {
134 char padchar = (flags & zero_pad) ? '0' : ' ';
135 printf_fill(obuf, opos, limit, padchar, fieldwidth - len);
139 if (precision != 0) {
140 printf_fill(obuf, opos, limit, '0', precision);
144 printf_string(obuf, opos, limit, buf + pos + 1, 64 - pos);
146 if ((flags & neg_field) && len < fieldwidth)
147 printf_fill(obuf, opos, limit, ' ', fieldwidth - len);
150 size_t vsnprintf(char *buf, size_t size, const char *str, va_list args)
152 size_t opos = 0; // position in the output string
153 unsigned int flags = 0;
159 for (size_t pos = 0; str[pos]; pos++) switch (state) {
161 if (str[pos] == '%') {
171 buf[opos] = str[pos];
176 case 1: // A percent has been seen; read in format characters
183 if (!(flags & has_precision)) {
191 if (flags & has_precision)
196 fieldwidth += str[pos++] - '0';
197 } while (str[pos] >= '0' && str[pos] <= '9');
203 if (fieldwidth || (flags & has_precision))
206 fieldwidth = va_arg(args, int);
210 flags |= has_precision;
212 if (str[pos + 1] == '*') {
214 precision = va_arg(args, int);
215 } else while (str[pos + 1] >= '0' && str[pos + 1] <= '9') {
217 precision += str[++pos] - '0';
227 flags |= leave_blank;
231 flags |= always_sign;
235 flags |= group_thousands;
239 if (flags & long_arg)
240 flags |= long_long_arg;
247 if (flags & long_arg)
248 flags |= short_short_arg;
259 flags |= ptrdiff_arg;
262 // Note that %z and other such "new" format characters are
263 // basically useless because some GCC coder actually went out
264 // of their way to make the compiler reject C99 format
265 // strings in C++ code, with no way of overriding it that I
266 // can find (the source code comments suggest the checking is
267 // only when using -pedantic, but I wasn't using -pedantic).
269 // Thus, we have the choice of either avoiding %z and friends
270 // (and possibly needing to insert hackish casts to silence
271 // the compiler's warnings if different architectures define
272 // types like size_t in different ways), or not using the
273 // format warnings at all.
275 // To mitigate this, 32-bit architectures should define
276 // pointer-sized special types as "long" rather than "int",
277 // so that %lx/%ld can always be used with them. Fixed-size
278 // 32-bit types should be declared as "int" rather than
279 // "long" for the same reason.
289 if ((flags & intmax_arg) || (flags & long_long_arg))
290 arg = va_arg(args, long long);
291 else if (flags & size_t_arg)
292 arg = va_arg(args, ssize_t);
293 else if (flags & ptrdiff_arg)
294 arg = va_arg(args, ptrdiff_t);
295 else if (flags & long_arg)
296 arg = va_arg(args, long);
297 else if (flags & short_short_arg)
298 arg = (signed char)va_arg(args, int);
299 else if (flags & short_arg)
300 arg = (short)va_arg(args, int);
302 arg = va_arg(args, int);
305 printf_num(buf, opos, size, arg, 10,
306 fieldwidth, precision, flags);
312 flags |= capital_hex;
326 if ((flags & intmax_arg) || (flags & long_long_arg))
327 arg = va_arg(args, unsigned long long);
328 else if (flags & size_t_arg)
329 arg = va_arg(args, size_t);
330 else if (flags & ptrdiff_arg)
331 arg = va_arg(args, intptr_t);
332 else if (flags & long_arg)
333 arg = va_arg(args, unsigned long);
334 else if (flags & short_short_arg)
335 arg = (unsigned char)va_arg(args, unsigned int);
336 else if (flags & short_arg)
337 arg = (unsigned short)va_arg(args, unsigned int);
338 else if (flags & short_short_arg)
339 arg = (signed char)va_arg(args, int);
340 else if (flags & short_arg)
341 arg = (short)va_arg(args, int);
343 arg = va_arg(args, unsigned int);
345 printf_num(buf, opos, size, arg, radix,
346 fieldwidth, precision, flags);
353 buf[opos] = va_arg(args, int);
360 const char *arg = va_arg(args, const char *);
365 size_t len = strlen(arg);
366 printf_string(buf, opos, size, arg, len);
372 const void *arg = va_arg(args, const void *);
374 printf_num(buf, opos, size, (ulong)arg, 16,
375 fieldwidth, precision, flags);
382 if ((flags & intmax_arg) || (flags & long_long_arg))
383 *va_arg(args, unsigned long long *) = opos;
384 else if (flags & size_t_arg)
385 *va_arg(args, ssize_t *) = opos;
386 else if (flags & ptrdiff_arg)
387 *va_arg(args, ptrdiff_t *) = opos;
388 else if (flags & long_arg)
389 *va_arg(args, long *) = opos;
390 else if (flags & short_short_arg)
391 *va_arg(args, signed char *) = opos;
392 else if (flags & short_arg)
393 *va_arg(args, short *) = opos;
395 *va_arg(args, int *) = opos;
401 default_case: // label for goto
404 buf[opos] = str[pos];
412 if (size > 0 && opos >= size)
418 size_t snprintf(char *buf, size_t size, const char *str, ...)
422 int ret = vsnprintf(buf, size, str, args);
427 size_t sprintf(char *buf, const char *str, ...)
431 int ret = vsnprintf(buf, ULONG_MAX, str, args);
436 void *memcpy(void *dest, const void *src, size_t len)
438 const char *cs = static_cast<const char *>(src);
439 char *cd = static_cast<char *>(dest);
441 for (size_t i = 0; i < len; i++)
447 void *memmove(void *dest, const void *src, size_t len)
450 return memcpy(dest, src, len);
452 const char *cs = static_cast<const char *>(src);
453 char *cd = static_cast<char *>(dest);
455 for (size_t i = len - 1; i >= 0; i--)
461 int memcmp(const void *b1, const void *b2, size_t len)
464 const char *c1 = static_cast<const char *>(b1);
465 const char *c2 = static_cast<const char *>(b2);
467 for (pos = 0; pos < len; pos++) {
468 if (c1[pos] != c2[pos])
469 return c1[pos] - c2[pos];
477 size_t strnlen(const char *s, size_t n)
480 while (pos < n && *s++)
485 size_t strlen(const char *s)
493 char *strcpy(char *dest, const char *src)
504 char *strncpy(char *dest, const char *src, size_t len)
519 char *strcat(char *dest, const char *src)
522 dest += strlen(dest);
531 char *strncat(char *dest, const char *src, size_t len)
534 int orig_len = strlen(dest);
550 void bzero(void *b, size_t len)
552 char *c = static_cast<char *>(b);
558 void *memset(void *b, int ch, size_t len)
560 char *c = static_cast<char *>(b);
568 #include <kern/pagealloc.h>
570 // Temporary hack until slab allocator is added
572 void *malloc(size_t len)
574 assert(len <= Arch::page_size - sizeof(size_t));
576 len = (len + sizeof(size_t) + Arch::page_size - 1) / Arch::page_size;
577 Mem::Page *page = Mem::PageAlloc::alloc(len);
579 size_t *ptr = (size_t *)Mem::page_to_kvirt(page);
585 void free(void *addr)
588 size_t *ptr = (size_t *)addr - 1;
590 Mem::Page *page = Mem::kvirt_to_page(addr);
591 Mem::PageAlloc::free(page, len);
595 void *operator new(size_t len)
600 void *operator new[](size_t len)
605 void operator delete(void *addr)
610 void operator delete[](void *addr)
615 extern "C" void __cxa_pure_virtual()
623 printf("abort() called in kernel\n");