Changeset b401b33 in mainline for uspace/lib/c/generic/str.c


Ignore:
Timestamp:
2019-06-06T12:15:29Z (5 years ago)
Author:
GitHub <noreply@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
2a103b5, e28175d
Parents:
83b64a59 (diff), 42e91ae (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the (diff) links above to see all the changes relative to each parent.
git-author:
Jiří Zárevúcky <zarevucky.jiri@…> (2019-06-06 12:15:29)
git-committer:
GitHub <noreply@…> (2019-06-06 12:15:29)
Message:

Merge pull request #169 from le-jzr/strtolwip

Removes internal str_uint() function in favor of the one in strtol.c.
Fixes handling of a bunch of corner cases.
The expected behavior of str_uint*_t() functions should be unchanged.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • 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
Note: See TracChangeset for help on using the changeset viewer.