Mercurial > audlegacy
annotate libaudacious/titlestring.c @ 2011:90cc014f8fdc trunk
[svn] - fix for custom format bug. closes #664.
author | yaz |
---|---|
date | Sat, 25 Nov 2006 21:29:05 -0800 |
parents | fda280358660 |
children | e6b15b72feac |
rev | line source |
---|---|
0 | 1 /* |
2 * Copyright (C) 2001, Espen Skoglund <esk@ira.uka.de> | |
3 * Copyright (C) 2001, Haavard Kvaalen <havardk@xmms.org> | |
4 * | |
5 * This program is free software; you can redistribute it and/or | |
6 * modify it under the terms of the GNU General Public License | |
7 * as published by the Free Software Foundation; either version 2 | |
8 * of the License, or (at your option) any later version. | |
9 * | |
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. | |
14 * | |
15 * You should have received a copy of the GNU General Public License | |
16 * along with this program; if not, write to the Free Software | |
1458
f12d7e208b43
[svn] Update FSF address in copyright notices. Update autotools templates.
chainsaw
parents:
1350
diff
changeset
|
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA |
1459 | 18 * 02110-1301, USA. |
0 | 19 * |
20 */ | |
21 | |
22 #ifdef HAVE_CONFIG_H | |
23 # include "config.h" | |
24 #endif | |
25 | |
751 | 26 #define GETTEXT_PACKAGE PACKAGE_NAME |
0 | 27 |
28 #include <glib.h> | |
29 #include <glib/gi18n-lib.h> | |
30 #include <gtk/gtk.h> | |
31 #include <stdio.h> | |
32 #include <string.h> | |
33 | |
34 #include "titlestring.h" | |
35 | |
36 #define CHECK(input, field) \ | |
37 (((gchar *) &input->field - (gchar *) input) < input->__size) | |
38 | |
39 #define VS(input, field) (CHECK(input, field) ? input->field : NULL) | |
40 #define VI(input, field) (CHECK(input, field) ? input->field : 0) | |
41 | |
42 | |
43 BmpTitleInput * | |
44 bmp_title_input_new() | |
45 { | |
46 BmpTitleInput *input; | |
47 input = g_new0(BmpTitleInput, 1); | |
48 input->__size = XMMS_TITLEINPUT_SIZE; | |
49 input->__version = XMMS_TITLEINPUT_VERSION; | |
50 return input; | |
51 } | |
52 | |
53 void | |
54 bmp_title_input_free(BmpTitleInput * input) | |
55 { | |
1350
ca5d03c4b3f1
[svn] - extra sanity checking keeps the double-free away
nenolod
parents:
751
diff
changeset
|
56 if (input == NULL) |
0 | 57 return; |
58 | |
1350
ca5d03c4b3f1
[svn] - extra sanity checking keeps the double-free away
nenolod
parents:
751
diff
changeset
|
59 if (input->performer != NULL) |
ca5d03c4b3f1
[svn] - extra sanity checking keeps the double-free away
nenolod
parents:
751
diff
changeset
|
60 g_free(input->performer); |
ca5d03c4b3f1
[svn] - extra sanity checking keeps the double-free away
nenolod
parents:
751
diff
changeset
|
61 |
ca5d03c4b3f1
[svn] - extra sanity checking keeps the double-free away
nenolod
parents:
751
diff
changeset
|
62 if (input->album_name != NULL) |
ca5d03c4b3f1
[svn] - extra sanity checking keeps the double-free away
nenolod
parents:
751
diff
changeset
|
63 g_free(input->album_name); |
ca5d03c4b3f1
[svn] - extra sanity checking keeps the double-free away
nenolod
parents:
751
diff
changeset
|
64 |
ca5d03c4b3f1
[svn] - extra sanity checking keeps the double-free away
nenolod
parents:
751
diff
changeset
|
65 if (input->track_name != NULL) |
ca5d03c4b3f1
[svn] - extra sanity checking keeps the double-free away
nenolod
parents:
751
diff
changeset
|
66 g_free(input->track_name); |
ca5d03c4b3f1
[svn] - extra sanity checking keeps the double-free away
nenolod
parents:
751
diff
changeset
|
67 |
ca5d03c4b3f1
[svn] - extra sanity checking keeps the double-free away
nenolod
parents:
751
diff
changeset
|
68 if (input->date != NULL) |
ca5d03c4b3f1
[svn] - extra sanity checking keeps the double-free away
nenolod
parents:
751
diff
changeset
|
69 g_free(input->date); |
ca5d03c4b3f1
[svn] - extra sanity checking keeps the double-free away
nenolod
parents:
751
diff
changeset
|
70 |
ca5d03c4b3f1
[svn] - extra sanity checking keeps the double-free away
nenolod
parents:
751
diff
changeset
|
71 if (input->genre != NULL) |
ca5d03c4b3f1
[svn] - extra sanity checking keeps the double-free away
nenolod
parents:
751
diff
changeset
|
72 g_free(input->genre); |
ca5d03c4b3f1
[svn] - extra sanity checking keeps the double-free away
nenolod
parents:
751
diff
changeset
|
73 |
ca5d03c4b3f1
[svn] - extra sanity checking keeps the double-free away
nenolod
parents:
751
diff
changeset
|
74 if (input->comment != NULL) |
ca5d03c4b3f1
[svn] - extra sanity checking keeps the double-free away
nenolod
parents:
751
diff
changeset
|
75 g_free(input->comment); |
ca5d03c4b3f1
[svn] - extra sanity checking keeps the double-free away
nenolod
parents:
751
diff
changeset
|
76 |
ca5d03c4b3f1
[svn] - extra sanity checking keeps the double-free away
nenolod
parents:
751
diff
changeset
|
77 if (input->file_name != NULL) |
ca5d03c4b3f1
[svn] - extra sanity checking keeps the double-free away
nenolod
parents:
751
diff
changeset
|
78 g_free(input->file_name); |
ca5d03c4b3f1
[svn] - extra sanity checking keeps the double-free away
nenolod
parents:
751
diff
changeset
|
79 |
ca5d03c4b3f1
[svn] - extra sanity checking keeps the double-free away
nenolod
parents:
751
diff
changeset
|
80 if (input->file_path != NULL) |
ca5d03c4b3f1
[svn] - extra sanity checking keeps the double-free away
nenolod
parents:
751
diff
changeset
|
81 g_free(input->file_path); |
ca5d03c4b3f1
[svn] - extra sanity checking keeps the double-free away
nenolod
parents:
751
diff
changeset
|
82 |
0 | 83 g_free(input); |
84 } | |
85 | |
86 gchar * | |
87 xmms_get_titlestring(const gchar * fmt, TitleInput * input) | |
88 { | |
89 GString *outstr; | |
90 const gchar *string; | |
91 gchar c, convert[16]; | |
92 gint numdigits, numpr, val, i; | |
93 gint f_left, f_space, f_zero, someflag, width, precision; | |
94 gboolean did_output = FALSE; | |
95 gchar digits[] = "0123456789"; | |
96 | |
97 #define PUTCH(ch) g_string_append_c(outstr, ch) | |
98 | |
99 #define LEFTPAD(num) \ | |
100 G_STMT_START { \ | |
101 gint cnt = (num); \ | |
102 if ( ! f_left && cnt > 0 ) \ | |
103 while ( cnt-- > 0 ) \ | |
104 PUTCH(f_zero ? '0' : ' '); \ | |
105 } G_STMT_END; | |
106 | |
107 #define RIGHTPAD(num) \ | |
108 G_STMT_START { \ | |
109 gint cnt = (num); \ | |
110 if ( f_left && cnt > 0 ) \ | |
111 while ( cnt-- > 0 ) \ | |
112 PUTCH( ' ' ); \ | |
113 } G_STMT_END; | |
114 | |
1658 | 115 if (fmt == NULL || input == NULL) |
0 | 116 return NULL; |
117 outstr = g_string_new(""); | |
118 | |
119 for (;;) { | |
120 /* Copy characters until we encounter '%'. */ | |
121 while ((c = *fmt++) != '%') { | |
122 if (c == '\0') | |
123 goto Done; | |
124 g_string_append_c(outstr, c); | |
125 } | |
126 | |
127 f_left = f_space = f_zero = 0; | |
128 someflag = 1; | |
129 | |
130 | |
131 /* Parse flags. */ | |
132 while (someflag) { | |
133 switch (*fmt) { | |
134 case '-': | |
135 f_left = 1; | |
136 fmt++; | |
137 break; | |
138 case ' ': | |
139 f_space = 1; | |
140 fmt++; | |
141 break; | |
142 case '0': | |
143 f_zero = 1; | |
144 fmt++; | |
145 break; | |
146 default: | |
147 someflag = 0; | |
148 break; | |
149 } | |
150 } | |
151 | |
152 | |
153 /* Parse field width. */ | |
154 if ((c = *fmt) >= '0' && c <= '9') { | |
155 width = 0; | |
156 while ((c = *fmt++) >= '0' && c <= '9') { | |
157 width *= 10; | |
158 width += c - '0'; | |
159 } | |
160 fmt--; | |
161 } | |
162 else | |
163 width = -1; | |
164 | |
165 | |
166 /* Parse precision. */ | |
167 if (*fmt == '.') { | |
168 if ((c = *++fmt) >= '0' && c <= '9') { | |
169 precision = 0; | |
170 while ((c = *fmt++) >= '0' && c <= '9') { | |
171 precision *= 10; | |
172 precision += c - '0'; | |
173 } | |
174 fmt--; | |
175 } | |
176 else | |
177 precision = -1; | |
178 } | |
179 else | |
180 precision = -1; | |
181 | |
182 | |
183 /* Parse format conversion. */ | |
184 switch (c = *fmt++) { | |
185 case '}': /* close optional, just ignore */ | |
186 continue; | |
187 | |
188 case '{':{ /* optional entry: %{n:...%} */ | |
189 char n = *fmt++; | |
190 if (!((n == 'a' && VS(input, album_name)) || | |
191 (n == 'c' && VS(input, comment)) || | |
192 (n == 'd' && VS(input, date)) || | |
193 (n == 'e' && VS(input, file_ext)) || | |
194 (n == 'f' && VS(input, file_name)) || | |
195 (n == 'F' && VS(input, file_path)) || | |
196 (n == 'g' && VS(input, genre)) || | |
197 (n == 'n' && VI(input, track_number)) || | |
198 (n == 'p' && VS(input, performer)) || | |
2011 | 199 (n == 't' && VS(input, track_name)) || |
200 (n == 'y' && VI(input, year)))) { | |
0 | 201 int nl = 0; |
202 char c; | |
203 while ((c = *fmt++)) /* until end of string */ | |
204 if (c == '}') /* if end of opt */ | |
205 if (!nl) | |
206 break; /* if outmost indent level */ | |
207 else | |
208 --nl; /* else reduce indent */ | |
209 else if (c == '{') | |
210 ++nl; /* increase indent */ | |
211 } | |
212 else | |
213 ++fmt; | |
214 break; | |
215 } | |
216 | |
217 case 'a': | |
218 string = VS(input, album_name); | |
219 goto Print_string; | |
220 case 'c': | |
221 string = VS(input, comment); | |
222 goto Print_string; | |
223 case 'd': | |
224 string = VS(input, date); | |
225 goto Print_string; | |
226 case 'e': | |
227 string = VS(input, file_ext); | |
228 goto Print_string; | |
229 case 'f': | |
230 string = VS(input, file_name); | |
231 goto Print_string; | |
232 case 'F': | |
233 string = VS(input, file_path); | |
234 goto Print_string; | |
235 case 'g': | |
236 string = VS(input, genre); | |
237 goto Print_string; | |
238 case 'n': | |
239 val = VI(input, track_number); | |
240 goto Print_number; | |
241 case 'p': | |
242 string = VS(input, performer); | |
243 goto Print_string; | |
244 case 't': | |
245 string = VS(input, track_name); | |
2011 | 246 goto Print_string; |
247 case 'y': | |
248 val = VI(input, year); | |
249 goto Print_number; | |
0 | 250 |
251 Print_string: | |
252 if (string == NULL) | |
253 break; | |
254 did_output = TRUE; | |
255 | |
256 numpr = 0; | |
257 if (width > 0) { | |
258 /* Calculate printed size. */ | |
259 numpr = strlen(string); | |
260 if (precision >= 0 && precision < numpr) | |
261 numpr = precision; | |
262 | |
263 LEFTPAD(width - numpr); | |
264 } | |
265 | |
266 /* Insert string. */ | |
267 if (precision >= 0) { | |
1594
44f67f556b60
[svn] - precision in title format is regarded as character count, not byte count.
yaz
parents:
1459
diff
changeset
|
268 glong offset_max = precision, offset; |
44f67f556b60
[svn] - precision in title format is regarded as character count, not byte count.
yaz
parents:
1459
diff
changeset
|
269 gchar *uptr = NULL; |
44f67f556b60
[svn] - precision in title format is regarded as character count, not byte count.
yaz
parents:
1459
diff
changeset
|
270 const gchar *tmpstring = string; |
44f67f556b60
[svn] - precision in title format is regarded as character count, not byte count.
yaz
parents:
1459
diff
changeset
|
271 while (precision > 0) { |
44f67f556b60
[svn] - precision in title format is regarded as character count, not byte count.
yaz
parents:
1459
diff
changeset
|
272 offset = offset_max - precision; |
44f67f556b60
[svn] - precision in title format is regarded as character count, not byte count.
yaz
parents:
1459
diff
changeset
|
273 uptr = g_utf8_offset_to_pointer(tmpstring, offset); |
44f67f556b60
[svn] - precision in title format is regarded as character count, not byte count.
yaz
parents:
1459
diff
changeset
|
274 if (*uptr == '\0') |
44f67f556b60
[svn] - precision in title format is regarded as character count, not byte count.
yaz
parents:
1459
diff
changeset
|
275 break; |
44f67f556b60
[svn] - precision in title format is regarded as character count, not byte count.
yaz
parents:
1459
diff
changeset
|
276 g_string_append_unichar(outstr, g_utf8_get_char(uptr)); |
44f67f556b60
[svn] - precision in title format is regarded as character count, not byte count.
yaz
parents:
1459
diff
changeset
|
277 precision--; |
44f67f556b60
[svn] - precision in title format is regarded as character count, not byte count.
yaz
parents:
1459
diff
changeset
|
278 } |
0 | 279 } |
280 else { | |
281 while ((c = *string++) != '\0') | |
282 PUTCH(c); | |
283 } | |
284 | |
285 RIGHTPAD(width - numpr); | |
286 break; | |
287 | |
288 Print_number: | |
289 if (val == 0) | |
290 break; | |
291 if (c != 'N') | |
292 did_output = TRUE; | |
293 | |
294 /* Create reversed number string. */ | |
295 numdigits = 0; | |
296 do { | |
297 convert[numdigits++] = digits[val % 10]; | |
298 val /= 10; | |
299 } | |
300 while (val > 0); | |
301 | |
302 numpr = numdigits > precision ? numdigits : precision; | |
303 | |
304 /* Insert left padding. */ | |
305 if (!f_left && width > numpr) { | |
306 if (f_zero) | |
307 numpr = width; | |
308 else | |
309 for (i = width - numpr; i-- > 0;) | |
310 PUTCH(' '); | |
311 } | |
312 | |
313 /* Insert zero padding. */ | |
314 for (i = numpr - numdigits; i-- > 0;) | |
315 PUTCH('0'); | |
316 | |
317 /* Insert number. */ | |
318 while (numdigits > 0) | |
319 PUTCH(convert[--numdigits]); | |
320 | |
321 RIGHTPAD(width - numpr); | |
322 break; | |
323 | |
324 case '%': | |
325 PUTCH('%'); | |
326 break; | |
327 | |
328 default: | |
329 PUTCH('%'); | |
330 PUTCH(c); | |
331 break; | |
332 } | |
333 } | |
334 | |
335 Done: | |
336 if (did_output) | |
337 return g_string_free(outstr, FALSE); | |
338 else | |
339 return NULL; | |
340 } | |
341 | |
342 struct _TagDescription { | |
343 gchar tag; | |
344 gchar *description; | |
345 }; | |
346 | |
347 typedef struct _TagDescription TagDescription; | |
348 | |
349 static TagDescription tag_descriptions[] = { | |
350 {'p', N_("Performer/Artist")}, | |
351 {'a', N_("Album")}, | |
352 {'g', N_("Genre")}, | |
353 {'f', N_("File name")}, | |
354 {'F', N_("File path")}, | |
355 {'e', N_("File extension")}, | |
356 {'t', N_("Track name")}, | |
357 {'n', N_("Track number")}, | |
358 {'d', N_("Date")}, | |
359 {'y', N_("Year")}, | |
360 {'c', N_("Comment")} | |
361 }; | |
362 | |
363 gint tag_descriptions_length = | |
364 sizeof(tag_descriptions) / sizeof(TagDescription); | |
365 | |
366 GtkWidget * | |
367 xmms_titlestring_descriptions(gchar * tags, gint columns) | |
368 { | |
369 GtkWidget *table, *label; | |
370 gchar tag_str[5]; | |
371 gint num = strlen(tags); | |
372 gint r = 0, c, i; | |
373 | |
374 g_return_val_if_fail(tags != NULL, NULL); | |
375 g_return_val_if_fail(columns <= num, NULL); | |
376 | |
377 table = gtk_table_new((num + columns - 1) / columns, columns * 2, FALSE); | |
378 gtk_table_set_row_spacings(GTK_TABLE(table), 2); | |
379 gtk_table_set_col_spacings(GTK_TABLE(table), 5); | |
380 | |
381 for (c = 0; c < columns; c++) { | |
382 for (r = 0; r < (num + columns - 1 - c) / columns; r++) { | |
383 g_snprintf(tag_str, sizeof(tag_str), "%%%c:", *tags); | |
384 label = gtk_label_new(tag_str); | |
385 gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5); | |
386 gtk_table_attach(GTK_TABLE(table), label, 2 * c, 2 * c + 1, r, | |
387 r + 1, GTK_FILL, GTK_FILL, 0, 0); | |
388 gtk_widget_show(label); | |
389 | |
390 for (i = 0; i < tag_descriptions_length; i++) { | |
391 if (*tags == tag_descriptions[i].tag) { | |
392 label = gtk_label_new(_(tag_descriptions[i].description)); | |
393 gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5); | |
394 gtk_table_attach(GTK_TABLE(table), label, 2 * c + 1, | |
395 2 * c + 2, r, r + 1, | |
396 GTK_EXPAND | GTK_FILL, | |
397 GTK_EXPAND | GTK_FILL, 0, 0); | |
398 gtk_widget_show(label); | |
399 break; | |
400 } | |
401 } | |
402 | |
403 if (i == tag_descriptions_length) | |
404 g_warning("Invalid tag: %c", *tags); | |
405 | |
406 tags++; | |
407 } | |
408 | |
409 } | |
410 | |
411 label = gtk_label_new(_("%{n:...%}: Display \"...\" only if element " | |
412 "%n is present")); | |
413 gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5); | |
414 gtk_table_attach(GTK_TABLE(table), label, 0, r + 1, | |
415 r + 1, r + 2, GTK_FILL, GTK_FILL, 0, 0); | |
416 gtk_widget_show(label); | |
417 | |
418 return table; | |
419 } |