xref: /nrf52832-nimble/rt-thread/src/kservice.c (revision 104654410c56c573564690304ae786df310c91fc)
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