Changes in / [83b64a59:b401b33] in mainline


Ignore:
Files:
1 added
7 edited

Legend:

Unmodified
Added
Removed
  • kernel/Makefile

    r83b64a59 rb401b33  
    207207        generic/src/lib/gsort.c \
    208208        generic/src/lib/str.c \
     209        generic/src/lib/strtol.c \
    209210        generic/src/lib/str_error.c \
    210211        generic/src/lib/elf.c \
  • kernel/generic/src/lib/str.c

    r83b64a59 rb401b33  
    789789        str_ncpy(dest, size + 1, src, size);
    790790        return dest;
    791 }
    792 
    793 /** Convert string to uint64_t (internal variant).
    794  *
    795  * @param nptr   Pointer to string.
    796  * @param endptr Pointer to the first invalid character is stored here.
    797  * @param base   Zero or number between 2 and 36 inclusive.
    798  * @param neg    Indication of unary minus is stored here.
    799  * @apram result Result of the conversion.
    800  *
    801  * @return EOK if conversion was successful.
    802  *
    803  */
    804 static errno_t str_uint(const char *nptr, char **endptr, unsigned int base,
    805     bool *neg, uint64_t *result)
    806 {
    807         assert(endptr != NULL);
    808         assert(neg != NULL);
    809         assert(result != NULL);
    810 
    811         *neg = false;
    812         const char *str = nptr;
    813 
    814         /* Ignore leading whitespace */
    815         while (isspace(*str))
    816                 str++;
    817 
    818         if (*str == '-') {
    819                 *neg = true;
    820                 str++;
    821         } else if (*str == '+')
    822                 str++;
    823 
    824         if (base == 0) {
    825                 /* Decode base if not specified */
    826                 base = 10;
    827 
    828                 if (*str == '0') {
    829                         base = 8;
    830                         str++;
    831 
    832                         switch (*str) {
    833                         case 'b':
    834                         case 'B':
    835                                 base = 2;
    836                                 str++;
    837                                 break;
    838                         case 'o':
    839                         case 'O':
    840                                 base = 8;
    841                                 str++;
    842                                 break;
    843                         case 'd':
    844                         case 'D':
    845                         case 't':
    846                         case 'T':
    847                                 base = 10;
    848                                 str++;
    849                                 break;
    850                         case 'x':
    851                         case 'X':
    852                                 base = 16;
    853                                 str++;
    854                                 break;
    855                         default:
    856                                 str--;
    857                         }
    858                 }
    859         } else {
    860                 /* Check base range */
    861                 if ((base < 2) || (base > 36)) {
    862                         *endptr = (char *) str;
    863                         return EINVAL;
    864                 }
    865         }
    866 
    867         *result = 0;
    868         const char *startstr = str;
    869 
    870         while (*str != 0) {
    871                 unsigned int digit;
    872 
    873                 if ((*str >= 'a') && (*str <= 'z'))
    874                         digit = *str - 'a' + 10;
    875                 else if ((*str >= 'A') && (*str <= 'Z'))
    876                         digit = *str - 'A' + 10;
    877                 else if ((*str >= '0') && (*str <= '9'))
    878                         digit = *str - '0';
    879                 else
    880                         break;
    881 
    882                 if (digit >= base)
    883                         break;
    884 
    885                 uint64_t prev = *result;
    886                 *result = (*result) * base + digit;
    887 
    888                 if (*result < prev) {
    889                         /* Overflow */
    890                         *endptr = (char *) str;
    891                         return EOVERFLOW;
    892                 }
    893 
    894                 str++;
    895         }
    896 
    897         if (str == startstr) {
    898                 /*
    899                  * No digits were decoded => first invalid character is
    900                  * the first character of the string.
    901                  */
    902                 str = nptr;
    903         }
    904 
    905         *endptr = (char *) str;
    906 
    907         if (str == nptr)
    908                 return EINVAL;
    909 
    910         return EOK;
    911 }
    912 
    913 /** Convert string to uint64_t.
    914  *
    915  * @param nptr   Pointer to string.
    916  * @param endptr If not NULL, pointer to the first invalid character
    917  *               is stored here.
    918  * @param base   Zero or number between 2 and 36 inclusive.
    919  * @param strict Do not allow any trailing characters.
    920  * @param result Result of the conversion.
    921  *
    922  * @return EOK if conversion was successful.
    923  *
    924  */
    925 errno_t str_uint64_t(const char *nptr, char **endptr, unsigned int base,
    926     bool strict, uint64_t *result)
    927 {
    928         assert(result != NULL);
    929 
    930         bool neg;
    931         char *lendptr;
    932         errno_t ret = str_uint(nptr, &lendptr, base, &neg, result);
    933 
    934         if (endptr != NULL)
    935                 *endptr = (char *) lendptr;
    936 
    937         if (ret != EOK)
    938                 return ret;
    939 
    940         /* Do not allow negative values */
    941         if (neg)
    942                 return EINVAL;
    943 
    944         /*
    945          * Check whether we are at the end of
    946          * the string in strict mode
    947          */
    948         if ((strict) && (*lendptr != 0))
    949                 return EINVAL;
    950 
    951         return EOK;
    952791}
    953792
  • uspace/lib/c/generic/ctype.c

    r83b64a59 rb401b33  
    9090        case '\v':
    9191                return 1;
    92                 break;
    9392        default:
    9493                return 0;
  • uspace/lib/c/generic/str.c

    r83b64a59 rb401b33  
    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

    r83b64a59 rb401b33  
    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
     76static inline int _prefixbase(const char *restrict *nptrptr, bool nonstd)
     77{
     78        const char *nptr = *nptrptr;
     79
     80        if (nptr[0] != '0')
     81                return 10;
     82
     83        if (nptr[1] == 'x' || nptr[1] == 'X') {
     84                if (_digit_value(nptr[2]) < 16) {
     85                        *nptrptr += 2;
     86                        return 16;
     87                }
     88        }
     89
     90        if (nonstd) {
     91                switch (nptr[1]) {
     92                case 'b':
     93                case 'B':
     94                        if (_digit_value(nptr[2]) < 2) {
     95                                *nptrptr += 2;
     96                                return 2;
     97                        }
     98                        break;
     99                case 'o':
     100                case 'O':
     101                        if (_digit_value(nptr[2]) < 8) {
     102                                *nptrptr += 2;
     103                                return 8;
     104                        }
     105                        break;
     106                case 'd':
     107                case 'D':
     108                case 't':
     109                case 'T':
     110                        if (_digit_value(nptr[2]) < 10) {
     111                                *nptrptr += 2;
     112                                return 10;
     113                        }
     114                        break;
     115                }
     116        }
     117
     118        return 8;
     119}
     120
    71121static inline uintmax_t _strtoumax(
    72122    const char *restrict nptr, char **restrict endptr, int base,
    73     bool *restrict sgn)
     123    bool *restrict sgn, errno_t *err, bool nonstd)
    74124{
    75125        assert(nptr != NULL);
    76126        assert(sgn != NULL);
     127
     128        const char *first = nptr;
    77129
    78130        /* Skip leading whitespace. */
     
    96148        /* Figure out the base. */
    97149
    98         if (base == 0) {
    99                 if (*nptr == '0') {
    100                         if (tolower(nptr[1]) == 'x') {
    101                                 /* 0x... is hex. */
    102                                 base = 16;
    103                                 nptr += 2;
    104                         } else {
    105                                 /* 0... is octal. */
    106                                 base = 8;
    107                         }
    108                 } else {
    109                         /* Anything else is decimal by default. */
    110                         base = 10;
    111                 }
    112         } else if (base == 16) {
    113                 /* Allow hex number to be prefixed with "0x". */
    114                 if (nptr[0] == '0' && tolower(nptr[1]) == 'x') {
     150        if (base == 0)
     151                base = _prefixbase(&nptr, nonstd);
     152
     153        if (base == 16 && !nonstd) {
     154                /*
     155                 * Standard strto* functions allow hexadecimal prefix to be
     156                 * present when base is explicitly set to 16.
     157                 * Our nonstandard str_* functions don't allow it.
     158                 * I don't know if that is intended, just matching the original
     159                 * functionality here.
     160                 */
     161
     162                if (nptr[0] == '0' && (nptr[1] == 'x' || nptr[1] == 'X') &&
     163                    _digit_value(nptr[2]) < base)
    115164                        nptr += 2;
    116                 }
    117         } else if (base < 0 || base == 1 || base > 36) {
    118                 errno = EINVAL;
     165        }
     166
     167        if (base < 2 || base > 36) {
     168                *err = EINVAL;
    119169                return 0;
    120170        }
    121171
    122         /* Read the value. */
     172        /* Must be at least one digit. */
     173
     174        if (_digit_value(*nptr) >= base) {
     175                /* No digits on input. */
     176                if (endptr != NULL)
     177                        *endptr = (char *) first;
     178                return 0;
     179        }
     180
     181        /* Read the value.  */
    123182
    124183        uintmax_t result = 0;
     
    127186
    128187        while (digit = _digit_value(*nptr), digit < base) {
    129 
    130188                if (result > max ||
    131189                    __builtin_add_overflow(result * base, digit, &result)) {
    132190
    133                         errno = ERANGE;
     191                        *err = nonstd ? EOVERFLOW : ERANGE;
    134192                        result = UINTMAX_MAX;
    135193                        break;
     
    145203                 * Move the pointer to the end of the number,
    146204                 * in case it isn't there already.
     205                 * This can happen when the number has legal formatting,
     206                 * but is out of range of the target type.
    147207                 */
    148208                while (_digit_value(*nptr) < base) {
     
    157217
    158218static inline intmax_t _strtosigned(const char *nptr, char **endptr, int base,
    159     intmax_t min, intmax_t max)
     219    intmax_t min, intmax_t max, errno_t *err, bool nonstd)
    160220{
    161221        bool sgn = false;
    162         uintmax_t number = _strtoumax(nptr, endptr, base, &sgn);
     222        uintmax_t number = _strtoumax(nptr, endptr, base, &sgn, err, nonstd);
    163223
    164224        if (number > (uintmax_t) max) {
     
    167227                }
    168228
    169                 errno = ERANGE;
     229                *err = nonstd ? EOVERFLOW : ERANGE;
    170230                return (sgn ? min : max);
    171231        }
     
    175235
    176236static inline uintmax_t _strtounsigned(const char *nptr, char **endptr, int base,
    177     uintmax_t max)
     237    uintmax_t max, errno_t *err, bool nonstd)
    178238{
    179239        bool sgn = false;
    180         uintmax_t number = _strtoumax(nptr, endptr, base, &sgn);
    181 
    182         if (sgn) {
    183                 if (number == 0) {
    184                         return 0;
    185                 } else {
    186                         errno = ERANGE;
    187                         return max;
    188                 }
     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;
    189246        }
    190247
    191248        if (number > max) {
    192                 errno = ERANGE;
     249                *err = nonstd ? EOVERFLOW : ERANGE;
    193250                return max;
    194251        }
    195252
    196         return number;
     253        return (sgn ? -number : number);
    197254}
    198255
     
    212269long strtol(const char *nptr, char **endptr, int base)
    213270{
    214         return _strtosigned(nptr, endptr, base, LONG_MIN, LONG_MAX);
     271        return _strtosigned(nptr, endptr, base, LONG_MIN, LONG_MAX, &errno, false);
    215272}
    216273
     
    230287unsigned long strtoul(const char *nptr, char **endptr, int base)
    231288{
    232         return _strtounsigned(nptr, endptr, base, ULONG_MAX);
     289        return _strtounsigned(nptr, endptr, base, ULONG_MAX, &errno, false);
    233290}
    234291
    235292long long strtoll(const char *nptr, char **endptr, int base)
    236293{
    237         return _strtosigned(nptr, endptr, base, LLONG_MIN, LLONG_MAX);
     294        return _strtosigned(nptr, endptr, base, LLONG_MIN, LLONG_MAX, &errno, false);
    238295}
    239296
    240297unsigned long long strtoull(const char *nptr, char **endptr, int base)
    241298{
    242         return _strtounsigned(nptr, endptr, base, ULLONG_MAX);
     299        return _strtounsigned(nptr, endptr, base, ULLONG_MAX, &errno, false);
    243300}
    244301
    245302intmax_t strtoimax(const char *nptr, char **endptr, int base)
    246303{
    247         return _strtosigned(nptr, endptr, base, INTMAX_MIN, INTMAX_MAX);
     304        return _strtosigned(nptr, endptr, base, INTMAX_MIN, INTMAX_MAX, &errno, false);
    248305}
    249306
    250307uintmax_t strtoumax(const char *nptr, char **endptr, int base)
    251308{
    252         return _strtounsigned(nptr, endptr, base, UINTMAX_MAX);
     309        return _strtounsigned(nptr, endptr, base, UINTMAX_MAX, &errno, false);
    253310}
    254311
     
    268325}
    269326
     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
    270537/** @}
    271538 */
  • uspace/lib/c/include/str.h

    r83b64a59 rb401b33  
    137137extern errno_t str_size_t(const char *, const char **, unsigned int, bool,
    138138    size_t *);
    139 extern int str_int64_t(const char *, const char **, unsigned int, bool,
     139extern errno_t str_int64_t(const char *, const char **, unsigned int, bool,
    140140    int64_t *);
    141141
  • uspace/lib/c/test/strtol.c

    r83b64a59 rb401b33  
    3838#include <stdlib.h>
    3939#include <str.h>
     40#include <limits.h>
    4041
    4142PCUT_INIT;
     
    217218        /* Correct result. */
    218219        PCUT_ASSERT_INT_EQUALS(EOVERFLOW, rc);
    219         PCUT_ASSERT_UINT_EQUALS(UINT64_MAX, result);
    220220#endif
    221221
     
    245245        /* Correct result. */
    246246        PCUT_ASSERT_INT_EQUALS(EOVERFLOW, rc);
    247         PCUT_ASSERT_UINT_EQUALS(UINT64_MAX, result);
    248247#endif
     248}
     249
     250PCUT_TEST(strtoul_negative_wraparound)
     251{
     252        long output;
     253        char *endp;
     254        char *endp_unchanged = (char *) "endp_unchanged unique pointer";
     255        int errno_unchanged = -1;
     256        const char *input;
     257        int base;
     258
     259        /*
     260         * N2176 7.22.1.4 The strtol, strtoll, strtoul, and strtoull functions
     261         *
     262         * "If the subject sequence begins with a minus sign, the value
     263         * resulting from the conversion is negated (in the return type)."
     264         */
     265
     266        endp = endp_unchanged;
     267        errno = errno_unchanged;
     268        output = strtoul(input = "-10", &endp, base = 0);
     269        PCUT_ASSERT_INT_EQUALS(errno_unchanged, errno);
     270        PCUT_ASSERT_PTR_EQUALS(input + 3, endp);
     271        PCUT_ASSERT_UINT_EQUALS(-(10ul), output);
    249272}
    250273
     
    404427        endp = endp_unchanged;
    405428        errno = errno_unchanged;
     429        output = strtol(input = "    0xg", &endp, base = 0);
     430        PCUT_ASSERT_INT_EQUALS(errno_unchanged, errno);
     431        PCUT_ASSERT_PTR_EQUALS(input + 5, endp);
     432        PCUT_ASSERT_INT_EQUALS(0, output);
     433
     434        endp = endp_unchanged;
     435        errno = errno_unchanged;
    406436        output = strtol(input = "    0x1", &endp, base = 0);
    407437        PCUT_ASSERT_INT_EQUALS(errno_unchanged, errno);
     
    418448        endp = endp_unchanged;
    419449        errno = errno_unchanged;
     450        output = strtol(input = "    0xg", &endp, base = 16);
     451        PCUT_ASSERT_INT_EQUALS(errno_unchanged, errno);
     452        PCUT_ASSERT_PTR_EQUALS(input + 5, endp);
     453        PCUT_ASSERT_INT_EQUALS(0, output);
     454
     455        endp = endp_unchanged;
     456        errno = errno_unchanged;
     457        output = strtol(input = "    g", &endp, base = 16);
     458        PCUT_ASSERT_INT_EQUALS(errno_unchanged, errno);
     459        PCUT_ASSERT_PTR_EQUALS(input, endp);
     460        PCUT_ASSERT_INT_EQUALS(0, output);
     461
     462        endp = endp_unchanged;
     463        errno = errno_unchanged;
    420464        output = strtol(input = "    0x1", &endp, base = 16);
    421465        PCUT_ASSERT_INT_EQUALS(errno_unchanged, errno);
    422466        PCUT_ASSERT_PTR_EQUALS(input + 7, endp);
    423467        PCUT_ASSERT_INT_EQUALS(1, output);
     468
     469        endp = endp_unchanged;
     470        errno = errno_unchanged;
     471        output = strtol(input = "    +", &endp, base = 0);
     472        PCUT_ASSERT_INT_EQUALS(errno_unchanged, errno);
     473        PCUT_ASSERT_PTR_EQUALS(input, endp);
     474        PCUT_ASSERT_INT_EQUALS(0, output);
     475
     476        endp = endp_unchanged;
     477        errno = errno_unchanged;
     478        output = strtol(input = "    -", &endp, base = 0);
     479        PCUT_ASSERT_INT_EQUALS(errno_unchanged, errno);
     480        PCUT_ASSERT_PTR_EQUALS(input, endp);
     481        PCUT_ASSERT_INT_EQUALS(0, output);
     482
     483        endp = endp_unchanged;
     484        errno = errno_unchanged;
     485        output = strtol(input = "    +", &endp, base = 10);
     486        PCUT_ASSERT_INT_EQUALS(errno_unchanged, errno);
     487        PCUT_ASSERT_PTR_EQUALS(input, endp);
     488        PCUT_ASSERT_INT_EQUALS(0, output);
     489
     490        endp = endp_unchanged;
     491        errno = errno_unchanged;
     492        output = strtol(input = "    -", &endp, base = 10);
     493        PCUT_ASSERT_INT_EQUALS(errno_unchanged, errno);
     494        PCUT_ASSERT_PTR_EQUALS(input, endp);
     495        PCUT_ASSERT_INT_EQUALS(0, output);
     496
     497        endp = endp_unchanged;
     498        errno = errno_unchanged;
     499        output = strtol(input = "+", &endp, base = 0);
     500        PCUT_ASSERT_INT_EQUALS(errno_unchanged, errno);
     501        PCUT_ASSERT_PTR_EQUALS(input, endp);
     502        PCUT_ASSERT_INT_EQUALS(0, output);
     503
     504        endp = endp_unchanged;
     505        errno = errno_unchanged;
     506        output = strtol(input = "-", &endp, base = 0);
     507        PCUT_ASSERT_INT_EQUALS(errno_unchanged, errno);
     508        PCUT_ASSERT_PTR_EQUALS(input, endp);
     509        PCUT_ASSERT_INT_EQUALS(0, output);
     510
     511        endp = endp_unchanged;
     512        errno = errno_unchanged;
     513        output = strtol(input = "+", &endp, base = 10);
     514        PCUT_ASSERT_INT_EQUALS(errno_unchanged, errno);
     515        PCUT_ASSERT_PTR_EQUALS(input, endp);
     516        PCUT_ASSERT_INT_EQUALS(0, output);
     517
     518        endp = endp_unchanged;
     519        errno = errno_unchanged;
     520        output = strtol(input = "-", &endp, base = 10);
     521        PCUT_ASSERT_INT_EQUALS(errno_unchanged, errno);
     522        PCUT_ASSERT_PTR_EQUALS(input, endp);
     523        PCUT_ASSERT_INT_EQUALS(0, output);
    424524}
    425525
Note: See TracChangeset for help on using the changeset viewer.