Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • uspace/lib/c/generic/str.c

    r1c9bf292 r09ab0a9a  
    11/*
    2  * Copyright (c) 2001-2004 Jakub Jermar
    32 * Copyright (c) 2005 Martin Decky
    43 * Copyright (c) 2008 Jiri Svoboda
     
    3433 * @{
    3534 */
    36 
    37 /**
    38  * @file
    39  * @brief String functions.
    40  *
    41  * Strings and characters use the Universal Character Set (UCS). The standard
    42  * strings, called just strings are encoded in UTF-8. Wide strings (encoded
    43  * in UTF-32) are supported to a limited degree. A single character is
    44  * represented as wchar_t.@n
    45  *
    46  * Overview of the terminology:@n
    47  *
    48  *  Term                  Meaning
    49  *  --------------------  ----------------------------------------------------
    50  *  byte                  8 bits stored in uint8_t (unsigned 8 bit integer)
    51  *
    52  *  character             UTF-32 encoded Unicode character, stored in wchar_t
    53  *                        (signed 32 bit integer), code points 0 .. 1114111
    54  *                        are valid
    55  *
    56  *  ASCII character       7 bit encoded ASCII character, stored in char
    57  *                        (usually signed 8 bit integer), code points 0 .. 127
    58  *                        are valid
    59  *
    60  *  string                UTF-8 encoded NULL-terminated Unicode string, char *
    61  *
    62  *  wide string           UTF-32 encoded NULL-terminated Unicode string,
    63  *                        wchar_t *
    64  *
    65  *  [wide] string size    number of BYTES in a [wide] string (excluding
    66  *                        the NULL-terminator), size_t
    67  *
    68  *  [wide] string length  number of CHARACTERS in a [wide] string (excluding
    69  *                        the NULL-terminator), size_t
    70  *
    71  *  [wide] string width   number of display cells on a monospace display taken
    72  *                        by a [wide] string, size_t
    73  *
    74  *
    75  * Overview of string metrics:@n
    76  *
    77  *  Metric  Abbrev.  Type     Meaning
    78  *  ------  ------   ------   -------------------------------------------------
    79  *  size    n        size_t   number of BYTES in a string (excluding the
    80  *                            NULL-terminator)
    81  *
    82  *  length  l        size_t   number of CHARACTERS in a string (excluding the
    83  *                            null terminator)
    84  *
    85  *  width  w         size_t   number of display cells on a monospace display
    86  *                            taken by a string
    87  *
    88  *
    89  * Function naming prefixes:@n
    90  *
    91  *  chr_    operate on characters
    92  *  ascii_  operate on ASCII characters
    93  *  str_    operate on strings
    94  *  wstr_   operate on wide strings
    95  *
    96  *  [w]str_[n|l|w]  operate on a prefix limited by size, length
    97  *                  or width
    98  *
    99  *
    100  * A specific character inside a [wide] string can be referred to by:@n
    101  *
    102  *  pointer (char *, wchar_t *)
    103  *  byte offset (size_t)
    104  *  character index (size_t)
    105  *
     35/** @file
    10636 */
    10737
    10838#include <str.h>
    109 
     39#include <stddef.h>
     40#include <stdint.h>
     41#include <stdlib.h>
    11042#include <assert.h>
    11143#include <ctype.h>
    11244#include <errno.h>
    113 #include <stdbool.h>
    114 #include <stddef.h>
    115 #include <stdint.h>
    116 #include <stdlib.h>
    117 
    11845#include <align.h>
    11946#include <mem.h>
     47#include <limits.h>
    12048
    12149/** Check the condition if wchar_t is signed */
     
    819747        /* There must be space for a null terminator in the buffer. */
    820748        assert(size > 0);
    821         assert(src != NULL);
    822749
    823750        size_t src_off = 0;
     
    13841311{
    13851312        size_t size = str_size(src) + 1;
    1386         char *dest = malloc(size);
    1387         if (!dest)
    1388                 return NULL;
     1313        char *dest = (char *) malloc(size);
     1314        if (dest == NULL)
     1315                return (char *) NULL;
    13891316
    13901317        str_cpy(dest, size, src);
     
    14181345                size = n;
    14191346
    1420         char *dest = malloc(size + 1);
    1421         if (!dest)
    1422                 return NULL;
     1347        char *dest = (char *) malloc(size + 1);
     1348        if (dest == NULL)
     1349                return (char *) NULL;
    14231350
    14241351        str_ncpy(dest, size + 1, src, size);
     
    14711398        *end = '\0';
    14721399        return start;
     1400}
     1401
     1402/** Convert string to uint64_t (internal variant).
     1403 *
     1404 * @param nptr   Pointer to string.
     1405 * @param endptr Pointer to the first invalid character is stored here.
     1406 * @param base   Zero or number between 2 and 36 inclusive.
     1407 * @param neg    Indication of unary minus is stored here.
     1408 * @apram result Result of the conversion.
     1409 *
     1410 * @return EOK if conversion was successful.
     1411 *
     1412 */
     1413static errno_t str_uint(const char *nptr, char **endptr, unsigned int base,
     1414    bool *neg, uint64_t *result)
     1415{
     1416        assert(endptr != NULL);
     1417        assert(neg != NULL);
     1418        assert(result != NULL);
     1419
     1420        *neg = false;
     1421        const char *str = nptr;
     1422
     1423        /* Ignore leading whitespace */
     1424        while (isspace(*str))
     1425                str++;
     1426
     1427        if (*str == '-') {
     1428                *neg = true;
     1429                str++;
     1430        } else if (*str == '+')
     1431                str++;
     1432
     1433        if (base == 0) {
     1434                /* Decode base if not specified */
     1435                base = 10;
     1436
     1437                if (*str == '0') {
     1438                        base = 8;
     1439                        str++;
     1440
     1441                        switch (*str) {
     1442                        case 'b':
     1443                        case 'B':
     1444                                base = 2;
     1445                                str++;
     1446                                break;
     1447                        case 'o':
     1448                        case 'O':
     1449                                base = 8;
     1450                                str++;
     1451                                break;
     1452                        case 'd':
     1453                        case 'D':
     1454                        case 't':
     1455                        case 'T':
     1456                                base = 10;
     1457                                str++;
     1458                                break;
     1459                        case 'x':
     1460                        case 'X':
     1461                                base = 16;
     1462                                str++;
     1463                                break;
     1464                        default:
     1465                                str--;
     1466                        }
     1467                }
     1468        } else {
     1469                /* Check base range */
     1470                if ((base < 2) || (base > 36)) {
     1471                        *endptr = (char *) str;
     1472                        return EINVAL;
     1473                }
     1474        }
     1475
     1476        *result = 0;
     1477        const char *startstr = str;
     1478
     1479        while (*str != 0) {
     1480                unsigned int digit;
     1481
     1482                if ((*str >= 'a') && (*str <= 'z'))
     1483                        digit = *str - 'a' + 10;
     1484                else if ((*str >= 'A') && (*str <= 'Z'))
     1485                        digit = *str - 'A' + 10;
     1486                else if ((*str >= '0') && (*str <= '9'))
     1487                        digit = *str - '0';
     1488                else
     1489                        break;
     1490
     1491                if (digit >= base)
     1492                        break;
     1493
     1494                uint64_t prev = *result;
     1495                *result = (*result) * base + digit;
     1496
     1497                if (*result < prev) {
     1498                        /* Overflow */
     1499                        *endptr = (char *) str;
     1500                        return EOVERFLOW;
     1501                }
     1502
     1503                str++;
     1504        }
     1505
     1506        if (str == startstr) {
     1507                /*
     1508                 * No digits were decoded => first invalid character is
     1509                 * the first character of the string.
     1510                 */
     1511                str = nptr;
     1512        }
     1513
     1514        *endptr = (char *) str;
     1515
     1516        if (str == nptr)
     1517                return EINVAL;
     1518
     1519        return EOK;
     1520}
     1521
     1522/** Convert string to uint8_t.
     1523 *
     1524 * @param nptr   Pointer to string.
     1525 * @param endptr If not NULL, pointer to the first invalid character
     1526 *               is stored here.
     1527 * @param base   Zero or number between 2 and 36 inclusive.
     1528 * @param strict Do not allow any trailing characters.
     1529 * @param result Result of the conversion.
     1530 *
     1531 * @return EOK if conversion was successful.
     1532 *
     1533 */
     1534errno_t str_uint8_t(const char *nptr, const char **endptr, unsigned int base,
     1535    bool strict, uint8_t *result)
     1536{
     1537        assert(result != NULL);
     1538
     1539        bool neg;
     1540        char *lendptr;
     1541        uint64_t res;
     1542        errno_t ret = str_uint(nptr, &lendptr, base, &neg, &res);
     1543
     1544        if (endptr != NULL)
     1545                *endptr = (char *) lendptr;
     1546
     1547        if (ret != EOK)
     1548                return ret;
     1549
     1550        /* Do not allow negative values */
     1551        if (neg)
     1552                return EINVAL;
     1553
     1554        /*
     1555         * Check whether we are at the end of
     1556         * the string in strict mode
     1557         */
     1558        if ((strict) && (*lendptr != 0))
     1559                return EINVAL;
     1560
     1561        /* Check for overflow */
     1562        uint8_t _res = (uint8_t) res;
     1563        if (_res != res)
     1564                return EOVERFLOW;
     1565
     1566        *result = _res;
     1567
     1568        return EOK;
     1569}
     1570
     1571/** Convert string to uint16_t.
     1572 *
     1573 * @param nptr   Pointer to string.
     1574 * @param endptr If not NULL, pointer to the first invalid character
     1575 *               is stored here.
     1576 * @param base   Zero or number between 2 and 36 inclusive.
     1577 * @param strict Do not allow any trailing characters.
     1578 * @param result Result of the conversion.
     1579 *
     1580 * @return EOK if conversion was successful.
     1581 *
     1582 */
     1583errno_t str_uint16_t(const char *nptr, const char **endptr, unsigned int base,
     1584    bool strict, uint16_t *result)
     1585{
     1586        assert(result != NULL);
     1587
     1588        bool neg;
     1589        char *lendptr;
     1590        uint64_t res;
     1591        errno_t ret = str_uint(nptr, &lendptr, base, &neg, &res);
     1592
     1593        if (endptr != NULL)
     1594                *endptr = (char *) lendptr;
     1595
     1596        if (ret != EOK)
     1597                return ret;
     1598
     1599        /* Do not allow negative values */
     1600        if (neg)
     1601                return EINVAL;
     1602
     1603        /*
     1604         * Check whether we are at the end of
     1605         * the string in strict mode
     1606         */
     1607        if ((strict) && (*lendptr != 0))
     1608                return EINVAL;
     1609
     1610        /* Check for overflow */
     1611        uint16_t _res = (uint16_t) res;
     1612        if (_res != res)
     1613                return EOVERFLOW;
     1614
     1615        *result = _res;
     1616
     1617        return EOK;
     1618}
     1619
     1620/** Convert string to uint32_t.
     1621 *
     1622 * @param nptr   Pointer to string.
     1623 * @param endptr If not NULL, pointer to the first invalid character
     1624 *               is stored here.
     1625 * @param base   Zero or number between 2 and 36 inclusive.
     1626 * @param strict Do not allow any trailing characters.
     1627 * @param result Result of the conversion.
     1628 *
     1629 * @return EOK if conversion was successful.
     1630 *
     1631 */
     1632errno_t str_uint32_t(const char *nptr, const char **endptr, unsigned int base,
     1633    bool strict, uint32_t *result)
     1634{
     1635        assert(result != NULL);
     1636
     1637        bool neg;
     1638        char *lendptr;
     1639        uint64_t res;
     1640        errno_t ret = str_uint(nptr, &lendptr, base, &neg, &res);
     1641
     1642        if (endptr != NULL)
     1643                *endptr = (char *) lendptr;
     1644
     1645        if (ret != EOK)
     1646                return ret;
     1647
     1648        /* Do not allow negative values */
     1649        if (neg)
     1650                return EINVAL;
     1651
     1652        /*
     1653         * Check whether we are at the end of
     1654         * the string in strict mode
     1655         */
     1656        if ((strict) && (*lendptr != 0))
     1657                return EINVAL;
     1658
     1659        /* Check for overflow */
     1660        uint32_t _res = (uint32_t) res;
     1661        if (_res != res)
     1662                return EOVERFLOW;
     1663
     1664        *result = _res;
     1665
     1666        return EOK;
     1667}
     1668
     1669/** Convert string to uint64_t.
     1670 *
     1671 * @param nptr   Pointer to string.
     1672 * @param endptr If not NULL, pointer to the first invalid character
     1673 *               is stored here.
     1674 * @param base   Zero or number between 2 and 36 inclusive.
     1675 * @param strict Do not allow any trailing characters.
     1676 * @param result Result of the conversion.
     1677 *
     1678 * @return EOK if conversion was successful.
     1679 *
     1680 */
     1681errno_t str_uint64_t(const char *nptr, const char **endptr, unsigned int base,
     1682    bool strict, uint64_t *result)
     1683{
     1684        assert(result != NULL);
     1685
     1686        bool neg;
     1687        char *lendptr;
     1688        errno_t ret = str_uint(nptr, &lendptr, base, &neg, result);
     1689
     1690        if (endptr != NULL)
     1691                *endptr = (char *) lendptr;
     1692
     1693        if (ret != EOK)
     1694                return ret;
     1695
     1696        /* Do not allow negative values */
     1697        if (neg)
     1698                return EINVAL;
     1699
     1700        /*
     1701         * Check whether we are at the end of
     1702         * the string in strict mode
     1703         */
     1704        if ((strict) && (*lendptr != 0))
     1705                return EINVAL;
     1706
     1707        return EOK;
     1708}
     1709
     1710/** Convert string to int64_t.
     1711 *
     1712 * @param nptr   Pointer to string.
     1713 * @param endptr If not NULL, pointer to the first invalid character
     1714 *               is stored here.
     1715 * @param base   Zero or number between 2 and 36 inclusive.
     1716 * @param strict Do not allow any trailing characters.
     1717 * @param result Result of the conversion.
     1718 *
     1719 * @return EOK if conversion was successful.
     1720 *
     1721 */
     1722int str_int64_t(const char *nptr, const char **endptr, unsigned int base,
     1723    bool strict, int64_t *result)
     1724{
     1725        assert(result != NULL);
     1726
     1727        bool neg;
     1728        char *lendptr;
     1729        uint64_t unsigned_result;
     1730        int ret = str_uint(nptr, &lendptr, base, &neg, &unsigned_result);
     1731
     1732        if (endptr != NULL)
     1733                *endptr = (char *) lendptr;
     1734
     1735        if (ret != EOK)
     1736                return ret;
     1737
     1738        /* Do not allow negative values */
     1739        if (neg) {
     1740                if (unsigned_result == UINT64_MAX)
     1741                        return EINVAL;
     1742
     1743                *result = -(int64_t) unsigned_result;
     1744        } else
     1745                *result = unsigned_result;
     1746
     1747        /*
     1748         * Check whether we are at the end of
     1749         * the string in strict mode
     1750         */
     1751        if ((strict) && (*lendptr != 0))
     1752                return EINVAL;
     1753
     1754        return EOK;
     1755}
     1756
     1757/** Convert string to size_t.
     1758 *
     1759 * @param nptr   Pointer to string.
     1760 * @param endptr If not NULL, pointer to the first invalid character
     1761 *               is stored here.
     1762 * @param base   Zero or number between 2 and 36 inclusive.
     1763 * @param strict Do not allow any trailing characters.
     1764 * @param result Result of the conversion.
     1765 *
     1766 * @return EOK if conversion was successful.
     1767 *
     1768 */
     1769errno_t str_size_t(const char *nptr, const char **endptr, unsigned int base,
     1770    bool strict, size_t *result)
     1771{
     1772        assert(result != NULL);
     1773
     1774        bool neg;
     1775        char *lendptr;
     1776        uint64_t res;
     1777        errno_t ret = str_uint(nptr, &lendptr, base, &neg, &res);
     1778
     1779        if (endptr != NULL)
     1780                *endptr = (char *) lendptr;
     1781
     1782        if (ret != EOK)
     1783                return ret;
     1784
     1785        /* Do not allow negative values */
     1786        if (neg)
     1787                return EINVAL;
     1788
     1789        /*
     1790         * Check whether we are at the end of
     1791         * the string in strict mode
     1792         */
     1793        if ((strict) && (*lendptr != 0))
     1794                return EINVAL;
     1795
     1796        /* Check for overflow */
     1797        size_t _res = (size_t) res;
     1798        if (_res != res)
     1799                return EOVERFLOW;
     1800
     1801        *result = _res;
     1802
     1803        return EOK;
    14731804}
    14741805
Note: See TracChangeset for help on using the changeset viewer.