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