Main Page | Modules | Alphabetical List | Data Structures | File List | Data Fields | Globals | Related Pages

src/main/path.c

Go to the documentation of this file.
00001 /*
00002  * "$Id: path.c,v 1.16 2004/08/15 19:58:08 rlk Exp $"
00003  *
00004  *   libgimpprint path functions - split and search paths.
00005  *
00006  *   Copyright 2002 Roger Leigh (rleigh@debian.org)
00007  *
00008  *   This program is free software; you can redistribute it and/or modify it
00009  *   under the terms of the GNU General Public License as published by the Free
00010  *   Software Foundation; either version 2 of the License, or (at your option)
00011  *   any later version.
00012  *
00013  *   This program is distributed in the hope that it will be useful, but
00014  *   WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
00015  *   or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
00016  *   for more details.
00017  *
00018  *   You should have received a copy of the GNU General Public License
00019  *   along with this program; if not, write to the Free Software
00020  *   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
00021  */
00022 
00023 #include <gimp-print/gimp-print.h>
00024 #include "gimp-print-internal.h"
00025 #include <gimp-print/gimp-print-intl-internal.h>
00026 #include <stdio.h>
00027 #include <stdlib.h>
00028 #include <string.h>
00029 #include <errno.h>
00030 #include <dirent.h>
00031 #include <sys/types.h>
00032 #include <sys/stat.h>
00033 #include <unistd.h>
00034 
00035 static int stpi_path_check(const struct dirent *module);
00036 static char *stpi_path_merge(const char *path,
00037                              const char *file);
00038 static int stpi_scandir (const char *dir,
00039                          struct dirent ***namelist,
00040                          int (*sel) (const struct dirent *),
00041                          int (*cmp) (const void *, const void *));
00042 
00043 /* WARNING: This is not thread safe! -- rlk 20030721 */
00044 static const char *path_check_path;   /* Path for stpi_scandir() callback */
00045 static const char *path_check_suffix; /* Suffix for stpi_scandir() callback */
00046 
00047 
00048 static int
00049 dirent_sort(const void *a,
00050             const void *b)
00051 {
00052   return strcoll ((*(const struct dirent **) a)->d_name,
00053                   (*(const struct dirent **) b)->d_name);
00054 }
00055 
00056 
00057 /*
00058  * Make a list of all modules in the search path.
00059  */
00060 stp_list_t *
00061 stp_path_search(stp_list_t *dirlist, /* List of directories to search */
00062                 const char *suffix)  /* Required filename suffix */
00063 {
00064   stp_list_t *findlist;              /* List of files to return */
00065   stp_list_item_t *diritem;          /* Current directory */
00066   struct dirent** module_dir;        /* Current directory contents */
00067   char *module_name;                 /* File name to check */
00068   int n;                             /* Number of directory entries */
00069 
00070   if (!dirlist)
00071     return NULL;
00072 
00073   path_check_suffix = suffix;
00074 
00075   findlist = stp_list_create();
00076   if (!findlist)
00077     return NULL;
00078   stp_list_set_freefunc(findlist, stp_list_node_free_data);
00079 
00080   diritem = stp_list_get_start(dirlist);
00081   while (diritem)
00082     {
00083       path_check_path = (const char *) stp_list_item_get_data(diritem);
00084       stp_deprintf(STP_DBG_PATH, "stp-path: directory: %s\n",
00085                    (const char *) stp_list_item_get_data(diritem));
00086       n = stpi_scandir ((const char *) stp_list_item_get_data(diritem),
00087                         &module_dir, stpi_path_check, dirent_sort);
00088       if (n >= 0)
00089         {
00090           int idx;
00091           for (idx = 0; idx < n; ++idx)
00092             {
00093               module_name = stpi_path_merge((const char *) stp_list_item_get_data(diritem),
00094                                            module_dir[idx]->d_name);
00095               stp_list_item_create(findlist, NULL, module_name);
00096               free (module_dir[idx]); /* Must use plain free() */
00097             }
00098           free (module_dir); /* Must use plain free() */
00099         }
00100       diritem = stp_list_item_next(diritem);
00101     }
00102   return findlist;
00103 }
00104 
00105 
00106 /*
00107  * stpi_scandir() callback.  Check the filename is sane, has the
00108  * correct mode bits and suffix.
00109  */
00110 static int
00111 stpi_path_check(const struct dirent *module) /* File to check */
00112 {
00113   int namelen;                              /* Filename length */
00114   int status = 0;                           /* Error status */
00115   int savederr;                             /* Saved errno */
00116   char *filename;                           /* Filename */
00117   struct stat modstat;                      /* stat() output */
00118 
00119   savederr = errno; /* since we are a callback, preserve
00120                        stpi_scandir() state */
00121 
00122   filename = stpi_path_merge(path_check_path, module->d_name);
00123 
00124   namelen = strlen(filename);
00125   /* make sure we can take off suffix (e.g. .la)
00126      and still have a sane filename */
00127   if (namelen >= strlen(path_check_suffix) + 1) 
00128     {
00129       if (!stat (filename, &modstat))
00130         {
00131           /* check file exists, and is a regular file */
00132           if (S_ISREG(modstat.st_mode))
00133             status = 1;
00134           if (strncmp(filename + (namelen - strlen(path_check_suffix)),
00135                       path_check_suffix,
00136                       strlen(path_check_suffix)))
00137             {
00138               status = 0;
00139             }
00140         }
00141     }
00142 
00143   if (status)
00144     stp_deprintf(STP_DBG_PATH, "stp-path: file: `%s'\n", filename);
00145 
00146   stp_free(filename);
00147   filename = NULL;
00148 
00149   errno = savederr;
00150   return status;
00151 }
00152 
00153 
00154 /*
00155  * Join a path and filename together.
00156  */
00157 static char *
00158 stpi_path_merge(const char *path, /* Path */
00159                const char *file) /* Filename */
00160 {
00161   char *filename;                /* Filename to return */
00162   int namelen = strlen(path) + strlen(file) + 2;
00163   filename = (char *) stp_malloc(namelen * sizeof(char));
00164   strcpy (filename, path);
00165   strcat (filename, "/");
00166   strcat (filename, file);
00167   filename[namelen - 1] = '\0';
00168   return filename;
00169 }
00170 
00171 
00172 /*
00173  * Split a PATH-type string (colon-delimited) into separate
00174  * directories.
00175  */
00176 void
00177 stp_path_split(stp_list_t *list, /* List to add directories to */
00178                const char *path) /* Path to split */
00179 {
00180   const char *start = path;      /* Start of path name */
00181   const char *end = NULL;        /* End of path name */
00182   char *dir = NULL;              /* Path name */
00183   int len;                       /* Length of path name */
00184 
00185   while (start)
00186     {
00187       end = (const char *) strchr(start, ':');
00188       if (!end)
00189         len = strlen(start) + 1;
00190       else
00191         len = (end - start);
00192 
00193       if (len && !(len == 1 && !end))
00194         {
00195           dir = (char *) stp_malloc(len + 1);
00196           strncpy(dir, start, len);
00197           dir[len] = '\0';
00198           stp_list_item_create(list, NULL, dir);
00199         }
00200       if (!end)
00201         {
00202           start = NULL;
00203           break;
00204         }
00205       start = end + 1;
00206     }
00207 }
00208 
00209 /* Adapted from GNU libc <dirent.h>
00210    These macros extract size information from a `struct dirent *'.
00211    They may evaluate their argument multiple times, so it must not
00212    have side effects.  Each of these may involve a relatively costly
00213    call to `strlen' on some systems, so these values should be cached.
00214 
00215    _D_EXACT_NAMLEN (DP) returns the length of DP->d_name, not including
00216    its terminating null character.
00217 
00218    _D_ALLOC_NAMLEN (DP) returns a size at least (_D_EXACT_NAMLEN (DP) + 1);
00219    that is, the allocation size needed to hold the DP->d_name string.
00220    Use this macro when you don't need the exact length, just an upper bound.
00221    This macro is less likely to require calling `strlen' than _D_EXACT_NAMLEN.
00222    */
00223 
00224 #ifdef _DIRENT_HAVE_D_NAMLEN
00225 # ifndef _D_EXACT_NAMLEN
00226 #  define _D_EXACT_NAMLEN(d) ((d)->d_namlen)
00227 # endif
00228 # ifndef _D_ALLOC_NAMLEN
00229 #  define _D_ALLOC_NAMLEN(d) (_D_EXACT_NAMLEN (d) + 1)
00230 # endif
00231 #else
00232 # ifndef _D_EXACT_NAMLEN
00233 #  define _D_EXACT_NAMLEN(d) (strlen ((d)->d_name))
00234 # endif
00235 # ifndef _D_ALLOC_NAMLEN
00236 #  ifdef _DIRENT_HAVE_D_RECLEN
00237 #   define _D_ALLOC_NAMLEN(d) (((char *) (d) + (d)->d_reclen) - &(d)->d_name[0])
00238 #  else
00239 #   define _D_ALLOC_NAMLEN(d) (sizeof (d)->d_name > 1 ? sizeof (d)->d_name : \
00240                                _D_EXACT_NAMLEN (d) + 1)
00241 #  endif
00242 # endif
00243 #endif
00244 
00245 /*
00246  * BSD scandir() replacement, from glibc
00247  */
00248 static int
00249 stpi_scandir (const char *dir,
00250               struct dirent ***namelist,
00251               int (*sel) (const struct dirent *),
00252               int (*cmp) (const void *, const void *))
00253 {
00254   DIR *dp = opendir (dir);
00255   struct dirent **v = NULL;
00256   size_t vsize = 0, i;
00257   struct dirent *d;
00258   int save;
00259 
00260   if (dp == NULL)
00261     return -1;
00262 
00263   save = errno;
00264   errno = 0;
00265 
00266   i = 0;
00267   while ((d = readdir (dp)) != NULL)
00268     if (sel == NULL || (*sel) (d))
00269       {
00270         struct dirent *vnew;
00271         size_t dsize;
00272 
00273         /* Ignore errors from sel or readdir */
00274         errno = 0;
00275 
00276         if (i == vsize)
00277           {
00278             struct dirent **new;
00279             if (vsize == 0)
00280               vsize = 10;
00281             else
00282               vsize *= 2;
00283             new = (struct dirent **) realloc (v, vsize * sizeof (*v));
00284             if (new == NULL)
00285               break;
00286             v = new;
00287           }
00288 
00289         dsize = &d->d_name[_D_ALLOC_NAMLEN (d)] - (char *) d;
00290         vnew = (struct dirent *) malloc (dsize);
00291         if (vnew == NULL)
00292           break;
00293 
00294         v[i++] = (struct dirent *) memcpy (vnew, d, dsize);
00295       }
00296 
00297   if (errno != 0)
00298     {
00299       save = errno;
00300 
00301       while (i > 0)
00302         free (v[--i]);
00303       free (v);
00304 
00305       i = -1;
00306     }
00307   else
00308     {
00309       /* Sort the list if we have a comparison function to sort with.  */
00310       if (cmp != NULL)
00311         qsort (v, i, sizeof (*v), cmp);
00312 
00313       *namelist = v;
00314     }
00315 
00316   (void) closedir (dp);
00317   errno = save;
00318 
00319   return i;
00320 }

Generated on Wed Aug 25 07:56:14 2004 for libgimpprint API Reference by doxygen 1.3.6