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_basename
= NULL
;
89 new_node
->parent
= NULL
;
92 new_node
->color
= DEFAULT_COLOR
;
93 new_node
->dont_redraw
= FALSE
;
94 new_node
->selectable
= TRUE
;
95 new_node
->selected
= FALSE
;
96 new_node
->locked_color
= -1;
98 new_node
->bus_ripper_direction
= 0;
100 new_node
->line_end
= END_NONE
;
101 new_node
->line_type
= TYPE_SOLID
;
102 new_node
->line_width
= 0;
103 new_node
->line_space
= 0;
104 new_node
->line_length
= 0;
105 new_node
->fill_width
= 0;
106 new_node
->fill_angle1
= 0;
107 new_node
->fill_angle2
= 0;
108 new_node
->fill_pitch1
= 0;
109 new_node
->fill_pitch2
= 0;
111 new_node
->attribs
= NULL
;
112 new_node
->attached_to
= NULL
;
113 new_node
->copied_to
= NULL
;
114 new_node
->show_name_value
= SHOW_NAME_VALUE
;
115 new_node
->visibility
= VISIBLE
;
117 new_node
->pin_type
= PIN_TYPE_NET
;
118 new_node
->whichend
= -1;
120 new_node
->weak_refs
= NULL
;
126 /*! \brief Helper to allocate and initialise an object.
128 * \par Function Description
129 * Allocates memory for an OBJECT and then calls s_basic_init_object() on it.
131 * \param [in] type The sub-type of the object to create; one of the OBJ_* constants.
132 * \param [in] prefix The name prefix for the session-unique object name.
133 * \return A pointer to the fully constructed OBJECT.
135 OBJECT
*s_basic_new_object(int type
, char const *prefix
)
137 return s_basic_init_object(g_malloc(sizeof (OBJECT
)), type
, prefix
);
141 /*! \todo Finish function documentation!!!
143 * \par Function Description
146 void print_struct_forw (GList
*list
)
148 OBJECT
*o_current
=NULL
;
152 printf("TRYING to PRINT\n");
153 while (iter
!= NULL
) {
154 o_current
= (OBJECT
*)iter
->data
;
155 printf("Name: %s\n", o_current
->name
);
156 printf("Type: %d\n", o_current
->type
);
157 printf("Sid: %d\n", o_current
->sid
);
159 if (o_current
->type
== OBJ_COMPLEX
|| o_current
->type
== OBJ_PLACEHOLDER
) {
160 print_struct_forw(o_current
->complex->prim_objs
);
163 o_attrib_print (o_current
->attribs
);
166 iter
= g_list_next (iter
);
170 /*! \todo Finish function documentation!!!
172 * \par Function Description
176 s_delete_object(TOPLEVEL
*toplevel
, OBJECT
*o_current
)
178 if (o_current
!= NULL
) {
179 /* If currently attached to a page, remove it from the page */
180 if (o_current
->page
!= NULL
) {
181 s_page_remove (toplevel
, o_current
->page
, o_current
);
184 s_conn_remove_object_connections (toplevel
, o_current
);
186 if (o_current
->attached_to
!= NULL
) {
187 /* do the actual remove */
188 o_attrib_remove(toplevel
, &o_current
->attached_to
->attribs
, o_current
);
191 if (o_current
->line
) {
192 /* printf("sdeleting line\n");*/
193 g_free(o_current
->line
);
195 o_current
->line
= NULL
;
197 if (o_current
->path
) {
198 g_free(o_current
->path
);
200 o_current
->path
= NULL
;
202 /* printf("sdeleting circle\n");*/
203 g_free(o_current
->circle
);
204 o_current
->circle
= NULL
;
206 /* printf("sdeleting arc\n");*/
207 g_free(o_current
->arc
);
208 o_current
->arc
= NULL
;
210 /* printf("sdeleting box\n");*/
211 g_free(o_current
->box
);
212 o_current
->box
= NULL
;
214 if (o_current
->picture
) {
215 /* printf("sdeleting picture\n");*/
217 g_free(o_current
->picture
->file_content
);
218 if (o_current
->picture
->pixbuf
)
219 g_object_unref (o_current
->picture
->pixbuf
);
221 g_free(o_current
->picture
->filename
);
222 g_free(o_current
->picture
);
224 o_current
->picture
= NULL
;
226 if (o_current
->text
) {
227 /*printf("sdeleting text->string\n");*/
228 g_free(o_current
->text
->string
);
229 o_current
->text
->string
= NULL
;
230 g_free(o_current
->text
->disp_string
);
231 /* printf("sdeleting text\n");*/
232 g_free(o_current
->text
);
234 o_current
->text
= NULL
;
236 /* printf("sdeleting name\n");*/
237 g_free(o_current
->name
);
238 o_current
->name
= NULL
;
241 /* printf("sdeleting complex_basename\n");*/
242 g_free(o_current
->complex_basename
);
243 o_current
->complex_basename
= NULL
;
245 if (o_current
->complex) {
247 if (o_current
->complex->prim_objs
) {
248 /* printf("sdeleting complex->primitive_objects\n");*/
249 s_delete_object_glist (toplevel
, o_current
->complex->prim_objs
);
250 o_current
->complex->prim_objs
= NULL
;
253 g_free(o_current
->complex);
254 o_current
->complex = NULL
;
257 o_attrib_detach_all (toplevel
, o_current
);
259 s_weakref_notify (o_current
, o_current
->weak_refs
);
261 g_free(o_current
); /* assuming it is not null */
263 o_current
=NULL
; /* misc clean up */
267 /*! \todo Finish function documentation!!!
269 * \par Function Description
272 /* deletes everything include the GList */
274 s_delete_object_glist(TOPLEVEL
*toplevel
, GList
*list
)
276 OBJECT
*o_current
=NULL
;
279 ptr
= g_list_last(list
);
281 /* do the delete backwards */
283 o_current
= (OBJECT
*) ptr
->data
;
284 s_delete_object(toplevel
, o_current
);
285 ptr
= g_list_previous (ptr
);
290 /*! \brief Add a weak reference watcher to an OBJECT.
291 * \par Function Description
292 * Adds the weak reference callback \a notify_func to \a object. When
293 * \a object is destroyed, \a notify_func will be called with two
294 * arguments: the \a object, and the \a user_data.
296 * \sa s_object_weak_unref
298 * \param [in,out] object Object to weak-reference.
299 * \param [in] notify_func Weak reference notify function.
300 * \param [in] user_data Data to be passed to \a notify_func.
303 s_object_weak_ref (OBJECT
*object
,
304 void (*notify_func
)(void *, void *),
307 g_return_if_fail (object
!= NULL
);
308 object
->weak_refs
= s_weakref_add (object
->weak_refs
, notify_func
, user_data
);
311 /*! \brief Remove a weak reference watcher from an OBJECT.
312 * \par Function Description
313 * Removes the weak reference callback \a notify_func from \a object.
315 * \sa s_object_weak_ref()
317 * \param [in,out] object Object to weak-reference.
318 * \param [in] notify_func Notify function to search for.
319 * \param [in] user_data Data to to search for.
322 s_object_weak_unref (OBJECT
*object
,
323 void (*notify_func
)(void *, void *),
326 g_return_if_fail (object
!= NULL
);
327 object
->weak_refs
= s_weakref_remove (object
->weak_refs
,
328 notify_func
, user_data
);
331 /*! \brief Add a weak pointer to an OBJECT.
332 * \par Function Description
333 * Adds the weak pointer at \a weak_pointer_loc to \a object. The
334 * value of \a weak_pointer_loc will be set to NULL when \a object is
337 * \sa s_object_remove_weak_ptr
339 * \param [in,out] object Object to weak-reference.
340 * \param [in] weak_pointer_loc Memory address of a pointer.
343 s_object_add_weak_ptr (OBJECT
*object
,
344 void *weak_pointer_loc
)
346 g_return_if_fail (object
!= NULL
);
347 object
->weak_refs
= s_weakref_add_ptr (object
->weak_refs
, weak_pointer_loc
);
350 /*! \brief Remove a weak pointer from an OBJECT.
351 * \par Function Description
352 * Removes the weak pointer at \a weak_pointer_loc from \a object.
354 * \sa s_object_add_weak_ptr()
356 * \param [in,out] object Object to weak-reference.
357 * \param [in] weak_pointer_loc Memory address of a pointer.
360 s_object_remove_weak_ptr (OBJECT
*object
,
361 void *weak_pointer_loc
)
363 g_return_if_fail (object
!= NULL
);
364 object
->weak_refs
= s_weakref_remove_ptr (object
->weak_refs
,
368 /*! \brief Gets the first line of the string
370 * This function modifies the string in place, so statically allocated strings
371 * cannot be passed to this function.
373 * \param [in,out] string the input string, NUL terminated
374 * \return the first line of the string with no ending newline
376 char *remove_nl(char *string
)
380 g_return_val_if_fail (string
!= NULL
, NULL
);
383 while(string
[i
] != '\0' && string
[i
] != '\n' && string
[i
] != '\r') {
392 /*! \brief Remove the ending newline
394 * This function removes the ending newline from the string. If no newline
395 * exists at the end of the string, this function returns the passed in
398 * This function modifies the string in place, so statically allocated strings
399 * cannot be passed to this function.
401 * \param [in,out] string the input string
402 * \return the string with no ending newline
404 char *remove_last_nl(char *string
)
408 g_return_val_if_fail (string
!= NULL
, NULL
);
410 len
= strlen(string
);
411 if (len
!= 0 && (string
[len
-1] == '\n' || string
[len
-1] == '\r'))
412 string
[len
-1] = '\0';
417 /*! \brief Expand environment variables in string.
418 * \par Function Description
419 * This function returns the passed string with environment variables
422 * The invocations of environment variable MUST be in the form
423 * '${variable_name}', '$variable_name' is not valid here. Environment
424 * variable names consists solely of letters, digits and '_'. It is
425 * possible to escape a '$' character in the string by repeating it
428 * It outputs error messages to console and leaves the malformed and
429 * bad variable names in the returned string.
431 * \param [in] string The string with variables to expand.
432 * \return A newly-allocated string with variables expanded or NULL
433 * if input string was NULL.
436 s_expand_env_variables (const gchar
*string
)
441 if (string
== NULL
) {
445 gstring
= g_string_sized_new (strlen (string
));
451 /* look for end of string or possible variable name start */
452 while (string
[i
] != '\0' && string
[i
] != '$') i
++;
453 g_string_append_len (gstring
, string
+ start
, i
- start
);
454 if (string
[i
] == '\0') {
455 /* end of string, return built string */
456 return g_string_free (gstring
, FALSE
);
462 /* look for the end of the variable name */
464 while (string
[i
] != '\0' && string
[i
] != '}') i
++;
465 if (string
[i
] == '\0') {
466 /* problem: no closing '}' to variable */
468 "Found malformed environment variable in '%s'\n",
470 g_string_append (gstring
, "$");
471 g_string_append_len (gstring
, string
+ start
, i
- start
+ 1);
477 /* test characters of variable name */
479 j
< i
&& (g_ascii_isalnum (string
[j
]) || string
[j
] == '_');
482 /* illegal character detected in variable name */
484 "Found bad character [%c] in variable name.\n",
486 g_string_append (gstring
, "${");
487 g_string_append_len (gstring
, string
+ start
, i
- start
+ 1);
489 /* extract variable name from string and expand it */
490 gchar
*variable_name
= g_strndup (string
+ start
, i
- start
);
491 const gchar
*env
= g_getenv (variable_name
);
492 g_free (variable_name
);
493 g_string_append (gstring
, (env
== NULL
) ? "" : env
);
501 g_string_append_c (gstring
, string
[i
++]);
505 /* an isolated '$', put it in output */
506 g_string_append_c (gstring
, '$');
515 /* -------------------------------------------------- */
519 /* Get a module handle for the libgeda DLL.
521 * Adapted from GLib, originally licensed under LGPLv2+. */
523 libgeda_module_handle ()
525 typedef BOOL (WINAPI
*t_GetModuleHandleExA
) (DWORD
, LPCTSTR
, HMODULE
*);
526 static t_GetModuleHandleExA p_GetModuleHandleExA
= NULL
;
527 static gconstpointer address
= (void (*)(void)) &libgeda_module_handle
;
528 static HMODULE hmodule
= NULL
;
530 if (hmodule
!= NULL
) return (gpointer
) hmodule
;
532 if (p_GetModuleHandleExA
== NULL
) {
533 p_GetModuleHandleExA
=
534 (t_GetModuleHandleExA
) GetProcAddress (GetModuleHandle ("kernel32.dll"),
535 "GetModuleHandleExA");
538 if (p_GetModuleHandleExA
== NULL
||
539 !(*p_GetModuleHandleExA
) (GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT
|
540 GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS
,
541 address
, &hmodule
)) {
542 MEMORY_BASIC_INFORMATION mbi
;
543 VirtualQuery (address
, &mbi
, sizeof (mbi
));
544 hmodule
= (HMODULE
) mbi
.AllocationBase
;
547 return (gpointer
) hmodule
;
550 #endif /* G_OS_WIN32 */
552 /*! \brief Get the directory with the gEDA system data.
553 * \par Function description
554 * Returns the path to be searched for gEDA data shared between all
555 * users. If the GEDADATA environment variable is set, returns its
556 * value; otherwise, uses a compiled-in path.
558 * On Windows, the compiled in path is *not* used, as it might not
559 * match the path where the user has installed gEDA.
561 * \warning The returned string is owned by libgeda and should not be
562 * modified or free'd.
564 * \todo On UNIX platforms we should follow the XDG Base Directory
567 * \return the gEDA shared data path, or NULL if none could be found.
569 const char *s_path_sys_data () {
570 static const char *p
= NULL
;
571 /* If GEDADATA is set in the environment, use that path */
573 p
= g_getenv ("GEDADATA");
576 # if defined (G_OS_WIN32)
577 /* On Windows, guess the path from the location of the libgeda
580 g_win32_get_package_installation_directory_of_module (libgeda_module_handle ());
581 p
= g_build_filename (d
, "share", "gEDA", NULL
);
584 /* On other platforms, use the compiled-in path */
591 /*! \brief Get the directory with the gEDA system configuration.
592 * \par Function description
593 * Returns the path to be searched for gEDA configuration shared
594 * between all users. If the GEDADATARC environment variable is set,
595 * returns its value; otherwise, uses a compiled-in path. Finally
596 * fallback to using the system data path.
598 * \warning The returned string is owned by libgeda and should not be
599 * modified or free'd.
601 * \todo On UNIX platforms we should follow the XDG Base Directory
604 * \return the gEDA shared config path, or NULL if none could be
607 const char *s_path_sys_config () {
608 static const char *p
= NULL
;
610 /* If GEDADATARC is set in the environment, use that path */
612 p
= g_getenv ("GEDADATARC");
615 #if defined (GEDARCDIR) && !defined(_WIN32)
616 /* If available, use the rc directory set during configure. */
619 /* Otherwise, just use the data directory */
620 p
= s_path_sys_data ();
626 /*! \brief Get the directory with the gEDA user configuration.
627 * \par Function description
628 * Returns the path to be searched for the current user's gEDA
629 * configuration. Currently defaults to a directory ".gEDA" in the
630 * user's home directory.
632 * \warning The returned string is owned by libgeda and should not be
633 * modified or free'd.
635 * \todo On Windows, we should use APPDATA.
637 * \todo On UNIX platforms we should follow the XDG Base Directory
640 const char *s_path_user_config () {
641 static const char *p
= NULL
;
644 const char *home
= g_getenv ("HOME");
645 if (home
== NULL
) home
= g_get_home_dir ();
646 p
= g_build_filename(home
, ".gEDA", NULL
);