source: trunk/libtransmission/utils.c @ 5221

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

lots more i18n string work -- making strings more consistent, folding redundant strings together, etc.

  • Property svn:keywords set to Date Rev Author Id
File size: 20.7 KB
Line 
1/******************************************************************************
2 * $Id: utils.c 5221 2008-03-07 20:48:36Z 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 read 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( _( "Couldn't read file \"%s\": %s" ), path, _( "Not a regular file" ) );
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 read 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\": %s" ), path, _( "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            char buf[MAX_PATH_LENGTH];
457            snprintf( buf, sizeof( buf ), _( "File \"%s\" is in the way" ), path );
458            tr_err( _( "Couldn't create \"%s\": %s" ), path_in, buf );
459            tr_free( path );
460            errno = ENOTDIR;
461            return -1;
462        }
463
464        if( done )
465            break;
466
467        *p = TR_PATH_DELIMITER;
468        p++;
469        pp = p;
470    }
471
472    tr_free( path );
473    return 0;
474}
475
476void
477tr_buildPath ( char *buf, size_t buflen, const char *first_element, ... )
478{
479    struct evbuffer * evbuf = evbuffer_new( );
480    const char * element = first_element;
481    va_list vl;
482    va_start( vl, first_element );
483    while( element ) {
484        if( EVBUFFER_LENGTH(evbuf) )
485            evbuffer_add_printf( evbuf, "%c", TR_PATH_DELIMITER );
486        evbuffer_add_printf( evbuf, "%s", element );
487        element = (const char*) va_arg( vl, const char* );
488    }
489    if( EVBUFFER_LENGTH(evbuf) )
490        strlcpy( buf, (char*)EVBUFFER_DATA(evbuf), buflen );
491    else
492        *buf = '\0';
493    evbuffer_free( evbuf );
494}
495
496int
497tr_ioErrorFromErrno( int err )
498{
499    switch( err )
500    {
501        case 0:
502            return TR_OK;
503        case EACCES:
504        case EROFS:
505            return TR_ERROR_IO_PERMISSIONS;
506        case ENOSPC:
507            return TR_ERROR_IO_SPACE;
508        case EMFILE:
509            return TR_ERROR_IO_OPEN_FILES;
510        case EFBIG:
511            return TR_ERROR_IO_FILE_TOO_BIG;
512        default:
513            tr_dbg( "generic i/o errno from errno: %s", tr_strerror( errno ) );
514            return TR_ERROR_IO_OTHER;
515    }
516}
517
518const char *
519tr_errorString( int code )
520{
521    switch( code )
522    {
523        case TR_OK:
524            return _( "No error" );
525
526        case TR_ERROR:
527            return _( "Generic error" );
528        case TR_ERROR_ASSERT:
529            return _( "Assert error" );
530
531        case TR_ERROR_IO_PARENT:
532            return _( "Download directory doesn't exist" );
533        case TR_ERROR_IO_PERMISSIONS:
534            return tr_strerror( EACCES );
535        case TR_ERROR_IO_SPACE:
536            return tr_strerror( ENOSPC );
537        case TR_ERROR_IO_FILE_TOO_BIG:
538            return tr_strerror( EFBIG );
539        case TR_ERROR_IO_OPEN_FILES:
540            return tr_strerror( EMFILE );
541        case TR_ERROR_IO_DUP_DOWNLOAD:
542            return _( "Already active transfer with same name and download folder" );
543        case TR_ERROR_IO_OTHER:
544            return _( "Generic I/O error" );
545
546        case TR_ERROR_TC_ERROR:
547            return _( "Tracker error" );
548        case TR_ERROR_TC_WARNING:
549            return _( "Tracker warning" );
550
551        case TR_ERROR_PEER_MESSAGE:
552            return _( "Peer sent a bad message" );
553
554        default:
555            return _( "Unknown error" );
556    }
557}
558
559/****
560*****
561****/
562
563char*
564tr_strdup( const char * in )
565{
566    return tr_strndup( in, in ? strlen(in) : 0 );
567}
568
569char*
570tr_strndup( const char * in, int len )
571{
572    char * out = NULL;
573
574    if( len < 0 )
575    {
576        out = tr_strdup( in );
577    }
578    else if( in != NULL )
579    {
580        out = tr_malloc( len+1 );
581        memcpy( out, in, len );
582        out[len] = '\0';
583    }
584    return out;
585}
586
587void*
588tr_calloc( size_t nmemb, size_t size )
589{
590    return nmemb && size ? calloc( nmemb, size ) : NULL;
591}
592
593void*
594tr_malloc( size_t size )
595{
596    return size ? malloc( size ) : NULL;
597}
598
599void*
600tr_malloc0( size_t size )
601{
602    void * ret = tr_malloc( size );
603    memset( ret, 0, size );
604    return ret;
605}
606
607void
608tr_free( void * p )
609{
610    if( p )
611        free( p );
612}
613
614const char*
615tr_strerror( int i )
616{
617    const char * ret = strerror( i );
618    if( ret == NULL )
619        ret = "Unknown Error";
620    return ret;
621}
622
623/****
624*****
625****/
626
627/* note that the argument is how many bits are needed, not bytes */
628tr_bitfield*
629tr_bitfieldNew( size_t bitcount )
630{
631    tr_bitfield * ret = calloc( 1, sizeof(tr_bitfield) );
632    if( NULL == ret )
633        return NULL;
634
635    ret->len = (bitcount+7u) / 8u;
636    ret->bits = calloc( ret->len, 1 );
637    if( NULL == ret->bits ) {
638        free( ret );
639        return NULL;
640    }
641
642    return ret;
643}
644
645tr_bitfield*
646tr_bitfieldDup( const tr_bitfield * in )
647{
648    tr_bitfield * ret = calloc( 1, sizeof(tr_bitfield) );
649    ret->len = in->len;
650    ret->bits = malloc( ret->len );
651    memcpy( ret->bits, in->bits, ret->len );
652    return ret;
653}
654
655void tr_bitfieldFree( tr_bitfield * bitfield )
656{
657    if( bitfield )
658    {
659        free( bitfield->bits );
660        free( bitfield );
661    }
662}
663
664void
665tr_bitfieldClear( tr_bitfield * bitfield )
666{
667    memset( bitfield->bits, 0, bitfield->len );
668}
669
670int
671tr_bitfieldIsEmpty( const tr_bitfield * bitfield )
672{
673    size_t i;
674
675    for( i=0; i<bitfield->len; ++i )
676        if( bitfield->bits[i] )
677            return 0;
678
679    return 1;
680}
681
682int
683tr_bitfieldHas( const tr_bitfield * bitfield, size_t nth )
684{
685    static const uint8_t ands[8] = { 128, 64, 32, 16, 8, 4, 2, 1 };
686    const size_t i = nth >> 3u;
687    return ( bitfield != NULL )
688        && ( bitfield->bits != NULL )
689        && ( i < bitfield->len )
690        && ( ( bitfield->bits[i] & ands[nth&7u] ) != 0 );
691}
692
693int
694tr_bitfieldAdd( tr_bitfield  * bitfield, size_t nth )
695{
696    static const uint8_t ands[8] = { 128, 64, 32, 16, 8, 4, 2, 1 };
697    const size_t i = nth >> 3u;
698
699    assert( bitfield != NULL );
700    assert( bitfield->bits != NULL );
701
702    if( i >= bitfield->len )
703        return -1;
704
705    bitfield->bits[i] |= ands[nth&7u];
706    assert( tr_bitfieldHas( bitfield, nth ) );
707    return 0;
708}
709
710int
711tr_bitfieldAddRange( tr_bitfield  * bitfield,
712                     size_t         begin,
713                     size_t         end )
714{
715    int err = 0;
716    size_t i;
717    for( i=begin; i<end; ++i )
718        if(( err = tr_bitfieldAdd( bitfield, i )))
719            break;
720    return err;
721}
722
723int
724tr_bitfieldRem( tr_bitfield   * bitfield,
725                size_t          nth )
726{
727    static const uint8_t rems[8] = { 127, 191, 223, 239, 247, 251, 253, 254 };
728    const size_t i = nth >> 3u;
729
730    assert( bitfield != NULL );
731    assert( bitfield->bits != NULL );
732
733    if( i >= bitfield->len )
734        return -1;
735
736    bitfield->bits[i] &= rems[nth&7u];
737    assert( !tr_bitfieldHas( bitfield, nth ) );
738    return 0;
739}
740
741int
742tr_bitfieldRemRange ( tr_bitfield  * b,
743                      size_t         begin,
744                      size_t         end )
745{
746    int err = 0;
747    size_t i;
748    for( i=begin; i<end; ++i )
749        if(( err = tr_bitfieldRem( b, i )))
750            break;
751    return err;
752}
753
754tr_bitfield*
755tr_bitfieldOr( tr_bitfield * a, const tr_bitfield * b )
756{
757    uint8_t *ait;
758    const uint8_t *aend, *bit;
759
760    assert( a->len == b->len );
761
762    for( ait=a->bits, bit=b->bits, aend=ait+a->len; ait!=aend; )
763        *ait++ |= *bit++;
764
765    return a;
766}
767
768size_t
769tr_bitfieldCountTrueBits( const tr_bitfield* b )
770{
771    size_t ret = 0;
772    const uint8_t *it, *end;
773    static const int trueBitCount[512] = {
774        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,
775        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,
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        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,
779        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,
780        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,
781        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,
782        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,
783        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,
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        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,
787        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,
788        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,
789        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
790    };
791
792    if( !b )
793        return 0;
794
795    for( it=b->bits, end=it+b->len; it!=end; ++it )
796        ret += trueBitCount[*it];
797
798    return ret;
799}
800
801/***
802****
803***/
804
805uint64_t
806tr_date( void )
807{
808    struct timeval tv;
809    gettimeofday( &tv, NULL );
810    return (uint64_t) tv.tv_sec * 1000 + ( tv.tv_usec / 1000 );
811}
812
813void
814tr_wait( uint64_t delay_milliseconds )
815{
816#ifdef __BEOS__
817    snooze( 1000 * delay_milliseconds );
818#elif defined(WIN32)
819    Sleep( (DWORD)delay_milliseconds );
820#else
821    usleep( 1000 * delay_milliseconds );
822#endif
823}
824
825/***
826****
827***/
828
829
830#ifndef HAVE_STRLCPY
831
832/*
833 * Copy src to string dst of size siz.  At most siz-1 characters
834 * will be copied.  Always NUL terminates (unless siz == 0).
835 * Returns strlen(src); if retval >= siz, truncation occurred.
836 */
837size_t
838strlcpy(char *dst, const char *src, size_t siz)
839{
840        char *d = dst;
841        const char *s = src;
842        size_t n = siz;
843
844        assert( s != NULL );
845        assert( d != NULL );
846
847        /* Copy as many bytes as will fit */
848        if (n != 0) {
849                while (--n != 0) {
850                        if ((*d++ = *s++) == '\0')
851                                break;
852                }
853        }
854
855        /* Not enough room in dst, add NUL and traverse rest of src */
856        if (n == 0) {
857                if (siz != 0)
858                        *d = '\0';              /* NUL-terminate dst */
859                while (*s++)
860                        ;
861        }
862
863        return(s - src - 1);    /* count does not include NUL */
864}
865
866#endif /* HAVE_STRLCPY */
867
868
869#ifndef HAVE_STRLCAT
870
871/*
872 * Appends src to string dst of size siz (unlike strncat, siz is the
873 * full size of dst, not space left).  At most siz-1 characters
874 * will be copied.  Always NUL terminates (unless siz <= strlen(dst)).
875 * Returns strlen(src) + MIN(siz, strlen(initial dst)).
876 * If retval >= siz, truncation occurred.
877 */
878size_t
879strlcat(char *dst, const char *src, size_t siz)
880{
881        char *d = dst;
882        const char *s = src;
883        size_t n = siz;
884        size_t dlen;
885
886        /* Find the end of dst and adjust bytes left but don't go past end */
887        while (n-- != 0 && *d != '\0')
888                d++;
889        dlen = d - dst;
890        n = siz - dlen;
891
892        if (n == 0)
893                return(dlen + strlen(s));
894        while (*s != '\0') {
895                if (n != 1) {
896                        *d++ = *s;
897                        n--;
898                }
899                s++;
900        }
901        *d = '\0';
902
903        return(dlen + (s - src));       /* count does not include NUL */
904}
905
906#endif /* HAVE_STRLCAT */
907
908/***
909****
910***/
911
912double
913tr_getRatio( double numerator, double denominator )
914{
915    double ratio;
916
917    if( denominator )
918        ratio = numerator / denominator;
919    else if( numerator )
920        ratio = TR_RATIO_INF;
921    else
922        ratio = TR_RATIO_NA;
923
924    return ratio;
925}
926
927void
928tr_sha1_to_hex( char * out, const uint8_t * sha1 )
929{
930    static const char hex[] = "0123456789abcdef";
931    int i;
932    for (i = 0; i < 20; i++) {
933        unsigned int val = *sha1++;
934        *out++ = hex[val >> 4];
935        *out++ = hex[val & 0xf];
936    }
937    *out = '\0';
938}
Note: See TracBrowser for help on using the repository browser.