source: trunk/libtransmission/utils.c @ 5193

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

first cut at adding i18n hooks into libtransmission.

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