kservice.c 32.6 KB
Newer Older
1 2 3
/*
 * File      : kservice.c
 * This file is part of RT-Thread RTOS
D
dzzxzz 已提交
4
 * COPYRIGHT (C) 2006 - 2012, RT-Thread Development Team
5
 *
B
Bernard Xiong 已提交
6 7 8 9 10 11 12 13 14 15 16 17 18
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License along
 *  with this program; if not, write to the Free Software Foundation, Inc.,
 *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 20 21 22 23 24
 *
 * Change Logs:
 * Date           Author       Notes
 * 2006-03-16     Bernard      the first version
 * 2006-05-25     Bernard      rewrite vsprintf
 * 2006-08-10     Bernard      add rt_show_version
B
bernard.xiong 已提交
25 26
 * 2010-03-17     Bernard      remove rt_strlcpy function
 *                             fix gcc compiling issue.
27
 * 2010-04-15     Bernard      remove weak definition on ICCM16C compiler
28
 * 2012-07-18     Arda         add the alignment display for signed integer
B
Bernard Xiong 已提交
29
 * 2012-11-23     Bernard      fix IAR compiler error.
30
 * 2012-12-22     Bernard      fix rt_kprintf issue, which found by Grissiom.
B
Bernard Xiong 已提交
31
 * 2013-06-24     Bernard      remove rt_kprintf if RT_USING_CONSOLE is not defined.
32
 * 2013-09-24     aozima       make sure the device is in STREAM mode when used by rt_kprintf.
33
 * 2015-07-06     Bernard      Add rt_assert_handler routine.
34 35 36 37 38
 */

#include <rtthread.h>
#include <rthw.h>

39 40 41 42
#ifdef RT_USING_MODULE
#include <dlmodule.h>
#endif

43 44 45
/* use precision */
#define RT_PRINTF_PRECISION

46 47 48
/**
 * @addtogroup KernelService
 */
D
dzzxzz 已提交
49

D
dogandog 已提交
50
/**@{*/
51

D
dzzxzz 已提交
52
/* global errno in RT-Thread */
B
bernard 已提交
53
static volatile int __rt_errno;
54

55
#if defined(RT_USING_DEVICE) && defined(RT_USING_CONSOLE)
B
bernard.xiong 已提交
56
static rt_device_t _console_device = RT_NULL;
57
#endif
58 59 60

/*
 * This function will get errno
B
bernard.xiong 已提交
61
 *
62 63 64 65
 * @return errno
 */
rt_err_t rt_get_errno(void)
{
66
    rt_thread_t tid;
B
bernard.xiong 已提交
67

68 69 70
    if (rt_interrupt_get_nest() != 0)
    {
        /* it's in interrupt context */
B
bernard 已提交
71
        return __rt_errno;
72
    }
73

74 75
    tid = rt_thread_self();
    if (tid == RT_NULL)
B
bernard 已提交
76
        return __rt_errno;
B
bernard.xiong 已提交
77

78
    return tid->error;
79
}
80
RTM_EXPORT(rt_get_errno);
81 82 83 84 85 86 87 88

/*
 * This function will set errno
 *
 * @param error the errno shall be set
 */
void rt_set_errno(rt_err_t error)
{
89
    rt_thread_t tid;
B
bernard.xiong 已提交
90

91 92 93
    if (rt_interrupt_get_nest() != 0)
    {
        /* it's in interrupt context */
B
bernard 已提交
94
        __rt_errno = error;
D
dzzxzz 已提交
95

96 97
        return;
    }
98

99 100 101
    tid = rt_thread_self();
    if (tid == RT_NULL)
    {
B
bernard 已提交
102
        __rt_errno = error;
B
Bernard Xiong 已提交
103

104 105
        return;
    }
B
bernard.xiong 已提交
106

107
    tid->error = error;
108
}
109
RTM_EXPORT(rt_set_errno);
110

111 112 113 114 115 116 117
/**
 * This function returns errno.
 *
 * @return the errno in the system
 */
int *_rt_errno(void)
{
118
    rt_thread_t tid;
B
Bernard Xiong 已提交
119

120
    if (rt_interrupt_get_nest() != 0)
B
bernard 已提交
121
        return (int *)&__rt_errno;
122

123 124
    tid = rt_thread_self();
    if (tid != RT_NULL)
125
        return (int *) & (tid->error);
126

B
bernard 已提交
127
    return (int *)&__rt_errno;
128
}
129
RTM_EXPORT(_rt_errno);
130

131 132 133 134 135 136 137 138 139
/**
 * This function will set the content of memory to specified value
 *
 * @param s the address of source memory
 * @param c the value shall be set in content
 * @param count the copied length
 *
 * @return the address of source memory
 */
D
dzzxzz 已提交
140
void *rt_memset(void *s, int c, rt_ubase_t count)
141
{
142
#ifdef RT_USING_TINY_SIZE
143
    char *xs = (char *)s;
144

145 146
    while (count--)
        *xs++ = c;
147

148
    return s;
149
#else
D
dzzxzz 已提交
150 151 152
#define LBLOCKSIZE      (sizeof(rt_int32_t))
#define UNALIGNED(X)    ((rt_int32_t)X & (LBLOCKSIZE - 1))
#define TOO_SMALL(LEN)  ((LEN) < LBLOCKSIZE)
153

154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204
    int i;
    char *m = (char *)s;
    rt_uint32_t buffer;
    rt_uint32_t *aligned_addr;
    rt_uint32_t d = c & 0xff;

    if (!TOO_SMALL(count) && !UNALIGNED(s))
    {
        /* If we get this far, we know that n is large and m is word-aligned. */
        aligned_addr = (rt_uint32_t *)s;

        /* Store D into each char sized location in BUFFER so that
         * we can set large blocks quickly.
         */
        if (LBLOCKSIZE == 4)
        {
            buffer = (d << 8) | d;
            buffer |= (buffer << 16);
        }
        else
        {
            buffer = 0;
            for (i = 0; i < LBLOCKSIZE; i ++)
                buffer = (buffer << 8) | d;
        }

        while (count >= LBLOCKSIZE * 4)
        {
            *aligned_addr++ = buffer;
            *aligned_addr++ = buffer;
            *aligned_addr++ = buffer;
            *aligned_addr++ = buffer;
            count -= 4 * LBLOCKSIZE;
        }

        while (count >= LBLOCKSIZE)
        {
            *aligned_addr++ = buffer;
            count -= LBLOCKSIZE;
        }

        /* Pick up the remainder with a bytewise loop. */
        m = (char *)aligned_addr;
    }

    while (count--)
    {
        *m++ = (char)d;
    }

    return s;
205 206 207 208 209 210

#undef LBLOCKSIZE
#undef UNALIGNED
#undef TOO_SMALL
#endif
}
211
RTM_EXPORT(rt_memset);
212 213 214 215 216 217 218 219 220 221 222

/**
 * This function will copy memory content from source address to destination
 * address.
 *
 * @param dst the address of destination memory
 * @param src  the address of source memory
 * @param count the copied length
 *
 * @return the address of destination memory
 */
D
dzzxzz 已提交
223
void *rt_memcpy(void *dst, const void *src, rt_ubase_t count)
224
{
225
#ifdef RT_USING_TINY_SIZE
226
    char *tmp = (char *)dst, *s = (char *)src;
227
    rt_ubase_t len;
E
emlslxl 已提交
228 229

    if (tmp <= s || tmp > (s + count))
230 231 232 233 234 235
    {
        while (count--)
            *tmp ++ = *s ++;
    }
    else
    {
E
emlslxl 已提交
236 237
        for (len = count; len > 0; len --)
            tmp[len - 1] = s[len - 1];
238
    }
239

E
emlslxl 已提交
240
    return dst;
241 242
#else

243 244 245
#define UNALIGNED(X, Y)                                               \
                        (((rt_int32_t)X & (sizeof(rt_int32_t) - 1)) | \
                         ((rt_int32_t)Y & (sizeof(rt_int32_t) - 1)))
D
dzzxzz 已提交
246 247
#define BIGBLOCKSIZE    (sizeof(rt_int32_t) << 2)
#define LITTLEBLOCKSIZE (sizeof(rt_int32_t))
248 249
#define TOO_SMALL(LEN)  ((LEN) < BIGBLOCKSIZE)

250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288
    char *dst_ptr = (char *)dst;
    char *src_ptr = (char *)src;
    rt_int32_t *aligned_dst;
    rt_int32_t *aligned_src;
    int len = count;

    /* If the size is small, or either SRC or DST is unaligned,
    then punt into the byte copy loop.  This should be rare. */
    if (!TOO_SMALL(len) && !UNALIGNED(src_ptr, dst_ptr))
    {
        aligned_dst = (rt_int32_t *)dst_ptr;
        aligned_src = (rt_int32_t *)src_ptr;

        /* Copy 4X long words at a time if possible. */
        while (len >= BIGBLOCKSIZE)
        {
            *aligned_dst++ = *aligned_src++;
            *aligned_dst++ = *aligned_src++;
            *aligned_dst++ = *aligned_src++;
            *aligned_dst++ = *aligned_src++;
            len -= BIGBLOCKSIZE;
        }

        /* Copy one long word at a time if possible. */
        while (len >= LITTLEBLOCKSIZE)
        {
            *aligned_dst++ = *aligned_src++;
            len -= LITTLEBLOCKSIZE;
        }

        /* Pick up any residual with a byte copier. */
        dst_ptr = (char *)aligned_dst;
        src_ptr = (char *)aligned_src;
    }

    while (len--)
        *dst_ptr++ = *src_ptr++;

    return dst;
289 290 291 292 293 294
#undef UNALIGNED
#undef BIGBLOCKSIZE
#undef LITTLEBLOCKSIZE
#undef TOO_SMALL
#endif
}
295
RTM_EXPORT(rt_memcpy);
296 297 298 299 300 301 302 303 304 305 306

/**
 * This function will move memory content from source address to destination
 * address.
 *
 * @param dest the address of destination memory
 * @param src  the address of source memory
 * @param n the copied length
 *
 * @return the address of destination memory
 */
D
dzzxzz 已提交
307
void *rt_memmove(void *dest, const void *src, rt_ubase_t n)
308
{
309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325
    char *tmp = (char *)dest, *s = (char *)src;

    if (s < tmp && tmp < s + n)
    {
        tmp += n;
        s += n;

        while (n--)
            *(--tmp) = *(--s);
    }
    else
    {
        while (n--)
            *tmp++ = *s++;
    }

    return dest;
326
}
327
RTM_EXPORT(rt_memmove);
328 329

/**
D
dzzxzz 已提交
330 331 332 333 334 335 336
 * This function will compare two areas of memory
 *
 * @param cs one area of memory
 * @param ct znother area of memory
 * @param count the size of the area
 *
 * @return the result
337
 */
D
dzzxzz 已提交
338
rt_int32_t rt_memcmp(const void *cs, const void *ct, rt_ubase_t count)
339
{
340 341
    const unsigned char *su1, *su2;
    int res = 0;
342

343 344 345
    for (su1 = cs, su2 = ct; 0 < count; ++su1, ++su2, count--)
        if ((res = *su1 - *su2) != 0)
            break;
D
dzzxzz 已提交
346

347
    return res;
348
}
349
RTM_EXPORT(rt_memcmp);
350 351 352 353 354 355 356 357 358

/**
 * This function will return the first occurrence of a string.
 *
 * @param s1 the source string
 * @param s2 the find string
 *
 * @return the first occurrence of a s2 in s1, or RT_NULL if no found.
 */
D
dzzxzz 已提交
359
char *rt_strstr(const char *s1, const char *s2)
360
{
361 362 363 364 365 366 367 368 369 370 371 372 373 374 375
    int l1, l2;

    l2 = rt_strlen(s2);
    if (!l2)
        return (char *)s1;
    l1 = rt_strlen(s1);
    while (l1 >= l2)
    {
        l1 --;
        if (!rt_memcmp(s1, s2, l2))
            return (char *)s1;
        s1 ++;
    }

    return RT_NULL;
376
}
377
RTM_EXPORT(rt_strstr);
378 379 380 381 382 383 384 385 386 387 388

/**
 * This function will compare two strings while ignoring differences in case
 *
 * @param a the string to be compared
 * @param b the string to be compared
 *
 * @return the result
 */
rt_uint32_t rt_strcasecmp(const char *a, const char *b)
{
389 390 391 392 393 394 395 396 397 398 399 400 401 402
    int ca, cb;

    do
    {
        ca = *a++ & 0xff;
        cb = *b++ & 0xff;
        if (ca >= 'A' && ca <= 'Z')
            ca += 'a' - 'A';
        if (cb >= 'A' && cb <= 'Z')
            cb += 'a' - 'A';
    }
    while (ca == cb && ca != '\0');

    return ca - cb;
403
}
404
RTM_EXPORT(rt_strcasecmp);
405 406 407 408

/**
 * This function will copy string no more than n bytes.
 *
409
 * @param dst the string to copy
410 411 412 413 414
 * @param src the string to be copied
 * @param n the maximum copied length
 *
 * @return the result
 */
415
char *rt_strncpy(char *dst, const char *src, rt_ubase_t n)
416
{
417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434
    if (n != 0)
    {
        char *d = dst;
        const char *s = src;

        do
        {
            if ((*d++ = *s++) == 0)
            {
                /* NUL pad the remaining n-1 bytes */
                while (--n != 0)
                    *d++ = 0;
                break;
            }
        } while (--n != 0);
    }

    return (dst);
435
}
436
RTM_EXPORT(rt_strncpy);
437 438 439 440 441 442 443 444 445 446

/**
 * This function will compare two strings with specified maximum length
 *
 * @param cs the string to be compared
 * @param ct the string to be compared
 * @param count the maximum compare length
 *
 * @return the result
 */
447
rt_int32_t rt_strncmp(const char *cs, const char *ct, rt_ubase_t count)
448
{
449
    register signed char __res = 0;
450

451 452 453 454 455 456
    while (count)
    {
        if ((__res = *cs - *ct++) != 0 || !*cs++)
            break;
        count --;
    }
457

458
    return __res;
459
}
460
RTM_EXPORT(rt_strncmp);
461

462 463 464 465 466 467 468 469
/**
 * This function will compare two strings without specified length
 *
 * @param cs the string to be compared
 * @param ct the string to be compared
 *
 * @return the result
 */
470
rt_int32_t rt_strcmp(const char *cs, const char *ct)
471
{
472 473
    while (*cs && *cs == *ct)
        cs++, ct++;
D
dzzxzz 已提交
474

475
    return (*cs - *ct);
476
}
477
RTM_EXPORT(rt_strcmp);
478 479
/**
 * The  strnlen()  function  returns the number of characters in the
480 481 482
 * string pointed to by s, excluding the terminating null byte ('\0'),
 * but at most maxlen.  In doing this, strnlen() looks only at the
 * first maxlen characters in the string pointed to by s and never
483 484 485 486 487 488 489 490 491 492 493 494
 * beyond s+maxlen.
 *
 * @param s the string
 * @param maxlen the max size
 * @return the length of string
 */
rt_size_t rt_strnlen(const char *s, rt_ubase_t maxlen)
{
    const char *sc;

    for (sc = s; *sc != '\0' && sc - s < maxlen; ++sc) /* nothing */
        ;
495

496 497
    return sc - s;
}
498 499 500 501 502 503 504 505
/**
 * This function will return the length of a string, which terminate will
 * null character.
 *
 * @param s the string
 *
 * @return the length of string
 */
506
rt_size_t rt_strlen(const char *s)
507
{
508
    const char *sc;
509

510 511
    for (sc = s; *sc != '\0'; ++sc) /* nothing */
        ;
512

513
    return sc - s;
514
}
515
RTM_EXPORT(rt_strlen);
516 517 518 519 520 521 522 523 524 525 526

#ifdef RT_USING_HEAP
/**
 * This function will duplicate a string.
 *
 * @param s the string to be duplicated
 *
 * @return the duplicated string pointer
 */
char *rt_strdup(const char *s)
{
527 528
    rt_size_t len = rt_strlen(s) + 1;
    char *tmp = (char *)rt_malloc(len);
529

530 531
    if (!tmp)
        return RT_NULL;
532

533
    rt_memcpy(tmp, s, len);
D
dzzxzz 已提交
534

535
    return tmp;
536
}
537
RTM_EXPORT(rt_strdup);
B
Bernard Xiong 已提交
538 539 540
#ifdef __CC_ARM
char *strdup(const char *s) __attribute__((alias("rt_strdup")));
#endif
541 542 543 544 545
#endif

/**
 * This function will show the version of rt-thread rtos
 */
D
dzzxzz 已提交
546
void rt_show_version(void)
547
{
548 549 550 551
    rt_kprintf("\n \\ | /\n");
    rt_kprintf("- RT -     Thread Operating System\n");
    rt_kprintf(" / | \\     %d.%d.%d build %s\n",
               RT_VERSION, RT_SUBVERSION, RT_REVISION, __DATE__);
552
    rt_kprintf(" 2006 - 2018 Copyright by rt-thread team\n");
553
}
554
RTM_EXPORT(rt_show_version);
555 556 557 558 559 560

/* private function */
#define isdigit(c)  ((unsigned)((c) - '0') < 10)

rt_inline rt_int32_t divide(rt_int32_t *n, rt_int32_t base)
{
561 562 563 564 565
    rt_int32_t res;

    /* optimized for processor which does not support divide instructions. */
    if (base == 10)
    {
566 567
        res = ((rt_uint32_t) * n) % 10U;
        *n = ((rt_uint32_t) * n) / 10U;
568 569 570
    }
    else
    {
571 572
        res = ((rt_uint32_t) * n) % 16U;
        *n = ((rt_uint32_t) * n) / 16U;
573 574 575
    }

    return res;
576 577 578 579
}

rt_inline int skip_atoi(const char **s)
{
580
    register int i = 0;
581 582
    while (isdigit(**s))
        i = i * 10 + *((*s)++) - '0';
583

584
    return i;
585 586
}

587 588 589 590 591 592 593
#define ZEROPAD     (1 << 0)    /* pad with zero */
#define SIGN        (1 << 1)    /* unsigned/signed long */
#define PLUS        (1 << 2)    /* show plus */
#define SPACE       (1 << 3)    /* space if plus */
#define LEFT        (1 << 4)    /* left justified */
#define SPECIAL     (1 << 5)    /* 0x */
#define LARGE       (1 << 6)    /* use 'ABCDEF' instead of 'abcdef' */
594 595

#ifdef RT_PRINTF_PRECISION
596 597 598 599 600 601 602
static char *print_number(char *buf,
                          char *end,
                          long  num,
                          int   base,
                          int   s,
                          int   precision,
                          int   type)
603
#else
604 605 606 607 608 609
static char *print_number(char *buf,
                          char *end,
                          long  num,
                          int   base,
                          int   s,
                          int   type)
610 611
#endif
{
612
    char c, sign;
613
#ifdef RT_PRINTF_LONGLONG
614
    char tmp[32];
615
#else
616
    char tmp[16];
617
#endif
618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645
    const char *digits;
    static const char small_digits[] = "0123456789abcdef";
    static const char large_digits[] = "0123456789ABCDEF";
    register int i;
    register int size;

    size = s;

    digits = (type & LARGE) ? large_digits : small_digits;
    if (type & LEFT)
        type &= ~ZEROPAD;

    c = (type & ZEROPAD) ? '0' : ' ';

    /* get sign */
    sign = 0;
    if (type & SIGN)
    {
        if (num < 0)
        {
            sign = '-';
            num = -num;
        }
        else if (type & PLUS)
            sign = '+';
        else if (type & SPACE)
            sign = ' ';
    }
646 647

#ifdef RT_PRINTF_SPECIAL
648 649 650 651 652 653 654
    if (type & SPECIAL)
    {
        if (base == 16)
            size -= 2;
        else if (base == 8)
            size--;
    }
655 656
#endif

657 658
    i = 0;
    if (num == 0)
659
        tmp[i++] = '0';
660 661 662 663 664
    else
    {
        while (num != 0)
            tmp[i++] = digits[divide(&num, base)];
    }
665 666

#ifdef RT_PRINTF_PRECISION
667 668 669
    if (i > precision)
        precision = i;
    size -= precision;
670
#else
671
    size -= i;
672 673
#endif

674
    if (!(type & (ZEROPAD | LEFT)))
675
    {
676
        if ((sign) && (size > 0))
677 678
            size--;

679
        while (size-- > 0)
680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695
        {
            if (buf <= end)
                *buf = ' ';
            ++ buf;
        }
    }

    if (sign)
    {
        if (buf <= end)
        {
            *buf = sign;
            -- size;
        }
        ++ buf;
    }
696 697

#ifdef RT_PRINTF_SPECIAL
698 699
    if (type & SPECIAL)
    {
700
        if (base == 8)
701 702 703 704 705 706 707 708 709 710 711 712
        {
            if (buf <= end)
                *buf = '0';
            ++ buf;
        }
        else if (base == 16)
        {
            if (buf <= end)
                *buf = '0';
            ++ buf;
            if (buf <= end)
            {
713
                *buf = type & LARGE ? 'X' : 'x';
714 715 716 717
            }
            ++ buf;
        }
    }
718 719
#endif

720 721 722 723 724 725 726 727 728 729
    /* no align to the left */
    if (!(type & LEFT))
    {
        while (size-- > 0)
        {
            if (buf <= end)
                *buf = c;
            ++ buf;
        }
    }
730 731

#ifdef RT_PRINTF_PRECISION
732 733 734 735 736 737
    while (i < precision--)
    {
        if (buf <= end)
            *buf = '0';
        ++ buf;
    }
738 739
#endif

740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755
    /* put number in the temporary buffer */
    while (i-- > 0)
    {
        if (buf <= end)
            *buf = tmp[i];
        ++ buf;
    }

    while (size-- > 0)
    {
        if (buf <= end)
            *buf = ' ';
        ++ buf;
    }

    return buf;
756 757
}

758 759 760 761
rt_int32_t rt_vsnprintf(char       *buf,
                        rt_size_t   size,
                        const char *fmt,
                        va_list     args)
762 763
{
#ifdef RT_PRINTF_LONGLONG
764
    unsigned long long num;
765
#else
766
    rt_uint32_t num;
767
#endif
768 769 770
    int i, len;
    char *str, *end, c;
    const char *s;
771

772 773 774 775
    rt_uint8_t base;            /* the base of number */
    rt_uint8_t flags;           /* flags to print number */
    rt_uint8_t qualifier;       /* 'h', 'l', or 'L' for integer fields */
    rt_int32_t field_width;     /* width of output field */
776 777

#ifdef RT_PRINTF_PRECISION
778
    int precision;      /* min. # of digits for integers and max for a string */
779 780
#endif

781 782 783 784 785 786
    str = buf;
    end = buf + size - 1;

    /* Make sure end is always >= buf */
    if (end < buf)
    {
787
        end  = ((char *) - 1);
788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829
        size = end - buf;
    }

    for (; *fmt ; ++fmt)
    {
        if (*fmt != '%')
        {
            if (str <= end)
                *str = *fmt;
            ++ str;
            continue;
        }

        /* process flags */
        flags = 0;

        while (1)
        {
            /* skips the first '%' also */
            ++ fmt;
            if (*fmt == '-') flags |= LEFT;
            else if (*fmt == '+') flags |= PLUS;
            else if (*fmt == ' ') flags |= SPACE;
            else if (*fmt == '#') flags |= SPECIAL;
            else if (*fmt == '0') flags |= ZEROPAD;
            else break;
        }

        /* get field width */
        field_width = -1;
        if (isdigit(*fmt)) field_width = skip_atoi(&fmt);
        else if (*fmt == '*')
        {
            ++ fmt;
            /* it's the next argument */
            field_width = va_arg(args, int);
            if (field_width < 0)
            {
                field_width = -field_width;
                flags |= LEFT;
            }
        }
830 831

#ifdef RT_PRINTF_PRECISION
832 833 834 835 836 837 838 839 840 841 842 843 844 845
        /* get the precision */
        precision = -1;
        if (*fmt == '.')
        {
            ++ fmt;
            if (isdigit(*fmt)) precision = skip_atoi(&fmt);
            else if (*fmt == '*')
            {
                ++ fmt;
                /* it's the next argument */
                precision = va_arg(args, int);
            }
            if (precision < 0) precision = 0;
        }
846
#endif
847 848
        /* get the conversion qualifier */
        qualifier = 0;
849
#ifdef RT_PRINTF_LONGLONG
850
        if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L')
851
#else
852
        if (*fmt == 'h' || *fmt == 'l')
853
#endif
854 855 856
        {
            qualifier = *fmt;
            ++ fmt;
857
#ifdef RT_PRINTF_LONGLONG
858 859 860 861 862
            if (qualifier == 'l' && *fmt == 'l')
            {
                qualifier = 'L';
                ++ fmt;
            }
863
#endif
864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898
        }

        /* the default base */
        base = 10;

        switch (*fmt)
        {
        case 'c':
            if (!(flags & LEFT))
            {
                while (--field_width > 0)
                {
                    if (str <= end) *str = ' ';
                    ++ str;
                }
            }

            /* get character */
            c = (rt_uint8_t)va_arg(args, int);
            if (str <= end) *str = c;
            ++ str;

            /* put width */
            while (--field_width > 0)
            {
                if (str <= end) *str = ' ';
                ++ str;
            }
            continue;

        case 's':
            s = va_arg(args, char *);
            if (!s) s = "(NULL)";

            len = rt_strlen(s);
899
#ifdef RT_PRINTF_PRECISION
900
            if (precision > 0 && len > precision) len = precision;
901 902
#endif

903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931
            if (!(flags & LEFT))
            {
                while (len < field_width--)
                {
                    if (str <= end) *str = ' ';
                    ++ str;
                }
            }

            for (i = 0; i < len; ++i)
            {
                if (str <= end) *str = *s;
                ++ str;
                ++ s;
            }

            while (len < field_width--)
            {
                if (str <= end) *str = ' ';
                ++ str;
            }
            continue;

        case 'p':
            if (field_width == -1)
            {
                field_width = sizeof(void *) << 1;
                flags |= ZEROPAD;
            }
932
#ifdef RT_PRINTF_PRECISION
933 934 935
            str = print_number(str, end,
                               (long)va_arg(args, void *),
                               16, field_width, precision, flags);
936
#else
937 938 939
            str = print_number(str, end,
                               (long)va_arg(args, void *),
                               16, field_width, flags);
940
#endif
941 942 943 944 945 946 947
            continue;

        case '%':
            if (str <= end) *str = '%';
            ++ str;
            continue;

948
        /* integer number formats - set up the flags and "break" */
949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979
        case 'o':
            base = 8;
            break;

        case 'X':
            flags |= LARGE;
        case 'x':
            base = 16;
            break;

        case 'd':
        case 'i':
            flags |= SIGN;
        case 'u':
            break;

        default:
            if (str <= end) *str = '%';
            ++ str;

            if (*fmt)
            {
                if (str <= end) *str = *fmt;
                ++ str;
            }
            else
            {
                -- fmt;
            }
            continue;
        }
980 981

#ifdef RT_PRINTF_LONGLONG
982 983
        if (qualifier == 'L') num = va_arg(args, long long);
        else if (qualifier == 'l')
984
#else
985
        if (qualifier == 'l')
986
#endif
987 988 989 990 991 992 993 994 995 996 997 998 999 1000
        {
            num = va_arg(args, rt_uint32_t);
            if (flags & SIGN) num = (rt_int32_t)num;
        }
        else if (qualifier == 'h')
        {
            num = (rt_uint16_t)va_arg(args, rt_int32_t);
            if (flags & SIGN) num = (rt_int16_t)num;
        }
        else
        {
            num = va_arg(args, rt_uint32_t);
            if (flags & SIGN) num = (rt_int32_t)num;
        }
1001
#ifdef RT_PRINTF_PRECISION
1002
        str = print_number(str, end, num, base, field_width, precision, flags);
1003
#else
1004
        str = print_number(str, end, num, base, field_width, flags);
1005
#endif
1006
    }
1007

1008 1009
    if (str <= end) *str = '\0';
    else *end = '\0';
1010

1011 1012 1013 1014
    /* the trailing null byte doesn't count towards the total
    * ++str;
    */
    return str - buf;
1015
}
1016
RTM_EXPORT(rt_vsnprintf);
1017 1018 1019 1020 1021 1022 1023 1024 1025 1026

/**
 * This function will fill a formatted string to buffer
 *
 * @param buf the buffer to save formatted string
 * @param size the size of buffer
 * @param fmt the format
 */
rt_int32_t rt_snprintf(char *buf, rt_size_t size, const char *fmt, ...)
{
1027 1028
    rt_int32_t n;
    va_list args;
1029

1030
    va_start(args, fmt);
1031
    n = rt_vsnprintf(buf, size, fmt, args);
1032
    va_end(args);
1033

1034
    return n;
1035
}
1036
RTM_EXPORT(rt_snprintf);
1037 1038 1039 1040 1041

/**
 * This function will fill a formatted string to buffer
 *
 * @param buf the buffer to save formatted string
B
bernard.xiong 已提交
1042
 * @param arg_ptr the arg_ptr
1043 1044 1045 1046
 * @param format the format
 */
rt_int32_t rt_vsprintf(char *buf, const char *format, va_list arg_ptr)
{
1047
    return rt_vsnprintf(buf, (rt_size_t) - 1, format, arg_ptr);
1048
}
1049
RTM_EXPORT(rt_vsprintf);
1050 1051 1052 1053 1054 1055 1056

/**
 * This function will fill a formatted string to buffer
 *
 * @param buf the buffer to save formatted string
 * @param format the format
 */
D
dzzxzz 已提交
1057
rt_int32_t rt_sprintf(char *buf, const char *format, ...)
1058
{
1059 1060
    rt_int32_t n;
    va_list arg_ptr;
B
bernard.xiong 已提交
1061

1062
    va_start(arg_ptr, format);
1063
    n = rt_vsprintf(buf, format, arg_ptr);
1064
    va_end(arg_ptr);
B
bernard.xiong 已提交
1065

1066
    return n;
1067
}
1068
RTM_EXPORT(rt_sprintf);
B
bernard.xiong 已提交
1069

1070 1071
#ifdef RT_USING_CONSOLE

1072
#ifdef RT_USING_DEVICE
1073 1074 1075 1076 1077 1078 1079
/**
 * This function returns the device using in console.
 *
 * @return the device using in console or RT_NULL
 */
rt_device_t rt_console_get_device(void)
{
1080
    return _console_device;
1081
}
1082
RTM_EXPORT(rt_console_get_device);
1083

1084
/**
B
bernard.xiong@gmail.com 已提交
1085
 * This function will set a device as console device.
1086
 * After set a device to console, all output of rt_kprintf will be
B
bernard.xiong@gmail.com 已提交
1087
 * redirected to this new device.
1088
 *
B
bernard.xiong@gmail.com 已提交
1089
 * @param name the name of new console device
1090
 *
B
bernard.xiong@gmail.com 已提交
1091
 * @return the old console device handler
1092
 */
D
dzzxzz 已提交
1093
rt_device_t rt_console_set_device(const char *name)
1094
{
1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110
    rt_device_t new, old;

    /* save old device */
    old = _console_device;

    /* find new console device */
    new = rt_device_find(name);
    if (new != RT_NULL)
    {
        if (_console_device != RT_NULL)
        {
            /* close old console device */
            rt_device_close(_console_device);
        }

        /* set new console device */
G
GalaIO 已提交
1111
        rt_device_open(new, RT_DEVICE_OFLAG_RDWR | RT_DEVICE_FLAG_STREAM);
1112 1113 1114 1115
        _console_device = new;
    }

    return old;
B
bernard.xiong 已提交
1116
}
1117
RTM_EXPORT(rt_console_set_device);
1118
#endif
1119

X
xieyangrun 已提交
1120
RT_WEAK void rt_hw_console_output(const char *str)
1121
{
1122
    /* empty console output */
1123
}
1124
RTM_EXPORT(rt_hw_console_output);
1125

B
bernard 已提交
1126 1127 1128 1129 1130 1131 1132
/**
 * This function will put string to the console.
 *
 * @param str the string output to the console.
 */
void rt_kputs(const char *str)
{
B
bernard 已提交
1133 1134
    if (!str) return;

B
bernard 已提交
1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152
#ifdef RT_USING_DEVICE
    if (_console_device == RT_NULL)
    {
        rt_hw_console_output(str);
    }
    else
    {
        rt_uint16_t old_flag = _console_device->open_flag;

        _console_device->open_flag |= RT_DEVICE_FLAG_STREAM;
        rt_device_write(_console_device, 0, str, rt_strlen(str));
        _console_device->open_flag = old_flag;
    }
#else
    rt_hw_console_output(str);
#endif
}

1153 1154 1155 1156 1157 1158 1159
/**
 * This function will print a formatted string on system console
 *
 * @param fmt the format
 */
void rt_kprintf(const char *fmt, ...)
{
1160 1161 1162 1163 1164 1165 1166 1167 1168 1169
    va_list args;
    rt_size_t length;
    static char rt_log_buf[RT_CONSOLEBUF_SIZE];

    va_start(args, fmt);
    /* the return value of vsnprintf is the number of bytes that would be
     * written to buffer had if the size of the buffer been sufficiently
     * large excluding the terminating null byte. If the output string
     * would be larger than the rt_log_buf, we have to adjust the output
     * length. */
1170
    length = rt_vsnprintf(rt_log_buf, sizeof(rt_log_buf) - 1, fmt, args);
1171 1172
    if (length > RT_CONSOLEBUF_SIZE - 1)
        length = RT_CONSOLEBUF_SIZE - 1;
1173
#ifdef RT_USING_DEVICE
1174 1175 1176 1177 1178 1179
    if (_console_device == RT_NULL)
    {
        rt_hw_console_output(rt_log_buf);
    }
    else
    {
1180
        rt_uint16_t old_flag = _console_device->open_flag;
1181

1182
        _console_device->open_flag |= RT_DEVICE_FLAG_STREAM;
1183
        rt_device_write(_console_device, 0, rt_log_buf, length);
1184
        _console_device->open_flag = old_flag;
1185
    }
1186
#else
1187
    rt_hw_console_output(rt_log_buf);
1188
#endif
1189
    va_end(args);
1190
}
1191
RTM_EXPORT(rt_kprintf);
1192
#endif
1193

1194 1195 1196 1197 1198 1199 1200 1201 1202 1203
#ifdef RT_USING_HEAP
/**
 * This function allocates a memory block, which address is aligned to the
 * specified alignment size.
 *
 * @param size the allocated memory block size
 * @param align the alignment size
 *
 * @return the allocated memory block on successful, otherwise returns RT_NULL
 */
1204
void *rt_malloc_align(rt_size_t size, rt_size_t align)
1205
{
1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218
    void *align_ptr;
    void *ptr;
    rt_size_t align_size;

    /* align the alignment size to 4 byte */
    align = ((align + 0x03) & ~0x03);

    /* get total aligned size */
    align_size = ((size + 0x03) & ~0x03) + align;
    /* allocate memory block from heap */
    ptr = rt_malloc(align_size);
    if (ptr != RT_NULL)
    {
1219
        /* the allocated memory block is aligned */
1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235
        if (((rt_uint32_t)ptr & (align - 1)) == 0)
        {
            align_ptr = (void *)((rt_uint32_t)ptr + align);
        }
        else
        {
            align_ptr = (void *)(((rt_uint32_t)ptr + (align - 1)) & ~(align - 1));
        }

        /* set the pointer before alignment pointer to the real pointer */
        *((rt_uint32_t *)((rt_uint32_t)align_ptr - sizeof(void *))) = (rt_uint32_t)ptr;

        ptr = align_ptr;
    }

    return ptr;
1236
}
1237
RTM_EXPORT(rt_malloc_align);
1238 1239

/**
1240 1241
 * This function release the memory block, which is allocated by
 * rt_malloc_align function and address is aligned.
1242 1243 1244
 *
 * @param ptr the memory block pointer
 */
D
dzzxzz 已提交
1245
void rt_free_align(void *ptr)
1246
{
1247
    void *real_ptr;
1248

1249
    real_ptr = (void *) * (rt_uint32_t *)((rt_uint32_t)ptr - sizeof(void *));
1250
    rt_free(real_ptr);
1251
}
1252
RTM_EXPORT(rt_free_align);
1253 1254
#endif

1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276
#ifndef RT_USING_CPU_FFS
const rt_uint8_t __lowest_bit_bitmap[] =
{
    /* 00 */ 0, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
    /* 10 */ 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
    /* 20 */ 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
    /* 30 */ 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
    /* 40 */ 6, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
    /* 50 */ 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
    /* 60 */ 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
    /* 70 */ 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
    /* 80 */ 7, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
    /* 90 */ 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
    /* A0 */ 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
    /* B0 */ 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
    /* C0 */ 6, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
    /* D0 */ 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
    /* E0 */ 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
    /* F0 */ 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0
};

/**
B
Bernard Xiong 已提交
1277
 * This function finds the first bit set (beginning with the least significant bit)
1278 1279
 * in value and return the index of that bit.
 *
B
Bernard Xiong 已提交
1280
 * Bits are numbered starting at 1 (the least significant bit).  A return value of
1281
 * zero from any of these functions means that the argument was zero.
B
Bernard Xiong 已提交
1282 1283
 *
 * @return return the index of the first bit set. If value is 0, then this function
1284 1285
 * shall return 0.
 */
B
bernard 已提交
1286
int __rt_ffs(int value)
1287 1288 1289 1290 1291 1292 1293 1294
{
    if (value == 0) return 0;

    if (value & 0xff)
        return __lowest_bit_bitmap[value & 0xff] + 1;

    if (value & 0xff00)
        return __lowest_bit_bitmap[(value & 0xff00) >> 8] + 9;
B
Bernard Xiong 已提交
1295

1296 1297
    if (value & 0xff0000)
        return __lowest_bit_bitmap[(value & 0xff0000) >> 16] + 17;
B
Bernard Xiong 已提交
1298

1299 1300 1301 1302
    return __lowest_bit_bitmap[(value & 0xff000000) >> 24] + 25;
}
#endif

armink_ztl's avatar
armink_ztl 已提交
1303 1304
#ifdef RT_DEBUG
/* RT_ASSERT(EX)'s hook */
1305
void (*rt_assert_hook)(const char *ex, const char *func, rt_size_t line);
armink_ztl's avatar
armink_ztl 已提交
1306 1307 1308 1309 1310
/**
 * This function will set a hook function to RT_ASSERT(EX). It will run when the expression is false.
 *
 * @param hook the hook function
 */
1311 1312
void rt_assert_set_hook(void (*hook)(const char *ex, const char *func, rt_size_t line))
{
armink_ztl's avatar
armink_ztl 已提交
1313 1314
    rt_assert_hook = hook;
}
1315 1316 1317 1318 1319 1320 1321 1322

/**
 * The RT_ASSERT function.
 *
 * @param ex the assertion condition string
 * @param func the function name when assertion.
 * @param line the file line number when assertion.
 */
1323
void rt_assert_handler(const char *ex_string, const char *func, rt_size_t line)
1324 1325 1326 1327 1328 1329
{
    volatile char dummy = 0;

    if (rt_assert_hook == RT_NULL)
    {
#ifdef RT_USING_MODULE
1330
        if (dlmodule_self())
1331
        {
1332 1333
            /* close assertion module */
            dlmodule_exit(-1);
1334 1335
        }
        else
1336
#endif
1337 1338 1339 1340
        {
            rt_kprintf("(%s) assertion failed at function:%s, line number:%d \n", ex_string, func, line);
            while (dummy == 0);
        }
1341
    }
1342 1343
    else
    {
1344
        rt_assert_hook(ex_string, func, line);
J
Jason Pan 已提交
1345
    }
1346 1347
}
RTM_EXPORT(rt_assert_handler);
armink_ztl's avatar
armink_ztl 已提交
1348 1349
#endif /* RT_DEBUG */

1350 1351
#if !defined (RT_USING_NEWLIB) && defined (RT_USING_MINILIBC) && defined (__GNUC__)
#include <sys/types.h>
D
dzzxzz 已提交
1352 1353 1354
void *memcpy(void *dest, const void *src, size_t n) __attribute__((weak, alias("rt_memcpy")));
void *memset(void *s, int c, size_t n) __attribute__((weak, alias("rt_memset")));
void *memmove(void *dest, const void *src, size_t n) __attribute__((weak, alias("rt_memmove")));
1355 1356 1357
int   memcmp(const void *s1, const void *s2, size_t n) __attribute__((weak, alias("rt_memcmp")));

size_t strlen(const char *s) __attribute__((weak, alias("rt_strlen")));
1358
char *strstr(const char *s1, const char *s2) __attribute__((weak, alias("rt_strstr")));
1359 1360
int strcasecmp(const char *a, const char *b) __attribute__((weak, alias("rt_strcasecmp")));
char *strncpy(char *dest, const char *src, size_t n) __attribute__((weak, alias("rt_strncpy")));
G
 
gary.li.wenchao.4 已提交
1361
int strncmp(const char *cs, const char *ct, size_t count) __attribute__((weak, alias("rt_strncmp")));
1362
#ifdef RT_USING_HEAP
G
 
gary.li.wenchao.4 已提交
1363
char *strdup(const char *s) __attribute__((weak, alias("rt_strdup")));
1364
#endif
1365

D
dzzxzz 已提交
1366
int sprintf(char *buf, const char *format, ...) __attribute__((weak, alias("rt_sprintf")));
1367 1368 1369
int snprintf(char *buf, rt_size_t size, const char *fmt, ...) __attribute__((weak, alias("rt_snprintf")));
int vsprintf(char *buf, const char *format, va_list arg_ptr) __attribute__((weak, alias("rt_vsprintf")));

1370 1371
#endif

D
dogandog 已提交
1372
/**@}*/