]> git.sesse.net Git - vlc/blob - src/config/dirs_xdg.c
Use var_Inherit* instead of var_CreateGet*.
[vlc] / src / config / dirs_xdg.c
1 /*****************************************************************************
2  * dirs_xdg.c: XDG directories configuration
3  *****************************************************************************
4  * Copyright (C) 2001-2007 the VideoLAN team
5  * Copyright © 2007-2009 Rémi Denis-Courmont
6  *
7  * Authors: Gildas Bazin <gbazin@videolan.org>
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22  *****************************************************************************/
23
24 #ifdef HAVE_CONFIG_H
25 # include "config.h"
26 #endif
27
28 #include <vlc_common.h>
29
30 #include "../libvlc.h"
31 #include <vlc_charset.h>
32 #include "config/configuration.h"
33
34 #include <unistd.h>
35 #include <pwd.h>
36 #include <assert.h>
37 #include <limits.h>
38
39 /**
40  * Determines the shared data directory
41  *
42  * @return a nul-terminated string or NULL. Use free() to release it.
43  */
44 char *config_GetDataDirDefault (void)
45 {
46     return strdup (DATA_PATH);
47 }
48
49 /**
50  * Determines the architecture-dependent data directory
51  *
52  * @return a string (always succeeds).
53  */
54 const char *config_GetLibDir (void)
55 {
56     return PKGLIBDIR;
57 }
58
59 /**
60  * Determines the system configuration directory.
61  *
62  * @return a string (always succeeds).
63  */
64 const char *config_GetConfDir( void )
65 {
66     return SYSCONFDIR;
67 }
68
69 static char *config_GetHomeDir (void)
70 {
71     /* 1/ Try $HOME  */
72     const char *home = getenv ("HOME");
73 #if defined(HAVE_GETPWUID_R)
74     /* 2/ Try /etc/passwd */
75     char buf[sysconf (_SC_GETPW_R_SIZE_MAX)];
76     if (home == NULL)
77     {
78         struct passwd pw, *res;
79
80         if (!getpwuid_r (getuid (), &pw, buf, sizeof (buf), &res) && res)
81             home = pw.pw_dir;
82     }
83 #endif
84
85     return FromLocaleDup (home);
86 }
87
88 static char *config_GetAppDir (const char *xdg_name, const char *xdg_default)
89 {
90     char *psz_dir;
91     char var[sizeof ("XDG__HOME") + strlen (xdg_name)];
92
93     /* XDG Base Directory Specification - Version 0.6 */
94     snprintf (var, sizeof (var), "XDG_%s_HOME", xdg_name);
95
96     char *psz_home = FromLocale (getenv (var));
97     if( psz_home )
98     {
99         if( asprintf( &psz_dir, "%s/vlc", psz_home ) == -1 )
100             psz_dir = NULL;
101         LocaleFree (psz_home);
102         return psz_dir;
103     }
104
105     psz_home = config_GetHomeDir ();
106     if( psz_home == NULL
107      || asprintf( &psz_dir, "%s/%s/vlc", psz_home, xdg_default ) == -1 )
108         psz_dir = NULL;
109     free (psz_home);
110     return psz_dir;
111 }
112
113 static char *config_GetTypeDir (const char *xdg_name)
114 {
115     const size_t namelen = strlen (xdg_name);
116     const char *home = getenv ("HOME");
117     const size_t homelen = strlen (home);
118     const char *dir = getenv ("XDG_CONFIG_HOME");
119     const char *file = "user-dirs.dirs";
120
121     if (home == NULL)
122         return NULL;
123     if (dir == NULL)
124     {
125         dir = home;
126         file = ".config/user-dirs.dirs";
127     }
128
129     char *path;
130     if (asprintf (&path, "%s/%s", dir, file) == -1)
131         return NULL;
132
133     FILE *stream = fopen (path, "rt");
134     free (path);
135     path = NULL;
136     if (stream != NULL)
137     {
138         char *linebuf = NULL;
139         size_t linelen = 0;
140
141         while (getline (&linebuf, &linelen, stream) != -1)
142         {
143             char *ptr = linebuf;
144             ptr += strspn (ptr, " \t"); /* Skip whites */
145             if (strncmp (ptr, "XDG_", 4))
146                 continue;
147             ptr += 4; /* Skip XDG_ */
148             if (strncmp (ptr, xdg_name, namelen))
149                 continue;
150             ptr += namelen; /* Skip XDG type name */
151             if (strncmp (ptr, "_DIR", 4))
152                 continue;
153             ptr += 4; /* Skip _DIR */
154             ptr += strspn (ptr, " \t"); /* Skip whites */
155             if (*ptr != '=')
156                 continue;
157             ptr++; /* Skip equality sign */
158             ptr += strspn (ptr, " \t"); /* Skip whites */
159             if (*ptr != '"')
160                 continue;
161             ptr++; /* Skip quote */
162             linelen -= ptr - linebuf;
163
164             char *out;
165             if (strncmp (ptr, "$HOME", 5))
166             {
167                 path = malloc (linelen);
168                 if (path == NULL)
169                     continue;
170                 out = path;
171             }
172             else
173             {   /* Prefix with $HOME */
174                 ptr += 5;
175                 path = malloc (homelen + linelen - 5);
176                 if (path == NULL)
177                     continue;
178                 memcpy (path, home, homelen);
179                 out = path + homelen;
180             }
181
182             while (*ptr != '"')
183             {
184                 if (*ptr == '\\')
185                     ptr++;
186                 if (*ptr == '\0')
187                 {
188                     free (path);
189                     path = NULL;
190                     continue;
191                 }
192                 *(out++) = *(ptr++);
193             }
194             *out = '\0';
195             break;
196         }
197         free (linebuf);
198         fclose (stream);
199     }
200
201     /* Default! */
202     if (path == NULL)
203     {
204         if (strcmp (xdg_name, "DESKTOP") == 0)
205         {
206             if (asprintf (&path, "%s/Desktop", home) == -1)
207                 path = NULL;
208         }
209         else
210             path = strdup (home);
211     }
212
213     char *ret = FromLocaleDup (path);
214     free (path);
215     return ret;
216 }
217
218
219 char *config_GetUserDir (vlc_userdir_t type)
220 {
221     switch (type)
222     {
223         case VLC_HOME_DIR:
224             break;
225         case VLC_CONFIG_DIR:
226             return config_GetAppDir ("CONFIG", ".config");
227         case VLC_DATA_DIR:
228             return config_GetAppDir ("DATA", ".local/share");
229         case VLC_CACHE_DIR:
230             return config_GetAppDir ("CACHE", ".cache");
231
232         case VLC_DESKTOP_DIR:
233             return config_GetTypeDir ("DESKTOP");
234         case VLC_DOWNLOAD_DIR:
235             return config_GetTypeDir ("DOWNLOAD");
236         case VLC_TEMPLATES_DIR:
237             return config_GetTypeDir ("TEMPLATES");
238         case VLC_PUBLICSHARE_DIR:
239             return config_GetTypeDir ("PUBLICSHARE");
240         case VLC_DOCUMENTS_DIR:
241             return config_GetTypeDir ("DOCUMENTS");
242         case VLC_MUSIC_DIR:
243             return config_GetTypeDir ("MUSIC");
244         case VLC_PICTURES_DIR:
245             return config_GetTypeDir ("PICTURES");
246         case VLC_VIDEOS_DIR:
247             return config_GetTypeDir ("VIDEOS");
248     }
249     return config_GetHomeDir ();
250 }