/* * Copyright (c) 1999 The University of Utah and * the Computer Systems Laboratory at the University of Utah (CSL). * * This file is part of Flick, the Flexible IDL Compiler Kit. * * Flick is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * Flick is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Flick; see the file COPYING. If not, write to * the Free Software Foundation, 59 Temple Place #330, Boston, MA 02111, USA. */ #include #include #include #include #include #include #include #define min(x,y) ((x < y) ? x : y) #define max(x,y) ((x > y) ? x : y) struct scml_handler_table *scml_context::sht = 0; scml_context::scml_context() { this->flags = 0; this->stream_pos = 0; this->scope = 0; this->lvalues = create_tag_list(0); this->rvalues = this->lvalues; this->offset_size = 0; this->indent_size = 0; this->ws_queue = 0; } scml_context::~scml_context() { } void scml_context::set_flags(int the_flags) { this->flags = the_flags; } int scml_context::get_flags() { return( this->flags ); } void scml_context::set_parent(struct scml_context *sc) { this->parent = sc; } struct scml_context *scml_context::get_parent() { return( this->parent ); } void scml_context::set_stream_pos(struct scml_stream_pos *ssp) { this->stream_pos = ssp; } struct scml_stream_pos *scml_context::get_stream_pos() { return( this->stream_pos ); } void scml_context::set_cmd_def(struct scml_cmd_definition *the_def) { this->def = the_def; } struct scml_cmd_definition *scml_context::get_cmd_def() { return( this->def ); } void scml_context::set_lvalues(tag_list *tl) { this->lvalues = tl; } tag_list *scml_context::get_lvalues() { return( this->lvalues ); } void scml_context::set_rvalues(tag_list *tl) { this->rvalues = tl; } tag_list *scml_context::get_rvalues() { return( this->rvalues ); } void scml_context::set_scope(struct scml_scope *the_scope) { this->scope = the_scope; } struct scml_scope *scml_context::get_scope() { return( this->scope ); } void scml_context::set_offset_size(int size) { this->offset_size = size; } int scml_context::get_offset_size() { return( this->offset_size ); } void scml_context::set_indent_size(int size) { this->indent_size = size; } int scml_context::get_indent_size() { return( this->indent_size ); } void scml_context::set_ws_queue(int size) { this->ws_queue = size; } int scml_context::get_ws_queue() { return( this->ws_queue ); } void scml_context::locate_scope(struct scml_token *st, struct scml_scope **inout_scope, const char **out_id) { switch( st->kind ) { case SCML_TERM_ID: *out_id = st->value.id; break; case SCML_NT_SCOPE_RES: if( (st->value.children[1].kind == SCML_TERM_ID) ) { struct scml_scope *child_scope; *out_id = 0; this->locate_scope(&st->value.children[0], inout_scope, out_id); if( *out_id && *inout_scope && (child_scope = (*inout_scope)-> find_child(*out_id)) ) { *out_id = st->value.children[1].value.id; *inout_scope = child_scope; } } else { scml_alert(this->stream_pos, SAF_ERROR|SAF_RUNTIME, "Non-ID(%s) used in scope resolution", scml_kind_map[st->value.children[1].kind]); *inout_scope = 0; *out_id = 0; } break; case SCML_NT_NAME: this->locate_scope(&st->value.children[0], inout_scope, out_id); break; default: scml_alert(this->stream_pos, SAF_ERROR|SAF_RUNTIME, "Non-ID(%s) used in scope resolution", scml_kind_map[st->value.children[1].kind]); *inout_scope = 0; *out_id = 0; break; } } void scml_context::print_indent(int size) { int lpc; for( lpc = 0; lpc < size; lpc++ ) { w_printf(" "); } } int scml_context::print_token(struct scml_token *st) { int retval = 1; switch( st->kind ) { case SCML_COL_POS: case SCML_ROW_POS: break; case SCML_TERM_BOOL: this->print_indent(this->ws_queue); this->ws_queue = 0; w_printf("%s", st->value.b ? "true" : "false"); break; case SCML_TERM_INT: this->print_indent(this->ws_queue); this->ws_queue = 0; w_printf("%d", st->value.i); break; case SCML_TERM_FLOAT: this->print_indent(this->ws_queue); this->ws_queue = 0; w_printf("%f", st->value.f); break; case SCML_TERM_STRING: st->value.str->print(this->ws_queue); this->ws_queue = 0; break; case SCML_TERM_TAG: /* * If its a tag ref we need to figure out what its * referring to, in order to print it */ if( (st->value.ti->data.kind == TAG_REF) ) { struct scml_token_sequence *ref_sts; struct scml_string *ref_ss; if( (ref_sts = scml_token_sequence:: ptr(st->value.ti->data. tag_data_u.ref)) ) { int old_offset, old_indent; /* * Its scml code so we need to adjust ourself * to the formatting of this sequence and * print it out. */ old_offset = this->offset_size; this->offset_size = ref_sts->get_indent(); old_indent = this->indent_size; if( this->flags & SCF_PREFORMATTED ) this->indent_size = this->stream_pos-> get_column() - old_offset; retval = this->format_sequence(ref_sts); this->indent_size = old_indent; this->offset_size = old_offset; } else if( (ref_ss = scml_string:: ptr(st->value.ti->data.tag_data_u.ref)) ) { /* An encapsulated string */ ref_ss->print(this->ws_queue); this->ws_queue = 0; } else { scml_alert(this->stream_pos, SAF_WARNING|SAF_INTERNAL, "Can't handle ref tag (%s)", st->value.ti->data.tag_data_u.ref); } } else { union tag_data_u data; /* Just a regular tag, print it */ data = get_tag_data(&st->value.ti->data, 0); print_tag_data(this->ws_queue, st->value.ti->data.kind, data); this->ws_queue = 0; } break; case SCML_TERM_TEXT: { int row, col; const char *curr; /* Track the row/column when printing (for errors) */ row = this->stream_pos->get_row(); col = this->stream_pos->get_column(); for( curr = st->value.text; *curr; curr++ ) { /* * Check for tabs that cross over the indentation * of the sequence. We'll need to fill it out with * spaces rather than printing the tab. */ if( (this->flags & SCF_PREFORMATTED) && (*curr == '\t') && (col < this->offset_size) && ((col + 8) > this->offset_size) ) { this->ws_queue = (col + 8) - this->offset_size; } else if( isspace(*curr) && (!(this->flags & SCF_PREFORMATTED) || (*curr != '\n')) ) { if( !(this->flags & SCF_IGNORE_WHITE_SPACE) && ((this->flags & SCF_PREFORMATTED) || (this->flags & SCF_PRINTING_BODY)) && (col >= this->offset_size) ) { if( this->flags & SCF_PREFORMATTED ) this->ws_queue += (*curr == '\t') ? 8 : 1; else if( !this->ws_queue ) this->ws_queue = 1; } } else if( !(this->flags & SCF_PREFORMATTED) || (col >= this->offset_size) || (*curr == '\n') ) { /* Print any queued white space */ if( this->ws_queue ) { if( *curr != '\n' ) this->print_indent(this-> ws_queue); this->ws_queue = 0; } /* * Record that we are in the body of the * sequence. */ this->flags |= SCF_PRINTING_BODY; w_printf("%c", *curr); /* * If this is a newline and we have some * extra indentation we'll need to print * that first */ if( (this->flags & SCF_PREFORMATTED) && (*curr == '\n') && !(this->flags & SCF_IGNORE_INDENT) ) { this->print_indent(this->indent_size); } } switch( *curr ) { case '\n': row++; col = 0; break; case '\t': col += 8; break; default: col++; break; } } /* There was some left over white space */ this->stream_pos->set_row(row); this->stream_pos->set_column(col); break; } case SCML_TERM_ESCAPE: { struct scml_escape *se = 0; struct scml_scope *curr; curr = this->scope; while( curr ) { if( (se = curr->get_escape_table()-> find_escape(st->value.escape)) ) { this->print_indent(this->ws_queue); this->ws_queue = 0; w_printf("%s", se->value); curr = 0; } else curr = curr->get_parent(); } if( !se ) { scml_alert(this->stream_pos, SAF_ERROR|SAF_RUNTIME, "Couldn't find escape '%s'", st->value.escape); retval = 0; } break; } case SCML_TERM_VERBATIM: this->print_indent(this->ws_queue); this->ws_queue = 0; w_printf("%s", st->value.text); break; case SCML_ERROR: retval = 0; scml_alert(this->stream_pos, SAF_ERROR|SAF_RUNTIME, "There was an error in execution", scml_kind_map[st->kind]); break; default: retval = 0; scml_alert(this->stream_pos, SAF_WARNING|SAF_INTERNAL, "Token (%s) not handled", scml_kind_map[st->kind]); break; } switch( st->kind ) { case SCML_COL_POS: case SCML_ROW_POS: break; default: /* We're printing out the body of the text */ this->flags |= SCF_PRINTING_BODY; break; } return( retval ); } int scml_context::equalize_tokens(struct scml_token *dest, struct scml_token *src, int count) { int retval = SCML_ERROR; int min_kind = SCML_NT_MAX, max_kind = 0, common_kind; int lpc; /* Strip everything and figure out what the range of types is */ for( lpc = 0; lpc < count; lpc++ ) { dest[lpc] = this->eval_token(&src[lpc]); dest[lpc].strip(); min_kind = min(min_kind, dest[lpc].kind); max_kind = max(max_kind, dest[lpc].kind); } if( (min_kind != max_kind) ) { /* * We don't have all the same kind of type so we promote * them all to the most accomodating type. */ common_kind = max_kind; min_kind = SCML_NT_MAX; max_kind = 0; for( lpc = 0; lpc < count; lpc++ ) { dest[lpc].promote(common_kind); min_kind = min(min_kind, dest[lpc].kind); max_kind = max(max_kind, dest[lpc].kind); } if( min_kind == max_kind ) retval = dest[0].kind; } else retval = dest[0].kind; return( retval ); } struct scml_token scml_context::eval_token(struct scml_token *st) { struct scml_token args[3]; struct scml_token retval; retval.kind = SCML_ERROR; switch( st->kind ) { case SCML_NONE: case SCML_IGNORE: case SCML_DONE: retval.kind = SCML_NONE; break; case SCML_ERROR: break; case SCML_COL_POS: this->stream_pos->set_column(st->value.i); retval = *st; break; case SCML_ROW_POS: this->stream_pos->set_row(st->value.i); retval = *st; break; case SCML_TERM_BOOL: case SCML_TERM_INT: case SCML_TERM_FLOAT: case SCML_TERM_STRING: case SCML_TERM_TAG: case SCML_TERM_VERBATIM: case SCML_TERM_TEXT: case SCML_TERM_ESCAPE: case SCML_TERM_TAG_LIST: case SCML_TERM_SLASH: case SCML_NT_COMMAND: /* These dont require any evaluation */ retval = *st; break; case SCML_NT_SET: { union tag_data_u data; tag_item *ti = 0; int index; /* Get the lvalue of a token, the tag and its array index */ this->token_lvalue(&st->value.children[0], &ti, &index); if( ti ) { /* Evaluate the right side */ args[0] = this->eval_token(&st->value.children[1]); args[0].strip(); retval.value.ti = ti; /* * Resolve any differences in types between the * right and left sides. */ switch( args[0].kind ) { case SCML_TERM_BOOL: if( (ti->data.kind == TAG_ANY) || (ti->data.kind == TAG_ANY_ARRAY) ) { ti->data.kind = (tag_data_kind) ((ti->data.kind & ~TAG_ANY) | TAG_BOOL); } if( (ti->data.kind == TAG_BOOL) || (ti->data.kind == TAG_BOOL_ARRAY) ) { retval.kind = SCML_TERM_TAG; data.b = args[0].value.b; set_tag_data(&ti->data, index, data); } break; case SCML_TERM_INT: if( (ti->data.kind == TAG_ANY) || (ti->data.kind == TAG_ANY_ARRAY) ) { ti->data.kind = (tag_data_kind) ((ti->data.kind & ~TAG_ANY) | TAG_INTEGER); } if( (ti->data.kind == TAG_INTEGER) || (ti->data.kind == TAG_INTEGER_ARRAY) ) { retval.kind = SCML_TERM_TAG; data.i = args[0].value.i; set_tag_data(&ti->data, index, data); } break; case SCML_TERM_FLOAT: if( (ti->data.kind == TAG_ANY) || (ti->data.kind == TAG_ANY_ARRAY) ) { ti->data.kind = (tag_data_kind) ((ti->data.kind & ~TAG_ANY) | TAG_FLOAT); } if( (ti->data.kind == TAG_FLOAT) || (ti->data.kind == TAG_FLOAT_ARRAY) ) { retval.kind = SCML_TERM_TAG; data.f = args[0].value.f; set_tag_data(&ti->data, index, data); } break; case SCML_TERM_STRING: if( (ti->data.kind == TAG_ANY) || (ti->data.kind == TAG_ANY_ARRAY) ) { ti->data.kind = (tag_data_kind) ((ti->data.kind & ~TAG_ANY) | TAG_REF); } if( (ti->data.kind == TAG_STRING) || (ti->data.kind == TAG_STRING_ARRAY) ) { if( (data.str = args[0].value.str-> make_chars()) ) { retval.kind = SCML_TERM_TAG; set_tag_data(&ti->data, index, data); } } if( (ti->data.kind == TAG_REF) || (ti->data.kind == TAG_REF_ARRAY) ) { retval.kind = SCML_TERM_TAG; data.ref = args[0].value.str-> tag_ref(); set_tag_data(&ti->data, index, data); } break; case SCML_TERM_TAG: if( (ti->data.kind == TAG_ANY) || (ti->data.kind == args[0].value.ti->data.kind) ) { retval.kind = SCML_TERM_TAG; ti->data = args[0].value.ti->data; } break; case SCML_TERM_TAG_LIST: if( (ti->data.kind == TAG_ANY) || (ti->data.kind == TAG_ANY_ARRAY) ) { ti->data.kind = (tag_data_kind) ((ti->data.kind & ~TAG_ANY) | TAG_TAG_LIST); } if( (ti->data.kind == TAG_TAG_LIST) || (ti->data.kind == TAG_TAG_LIST_ARRAY) ) { retval.kind = SCML_TERM_TAG; data.tl = args[0].value.tl; set_tag_data(&ti->data, index, data); } break; default: retval.kind = SCML_ERROR; break; } if( retval.kind == SCML_ERROR ) { scml_alert(this->stream_pos, SAF_ERROR|SAF_TYPE, "Incompatible types in assignment"); args[0].print(); print_tag(0, ti); } } break; } case SCML_NT_PLUS: retval.kind = this->equalize_tokens(args, st->value.children, 2); switch( retval.kind ) { case SCML_TERM_INT: retval.value.i = args[0].value.i + args[1].value.i; break; case SCML_TERM_FLOAT: retval.value.f = args[0].value.f + args[1].value.f; break; case SCML_TERM_STRING: retval.value.str = new scml_string; retval.value.str->concat(args[0].value.str); retval.value.str->concat(args[1].value.str); break; default: scml_alert(this->stream_pos, SAF_ERROR|SAF_TYPE, "Types for '+' are inconsistent"); args[0].print(); args[1].print(); retval.kind = SCML_ERROR; break; } break; case SCML_NT_MINUS: retval.kind = this->equalize_tokens(args, st->value.children, 2); switch( retval.kind ) { case SCML_TERM_INT: retval.value.i = args[0].value.i - args[1].value.i; break; case SCML_TERM_FLOAT: retval.value.f = args[0].value.f - args[1].value.f; break; default: scml_alert(this->stream_pos, SAF_ERROR|SAF_TYPE, "Types for '-' are inconsistent"); retval.kind = SCML_ERROR; break; } break; case SCML_NT_DIV: retval.kind = this->equalize_tokens(args, st->value.children, 2); switch( retval.kind ) { case SCML_TERM_INT: retval.value.i = args[0].value.i / args[1].value.i; break; case SCML_TERM_FLOAT: retval.value.f = args[0].value.f / args[1].value.f; break; default: retval.kind = SCML_ERROR; break; } break; case SCML_NT_MOD: retval.kind = this->equalize_tokens(args, st->value.children, 2); switch( retval.kind ) { case SCML_TERM_INT: retval.value.i = args[0].value.i % args[1].value.i; break; default: retval.kind = SCML_ERROR; break; } break; case SCML_NT_MULT: retval.kind = this->equalize_tokens(args, st->value.children, 2); switch( retval.kind ) { case SCML_TERM_INT: retval.value.i = args[0].value.i * args[1].value.i; break; case SCML_TERM_FLOAT: retval.value.f = args[0].value.f * args[1].value.f; break; default: retval.kind = SCML_ERROR; break; } break; case SCML_NT_COND: args[0] = this->eval_token(st->value.children); args[0].strip(); retval.kind = this->equalize_tokens(&args[1], &st->value.children[1], 2); if( (retval.kind != SCML_ERROR) && ((args[0].kind == SCML_TERM_INT) || (args[0].kind == SCML_TERM_BOOL)) ) { if( args[0].value.i ) retval = args[1]; else retval = args[2]; } break; case SCML_NT_EQUAL: { int cmp_kind; cmp_kind = this->equalize_tokens(args, st->value.children, 2); retval.kind = SCML_TERM_BOOL; switch( cmp_kind ) { case SCML_TERM_STRING: retval.value.i = !args[0].value.str-> cmp(args[1].value.str); break; case SCML_TERM_BOOL: case SCML_TERM_INT: retval.value.i = args[0].value.i == args[1].value.i; break; case SCML_TERM_FLOAT: retval.value.i = args[0].value.f == args[1].value.f; break; default: retval.kind = SCML_ERROR; break; } break; } case SCML_NT_NOT_EQUAL: { int cmp_kind; cmp_kind = this->equalize_tokens(args, st->value.children, 2); retval.kind = SCML_TERM_BOOL; switch( cmp_kind ) { case SCML_TERM_STRING: retval.value.i = args[0].value.str-> cmp(args[1].value.str); break; case SCML_TERM_BOOL: case SCML_TERM_INT: retval.value.i = args[0].value.i != args[1].value.i; break; case SCML_TERM_FLOAT: retval.value.i = args[0].value.f != args[1].value.f; break; default: retval.kind = SCML_ERROR; break; } break; } case SCML_NT_LT: { int cmp_kind; cmp_kind = this->equalize_tokens(args, st->value.children, 2); retval.kind = SCML_TERM_BOOL; switch( cmp_kind ) { case SCML_TERM_STRING: retval.value.i = (args[0].value.str-> cmp(args[1].value.str) < 0); break; case SCML_TERM_INT: retval.value.i = args[0].value.i < args[1].value.i; break; case SCML_TERM_FLOAT: retval.value.i = args[0].value.f < args[1].value.f; break; default: retval.kind = SCML_ERROR; break; } break; } case SCML_NT_GT: { int cmp_kind; cmp_kind = this->equalize_tokens(args, st->value.children, 2); retval.kind = SCML_TERM_BOOL; switch( cmp_kind ) { case SCML_TERM_STRING: retval.value.i = (args[0].value.str-> cmp(args[1].value.str) > 0); break; case SCML_TERM_INT: retval.value.i = args[0].value.i > args[1].value.i; break; case SCML_TERM_FLOAT: retval.value.i = args[0].value.f > args[1].value.f; break; default: retval.kind = SCML_ERROR; break; } break; } case SCML_NT_LE: { int cmp_kind; cmp_kind = this->equalize_tokens(args, st->value.children, 2); retval.kind = SCML_TERM_BOOL; switch( cmp_kind ) { case SCML_TERM_STRING: retval.value.i = (args[0].value.str-> cmp(args[1].value.str) <= 0); break; case SCML_TERM_INT: retval.value.i = args[0].value.i <= args[1].value.i; break; case SCML_TERM_FLOAT: retval.value.i = args[0].value.f <= args[1].value.f; break; default: retval.kind = SCML_ERROR; break; } break; } case SCML_NT_GE: { int cmp_kind; cmp_kind = this->equalize_tokens(args, st->value.children, 2); retval.kind = SCML_TERM_BOOL; switch( cmp_kind ) { case SCML_TERM_STRING: retval.value.i = (args[0].value.str-> cmp(args[1].value.str) >= 0); break; case SCML_TERM_INT: retval.value.i = args[0].value.i >= args[1].value.i; break; case SCML_TERM_FLOAT: retval.value.i = args[0].value.f >= args[1].value.f; break; default: retval.kind = SCML_ERROR; break; } break; } case SCML_NT_AND: break; case SCML_NT_LAND: retval.kind = this->equalize_tokens(args, st->value.children, 2); switch( retval.kind ) { case SCML_TERM_INT: case SCML_TERM_BOOL: retval.kind = SCML_TERM_BOOL; retval.value.i = args[0].value.i && args[1].value.i; break; default: scml_alert(this->stream_pos, SAF_ERROR|SAF_TYPE, "Types for '&&' are inconsistent"); args[0].print(); args[1].print(); retval.kind = SCML_ERROR; break; } break; case SCML_NT_OR: retval.kind = this->equalize_tokens(args, st->value.children, 2); if( retval.kind == SCML_TERM_TAG_LIST ) { retval.value.tl = copy_tag_list(args[0].value.tl); concat_tag_list(retval.value.tl, args[1].value.tl); } else { scml_alert(this->stream_pos, SAF_ERROR|SAF_GENERAL, "Couldn't get tag lists for union"); } break; case SCML_NT_LOR: retval.kind = this->equalize_tokens(args, st->value.children, 2); switch( retval.kind ) { case SCML_TERM_INT: case SCML_TERM_BOOL: retval.kind = SCML_TERM_BOOL; retval.value.i = args[0].value.i || args[1].value.i; break; default: retval.kind = SCML_ERROR; break; } break; break; case SCML_NT_NOT: retval.kind = this->equalize_tokens(args, st->value.children, 1); switch( retval.kind ) { case SCML_TERM_INT: case SCML_TERM_BOOL: retval.kind = SCML_TERM_BOOL; retval.value.i = !args[0].value.i; break; default: retval.kind = SCML_ERROR; break; } break; case SCML_NT_EXPR: retval = this->eval_token(&st->value.children[0]); break; case SCML_NT_DOT: { args[0] = this->eval_token(&st->value.children[0]); args[0].strip(); switch( args[0].kind ) { case SCML_TERM_TAG_LIST: { tag_item *ti; if( (st->value.children[1].kind == SCML_TERM_ID) && (ti = find_tag(args[0].value.tl, st->value.children[1].value.id)) ) { retval.kind = SCML_TERM_TAG; retval.value.ti = ti; } else { scml_alert(this->stream_pos, SAF_ERROR|SAF_GENERAL, "Couldn't find tag"); args[0].print(); st->value.children[1].print(); } break; } default: retval.kind = SCML_ERROR; break; } break; } case SCML_NT_SEL: { /* Evaluate the tag and its array index */ args[0] = this->eval_token(&st->value.children[0]); args[1] = this->eval_token(&st->value.children[1]); args[1].strip(); if( (args[0].kind == SCML_TERM_TAG) && (args[1].kind == SCML_TERM_INT) && (args[1].value.i < (int) tag_data_length(&args[0].value.ti->data)) ) { tag_item *ti; tag_data td; /* * We create a temporary tag to hold the value. We * have to do this since scml tokens don't encode * every tag type so we just make a fake one so * we can handle everything. Of course it gets * leaked which kinda sucks. */ td = create_tag_data((tag_data_kind) (args[0].value.ti->data.kind & ~TAG_ARRAY), 1); set_tag_data(&td, 0, get_tag_data(&args[0].value.ti->data, args[1].value.i)); ti = create_tag_item("", &td); retval.kind = SCML_TERM_TAG; retval.value.ti = ti; } else { if( args[0].kind != SCML_TERM_TAG ) { scml_alert(this->stream_pos, SAF_ERROR|SAF_RUNTIME, "Couldn't get a tag for selection"); } else if( args[1].kind != SCML_TERM_INT ) { scml_alert(this->stream_pos, SAF_ERROR|SAF_RUNTIME, "Selector isn't an integer"); } else { scml_alert(this->stream_pos, SAF_ERROR|SAF_RUNTIME, "Selector %d is out of range", args[1].value.i); } } break; } case SCML_NT_INIT: { union tag_data_u data; int error = 0, lpc; tag_data td; td = create_tag_data(TAG_ANY, 0); /* * Walk through all the children of this token. Each child * evaluates to a tag so we just copy it to the tag list */ for( lpc = 0; !error && (st->value.children[lpc].kind != SCML_NONE); lpc++ ) { args[0] = this->eval_token(&st->value.children[lpc]); switch( args[0].kind ) { case SCML_TERM_BOOL: if( td.kind == TAG_ANY ) { td.kind = TAG_BOOL_ARRAY; retval.kind = SCML_TERM_TAG; } if( td.kind == TAG_BOOL_ARRAY ) { data.b = args[0].value.b; append_tag_data(&td, data); } else error = 1; break; case SCML_TERM_INT: if( td.kind == TAG_ANY ) { td.kind = TAG_INTEGER_ARRAY; retval.kind = SCML_TERM_TAG; } if( td.kind == TAG_INTEGER_ARRAY ) { data.i = args[0].value.i; append_tag_data(&td, data); } else error = 1; break; case SCML_TERM_FLOAT: if( td.kind == TAG_ANY ) { td.kind = TAG_FLOAT_ARRAY; retval.kind = SCML_TERM_TAG; } if( td.kind == TAG_FLOAT_ARRAY ) { data.f = args[0].value.f; append_tag_data(&td, data); } else error = 1; break; case SCML_TERM_STRING: if( td.kind == TAG_ANY ) { td.kind = TAG_REF_ARRAY; retval.kind = SCML_TERM_TAG; } if( td.kind == TAG_REF_ARRAY ) { data.ref = args[0].value.str-> tag_ref(); append_tag_data(&td, data); } else error = 1; break; case SCML_TERM_TAG: if( td.kind == TAG_ANY ) { td.kind = TAG_TAG_LIST; retval.kind = SCML_TERM_TAG_LIST; retval.value.tl = create_tag_list(0); } if( td.kind == TAG_TAG_LIST ) { *(add_tag(retval.value.tl, args[0].value.ti->tag, TAG_NONE)) = *(args[0].value.ti); } else error = 1; break; case SCML_TERM_TAG_LIST: if( td.kind == TAG_ANY ) { td.kind = TAG_TAG_LIST_ARRAY; retval.kind = SCML_TERM_TAG; } if( td.kind == TAG_TAG_LIST_ARRAY ) { data.tl = args[0].value.tl; append_tag_data(&td, data); } else error = 1; break; default: error = 1; break; } } if( lpc == 0 ) { retval.kind = SCML_TERM_TAG_LIST; retval.value.tl = create_tag_list(0); } if( error ) { retval.kind = SCML_ERROR; scml_alert(this->stream_pos, SAF_ERROR|SAF_GENERAL, "Cannot add incompatible type", scml_kind_map[args[0].kind]); } if( retval.kind == SCML_TERM_TAG ) { retval.value.ti = create_tag_item("", &td); } break; } case SCML_NT_TAG: { tag_data_kind kind; union tag_data_u data; int size, lpc; tag_item *ti; tag_data td; /* This will construct a new tag with a specific type */ this->tag_type(&st->value.children[1], &kind, &size); if( (st->value.children[0].kind == SCML_TERM_ID) && (kind != -1) ) { td = create_tag_data(kind, size); ti = create_tag_item(st->value.children[0].value.id, &td); if( kind & TAG_ARRAY ) { /* Be nice and clear the memory */ memset(&data, 0, sizeof( union tag_data_u )); for( lpc = 0; lpc < size; lpc++ ) { set_tag_data(&ti->data, lpc, data); } } retval.kind = SCML_TERM_TAG; retval.value.ti = ti; } else { if( kind == -1 ) { scml_alert(this->stream_pos, SAF_ERROR|SAF_TYPE, "Invalid type given for tag"); } } break; } case SCML_TERM_ID: if( (retval.value.ti = find_tag(this->rvalues, st->value.id)) || (retval.value.ti = find_tag(this->scope->get_values(), st->value.id)) ) { retval.kind = SCML_TERM_TAG; } else { scml_alert(this->stream_pos, SAF_ERROR|SAF_GENERAL, "Couldn't find tag \"%s\"", st->value.id); } break; case SCML_NT_NAME: { struct scml_scope *var_scope; const char *id; var_scope = this->scope; while( var_scope->get_parent() ) var_scope = var_scope->get_parent(); this->locate_scope(st, &var_scope, &id); if( var_scope && (retval.value.ti = find_tag(var_scope->get_values(), id)) ) { retval.kind = SCML_TERM_TAG; } else { if( !var_scope ) { scml_alert(this->stream_pos, SAF_ERROR|SAF_GENERAL, "Couldn't locate scope"); } else if( !retval.value.ti ) { scml_alert(this->stream_pos, SAF_ERROR|SAF_GENERAL, "Couldn't locate id (%s) in scope" " %s", id, var_scope->get_name()); } } break; } default: break; } return( retval ); } void scml_context::token_lvalue(struct scml_token *st, tag_item **out_ti, int *out_index) { switch( st->kind ) { case SCML_TERM_TAG: *out_ti = st->value.ti; *out_index = 0; break; case SCML_TERM_ID: { tag_item *ti; /* If its in the list of lvalues than just return that */ if( (ti = find_tag(this->lvalues, st->value.id)) ) { *out_ti = ti; } else if( this->def && ((ti = find_tag(this->def->get_opt_params(), st->value.id)) || (ti = find_tag(this->def->get_req_params(), st->value.id))) ) { /* * If its part of the optional or required parameters * then we can safely add it to the lvalues. This * is used in parameter passing so that the parameter * lists are preserved and we still get access to the * variables. */ *out_ti = add_tag(this->lvalues, st->value.id, TAG_NONE); (*out_ti)->data = ti->data; } else if( (ti = find_tag(this->scope->get_values(), st->value.id)) ) { /* Its in the current scope */ *out_ti = ti; } else { *out_ti = 0; scml_alert(this->stream_pos, SAF_ERROR|SAF_GENERAL, "Couldn't find tag lvalue %s", st->value.id); } *out_index = 0; break; } case SCML_NT_SEL: { struct scml_token t_index; /* Its an array index, return the same tag with an index */ this->token_lvalue(&st->value.children[0], out_ti, out_index); t_index = this->eval_token(&st->value.children[1]); t_index.strip(); if( t_index.kind == SCML_TERM_INT ) { *out_index = t_index.value.i; } else { *out_ti = 0; *out_index = 0; } break; } case SCML_NT_DOT: /* Its a tag within a tag list */ if( st->value.children[1].kind == SCML_TERM_ID ) { this->token_lvalue(&st->value.children[0], out_ti, out_index); if( *out_ti && (((*out_ti)->data.kind == TAG_TAG_LIST) || ((*out_ti)->data.kind == TAG_TAG_LIST_ARRAY)) ) { if( ((*out_ti) = find_tag( get_tag_data(&(*out_ti)->data, *out_index).tl, st->value.children[1]. value.id)) ) { *out_index = 0; } } else { *out_ti = 0; } } break; case SCML_NT_EXPR: this->token_lvalue(&st->value.children[0], out_ti, out_index); break; case SCML_NT_TAG: { struct scml_token t_tag; t_tag = this->eval_token(st); if( t_tag.kind == SCML_TERM_TAG ) { *out_ti = t_tag.value.ti; *out_index = 0; } else *out_ti = 0; break; } default: *out_ti = 0; break; } } int scml_context::handle_params(struct scml_token *cmd) { int retval = 1; tag_item *ti; tag_list *tl; unsigned int lpc; /* * Handle_params has to build the lvalues tag list from the parameters * but it also has to have access to the parents values. This * inbetween state is accomplished by using the parents values as * our rvalues and then token_lvalue takes care of building our lvalues * from the parameter lists. */ this->rvalues = this->parent->lvalues; if( cmd->value.children[0].kind == SCML_TERM_SLASH ) lpc = 2; else lpc = 1; for( ; cmd->value.children[lpc].kind != SCML_NONE; lpc++ ) { if( this->eval_token(&cmd->value.children[lpc]).kind == SCML_ERROR ) { retval = 0; scml_alert(this->stream_pos, SAF_ERROR|SAF_RUNTIME, "Invalid arg"); cmd->value.children[lpc].print(); } } /* Add the optional paramters with their default values */ tl = this->def->get_opt_params(); for( lpc = 0; lpc < tl->items.items_len; lpc++ ) { if( !(ti = find_tag(this->lvalues, tl->items.items_val[lpc].tag)) ) { add_tag(this->lvalues, tl->items.items_val[lpc].tag, TAG_NONE)->data = copy_tag_data(&tl->items.items_val[lpc].data); } } /* Make sure all required parameters were specified */ tl = this->def->get_req_params(); for( lpc = 0; lpc < tl->items.items_len; lpc++ ) { if( !(ti = find_tag(this->lvalues, tl->items.items_val[lpc].tag)) ) { retval = 0; scml_alert(this->stream_pos, SAF_ERROR|SAF_GENERAL, "Missing required parameter %s", tl->items.items_val[lpc].tag); } } this->rvalues = this->lvalues; return( retval ); } struct scml_cmd_definition *scml_context::find_cmd( struct scml_scope **cmd_scope, struct scml_token *st) { struct scml_cmd_definition *retval = 0; switch( st->kind ) { case SCML_TERM_ID: retval = this->scope->find_cmd_definition(cmd_scope, st->value.id); break; case SCML_NT_NAME: { struct scml_scope *new_cmd_scope; const char *id = 0; new_cmd_scope = this->scope; while( new_cmd_scope->get_parent() ) new_cmd_scope = new_cmd_scope->get_parent(); this->locate_scope(st, &new_cmd_scope, &id); if( new_cmd_scope ) retval = new_cmd_scope->find_cmd_definition(cmd_scope, id); break; } default: break; } return( retval ); } struct scml_token_sequence *scml_context::get_contents( struct scml_cmd_definition *cmd_def, struct scml_token_sequence *sts, int start) { struct scml_token_sequence *retval = 0; struct scml_cmd_definition *sub_cmd; struct scml_scope *cmd_scope; int depth = 1, lpc, len; struct scml_token *st; tag_list *tl, *tl_sl; tag_item *ti; char *ident; assert(cmd_def); /* These tag lists are used to track begin/end commands */ tl = create_tag_list(0); tl_sl = create_tag_list(0); add_tag(tl, sts->get_value()[start - 1].value.children[0]. get_identifier(), TAG_INTEGER, 1); /* Walk through the sequence trying to find the terminating command */ for( lpc = start; (lpc < sts->get_length()) && depth; lpc++ ) { switch( sts->get_value()[lpc].kind ) { case SCML_NT_COMMAND: { int slash = 0; st = &sts->get_value()[lpc]; switch( st->value.children[0].kind ) { case SCML_NT_EXPR: sub_cmd = 0; break; case SCML_TERM_SLASH: /* Record any terminating commands */ slash = 1; sub_cmd = this->find_cmd(&cmd_scope, &st->value. children[1]); if( (ident = st->value.children[1]. get_identifier()) ) { if( (ti = find_tag(tl_sl, ident)) ) { ti->data.tag_data_u.i++; free(ident); } else { add_tag(tl_sl, ident, TAG_INTEGER, 1); } } break; case SCML_TERM_ID: case SCML_NT_NAME: /* Record any commands */ sub_cmd = this->find_cmd(&cmd_scope, &st->value. children[0]); if( (ident = st->value.children[0]. get_identifier()) ) { if( (ti = find_tag(tl, ident)) ) { ti->data.tag_data_u.i++; free(ident); } else { add_tag(tl, ident, TAG_INTEGER, 1); } } break; default: sub_cmd = 0; break; } /* * See if this command has been terminated, * or if it was nested */ if( sub_cmd && (sub_cmd->get_flags() & SCDF_BRACKETED) && (cmd_def == sub_cmd) ) { if( slash ) depth--; else depth++; } break; } default: break; } } if( depth ) { scml_alert(this->stream_pos, SAF_ERROR|SAF_RUNTIME, "This is a malformed bracketed tag %d", depth); } /* Make sure all the terminators have corresponding initiators */ len = lpc - start - 1; for( lpc = 0; lpc < (signed int)tl_sl->items.items_len; lpc++ ) { if( !find_tag(tl, tl_sl->items.items_val[lpc].tag) ) { scml_alert(this->stream_pos, SAF_ERROR|SAF_RUNTIME, "Terminators without initiators for " "command '%s'", tl_sl->items.items_val[lpc].tag); depth = 1; } } /* * Make sure every initiator is paired with a terminator. * Note - Because some of the initiators and terminators could be * defined within this sequence we can't be sure whether a command * has a terminator. We can only guess by checking to see if * its terminator was ever used. So we aren't able to check here * whether a terminator was needed but never paired with its * command. However, this isn't a problem since the lack of a * terminator will appear when you try and execute this sequence. */ for( lpc = 0; lpc < (signed int)tl->items.items_len; lpc++ ) { ti = find_tag(tl_sl, tl->items.items_val[lpc].tag); if( ti && (tl->items.items_val[lpc].data.tag_data_u.i > ti->data.tag_data_u.i) ) { scml_alert(this->stream_pos, SAF_ERROR|SAF_RUNTIME, "Not enough terminators for command '%s'", ti->tag); depth = 1; } else if( ti && (tl->items.items_val[lpc].data.tag_data_u.i < ti->data.tag_data_u.i) ) { scml_alert(this->stream_pos, SAF_ERROR|SAF_RUNTIME, "Too many terminators for command '%s'", ti->tag); depth = 1; } free(tl->items.items_val[lpc].tag); } delete_tag_list(tl); delete_tag_list(tl_sl); if( depth ) { scml_alert(this->stream_pos, SAF_ERROR|SAF_RUNTIME, "This is a malformed bracketed tag %d", depth); } else { /* Build a new sequence corresponding to this subsequence */ retval = new scml_token_sequence(); retval->set_indent(this->get_stream_pos()->get_column()); retval->set_stream_pos(sts->get_stream_pos()); retval->set_value(&(sts->get_value()[start])); retval->set_length(len); } return( retval ); } struct scml_token_sequence *scml_context::partition_sequence( struct scml_cmd_definition *cmd_def, struct scml_cmd_definition *partition, struct scml_token_sequence *sts) { struct scml_token_sequence *retval = 0; int lpc, poss_pivot = -1, pivot = -1; struct scml_cmd_definition *sub_cmd; struct scml_scope *cmd_scope; struct ptr_stack *cmd_stack; struct scml_token *st; cmd_stack = create_ptr_stack(); push_ptr(cmd_stack, cmd_def); /* * get_contents has already done the error checking for us so we * just need to find the subcommand and partition around it */ for( lpc = 0; (lpc < sts->get_length()) && !empty_ptr_stack(cmd_stack) && (pivot == -1); lpc++ ) { switch( sts->get_value()[lpc].kind ) { case SCML_NT_COMMAND: { int slash = 0; st = &sts->get_value()[lpc]; switch( st->value.children[0].kind ) { case SCML_NT_EXPR: sub_cmd = 0; break; case SCML_TERM_SLASH: slash = 1; sub_cmd = this->find_cmd(&cmd_scope, &st->value. children[1]); if( sub_cmd != cmd_def ) poss_pivot = -1; if( (top_ptr(cmd_stack) == sub_cmd) ) pop_ptr(cmd_stack); else { while( top_ptr(cmd_stack) == 0 ) pop_ptr(cmd_stack); if( top_ptr(cmd_stack) == sub_cmd ) pop_ptr(cmd_stack); } break; default: sub_cmd = this->find_cmd(&cmd_scope, &st->value. children[0]); if( !sub_cmd || (sub_cmd->get_flags() & SCDF_BRACKETED) ) push_ptr(cmd_stack, sub_cmd); break; } if( sub_cmd && (sub_cmd == partition) ) { poss_pivot = lpc; if( (ptr_stack_length(cmd_stack) == 1) ) { pivot = lpc; } } break; } default: break; } } delete_ptr_stack(cmd_stack); if( (poss_pivot != -1) && (pivot == -1) ) pivot = poss_pivot; if( pivot != -1 ) { int old_len; /* * Found the pivot command so adjust the current sequence to * enclose the first part, and make a new sequence to enclose * the second. */ old_len = sts->get_length(); sts->set_length(pivot - 1); retval = new scml_token_sequence(); retval->set_indent(sts->get_indent()); retval->set_stream_pos(sts->get_stream_pos()); retval->set_value(&(sts->get_value()[pivot + 1])); retval->set_length(old_len - (pivot + 1)); } return( retval ); } int scml_context::define(struct scml_context *sc) { tag_item *kind_ti, *name_ti, *value_ti; char *kind_str = 0, *name_str; int retval = 0; tag_list *tl; /* Grab our parameters */ tl = sc->get_lvalues(); name_ti = find_tag(tl, "name"); kind_ti = find_tag(tl, "kind"); value_ti = find_tag(tl, "value"); if( name_ti && kind_ti && value_ti ) { name_str = scml_string::tag_string(name_ti); kind_str = scml_string::tag_string(kind_ti); if( !strcmp(kind_str, "variable") ) { tag_list *dest_tl; dest_tl = this->lvalues; add_tag(dest_tl, name_str, TAG_NONE)->data = value_ti->data; retval = 1; } else if( !strcmp(kind_str, "static-variable") ) { tag_list *dest_tl, *par; dest_tl = this->scope->get_values(); par = dest_tl->parent; dest_tl->parent = 0; add_tag(dest_tl, name_str, TAG_NONE)->data = value_ti->data; dest_tl->parent = par; retval = 1; } else if( !strcmp(kind_str, "escape" ) ) { struct scml_escape *se; se = new scml_escape; se->name = name_str; if( (se->value = scml_string::tag_string(value_ti)) ) this->scope->get_escape_table()-> add_escape(se); else delete se; retval = 1; } else if( !strcmp(kind_str, "tag") ) { tag_item *oparams_ti, *rparams_ti; struct scml_handler *sh; char *value_str; /* Build a new command with the given parameters */ value_str = scml_string::tag_string(value_ti); oparams_ti = find_tag(tl, "oparams"); rparams_ti = find_tag(tl, "rparams"); sh = sht->find_handler(value_str); if( value_str && oparams_ti && rparams_ti && sh ) { struct scml_cmd_definition *scd; scd = new scml_cmd_definition; scd->set_name(name_str); scd->set_handler(sh); scd->set_opt_params(oparams_ti->data. tag_data_u.tl); scd->set_req_params(rparams_ti->data. tag_data_u.tl); this->scope->add_cmd_definition(scd); retval = 1; } else { if( !sh ) { scml_alert(this->stream_pos, SAF_ERROR|SAF_RUNTIME, "Couldn't find handler" " function (%s)", value_str); } } } else if( !strcmp(kind_str, "bracket-tag") ) { tag_item *oparams_ti, *rparams_ti; struct scml_handler *sh; char *value_str; /* Build a bracketed command with the parameters */ value_str = scml_string::tag_string(value_ti); oparams_ti = find_tag(tl, "oparams"); rparams_ti = find_tag(tl, "rparams"); sh = sht->find_handler(value_str); if( value_str && oparams_ti && rparams_ti && sh ) { struct scml_cmd_definition *scd; scd = new scml_cmd_definition; scd->set_name(name_str); scd->set_handler(sh); scd->set_flags(scd->get_flags() | SCDF_BRACKETED); scd->set_opt_params(oparams_ti->data. tag_data_u.tl); scd->set_req_params(rparams_ti->data. tag_data_u.tl); this->scope->add_cmd_definition(scd); retval = 1; } else { if( !sh ) { scml_alert(this->stream_pos, SAF_ERROR|SAF_RUNTIME, "Couldn't find handler" " function (%s)", value_str); } } } else { scml_alert(this->stream_pos, SAF_ERROR|SAF_GENERAL, "Unknown kind(%s) in define", kind_str); } } return( retval ); } int scml_context::undefine(struct scml_context *sc) { tag_item *name_ti; char *name_str; int retval = 0; name_ti = find_tag(sc->get_rvalues(), "name"); if( (name_str = scml_string::tag_string(name_ti)) ) { struct scml_escape *se; tag_item *ti; if( find_tag(this->lvalues, name_str) ) { rem_tag(this->lvalues, name_str); } else if( (ti = find_tag(this->scope->get_values(), name_str)) ) { struct scml_cmd_definition *scd; if( (ti->data.kind == TAG_REF) && (scd = scml_cmd_definition:: ptr(ti->data.tag_data_u.ref)) ) { delete scd; } rem_tag(this->scope->get_values(), name_str); } else if( (se = this->scope->get_escape_table()-> find_escape(name_str)) ) { this->scope->get_escape_table()->rem_escape(name_str); delete se; } retval = 1; } return( retval ); } int scml_context::rename(struct scml_context *sc) { char *name_str, *to_str; int retval = 0; tag_item *ti; ti = find_tag(sc->get_rvalues(), "name"); name_str = scml_string::tag_string(ti); ti = find_tag(sc->get_rvalues(), "to"); to_str = scml_string::tag_string(ti); if( name_str && to_str ) { struct scml_escape *se; if( (ti = find_tag(this->lvalues, name_str)) ) { add_tag(this->lvalues, to_str, TAG_NONE)->data = ti->data; rem_tag(this->lvalues, name_str); } else if( (ti = find_tag(this->scope->get_values(), name_str)) ) { tag_data td; td = ti->data; rem_tag(this->scope->get_values(), name_str); add_tag(this->scope->get_values(), to_str, TAG_NONE)->data = td; } else if( (se = this->scope->get_escape_table()-> find_escape(name_str)) ) { this->scope->get_escape_table()->rem_escape(name_str); se->name = to_str; this->scope->get_escape_table()->add_escape(se); } retval = 1; } return( retval ); } int scml_context::ifdef(struct scml_context *sc, struct scml_token_sequence *sub, int defined) { int found = 0, retval = 0; tag_item *name_ti; char *name_str; name_ti = find_tag(sc->get_rvalues(), "name"); if( (name_str = scml_string::tag_string(name_ti)) ) { struct scml_token_sequence *else_sts; struct scml_scope *cmd_scope; if( find_tag(this->get_rvalues(), name_str) ) found = 1; else if( find_tag(this->scope->get_values(), name_str) ) found = 1; else if( this->scope->get_escape_table()-> find_escape(name_str) ) found = 1; else_sts = this-> partition_sequence(sc->get_cmd_def(), this->get_scope()-> find_cmd_definition(&cmd_scope, "else"), sub); if( (found && defined) || (!found && !defined) ) { retval = this->format_sequence(sub); } else if( else_sts ) { retval = this->format_sequence(else_sts); } else retval = 1; } else { scml_alert(this->stream_pos, SAF_ERROR|SAF_RUNTIME, "Couldn't get string from 'name' argument"); } return( retval ); } int scml_context::exec_token(struct scml_token_sequence *sts, int *index, struct scml_token *st) { int retval = 1; switch( st->kind ) { case SCML_NT_COMMAND: { struct scml_cmd_definition *scd = 0; struct scml_scope *cmd_scope; switch( st->value.children[0].kind ) { case SCML_NT_EXPR: { struct scml_token expr; /* A simple expression, just print it */ expr = this->eval_token(&st->value.children[0]); retval = this->print_token(&expr); break; } case SCML_TERM_SLASH: if( !(scd = this->find_cmd(&cmd_scope, &st->value.children[1])) ) { scml_alert(this->stream_pos, SAF_ERROR|SAF_RUNTIME, "Couldn't locate command name %s", st->value.children[1]. get_identifier()); retval = 0; } break; case SCML_TERM_ID: case SCML_NT_NAME: if( !(scd = this->find_cmd(&cmd_scope, &st->value.children[0])) ) { scml_alert(this->stream_pos, SAF_ERROR|SAF_RUNTIME, "Couldn't locate command name %s", st->value.children[0]. get_identifier()); retval = 0; } break; default: scml_alert(this->stream_pos, SAF_ERROR|SAF_RUNTIME, "Invalid command"); retval = 0; break; } /* We have to execute a command */ if( scd ) { struct scml_token_sequence *sub = 0; struct scml_context *sc; /* Construct a sub context to execute the command in */ sc = new scml_context; sc->set_flags(this->flags & SCF_IGNORE_WHITE_SPACE); sc->set_parent(this); sc->set_stream_pos(this->stream_pos); sc->set_scope(cmd_scope); sc->set_offset_size(this->offset_size); sc->set_indent_size(this->indent_size); sc->set_ws_queue(this->ws_queue); sc->set_cmd_def(scd); /* Check for built in commands first */ if( !strcmp( "define", scd->get_name() ) ) { if( sc->handle_params(st) ) retval = this->define(sc); else scml_alert(this->stream_pos, SAF_ERROR|SAF_RUNTIME, "Bad args to %s", scd->get_name()); } else if( !strcmp( "undef", scd->get_name() ) ) { if( sc->handle_params(st) ) retval = this->undefine(sc); else scml_alert(this->stream_pos, SAF_ERROR|SAF_RUNTIME, "Bad args to %s", scd->get_name()); } else if( !strcmp( "rename", scd->get_name() ) ) { if( sc->handle_params(st) ) retval = this->rename(sc); else scml_alert(this->stream_pos, SAF_ERROR|SAF_RUNTIME, "Bad args to %s", scd->get_name()); } else if( !strcmp( "ifdef", scd->get_name() ) ) { if( sc->handle_params(st) && (sub = this-> get_contents(scd, sts, (*index) + 1)) ) { (*index) += sub->get_length() + 1; retval = this->ifdef(sc, sub, 1); } else scml_alert(this->stream_pos, SAF_ERROR|SAF_RUNTIME, "Bad args to %s", scd->get_name()); } else if( !strcmp( "ifndef", scd->get_name() ) ) { if( sc->handle_params(st) && (sub = this-> get_contents(scd, sts, (*index) + 1)) ) { (*index) += sub->get_length() + 1; retval = this->ifdef(sc, sub, 0); } else scml_alert(this->stream_pos, SAF_ERROR|SAF_RUNTIME, "Bad args to %s", scd->get_name()); } else { if( scd->get_flags() & SCDF_BRACKETED ) { /* * Its bracketed so get the contents * and add a "contents" tag to the * context so the command can use it */ if( (sub = this-> get_contents(scd, sts, (*index) + 1)) ) { add_tag(sc->rvalues, "contents", TAG_REF, sub->tag_ref()); /* * We have to skip over the * contents */ (*index) += sub-> get_length() + 1; retval = scd->execute(st, sc); } else { scml_alert(this->stream_pos, SAF_ERROR| SAF_RUNTIME, "Non terminated " "command '%s'", scd->get_name()); retval = 0; } } else { /* Its a plain command just execute */ retval = scd->execute(st, sc); } if( !retval ) { scml_alert(this->stream_pos, SAF_ERROR| SAF_RUNTIME, "Command '%s' failed to" " execute", scd->get_name()); } } if( sc->flags & SCF_PREFORMATTED ) this->ws_queue = sc->get_ws_queue(); else this->ws_queue = 0; delete sc; } (*index)++; break; } default: retval = this->print_token(st); (*index)++; break; } return( retval ); } int scml_context::format_sequence(struct scml_token_sequence *sts) { struct scml_stream_pos *old_ssp; struct scml_token curr; int lpc, retval = 1; old_ssp = this->stream_pos; this->stream_pos = sts->get_stream_pos(); for( lpc = 0; (lpc < sts->get_length()) && retval; ) { /* Evaluate and execute the tokens */ curr = this->eval_token(&(sts->get_value()[lpc])); retval = this->exec_token(sts, &lpc, &curr); } this->stream_pos = old_ssp; if( !retval ) { printf("Stack Trace -\n"); this->print(0); panic("Too many errors, bailing out"); } return( retval ); } struct scml_type_map { const char *name; tag_data_kind tag_type; }; struct scml_type_map scml_tag_types[] = { {"any", TAG_ANY}, {"int", TAG_INTEGER}, {"float", TAG_FLOAT}, {"string", TAG_REF}, {"tag_list", TAG_TAG_LIST}, {"bool", TAG_BOOL}, {"scml", TAG_REF}, {"cmd", TAG_REF}, {"internal", TAG_REF}, {"stream", TAG_REF}, {0, (tag_data_kind) 0} }; void scml_context::tag_type(struct scml_token *t_type, tag_data_kind *out_kind, int *out_size) { switch( t_type->kind ) { case SCML_NT_SEL: { struct scml_token st; this->tag_type(&t_type->value.children[0], out_kind, out_size); if( *out_kind != -1 ) { st = this->eval_token(&t_type->value.children[1]); st.strip(); if( st.kind == SCML_TERM_INT ) { *out_kind = (tag_data_kind) (*out_kind | TAG_ARRAY); *out_size = st.value.i; } else { scml_alert(this->stream_pos, SAF_ERROR|SAF_RUNTIME, "Couldn't get integer for " "array size"); *out_kind = (tag_data_kind)(-1); } } break; } case SCML_TERM_ID: { int lpc, match = -1; for( lpc = 0; scml_tag_types[lpc].name && (match == -1); lpc++ ) { if( !strcmp( scml_tag_types[lpc].name, t_type->value.id ) ) match = lpc; } if( match != -1 ) { *out_kind = scml_tag_types[match].tag_type; } else { *out_kind = (tag_data_kind)(-1); } break; } default: break; } } int scml_context::exec_cmd(const char *cmd_name, tag_list *locals, ...) { struct scml_cmd_definition *scd; struct scml_stream_pos *ssp = 0; struct scml_scope *cmd_scope; struct scml_stream *ss = 0; tag_data_kind tag_kind; struct scml_context *child; struct scml_token cmd, id; union tag_data_u data; va_list arg_addr; char *arg_name; int retval = 0; tag_item *ti; va_start(arg_addr, locals); if( (scd = this->scope->find_cmd_definition(&cmd_scope, cmd_name)) ) { /* Build up a fake command to execute */ id.kind = SCML_TERM_ID; id.value.id = cmd_name; cmd.kind = SCML_NT_COMMAND; cmd.value.children = new scml_token[2]; cmd.value.children[0] = id; cmd.value.children[1].kind = SCML_NONE; if( !this->stream_pos ) { if( scd->get_token_sequence() ) this->stream_pos = scd->get_token_sequence()-> get_stream_pos(); else { ss = new scml_stream; ss->set_desc(cmd_name); ssp = new scml_stream_pos; ssp->set_stream(ss); this->stream_pos = ssp; } } /* * Construct a child context to execute in. This is * necessary since we need to replicate the usual * environment for scml code. A context is executing * the root code and then spawns a child to execute * commands and what not. And since some of the * commands expect this environment, so who are we * to deny them? */ child = new scml_context; child->set_parent(this); child->set_stream_pos(this->stream_pos); child->set_cmd_def(scd); child->set_scope(cmd_scope); /* * Set the parents of the tag lists to be the passed in * locals so that they can reference data in them without * modify the actual tag list by defining variables. */ child->get_lvalues()->parent = locals; this->lvalues->parent = locals; /* * Walk through the var args list as if it were the parameter * list in a regular call. */ arg_name = va_arg(arg_addr, char *); while( arg_name ) { tag_kind = va_arg(arg_addr, tag_data_kind); data = va_arg(arg_addr, union tag_data_u); ti = add_tag(child->get_lvalues(), arg_name, TAG_NONE); ti->data.kind = tag_kind; set_tag_data(&ti->data, 0, data); arg_name = va_arg(arg_addr, char *); } retval = scd->execute(&cmd, child); child->get_lvalues()->parent = 0; this->lvalues->parent = 0; delete child; } if( ssp ) delete ssp; if( ss ) delete ss; va_end(arg_addr); return( retval ); } void scml_context::set_handler_table(struct scml_handler_table *handlers) { sht = handlers; } struct scml_handler_table *scml_context::get_handler_table() { return( sht ); } void scml_context::print(int level) { union tag_data_u data; w_set_fh(stdout); printf("SCML Context(%d)\n", level); if( this->scope->get_name() ) printf(" Current Scope: %s\n", this->scope->get_name()); else printf(" Root Scope\n"); data.tl = this->lvalues; printf(" lvalues: "); print_tag_data(4, TAG_TAG_LIST, data); printf("\n"); data.tl = this->rvalues; printf(" rvalues: "); print_tag_data(4, TAG_TAG_LIST, data); printf("\n"); if( this->parent ) this->parent->print(level + 1); } scml_handler_table::scml_handler_table() { int lpc; for( lpc = 0; lpc < SCML_HANDLER_TABLE_SIZE; lpc++ ) { this->table[lpc] = 0; } } scml_handler_table::~scml_handler_table() { } void scml_handler_table::add_handler(struct scml_handler *sh) { int h; h = scml_hash_name(sh->name, SCML_HANDLER_TABLE_SIZE); sh->next = this->table[h]; this->table[h] = sh; } struct scml_handler *scml_handler_table::find_handler(const char *name) { struct scml_handler *retval = 0, *curr; int h; if( name ) { h = scml_hash_name(name, SCML_HANDLER_TABLE_SIZE); curr = this->table[h]; while( curr && !retval ) { if( !strcmp( name, curr->name ) ) retval = curr; curr = curr->next; } } return( retval ); } int c_defvar_handler(struct scml_token *st, struct scml_context *sc) { struct scml_token expr; int lpc, retval = 1; /* * We diverge from regular syntax and just process the parameters * ourselves, turning them into variables for the parent context. */ for( lpc = 1; st->value.children[lpc].kind != SCML_NONE; lpc++ ) { expr = sc->get_parent()->eval_token(&st->value.children[lpc]); if( expr.kind == SCML_TERM_TAG ) { if( find_tag(sc->get_parent()->get_lvalues(), expr.value.ti->tag) ) { scml_alert(sc->get_stream_pos(), SAF_ERROR|SAF_GENERAL, "Tag \"%s\" has already been " "defined", expr.value.ti->tag); retval = 0; } else { add_tag(sc->get_parent()->get_lvalues(), expr.value.ti->tag, TAG_NONE)->data = expr.value.ti->data; delete_tag_item(expr.value.ti); } } else { scml_alert(sc->get_stream_pos(), SAF_ERROR|SAF_GENERAL, "Expression used in defvar doesn't" "result in a tag"); retval = 0; } } return( retval ); } int c_ignore_handler(struct scml_token *st, struct scml_context *sc) { int lpc; /* Similar to defvar except we don't change anything */ for( lpc = 1; st->value.children[lpc].kind != SCML_NONE; lpc++ ) { sc->get_parent()->eval_token(&st->value.children[lpc]); } return( 1 ); } int c_scope_handler(struct scml_token *st, struct scml_context *sc) { int retval = 0; if( sc->handle_params(st) ) { struct scml_token_sequence *sts; struct scml_scope *scope; char *sc_name; tag_item *ti; if( (sc_name = scml_string:: tag_string(find_tag(sc->get_rvalues(), "name"))) ) { if( strlen(sc_name) ) { if( !(scope = sc->get_parent()-> get_scope()->find_child(sc_name)) ) { /* * Construct a new scope if one isn't * already made. */ scope = new scml_scope; scope->set_name(sc_name); scope->set_escape_table( new scml_escape_table); sc->get_parent()->get_scope()-> add_child(scope); } } else { /* Empty string means goto the root scope */ scope = sc->get_parent()->get_scope(); while( scope->get_parent() ) scope = scope->get_parent(); } /* * We need to change the parent to this scope and then * have it execute our sequence since we're just * changing the lexical scope and not changing * the execution context. (i.e. we still need * to get access to any local variables and what not) */ sc->get_parent()->set_scope(scope); if( sc->get_parent()->get_flags() & SCF_PREFORMATTED ) { sc->print_indent(sc->get_ws_queue()); sc->set_ws_queue(0); sc->get_parent()->set_ws_queue(0); } sc->get_parent()-> set_flags(sc->get_parent()->get_flags() & ~(SCF_PRINTING_BODY)); ti = find_tag(sc->get_rvalues(), "contents"); if( ti && (ti->data.kind == TAG_REF) && (sts = scml_token_sequence:: ptr(ti->data.tag_data_u.ref)) ) { retval = sc->get_parent()-> format_sequence(sts); } sc->set_ws_queue(sc->get_parent()->get_ws_queue()); sc->get_parent()->set_scope(scope->get_parent()); } else { scml_alert(sc->get_stream_pos(), SAF_ERROR|SAF_RUNTIME, "Invalid string passed in name tag" "for scope"); } } return( retval ); } /* * This is the handler for the macro command, it will construct the macro * from its parameters and contents. */ int c_macro_handler(struct scml_token *st, struct scml_context *sc) { struct scml_cmd_definition *scd; struct scml_scope *cmd_scope; char *name_str; int retval = 0; if( !sc->handle_params(st) ) return( retval ); if( (name_str = scml_string:: tag_string(find_tag(sc->get_rvalues(), "name"))) && !sc->get_parent()->get_scope()-> find_cmd_definition(&cmd_scope, name_str) && find_tag(sc->get_rvalues(), "contents")) { /* Build the new command from the given parameters */ scd = new scml_cmd_definition; scd->set_name(name_str); if( find_tag(sc->get_rvalues(), "close")->data.tag_data_u.b ) { scd->set_flags(scd->get_flags() | SCDF_BRACKETED); } /* * We use a special handler to actually execute the * macro since all commands need a handler to actually * do something. */ scd->set_handler(scml_context::get_handler_table()-> find_handler("c-macro-executer")); scd->set_token_sequence(scml_token_sequence:: ptr(find_tag(sc->get_rvalues(), "contents")-> data.tag_data_u.ref)); scd->set_opt_params(find_tag(sc->get_rvalues(), "oparams")-> data.tag_data_u.tl); scd->set_req_params(find_tag(sc->get_rvalues(), "rparams")-> data.tag_data_u.tl); sc->get_parent()->get_scope()->add_cmd_definition(scd); retval = 1; } else if( !name_str ) { scml_alert(sc->get_stream_pos(), SAF_ERROR|SAF_RUNTIME, "Invalid string passed in name tag for macro"); } else { scml_alert(sc->get_stream_pos(), SAF_ERROR|SAF_RUNTIME, "A macro named %s has already been defined", name_str); } return( retval ); } /* * This is the handler for executing user macros. This is different from * the above handler since it only constructed the command for the macro * this does the actual execution. */ int c_macro_executer(struct scml_token *st, struct scml_context *sc) { int retval = 0; if( sc->handle_params(st) ) { struct scml_token_sequence *sts; int old_offset, old_indent; /* Setup the context with values from the sequence */ sts = sc->get_cmd_def()->get_token_sequence(); old_offset = sc->get_offset_size(); sc->set_offset_size(sts->get_indent()); old_indent = sc->get_indent_size(); /* * If the parent was preformatted than it will have * indenting information that we need to duplicate. This * will record the position of the macro call so that * it can be used when printing to get the same initial * indentation as well as any indentation in the macro. */ if( sc->get_parent()->get_flags() & SCF_PREFORMATTED ) sc->set_indent_size(sc->get_stream_pos()-> get_column() - old_offset); /* * Finally execute the macro, note that the format_sequence * that called up has already gotten our "contents" variable * set up. */ if( !(retval = sc->format_sequence(sts)) ) scml_alert(sc->get_stream_pos(), SAF_ERROR|SAF_RUNTIME, "There was an error in the macro body"); sc->set_indent_size(old_indent); sc->set_offset_size(old_offset); } return( retval ); } /* This handles the if command */ int c_if_handler(struct scml_token *st, struct scml_context *sc) { struct scml_token expr; int retval = 0; /* * Similar to defvar we cheat and don't follow the syntax, * the first child in the token is expected to just evaluate * to an int or bool, rather than setting a parameter. */ expr = sc->get_parent()->eval_token(&st->value.children[1]); expr.strip(); if( ((expr.kind == SCML_TERM_INT) || (expr.kind == SCML_TERM_BOOL)) ) { struct scml_token_sequence *sts, *else_sts; struct scml_scope *cmd_scope; tag_item *ti; ti = find_tag(sc->get_rvalues(), "contents"); if( ti && (ti->data.kind == TAG_REF) && (sts = scml_token_sequence:: ptr(ti->data.tag_data_u.ref)) ) { /* Try and partition around an */ sc->set_flags(sc->get_parent()->get_flags()); else_sts = sc->partition_sequence( sc->get_cmd_def(), sc->get_scope()-> find_cmd_definition(&cmd_scope, "else"), sts); if( sc->get_parent()->get_flags() & SCF_PREFORMATTED ) { sc->print_indent(sc->get_ws_queue()); sc->set_ws_queue(0); sc->get_parent()->set_ws_queue(0); } sc->get_parent()-> set_flags(sc->get_parent()->get_flags() & ~SCF_PRINTING_BODY); /* Finally, do the test and execute the code. */ if( expr.value.i ) { retval = sc->get_parent()-> format_sequence(sts); } else if( else_sts ) { retval = sc->get_parent()-> format_sequence(else_sts); } else retval = 1; sc->set_ws_queue(sc->get_parent()->get_ws_queue()); } } else { scml_alert(sc->get_stream_pos(), SAF_ERROR|SAF_RUNTIME, "Non integer or boolean used for if"); expr.print(); } return( retval ); } /* * This handles the else command. Since its sole purpose in live is to be * used as something to partition around we just throw an error. */ int c_else_handler(struct scml_token */*st*/, struct scml_context *sc) { scml_alert(sc->get_stream_pos(), SAF_ERROR|SAF_RUNTIME, "Else should never be called by itself, it needs" " to be contained in an if block"); return( 0 ); } /* * This is the handler for 'for'. It just a simple loop construct that * can iterate over a tag array. */ int c_for_handler(struct scml_token *st, struct scml_context *sc) { int retval = 0; if( sc->handle_params(st) ) { struct scml_token_sequence *sts; union tag_data_u data; char *iter_name, *each_str; tag_item *tag, *iter_ti, *ti; int len; /* Grab the iterator and tag to iterate over */ iter_name = scml_string:: tag_string(find_tag(sc->get_rvalues(), "iter")); if( (each_str = scml_string:: tag_string(find_tag(sc->get_rvalues(), "each"))) && iter_name ) { tag = find_tag(sc->get_parent()->get_rvalues(), each_str); if( !tag && strlen(each_str) ) { scml_alert(sc->get_stream_pos(), SAF_ERROR|SAF_RUNTIME, "Couldn't find tag '%s' for " "'for' loop", each_str); return 0; } /* We can iterate over an array or a specific length */ len = find_tag(sc->get_rvalues(), "length")-> data.tag_data_u.i; if( tag ) { len = tag_data_length(&tag->data); } /* Add the iterator tag */ if( !(iter_ti = find_tag(sc->get_parent()-> get_lvalues(), iter_name)) ) { iter_ti = add_tag(sc->get_parent()-> get_lvalues(), iter_name, TAG_INTEGER, 0); } ti = find_tag(sc->get_rvalues(), "contents"); if( iter_ti->data.kind != TAG_INTEGER ) { scml_alert(sc->get_stream_pos(), SAF_ERROR|SAF_RUNTIME, "Iterator '%s' already exists" " and is not an integer", iter_name); } else if( ti && (ti->data.kind == TAG_REF) && (sts = scml_token_sequence:: ptr(ti->data.tag_data_u.ref)) ) { int lpc; /* Finally, Loop over the contents */ retval = 1; for( lpc = 0; (lpc < len) && retval; lpc++ ) { data.i = lpc; set_tag_data(&find_tag(sc-> get_parent()-> get_rvalues(), iter_name)-> data, 0, data); retval = sc->get_parent()-> format_sequence(sts); } } } else { scml_alert(sc->get_stream_pos(), SAF_ERROR|SAF_RUNTIME, "Invalid string passed in tags for 'for'"); } } return( retval ); } /* * This is the handler for the preformatting tag, it just sets the flag * for preformatting in the context */ int c_pre_handler(struct scml_token *st, struct scml_context *sc) { int retval = 0; if( sc->handle_params(st) ) { struct scml_token_sequence *sts; tag_item *ti; int do_indent; /* Clear any queued white space */ sc->set_ws_queue(0); sc->get_parent()->set_ws_queue(0); sc->get_parent()->set_flags((sc->get_flags() | SCF_PREFORMATTED)); /* * Check if we're supposed to do extra indenting based * on where a command is called */ do_indent = find_tag(sc->get_rvalues(), "indented")->data. tag_data_u.b; if( !do_indent ) sc->get_parent()->set_flags(sc->get_parent()-> get_flags() | SCF_IGNORE_INDENT); ti = find_tag(sc->get_rvalues(), "contents"); if( ti && (ti->data.kind == TAG_REF) && (sts = scml_token_sequence:: ptr(ti->data.tag_data_u.ref)) ) { int old_offset; /* Set the parent to our sequences offset */ old_offset = sc->get_parent()->get_offset_size(); sc->get_parent()->set_offset_size(sts->get_indent()); if( !(retval = sc->get_parent()-> format_sequence(sts)) ) scml_alert(sc->get_stream_pos(), SAF_ERROR|SAF_RUNTIME, "There was an error in the " "preformat body"); sc->set_ws_queue(sc->get_parent()->get_ws_queue()); sc->get_parent()->set_offset_size(old_offset); } sc->get_parent()->set_flags(sc->get_flags()); } return( retval ); } /* * This is the handler for aliascmd, it simply creates a new command definition * that is an alias for another. */ int c_aliascmd_handler(struct scml_token *st, struct scml_context *sc) { int retval = 0; if( sc->handle_params(st) ) { struct scml_cmd_definition *scd = 0; struct scml_scope *cmd_scope; char *name_str; name_str = scml_string::tag_string(find_tag(sc->get_rvalues(), "name")); if( name_str && (scd = scml_cmd_definition::ptr(find_tag(sc->get_rvalues(), "handler")-> data.tag_data_u.ref)) && !sc->get_parent()->get_scope()-> find_cmd_definition(&cmd_scope, name_str) ) { struct scml_cmd_definition *new_scd; /* Make a new command def based on the specified one */ new_scd = new scml_cmd_definition; new_scd->set_name(name_str); new_scd->set_flags(scd->get_flags()); new_scd->set_handler(scd->get_handler()); new_scd->set_token_sequence(scd->get_token_sequence()); new_scd->set_opt_params(scd->get_opt_params()); new_scd->set_req_params(scd->get_req_params()); sc->get_parent()->get_scope()-> add_cmd_definition(new_scd); retval = 1; } else { if( !scd ) { scml_alert(sc->get_stream_pos(), SAF_ERROR|SAF_RUNTIME, "Couldn't resolve cmd_name value" " to a command"); } if( !name_str ) { scml_alert(sc->get_stream_pos(), SAF_ERROR|SAF_RUNTIME, "Invalid value for 'name' tag"); } } } return( retval ); } /* This is handler for include, it allows you to include other scml files. */ int c_include_handler(struct scml_token *st, struct scml_context *sc) { char *filename; int retval = 0; if( !sc->handle_params(st) ) return 0; if( (filename = scml_string::tag_string(find_tag(sc->get_rvalues(), "file"))) ) { const char * const *include_dir_list; FILE *file; char *found_filename; /* Try and open the file in a set of include dirs */ include_dir_list = sc->get_stream_pos()->get_stream()-> get_include_directory_list(); file = fopen_search(filename, include_dir_list, "r", &found_filename); if (file) { struct scml_token_sequence *sts; struct scml_stream_pos *ssp; struct scml_scope *scope; struct scml_stream *ss; struct scml_parser *sp; /* Read in, parse, and execute the file */ scope = sc->get_parent()->get_scope(); ss = new scml_stream(); ss->set_file(file); ss->set_desc(found_filename); ss->set_include_directory_list(include_dir_list); ssp = new scml_stream_pos(); ssp->set_stream(ss); sp = new scml_parser; sp->set_stream_pos(ssp); if( (sts = sp->parse()) ) { struct scml_context *new_sc; new_sc = new scml_context; new_sc->set_flags(new_sc->get_flags() | SCF_IGNORE_WHITE_SPACE); new_sc->set_stream_pos(ssp); new_sc->set_scope(scope); if( new_sc->format_sequence(sts) ) { retval = 1; } else { scml_alert(new_sc->get_stream_pos(), SAF_ERROR|SAF_RUNTIME, "There was an error in" "executing the include " "file '%s'", filename); } } else { scml_alert(ssp, SAF_ERROR|SAF_RUNTIME, "There was an error parsing " "include file '%s'", filename); } } else { scml_alert(sc->get_stream_pos(), SAF_ERROR|SAF_RUNTIME, "Cannot open include file '%s'", filename); } } else { scml_alert(sc->get_stream_pos(), SAF_ERROR|SAF_RUNTIME, "Unable to get string from 'file' argument"); } return( retval ); } int c_retarget_handler(struct scml_token *st, struct scml_context *sc) { int retval = 0; if( sc->handle_params(st) ) { struct scml_stream *ss; tag_item *ti; ti = find_tag(sc->get_rvalues(), "output"); if( (ss = scml_stream::ptr(ti->data.tag_data_u.ref)) ) { if( ss->get_file() ) { sc->get_parent()->set_flags( sc->get_parent()->get_flags() & ~SCF_IGNORE_WHITE_SPACE); w_set_fh(ss->get_file()); } else { sc->get_parent()->set_flags( sc->get_parent()->get_flags() | SCF_IGNORE_WHITE_SPACE); w_set_fh(stdout); } retval = 1; } else { scml_alert(sc->get_stream_pos(), SAF_ERROR|SAF_RUNTIME, "Cannot get output stream"); } } return( retval ); } int c_create_stream_handler(struct scml_token *st, struct scml_context *sc) { int retval = 0; if( sc->handle_params(st) ) { char *name_str, *path_str; tag_item *ti; ti = find_tag(sc->get_rvalues(), "name"); name_str = scml_string::tag_string(ti); ti = find_tag(sc->get_rvalues(), "path"); path_str = scml_string::tag_string(ti); if( name_str && path_str ) { struct scml_stream *ss; FILE *file = NULL; if( strlen(path_str) ) { file = fopen(path_str, "w"); if( !file ) panic("Cannot create file %s", path_str); } ss = new scml_stream; ss->set_flags((ss->get_flags() | SSF_OUTPUT) & ~SSF_INPUT); ss->set_desc(path_str); ss->set_file(file); add_tag(sc->get_scope()->get_values(), name_str, TAG_REF, ss->tag_ref()); retval = 1; } } return( retval ); } struct cast_handler_entry scml_code_cast_handler_entry; int init_scml() { struct scml_handler_table *sht; struct scml_handler *sh; scml_code_cast_handler_entry.he.name = "scml-code-cast-handler"; scml_code_cast_handler_entry.c_func = scml_code_cast_handler; add_entry(cast_handler_table, &scml_code_cast_handler_entry.he); /* Construct a handler table for the set of built in handlers */ sht = new scml_handler_table; sh = new scml_handler; sh->name = "c-ignore-handler"; sh->kind = SHK_C_FUNCTION; sh->function.c_func = c_ignore_handler; sht->add_handler(sh); sh = new scml_handler; sh->name = "c-macro-handler"; sh->kind = SHK_C_FUNCTION; sh->function.c_func = c_macro_handler; sht->add_handler(sh); sh = new scml_handler; sh->name = "c-macro-executer"; sh->kind = SHK_C_FUNCTION; sh->function.c_func = c_macro_executer; sht->add_handler(sh); sh = new scml_handler; sh->name = "c-scope-handler"; sh->kind = SHK_C_FUNCTION; sh->function.c_func = c_scope_handler; sht->add_handler(sh); sh = new scml_handler; sh->name = "c-if-handler"; sh->kind = SHK_C_FUNCTION; sh->function.c_func = c_if_handler; sht->add_handler(sh); sh = new scml_handler; sh->name = "c-defvar-handler"; sh->kind = SHK_C_FUNCTION; sh->function.c_func = c_defvar_handler; sht->add_handler(sh); sh = new scml_handler; sh->name = "c-else-handler"; sh->kind = SHK_C_FUNCTION; sh->function.c_func = c_else_handler; sht->add_handler(sh); sh = new scml_handler; sh->name = "c-for-handler"; sh->kind = SHK_C_FUNCTION; sh->function.c_func = c_for_handler; sht->add_handler(sh); sh = new scml_handler; sh->name = "c-pre-handler"; sh->kind = SHK_C_FUNCTION; sh->function.c_func = c_pre_handler; sht->add_handler(sh); sh = new scml_handler; sh->name = "c-aliascmd-handler"; sh->kind = SHK_C_FUNCTION; sh->function.c_func = c_aliascmd_handler; sht->add_handler(sh); sh = new scml_handler; sh->name = "c-include-handler"; sh->kind = SHK_C_FUNCTION; sh->function.c_func = c_include_handler; sht->add_handler(sh); sh = new scml_handler; sh->name = "c-retarget-handler"; sh->kind = SHK_C_FUNCTION; sh->function.c_func = c_retarget_handler; sht->add_handler(sh); sh = new scml_handler; sh->name = "c-create-stream-handler"; sh->kind = SHK_C_FUNCTION; sh->function.c_func = c_create_stream_handler; sht->add_handler(sh); scml_context::set_handler_table(sht); return( 1 ); } /* End of file. */