Code

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