/* $XConsortium: main.cxx,v 1.10 94/09/02 18:12:30 matt Exp $ */ /* Copyright (c) 1992-1993 Silicon Graphics, Inc. * Copyright (c) 1993 Fujitsu, Ltd. * * Permission to use, copy, modify, distribute, and sell this software and * its documentation for any purpose is hereby granted without fee, provided * that (i) the above copyright notices and this permission notice appear in * all copies of the software and related documentation, and (ii) the names * of Silicon Graphics and Fujitsu may not be used in any advertising or * publicity relating to the software without the specific, prior written * permission of Silicon Graphics and Fujitsu. * * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. * * IN NO EVENT SHALL SILICON GRAPHICS OR FUJITSU BE LIABLE FOR * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE * OF THIS SOFTWARE. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #if defined(AIXV3) || defined(__GNUC__) extern "C" int strcasecmp(const char*, const char*); #endif static char* err_argument_number = "Wrong number of arguments."; static char* err_argument_type = "Wrong argument type: "; class Dish { public: Dish(Tcl_Interp*); ~Dish(); void add_commands(Tcl_Interp*); void add_variables(Tcl_Interp*); Fresco* fresco(); static Dish& instance(); static void cleanup(); private: Fresco* fresco_; Boolean interactive_; char* default_unknown_; static Dish* instance_; void restore_args(Tcl_Interp*, int& argc, char**& argv); void add_var(Tcl_Interp*, char*, BaseObjectRef); Boolean string_to_object(char*, BaseObjectRef&); char* object_to_string(BaseObjectRef, char* result); Boolean dispatch(BaseObjectRef, int argc, char* argv[], Tcl_Interp*); void set_call_status( BaseObjectRef, int, char* op, Tcl_Interp*, RequestObj::CallStatus ); Boolean parse_args( int argc, char* argv[], RequestObjRef, TypeObj::OpInfo&, Tcl_Interp* ); char* try_expand(char* arg, Tcl_Interp*); Boolean add_arg(TypeObjRef, char* arg, RequestObjRef, Tcl_Interp*); /* marshalling arguments */ Boolean add_short(char* arg, RequestObjRef); Boolean add_long(char* arg, RequestObjRef); Boolean add_unsigned_short(char* arg, RequestObjRef); Boolean add_unsigned_long(char* arg, RequestObjRef); Boolean add_float(char* arg, RequestObjRef); Boolean add_double(char* arg, RequestObjRef); Boolean add_boolean(char* arg, RequestObjRef); Boolean add_char(char* arg, RequestObjRef); Boolean add_interface(TypeObjRef, char*, RequestObjRef, Tcl_Interp*); Boolean add_array(TypeObjRef, char*, RequestObjRef, Tcl_Interp*); Boolean add_enum(TypeObjRef, char*, RequestObjRef, Tcl_Interp*); Boolean add_struct(TypeObjRef, char*, RequestObjRef, Tcl_Interp*); Boolean add_sequence(TypeObjRef, char*, RequestObjRef, Tcl_Interp*); Boolean split_list( Tcl_Interp*, char* arg, int&, char**&, char* type_name ); /* getting results */ void get_results( int argc, char* argv[], RequestObjRef, TypeObj::OpInfo&, Tcl_Interp* ); void get_result(TypeObjRef, RequestObjRef, Tcl_Interp*); void get_concrete(TypeObj::KindOf, RequestObjRef, Tcl_Interp*); void get_interface(TypeObjRef, RequestObjRef, Tcl_Interp*); void get_array(TypeObjRef, RequestObjRef, Tcl_Interp*); void get_string(RequestObjRef, Tcl_Interp*); void get_enum(TypeObjRef, RequestObjRef, Tcl_Interp*); void get_struct(TypeObjRef, RequestObjRef, Tcl_Interp*); void get_sequence(TypeObjRef, RequestObjRef, Tcl_Interp*); /* Dish-specific Tcl commands */ static int unknown(ClientData, Tcl_Interp*, int argc, char* argv[]); static int main(ClientData, Tcl_Interp*, int argc, char* argv[]); static int spawn(ClientData, Tcl_Interp*, int argc, char* argv[]); static int action(ClientData, Tcl_Interp*, int argc, char* argv[]); static int delay(ClientData, Tcl_Interp*, int argc, char* argv[]); static int debug(ClientData, Tcl_Interp*, int argc, char* argv[]); }; class FrescoMain : public ActionImpl { public: FrescoMain(ViewerRef, GlyphRef); ~FrescoMain(); void execute(); private: ViewerRef viewer_; GlyphRef glyph_; }; class DishAction : public ActionImpl { public: DishAction(Tcl_Interp*, char* command); ~DishAction(); void execute(); private: Tcl_Interp* interp_; char* command_; }; /* class Dish */ Dish* Dish::instance_; Dish& Dish::instance() { return *instance_; } Dish::Dish(Tcl_Interp* interp) { instance_ = this; char* interactive = Tcl_GetVar( interp, "tcl_interactive", TCL_GLOBAL_ONLY ); interactive_ = (interactive[0] == '1'); int argc; char** argv; restore_args(interp, argc, argv); fresco_ = Fresco_open("Dish", argc, argv); default_unknown_ = nil; } Dish::~Dish() { Fresco::unref(fresco_); } Fresco* Dish::fresco() { return fresco_; } void Dish::cleanup() { delete instance_; } void Dish::restore_args(Tcl_Interp* interp, int& argc, char**& argv) { int tcl_argc; char** tcl_argv; Tcl_SplitList( interp, Tcl_GetVar(interp, "argv", TCL_GLOBAL_ONLY), &tcl_argc, &tcl_argv ); argc = tcl_argc + 1; argv = new char*[argc + 1]; char* argv0 = Tcl_GetVar(interp, "argv0", TCL_GLOBAL_ONLY); argv[0] = argv0; for (int i = 0; i < tcl_argc; i++) { const char* arg = tcl_argv[i]; int length = strlen(arg); char* copy = new char[length + 1]; sprintf(copy, "%s", arg); argv[i + 1] = copy; } argv[argc] = 0; delete [] tcl_argv; } void Dish::add_commands(Tcl_Interp* interp) { if (Tcl_Eval(interp, "rename unknown default_unknown") == TCL_OK) { default_unknown_ = "default_unknown"; } Tcl_CreateCommand(interp, "unknown", unknown, NULL, NULL); Tcl_CreateCommand(interp, "main", main, NULL, NULL); Tcl_CreateCommand(interp, "spawn", spawn, NULL, NULL); Tcl_CreateCommand(interp, "action", action, NULL, NULL); Tcl_CreateCommand(interp, "delay", delay, NULL, NULL); Tcl_CreateCommand(interp, "debug", debug, NULL, NULL); } void Dish::add_variables(Tcl_Interp* interp) { Dish& d = *instance_; Fresco* f = fresco_; d.add_var(interp, "drawing_kit", f->drawing_kit()); d.add_var(interp, "figure_kit", f->figure_kit()); d.add_var(interp, "layout_kit", f->layout_kit()); d.add_var(interp, "widget_kit", f->widget_kit()); } void Dish::add_var(Tcl_Interp* interp, char* name, BaseObjectRef value) { char buffer[100]; Tcl_SetVar(interp, name, object_to_string(value, buffer), 0); } /* * The 'unknown' command first determines if the command is Fresco object * or not. If it is, then Dish performs dii on the object. Otherwise, the * default 'unknown' command is invoked, if it exists. */ int Dish::unknown(ClientData, Tcl_Interp* interp, int argc, char* argv[]) { if (argc < 2) { interp->result = "\"unknown\" must be followed by a command."; return TCL_ERROR; } Dish& dish = instance(); BaseObjectRef object; if (dish.string_to_object(dish.try_expand(argv[1], interp), object)) { if (is_not_nil(object) && dish.dispatch(object, argc - 1, &argv[1], interp) ) { return TCL_OK; } else { return TCL_ERROR; } } else { char* default_unknown = dish.default_unknown_; if (default_unknown != nil) { argv[0] = default_unknown; return Tcl_Eval(interp, Tcl_Merge(argc, argv)); } else { Tcl_AppendResult( interp, "invalid command name: \"", argv[1], "\"", (char *)0 ); return TCL_ERROR; } } } Boolean Dish::string_to_object(char* s, BaseObjectRef& obj) { Boolean b = true; if (strcmp(s, "0") == 0) { obj = nil; } else { #if defined(__GNUC__) b = sscanf(s, "_dish_%lx", &obj) == 1; #else b = sscanf(s, "_dish_%p", &obj) == 1; #endif } return b; } char* Dish::object_to_string(BaseObjectRef obj, char* result) { if (is_not_nil(obj)) { #if defined(__GNUC__) sprintf(result, "_dish_%lx", obj); #else sprintf(result, "_dish_%p", obj); #endif } else { sprintf(result, "0"); } return result; } Boolean Dish::dispatch( BaseObjectRef obj, int argc, char* argv[], Tcl_Interp* interp ) { Boolean b = false; if (argc > 1) { RequestObj_var req = fresco_->create_request(obj); char* op = argv[1]; req->set_operation(op); TypeObj::OpInfo op_info; RequestObj::CallStatus status = req->op_info(op_info); if (status == RequestObj::ok) { if (parse_args(argc - 2, &argv[2], req, op_info, interp)) { status = req->invoke(); if (status == RequestObj::ok) { get_results(argc - 2, &argv[2], req, op_info, interp); b = true; } else { set_call_status(obj, argc, op, interp, status); } } } else { set_call_status(obj, argc, op, interp, status); } } else { Tcl_AppendResult(interp, err_argument_number, 0); } if (!b) { Tcl_AppendResult( interp, ".\nExpected: ObjectRef operation argument-list.", 0 ); } return b; } void Dish::set_call_status( BaseObjectRef obj, int argc, char* op, Tcl_Interp* interp, RequestObj::CallStatus status ) { char obj_string[100]; object_to_string(obj, obj_string); char* type_name = obj->_type()->name(); switch (status) { case RequestObj::unknown_operation: Tcl_AppendResult( interp, "Error: no operation '", type_name, "::", op, "' for object ", obj_string, 0 ); break; case RequestObj::bad_argument_count: { char count[10]; sprintf(count, "%d", argc - 2); Tcl_AppendResult( interp, "Error: bad argument count ", count, " for '", type_name, "::", op, 0 ); break; } case RequestObj::ambiguous_operation: Tcl_AppendResult( interp, "Error: ambigous operation '", op, "' for object ", obj_string, " of type ", type_name, 0 ); break; } } Boolean Dish::parse_args( int argc, char* argv[], RequestObjRef req, TypeObj::OpInfo& op_info, Tcl_Interp* interp ) { Boolean b = false; if (op_info.op_params._length == argc) { for (int i = 0; i < argc; i++) { TypeObj::ParamInfo& p = op_info.op_params._buffer[i]; char* arg = (p.param_mode != TypeObj::param_out) ? argv[i] : nil; if (!add_arg(p.param_type, arg, req, interp)) { Tcl_AppendResult( interp, err_argument_type, "\nExpecting: ", p.param_type->name(), ", got `", argv[i], "'", 0 ); break; } } b = i == argc; } else { Tcl_AppendResult(interp, err_argument_number, 0); } return b; } char* Dish::try_expand(char* arg, Tcl_Interp* interp) { char* expanded = Tcl_GetVar(interp, arg, 0); if (expanded == nil) { expanded = arg; } return expanded; } Boolean Dish::add_arg( TypeObjRef type, char* arg, RequestObjRef req, Tcl_Interp* interp ) { if (arg != nil) { arg = try_expand(arg, interp); } switch (type->kind()) { case TypeObj::interface_type: return add_interface(type, arg, req, interp); case TypeObj::boolean_type: return add_boolean(arg, req); case TypeObj::char_type: return add_char(arg, req); case TypeObj::double_type: return add_double(arg, req); case TypeObj::float_type: return add_float(arg, req); case TypeObj::long_type: return add_long(arg, req); case TypeObj::unsigned_long_type: return add_unsigned_long(arg, req); case TypeObj::short_type: return add_short(arg, req); case TypeObj::unsigned_short_type: return add_unsigned_short(arg, req); case TypeObj::array_type: return add_array(type, arg, req, interp); case TypeObj::enum_type: return add_enum(type, arg, req, interp); case TypeObj::struct_type: return add_struct(type, arg, req, interp); case TypeObj::sequence_type: return add_sequence(type, arg, req, interp); case TypeObj::typedef_type: return add_arg(type->typedef_info(), arg, req, interp); default: fprintf( stderr, "internal error: unknown type %d in add_arg\n", type->kind() ); abort(); } } Boolean Dish::add_short(char* arg, RequestObjRef req) { Boolean b = true; if (arg != nil) { char* ptr; short i = short(strtol(arg, &ptr, 0)); if (*ptr == '\0') { req->put_short(i); } else { b = false; } } else { req->put_short(0); } return b; } Boolean Dish::add_long(char* arg, RequestObjRef req) { Boolean b = true; if (arg != nil) { char* ptr; Long i = strtol(arg, &ptr, 0); if (*ptr == '\0') { req->put_long(i); } else { b = false; } } else { req->put_long(0); } return b; } Boolean Dish::add_unsigned_short(char* arg, RequestObjRef req) { Boolean b = true; if (arg != nil) { char* ptr; unsigned short i = (unsigned short) strtol(arg, &ptr, 0); if (*ptr == '\0') { req->put_unsigned_short(i); } else { b = false; } } else { req->put_unsigned_short(0); } return b; } Boolean Dish::add_unsigned_long(char* arg, RequestObjRef req) { Boolean b = true; if (arg != nil) { char* ptr; ULong i = strtol(arg, &ptr, 0); if (*ptr == '\0') { req->put_unsigned_long(i); } else { b = false; } } else { req->put_unsigned_long(0); } return b; } Boolean Dish::add_float(char* arg, RequestObjRef req) { Boolean b = true; if (arg != nil) { char* ptr; float f = float(strtod(arg, &ptr)); if (*ptr == '\0') { req->put_float(f); } else { b = false; } } else { req->put_float(0); } return b; } Boolean Dish::add_double(char* arg, RequestObjRef req) { Boolean b = true; if (arg != nil) { char* ptr; double d = strtod(arg, &ptr); if (*ptr == '\0') { req->put_double(d); } else { b = false; } } else { req->put_double(0); } return b; } Boolean Dish::add_boolean(char* arg, RequestObjRef req) { Boolean b = true; if (arg != nil) { if (strcasecmp(arg, "true") == 0) { req->put_boolean(true); } else if (strcasecmp(arg, "false") == 0) { req->put_boolean(false); } else { b = false; } } else { req->put_boolean(false); } return b; } Boolean Dish::add_char(char* arg, RequestObjRef req) { if (arg != nil) { req->put_char(arg[0]); } else { req->put_char(0); } return true; } Boolean Dish::add_interface( TypeObjRef type, char* arg, RequestObjRef req, Tcl_Interp* ) { Boolean b = true; if (arg != nil) { if (strcmp(type->name(), "CharString") == 0) { req->put_object(Fresco::string_copy(arg)); } else { BaseObjectRef o = nil; if (string_to_object(arg, o)) { /* todo: check if (object is_a type) */ req->put_object(o); } else { b = false; } } } else { req->put_object(nil); } return b; } Boolean Dish::add_array( TypeObjRef array, char* arg, RequestObjRef req, Tcl_Interp* interp ) { Boolean b = false; Long element_count; TypeObj_var element_type; array->array_info(element_type._out(), element_count); if (arg != nil) { int argc; char** argv; if (split_list(interp, arg, argc, argv, "array")) { if (argc == element_count) { req->begin_aggregate(); for (int i = 0; i < argc; i++) { if (!add_arg(element_type, argv[i], req, interp)) { char error[100]; sprintf( error, "%s: expected '%s', got '%s'", "Array element type mismatch", element_type->name(), argv[i] ); Tcl_AppendResult(interp, error, 0); break; } } req->end_aggregate(); b = i == argc; delete [] argv; } else { char error[100]; sprintf( error, "Array size mismatch: expected '%d', got '%d'\n.", element_count, argc ); Tcl_AppendResult(interp, error, 0); } } } else { req->begin_aggregate(); for (int i = 0; i < element_count; i++) { add_arg(element_type, nil, req, interp); } req->end_aggregate(); b = true; } return b; } Boolean Dish::add_enum( TypeObjRef, char* arg, RequestObjRef req, Tcl_Interp* ) { /* todo: allow enum literals */ /* should check that given value is valid */ return add_unsigned_long(arg, req); } Boolean Dish::add_struct( TypeObjRef t, char* arg, RequestObjRef req, Tcl_Interp* interp ) { Boolean b = false; long field_count = t->members(); if (arg != nil) { int argc; char** argv; if (split_list(interp, arg, argc, argv, "struct")) { if (argc == field_count) { req->begin_aggregate(); for (int i = 0; i < argc; i++) { TypeObjRef m = t->member_info(i); if (!add_arg(m, argv[i], req, interp)) { char error[100]; sprintf( error, "Field type mismatch: expected '%s', got '%s'", m->name(), argv[i] ); Tcl_AppendResult(interp, error, 0); break; } } req->end_aggregate(); b = i == argc; delete [] argv; } else { char error[100]; sprintf( error, "Struct field count mismatch: expected %d, got %d.", field_count, argc ); Tcl_AppendResult(interp, error, 0); } } } else { req->begin_aggregate(); for (int i = 0; i < field_count; i++) { add_arg(t->member_info(i), nil, req, interp); } req->end_aggregate(); b = true; } return b; } Boolean Dish::add_sequence( TypeObjRef sequence, char* arg, RequestObjRef req, Tcl_Interp* interp ) { Boolean b = false; Long length; TypeObj_var element_type; sequence->sequence_info(element_type._out(), length); if (arg != nil) { int argc; char** argv; if (split_list(interp, arg, argc, argv, "sequence")) { req->begin_aggregate(); /* put maximum and length */ req->put_long(argc); req->put_long(argc); for (int i = 0; i < argc; i++) { if (!add_arg(element_type, argv[i], req, interp)) { char error[100]; sprintf( error, "%s: expected '%s', got '%s'", "Sequence element type mismatch", element_type->name(), argv[i] ); Tcl_AppendResult(interp, error, 0); break; } req->end_aggregate(); b = (i == argc); delete [] argv; } } } else { req->begin_aggregate(); req->put_long(0); req->put_long(0); req->put_long(0); req->end_aggregate(); b = true; } return b; } Boolean Dish::split_list( Tcl_Interp* interp, char* arg, int& argc, char**& argv, char* type ) { Boolean b = false; /* todo: this doesn't handle "t scale scale" when scale isn't set */ if (Tcl_SplitList(interp, arg, &argc, &argv) == TCL_OK) { char** intermediate = argv; if (argc == 1 && Tcl_SplitList(interp, intermediate[0], &argc, &argv) == TCL_OK ) { b = true; delete [] intermediate; } } if (!b) { Tcl_AppendResult( interp, "Expecting ", type, " to be represented as tcl list, got '", arg, "'", 0 ); } return b; } void Dish::get_results( int argc, char* argv[], RequestObjRef req, TypeObj::OpInfo& op, Tcl_Interp* interp ) { for (int i = 0; i < argc; i++) { TypeObj::ParamInfo& p = op.op_params._buffer[i]; if (p.param_mode != TypeObj::param_in) { get_result(p.param_type, req, interp); char* arg = argv[i]; if (arg != nil) { Tcl_SetVar(interp, arg, interp->result, TCL_LIST_ELEMENT); Tcl_ResetResult(interp); } } } TypeObjRef return_type = op.op_result; if (return_type->kind() != TypeObj::void_type) { get_result(return_type, req, interp); } } void Dish::get_result( TypeObjRef type, RequestObjRef req, Tcl_Interp* interp ) { TypeObj::KindOf tag = type->kind(); switch (tag) { case TypeObj::interface_type: get_interface(type, req, interp); break; case TypeObj::array_type: get_array(type, req, interp); break; case TypeObj::enum_type: get_enum(type, req, interp); break; case TypeObj::struct_type: get_struct(type, req, interp); break; case TypeObj::sequence_type: get_sequence(type, req, interp); break; case TypeObj::typedef_type: get_result(type->typedef_info(), req, interp); break; default: get_concrete(tag, req, interp); break; } } void Dish::get_concrete( TypeObj::KindOf tag, RequestObjRef req, Tcl_Interp* interp ) { char result[200]; switch(tag) { case TypeObj::boolean_type: sprintf(result, "%s", req->get_boolean() ? "true" : "false"); break; case TypeObj::char_type: sprintf(result, "%c", req->get_char()); break; case TypeObj::double_type: sprintf(result, "%g", req->get_double()); break; case TypeObj::float_type: sprintf(result, "%g", req->get_float()); break; case TypeObj::long_type: sprintf(result, "%ld", req->get_long()); break; case TypeObj::unsigned_long_type: sprintf(result, "%ld", req->get_unsigned_long()); break; case TypeObj::short_type: sprintf(result, "%d", req->get_short()); break; case TypeObj::unsigned_short_type: sprintf(result, "%d", req->get_unsigned_short()); break; default: fprintf(stderr, "Dish::get_concrete: unknown type"); fflush(stderr); abort(); } Tcl_AppendResult(interp, result, 0); } /* * Should check the interface actual type is compatible with the formal. */ void Dish::get_interface( TypeObjRef, RequestObjRef req, Tcl_Interp* interp ) { BaseObjectRef object = req->get_object(); CharString_var s = CharString::_narrow(object); if (is_not_nil(s)) { CharStringBuffer cs(s); Tcl_AppendResult(interp, cs.string(), 0); } else { char buffer[100]; Tcl_AppendResult(interp, object_to_string(object, buffer), 0); } } void Dish::get_array( TypeObjRef array, RequestObjRef req, Tcl_Interp* interp ) { Tcl_DString result; Tcl_DStringInit(&result); Long element_count; TypeObj_var element_type; array->array_info(element_type._out(), element_count); for (int i = 0; i < element_count; i++) { get_result(element_type, req, interp); result.string = Tcl_DStringAppendElement(&result, interp->result); Tcl_ResetResult(interp); } Tcl_DStringResult(interp, &result); Tcl_DStringFree(&result); } void Dish::get_string(RequestObjRef req, Tcl_Interp* interp) { char* result = req->get_string(); Tcl_AppendResult(interp, result, 0); delete result; } void Dish::get_enum( TypeObjRef, RequestObjRef req, Tcl_Interp* interp ) { /* todo: use enum literals */ char result[10]; sprintf(result, "%ld", req->get_unsigned_long()); Tcl_AppendResult(interp, result, 0); } void Dish::get_struct( TypeObjRef struct_type, RequestObjRef req, Tcl_Interp* interp ) { Tcl_DString result; Tcl_DStringInit(&result); long field_count = struct_type->members(); for (int i = 0; i < field_count; i++) { get_result(struct_type->member_info(i), req, interp); result.string = Tcl_DStringAppendElement(&result, interp->result); Tcl_ResetResult(interp); } Tcl_DStringResult(interp, &result); Tcl_DStringFree(&result); } void Dish::get_sequence( TypeObjRef sequence, RequestObjRef req, Tcl_Interp* interp ) { Tcl_DString result; Tcl_DStringInit(&result); Long size; TypeObj_var element_type; sequence->sequence_info(element_type._out(), size); size = req->get_long(); long length = req->get_long(); for (int i = 0; i < length; i++) { get_result(element_type, req, interp); result.string = Tcl_DStringAppendElement(&result, interp->result); Tcl_ResetResult(interp); } Tcl_DStringResult(interp, &result); Tcl_DStringFree(&result); } int Dish::main(ClientData, Tcl_Interp* interp, int argc, char* argv[]) { int status = TCL_ERROR; Dish& dish = instance(); if (argc != 3) { Tcl_AppendResult(interp, err_argument_number, 0); } else { BaseObjectRef obj; char* argv1 = dish.try_expand(argv[1], interp); if (!dish.string_to_object(argv1, obj)) { Tcl_AppendResult(interp, err_argument_type, argv1, 0); } else { ViewerRef viewer = Viewer::_narrow(obj); char* argv2 = dish.try_expand(argv[2], interp); if (!dish.string_to_object(argv2, obj)) { Tcl_AppendResult(interp, err_argument_type, argv2, 0); } else { GlyphRef glyph = Glyph::_narrow(obj); if (!(is_not_nil(viewer) || is_not_nil(glyph))) { Tcl_AppendResult(interp, "nil viewer or glyph", 0); } else { Fresco* fresco = dish.fresco(); if (dish.interactive_) { ThreadKit_var threads = fresco->thread_kit(); ThreadObjRef t = threads->thread( new FrescoMain(viewer, glyph) ); if (is_not_nil(t)) { t->run(); } else { fresco->run(viewer, glyph); } } else { fresco->run(viewer, glyph); } status = TCL_OK; } } } } if (status == TCL_ERROR) { Tcl_AppendResult(interp, ".\nExpected `main ViewerRef GlyphRef'.", 0); } return status; } int Dish::spawn(ClientData, Tcl_Interp* interp, int argc, char* argv[]) { int status = TCL_ERROR; if (argc == 2) { Dish& dish = instance(); BaseObjectRef obj; if (dish.string_to_object(argv[1], obj)) { ActionRef a = Action::_narrow(obj); if (is_not_nil(a)) { Fresco* fresco = dish.fresco_; ThreadKit_var threads = fresco->thread_kit(); ThreadObjRef t = threads->thread(a); if (is_not_nil(t)) { t->run(); #if defined(__GNUC__) sprintf(interp->result, "%lx", ThreadObjRef(t)); #else sprintf(interp->result, "%p", ThreadObjRef(t)); #endif status = TCL_OK; } else { Tcl_AppendResult(interp, "No threads available", 0); } } else { Tcl_AppendResult(interp, err_argument_type, ": ", argv[1], 0); } } else { Tcl_AppendResult(interp, err_argument_type, ": ", argv[1], 0); } } else { Tcl_AppendResult(interp, err_argument_number, 0); } return status; } int Dish::action(ClientData, Tcl_Interp* interp, int argc, char* argv[]) { int status = TCL_ERROR; if (argc > 1) { ActionRef a = new DishAction(interp, Tcl_Merge(argc - 1, &argv[1])); char buffer[100]; Dish& d = Dish::instance(); Tcl_AppendResult(interp, d.object_to_string(a, buffer), 0); status = TCL_OK; } else { Tcl_AppendResult( interp, err_argument_number, ".\nExpected: 'action command'.", 0 ); } return status; } int Dish::delay(ClientData, Tcl_Interp* interp, int argc, char* argv[]) { int status = TCL_ERROR; if (argc == 2) { Dish& d = Dish::instance(); double n; if (Tcl_GetDouble(interp, d.try_expand(argv[1], interp), &n) == TCL_OK) { if (Fresco::delay(Float(n))) { status = TCL_OK; } else { Tcl_AppendResult(interp, "Failed in delay", 0); } } } else { Tcl_AppendResult(interp, err_argument_number, 0); } if ((status & TCL_ERROR) != 0) { Tcl_AppendResult(interp, ".\nExpected: 'delay float-seconds'.", 0); } return status; } int Dish::debug(ClientData, Tcl_Interp* interp, int argc, char* argv[]) { int status = TCL_ERROR; BaseObjectRef object; GlyphRef g; Dish& dish = Dish::instance(); if (argc != 3) { Tcl_AppendResult(interp, err_argument_number, 0); } else if ( !dish.string_to_object(dish.try_expand(argv[1], interp), object) ) { Tcl_AppendResult( interp, "Argument 1 ", argv[1], " is not a dish object.", 0 ); } else if (is_nil(g = Glyph::_narrow(object))) { Tcl_AppendResult( interp, "Argument 1 ", argv[1], " is not a glyph.", 0 ); } else { char* l = new char[strlen(argv[2]) + 1]; sprintf(l, "%s", argv[2]); GlyphRef d = new DebugGlyph(g, l, DebugGlyph::trace_request_traverse); char buffer[100]; Tcl_AppendResult(interp, dish.object_to_string(d, buffer), 0); status = TCL_OK; } if (status == TCL_ERROR) { Tcl_AppendResult(interp, " Expected: debug label.", 0); } return status; } /* class FrescoMain */ FrescoMain::FrescoMain(ViewerRef viewer, GlyphRef glyph) { viewer_ = viewer; glyph_ = glyph; } FrescoMain::~FrescoMain() {} void FrescoMain::execute() { ViewerRef v = viewer_; GlyphRef g = glyph_; Fresco* fresco = Dish::instance().fresco(); Display_var display = fresco->open_default_display(); Screen_var s = display->default_screen(); ViewerRef nv; if (is_nil(g)) { nv = v; } else { nv = new ViewerImpl(fresco, true); nv->body(g); if (is_not_nil(v)) { nv->append_viewer(v); } } Window_var w = s->application(nv); w->map(); display->run(true); delete this; } /* class DishAction */ DishAction::DishAction(Tcl_Interp* interp, char* command) { interp_ = interp; command_ = command; } DishAction::~DishAction() { delete command_; } void DishAction::execute() { if (Tcl_Eval(interp_, command_) != TCL_OK) { fprintf(stderr, "DishAction failed: %s.\n", interp_->result); fflush(stdout); } } /* * This is for platforms that don't have atexit() */ #if defined(sun) && !defined(SVR4) extern "C" int on_exit(void (*)(), caddr_t); int atexit(void (*func)(void)) { return on_exit(func, NULL); } #endif /* * This is for cfront-based compilers that need to call _main to * get static initializers run. */ #if defined(sun) && !defined(SVR4) && !defined(__GNUC__) extern "C" void _main(); void init_static_initializers() { _main(); } #else void init_static_initializers() { /* nothing */ } #endif /* * Called by main() defined in tcl lib. */ int Tcl_AppInit(Tcl_Interp* interp) { init_static_initializers(); atexit(&Dish::cleanup); Dish* dish = new Dish(interp); dish->add_commands(interp); dish->add_variables(interp); return TCL_OK; }