Updated Macedonian Translation <arangela@cvs.gnome.org>
[rhythmbox.git] / lib / rb-cut-and-paste-code.c
blob052c45bc42fac25491d28c38364de48f341e2e63
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) 2002 Jorn Baayen
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2, or (at your option)
10 * any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
23 #include <config.h>
25 #include <string.h>
26 #include <glib/gi18n.h>
28 #include "rb-cut-and-paste-code.h"
30 GdkPixbuf *
31 eel_create_colorized_pixbuf (GdkPixbuf *src,
32 int red_value,
33 int green_value,
34 int blue_value)
36 int i, j;
37 int width, height, has_alpha, src_row_stride, dst_row_stride;
38 guchar *target_pixels;
39 guchar *original_pixels;
40 guchar *pixsrc;
41 guchar *pixdest;
42 GdkPixbuf *dest;
44 g_return_val_if_fail (gdk_pixbuf_get_colorspace (src) == GDK_COLORSPACE_RGB, NULL);
45 g_return_val_if_fail ((!gdk_pixbuf_get_has_alpha (src)
46 && gdk_pixbuf_get_n_channels (src) == 3)
47 || (gdk_pixbuf_get_has_alpha (src)
48 && gdk_pixbuf_get_n_channels (src) == 4), NULL);
49 g_return_val_if_fail (gdk_pixbuf_get_bits_per_sample (src) == 8, NULL);
51 dest = gdk_pixbuf_new (gdk_pixbuf_get_colorspace (src),
52 gdk_pixbuf_get_has_alpha (src),
53 gdk_pixbuf_get_bits_per_sample (src),
54 gdk_pixbuf_get_width (src),
55 gdk_pixbuf_get_height (src));
57 has_alpha = gdk_pixbuf_get_has_alpha (src);
58 width = gdk_pixbuf_get_width (src);
59 height = gdk_pixbuf_get_height (src);
60 src_row_stride = gdk_pixbuf_get_rowstride (src);
61 dst_row_stride = gdk_pixbuf_get_rowstride (dest);
62 target_pixels = gdk_pixbuf_get_pixels (dest);
63 original_pixels = gdk_pixbuf_get_pixels (src);
65 for (i = 0; i < height; i++) {
66 pixdest = target_pixels + i*dst_row_stride;
67 pixsrc = original_pixels + i*src_row_stride;
68 for (j = 0; j < width; j++) {
69 *pixdest++ = (*pixsrc++ * red_value) >> 8;
70 *pixdest++ = (*pixsrc++ * green_value) >> 8;
71 *pixdest++ = (*pixsrc++ * blue_value) >> 8;
72 if (has_alpha) {
73 *pixdest++ = *pixsrc++;
77 return dest;
80 /* Legal conversion specifiers, as specified in the C standard. */
81 #define C_STANDARD_STRFTIME_CHARACTERS "aAbBcdHIjmMpSUwWxXyYZ"
82 #define C_STANDARD_NUMERIC_STRFTIME_CHARACTERS "dHIjmMSUwWyY"
84 /**
85 * eel_strdup_strftime:
87 * Cover for standard date-and-time-formatting routine strftime that returns
88 * a newly-allocated string of the correct size. The caller is responsible
89 * for g_free-ing the returned string.
91 * Besides the buffer management, there are two differences between this
92 * and the library strftime:
94 * 1) The modifiers "-" and "_" between a "%" and a numeric directive
95 * are defined as for the GNU version of strftime. "-" means "do not
96 * pad the field" and "_" means "pad with spaces instead of zeroes".
97 * 2) Non-ANSI extensions to strftime are flagged at runtime with a
98 * warning, so it's easy to notice use of the extensions without
99 * testing with multiple versions of the library.
101 * @format: format string to pass to strftime. See strftime documentation
102 * for details.
103 * @time_pieces: date/time, in struct format.
105 * Return value: Newly allocated string containing the formatted time.
107 char *
108 eel_strdup_strftime (const char *format, struct tm *time_pieces)
110 GString *string;
111 const char *remainder, *percent;
112 char code[3], buffer[512];
113 char *piece, *result, *converted;
114 size_t string_length;
115 gboolean strip_leading_zeros, turn_leading_zeros_to_spaces;
117 /* Format could be translated, and contain UTF-8 chars,
118 * so convert to locale encoding which strftime uses */
119 converted = g_locale_from_utf8 (format, -1, NULL, NULL, NULL);
120 g_return_val_if_fail (converted != NULL, NULL);
122 string = g_string_new ("");
123 remainder = converted;
125 /* Walk from % character to % character. */
126 for (;;) {
127 percent = strchr (remainder, '%');
128 if (percent == NULL) {
129 g_string_append (string, remainder);
130 break;
132 g_string_append_len (string, remainder,
133 percent - remainder);
135 /* Handle the "%" character. */
136 remainder = percent + 1;
137 switch (*remainder) {
138 case '-':
139 strip_leading_zeros = TRUE;
140 turn_leading_zeros_to_spaces = FALSE;
141 remainder++;
142 break;
143 case '_':
144 strip_leading_zeros = FALSE;
145 turn_leading_zeros_to_spaces = TRUE;
146 remainder++;
147 break;
148 case '%':
149 g_string_append_c (string, '%');
150 remainder++;
151 continue;
152 case '\0':
153 g_warning ("Trailing %% passed to eel_strdup_strftime");
154 g_string_append_c (string, '%');
155 continue;
156 default:
157 strip_leading_zeros = FALSE;
158 turn_leading_zeros_to_spaces = FALSE;
159 break;
162 if (strchr (C_STANDARD_STRFTIME_CHARACTERS, *remainder) == NULL) {
163 g_warning ("eel_strdup_strftime does not support "
164 "non-standard escape code %%%c",
165 *remainder);
168 /* Convert code to strftime format. We have a fixed
169 * limit here that each code can expand to a maximum
170 * of 512 bytes, which is probably OK. There's no
171 * limit on the total size of the result string.
173 code[0] = '%';
174 code[1] = *remainder;
175 code[2] = '\0';
176 string_length = strftime (buffer, sizeof (buffer),
177 code, time_pieces);
178 if (string_length == 0) {
179 /* We could put a warning here, but there's no
180 * way to tell a successful conversion to
181 * empty string from a failure.
183 buffer[0] = '\0';
186 /* Strip leading zeros if requested. */
187 piece = buffer;
188 if (strip_leading_zeros || turn_leading_zeros_to_spaces) {
189 if (strchr (C_STANDARD_NUMERIC_STRFTIME_CHARACTERS, *remainder) == NULL) {
190 g_warning ("eel_strdup_strftime does not support "
191 "modifier for non-numeric escape code %%%c%c",
192 remainder[-1],
193 *remainder);
195 if (*piece == '0') {
196 do {
197 piece++;
198 } while (*piece == '0');
199 if (!g_ascii_isdigit (*piece)) {
200 piece--;
203 if (turn_leading_zeros_to_spaces) {
204 memset (buffer, ' ', piece - buffer);
205 piece = buffer;
208 remainder++;
210 /* Add this piece. */
211 g_string_append (string, piece);
214 /* Convert the string back into utf-8. */
215 result = g_locale_to_utf8 (string->str, -1, NULL, NULL, NULL);
217 g_string_free (string, TRUE);
218 g_free (converted);
220 return result;
223 /* Based on evolution/mail/message-list.c:filter_date() */
224 char *
225 rb_utf_friendly_time (time_t date)
227 time_t nowdate;
228 time_t yesdate;
229 struct tm then, now, yesterday;
230 const char *format = NULL;
231 char *str = NULL;
232 gboolean done = FALSE;
234 nowdate = time (NULL);
236 if (date == 0)
237 return NULL;
239 localtime_r (&date, &then);
240 localtime_r (&nowdate, &now);
242 if (then.tm_mday == now.tm_mday &&
243 then.tm_mon == now.tm_mon &&
244 then.tm_year == now.tm_year) {
245 /* Translators: "friendly time" string for the current day, strftime format. like "Today 12:34 am" */
246 format = _("Today %I:%M %p");
247 done = TRUE;
250 if (! done) {
251 yesdate = nowdate - 60 * 60 * 24;
252 localtime_r (&yesdate, &yesterday);
253 if (then.tm_mday == yesterday.tm_mday &&
254 then.tm_mon == yesterday.tm_mon &&
255 then.tm_year == yesterday.tm_year) {
256 /* Translators: "friendly time" string for the previous day,
257 * strftime format. e.g. "Yesterday 12:34 am"
259 format = _("Yesterday %I:%M %p");
260 done = TRUE;
264 if (! done) {
265 int i;
266 for (i = 2; i < 7; i++) {
267 yesdate = nowdate - 60 * 60 * 24 * i;
268 localtime_r (&yesdate, &yesterday);
269 if (then.tm_mday == yesterday.tm_mday &&
270 then.tm_mon == yesterday.tm_mon &&
271 then.tm_year == yesterday.tm_year) {
272 /* Translators: "friendly time" string for a day in the current week,
273 * strftime format. e.g. "Wed 12:34 am"
275 format = _("%a %I:%M %p");
276 done = TRUE;
277 break;
282 if (! done) {
283 if (then.tm_year == now.tm_year) {
284 /* Translators: "friendly time" string for a day in the current year,
285 * strftime format. e.g. "Feb 12 12:34 am"
287 format = _("%b %d %I:%M %p");
288 } else {
289 /* Translators: "friendly time" string for a day in a different year,
290 * strftime format. e.g. "Feb 12 1997"
292 format = _("%b %d %Y");
296 if (format != NULL) {
297 str = eel_strdup_strftime (format, &then);
300 return str;
303 #ifndef HAVE_COLLATE_KEY_FILENAME
305 #define COLLATION_SENTINEL "\1\1\1"
307 /* this is taked from glib 2.7/2.8, in case it is not present */
308 gchar*
309 rb_utf8_collate_key_for_filename (const gchar *str, gssize len)
311 GString *result;
312 GString *append;
313 const gchar *p;
314 const gchar *prev;
315 gchar *collate_key;
316 gint digits;
317 gint leading_zeros;
319 if (len < 0)
320 len = strlen (str);
322 result = g_string_sized_new (len * 2);
323 append = g_string_sized_new (0);
325 /* No need to use utf8 functions, since we're only looking for ascii chars */
326 for (prev = p = str; *p != '\0'; p++) {
327 switch (*p) {
328 case '.':
329 if (prev != p) {
330 collate_key = g_utf8_collate_key (prev, p - prev);
331 g_string_append (result, collate_key);
332 g_free (collate_key);
335 g_string_append (result, COLLATION_SENTINEL "\1");
337 /* skip the dot */
338 prev = p + 1;
339 break;
341 case '0':
342 case '1':
343 case '2':
344 case '3':
345 case '4':
346 case '5':
347 case '6':
348 case '7':
349 case '8':
350 case '9':
351 if (prev != p) {
352 collate_key = g_utf8_collate_key (prev, p - prev);
353 g_string_append (result, collate_key);
354 g_free (collate_key);
357 g_string_append (result, COLLATION_SENTINEL "\2");
358 prev = p;
360 /* write d-1 colons */
361 if (*p == '0') {
362 leading_zeros = 1;
363 digits = 0;
364 } else {
365 leading_zeros = 0;
366 digits = 1;
369 do {
370 p++;
372 if (*p == '0' && !digits)
373 ++leading_zeros;
374 else if (g_ascii_isdigit(*p))
375 ++digits;
376 else
377 break;
378 } while (*p != '\0');
380 while (digits > 1) {
381 g_string_append_c (result, ':');
382 --digits;
385 if (leading_zeros > 0) {
386 g_string_append_c (append, (char)leading_zeros);
387 prev += leading_zeros;
390 /* write the number itself */
391 g_string_append_len (result, prev, p - prev);
393 prev = p;
394 --p; /* go one step back to avoid disturbing outer loop */
395 break;
397 default:
398 /* other characters just accumulate */
399 break;
403 if (prev != p) {
404 collate_key = g_utf8_collate_key (prev, p - prev);
405 g_string_append (result, collate_key);
406 g_free (collate_key);
409 g_string_append (result, append->str);
410 g_string_free (append, TRUE);
412 return g_string_free (result, FALSE);
414 #endif