source: trunk/libtransmission/utils.c @ 3425

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

new utility (tr_loadFile), and reimplement metainfo's "readtorrent" to use it.

  • Property svn:keywords set to Date Rev Author Id
File size: 23.3 KB
Line 
1/******************************************************************************
2 * $Id: utils.c 3425 2007-10-15 20:15:34Z 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 <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      * messageLock = NULL;
53static int            messageLevel = 0;
54static int            messageQueuing = FALSE;
55static tr_msg_list *  messageQueue = NULL;
56static tr_msg_list ** messageQueueTail = &messageQueue;
57
58void tr_msgInit( void )
59{
60    if( !messageLock )
61         messageLock = tr_lockNew( );
62}
63
64FILE*
65tr_getLog( void )
66{
67    static int initialized = FALSE;
68    static FILE * file= NULL;
69
70    if( !initialized )
71    {
72        const char * str = getenv( "TR_DEBUG_FD" );
73        int fd;
74        if( str && *str )
75            fd = atoi( str );
76        switch( fd ) {
77            case 1: file = stdout; break;
78            case 2: file = stderr; break;
79            default: file = NULL; break;
80        }
81        initialized = TRUE;
82    }
83
84    return file;
85}
86
87char*
88tr_getLogTimeStr( char * buf, int buflen )
89{
90    char tmp[64];
91    time_t now;
92    struct tm now_tm;
93    struct timeval tv;
94    int milliseconds;
95
96    now = time( NULL );
97    gettimeofday( &tv, NULL );
98
99    localtime_r( &now, &now_tm );
100    strftime( tmp, sizeof(tmp), "%H:%M:%S", &now_tm );
101    milliseconds = (int)(tv.tv_usec / 1000);
102    snprintf( buf, buflen, "%s.%03d", tmp, milliseconds );
103
104    return buf;
105}
106
107void
108tr_setMessageLevel( int level )
109{
110    tr_msgInit();
111    tr_lockLock( messageLock );
112    messageLevel = MAX( 0, level );
113    tr_lockUnlock( messageLock );
114}
115
116int tr_getMessageLevel( void )
117{
118    int ret;
119
120    tr_msgInit();
121    tr_lockLock( messageLock );
122    ret = messageLevel;
123    tr_lockUnlock( messageLock );
124
125    return ret;
126}
127
128void tr_setMessageQueuing( int enabled )
129{
130    tr_msgInit();
131    tr_lockLock( messageLock );
132    messageQueuing = enabled;
133    tr_lockUnlock( messageLock );
134}
135
136tr_msg_list * tr_getQueuedMessages( void )
137{
138    tr_msg_list * ret;
139
140    assert( NULL != messageLock );
141    tr_lockLock( messageLock );
142    ret = messageQueue;
143    messageQueue = NULL;
144    messageQueueTail = &messageQueue;
145    tr_lockUnlock( messageLock );
146
147    return ret;
148}
149
150void tr_freeMessageList( tr_msg_list * list )
151{
152    tr_msg_list * next;
153
154    while( NULL != list )
155    {
156        next = list->next;
157        free( list->message );
158        free( list );
159        list = next;
160    }
161}
162
163void tr_msg( int level, char * msg, ... )
164{
165    va_list       args1, args2;
166    tr_msg_list * newmsg;
167    int           len1, len2;
168    FILE        * fp;
169
170    assert( NULL != messageLock );
171    tr_lockLock( messageLock );
172
173    fp = tr_getLog( );
174
175    if( !messageLevel )
176    {
177        char * env;
178        env          = getenv( "TR_DEBUG" );
179        messageLevel = ( env ? atoi( env ) : 0 ) + 1;
180        messageLevel = MAX( 1, messageLevel );
181    }
182
183    if( messageLevel >= level )
184    {
185        va_start( args1, msg );
186        if( messageQueuing )
187        {
188            newmsg = calloc( 1, sizeof( *newmsg ) );
189            if( NULL != newmsg )
190            {
191                newmsg->level = level;
192                newmsg->when = time( NULL );
193                len1 = len2 = 0;
194                va_start( args2, msg );
195                tr_vsprintf( &newmsg->message, &len1, &len2, msg,
196                             args1, args2 );
197                va_end( args2 );
198                if( fp != NULL )
199                    fprintf( fp, "%s\n", newmsg->message );
200                if( NULL == newmsg->message )
201                {
202                    free( newmsg );
203                }
204                else
205                {
206                    *messageQueueTail = newmsg;
207                    messageQueueTail = &newmsg->next;
208                }
209            }
210        }
211        else
212        {
213            if( fp == NULL )
214                fp = stderr;
215            vfprintf( fp, msg, args1 );
216            fputc( '\n', fp );
217            fflush( fp );
218        }
219        va_end( args1 );
220    }
221
222    tr_lockUnlock( messageLock );
223}
224
225int tr_rand( int sup )
226{
227    static int init = 0;
228
229    assert( sup > 0 );
230
231    if( !init )
232    {
233        srand( tr_date() );
234        init = 1;
235    }
236    return rand() % sup;
237}
238
239/***
240****
241***/
242
243void
244tr_set_compare( const void * va, size_t aCount,
245                const void * vb, size_t bCount,
246                int compare( const void * a, const void * b ),
247                size_t elementSize,
248                tr_set_func in_a_cb,
249                tr_set_func in_b_cb,
250                tr_set_func in_both_cb,
251                void * userData )
252{
253    const uint8_t * a = (const uint8_t *) va;
254    const uint8_t * b = (const uint8_t *) vb;
255    const uint8_t * aend = a + elementSize*aCount;
256    const uint8_t * bend = b + elementSize*bCount;
257
258    while( a!=aend || b!=bend )
259    {
260        if( a==aend )
261        {
262            (*in_b_cb)( (void*)b, userData );
263            b += elementSize;
264        }
265        else if ( b==bend )
266        {
267            (*in_a_cb)( (void*)a, userData );
268            a += elementSize;
269        }
270        else
271        {
272            const int val = (*compare)( a, b );
273
274            if( !val )
275            {
276                (*in_both_cb)( (void*)a, userData );
277                a += elementSize;
278                b += elementSize;
279            }
280            else if( val < 0 )
281            {
282                (*in_a_cb)( (void*)a, userData );
283                a += elementSize;
284            }
285            else if( val > 0 )
286            {
287                (*in_b_cb)( (void*)b, userData );
288                b += elementSize;
289            }
290        }
291    }
292}
293
294/***
295****
296***/
297
298
299#if 0
300void*
301tr_memmem( const void* haystack, size_t hl,
302           const void* needle,   size_t nl)
303{
304    const char *walk, *end;
305
306    if( !nl )
307        return (void*) haystack;
308
309    if( hl < nl )
310        return NULL;
311
312    for (walk=(const char*)haystack, end=walk+hl-nl; walk!=end; ++walk)
313        if( !memcmp( walk, needle, nl ) )
314            return (void*) walk;
315
316    return NULL;
317}
318#else
319void * tr_memmem ( const void *vbig, size_t big_len,
320                   const void *vlittle, size_t little_len )
321{
322    const char *big = vbig;
323    const char *little = vlittle;
324    size_t ii, jj;
325
326    if( 0 == big_len || 0 == little_len )
327    {
328        return NULL;
329    }
330
331    for( ii = 0; ii + little_len <= big_len; ii++ )
332    {
333        for( jj = 0; jj < little_len; jj++ )
334        {
335            if( big[ii + jj] != little[jj] )
336            {
337                break;
338            }
339        }
340        if( jj == little_len )
341        {
342            return (char*)big + ii;
343        }
344    }
345
346    return NULL;
347}
348#endif
349
350/**
351***
352**/
353
354int
355tr_compareUint8 (  uint8_t a,  uint8_t b )
356{
357    if( a < b ) return -1;
358    if( a > b ) return 1;
359    return 0;
360}
361
362int
363tr_compareUint16( uint16_t a, uint16_t b )
364{
365    if( a < b ) return -1;
366    if( a > b ) return 1;
367    return 0;
368}
369
370int
371tr_compareUint32( uint32_t a, uint32_t b )
372{
373    if( a < b ) return -1;
374    if( a > b ) return 1;
375    return 0;
376}
377
378int
379tr_compareUint64( uint64_t a, uint64_t b )
380{
381    if( a < b ) return -1;
382    if( a > b ) return 1;
383    return 0;
384}
385
386/**
387***
388**/
389
390struct timeval
391timevalSec ( int seconds )
392{
393    struct timeval ret;
394    ret.tv_sec = seconds;
395    ret.tv_usec = 0;
396    return ret;
397}
398
399struct timeval
400timevalMsec ( int milliseconds )
401{
402    struct timeval ret;
403    const unsigned long microseconds = milliseconds * 1000;
404    ret.tv_sec  = microseconds / 1000000;
405    ret.tv_usec = microseconds % 1000000;
406    return ret;
407}
408
409uint8_t *
410tr_loadFile( const char * path, size_t * size )
411{
412    uint8_t    * buf;
413    struct stat  sb;
414    FILE       * file;
415
416    /* try to stat the file */
417    errno = 0;
418    if( stat( path, &sb ) )
419    {
420        tr_err( "Couldn't get information for file \"%s\" %s", path, strerror(errno) );
421        return NULL;
422    }
423
424    if( ( sb.st_mode & S_IFMT ) != S_IFREG )
425    {
426        tr_err( "Not a regular file (%s)", path );
427        return NULL;
428    }
429
430    /* Load the torrent file into our buffer */
431    file = fopen( path, "rb" );
432    if( !file )
433    {
434        tr_err( "Couldn't open file \"%s\" %s", path, strerror(errno) );
435        return NULL;
436    }
437    buf = malloc( sb.st_size );
438    if( NULL == buf )
439    {
440        tr_err( "Couldn't allocate memory (%"PRIu64" bytes)",
441                ( uint64_t )sb.st_size );
442        fclose( file );
443    }
444    fseek( file, 0, SEEK_SET );
445    if( fread( buf, sb.st_size, 1, file ) != 1 )
446    {
447        tr_err( "Error reading \"%s\" %s", path, strerror(errno) );
448        free( buf );
449        fclose( file );
450        return NULL;
451    }
452    fclose( file );
453
454    *size = sb.st_size;
455
456    return buf;
457}
458
459int
460tr_mkdir( const char * path, int permissions
461#ifdef WIN32
462                                             UNUSED
463#endif
464                                                    )
465{
466#ifdef WIN32
467    return mkdir( path );
468#else
469    return mkdir( path, permissions );
470#endif
471}
472
473int
474tr_mkdirp( char * path, int permissions )
475{
476    char      * p, * pp;
477    struct stat sb;
478    int done;
479
480    p = path;
481    while( '/' == *p )
482      p++;
483    pp = p;
484    done = 0;
485    while( ( p = strchr( pp, '/' ) ) || ( p = strchr( pp, '\0' ) ) )
486    {
487        if( '\0' == *p)
488        {
489            done = 1;
490        }
491        else
492        {
493            *p = '\0';
494        }
495        if( stat( path, &sb ) )
496        {
497            /* Folder doesn't exist yet */
498            if( tr_mkdir( path, permissions ) )
499            {
500                tr_err( "Could not create directory %s (%s)", path,
501                        strerror( errno ) );
502                *p = '/';
503                return 1;
504            }
505        }
506        else if( ( sb.st_mode & S_IFMT ) != S_IFDIR )
507        {
508            /* Node exists but isn't a folder */
509            tr_err( "Remove %s, it's in the way.", path );
510            *p = '/';
511            return 1;
512        }
513        if( done )
514        {
515            break;
516        }
517        *p = '/';
518        p++;
519        pp = p;
520    }
521
522    return 0;
523}
524
525int
526tr_strncasecmp( const char * s1, const char * s2, size_t n )
527{
528    if ( !n )
529        return 0;
530
531    while( n-- != 0 && tolower( *s1 ) == tolower( *s2 ) ) {
532        if( !n || !*s1 || !*s2 )
533            break;
534        ++s1;
535        ++s2;
536    }
537
538    return tolower(*(unsigned char *) s1) - tolower(*(unsigned char *) s2);
539}
540
541int tr_sprintf( char ** buf, int * used, int * max, const char * format, ... )
542{
543    va_list ap1, ap2;
544    int     ret;
545
546    va_start( ap1, format );
547    va_start( ap2, format );
548    ret = tr_vsprintf( buf, used, max, format, ap1, ap2 );
549    va_end( ap2 );
550    va_end( ap1 );
551
552    return ret;
553}
554
555int tr_vsprintf( char ** buf, int * used, int * max, const char * fmt,
556                 va_list ap1, va_list ap2 )
557{
558    int     want;
559
560    want = vsnprintf( NULL, 0, fmt, ap1 );
561
562    if( tr_concat( buf, used, max, NULL, want ) )
563    {
564        return 1;
565    }
566    assert( *used + want + 1 <= *max );
567
568    *used += vsnprintf( *buf + *used, *max - *used, fmt, ap2 );
569
570    return 0;
571}
572
573#ifndef HAVE_ASPRINTF
574
575int
576asprintf( char ** buf, const char * format, ... )
577{
578    va_list ap;
579    int     ret;
580
581    va_start( ap, format );
582    ret = vasprintf( buf, format, ap );
583    va_end( ap );
584
585    return ret;
586}
587
588int
589vasprintf( char ** buf, const char * format, va_list ap )
590{
591    va_list ap2;
592    int     used, max;
593
594    va_copy( ap2, ap );
595
596    *buf = NULL;
597    used = 0;
598    max  = 0;
599
600    if( tr_vsprintf( buf, &used, &max, format, ap, ap2 ) )
601    {
602        free( *buf );
603        return -1;
604    }
605
606    return used;
607}
608
609#endif /* HAVE_ASPRINTF */
610
611int tr_concat( char ** buf, int * used, int * max, const char * data, int len )
612{
613    int     newmax;
614    char  * newbuf;
615
616    newmax = *max;
617    while( *used + len + 1 > newmax )
618    {
619        newmax += SPRINTF_BUFSIZE;
620    }
621    if( newmax > *max )
622    {
623        newbuf = realloc( *buf, newmax );
624        if( NULL == newbuf )
625        {
626            return 1;
627        }
628        *buf = newbuf;
629        *max = newmax;
630    }
631
632    if( NULL != data )
633    {
634        memcpy( *buf + *used, data, len );
635        *used += len;
636    }
637
638    return 0;
639}
640
641void
642tr_buildPath ( char *buf, size_t buflen, const char *first_element, ... )
643{
644    va_list vl;
645    char* walk = buf;
646    const char * element = first_element;
647
648    if( first_element == NULL )
649        return;
650
651    va_start( vl, first_element );
652    for( ;; ) {
653        const size_t n = strlen( element );
654        memcpy( walk, element, n );
655        walk += n;
656        element = (const char*) va_arg( vl, const char* );
657        if( element == NULL )
658            break;
659        *walk++ = TR_PATH_DELIMITER;
660    }
661    *walk = '\0';
662    assert( walk-buf <= (int)buflen );
663}
664
665int
666tr_ioErrorFromErrno( void )
667{
668    switch( errno )
669    {
670        case EACCES:
671        case EROFS:
672            return TR_ERROR_IO_PERMISSIONS;
673        case ENOSPC:
674            return TR_ERROR_IO_SPACE;
675        case EMFILE:
676            return TR_ERROR_IO_OPEN_FILES;
677        case EFBIG:
678            return TR_ERROR_IO_FILE_TOO_BIG;
679        default:
680            tr_dbg( "generic i/o errno from errno: %s", strerror( errno ) );
681            return TR_ERROR_IO_OTHER;
682    }
683}
684
685char *
686tr_errorString( int code )
687{
688    switch( code )
689    {
690        case TR_OK:
691            return "No error";
692        case TR_ERROR:
693            return "Generic error";
694        case TR_ERROR_ASSERT:
695            return "Assert error";
696        case TR_ERROR_IO_PARENT:
697            return "Download folder does not exist";
698        case TR_ERROR_IO_PERMISSIONS:
699            return "Insufficient permissions";
700        case TR_ERROR_IO_SPACE:
701            return "Insufficient free space";
702        case TR_ERROR_IO_DUP_DOWNLOAD:
703            return "Already active transfer with same name and download folder";
704        case TR_ERROR_IO_FILE_TOO_BIG:
705            return "File too large";
706        case TR_ERROR_IO_OPEN_FILES:
707            return "Too many open files";
708        case TR_ERROR_IO_OTHER:
709            return "Generic I/O error";
710    }
711    return "Unknown error";
712}
713
714/****
715*****
716****/
717
718char*
719tr_strdup( const char * in )
720{
721    return tr_strndup( in, in ? strlen(in) : 0 );
722}
723
724char*
725tr_strndup( const char * in, int len )
726{
727    char * out = NULL;
728
729    if( in != NULL )
730    {
731        out = tr_malloc( len+1 );
732        memcpy( out, in, len );
733        out[len] = '\0';
734    }
735    return out;
736}
737
738void*
739tr_calloc( size_t nmemb, size_t size )
740{
741    return nmemb && size ? calloc( nmemb, size ) : NULL;
742}
743
744void*
745tr_malloc( size_t size )
746{
747    return size ? malloc( size ) : NULL;
748}
749
750void*
751tr_malloc0( size_t size )
752{
753    void * ret = tr_malloc( size );
754    memset( ret, 0, size );
755    return ret;
756}
757
758void
759tr_free( void * p )
760{
761    if( p )
762        free( p );
763}
764
765/****
766*****
767****/
768
769/* note that the argument is how many bits are needed, not bytes */
770tr_bitfield*
771tr_bitfieldNew( size_t bitcount )
772{
773    tr_bitfield * ret = calloc( 1, sizeof(tr_bitfield) );
774    if( NULL == ret )
775        return NULL;
776
777    ret->len = (bitcount+7u) / 8u;
778    ret->bits = calloc( ret->len, 1 );
779    if( NULL == ret->bits ) {
780        free( ret );
781        return NULL;
782    }
783
784    return ret;
785}
786
787tr_bitfield*
788tr_bitfieldDup( const tr_bitfield * in )
789{
790    tr_bitfield * ret = calloc( 1, sizeof(tr_bitfield) );
791    ret->len = in->len;
792    ret->bits = malloc( ret->len );
793    memcpy( ret->bits, in->bits, ret->len );
794    return ret;
795}
796
797void tr_bitfieldFree( tr_bitfield * bitfield )
798{
799    if( bitfield )
800    {
801        free( bitfield->bits );
802        free( bitfield );
803    }
804}
805
806void
807tr_bitfieldClear( tr_bitfield * bitfield )
808{
809    memset( bitfield->bits, 0, bitfield->len );
810}
811
812int
813tr_bitfieldIsEmpty( const tr_bitfield * bitfield )
814{
815    unsigned int i;
816
817    for( i=0; i<bitfield->len; ++i )
818        if( bitfield->bits[i] )
819            return 0;
820
821    return 1;
822}
823
824int
825tr_bitfieldHas( const tr_bitfield * bitfield, size_t nth )
826{
827    static const uint8_t ands[8] = { 128, 64, 32, 16, 8, 4, 2, 1 };
828    return bitfield!=NULL && (bitfield->bits[nth>>3u] & ands[nth&7u] );
829}
830
831void
832tr_bitfieldAdd( tr_bitfield  * bitfield, size_t nth )
833{
834    static const uint8_t ands[8] = { 128, 64, 32, 16, 8, 4, 2, 1 };
835    bitfield->bits[nth>>3u] |= ands[nth&7u];
836}
837
838void
839tr_bitfieldAddRange( tr_bitfield  * bitfield,
840                     size_t         begin,
841                     size_t         end )
842{
843    /* TODO: there are faster ways to do this */
844    unsigned int i;
845    for( i=begin; i<end; ++i )
846        tr_bitfieldAdd( bitfield, i );
847}
848
849void
850tr_bitfieldRem( tr_bitfield   * bitfield,
851                size_t          nth )
852{
853    static const uint8_t rems[8] = { 127, 191, 223, 239, 247, 251, 253, 254 };
854
855    if( bitfield != NULL )
856        bitfield->bits[nth>>3u] &= rems[nth&7u];
857}
858
859void
860tr_bitfieldRemRange ( tr_bitfield  * b,
861                      size_t         begin,
862                      size_t         end )
863{
864    /* TODO: there are faster ways to do this */
865    unsigned int i;
866    for( i=begin; i<end; ++i )
867        tr_bitfieldRem( b, i );
868}
869
870tr_bitfield*
871tr_bitfieldNegate( tr_bitfield * b )
872{
873    uint8_t *it;
874    const uint8_t *end;
875
876    for( it=b->bits, end=it+b->len; it!=end; ++it )
877        *it = ~*it;
878
879    return b;
880}
881
882tr_bitfield*
883tr_bitfieldAnd( tr_bitfield * a, const tr_bitfield * b )
884{
885    uint8_t *ait;
886    const uint8_t *aend, *bit;
887
888    assert( a->len == b->len );
889
890    for( ait=a->bits, bit=b->bits, aend=ait+a->len; ait!=aend; ++ait, ++bit )
891        *ait &= *bit;
892
893    return a;
894}
895
896size_t
897tr_bitfieldCountTrueBits( const tr_bitfield* b )
898{
899    size_t ret = 0;
900    const uint8_t *it, *end;
901    static const int trueBitCount[512] = {
902        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,
903        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,
904        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,
905        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,
906        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,
907        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,
908        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,
909        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,
910        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,
911        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,
912        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,
913        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,
914        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,
915        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,
916        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,
917        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
918    };
919
920    if( !b )
921        return 0;
922
923    for( it=b->bits, end=it+b->len; it!=end; ++it )
924        ret += trueBitCount[*it];
925
926    return ret;
927}
928
929/***
930****
931***/
932
933uint64_t
934tr_date( void )
935{
936    struct timeval tv;
937    gettimeofday( &tv, NULL );
938    return (uint64_t) tv.tv_sec * 1000 + ( tv.tv_usec / 1000 );
939}
940
941void
942tr_wait( uint64_t delay_milliseconds )
943{
944#ifdef __BEOS__
945    snooze( 1000 * delay_milliseconds );
946#elif defined(WIN32)
947    Sleep( (DWORD)delay_milliseconds );
948#else
949    usleep( 1000 * delay_milliseconds );
950#endif
951}
952
953#define WANTBYTES( want, got ) \
954    if( (want) > (got) ) { return; } else { (got) -= (want); }
955void
956strlcat_utf8( void * dest, const void * src, size_t len, char skip )
957{
958    char       * s      = dest;
959    const char * append = src;
960    const char * p;
961
962    /* don't overwrite the nul at the end */
963    len--;
964
965    /* Go to the end of the destination string */
966    while( s[0] )
967    {
968        s++;
969        len--;
970    }
971
972    /* Now start appending, converting on the fly if necessary */
973    for( p = append; p[0]; )
974    {
975        /* skip over the requested character */
976        if( skip == p[0] )
977        {
978            p++;
979            continue;
980        }
981
982        if( !( p[0] & 0x80 ) )
983        {
984            /* ASCII character */
985            WANTBYTES( 1, len );
986            *(s++) = *(p++);
987            continue;
988        }
989
990        if( ( p[0] & 0xE0 ) == 0xC0 && ( p[1] & 0xC0 ) == 0x80 )
991        {
992            /* 2-bytes UTF-8 character */
993            WANTBYTES( 2, len );
994            *(s++) = *(p++); *(s++) = *(p++);
995            continue;
996        }
997
998        if( ( p[0] & 0xF0 ) == 0xE0 && ( p[1] & 0xC0 ) == 0x80 &&
999            ( p[2] & 0xC0 ) == 0x80 )
1000        {
1001            /* 3-bytes UTF-8 character */
1002            WANTBYTES( 3, len );
1003            *(s++) = *(p++); *(s++) = *(p++);
1004            *(s++) = *(p++);
1005            continue;
1006        }
1007
1008        if( ( p[0] & 0xF8 ) == 0xF0 && ( p[1] & 0xC0 ) == 0x80 &&
1009            ( p[2] & 0xC0 ) == 0x80 && ( p[3] & 0xC0 ) == 0x80 )
1010        {
1011            /* 4-bytes UTF-8 character */
1012            WANTBYTES( 4, len );
1013            *(s++) = *(p++); *(s++) = *(p++);
1014            *(s++) = *(p++); *(s++) = *(p++);
1015            continue;
1016        }
1017
1018        /* ISO 8859-1 -> UTF-8 conversion */
1019        WANTBYTES( 2, len );
1020        *(s++) = 0xC0 | ( ( *p & 0xFF ) >> 6 );
1021        *(s++) = 0x80 | ( *(p++) & 0x3F );
1022    }
1023}
1024
1025size_t
1026bufsize_utf8( const void * vstr, int * changed )
1027{
1028    const char * str = vstr;
1029    size_t       ii, grow;
1030
1031    if( NULL != changed )
1032        *changed = 0;
1033
1034    ii   = 0;
1035    grow = 1;
1036    while( '\0' != str[ii] )
1037    {
1038        if( !( str[ii] & 0x80 ) )
1039            /* ASCII character */
1040            ii++;
1041        else if( ( str[ii]   & 0xE0 ) == 0xC0 && ( str[ii+1] & 0xC0 ) == 0x80 )
1042            /* 2-bytes UTF-8 character */
1043            ii += 2;
1044        else if( ( str[ii]   & 0xF0 ) == 0xE0 && ( str[ii+1] & 0xC0 ) == 0x80 &&
1045                 ( str[ii+2] & 0xC0 ) == 0x80 )
1046            /* 3-bytes UTF-8 character */
1047            ii += 3;
1048        else if( ( str[ii]   & 0xF8 ) == 0xF0 && ( str[ii+1] & 0xC0 ) == 0x80 &&
1049                 ( str[ii+2] & 0xC0 ) == 0x80 && ( str[ii+3] & 0xC0 ) == 0x80 )
1050            /* 4-bytes UTF-8 character */
1051            ii += 4;
1052        else
1053        {
1054            /* ISO 8859-1 -> UTF-8 conversion */
1055            ii++;
1056            grow++;
1057            if( NULL != changed )
1058                *changed = 1;
1059        }
1060    }
1061
1062    return ii + grow;
1063}
Note: See TracBrowser for help on using the repository browser.