static const char * lex_parse_integer__(const char *p, struct lex_token *token) { lex_token_init(token); token->type = LEX_T_INTEGER; memset(&token->value, 0, sizeof token->value); const char *start = p; const char *end = start; while (isalnum((unsigned char) *end) || *end == ':' || (*end == '.' && end[1] != '.')) { end++; } size_t len = end - start; int n; struct eth_addr mac; if (!len) { lex_error(token, "Integer constant expected."); } else if (len == 17 && ovs_scan(start, ETH_ADDR_SCAN_FMT"%n", ETH_ADDR_SCAN_ARGS(mac), &n) && n == len) { token->value.mac = mac; token->format = LEX_F_ETHERNET; } else if (start + strspn(start, "0123456789") == end) { if (p[0] == '0' && len > 1) { lex_error(token, "Decimal constants must not have leading zeros."); } else { unsigned long long int integer; char *tail; errno = 0; integer = strtoull(p, &tail, 10); if (tail != end || errno == ERANGE) { lex_error(token, "Decimal constants must be less than 2**64."); } else { token->value.integer = htonll(integer); token->format = LEX_F_DECIMAL; } } } else if (p[0] == '0' && (p[1] == 'x' || p[1] == 'X')) { if (len > 2) { lex_parse_hex_integer(start + 2, len - 2, token); } else { lex_error(token, "Hex digits expected following 0%c.", p[1]); } } else if (len < INET6_ADDRSTRLEN) { char copy[INET6_ADDRSTRLEN]; memcpy(copy, p, len); copy[len] = '\0'; if (ip_parse(copy, &token->value.ipv4)) { token->format = LEX_F_IPV4; } else if (ipv6_parse(copy, &token->value.ipv6)) { token->format = LEX_F_IPV6; } else { lex_error(token, "Invalid numeric constant."); } } else { lex_error(token, "Invalid numeric constant."); } ovs_assert(token->type == LEX_T_INTEGER || token->type == LEX_T_ERROR); return end; }
static const char * lex_parse_integer__(const char *p, struct lex_token *token) { lex_token_init(token); token->type = LEX_T_INTEGER; memset(&token->value, 0, sizeof token->value); /* Find the extent of an "integer" token, which can be in decimal or * hexadecimal, or an Ethernet address or IPv4 or IPv6 address, as 'start' * through 'end'. * * Special cases we handle here are: * * - The ellipsis token "..", used as e.g. 123..456. A doubled dot * is never valid syntax as part of an "integer", so we stop if * we encounter two dots in a row. * * - Syntax like 1.2.3.4:1234 to indicate an IPv4 address followed by a * port number should be considered three tokens: 1.2.3.4 : 1234. * The obvious approach is to allow just dots or just colons within a * given integer, but that would disallow IPv4-mapped IPv6 addresses, * e.g. ::ffff:192.0.2.128. However, even in those addresses, a * colon never follows a dot, so we stop if we encounter a colon * after a dot. * * (There is no corresponding way to parse an IPv6 address followed * by a port number: ::1:2:3:4:1234 is unavoidably ambiguous.) */ const char *start = p; const char *end = start; bool saw_dot = false; while (isalnum((unsigned char) *end) || (*end == ':' && !saw_dot) || (*end == '.' && end[1] != '.')) { if (*end == '.') { saw_dot = true; } end++; } size_t len = end - start; int n; struct eth_addr mac; if (!len) { lex_error(token, "Integer constant expected."); } else if (len == 17 && ovs_scan(start, ETH_ADDR_SCAN_FMT"%n", ETH_ADDR_SCAN_ARGS(mac), &n) && n == len) { token->value.mac = mac; token->format = LEX_F_ETHERNET; } else if (start + strspn(start, "0123456789") == end) { if (p[0] == '0' && len > 1) { lex_error(token, "Decimal constants must not have leading zeros."); } else { unsigned long long int integer; char *tail; errno = 0; integer = strtoull(p, &tail, 10); if (tail != end || errno == ERANGE) { lex_error(token, "Decimal constants must be less than 2**64."); } else { token->value.integer = htonll(integer); token->format = LEX_F_DECIMAL; } } } else if (p[0] == '0' && (p[1] == 'x' || p[1] == 'X')) { if (len > 2) { lex_parse_hex_integer(start + 2, len - 2, token); } else { lex_error(token, "Hex digits expected following 0%c.", p[1]); } } else if (len < INET6_ADDRSTRLEN) { char copy[INET6_ADDRSTRLEN]; memcpy(copy, p, len); copy[len] = '\0'; if (ip_parse(copy, &token->value.ipv4)) { token->format = LEX_F_IPV4; } else if (ipv6_parse(copy, &token->value.ipv6)) { token->format = LEX_F_IPV6; } else { lex_error(token, "Invalid numeric constant."); } } else { lex_error(token, "Invalid numeric constant."); } ovs_assert(token->type == LEX_T_INTEGER || token->type == LEX_T_ERROR); return end; }