1 /* gEDA - GPL Electronic Design Automation
2 * gattrib -- gEDA component and net attribute manipulation using spreadsheet.
3 * Copyright (C) 2003-2010 Stuart D. Brorson.
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA
23 * \section sdb_notes SDB's original comment in gattrib.c
25 * In the spirit of open source/free software, major sections of
26 * gattrib's code were borrowed from other sources, and hacked
27 * together by SDB in Dec. 2003. Particularly rich sources for code were
28 * gEDA/gnetlist, and the gtkextra program testgtksheet.c. Thanks to their
29 * authors for providing the foundation upon which this is built.
31 * Of course, I *did* write major portions of the code too . . . . .
32 * Some documentation about the internal operation of this program can be
33 * found in the "NOTES" file in the gattrib top-level directory.
34 * -- SDB December 2003 -
36 * \section ml_notes Architecture
38 * (extracted from SDB's mailing list posting:
39 * http://osdir.com/ml/cad.geda.devel/2007-06/msg00282.html - believed to
42 * gattrib has three major components:
44 * -# It manipulates objects held in the TOPLEVEL data structure. It
45 * does this by importing structs and functions from libgeda.
46 * -# Gattrib defines its own layer of structs, notably SHEET_DATA,
47 * which holds a table of attrib name=value pairs, and also holds a
48 * couple of linked lists corresponding to all component's refdeses, and
49 * to all attribute names found in the design. This stuff is native to
51 * -# Gattrib uses a spreadsheet widget called GtkSheet. This stuff
52 * came from the GtkExtra project, which at one time offered a bunch of
53 * interesting widgets for graphing and visualization. I think they're
54 * still around; you can do a Google search for them. I stole the two
55 * .h files defining the spreadsheet widgets, and also stole code from
56 * the program itself to implement the run-time functions which deal with
59 * When run, gattrib does this:
61 * -# It uses libgeda functions to read in your design, and fill up the
63 * -# It then loops over everything in TOPLEVEL and fills out the refdes
64 * list and the attribute name list. It sticks these into a STRING_LIST
65 * which is associated with the SHEET_DATA struct.
66 * -# Then, knowing all the refdeses and all the attribute names, it
67 * creates a TABLE data struct (a member of SHEET_DATA), and loops over
68 * each cell in the TABLE. For each cell, it queries TOPLEVEL for the
69 * corresponding name=value pair, and sticks the value in the TABLE.
70 * -# When done with that, it then creates a GtkSheet and populates it
71 * by looping over TABLE.
72 * -# Then it turns over control to the user, who can manipulate the
73 * GtkSheet. As the user adds and deletes values from the GtkSheet, the
74 * values are stored locally there. The GtkSheet is the master
75 * repository of all attributes at that point; the other data structures
78 * Saving out a design is similar, except the process runs in reverse:
80 * -# The program loops over all cells in GtkSheet, and sticks the
81 * values found into SHEET_DATA. Handling issues like added/deleted
82 * columns happens first at the GtkSheet, and then to SHEET_DATA and
83 * TOPLEVEL. I've kind of forgotten how I implemented these feaures,
85 * -# Then, the program loops over the cells in SHEET_DATA, and updates
86 * the attributes in TOPLEVEL using functions from libgeda, as well as by
87 * reaching directly into the TOPLEVEL data structure (a software
88 * engineering no-no). If a previously existing attrib has been removed,
89 * then it is removed from TOPLEVEL. If a new attrib has been attached
90 * to a component, then it is added to TOPLEVEL.
91 * -# Then the design is saved out using the save function from
94 * Therefore, think of SHEET_DATA and the other gattrib data structures
95 * as a thin layer between GtkSheet and TOPLEVEL. The gattrib data
96 * structures are used basically for convenience while trying to build or
97 * update either of the two other, more important data structures.
109 /*------------------------------------------------------------------*/
110 /* Includes originally from testgtksheet -- stuff needed to deal with
111 * spreadsheet widget.
112 *------------------------------------------------------------------*/
117 #include <gdk/gdkkeysyms.h>
120 #include <glib-object.h>
126 /*------------------------------------------------------------------*/
127 /* Gattrib specific includes -- stuff dealing with gattrib data structs.
128 *------------------------------------------------------------------*/
129 #include <libgeda/libgeda.h> /* geda library fcns */
130 #include "../include/struct.h" /* typdef and struct declarations */
131 #include "../include/prototype.h" /* function prototypes */
132 #include "../include/globals.h"
134 #ifdef HAVE_LIBDMALLOC
138 /*------------------------------------------------------------------*/
139 /*! \brief GTK callback to quit the program.
141 * This is called when the user quits the program using the UI. The
142 * callback is attached to the GTK window_delete event in
143 * x_window_init() and attached to the File->Quit menu item in
144 * x_window_create_menu(). On execution, the function checks for
145 * unsaved changes before calling gattrib_quit() to quit the program.
147 * \return value 0 to the shell to denote a successful quit.
149 gboolean
gattrib_really_quit(void)
151 if (sheet_head
->CHANGED
== TRUE
) {
152 x_dialog_unsaved_data();
159 /*------------------------------------------------------------------*/
160 /*! \brief Quit the program.
162 * Unconditionally quit gattrib. Flushes caches and I/O channels,
163 * calls the GTK function to quit the application then calls exit()
164 * with the appropriate return code.
166 * \param return_code Value to pass to the exit() system call.
168 gint
gattrib_quit(gint return_code
)
170 /* s_clib_cache_free(); */
173 /* s_rename_destroy_all(); */
177 printf("In gattrib_quit, calling gtk_main_quit()\n");
183 /*------------------------------------------------------------------*/
184 /*! \brief The "real" main for gattrib.
186 * This is the main program body for gattrib. A pointer to this
187 * function is passed to scm_boot_guile() at startup.
190 * - initialises threading, if the underlying GTK library is threaded.
191 * However, gattrib itself isn't threaded.
192 * - initialises libgeda;
193 * - parses the command line;
195 * - registers the Scheme functions with Guile;
196 * - parses the RC files;
197 * - initialises the GTK UI;
198 * - populates the spreadsheet data structure;
199 * - calls gtk_main() to start the event loop.
202 * \param argc Number of command line arguments
203 * \param argv Command line arguments
205 void gattrib_main(void *closure
, int argc
, char *argv
[])
207 /* TOPLEVEL *pr_current is a global */
208 /* SHEET_DATA *sheet_head is a global */
209 /* GtkWidget *main_window is a global */
214 /* Gattrib isn't threaded, but some of GTK's file chooser
215 * backends uses threading so we need to call g_thread_init().
216 * GLib requires threading be initialised before any other GLib
217 * functions are called. Do it now if its not already setup. */
218 if (!g_thread_supported ())
219 g_thread_init (NULL
);
222 /* Initialize gEDA stuff */
225 /* Ensure object->sel_func can be used to correctly determine object
226 * locking when the project is saved out */
227 select_func
= s_toplevel_select_object
;
229 /* Note that argv_index holds index to first non-flag command line option
230 * (that is, to the first file name) */
231 argv_index
= parse_commandline(argc
, argv
);
233 /* ---------- create log file right away ---------- */
234 /* ---------- even if logging is enabled ---------- */
235 s_log_init ("gattrib");
238 ("gEDA/gattrib version %s%s.%s\n", PREPEND_VERSION_STRING
,
239 PACKAGE_DOTTED_VERSION
, PACKAGE_DATE_VERSION
);
241 ("gEDA/gattrib comes with ABSOLUTELY NO WARRANTY; see COPYING for more details.\n");
243 ("This is free software, and you are welcome to redistribute it under certain\n");
245 ("conditions; please see the COPYING file for more details.\n\n");
247 /* ------ register guile (scheme) functions. Necessary to parse RC file. ------ */
250 /* ---------- Start creation of new project: (TOPLEVEL *pr_current) ---------- */
251 pr_current
= s_toplevel_new();
253 /* ----- Read in RC files. ----- */
254 g_rc_parse(pr_current
, "gattribrc", NULL
);
256 i_vars_set(pr_current
);
258 gtk_init(&argc
, &argv
);
262 /* ---------- Initialize SHEET_DATA data structure ---------- */
263 sheet_head
= s_sheet_data_new(); /* sheet_head was declared in globals.h */
265 GSList
*file_list
= NULL
;
266 if (argv_index
>= argc
) {
267 /* No files specified on the command line, pop up the File open dialog. */
268 file_list
= x_fileselect_open();
269 if(file_list
== NULL
)
272 /* Construct the list of filenames from the command line.
273 * argv_index holds the position of the first filename */
274 while (argv_index
< argc
) {
275 gchar
*filename
= f_normalize_filename(argv
[argv_index
], NULL
);
276 if (filename
!= NULL
) {
277 file_list
= g_slist_append(file_list
, filename
);
279 fprintf(stderr
, "Couldn't find file [%s]\n", argv
[argv_index
]);
287 if(x_fileselect_load_files(file_list
) == FALSE
) {
288 /* just exit the program */
292 g_slist_foreach(file_list
, (GFunc
)g_free
, NULL
);
293 g_slist_free(file_list
);
299 /*------------------------------------------------------------------*/
300 /*! \brief Entry point to gattrib
302 * This is just a wrapper which
303 * invokes the guile stuff, and points to the real main program,
304 * gattrib_main(). Note that I still need some vestigial
305 * guile stuff in order to read the rc files.
307 * \param argc Number of command line arguments
308 * \param argv Command line arguments
310 int main(int argc
, char *argv
[])
312 /* disable the deprecated warnings in guile 1.6.3 */
313 /* Eventually the warnings will need to be fixed */
314 if(getenv("GUILE_WARN_DEPRECATED")==NULL
)
315 putenv("GUILE_WARN_DEPRECATED=no");
317 /* Initialize the Guile Scheme interpreter. This function does not
318 * return but calls exit(0) on completion.
320 scm_boot_guile( argc
, argv
, gattrib_main
, NULL
);
322 exit(0); /* This is not real exit point. Real exit is in gattrib_quit. */