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 */
25 #include "strfsong.h"
26 #include "support.h"
27 #include "charset.h"
29 #include <string.h>
31 static const gchar *
32 skip(const gchar * p)
33 {
34 gint stack = 0;
36 while (*p != '\0') {
37 if(*p == '[') stack++;
38 if(*p == '#' && p[1] != '\0') {
39 /* skip escaped stuff */
40 ++p;
41 } else if(stack) {
42 if(*p == ']') stack--;
43 } else {
44 if(*p == '&' || *p == '|' || *p == ']') {
45 break;
46 }
47 }
48 ++p;
49 }
51 return p;
52 }
54 static gsize
55 _strfsong(gchar *s,
56 gsize max,
57 const gchar *format,
58 const struct mpd_song *song,
59 const gchar **last)
60 {
61 const gchar *p, *end;
62 gchar *temp;
63 gsize n, length = 0;
64 gboolean found = FALSE;
66 memset(s, 0, max);
67 if( song==NULL )
68 return 0;
70 for (p = format; *p != '\0' && length<max;) {
71 /* OR */
72 if (p[0] == '|') {
73 ++p;
74 if(!found) {
75 memset(s, 0, max);
76 length = 0;
77 } else {
78 p = skip(p);
79 }
80 continue;
81 }
83 /* AND */
84 if (p[0] == '&') {
85 ++p;
86 if(!found) {
87 p = skip(p);
88 } else {
89 found = FALSE;
90 }
91 continue;
92 }
94 /* EXPRESSION START */
95 if (p[0] == '[') {
96 temp = g_malloc0(max);
97 if( _strfsong(temp, max, p+1, song, &p) >0 ) {
98 g_strlcat(s, temp, max);
99 length = strlen(s);
100 found = TRUE;
101 }
102 g_free(temp);
103 continue;
104 }
106 /* EXPRESSION END */
107 if (p[0] == ']') {
108 if(last) *last = p+1;
109 if(!found && length) {
110 memset(s, 0, max);
111 length = 0;
112 }
113 return length;
114 }
116 /* pass-through non-escaped portions of the format string */
117 if (p[0] != '#' && p[0] != '%' && length<max) {
118 s[length++] = *p;
119 p++;
120 continue;
121 }
123 /* let the escape character escape itself */
124 if (p[0] == '#' && p[1] != '\0' && length<max) {
125 s[length++] = *(p+1);
126 p+=2;
127 continue;
128 }
130 /* advance past the esc character */
132 /* find the extent of this format specifier (stop at \0, ' ', or esc) */
133 temp = NULL;
134 end = p+1;
135 while(*end >= 'a' && *end <= 'z') {
136 end++;
137 }
138 n = end - p + 1;
139 if(*end != '%')
140 n--;
141 else if (strncmp("%file%", p, n) == 0)
142 temp = utf8_to_locale(song->file);
143 else if (strncmp("%artist%", p, n) == 0)
144 temp = song->artist ? utf8_to_locale(song->artist) : NULL;
145 else if (strncmp("%title%", p, n) == 0)
146 temp = song->title ? utf8_to_locale(song->title) : NULL;
147 else if (strncmp("%album%", p, n) == 0)
148 temp = song->album ? utf8_to_locale(song->album) : NULL;
149 else if (strncmp("%shortalbum%", p, n) == 0) {
150 temp = song->album ? utf8_to_locale(song->album) : NULL;
151 if (temp) {
152 gchar *temp2 = g_strndup(temp, 25);
153 if (strlen(temp) > 25) {
154 temp2[24] = '.';
155 temp2[23] = '.';
156 temp2[22] = '.';
157 }
158 g_free(temp);
159 temp = temp2;
160 }
161 }
162 else if (strncmp("%track%", p, n) == 0)
163 temp = song->track ? utf8_to_locale(song->track) : NULL;
164 else if (strncmp("%name%", p, n) == 0)
165 temp = song->name ? utf8_to_locale(song->name) : NULL;
166 else if (strncmp("%date%", p, n) == 0)
167 temp = song->date ? utf8_to_locale(song->date) : NULL;
168 else if (strncmp("%genre%", p, n) == 0)
169 temp = song->genre ? utf8_to_locale(song->genre) : NULL;
170 else if (strncmp("%shortfile%", p, n) == 0) {
171 if( strstr(song->file, "://") )
172 temp = utf8_to_locale(song->file);
173 else
174 temp = utf8_to_locale(basename(song->file));
175 } else if (strncmp("%time%", p, n) == 0) {
176 if (song->time != MPD_SONG_NO_TIME) {
177 if (song->time > 3600) {
178 temp = g_strdup_printf("%d:%02d:%02d",
179 song->time / 3600,
180 (song->time % 3600) / 60,
181 song->time % 60);
182 } else {
183 temp = g_strdup_printf("%d:%02d",
184 song->time / 60,
185 song->time % 60);
186 }
187 }
188 }
190 if( temp == NULL) {
191 gsize templen=n;
192 /* just pass-through any unknown specifiers (including esc) */
193 /* drop a null char in so printf stops at the end of this specifier,
194 but put the real character back in (pseudo-const) */
195 if( length+templen > max )
196 templen = max-length;
197 g_strlcat(s, p,max);
198 length+=templen;
199 } else {
200 gsize templen = strlen(temp);
202 found = TRUE;
203 if( length+templen > max )
204 templen = max-length;
205 g_strlcat(s, temp, max);
206 length+=templen;
207 g_free(temp);
208 }
210 /* advance past the specifier */
211 p += n;
212 }
214 if(last) *last = p;
216 return length;
217 }
219 gsize
220 strfsong(gchar *s, gsize max, const gchar *format,
221 const struct mpd_song *song)
222 {
223 return _strfsong(s, max, format, song, NULL);
224 }