gsch2pcb: Make --m4-file and -m4-pcbdir arguments work again.
[geda-gaf/peter-b.git] / gattrib / src / gattrib.c
blob3ba793fd92026d39441934c33690271d5684a3d3
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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 /**
21 * \mainpage
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
40 * still be relevant)
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
50 * gattrib.
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
57 * the spreadsheet.
59 * When run, gattrib does this:
61 * -# It uses libgeda functions to read in your design, and fill up the
62 * TOPLEVEL struct.
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
76 * are not updated.
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,
84 * however. :-S
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
92 * libgeda.
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.
102 #include <config.h>
103 #include <version.h>
105 #ifdef HAVE_UNISTD_H
106 #include <unistd.h>
107 #endif
109 /*------------------------------------------------------------------*/
110 /* Includes originally from testgtksheet -- stuff needed to deal with
111 * spreadsheet widget.
112 *------------------------------------------------------------------*/
113 #include <stdio.h>
114 #include <stdlib.h>
115 #include <gtk/gtk.h>
116 #include <gdk/gdk.h>
117 #include <gdk/gdkkeysyms.h>
119 #include <glib.h>
120 #include <glib-object.h>
122 #ifdef HAVE_STRING_H
123 #include <string.h>
124 #endif
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
135 #include <dmalloc.h>
136 #endif
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();
153 } else {
154 gattrib_quit(0);
156 return TRUE;
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(); */
171 s_clib_free();
172 s_slib_free();
173 /* s_rename_destroy_all(); */
174 #ifdef DEBUG
175 fflush(stderr);
176 fflush(stdout);
177 printf("In gattrib_quit, calling gtk_main_quit()\n");
178 #endif
179 gtk_main_quit();
180 exit(return_code);
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.
189 * This function:
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;
194 * - starts logging;
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.
201 * \param closure
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 */
211 int argv_index;
213 #ifdef HAVE_GTHREAD
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);
220 #endif
222 /* Initialize gEDA stuff */
223 libgeda_init();
225 /* Note that argv_index holds index to first non-flag command line option
226 * (that is, to the first file name) */
227 argv_index = parse_commandline(argc, argv);
229 /* ---------- create log file right away ---------- */
230 /* ---------- even if logging is enabled ---------- */
231 s_log_init ("gattrib");
233 s_log_message
234 ("gEDA/gattrib version %s%s.%s\n", PREPEND_VERSION_STRING,
235 PACKAGE_DOTTED_VERSION, PACKAGE_DATE_VERSION);
236 s_log_message
237 ("gEDA/gattrib comes with ABSOLUTELY NO WARRANTY; see COPYING for more details.\n");
238 s_log_message
239 ("This is free software, and you are welcome to redistribute it under certain\n");
240 s_log_message
241 ("conditions; please see the COPYING file for more details.\n\n");
243 /* ------ register guile (scheme) functions. Necessary to parse RC file. ------ */
244 g_register_funcs();
246 /* ---------- Start creation of new project: (TOPLEVEL *pr_current) ---------- */
247 pr_current = s_toplevel_new();
249 /* ----- Read in RC files. ----- */
250 g_rc_parse (pr_current, argv[0], "gattribrc", NULL);
252 i_vars_set(pr_current);
254 gtk_init(&argc, &argv);
256 x_window_init();
258 /* ---------- Initialize SHEET_DATA data structure ---------- */
259 sheet_head = s_sheet_data_new(); /* sheet_head was declared in globals.h */
261 GSList *file_list = NULL;
262 if (argv_index >= argc) {
263 /* No files specified on the command line, pop up the File open dialog. */
264 file_list = x_fileselect_open();
265 if(file_list == NULL)
266 exit(0);
267 } else {
268 /* Construct the list of filenames from the command line.
269 * argv_index holds the position of the first filename */
270 while (argv_index < argc) {
271 gchar *filename = f_normalize_filename(argv[argv_index], NULL);
272 if (filename != NULL) {
273 file_list = g_slist_append(file_list, filename);
274 } else {
275 fprintf(stderr, "Couldn't find file [%s]\n", argv[argv_index]);
276 exit(1);
278 argv_index++;
282 /* Load the files */
283 if(x_fileselect_load_files(file_list) == FALSE) {
284 /* just exit the program */
285 exit(1);
288 g_slist_foreach(file_list, (GFunc)g_free, NULL);
289 g_slist_free(file_list);
291 gtk_main();
292 exit(0);
295 /*------------------------------------------------------------------*/
296 /*! \brief Entry point to gattrib
298 * This is just a wrapper which
299 * invokes the guile stuff, and points to the real main program,
300 * gattrib_main(). Note that I still need some vestigial
301 * guile stuff in order to read the rc files.
303 * \param argc Number of command line arguments
304 * \param argv Command line arguments
306 int main(int argc, char *argv[])
308 /* disable the deprecated warnings in guile 1.6.3 */
309 /* Eventually the warnings will need to be fixed */
310 if(getenv("GUILE_WARN_DEPRECATED")==NULL)
311 putenv("GUILE_WARN_DEPRECATED=no");
313 /* Initialize the Guile Scheme interpreter. This function does not
314 * return but calls exit(0) on completion.
316 scm_boot_guile( argc, argv, gattrib_main, NULL);
318 exit(0); /* This is not real exit point. Real exit is in gattrib_quit. */