435c0d9fc8
This PR switches the Nomad repository from using govendor to Go modules for managing dependencies. Aspects of the Nomad workflow remain pretty much the same. The usual Makefile targets should continue to work as they always did. The API submodule simply defers to the parent Nomad version on the repository, keeping the semantics of API versioning that currently exists.
1686 lines
44 KiB
Go
1686 lines
44 KiB
Go
package yaml
|
|
|
|
import (
|
|
"bytes"
|
|
"fmt"
|
|
)
|
|
|
|
// Flush the buffer if needed.
|
|
func flush(emitter *yaml_emitter_t) bool {
|
|
if emitter.buffer_pos+5 >= len(emitter.buffer) {
|
|
return yaml_emitter_flush(emitter)
|
|
}
|
|
return true
|
|
}
|
|
|
|
// Put a character to the output buffer.
|
|
func put(emitter *yaml_emitter_t, value byte) bool {
|
|
if emitter.buffer_pos+5 >= len(emitter.buffer) && !yaml_emitter_flush(emitter) {
|
|
return false
|
|
}
|
|
emitter.buffer[emitter.buffer_pos] = value
|
|
emitter.buffer_pos++
|
|
emitter.column++
|
|
return true
|
|
}
|
|
|
|
// Put a line break to the output buffer.
|
|
func put_break(emitter *yaml_emitter_t) bool {
|
|
if emitter.buffer_pos+5 >= len(emitter.buffer) && !yaml_emitter_flush(emitter) {
|
|
return false
|
|
}
|
|
switch emitter.line_break {
|
|
case yaml_CR_BREAK:
|
|
emitter.buffer[emitter.buffer_pos] = '\r'
|
|
emitter.buffer_pos += 1
|
|
case yaml_LN_BREAK:
|
|
emitter.buffer[emitter.buffer_pos] = '\n'
|
|
emitter.buffer_pos += 1
|
|
case yaml_CRLN_BREAK:
|
|
emitter.buffer[emitter.buffer_pos+0] = '\r'
|
|
emitter.buffer[emitter.buffer_pos+1] = '\n'
|
|
emitter.buffer_pos += 2
|
|
default:
|
|
panic("unknown line break setting")
|
|
}
|
|
emitter.column = 0
|
|
emitter.line++
|
|
return true
|
|
}
|
|
|
|
// Copy a character from a string into buffer.
|
|
func write(emitter *yaml_emitter_t, s []byte, i *int) bool {
|
|
if emitter.buffer_pos+5 >= len(emitter.buffer) && !yaml_emitter_flush(emitter) {
|
|
return false
|
|
}
|
|
p := emitter.buffer_pos
|
|
w := width(s[*i])
|
|
switch w {
|
|
case 4:
|
|
emitter.buffer[p+3] = s[*i+3]
|
|
fallthrough
|
|
case 3:
|
|
emitter.buffer[p+2] = s[*i+2]
|
|
fallthrough
|
|
case 2:
|
|
emitter.buffer[p+1] = s[*i+1]
|
|
fallthrough
|
|
case 1:
|
|
emitter.buffer[p+0] = s[*i+0]
|
|
default:
|
|
panic("unknown character width")
|
|
}
|
|
emitter.column++
|
|
emitter.buffer_pos += w
|
|
*i += w
|
|
return true
|
|
}
|
|
|
|
// Write a whole string into buffer.
|
|
func write_all(emitter *yaml_emitter_t, s []byte) bool {
|
|
for i := 0; i < len(s); {
|
|
if !write(emitter, s, &i) {
|
|
return false
|
|
}
|
|
}
|
|
return true
|
|
}
|
|
|
|
// Copy a line break character from a string into buffer.
|
|
func write_break(emitter *yaml_emitter_t, s []byte, i *int) bool {
|
|
if s[*i] == '\n' {
|
|
if !put_break(emitter) {
|
|
return false
|
|
}
|
|
*i++
|
|
} else {
|
|
if !write(emitter, s, i) {
|
|
return false
|
|
}
|
|
emitter.column = 0
|
|
emitter.line++
|
|
}
|
|
return true
|
|
}
|
|
|
|
// Set an emitter error and return false.
|
|
func yaml_emitter_set_emitter_error(emitter *yaml_emitter_t, problem string) bool {
|
|
emitter.error = yaml_EMITTER_ERROR
|
|
emitter.problem = problem
|
|
return false
|
|
}
|
|
|
|
// Emit an event.
|
|
func yaml_emitter_emit(emitter *yaml_emitter_t, event *yaml_event_t) bool {
|
|
emitter.events = append(emitter.events, *event)
|
|
for !yaml_emitter_need_more_events(emitter) {
|
|
event := &emitter.events[emitter.events_head]
|
|
if !yaml_emitter_analyze_event(emitter, event) {
|
|
return false
|
|
}
|
|
if !yaml_emitter_state_machine(emitter, event) {
|
|
return false
|
|
}
|
|
yaml_event_delete(event)
|
|
emitter.events_head++
|
|
}
|
|
return true
|
|
}
|
|
|
|
// Check if we need to accumulate more events before emitting.
|
|
//
|
|
// We accumulate extra
|
|
// - 1 event for DOCUMENT-START
|
|
// - 2 events for SEQUENCE-START
|
|
// - 3 events for MAPPING-START
|
|
//
|
|
func yaml_emitter_need_more_events(emitter *yaml_emitter_t) bool {
|
|
if emitter.events_head == len(emitter.events) {
|
|
return true
|
|
}
|
|
var accumulate int
|
|
switch emitter.events[emitter.events_head].typ {
|
|
case yaml_DOCUMENT_START_EVENT:
|
|
accumulate = 1
|
|
break
|
|
case yaml_SEQUENCE_START_EVENT:
|
|
accumulate = 2
|
|
break
|
|
case yaml_MAPPING_START_EVENT:
|
|
accumulate = 3
|
|
break
|
|
default:
|
|
return false
|
|
}
|
|
if len(emitter.events)-emitter.events_head > accumulate {
|
|
return false
|
|
}
|
|
var level int
|
|
for i := emitter.events_head; i < len(emitter.events); i++ {
|
|
switch emitter.events[i].typ {
|
|
case yaml_STREAM_START_EVENT, yaml_DOCUMENT_START_EVENT, yaml_SEQUENCE_START_EVENT, yaml_MAPPING_START_EVENT:
|
|
level++
|
|
case yaml_STREAM_END_EVENT, yaml_DOCUMENT_END_EVENT, yaml_SEQUENCE_END_EVENT, yaml_MAPPING_END_EVENT:
|
|
level--
|
|
}
|
|
if level == 0 {
|
|
return false
|
|
}
|
|
}
|
|
return true
|
|
}
|
|
|
|
// Append a directive to the directives stack.
|
|
func yaml_emitter_append_tag_directive(emitter *yaml_emitter_t, value *yaml_tag_directive_t, allow_duplicates bool) bool {
|
|
for i := 0; i < len(emitter.tag_directives); i++ {
|
|
if bytes.Equal(value.handle, emitter.tag_directives[i].handle) {
|
|
if allow_duplicates {
|
|
return true
|
|
}
|
|
return yaml_emitter_set_emitter_error(emitter, "duplicate %TAG directive")
|
|
}
|
|
}
|
|
|
|
// [Go] Do we actually need to copy this given garbage collection
|
|
// and the lack of deallocating destructors?
|
|
tag_copy := yaml_tag_directive_t{
|
|
handle: make([]byte, len(value.handle)),
|
|
prefix: make([]byte, len(value.prefix)),
|
|
}
|
|
copy(tag_copy.handle, value.handle)
|
|
copy(tag_copy.prefix, value.prefix)
|
|
emitter.tag_directives = append(emitter.tag_directives, tag_copy)
|
|
return true
|
|
}
|
|
|
|
// Increase the indentation level.
|
|
func yaml_emitter_increase_indent(emitter *yaml_emitter_t, flow, indentless bool) bool {
|
|
emitter.indents = append(emitter.indents, emitter.indent)
|
|
if emitter.indent < 0 {
|
|
if flow {
|
|
emitter.indent = emitter.best_indent
|
|
} else {
|
|
emitter.indent = 0
|
|
}
|
|
} else if !indentless {
|
|
emitter.indent += emitter.best_indent
|
|
}
|
|
return true
|
|
}
|
|
|
|
// State dispatcher.
|
|
func yaml_emitter_state_machine(emitter *yaml_emitter_t, event *yaml_event_t) bool {
|
|
switch emitter.state {
|
|
default:
|
|
case yaml_EMIT_STREAM_START_STATE:
|
|
return yaml_emitter_emit_stream_start(emitter, event)
|
|
|
|
case yaml_EMIT_FIRST_DOCUMENT_START_STATE:
|
|
return yaml_emitter_emit_document_start(emitter, event, true)
|
|
|
|
case yaml_EMIT_DOCUMENT_START_STATE:
|
|
return yaml_emitter_emit_document_start(emitter, event, false)
|
|
|
|
case yaml_EMIT_DOCUMENT_CONTENT_STATE:
|
|
return yaml_emitter_emit_document_content(emitter, event)
|
|
|
|
case yaml_EMIT_DOCUMENT_END_STATE:
|
|
return yaml_emitter_emit_document_end(emitter, event)
|
|
|
|
case yaml_EMIT_FLOW_SEQUENCE_FIRST_ITEM_STATE:
|
|
return yaml_emitter_emit_flow_sequence_item(emitter, event, true)
|
|
|
|
case yaml_EMIT_FLOW_SEQUENCE_ITEM_STATE:
|
|
return yaml_emitter_emit_flow_sequence_item(emitter, event, false)
|
|
|
|
case yaml_EMIT_FLOW_MAPPING_FIRST_KEY_STATE:
|
|
return yaml_emitter_emit_flow_mapping_key(emitter, event, true)
|
|
|
|
case yaml_EMIT_FLOW_MAPPING_KEY_STATE:
|
|
return yaml_emitter_emit_flow_mapping_key(emitter, event, false)
|
|
|
|
case yaml_EMIT_FLOW_MAPPING_SIMPLE_VALUE_STATE:
|
|
return yaml_emitter_emit_flow_mapping_value(emitter, event, true)
|
|
|
|
case yaml_EMIT_FLOW_MAPPING_VALUE_STATE:
|
|
return yaml_emitter_emit_flow_mapping_value(emitter, event, false)
|
|
|
|
case yaml_EMIT_BLOCK_SEQUENCE_FIRST_ITEM_STATE:
|
|
return yaml_emitter_emit_block_sequence_item(emitter, event, true)
|
|
|
|
case yaml_EMIT_BLOCK_SEQUENCE_ITEM_STATE:
|
|
return yaml_emitter_emit_block_sequence_item(emitter, event, false)
|
|
|
|
case yaml_EMIT_BLOCK_MAPPING_FIRST_KEY_STATE:
|
|
return yaml_emitter_emit_block_mapping_key(emitter, event, true)
|
|
|
|
case yaml_EMIT_BLOCK_MAPPING_KEY_STATE:
|
|
return yaml_emitter_emit_block_mapping_key(emitter, event, false)
|
|
|
|
case yaml_EMIT_BLOCK_MAPPING_SIMPLE_VALUE_STATE:
|
|
return yaml_emitter_emit_block_mapping_value(emitter, event, true)
|
|
|
|
case yaml_EMIT_BLOCK_MAPPING_VALUE_STATE:
|
|
return yaml_emitter_emit_block_mapping_value(emitter, event, false)
|
|
|
|
case yaml_EMIT_END_STATE:
|
|
return yaml_emitter_set_emitter_error(emitter, "expected nothing after STREAM-END")
|
|
}
|
|
panic("invalid emitter state")
|
|
}
|
|
|
|
// Expect STREAM-START.
|
|
func yaml_emitter_emit_stream_start(emitter *yaml_emitter_t, event *yaml_event_t) bool {
|
|
if event.typ != yaml_STREAM_START_EVENT {
|
|
return yaml_emitter_set_emitter_error(emitter, "expected STREAM-START")
|
|
}
|
|
if emitter.encoding == yaml_ANY_ENCODING {
|
|
emitter.encoding = event.encoding
|
|
if emitter.encoding == yaml_ANY_ENCODING {
|
|
emitter.encoding = yaml_UTF8_ENCODING
|
|
}
|
|
}
|
|
if emitter.best_indent < 2 || emitter.best_indent > 9 {
|
|
emitter.best_indent = 2
|
|
}
|
|
if emitter.best_width >= 0 && emitter.best_width <= emitter.best_indent*2 {
|
|
emitter.best_width = 80
|
|
}
|
|
if emitter.best_width < 0 {
|
|
emitter.best_width = 1<<31 - 1
|
|
}
|
|
if emitter.line_break == yaml_ANY_BREAK {
|
|
emitter.line_break = yaml_LN_BREAK
|
|
}
|
|
|
|
emitter.indent = -1
|
|
emitter.line = 0
|
|
emitter.column = 0
|
|
emitter.whitespace = true
|
|
emitter.indention = true
|
|
|
|
if emitter.encoding != yaml_UTF8_ENCODING {
|
|
if !yaml_emitter_write_bom(emitter) {
|
|
return false
|
|
}
|
|
}
|
|
emitter.state = yaml_EMIT_FIRST_DOCUMENT_START_STATE
|
|
return true
|
|
}
|
|
|
|
// Expect DOCUMENT-START or STREAM-END.
|
|
func yaml_emitter_emit_document_start(emitter *yaml_emitter_t, event *yaml_event_t, first bool) bool {
|
|
|
|
if event.typ == yaml_DOCUMENT_START_EVENT {
|
|
|
|
if event.version_directive != nil {
|
|
if !yaml_emitter_analyze_version_directive(emitter, event.version_directive) {
|
|
return false
|
|
}
|
|
}
|
|
|
|
for i := 0; i < len(event.tag_directives); i++ {
|
|
tag_directive := &event.tag_directives[i]
|
|
if !yaml_emitter_analyze_tag_directive(emitter, tag_directive) {
|
|
return false
|
|
}
|
|
if !yaml_emitter_append_tag_directive(emitter, tag_directive, false) {
|
|
return false
|
|
}
|
|
}
|
|
|
|
for i := 0; i < len(default_tag_directives); i++ {
|
|
tag_directive := &default_tag_directives[i]
|
|
if !yaml_emitter_append_tag_directive(emitter, tag_directive, true) {
|
|
return false
|
|
}
|
|
}
|
|
|
|
implicit := event.implicit
|
|
if !first || emitter.canonical {
|
|
implicit = false
|
|
}
|
|
|
|
if emitter.open_ended && (event.version_directive != nil || len(event.tag_directives) > 0) {
|
|
if !yaml_emitter_write_indicator(emitter, []byte("..."), true, false, false) {
|
|
return false
|
|
}
|
|
if !yaml_emitter_write_indent(emitter) {
|
|
return false
|
|
}
|
|
}
|
|
|
|
if event.version_directive != nil {
|
|
implicit = false
|
|
if !yaml_emitter_write_indicator(emitter, []byte("%YAML"), true, false, false) {
|
|
return false
|
|
}
|
|
if !yaml_emitter_write_indicator(emitter, []byte("1.1"), true, false, false) {
|
|
return false
|
|
}
|
|
if !yaml_emitter_write_indent(emitter) {
|
|
return false
|
|
}
|
|
}
|
|
|
|
if len(event.tag_directives) > 0 {
|
|
implicit = false
|
|
for i := 0; i < len(event.tag_directives); i++ {
|
|
tag_directive := &event.tag_directives[i]
|
|
if !yaml_emitter_write_indicator(emitter, []byte("%TAG"), true, false, false) {
|
|
return false
|
|
}
|
|
if !yaml_emitter_write_tag_handle(emitter, tag_directive.handle) {
|
|
return false
|
|
}
|
|
if !yaml_emitter_write_tag_content(emitter, tag_directive.prefix, true) {
|
|
return false
|
|
}
|
|
if !yaml_emitter_write_indent(emitter) {
|
|
return false
|
|
}
|
|
}
|
|
}
|
|
|
|
if yaml_emitter_check_empty_document(emitter) {
|
|
implicit = false
|
|
}
|
|
if !implicit {
|
|
if !yaml_emitter_write_indent(emitter) {
|
|
return false
|
|
}
|
|
if !yaml_emitter_write_indicator(emitter, []byte("---"), true, false, false) {
|
|
return false
|
|
}
|
|
if emitter.canonical {
|
|
if !yaml_emitter_write_indent(emitter) {
|
|
return false
|
|
}
|
|
}
|
|
}
|
|
|
|
emitter.state = yaml_EMIT_DOCUMENT_CONTENT_STATE
|
|
return true
|
|
}
|
|
|
|
if event.typ == yaml_STREAM_END_EVENT {
|
|
if emitter.open_ended {
|
|
if !yaml_emitter_write_indicator(emitter, []byte("..."), true, false, false) {
|
|
return false
|
|
}
|
|
if !yaml_emitter_write_indent(emitter) {
|
|
return false
|
|
}
|
|
}
|
|
if !yaml_emitter_flush(emitter) {
|
|
return false
|
|
}
|
|
emitter.state = yaml_EMIT_END_STATE
|
|
return true
|
|
}
|
|
|
|
return yaml_emitter_set_emitter_error(emitter, "expected DOCUMENT-START or STREAM-END")
|
|
}
|
|
|
|
// Expect the root node.
|
|
func yaml_emitter_emit_document_content(emitter *yaml_emitter_t, event *yaml_event_t) bool {
|
|
emitter.states = append(emitter.states, yaml_EMIT_DOCUMENT_END_STATE)
|
|
return yaml_emitter_emit_node(emitter, event, true, false, false, false)
|
|
}
|
|
|
|
// Expect DOCUMENT-END.
|
|
func yaml_emitter_emit_document_end(emitter *yaml_emitter_t, event *yaml_event_t) bool {
|
|
if event.typ != yaml_DOCUMENT_END_EVENT {
|
|
return yaml_emitter_set_emitter_error(emitter, "expected DOCUMENT-END")
|
|
}
|
|
if !yaml_emitter_write_indent(emitter) {
|
|
return false
|
|
}
|
|
if !event.implicit {
|
|
// [Go] Allocate the slice elsewhere.
|
|
if !yaml_emitter_write_indicator(emitter, []byte("..."), true, false, false) {
|
|
return false
|
|
}
|
|
if !yaml_emitter_write_indent(emitter) {
|
|
return false
|
|
}
|
|
}
|
|
if !yaml_emitter_flush(emitter) {
|
|
return false
|
|
}
|
|
emitter.state = yaml_EMIT_DOCUMENT_START_STATE
|
|
emitter.tag_directives = emitter.tag_directives[:0]
|
|
return true
|
|
}
|
|
|
|
// Expect a flow item node.
|
|
func yaml_emitter_emit_flow_sequence_item(emitter *yaml_emitter_t, event *yaml_event_t, first bool) bool {
|
|
if first {
|
|
if !yaml_emitter_write_indicator(emitter, []byte{'['}, true, true, false) {
|
|
return false
|
|
}
|
|
if !yaml_emitter_increase_indent(emitter, true, false) {
|
|
return false
|
|
}
|
|
emitter.flow_level++
|
|
}
|
|
|
|
if event.typ == yaml_SEQUENCE_END_EVENT {
|
|
emitter.flow_level--
|
|
emitter.indent = emitter.indents[len(emitter.indents)-1]
|
|
emitter.indents = emitter.indents[:len(emitter.indents)-1]
|
|
if emitter.canonical && !first {
|
|
if !yaml_emitter_write_indicator(emitter, []byte{','}, false, false, false) {
|
|
return false
|
|
}
|
|
if !yaml_emitter_write_indent(emitter) {
|
|
return false
|
|
}
|
|
}
|
|
if !yaml_emitter_write_indicator(emitter, []byte{']'}, false, false, false) {
|
|
return false
|
|
}
|
|
emitter.state = emitter.states[len(emitter.states)-1]
|
|
emitter.states = emitter.states[:len(emitter.states)-1]
|
|
|
|
return true
|
|
}
|
|
|
|
if !first {
|
|
if !yaml_emitter_write_indicator(emitter, []byte{','}, false, false, false) {
|
|
return false
|
|
}
|
|
}
|
|
|
|
if emitter.canonical || emitter.column > emitter.best_width {
|
|
if !yaml_emitter_write_indent(emitter) {
|
|
return false
|
|
}
|
|
}
|
|
emitter.states = append(emitter.states, yaml_EMIT_FLOW_SEQUENCE_ITEM_STATE)
|
|
return yaml_emitter_emit_node(emitter, event, false, true, false, false)
|
|
}
|
|
|
|
// Expect a flow key node.
|
|
func yaml_emitter_emit_flow_mapping_key(emitter *yaml_emitter_t, event *yaml_event_t, first bool) bool {
|
|
if first {
|
|
if !yaml_emitter_write_indicator(emitter, []byte{'{'}, true, true, false) {
|
|
return false
|
|
}
|
|
if !yaml_emitter_increase_indent(emitter, true, false) {
|
|
return false
|
|
}
|
|
emitter.flow_level++
|
|
}
|
|
|
|
if event.typ == yaml_MAPPING_END_EVENT {
|
|
emitter.flow_level--
|
|
emitter.indent = emitter.indents[len(emitter.indents)-1]
|
|
emitter.indents = emitter.indents[:len(emitter.indents)-1]
|
|
if emitter.canonical && !first {
|
|
if !yaml_emitter_write_indicator(emitter, []byte{','}, false, false, false) {
|
|
return false
|
|
}
|
|
if !yaml_emitter_write_indent(emitter) {
|
|
return false
|
|
}
|
|
}
|
|
if !yaml_emitter_write_indicator(emitter, []byte{'}'}, false, false, false) {
|
|
return false
|
|
}
|
|
emitter.state = emitter.states[len(emitter.states)-1]
|
|
emitter.states = emitter.states[:len(emitter.states)-1]
|
|
return true
|
|
}
|
|
|
|
if !first {
|
|
if !yaml_emitter_write_indicator(emitter, []byte{','}, false, false, false) {
|
|
return false
|
|
}
|
|
}
|
|
if emitter.canonical || emitter.column > emitter.best_width {
|
|
if !yaml_emitter_write_indent(emitter) {
|
|
return false
|
|
}
|
|
}
|
|
|
|
if !emitter.canonical && yaml_emitter_check_simple_key(emitter) {
|
|
emitter.states = append(emitter.states, yaml_EMIT_FLOW_MAPPING_SIMPLE_VALUE_STATE)
|
|
return yaml_emitter_emit_node(emitter, event, false, false, true, true)
|
|
}
|
|
if !yaml_emitter_write_indicator(emitter, []byte{'?'}, true, false, false) {
|
|
return false
|
|
}
|
|
emitter.states = append(emitter.states, yaml_EMIT_FLOW_MAPPING_VALUE_STATE)
|
|
return yaml_emitter_emit_node(emitter, event, false, false, true, false)
|
|
}
|
|
|
|
// Expect a flow value node.
|
|
func yaml_emitter_emit_flow_mapping_value(emitter *yaml_emitter_t, event *yaml_event_t, simple bool) bool {
|
|
if simple {
|
|
if !yaml_emitter_write_indicator(emitter, []byte{':'}, false, false, false) {
|
|
return false
|
|
}
|
|
} else {
|
|
if emitter.canonical || emitter.column > emitter.best_width {
|
|
if !yaml_emitter_write_indent(emitter) {
|
|
return false
|
|
}
|
|
}
|
|
if !yaml_emitter_write_indicator(emitter, []byte{':'}, true, false, false) {
|
|
return false
|
|
}
|
|
}
|
|
emitter.states = append(emitter.states, yaml_EMIT_FLOW_MAPPING_KEY_STATE)
|
|
return yaml_emitter_emit_node(emitter, event, false, false, true, false)
|
|
}
|
|
|
|
// Expect a block item node.
|
|
func yaml_emitter_emit_block_sequence_item(emitter *yaml_emitter_t, event *yaml_event_t, first bool) bool {
|
|
if first {
|
|
if !yaml_emitter_increase_indent(emitter, false, emitter.mapping_context && !emitter.indention) {
|
|
return false
|
|
}
|
|
}
|
|
if event.typ == yaml_SEQUENCE_END_EVENT {
|
|
emitter.indent = emitter.indents[len(emitter.indents)-1]
|
|
emitter.indents = emitter.indents[:len(emitter.indents)-1]
|
|
emitter.state = emitter.states[len(emitter.states)-1]
|
|
emitter.states = emitter.states[:len(emitter.states)-1]
|
|
return true
|
|
}
|
|
if !yaml_emitter_write_indent(emitter) {
|
|
return false
|
|
}
|
|
if !yaml_emitter_write_indicator(emitter, []byte{'-'}, true, false, true) {
|
|
return false
|
|
}
|
|
emitter.states = append(emitter.states, yaml_EMIT_BLOCK_SEQUENCE_ITEM_STATE)
|
|
return yaml_emitter_emit_node(emitter, event, false, true, false, false)
|
|
}
|
|
|
|
// Expect a block key node.
|
|
func yaml_emitter_emit_block_mapping_key(emitter *yaml_emitter_t, event *yaml_event_t, first bool) bool {
|
|
if first {
|
|
if !yaml_emitter_increase_indent(emitter, false, false) {
|
|
return false
|
|
}
|
|
}
|
|
if event.typ == yaml_MAPPING_END_EVENT {
|
|
emitter.indent = emitter.indents[len(emitter.indents)-1]
|
|
emitter.indents = emitter.indents[:len(emitter.indents)-1]
|
|
emitter.state = emitter.states[len(emitter.states)-1]
|
|
emitter.states = emitter.states[:len(emitter.states)-1]
|
|
return true
|
|
}
|
|
if !yaml_emitter_write_indent(emitter) {
|
|
return false
|
|
}
|
|
if yaml_emitter_check_simple_key(emitter) {
|
|
emitter.states = append(emitter.states, yaml_EMIT_BLOCK_MAPPING_SIMPLE_VALUE_STATE)
|
|
return yaml_emitter_emit_node(emitter, event, false, false, true, true)
|
|
}
|
|
if !yaml_emitter_write_indicator(emitter, []byte{'?'}, true, false, true) {
|
|
return false
|
|
}
|
|
emitter.states = append(emitter.states, yaml_EMIT_BLOCK_MAPPING_VALUE_STATE)
|
|
return yaml_emitter_emit_node(emitter, event, false, false, true, false)
|
|
}
|
|
|
|
// Expect a block value node.
|
|
func yaml_emitter_emit_block_mapping_value(emitter *yaml_emitter_t, event *yaml_event_t, simple bool) bool {
|
|
if simple {
|
|
if !yaml_emitter_write_indicator(emitter, []byte{':'}, false, false, false) {
|
|
return false
|
|
}
|
|
} else {
|
|
if !yaml_emitter_write_indent(emitter) {
|
|
return false
|
|
}
|
|
if !yaml_emitter_write_indicator(emitter, []byte{':'}, true, false, true) {
|
|
return false
|
|
}
|
|
}
|
|
emitter.states = append(emitter.states, yaml_EMIT_BLOCK_MAPPING_KEY_STATE)
|
|
return yaml_emitter_emit_node(emitter, event, false, false, true, false)
|
|
}
|
|
|
|
// Expect a node.
|
|
func yaml_emitter_emit_node(emitter *yaml_emitter_t, event *yaml_event_t,
|
|
root bool, sequence bool, mapping bool, simple_key bool) bool {
|
|
|
|
emitter.root_context = root
|
|
emitter.sequence_context = sequence
|
|
emitter.mapping_context = mapping
|
|
emitter.simple_key_context = simple_key
|
|
|
|
switch event.typ {
|
|
case yaml_ALIAS_EVENT:
|
|
return yaml_emitter_emit_alias(emitter, event)
|
|
case yaml_SCALAR_EVENT:
|
|
return yaml_emitter_emit_scalar(emitter, event)
|
|
case yaml_SEQUENCE_START_EVENT:
|
|
return yaml_emitter_emit_sequence_start(emitter, event)
|
|
case yaml_MAPPING_START_EVENT:
|
|
return yaml_emitter_emit_mapping_start(emitter, event)
|
|
default:
|
|
return yaml_emitter_set_emitter_error(emitter,
|
|
fmt.Sprintf("expected SCALAR, SEQUENCE-START, MAPPING-START, or ALIAS, but got %v", event.typ))
|
|
}
|
|
}
|
|
|
|
// Expect ALIAS.
|
|
func yaml_emitter_emit_alias(emitter *yaml_emitter_t, event *yaml_event_t) bool {
|
|
if !yaml_emitter_process_anchor(emitter) {
|
|
return false
|
|
}
|
|
emitter.state = emitter.states[len(emitter.states)-1]
|
|
emitter.states = emitter.states[:len(emitter.states)-1]
|
|
return true
|
|
}
|
|
|
|
// Expect SCALAR.
|
|
func yaml_emitter_emit_scalar(emitter *yaml_emitter_t, event *yaml_event_t) bool {
|
|
if !yaml_emitter_select_scalar_style(emitter, event) {
|
|
return false
|
|
}
|
|
if !yaml_emitter_process_anchor(emitter) {
|
|
return false
|
|
}
|
|
if !yaml_emitter_process_tag(emitter) {
|
|
return false
|
|
}
|
|
if !yaml_emitter_increase_indent(emitter, true, false) {
|
|
return false
|
|
}
|
|
if !yaml_emitter_process_scalar(emitter) {
|
|
return false
|
|
}
|
|
emitter.indent = emitter.indents[len(emitter.indents)-1]
|
|
emitter.indents = emitter.indents[:len(emitter.indents)-1]
|
|
emitter.state = emitter.states[len(emitter.states)-1]
|
|
emitter.states = emitter.states[:len(emitter.states)-1]
|
|
return true
|
|
}
|
|
|
|
// Expect SEQUENCE-START.
|
|
func yaml_emitter_emit_sequence_start(emitter *yaml_emitter_t, event *yaml_event_t) bool {
|
|
if !yaml_emitter_process_anchor(emitter) {
|
|
return false
|
|
}
|
|
if !yaml_emitter_process_tag(emitter) {
|
|
return false
|
|
}
|
|
if emitter.flow_level > 0 || emitter.canonical || event.sequence_style() == yaml_FLOW_SEQUENCE_STYLE ||
|
|
yaml_emitter_check_empty_sequence(emitter) {
|
|
emitter.state = yaml_EMIT_FLOW_SEQUENCE_FIRST_ITEM_STATE
|
|
} else {
|
|
emitter.state = yaml_EMIT_BLOCK_SEQUENCE_FIRST_ITEM_STATE
|
|
}
|
|
return true
|
|
}
|
|
|
|
// Expect MAPPING-START.
|
|
func yaml_emitter_emit_mapping_start(emitter *yaml_emitter_t, event *yaml_event_t) bool {
|
|
if !yaml_emitter_process_anchor(emitter) {
|
|
return false
|
|
}
|
|
if !yaml_emitter_process_tag(emitter) {
|
|
return false
|
|
}
|
|
if emitter.flow_level > 0 || emitter.canonical || event.mapping_style() == yaml_FLOW_MAPPING_STYLE ||
|
|
yaml_emitter_check_empty_mapping(emitter) {
|
|
emitter.state = yaml_EMIT_FLOW_MAPPING_FIRST_KEY_STATE
|
|
} else {
|
|
emitter.state = yaml_EMIT_BLOCK_MAPPING_FIRST_KEY_STATE
|
|
}
|
|
return true
|
|
}
|
|
|
|
// Check if the document content is an empty scalar.
|
|
func yaml_emitter_check_empty_document(emitter *yaml_emitter_t) bool {
|
|
return false // [Go] Huh?
|
|
}
|
|
|
|
// Check if the next events represent an empty sequence.
|
|
func yaml_emitter_check_empty_sequence(emitter *yaml_emitter_t) bool {
|
|
if len(emitter.events)-emitter.events_head < 2 {
|
|
return false
|
|
}
|
|
return emitter.events[emitter.events_head].typ == yaml_SEQUENCE_START_EVENT &&
|
|
emitter.events[emitter.events_head+1].typ == yaml_SEQUENCE_END_EVENT
|
|
}
|
|
|
|
// Check if the next events represent an empty mapping.
|
|
func yaml_emitter_check_empty_mapping(emitter *yaml_emitter_t) bool {
|
|
if len(emitter.events)-emitter.events_head < 2 {
|
|
return false
|
|
}
|
|
return emitter.events[emitter.events_head].typ == yaml_MAPPING_START_EVENT &&
|
|
emitter.events[emitter.events_head+1].typ == yaml_MAPPING_END_EVENT
|
|
}
|
|
|
|
// Check if the next node can be expressed as a simple key.
|
|
func yaml_emitter_check_simple_key(emitter *yaml_emitter_t) bool {
|
|
length := 0
|
|
switch emitter.events[emitter.events_head].typ {
|
|
case yaml_ALIAS_EVENT:
|
|
length += len(emitter.anchor_data.anchor)
|
|
case yaml_SCALAR_EVENT:
|
|
if emitter.scalar_data.multiline {
|
|
return false
|
|
}
|
|
length += len(emitter.anchor_data.anchor) +
|
|
len(emitter.tag_data.handle) +
|
|
len(emitter.tag_data.suffix) +
|
|
len(emitter.scalar_data.value)
|
|
case yaml_SEQUENCE_START_EVENT:
|
|
if !yaml_emitter_check_empty_sequence(emitter) {
|
|
return false
|
|
}
|
|
length += len(emitter.anchor_data.anchor) +
|
|
len(emitter.tag_data.handle) +
|
|
len(emitter.tag_data.suffix)
|
|
case yaml_MAPPING_START_EVENT:
|
|
if !yaml_emitter_check_empty_mapping(emitter) {
|
|
return false
|
|
}
|
|
length += len(emitter.anchor_data.anchor) +
|
|
len(emitter.tag_data.handle) +
|
|
len(emitter.tag_data.suffix)
|
|
default:
|
|
return false
|
|
}
|
|
return length <= 128
|
|
}
|
|
|
|
// Determine an acceptable scalar style.
|
|
func yaml_emitter_select_scalar_style(emitter *yaml_emitter_t, event *yaml_event_t) bool {
|
|
|
|
no_tag := len(emitter.tag_data.handle) == 0 && len(emitter.tag_data.suffix) == 0
|
|
if no_tag && !event.implicit && !event.quoted_implicit {
|
|
return yaml_emitter_set_emitter_error(emitter, "neither tag nor implicit flags are specified")
|
|
}
|
|
|
|
style := event.scalar_style()
|
|
if style == yaml_ANY_SCALAR_STYLE {
|
|
style = yaml_PLAIN_SCALAR_STYLE
|
|
}
|
|
if emitter.canonical {
|
|
style = yaml_DOUBLE_QUOTED_SCALAR_STYLE
|
|
}
|
|
if emitter.simple_key_context && emitter.scalar_data.multiline {
|
|
style = yaml_DOUBLE_QUOTED_SCALAR_STYLE
|
|
}
|
|
|
|
if style == yaml_PLAIN_SCALAR_STYLE {
|
|
if emitter.flow_level > 0 && !emitter.scalar_data.flow_plain_allowed ||
|
|
emitter.flow_level == 0 && !emitter.scalar_data.block_plain_allowed {
|
|
style = yaml_SINGLE_QUOTED_SCALAR_STYLE
|
|
}
|
|
if len(emitter.scalar_data.value) == 0 && (emitter.flow_level > 0 || emitter.simple_key_context) {
|
|
style = yaml_SINGLE_QUOTED_SCALAR_STYLE
|
|
}
|
|
if no_tag && !event.implicit {
|
|
style = yaml_SINGLE_QUOTED_SCALAR_STYLE
|
|
}
|
|
}
|
|
if style == yaml_SINGLE_QUOTED_SCALAR_STYLE {
|
|
if !emitter.scalar_data.single_quoted_allowed {
|
|
style = yaml_DOUBLE_QUOTED_SCALAR_STYLE
|
|
}
|
|
}
|
|
if style == yaml_LITERAL_SCALAR_STYLE || style == yaml_FOLDED_SCALAR_STYLE {
|
|
if !emitter.scalar_data.block_allowed || emitter.flow_level > 0 || emitter.simple_key_context {
|
|
style = yaml_DOUBLE_QUOTED_SCALAR_STYLE
|
|
}
|
|
}
|
|
|
|
if no_tag && !event.quoted_implicit && style != yaml_PLAIN_SCALAR_STYLE {
|
|
emitter.tag_data.handle = []byte{'!'}
|
|
}
|
|
emitter.scalar_data.style = style
|
|
return true
|
|
}
|
|
|
|
// Write an anchor.
|
|
func yaml_emitter_process_anchor(emitter *yaml_emitter_t) bool {
|
|
if emitter.anchor_data.anchor == nil {
|
|
return true
|
|
}
|
|
c := []byte{'&'}
|
|
if emitter.anchor_data.alias {
|
|
c[0] = '*'
|
|
}
|
|
if !yaml_emitter_write_indicator(emitter, c, true, false, false) {
|
|
return false
|
|
}
|
|
return yaml_emitter_write_anchor(emitter, emitter.anchor_data.anchor)
|
|
}
|
|
|
|
// Write a tag.
|
|
func yaml_emitter_process_tag(emitter *yaml_emitter_t) bool {
|
|
if len(emitter.tag_data.handle) == 0 && len(emitter.tag_data.suffix) == 0 {
|
|
return true
|
|
}
|
|
if len(emitter.tag_data.handle) > 0 {
|
|
if !yaml_emitter_write_tag_handle(emitter, emitter.tag_data.handle) {
|
|
return false
|
|
}
|
|
if len(emitter.tag_data.suffix) > 0 {
|
|
if !yaml_emitter_write_tag_content(emitter, emitter.tag_data.suffix, false) {
|
|
return false
|
|
}
|
|
}
|
|
} else {
|
|
// [Go] Allocate these slices elsewhere.
|
|
if !yaml_emitter_write_indicator(emitter, []byte("!<"), true, false, false) {
|
|
return false
|
|
}
|
|
if !yaml_emitter_write_tag_content(emitter, emitter.tag_data.suffix, false) {
|
|
return false
|
|
}
|
|
if !yaml_emitter_write_indicator(emitter, []byte{'>'}, false, false, false) {
|
|
return false
|
|
}
|
|
}
|
|
return true
|
|
}
|
|
|
|
// Write a scalar.
|
|
func yaml_emitter_process_scalar(emitter *yaml_emitter_t) bool {
|
|
switch emitter.scalar_data.style {
|
|
case yaml_PLAIN_SCALAR_STYLE:
|
|
return yaml_emitter_write_plain_scalar(emitter, emitter.scalar_data.value, !emitter.simple_key_context)
|
|
|
|
case yaml_SINGLE_QUOTED_SCALAR_STYLE:
|
|
return yaml_emitter_write_single_quoted_scalar(emitter, emitter.scalar_data.value, !emitter.simple_key_context)
|
|
|
|
case yaml_DOUBLE_QUOTED_SCALAR_STYLE:
|
|
return yaml_emitter_write_double_quoted_scalar(emitter, emitter.scalar_data.value, !emitter.simple_key_context)
|
|
|
|
case yaml_LITERAL_SCALAR_STYLE:
|
|
return yaml_emitter_write_literal_scalar(emitter, emitter.scalar_data.value)
|
|
|
|
case yaml_FOLDED_SCALAR_STYLE:
|
|
return yaml_emitter_write_folded_scalar(emitter, emitter.scalar_data.value)
|
|
}
|
|
panic("unknown scalar style")
|
|
}
|
|
|
|
// Check if a %YAML directive is valid.
|
|
func yaml_emitter_analyze_version_directive(emitter *yaml_emitter_t, version_directive *yaml_version_directive_t) bool {
|
|
if version_directive.major != 1 || version_directive.minor != 1 {
|
|
return yaml_emitter_set_emitter_error(emitter, "incompatible %YAML directive")
|
|
}
|
|
return true
|
|
}
|
|
|
|
// Check if a %TAG directive is valid.
|
|
func yaml_emitter_analyze_tag_directive(emitter *yaml_emitter_t, tag_directive *yaml_tag_directive_t) bool {
|
|
handle := tag_directive.handle
|
|
prefix := tag_directive.prefix
|
|
if len(handle) == 0 {
|
|
return yaml_emitter_set_emitter_error(emitter, "tag handle must not be empty")
|
|
}
|
|
if handle[0] != '!' {
|
|
return yaml_emitter_set_emitter_error(emitter, "tag handle must start with '!'")
|
|
}
|
|
if handle[len(handle)-1] != '!' {
|
|
return yaml_emitter_set_emitter_error(emitter, "tag handle must end with '!'")
|
|
}
|
|
for i := 1; i < len(handle)-1; i += width(handle[i]) {
|
|
if !is_alpha(handle, i) {
|
|
return yaml_emitter_set_emitter_error(emitter, "tag handle must contain alphanumerical characters only")
|
|
}
|
|
}
|
|
if len(prefix) == 0 {
|
|
return yaml_emitter_set_emitter_error(emitter, "tag prefix must not be empty")
|
|
}
|
|
return true
|
|
}
|
|
|
|
// Check if an anchor is valid.
|
|
func yaml_emitter_analyze_anchor(emitter *yaml_emitter_t, anchor []byte, alias bool) bool {
|
|
if len(anchor) == 0 {
|
|
problem := "anchor value must not be empty"
|
|
if alias {
|
|
problem = "alias value must not be empty"
|
|
}
|
|
return yaml_emitter_set_emitter_error(emitter, problem)
|
|
}
|
|
for i := 0; i < len(anchor); i += width(anchor[i]) {
|
|
if !is_alpha(anchor, i) {
|
|
problem := "anchor value must contain alphanumerical characters only"
|
|
if alias {
|
|
problem = "alias value must contain alphanumerical characters only"
|
|
}
|
|
return yaml_emitter_set_emitter_error(emitter, problem)
|
|
}
|
|
}
|
|
emitter.anchor_data.anchor = anchor
|
|
emitter.anchor_data.alias = alias
|
|
return true
|
|
}
|
|
|
|
// Check if a tag is valid.
|
|
func yaml_emitter_analyze_tag(emitter *yaml_emitter_t, tag []byte) bool {
|
|
if len(tag) == 0 {
|
|
return yaml_emitter_set_emitter_error(emitter, "tag value must not be empty")
|
|
}
|
|
for i := 0; i < len(emitter.tag_directives); i++ {
|
|
tag_directive := &emitter.tag_directives[i]
|
|
if bytes.HasPrefix(tag, tag_directive.prefix) {
|
|
emitter.tag_data.handle = tag_directive.handle
|
|
emitter.tag_data.suffix = tag[len(tag_directive.prefix):]
|
|
return true
|
|
}
|
|
}
|
|
emitter.tag_data.suffix = tag
|
|
return true
|
|
}
|
|
|
|
// Check if a scalar is valid.
|
|
func yaml_emitter_analyze_scalar(emitter *yaml_emitter_t, value []byte) bool {
|
|
var (
|
|
block_indicators = false
|
|
flow_indicators = false
|
|
line_breaks = false
|
|
special_characters = false
|
|
|
|
leading_space = false
|
|
leading_break = false
|
|
trailing_space = false
|
|
trailing_break = false
|
|
break_space = false
|
|
space_break = false
|
|
|
|
preceded_by_whitespace = false
|
|
followed_by_whitespace = false
|
|
previous_space = false
|
|
previous_break = false
|
|
)
|
|
|
|
emitter.scalar_data.value = value
|
|
|
|
if len(value) == 0 {
|
|
emitter.scalar_data.multiline = false
|
|
emitter.scalar_data.flow_plain_allowed = false
|
|
emitter.scalar_data.block_plain_allowed = true
|
|
emitter.scalar_data.single_quoted_allowed = true
|
|
emitter.scalar_data.block_allowed = false
|
|
return true
|
|
}
|
|
|
|
if len(value) >= 3 && ((value[0] == '-' && value[1] == '-' && value[2] == '-') || (value[0] == '.' && value[1] == '.' && value[2] == '.')) {
|
|
block_indicators = true
|
|
flow_indicators = true
|
|
}
|
|
|
|
preceded_by_whitespace = true
|
|
for i, w := 0, 0; i < len(value); i += w {
|
|
w = width(value[i])
|
|
followed_by_whitespace = i+w >= len(value) || is_blank(value, i+w)
|
|
|
|
if i == 0 {
|
|
switch value[i] {
|
|
case '#', ',', '[', ']', '{', '}', '&', '*', '!', '|', '>', '\'', '"', '%', '@', '`':
|
|
flow_indicators = true
|
|
block_indicators = true
|
|
case '?', ':':
|
|
flow_indicators = true
|
|
if followed_by_whitespace {
|
|
block_indicators = true
|
|
}
|
|
case '-':
|
|
if followed_by_whitespace {
|
|
flow_indicators = true
|
|
block_indicators = true
|
|
}
|
|
}
|
|
} else {
|
|
switch value[i] {
|
|
case ',', '?', '[', ']', '{', '}':
|
|
flow_indicators = true
|
|
case ':':
|
|
flow_indicators = true
|
|
if followed_by_whitespace {
|
|
block_indicators = true
|
|
}
|
|
case '#':
|
|
if preceded_by_whitespace {
|
|
flow_indicators = true
|
|
block_indicators = true
|
|
}
|
|
}
|
|
}
|
|
|
|
if !is_printable(value, i) || !is_ascii(value, i) && !emitter.unicode {
|
|
special_characters = true
|
|
}
|
|
if is_space(value, i) {
|
|
if i == 0 {
|
|
leading_space = true
|
|
}
|
|
if i+width(value[i]) == len(value) {
|
|
trailing_space = true
|
|
}
|
|
if previous_break {
|
|
break_space = true
|
|
}
|
|
previous_space = true
|
|
previous_break = false
|
|
} else if is_break(value, i) {
|
|
line_breaks = true
|
|
if i == 0 {
|
|
leading_break = true
|
|
}
|
|
if i+width(value[i]) == len(value) {
|
|
trailing_break = true
|
|
}
|
|
if previous_space {
|
|
space_break = true
|
|
}
|
|
previous_space = false
|
|
previous_break = true
|
|
} else {
|
|
previous_space = false
|
|
previous_break = false
|
|
}
|
|
|
|
// [Go]: Why 'z'? Couldn't be the end of the string as that's the loop condition.
|
|
preceded_by_whitespace = is_blankz(value, i)
|
|
}
|
|
|
|
emitter.scalar_data.multiline = line_breaks
|
|
emitter.scalar_data.flow_plain_allowed = true
|
|
emitter.scalar_data.block_plain_allowed = true
|
|
emitter.scalar_data.single_quoted_allowed = true
|
|
emitter.scalar_data.block_allowed = true
|
|
|
|
if leading_space || leading_break || trailing_space || trailing_break {
|
|
emitter.scalar_data.flow_plain_allowed = false
|
|
emitter.scalar_data.block_plain_allowed = false
|
|
}
|
|
if trailing_space {
|
|
emitter.scalar_data.block_allowed = false
|
|
}
|
|
if break_space {
|
|
emitter.scalar_data.flow_plain_allowed = false
|
|
emitter.scalar_data.block_plain_allowed = false
|
|
emitter.scalar_data.single_quoted_allowed = false
|
|
}
|
|
if space_break || special_characters {
|
|
emitter.scalar_data.flow_plain_allowed = false
|
|
emitter.scalar_data.block_plain_allowed = false
|
|
emitter.scalar_data.single_quoted_allowed = false
|
|
emitter.scalar_data.block_allowed = false
|
|
}
|
|
if line_breaks {
|
|
emitter.scalar_data.flow_plain_allowed = false
|
|
emitter.scalar_data.block_plain_allowed = false
|
|
}
|
|
if flow_indicators {
|
|
emitter.scalar_data.flow_plain_allowed = false
|
|
}
|
|
if block_indicators {
|
|
emitter.scalar_data.block_plain_allowed = false
|
|
}
|
|
return true
|
|
}
|
|
|
|
// Check if the event data is valid.
|
|
func yaml_emitter_analyze_event(emitter *yaml_emitter_t, event *yaml_event_t) bool {
|
|
|
|
emitter.anchor_data.anchor = nil
|
|
emitter.tag_data.handle = nil
|
|
emitter.tag_data.suffix = nil
|
|
emitter.scalar_data.value = nil
|
|
|
|
switch event.typ {
|
|
case yaml_ALIAS_EVENT:
|
|
if !yaml_emitter_analyze_anchor(emitter, event.anchor, true) {
|
|
return false
|
|
}
|
|
|
|
case yaml_SCALAR_EVENT:
|
|
if len(event.anchor) > 0 {
|
|
if !yaml_emitter_analyze_anchor(emitter, event.anchor, false) {
|
|
return false
|
|
}
|
|
}
|
|
if len(event.tag) > 0 && (emitter.canonical || (!event.implicit && !event.quoted_implicit)) {
|
|
if !yaml_emitter_analyze_tag(emitter, event.tag) {
|
|
return false
|
|
}
|
|
}
|
|
if !yaml_emitter_analyze_scalar(emitter, event.value) {
|
|
return false
|
|
}
|
|
|
|
case yaml_SEQUENCE_START_EVENT:
|
|
if len(event.anchor) > 0 {
|
|
if !yaml_emitter_analyze_anchor(emitter, event.anchor, false) {
|
|
return false
|
|
}
|
|
}
|
|
if len(event.tag) > 0 && (emitter.canonical || !event.implicit) {
|
|
if !yaml_emitter_analyze_tag(emitter, event.tag) {
|
|
return false
|
|
}
|
|
}
|
|
|
|
case yaml_MAPPING_START_EVENT:
|
|
if len(event.anchor) > 0 {
|
|
if !yaml_emitter_analyze_anchor(emitter, event.anchor, false) {
|
|
return false
|
|
}
|
|
}
|
|
if len(event.tag) > 0 && (emitter.canonical || !event.implicit) {
|
|
if !yaml_emitter_analyze_tag(emitter, event.tag) {
|
|
return false
|
|
}
|
|
}
|
|
}
|
|
return true
|
|
}
|
|
|
|
// Write the BOM character.
|
|
func yaml_emitter_write_bom(emitter *yaml_emitter_t) bool {
|
|
if !flush(emitter) {
|
|
return false
|
|
}
|
|
pos := emitter.buffer_pos
|
|
emitter.buffer[pos+0] = '\xEF'
|
|
emitter.buffer[pos+1] = '\xBB'
|
|
emitter.buffer[pos+2] = '\xBF'
|
|
emitter.buffer_pos += 3
|
|
return true
|
|
}
|
|
|
|
func yaml_emitter_write_indent(emitter *yaml_emitter_t) bool {
|
|
indent := emitter.indent
|
|
if indent < 0 {
|
|
indent = 0
|
|
}
|
|
if !emitter.indention || emitter.column > indent || (emitter.column == indent && !emitter.whitespace) {
|
|
if !put_break(emitter) {
|
|
return false
|
|
}
|
|
}
|
|
for emitter.column < indent {
|
|
if !put(emitter, ' ') {
|
|
return false
|
|
}
|
|
}
|
|
emitter.whitespace = true
|
|
emitter.indention = true
|
|
return true
|
|
}
|
|
|
|
func yaml_emitter_write_indicator(emitter *yaml_emitter_t, indicator []byte, need_whitespace, is_whitespace, is_indention bool) bool {
|
|
if need_whitespace && !emitter.whitespace {
|
|
if !put(emitter, ' ') {
|
|
return false
|
|
}
|
|
}
|
|
if !write_all(emitter, indicator) {
|
|
return false
|
|
}
|
|
emitter.whitespace = is_whitespace
|
|
emitter.indention = (emitter.indention && is_indention)
|
|
emitter.open_ended = false
|
|
return true
|
|
}
|
|
|
|
func yaml_emitter_write_anchor(emitter *yaml_emitter_t, value []byte) bool {
|
|
if !write_all(emitter, value) {
|
|
return false
|
|
}
|
|
emitter.whitespace = false
|
|
emitter.indention = false
|
|
return true
|
|
}
|
|
|
|
func yaml_emitter_write_tag_handle(emitter *yaml_emitter_t, value []byte) bool {
|
|
if !emitter.whitespace {
|
|
if !put(emitter, ' ') {
|
|
return false
|
|
}
|
|
}
|
|
if !write_all(emitter, value) {
|
|
return false
|
|
}
|
|
emitter.whitespace = false
|
|
emitter.indention = false
|
|
return true
|
|
}
|
|
|
|
func yaml_emitter_write_tag_content(emitter *yaml_emitter_t, value []byte, need_whitespace bool) bool {
|
|
if need_whitespace && !emitter.whitespace {
|
|
if !put(emitter, ' ') {
|
|
return false
|
|
}
|
|
}
|
|
for i := 0; i < len(value); {
|
|
var must_write bool
|
|
switch value[i] {
|
|
case ';', '/', '?', ':', '@', '&', '=', '+', '$', ',', '_', '.', '~', '*', '\'', '(', ')', '[', ']':
|
|
must_write = true
|
|
default:
|
|
must_write = is_alpha(value, i)
|
|
}
|
|
if must_write {
|
|
if !write(emitter, value, &i) {
|
|
return false
|
|
}
|
|
} else {
|
|
w := width(value[i])
|
|
for k := 0; k < w; k++ {
|
|
octet := value[i]
|
|
i++
|
|
if !put(emitter, '%') {
|
|
return false
|
|
}
|
|
|
|
c := octet >> 4
|
|
if c < 10 {
|
|
c += '0'
|
|
} else {
|
|
c += 'A' - 10
|
|
}
|
|
if !put(emitter, c) {
|
|
return false
|
|
}
|
|
|
|
c = octet & 0x0f
|
|
if c < 10 {
|
|
c += '0'
|
|
} else {
|
|
c += 'A' - 10
|
|
}
|
|
if !put(emitter, c) {
|
|
return false
|
|
}
|
|
}
|
|
}
|
|
}
|
|
emitter.whitespace = false
|
|
emitter.indention = false
|
|
return true
|
|
}
|
|
|
|
func yaml_emitter_write_plain_scalar(emitter *yaml_emitter_t, value []byte, allow_breaks bool) bool {
|
|
if !emitter.whitespace {
|
|
if !put(emitter, ' ') {
|
|
return false
|
|
}
|
|
}
|
|
|
|
spaces := false
|
|
breaks := false
|
|
for i := 0; i < len(value); {
|
|
if is_space(value, i) {
|
|
if allow_breaks && !spaces && emitter.column > emitter.best_width && !is_space(value, i+1) {
|
|
if !yaml_emitter_write_indent(emitter) {
|
|
return false
|
|
}
|
|
i += width(value[i])
|
|
} else {
|
|
if !write(emitter, value, &i) {
|
|
return false
|
|
}
|
|
}
|
|
spaces = true
|
|
} else if is_break(value, i) {
|
|
if !breaks && value[i] == '\n' {
|
|
if !put_break(emitter) {
|
|
return false
|
|
}
|
|
}
|
|
if !write_break(emitter, value, &i) {
|
|
return false
|
|
}
|
|
emitter.indention = true
|
|
breaks = true
|
|
} else {
|
|
if breaks {
|
|
if !yaml_emitter_write_indent(emitter) {
|
|
return false
|
|
}
|
|
}
|
|
if !write(emitter, value, &i) {
|
|
return false
|
|
}
|
|
emitter.indention = false
|
|
spaces = false
|
|
breaks = false
|
|
}
|
|
}
|
|
|
|
emitter.whitespace = false
|
|
emitter.indention = false
|
|
if emitter.root_context {
|
|
emitter.open_ended = true
|
|
}
|
|
|
|
return true
|
|
}
|
|
|
|
func yaml_emitter_write_single_quoted_scalar(emitter *yaml_emitter_t, value []byte, allow_breaks bool) bool {
|
|
|
|
if !yaml_emitter_write_indicator(emitter, []byte{'\''}, true, false, false) {
|
|
return false
|
|
}
|
|
|
|
spaces := false
|
|
breaks := false
|
|
for i := 0; i < len(value); {
|
|
if is_space(value, i) {
|
|
if allow_breaks && !spaces && emitter.column > emitter.best_width && i > 0 && i < len(value)-1 && !is_space(value, i+1) {
|
|
if !yaml_emitter_write_indent(emitter) {
|
|
return false
|
|
}
|
|
i += width(value[i])
|
|
} else {
|
|
if !write(emitter, value, &i) {
|
|
return false
|
|
}
|
|
}
|
|
spaces = true
|
|
} else if is_break(value, i) {
|
|
if !breaks && value[i] == '\n' {
|
|
if !put_break(emitter) {
|
|
return false
|
|
}
|
|
}
|
|
if !write_break(emitter, value, &i) {
|
|
return false
|
|
}
|
|
emitter.indention = true
|
|
breaks = true
|
|
} else {
|
|
if breaks {
|
|
if !yaml_emitter_write_indent(emitter) {
|
|
return false
|
|
}
|
|
}
|
|
if value[i] == '\'' {
|
|
if !put(emitter, '\'') {
|
|
return false
|
|
}
|
|
}
|
|
if !write(emitter, value, &i) {
|
|
return false
|
|
}
|
|
emitter.indention = false
|
|
spaces = false
|
|
breaks = false
|
|
}
|
|
}
|
|
if !yaml_emitter_write_indicator(emitter, []byte{'\''}, false, false, false) {
|
|
return false
|
|
}
|
|
emitter.whitespace = false
|
|
emitter.indention = false
|
|
return true
|
|
}
|
|
|
|
func yaml_emitter_write_double_quoted_scalar(emitter *yaml_emitter_t, value []byte, allow_breaks bool) bool {
|
|
spaces := false
|
|
if !yaml_emitter_write_indicator(emitter, []byte{'"'}, true, false, false) {
|
|
return false
|
|
}
|
|
|
|
for i := 0; i < len(value); {
|
|
if !is_printable(value, i) || (!emitter.unicode && !is_ascii(value, i)) ||
|
|
is_bom(value, i) || is_break(value, i) ||
|
|
value[i] == '"' || value[i] == '\\' {
|
|
|
|
octet := value[i]
|
|
|
|
var w int
|
|
var v rune
|
|
switch {
|
|
case octet&0x80 == 0x00:
|
|
w, v = 1, rune(octet&0x7F)
|
|
case octet&0xE0 == 0xC0:
|
|
w, v = 2, rune(octet&0x1F)
|
|
case octet&0xF0 == 0xE0:
|
|
w, v = 3, rune(octet&0x0F)
|
|
case octet&0xF8 == 0xF0:
|
|
w, v = 4, rune(octet&0x07)
|
|
}
|
|
for k := 1; k < w; k++ {
|
|
octet = value[i+k]
|
|
v = (v << 6) + (rune(octet) & 0x3F)
|
|
}
|
|
i += w
|
|
|
|
if !put(emitter, '\\') {
|
|
return false
|
|
}
|
|
|
|
var ok bool
|
|
switch v {
|
|
case 0x00:
|
|
ok = put(emitter, '0')
|
|
case 0x07:
|
|
ok = put(emitter, 'a')
|
|
case 0x08:
|
|
ok = put(emitter, 'b')
|
|
case 0x09:
|
|
ok = put(emitter, 't')
|
|
case 0x0A:
|
|
ok = put(emitter, 'n')
|
|
case 0x0b:
|
|
ok = put(emitter, 'v')
|
|
case 0x0c:
|
|
ok = put(emitter, 'f')
|
|
case 0x0d:
|
|
ok = put(emitter, 'r')
|
|
case 0x1b:
|
|
ok = put(emitter, 'e')
|
|
case 0x22:
|
|
ok = put(emitter, '"')
|
|
case 0x5c:
|
|
ok = put(emitter, '\\')
|
|
case 0x85:
|
|
ok = put(emitter, 'N')
|
|
case 0xA0:
|
|
ok = put(emitter, '_')
|
|
case 0x2028:
|
|
ok = put(emitter, 'L')
|
|
case 0x2029:
|
|
ok = put(emitter, 'P')
|
|
default:
|
|
if v <= 0xFF {
|
|
ok = put(emitter, 'x')
|
|
w = 2
|
|
} else if v <= 0xFFFF {
|
|
ok = put(emitter, 'u')
|
|
w = 4
|
|
} else {
|
|
ok = put(emitter, 'U')
|
|
w = 8
|
|
}
|
|
for k := (w - 1) * 4; ok && k >= 0; k -= 4 {
|
|
digit := byte((v >> uint(k)) & 0x0F)
|
|
if digit < 10 {
|
|
ok = put(emitter, digit+'0')
|
|
} else {
|
|
ok = put(emitter, digit+'A'-10)
|
|
}
|
|
}
|
|
}
|
|
if !ok {
|
|
return false
|
|
}
|
|
spaces = false
|
|
} else if is_space(value, i) {
|
|
if allow_breaks && !spaces && emitter.column > emitter.best_width && i > 0 && i < len(value)-1 {
|
|
if !yaml_emitter_write_indent(emitter) {
|
|
return false
|
|
}
|
|
if is_space(value, i+1) {
|
|
if !put(emitter, '\\') {
|
|
return false
|
|
}
|
|
}
|
|
i += width(value[i])
|
|
} else if !write(emitter, value, &i) {
|
|
return false
|
|
}
|
|
spaces = true
|
|
} else {
|
|
if !write(emitter, value, &i) {
|
|
return false
|
|
}
|
|
spaces = false
|
|
}
|
|
}
|
|
if !yaml_emitter_write_indicator(emitter, []byte{'"'}, false, false, false) {
|
|
return false
|
|
}
|
|
emitter.whitespace = false
|
|
emitter.indention = false
|
|
return true
|
|
}
|
|
|
|
func yaml_emitter_write_block_scalar_hints(emitter *yaml_emitter_t, value []byte) bool {
|
|
if is_space(value, 0) || is_break(value, 0) {
|
|
indent_hint := []byte{'0' + byte(emitter.best_indent)}
|
|
if !yaml_emitter_write_indicator(emitter, indent_hint, false, false, false) {
|
|
return false
|
|
}
|
|
}
|
|
|
|
emitter.open_ended = false
|
|
|
|
var chomp_hint [1]byte
|
|
if len(value) == 0 {
|
|
chomp_hint[0] = '-'
|
|
} else {
|
|
i := len(value) - 1
|
|
for value[i]&0xC0 == 0x80 {
|
|
i--
|
|
}
|
|
if !is_break(value, i) {
|
|
chomp_hint[0] = '-'
|
|
} else if i == 0 {
|
|
chomp_hint[0] = '+'
|
|
emitter.open_ended = true
|
|
} else {
|
|
i--
|
|
for value[i]&0xC0 == 0x80 {
|
|
i--
|
|
}
|
|
if is_break(value, i) {
|
|
chomp_hint[0] = '+'
|
|
emitter.open_ended = true
|
|
}
|
|
}
|
|
}
|
|
if chomp_hint[0] != 0 {
|
|
if !yaml_emitter_write_indicator(emitter, chomp_hint[:], false, false, false) {
|
|
return false
|
|
}
|
|
}
|
|
return true
|
|
}
|
|
|
|
func yaml_emitter_write_literal_scalar(emitter *yaml_emitter_t, value []byte) bool {
|
|
if !yaml_emitter_write_indicator(emitter, []byte{'|'}, true, false, false) {
|
|
return false
|
|
}
|
|
if !yaml_emitter_write_block_scalar_hints(emitter, value) {
|
|
return false
|
|
}
|
|
if !put_break(emitter) {
|
|
return false
|
|
}
|
|
emitter.indention = true
|
|
emitter.whitespace = true
|
|
breaks := true
|
|
for i := 0; i < len(value); {
|
|
if is_break(value, i) {
|
|
if !write_break(emitter, value, &i) {
|
|
return false
|
|
}
|
|
emitter.indention = true
|
|
breaks = true
|
|
} else {
|
|
if breaks {
|
|
if !yaml_emitter_write_indent(emitter) {
|
|
return false
|
|
}
|
|
}
|
|
if !write(emitter, value, &i) {
|
|
return false
|
|
}
|
|
emitter.indention = false
|
|
breaks = false
|
|
}
|
|
}
|
|
|
|
return true
|
|
}
|
|
|
|
func yaml_emitter_write_folded_scalar(emitter *yaml_emitter_t, value []byte) bool {
|
|
if !yaml_emitter_write_indicator(emitter, []byte{'>'}, true, false, false) {
|
|
return false
|
|
}
|
|
if !yaml_emitter_write_block_scalar_hints(emitter, value) {
|
|
return false
|
|
}
|
|
|
|
if !put_break(emitter) {
|
|
return false
|
|
}
|
|
emitter.indention = true
|
|
emitter.whitespace = true
|
|
|
|
breaks := true
|
|
leading_spaces := true
|
|
for i := 0; i < len(value); {
|
|
if is_break(value, i) {
|
|
if !breaks && !leading_spaces && value[i] == '\n' {
|
|
k := 0
|
|
for is_break(value, k) {
|
|
k += width(value[k])
|
|
}
|
|
if !is_blankz(value, k) {
|
|
if !put_break(emitter) {
|
|
return false
|
|
}
|
|
}
|
|
}
|
|
if !write_break(emitter, value, &i) {
|
|
return false
|
|
}
|
|
emitter.indention = true
|
|
breaks = true
|
|
} else {
|
|
if breaks {
|
|
if !yaml_emitter_write_indent(emitter) {
|
|
return false
|
|
}
|
|
leading_spaces = is_blank(value, i)
|
|
}
|
|
if !breaks && is_space(value, i) && !is_space(value, i+1) && emitter.column > emitter.best_width {
|
|
if !yaml_emitter_write_indent(emitter) {
|
|
return false
|
|
}
|
|
i += width(value[i])
|
|
} else {
|
|
if !write(emitter, value, &i) {
|
|
return false
|
|
}
|
|
}
|
|
emitter.indention = false
|
|
breaks = false
|
|
}
|
|
}
|
|
return true
|
|
}
|