source: trunk/libtransmission/utils.c @ 3473

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

dead code removal.

  • Property svn:keywords set to Date Rev Author Id
File size: 19.4 KB
Line 
1/******************************************************************************
2 * $Id: utils.c 3473 2007-10-20 15:17:36Z 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, const 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
298void * tr_memmem ( const void *vbig, size_t big_len,
299                   const void *vlittle, size_t little_len )
300{
301    const char *big = vbig;
302    const char *little = vlittle;
303    size_t ii, jj;
304
305    if( 0 == big_len || 0 == little_len )
306    {
307        return NULL;
308    }
309
310    for( ii = 0; ii + little_len <= big_len; ii++ )
311    {
312        for( jj = 0; jj < little_len; jj++ )
313        {
314            if( big[ii + jj] != little[jj] )
315            {
316                break;
317            }
318        }
319        if( jj == little_len )
320        {
321            return (char*)big + ii;
322        }
323    }
324
325    return NULL;
326}
327
328/**
329***
330**/
331
332int
333tr_compareUint16( uint16_t a, uint16_t b )
334{
335    if( a < b ) return -1;
336    if( a > b ) return 1;
337    return 0;
338}
339
340int
341tr_compareUint32( uint32_t a, uint32_t b )
342{
343    if( a < b ) return -1;
344    if( a > b ) return 1;
345    return 0;
346}
347
348/**
349***
350**/
351
352struct timeval
353timevalMsec( uint64_t milliseconds )
354{
355    struct timeval ret;
356    const uint64_t microseconds = milliseconds * 1000;
357    ret.tv_sec  = microseconds / 1000000;
358    ret.tv_usec = microseconds % 1000000;
359    return ret;
360}
361
362uint8_t *
363tr_loadFile( const char * path, size_t * size )
364{
365    uint8_t    * buf;
366    struct stat  sb;
367    FILE       * file;
368
369    /* try to stat the file */
370    errno = 0;
371    if( stat( path, &sb ) )
372    {
373        tr_err( "Couldn't get information for file \"%s\" %s", path, strerror(errno) );
374        return NULL;
375    }
376
377    if( ( sb.st_mode & S_IFMT ) != S_IFREG )
378    {
379        tr_err( "Not a regular file (%s)", path );
380        return NULL;
381    }
382
383    /* Load the torrent file into our buffer */
384    file = fopen( path, "rb" );
385    if( !file )
386    {
387        tr_err( "Couldn't open file \"%s\" %s", path, strerror(errno) );
388        return NULL;
389    }
390    buf = malloc( sb.st_size );
391    if( NULL == buf )
392    {
393        tr_err( "Couldn't allocate memory (%"PRIu64" bytes)",
394                ( uint64_t )sb.st_size );
395        fclose( file );
396    }
397    fseek( file, 0, SEEK_SET );
398    if( fread( buf, sb.st_size, 1, file ) != 1 )
399    {
400        tr_err( "Error reading \"%s\" %s", path, strerror(errno) );
401        free( buf );
402        fclose( file );
403        return NULL;
404    }
405    fclose( file );
406
407    *size = sb.st_size;
408
409    return buf;
410}
411
412int
413tr_mkdir( const char * path, int permissions
414#ifdef WIN32
415                                             UNUSED
416#endif
417                                                    )
418{
419#ifdef WIN32
420    return mkdir( path );
421#else
422    return mkdir( path, permissions );
423#endif
424}
425
426int
427tr_mkdirp( char * path, int permissions )
428{
429    char      * p, * pp;
430    struct stat sb;
431    int done;
432
433    p = path;
434    while( '/' == *p )
435      p++;
436    pp = p;
437    done = 0;
438    while( ( p = strchr( pp, '/' ) ) || ( p = strchr( pp, '\0' ) ) )
439    {
440        if( '\0' == *p)
441        {
442            done = 1;
443        }
444        else
445        {
446            *p = '\0';
447        }
448        if( stat( path, &sb ) )
449        {
450            /* Folder doesn't exist yet */
451            if( tr_mkdir( path, permissions ) )
452            {
453                tr_err( "Could not create directory %s (%s)", path,
454                        strerror( errno ) );
455                *p = '/';
456                return 1;
457            }
458        }
459        else if( ( sb.st_mode & S_IFMT ) != S_IFDIR )
460        {
461            /* Node exists but isn't a folder */
462            tr_err( "Remove %s, it's in the way.", path );
463            *p = '/';
464            return 1;
465        }
466        if( done )
467        {
468            break;
469        }
470        *p = '/';
471        p++;
472        pp = p;
473    }
474
475    return 0;
476}
477
478int
479tr_strncasecmp( const char * s1, const char * s2, size_t n )
480{
481    if ( !n )
482        return 0;
483
484    while( n-- != 0 && tolower( *s1 ) == tolower( *s2 ) ) {
485        if( !n || !*s1 || !*s2 )
486            break;
487        ++s1;
488        ++s2;
489    }
490
491    return tolower(*(unsigned char *) s1) - tolower(*(unsigned char *) s2);
492}
493
494int tr_sprintf( char ** buf, int * used, int * max, const char * format, ... )
495{
496    va_list ap1, ap2;
497    int     ret;
498
499    va_start( ap1, format );
500    va_start( ap2, format );
501    ret = tr_vsprintf( buf, used, max, format, ap1, ap2 );
502    va_end( ap2 );
503    va_end( ap1 );
504
505    return ret;
506}
507
508int tr_vsprintf( char ** buf, int * used, int * max, const char * fmt,
509                 va_list ap1, va_list ap2 )
510{
511    int     want;
512
513    want = vsnprintf( NULL, 0, fmt, ap1 );
514
515    if( tr_concat( buf, used, max, NULL, want ) )
516    {
517        return 1;
518    }
519    assert( *used + want + 1 <= *max );
520
521    *used += vsnprintf( *buf + *used, *max - *used, fmt, ap2 );
522
523    return 0;
524}
525
526#ifndef HAVE_ASPRINTF
527
528int
529asprintf( char ** buf, const char * format, ... )
530{
531    va_list ap;
532    int     ret;
533
534    va_start( ap, format );
535    ret = vasprintf( buf, format, ap );
536    va_end( ap );
537
538    return ret;
539}
540
541int
542vasprintf( char ** buf, const char * format, va_list ap )
543{
544    va_list ap2;
545    int     used, max;
546
547    va_copy( ap2, ap );
548
549    *buf = NULL;
550    used = 0;
551    max  = 0;
552
553    if( tr_vsprintf( buf, &used, &max, format, ap, ap2 ) )
554    {
555        free( *buf );
556        return -1;
557    }
558
559    return used;
560}
561
562#endif /* HAVE_ASPRINTF */
563
564int tr_concat( char ** buf, int * used, int * max, const char * data, int len )
565{
566    int     newmax;
567    char  * newbuf;
568
569    newmax = *max;
570    while( *used + len + 1 > newmax )
571    {
572        newmax += SPRINTF_BUFSIZE;
573    }
574    if( newmax > *max )
575    {
576        newbuf = realloc( *buf, newmax );
577        if( NULL == newbuf )
578        {
579            return 1;
580        }
581        *buf = newbuf;
582        *max = newmax;
583    }
584
585    if( NULL != data )
586    {
587        memcpy( *buf + *used, data, len );
588        *used += len;
589    }
590
591    return 0;
592}
593
594void
595tr_buildPath ( char *buf, size_t buflen, const char *first_element, ... )
596{
597    va_list vl;
598    char* walk = buf;
599    const char * element = first_element;
600
601    if( first_element == NULL )
602        return;
603
604    va_start( vl, first_element );
605    for( ;; ) {
606        const size_t n = strlen( element );
607        memcpy( walk, element, n );
608        walk += n;
609        element = (const char*) va_arg( vl, const char* );
610        if( element == NULL )
611            break;
612        *walk++ = TR_PATH_DELIMITER;
613    }
614    *walk = '\0';
615    assert( walk-buf <= (int)buflen );
616}
617
618int
619tr_ioErrorFromErrno( void )
620{
621    switch( errno )
622    {
623        case EACCES:
624        case EROFS:
625            return TR_ERROR_IO_PERMISSIONS;
626        case ENOSPC:
627            return TR_ERROR_IO_SPACE;
628        case EMFILE:
629            return TR_ERROR_IO_OPEN_FILES;
630        case EFBIG:
631            return TR_ERROR_IO_FILE_TOO_BIG;
632        default:
633            tr_dbg( "generic i/o errno from errno: %s", strerror( errno ) );
634            return TR_ERROR_IO_OTHER;
635    }
636}
637
638char *
639tr_errorString( int code )
640{
641    switch( code )
642    {
643        case TR_OK:
644            return "No error";
645        case TR_ERROR:
646            return "Generic error";
647        case TR_ERROR_ASSERT:
648            return "Assert error";
649        case TR_ERROR_IO_PARENT:
650            return "Download folder does not exist";
651        case TR_ERROR_IO_PERMISSIONS:
652            return "Insufficient permissions";
653        case TR_ERROR_IO_SPACE:
654            return "Insufficient free space";
655        case TR_ERROR_IO_DUP_DOWNLOAD:
656            return "Already active transfer with same name and download folder";
657        case TR_ERROR_IO_FILE_TOO_BIG:
658            return "File too large";
659        case TR_ERROR_IO_OPEN_FILES:
660            return "Too many open files";
661        case TR_ERROR_IO_OTHER:
662            return "Generic I/O error";
663    }
664    return "Unknown error";
665}
666
667/****
668*****
669****/
670
671char*
672tr_strdup( const char * in )
673{
674    return tr_strndup( in, in ? strlen(in) : 0 );
675}
676
677char*
678tr_strndup( const char * in, int len )
679{
680    char * out = NULL;
681
682    if( in != NULL )
683    {
684        out = tr_malloc( len+1 );
685        memcpy( out, in, len );
686        out[len] = '\0';
687    }
688    return out;
689}
690
691void*
692tr_calloc( size_t nmemb, size_t size )
693{
694    return nmemb && size ? calloc( nmemb, size ) : NULL;
695}
696
697void*
698tr_malloc( size_t size )
699{
700    return size ? malloc( size ) : NULL;
701}
702
703void*
704tr_malloc0( size_t size )
705{
706    void * ret = tr_malloc( size );
707    memset( ret, 0, size );
708    return ret;
709}
710
711void
712tr_free( void * p )
713{
714    if( p )
715        free( p );
716}
717
718/****
719*****
720****/
721
722/* note that the argument is how many bits are needed, not bytes */
723tr_bitfield*
724tr_bitfieldNew( size_t bitcount )
725{
726    tr_bitfield * ret = calloc( 1, sizeof(tr_bitfield) );
727    if( NULL == ret )
728        return NULL;
729
730    ret->len = (bitcount+7u) / 8u;
731    ret->bits = calloc( ret->len, 1 );
732    if( NULL == ret->bits ) {
733        free( ret );
734        return NULL;
735    }
736
737    return ret;
738}
739
740tr_bitfield*
741tr_bitfieldDup( const tr_bitfield * in )
742{
743    tr_bitfield * ret = calloc( 1, sizeof(tr_bitfield) );
744    ret->len = in->len;
745    ret->bits = malloc( ret->len );
746    memcpy( ret->bits, in->bits, ret->len );
747    return ret;
748}
749
750void tr_bitfieldFree( tr_bitfield * bitfield )
751{
752    if( bitfield )
753    {
754        free( bitfield->bits );
755        free( bitfield );
756    }
757}
758
759void
760tr_bitfieldClear( tr_bitfield * bitfield )
761{
762    memset( bitfield->bits, 0, bitfield->len );
763}
764
765int
766tr_bitfieldIsEmpty( const tr_bitfield * bitfield )
767{
768    unsigned int i;
769
770    for( i=0; i<bitfield->len; ++i )
771        if( bitfield->bits[i] )
772            return 0;
773
774    return 1;
775}
776
777int
778tr_bitfieldHas( const tr_bitfield * bitfield, size_t nth )
779{
780    static const uint8_t ands[8] = { 128, 64, 32, 16, 8, 4, 2, 1 };
781    return bitfield!=NULL && (bitfield->bits[nth>>3u] & ands[nth&7u] );
782}
783
784void
785tr_bitfieldAdd( tr_bitfield  * bitfield, size_t nth )
786{
787    static const uint8_t ands[8] = { 128, 64, 32, 16, 8, 4, 2, 1 };
788    bitfield->bits[nth>>3u] |= ands[nth&7u];
789}
790
791void
792tr_bitfieldAddRange( tr_bitfield  * bitfield,
793                     size_t         begin,
794                     size_t         end )
795{
796    /* TODO: there are faster ways to do this */
797    unsigned int i;
798    for( i=begin; i<end; ++i )
799        tr_bitfieldAdd( bitfield, i );
800}
801
802void
803tr_bitfieldRem( tr_bitfield   * bitfield,
804                size_t          nth )
805{
806    static const uint8_t rems[8] = { 127, 191, 223, 239, 247, 251, 253, 254 };
807
808    if( bitfield != NULL )
809        bitfield->bits[nth>>3u] &= rems[nth&7u];
810}
811
812void
813tr_bitfieldRemRange ( tr_bitfield  * b,
814                      size_t         begin,
815                      size_t         end )
816{
817    /* TODO: there are faster ways to do this */
818    unsigned int i;
819    for( i=begin; i<end; ++i )
820        tr_bitfieldRem( b, i );
821}
822
823tr_bitfield*
824tr_bitfieldAnd( tr_bitfield * a, const tr_bitfield * b )
825{
826    uint8_t *ait;
827    const uint8_t *aend, *bit;
828
829    assert( a->len == b->len );
830
831    for( ait=a->bits, bit=b->bits, aend=ait+a->len; ait!=aend; ++ait, ++bit )
832        *ait &= *bit;
833
834    return a;
835}
836
837size_t
838tr_bitfieldCountTrueBits( const tr_bitfield* b )
839{
840    size_t ret = 0;
841    const uint8_t *it, *end;
842    static const int trueBitCount[512] = {
843        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,
844        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,
845        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,
846        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,
847        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,
848        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,
849        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,
850        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,
851        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,
852        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,
853        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,
854        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,
855        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,
856        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,
857        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,
858        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
859    };
860
861    if( !b )
862        return 0;
863
864    for( it=b->bits, end=it+b->len; it!=end; ++it )
865        ret += trueBitCount[*it];
866
867    return ret;
868}
869
870/***
871****
872***/
873
874uint64_t
875tr_date( void )
876{
877    struct timeval tv;
878    gettimeofday( &tv, NULL );
879    return (uint64_t) tv.tv_sec * 1000 + ( tv.tv_usec / 1000 );
880}
881
882void
883tr_wait( uint64_t delay_milliseconds )
884{
885#ifdef __BEOS__
886    snooze( 1000 * delay_milliseconds );
887#elif defined(WIN32)
888    Sleep( (DWORD)delay_milliseconds );
889#else
890    usleep( 1000 * delay_milliseconds );
891#endif
892}
Note: See TracBrowser for help on using the repository browser.