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
7 * Authors: Gildas Bazin <gbazin@videolan.org>
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.
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.
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 *****************************************************************************/
28 #include <vlc_common.h>
30 #include "../libvlc.h"
31 #include "config/configuration.h"
39 * Determines the architecture-dependent data directory
41 * @return a string (always succeeds).
43 VLC_WEAK
char *config_GetLibDir(void)
45 return strdup(LIBDIR
);
48 char *config_GetSysPath(vlc_sysdir_t type
, const char *filename
)
50 static const char env_vars
[][16] = {
51 [VLC_PKG_DATA_DIR
] = "VLC_DATA_PATH",
52 [VLC_PKG_LIB_DIR
] = "VLC_LIB_PATH",
53 [VLC_PKG_LIBEXEC_DIR
] = "VLC_LIB_PATH",
56 if (type
< ARRAY_SIZE(env_vars
)) {
57 const char *name
= env_vars
[type
];
59 const char *value
= getenv(name
);
61 const char *fmt
= (filename
!= NULL
) ? "%s/%s" : "%s";
64 if (unlikely(asprintf(&filepath
, fmt
, value
, filename
) == -1))
71 char *libdir
= config_GetLibDir();
73 return NULL
; /* OOM */
75 static const char *const dirs
[] = {
76 [VLC_PKG_DATA_DIR
] = PKGDATADIR
,
77 [VLC_PKG_LIB_DIR
] = PKGLIBDIR
,
78 [VLC_PKG_LIBEXEC_DIR
] = PKGLIBEXECDIR
,
79 [VLC_SYSDATA_DIR
] = SYSDATADIR
,
80 [VLC_LIB_DIR
] = LIBDIR
,
81 [VLC_LIBEXEC_DIR
] = LIBEXECDIR
,
82 [VLC_LOCALE_DIR
] = LOCALEDIR
,
84 assert(type
< ARRAY_SIZE(dirs
));
86 const char *dir_static
= dirs
[type
];
87 assert(*dir_static
!= '\0');
88 /* Look for common static prefix. */
89 size_t prefix_len
= 0;
90 while (prefix_len
< strlen(LIBDIR
)
91 && LIBDIR
[prefix_len
] == dir_static
[prefix_len
])
94 /* Check that suffix matches between static and dynamic libdir paths. */
95 char *filepath
= NULL
;
96 size_t suffix_len
= strlen(LIBDIR
) - prefix_len
;
97 size_t libdir_len
= strlen(libdir
);
99 if (suffix_len
> libdir_len
100 || memcmp(LIBDIR
+ prefix_len
, libdir
+ (libdir_len
- suffix_len
),
102 suffix_len
= libdir_len
;
106 /* Graft non-common static suffix to dynamically computed common prefix. */
107 const char *fmt
= (filename
!= NULL
) ? "%.*s%s/%s" : "%.*s%s";
109 if (unlikely(asprintf(&filepath
, fmt
, (int)(libdir_len
- suffix_len
),
110 libdir
, dir_static
+ prefix_len
, filename
) == -1))
117 static char *config_GetHomeDir (void)
120 const char *home
= getenv ("HOME");
122 return strdup (home
);
123 #if defined(HAVE_GETPWUID_R)
124 /* 2/ Try /etc/passwd */
125 long max
= sysconf (_SC_GETPW_R_SIZE_MAX
);
129 struct passwd pwbuf
, *pw
;
131 if (getpwuid_r (getuid (), &pwbuf
, buf
, sizeof (buf
), &pw
) == 0
133 return strdup (pw
->pw_dir
);
139 static char *config_GetAppDir (const char *xdg_name
, const char *xdg_default
)
142 char var
[sizeof ("XDG__HOME") + strlen (xdg_name
)];
144 /* XDG Base Directory Specification - Version 0.6 */
145 snprintf (var
, sizeof (var
), "XDG_%s_HOME", xdg_name
);
147 const char *home
= getenv (var
);
150 if (asprintf (&psz_dir
, "%s/vlc", home
) == -1)
155 char *psz_home
= config_GetHomeDir ();
157 || asprintf( &psz_dir
, "%s/%s/vlc", psz_home
, xdg_default
) == -1 )
163 static char *config_GetTypeDir (const char *xdg_name
)
165 const size_t namelen
= strlen (xdg_name
);
166 const char *home
= getenv ("HOME");
167 const char *dir
= getenv ("XDG_CONFIG_HOME");
168 const char *file
= "user-dirs.dirs";
175 file
= ".config/user-dirs.dirs";
179 if (asprintf (&path
, "%s/%s", dir
, file
) == -1)
182 FILE *stream
= fopen (path
, "rte");
187 char *linebuf
= NULL
;
190 while (getline (&linebuf
, &linelen
, stream
) != -1)
193 ptr
+= strspn (ptr
, " \t"); /* Skip whites */
194 if (strncmp (ptr
, "XDG_", 4))
196 ptr
+= 4; /* Skip XDG_ */
197 if (strncmp (ptr
, xdg_name
, namelen
))
199 ptr
+= namelen
; /* Skip XDG type name */
200 if (strncmp (ptr
, "_DIR", 4))
202 ptr
+= 4; /* Skip _DIR */
203 ptr
+= strspn (ptr
, " \t"); /* Skip whites */
206 ptr
++; /* Skip equality sign */
207 ptr
+= strspn (ptr
, " \t"); /* Skip whites */
210 ptr
++; /* Skip quote */
211 linelen
-= ptr
- linebuf
;
214 if (strncmp (ptr
, "$HOME", 5))
216 path
= malloc (linelen
);
222 { /* Prefix with $HOME */
223 const size_t homelen
= strlen (home
);
225 path
= malloc (homelen
+ linelen
- 5);
228 memcpy (path
, home
, homelen
);
229 out
= path
+ homelen
;
255 if (strcmp (xdg_name
, "DESKTOP") == 0)
257 if (asprintf (&path
, "%s/Desktop", home
) == -1)
261 path
= strdup (home
);
268 char *config_GetUserDir (vlc_userdir_t type
)
275 return config_GetAppDir ("CONFIG", ".config");
276 case VLC_USERDATA_DIR
:
277 return config_GetAppDir ("DATA", ".local/share");
279 return config_GetAppDir ("CACHE", ".cache");
281 case VLC_DESKTOP_DIR
:
282 return config_GetTypeDir ("DESKTOP");
283 case VLC_DOWNLOAD_DIR
:
284 return config_GetTypeDir ("DOWNLOAD");
285 case VLC_TEMPLATES_DIR
:
286 return config_GetTypeDir ("TEMPLATES");
287 case VLC_PUBLICSHARE_DIR
:
288 return config_GetTypeDir ("PUBLICSHARE");
289 case VLC_DOCUMENTS_DIR
:
290 return config_GetTypeDir ("DOCUMENTS");
292 return config_GetTypeDir ("MUSIC");
293 case VLC_PICTURES_DIR
:
294 return config_GetTypeDir ("PICTURES");
296 return config_GetTypeDir ("VIDEOS");
298 return config_GetHomeDir ();