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 }