source: trunk/libtransmission/utils.c @ 8424

Last change on this file since 8424 was 8424, checked in by charles, 13 years ago

(trunk libT) expose tr_memmem() so it can be used by client code. use the OS' implementation if that's available.

  • Property svn:keywords set to Date Rev Author Id
File size: 36.1 KB
Line 
1/*
2 * This file Copyright (C) 2009 Charles Kerr <charles@transmissionbt.com>
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.c 8424 2009-05-19 04:48:33Z charles $
11 */
12
13#include <assert.h>
14#include <ctype.h> /* isalpha, tolower */
15#include <errno.h>
16#include <stdarg.h>
17#include <stdio.h>
18#include <stdlib.h>
19#include <string.h> /* strerror, memset */
20
21#include <libgen.h> /* basename */
22#include <sys/time.h>
23#include <sys/types.h>
24#include <sys/stat.h>
25#include <unistd.h> /* usleep, stat, getcwd */
26
27#include "event.h"
28
29#ifdef WIN32
30 #include <direct.h> /* _getcwd */
31 #include <windows.h> /* Sleep */
32#endif
33
34#include "transmission.h"
35#include "fdlimit.h"
36#include "ConvertUTF.h"
37#include "list.h"
38#include "utils.h"
39#include "platform.h"
40#include "version.h"
41
42static tr_lock *      messageLock = NULL;
43static int            messageLevel = 0;
44static tr_bool        messageQueuing = FALSE;
45static tr_msg_list *  messageQueue = NULL;
46static tr_msg_list ** messageQueueTail = &messageQueue;
47
48#ifndef WIN32
49    /* make null versions of these win32 functions */
50    static int IsDebuggerPresent( void ) { return FALSE; }
51    static void OutputDebugString( const void * unused UNUSED ) { }
52#endif
53
54static void
55tr_msgInit( void )
56{
57    static tr_bool initialized = FALSE;
58
59    if( !initialized )
60    {
61        char * env = getenv( "TR_DEBUG" );
62        messageLevel = ( env ? atoi( env ) : 0 ) + 1;
63        messageLevel = MAX( 1, messageLevel );
64
65        messageLock = tr_lockNew( );
66
67        initialized = TRUE;
68    }
69}
70
71FILE*
72tr_getLog( void )
73{
74    static int    initialized = FALSE;
75    static FILE * file = NULL;
76
77    if( !initialized )
78    {
79        const char * str = getenv( "TR_DEBUG_FD" );
80        int          fd = 0;
81        if( str && *str )
82            fd = atoi( str );
83        switch( fd )
84        {
85            case 1:
86                file = stdout; break;
87
88            case 2:
89                file = stderr; break;
90
91            default:
92                file = NULL; break;
93        }
94        initialized = TRUE;
95    }
96
97    return file;
98}
99
100void
101tr_setMessageLevel( int level )
102{
103    tr_msgInit( );
104    tr_lockLock( messageLock );
105
106    messageLevel = MAX( 0, level );
107
108    tr_lockUnlock( messageLock );
109}
110
111int
112tr_getMessageLevel( void )
113{
114    int ret;
115    tr_msgInit( );
116    tr_lockLock( messageLock );
117
118    ret = messageLevel;
119
120    tr_lockUnlock( messageLock );
121    return ret;
122}
123
124void
125tr_setMessageQueuing( tr_bool enabled )
126{
127    tr_msgInit( );
128    tr_lockLock( messageLock );
129
130    messageQueuing = enabled;
131
132    tr_lockUnlock( messageLock );
133}
134
135tr_bool
136tr_getMessageQueuing( void )
137{
138    int ret;
139    tr_msgInit( );
140    tr_lockLock( messageLock );
141
142    ret = messageQueuing;
143
144    tr_lockUnlock( messageLock );
145    return ret;
146}
147
148tr_msg_list *
149tr_getQueuedMessages( void )
150{
151    tr_msg_list * ret;
152    tr_msgInit( );
153    tr_lockLock( messageLock );
154
155    ret = messageQueue;
156    messageQueue = NULL;
157    messageQueueTail = &messageQueue;
158
159    tr_lockUnlock( messageLock );
160    return ret;
161}
162
163void
164tr_freeMessageList( tr_msg_list * list )
165{
166    tr_msg_list * next;
167
168    while( NULL != list )
169    {
170        next = list->next;
171        free( list->message );
172        free( list->name );
173        free( list );
174        list = next;
175    }
176}
177
178/**
179***
180**/
181
182struct tm *
183tr_localtime_r( const time_t *_clock, struct tm *_result )
184{
185#ifdef HAVE_LOCALTIME_R
186    return localtime_r( _clock, _result );
187#else
188    struct tm *p = localtime( _clock );
189    if( p )
190        *(_result) = *p;
191    return p;
192#endif
193}
194
195char*
196tr_getLogTimeStr( char * buf, int buflen )
197{
198    char           tmp[64];
199    time_t         now;
200    struct tm      now_tm;
201    struct timeval tv;
202    int            milliseconds;
203
204    now = time( NULL );
205    gettimeofday( &tv, NULL );
206
207    tr_localtime_r( &now, &now_tm );
208    strftime( tmp, sizeof( tmp ), "%H:%M:%S", &now_tm );
209    milliseconds = (int)( tv.tv_usec / 1000 );
210    tr_snprintf( buf, buflen, "%s.%03d", tmp, milliseconds );
211
212    return buf;
213}
214
215void
216tr_assertImpl( const char * file, int line, const char * test, const char * fmt, ... )
217{
218    char buf[64];
219    fprintf( stderr, "[%s] Transmission %s Assertion \"%s\" failed at %s:%d.  ",
220                     tr_getLogTimeStr( buf, sizeof( buf ) ),
221                      LONG_VERSION_STRING, test, file, line );
222    if( fmt && *fmt ) {
223        va_list args;
224        fputc( '(', stderr );
225        va_start( args, fmt );
226        vfprintf( stderr, fmt, args );
227        va_end( args );
228        fputs( ")  ", stderr );
229    }
230    fputs( "Please report this bug at <http://trac.transmissionbt.com/newticket>; Thank you.\n", stderr );
231    abort( );
232}
233
234
235tr_bool
236tr_deepLoggingIsActive( void )
237{
238    static int8_t deepLoggingIsActive = -1;
239
240    if( deepLoggingIsActive < 0 )
241        deepLoggingIsActive = IsDebuggerPresent() || (tr_getLog()!=NULL);
242
243    return deepLoggingIsActive != 0;
244}
245
246void
247tr_deepLog( const char  * file,
248            int           line,
249            const char  * name,
250            const char  * fmt,
251            ... )
252{
253    FILE * fp = tr_getLog( );
254    if( fp || IsDebuggerPresent( ) )
255    {
256        va_list           args;
257        char              timestr[64];
258        struct evbuffer * buf = tr_getBuffer( );
259        char *            base = tr_basename( file );
260
261        evbuffer_add_printf( buf, "[%s] ",
262                            tr_getLogTimeStr( timestr, sizeof( timestr ) ) );
263        if( name )
264            evbuffer_add_printf( buf, "%s ", name );
265        va_start( args, fmt );
266        evbuffer_add_vprintf( buf, fmt, args );
267        va_end( args );
268        evbuffer_add_printf( buf, " (%s:%d)\n", base, line );
269        OutputDebugString( EVBUFFER_DATA( buf ) );
270        if(fp)
271            (void) fwrite( EVBUFFER_DATA( buf ), 1, EVBUFFER_LENGTH( buf ), fp );
272
273        tr_free( base );
274        tr_releaseBuffer( buf );
275    }
276}
277
278/***
279****
280***/
281   
282
283int
284tr_msgLoggingIsActive( int level )
285{
286    tr_msgInit( );
287
288    return messageLevel >= level;
289}
290
291void
292tr_msg( const char * file, int line,
293        int level, const char * name,
294        const char * fmt, ... )
295{
296    const int err = errno; /* message logging shouldn't affect errno */
297    FILE * fp;
298    tr_msgInit( );
299    tr_lockLock( messageLock );
300
301    fp = tr_getLog( );
302
303    if( messageLevel >= level )
304    {
305        char buf[MAX_STACK_ARRAY_SIZE];
306        va_list ap;
307
308        /* build the text message */
309        *buf = '\0';
310        va_start( ap, fmt );
311        evutil_vsnprintf( buf, sizeof( buf ), fmt, ap );
312        va_end( ap );
313
314        OutputDebugString( buf );
315
316        if( *buf )
317        {
318            if( messageQueuing )
319            {
320                tr_msg_list * newmsg;
321                newmsg = tr_new0( tr_msg_list, 1 );
322                newmsg->level = level;
323                newmsg->when = time( NULL );
324                newmsg->message = tr_strdup( buf );
325                newmsg->file = file;
326                newmsg->line = line;
327                newmsg->name = tr_strdup( name );
328
329                *messageQueueTail = newmsg;
330                messageQueueTail = &newmsg->next;
331            }
332            else
333            {
334                char timestr[64];
335
336                if( fp == NULL )
337                    fp = stderr;
338
339                tr_getLogTimeStr( timestr, sizeof( timestr ) );
340
341                if( name )
342                    fprintf( fp, "[%s] %s: %s\n", timestr, name, buf );
343                else
344                    fprintf( fp, "[%s] %s\n", timestr, buf );
345                fflush( fp );
346            }
347        }
348    }
349
350    tr_lockUnlock( messageLock );
351    errno = err;
352}
353
354/***
355****
356***/
357
358void
359tr_set_compare( const void * va,
360                size_t aCount,
361                const void * vb,
362                size_t bCount,
363                int compare( const void * a, const void * b ),
364                size_t elementSize,
365                tr_set_func in_a_cb,
366                tr_set_func in_b_cb,
367                tr_set_func in_both_cb,
368                void * userData )
369{
370    const uint8_t * a = (const uint8_t *) va;
371    const uint8_t * b = (const uint8_t *) vb;
372    const uint8_t * aend = a + elementSize * aCount;
373    const uint8_t * bend = b + elementSize * bCount;
374
375    while( a != aend || b != bend )
376    {
377        if( a == aend )
378        {
379            ( *in_b_cb )( (void*)b, userData );
380            b += elementSize;
381        }
382        else if( b == bend )
383        {
384            ( *in_a_cb )( (void*)a, userData );
385            a += elementSize;
386        }
387        else
388        {
389            const int val = ( *compare )( a, b );
390
391            if( !val )
392            {
393                ( *in_both_cb )( (void*)a, userData );
394                a += elementSize;
395                b += elementSize;
396            }
397            else if( val < 0 )
398            {
399                ( *in_a_cb )( (void*)a, userData );
400                a += elementSize;
401            }
402            else if( val > 0 )
403            {
404                ( *in_b_cb )( (void*)b, userData );
405                b += elementSize;
406            }
407        }
408    }
409}
410
411/***
412****
413***/
414
415#ifdef DISABLE_GETTEXT
416
417const char*
418tr_strip_positional_args( const char* str )
419{
420    static size_t bufsize = 0;
421    static char * buf = NULL;
422    const size_t  len = strlen( str );
423    char *        out;
424
425    if( bufsize < len )
426    {
427        bufsize = len * 2;
428        buf = tr_renew( char, buf, bufsize );
429    }
430
431    for( out = buf; *str; ++str )
432    {
433        *out++ = *str;
434        if( ( *str == '%' ) && isdigit( str[1] ) )
435        {
436            const char * tmp = str + 1;
437            while( isdigit( *tmp ) )
438                ++tmp;
439
440            if( *tmp == '$' )
441                str = tmp;
442        }
443    }
444    *out = '\0';
445
446    return buf;
447}
448
449#endif
450
451/**
452***
453**/
454
455void
456tr_timevalMsec( uint64_t milliseconds, struct timeval * setme )
457{
458    const uint64_t microseconds = milliseconds * 1000;
459    assert( setme != NULL );
460    setme->tv_sec  = microseconds / 1000000;
461    setme->tv_usec = microseconds % 1000000;
462}
463
464uint8_t *
465tr_loadFile( const char * path,
466             size_t *     size )
467{
468    uint8_t * buf;
469    struct stat  sb;
470    int fd;
471    ssize_t n;
472    const char * err_fmt = _( "Couldn't read \"%1$s\": %2$s" );
473
474    /* try to stat the file */
475    errno = 0;
476    if( stat( path, &sb ) )
477    {
478        const int err = errno;
479        tr_dbg( err_fmt, path, tr_strerror( errno ) );
480        errno = err;
481        return NULL;
482    }
483
484    if( ( sb.st_mode & S_IFMT ) != S_IFREG )
485    {
486        tr_err( err_fmt, path, _( "Not a regular file" ) );
487        errno = EISDIR;
488        return NULL;
489    }
490
491    /* Load the torrent file into our buffer */
492    fd = tr_open_file_for_scanning( path );
493    if( fd < 0 )
494    {
495        const int err = errno;
496        tr_err( err_fmt, path, tr_strerror( errno ) );
497        errno = err;
498        return NULL;
499    }
500    buf = malloc( sb.st_size + 1 );
501    if( !buf )
502    {
503        const int err = errno;
504        tr_err( err_fmt, path, _( "Memory allocation failed" ) );
505        tr_close_file( fd );
506        errno = err;
507        return NULL;
508    }
509    n = read( fd, buf, sb.st_size );
510    if( n == -1 )
511    {
512        const int err = errno;
513        tr_err( err_fmt, path, tr_strerror( errno ) );
514        tr_close_file( fd );
515        free( buf );
516        errno = err;
517        return NULL;
518    }
519
520    tr_close_file( fd );
521    buf[ sb.st_size ] = '\0';
522    *size = sb.st_size;
523    return buf;
524}
525
526char*
527tr_basename( const char * path )
528{
529    char * tmp = tr_strdup( path );
530    char * ret = tr_strdup( basename( tmp ) );
531    tr_free( tmp );
532    return ret;
533}
534
535char*
536tr_dirname( const char * path )
537{
538    char * tmp = tr_strdup( path );
539    char * ret = tr_strdup( dirname( tmp ) );
540    tr_free( tmp );
541    return ret;
542}
543
544int
545tr_mkdir( const char * path,
546          int permissions
547#ifdef WIN32
548                       UNUSED
549#endif
550        )
551{
552#ifdef WIN32
553    if( path && isalpha( path[0] ) && path[1] == ':' && !path[2] )
554        return 0;
555    return mkdir( path );
556#else
557    return mkdir( path, permissions );
558#endif
559}
560
561int
562tr_mkdirp( const char * path_in,
563           int          permissions )
564{
565    char *      path = tr_strdup( path_in );
566    char *      p, * pp;
567    struct stat sb;
568    int         done;
569
570    /* walk past the root */
571    p = path;
572    while( *p == TR_PATH_DELIMITER )
573        ++p;
574
575    pp = p;
576    done = 0;
577    while( ( p =
578                strchr( pp, TR_PATH_DELIMITER ) ) || ( p = strchr( pp, '\0' ) ) )
579    {
580        if( !*p )
581            done = 1;
582        else
583            *p = '\0';
584
585        if( stat( path, &sb ) )
586        {
587            /* Folder doesn't exist yet */
588            if( tr_mkdir( path, permissions ) )
589            {
590                const int err = errno;
591                tr_err( _(
592                           "Couldn't create \"%1$s\": %2$s" ), path,
593                       tr_strerror( err ) );
594                tr_free( path );
595                errno = err;
596                return -1;
597            }
598        }
599        else if( ( sb.st_mode & S_IFMT ) != S_IFDIR )
600        {
601            /* Node exists but isn't a folder */
602            char * buf = tr_strdup_printf( _( "File \"%s\" is in the way" ), path );
603            tr_err( _( "Couldn't create \"%1$s\": %2$s" ), path_in, buf );
604            tr_free( buf );
605            tr_free( path );
606            errno = ENOTDIR;
607            return -1;
608        }
609
610        if( done )
611            break;
612
613        *p = TR_PATH_DELIMITER;
614        p++;
615        pp = p;
616    }
617
618    tr_free( path );
619    return 0;
620}
621
622char*
623tr_buildPath( const char *first_element, ... )
624{
625    size_t bufLen = 0;
626    const char * element;
627    char * buf;
628    char * pch;
629    va_list vl;
630
631    /* pass 1: allocate enough space for the string */
632    va_start( vl, first_element );
633    element = first_element;
634    while( element ) {
635        bufLen += strlen( element ) + 1;
636        element = (const char*) va_arg( vl, const char* );
637    }
638    pch = buf = tr_new( char, bufLen );
639    va_end( vl );
640
641    /* pass 2: build the string piece by piece */
642    va_start( vl, first_element );
643    element = first_element;
644    while( element ) {
645        const size_t elementLen = strlen( element );
646        memcpy( pch, element, elementLen );
647        pch += elementLen;
648        *pch++ = TR_PATH_DELIMITER;
649        element = (const char*) va_arg( vl, const char* );
650    }
651    va_end( vl );
652
653    /* terminate the string.  if nonempty, eat the unwanted trailing slash */
654    if( pch != buf )
655        --pch;
656    *pch++ = '\0';
657
658    /* sanity checks & return */
659    assert( pch - buf == (off_t)bufLen );
660    return buf;
661}
662
663/****
664*****
665****/
666
667char*
668tr_strndup( const void * in, int len )
669{
670    char * out = NULL;
671
672    if( len < 0 )
673    {
674        out = tr_strdup( in );
675    }
676    else if( in )
677    {
678        out = tr_malloc( len + 1 );
679        memcpy( out, in, len );
680        out[len] = '\0';
681    }
682
683    return out;
684}
685
686const char*
687tr_memmem( const char * s1, size_t l1, /* haystack */
688           const char * s2, size_t l2 ) /* needle */
689{
690#ifdef HAVE_MEMMEM
691    return memmem( s1, l1, s2, l2 );
692#else
693    if( !l2 ) return s1;
694    while( l1 >= l2 )
695    {
696        l1--;
697        if( !memcmp( s1, s2, l2 ) )
698            return s1;
699        s1++;
700    }
701    return NULL;
702#endif
703}
704
705char*
706tr_strdup_printf( const char * fmt, ... )
707{
708    char *            ret = NULL;
709    struct evbuffer * buf;
710    va_list           ap;
711
712    buf = tr_getBuffer( );
713    va_start( ap, fmt );
714
715    if( evbuffer_add_vprintf( buf, fmt, ap ) != -1 )
716        ret = tr_strdup( EVBUFFER_DATA( buf ) );
717
718    va_end( ap );
719    tr_releaseBuffer( buf );
720    return ret;
721}
722
723const char*
724tr_strerror( int i )
725{
726    const char * ret = strerror( i );
727
728    if( ret == NULL )
729        ret = "Unknown Error";
730    return ret;
731}
732
733/****
734*****
735****/
736
737char*
738tr_strstrip( char * str )
739{
740    if( str != NULL )
741    {
742        size_t pos;
743        size_t len = strlen( str );
744
745        while( len && isspace( str[len - 1] ) )
746            --len;
747
748        str[len] = '\0';
749
750        for( pos = 0; pos < len && isspace( str[pos] ); )
751            ++pos;
752
753        len -= pos;
754        memmove( str, str + pos, len );
755        str[len] = '\0';
756    }
757
758    return str;
759}
760
761/****
762*****
763****/
764
765tr_bitfield*
766tr_bitfieldConstruct( tr_bitfield * b, size_t bitCount )
767{
768    b->bitCount = bitCount;
769    b->byteCount = ( bitCount + 7u ) / 8u;
770    b->bits = tr_new0( uint8_t, b->byteCount );
771    return b;
772}
773
774tr_bitfield*
775tr_bitfieldDestruct( tr_bitfield * b )
776{
777    if( b )
778        tr_free( b->bits );
779    return b;
780}
781
782tr_bitfield*
783tr_bitfieldDup( const tr_bitfield * in )
784{
785    tr_bitfield * ret = tr_new0( tr_bitfield, 1 );
786
787    ret->bitCount = in->bitCount;
788    ret->byteCount = in->byteCount;
789    ret->bits = tr_memdup( in->bits, in->byteCount );
790    return ret;
791}
792
793void
794tr_bitfieldClear( tr_bitfield * bitfield )
795{
796    memset( bitfield->bits, 0, bitfield->byteCount );
797}
798
799int
800tr_bitfieldIsEmpty( const tr_bitfield * bitfield )
801{
802    size_t i;
803
804    for( i = 0; i < bitfield->byteCount; ++i )
805        if( bitfield->bits[i] )
806            return 0;
807
808    return 1;
809}
810
811int
812tr_bitfieldAdd( tr_bitfield * bitfield,
813                size_t        nth )
814{
815    assert( bitfield );
816    assert( bitfield->bits );
817
818    if( nth >= bitfield->bitCount )
819        return -1;
820
821    bitfield->bits[nth >> 3u] |= ( 0x80 >> ( nth & 7u ) );
822    return 0;
823}
824
825/* Sets bit range [begin, end) to 1 */
826int
827tr_bitfieldAddRange( tr_bitfield * b,
828                     size_t        begin,
829                     size_t        end )
830{
831    size_t        sb, eb;
832    unsigned char sm, em;
833
834    end--;
835
836    if( ( end >= b->bitCount ) || ( begin > end ) )
837        return -1;
838
839    sb = begin >> 3;
840    sm = ~( 0xff << ( 8 - ( begin & 7 ) ) );
841    eb = end >> 3;
842    em = 0xff << ( 7 - ( end & 7 ) );
843
844    if( sb == eb )
845    {
846        b->bits[sb] |= ( sm & em );
847    }
848    else
849    {
850        b->bits[sb] |= sm;
851        b->bits[eb] |= em;
852        if( ++sb < eb )
853            memset ( b->bits + sb, 0xff, eb - sb );
854    }
855
856    return 0;
857}
858
859int
860tr_bitfieldRem( tr_bitfield * bitfield,
861                size_t        nth )
862{
863    assert( bitfield );
864    assert( bitfield->bits );
865
866    if( nth >= bitfield->bitCount )
867        return -1;
868
869    bitfield->bits[nth >> 3u] &= ( 0xff7f >> ( nth & 7u ) );
870    return 0;
871}
872
873/* Clears bit range [begin, end) to 0 */
874int
875tr_bitfieldRemRange( tr_bitfield * b,
876                     size_t        begin,
877                     size_t        end )
878{
879    size_t        sb, eb;
880    unsigned char sm, em;
881
882    end--;
883
884    if( ( end >= b->bitCount ) || ( begin > end ) )
885        return -1;
886
887    sb = begin >> 3;
888    sm = 0xff << ( 8 - ( begin & 7 ) );
889    eb = end >> 3;
890    em = ~( 0xff << ( 7 - ( end & 7 ) ) );
891
892    if( sb == eb )
893    {
894        b->bits[sb] &= ( sm | em );
895    }
896    else
897    {
898        b->bits[sb] &= sm;
899        b->bits[eb] &= em;
900        if( ++sb < eb )
901            memset ( b->bits + sb, 0, eb - sb );
902    }
903
904    return 0;
905}
906
907tr_bitfield*
908tr_bitfieldOr( tr_bitfield *       a,
909               const tr_bitfield * b )
910{
911    uint8_t *      ait;
912    const uint8_t *aend, *bit;
913
914    assert( a->bitCount == b->bitCount );
915
916    for( ait = a->bits, bit = b->bits, aend = ait + a->byteCount;
917         ait != aend; )
918        *ait++ |= *bit++;
919
920    return a;
921}
922
923/* set 'a' to all the flags that were in 'a' but not 'b' */
924void
925tr_bitfieldDifference( tr_bitfield *       a,
926                       const tr_bitfield * b )
927{
928    uint8_t *      ait;
929    const uint8_t *aend, *bit;
930
931    assert( a->bitCount == b->bitCount );
932
933    for( ait = a->bits, bit = b->bits, aend = ait + a->byteCount;
934         ait != aend; )
935        *ait++ &= ~( *bit++ );
936}
937
938size_t
939tr_bitfieldCountTrueBits( const tr_bitfield* b )
940{
941    size_t           ret = 0;
942    const uint8_t *  it, *end;
943    static const int trueBitCount[512] = {
944        0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4, 1, 2, 2, 3, 2, 3, 3,
945        4, 2, 3, 3, 4, 3, 4, 4, 5,
946        1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4,
947        5, 3, 4, 4, 5, 4, 5, 5, 6,
948        1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4,
949        5, 3, 4, 4, 5, 4, 5, 5, 6,
950        2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5,
951        6, 4, 5, 5, 6, 5, 6, 6, 7,
952        1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4,
953        5, 3, 4, 4, 5, 4, 5, 5, 6,
954        2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5,
955        6, 4, 5, 5, 6, 5, 6, 6, 7,
956        2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5,
957        6, 4, 5, 5, 6, 5, 6, 6, 7,
958        3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 4, 5, 5, 6, 5, 6, 6,
959        7, 5, 6, 6, 7, 6, 7, 7, 8,
960        1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4,
961        5, 3, 4, 4, 5, 4, 5, 5, 6,
962        2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5,
963        6, 4, 5, 5, 6, 5, 6, 6, 7,
964        2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5,
965        6, 4, 5, 5, 6, 5, 6, 6, 7,
966        3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 4, 5, 5, 6, 5, 6, 6,
967        7, 5, 6, 6, 7, 6, 7, 7, 8,
968        2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5,
969        6, 4, 5, 5, 6, 5, 6, 6, 7,
970        3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 4, 5, 5, 6, 5, 6, 6,
971        7, 5, 6, 6, 7, 6, 7, 7, 8,
972        3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 4, 5, 5, 6, 5, 6, 6,
973        7, 5, 6, 6, 7, 6, 7, 7, 8,
974        4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8, 5, 6, 6, 7, 6, 7, 7,
975        8, 6, 7, 7, 8, 7, 8, 8, 9
976    };
977
978    if( !b )
979        return 0;
980
981    for( it = b->bits, end = it + b->byteCount; it != end; ++it )
982        ret += trueBitCount[*it];
983
984    return ret;
985}
986
987/***
988****
989***/
990
991uint64_t
992tr_date( void )
993{
994    struct timeval tv;
995
996    gettimeofday( &tv, NULL );
997    return (uint64_t) tv.tv_sec * 1000 + ( tv.tv_usec / 1000 );
998}
999
1000void
1001tr_wait( uint64_t delay_milliseconds )
1002{
1003#ifdef WIN32
1004    Sleep( (DWORD)delay_milliseconds );
1005#else
1006    usleep( 1000 * delay_milliseconds );
1007#endif
1008}
1009
1010/***
1011****
1012***/
1013
1014int
1015tr_snprintf( char *       buf,
1016             size_t       buflen,
1017             const char * fmt,
1018             ... )
1019{
1020    int     len;
1021    va_list args;
1022
1023    va_start( args, fmt );
1024    len = evutil_vsnprintf( buf, buflen, fmt, args );
1025    va_end( args );
1026    return len;
1027}
1028
1029/*
1030 * Copy src to string dst of size siz.  At most siz-1 characters
1031 * will be copied.  Always NUL terminates (unless siz == 0).
1032 * Returns strlen(src); if retval >= siz, truncation occurred.
1033 */
1034size_t
1035tr_strlcpy( char *       dst,
1036            const void * src,
1037            size_t       siz )
1038{
1039#ifdef HAVE_STRLCPY
1040    return strlcpy( dst, src, siz );
1041#else
1042    char *      d = dst;
1043    const char *s = src;
1044    size_t      n = siz;
1045
1046    assert( s );
1047    assert( d );
1048
1049    /* Copy as many bytes as will fit */
1050    if( n != 0 )
1051    {
1052        while( --n != 0 )
1053        {
1054            if( ( *d++ = *s++ ) == '\0' )
1055                break;
1056        }
1057    }
1058
1059    /* Not enough room in dst, add NUL and traverse rest of src */
1060    if( n == 0 )
1061    {
1062        if( siz != 0 )
1063            *d = '\0'; /* NUL-terminate dst */
1064        while( *s++ )
1065            ;
1066    }
1067
1068    return s - (char*)src - 1;  /* count does not include NUL */
1069#endif
1070}
1071
1072/***
1073****
1074***/
1075
1076double
1077tr_getRatio( double numerator,
1078             double denominator )
1079{
1080    double ratio;
1081
1082    if( denominator )
1083        ratio = numerator / denominator;
1084    else if( numerator )
1085        ratio = TR_RATIO_INF;
1086    else
1087        ratio = TR_RATIO_NA;
1088
1089    return ratio;
1090}
1091
1092void
1093tr_sha1_to_hex( char *          out,
1094                const uint8_t * sha1 )
1095{
1096    static const char hex[] = "0123456789abcdef";
1097    int               i;
1098
1099    for( i = 0; i < 20; i++ )
1100    {
1101        unsigned int val = *sha1++;
1102        *out++ = hex[val >> 4];
1103        *out++ = hex[val & 0xf];
1104    }
1105    *out = '\0';
1106}
1107
1108/***
1109****
1110***/
1111
1112int
1113tr_httpIsValidURL( const char * url )
1114{
1115    const char *        c;
1116    static const char * rfc2396_valid_chars =
1117        "abcdefghijklmnopqrstuvwxyz" /* lowalpha */
1118        "ABCDEFGHIJKLMNOPQRSTUVWXYZ" /* upalpha */
1119        "0123456789"                 /* digit */
1120        "-_.!~*'()"                  /* mark */
1121        ";/?:@&=+$,"                 /* reserved */
1122        "<>#%<\""                    /* delims */
1123        "{}|\\^[]`";                 /* unwise */
1124
1125    if( url == NULL )
1126        return FALSE;
1127
1128    for( c = url; c && *c; ++c )
1129        if( !strchr( rfc2396_valid_chars, *c ) )
1130            return FALSE;
1131
1132    return !tr_httpParseURL( url, -1, NULL, NULL, NULL );
1133}
1134
1135int
1136tr_httpParseURL( const char * url_in,
1137                 int          len,
1138                 char **      setme_host,
1139                 int *        setme_port,
1140                 char **      setme_path )
1141{
1142    int          err;
1143    int          port = 0;
1144    int          n;
1145    char *       tmp;
1146    char *       pch;
1147    const char * protocol = NULL;
1148    const char * host = NULL;
1149    const char * path = NULL;
1150
1151    tmp = tr_strndup( url_in, len );
1152    if( ( pch = strstr( tmp, "://" ) ) )
1153    {
1154        *pch = '\0';
1155        protocol = tmp;
1156        pch += 3;
1157/*fprintf( stderr, "protocol is [%s]... what's left is [%s]\n", protocol, pch
1158  );*/
1159        if( ( n = strcspn( pch, ":/" ) ) )
1160        {
1161            const int havePort = pch[n] == ':';
1162            host = pch;
1163            pch += n;
1164            *pch++ = '\0';
1165/*fprintf( stderr, "host is [%s]... what's left is [%s]\n", host, pch );*/
1166            if( havePort )
1167            {
1168                char * end;
1169                port = strtol( pch, &end, 10 );
1170                pch = end;
1171/*fprintf( stderr, "port is [%d]... what's left is [%s]\n", port, pch );*/
1172            }
1173            path = pch;
1174/*fprintf( stderr, "path is [%s]\n", path );*/
1175        }
1176    }
1177
1178    err = !host || !path || !protocol
1179          || ( strcmp( protocol, "http" ) && strcmp( protocol, "https" ) );
1180
1181    if( !err && !port )
1182    {
1183        if( !strcmp( protocol, "http" ) ) port = 80;
1184        if( !strcmp( protocol, "https" ) ) port = 443;
1185    }
1186
1187    if( !err )
1188    {
1189        if( setme_host ){ ( (char*)host )[-3] = ':'; *setme_host =
1190                              tr_strdup( protocol ); }
1191        if( setme_path ){ ( (char*)path )[-1] = '/'; *setme_path =
1192                              tr_strdup( path - 1 ); }
1193        if( setme_port ) *setme_port = port;
1194    }
1195
1196
1197    tr_free( tmp );
1198    return err;
1199}
1200
1201#include <string.h>
1202#include <openssl/sha.h>
1203#include <openssl/hmac.h>
1204#include <openssl/evp.h>
1205#include <openssl/bio.h>
1206#include <openssl/buffer.h>
1207
1208char *
1209tr_base64_encode( const void * input,
1210                  int          length,
1211                  int *        setme_len )
1212{
1213    char *    ret;
1214    BIO *     b64;
1215    BIO *     bmem;
1216    BUF_MEM * bptr;
1217
1218    if( length < 1 )
1219        length = strlen( input );
1220
1221    bmem = BIO_new( BIO_s_mem( ) );
1222    b64 = BIO_new( BIO_f_base64( ) );
1223    b64 = BIO_push( b64, bmem );
1224    BIO_write( b64, input, length );
1225    (void) BIO_flush( b64 );
1226    BIO_get_mem_ptr( b64, &bptr );
1227    ret = tr_strndup( bptr->data, bptr->length );
1228    if( setme_len )
1229        *setme_len = bptr->length;
1230
1231    BIO_free_all( b64 );
1232    return ret;
1233}
1234
1235char *
1236tr_base64_decode( const void * input,
1237                  int          length,
1238                  int *        setme_len )
1239{
1240    char * ret;
1241    BIO *  b64;
1242    BIO *  bmem;
1243    int    retlen;
1244
1245    if( length < 1 )
1246        length = strlen( input );
1247
1248    ret = tr_new0( char, length );
1249    b64 = BIO_new( BIO_f_base64( ) );
1250    bmem = BIO_new_mem_buf( (unsigned char*)input, length );
1251    bmem = BIO_push( b64, bmem );
1252    retlen = BIO_read( bmem, ret, length );
1253    if( !retlen )
1254    {
1255        /* try again, but with the BIO_FLAGS_BASE64_NO_NL flag */
1256        BIO_free_all( bmem );
1257        b64 = BIO_new( BIO_f_base64( ) );
1258        BIO_set_flags( b64, BIO_FLAGS_BASE64_NO_NL );
1259        bmem = BIO_new_mem_buf( (unsigned char*)input, length );
1260        bmem = BIO_push( b64, bmem );
1261        retlen = BIO_read( bmem, ret, length );
1262    }
1263
1264    if( setme_len )
1265        *setme_len = retlen;
1266
1267    BIO_free_all( bmem );
1268    return ret;
1269}
1270
1271int
1272tr_ptr2int( void* v )
1273{
1274    return (intptr_t)v;
1275}
1276
1277void*
1278tr_int2ptr( int i )
1279{
1280    return (void*)(intptr_t)i;
1281}
1282
1283/***
1284****
1285***/
1286
1287static tr_list * _bufferList = NULL;
1288
1289static tr_lock *
1290getBufferLock( void )
1291{
1292    static tr_lock * lock = NULL;
1293    if( lock == NULL )
1294        lock = tr_lockNew( );
1295    return lock;
1296}
1297
1298struct evbuffer*
1299tr_getBuffer( void )
1300{
1301    struct evbuffer * buf;
1302    tr_lock * l = getBufferLock( );
1303    tr_lockLock( l );
1304
1305    buf = tr_list_pop_front( &_bufferList );
1306    if( buf == NULL )
1307        buf = evbuffer_new( );
1308
1309    tr_lockUnlock( l );
1310    return buf;
1311}
1312
1313void
1314tr_releaseBuffer( struct evbuffer * buf )
1315{
1316    tr_lock * l = getBufferLock( );
1317    tr_lockLock( l );
1318
1319    evbuffer_drain( buf, EVBUFFER_LENGTH( buf ) );
1320    assert( EVBUFFER_LENGTH( buf ) == 0 );
1321    tr_list_prepend( &_bufferList, buf );
1322
1323    tr_lockUnlock( l );
1324}
1325
1326/***
1327****
1328***/
1329
1330int
1331tr_lowerBound( const void * key,
1332               const void * base,
1333               size_t       nmemb,
1334               size_t       size,
1335               int       (* compar)(const void* key, const void* arrayMember),
1336               tr_bool    * exact_match )
1337{
1338    size_t first = 0;
1339    const char * cbase = base;
1340
1341    while( nmemb )
1342    {
1343        const size_t half = nmemb / 2;
1344        const size_t middle = first + half;
1345        const int c = compar( key, cbase + size*middle );
1346
1347        if( c < 0 )
1348        {
1349            first = middle + 1;
1350            nmemb = nmemb - half - 1;
1351        }
1352        else if( !c )
1353        {
1354            if( exact_match )
1355                *exact_match = TRUE;
1356            return middle;
1357        }
1358        else
1359        {
1360            nmemb = half;
1361        }
1362    }
1363
1364    if( exact_match )
1365        *exact_match = FALSE;
1366
1367    return first;
1368}
1369
1370/***
1371****
1372***/
1373
1374char*
1375tr_utf8clean( const char * str, int max_len, tr_bool * err )
1376{
1377    char * ret;
1378    const char * end;
1379
1380    if( max_len < 0 )
1381        max_len = (int) strlen( str );
1382
1383    if( err != NULL )
1384        *err = FALSE;
1385
1386    if( tr_utf8_validate( str, max_len, &end  ) )
1387    {
1388        ret = tr_strndup( str, max_len );
1389    }
1390    else
1391    {
1392        const char zero = '\0';
1393        struct evbuffer * buf = evbuffer_new( );
1394
1395        while( !tr_utf8_validate ( str, max_len, &end ) )
1396        {
1397            const int good_len = end - str;
1398
1399            evbuffer_add( buf, str, good_len );
1400            max_len -= ( good_len + 1 );
1401            str += ( good_len + 1 );
1402            evbuffer_add( buf, "?", 1 );
1403
1404            if( err != NULL )
1405                *err = TRUE;
1406        }
1407
1408        evbuffer_add( buf, str, max_len );
1409        evbuffer_add( buf, &zero, 1 );
1410        ret = tr_memdup( EVBUFFER_DATA( buf ), EVBUFFER_LENGTH( buf ) );
1411        evbuffer_free( buf );
1412    }
1413
1414    assert( tr_utf8_validate( ret, -1, NULL ) );
1415    return ret;
1416}
1417
1418/***
1419****
1420***/
1421
1422struct number_range
1423{
1424    int low;
1425    int high;
1426};
1427
1428/**
1429 * This should be a single number (ex. "6") or a range (ex. "6-9").
1430 * Anything else is an error and will return failure.
1431 */
1432static tr_bool
1433parseNumberSection( const char * str, int len, struct number_range * setme )
1434{
1435    long a, b;
1436    tr_bool success;
1437    char * end;
1438    const int error = errno;
1439    char * tmp = tr_strndup( str, len );
1440
1441    errno = 0;
1442    a = b = strtol( tmp, &end, 10 );
1443    if( errno || ( end == tmp ) ) {
1444        success = FALSE;
1445    } else if( *end != '-' ) {
1446        b = a;
1447        success = TRUE;
1448    } else {
1449        const char * pch = end + 1;
1450        b = strtol( pch, &end, 10 );
1451        if( errno || ( pch == end ) )
1452            success = FALSE;
1453        else if( *end ) /* trailing data */
1454            success = FALSE;
1455        else
1456            success = TRUE;
1457    }
1458    tr_free( tmp );
1459
1460    setme->low = MIN( a, b );
1461    setme->high = MAX( a, b );
1462
1463    errno = error;
1464    return success;
1465}
1466
1467static int
1468compareInt( const void * va, const void * vb )
1469{
1470    const int a = *(const int *)va;
1471    const int b = *(const int *)vb;
1472    return a - b;
1473}
1474
1475/**
1476 * Given a string like "1-4" or "1-4,6,9,14-51", this allocates and returns an
1477 * array of setmeCount ints of all the values in the array.
1478 * For example, "5-8" will return [ 5, 6, 7, 8 ] and setmeCount will be 4.
1479 * It's the caller's responsibility to call tr_free() on the returned array.
1480 * If a fragment of the string can't be parsed, NULL is returned.
1481 */
1482int*
1483tr_parseNumberRange( const char * str_in, int len, int * setmeCount )
1484{
1485    int n = 0;
1486    int * uniq = NULL;
1487    char * str = tr_strndup( str_in, len );
1488    const char * walk;
1489    tr_list * ranges = NULL;
1490    tr_bool success = TRUE;
1491
1492    walk = str;
1493    while( walk && *walk && success ) {
1494        struct number_range range;
1495        const char * pch = strchr( walk, ',' );
1496        if( pch ) {
1497            success = parseNumberSection( walk, pch-walk, &range );
1498            walk = pch + 1;
1499        } else {
1500            success = parseNumberSection( walk, strlen( walk ), &range );
1501            walk += strlen( walk );
1502        }
1503        if( success )
1504            tr_list_append( &ranges, tr_memdup( &range, sizeof( struct number_range ) ) );
1505    }
1506
1507    if( !success )
1508    {
1509        *setmeCount = 0;
1510        uniq = NULL;
1511    }
1512    else
1513    {
1514        int i;
1515        int n2;
1516        tr_list * l;
1517        int * sorted = NULL;
1518
1519        /* build a sorted number array */
1520        n = n2 = 0;
1521        for( l=ranges; l!=NULL; l=l->next ) {
1522            const struct number_range * r = l->data;
1523            n += r->high + 1 - r->low;
1524        }
1525        sorted = tr_new( int, n );
1526        for( l=ranges; l!=NULL; l=l->next ) {
1527            const struct number_range * r = l->data;
1528            int i;
1529            for( i=r->low; i<=r->high; ++i )
1530                sorted[n2++] = i;
1531        }
1532        qsort( sorted, n, sizeof( int ), compareInt );
1533        assert( n == n2 );
1534
1535        /* remove duplicates */
1536        uniq = tr_new( int, n );
1537        for( i=n=0; i<n2; ++i )
1538            if( !n || uniq[n-1] != sorted[i] )
1539                uniq[n++] = sorted[i];
1540
1541        tr_free( sorted );
1542    }
1543
1544    /* cleanup */
1545    tr_list_free( &ranges, tr_free );
1546    tr_free( str );
1547
1548    /* return the result */
1549    *setmeCount = n;
1550    return uniq;
1551}
1552
1553/***
1554****
1555***/
1556
1557static void
1558printf_double_without_rounding( char * buf, int buflen, double d, int places )
1559{
1560    char * pch;
1561    char tmp[128];
1562    int len;
1563    tr_snprintf( tmp, sizeof( tmp ), "%'.64f", d );
1564    pch = tmp;
1565    while( isdigit( *pch ) ) ++pch; /* walk to the decimal point */
1566    ++pch; /* walk over the decimal point */
1567    pch += places;
1568    len = MIN( buflen - 1, pch - tmp );
1569    memcpy( buf, tmp, len );
1570    buf[len] = '\0';
1571}
1572
1573char*
1574tr_strratio( char * buf, size_t buflen, double ratio, const char * infinity )
1575{
1576    if( (int)ratio == TR_RATIO_NA )
1577        tr_strlcpy( buf, _( "None" ), buflen );
1578    else if( (int)ratio == TR_RATIO_INF )
1579        tr_strlcpy( buf, infinity, buflen );
1580    else if( ratio < 10.0 )
1581        printf_double_without_rounding( buf, buflen, ratio, 2 );
1582    else if( ratio < 100.0 )
1583        printf_double_without_rounding( buf, buflen, ratio, 1 );
1584    else
1585        tr_snprintf( buf, buflen, "%'.0f", ratio );
1586    return buf;
1587}
1588
1589/***
1590****
1591***/
1592
1593int
1594tr_moveFile( const char * oldpath, const char * newpath )
1595{
1596    int in;
1597    int out;
1598    char * buf;
1599    struct stat st;
1600    size_t bytesLeft;
1601    size_t buflen;
1602
1603    /* make sure the old file exists */
1604    if( stat( oldpath, &st ) ) {
1605        const int err = errno;
1606        errno = err;
1607        return -1;
1608    }
1609    if( !S_ISREG( st.st_mode ) ) {
1610        errno = ENOENT;
1611        return -1;
1612    }
1613    bytesLeft = st.st_size;
1614
1615    /* make sure the target directory exists */
1616    {
1617        char * newdir = tr_dirname( newpath );
1618        int i = tr_mkdirp( newdir, 0777 );
1619        tr_free( newdir );
1620        if( i )
1621            return i;
1622    }
1623
1624    /* they  might be on the same filesystem... */
1625    if( !rename( oldpath, newpath ) )
1626        return 0;
1627
1628    /* copy the file */
1629    in = tr_open_file_for_scanning( oldpath );
1630    tr_preallocate_file( newpath, bytesLeft );
1631    out = tr_open_file_for_writing( newpath );
1632    buflen = stat( newpath, &st ) ? 4096 : st.st_blksize;
1633    buf = tr_new( char, buflen );
1634    while( bytesLeft > 0 )
1635    {
1636        ssize_t bytesWritten;
1637        const size_t bytesThisPass = MIN( bytesLeft, buflen );
1638        const int numRead = read( in, buf, bytesThisPass );
1639        if( numRead < 0 )
1640            break;
1641        bytesWritten = write( out, buf, numRead );
1642        if( bytesWritten < 0 )
1643            break;
1644        bytesLeft -= bytesWritten;
1645    }
1646
1647    /* cleanup */
1648    tr_free( buf );
1649    tr_close_file( out );
1650    tr_close_file( in );
1651    if( bytesLeft != 0 )
1652        return -1;
1653
1654    unlink( oldpath );
1655    return 0;
1656}
Note: See TracBrowser for help on using the repository browser.