1 /*
2  * MOC - music on console
3  * Copyright (C) 2008-2009 Geraud Le Falher and John Fitzgerald
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  */
11 
12 #ifdef HAVE_CONFIG_H
13 # include "config.h"
14 #endif
15 
16 #include <assert.h>
17 #include <errno.h>
18 #include <string.h>
19 
20 #include "common.h"
21 #include "files.h"
22 #include "log.h"
23 #include "options.h"
24 #include "lists.h"
25 #include "lyrics.h"
26 
27 static lists_t_strs *raw_lyrics = NULL;
28 static const char *lyrics_message = NULL;
29 
30 /* Return the list of lyrics lines, or NULL if none are loaded. */
lyrics_lines_get(void)31 lists_t_strs *lyrics_lines_get (void)
32 {
33 	return raw_lyrics;
34 }
35 
36 /* Store new lyrics lines as supplied. */
lyrics_lines_set(lists_t_strs * lines)37 void lyrics_lines_set (lists_t_strs *lines)
38 {
39 	assert (!raw_lyrics);
40 	assert (lines);
41 
42 	raw_lyrics = lines;
43 	lyrics_message = NULL;
44 }
45 
46 /* Return a list of lyrics lines loaded from a file, or NULL on error. */
lyrics_load_file(const char * filename)47 lists_t_strs *lyrics_load_file (const char *filename)
48 {
49 	int text_plain;
50 	FILE *lyrics_file = NULL;
51 	char *mime, *line;
52 	lists_t_strs *result;
53 
54 	assert (filename);
55 
56 	lyrics_message = "[No lyrics file!]";
57 	if (!file_exists (filename))
58 		return NULL;
59 	mime = file_mime_type (filename);
60 	text_plain = mime ? !strncmp (mime, "text/plain", 10) : 0;
61 	free (mime);
62 	if (!text_plain)
63 		return NULL;
64 
65 	lyrics_file = fopen (filename, "r");
66 	if (lyrics_file == NULL) {
67 		lyrics_message = "[Lyrics file cannot be read!]";
68 		logit ("Error reading '%s': %s", filename, strerror (errno));
69 		return NULL;
70 	}
71 
72 	result = lists_strs_new (0);
73 	while ((line = read_line (lyrics_file)) != NULL)
74 		lists_strs_push (result, line);
75 	fclose (lyrics_file);
76 
77 	lyrics_message = NULL;
78 	return result;
79 }
80 
81 /* Given an audio's file name, load lyrics from the default lyrics file name. */
lyrics_autoload(const char * filename)82 void lyrics_autoload (const char *filename)
83 {
84 	char *lyrics_filename, *extn;
85 
86 	assert (!raw_lyrics);
87 	assert (lyrics_message);
88 
89 	if (filename == NULL) {
90 		lyrics_message = "[No file playing!]";
91 		return;
92 	}
93 
94 	if (!options_get_bool ("AutoLoadLyrics")) {
95 		lyrics_message = "[Lyrics not autoloaded!]";
96 		return;
97 	}
98 
99 	if (is_url (filename)) {
100 		lyrics_message = "[Lyrics from URL is not supported!]";
101 		return;
102 	}
103 
104 	lyrics_filename = xstrdup (filename);
105 	extn = ext_pos (lyrics_filename);
106 	if (extn) {
107 		*--extn = '\0';
108 		raw_lyrics = lyrics_load_file (lyrics_filename);
109 	}
110 	else
111 		lyrics_message = "[No lyrics file!]";
112 
113 	free (lyrics_filename);
114 }
115 
116 /* Given a line, return a centred copy of it. */
centre_line(const char * line,int max)117 static char *centre_line (const char* line, int max)
118 {
119 	char *result;
120 	int len;
121 
122 	len = strlen (line);
123 	if (len < (max - 1)) {
124 		int space;
125 
126 		space = (max - len) / 2;
127 		result = (char *) xmalloc (space + len + 2);
128 		memset (result, ' ', space);
129 		strcpy (&result[space], line);
130 		len += space;
131 	}
132 	else {
133 		result = (char *) xmalloc (max + 2);
134 		strncpy (result, line, max);
135 		len = max;
136 	}
137 	strcpy (&result[len], "\n");
138 
139 	return result;
140 }
141 
142 /* Centre all the lines in the lyrics. */
centre_style(lists_t_strs * lines,int height ATTR_UNUSED,int width,void * data ATTR_UNUSED)143 static lists_t_strs *centre_style (lists_t_strs *lines, int height ATTR_UNUSED,
144                                    int width, void *data ATTR_UNUSED)
145 {
146 	lists_t_strs *result;
147 	int ix, size;
148 
149 	size = lists_strs_size (lines);
150 	result = lists_strs_new (size);
151 	for (ix = 0; ix < size; ix += 1) {
152 		char *old_line, *new_line;
153 
154 		old_line = lists_strs_at (lines, ix);
155 		new_line = centre_line (old_line, width);
156 		lists_strs_push (result, new_line);
157 	}
158 
159 	return result;
160 }
161 
162 /* Formatting function information. */
163 static lyrics_t_formatter *lyrics_formatter = centre_style;
164 static lyrics_t_reaper *formatter_reaper = NULL;
165 static void *formatter_data = NULL;
166 
167 /* Register a new function to be used for formatting.  A NULL formatter
168  * resets formatting to the default centred style. */
lyrics_use_formatter(lyrics_t_formatter formatter,lyrics_t_reaper reaper,void * data)169 void lyrics_use_formatter (lyrics_t_formatter formatter,
170                            lyrics_t_reaper reaper, void *data)
171 {
172 	if (formatter_reaper)
173 		formatter_reaper (formatter_data);
174 
175 	if (formatter) {
176 		lyrics_formatter = formatter;
177 		formatter_reaper = reaper;
178 		formatter_data = data;
179 	}
180 	else {
181 		lyrics_formatter = centre_style;
182 		formatter_reaper = NULL;
183 		formatter_data = NULL;
184 	}
185 }
186 
187 /* Return a list of either the formatted lyrics if any are loaded or
188  * a centred message. */
lyrics_format(int height,int width)189 lists_t_strs *lyrics_format (int height, int width)
190 {
191 	int ix;
192 	lists_t_strs *result;
193 
194 	assert (raw_lyrics || lyrics_message);
195 
196 	result = NULL;
197 
198 	if (raw_lyrics) {
199 		result = lyrics_formatter (raw_lyrics, height, width - 1,
200 			                                                 formatter_data);
201 		if (!result)
202 			lyrics_message = "[Error formatting lyrics!]";
203 	}
204 
205 	if (!result) {
206 		char *line;
207 
208 		result = lists_strs_new (1);
209 		line = centre_line (lyrics_message, width - 1);
210 		lists_strs_push (result, line);
211 	}
212 
213 	for (ix = 0; ix < lists_strs_size (result); ix += 1) {
214 		int len;
215 		char *this_line;
216 
217 		this_line = lists_strs_at (result, ix);
218 		len = strlen (this_line);
219 		if (len > width - 1)
220 			strcpy (&this_line[width - 1], "\n");
221 		else if (this_line[len - 1] != '\n') {
222 			char *new_line;
223 
224 			new_line = xmalloc (len + 2);
225 			strcpy (new_line, this_line);
226 			strcat (new_line, "\n");
227 			lists_strs_swap (result, ix, new_line);
228 			free (this_line);
229 		}
230 	}
231 
232 	return result;
233 }
234 
235 /* Dispose of raw lyrics lines. */
lyrics_cleanup(void)236 void lyrics_cleanup (void)
237 {
238 	if (raw_lyrics) {
239 		lists_strs_free (raw_lyrics);
240 		raw_lyrics = NULL;
241 	}
242 
243 	lyrics_message = "[No lyrics loaded!]";
244 }
245