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 strncat(s, temp, max-length);
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 strncat(s, p, 1);
141 length++;
142 ++p;
143 continue;
144 }
146 /* let the escape character escape itself */
147 if (p[0] == '#' && p[1] != '\0' && length<max)
148 {
149 strncat(s, p+1, 1);
150 length++;
151 p+=2;
152 continue;
153 }
155 /* advance past the esc character */
157 /* find the extent of this format specifier (stop at \0, ' ', or esc) */
158 temp = NULL;
159 end = p+1;
160 while(*end >= 'a' && *end <= 'z')
161 {
162 end++;
163 }
164 n = end - p + 1;
165 if(*end != '%')
166 n--;
167 else if (strncmp("%file%", p, n) == 0)
168 temp = utf8_to_locale(song->file);
169 else if (strncmp("%artist%", p, n) == 0)
170 temp = song->artist ? utf8_to_locale(song->artist) : NULL;
171 else if (strncmp("%title%", p, n) == 0)
172 temp = song->title ? utf8_to_locale(song->title) : NULL;
173 else if (strncmp("%album%", p, n) == 0)
174 temp = song->album ? utf8_to_locale(song->album) : NULL;
175 else if (strncmp("%track%", p, n) == 0)
176 temp = song->track ? utf8_to_locale(song->track) : NULL;
177 else if (strncmp("%name%", p, n) == 0)
178 temp = song->name ? utf8_to_locale(song->name) : NULL;
179 else if (strncmp("%shortfile%", p, n) == 0)
180 {
181 if( strstr(song->file, "://") )
182 temp = utf8_to_locale(song->file);
183 else
184 temp = utf8_to_locale(basename(song->file));
185 }
186 else if (strncmp("%time%", p, n) == 0)
187 {
188 if (song->time != MPD_SONG_NO_TIME) {
189 gchar s[10];
190 snprintf(s, 9, "%d:%d", song->time / 60,
191 song->time % 60 + 1);
192 /* nasty hack to use static buffer */
193 temp = g_strdup(s);
194 }
195 }
197 if( temp == NULL)
198 {
199 gsize templen=n;
200 /* just pass-through any unknown specifiers (including esc) */
201 /* drop a null char in so printf stops at the end of this specifier,
202 but put the real character back in (pseudo-const) */
203 if( length+templen > max )
204 templen = max-length;
205 strncat(s, p, templen);
206 length+=templen;
207 }
208 else {
209 gsize templen = strlen(temp);
211 found = TRUE;
212 if( length+templen > max )
213 templen = max-length;
214 strncat(s, temp, templen);
215 length+=templen;
216 g_free(temp);
217 }
219 /* advance past the specifier */
220 p += n;
221 }
223 if(last) *last = p;
225 return length;
226 }
228 gsize
229 strfsong(gchar *s, gsize max, const gchar *format, mpd_Song *song)
230 {
231 return _strfsong(s, max, format, song, NULL);
232 }