00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #include <limits.h>
00022 #include <math.h>
00023 #include <stdio.h>
00024 #include <stdlib.h>
00025 #include <glib.h>
00026 #include <string.h>
00027 #include <ctype.h>
00028
00029 #include <audacious/i18n.h>
00030
00031 #include "audstrings.h"
00032 #include "config.h"
00033
00034 #define FROM_HEX(c) ((c) < 'A' ? (c) - '0' : (c) < 'a' ? 10 + (c) - 'A' : 10 + (c) - 'a')
00035 #define TO_HEX(i) ((i) < 10 ? '0' + (i) : 'A' + (i) - 10)
00036 #define IS_LEGAL(c) (((c) >= 'A' && (c) <= 'Z') || ((c) >= 'a' && (c) <= 'z') \
00037 || ((c) >= '0' && (c) <= '9') || (strchr ("-_.~/", (c))))
00038
00039 bool_t str_has_prefix_nocase (const char * str, const char * prefix)
00040 {
00041 return ! g_ascii_strncasecmp (str, prefix, strlen (prefix));
00042 }
00043
00044 bool_t str_has_suffix_nocase (const char * str, const char * suffix)
00045 {
00046 int len1 = strlen (str);
00047 int len2 = strlen (suffix);
00048
00049 if (len2 > len1)
00050 return FALSE;
00051
00052 return ! g_ascii_strcasecmp (str + len1 - len2, suffix);
00053 }
00054
00055 static char * (* str_to_utf8_impl) (const char *) = NULL;
00056 static char * (* str_to_utf8_full_impl) (const char *, int, int *, int *) = NULL;
00057
00058 void str_set_utf8_impl (char * (* stu_impl) (const char *),
00059 char * (* stuf_impl) (const char *, int, int *, int *))
00060 {
00061 str_to_utf8_impl = stu_impl;
00062 str_to_utf8_full_impl = stuf_impl;
00063 }
00064
00065 char * str_to_utf8 (const char * str)
00066 {
00067 g_return_val_if_fail (str_to_utf8_impl, NULL);
00068 return str_to_utf8_impl (str);
00069 }
00070
00071 char * str_to_utf8_full (const char * str, int len, int * bytes_read, int * bytes_written)
00072 {
00073 g_return_val_if_fail (str_to_utf8_full_impl, NULL);
00074 return str_to_utf8_full_impl (str, len, bytes_read, bytes_written);
00075 }
00076
00077 void string_replace_char (char * string, char old_str, char new_str)
00078 {
00079 while ((string = strchr (string, old_str)) != NULL)
00080 * string = new_str;
00081 }
00082
00083
00084
00085
00086
00087 void str_decode_percent (const char * str, int len, char * out)
00088 {
00089 if (len < 0)
00090 len = INT_MAX;
00091
00092 while (len --)
00093 {
00094 char c = * str ++;
00095 if (! c)
00096 break;
00097
00098 if (c == '%' && len >= 2 && str[0] && str[1])
00099 {
00100 c = (FROM_HEX (str[0]) << 4) | FROM_HEX (str[1]);
00101 str += 2;
00102 len -= 2;
00103 }
00104
00105 * out ++ = c;
00106 }
00107
00108 * out = 0;
00109 }
00110
00111
00112
00113
00114
00115 void str_encode_percent (const char * str, int len, char * out)
00116 {
00117 if (len < 0)
00118 len = INT_MAX;
00119
00120 while (len --)
00121 {
00122 char c = * str ++;
00123 if (! c)
00124 break;
00125
00126 if (IS_LEGAL (c))
00127 * out ++ = c;
00128 else
00129 {
00130 * out ++ = '%';
00131 * out ++ = TO_HEX ((unsigned char) c >> 4);
00132 * out ++ = TO_HEX (c & 0xF);
00133 }
00134 }
00135
00136 * out = 0;
00137 }
00138
00139
00140
00141
00142
00143 char * filename_to_uri (const char * name)
00144 {
00145 char * utf8 = g_locale_to_utf8 (name, -1, NULL, NULL, NULL);
00146 if (! utf8)
00147 {
00148 fprintf (stderr, "Cannot convert filename from system locale: %s\n", name);
00149 return NULL;
00150 }
00151
00152 #ifdef _WIN32
00153 string_replace_char (utf8, '\\', '/');
00154 #endif
00155 char enc[3 * strlen (utf8) + 1];
00156 str_encode_percent (utf8, -1, enc);
00157
00158 g_free (utf8);
00159
00160 #ifdef _WIN32
00161 return g_strdup_printf ("file:///%s", enc);
00162 #else
00163 return g_strdup_printf ("file://%s", enc);
00164 #endif
00165 }
00166
00167
00168
00169
00170
00171 char * uri_to_filename (const char * uri)
00172 {
00173 #ifdef _WIN32
00174 g_return_val_if_fail (! strncmp (uri, "file:///", 8), NULL);
00175 char buf[strlen (uri + 8) + 1];
00176 str_decode_percent (uri + 8, -1, buf);
00177 #else
00178 g_return_val_if_fail (! strncmp (uri, "file://", 7), NULL);
00179 char buf[strlen (uri + 7) + 1];
00180 str_decode_percent (uri + 7, -1, buf);
00181 #endif
00182 #ifdef _WIN32
00183 string_replace_char (buf, '/', '\\');
00184 #endif
00185
00186 char * name = g_locale_from_utf8 (buf, -1, NULL, NULL, NULL);
00187 if (! name)
00188 fprintf (stderr, "Cannot convert filename to system locale: %s\n", buf);
00189
00190 return name;
00191 }
00192
00193
00194
00195
00196 char * uri_to_display (const char * uri)
00197 {
00198 if (! strncmp (uri, "cdda://?", 8))
00199 return g_strdup_printf (_("Audio CD, track %s"), uri + 8);
00200
00201 char buf[strlen (uri) + 1];
00202
00203 #ifdef _WIN32
00204 if (! strncmp (uri, "file:///", 8))
00205 {
00206 str_decode_percent (uri + 8, -1, buf);
00207 string_replace_char (buf, '/', '\\');
00208 }
00209 #else
00210 if (! strncmp (uri, "file://", 7))
00211 str_decode_percent (uri + 7, -1, buf);
00212 #endif
00213 else
00214 str_decode_percent (uri, -1, buf);
00215
00216 return g_strdup (buf);
00217 }
00218
00219 void uri_parse (const char * uri, const char * * base_p, const char * * ext_p,
00220 const char * * sub_p, int * isub_p)
00221 {
00222 const char * end = uri + strlen (uri);
00223 const char * base, * ext, * sub, * c;
00224 int isub = 0;
00225 char junk;
00226
00227 if ((c = strrchr (uri, '/')))
00228 base = c + 1;
00229 else
00230 base = end;
00231
00232 if ((c = strrchr (base, '?')) && sscanf (c + 1, "%d%c", & isub, & junk) == 1)
00233 sub = c;
00234 else
00235 sub = end;
00236
00237 char buf[sub - base + 1];
00238 memcpy (buf, base, sub - base);
00239 buf[sub - base] = 0;
00240
00241 if ((c = strrchr (buf, '.')))
00242 ext = base + (c - buf);
00243 else
00244 ext = sub;
00245
00246 if (base_p)
00247 * base_p = base;
00248 if (ext_p)
00249 * ext_p = ext;
00250 if (sub_p)
00251 * sub_p = sub;
00252 if (isub_p)
00253 * isub_p = isub;
00254 }
00255
00256
00257
00258
00259
00260 int string_compare (const char * ap, const char * bp)
00261 {
00262 if (ap == NULL)
00263 return (bp == NULL) ? 0 : -1;
00264 if (bp == NULL)
00265 return 1;
00266
00267 unsigned char a = * ap ++, b = * bp ++;
00268 for (; a || b; a = * ap ++, b = * bp ++)
00269 {
00270 if (a > '9' || b > '9' || a < '0' || b < '0')
00271 {
00272 if (a <= 'Z' && a >= 'A')
00273 a += 'a' - 'A';
00274 if (b <= 'Z' && b >= 'A')
00275 b += 'a' - 'A';
00276
00277 if (a > b)
00278 return 1;
00279 if (a < b)
00280 return -1;
00281 }
00282 else
00283 {
00284 int x = a - '0';
00285 for (; (a = * ap) <= '9' && a >= '0'; ap ++)
00286 x = 10 * x + (a - '0');
00287
00288 int y = b - '0';
00289 for (; (b = * bp) >= '0' && b <= '9'; bp ++)
00290 y = 10 * y + (b - '0');
00291
00292 if (x > y)
00293 return 1;
00294 if (x < y)
00295 return -1;
00296 }
00297 }
00298
00299 return 0;
00300 }
00301
00302
00303
00304 int string_compare_encoded (const char * ap, const char * bp)
00305 {
00306 if (ap == NULL)
00307 return (bp == NULL) ? 0 : -1;
00308 if (bp == NULL)
00309 return 1;
00310
00311 unsigned char a = * ap ++, b = * bp ++;
00312 for (; a || b; a = * ap ++, b = * bp ++)
00313 {
00314 if (a == '%' && ap[0] && ap[1])
00315 {
00316 a = (FROM_HEX (ap[0]) << 4) | FROM_HEX (ap[1]);
00317 ap += 2;
00318 }
00319 if (b == '%' && bp[0] && bp[1])
00320 {
00321 b = (FROM_HEX (bp[0]) << 4) | FROM_HEX (bp[1]);
00322 bp += 2;
00323 }
00324
00325 if (a > '9' || b > '9' || a < '0' || b < '0')
00326 {
00327 if (a <= 'Z' && a >= 'A')
00328 a += 'a' - 'A';
00329 if (b <= 'Z' && b >= 'A')
00330 b += 'a' - 'A';
00331
00332 if (a > b)
00333 return 1;
00334 if (a < b)
00335 return -1;
00336 }
00337 else
00338 {
00339 int x = a - '0';
00340 for (; (a = * ap) <= '9' && a >= '0'; ap ++)
00341 x = 10 * x + (a - '0');
00342
00343 int y = b - '0';
00344 for (; (b = * bp) >= '0' && b <= '9'; bp ++)
00345 y = 10 * y + (b - '0');
00346
00347 if (x > y)
00348 return 1;
00349 if (x < y)
00350 return -1;
00351 }
00352 }
00353
00354 return 0;
00355 }
00356
00357 char *
00358 str_replace_fragment(char *s, int size, const char *old, const char *new)
00359 {
00360 char *ptr = s;
00361 int left = strlen(s);
00362 int avail = size - (left + 1);
00363 int oldlen = strlen(old);
00364 int newlen = strlen(new);
00365 int diff = newlen - oldlen;
00366
00367 while (left >= oldlen)
00368 {
00369 if (strncmp(ptr, old, oldlen))
00370 {
00371 left--;
00372 ptr++;
00373 continue;
00374 }
00375
00376 if (diff > avail)
00377 break;
00378
00379 if (diff != 0)
00380 memmove(ptr + oldlen + diff, ptr + oldlen, left + 1 - oldlen);
00381
00382 memcpy(ptr, new, newlen);
00383 ptr += newlen;
00384 left -= oldlen;
00385 }
00386
00387 return s;
00388 }
00389
00390
00391
00392
00393
00394
00395
00396
00397
00398
00399
00400
00401
00402
00403
00404
00405 bool_t string_to_int (const char * string, int * addr)
00406 {
00407 bool_t neg = (string[0] == '-');
00408 if (neg)
00409 string ++;
00410
00411 int val = 0;
00412 char c;
00413
00414 while ((c = * string ++))
00415 {
00416 if (c < '0' || c > '9' || val > 100000000)
00417 goto ERR;
00418
00419 val = val * 10 + (c - '0');
00420 }
00421
00422 if (val > 1000000000)
00423 goto ERR;
00424
00425 * addr = neg ? -val : val;
00426 return TRUE;
00427
00428 ERR:
00429 return FALSE;
00430 }
00431
00432 bool_t string_to_double (const char * string, double * addr)
00433 {
00434 bool_t neg = (string[0] == '-');
00435 if (neg)
00436 string ++;
00437
00438 const char * p = strchr (string, '.');
00439 int i, f;
00440
00441 if (p)
00442 {
00443 char buf[11];
00444 int len;
00445
00446 len = p - string;
00447 if (len > 10)
00448 goto ERR;
00449
00450 memcpy (buf, string, len);
00451 buf[len] = 0;
00452
00453 if (! string_to_int (buf, & i))
00454 goto ERR;
00455
00456 len = strlen (p + 1);
00457 if (len > 6)
00458 goto ERR;
00459
00460 memcpy (buf, p + 1, len);
00461 memset (buf + len, '0', 6 - len);
00462 buf[6] = 0;
00463
00464 if (! string_to_int (buf, & f))
00465 goto ERR;
00466 }
00467 else
00468 {
00469 if (! string_to_int (string, & i))
00470 goto ERR;
00471
00472 f = 0;
00473 }
00474
00475 double val = i + (double) f / 1000000;
00476 if (val > 1000000000)
00477 goto ERR;
00478
00479 * addr = neg ? -val : val;
00480 return TRUE;
00481
00482 ERR:
00483 return FALSE;
00484 }
00485
00486 char * int_to_string (int val)
00487 {
00488 g_return_val_if_fail (val >= -1000000000 && val <= 1000000000, NULL);
00489 return g_strdup_printf ("%d", val);
00490 }
00491
00492 char * double_to_string (double val)
00493 {
00494 g_return_val_if_fail (val >= -1000000000 && val <= 1000000000, NULL);
00495
00496 bool_t neg = (val < 0);
00497 if (neg)
00498 val = -val;
00499
00500 int i = floor (val);
00501 int f = round ((val - i) * 1000000);
00502
00503 if (f == 1000000)
00504 {
00505 i ++;
00506 f = 0;
00507 }
00508
00509 char * s = neg ? g_strdup_printf ("-%d.%06d", i, f) : g_strdup_printf ("%d.%06d", i, f);
00510
00511 char * c = s + strlen (s);
00512 while (* (c - 1) == '0')
00513 c --;
00514 if (* (c - 1) == '.')
00515 c --;
00516 * c = 0;
00517
00518 return s;
00519 }
00520
00521 bool_t string_to_double_array (const char * string, double * array, int count)
00522 {
00523 char * * split = g_strsplit (string, ",", -1);
00524 if (g_strv_length (split) != count)
00525 goto ERR;
00526
00527 for (int i = 0; i < count; i ++)
00528 {
00529 if (! string_to_double (split[i], & array[i]))
00530 goto ERR;
00531 }
00532
00533 g_strfreev (split);
00534 return TRUE;
00535
00536 ERR:
00537 g_strfreev (split);
00538 return FALSE;
00539 }
00540
00541 char * double_array_to_string (const double * array, int count)
00542 {
00543 char * * split = g_malloc0 (sizeof (char *) * (count + 1));
00544
00545 for (int i = 0; i < count; i ++)
00546 {
00547 split[i] = double_to_string (array[i]);
00548 if (! split[i])
00549 goto ERR;
00550 }
00551
00552 char * string = g_strjoinv (",", split);
00553 g_strfreev (split);
00554 return string;
00555
00556 ERR:
00557 g_strfreev (split);
00558 return NULL;
00559 }