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 <limits.h> 00027 #include <unistd.h> 00028 00029 #ifdef _WIN32 00030 #include <windows.h> 00031 #endif 00032 00033 #ifdef HAVE_CONFIG_H 00034 # include "config.h" 00035 #endif 00036 00037 #include <glib.h> 00038 #include <stdlib.h> 00039 #include <string.h> 00040 #include <ctype.h> 00041 00042 #include <errno.h> 00043 00044 #ifdef HAVE_FTS_H 00045 # include <sys/types.h> 00046 # include <sys/stat.h> 00047 # include <fts.h> 00048 #endif 00049 00050 #include <libaudcore/audstrings.h> 00051 #include <libaudcore/stringpool.h> 00052 00053 #include "audconfig.h" 00054 #include "debug.h" 00055 #include "i18n.h" 00056 #include "misc.h" 00057 #include "plugins.h" 00058 #include "util.h" 00059 00060 gboolean 00061 dir_foreach(const gchar * path, DirForeachFunc function, 00062 gpointer user_data, GError ** error) 00063 { 00064 GError *error_out = NULL; 00065 GDir *dir; 00066 const gchar *entry; 00067 gchar *entry_fullpath; 00068 00069 if (!(dir = g_dir_open(path, 0, &error_out))) { 00070 g_propagate_error(error, error_out); 00071 return FALSE; 00072 } 00073 00074 while ((entry = g_dir_read_name(dir))) { 00075 entry_fullpath = g_build_filename(path, entry, NULL); 00076 00077 if ((*function) (entry_fullpath, entry, user_data)) { 00078 g_free(entry_fullpath); 00079 break; 00080 } 00081 00082 g_free(entry_fullpath); 00083 } 00084 00085 g_dir_close(dir); 00086 00087 return TRUE; 00088 } 00089 00098 gchar* 00099 util_get_localdir(void) 00100 { 00101 gchar *datadir; 00102 gchar *tmp; 00103 00104 if ( (tmp = getenv("XDG_CONFIG_HOME")) == NULL ) 00105 datadir = g_build_filename( g_get_home_dir() , ".config" , "audacious" , NULL ); 00106 else 00107 datadir = g_build_filename( tmp , "audacious" , NULL ); 00108 00109 return datadir; 00110 } 00111 00112 00113 gchar * construct_uri (const gchar * string, const gchar * playlist_name) 00114 { 00115 gchar *filename = g_strdup(string); 00116 gchar *uri = NULL; 00117 00118 /* try to translate dos path */ 00119 convert_dos_path(filename); /* in place replacement */ 00120 00121 // make full path uri here 00122 // case 1: filename is raw full path or uri 00123 if (filename[0] == '/' || strstr(filename, "://")) { 00124 uri = g_filename_to_uri(filename, NULL, NULL); 00125 if(!uri) 00126 uri = g_strdup(filename); 00127 } 00128 // case 2: filename is not raw full path nor uri 00129 // make full path by replacing last part of playlist path with filename. 00130 else 00131 { 00132 const gchar * slash = strrchr (playlist_name, '/'); 00133 if (slash) 00134 uri = g_strdup_printf ("%.*s/%s", (gint) (slash - playlist_name), 00135 playlist_name, filename); 00136 } 00137 00138 g_free (filename); 00139 return uri; 00140 } 00141 00142 /* local files -- not URI's */ 00143 gint file_get_mtime (const gchar * filename) 00144 { 00145 struct stat info; 00146 00147 if (stat (filename, & info)) 00148 return -1; 00149 00150 return info.st_mtime; 00151 } 00152 00153 void 00154 make_directory(const gchar * path, mode_t mode) 00155 { 00156 if (g_mkdir_with_parents(path, mode) == 0) 00157 return; 00158 00159 g_printerr(_("Could not create directory (%s): %s\n"), path, 00160 g_strerror(errno)); 00161 } 00162 00163 gchar * get_path_to_self (void) 00164 { 00165 gchar buf[PATH_MAX]; 00166 gint len; 00167 00168 #ifdef _WIN32 00169 if (! (len = GetModuleFileName (NULL, buf, sizeof buf)) || len == sizeof buf) 00170 { 00171 fprintf (stderr, "GetModuleFileName failed.\n"); 00172 return NULL; 00173 } 00174 #else 00175 if ((len = readlink ("/proc/self/exe", buf, sizeof buf)) < 0) 00176 { 00177 fprintf (stderr, "Cannot access /proc/self/exe: %s.\n", strerror (errno)); 00178 return NULL; 00179 } 00180 #endif 00181 00182 return g_strndup (buf, len); 00183 } 00184 00185 #define URL_HISTORY_MAX_SIZE 30 00186 00187 void 00188 util_add_url_history_entry(const gchar * url) 00189 { 00190 if (g_list_find_custom(cfg.url_history, url, (GCompareFunc) strcasecmp)) 00191 return; 00192 00193 cfg.url_history = g_list_prepend(cfg.url_history, g_strdup(url)); 00194 00195 while (g_list_length(cfg.url_history) > URL_HISTORY_MAX_SIZE) { 00196 GList *node = g_list_last(cfg.url_history); 00197 g_free(node->data); 00198 cfg.url_history = g_list_delete_link(cfg.url_history, node); 00199 } 00200 } 00201 00202 /* Strips various common top-level folders from a file name (not URI). The 00203 * string passed will not be modified, but the string returned will share the 00204 * same memory. Examples: 00205 * "/home/john/folder/file.mp3" -> "folder/file.mp3" 00206 * "/folder/file.mp3" -> "folder/file.mp3" 00207 * "C:\Users\John\folder\file.mp3" -> "folder\file.mp3" 00208 * "E:\folder\file.mp3" -> "folder\file.mp3" */ 00209 00210 static gchar * skip_top_folders (gchar * name) 00211 { 00212 const gchar * home = getenv ("HOME"); 00213 if (! home) 00214 goto NO_HOME; 00215 00216 gint len = strlen (home); 00217 if (len > 0 && home[len - 1] == G_DIR_SEPARATOR) 00218 len --; 00219 00220 #ifdef _WIN32 00221 if (! strncasecmp (name, home, len) && name[len] == '\\') 00222 #else 00223 if (! strncmp (name, home, len) && name[len] == '/') 00224 #endif 00225 return name + len + 1; 00226 00227 NO_HOME: 00228 #ifdef _WIN32 00229 return (name[0] && name[1] == ':' && name[2] == '\\') ? name + 3 : name; 00230 #else 00231 return (name[0] == '/') ? name + 1 : name; 00232 #endif 00233 } 00234 00235 /* Divides a file name (not URI) into the base name, the lowest folder, and the 00236 * second lowest folder. The string passed will be modified, and the strings 00237 * returned will use the same memory. May return NULL for <first> and <second>. 00238 * Examples: 00239 * "a/b/c/d/e.mp3" -> "e", "d", "c" 00240 * "d/e.mp3" -> "e", "d", NULL 00241 * "e.mp3" -> "e", NULL, NULL */ 00242 00243 static void split_filename (gchar * name, gchar * * base, gchar * * first, 00244 gchar * * second) 00245 { 00246 * first = * second = NULL; 00247 00248 gchar * c; 00249 00250 if ((c = strrchr (name, G_DIR_SEPARATOR))) 00251 { 00252 * base = c + 1; 00253 * c = 0; 00254 } 00255 else 00256 { 00257 * base = name; 00258 goto DONE; 00259 } 00260 00261 if ((c = strrchr (name, G_DIR_SEPARATOR))) 00262 { 00263 * first = c + 1; 00264 * c = 0; 00265 } 00266 else 00267 { 00268 * first = name; 00269 goto DONE; 00270 } 00271 00272 if ((c = strrchr (name, G_DIR_SEPARATOR))) 00273 * second = c + 1; 00274 else 00275 * second = name; 00276 00277 DONE: 00278 if ((c = strrchr (* base, '.'))) 00279 * c = 0; 00280 } 00281 00282 /* Separates the domain name from an internet URI. The string passed will be 00283 * modified, and the string returned will share the same memory. May return 00284 * NULL. Examples: 00285 * "http://some.domain.org/folder/file.mp3" -> "some.domain.org" 00286 * "http://some.stream.fm:8000" -> "some.stream.fm" */ 00287 00288 static gchar * stream_name (gchar * name) 00289 { 00290 if (! strncmp (name, "http://", 7)) 00291 name += 7; 00292 else if (! strncmp (name, "https://", 8)) 00293 name += 8; 00294 else if (! strncmp (name, "mms://", 6)) 00295 name += 6; 00296 else 00297 return NULL; 00298 00299 gchar * c; 00300 00301 if ((c = strchr (name, '/'))) 00302 * c = 0; 00303 if ((c = strchr (name, ':'))) 00304 * c = 0; 00305 if ((c = strchr (name, '?'))) 00306 * c = 0; 00307 00308 return name; 00309 } 00310 00311 /* Derives best guesses of title, artist, and album from a file name (URI) and 00312 * tuple. The returned strings are stringpooled or NULL. */ 00313 00314 void describe_song (const gchar * name, const Tuple * tuple, gchar * * _title, 00315 gchar * * _artist, gchar * * _album) 00316 { 00317 /* Common folder names to skip */ 00318 static const gchar * const skip[] = {"music"}; 00319 00320 const gchar * title = tuple_get_string (tuple, FIELD_TITLE, NULL); 00321 const gchar * artist = tuple_get_string (tuple, FIELD_ARTIST, NULL); 00322 const gchar * album = tuple_get_string (tuple, FIELD_ALBUM, NULL); 00323 00324 if (title && ! title[0]) 00325 title = NULL; 00326 if (artist && ! artist[0]) 00327 artist = NULL; 00328 if (album && ! album[0]) 00329 album = NULL; 00330 00331 gchar * copy = NULL; 00332 00333 if (title && artist && album) 00334 goto DONE; 00335 00336 copy = uri_to_display (name); 00337 00338 if (! strncmp (name, "file://", 7)) 00339 { 00340 gchar * base, * first, * second; 00341 split_filename (skip_top_folders (copy), & base, & first, 00342 & second); 00343 00344 if (! title) 00345 title = base; 00346 00347 for (gint i = 0; i < G_N_ELEMENTS (skip); i ++) 00348 { 00349 if (first && ! strcasecmp (first, skip[i])) 00350 first = NULL; 00351 if (second && ! strcasecmp (second, skip[i])) 00352 second = NULL; 00353 } 00354 00355 if (first) 00356 { 00357 if (second && ! artist && ! album) 00358 { 00359 artist = second; 00360 album = first; 00361 } 00362 else if (! artist) 00363 artist = first; 00364 else if (! album) 00365 album = first; 00366 } 00367 } 00368 else 00369 { 00370 if (! title) 00371 title = stream_name (copy); 00372 else if (! artist) 00373 artist = stream_name (copy); 00374 else if (! album) 00375 album = stream_name (copy); 00376 } 00377 00378 DONE: 00379 * _title = title ? stringpool_get ((gchar *) title, FALSE) : NULL; 00380 * _artist = artist ? stringpool_get ((gchar *) artist, FALSE) : NULL; 00381 * _album = album ? stringpool_get ((gchar *) album, FALSE) : NULL; 00382 00383 g_free (copy); 00384 }