diff options
Diffstat (limited to 'libpatch_parse_rcs_patch.c')
-rw-r--r-- | libpatch_parse_rcs_patch.c | 76 |
1 files changed, 76 insertions, 0 deletions
diff --git a/libpatch_parse_rcs_patch.c b/libpatch_parse_rcs_patch.c new file mode 100644 index 0000000..04dc671 --- /dev/null +++ b/libpatch_parse_rcs_patch.c @@ -0,0 +1,76 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" + + +static size_t +hunk_head(const char *text, size_t len, size_t *first, size_t *count) +{ + size_t off = 1, r; + off += r = libpatch_get_zu__(&text[off], len - off, first); + if (!r) + return 0; + if (off < len && text[off] == ' ') { + off += 1; + off += r = libpatch_get_zu__(&text[off], len - off, count); + if (!r) + return 0; + } else { + *count = 1; + } + return off; +} + + +int +libpatch_parse_rcs_patch(const char *text, size_t textlen, size_t *textend, + struct libpatch_patch **patch, size_t *patchlen) +{ + const char *patchtext = text; + size_t len = 0, size = 0, line, count = 0; + int has_patch = 0; + + while ((len = libpatch_next_line__(&text, &textlen, len))) { + if (count) { + count -= 1; + APPEND_STRING(0, LIBPATCH_PATCH_FILE2_ONLY); + (*patch)[*patchlen - 1].file1_lineno = line; + + } else if (len >= 5 && !strncmp(text, "diff ", 5)) { + if (has_patch && textend) + break; + APPEND_STRING(5, LIBPATCH_PATCH_DIFF_LINE); + + } else if (len >= 2 && text[0] == 'd' && isdigit(text[1])) { + if (hunk_head(text, len, &line, &count) < len) + goto garbage; + APPEND_NO_TEXT(LIBPATCH_PATCH_HUNK_WITH_DELETION); + (*patch)[*patchlen - 1].first_line = line; + (*patch)[*patchlen - 1].line_count = count; + has_patch = 1; + + } else if (len >= 2 && text[0] == 'a' && isdigit(text[1])) { + if (hunk_head(text, len, &line, &count) < len) + goto garbage; + APPEND_NO_TEXT(LIBPATCH_PATCH_HUNK); + line += 1; + has_patch = 1; + + } else { + garbage: + APPEND_STRING(0, LIBPATCH_PATCH_GARBAGE); + if (len == textlen) + (*patch)[*patchlen - 1].lf_terminated = 0; + } + } + + if (textend) + *textend = (size_t)(text - patchtext); + + return 0; + +fail: + free(*patch); + *patch = NULL; + *patchlen = 0; + return -1; +} |