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