home *** CD-ROM | disk | FTP | other *** search
/ Big Green CD 8 / BGCD_8_Dev.iso / NEXTSTEP / Languages / python / PyObjC-0.47-MIHS / pyobjc-0.47-src / Modules / objc_support.m < prev    next >
Encoding:
Text File  |  1996-11-14  |  26.2 KB  |  1,148 lines

  1. /* Copyright (c) 1996 by Lele Gaifax.  All Rights Reserved
  2.  *
  3.  * This software may be used and distributed freely for any purpose
  4.  * provided that this notice is included unchanged on any and all
  5.  * copies. The author does not warrant or guarantee this software in
  6.  * any way.
  7.  *
  8.  * This file is part of the PyObjC package.
  9.  *
  10.  * $RCSfile: objc_support.m,v $
  11.  * $Revision: 1.8 $
  12.  * $Date: 1996/11/15 02:33:46 $
  13.  *
  14.  * Created Tue Sep 10 14:16:02 1996.
  15.  */
  16.  
  17. #ifdef NeXT
  18. #include <bsd/libc.h>
  19. #endif
  20.  
  21. #include "ObjC.h"
  22. #include "objc_support.h"
  23. #include "myctype.h"
  24.  
  25. #ifndef GNU_RUNTIME
  26.  
  27. #ifndef MAX
  28. #define MAX(x,y) ({ unsigned int __x=(x), __y=(y); (__x > __y ? __x : __y); })
  29. #define MIN(x,y) ({ unsigned int __x=(x), __y=(y); (__x < __y ? __x : __y); })
  30. #endif
  31.  
  32. inline static const int
  33. ROUND(int v, int a)
  34. {
  35.   return a * ((v+a-1)/a);
  36. }
  37.  
  38. const char * 
  39. objc_skip_typespec (const char *type)
  40. {
  41.   type = objc_skip_type_qualifiers (type);
  42.  
  43.   switch (*type)
  44.     {
  45.       /* The following are one character type codes */
  46.     case _C_ID:
  47.  
  48.     case _C_CLASS:
  49.     case _C_SEL:
  50.     case _C_CHR:
  51.     case _C_UCHR:
  52.     case _C_CHARPTR:
  53.     case _C_SHT:
  54.     case _C_USHT:
  55.     case _C_INT:
  56.     case _C_UINT:
  57.     case _C_LNG:
  58.     case _C_ULNG:
  59.     case _C_FLT:
  60.     case _C_DBL:
  61.     case _C_VOID:
  62.       return ++type;
  63.       break;
  64.  
  65.     case _C_ARY_B:
  66.       /* skip digits, typespec and closing ']' */
  67.     
  68.       while (isdigit (*++type));
  69.       type = objc_skip_typespec (type);
  70.       //assert (*type == _C_ARY_E);
  71.       return ++type;
  72.       break;
  73.       
  74.     case _C_STRUCT_B:
  75.       /* skip name, and elements until closing '}'  */
  76.     
  77.       while (*type != _C_STRUCT_E && *type++ != '=');
  78.       while (*type != _C_STRUCT_E)
  79.     type = objc_skip_typespec (type);
  80.       return ++type;
  81.  
  82.     case _C_UNION_B:
  83.       /* skip name, and elements until closing ')'  */
  84.       type++;
  85.       while (*type != _C_UNION_E) { type = objc_skip_typespec (type); }
  86.       return ++type;
  87.       
  88.     case _C_PTR:
  89.       /* Just skip the following typespec */
  90.       return objc_skip_typespec (++type);
  91.     
  92.     default:
  93.       fprintf (stderr, "objc_skip_typespec: Unhandled type '%c'\n", *type);
  94.       abort();
  95.     }
  96. }
  97.  
  98. /*
  99.   Return the alignment of an object specified by type 
  100. */
  101.  
  102. static int
  103. objc_alignof_type (const char *type)
  104. {
  105.   switch (*type)
  106.     {
  107.     case _C_ID:
  108.       return __alignof__ (id);
  109.       break;
  110.  
  111.     case _C_CLASS:
  112.       return __alignof__ (Class);
  113.       break;
  114.     
  115.     case _C_SEL:
  116.       return __alignof__ (SEL);
  117.       break;
  118.  
  119.     case _C_CHR:
  120.       return __alignof__ (char);
  121.       break;
  122.     
  123.     case _C_UCHR:
  124.       return __alignof__ (unsigned char);
  125.       break;
  126.  
  127.     case _C_SHT:
  128.       return __alignof__ (short);
  129.       break;
  130.  
  131.     case _C_USHT:
  132.       return __alignof__ (unsigned short);
  133.       break;
  134.  
  135.     case _C_INT:
  136.       return __alignof__ (int);
  137.       break;
  138.  
  139.     case _C_UINT:
  140.       return __alignof__ (unsigned int);
  141.       break;
  142.  
  143.     case _C_LNG:
  144.       return __alignof__ (long);
  145.       break;
  146.  
  147.     case _C_ULNG:
  148.       return __alignof__ (unsigned long);
  149.       break;
  150.  
  151.     case _C_FLT:
  152.       return __alignof__ (float);
  153.       break;
  154.  
  155.     case _C_DBL:
  156.       return __alignof__ (double);
  157.       break;
  158.  
  159.     case _C_CHARPTR:
  160.       return __alignof__ (char *);
  161.       break;
  162.  
  163.     case _C_PTR:
  164.       return __alignof__ (void *);
  165.       break;
  166.       
  167.     case _C_ARY_B:
  168.       while (isdigit(*++type)) /* do nothing */;
  169.       return objc_alignof_type (type);
  170.       
  171.     case _C_STRUCT_B:
  172.       {
  173.     struct { int x; double y; } fooalign;
  174.     while(*type != _C_STRUCT_E && *type++ != '=') /* do nothing */;
  175.     if (*type != _C_STRUCT_E)
  176.       return MAX (objc_alignof_type (type), __alignof__ (fooalign));
  177.     else
  178.       return __alignof__ (fooalign);
  179.       }
  180.  
  181.     case _C_UNION_B:
  182.       {
  183.     int maxalign = 0;
  184.     type++;
  185.     while (*type != _C_UNION_E)
  186.       {
  187.         maxalign = MAX (maxalign, objc_alignof_type (type));
  188.         type = objc_skip_typespec (type);
  189.       }
  190.     return maxalign;
  191.       }
  192.     
  193.     default:
  194.       fprintf (stderr, "objc_align_type: Unhandled type '%c'\n", *type);
  195.       abort();
  196.     }
  197. }
  198.  
  199. /*
  200.   The aligned size if the size rounded up to the nearest alignment.
  201. */
  202.  
  203. static int
  204. objc_aligned_size (const char *type)
  205. {
  206.   static int objc_sizeof_type (const char *type);
  207.   
  208.   int size = objc_sizeof_type (type);
  209.   int align = objc_alignof_type (type);
  210.   return ROUND (size, align);
  211. }
  212.  
  213. /*
  214.   return the size of an object specified by type 
  215. */
  216.  
  217. int
  218. objc_sizeof_type (const char *type)
  219. {
  220.   switch (*type)
  221.     {
  222.     case _C_VOID:
  223.       return 0;
  224.       
  225.     case _C_ID:
  226.       return sizeof(id);
  227.       break;
  228.       
  229.     case _C_CLASS:
  230.       return sizeof(Class);
  231.       break;
  232.       
  233.     case _C_SEL:
  234.       return sizeof(SEL);
  235.       break;
  236.       
  237.     case _C_CHR:
  238.       return sizeof(char);
  239.       break;
  240.       
  241.     case _C_UCHR:
  242.       return sizeof(unsigned char);
  243.       break;
  244.       
  245.     case _C_SHT:
  246.       return sizeof(short);
  247.       break;
  248.       
  249.     case _C_USHT:
  250.       return sizeof(unsigned short);
  251.       break;
  252.       
  253.     case _C_INT:
  254.       return sizeof(int);
  255.       break;
  256.       
  257.     case _C_UINT:
  258.       return sizeof(unsigned int);
  259.       break;
  260.       
  261.     case _C_LNG:
  262.       return sizeof(long);
  263.       break;
  264.       
  265.     case _C_ULNG:
  266.       return sizeof(unsigned long);
  267.       break;
  268.       
  269.     case _C_FLT:
  270.       return sizeof(float);
  271.       break;
  272.       
  273.     case _C_DBL:
  274.       return sizeof(double);
  275.       break;
  276.       
  277.     case _C_PTR:
  278.     case _C_CHARPTR:
  279.       return sizeof(char*);
  280.       break;
  281.       
  282.     case _C_ARY_B:
  283.       {
  284.     int len = atoi(type+1);
  285.     while (isdigit(*++type));
  286.     return len*objc_aligned_size (type);
  287.       }
  288.     break; 
  289.     
  290.     case _C_STRUCT_B:
  291.       {
  292.     int acc_size = 0;
  293.     int align;
  294.     while (*type != _C_STRUCT_E && *type++ != '='); /* skip "<name>=" */
  295.     while (*type != _C_STRUCT_E)
  296.       {
  297.         align = objc_alignof_type (type);       /* padd to alignment */
  298.         acc_size = ROUND (acc_size, align);
  299.         acc_size += objc_sizeof_type (type);   /* add component size */
  300.         type = objc_skip_typespec (type);             /* skip component */
  301.       }
  302.     return acc_size;
  303.       }
  304.     
  305.     case _C_UNION_B:
  306.       {
  307.     int max_size = 0;
  308.     type++;
  309.     while (*type != _C_UNION_E)
  310.       {
  311.         max_size = MAX (max_size, objc_sizeof_type (type));
  312.         type = objc_skip_typespec (type);
  313.       }
  314.     return max_size;
  315.       }
  316.     
  317.     default:
  318.       fprintf (stderr, "objc_sizeof_type: Unhandled type '%c'\n", *type);
  319.       abort();
  320.     }
  321. }
  322.  
  323. #endif
  324.  
  325. /*#F Returns a tuple of objects representing the content of a C array
  326.   of type @var{type} pointed by @var{datum}. */
  327. static PyObject *
  328. pythonify_c_array (const char *type, void *datum, ObjCMethod *meth)
  329. {
  330.   PyObject *ret;
  331.   unsigned int nitems, offset, itemidx, sizeofitem;
  332.   
  333.   nitems = atoi (type+1);
  334.   while (isdigit (*++type));
  335.   sizeofitem = objc_sizeof_type (type);
  336.  
  337.   ret = PyTuple_New (nitems);
  338.   if (!ret)
  339.     return NULL;
  340.  
  341.   for (offset=itemidx=0; itemidx < nitems; itemidx++)
  342.     {
  343.       PyObject *pyitem = NULL;
  344.  
  345.       pyitem = pythonify_c_value (type, datum+offset, meth);
  346.  
  347.       if (pyitem)
  348.     PyTuple_SET_ITEM (ret, itemidx, pyitem);
  349.       else
  350.     {
  351.       Py_DECREF(ret);
  352.       return NULL;
  353.     }
  354.  
  355.       offset += sizeofitem;
  356.     }
  357.   
  358.   return ret;
  359. }
  360.  
  361. /*#F Returns a tuple of objects representing the content of a C structure
  362.   of type @var{type} pointed by @var{datum}. */
  363. static PyObject *
  364. pythonify_c_struct (const char *type, void *datum, ObjCMethod *meth)
  365. {
  366.   PyObject *ret;
  367.   unsigned int nitems, offset, itemidx;
  368.   const char *item;
  369.  
  370.   while (*type != _C_STRUCT_E && *type++ != '='); /* skip "<name>=" */
  371.   for (item=type, nitems=0; *item != _C_STRUCT_E; item = objc_skip_typespec (item))
  372.     nitems++;
  373.  
  374.   ret = PyTuple_New (nitems);
  375.   if (!ret)
  376.     return NULL;
  377.  
  378.   for (item=type, offset=itemidx=0; *item != _C_STRUCT_E; item = objc_skip_typespec (item))
  379.     {
  380.       PyObject *pyitem;
  381.  
  382.       pyitem = pythonify_c_value (item, datum+offset, meth);
  383.  
  384.       if (pyitem)
  385.     {
  386.       PyTuple_SET_ITEM (ret, itemidx, pyitem);
  387.     }
  388.       else
  389.     {
  390.       Py_DECREF(ret);
  391.       return NULL;
  392.     }
  393.  
  394.       itemidx++;
  395.       offset += objc_sizeof_type (item);
  396.     }
  397.   
  398.   return ret;
  399. }
  400.  
  401. /*#F Extracts the elements from the tuple @var{arg} and fills a C array
  402.   of type @var{type} pointed by @var{datum}. Returns an error message, or
  403.   NULL on success. */
  404. static const char *
  405. depythonify_c_array (const char *type, PyObject *arg, void *datum)
  406. {
  407.   unsigned int nitems, offset, itemidx, sizeofitem;
  408.  
  409.   nitems = atoi (type+1);
  410.   while (isdigit (*++type));
  411.   sizeofitem = objc_sizeof_type (type);
  412.  
  413.   if (nitems != PyTuple_Size (arg))
  414.     {
  415. #define ERRMSG "a tuple of %d items, got one of %d"
  416.       static char errmsg[sizeof ERRMSG + 4];
  417.  
  418.       sprintf (errmsg, ERRMSG, nitems, PyTuple_Size (arg));
  419.       return errmsg;
  420. #undef ERRMSG
  421.     }
  422.  
  423.   for (offset=itemidx=0; itemidx < nitems; itemidx++)
  424.     {
  425.       PyObject *pyarg = PyTuple_GetItem (arg, itemidx);
  426.       const char *error;
  427.  
  428.       error = depythonify_c_value (type, pyarg, datum+offset);
  429.       if (error)
  430.     return error;
  431.       
  432.       offset += sizeofitem;
  433.     }
  434.  
  435.   return NULL;
  436. }
  437.  
  438. /*#F Extracts the elements from the tuple @var{arg} and fills a C structure
  439.   of type @var{type} pointed by @var{datum}. Returns an error message, or
  440.   NULL on success. */
  441. static const char *
  442. depythonify_c_struct (const char *types, PyObject *arg, void *datum)
  443. {
  444.   unsigned int nitems, offset, itemidx;
  445.   const char *type;
  446.  
  447.   while (*types != _C_STRUCT_E && *types++ != '='); /* skip "<name>=" */
  448.   for (type=types, nitems=0; *type != _C_STRUCT_E; type = objc_skip_typespec (type))
  449.     nitems++;
  450.  
  451.   if (nitems != PyTuple_Size (arg))
  452.     {
  453. #define ERRMSG "a tuple of %d items, got one of %d"
  454.       static char errmsg[sizeof ERRMSG + 4];
  455.  
  456.       sprintf (errmsg, ERRMSG, nitems, PyTuple_Size (arg));
  457.       return errmsg;
  458. #undef ERRMSG
  459.     }
  460.  
  461.   for (type=types, offset=itemidx=0; *type != _C_STRUCT_E; type = objc_skip_typespec (type))
  462.     {
  463.       PyObject *argument = PyTuple_GetItem (arg, itemidx);
  464.       const char *error;
  465.  
  466.       error = depythonify_c_value (type, argument, datum+offset);
  467.       if (error)
  468.     return error;
  469.       
  470.       itemidx++;
  471.       offset += objc_sizeof_type (type);
  472.     }
  473.   return NULL;
  474. }
  475.  
  476. PyObject *
  477. pythonify_c_value (const char *type, void *datum, ObjCMethod *meth)
  478. {
  479.   PyObject *retobject = NULL;
  480.  
  481.   type = objc_skip_type_qualifiers (type);
  482.  
  483.   switch (*type)
  484.     {
  485.     case _C_CHR:
  486.     case _C_UCHR:
  487.       retobject = (PyObject *) PyInt_FromLong ((int) (*(char **) datum));
  488.       break;
  489.  
  490.     case _C_CHARPTR:
  491.       {
  492.     char *cp = *(char **) datum;
  493.  
  494.     if (! cp)
  495.       cp = "(null pointer)"; /* XXX */
  496.     retobject = (PyObject *) PyString_FromString (cp);
  497.     break;
  498.       }
  499.  
  500.     case _C_INT:
  501.     case _C_UINT:
  502.       retobject = (PyObject *) PyInt_FromLong (*(int *) datum);
  503.       break;
  504.  
  505.     case _C_SHT:
  506.     case _C_USHT:
  507.       retobject = (PyObject *) PyInt_FromLong (*(short *) datum);
  508.       break;
  509.  
  510.     case _C_LNG:
  511.     case _C_ULNG:
  512.       retobject = (PyObject *) PyInt_FromLong (*(long *) datum);
  513.       break;
  514.  
  515.     case _C_FLT:
  516.       retobject = (PyObject *) PyFloat_FromDouble (*(float *) datum);
  517.       break;
  518.  
  519.     case _C_DBL:
  520.       retobject = (PyObject *) PyFloat_FromDouble (*(double *) datum);
  521.       break;
  522.       
  523.     case _C_ID:
  524.       {
  525.     id obj = *(id *) datum;
  526.  
  527.     if (obj == nil)
  528.       {
  529.         /* XXX What should I do in this case? I used to treat it
  530.            as an error, but for example `-superclass' on Object
  531.            returns nil... */
  532.         // retobject = NULL;
  533.         retobject = Py_None;
  534.         Py_INCREF (retobject);
  535.       }
  536.     else if (meth && obj == meth->obj->oc_object)
  537.       {
  538.         retobject = (PyObject *) meth->obj;
  539.         Py_INCREF(retobject);
  540.       }
  541.     else
  542.       {
  543.         if ([obj isKindOf:[OC_PythonObject class]])
  544.           {
  545.         retobject = [obj object];
  546.         Py_INCREF(retobject);
  547.           }
  548.         else if ([obj isKindOf:[OC_Stream class]])
  549.           retobject = (PyObject *) ObjCStream_new ((OC_Stream *) obj);
  550.         else
  551.           retobject = (PyObject *) ObjCObject_new (obj);
  552.       }
  553.     break;
  554.       }
  555.  
  556.     case _C_SEL:
  557.       retobject = (PyObject *) ObjCMethod_new_with_selector (meth->obj,
  558.                                  *(SEL *) datum);
  559.       break;
  560.  
  561.     case _C_CLASS:
  562.       {
  563.     Class c = *(Class *) datum;
  564.  
  565.     if (c == Nil)
  566.       {
  567.         retobject = Py_None;
  568.         Py_INCREF (retobject);
  569.       }
  570.     else
  571.       retobject = (PyObject *) ObjCObject_new (c);
  572.     break;
  573.       }
  574.  
  575.     case _C_PTR:
  576. #ifndef WITH_FOUNDATION
  577. #define NXSTREAM_TYPE @encode (NXStream *)
  578. #define ALT_NXSTREAM_TYPE "^{?=I**iilii^{stream_functions}^v}"
  579.       if (!strncmp (type, NXSTREAM_TYPE, sizeof (NXSTREAM_TYPE)-1) ||
  580.       !strncmp (type, ALT_NXSTREAM_TYPE, sizeof (ALT_NXSTREAM_TYPE)-1))
  581.     retobject = (PyObject *) ObjCStream_new_from_stream (*(NXStream **) datum);
  582.       else
  583. #undef NXSTREAM_TYPE
  584. #undef ALT_NXSTREAM_TYPE
  585. #endif /* WITH_FOUNDATION */
  586.     retobject = (PyObject *) ObjCPointer_new (*(void **) datum, type+1);
  587.       break;
  588.       
  589.     case _C_UNION_B:
  590.       {
  591.     unsigned int size = objc_sizeof_type (type);
  592.     char *buffer = alloca (size);
  593.  
  594.     memcpy (buffer, (void *) datum, size);
  595.     retobject = PyString_FromStringAndSize (buffer, size);
  596.     break;
  597.       }
  598.     
  599.     case _C_STRUCT_B:
  600.       retobject = pythonify_c_struct (type, datum, meth);
  601.       break;
  602.  
  603.     case _C_ARY_B:
  604.       retobject = pythonify_c_array (type, datum, meth);
  605.       break;
  606.  
  607.     case _C_VOID:
  608.       retobject = Py_None;
  609.       Py_INCREF (retobject);
  610.       break;
  611.  
  612.     default:
  613.       {
  614. #ifdef GNU_RUNTIME
  615.     [NSException raise:NSInternalInconsistencyException 
  616.              format:@"unhandled value type (%c)", *type];
  617. #else
  618. #define ERRMSG "pythonify_c_value: unhandled value type (%c)"
  619.     char msg[sizeof ERRMSG];
  620.     sprintf (msg, ERRMSG, *type);
  621.     PyErr_SetString (ObjC_Error, msg);
  622. #undef ERRMSG
  623. #endif
  624.     break;
  625.       }
  626.     }
  627.  
  628.   return retobject;
  629. }
  630.  
  631. #ifdef WITH_THREAD
  632. #warning Does not support multiple threads yet.
  633. #endif
  634.  
  635. /* This is used as an array of pointers: both the memory for the array
  636.    and that for each array's slot is dinamically allocated with malloc().
  637.    We use it when we have to give an ObjC method a pointer to some datum:
  638.    since from the Python point of view we always work on values, not pointers,
  639.    when an ObjC does actually want a pointer, we allocate memory in the
  640.    next free slot (eventually growing the array), depythonify the argument
  641.    in that space and feed it to the method.
  642.    On the next method call this space will be freed. */
  643.  
  644. void **arguments_arena;
  645.  
  646. /* Count of used slots in arguments_arena. */
  647. static unsigned int arguments_arena_current_count;
  648.  
  649. /* Total number of slots in arguments_arena. */
  650. static unsigned int arguments_arena_slots;
  651.  
  652. static inline void
  653. xfree (void *ptr)
  654. {
  655.   if (ptr)
  656.     free (ptr);
  657. }
  658.  
  659. static inline void *
  660. xmalloc (unsigned int size)
  661. {
  662.   void *ptr = malloc (size);
  663.  
  664.   if (ptr == 0)
  665.     {
  666. #define ERRMSG "xmalloc: memory exausted"
  667.       write (fileno (stderr), ERRMSG, sizeof (ERRMSG)-1);
  668.       exit (1);
  669. #undef ERRMSG
  670.     }
  671.   return ptr;
  672. }
  673.  
  674. static inline void *
  675. xrealloc (void *ptr, unsigned int size)
  676. {
  677.   if (ptr == 0)
  678.     return xmalloc (size);
  679.   ptr = realloc (ptr, size);
  680.   if (ptr == 0)
  681.     {
  682. #define ERRMSG "xrealloc: memory exausted"
  683.       write (fileno (stderr), ERRMSG, sizeof (ERRMSG)-1);
  684.       exit (1);
  685. #undef ERRMSG
  686.     }
  687.   return ptr;
  688. }
  689.  
  690. /* If the arena is not empty, free it. Then initialize counters. */
  691. static inline void
  692. initialize_arguments_arena()
  693. {
  694.   if (arguments_arena)
  695.     {
  696.       while (arguments_arena_current_count--)
  697.     xfree (arguments_arena[arguments_arena_current_count]);
  698.  
  699.       xfree (arguments_arena);
  700.     }
  701.   arguments_arena_current_count = arguments_arena_slots = 0;
  702.   arguments_arena = NULL;
  703. }
  704.  
  705. /* Calculates the space needed to keep a value of type TYPE, then if
  706.    the arena isn't big enough reallocates a bigger array for it;
  707.    allocates the needed amount of memory for the value recording
  708.    its address in the next free slot and returns that pointer. */ 
  709. static void *
  710. get_space_on_arena_for_type (const char *type)
  711. {
  712.   unsigned int needed = objc_sizeof_type (type);
  713.   
  714.   if (arguments_arena_current_count == arguments_arena_slots)
  715.     {
  716.       if (arguments_arena_slots)
  717.     arguments_arena_slots *= 2;
  718.       else
  719.     arguments_arena_slots = 2;
  720.       arguments_arena = xrealloc (arguments_arena,
  721.                   arguments_arena_slots * sizeof (arguments_arena[0]));
  722.     }
  723.   return arguments_arena[arguments_arena_current_count++] = xmalloc (needed);
  724. }
  725.  
  726. const char *
  727. depythonify_c_value (const char *type, PyObject *argument, void *datum)
  728. {
  729.   const char *error = NULL;
  730.  
  731.   type = objc_skip_type_qualifiers (type);
  732.   
  733.   switch (*type)
  734.     {
  735.     case _C_CHR:
  736.       if (! PyString_Check (argument) &&
  737.       ! PyInt_Check (argument))
  738.     error = "a string or an integer";
  739.       else
  740.     if (PyInt_Check (argument))
  741.       *(char *) datum = PyInt_AsLong (argument);
  742.     else
  743.       *(char *) datum = PyString_AsString (argument)[0];
  744.       break;
  745.  
  746.     case _C_UCHR:
  747.       if (! PyString_Check (argument) &&
  748.       ! PyInt_Check (argument))
  749.     error = "a string or an integer";
  750.       else
  751.     if (PyInt_Check (argument))
  752.       *(unsigned char *) datum = PyInt_AsLong (argument);
  753.     else
  754.       *(unsigned char *) datum = PyString_AsString (argument)[0];
  755.       break;
  756.  
  757.     case _C_CHARPTR:
  758.       if (! PyString_Check (argument) && argument != Py_None)
  759.     error = "a string or None";
  760.       else
  761.     if (argument == Py_None)
  762.       *(char **) datum = NULL;
  763.     else
  764.       *(char **) datum = PyString_AsString (argument);
  765.       break;
  766.  
  767.     case _C_INT:
  768.       if (! PyInt_Check (argument))
  769.     error = "an integer";
  770.       else
  771.     *(int *) datum = PyInt_AsLong (argument);
  772.       break;
  773.  
  774.     case _C_SHT:
  775.       if (! PyInt_Check (argument))
  776.     error = "an integer";
  777.       else
  778.     *(short *) datum = PyInt_AsLong (argument);
  779.       break;
  780.  
  781.     case _C_UINT:
  782.       if (! PyInt_Check (argument))
  783.     error = "an integer";
  784.       else
  785.     *(unsigned int *) datum = PyInt_AsLong (argument);
  786.       break;
  787.  
  788.     case _C_USHT:
  789.       if (! PyInt_Check (argument))
  790.     error = "an integer";
  791.       else
  792.     *(unsigned short *) datum = PyInt_AsLong (argument);
  793.       break;
  794.  
  795.     case _C_LNG:
  796.       if (! PyInt_Check (argument))
  797.     error = "an integer";
  798.       else
  799.     *(long *) datum = PyInt_AsLong (argument);
  800.       break;
  801.  
  802.     case _C_ULNG:
  803.       if (! PyInt_Check (argument))
  804.     error = "an integer";
  805.       else
  806.     *(unsigned long *) datum = PyInt_AsLong (argument);
  807.       break;
  808.  
  809.     case _C_ID:
  810.       if (argument == Py_None)
  811.     *(id *) datum = nil;
  812.       else if (ObjCObject_Check (argument))
  813.     *(id *) datum = ((ObjCObject *) argument)->oc_object;
  814.       else if (ObjCStream_Check (argument))
  815.     *(id *) datum = ((ObjCStream *) argument)->stream;
  816.       else
  817.     *(id *) datum = [OC_PythonObject newWithObject:argument];
  818.       break;
  819.  
  820.     case _C_CLASS:
  821.       if (! (ObjCObject_Check (argument) &&
  822.          ISCLASS(((ObjCObject *) argument)->oc_object))
  823.       && argument != Py_None)
  824.     error = "a ObjC class or None";
  825.       else
  826.     *(Class *) datum = (argument == Py_None
  827.                 ? nil
  828.                 : ((ObjCObject *)(argument))->oc_object);
  829.       break;
  830.  
  831.     case _C_SEL:
  832.       if (! ObjCMethod_Check (argument) && ! PyString_Check (argument))
  833.     error = "a ObjC method or a string";
  834.       else
  835.     if (ObjCMethod_Check (argument))
  836.       *(SEL *) datum = ((ObjCMethod *) argument)->sel;
  837.     else
  838.       {
  839.         char *selname = PyString_AsString (argument);
  840.         SEL sel = SELUID (selname);
  841.  
  842.         /* XXX this is questionable */
  843.         if (sel)
  844.           *(SEL *) datum = sel;
  845.         else
  846.           *(char **) datum = selname;
  847.       }
  848.       break;
  849.  
  850.     case _C_PTR:
  851. #ifndef WITH_FOUNDATION
  852. #define NXSTREAM_TYPE @encode (NXStream *)
  853. #define ALT_NXSTREAM_TYPE "^{?=I**iilii^{stream_functions}^v}"
  854.       if ((!strncmp (type, NXSTREAM_TYPE, sizeof (NXSTREAM_TYPE)-1) ||
  855.        !strncmp (type, ALT_NXSTREAM_TYPE, sizeof (ALT_NXSTREAM_TYPE)-1)) &&
  856.       ObjCStream_Check (argument))
  857.     *(NXStream **) datum = ObjCStream_stream ((ObjCStream *) argument);
  858.       else
  859. #undef NXSTREAM_TYPE
  860. #undef ALT_NXSTREAM_TYPE
  861. #endif /* WITH_FOUNDATION */
  862.       if (PyString_Check (argument))
  863.     {
  864.       unsigned int expected_size = objc_sizeof_type (++type);
  865.       
  866.       if (expected_size != PyString_Size (argument))
  867.         {
  868. #define ERRMSG "a string of size %d instead of %d"
  869.           static char errmsg[sizeof (ERRMSG)+6+6];
  870.  
  871.           sprintf (errmsg, ERRMSG, expected_size, PyString_Size (argument));
  872.           error = errmsg;
  873. #undef ERRMSG
  874.         }
  875.       else
  876.         *(void **) datum = PyString_AS_STRING ((PyStringObject *) argument);
  877.     }
  878.       else if (ObjCPointer_Check (argument))
  879.     *(void **) datum = ((ObjCPointer *) argument)->ptr;
  880.       else           
  881.     {
  882.       *(void **) datum = get_space_on_arena_for_type (++type);
  883.       error = depythonify_c_value (type, argument, *(void **) datum);
  884.     }
  885.       break;
  886.  
  887.     case _C_FLT:
  888.       if (PyFloat_Check (argument))
  889.     *(float *) datum = (float) PyFloat_AsDouble (argument);
  890.       else if (PyInt_Check (argument))
  891.     *(float *) datum = (float) PyInt_AsLong (argument);
  892.       else
  893.     error = "a float or an integer";
  894.       break;
  895.  
  896.     case _C_DBL:
  897.       if (PyFloat_Check (argument))
  898.     *(double *) datum = PyFloat_AsDouble (argument);
  899.       else if (PyInt_Check (argument))
  900.     *(double *) datum = (double) PyInt_AsLong (argument);
  901.       else
  902.     error = "a float or an integer";
  903.       break;
  904.  
  905.     case _C_UNION_B:
  906.       if (PyString_Check (argument))
  907.     {
  908.       unsigned int expected_size = objc_sizeof_type (type);
  909.       
  910.       if (expected_size != PyString_Size (argument))
  911.         {
  912. #define ERRMSG "a string of size %d instead of %d"
  913.           static char errmsg[sizeof (ERRMSG)+6+6];
  914.  
  915.           sprintf (errmsg, ERRMSG, expected_size, PyString_Size (argument));
  916.           error = errmsg;
  917. #undef ERRMSG
  918.         }
  919.       else
  920.         memcpy ((void *) datum, PyString_AS_STRING ((PyStringObject *) argument), expected_size);
  921.     }
  922.       else
  923.     error = "a string";
  924.       break;
  925.  
  926.     case _C_STRUCT_B:
  927.       if (! PyTuple_Check (argument))
  928.     error = "a tuple";
  929.       else
  930.     error = depythonify_c_struct (type, argument, datum);
  931.       break;
  932.  
  933.     case _C_ARY_B:
  934.       if (! PyTuple_Check (argument))
  935.     error = "a tuple";
  936.       else
  937.     error = depythonify_c_array (type, argument, datum);
  938.       break;
  939.  
  940.     default:
  941.       {
  942. #define ERRMSG "unhandled typespec %c"
  943.     static char msg[sizeof ERRMSG];
  944.  
  945.     sprintf (msg, ERRMSG, *type);
  946.     error = msg;
  947.     break;
  948. #undef ERRMSG
  949.       }
  950.     }
  951.  
  952.   return error;
  953. }
  954.  
  955. PyObject *
  956. execute_and_pythonify_objc_method (ObjCMethod *meth, PyObject *args)
  957. {
  958.   PyObject *retobject = NULL;
  959.   METHOD methinfo;
  960.   unsigned int argcount;
  961.  
  962.   initialize_arguments_arena();
  963.   
  964.   if (ISCLASS(meth->obj->oc_object))
  965.     methinfo = CLASSMETH(meth->obj->oc_object, meth->sel);
  966.   else
  967.     methinfo = INSTMETH(meth->obj->oc_object, meth->sel);
  968.  
  969.   if (!methinfo)
  970.     {
  971. #define ERRORMSG " does not recognize "
  972.       const char *whoiam = NAMEOF(meth->obj->oc_object);
  973.       const char *selname = SELNAME(meth->sel);
  974.       char buffer[strlen (whoiam) + sizeof ERRORMSG + 1 + strlen (selname) + 1];
  975.       
  976.       strcpy (buffer, whoiam);
  977.       strcat (buffer, ERRORMSG);
  978.       strcat (buffer, (ISCLASS(meth->obj->oc_object) ? "+" : "-"));
  979.       strcat (buffer, selname);
  980.       PyErr_SetString (ObjC_Error, buffer);
  981. #undef ERRORMSG
  982.       return NULL;
  983.     }
  984.       
  985.   argcount = METHNARGS(methinfo);
  986.   if (PyTuple_Size (args) != argcount-2)
  987.     {
  988.       char error[100];
  989.  
  990.       sprintf (error, "wrong number of arguments, expected to be %d", argcount-2);
  991.       PyErr_SetString (ObjC_Error, error);
  992.       return NULL;
  993.     }
  994.   else
  995.     {
  996.  
  997. #ifdef GNU_RUNTIME
  998.   
  999.       void decoder (int argn, void *datum, const char *type)
  1000.     {
  1001.       if (argn == 0)
  1002.         *(id *)datum = meth->obj->oc_object;
  1003.       else if (argn == 1)
  1004.         *(SEL *)datum = meth->sel;
  1005.       else
  1006.         {
  1007.           PyObject *argument;
  1008.           const char *error = NULL;
  1009.           
  1010.           argument = PyTuple_GET_ITEM (args, argn-2);
  1011.           error = depythonify_c_value (type, argument, datum);
  1012.           if (error)
  1013.         [NSException raise:NSInvalidArgumentException
  1014.                  format:@"expected %s for argument %d", error, argn-2];
  1015.         }
  1016.     }
  1017.  
  1018.       void encoder (int argn, void *datum, const char *type, int flags)
  1019.     {
  1020.       if (argn == -1)    // return value
  1021.         retobject = pythonify_c_value (type, datum, meth);
  1022.  
  1023.       // XXX What if argn >= 0? 
  1024.     }
  1025.  
  1026.       NS_DURING
  1027.     
  1028.     mframe_do_call (methinfo->method_types, decoder, encoder);
  1029.       
  1030.       NS_HANDLER
  1031.     
  1032.     PyErr_SetString (ObjC_Error, (char *) [[localException reason] cString]);
  1033.       
  1034.       NS_ENDHANDLER
  1035.       
  1036. #else /* NeXT' runtime */
  1037.     
  1038.       unsigned int argsize;
  1039.       char *argbuffer;
  1040.       const char *type;
  1041.       int offset, i;
  1042.       const char *error = NULL;
  1043.       id receiver;
  1044.       
  1045.       argsize = METHSARGS(methinfo);
  1046.       argbuffer = alloca (argsize);
  1047.  
  1048.       receiver = meth->obj->oc_object;
  1049.  
  1050.       method_getArgumentInfo (methinfo, 0, &type, &offset);
  1051.       marg_setValue (argbuffer, offset, id, receiver);
  1052.  
  1053.       method_getArgumentInfo (methinfo, 1, &type, &offset);
  1054.       marg_setValue (argbuffer, offset, SEL, meth->sel);
  1055.   
  1056.       for (i = 2; i < argcount; i++)
  1057.     {
  1058.       PyObject *argument;
  1059.  
  1060.       method_getArgumentInfo (methinfo, i, &type, &offset);
  1061.  
  1062.       argument = PyTuple_GET_ITEM (args, i-2);
  1063.  
  1064.       error = depythonify_c_value (type, argument, argbuffer+offset);
  1065.         
  1066.       if (error)
  1067.         break;
  1068.     }
  1069.  
  1070.       if (error)
  1071.     {
  1072.       const char *typeend = objc_skip_typespec (type);
  1073. #define ERRMSG "expected %s for argument %d: its type is `%.*s'"
  1074.       char errmsg[sizeof ERRMSG + strlen (error) + typeend-type];
  1075.  
  1076.       sprintf (errmsg, ERRMSG, error, i-2, (int) (typeend-type), type);
  1077.       PyErr_SetString (ObjC_Error, errmsg);
  1078. #undef ERRMSG
  1079.       return NULL;
  1080.     }
  1081.  
  1082.       PyErr_Clear();
  1083.       type = objc_skip_type_qualifiers (methinfo->method_types);
  1084.       switch (*type)
  1085.     {
  1086.     case _C_DBL:
  1087.       {
  1088.         double ddatum = ((double (*)()) objc_msgSendv) (receiver, meth->sel, argsize, argbuffer);
  1089.  
  1090.         if (!PyErr_Occurred())
  1091.           retobject = pythonify_c_value (methinfo->method_types, &ddatum, meth);
  1092.         break;
  1093.       }
  1094.  
  1095.     case _C_FLT:
  1096.       {
  1097.         float fdatum = ((float (*)()) objc_msgSendv) (receiver, meth->sel, argsize, argbuffer);
  1098.  
  1099.         if (!PyErr_Occurred())
  1100.           retobject = pythonify_c_value (methinfo->method_types, &fdatum, meth);
  1101.         break;
  1102.       }
  1103.  
  1104.     default:
  1105.       {
  1106.         unsigned int ret_size = objc_sizeof_type (type);
  1107.         
  1108.         if (ret_size <= sizeof (void *))
  1109.           {
  1110.         void *datum = objc_msgSendv (receiver, meth->sel, argsize, argbuffer);
  1111.         
  1112.         if (!PyErr_Occurred())
  1113.           retobject = pythonify_c_value (methinfo->method_types, &datum, meth);
  1114.           }
  1115.         else
  1116.           {
  1117. #if 0
  1118. /* this generates a
  1119.      ``cc: Internal compiler error: program cc1obj got fatal signal 6''*/
  1120.  
  1121.         struct dummy
  1122.           {
  1123.             void *p;
  1124.             typeof (char [ret_size - sizeof (void *)]) items;
  1125.           } ldatum;
  1126.  
  1127.         ldatum = ((typeof (ldatum) (*)()) objc_msgSendv) (receiver, meth->sel, argsize, argbuffer);
  1128.  
  1129.         if (!PyErr_Occurred())
  1130.           retobject = pythonify_c_value (methinfo->method_types, ldatum, meth);
  1131. #else          
  1132.           PyErr_SetString (ObjC_Error, "Not able to handle big structures");
  1133. #endif
  1134.           }
  1135.         break;
  1136.       }
  1137.     }
  1138. #endif
  1139.     }
  1140.   return retobject;
  1141. }
  1142.  
  1143. /*
  1144. ** Local Variables:
  1145. ** change-log-default-name:"../ChangeLog.PyObjC"
  1146. ** End:
  1147. */
  1148.