X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=src%2Fextras%2Flibc.c;h=14b2932c36b533e5739df50dad603e9a55937da8;hb=d8a8f2de21d3200e3dfe3deabb7763ee7ffd776a;hp=f9b450839389aa02087b34cfd0c7e78d6ec09d77;hpb=b2656b1265dafffbe4d03f539399dceb639cc014;p=vlc diff --git a/src/extras/libc.c b/src/extras/libc.c index f9b4508393..14b2932c36 100644 --- a/src/extras/libc.c +++ b/src/extras/libc.c @@ -1,11 +1,14 @@ /***************************************************************************** * libc.c: Extra libc function for some systems. ***************************************************************************** - * Copyright (C) 2002 VideoLAN + * Copyright (C) 2002 the VideoLAN team * $Id$ * * Authors: Jon Lech Johansen * Samuel Hocevar + * Gildas Bazin + * Derk-Jan Hartman + * Christophe Massiot * * 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 @@ -36,6 +39,17 @@ # include #endif +#ifdef HAVE_DIRENT_H +# include +#endif + +#ifdef HAVE_FORK +# include +# include +# include +# include +#endif + /***************************************************************************** * getenv: just in case, but it should never be called *****************************************************************************/ @@ -85,26 +99,20 @@ char *vlc_strndup( const char *string, size_t n ) #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 @@ -114,26 +122,20 @@ int vlc_strcasecmp( const char *s1, const char *s2 ) #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; - - if( *s1 >= 'A' && *s1 <= 'Z' ) - { - i_delta -= 'A' - 'a'; - } - - if( *s2 >= 'A' && *s2 <= 'Z' ) - { - i_delta += 'A' - 'a'; - } + c1 = tolower(*s1); + c2 = tolower(*s2); - s1++; s2++; + if( c1 != c2 ) return (c1 < c2 ? -1 : 1); + s1++; s2++; n--; } - return i_delta; + if( !n || (!*s1 && !*s2) ) return 0; + else return (*s1 ? 1 : -1); } #endif @@ -144,16 +146,16 @@ int vlc_strncasecmp( const char *s1, const char *s2, size_t n ) #if !defined( HAVE_STRCASESTR ) && !defined( HAVE_STRISTR ) char * vlc_strcasestr( const char *psz_big, const char *psz_little ) { - char *p_pos = psz_big; + char *p_pos = (char *)psz_big; - if( !psz_big || !psz_little || !*psz_little ) return psz_big; + if( !psz_big || !psz_little || !*psz_little ) return p_pos; while( *p_pos ) { if( toupper( *p_pos ) == toupper( *psz_little ) ) { char * psz_cur1 = p_pos + 1; - char * psz_cur2 = psz_little + 1; + char * psz_cur2 = (char *)psz_little + 1; while( *psz_cur1 && *psz_cur2 && toupper( *psz_cur1 ) == toupper( *psz_cur2 ) ) { @@ -333,14 +335,161 @@ int64_t vlc_atoll( const char *nptr ) #endif /***************************************************************************** - * lseek: reposition read/write file offset. - ***************************************************************************** - * FIXME: this cast sucks! + * vlc_*dir_wrapper: wrapper under Windows to return the list of drive letters + * when called with an empty argument or just '\' + *****************************************************************************/ +#if defined(WIN32) || defined(UNDER_CE) + +#define WIN32_LEAN_AND_MEAN +#include /* for GetLogicalDrives */ + +typedef struct vlc_DIR +{ + DIR *p_real_dir; + int i_drives; + struct dirent dd_dir; + vlc_bool_t b_insert_back; +} vlc_DIR; + +void *vlc_opendir_wrapper( const char *psz_path ) +{ + vlc_DIR *p_dir; + DIR *p_real_dir; + + if ( psz_path == NULL || psz_path[0] == '\0' + || (psz_path[0] == '\\' && psz_path[1] == '\0') ) + { + /* Special mode to list drive letters */ + p_dir = malloc( sizeof(vlc_DIR) ); + p_dir->p_real_dir = NULL; + p_dir->i_drives = GetLogicalDrives(); + return (void *)p_dir; + } + + p_real_dir = opendir( psz_path ); + if ( p_real_dir == NULL ) + return NULL; + + p_dir = malloc( sizeof(vlc_DIR) ); + p_dir->p_real_dir = p_real_dir; + p_dir->b_insert_back = ( psz_path[1] == ':' && psz_path[2] == '\\' + && psz_path[3] =='\0' ); + return (void *)p_dir; +} + +struct dirent *vlc_readdir_wrapper( void *_p_dir ) +{ + vlc_DIR *p_dir = (vlc_DIR *)_p_dir; + unsigned int i; + DWORD i_drives; + + if ( p_dir->p_real_dir != NULL ) + { + if ( p_dir->b_insert_back ) + { + p_dir->dd_dir.d_ino = 0; + p_dir->dd_dir.d_reclen = 0; + p_dir->dd_dir.d_namlen = 2; + strcpy( p_dir->dd_dir.d_name, ".." ); + p_dir->b_insert_back = VLC_FALSE; + return &p_dir->dd_dir; + } + + return readdir( p_dir->p_real_dir ); + } + + /* Drive letters mode */ + i_drives = p_dir->i_drives; + if ( !i_drives ) + return NULL; /* end */ + + for ( i = 0; i < sizeof(DWORD)*8; i++, i_drives >>= 1 ) + if ( i_drives & 1 ) break; + + if ( i >= 26 ) + return NULL; /* this should not happen */ + + sprintf( p_dir->dd_dir.d_name, "%c:\\", 'A' + i ); + p_dir->dd_dir.d_namlen = strlen(p_dir->dd_dir.d_name); + p_dir->i_drives &= ~(1UL << i); + return &p_dir->dd_dir; +} + +int vlc_closedir_wrapper( void *_p_dir ) +{ + vlc_DIR *p_dir = (vlc_DIR *)_p_dir; + + if ( p_dir->p_real_dir != NULL ) + { + int i_ret = closedir( p_dir->p_real_dir ); + free( p_dir ); + return i_ret; + } + + free( p_dir ); + return 0; +} +#else +void *vlc_opendir_wrapper( const char *psz_path ) +{ + return (void *)opendir( psz_path ); +} +struct dirent *vlc_readdir_wrapper( void *_p_dir ) +{ + return readdir( (DIR *)_p_dir ); +} +int vlc_closedir_wrapper( void *_p_dir ) +{ + return closedir( (DIR *)_p_dir ); +} +#endif + +/***************************************************************************** + * scandir: scan a directory alpha-sorted *****************************************************************************/ -#if !defined( HAVE_LSEEK ) -off_t vlc_lseek( int fildes, off_t offset, int whence ) +#if !defined( HAVE_SCANDIR ) +int vlc_alphasort( const struct dirent **a, const struct dirent **b ) { - return SetFilePointer( (HANDLE)fildes, (long)offset, NULL, whence ); + 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 = vlc_opendir_wrapper( name ) ) ) return -1; + + ret = 0; + pp_list = NULL; + while( ( p_content = vlc_readdir_wrapper( 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++; + } + + vlc_closedir_wrapper( p_dir ); + + if( compar ) + { + qsort( pp_list, ret, sizeof( struct dirent * ), + (int (*)(const void *, const void *)) compar ); + } + + *namelist = pp_list; + return ret; } #endif @@ -462,7 +611,7 @@ size_t vlc_iconv( vlc_iconv_t cd, char **inbuf, size_t *inbytesleft, #if defined(HAVE_ICONV) return iconv( cd, inbuf, inbytesleft, outbuf, outbytesleft ); #else - int i_bytes = __MIN(inbytesleft, outbytesleft); + int i_bytes = __MIN(*inbytesleft, *outbytesleft); if( !inbuf || !outbuf || !i_bytes ) return (size_t)(-1); memcpy( *outbuf, *inbuf, i_bytes ); inbuf += i_bytes; @@ -486,11 +635,11 @@ int vlc_iconv_close( vlc_iconv_t cd ) * reduce a fraction * (adapted from libavcodec, author Michael Niedermayer ) *****************************************************************************/ -vlc_bool_t vlc_reduce( int *pi_dst_nom, int *pi_dst_den, - int64_t i_nom, int64_t i_den, int64_t i_max ) +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, b_sign = 0; - int64_t i_gcd; + vlc_bool_t b_exact = 1; + uint64_t i_gcd; if( i_den == 0 ) { @@ -499,18 +648,6 @@ vlc_bool_t vlc_reduce( int *pi_dst_nom, int *pi_dst_den, return 1; } - if( i_den < 0 ) - { - i_den = - i_den; - i_nom = - i_nom; - } - - if( i_nom < 0 ) - { - i_nom = - i_nom; - b_sign = 1; - } - i_gcd = GCD( i_nom, i_den ); i_nom /= i_gcd; i_den /= i_gcd; @@ -519,14 +656,14 @@ vlc_bool_t vlc_reduce( int *pi_dst_nom, int *pi_dst_den, if( i_nom > i_max || i_den > i_max ) { - int i_a0_num = 0, i_a0_den = 1, i_a1_num = 1, i_a1_den = 0; + uint64_t i_a0_num = 0, i_a0_den = 1, i_a1_num = 1, i_a1_den = 0; b_exact = 0; for( ; ; ) { - int64_t i_x = i_nom / i_den; - int64_t i_a2n = i_x * i_a1_num + i_a0_num; - int64_t i_a2d = i_x * i_a1_den + i_a0_den; + 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; @@ -541,10 +678,276 @@ vlc_bool_t vlc_reduce( int *pi_dst_nom, int *pi_dst_den, i_den = i_a1_den; } - if( b_sign ) i_nom = - i_nom; - *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; +} + +/************************************************************************* + * vlc_execve: Execute an external program with a given environment, + * wait until it finishes and return its standard output + *************************************************************************/ +int __vlc_execve( vlc_object_t *p_object, int i_argc, char **ppsz_argv, + char **ppsz_env, char *psz_cwd, char *p_in, int i_in, + char **pp_data, int *pi_data ) +{ +#ifdef HAVE_FORK + int pi_stdin[2]; + int pi_stdout[2]; + pid_t i_child_pid; + + pipe( pi_stdin ); + pipe( pi_stdout ); + + if ( (i_child_pid = fork()) == -1 ) + { + msg_Err( p_object, "unable to fork (%s)", strerror(errno) ); + return -1; + } + + if ( i_child_pid == 0 ) + { + close(0); + dup(pi_stdin[1]); + close(pi_stdin[0]); + + close(1); + dup(pi_stdout[1]); + close(pi_stdout[0]); + + close(2); + + if ( psz_cwd != NULL ) + chdir( psz_cwd ); + execve( ppsz_argv[0], ppsz_argv, ppsz_env ); + exit(1); + } + + close(pi_stdin[1]); + close(pi_stdout[1]); + if ( !i_in ) + close( pi_stdin[0] ); + + *pi_data = 0; + *pp_data = malloc( 1025 ); /* +1 for \0 */ + + while ( !p_object->b_die ) + { + int i_ret, i_status; + fd_set readfds, writefds; + struct timeval tv; + + FD_ZERO( &readfds ); + FD_ZERO( &writefds ); + FD_SET( pi_stdout[0], &readfds ); + if ( i_in ) + FD_SET( pi_stdin[0], &writefds ); + + tv.tv_sec = 0; + tv.tv_usec = 10000; + + i_ret = select( pi_stdin[0] > pi_stdout[0] ? pi_stdin[0] + 1 : + pi_stdout[0] + 1, &readfds, &writefds, NULL, &tv ); + if ( i_ret > 0 ) + { + if ( FD_ISSET( pi_stdout[0], &readfds ) ) + { + ssize_t i_read = read( pi_stdout[0], &(*pp_data)[*pi_data], + 1024 ); + if ( i_read > 0 ) + { + *pi_data += i_read; + *pp_data = realloc( *pp_data, *pi_data + 1025 ); + } + } + if ( FD_ISSET( pi_stdin[0], &writefds ) ) + { + ssize_t i_write = write( pi_stdin[0], p_in, __MIN(i_in, 1024) ); + + if ( i_write > 0 ) + { + p_in += i_write; + i_in -= i_write; + } + if ( !i_in ) + close( pi_stdin[0] ); + } + } + + if ( waitpid( i_child_pid, &i_status, WNOHANG ) == i_child_pid ) + { + if ( WIFEXITED( i_status ) ) + { + if ( WEXITSTATUS( i_status ) ) + { + msg_Warn( p_object, + "child %s returned with error code %d", + ppsz_argv[0], WEXITSTATUS( i_status ) ); + } + } + else + { + if ( WIFSIGNALED( i_status ) ) + { + msg_Warn( p_object, + "child %s quit on signal %d", ppsz_argv[0], + WTERMSIG( i_status ) ); + } + } + if ( i_in ) + close( pi_stdin[0] ); + close( pi_stdout[0] ); + break; + } + + if ( i_ret < 0 && errno != EINTR ) + { + msg_Warn( p_object, "select failed (%s)", strerror(errno) ); + } + } + +#else + msg_Err( p_object, "vlc_execve called but no implementation is available" ); + return -1; + +#endif + + (*pp_data)[*pi_data] = '\0'; + + return 0; +}