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