missing NULL terminator in set_config_x
[geda-gaf.git] / gschem / src / x_hierarchy.c
blob6d84180b465f8504f5f00474c3b4e76969bddfe8
1 /* gEDA - GPL Electronic Design Automation
2 * gschem - gEDA Schematic Capture
3 * Copyright (C) 1998-2010 Ales Hvezda
4 * Copyright (C) 1998-2020 gEDA Contributors (see ChangeLog for details)
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21 /*! \file x_hierarchy.c
22 * \brief Hierarchy navigation functions.
24 #include <config.h>
26 #include "gschem.h"
29 static PAGE *
30 load_source (GschemToplevel *w_current, const gchar *filename,
31 int *page_control)
33 TOPLEVEL *toplevel = gschem_toplevel_get_toplevel (w_current);
34 gchar *source_path;
35 PAGE *page;
36 PAGE *forbear;
38 g_return_val_if_fail (toplevel != NULL, NULL);
39 g_return_val_if_fail (toplevel->page_current != NULL, NULL);
40 g_return_val_if_fail (filename != NULL, NULL);
42 s_log_message (_("Searching for source [%s]\n"), filename);
43 source_path = s_slib_search_single (filename);
45 if (source_path != NULL) {
46 page = x_lowlevel_open_page (w_current, source_path);
47 g_free (source_path);
49 if (page == NULL)
50 /* Some error occurred while loading the schematic. In this case,
51 x_lowlevel_open_page already displayed an error message. */
52 return NULL;
54 /* check whether this page is in the parents list */
55 forbear = toplevel->page_current;
56 while (forbear != NULL && forbear->pid != page->pid && forbear->up >= 0)
57 forbear = s_page_search_by_page_id (toplevel->pages, forbear->up);
59 if (forbear != NULL && forbear->pid == page->pid) {
60 s_log_message (_("Failed to descend into '%s': "
61 "Hierarchy contains a circular dependency.\n"),
62 filename);
64 GtkWidget *dialog =
65 gtk_message_dialog_new (GTK_WINDOW (w_current->main_window),
66 GTK_DIALOG_MODAL, GTK_MESSAGE_ERROR,
67 GTK_BUTTONS_CLOSE,
68 _("Failed to descend into \"%s\"."), filename);
69 g_object_set (G_OBJECT (dialog), "secondary-text",
70 _("The hierarchy contains a circular dependency."), NULL);
71 gtk_window_set_title (GTK_WINDOW (dialog), _("gschem"));
72 gtk_dialog_run (GTK_DIALOG (dialog));
73 gtk_widget_destroy (dialog);
74 return NULL;
76 } else {
77 /* Has a new page with this name already been created? */
78 for (const GList *l = geda_list_get_glist(toplevel->pages);
79 l != NULL; l = l->next) {
80 PAGE *page = (PAGE *) l->data;
81 const gchar *sep = strrchr (page->page_filename, '/');
82 /* FIXME: This may not be correct on platforms with
83 case-insensitive filesystems. */
84 if (page->up == toplevel->page_current->pid && !page->is_untitled &&
85 sep != NULL && strcmp (sep + 1, filename) == 0)
86 /* page control has been set before, just return page */
87 return page;
90 if (!x_dialog_confirm_create (
91 GTK_WINDOW (w_current->main_window),
92 _("The subschematic \"%s\" doesn't appear to exist.\n\n"
93 "Do you want to create a new schematic with this name?"),
94 filename))
95 return NULL;
97 page = x_fileselect_create (w_current, s_slib_getdir (0), filename);
98 if (page == NULL)
99 return NULL;
102 if (*page_control == 0) {
103 page_control_counter++;
104 *page_control = page_control_counter;
106 page->page_control = *page_control;
107 page->up = toplevel->page_current->pid;
109 return page;
113 static GSList *
114 get_source_filenames (GschemToplevel *w_current, OBJECT *object)
116 char *attrib = NULL;
117 int count = 0;
118 int looking_inside = FALSE;
119 int pcount = 0;
120 char *current_filename = NULL;
121 GSList *filenames = NULL;
123 /* only allow going into symbols */
124 if (object->type != OBJ_COMPLEX)
125 return NULL;
127 attrib = o_attrib_search_attached_attribs_by_name (object, "source", count);
129 /* if above is null, then look inside symbol */
130 if (attrib == NULL) {
131 attrib =
132 o_attrib_search_inherited_attribs_by_name (object, "source", count);
133 looking_inside = TRUE;
136 while (attrib != NULL) {
137 /* look for source=filename,filename, ... */
138 pcount = 0;
139 current_filename = u_basic_breakup_string (attrib, ',', pcount);
141 /* loop over all filenames */
142 while (current_filename != NULL) {
143 filenames = g_slist_prepend (filenames, current_filename);
144 pcount++;
145 current_filename = u_basic_breakup_string (attrib, ',', pcount);
148 g_free (attrib);
149 g_free (current_filename);
151 count++;
152 attrib = looking_inside ?
153 o_attrib_search_inherited_attribs_by_name (object, "source", count) :
154 o_attrib_search_attached_attribs_by_name (object, "source", count);
157 return g_slist_reverse (filenames);
161 gboolean
162 x_hierarchy_down_schematic (GschemToplevel *w_current, OBJECT *object)
164 GSList *filenames = get_source_filenames (w_current, object);
165 int page_control = 0;
166 PAGE *first_page = NULL;
168 for (const GSList *l = filenames; l != NULL; l = l->next) {
169 PAGE *page = load_source (w_current, (gchar *) l->data, &page_control);
171 if (first_page == NULL)
172 first_page = page;
175 g_slist_free_full (filenames, g_free);
177 if (first_page == NULL)
178 return FALSE;
180 x_window_set_current_page (w_current, first_page);
181 return TRUE;
185 /*! \bug may cause problems with non-directory symbols */
186 gboolean
187 x_hierarchy_down_symbol (GschemToplevel *w_current, OBJECT *object)
189 TOPLEVEL *toplevel = gschem_toplevel_get_toplevel (w_current);
190 const CLibSymbol *sym;
191 gchar *filename;
192 PAGE *page;
194 /* only allow going into symbols */
195 if (object->type != OBJ_COMPLEX)
196 return FALSE;
198 if (object->complex_embedded) {
199 s_log_message (_("Cannot descend into embedded symbol!\n"));
200 return FALSE;
203 s_log_message (_("Searching for symbol [%s]\n"), object->complex_basename);
204 sym = s_clib_get_symbol_by_name (object->complex_basename);
205 if (sym == NULL)
206 return FALSE;
208 filename = s_clib_symbol_get_filename (sym);
209 if (filename == NULL) {
210 s_log_message (_("Symbol is not a real file. Symbol cannot be loaded.\n"));
211 return FALSE;
214 page = x_lowlevel_open_page (w_current, filename);
215 g_free (filename);
217 if (page == NULL)
218 /* Some error occurred while loading the symbol. In this case,
219 x_lowlevel_open_page already displayed an error message. */
220 return FALSE;
222 page_control_counter++;
223 page->page_control = page_control_counter;
224 /* change link to parent page even if the page existed since we can
225 come here from any parent and must come back to the same page */
226 page->up = toplevel->page_current->pid;
228 x_window_set_current_page (w_current, page);
229 return TRUE;
233 gboolean
234 x_hierarchy_up (GschemToplevel *w_current)
236 TOPLEVEL *toplevel = gschem_toplevel_get_toplevel (w_current);
237 PAGE *page = toplevel->page_current;
238 PAGE *parent;
239 g_return_val_if_fail (page != NULL, FALSE);
241 if (page->up < 0) {
242 s_log_message (_("There are no schematics above the current one!\n"));
243 return FALSE;
246 parent = s_page_search_by_page_id (toplevel->pages, page->up);
247 if (parent == NULL) {
248 s_log_message (_("Cannot find any schematics above the current one!\n"));
249 return FALSE;
252 if (!page->is_untitled) {
253 gchar *lowercase_filename = g_ascii_strdown (page->page_filename, -1);
254 gboolean is_symbol = g_str_has_suffix (lowercase_filename, ".sym");
255 g_free (lowercase_filename);
257 if (is_symbol && !x_highlevel_close_page (w_current, page))
258 return FALSE;
261 x_window_set_current_page (w_current, parent);
262 return TRUE;