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