source: trunk/libtransmission/utils.c @ 8017

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

(trunk) #1881: promote tr_strratio() to libtransmission, so that its code doesn't have to be repeated in all the clients

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