Updated copyright text/header in most source files.
[geda-gaf/peter-b.git] / libgeda / src / s_basic.c
blob69f8e425eddc6423973dc8d6b455dffd0d926b2c
1 /* gEDA - GPL Electronic Design Automation
2 * libgeda - gEDA's library
3 * Copyright (C) 1998-2010 Ales Hvezda
4 * Copyright (C) 1998-2010 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_STRING_H
28 #include <string.h>
29 #endif
31 #include "libgeda_priv.h"
33 #ifdef HAVE_LIBDMALLOC
34 #include <dmalloc.h>
35 #endif
37 /*! this is modified here and in o_list.c */
38 int global_sid=0;
40 /*! \todo Finish function documentation!!!
41 * \brief
42 * \par Function Description
45 void error_if_called(void)
47 fprintf(stderr, "Somebody called error_if_called!\n");
48 g_assert(0);
51 /*! \todo Finish function documentation!!!
52 * \brief
53 * \par Function Description
56 void exit_if_null(void *ptr)
58 if (ptr == NULL) {
59 fprintf(stderr, "gEDA: Got NULL ptr!, please e-mail maintainer\n");
60 g_assert(0);
61 exit(-1);
66 /*! \brief Initialize an already-allocated object.
67 * \par Function Description
68 * Initializes the members of the OBJECT structure.
70 * \param [in] new_node A pointer to an allocated OBJECT
71 * \param [in] type The object type; one of the OBJ_* constants.
72 * \param [in] name A prefix for the object's session-unique name.
73 * \return A pointer to the initialized object.
75 OBJECT *s_basic_init_object(OBJECT *new_node, int type, char const *name)
77 /* setup sid */
78 new_node->sid = global_sid++;
79 new_node->type = type;
81 /* Setup the name */
82 new_node->name = g_strdup_printf("%s.%d", name, new_node->sid);
84 /* Setup the bounding box */
85 new_node->w_top = 0;
86 new_node->w_left = 0;
87 new_node->w_right = 0;
88 new_node->w_bottom = 0;
89 new_node->w_bounds_valid = FALSE;
91 /* Setup line/circle structs */
92 new_node->line = NULL;
93 new_node->path = NULL;
94 new_node->circle = NULL;
95 new_node->arc = NULL;
96 new_node->box = NULL;
97 new_node->picture = NULL;
98 new_node->text = NULL;
99 new_node->complex = NULL;
101 new_node->tiles = NULL;
103 new_node->conn_list = NULL;
105 new_node->complex_basename = NULL;
106 new_node->parent = NULL;
108 /* Setup the color */
109 new_node->color = DEFAULT_COLOR;
110 new_node->selected = FALSE;
111 new_node->dont_redraw = FALSE;
112 new_node->locked_color = -1;
114 new_node->bus_ripper_direction = 0;
116 new_node->action_func = error_if_called;
117 new_node->sel_func = error_if_called;
118 new_node->draw_func = error_if_called;
120 new_node->line_end = END_NONE;
121 new_node->line_type = TYPE_SOLID;
122 new_node->line_width = 0;
123 new_node->line_space = 0;
124 new_node->line_length = 0;
125 new_node->fill_width = 0;
126 new_node->fill_angle1 = 0;
127 new_node->fill_angle2 = 0;
128 new_node->fill_pitch1 = 0;
129 new_node->fill_pitch2 = 0;
131 new_node->attribs = NULL;
132 new_node->attached_to = NULL;
133 new_node->copied_to = NULL;
134 new_node->show_name_value = SHOW_NAME_VALUE;
135 new_node->visibility = VISIBLE;
137 new_node->pin_type = PIN_TYPE_NET;
138 new_node->whichend = -1;
140 return(new_node);
144 /*! \brief Helper to allocate and initialise an object.
146 * \par Function Description
147 * Allocates memory for an OBJECT and then calls s_basic_init_object() on it.
149 * \param [in] type The sub-type of the object to create; one of the OBJ_* constants.
150 * \param [in] prefix The name prefix for the session-unique object name.
151 * \return A pointer to the fully constructed OBJECT.
153 OBJECT *s_basic_new_object(int type, char const *prefix)
155 return s_basic_init_object(g_malloc(sizeof (OBJECT)), type, prefix);
159 /*! \todo Finish function documentation!!!
160 * \brief
161 * \par Function Description
164 void print_struct_forw (GList *list)
166 OBJECT *o_current=NULL;
167 GList *iter;
169 iter = list;
170 printf("TRYING to PRINT\n");
171 while (iter != NULL) {
172 o_current = (OBJECT *)iter->data;
173 printf("Name: %s\n", o_current->name);
174 printf("Type: %d\n", o_current->type);
175 printf("Sid: %d\n", o_current->sid);
177 if (o_current->type == OBJ_COMPLEX || o_current->type == OBJ_PLACEHOLDER) {
178 print_struct_forw(o_current->complex->prim_objs);
181 o_attrib_print (o_current->attribs);
183 printf("----\n");
184 iter = g_list_next (iter);
188 /*! \todo Finish function documentation!!!
189 * \brief
190 * \par Function Description
193 void print_struct(OBJECT *ptr)
195 OBJECT *o_current=NULL;
197 o_current = ptr;
199 if (o_current != NULL) {
200 printf("Name: %s\n", o_current->name);
201 printf("Type: %d\n", o_current->type);
202 printf("Sid: %d\n", o_current->sid);
203 if (o_current->line != NULL) {
204 printf("Line points.x1: %d\n", o_current->line->x[0]);
205 printf("Line points.y1: %d\n", o_current->line->y[0]);
206 printf("Line points.x2: %d\n", o_current->line->x[1]);
207 printf("Line points.y2: %d\n", o_current->line->y[1]);
210 o_attrib_print (o_current->attribs);
212 printf("----\n");
216 /*! \todo Finish function documentation!!!
217 * \brief
218 * \par Function Description
221 void
222 s_delete_object(TOPLEVEL *toplevel, OBJECT *o_current)
224 if (o_current != NULL) {
225 s_conn_remove_object (toplevel, o_current);
227 if (o_current->attached_to != NULL) {
228 /* do the actual remove */
229 o_attrib_remove(toplevel, &o_current->attached_to->attribs, o_current);
232 if (toplevel->page_current->object_lastplace == o_current) {
233 toplevel->page_current->object_lastplace = NULL;
236 if (o_current->line) {
237 /* printf("sdeleting line\n");*/
238 g_free(o_current->line);
240 /* yes this object might be in the tile system */
241 s_tile_remove_object(o_current);
243 o_current->line = NULL;
245 if (o_current->path) {
246 g_free(o_current->path);
248 o_current->path = NULL;
250 /* printf("sdeleting circle\n");*/
251 g_free(o_current->circle);
252 o_current->circle = NULL;
254 /* printf("sdeleting arc\n");*/
255 g_free(o_current->arc);
256 o_current->arc = NULL;
258 /* printf("sdeleting box\n");*/
259 g_free(o_current->box);
260 o_current->box = NULL;
262 if (o_current->picture) {
263 /* printf("sdeleting picture\n");*/
265 g_free(o_current->picture->file_content);
266 if (o_current->picture->pixbuf)
267 g_object_unref (o_current->picture->pixbuf);
269 g_free(o_current->picture->filename);
270 g_free(o_current->picture);
272 o_current->picture = NULL;
274 if (o_current->text) {
275 /*printf("sdeleting text->string\n");*/
276 g_free(o_current->text->string);
277 o_current->text->string = NULL;
278 g_free(o_current->text->disp_string);
279 /* printf("sdeleting text\n");*/
280 g_free(o_current->text);
282 o_current->text = NULL;
284 /* printf("sdeleting name\n");*/
285 g_free(o_current->name);
286 o_current->name = NULL;
289 /* printf("sdeleting complex_basename\n");*/
290 g_free(o_current->complex_basename);
291 o_current->complex_basename = NULL;
293 if (o_current->complex) {
295 if (o_current->complex->prim_objs) {
296 /* printf("sdeleting complex->primitive_objects\n");*/
297 s_delete_object_glist (toplevel, o_current->complex->prim_objs);
298 o_current->complex->prim_objs = NULL;
301 g_free(o_current->complex);
302 o_current->complex = NULL;
305 o_attrib_detach_all (toplevel, o_current);
307 g_free(o_current); /* assuming it is not null */
309 o_current=NULL; /* misc clean up */
313 /*! \todo Finish function documentation!!!
314 * \brief
315 * \par Function Description
318 /* deletes everything include the GList */
319 void
320 s_delete_object_glist(TOPLEVEL *toplevel, GList *list)
322 OBJECT *o_current=NULL;
323 GList *ptr;
325 ptr = g_list_last(list);
327 /* do the delete backwards */
328 while(ptr != NULL) {
329 o_current = (OBJECT *) ptr->data;
330 s_delete_object(toplevel, o_current);
331 ptr = g_list_previous (ptr);
333 g_list_free(list);
337 /*! \todo Finish function documentation!!!
338 * \brief
339 * \par Function Description
342 /* used by o_text_read */
343 char *remove_nl(char *string)
345 int i;
347 if (!string)
348 return NULL;
350 i = 0;
351 while(string[i] != '\0' && string[i] != '\n' && string[i] != '\r') {
352 i++;
355 string[i] = '\0';
357 return(string);
360 /*! \todo Finish function documentation!!!
361 * \brief
362 * \par Function Description
365 /* used by o_text_read */
366 char *remove_last_nl(char *string)
368 int len;
370 if (!string)
371 return NULL;
373 len = strlen(string);
374 if (string[len-1] == '\n' || string[len-1] == '\r')
375 string[len-1] = '\0';
377 return(string);
380 /*! \brief Expand environment variables in string.
381 * \par Function Description
382 * This function returns the passed string with environment variables
383 * expanded.
385 * The invocations of environment variable MUST be in the form
386 * '${variable_name}', '$variable_name' is not valid here. Environment
387 * variable names consists solely of letters, digits and '_'. It is
388 * possible to escape a '$' character in the string by repeating it
389 * twice.
391 * It outputs error messages to console and leaves the malformed and
392 * bad variable names in the returned string.
394 * \param [in] string The string with variables to expand.
395 * \return A newly-allocated string with variables expanded or NULL
396 * if input string was NULL.
398 gchar*
399 s_expand_env_variables (const gchar *string)
401 GString *gstring;
402 gint i;
404 if (string == NULL) {
405 return NULL;
408 gstring = g_string_sized_new (strlen (string));
409 i = 0;
410 while (TRUE) {
411 gint start;
413 start = i;
414 /* look for end of string or possible variable name start */
415 while (string[i] != '\0' && string[i] != '$') i++;
416 g_string_append_len (gstring, string + start, i - start);
417 if (string[i] == '\0') {
418 /* end of string, return built string */
419 return g_string_free (gstring, FALSE);
422 i++;
423 switch (string[i]) {
424 case ('{'):
425 /* look for the end of the variable name */
426 start = i;
427 while (string[i] != '\0' && string[i] != '}') i++;
428 if (string[i] == '\0') {
429 /* problem: no closing '}' to variable */
430 fprintf (stderr,
431 "Found malformed environment variable in '%s'\n",
432 string);
433 g_string_append (gstring, "$");
434 g_string_append_len (gstring, string + start, i - start + 1);
435 } else {
436 gint j;
438 /* discard "${" */
439 start = start + 1;
440 /* test characters of variable name */
441 for (j = start;
442 j < i && (g_ascii_isalnum (string[j]) || string[j] == '_');
443 j++);
444 if (i != j) {
445 /* illegal character detected in variable name */
446 fprintf (stderr,
447 "Found bad character [%c] in variable name.\n",
448 string[j]);
449 g_string_append (gstring, "${");
450 g_string_append_len (gstring, string + start, i - start + 1);
451 } else {
452 /* extract variable name from string and expand it */
453 gchar *variable_name = g_strndup (string + start, i - start);
454 const gchar *env = g_getenv (variable_name);
455 g_free (variable_name);
456 g_string_append (gstring, (env == NULL) ? "" : env);
458 i++;
460 break;
462 case ('$'):
463 /* an escaped '$' */
464 g_string_append_c (gstring, string[i++]);
465 break;
467 default:
468 /* an isolated '$', put it in output */
469 g_string_append_c (gstring, '$');
473 /* never reached */
474 return NULL;
478 /* -------------------------------------------------- */
480 /*! \brief Get the directory with the gEDA system data.
481 * \par Function description
482 * Returns the path to be searched for gEDA data shared between all
483 * users. If the GEDADATA environment variable is set, returns its
484 * value; otherwise, uses a compiled-in path.
486 * On Windows, the compiled in path is *not* used, as it might not
487 * match the path where the user has installed gEDA.
489 * \warning The returned string is owned by libgeda and should not be
490 * modified or free'd.
492 * \return the gEDA shared data path, or NULL if none could be found.
494 const char *s_path_sys_data () {
495 static const char *p = NULL;
496 if (p == NULL) {
497 p = g_getenv ("GEDADATA");
499 # if !defined (_WIN32)
500 if (p == NULL) {
501 p = GEDADATADIR;
502 g_setenv ("GEDADATA", p, FALSE);
504 # endif
505 return p;
508 /*! \brief Get the directory with the gEDA system configuration.
509 * \par Function description
510 * Returns the path to be searched for gEDA configuration shared
511 * between all users. If the GEDADATARC environment variable is set,
512 * returns its value; otherwise, uses a compiled-in path. Finally
513 * fallback to using the system data path.
515 * \warning The returned string is owned by libgeda and should not be
516 * modified or free'd.
518 * \return the gEDA shared config path, or NULL if none could be
519 * found.
521 const char *s_path_sys_config () {
522 static const char *p = NULL;
524 /* If GEDADATARC is set in the environment, use that path */
525 if (p == NULL) {
526 p = g_getenv ("GEDADATARC");
528 if (p == NULL) {
529 #ifdef GEDARCDIR
530 /* If available, use the rc directory set during configure. */
531 p = GEDARCDIR;
532 #else
533 /* Otherwise, just use the data directory */
534 p = s_path_sys_data ();
535 #endif
537 if (p != NULL) g_setenv("GEDADATARC", p, FALSE);
538 return p;
541 /*! \brief Get the directory with the gEDA user configuration.
542 * \par Function description
543 * Returns the path to be searched for the current user's gEDA
544 * configuration. Currently defaults to a directory ".gEDA" in the
545 * user's home directory.
547 * \warning The returned string is owned by libgeda and should not be
548 * modified or free'd.
550 * \todo On Windows, we should use APPDATA.
552 const char *s_path_user_config () {
553 static const char *p = NULL;
555 if (p == NULL) {
556 const char *home = g_getenv ("HOME");
557 if (home == NULL) home = g_get_home_dir ();
558 p = g_build_filename(home, ".gEDA", NULL);
560 return p;