Audacious $Id:Doxyfile42802007-03-2104:39:00Znenolod$
|
00001 /* Audacious - Cross-platform multimedia player 00002 * Copyright (C) 2005-2011 Audacious development team 00003 * 00004 * Based on BMP: 00005 * Copyright (C) 2003-2004 BMP development team. 00006 * 00007 * Based on XMMS: 00008 * Copyright (C) 1998-2003 XMMS development team. 00009 * 00010 * This program is free software; you can redistribute it and/or modify 00011 * it under the terms of the GNU General Public License as published by 00012 * the Free Software Foundation; under version 3 of the License. 00013 * 00014 * This program is distributed in the hope that it will be useful, 00015 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00016 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00017 * GNU General Public License for more details. 00018 * 00019 * You should have received a copy of the GNU General Public License 00020 * along with this program. If not, see <http://www.gnu.org/licenses>. 00021 * 00022 * The Audacious team does not consider modular code linking to 00023 * Audacious or using our public API to be a derived work. 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 /* try to translate dos path */ 00115 convert_dos_path(filename); /* in place replacement */ 00116 00117 // make full path uri here 00118 // case 1: filename is raw full path or uri 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 // case 2: filename is not raw full path nor uri 00125 // make full path by replacing last part of playlist path with filename. 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 /* local files -- not URI's */ 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 /* Strips various common top-level folders from a file name (not URI). The 00199 * string passed will not be modified, but the string returned will share the 00200 * same memory. Examples: 00201 * "/home/john/folder/file.mp3" -> "folder/file.mp3" 00202 * "/folder/file.mp3" -> "folder/file.mp3" 00203 * "C:\Users\John\folder\file.mp3" -> "folder\file.mp3" 00204 * "E:\folder\file.mp3" -> "folder\file.mp3" */ 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 /* Divides a file name (not URI) into the base name, the lowest folder, and the 00232 * second lowest folder. The string passed will be modified, and the strings 00233 * returned will use the same memory. May return NULL for <first> and <second>. 00234 * Examples: 00235 * "a/b/c/d/e.mp3" -> "e", "d", "c" 00236 * "d/e.mp3" -> "e", "d", NULL 00237 * "e.mp3" -> "e", NULL, NULL */ 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 /* Separates the domain name from an internet URI. The string passed will be 00279 * modified, and the string returned will share the same memory. May return 00280 * NULL. Examples: 00281 * "http://some.domain.org/folder/file.mp3" -> "some.domain.org" 00282 * "http://some.stream.fm:8000" -> "some.stream.fm" */ 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 /* Derives best guesses of title, artist, and album from a file name (URI) and 00308 * tuple. The returned strings are stringpooled or NULL. */ 00309 00310 void describe_song (const gchar * name, const Tuple * tuple, gchar * * _title, 00311 gchar * * _artist, gchar * * _album) 00312 { 00313 /* Common folder names to skip */ 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 }