1 | /* |
---|
2 | * This file Copyright (C) 2009-2010 Mnemosyne LLC |
---|
3 | * |
---|
4 | * This file is licensed by the GPL version 2. Works owned by the |
---|
5 | * Transmission project are granted a special exemption to clause 2(b) |
---|
6 | * so that the bulk of its code can remain under the MIT license. |
---|
7 | * This exemption does not extend to derived works not owned by |
---|
8 | * the Transmission project. |
---|
9 | * |
---|
10 | * $Id: utils.h 11575 2010-12-22 07:06:00Z charles $ |
---|
11 | */ |
---|
12 | |
---|
13 | #ifndef TR_UTILS_H |
---|
14 | #define TR_UTILS_H 1 |
---|
15 | |
---|
16 | #include <inttypes.h> |
---|
17 | #include <stddef.h> /* size_t */ |
---|
18 | #include <stdio.h> /* FILE* */ |
---|
19 | #include <string.h> /* memcpy()* */ |
---|
20 | #include <stdlib.h> /* malloc() */ |
---|
21 | #include <time.h> /* time_t */ |
---|
22 | |
---|
23 | #ifdef __cplusplus |
---|
24 | extern "C" { |
---|
25 | #endif |
---|
26 | |
---|
27 | /*** |
---|
28 | **** |
---|
29 | ***/ |
---|
30 | |
---|
31 | /** |
---|
32 | * @addtogroup utils Utilities |
---|
33 | * @{ |
---|
34 | */ |
---|
35 | |
---|
36 | #ifndef FALSE |
---|
37 | #define FALSE 0 |
---|
38 | #endif |
---|
39 | |
---|
40 | #ifndef TRUE |
---|
41 | #define TRUE 1 |
---|
42 | #endif |
---|
43 | |
---|
44 | #ifndef UNUSED |
---|
45 | #ifdef __GNUC__ |
---|
46 | #define UNUSED __attribute__ ( ( unused ) ) |
---|
47 | #else |
---|
48 | #define UNUSED |
---|
49 | #endif |
---|
50 | #endif |
---|
51 | |
---|
52 | #ifndef TR_GNUC_PRINTF |
---|
53 | #ifdef __GNUC__ |
---|
54 | #define TR_GNUC_PRINTF( fmt, args ) __attribute__ ( ( format ( printf, fmt, args ) ) ) |
---|
55 | #else |
---|
56 | #define TR_GNUC_PRINTF( fmt, args ) |
---|
57 | #endif |
---|
58 | #endif |
---|
59 | |
---|
60 | #ifndef TR_GNUC_NONNULL |
---|
61 | #ifdef __GNUC__ |
---|
62 | #define TR_GNUC_NONNULL( ... ) __attribute__((nonnull (__VA_ARGS__))) |
---|
63 | #else |
---|
64 | #define TR_GNUC_NONNULL( ... ) |
---|
65 | #endif |
---|
66 | #endif |
---|
67 | |
---|
68 | #ifndef TR_GNUC_NULL_TERMINATED |
---|
69 | #if __GNUC__ > 4 || ( __GNUC__ == 4 && __GNUC_MINOR__ >= 3 ) |
---|
70 | #define TR_GNUC_NULL_TERMINATED __attribute__ ( ( __sentinel__ ) ) |
---|
71 | #define TR_GNUC_HOT __attribute ( ( hot ) ) |
---|
72 | #else |
---|
73 | #define TR_GNUC_NULL_TERMINATED |
---|
74 | #define TR_GNUC_HOT |
---|
75 | #endif |
---|
76 | #endif |
---|
77 | |
---|
78 | #if __GNUC__ > 2 || ( __GNUC__ == 2 && __GNUC_MINOR__ >= 96 ) |
---|
79 | #define TR_GNUC_PURE __attribute__ ( ( __pure__ ) ) |
---|
80 | #define TR_GNUC_MALLOC __attribute__ ( ( __malloc__ ) ) |
---|
81 | #else |
---|
82 | #define TR_GNUC_PURE |
---|
83 | #define TR_GNUC_MALLOC |
---|
84 | #endif |
---|
85 | |
---|
86 | |
---|
87 | /*** |
---|
88 | **** |
---|
89 | ***/ |
---|
90 | |
---|
91 | #if !defined( _ ) |
---|
92 | #if defined( HAVE_LIBINTL_H ) && !defined( SYS_DARWIN ) |
---|
93 | #include <libintl.h> |
---|
94 | #define _( a ) gettext ( a ) |
---|
95 | #else |
---|
96 | #define _( a ) ( a ) |
---|
97 | #endif |
---|
98 | #endif |
---|
99 | |
---|
100 | /* #define DISABLE_GETTEXT */ |
---|
101 | #if defined(TR_EMBEDDED) && !defined(DISABLE_GETTEXT) |
---|
102 | #define DISABLE_GETTEXT |
---|
103 | #endif |
---|
104 | #ifdef DISABLE_GETTEXT |
---|
105 | const char * tr_strip_positional_args( const char * fmt ); |
---|
106 | #undef _ |
---|
107 | #define _( a ) tr_strip_positional_args( a ) |
---|
108 | #endif |
---|
109 | |
---|
110 | /**** |
---|
111 | ***** |
---|
112 | ****/ |
---|
113 | |
---|
114 | void tr_msgInit( void ); |
---|
115 | |
---|
116 | #define TR_MAX_MSG_LOG 10000 |
---|
117 | |
---|
118 | extern int messageLevel; |
---|
119 | |
---|
120 | static inline tr_bool tr_msgLoggingIsActive( int level ) |
---|
121 | { |
---|
122 | return messageLevel >= level; |
---|
123 | } |
---|
124 | |
---|
125 | void tr_msg( const char * file, int line, |
---|
126 | int level, |
---|
127 | const char * torrent, |
---|
128 | const char * fmt, ... ) TR_GNUC_PRINTF( 5, 6 ); |
---|
129 | |
---|
130 | #define tr_nerr( n, ... ) \ |
---|
131 | do { \ |
---|
132 | if( tr_msgLoggingIsActive( TR_MSG_ERR ) ) \ |
---|
133 | tr_msg( __FILE__, __LINE__, TR_MSG_ERR, n, __VA_ARGS__ ); \ |
---|
134 | } while( 0 ) |
---|
135 | |
---|
136 | #define tr_ninf( n, ... ) \ |
---|
137 | do { \ |
---|
138 | if( tr_msgLoggingIsActive( TR_MSG_INF) ) \ |
---|
139 | tr_msg( __FILE__, __LINE__, TR_MSG_INF, n, __VA_ARGS__ ); \ |
---|
140 | } while( 0 ) |
---|
141 | |
---|
142 | #define tr_ndbg( n, ... ) \ |
---|
143 | do { \ |
---|
144 | if( tr_msgLoggingIsActive( TR_MSG_DBG) ) \ |
---|
145 | tr_msg( __FILE__, __LINE__, TR_MSG_DBG, n, __VA_ARGS__ ); \ |
---|
146 | } while( 0 ) |
---|
147 | |
---|
148 | #define tr_torerr( tor, ... ) \ |
---|
149 | do { \ |
---|
150 | if( tr_msgLoggingIsActive( TR_MSG_ERR ) ) \ |
---|
151 | tr_msg( __FILE__, __LINE__, TR_MSG_ERR, tor->info.name, __VA_ARGS__ ); \ |
---|
152 | } while( 0 ) |
---|
153 | |
---|
154 | #define tr_torinf( tor, ... ) \ |
---|
155 | do { \ |
---|
156 | if( tr_msgLoggingIsActive( TR_MSG_INF ) ) \ |
---|
157 | tr_msg( __FILE__, __LINE__, TR_MSG_INF, tor->info.name, __VA_ARGS__ ); \ |
---|
158 | } while( 0 ) |
---|
159 | |
---|
160 | #define tr_tordbg( tor, ... ) \ |
---|
161 | do { \ |
---|
162 | if( tr_msgLoggingIsActive( TR_MSG_DBG ) ) \ |
---|
163 | tr_msg( __FILE__, __LINE__, TR_MSG_DBG, tor->info.name, __VA_ARGS__ ); \ |
---|
164 | } while( 0 ) |
---|
165 | |
---|
166 | #define tr_err( ... ) \ |
---|
167 | do { \ |
---|
168 | if( tr_msgLoggingIsActive( TR_MSG_ERR ) ) \ |
---|
169 | tr_msg( __FILE__, __LINE__, TR_MSG_ERR, NULL, __VA_ARGS__ ); \ |
---|
170 | } while( 0 ) |
---|
171 | |
---|
172 | #define tr_inf( ... ) \ |
---|
173 | do { \ |
---|
174 | if( tr_msgLoggingIsActive( TR_MSG_INF ) ) \ |
---|
175 | tr_msg( __FILE__, __LINE__, TR_MSG_INF, NULL, __VA_ARGS__ ); \ |
---|
176 | } while( 0 ) |
---|
177 | |
---|
178 | #define tr_dbg( ... ) \ |
---|
179 | do { \ |
---|
180 | if( tr_msgLoggingIsActive( TR_MSG_DBG ) ) \ |
---|
181 | tr_msg( __FILE__, __LINE__, TR_MSG_DBG, NULL, __VA_ARGS__ ); \ |
---|
182 | } while( 0 ) |
---|
183 | |
---|
184 | |
---|
185 | |
---|
186 | FILE* tr_getLog( void ); |
---|
187 | |
---|
188 | /** @brief return true if deep logging has been enabled by the user; false otherwise */ |
---|
189 | tr_bool tr_deepLoggingIsActive( void ); |
---|
190 | |
---|
191 | void tr_deepLog( const char * file, |
---|
192 | int line, |
---|
193 | const char * name, |
---|
194 | const char * fmt, |
---|
195 | ... ) TR_GNUC_PRINTF( 4, 5 ) TR_GNUC_NONNULL(1,4); |
---|
196 | |
---|
197 | /** @brief set the buffer with the current time formatted for deep logging. */ |
---|
198 | char* tr_getLogTimeStr( char * buf, int buflen ) TR_GNUC_NONNULL(1); |
---|
199 | |
---|
200 | |
---|
201 | /** |
---|
202 | * @brief Rich Salz's classic implementation of shell-style pattern matching for ?, \, [], and * characters. |
---|
203 | * @return 1 if the pattern matches, 0 if it doesn't, or -1 if an error occured |
---|
204 | */ |
---|
205 | int tr_wildmat( const char * text, const char * pattern ) TR_GNUC_NONNULL(1,2); |
---|
206 | |
---|
207 | /** @brief Portability wrapper for basename() that uses the system implementation if available */ |
---|
208 | char* tr_basename( const char * path ) TR_GNUC_MALLOC; |
---|
209 | |
---|
210 | /** @brief Portability wrapper for dirname() that uses the system implementation if available */ |
---|
211 | char* tr_dirname( const char * path ) TR_GNUC_MALLOC; |
---|
212 | |
---|
213 | /** |
---|
214 | * @brief Portability wrapper for mkdir() |
---|
215 | * |
---|
216 | * A portability wrapper around mkdir(). |
---|
217 | * On WIN32, the `permissions' argument is unused. |
---|
218 | * |
---|
219 | * @return zero on success, or -1 if an error occurred |
---|
220 | * (in which case errno is set appropriately). |
---|
221 | */ |
---|
222 | int tr_mkdir( const char * path, int permissions ) TR_GNUC_NONNULL(1); |
---|
223 | |
---|
224 | /** |
---|
225 | * Like mkdir, but makes parent directories as needed. |
---|
226 | * |
---|
227 | * @return zero on success, or -1 if an error occurred |
---|
228 | * (in which case errno is set appropriately). |
---|
229 | */ |
---|
230 | int tr_mkdirp( const char * path, int permissions ) TR_GNUC_NONNULL(1); |
---|
231 | |
---|
232 | |
---|
233 | /** |
---|
234 | * @brief Loads a file and returns its contents. |
---|
235 | * On failure, NULL is returned and errno is set. |
---|
236 | */ |
---|
237 | uint8_t* tr_loadFile( const char * filename, size_t * size ) TR_GNUC_MALLOC |
---|
238 | TR_GNUC_NONNULL(1); |
---|
239 | |
---|
240 | |
---|
241 | /** @brief build a filename from a series of elements using the |
---|
242 | platform's correct directory separator. */ |
---|
243 | char* tr_buildPath( const char * first_element, ... ) TR_GNUC_NULL_TERMINATED |
---|
244 | TR_GNUC_MALLOC; |
---|
245 | |
---|
246 | struct event; |
---|
247 | |
---|
248 | /** |
---|
249 | * @brief Convenience wrapper around timer_add() to have a timer wake up in a number of seconds and microseconds |
---|
250 | * @param timer |
---|
251 | * @param seconds |
---|
252 | * @param microseconds |
---|
253 | */ |
---|
254 | void tr_timerAdd( struct event * timer, int seconds, int microseconds ) TR_GNUC_NONNULL(1); |
---|
255 | |
---|
256 | /** |
---|
257 | * @brief Convenience wrapper around timer_add() to have a timer wake up in a number of milliseconds |
---|
258 | * @param timer |
---|
259 | * @param milliseconds |
---|
260 | */ |
---|
261 | void tr_timerAddMsec( struct event * timer, int milliseconds ) TR_GNUC_NONNULL(1); |
---|
262 | |
---|
263 | |
---|
264 | /** @brief return the current date in milliseconds */ |
---|
265 | uint64_t tr_date( void ); |
---|
266 | |
---|
267 | /** @brief sleep the specified number of milliseconds */ |
---|
268 | void tr_wait_msec( long int delay_milliseconds ); |
---|
269 | |
---|
270 | /** |
---|
271 | * @brief make a copy of 'str' whose non-utf8 content has been corrected or stripped |
---|
272 | * @return a newly-allocated string that must be freed with tr_free() |
---|
273 | * @param str the string to make a clean copy of |
---|
274 | * @param len the length of the string to copy. If -1, the entire string is used. |
---|
275 | */ |
---|
276 | char* tr_utf8clean( const char * str, int len ) TR_GNUC_MALLOC; |
---|
277 | |
---|
278 | |
---|
279 | /*** |
---|
280 | **** |
---|
281 | ***/ |
---|
282 | |
---|
283 | /* Sometimes the system defines MAX/MIN, sometimes not. |
---|
284 | In the latter case, define those here since we will use them */ |
---|
285 | #ifndef MAX |
---|
286 | #define MAX( a, b ) ( ( a ) > ( b ) ? ( a ) : ( b ) ) |
---|
287 | #endif |
---|
288 | #ifndef MIN |
---|
289 | #define MIN( a, b ) ( ( a ) > ( b ) ? ( b ) : ( a ) ) |
---|
290 | #endif |
---|
291 | |
---|
292 | /*** |
---|
293 | **** |
---|
294 | ***/ |
---|
295 | |
---|
296 | /** @brief Portability wrapper around malloc() in which `0' is a safe argument */ |
---|
297 | static inline void* tr_malloc( size_t size ) |
---|
298 | { |
---|
299 | return size ? malloc( size ) : NULL; |
---|
300 | } |
---|
301 | |
---|
302 | /** @brief Portability wrapper around calloc() in which `0' is a safe argument */ |
---|
303 | static inline void* tr_malloc0( size_t size ) |
---|
304 | { |
---|
305 | return size ? calloc( 1, size ) : NULL; |
---|
306 | } |
---|
307 | |
---|
308 | /** @brief Portability wrapper around free() in which `NULL' is a safe argument */ |
---|
309 | static inline void tr_free( void * p ) |
---|
310 | { |
---|
311 | if( p != NULL ) |
---|
312 | free( p ); |
---|
313 | } |
---|
314 | |
---|
315 | /** |
---|
316 | * @brief make a newly-allocated copy of a chunk of memory |
---|
317 | * @param src the memory to copy |
---|
318 | * @param byteCount the number of bytes to copy |
---|
319 | * @return a newly-allocated copy of `src' that can be freed with tr_free() |
---|
320 | */ |
---|
321 | static inline void* tr_memdup( const void * src, int byteCount ) |
---|
322 | { |
---|
323 | return memcpy( tr_malloc( byteCount ), src, byteCount ); |
---|
324 | } |
---|
325 | |
---|
326 | #define tr_new( struct_type, n_structs ) \ |
---|
327 | ( (struct_type *) tr_malloc ( ( (size_t) sizeof ( struct_type ) ) * ( ( size_t) ( n_structs ) ) ) ) |
---|
328 | |
---|
329 | #define tr_new0( struct_type, n_structs ) \ |
---|
330 | ( (struct_type *) tr_malloc0 ( ( (size_t) sizeof ( struct_type ) ) * ( ( size_t) ( n_structs ) ) ) ) |
---|
331 | |
---|
332 | #define tr_renew( struct_type, mem, n_structs ) \ |
---|
333 | ( (struct_type *) realloc ( ( mem ), ( (size_t) sizeof ( struct_type ) ) * ( ( size_t) ( n_structs ) ) ) ) |
---|
334 | |
---|
335 | void* tr_valloc( size_t bufLen ); |
---|
336 | |
---|
337 | /** |
---|
338 | * @brief make a newly-allocated copy of a substring |
---|
339 | * @param in is a void* so that callers can pass in both signed & unsigned without a cast |
---|
340 | * @param len length of the substring to copy. if a length less than zero is passed in, strlen( len ) is used |
---|
341 | * @return a newly-allocated copy of `in' that can be freed with tr_free() |
---|
342 | */ |
---|
343 | char* tr_strndup( const void * in, int len ) TR_GNUC_MALLOC; |
---|
344 | |
---|
345 | /** |
---|
346 | * @brief make a newly-allocated copy of a string |
---|
347 | * @param in is a void* so that callers can pass in both signed & unsigned without a cast |
---|
348 | * @return a newly-allocated copy of `in' that can be freed with tr_free() |
---|
349 | */ |
---|
350 | static inline char* tr_strdup( const void * in ) |
---|
351 | { |
---|
352 | return tr_strndup( in, in ? strlen( (const char *) in ) : 0 ); |
---|
353 | } |
---|
354 | |
---|
355 | /** @brief similar to bsearch() but returns the index of the lower bound */ |
---|
356 | int tr_lowerBound( const void * key, |
---|
357 | const void * base, |
---|
358 | size_t nmemb, |
---|
359 | size_t size, |
---|
360 | int (* compar)(const void* key, const void* arrayMember), |
---|
361 | tr_bool * exact_match ) TR_GNUC_HOT TR_GNUC_NONNULL(1,5,6); |
---|
362 | |
---|
363 | |
---|
364 | /** |
---|
365 | * @brief sprintf() a string into a newly-allocated buffer large enough to hold it |
---|
366 | * @return a newly-allocated string that can be freed with tr_free() |
---|
367 | */ |
---|
368 | char* tr_strdup_printf( const char * fmt, ... ) TR_GNUC_PRINTF( 1, 2 ) |
---|
369 | TR_GNUC_MALLOC; |
---|
370 | |
---|
371 | /** |
---|
372 | * @brief Translate a block of bytes into base64 |
---|
373 | * @return a newly-allocated string that can be freed with tr_free() |
---|
374 | */ |
---|
375 | char* tr_base64_encode( const void * input, |
---|
376 | int inlen, |
---|
377 | int * outlen ) TR_GNUC_MALLOC; |
---|
378 | |
---|
379 | /** |
---|
380 | * @brief Translate a block of bytes from base64 into raw form |
---|
381 | * @return a newly-allocated string that can be freed with tr_free() |
---|
382 | */ |
---|
383 | char* tr_base64_decode( const void * input, |
---|
384 | int inlen, |
---|
385 | int * outlen ) TR_GNUC_MALLOC; |
---|
386 | |
---|
387 | /** @brief Portability wrapper for strlcpy() that uses the system implementation if available */ |
---|
388 | size_t tr_strlcpy( char * dst, const void * src, size_t siz ); |
---|
389 | |
---|
390 | /** @brief Portability wrapper for snprintf() that uses the system implementation if available */ |
---|
391 | int tr_snprintf( char * buf, size_t buflen, |
---|
392 | const char * fmt, ... ) TR_GNUC_PRINTF( 3, 4 ) TR_GNUC_NONNULL(1,3); |
---|
393 | |
---|
394 | /** @brief Convenience wrapper around strerorr() guaranteed to not return NULL |
---|
395 | @param errno */ |
---|
396 | const char* tr_strerror( int ); |
---|
397 | |
---|
398 | /** @brief strips leading and trailing whitspace from a string |
---|
399 | @return the stripped string */ |
---|
400 | char* tr_strstrip( char * str ); |
---|
401 | |
---|
402 | /** @brief Returns true if the string ends with the specified case-insensitive suffix */ |
---|
403 | tr_bool tr_str_has_suffix( const char *str, const char *suffix ); |
---|
404 | |
---|
405 | |
---|
406 | /** @brief Portability wrapper for memmem() that uses the system implementation if available */ |
---|
407 | const char* tr_memmem( const char * haystack, size_t haystack_len, |
---|
408 | const char * needle, size_t needle_len ); |
---|
409 | |
---|
410 | /*** |
---|
411 | **** |
---|
412 | ***/ |
---|
413 | |
---|
414 | typedef void ( tr_set_func )( void * element, void * userData ); |
---|
415 | |
---|
416 | /** |
---|
417 | * @brief find the differences and commonalities in two sorted sets |
---|
418 | * @param a the first set |
---|
419 | * @param aCount the number of elements in the set 'a' |
---|
420 | * @param b the second set |
---|
421 | * @param bCount the number of elements in the set 'b' |
---|
422 | * @param compare the sorting method for both sets |
---|
423 | * @param elementSize the sizeof the element in the two sorted sets |
---|
424 | * @param in_a called for items in set 'a' but not set 'b' |
---|
425 | * @param in_b called for items in set 'b' but not set 'a' |
---|
426 | * @param in_both called for items that are in both sets |
---|
427 | * @param userData user data passed along to in_a, in_b, and in_both |
---|
428 | */ |
---|
429 | void tr_set_compare( const void * a, size_t aCount, |
---|
430 | const void * b, size_t bCount, |
---|
431 | int compare( const void * a, const void * b ), |
---|
432 | size_t elementSize, |
---|
433 | tr_set_func in_a_cb, |
---|
434 | tr_set_func in_b_cb, |
---|
435 | tr_set_func in_both_cb, |
---|
436 | void * userData ); |
---|
437 | |
---|
438 | void tr_sha1_to_hex( char * out, const uint8_t * sha1 ) TR_GNUC_NONNULL(1,2); |
---|
439 | |
---|
440 | void tr_hex_to_sha1( uint8_t * out, const char * hex ) TR_GNUC_NONNULL(1,2); |
---|
441 | |
---|
442 | /** @brief convenience function to determine if an address is an IP address (IPv4 or IPv6) */ |
---|
443 | tr_bool tr_addressIsIP( const char * address ); |
---|
444 | |
---|
445 | /** @brief return TRUE if the url is a http or https url that Transmission understands */ |
---|
446 | tr_bool tr_urlIsValidTracker( const char * url ) TR_GNUC_NONNULL(1); |
---|
447 | |
---|
448 | /** @brief return TRUE if the url is a [ http, https, ftp, ftps ] url that Transmission understands */ |
---|
449 | tr_bool tr_urlIsValid( const char * url ) TR_GNUC_NONNULL(1); |
---|
450 | |
---|
451 | /** @brief parse a URL into its component parts |
---|
452 | @return zero on success or an error number if an error occurred */ |
---|
453 | int tr_urlParse( const char * url, |
---|
454 | int url_len, |
---|
455 | char ** setme_scheme, |
---|
456 | char ** setme_host, |
---|
457 | int * setme_port, |
---|
458 | char ** setme_path ) TR_GNUC_NONNULL(1); |
---|
459 | |
---|
460 | |
---|
461 | /** @brief return TR_RATIO_NA, TR_RATIO_INF, or a number in [0..1] |
---|
462 | @return TR_RATIO_NA, TR_RATIO_INF, or a number in [0..1] */ |
---|
463 | double tr_getRatio( double numerator, double denominator ); |
---|
464 | |
---|
465 | /** |
---|
466 | * @brief Given a string like "1-4" or "1-4,6,9,14-51", this returns a |
---|
467 | * newly-allocated array of all the integers in the set. |
---|
468 | * @return a newly-allocated array of integers that must be freed with tr_free(), |
---|
469 | * or NULL if a fragment of the string can't be parsed. |
---|
470 | * |
---|
471 | * For example, "5-8" will return [ 5, 6, 7, 8 ] and setmeCount will be 4. |
---|
472 | */ |
---|
473 | int* tr_parseNumberRange( const char * str, |
---|
474 | int str_len, |
---|
475 | int * setmeCount ) TR_GNUC_MALLOC TR_GNUC_NONNULL(1); |
---|
476 | |
---|
477 | |
---|
478 | /** |
---|
479 | * @brief truncate a double value at a given number of decimal places. |
---|
480 | * |
---|
481 | * this can be used to prevent a printf() call from rounding up: |
---|
482 | * call with the decimal_places argument equal to the number of |
---|
483 | * decimal places in the printf()'s precision: |
---|
484 | * |
---|
485 | * - printf("%.2f%%", 99.999 ) ==> "100.00%" |
---|
486 | * |
---|
487 | * - printf("%.2f%%", tr_truncd(99.999, 2)) ==> "99.99%" |
---|
488 | * ^ ^ |
---|
489 | * | These should match | |
---|
490 | * +------------------------+ |
---|
491 | */ |
---|
492 | double tr_truncd( double x, int decimal_places ); |
---|
493 | |
---|
494 | /** |
---|
495 | * @param buf the buffer to write the string to |
---|
496 | * @param buflef buf's size |
---|
497 | * @param ratio the ratio to convert to a string |
---|
498 | * @param the string represntation of "infinity" |
---|
499 | */ |
---|
500 | char* tr_strratio( char * buf, size_t buflen, double ratio, const char * infinity ) TR_GNUC_NONNULL(1,4); |
---|
501 | |
---|
502 | /** @brief Portability wrapper for localtime_r() that uses the system implementation if available */ |
---|
503 | struct tm * tr_localtime_r( const time_t *_clock, struct tm *_result ); |
---|
504 | |
---|
505 | |
---|
506 | /** |
---|
507 | * @brief move a file |
---|
508 | * @return 0 on success; otherwise, return -1 and set errno |
---|
509 | */ |
---|
510 | int tr_moveFile( const char * oldpath, const char * newpath, |
---|
511 | tr_bool * renamed ) TR_GNUC_NONNULL(1,2); |
---|
512 | |
---|
513 | /** @brief Test to see if the two filenames point to the same file. */ |
---|
514 | tr_bool tr_is_same_file( const char * filename1, const char * filename2 ); |
---|
515 | |
---|
516 | /** @brief convenience function to remove an item from an array */ |
---|
517 | static inline void tr_removeElementFromArray( void * array, |
---|
518 | int index_to_remove, |
---|
519 | size_t sizeof_element, |
---|
520 | size_t nmemb ) |
---|
521 | { |
---|
522 | char * a = (char*) array; |
---|
523 | |
---|
524 | memmove( a + sizeof_element * index_to_remove, |
---|
525 | a + sizeof_element * ( index_to_remove + 1 ), |
---|
526 | sizeof_element * ( --nmemb - index_to_remove ) ); |
---|
527 | } |
---|
528 | |
---|
529 | /*** |
---|
530 | **** |
---|
531 | ***/ |
---|
532 | |
---|
533 | /** @brief Private libtransmission variable that's visible only for inlining in tr_time() */ |
---|
534 | extern time_t transmission_now; |
---|
535 | |
---|
536 | /** |
---|
537 | * @brief very inexpensive form of time(NULL) |
---|
538 | * @return the current epoch time in seconds |
---|
539 | * |
---|
540 | * This function returns a second counter that is updated once per second. |
---|
541 | * If something blocks the libtransmission thread for more than a second, |
---|
542 | * that counter may be thrown off, so this function is not guaranteed |
---|
543 | * to always be accurate. However, it is *much* faster when 100% accuracy |
---|
544 | * isn't needed |
---|
545 | */ |
---|
546 | static inline time_t tr_time( void ) { return transmission_now; } |
---|
547 | |
---|
548 | /** @brief Private libtransmission function to update tr_time()'s counter */ |
---|
549 | static inline void tr_timeUpdate( time_t now ) { transmission_now = now; } |
---|
550 | |
---|
551 | /*** |
---|
552 | **** |
---|
553 | ***/ |
---|
554 | |
---|
555 | #ifdef __cplusplus |
---|
556 | } |
---|
557 | #endif |
---|
558 | |
---|
559 | /** @} */ |
---|
560 | |
---|
561 | #endif |
---|