00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026 #include <dirent.h>
00027 #include <limits.h>
00028 #include <unistd.h>
00029
00030 #ifdef _WIN32
00031 #include <windows.h>
00032 #endif
00033
00034 #ifdef HAVE_CONFIG_H
00035 # include "config.h"
00036 #endif
00037
00038 #include <glib.h>
00039 #include <stdlib.h>
00040 #include <string.h>
00041 #include <ctype.h>
00042
00043 #include <errno.h>
00044
00045 #ifdef HAVE_FTS_H
00046 # include <sys/types.h>
00047 # include <sys/stat.h>
00048 # include <fts.h>
00049 #endif
00050
00051 #include <libaudcore/audstrings.h>
00052 #include <libaudcore/stringpool.h>
00053
00054 #include "audconfig.h"
00055 #include "debug.h"
00056 #include "i18n.h"
00057 #include "misc.h"
00058 #include "plugins.h"
00059 #include "util.h"
00060
00061 gboolean dir_foreach (const gchar * path, DirForeachFunc func, void * user)
00062 {
00063 DIR * dir = opendir (path);
00064 if (! dir)
00065 return FALSE;
00066
00067 gchar full[PATH_MAX];
00068 gint len = snprintf (full, sizeof full, "%s" G_DIR_SEPARATOR_S, path);
00069
00070 struct dirent * entry;
00071 while ((entry = readdir (dir)))
00072 {
00073 if (entry->d_name[0] == '.')
00074 continue;
00075
00076 snprintf (full + len, sizeof full - len, "%s", entry->d_name);
00077
00078 if (func (full, entry->d_name, user))
00079 break;
00080 }
00081
00082 closedir (dir);
00083 return TRUE;
00084 }
00085
00094 gchar*
00095 util_get_localdir(void)
00096 {
00097 gchar *datadir;
00098 gchar *tmp;
00099
00100 if ( (tmp = getenv("XDG_CONFIG_HOME")) == NULL )
00101 datadir = g_build_filename( g_get_home_dir() , ".config" , "audacious" , NULL );
00102 else
00103 datadir = g_build_filename( tmp , "audacious" , NULL );
00104
00105 return datadir;
00106 }
00107
00108
00109 gchar * construct_uri (const gchar * string, const gchar * playlist_name)
00110 {
00111 gchar *filename = g_strdup(string);
00112 gchar *uri = NULL;
00113
00114
00115 convert_dos_path(filename);
00116
00117
00118
00119 if (filename[0] == '/' || strstr(filename, "://")) {
00120 uri = g_filename_to_uri(filename, NULL, NULL);
00121 if(!uri)
00122 uri = g_strdup(filename);
00123 }
00124
00125
00126 else
00127 {
00128 const gchar * slash = strrchr (playlist_name, '/');
00129 if (slash)
00130 uri = g_strdup_printf ("%.*s/%s", (gint) (slash - playlist_name),
00131 playlist_name, filename);
00132 }
00133
00134 g_free (filename);
00135 return uri;
00136 }
00137
00138
00139 gint file_get_mtime (const gchar * filename)
00140 {
00141 struct stat info;
00142
00143 if (stat (filename, & info))
00144 return -1;
00145
00146 return info.st_mtime;
00147 }
00148
00149 void
00150 make_directory(const gchar * path, mode_t mode)
00151 {
00152 if (g_mkdir_with_parents(path, mode) == 0)
00153 return;
00154
00155 g_printerr(_("Could not create directory (%s): %s\n"), path,
00156 g_strerror(errno));
00157 }
00158
00159 gchar * get_path_to_self (void)
00160 {
00161 gchar buf[PATH_MAX];
00162 gint len;
00163
00164 #ifdef _WIN32
00165 if (! (len = GetModuleFileName (NULL, buf, sizeof buf)) || len == sizeof buf)
00166 {
00167 fprintf (stderr, "GetModuleFileName failed.\n");
00168 return NULL;
00169 }
00170 #else
00171 if ((len = readlink ("/proc/self/exe", buf, sizeof buf)) < 0)
00172 {
00173 fprintf (stderr, "Cannot access /proc/self/exe: %s.\n", strerror (errno));
00174 return NULL;
00175 }
00176 #endif
00177
00178 return g_strndup (buf, len);
00179 }
00180
00181 #define URL_HISTORY_MAX_SIZE 30
00182
00183 void
00184 util_add_url_history_entry(const gchar * url)
00185 {
00186 if (g_list_find_custom(cfg.url_history, url, (GCompareFunc) strcasecmp))
00187 return;
00188
00189 cfg.url_history = g_list_prepend(cfg.url_history, g_strdup(url));
00190
00191 while (g_list_length(cfg.url_history) > URL_HISTORY_MAX_SIZE) {
00192 GList *node = g_list_last(cfg.url_history);
00193 g_free(node->data);
00194 cfg.url_history = g_list_delete_link(cfg.url_history, node);
00195 }
00196 }
00197
00198
00199
00200
00201
00202
00203
00204
00205
00206 static gchar * skip_top_folders (gchar * name)
00207 {
00208 const gchar * home = getenv ("HOME");
00209 if (! home)
00210 goto NO_HOME;
00211
00212 gint len = strlen (home);
00213 if (len > 0 && home[len - 1] == G_DIR_SEPARATOR)
00214 len --;
00215
00216 #ifdef _WIN32
00217 if (! strncasecmp (name, home, len) && name[len] == '\\')
00218 #else
00219 if (! strncmp (name, home, len) && name[len] == '/')
00220 #endif
00221 return name + len + 1;
00222
00223 NO_HOME:
00224 #ifdef _WIN32
00225 return (name[0] && name[1] == ':' && name[2] == '\\') ? name + 3 : name;
00226 #else
00227 return (name[0] == '/') ? name + 1 : name;
00228 #endif
00229 }
00230
00231
00232
00233
00234
00235
00236
00237
00238
00239 static void split_filename (gchar * name, gchar * * base, gchar * * first,
00240 gchar * * second)
00241 {
00242 * first = * second = NULL;
00243
00244 gchar * c;
00245
00246 if ((c = strrchr (name, G_DIR_SEPARATOR)))
00247 {
00248 * base = c + 1;
00249 * c = 0;
00250 }
00251 else
00252 {
00253 * base = name;
00254 goto DONE;
00255 }
00256
00257 if ((c = strrchr (name, G_DIR_SEPARATOR)))
00258 {
00259 * first = c + 1;
00260 * c = 0;
00261 }
00262 else
00263 {
00264 * first = name;
00265 goto DONE;
00266 }
00267
00268 if ((c = strrchr (name, G_DIR_SEPARATOR)))
00269 * second = c + 1;
00270 else
00271 * second = name;
00272
00273 DONE:
00274 if ((c = strrchr (* base, '.')))
00275 * c = 0;
00276 }
00277
00278
00279
00280
00281
00282
00283
00284 static gchar * stream_name (gchar * name)
00285 {
00286 if (! strncmp (name, "http://", 7))
00287 name += 7;
00288 else if (! strncmp (name, "https://", 8))
00289 name += 8;
00290 else if (! strncmp (name, "mms://", 6))
00291 name += 6;
00292 else
00293 return NULL;
00294
00295 gchar * c;
00296
00297 if ((c = strchr (name, '/')))
00298 * c = 0;
00299 if ((c = strchr (name, ':')))
00300 * c = 0;
00301 if ((c = strchr (name, '?')))
00302 * c = 0;
00303
00304 return name;
00305 }
00306
00307
00308
00309
00310 void describe_song (const gchar * name, const Tuple * tuple, gchar * * _title,
00311 gchar * * _artist, gchar * * _album)
00312 {
00313
00314 static const gchar * const skip[] = {"music"};
00315
00316 const gchar * title = tuple_get_string (tuple, FIELD_TITLE, NULL);
00317 const gchar * artist = tuple_get_string (tuple, FIELD_ARTIST, NULL);
00318 const gchar * album = tuple_get_string (tuple, FIELD_ALBUM, NULL);
00319
00320 if (title && ! title[0])
00321 title = NULL;
00322 if (artist && ! artist[0])
00323 artist = NULL;
00324 if (album && ! album[0])
00325 album = NULL;
00326
00327 gchar * copy = NULL;
00328
00329 if (title && artist && album)
00330 goto DONE;
00331
00332 copy = uri_to_display (name);
00333
00334 if (! strncmp (name, "file://", 7))
00335 {
00336 gchar * base, * first, * second;
00337 split_filename (skip_top_folders (copy), & base, & first,
00338 & second);
00339
00340 if (! title)
00341 title = base;
00342
00343 for (gint i = 0; i < G_N_ELEMENTS (skip); i ++)
00344 {
00345 if (first && ! strcasecmp (first, skip[i]))
00346 first = NULL;
00347 if (second && ! strcasecmp (second, skip[i]))
00348 second = NULL;
00349 }
00350
00351 if (first)
00352 {
00353 if (second && ! artist && ! album)
00354 {
00355 artist = second;
00356 album = first;
00357 }
00358 else if (! artist)
00359 artist = first;
00360 else if (! album)
00361 album = first;
00362 }
00363 }
00364 else
00365 {
00366 if (! title)
00367 title = stream_name (copy);
00368 else if (! artist)
00369 artist = stream_name (copy);
00370 else if (! album)
00371 album = stream_name (copy);
00372 }
00373
00374 DONE:
00375 * _title = title ? stringpool_get ((gchar *) title, FALSE) : NULL;
00376 * _artist = artist ? stringpool_get ((gchar *) artist, FALSE) : NULL;
00377 * _album = album ? stringpool_get ((gchar *) album, FALSE) : NULL;
00378
00379 g_free (copy);
00380 }