refdes_renum: warn of possible number clash with non-conforming values
[geda-gaf/whiteaudio.git] / libgeda / src / s_basic.c
blob5923813a7d0653c771de2021d33392ad719ce9df
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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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 #ifdef G_OS_WIN32
38 # define STRICT
39 # include <windows.h>
40 # undef STRICT
41 # ifndef GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS
42 # define GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT 2
43 # define GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS 4
44 # endif
45 #endif
47 /*! this is modified here and in o_list.c */
48 int global_sid=0;
50 /*! \brief Initialize an already-allocated object.
51 * \par Function Description
52 * Initializes the members of the OBJECT structure.
54 * \param [in] new_node A pointer to an allocated OBJECT
55 * \param [in] type The object type; one of the OBJ_* constants.
56 * \param [in] name A prefix for the object's session-unique name.
57 * \return A pointer to the initialized object.
59 OBJECT *s_basic_init_object(OBJECT *new_node, int type, char const *name)
61 /* setup sid */
62 new_node->sid = global_sid++;
63 new_node->type = type;
65 /* Setup the name */
66 new_node->name = g_strdup_printf("%s.%d", name, new_node->sid);
68 /* Don't associate with a page, initially */
69 new_node->page = NULL;
71 /* Setup the bounding box */
72 new_node->w_top = 0;
73 new_node->w_left = 0;
74 new_node->w_right = 0;
75 new_node->w_bottom = 0;
76 new_node->w_bounds_valid = FALSE;
78 /* Setup line/circle structs */
79 new_node->line = NULL;
80 new_node->path = NULL;
81 new_node->circle = NULL;
82 new_node->arc = NULL;
83 new_node->box = NULL;
84 new_node->picture = NULL;
85 new_node->text = NULL;
86 new_node->complex = NULL;
88 new_node->tiles = NULL;
90 new_node->conn_list = NULL;
92 new_node->complex_basename = NULL;
93 new_node->parent = NULL;
95 /* Setup the color */
96 new_node->color = DEFAULT_COLOR;
97 new_node->dont_redraw = FALSE;
98 new_node->selectable = TRUE;
99 new_node->selected = FALSE;
100 new_node->locked_color = -1;
102 new_node->bus_ripper_direction = 0;
104 new_node->line_end = END_NONE;
105 new_node->line_type = TYPE_SOLID;
106 new_node->line_width = 0;
107 new_node->line_space = 0;
108 new_node->line_length = 0;
109 new_node->fill_width = 0;
110 new_node->fill_angle1 = 0;
111 new_node->fill_angle2 = 0;
112 new_node->fill_pitch1 = 0;
113 new_node->fill_pitch2 = 0;
115 new_node->attribs = NULL;
116 new_node->attached_to = NULL;
117 new_node->copied_to = NULL;
118 new_node->show_name_value = SHOW_NAME_VALUE;
119 new_node->visibility = VISIBLE;
121 new_node->pin_type = PIN_TYPE_NET;
122 new_node->whichend = -1;
124 new_node->net_num_connected = 0;
125 new_node->valid_num_connected = FALSE;
127 new_node->weak_refs = NULL;
129 new_node->attrib_notify_freeze_count = 0;
130 new_node->attrib_notify_pending = 0;
132 new_node->conn_notify_freeze_count = 0;
133 new_node->conn_notify_pending = 0;
135 return(new_node);
139 /*! \brief Helper to allocate and initialise an object.
141 * \par Function Description
142 * Allocates memory for an OBJECT and then calls s_basic_init_object() on it.
144 * \param [in] type The sub-type of the object to create; one of the OBJ_* constants.
145 * \param [in] prefix The name prefix for the session-unique object name.
146 * \return A pointer to the fully constructed OBJECT.
148 OBJECT *s_basic_new_object(int type, char const *prefix)
150 return s_basic_init_object(g_malloc(sizeof (OBJECT)), type, prefix);
154 /*! \todo Finish function documentation!!!
155 * \brief
156 * \par Function Description
159 void print_struct_forw (GList *list)
161 OBJECT *o_current=NULL;
162 GList *iter;
164 iter = list;
165 printf("TRYING to PRINT\n");
166 while (iter != NULL) {
167 o_current = (OBJECT *)iter->data;
168 printf("Name: %s\n", o_current->name);
169 printf("Type: %d\n", o_current->type);
170 printf("Sid: %d\n", o_current->sid);
172 if (o_current->type == OBJ_COMPLEX || o_current->type == OBJ_PLACEHOLDER) {
173 print_struct_forw(o_current->complex->prim_objs);
176 o_attrib_print (o_current->attribs);
178 printf("----\n");
179 iter = g_list_next (iter);
183 /*! \todo Finish function documentation!!!
184 * \brief
185 * \par Function Description
188 void print_struct(OBJECT *ptr)
190 OBJECT *o_current=NULL;
192 o_current = ptr;
194 if (o_current != NULL) {
195 printf("Name: %s\n", o_current->name);
196 printf("Type: %d\n", o_current->type);
197 printf("Sid: %d\n", o_current->sid);
198 if (o_current->line != NULL) {
199 printf("Line points.x1: %d\n", o_current->line->x[0]);
200 printf("Line points.y1: %d\n", o_current->line->y[0]);
201 printf("Line points.x2: %d\n", o_current->line->x[1]);
202 printf("Line points.y2: %d\n", o_current->line->y[1]);
205 o_attrib_print (o_current->attribs);
207 printf("----\n");
211 /*! \todo Finish function documentation!!!
212 * \brief
213 * \par Function Description
216 void
217 s_delete_object(TOPLEVEL *toplevel, OBJECT *o_current)
219 if (o_current != NULL) {
220 /* If currently attached to a page, remove it from the page */
221 if (o_current->page != NULL) {
222 s_page_remove (toplevel, o_current->page, o_current);
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 /* Don't bother with hooks for this dying object,
233 * leak the freeze count, so the object dies frozen.
235 o_attrib_freeze_hooks (toplevel, o_current);
236 o_attrib_detach_all (toplevel, o_current);
238 if (o_current->line) {
239 /* printf("sdeleting line\n");*/
240 g_free(o_current->line);
242 o_current->line = NULL;
244 if (o_current->path) {
245 g_free(o_current->path);
247 o_current->path = NULL;
249 /* printf("sdeleting circle\n");*/
250 g_free(o_current->circle);
251 o_current->circle = NULL;
253 /* printf("sdeleting arc\n");*/
254 g_free(o_current->arc);
255 o_current->arc = NULL;
257 /* printf("sdeleting box\n");*/
258 g_free(o_current->box);
259 o_current->box = NULL;
261 if (o_current->picture) {
262 /* printf("sdeleting picture\n");*/
264 g_free(o_current->picture->file_content);
265 if (o_current->picture->pixbuf)
266 g_object_unref (o_current->picture->pixbuf);
268 g_free(o_current->picture->filename);
269 g_free(o_current->picture);
271 o_current->picture = NULL;
273 if (o_current->text) {
274 /*printf("sdeleting text->string\n");*/
275 g_free(o_current->text->string);
276 o_current->text->string = NULL;
277 g_free(o_current->text->disp_string);
278 /* printf("sdeleting text\n");*/
279 g_free(o_current->text);
281 o_current->text = NULL;
283 /* printf("sdeleting name\n");*/
284 g_free(o_current->name);
285 o_current->name = NULL;
288 /* printf("sdeleting complex_basename\n");*/
289 g_free(o_current->complex_basename);
290 o_current->complex_basename = NULL;
292 if (o_current->complex) {
294 if (o_current->complex->prim_objs) {
295 /* printf("sdeleting complex->primitive_objects\n");*/
296 s_delete_object_glist (toplevel, o_current->complex->prim_objs);
297 o_current->complex->prim_objs = NULL;
300 g_free(o_current->complex);
301 o_current->complex = NULL;
304 s_weakref_notify (o_current, o_current->weak_refs);
306 g_free(o_current); /* assuming it is not null */
308 o_current=NULL; /* misc clean up */
312 /*! \todo Finish function documentation!!!
313 * \brief
314 * \par Function Description
317 /* deletes everything include the GList */
318 void
319 s_delete_object_glist(TOPLEVEL *toplevel, GList *list)
321 OBJECT *o_current=NULL;
322 GList *ptr;
324 ptr = g_list_last(list);
326 /* do the delete backwards */
327 while(ptr != NULL) {
328 o_current = (OBJECT *) ptr->data;
329 s_delete_object(toplevel, o_current);
330 ptr = g_list_previous (ptr);
332 g_list_free(list);
335 /*! \brief Add a weak reference watcher to an OBJECT.
336 * \par Function Description
337 * Adds the weak reference callback \a notify_func to \a object. When
338 * \a object is destroyed, \a notify_func will be called with two
339 * arguments: the \a object, and the \a user_data.
341 * \sa s_object_weak_unref
343 * \param [in,out] object Object to weak-reference.
344 * \param [in] notify_func Weak reference notify function.
345 * \param [in] user_data Data to be passed to \a notify_func.
347 void
348 s_object_weak_ref (OBJECT *object,
349 void (*notify_func)(void *, void *),
350 void *user_data)
352 g_return_if_fail (object != NULL);
353 object->weak_refs = s_weakref_add (object->weak_refs, notify_func, user_data);
356 /*! \brief Remove a weak reference watcher from an OBJECT.
357 * \par Function Description
358 * Removes the weak reference callback \a notify_func from \a object.
360 * \sa s_object_weak_ref()
362 * \param [in,out] object Object to weak-reference.
363 * \param [in] notify_func Notify function to search for.
364 * \param [in] user_data Data to to search for.
366 void
367 s_object_weak_unref (OBJECT *object,
368 void (*notify_func)(void *, void *),
369 void *user_data)
371 g_return_if_fail (object != NULL);
372 object->weak_refs = s_weakref_remove (object->weak_refs,
373 notify_func, user_data);
376 /*! \brief Add a weak pointer to an OBJECT.
377 * \par Function Description
378 * Adds the weak pointer at \a weak_pointer_loc to \a object. The
379 * value of \a weak_pointer_loc will be set to NULL when \a object is
380 * destroyed.
382 * \sa s_object_remove_weak_ptr
384 * \param [in,out] object Object to weak-reference.
385 * \param [in] weak_pointer_loc Memory address of a pointer.
387 void
388 s_object_add_weak_ptr (OBJECT *object,
389 void *weak_pointer_loc)
391 g_return_if_fail (object != NULL);
392 object->weak_refs = s_weakref_add_ptr (object->weak_refs, weak_pointer_loc);
395 /*! \brief Remove a weak pointer from an OBJECT.
396 * \par Function Description
397 * Removes the weak pointer at \a weak_pointer_loc from \a object.
399 * \sa s_object_add_weak_ptr()
401 * \param [in,out] object Object to weak-reference.
402 * \param [in] weak_pointer_loc Memory address of a pointer.
404 void
405 s_object_remove_weak_ptr (OBJECT *object,
406 void *weak_pointer_loc)
408 g_return_if_fail (object != NULL);
409 object->weak_refs = s_weakref_remove_ptr (object->weak_refs,
410 weak_pointer_loc);
413 /*! \todo Finish function documentation!!!
414 * \brief
415 * \par Function Description
418 /* used by o_text_read */
419 char *remove_nl(char *string)
421 int i;
423 if (!string)
424 return NULL;
426 i = 0;
427 while(string[i] != '\0' && string[i] != '\n' && string[i] != '\r') {
428 i++;
431 string[i] = '\0';
433 return(string);
436 /*! \todo Finish function documentation!!!
437 * \brief
438 * \par Function Description
441 /* used by o_text_read */
442 char *remove_last_nl(char *string)
444 int len;
446 if (!string)
447 return NULL;
449 len = strlen(string);
450 if (string[len-1] == '\n' || string[len-1] == '\r')
451 string[len-1] = '\0';
453 return(string);
456 /*! \brief Expand environment variables in string.
457 * \par Function Description
458 * This function returns the passed string with environment variables
459 * expanded.
461 * The invocations of environment variable MUST be in the form
462 * '${variable_name}', '$variable_name' is not valid here. Environment
463 * variable names consists solely of letters, digits and '_'. It is
464 * possible to escape a '$' character in the string by repeating it
465 * twice.
467 * It outputs error messages to console and leaves the malformed and
468 * bad variable names in the returned string.
470 * \param [in] string The string with variables to expand.
471 * \return A newly-allocated string with variables expanded or NULL
472 * if input string was NULL.
474 gchar*
475 s_expand_env_variables (const gchar *string)
477 GString *gstring;
478 gint i;
480 if (string == NULL) {
481 return NULL;
484 gstring = g_string_sized_new (strlen (string));
485 i = 0;
486 while (TRUE) {
487 gint start;
489 start = i;
490 /* look for end of string or possible variable name start */
491 while (string[i] != '\0' && string[i] != '$') i++;
492 g_string_append_len (gstring, string + start, i - start);
493 if (string[i] == '\0') {
494 /* end of string, return built string */
495 return g_string_free (gstring, FALSE);
498 i++;
499 switch (string[i]) {
500 case ('{'):
501 /* look for the end of the variable name */
502 start = i;
503 while (string[i] != '\0' && string[i] != '}') i++;
504 if (string[i] == '\0') {
505 /* problem: no closing '}' to variable */
506 fprintf (stderr,
507 "Found malformed environment variable in '%s'\n",
508 string);
509 g_string_append (gstring, "$");
510 g_string_append_len (gstring, string + start, i - start + 1);
511 } else {
512 gint j;
514 /* discard "${" */
515 start = start + 1;
516 /* test characters of variable name */
517 for (j = start;
518 j < i && (g_ascii_isalnum (string[j]) || string[j] == '_');
519 j++);
520 if (i != j) {
521 /* illegal character detected in variable name */
522 fprintf (stderr,
523 "Found bad character [%c] in variable name.\n",
524 string[j]);
525 g_string_append (gstring, "${");
526 g_string_append_len (gstring, string + start, i - start + 1);
527 } else {
528 /* extract variable name from string and expand it */
529 gchar *variable_name = g_strndup (string + start, i - start);
530 const gchar *env = g_getenv (variable_name);
531 g_free (variable_name);
532 g_string_append (gstring, (env == NULL) ? "" : env);
534 i++;
536 break;
538 case ('$'):
539 /* an escaped '$' */
540 g_string_append_c (gstring, string[i++]);
541 break;
543 default:
544 /* an isolated '$', put it in output */
545 g_string_append_c (gstring, '$');
549 /* never reached */
550 return NULL;
554 /* -------------------------------------------------- */
556 #ifdef G_OS_WIN32
558 /* Get a module handle for the libgeda DLL.
560 * Adapted from GLib, originally licensed under LGPLv2+. */
561 static gpointer
562 libgeda_module_handle ()
564 typedef BOOL (WINAPI *t_GetModuleHandleExA) (DWORD, LPCTSTR, HMODULE *);
565 static t_GetModuleHandleExA p_GetModuleHandleExA = NULL;
566 static gconstpointer address = (void (*)(void)) &libgeda_module_handle;
567 static HMODULE hmodule = NULL;
569 if (hmodule != NULL) return (gpointer) hmodule;
571 if (p_GetModuleHandleExA == NULL) {
572 p_GetModuleHandleExA =
573 (t_GetModuleHandleExA) GetProcAddress (GetModuleHandle ("kernel32.dll"),
574 "GetModuleHandleExA");
577 if (p_GetModuleHandleExA == NULL ||
578 !(*p_GetModuleHandleExA) (GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT |
579 GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS,
580 address, &hmodule)) {
581 MEMORY_BASIC_INFORMATION mbi;
582 VirtualQuery (address, &mbi, sizeof (mbi));
583 hmodule = (HMODULE) mbi.AllocationBase;
586 return (gpointer) hmodule;
589 #endif /* G_OS_WIN32 */
591 /*! \brief Get the directory with the gEDA system data.
592 * \par Function description
593 * Returns the path to be searched for gEDA data shared between all
594 * users. If the GEDADATA environment variable is set, returns its
595 * value; otherwise, uses a compiled-in path.
597 * On Windows, the compiled in path is *not* used, as it might not
598 * match the path where the user has installed gEDA.
600 * \warning The returned string is owned by libgeda and should not be
601 * modified or free'd.
603 * \todo On UNIX platforms we should follow the XDG Base Directory
604 * Specification.
606 * \return the gEDA shared data path, or NULL if none could be found.
608 const char *s_path_sys_data () {
609 static const char *p = NULL;
610 /* If GEDADATA is set in the environment, use that path */
611 if (p == NULL) {
612 p = g_getenv ("GEDADATA");
614 if (p == NULL) {
615 # if defined (G_OS_WIN32)
616 /* On Windows, guess the path from the location of the libgeda
617 * DLL. */
618 gchar *d =
619 g_win32_get_package_installation_directory_of_module (libgeda_module_handle ());
620 p = g_build_filename (d, "share", "gEDA", NULL);
621 g_free (d);
622 # else
623 /* On other platforms, use the compiled-in path */
624 p = GEDADATADIR;
625 # endif
626 g_setenv ("GEDADATA", p, FALSE);
628 return p;
631 /*! \brief Get the directory with the gEDA system configuration.
632 * \par Function description
633 * Returns the path to be searched for gEDA configuration shared
634 * between all users. If the GEDADATARC environment variable is set,
635 * returns its value; otherwise, uses a compiled-in path. Finally
636 * fallback to using the system data path.
638 * \warning The returned string is owned by libgeda and should not be
639 * modified or free'd.
641 * \todo On UNIX platforms we should follow the XDG Base Directory
642 * Specification.
644 * \return the gEDA shared config path, or NULL if none could be
645 * found.
647 const char *s_path_sys_config () {
648 static const char *p = NULL;
650 /* If GEDADATARC is set in the environment, use that path */
651 if (p == NULL) {
652 p = g_getenv ("GEDADATARC");
654 if (p == NULL) {
655 #if defined (GEDARCDIR) && !defined(_WIN32)
656 /* If available, use the rc directory set during configure. */
657 p = GEDARCDIR;
658 #else
659 /* Otherwise, just use the data directory */
660 p = s_path_sys_data ();
661 #endif
663 if (p != NULL) g_setenv("GEDADATARC", p, FALSE);
664 return p;
667 /*! \brief Get the directory with the gEDA user configuration.
668 * \par Function description
669 * Returns the path to be searched for the current user's gEDA
670 * configuration. Currently defaults to a directory ".gEDA" in the
671 * user's home directory.
673 * \warning The returned string is owned by libgeda and should not be
674 * modified or free'd.
676 * \todo On Windows, we should use APPDATA.
678 * \todo On UNIX platforms we should follow the XDG Base Directory
679 * Specification.
681 const char *s_path_user_config () {
682 static const char *p = NULL;
684 if (p == NULL) {
685 const char *home = g_getenv ("HOME");
686 if (home == NULL) home = g_get_home_dir ();
687 p = g_build_filename(home, ".gEDA", NULL);
689 return p;