1 /* 2 * Copyright (c) 2006-2018, RT-Thread Development Team 3 * 4 * SPDX-License-Identifier: Apache-2.0 5 * 6 * Change Logs: 7 * Date Author Notes 8 * 2006-03-16 Bernard the first version 9 * 2006-05-25 Bernard rewrite vsprintf 10 * 2006-08-10 Bernard add rt_show_version 11 * 2010-03-17 Bernard remove rt_strlcpy function 12 * fix gcc compiling issue. 13 * 2010-04-15 Bernard remove weak definition on ICCM16C compiler 14 * 2012-07-18 Arda add the alignment display for signed integer 15 * 2012-11-23 Bernard fix IAR compiler error. 16 * 2012-12-22 Bernard fix rt_kprintf issue, which found by Grissiom. 17 * 2013-06-24 Bernard remove rt_kprintf if RT_USING_CONSOLE is not defined. 18 * 2013-09-24 aozima make sure the device is in STREAM mode when used by rt_kprintf. 19 * 2015-07-06 Bernard Add rt_assert_handler routine. 20 */ 21 22 #include <rtthread.h> 23 #include <rthw.h> 24 25 #ifdef RT_USING_MODULE 26 #include <dlmodule.h> 27 #endif 28 29 /* use precision */ 30 #define RT_PRINTF_PRECISION 31 32 /** 33 * @addtogroup KernelService 34 */ 35 36 /**@{*/ 37 38 /* global errno in RT-Thread */ 39 static volatile int __rt_errno; 40 41 #if defined(RT_USING_DEVICE) && defined(RT_USING_CONSOLE) 42 static rt_device_t _console_device = RT_NULL; 43 #endif 44 45 /* 46 * This function will get errno 47 * 48 * @return errno 49 */ 50 rt_err_t rt_get_errno(void) 51 { 52 rt_thread_t tid; 53 54 if (rt_interrupt_get_nest() != 0) 55 { 56 /* it's in interrupt context */ 57 return __rt_errno; 58 } 59 60 tid = rt_thread_self(); 61 if (tid == RT_NULL) 62 return __rt_errno; 63 64 return tid->error; 65 } 66 RTM_EXPORT(rt_get_errno); 67 68 /* 69 * This function will set errno 70 * 71 * @param error the errno shall be set 72 */ 73 void rt_set_errno(rt_err_t error) 74 { 75 rt_thread_t tid; 76 77 if (rt_interrupt_get_nest() != 0) 78 { 79 /* it's in interrupt context */ 80 __rt_errno = error; 81 82 return; 83 } 84 85 tid = rt_thread_self(); 86 if (tid == RT_NULL) 87 { 88 __rt_errno = error; 89 90 return; 91 } 92 93 tid->error = error; 94 } 95 RTM_EXPORT(rt_set_errno); 96 97 /** 98 * This function returns errno. 99 * 100 * @return the errno in the system 101 */ 102 int *_rt_errno(void) 103 { 104 rt_thread_t tid; 105 106 if (rt_interrupt_get_nest() != 0) 107 return (int *)&__rt_errno; 108 109 tid = rt_thread_self(); 110 if (tid != RT_NULL) 111 return (int *) & (tid->error); 112 113 return (int *)&__rt_errno; 114 } 115 RTM_EXPORT(_rt_errno); 116 117 /** 118 * This function will set the content of memory to specified value 119 * 120 * @param s the address of source memory 121 * @param c the value shall be set in content 122 * @param count the copied length 123 * 124 * @return the address of source memory 125 */ 126 void *rt_memset(void *s, int c, rt_ubase_t count) 127 { 128 #ifdef RT_USING_TINY_SIZE 129 char *xs = (char *)s; 130 131 while (count--) 132 *xs++ = c; 133 134 return s; 135 #else 136 #define LBLOCKSIZE (sizeof(long)) 137 #define UNALIGNED(X) ((long)X & (LBLOCKSIZE - 1)) 138 #define TOO_SMALL(LEN) ((LEN) < LBLOCKSIZE) 139 140 unsigned int i; 141 char *m = (char *)s; 142 unsigned long buffer; 143 unsigned long *aligned_addr; 144 unsigned int d = c & 0xff; /* To avoid sign extension, copy C to an 145 unsigned variable. */ 146 147 if (!TOO_SMALL(count) && !UNALIGNED(s)) 148 { 149 /* If we get this far, we know that n is large and m is word-aligned. */ 150 aligned_addr = (unsigned long *)s; 151 152 /* Store D into each char sized location in BUFFER so that 153 * we can set large blocks quickly. 154 */ 155 if (LBLOCKSIZE == 4) 156 { 157 buffer = (d << 8) | d; 158 buffer |= (buffer << 16); 159 } 160 else 161 { 162 buffer = 0; 163 for (i = 0; i < LBLOCKSIZE; i ++) 164 buffer = (buffer << 8) | d; 165 } 166 167 while (count >= LBLOCKSIZE * 4) 168 { 169 *aligned_addr++ = buffer; 170 *aligned_addr++ = buffer; 171 *aligned_addr++ = buffer; 172 *aligned_addr++ = buffer; 173 count -= 4 * LBLOCKSIZE; 174 } 175 176 while (count >= LBLOCKSIZE) 177 { 178 *aligned_addr++ = buffer; 179 count -= LBLOCKSIZE; 180 } 181 182 /* Pick up the remainder with a bytewise loop. */ 183 m = (char *)aligned_addr; 184 } 185 186 while (count--) 187 { 188 *m++ = (char)d; 189 } 190 191 return s; 192 193 #undef LBLOCKSIZE 194 #undef UNALIGNED 195 #undef TOO_SMALL 196 #endif 197 } 198 RTM_EXPORT(rt_memset); 199 200 /** 201 * This function will copy memory content from source address to destination 202 * address. 203 * 204 * @param dst the address of destination memory 205 * @param src the address of source memory 206 * @param count the copied length 207 * 208 * @return the address of destination memory 209 */ 210 void *rt_memcpy(void *dst, const void *src, rt_ubase_t count) 211 { 212 #ifdef RT_USING_TINY_SIZE 213 char *tmp = (char *)dst, *s = (char *)src; 214 rt_ubase_t len; 215 216 if (tmp <= s || tmp > (s + count)) 217 { 218 while (count--) 219 *tmp ++ = *s ++; 220 } 221 else 222 { 223 for (len = count; len > 0; len --) 224 tmp[len - 1] = s[len - 1]; 225 } 226 227 return dst; 228 #else 229 230 #define UNALIGNED(X, Y) \ 231 (((long)X & (sizeof (long) - 1)) | ((long)Y & (sizeof (long) - 1))) 232 #define BIGBLOCKSIZE (sizeof (long) << 2) 233 #define LITTLEBLOCKSIZE (sizeof (long)) 234 #define TOO_SMALL(LEN) ((LEN) < BIGBLOCKSIZE) 235 236 char *dst_ptr = (char *)dst; 237 char *src_ptr = (char *)src; 238 long *aligned_dst; 239 long *aligned_src; 240 int len = count; 241 242 /* If the size is small, or either SRC or DST is unaligned, 243 then punt into the byte copy loop. This should be rare. */ 244 if (!TOO_SMALL(len) && !UNALIGNED(src_ptr, dst_ptr)) 245 { 246 aligned_dst = (long *)dst_ptr; 247 aligned_src = (long *)src_ptr; 248 249 /* Copy 4X long words at a time if possible. */ 250 while (len >= BIGBLOCKSIZE) 251 { 252 *aligned_dst++ = *aligned_src++; 253 *aligned_dst++ = *aligned_src++; 254 *aligned_dst++ = *aligned_src++; 255 *aligned_dst++ = *aligned_src++; 256 len -= BIGBLOCKSIZE; 257 } 258 259 /* Copy one long word at a time if possible. */ 260 while (len >= LITTLEBLOCKSIZE) 261 { 262 *aligned_dst++ = *aligned_src++; 263 len -= LITTLEBLOCKSIZE; 264 } 265 266 /* Pick up any residual with a byte copier. */ 267 dst_ptr = (char *)aligned_dst; 268 src_ptr = (char *)aligned_src; 269 } 270 271 while (len--) 272 *dst_ptr++ = *src_ptr++; 273 274 return dst; 275 #undef UNALIGNED 276 #undef BIGBLOCKSIZE 277 #undef LITTLEBLOCKSIZE 278 #undef TOO_SMALL 279 #endif 280 } 281 RTM_EXPORT(rt_memcpy); 282 283 /** 284 * This function will move memory content from source address to destination 285 * address. 286 * 287 * @param dest the address of destination memory 288 * @param src the address of source memory 289 * @param n the copied length 290 * 291 * @return the address of destination memory 292 */ 293 void *rt_memmove(void *dest, const void *src, rt_ubase_t n) 294 { 295 char *tmp = (char *)dest, *s = (char *)src; 296 297 if (s < tmp && tmp < s + n) 298 { 299 tmp += n; 300 s += n; 301 302 while (n--) 303 *(--tmp) = *(--s); 304 } 305 else 306 { 307 while (n--) 308 *tmp++ = *s++; 309 } 310 311 return dest; 312 } 313 RTM_EXPORT(rt_memmove); 314 315 /** 316 * This function will compare two areas of memory 317 * 318 * @param cs one area of memory 319 * @param ct znother area of memory 320 * @param count the size of the area 321 * 322 * @return the result 323 */ 324 rt_int32_t rt_memcmp(const void *cs, const void *ct, rt_ubase_t count) 325 { 326 const unsigned char *su1, *su2; 327 int res = 0; 328 329 for (su1 = cs, su2 = ct; 0 < count; ++su1, ++su2, count--) 330 if ((res = *su1 - *su2) != 0) 331 break; 332 333 return res; 334 } 335 RTM_EXPORT(rt_memcmp); 336 337 /** 338 * This function will return the first occurrence of a string. 339 * 340 * @param s1 the source string 341 * @param s2 the find string 342 * 343 * @return the first occurrence of a s2 in s1, or RT_NULL if no found. 344 */ 345 char *rt_strstr(const char *s1, const char *s2) 346 { 347 int l1, l2; 348 349 l2 = rt_strlen(s2); 350 if (!l2) 351 return (char *)s1; 352 l1 = rt_strlen(s1); 353 while (l1 >= l2) 354 { 355 l1 --; 356 if (!rt_memcmp(s1, s2, l2)) 357 return (char *)s1; 358 s1 ++; 359 } 360 361 return RT_NULL; 362 } 363 RTM_EXPORT(rt_strstr); 364 365 /** 366 * This function will compare two strings while ignoring differences in case 367 * 368 * @param a the string to be compared 369 * @param b the string to be compared 370 * 371 * @return the result 372 */ 373 rt_uint32_t rt_strcasecmp(const char *a, const char *b) 374 { 375 int ca, cb; 376 377 do 378 { 379 ca = *a++ & 0xff; 380 cb = *b++ & 0xff; 381 if (ca >= 'A' && ca <= 'Z') 382 ca += 'a' - 'A'; 383 if (cb >= 'A' && cb <= 'Z') 384 cb += 'a' - 'A'; 385 } 386 while (ca == cb && ca != '\0'); 387 388 return ca - cb; 389 } 390 RTM_EXPORT(rt_strcasecmp); 391 392 /** 393 * This function will copy string no more than n bytes. 394 * 395 * @param dst the string to copy 396 * @param src the string to be copied 397 * @param n the maximum copied length 398 * 399 * @return the result 400 */ 401 char *rt_strncpy(char *dst, const char *src, rt_ubase_t n) 402 { 403 if (n != 0) 404 { 405 char *d = dst; 406 const char *s = src; 407 408 do 409 { 410 if ((*d++ = *s++) == 0) 411 { 412 /* NUL pad the remaining n-1 bytes */ 413 while (--n != 0) 414 *d++ = 0; 415 break; 416 } 417 } while (--n != 0); 418 } 419 420 return (dst); 421 } 422 RTM_EXPORT(rt_strncpy); 423 424 /** 425 * This function will compare two strings with specified maximum length 426 * 427 * @param cs the string to be compared 428 * @param ct the string to be compared 429 * @param count the maximum compare length 430 * 431 * @return the result 432 */ 433 rt_int32_t rt_strncmp(const char *cs, const char *ct, rt_ubase_t count) 434 { 435 register signed char __res = 0; 436 437 while (count) 438 { 439 if ((__res = *cs - *ct++) != 0 || !*cs++) 440 break; 441 count --; 442 } 443 444 return __res; 445 } 446 RTM_EXPORT(rt_strncmp); 447 448 /** 449 * This function will compare two strings without specified length 450 * 451 * @param cs the string to be compared 452 * @param ct the string to be compared 453 * 454 * @return the result 455 */ 456 rt_int32_t rt_strcmp(const char *cs, const char *ct) 457 { 458 while (*cs && *cs == *ct) 459 cs++, ct++; 460 461 return (*cs - *ct); 462 } 463 RTM_EXPORT(rt_strcmp); 464 /** 465 * The strnlen() function returns the number of characters in the 466 * string pointed to by s, excluding the terminating null byte ('\0'), 467 * but at most maxlen. In doing this, strnlen() looks only at the 468 * first maxlen characters in the string pointed to by s and never 469 * beyond s+maxlen. 470 * 471 * @param s the string 472 * @param maxlen the max size 473 * @return the length of string 474 */ 475 rt_size_t rt_strnlen(const char *s, rt_ubase_t maxlen) 476 { 477 const char *sc; 478 479 for (sc = s; *sc != '\0' && sc - s < maxlen; ++sc) /* nothing */ 480 ; 481 482 return sc - s; 483 } 484 /** 485 * This function will return the length of a string, which terminate will 486 * null character. 487 * 488 * @param s the string 489 * 490 * @return the length of string 491 */ 492 rt_size_t rt_strlen(const char *s) 493 { 494 const char *sc; 495 496 for (sc = s; *sc != '\0'; ++sc) /* nothing */ 497 ; 498 499 return sc - s; 500 } 501 RTM_EXPORT(rt_strlen); 502 503 #ifdef RT_USING_HEAP 504 /** 505 * This function will duplicate a string. 506 * 507 * @param s the string to be duplicated 508 * 509 * @return the duplicated string pointer 510 */ 511 char *rt_strdup(const char *s) 512 { 513 rt_size_t len = rt_strlen(s) + 1; 514 char *tmp = (char *)rt_malloc(len); 515 516 if (!tmp) 517 return RT_NULL; 518 519 rt_memcpy(tmp, s, len); 520 521 return tmp; 522 } 523 RTM_EXPORT(rt_strdup); 524 #if defined(__CC_ARM) || defined(__CLANG_ARM) 525 char *strdup(const char *s) __attribute__((alias("rt_strdup"))); 526 #endif 527 #endif 528 529 /** 530 * This function will show the version of rt-thread rtos 531 */ 532 void rt_show_version(void) 533 { 534 rt_kprintf("\n \\ | /\n"); 535 rt_kprintf("- RT - Thread Operating System\n"); 536 rt_kprintf(" / | \\ %d.%d.%d build %s\n", 537 RT_VERSION, RT_SUBVERSION, RT_REVISION, __DATE__); 538 rt_kprintf(" 2006 - 2018 Copyright by rt-thread team\n"); 539 } 540 RTM_EXPORT(rt_show_version); 541 542 /* private function */ 543 #define isdigit(c) ((unsigned)((c) - '0') < 10) 544 545 rt_inline int divide(long *n, int base) 546 { 547 int res; 548 549 /* optimized for processor which does not support divide instructions. */ 550 if (base == 10) 551 { 552 res = (int)(((unsigned long)*n) % 10U); 553 *n = (long)(((unsigned long)*n) / 10U); 554 } 555 else 556 { 557 res = (int)(((unsigned long)*n) % 16U); 558 *n = (long)(((unsigned long)*n) / 16U); 559 } 560 561 return res; 562 } 563 564 rt_inline int skip_atoi(const char **s) 565 { 566 register int i = 0; 567 while (isdigit(**s)) 568 i = i * 10 + *((*s)++) - '0'; 569 570 return i; 571 } 572 573 #define ZEROPAD (1 << 0) /* pad with zero */ 574 #define SIGN (1 << 1) /* unsigned/signed long */ 575 #define PLUS (1 << 2) /* show plus */ 576 #define SPACE (1 << 3) /* space if plus */ 577 #define LEFT (1 << 4) /* left justified */ 578 #define SPECIAL (1 << 5) /* 0x */ 579 #define LARGE (1 << 6) /* use 'ABCDEF' instead of 'abcdef' */ 580 581 #ifdef RT_PRINTF_PRECISION 582 static char *print_number(char *buf, 583 char *end, 584 long num, 585 int base, 586 int s, 587 int precision, 588 int type) 589 #else 590 static char *print_number(char *buf, 591 char *end, 592 long num, 593 int base, 594 int s, 595 int type) 596 #endif 597 { 598 char c, sign; 599 #ifdef RT_PRINTF_LONGLONG 600 char tmp[32]; 601 #else 602 char tmp[16]; 603 #endif 604 int precision_bak = precision; 605 const char *digits; 606 static const char small_digits[] = "0123456789abcdef"; 607 static const char large_digits[] = "0123456789ABCDEF"; 608 register int i; 609 register int size; 610 611 size = s; 612 613 digits = (type & LARGE) ? large_digits : small_digits; 614 if (type & LEFT) 615 type &= ~ZEROPAD; 616 617 c = (type & ZEROPAD) ? '0' : ' '; 618 619 /* get sign */ 620 sign = 0; 621 if (type & SIGN) 622 { 623 if (num < 0) 624 { 625 sign = '-'; 626 num = -num; 627 } 628 else if (type & PLUS) 629 sign = '+'; 630 else if (type & SPACE) 631 sign = ' '; 632 } 633 634 #ifdef RT_PRINTF_SPECIAL 635 if (type & SPECIAL) 636 { 637 if (base == 16) 638 size -= 2; 639 else if (base == 8) 640 size--; 641 } 642 #endif 643 644 i = 0; 645 if (num == 0) 646 tmp[i++] = '0'; 647 else 648 { 649 while (num != 0) 650 tmp[i++] = digits[divide(&num, base)]; 651 } 652 653 #ifdef RT_PRINTF_PRECISION 654 if (i > precision) 655 precision = i; 656 size -= precision; 657 #else 658 size -= i; 659 #endif 660 661 if (!(type & (ZEROPAD | LEFT))) 662 { 663 if ((sign) && (size > 0)) 664 size--; 665 666 while (size-- > 0) 667 { 668 if (buf <= end) 669 *buf = ' '; 670 ++ buf; 671 } 672 } 673 674 if (sign) 675 { 676 if (buf <= end) 677 { 678 *buf = sign; 679 -- size; 680 } 681 ++ buf; 682 } 683 684 #ifdef RT_PRINTF_SPECIAL 685 if (type & SPECIAL) 686 { 687 if (base == 8) 688 { 689 if (buf <= end) 690 *buf = '0'; 691 ++ buf; 692 } 693 else if (base == 16) 694 { 695 if (buf <= end) 696 *buf = '0'; 697 ++ buf; 698 if (buf <= end) 699 { 700 *buf = type & LARGE ? 'X' : 'x'; 701 } 702 ++ buf; 703 } 704 } 705 #endif 706 707 /* no align to the left */ 708 if (!(type & LEFT)) 709 { 710 while (size-- > 0) 711 { 712 if (buf <= end) 713 *buf = c; 714 ++ buf; 715 } 716 } 717 718 #ifdef RT_PRINTF_PRECISION 719 while (i < precision--) 720 { 721 if (buf <= end) 722 *buf = '0'; 723 ++ buf; 724 } 725 #endif 726 727 /* put number in the temporary buffer */ 728 while (i-- > 0 && (precision_bak != 0)) 729 { 730 if (buf <= end) 731 *buf = tmp[i]; 732 ++ buf; 733 } 734 735 while (size-- > 0) 736 { 737 if (buf <= end) 738 *buf = ' '; 739 ++ buf; 740 } 741 742 return buf; 743 } 744 745 rt_int32_t rt_vsnprintf(char *buf, 746 rt_size_t size, 747 const char *fmt, 748 va_list args) 749 { 750 #ifdef RT_PRINTF_LONGLONG 751 unsigned long long num; 752 #else 753 rt_uint32_t num; 754 #endif 755 int i, len; 756 char *str, *end, c; 757 const char *s; 758 759 rt_uint8_t base; /* the base of number */ 760 rt_uint8_t flags; /* flags to print number */ 761 rt_uint8_t qualifier; /* 'h', 'l', or 'L' for integer fields */ 762 rt_int32_t field_width; /* width of output field */ 763 764 #ifdef RT_PRINTF_PRECISION 765 int precision; /* min. # of digits for integers and max for a string */ 766 #endif 767 768 str = buf; 769 end = buf + size - 1; 770 771 /* Make sure end is always >= buf */ 772 if (end < buf) 773 { 774 end = ((char *) - 1); 775 size = end - buf; 776 } 777 778 for (; *fmt ; ++fmt) 779 { 780 if (*fmt != '%') 781 { 782 if (str <= end) 783 *str = *fmt; 784 ++ str; 785 continue; 786 } 787 788 /* process flags */ 789 flags = 0; 790 791 while (1) 792 { 793 /* skips the first '%' also */ 794 ++ fmt; 795 if (*fmt == '-') flags |= LEFT; 796 else if (*fmt == '+') flags |= PLUS; 797 else if (*fmt == ' ') flags |= SPACE; 798 else if (*fmt == '#') flags |= SPECIAL; 799 else if (*fmt == '0') flags |= ZEROPAD; 800 else break; 801 } 802 803 /* get field width */ 804 field_width = -1; 805 if (isdigit(*fmt)) field_width = skip_atoi(&fmt); 806 else if (*fmt == '*') 807 { 808 ++ fmt; 809 /* it's the next argument */ 810 field_width = va_arg(args, int); 811 if (field_width < 0) 812 { 813 field_width = -field_width; 814 flags |= LEFT; 815 } 816 } 817 818 #ifdef RT_PRINTF_PRECISION 819 /* get the precision */ 820 precision = -1; 821 if (*fmt == '.') 822 { 823 ++ fmt; 824 if (isdigit(*fmt)) precision = skip_atoi(&fmt); 825 else if (*fmt == '*') 826 { 827 ++ fmt; 828 /* it's the next argument */ 829 precision = va_arg(args, int); 830 } 831 if (precision < 0) precision = 0; 832 } 833 #endif 834 /* get the conversion qualifier */ 835 qualifier = 0; 836 #ifdef RT_PRINTF_LONGLONG 837 if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L') 838 #else 839 if (*fmt == 'h' || *fmt == 'l') 840 #endif 841 { 842 qualifier = *fmt; 843 ++ fmt; 844 #ifdef RT_PRINTF_LONGLONG 845 if (qualifier == 'l' && *fmt == 'l') 846 { 847 qualifier = 'L'; 848 ++ fmt; 849 } 850 #endif 851 } 852 853 /* the default base */ 854 base = 10; 855 856 switch (*fmt) 857 { 858 case 'c': 859 if (!(flags & LEFT)) 860 { 861 while (--field_width > 0) 862 { 863 if (str <= end) *str = ' '; 864 ++ str; 865 } 866 } 867 868 /* get character */ 869 c = (rt_uint8_t)va_arg(args, int); 870 if (str <= end) *str = c; 871 ++ str; 872 873 /* put width */ 874 while (--field_width > 0) 875 { 876 if (str <= end) *str = ' '; 877 ++ str; 878 } 879 continue; 880 881 case 's': 882 s = va_arg(args, char *); 883 if (!s) s = "(NULL)"; 884 885 len = rt_strlen(s); 886 #ifdef RT_PRINTF_PRECISION 887 if (precision > 0 && len > precision) len = precision; 888 #endif 889 890 if (!(flags & LEFT)) 891 { 892 while (len < field_width--) 893 { 894 if (str <= end) *str = ' '; 895 ++ str; 896 } 897 } 898 899 for (i = 0; i < len; ++i) 900 { 901 if (str <= end) *str = *s; 902 ++ str; 903 ++ s; 904 } 905 906 while (len < field_width--) 907 { 908 if (str <= end) *str = ' '; 909 ++ str; 910 } 911 continue; 912 913 case 'p': 914 if (field_width == -1) 915 { 916 field_width = sizeof(void *) << 1; 917 flags |= ZEROPAD; 918 } 919 #ifdef RT_PRINTF_PRECISION 920 str = print_number(str, end, 921 (long)va_arg(args, void *), 922 16, field_width, precision, flags); 923 #else 924 str = print_number(str, end, 925 (long)va_arg(args, void *), 926 16, field_width, flags); 927 #endif 928 continue; 929 930 case '%': 931 if (str <= end) *str = '%'; 932 ++ str; 933 continue; 934 935 /* integer number formats - set up the flags and "break" */ 936 case 'o': 937 base = 8; 938 break; 939 940 case 'X': 941 flags |= LARGE; 942 case 'x': 943 base = 16; 944 break; 945 946 case 'd': 947 case 'i': 948 flags |= SIGN; 949 case 'u': 950 break; 951 952 default: 953 if (str <= end) *str = '%'; 954 ++ str; 955 956 if (*fmt) 957 { 958 if (str <= end) *str = *fmt; 959 ++ str; 960 } 961 else 962 { 963 -- fmt; 964 } 965 continue; 966 } 967 968 #ifdef RT_PRINTF_LONGLONG 969 if (qualifier == 'L') num = va_arg(args, long long); 970 else if (qualifier == 'l') 971 #else 972 if (qualifier == 'l') 973 #endif 974 { 975 num = va_arg(args, rt_uint32_t); 976 if (flags & SIGN) num = (rt_int32_t)num; 977 } 978 else if (qualifier == 'h') 979 { 980 num = (rt_uint16_t)va_arg(args, rt_int32_t); 981 if (flags & SIGN) num = (rt_int16_t)num; 982 } 983 else 984 { 985 num = va_arg(args, rt_uint32_t); 986 if (flags & SIGN) num = (rt_int32_t)num; 987 } 988 #ifdef RT_PRINTF_PRECISION 989 str = print_number(str, end, num, base, field_width, precision, flags); 990 #else 991 str = print_number(str, end, num, base, field_width, flags); 992 #endif 993 } 994 995 if (str <= end) *str = '\0'; 996 else *end = '\0'; 997 998 /* the trailing null byte doesn't count towards the total 999 * ++str; 1000 */ 1001 return str - buf; 1002 } 1003 RTM_EXPORT(rt_vsnprintf); 1004 1005 /** 1006 * This function will fill a formatted string to buffer 1007 * 1008 * @param buf the buffer to save formatted string 1009 * @param size the size of buffer 1010 * @param fmt the format 1011 */ 1012 rt_int32_t rt_snprintf(char *buf, rt_size_t size, const char *fmt, ...) 1013 { 1014 rt_int32_t n; 1015 va_list args; 1016 1017 va_start(args, fmt); 1018 n = rt_vsnprintf(buf, size, fmt, args); 1019 va_end(args); 1020 1021 return n; 1022 } 1023 RTM_EXPORT(rt_snprintf); 1024 1025 /** 1026 * This function will fill a formatted string to buffer 1027 * 1028 * @param buf the buffer to save formatted string 1029 * @param arg_ptr the arg_ptr 1030 * @param format the format 1031 */ 1032 rt_int32_t rt_vsprintf(char *buf, const char *format, va_list arg_ptr) 1033 { 1034 return rt_vsnprintf(buf, (rt_size_t) - 1, format, arg_ptr); 1035 } 1036 RTM_EXPORT(rt_vsprintf); 1037 1038 /** 1039 * This function will fill a formatted string to buffer 1040 * 1041 * @param buf the buffer to save formatted string 1042 * @param format the format 1043 */ 1044 rt_int32_t rt_sprintf(char *buf, const char *format, ...) 1045 { 1046 rt_int32_t n; 1047 va_list arg_ptr; 1048 1049 va_start(arg_ptr, format); 1050 n = rt_vsprintf(buf, format, arg_ptr); 1051 va_end(arg_ptr); 1052 1053 return n; 1054 } 1055 RTM_EXPORT(rt_sprintf); 1056 1057 #ifdef RT_USING_CONSOLE 1058 1059 #ifdef RT_USING_DEVICE 1060 /** 1061 * This function returns the device using in console. 1062 * 1063 * @return the device using in console or RT_NULL 1064 */ 1065 rt_device_t rt_console_get_device(void) 1066 { 1067 return _console_device; 1068 } 1069 RTM_EXPORT(rt_console_get_device); 1070 1071 /** 1072 * This function will set a device as console device. 1073 * After set a device to console, all output of rt_kprintf will be 1074 * redirected to this new device. 1075 * 1076 * @param name the name of new console device 1077 * 1078 * @return the old console device handler 1079 */ 1080 rt_device_t rt_console_set_device(const char *name) 1081 { 1082 rt_device_t new, old; 1083 1084 /* save old device */ 1085 old = _console_device; 1086 1087 /* find new console device */ 1088 new = rt_device_find(name); 1089 if (new != RT_NULL) 1090 { 1091 if (_console_device != RT_NULL) 1092 { 1093 /* close old console device */ 1094 rt_device_close(_console_device); 1095 } 1096 1097 /* set new console device */ 1098 rt_device_open(new, RT_DEVICE_OFLAG_RDWR | RT_DEVICE_FLAG_STREAM); 1099 _console_device = new; 1100 } 1101 1102 return old; 1103 } 1104 RTM_EXPORT(rt_console_set_device); 1105 #endif 1106 1107 RT_WEAK void rt_hw_console_output(const char *str) 1108 { 1109 /* empty console output */ 1110 } 1111 RTM_EXPORT(rt_hw_console_output); 1112 1113 /** 1114 * This function will put string to the console. 1115 * 1116 * @param str the string output to the console. 1117 */ 1118 void rt_kputs(const char *str) 1119 { 1120 if (!str) return; 1121 1122 #ifdef RT_USING_DEVICE 1123 if (_console_device == RT_NULL) 1124 { 1125 rt_hw_console_output(str); 1126 } 1127 else 1128 { 1129 rt_uint16_t old_flag = _console_device->open_flag; 1130 1131 _console_device->open_flag |= RT_DEVICE_FLAG_STREAM; 1132 rt_device_write(_console_device, 0, str, rt_strlen(str)); 1133 _console_device->open_flag = old_flag; 1134 } 1135 #else 1136 rt_hw_console_output(str); 1137 #endif 1138 } 1139 1140 /** 1141 * This function will print a formatted string on system console 1142 * 1143 * @param fmt the format 1144 */ 1145 void rt_kprintf(const char *fmt, ...) 1146 { 1147 va_list args; 1148 rt_size_t length; 1149 static char rt_log_buf[RT_CONSOLEBUF_SIZE]; 1150 1151 va_start(args, fmt); 1152 /* the return value of vsnprintf is the number of bytes that would be 1153 * written to buffer had if the size of the buffer been sufficiently 1154 * large excluding the terminating null byte. If the output string 1155 * would be larger than the rt_log_buf, we have to adjust the output 1156 * length. */ 1157 length = rt_vsnprintf(rt_log_buf, sizeof(rt_log_buf) - 1, fmt, args); 1158 if (length > RT_CONSOLEBUF_SIZE - 1) 1159 length = RT_CONSOLEBUF_SIZE - 1; 1160 #ifdef RT_USING_DEVICE 1161 if (_console_device == RT_NULL) 1162 { 1163 rt_hw_console_output(rt_log_buf); 1164 } 1165 else 1166 { 1167 rt_uint16_t old_flag = _console_device->open_flag; 1168 1169 _console_device->open_flag |= RT_DEVICE_FLAG_STREAM; 1170 rt_device_write(_console_device, 0, rt_log_buf, length); 1171 _console_device->open_flag = old_flag; 1172 } 1173 #else 1174 rt_hw_console_output(rt_log_buf); 1175 #endif 1176 va_end(args); 1177 } 1178 RTM_EXPORT(rt_kprintf); 1179 #endif 1180 1181 #ifdef RT_USING_HEAP 1182 /** 1183 * This function allocates a memory block, which address is aligned to the 1184 * specified alignment size. 1185 * 1186 * @param size the allocated memory block size 1187 * @param align the alignment size 1188 * 1189 * @return the allocated memory block on successful, otherwise returns RT_NULL 1190 */ 1191 void *rt_malloc_align(rt_size_t size, rt_size_t align) 1192 { 1193 void *ptr; 1194 void *align_ptr; 1195 int uintptr_size; 1196 rt_size_t align_size; 1197 1198 /* sizeof pointer */ 1199 uintptr_size = sizeof(void*); 1200 uintptr_size -= 1; 1201 1202 /* align the alignment size to uintptr size byte */ 1203 align = ((align + uintptr_size) & ~uintptr_size); 1204 1205 /* get total aligned size */ 1206 align_size = ((size + uintptr_size) & ~uintptr_size) + align; 1207 /* allocate memory block from heap */ 1208 ptr = rt_malloc(align_size); 1209 if (ptr != RT_NULL) 1210 { 1211 /* the allocated memory block is aligned */ 1212 if (((rt_ubase_t)ptr & (align - 1)) == 0) 1213 { 1214 align_ptr = (void *)((rt_ubase_t)ptr + align); 1215 } 1216 else 1217 { 1218 align_ptr = (void *)(((rt_ubase_t)ptr + (align - 1)) & ~(align - 1)); 1219 } 1220 1221 /* set the pointer before alignment pointer to the real pointer */ 1222 *((rt_ubase_t *)((rt_ubase_t)align_ptr - sizeof(void *))) = (rt_ubase_t)ptr; 1223 1224 ptr = align_ptr; 1225 } 1226 1227 return ptr; 1228 } 1229 RTM_EXPORT(rt_malloc_align); 1230 1231 /** 1232 * This function release the memory block, which is allocated by 1233 * rt_malloc_align function and address is aligned. 1234 * 1235 * @param ptr the memory block pointer 1236 */ 1237 void rt_free_align(void *ptr) 1238 { 1239 void *real_ptr; 1240 1241 real_ptr = (void *) * (rt_ubase_t *)((rt_ubase_t)ptr - sizeof(void *)); 1242 rt_free(real_ptr); 1243 } 1244 RTM_EXPORT(rt_free_align); 1245 #endif 1246 1247 #ifndef RT_USING_CPU_FFS 1248 const rt_uint8_t __lowest_bit_bitmap[] = 1249 { 1250 /* 00 */ 0, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 1251 /* 10 */ 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 1252 /* 20 */ 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 1253 /* 30 */ 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 1254 /* 40 */ 6, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 1255 /* 50 */ 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 1256 /* 60 */ 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 1257 /* 70 */ 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 1258 /* 80 */ 7, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 1259 /* 90 */ 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 1260 /* A0 */ 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 1261 /* B0 */ 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 1262 /* C0 */ 6, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 1263 /* D0 */ 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 1264 /* E0 */ 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 1265 /* F0 */ 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0 1266 }; 1267 1268 /** 1269 * This function finds the first bit set (beginning with the least significant bit) 1270 * in value and return the index of that bit. 1271 * 1272 * Bits are numbered starting at 1 (the least significant bit). A return value of 1273 * zero from any of these functions means that the argument was zero. 1274 * 1275 * @return return the index of the first bit set. If value is 0, then this function 1276 * shall return 0. 1277 */ 1278 int __rt_ffs(int value) 1279 { 1280 if (value == 0) return 0; 1281 1282 if (value & 0xff) 1283 return __lowest_bit_bitmap[value & 0xff] + 1; 1284 1285 if (value & 0xff00) 1286 return __lowest_bit_bitmap[(value & 0xff00) >> 8] + 9; 1287 1288 if (value & 0xff0000) 1289 return __lowest_bit_bitmap[(value & 0xff0000) >> 16] + 17; 1290 1291 return __lowest_bit_bitmap[(value & 0xff000000) >> 24] + 25; 1292 } 1293 #endif 1294 1295 #ifdef RT_DEBUG 1296 /* RT_ASSERT(EX)'s hook */ 1297 void (*rt_assert_hook)(const char *ex, const char *func, rt_size_t line); 1298 /** 1299 * This function will set a hook function to RT_ASSERT(EX). It will run when the expression is false. 1300 * 1301 * @param hook the hook function 1302 */ 1303 void rt_assert_set_hook(void (*hook)(const char *ex, const char *func, rt_size_t line)) 1304 { 1305 rt_assert_hook = hook; 1306 } 1307 1308 /** 1309 * The RT_ASSERT function. 1310 * 1311 * @param ex the assertion condition string 1312 * @param func the function name when assertion. 1313 * @param line the file line number when assertion. 1314 */ 1315 void rt_assert_handler(const char *ex_string, const char *func, rt_size_t line) 1316 { 1317 volatile char dummy = 0; 1318 1319 if (rt_assert_hook == RT_NULL) 1320 { 1321 #ifdef RT_USING_MODULE 1322 if (dlmodule_self()) 1323 { 1324 /* close assertion module */ 1325 dlmodule_exit(-1); 1326 } 1327 else 1328 #endif 1329 { 1330 rt_kprintf("(%s) assertion failed at function:%s, line number:%d \n", ex_string, func, line); 1331 while (dummy == 0); 1332 } 1333 } 1334 else 1335 { 1336 rt_assert_hook(ex_string, func, line); 1337 } 1338 } 1339 RTM_EXPORT(rt_assert_handler); 1340 #endif /* RT_DEBUG */ 1341 1342 #if !defined (RT_USING_NEWLIB) && defined (RT_USING_MINILIBC) && defined (__GNUC__) 1343 #include <sys/types.h> 1344 void *memcpy(void *dest, const void *src, size_t n) __attribute__((weak, alias("rt_memcpy"))); 1345 void *memset(void *s, int c, size_t n) __attribute__((weak, alias("rt_memset"))); 1346 void *memmove(void *dest, const void *src, size_t n) __attribute__((weak, alias("rt_memmove"))); 1347 int memcmp(const void *s1, const void *s2, size_t n) __attribute__((weak, alias("rt_memcmp"))); 1348 1349 size_t strlen(const char *s) __attribute__((weak, alias("rt_strlen"))); 1350 char *strstr(const char *s1, const char *s2) __attribute__((weak, alias("rt_strstr"))); 1351 int strcasecmp(const char *a, const char *b) __attribute__((weak, alias("rt_strcasecmp"))); 1352 char *strncpy(char *dest, const char *src, size_t n) __attribute__((weak, alias("rt_strncpy"))); 1353 int strncmp(const char *cs, const char *ct, size_t count) __attribute__((weak, alias("rt_strncmp"))); 1354 #ifdef RT_USING_HEAP 1355 char *strdup(const char *s) __attribute__((weak, alias("rt_strdup"))); 1356 #endif 1357 1358 int sprintf(char *buf, const char *format, ...) __attribute__((weak, alias("rt_sprintf"))); 1359 int snprintf(char *buf, rt_size_t size, const char *fmt, ...) __attribute__((weak, alias("rt_snprintf"))); 1360 int vsprintf(char *buf, const char *format, va_list arg_ptr) __attribute__((weak, alias("rt_vsprintf"))); 1361 1362 #endif 1363 1364 /**@}*/ 1365