/* * COPYRIGHT * * cschem - modular/flexible schematics editor - libcschem (core library) * Copyright (C) 2018,2022 Tibor 'Igor2' Palinkas * * (Supported by NLnet NGI0 PET Fund in 2022) * * 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 */ /* Dynamic text (dyntext) management/render */ #include "config.h" #include #include #include #include #include "abstract.h" #include "cnc_text.h" #include "cnc_grp.h" #include "cnc_text_dyn.h" #include "project.h" RND_INLINE const csch_chdr_t *get_attrib_obj(char **path, const csch_text_t *text) { const csch_chdr_t *hdr = &text->hdr; for(;;) { if (((*path)[0] == '.') && ((*path)[1] == '.') && ((*path)[2] == '/')) { if (hdr->parent != NULL) hdr = &hdr->parent->hdr; *path += 3; } else break; } return hdr; } static const char *get_filename(csch_sheet_t *sheet) { const char *sep, *fn = sheet->hidlib.fullpath; if (fn == NULL) return ""; sep = strrchr(fn, '/'); if (sep != NULL) return sep+1; /* basename */ return fn; } static const char *prj_name(const char *fullpath) { static char res[1024], *d; const char *s; for(s = rnd_parent_dir_name(fullpath), d = res; *s != '/'; s++, d++) { if ((d - res) > sizeof(res)-2) break; *d = *s; } *d = '\0'; return res; } static const char *get_prjname(csch_sheet_t *sheet) { const char *fn = sheet->hidlib.loadname; csch_project_t *prj = NULL; htsp_entry_t *e; if ((fn == NULL) || (fn[0] == '<')) return " (save sheet!)"; prj = (csch_project_t *)sheet->hidlib.project; if (prj == NULL) return " (no project)"; if (prj->hdr.fullpath != NULL) return prj_name(prj->hdr.fullpath); for(e = htsp_first(&rnd_projects); e != NULL; e = htsp_next(&rnd_projects, e)) if (prj == e->value) return prj_name(e->key); return " (unnamed prj)"; } static const char *dyntext_get_attr_val(const csch_attribs_t *attrs, const char *key) { const char *val = csch_attrib_get_str(attrs, key); if (val == NULL) { const vts0_t *arr = csch_attrib_get_arr(attrs, key); if (arr != NULL) { if (arr->used == 1) val = arr->array[0]; else val = ""; } } return val; } static int csch_text_render_str_cb(void *ctx, gds_t *s, const char **input) { const csch_text_t *text = ctx; const csch_attribs_t *attrs = NULL; const csch_chdr_t *agrp; char *end, key[128], *path; const char *val = NULL; size_t len; end = strchr(*input, '%'); len = end - *input; if (len > sizeof(key)-1) return -1; strncpy(key, *input, len); key[len] = '\0'; *input += len+1; if (strcmp(key, "filename") == 0) { val = get_filename(text->hdr.sheet); goto append; } if (strcmp(key, "project.name") == 0) { val = get_prjname(text->hdr.sheet); goto append; } if (strncmp(key, "stance.", 7) == 0) { val = csch_stance_get(key+7); goto append; } if (strncmp(key, "view.", 5) == 0) { val = csch_view_get_prop((csch_project_t *)text->hdr.sheet->hidlib.project, -1, key+5); goto append; } path = key; agrp = get_attrib_obj(&path, text); if ((path[0] == 'A') && (path[1] == '.')) { if (agrp != NULL) { csch_cgrp_t *g = (csch_cgrp_t *)agrp; attrs = &g->attr; } path+=2; if (attrs != NULL) { val = dyntext_get_attr_val(attrs, path); goto append; } } else if ((path[0] == 'a') && (path[1] == '.')) { int hier_idx = 0; csch_ahdr_t *a = NULL; path+=2; TODO("hierarchic: provide a spinbox next to the view name for selecting hier_idx here instead of hardwiring 0"); if (agrp != NULL) { assert(csch_obj_is_grp(agrp)); a = csch_cgrp_get_abstract(text->hdr.sheet, (const csch_cgrp_t *)agrp, hier_idx); } if (a != NULL) attrs = &a->attr; if (attrs != NULL) { val = dyntext_get_attr_val(attrs, path); goto append; } } return 0; append:; if (val != NULL) gds_append_str(s, val); return 0; } void csch_text_dyntext_inval(csch_text_t *text) { free(text->rtext); text->rtext = NULL; } void csch_text_dyntext_render(csch_text_t *text) { const char *empty = "\001"; csch_text_dyntext_inval(text); if (text->dyntext) { gds_t tmp = {0}; rnd_subst_append(&tmp, text->text, csch_text_render_str_cb, (void *)text, RND_SUBST_PERCENT | RND_SUBST_CONF, 0); if ((tmp.array == NULL) || (*tmp.array == '\0')) { text->rtext = rnd_strdup(empty); gds_uninit(&tmp); } else text->rtext = tmp.array; } else { if ((text->text == NULL) || (*text->text == '\0')) text->rtext = rnd_strdup(empty); else text->rtext = rnd_strdup(text->text); } }