| | 2347 | /* |
|---|
| | 2348 | * Eat whitespaces and comments until the next token is found. |
|---|
| | 2349 | */ |
|---|
| | 2350 | |
|---|
| | 2351 | static int |
|---|
| | 2352 | yaml_parser_scan_to_next_token(yaml_parser_t *parser) |
|---|
| | 2353 | { |
|---|
| | 2354 | /* Until the next token is not found. */ |
|---|
| | 2355 | |
|---|
| | 2356 | while (1) |
|---|
| | 2357 | { |
|---|
| | 2358 | /* Allow the BOM mark to start a line. */ |
|---|
| | 2359 | |
|---|
| | 2360 | if (!UPDATE(parser, 1)) return 0; |
|---|
| | 2361 | |
|---|
| | 2362 | if (parser->column == 0 && IS_BOM(parser)) |
|---|
| | 2363 | FORWARD(parser); |
|---|
| | 2364 | |
|---|
| | 2365 | /* |
|---|
| | 2366 | * Eat whitespaces. |
|---|
| | 2367 | * |
|---|
| | 2368 | * Tabs are allowed: |
|---|
| | 2369 | * |
|---|
| | 2370 | * - in the flow context; |
|---|
| | 2371 | * - in the block context, but not at the beginning of the line or |
|---|
| | 2372 | * after '-', '?', or ':' (complex value). |
|---|
| | 2373 | */ |
|---|
| | 2374 | |
|---|
| | 2375 | if (!UPDATE(parser, 1)) return 0; |
|---|
| | 2376 | |
|---|
| | 2377 | while (CHECK(parser,' ') || |
|---|
| | 2378 | ((parser->flow_level || !parser->simple_key_allowed) && |
|---|
| | 2379 | CHECK(parser, '\t'))) { |
|---|
| | 2380 | FORWARD(parser); |
|---|
| | 2381 | if (!UPDATE(parser, 1)) return 0; |
|---|
| | 2382 | } |
|---|
| | 2383 | |
|---|
| | 2384 | /* Eat a comment until a line break. */ |
|---|
| | 2385 | |
|---|
| | 2386 | if (CHECK(parser, '#')) { |
|---|
| | 2387 | while (!IS_BREAKZ(parser)) { |
|---|
| | 2388 | FORWARD(parser); |
|---|
| | 2389 | if (!UPDATE(parser, 1)) return 0; |
|---|
| | 2390 | } |
|---|
| | 2391 | } |
|---|
| | 2392 | |
|---|
| | 2393 | /* If it is a line break, eat it. */ |
|---|
| | 2394 | |
|---|
| | 2395 | if (IS_BREAK(parser)) |
|---|
| | 2396 | { |
|---|
| | 2397 | if (!UPDATE(parser, 2)) return 0; |
|---|
| | 2398 | FORWARD_LINE(parser); |
|---|
| | 2399 | |
|---|
| | 2400 | /* In the block context, a new line may start a simple key. */ |
|---|
| | 2401 | |
|---|
| | 2402 | if (!parser->flow_level) { |
|---|
| | 2403 | parser->simple_key_allowed = 1; |
|---|
| | 2404 | } |
|---|
| | 2405 | } |
|---|
| | 2406 | else |
|---|
| | 2407 | { |
|---|
| | 2408 | /* We have found a token. */ |
|---|
| | 2409 | |
|---|
| | 2410 | break; |
|---|
| | 2411 | } |
|---|
| | 2412 | } |
|---|
| | 2413 | |
|---|
| | 2414 | return 1; |
|---|
| | 2415 | } |
|---|
| | 2416 | |
|---|
| | 2417 | /* |
|---|
| | 2418 | * Scan a YAML-DIRECTIVE or TAG-DIRECTIVE token. |
|---|
| | 2419 | * |
|---|
| | 2420 | * Scope: |
|---|
| | 2421 | * %YAML 1.1 # a comment \n |
|---|
| | 2422 | * ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ |
|---|
| | 2423 | * %TAG !yaml! tag:yaml.org,2002: \n |
|---|
| | 2424 | * ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ |
|---|
| | 2425 | */ |
|---|
| | 2426 | |
|---|
| | 2427 | static yaml_token_t * |
|---|
| | 2428 | yaml_parser_scan_directive(yaml_parser_t *parser) |
|---|
| | 2429 | { |
|---|
| | 2430 | yaml_mark_t start_mark, end_mark; |
|---|
| | 2431 | yaml_char_t *name = NULL; |
|---|
| | 2432 | int major, minor; |
|---|
| | 2433 | yaml_char_t *handle = NULL, *prefix = NULL; |
|---|
| | 2434 | yaml_token_t *token = NULL; |
|---|
| | 2435 | |
|---|
| | 2436 | /* Eat '%'. */ |
|---|
| | 2437 | |
|---|
| | 2438 | start_mark = yaml_parser_get_mark(parser); |
|---|
| | 2439 | |
|---|
| | 2440 | FORWARD(parser); |
|---|
| | 2441 | |
|---|
| | 2442 | /* Scan the directive name. */ |
|---|
| | 2443 | |
|---|
| | 2444 | if (!yaml_parser_scan_directive_name(parser, start_mark, &name)) |
|---|
| | 2445 | goto error; |
|---|
| | 2446 | |
|---|
| | 2447 | /* Is it a YAML directive? */ |
|---|
| | 2448 | |
|---|
| | 2449 | if (strcmp((char *)name, "YAML") == 0) |
|---|
| | 2450 | { |
|---|
| | 2451 | /* Scan the VERSION directive value. */ |
|---|
| | 2452 | |
|---|
| | 2453 | if (!yaml_parser_scan_version_directive_value(parser, start_mark, |
|---|
| | 2454 | &major, &minor)) |
|---|
| | 2455 | goto error; |
|---|
| | 2456 | |
|---|
| | 2457 | end_mark = yaml_parser_get_mark(parser); |
|---|
| | 2458 | |
|---|
| | 2459 | /* Create a VERSION-DIRECTIVE token. */ |
|---|
| | 2460 | |
|---|
| | 2461 | token = yaml_version_directive_token_new(major, minor, |
|---|
| | 2462 | start_mark, end_mark); |
|---|
| | 2463 | if (!token) goto error; |
|---|
| | 2464 | } |
|---|
| | 2465 | |
|---|
| | 2466 | /* Is it a TAG directive? */ |
|---|
| | 2467 | |
|---|
| | 2468 | else if (strcmp((char *)name, "TAG") == 0) |
|---|
| | 2469 | { |
|---|
| | 2470 | /* Scan the TAG directive value. */ |
|---|
| | 2471 | |
|---|
| | 2472 | if (!yaml_parser_scan_tag_directive_value(parser, start_mark, |
|---|
| | 2473 | &handle, &prefix)) |
|---|
| | 2474 | goto error; |
|---|
| | 2475 | |
|---|
| | 2476 | end_mark = yaml_parser_get_mark(parser); |
|---|
| | 2477 | |
|---|
| | 2478 | /* Create a TAG-DIRECTIVE token. */ |
|---|
| | 2479 | |
|---|
| | 2480 | token = yaml_tag_directive_token_new(handle, prefix, |
|---|
| | 2481 | start_mark, end_mark); |
|---|
| | 2482 | if (!token) goto error; |
|---|
| | 2483 | } |
|---|
| | 2484 | |
|---|
| | 2485 | /* Unknown directive. */ |
|---|
| | 2486 | |
|---|
| | 2487 | else |
|---|
| | 2488 | { |
|---|
| | 2489 | yaml_parser_set_scanner_error(parser, "While scanning a directive", |
|---|
| | 2490 | start_mark, "found uknown directive name"); |
|---|
| | 2491 | goto error; |
|---|
| | 2492 | } |
|---|
| | 2493 | |
|---|
| | 2494 | /* Eat the rest of the line including any comments. */ |
|---|
| | 2495 | |
|---|
| | 2496 | while (IS_BLANK(parser)) { |
|---|
| | 2497 | FORWARD(parser); |
|---|
| | 2498 | if (!UPDATE(parser, 1)) goto error; |
|---|
| | 2499 | } |
|---|
| | 2500 | |
|---|
| | 2501 | if (CHECK(parser, '#')) { |
|---|
| | 2502 | while (!IS_BREAKZ(parser)) { |
|---|
| | 2503 | FORWARD(parser); |
|---|
| | 2504 | if (!UPDATE(parser, 1)) goto error; |
|---|
| | 2505 | } |
|---|
| | 2506 | } |
|---|
| | 2507 | |
|---|
| | 2508 | /* Check if we are at the end of the line. */ |
|---|
| | 2509 | |
|---|
| | 2510 | if (!IS_BREAKZ(parser)) { |
|---|
| | 2511 | yaml_parser_set_scanner_error(parser, "While scanning a directive", |
|---|
| | 2512 | start_mark, "did not found expected comment or line break"); |
|---|
| | 2513 | goto error; |
|---|
| | 2514 | } |
|---|
| | 2515 | |
|---|
| | 2516 | /* Eat a line break. */ |
|---|
| | 2517 | |
|---|
| | 2518 | if (IS_BREAK(parser)) { |
|---|
| | 2519 | if (!UPDATE(parser, 2)) goto error; |
|---|
| | 2520 | FORWARD_LINE(parser); |
|---|
| | 2521 | } |
|---|
| | 2522 | |
|---|
| | 2523 | yaml_free(name); |
|---|
| | 2524 | |
|---|
| | 2525 | return token; |
|---|
| | 2526 | |
|---|
| | 2527 | error: |
|---|
| | 2528 | yaml_free(token); |
|---|
| | 2529 | yaml_free(prefix); |
|---|
| | 2530 | yaml_free(handle); |
|---|
| | 2531 | yaml_free(name); |
|---|
| | 2532 | return NULL; |
|---|
| | 2533 | } |
|---|
| | 2534 | |
|---|
| | 2535 | /* |
|---|
| | 2536 | * Scan the directive name. |
|---|
| | 2537 | * |
|---|
| | 2538 | * Scope: |
|---|
| | 2539 | * %YAML 1.1 # a comment \n |
|---|
| | 2540 | * ^^^^ |
|---|
| | 2541 | * %TAG !yaml! tag:yaml.org,2002: \n |
|---|
| | 2542 | * ^^^ |
|---|
| | 2543 | */ |
|---|
| | 2544 | |
|---|
| | 2545 | static int |
|---|
| | 2546 | yaml_parser_scan_directive_name(yaml_parser_t *parser, |
|---|
| | 2547 | yaml_mark_t start_mark, yaml_char_t **name) |
|---|
| | 2548 | { |
|---|
| | 2549 | yaml_string_t string = yaml_parser_new_string(parser); |
|---|
| | 2550 | |
|---|
| | 2551 | if (!string.buffer) goto error; |
|---|
| | 2552 | |
|---|
| | 2553 | /* Consume the directive name. */ |
|---|
| | 2554 | |
|---|
| | 2555 | if (!UPDATE(parser, 1)) goto error; |
|---|
| | 2556 | |
|---|
| | 2557 | while (IS_ALPHA(parser)) |
|---|
| | 2558 | { |
|---|
| | 2559 | if (!RESIZE(parser, string)) goto error; |
|---|
| | 2560 | COPY(parser, string); |
|---|
| | 2561 | if (!UPDATE(parser, 1)) goto error; |
|---|
| | 2562 | } |
|---|
| | 2563 | |
|---|
| | 2564 | /* Check if the name is empty. */ |
|---|
| | 2565 | |
|---|
| | 2566 | if (string.buffer == string.pointer) { |
|---|
| | 2567 | yaml_parser_set_scanner_error(parser, "while scanning a directive", |
|---|
| | 2568 | start_mark, "cannot found expected directive name"); |
|---|
| | 2569 | goto error; |
|---|
| | 2570 | } |
|---|
| | 2571 | |
|---|
| | 2572 | /* Check for an blank character after the name. */ |
|---|
| | 2573 | |
|---|
| | 2574 | if (!IS_BLANKZ(parser)) { |
|---|
| | 2575 | yaml_parser_set_scanner_error(parser, "while scanning a directive", |
|---|
| | 2576 | start_mark, "found unexpected non-alphabetical character"); |
|---|
| | 2577 | goto error; |
|---|
| | 2578 | } |
|---|
| | 2579 | |
|---|
| | 2580 | *name = string.buffer; |
|---|
| | 2581 | |
|---|
| | 2582 | return 1; |
|---|
| | 2583 | |
|---|
| | 2584 | error: |
|---|
| | 2585 | yaml_free(string.buffer); |
|---|
| | 2586 | return 0; |
|---|
| | 2587 | } |
|---|
| | 2588 | |
|---|
| | 2589 | /* |
|---|
| | 2590 | * Scan the value of VERSION-DIRECTIVE. |
|---|
| | 2591 | * |
|---|
| | 2592 | * Scope: |
|---|
| | 2593 | * %YAML 1.1 # a comment \n |
|---|
| | 2594 | * ^^^^^^ |
|---|
| | 2595 | */ |
|---|
| | 2596 | |
|---|
| | 2597 | static int |
|---|
| | 2598 | yaml_parser_scan_version_directive_value(yaml_parser_t *parser, |
|---|
| | 2599 | yaml_mark_t start_mark, int *major, int *minor) |
|---|
| | 2600 | { |
|---|
| | 2601 | /* Eat whitespaces. */ |
|---|
| | 2602 | |
|---|
| | 2603 | if (!UPDATE(parser, 1)) return 0; |
|---|
| | 2604 | |
|---|
| | 2605 | while (IS_BLANK(parser)) { |
|---|
| | 2606 | FORWARD(parser); |
|---|
| | 2607 | if (!UPDATE(parser, 1)) return 0; |
|---|
| | 2608 | } |
|---|
| | 2609 | |
|---|
| | 2610 | /* Consume the major version number. */ |
|---|
| | 2611 | |
|---|
| | 2612 | if (!yaml_parser_scan_version_directive_number(parser, start_mark, major)) |
|---|
| | 2613 | return 0; |
|---|
| | 2614 | |
|---|
| | 2615 | /* Eat '.'. */ |
|---|
| | 2616 | |
|---|
| | 2617 | if (!CHECK(parser, '.')) { |
|---|
| | 2618 | return yaml_parser_set_scanner_error(parser, "while scanning a %YAML directive", |
|---|
| | 2619 | start_mark, "did not find expected digit or '.' character"); |
|---|
| | 2620 | } |
|---|
| | 2621 | |
|---|
| | 2622 | FORWARD(parser); |
|---|
| | 2623 | |
|---|
| | 2624 | /* Consume the minor version number. */ |
|---|
| | 2625 | |
|---|
| | 2626 | if (!yaml_parser_scan_version_directive_number(parser, start_mark, minor)) |
|---|
| | 2627 | return 0; |
|---|
| | 2628 | } |
|---|
| | 2629 | |
|---|
| | 2630 | #define MAX_NUMBER_LENGTH 9 |
|---|
| | 2631 | |
|---|
| | 2632 | /* |
|---|
| | 2633 | * Scan the version number of VERSION-DIRECTIVE. |
|---|
| | 2634 | * |
|---|
| | 2635 | * Scope: |
|---|
| | 2636 | * %YAML 1.1 # a comment \n |
|---|
| | 2637 | * ^ |
|---|
| | 2638 | * %YAML 1.1 # a comment \n |
|---|
| | 2639 | * ^ |
|---|
| | 2640 | */ |
|---|
| | 2641 | |
|---|
| | 2642 | static int |
|---|
| | 2643 | yaml_parser_scan_version_directive_number(yaml_parser_t *parser, |
|---|
| | 2644 | yaml_mark_t start_mark, int *number) |
|---|
| | 2645 | { |
|---|
| | 2646 | int value = 0; |
|---|
| | 2647 | size_t length = 0; |
|---|
| | 2648 | |
|---|
| | 2649 | /* Repeat while the next character is digit. */ |
|---|
| | 2650 | |
|---|
| | 2651 | if (!UPDATE(parser, 1)) return 0; |
|---|
| | 2652 | |
|---|
| | 2653 | while (IS_DIGIT(parser)) |
|---|
| | 2654 | { |
|---|
| | 2655 | /* Check if the number is too long. */ |
|---|
| | 2656 | |
|---|
| | 2657 | if (++length > MAX_NUMBER_LENGTH) { |
|---|
| | 2658 | return yaml_parser_set_scanner_error(parser, "while scanning a %YAML directive", |
|---|
| | 2659 | start_mark, "found extremely long version number"); |
|---|
| | 2660 | } |
|---|
| | 2661 | |
|---|
| | 2662 | value = value*10 + AS_DIGIT(parser); |
|---|
| | 2663 | |
|---|
| | 2664 | FORWARD(parser); |
|---|
| | 2665 | |
|---|
| | 2666 | if (!UPDATE(parser, 1)) return 0; |
|---|
| | 2667 | } |
|---|
| | 2668 | |
|---|
| | 2669 | /* Check if the number was present. */ |
|---|
| | 2670 | |
|---|
| | 2671 | if (!length) { |
|---|
| | 2672 | return yaml_parser_set_scanner_error(parser, "while scanning a %YAML directive", |
|---|
| | 2673 | start_mark, "did not find expected version number"); |
|---|
| | 2674 | } |
|---|
| | 2675 | |
|---|
| | 2676 | *number = value; |
|---|
| | 2677 | |
|---|
| | 2678 | return 1; |
|---|
| | 2679 | } |
|---|
| | 2680 | |
|---|
| | 2681 | /* |
|---|
| | 2682 | * Scan the value of a TAG-DIRECTIVE token. |
|---|
| | 2683 | * |
|---|
| | 2684 | * Scope: |
|---|
| | 2685 | * %TAG !yaml! tag:yaml.org,2002: \n |
|---|
| | 2686 | * ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ |
|---|
| | 2687 | */ |
|---|
| | 2688 | |
|---|
| | 2689 | static int |
|---|
| | 2690 | yaml_parser_scan_tag_directive_value(yaml_parser_t *parser, |
|---|
| | 2691 | yaml_mark_t start_mark, yaml_char_t **handle, yaml_char_t **prefix) |
|---|
| | 2692 | { |
|---|
| | 2693 | yaml_char_t *handle_value = NULL; |
|---|
| | 2694 | yaml_char_t *prefix_value = NULL; |
|---|
| | 2695 | |
|---|
| | 2696 | /* Eat whitespaces. */ |
|---|
| | 2697 | |
|---|
| | 2698 | if (!UPDATE(parser, 1)) goto error; |
|---|
| | 2699 | |
|---|
| | 2700 | while (IS_BLANK(parser)) { |
|---|
| | 2701 | FORWARD(parser); |
|---|
| | 2702 | if (!UPDATE(parser, 1)) goto error; |
|---|
| | 2703 | } |
|---|
| | 2704 | |
|---|
| | 2705 | /* Scan a handle. */ |
|---|
| | 2706 | |
|---|
| | 2707 | if (!yaml_parser_scan_tag_handle(parser, 1, start_mark, &handle_value)) |
|---|
| | 2708 | goto error; |
|---|
| | 2709 | |
|---|
| | 2710 | /* Expect a whitespace. */ |
|---|
| | 2711 | |
|---|
| | 2712 | if (!UPDATE(parser, 1)) goto error; |
|---|
| | 2713 | |
|---|
| | 2714 | if (!IS_BLANK(parser)) { |
|---|
| | 2715 | yaml_parser_set_scanner_error(parser, "while scanning a %TAG directive", |
|---|
| | 2716 | start_mark, "did not find expected whitespace"); |
|---|
| | 2717 | goto error; |
|---|
| | 2718 | } |
|---|
| | 2719 | |
|---|
| | 2720 | /* Eat whitespaces. */ |
|---|
| | 2721 | |
|---|
| | 2722 | while (IS_BLANK(parser)) { |
|---|
| | 2723 | FORWARD(parser); |
|---|
| | 2724 | if (!UPDATE(parser, 1)) goto error; |
|---|
| | 2725 | } |
|---|
| | 2726 | |
|---|
| | 2727 | /* Scan a prefix. */ |
|---|
| | 2728 | |
|---|
| | 2729 | if (!yaml_parser_scan_tag_uri(parser, 1, NULL, start_mark, &prefix_value)) |
|---|
| | 2730 | goto error; |
|---|
| | 2731 | |
|---|
| | 2732 | /* Expect a whitespace or line break. */ |
|---|
| | 2733 | |
|---|
| | 2734 | if (!UPDATE(parser, 1)) goto error; |
|---|
| | 2735 | |
|---|
| | 2736 | if (!IS_BLANKZ(parser)) { |
|---|
| | 2737 | yaml_parser_set_scanner_error(parser, "while scanning a %TAG directive", |
|---|
| | 2738 | start_mark, "did not find expected whitespace or line break"); |
|---|
| | 2739 | goto error; |
|---|
| | 2740 | } |
|---|
| | 2741 | |
|---|
| | 2742 | *handle = handle_value; |
|---|
| | 2743 | *prefix = prefix_value; |
|---|
| | 2744 | |
|---|
| | 2745 | return 1; |
|---|
| | 2746 | |
|---|
| | 2747 | error: |
|---|
| | 2748 | yaml_free(handle_value); |
|---|
| | 2749 | yaml_free(prefix_value); |
|---|
| | 2750 | return 0; |
|---|
| | 2751 | } |
|---|
| | 2752 | |
|---|
| | 2753 | static yaml_token_t * |
|---|
| | 2754 | yaml_parser_scan_anchor(yaml_parser_t *parser, |
|---|
| | 2755 | yaml_token_type_t type) |
|---|
| | 2756 | { |
|---|
| | 2757 | int length = 0; |
|---|
| | 2758 | yaml_mark_t start_mark, end_mark; |
|---|
| | 2759 | yaml_token_t *token = NULL; |
|---|
| | 2760 | yaml_string_t string = yaml_parser_new_string(parser); |
|---|
| | 2761 | |
|---|
| | 2762 | if (!string.buffer) goto error; |
|---|
| | 2763 | |
|---|
| | 2764 | /* Eat the indicator character. */ |
|---|
| | 2765 | |
|---|
| | 2766 | start_mark = yaml_parser_get_mark(parser); |
|---|
| | 2767 | |
|---|
| | 2768 | FORWARD(parser); |
|---|
| | 2769 | |
|---|
| | 2770 | /* Consume the value. */ |
|---|
| | 2771 | |
|---|
| | 2772 | if (!UPDATE(parser, 1)) goto error; |
|---|
| | 2773 | |
|---|
| | 2774 | while (IS_ALPHA(parser)) { |
|---|
| | 2775 | if (!RESIZE(parser, string)) goto error; |
|---|
| | 2776 | COPY(parser, string); |
|---|
| | 2777 | if (!UPDATE(parser, 1)) goto error; |
|---|
| | 2778 | length ++; |
|---|
| | 2779 | } |
|---|
| | 2780 | |
|---|
| | 2781 | end_mark = yaml_parser_get_mark(parser); |
|---|
| | 2782 | |
|---|
| | 2783 | /* |
|---|
| | 2784 | * Check if length of the anchor is greater than 0 and it is followed by |
|---|
| | 2785 | * a whitespace character or one of the indicators: |
|---|
| | 2786 | * |
|---|
| | 2787 | * '?', ':', ',', ']', '}', '%', '@', '`'. |
|---|
| | 2788 | */ |
|---|
| | 2789 | |
|---|
| | 2790 | if (!length || !(IS_BLANKZ(parser) || CHECK(parser, '?') || CHECK(parser, ':') || |
|---|
| | 2791 | CHECK(parser, ',') || CHECK(parser, ']') || CHECK(parser, '}') || |
|---|
| | 2792 | CHECK(parser, '%') || CHECK(parser, '@') || CHECK(parser, '`'))) { |
|---|
| | 2793 | yaml_parser_set_scanner_error(parser, type == YAML_ANCHOR_TOKEN ? |
|---|
| | 2794 | "while scanning an anchor" : "while scanning an alias", start_mark, |
|---|
| | 2795 | "did not find expected alphabetic or numeric character"); |
|---|
| | 2796 | goto error; |
|---|
| | 2797 | } |
|---|
| | 2798 | |
|---|
| | 2799 | /* Create a token. */ |
|---|
| | 2800 | |
|---|
| | 2801 | token = type == YAML_ANCHOR_TOKEN ? |
|---|
| | 2802 | yaml_anchor_token_new(string.buffer, start_mark, end_mark) : |
|---|
| | 2803 | yaml_alias_token_new(string.buffer, start_mark, end_mark); |
|---|
| | 2804 | if (!token) goto error; |
|---|
| | 2805 | |
|---|
| | 2806 | return token; |
|---|
| | 2807 | |
|---|
| | 2808 | error: |
|---|
| | 2809 | yaml_free(string.buffer); |
|---|
| | 2810 | yaml_free(token); |
|---|
| | 2811 | return 0; |
|---|
| | 2812 | } |
|---|
| | 2813 | |
|---|
| | 2814 | /* |
|---|
| | 2815 | * Scan a TAG token. |
|---|
| | 2816 | */ |
|---|
| | 2817 | |
|---|
| | 2818 | static yaml_token_t * |
|---|
| | 2819 | yaml_parser_scan_tag(yaml_parser_t *parser) |
|---|
| | 2820 | { |
|---|
| | 2821 | yaml_char_t *handle = NULL; |
|---|
| | 2822 | yaml_char_t *suffix = NULL; |
|---|
| | 2823 | yaml_token_t *token = NULL; |
|---|
| | 2824 | yaml_mark_t start_mark, end_mark; |
|---|
| | 2825 | |
|---|
| | 2826 | start_mark = yaml_parser_get_mark(parser); |
|---|
| | 2827 | |
|---|
| | 2828 | /* Check if the tag is in the canonical form. */ |
|---|
| | 2829 | |
|---|
| | 2830 | if (!UPDATE(parser, 2)) goto error; |
|---|
| | 2831 | |
|---|
| | 2832 | if (CHECK_AT(parser, '<', 1)) |
|---|
| | 2833 | { |
|---|
| | 2834 | /* Set the handle to '' */ |
|---|
| | 2835 | |
|---|
| | 2836 | handle = yaml_malloc(1); |
|---|
| | 2837 | if (!handle) goto error; |
|---|
| | 2838 | handle[0] = '\0'; |
|---|
| | 2839 | |
|---|
| | 2840 | /* Eat '!<' */ |
|---|
| | 2841 | |
|---|
| | 2842 | FORWARD(parser); |
|---|
| | 2843 | FORWARD(parser); |
|---|
| | 2844 | |
|---|
| | 2845 | /* Consume the tag value. */ |
|---|
| | 2846 | |
|---|
| | 2847 | if (!yaml_parser_scan_tag_uri(parser, 0, NULL, start_mark, &suffix)) |
|---|
| | 2848 | goto error; |
|---|
| | 2849 | |
|---|
| | 2850 | /* Check for '>' and eat it. */ |
|---|
| | 2851 | |
|---|
| | 2852 | if (!CHECK(parser, '>')) { |
|---|
| | 2853 | yaml_parser_set_scanner_error(parser, "while scanning a tag", |
|---|
| | 2854 | start_mark, "did not find the expected '>'"); |
|---|
| | 2855 | goto error; |
|---|
| | 2856 | } |
|---|
| | 2857 | |
|---|
| | 2858 | FORWARD(parser); |
|---|
| | 2859 | } |
|---|
| | 2860 | else |
|---|
| | 2861 | { |
|---|
| | 2862 | /* The tag has either the '!suffix' or the '!handle!suffix' form. */ |
|---|
| | 2863 | |
|---|
| | 2864 | /* First, try to scan a handle. */ |
|---|
| | 2865 | |
|---|
| | 2866 | if (!yaml_parser_scan_tag_handle(parser, 0, start_mark, &handle)) |
|---|
| | 2867 | goto error; |
|---|
| | 2868 | |
|---|
| | 2869 | /* Check if it is, indeed, handle. */ |
|---|
| | 2870 | |
|---|
| | 2871 | if (handle[0] == '!' && handle[1] != '\0' && handle[strlen((char *)handle)-1] == '!') |
|---|
| | 2872 | { |
|---|
| | 2873 | /* Scan the suffix now. */ |
|---|
| | 2874 | |
|---|
| | 2875 | if (!yaml_parser_scan_tag_uri(parser, 0, NULL, start_mark, &suffix)) |
|---|
| | 2876 | goto error; |
|---|
| | 2877 | } |
|---|
| | 2878 | else |
|---|
| | 2879 | { |
|---|
| | 2880 | /* It wasn't a handle after all. Scan the rest of the tag. */ |
|---|
| | 2881 | |
|---|
| | 2882 | if (!yaml_parser_scan_tag_uri(parser, 0, handle, start_mark, &suffix)) |
|---|
| | 2883 | goto error; |
|---|
| | 2884 | |
|---|
| | 2885 | /* Set the handle to '!'. */ |
|---|
| | 2886 | |
|---|
| | 2887 | yaml_free(handle); |
|---|
| | 2888 | handle = yaml_malloc(2); |
|---|
| | 2889 | if (!handle) goto error; |
|---|
| | 2890 | handle[0] = '!'; |
|---|
| | 2891 | handle[1] = '\0'; |
|---|
| | 2892 | } |
|---|
| | 2893 | } |
|---|
| | 2894 | |
|---|
| | 2895 | /* Check the character which ends the tag. */ |
|---|
| | 2896 | |
|---|
| | 2897 | if (!UPDATE(parser, 1)) goto error; |
|---|
| | 2898 | |
|---|
| | 2899 | if (!IS_BLANKZ(parser)) { |
|---|
| | 2900 | yaml_parser_set_scanner_error(parser, "while scanning a tag", |
|---|
| | 2901 | start_mark, "did not found expected whitespace or line break"); |
|---|
| | 2902 | goto error; |
|---|
| | 2903 | } |
|---|
| | 2904 | |
|---|
| | 2905 | end_mark = yaml_parser_get_mark(parser); |
|---|
| | 2906 | |
|---|
| | 2907 | /* Create a token. */ |
|---|
| | 2908 | |
|---|
| | 2909 | token = yaml_tag_token_new(handle, suffix, start_mark, end_mark); |
|---|
| | 2910 | if (!token) goto error; |
|---|
| | 2911 | |
|---|
| | 2912 | return token; |
|---|
| | 2913 | |
|---|
| | 2914 | error: |
|---|
| | 2915 | yaml_free(handle); |
|---|
| | 2916 | yaml_free(suffix); |
|---|
| | 2917 | return NULL; |
|---|
| | 2918 | } |
|---|
| | 2919 | |
|---|
| | 2920 | /* |
|---|
| | 2921 | * Scan a tag handle. |
|---|
| | 2922 | */ |
|---|
| | 2923 | |
|---|
| | 2924 | static int |
|---|
| | 2925 | yaml_parser_scan_tag_handle(yaml_parser_t *parser, int directive, |
|---|
| | 2926 | yaml_mark_t start_mark, yaml_char_t **handle) |
|---|
| | 2927 | { |
|---|
| | 2928 | yaml_string_t string = yaml_parser_new_string(parser); |
|---|
| | 2929 | |
|---|
| | 2930 | if (!string.buffer) goto error; |
|---|
| | 2931 | |
|---|
| | 2932 | /* Check the initial '!' character. */ |
|---|
| | 2933 | |
|---|
| | 2934 | if (!UPDATE(parser, 1)) goto error; |
|---|
| | 2935 | |
|---|
| | 2936 | if (!CHECK(parser, '!')) { |
|---|
| | 2937 | yaml_parser_set_scanner_error(parser, directive ? |
|---|
| | 2938 | "while scanning a tag directive" : "while scanning a tag", |
|---|
| | 2939 | start_mark, "did not find expected '!'"); |
|---|
| | 2940 | goto error; |
|---|
| | 2941 | } |
|---|
| | 2942 | |
|---|
| | 2943 | /* Copy the '!' character. */ |
|---|
| | 2944 | |
|---|
| | 2945 | COPY(parser, string); |
|---|
| | 2946 | |
|---|
| | 2947 | /* Copy all subsequent alphabetical and numerical characters. */ |
|---|
| | 2948 | |
|---|
| | 2949 | if (!UPDATE(parser, 1)) goto error; |
|---|
| | 2950 | |
|---|
| | 2951 | while (IS_ALPHA(parser)) |
|---|
| | 2952 | { |
|---|
| | 2953 | if (!RESIZE(parser, string)) goto error; |
|---|
| | 2954 | COPY(parser, string); |
|---|
| | 2955 | if (!UPDATE(parser, 1)) goto error; |
|---|
| | 2956 | } |
|---|
| | 2957 | |
|---|
| | 2958 | /* Check if the trailing character is '!' and copy it. */ |
|---|
| | 2959 | |
|---|
| | 2960 | if (CHECK(parser, '!')) |
|---|
| | 2961 | { |
|---|
| | 2962 | if (!RESIZE(parser, string)) goto error; |
|---|
| | 2963 | COPY(parser, string); |
|---|
| | 2964 | } |
|---|
| | 2965 | else |
|---|
| | 2966 | { |
|---|
| | 2967 | /* |
|---|
| | 2968 | * It's not really a tag handle. If it's a %TAG directive, it's an |
|---|
| | 2969 | * error. If it's a tag token, it must be a part of URI. |
|---|
| | 2970 | */ |
|---|
| | 2971 | |
|---|
| | 2972 | if (directive) { |
|---|
| | 2973 | yaml_parser_set_scanner_error(parser, "while parsing a directive", |
|---|
| | 2974 | start_mark, "did not find expected '!'"); |
|---|
| | 2975 | goto error; |
|---|
| | 2976 | } |
|---|
| | 2977 | } |
|---|
| | 2978 | |
|---|
| | 2979 | *handle = string.buffer; |
|---|
| | 2980 | |
|---|
| | 2981 | return 1; |
|---|
| | 2982 | |
|---|
| | 2983 | error: |
|---|
| | 2984 | yaml_free(string.buffer); |
|---|
| | 2985 | return 0; |
|---|
| | 2986 | } |
|---|
| | 2987 | |
|---|
| | 2988 | /* |
|---|
| | 2989 | * Scan a tag. |
|---|
| | 2990 | */ |
|---|
| | 2991 | |
|---|
| | 2992 | static int |
|---|
| | 2993 | yaml_parser_scan_tag_uri(yaml_parser_t *parser, int directive, |
|---|
| | 2994 | yaml_char_t *head, yaml_mark_t start_mark, yaml_char_t **uri) |
|---|
| | 2995 | { |
|---|
| | 2996 | size_t length = head ? strlen((char *)head) : 0; |
|---|
| | 2997 | yaml_string_t string = yaml_parser_new_string(parser); |
|---|
| | 2998 | |
|---|
| | 2999 | if (!string.buffer) goto error; |
|---|
| | 3000 | |
|---|
| | 3001 | /* Resize the string to include the head. */ |
|---|
| | 3002 | |
|---|
| | 3003 | while (string.size <= length) { |
|---|
| | 3004 | if (!yaml_parser_resize_string(parser, &string)) goto error; |
|---|
| | 3005 | } |
|---|
| | 3006 | |
|---|
| | 3007 | /* Copy the head if needed. */ |
|---|
| | 3008 | |
|---|
| | 3009 | if (length) { |
|---|
| | 3010 | memcpy(string.buffer, head, length); |
|---|
| | 3011 | string.pointer += length; |
|---|
| | 3012 | } |
|---|
| | 3013 | |
|---|
| | 3014 | /* Scan the tag. */ |
|---|
| | 3015 | |
|---|
| | 3016 | if (!UPDATE(parser, 1)) goto error; |
|---|
| | 3017 | |
|---|
| | 3018 | /* |
|---|
| | 3019 | * The set of characters that may appear in URI is as follows: |
|---|
| | 3020 | * |
|---|
| | 3021 | * '0'-'9', 'A'-'Z', 'a'-'z', '_', '-', ';', '/', '?', ':', '@', '&', |
|---|
| | 3022 | * '=', '+', '$', ',', '.', '!', '~', '*', '\'', '(', ')', '[', ']', |
|---|
| | 3023 | * '%'. |
|---|
| | 3024 | */ |
|---|
| | 3025 | |
|---|
| | 3026 | while (IS_ALPHA(parser) || CHECK(parser, ';') || CHECK(parser, '/') || |
|---|
| | 3027 | CHECK(parser, '?') || CHECK(parser, ':') || CHECK(parser, '@') || |
|---|
| | 3028 | CHECK(parser, '&') || CHECK(parser, '=') || CHECK(parser, '+') || |
|---|
| | 3029 | CHECK(parser, '$') || CHECK(parser, ',') || CHECK(parser, '.') || |
|---|
| | 3030 | CHECK(parser, '!') || CHECK(parser, '~') || CHECK(parser, '*') || |
|---|
| | 3031 | CHECK(parser, '\'') || CHECK(parser, '(') || CHECK(parser, ')') || |
|---|
| | 3032 | CHECK(parser, '[') || CHECK(parser, ']') || CHECK(parser, '%')) |
|---|
| | 3033 | { |
|---|
| | 3034 | if (!RESIZE(parser, string)) goto error; |
|---|
| | 3035 | |
|---|
| | 3036 | /* Check if it is a URI-escape sequence. */ |
|---|
| | 3037 | |
|---|
| | 3038 | if (CHECK(parser, '%')) { |
|---|
| | 3039 | if (!yaml_parser_scan_uri_escapes(parser, |
|---|
| | 3040 | directive, start_mark, &string)) goto error; |
|---|
| | 3041 | } |
|---|
| | 3042 | else { |
|---|
| | 3043 | COPY(parser, string); |
|---|
| | 3044 | } |
|---|
| | 3045 | |
|---|
| | 3046 | length ++; |
|---|
| | 3047 | if (!UPDATE(parser, 1)) goto error; |
|---|
| | 3048 | }&n |
|---|