static PyObject * stdprinter_write(PyStdPrinter_Object *self, PyObject *args) { PyObject *unicode; PyObject *bytes = NULL; const char *str; Py_ssize_t n; int err; if (self->fd < 0) { /* fd might be invalid on Windows * I can't raise an exception here. It may lead to an * unlimited recursion in the case stderr is invalid. */ Py_RETURN_NONE; } if (!PyArg_ParseTuple(args, "U", &unicode)) return NULL; /* encode Unicode to UTF-8 */ str = PyUnicode_AsUTF8AndSize(unicode, &n); if (str == NULL) { PyErr_Clear(); bytes = _PyUnicode_AsUTF8String(unicode, "backslashreplace"); if (bytes == NULL) return NULL; str = PyBytes_AS_STRING(bytes); n = PyBytes_GET_SIZE(bytes); } n = _Py_write(self->fd, str, n); /* save errno, it can be modified indirectly by Py_XDECREF() */ err = errno; Py_XDECREF(bytes); if (n == -1) { if (err == EAGAIN) { PyErr_Clear(); Py_RETURN_NONE; } return NULL; } return PyLong_FromSsize_t(n); }
/* Encode a (wide) character string to the locale encoding with the surrogateescape error handler (characters in range U+DC80..U+DCFF are converted to bytes 0x80..0xFF). This function is the reverse of _Py_char2wchar(). Return a pointer to a newly allocated byte string (use PyMem_Free() to free the memory), or NULL on encoding or memory allocation error. If error_pos is not NULL: *error_pos is the index of the invalid character on encoding error, or (size_t)-1 otherwise. */ char* _Py_wchar2char(const wchar_t *text, size_t *error_pos) { #ifdef __APPLE__ Py_ssize_t len; PyObject *unicode, *bytes = NULL; char *cpath; unicode = PyUnicode_FromWideChar(text, wcslen(text)); if (unicode == NULL) return NULL; bytes = _PyUnicode_AsUTF8String(unicode, "surrogateescape"); Py_DECREF(unicode); if (bytes == NULL) { PyErr_Clear(); if (error_pos != NULL) *error_pos = (size_t)-1; return NULL; } len = PyBytes_GET_SIZE(bytes); cpath = PyMem_Malloc(len+1); if (cpath == NULL) { PyErr_Clear(); Py_DECREF(bytes); if (error_pos != NULL) *error_pos = (size_t)-1; return NULL; } memcpy(cpath, PyBytes_AsString(bytes), len + 1); Py_DECREF(bytes); return cpath; #else /* __APPLE__ */ const size_t len = wcslen(text); char *result = NULL, *bytes = NULL; size_t i, size, converted; wchar_t c, buf[2]; #ifndef MS_WINDOWS if (force_ascii == -1) force_ascii = check_force_ascii(); if (force_ascii) return encode_ascii_surrogateescape(text, error_pos); #endif /* The function works in two steps: 1. compute the length of the output buffer in bytes (size) 2. outputs the bytes */ size = 0; buf[1] = 0; while (1) { for (i=0; i < len; i++) { c = text[i]; if (c >= 0xdc80 && c <= 0xdcff) { /* UTF-8b surrogate */ if (bytes != NULL) { *bytes++ = c - 0xdc00; size--; } else size++; continue; } else { buf[0] = c; if (bytes != NULL) converted = wcstombs(bytes, buf, size); else converted = wcstombs(NULL, buf, 0); if (converted == (size_t)-1) { if (result != NULL) PyMem_Free(result); if (error_pos != NULL) *error_pos = i; return NULL; } if (bytes != NULL) { bytes += converted; size -= converted; } else size += converted; } } if (result != NULL) { *bytes = '\0'; break; } size += 1; /* nul byte at the end */ result = PyMem_Malloc(size); if (result == NULL) { if (error_pos != NULL) *error_pos = (size_t)-1; return NULL; } bytes = result; } return result; #endif /* __APPLE__ */ }