/* * 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 netname for v/netname in all hlev parents. Return NULL if not found. */ RND_INLINE csch_anet_t *net_search_subtree_up(csch_abstract_t *abs, csch_hlevel_t *hlev, const char *netname) { for(hlev = hlev->parent; hlev != NULL; hlev = hlev->parent) { csch_anet_t *net = htsp_get(&hlev->nets, netname); if ((net != NULL) && (net->scope == CSCH_ASCOPE_SUBTREE_LOCAL)) return net; } return NULL; } csch_anet_t *csch_anet_get_at(csch_abstract_t *abs, csch_hlevel_t *hlev, csch_ascope_t scope, const char *netname) { csch_anet_t *net = NULL; csch_ascope_t prefix_scope; const char *orig_name = netname; prefix_scope = csch_split_name_scope(&netname); if (scope != CSCH_ASCOPE_unknown) { if ((prefix_scope != CSCH_ASCOPE_AUTO) && (prefix_scope != scope)) { rnd_message(RND_MSG_ERROR, "Failed to resolve net '%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/ nets */ if (hlev != NULL) { net = htsp_get(&hlev->nets, netname); if (net != NULL) return net; net = net_search_subtree_up(abs, hlev, netname); if (net != NULL) return net; } return htsp_get(&abs->nets, netname); /* fall back to global */ case CSCH_ASCOPE_GLOBAL: return htsp_get(&abs->nets, netname); case CSCH_ASCOPE_SHEET_LOCAL: return htsp_get(&hlev->nets, netname); 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 net searching upward */ return htsp_get(&hlev->nets, netname); case CSCH_ASCOPE_SUBTREE_AUTO: /* The ^/ prefix */ if (hlev == NULL) { rnd_message(RND_MSG_ERROR, "Failed to resolve net '%s': scope requires hierarchy which is not available\n", orig_name); return NULL; } /* search on sheet local and parents for v/ nets */ return net_search_subtree_up(abs, hlev, netname); case CSCH_ASCOPE_unknown: rnd_message(RND_MSG_ERROR, "Failed to resolve net '%s': unknown scope\n", orig_name); return NULL; } return NULL; } csch_anet_t *csch_anet_get(csch_abstract_t *abs, const char *netname) { return csch_anet_get_at(abs, NULL, CSCH_ASCOPE_unknown, netname); } csch_anet_t *csch_anet_new(csch_abstract_t *abs, csch_hlevel_t *hlev, csch_ascope_t scope, const char *name_glob, const char *name_loc, int set_no_uname) { csch_anet_t *net = calloc(sizeof(csch_anet_t), 1); int short_name; if (scope == CSCH_ASCOPE_SUBTREE_AUTO) { rnd_message(RND_MSG_ERROR, "Can not find subtree-local net v/%s\n", name_loc); return NULL; } /* create global nets 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, &net->hdr, CSCH_ATYPE_NET); net->name = rnd_strdup(short_name ? name_loc : name_glob); net->name_loc = rnd_strdup(name_loc); net->no_uname = set_no_uname; net->hlev = hlev; net->hdepth = (hlev == NULL) ? 0 : hlev->hdepth; htsp_set(&abs->nets, net->name, net); 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->nets, net->name_loc, net); break; case CSCH_ASCOPE_SUBTREE_AUTO: return NULL; /* can't get here */ } } net->scope = scope; return net; }