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