Mercurial > audlegacy
annotate libaudacious/titlestring.c @ 2065:598564ddc4e9 trunk
[svn] - no, this is not going to work
| author | nenolod |
|---|---|
| date | Thu, 07 Dec 2006 00:22:55 -0800 |
| parents | 27aa778eb73c |
| children |
| 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 | |
| 2050 | 42 /** |
| 43 * bmp_title_input_new: | |
| 44 * | |
| 45 * #BmpTitleInput tuple factory. | |
| 2051 | 46 * |
| 47 * Return value: A #BmpTitleInput object. | |
| 2050 | 48 **/ |
| 0 | 49 BmpTitleInput * |
| 50 bmp_title_input_new() | |
| 51 { | |
| 52 BmpTitleInput *input; | |
| 53 input = g_new0(BmpTitleInput, 1); | |
| 54 input->__size = XMMS_TITLEINPUT_SIZE; | |
| 55 input->__version = XMMS_TITLEINPUT_VERSION; | |
| 56 return input; | |
| 57 } | |
| 58 | |
| 2050 | 59 /** |
| 60 * bmp_title_input_free: | |
| 61 * @input: A #BmpTitleInput tuple to destroy. | |
| 62 * | |
| 63 * Destroys a #BmpTitleInput tuple. | |
| 64 **/ | |
| 0 | 65 void |
| 66 bmp_title_input_free(BmpTitleInput * input) | |
| 67 { | |
|
1350
ca5d03c4b3f1
[svn] - extra sanity checking keeps the double-free away
nenolod
parents:
751
diff
changeset
|
68 if (input == NULL) |
| 0 | 69 return; |
| 70 | |
|
1350
ca5d03c4b3f1
[svn] - extra sanity checking keeps the double-free away
nenolod
parents:
751
diff
changeset
|
71 if (input->performer != NULL) |
|
ca5d03c4b3f1
[svn] - extra sanity checking keeps the double-free away
nenolod
parents:
751
diff
changeset
|
72 g_free(input->performer); |
|
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->album_name != NULL) |
|
ca5d03c4b3f1
[svn] - extra sanity checking keeps the double-free away
nenolod
parents:
751
diff
changeset
|
75 g_free(input->album_name); |
|
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->track_name != NULL) |
|
ca5d03c4b3f1
[svn] - extra sanity checking keeps the double-free away
nenolod
parents:
751
diff
changeset
|
78 g_free(input->track_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->date != NULL) |
|
ca5d03c4b3f1
[svn] - extra sanity checking keeps the double-free away
nenolod
parents:
751
diff
changeset
|
81 g_free(input->date); |
|
ca5d03c4b3f1
[svn] - extra sanity checking keeps the double-free away
nenolod
parents:
751
diff
changeset
|
82 |
|
ca5d03c4b3f1
[svn] - extra sanity checking keeps the double-free away
nenolod
parents:
751
diff
changeset
|
83 if (input->genre != NULL) |
|
ca5d03c4b3f1
[svn] - extra sanity checking keeps the double-free away
nenolod
parents:
751
diff
changeset
|
84 g_free(input->genre); |
|
ca5d03c4b3f1
[svn] - extra sanity checking keeps the double-free away
nenolod
parents:
751
diff
changeset
|
85 |
|
ca5d03c4b3f1
[svn] - extra sanity checking keeps the double-free away
nenolod
parents:
751
diff
changeset
|
86 if (input->comment != NULL) |
|
ca5d03c4b3f1
[svn] - extra sanity checking keeps the double-free away
nenolod
parents:
751
diff
changeset
|
87 g_free(input->comment); |
|
ca5d03c4b3f1
[svn] - extra sanity checking keeps the double-free away
nenolod
parents:
751
diff
changeset
|
88 |
|
ca5d03c4b3f1
[svn] - extra sanity checking keeps the double-free away
nenolod
parents:
751
diff
changeset
|
89 if (input->file_name != NULL) |
|
ca5d03c4b3f1
[svn] - extra sanity checking keeps the double-free away
nenolod
parents:
751
diff
changeset
|
90 g_free(input->file_name); |
|
ca5d03c4b3f1
[svn] - extra sanity checking keeps the double-free away
nenolod
parents:
751
diff
changeset
|
91 |
|
ca5d03c4b3f1
[svn] - extra sanity checking keeps the double-free away
nenolod
parents:
751
diff
changeset
|
92 if (input->file_path != NULL) |
|
ca5d03c4b3f1
[svn] - extra sanity checking keeps the double-free away
nenolod
parents:
751
diff
changeset
|
93 g_free(input->file_path); |
|
ca5d03c4b3f1
[svn] - extra sanity checking keeps the double-free away
nenolod
parents:
751
diff
changeset
|
94 |
| 0 | 95 g_free(input); |
| 96 } | |
| 97 | |
| 2050 | 98 /** |
| 99 * xmms_get_titlestring: | |
| 100 * @fmt: A format string. | |
| 101 * @input: A tuple to use for data. | |
| 102 * | |
| 103 * Generates a formatted string from a tuple. | |
| 104 * | |
| 105 * Return value: A formatted tuple string. | |
| 106 **/ | |
| 0 | 107 gchar * |
| 108 xmms_get_titlestring(const gchar * fmt, TitleInput * input) | |
| 109 { | |
| 110 GString *outstr; | |
| 111 const gchar *string; | |
| 112 gchar c, convert[16]; | |
| 113 gint numdigits, numpr, val, i; | |
| 114 gint f_left, f_space, f_zero, someflag, width, precision; | |
| 115 gboolean did_output = FALSE; | |
| 116 gchar digits[] = "0123456789"; | |
| 117 | |
| 118 #define PUTCH(ch) g_string_append_c(outstr, ch) | |
| 119 | |
| 120 #define LEFTPAD(num) \ | |
| 121 G_STMT_START { \ | |
| 122 gint cnt = (num); \ | |
| 123 if ( ! f_left && cnt > 0 ) \ | |
| 124 while ( cnt-- > 0 ) \ | |
| 125 PUTCH(f_zero ? '0' : ' '); \ | |
| 126 } G_STMT_END; | |
| 127 | |
| 128 #define RIGHTPAD(num) \ | |
| 129 G_STMT_START { \ | |
| 130 gint cnt = (num); \ | |
| 131 if ( f_left && cnt > 0 ) \ | |
| 132 while ( cnt-- > 0 ) \ | |
| 133 PUTCH( ' ' ); \ | |
| 134 } G_STMT_END; | |
| 135 | |
| 1658 | 136 if (fmt == NULL || input == NULL) |
| 0 | 137 return NULL; |
| 138 outstr = g_string_new(""); | |
| 139 | |
| 140 for (;;) { | |
| 141 /* Copy characters until we encounter '%'. */ | |
| 142 while ((c = *fmt++) != '%') { | |
| 143 if (c == '\0') | |
| 144 goto Done; | |
| 145 g_string_append_c(outstr, c); | |
| 146 } | |
| 147 | |
| 148 f_left = f_space = f_zero = 0; | |
| 149 someflag = 1; | |
| 150 | |
| 151 | |
| 152 /* Parse flags. */ | |
| 153 while (someflag) { | |
| 154 switch (*fmt) { | |
| 155 case '-': | |
| 156 f_left = 1; | |
| 157 fmt++; | |
| 158 break; | |
| 159 case ' ': | |
| 160 f_space = 1; | |
| 161 fmt++; | |
| 162 break; | |
| 163 case '0': | |
| 164 f_zero = 1; | |
| 165 fmt++; | |
| 166 break; | |
| 167 default: | |
| 168 someflag = 0; | |
| 169 break; | |
| 170 } | |
| 171 } | |
| 172 | |
| 173 | |
| 174 /* Parse field width. */ | |
| 175 if ((c = *fmt) >= '0' && c <= '9') { | |
| 176 width = 0; | |
| 177 while ((c = *fmt++) >= '0' && c <= '9') { | |
| 178 width *= 10; | |
| 179 width += c - '0'; | |
| 180 } | |
| 181 fmt--; | |
| 182 } | |
| 183 else | |
| 184 width = -1; | |
| 185 | |
| 186 | |
| 187 /* Parse precision. */ | |
| 188 if (*fmt == '.') { | |
| 189 if ((c = *++fmt) >= '0' && c <= '9') { | |
| 190 precision = 0; | |
| 191 while ((c = *fmt++) >= '0' && c <= '9') { | |
| 192 precision *= 10; | |
| 193 precision += c - '0'; | |
| 194 } | |
| 195 fmt--; | |
| 196 } | |
| 197 else | |
| 198 precision = -1; | |
| 199 } | |
| 200 else | |
| 201 precision = -1; | |
| 202 | |
| 203 | |
| 204 /* Parse format conversion. */ | |
| 205 switch (c = *fmt++) { | |
| 206 case '}': /* close optional, just ignore */ | |
| 207 continue; | |
| 208 | |
| 209 case '{':{ /* optional entry: %{n:...%} */ | |
| 210 char n = *fmt++; | |
| 211 if (!((n == 'a' && VS(input, album_name)) || | |
| 212 (n == 'c' && VS(input, comment)) || | |
| 213 (n == 'd' && VS(input, date)) || | |
| 214 (n == 'e' && VS(input, file_ext)) || | |
| 215 (n == 'f' && VS(input, file_name)) || | |
| 216 (n == 'F' && VS(input, file_path)) || | |
| 217 (n == 'g' && VS(input, genre)) || | |
| 218 (n == 'n' && VI(input, track_number)) || | |
| 219 (n == 'p' && VS(input, performer)) || | |
| 2011 | 220 (n == 't' && VS(input, track_name)) || |
| 221 (n == 'y' && VI(input, year)))) { | |
| 0 | 222 int nl = 0; |
| 223 char c; | |
| 224 while ((c = *fmt++)) /* until end of string */ | |
| 225 if (c == '}') /* if end of opt */ | |
| 226 if (!nl) | |
| 227 break; /* if outmost indent level */ | |
| 228 else | |
| 229 --nl; /* else reduce indent */ | |
| 230 else if (c == '{') | |
| 231 ++nl; /* increase indent */ | |
| 232 } | |
| 233 else | |
| 234 ++fmt; | |
| 235 break; | |
| 236 } | |
| 237 | |
| 238 case 'a': | |
| 239 string = VS(input, album_name); | |
| 240 goto Print_string; | |
| 241 case 'c': | |
| 242 string = VS(input, comment); | |
| 243 goto Print_string; | |
| 244 case 'd': | |
| 245 string = VS(input, date); | |
| 246 goto Print_string; | |
| 247 case 'e': | |
| 248 string = VS(input, file_ext); | |
| 249 goto Print_string; | |
| 250 case 'f': | |
| 251 string = VS(input, file_name); | |
| 252 goto Print_string; | |
| 253 case 'F': | |
| 254 string = VS(input, file_path); | |
| 255 goto Print_string; | |
| 256 case 'g': | |
| 257 string = VS(input, genre); | |
| 258 goto Print_string; | |
| 259 case 'n': | |
| 260 val = VI(input, track_number); | |
| 261 goto Print_number; | |
| 262 case 'p': | |
| 263 string = VS(input, performer); | |
| 264 goto Print_string; | |
| 265 case 't': | |
| 266 string = VS(input, track_name); | |
| 2011 | 267 goto Print_string; |
| 268 case 'y': | |
| 269 val = VI(input, year); | |
| 270 goto Print_number; | |
| 0 | 271 |
| 272 Print_string: | |
| 273 if (string == NULL) | |
| 274 break; | |
| 275 did_output = TRUE; | |
| 276 | |
| 277 numpr = 0; | |
| 278 if (width > 0) { | |
| 279 /* Calculate printed size. */ | |
| 280 numpr = strlen(string); | |
| 281 if (precision >= 0 && precision < numpr) | |
| 282 numpr = precision; | |
| 283 | |
| 284 LEFTPAD(width - numpr); | |
| 285 } | |
| 286 | |
| 287 /* Insert string. */ | |
| 288 if (precision >= 0) { | |
|
1594
44f67f556b60
[svn] - precision in title format is regarded as character count, not byte count.
yaz
parents:
1459
diff
changeset
|
289 glong offset_max = precision, offset; |
|
44f67f556b60
[svn] - precision in title format is regarded as character count, not byte count.
yaz
parents:
1459
diff
changeset
|
290 gchar *uptr = NULL; |
|
44f67f556b60
[svn] - precision in title format is regarded as character count, not byte count.
yaz
parents:
1459
diff
changeset
|
291 const gchar *tmpstring = string; |
|
44f67f556b60
[svn] - precision in title format is regarded as character count, not byte count.
yaz
parents:
1459
diff
changeset
|
292 while (precision > 0) { |
|
44f67f556b60
[svn] - precision in title format is regarded as character count, not byte count.
yaz
parents:
1459
diff
changeset
|
293 offset = offset_max - precision; |
|
44f67f556b60
[svn] - precision in title format is regarded as character count, not byte count.
yaz
parents:
1459
diff
changeset
|
294 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
|
295 if (*uptr == '\0') |
|
44f67f556b60
[svn] - precision in title format is regarded as character count, not byte count.
yaz
parents:
1459
diff
changeset
|
296 break; |
|
44f67f556b60
[svn] - precision in title format is regarded as character count, not byte count.
yaz
parents:
1459
diff
changeset
|
297 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
|
298 precision--; |
|
44f67f556b60
[svn] - precision in title format is regarded as character count, not byte count.
yaz
parents:
1459
diff
changeset
|
299 } |
| 0 | 300 } |
| 301 else { | |
| 302 while ((c = *string++) != '\0') | |
| 303 PUTCH(c); | |
| 304 } | |
| 305 | |
| 306 RIGHTPAD(width - numpr); | |
| 307 break; | |
| 308 | |
| 309 Print_number: | |
| 310 if (val == 0) | |
| 311 break; | |
| 312 if (c != 'N') | |
| 313 did_output = TRUE; | |
| 314 | |
| 315 /* Create reversed number string. */ | |
| 316 numdigits = 0; | |
| 317 do { | |
| 318 convert[numdigits++] = digits[val % 10]; | |
| 319 val /= 10; | |
| 320 } | |
| 321 while (val > 0); | |
| 322 | |
| 323 numpr = numdigits > precision ? numdigits : precision; | |
| 324 | |
| 325 /* Insert left padding. */ | |
| 326 if (!f_left && width > numpr) { | |
| 327 if (f_zero) | |
| 328 numpr = width; | |
| 329 else | |
| 330 for (i = width - numpr; i-- > 0;) | |
| 331 PUTCH(' '); | |
| 332 } | |
| 333 | |
| 334 /* Insert zero padding. */ | |
| 335 for (i = numpr - numdigits; i-- > 0;) | |
| 336 PUTCH('0'); | |
| 337 | |
| 338 /* Insert number. */ | |
| 339 while (numdigits > 0) | |
| 340 PUTCH(convert[--numdigits]); | |
| 341 | |
| 342 RIGHTPAD(width - numpr); | |
| 343 break; | |
| 344 | |
| 345 case '%': | |
| 346 PUTCH('%'); | |
| 347 break; | |
| 348 | |
| 349 default: | |
| 350 PUTCH('%'); | |
| 351 PUTCH(c); | |
| 352 break; | |
| 353 } | |
| 354 } | |
| 355 | |
| 356 Done: | |
| 357 if (did_output) | |
| 358 return g_string_free(outstr, FALSE); | |
| 359 else | |
| 360 return NULL; | |
| 361 } | |
| 362 | |
| 363 struct _TagDescription { | |
| 364 gchar tag; | |
| 365 gchar *description; | |
| 366 }; | |
| 367 | |
| 368 typedef struct _TagDescription TagDescription; | |
| 369 | |
| 370 static TagDescription tag_descriptions[] = { | |
| 371 {'p', N_("Performer/Artist")}, | |
| 372 {'a', N_("Album")}, | |
| 373 {'g', N_("Genre")}, | |
| 374 {'f', N_("File name")}, | |
| 375 {'F', N_("File path")}, | |
| 376 {'e', N_("File extension")}, | |
| 377 {'t', N_("Track name")}, | |
| 378 {'n', N_("Track number")}, | |
| 379 {'d', N_("Date")}, | |
| 380 {'y', N_("Year")}, | |
| 381 {'c', N_("Comment")} | |
| 382 }; | |
| 383 | |
| 384 gint tag_descriptions_length = | |
| 385 sizeof(tag_descriptions) / sizeof(TagDescription); | |
| 386 | |
| 2050 | 387 /** |
| 388 * xmms_titlestring_descriptions: | |
| 389 * @tags: A list of formatters to provide. | |
| 390 * @columns: A number of columns to arrange them in. | |
| 391 * | |
| 392 * Generates a box explaining how to use the formatters. | |
| 393 * | |
| 394 * Return value: A GtkWidget containing the table. | |
| 395 **/ | |
| 0 | 396 GtkWidget * |
| 397 xmms_titlestring_descriptions(gchar * tags, gint columns) | |
| 398 { | |
| 399 GtkWidget *table, *label; | |
| 400 gchar tag_str[5]; | |
| 401 gint num = strlen(tags); | |
| 402 gint r = 0, c, i; | |
| 403 | |
| 404 g_return_val_if_fail(tags != NULL, NULL); | |
| 405 g_return_val_if_fail(columns <= num, NULL); | |
| 406 | |
| 407 table = gtk_table_new((num + columns - 1) / columns, columns * 2, FALSE); | |
| 408 gtk_table_set_row_spacings(GTK_TABLE(table), 2); | |
| 409 gtk_table_set_col_spacings(GTK_TABLE(table), 5); | |
| 410 | |
| 411 for (c = 0; c < columns; c++) { | |
| 412 for (r = 0; r < (num + columns - 1 - c) / columns; r++) { | |
| 413 g_snprintf(tag_str, sizeof(tag_str), "%%%c:", *tags); | |
| 414 label = gtk_label_new(tag_str); | |
| 415 gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5); | |
| 416 gtk_table_attach(GTK_TABLE(table), label, 2 * c, 2 * c + 1, r, | |
| 417 r + 1, GTK_FILL, GTK_FILL, 0, 0); | |
| 418 gtk_widget_show(label); | |
| 419 | |
| 420 for (i = 0; i < tag_descriptions_length; i++) { | |
| 421 if (*tags == tag_descriptions[i].tag) { | |
| 422 label = gtk_label_new(_(tag_descriptions[i].description)); | |
| 423 gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5); | |
| 424 gtk_table_attach(GTK_TABLE(table), label, 2 * c + 1, | |
| 425 2 * c + 2, r, r + 1, | |
| 426 GTK_EXPAND | GTK_FILL, | |
| 427 GTK_EXPAND | GTK_FILL, 0, 0); | |
| 428 gtk_widget_show(label); | |
| 429 break; | |
| 430 } | |
| 431 } | |
| 432 | |
| 433 if (i == tag_descriptions_length) | |
| 434 g_warning("Invalid tag: %c", *tags); | |
| 435 | |
| 436 tags++; | |
| 437 } | |
| 438 | |
| 439 } | |
| 440 | |
| 441 label = gtk_label_new(_("%{n:...%}: Display \"...\" only if element " | |
| 442 "%n is present")); | |
| 443 gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5); | |
| 444 gtk_table_attach(GTK_TABLE(table), label, 0, r + 1, | |
| 445 r + 1, r + 2, GTK_FILL, GTK_FILL, 0, 0); | |
| 446 gtk_widget_show(label); | |
| 447 | |
| 448 return table; | |
| 449 } |
