static void process_deferred_overrides (lists_t_strs *deferred) { int ix; bool cleared; const char marker[] = "*Marker*"; char **config_decoders; lists_t_strs *decoders_option; /* We need to shuffle the PreferredDecoders list into the * right order as we load any deferred overriding options. */ decoders_option = options_get_list ("PreferredDecoders"); lists_strs_reverse (decoders_option); config_decoders = lists_strs_save (decoders_option); lists_strs_clear (decoders_option); lists_strs_append (decoders_option, marker); for (ix = 0; ix < lists_strs_size (deferred); ix += 1) override_config_option (lists_strs_at (deferred, ix), NULL); cleared = lists_strs_empty (decoders_option) || strcmp (lists_strs_at (decoders_option, 0), marker) != 0; lists_strs_reverse (decoders_option); if (!cleared) { char **override_decoders; free (lists_strs_pop (decoders_option)); override_decoders = lists_strs_save (decoders_option); lists_strs_clear (decoders_option); lists_strs_load (decoders_option, config_decoders); lists_strs_load (decoders_option, override_decoders); free (override_decoders); } free (config_decoders); }
static void override_config_option (const char *optarg, lists_t_strs *deferred) { int len; bool append; char *ptr, *name, *value; enum option_type type; assert (optarg != NULL); ptr = strchr (optarg, '='); if (ptr == NULL) goto error; /* Allow for list append operator ("+="). */ append = (ptr > optarg && *(ptr - 1) == '+'); name = trim (optarg, ptr - optarg - (append ? 1 : 0)); if (!name || !name[0]) goto error; type = options_get_type (name); if (type == OPTION_LIST) { if (deferred) { lists_strs_append (deferred, optarg); free (name); return; } } else if (append) goto error; value = trim (ptr + 1, strlen (ptr + 1)); if (!value || !value[0]) goto error; if (value[0] == '\'' || value[0] == '"') { len = strlen (value); if (value[0] != value[len - 1]) goto error; if (strlen (value) < 2) goto error; memmove (value, value + 1, len - 2); value[len - 2] = 0x00; } if (!options_set_pair (name, value, append)) goto error; options_ignore_config (name); free (name); free (value); return; error: fatal ("Malformed override option: %s", optarg); }
static void load_extn_list () { const int counts[] = {SFC_GET_SIMPLE_FORMAT_COUNT, SFC_GET_FORMAT_MAJOR_COUNT}; const int formats[] = {SFC_GET_SIMPLE_FORMAT, SFC_GET_FORMAT_MAJOR}; supported_extns = lists_strs_new (16); for (size_t ix = 0; ix < ARRAY_SIZE(counts); ix += 1) { int limit; SF_FORMAT_INFO format_info; sf_command (NULL, counts[ix], &limit, sizeof (limit)); for (int iy = 0 ; iy < limit ; iy += 1) { format_info.format = iy ; sf_command (NULL, formats[ix], &format_info, sizeof (format_info)); if (!lists_strs_exists (supported_extns, format_info.extension)) lists_strs_append (supported_extns, format_info.extension); } } /* These are synonyms of supported extensions. */ if (lists_strs_exists (supported_extns, "aiff")) lists_strs_append (supported_extns, "aif"); if (lists_strs_exists (supported_extns, "au")) lists_strs_append (supported_extns, "snd"); if (lists_strs_exists (supported_extns, "wav")) { lists_strs_append (supported_extns, "nist"); lists_strs_append (supported_extns, "sph"); } if (lists_strs_exists (supported_extns, "iff")) lists_strs_append (supported_extns, "svx"); if (lists_strs_exists (supported_extns, "oga")) lists_strs_append (supported_extns, "ogg"); if (lists_strs_exists (supported_extns, "sf")) lists_strs_append (supported_extns, "ircam"); if (lists_strs_exists (supported_extns, "mat")) { lists_strs_append (supported_extns, "mat4"); lists_strs_append (supported_extns, "mat5"); } }
/* Reload saved strings into a list. The reloaded strings are appended * to the list. The number of items reloaded is returned. */ int lists_strs_load (lists_t_strs *list, const char **saved) { int size; assert (list); assert (saved); size = lists_strs_size (list); while (*saved) lists_strs_append (list, *saved++); return lists_strs_size (list) - size; }
/* Read and return a line from 'stream' in a dynamically allocated buffer. * Return NULL at end of file. */ char *xgetline (FILE *stream) { static char buffer[64]; char *result; lists_t_strs *line; line = lists_strs_new (4); do { if (!fgets (buffer, sizeof (buffer), stream)) break; lists_strs_append (line, buffer); } while (buffer[strlen (buffer) - 1] != '\n'); result = lists_strs_cat (line); lists_strs_free (line); return result; }
/* Split a string at any delimiter in given string. The resulting segments * are appended to the given string list. Returns the number of tokens * appended. */ int lists_strs_split (lists_t_strs *list, const char *s, const char *delim) { int result; char *str, *token, *saveptr; assert (list); assert (s); assert (delim); result = 0; str = xstrdup (s); token = strtok_r (str, delim, &saveptr); while (token) { result += 1; lists_strs_append (list, token); token = strtok_r (NULL, delim, &saveptr); } free (str); return result; }
/* Return a string of concatenated driver names. */ static char *list_decoder_names (int *decoder_list, int count) { int ix; char *result; lists_t_strs *names; if (count == 0) return xstrdup (""); names = lists_strs_new (count); for (ix = 0; ix < count; ix += 1) lists_strs_append (names, plugins[decoder_list[ix]].name); if (have_tremor) { ix = lists_strs_find (names, "vorbis"); if (ix < lists_strs_size (names)) lists_strs_replace (names, ix, "vorbis(tremor)"); } result = lists_strs_fmt (names, " %s"); lists_strs_free (names); return result; }
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; }