Mercurial > pidgin
comparison src/util.c @ 7108:6faeeecab0dc
[gaim-migrate @ 7673]
Put the rest of util.[ch] into namespaces and sectioned off the functions.
committer: Tailor Script <tailor@pidgin.im>
author | Christian Hammond <chipx86@chipx86.com> |
---|---|
date | Wed, 01 Oct 2003 07:15:53 +0000 |
parents | 9220c7490cd1 |
children | b003397b16fe |
comparison
equal
deleted
inserted
replaced
7107:9220c7490cd1 | 7108:6faeeecab0dc |
---|---|
58 } GaimFetchUrlData; | 58 } GaimFetchUrlData; |
59 | 59 |
60 | 60 |
61 static char home_dir[MAXPATHLEN]; | 61 static char home_dir[MAXPATHLEN]; |
62 | 62 |
63 char *full_date() | 63 |
64 { | 64 /************************************************************************** |
65 char *date; | 65 * Base16 Functions |
66 time_t tme; | 66 **************************************************************************/ |
67 | 67 unsigned char * |
68 time(&tme); | 68 gaim_base16_encode(const unsigned char *data, int length) |
69 date = ctime(&tme); | 69 { |
70 date[strlen(date) - 1] = '\0'; | 70 int i; |
71 return date; | 71 unsigned char *ascii = NULL; |
72 } | 72 |
73 | 73 g_return_val_if_fail(data != NULL, NULL); |
74 G_GNUC_CONST static gint badchar(char c) | 74 g_return_val_if_fail(length > 0, NULL); |
75 { | 75 |
76 switch (c) { | 76 ascii = g_malloc(length * 2 + 1); |
77 case ' ': | 77 |
78 case ',': | 78 for (i = 0; i < length; i++) |
79 case '(': | 79 snprintf(&ascii[i * 2], 3, "%02hhx", data[i]); |
80 case ')': | 80 |
81 case '\0': | 81 return ascii; |
82 case '\n': | 82 } |
83 case '<': | 83 |
84 case '>': | 84 int |
85 case '"': | 85 gaim_base16_decode(const char *ascii, unsigned char **raw) |
86 case '\'': | 86 { |
87 return 1; | 87 int len, i, accumulator = 0; |
88 default: | 88 unsigned char *data; |
89 return 0; | 89 |
90 } | 90 g_return_val_if_fail(ascii != NULL, 0); |
91 } | 91 |
92 | 92 len = strlen(ascii); |
93 | 93 |
94 gchar *sec_to_text(guint sec) | 94 g_return_val_if_fail(strlen(ascii) > 0, 0); |
95 { | 95 g_return_val_if_fail(len % 2 > 0, 0); |
96 guint daze, hrs, min; | 96 |
97 char *ret = NULL; | 97 data = g_malloc(len / 2); |
98 | 98 |
99 daze = sec / (60 * 60 * 24); | 99 for (i = 0; i < len; i++) |
100 hrs = (sec % (60 * 60 * 24)) / (60 * 60); | 100 { |
101 min = (sec % (60 * 60)) / 60; | 101 if ((i % 2) == 0) |
102 sec = min % 60; | 102 accumulator = 0; |
103 | 103 else |
104 if (daze) { | 104 accumulator <<= 4; |
105 if (hrs || min) { | 105 |
106 if (hrs) { | 106 if (isdigit(ascii[i])) |
107 if (min) { | 107 accumulator |= ascii[i] - 48; |
108 ret = g_strdup_printf( | 108 else |
109 "%d %s, %d %s, %d %s.", | 109 { |
110 daze, ngettext("day","days",daze), | 110 switch(ascii[i]) |
111 hrs, ngettext("hour","hours",hrs), min, ngettext("minute","minutes",min)); | 111 { |
112 } else { | 112 case 'a': case 'A': accumulator |= 10; break; |
113 ret = g_strdup_printf( | 113 case 'b': case 'B': accumulator |= 11; break; |
114 "%d %s, %d %s.", | 114 case 'c': case 'C': accumulator |= 12; break; |
115 daze, ngettext("day","days",daze), hrs, ngettext("hour","hours",hrs)); | 115 case 'd': case 'D': accumulator |= 13; break; |
116 } | 116 case 'e': case 'E': accumulator |= 14; break; |
117 } else { | 117 case 'f': case 'F': accumulator |= 15; break; |
118 ret = g_strdup_printf( | 118 } |
119 "%d %s, %d %s.", | 119 } |
120 daze, ngettext("day","days",daze), min, ngettext("minute","minutes",min)); | 120 |
121 } | 121 if (i % 2) |
122 } else | 122 data[(i - 1) / 2] = accumulator; |
123 ret = g_strdup_printf("%d %s.", daze, ngettext("day","days",daze)); | 123 } |
124 } else { | 124 |
125 if (hrs) { | 125 *raw = data; |
126 if (min) { | 126 |
127 ret = g_strdup_printf( | 127 return (len / 2); |
128 "%d %s, %d %s.", | 128 } |
129 hrs, ngettext("hour","hours",hrs), min, ngettext("minute","minutes",min)); | 129 |
130 } else { | 130 /************************************************************************** |
131 ret = g_strdup_printf("%d %s.", hrs, ngettext("hour","hours",hrs)); | 131 * Base64 Functions |
132 } | 132 **************************************************************************/ |
133 } else { | |
134 ret = g_strdup_printf("%d %s.", min, ngettext("minute","minutes",min)); | |
135 } | |
136 } | |
137 | |
138 return ret; | |
139 } | |
140 | |
141 | |
142 static const char alphabet[] = | 133 static const char alphabet[] = |
143 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" | 134 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" |
144 "0123456789+/"; | 135 "0123456789+/"; |
145 | 136 |
146 char *gaim_base64_encode(const unsigned char *in, size_t inlen) | 137 unsigned char * |
138 gaim_base64_encode(const unsigned char *in, size_t inlen) | |
147 { | 139 { |
148 char *out, *rv; | 140 char *out, *rv; |
149 | 141 |
142 g_return_val_if_fail(in != NULL, NULL); | |
143 g_return_val_if_fail(inlen > 0, NULL); | |
144 | |
150 rv = out = g_malloc((4 * (inlen + 1)) / 3 + 1); | 145 rv = out = g_malloc((4 * (inlen + 1)) / 3 + 1); |
151 | 146 |
152 for (; inlen >= 3; inlen -= 3) | 147 for (; inlen >= 3; inlen -= 3) |
153 { | 148 { |
154 *out++ = alphabet[in[0] >> 2]; | 149 *out++ = alphabet[in[0] >> 2]; |
155 *out++ = alphabet[((in[0] << 4) & 0x30) | (in[1] >> 4)]; | 150 *out++ = alphabet[((in[0] << 4) & 0x30) | (in[1] >> 4)]; |
156 *out++ = alphabet[((in[1] << 2) & 0x3c) | (in[2] >> 6)]; | 151 *out++ = alphabet[((in[1] << 2) & 0x3c) | (in[2] >> 6)]; |
157 *out++ = alphabet[in[2] & 0x3f]; | 152 *out++ = alphabet[in[2] & 0x3f]; |
158 in += 3; | 153 in += 3; |
159 } | 154 } |
160 if (inlen > 0) | 155 |
161 { | 156 if (inlen > 0) |
162 unsigned char fragment; | 157 { |
163 | 158 unsigned char fragment; |
164 *out++ = alphabet[in[0] >> 2]; | 159 |
165 fragment = (in[0] << 4) & 0x30; | 160 *out++ = alphabet[in[0] >> 2]; |
166 if (inlen > 1) | 161 fragment = (in[0] << 4) & 0x30; |
167 fragment |= in[1] >> 4; | 162 |
168 *out++ = alphabet[fragment]; | 163 if (inlen > 1) |
169 *out++ = (inlen < 2) ? '=' : alphabet[(in[1] << 2) & 0x3c]; | 164 fragment |= in[1] >> 4; |
170 *out++ = '='; | 165 |
171 } | 166 *out++ = alphabet[fragment]; |
172 *out = '\0'; | 167 *out++ = (inlen < 2) ? '=' : alphabet[(in[1] << 2) & 0x3c]; |
168 *out++ = '='; | |
169 } | |
170 | |
171 *out = '\0'; | |
173 | 172 |
174 return rv; | 173 return rv; |
175 } | 174 } |
176 | 175 |
177 | 176 void |
178 void gaim_base64_decode(const char *text, char **data, int *size) | 177 gaim_base64_decode(const char *text, char **data, int *size) |
179 { | 178 { |
180 char *out = NULL; | 179 char *out = NULL; |
181 char tmp = 0; | 180 char tmp = 0; |
182 const char *c; | 181 const char *c; |
183 gint32 tmp2 = 0; | 182 gint32 tmp2 = 0; |
184 int len = 0, n = 0; | 183 int len = 0, n = 0; |
185 | 184 |
186 if (!text || !data) | 185 g_return_if_fail(text != NULL); |
187 return; | 186 g_return_if_fail(data != NULL); |
188 | 187 |
189 c = text; | 188 c = text; |
190 | 189 |
191 while (*c) { | 190 while (*c) { |
192 if (*c >= 'A' && *c <= 'Z') { | 191 if (*c >= 'A' && *c <= 'Z') { |
234 | 233 |
235 out = g_realloc(out, len + 1); | 234 out = g_realloc(out, len + 1); |
236 out[len] = 0; | 235 out[len] = 0; |
237 | 236 |
238 *data = out; | 237 *data = out; |
238 | |
239 if (size) | 239 if (size) |
240 *size = len; | 240 *size = len; |
241 } | 241 } |
242 | 242 |
243 /* | 243 |
244 * Converts raw data to a pretty, null-terminated base16 string. | 244 /************************************************************************** |
245 */ | 245 * Date/Time Functions |
246 unsigned char *gaim_base16_encode(const unsigned char *data, int length) | 246 **************************************************************************/ |
247 { | 247 char * |
248 int i; | 248 gaim_date(void) |
249 unsigned char *ascii = NULL; | |
250 | |
251 if (!data || !length) | |
252 return NULL; | |
253 | |
254 ascii = g_malloc(length*2 + 1); | |
255 | |
256 for (i=0; i<length; i++) | |
257 snprintf(&ascii[i*2], 3, "%02hhx", data[i]); | |
258 | |
259 return ascii; | |
260 } | |
261 | |
262 /* | |
263 * Converts a null-terminated string of hexidecimal to raw data. | |
264 */ | |
265 int gaim_base16_decode(const char *ascii, unsigned char **raw) | |
266 { | |
267 int len, i, accumulator=0; | |
268 unsigned char *data; | |
269 | |
270 if (!ascii || !(len = strlen(ascii)) || (len % 2)) | |
271 return 0; | |
272 | |
273 data = g_malloc(len/2); | |
274 for (i=0; i<len; i++) { | |
275 if (!(i % 2)) | |
276 accumulator = 0; | |
277 else | |
278 accumulator = accumulator << 4; | |
279 if (isdigit(ascii[i])) | |
280 accumulator |= ascii[i]-48; | |
281 else switch(ascii[i]) { | |
282 case 'a': case 'A': accumulator|=10; break; | |
283 case 'b': case 'B': accumulator|=11; break; | |
284 case 'c': case 'C': accumulator|=12; break; | |
285 case 'd': case 'D': accumulator|=13; break; | |
286 case 'e': case 'E': accumulator|=14; break; | |
287 case 'f': case 'F': accumulator|=15; break; | |
288 } | |
289 if (i % 2) | |
290 data[(i-1)/2] = accumulator; | |
291 } | |
292 | |
293 *raw = data; | |
294 return len/2; | |
295 } | |
296 | |
297 char *gaim_normalize(const char *s) | |
298 { | |
299 static char buf[BUF_LEN]; | |
300 char *tmp; | |
301 int i, j; | |
302 | |
303 g_return_val_if_fail((s != NULL), NULL); | |
304 | |
305 strncpy(buf, s, BUF_LEN); | |
306 for (i=0, j=0; buf[j]; i++, j++) { | |
307 while (buf[j] == ' ') | |
308 j++; | |
309 buf[i] = buf[j]; | |
310 } | |
311 buf[i] = '\0'; | |
312 | |
313 tmp = g_utf8_strdown(buf, -1); | |
314 g_snprintf(buf, sizeof(buf), "%s", tmp); | |
315 g_free(tmp); | |
316 tmp = g_utf8_normalize(buf, -1, G_NORMALIZE_DEFAULT); | |
317 g_snprintf(buf, sizeof(buf), "%s", tmp); | |
318 g_free(tmp); | |
319 | |
320 return buf; | |
321 } | |
322 | |
323 char *date() | |
324 { | 249 { |
325 static char date[80]; | 250 static char date[80]; |
326 time_t tme; | 251 time_t tme; |
252 | |
327 time(&tme); | 253 time(&tme); |
328 strftime(date, sizeof(date), "%H:%M:%S", localtime(&tme)); | 254 strftime(date, sizeof(date), "%H:%M:%S", localtime(&tme)); |
255 | |
329 return date; | 256 return date; |
330 } | 257 } |
331 | 258 |
332 /* Look for %n, %d, or %t in msg, and replace with the sender's name, date, | 259 char * |
333 or time */ | 260 gaim_date_full(void) |
334 char *away_subs(const char *msg, const char *name) | 261 { |
335 { | 262 char *date; |
336 char *c; | 263 time_t tme; |
337 static char cpy[BUF_LONG]; | 264 |
338 int cnt = 0; | 265 time(&tme); |
339 time_t t = time(0); | 266 date = ctime(&tme); |
340 struct tm *tme = localtime(&t); | 267 date[strlen(date) - 1] = '\0'; |
341 char tmp[20]; | 268 |
342 | 269 return date; |
343 cpy[0] = '\0'; | 270 } |
344 c = (char *)msg; | 271 |
345 while (*c) { | 272 time_t |
346 switch (*c) { | 273 gaim_time_build(int year, int month, int day, int hour, int min, int sec) |
347 case '%': | |
348 if (*(c + 1)) { | |
349 switch (*(c + 1)) { | |
350 case 'n': | |
351 /* append name */ | |
352 strcpy(cpy + cnt, name); | |
353 cnt += strlen(name); | |
354 c++; | |
355 break; | |
356 case 'd': | |
357 /* append date */ | |
358 strftime(tmp, 20, "%m/%d/%Y", tme); | |
359 strcpy(cpy + cnt, tmp); | |
360 cnt += strlen(tmp); | |
361 c++; | |
362 break; | |
363 case 't': | |
364 /* append time */ | |
365 strftime(tmp, 20, "%r", tme); | |
366 strcpy(cpy + cnt, tmp); | |
367 cnt += strlen(tmp); | |
368 c++; | |
369 break; | |
370 default: | |
371 cpy[cnt++] = *c; | |
372 } | |
373 } | |
374 break; | |
375 default: | |
376 cpy[cnt++] = *c; | |
377 } | |
378 c++; | |
379 } | |
380 cpy[cnt] = '\0'; | |
381 return (cpy); | |
382 } | |
383 | |
384 GSList *message_split(char *message, int limit) | |
385 { | |
386 static GSList *ret = NULL; | |
387 int lastgood = 0, curgood = 0, curpos = 0, len = strlen(message); | |
388 gboolean intag = FALSE; | |
389 | |
390 if (ret) { | |
391 GSList *tmp = ret; | |
392 while (tmp) { | |
393 g_free(tmp->data); | |
394 tmp = g_slist_remove(tmp, tmp->data); | |
395 } | |
396 ret = NULL; | |
397 } | |
398 | |
399 while (TRUE) { | |
400 if (lastgood >= len) | |
401 return ret; | |
402 | |
403 if (len - lastgood < limit) { | |
404 ret = g_slist_append(ret, g_strdup(&message[lastgood])); | |
405 return ret; | |
406 } | |
407 | |
408 curgood = curpos = 0; | |
409 intag = FALSE; | |
410 while (curpos <= limit) { | |
411 if (isspace(message[curpos + lastgood]) && !intag) | |
412 curgood = curpos; | |
413 if (message[curpos + lastgood] == '<') | |
414 intag = TRUE; | |
415 if (message[curpos + lastgood] == '>') | |
416 intag = FALSE; | |
417 curpos++; | |
418 } | |
419 | |
420 if (curgood) { | |
421 ret = g_slist_append(ret, g_strndup(&message[lastgood], curgood)); | |
422 if (isspace(message[curgood + lastgood])) | |
423 lastgood += curgood + 1; | |
424 else | |
425 lastgood += curgood; | |
426 } else { | |
427 /* whoops, guess we have to fudge it here */ | |
428 ret = g_slist_append(ret, g_strndup(&message[lastgood], limit)); | |
429 lastgood += limit; | |
430 } | |
431 } | |
432 } | |
433 | |
434 const gchar *gaim_home_dir() | |
435 { | |
436 #ifndef _WIN32 | |
437 if(g_get_home_dir()) | |
438 return g_get_home_dir(); | |
439 else | |
440 return NULL; | |
441 #else | |
442 return wgaim_data_dir(); | |
443 #endif | |
444 } | |
445 | |
446 /* returns a string of the form ~/.gaim, where ~ is replaced by the user's home | |
447 * dir. Note that there is no trailing slash after .gaim. */ | |
448 gchar *gaim_user_dir() | |
449 { | |
450 const gchar *hd = gaim_home_dir(); | |
451 if(hd) { | |
452 strcpy( (char*)&home_dir, hd ); | |
453 strcat( (char*)&home_dir, G_DIR_SEPARATOR_S ".gaim" ); | |
454 return (gchar*)&home_dir; | |
455 } | |
456 else { | |
457 return NULL; | |
458 } | |
459 } | |
460 | |
461 /* | |
462 * rcg10312000 This could be more robust, but it works for my current | |
463 * goal: to remove those annoying <BR> tags. :) | |
464 * dtf12162000 made the loop more readable. i am a neat freak. ;) */ | |
465 void strncpy_nohtml(gchar *dest, const gchar *src, size_t destsize) | |
466 { | |
467 gchar *ptr; | |
468 g_snprintf(dest, destsize, "%s", src); | |
469 | |
470 while ((ptr = strstr(dest, "<BR>")) != NULL) { | |
471 /* replace <BR> with a newline. */ | |
472 *ptr = '\n'; | |
473 memmove(ptr + 1, ptr + 4, strlen(ptr + 4) + 1); | |
474 } | |
475 } | |
476 | |
477 void strncpy_withhtml(gchar *dest, const gchar *src, size_t destsize) | |
478 { | |
479 gchar *end = dest + destsize; | |
480 | |
481 while (dest < end) { | |
482 if (*src == '\n' && dest < end - 5) { | |
483 strcpy(dest, "<BR>"); | |
484 src++; | |
485 dest += 4; | |
486 } else if(*src == '\r') { | |
487 src++; | |
488 } else { | |
489 *dest++ = *src; | |
490 if (*src == '\0') | |
491 return; | |
492 else | |
493 src++; | |
494 } | |
495 } | |
496 } | |
497 | |
498 | |
499 /* | |
500 * Like strncpy_withhtml (above), but malloc()'s the necessary space | |
501 * | |
502 * The caller is responsible for freeing the space pointed to by the | |
503 * return value. | |
504 */ | |
505 | |
506 gchar *strdup_withhtml(const gchar *src) | |
507 { | |
508 gchar *sp, *dest; | |
509 gulong destsize; | |
510 | |
511 if(!src) | |
512 return NULL; | |
513 | |
514 /* | |
515 * All we need do is multiply the number of newlines by 3 (the | |
516 * additional length of "<BR>" over "\n"), account for the | |
517 * terminator, malloc the space and call strncpy_withhtml. | |
518 */ | |
519 for(destsize = 0, sp = (gchar *)src; (sp = strchr(sp, '\n')) != NULL; ++sp, ++destsize) | |
520 ; | |
521 destsize *= 3; | |
522 destsize += strlen(src) + 1; | |
523 dest = g_malloc(destsize); | |
524 strncpy_withhtml(dest, src, destsize); | |
525 | |
526 return(dest); | |
527 } | |
528 | |
529 void strip_linefeed(gchar *text) | |
530 { | |
531 int i, j; | |
532 gchar *text2 = g_malloc(strlen(text) + 1); | |
533 | |
534 for (i = 0, j = 0; text[i]; i++) | |
535 if (text[i] != '\r') | |
536 text2[j++] = text[i]; | |
537 text2[j] = '\0'; | |
538 | |
539 strcpy(text, text2); | |
540 g_free(text2); | |
541 } | |
542 | |
543 char *add_cr(const char *text) | |
544 { | |
545 char *ret = NULL; | |
546 int count = 0, i, j; | |
547 | |
548 if (text[0] == '\n') | |
549 count++; | |
550 for (i = 1; i < strlen(text); i++) | |
551 if (text[i] == '\n' && text[i - 1] != '\r') | |
552 count++; | |
553 | |
554 if (count == 0) | |
555 return g_strdup(text); | |
556 | |
557 ret = g_malloc0(strlen(text) + count + 1); | |
558 | |
559 i = 0; j = 0; | |
560 if (text[i] == '\n') | |
561 ret[j++] = '\r'; | |
562 ret[j++] = text[i++]; | |
563 for (; i < strlen(text); i++) { | |
564 if (text[i] == '\n' && text[i - 1] != '\r') | |
565 ret[j++] = '\r'; | |
566 ret[j++] = text[i]; | |
567 } | |
568 | |
569 gaim_debug(GAIM_DEBUG_INFO, "add_cr", "got: %s, leaving with %s\n", | |
570 text, ret); | |
571 | |
572 return ret; | |
573 } | |
574 | |
575 time_t get_time(int year, int month, int day, int hour, int min, int sec) | |
576 { | 274 { |
577 struct tm tm; | 275 struct tm tm; |
578 | 276 |
579 tm.tm_year = year - 1900; | 277 tm.tm_year = year - 1900; |
580 tm.tm_mon = month - 1; | 278 tm.tm_mon = month - 1; |
581 tm.tm_mday = day; | 279 tm.tm_mday = day; |
582 tm.tm_hour = hour; | 280 tm.tm_hour = hour; |
583 tm.tm_min = min; | 281 tm.tm_min = min; |
584 tm.tm_sec = sec >= 0 ? sec : time(NULL) % 60; | 282 tm.tm_sec = sec >= 0 ? sec : time(NULL) % 60; |
283 | |
585 return mktime(&tm); | 284 return mktime(&tm); |
586 } | 285 } |
587 | 286 |
588 /* | 287 |
589 * Like mkstemp() but returns a file pointer, uses a pre-set template, | 288 /************************************************************************** |
590 * uses the semantics of tempnam() for the directory to use and allocates | 289 * Markup Functions |
591 * the space for the filepath. | 290 **************************************************************************/ |
592 * | |
593 * Caller is responsible for closing the file and removing it when done, | |
594 * as well as freeing the space pointed-to by "path" with g_free(). | |
595 * | |
596 * Returns NULL on failure and cleans up after itself if so. | |
597 */ | |
598 static const char *gaim_mkstemp_templ = {"gaimXXXXXX"}; | |
599 | |
600 FILE *gaim_mkstemp(gchar **fpath) | |
601 { | |
602 const gchar *tmpdir; | |
603 #ifndef _WIN32 | |
604 int fd; | |
605 #endif | |
606 FILE *fp = NULL; | |
607 | |
608 if((tmpdir = (gchar*)g_get_tmp_dir()) != NULL) { | |
609 if((*fpath = g_strdup_printf("%s" G_DIR_SEPARATOR_S "%s", tmpdir, gaim_mkstemp_templ)) != NULL) { | |
610 #ifdef _WIN32 | |
611 char* result = _mktemp( *fpath ); | |
612 if( result == NULL ) | |
613 gaim_debug(GAIM_DEBUG_ERROR, "gaim_mkstemp", | |
614 "Problem creating the template\n"); | |
615 else | |
616 { | |
617 if( (fp = fopen( result, "w+" )) == NULL ) { | |
618 gaim_debug(GAIM_DEBUG_ERROR, "gaim_mkstemp", | |
619 "Couldn't fopen() %s\n", result); | |
620 } | |
621 } | |
622 #else | |
623 if((fd = mkstemp(*fpath)) == -1) { | |
624 gaim_debug(GAIM_DEBUG_ERROR, "gaim_mkstemp", | |
625 "Couldn't make \"%s\", error: %d\n", | |
626 *fpath, errno); | |
627 } else { | |
628 if((fp = fdopen(fd, "r+")) == NULL) { | |
629 close(fd); | |
630 gaim_debug(GAIM_DEBUG_ERROR, "gaim_mkstemp", | |
631 "Couldn't fdopen(), error: %d\n", errno); | |
632 } | |
633 } | |
634 #endif | |
635 if(!fp) { | |
636 g_free(*fpath); | |
637 *fpath = NULL; | |
638 } | |
639 } | |
640 } else { | |
641 gaim_debug(GAIM_DEBUG_ERROR, "gaim_mkstemp", | |
642 "g_get_tmp_dir() failed!"); | |
643 } | |
644 | |
645 return fp; | |
646 } | |
647 | |
648 gboolean program_is_valid(const char *program) | |
649 { | |
650 GError *error = NULL; | |
651 char **argv; | |
652 gchar *progname; | |
653 gboolean is_valid = FALSE; | |
654 | |
655 if (program == NULL || *program == '\0') { | |
656 return FALSE; | |
657 } | |
658 | |
659 if (!g_shell_parse_argv(program, NULL, &argv, &error)) { | |
660 gaim_debug(GAIM_DEBUG_ERROR, "program_is_valid", | |
661 "Could not parse program '%s': %s\n", | |
662 program, error->message); | |
663 g_error_free(error); | |
664 return FALSE; | |
665 } | |
666 | |
667 if (argv == NULL) { | |
668 return FALSE; | |
669 } | |
670 | |
671 progname = g_find_program_in_path(argv[0]); | |
672 is_valid = (progname != NULL); | |
673 | |
674 g_strfreev(argv); | |
675 g_free(progname); | |
676 | |
677 return is_valid; | |
678 } | |
679 | |
680 char *gaim_try_conv_to_utf8(const char *str) | |
681 { | |
682 gsize converted; | |
683 char *utf8; | |
684 | |
685 if (str == NULL) { | |
686 return NULL; | |
687 } | |
688 | |
689 if (g_utf8_validate(str, -1, NULL)) { | |
690 return g_strdup(str); | |
691 } | |
692 | |
693 utf8 = g_locale_to_utf8(str, -1, &converted, NULL, NULL); | |
694 if (utf8) | |
695 return(utf8); | |
696 | |
697 g_free(utf8); | |
698 | |
699 utf8 = g_convert(str, -1, "UTF-8", "ISO-8859-15", &converted, NULL, NULL); | |
700 if (utf8 && converted == strlen (str)) { | |
701 return(utf8); | |
702 } else if (utf8) { | |
703 g_free(utf8); | |
704 } | |
705 | |
706 return(NULL); | |
707 } | |
708 | |
709 char *gaim_getip_from_fd(int fd) | |
710 { | |
711 struct sockaddr addr; | |
712 socklen_t namelen = sizeof(addr); | |
713 | |
714 if (getsockname(fd, &addr, &namelen)) | |
715 return NULL; | |
716 | |
717 return g_strdup(inet_ntoa(((struct sockaddr_in *)&addr)->sin_addr)); | |
718 } | |
719 | |
720 gint gaim_utf8_strcasecmp(const gchar *a, const gchar *b) { | |
721 gchar *a_norm=NULL; | |
722 gchar *b_norm=NULL; | |
723 gint ret=-1; | |
724 | |
725 if(!a && b) | |
726 return -1; | |
727 else if(!b && a) | |
728 return 1; | |
729 else if(!a && !b) | |
730 return 0; | |
731 | |
732 if(!g_utf8_validate(a, -1, NULL) || !g_utf8_validate(b, -1, NULL)) { | |
733 gaim_debug(GAIM_DEBUG_ERROR, "gaim_utf8_strcasecmp", "One or both parameters are invalid UTF8\n"); | |
734 return ret; | |
735 } | |
736 | |
737 a_norm = g_utf8_casefold(a, -1); | |
738 b_norm = g_utf8_casefold(b, -1); | |
739 ret = g_utf8_collate(a_norm, b_norm); | |
740 g_free(a_norm); | |
741 g_free(b_norm); | |
742 return ret; | |
743 } | |
744 | |
745 gchar *gaim_strreplace(const gchar *string, const gchar *delimiter, const gchar *replacement) { | |
746 gchar **split; | |
747 gchar *ret; | |
748 | |
749 split = g_strsplit(string, delimiter, 0); | |
750 ret = g_strjoinv(replacement, split); | |
751 g_strfreev(split); | |
752 | |
753 return ret; | |
754 } | |
755 | |
756 const char *gaim_strcasestr(const char *haystack, const char *needle) { | |
757 size_t hlen, nlen; | |
758 const char *tmp, *ret; | |
759 | |
760 g_return_val_if_fail(haystack != NULL, NULL); | |
761 g_return_val_if_fail(needle != NULL, NULL); | |
762 | |
763 hlen = strlen(haystack); | |
764 nlen = strlen(needle); | |
765 tmp = haystack, | |
766 ret = NULL; | |
767 | |
768 g_return_val_if_fail(hlen > 0, NULL); | |
769 g_return_val_if_fail(nlen > 0, NULL); | |
770 | |
771 while (*tmp && !ret) { | |
772 if (!g_ascii_strncasecmp(needle, tmp, nlen)) | |
773 ret = tmp; | |
774 else | |
775 tmp++; | |
776 } | |
777 | |
778 return ret; | |
779 } | |
780 | |
781 char * | |
782 gaim_str_size_to_units(size_t size) | |
783 { | |
784 static const char *size_str[4] = { "bytes", "KB", "MB", "GB" }; | |
785 float size_mag; | |
786 int size_index = 0; | |
787 | |
788 if (size == -1) { | |
789 return g_strdup(_("Calculating...")); | |
790 } | |
791 else if (size == 0) { | |
792 return g_strdup(_("Unknown.")); | |
793 } | |
794 else { | |
795 size_mag = (float)size; | |
796 | |
797 while ((size_index < 4) && (size_mag > 1024)) { | |
798 size_mag /= 1024; | |
799 size_index++; | |
800 } | |
801 | |
802 return g_strdup_printf("%.2f %s", size_mag, size_str[size_index]); | |
803 } | |
804 } | |
805 | |
806 gboolean | 291 gboolean |
807 gaim_markup_find_tag(const char *needle, const char *haystack, | 292 gaim_markup_find_tag(const char *needle, const char *haystack, |
808 const char **start, const char **end, GData **attributes) | 293 const char **start, const char **end, GData **attributes) |
809 { | 294 { |
810 GData *attribs; | 295 GData *attribs; |
1384 str2[j] = '\0'; | 869 str2[j] = '\0'; |
1385 | 870 |
1386 return str2; | 871 return str2; |
1387 } | 872 } |
1388 | 873 |
874 static gint | |
875 badchar(char c) | |
876 { | |
877 switch (c) { | |
878 case ' ': | |
879 case ',': | |
880 case '(': | |
881 case ')': | |
882 case '\0': | |
883 case '\n': | |
884 case '<': | |
885 case '>': | |
886 case '"': | |
887 case '\'': | |
888 return 1; | |
889 default: | |
890 return 0; | |
891 } | |
892 } | |
893 | |
1389 char * | 894 char * |
1390 gaim_markup_linkify(const char *text) | 895 gaim_markup_linkify(const char *text) |
1391 { | 896 { |
1392 const char *c, *t, *q = NULL; | 897 const char *c, *t, *q = NULL; |
1393 char *tmp; | 898 char *tmp; |
1593 tmp = ret->str; | 1098 tmp = ret->str; |
1594 g_string_free(ret, FALSE); | 1099 g_string_free(ret, FALSE); |
1595 return tmp; | 1100 return tmp; |
1596 } | 1101 } |
1597 | 1102 |
1103 | |
1104 /************************************************************************** | |
1105 * Path/Filename Functions | |
1106 **************************************************************************/ | |
1107 const char * | |
1108 gaim_home_dir(void) | |
1109 { | |
1110 #ifndef _WIN32 | |
1111 if(g_get_home_dir()) | |
1112 return g_get_home_dir(); | |
1113 else | |
1114 return NULL; | |
1115 #else | |
1116 return wgaim_data_dir(); | |
1117 #endif | |
1118 } | |
1119 | |
1120 /* returns a string of the form ~/.gaim, where ~ is replaced by the user's home | |
1121 * dir. Note that there is no trailing slash after .gaim. */ | |
1122 char * | |
1123 gaim_user_dir(void) | |
1124 { | |
1125 const gchar *hd = gaim_home_dir(); | |
1126 | |
1127 if(hd) | |
1128 { | |
1129 strcpy( (char*)&home_dir, hd ); | |
1130 strcat( (char*)&home_dir, G_DIR_SEPARATOR_S ".gaim" ); | |
1131 | |
1132 return (gchar*)&home_dir; | |
1133 } | |
1134 | |
1135 return NULL; | |
1136 } | |
1137 | |
1138 /* | |
1139 * Like mkstemp() but returns a file pointer, uses a pre-set template, | |
1140 * uses the semantics of tempnam() for the directory to use and allocates | |
1141 * the space for the filepath. | |
1142 * | |
1143 * Caller is responsible for closing the file and removing it when done, | |
1144 * as well as freeing the space pointed-to by "path" with g_free(). | |
1145 * | |
1146 * Returns NULL on failure and cleans up after itself if so. | |
1147 */ | |
1148 static const char *gaim_mkstemp_templ = {"gaimXXXXXX"}; | |
1149 | |
1150 FILE * | |
1151 gaim_mkstemp(char **fpath) | |
1152 { | |
1153 const gchar *tmpdir; | |
1154 #ifndef _WIN32 | |
1155 int fd; | |
1156 #endif | |
1157 FILE *fp = NULL; | |
1158 | |
1159 g_return_val_if_fail(fpath != NULL, NULL); | |
1160 | |
1161 if((tmpdir = (gchar*)g_get_tmp_dir()) != NULL) { | |
1162 if((*fpath = g_strdup_printf("%s" G_DIR_SEPARATOR_S "%s", tmpdir, gaim_mkstemp_templ)) != NULL) { | |
1163 #ifdef _WIN32 | |
1164 char* result = _mktemp( *fpath ); | |
1165 if( result == NULL ) | |
1166 gaim_debug(GAIM_DEBUG_ERROR, "gaim_mkstemp", | |
1167 "Problem creating the template\n"); | |
1168 else | |
1169 { | |
1170 if( (fp = fopen( result, "w+" )) == NULL ) { | |
1171 gaim_debug(GAIM_DEBUG_ERROR, "gaim_mkstemp", | |
1172 "Couldn't fopen() %s\n", result); | |
1173 } | |
1174 } | |
1175 #else | |
1176 if((fd = mkstemp(*fpath)) == -1) { | |
1177 gaim_debug(GAIM_DEBUG_ERROR, "gaim_mkstemp", | |
1178 "Couldn't make \"%s\", error: %d\n", | |
1179 *fpath, errno); | |
1180 } else { | |
1181 if((fp = fdopen(fd, "r+")) == NULL) { | |
1182 close(fd); | |
1183 gaim_debug(GAIM_DEBUG_ERROR, "gaim_mkstemp", | |
1184 "Couldn't fdopen(), error: %d\n", errno); | |
1185 } | |
1186 } | |
1187 #endif | |
1188 if(!fp) { | |
1189 g_free(*fpath); | |
1190 *fpath = NULL; | |
1191 } | |
1192 } | |
1193 } else { | |
1194 gaim_debug(GAIM_DEBUG_ERROR, "gaim_mkstemp", | |
1195 "g_get_tmp_dir() failed!"); | |
1196 } | |
1197 | |
1198 return fp; | |
1199 } | |
1200 | |
1201 gboolean | |
1202 gaim_program_is_valid(const char *program) | |
1203 { | |
1204 GError *error = NULL; | |
1205 char **argv; | |
1206 gchar *progname; | |
1207 gboolean is_valid = FALSE; | |
1208 | |
1209 g_return_val_if_fail(program != NULL, FALSE); | |
1210 g_return_val_if_fail(*program != '\0', FALSE); | |
1211 | |
1212 if (!g_shell_parse_argv(program, NULL, &argv, &error)) { | |
1213 gaim_debug(GAIM_DEBUG_ERROR, "program_is_valid", | |
1214 "Could not parse program '%s': %s\n", | |
1215 program, error->message); | |
1216 g_error_free(error); | |
1217 return FALSE; | |
1218 } | |
1219 | |
1220 if (argv == NULL) { | |
1221 return FALSE; | |
1222 } | |
1223 | |
1224 progname = g_find_program_in_path(argv[0]); | |
1225 is_valid = (progname != NULL); | |
1226 | |
1227 g_strfreev(argv); | |
1228 g_free(progname); | |
1229 | |
1230 return is_valid; | |
1231 } | |
1232 | |
1233 char * | |
1234 gaim_fd_get_ip(int fd) | |
1235 { | |
1236 struct sockaddr addr; | |
1237 socklen_t namelen = sizeof(addr); | |
1238 | |
1239 g_return_val_if_fail(fd != 0, NULL); | |
1240 | |
1241 if (getsockname(fd, &addr, &namelen)) | |
1242 return NULL; | |
1243 | |
1244 return g_strdup(inet_ntoa(((struct sockaddr_in *)&addr)->sin_addr)); | |
1245 } | |
1246 | |
1247 | |
1248 /************************************************************************** | |
1249 * String Functions | |
1250 **************************************************************************/ | |
1251 char * | |
1252 gaim_normalize(const char *s) | |
1253 { | |
1254 static char buf[BUF_LEN]; | |
1255 char *tmp; | |
1256 int i, j; | |
1257 | |
1258 g_return_val_if_fail(s != NULL, NULL); | |
1259 | |
1260 strncpy(buf, s, BUF_LEN); | |
1261 for (i=0, j=0; buf[j]; i++, j++) { | |
1262 while (buf[j] == ' ') | |
1263 j++; | |
1264 buf[i] = buf[j]; | |
1265 } | |
1266 buf[i] = '\0'; | |
1267 | |
1268 tmp = g_utf8_strdown(buf, -1); | |
1269 g_snprintf(buf, sizeof(buf), "%s", tmp); | |
1270 g_free(tmp); | |
1271 tmp = g_utf8_normalize(buf, -1, G_NORMALIZE_DEFAULT); | |
1272 g_snprintf(buf, sizeof(buf), "%s", tmp); | |
1273 g_free(tmp); | |
1274 | |
1275 return buf; | |
1276 } | |
1277 | |
1278 /* Look for %n, %d, or %t in msg, and replace with the sender's name, date, | |
1279 or time */ | |
1280 char * | |
1281 gaim_str_sub_away_formatters(const char *msg, const char *name) | |
1282 { | |
1283 char *c; | |
1284 static char cpy[BUF_LONG]; | |
1285 int cnt = 0; | |
1286 time_t t; | |
1287 struct tm *tme; | |
1288 char tmp[20]; | |
1289 | |
1290 g_return_val_if_fail(msg != NULL, NULL); | |
1291 g_return_val_if_fail(name != NULL, NULL); | |
1292 | |
1293 t = time(NULL); | |
1294 tme = localtime(&t); | |
1295 | |
1296 cpy[0] = '\0'; | |
1297 c = (char *)msg; | |
1298 while (*c) { | |
1299 switch (*c) { | |
1300 case '%': | |
1301 if (*(c + 1)) { | |
1302 switch (*(c + 1)) { | |
1303 case 'n': | |
1304 /* append name */ | |
1305 strcpy(cpy + cnt, name); | |
1306 cnt += strlen(name); | |
1307 c++; | |
1308 break; | |
1309 case 'd': | |
1310 /* append date */ | |
1311 strftime(tmp, 20, "%m/%d/%Y", tme); | |
1312 strcpy(cpy + cnt, tmp); | |
1313 cnt += strlen(tmp); | |
1314 c++; | |
1315 break; | |
1316 case 't': | |
1317 /* append time */ | |
1318 strftime(tmp, 20, "%r", tme); | |
1319 strcpy(cpy + cnt, tmp); | |
1320 cnt += strlen(tmp); | |
1321 c++; | |
1322 break; | |
1323 default: | |
1324 cpy[cnt++] = *c; | |
1325 } | |
1326 } | |
1327 break; | |
1328 default: | |
1329 cpy[cnt++] = *c; | |
1330 } | |
1331 c++; | |
1332 } | |
1333 cpy[cnt] = '\0'; | |
1334 return (cpy); | |
1335 } | |
1336 | |
1337 /* | |
1338 * rcg10312000 This could be more robust, but it works for my current | |
1339 * goal: to remove those annoying <BR> tags. :) | |
1340 * dtf12162000 made the loop more readable. i am a neat freak. ;) */ | |
1341 void | |
1342 gaim_strncpy_nohtml(char *dest, const char *src, size_t destsize) | |
1343 { | |
1344 char *ptr; | |
1345 | |
1346 g_return_if_fail(dest != NULL); | |
1347 g_return_if_fail(src != NULL); | |
1348 g_return_if_fail(destsize > 0); | |
1349 | |
1350 g_snprintf(dest, destsize, "%s", src); | |
1351 | |
1352 while ((ptr = strstr(dest, "<BR>")) != NULL) { | |
1353 /* replace <BR> with a newline. */ | |
1354 *ptr = '\n'; | |
1355 memmove(ptr + 1, ptr + 4, strlen(ptr + 4) + 1); | |
1356 } | |
1357 } | |
1358 | |
1359 void | |
1360 gaim_strncpy_withhtml(gchar *dest, const gchar *src, size_t destsize) | |
1361 { | |
1362 gchar *end; | |
1363 | |
1364 g_return_if_fail(dest != NULL); | |
1365 g_return_if_fail(src != NULL); | |
1366 g_return_if_fail(destsize > 0); | |
1367 | |
1368 end = dest + destsize; | |
1369 | |
1370 while (dest < end) { | |
1371 if (*src == '\n' && dest < end - 5) { | |
1372 strcpy(dest, "<BR>"); | |
1373 src++; | |
1374 dest += 4; | |
1375 } else if(*src == '\r') { | |
1376 src++; | |
1377 } else { | |
1378 *dest++ = *src; | |
1379 if (*src == '\0') | |
1380 return; | |
1381 else | |
1382 src++; | |
1383 } | |
1384 } | |
1385 } | |
1386 | |
1387 /* | |
1388 * Like strncpy_withhtml (above), but malloc()'s the necessary space | |
1389 * | |
1390 * The caller is responsible for freeing the space pointed to by the | |
1391 * return value. | |
1392 */ | |
1393 char * | |
1394 gaim_strdup_withhtml(const char *src) | |
1395 { | |
1396 char *sp, *dest; | |
1397 gulong destsize; | |
1398 | |
1399 g_return_val_if_fail(src != NULL, NULL); | |
1400 | |
1401 /* | |
1402 * All we need do is multiply the number of newlines by 3 (the | |
1403 * additional length of "<BR>" over "\n"), account for the | |
1404 * terminator, malloc the space and call strncpy_withhtml. | |
1405 */ | |
1406 for(destsize = 0, sp = (gchar *)src; | |
1407 (sp = strchr(sp, '\n')) != NULL; | |
1408 ++sp, ++destsize) | |
1409 ; | |
1410 | |
1411 destsize *= 3; | |
1412 destsize += strlen(src) + 1; | |
1413 dest = g_malloc(destsize); | |
1414 gaim_strncpy_withhtml(dest, src, destsize); | |
1415 | |
1416 return dest; | |
1417 } | |
1418 | |
1419 char * | |
1420 gaim_str_add_cr(const char *text) | |
1421 { | |
1422 char *ret = NULL; | |
1423 int count = 0, i, j; | |
1424 | |
1425 g_return_val_if_fail(text != NULL, NULL); | |
1426 | |
1427 if (text[0] == '\n') | |
1428 count++; | |
1429 for (i = 1; i < strlen(text); i++) | |
1430 if (text[i] == '\n' && text[i - 1] != '\r') | |
1431 count++; | |
1432 | |
1433 if (count == 0) | |
1434 return g_strdup(text); | |
1435 | |
1436 ret = g_malloc0(strlen(text) + count + 1); | |
1437 | |
1438 i = 0; j = 0; | |
1439 if (text[i] == '\n') | |
1440 ret[j++] = '\r'; | |
1441 ret[j++] = text[i++]; | |
1442 for (; i < strlen(text); i++) { | |
1443 if (text[i] == '\n' && text[i - 1] != '\r') | |
1444 ret[j++] = '\r'; | |
1445 ret[j++] = text[i]; | |
1446 } | |
1447 | |
1448 gaim_debug_misc("gaim_str_add_cr", "got: %s, leaving with %s\n", | |
1449 text, ret); | |
1450 | |
1451 return ret; | |
1452 } | |
1453 | |
1454 void | |
1455 gaim_str_strip_linefeed(char *text) | |
1456 { | |
1457 int i, j; | |
1458 char *text2; | |
1459 | |
1460 g_return_if_fail(text != NULL); | |
1461 | |
1462 text2 = g_malloc(strlen(text) + 1); | |
1463 | |
1464 for (i = 0, j = 0; text[i]; i++) | |
1465 if (text[i] != '\r') | |
1466 text2[j++] = text[i]; | |
1467 text2[j] = '\0'; | |
1468 | |
1469 strcpy(text, text2); | |
1470 g_free(text2); | |
1471 } | |
1472 | |
1473 char * | |
1474 gaim_strreplace(const char *string, const char *delimiter, | |
1475 const char *replacement) | |
1476 { | |
1477 gchar **split; | |
1478 gchar *ret; | |
1479 | |
1480 g_return_val_if_fail(string != NULL, NULL); | |
1481 g_return_val_if_fail(delimiter != NULL, NULL); | |
1482 g_return_val_if_fail(replacement != NULL, NULL); | |
1483 | |
1484 split = g_strsplit(string, delimiter, 0); | |
1485 ret = g_strjoinv(replacement, split); | |
1486 g_strfreev(split); | |
1487 | |
1488 return ret; | |
1489 } | |
1490 | |
1491 const char * | |
1492 gaim_strcasestr(const char *haystack, const char *needle) | |
1493 { | |
1494 size_t hlen, nlen; | |
1495 const char *tmp, *ret; | |
1496 | |
1497 g_return_val_if_fail(haystack != NULL, NULL); | |
1498 g_return_val_if_fail(needle != NULL, NULL); | |
1499 | |
1500 hlen = strlen(haystack); | |
1501 nlen = strlen(needle); | |
1502 tmp = haystack, | |
1503 ret = NULL; | |
1504 | |
1505 g_return_val_if_fail(hlen > 0, NULL); | |
1506 g_return_val_if_fail(nlen > 0, NULL); | |
1507 | |
1508 while (*tmp && !ret) { | |
1509 if (!g_ascii_strncasecmp(needle, tmp, nlen)) | |
1510 ret = tmp; | |
1511 else | |
1512 tmp++; | |
1513 } | |
1514 | |
1515 return ret; | |
1516 } | |
1517 | |
1518 char * | |
1519 gaim_str_size_to_units(size_t size) | |
1520 { | |
1521 static const char *size_str[4] = { "bytes", "KB", "MB", "GB" }; | |
1522 float size_mag; | |
1523 int size_index = 0; | |
1524 | |
1525 if (size == -1) { | |
1526 return g_strdup(_("Calculating...")); | |
1527 } | |
1528 else if (size == 0) { | |
1529 return g_strdup(_("Unknown.")); | |
1530 } | |
1531 else { | |
1532 size_mag = (float)size; | |
1533 | |
1534 while ((size_index < 4) && (size_mag > 1024)) { | |
1535 size_mag /= 1024; | |
1536 size_index++; | |
1537 } | |
1538 | |
1539 return g_strdup_printf("%.2f %s", size_mag, size_str[size_index]); | |
1540 } | |
1541 } | |
1542 | |
1543 char * | |
1544 gaim_str_seconds_to_string(guint sec) | |
1545 { | |
1546 guint daze, hrs, min; | |
1547 char *ret = NULL; | |
1548 | |
1549 daze = sec / (60 * 60 * 24); | |
1550 hrs = (sec % (60 * 60 * 24)) / (60 * 60); | |
1551 min = (sec % (60 * 60)) / 60; | |
1552 sec = min % 60; | |
1553 | |
1554 if (daze) { | |
1555 if (hrs || min) { | |
1556 if (hrs) { | |
1557 if (min) { | |
1558 ret = g_strdup_printf( | |
1559 "%d %s, %d %s, %d %s.", | |
1560 daze, ngettext("day","days",daze), | |
1561 hrs, ngettext("hour","hours",hrs), min, ngettext("minute","minutes",min)); | |
1562 } else { | |
1563 ret = g_strdup_printf( | |
1564 "%d %s, %d %s.", | |
1565 daze, ngettext("day","days",daze), hrs, ngettext("hour","hours",hrs)); | |
1566 } | |
1567 } else { | |
1568 ret = g_strdup_printf( | |
1569 "%d %s, %d %s.", | |
1570 daze, ngettext("day","days",daze), min, ngettext("minute","minutes",min)); | |
1571 } | |
1572 } else | |
1573 ret = g_strdup_printf("%d %s.", daze, ngettext("day","days",daze)); | |
1574 } else { | |
1575 if (hrs) { | |
1576 if (min) { | |
1577 ret = g_strdup_printf( | |
1578 "%d %s, %d %s.", | |
1579 hrs, ngettext("hour","hours",hrs), min, ngettext("minute","minutes",min)); | |
1580 } else { | |
1581 ret = g_strdup_printf("%d %s.", hrs, ngettext("hour","hours",hrs)); | |
1582 } | |
1583 } else { | |
1584 ret = g_strdup_printf("%d %s.", min, ngettext("minute","minutes",min)); | |
1585 } | |
1586 } | |
1587 | |
1588 return ret; | |
1589 } | |
1590 | |
1591 /************************************************************************** | |
1592 * URI/URL Functions | |
1593 **************************************************************************/ | |
1598 gboolean | 1594 gboolean |
1599 gaim_url_parse(const char *url, char **ret_host, int *ret_port, | 1595 gaim_url_parse(const char *url, char **ret_host, int *ret_port, |
1600 char **ret_path) | 1596 char **ret_path) |
1601 { | 1597 { |
1602 char scan_info[255]; | 1598 char scan_info[255]; |
1918 destroy_fetch_url_data(gfud); | 1914 destroy_fetch_url_data(gfud); |
1919 | 1915 |
1920 cb(user_data, g_strdup(_("g003: Error opening connection.\n")), 0); | 1916 cb(user_data, g_strdup(_("g003: Error opening connection.\n")), 0); |
1921 } | 1917 } |
1922 } | 1918 } |
1919 | |
1920 | |
1921 /************************************************************************** | |
1922 * UTF8 String Functions | |
1923 **************************************************************************/ | |
1924 char * | |
1925 gaim_utf8_try_convert(const char *str) | |
1926 { | |
1927 gsize converted; | |
1928 char *utf8; | |
1929 | |
1930 g_return_val_if_fail(str != NULL, NULL); | |
1931 | |
1932 if (g_utf8_validate(str, -1, NULL)) { | |
1933 return g_strdup(str); | |
1934 } | |
1935 | |
1936 utf8 = g_locale_to_utf8(str, -1, &converted, NULL, NULL); | |
1937 if (utf8) | |
1938 return(utf8); | |
1939 | |
1940 g_free(utf8); | |
1941 | |
1942 utf8 = g_convert(str, -1, "UTF-8", "ISO-8859-15", &converted, NULL, NULL); | |
1943 if (utf8 && converted == strlen (str)) { | |
1944 return(utf8); | |
1945 } else if (utf8) { | |
1946 g_free(utf8); | |
1947 } | |
1948 | |
1949 return(NULL); | |
1950 } | |
1951 | |
1952 int | |
1953 gaim_utf8_strcasecmp(const char *a, const char *b) | |
1954 { | |
1955 char *a_norm = NULL; | |
1956 char *b_norm = NULL; | |
1957 int ret = -1; | |
1958 | |
1959 if(!a && b) | |
1960 return -1; | |
1961 else if(!b && a) | |
1962 return 1; | |
1963 else if(!a && !b) | |
1964 return 0; | |
1965 | |
1966 if(!g_utf8_validate(a, -1, NULL) || !g_utf8_validate(b, -1, NULL)) | |
1967 { | |
1968 gaim_debug_error("gaim_utf8_strcasecmp", | |
1969 "One or both parameters are invalid UTF8\n"); | |
1970 return ret; | |
1971 } | |
1972 | |
1973 a_norm = g_utf8_casefold(a, -1); | |
1974 b_norm = g_utf8_casefold(b, -1); | |
1975 ret = g_utf8_collate(a_norm, b_norm); | |
1976 g_free(a_norm); | |
1977 g_free(b_norm); | |
1978 | |
1979 return ret; | |
1980 } |