diff options
Diffstat (limited to 'src/libaudcore/audstrings.cc')
-rw-r--r-- | src/libaudcore/audstrings.cc | 211 |
1 files changed, 134 insertions, 77 deletions
diff --git a/src/libaudcore/audstrings.cc b/src/libaudcore/audstrings.cc index cb2be04..6a89121 100644 --- a/src/libaudcore/audstrings.cc +++ b/src/libaudcore/audstrings.cc @@ -33,6 +33,10 @@ #include "internal.h" #include "runtime.h" +#define MAX_POW10 9 +static const unsigned int_pow10[MAX_POW10 + 1] = + {1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000}; + static const char ascii_to_hex[256] = "\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0" "\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0" @@ -68,6 +72,12 @@ static const char swap_case[256] = #define IS_LEGAL(c) (uri_legal_table[(unsigned char) (c)]) #define SWAP_CASE(c) (swap_case[(unsigned char) (c)]) +#ifdef _WIN32 +#define IS_SEP(c) ((c) == '/' || (c) == '\\') +#else +#define IS_SEP(c) ((c) == '/') +#endif + /* strcmp() that handles nullptr safely */ EXPORT int strcmp_safe (const char * a, const char * b, int len) { @@ -184,13 +194,13 @@ EXPORT unsigned str_calc_hash (const char * s) while (len >= 8) { h = h * 1954312449 + - s[0] * 3963737313 + - s[1] * 1291467969 + - s[2] * 39135393 + - s[3] * 1185921 + - s[4] * 35937 + - s[5] * 1089 + - s[6] * 33 + + (unsigned) s[0] * 3963737313 + + (unsigned) s[1] * 1291467969 + + (unsigned) s[2] * 39135393 + + (unsigned) s[3] * 1185921 + + (unsigned) s[4] * 35937 + + (unsigned) s[5] * 1089 + + (unsigned) s[6] * 33 + s[7]; s += 8; @@ -200,9 +210,9 @@ EXPORT unsigned str_calc_hash (const char * s) if (len >= 4) { h = h * 1185921 + - s[0] * 35937 + - s[1] * 1089 + - s[2] * 33 + + (unsigned) s[0] * 35937 + + (unsigned) s[1] * 1089 + + (unsigned) s[2] * 33 + s[3]; s += 4; @@ -415,6 +425,43 @@ EXPORT StringBuf filename_normalize (StringBuf && filename) return std::move (filename); } +/* note #1: recommended order is filename_contract(filename_normalize(f)) */ +/* note #2: currently assumes filename is UTF-8 (intended for display) */ +EXPORT StringBuf filename_contract (StringBuf && filename) +{ + /* replace home folder with '~' */ + const char * home = get_home_utf8 (); + int homelen = home ? strlen (home) : 0; + + if (homelen && ! strncmp (filename, home, homelen) && + (! filename[homelen] || IS_SEP (filename[homelen]))) + { + filename[0] = '~'; + filename.remove (1, homelen - 1); + } + + return std::move (filename); +} + +/* note #1: recommended order is filename_normalize(filename_expand(f)) */ +/* note #2: currently assumes filename is UTF-8 (intended for display) */ +EXPORT StringBuf filename_expand (StringBuf && filename) +{ + /* expand leading '~' */ + if (filename[0] == '~' && (! filename[1] || IS_SEP(filename[1]))) + { + const char * home = get_home_utf8 (); + + if (home && home[0]) + { + filename[0] = home[0]; + filename.insert (1, home + 1, -1); + } + } + + return std::move (filename); +} + EXPORT StringBuf filename_get_parent (const char * filename) { StringBuf buf = filename_normalize (str_copy (filename)); @@ -454,25 +501,14 @@ EXPORT StringBuf filename_build (const std::initializer_list<const char *> & ele for (const char * s : elems) { -#ifdef _WIN32 - if (set > str && set[-1] != '/' && set[-1] != '\\') + if (set > str && ! IS_SEP (set[-1])) { if (! left) throw std::bad_alloc (); - * set ++ = '\\'; + * set ++ = G_DIR_SEPARATOR; left --; } -#else - if (set > str && set[-1] != '/') - { - if (! left) - throw std::bad_alloc (); - - * set ++ = '/'; - left --; - } -#endif int len = strlen (s); if (len > left) @@ -547,6 +583,14 @@ EXPORT StringBuf uri_to_filename (const char * uri, bool use_locale) } #endif + /* if UTF-8 was requested, make sure the result is valid */ + if (! use_locale) + { + buf.steal (str_to_utf8 (std::move (buf))); + if (! buf) + return StringBuf (); + } + return filename_normalize (std::move (buf)); } @@ -564,20 +608,10 @@ EXPORT StringBuf uri_to_display (const char * uri) if (! buf) return str_copy (_("(character encoding error)")); - if (strncmp (buf, URI_PREFIX, URI_PREFIX_LEN)) - return buf; - - buf.remove (0, URI_PREFIX_LEN); - buf.steal (filename_normalize (std::move (buf))); - - const char * home = get_home_utf8 (); - int homelen = home ? strlen (home) : 0; - - if (homelen && ! strncmp (buf, home, homelen) && - (! buf[homelen] || buf[homelen] == G_DIR_SEPARATOR)) + if (! strncmp (buf, URI_PREFIX, URI_PREFIX_LEN)) { - buf[0] = '~'; - buf.remove (1, homelen - 1); + buf.remove (0, URI_PREFIX_LEN); + return filename_contract (filename_normalize (std::move (buf))); } return buf; @@ -655,7 +689,7 @@ EXPORT StringBuf uri_construct (const char * path, const char * reference) /* absolute filename */ #ifdef _WIN32 - if (path[0] && path[1] == ':' && (path[2] == '/' || path[2] == '\\')) + if (path[0] && path[1] == ':' && IS_SEP (path[2])) #else if (path[0] == '/') #endif @@ -860,24 +894,44 @@ EXPORT StringBuf index_to_str_list (const Index<String> & index, const char * se * have an accuracy of 6 decimal places. */ -static int str_to_uint (const char * string) +static unsigned str_to_uint (const char * string, const char * * end = nullptr, + const char * stop = nullptr) { - int val = 0; - char c; - - while ((c = * string ++) && c >= '0' && c <= '9') + unsigned val = 0; + for (char c; string != stop && (c = * string) >= '0' && c <= '9'; string ++) val = val * 10 + (c - '0'); + if (end) + * end = string; + return val; } +static int digits_for (unsigned val) +{ + int digits = 1; + + for (; val >= 1000; val /= 1000) + digits += 3; + for (; val >= 10; val /= 10) + digits ++; + + return digits; +} + +static void uint_to_str (unsigned val, char * buf, int digits) +{ + for (char * rev = buf + digits; rev > buf; val /= 10) + * (-- rev) = '0' + val % 10; +} + EXPORT int str_to_int (const char * string) { bool neg = (string[0] == '-'); if (neg || string[0] == '+') string ++; - int val = str_to_uint (string); + unsigned val = str_to_uint (string); return neg ? -val : val; } @@ -887,14 +941,14 @@ EXPORT double str_to_double (const char * string) if (neg || string[0] == '+') string ++; - double val = str_to_uint (string); - const char * p = strchr (string, '.'); + const char * p; + double val = str_to_uint (string, & p); - if (p) + if (* (p ++) == '.') { - char buf[7] = "000000"; - memcpy (buf, p + 1, strlen_bounded (p + 1, 6)); - val += str_to_uint (buf) / 1000000.0; + const char * end; + double decimal = str_to_uint (p, & end, p + MAX_POW10); + val += decimal / int_pow10[end - p]; } return neg ? -val : val; @@ -903,26 +957,18 @@ EXPORT double str_to_double (const char * string) EXPORT StringBuf int_to_str (int val) { bool neg = (val < 0); - if (neg) - val = -val; + unsigned absval = neg ? -val : val; - char buf[16]; - char * rev = buf + sizeof buf; + int digits = digits_for (absval); + StringBuf buf ((neg ? 1 : 0) + digits); - while (rev > buf) - { - * (-- rev) = '0' + val % 10; - if (! (val /= 10)) - break; - } + char * set = buf; + if (neg) + * (set ++) = '-'; - if (neg && rev > buf) - * (-- rev) = '-'; + uint_to_str (absval, set, digits); - int len = buf + sizeof buf - rev; - StringBuf buf2 (len); - memcpy (buf2, rev, len); - return buf2; + return buf; } EXPORT StringBuf double_to_str (double val) @@ -931,8 +977,8 @@ EXPORT StringBuf double_to_str (double val) if (neg) val = -val; - int i = floor (val); - int f = round ((val - i) * 1000000); + unsigned i = floor (val); + unsigned f = round ((val - i) * 1000000); if (f == 1000000) { @@ -940,15 +986,26 @@ EXPORT StringBuf double_to_str (double val) f = 0; } - StringBuf buf = str_printf ("%s%d.%06d", neg ? "-" : "", i, f); + int decimals = f ? 6 : 0; + for (; decimals && ! (f % 10); f /= 10) + decimals --; + + int digits = digits_for (i); + StringBuf buf ((neg ? 1 : 0) + digits + (decimals ? 1 : 0) + decimals); + + char * set = buf; + if (neg) + * (set ++) = '-'; + + uint_to_str (i, set, digits); - char * c = buf + buf.len (); - while (c[-1] == '0') - c --; - if (c[-1] == '.') - c --; + if (decimals) + { + set += digits; + * (set ++) = '.'; + uint_to_str (f, set, decimals); + } - buf.resize (c - buf); return buf; } @@ -1001,11 +1058,11 @@ EXPORT StringBuf double_array_to_str (const double * array, int count) EXPORT StringBuf str_format_time (int64_t milliseconds) { int hours = milliseconds / 3600000; - int minutes = (milliseconds / 60000) % 60; + int minutes = milliseconds / 60000; int seconds = (milliseconds / 1000) % 60; - if (hours) - return str_printf ("%d:%02d:%02d", hours, minutes, seconds); + if (hours && aud_get_bool (nullptr, "show_hours")) + return str_printf ("%d:%02d:%02d", hours, minutes % 60, seconds); else { bool zero = aud_get_bool (nullptr, "leading_zero"); |