00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026 #ifdef HAVE_CONFIG_H
00027 # include "config.h"
00028 #endif
00029
00030 #include "audstrings.h"
00031
00032 #include <stdio.h>
00033 #include <glib.h>
00034 #include <audacious/i18n.h>
00035 #include <string.h>
00036 #include <ctype.h>
00037
00044 gchar *
00045 escape_shell_chars(const gchar * string)
00046 {
00047 const gchar *special = "$`\"\\";
00048 const gchar *in = string;
00049 gchar *out, *escaped;
00050 gint num = 0;
00051
00052 while (*in != '\0')
00053 if (strchr(special, *in++))
00054 num++;
00055
00056 escaped = g_malloc(strlen(string) + num + 1);
00057
00058 in = string;
00059 out = escaped;
00060
00061 while (*in != '\0') {
00062 if (strchr(special, *in))
00063 *out++ = '\\';
00064 *out++ = *in++;
00065 }
00066 *out = '\0';
00067
00068 return escaped;
00069 }
00070
00077 static gchar *
00078 str_replace_drive_letter(gchar * str)
00079 {
00080 gchar *match, *match_end;
00081
00082 g_return_val_if_fail(str != NULL, NULL);
00083
00084 while ((match = strstr(str, ":\\")) != NULL) {
00085 match--;
00086 match_end = match + 3;
00087 *match++ = '/';
00088 while (*match_end)
00089 *match++ = *match_end++;
00090 *match = 0;
00091 }
00092
00093 return str;
00094 }
00095
00096 gchar *
00097 str_append(gchar * str, const gchar * add_str)
00098 {
00099 return str_replace(str, g_strconcat(str, add_str, NULL));
00100 }
00101
00102 gchar *
00103 str_replace(gchar * str, gchar * new_str)
00104 {
00105 g_free(str);
00106 return new_str;
00107 }
00108
00109 void
00110 str_replace_in(gchar ** str, gchar * new_str)
00111 {
00112 *str = str_replace(*str, new_str);
00113 }
00114
00115 gboolean
00116 str_has_prefix_nocase(const gchar * str, const gchar * prefix)
00117 {
00118
00119 return (str != NULL && (strncasecmp(str, prefix, strlen(prefix)) == 0));
00120 }
00121
00122 gboolean
00123 str_has_suffix_nocase(const gchar * str, const gchar * suffix)
00124 {
00125 return (str != NULL && strcasecmp(str + strlen(str) - strlen(suffix), suffix) == 0);
00126 }
00127
00128 gboolean
00129 str_has_suffixes_nocase(const gchar * str, gchar * const *suffixes)
00130 {
00131 gchar *const *suffix;
00132
00133 g_return_val_if_fail(str != NULL, FALSE);
00134 g_return_val_if_fail(suffixes != NULL, FALSE);
00135
00136 for (suffix = suffixes; *suffix; suffix++)
00137 if (str_has_suffix_nocase(str, *suffix))
00138 return TRUE;
00139
00140 return FALSE;
00141 }
00142
00143 gchar *
00144 str_to_utf8_fallback(const gchar * str)
00145 {
00146 gchar *out_str, *convert_str, *chr;
00147
00148 if (!str)
00149 return NULL;
00150
00151 convert_str = g_strdup(str);
00152 for (chr = convert_str; *chr; chr++) {
00153 if (*chr & 0x80)
00154 *chr = '?';
00155 }
00156
00157 out_str = g_strconcat(convert_str, _(" (invalid UTF-8)"), NULL);
00158 g_free(convert_str);
00159
00160 return out_str;
00161 }
00162
00169 gchar *(*str_to_utf8)(const gchar * str) = str_to_utf8_fallback;
00170
00171 gchar *(*chardet_to_utf8)(const gchar *str, gssize len,
00172 gsize *arg_bytes_read, gsize *arg_bytes_write,
00173 GError **arg_error) = NULL;
00174
00175 #ifdef HAVE_EXECINFO_H
00176 # include <execinfo.h>
00177 #endif
00178
00193 gchar *
00194 str_assert_utf8(const gchar * str)
00195 {
00196
00197 if (str == NULL)
00198 return NULL;
00199
00200
00201 if (!g_utf8_validate(str, -1, NULL)) {
00202 #ifdef HAVE_EXECINFO_H
00203 gint i, nsymbols;
00204 const gint nsymmax = 50;
00205 void *addrbuf[nsymmax];
00206 gchar **symbols;
00207 nsymbols = backtrace(addrbuf, nsymmax);
00208 symbols = backtrace_symbols(addrbuf, nsymbols);
00209
00210 fprintf(stderr, "String '%s' was not UTF-8! Backtrace (%d):\n", str, nsymbols);
00211
00212 for (i = 0; i < nsymbols; i++)
00213 fprintf(stderr, " #%d: %s\n", i, symbols[i]);
00214
00215 free(symbols);
00216 #else
00217 g_warning("String '%s' was not UTF-8!", str);
00218 #endif
00219 return str_to_utf8(str);
00220 } else
00221 return g_strdup(str);
00222 }
00223
00224
00225 const gchar *
00226 str_skip_chars(const gchar * str, const gchar * chars)
00227 {
00228 while (strchr(chars, *str) != NULL)
00229 str++;
00230 return str;
00231 }
00232
00233 const void * memfind (const void * mem, gint size, const void * token, gint
00234 length)
00235 {
00236 if (! length)
00237 return mem;
00238
00239 size -= length - 1;
00240
00241 while (size > 0)
00242 {
00243 const void * maybe = memchr (mem, * (guchar *) token, size);
00244
00245 if (maybe == NULL)
00246 return NULL;
00247
00248 if (! memcmp (maybe, token, length))
00249 return maybe;
00250
00251 size -= (guchar *) maybe + 1 - (guchar *) mem;
00252 mem = (guchar *) maybe + 1;
00253 }
00254
00255 return NULL;
00256 }
00257
00258 gchar *
00259 convert_dos_path(gchar * path)
00260 {
00261 g_return_val_if_fail(path != NULL, NULL);
00262
00263
00264 str_replace_drive_letter(path);
00265
00266
00267 string_replace_char (path, '\\', '/');
00268
00269 return path;
00270 }
00271
00284 gchar *
00285 filename_get_subtune(const gchar * filename, gint * track)
00286 {
00287 gchar *pos;
00288
00289 if ((pos = strrchr(filename, '?')) != NULL)
00290 {
00291 const gchar *s = pos + 1;
00292 while (*s != '\0' && g_ascii_isdigit(*s)) s++;
00293 if (*s == '\0') {
00294 if (track != NULL)
00295 *track = atoi(pos + 1);
00296 return pos;
00297 }
00298 }
00299
00300 return NULL;
00301 }
00302
00315 gchar *
00316 filename_split_subtune(const gchar * filename, gint * track)
00317 {
00318 gchar *result;
00319 gchar *pos;
00320
00321 g_return_val_if_fail(filename != NULL, NULL);
00322
00323 result = g_strdup(filename);
00324 g_return_val_if_fail(result != NULL, NULL);
00325
00326 if ((pos = filename_get_subtune(result, track)) != NULL)
00327 *pos = '\0';
00328
00329 return result;
00330 }
00331
00332 void string_replace_char (gchar * string, gchar old_str, gchar new_str)
00333 {
00334 while ((string = strchr (string, old_str)) != NULL)
00335 * string = new_str;
00336 }
00337
00338 static inline gchar get_hex_digit (const gchar * * get)
00339 {
00340 gchar c = * * get;
00341
00342 if (! c)
00343 return 0;
00344
00345 (* get) ++;
00346
00347 if (c < 'A')
00348 return c - '0';
00349 if (c < 'a')
00350 return c - 'A' + 10;
00351
00352 return c - 'a' + 10;
00353 }
00354
00355
00356
00357
00358 static void string_decode_percent_2 (const gchar * from, gchar * to)
00359 {
00360 gchar c;
00361 while ((c = * from ++))
00362 * to ++ = (c != '%') ? c : ((get_hex_digit (& from) << 4) | get_hex_digit
00363 (& from));
00364
00365 * to = 0;
00366 }
00367
00368
00369
00370 void string_decode_percent (gchar * s)
00371 {
00372 string_decode_percent_2 (s, s);
00373 }
00374
00375
00376
00377 static gboolean is_legal_char (gchar c, gboolean is_filename)
00378 {
00379 return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || (c >= '0' && c <=
00380 '9') || (strchr ("-_.~", c) != NULL) || (is_filename && c == '/');
00381 }
00382
00383 static gchar make_hex_digit (gint i)
00384 {
00385 if (i < 10)
00386 return '0' + i;
00387 else
00388 return ('A' - 10) + i;
00389 }
00390
00391
00392
00393 gchar * string_encode_percent (const gchar * string, gboolean is_filename)
00394 {
00395 gint length = 0;
00396 const gchar * get;
00397 gchar c;
00398 gchar * new, * set;
00399
00400 for (get = string; (c = * get); get ++)
00401 {
00402 if (is_legal_char (c, is_filename))
00403 length ++;
00404 else
00405 length += 3;
00406 }
00407
00408 new = g_malloc (length + 1);
00409 set = new;
00410
00411 for (get = string; (c = * get); get ++)
00412 {
00413 if (is_legal_char (c, is_filename))
00414 * set ++ = c;
00415 else
00416 {
00417 * set ++ = '%';
00418 * set ++ = make_hex_digit (((guchar) c) >> 4);
00419 * set ++ = make_hex_digit (c & 0xF);
00420 }
00421 }
00422
00423 * set = 0;
00424 return new;
00425 }
00426
00427
00428
00429
00430 gboolean uri_is_utf8 (const gchar * uri, gboolean warn)
00431 {
00432 gchar buf[strlen (uri) + 1];
00433 string_decode_percent_2 (uri, buf);
00434
00435 if (g_utf8_validate (buf, -1, NULL))
00436 return TRUE;
00437
00438 if (warn)
00439 fprintf (stderr, "URI is not UTF-8: %s.\n", buf);
00440
00441 return FALSE;
00442 }
00443
00444
00445
00446
00447
00448
00449
00450
00451
00452
00453
00454
00455
00456
00457
00458
00459
00460
00461
00462
00463
00464
00465 gchar * uri_to_utf8 (const gchar * uri)
00466 {
00467 if (strncmp (uri, "file://", 7))
00468 return g_strdup (uri);
00469
00470
00471 gchar buf[strlen (uri + 7) + 1];
00472 string_decode_percent_2 (uri + 7, buf);
00473
00474
00475 return filename_to_uri (buf);
00476 }
00477
00478
00479
00480
00481
00482 void uri_check_utf8 (gchar * * uri, gboolean warn)
00483 {
00484 if (uri_is_utf8 (* uri, warn))
00485 return;
00486
00487 gchar * copy = uri_to_utf8 (* uri);
00488 g_free (* uri);
00489 * uri = copy;
00490 }
00491
00492
00493
00494
00495 gchar * filename_to_uri (const gchar * name)
00496 {
00497 gchar * utf8 = g_locale_to_utf8 (name, -1, NULL, NULL, NULL);
00498 gchar * enc = string_encode_percent (utf8 ? utf8 : name, TRUE);
00499 g_free (utf8);
00500 gchar * uri = g_strdup_printf ("file://%s", enc);
00501 g_free (enc);
00502 return uri;
00503 }
00504
00505
00506
00507
00508 gchar * uri_to_filename (const gchar * uri)
00509 {
00510 g_return_val_if_fail (! strncmp (uri, "file://", 7), NULL);
00511 gchar buf[strlen (uri + 7) + 1];
00512 string_decode_percent_2 (uri + 7, buf);
00513 gchar * name = g_locale_from_utf8 (buf, -1, NULL, NULL, NULL);
00514 return name ? name : g_strdup (buf);
00515 }
00516
00517 void string_cut_extension(gchar *string)
00518 {
00519 gchar *period = strrchr(string, '.');
00520
00521 if (period != NULL)
00522 *period = 0;
00523 }
00524
00525
00526
00527
00528
00529 gint string_compare (const gchar * ap, const gchar * bp)
00530 {
00531 if (ap == NULL)
00532 return (bp == NULL) ? 0 : -1;
00533 if (bp == NULL)
00534 return 1;
00535
00536 guchar a = * ap ++, b = * bp ++;
00537 for (; a || b; a = * ap ++, b = * bp ++)
00538 {
00539 if (a > '9' || b > '9' || a < '0' || b < '0')
00540 {
00541 if (a <= 'Z' && a >= 'A')
00542 a += 'a' - 'A';
00543 if (b <= 'Z' && b >= 'A')
00544 b += 'a' - 'A';
00545
00546 if (a > b)
00547 return 1;
00548 if (a < b)
00549 return -1;
00550 }
00551 else
00552 {
00553 gint x = a - '0';
00554 for (; (a = * ap) <= '9' && a >= '0'; ap ++)
00555 x = 10 * x + (a - '0');
00556
00557 gint y = b - '0';
00558 for (; (b = * bp) >= '0' && b <= '9'; bp ++)
00559 y = 10 * y + (b - '0');
00560
00561 if (x > y)
00562 return 1;
00563 if (x < y)
00564 return -1;
00565 }
00566 }
00567
00568 return 0;
00569 }
00570
00571
00572
00573 gint string_compare_encoded (const gchar * ap, const gchar * bp)
00574 {
00575 if (ap == NULL)
00576 return (bp == NULL) ? 0 : -1;
00577 if (bp == NULL)
00578 return 1;
00579
00580 guchar a = * ap ++, b = * bp ++;
00581 for (; a || b; a = * ap ++, b = * bp ++)
00582 {
00583 if (a == '%')
00584 a = (get_hex_digit (& ap) << 4) | get_hex_digit (& ap);
00585 if (b == '%')
00586 b = (get_hex_digit (& bp) << 4) | get_hex_digit (& bp);
00587
00588 if (a > '9' || b > '9' || a < '0' || b < '0')
00589 {
00590 if (a <= 'Z' && a >= 'A')
00591 a += 'a' - 'A';
00592 if (b <= 'Z' && b >= 'A')
00593 b += 'a' - 'A';
00594
00595 if (a > b)
00596 return 1;
00597 if (a < b)
00598 return -1;
00599 }
00600 else
00601 {
00602 gint x = a - '0';
00603 for (; (a = * ap) <= '9' && a >= '0'; ap ++)
00604 x = 10 * x + (a - '0');
00605
00606 gint y = b - '0';
00607 for (; (b = * bp) >= '0' && b <= '9'; bp ++)
00608 y = 10 * y + (b - '0');
00609
00610 if (x > y)
00611 return 1;
00612 if (x < y)
00613 return -1;
00614 }
00615 }
00616
00617 return 0;
00618 }