d8ae7178e2
Signed-off-by: Antonio Murdaca <runcom@redhat.com>
2072 lines
45 KiB
Go
2072 lines
45 KiB
Go
/*
|
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|
you may not use this file except in compliance with the License.
|
|
You may obtain a copy of the License at
|
|
|
|
http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
Unless required by applicable law or agreed to in writing, software
|
|
distributed under the License is distributed on an "AS IS" BASIS,
|
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
See the License for the specific language governing permissions and
|
|
limitations under the License.
|
|
*/
|
|
|
|
package candiedyaml
|
|
|
|
import (
|
|
"bytes"
|
|
)
|
|
|
|
var default_tag_directives = []yaml_tag_directive_t{
|
|
{[]byte("!"), []byte("!")},
|
|
{[]byte("!!"), []byte("tag:yaml.org,2002:")},
|
|
}
|
|
|
|
/*
|
|
* 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 !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 !flush(emitter) {
|
|
return false
|
|
}
|
|
switch emitter.line_break {
|
|
case yaml_CR_BREAK:
|
|
emitter.buffer[emitter.buffer_pos] = '\r'
|
|
emitter.buffer_pos++
|
|
case yaml_LN_BREAK:
|
|
emitter.buffer[emitter.buffer_pos] = '\n'
|
|
emitter.buffer_pos++
|
|
case yaml_CRLN_BREAK:
|
|
emitter.buffer[emitter.buffer_pos] = '\r'
|
|
emitter.buffer[emitter.buffer_pos] = '\n'
|
|
emitter.buffer_pos += 2
|
|
default:
|
|
return false
|
|
}
|
|
emitter.column = 0
|
|
emitter.line++
|
|
return true
|
|
}
|
|
|
|
/*
|
|
* Copy a character from a string into buffer.
|
|
*/
|
|
func write(emitter *yaml_emitter_t, src []byte, src_pos *int) bool {
|
|
if !flush(emitter) {
|
|
return false
|
|
}
|
|
copy_bytes(emitter.buffer, &emitter.buffer_pos, src, src_pos)
|
|
emitter.column++
|
|
return true
|
|
}
|
|
|
|
/*
|
|
* Copy a line break character from a string into buffer.
|
|
*/
|
|
|
|
func write_break(emitter *yaml_emitter_t, src []byte, src_pos *int) bool {
|
|
if src[*src_pos] == '\n' {
|
|
if !put_break(emitter) {
|
|
return false
|
|
}
|
|
*src_pos++
|
|
} else {
|
|
if !write(emitter, src, src_pos) {
|
|
return false
|
|
}
|
|
emitter.column = 0
|
|
emitter.line++
|
|
}
|
|
|
|
return true
|
|
}
|
|
|
|
/*
|
|
* Set an emitter error and return 0.
|
|
*/
|
|
|
|
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
|
|
}
|
|
|
|
accumulate := 0
|
|
switch emitter.events[emitter.events_head].event_type {
|
|
case yaml_DOCUMENT_START_EVENT:
|
|
accumulate = 1
|
|
case yaml_SEQUENCE_START_EVENT:
|
|
accumulate = 2
|
|
case yaml_MAPPING_START_EVENT:
|
|
accumulate = 3
|
|
default:
|
|
return false
|
|
}
|
|
|
|
if len(emitter.events)-emitter.events_head > accumulate {
|
|
return false
|
|
}
|
|
|
|
level := 0
|
|
for i := emitter.events_head; i < len(emitter.events); i++ {
|
|
switch emitter.events[i].event_type {
|
|
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 := range emitter.tag_directives {
|
|
|
|
if bytes.Equal(value.handle, emitter.tag_directives[i].handle) {
|
|
if allow_duplicates {
|
|
return true
|
|
}
|
|
return yaml_emitter_set_emitter_error(emitter, "duplicat %TAG directive")
|
|
}
|
|
}
|
|
|
|
tag_copy := yaml_tag_directive_t{
|
|
handle: value.handle,
|
|
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 bool, 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 {
|
|
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 state")
|
|
}
|
|
|
|
/*
|
|
* Expect STREAM-START.
|
|
*/
|
|
|
|
func yaml_emitter_emit_stream_start(emitter *yaml_emitter_t, event *yaml_event_t) bool {
|
|
|
|
if event.event_type != 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.event_type == yaml_DOCUMENT_START_EVENT {
|
|
if event.version_directive != nil {
|
|
if !yaml_emitter_analyze_version_directive(emitter,
|
|
*event.version_directive) {
|
|
return false
|
|
}
|
|
}
|
|
|
|
for i := range event.tag_directives {
|
|
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 := range default_tag_directives {
|
|
if !yaml_emitter_append_tag_directive(emitter, &default_tag_directives[i], true) {
|
|
return false
|
|
}
|
|
}
|
|
|
|
implicit := event.implicit
|
|
if !first || emitter.canonical {
|
|
implicit = false
|
|
}
|
|
|
|
if (event.version_directive != nil || len(event.tag_directives) > 0) &&
|
|
emitter.open_ended {
|
|
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 := range event.tag_directives {
|
|
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
|
|
} else if event.event_type == 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.event_type != 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 {
|
|
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.event_type == 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.event_type == 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)
|
|
} else {
|
|
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.event_type == 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.event_type == 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)
|
|
} else {
|
|
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.event_type {
|
|
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,
|
|
"expected SCALAR, SEQUENCE-START, MAPPING-START, or ALIAS")
|
|
}
|
|
|
|
return false
|
|
}
|
|
|
|
/*
|
|
* 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.style == yaml_style_t(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.style == yaml_style_t(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
|
|
}
|
|
|
|
/*
|
|
* 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].event_type == yaml_SEQUENCE_START_EVENT &&
|
|
emitter.events[emitter.events_head+1].event_type == 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].event_type == yaml_MAPPING_START_EVENT &&
|
|
emitter.events[emitter.events_head+1].event_type == 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].event_type {
|
|
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
|
|
}
|
|
|
|
if length > 128 {
|
|
return false
|
|
}
|
|
|
|
return true
|
|
}
|
|
|
|
/*
|
|
* 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 := yaml_scalar_style_t(event.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 achor.
|
|
*/
|
|
|
|
func yaml_emitter_process_anchor(emitter *yaml_emitter_t) bool {
|
|
if emitter.anchor_data.anchor == nil {
|
|
return true
|
|
}
|
|
|
|
indicator := "*"
|
|
if !emitter.anchor_data.alias {
|
|
indicator = "&"
|
|
}
|
|
if !yaml_emitter_write_indicator(emitter, []byte(indicator), 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 {
|
|
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)
|
|
|
|
default:
|
|
panic("unknown scalar")
|
|
}
|
|
|
|
return false
|
|
}
|
|
|
|
/*
|
|
* 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; 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 {
|
|
errmsg := "alias value must not be empty"
|
|
if !alias {
|
|
errmsg = "anchor value must not be empty"
|
|
}
|
|
return yaml_emitter_set_emitter_error(emitter, errmsg)
|
|
}
|
|
|
|
for i := 0; i < len(anchor); i += width(anchor[i]) {
|
|
if !is_alpha(anchor[i]) {
|
|
errmsg := "alias value must contain alphanumerical characters only"
|
|
if !alias {
|
|
errmsg = "anchor value must contain alphanumerical characters only"
|
|
}
|
|
return yaml_emitter_set_emitter_error(emitter, errmsg)
|
|
}
|
|
}
|
|
|
|
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 := range emitter.tag_directives {
|
|
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 {
|
|
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
|
|
|
|
preceeded_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
|
|
}
|
|
|
|
preceeded_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_blankz_at(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 preceeded_by_whitespace {
|
|
flow_indicators = true
|
|
block_indicators = true
|
|
}
|
|
}
|
|
}
|
|
|
|
if !is_printable_at(value, i) || (!is_ascii(value[i]) && !emitter.unicode) {
|
|
special_characters = true
|
|
}
|
|
|
|
if is_break_at(value, i) {
|
|
line_breaks = true
|
|
}
|
|
|
|
if is_space(value[i]) {
|
|
if i == 0 {
|
|
leading_space = true
|
|
}
|
|
if i+w == len(value) {
|
|
trailing_space = true
|
|
}
|
|
if previous_break {
|
|
break_space = true
|
|
}
|
|
previous_space = true
|
|
previous_break = false
|
|
} else if is_break_at(value, i) {
|
|
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
|
|
}
|
|
|
|
preceeded_by_whitespace = is_blankz_at(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.event_type {
|
|
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] = '\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 bool,
|
|
is_whitespace bool, is_indention bool) bool {
|
|
if need_whitespace && !emitter.whitespace {
|
|
if !put(emitter, ' ') {
|
|
return false
|
|
}
|
|
}
|
|
|
|
ind_pos := 0
|
|
for ind_pos < len(indicator) {
|
|
if !write(emitter, indicator, &ind_pos) {
|
|
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 {
|
|
pos := 0
|
|
for pos < len(value) {
|
|
if !write(emitter, value, &pos) {
|
|
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
|
|
}
|
|
}
|
|
|
|
pos := 0
|
|
for pos < len(value) {
|
|
if !write(emitter, value, &pos) {
|
|
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); {
|
|
write_it := false
|
|
switch value[i] {
|
|
case ';', '/', '?', ':', '@', '&', '=', '+', '$', ',', '_',
|
|
'.', '!', '~', '*', '\'', '(', ')', '[', ']':
|
|
write_it = true
|
|
default:
|
|
write_it = is_alpha(value[i])
|
|
}
|
|
if write_it {
|
|
if !write(emitter, value, &i) {
|
|
return false
|
|
}
|
|
} else {
|
|
w := width(value[i])
|
|
for j := 0; j < w; j++ {
|
|
val := value[i]
|
|
i++
|
|
|
|
if !put(emitter, '%') {
|
|
return false
|
|
}
|
|
c := val >> 4
|
|
if c < 10 {
|
|
c += '0'
|
|
} else {
|
|
c += 'A' - 10
|
|
}
|
|
if !put(emitter, c) {
|
|
return false
|
|
}
|
|
|
|
c = val & 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 {
|
|
spaces := false
|
|
breaks := false
|
|
|
|
if !emitter.whitespace {
|
|
if !put(emitter, ' ') {
|
|
return 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_at(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 {
|
|
spaces := false
|
|
breaks := false
|
|
|
|
if !yaml_emitter_write_indicator(emitter, []byte("'"), true, false, false) {
|
|
return 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_at(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_at(value, i) || (!emitter.unicode && !is_ascii(value[i])) ||
|
|
is_bom_at(value, i) || is_break_at(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
|
|
}
|
|
|
|
switch v {
|
|
case 0x00:
|
|
if !put(emitter, '0') {
|
|
return false
|
|
}
|
|
case 0x07:
|
|
if !put(emitter, 'a') {
|
|
return false
|
|
}
|
|
case 0x08:
|
|
if !put(emitter, 'b') {
|
|
return false
|
|
}
|
|
case 0x09:
|
|
if !put(emitter, 't') {
|
|
return false
|
|
}
|
|
|
|
case 0x0A:
|
|
if !put(emitter, 'n') {
|
|
return false
|
|
}
|
|
|
|
case 0x0B:
|
|
if !put(emitter, 'v') {
|
|
return false
|
|
}
|
|
|
|
case 0x0C:
|
|
if !put(emitter, 'f') {
|
|
return false
|
|
}
|
|
|
|
case 0x0D:
|
|
if !put(emitter, 'r') {
|
|
return false
|
|
}
|
|
|
|
case 0x1B:
|
|
if !put(emitter, 'e') {
|
|
return false
|
|
}
|
|
case 0x22:
|
|
if !put(emitter, '"') {
|
|
return false
|
|
}
|
|
case 0x5C:
|
|
if !put(emitter, '\\') {
|
|
return false
|
|
}
|
|
case 0x85:
|
|
if !put(emitter, 'N') {
|
|
return false
|
|
}
|
|
|
|
case 0xA0:
|
|
if !put(emitter, '_') {
|
|
return false
|
|
}
|
|
|
|
case 0x2028:
|
|
if !put(emitter, 'L') {
|
|
return false
|
|
}
|
|
|
|
case 0x2029:
|
|
if !put(emitter, 'P') {
|
|
return false
|
|
}
|
|
default:
|
|
if v <= 0xFF {
|
|
if !put(emitter, 'x') {
|
|
return false
|
|
}
|
|
w = 2
|
|
} else if v <= 0xFFFF {
|
|
if !put(emitter, 'u') {
|
|
return false
|
|
}
|
|
w = 4
|
|
} else {
|
|
if !put(emitter, 'U') {
|
|
return false
|
|
}
|
|
w = 8
|
|
}
|
|
for k := (w - 1) * 4; k >= 0; k -= 4 {
|
|
digit := byte((v >> uint(k)) & 0x0F)
|
|
c := digit + '0'
|
|
if c > 9 {
|
|
c = digit + 'A' - 10
|
|
}
|
|
if !put(emitter, c) {
|
|
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_at(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_at(value, i) {
|
|
chomp_hint[0] = '-'
|
|
} else if i == 0 {
|
|
chomp_hint[0] = '+'
|
|
emitter.open_ended = true
|
|
} else {
|
|
for value[i]&0xC0 == 0x80 {
|
|
i--
|
|
}
|
|
|
|
if is_break_at(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 {
|
|
|
|
breaks := true
|
|
|
|
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
|
|
|
|
for i := 0; i < len(value); {
|
|
if is_break_at(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 {
|
|
breaks := true
|
|
leading_spaces := true
|
|
|
|
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
|
|
|
|
for i := 0; i < len(value); {
|
|
if is_break_at(value, i) {
|
|
if !breaks && !leading_spaces && value[i] == '\n' {
|
|
k := i
|
|
for is_break_at(value, k) {
|
|
k += width(value[k])
|
|
}
|
|
if !is_blankz_at(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
|
|
}
|