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