Code

Update copyright notices
[ncmpc.git] / src / strfsong.c
1 /* ncmpc (Ncurses MPD Client)
2  * (c) 2004-2009 The Music Player Daemon Project
3  * Project homepage: http://musicpd.org
4  
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
15  * You should have received a copy of the GNU General Public License along
16  * with this program; if not, write to the Free Software Foundation, Inc.,
17  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
20 #include "strfsong.h"
21 #include "charset.h"
23 #include <string.h>
25 static const gchar *
26 skip(const gchar * p)
27 {
28         gint stack = 0;
30         while (*p != '\0') {
31                 if (*p == '[')
32                         stack++;
33                 if (*p == '#' && p[1] != '\0') {
34                         /* skip escaped stuff */
35                         ++p;
36                 } else if (stack) {
37                         if(*p == ']') stack--;
38                 } else {
39                         if(*p == '&' || *p == '|' || *p == ']') {
40                                 break;
41                         }
42                 }
43                 ++p;
44         }
46         return p;
47 }
49 static gsize
50 _strfsong(gchar *s,
51           gsize max,
52           const gchar *format,
53           const struct mpd_song *song,
54           const gchar **last)
55 {
56         const gchar *p, *end;
57         gchar *temp;
58         gsize n, length = 0;
59         gboolean found = FALSE;
61         memset(s, 0, max);
62         if (song == NULL)
63                 return 0;
65         for (p = format; *p != '\0' && length<max;) {
66                 /* OR */
67                 if (p[0] == '|') {
68                         ++p;
69                         if(!found) {
70                                 memset(s, 0, max);
71                                 length = 0;
72                         } else {
73                                 p = skip(p);
74                         }
75                         continue;
76                 }
78                 /* AND */
79                 if (p[0] == '&') {
80                         ++p;
81                         if(!found) {
82                                 p = skip(p);
83                         } else {
84                                 found = FALSE;
85                         }
86                         continue;
87                 }
89                 /* EXPRESSION START */
90                 if (p[0] == '[') {
91                         temp = g_malloc0(max);
92                         if( _strfsong(temp, max, p+1, song, &p) >0 ) {
93                                 g_strlcat(s, temp, max);
94                                 length = strlen(s);
95                                 found = TRUE;
96                         }
97                         g_free(temp);
98                         continue;
99                 }
101                 /* EXPRESSION END */
102                 if (p[0] == ']') {
103                         if(last) *last = p+1;
104                         if(!found && length) {
105                                 memset(s, 0, max);
106                                 length = 0;
107                         }
108                         return length;
109                 }
111                 /* pass-through non-escaped portions of the format string */
112                 if (p[0] != '#' && p[0] != '%' && length<max) {
113                         s[length++] = *p;
114                         p++;
115                         continue;
116                 }
118                 /* let the escape character escape itself */
119                 if (p[0] == '#' && p[1] != '\0' && length<max) {
120                         s[length++] = *(p+1);
121                         p+=2;
122                         continue;
123                 }
125                 /* advance past the esc character */
127                 /* find the extent of this format specifier (stop at \0, ' ', or esc) */
128                 temp = NULL;
129                 end  = p+1;
130                 while(*end >= 'a' && *end <= 'z') {
131                         end++;
132                 }
133                 n = end - p + 1;
134                 if(*end != '%')
135                         n--;
136                 else if (strncmp("%file%", p, n) == 0)
137                         temp = utf8_to_locale(song->file);
138                 else if (strncmp("%artist%", p, n) == 0)
139                         temp = song->artist ? utf8_to_locale(song->artist) : NULL;
140                 else if (strncmp("%title%", p, n) == 0)
141                         temp = song->title ? utf8_to_locale(song->title) : NULL;
142                 else if (strncmp("%album%", p, n) == 0)
143                         temp = song->album ? utf8_to_locale(song->album) : NULL;
144                 else if (strncmp("%shortalbum%", p, n) == 0) {
145                         temp = song->album ? utf8_to_locale(song->album) : NULL;
146                         if (temp) {
147                                 gchar *temp2 = g_strndup(temp, 25);
148                                 if (strlen(temp) > 25) {
149                                         temp2[24] = '.';
150                                         temp2[23] = '.';
151                                         temp2[22] = '.';
152                                 }
153                                 g_free(temp);
154                                 temp = temp2;
155                         }
156                 }
157                 else if (strncmp("%track%", p, n) == 0)
158                         temp = song->track ? utf8_to_locale(song->track) : NULL;
159                 else if (strncmp("%name%", p, n) == 0)
160                         temp = song->name ? utf8_to_locale(song->name) : NULL;
161                 else if (strncmp("%date%", p, n) == 0)
162                         temp = song->date ? utf8_to_locale(song->date) : NULL;
163                 else if (strncmp("%genre%", p, n) == 0)
164                         temp = song->genre ? utf8_to_locale(song->genre) : NULL;
165                 else if (strncmp("%shortfile%", p, n) == 0) {
166                         if( strstr(song->file, "://") )
167                                 temp = utf8_to_locale(song->file);
168                         else
169                                 temp = utf8_to_locale(g_basename(song->file));
170                 } else if (strncmp("%time%", p, n) == 0) {
171                         if (song->time != MPD_SONG_NO_TIME)  {
172                                 if (song->time > 3600) {
173                                         temp = g_strdup_printf("%d:%02d:%02d",
174                                                                song->time / 3600,
175                                                                (song->time % 3600) / 60,
176                                                                song->time % 60);
177                                 } else {
178                                         temp = g_strdup_printf("%d:%02d",
179                                                                song->time / 60,
180                                                                song->time % 60);
181                                 }
182                         }
183                 }
185                 if( temp == NULL) {
186                         gsize templen=n;
187                         /* just pass-through any unknown specifiers (including esc) */
188                         /* drop a null char in so printf stops at the end of this specifier,
189                            but put the real character back in (pseudo-const) */
190                         if( length+templen > max )
191                                 templen = max-length;
192                         g_strlcat(s, p,max);
193                         length+=templen;
194                 } else {
195                         gsize templen = strlen(temp);
197                         found = TRUE;
198                         if( length+templen > max )
199                                 templen = max-length;
200                         g_strlcat(s, temp, max);
201                         length+=templen;
202                         g_free(temp);
203                 }
205                 /* advance past the specifier */
206                 p += n;
207         }
209         if(last) *last = p;
211         return length;
214 gsize
215 strfsong(gchar *s, gsize max, const gchar *format,
216          const struct mpd_song *song)
218         return _strfsong(s, max, format, song, NULL);