From patchwork Wed Mar 25 09:53:55 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Patrick Steinhardt X-Patchwork-Id: 11457347 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id B7C7614B4 for ; Wed, 25 Mar 2020 09:53:57 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 89E642077D for ; Wed, 25 Mar 2020 09:53:57 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=pks.im header.i=@pks.im header.b="i6ULELT3"; dkim=pass (2048-bit key) header.d=messagingengine.com header.i=@messagingengine.com header.b="mI+SUwu+" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727452AbgCYJx4 (ORCPT ); Wed, 25 Mar 2020 05:53:56 -0400 Received: from out5-smtp.messagingengine.com ([66.111.4.29]:56119 "EHLO out5-smtp.messagingengine.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727281AbgCYJx4 (ORCPT ); Wed, 25 Mar 2020 05:53:56 -0400 Received: from compute3.internal (compute3.nyi.internal [10.202.2.43]) by mailout.nyi.internal (Postfix) with ESMTP id 6A8445C0227; Wed, 25 Mar 2020 05:53:55 -0400 (EDT) Received: from mailfrontend1 ([10.202.2.162]) by compute3.internal (MEProxy); Wed, 25 Mar 2020 05:53:55 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=pks.im; h=date :from:to:cc:subject:message-id:references:mime-version :content-type:in-reply-to; s=fm3; bh=lh0q1o++tE+2Dc66P8nRvQgka41 0aAtpGllrXJFNIMY=; b=i6ULELT3dZALA5gJL4CMSTHtdFlf8Sl2VujZh7xRpyq imYsdbO/zWbs7YRF8hflXnCnHCTLBijQHFiYN05yZgoIWN94Auk2vnSNgkYBFHFJ X60bpidhUnOj2vKLbnfqpgKG651xC/c70IaGhrmKnhdb0Qaz5McB1BTTrVg4AraX EMuuoIlMsItilPOgupVShPrxhZkuarSylrmWF8lNSS/WnLmCw502Gz3AK7Pj0Frc gjDBQxLYLF5PkCSAW2g4EhddexneJ/GKW9GWH66DUa5VPf7GW9zpnH3u2scZOs50 gHo7X+Ce+kFHXgN10UocZUyqwGUZwe/R1xymnmV5s7g== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:content-type:date:from:in-reply-to :message-id:mime-version:references:subject:to:x-me-proxy :x-me-proxy:x-me-sender:x-me-sender:x-sasl-enc; s=fm2; bh=lh0q1o ++tE+2Dc66P8nRvQgka410aAtpGllrXJFNIMY=; b=mI+SUwu+6pcrffhk0cSKFf 90a7ApqL1A9t7LSu4UwHoBasuCPOl/8402CkrzqbwGQEwLY6DYdcjtnUMZzTjtrV x32SmHGXEJ3AvT0YHLEo5JPKCczZFBIG8+9A1WX8V0BP9FfyqMn7/KsQ0p2nQScL nFGS5X7f7+NoYR9GcCQ/LguLBqbtGKFQBTWnzytuaIxwpjicTh0L64I/DUQ70V1n 6MVSK7g8RNdYnbcUXJvxGsbQnyjLJVCeDZ/ZmDyiaKUkaSx1cd5NM+SIOZ7PNYNG L1V34ze5MisujyIEP+l/zRTMWOCNXZSCh7Z0ldpjI9J6WB9zZpNzV4uonfPv0P+A == X-ME-Sender: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgedugedrudehfedgtdekucetufdoteggodetrfdotf fvucfrrhhofhhilhgvmecuhfgrshhtofgrihhlpdfqfgfvpdfurfetoffkrfgpnffqhgen uceurghilhhouhhtmecufedttdenucesvcftvggtihhpihgvnhhtshculddquddttddmne cujfgurhepfffhvffukfhfgggtuggjsehgtderredttddvnecuhfhrohhmpefrrghtrhhi tghkucfuthgvihhnhhgrrhguthcuoehpshesphhkshdrihhmqeenucfkphepjeejrddufe drudekhedrjedvnecuvehluhhsthgvrhfuihiivgepfeenucfrrghrrghmpehmrghilhhf rhhomhepphhssehpkhhsrdhimh X-ME-Proxy: Received: from vm-mail.pks.im (x4d0db948.dyn.telefonica.de [77.13.185.72]) by mail.messagingengine.com (Postfix) with ESMTPA id D8EF0328005E; Wed, 25 Mar 2020 05:53:54 -0400 (EDT) Received: from localhost (ncase [10.192.0.11]) by vm-mail.pks.im (OpenSMTPD) with ESMTPSA id 93f558bc (TLSv1.3:TLS_AES_256_GCM_SHA384:256:NO); Wed, 25 Mar 2020 09:53:53 +0000 (UTC) Date: Wed, 25 Mar 2020 10:53:55 +0100 From: Patrick Steinhardt To: git Cc: Christian Couder Subject: [PATCH 4/9] update-ref: organize commands in an array Message-ID: <50ffc263293571f8af71fd1d253ac238c6909229.1585129842.git.ps@pks.im> References: MIME-Version: 1.0 Content-Disposition: inline In-Reply-To: Sender: git-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org We currently manually wire up all commands known to `git-update-ref --stdin`, making it harder than necessary to preprocess arguments after the command is determined. To make this more extensible, let's refactor the code to use an array of known commands instead. While this doesn't add a lot of value now, it is a preparatory step to implement line-wise reading of commands. As we're going to introduce commands without trailing spaces, this commit also moves whitespace parsing into the respective commands. Signed-off-by: Patrick Steinhardt --- builtin/update-ref.c | 66 ++++++++++++++++++++++++++++++++------------ 1 file changed, 49 insertions(+), 17 deletions(-) diff --git a/builtin/update-ref.c b/builtin/update-ref.c index 2d8f7f0578..d2b917a47c 100644 --- a/builtin/update-ref.c +++ b/builtin/update-ref.c @@ -171,11 +171,11 @@ static int parse_next_oid(struct strbuf *input, const char **next, /* * The following five parse_cmd_*() functions parse the corresponding * command. In each case, next points at the character following the - * command name and the following space. They each return a pointer - * to the character terminating the command, and die with an - * explanatory message if there are any parsing problems. All of - * these functions handle either text or binary format input, - * depending on how line_termination is set. + * command name. They each return a pointer to the character + * terminating the command, and die with an explanatory message if + * there are any parsing problems. All of these functions handle + * either text or binary format input, depending on how + * line_termination is set. */ static const char *parse_cmd_update(struct ref_transaction *transaction, @@ -186,6 +186,9 @@ static const char *parse_cmd_update(struct ref_transaction *transaction, struct object_id new_oid, old_oid; int have_old; + if (!skip_prefix(next, " ", &next)) + die("update: missing space after command"); + refname = parse_refname(input, &next); if (!refname) die("update: missing "); @@ -220,6 +223,9 @@ static const char *parse_cmd_create(struct ref_transaction *transaction, char *refname; struct object_id new_oid; + if (!skip_prefix(next, " ", &next)) + die("create: missing space after command"); + refname = parse_refname(input, &next); if (!refname) die("create: missing "); @@ -253,6 +259,9 @@ static const char *parse_cmd_delete(struct ref_transaction *transaction, struct object_id old_oid; int have_old; + if (!skip_prefix(next, " ", &next)) + die("delete: missing space after command"); + refname = parse_refname(input, &next); if (!refname) die("delete: missing "); @@ -288,6 +297,9 @@ static const char *parse_cmd_verify(struct ref_transaction *transaction, char *refname; struct object_id old_oid; + if (!skip_prefix(next, " ", &next)) + die("verify: missing space after command"); + refname = parse_refname(input, &next); if (!refname) die("verify: missing "); @@ -310,9 +322,12 @@ static const char *parse_cmd_verify(struct ref_transaction *transaction, return next; } -static const char *parse_cmd_option(struct strbuf *input, const char *next) +static const char *parse_cmd_option(struct ref_transaction *transaction, + struct strbuf *input, const char *next) { const char *rest; + if (!skip_prefix(next, " ", &next)) + die("option: missing space after command"); if (skip_prefix(next, "no-deref", &rest) && *rest == line_termination) update_flags |= REF_NO_DEREF; else @@ -320,33 +335,50 @@ static const char *parse_cmd_option(struct strbuf *input, const char *next) return rest; } +static const struct parse_cmd { + const char *prefix; + const char *(*fn)(struct ref_transaction *, struct strbuf *, const char *); +} commands[] = { + { "update", parse_cmd_update }, + { "create", parse_cmd_create }, + { "delete", parse_cmd_delete }, + { "verify", parse_cmd_verify }, + { "option", parse_cmd_option }, +}; + static void update_refs_stdin(struct ref_transaction *transaction) { struct strbuf input = STRBUF_INIT; const char *next; + int i; if (strbuf_read(&input, 0, 1000) < 0) die_errno("could not read from stdin"); next = input.buf; /* Read each line dispatch its command */ while (next < input.buf + input.len) { + const struct parse_cmd *cmd = NULL; + if (*next == line_termination) die("empty command in input"); else if (isspace(*next)) die("whitespace before command: %s", next); - else if (skip_prefix(next, "update ", &next)) - next = parse_cmd_update(transaction, &input, next); - else if (skip_prefix(next, "create ", &next)) - next = parse_cmd_create(transaction, &input, next); - else if (skip_prefix(next, "delete ", &next)) - next = parse_cmd_delete(transaction, &input, next); - else if (skip_prefix(next, "verify ", &next)) - next = parse_cmd_verify(transaction, &input, next); - else if (skip_prefix(next, "option ", &next)) - next = parse_cmd_option(&input, next); - else + + for (i = 0; i < ARRAY_SIZE(commands); i++) { + if (!skip_prefix(next, commands[i].prefix , &next)) + continue; + cmd = &commands[i]; + break; + } + if (!cmd) die("unknown command: %s", next); + if (input.buf[strlen(cmd->prefix)] != line_termination && + input.buf[strlen(cmd->prefix)] != '\0' && + input.buf[strlen(cmd->prefix)] != ' ') + die("%s: no separator after command", cmd->prefix); + + next = cmd->fn(transaction, &input, next); next++; }