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