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