1a0698ed9Schristos #include "test/jemalloc_test.h" 2a0698ed9Schristos 3a0698ed9Schristos #include "jemalloc/internal/util.h" 4a0698ed9Schristos 5a0698ed9Schristos typedef enum { 6a0698ed9Schristos TOKEN_TYPE_NONE, 7a0698ed9Schristos TOKEN_TYPE_ERROR, 8a0698ed9Schristos TOKEN_TYPE_EOI, 9a0698ed9Schristos TOKEN_TYPE_NULL, 10a0698ed9Schristos TOKEN_TYPE_FALSE, 11a0698ed9Schristos TOKEN_TYPE_TRUE, 12a0698ed9Schristos TOKEN_TYPE_LBRACKET, 13a0698ed9Schristos TOKEN_TYPE_RBRACKET, 14a0698ed9Schristos TOKEN_TYPE_LBRACE, 15a0698ed9Schristos TOKEN_TYPE_RBRACE, 16a0698ed9Schristos TOKEN_TYPE_COLON, 17a0698ed9Schristos TOKEN_TYPE_COMMA, 18a0698ed9Schristos TOKEN_TYPE_STRING, 19a0698ed9Schristos TOKEN_TYPE_NUMBER 20a0698ed9Schristos } token_type_t; 21a0698ed9Schristos 22a0698ed9Schristos typedef struct parser_s parser_t; 23a0698ed9Schristos typedef struct { 24a0698ed9Schristos parser_t *parser; 25a0698ed9Schristos token_type_t token_type; 26a0698ed9Schristos size_t pos; 27a0698ed9Schristos size_t len; 28a0698ed9Schristos size_t line; 29a0698ed9Schristos size_t col; 30a0698ed9Schristos } token_t; 31a0698ed9Schristos 32a0698ed9Schristos struct parser_s { 33a0698ed9Schristos bool verbose; 34a0698ed9Schristos char *buf; /* '\0'-terminated. */ 35a0698ed9Schristos size_t len; /* Number of characters preceding '\0' in buf. */ 36a0698ed9Schristos size_t pos; 37a0698ed9Schristos size_t line; 38a0698ed9Schristos size_t col; 39a0698ed9Schristos token_t token; 40a0698ed9Schristos }; 41a0698ed9Schristos 42a0698ed9Schristos static void 43a0698ed9Schristos token_init(token_t *token, parser_t *parser, token_type_t token_type, 44a0698ed9Schristos size_t pos, size_t len, size_t line, size_t col) { 45a0698ed9Schristos token->parser = parser; 46a0698ed9Schristos token->token_type = token_type; 47a0698ed9Schristos token->pos = pos; 48a0698ed9Schristos token->len = len; 49a0698ed9Schristos token->line = line; 50a0698ed9Schristos token->col = col; 51a0698ed9Schristos } 52a0698ed9Schristos 53a0698ed9Schristos static void 54a0698ed9Schristos token_error(token_t *token) { 55a0698ed9Schristos if (!token->parser->verbose) { 56a0698ed9Schristos return; 57a0698ed9Schristos } 58a0698ed9Schristos switch (token->token_type) { 59a0698ed9Schristos case TOKEN_TYPE_NONE: 60a0698ed9Schristos not_reached(); 61a0698ed9Schristos case TOKEN_TYPE_ERROR: 62a0698ed9Schristos malloc_printf("%zu:%zu: Unexpected character in token: ", 63a0698ed9Schristos token->line, token->col); 64a0698ed9Schristos break; 65a0698ed9Schristos default: 66a0698ed9Schristos malloc_printf("%zu:%zu: Unexpected token: ", token->line, 67a0698ed9Schristos token->col); 68a0698ed9Schristos break; 69a0698ed9Schristos } 70a0698ed9Schristos UNUSED ssize_t err = malloc_write_fd(STDERR_FILENO, 71a0698ed9Schristos &token->parser->buf[token->pos], token->len); 72a0698ed9Schristos malloc_printf("\n"); 73a0698ed9Schristos } 74a0698ed9Schristos 75a0698ed9Schristos static void 76a0698ed9Schristos parser_init(parser_t *parser, bool verbose) { 77a0698ed9Schristos parser->verbose = verbose; 78a0698ed9Schristos parser->buf = NULL; 79a0698ed9Schristos parser->len = 0; 80a0698ed9Schristos parser->pos = 0; 81a0698ed9Schristos parser->line = 1; 82a0698ed9Schristos parser->col = 0; 83a0698ed9Schristos } 84a0698ed9Schristos 85a0698ed9Schristos static void 86a0698ed9Schristos parser_fini(parser_t *parser) { 87a0698ed9Schristos if (parser->buf != NULL) { 88a0698ed9Schristos dallocx(parser->buf, MALLOCX_TCACHE_NONE); 89a0698ed9Schristos } 90a0698ed9Schristos } 91a0698ed9Schristos 92a0698ed9Schristos static bool 93a0698ed9Schristos parser_append(parser_t *parser, const char *str) { 94a0698ed9Schristos size_t len = strlen(str); 95a0698ed9Schristos char *buf = (parser->buf == NULL) ? mallocx(len + 1, 96a0698ed9Schristos MALLOCX_TCACHE_NONE) : rallocx(parser->buf, parser->len + len + 1, 97a0698ed9Schristos MALLOCX_TCACHE_NONE); 98a0698ed9Schristos if (buf == NULL) { 99a0698ed9Schristos return true; 100a0698ed9Schristos } 101a0698ed9Schristos memcpy(&buf[parser->len], str, len + 1); 102a0698ed9Schristos parser->buf = buf; 103a0698ed9Schristos parser->len += len; 104a0698ed9Schristos return false; 105a0698ed9Schristos } 106a0698ed9Schristos 107a0698ed9Schristos static bool 108a0698ed9Schristos parser_tokenize(parser_t *parser) { 109a0698ed9Schristos enum { 110a0698ed9Schristos STATE_START, 111a0698ed9Schristos STATE_EOI, 112a0698ed9Schristos STATE_N, STATE_NU, STATE_NUL, STATE_NULL, 113a0698ed9Schristos STATE_F, STATE_FA, STATE_FAL, STATE_FALS, STATE_FALSE, 114a0698ed9Schristos STATE_T, STATE_TR, STATE_TRU, STATE_TRUE, 115a0698ed9Schristos STATE_LBRACKET, 116a0698ed9Schristos STATE_RBRACKET, 117a0698ed9Schristos STATE_LBRACE, 118a0698ed9Schristos STATE_RBRACE, 119a0698ed9Schristos STATE_COLON, 120a0698ed9Schristos STATE_COMMA, 121a0698ed9Schristos STATE_CHARS, 122a0698ed9Schristos STATE_CHAR_ESCAPE, 123a0698ed9Schristos STATE_CHAR_U, STATE_CHAR_UD, STATE_CHAR_UDD, STATE_CHAR_UDDD, 124a0698ed9Schristos STATE_STRING, 125a0698ed9Schristos STATE_MINUS, 126a0698ed9Schristos STATE_LEADING_ZERO, 127a0698ed9Schristos STATE_DIGITS, 128a0698ed9Schristos STATE_DECIMAL, 129a0698ed9Schristos STATE_FRAC_DIGITS, 130a0698ed9Schristos STATE_EXP, 131a0698ed9Schristos STATE_EXP_SIGN, 132a0698ed9Schristos STATE_EXP_DIGITS, 133a0698ed9Schristos STATE_ACCEPT 134a0698ed9Schristos } state = STATE_START; 135a0698ed9Schristos size_t token_pos JEMALLOC_CC_SILENCE_INIT(0); 136a0698ed9Schristos size_t token_line JEMALLOC_CC_SILENCE_INIT(1); 137a0698ed9Schristos size_t token_col JEMALLOC_CC_SILENCE_INIT(0); 138a0698ed9Schristos 139*7bdf38e5Schristos expect_zu_le(parser->pos, parser->len, 140a0698ed9Schristos "Position is past end of buffer"); 141a0698ed9Schristos 142a0698ed9Schristos while (state != STATE_ACCEPT) { 143a0698ed9Schristos char c = parser->buf[parser->pos]; 144a0698ed9Schristos 145a0698ed9Schristos switch (state) { 146a0698ed9Schristos case STATE_START: 147a0698ed9Schristos token_pos = parser->pos; 148a0698ed9Schristos token_line = parser->line; 149a0698ed9Schristos token_col = parser->col; 150a0698ed9Schristos switch (c) { 151a0698ed9Schristos case ' ': case '\b': case '\n': case '\r': case '\t': 152a0698ed9Schristos break; 153a0698ed9Schristos case '\0': 154a0698ed9Schristos state = STATE_EOI; 155a0698ed9Schristos break; 156a0698ed9Schristos case 'n': 157a0698ed9Schristos state = STATE_N; 158a0698ed9Schristos break; 159a0698ed9Schristos case 'f': 160a0698ed9Schristos state = STATE_F; 161a0698ed9Schristos break; 162a0698ed9Schristos case 't': 163a0698ed9Schristos state = STATE_T; 164a0698ed9Schristos break; 165a0698ed9Schristos case '[': 166a0698ed9Schristos state = STATE_LBRACKET; 167a0698ed9Schristos break; 168a0698ed9Schristos case ']': 169a0698ed9Schristos state = STATE_RBRACKET; 170a0698ed9Schristos break; 171a0698ed9Schristos case '{': 172a0698ed9Schristos state = STATE_LBRACE; 173a0698ed9Schristos break; 174a0698ed9Schristos case '}': 175a0698ed9Schristos state = STATE_RBRACE; 176a0698ed9Schristos break; 177a0698ed9Schristos case ':': 178a0698ed9Schristos state = STATE_COLON; 179a0698ed9Schristos break; 180a0698ed9Schristos case ',': 181a0698ed9Schristos state = STATE_COMMA; 182a0698ed9Schristos break; 183a0698ed9Schristos case '"': 184a0698ed9Schristos state = STATE_CHARS; 185a0698ed9Schristos break; 186a0698ed9Schristos case '-': 187a0698ed9Schristos state = STATE_MINUS; 188a0698ed9Schristos break; 189a0698ed9Schristos case '0': 190a0698ed9Schristos state = STATE_LEADING_ZERO; 191a0698ed9Schristos break; 192a0698ed9Schristos case '1': case '2': case '3': case '4': 193a0698ed9Schristos case '5': case '6': case '7': case '8': case '9': 194a0698ed9Schristos state = STATE_DIGITS; 195a0698ed9Schristos break; 196a0698ed9Schristos default: 197a0698ed9Schristos token_init(&parser->token, parser, 198a0698ed9Schristos TOKEN_TYPE_ERROR, token_pos, parser->pos + 1 199a0698ed9Schristos - token_pos, token_line, token_col); 200a0698ed9Schristos return true; 201a0698ed9Schristos } 202a0698ed9Schristos break; 203a0698ed9Schristos case STATE_EOI: 204a0698ed9Schristos token_init(&parser->token, parser, 205a0698ed9Schristos TOKEN_TYPE_EOI, token_pos, parser->pos - 206a0698ed9Schristos token_pos, token_line, token_col); 207a0698ed9Schristos state = STATE_ACCEPT; 208a0698ed9Schristos break; 209a0698ed9Schristos case STATE_N: 210a0698ed9Schristos switch (c) { 211a0698ed9Schristos case 'u': 212a0698ed9Schristos state = STATE_NU; 213a0698ed9Schristos break; 214a0698ed9Schristos default: 215a0698ed9Schristos token_init(&parser->token, parser, 216a0698ed9Schristos TOKEN_TYPE_ERROR, token_pos, parser->pos + 1 217a0698ed9Schristos - token_pos, token_line, token_col); 218a0698ed9Schristos return true; 219a0698ed9Schristos } 220a0698ed9Schristos break; 221a0698ed9Schristos case STATE_NU: 222a0698ed9Schristos switch (c) { 223a0698ed9Schristos case 'l': 224a0698ed9Schristos state = STATE_NUL; 225a0698ed9Schristos break; 226a0698ed9Schristos default: 227a0698ed9Schristos token_init(&parser->token, parser, 228a0698ed9Schristos TOKEN_TYPE_ERROR, token_pos, parser->pos + 1 229a0698ed9Schristos - token_pos, token_line, token_col); 230a0698ed9Schristos return true; 231a0698ed9Schristos } 232a0698ed9Schristos break; 233a0698ed9Schristos case STATE_NUL: 234a0698ed9Schristos switch (c) { 235a0698ed9Schristos case 'l': 236a0698ed9Schristos state = STATE_NULL; 237a0698ed9Schristos break; 238a0698ed9Schristos default: 239a0698ed9Schristos token_init(&parser->token, parser, 240a0698ed9Schristos TOKEN_TYPE_ERROR, token_pos, parser->pos + 1 241a0698ed9Schristos - token_pos, token_line, token_col); 242a0698ed9Schristos return true; 243a0698ed9Schristos } 244a0698ed9Schristos break; 245a0698ed9Schristos case STATE_NULL: 246a0698ed9Schristos switch (c) { 247a0698ed9Schristos case ' ': case '\b': case '\n': case '\r': case '\t': 248a0698ed9Schristos case '\0': 249a0698ed9Schristos case '[': case ']': case '{': case '}': case ':': 250a0698ed9Schristos case ',': 251a0698ed9Schristos break; 252a0698ed9Schristos default: 253a0698ed9Schristos token_init(&parser->token, parser, 254a0698ed9Schristos TOKEN_TYPE_ERROR, token_pos, parser->pos + 1 255a0698ed9Schristos - token_pos, token_line, token_col); 256a0698ed9Schristos return true; 257a0698ed9Schristos } 258a0698ed9Schristos token_init(&parser->token, parser, TOKEN_TYPE_NULL, 259a0698ed9Schristos token_pos, parser->pos - token_pos, token_line, 260a0698ed9Schristos token_col); 261a0698ed9Schristos state = STATE_ACCEPT; 262a0698ed9Schristos break; 263a0698ed9Schristos case STATE_F: 264a0698ed9Schristos switch (c) { 265a0698ed9Schristos case 'a': 266a0698ed9Schristos state = STATE_FA; 267a0698ed9Schristos break; 268a0698ed9Schristos default: 269a0698ed9Schristos token_init(&parser->token, parser, 270a0698ed9Schristos TOKEN_TYPE_ERROR, token_pos, parser->pos + 1 271a0698ed9Schristos - token_pos, token_line, token_col); 272a0698ed9Schristos return true; 273a0698ed9Schristos } 274a0698ed9Schristos break; 275a0698ed9Schristos case STATE_FA: 276a0698ed9Schristos switch (c) { 277a0698ed9Schristos case 'l': 278a0698ed9Schristos state = STATE_FAL; 279a0698ed9Schristos break; 280a0698ed9Schristos default: 281a0698ed9Schristos token_init(&parser->token, parser, 282a0698ed9Schristos TOKEN_TYPE_ERROR, token_pos, parser->pos + 1 283a0698ed9Schristos - token_pos, token_line, token_col); 284a0698ed9Schristos return true; 285a0698ed9Schristos } 286a0698ed9Schristos break; 287a0698ed9Schristos case STATE_FAL: 288a0698ed9Schristos switch (c) { 289a0698ed9Schristos case 's': 290a0698ed9Schristos state = STATE_FALS; 291a0698ed9Schristos break; 292a0698ed9Schristos default: 293a0698ed9Schristos token_init(&parser->token, parser, 294a0698ed9Schristos TOKEN_TYPE_ERROR, token_pos, parser->pos + 1 295a0698ed9Schristos - token_pos, token_line, token_col); 296a0698ed9Schristos return true; 297a0698ed9Schristos } 298a0698ed9Schristos break; 299a0698ed9Schristos case STATE_FALS: 300a0698ed9Schristos switch (c) { 301a0698ed9Schristos case 'e': 302a0698ed9Schristos state = STATE_FALSE; 303a0698ed9Schristos break; 304a0698ed9Schristos default: 305a0698ed9Schristos token_init(&parser->token, parser, 306a0698ed9Schristos TOKEN_TYPE_ERROR, token_pos, parser->pos + 1 307a0698ed9Schristos - token_pos, token_line, token_col); 308a0698ed9Schristos return true; 309a0698ed9Schristos } 310a0698ed9Schristos break; 311a0698ed9Schristos case STATE_FALSE: 312a0698ed9Schristos switch (c) { 313a0698ed9Schristos case ' ': case '\b': case '\n': case '\r': case '\t': 314a0698ed9Schristos case '\0': 315a0698ed9Schristos case '[': case ']': case '{': case '}': case ':': 316a0698ed9Schristos case ',': 317a0698ed9Schristos break; 318a0698ed9Schristos default: 319a0698ed9Schristos token_init(&parser->token, parser, 320a0698ed9Schristos TOKEN_TYPE_ERROR, token_pos, parser->pos + 1 321a0698ed9Schristos - token_pos, token_line, token_col); 322a0698ed9Schristos return true; 323a0698ed9Schristos } 324a0698ed9Schristos token_init(&parser->token, parser, 325a0698ed9Schristos TOKEN_TYPE_FALSE, token_pos, parser->pos - 326a0698ed9Schristos token_pos, token_line, token_col); 327a0698ed9Schristos state = STATE_ACCEPT; 328a0698ed9Schristos break; 329a0698ed9Schristos case STATE_T: 330a0698ed9Schristos switch (c) { 331a0698ed9Schristos case 'r': 332a0698ed9Schristos state = STATE_TR; 333a0698ed9Schristos break; 334a0698ed9Schristos default: 335a0698ed9Schristos token_init(&parser->token, parser, 336a0698ed9Schristos TOKEN_TYPE_ERROR, token_pos, parser->pos + 1 337a0698ed9Schristos - token_pos, token_line, token_col); 338a0698ed9Schristos return true; 339a0698ed9Schristos } 340a0698ed9Schristos break; 341a0698ed9Schristos case STATE_TR: 342a0698ed9Schristos switch (c) { 343a0698ed9Schristos case 'u': 344a0698ed9Schristos state = STATE_TRU; 345a0698ed9Schristos break; 346a0698ed9Schristos default: 347a0698ed9Schristos token_init(&parser->token, parser, 348a0698ed9Schristos TOKEN_TYPE_ERROR, token_pos, parser->pos + 1 349a0698ed9Schristos - token_pos, token_line, token_col); 350a0698ed9Schristos return true; 351a0698ed9Schristos } 352a0698ed9Schristos break; 353a0698ed9Schristos case STATE_TRU: 354a0698ed9Schristos switch (c) { 355a0698ed9Schristos case 'e': 356a0698ed9Schristos state = STATE_TRUE; 357a0698ed9Schristos break; 358a0698ed9Schristos default: 359a0698ed9Schristos token_init(&parser->token, parser, 360a0698ed9Schristos TOKEN_TYPE_ERROR, token_pos, parser->pos + 1 361a0698ed9Schristos - token_pos, token_line, token_col); 362a0698ed9Schristos return true; 363a0698ed9Schristos } 364a0698ed9Schristos break; 365a0698ed9Schristos case STATE_TRUE: 366a0698ed9Schristos switch (c) { 367a0698ed9Schristos case ' ': case '\b': case '\n': case '\r': case '\t': 368a0698ed9Schristos case '\0': 369a0698ed9Schristos case '[': case ']': case '{': case '}': case ':': 370a0698ed9Schristos case ',': 371a0698ed9Schristos break; 372a0698ed9Schristos default: 373a0698ed9Schristos token_init(&parser->token, parser, 374a0698ed9Schristos TOKEN_TYPE_ERROR, token_pos, parser->pos + 1 375a0698ed9Schristos - token_pos, token_line, token_col); 376a0698ed9Schristos return true; 377a0698ed9Schristos } 378a0698ed9Schristos token_init(&parser->token, parser, TOKEN_TYPE_TRUE, 379a0698ed9Schristos token_pos, parser->pos - token_pos, token_line, 380a0698ed9Schristos token_col); 381a0698ed9Schristos state = STATE_ACCEPT; 382a0698ed9Schristos break; 383a0698ed9Schristos case STATE_LBRACKET: 384a0698ed9Schristos token_init(&parser->token, parser, TOKEN_TYPE_LBRACKET, 385a0698ed9Schristos token_pos, parser->pos - token_pos, token_line, 386a0698ed9Schristos token_col); 387a0698ed9Schristos state = STATE_ACCEPT; 388a0698ed9Schristos break; 389a0698ed9Schristos case STATE_RBRACKET: 390a0698ed9Schristos token_init(&parser->token, parser, TOKEN_TYPE_RBRACKET, 391a0698ed9Schristos token_pos, parser->pos - token_pos, token_line, 392a0698ed9Schristos token_col); 393a0698ed9Schristos state = STATE_ACCEPT; 394a0698ed9Schristos break; 395a0698ed9Schristos case STATE_LBRACE: 396a0698ed9Schristos token_init(&parser->token, parser, TOKEN_TYPE_LBRACE, 397a0698ed9Schristos token_pos, parser->pos - token_pos, token_line, 398a0698ed9Schristos token_col); 399a0698ed9Schristos state = STATE_ACCEPT; 400a0698ed9Schristos break; 401a0698ed9Schristos case STATE_RBRACE: 402a0698ed9Schristos token_init(&parser->token, parser, TOKEN_TYPE_RBRACE, 403a0698ed9Schristos token_pos, parser->pos - token_pos, token_line, 404a0698ed9Schristos token_col); 405a0698ed9Schristos state = STATE_ACCEPT; 406a0698ed9Schristos break; 407a0698ed9Schristos case STATE_COLON: 408a0698ed9Schristos token_init(&parser->token, parser, TOKEN_TYPE_COLON, 409a0698ed9Schristos token_pos, parser->pos - token_pos, token_line, 410a0698ed9Schristos token_col); 411a0698ed9Schristos state = STATE_ACCEPT; 412a0698ed9Schristos break; 413a0698ed9Schristos case STATE_COMMA: 414a0698ed9Schristos token_init(&parser->token, parser, TOKEN_TYPE_COMMA, 415a0698ed9Schristos token_pos, parser->pos - token_pos, token_line, 416a0698ed9Schristos token_col); 417a0698ed9Schristos state = STATE_ACCEPT; 418a0698ed9Schristos break; 419a0698ed9Schristos case STATE_CHARS: 420a0698ed9Schristos switch (c) { 421a0698ed9Schristos case '\\': 422a0698ed9Schristos state = STATE_CHAR_ESCAPE; 423a0698ed9Schristos break; 424a0698ed9Schristos case '"': 425a0698ed9Schristos state = STATE_STRING; 426a0698ed9Schristos break; 427a0698ed9Schristos case 0x00: case 0x01: case 0x02: case 0x03: case 0x04: 428a0698ed9Schristos case 0x05: case 0x06: case 0x07: case 0x08: case 0x09: 429a0698ed9Schristos case 0x0a: case 0x0b: case 0x0c: case 0x0d: case 0x0e: 430a0698ed9Schristos case 0x0f: case 0x10: case 0x11: case 0x12: case 0x13: 431a0698ed9Schristos case 0x14: case 0x15: case 0x16: case 0x17: case 0x18: 432a0698ed9Schristos case 0x19: case 0x1a: case 0x1b: case 0x1c: case 0x1d: 433a0698ed9Schristos case 0x1e: case 0x1f: 434a0698ed9Schristos token_init(&parser->token, parser, 435a0698ed9Schristos TOKEN_TYPE_ERROR, token_pos, parser->pos + 1 436a0698ed9Schristos - token_pos, token_line, token_col); 437a0698ed9Schristos return true; 438a0698ed9Schristos default: 439a0698ed9Schristos break; 440a0698ed9Schristos } 441a0698ed9Schristos break; 442a0698ed9Schristos case STATE_CHAR_ESCAPE: 443a0698ed9Schristos switch (c) { 444a0698ed9Schristos case '"': case '\\': case '/': case 'b': case 'n': 445a0698ed9Schristos case 'r': case 't': 446a0698ed9Schristos state = STATE_CHARS; 447a0698ed9Schristos break; 448a0698ed9Schristos case 'u': 449a0698ed9Schristos state = STATE_CHAR_U; 450a0698ed9Schristos break; 451a0698ed9Schristos default: 452a0698ed9Schristos token_init(&parser->token, parser, 453a0698ed9Schristos TOKEN_TYPE_ERROR, token_pos, parser->pos + 1 454a0698ed9Schristos - token_pos, token_line, token_col); 455a0698ed9Schristos return true; 456a0698ed9Schristos } 457a0698ed9Schristos break; 458a0698ed9Schristos case STATE_CHAR_U: 459a0698ed9Schristos switch (c) { 460a0698ed9Schristos case '0': case '1': case '2': case '3': case '4': 461a0698ed9Schristos case '5': case '6': case '7': case '8': case '9': 462a0698ed9Schristos case 'a': case 'b': case 'c': case 'd': case 'e': 463a0698ed9Schristos case 'f': 464a0698ed9Schristos case 'A': case 'B': case 'C': case 'D': case 'E': 465a0698ed9Schristos case 'F': 466a0698ed9Schristos state = STATE_CHAR_UD; 467a0698ed9Schristos break; 468a0698ed9Schristos default: 469a0698ed9Schristos token_init(&parser->token, parser, 470a0698ed9Schristos TOKEN_TYPE_ERROR, token_pos, parser->pos + 1 471a0698ed9Schristos - token_pos, token_line, token_col); 472a0698ed9Schristos return true; 473a0698ed9Schristos } 474a0698ed9Schristos break; 475a0698ed9Schristos case STATE_CHAR_UD: 476a0698ed9Schristos switch (c) { 477a0698ed9Schristos case '0': case '1': case '2': case '3': case '4': 478a0698ed9Schristos case '5': case '6': case '7': case '8': case '9': 479a0698ed9Schristos case 'a': case 'b': case 'c': case 'd': case 'e': 480a0698ed9Schristos case 'f': 481a0698ed9Schristos case 'A': case 'B': case 'C': case 'D': case 'E': 482a0698ed9Schristos case 'F': 483a0698ed9Schristos state = STATE_CHAR_UDD; 484a0698ed9Schristos break; 485a0698ed9Schristos default: 486a0698ed9Schristos token_init(&parser->token, parser, 487a0698ed9Schristos TOKEN_TYPE_ERROR, token_pos, parser->pos + 1 488a0698ed9Schristos - token_pos, token_line, token_col); 489a0698ed9Schristos return true; 490a0698ed9Schristos } 491a0698ed9Schristos break; 492a0698ed9Schristos case STATE_CHAR_UDD: 493a0698ed9Schristos switch (c) { 494a0698ed9Schristos case '0': case '1': case '2': case '3': case '4': 495a0698ed9Schristos case '5': case '6': case '7': case '8': case '9': 496a0698ed9Schristos case 'a': case 'b': case 'c': case 'd': case 'e': 497a0698ed9Schristos case 'f': 498a0698ed9Schristos case 'A': case 'B': case 'C': case 'D': case 'E': 499a0698ed9Schristos case 'F': 500a0698ed9Schristos state = STATE_CHAR_UDDD; 501a0698ed9Schristos break; 502a0698ed9Schristos default: 503a0698ed9Schristos token_init(&parser->token, parser, 504a0698ed9Schristos TOKEN_TYPE_ERROR, token_pos, parser->pos + 1 505a0698ed9Schristos - token_pos, token_line, token_col); 506a0698ed9Schristos return true; 507a0698ed9Schristos } 508a0698ed9Schristos break; 509a0698ed9Schristos case STATE_CHAR_UDDD: 510a0698ed9Schristos switch (c) { 511a0698ed9Schristos case '0': case '1': case '2': case '3': case '4': 512a0698ed9Schristos case '5': case '6': case '7': case '8': case '9': 513a0698ed9Schristos case 'a': case 'b': case 'c': case 'd': case 'e': 514a0698ed9Schristos case 'f': 515a0698ed9Schristos case 'A': case 'B': case 'C': case 'D': case 'E': 516a0698ed9Schristos case 'F': 517a0698ed9Schristos state = STATE_CHARS; 518a0698ed9Schristos break; 519a0698ed9Schristos default: 520a0698ed9Schristos token_init(&parser->token, parser, 521a0698ed9Schristos TOKEN_TYPE_ERROR, token_pos, parser->pos + 1 522a0698ed9Schristos - token_pos, token_line, token_col); 523a0698ed9Schristos return true; 524a0698ed9Schristos } 525a0698ed9Schristos break; 526a0698ed9Schristos case STATE_STRING: 527a0698ed9Schristos token_init(&parser->token, parser, TOKEN_TYPE_STRING, 528a0698ed9Schristos token_pos, parser->pos - token_pos, token_line, 529a0698ed9Schristos token_col); 530a0698ed9Schristos state = STATE_ACCEPT; 531a0698ed9Schristos break; 532a0698ed9Schristos case STATE_MINUS: 533a0698ed9Schristos switch (c) { 534a0698ed9Schristos case '0': 535a0698ed9Schristos state = STATE_LEADING_ZERO; 536a0698ed9Schristos break; 537a0698ed9Schristos case '1': case '2': case '3': case '4': 538a0698ed9Schristos case '5': case '6': case '7': case '8': case '9': 539a0698ed9Schristos state = STATE_DIGITS; 540a0698ed9Schristos break; 541a0698ed9Schristos default: 542a0698ed9Schristos token_init(&parser->token, parser, 543a0698ed9Schristos TOKEN_TYPE_ERROR, token_pos, parser->pos + 1 544a0698ed9Schristos - token_pos, token_line, token_col); 545a0698ed9Schristos return true; 546a0698ed9Schristos } 547a0698ed9Schristos break; 548a0698ed9Schristos case STATE_LEADING_ZERO: 549a0698ed9Schristos switch (c) { 550a0698ed9Schristos case '.': 551a0698ed9Schristos state = STATE_DECIMAL; 552a0698ed9Schristos break; 553a0698ed9Schristos default: 554a0698ed9Schristos token_init(&parser->token, parser, 555a0698ed9Schristos TOKEN_TYPE_NUMBER, token_pos, parser->pos - 556a0698ed9Schristos token_pos, token_line, token_col); 557a0698ed9Schristos state = STATE_ACCEPT; 558a0698ed9Schristos break; 559a0698ed9Schristos } 560a0698ed9Schristos break; 561a0698ed9Schristos case STATE_DIGITS: 562a0698ed9Schristos switch (c) { 563a0698ed9Schristos case '0': case '1': case '2': case '3': case '4': 564a0698ed9Schristos case '5': case '6': case '7': case '8': case '9': 565a0698ed9Schristos break; 566a0698ed9Schristos case '.': 567a0698ed9Schristos state = STATE_DECIMAL; 568a0698ed9Schristos break; 569a0698ed9Schristos default: 570a0698ed9Schristos token_init(&parser->token, parser, 571a0698ed9Schristos TOKEN_TYPE_NUMBER, token_pos, parser->pos - 572a0698ed9Schristos token_pos, token_line, token_col); 573a0698ed9Schristos state = STATE_ACCEPT; 574a0698ed9Schristos break; 575a0698ed9Schristos } 576a0698ed9Schristos break; 577a0698ed9Schristos case STATE_DECIMAL: 578a0698ed9Schristos switch (c) { 579a0698ed9Schristos case '0': case '1': case '2': case '3': case '4': 580a0698ed9Schristos case '5': case '6': case '7': case '8': case '9': 581a0698ed9Schristos state = STATE_FRAC_DIGITS; 582a0698ed9Schristos break; 583a0698ed9Schristos default: 584a0698ed9Schristos token_init(&parser->token, parser, 585a0698ed9Schristos TOKEN_TYPE_ERROR, token_pos, parser->pos + 1 586a0698ed9Schristos - token_pos, token_line, token_col); 587a0698ed9Schristos return true; 588a0698ed9Schristos } 589a0698ed9Schristos break; 590a0698ed9Schristos case STATE_FRAC_DIGITS: 591a0698ed9Schristos switch (c) { 592a0698ed9Schristos case '0': case '1': case '2': case '3': case '4': 593a0698ed9Schristos case '5': case '6': case '7': case '8': case '9': 594a0698ed9Schristos break; 595a0698ed9Schristos case 'e': case 'E': 596a0698ed9Schristos state = STATE_EXP; 597a0698ed9Schristos break; 598a0698ed9Schristos default: 599a0698ed9Schristos token_init(&parser->token, parser, 600a0698ed9Schristos TOKEN_TYPE_NUMBER, token_pos, parser->pos - 601a0698ed9Schristos token_pos, token_line, token_col); 602a0698ed9Schristos state = STATE_ACCEPT; 603a0698ed9Schristos break; 604a0698ed9Schristos } 605a0698ed9Schristos break; 606a0698ed9Schristos case STATE_EXP: 607a0698ed9Schristos switch (c) { 608a0698ed9Schristos case '-': case '+': 609a0698ed9Schristos state = STATE_EXP_SIGN; 610a0698ed9Schristos break; 611a0698ed9Schristos case '0': case '1': case '2': case '3': case '4': 612a0698ed9Schristos case '5': case '6': case '7': case '8': case '9': 613a0698ed9Schristos state = STATE_EXP_DIGITS; 614a0698ed9Schristos break; 615a0698ed9Schristos default: 616a0698ed9Schristos token_init(&parser->token, parser, 617a0698ed9Schristos TOKEN_TYPE_ERROR, token_pos, parser->pos + 1 618a0698ed9Schristos - token_pos, token_line, token_col); 619a0698ed9Schristos return true; 620a0698ed9Schristos } 621a0698ed9Schristos break; 622a0698ed9Schristos case STATE_EXP_SIGN: 623a0698ed9Schristos switch (c) { 624a0698ed9Schristos case '0': case '1': case '2': case '3': case '4': 625a0698ed9Schristos case '5': case '6': case '7': case '8': case '9': 626a0698ed9Schristos state = STATE_EXP_DIGITS; 627a0698ed9Schristos break; 628a0698ed9Schristos default: 629a0698ed9Schristos token_init(&parser->token, parser, 630a0698ed9Schristos TOKEN_TYPE_ERROR, token_pos, parser->pos + 1 631a0698ed9Schristos - token_pos, token_line, token_col); 632a0698ed9Schristos return true; 633a0698ed9Schristos } 634a0698ed9Schristos break; 635a0698ed9Schristos case STATE_EXP_DIGITS: 636a0698ed9Schristos switch (c) { 637a0698ed9Schristos case '0': case '1': case '2': case '3': case '4': 638a0698ed9Schristos case '5': case '6': case '7': case '8': case '9': 639a0698ed9Schristos break; 640a0698ed9Schristos default: 641a0698ed9Schristos token_init(&parser->token, parser, 642a0698ed9Schristos TOKEN_TYPE_NUMBER, token_pos, parser->pos - 643a0698ed9Schristos token_pos, token_line, token_col); 644a0698ed9Schristos state = STATE_ACCEPT; 645a0698ed9Schristos break; 646a0698ed9Schristos } 647a0698ed9Schristos break; 648a0698ed9Schristos default: 649a0698ed9Schristos not_reached(); 650a0698ed9Schristos } 651a0698ed9Schristos 652a0698ed9Schristos if (state != STATE_ACCEPT) { 653a0698ed9Schristos if (c == '\n') { 654a0698ed9Schristos parser->line++; 655a0698ed9Schristos parser->col = 0; 656a0698ed9Schristos } else { 657a0698ed9Schristos parser->col++; 658a0698ed9Schristos } 659a0698ed9Schristos parser->pos++; 660a0698ed9Schristos } 661a0698ed9Schristos } 662a0698ed9Schristos return false; 663a0698ed9Schristos } 664a0698ed9Schristos 665a0698ed9Schristos static bool parser_parse_array(parser_t *parser); 666a0698ed9Schristos static bool parser_parse_object(parser_t *parser); 667a0698ed9Schristos 668a0698ed9Schristos static bool 669a0698ed9Schristos parser_parse_value(parser_t *parser) { 670a0698ed9Schristos switch (parser->token.token_type) { 671a0698ed9Schristos case TOKEN_TYPE_NULL: 672a0698ed9Schristos case TOKEN_TYPE_FALSE: 673a0698ed9Schristos case TOKEN_TYPE_TRUE: 674a0698ed9Schristos case TOKEN_TYPE_STRING: 675a0698ed9Schristos case TOKEN_TYPE_NUMBER: 676a0698ed9Schristos return false; 677a0698ed9Schristos case TOKEN_TYPE_LBRACE: 678a0698ed9Schristos return parser_parse_object(parser); 679a0698ed9Schristos case TOKEN_TYPE_LBRACKET: 680a0698ed9Schristos return parser_parse_array(parser); 681a0698ed9Schristos default: 682a0698ed9Schristos return true; 683a0698ed9Schristos } 684a0698ed9Schristos not_reached(); 685a0698ed9Schristos } 686a0698ed9Schristos 687a0698ed9Schristos static bool 688a0698ed9Schristos parser_parse_pair(parser_t *parser) { 689*7bdf38e5Schristos expect_d_eq(parser->token.token_type, TOKEN_TYPE_STRING, 690a0698ed9Schristos "Pair should start with string"); 691a0698ed9Schristos if (parser_tokenize(parser)) { 692a0698ed9Schristos return true; 693a0698ed9Schristos } 694a0698ed9Schristos switch (parser->token.token_type) { 695a0698ed9Schristos case TOKEN_TYPE_COLON: 696a0698ed9Schristos if (parser_tokenize(parser)) { 697a0698ed9Schristos return true; 698a0698ed9Schristos } 699a0698ed9Schristos return parser_parse_value(parser); 700a0698ed9Schristos default: 701a0698ed9Schristos return true; 702a0698ed9Schristos } 703a0698ed9Schristos } 704a0698ed9Schristos 705a0698ed9Schristos static bool 706a0698ed9Schristos parser_parse_values(parser_t *parser) { 707a0698ed9Schristos if (parser_parse_value(parser)) { 708a0698ed9Schristos return true; 709a0698ed9Schristos } 710a0698ed9Schristos 711a0698ed9Schristos while (true) { 712a0698ed9Schristos if (parser_tokenize(parser)) { 713a0698ed9Schristos return true; 714a0698ed9Schristos } 715a0698ed9Schristos switch (parser->token.token_type) { 716a0698ed9Schristos case TOKEN_TYPE_COMMA: 717a0698ed9Schristos if (parser_tokenize(parser)) { 718a0698ed9Schristos return true; 719a0698ed9Schristos } 720a0698ed9Schristos if (parser_parse_value(parser)) { 721a0698ed9Schristos return true; 722a0698ed9Schristos } 723a0698ed9Schristos break; 724a0698ed9Schristos case TOKEN_TYPE_RBRACKET: 725a0698ed9Schristos return false; 726a0698ed9Schristos default: 727a0698ed9Schristos return true; 728a0698ed9Schristos } 729a0698ed9Schristos } 730a0698ed9Schristos } 731a0698ed9Schristos 732a0698ed9Schristos static bool 733a0698ed9Schristos parser_parse_array(parser_t *parser) { 734*7bdf38e5Schristos expect_d_eq(parser->token.token_type, TOKEN_TYPE_LBRACKET, 735a0698ed9Schristos "Array should start with ["); 736a0698ed9Schristos if (parser_tokenize(parser)) { 737a0698ed9Schristos return true; 738a0698ed9Schristos } 739a0698ed9Schristos switch (parser->token.token_type) { 740a0698ed9Schristos case TOKEN_TYPE_RBRACKET: 741a0698ed9Schristos return false; 742a0698ed9Schristos default: 743a0698ed9Schristos return parser_parse_values(parser); 744a0698ed9Schristos } 745a0698ed9Schristos not_reached(); 746a0698ed9Schristos } 747a0698ed9Schristos 748a0698ed9Schristos static bool 749a0698ed9Schristos parser_parse_pairs(parser_t *parser) { 750*7bdf38e5Schristos expect_d_eq(parser->token.token_type, TOKEN_TYPE_STRING, 751a0698ed9Schristos "Object should start with string"); 752a0698ed9Schristos if (parser_parse_pair(parser)) { 753a0698ed9Schristos return true; 754a0698ed9Schristos } 755a0698ed9Schristos 756a0698ed9Schristos while (true) { 757a0698ed9Schristos if (parser_tokenize(parser)) { 758a0698ed9Schristos return true; 759a0698ed9Schristos } 760a0698ed9Schristos switch (parser->token.token_type) { 761a0698ed9Schristos case TOKEN_TYPE_COMMA: 762a0698ed9Schristos if (parser_tokenize(parser)) { 763a0698ed9Schristos return true; 764a0698ed9Schristos } 765a0698ed9Schristos switch (parser->token.token_type) { 766a0698ed9Schristos case TOKEN_TYPE_STRING: 767a0698ed9Schristos if (parser_parse_pair(parser)) { 768a0698ed9Schristos return true; 769a0698ed9Schristos } 770a0698ed9Schristos break; 771a0698ed9Schristos default: 772a0698ed9Schristos return true; 773a0698ed9Schristos } 774a0698ed9Schristos break; 775a0698ed9Schristos case TOKEN_TYPE_RBRACE: 776a0698ed9Schristos return false; 777a0698ed9Schristos default: 778a0698ed9Schristos return true; 779a0698ed9Schristos } 780a0698ed9Schristos } 781a0698ed9Schristos } 782a0698ed9Schristos 783a0698ed9Schristos static bool 784a0698ed9Schristos parser_parse_object(parser_t *parser) { 785*7bdf38e5Schristos expect_d_eq(parser->token.token_type, TOKEN_TYPE_LBRACE, 786a0698ed9Schristos "Object should start with {"); 787a0698ed9Schristos if (parser_tokenize(parser)) { 788a0698ed9Schristos return true; 789a0698ed9Schristos } 790a0698ed9Schristos switch (parser->token.token_type) { 791a0698ed9Schristos case TOKEN_TYPE_STRING: 792a0698ed9Schristos return parser_parse_pairs(parser); 793a0698ed9Schristos case TOKEN_TYPE_RBRACE: 794a0698ed9Schristos return false; 795a0698ed9Schristos default: 796a0698ed9Schristos return true; 797a0698ed9Schristos } 798a0698ed9Schristos not_reached(); 799a0698ed9Schristos } 800a0698ed9Schristos 801a0698ed9Schristos static bool 802a0698ed9Schristos parser_parse(parser_t *parser) { 803a0698ed9Schristos if (parser_tokenize(parser)) { 804a0698ed9Schristos goto label_error; 805a0698ed9Schristos } 806a0698ed9Schristos if (parser_parse_value(parser)) { 807a0698ed9Schristos goto label_error; 808a0698ed9Schristos } 809a0698ed9Schristos 810a0698ed9Schristos if (parser_tokenize(parser)) { 811a0698ed9Schristos goto label_error; 812a0698ed9Schristos } 813a0698ed9Schristos switch (parser->token.token_type) { 814a0698ed9Schristos case TOKEN_TYPE_EOI: 815a0698ed9Schristos return false; 816a0698ed9Schristos default: 817a0698ed9Schristos goto label_error; 818a0698ed9Schristos } 819a0698ed9Schristos not_reached(); 820a0698ed9Schristos 821a0698ed9Schristos label_error: 822a0698ed9Schristos token_error(&parser->token); 823a0698ed9Schristos return true; 824a0698ed9Schristos } 825a0698ed9Schristos 826a0698ed9Schristos TEST_BEGIN(test_json_parser) { 827a0698ed9Schristos size_t i; 828a0698ed9Schristos const char *invalid_inputs[] = { 829a0698ed9Schristos /* Tokenizer error case tests. */ 830a0698ed9Schristos "{ \"string\": X }", 831a0698ed9Schristos "{ \"string\": nXll }", 832a0698ed9Schristos "{ \"string\": nuXl }", 833a0698ed9Schristos "{ \"string\": nulX }", 834a0698ed9Schristos "{ \"string\": nullX }", 835a0698ed9Schristos "{ \"string\": fXlse }", 836a0698ed9Schristos "{ \"string\": faXse }", 837a0698ed9Schristos "{ \"string\": falXe }", 838a0698ed9Schristos "{ \"string\": falsX }", 839a0698ed9Schristos "{ \"string\": falseX }", 840a0698ed9Schristos "{ \"string\": tXue }", 841a0698ed9Schristos "{ \"string\": trXe }", 842a0698ed9Schristos "{ \"string\": truX }", 843a0698ed9Schristos "{ \"string\": trueX }", 844a0698ed9Schristos "{ \"string\": \"\n\" }", 845a0698ed9Schristos "{ \"string\": \"\\z\" }", 846a0698ed9Schristos "{ \"string\": \"\\uX000\" }", 847a0698ed9Schristos "{ \"string\": \"\\u0X00\" }", 848a0698ed9Schristos "{ \"string\": \"\\u00X0\" }", 849a0698ed9Schristos "{ \"string\": \"\\u000X\" }", 850a0698ed9Schristos "{ \"string\": -X }", 851a0698ed9Schristos "{ \"string\": 0.X }", 852a0698ed9Schristos "{ \"string\": 0.0eX }", 853a0698ed9Schristos "{ \"string\": 0.0e+X }", 854a0698ed9Schristos 855a0698ed9Schristos /* Parser error test cases. */ 856a0698ed9Schristos "{\"string\": }", 857a0698ed9Schristos "{\"string\" }", 858a0698ed9Schristos "{\"string\": [ 0 }", 859a0698ed9Schristos "{\"string\": {\"a\":0, 1 } }", 860a0698ed9Schristos "{\"string\": {\"a\":0: } }", 861a0698ed9Schristos "{", 862a0698ed9Schristos "{}{", 863a0698ed9Schristos }; 864a0698ed9Schristos const char *valid_inputs[] = { 865a0698ed9Schristos /* Token tests. */ 866a0698ed9Schristos "null", 867a0698ed9Schristos "false", 868a0698ed9Schristos "true", 869a0698ed9Schristos "{}", 870a0698ed9Schristos "{\"a\": 0}", 871a0698ed9Schristos "[]", 872a0698ed9Schristos "[0, 1]", 873a0698ed9Schristos "0", 874a0698ed9Schristos "1", 875a0698ed9Schristos "10", 876a0698ed9Schristos "-10", 877a0698ed9Schristos "10.23", 878a0698ed9Schristos "10.23e4", 879a0698ed9Schristos "10.23e-4", 880a0698ed9Schristos "10.23e+4", 881a0698ed9Schristos "10.23E4", 882a0698ed9Schristos "10.23E-4", 883a0698ed9Schristos "10.23E+4", 884a0698ed9Schristos "-10.23", 885a0698ed9Schristos "-10.23e4", 886a0698ed9Schristos "-10.23e-4", 887a0698ed9Schristos "-10.23e+4", 888a0698ed9Schristos "-10.23E4", 889a0698ed9Schristos "-10.23E-4", 890a0698ed9Schristos "-10.23E+4", 891a0698ed9Schristos "\"value\"", 892a0698ed9Schristos "\" \\\" \\/ \\b \\n \\r \\t \\u0abc \\u1DEF \"", 893a0698ed9Schristos 894a0698ed9Schristos /* Parser test with various nesting. */ 895a0698ed9Schristos "{\"a\":null, \"b\":[1,[{\"c\":2},3]], \"d\":{\"e\":true}}", 896a0698ed9Schristos }; 897a0698ed9Schristos 898a0698ed9Schristos for (i = 0; i < sizeof(invalid_inputs)/sizeof(const char *); i++) { 899a0698ed9Schristos const char *input = invalid_inputs[i]; 900a0698ed9Schristos parser_t parser; 901a0698ed9Schristos parser_init(&parser, false); 902*7bdf38e5Schristos expect_false(parser_append(&parser, input), 903a0698ed9Schristos "Unexpected input appending failure"); 904*7bdf38e5Schristos expect_true(parser_parse(&parser), 905a0698ed9Schristos "Unexpected parse success for input: %s", input); 906a0698ed9Schristos parser_fini(&parser); 907a0698ed9Schristos } 908a0698ed9Schristos 909a0698ed9Schristos for (i = 0; i < sizeof(valid_inputs)/sizeof(const char *); i++) { 910a0698ed9Schristos const char *input = valid_inputs[i]; 911a0698ed9Schristos parser_t parser; 912a0698ed9Schristos parser_init(&parser, true); 913*7bdf38e5Schristos expect_false(parser_append(&parser, input), 914a0698ed9Schristos "Unexpected input appending failure"); 915*7bdf38e5Schristos expect_false(parser_parse(&parser), 916a0698ed9Schristos "Unexpected parse error for input: %s", input); 917a0698ed9Schristos parser_fini(&parser); 918a0698ed9Schristos } 919a0698ed9Schristos } 920a0698ed9Schristos TEST_END 921a0698ed9Schristos 922a0698ed9Schristos void 923a0698ed9Schristos write_cb(void *opaque, const char *str) { 924a0698ed9Schristos parser_t *parser = (parser_t *)opaque; 925a0698ed9Schristos if (parser_append(parser, str)) { 926a0698ed9Schristos test_fail("Unexpected input appending failure"); 927a0698ed9Schristos } 928a0698ed9Schristos } 929a0698ed9Schristos 930a0698ed9Schristos TEST_BEGIN(test_stats_print_json) { 931a0698ed9Schristos const char *opts[] = { 932a0698ed9Schristos "J", 933a0698ed9Schristos "Jg", 934a0698ed9Schristos "Jm", 935a0698ed9Schristos "Jd", 936a0698ed9Schristos "Jmd", 937a0698ed9Schristos "Jgd", 938a0698ed9Schristos "Jgm", 939a0698ed9Schristos "Jgmd", 940a0698ed9Schristos "Ja", 941a0698ed9Schristos "Jb", 942a0698ed9Schristos "Jl", 943a0698ed9Schristos "Jx", 944a0698ed9Schristos "Jbl", 945a0698ed9Schristos "Jal", 946a0698ed9Schristos "Jab", 947a0698ed9Schristos "Jabl", 948a0698ed9Schristos "Jax", 949a0698ed9Schristos "Jbx", 950a0698ed9Schristos "Jlx", 951a0698ed9Schristos "Jablx", 952a0698ed9Schristos "Jgmdablx", 953a0698ed9Schristos }; 954a0698ed9Schristos unsigned arena_ind, i; 955a0698ed9Schristos 956a0698ed9Schristos for (i = 0; i < 3; i++) { 957a0698ed9Schristos unsigned j; 958a0698ed9Schristos 959a0698ed9Schristos switch (i) { 960a0698ed9Schristos case 0: 961a0698ed9Schristos break; 962a0698ed9Schristos case 1: { 963a0698ed9Schristos size_t sz = sizeof(arena_ind); 964*7bdf38e5Schristos expect_d_eq(mallctl("arenas.create", (void *)&arena_ind, 965a0698ed9Schristos &sz, NULL, 0), 0, "Unexpected mallctl failure"); 966a0698ed9Schristos break; 967a0698ed9Schristos } case 2: { 968a0698ed9Schristos size_t mib[3]; 969a0698ed9Schristos size_t miblen = sizeof(mib)/sizeof(size_t); 970*7bdf38e5Schristos expect_d_eq(mallctlnametomib("arena.0.destroy", 971a0698ed9Schristos mib, &miblen), 0, 972a0698ed9Schristos "Unexpected mallctlnametomib failure"); 973a0698ed9Schristos mib[1] = arena_ind; 974*7bdf38e5Schristos expect_d_eq(mallctlbymib(mib, miblen, NULL, NULL, NULL, 975a0698ed9Schristos 0), 0, "Unexpected mallctlbymib failure"); 976a0698ed9Schristos break; 977a0698ed9Schristos } default: 978a0698ed9Schristos not_reached(); 979a0698ed9Schristos } 980a0698ed9Schristos 981a0698ed9Schristos for (j = 0; j < sizeof(opts)/sizeof(const char *); j++) { 982a0698ed9Schristos parser_t parser; 983a0698ed9Schristos 984a0698ed9Schristos parser_init(&parser, true); 985a0698ed9Schristos malloc_stats_print(write_cb, (void *)&parser, opts[j]); 986*7bdf38e5Schristos expect_false(parser_parse(&parser), 987a0698ed9Schristos "Unexpected parse error, opts=\"%s\"", opts[j]); 988a0698ed9Schristos parser_fini(&parser); 989a0698ed9Schristos } 990a0698ed9Schristos } 991a0698ed9Schristos } 992a0698ed9Schristos TEST_END 993a0698ed9Schristos 994a0698ed9Schristos int 995a0698ed9Schristos main(void) { 996a0698ed9Schristos return test( 997a0698ed9Schristos test_json_parser, 998a0698ed9Schristos test_stats_print_json); 999a0698ed9Schristos } 1000