1 /* gEDA - GPL Electronic Design Automation
2 * libgeda - gEDA's library
3 * Copyright (C) 1998-2010 Ales Hvezda
4 * Copyright (C) 1998-2020 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
31 #include "libgeda_priv.h"
39 # ifndef GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS
40 # define GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT 2
41 # define GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS 4
45 /*! this is modified here and in o_list.c */
48 /*! \brief Initialize an already-allocated object.
49 * \par Function Description
50 * Initializes the members of the OBJECT structure.
52 * \param [in] new_node A pointer to an allocated OBJECT
53 * \param [in] type The object type; one of the OBJ_* constants.
54 * \param [in] name A prefix for the object's session-unique name.
55 * \return A pointer to the initialized object.
57 OBJECT
*s_basic_init_object(OBJECT
*new_node
, int type
, char const *name
)
60 new_node
->sid
= global_sid
++;
61 new_node
->type
= type
;
64 new_node
->name
= g_strdup_printf("%s.%d", name
, new_node
->sid
);
66 /* Don't associate with a page, initially */
67 new_node
->page
= NULL
;
69 /* Setup the bounding box */
72 new_node
->w_right
= 0;
73 new_node
->w_bottom
= 0;
74 new_node
->w_bounds_valid_for
= NULL
;
76 /* Setup line/circle structs */
77 new_node
->line
= NULL
;
78 new_node
->path
= NULL
;
79 new_node
->circle
= NULL
;
82 new_node
->picture
= NULL
;
83 new_node
->text
= NULL
;
84 new_node
->complex = NULL
;
86 new_node
->conn_list
= NULL
;
88 new_node
->complex_embedded
= FALSE
;
89 new_node
->complex_basename
= NULL
;
90 new_node
->parent
= NULL
;
93 new_node
->color
= DEFAULT_COLOR
;
94 new_node
->dont_redraw
= FALSE
;
95 new_node
->selectable
= TRUE
;
96 new_node
->selected
= FALSE
;
97 new_node
->locked_color
= -1;
99 new_node
->bus_ripper_direction
= 0;
101 new_node
->line_end
= END_NONE
;
102 new_node
->line_type
= TYPE_SOLID
;
103 new_node
->line_width
= 0;
104 new_node
->line_space
= 0;
105 new_node
->line_length
= 0;
107 new_node
->fill_type
= FILLING_HOLLOW
;
108 new_node
->fill_width
= 0;
109 new_node
->fill_angle1
= 0;
110 new_node
->fill_angle2
= 0;
111 new_node
->fill_pitch1
= 0;
112 new_node
->fill_pitch2
= 0;
114 new_node
->font_text_size
= 0;
115 new_node
->font_prim_objs
= NULL
;
117 new_node
->attribs
= NULL
;
118 new_node
->attached_to
= NULL
;
119 new_node
->copied_to
= NULL
;
120 new_node
->show_name_value
= SHOW_NAME_VALUE
;
121 new_node
->visibility
= VISIBLE
;
123 new_node
->pin_type
= PIN_TYPE_NET
;
124 new_node
->whichend
= -1;
126 new_node
->weak_refs
= NULL
;
132 /*! \brief Helper to allocate and initialise an object.
134 * \par Function Description
135 * Allocates memory for an OBJECT and then calls s_basic_init_object() on it.
137 * \param [in] type The sub-type of the object to create; one of the OBJ_* constants.
138 * \param [in] prefix The name prefix for the session-unique object name.
139 * \return A pointer to the fully constructed OBJECT.
141 OBJECT
*s_basic_new_object(int type
, char const *prefix
)
143 return s_basic_init_object(g_malloc(sizeof (OBJECT
)), type
, prefix
);
147 /*! \todo Finish function documentation!!!
149 * \par Function Description
152 void print_struct_forw (GList
*list
)
154 OBJECT
*o_current
=NULL
;
158 printf("TRYING to PRINT\n");
159 while (iter
!= NULL
) {
160 o_current
= (OBJECT
*)iter
->data
;
161 printf("Name: %s\n", o_current
->name
);
162 printf("Type: %d\n", o_current
->type
);
163 printf("Sid: %d\n", o_current
->sid
);
165 if (o_current
->type
== OBJ_COMPLEX
|| o_current
->type
== OBJ_PLACEHOLDER
) {
166 print_struct_forw(o_current
->complex->prim_objs
);
169 o_attrib_print (o_current
->attribs
);
172 iter
= g_list_next (iter
);
176 /*! \todo Finish function documentation!!!
178 * \par Function Description
182 s_delete_object(TOPLEVEL
*toplevel
, OBJECT
*o_current
)
184 if (o_current
!= NULL
) {
185 /* If currently attached to a page, remove it from the page */
186 if (o_current
->page
!= NULL
) {
187 s_page_remove (toplevel
, o_current
->page
, o_current
);
190 s_conn_remove_object_connections (toplevel
, o_current
);
192 if (o_current
->attached_to
!= NULL
) {
193 /* do the actual remove */
194 o_attrib_remove(toplevel
, &o_current
->attached_to
->attribs
, o_current
);
197 if (o_current
->line
) {
198 /* printf("sdeleting line\n");*/
199 g_free(o_current
->line
);
201 o_current
->line
= NULL
;
203 if (o_current
->path
) {
204 g_free(o_current
->path
);
206 o_current
->path
= NULL
;
208 /* printf("sdeleting circle\n");*/
209 g_free(o_current
->circle
);
210 o_current
->circle
= NULL
;
212 /* printf("sdeleting arc\n");*/
213 g_free(o_current
->arc
);
214 o_current
->arc
= NULL
;
216 /* printf("sdeleting box\n");*/
217 g_free(o_current
->box
);
218 o_current
->box
= NULL
;
220 if (o_current
->picture
) {
221 /* printf("sdeleting picture\n");*/
223 g_free(o_current
->picture
->file_content
);
224 if (o_current
->picture
->pixbuf
)
225 g_object_unref (o_current
->picture
->pixbuf
);
227 g_free(o_current
->picture
->filename
);
228 g_free(o_current
->picture
);
230 o_current
->picture
= NULL
;
232 if (o_current
->text
) {
233 /*printf("sdeleting text->string\n");*/
234 g_free(o_current
->text
->string
);
235 o_current
->text
->string
= NULL
;
236 g_free(o_current
->text
->disp_string
);
237 /* printf("sdeleting text\n");*/
238 g_free(o_current
->text
);
240 o_current
->text
= NULL
;
242 /* printf("sdeleting name\n");*/
243 g_free(o_current
->name
);
244 o_current
->name
= NULL
;
247 /* printf("sdeleting complex_basename\n");*/
248 g_free(o_current
->complex_basename
);
249 o_current
->complex_basename
= NULL
;
251 if (o_current
->complex) {
253 if (o_current
->complex->prim_objs
) {
254 /* printf("sdeleting complex->primitive_objects\n");*/
255 s_delete_object_glist (toplevel
, o_current
->complex->prim_objs
);
256 o_current
->complex->prim_objs
= NULL
;
259 g_free(o_current
->complex);
260 o_current
->complex = NULL
;
263 o_attrib_detach_all (toplevel
, o_current
);
265 s_weakref_notify (o_current
, o_current
->weak_refs
);
267 g_free(o_current
); /* assuming it is not null */
269 o_current
=NULL
; /* misc clean up */
273 /*! \todo Finish function documentation!!!
275 * \par Function Description
278 /* deletes everything include the GList */
280 s_delete_object_glist(TOPLEVEL
*toplevel
, GList
*list
)
282 OBJECT
*o_current
=NULL
;
285 ptr
= g_list_last(list
);
287 /* do the delete backwards */
289 o_current
= (OBJECT
*) ptr
->data
;
290 s_delete_object(toplevel
, o_current
);
291 ptr
= g_list_previous (ptr
);
296 /*! \brief Add a weak reference watcher to an OBJECT.
297 * \par Function Description
298 * Adds the weak reference callback \a notify_func to \a object. When
299 * \a object is destroyed, \a notify_func will be called with two
300 * arguments: the \a object, and the \a user_data.
302 * \sa s_object_weak_unref
304 * \param [in,out] object Object to weak-reference.
305 * \param [in] notify_func Weak reference notify function.
306 * \param [in] user_data Data to be passed to \a notify_func.
309 s_object_weak_ref (OBJECT
*object
,
310 void (*notify_func
)(void *, void *),
313 g_return_if_fail (object
!= NULL
);
314 object
->weak_refs
= s_weakref_add (object
->weak_refs
, notify_func
, user_data
);
317 /*! \brief Remove a weak reference watcher from an OBJECT.
318 * \par Function Description
319 * Removes the weak reference callback \a notify_func from \a object.
321 * \sa s_object_weak_ref()
323 * \param [in,out] object Object to weak-reference.
324 * \param [in] notify_func Notify function to search for.
325 * \param [in] user_data Data to to search for.
328 s_object_weak_unref (OBJECT
*object
,
329 void (*notify_func
)(void *, void *),
332 g_return_if_fail (object
!= NULL
);
333 object
->weak_refs
= s_weakref_remove (object
->weak_refs
,
334 notify_func
, user_data
);
337 /*! \brief Add a weak pointer to an OBJECT.
338 * \par Function Description
339 * Adds the weak pointer at \a weak_pointer_loc to \a object. The
340 * value of \a weak_pointer_loc will be set to NULL when \a object is
343 * \sa s_object_remove_weak_ptr
345 * \param [in,out] object Object to weak-reference.
346 * \param [in] weak_pointer_loc Memory address of a pointer.
349 s_object_add_weak_ptr (OBJECT
*object
,
350 void *weak_pointer_loc
)
352 g_return_if_fail (object
!= NULL
);
353 object
->weak_refs
= s_weakref_add_ptr (object
->weak_refs
, weak_pointer_loc
);
356 /*! \brief Remove a weak pointer from an OBJECT.
357 * \par Function Description
358 * Removes the weak pointer at \a weak_pointer_loc from \a object.
360 * \sa s_object_add_weak_ptr()
362 * \param [in,out] object Object to weak-reference.
363 * \param [in] weak_pointer_loc Memory address of a pointer.
366 s_object_remove_weak_ptr (OBJECT
*object
,
367 void *weak_pointer_loc
)
369 g_return_if_fail (object
!= NULL
);
370 object
->weak_refs
= s_weakref_remove_ptr (object
->weak_refs
,
374 /*! \brief Gets the first line of the string
376 * This function modifies the string in place, so statically allocated strings
377 * cannot be passed to this function.
379 * \param [in,out] string the input string, NUL terminated
380 * \return the first line of the string with no ending newline
382 char *remove_nl(char *string
)
386 g_return_val_if_fail (string
!= NULL
, NULL
);
389 while(string
[i
] != '\0' && string
[i
] != '\n' && string
[i
] != '\r') {
398 /*! \brief Remove the ending newline
400 * This function removes the ending newline from the string. If no newline
401 * exists at the end of the string, this function returns the passed in
404 * This function modifies the string in place, so statically allocated strings
405 * cannot be passed to this function.
407 * \param [in,out] string the input string
408 * \return the string with no ending newline
410 char *remove_last_nl(char *string
)
414 g_return_val_if_fail (string
!= NULL
, NULL
);
416 len
= strlen(string
);
417 if (len
!= 0 && (string
[len
-1] == '\n' || string
[len
-1] == '\r'))
418 string
[len
-1] = '\0';
423 /*! \brief Expand environment variables in string.
424 * \par Function Description
425 * This function returns the passed string with environment variables
428 * The invocations of environment variable MUST be in the form
429 * '${variable_name}', '$variable_name' is not valid here. Environment
430 * variable names consists solely of letters, digits and '_'. It is
431 * possible to escape a '$' character in the string by repeating it
434 * It outputs error messages to console and leaves the malformed and
435 * bad variable names in the returned string.
437 * \param [in] string The string with variables to expand.
438 * \return A newly-allocated string with variables expanded or NULL
439 * if input string was NULL.
442 s_expand_env_variables (const gchar
*string
)
447 if (string
== NULL
) {
451 gstring
= g_string_sized_new (strlen (string
));
457 /* look for end of string or possible variable name start */
458 while (string
[i
] != '\0' && string
[i
] != '$') i
++;
459 g_string_append_len (gstring
, string
+ start
, i
- start
);
460 if (string
[i
] == '\0') {
461 /* end of string, return built string */
462 return g_string_free (gstring
, FALSE
);
468 /* look for the end of the variable name */
470 while (string
[i
] != '\0' && string
[i
] != '}') i
++;
471 if (string
[i
] == '\0') {
472 /* problem: no closing '}' to variable */
474 "Found malformed environment variable in '%s'\n",
476 g_string_append (gstring
, "$");
477 g_string_append_len (gstring
, string
+ start
, i
- start
+ 1);
483 /* test characters of variable name */
485 j
< i
&& (g_ascii_isalnum (string
[j
]) || string
[j
] == '_');
488 /* illegal character detected in variable name */
490 "Found bad character [%c] in variable name.\n",
492 g_string_append (gstring
, "${");
493 g_string_append_len (gstring
, string
+ start
, i
- start
+ 1);
495 /* extract variable name from string and expand it */
496 gchar
*variable_name
= g_strndup (string
+ start
, i
- start
);
497 const gchar
*env
= g_getenv (variable_name
);
498 g_free (variable_name
);
499 g_string_append (gstring
, (env
== NULL
) ? "" : env
);
507 g_string_append_c (gstring
, string
[i
++]);
511 /* an isolated '$', put it in output */
512 g_string_append_c (gstring
, '$');
521 /* -------------------------------------------------- */
525 /* Get a module handle for the libgeda DLL.
527 * Adapted from GLib, originally licensed under LGPLv2+. */
529 libgeda_module_handle ()
531 typedef BOOL (WINAPI
*t_GetModuleHandleExA
) (DWORD
, LPCTSTR
, HMODULE
*);
532 static t_GetModuleHandleExA p_GetModuleHandleExA
= NULL
;
533 static gconstpointer address
= (void (*)(void)) &libgeda_module_handle
;
534 static HMODULE hmodule
= NULL
;
536 if (hmodule
!= NULL
) return (gpointer
) hmodule
;
538 if (p_GetModuleHandleExA
== NULL
) {
539 p_GetModuleHandleExA
=
540 (t_GetModuleHandleExA
) GetProcAddress (GetModuleHandle ("kernel32.dll"),
541 "GetModuleHandleExA");
544 if (p_GetModuleHandleExA
== NULL
||
545 !(*p_GetModuleHandleExA
) (GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT
|
546 GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS
,
547 address
, &hmodule
)) {
548 MEMORY_BASIC_INFORMATION mbi
;
549 VirtualQuery (address
, &mbi
, sizeof (mbi
));
550 hmodule
= (HMODULE
) mbi
.AllocationBase
;
553 return (gpointer
) hmodule
;
556 #endif /* G_OS_WIN32 */
558 /*! \brief Get the directory with the gEDA system data.
559 * \par Function description
560 * Returns the path to be searched for gEDA data shared between all
561 * users. If the GEDADATA environment variable is set, returns its
562 * value; otherwise, uses a compiled-in path.
564 * On Windows, the compiled in path is *not* used, as it might not
565 * match the path where the user has installed gEDA.
567 * \warning The returned string is owned by libgeda and should not be
568 * modified or free'd.
570 * \todo On UNIX platforms we should follow the XDG Base Directory
573 * \return the gEDA shared data path, or NULL if none could be found.
575 const char *s_path_sys_data () {
576 static const char *p
= NULL
;
577 /* If GEDADATA is set in the environment, use that path */
579 p
= g_getenv ("GEDADATA");
582 # if defined (G_OS_WIN32)
583 /* On Windows, guess the path from the location of the libgeda
586 g_win32_get_package_installation_directory_of_module (libgeda_module_handle ());
587 p
= g_build_filename (d
, "share", "gEDA", NULL
);
590 /* On other platforms, use the compiled-in path */
597 /*! \brief Get the directory with the gEDA system configuration.
598 * \par Function description
599 * Returns the path to be searched for gEDA configuration shared
600 * between all users. If the GEDADATARC environment variable is set,
601 * returns its value; otherwise, uses a compiled-in path. Finally
602 * fallback to using the system data path.
604 * \warning The returned string is owned by libgeda and should not be
605 * modified or free'd.
607 * \todo On UNIX platforms we should follow the XDG Base Directory
610 * \return the gEDA shared config path, or NULL if none could be
613 const char *s_path_sys_config () {
614 static const char *p
= NULL
;
616 /* If GEDADATARC is set in the environment, use that path */
618 p
= g_getenv ("GEDADATARC");
621 #if defined (GEDARCDIR) && !defined(_WIN32)
622 /* If available, use the rc directory set during configure. */
625 /* Otherwise, just use the data directory */
626 p
= s_path_sys_data ();
632 /*! \brief Get the directory with the gEDA user configuration.
633 * \par Function description
634 * Returns the path to be searched for the current user's gEDA
635 * configuration. Currently defaults to a directory ".gEDA" in the
636 * user's home directory.
638 * \warning The returned string is owned by libgeda and should not be
639 * modified or free'd.
641 * \todo On Windows, we should use APPDATA.
643 * \todo On UNIX platforms we should follow the XDG Base Directory
646 const char *s_path_user_config () {
647 static const char *p
= NULL
;
650 const char *home
= g_getenv ("HOME");
651 if (home
== NULL
) home
= g_get_home_dir ();
652 p
= g_build_filename(home
, ".gEDA", NULL
);