Code

way too much stuff to describe here
[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("%shortalbum%", p, n) == 0)
174         {
175           temp = song->album ? utf8_to_locale(song->album) : NULL;
176           if (temp)
177             {
178               gchar *temp2 = g_strndup(temp, 25);
179               if (strlen(temp) > 25)
180                 {
181                   temp2[24] = '.';
182                   temp2[23] = '.';
183                   temp2[22] = '.';
184                 }
185               g_free(temp);
186               temp = temp2;
187             }
188         }
189       else if (strncmp("%track%", p, n) == 0)
190         temp = song->track ? utf8_to_locale(song->track) : NULL;
191       else if (strncmp("%name%", p, n) == 0)
192         temp = song->name ? utf8_to_locale(song->name) : NULL;
193       else if (strncmp("%date%", p, n) == 0)
194         temp = song->date ? utf8_to_locale(song->date) : NULL;
195       else if (strncmp("%genre%", p, n) == 0)
196         temp = song->genre ? utf8_to_locale(song->genre) : NULL;
197       else if (strncmp("%shortfile%", p, n) == 0)
198         {
199           if( strstr(song->file, "://") )
200             temp = utf8_to_locale(song->file);
201           else
202             temp = utf8_to_locale(basename(song->file));
203         }
204       else if (strncmp("%time%", p, n) == 0)
205         {
206           if (song->time != MPD_SONG_NO_TIME) 
207             {
208               if (song->time > 3600)
209                 {
210                   temp = g_strdup_printf("%d:%02d:%02d", 
211                           song->time / 3600, 
212                           (song->time % 3600) / 60, 
213                           song->time % 60);
214                 }
215               else
216                 {
217                   temp = g_strdup_printf("%d:%02d", 
218                           song->time / 60, 
219                           song->time % 60);
220                 }
221             }
222         }
224       if( temp == NULL)
225         {
226           gsize templen=n;
227           /* just pass-through any unknown specifiers (including esc) */
228           /* drop a null char in so printf stops at the end of this specifier,
229              but put the real character back in (pseudo-const) */
230           if( length+templen > max )
231             templen = max-length;
232           g_strlcat(s, p,max);
233           length+=templen;
234         }
235       else {
236         gsize templen = strlen(temp);
238         found = TRUE;
239         if( length+templen > max )
240           templen = max-length;
241         g_strlcat(s, temp, max);
242         length+=templen;
243         g_free(temp);
244       }
246       /* advance past the specifier */
247       p += n;
248     }
250   if(last) *last = p;
252   return length;
255 gsize
256 strfsong(gchar *s, gsize max, const gchar *format, mpd_Song *song)
258   return _strfsong(s, max, format, song, NULL);
260