static const char * lex_parse_mask(const char *p, struct lex_token *token) { struct lex_token mask; /* Parse just past the '/' as a second integer. Handle errors. */ p = lex_parse_integer__(p + 1, &mask); if (mask.type == LEX_T_ERROR) { lex_token_swap(&mask, token); lex_token_destroy(&mask); return p; } ovs_assert(mask.type == LEX_T_INTEGER); /* Now convert the value and mask into a masked integer token. * We have a few special cases. */ token->type = LEX_T_MASKED_INTEGER; memset(&token->mask, 0, sizeof token->mask); uint32_t prefix_bits = ntohll(mask.value.integer); if (token->format == mask.format) { /* Same format value and mask is always OK. */ token->mask = mask.value; } else if (token->format == LEX_F_IPV4 && mask.format == LEX_F_DECIMAL && prefix_bits <= 32) { /* IPv4 address with decimal mask is a CIDR prefix. */ token->mask.integer = htonll(ntohl(be32_prefix_mask(prefix_bits))); } else if (token->format == LEX_F_IPV6 && mask.format == LEX_F_DECIMAL && prefix_bits <= 128) { /* IPv6 address with decimal mask is a CIDR prefix. */ token->mask.ipv6 = ipv6_create_mask(prefix_bits); } else if (token->format == LEX_F_DECIMAL && mask.format == LEX_F_HEXADECIMAL && token->value.integer == 0) { /* Special case for e.g. 0/0x1234. */ token->format = LEX_F_HEXADECIMAL; token->mask = mask.value; } else { lex_error(token, "Value and mask have incompatible formats."); return p; } /* Check invariant that a 1-bit in the value corresponds to a 1-bit in the * mask. */ for (int i = 0; i < ARRAY_SIZE(token->mask.be32); i++) { ovs_be32 v = token->value.be32[i]; ovs_be32 m = token->mask.be32[i]; if (v & ~m) { lex_error(token, "Value contains unmasked 1-bits."); break; } } /* Done! */ lex_token_destroy(&mask); return p; }
/* Obtains the next token from 'lexer' into 'lexer->token', and returns the * token's type. The caller may examine 'lexer->token' directly to obtain full * information about the token. */ enum lex_type lexer_get(struct lexer *lexer) { lex_token_destroy(&lexer->token); lexer->input = lex_token_parse(&lexer->token, lexer->input, &lexer->start); return lexer->token.type; }
/* The string 's' need not be null-terminated at 'length'. */ void lex_token_strcpy(struct lex_token *token, const char *s, size_t length) { lex_token_destroy(token); token->s = (length + 1 <= sizeof token->buffer ? token->buffer : xmalloc(length + 1)); memcpy(token->s, s, length); token->buffer[length] = '\0'; }
/* Returns the type of the next token that will be fetched by lexer_get(), * without advancing 'lexer->token' to that token. */ enum lex_type lexer_lookahead(const struct lexer *lexer) { struct lex_token next; enum lex_type type; const char *start; lex_token_parse(&next, lexer->input, &start); type = next.type; lex_token_destroy(&next); return type; }
void lex_token_vsprintf(struct lex_token *token, const char *format, va_list args) { lex_token_destroy(token); va_list args2; va_copy(args2, args); token->s = (vsnprintf(token->buffer, sizeof token->buffer, format, args) < sizeof token->buffer ? token->buffer : xvasprintf(format, args2)); va_end(args2); }
/* Frees storage associated with 'lexer'. */ void lexer_destroy(struct lexer *lexer) { lex_token_destroy(&lexer->token); }
void lex_token_strset(struct lex_token *token, char *s) { lex_token_destroy(token); token->s = s; }