source: trunk/libtransmission/utils.c @ 8592

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

(trunk libT) add a bunch of comments denoting where the libevent 2.0 changes will go

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