Code

Major cleanup of the mpd client code (mpc->mpdclient)
[ncmpc.git] / src / strfsong.c
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;
22  
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;
58   
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;
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)
212   return _strfsong(s, max, format, song, NULL);
214