Ignore:
File:
1 edited

Legend:

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

    r09ab0a9a r1c9bf292  
    11/*
     2 * Copyright (c) 2001-2004 Jakub Jermar
    23 * Copyright (c) 2005 Martin Decky
    34 * Copyright (c) 2008 Jiri Svoboda
     
    3334 * @{
    3435 */
    35 /** @file
     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 *
    36106 */
    37107
    38108#include <str.h>
     109
     110#include <assert.h>
     111#include <ctype.h>
     112#include <errno.h>
     113#include <stdbool.h>
    39114#include <stddef.h>
    40115#include <stdint.h>
    41116#include <stdlib.h>
    42 #include <assert.h>
    43 #include <ctype.h>
    44 #include <errno.h>
     117
    45118#include <align.h>
    46119#include <mem.h>
    47 #include <limits.h>
    48120
    49121/** Check the condition if wchar_t is signed */
     
    747819        /* There must be space for a null terminator in the buffer. */
    748820        assert(size > 0);
     821        assert(src != NULL);
    749822
    750823        size_t src_off = 0;
     
    13111384{
    13121385        size_t size = str_size(src) + 1;
    1313         char *dest = (char *) malloc(size);
    1314         if (dest == NULL)
    1315                 return (char *) NULL;
     1386        char *dest = malloc(size);
     1387        if (!dest)
     1388                return NULL;
    13161389
    13171390        str_cpy(dest, size, src);
     
    13451418                size = n;
    13461419
    1347         char *dest = (char *) malloc(size + 1);
    1348         if (dest == NULL)
    1349                 return (char *) NULL;
     1420        char *dest = malloc(size + 1);
     1421        if (!dest)
     1422                return NULL;
    13501423
    13511424        str_ncpy(dest, size + 1, src, size);
     
    13981471        *end = '\0';
    13991472        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  */
    1413 static 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  */
    1534 errno_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  */
    1583 errno_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  */
    1632 errno_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  */
    1681 errno_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  */
    1722 int 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  */
    1769 errno_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;
    18041473}
    18051474
Note: See TracChangeset for help on using the changeset viewer.