source: trunk/libtransmission/utils.c @ 2149

Last change on this file since 2149 was 2149, checked in by livings124, 15 years ago

Merge file selection and torrent creation into the main branch.

The new code for these features is under a new license.

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