]> git.sesse.net Git - vlc/blob - src/posix/dirs.c
Fix Metacube header handling with multiple header blocks.
[vlc] / src / posix / dirs.c
1 /*****************************************************************************
2  * dirs.c: XDG directories configuration
3  *****************************************************************************
4  * Copyright (C) 2001-2007 VLC authors and VideoLAN
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 it
10  * under the terms of the GNU Lesser General Public License as published by
11  * the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public License
20  * along with this program; if not, write to the Free Software Foundation,
21  * 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 "config/configuration.h"
32
33 #include <unistd.h>
34 #include <pwd.h>
35 #include <assert.h>
36 #include <limits.h>
37
38 #if !defined (__linux__)
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_GetDataDir (void)
45 {
46     const char *path = getenv ("VLC_DATA_PATH");
47     return strdup ((path != NULL) ? path : PKGDATADIR);
48 }
49
50 /**
51  * Determines the architecture-dependent data directory
52  *
53  * @return a string (always succeeds).
54  */
55 char *config_GetLibDir (void)
56 {
57     return strdup (PKGLIBDIR);
58 }
59 #endif
60
61 static char *config_GetHomeDir (void)
62 {
63     /* 1/ Try $HOME  */
64     const char *home = getenv ("HOME");
65     if (home != NULL)
66         return strdup (home);
67 #if defined(HAVE_GETPWUID_R)
68     /* 2/ Try /etc/passwd */
69     long max = sysconf (_SC_GETPW_R_SIZE_MAX);
70     if (max != -1)
71     {
72         char buf[max];
73         struct passwd pwbuf, *pw;
74
75         if (getpwuid_r (getuid (), &pwbuf, buf, sizeof (buf), &pw) == 0
76           && pw != NULL)
77             return strdup (pw->pw_dir);
78     }
79 #endif
80     return NULL;
81 }
82
83 static char *config_GetAppDir (const char *xdg_name, const char *xdg_default)
84 {
85     char *psz_dir;
86     char var[sizeof ("XDG__HOME") + strlen (xdg_name)];
87
88     /* XDG Base Directory Specification - Version 0.6 */
89     snprintf (var, sizeof (var), "XDG_%s_HOME", xdg_name);
90
91     const char *home = getenv (var);
92     if (home != NULL)
93     {
94         if (asprintf (&psz_dir, "%s/vlc", home) == -1)
95             psz_dir = NULL;
96         return psz_dir;
97     }
98
99     char *psz_home = config_GetHomeDir ();
100     if( psz_home == NULL
101      || asprintf( &psz_dir, "%s/%s/vlc", psz_home, xdg_default ) == -1 )
102         psz_dir = NULL;
103     free (psz_home);
104     return psz_dir;
105 }
106
107 static char *config_GetTypeDir (const char *xdg_name)
108 {
109     const size_t namelen = strlen (xdg_name);
110     const char *home = getenv ("HOME");
111     const char *dir = getenv ("XDG_CONFIG_HOME");
112     const char *file = "user-dirs.dirs";
113
114     if (home == NULL)
115         return NULL;
116     if (dir == NULL)
117     {
118         dir = home;
119         file = ".config/user-dirs.dirs";
120     }
121
122     char *path;
123     if (asprintf (&path, "%s/%s", dir, file) == -1)
124         return NULL;
125
126     FILE *stream = fopen (path, "rte");
127     free (path);
128     path = NULL;
129     if (stream != NULL)
130     {
131         char *linebuf = NULL;
132         size_t linelen = 0;
133
134         while (getline (&linebuf, &linelen, stream) != -1)
135         {
136             char *ptr = linebuf;
137             ptr += strspn (ptr, " \t"); /* Skip whites */
138             if (strncmp (ptr, "XDG_", 4))
139                 continue;
140             ptr += 4; /* Skip XDG_ */
141             if (strncmp (ptr, xdg_name, namelen))
142                 continue;
143             ptr += namelen; /* Skip XDG type name */
144             if (strncmp (ptr, "_DIR", 4))
145                 continue;
146             ptr += 4; /* Skip _DIR */
147             ptr += strspn (ptr, " \t"); /* Skip whites */
148             if (*ptr != '=')
149                 continue;
150             ptr++; /* Skip equality sign */
151             ptr += strspn (ptr, " \t"); /* Skip whites */
152             if (*ptr != '"')
153                 continue;
154             ptr++; /* Skip quote */
155             linelen -= ptr - linebuf;
156
157             char *out;
158             if (strncmp (ptr, "$HOME", 5))
159             {
160                 path = malloc (linelen);
161                 if (path == NULL)
162                     continue;
163                 out = path;
164             }
165             else
166             {   /* Prefix with $HOME */
167                 const size_t homelen = strlen (home);
168                 ptr += 5;
169                 path = malloc (homelen + linelen - 5);
170                 if (path == NULL)
171                     continue;
172                 memcpy (path, home, homelen);
173                 out = path + homelen;
174             }
175
176             while (*ptr != '"')
177             {
178                 if (*ptr == '\\')
179                     ptr++;
180                 if (*ptr == '\0')
181                 {
182                     free (path);
183                     path = NULL;
184                     break;
185                 }
186                 *(out++) = *(ptr++);
187             }
188             if (path != NULL)
189                 *out = '\0';
190             break;
191         }
192         free (linebuf);
193         fclose (stream);
194     }
195
196     /* Default! */
197     if (path == NULL)
198     {
199         if (strcmp (xdg_name, "DESKTOP") == 0)
200         {
201             if (asprintf (&path, "%s/Desktop", home) == -1)
202                 return NULL;
203         }
204         else
205             path = strdup (home);
206     }
207
208     return path;
209 }
210
211
212 char *config_GetUserDir (vlc_userdir_t type)
213 {
214     switch (type)
215     {
216         case VLC_HOME_DIR:
217             break;
218         case VLC_CONFIG_DIR:
219             return config_GetAppDir ("CONFIG", ".config");
220         case VLC_DATA_DIR:
221             return config_GetAppDir ("DATA", ".local/share");
222         case VLC_CACHE_DIR:
223             return config_GetAppDir ("CACHE", ".cache");
224
225         case VLC_DESKTOP_DIR:
226             return config_GetTypeDir ("DESKTOP");
227         case VLC_DOWNLOAD_DIR:
228             return config_GetTypeDir ("DOWNLOAD");
229         case VLC_TEMPLATES_DIR:
230             return config_GetTypeDir ("TEMPLATES");
231         case VLC_PUBLICSHARE_DIR:
232             return config_GetTypeDir ("PUBLICSHARE");
233         case VLC_DOCUMENTS_DIR:
234             return config_GetTypeDir ("DOCUMENTS");
235         case VLC_MUSIC_DIR:
236             return config_GetTypeDir ("MUSIC");
237         case VLC_PICTURES_DIR:
238             return config_GetTypeDir ("PICTURES");
239         case VLC_VIDEOS_DIR:
240             return config_GetTypeDir ("VIDEOS");
241     }
242     return config_GetHomeDir ();
243 }