Beispiel #1
0
/*! \brief Initialise the component library.
 *  \par Function Description
 *  Resets and initialises the component library.
 *
 *  \warning This function must be called before any other functions
 *  from s_clib.c.
 */
void s_clib_init ()
{
  if (clib_sources != NULL) {
    s_clib_free ();
  }

  if (clib_search_cache != NULL) {
    s_clib_flush_search_cache();
  } else {
    clib_search_cache = g_hash_table_new_full ((GHashFunc) g_str_hash,
                                               (GEqualFunc)g_str_equal,
                                               (GDestroyNotify) g_free,
                                               (GDestroyNotify) g_list_free);
  }

  if (clib_symbol_cache != NULL) {
    s_clib_flush_symbol_cache();
  } else {
    clib_symbol_cache =
      g_hash_table_new_full ((GHashFunc) g_direct_hash,
                             (GEqualFunc) g_direct_equal,
                             NULL,
                             (GDestroyNotify) free_symbol_cache_entry);
  }
}
Beispiel #2
0
/*! \brief Re-poll a library command for symbols.
 *  \par Function Description
 *  Runs a library command, requesting a list of available symbols,
 *  and updates the source with the new list.
 *
 *  Private function used only in s_clib.c.
 */
static void refresh_command (CLibSource *source)
{
  gchar *cmdout;
  TextBuffer *tb;
  const gchar *line;
  CLibSymbol *symbol;
  gchar *name;

  g_return_if_fail (source != NULL);
  g_return_if_fail (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 */
  cmdout = run_source_command (source->list_cmd);
  if (cmdout == NULL) return;

  /* Use a TextBuffer to help reading out the lines of the output */
  tb = s_textbuffer_new (cmdout, -1, "s_clib.c::refresh_command()");

  while (1) {
    line = s_textbuffer_next_line (tb);
    if (line == NULL) break;
    if (line[0] == '.') continue;  /* TODO is this sane? */

    name = geda_string_get_first_line (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 and it doesn't matter what order we
     * add them. */
    source->symbols = g_list_prepend (source->symbols, symbol);
  }

  s_textbuffer_free (tb);
  g_free (cmdout);

  /* Sort all symbols by name. */
  source->symbols = g_list_sort (source->symbols,
				 (GCompareFunc) compare_symbol_name);

  s_clib_flush_search_cache();
  s_clib_flush_symbol_cache();
}
Beispiel #3
0
/*! \brief Re-poll a scheme procedure for symbols.
 *  \par Function Description
 *  Calls a Scheme procedure to obtain a list of available symbols,
 *  and updates the source with the new list
 *
 *  Private function used only in s_clib.c.
 */
static void refresh_scm (CLibSource *source)
{
  SCM symlist;
  SCM symname;
  CLibSymbol *symbol;
  char *tmp;

  g_return_if_fail (source != NULL);
  g_return_if_fail (source->type == CLIB_SCM);

  /* Clear the current symbol list */
  g_list_foreach (source->symbols, (GFunc) free_symbol, NULL);
  g_list_free (source->symbols);
  source->symbols = NULL;

  symlist = scm_call_0 (source->list_fn);

  if (scm_is_false (scm_list_p (symlist))) {
    s_log_message (_("Failed to scan library [%1$s]: Scheme function returned non-list."),
		   source->name);
    return;
  }

  while (!scm_is_null (symlist)) {
    symname = SCM_CAR (symlist);
    if (!scm_is_string (symname)) {
      s_log_message (_("Non-string symbol name while scanning library [%1$s]"),
		     source->name);
    } else {
      symbol = g_new0 (CLibSymbol, 1);
      symbol->source = source;

      /* Need to make sure that the correct free() function is called
       * on strings allocated by Guile. */
      tmp = scm_to_utf8_string (symname);
      symbol->name = g_strdup(tmp);
      free (tmp);

      /* Prepend because it's faster and it doesn't matter what order we
       * add them. */
      source->symbols = g_list_prepend (source->symbols, symbol);
    }

    symlist = SCM_CDR (symlist);
  }

  /* Now sort the list of symbols by name. */
  source->symbols = g_list_sort (source->symbols,
				 (GCompareFunc) compare_symbol_name);

  s_clib_flush_search_cache();
  s_clib_flush_symbol_cache();
}
Beispiel #4
0
/*! \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 *low_entry;
  gchar *fullpath;
  gboolean isfile;
  GError *e = NULL;

  g_return_if_fail (source != NULL);
  g_return_if_fail (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->directory, 0, &e);

  if (e != NULL) {
    s_log_message (_("Failed to open directory [%1$s]: %2$s"),
		   source->directory, 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->directory, entry, NULL);
    isfile = g_file_test (fullpath, G_FILE_TEST_IS_REGULAR);
    g_free (fullpath);
    if (!isfile) continue;

    /* skip filenames that we already know about. */
    if (source_has_symbol (source, entry) != NULL) continue;

    /* skip filenames which don't have the right suffix. */
    low_entry = g_utf8_strdown (entry, -1);
    if (!g_str_has_suffix (low_entry, SYM_FILENAME_FILTER)) {
      g_free (low_entry);
      continue;
    }
    g_free (low_entry);

    /* Create and add new symbol record */
    symbol = g_new0 (CLibSymbol, 1);
    symbol->source = source;
    symbol->name = g_strdup(entry);

    /* Prepend because it's faster and it doesn't matter what order we
     * add them. */
    source->symbols = g_list_prepend (source->symbols, symbol);
  }

  entry = NULL;
  g_dir_close (dir);

  /* Now sort the list of symbols by name. */
  source->symbols = g_list_sort (source->symbols,
				 (GCompareFunc) compare_symbol_name);

  s_clib_flush_search_cache();
  s_clib_flush_symbol_cache();
}
Beispiel #5
0
/*! \brief Update a component.
 *
 * \par Function Description
 * Updates \a o_current to the latest version of the symbol available
 * in the symbol library, while preserving any attributes set in the
 * current schematic. On success, returns the new OBJECT which
 * replaces \a o_current on the page; \a o_current is deleted. On
 * failure, returns NULL, and \a o_current is left unchanged.
 *
 * \param [in]     w_current The GSCHEM_TOPLEVEL object.
 * \param [in,out] o_current The OBJECT to be updated.
 *
 * \return the new OBJECT that replaces \a o_current.
 */
OBJECT *
o_update_component (GSCHEM_TOPLEVEL *w_current, OBJECT *o_current)
{
  TOPLEVEL *toplevel = w_current->toplevel;
  OBJECT *o_new;
  PAGE *page;
  GList *new_attribs;
  GList *old_attribs;
  GList *iter;
  const CLibSymbol *clib;

  g_return_val_if_fail (o_current != NULL, NULL);
  g_return_val_if_fail (o_current->type == OBJ_COMPLEX, NULL);
  g_return_val_if_fail (o_current->complex_basename != NULL, NULL);

  page = o_get_page (toplevel, o_current);

  /* This should be replaced with API to invalidate only the specific
   * symbol name we want to update */
  s_clib_flush_symbol_cache ();
  clib = s_clib_get_symbol_by_name (o_current->complex_basename);

  if (clib == NULL) {
    s_log_message (_("Could not find symbol [%s] in library. Update failed.\n"),
                   o_current->complex_basename);
    return NULL;
  }

  /* Unselect the old object. */
  o_selection_remove (toplevel, page->selection_list, o_current);

  /* Create new object and set embedded */
  o_new = o_complex_new (toplevel, OBJ_COMPLEX, DEFAULT_COLOR,
                         o_current->complex->x,
                         o_current->complex->y,
                         o_current->complex->angle,
                         o_current->complex->mirror,
                         clib, o_current->complex_basename,
                         1);
  if (o_complex_is_embedded (o_current)) {
    o_embed (toplevel, o_new);
  }

  new_attribs = o_complex_promote_attribs (toplevel, o_new);

  /* Cull any attributes from new COMPLEX that are already attached to
   * old COMPLEX. Note that the new_attribs list is kept consistent by
   * setting GList data pointers to NULL if their OBJECTs are
   * culled. At the end, the new_attribs list is updated by removing
   * all list items with NULL data. This is slightly magic, but
   * works. */
  for (iter = new_attribs; iter != NULL; iter = g_list_next (iter)) {
    OBJECT *attr_new = iter->data;
    gchar *name;
    gchar *value;

    g_assert (attr_new->type == OBJ_TEXT);

    o_attrib_get_name_value (attr_new, &name, NULL);

    value = o_attrib_search_attached_attribs_by_name (o_current, name, 0);
    if (value != NULL) {
      o_attrib_remove (toplevel, &o_new->attribs, attr_new);
      s_delete_object (toplevel, attr_new);
      iter->data = NULL;
    }

    g_free (name);
    g_free (value);
  }
  new_attribs = g_list_remove_all (new_attribs, NULL);

  /* Detach attributes from old OBJECT and attach to new OBJECT */
  old_attribs = g_list_copy (o_current->attribs);
  o_attrib_detach_all (toplevel, o_current);
  o_attrib_attach_list (toplevel, old_attribs, o_new, 1);
  g_list_free (old_attribs);

  /* Add new attributes to page */
  s_page_append_list (toplevel, page, new_attribs);

  /* Update pinnumbers for current slot */
  s_slot_update_object (toplevel, o_new);

  /* Replace old OBJECT with new OBJECT */
  s_page_replace (toplevel, page, o_current, o_new);
  s_delete_object (toplevel, o_current);

  /* Select new OBJECT */
  o_selection_add (toplevel, page->selection_list, o_new);

  /* mark the page as modified */
  toplevel->page_current->CHANGED = 1;
  o_undo_savestate (w_current, UNDO_ALL);

  return o_new;
}