1 | /* -*- mode: C; tab-width:8; c-basic-offset:8 -*- |
---|
2 | * vi:set ts=8: |
---|
3 | * |
---|
4 | * al_config.c |
---|
5 | * |
---|
6 | * Handling of the configuration file and alrc configuration variables. |
---|
7 | * |
---|
8 | * FIXME: make thread safe |
---|
9 | * needs to be more robust. |
---|
10 | * leaks memory |
---|
11 | * needs gc |
---|
12 | * |
---|
13 | */ |
---|
14 | #include "al_siteconfig.h" |
---|
15 | |
---|
16 | #include <AL/al.h> |
---|
17 | #include <ctype.h> |
---|
18 | #include <limits.h> |
---|
19 | #include <stdio.h> |
---|
20 | #include <stdlib.h> |
---|
21 | #include <sys/stat.h> |
---|
22 | #include <unistd.h> |
---|
23 | #include <string.h> |
---|
24 | |
---|
25 | #include "al_main.h" |
---|
26 | #include "al_ext.h" |
---|
27 | #include "al_config.h" |
---|
28 | #include "al_error.h" |
---|
29 | #include "al_debug.h" |
---|
30 | |
---|
31 | #ifndef __MORPHOS__ |
---|
32 | #define _AL_FNAME "openalrc" |
---|
33 | #else |
---|
34 | #define _AL_FNAME "OpenAL.prefs" |
---|
35 | #endif |
---|
36 | |
---|
37 | #ifndef PATH_MAX |
---|
38 | #define PATH_MAX 4096 |
---|
39 | #endif |
---|
40 | |
---|
41 | #define alrc_cadr(ls) alrc_car(alrc_cdr(ls)) |
---|
42 | |
---|
43 | /* |
---|
44 | * our symbol table definition. Simple binary tree. |
---|
45 | */ |
---|
46 | typedef struct _AL_SymTab { |
---|
47 | char str[ALRC_MAXSTRLEN + 1]; |
---|
48 | AL_rctree *datum; |
---|
49 | |
---|
50 | struct _AL_SymTab *left; |
---|
51 | struct _AL_SymTab *right; |
---|
52 | } AL_SymTab; |
---|
53 | |
---|
54 | /* |
---|
55 | * root is our scratch space for evaluating expressions. |
---|
56 | */ |
---|
57 | static AL_rctree *root = NULL; |
---|
58 | |
---|
59 | /* |
---|
60 | * symbols with global scope. |
---|
61 | */ |
---|
62 | static AL_SymTab *glsyms; |
---|
63 | |
---|
64 | /* |
---|
65 | * _alOpenRcFile( void ); |
---|
66 | * |
---|
67 | * Opens any openalrc file and returns its contents. |
---|
68 | */ |
---|
69 | static char *_alOpenRcFile( void ); |
---|
70 | |
---|
71 | /* |
---|
72 | * _alEval( AL_rctree *head ) |
---|
73 | * |
---|
74 | * Evaluate an expression in AL_rctree form. |
---|
75 | */ |
---|
76 | static AL_rctree *_alEval( AL_rctree *head ); |
---|
77 | |
---|
78 | /* |
---|
79 | * _alSymbolTableAlloc( void ) |
---|
80 | * |
---|
81 | * Allocate and return a new symbol table object. |
---|
82 | */ |
---|
83 | static AL_SymTab *_alSymbolTableAlloc( void ); |
---|
84 | |
---|
85 | /* |
---|
86 | * _alSymbolTableAdd( AL_SymTab *table, |
---|
87 | * const char *symname, |
---|
88 | * AL_rctree *datum ) |
---|
89 | * |
---|
90 | * Adds binding for symbol named by str to table, returning the table. |
---|
91 | */ |
---|
92 | static AL_SymTab *_alSymbolTableAdd( AL_SymTab *table, |
---|
93 | const char *symname, |
---|
94 | AL_rctree *datum ); |
---|
95 | |
---|
96 | /* |
---|
97 | * _alSymbolTableRemove( AL_SymTab *table, const char *sym ) |
---|
98 | * |
---|
99 | * Removes binding for symbol named by sym from table. |
---|
100 | */ |
---|
101 | static AL_SymTab *_alSymbolTableRemove( AL_SymTab *table, const char *sym ); |
---|
102 | |
---|
103 | /* |
---|
104 | * _alSymbolTableGet( AL_SymTab *head, const char *str ) |
---|
105 | * |
---|
106 | * Returns the definition associated with the symbol named by str, or NULL if |
---|
107 | * no such definition exists. |
---|
108 | */ |
---|
109 | static AL_rctree *_alSymbolTableGet( AL_SymTab *head, const char *str ); |
---|
110 | |
---|
111 | /* |
---|
112 | * _alSymbolTableDestroy( AL_SymTab *head ) |
---|
113 | * |
---|
114 | * Destroys the symbol table head. |
---|
115 | */ |
---|
116 | static void _alSymbolTableDestroy( AL_SymTab *head ); |
---|
117 | |
---|
118 | /* |
---|
119 | * is_string( const char *tokenname ) |
---|
120 | * |
---|
121 | * Returns AL_TRUE if tokenname describes a string, AL_FALSE otherwise. A |
---|
122 | * string in this context means any data contained between two quotation |
---|
123 | * marks. |
---|
124 | */ |
---|
125 | static ALboolean is_string( const char *tokenname ); |
---|
126 | |
---|
127 | /* |
---|
128 | * is_int( const char *tokenname ) |
---|
129 | * |
---|
130 | * Returns AL_TRUE if tokenname describes an integer (either base 10 or 16), |
---|
131 | * AL_FALSE otherwise. |
---|
132 | */ |
---|
133 | static ALboolean is_int( const char *tokenname ); |
---|
134 | |
---|
135 | /* |
---|
136 | * is_float( const char *tokenname ) |
---|
137 | * |
---|
138 | * Returns AL_TRUE if tokenname describes a float, AL_FALSE otherwise. |
---|
139 | */ |
---|
140 | static ALboolean is_float( const char *tokenname ); |
---|
141 | |
---|
142 | /* |
---|
143 | * is_lispchar( int ch ) |
---|
144 | * |
---|
145 | * Returns AL_TRUE if ch is ( or ), AL_FALSE otherwise. |
---|
146 | */ |
---|
147 | static ALboolean is_lispchar( int ch ); |
---|
148 | |
---|
149 | /* |
---|
150 | * is_whitespace( int ch ) |
---|
151 | * |
---|
152 | * Returns AL_TRUE if ch is any form of whitespace, AL_FALSE otherwise. |
---|
153 | */ |
---|
154 | static ALboolean is_whitespace( int ch ); |
---|
155 | |
---|
156 | /* |
---|
157 | * AL_rctree_copy( AL_rctree *src ) |
---|
158 | * |
---|
159 | * Returns a copy of src, including car and cdr sections. |
---|
160 | */ |
---|
161 | static AL_rctree *AL_rctree_copy( AL_rctree *src ); |
---|
162 | |
---|
163 | /* |
---|
164 | * buildExp( const char *tokenstr, unsigned int *offset ) |
---|
165 | * |
---|
166 | * Builds an AL_rctree representation of the alrc expression in |
---|
167 | * tokenstr[*offset], setting *offset to the last scanned position, or NULL if |
---|
168 | * tokenstr[*offset...] does not describe a valid alrc expression. |
---|
169 | */ |
---|
170 | static AL_rctree *buildExp( const char *tokenstr, unsigned int *offset ); |
---|
171 | |
---|
172 | /* |
---|
173 | * getTokenStr( const char *data, char *retbuf, |
---|
174 | * ALuint *offset, ALuint size ) |
---|
175 | * |
---|
176 | * copies the next alrc token from data[*offset] to retbuf, not exceeding |
---|
177 | * size ( size is the length of retbuf ), and returning the length of the |
---|
178 | * token. -1 is returned on error. |
---|
179 | * |
---|
180 | */ |
---|
181 | static int getTokenStr( const char *data, char *retbuf, |
---|
182 | ALuint *offset, ALuint size ); |
---|
183 | |
---|
184 | /* |
---|
185 | * literalExp( const char *foo ) |
---|
186 | * |
---|
187 | * Creates and returns an AL_rctree * with the value described by foo. Let's |
---|
188 | * just say that foo had better describe self-evaluating. |
---|
189 | */ |
---|
190 | static AL_rctree *literalExp( const char *foo ); |
---|
191 | |
---|
192 | /* |
---|
193 | * selfEvaluating( AL_rctree *head ) |
---|
194 | * |
---|
195 | * Return AL_TRUE if the alrc token head is self-evaluating ( integer, float, |
---|
196 | * string, bool, or primitive ), AL_FALSE otherwise. |
---|
197 | */ |
---|
198 | static ALboolean selfEvaluating( AL_rctree *head ); |
---|
199 | |
---|
200 | /* |
---|
201 | * apply( AL_rctree *proc, AL_rctree *args ) |
---|
202 | * |
---|
203 | * Calls procedure proc with arguments args, returning return. |
---|
204 | */ |
---|
205 | static AL_rctree *apply( AL_rctree *proc, AL_rctree *args ); |
---|
206 | |
---|
207 | /* |
---|
208 | * length( AL_rctree *ls ) |
---|
209 | * |
---|
210 | * Returns length of list ls, or 0 if ls is not a cons cell. |
---|
211 | */ |
---|
212 | static ALuint length( AL_rctree *ls ); |
---|
213 | |
---|
214 | /** |
---|
215 | * primitives |
---|
216 | */ |
---|
217 | |
---|
218 | /* |
---|
219 | * and_prim( AL_rctree *env, AL_rctree *args ) |
---|
220 | * |
---|
221 | * Evaluates each car in the list args, returning NULL if any evaluation is |
---|
222 | * NULL or #f, something else otherwise. |
---|
223 | */ |
---|
224 | static AL_rctree *and_prim( AL_rctree *env, AL_rctree *args ); |
---|
225 | |
---|
226 | /* |
---|
227 | * define_prim( AL_rctree *env, AL_rctree *args ) |
---|
228 | * |
---|
229 | * Defines the car of args to be the evaluation of the cadr of args, |
---|
230 | * returning said evaluation. |
---|
231 | */ |
---|
232 | static AL_rctree *define_prim( AL_rctree *env, AL_rctree *args ); |
---|
233 | |
---|
234 | /* |
---|
235 | * load_ext_prim( AL_rctree *env, AL_rctree *args ); |
---|
236 | * |
---|
237 | * Loads an extension library named by ( eval ( car args ) ). |
---|
238 | */ |
---|
239 | static AL_rctree *load_ext_prim( AL_rctree *env, AL_rctree *args ); |
---|
240 | |
---|
241 | /* |
---|
242 | * quote_prim( AL_rctree *env, AL_rctree *args ) |
---|
243 | * |
---|
244 | * Evaluates to args. |
---|
245 | */ |
---|
246 | static AL_rctree *quote_prim( AL_rctree *env, AL_rctree *args ); |
---|
247 | |
---|
248 | /* symbols to be defined as primitives */ |
---|
249 | static struct _global_table { |
---|
250 | const char *symname; |
---|
251 | alrc_prim datum; |
---|
252 | } global_primitive_table[] = { |
---|
253 | { "and", and_prim }, |
---|
254 | { "define", define_prim }, |
---|
255 | { "load-extension", load_ext_prim }, |
---|
256 | { "quote", quote_prim }, |
---|
257 | { NULL, NULL } |
---|
258 | }; |
---|
259 | |
---|
260 | /* string defining the default environment */ |
---|
261 | static const char *default_environment = |
---|
262 | "(define speaker-num 2)" |
---|
263 | "(define display-banner #t)" |
---|
264 | "(define source-gain 1.0)"; |
---|
265 | |
---|
266 | /* FIXME: get rid of this */ |
---|
267 | const AL_rctree scmtrue = { ALRC_BOOL, { 1 } }; |
---|
268 | |
---|
269 | /* |
---|
270 | * _alParseConfig( void ) |
---|
271 | * |
---|
272 | * Parse the openalrc config file, if any. Returns AL_TRUE if one was found |
---|
273 | * and contained valid openalrc syntax, AL_FALSE otherwise. |
---|
274 | * |
---|
275 | * FIXME: clean this up. |
---|
276 | */ |
---|
277 | ALboolean _alParseConfig( void ) { |
---|
278 | AL_rctree *temp; |
---|
279 | ALboolean retval; |
---|
280 | char *rcbuf; |
---|
281 | int i; |
---|
282 | |
---|
283 | if(root != NULL) { |
---|
284 | /* already been here */ |
---|
285 | return AL_TRUE; |
---|
286 | } |
---|
287 | |
---|
288 | for(i = 0; global_primitive_table[i].symname != NULL; i++) { |
---|
289 | temp = _alRcTreeAlloc(); |
---|
290 | |
---|
291 | temp->type = ALRC_PRIMITIVE; |
---|
292 | temp->data.proc = global_primitive_table[i].datum; |
---|
293 | |
---|
294 | glsyms = _alSymbolTableAdd( glsyms, |
---|
295 | global_primitive_table[i].symname, |
---|
296 | temp ); |
---|
297 | } |
---|
298 | |
---|
299 | /* now, evaluate our default environment */ |
---|
300 | root = _alEvalStr( default_environment ); |
---|
301 | if(root == NULL) { |
---|
302 | _alDebug(ALD_CONFIG, __FILE__, __LINE__, "Invalid default"); |
---|
303 | return AL_FALSE; |
---|
304 | } |
---|
305 | |
---|
306 | _alRcTreeFree( root ); |
---|
307 | root = NULL; |
---|
308 | |
---|
309 | /* now, parse user's config */ |
---|
310 | rcbuf = _alOpenRcFile(); |
---|
311 | if(rcbuf == NULL) { |
---|
312 | return AL_FALSE; |
---|
313 | } |
---|
314 | |
---|
315 | root = _alEvalStr( rcbuf ); |
---|
316 | |
---|
317 | retval = AL_TRUE; |
---|
318 | if(root == NULL) { |
---|
319 | retval = AL_FALSE; |
---|
320 | } |
---|
321 | |
---|
322 | _alRcTreeFree( root ); |
---|
323 | root = NULL; |
---|
324 | |
---|
325 | free( rcbuf ); |
---|
326 | |
---|
327 | return retval; |
---|
328 | } |
---|
329 | |
---|
330 | /* |
---|
331 | * _alOpenRcFile( void ); |
---|
332 | * |
---|
333 | * Opens any openalrc file and returns its contents. |
---|
334 | */ |
---|
335 | static char *_alOpenRcFile( void ) { |
---|
336 | FILE *fh = NULL; |
---|
337 | struct stat buf; |
---|
338 | static char pathname[PATH_MAX]; |
---|
339 | char *retval = NULL; |
---|
340 | unsigned long filelen = 0; |
---|
341 | int i; |
---|
342 | |
---|
343 | #ifndef __MORPHOS__ |
---|
344 | /* |
---|
345 | * try home dir |
---|
346 | */ |
---|
347 | snprintf(pathname, sizeof(pathname), "%s/.%s", getenv("HOME"), _AL_FNAME); |
---|
348 | #else |
---|
349 | snprintf(pathname, sizeof(pathname), "ENV:%s", _AL_FNAME); |
---|
350 | #endif |
---|
351 | if(stat(pathname, &buf) != -1) { |
---|
352 | fh = fopen(pathname, "rb"); |
---|
353 | |
---|
354 | /* for later malloc, get size */ |
---|
355 | filelen = buf.st_size; |
---|
356 | } else { |
---|
357 | /* try system wide OpenAL config file */ |
---|
358 | snprintf(pathname, sizeof(pathname), "/etc/%s", _AL_FNAME); |
---|
359 | if(stat(pathname, &buf) != -1) { |
---|
360 | fh = fopen(pathname, "rb"); |
---|
361 | |
---|
362 | /* for later malloc, get size */ |
---|
363 | filelen = buf.st_size; |
---|
364 | } |
---|
365 | } |
---|
366 | |
---|
367 | if( fh == NULL ) { |
---|
368 | return NULL; |
---|
369 | } |
---|
370 | |
---|
371 | retval = malloc(filelen + 1); |
---|
372 | if(retval == NULL) { |
---|
373 | return NULL; |
---|
374 | } |
---|
375 | |
---|
376 | fread(retval, filelen, 1, fh); |
---|
377 | retval[filelen] = '\0'; |
---|
378 | |
---|
379 | fclose( fh ); |
---|
380 | |
---|
381 | i = strlen( retval ); |
---|
382 | |
---|
383 | /* trim newlines */ |
---|
384 | while(retval[--i] == '\n') { |
---|
385 | retval[i] = '\0'; |
---|
386 | } |
---|
387 | |
---|
388 | return retval; |
---|
389 | } |
---|
390 | |
---|
391 | /* |
---|
392 | * is_float( const char *tokenname ) |
---|
393 | * |
---|
394 | * Returns AL_TRUE if tokenname describes a float, AL_FALSE otherwise. |
---|
395 | */ |
---|
396 | static ALboolean is_float( const char *tokenname ) { |
---|
397 | int i = strlen( tokenname ); |
---|
398 | int c; |
---|
399 | |
---|
400 | while(i--) { |
---|
401 | c = tokenname[i]; |
---|
402 | |
---|
403 | if((isdigit(c) == 0) && |
---|
404 | (c != '-') && |
---|
405 | (c != '.')) { |
---|
406 | return AL_FALSE; |
---|
407 | } |
---|
408 | } |
---|
409 | |
---|
410 | return AL_TRUE; |
---|
411 | } |
---|
412 | |
---|
413 | /* |
---|
414 | * is_int( const char *tokenname ) |
---|
415 | * |
---|
416 | * Returns AL_TRUE if tokenname describes an integer (either base 10 or 16), |
---|
417 | * AL_FALSE otherwise. |
---|
418 | */ |
---|
419 | ALboolean is_int( const char *tokenname ) { |
---|
420 | int i = strlen(tokenname); |
---|
421 | int c; |
---|
422 | |
---|
423 | while(i--) { |
---|
424 | c = tokenname[i]; |
---|
425 | |
---|
426 | if(isdigit(c) == 0) { |
---|
427 | return AL_FALSE; |
---|
428 | } |
---|
429 | } |
---|
430 | |
---|
431 | return AL_TRUE; |
---|
432 | } |
---|
433 | |
---|
434 | /* |
---|
435 | * is_string( const char *tokenname ) |
---|
436 | * |
---|
437 | * Returns AL_TRUE if tokenname describes a string, AL_FALSE otherwise. A |
---|
438 | * string in this context means any data contained between two quotation |
---|
439 | * marks. |
---|
440 | */ |
---|
441 | ALboolean is_string( const char *tokenname ) { |
---|
442 | int i = strlen( tokenname ); |
---|
443 | int c; |
---|
444 | |
---|
445 | if(tokenname[0] != '"') { |
---|
446 | return AL_FALSE; |
---|
447 | } |
---|
448 | |
---|
449 | while(i--) { |
---|
450 | c = tokenname[i]; |
---|
451 | |
---|
452 | if((isgraph(c) == 0) && |
---|
453 | (isspace(c) == 0)) { |
---|
454 | _alDebug(ALD_CONFIG, __FILE__, __LINE__, |
---|
455 | "tokenname %s failed at %d '%c'", |
---|
456 | tokenname, i, tokenname[i]); |
---|
457 | |
---|
458 | return AL_FALSE; |
---|
459 | } |
---|
460 | } |
---|
461 | |
---|
462 | return AL_TRUE; |
---|
463 | } |
---|
464 | |
---|
465 | /* |
---|
466 | * is_lispchar( int ch ) |
---|
467 | * |
---|
468 | * Returns AL_TRUE if ch is ( or ), AL_FALSE otherwise. |
---|
469 | */ |
---|
470 | static ALboolean is_lispchar( int ch ) { |
---|
471 | switch(ch) { |
---|
472 | case ')': |
---|
473 | case '(': |
---|
474 | return AL_TRUE; |
---|
475 | default: |
---|
476 | break; |
---|
477 | } |
---|
478 | |
---|
479 | return AL_FALSE; |
---|
480 | } |
---|
481 | |
---|
482 | /* |
---|
483 | * is_whitespace( int ch ) |
---|
484 | * |
---|
485 | * Returns AL_TRUE if ch is any form of whitespace, AL_FALSE otherwise. |
---|
486 | */ |
---|
487 | static ALboolean is_whitespace( int ch ) { |
---|
488 | switch(ch) { |
---|
489 | case ' ': |
---|
490 | case '\t': |
---|
491 | case '\n': |
---|
492 | case '\r': |
---|
493 | return AL_TRUE; |
---|
494 | default: |
---|
495 | break; |
---|
496 | } |
---|
497 | |
---|
498 | return AL_FALSE; |
---|
499 | } |
---|
500 | |
---|
501 | /* |
---|
502 | * Returns AL_TRUE if foo[offset...] describes a float. Instead of simply |
---|
503 | * being limited to the NUL character, any form of whitespace or moving into |
---|
504 | * foo[len] is also a terminating condition. |
---|
505 | */ |
---|
506 | static int is_floatWS( const char *foo, ALuint offset, size_t len ) { |
---|
507 | int decimalPoints = 0; |
---|
508 | ALuint i = offset; |
---|
509 | |
---|
510 | if ( offset >= len ) { |
---|
511 | return -1; |
---|
512 | } |
---|
513 | |
---|
514 | if( foo[i] == '-' ) { |
---|
515 | i++; |
---|
516 | } |
---|
517 | |
---|
518 | while( foo[i] && !is_whitespace( foo[i] ) && ( i < len ) ) { |
---|
519 | if(!isdigit( (int) foo[i] )) { |
---|
520 | if( foo[i] == '.' ) { |
---|
521 | if( decimalPoints > 1 ) { |
---|
522 | return -1; |
---|
523 | } |
---|
524 | |
---|
525 | decimalPoints++; |
---|
526 | } else { |
---|
527 | return -1; |
---|
528 | } |
---|
529 | } |
---|
530 | |
---|
531 | i++; |
---|
532 | } |
---|
533 | |
---|
534 | return i - offset; |
---|
535 | } |
---|
536 | |
---|
537 | /* |
---|
538 | * _alGlobalBinding( const char *str ) |
---|
539 | * |
---|
540 | * If str names an existing alrc symbol, return a pointer to the value |
---|
541 | * associated with that symbol. Otherwise, return NULL. |
---|
542 | * |
---|
543 | */ |
---|
544 | AL_rctree *_alGlobalBinding( const char *str ) { |
---|
545 | AL_rctree *retval; |
---|
546 | |
---|
547 | retval = _alSymbolTableGet( glsyms, str ); |
---|
548 | |
---|
549 | if( retval == NULL ) { |
---|
550 | _alDebug( ALD_CONFIG, __FILE__, __LINE__, |
---|
551 | "could not resolve %s", str ); |
---|
552 | } |
---|
553 | |
---|
554 | return retval; |
---|
555 | } |
---|
556 | |
---|
557 | /* |
---|
558 | * _alSymbolTableGet( AL_SymTab *head, const char *str ) |
---|
559 | * |
---|
560 | * Returns the definition associated with the symbol named by str, or NULL if |
---|
561 | * no such definition exists. |
---|
562 | */ |
---|
563 | static AL_rctree *_alSymbolTableGet( AL_SymTab *head, const char *str ) { |
---|
564 | int i; |
---|
565 | |
---|
566 | if(head == NULL) { |
---|
567 | return NULL; |
---|
568 | } |
---|
569 | |
---|
570 | i = strncmp(head->str, str, ALRC_MAXSTRLEN); |
---|
571 | |
---|
572 | if(i < 0) { |
---|
573 | return _alSymbolTableGet(head->left, str); |
---|
574 | } else if (i == 0) { |
---|
575 | return head->datum; |
---|
576 | } else if (i > 0) { |
---|
577 | return _alSymbolTableGet(head->right, str); |
---|
578 | } |
---|
579 | |
---|
580 | return NULL; |
---|
581 | } |
---|
582 | |
---|
583 | /* |
---|
584 | * _alSymbolTableAdd( AL_SymTab *table, const char *sym, AL_rctree *datum ) |
---|
585 | * |
---|
586 | * Adds binding for symbol named by sym to table, returning the table. |
---|
587 | * |
---|
588 | * Since AL_SymTab is a simple binary tree, this is a simple recursive |
---|
589 | * function. |
---|
590 | */ |
---|
591 | static AL_SymTab *_alSymbolTableAdd( AL_SymTab *head, const char *sym, |
---|
592 | AL_rctree *datum ) { |
---|
593 | int i; |
---|
594 | |
---|
595 | if(head == NULL) { |
---|
596 | head = _alSymbolTableAlloc(); |
---|
597 | |
---|
598 | strncpy( head->str, sym, ALRC_MAXSTRLEN ); |
---|
599 | |
---|
600 | head->datum = AL_rctree_copy( datum ); |
---|
601 | |
---|
602 | return head; |
---|
603 | } |
---|
604 | |
---|
605 | i = strncmp(head->str, sym, ALRC_MAXSTRLEN); |
---|
606 | |
---|
607 | if(i < 0) { |
---|
608 | head->left = _alSymbolTableAdd( head->left, sym, datum); |
---|
609 | |
---|
610 | return head; |
---|
611 | } |
---|
612 | |
---|
613 | if(i == 0) { |
---|
614 | strncpy(head->str, sym, ALRC_MAXSTRLEN); |
---|
615 | |
---|
616 | head->datum = AL_rctree_copy( datum ); |
---|
617 | |
---|
618 | return head; |
---|
619 | } |
---|
620 | |
---|
621 | if(i > 0) { |
---|
622 | head->right = _alSymbolTableAdd( head->right, sym, datum ); |
---|
623 | return head; |
---|
624 | } |
---|
625 | |
---|
626 | return NULL; |
---|
627 | } |
---|
628 | |
---|
629 | /* |
---|
630 | * _alSymbolTableAlloc( void ) |
---|
631 | * |
---|
632 | * Allocate and return a new symbol table object. |
---|
633 | */ |
---|
634 | AL_SymTab *_alSymbolTableAlloc( void ) { |
---|
635 | AL_SymTab *retval; |
---|
636 | |
---|
637 | retval = malloc( sizeof *retval ); |
---|
638 | if(retval == NULL) { |
---|
639 | return NULL; |
---|
640 | } |
---|
641 | |
---|
642 | memset( retval->str, 0, ALRC_MAXSTRLEN + 1 ); |
---|
643 | |
---|
644 | retval->datum = NULL; |
---|
645 | retval->left = NULL; |
---|
646 | retval->right = NULL; |
---|
647 | |
---|
648 | return retval; |
---|
649 | } |
---|
650 | |
---|
651 | /* |
---|
652 | * define_prim( AL_rctree *env, AL_rctree *args ) |
---|
653 | * |
---|
654 | * Defines the car of args to be the evaluation of the cadr of args, |
---|
655 | * returning said evaluation. |
---|
656 | */ |
---|
657 | static AL_rctree *define_prim( UNUSED(AL_rctree *env), AL_rctree *args ) { |
---|
658 | AL_rctree *symbol; |
---|
659 | AL_rctree *retval; |
---|
660 | |
---|
661 | symbol = alrc_car( args ); |
---|
662 | retval = _alEval( alrc_cadr( args ) ); |
---|
663 | |
---|
664 | if((symbol == NULL) || (retval == NULL)) { |
---|
665 | _alDebug(ALD_CONFIG, __FILE__, __LINE__, |
---|
666 | "define_prim fail" ); |
---|
667 | |
---|
668 | return NULL; |
---|
669 | } |
---|
670 | |
---|
671 | glsyms = _alSymbolTableAdd( glsyms, |
---|
672 | symbol->data.str.c_str, |
---|
673 | retval ); |
---|
674 | |
---|
675 | _alDebug( ALD_CONFIG, __FILE__, __LINE__, |
---|
676 | "define %s", symbol->data.str.c_str ); |
---|
677 | |
---|
678 | return retval; |
---|
679 | } |
---|
680 | |
---|
681 | /* |
---|
682 | * and_prim( AL_rctree *env, AL_rctree *args ) |
---|
683 | * |
---|
684 | * Evaluates each car in the list args, returning NULL if any evaluation is |
---|
685 | * NULL or #f, something else otherwise. |
---|
686 | */ |
---|
687 | static AL_rctree *and_prim( UNUSED(AL_rctree *env), AL_rctree *args ) { |
---|
688 | AL_rctree *result = NULL; |
---|
689 | AL_rctree *itr; |
---|
690 | AL_rctree *temp; |
---|
691 | ALboolean keepgoing = AL_TRUE; |
---|
692 | |
---|
693 | itr = args; |
---|
694 | while(itr && (keepgoing == AL_TRUE)) { |
---|
695 | temp = alrc_cdr( itr ); |
---|
696 | |
---|
697 | result = _alEval( alrc_car( itr ) ); |
---|
698 | |
---|
699 | if( result == NULL ) { |
---|
700 | result = _alRcTreeAlloc(); |
---|
701 | result->type = ALRC_BOOL; |
---|
702 | result->data.i = AL_FALSE; |
---|
703 | |
---|
704 | _alDebug( ALD_CONFIG, __FILE__, __LINE__, |
---|
705 | "and_prim false" ); |
---|
706 | |
---|
707 | return result; |
---|
708 | } |
---|
709 | |
---|
710 | itr = temp; |
---|
711 | |
---|
712 | } |
---|
713 | |
---|
714 | result = _alRcTreeAlloc(); |
---|
715 | result->type = ALRC_BOOL; |
---|
716 | result->data.i = AL_TRUE; |
---|
717 | |
---|
718 | return result; |
---|
719 | } |
---|
720 | |
---|
721 | |
---|
722 | /* |
---|
723 | * _alDestroyConfig( void ) |
---|
724 | * |
---|
725 | * Deallocate the memory reserved in the call to _alParseConfig, as well as |
---|
726 | * any alrc objects that have been created since that point. |
---|
727 | */ |
---|
728 | void _alDestroyConfig( void ) { |
---|
729 | _alSymbolTableDestroy( glsyms ); |
---|
730 | glsyms = NULL; |
---|
731 | |
---|
732 | _alRcTreeDestroyAll(); /* gc replacement. sigh */ |
---|
733 | |
---|
734 | return; |
---|
735 | } |
---|
736 | |
---|
737 | /* |
---|
738 | * _alSymbolTableDestroy( AL_SymTab *head ) |
---|
739 | * |
---|
740 | * Destroys the symbol table head. |
---|
741 | */ |
---|
742 | static void _alSymbolTableDestroy( AL_SymTab *head ) { |
---|
743 | if( head == NULL ) { |
---|
744 | return; |
---|
745 | } |
---|
746 | |
---|
747 | if( head->left ) { |
---|
748 | _alSymbolTableDestroy( head->left ); |
---|
749 | } |
---|
750 | if( head->right ) { |
---|
751 | _alSymbolTableDestroy( head->right ); |
---|
752 | } |
---|
753 | |
---|
754 | free( head ); |
---|
755 | |
---|
756 | return; |
---|
757 | } |
---|
758 | |
---|
759 | |
---|
760 | |
---|
761 | /* |
---|
762 | * load_ext_prim( AL_rctree *env, AL_rctree *args ); |
---|
763 | * |
---|
764 | * Loads an extension library named by ( eval ( car args ) ). |
---|
765 | * |
---|
766 | * FIXME: return #t or something? |
---|
767 | */ |
---|
768 | static AL_rctree *load_ext_prim(UNUSED(AL_rctree *env), AL_rctree *args) { |
---|
769 | AL_rctree *retval; |
---|
770 | static char fname[128]; /* FIXME */ |
---|
771 | char *symname; |
---|
772 | size_t len; |
---|
773 | |
---|
774 | if(args->type != ALRC_STRING) { |
---|
775 | _alDebug(ALD_CONFIG, __FILE__, __LINE__, |
---|
776 | "syntax error: load_ext_prim passed type is 0x%x", |
---|
777 | args->type); |
---|
778 | |
---|
779 | return NULL; |
---|
780 | } |
---|
781 | |
---|
782 | /* skip first and last quote */ |
---|
783 | symname = args->data.str.c_str; |
---|
784 | len = args->data.str.len; |
---|
785 | |
---|
786 | /* copy data */ |
---|
787 | memcpy(fname, symname, len); |
---|
788 | fname[len] = '\0'; |
---|
789 | |
---|
790 | /* prepare retval */ |
---|
791 | |
---|
792 | retval = _alRcTreeAlloc(); |
---|
793 | retval->type = ALRC_BOOL; |
---|
794 | retval->data.i = AL_TRUE; |
---|
795 | |
---|
796 | if(_alLoadDL(fname) == AL_FALSE) |
---|
797 | { |
---|
798 | _alDebug(ALD_CONFIG, __FILE__, __LINE__, |
---|
799 | "Couldn't load %s", fname); |
---|
800 | |
---|
801 | retval->data.i = AL_FALSE; |
---|
802 | } |
---|
803 | |
---|
804 | return retval; |
---|
805 | } |
---|
806 | |
---|
807 | /* |
---|
808 | * quote_prim( AL_rctree *env, AL_rctree *args ) |
---|
809 | * |
---|
810 | * Evaluates to args. |
---|
811 | */ |
---|
812 | static AL_rctree *quote_prim(UNUSED(AL_rctree *env), AL_rctree *args) { |
---|
813 | return args; |
---|
814 | } |
---|
815 | |
---|
816 | /* |
---|
817 | * _alGetGlobalScalar( const char *str, ALRcEnum type, ALvoid *retref ) |
---|
818 | * |
---|
819 | * If str names an existing alrc symbol, and type matches the type of that |
---|
820 | * symbol, *retref is populated with the value of that symbol and this call |
---|
821 | * returns AL_TRUE. Otherwise, AL_FALSE is returned. |
---|
822 | * |
---|
823 | * NOTE: future revisions should replace this with a call to rc_lookup. |
---|
824 | * |
---|
825 | * FIXME: fill out literal support |
---|
826 | */ |
---|
827 | ALboolean _alGetGlobalScalar( const char *str, ALRcEnum type, ALvoid *retref ) { |
---|
828 | AL_rctree *sym; |
---|
829 | ALfloat *fvp; |
---|
830 | ALint *ivp; |
---|
831 | |
---|
832 | if(retref == NULL) { |
---|
833 | return AL_FALSE; |
---|
834 | } |
---|
835 | |
---|
836 | /* [fi]vp, the dereference helper */ |
---|
837 | fvp = retref; |
---|
838 | ivp = retref; |
---|
839 | |
---|
840 | sym = _alGlobalBinding(str); |
---|
841 | if(sym == NULL) { |
---|
842 | return AL_FALSE; |
---|
843 | } |
---|
844 | |
---|
845 | switch(sym->type) { |
---|
846 | case ALRC_INTEGER: |
---|
847 | case ALRC_BOOL: |
---|
848 | switch(type) { |
---|
849 | case ALRC_INTEGER: |
---|
850 | case ALRC_BOOL: |
---|
851 | *ivp = sym->data.i; |
---|
852 | return AL_TRUE; |
---|
853 | case ALRC_FLOAT: |
---|
854 | *fvp = sym->data.i; |
---|
855 | return AL_TRUE; |
---|
856 | default: |
---|
857 | return AL_FALSE; |
---|
858 | } |
---|
859 | case ALRC_FLOAT: |
---|
860 | switch(type) { |
---|
861 | case ALRC_INTEGER: |
---|
862 | case ALRC_BOOL: |
---|
863 | *ivp = sym->data.f; |
---|
864 | return AL_TRUE; |
---|
865 | case ALRC_FLOAT: |
---|
866 | *fvp = sym->data.f; |
---|
867 | return AL_TRUE; |
---|
868 | default: |
---|
869 | return AL_FALSE; |
---|
870 | } |
---|
871 | default: |
---|
872 | return AL_FALSE; |
---|
873 | } |
---|
874 | } |
---|
875 | |
---|
876 | /* |
---|
877 | * _alDefine( const char *symname, AL_rctree *value ) |
---|
878 | * |
---|
879 | * Bind a symbol, named by symname, to the evaluation of value. |
---|
880 | */ |
---|
881 | AL_rctree *_alDefine( const char *symname, AL_rctree *value ) { |
---|
882 | glsyms = _alSymbolTableAdd( glsyms, symname, _alEval( value )); |
---|
883 | |
---|
884 | _alDebug( ALD_CONFIG, __FILE__, __LINE__, "defining %s", symname ); |
---|
885 | |
---|
886 | return value; |
---|
887 | } |
---|
888 | |
---|
889 | /* |
---|
890 | * selfEvaluating( AL_rctree *head ) |
---|
891 | * |
---|
892 | * Return AL_TRUE if the alrc token head is self-evaluating ( integer, float, |
---|
893 | * string, bool, or primitive ), AL_FALSE otherwise. |
---|
894 | */ |
---|
895 | static ALboolean selfEvaluating( AL_rctree *head ) { |
---|
896 | switch( head->type ) { |
---|
897 | case ALRC_INVALID: |
---|
898 | case ALRC_INTEGER: |
---|
899 | case ALRC_FLOAT: |
---|
900 | case ALRC_STRING: |
---|
901 | case ALRC_BOOL: |
---|
902 | case ALRC_PRIMITIVE: |
---|
903 | return AL_TRUE; |
---|
904 | break; |
---|
905 | case ALRC_SYMBOL: |
---|
906 | case ALRC_CONSCELL: |
---|
907 | default: |
---|
908 | break; |
---|
909 | } |
---|
910 | |
---|
911 | return AL_FALSE; |
---|
912 | } |
---|
913 | |
---|
914 | /* |
---|
915 | * alrc_cons( AL_rctree *ls1, AL_rctree *ls2 ) |
---|
916 | * |
---|
917 | * Create and return a cons cell, with the car section pointing to ls1 and the |
---|
918 | * cdr section pointing to ls2. |
---|
919 | */ |
---|
920 | AL_rctree *alrc_cons( AL_rctree *ls1, AL_rctree *ls2 ) { |
---|
921 | AL_rctree *newc; |
---|
922 | |
---|
923 | assert( ls1->type == ALRC_CONSCELL ); |
---|
924 | |
---|
925 | if( ls1->data.ccell.cdr == NULL ) { |
---|
926 | newc = ls1->data.ccell.cdr = _alRcTreeAlloc(); |
---|
927 | newc->type = ALRC_CONSCELL; |
---|
928 | |
---|
929 | newc->data.ccell.car = ls2; |
---|
930 | |
---|
931 | return newc; |
---|
932 | } |
---|
933 | |
---|
934 | alrc_cons( alrc_cdr(ls1), ls2 ); |
---|
935 | |
---|
936 | return ls1; |
---|
937 | } |
---|
938 | |
---|
939 | /* |
---|
940 | * alrc_car( AL_rctree *ls ) |
---|
941 | * |
---|
942 | * Return the car section of the cons cell named by ls, or NULL if ls is not a |
---|
943 | * cons cell. |
---|
944 | */ |
---|
945 | AL_rctree *alrc_car( AL_rctree *ls ) { |
---|
946 | assert( ls->type == ALRC_CONSCELL ); |
---|
947 | |
---|
948 | return ls->data.ccell.car; |
---|
949 | } |
---|
950 | |
---|
951 | /* |
---|
952 | * alrc_cdr( AL_rctree *ls ) |
---|
953 | * |
---|
954 | * Return the cdr section of the cons cell named by ls, or NULL if ls is not a |
---|
955 | * cons cell. |
---|
956 | */ |
---|
957 | AL_rctree *alrc_cdr( AL_rctree *ls ) { |
---|
958 | assert( ls->type == ALRC_CONSCELL ); |
---|
959 | |
---|
960 | return ls->data.ccell.cdr; |
---|
961 | } |
---|
962 | |
---|
963 | /* |
---|
964 | * apply( AL_rctree *proc, AL_rctree *args ) |
---|
965 | * |
---|
966 | * Calls procedure proc with arguments args, returning return. |
---|
967 | */ |
---|
968 | AL_rctree *apply( AL_rctree *procobj, AL_rctree *args ) { |
---|
969 | AL_rctree *lobj; |
---|
970 | AL_rctree *prototype; |
---|
971 | AL_rctree *body; |
---|
972 | AL_rctree *retval; |
---|
973 | int i; |
---|
974 | |
---|
975 | if( procobj->type == ALRC_PRIMITIVE ) { |
---|
976 | alrc_prim proc = procobj->data.proc; |
---|
977 | |
---|
978 | return proc(root, args); |
---|
979 | } |
---|
980 | |
---|
981 | if( procobj->type != ALRC_CONSCELL) { |
---|
982 | assert(0); |
---|
983 | |
---|
984 | return NULL; |
---|
985 | } |
---|
986 | |
---|
987 | lobj = alrc_cdr( procobj ); |
---|
988 | |
---|
989 | prototype = alrc_car( lobj ); |
---|
990 | body = alrc_cadr( lobj ); |
---|
991 | |
---|
992 | /* lambda expression */ |
---|
993 | assert(length(prototype) == length(args)); |
---|
994 | |
---|
995 | /* build bindings */ |
---|
996 | i = length( prototype ); |
---|
997 | while(i--) { |
---|
998 | glsyms = _alSymbolTableAdd(glsyms, |
---|
999 | alrc_car(prototype)->data.str.c_str, |
---|
1000 | _alEval( alrc_car( args ))); |
---|
1001 | |
---|
1002 | |
---|
1003 | prototype = alrc_cdr(prototype); |
---|
1004 | args = alrc_cdr(args); |
---|
1005 | } |
---|
1006 | |
---|
1007 | retval = _alEval( body ); |
---|
1008 | |
---|
1009 | /* remove bindings */ |
---|
1010 | prototype = alrc_car( lobj ); |
---|
1011 | i = length( prototype ); |
---|
1012 | while(i--) { |
---|
1013 | glsyms = _alSymbolTableRemove( glsyms, |
---|
1014 | alrc_car( prototype )->data.str.c_str ); |
---|
1015 | |
---|
1016 | prototype = alrc_cdr( prototype ); |
---|
1017 | } |
---|
1018 | |
---|
1019 | return retval; |
---|
1020 | } |
---|
1021 | |
---|
1022 | /* |
---|
1023 | * length( AL_rctree *ls ) |
---|
1024 | * |
---|
1025 | * Returns length of list ls, or 0 if ls is not a cons cell. |
---|
1026 | */ |
---|
1027 | static ALuint |
---|
1028 | length( AL_rctree *ls ) |
---|
1029 | { |
---|
1030 | return ( ls == NULL || ls->type != ALRC_CONSCELL ) ? |
---|
1031 | 0 : |
---|
1032 | ( 1 + length( alrc_cdr( ls ) )); |
---|
1033 | } |
---|
1034 | |
---|
1035 | /* |
---|
1036 | * _alSymbolTableRemove( AL_SymTab *table, const char *sym ) |
---|
1037 | * |
---|
1038 | * Removes binding for symbol named by sym from table. |
---|
1039 | */ |
---|
1040 | AL_SymTab *_alSymbolTableRemove( AL_SymTab *head, const char *sym ) { |
---|
1041 | int i; |
---|
1042 | |
---|
1043 | if(head == NULL) { |
---|
1044 | return NULL; |
---|
1045 | } |
---|
1046 | |
---|
1047 | i = strncmp( head->str, sym, ALRC_MAXSTRLEN ); |
---|
1048 | if(i < 0) { |
---|
1049 | head->left = _alSymbolTableRemove( head->left, sym ); |
---|
1050 | return head; |
---|
1051 | } |
---|
1052 | if(i == 0) { |
---|
1053 | free( head ); |
---|
1054 | |
---|
1055 | return NULL; |
---|
1056 | } |
---|
1057 | if(i > 0) { |
---|
1058 | head->right = _alSymbolTableRemove( head->right, sym ); |
---|
1059 | return head; |
---|
1060 | } |
---|
1061 | |
---|
1062 | return head; |
---|
1063 | } |
---|
1064 | |
---|
1065 | /* |
---|
1066 | * AL_rctree_copy( AL_rctree *src ) |
---|
1067 | * |
---|
1068 | * Returns a copy of src, including car and cdr sections. |
---|
1069 | */ |
---|
1070 | static AL_rctree *AL_rctree_copy( AL_rctree *src ) { |
---|
1071 | AL_rctree *retval; |
---|
1072 | |
---|
1073 | if( src == NULL ) { |
---|
1074 | return NULL; |
---|
1075 | } |
---|
1076 | |
---|
1077 | retval = _alRcTreeAlloc(); |
---|
1078 | |
---|
1079 | if( src->type == ALRC_CONSCELL ) { |
---|
1080 | retval->type = ALRC_CONSCELL; |
---|
1081 | |
---|
1082 | retval->data.ccell.car = AL_rctree_copy( src->data.ccell.car ); |
---|
1083 | retval->data.ccell.cdr = AL_rctree_copy( src->data.ccell.cdr ); |
---|
1084 | |
---|
1085 | return retval; |
---|
1086 | } |
---|
1087 | |
---|
1088 | *retval = *src; |
---|
1089 | |
---|
1090 | return retval; |
---|
1091 | } |
---|
1092 | |
---|
1093 | /* |
---|
1094 | * buildExp( const char *tokenstr, unsigned int *offset ) |
---|
1095 | * |
---|
1096 | * Builds an AL_rctree representation of the alrc expression in |
---|
1097 | * tokenstr[*offset], setting *offset to the last scanned position, or NULL if |
---|
1098 | * tokenstr[*offset...] does not describe a valid alrc expression. |
---|
1099 | */ |
---|
1100 | static AL_rctree *buildExp( const char *tokenstr, unsigned int *offset ) { |
---|
1101 | AL_rctree *retval = NULL; |
---|
1102 | unsigned int len = strlen(tokenstr); |
---|
1103 | char *buffer; |
---|
1104 | |
---|
1105 | while(is_whitespace(tokenstr[*offset]) && (*offset < len)) { |
---|
1106 | (*offset)++; |
---|
1107 | } |
---|
1108 | |
---|
1109 | /* skip comments */ |
---|
1110 | while(tokenstr[*offset] == ';') { |
---|
1111 | /* FIXME: do dos crlf as well */ |
---|
1112 | while((tokenstr[*offset] != '\n') && (*offset < len)) |
---|
1113 | { |
---|
1114 | (*offset)++; |
---|
1115 | } |
---|
1116 | |
---|
1117 | while(is_whitespace(tokenstr[*offset]) && (*offset < len)) { |
---|
1118 | (*offset)++; |
---|
1119 | } |
---|
1120 | } |
---|
1121 | |
---|
1122 | if((len == 0) || (*offset >= len)) { |
---|
1123 | _alDebug( ALD_CONFIG, __FILE__, __LINE__, "NULL here"); |
---|
1124 | |
---|
1125 | return NULL; |
---|
1126 | } |
---|
1127 | |
---|
1128 | if(tokenstr[*offset] == '\'') { |
---|
1129 | /* quoted */ |
---|
1130 | (*offset)++; |
---|
1131 | |
---|
1132 | retval = _alRcTreeAlloc(); |
---|
1133 | retval->type = ALRC_CONSCELL; |
---|
1134 | |
---|
1135 | retval->data.ccell.car = _alRcTreeAlloc(); |
---|
1136 | retval->data.ccell.car->type = ALRC_SYMBOL; |
---|
1137 | snprintf(retval->data.ccell.car->data.str.c_str, ALRC_MAXSTRLEN, |
---|
1138 | "quote"); |
---|
1139 | retval->data.ccell.car->data.str.len = 5; |
---|
1140 | |
---|
1141 | retval->data.ccell.cdr = buildExp( tokenstr, offset ); |
---|
1142 | |
---|
1143 | return retval; |
---|
1144 | } |
---|
1145 | |
---|
1146 | if(tokenstr[*offset] == '(') { |
---|
1147 | /* it's a list */ |
---|
1148 | AL_rctree *foo = NULL; |
---|
1149 | AL_rctree *lp = NULL; |
---|
1150 | AL_rctree *rp = NULL; |
---|
1151 | |
---|
1152 | (*offset)++; |
---|
1153 | |
---|
1154 | retval = rp = _alRcTreeAlloc(); |
---|
1155 | retval->type = ALRC_CONSCELL; |
---|
1156 | |
---|
1157 | /* cdr */ |
---|
1158 | while((foo = buildExp(tokenstr, offset)) != NULL) { |
---|
1159 | /*car(rp, foo); */ |
---|
1160 | rp->data.ccell.car = foo; |
---|
1161 | |
---|
1162 | /* cdr(rp, l_conscell_alloc(NULL, NULL));*/ |
---|
1163 | rp->data.ccell.cdr = _alRcTreeAlloc(); |
---|
1164 | rp->data.ccell.cdr->type = ALRC_CONSCELL; |
---|
1165 | |
---|
1166 | lp = rp; |
---|
1167 | rp = rp->data.ccell.cdr; |
---|
1168 | } |
---|
1169 | |
---|
1170 | if( lp != NULL ) { |
---|
1171 | _alRcTreeFree( lp->data.ccell.cdr ); |
---|
1172 | lp->data.ccell.cdr = NULL; |
---|
1173 | } |
---|
1174 | |
---|
1175 | return (AL_rctree *) retval; |
---|
1176 | } |
---|
1177 | |
---|
1178 | if(tokenstr[*offset] == ')') { |
---|
1179 | (*offset)++; |
---|
1180 | |
---|
1181 | return NULL; |
---|
1182 | } |
---|
1183 | |
---|
1184 | buffer = malloc( len + 1 ); |
---|
1185 | |
---|
1186 | getTokenStr(tokenstr, buffer, offset, len); |
---|
1187 | |
---|
1188 | retval = literalExp( buffer ); |
---|
1189 | |
---|
1190 | free( buffer ); |
---|
1191 | |
---|
1192 | return retval; |
---|
1193 | } |
---|
1194 | |
---|
1195 | /* |
---|
1196 | * literalExp( const char *foo ) |
---|
1197 | * |
---|
1198 | * Creates and returns an AL_rctree * with the value described by foo. Let's |
---|
1199 | * just say that foo had better describe self-evaluating. |
---|
1200 | */ |
---|
1201 | static AL_rctree *literalExp( const char *foo ) { |
---|
1202 | AL_rctree *retval = _alRcTreeAlloc(); |
---|
1203 | |
---|
1204 | assert(foo[0] != '('); |
---|
1205 | assert(foo[0] != '\''); |
---|
1206 | assert(foo[0] != '('); |
---|
1207 | |
---|
1208 | if ((foo[0] == '#') && (foo[1] == 'p')) |
---|
1209 | { |
---|
1210 | long foop = strtol( &foo[2], NULL, 0 ); |
---|
1211 | |
---|
1212 | retval->type = ALRC_POINTER; |
---|
1213 | retval->data.p = (void *) foop; |
---|
1214 | } |
---|
1215 | else if ((foo[0] == '#') && ((foo[1] == 't') || (foo[1] == 'f'))) |
---|
1216 | { |
---|
1217 | switch(foo[1]) { |
---|
1218 | case 'f': |
---|
1219 | retval->data.b = AL_FALSE; |
---|
1220 | break; |
---|
1221 | case 't': |
---|
1222 | retval->data.b = AL_TRUE; |
---|
1223 | break; |
---|
1224 | default: |
---|
1225 | assert( 0 ); |
---|
1226 | _alRcTreeFree( retval ); |
---|
1227 | |
---|
1228 | return NULL; |
---|
1229 | } |
---|
1230 | |
---|
1231 | retval->type = ALRC_BOOL; |
---|
1232 | } |
---|
1233 | else if (is_int(foo)) |
---|
1234 | { |
---|
1235 | retval->type = ALRC_INTEGER; |
---|
1236 | retval->data.i = atoi( foo ); |
---|
1237 | } |
---|
1238 | else if (is_float( foo )) |
---|
1239 | { |
---|
1240 | retval->type = ALRC_FLOAT; |
---|
1241 | retval->data.f = atof( foo ); |
---|
1242 | } |
---|
1243 | else if (is_string(foo)) |
---|
1244 | { |
---|
1245 | retval->type = ALRC_STRING; |
---|
1246 | snprintf( retval->data.str.c_str, ALRC_MAXSTRLEN, &foo[1] ); |
---|
1247 | |
---|
1248 | retval->data.str.len = strlen( foo ) - 2; |
---|
1249 | } |
---|
1250 | else |
---|
1251 | { |
---|
1252 | retval->type = ALRC_SYMBOL; |
---|
1253 | snprintf( retval->data.str.c_str, ALRC_MAXSTRLEN, foo ); |
---|
1254 | |
---|
1255 | retval->data.str.len = strlen( foo ); |
---|
1256 | } |
---|
1257 | |
---|
1258 | return retval; |
---|
1259 | } |
---|
1260 | |
---|
1261 | /* |
---|
1262 | * _alEval( AL_rctree *head ) |
---|
1263 | * |
---|
1264 | * Evaluate an expression in AL_rctree form. |
---|
1265 | */ |
---|
1266 | static AL_rctree *_alEval( AL_rctree *head ) { |
---|
1267 | AL_rctree *retval; |
---|
1268 | |
---|
1269 | if(head == NULL) { |
---|
1270 | return NULL; |
---|
1271 | } |
---|
1272 | |
---|
1273 | if( selfEvaluating( head ) == AL_TRUE ) { |
---|
1274 | return head; |
---|
1275 | } |
---|
1276 | |
---|
1277 | if( head->type == ALRC_CONSCELL ) { |
---|
1278 | AL_rctree *procsym = alrc_car( head ); |
---|
1279 | AL_rctree *args; |
---|
1280 | AL_rctree *proc; |
---|
1281 | |
---|
1282 | if( procsym == NULL ) { |
---|
1283 | _alDebug( ALD_CONFIG, __FILE__, __LINE__, |
---|
1284 | "trouble" ); |
---|
1285 | |
---|
1286 | return NULL; |
---|
1287 | } |
---|
1288 | |
---|
1289 | proc = _alGlobalBinding( procsym->data.str.c_str ); |
---|
1290 | args = alrc_cdr(head); |
---|
1291 | |
---|
1292 | if( proc == NULL ) { |
---|
1293 | _alDebug( ALD_CONFIG, __FILE__, __LINE__, |
---|
1294 | "could not apply %s", |
---|
1295 | alrc_car(head)->data.str.c_str ); |
---|
1296 | |
---|
1297 | return NULL; |
---|
1298 | } |
---|
1299 | |
---|
1300 | return apply( proc, args ); |
---|
1301 | } else { |
---|
1302 | /* symbols are resolved */ |
---|
1303 | retval = _alGlobalBinding( head->data.str.c_str ); |
---|
1304 | if(retval == NULL) { |
---|
1305 | _alDebug( ALD_CONFIG, __FILE__, __LINE__, |
---|
1306 | "invalid symbol %s", head->data.str.c_str ); |
---|
1307 | } |
---|
1308 | |
---|
1309 | return retval; |
---|
1310 | } |
---|
1311 | } |
---|
1312 | |
---|
1313 | /* |
---|
1314 | * getTokenStr( const char *data, char *retbuf, |
---|
1315 | * ALuint *offset, ALuint size ) |
---|
1316 | * |
---|
1317 | * copies the next alrc token from data[*offset] to retbuf, not exceeding |
---|
1318 | * size ( size is the length of retbuf ), and returning the length of the |
---|
1319 | * token. -1 is returned on error. |
---|
1320 | * |
---|
1321 | */ |
---|
1322 | static int getTokenStr( const char *data, char *outp, |
---|
1323 | ALuint *offsetp, ALuint size ) { |
---|
1324 | ALuint offset = *offsetp; |
---|
1325 | int start = 0; |
---|
1326 | int end = 0; |
---|
1327 | int tokenlen = 0; |
---|
1328 | size_t retlen = 0; |
---|
1329 | |
---|
1330 | while(is_whitespace(data[offset]) && (offset < size)) { |
---|
1331 | offset++; |
---|
1332 | } |
---|
1333 | |
---|
1334 | if((data[offset] == '\'') || |
---|
1335 | (data[offset] == '(') || |
---|
1336 | (data[offset] == ')')) |
---|
1337 | { |
---|
1338 | start = offset++; |
---|
1339 | end = offset; |
---|
1340 | |
---|
1341 | } else if((data[offset] == '#') && (data[offset+1] == 'p')) { |
---|
1342 | /* pointer value */ |
---|
1343 | start = offset; |
---|
1344 | |
---|
1345 | offset += 2; |
---|
1346 | |
---|
1347 | if((data[offset] == '0') && (data[offset+1] == 'x')) { |
---|
1348 | /* in hex */ |
---|
1349 | offset += 2; |
---|
1350 | } |
---|
1351 | |
---|
1352 | while( isxdigit( (int) data[offset]) && (offset < size)) |
---|
1353 | { |
---|
1354 | offset++; |
---|
1355 | } |
---|
1356 | } else if((data[offset] == '#') && ((data[offset+1] == 'f') || (data[offset+1] == 't'))) { |
---|
1357 | /* boolean */ |
---|
1358 | start = offset; |
---|
1359 | |
---|
1360 | offset += 2; |
---|
1361 | } else if((data[offset] == '0') && (data[offset+1] == 'x')) { |
---|
1362 | /* hex numbers */ |
---|
1363 | start = offset; |
---|
1364 | |
---|
1365 | while(isdigit( (int) data[offset]) && (offset < size)) { |
---|
1366 | offset++; |
---|
1367 | } |
---|
1368 | } else if((tokenlen = is_floatWS( data, offset, size )) > 0) { |
---|
1369 | /* float */ |
---|
1370 | start = offset; |
---|
1371 | offset += tokenlen; |
---|
1372 | |
---|
1373 | } else if(data[offset] == '"') { |
---|
1374 | /* it's a string */ |
---|
1375 | start = offset; |
---|
1376 | |
---|
1377 | offset++; |
---|
1378 | |
---|
1379 | while((data[offset] != '"') && (offset < size)) { |
---|
1380 | offset++; |
---|
1381 | } |
---|
1382 | |
---|
1383 | offset++; /* get last one too */ |
---|
1384 | } else { |
---|
1385 | start = offset; |
---|
1386 | |
---|
1387 | while(!is_whitespace(data[offset]) && |
---|
1388 | !is_lispchar(data[offset]) && |
---|
1389 | (offset < size)) { |
---|
1390 | offset++; |
---|
1391 | } |
---|
1392 | |
---|
1393 | } |
---|
1394 | |
---|
1395 | if(offset > size) { |
---|
1396 | *offsetp = size; |
---|
1397 | |
---|
1398 | /* invalid expression */ |
---|
1399 | return 0; |
---|
1400 | } |
---|
1401 | |
---|
1402 | end = offset; |
---|
1403 | |
---|
1404 | retlen = end - start; |
---|
1405 | |
---|
1406 | memcpy(outp, &data[start], retlen); |
---|
1407 | |
---|
1408 | outp[retlen] = '\0'; |
---|
1409 | |
---|
1410 | *offsetp = offset; |
---|
1411 | |
---|
1412 | return strlen( outp ); |
---|
1413 | } |
---|
1414 | |
---|
1415 | /* |
---|
1416 | * _alEvalStr( const char *expression ) |
---|
1417 | * |
---|
1418 | * Evaluate an alrc expression (expression), returning result. |
---|
1419 | */ |
---|
1420 | AL_rctree *_alEvalStr( const char *expression ) { |
---|
1421 | ALuint offset = 0; |
---|
1422 | ALuint len = strlen( expression ); |
---|
1423 | AL_rctree *retval = NULL; |
---|
1424 | |
---|
1425 | while( offset < len ) { |
---|
1426 | retval = _alEval( buildExp( expression, &offset ) ); |
---|
1427 | } |
---|
1428 | |
---|
1429 | return retval; |
---|
1430 | } |
---|