source: branches/1.5x/libtransmission/utils.c @ 7855

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

(1.5x libT) backport #1671, #1798

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