summaryrefslogtreecommitdiff
path: root/src/libaudcore/audstrings.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/libaudcore/audstrings.cc')
-rw-r--r--src/libaudcore/audstrings.cc211
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");