]> de.git.xonotic.org Git - xonotic/netradiant.git/blob - libs/picomodel/picointernal.c
Wean off #define
[xonotic/netradiant.git] / libs / picomodel / picointernal.c
1 /* -----------------------------------------------------------------------------
2
3    PicoModel Library
4
5    Copyright (c) 2002, Randy Reddig & seaw0lf
6    All rights reserved.
7
8    Redistribution and use in source and binary forms, with or without modification,
9    are permitted provided that the following conditions are met:
10
11    Redistributions of source code must retain the above copyright notice, this list
12    of conditions and the following disclaimer.
13
14    Redistributions in binary form must reproduce the above copyright notice, this
15    list of conditions and the following disclaimer in the documentation and/or
16    other materials provided with the distribution.
17
18    Neither the names of the copyright holders nor the names of its contributors may
19    be used to endorse or promote products derived from this software without
20    specific prior written permission.
21
22    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
23    ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
24    WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
25    DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
26    ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
27    (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28    LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
29    ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30    (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
31    SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32
33    ----------------------------------------------------------------------------- */
34
35 /* todo:
36  * - fix p->curLine for parser routines. increased twice
37  */
38
39 /* dependencies */
40 #include <string.h>
41 #include "picointernal.h"
42
43
44
45 /* function pointers */
46 void *( *_pico_ptr_malloc    )( size_t ) = malloc;
47 void ( *_pico_ptr_free      )( void* ) = free;
48 void ( *_pico_ptr_load_file )( const char*, unsigned char**, int* ) = NULL;
49 void ( *_pico_ptr_free_file )( void* ) = NULL;
50 void ( *_pico_ptr_print     )( int, const char* ) = NULL;
51
52 typedef union
53 {
54         float f;
55         char c[4];
56 }
57 floatSwapUnion;
58
59 /* _pico_alloc:
60  *  kludged memory allocation wrapper
61  */
62 void *_pico_alloc( size_t size ){
63         void *ptr;
64
65         /* some sanity checks */
66         if ( size == 0 ) {
67                 return NULL;
68         }
69         if ( _pico_ptr_malloc == NULL ) {
70                 return NULL;
71         }
72
73         /* allocate memory */
74         ptr = _pico_ptr_malloc( size );
75         if ( ptr == NULL ) {
76                 return NULL;
77         }
78
79         /* zero out allocated memory */
80         memset( ptr,0,size );
81
82         /* return pointer to allocated memory */
83         return ptr;
84 }
85
86 /* _pico_calloc:
87  *  _pico_calloc wrapper
88  */
89 void *_pico_calloc( size_t num, size_t size ){
90         void *ptr;
91
92         /* some sanity checks */
93         if ( num == 0 || size == 0 ) {
94                 return NULL;
95         }
96         if ( _pico_ptr_malloc == NULL ) {
97                 return NULL;
98         }
99
100         /* allocate memory */
101         ptr = _pico_ptr_malloc( num * size );
102         if ( ptr == NULL ) {
103                 return NULL;
104         }
105
106         /* zero out allocated memory */
107         memset( ptr,0,num * size );
108
109         /* return pointer to allocated memory */
110         return ptr;
111 }
112
113 /* _pico_realloc:
114  *  memory reallocation wrapper (note: only grows,
115  *  but never shrinks or frees)
116  */
117 void *_pico_realloc( void **ptr, size_t oldSize, size_t newSize ){
118         void *ptr2;
119
120         /* sanity checks */
121         if ( ptr == NULL ) {
122                 return NULL;
123         }
124         if ( newSize < oldSize ) {
125                 return *ptr;
126         }
127         if ( _pico_ptr_malloc == NULL ) {
128                 return NULL;
129         }
130
131         /* allocate new pointer */
132         ptr2 = _pico_alloc( newSize );
133         if ( ptr2 == NULL ) {
134                 return NULL;
135         }
136
137         /* copy */
138         if ( *ptr != NULL ) {
139                 memcpy( ptr2, *ptr, oldSize );
140                 _pico_free( *ptr );
141         }
142
143         /* fix up and return */
144         *ptr = ptr2;
145         return *ptr;
146 }
147
148 /* _pico_clone_alloc:
149  *  handy function for quick string allocation/copy. it clones
150  *  the given string and returns a pointer to the new allocated
151  *  clone (which must be freed by caller of course) or returns
152  *  NULL on memory alloc or param errors. if 'size' is -1 the
153  *  length of the input string is used, otherwise 'size' is used
154  *  as custom clone size (the string is cropped to fit into mem
155  *  if needed). -sea
156  */
157 char *_pico_clone_alloc( const char *str ){
158         char* cloned;
159
160         /* sanity check */
161         if ( str == NULL ) {
162                 return NULL;
163         }
164
165         /* allocate memory */
166         cloned = _pico_alloc( strlen( str ) + 1 );
167         if ( cloned == NULL ) {
168                 return NULL;
169         }
170
171         /* copy input string to cloned string */
172         strcpy( cloned, str );
173
174         /* return ptr to cloned string */
175         return cloned;
176 }
177
178 /* _pico_free:
179  * wrapper around the free function pointer
180  */
181 void _pico_free( void *ptr ){
182         /* sanity checks */
183         if ( ptr == NULL ) {
184                 return;
185         }
186         if ( _pico_ptr_free == NULL ) {
187                 return;
188         }
189
190         /* free the allocated memory */
191         _pico_ptr_free( ptr );
192 }
193
194 /* _pico_load_file:
195  * wrapper around the loadfile function pointer
196  */
197 void _pico_load_file( const char *name, unsigned char **buffer, int *bufSize ){
198         /* sanity checks */
199         if ( name == NULL ) {
200                 *bufSize = -1;
201                 return;
202         }
203         if ( _pico_ptr_load_file == NULL ) {
204                 *bufSize = -1;
205                 return;
206         }
207         /* do the actual call to read in the file; */
208         /* BUFFER IS ALLOCATED BY THE EXTERNAL LOADFILE FUNC */
209         _pico_ptr_load_file( name,buffer,bufSize );
210 }
211
212 /* _pico_free_file:
213  * wrapper around the file free function pointer
214  */
215 void _pico_free_file( void *buffer ){
216         /* sanity checks */
217         if ( buffer == NULL ) {
218                 return;
219         }
220
221         /* use default free */
222         if ( _pico_ptr_free_file == NULL ) {
223                 free( buffer );
224                 return;
225         }
226         /* free the allocated file */
227         _pico_ptr_free_file( buffer );
228 }
229
230 /* _pico_printf:
231  * wrapper around the print function pointer -sea
232  */
233 void _pico_printf( int level, const char *format, ... ){
234         char str[4096];
235         va_list argptr;
236
237         /* sanity checks */
238         if ( format == NULL ) {
239                 return;
240         }
241         if ( _pico_ptr_print == NULL ) {
242                 return;
243         }
244
245         /* format string */
246         va_start( argptr,format );
247         vsprintf( str,format,argptr );
248         va_end( argptr );
249
250         /* remove linefeeds */
251         if ( str[ strlen( str ) - 1 ] == '\n' ) {
252                 str[ strlen( str ) - 1 ] = '\0';
253         }
254
255         /* do the actual call */
256         _pico_ptr_print( level,str );
257 }
258
259 /* _pico_first_token:
260  * trims everything after the first whitespace-delimited token
261  */
262
263 void _pico_first_token( char *str ){
264         if ( !str || !*str ) {
265                 return;
266         }
267         while ( *str && !isspace( *str ) )
268                 str++;
269         *str = '\0';
270 }
271
272 /* _pico_strltrim:
273  * left trims the given string -sea
274  */
275 char *_pico_strltrim( char *str ){
276         char *str1 = str, *str2 = str;
277
278         while ( isspace( *str2 ) ) str2++;
279         if ( str2 != str ) {
280                 while ( *str2 != '\0' ) /* fix: ydnar */
281                         *str1++ = *str2++;
282         }
283         return str;
284 }
285
286 /* _pico_strrtrim:
287  * right trims the given string -sea
288  */
289 char *_pico_strrtrim( char *str ){
290         if ( str && *str ) {
291                 char *str1 = str;
292                 int allspace = 1;
293
294                 while ( *str1 )
295                 {
296                         if ( allspace && !isspace( *str1 ) ) {
297                                 allspace = 0;
298                         }
299                         str1++;
300                 }
301                 if ( allspace ) {
302                         *str = '\0';
303                 }
304                 else {
305                         str1--;
306                         while ( ( isspace( *str1 ) ) && ( str1 >= str ) )
307                                 *str1-- = '\0';
308                 }
309         }
310         return str;
311 }
312
313 /* _pico_strlwr:
314  *  pico internal string-to-lower routine.
315  */
316 char *_pico_strlwr( char *str ){
317         char *cp;
318         for ( cp = str; *cp; ++cp )
319         {
320                 if ( 'A' <= *cp && *cp <= 'Z' ) {
321                         *cp += ( 'a' - 'A' );
322                 }
323         }
324         return str;
325 }
326
327 /* _pico_strchcount:
328  *  counts how often the given char appears in str. -sea
329  */
330 int _pico_strchcount( char *str, int ch ){
331         int count = 0;
332         while ( *str++ ) if ( *str == ch ) {
333                         count++;
334                 }
335         return count;
336 }
337
338 void _pico_zero_bounds( picoVec3_t mins, picoVec3_t maxs ){
339         int i;
340         for ( i = 0; i < 3; i++ )
341         {
342                 mins[i] = +999999;
343                 maxs[i] = -999999;
344         }
345 }
346
347 void _pico_expand_bounds( picoVec3_t p, picoVec3_t mins, picoVec3_t maxs ){
348         int i;
349         for ( i = 0; i < 3; i++ )
350         {
351                 float value = p[i];
352                 if ( value < mins[i] ) {
353                         mins[i] = value;
354                 }
355                 if ( value > maxs[i] ) {
356                         maxs[i] = value;
357                 }
358         }
359 }
360
361 void _pico_zero_vec( picoVec3_t vec ){
362         vec[ 0 ] = vec[ 1 ] = vec[ 2 ] = 0;
363 }
364
365 void _pico_zero_vec2( picoVec2_t vec ){
366         vec[ 0 ] = vec[ 1 ] = 0;
367 }
368
369 void _pico_zero_vec4( picoVec4_t vec ){
370         vec[ 0 ] = vec[ 1 ] = vec[ 2 ] = vec[ 3 ] = 0;
371 }
372
373 void _pico_set_vec( picoVec3_t v, float a, float b, float c ){
374         v[ 0 ] = a;
375         v[ 1 ] = b;
376         v[ 2 ] = c;
377 }
378
379 void _pico_set_vec4( picoVec4_t v, float a, float b, float c, float d ){
380         v[ 0 ] = a;
381         v[ 1 ] = b;
382         v[ 2 ] = c;
383         v[ 3 ] = d;
384 }
385
386 void _pico_copy_vec( picoVec3_t src, picoVec3_t dest ){
387         dest[ 0 ] = src[ 0 ];
388         dest[ 1 ] = src[ 1 ];
389         dest[ 2 ] = src[ 2 ];
390 }
391
392 void _pico_copy_vec2( picoVec2_t src, picoVec2_t dest ){
393         dest[ 0 ] = src[ 0 ];
394         dest[ 1 ] = src[ 1 ];
395 }
396
397 void _pico_copy_vec4( picoVec4_t src, picoVec4_t dest ){
398         dest[ 0 ] = src[ 0 ];
399         dest[ 1 ] = src[ 1 ];
400         dest[ 2 ] = src[ 2 ];
401         dest[ 3 ] = src[ 3 ];
402 }
403
404 /* ydnar */
405 picoVec_t _pico_normalize_vec( picoVec3_t vec ){
406         double len, ilen;
407
408         len = sqrt( vec[ 0 ] * vec[ 0 ] + vec[ 1 ] * vec[ 1 ] + vec[ 2 ] * vec[ 2 ] );
409         if ( len == 0.0 ) {
410                 return 0.0;
411         }
412         ilen = 1.0 / len;
413         vec[ 0 ] *= (picoVec_t) ilen;
414         vec[ 1 ] *= (picoVec_t) ilen;
415         vec[ 2 ] *= (picoVec_t) ilen;
416         return (picoVec_t) len;
417 }
418
419 void _pico_add_vec( picoVec3_t a, picoVec3_t b, picoVec3_t dest ){
420         dest[ 0 ] = a[ 0 ] + b[ 0 ];
421         dest[ 1 ] = a[ 1 ] + b[ 1 ];
422         dest[ 2 ] = a[ 2 ] + b[ 2 ];
423 }
424
425 void _pico_subtract_vec( picoVec3_t a, picoVec3_t b, picoVec3_t dest ){
426         dest[ 0 ] = a[ 0 ] - b[ 0 ];
427         dest[ 1 ] = a[ 1 ] - b[ 1 ];
428         dest[ 2 ] = a[ 2 ] - b[ 2 ];
429 }
430
431 void _pico_scale_vec( picoVec3_t v, float scale, picoVec3_t dest ){
432         dest[ 0 ] = v[ 0 ] * scale;
433         dest[ 1 ] = v[ 1 ] * scale;
434         dest[ 2 ] = v[ 2 ] * scale;
435 }
436
437 void _pico_scale_vec4( picoVec4_t v, float scale, picoVec4_t dest ){
438         dest[ 0 ] = v[ 0 ] * scale;
439         dest[ 1 ] = v[ 1 ] * scale;
440         dest[ 2 ] = v[ 2 ] * scale;
441         dest[ 3 ] = v[ 3 ] * scale;
442 }
443
444 picoVec_t _pico_dot_vec( picoVec3_t a, picoVec3_t b ){
445         return a[ 0 ] * b[ 0 ] + a[ 1 ] * b[ 1 ] + a[ 2 ] * b[ 2 ];
446 }
447
448 void _pico_cross_vec( picoVec3_t a, picoVec3_t b, picoVec3_t dest ){
449         dest[ 0 ] = a[ 1 ] * b[ 2 ] - a[ 2 ] * b[ 1 ];
450         dest[ 1 ] = a[ 2 ] * b[ 0 ] - a[ 0 ] * b[ 2 ];
451         dest[ 2 ] = a[ 0 ] * b[ 1 ] - a[ 1 ] * b[ 0 ];
452 }
453
454 picoVec_t _pico_calc_plane( picoVec4_t plane, picoVec3_t a, picoVec3_t b, picoVec3_t c ){
455         picoVec3_t ba, ca;
456
457         _pico_subtract_vec( b, a, ba );
458         _pico_subtract_vec( c, a, ca );
459         _pico_cross_vec( ca, ba, plane );
460         plane[ 3 ] = _pico_dot_vec( a, plane );
461         return _pico_normalize_vec( plane );
462 }
463
464 /* separate from _pico_set_vec4 */
465 void _pico_set_color( picoColor_t c, int r, int g, int b, int a ){
466         c[ 0 ] = r;
467         c[ 1 ] = g;
468         c[ 2 ] = b;
469         c[ 3 ] = a;
470 }
471
472 void _pico_copy_color( picoColor_t src, picoColor_t dest ){
473         dest[ 0 ] = src[ 0 ];
474         dest[ 1 ] = src[ 1 ];
475         dest[ 2 ] = src[ 2 ];
476         dest[ 3 ] = src[ 3 ];
477 }
478
479 #ifdef __BIG_ENDIAN__
480
481 int   _pico_big_long( int src ) { return src; }
482 short _pico_big_short( short src ) { return src; }
483 float _pico_big_float( float src ) { return src; }
484
485 int _pico_little_long( int src ){
486         return ( ( src & 0xFF000000 ) >> 24 ) |
487                    ( ( src & 0x00FF0000 ) >> 8 ) |
488                    ( ( src & 0x0000FF00 ) << 8 ) |
489                    ( ( src & 0x000000FF ) << 24 );
490 }
491
492 short _pico_little_short( short src ){
493         return ( ( src & 0xFF00 ) >> 8 ) |
494                    ( ( src & 0x00FF ) << 8 );
495 }
496
497 float _pico_little_float( float src ){
498         floatSwapUnion in,out;
499         in.f = src;
500         out.c[ 0 ] = in.c[ 3 ];
501         out.c[ 1 ] = in.c[ 2 ];
502         out.c[ 2 ] = in.c[ 1 ];
503         out.c[ 3 ] = in.c[ 0 ];
504         return out.f;
505 }
506 #else /*__BIG_ENDIAN__*/
507
508 int   _pico_little_long( int src ) { return src; }
509 short _pico_little_short( short src ) { return src; }
510 float _pico_little_float( float src ) { return src; }
511
512 int _pico_big_long( int src ){
513         return ( ( src & 0xFF000000 ) >> 24 ) |
514                    ( ( src & 0x00FF0000 ) >> 8 ) |
515                    ( ( src & 0x0000FF00 ) << 8 ) |
516                    ( ( src & 0x000000FF ) << 24 );
517 }
518
519 short _pico_big_short( short src ){
520         return ( ( src & 0xFF00 ) >> 8 ) |
521                    ( ( src & 0x00FF ) << 8 );
522 }
523
524 float _pico_big_float( float src ){
525         floatSwapUnion in,out;
526         in.f = src;
527         out.c[ 0 ] = in.c[ 3 ];
528         out.c[ 1 ] = in.c[ 2 ];
529         out.c[ 2 ] = in.c[ 1 ];
530         out.c[ 3 ] = in.c[ 0 ];
531         return out.f;
532 }
533 #endif /*__BIG_ENDIAN__*/
534
535 /* _pico_stristr:
536  *  case-insensitive strstr. -sea
537  */
538 const char *_pico_stristr( const char *str, const char *substr ){
539         const size_t sublen = strlen( substr );
540         while ( *str )
541         {
542                 if ( !_pico_strnicmp( str,substr,sublen ) ) {
543                         break;
544                 }
545                 str++;
546         }
547         if ( !( *str ) ) {
548                 str = NULL;
549         }
550         return str;
551 }
552
553 /*
554    _pico_unixify()
555    changes dos \ style path separators to /
556  */
557
558 void _pico_unixify( char *path ){
559         if ( path == NULL ) {
560                 return;
561         }
562         while ( *path )
563         {
564                 if ( *path == '\\' ) {
565                         *path = '/';
566                 }
567                 path++;
568         }
569 }
570
571 /* _pico_nofname:
572  *  removes file name portion from given file path and converts
573  *  the directory separators to un*x style. returns 1 on success
574  *  or 0 when 'destSize' was exceeded. -sea
575  */
576 int _pico_nofname( const char *path, char *dest, int destSize ){
577         int left  = destSize;
578         char *temp  = dest;
579
580         while ( ( *dest = *path ) != '\0' )
581         {
582                 if ( *dest == '/' || *dest == '\\' ) {
583                         temp = ( dest + 1 );
584                         *dest = '/';
585                 }
586                 dest++; path++;
587
588                 if ( --left < 1 ) {
589                         *temp = '\0';
590                         return 0;
591                 }
592         }
593         *temp = '\0';
594         return 1;
595 }
596
597 /* _pico_nopath:
598  *  returns ptr to filename portion in given path or an empty
599  *  string otherwise. given 'path' is not altered. -sea
600  */
601 const char *_pico_nopath( const char *path ){
602         const char *src;
603         src = path + ( strlen( path ) - 1 );
604
605         if ( path == NULL ) {
606                 return "";
607         }
608         if ( !strchr( path,'/' ) && !strchr( path,'\\' ) ) {
609                 return ( path );
610         }
611
612         while ( ( src-- ) != path )
613         {
614                 if ( *src == '/' || *src == '\\' ) {
615                         return ( ++src );
616                 }
617         }
618         return "";
619 }
620
621 /* _pico_setfext:
622  *  sets/changes the file extension for the given filename
623  *  or filepath's filename portion. the given 'path' *is*
624  *  altered. leave 'ext' empty to remove extension. -sea
625  */
626 char *_pico_setfext( char *path, const char *ext ){
627         char *src;
628         int remfext = 0;
629
630         src = path + ( strlen( path ) - 1 );
631
632         if ( ext == NULL ) {
633                 ext = "";
634         }
635         if ( strlen( ext ) < 1 ) {
636                 remfext = 1;
637         }
638         if ( strlen( path ) < 1 ) {
639                 return path;
640         }
641
642         while ( ( src-- ) != path )
643         {
644                 if ( *src == '/' || *src == '\\' ) {
645                         return path;
646                 }
647
648                 if ( *src == '.' ) {
649                         if ( remfext ) {
650                                 *src = '\0';
651                                 return path;
652                         }
653                         *( ++src ) = '\0';
654                         break;
655                 }
656         }
657         strcat( path,ext );
658         return path;
659 }
660
661 /* _pico_getline:
662  *  extracts one line from the given buffer and stores it in dest.
663  *  returns -1 on error or the length of the line on success. i've
664  *  removed string trimming here. this can be done manually by the
665  *  calling func.
666  */
667 int _pico_getline( char *buf, int bufsize, char *dest, int destsize ){
668         int pos;
669
670         /* check output */
671         if ( dest == NULL || destsize < 1 ) {
672                 return -1;
673         }
674         memset( dest,0,destsize );
675
676         /* check input */
677         if ( buf == NULL || bufsize < 1 ) {
678                 return -1;
679         }
680
681         /* get next line */
682         for ( pos = 0; pos < bufsize && pos < destsize; pos++ )
683         {
684                 if ( buf[pos] == '\n' ) {
685                         pos++; break;
686                 }
687                 dest[pos] = buf[pos];
688         }
689         /* terminate dest and return */
690         dest[pos] = '\0';
691         return pos;
692 }
693
694 /* _pico_parse_skip_white:
695  *  skips white spaces in current pico parser, sets *hasLFs
696  *  to 1 if linefeeds were skipped, and either returns the
697  *  parser's cursor pointer or NULL on error. -sea
698  */
699 void _pico_parse_skip_white( picoParser_t *p, int *hasLFs ){
700         /* sanity checks */
701         if ( p == NULL || p->cursor == NULL ) {
702                 return;
703         }
704
705         /* skin white spaces */
706         while ( 1 )
707         {
708                 /* sanity checks */
709                 if ( p->cursor <  p->buffer ||
710                          p->cursor >= p->max ) {
711                         return;
712                 }
713                 /* break for chars other than white spaces */
714                 if ( *p->cursor >  0x20 ) {
715                         break;
716                 }
717                 if ( *p->cursor == 0x00 ) {
718                         return;
719                 }
720
721                 /* a bit of linefeed handling */
722                 if ( *p->cursor == '\n' ) {
723                         *hasLFs = 1;
724                         p->curLine++;
725                 }
726                 /* go to next character */
727                 p->cursor++;
728         }
729 }
730
731 /* _pico_new_parser:
732  *  allocates a new ascii parser object.
733  */
734 picoParser_t *_pico_new_parser( const picoByte_t *buffer, int bufSize ){
735         picoParser_t *p;
736
737         /* sanity check */
738         if ( buffer == NULL || bufSize <= 0 ) {
739                 return NULL;
740         }
741
742         /* allocate reader */
743         p = _pico_alloc( sizeof( picoParser_t ) );
744         if ( p == NULL ) {
745                 return NULL;
746         }
747         memset( p,0,sizeof( picoParser_t ) );
748
749         /* allocate token space */
750         p->tokenSize = 0;
751         p->tokenMax = 1024;
752         p->token = _pico_alloc( p->tokenMax );
753         if ( p->token == NULL ) {
754                 _pico_free( p );
755                 return NULL;
756         }
757         /* setup */
758         p->buffer   = (const char *) buffer;
759         p->cursor   = (const char *) buffer;
760         p->bufSize  = bufSize;
761         p->max      = p->buffer + bufSize;
762         p->curLine = 1; /* sea: new */
763
764         /* return ptr to parser */
765         return p;
766 }
767
768 /* _pico_free_parser:
769  *  frees an existing pico parser object.
770  */
771 void _pico_free_parser( picoParser_t *p ){
772         /* sanity check */
773         if ( p == NULL ) {
774                 return;
775         }
776
777         /* free the parser */
778         if ( p->token != NULL ) {
779                 _pico_free( p->token );
780         }
781         _pico_free( p );
782 }
783
784 /* _pico_parse_ex:
785  *  reads the next token from given pico parser object. if param
786  * 'allowLFs' is 1 it will read beyond linefeeds and return 0 when
787  *  the EOF is reached. if 'allowLFs' is 0 it will return 0 when
788  *  the EOL is reached. if 'handleQuoted' is 1 the parser function
789  *  will handle "quoted" strings and return the data between the
790  *  quotes as token. returns 0 on end/error or 1 on success. -sea
791  */
792 int _pico_parse_ex( picoParser_t *p, int allowLFs, int handleQuoted ){
793         int hasLFs = 0;
794         const char *old;
795
796         /* sanity checks */
797         if ( p == NULL || p->buffer == NULL ||
798                  p->cursor <  p->buffer ||
799                  p->cursor >= p->max ) {
800                 return 0;
801         }
802         /* clear parser token */
803         p->tokenSize = 0;
804         p->token[ 0 ] = '\0';
805         old = p->cursor;
806
807         /* skip whitespaces */
808         while ( p->cursor < p->max && *p->cursor <= 32 )
809         {
810                 if ( *p->cursor == '\n' ) {
811                         p->curLine++;
812                         hasLFs++;
813                 }
814                 p->cursor++;
815         }
816         /* return if we're not allowed to go beyond lfs */
817         if ( ( hasLFs > 0 ) && !allowLFs ) {
818                 p->cursor = old;
819                 return 0;
820         }
821         /* get next quoted string */
822         if ( *p->cursor == '\"' && handleQuoted ) {
823                 p->cursor++;
824                 while ( p->cursor < p->max && *p->cursor )
825                 {
826                         if ( *p->cursor == '\\' ) {
827                                 if ( *( p->cursor + 1 ) == '"' ) {
828                                         p->cursor++;
829                                 }
830                                 p->token[ p->tokenSize++ ] = *p->cursor++;
831                                 continue;
832                         }
833                         else if ( *p->cursor == '\"' ) {
834                                 p->cursor++;
835                                 break;
836                         }
837                         else if ( *p->cursor == '\n' ) {
838                                 p->curLine++;
839                         }
840                         p->token[ p->tokenSize++ ] = *p->cursor++;
841                 }
842                 /* terminate token */
843                 p->token[ p->tokenSize ] = '\0';
844                 return 1;
845         }
846         /* otherwise get next word */
847         while ( p->cursor < p->max && *p->cursor > 32 )
848         {
849                 if ( *p->cursor == '\n' ) {
850                         p->curLine++;
851                 }
852                 p->token[ p->tokenSize++ ] = *p->cursor++;
853         }
854         /* terminate token */
855         p->token[ p->tokenSize ] = '\0';
856         return 1;
857 }
858
859 /* _pico_parse_first:
860  *  reads the first token from the next line and returns
861  *  a pointer to it. returns NULL on EOL or EOF. -sea
862  */
863 char *_pico_parse_first( picoParser_t *p ){
864         /* sanity check */
865         if ( p == NULL ) {
866                 return NULL;
867         }
868
869         /* try to read next token (with lfs & quots) */
870         if ( !_pico_parse_ex( p,1,1 ) ) {
871                 return NULL;
872         }
873
874         /* return ptr to the token string */
875         return p->token;
876 }
877
878 /* _pico_parse:
879  *  reads the next token from the parser and returns a pointer
880  *  to it. quoted strings are handled as usual. returns NULL
881  *  on EOL or EOF. -sea
882  */
883 char *_pico_parse( picoParser_t *p, int allowLFs ){
884         /* sanity check */
885         if ( p == NULL ) {
886                 return NULL;
887         }
888
889         /* try to read next token (with quots) */
890         if ( !_pico_parse_ex( p,allowLFs,1 ) ) {
891                 return NULL;
892         }
893
894         /* return ptr to the token string */
895         return p->token;
896 }
897
898 /* _pico_parse_skip_rest:
899  *  skips the rest of the current line in parser.
900  */
901 void _pico_parse_skip_rest( picoParser_t *p ){
902         while ( _pico_parse_ex( p,0,0 ) ) ;
903 }
904
905 /* _pico_parse_skip_braced:
906  *  parses/skips over a braced section. returns 1 on success
907  *  or 0 on error (when there was no closing bracket and the
908  *  end of buffer was reached or when the opening bracket was
909  *  missing).
910  */
911 int _pico_parse_skip_braced( picoParser_t *p ){
912         int firstToken = 1;
913         int level;
914
915         /* sanity check */
916         if ( p == NULL ) {
917                 return 0;
918         }
919
920         /* set the initial level for parsing */
921         level = 0;
922
923         /* skip braced section */
924         while ( 1 )
925         {
926                 /* read next token (lfs allowed) */
927                 if ( !_pico_parse_ex( p,1,1 ) ) {
928                         /* end of parser buffer reached */
929                         return 0;
930                 }
931                 /* first token must be an opening bracket */
932                 if ( firstToken && p->token[0] != '{' ) {
933                         /* opening bracket missing */
934                         return 0;
935                 }
936                 /* we only check this once */
937                 firstToken = 0;
938
939                 /* update level */
940                 if ( p->token[1] == '\0' ) {
941                         if ( p->token[0] == '{' ) {
942                                 level++;
943                         }
944                         if ( p->token[0] == '}' ) {
945                                 level--;
946                         }
947                 }
948                 /* break if we're back at our starting level */
949                 if ( level == 0 ) {
950                         break;
951                 }
952         }
953         /* successfully skipped braced section */
954         return 1;
955 }
956
957 int _pico_parse_check( picoParser_t *p, int allowLFs, char *str ){
958         if ( !_pico_parse_ex( p,allowLFs,1 ) ) {
959                 return 0;
960         }
961         if ( !strcmp( p->token,str ) ) {
962                 return 1;
963         }
964         return 0;
965 }
966
967 int _pico_parse_checki( picoParser_t *p, int allowLFs, char *str ){
968         if ( !_pico_parse_ex( p,allowLFs,1 ) ) {
969                 return 0;
970         }
971         if ( !_pico_stricmp( p->token,str ) ) {
972                 return 1;
973         }
974         return 0;
975 }
976
977 int _pico_parse_int( picoParser_t *p, int *out ){
978         char *token;
979
980         /* sanity checks */
981         if ( p == NULL || out == NULL ) {
982                 return 0;
983         }
984
985         /* get token and turn it into an integer */
986         *out = 0;
987         token = _pico_parse( p,0 );
988         if ( token == NULL ) {
989                 return 0;
990         }
991         *out = atoi( token );
992
993         /* success */
994         return 1;
995 }
996
997 int _pico_parse_int_def( picoParser_t *p, int *out, int def ){
998         char *token;
999
1000         /* sanity checks */
1001         if ( p == NULL || out == NULL ) {
1002                 return 0;
1003         }
1004
1005         /* get token and turn it into an integer */
1006         *out = def;
1007         token = _pico_parse( p,0 );
1008         if ( token == NULL ) {
1009                 return 0;
1010         }
1011         *out = atoi( token );
1012
1013         /* success */
1014         return 1;
1015 }
1016
1017 int _pico_parse_float( picoParser_t *p, float *out ){
1018         char *token;
1019
1020         /* sanity checks */
1021         if ( p == NULL || out == NULL ) {
1022                 return 0;
1023         }
1024
1025         /* get token and turn it into a float */
1026         *out = 0.0f;
1027         token = _pico_parse( p,0 );
1028         if ( token == NULL ) {
1029                 return 0;
1030         }
1031         *out = (float) atof( token );
1032
1033         /* success */
1034         return 1;
1035 }
1036
1037 int _pico_parse_float_def( picoParser_t *p, float *out, float def ){
1038         char *token;
1039
1040         /* sanity checks */
1041         if ( p == NULL || out == NULL ) {
1042                 return 0;
1043         }
1044
1045         /* get token and turn it into a float */
1046         *out = def;
1047         token = _pico_parse( p,0 );
1048         if ( token == NULL ) {
1049                 return 0;
1050         }
1051         *out = (float) atof( token );
1052
1053         /* success */
1054         return 1;
1055 }
1056
1057 int _pico_parse_vec( picoParser_t *p, picoVec3_t out ){
1058         char *token;
1059         int i;
1060
1061         /* sanity checks */
1062         if ( p == NULL || out == NULL ) {
1063                 return 0;
1064         }
1065
1066         /* zero out outination vector */
1067         _pico_zero_vec( out );
1068
1069         /* parse three vector components */
1070         for ( i = 0; i < 3; i++ )
1071         {
1072                 token = _pico_parse( p,0 );
1073                 if ( token == NULL ) {
1074                         _pico_zero_vec( out );
1075                         return 0;
1076                 }
1077                 out[ i ] = (float) atof( token );
1078         }
1079         /* success */
1080         return 1;
1081 }
1082
1083 int _pico_parse_vec_def( picoParser_t *p, picoVec3_t out, picoVec3_t def ){
1084         char *token;
1085         int i;
1086
1087         /* sanity checks */
1088         if ( p == NULL || out == NULL ) {
1089                 return 0;
1090         }
1091
1092         /* assign default vector value */
1093         _pico_copy_vec( def,out );
1094
1095         /* parse three vector components */
1096         for ( i = 0; i < 3; i++ )
1097         {
1098                 token = _pico_parse( p,0 );
1099                 if ( token == NULL ) {
1100                         _pico_copy_vec( def,out );
1101                         return 0;
1102                 }
1103                 out[ i ] = (float) atof( token );
1104         }
1105         /* success */
1106         return 1;
1107 }
1108
1109 int _pico_parse_vec2( picoParser_t *p, picoVec2_t out ){
1110         char *token;
1111         int i;
1112
1113         /* sanity checks */
1114         if ( p == NULL || out == NULL ) {
1115                 return 0;
1116         }
1117
1118         /* zero out outination vector */
1119         _pico_zero_vec2( out );
1120
1121         /* parse two vector components */
1122         for ( i = 0; i < 2; i++ )
1123         {
1124                 token = _pico_parse( p,0 );
1125                 if ( token == NULL ) {
1126                         _pico_zero_vec2( out );
1127                         return 0;
1128                 }
1129                 out[ i ] = (float) atof( token );
1130         }
1131         /* success */
1132         return 1;
1133 }
1134
1135 int _pico_parse_vec2_def( picoParser_t *p, picoVec2_t out, picoVec2_t def ){
1136         char *token;
1137         int i;
1138
1139         /* sanity checks */
1140         if ( p == NULL || out == NULL ) {
1141                 return 0;
1142         }
1143
1144         /* assign default vector value */
1145         _pico_copy_vec2( def,out );
1146
1147         /* parse two vector components */
1148         for ( i = 0; i < 2; i++ )
1149         {
1150                 token = _pico_parse( p,0 );
1151                 if ( token == NULL ) {
1152                         _pico_copy_vec2( def,out );
1153                         return 0;
1154                 }
1155                 out[ i ] = (float) atof( token );
1156         }
1157         /* success */
1158         return 1;
1159 }
1160
1161 int _pico_parse_vec4( picoParser_t *p, picoVec4_t out ){
1162         char *token;
1163         int i;
1164
1165         /* sanity checks */
1166         if ( p == NULL || out == NULL ) {
1167                 return 0;
1168         }
1169
1170         /* zero out outination vector */
1171         _pico_zero_vec4( out );
1172
1173         /* parse four vector components */
1174         for ( i = 0; i < 4; i++ )
1175         {
1176                 token = _pico_parse( p,0 );
1177                 if ( token == NULL ) {
1178                         _pico_zero_vec4( out );
1179                         return 0;
1180                 }
1181                 out[ i ] = (float) atof( token );
1182         }
1183         /* success */
1184         return 1;
1185 }
1186
1187 int _pico_parse_vec4_def( picoParser_t *p, picoVec4_t out, picoVec4_t def ){
1188         char *token;
1189         int i;
1190
1191         /* sanity checks */
1192         if ( p == NULL || out == NULL ) {
1193                 return 0;
1194         }
1195
1196         /* assign default vector value */
1197         _pico_copy_vec4( def,out );
1198
1199         /* parse four vector components */
1200         for ( i = 0; i < 4; i++ )
1201         {
1202                 token = _pico_parse( p,0 );
1203                 if ( token == NULL ) {
1204                         _pico_copy_vec4( def,out );
1205                         return 0;
1206                 }
1207                 out[ i ] = (float) atof( token );
1208         }
1209         /* success */
1210         return 1;
1211 }
1212
1213 /* _pico_new_memstream:
1214  *  allocates a new memorystream object.
1215  */
1216 picoMemStream_t *_pico_new_memstream( const picoByte_t *buffer, int bufSize ){
1217         picoMemStream_t *s;
1218
1219         /* sanity check */
1220         if ( buffer == NULL || bufSize <= 0 ) {
1221                 return NULL;
1222         }
1223
1224         /* allocate stream */
1225         s = _pico_alloc( sizeof( picoMemStream_t ) );
1226         if ( s == NULL ) {
1227                 return NULL;
1228         }
1229         memset( s,0,sizeof( picoMemStream_t ) );
1230
1231         /* setup */
1232         s->buffer   = buffer;
1233         s->curPos   = buffer;
1234         s->bufSize  = bufSize;
1235         s->flag     = 0;
1236
1237         /* return ptr to stream */
1238         return s;
1239 }
1240
1241 /* _pico_free_memstream:
1242  *  frees an existing pico memorystream object.
1243  */
1244 void _pico_free_memstream( picoMemStream_t *s ){
1245         /* sanity check */
1246         if ( s == NULL ) {
1247                 return;
1248         }
1249
1250         /* free the stream */
1251         _pico_free( s );
1252 }
1253
1254 /* _pico_memstream_read:
1255  *  reads data from a pico memorystream into a buffer.
1256  */
1257 int _pico_memstream_read( picoMemStream_t *s, void *buffer, int len ){
1258         int ret = 1;
1259
1260         /* sanity checks */
1261         if ( s == NULL || buffer == NULL ) {
1262                 return 0;
1263         }
1264
1265         if ( s->curPos + len > s->buffer + s->bufSize ) {
1266                 s->flag |= PICO_IOEOF;
1267                 len = s->buffer + s->bufSize - s->curPos;
1268                 ret = 0;
1269         }
1270
1271         /* read the data */
1272         memcpy( buffer, s->curPos, len );
1273         s->curPos += len;
1274         return ret;
1275 }
1276
1277 /* _pico_memstream_read:
1278  *  reads a character from a pico memorystream
1279  */
1280 int _pico_memstream_getc( picoMemStream_t *s ){
1281         int c = 0;
1282
1283         /* sanity check */
1284         if ( s == NULL ) {
1285                 return -1;
1286         }
1287
1288         /* read the character */
1289         if ( _pico_memstream_read( s, &c, 1 ) == 0 ) {
1290                 return -1;
1291         }
1292
1293         return c;
1294 }
1295
1296 /* _pico_memstream_seek:
1297  *  sets the current read position to a different location
1298  */
1299 int _pico_memstream_seek( picoMemStream_t *s, long offset, int origin ){
1300         int overflow;
1301
1302         /* sanity check */
1303         if ( s == NULL ) {
1304                 return -1;
1305         }
1306
1307         if ( origin == PICO_SEEK_SET ) {
1308                 s->curPos = s->buffer + offset;
1309                 overflow = s->curPos - ( s->buffer + s->bufSize );
1310                 if ( overflow > 0 ) {
1311                         s->curPos = s->buffer + s->bufSize;
1312                         return offset - overflow;
1313                 }
1314                 return 0;
1315         }
1316         else if ( origin == PICO_SEEK_CUR ) {
1317                 s->curPos += offset;
1318                 overflow = s->curPos - ( s->buffer + s->bufSize );
1319                 if ( overflow > 0 ) {
1320                         s->curPos = s->buffer + s->bufSize;
1321                         return offset - overflow;
1322                 }
1323                 return 0;
1324         }
1325         else if ( origin == PICO_SEEK_END ) {
1326                 s->curPos = ( s->buffer + s->bufSize ) - offset;
1327                 overflow = s->buffer - s->curPos;
1328                 if ( overflow > 0 ) {
1329                         s->curPos = s->buffer;
1330                         return offset - overflow;
1331                 }
1332                 return 0;
1333         }
1334
1335         return -1;
1336 }
1337
1338 /* _pico_memstream_tell:
1339  *  returns the current read position in the pico memorystream
1340  */
1341 long _pico_memstream_tell( picoMemStream_t *s ){
1342         /* sanity check */
1343         if ( s == NULL ) {
1344                 return -1;
1345         }
1346
1347         return s->curPos - s->buffer;
1348 }