missing NULL terminator in set_config_x
[geda-gaf.git] / libgeda / src / s_basic.c
blob1d216b5b92dd8eb3c11b7360cb8aa11a93a735db
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_embedded = FALSE;
89 new_node->complex_basename = NULL;
90 new_node->parent = NULL;
92 /* Setup the color */
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;
128 return(new_node);
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!!!
148 * \brief
149 * \par Function Description
152 void print_struct_forw (GList *list)
154 OBJECT *o_current=NULL;
155 GList *iter;
157 iter = list;
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);
171 printf("----\n");
172 iter = g_list_next (iter);
176 /*! \todo Finish function documentation!!!
177 * \brief
178 * \par Function Description
181 void
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!!!
274 * \brief
275 * \par Function Description
278 /* deletes everything include the GList */
279 void
280 s_delete_object_glist(TOPLEVEL *toplevel, GList *list)
282 OBJECT *o_current=NULL;
283 GList *ptr;
285 ptr = g_list_last(list);
287 /* do the delete backwards */
288 while(ptr != NULL) {
289 o_current = (OBJECT *) ptr->data;
290 s_delete_object(toplevel, o_current);
291 ptr = g_list_previous (ptr);
293 g_list_free(list);
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.
308 void
309 s_object_weak_ref (OBJECT *object,
310 void (*notify_func)(void *, void *),
311 void *user_data)
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.
327 void
328 s_object_weak_unref (OBJECT *object,
329 void (*notify_func)(void *, void *),
330 void *user_data)
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
341 * destroyed.
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.
348 void
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.
365 void
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,
371 weak_pointer_loc);
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)
384 int i;
386 g_return_val_if_fail (string != NULL, NULL);
388 i = 0;
389 while(string[i] != '\0' && string[i] != '\n' && string[i] != '\r') {
390 i++;
393 string[i] = '\0';
395 return(string);
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
402 * string.
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)
412 int len;
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';
420 return(string);
423 /*! \brief Expand environment variables in string.
424 * \par Function Description
425 * This function returns the passed string with environment variables
426 * expanded.
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
432 * twice.
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.
441 gchar*
442 s_expand_env_variables (const gchar *string)
444 GString *gstring;
445 gint i;
447 if (string == NULL) {
448 return NULL;
451 gstring = g_string_sized_new (strlen (string));
452 i = 0;
453 while (TRUE) {
454 gint start;
456 start = i;
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);
465 i++;
466 switch (string[i]) {
467 case ('{'):
468 /* look for the end of the variable name */
469 start = i;
470 while (string[i] != '\0' && string[i] != '}') i++;
471 if (string[i] == '\0') {
472 /* problem: no closing '}' to variable */
473 fprintf (stderr,
474 "Found malformed environment variable in '%s'\n",
475 string);
476 g_string_append (gstring, "$");
477 g_string_append_len (gstring, string + start, i - start + 1);
478 } else {
479 gint j;
481 /* discard "${" */
482 start = start + 1;
483 /* test characters of variable name */
484 for (j = start;
485 j < i && (g_ascii_isalnum (string[j]) || string[j] == '_');
486 j++);
487 if (i != j) {
488 /* illegal character detected in variable name */
489 fprintf (stderr,
490 "Found bad character [%c] in variable name.\n",
491 string[j]);
492 g_string_append (gstring, "${");
493 g_string_append_len (gstring, string + start, i - start + 1);
494 } else {
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);
501 i++;
503 break;
505 case ('$'):
506 /* an escaped '$' */
507 g_string_append_c (gstring, string[i++]);
508 break;
510 default:
511 /* an isolated '$', put it in output */
512 g_string_append_c (gstring, '$');
516 /* never reached */
517 return NULL;
521 /* -------------------------------------------------- */
523 #ifdef G_OS_WIN32
525 /* Get a module handle for the libgeda DLL.
527 * Adapted from GLib, originally licensed under LGPLv2+. */
528 static gpointer
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
571 * Specification.
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 */
578 if (p == NULL) {
579 p = g_getenv ("GEDADATA");
581 if (p == NULL) {
582 # if defined (G_OS_WIN32)
583 /* On Windows, guess the path from the location of the libgeda
584 * DLL. */
585 gchar *d =
586 g_win32_get_package_installation_directory_of_module (libgeda_module_handle ());
587 p = g_build_filename (d, "share", "gEDA", NULL);
588 g_free (d);
589 # else
590 /* On other platforms, use the compiled-in path */
591 p = GEDADATADIR;
592 # endif
594 return p;
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
608 * Specification.
610 * \return the gEDA shared config path, or NULL if none could be
611 * found.
613 const char *s_path_sys_config () {
614 static const char *p = NULL;
616 /* If GEDADATARC is set in the environment, use that path */
617 if (p == NULL) {
618 p = g_getenv ("GEDADATARC");
620 if (p == NULL) {
621 #if defined (GEDARCDIR) && !defined(_WIN32)
622 /* If available, use the rc directory set during configure. */
623 p = GEDARCDIR;
624 #else
625 /* Otherwise, just use the data directory */
626 p = s_path_sys_data ();
627 #endif
629 return p;
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
644 * Specification.
646 const char *s_path_user_config () {
647 static const char *p = NULL;
649 if (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);
654 return p;