tclObjc.m
上传用户:shenzhenrh
上传日期:2013-05-12
资源大小:2904k
文件大小:17k
源码类别:

信息检索与抽取

开发平台:

Unix_Linux

  1. /* Implementation for Objective-C Tcl interpreter functions
  2.    Copyright (C) 1993,1994  R. Andrew McCallum
  3.    Written by:  R. Andrew McCallum <mccallum@cs.rochester.edu>
  4.    Dept. of Computer Science, U. of Rochester, Rochester, NY  14627
  5.    Rewritten for Swarm FCall by Marcus G. Daniels <mgd@santafe.edu>. (C)1999
  6.    With NeXT runtime compatibility incorporated by:
  7.    Robert Stabl <stabl@informatik.uni-muenchen.de>
  8.    Comp. Sci. Inst., U. of Munich, Leopoldstr. 11B D-80802 Muenchen
  9.    This file is part of the Tcl/Objective-C interface library.
  10.    This library is free software; you can redistribute it and/or
  11.    modify it under the terms of the GNU Library General Public
  12.    License as published by the Free Software Foundation; either
  13.    version 2 of the License, or (at your option) any later version.
  14.    
  15.    This library is distributed in the hope that it will be useful,
  16.    but WITHOUT ANY WARRANTY; without even the implied warranty of
  17.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  18.    Library General Public License for more details.
  19.    You should have received a copy of the GNU Library General Public
  20.    License along with this library; if not, write to the Free
  21.    Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  22. */ 
  23. #include <swarmconfig.h>
  24. #import <defobj.h> // FArguments, FCall
  25. #import <defobj/DefObject.h> // mapalloc_t for defalloc
  26. #import <defobj/defalloc.h> // getCZone
  27. #include "tclObjc.h"
  28. #include <tcl.h>
  29. #include <misc.h>
  30. #define ATDELIMCHAR '@'
  31.   
  32. #include <objc/objc-api.h>
  33. #include <objc/encoding.h>
  34. int (*tclObjc_eventHook) ();
  35. Tcl_Interp *_TclObject_interp;
  36. char *
  37. tclObjc_objectToName(id obj)
  38. {
  39.   /* Fix this messiness */
  40.   static char name[512];
  41.   if (obj)
  42.     {
  43.       sprintf(name, "%s%c" PTRHEXFMT, obj->class_pointer->name, ATDELIMCHAR, obj);
  44.       return name;
  45.     }
  46.   return "nil";
  47. }
  48. /* Return TCLOBJC_NO_OBJ if name is no good */
  49. id
  50. tclObjc_nameToObject (const char *name)
  51. {
  52.   id object;
  53.   unsigned long ul;
  54.   const char *p = name;
  55.   while (*p != ATDELIMCHAR && *p != '') p++;
  56.   if ((*p) && (sscanf(p+3, "%lx", &ul) == 1))
  57.     {
  58.       return (id)ul;
  59.     }
  60.   else if ((!strcmp(name, "nil")) 
  61.    || (!strcmp(name, "Nil"))
  62.    || (!strcmp(name, "0x0")))
  63.     {
  64.       return nil;
  65.     }
  66.   else if ((object = (id)objc_lookup_class(name)))
  67.     {
  68.       return object;
  69.     }
  70.   return TCLOBJC_NO_OBJ;
  71. }
  72. static id
  73. getObjectReturn (void *p)
  74. {
  75.   return *(id *) p;
  76. }
  77. static void *
  78. getPointerReturn (void *p)
  79. {
  80.   return *(void **) p;
  81. }
  82. static int
  83. getIntegerReturn (void * p)
  84. {
  85.   return *(int *) p;
  86. }
  87. static unsigned
  88. getUIntegerReturn (void *p)
  89. {
  90.   return *(unsigned *) p;
  91. }
  92. static short
  93. getShortReturn (void *p)
  94. {
  95.   return *(short *) p;
  96. }
  97. static unsigned short
  98. getUShortReturn (void *p)
  99. {
  100.   return *(unsigned short *) p;
  101. }
  102. static long
  103. getLongReturn (void *p)
  104. {
  105.   return *(long *) p;
  106. }
  107. static unsigned long
  108. getULongReturn (void *p)
  109. {
  110.   return *(unsigned long *) p;
  111. }
  112. static char
  113. getCharReturn (void *p)
  114. {
  115.   return *(char *) p;
  116. }
  117. static unsigned char
  118. getUCharReturn (void *p)
  119. {
  120.   return *(unsigned char *) p;
  121. }
  122. static char *
  123. getStringReturn (void *p)
  124. {
  125.   return *(unsigned char **) p;
  126. }
  127. static float
  128. getFloatReturn (void *p)
  129. {
  130.   return *(float *) p;
  131. }
  132. static double
  133. getDoubleReturn (void *p)
  134. {
  135.   return *(double *) p;
  136. }
  137. int
  138. tclObjc_msgSendToClientData(ClientData clientData, Tcl_Interp *interp,
  139.     int argc, char *argv[])
  140. {
  141.   char resultString[1024];
  142.   char methodName[100];
  143.   BOOL argvIsMethodArg[256];
  144.   id target;
  145.   SEL sel;
  146.   unsigned i;
  147.   if (argc < 2)
  148.     {
  149.       interp->result = "no method specified.";
  150.       return TCL_ERROR;
  151.     }
  152.   argvIsMethodArg[0] = NO;
  153.   argvIsMethodArg[1] = NO;
  154.   strcpy (methodName, argv[1]);
  155.   for (i = 2; i < (unsigned)argc; i++)
  156.     {
  157.       if (argv[i][strlen (argv[i]) - 1] == ':')
  158. {
  159.   strcat (methodName, argv[i]);
  160.   argvIsMethodArg[i] = NO;
  161. }
  162.       else
  163.         argvIsMethodArg[i] = YES;
  164.     }
  165.   target = (id) clientData;
  166.   sel = sel_get_any_typed_uid (methodName);
  167.   if (![target respondsTo: sel])
  168.     {
  169.       fprintf (stderr, "%s does not respond to method %sn",
  170.                [target name], methodName);
  171.       Tcl_SetResult (interp, "object does not respond to method", TCL_STATIC); 
  172.       return TCL_ERROR;
  173.     }
  174.   
  175.   {
  176.     const char *seltype = sel_get_type (sel), *type;
  177.     id <FArguments> fa;
  178.     id <FCall> fc = nil;
  179.     void *ret = NULL;
  180.     unsigned argnum;
  181.     fa = [FArguments createBegin: getCZone (scratchZone)];
  182.     [fa setObjCReturnType: *(objc_skip_type_qualifiers (seltype))];
  183.     type = objc_skip_argspec (seltype);
  184.     type = objc_skip_argspec (type);
  185.     type = objc_skip_argspec (type);
  186.     for (argnum = 2; *type; type = objc_skip_argspec (type), argnum++)
  187.       {
  188.         while (!argvIsMethodArg[argnum]) argnum++;
  189.           const char *unqualifiedtype = objc_skip_type_qualifiers (type);
  190.           
  191.           switch (*unqualifiedtype)
  192.             {
  193.             case _C_ID:
  194.               {
  195.                 id obj = tclObjc_nameToObject (argv[argnum]);
  196.                 
  197.                 if (obj != TCLOBJC_NO_OBJ)
  198.                   [fa addObject: obj];
  199.                 else
  200.                   {
  201.                     sprintf (interp->result, 
  202.                              "Expected objc object, got %s instead.n", 
  203.                              argv[argnum]);
  204.                     goto fail;
  205.                   }
  206.               }
  207.               break;
  208.             case _C_PTR:
  209.               abort ();
  210.               break;
  211.             case _C_INT:
  212.               {
  213.                 int value;
  214.                 
  215.                 sscanf (argv[argnum], "%d", &value);
  216.                 [fa addInt: value];
  217.               }
  218.               break;
  219.             case _C_UINT:
  220.               {
  221.                 unsigned value;
  222.                 
  223.                 sscanf (argv[argnum], "%u", &value);
  224.                 [fa addUnsigned: value];
  225.               }
  226.               break;
  227.             case _C_LNG:
  228.               {
  229.                 long value;
  230.                 
  231.                 sscanf (argv[argnum], "%ld", &value);
  232.                 [fa addLong: value];
  233.               }
  234.               break;
  235.             case _C_ULNG:
  236.               {
  237.                 unsigned long value;
  238.                 
  239.                 sscanf (argv[argnum], "%lu", &value);
  240.                 [fa addUnsignedLong: value];
  241.               }
  242.               break;
  243.             case _C_SHT:
  244.               {
  245.                 short value;
  246.                 
  247.                 sscanf (argv[argnum], "%hd", &value);
  248.                 [fa addShort: value];
  249.               }
  250.               break;
  251.             case _C_USHT:
  252.               {
  253.                 unsigned short value;
  254.                 
  255.                 sscanf (argv[argnum], "%hu", &value);
  256.                 [fa addUnsignedShort: value];
  257.               }
  258.               break;
  259.             case _C_CHR:
  260.               {
  261.                 char value;
  262.                 
  263.                 sscanf (argv[argnum], "%c", &value);
  264.                 [fa addChar: value];
  265.               }
  266.               break;
  267.             case _C_UCHR:
  268.               {
  269.                 unsigned value;
  270.                 
  271.                 sscanf (argv[argnum], "%u", &value);
  272.                 [fa addUnsignedChar: (unsigned char) value];
  273.               }
  274.               break;
  275.             case _C_CHARPTR:
  276.               [fa addString: argv[argnum]];
  277.               break;
  278.             case _C_FLT:
  279.               {
  280.                 float value;
  281.                 
  282.                 sscanf (argv[argnum], "%f", &value);
  283.                 [fa addFloat: value];
  284.               }
  285.               break;
  286.             case  _C_DBL:
  287.               {
  288.                 double value;
  289.                 
  290.                 sscanf (argv[argnum], "%lf", &value);
  291.                 [fa addDouble: value];
  292.               }
  293.               break;
  294.             default:
  295.               {
  296.                 fprintf (stderr, "Tcl can't handle arg type `%s' in `%s'",
  297.                          type, seltype);
  298.                 sprintf (resultString, "Tcl can't handle arg type %s", type);
  299.                 Tcl_SetResult (interp, resultString, TCL_VOLATILE);
  300.                 goto fail;
  301.               }
  302.             }
  303.         }
  304.       }
  305.     fc = [[[[FCall createBegin: getCZone (scratchZone)]
  306.              setArguments: [fa createEnd]]
  307.             setMethodFromSelector: sel inObject: target]
  308.            createEnd];
  309.     
  310.     [fc performCall];
  311.     
  312.     ret = [fc getResult];
  313.     type = objc_skip_type_qualifiers (seltype);
  314.     switch (*type)
  315.       {
  316.       case _C_ID:
  317.         {
  318.           id returnedObject;
  319.           char *s;
  320.           returnedObject = getObjectReturn (ret);
  321.           
  322.           s = tclObjc_objectToName (returnedObject);
  323.           strcpy (resultString, s);
  324.         }
  325.         break;
  326.       case _C_PTR:
  327.         sprintf (resultString, PTRHEXFMT, getPointerReturn (ret));
  328.         break;
  329.       case _C_INT:
  330.         sprintf (resultString, "%d", getIntegerReturn (ret));
  331.         break;
  332.       case _C_UINT:
  333.         sprintf (resultString, "%u", getUIntegerReturn (ret));
  334.         break;
  335.       case _C_SHT:
  336.         sprintf (resultString, "%d", (int) getShortReturn (ret));
  337.         break;
  338.       case _C_USHT:
  339.         sprintf (resultString, "%u", (unsigned) getUShortReturn (ret));
  340.         break;
  341.       case _C_LNG:
  342.         sprintf (resultString, "%ld", getLongReturn (ret));
  343.         break;
  344.       case _C_ULNG:
  345.         sprintf (resultString, "%lu", getULongReturn (ret));
  346.         break;
  347.       case _C_CHR:
  348.         sprintf (resultString, "%d", (int) getCharReturn (ret));
  349.         break;
  350.       case _C_UCHR:
  351.         sprintf (resultString, "%u", (unsigned) getUCharReturn (ret));
  352.         break;
  353.       case _C_CHARPTR:
  354.         strcpy (resultString, getStringReturn (ret));
  355.         break;
  356.       case _C_FLT:
  357.         sprintf (resultString, "%g", getFloatReturn (ret));
  358.         break;
  359.       case _C_DBL:
  360.         sprintf (resultString, "%g", getDoubleReturn (ret));
  361.         break;
  362.       case _C_VOID:
  363.         resultString[0] = '';
  364.         break;
  365.       default:
  366.         {
  367.           fprintf (stderr, "Tcl can't handle ret type `%s' in `%s'",
  368.                    type, seltype);
  369.           sprintf (resultString, "Tcl can't handle ret type %s", type);
  370.           Tcl_SetResult (interp, resultString, TCL_VOLATILE);
  371.           goto fail;
  372.         }
  373.       }
  374.     Tcl_SetResult (interp, resultString, TCL_VOLATILE);
  375.     if (tclObjc_eventHook)
  376.       (*tclObjc_eventHook) ();
  377.     [fc drop];
  378.     [fa drop];
  379.     return TCL_OK;
  380.   fail:
  381.     if (fc)
  382.       [fc drop];
  383.     [fa drop];
  384.     return TCL_ERROR;
  385.   }
  386. }
  387. void
  388. tclObjc_registerObjectWithName (Tcl_Interp *interp, 
  389.     id object, const char *name)
  390. {
  391.   Tcl_CreateCommand(interp, (char *) name, tclObjc_msgSendToClientData,
  392.     object, 0);
  393. }
  394. void
  395. tclObjc_unregisterObjectNamed (Tcl_Interp *interp,
  396.                                const char *name)
  397. {
  398.   Tcl_DeleteCommand(interp, (char *)name);
  399. }
  400. void
  401. tclObjc_registerClassnames (Tcl_Interp *interp)
  402. {
  403.   id class; 
  404.   void *es = NULL;
  405.   while ((class = objc_next_class(&es)))
  406.     tclObjc_registerObjectWithName(interp, class, [class name]);
  407. #if 0
  408.   node_ptr node = NULL;
  409.   /* register all class names with tcl */
  410.   while ((node = hash_next(__objc_class_hash, node)))
  411.     {
  412.       //      printf("registering %sn", (char *)node->key);
  413.       tclObjc_registerObjectWithName(interp, node->value, node->key);
  414.     }
  415. #endif
  416. }
  417. int
  418. tclObjc_msgSendToArgv1 (ClientData clientData,
  419.                         Tcl_Interp *interp,
  420.                         int argc,
  421.                         char *argv[])
  422. {
  423.   id obj;
  424.   if ((obj = tclObjc_nameToObject(argv[1])) != TCLOBJC_NO_OBJ)
  425.     return tclObjc_msgSendToClientData ((ClientData) obj,
  426.                                         interp, 
  427.                                         argc-1,
  428.                                         &(argv[1]));
  429.   else
  430.     {
  431.       sprintf(interp->result, 
  432.       "tclObjc: %s not recognized as an object", argv[1]);
  433.       return TCL_ERROR;
  434.     }
  435. }
  436. @implementation TclObject
  437. - (BOOL)respondsTo: (SEL)aSel
  438. {
  439.   Tcl_CmdInfo cmdInfo;
  440.   char selString[128];
  441.   sprintf(selString, "%s%s", _tclName, sel_get_name(aSel));
  442.   return (((object_is_instance (self)
  443.             ? class_get_instance_method(self->ISA, aSel)
  444.     : class_get_class_method(self->ISA, aSel)) != METHOD_NULL)
  445.   || Tcl_GetCommandInfo(_interp, selString, &cmdInfo));
  446. }
  447. + newName: (char *)objectName
  448. {
  449.   TclObject *newTclObject = class_create_instance (self);
  450.   newTclObject->_tclName =
  451.     (char*) objc_malloc ((unsigned) (strlen(objectName) + 1) * sizeof(char));
  452.   strcpy(newTclObject->_tclName, objectName);
  453.   /* Fix this ugliness!!! */
  454.   newTclObject->_interp = _TclObject_interp;
  455.   return newTclObject;
  456. }
  457. - free
  458. {
  459.   objc_free (_tclName);
  460.   return object_dispose (self);
  461. }  
  462. - forward: (SEL)aSel : (arglist_t)argframe
  463. {
  464.   return [self performv: aSel :argframe];
  465. }
  466. #define marg_getRef(margs, offset, type) ( (type *)offset )
  467. - performv:(SEL)aSel :(arglist_t)argframe
  468. {
  469.   char *datum;
  470.   const char *type;
  471.   char *objcdebug;
  472.   BOOL debug_printing;
  473.   Method_t method = 0;
  474.   char argString[256];
  475.   Tcl_DString command;
  476.   char *cmd;
  477.   int tmpint;
  478.   unsigned int tmpuint;
  479.   if (_interp == NULL)
  480.     {
  481.       fprintf(stderr, "interp not set yet, %sn", sel_get_name(aSel));
  482.       return self;
  483.     }
  484.   objcdebug = Tcl_GetVar(_interp, "objcdebug", TCL_GLOBAL_ONLY);
  485.   if (objcdebug) 
  486.     debug_printing = YES;
  487.   else 
  488.     debug_printing = NO;
  489.   Tcl_DStringInit(&command);
  490.   Tcl_DStringAppend(&command, _tclName, -1);
  491.   //  Tcl_DStringAppend(&command, " ", -1);
  492.   Tcl_DStringAppend(&command, (char *)sel_get_name(aSel), -1);
  493.   Tcl_DStringAppend(&command, " ", -1);
  494.   if (debug_printing)
  495.     printf("selector: %sn", sel_get_name(aSel));
  496.   /* search all classes for the method */
  497.   {
  498.     id class;
  499.     void *es = NULL;
  500.     while ((class = objc_next_class(&es))
  501.    && (!(method = class_get_instance_method(class, aSel)))
  502.    && (!(method = class_get_class_method(class, aSel))))
  503.       ;
  504.   }
  505. #if 0
  506.   {
  507.     node_ptr node = NULL;
  508.     while ((node = hash_next(__objc_class_hash, node))
  509.            && (!(method = class_get_instance_method(node->value, aSel)))
  510.            && (!(method = class_get_class_method(node->value, aSel))))
  511.       ;
  512.   }
  513. #endif
  514.   if (!method)
  515.     {
  516.       fprintf(stderr, "method not found, %sn", sel_get_name(aSel));
  517.       return self;
  518.     }
  519.   /* self */
  520.   datum = method_get_first_argument(method, argframe, &type);
  521.   /* SEL */
  522.   datum = method_get_next_argument(argframe, &type);
  523.   for (datum = method_get_next_argument(argframe, &type);
  524.        datum;
  525.        datum = method_get_next_argument(argframe, &type))
  526.     {
  527.       unsigned flags = objc_get_type_qualifiers(type);
  528.       type = objc_skip_type_qualifiers(type);
  529.       flags = flags;
  530.       switch (*type)
  531. {
  532. case _C_PTR:
  533.   sprintf(argString, PTRHEXFMT, 
  534.         *(void **) (marg_getRef(argframe, datum, void *)));
  535.   Tcl_DStringAppendElement(&command, argString);
  536.   break;
  537. case _C_ID:
  538.   strcpy(argString, tclObjc_objectToName(
  539.    *(id*)(marg_getRef(argframe, datum, id))));
  540.   Tcl_DStringAppendElement(&command, argString);
  541.   break;
  542. case _C_INT:
  543.   sprintf(argString, "%d", 
  544.    *(int*)(marg_getRef(argframe, datum, int)));
  545.   Tcl_DStringAppendElement(&command, argString);
  546.   break;
  547. case _C_UINT:
  548.   sprintf(argString, "%u", 
  549.    *(unsigned int*)(marg_getRef(argframe, datum, unsigned int)));
  550.   Tcl_DStringAppendElement(&command, argString);
  551.   break;
  552. case _C_SHT:
  553.   tmpint = 
  554.    *(short*)(marg_getRef(argframe, datum, short));
  555.   sprintf(argString, "%d", tmpint);
  556.   Tcl_DStringAppendElement(&command, argString);
  557.   break;
  558. case _C_USHT:
  559.   tmpuint = 
  560.    *(unsigned short*)(marg_getRef(argframe, datum, unsigned short));
  561.   sprintf(argString, "%u", tmpuint);
  562.   Tcl_DStringAppendElement(&command, argString);
  563.   break;
  564. case _C_CHR:
  565.   sprintf(argString, "%c", 
  566.    *(char*)(marg_getRef(argframe, datum, char)));
  567.   Tcl_DStringAppendElement(&command, argString);
  568.   break;
  569. case _C_UCHR:
  570.   tmpuint = 
  571.    *(unsigned char*)(marg_getRef(argframe, datum, unsigned char));
  572.   sprintf(argString, "%u", tmpuint);
  573.   Tcl_DStringAppendElement(&command, argString);
  574.   break;
  575. case _C_CHARPTR:
  576.   Tcl_DStringAppendElement(&command, 
  577.    *(char**)(marg_getRef(argframe, datum, char *)));
  578.   break;
  579. case _C_FLT:
  580.   sprintf(argString, "%f", 
  581.    *(float*)(marg_getRef(argframe, datum, float)));
  582.   Tcl_DStringAppendElement(&command, argString);
  583.   break;
  584. case  _C_DBL:
  585.   sprintf(argString, "%f", 
  586.    *(double*)(marg_getRef(argframe, datum, double)));
  587.   Tcl_DStringAppendElement(&command, argString);
  588.   break;
  589. default:
  590.   {
  591.     fprintf(stderr, "TclObject can't handle arg type %s", type);
  592.     return self;
  593.   }
  594. }
  595.     }
  596.   cmd = Tcl_DStringAppend(&command, "n", -1);
  597.   Tcl_GlobalEval(_interp, cmd);
  598.   // I should interpret returned string and return it!;
  599.   return self;
  600. }
  601. @end
  602. /*****************************************************************/
  603. static char tclObjcInitCmd[] =
  604. "if {[llength [info procs unknown]]} { n
  605.    rename unknown unknown_pre_tclObjc n
  606.  } n
  607.  proc unknown {name args} {n
  608.    if {[string match *%c0x* $name]} {n
  609.      return [uplevel tclObjc_msg_send $name $args]n
  610.    } else {n
  611.      if {[llength [info procs unknown_pre_tclObjc]]} {n
  612.        unknown_pre_tclObjc $name $argsn
  613.      } else {n
  614.        error "in unknown: invalid command name: $name"n
  615.      }n
  616.    }n
  617.  }n";
  618. int
  619. TclObjc_Init (Tcl_Interp *interp)
  620. {
  621.   /* Fix this ugliness!!! */
  622.   _TclObject_interp = interp;
  623.   tclObjc_registerClassnames(interp);
  624.   Tcl_CreateCommand(interp, "tclObjc_msg_send", 
  625.     tclObjc_msgSendToArgv1, 0, 0);
  626.   {
  627.     int code;
  628.     char buf [strlen (tclObjcInitCmd) + 1];
  629.     sprintf (buf, tclObjcInitCmd, ATDELIMCHAR);
  630.     code = Tcl_Eval(interp, buf);
  631.     if (code != TCL_OK)
  632.       {
  633.         fprintf(stderr, "tclObjc: Error during TclObjc_Init:n");
  634.         fprintf(stderr, interp->result);
  635.       }
  636.   }
  637.   return TCL_OK;
  638. }