(root)/
gettext-0.22.4/
gettext-tools/
src/
search-path.c
       1  /* Routines for locating data files
       2     Copyright (C) 2016, 2019 Free Software Foundation, Inc.
       3  
       4     This file was written by Daiki Ueno <ueno@gnu.org>, 2016.
       5  
       6     This program 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; either version 3 of the License, or
       9     (at your option) any later version.
      10  
      11     This program is distributed in the hope that it will be useful,
      12     but WITHOUT ANY WARRANTY; without even the implied warranty of
      13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      14     GNU General Public License for more details.
      15  
      16     You should have received a copy of the GNU General Public License
      17     along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
      18  
      19  #ifdef HAVE_CONFIG_H
      20  # include <config.h>
      21  #endif
      22  
      23  /* Specification.  */
      24  #include "search-path.h"
      25  
      26  #include <stdlib.h>
      27  #include <string.h>
      28  
      29  #include "concat-filename.h"
      30  #include "relocatable.h"
      31  #include "xalloc.h"
      32  #include "xmemdup0.h"
      33  #include "xvasprintf.h"
      34  
      35  typedef void (* foreach_function_ty) (const char *dir, size_t len, void *data);
      36  
      37  struct path_array_ty {
      38    char **ptr;
      39    size_t len;
      40    /* Transient argument for fill().  */
      41    const char *sub;
      42  };
      43  
      44  static void
      45  foreach_elements (const char *dirs, foreach_function_ty function, void *data)
      46  {
      47    const char *start = dirs;
      48  
      49    /* Count the number of valid elements in DIRS.  */
      50    while (*start != '\0')
      51      {
      52        char *end = strchrnul (start, ':');
      53  
      54        /* Skip empty element.  */
      55        if (start != end)
      56          function (start, end - start, data);
      57  
      58        if (*end == '\0')
      59          break;
      60  
      61        start = end + 1;
      62      }
      63  }
      64  
      65  static void
      66  increment (const char *dir, size_t len, void *data)
      67  {
      68    size_t *count = data;
      69    (*count)++;
      70  }
      71  
      72  static void
      73  fill (const char *dir, size_t len, void *data)
      74  {
      75    struct path_array_ty *array = data;
      76    char *base, *name;
      77  
      78    base = xmemdup0 (dir, len);
      79    if (array->sub == NULL)
      80      name = base;
      81    else
      82      {
      83        name = xconcatenated_filename (base, array->sub, NULL);
      84        free (base);
      85      }
      86  
      87    array->ptr[array->len++] = name;
      88  }
      89  
      90  /* Find the standard search path for data files.  If SUB is not NULL, append it
      91     to each directory.
      92     Returns a freshly allocated NULL terminated list of freshly allocated
      93     strings.
      94  
      95     The order in the path is as follows:
      96  
      97     1. $GETTEXTDATADIR or GETTEXTDATADIR
      98     2. $GETTEXTDATADIRS
      99     3. $XDG_DATA_DIRS, where each element is suffixed with "gettext"
     100     4. $GETTEXTDATADIR or GETTEXTDATADIR, suffixed with PACKAGE_SUFFIX  */
     101  char **
     102  get_search_path (const char *sub)
     103  {
     104    const char *gettextdatadir;
     105    const char *gettextdatadirs;
     106    const char *xdgdatadirs;
     107    struct path_array_ty array;
     108  
     109    /* Count how many array elements are needed.  */
     110    size_t count = 2;
     111  
     112    gettextdatadirs = getenv ("GETTEXTDATADIRS");
     113    if (gettextdatadirs != NULL)
     114      foreach_elements (gettextdatadirs, increment, &count);
     115  
     116    xdgdatadirs = getenv ("XDG_DATA_DIRS");
     117    if (xdgdatadirs != NULL)
     118      foreach_elements (xdgdatadirs, increment, &count);
     119  
     120    /* Allocate the array.  */
     121    array.ptr = XCALLOC (count + 1, char *);
     122    array.len = 0;
     123  
     124    /* Fill the array.  */
     125    {
     126      gettextdatadir = getenv ("GETTEXTDATADIR");
     127      if (gettextdatadir == NULL || gettextdatadir[0] == '\0')
     128        /* Make it possible to override the locator file location.  This
     129           is necessary for running the testsuite before "make
     130           install".  */
     131        gettextdatadir = relocate (GETTEXTDATADIR);
     132  
     133      /* Append element from GETTEXTDATADIR.  */
     134      {
     135        char *name;
     136        if (sub == NULL)
     137          name = xstrdup (gettextdatadir);
     138        else
     139          name = xconcatenated_filename (gettextdatadir, sub, NULL);
     140        array.ptr[array.len++] = name;
     141      }
     142  
     143      /* Append elements from GETTEXTDATADIRS.  */
     144      if (gettextdatadirs != NULL)
     145        {
     146          array.sub = sub;
     147          foreach_elements (gettextdatadirs, fill, &array);
     148        }
     149  
     150      /* Append elements from XDG_DATA_DIRS.  Note that each element needs
     151         to have "gettext" suffix.  */
     152      if (xdgdatadirs != NULL)
     153        {
     154          char *combined_sub;
     155          if (sub == NULL)
     156            combined_sub = xstrdup ("gettext");
     157          else
     158            combined_sub = xconcatenated_filename ("gettext", sub, NULL);
     159  
     160          array.sub = combined_sub;
     161          foreach_elements (xdgdatadirs, fill, &array);
     162  
     163          free (combined_sub);
     164        }
     165  
     166      /* Append version specific directory.  */
     167      {
     168        char *base = xasprintf ("%s%s", gettextdatadir, PACKAGE_SUFFIX);
     169        char *name;
     170        if (sub == NULL)
     171          name = base;
     172        else
     173          {
     174            name = xconcatenated_filename (base, sub, NULL);
     175            free (base);
     176          }
     177        array.ptr[array.len++] = name;
     178      }
     179    }
     180  
     181    return array.ptr;
     182  }