Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Blame | Last modification | View Log | Download | RSS feed

  1. /*
  2.  * Copyright 2010 Vincent Sanders <vince@kyllikki.org>
  3.  *
  4.  * This file is part of NetSurf, http://www.netsurf-browser.org/
  5.  *
  6.  * NetSurf is free software; you can redistribute it and/or modify
  7.  * it under the terms of the GNU General Public License as published by
  8.  * the Free Software Foundation; version 2 of the License.
  9.  *
  10.  * NetSurf is distributed in the hope that it will be useful,
  11.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13.  * GNU General Public License for more details.
  14.  *
  15.  * You should have received a copy of the GNU General Public License
  16.  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  17.  */
  18.  
  19. /** \file
  20.  * Provides utility functions for finding readable files.
  21.  *
  22.  * These functions are intended to make finding resource files more straightforward.
  23.  */
  24.  
  25. #include <sys/types.h>
  26. #include <sys/stat.h>
  27. #include <stdarg.h>
  28. #include <limits.h>
  29. #include <stdio.h>
  30. #include <stdlib.h>
  31. #include <unistd.h>
  32. #include <string.h>
  33.  
  34. #include "utils/config.h"
  35. #include "utils/filepath.h"
  36.  
  37. /** maximum number of elements in the resource vector */
  38. #define MAX_RESPATH 128
  39.  
  40. /* exported interface documented in filepath.h */
  41. char *filepath_vsfindfile(char *str, const char *format, va_list ap)
  42. {
  43.         char *realpathname;
  44.         char *pathname;
  45.         int len;
  46.  
  47.         pathname = malloc(PATH_MAX);
  48.         if (pathname == NULL)
  49.                 return NULL; /* unable to allocate memory */
  50.  
  51.         len = vsnprintf(pathname, PATH_MAX, format, ap);
  52.  
  53.         if ((len < 0) || (len >= PATH_MAX)) {
  54.                 /* error or output exceeded PATH_MAX length so
  55.                  * operation is doomed to fail.
  56.                  */
  57.                 free(pathname);
  58.                 return NULL;
  59.         }
  60.  
  61.         realpathname = realpath(pathname, str);
  62.        
  63.         free(pathname);
  64.        
  65.         if (realpathname != NULL) {
  66.                 /* sucessfully expanded pathname */
  67.                 if (access(realpathname, R_OK) != 0) {
  68.                         /* unable to read the file */
  69.                         return NULL;
  70.                 }      
  71.         }
  72.  
  73.         return realpathname;
  74. }
  75.  
  76. /* exported interface documented in filepath.h */
  77. char *filepath_sfindfile(char *str, const char *format, ...)
  78. {
  79.         va_list ap;
  80.         char *ret;
  81.  
  82.         va_start(ap, format);
  83.         ret = filepath_vsfindfile(str, format, ap);
  84.         va_end(ap);
  85.  
  86.         return ret;
  87. }
  88.  
  89. /* exported interface documented in filepath.h */
  90. char *filepath_findfile(const char *format, ...)
  91. {
  92.         char *str;
  93.         char *ret;
  94.         va_list ap;
  95.  
  96.         str = malloc(PATH_MAX);
  97.         if (str == NULL)
  98.                 return NULL; /* unable to allocate memory */
  99.  
  100.         va_start(ap, format);
  101.         ret = filepath_vsfindfile(str, format, ap);
  102.         va_end(ap);
  103.  
  104.         if (ret == NULL)
  105.                 free(str);
  106.  
  107.         return ret;
  108. }
  109.  
  110. /* exported interface documented in filepath.h */
  111. char *filepath_sfind(char **respathv, char *filepath, const char *filename)
  112. {
  113.         int respathc = 0;
  114.  
  115.         if ((respathv == NULL) || (respathv[0] == NULL) || (filepath == NULL))
  116.                 return NULL;
  117.  
  118.         while (respathv[respathc] != NULL) {
  119.                 if (filepath_sfindfile(filepath, "%s/%s", respathv[respathc], filename) != NULL) {
  120.                         return filepath;
  121.                 }
  122.  
  123.                 respathc++;
  124.         }
  125.  
  126.         return NULL;
  127. }
  128.  
  129. /* exported interface documented in filepath.h */
  130. char *filepath_find(char **respathv, const char *filename)
  131. {
  132.         char *ret;
  133.         char *filepath;
  134.  
  135.         if ((respathv == NULL) || (respathv[0] == NULL))
  136.                 return NULL;
  137.  
  138.         filepath = malloc(PATH_MAX);
  139.         if (filepath == NULL)
  140.                 return NULL;
  141.  
  142.         ret = filepath_sfind(respathv, filepath, filename);
  143.  
  144.         if (ret == NULL)
  145.                 free(filepath);
  146.  
  147.         return ret;
  148. }
  149.  
  150. /* exported interface documented in filepath.h */
  151. char *filepath_sfinddef(char **respathv, char *filepath, const char *filename, const char *def)
  152. {
  153.         char t[PATH_MAX];
  154.         char *ret;
  155.  
  156.         if ((respathv == NULL) || (respathv[0] == NULL) || (filepath == NULL))
  157.                 return NULL;
  158.  
  159.         ret = filepath_sfind(respathv, filepath, filename);
  160.  
  161.         if ((ret == NULL) && (def != NULL)) {
  162.                 /* search failed, return the path specified */
  163.                 ret = filepath;
  164.                 if (def[0] == '~') {
  165.                         snprintf(t, PATH_MAX, "%s/%s/%s", getenv("HOME"), def + 1, filename);
  166.                 } else {
  167.                         snprintf(t, PATH_MAX, "%s/%s", def, filename);
  168.                 }              
  169.                 if (realpath(t, ret) == NULL) {
  170.                         strcpy(ret, t);
  171.                 }
  172.  
  173.         }
  174.         return ret;
  175. }
  176.  
  177.  
  178. /* exported interface documented in filepath.h */
  179. char **
  180. filepath_generate(char * const *pathv, const char * const *langv)
  181. {
  182.         char **respath; /* resource paths vector */
  183.         int pathc = 0;
  184.         int langc = 0;
  185.         int respathc = 0;
  186.         struct stat dstat;
  187.         char tmppath[PATH_MAX];
  188.  
  189.         respath = calloc(MAX_RESPATH, sizeof(char *));
  190.  
  191.         while (pathv[pathc] != NULL) {
  192.                 if ((stat(pathv[pathc], &dstat) == 0) &&
  193.                     S_ISDIR(dstat.st_mode)) {
  194.                         /* path element exists and is a directory */
  195.                         langc = 0;
  196.                         while (langv[langc] != NULL) {
  197.                                 snprintf(tmppath, sizeof tmppath, "%s/%s", pathv[pathc],langv[langc]);
  198.                                 if ((stat(tmppath, &dstat) == 0) &&
  199.                                     S_ISDIR(dstat.st_mode)) {
  200.                                         /* path element exists and is a directory */
  201.                                         respath[respathc++] = strdup(tmppath);
  202.                                 }
  203.                                 langc++;
  204.                         }
  205.                         respath[respathc++] = strdup(pathv[pathc]);
  206.                 }
  207.                 pathc++;
  208.         }
  209.  
  210.         return respath;
  211. }
  212.  
  213. /* expand ${} in a string into environment variables */
  214. static char *
  215. expand_path(const char *path, int pathlen)
  216. {
  217.         char *exp;
  218.         int explen;
  219.         int cstart = -1;
  220.         int cloop = 0;
  221.         char *envv;
  222.         int envlen;
  223.         int replen; /* length of replacement */
  224.  
  225.         exp = malloc(pathlen + 1);
  226.         if (exp == NULL)
  227.                 return NULL;
  228.  
  229.         memcpy(exp, path, pathlen);
  230.         exp[pathlen] = 0;
  231.  
  232.         explen = strlen(exp);
  233.  
  234.         while (exp[cloop] != 0) {
  235.                 if ((exp[cloop] == '$') &&
  236.                     (exp[cloop + 1] == '{')) {
  237.                         cstart = cloop;
  238.                         cloop++;
  239.                 }
  240.                
  241.                 if ((cstart != -1) &&
  242.                     (exp[cloop] == '}')) {
  243.                         replen = cloop - cstart;
  244.                         exp[cloop] = 0;
  245.                         envv = getenv(exp + cstart + 2);
  246.                         if (envv == NULL) {
  247.                                 memmove(exp + cstart,
  248.                                         exp + cloop + 1,
  249.                                         explen - cloop);
  250.                                 explen -= replen;
  251.                         } else {
  252.                                 envlen = strlen(envv);
  253.                                 exp = realloc(exp, explen + envlen - replen);
  254.                                 memmove(exp + cstart + envlen,
  255.                                         exp + cloop + 1,
  256.                                         explen - cloop );
  257.                                 memmove(exp + cstart, envv, envlen);
  258.                                 explen += envlen - replen;
  259.                         }
  260.                         cloop -= replen;
  261.                         cstart = -1;
  262.                 }
  263.  
  264.                 cloop++;
  265.         }
  266.  
  267.         if (explen == 1) {
  268.                 free(exp);
  269.                 exp = NULL;
  270.         }
  271.  
  272.         return exp;
  273. }
  274.  
  275. /* exported interface documented in filepath.h */
  276. char **
  277. filepath_path_to_strvec(const char *path)
  278. {
  279.         char **strvec;
  280.         int strc = 0;
  281.         const char *estart; /* path element start */
  282.         const char *eend; /* path element end */
  283.         int elen;
  284.  
  285.         strvec = calloc(MAX_RESPATH, sizeof(char *));
  286.         if (strvec == NULL)
  287.                 return NULL;
  288.  
  289.         estart = eend = path;
  290.  
  291.         while (strc < (MAX_RESPATH - 2)) {
  292.                 while ( (*eend != 0) && (*eend != ':') )
  293.                         eend++;
  294.                 elen = eend - estart;
  295.  
  296.                 if (elen > 1) {
  297.                         /* more than an empty colon */
  298.                         strvec[strc] = expand_path(estart, elen);
  299.                         if (strvec[strc] != NULL) {
  300.                                 /* successfully expanded an element */
  301.                                 strc++;
  302.                         }
  303.                 }
  304.  
  305.                 /* skip colons */
  306.                 while (*eend == ':')
  307.                         eend++;
  308.  
  309.                 /* check for termination */
  310.                 if (*eend == 0)
  311.                         break;
  312.                
  313.                 estart = eend;
  314.         }
  315.         return strvec;
  316. }
  317.  
  318. /* exported interface documented in filepath.h */
  319. void filepath_free_strvec(char **pathv)
  320. {
  321.         free(pathv[0]);
  322.         free(pathv);
  323. }
  324.