/* gEDA - GPL Electronic Design Automation
* libgeda - gEDA's library
* Copyright (C) 1998-2000 Ales V. Hvezda
*
* 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
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* 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
* clib stands for component library.
*
* A component library is made of several directories gathering
* component files.
*
* 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
#include
#ifdef HAVE_STRING_H
#include
#endif
#ifdef HAVE_LIBDMALLOC
#include
#endif
#include "defines.h"
void s_clib_free (void);
static GList *clib_directories = NULL;
static GHashTable *clib_cache = NULL;
/*! \brief Initializes the component library handling code.
* \par Function Description
* Initializes the component library handling code.
* \warning This function must be called before any other function
* of this file.
*/
void s_clib_init (void)
{
if (clib_directories != NULL || clib_cache != NULL) {
s_clib_free ();
}
clib_cache = g_hash_table_new (g_str_hash, g_str_equal);
}
/*! \todo Finish function documentation!!!
* \brief
* \par Function Description
*
*/
static void clib_free_cache_entry (gpointer key, gpointer value,
gpointer user_data)
{
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);
}
}
/*! \brief Frees memory used by the component library.
* \par Function Description
* Frees memory used by the component library.
*/
void s_clib_free (void)
{
if (clib_directories != NULL) {
g_list_foreach (clib_directories, (GFunc)g_free, NULL);
g_list_free (clib_directories);
clib_directories = NULL;
}
if (clib_cache != NULL) {
g_hash_table_foreach (clib_cache, clib_free_cache_entry, NULL);
g_hash_table_destroy (clib_cache);
clib_cache = NULL;
}
}
/*! \brief Adds a new directory to the component library.
* \par Function Description
* Adds directory as a new directory for the component library.
*
* \param [in] directory Character string with the new directory name.
*/
void s_clib_add_directory (const gchar *directory)
{
/* 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));
}
}
/*! \brief Get list of component library directories.
* \par Function Description
* This function returns the list of directories part of
* the component library.
*
* \return Global libgead #clib_directories variable.
* \warning
* The returned value is owned by libgeda and must not be modified or freed.
*
*/
const GList *s_clib_get_directories()
{
return clib_directories;
}
/*! \brief Get a list of files found a directory.
* \par Function Description
* This function returns a list of file names found in directory and
* that match filter
*
* \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 filter, NULL otherwise.
*/
GSList *s_clib_get_files (const gchar *directory, const gchar *filter)
{
GDir *dir;
const gchar *entry;
GSList *ret = NULL;
/* 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);
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);
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;
}
/* identify filter-matching filenames */
if (strstr (entry, filter)) {
ret = g_slist_append (ret, (gpointer)g_strdup (entry));
}
}
/* finished: close the directory stream */
g_dir_close (dir);
/* sort the list alphabetically */
ret = g_slist_sort (ret, (GCompareFunc)g_strcasecmp);
/* and return the sorted list of filenames */
return ret;
}
/*! \brief Search for a symbol file in the component library.
* \par Function Description
* Searches in component library for a symbol file with name basename.
*
* \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.
*
* \warning
* The returned value is owned by libgeda and must not be modified or freed.
*
*/
const GSList *s_clib_search_basename(const gchar *basename)
{
GSList *ret;
GList *tmp;
/* 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;
}
/* 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);
}
/* 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;
}