[Author Prev][Author Next][Thread Prev][Thread Next][Author Index][Thread Index]

gEDA-cvs: CVS update: a_basic.c



  User: peterb  
  Date: 07/05/28 03:37:50

  Modified:    .        a_basic.c o_complex_basic.c o_embed.c o_list.c
                        s_basic.c s_clib.c s_hierarchy.c s_toplevel.c
  Log:
  Implement new component library system in libgeda.
  
  
  
  A new component library model is needed to allow gschem etc.
  
  to work well with part database systems.  This patch
  
  provides the necessary infrastructure in libgeda, without
  
  the frontend Guile commands required to make use of the new
  
  features.  In particular, it abstracts the component
  
  library into the concepts of "Component Sources" and
  
  "Symbols", and allows external "Library Commands" to
  
  provide symbol data in addition to the traditional directory
  
  libraries.
  
  
  
  In order to allow the new system to work, there are major
  
  changes in all code which manipulates COMPLEX objects; in 
  
  particular, the magic "EMBEDDED" string is now only used 
  
  in the on-disc representation.
  
  
  
  
  Revision  Changes    Path
  1.25                 eda/geda/gaf/libgeda/src/a_basic.c
  
  (In the diff below, changes in quantity of whitespace are not shown.)
  
  Index: a_basic.c
  ===================================================================
  RCS file: /home/cvspsrv/cvsroot/eda/geda/gaf/libgeda/src/a_basic.c,v
  retrieving revision 1.24
  retrieving revision 1.25
  diff -u -b -r1.24 -r1.25
  --- a_basic.c	28 May 2007 07:30:31 -0000	1.24
  +++ a_basic.c	28 May 2007 07:37:49 -0000	1.25
  @@ -92,7 +92,7 @@
   
             case(OBJ_COMPLEX):
               out = (char *) o_complex_save(o_current);
  -            if (strncmp(o_current->complex_clib, "EMBEDDED", 8) == 0) {
  +            if (o_complex_is_embedded(o_current)) {
                 fprintf(fp, "[\n");
   								
                 o_save_embedded(
  @@ -225,7 +225,7 @@
               fprintf(fp, "%s\n", out);
               already_wrote=1;
   	    g_free(out); /* need to free here because of the above flag */
  -            if (strncmp(o_current->complex_clib, "EMBEDDED", 8) == 0) {
  +            if (o_complex_is_embedded(o_current)) {
                 fprintf(fp, "[\n");
   								
                 o_save_embedded(
  
  
  
  1.34                 eda/geda/gaf/libgeda/src/o_complex_basic.c
  
  (In the diff below, changes in quantity of whitespace are not shown.)
  
  Index: o_complex_basic.c
  ===================================================================
  RCS file: /home/cvspsrv/cvsroot/eda/geda/gaf/libgeda/src/o_complex_basic.c,v
  retrieving revision 1.33
  retrieving revision 1.34
  diff -u -b -r1.33 -r1.34
  --- o_complex_basic.c	29 Apr 2007 12:01:21 -0000	1.33
  +++ o_complex_basic.c	28 May 2007 07:37:49 -0000	1.34
  @@ -308,8 +308,7 @@
     if(o_current->complex == NULL)
     return 0;
   
  -  if (o_current->complex_clib && 
  -      strncmp(o_current->complex_clib, "EMBEDDED", 8) == 0) {
  +  if (o_current->complex_embedded) {
       return 1;
     } else {
       return 0;
  @@ -317,6 +316,46 @@
   
   }
   
  +/*! \brief Add a symbol given its basename.
  + *  \todo Complete function documentation
  + */
  +OBJECT *o_complex_add_by_name(TOPLEVEL *w_current, OBJECT *object_list, 
  +			      GList **object_glist, char type,
  +			      int color, int x, int y, int angle,
  +			      int mirror, const gchar *basename,
  +			      int selectable,
  +			      int attribute_promotion)
  +{
  +  const CLibSymbol *sym;
  +  GList *symlist;
  +
  +  symlist = s_clib_glob (basename);
  +
  +  if (symlist == NULL) {
  +    s_log_message("Component [%s] was not found in any component library\n", 
  +		  basename);
  +    fprintf(stderr,
  +	    "Component [%s] was not found in any component library\n", 
  +	    basename);
  +    sym = NULL;
  +  } else {
  +    if (g_list_next (symlist) != NULL) {
  +      s_log_message ("More than one component found with name [%s]\n",
  +		     basename);
  +    }
  +    /*! \todo For now, use the first source with a symbol with that
  +     *  name. Maybe open a dialog to select the right one? */
  +    sym = (CLibSymbol *) symlist->data;
  +  }
  +
  +  g_list_free (symlist);
  +
  +  return o_complex_add (w_current, object_list, object_glist, type,
  +			color, x, y, angle, mirror, sym, basename,
  +			selectable, attribute_promotion);
  +
  +}
  +
   /* Done */
   /*! \brief
    *  \par Function Description
  @@ -325,8 +364,9 @@
   OBJECT *o_complex_add(TOPLEVEL *w_current, OBJECT *object_list, 
   		      GList **object_glist, char type,
   		      int color, int x, int y, int angle,
  -		      int mirror, char *clib,
  -		      char *basename, int selectable,
  +		      int mirror, const CLibSymbol *clib,
  +		      const gchar *basename,
  +		      int selectable,
   		      int attribute_promotion)
   {
     OBJECT *new_node=NULL;
  @@ -336,9 +376,10 @@
     int save_adding_sel = 0;
     int loaded_normally = FALSE;
     gboolean use_object_list;
  -  char *filename;
     GList *glist_ptr;
   
  +  gchar *buffer;
  +
     if (object_list) {
       use_object_list = TRUE;
     } else {
  @@ -348,11 +389,15 @@
     new_node = s_basic_init_object("complex");
     new_node->type = type;
   
  -  new_node->complex_basename = g_strdup(basename);
  -  if (clib)
  -    new_node->complex_clib = g_strdup(clib);
  -  else
  -    new_node->complex_clib = NULL;
  +  new_node->complex_clib = clib;
  +  if (clib != NULL) {
  +    new_node->complex_basename = g_strdup (s_clib_symbol_get_name (clib));
  +  } else {
  +    new_node->complex_basename = g_strdup (basename);
  +  }
  +
  +
  +  new_node->complex_embedded = FALSE;
   
     new_node->color = color;
   	
  @@ -389,30 +434,21 @@
     w_current->page_current->object_parent = prim_objs;
     /* reason this works is because it has a head, see add_head above */
   
  -  /* check for validity */
  -  if (clib && basename)
  -    filename = g_strdup_printf("%s%c%s", clib, G_DIR_SEPARATOR, basename);
  -  else 
  -    filename = g_strdup("unknown");
  +  /* get the symbol data */
  +  if (clib != NULL) {
  +    buffer = s_clib_symbol_get_data (clib);
  +  }
   
     save_adding_sel = w_current->ADDING_SEL;
     w_current->ADDING_SEL = 1;	/* name is hack, don't want to */
   
  -  if (access(filename, R_OK)) {
  +  if (clib == NULL || buffer == NULL) {
   
       OBJECT *save_prim_objs;
       char *not_found_text = NULL;
       int left, right, top, bottom;
       int x_offset, y_offset;
   
  -    if (clib == NULL) {
  -      s_log_message("Component library was not found or specified\n");
  -    } else if (basename == NULL) {
  -      s_log_message("Basename (component) was not found or specified\n");
  -    } else {
  -      s_log_message("Could not open symbol file [%s]\n", filename); 
  -    } 
  -
       /* filename was NOT found */
       loaded_normally = FALSE;
   
  @@ -434,7 +470,8 @@
   
       /* Add some useful text */
       not_found_text = 
  -      g_strdup_printf ("Component not found:\n %s", basename);
  +      g_strdup_printf ("Component not found:\n %s", 
  +		       new_node->complex_basename);
       prim_objs = o_text_add(w_current, prim_objs,
                              OBJ_TEXT, DETACHED_ATTRIBUTE_COLOR, 
                              x + NOT_FOUND_TEXT_X, 
  @@ -488,7 +525,9 @@
       loaded_normally = TRUE;
       
       /* add connections till translated */
  -    o_read(w_current, prim_objs, filename);
  +    o_read_buffer(w_current, prim_objs, buffer, -1, new_node->complex_basename);
  +
  +    g_free (buffer);
       
     }
     w_current->ADDING_SEL = save_adding_sel;
  @@ -618,7 +657,6 @@
     else
       o_complex_recalc(w_current, new_node);
   
  -  g_free(filename);
     return(object_list);
   }
   
  @@ -628,7 +666,7 @@
    */
   OBJECT *o_complex_add_embedded(TOPLEVEL *w_current, OBJECT *object_list,
   			       char type, int color, int x, int y, int angle,
  -			       char *clib, char *basename, int selectable)
  +			       const gchar *basename, int selectable)
   {
     OBJECT *prim_objs=NULL;
     OBJECT *new_node=NULL;
  @@ -643,11 +681,10 @@
     new_node->complex->angle = angle;
     new_node->complex->mirror = 0;
   	
  -  new_node->complex_basename = g_strdup(basename);
  -  if (clib)
  -    new_node->complex_clib = g_strdup(clib);
  -  else
       new_node->complex_clib = NULL;
  +  new_node->complex_basename = g_strdup(basename);
  +
  +  new_node->complex_embedded = TRUE;
   
     new_node->color = color;
   
  @@ -700,6 +737,7 @@
   /*! \brief
    *  \par Function Description
    *
  + *  \todo Don't use fixed-length string for symbol basename
    */
   OBJECT *o_complex_read(TOPLEVEL *w_current, OBJECT *object_list,
   		       char buf[], unsigned int release_ver,
  @@ -709,8 +747,7 @@
     int x1, y1;
     int angle;
   
  -  char basename[256]; /* hack */
  -  char *clib=NULL;
  +  char basename[256]; /* FIXME This is a hack */
   	
     int selectable;
     int mirror;
  @@ -749,32 +786,15 @@
     object_list = o_complex_add_embedded(w_current, 
                                          object_list, type, 
                                          WHITE, x1, y1, angle,
  -                                       "EMBEDDED", basename, 
  +                                       basename + 8, 
                                          selectable);
     } else {
  -    const GSList *clibs = s_clib_search_basename (basename);
  -    if (clibs == NULL) {
  -      s_log_message("Component [%s] was not found in any component library\n", 
  -		    basename);
  -      fprintf(stderr,
  -	      "Component [%s] was not found in any component library\n", 
  -	      basename);
  -      clib = NULL;
  -    } else {
  -      if (g_slist_next (clibs)) {
  -	s_log_message ("More than one component found with name [%s]\n",
  -		       basename);
  -	/* PB: for now, use the first directory in clibs */
  -	/* PB: maybe open a dialog to select the right one? */
  -      }
  -      clib = (gchar*)clibs->data;
  -    }
       
  -    object_list = o_complex_add(w_current, object_list, NULL, type, 
  +    object_list = o_complex_add_by_name(w_current, object_list, NULL, type, 
   				WHITE, 
   				x1, y1, 
   				angle, mirror,
  -				clib, basename, selectable, FALSE);
  +					basename, selectable, FALSE);
     }
   
     return object_list;
  @@ -788,6 +808,7 @@
   {
     int selectable;
     char *buf = NULL;
  +  char *basename;
   
     g_return_val_if_fail (object != NULL, NULL);
   
  @@ -796,16 +817,28 @@
     else 
     selectable = 0;
   
  -  if (object->type == OBJ_COMPLEX) {
  -    buf = g_strdup_printf("%c %d %d %d %d %d %s", object->type,
  -	    		  object->complex->x, object->complex->y, selectable, 
  -			  object->complex->angle, object->complex->mirror, 
  +  if ((object->type == OBJ_COMPLEX) || (object->type == OBJ_PLACEHOLDER)) {
  +    basename = g_strdup_printf ("%s%s",
  +				object->complex_embedded ? "EMBEDDED" : "",
   			  object->complex_basename);
  -  } else if (object->type == OBJ_PLACEHOLDER) {
  +    switch (object->type) {
  +    case OBJ_COMPLEX:
  +      buf = g_strdup_printf("%c %d %d %d %d %d %s", object->type,
  +			    object->complex->x, object->complex->y, 
  +			    selectable, object->complex->angle, 
  +			    object->complex->mirror, basename);
  +      break;
  +    case OBJ_PLACEHOLDER:
  +      /* write 'C' manually */
       buf = g_strdup_printf("C %d %d %d %d %d %s",
  -	    		  object->complex->x, object->complex->y, selectable, 
  -			  object->complex->angle, object->complex->mirror, 
  -			  object->complex_basename);  /* write 'C' manually */
  +			    object->complex->x, object->complex->y, 
  +			    selectable, object->complex->angle, 
  +			    object->complex->mirror, basename);
  +      break;
  +    default:
  +      g_assert_not_reached();
  +    }
  +    g_free (basename);
     }
   
     return(buf);
  @@ -815,36 +848,14 @@
    *  \par Function Description
    *
    */
  -void o_complex_set_filename(TOPLEVEL *w_current, char *clib, char *basename) 
  +void o_complex_set_filename(TOPLEVEL *w_current, const CLibSymbol *clib, char *basename) 
   {
  -  int len;
  -
  -  if (basename == NULL) {
  -    fprintf(stderr, "Got NULL basename in o_complex_set_filename!\n");
  -    exit(-1);
  -  }
  -
     if (clib == NULL) {
       fprintf(stderr, "Got NULL clib in o_complex_set_filename!\n");
       exit(-1);
     }
   
  -  if (w_current->internal_basename) {
  -    g_free(w_current->internal_basename);
  -  }
  -
  -  if (w_current->internal_clib) {
  -    g_free(w_current->internal_clib);
  -  }
  -
  -  len = strlen(basename);
  -  w_current->internal_basename = (char *) g_malloc(sizeof(char)*len+1);
  -
  -  len = strlen(clib) + 1;	
  -  w_current->internal_clib = (char *) g_malloc(sizeof(char)*len+1);
  -
  -  strcpy(w_current->internal_basename, basename);	
  -  strcpy(w_current->internal_clib, clib);	
  +  w_current->internal_clib = clib;
   } 
   
   /*! \brief
  @@ -853,13 +864,7 @@
    */
   void o_complex_free_filename(TOPLEVEL *w_current)
   {
  -  if (w_current->internal_basename) {
  -    g_free(w_current->internal_basename);
  -  }
   
  -  if (w_current->internal_clib) {
  -    g_free(w_current->internal_clib);
  -  }
   }
   
   /*! \brief
  @@ -998,7 +1003,8 @@
   
     new_obj = o_complex_add(w_current, list_tail, NULL, o_current->type, color,
                             o_current->complex->x, o_current->complex->y, 
  -                          o_current->complex->angle, o_current->complex->mirror,
  +                          o_current->complex->angle, 
  +			  o_current->complex->mirror,
                             o_current->complex_clib, o_current->complex_basename, 
                             selectable, FALSE); 
   
  @@ -1056,7 +1062,6 @@
                                      color,
                                      o_current->complex->x, o_current->complex->y, 
                                      o_current->complex->angle, 
  -                                   o_current->complex_clib, 
                                      o_current->complex_basename, 
                                      selectable); 
     /* deal with stuff that has changed */
  
  
  
  1.2                  eda/geda/gaf/libgeda/src/o_embed.c
  
  (In the diff below, changes in quantity of whitespace are not shown.)
  
  Index: o_embed.c
  ===================================================================
  RCS file: /home/cvspsrv/cvsroot/eda/geda/gaf/libgeda/src/o_embed.c,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -b -r1.1 -r1.2
  --- o_embed.c	9 Jan 2007 04:47:11 -0000	1.1
  +++ o_embed.c	28 May 2007 07:37:49 -0000	1.2
  @@ -49,27 +49,17 @@
    */
   void o_embed(TOPLEVEL *w_current, OBJECT *o_current)
   {
  -  gchar *new_basename;
   
     /* check o_current is a complex and is not already embedded */
     if (o_current->type == OBJ_COMPLEX &&
         !o_complex_is_embedded (o_current))
     {
  -    /* change the clib of complex to "EMBEDDED" */
  -    if (o_current->complex_clib) {
  -      g_free (o_current->complex_clib);
  -    }
  -    o_current->complex_clib = g_strdup ("EMBEDDED");
  -
  -    /* change the basename to "EMBEDDED"+basename */
  -    new_basename = g_strconcat ("EMBEDDED",
  -                                o_current->complex_basename,
  -                                NULL);
  -    g_free (o_current->complex_basename);
  -    o_current->complex_basename = new_basename;
  +
  +    /* set the embedded flag */
  +    o_current->complex_embedded = TRUE;
   
       s_log_message ("Component [%s] has been embedded\n",
  -                   o_current->complex_basename + 8);
  +                   o_current->complex_basename);
       
       /* page content has been modified */
       w_current->page_current->CHANGED = 1;
  @@ -98,39 +88,34 @@
    */
   void o_unembed(TOPLEVEL *w_current, OBJECT *o_current)
   {
  -  gchar *new_basename, *new_clib;
  -  const GSList *clibs;
  +  GList *symlist;
     
     /* check o_current is an embedded complex */
     if (o_current->type == OBJ_COMPLEX &&
         o_complex_is_embedded (o_current))
     {
  -    /* get ride of the EMBEDDED word in basename */
  -    new_basename = g_strdup (o_current->complex_basename + 8);
       
       /* search for the symbol in the library */
  -    clibs = s_clib_search_basename (new_basename);
  +    symlist = s_clib_glob (o_current->complex_basename);
   
  -    if (!clibs) {
  +    if (!symlist) {
         /* symbol not found in the symbol library: signal an error */
         s_log_message ("Could not find component [%s], while trying to unembed. Component is still embedded\n",
  -                     o_current->complex_basename + 8);
  +                     o_current->complex_basename);
         
       } else {
  -      /* set the object new basename */
  -      g_free (o_current->complex_basename);
  -      o_current->complex_basename = new_basename;
   
         /* set the object new clib */
  -      g_free (o_current->complex_clib);
  -      if (g_slist_next (clibs)) {
  +      if (g_list_next (symlist)) {
           s_log_message ("More than one component found with name [%s]\n",
  -                       new_basename);
  +                       o_current->complex_basename);
           /* PB: for now, use the first directory in clibs */
           /* PB: maybe open a dialog to select the right one? */
         }
  -      new_clib = g_strdup ((gchar*)clibs->data);
  -      o_current->complex_clib = new_clib;
  +      o_current->complex_clib = (CLibSymbol *) symlist->data;
  +
  +      /* clear the embedded flag */
  +      o_current->complex_embedded = FALSE;
   
         s_log_message ("Component [%s] has been successfully unembedded\n",
                        o_current->complex_basename);
  
  
  
  1.20                 eda/geda/gaf/libgeda/src/o_list.c
  
  (In the diff below, changes in quantity of whitespace are not shown.)
  
  Index: o_list.c
  ===================================================================
  RCS file: /home/cvspsrv/cvsroot/eda/geda/gaf/libgeda/src/o_list.c,v
  retrieving revision 1.19
  retrieving revision 1.20
  diff -u -b -r1.19 -r1.20
  --- o_list.c	17 Dec 2006 04:14:07 -0000	1.19
  +++ o_list.c	28 May 2007 07:37:49 -0000	1.20
  @@ -95,8 +95,7 @@
   
       case(OBJ_COMPLEX):
       case(OBJ_PLACEHOLDER):
  -      if (selected->complex_clib && 
  -          strncmp(selected->complex_clib, "EMBEDDED", 8) == 0) {
  +      if (o_complex_is_embedded (selected)) {
           end = (OBJECT *) o_complex_copy_embedded(w_current, end, selected);	
         } else {
           end = (OBJECT *) o_complex_copy(w_current, end, selected);	
  
  
  
  1.27                 eda/geda/gaf/libgeda/src/s_basic.c
  
  (In the diff below, changes in quantity of whitespace are not shown.)
  
  Index: s_basic.c
  ===================================================================
  RCS file: /home/cvspsrv/cvsroot/eda/geda/gaf/libgeda/src/s_basic.c,v
  retrieving revision 1.26
  retrieving revision 1.27
  diff -u -b -r1.26 -r1.27
  --- s_basic.c	17 Apr 2007 20:19:21 -0000	1.26
  +++ s_basic.c	28 May 2007 07:37:49 -0000	1.27
  @@ -454,10 +454,6 @@
       }
       o_current->complex_basename = NULL;
   
  -    if (o_current->complex_clib) {
  -      /*	printf("sdeleting complex_clib\n");*/
  -      g_free(o_current->complex_clib); 
  -    }
       o_current->complex_clib = NULL;
   
       if (o_current->complex) {
  
  
  
  1.20                 eda/geda/gaf/libgeda/src/s_clib.c
  
  (In the diff below, changes in quantity of whitespace are not shown.)
  
  Index: s_clib.c
  ===================================================================
  RCS file: /home/cvspsrv/cvsroot/eda/geda/gaf/libgeda/src/s_clib.c,v
  retrieving revision 1.19
  retrieving revision 1.20
  diff -u -b -r1.19 -r1.20
  --- s_clib.c	5 Dec 2006 19:39:14 -0000	1.19
  +++ s_clib.c	28 May 2007 07:37:49 -0000	1.20
  @@ -1,6 +1,6 @@
   /* gEDA - GPL Electronic Design Automation
    * libgeda - gEDA's library
  - * Copyright (C) 1998-2000 Ales V. Hvezda
  + * Copyright (C) 1998-2007 gEDA Contributors
    *
    * This program is free software; you can redistribute it and/or modify
    * it under the terms of the GNU General Public License as published by
  @@ -16,25 +16,102 @@
    * along with this program; if not, write to the Free Software
    * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA
    */
  +
   /*! \file s_clib.c
  + *  \brief The component library system
  + *
    *  <B>clib</B> stands for component library.
    *
  - *  A component library is made of several directories gathering
  - *  component files. 
  + *  The <b>component library</b> is made up of a number of
  + *  <b>component sources</b>, each of which in turn makes available a
  + *  number of component <b>symbols</b>.  Each source may be either a
  + *  directory on disk containing symbol files, or a command in the
  + *  system PATH which can generate gEDA symbol data (e.g. from a
  + *  database).  A component source is represented by a CLibSource
  + *  instance.
  + *
  + *  The component library system manages component sources and
  + *  symbols, and abstracts the interface to the underlying storage.
  + *
  + *  To initialise the component library, s_clib_init() is called.  To
  + *  clean up when it is no longer needed, s_clib_free() should be
  + *  called.
  + * 
  + *  A directory which contains one or more symbol files in gEDA
  + *  format may be used as a component source. Each symbol file should
  + *  have a filename ending in ".sym" (case sensitive).  A
  + *  component source based on a directory can be added using
  + *  s_clib_add_directory().  Symbol files with filenames starting with
  + *  a period "." are ignored.
  + *
  + *  An executable program in the system search path may be used as a
  + *  component source, and it must conform with the specification given
  + *  on page \ref libcmds.  A component source based on a command may
  + *  be added using s_clib_add_command().
  + *
  + *  Each symbol is identified by its \b name, which is stored in the
  + *  saved schematic file.  The name must be a valid for storage in a
  + *  gEDA schematic file as the "basename" of a "component" object.
  + *  For symbols from directory sources, the filename of the symbol is
  + *  taken as the symbol name.  For a command source, the name may be
  + *  any permissible string.  Guidelines to follow:
  + *
  + *    -# Do not begin a symbol name with "<tt>EMBEDDED</tt>"
  + *    -# Do not use whitespace, or any of the characters "<tt>/:!*?</tt>".
  + *    -# Try to use unique names.
  + *  
  + *  The component database may be queried using s_clib_glob().  A
  + *  null-terminated buffer containing symbol data (suitable for
  + *  loading using o_read_buffer()) may be obtained using
  + *  s_clib_symbol_get_data().  If an exact symbol name is known, the
  + *  symbol data may be requested directly using
  + *  s_clib_symbol_get_data_by_name().
  + *
  + *  \todo
  + *    -# Categorisation of symbols.
  + *
  + *    -# Case-insensitive matching of symbol file extensions (both ".sym"
  + *       and ".SYM" should match).
  + *
  + *  \page libcmds Library Commands
  + *
  + *  A library command should implement this specification.  Note that
  + *  as additional features may be added to the component library in
  + *  the future, ideally a library command should only respond to the
  + *  commands detailed here.
  + *
  + *  The command line syntax for a library command is:
  + *
  + *  <tt>libcmd \<mode\> [mode arguments]</tt>
  + *
  + *  All diagnostic and error information should be printed to standard
  + *  error.  Only data should be printed to standard output.  All data
  + *  output from a library command should be encoded using UTF8.
  + *
  + *  If an error occurs, the command must exit with non-zero exit
  + *  status, with any diagnostic information should be printed on
  + *  standard error.
  + *
  + *  \section libcmds_modes Modes
  + *
  + *  <tt>libcmd help</tt>
  + *
  + *  If \b help is passed as the mode, a command may output a help
  + *  message.  This mode is optional.
  + *
  + *  <tt>libcmd list</tt>
  + *
  + *  If \b list is passed as the mode, a command must output a list of
  + *  the symbols it provides, separated by newlines.  Lines beginning
  + *  with a period '.' are ignored.  If an error occurs, the command
  + *  must exit with non-zero exit status.
  + *
  + *  <tt>libcmd get \<symbolname\>
  + *
  + *  If \b get is passed as the mode, a command must output the symbol
  + *  data corresponding to \b symbolname.  If \b symbolname is unknown
  + *  to the command, the command must exit with non-zero exit status.
    *
  - *  It must first be initialized with #s_clib_init(). When it is no more
  - *  useful, use #s_clib_free() to free memory and reset the component
  - *  library.
  - *
  - *  To add a directory to the library, use #s_clib_add_directory().
  - *
  - *  To retrieve a list of the directories that make the library, use
  - *  #s_clib_get_directories(). For a list of component files in a
  - *  directory of the library, use #s_clib_get_files().
  - *
  - *  #s_clib_search_basename() let you find a specific component from
  - *  its name. Please note that it returns a list of directories as there
  - *  may be several places that contains a component with this name.
    */
   
   #include <config.h>
  @@ -49,207 +126,778 @@
   #include <dmalloc.h>
   #endif
   
  +#include <gtk/gtk.h>
  +#include <libguile.h>
  +
  +#include <sys/wait.h>
  +
   #include "defines.h"
  +#include "struct.h"
  +#include "globals.h"
  +#include "o_types.h"
  +#include "colors.h"
  +#include "i_vars.h"
  +#include "prototype.h"
   
  +/* Constant definitions
  + * ===================
  + */
  +
  +/*! All symbols in directory sources end with this string */
  +#define SYM_FILENAME_FILTER ".sym"
   
  -void s_clib_free (void);
  +/*! Library command mode used to fetch list of symbols */
  +#define CLIB_LIST_CMD       "list"
   
  -static GList *clib_directories = NULL;
  +/*! Library command mode used to fetch symbol data */
  +#define CLIB_DATA_CMD       "get"
   
  -static GHashTable *clib_cache = NULL;
  +/* Type definitions
  + * ================
  + */
  +
  +/*! Valid types of component source */
  +enum CLibSourceType { 
  +  /*! Directory source */
  +  CLIB_DIR, 
  +  /*! Command source */
  +  CLIB_CMD };
  +
  +/*! Stores data about a particular component source */
  +struct _CLibSource {
  +  /*! Type of source */
  +  enum CLibSourceType type;
  +  /*! Path to directory or name of executable */
  +  gchar *path_cmd;
  +  /*! Available symbols (CLibSymbol) */
  +  GList *symbols;
  +};
  +
  +/*! Stores data about a particular symbol */
  +struct _CLibSymbol {
  +  /*! The source this symbols is available from */
  +  CLibSource *source;
  +  /*! The name of this symbol */
  +  gchar *name;
  +};
  +
  +/* Static variables
  + * ================
  + */
  +
  +/*! Holds the list of all known component sources */
  +static GList *clib_sources = NULL;
  +
  +/* Local static functions
  + * ======================
  + */
   
  -/*! \brief Initializes the component library handling code.
  +static void free_symbol (gpointer data, gpointer user_data);
  +static void free_source (gpointer data, gpointer user_data);
  +static gchar *run_source_command (gchar **argv);
  +static CLibSymbol *source_has_symbol (const CLibSource *source, 
  +				      const gchar *name);
  +static void refresh_directory (CLibSource *source);
  +static void refresh_command (CLibSource *source);
  +static CLibSource *check_source_bump (const gchar *path_cmd);
  +static gchar *get_data_directory (const CLibSymbol *symbol);
  +static gchar *get_data_command (const CLibSymbol *symbol);
  +
  +/*! \brief Initialise the component library.
    *  \par Function Description
  - *  Initializes the component library handling code.
  - *  \warning This function must be called before any other function
  - *           of this file.
  + *  Resets and initialises the component library.
  + *
  + *  \warning This function must be called before any other functions
  + *  from s_clib.c.
    */
  -void s_clib_init (void)
  +void s_clib_init ()
   {
  -  if (clib_directories != NULL || clib_cache != NULL) {
  +  if (clib_sources != NULL) {
       s_clib_free ();
     }
  +}
  +
  +/*! \brief Iterator callback for freeing a symbol.
  + *  \par Function Description
  + *  Private function used only in s_clib.c.
  + */
  +static void free_symbol (gpointer data, gpointer user_data)
  +{
  +  CLibSymbol *symbol = data;
  +  if (symbol != NULL) {
  +    if (symbol->source != NULL) {
  +      symbol->source = NULL;
  +    }
  +    if (symbol->name != NULL) {
  +      g_free (symbol->name);
  +      symbol->name = NULL;
  +    }
  +  }
  +}
   
  -  clib_cache = g_hash_table_new (g_str_hash, g_str_equal);
  +/*! \brief Iterator callback for freeing a source.
  + *  \par Function Description
  + *  Private function used only in s_clib.c.
  + */
  +static void free_source (gpointer data, gpointer user_data)
  +{
  +  CLibSource *source = data;
  +  if (source != NULL) {
  +    if (source->path_cmd != NULL) {
  +      g_free (source->path_cmd);
  +      source->path_cmd = NULL;
  +    }
  +    if (source->symbols != NULL) {
  +      g_list_foreach (source->symbols, (GFunc) free_symbol, NULL);
  +      g_list_free (source->symbols);
  +      source->symbols = NULL;
  +    }
  +  }
  +}
     
  +/*! \brief Free all memory used by the component library.
  + *  \par Function Description
  + *  Should be called at program exit to clean up any remaining data
  + *  being used by the component library system.
  + */
  +void s_clib_free ()
  +{
  +  if (clib_sources != NULL) {
  +    g_list_foreach (clib_sources, (GFunc) free_source, NULL);
  +    g_list_free (clib_sources);
  +    clib_sources = NULL;
  +  }
   }
   
  -/*! \todo Finish function documentation!!!
  - *  \brief
  +/*! \brief Execute a library command.
    *  \par Function Description
  + *  Execute a library command, returning the standard output, or \b
  + *  NULL if the command fails for some reason.  The system \b PATH is
  + *  used to find the program to execute.
  + *
  + *  Private function used only in s_clib.c.
  + *
  + *  \param argv null-terminated list of arguments.  The name of the
  + *              program to execute should appear first.
    *
  + *  \return The program's output, or \b NULL on failure.
    */
  -static void clib_free_cache_entry (gpointer key, gpointer value,
  -				   gpointer user_data)
  +static gchar *run_source_command (gchar **argv)
   {
  -  g_free (key);
  -  if (value != NULL) {
  -    /* value is a singly-linked list of strings */
  -    g_list_foreach (value, (GFunc)g_free, NULL);
  -    g_slist_free ((GSList*)value);
  +  gchar *standard_output = NULL;
  +  gchar *standard_error = NULL;
  +  gint exit_status;
  +  GError *e = NULL;
  +  gchar *command = NULL;
  +  gboolean success = FALSE;
  +  
  +  g_spawn_sync (NULL, /* Use gschem's CWD */
  +		argv,
  +		NULL, /* No special environment */
  +		G_SPAWN_SEARCH_PATH,
  +		NULL, /* No setup function (not portable anyway) */
  +		NULL, /* No user data */
  +		&standard_output,
  +		&standard_error,
  +		&exit_status,
  +		&e);
  +
  +  command = g_strjoinv (" ", argv);
  +
  +  if (e != NULL) {
  +    s_log_message ("Library command failed [%s]: %s\n", command, 
  +		   e->message);
  +    g_error_free (e);
  +
  +  } else if (WIFSIGNALED(exit_status)) {
  +    s_log_message ("Library command failed [%s]: Uncaught signal %i.\n",
  +		   command, WTERMSIG(exit_status));
  +    
  +  } else if (!WIFEXITED(exit_status)) {
  +    s_log_message ("Library command failed [%s]\n", command);
  +    s_log_message("Error output was:\n%s\n", standard_error);
  +
  +  } else {
  +    success = TRUE;
     }
  +
  +  g_free (command);
  +  g_free (standard_error);
  +  
  +  if (success) return standard_output;
  +
  +  g_free (standard_output);
  +  return NULL;
  +}
  +
  +/*! \brief Get a list of available component sources.
  + *  \par Function Description
  + *  Gets the current list of sources.
  + *  \warning The GList returned should be freed when no longer
  + *  needed. The returned value is not guaranteed to remain valid over
  + *  calls to s_clib_add_directory() or s_clib_add_command().
  + *  \return A \b GList of CLibSource.
  + */
  +GList *s_clib_get_sources ()
  +{
  +  return g_list_copy(clib_sources);
   }
   
  -/*! \brief Frees memory used by the component library.
  +/*! \brief Find any symbols within a source with a given name.
    *  \par Function Description
  - *  Frees memory used by the component library.
  + *  Iterates through the symbol list of the given source, checking if
  + *  there is already a symbol with the given name.  If there is
  + *  such a symbol, it is returned.
  + *
  + *  \param source The source to check.
  + *  \param name The symbol name to look for.
  + *  \return The matching symbol, or \b NULL if no match was found.
    */
  -void s_clib_free (void)
  +static CLibSymbol *source_has_symbol (const CLibSource *source, 
  +				      const gchar *name)
   {
  -  if (clib_directories != NULL) {
  -    g_list_foreach (clib_directories, (GFunc)g_free, NULL);
  -    g_list_free (clib_directories);
  -    clib_directories = NULL;
  +  GList *symlist;
  +  CLibSymbol *symbol;
  +
  +  for (symlist = g_list_first(source->symbols); 
  +       symlist != NULL; 
  +       symlist = g_list_next(symlist)) {
  +    
  +    symbol = (CLibSymbol *) symlist->data;
  +
  +    if (strcmp (symbol->name, name) == 0) return symbol;
     }
   
  -  if (clib_cache != NULL) {
  -    g_hash_table_foreach (clib_cache, clib_free_cache_entry, NULL);
  -    g_hash_table_destroy (clib_cache);
  -    clib_cache = NULL;
  +  return NULL;
  +}
  +
  +/*! \brief Rescan a directory for symbols.
  + *  \par Function Description
  + *  Rescans a directory for symbols.
  + *
  + *  \todo Does this need to do something more sane with subdirectories
  + *  than just skipping them silently?
  + *
  + *  Private function used only in s_clib.c.
  + */
  +static void refresh_directory (CLibSource *source)
  +{
  +  CLibSymbol *symbol;
  +  GDir *dir;
  +  const gchar *entry;
  +  gchar *fullpath;
  +  gboolean isfile;
  +  GError *e = NULL;
  +
  +  g_assert (source != NULL);
  +  g_assert (source->type == CLIB_DIR);
  +
  +  /* Clear the current symbol list */
  +  g_list_foreach (source->symbols, (GFunc) free_symbol, NULL);
  +  g_list_free (source->symbols);
  +  source->symbols = NULL;  
  +
  +  /* Open the directory for reading. */
  +  dir = g_dir_open (source->path_cmd, 0, &e);
  +
  +  if (e != NULL) {
  +    s_log_message ("Failed to open directory [%s]: %s\n",
  +		   source->path_cmd, e->message);
  +    g_error_free (e);
  +    return;
     }
     
  +  while ((entry = g_dir_read_name (dir)) != NULL) {
  +    /* skip ".", ".." & hidden files */
  +    if (entry[0] == '.') continue;
  +
  +    /* skip subdirectories (for now) */
  +    fullpath = g_build_filename (source->path_cmd, entry, NULL);
  +    isfile = g_file_test (fullpath, G_FILE_TEST_IS_REGULAR);
  +    g_free (fullpath);
  +    if (!isfile) continue;
  +
  +    /* skip filenames that don't match the filter or that we already
  +     * know about. */
  +    if (!g_str_has_suffix (entry, SYM_FILENAME_FILTER)
  +	|| (source_has_symbol (source, entry) != NULL)) {
  +      continue;
  +    }
  +
  +    /* Create and add new symbol record */
  +    symbol = g_new0 (CLibSymbol, 1);
  +    symbol->source = source;
  +    symbol->name = g_strdup(entry);
  +
  +    /* Prepend because it's faster. */
  +    source->symbols = g_list_prepend (source->symbols, symbol);
  +  }
  +
  +  entry = NULL;
  +  g_dir_close (dir);
  +
  +  /* We prepended each element, so now we have to reverse the whole
  +   * list. */
  +  source->symbols = g_list_reverse (source->symbols);
   }
   
  -/*! \brief Adds a new directory to the component library.
  +/*! \brief Re-poll a library command for symbols.
    *  \par Function Description
  - *  Adds <B>directory</B> as a new directory for the component library.
  + *  Runs a library command, requesting a list of available symbols,
  + *  and updates the source with the new list.
    *
  - *  \param [in] directory  Character string with the new directory name.
  + *  Private function used only in s_clib.c.
    */
  -void s_clib_add_directory (const gchar *directory)
  +static void refresh_command (CLibSource *source)
   {
  -  /* search for directory in clib_directories */
  -  if (!g_list_find_custom (clib_directories,
  -			   directory,
  -			   (GCompareFunc) g_strcasecmp))
  -  {
  -    /* directory not yet in the list of known directories */
  -    /* add directory to list */
  -    clib_directories = g_list_append (clib_directories,
  -				      g_strdup (directory));
  +  gchar *cmdout;
  +  TextBuffer *tb;
  +  const gchar *line;
  +  CLibSymbol *symbol;
  +  gchar *name;
  +  gchar *argv[3];
  +
  +  g_assert (source != NULL);
  +  g_assert (source->type == CLIB_CMD);
  +
  +  /* Clear the current symbol list */
  +  g_list_foreach (source->symbols, (GFunc) free_symbol, NULL);
  +  g_list_free (source->symbols);
  +  source->symbols = NULL;  
  +
  +  /* Run the command to get the list of symbols */
  +  argv[0] = source->path_cmd;
  +  argv[1] = CLIB_LIST_CMD;
  +  argv[2] = NULL;
  +  cmdout = run_source_command ( argv );
  +  if (cmdout == NULL) return;
  +
  +  /* Use a TextBuffer to help reading out the lines of the output */
  +  tb = s_textbuffer_new (cmdout, -1);
  +
  +  while (1) {
  +    line = s_textbuffer_next_line (tb);
  +    if (line == NULL) break;
  +    if (line[0] == '.') continue;  /* TODO is this sane? */
  +
  +    name = remove_nl(g_strdup(line));
  +
  +    /* skip symbols already known about */
  +    if (source_has_symbol (source, name) != NULL) {
  +      g_free (name);
  +      continue;
     }
     
  +    symbol = g_new0 (CLibSymbol, 1);
  +    symbol->source = source;
  +    symbol->name = name;
  +
  +    /* Prepend because it's faster. */
  +    source->symbols = g_list_prepend (source->symbols, symbol);    
  +  }
  +
  +  s_textbuffer_free (tb);
  +  g_free (cmdout);
  +
  +  /* We prepended each element, so now we have to reverse the whole
  +   * list. */
  +  source->symbols = g_list_reverse (source->symbols);  
   }
   
  -/*! \brief Get list of component library directories.
  +/*! \brief Rescan all available component libraries.
    *  \par Function Description
  - *  This function returns the list of directories part of
  - *  the component library.
  + *  Resets the list of symbols available from each source, and
  + *  repopulates it from scratch.  Useful e.g. for checking for new
  + *  symbols.
    *
  - *  \return Global libgead #clib_directories variable.
  - *  \warning
  - *  The returned value is owned by libgeda and must not be modified or freed.
  + *  \todo Disabled for now because it would break cached CLibSymbols used
  + *  all over the place (e.g. in #st_object).
  + */
  +void s_clib_refresh ()
  +{
  +#if 0
  +  GList *sourcelist;
  +  CLibSource *source;
  +
  +  for (sourcelist = clib_sources; 
  +       sourcelist != NULL; 
  +       sourcelist = g_list_next(sourcelist)) {
  +    
  +    source = (CLibSource *) sourcelist->data;
  +    switch (source->type)
  +      {
  +      case CLIB_DIR:
  +	refresh_directory(source);
  +	break;
  +      case CLIB_CMD:
  +	refresh_command (source);
  +	break;
  +      default:
  +	g_assert_not_reached();
  +      }
  +  }
  +#endif
  +}
  +
  +/*! \brief Check if a given component source is already known.
  + *  \par Function Description
  + *  Iterates through the known component sources, checking if there is
  + *  already a source associated with \b path_cmd.  If there is such a
  + *  source, it is bumped to the front of the list of component sources.
  + *  
  + *  Private function used only in s_clib.c.
    *
  + *  \param path_cmd The source string to check.
  + *
  + *  \return The matching source, or \b NULL if no match was found.
    */
  -const GList *s_clib_get_directories()
  +static CLibSource *check_source_bump (const gchar *path_cmd)
   {
  -  return clib_directories;
  +  GList *sourcelist;
  +  CLibSource *source;
  +
  +  for (sourcelist = clib_sources; 
  +       sourcelist != NULL; 
  +       sourcelist = g_list_next(sourcelist)) {
  +
  +    source = (CLibSource *) sourcelist->data;
  +    if (strcmp (source->path_cmd, path_cmd) == 0) {
  +      clib_sources = g_list_remove_link (clib_sources, sourcelist);
  +      clib_sources = g_list_concat (sourcelist, clib_sources);
  +      return source;
  +    }
  +  }
  +
  +  return NULL;
   }
   
  -/*! \brief Get a list of files found a directory.
  +/*! \brief Add a directory of symbol files to the library
    *  \par Function Description
  - *  This function returns a list of file names found in <B>directory</B> and
  - *  that match <B>filter</B>
  + *  Adds a directory containing symbol files to the library.  Only
  + *  files ending with #SYM_FILENAME_FILTER are considered to be symbol
  + *  files.
    *
  - *  \param [in] directory  Character string with the path to search.
  - *  \param [in] filter     Character string to compare file names against.
  - *  \return List of file name that matched <B>filter</B>, NULL otherwise.
  + *  \param directory The path of the directory to add (UTF8).
  + *  \return The #CLibSource associated with the directory.
    */
  -GSList *s_clib_get_files (const gchar *directory, const gchar *filter)
  +const CLibSource *s_clib_add_directory (const gchar *directory)
   {
  -  GDir *dir;
  -  const gchar *entry;
  -  GSList *ret = NULL;
  +  CLibSource *source;
   
  -  /* check directory is in clib_directories */
  -  if (g_list_find_custom (clib_directories,
  -			  directory,
  -			  (GCompareFunc) g_strcasecmp) == NULL)
  -  {
  -    /* no, unknown directory: report an error */
  -    s_log_message ("Directory [%s] is not part of the component library\n",
  -                   directory);
  +  if (directory == NULL) {
       return NULL;
     }
   
  -  /* open the directory */
  -  dir = g_dir_open (directory, 0, NULL);
  -  if (dir == NULL) {
  -    s_log_message ("Failed to open directory [%s]\n", directory);
  +  source = check_source_bump (directory);
  +  if (source != NULL) return source;
  +
  +  source = g_new0 (CLibSource, 1);
  +  source->type = CLIB_DIR;
  +  source->path_cmd = g_strdup (directory);
  +  
  +  refresh_directory (source);
  +
  +  /* Sources added later get scanned earlier */
  +  clib_sources = g_list_prepend (clib_sources, source);
  +
  +  return source;
  +}
  +
  +/*! \brief Add a symbol-generating command to the library
  + *  \par Function Description
  + *  Adds a command which can generate symbols to the library.
  + *  See page \ref libcmds for more information on library commands.
  + *
  + *  \param command The executable to run, resolved using the \b PATH
  + *                 environment variable.
  + *
  + *  \return The CLibSource associated with the command.
  + */
  +const CLibSource *s_clib_add_command (const gchar *command)
  +{
  +  CLibSource *source;
  +  
  +  if (command == NULL) {
       return NULL;
     }
   
  -  /* now read the entire directory */
  -  /* and build a list of filenames in directory that match filter */
  -  while ((entry = g_dir_read_name (dir)) != NULL) {
  -    /* skip .'s */
  -    if (entry[0] == '.') {
  -      continue;
  -    }
  +  source = check_source_bump (command);
  +  if (source != NULL) return source;
   
  -    /* identify filter-matching filenames */
  -    if (strstr (entry, filter)) {
  -      ret = g_slist_append (ret, (gpointer)g_strdup (entry));
  -    }
  +  source = g_new0 (CLibSource, 1);
  +  source->type = CLIB_CMD;
  +  source->path_cmd = g_strdup (command);
  +
  +  refresh_command (source);
  +
  +  /* Sources added later get scanned earlier */
  +  clib_sources = g_list_prepend (clib_sources, source);
  +
  +  return source;
  +}
  +
  +
  +/*! \brief Get the name of a source.
  + *  \par Function Description
  + *  Get the name of a source for use e.g. in displaying a GUI.
  + *
  + *  \todo Make this do something cleverer than just returning
  + *  \b path_cmd.
  + *
  + *  \param source Source to be examined.
  + *  \return Name of source.
  +*/
  +const gchar *s_clib_source_get_name (const CLibSource *source)
  +{
  +  if (source == NULL) return NULL;
  +  return source->path_cmd;
  +}
  +
  +/*! \brief Get a list of symbols available from a given source.
  + *  \par Function Description
  + *  Get a \b GList containing all of the symbols available from \a
  + *  source.
  + *
  + *  \warning The returned \b GList will not be consistent over a call to
  + *  s_clib_refresh().  It should be freed when no longer needed.
  + *  
  + *  \param source Source to be examined.
  + *  \return A \b GList of #CLibSymbol.
  + */
  +GList *s_clib_source_get_symbols (const CLibSource *source)
  +{
  +  if (source == NULL) return NULL;
  +  return g_list_copy(source->symbols);
  +}
  +
  +
  +/*! \brief Get the name of a symbol.
  + *  \par Function Description
  + *  Get the name of a symbol.  The symbol name uniquely identifies it
  + *  to libgeda.
  + *
  + *  \param symbol Symbol to be examined.
  + *  \return Name of symbol.
  +*/
  +const gchar *s_clib_symbol_get_name (const CLibSymbol *symbol)
  +{
  +  if (symbol == NULL) return NULL;
  +  return symbol->name;
  +}
  +
  +/*! \brief Get a filename for editing a symbol.  
  + *  \par Function Description
  + *  Get the filename of the file a symbol was loaded from, if possible
  + *  (e.g. to allow loading for user editing).
  + *
  + *  \warning The returned string should be freed when no longer
  + *  needed.
  + *
  + *  \todo This is hack until there is a way to edit documents in
  + *  gschem which do not have a file in the filesystem associated with
  + *  them.
  + *
  + *  \deprecated This function is a temporary workaround.
  + *
  + *  \param symbol Symbol to be examined.
  + *  \return Filename of symbol.
  + */
  +gchar *s_clib_symbol_get_filename (const CLibSymbol *symbol)
  +{
  +  if (symbol == NULL) return NULL;
  +
  +  if (symbol->source->type != CLIB_DIR) return NULL;
  +
  +  return g_build_filename(symbol->source->path_cmd, symbol->name, NULL);
  +}
  +
  +/*! \brief Get the source to which a symbol belongs.
  + *  \par Function Description
  + *  Get the source which a symbol is associated.
  + *
  + *  \param symbol Symbol to be examined.
  + *  \return Source which owns symbol.
  +*/
  +const CLibSource *s_clib_symbol_get_source (const CLibSymbol *symbol)
  +{
  +  if (symbol == NULL) return NULL;
  +  return symbol->source;
  +}
  +
  +/*! \brief Get symbol data from a directory source.
  + *  \par Function Description
  + *  Get symbol data from a directory data source.  The return value
  + *  should be free()'d when no longer needed.
  + *
  + *  Private function used only in s_clib.c.
  + *
  + *  \param symbol Symbol to get data for.
  + *  \return Allocated buffer containing symbol data.
  + */
  +static gchar *get_data_directory (const CLibSymbol *symbol)
  +{
  +  gchar *filename = NULL;
  +  gchar *data = NULL;
  +  GError *e = NULL;
      
  +  g_assert (symbol != NULL);
  +  g_assert (symbol->source->type == CLIB_DIR);
  +
  +  filename = g_build_filename(symbol->source->path_cmd, 
  +			      symbol->name, NULL);
  +
  +  g_file_get_contents (filename, &data, NULL, &e);
  +
  +  if (e != NULL) {
  +    s_log_message ("Failed to load symbol from file [%s]: %s\n",
  +		   filename, e->message);
  +    g_error_free (e);
     }
     
  -  /* finished: close the directory stream */
  -  g_dir_close (dir);
  +  g_free (filename);
  +  return data;
  +}
   
  -  /* sort the list alphabetically */
  -  ret = g_slist_sort (ret, (GCompareFunc)g_strcasecmp);
  +/*! \brief Get symbol data from a library command.
  + *  \par Function Description
  + *  Get symbol data from a library command.  The return value should
  + *  be free()'d when no longer needed.
  + *
  + *  Private function used only in s_clib.c.
  + *
  + *  \param symbol Symbol to get data for.
  + *  \return Allocated buffer containing symbol data.
  + */
  +static gchar *get_data_command (const CLibSymbol *symbol)
  +{
  +  gchar *argv[4];
  +
  +  g_assert (symbol != NULL);
  +  g_assert (symbol->source->type == CLIB_CMD);
  +  
  +  argv[0] = symbol->source->path_cmd;
  +  argv[1] = CLIB_DATA_CMD;
  +  argv[2] = symbol->name;
  +  argv[3] = NULL;
     
  -  /* and return the sorted list of filenames */
  -  return ret;
  +  return run_source_command ( argv );
   }
   
  -/*! \brief Search for a symbol file in the component library.
  +/*! \brief Get symbol data.
    *  \par Function Description
  - *  Searches in component library for a symbol file with name <B>basename</B>.
  + *  Get the unparsed gEDA-format data corresponding to a symbol from
  + *  the symbol's data source.  The return value should be free()'d
  + *  when no longer needed.
    *
  - *  \param [in] basename  Character string with base symbol name to search for.
  - *  \return List of directories where symbol file with this name was found,
  - *          NULL otherwise.
  + *  On failure, returns \b NULL (the error will be logged).
    *
  - *  \warning
  - *  The returned value is owned by libgeda and must not be modified or freed.
  + *  \param symbol Symbol to get data for.
  + *  \return Allocated buffer containing symbol data.
  + */
  +gchar *s_clib_symbol_get_data (const CLibSymbol *symbol)
  +{
  +  g_assert (symbol != NULL);
  +
  +  switch (symbol->source->type)
  +    {
  +    case CLIB_DIR:
  +      return get_data_directory (symbol);
  +    case CLIB_CMD:
  +      return get_data_command (symbol);
  +    default:
  +      g_assert_not_reached();
  +    }
  +}
  +
  +
  +/*! \brief Find all symbols matching a glob pattern.  \par Function
  + *  Description Searches the library, returning all symbols whose
  + *  names match \a glob (see the GLib documentation for details of the
  + *  glob syntax applicable).
  + *
  + *  \warning The #CLibSymbol instances in the \b GList returned belong
  + *  to the component library, and should be considered constants; they
  + *  should not be manipulated or free()'d.  On the other hand, the \b
  + *  GList returned must be freed with \b g_list_free() when no longer
  + *  needed.  Note that the values returned will be invalidated by a
  + *  call to s_clib_free() or s_clib_refresh().
    *
  + *  \param glob The glob pattern to match against.
  + *  \return A \b GList of matching #CLibSymbol structures.
    */
  -const GSList *s_clib_search_basename(const gchar *basename)
  +GList *s_clib_glob (const gchar *glob)
   {
  -  GSList *ret; 
  -  GList *tmp;
  +  GList *sourcelist;
  +  GList *symlist;
  +  GList *result = NULL;
  +  CLibSource *source;
  +  CLibSymbol *symbol;
  +  GPatternSpec *pattern;
  +
  +  if (glob == NULL) return NULL;
  +
  +  pattern = g_pattern_spec_new(glob);
  +
  +  for (sourcelist = clib_sources; 
  +       sourcelist != NULL; 
  +       sourcelist = g_list_next(sourcelist)) {
  +
  +    source = (CLibSource *) sourcelist->data;
     
  -  /* first check if basename is in cache */
  -  ret = g_hash_table_lookup (clib_cache, basename);
  -  if (ret != NULL) {
  -    /* yes, found basename in cache, nothing more to do */
  -    return ret;
  +    for (symlist = source->symbols;
  +	 symlist != NULL;
  +	 symlist = g_list_next(symlist)) {
  +    
  +      symbol = (CLibSymbol *) symlist->data;
  +
  +      if (g_pattern_match_string (pattern, symbol->name)) {
  +	result = g_list_prepend (result, symbol);
     }
   
  -  /* looks like we have to search for basename in the library */
  -  for (tmp = g_list_last(clib_directories); 
  -       tmp != NULL; tmp = g_list_previous (tmp)) {
  -    gchar *dir_name  = (gchar*)tmp->data;
  -    gchar *file_name = g_strconcat (dir_name,
  -                                    G_DIR_SEPARATOR_S,
  -                                    basename,
  -                                    NULL);
  +    }
   
  -    if (g_file_test (file_name, G_FILE_TEST_EXISTS)) {
  -      /* add directory name to the list */
  -      ret = g_slist_append (ret, g_strdup (dir_name));
       }
   
  -    g_free (file_name);
  +  result = g_list_reverse (result);
  +
  +  g_pattern_spec_free (pattern);
  +
  +  return result;
  +}
  +
  +/*! \brief Get symbol data for a given symbol name.
  + *  \par Function Description
  + *  Return the data for the first symbol found with the given name.
  + *  This is a helper function for the schematic load system, as it
  + *  will always want to load symbols given only their name.
  + *
  + *  On failure, returns \b NULL (the error will be logged).
  + *
  + *  \todo Speed this up repeated calls by caching the #CLibSymbol
  + *  pointers found for each name requested.
  + *
  + *  \param name The symbol name to match against.
  + *  \return Allocated buffer containing symbol data.
  + */
  +gchar *s_clib_symbol_get_data_by_name (const gchar *name)
  +{
  +  GList *sourcelist;
  +  CLibSource *source;
  +  CLibSymbol *symbol;
  +
  +  for (sourcelist = clib_sources; 
  +       sourcelist != NULL; 
  +       sourcelist = g_list_next(sourcelist)) {
  +
  +    source = (CLibSource *) sourcelist->data;
  +
  +    symbol = source_has_symbol (source, name);
  +
  +    if (symbol != NULL) {
  +      return s_clib_symbol_get_data (symbol);
     }
   
  -  /* have we found something? */
  -  if (ret != NULL) {
  -    /* yes, add the result to cache */
  -    g_hash_table_insert (clib_cache, g_strdup (basename), ret);
     }
     
  -  return ret;
  +  return NULL;
   }
  
  
  
  1.15                 eda/geda/gaf/libgeda/src/s_hierarchy.c
  
  (In the diff below, changes in quantity of whitespace are not shown.)
  
  Index: s_hierarchy.c
  ===================================================================
  RCS file: /home/cvspsrv/cvsroot/eda/geda/gaf/libgeda/src/s_hierarchy.c,v
  retrieving revision 1.14
  retrieving revision 1.15
  diff -u -b -r1.14 -r1.15
  --- s_hierarchy.c	15 Jul 2006 17:00:51 -0000	1.14
  +++ s_hierarchy.c	28 May 2007 07:37:49 -0000	1.15
  @@ -214,17 +214,23 @@
    *
    */
   void s_hierarchy_down_symbol (TOPLEVEL *w_current,
  -			      const gchar *filename, PAGE *parent)
  +			      const CLibSymbol *symbol, PAGE *parent)
   {
     PAGE *page;
  +  gchar *filename;
  +
  +  filename = s_clib_symbol_get_filename (symbol);
   
     page = s_page_search (w_current, filename);
     if (page) {
       s_page_goto (w_current, page);
  +    g_free (filename);
       return;
     }
   
     page = s_page_new (w_current, filename);
  +  g_free(filename);
  +
     s_page_goto (w_current, page);
   
     f_open(w_current, page->page_filename);
  
  
  
  1.20                 eda/geda/gaf/libgeda/src/s_toplevel.c
  
  (In the diff below, changes in quantity of whitespace are not shown.)
  
  Index: s_toplevel.c
  ===================================================================
  RCS file: /home/cvspsrv/cvsroot/eda/geda/gaf/libgeda/src/s_toplevel.c,v
  retrieving revision 1.19
  retrieving revision 1.20
  diff -u -b -r1.19 -r1.20
  --- s_toplevel.c	17 Apr 2007 20:19:21 -0000	1.19
  +++ s_toplevel.c	28 May 2007 07:37:49 -0000	1.20
  @@ -93,7 +93,6 @@
     toplevel->current_visible = -1; /* not sure on these */
     toplevel->current_show    = -1;
   
  -  toplevel->internal_basename = NULL;
     toplevel->internal_clib = NULL;
     
     toplevel->RC_list = NULL;
  
  
  


_______________________________________________
geda-cvs mailing list
geda-cvs@xxxxxxxxxxxxxx
http://www.seul.org/cgi-bin/mailman/listinfo/geda-cvs