From nobody Thu May 15 02:31:36 2025 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of redhat.com designates 209.132.183.28 as permitted sender) client-ip=209.132.183.28; envelope-from=libvir-list-bounces@redhat.com; helo=mx1.redhat.com; Authentication-Results: mx.zohomail.com; spf=pass (zoho.com: domain of redhat.com designates 209.132.183.28 as permitted sender) smtp.mailfrom=libvir-list-bounces@redhat.com Return-Path: Received: from mx1.redhat.com (mx1.redhat.com [209.132.183.28]) by mx.zohomail.com with SMTPS id 1514913157820963.4237469328752; Tue, 2 Jan 2018 09:12:37 -0800 (PST) Received: from smtp.corp.redhat.com (int-mx05.intmail.prod.int.phx2.redhat.com [10.5.11.15]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 7068D7EA97; Tue, 2 Jan 2018 17:12:36 +0000 (UTC) Received: from colo-mx.corp.redhat.com (colo-mx01.intmail.prod.int.phx2.redhat.com [10.5.11.20]) by smtp.corp.redhat.com (Postfix) with ESMTPS id 358A05EE0C; Tue, 2 Jan 2018 17:12:36 +0000 (UTC) Received: from lists01.pubmisc.prod.ext.phx2.redhat.com (lists01.pubmisc.prod.ext.phx2.redhat.com [10.5.19.33]) by colo-mx.corp.redhat.com (Postfix) with ESMTP id EA61E180474E; Tue, 2 Jan 2018 17:12:35 +0000 (UTC) Received: from smtp.corp.redhat.com (int-mx06.intmail.prod.int.phx2.redhat.com [10.5.11.16]) by lists01.pubmisc.prod.ext.phx2.redhat.com (8.13.8/8.13.8) with ESMTP id w02HCXuw003118 for ; Tue, 2 Jan 2018 12:12:33 -0500 Received: by smtp.corp.redhat.com (Postfix) id D4DDD171BE; Tue, 2 Jan 2018 17:12:33 +0000 (UTC) Received: from localhost.localdomain (ovpn-204-45.brq.redhat.com [10.40.204.45]) by smtp.corp.redhat.com (Postfix) with ESMTP id 448765C890 for ; Tue, 2 Jan 2018 17:12:32 +0000 (UTC) From: Michal Privoznik To: libvir-list@redhat.com Date: Tue, 2 Jan 2018 18:12:00 +0100 Message-Id: In-Reply-To: References: In-Reply-To: References: X-Scanned-By: MIMEDefang 2.79 on 10.5.11.16 X-loop: libvir-list@redhat.com Subject: [libvirt] [PATCH 07/18] vshReadlineParse: Use string list X-BeenThere: libvir-list@redhat.com X-Mailman-Version: 2.1.12 Precedence: junk List-Id: Development discussions about the libvirt library & tools List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Sender: libvir-list-bounces@redhat.com Errors-To: libvir-list-bounces@redhat.com X-Scanned-By: MIMEDefang 2.79 on 10.5.11.15 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.28]); Tue, 02 Jan 2018 17:12:37 +0000 (UTC) X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Type: text/plain; charset="utf-8" It's better to fetch list of either commands or options just once and then iterate over it. Moreover, it makes future completers way simpler as they will return string lists too. Signed-off-by: Michal Privoznik --- tools/vsh.c | 121 ++++++++++++++++++++++++++++++++++++--------------------= ---- 1 file changed, 73 insertions(+), 48 deletions(-) diff --git a/tools/vsh.c b/tools/vsh.c index bcabf4231..ebc8d9cb1 100644 --- a/tools/vsh.c +++ b/tools/vsh.c @@ -2605,25 +2605,25 @@ vshTreePrint(vshControl *ctl, vshTreeLookup lookup,= void *opaque, * ----------------- */ =20 -/* - * Generator function for command completion. STATE lets us - * know whether to start from scratch; without any state - * (i.e. STATE =3D=3D 0), then we start at the top of the list. +/** + * vshReadlineCommandGenerator: + * @text: optional command prefix + * + * Generator function for command completion. + * + * Returns a string list of commands with @text prefix, + * NULL if there's no such command. */ -static char * -vshReadlineCommandGenerator(const char *text, int state) +static char ** +vshReadlineCommandGenerator(const char *text) { - static unsigned int grp_list_index, cmd_list_index; - static size_t len; + size_t grp_list_index =3D 0, cmd_list_index =3D 0; + size_t len =3D strlen(text); const char *name; const vshCmdGrp *grp; const vshCmdDef *cmds; - - if (!state) { - grp_list_index =3D 0; - cmd_list_index =3D 0; - len =3D strlen(text); - } + size_t ret_size =3D 0; + char **ret =3D NULL; =20 grp =3D cmdGroups; =20 @@ -2638,8 +2638,16 @@ vshReadlineCommandGenerator(const char *text, int st= ate) if (cmds[cmd_list_index++].flags & VSH_CMD_FLAG_ALIAS) continue; =20 - if (STREQLEN(name, text, len)) - return vshStrdup(NULL, name); + if (STREQLEN(name, text, len)) { + if (VIR_REALLOC_N(ret, ret_size + 2) < 0) { + virStringListFree(ret); + return NULL; + } + ret[ret_size] =3D vshStrdup(NULL, name); + ret_size++; + /* Terminate the string list properly. */ + ret[ret_size] =3D NULL; + } } } else { cmd_list_index =3D 0; @@ -2647,23 +2655,17 @@ vshReadlineCommandGenerator(const char *text, int s= tate) } } =20 - /* If no names matched, then return NULL. */ - return NULL; + return ret; } =20 -static char * -vshReadlineOptionsGenerator(const char *text, int state, const vshCmdDef *= cmd_parsed) +static char ** +vshReadlineOptionsGenerator(const char *text, const vshCmdDef *cmd) { - static unsigned int list_index; - static size_t len; - static const vshCmdDef *cmd; + size_t list_index =3D 0; + size_t len =3D strlen(text); const char *name; - - if (!state) { - cmd =3D cmd_parsed; - list_index =3D 0; - len =3D strlen(text); - } + size_t ret_size =3D 0; + char **ret =3D NULL; =20 if (!cmd) return NULL; @@ -2672,7 +2674,7 @@ vshReadlineOptionsGenerator(const char *text, int sta= te, const vshCmdDef *cmd_pa return NULL; =20 while ((name =3D cmd->opts[list_index].name)) { - char *res; + size_t name_len; =20 list_index++; =20 @@ -2685,28 +2687,40 @@ vshReadlineOptionsGenerator(const char *text, int s= tate, const vshCmdDef *cmd_pa } else if (STRNEQLEN(text, "--", len)) { return NULL; } - res =3D vshMalloc(NULL, strlen(name) + 3); - snprintf(res, strlen(name) + 3, "--%s", name); - return res; + + if (VIR_REALLOC_N(ret, ret_size + 2) < 0) { + virStringListFree(ret); + return NULL; + } + + name_len =3D strlen(name); + ret[ret_size] =3D vshMalloc(NULL, name_len + 3); + snprintf(ret[ret_size], name_len + 3, "--%s", name); + ret_size++; + /* Terminate the string list properly. */ + ret[ret_size] =3D NULL; } =20 - /* If no names matched, then return NULL. */ - return NULL; + return ret; } =20 static char * vshReadlineParse(const char *text, int state) { static vshCmd *partial; - static const vshCmdDef *cmd; - char *res =3D NULL; + static char **list; + static size_t list_index; + const vshCmdDef *cmd =3D NULL; + char *ret =3D NULL; =20 if (!state) { char *buf =3D vshStrdup(NULL, rl_line_buffer); =20 vshCommandFree(partial); partial =3D NULL; - cmd =3D NULL; + virStringListFree(list); + list =3D NULL; + list_index =3D 0; =20 *(buf + rl_point) =3D '\0'; =20 @@ -2729,26 +2743,37 @@ vshReadlineParse(const char *text, int state) } } =20 - if (!cmd) { - res =3D vshReadlineCommandGenerator(text, state); - } else { - res =3D vshReadlineOptionsGenerator(text, state, cmd); + if (!list) { + if (!cmd) { + list =3D vshReadlineCommandGenerator(text); + } else { + list =3D vshReadlineOptionsGenerator(text, cmd); + } } =20 - if (res && + if (list) { + ret =3D vshStrdup(NULL, list[list_index]); + list_index++; + } + + if (ret && !rl_completion_quote_character) { virBuffer buf =3D VIR_BUFFER_INITIALIZER; - virBufferEscapeShell(&buf, res); - VIR_FREE(res); - res =3D virBufferContentAndReset(&buf); + virBufferEscapeShell(&buf, ret); + VIR_FREE(ret); + ret =3D virBufferContentAndReset(&buf); } =20 - if (!res) { + if (!ret) { vshCommandFree(partial); partial =3D NULL; + virStringListFree(list); + list =3D NULL; + list_index =3D 0; } =20 - return res; + return ret; + } =20 static char ** --=20 2.13.6 -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list