Mercurial > libjeffpc
view sexpr_dump.c @ 794:d018af7c979c
slab: make struct mem_cache private
Signed-off-by: Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
author | Josef 'Jeff' Sipek <jeffpc@josefsipek.net> |
---|---|
date | Sun, 15 Mar 2020 15:52:09 +0200 |
parents | b1e4c7607050 |
children | c4e75447a4df |
line wrap: on
line source
/* * Copyright (c) 2015-2018 Josef 'Jeff' Sipek <jeffpc@josefsipek.net> * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ #include <stdio.h> #include <ctype.h> #include <jeffpc/sexpr.h> #include "sexpr_impl.h" static struct str *do_sexpr_dump(struct val *lv, bool raw, bool wrap); static char *escape_str(const char *in) { char *out, *tmp; const char *s; size_t outlen; outlen = strlen(in); for (s = in; *s; s++) { char c = *s; switch (c) { case '\n': case '\t': case '\r': case '\b': case '\f': case '\\': case '"': /* "\n", "\t", ... */ outlen++; break; } } out = malloc(outlen + 1); if (!out) return NULL; for (s = in, tmp = out; *s; s++, tmp++) { unsigned char c = *s; switch (c) { case '\n': strcpy(tmp, "\\n"); tmp++; break; case '\t': strcpy(tmp, "\\t"); tmp++; break; case '\r': strcpy(tmp, "\\r"); tmp++; break; case '\b': strcpy(tmp, "\\b"); tmp++; break; case '\f': strcpy(tmp, "\\f"); tmp++; break; case '\\': strcpy(tmp, "\\\\"); tmp++; break; case '"': strcpy(tmp, "\\\""); tmp++; break; default: *tmp = c; break; } } *tmp = '\0'; return out; } static struct str *dump_atom(struct val *lv) { static struct str dquote = STR_STATIC_CHAR_INITIALIZER('"'); static struct str null = STR_STATIC_INITIALIZER("#n"); static struct str poundt = STR_STATIC_INITIALIZER("#t"); static struct str poundf = STR_STATIC_INITIALIZER("#f"); struct str *tmp; switch (lv->type) { case VT_SYM: return str_dup(val_cstr(lv)); case VT_STR: tmp = str_alloc(escape_str(val_cstr(lv))); if (IS_ERR(tmp)) return tmp; return str_cat(3, &dquote, tmp, &dquote); case VT_NULL: return &null; case VT_BOOL: return lv->b ? £t : £f; case VT_CHAR: if (lv->i == '\0') return STATIC_STR("#\\nul"); else if (lv->i == ' ') return STATIC_STR("#\\space"); else if (isprint(lv->i)) return str_printf("#\\%c", (char) lv->i); else return str_printf("#\\u%04"PRIX64, lv->i); case VT_INT: return str_printf("%"PRIu64, lv->i); case VT_CONS: panic("%s: VT_CONS is not an atom", __func__); case VT_BLOB: case VT_ARRAY: case VT_NVL: return ERR_PTR(-ENOTSUP); } panic("%s: unknown val type: %u", __func__, lv->type); } static inline int dump_cons_parts(struct val *head, struct str **hstr, struct val *tail, struct str **tstr, bool raw) { struct str *h, *t; /* pacify gcc */ *hstr = NULL; *tstr = NULL; /* the head needs to always be wrapped */ h = do_sexpr_dump(head, raw, true); if (IS_ERR(h)) return PTR_ERR(h); /* the tail needs to be wrapped only when dumping raw */ t = do_sexpr_dump(tail, raw, raw); if (IS_ERR(t)) { str_putref(h); return PTR_ERR(t); } *hstr = h; *tstr = t; return 0; } static struct str *dump_cons_pretty_quote(struct val *lv) { static struct str squote = STR_STATIC_CHAR_INITIALIZER('\''); struct str *tmp; tmp = do_sexpr_dump(lv, false, false); if (IS_ERR(tmp)) return tmp; return str_cat(2, &squote, tmp); } static struct str *dump_cons_pretty(struct val *lv, bool wrap) { static struct str oparen = STR_STATIC_CHAR_INITIALIZER('('); static struct str cparen = STR_STATIC_CHAR_INITIALIZER(')'); static struct str dot = STR_STATIC_INITIALIZER(" . "); static struct str space = STR_STATIC_INITIALIZER(" "); struct val *head = lv->cons.head; struct val *tail = lv->cons.tail; struct str *hstr; struct str *tstr; struct str *tmp; int ret; ASSERT(!sexpr_is_null(lv)); ASSERT3U(lv->type, ==, VT_CONS); if (head && (head->type == VT_SYM) && !strcmp(val_cstr(head), "quote")) /* * quote . tail -> 'tail * * note: we don't wrap */ return dump_cons_pretty_quote(tail); ret = dump_cons_parts(head, &hstr, tail, &tstr, false); if (ret) return ERR_PTR(ret); if (sexpr_is_null(tail)) { /* head . () -> head */ str_putref(tstr); tmp = hstr; } else if (tail->type == VT_CONS) { /* head . (x . y) -> head x . y */ tmp = str_cat(3, hstr, &space, tstr); } else { /* head . tail -> head . tail */ tmp = str_cat(3, hstr, &dot, tstr); } return wrap ? str_cat(3, &oparen, tmp, &cparen) : tmp; } static struct str *dump_cons_raw(struct val *lv) { static struct str oparen = STR_STATIC_CHAR_INITIALIZER('('); static struct str cparen = STR_STATIC_CHAR_INITIALIZER(')'); static struct str dot = STR_STATIC_INITIALIZER(" . "); struct str *hstr; struct str *tstr; int ret; ret = dump_cons_parts(lv->cons.head, &hstr, lv->cons.tail, &tstr, true); if (ret) return ERR_PTR(ret); return str_cat(5, &oparen, hstr, &dot, tstr, &cparen); } static struct str *do_sexpr_dump(struct val *lv, bool raw, bool wrap) { static struct str empty = STR_STATIC_INITIALIZER("()"); if (sexpr_is_null(lv)) return ∅ switch (lv->type) { case VT_SYM: case VT_STR: case VT_NULL: case VT_BOOL: case VT_CHAR: case VT_INT: case VT_BLOB: case VT_ARRAY: case VT_NVL: return dump_atom(lv); case VT_CONS: if (raw) return dump_cons_raw(lv); return dump_cons_pretty(lv, wrap); } panic("%s: unknown val type: %u", __func__, lv->type); } struct str *sexpr_dump(struct val *lv, bool raw) { return do_sexpr_dump(lv, raw, true); } int sexpr_dump_file(FILE *out, struct val *lv, bool raw) { struct str *tmp; tmp = sexpr_dump(lv, raw); if (IS_ERR(tmp)) return PTR_ERR(tmp); fprintf(out, "%s", str_cstr(tmp)); str_putref(tmp); return 0; }