Date: 2025-03-28T21:11:14+00:00

Actual source code: scanner.c

      2: /*
      3:  * Introduction
      4:  * ************
      5:  *
      6:  * The following notes assume that you are familiar with the YAML specification
      7:  * (http://yaml.org/spec/cvs/current.html).  We mostly follow it, although in
      8:  * some cases we are less restrictive that it requires.
      9:  *
     10:  * The process of transforming a YAML stream into a sequence of events is
     11:  * divided on two steps: Scanning and Parsing.
     12:  *
     13:  * The Scanner transforms the input stream into a sequence of tokens, while the
     14:  * parser transform the sequence of tokens produced by the Scanner into a
     15:  * sequence of parsing events.
     16:  *
     17:  * The Scanner is rather clever and complicated. The Parser, on the contrary,
     18:  * is a straightforward implementation of a recursive-descendant parser (or,
     19:  * LL(1) parser, as it is usually called).
     20:  *
     21:  * Actually there are two issues of Scanning that might be called "clever", the
     22:  * rest is quite straightforward.  The issues are "block collection start" and
     23:  * "simple keys".  Both issues are explained below in details.
     24:  *
     25:  * Here the Scanning step is explained and implemented.  We start with the list
     26:  * of all the tokens produced by the Scanner together with short descriptions.
     27:  *
     28:  * Now, tokens:
     29:  *
     30:  *      STREAM-START(encoding)          # The stream start.
     31:  *      STREAM-END                      # The stream end.
     32:  *      VERSION-DIRECTIVE(major,minor)  # The '%YAML' directive.
     33:  *      TAG-DIRECTIVE(handle,prefix)    # The '%TAG' directive.
     34:  *      DOCUMENT-START                  # '---'
     35:  *      DOCUMENT-END                    # '...'
     36:  *      BLOCK-SEQUENCE-START            # Indentation increase denoting a block
     37:  *      BLOCK-MAPPING-START             # sequence or a block mapping.
     38:  *      BLOCK-END                       # Indentation decrease.
     39:  *      FLOW-SEQUENCE-START             # '['
     40:  *      FLOW-SEQUENCE-END               # ']'
     41:  *      FLOW-MAPPING-START              # '{'
     42:  *      FLOW-MAPPING-END                # '}'
     43:  *      BLOCK-ENTRY                     # '-'
     44:  *      FLOW-ENTRY                      # ','
     45:  *      KEY                             # '?' or nothing (simple keys).
     46:  *      VALUE                           # ':'
     47:  *      ALIAS(anchor)                   # '*anchor'
     48:  *      ANCHOR(anchor)                  # '&anchor'
     49:  *      TAG(handle,suffix)              # '!handle!suffix'
     50:  *      SCALAR(value,style)             # A scalar.
     51:  *
     52:  * The following two tokens are "virtual" tokens denoting the beginning and the
     53:  * end of the stream:
     54:  *
     55:  *      STREAM-START(encoding)
     56:  *      STREAM-END
     57:  *
     58:  * We pass the information about the input stream encoding with the
     59:  * STREAM-START token.
     60:  *
     61:  * The next two tokens are responsible for tags:
     62:  *
     63:  *      VERSION-DIRECTIVE(major,minor)
     64:  *      TAG-DIRECTIVE(handle,prefix)
     65:  *
     66:  * Example:
     67:  *
     68:  *      %YAML   1.1
     69:  *      %TAG    !   !foo
     70:  *      %TAG    !yaml!  tag:yaml.org,2002:
     71:  *      ---
     72:  *
     73:  * The corresponding sequence of tokens:
     74:  *
     75:  *      STREAM-START(utf-8)
     76:  *      VERSION-DIRECTIVE(1,1)
     77:  *      TAG-DIRECTIVE("!","!foo")
     78:  *      TAG-DIRECTIVE("!yaml","tag:yaml.org,2002:")
     79:  *      DOCUMENT-START
     80:  *      STREAM-END
     81:  *
     82:  * Note that the VERSION-DIRECTIVE and TAG-DIRECTIVE tokens occupy a whole
     83:  * line.
     84:  *
     85:  * The document start and end indicators are represented by:
     86:  *
     87:  *      DOCUMENT-START
     88:  *      DOCUMENT-END
     89:  *
     90:  * Note that if a YAML stream contains an implicit document (without '---'
     91:  * and '...' indicators), no DOCUMENT-START and DOCUMENT-END tokens will be
     92:  * produced.
     93:  *
     94:  * In the following examples, we present whole documents together with the
     95:  * produced tokens.
     96:  *
     97:  *      1. An implicit document:
     98:  *
     99:  *          'a scalar'
    100:  *
    101:  *      Tokens:
    102:  *
    103:  *          STREAM-START(utf-8)
    104:  *          SCALAR("a scalar",single-quoted)
    105:  *          STREAM-END
    106:  *
    107:  *      2. An explicit document:
    108:  *
    109:  *          ---
    110:  *          'a scalar'
    111:  *          ...
    112:  *
    113:  *      Tokens:
    114:  *
    115:  *          STREAM-START(utf-8)
    116:  *          DOCUMENT-START
    117:  *          SCALAR("a scalar",single-quoted)
    118:  *          DOCUMENT-END
    119:  *          STREAM-END
    120:  *
    121:  *      3. Several documents in a stream:
    122:  *
    123:  *          'a scalar'
    124:  *          ---
    125:  *          'another scalar'
    126:  *          ---
    127:  *          'yet another scalar'
    128:  *
    129:  *      Tokens:
    130:  *
    131:  *          STREAM-START(utf-8)
    132:  *          SCALAR("a scalar",single-quoted)
    133:  *          DOCUMENT-START
    134:  *          SCALAR("another scalar",single-quoted)
    135:  *          DOCUMENT-START
    136:  *          SCALAR("yet another scalar",single-quoted)
    137:  *          STREAM-END
    138:  *
    139:  * We have already introduced the SCALAR token above.  The following tokens are
    140:  * used to describe aliases, anchors, tag, and scalars:
    141:  *
    142:  *      ALIAS(anchor)
    143:  *      ANCHOR(anchor)
    144:  *      TAG(handle,suffix)
    145:  *      SCALAR(value,style)
    146:  *
    147:  * The following series of examples illustrate the usage of these tokens:
    148:  *
    149:  *      1. A recursive sequence:
    150:  *
    151:  *          &A [ *A ]
    152:  *
    153:  *      Tokens:
    154:  *
    155:  *          STREAM-START(utf-8)
    156:  *          ANCHOR("A")
    157:  *          FLOW-SEQUENCE-START
    158:  *          ALIAS("A")
    159:  *          FLOW-SEQUENCE-END
    160:  *          STREAM-END
    161:  *
    162:  *      2. A tagged scalar:
    163:  *
    164:  *          !!float "3.14"  # A good approximation.
    165:  *
    166:  *      Tokens:
    167:  *
    168:  *          STREAM-START(utf-8)
    169:  *          TAG("!!","float")
    170:  *          SCALAR("3.14",double-quoted)
    171:  *          STREAM-END
    172:  *
    173:  *      3. Various scalar styles:
    174:  *
    175:  *          --- # Implicit empty plain scalars do not produce tokens.
    176:  *          --- a plain scalar
    177:  *          --- 'a single-quoted scalar'
    178:  *          --- "a double-quoted scalar"
    179:  *          --- |-
    180:  *            a literal scalar
    181:  *          --- >-
    182:  *            a folded
    183:  *            scalar
    184:  *
    185:  *      Tokens:
    186:  *
    187:  *          STREAM-START(utf-8)
    188:  *          DOCUMENT-START
    189:  *          DOCUMENT-START
    190:  *          SCALAR("a plain scalar",plain)
    191:  *          DOCUMENT-START
    192:  *          SCALAR("a single-quoted scalar",single-quoted)
    193:  *          DOCUMENT-START
    194:  *          SCALAR("a double-quoted scalar",double-quoted)
    195:  *          DOCUMENT-START
    196:  *          SCALAR("a literal scalar",literal)
    197:  *          DOCUMENT-START
    198:  *          SCALAR("a folded scalar",folded)
    199:  *          STREAM-END
    200:  *
    201:  * Now it's time to review collection-related tokens. We will start with
    202:  * flow collections:
    203:  *
    204:  *      FLOW-SEQUENCE-START
    205:  *      FLOW-SEQUENCE-END
    206:  *      FLOW-MAPPING-START
    207:  *      FLOW-MAPPING-END
    208:  *      FLOW-ENTRY
    209:  *      KEY
    210:  *      VALUE
    211:  *
    212:  * The tokens FLOW-SEQUENCE-START, FLOW-SEQUENCE-END, FLOW-MAPPING-START, and
    213:  * FLOW-MAPPING-END represent the indicators '[', ']', '{', and '}'
    214:  * correspondingly.  FLOW-ENTRY represent the ',' indicator.  Finally the
    215:  * indicators '?' and ':', which are used for denoting mapping keys and values,
    216:  * are represented by the KEY and VALUE tokens.
    217:  *
    218:  * The following examples show flow collections:
    219:  *
    220:  *      1. A flow sequence:
    221:  *
    222:  *          [item 1, item 2, item 3]
    223:  *
    224:  *      Tokens:
    225:  *
    226:  *          STREAM-START(utf-8)
    227:  *          FLOW-SEQUENCE-START
    228:  *          SCALAR("item 1",plain)
    229:  *          FLOW-ENTRY
    230:  *          SCALAR("item 2",plain)
    231:  *          FLOW-ENTRY
    232:  *          SCALAR("item 3",plain)
    233:  *          FLOW-SEQUENCE-END
    234:  *          STREAM-END
    235:  *
    236:  *      2. A flow mapping:
    237:  *
    238:  *          {
    239:  *              a simple key: a value,  # Note that the KEY token is produced.
    240:  *              ? a complex key: another value,
    241:  *          }
    242:  *
    243:  *      Tokens:
    244:  *
    245:  *          STREAM-START(utf-8)
    246:  *          FLOW-MAPPING-START
    247:  *          KEY
    248:  *          SCALAR("a simple key",plain)
    249:  *          VALUE
    250:  *          SCALAR("a value",plain)
    251:  *          FLOW-ENTRY
    252:  *          KEY
    253:  *          SCALAR("a complex key",plain)
    254:  *          VALUE
    255:  *          SCALAR("another value",plain)
    256:  *          FLOW-ENTRY
    257:  *          FLOW-MAPPING-END
    258:  *          STREAM-END
    259:  *
    260:  * A simple key is a key which is not denoted by the '?' indicator.  Note that
    261:  * the Scanner still produce the KEY token whenever it encounters a simple key.
    262:  *
    263:  * For scanning block collections, the following tokens are used (note that we
    264:  * repeat KEY and VALUE here):
    265:  *
    266:  *      BLOCK-SEQUENCE-START
    267:  *      BLOCK-MAPPING-START
    268:  *      BLOCK-END
    269:  *      BLOCK-ENTRY
    270:  *      KEY
    271:  *      VALUE
    272:  *
    273:  * The tokens BLOCK-SEQUENCE-START and BLOCK-MAPPING-START denote indentation
    274:  * increase that precedes a block collection (cf. the INDENT token in Python).
    275:  * The token BLOCK-END denote indentation decrease that ends a block collection
    276:  * (cf. the DEDENT token in Python).  However YAML has some syntax peculiarities
    277:  * that makes detections of these tokens more complex.
    278:  *
    279:  * The tokens BLOCK-ENTRY, KEY, and VALUE are used to represent the indicators
    280:  * '-', '?', and ':' correspondingly.
    281:  *
    282:  * The following examples show how the tokens BLOCK-SEQUENCE-START,
    283:  * BLOCK-MAPPING-START, and BLOCK-END are emitted by the Scanner:
    284:  *
    285:  *      1. Block sequences:
    286:  *
    287:  *          - item 1
    288:  *          - item 2
    289:  *          -
    290:  *            - item 3.1
    291:  *            - item 3.2
    292:  *          -
    293:  *            key 1: value 1
    294:  *            key 2: value 2
    295:  *
    296:  *      Tokens:
    297:  *
    298:  *          STREAM-START(utf-8)
    299:  *          BLOCK-SEQUENCE-START
    300:  *          BLOCK-ENTRY
    301:  *          SCALAR("item 1",plain)
    302:  *          BLOCK-ENTRY
    303:  *          SCALAR("item 2",plain)
    304:  *          BLOCK-ENTRY
    305:  *          BLOCK-SEQUENCE-START
    306:  *          BLOCK-ENTRY
    307:  *          SCALAR("item 3.1",plain)
    308:  *          BLOCK-ENTRY
    309:  *          SCALAR("item 3.2",plain)
    310:  *          BLOCK-END
    311:  *          BLOCK-ENTRY
    312:  *          BLOCK-MAPPING-START
    313:  *          KEY
    314:  *          SCALAR("key 1",plain)
    315:  *          VALUE
    316:  *          SCALAR("value 1",plain)
    317:  *          KEY
    318:  *          SCALAR("key 2",plain)
    319:  *          VALUE
    320:  *          SCALAR("value 2",plain)
    321:  *          BLOCK-END
    322:  *          BLOCK-END
    323:  *          STREAM-END
    324:  *
    325:  *      2. Block mappings:
    326:  *
    327:  *          a simple key: a value   # The KEY token is produced here.
    328:  *          ? a complex key
    329:  *          : another value
    330:  *          a mapping:
    331:  *            key 1: value 1
    332:  *            key 2: value 2
    333:  *          a sequence:
    334:  *            - item 1
    335:  *            - item 2
    336:  *
    337:  *      Tokens:
    338:  *
    339:  *          STREAM-START(utf-8)
    340:  *          BLOCK-MAPPING-START
    341:  *          KEY
    342:  *          SCALAR("a simple key",plain)
    343:  *          VALUE
    344:  *          SCALAR("a value",plain)
    345:  *          KEY
    346:  *          SCALAR("a complex key",plain)
    347:  *          VALUE
    348:  *          SCALAR("another value",plain)
    349:  *          KEY
    350:  *          SCALAR("a mapping",plain)
    351:  *          VALUE
    352:  *          BLOCK-MAPPING-START
    353:  *          KEY
    354:  *          SCALAR("key 1",plain)
    355:  *          VALUE
    356:  *          SCALAR("value 1",plain)
    357:  *          KEY
    358:  *          SCALAR("key 2",plain)
    359:  *          VALUE
    360:  *          SCALAR("value 2",plain)
    361:  *          BLOCK-END
    362:  *          KEY
    363:  *          SCALAR("a sequence",plain)
    364:  *          VALUE
    365:  *          BLOCK-SEQUENCE-START
    366:  *          BLOCK-ENTRY
    367:  *          SCALAR("item 1",plain)
    368:  *          BLOCK-ENTRY
    369:  *          SCALAR("item 2",plain)
    370:  *          BLOCK-END
    371:  *          BLOCK-END
    372:  *          STREAM-END
    373:  *
    374:  * YAML does not always require to start a new block collection from a new
    375:  * line.  If the current line contains only '-', '?', and ':' indicators, a new
    376:  * block collection may start at the current line.  The following examples
    377:  * illustrate this case:
    378:  *
    379:  *      1. Collections in a sequence:
    380:  *
    381:  *          - - item 1
    382:  *            - item 2
    383:  *          - key 1: value 1
    384:  *            key 2: value 2
    385:  *          - ? complex key
    386:  *            : complex value
    387:  *
    388:  *      Tokens:
    389:  *
    390:  *          STREAM-START(utf-8)
    391:  *          BLOCK-SEQUENCE-START
    392:  *          BLOCK-ENTRY
    393:  *          BLOCK-SEQUENCE-START
    394:  *          BLOCK-ENTRY
    395:  *          SCALAR("item 1",plain)
    396:  *          BLOCK-ENTRY
    397:  *          SCALAR("item 2",plain)
    398:  *          BLOCK-END
    399:  *          BLOCK-ENTRY
    400:  *          BLOCK-MAPPING-START
    401:  *          KEY
    402:  *          SCALAR("key 1",plain)
    403:  *          VALUE
    404:  *          SCALAR("value 1",plain)
    405:  *          KEY
    406:  *          SCALAR("key 2",plain)
    407:  *          VALUE
    408:  *          SCALAR("value 2",plain)
    409:  *          BLOCK-END
    410:  *          BLOCK-ENTRY
    411:  *          BLOCK-MAPPING-START
    412:  *          KEY
    413:  *          SCALAR("complex key")
    414:  *          VALUE
    415:  *          SCALAR("complex value")
    416:  *          BLOCK-END
    417:  *          BLOCK-END
    418:  *          STREAM-END
    419:  *
    420:  *      2. Collections in a mapping:
    421:  *
    422:  *          ? a sequence
    423:  *          : - item 1
    424:  *            - item 2
    425:  *          ? a mapping
    426:  *          : key 1: value 1
    427:  *            key 2: value 2
    428:  *
    429:  *      Tokens:
    430:  *
    431:  *          STREAM-START(utf-8)
    432:  *          BLOCK-MAPPING-START
    433:  *          KEY
    434:  *          SCALAR("a sequence",plain)
    435:  *          VALUE
    436:  *          BLOCK-SEQUENCE-START
    437:  *          BLOCK-ENTRY
    438:  *          SCALAR("item 1",plain)
    439:  *          BLOCK-ENTRY
    440:  *          SCALAR("item 2",plain)
    441:  *          BLOCK-END
    442:  *          KEY
    443:  *          SCALAR("a mapping",plain)
    444:  *          VALUE
    445:  *          BLOCK-MAPPING-START
    446:  *          KEY
    447:  *          SCALAR("key 1",plain)
    448:  *          VALUE
    449:  *          SCALAR("value 1",plain)
    450:  *          KEY
    451:  *          SCALAR("key 2",plain)
    452:  *          VALUE
    453:  *          SCALAR("value 2",plain)
    454:  *          BLOCK-END
    455:  *          BLOCK-END
    456:  *          STREAM-END
    457:  *
    458:  * YAML also permits non-indented sequences if they are included into a block
    459:  * mapping.  In this case, the token BLOCK-SEQUENCE-START is not produced:
    460:  *
    461:  *      key:
    462:  *      - item 1    # BLOCK-SEQUENCE-START is NOT produced here.
    463:  *      - item 2
    464:  *
    465:  * Tokens:
    466:  *
    467:  *      STREAM-START(utf-8)
    468:  *      BLOCK-MAPPING-START
    469:  *      KEY
    470:  *      SCALAR("key",plain)
    471:  *      VALUE
    472:  *      BLOCK-ENTRY
    473:  *      SCALAR("item 1",plain)
    474:  *      BLOCK-ENTRY
    475:  *      SCALAR("item 2",plain)
    476:  *      BLOCK-END
    477:  */

    479: #include "yaml_private.h"

    481: /*
    482:  * Ensure that the buffer contains the required number of characters.
    483:  * Return 1 on success, 0 on failure (reader error or memory error).
    484:  */

    486: #define CACHE(parser,length)                                                    \
    487:     (parser->unread >= (length)                                                 \
    488:         ? 1                                                                     \
    489:         : yaml_parser_update_buffer(parser, (length)))

    491: /*
    492:  * Advance the buffer pointer.
    493:  */

    495: #define SKIP(parser)                                                            \
    496:      (parser->mark.index ++,                                                    \
    497:       parser->mark.column ++,                                                   \
    498:       parser->unread --,                                                        \
    499:       parser->buffer.pointer += WIDTH(parser->buffer))

    501: #define SKIP_LINE(parser)                                                       \
    502:      (IS_CRLF(parser->buffer) ?                                                 \
    503:       (parser->mark.index += 2,                                                 \
    504:        parser->mark.column = 0,                                                 \
    505:        parser->mark.line ++,                                                    \
    506:        parser->unread -= 2,                                                     \
    507:        parser->buffer.pointer += 2) :                                           \
    508:       IS_BREAK(parser->buffer) ?                                                \
    509:       (parser->mark.index ++,                                                   \
    510:        parser->mark.column = 0,                                                 \
    511:        parser->mark.line ++,                                                    \
    512:        parser->unread --,                                                       \
    513:        parser->buffer.pointer += WIDTH(parser->buffer)) : NULL)

    515: /*
    516:  * Copy a character to a string buffer and advance pointers.
    517:  */

    519: #define READ(parser,string)                                                     \
    520:      (STRING_EXTEND(parser,string) ?                                            \
    521:          (COPY(string,parser->buffer),                                          \
    522:           parser->mark.index ++,                                                \
    523:           parser->mark.column ++,                                               \
    524:           parser->unread --,                                                    \
    525:           1) : 0)

    527: /*
    528:  * Copy a line break character to a string buffer and advance pointers.
    529:  */

    531: #define READ_LINE(parser,string)                                                \
    532:     (STRING_EXTEND(parser,string) ?                                             \
    533:     (((CHECK_AT(parser->buffer,'\r',0)                                          \
    534:        && CHECK_AT(parser->buffer,'\n',1)) ?        /* CR LF -> LF */           \
    535:      (*((string).pointer++) = (yaml_char_t) '\n',                               \
    536:       parser->buffer.pointer += 2,                                              \
    537:       parser->mark.index += 2,                                                  \
    538:       parser->mark.column = 0,                                                  \
    539:       parser->mark.line ++,                                                     \
    540:       parser->unread -= 2) :                                                    \
    541:      (CHECK_AT(parser->buffer,'\r',0)                                           \
    542:       || CHECK_AT(parser->buffer,'\n',0)) ?         /* CR|LF -> LF */           \
    543:      (*((string).pointer++) = (yaml_char_t) '\n',                               \
    544:       parser->buffer.pointer ++,                                                \
    545:       parser->mark.index ++,                                                    \
    546:       parser->mark.column = 0,                                                  \
    547:       parser->mark.line ++,                                                     \
    548:       parser->unread --) :                                                      \
    549:      (CHECK_AT(parser->buffer,'\xC2',0)                                         \
    550:       && CHECK_AT(parser->buffer,'\x85',1)) ?       /* NEL -> LF */             \
    551:      (*((string).pointer++) = (yaml_char_t) '\n',                               \
    552:       parser->buffer.pointer += 2,                                              \
    553:       parser->mark.index ++,                                                    \
    554:       parser->mark.column = 0,                                                  \
    555:       parser->mark.line ++,                                                     \
    556:       parser->unread --) :                                                      \
    557:      (CHECK_AT(parser->buffer,'\xE2',0) &&                                      \
    558:       CHECK_AT(parser->buffer,'\x80',1) &&                                      \
    559:       (CHECK_AT(parser->buffer,'\xA8',2) ||                                     \
    560:        CHECK_AT(parser->buffer,'\xA9',2))) ?        /* LS|PS -> LS|PS */        \
    561:      (*((string).pointer++) = *(parser->buffer.pointer++),                      \
    562:       *((string).pointer++) = *(parser->buffer.pointer++),                      \
    563:       *((string).pointer++) = *(parser->buffer.pointer++),                      \
    564:       parser->mark.index ++,                                                    \
    565:       parser->mark.column = 0,                                                  \
    566:       parser->mark.line ++,                                                     \
    567:       parser->unread --) : 0),                                                  \
    568:     1) : 0)

    570: /*
    571:  * Public API declarations.
    572:  */

    574: YAML_DECLARE(int)
    575: yaml_parser_scan(yaml_parser_t *parser, yaml_token_t *token);

    577: /*
    578:  * Error handling.
    579:  */

    581: static int
    582: yaml_parser_set_scanner_error(yaml_parser_t *parser, const char *context,
    583:         yaml_mark_t context_mark, const char *problem);

    585: /*
    586:  * High-level token API.
    587:  */

    589: YAML_DECLARE(int)
    590: yaml_parser_fetch_more_tokens(yaml_parser_t *parser);

    592: static int
    593: yaml_parser_fetch_next_token(yaml_parser_t *parser);

    595: /*
    596:  * Potential simple keys.
    597:  */

    599: static int
    600: yaml_parser_stale_simple_keys(yaml_parser_t *parser);

    602: static int
    603: yaml_parser_save_simple_key(yaml_parser_t *parser);

    605: static int
    606: yaml_parser_remove_simple_key(yaml_parser_t *parser);

    608: static int
    609: yaml_parser_increase_flow_level(yaml_parser_t *parser);

    611: static int
    612: yaml_parser_decrease_flow_level(yaml_parser_t *parser);

    614: /*
    615:  * Indentation treatment.
    616:  */

    618: static int
    619: yaml_parser_roll_indent(yaml_parser_t *parser, ptrdiff_t column,
    620:         ptrdiff_t number, yaml_token_type_t type, yaml_mark_t mark);

    622: static int
    623: yaml_parser_unroll_indent(yaml_parser_t *parser, ptrdiff_t column);

    625: /*
    626:  * Token fetchers.
    627:  */

    629: static int
    630: yaml_parser_fetch_stream_start(yaml_parser_t *parser);

    632: static int
    633: yaml_parser_fetch_stream_end(yaml_parser_t *parser);

    635: static int
    636: yaml_parser_fetch_directive(yaml_parser_t *parser);

    638: static int
    639: yaml_parser_fetch_document_indicator(yaml_parser_t *parser,
    640:         yaml_token_type_t type);

    642: static int
    643: yaml_parser_fetch_flow_collection_start(yaml_parser_t *parser,
    644:         yaml_token_type_t type);

    646: static int
    647: yaml_parser_fetch_flow_collection_end(yaml_parser_t *parser,
    648:         yaml_token_type_t type);

    650: static int
    651: yaml_parser_fetch_flow_entry(yaml_parser_t *parser);

    653: static int
    654: yaml_parser_fetch_block_entry(yaml_parser_t *parser);

    656: static int
    657: yaml_parser_fetch_key(yaml_parser_t *parser);

    659: static int
    660: yaml_parser_fetch_value(yaml_parser_t *parser);

    662: static int
    663: yaml_parser_fetch_anchor(yaml_parser_t *parser, yaml_token_type_t type);

    665: static int
    666: yaml_parser_fetch_tag(yaml_parser_t *parser);

    668: static int
    669: yaml_parser_fetch_block_scalar(yaml_parser_t *parser, int literal);

    671: static int
    672: yaml_parser_fetch_flow_scalar(yaml_parser_t *parser, int single);

    674: static int
    675: yaml_parser_fetch_plain_scalar(yaml_parser_t *parser);

    677: /*
    678:  * Token scanners.
    679:  */

    681: static int
    682: yaml_parser_scan_to_next_token(yaml_parser_t *parser);

    684: static int
    685: yaml_parser_scan_directive(yaml_parser_t *parser, yaml_token_t *token);

    687: static int
    688: yaml_parser_scan_directive_name(yaml_parser_t *parser,
    689:         yaml_mark_t start_mark, yaml_char_t **name);

    691: static int
    692: yaml_parser_scan_version_directive_value(yaml_parser_t *parser,
    693:         yaml_mark_t start_mark, int *major, int *minor);

    695: static int
    696: yaml_parser_scan_version_directive_number(yaml_parser_t *parser,
    697:         yaml_mark_t start_mark, int *number);

    699: static int
    700: yaml_parser_scan_tag_directive_value(yaml_parser_t *parser,
    701:         yaml_mark_t mark, yaml_char_t **handle, yaml_char_t **prefix);

    703: static int
    704: yaml_parser_scan_anchor(yaml_parser_t *parser, yaml_token_t *token,
    705:         yaml_token_type_t type);

    707: static int
    708: yaml_parser_scan_tag(yaml_parser_t *parser, yaml_token_t *token);

    710: static int
    711: yaml_parser_scan_tag_handle(yaml_parser_t *parser, int directive,
    712:         yaml_mark_t start_mark, yaml_char_t **handle);

    714: static int
    715: yaml_parser_scan_tag_uri(yaml_parser_t *parser, int uri_char, int directive,
    716:         yaml_char_t *head, yaml_mark_t start_mark, yaml_char_t **uri);

    718: static int
    719: yaml_parser_scan_uri_escapes(yaml_parser_t *parser, int directive,
    720:         yaml_mark_t start_mark, yaml_string_t *string);

    722: static int
    723: yaml_parser_scan_block_scalar(yaml_parser_t *parser, yaml_token_t *token,
    724:         int literal);

    726: static int
    727: yaml_parser_scan_block_scalar_breaks(yaml_parser_t *parser,
    728:         int *indent, yaml_string_t *breaks,
    729:         yaml_mark_t start_mark, yaml_mark_t *end_mark);

    731: static int
    732: yaml_parser_scan_flow_scalar(yaml_parser_t *parser, yaml_token_t *token,
    733:         int single);

    735: static int
    736: yaml_parser_scan_plain_scalar(yaml_parser_t *parser, yaml_token_t *token);

    738: /*
    739:  * Get the next token.
    740:  */

    742: YAML_DECLARE(int)
    743: yaml_parser_scan(yaml_parser_t *parser, yaml_token_t *token)
    744: {
    745:     assert(parser); /* Non-NULL parser object is expected. */
    746:     assert(token);  /* Non-NULL token object is expected. */

    748:     /* Erase the token object. */

    750:     memset(token, 0, sizeof(yaml_token_t));

    752:     /* No tokens after STREAM-END or error. */

    754:     if (parser->stream_end_produced || parser->error) {
    755:         return 1;
    756:     }

    758:     /* Ensure that the tokens queue contains enough tokens. */

    760:     if (!parser->token_available) {
    761:         if (!yaml_parser_fetch_more_tokens(parser))
    762:             return 0;
    763:     }

    765:     /* Fetch the next token from the queue. */

    767:     *token = DEQUEUE(parser, parser->tokens);
    768:     parser->token_available = 0;
    769:     parser->tokens_parsed ++;

    771:     if (token->type == YAML_STREAM_END_TOKEN) {
    772:         parser->stream_end_produced = 1;
    773:     }

    775:     return 1;
    776: }

    778: /*
    779:  * Set the scanner error and return 0.
    780:  */

    782: static int
    783: yaml_parser_set_scanner_error(yaml_parser_t *parser, const char *context,
    784:         yaml_mark_t context_mark, const char *problem)
    785: {
    786:     parser->error = YAML_SCANNER_ERROR;
    787:     parser->context = context;
    788:     parser->context_mark = context_mark;
    789:     parser->problem = problem;
    790:     parser->problem_mark = parser->mark;

    792:     return 0;
    793: }

    795: /*
    796:  * Ensure that the tokens queue contains at least one token which can be
    797:  * returned to the Parser.
    798:  */

    800: YAML_DECLARE(int)
    801: yaml_parser_fetch_more_tokens(yaml_parser_t *parser)
    802: {
    803:     int need_more_tokens;

    805:     /* While we need more tokens to fetch, do it. */

    807:     while (1)
    808:     {
    809:         /*
    810:          * Check if we really need to fetch more tokens.
    811:          */

    813:         need_more_tokens = 0;

    815:         if (parser->tokens.head == parser->tokens.tail)
    816:         {
    817:             /* Queue is empty. */

    819:             need_more_tokens = 1;
    820:         }
    821:         else
    822:         {
    823:             yaml_simple_key_t *simple_key;

    825:             /* Check if any potential simple key may occupy the head position. */

    827:             if (!yaml_parser_stale_simple_keys(parser))
    828:                 return 0;

    830:             for (simple_key = parser->simple_keys.start;
    831:                     simple_key != parser->simple_keys.top; simple_key++) {
    832:                 if (simple_key->possible
    833:                         && simple_key->token_number == parser->tokens_parsed) {
    834:                     need_more_tokens = 1;
    835:                     break;
    836:                 }
    837:             }
    838:         }

    840:         /* We are finished. */

    842:         if (!need_more_tokens)
    843:             break;

    845:         /* Fetch the next token. */

    847:         if (!yaml_parser_fetch_next_token(parser))
    848:             return 0;
    849:     }

    851:     parser->token_available = 1;

    853:     return 1;
    854: }

    856: /*
    857:  * The dispatcher for token fetchers.
    858:  */

    860: static int
    861: yaml_parser_fetch_next_token(yaml_parser_t *parser)
    862: {
    863:     /* Ensure that the buffer is initialized. */

    865:     if (!CACHE(parser, 1))
    866:         return 0;

    868:     /* Check if we just started scanning.  Fetch STREAM-START then. */

    870:     if (!parser->stream_start_produced)
    871:         return yaml_parser_fetch_stream_start(parser);

    873:     /* Eat whitespaces and comments until we reach the next token. */

    875:     if (!yaml_parser_scan_to_next_token(parser))
    876:         return 0;

    878:     /* Remove obsolete potential simple keys. */

    880:     if (!yaml_parser_stale_simple_keys(parser))
    881:         return 0;

    883:     /* Check the indentation level against the current column. */

    885:     if (!yaml_parser_unroll_indent(parser, parser->mark.column))
    886:         return 0;

    888:     /*
    889:      * Ensure that the buffer contains at least 4 characters.  4 is the length
    890:      * of the longest indicators ('--- ' and '... ').
    891:      */

    893:     if (!CACHE(parser, 4))
    894:         return 0;

    896:     /* Is it the end of the stream? */

    898:     if (IS_Z(parser->buffer))
    899:         return yaml_parser_fetch_stream_end(parser);

    901:     /* Is it a directive? */

    903:     if (parser->mark.column == 0 && CHECK(parser->buffer, '%'))
    904:         return yaml_parser_fetch_directive(parser);

    906:     /* Is it the document start indicator? */

    908:     if (parser->mark.column == 0
    909:             && CHECK_AT(parser->buffer, '-', 0)
    910:             && CHECK_AT(parser->buffer, '-', 1)
    911:             && CHECK_AT(parser->buffer, '-', 2)
    912:             && IS_BLANKZ_AT(parser->buffer, 3))
    913:         return yaml_parser_fetch_document_indicator(parser,
    914:                 YAML_DOCUMENT_START_TOKEN);

    916:     /* Is it the document end indicator? */

    918:     if (parser->mark.column == 0
    919:             && CHECK_AT(parser->buffer, '.', 0)
    920:             && CHECK_AT(parser->buffer, '.', 1)
    921:             && CHECK_AT(parser->buffer, '.', 2)
    922:             && IS_BLANKZ_AT(parser->buffer, 3))
    923:         return yaml_parser_fetch_document_indicator(parser,
    924:                 YAML_DOCUMENT_END_TOKEN);

    926:     /* Is it the flow sequence start indicator? */

    928:     if (CHECK(parser->buffer, '['))
    929:         return yaml_parser_fetch_flow_collection_start(parser,
    930:                 YAML_FLOW_SEQUENCE_START_TOKEN);

    932:     /* Is it the flow mapping start indicator? */

    934:     if (CHECK(parser->buffer, '{'))
    935:         return yaml_parser_fetch_flow_collection_start(parser,
    936:                 YAML_FLOW_MAPPING_START_TOKEN);

    938:     /* Is it the flow sequence end indicator? */

    940:     if (CHECK(parser->buffer, ']'))
    941:         return yaml_parser_fetch_flow_collection_end(parser,
    942:                 YAML_FLOW_SEQUENCE_END_TOKEN);

    944:     /* Is it the flow mapping end indicator? */

    946:     if (CHECK(parser->buffer, '}'))
    947:         return yaml_parser_fetch_flow_collection_end(parser,
    948:                 YAML_FLOW_MAPPING_END_TOKEN);

    950:     /* Is it the flow entry indicator? */

    952:     if (CHECK(parser->buffer, ','))
    953:         return yaml_parser_fetch_flow_entry(parser);

    955:     /* Is it the block entry indicator? */

    957:     if (CHECK(parser->buffer, '-') && IS_BLANKZ_AT(parser->buffer, 1))
    958:         return yaml_parser_fetch_block_entry(parser);

    960:     /* Is it the key indicator? */

    962:     if (CHECK(parser->buffer, '?')
    963:             && (parser->flow_level || IS_BLANKZ_AT(parser->buffer, 1)))
    964:         return yaml_parser_fetch_key(parser);

    966:     /* Is it the value indicator? */

    968:     if (CHECK(parser->buffer, ':')
    969:             && (parser->flow_level || IS_BLANKZ_AT(parser->buffer, 1)))
    970:         return yaml_parser_fetch_value(parser);

    972:     /* Is it an alias? */

    974:     if (CHECK(parser->buffer, '*'))
    975:         return yaml_parser_fetch_anchor(parser, YAML_ALIAS_TOKEN);

    977:     /* Is it an anchor? */

    979:     if (CHECK(parser->buffer, '&'))
    980:         return yaml_parser_fetch_anchor(parser, YAML_ANCHOR_TOKEN);

    982:     /* Is it a tag? */

    984:     if (CHECK(parser->buffer, '!'))
    985:         return yaml_parser_fetch_tag(parser);

    987:     /* Is it a literal scalar? */

    989:     if (CHECK(parser->buffer, '|') && !parser->flow_level)
    990:         return yaml_parser_fetch_block_scalar(parser, 1);

    992:     /* Is it a folded scalar? */

    994:     if (CHECK(parser->buffer, '>') && !parser->flow_level)
    995:         return yaml_parser_fetch_block_scalar(parser, 0);

    997:     /* Is it a single-quoted scalar? */

    999:     if (CHECK(parser->buffer, '\''))
    1000:         return yaml_parser_fetch_flow_scalar(parser, 1);

    1002:     /* Is it a double-quoted scalar? */

    1004:     if (CHECK(parser->buffer, '"'))
    1005:         return yaml_parser_fetch_flow_scalar(parser, 0);

    1007:     /*
    1008:      * Is it a plain scalar?
    1009:      *
    1010:      * A plain scalar may start with any non-blank characters except
    1011:      *
    1012:      *      '-', '?', ':', ',', '[', ']', '{', '}',
    1013:      *      '#', '&', '*', '!', '|', '>', '\'', '\"',
    1014:      *      '%', '@', '`'.
    1015:      *
    1016:      * In the block context (and, for the '-' indicator, in the flow context
    1017:      * too), it may also start with the characters
    1018:      *
    1019:      *      '-', '?', ':'
    1020:      *
    1021:      * if it is followed by a non-space character.
    1022:      *
    1023:      * The last rule is more restrictive than the specification requires.
    1024:      */

    1026:     if (!(IS_BLANKZ(parser->buffer) || CHECK(parser->buffer, '-')
    1027:                 || CHECK(parser->buffer, '?') || CHECK(parser->buffer, ':')
    1028:                 || CHECK(parser->buffer, ',') || CHECK(parser->buffer, '[')
    1029:                 || CHECK(parser->buffer, ']') || CHECK(parser->buffer, '{')
    1030:                 || CHECK(parser->buffer, '}') || CHECK(parser->buffer, '#')
    1031:                 || CHECK(parser->buffer, '&') || CHECK(parser->buffer, '*')
    1032:                 || CHECK(parser->buffer, '!') || CHECK(parser->buffer, '|')
    1033:                 || CHECK(parser->buffer, '>') || CHECK(parser->buffer, '\'')
    1034:                 || CHECK(parser->buffer, '"') || CHECK(parser->buffer, '%')
    1035:                 || CHECK(parser->buffer, '@') || CHECK(parser->buffer, '`')) ||
    1036:             (CHECK(parser->buffer, '-') && !IS_BLANK_AT(parser->buffer, 1)) ||
    1037:             (!parser->flow_level &&
    1038:              (CHECK(parser->buffer, '?') || CHECK(parser->buffer, ':'))
    1039:              && !IS_BLANKZ_AT(parser->buffer, 1)))
    1040:         return yaml_parser_fetch_plain_scalar(parser);

    1042:     /*
    1043:      * If we don't determine the token type so far, it is an error.
    1044:      */

    1046:     return yaml_parser_set_scanner_error(parser,
    1047:             "while scanning for the next token", parser->mark,
    1048:             "found character that cannot start any token");
    1049: }

    1051: /*
    1052:  * Check the list of potential simple keys and remove the positions that
    1053:  * cannot contain simple keys anymore.
    1054:  */

    1056: static int
    1057: yaml_parser_stale_simple_keys(yaml_parser_t *parser)
    1058: {
    1059:     yaml_simple_key_t *simple_key;

    1061:     /* Check for a potential simple key for each flow level. */

    1063:     for (simple_key = parser->simple_keys.start;
    1064:             simple_key != parser->simple_keys.top; simple_key ++)
    1065:     {
    1066:         /*
    1067:          * The specification requires that a simple key
    1068:          *
    1069:          *  - is limited to a single line,
    1070:          *  - is shorter than 1024 characters.
    1071:          */

    1073:         if (simple_key->possible
    1074:                 && (simple_key->mark.line < parser->mark.line
    1075:                     || simple_key->mark.index+1024 < parser->mark.index)) {

    1077:             /* Check if the potential simple key to be removed is required. */

    1079:             if (simple_key->required) {
    1080:                 return yaml_parser_set_scanner_error(parser,
    1081:                         "while scanning a simple key", simple_key->mark,
    1082:                         "could not find expected ':'");
    1083:             }

    1085:             simple_key->possible = 0;
    1086:         }
    1087:     }

    1089:     return 1;
    1090: }

    1092: /*
    1093:  * Check if a simple key may start at the current position and add it if
    1094:  * needed.
    1095:  */

    1097: static int
    1098: yaml_parser_save_simple_key(yaml_parser_t *parser)
    1099: {
    1100:     /*
    1101:      * A simple key is required at the current position if the scanner is in
    1102:      * the block context and the current column coincides with the indentation
    1103:      * level.
    1104:      */

    1106:     int required = (!parser->flow_level
    1107:             && parser->indent == (ptrdiff_t)parser->mark.column);

    1109:     /*
    1110:      * If the current position may start a simple key, save it.
    1111:      */

    1113:     if (parser->simple_key_allowed)
    1114:     {
    1115:         yaml_simple_key_t simple_key;
    1116:         simple_key.possible = 1;
    1117:         simple_key.required = required;
    1118:         simple_key.token_number =
    1119:             parser->tokens_parsed + (parser->tokens.tail - parser->tokens.head);
    1120:         simple_key.mark = parser->mark;

    1122:         if (!yaml_parser_remove_simple_key(parser)) return 0;

    1124:         *(parser->simple_keys.top-1) = simple_key;
    1125:     }

    1127:     return 1;
    1128: }

    1130: /*
    1131:  * Remove a potential simple key at the current flow level.
    1132:  */

    1134: static int
    1135: yaml_parser_remove_simple_key(yaml_parser_t *parser)
    1136: {
    1137:     yaml_simple_key_t *simple_key = parser->simple_keys.top-1;

    1139:     if (simple_key->possible)
    1140:     {
    1141:         /* If the key is required, it is an error. */

    1143:         if (simple_key->required) {
    1144:             return yaml_parser_set_scanner_error(parser,
    1145:                     "while scanning a simple key", simple_key->mark,
    1146:                     "could not find expected ':'");
    1147:         }
    1148:     }

    1150:     /* Remove the key from the stack. */

    1152:     simple_key->possible = 0;

    1154:     return 1;
    1155: }

    1157: /*
    1158:  * Increase the flow level and resize the simple key list if needed.
    1159:  */

    1161: static int
    1162: yaml_parser_increase_flow_level(yaml_parser_t *parser)
    1163: {
    1164:     yaml_simple_key_t empty_simple_key = { 0, 0, 0, { 0, 0, 0 } };

    1166:     /* Reset the simple key on the next level. */

    1168:     if (!PUSH(parser, parser->simple_keys, empty_simple_key))
    1169:         return 0;

    1171:     /* Increase the flow level. */

    1173:     if (parser->flow_level == INT_MAX) {
    1174:         parser->error = YAML_MEMORY_ERROR;
    1175:         return 0;
    1176:     }

    1178:     parser->flow_level++;

    1180:     return 1;
    1181: }

    1183: /*
    1184:  * Decrease the flow level.
    1185:  */

    1187: static int
    1188: yaml_parser_decrease_flow_level(yaml_parser_t *parser)
    1189: {
    1190:     if (parser->flow_level) {
    1191:         parser->flow_level --;
    1192:         (void)POP(parser, parser->simple_keys);
    1193:     }

    1195:     return 1;
    1196: }

    1198: /*
    1199:  * Push the current indentation level to the stack and set the new level
    1200:  * the current column is greater than the indentation level.  In this case,
    1201:  * append or insert the specified token into the token queue.
    1202:  *
    1203:  */

    1205: static int
    1206: yaml_parser_roll_indent(yaml_parser_t *parser, ptrdiff_t column,
    1207:         ptrdiff_t number, yaml_token_type_t type, yaml_mark_t mark)
    1208: {
    1209:     yaml_token_t token;

    1211:     /* In the flow context, do nothing. */

    1213:     if (parser->flow_level)
    1214:         return 1;

    1216:     if (parser->indent < column)
    1217:     {
    1218:         /*
    1219:          * Push the current indentation level to the stack and set the new
    1220:          * indentation level.
    1221:          */

    1223:         if (!PUSH(parser, parser->indents, parser->indent))
    1224:             return 0;

    1226:         if (column > INT_MAX) {
    1227:             parser->error = YAML_MEMORY_ERROR;
    1228:             return 0;
    1229:         }

    1231:         parser->indent = column;

    1233:         /* Create a token and insert it into the queue. */

    1235:         TOKEN_INIT(token, type, mark, mark);

    1237:         if (number == -1) {
    1238:             if (!ENQUEUE(parser, parser->tokens, token))
    1239:                 return 0;
    1240:         }
    1241:         else {
    1242:             if (!QUEUE_INSERT(parser,
    1243:                         parser->tokens, number - parser->tokens_parsed, token))
    1244:                 return 0;
    1245:         }
    1246:     }

    1248:     return 1;
    1249: }

    1251: /*
    1252:  * Pop indentation levels from the indents stack until the current level
    1253:  * becomes less or equal to the column.  For each indentation level, append
    1254:  * the BLOCK-END token.
    1255:  */

    1258: static int
    1259: yaml_parser_unroll_indent(yaml_parser_t *parser, ptrdiff_t column)
    1260: {
    1261:     yaml_token_t token;

    1263:     /* In the flow context, do nothing. */

    1265:     if (parser->flow_level)
    1266:         return 1;

    1268:     /* Loop through the indentation levels in the stack. */

    1270:     while (parser->indent > column)
    1271:     {
    1272:         /* Create a token and append it to the queue. */

    1274:         TOKEN_INIT(token, YAML_BLOCK_END_TOKEN, parser->mark, parser->mark);

    1276:         if (!ENQUEUE(parser, parser->tokens, token))
    1277:             return 0;

    1279:         /* Pop the indentation level. */

    1281:         parser->indent = POP(parser, parser->indents);
    1282:     }

    1284:     return 1;
    1285: }

    1287: /*
    1288:  * Initialize the scanner and produce the STREAM-START token.
    1289:  */

    1291: static int
    1292: yaml_parser_fetch_stream_start(yaml_parser_t *parser)
    1293: {
    1294:     yaml_simple_key_t simple_key = { 0, 0, 0, { 0, 0, 0 } };
    1295:     yaml_token_t token;

    1297:     /* Set the initial indentation. */

    1299:     parser->indent = -1;

    1301:     /* Initialize the simple key stack. */

    1303:     if (!PUSH(parser, parser->simple_keys, simple_key))
    1304:         return 0;

    1306:     /* A simple key is allowed at the beginning of the stream. */

    1308:     parser->simple_key_allowed = 1;

    1310:     /* We have started. */

    1312:     parser->stream_start_produced = 1;

    1314:     /* Create the STREAM-START token and append it to the queue. */

    1316:     STREAM_START_TOKEN_INIT(token, parser->encoding,
    1317:             parser->mark, parser->mark);

    1319:     if (!ENQUEUE(parser, parser->tokens, token))
    1320:         return 0;

    1322:     return 1;
    1323: }

    1325: /*
    1326:  * Produce the STREAM-END token and shut down the scanner.
    1327:  */

    1329: static int
    1330: yaml_parser_fetch_stream_end(yaml_parser_t *parser)
    1331: {
    1332:     yaml_token_t token;

    1334:     /* Force new line. */

    1336:     if (parser->mark.column != 0) {
    1337:         parser->mark.column = 0;
    1338:         parser->mark.line ++;
    1339:     }

    1341:     /* Reset the indentation level. */

    1343:     if (!yaml_parser_unroll_indent(parser, -1))
    1344:         return 0;

    1346:     /* Reset simple keys. */

    1348:     if (!yaml_parser_remove_simple_key(parser))
    1349:         return 0;

    1351:     parser->simple_key_allowed = 0;

    1353:     /* Create the STREAM-END token and append it to the queue. */

    1355:     STREAM_END_TOKEN_INIT(token, parser->mark, parser->mark);

    1357:     if (!ENQUEUE(parser, parser->tokens, token))
    1358:         return 0;

    1360:     return 1;
    1361: }

    1363: /*
    1364:  * Produce a VERSION-DIRECTIVE or TAG-DIRECTIVE token.
    1365:  */

    1367: static int
    1368: yaml_parser_fetch_directive(yaml_parser_t *parser)
    1369: {
    1370:     yaml_token_t token;

    1372:     /* Reset the indentation level. */

    1374:     if (!yaml_parser_unroll_indent(parser, -1))
    1375:         return 0;

    1377:     /* Reset simple keys. */

    1379:     if (!yaml_parser_remove_simple_key(parser))
    1380:         return 0;

    1382:     parser->simple_key_allowed = 0;

    1384:     /* Create the YAML-DIRECTIVE or TAG-DIRECTIVE token. */

    1386:     if (!yaml_parser_scan_directive(parser, &token))
    1387:         return 0;

    1389:     /* Append the token to the queue. */

    1391:     if (!ENQUEUE(parser, parser->tokens, token)) {
    1392:         yaml_token_delete(&token);
    1393:         return 0;
    1394:     }

    1396:     return 1;
    1397: }

    1399: /*
    1400:  * Produce the DOCUMENT-START or DOCUMENT-END token.
    1401:  */

    1403: static int
    1404: yaml_parser_fetch_document_indicator(yaml_parser_t *parser,
    1405:         yaml_token_type_t type)
    1406: {
    1407:     yaml_mark_t start_mark, end_mark;
    1408:     yaml_token_t token;

    1410:     /* Reset the indentation level. */

    1412:     if (!yaml_parser_unroll_indent(parser, -1))
    1413:         return 0;

    1415:     /* Reset simple keys. */

    1417:     if (!yaml_parser_remove_simple_key(parser))
    1418:         return 0;

    1420:     parser->simple_key_allowed = 0;

    1422:     /* Consume the token. */

    1424:     start_mark = parser->mark;

    1426:     SKIP(parser);
    1427:     SKIP(parser);
    1428:     SKIP(parser);

    1430:     end_mark = parser->mark;

    1432:     /* Create the DOCUMENT-START or DOCUMENT-END token. */

    1434:     TOKEN_INIT(token, type, start_mark, end_mark);

    1436:     /* Append the token to the queue. */

    1438:     if (!ENQUEUE(parser, parser->tokens, token))
    1439:         return 0;

    1441:     return 1;
    1442: }

    1444: /*
    1445:  * Produce the FLOW-SEQUENCE-START or FLOW-MAPPING-START token.
    1446:  */

    1448: static int
    1449: yaml_parser_fetch_flow_collection_start(yaml_parser_t *parser,
    1450:         yaml_token_type_t type)
    1451: {
    1452:     yaml_mark_t start_mark, end_mark;
    1453:     yaml_token_t token;

    1455:     /* The indicators '[' and '{' may start a simple key. */

    1457:     if (!yaml_parser_save_simple_key(parser))
    1458:         return 0;

    1460:     /* Increase the flow level. */

    1462:     if (!yaml_parser_increase_flow_level(parser))
    1463:         return 0;

    1465:     /* A simple key may follow the indicators '[' and '{'. */

    1467:     parser->simple_key_allowed = 1;

    1469:     /* Consume the token. */

    1471:     start_mark = parser->mark;
    1472:     SKIP(parser);
    1473:     end_mark = parser->mark;

    1475:     /* Create the FLOW-SEQUENCE-START of FLOW-MAPPING-START token. */

    1477:     TOKEN_INIT(token, type, start_mark, end_mark);

    1479:     /* Append the token to the queue. */

    1481:     if (!ENQUEUE(parser, parser->tokens, token))
    1482:         return 0;

    1484:     return 1;
    1485: }

    1487: /*
    1488:  * Produce the FLOW-SEQUENCE-END or FLOW-MAPPING-END token.
    1489:  */

    1491: static int
    1492: yaml_parser_fetch_flow_collection_end(yaml_parser_t *parser,
    1493:         yaml_token_type_t type)
    1494: {
    1495:     yaml_mark_t start_mark, end_mark;
    1496:     yaml_token_t token;

    1498:     /* Reset any potential simple key on the current flow level. */

    1500:     if (!yaml_parser_remove_simple_key(parser))
    1501:         return 0;

    1503:     /* Decrease the flow level. */

    1505:     if (!yaml_parser_decrease_flow_level(parser))
    1506:         return 0;

    1508:     /* No simple keys after the indicators ']' and '}'. */

    1510:     parser->simple_key_allowed = 0;

    1512:     /* Consume the token. */

    1514:     start_mark = parser->mark;
    1515:     SKIP(parser);
    1516:     end_mark = parser->mark;

    1518:     /* Create the FLOW-SEQUENCE-END of FLOW-MAPPING-END token. */

    1520:     TOKEN_INIT(token, type, start_mark, end_mark);

    1522:     /* Append the token to the queue. */

    1524:     if (!ENQUEUE(parser, parser->tokens, token))
    1525:         return 0;

    1527:     return 1;
    1528: }

    1530: /*
    1531:  * Produce the FLOW-ENTRY token.
    1532:  */

    1534: static int
    1535: yaml_parser_fetch_flow_entry(yaml_parser_t *parser)
    1536: {
    1537:     yaml_mark_t start_mark, end_mark;
    1538:     yaml_token_t token;

    1540:     /* Reset any potential simple keys on the current flow level. */

    1542:     if (!yaml_parser_remove_simple_key(parser))
    1543:         return 0;

    1545:     /* Simple keys are allowed after ','. */

    1547:     parser->simple_key_allowed = 1;

    1549:     /* Consume the token. */

    1551:     start_mark = parser->mark;
    1552:     SKIP(parser);
    1553:     end_mark = parser->mark;

    1555:     /* Create the FLOW-ENTRY token and append it to the queue. */

    1557:     TOKEN_INIT(token, YAML_FLOW_ENTRY_TOKEN, start_mark, end_mark);

    1559:     if (!ENQUEUE(parser, parser->tokens, token))
    1560:         return 0;

    1562:     return 1;
    1563: }

    1565: /*
    1566:  * Produce the BLOCK-ENTRY token.
    1567:  */

    1569: static int
    1570: yaml_parser_fetch_block_entry(yaml_parser_t *parser)
    1571: {
    1572:     yaml_mark_t start_mark, end_mark;
    1573:     yaml_token_t token;

    1575:     /* Check if the scanner is in the block context. */

    1577:     if (!parser->flow_level)
    1578:     {
    1579:         /* Check if we are allowed to start a new entry. */

    1581:         if (!parser->simple_key_allowed) {
    1582:             return yaml_parser_set_scanner_error(parser, NULL, parser->mark,
    1583:                     "block sequence entries are not allowed in this context");
    1584:         }

    1586:         /* Add the BLOCK-SEQUENCE-START token if needed. */

    1588:         if (!yaml_parser_roll_indent(parser, parser->mark.column, -1,
    1589:                     YAML_BLOCK_SEQUENCE_START_TOKEN, parser->mark))
    1590:             return 0;
    1591:     }
    1592:     else
    1593:     {
    1594:         /*
    1595:          * It is an error for the '-' indicator to occur in the flow context,
    1596:          * but we let the Parser detect and report about it because the Parser
    1597:          * is able to point to the context.
    1598:          */
    1599:     }

    1601:     /* Reset any potential simple keys on the current flow level. */

    1603:     if (!yaml_parser_remove_simple_key(parser))
    1604:         return 0;

    1606:     /* Simple keys are allowed after '-'. */

    1608:     parser->simple_key_allowed = 1;

    1610:     /* Consume the token. */

    1612:     start_mark = parser->mark;
    1613:     SKIP(parser);
    1614:     end_mark = parser->mark;

    1616:     /* Create the BLOCK-ENTRY token and append it to the queue. */

    1618:     TOKEN_INIT(token, YAML_BLOCK_ENTRY_TOKEN, start_mark, end_mark);

    1620:     if (!ENQUEUE(parser, parser->tokens, token))
    1621:         return 0;

    1623:     return 1;
    1624: }

    1626: /*
    1627:  * Produce the KEY token.
    1628:  */

    1630: static int
    1631: yaml_parser_fetch_key(yaml_parser_t *parser)
    1632: {
    1633:     yaml_mark_t start_mark, end_mark;
    1634:     yaml_token_t token;

    1636:     /* In the block context, additional checks are required. */

    1638:     if (!parser->flow_level)
    1639:     {
    1640:         /* Check if we are allowed to start a new key (not necessary simple). */

    1642:         if (!parser->simple_key_allowed) {
    1643:             return yaml_parser_set_scanner_error(parser, NULL, parser->mark,
    1644:                     "mapping keys are not allowed in this context");
    1645:         }

    1647:         /* Add the BLOCK-MAPPING-START token if needed. */

    1649:         if (!yaml_parser_roll_indent(parser, parser->mark.column, -1,
    1650:                     YAML_BLOCK_MAPPING_START_TOKEN, parser->mark))
    1651:             return 0;
    1652:     }

    1654:     /* Reset any potential simple keys on the current flow level. */

    1656:     if (!yaml_parser_remove_simple_key(parser))
    1657:         return 0;

    1659:     /* Simple keys are allowed after '?' in the block context. */

    1661:     parser->simple_key_allowed = (!parser->flow_level);

    1663:     /* Consume the token. */

    1665:     start_mark = parser->mark;
    1666:     SKIP(parser);
    1667:     end_mark = parser->mark;

    1669:     /* Create the KEY token and append it to the queue. */

    1671:     TOKEN_INIT(token, YAML_KEY_TOKEN, start_mark, end_mark);

    1673:     if (!ENQUEUE(parser, parser->tokens, token))
    1674:         return 0;

    1676:     return 1;
    1677: }

    1679: /*
    1680:  * Produce the VALUE token.
    1681:  */

    1683: static int
    1684: yaml_parser_fetch_value(yaml_parser_t *parser)
    1685: {
    1686:     yaml_mark_t start_mark, end_mark;
    1687:     yaml_token_t token;
    1688:     yaml_simple_key_t *simple_key = parser->simple_keys.top-1;

    1690:     /* Have we found a simple key? */

    1692:     if (simple_key->possible)
    1693:     {

    1695:         /* Create the KEY token and insert it into the queue. */

    1697:         TOKEN_INIT(token, YAML_KEY_TOKEN, simple_key->mark, simple_key->mark);

    1699:         if (!QUEUE_INSERT(parser, parser->tokens,
    1700:                     simple_key->token_number - parser->tokens_parsed, token))
    1701:             return 0;

    1703:         /* In the block context, we may need to add the BLOCK-MAPPING-START token. */

    1705:         if (!yaml_parser_roll_indent(parser, simple_key->mark.column,
    1706:                     simple_key->token_number,
    1707:                     YAML_BLOCK_MAPPING_START_TOKEN, simple_key->mark))
    1708:             return 0;

    1710:         /* Remove the simple key. */

    1712:         simple_key->possible = 0;

    1714:         /* A simple key cannot follow another simple key. */

    1716:         parser->simple_key_allowed = 0;
    1717:     }
    1718:     else
    1719:     {
    1720:         /* The ':' indicator follows a complex key. */

    1722:         /* In the block context, extra checks are required. */

    1724:         if (!parser->flow_level)
    1725:         {
    1726:             /* Check if we are allowed to start a complex value. */

    1728:             if (!parser->simple_key_allowed) {
    1729:                 return yaml_parser_set_scanner_error(parser, NULL, parser->mark,
    1730:                         "mapping values are not allowed in this context");
    1731:             }

    1733:             /* Add the BLOCK-MAPPING-START token if needed. */

    1735:             if (!yaml_parser_roll_indent(parser, parser->mark.column, -1,
    1736:                         YAML_BLOCK_MAPPING_START_TOKEN, parser->mark))
    1737:                 return 0;
    1738:         }

    1740:         /* Simple keys after ':' are allowed in the block context. */

    1742:         parser->simple_key_allowed = (!parser->flow_level);
    1743:     }

    1745:     /* Consume the token. */

    1747:     start_mark = parser->mark;
    1748:     SKIP(parser);
    1749:     end_mark = parser->mark;

    1751:     /* Create the VALUE token and append it to the queue. */

    1753:     TOKEN_INIT(token, YAML_VALUE_TOKEN, start_mark, end_mark);

    1755:     if (!ENQUEUE(parser, parser->tokens, token))
    1756:         return 0;

    1758:     return 1;
    1759: }

    1761: /*
    1762:  * Produce the ALIAS or ANCHOR token.
    1763:  */

    1765: static int
    1766: yaml_parser_fetch_anchor(yaml_parser_t *parser, yaml_token_type_t type)
    1767: {
    1768:     yaml_token_t token;

    1770:     /* An anchor or an alias could be a simple key. */

    1772:     if (!yaml_parser_save_simple_key(parser))
    1773:         return 0;

    1775:     /* A simple key cannot follow an anchor or an alias. */

    1777:     parser->simple_key_allowed = 0;

    1779:     /* Create the ALIAS or ANCHOR token and append it to the queue. */

    1781:     if (!yaml_parser_scan_anchor(parser, &token, type))
    1782:         return 0;

    1784:     if (!ENQUEUE(parser, parser->tokens, token)) {
    1785:         yaml_token_delete(&token);
    1786:         return 0;
    1787:     }
    1788:     return 1;
    1789: }

    1791: /*
    1792:  * Produce the TAG token.
    1793:  */

    1795: static int
    1796: yaml_parser_fetch_tag(yaml_parser_t *parser)
    1797: {
    1798:     yaml_token_t token;

    1800:     /* A tag could be a simple key. */

    1802:     if (!yaml_parser_save_simple_key(parser))
    1803:         return 0;

    1805:     /* A simple key cannot follow a tag. */

    1807:     parser->simple_key_allowed = 0;

    1809:     /* Create the TAG token and append it to the queue. */

    1811:     if (!yaml_parser_scan_tag(parser, &token))
    1812:         return 0;

    1814:     if (!ENQUEUE(parser, parser->tokens, token)) {
    1815:         yaml_token_delete(&token);
    1816:         return 0;
    1817:     }

    1819:     return 1;
    1820: }

    1822: /*
    1823:  * Produce the SCALAR(...,literal) or SCALAR(...,folded) tokens.
    1824:  */

    1826: static int
    1827: yaml_parser_fetch_block_scalar(yaml_parser_t *parser, int literal)
    1828: {
    1829:     yaml_token_t token;

    1831:     /* Remove any potential simple keys. */

    1833:     if (!yaml_parser_remove_simple_key(parser))
    1834:         return 0;

    1836:     /* A simple key may follow a block scalar. */

    1838:     parser->simple_key_allowed = 1;

    1840:     /* Create the SCALAR token and append it to the queue. */

    1842:     if (!yaml_parser_scan_block_scalar(parser, &token, literal))
    1843:         return 0;

    1845:     if (!ENQUEUE(parser, parser->tokens, token)) {
    1846:         yaml_token_delete(&token);
    1847:         return 0;
    1848:     }

    1850:     return 1;
    1851: }

    1853: /*
    1854:  * Produce the SCALAR(...,single-quoted) or SCALAR(...,double-quoted) tokens.
    1855:  */

    1857: static int
    1858: yaml_parser_fetch_flow_scalar(yaml_parser_t *parser, int single)
    1859: {
    1860:     yaml_token_t token;

    1862:     /* A plain scalar could be a simple key. */

    1864:     if (!yaml_parser_save_simple_key(parser))
    1865:         return 0;

    1867:     /* A simple key cannot follow a flow scalar. */

    1869:     parser->simple_key_allowed = 0;

    1871:     /* Create the SCALAR token and append it to the queue. */

    1873:     if (!yaml_parser_scan_flow_scalar(parser, &token, single))
    1874:         return 0;

    1876:     if (!ENQUEUE(parser, parser->tokens, token)) {
    1877:         yaml_token_delete(&token);
    1878:         return 0;
    1879:     }

    1881:     return 1;
    1882: }

    1884: /*
    1885:  * Produce the SCALAR(...,plain) token.
    1886:  */

    1888: static int
    1889: yaml_parser_fetch_plain_scalar(yaml_parser_t *parser)
    1890: {
    1891:     yaml_token_t token;

    1893:     /* A plain scalar could be a simple key. */

    1895:     if (!yaml_parser_save_simple_key(parser))
    1896:         return 0;

    1898:     /* A simple key cannot follow a flow scalar. */

    1900:     parser->simple_key_allowed = 0;

    1902:     /* Create the SCALAR token and append it to the queue. */

    1904:     if (!yaml_parser_scan_plain_scalar(parser, &token))
    1905:         return 0;

    1907:     if (!ENQUEUE(parser, parser->tokens, token)) {
    1908:         yaml_token_delete(&token);
    1909:         return 0;
    1910:     }

    1912:     return 1;
    1913: }

    1915: /*
    1916:  * Eat whitespaces and comments until the next token is found.
    1917:  */

    1919: static int
    1920: yaml_parser_scan_to_next_token(yaml_parser_t *parser)
    1921: {
    1922:     /* Until the next token is not found. */

    1924:     while (1)
    1925:     {
    1926:         /* Allow the BOM mark to start a line. */

    1928:         if (!CACHE(parser, 1)) return 0;

    1930:         if (parser->mark.column == 0 && IS_BOM(parser->buffer))
    1931:             SKIP(parser);

    1933:         /*
    1934:          * Eat whitespaces.
    1935:          *
    1936:          * Tabs are allowed:
    1937:          *
    1938:          *  - in the flow context;
    1939:          *  - in the block context, but not at the beginning of the line or
    1940:          *  after '-', '?', or ':' (complex value).
    1941:          */

    1943:         if (!CACHE(parser, 1)) return 0;

    1945:         while (CHECK(parser->buffer,' ') ||
    1946:                 ((parser->flow_level || !parser->simple_key_allowed) &&
    1947:                  CHECK(parser->buffer, '\t'))) {
    1948:             SKIP(parser);
    1949:             if (!CACHE(parser, 1)) return 0;
    1950:         }

    1952:         /* Eat a comment until a line break. */

    1954:         if (CHECK(parser->buffer, '#')) {
    1955:             while (!IS_BREAKZ(parser->buffer)) {
    1956:                 SKIP(parser);
    1957:                 if (!CACHE(parser, 1)) return 0;
    1958:             }
    1959:         }

    1961:         /* If it is a line break, eat it. */

    1963:         if (IS_BREAK(parser->buffer))
    1964:         {
    1965:             if (!CACHE(parser, 2)) return 0;
    1966:             SKIP_LINE(parser);

    1968:             /* In the block context, a new line may start a simple key. */

    1970:             if (!parser->flow_level) {
    1971:                 parser->simple_key_allowed = 1;
    1972:             }
    1973:         }
    1974:         else
    1975:         {
    1976:             /* We have found a token. */

    1978:             break;
    1979:         }
    1980:     }

    1982:     return 1;
    1983: }

    1985: /*
    1986:  * Scan a YAML-DIRECTIVE or TAG-DIRECTIVE token.
    1987:  *
    1988:  * Scope:
    1989:  *      %YAML    1.1    # a comment \n
    1990:  *      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    1991:  *      %TAG    !yaml!  tag:yaml.org,2002:  \n
    1992:  *      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    1993:  */

    1995: int
    1996: yaml_parser_scan_directive(yaml_parser_t *parser, yaml_token_t *token)
    1997: {
    1998:     yaml_mark_t start_mark, end_mark;
    1999:     yaml_char_t *name = NULL;
    2000:     int major, minor;
    2001:     yaml_char_t *handle = NULL, *prefix = NULL;

    2003:     /* Eat '%'. */

    2005:     start_mark = parser->mark;

    2007:     SKIP(parser);

    2009:     /* Scan the directive name. */

    2011:     if (!yaml_parser_scan_directive_name(parser, start_mark, &name))
    2012:         goto error;

    2014:     /* Is it a YAML directive? */

    2016:     if (strcmp((char *)name, "YAML") == 0)
    2017:     {
    2018:         /* Scan the VERSION directive value. */

    2020:         if (!yaml_parser_scan_version_directive_value(parser, start_mark,
    2021:                     &major, &minor))
    2022:             goto error;

    2024:         end_mark = parser->mark;

    2026:         /* Create a VERSION-DIRECTIVE token. */

    2028:         VERSION_DIRECTIVE_TOKEN_INIT(*token, major, minor,
    2029:                 start_mark, end_mark);
    2030:     }

    2032:     /* Is it a TAG directive? */

    2034:     else if (strcmp((char *)name, "TAG") == 0)
    2035:     {
    2036:         /* Scan the TAG directive value. */

    2038:         if (!yaml_parser_scan_tag_directive_value(parser, start_mark,
    2039:                     &handle, &prefix))
    2040:             goto error;

    2042:         end_mark = parser->mark;

    2044:         /* Create a TAG-DIRECTIVE token. */

    2046:         TAG_DIRECTIVE_TOKEN_INIT(*token, handle, prefix,
    2047:                 start_mark, end_mark);
    2048:     }

    2050:     /* Unknown directive. */

    2052:     else
    2053:     {
    2054:         yaml_parser_set_scanner_error(parser, "while scanning a directive",
    2055:                 start_mark, "found unknown directive name");
    2056:         goto error;
    2057:     }

    2059:     /* Eat the rest of the line including any comments. */

    2061:     if (!CACHE(parser, 1)) goto error;

    2063:     while (IS_BLANK(parser->buffer)) {
    2064:         SKIP(parser);
    2065:         if (!CACHE(parser, 1)) goto error;
    2066:     }

    2068:     if (CHECK(parser->buffer, '#')) {
    2069:         while (!IS_BREAKZ(parser->buffer)) {
    2070:             SKIP(parser);
    2071:             if (!CACHE(parser, 1)) goto error;
    2072:         }
    2073:     }

    2075:     /* Check if we are at the end of the line. */

    2077:     if (!IS_BREAKZ(parser->buffer)) {
    2078:         yaml_parser_set_scanner_error(parser, "while scanning a directive",
    2079:                 start_mark, "did not find expected comment or line break");
    2080:         goto error;
    2081:     }

    2083:     /* Eat a line break. */

    2085:     if (IS_BREAK(parser->buffer)) {
    2086:         if (!CACHE(parser, 2)) goto error;
    2087:         SKIP_LINE(parser);
    2088:     }

    2090:     yaml_free(name);

    2092:     return 1;

    2094: error:
    2095:     yaml_free(prefix);
    2096:     yaml_free(handle);
    2097:     yaml_free(name);
    2098:     return 0;
    2099: }

    2101: /*
    2102:  * Scan the directive name.
    2103:  *
    2104:  * Scope:
    2105:  *      %YAML   1.1     # a comment \n
    2106:  *       ^^^^
    2107:  *      %TAG    !yaml!  tag:yaml.org,2002:  \n
    2108:  *       ^^^
    2109:  */

    2111: static int
    2112: yaml_parser_scan_directive_name(yaml_parser_t *parser,
    2113:         yaml_mark_t start_mark, yaml_char_t **name)
    2114: {
    2115:     yaml_string_t string = NULL_STRING;

    2117:     if (!STRING_INIT(parser, string, INITIAL_STRING_SIZE)) goto error;

    2119:     /* Consume the directive name. */

    2121:     if (!CACHE(parser, 1)) goto error;

    2123:     while (IS_ALPHA(parser->buffer))
    2124:     {
    2125:         if (!READ(parser, string)) goto error;
    2126:         if (!CACHE(parser, 1)) goto error;
    2127:     }

    2129:     /* Check if the name is empty. */

    2131:     if (string.start == string.pointer) {
    2132:         yaml_parser_set_scanner_error(parser, "while scanning a directive",
    2133:                 start_mark, "could not find expected directive name");
    2134:         goto error;
    2135:     }

    2137:     /* Check for an blank character after the name. */

    2139:     if (!IS_BLANKZ(parser->buffer)) {
    2140:         yaml_parser_set_scanner_error(parser, "while scanning a directive",
    2141:                 start_mark, "found unexpected non-alphabetical character");
    2142:         goto error;
    2143:     }

    2145:     *name = string.start;

    2147:     return 1;

    2149: error:
    2150:     STRING_DEL(parser, string);
    2151:     return 0;
    2152: }

    2154: /*
    2155:  * Scan the value of VERSION-DIRECTIVE.
    2156:  *
    2157:  * Scope:
    2158:  *      %YAML   1.1     # a comment \n
    2159:  *           ^^^^^^
    2160:  */

    2162: static int
    2163: yaml_parser_scan_version_directive_value(yaml_parser_t *parser,
    2164:         yaml_mark_t start_mark, int *major, int *minor)
    2165: {
    2166:     /* Eat whitespaces. */

    2168:     if (!CACHE(parser, 1)) return 0;

    2170:     while (IS_BLANK(parser->buffer)) {
    2171:         SKIP(parser);
    2172:         if (!CACHE(parser, 1)) return 0;
    2173:     }

    2175:     /* Consume the major version number. */

    2177:     if (!yaml_parser_scan_version_directive_number(parser, start_mark, major))
    2178:         return 0;

    2180:     /* Eat '.'. */

    2182:     if (!CHECK(parser->buffer, '.')) {
    2183:         return yaml_parser_set_scanner_error(parser, "while scanning a %YAML directive",
    2184:                 start_mark, "did not find expected digit or '.' character");
    2185:     }

    2187:     SKIP(parser);

    2189:     /* Consume the minor version number. */

    2191:     if (!yaml_parser_scan_version_directive_number(parser, start_mark, minor))
    2192:         return 0;

    2194:     return 1;
    2195: }

    2197: #define MAX_NUMBER_LENGTH   9

    2199: /*
    2200:  * Scan the version number of VERSION-DIRECTIVE.
    2201:  *
    2202:  * Scope:
    2203:  *      %YAML   1.1     # a comment \n
    2204:  *              ^
    2205:  *      %YAML   1.1     # a comment \n
    2206:  *                ^
    2207:  */

    2209: static int
    2210: yaml_parser_scan_version_directive_number(yaml_parser_t *parser,
    2211:         yaml_mark_t start_mark, int *number)
    2212: {
    2213:     int value = 0;
    2214:     size_t length = 0;

    2216:     /* Repeat while the next character is digit. */

    2218:     if (!CACHE(parser, 1)) return 0;

    2220:     while (IS_DIGIT(parser->buffer))
    2221:     {
    2222:         /* Check if the number is too long. */

    2224:         if (++length > MAX_NUMBER_LENGTH) {
    2225:             return yaml_parser_set_scanner_error(parser, "while scanning a %YAML directive",
    2226:                     start_mark, "found extremely long version number");
    2227:         }

    2229:         value = value*10 + AS_DIGIT(parser->buffer);

    2231:         SKIP(parser);

    2233:         if (!CACHE(parser, 1)) return 0;
    2234:     }

    2236:     /* Check if the number was present. */

    2238:     if (!length) {
    2239:         return yaml_parser_set_scanner_error(parser, "while scanning a %YAML directive",
    2240:                 start_mark, "did not find expected version number");
    2241:     }

    2243:     *number = value;

    2245:     return 1;
    2246: }

    2248: /*
    2249:  * Scan the value of a TAG-DIRECTIVE token.
    2250:  *
    2251:  * Scope:
    2252:  *      %TAG    !yaml!  tag:yaml.org,2002:  \n
    2253:  *          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    2254:  */

    2256: static int
    2257: yaml_parser_scan_tag_directive_value(yaml_parser_t *parser,
    2258:         yaml_mark_t start_mark, yaml_char_t **handle, yaml_char_t **prefix)
    2259: {
    2260:     yaml_char_t *handle_value = NULL;
    2261:     yaml_char_t *prefix_value = NULL;

    2263:     /* Eat whitespaces. */

    2265:     if (!CACHE(parser, 1)) goto error;

    2267:     while (IS_BLANK(parser->buffer)) {
    2268:         SKIP(parser);
    2269:         if (!CACHE(parser, 1)) goto error;
    2270:     }

    2272:     /* Scan a handle. */

    2274:     if (!yaml_parser_scan_tag_handle(parser, 1, start_mark, &handle_value))
    2275:         goto error;

    2277:     /* Expect a whitespace. */

    2279:     if (!CACHE(parser, 1)) goto error;

    2281:     if (!IS_BLANK(parser->buffer)) {
    2282:         yaml_parser_set_scanner_error(parser, "while scanning a %TAG directive",
    2283:                 start_mark, "did not find expected whitespace");
    2284:         goto error;
    2285:     }

    2287:     /* Eat whitespaces. */

    2289:     while (IS_BLANK(parser->buffer)) {
    2290:         SKIP(parser);
    2291:         if (!CACHE(parser, 1)) goto error;
    2292:     }

    2294:     /* Scan a prefix. */

    2296:     if (!yaml_parser_scan_tag_uri(parser, 1, 1, NULL, start_mark, &prefix_value))
    2297:         goto error;

    2299:     /* Expect a whitespace or line break. */

    2301:     if (!CACHE(parser, 1)) goto error;

    2303:     if (!IS_BLANKZ(parser->buffer)) {
    2304:         yaml_parser_set_scanner_error(parser, "while scanning a %TAG directive",
    2305:                 start_mark, "did not find expected whitespace or line break");
    2306:         goto error;
    2307:     }

    2309:     *handle = handle_value;
    2310:     *prefix = prefix_value;

    2312:     return 1;

    2314: error:
    2315:     yaml_free(handle_value);
    2316:     yaml_free(prefix_value);
    2317:     return 0;
    2318: }

    2320: static int
    2321: yaml_parser_scan_anchor(yaml_parser_t *parser, yaml_token_t *token,
    2322:         yaml_token_type_t type)
    2323: {
    2324:     int length = 0;
    2325:     yaml_mark_t start_mark, end_mark;
    2326:     yaml_string_t string = NULL_STRING;

    2328:     if (!STRING_INIT(parser, string, INITIAL_STRING_SIZE)) goto error;

    2330:     /* Eat the indicator character. */

    2332:     start_mark = parser->mark;

    2334:     SKIP(parser);

    2336:     /* Consume the value. */

    2338:     if (!CACHE(parser, 1)) goto error;

    2340:     while (IS_ALPHA(parser->buffer)) {
    2341:         if (!READ(parser, string)) goto error;
    2342:         if (!CACHE(parser, 1)) goto error;
    2343:         length ++;
    2344:     }

    2346:     end_mark = parser->mark;

    2348:     /*
    2349:      * Check if length of the anchor is greater than 0 and it is followed by
    2350:      * a whitespace character or one of the indicators:
    2351:      *
    2352:      *      '?', ':', ',', ']', '}', '%', '@', '`'.
    2353:      */

    2355:     if (!length || !(IS_BLANKZ(parser->buffer) || CHECK(parser->buffer, '?')
    2356:                 || CHECK(parser->buffer, ':') || CHECK(parser->buffer, ',')
    2357:                 || CHECK(parser->buffer, ']') || CHECK(parser->buffer, '}')
    2358:                 || CHECK(parser->buffer, '%') || CHECK(parser->buffer, '@')
    2359:                 || CHECK(parser->buffer, '`'))) {
    2360:         yaml_parser_set_scanner_error(parser, type == YAML_ANCHOR_TOKEN ?
    2361:                 "while scanning an anchor" : "while scanning an alias", start_mark,
    2362:                 "did not find expected alphabetic or numeric character");
    2363:         goto error;
    2364:     }

    2366:     /* Create a token. */

    2368:     if (type == YAML_ANCHOR_TOKEN) {
    2369:         ANCHOR_TOKEN_INIT(*token, string.start, start_mark, end_mark);
    2370:     }
    2371:     else {
    2372:         ALIAS_TOKEN_INIT(*token, string.start, start_mark, end_mark);
    2373:     }

    2375:     return 1;

    2377: error:
    2378:     STRING_DEL(parser, string);
    2379:     return 0;
    2380: }

    2382: /*
    2383:  * Scan a TAG token.
    2384:  */

    2386: static int
    2387: yaml_parser_scan_tag(yaml_parser_t *parser, yaml_token_t *token)
    2388: {
    2389:     yaml_char_t *handle = NULL;
    2390:     yaml_char_t *suffix = NULL;
    2391:     yaml_mark_t start_mark, end_mark;

    2393:     start_mark = parser->mark;

    2395:     /* Check if the tag is in the canonical form. */

    2397:     if (!CACHE(parser, 2)) goto error;

    2399:     if (CHECK_AT(parser->buffer, '<', 1))
    2400:     {
    2401:         /* Set the handle to '' */

    2403:         handle = YAML_MALLOC(1);
    2404:         if (!handle) goto error;
    2405:         handle[0] = '\0';

    2407:         /* Eat '!<' */

    2409:         SKIP(parser);
    2410:         SKIP(parser);

    2412:         /* Consume the tag value. */

    2414:         if (!yaml_parser_scan_tag_uri(parser, 1, 0, NULL, start_mark, &suffix))
    2415:             goto error;

    2417:         /* Check for '>' and eat it. */

    2419:         if (!CHECK(parser->buffer, '>')) {
    2420:             yaml_parser_set_scanner_error(parser, "while scanning a tag",
    2421:                     start_mark, "did not find the expected '>'");
    2422:             goto error;
    2423:         }

    2425:         SKIP(parser);
    2426:     }
    2427:     else
    2428:     {
    2429:         /* The tag has either the '!suffix' or the '!handle!suffix' form. */

    2431:         /* First, try to scan a handle. */

    2433:         if (!yaml_parser_scan_tag_handle(parser, 0, start_mark, &handle))
    2434:             goto error;

    2436:         /* Check if it is, indeed, handle. */

    2438:         if (handle[0] == '!' && handle[1] != '\0' && handle[strlen((char *)handle)-1] == '!')
    2439:         {
    2440:             /* Scan the suffix now. */

    2442:             if (!yaml_parser_scan_tag_uri(parser, 0, 0, NULL, start_mark, &suffix))
    2443:                 goto error;
    2444:         }
    2445:         else
    2446:         {
    2447:             /* It wasn't a handle after all.  Scan the rest of the tag. */

    2449:             if (!yaml_parser_scan_tag_uri(parser, 0, 0, handle, start_mark, &suffix))
    2450:                 goto error;

    2452:             /* Set the handle to '!'. */

    2454:             yaml_free(handle);
    2455:             handle = YAML_MALLOC(2);
    2456:             if (!handle) goto error;
    2457:             handle[0] = '!';
    2458:             handle[1] = '\0';

    2460:             /*
    2461:              * A special case: the '!' tag.  Set the handle to '' and the
    2462:              * suffix to '!'.
    2463:              */

    2465:             if (suffix[0] == '\0') {
    2466:                 yaml_char_t *tmp = handle;
    2467:                 handle = suffix;
    2468:                 suffix = tmp;
    2469:             }
    2470:         }
    2471:     }

    2473:     /* Check the character which ends the tag. */

    2475:     if (!CACHE(parser, 1)) goto error;

    2477:     if (!IS_BLANKZ(parser->buffer)) {
    2478:         if (!parser->flow_level || !CHECK(parser->buffer, ',') ) {
    2479:             yaml_parser_set_scanner_error(parser, "while scanning a tag",
    2480:                     start_mark, "did not find expected whitespace or line break");
    2481:             goto error;
    2482:         }
    2483:     }

    2485:     end_mark = parser->mark;

    2487:     /* Create a token. */

    2489:     TAG_TOKEN_INIT(*token, handle, suffix, start_mark, end_mark);

    2491:     return 1;

    2493: error:
    2494:     yaml_free(handle);
    2495:     yaml_free(suffix);
    2496:     return 0;
    2497: }

    2499: /*
    2500:  * Scan a tag handle.
    2501:  */

    2503: static int
    2504: yaml_parser_scan_tag_handle(yaml_parser_t *parser, int directive,
    2505:         yaml_mark_t start_mark, yaml_char_t **handle)
    2506: {
    2507:     yaml_string_t string = NULL_STRING;

    2509:     if (!STRING_INIT(parser, string, INITIAL_STRING_SIZE)) goto error;

    2511:     /* Check the initial '!' character. */

    2513:     if (!CACHE(parser, 1)) goto error;

    2515:     if (!CHECK(parser->buffer, '!')) {
    2516:         yaml_parser_set_scanner_error(parser, directive ?
    2517:                 "while scanning a tag directive" : "while scanning a tag",
    2518:                 start_mark, "did not find expected '!'");
    2519:         goto error;
    2520:     }

    2522:     /* Copy the '!' character. */

    2524:     if (!READ(parser, string)) goto error;

    2526:     /* Copy all subsequent alphabetical and numerical characters. */

    2528:     if (!CACHE(parser, 1)) goto error;

    2530:     while (IS_ALPHA(parser->buffer))
    2531:     {
    2532:         if (!READ(parser, string)) goto error;
    2533:         if (!CACHE(parser, 1)) goto error;
    2534:     }

    2536:     /* Check if the trailing character is '!' and copy it. */

    2538:     if (CHECK(parser->buffer, '!'))
    2539:     {
    2540:         if (!READ(parser, string)) goto error;
    2541:     }
    2542:     else
    2543:     {
    2544:         /*
    2545:          * It's either the '!' tag or not really a tag handle.  If it's a %TAG
    2546:          * directive, it's an error.  If it's a tag token, it must be a part of
    2547:          * URI.
    2548:          */

    2550:         if (directive && !(string.start[0] == '!' && string.start[1] == '\0')) {
    2551:             yaml_parser_set_scanner_error(parser, "while parsing a tag directive",
    2552:                     start_mark, "did not find expected '!'");
    2553:             goto error;
    2554:         }
    2555:     }

    2557:     *handle = string.start;

    2559:     return 1;

    2561: error:
    2562:     STRING_DEL(parser, string);
    2563:     return 0;
    2564: }

    2566: /*
    2567:  * Scan a tag.
    2568:  */

    2570: static int
    2571: yaml_parser_scan_tag_uri(yaml_parser_t *parser, int uri_char, int directive,
    2572:         yaml_char_t *head, yaml_mark_t start_mark, yaml_char_t **uri)
    2573: {
    2574:     size_t length = head ? strlen((char *)head) : 0;
    2575:     yaml_string_t string = NULL_STRING;

    2577:     if (!STRING_INIT(parser, string, INITIAL_STRING_SIZE)) goto error;

    2579:     /* Resize the string to include the head. */

    2581:     while ((size_t)(string.end - string.start) <= length) {
    2582:         if (!yaml_string_extend(&string.start, &string.pointer, &string.end)) {
    2583:             parser->error = YAML_MEMORY_ERROR;
    2584:             goto error;
    2585:         }
    2586:     }

    2588:     /*
    2589:      * Copy the head if needed.
    2590:      *
    2591:      * Note that we don't copy the leading '!' character.
    2592:      */

    2594:     if (length > 1) {
    2595:         memcpy(string.start, head+1, length-1);
    2596:         string.pointer += length-1;
    2597:     }

    2599:     /* Scan the tag. */

    2601:     if (!CACHE(parser, 1)) goto error;

    2603:     /*
    2604:      * The set of characters that may appear in URI is as follows:
    2605:      *
    2606:      *      '0'-'9', 'A'-'Z', 'a'-'z', '_', '-', ';', '/', '?', ':', '@', '&',
    2607:      *      '=', '+', '$', '.', '!', '~', '*', '\'', '(', ')', '%'.
    2608:      *
    2609:      * If we are inside a verbatim tag <...> (parameter uri_char is true)
    2610:      * then also the following flow indicators are allowed:
    2611:      *      ',', '[', ']'
    2612:      */

    2614:     while (IS_ALPHA(parser->buffer) || CHECK(parser->buffer, ';')
    2615:             || CHECK(parser->buffer, '/') || CHECK(parser->buffer, '?')
    2616:             || CHECK(parser->buffer, ':') || CHECK(parser->buffer, '@')
    2617:             || CHECK(parser->buffer, '&') || CHECK(parser->buffer, '=')
    2618:             || CHECK(parser->buffer, '+') || CHECK(parser->buffer, '$')
    2619:             || CHECK(parser->buffer, '.') || CHECK(parser->buffer, '%')
    2620:             || CHECK(parser->buffer, '!') || CHECK(parser->buffer, '~')
    2621:             || CHECK(parser->buffer, '*') || CHECK(parser->buffer, '\'')
    2622:             || CHECK(parser->buffer, '(') || CHECK(parser->buffer, ')')
    2623:             || (uri_char && (
    2624:                 CHECK(parser->buffer, ',')
    2625:                 || CHECK(parser->buffer, '[') || CHECK(parser->buffer, ']')
    2626:                 )
    2627:             ))
    2628:     {
    2629:         /* Check if it is a URI-escape sequence. */

    2631:         if (CHECK(parser->buffer, '%')) {
    2632:             if (!STRING_EXTEND(parser, string))
    2633:                 goto error;

    2635:             if (!yaml_parser_scan_uri_escapes(parser,
    2636:                         directive, start_mark, &string)) goto error;
    2637:         }
    2638:         else {
    2639:             if (!READ(parser, string)) goto error;
    2640:         }

    2642:         length ++;
    2643:         if (!CACHE(parser, 1)) goto error;
    2644:     }

    2646:     /* Check if the tag is non-empty. */

    2648:     if (!length) {
    2649:         if (!STRING_EXTEND(parser, string))
    2650:             goto error;

    2652:         yaml_parser_set_scanner_error(parser, directive ?
    2653:                 "while parsing a %TAG directive" : "while parsing a tag",
    2654:                 start_mark, "did not find expected tag URI");
    2655:         goto error;
    2656:     }

    2658:     *uri = string.start;

    2660:     return 1;

    2662: error:
    2663:     STRING_DEL(parser, string);
    2664:     return 0;
    2665: }

    2667: /*
    2668:  * Decode an URI-escape sequence corresponding to a single UTF-8 character.
    2669:  */

    2671: static int
    2672: yaml_parser_scan_uri_escapes(yaml_parser_t *parser, int directive,
    2673:         yaml_mark_t start_mark, yaml_string_t *string)
    2674: {
    2675:     int width = 0;

    2677:     /* Decode the required number of characters. */

    2679:     do {

    2681:         unsigned char octet = 0;

    2683:         /* Check for a URI-escaped octet. */

    2685:         if (!CACHE(parser, 3)) return 0;

    2687:         if (!(CHECK(parser->buffer, '%')
    2688:                     && IS_HEX_AT(parser->buffer, 1)
    2689:                     && IS_HEX_AT(parser->buffer, 2))) {
    2690:             return yaml_parser_set_scanner_error(parser, directive ?
    2691:                     "while parsing a %TAG directive" : "while parsing a tag",
    2692:                     start_mark, "did not find URI escaped octet");
    2693:         }

    2695:         /* Get the octet. */

    2697:         octet = (AS_HEX_AT(parser->buffer, 1) << 4) + AS_HEX_AT(parser->buffer, 2);

    2699:         /* If it is the leading octet, determine the length of the UTF-8 sequence. */

    2701:         if (!width)
    2702:         {
    2703:             width = (octet & 0x80) == 0x00 ? 1 :
    2704:                     (octet & 0xE0) == 0xC0 ? 2 :
    2705:                     (octet & 0xF0) == 0xE0 ? 3 :
    2706:                     (octet & 0xF8) == 0xF0 ? 4 : 0;
    2707:             if (!width) {
    2708:                 return yaml_parser_set_scanner_error(parser, directive ?
    2709:                         "while parsing a %TAG directive" : "while parsing a tag",
    2710:                         start_mark, "found an incorrect leading UTF-8 octet");
    2711:             }
    2712:         }
    2713:         else
    2714:         {
    2715:             /* Check if the trailing octet is correct. */

    2717:             if ((octet & 0xC0) != 0x80) {
    2718:                 return yaml_parser_set_scanner_error(parser, directive ?
    2719:                         "while parsing a %TAG directive" : "while parsing a tag",
    2720:                         start_mark, "found an incorrect trailing UTF-8 octet");
    2721:             }
    2722:         }

    2724:         /* Copy the octet and move the pointers. */

    2726:         *(string->pointer++) = octet;
    2727:         SKIP(parser);
    2728:         SKIP(parser);
    2729:         SKIP(parser);

    2731:     } while (--width);

    2733:     return 1;
    2734: }

    2736: /*
    2737:  * Scan a block scalar.
    2738:  */

    2740: static int
    2741: yaml_parser_scan_block_scalar(yaml_parser_t *parser, yaml_token_t *token,
    2742:         int literal)
    2743: {
    2744:     yaml_mark_t start_mark;
    2745:     yaml_mark_t end_mark;
    2746:     yaml_string_t string = NULL_STRING;
    2747:     yaml_string_t leading_break = NULL_STRING;
    2748:     yaml_string_t trailing_breaks = NULL_STRING;
    2749:     int chomping = 0;
    2750:     int increment = 0;
    2751:     int indent = 0;
    2752:     int leading_blank = 0;
    2753:     int trailing_blank = 0;

    2755:     if (!STRING_INIT(parser, string, INITIAL_STRING_SIZE)) goto error;
    2756:     if (!STRING_INIT(parser, leading_break, INITIAL_STRING_SIZE)) goto error;
    2757:     if (!STRING_INIT(parser, trailing_breaks, INITIAL_STRING_SIZE)) goto error;

    2759:     /* Eat the indicator '|' or '>'. */

    2761:     start_mark = parser->mark;

    2763:     SKIP(parser);

    2765:     /* Scan the additional block scalar indicators. */

    2767:     if (!CACHE(parser, 1)) goto error;

    2769:     /* Check for a chomping indicator. */

    2771:     if (CHECK(parser->buffer, '+') || CHECK(parser->buffer, '-'))
    2772:     {
    2773:         /* Set the chomping method and eat the indicator. */

    2775:         chomping = CHECK(parser->buffer, '+') ? +1 : -1;

    2777:         SKIP(parser);

    2779:         /* Check for an indentation indicator. */

    2781:         if (!CACHE(parser, 1)) goto error;

    2783:         if (IS_DIGIT(parser->buffer))
    2784:         {
    2785:             /* Check that the indentation is greater than 0. */

    2787:             if (CHECK(parser->buffer, '0')) {
    2788:                 yaml_parser_set_scanner_error(parser, "while scanning a block scalar",
    2789:                         start_mark, "found an indentation indicator equal to 0");
    2790:                 goto error;
    2791:             }

    2793:             /* Get the indentation level and eat the indicator. */

    2795:             increment = AS_DIGIT(parser->buffer);

    2797:             SKIP(parser);
    2798:         }
    2799:     }

    2801:     /* Do the same as above, but in the opposite order. */

    2803:     else if (IS_DIGIT(parser->buffer))
    2804:     {
    2805:         if (CHECK(parser->buffer, '0')) {
    2806:             yaml_parser_set_scanner_error(parser, "while scanning a block scalar",
    2807:                     start_mark, "found an indentation indicator equal to 0");
    2808:             goto error;
    2809:         }

    2811:         increment = AS_DIGIT(parser->buffer);

    2813:         SKIP(parser);

    2815:         if (!CACHE(parser, 1)) goto error;

    2817:         if (CHECK(parser->buffer, '+') || CHECK(parser->buffer, '-')) {
    2818:             chomping = CHECK(parser->buffer, '+') ? +1 : -1;

    2820:             SKIP(parser);
    2821:         }
    2822:     }

    2824:     /* Eat whitespaces and comments to the end of the line. */

    2826:     if (!CACHE(parser, 1)) goto error;

    2828:     while (IS_BLANK(parser->buffer)) {
    2829:         SKIP(parser);
    2830:         if (!CACHE(parser, 1)) goto error;
    2831:     }

    2833:     if (CHECK(parser->buffer, '#')) {
    2834:         while (!IS_BREAKZ(parser->buffer)) {
    2835:             SKIP(parser);
    2836:             if (!CACHE(parser, 1)) goto error;
    2837:         }
    2838:     }

    2840:     /* Check if we are at the end of the line. */

    2842:     if (!IS_BREAKZ(parser->buffer)) {
    2843:         yaml_parser_set_scanner_error(parser, "while scanning a block scalar",
    2844:                 start_mark, "did not find expected comment or line break");
    2845:         goto error;
    2846:     }

    2848:     /* Eat a line break. */

    2850:     if (IS_BREAK(parser->buffer)) {
    2851:         if (!CACHE(parser, 2)) goto error;
    2852:         SKIP_LINE(parser);
    2853:     }

    2855:     end_mark = parser->mark;

    2857:     /* Set the indentation level if it was specified. */

    2859:     if (increment) {
    2860:         indent = parser->indent >= 0 ? parser->indent+increment : increment;
    2861:     }

    2863:     /* Scan the leading line breaks and determine the indentation level if needed. */

    2865:     if (!yaml_parser_scan_block_scalar_breaks(parser, &indent, &trailing_breaks,
    2866:                 start_mark, &end_mark)) goto error;

    2868:     /* Scan the block scalar content. */

    2870:     if (!CACHE(parser, 1)) goto error;

    2872:     while ((int)parser->mark.column == indent && !(IS_Z(parser->buffer)))
    2873:     {
    2874:         /*
    2875:          * We are at the beginning of a non-empty line.
    2876:          */

    2878:         /* Is it a trailing whitespace? */

    2880:         trailing_blank = IS_BLANK(parser->buffer);

    2882:         /* Check if we need to fold the leading line break. */

    2884:         if (!literal && (*leading_break.start == '\n')
    2885:                 && !leading_blank && !trailing_blank)
    2886:         {
    2887:             /* Do we need to join the lines by space? */

    2889:             if (*trailing_breaks.start == '\0') {
    2890:                 if (!STRING_EXTEND(parser, string)) goto error;
    2891:                 *(string.pointer ++) = ' ';
    2892:             }

    2894:             CLEAR(parser, leading_break);
    2895:         }
    2896:         else {
    2897:             if (!JOIN(parser, string, leading_break)) goto error;
    2898:             CLEAR(parser, leading_break);
    2899:         }

    2901:         /* Append the remaining line breaks. */

    2903:         if (!JOIN(parser, string, trailing_breaks)) goto error;
    2904:         CLEAR(parser, trailing_breaks);

    2906:         /* Is it a leading whitespace? */

    2908:         leading_blank = IS_BLANK(parser->buffer);

    2910:         /* Consume the current line. */

    2912:         while (!IS_BREAKZ(parser->buffer)) {
    2913:             if (!READ(parser, string)) goto error;
    2914:             if (!CACHE(parser, 1)) goto error;
    2915:         }

    2917:         /* Consume the line break. */

    2919:         if (!CACHE(parser, 2)) goto error;

    2921:         if (!READ_LINE(parser, leading_break)) goto error;

    2923:         /* Eat the following indentation spaces and line breaks. */

    2925:         if (!yaml_parser_scan_block_scalar_breaks(parser,
    2926:                     &indent, &trailing_breaks, start_mark, &end_mark)) goto error;
    2927:     }

    2929:     /* Chomp the tail. */

    2931:     if (chomping != -1) {
    2932:         if (!JOIN(parser, string, leading_break)) goto error;
    2933:     }
    2934:     if (chomping == 1) {
    2935:         if (!JOIN(parser, string, trailing_breaks)) goto error;
    2936:     }

    2938:     /* Create a token. */

    2940:     SCALAR_TOKEN_INIT(*token, string.start, string.pointer-string.start,
    2941:             literal ? YAML_LITERAL_SCALAR_STYLE : YAML_FOLDED_SCALAR_STYLE,
    2942:             start_mark, end_mark);

    2944:     STRING_DEL(parser, leading_break);
    2945:     STRING_DEL(parser, trailing_breaks);

    2947:     return 1;

    2949: error:
    2950:     STRING_DEL(parser, string);
    2951:     STRING_DEL(parser, leading_break);
    2952:     STRING_DEL(parser, trailing_breaks);

    2954:     return 0;
    2955: }

    2957: /*
    2958:  * Scan indentation spaces and line breaks for a block scalar.  Determine the
    2959:  * indentation level if needed.
    2960:  */

    2962: static int
    2963: yaml_parser_scan_block_scalar_breaks(yaml_parser_t *parser,
    2964:         int *indent, yaml_string_t *breaks,
    2965:         yaml_mark_t start_mark, yaml_mark_t *end_mark)
    2966: {
    2967:     int max_indent = 0;

    2969:     *end_mark = parser->mark;

    2971:     /* Eat the indentation spaces and line breaks. */

    2973:     while (1)
    2974:     {
    2975:         /* Eat the indentation spaces. */

    2977:         if (!CACHE(parser, 1)) return 0;

    2979:         while ((!*indent || (int)parser->mark.column < *indent)
    2980:                 && IS_SPACE(parser->buffer)) {
    2981:             SKIP(parser);
    2982:             if (!CACHE(parser, 1)) return 0;
    2983:         }

    2985:         if ((int)parser->mark.column > max_indent)
    2986:             max_indent = (int)parser->mark.column;

    2988:         /* Check for a tab character messing the indentation. */

    2990:         if ((!*indent || (int)parser->mark.column < *indent)
    2991:                 && IS_TAB(parser->buffer)) {
    2992:             return yaml_parser_set_scanner_error(parser, "while scanning a block scalar",
    2993:                     start_mark, "found a tab character where an indentation space is expected");
    2994:         }

    2996:         /* Have we found a non-empty line? */

    2998:         if (!IS_BREAK(parser->buffer)) break;

    3000:         /* Consume the line break. */

    3002:         if (!CACHE(parser, 2)) return 0;
    3003:         if (!READ_LINE(parser, *breaks)) return 0;
    3004:         *end_mark = parser->mark;
    3005:     }

    3007:     /* Determine the indentation level if needed. */

    3009:     if (!*indent) {
    3010:         *indent = max_indent;
    3011:         if (*indent < parser->indent + 1)
    3012:             *indent = parser->indent + 1;
    3013:         if (*indent < 1)
    3014:             *indent = 1;
    3015:     }

    3017:    return 1;
    3018: }

    3020: /*
    3021:  * Scan a quoted scalar.
    3022:  */

    3024: static int
    3025: yaml_parser_scan_flow_scalar(yaml_parser_t *parser, yaml_token_t *token,
    3026:         int single)
    3027: {
    3028:     yaml_mark_t start_mark;
    3029:     yaml_mark_t end_mark;
    3030:     yaml_string_t string = NULL_STRING;
    3031:     yaml_string_t leading_break = NULL_STRING;
    3032:     yaml_string_t trailing_breaks = NULL_STRING;
    3033:     yaml_string_t whitespaces = NULL_STRING;
    3034:     int leading_blanks;

    3036:     if (!STRING_INIT(parser, string, INITIAL_STRING_SIZE)) goto error;
    3037:     if (!STRING_INIT(parser, leading_break, INITIAL_STRING_SIZE)) goto error;
    3038:     if (!STRING_INIT(parser, trailing_breaks, INITIAL_STRING_SIZE)) goto error;
    3039:     if (!STRING_INIT(parser, whitespaces, INITIAL_STRING_SIZE)) goto error;

    3041:     /* Eat the left quote. */

    3043:     start_mark = parser->mark;

    3045:     SKIP(parser);

    3047:     /* Consume the content of the quoted scalar. */

    3049:     while (1)
    3050:     {
    3051:         /* Check that there are no document indicators at the beginning of the line. */

    3053:         if (!CACHE(parser, 4)) goto error;

    3055:         if (parser->mark.column == 0 &&
    3056:             ((CHECK_AT(parser->buffer, '-', 0) &&
    3057:               CHECK_AT(parser->buffer, '-', 1) &&
    3058:               CHECK_AT(parser->buffer, '-', 2)) ||
    3059:              (CHECK_AT(parser->buffer, '.', 0) &&
    3060:               CHECK_AT(parser->buffer, '.', 1) &&
    3061:               CHECK_AT(parser->buffer, '.', 2))) &&
    3062:             IS_BLANKZ_AT(parser->buffer, 3))
    3063:         {
    3064:             yaml_parser_set_scanner_error(parser, "while scanning a quoted scalar",
    3065:                     start_mark, "found unexpected document indicator");
    3066:             goto error;
    3067:         }

    3069:         /* Check for EOF. */

    3071:         if (IS_Z(parser->buffer)) {
    3072:             yaml_parser_set_scanner_error(parser, "while scanning a quoted scalar",
    3073:                     start_mark, "found unexpected end of stream");
    3074:             goto error;
    3075:         }

    3077:         /* Consume non-blank characters. */

    3079:         if (!CACHE(parser, 2)) goto error;

    3081:         leading_blanks = 0;

    3083:         while (!IS_BLANKZ(parser->buffer))
    3084:         {
    3085:             /* Check for an escaped single quote. */

    3087:             if (single && CHECK_AT(parser->buffer, '\'', 0)
    3088:                     && CHECK_AT(parser->buffer, '\'', 1))
    3089:             {
    3090:                 if (!STRING_EXTEND(parser, string)) goto error;
    3091:                 *(string.pointer++) = '\'';
    3092:                 SKIP(parser);
    3093:                 SKIP(parser);
    3094:             }

    3096:             /* Check for the right quote. */

    3098:             else if (CHECK(parser->buffer, single ? '\'' : '"'))
    3099:             {
    3100:                 break;
    3101:             }

    3103:             /* Check for an escaped line break. */

    3105:             else if (!single && CHECK(parser->buffer, '\\')
    3106:                     && IS_BREAK_AT(parser->buffer, 1))
    3107:             {
    3108:                 if (!CACHE(parser, 3)) goto error;
    3109:                 SKIP(parser);
    3110:                 SKIP_LINE(parser);
    3111:                 leading_blanks = 1;
    3112:                 break;
    3113:             }

    3115:             /* Check for an escape sequence. */

    3117:             else if (!single && CHECK(parser->buffer, '\\'))
    3118:             {
    3119:                 size_t code_length = 0;

    3121:                 if (!STRING_EXTEND(parser, string)) goto error;

    3123:                 /* Check the escape character. */

    3125:                 switch (parser->buffer.pointer[1])
    3126:                 {
    3127:                     case '0':
    3128:                         *(string.pointer++) = '\0';
    3129:                         break;

    3131:                     case 'a':
    3132:                         *(string.pointer++) = '\x07';
    3133:                         break;

    3135:                     case 'b':
    3136:                         *(string.pointer++) = '\x08';
    3137:                         break;

    3139:                     case 't':
    3140:                     case '\t':
    3141:                         *(string.pointer++) = '\x09';
    3142:                         break;

    3144:                     case 'n':
    3145:                         *(string.pointer++) = '\x0A';
    3146:                         break;

    3148:                     case 'v':
    3149:                         *(string.pointer++) = '\x0B';
    3150:                         break;

    3152:                     case 'f':
    3153:                         *(string.pointer++) = '\x0C';
    3154:                         break;

    3156:                     case 'r':
    3157:                         *(string.pointer++) = '\x0D';
    3158:                         break;

    3160:                     case 'e':
    3161:                         *(string.pointer++) = '\x1B';
    3162:                         break;

    3164:                     case ' ':
    3165:                         *(string.pointer++) = '\x20';
    3166:                         break;

    3168:                     case '"':
    3169:                         *(string.pointer++) = '"';
    3170:                         break;

    3172:                     case '/':
    3173:                         *(string.pointer++) = '/';
    3174:                         break;

    3176:                     case '\\':
    3177:                         *(string.pointer++) = '\\';
    3178:                         break;

    3180:                     case 'N':   /* NEL (#x85) */
    3181:                         *(string.pointer++) = (unsigned char)'\xC2';
    3182:                         *(string.pointer++) = (unsigned char)'\x85';
    3183:                         break;

    3185:                     case '_':   /* #xA0 */
    3186:                         *(string.pointer++) = (unsigned char)'\xC2';
    3187:                         *(string.pointer++) = (unsigned char) '\xA0';
    3188:                         break;

    3190:                     case 'L':   /* LS (#x2028) */
    3191:                         *(string.pointer++) = (unsigned char)'\xE2';
    3192:                         *(string.pointer++) = (unsigned char)'\x80';
    3193:                         *(string.pointer++) = (unsigned char)'\xA8';
    3194:                         break;

    3196:                     case 'P':   /* PS (#x2029) */
    3197:                         *(string.pointer++) = (unsigned char)'\xE2';
    3198:                         *(string.pointer++) = (unsigned char)'\x80';
    3199:                         *(string.pointer++) = (unsigned char)'\xA9';
    3200:                         break;

    3202:                     case 'x':
    3203:                         code_length = 2;
    3204:                         break;

    3206:                     case 'u':
    3207:                         code_length = 4;
    3208:                         break;

    3210:                     case 'U':
    3211:                         code_length = 8;
    3212:                         break;

    3214:                     default:
    3215:                         yaml_parser_set_scanner_error(parser, "while parsing a quoted scalar",
    3216:                                 start_mark, "found unknown escape character");
    3217:                         goto error;
    3218:                 }

    3220:                 SKIP(parser);
    3221:                 SKIP(parser);

    3223:                 /* Consume an arbitrary escape code. */

    3225:                 if (code_length)
    3226:                 {
    3227:                     unsigned int value = 0;
    3228:                     size_t k;

    3230:                     /* Scan the character value. */

    3232:                     if (!CACHE(parser, code_length)) goto error;

    3234:                     for (k = 0; k < code_length; k ++) {
    3235:                         if (!IS_HEX_AT(parser->buffer, k)) {
    3236:                             yaml_parser_set_scanner_error(parser, "while parsing a quoted scalar",
    3237:                                     start_mark, "did not find expected hexadecimal number");
    3238:                             goto error;
    3239:                         }
    3240:                         value = (value << 4) + AS_HEX_AT(parser->buffer, k);
    3241:                     }

    3243:                     /* Check the value and write the character. */

    3245:                     if ((value >= 0xD800 && value <= 0xDFFF) || value > 0x10FFFF) {
    3246:                         yaml_parser_set_scanner_error(parser, "while parsing a quoted scalar",
    3247:                                 start_mark, "found invalid Unicode character escape code");
    3248:                         goto error;
    3249:                     }

    3251:                     if (value <= 0x7F) {
    3252:                         *(string.pointer++) = value;
    3253:                     }
    3254:                     else if (value <= 0x7FF) {
    3255:                         *(string.pointer++) = 0xC0 + (value >> 6);
    3256:                         *(string.pointer++) = 0x80 + (value & 0x3F);
    3257:                     }
    3258:                     else if (value <= 0xFFFF) {
    3259:                         *(string.pointer++) = 0xE0 + (value >> 12);
    3260:                         *(string.pointer++) = 0x80 + ((value >> 6) & 0x3F);
    3261:                         *(string.pointer++) = 0x80 + (value & 0x3F);
    3262:                     }
    3263:                     else {
    3264:                         *(string.pointer++) = 0xF0 + (value >> 18);
    3265:                         *(string.pointer++) = 0x80 + ((value >> 12) & 0x3F);
    3266:                         *(string.pointer++) = 0x80 + ((value >> 6) & 0x3F);
    3267:                         *(string.pointer++) = 0x80 + (value & 0x3F);
    3268:                     }

    3270:                     /* Advance the pointer. */

    3272:                     for (k = 0; k < code_length; k ++) {
    3273:                         SKIP(parser);
    3274:                     }
    3275:                 }
    3276:             }

    3278:             else
    3279:             {
    3280:                 /* It is a non-escaped non-blank character. */

    3282:                 if (!READ(parser, string)) goto error;
    3283:             }

    3285:             if (!CACHE(parser, 2)) goto error;
    3286:         }

    3288:         /* Check if we are at the end of the scalar. */

    3290:         /* Fix for crash uninitialized value crash
    3291:          * Credit for the bug and input is to OSS Fuzz
    3292:          * Credit for the fix to Alex Gaynor
    3293:          */
    3294:         if (!CACHE(parser, 1)) goto error;
    3295:         if (CHECK(parser->buffer, single ? '\'' : '"'))
    3296:             break;

    3298:         /* Consume blank characters. */

    3300:         if (!CACHE(parser, 1)) goto error;

    3302:         while (IS_BLANK(parser->buffer) || IS_BREAK(parser->buffer))
    3303:         {
    3304:             if (IS_BLANK(parser->buffer))
    3305:             {
    3306:                 /* Consume a space or a tab character. */

    3308:                 if (!leading_blanks) {
    3309:                     if (!READ(parser, whitespaces)) goto error;
    3310:                 }
    3311:                 else {
    3312:                     SKIP(parser);
    3313:                 }
    3314:             }
    3315:             else
    3316:             {
    3317:                 if (!CACHE(parser, 2)) goto error;

    3319:                 /* Check if it is a first line break. */

    3321:                 if (!leading_blanks)
    3322:                 {
    3323:                     CLEAR(parser, whitespaces);
    3324:                     if (!READ_LINE(parser, leading_break)) goto error;
    3325:                     leading_blanks = 1;
    3326:                 }
    3327:                 else
    3328:                 {
    3329:                     if (!READ_LINE(parser, trailing_breaks)) goto error;
    3330:                 }
    3331:             }
    3332:             if (!CACHE(parser, 1)) goto error;
    3333:         }

    3335:         /* Join the whitespaces or fold line breaks. */

    3337:         if (leading_blanks)
    3338:         {
    3339:             /* Do we need to fold line breaks? */

    3341:             if (leading_break.start[0] == '\n') {
    3342:                 if (trailing_breaks.start[0] == '\0') {
    3343:                     if (!STRING_EXTEND(parser, string)) goto error;
    3344:                     *(string.pointer++) = ' ';
    3345:                 }
    3346:                 else {
    3347:                     if (!JOIN(parser, string, trailing_breaks)) goto error;
    3348:                     CLEAR(parser, trailing_breaks);
    3349:                 }
    3350:                 CLEAR(parser, leading_break);
    3351:             }
    3352:             else {
    3353:                 if (!JOIN(parser, string, leading_break)) goto error;
    3354:                 if (!JOIN(parser, string, trailing_breaks)) goto error;
    3355:                 CLEAR(parser, leading_break);
    3356:                 CLEAR(parser, trailing_breaks);
    3357:             }
    3358:         }
    3359:         else
    3360:         {
    3361:             if (!JOIN(parser, string, whitespaces)) goto error;
    3362:             CLEAR(parser, whitespaces);
    3363:         }
    3364:     }

    3366:     /* Eat the right quote. */

    3368:     SKIP(parser);

    3370:     end_mark = parser->mark;

    3372:     /* Create a token. */

    3374:     SCALAR_TOKEN_INIT(*token, string.start, string.pointer-string.start,
    3375:             single ? YAML_SINGLE_QUOTED_SCALAR_STYLE : YAML_DOUBLE_QUOTED_SCALAR_STYLE,
    3376:             start_mark, end_mark);

    3378:     STRING_DEL(parser, leading_break);
    3379:     STRING_DEL(parser, trailing_breaks);
    3380:     STRING_DEL(parser, whitespaces);

    3382:     return 1;

    3384: error:
    3385:     STRING_DEL(parser, string);
    3386:     STRING_DEL(parser, leading_break);
    3387:     STRING_DEL(parser, trailing_breaks);
    3388:     STRING_DEL(parser, whitespaces);

    3390:     return 0;
    3391: }

    3393: /*
    3394:  * Scan a plain scalar.
    3395:  */

    3397: static int
    3398: yaml_parser_scan_plain_scalar(yaml_parser_t *parser, yaml_token_t *token)
    3399: {
    3400:     yaml_mark_t start_mark;
    3401:     yaml_mark_t end_mark;
    3402:     yaml_string_t string = NULL_STRING;
    3403:     yaml_string_t leading_break = NULL_STRING;
    3404:     yaml_string_t trailing_breaks = NULL_STRING;
    3405:     yaml_string_t whitespaces = NULL_STRING;
    3406:     int leading_blanks = 0;
    3407:     int indent = parser->indent+1;

    3409:     if (!STRING_INIT(parser, string, INITIAL_STRING_SIZE)) goto error;
    3410:     if (!STRING_INIT(parser, leading_break, INITIAL_STRING_SIZE)) goto error;
    3411:     if (!STRING_INIT(parser, trailing_breaks, INITIAL_STRING_SIZE)) goto error;
    3412:     if (!STRING_INIT(parser, whitespaces, INITIAL_STRING_SIZE)) goto error;

    3414:     start_mark = end_mark = parser->mark;

    3416:     /* Consume the content of the plain scalar. */

    3418:     while (1)
    3419:     {
    3420:         /* Check for a document indicator. */

    3422:         if (!CACHE(parser, 4)) goto error;

    3424:         if (parser->mark.column == 0 &&
    3425:             ((CHECK_AT(parser->buffer, '-', 0) &&
    3426:               CHECK_AT(parser->buffer, '-', 1) &&
    3427:               CHECK_AT(parser->buffer, '-', 2)) ||
    3428:              (CHECK_AT(parser->buffer, '.', 0) &&
    3429:               CHECK_AT(parser->buffer, '.', 1) &&
    3430:               CHECK_AT(parser->buffer, '.', 2))) &&
    3431:             IS_BLANKZ_AT(parser->buffer, 3)) break;

    3433:         /* Check for a comment. */

    3435:         if (CHECK(parser->buffer, '#'))
    3436:             break;

    3438:         /* Consume non-blank characters. */

    3440:         while (!IS_BLANKZ(parser->buffer))
    3441:         {
    3442:             /* Check for "x:" + one of ',?[]{}' in the flow context. TODO: Fix the test "spec-08-13".
    3443:              * This is not completely according to the spec
    3444:              * See http://yaml.org/spec/1.1/#id907281 9.1.3. Plain
    3445:              */

    3447:             if (parser->flow_level
    3448:                     && CHECK(parser->buffer, ':')
    3449:                     && (
    3450:                         CHECK_AT(parser->buffer, ',', 1)
    3451:                         || CHECK_AT(parser->buffer, '?', 1)
    3452:                         || CHECK_AT(parser->buffer, '[', 1)
    3453:                         || CHECK_AT(parser->buffer, ']', 1)
    3454:                         || CHECK_AT(parser->buffer, '{', 1)
    3455:                         || CHECK_AT(parser->buffer, '}', 1)
    3456:                     )
    3457:                     ) {
    3458:                 yaml_parser_set_scanner_error(parser, "while scanning a plain scalar",
    3459:                         start_mark, "found unexpected ':'");
    3460:                 goto error;
    3461:             }

    3463:             /* Check for indicators that may end a plain scalar. */

    3465:             if ((CHECK(parser->buffer, ':') && IS_BLANKZ_AT(parser->buffer, 1))
    3466:                     || (parser->flow_level &&
    3467:                         (CHECK(parser->buffer, ',')
    3468:                          || CHECK(parser->buffer, '[')
    3469:                          || CHECK(parser->buffer, ']') || CHECK(parser->buffer, '{')
    3470:                          || CHECK(parser->buffer, '}'))))
    3471:                 break;

    3473:             /* Check if we need to join whitespaces and breaks. */

    3475:             if (leading_blanks || whitespaces.start != whitespaces.pointer)
    3476:             {
    3477:                 if (leading_blanks)
    3478:                 {
    3479:                     /* Do we need to fold line breaks? */

    3481:                     if (leading_break.start[0] == '\n') {
    3482:                         if (trailing_breaks.start[0] == '\0') {
    3483:                             if (!STRING_EXTEND(parser, string)) goto error;
    3484:                             *(string.pointer++) = ' ';
    3485:                         }
    3486:                         else {
    3487:                             if (!JOIN(parser, string, trailing_breaks)) goto error;
    3488:                             CLEAR(parser, trailing_breaks);
    3489:                         }
    3490:                         CLEAR(parser, leading_break);
    3491:                     }
    3492:                     else {
    3493:                         if (!JOIN(parser, string, leading_break)) goto error;
    3494:                         if (!JOIN(parser, string, trailing_breaks)) goto error;
    3495:                         CLEAR(parser, leading_break);
    3496:                         CLEAR(parser, trailing_breaks);
    3497:                     }

    3499:                     leading_blanks = 0;
    3500:                 }
    3501:                 else
    3502:                 {
    3503:                     if (!JOIN(parser, string, whitespaces)) goto error;
    3504:                     CLEAR(parser, whitespaces);
    3505:                 }
    3506:             }

    3508:             /* Copy the character. */

    3510:             if (!READ(parser, string)) goto error;

    3512:             end_mark = parser->mark;

    3514:             if (!CACHE(parser, 2)) goto error;
    3515:         }

    3517:         /* Is it the end? */

    3519:         if (!(IS_BLANK(parser->buffer) || IS_BREAK(parser->buffer)))
    3520:             break;

    3522:         /* Consume blank characters. */

    3524:         if (!CACHE(parser, 1)) goto error;

    3526:         while (IS_BLANK(parser->buffer) || IS_BREAK(parser->buffer))
    3527:         {
    3528:             if (IS_BLANK(parser->buffer))
    3529:             {
    3530:                 /* Check for tab characters that abuse indentation. */

    3532:                 if (leading_blanks && (int)parser->mark.column < indent
    3533:                         && IS_TAB(parser->buffer)) {
    3534:                     yaml_parser_set_scanner_error(parser, "while scanning a plain scalar",
    3535:                             start_mark, "found a tab character that violates indentation");
    3536:                     goto error;
    3537:                 }

    3539:                 /* Consume a space or a tab character. */

    3541:                 if (!leading_blanks) {
    3542:                     if (!READ(parser, whitespaces)) goto error;
    3543:                 }
    3544:                 else {
    3545:                     SKIP(parser);
    3546:                 }
    3547:             }
    3548:             else
    3549:             {
    3550:                 if (!CACHE(parser, 2)) goto error;

    3552:                 /* Check if it is a first line break. */

    3554:                 if (!leading_blanks)
    3555:                 {
    3556:                     CLEAR(parser, whitespaces);
    3557:                     if (!READ_LINE(parser, leading_break)) goto error;
    3558:                     leading_blanks = 1;
    3559:                 }
    3560:                 else
    3561:                 {
    3562:                     if (!READ_LINE(parser, trailing_breaks)) goto error;
    3563:                 }
    3564:             }
    3565:             if (!CACHE(parser, 1)) goto error;
    3566:         }

    3568:         /* Check indentation level. */

    3570:         if (!parser->flow_level && (int)parser->mark.column < indent)
    3571:             break;
    3572:     }

    3574:     /* Create a token. */

    3576:     SCALAR_TOKEN_INIT(*token, string.start, string.pointer-string.start,
    3577:             YAML_PLAIN_SCALAR_STYLE, start_mark, end_mark);

    3579:     /* Note that we change the 'simple_key_allowed' flag. */

    3581:     if (leading_blanks) {
    3582:         parser->simple_key_allowed = 1;
    3583:     }

    3585:     STRING_DEL(parser, leading_break);
    3586:     STRING_DEL(parser, trailing_breaks);
    3587:     STRING_DEL(parser, whitespaces);

    3589:     return 1;

    3591: error:
    3592:     STRING_DEL(parser, string);
    3593:     STRING_DEL(parser, leading_break);
    3594:     STRING_DEL(parser, trailing_breaks);
    3595:     STRING_DEL(parser, whitespaces);

    3597:     return 0;
    3598: }