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 condition:
12 // The above copyright notice and this permission notice shall be
13 // included in all copies or substantial portions of the Software.
15 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
17 // FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 // CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE
24 #include <kern/types.h>
25 #include <kern/libc.h>
30 // FIXME: Move printf to lib/kernel
32 static const int alt_form = 0x0001;
33 static const int zero_pad = 0x0002;
34 static const int neg_field = 0x0004;
35 static const int leave_blank = 0x0008;
36 static const int always_sign = 0x0010;
37 static const int group_thousands = 0x0020; // FIXME -- unimplemented
38 static const int long_arg = 0x0040;
39 static const int long_long_arg = 0x0080;
40 static const int short_arg = 0x0100;
41 static const int short_short_arg = 0x0200;
42 static const int intmax_arg = 0x0400;
43 static const int ptrdiff_arg = 0x0800;
44 static const int size_t_arg = 0x1000;
45 static const int capital_hex = 0x2000;
46 static const int num_signed = 0x4000;
47 static const int has_precision = 0x8000;
49 static void printf_string(char *buf, size_t &opos, size_t limit,
50 char *src, size_t len)
53 size_t olen = opos + len <= limit ? len : limit - opos;
54 memcpy(buf + opos, src, olen);
60 static void printf_fill(char *buf, size_t &opos, size_t limit,
64 size_t olen = opos + len <= limit ? len : limit - opos;
65 memset(buf + opos, ch, olen);
71 static void printf_num(char *obuf, size_t &opos, size_t limit,
72 s64 value, long radix, int fieldwidth,
73 int precision, int flags)
77 int letter = (flags & capital_hex) ? 'A' - 10 : 'a' - 10;
80 if (flags & num_signed)
81 uval = value < 0 ? -value : value;
85 // An explicit precision of 0 suppresses all output if the value
86 // is zero. Otherwise, the output size is not limited by precision
89 if (uval != 0 || !(flags & has_precision) || precision != 0) do {
90 int ch = uval % radix;
95 buf[pos] = ch + letter;
103 // length which counts against fieldwidth but not precision
106 if (flags & num_signed) {
108 printf_fill(obuf, opos, limit, '-', 1);
110 } else if (flags & always_sign) {
111 printf_fill(obuf, opos, limit, '+', 1);
113 } else if (flags & leave_blank) {
114 printf_fill(obuf, opos, limit, ' ', 1);
119 if ((flags & alt_form) && value != 0) {
120 if (radix == 8 && (!(flags & has_precision) || precision <= len)) {
121 flags |= has_precision;
126 printf_string(obuf, opos, limit, "0x", 2);
131 if ((flags & has_precision) && len < precision) {
140 if (!(flags & neg_field) && len < fieldwidth) {
141 char padchar = (flags & zero_pad) ? '0' : ' ';
142 printf_fill(obuf, opos, limit, padchar, fieldwidth - len);
146 if (precision != 0) {
147 printf_fill(obuf, opos, limit, '0', precision);
151 printf_string(obuf, opos, limit, buf + pos + 1, 64 - pos);
153 if ((flags & neg_field) && len < fieldwidth)
154 printf_fill(obuf, opos, limit, ' ', fieldwidth - len);
157 size_t vsnprintf(char *buf, size_t size, const char *str, va_list args)
159 size_t opos = 0; // position in the output string
160 unsigned int flags = 0;
166 for (size_t pos = 0; str[pos]; pos++) switch (state) {
168 if (str[pos] == '%') {
178 buf[opos] = str[pos];
183 case 1: // A percent has been seen; read in format characters
190 if (!(flags & has_precision)) {
198 if (flags & has_precision)
203 fieldwidth += str[pos++] - '0';
204 } while (str[pos] >= '0' && str[pos] <= '9');
210 if (fieldwidth || (flags & has_precision))
213 fieldwidth = va_arg(args, int);
217 flags |= has_precision;
219 if (str[pos + 1] == '*') {
221 precision = va_arg(args, int);
222 } else while (str[pos + 1] >= '0' && str[pos + 1] <= '9') {
224 precision += str[++pos] - '0';
234 flags |= leave_blank;
238 flags |= always_sign;
242 flags |= group_thousands;
246 if (flags & long_arg)
247 flags |= long_long_arg;
254 if (flags & long_arg)
255 flags |= short_short_arg;
266 flags |= ptrdiff_arg;
269 // Note that %z and other such "new" format characters are
270 // basically useless because some GCC coder actually went out
271 // of their way to make the compiler reject C99 format
272 // strings in C++ code, with no way of overriding it that I
273 // can find (the source code comments suggest the checking is
274 // only when using -pedantic, but I wasn't using -pedantic).
276 // Thus, we have the choice of either avoiding %z and friends
277 // (and possibly needing to insert hackish casts to silence
278 // the compiler's warnings if different architectures define
279 // types like size_t in different ways), or not using the
280 // format warnings at all.
282 // To mitigate this, 32-bit architectures should define
283 // pointer-sized special types as "long" rather than "int",
284 // so that %lx/%ld can always be used with them. Fixed-size
285 // 32-bit types should be declared as "int" rather than
286 // "long" for the same reason.
296 if ((flags & intmax_arg) || (flags & long_long_arg))
297 arg = va_arg(args, long long);
298 else if (flags & size_t_arg)
299 arg = va_arg(args, ssize_t);
300 else if (flags & ptrdiff_arg)
301 arg = va_arg(args, ptrdiff_t);
302 else if (flags & long_arg)
303 arg = va_arg(args, long);
304 else if (flags & short_short_arg)
305 arg = (signed char)va_arg(args, int);
306 else if (flags & short_arg)
307 arg = (short)va_arg(args, int);
309 arg = va_arg(args, int);
312 printf_num(buf, opos, size, arg, 10,
313 fieldwidth, precision, flags);
319 flags |= capital_hex;
333 if ((flags & intmax_arg) || (flags & long_long_arg))
334 arg = va_arg(args, unsigned long long);
335 else if (flags & size_t_arg)
336 arg = va_arg(args, size_t);
337 else if (flags & ptrdiff_arg)
338 arg = va_arg(args, intptr_t);
339 else if (flags & long_arg)
340 arg = va_arg(args, unsigned long);
341 else if (flags & short_short_arg)
342 arg = (unsigned char)va_arg(args, unsigned int);
343 else if (flags & short_arg)
344 arg = (unsigned short)va_arg(args, unsigned int);
345 else if (flags & short_short_arg)
346 arg = (signed char)va_arg(args, int);
347 else if (flags & short_arg)
348 arg = (short)va_arg(args, int);
350 arg = va_arg(args, unsigned int);
352 printf_num(buf, opos, size, arg, radix,
353 fieldwidth, precision, flags);
360 buf[opos] = va_arg(args, int);
367 char *arg = va_arg(args, char *);
372 size_t len = strlen(arg);
373 printf_string(buf, opos, size, arg, len);
379 void *arg = va_arg(args, void *);
381 printf_num(buf, opos, size, (ulong)arg, 16,
382 fieldwidth, precision, flags);
389 if ((flags & intmax_arg) || (flags & long_long_arg))
390 *va_arg(args, unsigned long long *) = opos;
391 else if (flags & size_t_arg)
392 *va_arg(args, ssize_t *) = opos;
393 else if (flags & ptrdiff_arg)
394 *va_arg(args, ptrdiff_t *) = opos;
395 else if (flags & long_arg)
396 *va_arg(args, long *) = opos;
397 else if (flags & short_short_arg)
398 *va_arg(args, signed char *) = opos;
399 else if (flags & short_arg)
400 *va_arg(args, short *) = opos;
402 *va_arg(args, int *) = opos;
408 default_case: // label for goto
411 buf[opos] = str[pos];
419 if (size > 0 && opos >= size)
425 size_t snprintf(char *buf, size_t size, const char *str, ...)
429 int ret = vsnprintf(buf, size, str, args);
434 size_t sprintf(char *buf, const char *str, ...)
438 int ret = vsnprintf(buf, ULONG_MAX, str, args);
443 void *memcpy(void *dest, const void *src, size_t len)
445 const char *cs = static_cast<const char *>(src);
446 char *cd = static_cast<char *>(dest);
448 for (size_t i = 0; i < len; i++)
454 void *memmove(void *dest, const void *src, size_t len)
457 return memcpy(dest, src, len);
459 const char *cs = static_cast<const char *>(src);
460 char *cd = static_cast<char *>(dest);
462 for (size_t i = len - 1; i >= 0; i--)
468 int memcmp(const void *b1, const void *b2, size_t len)
471 const char *c1 = static_cast<const char *>(b1);
472 const char *c2 = static_cast<const char *>(b2);
474 for (pos = 0; pos < len; pos++) {
475 if (c1[pos] != c2[pos])
476 return c1[pos] - c2[pos];
484 size_t strnlen(const char *s, size_t n)
487 while (pos < n && *s++)
492 size_t strlen(const char *s)
500 char *strcpy(char *dest, const char *src)
511 char *strncpy(char *dest, const char *src, size_t len)
526 void bzero(void *b, size_t len)
528 char *c = static_cast<char *>(b);
534 void *memset(void *b, int ch, size_t len)
536 char *c = static_cast<char *>(b);
544 #include <kern/pagealloc.h>
546 // Temporary hack until slab allocator is added
548 void *malloc(size_t len)
550 len = (len + sizeof(size_t) + Arch::page_size - 1) / Arch::page_size;
551 Mem::Page *page = Mem::PageAlloc::alloc(len);
553 size_t *ptr = (size_t *)Mem::page_to_kvirt(page);
559 void free(void *addr)
562 size_t *ptr = (size_t *)addr;
565 Mem::Page *page = Mem::kvirt_to_page(addr);
566 Mem::PageAlloc::free(page, len);
570 void *operator new(size_t len)
575 void *operator new[](size_t len)
580 void operator delete(void *addr)
585 void operator delete[](void *addr)
590 extern "C" void __cxa_pure_virtual()
598 printf("abort() called in kernel\n");