LCOV - code coverage report
Current view: top level - include/flatcc/portable - pparseint.h (source / functions) Hit Total Coverage
Test: coverage.info Lines: 16 27 59.3 %
Date: 2016-11-30 13:12:14 Functions: 1 1 100.0 %
Branches: 10 22 45.5 %

           Branch data     Line data    Source code
       1                 :            : #ifndef PPARSEINT_H
       2                 :            : #define PPARSEINT_H
       3                 :            : 
       4                 :            : /*
       5                 :            :  * Type specific integer parsers:
       6                 :            :  *
       7                 :            :  *     const char *
       8                 :            :  *     parse_<type-name>(const char *buf, int len, <type> *value, int *status);
       9                 :            :  *
      10                 :            :  *     parse_uint64, parse_int64
      11                 :            :  *     parse_uint32, parse_int32
      12                 :            :  *     parse_uint16, parse_int16
      13                 :            :  *     parse_uint8, parse_int8
      14                 :            :  *     parse_ushort,  parse_short
      15                 :            :  *     parse_uint, parse_int
      16                 :            :  *     parse_ulong, parse_long
      17                 :            :  *
      18                 :            :  * Leading space must be stripped in advance. Status argument can be
      19                 :            :  * null.
      20                 :            :  *
      21                 :            :  * Returns pointer to end of match and a non-negative status code
      22                 :            :  * on succcess (0 for unsigned, 1 for signed):
      23                 :            :  *
      24                 :            :  *     PARSE_INTEGER_UNSIGNED
      25                 :            :  *     PARSE_INTEGER_SIGNED
      26                 :            :  *
      27                 :            :  * Returns null with a negative status code and unmodified value on
      28                 :            :  * invalid integer formats:
      29                 :            :  *
      30                 :            :  *     PARSE_INTEGER_OVERFLOW
      31                 :            :  *     PARSE_INTEGER_UNDERFLOW
      32                 :            :  *     PARSE_INTEGER_INVALID
      33                 :            :  *
      34                 :            :  * Returns input buffer with negative status code and unmodified value
      35                 :            :  * if first character does not start an integer (not a sign or a digit).
      36                 :            :  *
      37                 :            :  *     PARSE_INTEGER_UNMATCHED
      38                 :            :  *     PARSE_INTEGER_END
      39                 :            :  *
      40                 :            :  * The signed parsers only works with two's complement architectures.
      41                 :            :  *
      42                 :            :  * Note: the corresponding parse_float and parse_double parsers do not
      43                 :            :  * have a status argument because +/-Inf and NaN are conventionally used
      44                 :            :  * for this.
      45                 :            :  */
      46                 :            : 
      47                 :            : #include "limits.h"
      48                 :            : #ifndef UINT8_MAX
      49                 :            : #include <stdint.h>
      50                 :            : #endif
      51                 :            : 
      52                 :            : #define PARSE_INTEGER_UNSIGNED       0
      53                 :            : #define PARSE_INTEGER_SIGNED         1
      54                 :            : #define PARSE_INTEGER_OVERFLOW      -1
      55                 :            : #define PARSE_INTEGER_UNDERFLOW     -2
      56                 :            : #define PARSE_INTEGER_INVALID       -3
      57                 :            : #define PARSE_INTEGER_UNMATCHED     -4
      58                 :            : #define PARSE_INTEGER_END           -5
      59                 :            : 
      60                 :            : /*
      61                 :            :  * Generic integer parser that holds 64-bit unsigned values and stores
      62                 :            :  * sign separately. Leading space is not valid.
      63                 :            :  *
      64                 :            :  * Note: this function differs from the type specific parsers like
      65                 :            :  * parse_int64 by not negating the value when there is a sign. It
      66                 :            :  * differs from parse_uint64 by being able to return a negative
      67                 :            :  * UINT64_MAX successfully.
      68                 :            :  *
      69                 :            :  * This parser is used by all type specific integer parsers.
      70                 :            :  *
      71                 :            :  * Status argument can be null.
      72                 :            :  */
      73                 :        287 : static const char *parse_integer(const char *buf, int len, uint64_t *value, int *status)
      74                 :            : {
      75                 :            :     uint64_t x0, x = 0;
      76                 :        287 :     const char *k, *end = buf + len;
      77                 :            :     int sign, status_;
      78                 :            : 
      79         [ -  + ]:        287 :     if (!status) {
      80                 :            :         status = &status_;
      81                 :            :     }
      82         [ -  + ]:        287 :     if (buf == end) {
      83                 :          0 :         *status = PARSE_INTEGER_END;
      84                 :          0 :         return buf;
      85                 :            :     }
      86                 :            :     k = buf;
      87                 :        287 :     sign = *buf == '-';
      88                 :        287 :     buf += sign;
      89 [ +  + ][ +  - ]:        765 :     while (buf != end && *buf >= '0' && *buf <= '9') {
                 [ +  - ]
      90                 :            :         x0 = x;
      91                 :        478 :         x = x * 10 + *buf - '0';
      92         [ -  + ]:        478 :         if (x0 > x) {
      93         [ #  # ]:          0 :             *status = sign ? PARSE_INTEGER_UNDERFLOW : PARSE_INTEGER_OVERFLOW;
      94                 :          0 :             return 0;
      95                 :            :         }
      96                 :        478 :         ++buf;
      97                 :            :     }
      98         [ -  + ]:        287 :     if (buf == k) {
      99                 :            :         /* No number was matched, but it isn't an invalid number either. */
     100                 :          0 :         *status = PARSE_INTEGER_UNMATCHED;
     101                 :          0 :         return buf;
     102                 :            :     }
     103         [ -  + ]:        287 :     if (buf == k + sign) {
     104                 :          0 :         *status = PARSE_INTEGER_INVALID;
     105                 :          0 :         return 0;
     106                 :            :     }
     107         [ -  + ]:        287 :     if (buf != end)
     108         [ #  # ]:          0 :     switch (*buf) {
     109                 :            :     case 'e': case 'E': case '.': case 'p': case 'P':
     110                 :          0 :         *status = PARSE_INTEGER_INVALID;
     111                 :          0 :         return 0;
     112                 :            :     }
     113                 :        287 :     *value = x;
     114                 :        287 :     *status = sign;
     115                 :        287 :     return buf;
     116                 :            : }
     117                 :            : 
     118                 :            : #define __portable_define_parse_unsigned(NAME, TYPE, LIMIT)                 \
     119                 :            : static inline const char *parse_ ## NAME                                    \
     120                 :            :         (const char *buf, int len, TYPE *value, int *status)                \
     121                 :            : {                                                                           \
     122                 :            :     int status_ = 0;                                                        \
     123                 :            :     uint64_t x;                                                             \
     124                 :            :                                                                             \
     125                 :            :     if (!status) {                                                          \
     126                 :            :         status = &status_;                                                  \
     127                 :            :     }                                                                       \
     128                 :            :     buf = parse_integer(buf, len, &x, status);                              \
     129                 :            :     switch (*status) {                                                      \
     130                 :            :     case PARSE_INTEGER_UNSIGNED:                                            \
     131                 :            :         if (x <= LIMIT) {                                                   \
     132                 :            :             *value = (TYPE)x;                                               \
     133                 :            :             return buf;                                                     \
     134                 :            :         }                                                                   \
     135                 :            :         *status = PARSE_INTEGER_OVERFLOW;                                   \
     136                 :            :         return 0;                                                           \
     137                 :            :     case PARSE_INTEGER_SIGNED:                                              \
     138                 :            :         *status = PARSE_INTEGER_UNDERFLOW;                                  \
     139                 :            :         return 0;                                                           \
     140                 :            :     default:                                                                \
     141                 :            :         return buf;                                                         \
     142                 :            :     }                                                                       \
     143                 :            : }
     144                 :            : 
     145                 :            : /* This assumes two's complement. */
     146                 :            : #define __portable_define_parse_signed(NAME, TYPE, LIMIT)                   \
     147                 :            : static inline const char *parse_ ## NAME                                    \
     148                 :            :         (const char *buf, int len, TYPE *value, int *status)                \
     149                 :            : {                                                                           \
     150                 :            :     int status_ = 0;                                                        \
     151                 :            :     uint64_t x;                                                             \
     152                 :            :                                                                             \
     153                 :            :     if (!status) {                                                          \
     154                 :            :         status = &status_;                                                  \
     155                 :            :     }                                                                       \
     156                 :            :     buf = parse_integer(buf, len, &x, status);                              \
     157                 :            :     switch (*status) {                                                      \
     158                 :            :     case PARSE_INTEGER_UNSIGNED:                                            \
     159                 :            :         if (x <= LIMIT) {                                                   \
     160                 :            :             *value = (TYPE)x;                                               \
     161                 :            :             return buf;                                                     \
     162                 :            :         }                                                                   \
     163                 :            :         *status = PARSE_INTEGER_OVERFLOW;                                   \
     164                 :            :         return 0;                                                           \
     165                 :            :     case PARSE_INTEGER_SIGNED:                                              \
     166                 :            :         if (x <= (uint64_t)(LIMIT) + 1) {                                   \
     167                 :            :             *value = (TYPE)-(int64_t)x;                                     \
     168                 :            :             return buf;                                                     \
     169                 :            :         }                                                                   \
     170                 :            :         *status = PARSE_INTEGER_UNDERFLOW;                                  \
     171                 :            :         return 0;                                                           \
     172                 :            :     default:                                                                \
     173                 :            :         return buf;                                                         \
     174                 :            :     }                                                                       \
     175                 :            : }
     176                 :            : 
     177                 :            : static inline const char *parse_uint64(const char *buf, int len, uint64_t *value, int *status)
     178                 :            : {
     179                 :            :     buf = parse_integer(buf, len, value, status);
     180                 :            :     if (*status == PARSE_INTEGER_SIGNED) {
     181                 :            :         *status = PARSE_INTEGER_UNDERFLOW;
     182                 :            :         return 0;
     183                 :            :     }
     184                 :            :     return buf;
     185                 :            : }
     186                 :            : 
     187                 :            : __portable_define_parse_signed(int64, int64_t, INT64_MAX)
     188                 :            : __portable_define_parse_signed(int32, int32_t, INT32_MAX)
     189                 :            : __portable_define_parse_unsigned(uint16, uint16_t, UINT16_MAX)
     190                 :            : __portable_define_parse_signed(int16, int16_t, INT16_MAX)
     191                 :            : __portable_define_parse_unsigned(uint8, uint8_t, UINT8_MAX)
     192                 :            : __portable_define_parse_signed(int8, int8_t, INT8_MAX)
     193                 :            : 
     194                 :            : __portable_define_parse_unsigned(ushort, unsigned short, USHRT_MAX)
     195                 :            : __portable_define_parse_signed(short, short, SHRT_MAX)
     196                 :            : __portable_define_parse_unsigned(uint, unsigned int, UINT_MAX)
     197                 :            : __portable_define_parse_signed(int, int, INT_MAX)
     198                 :            : __portable_define_parse_unsigned(ulong, unsigned long, ULONG_MAX)
     199                 :            : __portable_define_parse_signed(long, unsigned long, LONG_MAX)
     200                 :            : 
     201                 :            : #endif /* PPARSEINT_H */

Generated by: LCOV version 1.12