DMS-Parser-XS
view release on metacpan or search on metacpan
vendor/dms-c/dms.c view on Meta::CPAN
snprintf(tmp, sizeof tmp, "\\u%04X", c);
emit_push(e, tmp);
} else {
emit_push_ch(e, (char)c);
}
}
}
static void emit_format_key(emitter *e, const char *k) {
if (key_is_bare(k)) {
emit_push(e, k);
return;
}
bool has_sq = strchr(k, '\'') != NULL;
bool has_nl = strchr(k, '\n') != NULL || strchr(k, '\r') != NULL;
if (!has_sq && !has_nl) {
emit_push_ch(e, '\'');
emit_push(e, k);
emit_push_ch(e, '\'');
} else {
emit_push_ch(e, '"');
emit_escape_basic(e, k);
emit_push_ch(e, '"');
}
}
/* ---- forward decls ---- */
static void emit_document_body(emitter *e);
static void emit_table_block(emitter *e, const dms_table *t,
const dms_breadcrumb_seg *path, size_t path_len,
size_t indent);
static void emit_list_block(emitter *e, const dms_list *l,
const dms_breadcrumb_seg *path, size_t path_len,
size_t indent);
static void emit_value_inline(emitter *e, const dms_value *v,
const dms_breadcrumb_seg *path, size_t path_len);
static void emit_integer(emitter *e, int64_t n,
const dms_breadcrumb_seg *path, size_t path_len);
static void emit_string(emitter *e, const char *s,
const dms_breadcrumb_seg *path, size_t path_len);
static void emit_heredoc(emitter *e, const char *body,
dms_heredoc_flavor flavor, const char *label,
const dms_heredoc_modifier_call *mods, size_t nmods);
static void emit_modifier_arg(emitter *e, const dms_value *v);
static void emit_comment_line(emitter *e, const dms_attached_comment *ac, size_t indent);
static void emit_trailing_for(emitter *e, const dms_breadcrumb_seg *path, size_t path_len);
static void emit_floating_for(emitter *e, const dms_breadcrumb_seg *path, size_t path_len, size_t indent);
static void emit_leading_for(emitter *e, const dms_breadcrumb_seg *path, size_t path_len, size_t indent);
static bool has_trailing_for(const emitter *e, const dms_breadcrumb_seg *path, size_t path_len);
static bool is_flow_safe(const emitter *e, const dms_value *v,
const dms_breadcrumb_seg *path, size_t path_len);
static const dms_original_literal *find_form(const emitter *e,
const dms_breadcrumb_seg *path, size_t path_len);
/* Build + sort index arrays. In lite mode, both lookup arrays are
left NULL so every `find_first_match` short-circuits â comments are
dropped, integer base / string flavor fall back to canonical form. */
static void emitter_init(emitter *e, const dms_document *doc, bool lite) {
buf_init(&e->out);
buf_ensure(&e->out, 64 * 1024); /* pre-size: skip realloc cascade on typical-sized configs */
e->doc = doc;
e->comments_sorted = NULL;
e->forms_sorted = NULL;
e->path_buf = NULL;
e->path_buf_cap = 0;
e->lite = lite;
if (lite) return;
if (doc->num_comments > 0) {
e->comments_sorted = (size_t *)malloc(doc->num_comments * sizeof(size_t));
for (size_t i = 0; i < doc->num_comments; i++) e->comments_sorted[i] = i;
sort_ctx ctx; ctx.doc = doc; ctx.is_form = 0;
sort_indices(e->comments_sorted, doc->num_comments, ctx);
}
if (doc->num_original_forms > 0) {
e->forms_sorted = (size_t *)malloc(doc->num_original_forms * sizeof(size_t));
for (size_t i = 0; i < doc->num_original_forms; i++) e->forms_sorted[i] = i;
sort_ctx ctx; ctx.doc = doc; ctx.is_form = 1;
sort_indices(e->forms_sorted, doc->num_original_forms, ctx);
}
}
static void emitter_free(emitter *e) {
free(e->comments_sorted);
free(e->forms_sorted);
free(e->path_buf);
}
/* Grow the shared breadcrumb buffer to fit at least `need` segments.
Used by emit_table_block / emit_list_block / emit_value_inline so they
no longer malloc/free a fresh path per kvpair. */
static void path_ensure(emitter *e, size_t need) {
if (need <= e->path_buf_cap) return;
size_t newcap = e->path_buf_cap ? e->path_buf_cap * 2 : 16;
while (newcap < need) newcap *= 2;
e->path_buf = (dms_breadcrumb_seg *)xrealloc(e->path_buf, newcap * sizeof(dms_breadcrumb_seg));
e->path_buf_cap = newcap;
}
/* Look up the first OriginalLiteral whose path equals (path, path_len). */
static const dms_original_literal *find_form(const emitter *e,
const dms_breadcrumb_seg *path, size_t path_len) {
size_t idx = find_first_match(e, 1, path, path_len);
if (idx == (size_t)-1) return NULL;
size_t src_idx = e->forms_sorted[idx];
return &e->doc->original_forms[src_idx].lit;
}
/* ---- comment helpers ---- */
static bool has_trailing_for(const emitter *e, const dms_breadcrumb_seg *path, size_t path_len) {
size_t first = find_first_match(e, 0, path, path_len);
if (first == (size_t)-1) return false;
for (size_t i = first; i < e->doc->num_comments; i++) {
const dms_attached_comment *ac = &e->doc->comments[e->comments_sorted[i]];
if (cmp_path(ac->path, ac->path_len, path, path_len) != 0) break;
if (ac->position == DMS_COMMENT_TRAILING) return true;
}
return false;
}
( run in 1.311 second using v1.01-cache-2.11-cpan-40ba7b3775d )