/*****************************************************************************
* libc.c: Extra libc function for some systems.
*****************************************************************************
- * Copyright (C) 2002 VideoLAN
- * $Id: libc.c,v 1.16 2004/02/09 16:12:25 sigmunau Exp $
+ * Copyright (C) 2002 the VideoLAN team
+ * $Id$
*
* Authors: Jon Lech Johansen <jon-vl@nanocrew.net>
* Samuel Hocevar <sam@zoy.org>
+ * Gildas Bazin <gbazin@videolan.org>
+ * Derk-Jan Hartman <hartman at videolan dot org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
*****************************************************************************/
#include <string.h> /* strdup() */
#include <stdlib.h>
+#include <ctype.h>
#include <vlc/vlc.h>
+#undef iconv_t
+#undef iconv_open
+#undef iconv
+#undef iconv_close
+
+#if defined(HAVE_ICONV)
+# include <iconv.h>
+#endif
+
+#ifdef HAVE_DIRENT_H
+# include <dirent.h>
+#endif
+
/*****************************************************************************
* getenv: just in case, but it should never be called
*****************************************************************************/
#if !defined( HAVE_STRCASECMP ) && !defined( HAVE_STRICMP )
int vlc_strcasecmp( const char *s1, const char *s2 )
{
- int i_delta = 0;
+ int c1, c2;
+ if( !s1 || !s2 ) return -1;
- while( !i_delta && *s1 && *s2 )
+ while( *s1 && *s2 )
{
- i_delta = *s1 - *s2;
-
- if( *s1 >= 'A' && *s1 <= 'Z' )
- {
- i_delta -= 'A' - 'a';
- }
-
- if( *s2 >= 'A' && *s2 <= 'Z' )
- {
- i_delta += 'A' - 'a';
- }
+ c1 = tolower(*s1);
+ c2 = tolower(*s2);
+ if( c1 != c2 ) return (c1 < c2 ? -1 : 1);
s1++; s2++;
}
- return i_delta;
+ if( !*s1 && !*s2 ) return 0;
+ else return (*s1 ? 1 : -1);
}
#endif
#if !defined( HAVE_STRNCASECMP ) && !defined( HAVE_STRNICMP )
int vlc_strncasecmp( const char *s1, const char *s2, size_t n )
{
- int i_delta = 0;
+ int c1, c2;
+ if( !s1 || !s2 ) return -1;
- while( n-- && !i_delta && *s1 )
+ while( n > 0 && *s1 && *s2 )
{
- i_delta = *s1 - *s2;
+ c1 = tolower(*s1);
+ c2 = tolower(*s2);
- if( *s1 >= 'A' && *s1 <= 'Z' )
- {
- i_delta -= 'A' - 'a';
- }
+ if( c1 != c2 ) return (c1 < c2 ? -1 : 1);
+ s1++; s2++; n--;
+ }
+
+ if( !n || (!*s1 && !*s2) ) return 0;
+ else return (*s1 ? 1 : -1);
+}
+#endif
+
+/******************************************************************************
+ * strcasestr: find a substring (little) in another substring (big)
+ * Case sensitive. Return NULL if not found, return big if little == null
+ *****************************************************************************/
+#if !defined( HAVE_STRCASESTR ) && !defined( HAVE_STRISTR )
+char * vlc_strcasestr( const char *psz_big, const char *psz_little )
+{
+ char *p_pos = (char *)psz_big;
- if( *s2 >= 'A' && *s2 <= 'Z' )
+ if( !psz_big || !psz_little || !*psz_little ) return p_pos;
+
+ while( *p_pos )
+ {
+ if( toupper( *p_pos ) == toupper( *psz_little ) )
{
- i_delta += 'A' - 'a';
+ char * psz_cur1 = p_pos + 1;
+ char * psz_cur2 = (char *)psz_little + 1;
+ while( *psz_cur1 && *psz_cur2 &&
+ toupper( *psz_cur1 ) == toupper( *psz_cur2 ) )
+ {
+ psz_cur1++;
+ psz_cur2++;
+ }
+ if( !*psz_cur2 ) return p_pos;
}
-
- s1++; s2++;
+ p_pos++;
}
-
- return i_delta;
+ return NULL;
}
#endif
#endif
/*****************************************************************************
- * atoll: convert a string to a 64 bits int.
+ * strtoll: convert a string to a 64 bits int.
*****************************************************************************/
-#if !defined( HAVE_ATOLL )
-int64_t vlc_atoll( const char *str )
+#if !defined( HAVE_STRTOLL )
+int64_t vlc_strtoll( const char *nptr, char **endptr, int base )
{
int64_t i_value = 0;
- int sign = 1;
+ int sign = 1, newbase = base ? base : 10;
+
+ while( isspace(*nptr) ) nptr++;
- if( *str == '-' )
+ if( *nptr == '-' )
{
sign = -1;
+ nptr++;
}
- while( *str >= '0' && *str <= '9' )
+ /* Try to detect base */
+ if( *nptr == '0' )
{
- i_value = i_value * 10 + ( *str++ - '0' );
+ newbase = 8;
+ nptr++;
+
+ if( *nptr == 'x' )
+ {
+ newbase = 16;
+ nptr++;
+ }
+ }
+
+ if( base && newbase != base )
+ {
+ if( endptr ) *endptr = (char *)nptr;
+ return i_value;
+ }
+
+ switch( newbase )
+ {
+ case 10:
+ while( *nptr >= '0' && *nptr <= '9' )
+ {
+ i_value *= 10;
+ i_value += ( *nptr++ - '0' );
+ }
+ if( endptr ) *endptr = (char *)nptr;
+ break;
+
+ case 16:
+ while( (*nptr >= '0' && *nptr <= '9') ||
+ (*nptr >= 'a' && *nptr <= 'f') ||
+ (*nptr >= 'A' && *nptr <= 'F') )
+ {
+ int i_valc = 0;
+ if(*nptr >= '0' && *nptr <= '9') i_valc = *nptr - '0';
+ else if(*nptr >= 'a' && *nptr <= 'f') i_valc = *nptr - 'a' +10;
+ else if(*nptr >= 'A' && *nptr <= 'F') i_valc = *nptr - 'A' +10;
+ i_value *= 16;
+ i_value += i_valc;
+ nptr++;
+ }
+ if( endptr ) *endptr = (char *)nptr;
+ break;
+
+ default:
+ i_value = strtol( nptr, endptr, newbase );
+ break;
}
return i_value * sign;
#endif
/*****************************************************************************
- * lseek: reposition read/write file offset.
- *****************************************************************************
- * FIXME: this cast sucks!
+ * atoll: convert a string to a 64 bits int.
*****************************************************************************/
-#if !defined( HAVE_LSEEK )
-off_t vlc_lseek( int fildes, off_t offset, int whence )
+#if !defined( HAVE_ATOLL )
+int64_t vlc_atoll( const char *nptr )
{
- return SetFilePointer( (HANDLE)fildes, (long)offset, NULL, whence );
+ return strtoll( nptr, (char **)NULL, 10 );
+}
+#endif
+
+/*****************************************************************************
+ * scandir: scan a directory alpha-sorted
+ *****************************************************************************/
+#if !defined( HAVE_SCANDIR )
+int vlc_alphasort( const struct dirent **a, const struct dirent **b )
+{
+ return strcoll( (*a)->d_name, (*b)->d_name );
+}
+
+int vlc_scandir( const char *name, struct dirent ***namelist,
+ int (*filter) ( const struct dirent * ),
+ int (*compar) ( const struct dirent **,
+ const struct dirent ** ) )
+{
+ DIR * p_dir;
+ struct dirent * p_content;
+ struct dirent ** pp_list;
+ int ret, size;
+
+ if( !namelist || !( p_dir = opendir( name ) ) ) return -1;
+
+ ret = 0;
+ pp_list = NULL;
+ while( ( p_content = readdir( p_dir ) ) )
+ {
+ if( filter && !filter( p_content ) )
+ {
+ continue;
+ }
+ pp_list = realloc( pp_list, ( ret + 1 ) * sizeof( struct dirent * ) );
+ size = sizeof( struct dirent ) + strlen( p_content->d_name ) + 1;
+ pp_list[ret] = malloc( size );
+ memcpy( pp_list[ret], p_content, size );
+ ret++;
+ }
+
+ closedir( p_dir );
+
+ if( compar )
+ {
+ qsort( pp_list, ret, sizeof( struct dirent * ),
+ (int (*)(const void *, const void *)) compar );
+ }
+
+ *namelist = pp_list;
+ return ret;
}
#endif
return psz_new_text;
}
+
+/*****************************************************************************
+ * iconv wrapper
+ *****************************************************************************/
+vlc_iconv_t vlc_iconv_open( const char *tocode, const char *fromcode )
+{
+#if defined(HAVE_ICONV)
+ return iconv_open( tocode, fromcode );
+#else
+ return NULL;
+#endif
+}
+
+size_t vlc_iconv( vlc_iconv_t cd, char **inbuf, size_t *inbytesleft,
+ char **outbuf, size_t *outbytesleft )
+{
+#if defined(HAVE_ICONV)
+ return iconv( cd, inbuf, inbytesleft, outbuf, outbytesleft );
+#else
+ int i_bytes = __MIN(*inbytesleft, *outbytesleft);
+ if( !inbuf || !outbuf || !i_bytes ) return (size_t)(-1);
+ memcpy( *outbuf, *inbuf, i_bytes );
+ inbuf += i_bytes;
+ outbuf += i_bytes;
+ inbytesleft -= i_bytes;
+ outbytesleft -= i_bytes;
+ return i_bytes;
+#endif
+}
+
+int vlc_iconv_close( vlc_iconv_t cd )
+{
+#if defined(HAVE_ICONV)
+ return iconv_close( cd );
+#else
+ return 0;
+#endif
+}
+
+/*****************************************************************************
+ * reduce a fraction
+ * (adapted from libavcodec, author Michael Niedermayer <michaelni@gmx.at>)
+ *****************************************************************************/
+vlc_bool_t vlc_ureduce( unsigned *pi_dst_nom, unsigned *pi_dst_den,
+ uint64_t i_nom, uint64_t i_den, uint64_t i_max )
+{
+ vlc_bool_t b_exact = 1;
+ uint64_t i_gcd;
+
+ if( i_den == 0 )
+ {
+ *pi_dst_nom = 0;
+ *pi_dst_den = 1;
+ return 1;
+ }
+
+ i_gcd = GCD( i_nom, i_den );
+ i_nom /= i_gcd;
+ i_den /= i_gcd;
+
+ if( i_max == 0 ) i_max = I64C(0xFFFFFFFF);
+
+ if( i_nom > i_max || i_den > i_max )
+ {
+ uint64_t i_a0_num = 0, i_a0_den = 1, i_a1_num = 1, i_a1_den = 0;
+ b_exact = 0;
+
+ for( ; ; )
+ {
+ uint64_t i_x = i_nom / i_den;
+ uint64_t i_a2n = i_x * i_a1_num + i_a0_num;
+ uint64_t i_a2d = i_x * i_a1_den + i_a0_den;
+
+ if( i_a2n > i_max || i_a2d > i_max ) break;
+
+ i_nom %= i_den;
+
+ i_a0_num = i_a1_num; i_a0_den = i_a1_den;
+ i_a1_num = i_a2n; i_a1_den = i_a2d;
+ if( i_nom == 0 ) break;
+ i_x = i_nom; i_nom = i_den; i_den = i_x;
+ }
+ i_nom = i_a1_num;
+ i_den = i_a1_den;
+ }
+
+ *pi_dst_nom = i_nom;
+ *pi_dst_den = i_den;
+
+ return b_exact;
+}
+
+/*************************************************************************
+ * vlc_parse_cmdline: Command line parsing into elements.
+ *
+ * The command line is composed of space/tab separated arguments.
+ * Quotes can be used as argument delimiters and a backslash can be used to
+ * escape a quote.
+ *************************************************************************/
+static void find_end_quote( char **s, char **ppsz_parser, int i_quote )
+{
+ int i_bcount = 0;
+
+ while( **s )
+ {
+ if( **s == '\\' )
+ {
+ **ppsz_parser = **s;
+ (*ppsz_parser)++; (*s)++;
+ i_bcount++;
+ }
+ else if( **s == '"' || **s == '\'' )
+ {
+ /* Preceeded by a number of '\' which we erase. */
+ *ppsz_parser -= i_bcount / 2;
+ if( i_bcount & 1 )
+ {
+ /* '\\' followed by a '"' or '\'' */
+ *ppsz_parser -= 1;
+ **ppsz_parser = **s;
+ (*ppsz_parser)++; (*s)++;
+ i_bcount = 0;
+ continue;
+ }
+
+ if( **s == i_quote )
+ {
+ /* End */
+ return;
+ }
+ else
+ {
+ /* Different quoting */
+ int i_quote = **s;
+ **ppsz_parser = **s;
+ (*ppsz_parser)++; (*s)++;
+ find_end_quote( s, ppsz_parser, i_quote );
+ **ppsz_parser = **s;
+ (*ppsz_parser)++; (*s)++;
+ }
+
+ i_bcount = 0;
+ }
+ else
+ {
+ /* A regular character */
+ **ppsz_parser = **s;
+ (*ppsz_parser)++; (*s)++;
+ i_bcount = 0;
+ }
+ }
+}
+
+char **vlc_parse_cmdline( const char *psz_cmdline, int *i_args )
+{
+ int argc = 0;
+ char **argv = 0;
+ char *s, *psz_parser, *psz_arg, *psz_orig;
+ int i_bcount = 0;
+
+ if( !psz_cmdline ) return 0;
+ psz_orig = strdup( psz_cmdline );
+ psz_arg = psz_parser = s = psz_orig;
+
+ while( *s )
+ {
+ if( *s == '\t' || *s == ' ' )
+ {
+ /* We have a complete argument */
+ *psz_parser = 0;
+ TAB_APPEND( argc, argv, strdup(psz_arg) );
+
+ /* Skip trailing spaces/tabs */
+ do{ s++; } while( *s == '\t' || *s == ' ' );
+
+ /* New argument */
+ psz_arg = psz_parser = s;
+ i_bcount = 0;
+ }
+ else if( *s == '\\' )
+ {
+ *psz_parser++ = *s++;
+ i_bcount++;
+ }
+ else if( *s == '"' || *s == '\'' )
+ {
+ if( ( i_bcount & 1 ) == 0 )
+ {
+ /* Preceeded by an even number of '\', this is half that
+ * number of '\', plus a quote which we erase. */
+ int i_quote = *s;
+ psz_parser -= i_bcount / 2;
+ s++;
+ find_end_quote( &s, &psz_parser, i_quote );
+ s++;
+ }
+ else
+ {
+ /* Preceeded by an odd number of '\', this is half that
+ * number of '\' followed by a '"' */
+ psz_parser = psz_parser - i_bcount/2 - 1;
+ *psz_parser++ = '"';
+ s++;
+ }
+ i_bcount = 0;
+ }
+ else
+ {
+ /* A regular character */
+ *psz_parser++ = *s++;
+ i_bcount = 0;
+ }
+ }
+
+ /* Take care of the last arg */
+ if( *psz_arg )
+ {
+ *psz_parser = '\0';
+ TAB_APPEND( argc, argv, strdup(psz_arg) );
+ }
+
+ if( i_args ) *i_args = argc;
+ free( psz_orig );
+ return argv;
+}