diff options
author | Mattias Andrée <maandree@kth.se> | 2024-01-09 22:04:24 +0100 |
---|---|---|
committer | Mattias Andrée <maandree@kth.se> | 2024-01-09 22:04:24 +0100 |
commit | ae850b1ac755f471beac4dbfef4654fe3fbaaae9 (patch) | |
tree | 319e7f7f1b99cd1ee75e100f0a29b0f7c827ccea /libpatch_parse_ed_patch.c | |
download | libpatch-ae850b1ac755f471beac4dbfef4654fe3fbaaae9.tar.gz libpatch-ae850b1ac755f471beac4dbfef4654fe3fbaaae9.tar.bz2 libpatch-ae850b1ac755f471beac4dbfef4654fe3fbaaae9.tar.xz |
First commit
Signed-off-by: Mattias Andrée <maandree@kth.se>
Diffstat (limited to 'libpatch_parse_ed_patch.c')
-rw-r--r-- | libpatch_parse_ed_patch.c | 149 |
1 files changed, 149 insertions, 0 deletions
diff --git a/libpatch_parse_ed_patch.c b/libpatch_parse_ed_patch.c new file mode 100644 index 0000000..f3dec51 --- /dev/null +++ b/libpatch_parse_ed_patch.c @@ -0,0 +1,149 @@ +/* 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 *last) +{ + 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, last); + if (!r) + return 0; + } else { + *last = *first; + } + return off; +} + + +int +libpatch_parse_ed_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, off, line, last, count; + int in_hunk = 0, can_continue = 0, has_patch = 0; + size_t *hunks = NULL, *new; + size_t nhunks = 0, hunks_size = 0; + struct libpatch_patch *patchcopy = NULL; + size_t patchcopysize = 0; + + *patch = NULL; + *patchlen = 0; + + while ((len = libpatch_next_line__(&text, &textlen, len))) { + if (can_continue) { + can_continue = 0; + if (len == 1 && text[0] == 'a') { + in_hunk = 1; + } else if (len == 1 && text[0] == 'i') { + goto garbage; /* TODO */ + } else if (len >= 5 && !strncmp(text, "s/", 2) && text[len - 1] == '/') { + if (*patchlen < 2 || !IS_LINE((*patch)[*patchlen - 2].type)) + goto garbage; + /* TODO add support for more weird alternatives */ + if (!(len == 5 && !strncmp(text, "s/.//", len)) && + !(len == 6 && !strncmp(text, "s/^.//", len)) && + !(len == 6 && !strncmp(text, "s/\\.//", len)) && + !(len == 7 && !strncmp(text, "s/^\\.//", len))) + goto garbage; + (*patch)[*patchlen - 2].text_offset += 1; + (*patch)[*patchlen - 2].text_length -= 1; + APPEND_STRING(len, LIBPATCH_PATCH_SYNTACTICAL); + } else { + goto else_if; + } + APPEND_STRING(len, LIBPATCH_PATCH_SYNTACTICAL); + + } else else_if: if (in_hunk && len == 1 && text[0] == '.') { + APPEND_STRING(len, LIBPATCH_PATCH_SYNTACTICAL); + in_hunk = 0; + can_continue = 1; + + } else if (in_hunk) { + 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; + if (libpatch_reverse_hunks__(*patch, *patchlen, hunks, nhunks, &patchcopy, &patchcopysize)) + goto fail; + nhunks = 0; + APPEND_STRING(5, LIBPATCH_PATCH_DIFF_LINE); + + } else if (len >= 2 && isdigit(text[0])) { + off = hunk_head(text, len, &line, &last); + if (len - off != 1) + goto garbage; + if (!line && last) + goto garbage; + else if (!line) + count = 0, line = 1; + else if (last < line) + goto garbage; + else + count = last - line + 1; + + if (text[off] == 'd') { + APPEND_NO_TEXT(LIBPATCH_PATCH_HUNK_WITH_DELETION); + (*patch)[*patchlen - 1].first_line = line; + (*patch)[*patchlen - 1].line_count = count; + } else if (text[off] == 'a') { + APPEND_NO_TEXT(LIBPATCH_PATCH_HUNK); + in_hunk = 1; + } else if (text[off] == 'c') { + APPEND_NO_TEXT(LIBPATCH_PATCH_HUNK_WITH_DELETION); + (*patch)[*patchlen - 1].first_line = line; + (*patch)[*patchlen - 1].line_count = count; + in_hunk = 1; + } else if (text[off] == 'i') { + goto garbage; /* TODO */ + } else { + goto garbage; + } + + if (nhunks == hunks_size) { + if (hunks_size > SIZE_MAX / sizeof(*hunks) - 16) + goto enomem; + new = realloc(hunks, (hunks_size += 16) * sizeof(*hunks)); + if (!new) + goto fail; + hunks = new; + } + hunks[nhunks++] = *patchlen - 1; + has_patch = 1; + + } else { + garbage: + APPEND_STRING(0, LIBPATCH_PATCH_GARBAGE); + if (len == textlen) + (*patch)[*patchlen - 1].lf_terminated = 0; + } + } + + if (libpatch_reverse_hunks__(*patch, *patchlen, hunks, nhunks, &patchcopy, &patchcopysize)) + goto fail; + + if (textend) + *textend = (size_t)(text - patchtext); + + free(patchcopy); + free(hunks); + return 0; + +enomem: + errno = ENOMEM; +fail: + free(patchcopy); + free(hunks); + free(*patch); + *patch = NULL; + *patchlen = 0; + return -1; +} |