Move o_redraw_single() from libgeda to gschem
[geda-gaf/peter-b.git] / libgeda / src / s_basic.c
blob7668555b60833e55ff37a9163c3206628beec143
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 #include <ctype.h>
24 #ifdef HAVE_STDLIB_H
25 #include <stdlib.h>
26 #endif
27 #ifdef HAVE_ASSERT_H
28 #include <assert.h>
29 #endif
30 #ifndef HAVE_VSNPRINTF
31 #include <stdarg.h>
32 #endif
33 #ifdef HAVE_STRING_H
34 #include <string.h>
35 #endif
37 #include <gtk/gtk.h>
38 #include <libguile.h>
40 #include "defines.h"
41 #include "struct.h"
42 #include "defines.h"
43 #include "globals.h"
44 #include "o_types.h"
45 #include "colors.h"
47 #include "../include/prototype.h"
49 #ifdef HAVE_LIBDMALLOC
50 #include <dmalloc.h>
51 #endif
53 /*! this is modified here and in o_list.c */
54 int global_sid=0;
56 #define NUMCOLORS 9 /*!< */
58 /*! \brief */
59 struct st_old_colors {
60 char *name;
61 int value;
64 /*! \brief
65 * Colors must be in alphabetical order
66 * be sure that you update above define
68 struct st_old_colors old_colors[] = {
69 { "black", 0 },
70 { "blue", 4 },
71 { "cyan", 6 },
72 { "green", 3 },
73 { "grey", 7 },
74 { "grey90", 8 },
75 { "red", 2 },
76 { "white", 1 },
77 { "yellow", 5 },
80 /*! \todo Finish function documentation!!!
81 * \brief
82 * \par Function Description
85 void error_if_called(void)
87 fprintf(stderr, "Somebody called error_if_called!\n");
88 assert(0);
91 /*! \todo Finish function documentation!!!
92 * \brief
93 * \par Function Description
96 void exit_if_null(void *ptr)
98 if (ptr == NULL) {
99 fprintf(stderr, "gEDA: Got NULL ptr!, please e-mail maintainer\n");
100 assert(0);
101 exit(-1);
105 /*! \todo Finish function documentation!!!
106 * \brief
107 * \par Function Description
110 /* hack rename this to be s_return_tail */
111 /* update object_tail or any list of that matter */
112 OBJECT *return_tail(OBJECT *head)
114 OBJECT *o_current=NULL;
115 OBJECT *ret_struct=NULL;
117 o_current = head;
118 while ( o_current != NULL ) { /* goto end of list */
119 ret_struct = o_current;
120 o_current = o_current->next;
123 return(ret_struct);
126 /*! \todo Finish function documentation!!!
127 * \brief
128 * \par Function Description
131 /* hack rename this to be s_return_head */
132 /* update object_tail or any list of that matter */
133 OBJECT *return_head(OBJECT *tail)
135 OBJECT *o_current=NULL;
136 OBJECT *ret_struct=NULL;
138 o_current = tail;
139 while ( o_current != NULL ) { /* goto end of list */
140 ret_struct = o_current;
141 o_current = o_current->prev;
144 return(ret_struct);
147 /*! \todo Finish function documentation!!!
148 * \brief
149 * \par Function Description
152 OBJECT *s_basic_init_object( char *name )
154 OBJECT *new_node;
156 new_node = (OBJECT *) g_malloc(sizeof(OBJECT));
158 if (new_node == NULL) {
159 fprintf(stderr, "Could not perform malloc; something is broken or increase your process limits\n");
160 exit(-1);
163 /* setup sid */
164 new_node->sid = global_sid++;
165 new_node->type = -1;
167 /* Setup the name */
168 /*! \todo get rid of magic number 16 that's the size of new_node->sid, */
169 new_node->name = (char *) g_malloc(sizeof(char)*(strlen(name)+16));
170 sprintf(new_node->name, "%s.%d", name, new_node->sid);
172 /* Setup the bounding box */
173 new_node->w_top = 0;
174 new_node->w_left = 0;
175 new_node->w_right = 0;
176 new_node->w_bottom = 0;
178 /* Setup line/circle structs */
179 new_node->line = NULL;
180 new_node->circle = NULL;
181 new_node->arc = NULL;
182 new_node->box = NULL;
183 new_node->picture = NULL;
184 new_node->text = NULL;
185 new_node->complex = NULL;
187 new_node->tile_locs = NULL;
189 new_node->conn_list = NULL;
191 new_node->visited = 0;
193 new_node->complex_basename = NULL;
194 new_node->complex_parent = NULL;
196 /* Setup the color */
197 new_node->color = WHITE;
198 new_node->saved_color = -1;
199 new_node->selected = FALSE;
200 new_node->locked_color = -1;
201 new_node->draw_grips = FALSE;
203 new_node->bus_ripper_direction = 0;
205 new_node->action_func = error_if_called;
206 new_node->sel_func = error_if_called;
207 new_node->draw_func = error_if_called;
209 new_node->line_end = END_NONE;
210 new_node->line_type = TYPE_SOLID;
211 new_node->line_width = 0;
212 new_node->line_space = 0;
213 new_node->line_length = 0;
214 new_node->fill_width = 0;
215 new_node->fill_angle1 = 0;
216 new_node->fill_angle2 = 0;
217 new_node->fill_pitch1 = 0;
218 new_node->fill_pitch2 = 0;
220 new_node->attribs = NULL;
221 new_node->attached_to = NULL;
222 new_node->attribute = 0;
223 new_node->show_name_value = SHOW_NAME_VALUE;
224 new_node->visibility = VISIBLE;
226 new_node->pin_type = PIN_TYPE_NET;
227 new_node->whichend = -1;
229 /* Setup link list stuff */
230 new_node->prev = NULL;
231 new_node->next = NULL;
233 return(new_node);
236 OBJECT *s_basic_link_object( OBJECT *new_node, OBJECT *ptr )
238 /* should never happen, but could */
239 if (new_node == NULL) {
240 fprintf(stderr, "Got a null new_node in link_object\n");
241 return(ptr);
244 if (ptr == NULL) {
245 new_node->prev = NULL; /* setup previous link */
246 return(new_node);
247 } else {
248 new_node->prev = ptr; /* setup previous link */
249 ptr->next = new_node;
250 return(ptr->next);
254 /*! \todo Finish function documentation!!!
255 * \brief
256 * \par Function Description
259 void print_struct_forw(OBJECT *ptr)
261 OBJECT *o_current=NULL;
263 o_current = ptr;
265 if (o_current == NULL) {
267 printf("AGGGGGGGGGGG NULLLLL PRINT\n");
269 printf("TRYING to PRINT\n");
270 while (o_current != NULL) {
271 printf("Name: %s\n", o_current->name);
272 printf("Type: %d\n", o_current->type);
273 printf("Sid: %d\n", o_current->sid);
275 if (o_current->type == OBJ_COMPLEX || o_current->type == OBJ_PLACEHOLDER) {
276 print_struct_forw(o_current->complex->prim_objs);
279 o_attrib_print (o_current->attribs);
281 printf("----\n");
282 o_current = o_current->next;
286 /*! \todo Finish function documentation!!!
287 * \brief
288 * \par Function Description
291 void print_struct_back(OBJECT *ptr)
293 OBJECT *o_current=NULL;
295 o_current = ptr;
297 while (o_current != NULL) {
298 printf("Name: %s\n", o_current->name);
299 printf("Type: %d\n", o_current->type);
300 printf("Sid: %d\n", o_current->sid);
301 printf("----\n");
302 o_current = o_current->prev;
306 /*! \todo Finish function documentation!!!
307 * \brief
308 * \par Function Description
311 void print_struct(OBJECT *ptr)
313 OBJECT *o_current=NULL;
315 o_current = ptr;
317 if (o_current != NULL) {
318 printf("Name: %s\n", o_current->name);
319 printf("Type: %d\n", o_current->type);
320 printf("Sid: %d\n", o_current->sid);
321 if (o_current->line != NULL) {
322 printf("Line points.x1: %d\n", o_current->line->x[0]);
323 printf("Line points.y1: %d\n", o_current->line->y[0]);
324 printf("Line points.x2: %d\n", o_current->line->x[1]);
325 printf("Line points.y2: %d\n", o_current->line->y[1]);
328 o_attrib_print (o_current->attribs);
330 printf("----\n");
334 /*! \todo Finish function documentation!!!
335 * \brief
336 * \par Function Description
339 void
340 s_delete_object(TOPLEVEL *toplevel, OBJECT *o_current)
342 if (o_current != NULL) {
343 s_conn_remove(toplevel, o_current);
345 /* second half of if is odd that we need it? hack */
346 /* need to do this early so we can do the printfs */
347 if (o_current->attached_to != NULL && o_current->attribute == 1) {
348 if (o_current->attached_to->object) {
349 /*printf("removing %s\n", o_current->attached_to->object->name);*/
350 } else {
351 printf("found a null I didn't expect!!!!!!!!!\n");
354 /* do the actual remove */
355 o_attrib_delete(o_current->attached_to);
358 if (toplevel->page_current->object_lastplace == o_current) {
359 toplevel->page_current->object_lastplace = NULL;
362 if (o_current->line) {
363 /* printf("sdeleting line\n");*/
364 g_free(o_current->line);
366 /* yes this object might be in the tile system */
367 s_tile_remove_object_all(toplevel,
368 toplevel->page_current,
369 o_current);
371 o_current->line = NULL;
373 if (o_current->circle) {
374 /* printf("sdeleting circle\n");*/
375 g_free(o_current->circle);
377 o_current->circle = NULL;
379 if (o_current->arc) {
380 /* printf("sdeleting arc\n");*/
381 g_free(o_current->arc);
383 o_current->arc = NULL;
385 if (o_current->box) {
386 /* printf("sdeleting box\n");*/
387 g_free(o_current->box);
389 o_current->box = NULL;
391 if (o_current->picture) {
392 /* printf("sdeleting picture\n");*/
394 if (o_current->picture->original_picture)
395 g_object_unref(o_current->picture->original_picture);
396 if (o_current->picture->displayed_picture)
397 g_object_unref(o_current->picture->displayed_picture);
399 if (o_current->picture->filename)
400 g_free(o_current->picture->filename);
401 g_free(o_current->picture);
403 o_current->picture = NULL;
405 if (o_current->text) {
406 if (o_current->text->string) {
407 /*printf("sdeleting text->string\n");*/
408 g_free(o_current->text->string);
410 o_current->text->string = NULL;
412 if (o_current->text->prim_objs) {
413 /*printf("sdeleting text complex\n");*/
414 s_delete_list_fromstart(toplevel,
415 o_current->text->prim_objs);
417 o_current->text->prim_objs = NULL;
419 /* printf("sdeleting text\n");*/
420 g_free(o_current->text);
422 o_current->text = NULL;
424 if (o_current->name) {
425 /* printf("sdeleting name\n");*/
426 g_free(o_current->name);
428 o_current->name = NULL;
431 if (o_current->complex_basename) {
432 /* printf("sdeleting complex_basename\n");*/
433 g_free(o_current->complex_basename);
435 o_current->complex_basename = NULL;
437 if (o_current->complex) {
439 if (o_current->complex->prim_objs) {
440 /* printf("sdeleting complex->primitive_objects\n");*/
441 s_delete_list_fromstart(toplevel,
442 o_current->complex->prim_objs);
444 o_current->complex->prim_objs = NULL;
446 g_free(o_current->complex);
447 o_current->complex = NULL;
450 if (o_current->attribs) {
451 o_attrib_free_all(toplevel, o_current->attribs);
453 o_current->attribs = NULL;
456 g_free(o_current); /* assuming it is not null */
458 o_current=NULL; /* misc clean up */
462 /*! \todo Finish function documentation!!!
463 * \brief
464 * \par Function Description
467 void
468 s_delete(TOPLEVEL *toplevel, OBJECT *o_current)
470 if (o_current != NULL) {
473 #if DEBUG
474 printf("sdel: %s\n", o_current->name);
475 printf("sdel: %d\n", o_current->sid);
476 #endif
478 if (o_current->next)
479 o_current->next->prev = o_current->prev;
480 else
481 o_current->next = NULL;
483 if (o_current->prev)
484 o_current->prev->next = o_current->next;
485 else
486 o_current->prev = NULL;
488 s_delete_object(toplevel, o_current);
492 /*! \todo Finish function documentation!!!
493 * \brief
494 * \par Function Description
497 /* deletes everything include the head */
498 void s_delete_list_fromstart(TOPLEVEL *toplevel, OBJECT *start)
500 OBJECT *temp=NULL; /* literally is a temp */
501 OBJECT *current=NULL; /* ugg... you have both o_current and current? */
502 OBJECT *o_current=NULL; /* hack */
504 temp = start;
505 current = return_tail(start);
507 /* do the delete backwards */
508 /*while(current != NULL && current->type != OBJ_HEAD ) {*/
509 while(current != NULL) {
510 o_current = current->prev;
511 s_delete(toplevel, current);
512 current = o_current;
515 /* now delete the head node */
516 /* might not need this but what the hell */
517 /* no longer needed, since it's deleted above */
518 /*s_delete_head(toplevel, start);*/
521 #if 0 /* old way of doing this */
522 /*! \todo Finish function documentation!!!
523 * \brief
524 * \par Function Description
527 void s_delete_list_fromstart(OBJECT *start)
529 OBJECT *traverse=NULL;
530 OBJECT *o_current=NULL;
532 for (traverse = start; traverse ; traverse = o_current) {
533 o_current = traverse->next;
534 if (traverse->type != OBJ_HEAD) /* don't delete any head nodes */
535 s_delete(traverse);
536 else
537 break; /* found a head node */
539 s_delete(traverse);
541 #endif
543 /*! \todo Finish function documentation!!!
544 * \brief
545 * \par Function Description
548 /* deletes everything include the GList */
549 void
550 s_delete_object_glist(TOPLEVEL *toplevel, GList *list)
552 OBJECT *o_current=NULL;
553 GList *ptr;
555 ptr = g_list_last(list);
557 /* do the delete backwards */
558 while(ptr != NULL) {
559 o_current = (OBJECT *) ptr->data;
560 s_delete_object(toplevel, o_current);
561 ptr = g_list_previous (ptr);
563 g_list_free(list);
567 /*! \todo Finish function documentation!!!
568 * \brief
569 * \par Function Description
570 * This function removes one object pointed by parameter <B>object</B> from
571 * a list as far as it does not represents a head. If so the function returns
572 * NULL. If not it returns the pointer on the object, i.e. the same as the
573 * parameter.
575 * This function must be followed by a call to #return_tail() on the
576 * list it belonged to as it can be the last object. Therefore the tail
577 * of the list is modified.
579 * \param [in] toplevel The TOPLEVEL object.
580 * \param [in] object
581 * \return OBJECT *
583 OBJECT *s_remove(TOPLEVEL *toplevel, OBJECT *object)
585 if(object->type == OBJ_HEAD)
586 return NULL;
588 if(object->prev != NULL)
589 object->prev->next = object->next;
590 if(object->next != NULL)
591 object->next->prev = object->prev;
593 object->next = NULL;
594 object->prev = NULL;
596 return object;
599 /*! \todo Finish function documentation!!!
600 * \brief
601 * \par Function Description
604 /* Done */
605 void string_toupper(char *in, char *out)
607 int len;
608 int i;
610 len = strlen(in);
612 for (i = 0 ; i < len ; i++) {
613 out[i] = toupper(in[i]);
617 /*! \todo Finish function documentation!!!
618 * \brief
619 * \par Function Description
622 void string_tolower(char *in, char *out)
624 int len;
625 int i;
627 len = strlen(in);
629 for (i = 0 ; i < len ; i++) {
630 out[i] = tolower(in[i]);
634 /*! \todo Finish function documentation!!!
635 * \brief
636 * \par Function Description
639 int colornametovalue(char *string)
642 int lower = 0;
643 int upper = NUMCOLORS - 1;
644 int middle;
645 int val;
646 struct st_old_colors *ptr=NULL;
648 if (!string) {
649 return(-1);
652 string_tolower(string, string);
653 while (lower <= upper) {
654 middle = (lower + upper) / 2;
656 ptr = &old_colors[middle];
657 val = strcmp (ptr->name, string);
659 if (val < 0) {
660 lower = middle + 1;
661 } else if (val == 0) {
662 return(ptr->value);
663 } else {
664 upper = middle - 1;
667 return(-1);
670 /*! \todo Finish function documentation!!!
671 * \brief
672 * \par Function Description
675 /* used by o_text_read */
676 char *remove_nl(char *string)
678 int i;
680 if (!string)
681 return NULL;
683 i = 0;
684 while(string[i] != '\0' && string[i] != '\n' && string[i] != '\r') {
685 i++;
688 string[i] = '\0';
690 return(string);
693 /*! \todo Finish function documentation!!!
694 * \brief
695 * \par Function Description
698 /* used by o_text_read */
699 char *remove_last_nl(char *string)
701 int len;
703 if (!string)
704 return NULL;
706 len = strlen(string);
707 if (string[len-1] == '\n' || string[len-1] == '\r')
708 string[len-1] = '\0';
710 return(string);
713 #ifndef HAVE_VSNPRINTF
714 /*! \todo Finish function documentation!!!
715 * \brief
716 * \par Function Description
719 void vsnprintf(char *buff, size_t bufsiz, const char *fmt, va_list ap)
721 char *tmpbuf = buff;
723 vsprintf(tmpbuf, fmt, ap);
725 #endif
727 /*! \todo Finish function documentation!!!
728 * \brief
729 * \par Function Description
732 /* this function is called by expand_env_variables */
733 /* changes and returns new string, frees the one that was passed in */
734 char *remove_string(char *string, int start, int end)
736 char *return_string;
737 int i;
738 int len;
739 int j;
741 if (!string) {
742 return(NULL);
745 len = strlen(string);
747 return_string = (char *) g_malloc(sizeof(char)*(len+1));
749 j = 0;
750 for (i = 0 ; i < len; i++) {
751 if (i >= start && i <= end) {
752 /* do nothing */
753 /* removing characters */
754 } else {
755 return_string[j] = string[i];
756 j++;
759 return_string[j] = '\0';
761 /* free original string */
762 g_free(string);
764 return(return_string);
767 /*! \todo Finish function documentation!!!
768 * \brief
769 * \par Function Description
772 /* this function is called by expand_env_variables */
773 /* changes and returns new string, frees the one that was passed in */
774 char *insert_string(char *string, int start, char *insert_string)
776 char *new_string=NULL;
777 int i;
778 int len;
779 int insert_len;
780 int total_len;
781 int j;
782 int orig_count=0;
784 /* this should never happen */
785 if (!insert_string) {
786 return(NULL);
789 /* this should never happen either */
790 if (!string) {
791 return(NULL);
794 len = strlen(string);
795 insert_len = strlen(insert_string);
796 total_len = len+insert_len;
798 new_string = (char *) g_malloc(sizeof(char)*(total_len+1));
800 i = 0;
801 while (i < total_len) {
802 if (i == start) {
803 for (j = 0 ; j < insert_len; j++) {
804 new_string[i+j] = insert_string[j];
806 i = j+i;
807 } else {
808 new_string[i] = string[orig_count];
809 i++;
810 orig_count++;
814 new_string[i] = '\0';
816 /* now free the original string */
817 g_free(string);
819 return(new_string);
822 /*! \todo Finish function documentation!!!
823 * \brief
824 * \par Function Description
827 /* this function changes and then returns the string which has the
828 * expanded environment variables, frees passed in string */
829 /* Environment variables MUST be in the form ${variable_name} */
830 /* $variable_name is not valid here */
831 char *expand_env_variables(char *string)
833 char wanted_var[80]; /* size is hack */
834 char *return_string=NULL;
835 char *environment_string=NULL;
836 int changed=1;
837 int found_dollar=0;
838 int found_lbrac=0;
839 int found_rbrac=0;
840 int start_of_variable= -1;
841 int end_of_variable= -1;
842 int count=0;
843 int i,j;
845 if (!string) {
846 return(NULL);
849 return_string = string;
851 while(changed) {
853 changed=0;
854 j=0;
855 for (i = 0 ; i < strlen(return_string); i++) {
857 switch(return_string[i]) {
859 case('$'):
861 #if DEBUG
862 printf("found a $\n");
863 #endif
864 found_dollar=1;
865 start_of_variable=i;
866 break;
868 case('{'):
869 if (found_dollar) {
870 found_lbrac=1;
871 count=1;
873 break;
875 case('}'):
876 if (found_dollar) {
877 found_rbrac=1;
878 /* ends filling of wanted_var */
879 found_lbrac=0;
880 end_of_variable=i;
882 break;
886 /* the > 1 bit is so that we don't store the { */
887 if (found_dollar && found_lbrac && (count > 1)) {
888 wanted_var[j] = return_string[i];
889 j++; /* check for size */
892 /* skip over initial { */
893 count++;
895 if (found_rbrac && !found_lbrac) {
896 wanted_var[j] = '\0';
897 #if DEBUG
898 printf("variable wanted: _%s_\n", wanted_var);
899 printf("Between index: %d and %d\n",
900 start_of_variable,
901 end_of_variable);
902 #endif
905 environment_string = getenv(wanted_var);
907 #if DEBUG
908 if (environment_string) {
909 printf("%s = _%s_\n", wanted_var,
910 environment_string);
912 #endif
914 return_string = remove_string(return_string,
915 start_of_variable,
916 end_of_variable);
918 #if DEBUG
919 printf("removed string: _%s_\n", return_string);
920 #endif
922 if (environment_string) {
923 return_string = insert_string(
924 return_string,
925 start_of_variable,
926 environment_string);
930 #if DEBUG
931 printf("final string: _%s_\n", return_string);
932 #endif
933 changed=1;
935 /* end of search */
936 found_dollar=0;
937 found_rbrac=0;
938 count=0;
939 start_of_variable= -1;
940 end_of_variable= -1;
942 break;
947 if (found_dollar) {
948 fprintf(stderr, "Found malformed environment variable (use ${varname})!\n");
951 return(return_string);