source: trunk/libtransmission/utils.c @ 8368

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

(trunk libT) #2030: revert false alarm r8361 as per this suggestion http://trac.transmissionbt.com/ticket/2030#comment:45

  • Property svn:keywords set to Date Rev Author Id
File size: 34.2 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 8368 2009-05-08 20:52:12Z 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
686char*
687tr_strdup_printf( const char * fmt, ... )
688{
689    char *            ret = NULL;
690    struct evbuffer * buf;
691    va_list           ap;
692
693    buf = tr_getBuffer( );
694    va_start( ap, fmt );
695
696    if( evbuffer_add_vprintf( buf, fmt, ap ) != -1 )
697        ret = tr_strdup( EVBUFFER_DATA( buf ) );
698
699    va_end( ap );
700    tr_releaseBuffer( buf );
701    return ret;
702}
703
704const char*
705tr_strerror( int i )
706{
707    const char * ret = strerror( i );
708
709    if( ret == NULL )
710        ret = "Unknown Error";
711    return ret;
712}
713
714/****
715*****
716****/
717
718char*
719tr_strstrip( char * str )
720{
721    if( str != NULL )
722    {
723        size_t pos;
724        size_t len = strlen( str );
725
726        while( len && isspace( str[len - 1] ) )
727            --len;
728
729        str[len] = '\0';
730
731        for( pos = 0; pos < len && isspace( str[pos] ); )
732            ++pos;
733
734        len -= pos;
735        memmove( str, str + pos, len );
736        str[len] = '\0';
737    }
738
739    return str;
740}
741
742/****
743*****
744****/
745
746tr_bitfield*
747tr_bitfieldConstruct( tr_bitfield * b, size_t bitCount )
748{
749    b->bitCount = bitCount;
750    b->byteCount = ( bitCount + 7u ) / 8u;
751    b->bits = tr_new0( uint8_t, b->byteCount );
752    return b;
753}
754
755tr_bitfield*
756tr_bitfieldDestruct( tr_bitfield * b )
757{
758    if( b )
759        tr_free( b->bits );
760    return b;
761}
762
763tr_bitfield*
764tr_bitfieldDup( const tr_bitfield * in )
765{
766    tr_bitfield * ret = tr_new0( tr_bitfield, 1 );
767
768    ret->bitCount = in->bitCount;
769    ret->byteCount = in->byteCount;
770    ret->bits = tr_memdup( in->bits, in->byteCount );
771    return ret;
772}
773
774void
775tr_bitfieldClear( tr_bitfield * bitfield )
776{
777    memset( bitfield->bits, 0, bitfield->byteCount );
778}
779
780int
781tr_bitfieldIsEmpty( const tr_bitfield * bitfield )
782{
783    size_t i;
784
785    for( i = 0; i < bitfield->byteCount; ++i )
786        if( bitfield->bits[i] )
787            return 0;
788
789    return 1;
790}
791
792int
793tr_bitfieldAdd( tr_bitfield * bitfield,
794                size_t        nth )
795{
796    assert( bitfield );
797    assert( bitfield->bits );
798
799    if( nth >= bitfield->bitCount )
800        return -1;
801
802    bitfield->bits[nth >> 3u] |= ( 0x80 >> ( nth & 7u ) );
803    return 0;
804}
805
806/* Sets bit range [begin, end) to 1 */
807int
808tr_bitfieldAddRange( tr_bitfield * b,
809                     size_t        begin,
810                     size_t        end )
811{
812    size_t        sb, eb;
813    unsigned char sm, em;
814
815    end--;
816
817    if( ( end >= b->bitCount ) || ( begin > end ) )
818        return -1;
819
820    sb = begin >> 3;
821    sm = ~( 0xff << ( 8 - ( begin & 7 ) ) );
822    eb = end >> 3;
823    em = 0xff << ( 7 - ( end & 7 ) );
824
825    if( sb == eb )
826    {
827        b->bits[sb] |= ( sm & em );
828    }
829    else
830    {
831        b->bits[sb] |= sm;
832        b->bits[eb] |= em;
833        if( ++sb < eb )
834            memset ( b->bits + sb, 0xff, eb - sb );
835    }
836
837    return 0;
838}
839
840int
841tr_bitfieldRem( tr_bitfield * bitfield,
842                size_t        nth )
843{
844    assert( bitfield );
845    assert( bitfield->bits );
846
847    if( nth >= bitfield->bitCount )
848        return -1;
849
850    bitfield->bits[nth >> 3u] &= ( 0xff7f >> ( nth & 7u ) );
851    return 0;
852}
853
854/* Clears bit range [begin, end) to 0 */
855int
856tr_bitfieldRemRange( tr_bitfield * b,
857                     size_t        begin,
858                     size_t        end )
859{
860    size_t        sb, eb;
861    unsigned char sm, em;
862
863    end--;
864
865    if( ( end >= b->bitCount ) || ( begin > end ) )
866        return -1;
867
868    sb = begin >> 3;
869    sm = 0xff << ( 8 - ( begin & 7 ) );
870    eb = end >> 3;
871    em = ~( 0xff << ( 7 - ( end & 7 ) ) );
872
873    if( sb == eb )
874    {
875        b->bits[sb] &= ( sm | em );
876    }
877    else
878    {
879        b->bits[sb] &= sm;
880        b->bits[eb] &= em;
881        if( ++sb < eb )
882            memset ( b->bits + sb, 0, eb - sb );
883    }
884
885    return 0;
886}
887
888tr_bitfield*
889tr_bitfieldOr( tr_bitfield *       a,
890               const tr_bitfield * b )
891{
892    uint8_t *      ait;
893    const uint8_t *aend, *bit;
894
895    assert( a->bitCount == b->bitCount );
896
897    for( ait = a->bits, bit = b->bits, aend = ait + a->byteCount;
898         ait != aend; )
899        *ait++ |= *bit++;
900
901    return a;
902}
903
904/* set 'a' to all the flags that were in 'a' but not 'b' */
905void
906tr_bitfieldDifference( tr_bitfield *       a,
907                       const tr_bitfield * b )
908{
909    uint8_t *      ait;
910    const uint8_t *aend, *bit;
911
912    assert( a->bitCount == b->bitCount );
913
914    for( ait = a->bits, bit = b->bits, aend = ait + a->byteCount;
915         ait != aend; )
916        *ait++ &= ~( *bit++ );
917}
918
919size_t
920tr_bitfieldCountTrueBits( const tr_bitfield* b )
921{
922    size_t           ret = 0;
923    const uint8_t *  it, *end;
924    static const int trueBitCount[512] = {
925        0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4, 1, 2, 2, 3, 2, 3, 3,
926        4, 2, 3, 3, 4, 3, 4, 4, 5,
927        1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4,
928        5, 3, 4, 4, 5, 4, 5, 5, 6,
929        1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4,
930        5, 3, 4, 4, 5, 4, 5, 5, 6,
931        2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5,
932        6, 4, 5, 5, 6, 5, 6, 6, 7,
933        1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4,
934        5, 3, 4, 4, 5, 4, 5, 5, 6,
935        2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5,
936        6, 4, 5, 5, 6, 5, 6, 6, 7,
937        2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5,
938        6, 4, 5, 5, 6, 5, 6, 6, 7,
939        3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 4, 5, 5, 6, 5, 6, 6,
940        7, 5, 6, 6, 7, 6, 7, 7, 8,
941        1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4,
942        5, 3, 4, 4, 5, 4, 5, 5, 6,
943        2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5,
944        6, 4, 5, 5, 6, 5, 6, 6, 7,
945        2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5,
946        6, 4, 5, 5, 6, 5, 6, 6, 7,
947        3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 4, 5, 5, 6, 5, 6, 6,
948        7, 5, 6, 6, 7, 6, 7, 7, 8,
949        2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5,
950        6, 4, 5, 5, 6, 5, 6, 6, 7,
951        3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 4, 5, 5, 6, 5, 6, 6,
952        7, 5, 6, 6, 7, 6, 7, 7, 8,
953        3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 4, 5, 5, 6, 5, 6, 6,
954        7, 5, 6, 6, 7, 6, 7, 7, 8,
955        4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8, 5, 6, 6, 7, 6, 7, 7,
956        8, 6, 7, 7, 8, 7, 8, 8, 9
957    };
958
959    if( !b )
960        return 0;
961
962    for( it = b->bits, end = it + b->byteCount; it != end; ++it )
963        ret += trueBitCount[*it];
964
965    return ret;
966}
967
968/***
969****
970***/
971
972uint64_t
973tr_date( void )
974{
975    struct timeval tv;
976
977    gettimeofday( &tv, NULL );
978    return (uint64_t) tv.tv_sec * 1000 + ( tv.tv_usec / 1000 );
979}
980
981void
982tr_wait( uint64_t delay_milliseconds )
983{
984#ifdef WIN32
985    Sleep( (DWORD)delay_milliseconds );
986#else
987    usleep( 1000 * delay_milliseconds );
988#endif
989}
990
991/***
992****
993***/
994
995int
996tr_snprintf( char *       buf,
997             size_t       buflen,
998             const char * fmt,
999             ... )
1000{
1001    int     len;
1002    va_list args;
1003
1004    va_start( args, fmt );
1005    len = evutil_vsnprintf( buf, buflen, fmt, args );
1006    va_end( args );
1007    return len;
1008}
1009
1010/*
1011 * Copy src to string dst of size siz.  At most siz-1 characters
1012 * will be copied.  Always NUL terminates (unless siz == 0).
1013 * Returns strlen(src); if retval >= siz, truncation occurred.
1014 */
1015size_t
1016tr_strlcpy( char *       dst,
1017            const void * src,
1018            size_t       siz )
1019{
1020#ifdef HAVE_STRLCPY
1021    return strlcpy( dst, src, siz );
1022#else
1023    char *      d = dst;
1024    const char *s = src;
1025    size_t      n = siz;
1026
1027    assert( s );
1028    assert( d );
1029
1030    /* Copy as many bytes as will fit */
1031    if( n != 0 )
1032    {
1033        while( --n != 0 )
1034        {
1035            if( ( *d++ = *s++ ) == '\0' )
1036                break;
1037        }
1038    }
1039
1040    /* Not enough room in dst, add NUL and traverse rest of src */
1041    if( n == 0 )
1042    {
1043        if( siz != 0 )
1044            *d = '\0'; /* NUL-terminate dst */
1045        while( *s++ )
1046            ;
1047    }
1048
1049    return s - (char*)src - 1;  /* count does not include NUL */
1050#endif
1051}
1052
1053/***
1054****
1055***/
1056
1057double
1058tr_getRatio( double numerator,
1059             double denominator )
1060{
1061    double ratio;
1062
1063    if( denominator )
1064        ratio = numerator / denominator;
1065    else if( numerator )
1066        ratio = TR_RATIO_INF;
1067    else
1068        ratio = TR_RATIO_NA;
1069
1070    return ratio;
1071}
1072
1073void
1074tr_sha1_to_hex( char *          out,
1075                const uint8_t * sha1 )
1076{
1077    static const char hex[] = "0123456789abcdef";
1078    int               i;
1079
1080    for( i = 0; i < 20; i++ )
1081    {
1082        unsigned int val = *sha1++;
1083        *out++ = hex[val >> 4];
1084        *out++ = hex[val & 0xf];
1085    }
1086    *out = '\0';
1087}
1088
1089/***
1090****
1091***/
1092
1093int
1094tr_httpIsValidURL( const char * url )
1095{
1096    const char *        c;
1097    static const char * rfc2396_valid_chars =
1098        "abcdefghijklmnopqrstuvwxyz" /* lowalpha */
1099        "ABCDEFGHIJKLMNOPQRSTUVWXYZ" /* upalpha */
1100        "0123456789"                 /* digit */
1101        "-_.!~*'()"                  /* mark */
1102        ";/?:@&=+$,"                 /* reserved */
1103        "<>#%<\""                    /* delims */
1104        "{}|\\^[]`";                 /* unwise */
1105
1106    if( url == NULL )
1107        return FALSE;
1108
1109    for( c = url; c && *c; ++c )
1110        if( !strchr( rfc2396_valid_chars, *c ) )
1111            return FALSE;
1112
1113    return !tr_httpParseURL( url, -1, NULL, NULL, NULL );
1114}
1115
1116int
1117tr_httpParseURL( const char * url_in,
1118                 int          len,
1119                 char **      setme_host,
1120                 int *        setme_port,
1121                 char **      setme_path )
1122{
1123    int          err;
1124    int          port = 0;
1125    int          n;
1126    char *       tmp;
1127    char *       pch;
1128    const char * protocol = NULL;
1129    const char * host = NULL;
1130    const char * path = NULL;
1131
1132    tmp = tr_strndup( url_in, len );
1133    if( ( pch = strstr( tmp, "://" ) ) )
1134    {
1135        *pch = '\0';
1136        protocol = tmp;
1137        pch += 3;
1138/*fprintf( stderr, "protocol is [%s]... what's left is [%s]\n", protocol, pch
1139  );*/
1140        if( ( n = strcspn( pch, ":/" ) ) )
1141        {
1142            const int havePort = pch[n] == ':';
1143            host = pch;
1144            pch += n;
1145            *pch++ = '\0';
1146/*fprintf( stderr, "host is [%s]... what's left is [%s]\n", host, pch );*/
1147            if( havePort )
1148            {
1149                char * end;
1150                port = strtol( pch, &end, 10 );
1151                pch = end;
1152/*fprintf( stderr, "port is [%d]... what's left is [%s]\n", port, pch );*/
1153            }
1154            path = pch;
1155/*fprintf( stderr, "path is [%s]\n", path );*/
1156        }
1157    }
1158
1159    err = !host || !path || !protocol
1160          || ( strcmp( protocol, "http" ) && strcmp( protocol, "https" ) );
1161
1162    if( !err && !port )
1163    {
1164        if( !strcmp( protocol, "http" ) ) port = 80;
1165        if( !strcmp( protocol, "https" ) ) port = 443;
1166    }
1167
1168    if( !err )
1169    {
1170        if( setme_host ){ ( (char*)host )[-3] = ':'; *setme_host =
1171                              tr_strdup( protocol ); }
1172        if( setme_path ){ ( (char*)path )[-1] = '/'; *setme_path =
1173                              tr_strdup( path - 1 ); }
1174        if( setme_port ) *setme_port = port;
1175    }
1176
1177
1178    tr_free( tmp );
1179    return err;
1180}
1181
1182#include <string.h>
1183#include <openssl/sha.h>
1184#include <openssl/hmac.h>
1185#include <openssl/evp.h>
1186#include <openssl/bio.h>
1187#include <openssl/buffer.h>
1188
1189char *
1190tr_base64_encode( const void * input,
1191                  int          length,
1192                  int *        setme_len )
1193{
1194    char *    ret;
1195    BIO *     b64;
1196    BIO *     bmem;
1197    BUF_MEM * bptr;
1198
1199    if( length < 1 )
1200        length = strlen( input );
1201
1202    bmem = BIO_new( BIO_s_mem( ) );
1203    b64 = BIO_new( BIO_f_base64( ) );
1204    b64 = BIO_push( b64, bmem );
1205    BIO_write( b64, input, length );
1206    (void) BIO_flush( b64 );
1207    BIO_get_mem_ptr( b64, &bptr );
1208    ret = tr_strndup( bptr->data, bptr->length );
1209    if( setme_len )
1210        *setme_len = bptr->length;
1211
1212    BIO_free_all( b64 );
1213    return ret;
1214}
1215
1216char *
1217tr_base64_decode( const void * input,
1218                  int          length,
1219                  int *        setme_len )
1220{
1221    char * ret;
1222    BIO *  b64;
1223    BIO *  bmem;
1224    int    retlen;
1225
1226    if( length < 1 )
1227        length = strlen( input );
1228
1229    ret = tr_new0( char, length );
1230    b64 = BIO_new( BIO_f_base64( ) );
1231    bmem = BIO_new_mem_buf( (unsigned char*)input, length );
1232    bmem = BIO_push( b64, bmem );
1233    retlen = BIO_read( bmem, ret, length );
1234    if( !retlen )
1235    {
1236        /* try again, but with the BIO_FLAGS_BASE64_NO_NL flag */
1237        BIO_free_all( bmem );
1238        b64 = BIO_new( BIO_f_base64( ) );
1239        BIO_set_flags( b64, BIO_FLAGS_BASE64_NO_NL );
1240        bmem = BIO_new_mem_buf( (unsigned char*)input, length );
1241        bmem = BIO_push( b64, bmem );
1242        retlen = BIO_read( bmem, ret, length );
1243    }
1244
1245    if( setme_len )
1246        *setme_len = retlen;
1247
1248    BIO_free_all( bmem );
1249    return ret;
1250}
1251
1252int
1253tr_ptr2int( void* v )
1254{
1255    return (intptr_t)v;
1256}
1257
1258void*
1259tr_int2ptr( int i )
1260{
1261    return (void*)(intptr_t)i;
1262}
1263
1264/***
1265****
1266***/
1267
1268static tr_list * _bufferList = NULL;
1269
1270static tr_lock *
1271getBufferLock( void )
1272{
1273    static tr_lock * lock = NULL;
1274    if( lock == NULL )
1275        lock = tr_lockNew( );
1276    return lock;
1277}
1278
1279struct evbuffer*
1280tr_getBuffer( void )
1281{
1282    struct evbuffer * buf;
1283    tr_lock * l = getBufferLock( );
1284    tr_lockLock( l );
1285
1286    buf = tr_list_pop_front( &_bufferList );
1287    if( buf == NULL )
1288        buf = evbuffer_new( );
1289
1290    tr_lockUnlock( l );
1291    return buf;
1292}
1293
1294void
1295tr_releaseBuffer( struct evbuffer * buf )
1296{
1297    tr_lock * l = getBufferLock( );
1298    tr_lockLock( l );
1299
1300    evbuffer_drain( buf, EVBUFFER_LENGTH( buf ) );
1301    assert( EVBUFFER_LENGTH( buf ) == 0 );
1302    tr_list_prepend( &_bufferList, buf );
1303
1304    tr_lockUnlock( l );
1305}
1306
1307/***
1308****
1309***/
1310
1311int
1312tr_lowerBound( const void * key,
1313               const void * base,
1314               size_t       nmemb,
1315               size_t       size,
1316               int       (* compar)(const void* key, const void* arrayMember),
1317               tr_bool    * exact_match )
1318{
1319    size_t first = 0;
1320    const char * cbase = base;
1321
1322    while( nmemb )
1323    {
1324        const size_t half = nmemb / 2;
1325        const size_t middle = first + half;
1326        const int c = compar( key, cbase + size*middle );
1327
1328        if( c < 0 )
1329        {
1330            first = middle + 1;
1331            nmemb = nmemb - half - 1;
1332        }
1333        else if( !c )
1334        {
1335            if( exact_match )
1336                *exact_match = TRUE;
1337            return middle;
1338        }
1339        else
1340        {
1341            nmemb = half;
1342        }
1343    }
1344
1345    if( exact_match )
1346        *exact_match = FALSE;
1347
1348    return first;
1349}
1350
1351/***
1352****
1353***/
1354
1355char*
1356tr_utf8clean( const char * str, int max_len, tr_bool * err )
1357{
1358    char * ret;
1359    const char * end;
1360
1361    if( max_len < 0 )
1362        max_len = (int) strlen( str );
1363
1364    if( err != NULL )
1365        *err = FALSE;
1366
1367    if( tr_utf8_validate( str, max_len, &end  ) )
1368    {
1369        ret = tr_strndup( str, max_len );
1370    }
1371    else
1372    {
1373        const char zero = '\0';
1374        struct evbuffer * buf = evbuffer_new( );
1375
1376        while( !tr_utf8_validate ( str, max_len, &end ) )
1377        {
1378            const int good_len = end - str;
1379
1380            evbuffer_add( buf, str, good_len );
1381            max_len -= ( good_len + 1 );
1382            str += ( good_len + 1 );
1383            evbuffer_add( buf, "?", 1 );
1384
1385            if( err != NULL )
1386                *err = TRUE;
1387        }
1388
1389        evbuffer_add( buf, str, max_len );
1390        evbuffer_add( buf, &zero, 1 );
1391        ret = tr_memdup( EVBUFFER_DATA( buf ), EVBUFFER_LENGTH( buf ) );
1392        evbuffer_free( buf );
1393    }
1394
1395    assert( tr_utf8_validate( ret, -1, NULL ) );
1396    return ret;
1397}
1398
1399/***
1400****
1401***/
1402
1403struct number_range
1404{
1405    int low;
1406    int high;
1407};
1408
1409/**
1410 * This should be a single number (ex. "6") or a range (ex. "6-9").
1411 * Anything else is an error and will return failure.
1412 */
1413static tr_bool
1414parseNumberSection( const char * str, int len, struct number_range * setme )
1415{
1416    long a, b;
1417    tr_bool success;
1418    char * end;
1419    const int error = errno;
1420    char * tmp = tr_strndup( str, len );
1421
1422    errno = 0;
1423    a = b = strtol( tmp, &end, 10 );
1424    if( errno || ( end == tmp ) ) {
1425        success = FALSE;
1426    } else if( *end != '-' ) {
1427        b = a;
1428        success = TRUE;
1429    } else {
1430        const char * pch = end + 1;
1431        b = strtol( pch, &end, 10 );
1432        if( errno || ( pch == end ) )
1433            success = FALSE;
1434        else if( *end ) /* trailing data */
1435            success = FALSE;
1436        else
1437            success = TRUE;
1438    }
1439    tr_free( tmp );
1440
1441    setme->low = MIN( a, b );
1442    setme->high = MAX( a, b );
1443
1444    errno = error;
1445    return success;
1446}
1447
1448static int
1449compareInt( const void * va, const void * vb )
1450{
1451    const int a = *(const int *)va;
1452    const int b = *(const int *)vb;
1453    return a - b;
1454}
1455
1456/**
1457 * Given a string like "1-4" or "1-4,6,9,14-51", this allocates and returns an
1458 * array of setmeCount ints of all the values in the array.
1459 * For example, "5-8" will return [ 5, 6, 7, 8 ] and setmeCount will be 4.
1460 * It's the caller's responsibility to call tr_free() on the returned array.
1461 * If a fragment of the string can't be parsed, NULL is returned.
1462 */
1463int*
1464tr_parseNumberRange( const char * str_in, int len, int * setmeCount )
1465{
1466    int n = 0;
1467    int * uniq = NULL;
1468    char * str = tr_strndup( str_in, len );
1469    const char * walk;
1470    tr_list * ranges = NULL;
1471    tr_bool success = TRUE;
1472
1473    walk = str;
1474    while( walk && *walk && success ) {
1475        struct number_range range;
1476        const char * pch = strchr( walk, ',' );
1477        if( pch ) {
1478            success = parseNumberSection( walk, pch-walk, &range );
1479            walk = pch + 1;
1480        } else {
1481            success = parseNumberSection( walk, strlen( walk ), &range );
1482            walk += strlen( walk );
1483        }
1484        if( success )
1485            tr_list_append( &ranges, tr_memdup( &range, sizeof( struct number_range ) ) );
1486    }
1487
1488    if( !success )
1489    {
1490        *setmeCount = 0;
1491        uniq = NULL;
1492    }
1493    else
1494    {
1495        int i;
1496        int n2;
1497        tr_list * l;
1498        int * sorted = NULL;
1499
1500        /* build a sorted number array */
1501        n = n2 = 0;
1502        for( l=ranges; l!=NULL; l=l->next ) {
1503            const struct number_range * r = l->data;
1504            n += r->high + 1 - r->low;
1505        }
1506        sorted = tr_new( int, n );
1507        for( l=ranges; l!=NULL; l=l->next ) {
1508            const struct number_range * r = l->data;
1509            int i;
1510            for( i=r->low; i<=r->high; ++i )
1511                sorted[n2++] = i;
1512        }
1513        qsort( sorted, n, sizeof( int ), compareInt );
1514        assert( n == n2 );
1515
1516        /* remove duplicates */
1517        uniq = tr_new( int, n );
1518        for( i=n=0; i<n2; ++i )
1519            if( !n || uniq[n-1] != sorted[i] )
1520                uniq[n++] = sorted[i];
1521
1522        tr_free( sorted );
1523    }
1524
1525    /* cleanup */
1526    tr_list_free( &ranges, tr_free );
1527    tr_free( str );
1528
1529    /* return the result */
1530    *setmeCount = n;
1531    return uniq;
1532}
1533
1534/***
1535****
1536***/
1537
1538static void
1539printf_double_without_rounding( char * buf, int buflen, double d, int places )
1540{
1541    char * pch;
1542    char tmp[128];
1543    int len;
1544    tr_snprintf( tmp, sizeof( tmp ), "%'.64f", d );
1545    pch = tmp;
1546    while( isdigit( *pch ) ) ++pch; /* walk to the decimal point */
1547    ++pch; /* walk over the decimal point */
1548    pch += places;
1549    len = MIN( buflen - 1, pch - tmp );
1550    memcpy( buf, tmp, len );
1551    buf[len] = '\0';
1552}
1553
1554char*
1555tr_strratio( char * buf, size_t buflen, double ratio, const char * infinity )
1556{
1557    if( (int)ratio == TR_RATIO_NA )
1558        tr_strlcpy( buf, _( "None" ), buflen );
1559    else if( (int)ratio == TR_RATIO_INF )
1560        tr_strlcpy( buf, infinity, buflen );
1561    else if( ratio < 10.0 )
1562        printf_double_without_rounding( buf, buflen, ratio, 2 );
1563    else if( ratio < 100.0 )
1564        printf_double_without_rounding( buf, buflen, ratio, 1 );
1565    else
1566        tr_snprintf( buf, buflen, "%'.0f", ratio );
1567    return buf;
1568}
Note: See TracBrowser for help on using the repository browser.