source: trunk/libtransmission/utils.c @ 2360

Last change on this file since 2360 was 2360, checked in by charles, 15 years ago

make tr_torrentStat() const.
malloc, rather than calloc, the buffer in strndup.

  • Property svn:keywords set to Date Rev Author Id
File size: 14.2 KB
Line 
1/******************************************************************************
2 * $Id: utils.c 2360 2007-07-15 19:12:54Z charles $
3 *
4 * Copyright (c) 2005-2007 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 <ctype.h>
26#include <stdarg.h>
27#include <sys/time.h>
28#include <sys/types.h>
29#include <sys/stat.h>
30#include <unistd.h> /* usleep, stat */
31#include "transmission.h"
32
33#define SPRINTF_BUFSIZE         100
34
35static tr_lock_t      * messageLock = NULL;
36static int              messageLevel = 0;
37static int              messageQueuing = 0;
38static tr_msg_list_t *  messageQueue = NULL;
39static tr_msg_list_t ** messageQueueTail = &messageQueue;
40
41void tr_msgInit( void )
42{
43    if( NULL == messageLock )
44    {
45        messageLock = calloc( 1, sizeof( *messageLock ) );
46        tr_lockInit( messageLock );
47    }
48}
49
50void tr_setMessageLevel( int level )
51{
52    tr_msgInit();
53    tr_lockLock( messageLock );
54    messageLevel = MAX( 0, level );
55    tr_lockUnlock( messageLock );
56}
57
58int tr_getMessageLevel( void )
59{
60    int ret;
61
62    tr_msgInit();
63    tr_lockLock( messageLock );
64    ret = messageLevel;
65    tr_lockUnlock( messageLock );
66
67    return ret;
68}
69
70void tr_setMessageQueuing( int enabled )
71{
72    tr_msgInit();
73    tr_lockLock( messageLock );
74    messageQueuing = enabled;
75    tr_lockUnlock( messageLock );
76}
77
78tr_msg_list_t * tr_getQueuedMessages( void )
79{
80    tr_msg_list_t * ret;
81
82    assert( NULL != messageLock );
83    tr_lockLock( messageLock );
84    ret = messageQueue;
85    messageQueue = NULL;
86    messageQueueTail = &messageQueue;
87    tr_lockUnlock( messageLock );
88
89    return ret;
90}
91
92void tr_freeMessageList( tr_msg_list_t * list )
93{
94    tr_msg_list_t * next;
95
96    while( NULL != list )
97    {
98        next = list->next;
99        free( list->message );
100        free( list );
101        list = next;
102    }
103}
104
105void tr_msg( int level, char * msg, ... )
106{
107    va_list         args1, args2;
108    tr_msg_list_t * newmsg;
109    int             len1, len2;
110
111    assert( NULL != messageLock );
112    tr_lockLock( messageLock );
113
114    if( !messageLevel )
115    {
116        char * env;
117        env          = getenv( "TR_DEBUG" );
118        messageLevel = ( env ? atoi( env ) : 0 ) + 1;
119        messageLevel = MAX( 1, messageLevel );
120    }
121
122    if( messageLevel >= level )
123    {
124        va_start( args1, msg );
125        if( messageQueuing )
126        {
127            newmsg = calloc( 1, sizeof( *newmsg ) );
128            if( NULL != newmsg )
129            {
130                newmsg->level = level;
131                newmsg->when = time( NULL );
132                len1 = len2 = 0;
133                va_start( args2, msg );
134                tr_vsprintf( &newmsg->message, &len1, &len2, msg,
135                             args1, args2 );
136                va_end( args2 );
137                if( NULL == newmsg->message )
138                {
139                    free( newmsg );
140                }
141                else
142                {
143                    *messageQueueTail = newmsg;
144                    messageQueueTail = &newmsg->next;
145                }
146            }
147        }
148        else
149        {
150            vfprintf( stderr, msg, args1 );
151            fputc( '\n', stderr );
152        }
153        va_end( args1 );
154    }
155
156    tr_lockUnlock( messageLock );
157}
158
159int tr_rand( int sup )
160{
161    static int init = 0;
162    if( !init )
163    {
164        srand( tr_date() );
165        init = 1;
166    }
167    return rand() % sup;
168}
169
170
171void*
172tr_memmem( const void* haystack, size_t hl,
173           const void* needle,   size_t nl)
174{
175    const char *walk, *end;
176
177    if( !nl )
178        return (void*) haystack;
179
180    if( hl < nl )
181        return NULL;
182
183    for (walk=(const char*)haystack, end=walk+hl-nl; walk!=end; ++walk)
184        if( !memcmp( walk, needle, nl ) )
185            return (void*) walk;
186
187    return NULL;
188}
189
190int tr_mkdir( char * path )
191{
192    char      * p, * pp;
193    struct stat sb;
194    int done;
195
196    p = path;
197    while( '/' == *p )
198      p++;
199    pp = p;
200    done = 0;
201    while( ( p = strchr( pp, '/' ) ) || ( p = strchr( pp, '\0' ) ) )
202    {
203        if( '\0' == *p)
204        {
205            done = 1;
206        }
207        else
208        {
209            *p = '\0';
210        }
211        if( stat( path, &sb ) )
212        {
213            /* Folder doesn't exist yet */
214            if( mkdir( path, 0777 ) )
215            {
216                tr_err( "Could not create directory %s (%s)", path,
217                        strerror( errno ) );
218                *p = '/';
219                return 1;
220            }
221        }
222        else if( ( sb.st_mode & S_IFMT ) != S_IFDIR )
223        {
224            /* Node exists but isn't a folder */
225            tr_err( "Remove %s, it's in the way.", path );
226            *p = '/';
227            return 1;
228        }
229        if( done )
230        {
231            break;
232        }
233        *p = '/';
234        p++;
235        pp = p;
236    }
237
238    return 0;
239}
240
241int
242tr_strncasecmp( const char * s1, const char * s2, size_t n )
243{
244    if ( !n )
245        return 0;
246
247    while( n-- != 0 && tolower( *s1 ) == tolower( *s2 ) ) {
248        if( !n || !*s1 || !*s2 )
249            break;
250        ++s1;
251        ++s2;
252    }
253
254    return tolower(*(unsigned char *) s1) - tolower(*(unsigned char *) s2);
255}
256
257int tr_sprintf( char ** buf, int * used, int * max, const char * format, ... )
258{
259    va_list ap1, ap2;
260    int     ret;
261
262    va_start( ap1, format );
263    va_start( ap2, format );
264    ret = tr_vsprintf( buf, used, max, format, ap1, ap2 );
265    va_end( ap2 );
266    va_end( ap1 );
267
268    return ret;
269}
270
271int tr_vsprintf( char ** buf, int * used, int * max, const char * fmt,
272                 va_list ap1, va_list ap2 )
273{
274    int     want;
275
276    want = vsnprintf( NULL, 0, fmt, ap1 );
277
278    if( tr_concat( buf, used, max, NULL, want ) )
279    {
280        return 1;
281    }
282    assert( *used + want + 1 <= *max );
283
284    *used += vsnprintf( *buf + *used, *max - *used, fmt, ap2 );
285
286    return 0;
287}
288
289int tr_concat( char ** buf, int * used, int * max, const char * data, int len )
290{
291    int     newmax;
292    char  * newbuf;
293
294    newmax = *max;
295    while( *used + len + 1 > newmax )
296    {
297        newmax += SPRINTF_BUFSIZE;
298    }
299    if( newmax > *max )
300    {
301        newbuf = realloc( *buf, newmax );
302        if( NULL == newbuf )
303        {
304            return 1;
305        }
306        *buf = newbuf;
307        *max = newmax;
308    }
309
310    if( NULL != data )
311    {
312        memcpy( *buf + *used, data, len );
313        *used += len;
314    }
315
316    return 0;
317}
318
319void
320tr_buildPath ( char *buf, size_t buflen, const char *first_element, ... )
321{
322    va_list vl;
323    char* walk = buf;
324    const char * element = first_element;
325    va_start( vl, first_element );
326    for( ;; ) {
327        const size_t n = strlen( element );
328        memcpy( walk, element, n );
329        walk += n;
330        element = (const char*) va_arg( vl, const char* );
331        if( element == NULL )
332            break;
333        *walk++ = TR_PATH_DELIMITER;
334    }
335    *walk = '\0';
336    assert( walk-buf <= (int)buflen );
337}
338
339int
340tr_ioErrorFromErrno( void )
341{
342    switch( errno )
343    {
344        case EACCES:
345        case EROFS:
346            return TR_ERROR_IO_PERMISSIONS;
347        case ENOSPC:
348            return TR_ERROR_IO_SPACE;
349        case EMFILE:
350            return TR_ERROR_IO_FILE_TOO_BIG;
351        case EFBIG:
352            return TR_ERROR_IO_OPEN_FILES;
353        default:
354            tr_dbg( "generic i/o errno from errno: %s", strerror( errno ) );
355            return TR_ERROR_IO_OTHER;
356    }
357}
358
359char *
360tr_errorString( int code )
361{
362    switch( code )
363    {
364        case TR_OK:
365            return "No error";
366        case TR_ERROR:
367            return "Generic error";
368        case TR_ERROR_ASSERT:
369            return "Assert error";
370        case TR_ERROR_IO_PARENT:
371            return "Download folder does not exist";
372        case TR_ERROR_IO_PERMISSIONS:
373            return "Insufficient permissions";
374        case TR_ERROR_IO_SPACE:
375            return "Insufficient free space";
376        case TR_ERROR_IO_DUP_DOWNLOAD:
377            return "Already active transfer with same name and download folder";
378        case TR_ERROR_IO_FILE_TOO_BIG:
379            return "File too large";
380        case TR_ERROR_IO_OPEN_FILES:
381            return "Too many open files";
382        case TR_ERROR_IO_OTHER:
383            return "Generic I/O error";
384    }
385    return "Unknown error";
386}
387
388/****
389*****
390****/
391
392char*
393tr_strdup( const char * in )
394{
395    return tr_strndup( in, in ? strlen(in) : 0 );
396}
397
398char*
399tr_strndup( const char * in, int len )
400{
401    char * out = NULL;
402
403    if( in != NULL )
404    {
405        out = tr_malloc( len+1 );
406        memcpy( out, in, len );
407        out[len] = '\0';
408    }
409    return out;
410}
411
412void*
413tr_calloc( size_t nmemb, size_t size )
414{
415    return nmemb && size ? calloc( nmemb, size ) : NULL;
416}
417
418void*
419tr_malloc( size_t size )
420{
421    return size ? malloc( size ) : NULL;
422}
423
424void*
425tr_malloc0( size_t size )
426{
427    void * ret = tr_malloc( size );
428    memset( ret, 0, size );
429    return ret;
430}
431
432void tr_free( void * p )
433{
434    if( p )
435        free( p );
436}
437
438/****
439*****
440****/
441
442/* note that the argument is how many bits are needed, not bytes */
443tr_bitfield_t*
444tr_bitfieldNew( size_t bitcount )
445{
446    tr_bitfield_t * ret = calloc( 1, sizeof(tr_bitfield_t) );
447    if( NULL == ret )
448        return NULL;
449
450    ret->len = ( bitcount + 7u ) / 8u;
451    ret->bits = calloc( ret->len, 1 );
452    if( NULL == ret->bits ) {
453        free( ret );
454        return NULL;
455    }
456
457    return ret;
458}
459
460tr_bitfield_t*
461tr_bitfieldDup( const tr_bitfield_t * in )
462{
463    tr_bitfield_t * ret = calloc( 1, sizeof(tr_bitfield_t) );
464    ret->len = in->len;
465    ret->bits = malloc( ret->len );
466    memcpy( ret->bits, in->bits, ret->len );
467    return ret;
468}
469
470void tr_bitfieldFree( tr_bitfield_t * bitfield )
471{
472    if( bitfield )
473    {
474        free( bitfield->bits );
475        free( bitfield );
476    }
477}
478
479void
480tr_bitfieldClear( tr_bitfield_t * bitfield )
481{
482    memset( bitfield->bits, 0, bitfield->len );
483}
484
485int
486tr_bitfieldIsEmpty( const tr_bitfield_t * bitfield )
487{
488    unsigned int i;
489
490    for( i=0; i<bitfield->len; ++i )
491        if( bitfield->bits[i] )
492            return 0;
493
494    return 1;
495}
496
497static const uint8_t bitmask[8] = { 128u, 64u, 32u, 16u, 8u, 4u, 2u, 1u };
498
499int
500tr_bitfieldHas( const tr_bitfield_t   * bitfield,
501                size_t                  bit )
502{
503    if ( bitfield == NULL ) return 0;
504    assert( bit / 8u < bitfield->len );
505    return ( bitfield->bits[ bit/8u ] & bitmask[bit%8] ) != 0;
506}
507
508void
509tr_bitfieldAdd( tr_bitfield_t  * bitfield, size_t bit )
510{
511    assert( bit / 8u < bitfield->len );
512    bitfield->bits[ bit/8u ] |= bitmask[bit%8];
513}
514
515void
516tr_bitfieldAddRange( tr_bitfield_t  * bitfield,
517                     size_t           begin,
518                     size_t           end )
519{
520    /* TODO: there are faster ways to do this */
521    unsigned int i;
522    for( i=begin; i<end; ++i )
523        tr_bitfieldAdd( bitfield, i );
524}
525
526void
527tr_bitfieldRem( tr_bitfield_t   * bitfield,
528                size_t            bit )
529{
530    if( bitfield != NULL )
531    {
532        assert( bit / 8u < bitfield->len );
533        bitfield->bits[bit/8u] &= ~bitmask[bit%8];
534    }
535}
536
537void
538tr_bitfieldRemRange ( tr_bitfield_t  * b,
539                      size_t           begin,
540                      size_t           end )
541{
542    /* TODO: there are faster ways to do this */
543    unsigned int i;
544    for( i=begin; i<end; ++i )
545        tr_bitfieldRem( b, i );
546}
547
548tr_bitfield_t*
549tr_bitfieldNegate( tr_bitfield_t * b )
550{
551    uint8_t *it;
552    const uint8_t *end;
553
554    for( it=b->bits, end=it+b->len; it!=end; ++it )
555        *it = ~*it;
556
557    return b;
558}
559
560tr_bitfield_t*
561tr_bitfieldAnd( tr_bitfield_t * a, const tr_bitfield_t * b )
562{
563    uint8_t *ait;
564    const uint8_t *aend, *bit;
565
566    assert( a->len == b->len );
567
568    for( ait=a->bits, bit=b->bits, aend=ait+a->len; ait!=aend; ++ait, ++bit )
569        *ait &= *bit;
570
571    return a;
572}
573
574size_t
575tr_bitfieldCountTrueBits( const tr_bitfield_t* b )
576{
577    size_t ret = 0;
578    const uint8_t *it, *end;
579    static const int trueBitCount[512] = {
580        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,
581        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,
582        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,
583        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,
584        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,
585        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,
586        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,
587        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,
588        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,
589        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,
590        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,
591        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,
592        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,
593        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,
594        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,
595        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
596    };
597
598    for( it=b->bits, end=it+b->len; it!=end; ++it )
599        ret += trueBitCount[*it];
600
601    return ret;
602}
603
604/***
605****
606***/
607
608uint64_t
609tr_date( void )
610{
611    struct timeval tv;
612    gettimeofday( &tv, NULL );
613    return (uint64_t) tv.tv_sec * 1000 + ( tv.tv_usec / 1000 );
614}
615
616void
617tr_wait( uint64_t delay_msec )
618{
619#ifdef SYS_BEOS
620    snooze( 1000 * delay_msec );
621#else
622    usleep( 1000 * delay_msec );
623#endif
624}
Note: See TracBrowser for help on using the repository browser.