source: trunk/libtransmission/utils.c @ 8350

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

(trunk libT) clean up the debugging messages added to smoke out #2030

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