1 /*
2 * $Id$
3 *
4 * Based on mpc's songToFormatedString modified for glib and ncmpc
5 *
6 *
7 * (c) 2003-2004 by normalperson and Warren Dukes (shank@mercury.chem.pitt.edu)
8 * and Daniel Brown (danb@cs.utexas.edu)
9 * and Kalle Wallin (kaw@linux.se)
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 */
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <unistd.h>
29 #include <string.h>
30 #include <glib.h>
32 #include "config.h"
33 #include "libmpdclient.h"
34 #include "support.h"
35 #include "strfsong.h"
37 static gchar *
38 skip(gchar * p)
39 {
40 gint stack = 0;
42 while (*p != '\0') {
43 if(*p == '[') stack++;
44 if(*p == '#' && p[1] != '\0') {
45 /* skip escaped stuff */
46 ++p;
47 }
48 else if(stack) {
49 if(*p == ']') stack--;
50 }
51 else {
52 if(*p == '&' || *p == '|' || *p == ']') {
53 break;
54 }
55 }
56 ++p;
57 }
59 return p;
60 }
62 static gsize
63 _strfsong(gchar *s,
64 gsize max,
65 const gchar *format,
66 mpd_Song *song,
67 gchar **last)
68 {
69 gchar *p, *end;
70 gchar *temp;
71 gsize n, length = 0;
72 gboolean found = FALSE;
74 memset(s, 0, max);
75 if( song==NULL )
76 return 0;
78 for( p=(gchar *) format; *p != '\0' && length<max; )
79 {
80 /* OR */
81 if (p[0] == '|')
82 {
83 ++p;
84 if(!found)
85 {
86 memset(s, 0, max);
87 length = 0;
88 }
89 else
90 {
91 p = skip(p);
92 }
93 continue;
94 }
96 /* AND */
97 if (p[0] == '&')
98 {
99 ++p;
100 if(!found)
101 {
102 p = skip(p);
103 }
104 else
105 {
106 found = FALSE;
107 }
108 continue;
109 }
111 /* EXPRESSION START */
112 if (p[0] == '[')
113 {
114 temp = g_malloc0(max);
115 if( _strfsong(temp, max, p+1, song, &p) >0 )
116 {
117 g_strlcat(s, temp, max);
118 length = strlen(s);
119 found = TRUE;
120 }
121 g_free(temp);
122 continue;
123 }
125 /* EXPRESSION END */
126 if (p[0] == ']')
127 {
128 if(last) *last = p+1;
129 if(!found && length)
130 {
131 memset(s, 0, max);
132 length = 0;
133 }
134 return length;
135 }
137 /* pass-through non-escaped portions of the format string */
138 if (p[0] != '#' && p[0] != '%' && length<max)
139 {
140 s[length++] = *p;
141 p++;
142 continue;
143 }
145 /* let the escape character escape itself */
146 if (p[0] == '#' && p[1] != '\0' && length<max)
147 {
148 s[length++] = *(p+1);
149 p+=2;
150 continue;
151 }
153 /* advance past the esc character */
155 /* find the extent of this format specifier (stop at \0, ' ', or esc) */
156 temp = NULL;
157 end = p+1;
158 while(*end >= 'a' && *end <= 'z')
159 {
160 end++;
161 }
162 n = end - p + 1;
163 if(*end != '%')
164 n--;
165 else if (strncmp("%file%", p, n) == 0)
166 temp = utf8_to_locale(song->file);
167 else if (strncmp("%artist%", p, n) == 0)
168 temp = song->artist ? utf8_to_locale(song->artist) : NULL;
169 else if (strncmp("%title%", p, n) == 0)
170 temp = song->title ? utf8_to_locale(song->title) : NULL;
171 else if (strncmp("%album%", p, n) == 0)
172 temp = song->album ? utf8_to_locale(song->album) : NULL;
173 else if (strncmp("%shortalbum%", p, n) == 0)
174 {
175 temp = song->album ? utf8_to_locale(song->album) : NULL;
176 if (temp)
177 {
178 gchar *temp2 = g_strndup(temp, 25);
179 if (strlen(temp) > 25)
180 {
181 temp2[24] = '.';
182 temp2[23] = '.';
183 temp2[22] = '.';
184 }
185 g_free(temp);
186 temp = temp2;
187 }
188 }
189 else if (strncmp("%track%", p, n) == 0)
190 temp = song->track ? utf8_to_locale(song->track) : NULL;
191 else if (strncmp("%name%", p, n) == 0)
192 temp = song->name ? utf8_to_locale(song->name) : NULL;
193 else if (strncmp("%date%", p, n) == 0)
194 temp = song->date ? utf8_to_locale(song->date) : NULL;
195 else if (strncmp("%genre%", p, n) == 0)
196 temp = song->genre ? utf8_to_locale(song->genre) : NULL;
197 else if (strncmp("%shortfile%", p, n) == 0)
198 {
199 if( strstr(song->file, "://") )
200 temp = utf8_to_locale(song->file);
201 else
202 temp = utf8_to_locale(basename(song->file));
203 }
204 else if (strncmp("%time%", p, n) == 0)
205 {
206 if (song->time != MPD_SONG_NO_TIME)
207 {
208 if (song->time > 3600)
209 {
210 temp = g_strdup_printf("%d:%02d:%02d",
211 song->time / 3600,
212 (song->time % 3600) / 60,
213 song->time % 60);
214 }
215 else
216 {
217 temp = g_strdup_printf("%d:%02d",
218 song->time / 60,
219 song->time % 60);
220 }
221 }
222 }
224 if( temp == NULL)
225 {
226 gsize templen=n;
227 /* just pass-through any unknown specifiers (including esc) */
228 /* drop a null char in so printf stops at the end of this specifier,
229 but put the real character back in (pseudo-const) */
230 if( length+templen > max )
231 templen = max-length;
232 g_strlcat(s, p,max);
233 length+=templen;
234 }
235 else {
236 gsize templen = strlen(temp);
238 found = TRUE;
239 if( length+templen > max )
240 templen = max-length;
241 g_strlcat(s, temp, max);
242 length+=templen;
243 g_free(temp);
244 }
246 /* advance past the specifier */
247 p += n;
248 }
250 if(last) *last = p;
252 return length;
253 }
255 gsize
256 strfsong(gchar *s, gsize max, const gchar *format, mpd_Song *song)
257 {
258 return _strfsong(s, max, format, song, NULL);
259 }