source: trunk/libtransmission/utils.c @ 5838

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

add tr_strdup_printf()

  • Property svn:keywords set to Date Rev Author Id
File size: 22.7 KB
Line 
1/******************************************************************************
2 * $Id: utils.c 5838 2008-05-15 15:44:51Z charles $
3 *
4 * Copyright (c) 2005-2008 Transmission authors and contributors
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the "Software"),
8 * to deal in the Software without restriction, including without limitation
9 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 * and/or sell copies of the Software, and to permit persons to whom the
11 * Software is furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22 * DEALINGS IN THE SOFTWARE.
23 *****************************************************************************/
24
25#include <assert.h>
26#include <ctype.h> /* isalpha */
27#include <errno.h>
28#include <stdarg.h>
29#include <stdio.h>
30#include <stdlib.h>
31#include <string.h> /* strerror */
32
33#include <libgen.h> /* basename */
34#include <sys/time.h>
35#include <sys/types.h>
36#include <sys/stat.h>
37#include <unistd.h> /* usleep, stat */
38
39#include "event.h"
40
41#ifdef WIN32
42    #include <windows.h> /* for Sleep */
43#elif defined(__BEOS__)
44    #include <kernel/OS.h>
45#endif
46
47#include "transmission.h"
48#include "trcompat.h"
49#include "utils.h"
50#include "platform.h"
51
52static tr_lock      * messageLock = NULL;
53static int            messageLevel = 0;
54static int            messageQueuing = FALSE;
55static tr_msg_list *  messageQueue = NULL;
56static tr_msg_list ** messageQueueTail = &messageQueue;
57
58void tr_msgInit( void )
59{
60    if( !messageLock )
61         messageLock = tr_lockNew( );
62}
63
64FILE*
65tr_getLog( void )
66{
67    static int initialized = FALSE;
68    static FILE * file= NULL;
69
70    if( !initialized )
71    {
72        const char * str = getenv( "TR_DEBUG_FD" );
73        int fd = 0;
74        if( str && *str )
75            fd = atoi( str );
76        switch( fd ) {
77            case 1: file = stdout; break;
78            case 2: file = stderr; break;
79            default: file = NULL; break;
80        }
81        initialized = TRUE;
82    }
83
84    return file;
85}
86
87void
88tr_setMessageLevel( int level )
89{
90    tr_msgInit();
91    tr_lockLock( messageLock );
92    messageLevel = MAX( 0, level );
93    tr_lockUnlock( messageLock );
94}
95
96int
97tr_getMessageLevel( void )
98{
99    int ret;
100
101    tr_msgInit();
102    tr_lockLock( messageLock );
103    ret = messageLevel;
104    tr_lockUnlock( messageLock );
105
106    return ret;
107}
108
109void
110tr_setMessageQueuing( int enabled )
111{
112    tr_msgInit();
113    tr_lockLock( messageLock );
114    messageQueuing = enabled;
115    tr_lockUnlock( messageLock );
116}
117
118tr_msg_list *
119tr_getQueuedMessages( void )
120{
121    tr_msg_list * ret;
122
123    assert( NULL != messageLock );
124    tr_lockLock( messageLock );
125    ret = messageQueue;
126    messageQueue = NULL;
127    messageQueueTail = &messageQueue;
128    tr_lockUnlock( messageLock );
129
130    return ret;
131}
132
133void
134tr_freeMessageList( tr_msg_list * list )
135{
136    tr_msg_list * next;
137
138    while( NULL != list )
139    {
140        next = list->next;
141        free( list->message );
142        free( list->name );
143        free( list );
144        list = next;
145    }
146}
147
148/**
149***
150**/
151
152char*
153tr_getLogTimeStr( char * buf, int buflen )
154{
155    char tmp[64];
156    time_t now;
157    struct tm now_tm;
158    struct timeval tv;
159    int milliseconds;
160
161    now = time( NULL );
162    gettimeofday( &tv, NULL );
163
164#ifdef WIN32
165    now_tm = *localtime( &now );
166#else
167    localtime_r( &now, &now_tm );
168#endif
169    strftime( tmp, sizeof(tmp), "%H:%M:%S", &now_tm );
170    milliseconds = (int)(tv.tv_usec / 1000);
171    snprintf( buf, buflen, "%s.%03d", tmp, milliseconds );
172
173    return buf;
174}
175
176void
177tr_deepLog( const char * file, int line, const char * name, const char * fmt, ... )
178{
179    FILE * fp = tr_getLog( );
180    if( fp != NULL )
181    {
182        va_list args;
183        char timestr[64];
184        struct evbuffer * buf = evbuffer_new( );
185        char * myfile = tr_strdup( file );
186
187        evbuffer_add_printf( buf, "[%s] ", tr_getLogTimeStr( timestr, sizeof(timestr) ) );
188        if( name )
189            evbuffer_add_printf( buf, "%s ", name );
190        va_start( args, fmt );
191        evbuffer_add_vprintf( buf, fmt, args );
192        va_end( args );
193        evbuffer_add_printf( buf, " (%s:%d)\n", basename(myfile), line );
194        fwrite( EVBUFFER_DATA(buf), 1, EVBUFFER_LENGTH(buf), fp );
195
196        tr_free( myfile );
197        evbuffer_free( buf );
198    }
199}
200
201/***
202****
203***/
204
205void
206tr_msg( const char * file, int line, int level,
207        const char * name,
208        const char * fmt, ... )
209{
210    FILE * fp;
211
212    if( messageLock )
213        tr_lockLock( messageLock );
214
215    fp = tr_getLog( );
216
217    if( !messageLevel )
218    {
219        char * env = getenv( "TR_DEBUG" );
220        messageLevel = ( env ? atoi( env ) : 0 ) + 1;
221        messageLevel = MAX( 1, messageLevel );
222    }
223
224    if( messageLevel >= level )
225    {
226        va_list ap;
227        struct evbuffer * buf = evbuffer_new( );
228
229        /* build the text message */
230        va_start( ap, fmt );
231        evbuffer_add_vprintf( buf, fmt, ap );
232        va_end( ap );
233
234        if( EVBUFFER_LENGTH( buf ) )
235        {
236            if( messageQueuing )
237            {
238                tr_msg_list * newmsg;
239                newmsg = tr_new0( tr_msg_list, 1 );
240                newmsg->level = level;
241                newmsg->when = time( NULL );
242                newmsg->message = tr_strdup( (char*)EVBUFFER_DATA( buf ) );
243                newmsg->file = file;
244                newmsg->line = line;
245                newmsg->name = tr_strdup( name );
246
247                *messageQueueTail = newmsg;
248                messageQueueTail = &newmsg->next;
249            }
250            else
251            {
252                if( fp == NULL )
253                    fp = stderr;
254                fprintf( fp, "%s\n", (char*)EVBUFFER_DATA(buf) );
255                fflush( fp );
256            }
257
258            evbuffer_free( buf );
259        }
260    }
261
262    if( messageLock )
263        tr_lockUnlock( messageLock );
264}
265
266int tr_rand( int sup )
267{
268    static int init = 0;
269
270    assert( sup > 0 );
271
272    if( !init )
273    {
274        srand( tr_date() );
275        init = 1;
276    }
277    return rand() % sup;
278}
279
280/***
281****
282***/
283
284void
285tr_set_compare( const void * va, size_t aCount,
286                const void * vb, size_t bCount,
287                int compare( const void * a, const void * b ),
288                size_t elementSize,
289                tr_set_func in_a_cb,
290                tr_set_func in_b_cb,
291                tr_set_func in_both_cb,
292                void * userData )
293{
294    const uint8_t * a = (const uint8_t *) va;
295    const uint8_t * b = (const uint8_t *) vb;
296    const uint8_t * aend = a + elementSize*aCount;
297    const uint8_t * bend = b + elementSize*bCount;
298
299    while( a!=aend || b!=bend )
300    {
301        if( a==aend )
302        {
303            (*in_b_cb)( (void*)b, userData );
304            b += elementSize;
305        }
306        else if ( b==bend )
307        {
308            (*in_a_cb)( (void*)a, userData );
309            a += elementSize;
310        }
311        else
312        {
313            const int val = (*compare)( a, b );
314
315            if( !val )
316            {
317                (*in_both_cb)( (void*)a, userData );
318                a += elementSize;
319                b += elementSize;
320            }
321            else if( val < 0 )
322            {
323                (*in_a_cb)( (void*)a, userData );
324                a += elementSize;
325            }
326            else if( val > 0 )
327            {
328                (*in_b_cb)( (void*)b, userData );
329                b += elementSize;
330            }
331        }
332    }
333}
334
335/***
336****
337***/
338
339int
340tr_compareUint16( uint16_t a, uint16_t b )
341{
342    if( a < b ) return -1;
343    if( a > b ) return 1;
344    return 0;
345}
346
347int
348tr_compareUint32( uint32_t a, uint32_t b )
349{
350    if( a < b ) return -1;
351    if( a > b ) return 1;
352    return 0;
353}
354
355/**
356***
357**/
358
359struct timeval
360tr_timevalMsec( uint64_t milliseconds )
361{
362    struct timeval ret;
363    const uint64_t microseconds = milliseconds * 1000;
364    ret.tv_sec  = microseconds / 1000000;
365    ret.tv_usec = microseconds % 1000000;
366    return ret;
367}
368
369uint8_t *
370tr_loadFile( const char * path, size_t * size )
371{
372    uint8_t    * buf;
373    struct stat  sb;
374    FILE       * file;
375    const char * err_fmt = _( "Couldn't read \"%1$s\": %2$s" );
376
377    /* try to stat the file */
378    errno = 0;
379    if( stat( path, &sb ) )
380    {
381        tr_dbg( err_fmt, path, tr_strerror(errno) );
382        return NULL;
383    }
384
385    if( ( sb.st_mode & S_IFMT ) != S_IFREG )
386    {
387        tr_err( err_fmt, path, _( "Not a regular file" ) );
388        return NULL;
389    }
390
391    /* Load the torrent file into our buffer */
392    file = fopen( path, "rb" );
393    if( !file )
394    {
395        tr_err( err_fmt, path, tr_strerror(errno) );
396        return NULL;
397    }
398    buf = malloc( sb.st_size );
399    if( NULL == buf )
400    {
401        tr_err( err_fmt, path, _( "Memory allocation failed" ) );
402        fclose( file );
403        return NULL;
404    }
405    fseek( file, 0, SEEK_SET );
406    if( fread( buf, sb.st_size, 1, file ) != 1 )
407    {
408        tr_err( err_fmt, path, tr_strerror(errno) );
409        free( buf );
410        fclose( file );
411        return NULL;
412    }
413    fclose( file );
414
415    *size = sb.st_size;
416
417    return buf;
418}
419
420int
421tr_mkdir( const char * path, int permissions
422#ifdef WIN32
423                                             UNUSED
424#endif
425                                                    )
426{
427#ifdef WIN32
428    if( path && isalpha(path[0]) && path[1]==':' && !path[2] )
429        return 0;
430    return mkdir( path );
431#else
432    return mkdir( path, permissions );
433#endif
434}
435
436int
437tr_mkdirp( const char * path_in, int permissions )
438{
439    char * path = tr_strdup( path_in );
440    char * p, * pp;
441    struct stat sb;
442    int done;
443
444    /* walk past the root */
445    p = path;
446    while( *p == TR_PATH_DELIMITER )
447        ++p;
448
449    pp = p;
450    done = 0;
451    while( ( p = strchr( pp, TR_PATH_DELIMITER ) ) || ( p = strchr( pp, '\0' ) ) )
452    {
453        if( !*p )
454            done = 1;
455        else
456            *p = '\0';
457
458        if( stat( path, &sb ) )
459        {
460            /* Folder doesn't exist yet */
461            if( tr_mkdir( path, permissions ) ) {
462                const int err = errno;
463                tr_err( _( "Couldn't create \"%1$s\": %2$s" ), path, tr_strerror( err ) );
464                tr_free( path );
465                errno = err;
466                return -1;
467            }
468        }
469        else if( ( sb.st_mode & S_IFMT ) != S_IFDIR )
470        {
471            /* Node exists but isn't a folder */
472            char buf[MAX_PATH_LENGTH];
473            snprintf( buf, sizeof( buf ), _( "File \"%s\" is in the way" ), path );
474            tr_err( _( "Couldn't create \"%1$s\": %2$s" ), path_in, buf );
475            tr_free( path );
476            errno = ENOTDIR;
477            return -1;
478        }
479
480        if( done )
481            break;
482
483        *p = TR_PATH_DELIMITER;
484        p++;
485        pp = p;
486    }
487
488    tr_free( path );
489    return 0;
490}
491
492void
493tr_buildPath ( char *buf, size_t buflen, const char *first_element, ... )
494{
495    struct evbuffer * evbuf = evbuffer_new( );
496    const char * element = first_element;
497    va_list vl;
498    va_start( vl, first_element );
499    while( element ) {
500        if( EVBUFFER_LENGTH(evbuf) )
501            evbuffer_add_printf( evbuf, "%c", TR_PATH_DELIMITER );
502        evbuffer_add_printf( evbuf, "%s", element );
503        element = (const char*) va_arg( vl, const char* );
504    }
505    if( EVBUFFER_LENGTH(evbuf) )
506        strlcpy( buf, (char*)EVBUFFER_DATA(evbuf), buflen );
507    else
508        *buf = '\0';
509    evbuffer_free( evbuf );
510}
511
512int
513tr_ioErrorFromErrno( int err )
514{
515    switch( err )
516    {
517        case 0:
518            return TR_OK;
519        case EACCES:
520        case EROFS:
521            return TR_ERROR_IO_PERMISSIONS;
522        case ENOSPC:
523            return TR_ERROR_IO_SPACE;
524        case EMFILE:
525            return TR_ERROR_IO_OPEN_FILES;
526        case EFBIG:
527            return TR_ERROR_IO_FILE_TOO_BIG;
528        default:
529            tr_dbg( "generic i/o errno from errno: %s", tr_strerror( errno ) );
530            return TR_ERROR_IO_OTHER;
531    }
532}
533
534const char *
535tr_errorString( int code )
536{
537    switch( code )
538    {
539        case TR_OK:
540            return _( "No error" );
541
542        case TR_ERROR:
543            return _( "Unspecified error" );
544        case TR_ERROR_ASSERT:
545            return _( "Assert error" );
546
547        case TR_ERROR_IO_PARENT:
548            return _( "Destination folder doesn't exist" );
549        case TR_ERROR_IO_PERMISSIONS:
550            return tr_strerror( EACCES );
551        case TR_ERROR_IO_SPACE:
552            return tr_strerror( ENOSPC );
553        case TR_ERROR_IO_FILE_TOO_BIG:
554            return tr_strerror( EFBIG );
555        case TR_ERROR_IO_OPEN_FILES:
556            return tr_strerror( EMFILE );
557        case TR_ERROR_IO_DUP_DOWNLOAD:
558            return _( "A torrent with this name and destination folder already exists." );
559        case TR_ERROR_IO_CHECKSUM:
560            return _( "Checksum failed" );
561        case TR_ERROR_IO_OTHER:
562            return _( "Unspecified I/O error" );
563
564        case TR_ERROR_TC_ERROR:
565            return _( "Tracker error" );
566        case TR_ERROR_TC_WARNING:
567            return _( "Tracker warning" );
568
569        case TR_ERROR_PEER_MESSAGE:
570            return _( "Peer sent a bad message" );
571
572        default:
573            return _( "Unknown error" );
574    }
575}
576
577/****
578*****
579****/
580
581char*
582tr_strdup( const char * in )
583{
584    return tr_strndup( in, in ? strlen(in) : 0 );
585}
586
587char*
588tr_strndup( const char * in, int len )
589{
590    char * out = NULL;
591
592    if( len < 0 )
593    {
594        out = tr_strdup( in );
595    }
596    else if( in != NULL )
597    {
598        out = tr_malloc( len+1 );
599        memcpy( out, in, len );
600        out[len] = '\0';
601    }
602    return out;
603}
604
605char*
606tr_strdup_printf( const char * fmt, ... )
607{
608    char * ret = NULL;
609    struct evbuffer * buf;
610    va_list ap;
611
612    buf = evbuffer_new( );
613    va_start( ap, fmt );
614    if( evbuffer_add_vprintf( buf, fmt, ap ) != -1 )
615        ret = tr_strdup( (char*)EVBUFFER_DATA( buf ) );
616    evbuffer_free( buf );
617
618    return ret;
619}
620
621void*
622tr_calloc( size_t nmemb, size_t size )
623{
624    return nmemb && size ? calloc( nmemb, size ) : NULL;
625}
626
627void*
628tr_malloc( size_t size )
629{
630    return size ? malloc( size ) : NULL;
631}
632
633void*
634tr_malloc0( size_t size )
635{
636    void * ret = tr_malloc( size );
637    memset( ret, 0, size );
638    return ret;
639}
640
641void
642tr_free( void * p )
643{
644    if( p )
645        free( p );
646}
647
648const char*
649tr_strerror( int i )
650{
651    const char * ret = strerror( i );
652    if( ret == NULL )
653        ret = "Unknown Error";
654    return ret;
655}
656
657/****
658*****
659****/
660
661/* note that the argument is how many bits are needed, not bytes */
662tr_bitfield*
663tr_bitfieldNew( size_t bitcount )
664{
665    tr_bitfield * ret = calloc( 1, sizeof(tr_bitfield) );
666    if( NULL == ret )
667        return NULL;
668
669    ret->len = (bitcount+7u) / 8u;
670    ret->bits = calloc( ret->len, 1 );
671    if( NULL == ret->bits ) {
672        free( ret );
673        return NULL;
674    }
675
676    return ret;
677}
678
679tr_bitfield*
680tr_bitfieldDup( const tr_bitfield * in )
681{
682    tr_bitfield * ret = calloc( 1, sizeof(tr_bitfield) );
683    ret->len = in->len;
684    ret->bits = malloc( ret->len );
685    memcpy( ret->bits, in->bits, ret->len );
686    return ret;
687}
688
689void tr_bitfieldFree( tr_bitfield * bitfield )
690{
691    if( bitfield )
692    {
693        free( bitfield->bits );
694        free( bitfield );
695    }
696}
697
698void
699tr_bitfieldClear( tr_bitfield * bitfield )
700{
701    memset( bitfield->bits, 0, bitfield->len );
702}
703
704int
705tr_bitfieldIsEmpty( const tr_bitfield * bitfield )
706{
707    size_t i;
708
709    for( i=0; i<bitfield->len; ++i )
710        if( bitfield->bits[i] )
711            return 0;
712
713    return 1;
714}
715
716int
717tr_bitfieldHas( const tr_bitfield * bitfield, size_t nth )
718{
719    static const uint8_t ands[8] = { 128, 64, 32, 16, 8, 4, 2, 1 };
720    const size_t i = nth >> 3u;
721    return ( bitfield != NULL )
722        && ( bitfield->bits != NULL )
723        && ( i < bitfield->len )
724        && ( ( bitfield->bits[i] & ands[nth&7u] ) != 0 );
725}
726
727int
728tr_bitfieldAdd( tr_bitfield  * bitfield, size_t nth )
729{
730    static const uint8_t ands[8] = { 128, 64, 32, 16, 8, 4, 2, 1 };
731    const size_t i = nth >> 3u;
732
733    assert( bitfield != NULL );
734    assert( bitfield->bits != NULL );
735
736    if( i >= bitfield->len )
737        return -1;
738
739    bitfield->bits[i] |= ands[nth&7u];
740    assert( tr_bitfieldHas( bitfield, nth ) );
741    return 0;
742}
743
744int
745tr_bitfieldAddRange( tr_bitfield  * bitfield,
746                     size_t         begin,
747                     size_t         end )
748{
749    int err = 0;
750    size_t i;
751    for( i=begin; i<end; ++i )
752        if(( err = tr_bitfieldAdd( bitfield, i )))
753            break;
754    return err;
755}
756
757int
758tr_bitfieldRem( tr_bitfield   * bitfield,
759                size_t          nth )
760{
761    static const uint8_t rems[8] = { 127, 191, 223, 239, 247, 251, 253, 254 };
762    const size_t i = nth >> 3u;
763
764    assert( bitfield != NULL );
765    assert( bitfield->bits != NULL );
766
767    if( i >= bitfield->len )
768        return -1;
769
770    bitfield->bits[i] &= rems[nth&7u];
771    assert( !tr_bitfieldHas( bitfield, nth ) );
772    return 0;
773}
774
775int
776tr_bitfieldRemRange ( tr_bitfield  * b,
777                      size_t         begin,
778                      size_t         end )
779{
780    int err = 0;
781    size_t i;
782    for( i=begin; i<end; ++i )
783        if(( err = tr_bitfieldRem( b, i )))
784            break;
785    return err;
786}
787
788tr_bitfield*
789tr_bitfieldOr( tr_bitfield * a, const tr_bitfield * b )
790{
791    uint8_t *ait;
792    const uint8_t *aend, *bit;
793
794    assert( a->len == b->len );
795
796    for( ait=a->bits, bit=b->bits, aend=ait+a->len; ait!=aend; )
797        *ait++ |= *bit++;
798
799    return a;
800}
801
802/* set 'a' to all the flags that were in 'a' but not 'b' */
803void
804tr_bitfieldDifference( tr_bitfield * a, const tr_bitfield * b )
805{
806    uint8_t *ait;
807    const uint8_t *aend, *bit;
808
809    assert( a->len == b->len );
810
811    for( ait=a->bits, bit=b->bits, aend=ait+a->len; ait!=aend; )
812        *ait++ &= ~(*bit++);
813}
814
815
816size_t
817tr_bitfieldCountTrueBits( const tr_bitfield* b )
818{
819    size_t ret = 0;
820    const uint8_t *it, *end;
821    static const int trueBitCount[512] = {
822        0,1,1,2,1,2,2,3,1,2,2,3,2,3,3,4,1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,
823        1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,
824        1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,
825        2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,
826        1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,
827        2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,
828        2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,
829        3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,
830        1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,
831        2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,
832        2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,
833        3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,
834        2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,
835        3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,
836        3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,
837        4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9
838    };
839
840    if( !b )
841        return 0;
842
843    for( it=b->bits, end=it+b->len; it!=end; ++it )
844        ret += trueBitCount[*it];
845
846    return ret;
847}
848
849/***
850****
851***/
852
853uint64_t
854tr_date( void )
855{
856    struct timeval tv;
857    gettimeofday( &tv, NULL );
858    return (uint64_t) tv.tv_sec * 1000 + ( tv.tv_usec / 1000 );
859}
860
861void
862tr_wait( uint64_t delay_milliseconds )
863{
864#ifdef __BEOS__
865    snooze( 1000 * delay_milliseconds );
866#elif defined(WIN32)
867    Sleep( (DWORD)delay_milliseconds );
868#else
869    usleep( 1000 * delay_milliseconds );
870#endif
871}
872
873/***
874****
875***/
876
877
878#ifndef HAVE_STRLCPY
879
880/*
881 * Copy src to string dst of size siz.  At most siz-1 characters
882 * will be copied.  Always NUL terminates (unless siz == 0).
883 * Returns strlen(src); if retval >= siz, truncation occurred.
884 */
885size_t
886strlcpy(char *dst, const char *src, size_t siz)
887{
888        char *d = dst;
889        const char *s = src;
890        size_t n = siz;
891
892        assert( s != NULL );
893        assert( d != NULL );
894
895        /* Copy as many bytes as will fit */
896        if (n != 0) {
897                while (--n != 0) {
898                        if ((*d++ = *s++) == '\0')
899                                break;
900                }
901        }
902
903        /* Not enough room in dst, add NUL and traverse rest of src */
904        if (n == 0) {
905                if (siz != 0)
906                        *d = '\0';              /* NUL-terminate dst */
907                while (*s++)
908                        ;
909        }
910
911        return(s - src - 1);    /* count does not include NUL */
912}
913
914#endif /* HAVE_STRLCPY */
915
916/***
917****
918***/
919
920double
921tr_getRatio( double numerator, double denominator )
922{
923    double ratio;
924
925    if( denominator )
926        ratio = numerator / denominator;
927    else if( numerator )
928        ratio = TR_RATIO_INF;
929    else
930        ratio = TR_RATIO_NA;
931
932    return ratio;
933}
934
935void
936tr_sha1_to_hex( char * out, const uint8_t * sha1 )
937{
938    static const char hex[] = "0123456789abcdef";
939    int i;
940    for (i = 0; i < 20; i++) {
941        unsigned int val = *sha1++;
942        *out++ = hex[val >> 4];
943        *out++ = hex[val & 0xf];
944    }
945    *out = '\0';
946}
947
948/***
949****
950***/
951
952int
953tr_httpIsValidURL( const char * url )
954{
955    return !tr_httpParseURL( url, -1, NULL, NULL, NULL );
956}
957
958int
959tr_httpParseURL( const char * url_in, int len,
960                 char ** setme_host,
961                 int * setme_port,
962                 char ** setme_path )
963{
964    int err;
965    int port = 0;
966    int n;
967    char * tmp;
968    char * pch;
969    const char * protocol = NULL;
970    const char * host = NULL;
971    const char * path = NULL;
972
973    tmp = tr_strndup( url_in, len );
974    if(( pch = strstr( tmp, "://" )))
975    {
976       *pch = '\0';
977       protocol = tmp;
978       pch += 3;
979/*fprintf( stderr, "protocol is [%s]... what's left is [%s]\n", protocol, pch );*/
980       if(( n = strcspn( pch, ":/" )))
981       {
982           const int havePort = pch[n] == ':';
983           host = pch;
984           pch += n;
985           *pch++ = '\0';
986/*fprintf( stderr, "host is [%s]... what's left is [%s]\n", host, pch );*/
987           if( havePort )
988           {
989               char * end;
990               port = strtol( pch, &end, 10 );
991               pch = end;
992/*fprintf( stderr, "port is [%d]... what's left is [%s]\n", port, pch );*/
993           }
994           path = pch;
995/*fprintf( stderr, "path is [%s]\n", path );*/
996       }
997    }
998
999    err = !host || !path || !protocol || ( strcmp(protocol,"http") && strcmp(protocol,"https") );
1000
1001    if( !err && !port ) {
1002        if( !strcmp(protocol,"http") ) port = 80;
1003        if( !strcmp(protocol,"https") ) port = 443;
1004    }
1005
1006    if( !err ) {
1007        if( setme_host) { ((char*)host)[-3]=':'; *setme_host = tr_strdup( protocol ); }
1008        if( setme_path) { ((char*)path)[-1]='/'; *setme_path = tr_strdup( path-1 ); }
1009        if( setme_port) *setme_port = port;
1010    }
1011
1012
1013    tr_free( tmp );
1014    return err;
1015}
Note: See TracBrowser for help on using the repository browser.