Commit 252f2eeee0ecc90e5ae21efeadaccc9da666b845

Patrick Steinhardt 2017-07-14T13:45:05

parse: implement and use `git_parse_advance_digit` The patch parsing code has multiple recurring patterns where we want to parse an actual number. Create a new function `git_parse_advance_digit` and use it to avoid code duplication.

diff --git a/src/parse.c b/src/parse.c
index f7365ef..57da1c3 100644
--- a/src/parse.c
+++ b/src/parse.c
@@ -79,3 +79,18 @@ int git_parse_advance_nl(git_parse_ctx *ctx)
 	git_parse_advance_line(ctx);
 	return 0;
 }
+
+int git_parse_advance_digit(int64_t *out, git_parse_ctx *ctx, int base)
+{
+	const char *end;
+	int ret;
+
+	if (ctx->line_len < 1 || !git__isdigit(ctx->line[0]))
+		return -1;
+
+	if ((ret = git__strntol64(out, ctx->line, ctx->line_len, &end, base)) < 0)
+		return -1;
+
+	git_parse_advance_chars(ctx, (end - ctx->line));
+	return 0;
+}
diff --git a/src/parse.h b/src/parse.h
index 56fbab5..8112eae 100644
--- a/src/parse.h
+++ b/src/parse.h
@@ -47,3 +47,4 @@ int git_parse_advance_expected(
 
 int git_parse_advance_ws(git_parse_ctx *ctx);
 int git_parse_advance_nl(git_parse_ctx *ctx);
+int git_parse_advance_digit(int64_t *out, git_parse_ctx *ctx, int base);
diff --git a/src/patch_parse.c b/src/patch_parse.c
index 0b3ad8f..735b889 100644
--- a/src/patch_parse.c
+++ b/src/patch_parse.c
@@ -102,24 +102,17 @@ static int parse_header_git_newpath(
 
 static int parse_header_mode(uint16_t *mode, git_patch_parse_ctx *ctx)
 {
-	const char *end;
-	int32_t m;
-	int ret;
+	int64_t m;
 
-	if (ctx->parse_ctx.line_len < 1 || !git__isdigit(ctx->parse_ctx.line[0]))
+	if ((git_parse_advance_digit(&m, &ctx->parse_ctx, 8)) < 0)
 		return git_parse_err("invalid file mode at line %"PRIuZ, ctx->parse_ctx.line_num);
 
-	if ((ret = git__strntol32(&m, ctx->parse_ctx.line, ctx->parse_ctx.line_len, &end, 8)) < 0)
-		return ret;
-
 	if (m > UINT16_MAX)
 		return -1;
 
 	*mode = (uint16_t)m;
 
-	git_parse_advance_chars(&ctx->parse_ctx, (end - ctx->parse_ctx.line));
-
-	return ret;
+	return 0;
 }
 
 static int parse_header_oid(
@@ -258,19 +251,15 @@ static int parse_header_copyto(
 
 static int parse_header_percent(uint16_t *out, git_patch_parse_ctx *ctx)
 {
-	int32_t val;
-	const char *end;
+	int64_t val;
 
-	if (ctx->parse_ctx.line_len < 1 || !git__isdigit(ctx->parse_ctx.line[0]) ||
-		git__strntol32(&val, ctx->parse_ctx.line, ctx->parse_ctx.line_len, &end, 10) < 0)
+	if (git_parse_advance_digit(&val, &ctx->parse_ctx, 10) < 0)
 		return -1;
 
-	git_parse_advance_chars(&ctx->parse_ctx, (end - ctx->parse_ctx.line));
-
 	if (git_parse_advance_expected_str(&ctx->parse_ctx, "%") < 0)
 		return -1;
 
-	if (val > 100)
+	if (val < 0 || val > 100)
 		return -1;
 
 	*out = val;
@@ -457,7 +446,7 @@ static int parse_int(int *out, git_patch_parse_ctx *ctx)
 {
 	git_off_t num;
 
-	if (parse_number(&num, ctx) < 0 || !git__is_int(num))
+	if (git_parse_advance_digit(&num, &ctx->parse_ctx, 10) < 0 || !git__is_int(num))
 		return -1;
 
 	*out = (int)num;
@@ -687,7 +676,8 @@ static int parse_patch_binary_side(
 		goto done;
 	}
 
-	if (parse_number(&len, ctx) < 0 || git_parse_advance_nl(&ctx->parse_ctx) < 0 || len < 0) {
+	if (git_parse_advance_digit(&len, &ctx->parse_ctx, 10) < 0 ||
+	    git_parse_advance_nl(&ctx->parse_ctx) < 0 || len < 0) {
 		error = git_parse_err("invalid binary size at line %"PRIuZ, ctx->parse_ctx.line_num);
 		goto done;
 	}