/* * COPYRIGHT * * cschem - modular/flexible schematics editor - libcschem (core library) * Copyright (C) 2020 Tibor 'Igor2' Palinkas * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version.* * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 31 Milk Street, # 960789 Boston, MA 02196 USA * * Contact: * Project page: http://repo.hu/projects/sch-rnd * contact lead developer: http://www.repo.hu/projects/sch-rnd/contact.html * mailing list: http://www.repo.hu/projects/sch-rnd/contact.html */ #include "config.h" #include #include #include #include #include #include "cnc_any_obj.h" #include "engine.h" #include "project.h" #include "util_parse.h" /*** load_cache low levels ***/ /* called when the file is first loaded; should allocate (ldch_file_t *) */ static ldch_file_t *ldlht_parse_alloc(ldch_low_parser_t *parser, void *call_ctx, const char *fn) { return ldch_file_alloc(parser->ctx, parser, sizeof(lht_doc_t *)); } /* called after parse_alloc() on initial load or after free_payload() on reload */ static int ldlht_parse(ldch_low_parser_t *parser, void *call_ctx, ldch_file_t *file, const char *fn) { char *errmsg; lht_doc_t **payload = (lht_doc_t **)&file->low_payload; *payload = lht_dom_load(fn, &errmsg); if (*payload == NULL) { rnd_message(RND_MSG_ERROR, "Failed to parse lihata file '%s': %s\n", fn, errmsg); return -1; } return 0; } /* should free the in-memory document/parse-tree; a call to parse() may follow when reloading */ static void ldlht_free_payload(ldch_low_parser_t *low, ldch_file_t *file) { lht_doc_t **payload = (lht_doc_t **)&file->low_payload; if (*payload != NULL) lht_dom_uninit(*payload); } lht_doc_t *ldch_lht_get_doc(ldch_file_t *file) { lht_doc_t **payload = (lht_doc_t **)&file->low_payload; return *payload; } ldch_low_parser_t *ldch_lht_reg_low_parser(ldch_ctx_t *ctx) { ldch_low_parser_t *p = ldch_reg_low_parser(ctx, "lihata"); p->parse_alloc = ldlht_parse_alloc; p->parse = ldlht_parse; p->free_payload = ldlht_free_payload; return p; } /*** lihata parsers ***/ static void csch_lht_parse_attribs_val(csch_sheet_t *sheet, csch_cgrp_t *dstg, csch_attribs_t *dsta, const char *key, lht_node_t *n, void (*error)(void *ectx, lht_node_t *n, const char *msg), void *ectx, int prio) { lht_node_t *i, *np, *nv; long idx; const char *val; csch_source_arg_t *src; if (dstg != NULL) { assert(csch_obj_is_grp(&dstg->hdr)); } switch(n->type) { case LHT_TEXT: /* plain text: scalar attrib */ val = n->data.text.value; src = csch_attrib_src_c(n->file_name, n->line, n->col, NULL); if (dstg != NULL) csch_cobj_attrib_set(sheet, dstg, prio, key, val, src); else csch_attrib_set(dsta, prio, key, val, src, NULL); break; case LHT_LIST: /* array attrib */ /* first create the attribute as an empty array, just in case it is indeed an empty arrya with no child */ src = csch_attrib_src_c(n->file_name, n->line, n->col, NULL); if (dstg != NULL) csch_cobj_attrib_set(sheet, dstg, prio, key, NULL, src); else csch_attrib_set(dsta, prio, key, NULL, src, NULL); for(i = n->data.list.first, idx = 0; i != NULL; i = i->next) { if (i->type != LHT_TEXT) { error(ectx, i, "invalid node type for an attribute list item"); continue; } val = i->data.text.value; src = csch_attrib_src_c(i->file_name, i->line, i->col, NULL); if (dstg != NULL) csch_cobj_attrib_seti(sheet, dstg, prio, key, idx, val, src); else csch_attrib_seti(dsta, prio, key, idx, val, src, NULL); idx++; } break; case LHT_HASH: /* subtree with explicit prio value */ nv = lht_dom_hash_get(n, "value"); if (nv == NULL) { error(ectx, n, "missing attribute value subtree"); return; } if ((nv->type != LHT_TEXT) && (nv->type != LHT_LIST)) { error(ectx, n, "wrong attribute value subtree type (must be text or list)"); return; } np = lht_dom_hash_get(n, "prio"); if (np != NULL) { if (np->type == LHT_TEXT) { char *end; prio = strtol(np->data.text.value, &end, 10); if (*end != '\0') { error(ectx, n, "prio value is not integer"); return; } if ((prio < 0) || (prio > 32767)) { error(ectx, n, "attribute prio is out of range"); return; } } else { error(ectx, n, "wrong attribute prio type (must be text)"); return; } } csch_lht_parse_attribs_val(sheet, dstg, dsta, key, nv, error, ectx, prio); break; default: error(ectx, n, "invalid node type for an attribute"); } } int csch_lht_parse_attribs_(csch_sheet_t *sheet, csch_chdr_t *dsth, csch_attribs_t *dsta, lht_node_t *subtree, void (*error)(void *ectx, lht_node_t *n, const char *msg), void *ectx) { lht_node_t *n; lht_dom_iterator_t it; csch_cgrp_t *dstg = (csch_cgrp_t *)dsth; if ((subtree == NULL) || (subtree->type != LHT_HASH)) return 0; if (dstg != NULL) { assert(csch_obj_is_grp(dsth)); assert(dstg->extobj_inhibit >= 0); dstg->extobj_inhibit++; } for(n = lht_dom_first(&it, subtree); n != NULL; n = lht_dom_next(&it)) csch_lht_parse_attribs_val(sheet, dstg, dsta, n->name, n, error, ectx, CSCH_ATP_USER_DEFAULT); if (dstg != NULL) { dstg->extobj_inhibit--; assert(dstg->extobj_inhibit >= 0); } return 0; } int csch_lht_parse_attribs(csch_attribs_t *dst, lht_node_t *subtree, void (*error)(void *ectx, lht_node_t *n, const char *msg), void *ectx) { return csch_lht_parse_attribs_(NULL, NULL, dst, subtree, error, ectx); } static lht_node_t *csch_view2lht_engines_in_(lht_node_t *nv, const csch_view_t *view) { lht_node_t *ne, *neng, *nd; long n; ne = lht_dom_node_alloc(LHT_LIST, "engines"); lht_dom_hash_put(nv, ne); for(n = 0; n < view->engines.used; n++) { csch_view_eng_t *e = view->engines.array[n]; neng = lht_dom_node_alloc(LHT_HASH, e->obj->name); lht_dom_list_append(ne, neng); nd = lht_dom_node_alloc(LHT_TEXT, "plugin"); nd->data.text.value = rnd_strdup(e->obj->engine->name); lht_dom_hash_put(neng, nd); if (e->options != NULL) { nd = lht_dom_node_alloc(LHT_TEXT, "options"); nd->data.text.value = rnd_strdup(e->options); lht_dom_hash_put(neng, nd); } } return nv; } lht_node_t *csch_view2lht_in(lht_node_t *nv, const csch_view_t *view) { lht_node_t *old; /* purge old nodes under nv so they can be replaced with newly allocated */ old = lht_dom_hash_get(nv, "engines"); if (old != NULL) lht_tree_del(old); return csch_view2lht_engines_in_(nv, view); } lht_node_t *csch_view2lht(const csch_view_t *view) { lht_node_t *nv = lht_dom_node_alloc(LHT_HASH, view->fgw_ctx.name); return csch_view2lht_engines_in_(nv, view); }