Bump gEDA version
[geda-gaf.git] / libgeda / src / s_basic.c
blob23d84c1e34d3f1a553670c593ec2326de3c0491a
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
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 G_OS_WIN32
34 # ifndef STRICT
35 # define STRICT
36 # include <windows.h>
37 # undef STRICT
38 # endif
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
42 # endif
43 #endif
45 /*! this is modified here and in o_list.c */
46 int global_sid=0;
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)
59 /* setup sid */
60 new_node->sid = global_sid++;
61 new_node->type = type;
63 /* Setup the name */
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 */
70 new_node->w_top = 0;
71 new_node->w_left = 0;
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;
80 new_node->arc = NULL;
81 new_node->box = 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;
91 /* Setup the color */
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;
122 return(new_node);
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!!!
142 * \brief
143 * \par Function Description
146 void print_struct_forw (GList *list)
148 OBJECT *o_current=NULL;
149 GList *iter;
151 iter = list;
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);
165 printf("----\n");
166 iter = g_list_next (iter);
170 /*! \todo Finish function documentation!!!
171 * \brief
172 * \par Function Description
175 void
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!!!
268 * \brief
269 * \par Function Description
272 /* deletes everything include the GList */
273 void
274 s_delete_object_glist(TOPLEVEL *toplevel, GList *list)
276 OBJECT *o_current=NULL;
277 GList *ptr;
279 ptr = g_list_last(list);
281 /* do the delete backwards */
282 while(ptr != NULL) {
283 o_current = (OBJECT *) ptr->data;
284 s_delete_object(toplevel, o_current);
285 ptr = g_list_previous (ptr);
287 g_list_free(list);
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.
302 void
303 s_object_weak_ref (OBJECT *object,
304 void (*notify_func)(void *, void *),
305 void *user_data)
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.
321 void
322 s_object_weak_unref (OBJECT *object,
323 void (*notify_func)(void *, void *),
324 void *user_data)
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
335 * destroyed.
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.
342 void
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.
359 void
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,
365 weak_pointer_loc);
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)
378 int i;
380 g_return_val_if_fail (string != NULL, NULL);
382 i = 0;
383 while(string[i] != '\0' && string[i] != '\n' && string[i] != '\r') {
384 i++;
387 string[i] = '\0';
389 return(string);
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
396 * string.
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)
406 int len;
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';
414 return(string);
417 /*! \brief Expand environment variables in string.
418 * \par Function Description
419 * This function returns the passed string with environment variables
420 * expanded.
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
426 * twice.
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.
435 gchar*
436 s_expand_env_variables (const gchar *string)
438 GString *gstring;
439 gint i;
441 if (string == NULL) {
442 return NULL;
445 gstring = g_string_sized_new (strlen (string));
446 i = 0;
447 while (TRUE) {
448 gint start;
450 start = i;
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);
459 i++;
460 switch (string[i]) {
461 case ('{'):
462 /* look for the end of the variable name */
463 start = i;
464 while (string[i] != '\0' && string[i] != '}') i++;
465 if (string[i] == '\0') {
466 /* problem: no closing '}' to variable */
467 fprintf (stderr,
468 "Found malformed environment variable in '%s'\n",
469 string);
470 g_string_append (gstring, "$");
471 g_string_append_len (gstring, string + start, i - start + 1);
472 } else {
473 gint j;
475 /* discard "${" */
476 start = start + 1;
477 /* test characters of variable name */
478 for (j = start;
479 j < i && (g_ascii_isalnum (string[j]) || string[j] == '_');
480 j++);
481 if (i != j) {
482 /* illegal character detected in variable name */
483 fprintf (stderr,
484 "Found bad character [%c] in variable name.\n",
485 string[j]);
486 g_string_append (gstring, "${");
487 g_string_append_len (gstring, string + start, i - start + 1);
488 } else {
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);
495 i++;
497 break;
499 case ('$'):
500 /* an escaped '$' */
501 g_string_append_c (gstring, string[i++]);
502 break;
504 default:
505 /* an isolated '$', put it in output */
506 g_string_append_c (gstring, '$');
510 /* never reached */
511 return NULL;
515 /* -------------------------------------------------- */
517 #ifdef G_OS_WIN32
519 /* Get a module handle for the libgeda DLL.
521 * Adapted from GLib, originally licensed under LGPLv2+. */
522 static gpointer
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
565 * Specification.
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 */
572 if (p == NULL) {
573 p = g_getenv ("GEDADATA");
575 if (p == NULL) {
576 # if defined (G_OS_WIN32)
577 /* On Windows, guess the path from the location of the libgeda
578 * DLL. */
579 gchar *d =
580 g_win32_get_package_installation_directory_of_module (libgeda_module_handle ());
581 p = g_build_filename (d, "share", "gEDA", NULL);
582 g_free (d);
583 # else
584 /* On other platforms, use the compiled-in path */
585 p = GEDADATADIR;
586 # endif
588 return p;
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
602 * Specification.
604 * \return the gEDA shared config path, or NULL if none could be
605 * found.
607 const char *s_path_sys_config () {
608 static const char *p = NULL;
610 /* If GEDADATARC is set in the environment, use that path */
611 if (p == NULL) {
612 p = g_getenv ("GEDADATARC");
614 if (p == NULL) {
615 #if defined (GEDARCDIR) && !defined(_WIN32)
616 /* If available, use the rc directory set during configure. */
617 p = GEDARCDIR;
618 #else
619 /* Otherwise, just use the data directory */
620 p = s_path_sys_data ();
621 #endif
623 return p;
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
638 * Specification.
640 const char *s_path_user_config () {
641 static const char *p = NULL;
643 if (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);
648 return p;