cpburnz

C goto example for error clean up.

Feb 12th, 2013
132
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 4.98 KB | None | 0 0
  1. /**
  2. Converts a Python value to a PHP value.
  3.  
  4. *pyobj* (``PyObject *``) is the python value.
  5.  
  6. .. NOTE:: If this is a ``PyUnicodeObject``, the resulting PHP value will
  7.    contain a UTF-8 encoded string.
  8.  
  9. *pymemo* (``PyObject *``) is a memo dictionary of objects already copied. This
  10. is used internally by this method so it should be set to ``NULL``.
  11.  
  12. Returns the new PHP value (``zval *``).
  13.  
  14. .. NOTE:: If the return value is ``NULL``, a Python exception has been raised.
  15. */
  16. static zval * PyObject_to_zval(PyObject * pyobj, PyObject * pymemo) {
  17.     // Other python object type checks...
  18.     else if (PyDict_Check(pyobj)) {
  19.         bool pymemo_is_tmp = false;
  20.         Py_ssize_t pylen = 0;
  21.         Py_ssize_t pypos = 0;
  22.         Py_ssize_t keylen = 0;
  23.         const char * key = NULL; // borrowed
  24.         zval * zdict = NULL; // owned
  25.         zval * zv = NULL; // owned
  26.         PyObject * pyptr = NULL; // borrowed
  27.         PyObject * pykey = NULL; // borrowed
  28.         PyObject * pyval = NULL; // borrowed
  29.         PyObject * pyptr_tmp = NULL; // owned
  30.         PyObject * pykey_tmp = NULL; // owned
  31.         PyObject * pyval_tmp = NULL; // owned
  32.    
  33.         // Make sure the dict is small enough.
  34.         pylen = PyDict_Size(pyobj);
  35.         if (pylen < 0 || INT_MAX < pylen) {
  36.             PyErr_Format(PyExc_ValueError, "Python object:%s length:%" PY_Z "i must be between 0 and %i inclusive.", Py_TYPE(pyobj)->tp_name, pylen, INT_MAX);
  37.             return NULL;
  38.         }
  39.    
  40.         // Initialize PHP array.
  41.         MAKE_STD_ZVAL(zdict);
  42.         if (zdict == NULL) {
  43.             PyErr_Format(InternalErrorType, "Failed to create zval.");
  44.             return NULL;
  45.         }
  46.         if (array_init(zdict) != SUCCESS) {
  47.             PyErr_Format(InternalErrorType, "Failed to initialize zval array.");
  48.             goto dict_error;
  49.         }
  50.        
  51.         // Create memo dict if we don't have one.
  52.         if (pymemo == NULL) {
  53.             pymemo = PyDict_New();
  54.             if (pymemo == NULL) {
  55.                 goto dict_error;
  56.             }
  57.             pymemo_is_tmp = true;
  58.         }
  59.        
  60.         // Iterate over python dict, convert python key-value pairs into PHP key
  61.         // value pairs and append them to the PHP array.
  62.         while (PyDict_Next(pyobj, &pypos, &pykey, &pyval)) {
  63.        
  64.             // Get python key string.
  65.             if (pykey == Py_None || pykey == Py_False) {
  66.                 // In PHP both `null` and `false` become empty strings when casted.
  67.                 key = "";
  68.                 keylen = 0;
  69.             } else {
  70.                 if (PyString_Check(pykey)) {
  71.                     key = PyString_AS_STRING(pykey);
  72.                     keylen = PyString_GET_SIZE(pykey);
  73.                 } else {
  74.                     if (PyUnicode_Check(pykey)) {
  75.                         pykey_tmp = PyUnicode_AsUTF8String(pykey);
  76.                     } else {
  77.                         pykey_tmp = PyObject_Str(pykey);
  78.                     }
  79.                     if (pykey_tmp == NULL) {
  80.                         goto dict_error; // Clean up.
  81.                     }
  82.                     key = PyString_AS_STRING(pykey_tmp);
  83.                     keylen = PyString_GET_SIZE(pykey_tmp);
  84.                 }
  85.                 if (keylen < 0 || INT_MAX < keylen) {
  86.                     PyErr_Format(InternalErrorType, "Python key:%s length:%" PY_Z "i must be between 0 and %i inclusive.", Py_TYPE(pykey)->tp_name, keylen, INT_MAX);
  87.                     goto dict_error; // Clean up.
  88.                 }
  89.             }
  90.            
  91.             // Convert python value to php value.
  92.             // - The memo dict maps python value pointer to php value pointer.
  93.             pyval_tmp = PyLong_FromVoidPtr(pyval);
  94.             if (pyval_tmp == NULL) {
  95.                 goto dict_error; // Clean up.
  96.             }
  97.             pyptr = PyDict_GetItem(pymemo, pyval_tmp);
  98.             if (pyptr != NULL) {
  99.                 // Get mapped php value pointer from python value pointer.
  100.                 zv = PyLong_AsVoidPtr(pyptr);
  101.                 if (zv == NULL) {
  102.                     goto dict_error; // Clean up.
  103.                 }
  104.             } else {
  105.                 zv = PyObject_to_zval(pyval, pymemo);
  106.                 if (zv == NULL) {
  107.                     goto dict_error; // Clean up.
  108.                 }
  109.                 // Map python value pointer to php value pointer to support recursion.
  110.                 pyptr_tmp = PyLong_FromVoidPtr(zv);
  111.                 if (pyptr_tmp == NULL) {
  112.                     goto dict_error; // Clean up.
  113.                 }
  114.                 if (PyDict_SetItem(pymemo, pyval_tmp, pyptr_tmp) != 0) {
  115.                     goto dict_error; // Clean up.
  116.                 }
  117.             }
  118.            
  119.             // Set new php value in array.
  120.             // - NOTE: Hash key length MUST include NULL byte.
  121.             if (zend_symtable_update(Z_ARRVAL_P(zdict), key, (unsigned int)keylen + 1, &zv, sizeof(zv), NULL) != SUCCESS) {
  122.                 PyErr_Format(InternalErrorType, "Failed to set key in php array.");
  123.                 goto dict_error;
  124.             }
  125.             zv = NULL; // PHP dict steals reference to php value.
  126.            
  127.             // Destroy temporary python values.
  128.             Py_CLEAR(pyptr_tmp);
  129.             Py_CLEAR(pyval_tmp);
  130.             Py_CLEAR(pykey_tmp);
  131.         }
  132.        
  133.         // Clean up remaining python temporary values.
  134.         if (pymemo_is_tmp) {
  135.             Py_DECREF(pymemo);
  136.         }
  137.        
  138.         // Return new PHP array.
  139.         return zdict;
  140.        
  141.         // Failed to convert python dict to php array.
  142.         dict_error: {
  143.             // Clean up temporary python values.
  144.             Py_XDECREF(pyptr_tmp);
  145.             Py_XDECREF(pyval_tmp);
  146.             Py_XDECREF(pykey_tmp);
  147.             if (pymemo_is_tmp) {
  148.                 Py_DECREF(pymemo);
  149.             }
  150.             // Destory orphaned php value.
  151.             if (zv != NULL) {
  152.                 zval_del(&zv);
  153.             }
  154.             // Destory php array.
  155.             zval_del(&zdict);
  156.         }
  157.         return NULL;
  158.        
  159.     }
  160.  
  161.     // Other python object type checks...
  162.    
  163.     // Python object not supported.
  164.     PyErr_Format(PyExc_TypeError, "Python type:%s cannot be converted to a PHP value.", Py_TYPE(pyobj)->tp_name);
  165.     return NULL;
  166. }
Advertisement
Add Comment
Please, Sign In to add comment