a7eb011f87b77a448e3eaabeaff81e293a3e0559
1 /*
2 * $Id$
3 *
4 */
6 #include <stdio.h>
7 #include <stdlib.h>
8 #include <unistd.h>
9 #include <string.h>
10 #include <glib.h>
12 #include "config.h"
13 #include "libmpdclient.h"
14 #include "ncmpc.h"
15 #include "support.h"
16 #include "strfsong.h"
18 static char *
19 skip(char * p)
20 {
21 int stack = 0;
23 while (*p != '\0') {
24 if(*p == '[') stack++;
25 if(*p == '#' && p[1] != '\0') {
26 /* skip escaped stuff */
27 ++p;
28 }
29 else if(stack) {
30 if(*p == ']') stack--;
31 }
32 else {
33 if(*p == '&' || *p == '|' || *p == ']') {
34 break;
35 }
36 }
37 ++p;
38 }
40 return p;
41 }
43 static gsize
44 _strfsong(gchar *s,
45 gsize max,
46 const gchar *format,
47 mpd_Song *song,
48 gchar **last)
49 {
50 gchar *p, *end;
51 gchar *temp;
52 gsize n, length = 0;
53 gboolean found = FALSE;
55 memset(s, 0, max);
56 if( song==NULL )
57 return 0;
59 for( p=(gchar *) format; *p != '\0' && length<max; )
60 {
61 /* OR */
62 if (p[0] == '|')
63 {
64 ++p;
65 if(!found)
66 {
67 memset(s, 0, max);
68 length = 0;
69 }
70 else
71 {
72 p = skip(p);
73 }
74 continue;
75 }
77 /* AND */
78 if (p[0] == '&')
79 {
80 ++p;
81 if(!found)
82 {
83 p = skip(p);
84 }
85 else
86 {
87 found = FALSE;
88 }
89 continue;
90 }
92 /* EXPRESSION START */
93 if (p[0] == '[')
94 {
95 temp = g_malloc0(max);
96 if( _strfsong(temp, max, p+1, song, &p) >0 )
97 {
98 strncat(s, temp, max-length);
99 length = strlen(s);
100 found = TRUE;
101 }
102 g_free(temp);
103 continue;
104 }
106 /* EXPRESSION END */
107 if (p[0] == ']')
108 {
109 if(last) *last = p+1;
110 if(!found && length)
111 {
112 memset(s, 0, max);
113 length = 0;
114 }
115 return length;
116 }
118 /* pass-through non-escaped portions of the format string */
119 if (p[0] != '#' && p[0] != '%' && length<max)
120 {
121 strncat(s, p, 1);
122 length++;
123 ++p;
124 continue;
125 }
127 /* let the escape character escape itself */
128 if (p[0] == '#' && p[1] != '\0' && length<max)
129 {
130 strncat(s, p+1, 1);
131 length++;
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 {
143 end++;
144 }
145 n = end - p + 1;
146 if(*end != '%')
147 n--;
148 else if (strncmp("%basename%", p, n) == 0)
149 temp = utf8_to_locale(basename(song->file));
150 else if (strncmp("%file%", p, n) == 0)
151 temp = utf8_to_locale(song->file);
152 else if (strncmp("%artist%", p, n) == 0)
153 temp = song->artist ? utf8_to_locale(song->artist) : NULL;
154 else if (strncmp("%title%", p, n) == 0)
155 temp = song->title ? utf8_to_locale(song->title) : NULL;
156 else if (strncmp("%album%", p, n) == 0)
157 temp = song->album ? utf8_to_locale(song->album) : NULL;
158 else if (strncmp("%track%", p, n) == 0)
159 temp = song->track ? utf8_to_locale(song->track) : NULL;
160 else if (strncmp("%name%", p, n) == 0)
161 temp = song->name ? utf8_to_locale(song->name) : NULL;
162 else if (strncmp("%time%", p, n) == 0)
163 {
164 if (song->time != MPD_SONG_NO_TIME) {
165 gchar s[10];
166 snprintf(s, 9, "%d:%d", song->time / 60,
167 song->time % 60 + 1);
168 /* nasty hack to use static buffer */
169 temp = g_strdup(s);
170 }
171 }
173 if( temp == NULL)
174 {
175 gsize templen=n;
176 /* just pass-through any unknown specifiers (including esc) */
177 /* drop a null char in so printf stops at the end of this specifier,
178 but put the real character back in (pseudo-const) */
179 if( length+templen > max )
180 templen = max-length;
181 strncat(s, p, templen);
182 length+=templen;
183 }
184 else {
185 gsize templen = strlen(temp);
187 found = TRUE;
188 if( length+templen > max )
189 templen = max-length;
190 strncat(s, temp, templen);
191 length+=templen;
192 g_free(temp);
193 }
195 /* advance past the specifier */
196 p += n;
197 }
199 if(last) *last = p;
201 return length;
202 }
205 /* a modified version of mpc's songToFormatedString (util.c)
206 * added - %basename%
207 */
209 gsize
210 strfsong(gchar *s, gsize max, const gchar *format, mpd_Song *song)
211 {
212 return _strfsong(s, max, format, song, NULL);
213 }