struct sr_java_frame * sr_java_frame_parse(const char **input, struct sr_location *location) { const char *mark = *input; int lines, columns; /* at SimpleTest.throwNullPointerException(SimpleTest.java:36) [file:/usr/lib/java/foo.class] */ const char *cursor = sr_strstr_location(mark, "at", &lines, &columns); if (!cursor) { location->message = "Frame expected"; return NULL; } /* SimpleTest.throwNullPointerException(SimpleTest.java:36) [file:/usr/lib/java/foo.class] */ cursor = mark = cursor + 2; sr_location_add(location, lines, columns + 2); /* SimpleTest.throwNullPointerException(SimpleTest.java:36) [file:/usr/lib/java/foo.class] */ cursor = sr_skip_whitespace(cursor); sr_location_add(location, 0, cursor - mark); mark = cursor; sr_location_add(location, 0, sr_skip_char_cspan(&cursor, "(\n")); struct sr_java_frame *frame = sr_java_frame_new(); if (cursor != mark) frame->name = sr_strndup(mark, cursor - mark); /* (SimpleTest.java:36) [file:/usr/lib/java/foo.class] */ if (*cursor == '(') { ++cursor; sr_location_add(location, 0, 1); mark = cursor; sr_location_add(location, 0, sr_skip_char_cspan(&cursor, ":)\n")); if (mark != cursor) { if (sr_java_frame_parse_is_native_method(mark)) frame->is_native = true; else if (!sr_java_frame_parse_is_unknown_source(mark)) { /* DO NOT set file_name if input says that source isn't known */ frame->file_name = sr_strndup(mark, cursor - mark); frame->file_name = anonymize_path(frame->file_name); } } if (*cursor == ':') { ++cursor; sr_location_add(location, 0, 1); mark = cursor; sr_parse_uint32(&cursor, &(frame->file_line)); sr_location_add(location, 0, cursor - mark); } } /* [file:/usr/lib/java/foo.class] */ mark = sr_java_frame_parse_frame_url(frame, cursor, location); cursor = strchrnul(mark, '\n'); if (*cursor == '\n') { *input = cursor + 1; sr_location_add(location, 2, 0); } else { *input = cursor; /* don't take \0 Byte into account */ sr_location_add(location, 0, (cursor - mark) - 1); } return frame; }
struct sr_ruby_frame * sr_ruby_frame_parse(const char **input, struct sr_location *location) { const char *local_input = *input; struct sr_ruby_frame *frame = sr_ruby_frame_new(); /* take everything before the backtick * /usr/share/rubygems/rubygems/core_ext/kernel_require.rb:55:in `require' * ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ */ char *filename_lineno_in = NULL; if (!sr_parse_char_cspan(&local_input, "`", &filename_lineno_in)) { location->message = sr_strdup("Unable to find the '`' character " "identifying the beginning of function name."); goto fail; } size_t l = strlen(filename_lineno_in); location->column += l; char *p = filename_lineno_in + l; /* /usr/share/rubygems/rubygems/core_ext/kernel_require.rb:55:in `require' * ^^^^ */ p -= strlen(":in "); if (p < filename_lineno_in || 0 != strcmp(":in ", p)) { location->column -= strlen(":in "); location->message = sr_strdup("Unable to find ':in ' preceding the " "backtick character."); goto fail; } /* Find the beginning of the line number. */ *p = '\0'; do { p--; } while (p >= filename_lineno_in && isdigit(*p)); p++; /* /usr/share/rubygems/rubygems/core_ext/kernel_require.rb:55:in `require' * ^^ */ char *p_copy = p; int lineno_len = sr_parse_uint32((const char **)&p_copy, &frame->file_line); if (lineno_len <= 0) { location->message = sr_strdup("Unable to find line number before ':in '"); goto fail; } /* /usr/share/rubygems/rubygems/core_ext/kernel_require.rb:55:in `require' * ^ */ p--; if (p < filename_lineno_in || *p != ':') { location->column -= lineno_len; location->message = sr_strdup("Unable to fin the ':' character " "preceding the line number"); goto fail; } /* Everything before the colon is the file name. */ *p = '\0'; frame->file_name = filename_lineno_in; filename_lineno_in = NULL; if(!sr_skip_char(&local_input, '`')) { location->message = sr_strdup("Unable to find the '`' character " "identifying the beginning of function name."); goto fail; } location->column++; /* The part in quotes can look like: * `rescue in rescue in block (3 levels) in func' * parse the number of rescues and blocks */ while (sr_skip_string(&local_input, "rescue in ")) { frame->rescue_level++; location->column += strlen("rescue in "); } if (sr_skip_string(&local_input, "block in ")) { frame->block_level = 1; location->column += strlen("block in"); } else if(sr_skip_string(&local_input, "block (")) { location->column += strlen("block ("); int len = sr_parse_uint32(&local_input, &frame->block_level); if (len == 0 || !sr_skip_string(&local_input, " levels) in ")) { location->message = sr_strdup("Unable to parse block depth."); goto fail; } location->column += len + strlen(" levels) in "); } if (sr_skip_char(&local_input, '<')) { location->column++; frame->special_function = true; } if (!sr_parse_char_cspan(&local_input, "'>", &frame->function_name)) { location->message = sr_strdup("Unable to find the \"'\" character " "delimiting the function name."); goto fail; } location->column += strlen(frame->function_name); if (frame->special_function) { if (!sr_skip_char(&local_input, '>')) { location->message = sr_strdup("Unable to find the \">\" character " "delimiting the function name."); goto fail; } location->column++; } if (!sr_skip_char(&local_input, '\'')) { location->message = sr_strdup("Unable to find the \"'\" character " "delimiting the function name."); goto fail; } location->column++; *input = local_input; return frame; fail: sr_ruby_frame_free(frame); free(filename_lineno_in); return NULL; }
struct sr_python_frame * sr_python_frame_parse(const char **input, struct sr_location *location) { const char *local_input = *input; if (0 == sr_skip_string(&local_input, " File \"")) { location->message = sr_asprintf("Frame header not found."); return NULL; } location->column += strlen(" File \""); struct sr_python_frame *frame = sr_python_frame_new(); /* Parse file name */ if (!sr_parse_char_cspan(&local_input, "\"", &frame->file_name)) { location->message = sr_asprintf("Unable to find the '\"' character " "identifying the beginning of file name."); goto fail; } if (strlen(frame->file_name) > 0 && frame->file_name[0] == '<' && frame->file_name[strlen(frame->file_name)-1] == '>') { frame->special_file = true; frame->file_name[strlen(frame->file_name)-1] = '\0'; char *inside = sr_strdup(frame->file_name + 1); free(frame->file_name); frame->file_name = inside; } frame->file_name = anonymize_path(frame->file_name); location->column += strlen(frame->file_name); if (0 == sr_skip_string(&local_input, "\", line ")) { location->message = sr_asprintf("Line separator not found."); goto fail; } location->column += strlen("\", line "); /* Parse line number */ int length = sr_parse_uint32(&local_input, &frame->file_line); if (0 == length) { location->message = sr_asprintf("Line number not found."); goto fail; } location->column += length; if (0 == sr_skip_string(&local_input, ", in ")) { if (local_input[0] != '\n') { location->message = sr_asprintf("Function name separator not found."); goto fail; } /* The last frame of SyntaxError stack trace does not have * function name on its line. For the sake of simplicity, we will * believe that we are dealing with such a frame now. */ frame->function_name = sr_strdup("syntax"); frame->special_function = true; } else { location->column += strlen(", in "); /* Parse function name */ if (!sr_parse_char_cspan(&local_input, "\n", &frame->function_name)) { location->message = sr_asprintf("Unable to find the newline character " "identifying the end of function name."); goto fail; } location->column += strlen(frame->function_name); if (strlen(frame->function_name) > 0 && frame->function_name[0] == '<' && frame->function_name[strlen(frame->function_name)-1] == '>') { frame->special_function = true; frame->function_name[strlen(frame->function_name)-1] = '\0'; char *inside = sr_strdup(frame->function_name + 1); free(frame->function_name); frame->function_name = inside; } } if (sr_skip_char(&local_input, '\n')) sr_location_add(location, 1, 0); /* Parse source code line (optional). */ if (4 == sr_skip_string(&local_input, " ")) { if (sr_parse_char_cspan(&local_input, "\n", &frame->line_contents) && sr_skip_char(&local_input, '\n')) sr_location_add(location, 1, 0); } *input = local_input; return frame; fail: sr_python_frame_free(frame); return NULL; }