Fork us on GitHub Follow us on Facebook Follow us on Twitter

Changeset 1c9bf292 in mainline


Ignore:
Timestamp:
2019-05-27T20:27:49Z (20 months ago)
Author:
Jiří Zárevúcky <zarevucky.jiri@…>
Branches:
master
Children:
42e91ae
Parents:
dd0502ae
Message:

Reunite uspace string-to-int conversion functions

Location:
uspace/lib/c
Files:
4 edited

Legend:

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

    rdd0502ae r1c9bf292  
    14711471        *end = '\0';
    14721472        return start;
    1473 }
    1474 
    1475 /** Convert string to uint64_t (internal variant).
    1476  *
    1477  * @param nptr   Pointer to string.
    1478  * @param endptr Pointer to the first invalid character is stored here.
    1479  * @param base   Zero or number between 2 and 36 inclusive.
    1480  * @param neg    Indication of unary minus is stored here.
    1481  * @apram result Result of the conversion.
    1482  *
    1483  * @return EOK if conversion was successful.
    1484  *
    1485  */
    1486 static errno_t str_uint(const char *nptr, char **endptr, unsigned int base,
    1487     bool *neg, uint64_t *result)
    1488 {
    1489         assert(endptr != NULL);
    1490         assert(neg != NULL);
    1491         assert(result != NULL);
    1492 
    1493         *neg = false;
    1494         const char *str = nptr;
    1495 
    1496         /* Ignore leading whitespace */
    1497         while (isspace(*str))
    1498                 str++;
    1499 
    1500         if (*str == '-') {
    1501                 *neg = true;
    1502                 str++;
    1503         } else if (*str == '+')
    1504                 str++;
    1505 
    1506         if (base == 0) {
    1507                 /* Decode base if not specified */
    1508                 base = 10;
    1509 
    1510                 if (*str == '0') {
    1511                         base = 8;
    1512                         str++;
    1513 
    1514                         switch (*str) {
    1515                         case 'b':
    1516                         case 'B':
    1517                                 base = 2;
    1518                                 str++;
    1519                                 break;
    1520                         case 'o':
    1521                         case 'O':
    1522                                 base = 8;
    1523                                 str++;
    1524                                 break;
    1525                         case 'd':
    1526                         case 'D':
    1527                         case 't':
    1528                         case 'T':
    1529                                 base = 10;
    1530                                 str++;
    1531                                 break;
    1532                         case 'x':
    1533                         case 'X':
    1534                                 base = 16;
    1535                                 str++;
    1536                                 break;
    1537                         default:
    1538                                 str--;
    1539                         }
    1540                 }
    1541         } else {
    1542                 /* Check base range */
    1543                 if ((base < 2) || (base > 36)) {
    1544                         *endptr = (char *) str;
    1545                         return EINVAL;
    1546                 }
    1547         }
    1548 
    1549         *result = 0;
    1550         const char *startstr = str;
    1551 
    1552         while (*str != 0) {
    1553                 unsigned int digit;
    1554 
    1555                 if ((*str >= 'a') && (*str <= 'z'))
    1556                         digit = *str - 'a' + 10;
    1557                 else if ((*str >= 'A') && (*str <= 'Z'))
    1558                         digit = *str - 'A' + 10;
    1559                 else if ((*str >= '0') && (*str <= '9'))
    1560                         digit = *str - '0';
    1561                 else
    1562                         break;
    1563 
    1564                 if (digit >= base)
    1565                         break;
    1566 
    1567                 uint64_t prev = *result;
    1568                 *result = (*result) * base + digit;
    1569 
    1570                 if (*result < prev) {
    1571                         /* Overflow */
    1572                         *endptr = (char *) str;
    1573                         return EOVERFLOW;
    1574                 }
    1575 
    1576                 str++;
    1577         }
    1578 
    1579         if (str == startstr) {
    1580                 /*
    1581                  * No digits were decoded => first invalid character is
    1582                  * the first character of the string.
    1583                  */
    1584                 str = nptr;
    1585         }
    1586 
    1587         *endptr = (char *) str;
    1588 
    1589         if (str == nptr)
    1590                 return EINVAL;
    1591 
    1592         return EOK;
    1593 }
    1594 
    1595 /** Convert string to uint8_t.
    1596  *
    1597  * @param nptr   Pointer to string.
    1598  * @param endptr If not NULL, pointer to the first invalid character
    1599  *               is stored here.
    1600  * @param base   Zero or number between 2 and 36 inclusive.
    1601  * @param strict Do not allow any trailing characters.
    1602  * @param result Result of the conversion.
    1603  *
    1604  * @return EOK if conversion was successful.
    1605  *
    1606  */
    1607 errno_t str_uint8_t(const char *nptr, const char **endptr, unsigned int base,
    1608     bool strict, uint8_t *result)
    1609 {
    1610         assert(result != NULL);
    1611 
    1612         bool neg;
    1613         char *lendptr;
    1614         uint64_t res;
    1615         errno_t ret = str_uint(nptr, &lendptr, base, &neg, &res);
    1616 
    1617         if (endptr != NULL)
    1618                 *endptr = (char *) lendptr;
    1619 
    1620         if (ret != EOK)
    1621                 return ret;
    1622 
    1623         /* Do not allow negative values */
    1624         if (neg)
    1625                 return EINVAL;
    1626 
    1627         /*
    1628          * Check whether we are at the end of
    1629          * the string in strict mode
    1630          */
    1631         if ((strict) && (*lendptr != 0))
    1632                 return EINVAL;
    1633 
    1634         /* Check for overflow */
    1635         uint8_t _res = (uint8_t) res;
    1636         if (_res != res)
    1637                 return EOVERFLOW;
    1638 
    1639         *result = _res;
    1640 
    1641         return EOK;
    1642 }
    1643 
    1644 /** Convert string to uint16_t.
    1645  *
    1646  * @param nptr   Pointer to string.
    1647  * @param endptr If not NULL, pointer to the first invalid character
    1648  *               is stored here.
    1649  * @param base   Zero or number between 2 and 36 inclusive.
    1650  * @param strict Do not allow any trailing characters.
    1651  * @param result Result of the conversion.
    1652  *
    1653  * @return EOK if conversion was successful.
    1654  *
    1655  */
    1656 errno_t str_uint16_t(const char *nptr, const char **endptr, unsigned int base,
    1657     bool strict, uint16_t *result)
    1658 {
    1659         assert(result != NULL);
    1660 
    1661         bool neg;
    1662         char *lendptr;
    1663         uint64_t res;
    1664         errno_t ret = str_uint(nptr, &lendptr, base, &neg, &res);
    1665 
    1666         if (endptr != NULL)
    1667                 *endptr = (char *) lendptr;
    1668 
    1669         if (ret != EOK)
    1670                 return ret;
    1671 
    1672         /* Do not allow negative values */
    1673         if (neg)
    1674                 return EINVAL;
    1675 
    1676         /*
    1677          * Check whether we are at the end of
    1678          * the string in strict mode
    1679          */
    1680         if ((strict) && (*lendptr != 0))
    1681                 return EINVAL;
    1682 
    1683         /* Check for overflow */
    1684         uint16_t _res = (uint16_t) res;
    1685         if (_res != res)
    1686                 return EOVERFLOW;
    1687 
    1688         *result = _res;
    1689 
    1690         return EOK;
    1691 }
    1692 
    1693 /** Convert string to uint32_t.
    1694  *
    1695  * @param nptr   Pointer to string.
    1696  * @param endptr If not NULL, pointer to the first invalid character
    1697  *               is stored here.
    1698  * @param base   Zero or number between 2 and 36 inclusive.
    1699  * @param strict Do not allow any trailing characters.
    1700  * @param result Result of the conversion.
    1701  *
    1702  * @return EOK if conversion was successful.
    1703  *
    1704  */
    1705 errno_t str_uint32_t(const char *nptr, const char **endptr, unsigned int base,
    1706     bool strict, uint32_t *result)
    1707 {
    1708         assert(result != NULL);
    1709 
    1710         bool neg;
    1711         char *lendptr;
    1712         uint64_t res;
    1713         errno_t ret = str_uint(nptr, &lendptr, base, &neg, &res);
    1714 
    1715         if (endptr != NULL)
    1716                 *endptr = (char *) lendptr;
    1717 
    1718         if (ret != EOK)
    1719                 return ret;
    1720 
    1721         /* Do not allow negative values */
    1722         if (neg)
    1723                 return EINVAL;
    1724 
    1725         /*
    1726          * Check whether we are at the end of
    1727          * the string in strict mode
    1728          */
    1729         if ((strict) && (*lendptr != 0))
    1730                 return EINVAL;
    1731 
    1732         /* Check for overflow */
    1733         uint32_t _res = (uint32_t) res;
    1734         if (_res != res)
    1735                 return EOVERFLOW;
    1736 
    1737         *result = _res;
    1738 
    1739         return EOK;
    1740 }
    1741 
    1742 /** Convert string to uint64_t.
    1743  *
    1744  * @param nptr   Pointer to string.
    1745  * @param endptr If not NULL, pointer to the first invalid character
    1746  *               is stored here.
    1747  * @param base   Zero or number between 2 and 36 inclusive.
    1748  * @param strict Do not allow any trailing characters.
    1749  * @param result Result of the conversion.
    1750  *
    1751  * @return EOK if conversion was successful.
    1752  *
    1753  */
    1754 errno_t str_uint64_t(const char *nptr, const char **endptr, unsigned int base,
    1755     bool strict, uint64_t *result)
    1756 {
    1757         assert(result != NULL);
    1758 
    1759         bool neg;
    1760         char *lendptr;
    1761         errno_t ret = str_uint(nptr, &lendptr, base, &neg, result);
    1762 
    1763         if (endptr != NULL)
    1764                 *endptr = (char *) lendptr;
    1765 
    1766         if (ret != EOK)
    1767                 return ret;
    1768 
    1769         /* Do not allow negative values */
    1770         if (neg)
    1771                 return EINVAL;
    1772 
    1773         /*
    1774          * Check whether we are at the end of
    1775          * the string in strict mode
    1776          */
    1777         if ((strict) && (*lendptr != 0))
    1778                 return EINVAL;
    1779 
    1780         return EOK;
    1781 }
    1782 
    1783 /** Convert string to int64_t.
    1784  *
    1785  * @param nptr   Pointer to string.
    1786  * @param endptr If not NULL, pointer to the first invalid character
    1787  *               is stored here.
    1788  * @param base   Zero or number between 2 and 36 inclusive.
    1789  * @param strict Do not allow any trailing characters.
    1790  * @param result Result of the conversion.
    1791  *
    1792  * @return EOK if conversion was successful.
    1793  *
    1794  */
    1795 int str_int64_t(const char *nptr, const char **endptr, unsigned int base,
    1796     bool strict, int64_t *result)
    1797 {
    1798         assert(result != NULL);
    1799 
    1800         bool neg;
    1801         char *lendptr;
    1802         uint64_t unsigned_result;
    1803         int ret = str_uint(nptr, &lendptr, base, &neg, &unsigned_result);
    1804 
    1805         if (endptr != NULL)
    1806                 *endptr = (char *) lendptr;
    1807 
    1808         if (ret != EOK)
    1809                 return ret;
    1810 
    1811         /* Do not allow negative values */
    1812         if (neg) {
    1813                 if (unsigned_result == UINT64_MAX)
    1814                         return EINVAL;
    1815 
    1816                 *result = -(int64_t) unsigned_result;
    1817         } else
    1818                 *result = unsigned_result;
    1819 
    1820         /*
    1821          * Check whether we are at the end of
    1822          * the string in strict mode
    1823          */
    1824         if ((strict) && (*lendptr != 0))
    1825                 return EINVAL;
    1826 
    1827         return EOK;
    1828 }
    1829 
    1830 /** Convert string to size_t.
    1831  *
    1832  * @param nptr   Pointer to string.
    1833  * @param endptr If not NULL, pointer to the first invalid character
    1834  *               is stored here.
    1835  * @param base   Zero or number between 2 and 36 inclusive.
    1836  * @param strict Do not allow any trailing characters.
    1837  * @param result Result of the conversion.
    1838  *
    1839  * @return EOK if conversion was successful.
    1840  *
    1841  */
    1842 errno_t str_size_t(const char *nptr, const char **endptr, unsigned int base,
    1843     bool strict, size_t *result)
    1844 {
    1845         assert(result != NULL);
    1846 
    1847         bool neg;
    1848         char *lendptr;
    1849         uint64_t res;
    1850         errno_t ret = str_uint(nptr, &lendptr, base, &neg, &res);
    1851 
    1852         if (endptr != NULL)
    1853                 *endptr = (char *) lendptr;
    1854 
    1855         if (ret != EOK)
    1856                 return ret;
    1857 
    1858         /* Do not allow negative values */
    1859         if (neg)
    1860                 return EINVAL;
    1861 
    1862         /*
    1863          * Check whether we are at the end of
    1864          * the string in strict mode
    1865          */
    1866         if ((strict) && (*lendptr != 0))
    1867                 return EINVAL;
    1868 
    1869         /* Check for overflow */
    1870         size_t _res = (size_t) res;
    1871         if (_res != res)
    1872                 return EOVERFLOW;
    1873 
    1874         *result = _res;
    1875 
    1876         return EOK;
    18771473}
    18781474
  • uspace/lib/c/generic/strtol.c

    rdd0502ae r1c9bf292  
    4444#include <stdbool.h>
    4545#include <stdlib.h>
    46 
    47 // TODO: unit tests
     46#include <str.h>
     47
     48// FIXME: The original HelenOS functions return EOVERFLOW instead
     49//        of ERANGE. It's a pointless distinction from standard functions,
     50//        so we should change that. Beware the callers though.
     51
     52// TODO: more unit tests
    4853
    4954static inline int _digit_value(int c)
     
    6974}
    7075
    71 static inline int _prefixbase(const char *restrict *nptrptr, bool nonstandard_prefixes)
     76static inline int _prefixbase(const char *restrict *nptrptr, bool nonstd)
    7277{
    7378        const char *nptr = *nptrptr;
     
    8388        }
    8489
    85         if (nonstandard_prefixes) {
     90        if (nonstd) {
    8691                switch (nptr[1]) {
    8792                case 'b':
     
    116121static inline uintmax_t _strtoumax(
    117122    const char *restrict nptr, char **restrict endptr, int base,
    118     bool *restrict sgn, errno_t *err, bool nonstandard_prefixes)
     123    bool *restrict sgn, errno_t *err, bool nonstd)
    119124{
    120125        assert(nptr != NULL);
     
    144149
    145150        if (base == 0)
    146                 base = _prefixbase(&nptr, nonstandard_prefixes);
    147 
    148         if (base == 16 && !nonstandard_prefixes) {
     151                base = _prefixbase(&nptr, nonstd);
     152
     153        if (base == 16 && !nonstd) {
    149154                /*
    150155                 * Standard strto* functions allow hexadecimal prefix to be
     
    184189                    __builtin_add_overflow(result * base, digit, &result)) {
    185190
    186                         *err = ERANGE;
     191                        *err = nonstd ? EOVERFLOW : ERANGE;
    187192                        result = UINTMAX_MAX;
    188193                        break;
     
    212217
    213218static inline intmax_t _strtosigned(const char *nptr, char **endptr, int base,
    214     intmax_t min, intmax_t max, errno_t *err, bool nonstandard_prefixes)
     219    intmax_t min, intmax_t max, errno_t *err, bool nonstd)
    215220{
    216221        bool sgn = false;
    217         uintmax_t number = _strtoumax(nptr, endptr, base, &sgn, err,
    218             nonstandard_prefixes);
     222        uintmax_t number = _strtoumax(nptr, endptr, base, &sgn, err, nonstd);
    219223
    220224        if (number > (uintmax_t) max) {
     
    223227                }
    224228
    225                 *err = ERANGE;
     229                *err = nonstd ? EOVERFLOW : ERANGE;
    226230                return (sgn ? min : max);
    227231        }
     
    231235
    232236static inline uintmax_t _strtounsigned(const char *nptr, char **endptr, int base,
    233     uintmax_t max, errno_t *err, bool nonstandard_prefixes)
     237    uintmax_t max, errno_t *err, bool nonstd)
    234238{
    235239        bool sgn = false;
    236         uintmax_t number = _strtoumax(nptr, endptr, base, &sgn, err,
    237             nonstandard_prefixes);
     240        uintmax_t number = _strtoumax(nptr, endptr, base, &sgn, err, nonstd);
     241
     242        if (nonstd && sgn) {
     243                /* Do not allow negative values */
     244                *err = EINVAL;
     245                return 0;
     246        }
    238247
    239248        if (number > max) {
    240                 *err = ERANGE;
     249                *err = nonstd ? EOVERFLOW : ERANGE;
    241250                return max;
    242251        }
     
    316325}
    317326
     327/** Convert string to uint8_t.
     328 *
     329 * @param nptr   Pointer to string.
     330 * @param endptr If not NULL, pointer to the first invalid character
     331 *               is stored here.
     332 * @param base   Zero or number between 2 and 36 inclusive.
     333 * @param strict Do not allow any trailing characters.
     334 * @param result Result of the conversion.
     335 *
     336 * @return EOK if conversion was successful.
     337 *
     338 */
     339errno_t str_uint8_t(const char *nptr, const char **endptr, unsigned int base,
     340    bool strict, uint8_t *result)
     341{
     342        assert(result != NULL);
     343
     344        errno_t rc = EOK;
     345        char *lendptr = (char *) nptr;
     346
     347        uintmax_t r = _strtounsigned(nptr, &lendptr, base, UINT8_MAX, &rc, true);
     348
     349        if (endptr)
     350                *endptr = lendptr;
     351
     352        if (rc != EOK)
     353                return rc;
     354
     355        if (strict && *lendptr != '\0')
     356                return EINVAL;
     357
     358        *result = r;
     359        return EOK;
     360}
     361
     362/** Convert string to uint16_t.
     363 *
     364 * @param nptr   Pointer to string.
     365 * @param endptr If not NULL, pointer to the first invalid character
     366 *               is stored here.
     367 * @param base   Zero or number between 2 and 36 inclusive.
     368 * @param strict Do not allow any trailing characters.
     369 * @param result Result of the conversion.
     370 *
     371 * @return EOK if conversion was successful.
     372 *
     373 */
     374errno_t str_uint16_t(const char *nptr, const char **endptr, unsigned int base,
     375    bool strict, uint16_t *result)
     376{
     377        assert(result != NULL);
     378
     379        errno_t rc = EOK;
     380        char *lendptr = (char *) nptr;
     381
     382        uintmax_t r = _strtounsigned(nptr, &lendptr, base, UINT16_MAX, &rc, true);
     383
     384        if (endptr)
     385                *endptr = lendptr;
     386
     387        if (rc != EOK)
     388                return rc;
     389
     390        if (strict && *lendptr != '\0')
     391                return EINVAL;
     392
     393        *result = r;
     394        return EOK;
     395}
     396
     397/** Convert string to uint32_t.
     398 *
     399 * @param nptr   Pointer to string.
     400 * @param endptr If not NULL, pointer to the first invalid character
     401 *               is stored here.
     402 * @param base   Zero or number between 2 and 36 inclusive.
     403 * @param strict Do not allow any trailing characters.
     404 * @param result Result of the conversion.
     405 *
     406 * @return EOK if conversion was successful.
     407 *
     408 */
     409errno_t str_uint32_t(const char *nptr, const char **endptr, unsigned int base,
     410    bool strict, uint32_t *result)
     411{
     412        assert(result != NULL);
     413
     414        errno_t rc = EOK;
     415        char *lendptr = (char *) nptr;
     416
     417        uintmax_t r = _strtounsigned(nptr, &lendptr, base, UINT32_MAX, &rc, true);
     418
     419        if (endptr)
     420                *endptr = lendptr;
     421
     422        if (rc != EOK)
     423                return rc;
     424
     425        if (strict && *lendptr != '\0')
     426                return EINVAL;
     427
     428        *result = r;
     429        return EOK;
     430}
     431
     432/** Convert string to uint64_t.
     433 *
     434 * @param nptr   Pointer to string.
     435 * @param endptr If not NULL, pointer to the first invalid character
     436 *               is stored here.
     437 * @param base   Zero or number between 2 and 36 inclusive.
     438 * @param strict Do not allow any trailing characters.
     439 * @param result Result of the conversion.
     440 *
     441 * @return EOK if conversion was successful.
     442 *
     443 */
     444errno_t str_uint64_t(const char *nptr, const char **endptr, unsigned int base,
     445    bool strict, uint64_t *result)
     446{
     447        assert(result != NULL);
     448
     449        errno_t rc = EOK;
     450        char *lendptr = (char *) nptr;
     451
     452        uintmax_t r = _strtounsigned(nptr, &lendptr, base, UINT64_MAX, &rc, true);
     453
     454        if (endptr)
     455                *endptr = lendptr;
     456
     457        if (rc != EOK)
     458                return rc;
     459
     460        if (strict && *lendptr != '\0')
     461                return EINVAL;
     462
     463        *result = r;
     464        return EOK;
     465}
     466
     467/** Convert string to int64_t.
     468 *
     469 * @param nptr   Pointer to string.
     470 * @param endptr If not NULL, pointer to the first invalid character
     471 *               is stored here.
     472 * @param base   Zero or number between 2 and 36 inclusive.
     473 * @param strict Do not allow any trailing characters.
     474 * @param result Result of the conversion.
     475 *
     476 * @return EOK if conversion was successful.
     477 *
     478 */
     479errno_t str_int64_t(const char *nptr, const char **endptr, unsigned int base,
     480    bool strict, int64_t *result)
     481{
     482        assert(result != NULL);
     483
     484        errno_t rc = EOK;
     485        char *lendptr = (char *) nptr;
     486
     487        intmax_t r = _strtosigned(nptr, &lendptr, base, INT64_MIN, INT64_MAX, &rc, true);
     488
     489        if (endptr)
     490                *endptr = lendptr;
     491
     492        if (rc != EOK)
     493                return rc;
     494
     495        if (strict && *lendptr != '\0')
     496                return EINVAL;
     497
     498        *result = r;
     499        return EOK;
     500}
     501
     502/** Convert string to size_t.
     503 *
     504 * @param nptr   Pointer to string.
     505 * @param endptr If not NULL, pointer to the first invalid character
     506 *               is stored here.
     507 * @param base   Zero or number between 2 and 36 inclusive.
     508 * @param strict Do not allow any trailing characters.
     509 * @param result Result of the conversion.
     510 *
     511 * @return EOK if conversion was successful.
     512 *
     513 */
     514errno_t str_size_t(const char *nptr, const char **endptr, unsigned int base,
     515    bool strict, size_t *result)
     516{
     517        assert(result != NULL);
     518
     519        errno_t rc = EOK;
     520        char *lendptr = (char *) nptr;
     521
     522        uintmax_t r = _strtounsigned(nptr, &lendptr, base, SIZE_MAX, &rc, true);
     523
     524        if (endptr)
     525                *endptr = lendptr;
     526
     527        if (rc != EOK)
     528                return rc;
     529
     530        if (strict && *lendptr != '\0')
     531                return EINVAL;
     532
     533        *result = r;
     534        return EOK;
     535}
     536
    318537/** @}
    319538 */
  • uspace/lib/c/include/str.h

    rdd0502ae r1c9bf292  
    134134extern errno_t str_size_t(const char *, const char **, unsigned int, bool,
    135135    size_t *);
    136 extern int str_int64_t(const char *, const char **, unsigned int, bool,
     136extern errno_t str_int64_t(const char *, const char **, unsigned int, bool,
    137137    int64_t *);
    138138
  • uspace/lib/c/test/strtol.c

    rdd0502ae r1c9bf292  
    218218        /* Correct result. */
    219219        PCUT_ASSERT_INT_EQUALS(EOVERFLOW, rc);
    220         PCUT_ASSERT_UINT_EQUALS(UINT64_MAX, result);
    221220#endif
    222221
     
    246245        /* Correct result. */
    247246        PCUT_ASSERT_INT_EQUALS(EOVERFLOW, rc);
    248         PCUT_ASSERT_UINT_EQUALS(UINT64_MAX, result);
    249247#endif
    250248}
Note: See TracChangeset for help on using the changeset viewer.