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)
5  *
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.
10  *
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.
15  *
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
19  */
20 #include <config.h>
21 
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
30 
31 #include "libgeda_priv.h"
32 
33 #ifdef HAVE_LIBDMALLOC
34 #include <dmalloc.h>
35 #endif
36 
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
46 
47 /*! this is modified here and in o_list.c */
48 int global_sid=0;
49 
50 /*! \brief Initialize an already-allocated object.
51  *  \par Function Description
52  *  Initializes the members of the OBJECT structure.
53  *
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.
58  */
s_basic_init_object(OBJECT * new_node,int type,char const * name)59 OBJECT *s_basic_init_object(OBJECT *new_node, int type, char const *name)
60 {
61   /* setup sid */
62   new_node->sid = global_sid++;
63   new_node->type = type;
64 
65   /* Setup the name */
66   new_node->name = g_strdup_printf("%s.%d", name, new_node->sid);
67 
68   /* Don't associate with a page, initially */
69   new_node->page = NULL;
70 
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;
77 
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;
87 
88   new_node->tiles = NULL;
89 
90   new_node->conn_list = NULL;
91 
92   new_node->complex_basename = NULL;
93   new_node->parent = NULL;
94 
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;
101 
102   new_node->bus_ripper_direction = 0;
103 
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;
114 
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;
120 
121   new_node->pin_type = PIN_TYPE_NET;
122   new_node->whichend = -1;
123 
124   new_node->net_num_connected = 0;
125   new_node->valid_num_connected = FALSE;
126 
127   new_node->weak_refs = NULL;
128 
129   new_node->attrib_notify_freeze_count = 0;
130   new_node->attrib_notify_pending = 0;
131 
132   new_node->conn_notify_freeze_count = 0;
133   new_node->conn_notify_pending = 0;
134 
135   return(new_node);
136 }
137 
138 
139 /*! \brief Helper to allocate and initialise an object.
140  *
141  *  \par Function Description
142  *  Allocates memory for an OBJECT and then calls s_basic_init_object() on it.
143  *
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.
147  */
s_basic_new_object(int type,char const * prefix)148 OBJECT *s_basic_new_object(int type, char const *prefix)
149 {
150   return s_basic_init_object(g_malloc(sizeof (OBJECT)), type, prefix);
151 }
152 
153 
154 /*! \todo Finish function documentation!!!
155  *  \brief
156  *  \par Function Description
157  *
158  */
print_struct_forw(GList * list)159 void print_struct_forw (GList *list)
160 {
161   OBJECT *o_current=NULL;
162   GList *iter;
163 
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);
171 
172     if (o_current->type == OBJ_COMPLEX || o_current->type == OBJ_PLACEHOLDER) {
173       print_struct_forw(o_current->complex->prim_objs);
174     }
175 
176     o_attrib_print (o_current->attribs);
177 
178     printf("----\n");
179     iter = g_list_next (iter);
180   }
181 }
182 
183 /*! \todo Finish function documentation!!!
184  *  \brief
185  *  \par Function Description
186  *
187  */
print_struct(OBJECT * ptr)188 void print_struct(OBJECT *ptr)
189 {
190   OBJECT *o_current=NULL;
191 
192   o_current = ptr;
193 
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]);
203     }
204 
205     o_attrib_print (o_current->attribs);
206 
207     printf("----\n");
208   }
209 }
210 
211 /*! \todo Finish function documentation!!!
212  *  \brief
213  *  \par Function Description
214  *
215  */
216 void
s_delete_object(TOPLEVEL * toplevel,OBJECT * o_current)217 s_delete_object(TOPLEVEL *toplevel, OBJECT *o_current)
218 {
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);
223     }
224 
225     s_conn_remove_object (toplevel, o_current);
226 
227     if (o_current->attached_to != NULL) {
228       /* do the actual remove */
229       o_attrib_remove(toplevel, &o_current->attached_to->attribs, o_current);
230     }
231 
232     /* Don't bother with hooks for this dying object,
233      * leak the freeze count, so the object dies frozen.
234      */
235     o_attrib_freeze_hooks (toplevel, o_current);
236     o_attrib_detach_all (toplevel, o_current);
237 
238     if (o_current->line) {
239       /*	printf("sdeleting line\n");*/
240       g_free(o_current->line);
241     }
242     o_current->line = NULL;
243 
244     if (o_current->path) {
245       g_free(o_current->path);
246     }
247     o_current->path = NULL;
248 
249     /*	printf("sdeleting circle\n");*/
250     g_free(o_current->circle);
251     o_current->circle = NULL;
252 
253     /*	printf("sdeleting arc\n");*/
254     g_free(o_current->arc);
255     o_current->arc = NULL;
256 
257     /*	printf("sdeleting box\n");*/
258     g_free(o_current->box);
259     o_current->box = NULL;
260 
261     if (o_current->picture) {
262       /*	printf("sdeleting picture\n");*/
263 
264       g_free(o_current->picture->file_content);
265       if (o_current->picture->pixbuf)
266         g_object_unref (o_current->picture->pixbuf);
267 
268       g_free(o_current->picture->filename);
269       g_free(o_current->picture);
270     }
271     o_current->picture = NULL;
272 
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);
280     }
281     o_current->text = NULL;
282 
283     /*	printf("sdeleting name\n");*/
284     g_free(o_current->name);
285     o_current->name = NULL;
286 
287 
288     /*	printf("sdeleting complex_basename\n");*/
289     g_free(o_current->complex_basename);
290     o_current->complex_basename = NULL;
291 
292     if (o_current->complex) {
293 
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;
298       }
299 
300       g_free(o_current->complex);
301       o_current->complex = NULL;
302     }
303 
304     s_weakref_notify (o_current, o_current->weak_refs);
305 
306     g_free(o_current);	/* assuming it is not null */
307 
308     o_current=NULL;		/* misc clean up */
309   }
310 }
311 
312 /*! \todo Finish function documentation!!!
313  *  \brief
314  *  \par Function Description
315  *
316  */
317 /* deletes everything include the GList */
318 void
s_delete_object_glist(TOPLEVEL * toplevel,GList * list)319 s_delete_object_glist(TOPLEVEL *toplevel, GList *list)
320 {
321   OBJECT *o_current=NULL;
322   GList *ptr;
323 
324   ptr = g_list_last(list);
325 
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);
331   }
332   g_list_free(list);
333 }
334 
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.
340  *
341  * \sa s_object_weak_unref
342  *
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.
346  */
347 void
s_object_weak_ref(OBJECT * object,void (* notify_func)(void *,void *),void * user_data)348 s_object_weak_ref (OBJECT *object,
349                    void (*notify_func)(void *, void *),
350                    void *user_data)
351 {
352   g_return_if_fail (object != NULL);
353   object->weak_refs = s_weakref_add (object->weak_refs, notify_func, user_data);
354 }
355 
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.
359  *
360  * \sa s_object_weak_ref()
361  *
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.
365  */
366 void
s_object_weak_unref(OBJECT * object,void (* notify_func)(void *,void *),void * user_data)367 s_object_weak_unref (OBJECT *object,
368                      void (*notify_func)(void *, void *),
369                      void *user_data)
370 {
371   g_return_if_fail (object != NULL);
372   object->weak_refs = s_weakref_remove (object->weak_refs,
373                                         notify_func, user_data);
374 }
375 
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.
381  *
382  * \sa s_object_remove_weak_ptr
383  *
384  * \param [in,out] object        Object to weak-reference.
385  * \param [in] weak_pointer_loc  Memory address of a pointer.
386  */
387 void
s_object_add_weak_ptr(OBJECT * object,void * weak_pointer_loc)388 s_object_add_weak_ptr (OBJECT *object,
389                        void *weak_pointer_loc)
390 {
391   g_return_if_fail (object != NULL);
392   object->weak_refs = s_weakref_add_ptr (object->weak_refs, weak_pointer_loc);
393 }
394 
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.
398  *
399  * \sa s_object_add_weak_ptr()
400  *
401  * \param [in,out] object        Object to weak-reference.
402  * \param [in] weak_pointer_loc  Memory address of a pointer.
403  */
404 void
s_object_remove_weak_ptr(OBJECT * object,void * weak_pointer_loc)405 s_object_remove_weak_ptr (OBJECT *object,
406                           void *weak_pointer_loc)
407 {
408   g_return_if_fail (object != NULL);
409   object->weak_refs = s_weakref_remove_ptr (object->weak_refs,
410                                             weak_pointer_loc);
411 }
412 
413 /*! \todo Finish function documentation!!!
414  *  \brief
415  *  \par Function Description
416  *
417  */
418 /* used by o_text_read */
remove_nl(char * string)419 char *remove_nl(char *string)
420 {
421   int i;
422 
423   if (!string)
424     return NULL;
425 
426   i = 0;
427   while(string[i] != '\0' && string[i] != '\n' && string[i] != '\r') {
428     i++;
429   }
430 
431   string[i] = '\0';
432 
433   return(string);
434 }
435 
436 /*! \todo Finish function documentation!!!
437  *  \brief
438  *  \par Function Description
439  *
440  */
441 /* used by o_text_read */
remove_last_nl(char * string)442 char *remove_last_nl(char *string)
443 {
444   int len;
445 
446   if (!string)
447     return NULL;
448 
449   len = strlen(string);
450   if (string[len-1] == '\n' || string[len-1] == '\r')
451     string[len-1] = '\0';
452 
453   return(string);
454 }
455 
456 /*! \brief Expand environment variables in string.
457  *  \par Function Description
458  *  This function returns the passed string with environment variables
459  *  expanded.
460  *
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.
466  *
467  *  It outputs error messages to console and leaves the malformed and
468  *  bad variable names in the returned string.
469  *
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.
473  */
474 gchar*
s_expand_env_variables(const gchar * string)475 s_expand_env_variables (const gchar *string)
476 {
477   GString *gstring;
478   gint i;
479 
480   if (string == NULL) {
481     return NULL;
482   }
483 
484   gstring = g_string_sized_new (strlen (string));
485   i = 0;
486   while (TRUE) {
487     gint start;
488 
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);
496     }
497 
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;
513 
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);
533             }
534             i++;
535           }
536           break;
537 
538         case ('$'):
539           /* an escaped '$' */
540           g_string_append_c (gstring, string[i++]);
541           break;
542 
543         default:
544           /* an isolated '$', put it in output */
545           g_string_append_c (gstring, '$');
546     }
547   }
548 
549   /* never reached */
550   return NULL;
551 }
552 
553 
554 /* -------------------------------------------------- */
555 
556 #ifdef G_OS_WIN32
557 
558 /* Get a module handle for the libgeda DLL.
559  *
560  * Adapted from GLib, originally licensed under LGPLv2+. */
561 static gpointer
libgeda_module_handle()562 libgeda_module_handle ()
563 {
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;
568 
569   if (hmodule != NULL) return (gpointer) hmodule;
570 
571   if (p_GetModuleHandleExA == NULL) {
572     p_GetModuleHandleExA =
573       (t_GetModuleHandleExA) GetProcAddress (GetModuleHandle ("kernel32.dll"),
574                                              "GetModuleHandleExA");
575   }
576 
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;
584   }
585 
586   return (gpointer) hmodule;
587 }
588 
589 #endif /* G_OS_WIN32 */
590 
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.
596  *
597  *  On Windows, the compiled in path is *not* used, as it might not
598  *  match the path where the user has installed gEDA.
599  *
600  *  \warning The returned string is owned by libgeda and should not be
601  *  modified or free'd.
602  *
603  *  \todo On UNIX platforms we should follow the XDG Base Directory
604  *  Specification.
605  *
606  *  \return the gEDA shared data path, or NULL if none could be found.
607  */
s_path_sys_data()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");
613   }
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);
627   }
628   return p;
629 }
630 
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.
637  *
638  *  \warning The returned string is owned by libgeda and should not be
639  *  modified or free'd.
640  *
641  *  \todo On UNIX platforms we should follow the XDG Base Directory
642  *  Specification.
643  *
644  *  \return the gEDA shared config path, or NULL if none could be
645  *  found.
646  */
s_path_sys_config()647 const char *s_path_sys_config () {
648   static const char *p = NULL;
649 
650   /* If GEDADATARC is set in the environment, use that path */
651   if (p == NULL) {
652     p = g_getenv ("GEDADATARC");
653   }
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
662   }
663   if (p != NULL) g_setenv("GEDADATARC", p, FALSE);
664   return p;
665 }
666 
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.
672  *
673  *  \warning The returned string is owned by libgeda and should not be
674  *  modified or free'd.
675  *
676  *  \todo On Windows, we should use APPDATA.
677  *
678  *  \todo On UNIX platforms we should follow the XDG Base Directory
679  *  Specification.
680  */
s_path_user_config()681 const char *s_path_user_config () {
682   static const char *p = NULL;
683 
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);
688   }
689   return p;
690 }
691