2 * This file Copyright (C) 2009-2014 Mnemosyne LLC
4 * It may be used under the GNU GPL versions 2 or 3
5 * or any future license endorsed by Mnemosyne LLC.
7 * $Id: utils.c 14241 2014-01-21 03:10:30Z jordan $
11 #define _GNU_SOURCE /* glibc's string.h needs this to pick up memmem */
14 #if defined (XCODE_BUILD)
15 #define HAVE_GETPAGESIZE
16 #define HAVE_ICONV_OPEN
22 #include <ctype.h> /* isdigit (), isalpha (), tolower () */
24 #include <float.h> /* DBL_EPSILON */
25 #include <locale.h> /* localeconv () */
26 #include <math.h> /* pow (), fabs (), floor () */
30 #include <string.h> /* strerror (), memset (), memmem () */
31 #include <time.h> /* nanosleep () */
33 #ifdef HAVE_ICONV_OPEN
36 #include <libgen.h> /* basename () */
38 #include <sys/types.h>
40 #include <unistd.h> /* stat (), getcwd (), getpagesize () */
42 #include <event2/buffer.h>
43 #include <event2/event.h>
47 #define WINVER WindowsXP /* freeaddrinfo (), getaddrinfo (), getnameinfo () */
48 #include <direct.h> /* _getcwd () */
49 #include <windows.h> /* Sleep (), GetSystemTimeAsFileTime () */
52 #include "transmission.h"
54 #include "ConvertUTF.h"
58 #include "platform.h" /* tr_lockLock (), TR_PATH_MAX */
59 #include "platform-quota.h" /* tr_device_info_create(), tr_device_info_get_free_space(), tr_device_info_free() */
64 time_t __tr_current_time
= 0;
71 tr_localtime_r (const time_t *_clock
, struct tm
*_result
)
73 #ifdef HAVE_LOCALTIME_R
74 return localtime_r (_clock
, _result
);
76 struct tm
*p
= localtime (_clock
);
84 tr_gettimeofday (struct timeval
* tv
)
87 #define DELTA_EPOCH_IN_MICROSECS 11644473600000000Ui64
98 GetSystemTimeAsFileTime(&ft
);
99 tmp
|= ft
.dwHighDateTime
;
101 tmp
|= ft
.dwLowDateTime
;
102 tmp
/= 10; /* to microseconds */
103 tmp
-= DELTA_EPOCH_IN_MICROSECS
;
105 tv
->tv_sec
= tmp
/ 1000000UL;
106 tv
->tv_usec
= tmp
% 1000000UL;
110 #undef DELTA_EPOCH_IN_MICROSECS
113 return gettimeofday (tv
, NULL
);
123 tr_malloc (size_t size
)
125 return size
? malloc (size
) : NULL
;
129 tr_malloc0 (size_t size
)
131 return size
? calloc (1, size
) : NULL
;
142 tr_memdup (const void * src
, size_t byteCount
)
144 return memcpy (tr_malloc (byteCount
), src
, byteCount
);
152 tr_strip_positional_args (const char* str
)
155 static size_t bufsize
= 0;
156 static char * buf
= NULL
;
157 const char * in
= str
;
158 const size_t len
= str
? strlen (str
) : 0;
160 if (!buf
|| (bufsize
< len
))
162 bufsize
= len
* 2 + 1;
163 buf
= tr_renew (char, buf
, bufsize
);
166 for (out
= buf
; str
&& *str
; ++str
)
170 if ((*str
== '%') && isdigit (str
[1]))
172 const char * tmp
= str
+ 1;
173 while (isdigit (*tmp
))
176 str
= tmp
[1]=='\'' ? tmp
+1 : tmp
;
179 if ((*str
== '%') && (str
[1] == '\''))
185 return !in
|| strcmp (buf
, in
) ? buf
: in
;
193 tr_timerAdd (struct event
* timer
, int seconds
, int microseconds
)
197 tv
.tv_usec
= microseconds
;
199 assert (tv
.tv_sec
>= 0);
200 assert (tv
.tv_usec
>= 0);
201 assert (tv
.tv_usec
< 1000000);
203 evtimer_add (timer
, &tv
);
207 tr_timerAddMsec (struct event
* timer
, int msec
)
209 const int seconds
= msec
/ 1000;
210 const int usec
= (msec
%1000) * 1000;
211 tr_timerAdd (timer
, seconds
, usec
);
219 tr_loadFile (const char * path
,
226 const char * const err_fmt
= _("Couldn't read \"%1$s\": %2$s");
228 /* try to stat the file */
230 if (stat (path
, &sb
))
232 const int err
= errno
;
233 tr_logAddDebug (err_fmt
, path
, tr_strerror (errno
));
238 if ((sb
.st_mode
& S_IFMT
) != S_IFREG
)
240 tr_logAddError (err_fmt
, path
, _("Not a regular file"));
245 /* Load the torrent file into our buffer */
246 fd
= tr_open_file_for_scanning (path
);
249 const int err
= errno
;
250 tr_logAddError (err_fmt
, path
, tr_strerror (errno
));
254 buf
= tr_malloc (sb
.st_size
+ 1);
257 const int err
= errno
;
258 tr_logAddError (err_fmt
, path
, _("Memory allocation failed"));
263 n
= read (fd
, buf
, (size_t)sb
.st_size
);
266 const int err
= errno
;
267 tr_logAddError (err_fmt
, path
, tr_strerror (errno
));
275 buf
[ sb
.st_size
] = '\0';
281 tr_basename (const char * path
)
285 char fname
[_MAX_FNAME
], ext
[_MAX_EXT
];
286 if (_splitpath_s (path
, NULL
, 0, NULL
, 0, fname
, sizeof (fname
), ext
, sizeof (ext
)) == 0)
288 const size_t tmpLen
= strlen(fname
) + strlen(ext
) + 2;
289 char * const tmp
= tr_malloc (tmpLen
);
292 if (_makepath_s (tmp
, tmpLen
, NULL
, NULL
, fname
, ext
) == 0)
299 return tr_strdup (".");
303 char * tmp
= tr_strdup (path
);
304 char * ret
= tr_strdup (basename (tmp
));
312 tr_dirname (const char * path
)
316 char drive
[_MAX_DRIVE
], dir
[_MAX_DIR
];
317 if (_splitpath_s (path
, drive
, sizeof (drive
), dir
, sizeof (dir
), NULL
, 0, NULL
, 0) == 0)
319 const size_t tmpLen
= strlen(drive
) + strlen(dir
) + 2;
320 char * const tmp
= tr_malloc (tmpLen
);
323 if (_makepath_s (tmp
, tmpLen
, drive
, dir
, NULL
, NULL
) == 0)
325 size_t len
= strlen(tmp
);
326 while (len
> 0 && (tmp
[len
- 1] == '/' || tmp
[len
- 1] == '\\'))
336 return tr_strdup (".");
340 char * tmp
= tr_strdup (path
);
341 char * ret
= tr_strdup (dirname (tmp
));
349 tr_mkdtemp (char * template)
352 return mkdtemp (template);
354 if (!mktemp (template) || mkdir (template, 0700))
361 * @brief Portability wrapper for mkdir ()
363 * A portability wrapper around mkdir ().
364 * On WIN32, the `permissions' argument is unused.
366 * @return zero on success, or -1 if an error occurred
367 * (in which case errno is set appropriately).
370 tr_mkdir (const char * path
, int permissions UNUSED
)
373 if (path
&& isalpha (path
[0]) && path
[1] == ':' && !path
[2])
377 return mkdir (path
, permissions
);
382 tr_mkdirp (const char * path_in
,
393 /* make a temporary copy of path */
394 path
= tr_strdup (path_in
);
401 /* walk past the root */
403 while (*p
== TR_PATH_DELIMITER
)
408 while ((p
= strchr (pp
, TR_PATH_DELIMITER
)) || (p
= strchr (pp
, '\0')))
416 rv
= stat (path
, &sb
);
420 /* Folder doesn't exist yet */
421 if (tr_mkdir (path
, permissions
))
424 tr_logAddError (_("Couldn't create \"%1$s\": %2$s"), path
, tr_strerror (tmperr
));
430 else if ((sb
.st_mode
& S_IFMT
) != S_IFDIR
)
432 /* Node exists but isn't a folder */
433 char * buf
= tr_strdup_printf (_("File \"%s\" is in the way"), path
);
434 tr_logAddError (_("Couldn't create \"%1$s\": %2$s"), path_in
, buf
);
444 *p
= TR_PATH_DELIMITER
;
454 tr_buildPath (const char *first_element
, ...)
456 const char * element
;
462 /* pass 1: allocate enough space for the string */
463 va_start (vl
, first_element
);
464 element
= first_element
;
467 bufLen
+= strlen (element
) + 1;
468 element
= va_arg (vl
, const char*);
470 pch
= buf
= tr_new (char, bufLen
);
475 /* pass 2: build the string piece by piece */
476 va_start (vl
, first_element
);
477 element
= first_element
;
480 const size_t elementLen
= strlen (element
);
481 memcpy (pch
, element
, elementLen
);
483 *pch
++ = TR_PATH_DELIMITER
;
484 element
= va_arg (vl
, const char*);
488 /* terminate the string. if nonempty, eat the unwanted trailing slash */
493 /* sanity checks & return */
494 assert (pch
- buf
== (off_t
)bufLen
);
499 #define TR_STAT_MTIME(sb)((sb).st_mtimespec.tv_sec)
501 #define TR_STAT_MTIME(sb)((sb).st_mtime)
505 tr_fileExists (const char * filename
, time_t * mtime
)
508 const bool ok
= !stat (filename
, &sb
);
510 if (ok
&& (mtime
!= NULL
))
511 *mtime
= TR_STAT_MTIME (sb
);
517 tr_getDirFreeSpace (const char * dir
)
528 struct tr_device_info
* info
;
529 info
= tr_device_info_create (dir
);
530 free_space
= tr_device_info_get_free_space (info
);
531 tr_device_info_free (info
);
542 evbuffer_free_to_str (struct evbuffer
* buf
)
544 const size_t n
= evbuffer_get_length (buf
);
545 char * ret
= tr_new (char, n
+ 1);
546 evbuffer_copyout (buf
, ret
, n
);
553 tr_strdup (const void * in
)
555 return tr_strndup (in
, in
? (int)strlen ((const char *)in
) : 0);
559 tr_strndup (const void * in
, int len
)
565 out
= tr_strdup (in
);
569 out
= tr_malloc (len
+ 1);
573 memcpy (out
, in
, len
);
582 tr_memmem (const char * haystack
, size_t haystacklen
,
583 const char * needle
, size_t needlelen
)
586 return memmem (haystack
, haystacklen
, needle
, needlelen
);
591 if (needlelen
> haystacklen
|| !haystack
|| !needle
)
593 for (i
=0; i
<=haystacklen
-needlelen
; ++i
)
594 if (!memcmp (haystack
+i
, needle
, needlelen
))
601 tr_strdup_printf (const char * fmt
, ...)
609 len
= evutil_vsnprintf (statbuf
, sizeof (statbuf
), fmt
, ap
);
612 if (len
< sizeof (statbuf
))
614 ret
= tr_strndup (statbuf
, len
);
618 ret
= tr_new (char, len
+ 1);
620 evutil_vsnprintf (ret
, len
+ 1, fmt
, ap
);
630 const char * ret
= strerror (i
);
633 ret
= "Unknown Error";
639 tr_strcmp0 (const char * str1
, const char * str2
)
641 if (str1
&& str2
) return strcmp (str1
, str2
);
651 /* https://bugs.launchpad.net/percona-patches/+bug/526863/+attachment/1160199/+files/solaris_10_fix.patch */
653 tr_strsep (char ** str
, const char * delims
)
656 return strsep (str
, delims
);
660 if (*str
== NULL
) /* no more tokens */
664 while (**str
!= '\0')
666 if (strchr (delims
, **str
) != NULL
)
675 /* there is not another token */
683 tr_strstrip (char * str
)
688 size_t len
= strlen (str
);
690 while (len
&& isspace (str
[len
- 1]))
693 for (pos
= 0; pos
< len
&& isspace (str
[pos
]);)
697 memmove (str
, str
+ pos
, len
);
705 tr_str_has_suffix (const char *str
, const char *suffix
)
715 str_len
= strlen (str
);
716 suffix_len
= strlen (suffix
);
717 if (str_len
< suffix_len
)
720 return !evutil_ascii_strncasecmp (str
+ str_len
- suffix_len
, suffix
, suffix_len
);
732 tr_gettimeofday (&tv
);
733 return (uint64_t) tv
.tv_sec
* 1000 + (tv
.tv_usec
/ 1000);
737 tr_wait_msec (long int msec
)
743 ts
.tv_sec
= msec
/ 1000;
744 ts
.tv_nsec
= (msec
% 1000) * 1000000;
745 nanosleep (&ts
, NULL
);
754 tr_snprintf (char * buf
, size_t buflen
, const char * fmt
, ...)
759 va_start (args
, fmt
);
760 len
= evutil_vsnprintf (buf
, buflen
, fmt
, args
);
766 * Copy src to string dst of size siz. At most siz-1 characters
767 * will be copied. Always NUL terminates (unless siz == 0).
768 * Returns strlen (src); if retval >= siz, truncation occurred.
771 tr_strlcpy (char * dst
, const void * src
, size_t siz
)
774 return strlcpy (dst
, src
, siz
);
783 /* Copy as many bytes as will fit */
788 if ((*d
++ = *s
++) == '\0')
793 /* Not enough room in dst, add NUL and traverse rest of src */
797 *d
= '\0'; /* NUL-terminate dst */
802 return s
- (char*)src
- 1; /* count does not include NUL */
811 tr_getRatio (uint64_t numerator
, uint64_t denominator
)
816 ratio
= numerator
/ (double)denominator
;
817 else if (numerator
> 0)
818 ratio
= TR_RATIO_INF
;
826 tr_sha1_to_hex (char * out
, const uint8_t * sha1
)
829 static const char hex
[] = "0123456789abcdef";
833 const unsigned int val
= *sha1
++;
834 *out
++ = hex
[val
>> 4];
835 *out
++ = hex
[val
& 0xf];
842 tr_hex_to_sha1 (uint8_t * out
, const char * in
)
845 static const char hex
[] = "0123456789abcdef";
849 const int hi
= strchr (hex
, tolower (*in
++)) - hex
;
850 const int lo
= strchr (hex
, tolower (*in
++)) - hex
;
851 *out
++ = (uint8_t)((hi
<<4) | lo
);
860 isValidURLChars (const char * url
, int url_len
)
864 static const char * rfc2396_valid_chars
=
865 "abcdefghijklmnopqrstuvwxyz" /* lowalpha */
866 "ABCDEFGHIJKLMNOPQRSTUVWXYZ" /* upalpha */
867 "0123456789" /* digit */
868 "-_.!~*'()" /* mark */
869 ";/?:@&=+$," /* reserved */
870 "<>#%<\"" /* delims */
871 "{}|\\^[]`"; /* unwise */
876 for (c
=url
, end
=c
+url_len
; c
&& *c
&& c
!=end
; ++c
)
877 if (!strchr (rfc2396_valid_chars
, *c
))
883 /** @brief return true if the URL is a http or https or UDP one that Transmission understands */
885 tr_urlIsValidTracker (const char * url
)
895 const int len
= strlen (url
);
897 valid
= isValidURLChars (url
, len
)
898 && !tr_urlParse (url
, len
, NULL
, NULL
, NULL
, NULL
)
899 && (!memcmp (url
,"http://",7) || !memcmp (url
,"https://",8) || !memcmp (url
,"udp://",6));
905 /** @brief return true if the URL is a http or https or ftp or sftp one that Transmission understands */
907 tr_urlIsValid (const char * url
, int url_len
)
918 url_len
= strlen (url
);
920 valid
= isValidURLChars (url
, url_len
)
921 && !tr_urlParse (url
, url_len
, NULL
, NULL
, NULL
, NULL
)
922 && (!memcmp (url
,"http://",7) || !memcmp (url
,"https://",8) || !memcmp (url
,"ftp://",6) || !memcmp (url
,"sftp://",7));
929 tr_addressIsIP (const char * str
)
932 return tr_address_from_string (&tmp
, str
);
936 tr_urlParse (const char * url_in
,
938 char ** setme_protocol
,
950 const char * host
= NULL
;
951 const char * protocol
= NULL
;
952 const char * path
= NULL
;
954 tmp
= tr_strndup (url_in
, len
);
955 if ((pch
= strstr (tmp
, "://")))
959 protocol_len
= pch
- protocol
;
961 if ((n
= strcspn (pch
, ":/")))
963 const int havePort
= pch
[n
] == ':';
972 port
= strtol (pch
, &end
, 10);
979 err
= !host
|| !path
|| !protocol
;
983 if (!strcmp (protocol
, "udp")) port
= 80;
984 else if (!strcmp (protocol
, "ftp")) port
= 21;
985 else if (!strcmp (protocol
, "sftp")) port
= 22;
986 else if (!strcmp (protocol
, "http")) port
= 80;
987 else if (!strcmp (protocol
, "https")) port
= 443;
992 if (setme_protocol
) *setme_protocol
= tr_strndup (protocol
, protocol_len
);
994 if (setme_host
){ ((char*)host
)[-3] = ':'; *setme_host
=
995 tr_strndup (host
, host_len
); }
997 if (setme_path
){ if (!*path
) *setme_path
= tr_strdup ("/");
998 else if (path
[0] == '/') *setme_path
= tr_strdup (path
);
999 else { ((char*)path
)[-1] = '/'; *setme_path
= tr_strdup (path
- 1); } }
1001 if (setme_port
) *setme_port
= port
;
1010 #include <openssl/sha.h>
1011 #include <openssl/hmac.h>
1012 #include <openssl/evp.h>
1013 #include <openssl/bio.h>
1014 #include <openssl/buffer.h>
1017 tr_base64_encode (const void * input
, int length
, int * setme_len
)
1029 length
= (int)strlen (input
);
1031 bmem
= BIO_new (BIO_s_mem ());
1032 b64
= BIO_new (BIO_f_base64 ());
1033 BIO_set_flags (b64
, BIO_FLAGS_BASE64_NO_NL
);
1034 b64
= BIO_push (b64
, bmem
);
1035 BIO_write (b64
, input
, length
);
1036 (void) BIO_flush (b64
);
1037 BIO_get_mem_ptr (b64
, &bptr
);
1038 ret
= tr_strndup (bptr
->data
, bptr
->length
);
1039 retlen
= bptr
->length
;
1044 *setme_len
= retlen
;
1050 tr_base64_decode (const void * input
,
1060 length
= strlen (input
);
1062 ret
= tr_new0 (char, length
);
1063 b64
= BIO_new (BIO_f_base64 ());
1064 bmem
= BIO_new_mem_buf ((unsigned char*)input
, length
);
1065 bmem
= BIO_push (b64
, bmem
);
1066 retlen
= BIO_read (bmem
, ret
, length
);
1069 /* try again, but with the BIO_FLAGS_BASE64_NO_NL flag */
1070 BIO_free_all (bmem
);
1071 b64
= BIO_new (BIO_f_base64 ());
1072 BIO_set_flags (b64
, BIO_FLAGS_BASE64_NO_NL
);
1073 bmem
= BIO_new_mem_buf ((unsigned char*)input
, length
);
1074 bmem
= BIO_push (b64
, bmem
);
1075 retlen
= BIO_read (bmem
, ret
, length
);
1079 *setme_len
= retlen
;
1081 BIO_free_all (bmem
);
1090 tr_removeElementFromArray (void * array
,
1091 unsigned int index_to_remove
,
1092 size_t sizeof_element
,
1097 memmove (a
+ sizeof_element
* index_to_remove
,
1098 a
+ sizeof_element
* (index_to_remove
+ 1),
1099 sizeof_element
* (--nmemb
- index_to_remove
));
1103 tr_lowerBound (const void * key
,
1107 int (* compar
)(const void* key
, const void* arrayMember
),
1111 const char * cbase
= base
;
1116 const size_t half
= nmemb
/ 2;
1117 const size_t middle
= first
+ half
;
1118 const int c
= compar (key
, cbase
+ size
*middle
);
1129 nmemb
= nmemb
- half
- 1;
1133 *exact_match
= exact
;
1142 /* Byte-wise swap two items of size SIZE.
1143 From glibc, written by Douglas C. Schmidt, LGPL 2.1 or higher */
1144 #define SWAP(a, b, size) \
1146 register size_t __size = (size); \
1147 register char *__a = (a), *__b = (b); \
1148 if (__a != __b) do { \
1149 char __tmp = *__a; \
1152 } while (--__size > 0); \
1157 quickfindPartition (char * base
, size_t left
, size_t right
, size_t size
,
1158 int (*compar
)(const void *, const void *), size_t pivotIndex
)
1163 /* move pivot to the end */
1164 SWAP (base
+(size
*pivotIndex
), base
+(size
*right
), size
);
1167 for (i
=left
; i
<=right
-1; ++i
)
1169 if (compar (base
+(size
*i
), base
+(size
*right
)) <= 0)
1171 SWAP (base
+(size
*storeIndex
), base
+(size
*i
), size
);
1176 /* move pivot to its final place */
1177 SWAP (base
+(size
*right
), base
+(size
*storeIndex
), size
);
1179 /* sanity check the partition */
1181 assert (storeIndex
>= left
);
1182 assert (storeIndex
<= right
);
1184 for (i
=left
; i
<storeIndex
; ++i
)
1185 assert (compar (base
+(size
*i
), base
+(size
*storeIndex
)) <= 0);
1186 for (i
=storeIndex
+1; i
<=right
; ++i
)
1187 assert (compar (base
+(size
*i
), base
+(size
*storeIndex
)) >= 0);
1194 quickfindFirstK (char * base
, size_t left
, size_t right
, size_t size
,
1195 int (*compar
)(const void *, const void *), size_t k
)
1199 const size_t pivotIndex
= left
+ (right
-left
)/2u;
1201 const size_t pivotNewIndex
= quickfindPartition (base
, left
, right
, size
, compar
, pivotIndex
);
1203 if (pivotNewIndex
> left
+ k
) /* new condition */
1204 quickfindFirstK (base
, left
, pivotNewIndex
-1, size
, compar
, k
);
1205 else if (pivotNewIndex
< left
+ k
)
1206 quickfindFirstK (base
, pivotNewIndex
+1, right
, size
, compar
, k
+left
-pivotNewIndex
-1);
1212 checkBestScoresComeFirst (char * base
, size_t nmemb
, size_t size
,
1213 int (*compar
)(const void *, const void *), size_t k
)
1216 size_t worstFirstPos
= 0;
1219 if (compar (base
+(size
*worstFirstPos
), base
+(size
*i
)) < 0)
1223 assert (compar (base
+(size
*i
), base
+(size
*worstFirstPos
)) <= 0);
1224 for (i
=k
; i
<nmemb
; ++i
)
1225 assert (compar (base
+(size
*i
), base
+(size
*worstFirstPos
)) >= 0);
1230 tr_quickfindFirstK (void * base
, size_t nmemb
, size_t size
,
1231 int (*compar
)(const void *, const void *), size_t k
)
1235 quickfindFirstK (base
, 0, nmemb
-1, size
, compar
, k
);
1238 checkBestScoresComeFirst (base
, nmemb
, size
, compar
, k
);
1248 strip_non_utf8 (const char * in
, size_t inlen
)
1251 const char zero
= '\0';
1252 struct evbuffer
* buf
= evbuffer_new ();
1254 while (!tr_utf8_validate (in
, inlen
, &end
))
1256 const int good_len
= end
- in
;
1258 evbuffer_add (buf
, in
, good_len
);
1259 inlen
-= (good_len
+ 1);
1260 in
+= (good_len
+ 1);
1261 evbuffer_add (buf
, "?", 1);
1264 evbuffer_add (buf
, in
, inlen
);
1265 evbuffer_add (buf
, &zero
, 1);
1266 return evbuffer_free_to_str (buf
);
1270 to_utf8 (const char * in
, size_t inlen
)
1274 #ifdef HAVE_ICONV_OPEN
1276 const char * encodings
[] = { "CURRENT", "ISO-8859-15" };
1277 const int encoding_count
= sizeof (encodings
) / sizeof (encodings
[1]);
1278 const size_t buflen
= inlen
*4 + 10;
1279 char * out
= tr_new (char, buflen
);
1281 for (i
=0; !ret
&& i
<encoding_count
; ++i
)
1283 char * inbuf
= (char*) in
;
1284 char * outbuf
= out
;
1285 size_t inbytesleft
= inlen
;
1286 size_t outbytesleft
= buflen
;
1287 const char * test_encoding
= encodings
[i
];
1289 iconv_t cd
= iconv_open ("UTF-8", test_encoding
);
1290 if (cd
!= (iconv_t
)-1)
1292 if (iconv (cd
, &inbuf
, &inbytesleft
, &outbuf
, &outbytesleft
) != (size_t)-1)
1293 ret
= tr_strndup (out
, buflen
-outbytesleft
);
1302 ret
= strip_non_utf8 (in
, inlen
);
1308 tr_utf8clean (const char * str
, int max_len
)
1314 max_len
= (int) strlen (str
);
1316 if (tr_utf8_validate (str
, max_len
, &end
))
1317 ret
= tr_strndup (str
, max_len
);
1319 ret
= to_utf8 (str
, max_len
);
1321 assert (tr_utf8_validate (ret
, -1, NULL
));
1336 * This should be a single number (ex. "6") or a range (ex. "6-9").
1337 * Anything else is an error and will return failure.
1340 parseNumberSection (const char * str
, int len
, struct number_range
* setme
)
1345 const int error
= errno
;
1346 char * tmp
= tr_strndup (str
, len
);
1349 a
= b
= strtol (tmp
, &end
, 10);
1350 if (errno
|| (end
== tmp
))
1354 else if (*end
!= '-')
1360 const char * pch
= end
+ 1;
1361 b
= strtol (pch
, &end
, 10);
1362 if (errno
|| (pch
== end
))
1364 else if (*end
) /* trailing data */
1372 setme
->low
= MIN (a
, b
);
1373 setme
->high
= MAX (a
, b
);
1380 compareInt (const void * va
, const void * vb
)
1382 const int a
= * (const int *)va
;
1383 const int b
= * (const int *)vb
;
1388 * Given a string like "1-4" or "1-4,6,9,14-51", this allocates and returns an
1389 * array of setmeCount ints of all the values in the array.
1390 * For example, "5-8" will return [ 5, 6, 7, 8 ] and setmeCount will be 4.
1391 * It's the caller's responsibility to call tr_free () on the returned array.
1392 * If a fragment of the string can't be parsed, NULL is returned.
1395 tr_parseNumberRange (const char * str_in
, int len
, int * setmeCount
)
1399 char * str
= tr_strndup (str_in
, len
);
1401 tr_list
* ranges
= NULL
;
1402 bool success
= true;
1405 while (walk
&& *walk
&& success
)
1407 struct number_range range
;
1408 const char * pch
= strchr (walk
, ',');
1411 success
= parseNumberSection (walk
, pch
-walk
, &range
);
1416 success
= parseNumberSection (walk
, strlen (walk
), &range
);
1417 walk
+= strlen (walk
);
1420 tr_list_append (&ranges
, tr_memdup (&range
, sizeof (struct number_range
)));
1433 int * sorted
= NULL
;
1435 /* build a sorted number array */
1437 for (l
=ranges
; l
!=NULL
; l
=l
->next
)
1439 const struct number_range
* r
= l
->data
;
1440 n
+= r
->high
+ 1 - r
->low
;
1442 sorted
= tr_new (int, n
);
1450 for (l
=ranges
; l
!=NULL
; l
=l
->next
)
1453 const struct number_range
* r
= l
->data
;
1454 for (i
=r
->low
; i
<=r
->high
; ++i
)
1457 qsort (sorted
, n
, sizeof (int), compareInt
);
1460 /* remove duplicates */
1461 uniq
= tr_new (int, n
);
1468 for (i
=n
=0; i
<n2
; ++i
)
1469 if (!n
|| uniq
[n
-1] != sorted
[i
])
1470 uniq
[n
++] = sorted
[i
];
1478 tr_list_free (&ranges
, tr_free
);
1481 /* return the result */
1491 tr_truncd (double x
, int precision
)
1495 const int max_precision
= (int) log10 (1.0 / DBL_EPSILON
) - 1;
1496 tr_snprintf (buf
, sizeof (buf
), "%.*f", max_precision
, x
);
1497 if ((pt
= strstr (buf
, localeconv ()->decimal_point
)))
1498 pt
[precision
? precision
+1 : 0] = '\0';
1502 /* return a truncated double as a string */
1504 tr_strtruncd (char * buf
, double x
, int precision
, size_t buflen
)
1506 tr_snprintf (buf
, buflen
, "%.*f", precision
, tr_truncd (x
, precision
));
1511 tr_strpercent (char * buf
, double x
, size_t buflen
)
1514 tr_strtruncd (buf
, x
, 1, buflen
);
1516 tr_strtruncd (buf
, x
, 0, buflen
);
1522 tr_strratio (char * buf
, size_t buflen
, double ratio
, const char * infinity
)
1524 if ((int)ratio
== TR_RATIO_NA
)
1525 tr_strlcpy (buf
, _("None"), buflen
);
1526 else if ((int)ratio
== TR_RATIO_INF
)
1527 tr_strlcpy (buf
, infinity
, buflen
);
1529 tr_strpercent (buf
, ratio
, buflen
);
1539 tr_moveFile (const char * oldpath
, const char * newpath
, bool * renamed
)
1546 const size_t buflen
= 1024 * 128; /* 128 KiB buffer */
1548 /* make sure the old file exists */
1549 if (stat (oldpath
, &st
))
1551 const int err
= errno
;
1555 if (!S_ISREG (st
.st_mode
))
1560 bytesLeft
= st
.st_size
;
1562 /* make sure the target directory exists */
1564 char * newdir
= tr_dirname (newpath
);
1565 int i
= tr_mkdirp (newdir
, 0777);
1571 /* they might be on the same filesystem... */
1573 const int i
= tr_rename (oldpath
, newpath
);
1574 if (renamed
!= NULL
)
1581 in
= tr_open_file_for_scanning (oldpath
);
1582 out
= tr_open_file_for_writing (newpath
);
1583 buf
= tr_valloc (buflen
);
1584 while (bytesLeft
> 0)
1586 ssize_t bytesWritten
;
1587 const off_t bytesThisPass
= MIN (bytesLeft
, (off_t
)buflen
);
1588 const int numRead
= read (in
, buf
, bytesThisPass
);
1591 bytesWritten
= write (out
, buf
, numRead
);
1592 if (bytesWritten
< 0)
1594 bytesLeft
-= bytesWritten
;
1599 tr_close_file (out
);
1604 tr_remove (oldpath
);
1609 tr_rename (const char * oldpath
, const char * newpath
)
1611 /* FIXME: needs win32 utf-16 support */
1613 return rename (oldpath
, newpath
);
1617 tr_remove (const char * pathname
)
1619 /* FIXME: needs win32 utf-16 support */
1621 return remove (pathname
);
1625 tr_is_same_file (const char * filename1
, const char * filename2
)
1631 BY_HANDLE_FILE_INFORMATION fi1
, fi2
;
1632 int n
= strlen (filename1
) + 1;
1633 int m
= strlen (filename2
) + 1;
1634 wchar_t f1nameUTF16
[n
];
1635 wchar_t f2nameUTF16
[m
];
1637 MultiByteToWideChar (CP_UTF8
, 0, filename1
, -1, f1nameUTF16
, n
);
1638 MultiByteToWideChar (CP_UTF8
, 0, filename2
, -1, f2nameUTF16
, m
);
1639 fh1
= CreateFileW (chkFilename (f1nameUTF16
), 0, 0, NULL
, OPEN_EXISTING
, FILE_FLAG_BACKUP_SEMANTICS
, NULL
);
1640 fh2
= CreateFileW (chkFilename (f2nameUTF16
), 0, 0, NULL
, OPEN_EXISTING
, FILE_FLAG_BACKUP_SEMANTICS
, NULL
);
1641 res
= GetFileInformationByHandle (fh1
, &fi1
)
1642 && GetFileInformationByHandle (fh2
, &fi2
)
1643 && (fi1
.dwVolumeSerialNumber
== fi2
.dwVolumeSerialNumber
)
1644 && (fi1
.nFileIndexHigh
== fi2
.nFileIndexHigh
)
1645 && (fi1
.nFileIndexLow
== fi2
.nFileIndexLow
);
1652 struct stat sb1
, sb2
;
1654 return !stat (filename1
, &sb1
)
1655 && !stat (filename2
, &sb2
)
1656 && (sb1
.st_dev
== sb2
.st_dev
)
1657 && (sb1
.st_ino
== sb2
.st_ino
);
1667 tr_valloc (size_t bufLen
)
1671 static size_t pageSize
= 0;
1675 #ifdef HAVE_GETPAGESIZE
1676 pageSize
= (size_t) getpagesize ();
1682 allocLen
= pageSize
;
1683 while (allocLen
< bufLen
)
1684 allocLen
+= pageSize
;
1686 #ifdef HAVE_POSIX_MEMALIGN
1688 if (posix_memalign (&buf
, pageSize
, allocLen
))
1689 buf
= NULL
; /* just retry with valloc/malloc */
1693 buf
= valloc (allocLen
);
1696 buf
= tr_malloc (allocLen
);
1702 tr_realpath (const char * path
, char * resolved_path
)
1705 /* From a message to the Mingw-msys list, Jun 2, 2005 by Mark Junker. */
1706 if (GetFullPathNameA (path
, TR_PATH_MAX
, resolved_path
, NULL
) == 0)
1708 return resolved_path
;
1710 return realpath (path
, resolved_path
);
1719 tr_htonll (uint64_t x
)
1724 /* fallback code by bdonlan at
1725 * http://stackoverflow.com/questions/809902/64-bit-ntohl-in-c/875505#875505 */
1726 union { uint32_t lx
[2]; uint64_t llx
; } u
;
1727 u
.lx
[0] = htonl (x
>> 32);
1728 u
.lx
[1] = htonl (x
& 0xFFFFFFFFULL
);
1734 tr_ntohll (uint64_t x
)
1739 /* fallback code by bdonlan at
1740 * http://stackoverflow.com/questions/809902/64-bit-ntohl-in-c/875505#875505 */
1741 union { uint32_t lx
[2]; uint64_t llx
; } u
;
1743 return ((uint64_t)ntohl (u
.lx
[0]) << 32) | (uint64_t)ntohl (u
.lx
[1]);
1753 struct formatter_unit
1759 struct formatter_units
1761 struct formatter_unit units
[4];
1764 enum { TR_FMT_KB
, TR_FMT_MB
, TR_FMT_GB
, TR_FMT_TB
};
1767 formatter_init (struct formatter_units
* units
,
1769 const char * kb
, const char * mb
,
1770 const char * gb
, const char * tb
)
1775 units
->units
[TR_FMT_KB
].name
= tr_strdup (kb
);
1776 units
->units
[TR_FMT_KB
].value
= value
;
1779 units
->units
[TR_FMT_MB
].name
= tr_strdup (mb
);
1780 units
->units
[TR_FMT_MB
].value
= value
;
1783 units
->units
[TR_FMT_GB
].name
= tr_strdup (gb
);
1784 units
->units
[TR_FMT_GB
].value
= value
;
1787 units
->units
[TR_FMT_TB
].name
= tr_strdup (tb
);
1788 units
->units
[TR_FMT_TB
].value
= value
;
1792 formatter_get_size_str (const struct formatter_units
* u
,
1793 char * buf
, int64_t bytes
, size_t buflen
)
1798 const struct formatter_unit
* unit
;
1800 if (bytes
< u
->units
[1].value
) unit
= &u
->units
[0];
1801 else if (bytes
< u
->units
[2].value
) unit
= &u
->units
[1];
1802 else if (bytes
< u
->units
[3].value
) unit
= &u
->units
[2];
1803 else unit
= &u
->units
[3];
1805 value
= (double)bytes
/ unit
->value
;
1808 if (unit
->value
== 1)
1810 else if (value
< 100)
1815 tr_snprintf (buf
, buflen
, "%.*f %s", precision
, value
, units
);
1819 static struct formatter_units size_units
;
1822 tr_formatter_size_init (unsigned int kilo
,
1823 const char * kb
, const char * mb
,
1824 const char * gb
, const char * tb
)
1826 formatter_init (&size_units
, kilo
, kb
, mb
, gb
, tb
);
1830 tr_formatter_size_B (char * buf
, int64_t bytes
, size_t buflen
)
1832 return formatter_get_size_str (&size_units
, buf
, bytes
, buflen
);
1835 static struct formatter_units speed_units
;
1837 unsigned int tr_speed_K
= 0u;
1840 tr_formatter_speed_init (unsigned int kilo
,
1841 const char * kb
, const char * mb
,
1842 const char * gb
, const char * tb
)
1845 formatter_init (&speed_units
, kilo
, kb
, mb
, gb
, tb
);
1849 tr_formatter_speed_KBps (char * buf
, double KBps
, size_t buflen
)
1851 const double K
= speed_units
.units
[TR_FMT_KB
].value
;
1852 double speed
= KBps
;
1854 if (speed
<= 999.95) /* 0.0 KB to 999.9 KB */
1856 tr_snprintf (buf
, buflen
, "%d %s", (int)speed
, speed_units
.units
[TR_FMT_KB
].name
);
1862 if (speed
<= 99.995) /* 0.98 MB to 99.99 MB */
1863 tr_snprintf (buf
, buflen
, "%.2f %s", speed
, speed_units
.units
[TR_FMT_MB
].name
);
1864 else if (speed
<= 999.95) /* 100.0 MB to 999.9 MB */
1865 tr_snprintf (buf
, buflen
, "%.1f %s", speed
, speed_units
.units
[TR_FMT_MB
].name
);
1867 tr_snprintf (buf
, buflen
, "%.1f %s", speed
/K
, speed_units
.units
[TR_FMT_GB
].name
);
1873 static struct formatter_units mem_units
;
1875 unsigned int tr_mem_K
= 0u;
1878 tr_formatter_mem_init (unsigned int kilo
,
1879 const char * kb
, const char * mb
,
1880 const char * gb
, const char * tb
)
1883 formatter_init (&mem_units
, kilo
, kb
, mb
, gb
, tb
);
1887 tr_formatter_mem_B (char * buf
, int64_t bytes_per_second
, size_t buflen
)
1889 return formatter_get_size_str (&mem_units
, buf
, bytes_per_second
, buflen
);
1893 tr_formatter_get_units (void * vdict
)
1897 tr_variant
* dict
= vdict
;
1899 tr_variantDictReserve (dict
, 6);
1901 tr_variantDictAddInt (dict
, TR_KEY_memory_bytes
, mem_units
.units
[TR_FMT_KB
].value
);
1902 l
= tr_variantDictAddList (dict
, TR_KEY_memory_units
, 4);
1904 tr_variantListAddStr (l
, mem_units
.units
[i
].name
);
1906 tr_variantDictAddInt (dict
, TR_KEY_size_bytes
, size_units
.units
[TR_FMT_KB
].value
);
1907 l
= tr_variantDictAddList (dict
, TR_KEY_size_units
, 4);
1909 tr_variantListAddStr (l
, size_units
.units
[i
].name
);
1911 tr_variantDictAddInt (dict
, TR_KEY_speed_bytes
, speed_units
.units
[TR_FMT_KB
].value
);
1912 l
= tr_variantDictAddList (dict
, TR_KEY_speed_units
, 4);
1914 tr_variantListAddStr (l
, speed_units
.units
[i
].name
);