]> git.sesse.net Git - vlc/blob - src/extras/libc.c
* src/extras/libc.c: Added an implementation of scandir (from directory.c).
[vlc] / src / extras / libc.c
1 /*****************************************************************************
2  * libc.c: Extra libc function for some systems.
3  *****************************************************************************
4  * Copyright (C) 2002 the VideoLAN team
5  * $Id$
6  *
7  * Authors: Jon Lech Johansen <jon-vl@nanocrew.net>
8  *          Samuel Hocevar <sam@zoy.org>
9  *          Gildas Bazin <gbazin@videolan.org>
10  *          Derk-Jan Hartman <hartman at videolan dot org>
11  *
12  * This program is free software; you can redistribute it and/or modify
13  * it under the terms of the GNU General Public License as published by
14  * the Free Software Foundation; either version 2 of the License, or
15  * (at your option) any later version.
16  *
17  * This program is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20  * GNU General Public License for more details.
21  *
22  * You should have received a copy of the GNU General Public License
23  * along with this program; if not, write to the Free Software
24  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
25  *****************************************************************************/
26 #include <string.h>                                              /* strdup() */
27 #include <stdlib.h>
28 #include <ctype.h>
29
30 #include <vlc/vlc.h>
31
32 #undef iconv_t
33 #undef iconv_open
34 #undef iconv
35 #undef iconv_close
36
37 #if defined(HAVE_ICONV)
38 #   include <iconv.h>
39 #endif
40
41 /*****************************************************************************
42  * getenv: just in case, but it should never be called
43  *****************************************************************************/
44 #if !defined( HAVE_GETENV )
45 char *vlc_getenv( const char *name )
46 {
47     return NULL;
48 }
49 #endif
50
51 /*****************************************************************************
52  * strdup: returns a malloc'd copy of a string
53  *****************************************************************************/
54 #if !defined( HAVE_STRDUP )
55 char *vlc_strdup( const char *string )
56 {
57     return strndup( string, strlen( string ) );
58 }
59 #endif
60
61 /*****************************************************************************
62  * strndup: returns a malloc'd copy of at most n bytes of string
63  * Does anyone know whether or not it will be present in Jaguar?
64  *****************************************************************************/
65 #if !defined( HAVE_STRNDUP )
66 char *vlc_strndup( const char *string, size_t n )
67 {
68     char *psz;
69     size_t len = strlen( string );
70
71     len = __MIN( len, n );
72     psz = (char*)malloc( len + 1 );
73
74     if( psz != NULL )
75     {
76         memcpy( (void*)psz, (const void*)string, len );
77         psz[ len ] = 0;
78     }
79
80     return psz;
81 }
82 #endif
83
84 /*****************************************************************************
85  * strcasecmp: compare two strings ignoring case
86  *****************************************************************************/
87 #if !defined( HAVE_STRCASECMP ) && !defined( HAVE_STRICMP )
88 int vlc_strcasecmp( const char *s1, const char *s2 )
89 {
90     int c1, c2;
91     if( !s1 || !s2 ) return  -1;
92
93     while( *s1 && *s2 )
94     {
95         c1 = tolower(*s1);
96         c2 = tolower(*s2);
97
98         if( c1 != c2 ) return (c1 < c2 ? -1 : 1);
99         s1++; s2++;
100     }
101
102     if( !*s1 && !*s2 ) return 0;
103     else return (*s1 ? 1 : -1);
104 }
105 #endif
106
107 /*****************************************************************************
108  * strncasecmp: compare n chars from two strings ignoring case
109  *****************************************************************************/
110 #if !defined( HAVE_STRNCASECMP ) && !defined( HAVE_STRNICMP )
111 int vlc_strncasecmp( const char *s1, const char *s2, size_t n )
112 {
113     int c1, c2;
114     if( !s1 || !s2 ) return  -1;
115
116     while( n > 0 && *s1 && *s2 )
117     {
118         c1 = tolower(*s1);
119         c2 = tolower(*s2);
120
121         if( c1 != c2 ) return (c1 < c2 ? -1 : 1);
122         s1++; s2++; n--;
123     }
124
125     if( !n || (!*s1 && !*s2) ) return 0;
126     else return (*s1 ? 1 : -1);
127 }
128 #endif
129
130 /******************************************************************************
131  * strcasestr: find a substring (little) in another substring (big)
132  * Case sensitive. Return NULL if not found, return big if little == null
133  *****************************************************************************/
134 #if !defined( HAVE_STRCASESTR ) && !defined( HAVE_STRISTR )
135 char * vlc_strcasestr( const char *psz_big, const char *psz_little )
136 {
137     char *p_pos = (char *)psz_big;
138
139     if( !psz_big || !psz_little || !*psz_little ) return p_pos;
140  
141     while( *p_pos ) 
142     {
143         if( toupper( *p_pos ) == toupper( *psz_little ) )
144         {
145             char * psz_cur1 = p_pos + 1;
146             char * psz_cur2 = (char *)psz_little + 1;
147             while( *psz_cur1 && *psz_cur2 &&
148                    toupper( *psz_cur1 ) == toupper( *psz_cur2 ) )
149             {
150                 psz_cur1++;
151                 psz_cur2++;
152             }
153             if( !*psz_cur2 ) return p_pos;
154         }
155         p_pos++;
156     }
157     return NULL;
158 }
159 #endif
160
161 /*****************************************************************************
162  * vasprintf:
163  *****************************************************************************/
164 #if !defined(HAVE_VASPRINTF) || defined(SYS_DARWIN) || defined(SYS_BEOS)
165 int vlc_vasprintf(char **strp, const char *fmt, va_list ap)
166 {
167     /* Guess we need no more than 100 bytes. */
168     int     i_size = 100;
169     char    *p = malloc( i_size );
170     int     n;
171
172     if( p == NULL )
173     {
174         *strp = NULL;
175         return -1;
176     }
177
178     for( ;; )
179     {
180         /* Try to print in the allocated space. */
181         n = vsnprintf( p, i_size, fmt, ap );
182
183         /* If that worked, return the string. */
184         if (n > -1 && n < i_size)
185         {
186             *strp = p;
187             return strlen( p );
188         }
189         /* Else try again with more space. */
190         if (n > -1)    /* glibc 2.1 */
191         {
192            i_size = n+1; /* precisely what is needed */
193         }
194         else           /* glibc 2.0 */
195         {
196            i_size *= 2;  /* twice the old size */
197         }
198         if( (p = realloc( p, i_size ) ) == NULL)
199         {
200             *strp = NULL;
201             return -1;
202         }
203     }
204 }
205 #endif
206
207 /*****************************************************************************
208  * asprintf:
209  *****************************************************************************/
210 #if !defined(HAVE_ASPRINTF) || defined(SYS_DARWIN) || defined(SYS_BEOS)
211 int vlc_asprintf( char **strp, const char *fmt, ... )
212 {
213     va_list args;
214     int i_ret;
215
216     va_start( args, fmt );
217     i_ret = vasprintf( strp, fmt, args );
218     va_end( args );
219
220     return i_ret;
221 }
222 #endif
223
224 /*****************************************************************************
225  * atof: convert a string to a double.
226  *****************************************************************************/
227 #if !defined( HAVE_ATOF )
228 double vlc_atof( const char *nptr )
229 {
230     double f_result;
231     wchar_t *psz_tmp;
232     int i_len = strlen( nptr ) + 1;
233
234     psz_tmp = malloc( i_len * sizeof(wchar_t) );
235     MultiByteToWideChar( CP_ACP, 0, nptr, -1, psz_tmp, i_len );
236     f_result = wcstod( psz_tmp, NULL );
237     free( psz_tmp );
238
239     return f_result;
240 }
241 #endif
242
243 /*****************************************************************************
244  * strtoll: convert a string to a 64 bits int.
245  *****************************************************************************/
246 #if !defined( HAVE_STRTOLL )
247 int64_t vlc_strtoll( const char *nptr, char **endptr, int base )
248 {
249     int64_t i_value = 0;
250     int sign = 1, newbase = base ? base : 10;
251
252     while( isspace(*nptr) ) nptr++;
253
254     if( *nptr == '-' )
255     {
256         sign = -1;
257         nptr++;
258     }
259
260     /* Try to detect base */
261     if( *nptr == '0' )
262     {
263         newbase = 8;
264         nptr++;
265
266         if( *nptr == 'x' )
267         {
268             newbase = 16;
269             nptr++;
270         }
271     }
272
273     if( base && newbase != base )
274     {
275         if( endptr ) *endptr = (char *)nptr;
276         return i_value;
277     }
278
279     switch( newbase )
280     {
281         case 10:
282             while( *nptr >= '0' && *nptr <= '9' )
283             {
284                 i_value *= 10;
285                 i_value += ( *nptr++ - '0' );
286             }
287             if( endptr ) *endptr = (char *)nptr;
288             break;
289
290         case 16:
291             while( (*nptr >= '0' && *nptr <= '9') ||
292                    (*nptr >= 'a' && *nptr <= 'f') ||
293                    (*nptr >= 'A' && *nptr <= 'F') )
294             {
295                 int i_valc = 0;
296                 if(*nptr >= '0' && *nptr <= '9') i_valc = *nptr - '0';
297                 else if(*nptr >= 'a' && *nptr <= 'f') i_valc = *nptr - 'a' +10;
298                 else if(*nptr >= 'A' && *nptr <= 'F') i_valc = *nptr - 'A' +10;
299                 i_value *= 16;
300                 i_value += i_valc;
301                 nptr++;
302             }
303             if( endptr ) *endptr = (char *)nptr;
304             break;
305
306         default:
307             i_value = strtol( nptr, endptr, newbase );
308             break;
309     }
310
311     return i_value * sign;
312 }
313 #endif
314
315 /*****************************************************************************
316  * atoll: convert a string to a 64 bits int.
317  *****************************************************************************/
318 #if !defined( HAVE_ATOLL )
319 int64_t vlc_atoll( const char *nptr )
320 {
321     return strtoll( nptr, (char **)NULL, 10 );
322 }
323 #endif
324
325 /*****************************************************************************
326  * scandir: scan a directory alpha-sorted
327  *****************************************************************************/
328 #if !defined( HAVE_SCANDIR )
329 int vlc_alphasort( const struct dirent **a, const struct dirent **b )
330 {
331     return strcoll( (*a)->d_name, (*b)->d_name );
332 }
333
334 int vlc_scandir( const char *name, struct dirent ***namelist,
335                     int (*filter) ( const struct dirent * ),
336                     int (*compar) ( const struct dirent **,
337                                     const struct dirent ** ) )
338 {
339     DIR            * p_dir;
340     struct dirent  * p_content;
341     struct dirent ** pp_list;
342     int              ret, size;
343
344     if( !namelist || !( p_dir = opendir( name ) ) ) return -1;
345
346     ret     = 0;
347     pp_list = NULL;
348     while( ( p_content = readdir( p_dir ) ) )
349     {
350         if( filter && !filter( p_content ) )
351         {
352             continue;
353         }
354         pp_list = realloc( pp_list, ( ret + 1 ) * sizeof( struct dirent * ) );
355         size = sizeof( struct dirent ) + strlen( p_content->d_name ) + 1;
356         pp_list[ret] = malloc( size );
357         memcpy( pp_list[ret], p_content, size );
358         ret++;
359     }
360
361     closedir( p_dir );
362
363     if( compar )
364     {
365         qsort( pp_list, ret, sizeof( struct dirent * ),
366                (int (*)(const void *, const void *)) compar );
367     }
368
369     *namelist = pp_list;
370     return ret;
371 }
372 #endif
373
374 /*****************************************************************************
375  * dgettext: gettext for plugins.
376  *****************************************************************************/
377 char *vlc_dgettext( const char *package, const char *msgid )
378 {
379 #if defined( ENABLE_NLS ) \
380      && ( defined(HAVE_GETTEXT) || defined(HAVE_INCLUDED_GETTEXT) )
381     return dgettext( package, msgid );
382 #else
383     return (char *)msgid;
384 #endif
385 }
386
387 /*****************************************************************************
388  * count_utf8_string: returns the number of characters in the string.
389  *****************************************************************************/
390 static int count_utf8_string( const char *psz_string )
391 {
392     int i = 0, i_count = 0;
393     while( psz_string[ i ] != 0 )
394     {
395         if( ((unsigned char *)psz_string)[ i ] <  0x80UL ) i_count++;
396         i++;
397     }
398     return i_count;
399 }
400
401 /*****************************************************************************
402  * wraptext: inserts \n at convenient places to wrap the text.
403  *           Returns the modified string in a new buffer.
404  *****************************************************************************/
405 char *vlc_wraptext( const char *psz_text, int i_line, vlc_bool_t b_utf8 )
406 {
407     int i_len;
408     char *psz_line, *psz_new_text;
409
410     psz_line = psz_new_text = strdup( psz_text );
411
412     if( b_utf8 )
413         i_len = count_utf8_string( psz_text );
414     else
415         i_len = strlen( psz_text );
416
417     while( i_len > i_line )
418     {
419         /* Look if there is a newline somewhere. */
420         char *psz_parser = psz_line;
421         int i_count = 0;
422         while( i_count <= i_line && *psz_parser != '\n' )
423         {
424             if( b_utf8 )
425             {
426                 while( *((unsigned char *)psz_parser) >= 0x80UL ) psz_parser++;
427             }
428             psz_parser++;
429             i_count++;
430         }
431         if( *psz_parser == '\n' )
432         {
433             i_len -= (i_count + 1);
434             psz_line = psz_parser + 1;
435             continue;
436         }
437
438         /* Find the furthest space. */
439         while( psz_parser > psz_line && *psz_parser != ' ' )
440         {
441             if( b_utf8 )
442             {
443                 while( *((unsigned char *)psz_parser) >= 0x80UL ) psz_parser--;
444             }
445             psz_parser--;
446             i_count--;
447         }
448         if( *psz_parser == ' ' )
449         {
450             *psz_parser = '\n';
451             i_len -= (i_count + 1);
452             psz_line = psz_parser + 1;
453             continue;
454         }
455
456         /* Wrapping has failed. Find the first space or newline */
457         while( i_count < i_len && *psz_parser != ' ' && *psz_parser != '\n' )
458         {
459             if( b_utf8 )
460             {
461                 while( *((unsigned char *)psz_parser) >= 0x80UL ) psz_parser++;
462             }
463             psz_parser++;
464             i_count++;
465         }
466         if( i_count < i_len ) *psz_parser = '\n';
467         i_len -= (i_count + 1);
468         psz_line = psz_parser + 1;
469     }
470
471     return psz_new_text;
472 }
473
474 /*****************************************************************************
475  * iconv wrapper
476  *****************************************************************************/
477 vlc_iconv_t vlc_iconv_open( const char *tocode, const char *fromcode )
478 {
479 #if defined(HAVE_ICONV)
480     return iconv_open( tocode, fromcode );
481 #else
482     return NULL;
483 #endif
484 }
485
486 size_t vlc_iconv( vlc_iconv_t cd, char **inbuf, size_t *inbytesleft,
487                   char **outbuf, size_t *outbytesleft )
488 {
489 #if defined(HAVE_ICONV)
490     return iconv( cd, inbuf, inbytesleft, outbuf, outbytesleft );
491 #else
492     int i_bytes = __MIN(*inbytesleft, *outbytesleft);
493     if( !inbuf || !outbuf || !i_bytes ) return (size_t)(-1);
494     memcpy( *outbuf, *inbuf, i_bytes );
495     inbuf += i_bytes;
496     outbuf += i_bytes;
497     inbytesleft -= i_bytes;
498     outbytesleft -= i_bytes;
499     return i_bytes;
500 #endif
501 }
502
503 int vlc_iconv_close( vlc_iconv_t cd )
504 {
505 #if defined(HAVE_ICONV)
506     return iconv_close( cd );
507 #else
508     return 0;
509 #endif
510 }
511
512 /*****************************************************************************
513  * reduce a fraction
514  *   (adapted from libavcodec, author Michael Niedermayer <michaelni@gmx.at>)
515  *****************************************************************************/
516 vlc_bool_t vlc_ureduce( unsigned *pi_dst_nom, unsigned *pi_dst_den,
517                         uint64_t i_nom, uint64_t i_den, uint64_t i_max )
518 {
519     vlc_bool_t b_exact = 1;
520     uint64_t i_gcd;
521
522     if( i_den == 0 )
523     {
524         *pi_dst_nom = 0;
525         *pi_dst_den = 1;
526         return 1;
527     }
528
529     i_gcd = GCD( i_nom, i_den );
530     i_nom /= i_gcd;
531     i_den /= i_gcd;
532
533     if( i_max == 0 ) i_max = I64C(0xFFFFFFFF);
534
535     if( i_nom > i_max || i_den > i_max )
536     {
537         uint64_t i_a0_num = 0, i_a0_den = 1, i_a1_num = 1, i_a1_den = 0;
538         b_exact = 0;
539
540         for( ; ; )
541         {
542             uint64_t i_x = i_nom / i_den;
543             uint64_t i_a2n = i_x * i_a1_num + i_a0_num;
544             uint64_t i_a2d = i_x * i_a1_den + i_a0_den;
545
546             if( i_a2n > i_max || i_a2d > i_max ) break;
547
548             i_nom %= i_den;
549
550             i_a0_num = i_a1_num; i_a0_den = i_a1_den;
551             i_a1_num = i_a2n; i_a1_den = i_a2d;
552             if( i_nom == 0 ) break;
553             i_x = i_nom; i_nom = i_den; i_den = i_x;
554         }
555         i_nom = i_a1_num;
556         i_den = i_a1_den;
557     }
558
559     *pi_dst_nom = i_nom;
560     *pi_dst_den = i_den;
561
562     return b_exact;
563 }
564
565 /*************************************************************************
566  * vlc_parse_cmdline: Command line parsing into elements.
567  *
568  * The command line is composed of space/tab separated arguments.
569  * Quotes can be used as argument delimiters and a backslash can be used to
570  * escape a quote.
571  *************************************************************************/
572 static void find_end_quote( char **s, char **ppsz_parser, int i_quote )
573 {
574     int i_bcount = 0;
575
576     while( **s )
577     {
578         if( **s == '\\' )
579         {
580             **ppsz_parser = **s;
581             (*ppsz_parser)++; (*s)++;
582             i_bcount++;
583         }
584         else if( **s == '"' || **s == '\'' )
585         {
586             /* Preceeded by a number of '\' which we erase. */
587             *ppsz_parser -= i_bcount / 2;
588             if( i_bcount & 1 )
589             {
590                 /* '\\' followed by a '"' or '\'' */
591                 *ppsz_parser -= 1;
592                 **ppsz_parser = **s;
593                 (*ppsz_parser)++; (*s)++;
594                 i_bcount = 0;
595                 continue;
596             }
597
598             if( **s == i_quote )
599             {
600                 /* End */
601                 return;
602             }
603             else
604             {
605                 /* Different quoting */
606                 int i_quote = **s;
607                 **ppsz_parser = **s;
608                 (*ppsz_parser)++; (*s)++;
609                 find_end_quote( s, ppsz_parser, i_quote );
610                 **ppsz_parser = **s;
611                 (*ppsz_parser)++; (*s)++;
612             }
613
614             i_bcount = 0;
615         }
616         else
617         {
618             /* A regular character */
619             **ppsz_parser = **s;
620             (*ppsz_parser)++; (*s)++;
621             i_bcount = 0;
622         }
623     }
624 }
625
626 char **vlc_parse_cmdline( const char *psz_cmdline, int *i_args )
627 {
628     int argc = 0;
629     char **argv = 0;
630     char *s, *psz_parser, *psz_arg, *psz_orig;
631     int i_bcount = 0;
632
633     if( !psz_cmdline ) return 0;
634     psz_orig = strdup( psz_cmdline );
635     psz_arg = psz_parser = s = psz_orig;
636
637     while( *s )
638     {
639         if( *s == '\t' || *s == ' ' )
640         {
641             /* We have a complete argument */
642             *psz_parser = 0;
643             TAB_APPEND( argc, argv, strdup(psz_arg) );
644
645             /* Skip trailing spaces/tabs */
646             do{ s++; } while( *s == '\t' || *s == ' ' );
647
648             /* New argument */
649             psz_arg = psz_parser = s;
650             i_bcount = 0;
651         }
652         else if( *s == '\\' )
653         {
654             *psz_parser++ = *s++;
655             i_bcount++;
656         }
657         else if( *s == '"' || *s == '\'' )
658         {
659             if( ( i_bcount & 1 ) == 0 )
660             {
661                 /* Preceeded by an even number of '\', this is half that
662                  * number of '\', plus a quote which we erase. */
663                 int i_quote = *s;
664                 psz_parser -= i_bcount / 2;
665                 s++;
666                 find_end_quote( &s, &psz_parser, i_quote );
667                 s++;
668             }
669             else
670             {
671                 /* Preceeded by an odd number of '\', this is half that
672                  * number of '\' followed by a '"' */
673                 psz_parser = psz_parser - i_bcount/2 - 1;
674                 *psz_parser++ = '"';
675                 s++;
676             }
677             i_bcount = 0;
678         }
679         else
680         {
681             /* A regular character */
682             *psz_parser++ = *s++;
683             i_bcount = 0;
684         }
685     }
686
687     /* Take care of the last arg */
688     if( *psz_arg )
689     {
690         *psz_parser = '\0';
691         TAB_APPEND( argc, argv, strdup(psz_arg) );
692     }
693
694     if( i_args ) *i_args = argc;
695     free( psz_orig );
696     return argv;
697 }