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)
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>
29 #include <glib/gi18n.h>
31 #include "rb-cut-and-paste-code.h"
34 eel_create_colorized_pixbuf (GdkPixbuf
*src
,
40 int width
, height
, has_alpha
, src_row_stride
, dst_row_stride
;
41 guchar
*target_pixels
;
42 guchar
*original_pixels
;
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;
76 *pixdest
++ = *pixsrc
++;
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"
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
107 * @time_pieces: date/time, in struct format.
109 * Return value: Newly allocated string containing the formatted time.
112 eel_strdup_strftime (const char *format
, struct tm
*time_pieces
)
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
;
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. */
133 percent
= strchr (remainder
, '%');
134 if (percent
== NULL
) {
135 g_string_append (string
, remainder
);
138 g_string_append_len (string
, remainder
,
139 percent
- remainder
);
141 /* Handle the "%" character. */
142 remainder
= percent
+ 1;
143 switch (*remainder
) {
145 strip_leading_zeros
= TRUE
;
146 turn_leading_zeros_to_spaces
= FALSE
;
150 strip_leading_zeros
= FALSE
;
151 turn_leading_zeros_to_spaces
= TRUE
;
155 g_string_append_c (string
, '%');
159 g_warning ("Trailing %% passed to eel_strdup_strftime");
160 g_string_append_c (string
, '%');
163 strip_leading_zeros
= FALSE
;
164 turn_leading_zeros_to_spaces
= FALSE
;
169 if (strchr (SUS_EXTENDED_STRFTIME_MODIFIERS
, *remainder
) != NULL
) {
170 modifier
= *remainder
;
173 if (*remainder
== 0) {
174 g_warning ("Unfinished %%%c modifier passed to eel_strdup_strftime", modifier
);
179 if (strchr (C_STANDARD_STRFTIME_CHARACTERS
, *remainder
) == NULL
) {
180 g_warning ("eel_strdup_strftime does not support "
181 "non-standard escape code %%%c",
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.
193 #ifdef HAVE_STRFTIME_EXTENSION
194 code
[i
++] = modifier
;
197 code
[i
++] = *remainder
;
199 string_length
= strftime (buffer
, sizeof (buffer
),
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.
209 /* Strip leading zeros if requested. */
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",
221 } while (*piece
== '0');
222 if (!g_ascii_isdigit (*piece
)) {
226 if (turn_leading_zeros_to_spaces
) {
227 memset (buffer
, ' ', piece
- buffer
);
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
);
246 /* Based on evolution/mail/message-list.c:filter_date() */
248 rb_utf_friendly_time (time_t date
)
252 struct tm then
, now
, yesterday
;
253 const char *format
= NULL
;
255 gboolean done
= FALSE
;
257 nowdate
= time (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");
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");
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");
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");
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
);
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 */
332 rb_utf8_collate_key_for_filename (const gchar
*str
, gssize len
)
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
++) {
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");
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");
383 /* write d-1 colons */
395 if (*p
== '0' && !digits
)
397 else if (g_ascii_isdigit(*p
))
401 } while (*p
!= '\0');
404 g_string_append_c (result
, ':');
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
);
417 --p
; /* go one step back to avoid disturbing outer loop */
421 /* other characters just accumulate */
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
);
440 /* Copied from eel-vfs-extensions.c from eel CVS HEAD on 2004-05-09
441 * This function is (C) 1999, 2000 Eazel, Inc.
444 rb_make_valid_utf8 (const char *name
, char substitute
)
447 const char *remainder
, *invalid
;
448 int remaining_bytes
, valid_bytes
;
452 remaining_bytes
= strlen (name
);
454 while (remaining_bytes
!= 0) {
455 if (g_utf8_validate (remainder
, remaining_bytes
, &invalid
)) {
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
);