/* constructor */ PyObject * sr_py_java_frame_new(PyTypeObject *object, PyObject *args, PyObject *kwds) { struct sr_py_java_frame *fo = (struct sr_py_java_frame*) PyObject_New(struct sr_py_java_frame, &sr_py_java_frame_type); if (!fo) return PyErr_NoMemory(); const char *str = NULL; if (!PyArg_ParseTuple(args, "|s", &str)) return NULL; if (str) { struct sr_location location; sr_location_init(&location); fo->frame = sr_java_frame_parse(&str, &location); if (!fo->frame) { PyErr_SetString(PyExc_ValueError, location.message); return NULL; } } else fo->frame = sr_java_frame_new(); return (PyObject*)fo; }
struct sr_java_frame * sr_java_frame_parse_exception(const char **input, struct sr_location *location) { /* java.lang.NullPointerException: foo */ const char *cursor = sr_skip_whitespace(*input); sr_location_add(location, 0, cursor - *input); const char *mark = cursor; sr_location_add(location, 0, sr_skip_char_cspan(&cursor, ": \t\n")); if (mark == cursor) { location->message = "Expected exception name"; return NULL; } struct sr_java_frame *exception = sr_java_frame_new_exception(); exception->name = sr_strndup(mark, cursor - mark); /* : foo */ if (*cursor == ':') { ++cursor; sr_location_add(location, 0, 1); mark = cursor; /* foo */ cursor = sr_skip_whitespace(mark); sr_location_add(location, 0, cursor - mark); mark = cursor; sr_location_add(location, 0, sr_skip_char_cspan(&cursor, "\n")); if (mark != cursor) exception->message = sr_strndup(mark, cursor - mark); } else { /* just to be sure, that we skip white space behind exception name */ sr_location_add(location, 0, sr_skip_char_cspan(&cursor, "\n")); } if (*cursor == '\n') { ++cursor; /* this adds one line */ sr_location_add(location, 2, 0); } /* else *cursor == '\0' */ mark = cursor; struct sr_java_frame *frame = NULL; /* iterate line by line best effort - continue on error */ while (*cursor != '\0') { cursor = sr_skip_whitespace(mark); sr_location_add(location, 0, cursor - mark); /* Each inner exception has '...' at its end */ if (strncmp("... ", cursor, strlen("... ")) == 0) goto current_exception_done; /* Suppressed exceptions follow after the end of current exception */ if (strncmp("Suppressed: ", cursor, strlen("Suppressed: ")) == 0) goto current_exception_done; /* The top most exception does not have '...' at its end */ if (strncmp("Caused by: ", cursor, strlen("Caused by: ")) == 0) goto parse_inner_exception; struct sr_java_frame *parsed = sr_java_frame_parse(&cursor, location); if (parsed == NULL) { sr_java_frame_free(exception); return NULL; } mark = cursor; if (exception->next == NULL) exception->next = parsed; else { assert(frame); frame->next = parsed; } frame = parsed; } /* We are done with the top most exception without inner exceptions */ /* because of no 'Caused by:' and no '...' */ goto exception_parsing_successful; current_exception_done: sr_skip_to_next_line_location(&cursor, &location->line, &location->column); mark = cursor; cursor = sr_skip_whitespace(mark); sr_location_add(location, 0, cursor - mark); if (strncmp("Suppressed: ", cursor, strlen("Suppressed: ")) == 0) { /* Skip all lines related to the suppressed exception. We can do * this by skipping all lines that begin with a whitespace - the * main exception chain always begins without preceding whitespace. */ sr_skip_to_next_line_location(&cursor, &location->line, &location->column); while (cursor && isspace(*cursor)) sr_skip_to_next_line_location(&cursor, &location->line, &location->column); } if (strncmp("Caused by: ", cursor, strlen("Caused by: ")) == 0) { parse_inner_exception: cursor += strlen("Caused by: "); sr_location_add(location, 0, strlen("Caused by: ")); struct sr_java_frame *inner = sr_java_frame_parse_exception(&cursor, location); if (inner == NULL) { sr_java_frame_free(exception); return NULL; } struct sr_java_frame *last_inner = sr_java_frame_get_last(inner); last_inner->next = exception; exception = inner; } exception_parsing_successful: *input = cursor; return exception; }