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