Fixed transpositions, typos, and random spelling errors.
[geda-gaf/peter-b.git] / libgeda / src / a_basic.c
blob06c31493e5b58462291daf222b34a9668e8a6258
1 /* gEDA - GPL Electronic Design Automation
2 * libgeda - gEDA's library
3 * Copyright (C) 1998-2007 Ales Hvezda
4 * Copyright (C) 1998-2007 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., 59 Temple Place, Suite 330, Boston, MA 02111 USA
20 #include <config.h>
22 #include <stdio.h>
23 #ifdef HAVE_STRING_H
24 #include <string.h>
25 #endif
27 #include <gtk/gtk.h>
28 #include <libguile.h>
30 #include "defines.h"
31 #include "struct.h"
32 #include "globals.h"
33 #include "o_types.h"
34 #include "colors.h"
36 #include "../include/prototype.h"
38 #ifdef HAVE_LIBDMALLOC
39 #include <dmalloc.h>
40 #endif
42 /*! \brief Current version string */
43 #define VERSION_20020825 20020825
45 /*! \brief Save embedded attributes to current file
46 * \par Function Description
47 * This function will save all embedded attributes to a file.
49 * \param [in,out] w_current
50 * \param [in] object_list The list of attributes to write to file
51 * \param [in] fp The file to write to.
53 void o_save_embedded(TOPLEVEL *w_current, OBJECT *object_list, FILE *fp)
55 OBJECT *o_current=NULL;
56 char *out;
58 /* make sure you init net_consolide to false (default) in all */
59 /* programs */
60 if (w_current->net_consolidate == TRUE) {
61 o_net_consolidate(w_current);
64 o_current = object_list;
66 while ( o_current != NULL ) {
68 if (o_current->type != OBJ_HEAD) {
70 if (o_current->attribute == 0) {
72 switch (o_current->type) {
74 case(OBJ_LINE):
75 out = (char *) o_line_save(o_current);
76 break;
78 case(OBJ_NET):
79 out = (char *) o_net_save(o_current);
80 break;
82 case(OBJ_BUS):
83 out = (char *) o_bus_save(o_current);
84 break;
86 case(OBJ_BOX):
87 out = (char *) o_box_save(o_current);
88 break;
90 case(OBJ_CIRCLE):
91 out = (char *) o_circle_save(o_current);
92 break;
94 case(OBJ_COMPLEX):
95 out = (char *) o_complex_save(o_current);
96 if (o_complex_is_embedded(o_current)) {
97 fprintf(fp, "[\n");
99 o_save_embedded(
100 w_current,
101 o_current->
102 complex->prim_objs,
103 fp);
105 fprintf(fp, "]\n");
107 break;
109 case(OBJ_PLACEHOLDER): /* new type by SDB 1.20.2005 */
110 out = (char *) o_complex_save(o_current);
111 break;
113 case(OBJ_TEXT):
114 out = (char *) o_text_save(o_current);
115 break;
117 case(OBJ_PIN):
118 out = (char *) o_pin_save(o_current);
119 break;
121 case(OBJ_ARC):
122 out = (char *) o_arc_save(o_current);
123 break;
125 case(OBJ_PICTURE):
126 out = (char *) o_picture_save(o_current);
127 break;
129 default:
130 fprintf(stderr, "Error type!\n");
131 exit(-1);
132 break;
135 /* output the line */
136 fprintf(fp, "%s\n", out);
137 g_free(out);
139 /* save those attributes */
140 if (o_current->attribs != NULL) {
141 if (o_current->attribs->next != NULL) {
142 o_save_attribs(fp, o_current->attribs->next);
148 o_current = o_current->next;
152 /*! \brief Write libgeda file header
153 * \par Function Description
154 * This function simply prints the DATE_VERSION and FILEFORMAT_VERSION
155 * definitions to the file.
157 * \param [in] fp The file to write the header to.
159 void o_save_write_header(FILE *fp)
161 fprintf(fp, "v %s %u\n", DATE_VERSION, FILEFORMAT_VERSION);
164 /*! \brief Save a file
165 * \par Function Description
166 * This function saves the data in a libgeda format to a file
167 * \param [in] w_current The data to save to file.
168 * \param [in] filename The filename to save the data to.
169 * \return 1 on success, 0 on failure.
171 int o_save(TOPLEVEL *w_current, const char *filename)
173 OBJECT *o_current=NULL;
174 FILE *fp;
175 char *out;
176 int already_wrote=0;
178 fp = fopen(filename, "wb");
180 if (fp == NULL) {
181 s_log_message("o_save: Could not open [%s]\n", filename);
182 return 0;
186 o_current = w_current->page_current->object_head;
188 /* make sure you init net_consolide to false (default) in all */
189 /* programs */
190 if (w_current->net_consolidate == TRUE) {
191 o_net_consolidate(w_current);
194 o_save_write_header(fp);
196 while ( o_current != NULL ) {
198 if (o_current->type != OBJ_HEAD) {
200 if (o_current->attribute == 0) {
202 switch (o_current->type) {
204 case(OBJ_LINE):
205 out = (char *) o_line_save(o_current);
206 break;
208 case(OBJ_NET):
209 out = (char *) o_net_save(o_current);
210 break;
212 case(OBJ_BUS):
213 out = (char *) o_bus_save(o_current);
214 break;
216 case(OBJ_BOX):
217 out = (char *) o_box_save(o_current);
218 break;
220 case(OBJ_CIRCLE):
221 out = (char *) o_circle_save(o_current);
222 break;
224 case(OBJ_COMPLEX):
225 out = (char *) o_complex_save(o_current);
226 fprintf(fp, "%s\n", out);
227 already_wrote=1;
228 g_free(out); /* need to free here because of the above flag */
229 if (o_complex_is_embedded(o_current)) {
230 fprintf(fp, "[\n");
232 o_save_embedded(
233 w_current,
234 o_current->
235 complex->prim_objs,
236 fp);
238 fprintf(fp, "]\n");
240 break;
242 case(OBJ_PLACEHOLDER): /* new type by SDB 1.20.2005 */
243 out = (char *) o_complex_save(o_current);
244 break;
246 case(OBJ_TEXT):
247 out = (char *) o_text_save(o_current);
248 break;
250 case(OBJ_PIN):
251 out = (char *) o_pin_save(o_current);
252 break;
254 case(OBJ_ARC):
255 out = (char *) o_arc_save(o_current);
256 break;
258 case(OBJ_PICTURE):
259 out = (char *) o_picture_save(o_current);
260 break;
262 default:
263 fprintf(stderr, "Error type!\n");
264 exit(-1);
265 break;
268 /* output the line */
269 if (!already_wrote) {
270 fprintf(fp, "%s\n", out);
271 g_free(out);
272 } else {
273 already_wrote=0;
276 /* save those attributes */
277 if (o_current->attribs != NULL) {
278 if (o_current->attribs->next != NULL) {
279 o_save_attribs(fp, o_current->attribs->next);
285 o_current = o_current->next;
288 fclose(fp);
289 return 1;
292 /*! \brief Read a memory buffer
293 * \par Function Description
294 * This function reads data in libgeda format from a memory buffer.
296 * If the size argument is negative, the buffer is assumed to be
297 * null-terminated.
299 * The name argument is used for debugging, and should be set to a
300 * meaningful string (e.g. the name of the file the data is from).
302 * \param [in,out] w_current The current TOPLEVEL structure.
303 * \param [in] object_list The object_list to read data to.
304 * \param [in] buffer The memory buffer to read from.
305 * \param [in] size The size of the buffer.
306 * \param [in] name The name to describe the data with.
307 * \return object_list if successful read, or NULL on error.
309 OBJECT *o_read_buffer(TOPLEVEL *w_current, OBJECT *object_list,
310 char *buffer, const int size,
311 const char *name)
313 char *line = NULL;
314 TextBuffer *tb = NULL;
316 char objtype;
317 OBJECT *object_list_save=NULL;
318 OBJECT *temp_tail=NULL;
319 OBJECT *temp_parent=NULL;
320 OBJECT *object_before_attr=NULL;
321 unsigned int release_ver;
322 unsigned int fileformat_ver;
323 unsigned int current_fileformat_ver;
324 int found_pin = 0;
325 OBJECT* last_complex = NULL;
326 int itemsread = 0;
328 int embedded_level = 0;
331 /* fill version with default file format version (the current one) */
332 current_fileformat_ver = FILEFORMAT_VERSION;
334 if (buffer == NULL) {
335 s_log_message("o_read_buffer: Received NULL buffer\n");
336 return(NULL);
339 tb = s_textbuffer_new (buffer, size);
340 g_assert (tb != NULL);
342 while (1) {
344 line = s_textbuffer_next_line(tb);
345 if (line == NULL) break;
347 sscanf(line, "%c", &objtype);
349 /* Do we need to check the symbol version? Yes, but only if */
350 /* 1) the last object read was a complex and */
351 /* 2) the next object isn't the start of attributes. */
352 /* If the next object is the start of attributes, then check the */
353 /* symbol version after the attributes have been read in, see the */
354 /* STARTATTACH_ATTR case */
355 if (last_complex && objtype != STARTATTACH_ATTR)
357 /* yes */
358 /* verify symbol version (not file format but rather contents) */
359 o_complex_check_symversion(w_current, last_complex);
360 last_complex = NULL; /* no longer need to check */
363 switch (objtype) {
365 case(OBJ_LINE):
366 object_list = (OBJECT *) o_line_read(w_current, object_list, line,
367 release_ver, fileformat_ver);
368 break;
371 case(OBJ_NET):
372 object_list = (OBJECT *) o_net_read(w_current, object_list, line,
373 release_ver, fileformat_ver);
374 break;
376 case(OBJ_BUS):
377 object_list = (OBJECT *) o_bus_read(w_current, object_list, line,
378 release_ver, fileformat_ver);
379 break;
381 case(OBJ_BOX):
382 object_list = (OBJECT *) o_box_read(w_current, object_list, line,
383 release_ver, fileformat_ver);
384 break;
386 case(OBJ_PICTURE):
387 line = g_strdup(line);
388 object_list = (OBJECT *) o_picture_read(w_current, object_list,
389 line, tb,
390 release_ver, fileformat_ver);
391 g_free (line);
392 break;
394 case(OBJ_CIRCLE):
395 object_list = (OBJECT *) o_circle_read(w_current, object_list, line,
396 release_ver, fileformat_ver);
397 break;
399 case(OBJ_COMPLEX):
400 case(OBJ_PLACEHOLDER):
401 object_list = (OBJECT *) o_complex_read(w_current, object_list, line,
402 release_ver, fileformat_ver);
404 /* this is necessary because complex may add attributes which float */
405 /* needed now? */
406 object_list = (OBJECT *) return_tail(object_list);
408 /* last_complex is used for verifying symversion attribute */
409 last_complex = object_list;
410 break;
412 case(OBJ_TEXT):
413 line = g_strdup(line);
414 object_list = (OBJECT *) o_text_read(w_current, object_list,
415 line, tb,
416 release_ver, fileformat_ver);
417 g_free(line);
418 break;
420 case(OBJ_PIN):
421 object_list = (OBJECT *) o_pin_read(w_current, object_list, line,
422 release_ver, fileformat_ver);
423 found_pin++;
424 break;
426 case(OBJ_ARC):
427 object_list = (OBJECT *) o_arc_read(w_current, object_list, line,
428 release_ver, fileformat_ver);
429 break;
431 case(STARTATTACH_ATTR):
432 object_before_attr = object_list;
433 /* first is the fp */
434 /* 2nd is the object to get the attributes */
435 object_list = (OBJECT *) o_read_attribs(w_current, object_list,
437 release_ver, fileformat_ver);
439 /* by now we have finished reading all the attributes */
440 /* did we just finish attaching to a complex object? */
441 if (last_complex)
443 /* yes */
444 /* verify symbol version (not file format but rather contents) */
445 o_complex_check_symversion(w_current, last_complex);
446 last_complex = NULL;
449 /* slots only apply to complex objects */
450 if (object_before_attr->type == OBJ_COMPLEX ||
451 object_before_attr->type == OBJ_PLACEHOLDER) {
452 o_attrib_slot_update(w_current, object_before_attr);
455 /* need this? nope */
456 /*object_list = return_tail(object_list);*/
457 object_before_attr = NULL;
458 break;
460 case(START_EMBEDDED):
462 if(object_list->type == OBJ_COMPLEX ||
463 object_list->type == OBJ_PLACEHOLDER) {
465 object_list_save = object_list;
466 object_list = object_list_save->complex->prim_objs;
468 temp_tail = w_current->page_current->object_tail;
469 temp_parent = w_current->page_current->object_parent;
470 w_current->page_current->object_parent = object_list;
472 embedded_level++;
473 } else {
474 fprintf(stderr, "Read unexpected embedded "
475 "symbol start marker in [%s] :\n>>\n%s<<\n",
476 name, line);
478 break;
480 case(END_EMBEDDED):
481 if(embedded_level>0) {
482 object_list = object_list_save;
483 /* don't do this since objects are already
484 * stored/read translated
485 * o_complex_world_translate(w_current, object_list->x,
486 * object_list->y, object_list->complex);
488 w_current->page_current->object_tail = temp_tail;
489 w_current->page_current->object_parent = temp_parent;
491 o_complex_recalc( w_current, object_list );
492 embedded_level--;
493 } else {
494 fprintf(stderr, "Read unexpected embedded "
495 "symbol end marker in [%s] :\n>>\n%s<<\n",
496 name, line);
499 break;
501 case(ENDATTACH_ATTR):
502 /* this case is never hit, since the } is consumed by o_read_attribs */
503 break;
505 case(INFO_FONT):
506 o_text_set_info_font(line);
507 break;
509 case(COMMENT):
510 /* do nothing */
511 break;
513 case(VERSION_CHAR):
514 itemsread = sscanf(line, "v %u %u\n", &release_ver, &fileformat_ver);
516 /* 20030921 was the last version which did not have a fileformat */
517 /* version. The below latter test should not happen, but it is here */
518 /* just in in case. */
519 if (release_ver <= VERSION_20030921 || itemsread == 1)
521 fileformat_ver = 0;
524 if (fileformat_ver < current_fileformat_ver)
526 s_log_message("Read an old format sym/sch file!\n"
527 "Please run g[sym|sch]update on:\n[%s]\n", name);
529 break;
531 default:
532 fprintf(stderr, "Read garbage in [%s] :\n>>\n%s<<\n",
533 name, line);
534 break;
539 /* Was the very last thing we read a complex and has it not been checked */
540 /* yet? This would happen if the complex is at the very end of the file */
541 /* and had no attached attributes */
542 if (last_complex)
544 o_complex_check_symversion(w_current, last_complex);
545 last_complex = NULL; /* no longer need to check */
548 if (found_pin) {
549 if (release_ver <= VERSION_20020825) {
550 o_pin_update_whichend(w_current, return_head(object_list), found_pin);
554 tb = s_textbuffer_free(tb);
556 return(object_list);
560 /*! \brief Read a file
561 * \par Function Description
562 * This function reads a file in libgeda format.
564 * \param [in,out] w_current The current TOPLEVEL structure.
565 * \param [in] object_list The object_list to read data to.
566 * \param [in] filename The filename to read from.
567 * \return object_list if successful read, or NULL on error.
569 OBJECT *o_read(TOPLEVEL *w_current, OBJECT *object_list, char *filename)
571 GError *err = NULL;
572 char *buffer = NULL;
573 size_t size;
574 OBJECT *result = NULL;
576 g_file_get_contents(filename, &buffer, &size, &err);
578 g_assert ((buffer == NULL && err != NULL)
579 || (buffer != NULL && err == NULL));
581 if (err != NULL)
583 /* Report error to user, and free error */
584 g_assert (buffer == NULL);
585 fprintf (stderr, "o_read: Unable to read file: [%s]\n", err->message);
586 g_error_free (err);
587 return NULL;
590 /* Parse file contents */
591 g_assert (buffer != NULL);
592 result = o_read_buffer (w_current, object_list, buffer, size, filename);
593 g_free (buffer);
594 return result;
597 /*! \brief Scale a set of lines.
598 * \par Function Description
599 * This function takes a list of lines and scales them
600 * by the values of x_scale and y_scale.
602 * \param [in] w_current The current TOPLEVEL object.
603 * \param [in,out] list The list with lines to scale.
604 * \param [in] x_scale The x scale value for the lines.
605 * \param [in] y_scale The y scale value for the lines.
607 * \todo this really doesn't belong here. you need more of a core routine
608 * first. yes.. this is the core routine, just strip out the drawing
609 * stuff
610 * move it to o_complex_scale
612 void o_scale(TOPLEVEL *w_current, OBJECT *list, int x_scale, int y_scale)
614 OBJECT *o_current;
616 /* this is okay if you just hit scale and have nothing selected */
617 if (list == NULL) {
618 /* w_current->event_state = SELECT;*/
619 /* i_update_status(w_current, "Select Mode"); not here */
620 /* w_current->inside_action = 0;*/
621 return;
625 o_current = list;
628 while (o_current != NULL) {
630 switch(o_current->type) {
632 case(OBJ_LINE):
633 /* erase the current selection */
634 w_current->override_color =
635 w_current->background_color;
636 o_redraw_single(w_current, o_current);
637 /* o_line_draw(w_current, o_current);*/
638 w_current->override_color = -1;
640 o_line_scale_world(w_current,
641 x_scale, y_scale, o_current);
642 break;
645 o_current = o_current->next;
648 /* don't do this at this level */
649 /* w_current->page_current->CHANGED=1;*/