Index: Python/pythonrun.c =================================================================== --- Python/pythonrun.c (révision 70384) +++ Python/pythonrun.c (copie de travail) @@ -1212,15 +1212,18 @@ static int parse_syntax_error(PyObject *err, PyObject **message, const char **filename, - int *lineno, int *offset, const char **text) + int *lineno, int *offset, PyObject **text) { long hold; PyObject *v; /* old style errors */ - if (PyTuple_Check(err)) - return PyArg_ParseTuple(err, "O(ziiz)", message, filename, - lineno, offset, text); + if (PyTuple_Check(err)) { + if (!PyArg_ParseTuple(err, "O(ziiO)", message, filename, + lineno, offset, text)) + return 0; + return PyUnicode_Check(*text); + } /* new style errors. `err' is an instance */ @@ -1262,12 +1265,13 @@ if (!(v = PyObject_GetAttrString(err, "text"))) goto finally; - if (v == Py_None) + if (v == Py_None) { *text = NULL; - else if (!PyUnicode_Check(v) || - !(*text = _PyUnicode_AsString(v))) - goto finally; Py_DECREF(v); + } else if (!PyUnicode_Check(v)) + goto finally; + else + *text = v; return 1; finally: @@ -1281,33 +1285,129 @@ PyErr_PrintEx(1); } +static int +utf8_len(Py_UNICODE code) +{ + if (code < 0x80) + return 1; + if (code < 0x0800) + return 2; +#ifdef Py_UNICODE_WIDE + if (code < 0x10000) + return 3; + return 4; +#else + return 3; +#endif +} + +static int +utf8_to_unicode_offset(Py_UNICODE *text, Py_ssize_t textlen, int byte_offset) +{ + int character_offset = 0; + Py_ssize_t i; + for (i=0; i < textlen; i++, text++) { + byte_offset -= utf8_len(*text); + if (byte_offset <= 0) + break; + character_offset++; + } + return character_offset; +} + + +static int +adjust_offset(PyObject *unicode, Py_ssize_t len) +{ + wchar_t *buf; + int res; + + res = len; + + buf = PyMem_New(wchar_t, len); + if (!buf) { + PyErr_NoMemory(); + goto done; + } + if (PyUnicode_AsWideChar((PyUnicodeObject*)unicode, buf, len) == -1) + goto done; + +/* FIXME: if defined(HAVE_WCSWIDTH) */ +#if 1 + { + char *oldloc; + int r; + + oldloc = setlocale(LC_ALL, NULL); + setlocale(LC_ALL, ""); + r = wcswidth(buf, len); + setlocale(LC_ALL, oldloc); + if (r != -1) + res = r; + } +#elif defined(MS_WINDOWS) + { + int r; + + r = WideCharToMultiByte(CP_ACP, 0, buf, len, NULL, 0, NULL, NULL); + if (r != FALSE) res = r; + } +#else + /* FIXME */ +#endif +done: + if (buf) PyMem_FREE(buf); + return res; +} + static void -print_error_text(PyObject *f, int offset, const char *text) +print_error_text(PyObject *f, int offset, PyObject *textobj) { - char *nl; + Py_UNICODE *nl, *text = PyUnicode_AS_UNICODE(textobj); + Py_ssize_t textlen = PyUnicode_GET_SIZE(textobj); + PyObject *truncated; + + offset = utf8_to_unicode_offset(text, textlen, offset); + if (offset >= 0) { - if (offset > 0 && offset == (int)strlen(text)) + if (offset > 0 && offset == textlen) offset--; for (;;) { - nl = strchr(text, '\n'); + int diff; + nl = Py_UNICODE_strchr(text, '\n'); if (nl == NULL || nl-text >= offset) break; - offset -= (int)(nl+1-text); + diff = (int)(nl+1-text); + offset -= diff; + textlen -= diff; text = nl+1; } while (*text == ' ' || *text == '\t') { text++; + textlen--; offset--; } } + PyFile_WriteString(" ", f); - PyFile_WriteString(text, f); - if (*text == '\0' || text[strlen(text)-1] != '\n') + + truncated = PyUnicode_FromUnicode(text, textlen); + if (truncated) { + offset = adjust_offset(truncated, offset); + + PyFile_WriteObject(truncated, f, Py_PRINT_RAW); + Py_DECREF(truncated); + if (*text == '\0' || text[textlen-1] != '\n') PyFile_WriteString("\n", f); + } else { + PyErr_Clear(); + PyFile_WriteString("\n", f); + } + if (offset == -1) return; PyFile_WriteString(" ", f); - offset--; + while (offset > 0) { PyFile_WriteString(" ", f); offset--; @@ -1450,8 +1550,8 @@ if (err == 0 && PyObject_HasAttrString(value, "print_file_and_line")) { - PyObject *message; - const char *filename, *text; + PyObject *message, *text; + const char *filename; int lineno, offset; if (!parse_syntax_error(value, &message, &filename, &lineno, &offset, &text)) @@ -1467,8 +1567,10 @@ PyOS_snprintf(buf, sizeof(buf), "%d", lineno); PyFile_WriteString(buf, f); PyFile_WriteString("\n", f); - if (text != NULL) + if (text != NULL) { print_error_text(f, offset, text); + Py_DECREF(text); + } Py_DECREF(value); value = message; /* Can't be bothered to check all those