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