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


Ignore:
Timestamp:
2018-01-16T19:12:36Z (7 years ago)
Author:
Jiří Zárevúcky <zarevucky.jiri@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
33b8d024
Parents:
aec41c8
git-author:
Jiří Zárevúcky <zarevucky.jiri@…> (2018-01-16 19:04:19)
git-committer:
Jiří Zárevúcky <zarevucky.jiri@…> (2018-01-16 19:12:36)
Message:

Implement the full suite of standard string-to-int conversion functions in libc.

File:
1 edited

Legend:

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

    raec41c8 rd39c46e0  
    12731273}
    12741274
    1275 /** Convert string to a number.
    1276  * Core of strtol and strtoul functions.
    1277  *
    1278  * @param nptr          Pointer to string.
    1279  * @param endptr        If not NULL, function stores here pointer to the first
    1280  *                      invalid character.
    1281  * @param base          Zero or number between 2 and 36 inclusive.
    1282  * @param sgn           It's set to 1 if minus found.
    1283  * @return              Result of conversion.
    1284  */
    1285 static unsigned long
    1286 _strtoul(const char *nptr, char **endptr, int base, char *sgn)
    1287 {
    1288         unsigned char c;
    1289         unsigned long result = 0;
    1290         unsigned long a, b;
    1291         const char *str = nptr;
    1292         const char *tmpptr;
    1293        
    1294         while (isspace(*str))
    1295                 str++;
    1296        
    1297         if (*str == '-') {
    1298                 *sgn = 1;
    1299                 ++str;
    1300         } else if (*str == '+')
    1301                 ++str;
    1302        
    1303         if (base) {
    1304                 if ((base == 1) || (base > 36)) {
    1305                         /* FIXME: set errno to EINVAL */
    1306                         return 0;
    1307                 }
    1308                 if ((base == 16) && (*str == '0') && ((str[1] == 'x') ||
    1309                     (str[1] == 'X'))) {
    1310                         str += 2;
    1311                 }
    1312         } else {
    1313                 base = 10;
    1314                
    1315                 if (*str == '0') {
    1316                         base = 8;
    1317                         if ((str[1] == 'X') || (str[1] == 'x'))  {
    1318                                 base = 16;
    1319                                 str += 2;
    1320                         }
    1321                 }
    1322         }
    1323        
    1324         tmpptr = str;
    1325 
    1326         while (*str) {
    1327                 c = *str;
    1328                 c = (c >= 'a' ? c - 'a' + 10 : (c >= 'A' ? c - 'A' + 10 :
    1329                     (c <= '9' ? c - '0' : 0xff)));
    1330                 if (c >= base) {
    1331                         break;
    1332                 }
    1333                
    1334                 a = (result & 0xff) * base + c;
    1335                 b = (result >> 8) * base + (a >> 8);
    1336                
    1337                 if (b > (ULONG_MAX >> 8)) {
    1338                         /* overflow */
    1339                         /* FIXME: errno = ERANGE*/
    1340                         return ULONG_MAX;
    1341                 }
    1342        
    1343                 result = (b << 8) + (a & 0xff);
    1344                 ++str;
    1345         }
    1346        
    1347         if (str == tmpptr) {
    1348                 /*
    1349                  * No number was found => first invalid character is the first
    1350                  * character of the string.
    1351                  */
    1352                 /* FIXME: set errno to EINVAL */
    1353                 str = nptr;
    1354                 result = 0;
    1355         }
    1356        
    1357         if (endptr)
    1358                 *endptr = (char *) str;
    1359 
    1360         if (nptr == str) {
    1361                 /*FIXME: errno = EINVAL*/
    1362                 return 0;
    1363         }
    1364 
    1365         return result;
    1366 }
    1367 
    1368 /** Convert initial part of string to long int according to given base.
    1369  * The number may begin with an arbitrary number of whitespaces followed by
    1370  * optional sign (`+' or `-'). If the base is 0 or 16, the prefix `0x' may be
    1371  * inserted and the number will be taken as hexadecimal one. If the base is 0
    1372  * and the number begin with a zero, number will be taken as octal one (as with
    1373  * base 8). Otherwise the base 0 is taken as decimal.
    1374  *
    1375  * @param nptr          Pointer to string.
    1376  * @param endptr        If not NULL, function stores here pointer to the first
    1377  *                      invalid character.
    1378  * @param base          Zero or number between 2 and 36 inclusive.
    1379  * @return              Result of conversion.
    1380  */
    1381 long int strtol(const char *nptr, char **endptr, int base)
    1382 {
    1383         char sgn = 0;
    1384         unsigned long number = 0;
    1385        
    1386         number = _strtoul(nptr, endptr, base, &sgn);
    1387 
    1388         if (number > LONG_MAX) {
    1389                 if ((sgn) && (number == (unsigned long) (LONG_MAX) + 1)) {
    1390                         /* FIXME: set 0 to errno */
    1391                         return number;
    1392                 }
    1393                 /* FIXME: set ERANGE to errno */
    1394                 return (sgn ? LONG_MIN : LONG_MAX);
    1395         }
    1396        
    1397         return (sgn ? -number : number);
    1398 }
    13991275
    14001276/** Duplicate string.
     
    14571333        str_ncpy(dest, size + 1, src, size);
    14581334        return dest;
    1459 }
    1460 
    1461 /** Convert initial part of string to unsigned long according to given base.
    1462  * The number may begin with an arbitrary number of whitespaces followed by
    1463  * optional sign (`+' or `-'). If the base is 0 or 16, the prefix `0x' may be
    1464  * inserted and the number will be taken as hexadecimal one. If the base is 0
    1465  * and the number begin with a zero, number will be taken as octal one (as with
    1466  * base 8). Otherwise the base 0 is taken as decimal.
    1467  *
    1468  * @param nptr          Pointer to string.
    1469  * @param endptr        If not NULL, function stores here pointer to the first
    1470  *                      invalid character
    1471  * @param base          Zero or number between 2 and 36 inclusive.
    1472  * @return              Result of conversion.
    1473  */
    1474 unsigned long strtoul(const char *nptr, char **endptr, int base)
    1475 {
    1476         char sgn = 0;
    1477         unsigned long number = 0;
    1478        
    1479         number = _strtoul(nptr, endptr, base, &sgn);
    1480 
    1481         return (sgn ? -number : number);
    14821335}
    14831336
Note: See TracChangeset for help on using the changeset viewer.