/* Return a list of lyrics lines loaded from a file, or NULL on error. */ lists_t_strs *lyrics_load_file (const char *filename) { FILE *lyrics_file = NULL; const char *mime; char *line; lists_t_strs *result; assert (filename); lyrics_message = "[No lyrics file!]"; if (!file_exists (filename)) return NULL; mime = file_mime_type (filename); if (mime && strncmp (mime, "text/plain", 10)) return NULL; lyrics_file = fopen (filename, "r"); if (lyrics_file == NULL) { lyrics_message = "[Lyrics file cannot be read!]"; logit ("Error reading '%s': %s", filename, strerror (errno)); return NULL; } result = lists_strs_new (0); while ((line = read_line (lyrics_file)) != NULL) lists_strs_push (result, line); fclose (lyrics_file); lyrics_message = NULL; return result; }
/* Put something into the log */ void internal_logit (const char *file, const int line, const char *function, const char *format, ...) { int len; char *msg, time_str[20]; struct timeval utc_time; va_list va; struct tm tm_time; const char fmt[] = "%s.%06u: %s:%d %s(): %s\n"; if (!logfp) { switch (logging_state) { case UNINITIALISED: buffered_log = lists_strs_new (128); logging_state = BUFFERING; break; case BUFFERING: /* Don't let storage run away on us. */ if (lists_strs_size (buffered_log) < lists_strs_capacity (buffered_log)) break; log_records_spilt += 1; return; case LOGGING: return; } } va_start (va, format); len = vsnprintf (NULL, 0, format, va) + 1; va_end (va); msg = xmalloc (len); va_start (va, format); vsnprintf (msg, len, format, va); va_end (va); gettimeofday (&utc_time, NULL); localtime_r (&utc_time.tv_sec, &tm_time); strftime (time_str, sizeof (time_str), "%b %e %T", &tm_time); if (logfp) { fprintf (logfp, fmt, time_str, (unsigned)utc_time.tv_usec, file, line, function, msg); fflush (logfp); } else { char *str; len = snprintf (NULL, 0, fmt, time_str, (unsigned)utc_time.tv_usec, file, line, function, msg); str = xmalloc (len + 1); snprintf (str, len + 1, fmt, time_str, (unsigned)utc_time.tv_usec, file, line, function, msg); lists_strs_push (buffered_log, str); } free (msg); }
/* Copy a string and append it to the end of a list. */ void lists_strs_append (lists_t_strs *list, const char *s) { char *str; assert (list); assert (s); str = xstrdup (s); lists_strs_push (list, str); }
static void on_song_change () { static char *last_file = NULL; static lists_t_strs *on_song_change = NULL; int ix; bool same_file, unpaused; char *curr_file, **args; struct file_tags *curr_tags; lists_t_strs *arg_list; /* We only need to do OnSongChange tokenisation once. */ if (on_song_change == NULL) { char *command; on_song_change = lists_strs_new (4); command = options_get_str ("OnSongChange"); if (command) lists_strs_tokenise (on_song_change, command); } if (lists_strs_empty (on_song_change)) return; curr_file = audio_get_sname (); if (curr_file == NULL) return; same_file = (last_file && !strcmp (last_file, curr_file)); unpaused = (audio_get_prev_state () == STATE_PAUSE); if (same_file && (unpaused || !options_get_bool ("RepeatSongChange"))) { free (curr_file); return; } curr_tags = tags_cache_get_immediate (tags_cache, curr_file, TAGS_COMMENTS | TAGS_TIME); arg_list = lists_strs_new (lists_strs_size (on_song_change)); for (ix = 0; ix < lists_strs_size (on_song_change); ix += 1) { char *arg, *str; arg = lists_strs_at (on_song_change, ix); if (arg[0] != '%') lists_strs_append (arg_list, arg); else if (!curr_tags) lists_strs_append (arg_list, ""); else { switch (arg[1]) { case 'a': str = curr_tags->artist ? curr_tags->artist : ""; lists_strs_append (arg_list, str); break; case 'r': str = curr_tags->album ? curr_tags->album : ""; lists_strs_append (arg_list, str); break; case 't': str = curr_tags->title ? curr_tags->title : ""; lists_strs_append (arg_list, str); break; case 'n': if (curr_tags->track >= 0) { str = (char *) xmalloc (sizeof (char) * 4); snprintf (str, 4, "%d", curr_tags->track); lists_strs_push (arg_list, str); } else lists_strs_append (arg_list, ""); break; case 'f': lists_strs_append (arg_list, curr_file); break; case 'D': if (curr_tags->time >= 0) { str = (char *) xmalloc (sizeof (char) * 10); snprintf (str, 10, "%d", curr_tags->time); lists_strs_push (arg_list, str); } else lists_strs_append (arg_list, ""); break; case 'd': if (curr_tags->time >= 0) { str = (char *) xmalloc (sizeof (char) * 12); sec_to_min (str, curr_tags->time); lists_strs_push (arg_list, str); } else lists_strs_append (arg_list, ""); break; default: lists_strs_append (arg_list, arg); } } } tags_free (curr_tags); #ifndef NDEBUG { char *cmd; cmd = lists_strs_fmt (arg_list, " %s"); debug ("Running command: %s", cmd); free (cmd); } #endif switch (fork ()) { case 0: args = lists_strs_save (arg_list); execve (args[0], args, environ); exit (EXIT_FAILURE); case -1: log_errno ("Failed to fork()", errno); } lists_strs_free (arg_list); free (last_file); last_file = curr_file; }