From patchwork Wed Nov 3 23:23:28 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Marek_Beh=C3=BAn?= X-Patchwork-Id: 1550633 X-Patchwork-Delegate: sjg@chromium.org Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: bilbo.ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=kernel.org header.i=@kernel.org header.a=rsa-sha256 header.s=k20201202 header.b=c6u7lCJU; dkim-atps=neutral Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=lists.denx.de (client-ip=2a01:238:438b:c500:173d:9f52:ddab:ee01; helo=phobos.denx.de; envelope-from=u-boot-bounces@lists.denx.de; receiver=) Received: from phobos.denx.de (phobos.denx.de [IPv6:2a01:238:438b:c500:173d:9f52:ddab:ee01]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits)) (No client certificate requested) by bilbo.ozlabs.org (Postfix) with ESMTPS id 4Hl2tH0Tkxz9sRN for ; Thu, 4 Nov 2021 10:24:55 +1100 (AEDT) Received: from h2850616.stratoserver.net (localhost [IPv6:::1]) by phobos.denx.de (Postfix) with ESMTP id 8AFF983673; Thu, 4 Nov 2021 00:24:14 +0100 (CET) Authentication-Results: phobos.denx.de; dmarc=pass (p=none dis=none) header.from=kernel.org Authentication-Results: phobos.denx.de; spf=pass smtp.mailfrom=u-boot-bounces@lists.denx.de Authentication-Results: phobos.denx.de; dkim=pass (2048-bit key; unprotected) header.d=kernel.org header.i=@kernel.org header.b="c6u7lCJU"; dkim-atps=neutral Received: by phobos.denx.de (Postfix, from userid 109) id 4F67B83649; Thu, 4 Nov 2021 00:23:55 +0100 (CET) X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on phobos.denx.de X-Spam-Level: X-Spam-Status: No, score=-2.8 required=5.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,SPF_HELO_NONE, SPF_PASS autolearn=ham autolearn_force=no version=3.4.2 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by phobos.denx.de (Postfix) with ESMTPS id ACB0F83632 for ; Thu, 4 Nov 2021 00:23:47 +0100 (CET) Authentication-Results: phobos.denx.de; dmarc=pass (p=none dis=none) header.from=kernel.org Authentication-Results: phobos.denx.de; spf=pass smtp.mailfrom=kabel@kernel.org Received: by mail.kernel.org (Postfix) with ESMTPSA id 64F93611C6; Wed, 3 Nov 2021 23:23:45 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1635981826; bh=n9EcZECDczBOER/CWEX2r9bq1iWrmit7jmterRQM7kI=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=c6u7lCJUKQ3g97N/sMZ/ojdSg45ANHTIkaHsUguEg+drsDNnX3jn/IsQynPHffq+o gU6uAhlYAcDMrJVHY1hmub2zDG/KpstjJICNap5xFXQ/Atnm17mWo37DelBEqn+gpG gZZKOPGnc/ZUXhnm8uwb4yRh88e0F26ft8yAhO/BgPbxQEEyrCcKt/WnD2yI/PpXUp nuJXGTLj0t+GCaD6PElNyWhS82kgUdiWRHHCiHhT8OrcE8492F2LbeTSKSuvon3PTW htUq4laG+N5b7Q4jROBDr00/e8XdZDwZuJRAonc61kPzsBMfYWIbgo4veBJK8B1Z3y BpcNKdgDvtYJw== From: =?utf-8?q?Marek_Beh=C3=BAn?= To: Simon Glass , =?utf-8?q?Pali_Roh=C3=A1r?= Cc: u-boot@lists.denx.de, =?utf-8?q?Marek_Beh=C3=BAn?= Subject: [PATCH v2 08/12] sysinfo: Add support for iterating string list Date: Thu, 4 Nov 2021 00:23:28 +0100 Message-Id: <20211103232332.2737-9-kabel@kernel.org> X-Mailer: git-send-email 2.32.0 In-Reply-To: <20211103232332.2737-1-kabel@kernel.org> References: <20211103232332.2737-1-kabel@kernel.org> MIME-Version: 1.0 X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.34 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: u-boot-bounces@lists.denx.de Sender: "U-Boot" X-Virus-Scanned: clamav-milter 0.103.2 at phobos.denx.de X-Virus-Status: Clean From: Marek BehĂșn Add function sysinfo_get_str_list_max_len() to determine length of the longest string in a string list, functions sysinfo_str_list_first() and sysinfo_str_list_next() to support iteration over string list elements and macro for_each_sysinfo_str_list() to make the iteration simple to use. Signed-off-by: Marek BehĂșn --- drivers/sysinfo/sysinfo-uclass.c | 79 +++++++++++++++++++++++++ include/sysinfo.h | 99 ++++++++++++++++++++++++++++++++ test/dm/sysinfo.c | 35 +++++++++++ 3 files changed, 213 insertions(+) diff --git a/drivers/sysinfo/sysinfo-uclass.c b/drivers/sysinfo/sysinfo-uclass.c index d945f073c5..78035a95aa 100644 --- a/drivers/sysinfo/sysinfo-uclass.c +++ b/drivers/sysinfo/sysinfo-uclass.c @@ -8,6 +8,7 @@ #include #include +#include #include struct sysinfo_priv { @@ -104,6 +105,84 @@ int sysinfo_get_str_list(struct udevice *dev, int id, unsigned idx, size_t size, return ops->get_str_list(dev, id, idx, size, val); } +int sysinfo_get_str_list_max_len(struct udevice *dev, int id) +{ + int maxlen = 0; + unsigned i; + + /* first find out length of the longest string in the list */ + for (i = 0; ; ++i) { + char dummy[1]; + int len; + + len = sysinfo_get_str_list(dev, id, i, 0, dummy); + if (len == -ERANGE) + break; + else if (len < 0) + return len; + else if (len > maxlen) + maxlen = len; + } + + return maxlen; +} + +struct sysinfo_str_list_iter { + struct udevice *dev; + int id; + size_t size; + unsigned idx; + char value[]; +}; + +char *sysinfo_str_list_first(struct udevice *dev, int id, void *_iter) +{ + struct sysinfo_str_list_iter *iter, **iterp = _iter; + int maxlen, res; + + maxlen = sysinfo_get_str_list_max_len(dev, id); + if (maxlen < 0) + return NULL; + + iter = malloc(sizeof(struct sysinfo_str_list_iter) + maxlen + 1); + if (!iter) { + printf("No memory for sysinfo string list iterator\n"); + return NULL; + } + + iter->dev = dev; + iter->id = id; + iter->size = maxlen + 1; + iter->idx = 0; + + res = sysinfo_get_str_list(dev, id, 0, iter->size, iter->value); + if (res < 0) { + *iterp = NULL; + free(iter); + return NULL; + } + + *iterp = iter; + + return iter->value; +} + +char *sysinfo_str_list_next(void *_iter) +{ + struct sysinfo_str_list_iter **iterp = _iter, *iter = *iterp; + int res; + + res = sysinfo_get_str_list(iter->dev, iter->id, ++iter->idx, iter->size, + iter->value); + if (res < 0) { + *iterp = NULL; + free(iter); + return NULL; + } + + return iter->value; +} + UCLASS_DRIVER(sysinfo) = { .id = UCLASS_SYSINFO, .name = "sysinfo", diff --git a/include/sysinfo.h b/include/sysinfo.h index 0d8a2d1676..d32bf3e808 100644 --- a/include/sysinfo.h +++ b/include/sysinfo.h @@ -218,6 +218,61 @@ int sysinfo_get_str(struct udevice *dev, int id, size_t size, char *val); int sysinfo_get_str_list(struct udevice *dev, int id, unsigned idx, size_t size, char *val); +/** + * sysinfo_get_str_list_max_len() - Get length of longest string in a string + * list that describes hardware setup. + * @dev: The sysinfo instance to gather the data. + * @id: A unique identifier for the string list to read from. + * + * Return: Length (excluding the terminating NULL-byte) of the longest string in + * the string list, or -ve on error. + */ +int sysinfo_get_str_list_max_len(struct udevice *dev, int id); + +/** + * sysinfo_str_list_first() - Start iterating a string list. + * @dev: The sysinfo instance to gather the data. + * @id: A unique identifier for the string list to read from. + * @_iter: Pointer where iterator data will be stored. + * + * Pass a reference to a void * pointer as @_iter, i.e. + * void *iter; + * first = sysinfo_str_list_first(dev, id, &iter); + * + * The function will allocate space for the value. You need to iterate all + * elements with sysinfo_str_list_next() for the space to be freed, or free + * the pointer stored in @_iter, i.e. + * void *iter; + * first = sysinfo_str_list_first(dev, id, &iter); + * if (first) + * free(iter); + * + * Return: First string in the string list, or NULL on error. + */ +char *sysinfo_str_list_first(struct udevice *dev, int id, void *_iter); + +/** + * sysinfo_str_list_next() - Get next string in the string string list. + * @_iter: Pointer to iterator, filled in by sysinfo_str_list_first(). + * + * Pass a reference to a void * pointer as @_iter, i.e. + * void *iter; + * first = sysinfo_str_list_first(dev, id, &iter); + * next = sysinfo_str_list_next(&iter); + * + * All elements must be iterated until the function returns NULL for the + * resources allocated for the iteration to be freed, or pointer stored in + * @_iter must be freed, i.e.: + * void *iter; + * first = sysinfo_str_list_first(dev, id, &iter); + * next = sysinfo_str_list_next(&iter); + * if (next) + * free(iter); + * + * Return: Next string in the string list, NULL on end of list or NULL on error. + */ +char *sysinfo_str_list_next(void *_iter); + /** * sysinfo_get() - Return the sysinfo device for the sysinfo in question. * @devp: Pointer to structure to receive the sysinfo device. @@ -279,6 +334,22 @@ static inline int sysinfo_get_str_list(struct udevice *dev, int id, return -ENOSYS; } +static inline int sysinfo_get_str_list_max_len(struct udevice *dev, int id) +{ + return -ENOSYS; +} + +static inline char *sysinfo_str_list_first(struct udevice *dev, int id, + void *_iter) +{ + return NULL; +} + +static inline char *sysinfo_str_list_next(void *_iter) +{ + return NULL; +} + static inline int sysinfo_get(struct udevice **devp) { return -ENOSYS; @@ -291,4 +362,32 @@ static inline int sysinfo_get_fit_loadable(struct udevice *dev, int index, } #endif + +/** + * for_each_sysinfo_str_list - Iterate a sysinfo string list + * @dev: The sysinfo instance to gather the data. + * @id: A unique identifier for the string list to read from. + * @val: String pointer for the value. + * @iter: Pointer where iteration data are stored. + * + * Important: all elements of the list must be iterated for the iterator + * resources to be freed automatically. If you need to break from the for cycle, + * you need to free the iterator. + * + * Example: + * char *value; + * void *iter; + * for_each_sysinfo_str_list(dev, MY_STR_LIST, value, iter) { + * printf("Value: %s\n", value); + * if (!strcmp(value, "needle")) { + * free(iter); + * break; + * } + * } + */ +#define for_each_sysinfo_str_list(dev, id, val, iter) \ + for ((val) = sysinfo_str_list_first((dev), (id), &(iter)); \ + (val); \ + (val) = sysinfo_str_list_next(&(iter))) + #endif diff --git a/test/dm/sysinfo.c b/test/dm/sysinfo.c index a6b246f2df..e9b70d8e1a 100644 --- a/test/dm/sysinfo.c +++ b/test/dm/sysinfo.c @@ -75,3 +75,38 @@ static int dm_test_sysinfo(struct unit_test_state *uts) } DM_TEST(dm_test_sysinfo, UT_TESTF_SCAN_PDATA | UT_TESTF_SCAN_FDT); + +static int dm_test_sysinfo_str_list_iter(struct unit_test_state *uts) +{ + struct udevice *sysinfo; + char *value; + void *iter; + int idx; + + ut_assertok(sysinfo_get(&sysinfo)); + ut_assert(sysinfo); + + sysinfo_detect(sysinfo); + + idx = 0; + for_each_sysinfo_str_list(sysinfo, STR_VACATIONSPOT, value, iter) { + switch (idx) { + case 0: + ut_asserteq_str(value, "R'lyeh"); + break; + case 2: + ut_asserteq_str(value, "Plateau of Leng"); + break; + case 3: + ut_asserteq_str(value, "Carcosa"); + break; + } + ++idx; + } + + ut_assert(NULL == iter); + + return 0; +} + +DM_TEST(dm_test_sysinfo_str_list_iter, UT_TESTF_SCAN_PDATA | UT_TESTF_SCAN_FDT);