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 */
rt_get_errno(void)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 */
rt_set_errno(rt_err_t error)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 */
_rt_errno(void)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 */
rt_memset(void * s,int c,rt_ubase_t count)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 */
rt_memcpy(void * dst,const void * src,rt_ubase_t count)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 */
rt_memmove(void * dest,const void * src,rt_ubase_t n)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 */
rt_memcmp(const void * cs,const void * ct,rt_ubase_t count)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 */
rt_strstr(const char * s1,const char * s2)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 */
rt_strcasecmp(const char * a,const char * b)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 */
rt_strncpy(char * dst,const char * src,rt_ubase_t n)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 */
rt_strncmp(const char * cs,const char * ct,rt_ubase_t count)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 */
rt_strcmp(const char * cs,const char * ct)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 */
rt_strnlen(const char * s,rt_ubase_t maxlen)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 */
rt_strlen(const char * s)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 */
rt_strdup(const char * s)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 */
rt_show_version(void)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
divide(long * n,int base)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
skip_atoi(const char ** s)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
print_number(char * buf,char * end,long num,int base,int s,int precision,int type)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
rt_vsnprintf(char * buf,rt_size_t size,const char * fmt,va_list args)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 */
rt_snprintf(char * buf,rt_size_t size,const char * fmt,...)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 */
rt_vsprintf(char * buf,const char * format,va_list arg_ptr)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 */
rt_sprintf(char * buf,const char * format,...)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 */
rt_console_get_device(void)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 */
rt_console_set_device(const char * name)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
rt_hw_console_output(const char * str)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 */
rt_kputs(const char * str)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 */
rt_kprintf(const char * fmt,...)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 */
rt_malloc_align(rt_size_t size,rt_size_t align)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 */
rt_free_align(void * ptr)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 */
__rt_ffs(int value)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 */
rt_assert_set_hook(void (* hook)(const char * ex,const char * func,rt_size_t line))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 */
rt_assert_handler(const char * ex_string,const char * func,rt_size_t line)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