libgimpprint API Reference: src/main/path.c Source File

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_8c-source.html,v 1.1.1.2 2004/12/22 23:49:05 jlovell 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 }