source: trunk/libtransmission/utils.c @ 8308

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

(trunk libT) silently add a \0 after the end of files read by tr_loadFile() so that text files can be handled directly as ascii strings

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