udapted vi.po
[rhythmbox.git] / lib / rb-cut-and-paste-code.c
blobbb561209404cbb39baf7a06006c97b4183bbcc2e
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
3 * arch-tag: File containing code cut and pasted from elsewhere
5 * Copyright (C) 2000 Eazel, Inc.
6 * Copyright (C) 2002 Jorn Baayen
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2, or (at your option)
11 * any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
22 * Authors: John Sullivan <sullivan@eazel.com>
23 * Jorn Baayen
26 #include <config.h>
28 #include <string.h>
29 #include <glib/gi18n.h>
31 #include "rb-cut-and-paste-code.h"
33 GdkPixbuf *
34 eel_create_colorized_pixbuf (GdkPixbuf *src,
35 int red_value,
36 int green_value,
37 int blue_value)
39 int i, j;
40 int width, height, has_alpha, src_row_stride, dst_row_stride;
41 guchar *target_pixels;
42 guchar *original_pixels;
43 guchar *pixsrc;
44 guchar *pixdest;
45 GdkPixbuf *dest;
47 g_return_val_if_fail (gdk_pixbuf_get_colorspace (src) == GDK_COLORSPACE_RGB, NULL);
48 g_return_val_if_fail ((!gdk_pixbuf_get_has_alpha (src)
49 && gdk_pixbuf_get_n_channels (src) == 3)
50 || (gdk_pixbuf_get_has_alpha (src)
51 && gdk_pixbuf_get_n_channels (src) == 4), NULL);
52 g_return_val_if_fail (gdk_pixbuf_get_bits_per_sample (src) == 8, NULL);
54 dest = gdk_pixbuf_new (gdk_pixbuf_get_colorspace (src),
55 gdk_pixbuf_get_has_alpha (src),
56 gdk_pixbuf_get_bits_per_sample (src),
57 gdk_pixbuf_get_width (src),
58 gdk_pixbuf_get_height (src));
60 has_alpha = gdk_pixbuf_get_has_alpha (src);
61 width = gdk_pixbuf_get_width (src);
62 height = gdk_pixbuf_get_height (src);
63 src_row_stride = gdk_pixbuf_get_rowstride (src);
64 dst_row_stride = gdk_pixbuf_get_rowstride (dest);
65 target_pixels = gdk_pixbuf_get_pixels (dest);
66 original_pixels = gdk_pixbuf_get_pixels (src);
68 for (i = 0; i < height; i++) {
69 pixdest = target_pixels + i*dst_row_stride;
70 pixsrc = original_pixels + i*src_row_stride;
71 for (j = 0; j < width; j++) {
72 *pixdest++ = (*pixsrc++ * red_value) >> 8;
73 *pixdest++ = (*pixsrc++ * green_value) >> 8;
74 *pixdest++ = (*pixsrc++ * blue_value) >> 8;
75 if (has_alpha) {
76 *pixdest++ = *pixsrc++;
80 return dest;
83 /* Legal conversion specifiers, as specified in the C standard. */
84 #define C_STANDARD_STRFTIME_CHARACTERS "aAbBcdHIjmMpSUwWxXyYZ"
85 #define C_STANDARD_NUMERIC_STRFTIME_CHARACTERS "dHIjmMSUwWyY"
86 #define SUS_EXTENDED_STRFTIME_MODIFIERS "EO"
88 /**
89 * eel_strdup_strftime:
91 * Cover for standard date-and-time-formatting routine strftime that returns
92 * a newly-allocated string of the correct size. The caller is responsible
93 * for g_free-ing the returned string.
95 * Besides the buffer management, there are two differences between this
96 * and the library strftime:
98 * 1) The modifiers "-" and "_" between a "%" and a numeric directive
99 * are defined as for the GNU version of strftime. "-" means "do not
100 * pad the field" and "_" means "pad with spaces instead of zeroes".
101 * 2) Non-ANSI extensions to strftime are flagged at runtime with a
102 * warning, so it's easy to notice use of the extensions without
103 * testing with multiple versions of the library.
105 * @format: format string to pass to strftime. See strftime documentation
106 * for details.
107 * @time_pieces: date/time, in struct format.
109 * Return value: Newly allocated string containing the formatted time.
111 char *
112 eel_strdup_strftime (const char *format, struct tm *time_pieces)
114 GString *string;
115 const char *remainder, *percent;
116 char code[4], buffer[512];
117 char *piece, *result, *converted;
118 size_t string_length;
119 gboolean strip_leading_zeros, turn_leading_zeros_to_spaces;
120 char modifier;
121 int i;
123 /* Format could be translated, and contain UTF-8 chars,
124 * so convert to locale encoding which strftime uses */
125 converted = g_locale_from_utf8 (format, -1, NULL, NULL, NULL);
126 g_return_val_if_fail (converted != NULL, NULL);
128 string = g_string_new ("");
129 remainder = converted;
131 /* Walk from % character to % character. */
132 for (;;) {
133 percent = strchr (remainder, '%');
134 if (percent == NULL) {
135 g_string_append (string, remainder);
136 break;
138 g_string_append_len (string, remainder,
139 percent - remainder);
141 /* Handle the "%" character. */
142 remainder = percent + 1;
143 switch (*remainder) {
144 case '-':
145 strip_leading_zeros = TRUE;
146 turn_leading_zeros_to_spaces = FALSE;
147 remainder++;
148 break;
149 case '_':
150 strip_leading_zeros = FALSE;
151 turn_leading_zeros_to_spaces = TRUE;
152 remainder++;
153 break;
154 case '%':
155 g_string_append_c (string, '%');
156 remainder++;
157 continue;
158 case '\0':
159 g_warning ("Trailing %% passed to eel_strdup_strftime");
160 g_string_append_c (string, '%');
161 continue;
162 default:
163 strip_leading_zeros = FALSE;
164 turn_leading_zeros_to_spaces = FALSE;
165 break;
168 modifier = 0;
169 if (strchr (SUS_EXTENDED_STRFTIME_MODIFIERS, *remainder) != NULL) {
170 modifier = *remainder;
171 remainder++;
173 if (*remainder == 0) {
174 g_warning ("Unfinished %%%c modifier passed to eel_strdup_strftime", modifier);
175 break;
179 if (strchr (C_STANDARD_STRFTIME_CHARACTERS, *remainder) == NULL) {
180 g_warning ("eel_strdup_strftime does not support "
181 "non-standard escape code %%%c",
182 *remainder);
185 /* Convert code to strftime format. We have a fixed
186 * limit here that each code can expand to a maximum
187 * of 512 bytes, which is probably OK. There's no
188 * limit on the total size of the result string.
190 i = 0;
191 code[i++] = '%';
192 if (modifier != 0) {
193 #ifdef HAVE_STRFTIME_EXTENSION
194 code[i++] = modifier;
195 #endif
197 code[i++] = *remainder;
198 code[i++] = '\0';
199 string_length = strftime (buffer, sizeof (buffer),
200 code, time_pieces);
201 if (string_length == 0) {
202 /* We could put a warning here, but there's no
203 * way to tell a successful conversion to
204 * empty string from a failure.
206 buffer[0] = '\0';
209 /* Strip leading zeros if requested. */
210 piece = buffer;
211 if (strip_leading_zeros || turn_leading_zeros_to_spaces) {
212 if (strchr (C_STANDARD_NUMERIC_STRFTIME_CHARACTERS, *remainder) == NULL) {
213 g_warning ("eel_strdup_strftime does not support "
214 "modifier for non-numeric escape code %%%c%c",
215 remainder[-1],
216 *remainder);
218 if (*piece == '0') {
219 do {
220 piece++;
221 } while (*piece == '0');
222 if (!g_ascii_isdigit (*piece)) {
223 piece--;
226 if (turn_leading_zeros_to_spaces) {
227 memset (buffer, ' ', piece - buffer);
228 piece = buffer;
231 remainder++;
233 /* Add this piece. */
234 g_string_append (string, piece);
237 /* Convert the string back into utf-8. */
238 result = g_locale_to_utf8 (string->str, -1, NULL, NULL, NULL);
240 g_string_free (string, TRUE);
241 g_free (converted);
243 return result;
246 /* Based on evolution/mail/message-list.c:filter_date() */
247 char *
248 rb_utf_friendly_time (time_t date)
250 time_t nowdate;
251 time_t yesdate;
252 struct tm then, now, yesterday;
253 const char *format = NULL;
254 char *str = NULL;
255 gboolean done = FALSE;
257 nowdate = time (NULL);
259 if (date == 0)
260 return NULL;
262 localtime_r (&date, &then);
263 localtime_r (&nowdate, &now);
265 if (then.tm_mday == now.tm_mday &&
266 then.tm_mon == now.tm_mon &&
267 then.tm_year == now.tm_year) {
268 /* Translators: "friendly time" string for the current day, strftime format. like "Today 12:34 am" */
269 format = _("Today %I:%M %p");
270 done = TRUE;
273 if (! done) {
274 yesdate = nowdate - 60 * 60 * 24;
275 localtime_r (&yesdate, &yesterday);
276 if (then.tm_mday == yesterday.tm_mday &&
277 then.tm_mon == yesterday.tm_mon &&
278 then.tm_year == yesterday.tm_year) {
279 /* Translators: "friendly time" string for the previous day,
280 * strftime format. e.g. "Yesterday 12:34 am"
282 format = _("Yesterday %I:%M %p");
283 done = TRUE;
287 if (! done) {
288 int i;
289 for (i = 2; i < 7; i++) {
290 yesdate = nowdate - 60 * 60 * 24 * i;
291 localtime_r (&yesdate, &yesterday);
292 if (then.tm_mday == yesterday.tm_mday &&
293 then.tm_mon == yesterday.tm_mon &&
294 then.tm_year == yesterday.tm_year) {
295 /* Translators: "friendly time" string for a day in the current week,
296 * strftime format. e.g. "Wed 12:34 am"
298 format = _("%a %I:%M %p");
299 done = TRUE;
300 break;
305 if (! done) {
306 if (then.tm_year == now.tm_year) {
307 /* Translators: "friendly time" string for a day in the current year,
308 * strftime format. e.g. "Feb 12 12:34 am"
310 format = _("%b %d %I:%M %p");
311 } else {
312 /* Translators: "friendly time" string for a day in a different year,
313 * strftime format. e.g. "Feb 12 1997"
315 format = _("%b %d %Y");
319 if (format != NULL) {
320 str = eel_strdup_strftime (format, &then);
323 return str;
326 #ifndef HAVE_COLLATE_KEY_FILENAME
328 #define COLLATION_SENTINEL "\1\1\1"
330 /* this is taked from glib 2.7/2.8, in case it is not present */
331 gchar*
332 rb_utf8_collate_key_for_filename (const gchar *str, gssize len)
334 GString *result;
335 GString *append;
336 const gchar *p;
337 const gchar *prev;
338 gchar *collate_key;
339 gint digits;
340 gint leading_zeros;
342 if (len < 0)
343 len = strlen (str);
345 result = g_string_sized_new (len * 2);
346 append = g_string_sized_new (0);
348 /* No need to use utf8 functions, since we're only looking for ascii chars */
349 for (prev = p = str; *p != '\0'; p++) {
350 switch (*p) {
351 case '.':
352 if (prev != p) {
353 collate_key = g_utf8_collate_key (prev, p - prev);
354 g_string_append (result, collate_key);
355 g_free (collate_key);
358 g_string_append (result, COLLATION_SENTINEL "\1");
360 /* skip the dot */
361 prev = p + 1;
362 break;
364 case '0':
365 case '1':
366 case '2':
367 case '3':
368 case '4':
369 case '5':
370 case '6':
371 case '7':
372 case '8':
373 case '9':
374 if (prev != p) {
375 collate_key = g_utf8_collate_key (prev, p - prev);
376 g_string_append (result, collate_key);
377 g_free (collate_key);
380 g_string_append (result, COLLATION_SENTINEL "\2");
381 prev = p;
383 /* write d-1 colons */
384 if (*p == '0') {
385 leading_zeros = 1;
386 digits = 0;
387 } else {
388 leading_zeros = 0;
389 digits = 1;
392 do {
393 p++;
395 if (*p == '0' && !digits)
396 ++leading_zeros;
397 else if (g_ascii_isdigit(*p))
398 ++digits;
399 else
400 break;
401 } while (*p != '\0');
403 while (digits > 1) {
404 g_string_append_c (result, ':');
405 --digits;
408 if (leading_zeros > 0) {
409 g_string_append_c (append, (char)leading_zeros);
410 prev += leading_zeros;
413 /* write the number itself */
414 g_string_append_len (result, prev, p - prev);
416 prev = p;
417 --p; /* go one step back to avoid disturbing outer loop */
418 break;
420 default:
421 /* other characters just accumulate */
422 break;
426 if (prev != p) {
427 collate_key = g_utf8_collate_key (prev, p - prev);
428 g_string_append (result, collate_key);
429 g_free (collate_key);
432 g_string_append (result, append->str);
433 g_string_free (append, TRUE);
435 return g_string_free (result, FALSE);
437 #endif
440 /* Copied from eel-vfs-extensions.c from eel CVS HEAD on 2004-05-09
441 * This function is (C) 1999, 2000 Eazel, Inc.
443 char *
444 rb_make_valid_utf8 (const char *name, char substitute)
446 GString *string;
447 const char *remainder, *invalid;
448 int remaining_bytes, valid_bytes;
450 string = NULL;
451 remainder = name;
452 remaining_bytes = strlen (name);
454 while (remaining_bytes != 0) {
455 if (g_utf8_validate (remainder, remaining_bytes, &invalid)) {
456 break;
458 valid_bytes = invalid - remainder;
460 if (string == NULL) {
461 string = g_string_sized_new (remaining_bytes);
463 g_string_append_len (string, remainder, valid_bytes);
464 g_string_append_c (string, substitute);
466 remaining_bytes -= valid_bytes + 1;
467 remainder = invalid + 1;
470 if (string == NULL) {
471 return g_strdup (name);
474 g_string_append (string, remainder);
475 g_assert (g_utf8_validate (string->str, -1, NULL));
477 return g_string_free (string, FALSE);