@@ -435,8 +435,7 @@ func (ir *interpreter) eval_as(out interface{}, script []byte) error {
435435 return ir .tcl_obj_to_go_value (C .Tcl_GetObjResult (ir .C ), v )
436436}
437437
438- func go_value_to_tcl_obj (value interface {}) * C.Tcl_Obj {
439- v := reflect .ValueOf (value )
438+ func go_value_to_tcl_obj (v reflect.Value ) * C.Tcl_Obj {
440439 switch v .Kind () {
441440 case reflect .Int , reflect .Int8 , reflect .Int16 , reflect .Int32 , reflect .Int64 :
442441 return C .Tcl_NewWideIntObj (C .Tcl_WideInt (v .Int ()))
@@ -451,14 +450,16 @@ func go_value_to_tcl_obj(value interface{}) *C.Tcl_Obj {
451450 return C .Tcl_NewBooleanObj (0 )
452451 case reflect .String :
453452 s := v .String ()
454- sh := * (* reflect .StringHeader )(unsafe .Pointer (& s ))
455- return C .Tcl_NewStringObj ((* C .char )(unsafe .Pointer (sh .Data )), C .int (len (s )))
453+ b := C .CBytes ([]byte (s ))
454+ obj := C .Tcl_NewStringObj ((* C .char )(b ), C .int (len (s )))
455+ C .free (b )
456+ return obj
456457 }
457458 return nil
458459}
459460
460461func (ir * interpreter ) set (name string , value interface {}) error {
461- obj := go_value_to_tcl_obj (value )
462+ obj := go_value_to_tcl_obj (reflect . ValueOf ( value ) )
462463 if obj == nil {
463464 return errors .New ("gothic: cannot convert Go value to TCL object" )
464465 }
@@ -593,6 +594,19 @@ func _gotk_go_command_handler(clidataup unsafe.Pointer, objc C.int, objv unsafe.
593594 for i , n := 0 , ft .NumIn (); i < n ; i ++ {
594595 in := ft .In (i )
595596
597+ if ft .IsVariadic () && i == n - 1 && in .Kind () == reflect .Slice {
598+ for i := i ; i < len (args ); i ++ {
599+ v := reflect .New (in .Elem ()).Elem ()
600+ err := ir .tcl_obj_to_go_value (args [i ], v )
601+ if err != nil {
602+ C ._gotk_c_tcl_set_result (ir .C , C .CString (err .Error ()))
603+ return C .TCL_ERROR
604+ }
605+ ir .valuesbuf = append (ir .valuesbuf , v )
606+ }
607+ break
608+ }
609+
596610 // use default value, if there is not enough args
597611 if len (args ) <= i {
598612 ir .valuesbuf = append (ir .valuesbuf , reflect .New (in ).Elem ())
@@ -609,8 +623,33 @@ func _gotk_go_command_handler(clidataup unsafe.Pointer, objc C.int, objv unsafe.
609623 ir .valuesbuf = append (ir .valuesbuf , v )
610624 }
611625
612- // TODO: handle return value
613- f .Call (ir .valuesbuf )
626+ // Cycle through results. The first value result will be
627+ // returned; if a non-nil error result is encountered, an
628+ // error will be returned. If more than one non-error result
629+ // is encountered, that itself is an error.
630+ var returnValue * C.Tcl_Obj
631+ for _ , result := range f .Call (ir .valuesbuf ) {
632+ if result .Type ().Implements (reflect .TypeOf ((* error )(nil )).Elem ()) {
633+ if result .IsNil () {
634+ continue
635+ }
636+ e := result .MethodByName ("Error" )
637+ s := e .Call (nil )
638+ C ._gotk_c_tcl_set_result (ir .C , C .CString (s [0 ].String ()))
639+ return C .TCL_ERROR
640+ }
641+ if returnValue != nil {
642+ C ._gotk_c_tcl_set_result (ir .C , C .CString ("gothic: cannot return multiple results to TCL" ))
643+ return C .TCL_ERROR
644+ }
645+ if returnValue = go_value_to_tcl_obj (result ); returnValue == nil {
646+ C ._gotk_c_tcl_set_result (ir .C , C .CString ("gothic: cannot convert Go value to TCL object" ))
647+ return C .TCL_ERROR
648+ }
649+ }
650+ if returnValue != nil {
651+ C ._gotk_c_tcl_set_obj_result (ir .C , returnValue )
652+ }
614653
615654 return C .TCL_OK
616655}
0 commit comments