source: trunk/libtransmission/utils.c @ 7748

Last change on this file since 7748 was 7748, checked in by charles, 14 years ago

(trunk libT) prefer int' over ssize_t'

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