/* * COPYRIGHT * * cschem - modular/flexible schematics editor - libcschem (core library) * Copyright (C) 2024 Tibor 'Igor2' Palinkas * * (Supported by NLnet NGI0 Entrust in 2023) * * 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 */ /* included from abstract.c */ /* Search component for v/name in all hlev parents. Return NULL if not found. */ RND_INLINE csch_acomp_t *comp_search_subtree_up(csch_abstract_t *abs, csch_hlevel_t *hlev, const char *name) { for(hlev = hlev->parent; hlev != NULL; hlev = hlev->parent) { csch_acomp_t *comp = htsp_get(&hlev->comps, name); if ((comp != NULL) && (comp->scope == CSCH_ASCOPE_SUBTREE_LOCAL)) return comp; } return NULL; } csch_acomp_t *csch_acomp_get_at(csch_abstract_t *abs, csch_hlevel_t *hlev, csch_ascope_t scope, const char *name) { csch_acomp_t *comp = NULL; csch_ascope_t prefix_scope; const char *orig_name = name; if (name == NULL) return NULL; prefix_scope = csch_split_name_scope(&name); if (scope != CSCH_ASCOPE_unknown) { if ((prefix_scope != CSCH_ASCOPE_AUTO) && (prefix_scope != scope)) { rnd_message(RND_MSG_ERROR, "Failed to resolve component '%s': conflicting scopes\n", orig_name); return NULL; } } else scope = prefix_scope; switch(scope) { case CSCH_ASCOPE_AUTO: /* first search on sheet local and parents for v/ components */ if (hlev != NULL) { comp = htsp_get(&hlev->comps, name); if (comp != NULL) return comp; comp = comp_search_subtree_up(abs, hlev, name); if (comp != NULL) return comp; } return htsp_get(&abs->comps, name); /* fall back to global */ case CSCH_ASCOPE_GLOBAL: return htsp_get(&abs->comps, name); case CSCH_ASCOPE_SHEET_LOCAL: return htsp_get(&hlev->comps, name); case CSCH_ASCOPE_SUBTREE_LOCAL: /* search in sheet only so that multuple v/foo are merged together; sub-sheets are compiled later so they can find this comp searching upward */ return htsp_get(&hlev->comps, name); case CSCH_ASCOPE_SUBTREE_AUTO: /* The ^/ prefix */ if (hlev == NULL) { rnd_message(RND_MSG_ERROR, "Failed to resolve component '%s': scope requires hierarchy which is not available\n", orig_name); return NULL; } /* search on sheet local and parents for v/ comps */ return comp_search_subtree_up(abs, hlev, name); case CSCH_ASCOPE_unknown: rnd_message(RND_MSG_ERROR, "Failed to resolve component '%s': unknown scope\n", orig_name); return NULL; } return NULL; } csch_acomp_t *csch_acomp_get(csch_abstract_t *abs, const char *name) { return csch_acomp_get_at(abs, NULL, CSCH_ASCOPE_unknown, name); } csch_acomp_t *csch_acomp_new(csch_abstract_t *abs, csch_hlevel_t *hlev, csch_ascope_t scope, const char *name_glob, const char *name_loc) { csch_acomp_t *comp = calloc(sizeof(csch_acomp_t), 1); int short_name; if (scope == CSCH_ASCOPE_SUBTREE_AUTO) { rnd_message(RND_MSG_ERROR, "Can not find subtree-local component v/%s\n", name_loc); return NULL; } /* create global comps with the short name; AUTO is taken GLOBAL: if we got here no other binding worked for it */ short_name = (scope == CSCH_ASCOPE_GLOBAL) || (scope == CSCH_ASCOPE_AUTO); csch_aobj_init(abs, &comp->hdr, CSCH_ATYPE_COMP); comp->name = rnd_strdup(short_name ? name_loc : name_glob); comp->name_loc = rnd_strdup(name_loc); comp->scope = scope; comp->hlev = hlev; comp->hdepth = hlev->hdepth; htsp_init(&comp->ports, strhash, strkeyeq); htsp_set(&abs->comps, comp->name, comp); if (hlev != NULL) { switch(scope) { case CSCH_ASCOPE_AUTO: /* if we got here, we are adding it as global */ case CSCH_ASCOPE_GLOBAL: case CSCH_ASCOPE_unknown: break; /* has no impact on local */ case CSCH_ASCOPE_SUBTREE_LOCAL: case CSCH_ASCOPE_SHEET_LOCAL: htsp_set(&hlev->comps, comp->name_loc, comp); break; case CSCH_ASCOPE_SUBTREE_AUTO: return NULL; /* can't get here */ } } return comp; }