aboutsummaryrefslogtreecommitdiffstats
path: root/libpatch_guess_format.c
diff options
context:
space:
mode:
Diffstat (limited to 'libpatch_guess_format.c')
-rw-r--r--libpatch_guess_format.c121
1 files changed, 121 insertions, 0 deletions
diff --git a/libpatch_guess_format.c b/libpatch_guess_format.c
new file mode 100644
index 0000000..48ce419
--- /dev/null
+++ b/libpatch_guess_format.c
@@ -0,0 +1,121 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+
+
+static int
+is_unsigned(const char *text, size_t textlen, size_t *off)
+{
+ if (*off == textlen || !isdigit(text[*off]))
+ return 0;
+ while (isdigit(++*off));
+ return 1;
+}
+
+
+enum libpatch_style
+libpatch_guess_format(const char *text, size_t textlen, size_t *offset)
+{
+ enum libpatch_style guess = LIBPATCH_STYLE_GARBAGE;
+ size_t off = offset ? *offset : 0;
+ size_t two_nums;
+
+ while (off < textlen) {
+ if (text[off] == '+') {
+ if (textlen - off < 3 || strncmp(&text[off], "+++", 3))
+ goto skip_line;
+ goto unified;
+
+ } else if (text[off] == '*') {
+ if (textlen - off < 3 || strncmp(&text[off], "***", 3))
+ goto skip_line;
+ goto copied;
+
+ } else if (text[off] == '@') {
+ if (textlen - off < 3 || strncmp(&text[off], "@@ ", 3))
+ goto skip_line;
+ goto unified;
+
+ } else if (text[off] == 'a') {
+ off++;
+ if (!is_unsigned(text, textlen, &off))
+ goto skip_line;
+ if (off != textlen && text[off] == ' ')
+ off++;
+ if (is_unsigned(text, textlen, &off))
+ goto rcs;
+ else
+ goto ed_alternative;
+
+ } else if (text[off] == 'd') {
+ off++;
+ if (!is_unsigned(text, textlen, &off))
+ goto skip_line;
+ if (off != textlen && text[off] == ' ')
+ off++;
+ if (!is_unsigned(text, textlen, &off))
+ goto ed_alternative;
+ guess = LIBPATCH_STYLE_RCS;
+ /* could also be LIBPATCH_STYLE_ED_ALTERNATIVE,
+ * whould cannot be parsed so LIBPATCH_STYLE_RCS
+ * is preferred if the patch happens to be valid
+ * in both */
+ goto skip_line;
+
+ } else if (text[off] == 'c') {
+ off++;
+ if (!is_unsigned(text, textlen, &off))
+ goto skip_line;
+ goto ed_alternative;
+
+ } else if (isdigit(text[off])) {
+ if (!is_unsigned(text, textlen, &off))
+ goto skip_line;
+ two_nums = (off != textlen && text[off] == ',');
+ if (two_nums) {
+ off += 1;
+ if (!is_unsigned(text, textlen, &off))
+ goto skip_line;
+ }
+ switch (text[off]) {
+ case 'i':
+ goto ed;
+ case 'a':
+ if (two_nums)
+ goto normal;
+ /* fall through */
+ case 'c':
+ case 'd':
+ off++;
+ if (off == textlen || text[off] == '\n')
+ goto ed;
+ else if (isdigit(text[off]))
+ goto normal;
+ /* fall through */
+ default:
+ goto skip_line;
+ }
+
+ } else {
+ skip_line:
+ while (off != textlen && text[off] != '\n')
+ off++;
+ off += (off != textlen);
+ }
+ }
+
+ *offset = off;
+ return guess;
+
+determined:
+ while (off != textlen && text[off] != '\n')
+ off++;
+ *offset = off += (off != textlen);
+ return guess;
+
+normal: guess = LIBPATCH_STYLE_NORMAL; goto determined;
+copied: guess = LIBPATCH_STYLE_COPIED; goto determined;
+unified: guess = LIBPATCH_STYLE_UNIFIED; goto determined;
+ed: guess = LIBPATCH_STYLE_ED; goto determined;
+ed_alternative: guess = LIBPATCH_STYLE_ED_ALTERNATIVE; goto determined;
+rcs: guess = LIBPATCH_STYLE_RCS; goto determined;
+}