source: trunk/libtransmission/utils.c @ 2614

Last change on this file since 2614 was 2614, checked in by joshe, 15 years ago

Use BEOS to test for beos instead of relying on the build to set SYS_BEOS.
Add missing headers and other miscellaneous fixes for beos.

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