Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • kernel/generic/src/lib/str.c

    r19f857a re535eeb  
    110110#include <align.h>
    111111#include <debug.h>
     112#include <macros.h>
    112113
    113114/** Byte mask consisting of lowest @n bits (out of 8) */
     
    537538 * null-terminated and containing only complete characters.
    538539 *
    539  * @param dest   Destination buffer.
     540 * @param dest  Destination buffer.
    540541 * @param count Size of the destination buffer (must be > 0).
    541542 * @param src   Source string.
     543 *
    542544 */
    543545void str_cpy(char *dest, size_t size, const char *src)
    544546{
    545         wchar_t ch;
    546         size_t src_off;
    547         size_t dest_off;
    548 
    549547        /* There must be space for a null terminator in the buffer. */
    550548        ASSERT(size > 0);
    551549       
    552         src_off = 0;
    553         dest_off = 0;
    554 
     550        size_t src_off = 0;
     551        size_t dest_off = 0;
     552       
     553        wchar_t ch;
    555554        while ((ch = str_decode(src, &src_off, STR_NO_LIMIT)) != 0) {
    556555                if (chr_encode(ch, dest, &dest_off, size - 1) != EOK)
    557556                        break;
    558557        }
    559 
     558       
    560559        dest[dest_off] = '\0';
    561560}
     
    571570 * have to be null-terminated.
    572571 *
    573  * @param dest   Destination buffer.
     572 * @param dest  Destination buffer.
    574573 * @param count Size of the destination buffer (must be > 0).
    575574 * @param src   Source string.
    576  * @param n     Maximum number of bytes to read from @a src.
     575 * @param n     Maximum number of bytes to read from @a src.
     576 *
    577577 */
    578578void str_ncpy(char *dest, size_t size, const char *src, size_t n)
    579579{
    580         wchar_t ch;
    581         size_t src_off;
    582         size_t dest_off;
    583 
    584580        /* There must be space for a null terminator in the buffer. */
    585581        ASSERT(size > 0);
    586582       
    587         src_off = 0;
    588         dest_off = 0;
    589 
     583        size_t src_off = 0;
     584        size_t dest_off = 0;
     585       
     586        wchar_t ch;
    590587        while ((ch = str_decode(src, &src_off, n)) != 0) {
    591588                if (chr_encode(ch, dest, &dest_off, size - 1) != EOK)
    592589                        break;
    593590        }
    594 
     591       
    595592        dest[dest_off] = '\0';
     593}
     594
     595/** Duplicate string.
     596 *
     597 * Allocate a new string and copy characters from the source
     598 * string into it. The duplicate string is allocated via sleeping
     599 * malloc(), thus this function can sleep in no memory conditions.
     600 *
     601 * The allocation cannot fail and the return value is always
     602 * a valid pointer. The duplicate string is always a well-formed
     603 * null-terminated UTF-8 string, but it can differ from the source
     604 * string on the byte level.
     605 *
     606 * @param src Source string.
     607 *
     608 * @return Duplicate string.
     609 *
     610 */
     611char *str_dup(const char *src)
     612{
     613        size_t size = str_size(src) + 1;
     614        char *dest = malloc(size, 0);
     615        ASSERT(dest);
     616       
     617        str_cpy(dest, size, src);
     618        return dest;
     619}
     620
     621/** Duplicate string with size limit.
     622 *
     623 * Allocate a new string and copy up to @max_size bytes from the source
     624 * string into it. The duplicate string is allocated via sleeping
     625 * malloc(), thus this function can sleep in no memory conditions.
     626 * No more than @max_size + 1 bytes is allocated, but if the size
     627 * occupied by the source string is smaller than @max_size + 1,
     628 * less is allocated.
     629 *
     630 * The allocation cannot fail and the return value is always
     631 * a valid pointer. The duplicate string is always a well-formed
     632 * null-terminated UTF-8 string, but it can differ from the source
     633 * string on the byte level.
     634 *
     635 * @param src Source string.
     636 * @param n   Maximum number of bytes to duplicate.
     637 *
     638 * @return Duplicate string.
     639 *
     640 */
     641char *str_ndup(const char *src, size_t n)
     642{
     643        size_t size = str_size(src);
     644        if (size > n)
     645                size = n;
     646       
     647        char *dest = malloc(size + 1, 0);
     648        ASSERT(dest);
     649       
     650        str_ncpy(dest, size + 1, src, size);
     651        return dest;
    596652}
    597653
     
    705761}
    706762
     763/** Convert string to uint64_t (internal variant).
     764 *
     765 * @param nptr   Pointer to string.
     766 * @param endptr Pointer to the first invalid character is stored here.
     767 * @param base   Zero or number between 2 and 36 inclusive.
     768 * @param neg    Indication of unary minus is stored here.
     769 * @apram result Result of the conversion.
     770 *
     771 * @return EOK if conversion was successful.
     772 *
     773 */
     774static int str_uint(const char *nptr, char **endptr, unsigned int base,
     775    bool *neg, uint64_t *result)
     776{
     777        ASSERT(endptr != NULL);
     778        ASSERT(neg != NULL);
     779        ASSERT(result != NULL);
     780       
     781        *neg = false;
     782        const char *str = nptr;
     783       
     784        /* Ignore leading whitespace */
     785        while (isspace(*str))
     786                str++;
     787       
     788        if (*str == '-') {
     789                *neg = true;
     790                str++;
     791        } else if (*str == '+')
     792                str++;
     793       
     794        if (base == 0) {
     795                /* Decode base if not specified */
     796                base = 10;
     797               
     798                if (*str == '0') {
     799                        base = 8;
     800                        str++;
     801                       
     802                        switch (*str) {
     803                        case 'b':
     804                        case 'B':
     805                                base = 2;
     806                                str++;
     807                                break;
     808                        case 'o':
     809                        case 'O':
     810                                base = 8;
     811                                str++;
     812                                break;
     813                        case 'd':
     814                        case 'D':
     815                        case 't':
     816                        case 'T':
     817                                base = 10;
     818                                str++;
     819                                break;
     820                        case 'x':
     821                        case 'X':
     822                                base = 16;
     823                                str++;
     824                                break;
     825                        }
     826                }
     827        } else {
     828                /* Check base range */
     829                if ((base < 2) || (base > 36)) {
     830                        *endptr = (char *) str;
     831                        return EINVAL;
     832                }
     833        }
     834       
     835        *result = 0;
     836        const char *startstr = str;
     837       
     838        while (*str != 0) {
     839                unsigned int digit;
     840               
     841                if ((*str >= 'a') && (*str <= 'z'))
     842                        digit = *str - 'a' + 10;
     843                else if ((*str >= 'A') && (*str <= 'Z'))
     844                        digit = *str - 'A' + 10;
     845                else if ((*str >= '0') && (*str <= '9'))
     846                        digit = *str - '0';
     847                else
     848                        break;
     849               
     850                if (digit >= base)
     851                        break;
     852               
     853                uint64_t prev = *result;
     854                *result = (*result) * base + digit;
     855               
     856                if (*result < prev) {
     857                        /* Overflow */
     858                        *endptr = (char *) str;
     859                        return EOVERFLOW;
     860                }
     861               
     862                str++;
     863        }
     864       
     865        if (str == startstr) {
     866                /*
     867                 * No digits were decoded => first invalid character is
     868                 * the first character of the string.
     869                 */
     870                str = nptr;
     871        }
     872       
     873        *endptr = (char *) str;
     874       
     875        if (str == nptr)
     876                return EINVAL;
     877       
     878        return EOK;
     879}
     880
     881/** Convert string to uint64_t.
     882 *
     883 * @param nptr   Pointer to string.
     884 * @param endptr If not NULL, pointer to the first invalid character
     885 *               is stored here.
     886 * @param base   Zero or number between 2 and 36 inclusive.
     887 * @param strict Do not allow any trailing characters.
     888 * @apram result Result of the conversion.
     889 *
     890 * @return EOK if conversion was successful.
     891 *
     892 */
     893int str_uint64(const char *nptr, char **endptr, unsigned int base,
     894    bool strict, uint64_t *result)
     895{
     896        ASSERT(result != NULL);
     897       
     898        bool neg;
     899        char *lendptr;
     900        int ret = str_uint(nptr, &lendptr, base, &neg, result);
     901       
     902        if (endptr != NULL)
     903                *endptr = (char *) lendptr;
     904       
     905        if (ret != EOK)
     906                return ret;
     907       
     908        /* Do not allow negative values */
     909        if (neg)
     910                return EINVAL;
     911       
     912        /* Check whether we are at the end of
     913           the string in strict mode */
     914        if ((strict) && (*lendptr != 0))
     915                return EINVAL;
     916       
     917        return EOK;
     918}
     919
     920void order_suffix(const uint64_t val, uint64_t *rv, char *suffix)
     921{
     922        if (val > 10000000000000000000ULL) {
     923                *rv = val / 1000000000000000000ULL;
     924                *suffix = 'Z';
     925        } else if (val > 1000000000000000000ULL) {
     926                *rv = val / 1000000000000000ULL;
     927                *suffix = 'E';
     928        } else if (val > 1000000000000000ULL) {
     929                *rv = val / 1000000000000ULL;
     930                *suffix = 'T';
     931        } else if (val > 1000000000000ULL) {
     932                *rv = val / 1000000000ULL;
     933                *suffix = 'G';
     934        } else if (val > 1000000000ULL) {
     935                *rv = val / 1000000ULL;
     936                *suffix = 'M';
     937        } else if (val > 1000000ULL) {
     938                *rv = val / 1000ULL;
     939                *suffix = 'k';
     940        } else {
     941                *rv = val;
     942                *suffix = ' ';
     943        }
     944}
     945
    707946/** @}
    708947 */
Note: See TracChangeset for help on using the changeset viewer.