/* 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; }