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