2020-12-22 13:12:04

by Alexandru Ardelean

[permalink] [raw]
Subject: [PATCH v6 1/2] lib/string.c: add __sysfs_match_string_with_gaps() helper

The original docstring of the __sysfs_match_string() and match_string()
helper, implied that -1 could be used to search through NULL terminated
arrays, and positive 'n' could be used to go through arrays that may have
NULL elements in the middle of the array.

This isn't true. Regardless of the value of 'n', the first NULL element in
the array will stop the search, even if the element may be after a NULL
element.

To allow for a behavior where we can use the __sysfs_match_string() to
search over arrays with NULL elements in the middle, the
__sysfs_match_string_with_gaps() helper is added.
If n > 0, the search will continue until the element is found or n is
reached.
If n < 0, the search will continue until the element is found or a NULL
character is found.

Signed-off-by: Alexandru Ardelean <[email protected]>
---

Changelog v5 -> v6
* https://lore.kernel.org/linux-iio/[email protected]/
* Fixed/updated comment; one sentence was stopping midway

include/linux/string.h | 1 +
lib/string.c | 55 +++++++++++++++++++++++++++++++++---------
2 files changed, 44 insertions(+), 12 deletions(-)

diff --git a/include/linux/string.h b/include/linux/string.h
index b1f3894a0a3e..d7999e50dae1 100644
--- a/include/linux/string.h
+++ b/include/linux/string.h
@@ -191,6 +191,7 @@ static inline int strtobool(const char *s, bool *res)

int match_string(const char * const *array, size_t n, const char *string);
int __sysfs_match_string(const char * const *array, size_t n, const char *s);
+int __sysfs_match_string_with_gaps(const char * const *array, ssize_t n, const char *s);

/**
* sysfs_match_string - matches given string in an array
diff --git a/lib/string.c b/lib/string.c
index 4288e0158d47..3dbd362f28a2 100644
--- a/lib/string.c
+++ b/lib/string.c
@@ -751,6 +751,26 @@ int match_string(const char * const *array, size_t n, const char *string)
}
EXPORT_SYMBOL(match_string);

+static int __sysfs_match_string_common(const char * const *array, ssize_t n,
+ const char *str, bool gaps)
+{
+ const char *item;
+ int index;
+
+ for (index = 0; index < n; index++) {
+ item = array[index];
+ if (!item) {
+ if (gaps && n > 0)
+ continue;
+ break;
+ }
+ if (sysfs_streq(item, str))
+ return index;
+ }
+
+ return -EINVAL;
+}
+
/**
* __sysfs_match_string - matches given string in an array
* @array: array of strings
@@ -770,21 +790,32 @@ EXPORT_SYMBOL(match_string);
*/
int __sysfs_match_string(const char * const *array, size_t n, const char *str)
{
- const char *item;
- int index;
-
- for (index = 0; index < n; index++) {
- item = array[index];
- if (!item)
- break;
- if (sysfs_streq(item, str))
- return index;
- }
-
- return -EINVAL;
+ return __sysfs_match_string_common(array, n, str, false);
}
EXPORT_SYMBOL(__sysfs_match_string);

+/**
+ * __sysfs_match_string_with_gaps - matches given string in an array with gaps
+ * @array: array of strings
+ * @n: number of strings in the array or negative for NULL terminated arrays
+ * @str: string to match with
+ *
+ * Returns index of @str in the @array or -EINVAL, similar to match_string().
+ * Uses sysfs_streq instead of strcmp for matching.
+ *
+ * This routine will look for a string in an array of strings.
+ * If n > 0, then the search will continue until the element is found or
+ * the n-th element is reached, regardless of any NULL elements in the array.
+ * If n < 0, then the search will continue until the element is found or
+ * util the first NULL element.
+ */
+int __sysfs_match_string_with_gaps(const char * const *array, ssize_t n,
+ const char *str)
+{
+ return __sysfs_match_string_common(array, n, str, true);
+}
+EXPORT_SYMBOL(__sysfs_match_string_with_gaps);
+
#ifndef __HAVE_ARCH_MEMSET
/**
* memset - Fill a region of memory with the given value
--
2.17.1


2020-12-22 13:43:36

by Andy Shevchenko

[permalink] [raw]
Subject: Re: [PATCH v6 1/2] lib/string.c: add __sysfs_match_string_with_gaps() helper

On Tue, Dec 22, 2020 at 3:09 PM Alexandru Ardelean
<[email protected]> wrote:
>
> The original docstring of the __sysfs_match_string() and match_string()
> helper, implied that -1 could be used to search through NULL terminated
> arrays, and positive 'n' could be used to go through arrays that may have
> NULL elements in the middle of the array.
>
> This isn't true. Regardless of the value of 'n', the first NULL element in
> the array will stop the search, even if the element may be after a NULL
> element.
>
> To allow for a behavior where we can use the __sysfs_match_string() to
> search over arrays with NULL elements in the middle, the
> __sysfs_match_string_with_gaps() helper is added.
> If n > 0, the search will continue until the element is found or n is
> reached.
> If n < 0, the search will continue until the element is found or a NULL
> character is found.

I'm wondering if we can leave __sysfs_match_string() alone (w/o adding
unnecessary branch).

int __sysfs_match_string_with_gaps(const char * const *array, size_t
n, const char *str)
{
const char *item;
int index;

for (index = 0; index < n; index++) {
item = array[index];
if (!item)
continue;
if (sysfs_streq(item, str))
return index;
}
return -EINVAL;
}

Note, the check n>0 seems redundant for this particular function.

> +static int __sysfs_match_string_common(const char * const *array, ssize_t n,
> + const char *str, bool gaps)
> +{
> + const char *item;
> + int index;
> +
> + for (index = 0; index < n; index++) {
> + item = array[index];
> + if (!item) {
> + if (gaps && n > 0)
> + continue;
> + break;
> + }
> + if (sysfs_streq(item, str))
> + return index;
> + }
> +
> + return -EINVAL;
> +}
> +
> /**
> * __sysfs_match_string - matches given string in an array
> * @array: array of strings
> @@ -770,21 +790,32 @@ EXPORT_SYMBOL(match_string);
> */
> int __sysfs_match_string(const char * const *array, size_t n, const char *str)
> {
> - const char *item;
> - int index;
> -
> - for (index = 0; index < n; index++) {
> - item = array[index];
> - if (!item)
> - break;
> - if (sysfs_streq(item, str))
> - return index;
> - }
> -
> - return -EINVAL;
> + return __sysfs_match_string_common(array, n, str, false);
> }

--
With Best Regards,
Andy Shevchenko

2020-12-23 07:34:47

by Alexandru Ardelean

[permalink] [raw]
Subject: Re: [PATCH v6 1/2] lib/string.c: add __sysfs_match_string_with_gaps() helper

On Tue, Dec 22, 2020 at 3:43 PM Andy Shevchenko
<[email protected]> wrote:
>
> On Tue, Dec 22, 2020 at 3:09 PM Alexandru Ardelean
> <[email protected]> wrote:
> >
> > The original docstring of the __sysfs_match_string() and match_string()
> > helper, implied that -1 could be used to search through NULL terminated
> > arrays, and positive 'n' could be used to go through arrays that may have
> > NULL elements in the middle of the array.
> >
> > This isn't true. Regardless of the value of 'n', the first NULL element in
> > the array will stop the search, even if the element may be after a NULL
> > element.
> >
> > To allow for a behavior where we can use the __sysfs_match_string() to
> > search over arrays with NULL elements in the middle, the
> > __sysfs_match_string_with_gaps() helper is added.
> > If n > 0, the search will continue until the element is found or n is
> > reached.
> > If n < 0, the search will continue until the element is found or a NULL
> > character is found.
>
> I'm wondering if we can leave __sysfs_match_string() alone (w/o adding
> unnecessary branch).

Works for me.
Will re-spin.

>
> int __sysfs_match_string_with_gaps(const char * const *array, size_t
> n, const char *str)
> {
> const char *item;
> int index;
>
> for (index = 0; index < n; index++) {
> item = array[index];
> if (!item)
> continue;
> if (sysfs_streq(item, str))
> return index;
> }
> return -EINVAL;
> }
>
> Note, the check n>0 seems redundant for this particular function.
>
> > +static int __sysfs_match_string_common(const char * const *array, ssize_t n,
> > + const char *str, bool gaps)
> > +{
> > + const char *item;
> > + int index;
> > +
> > + for (index = 0; index < n; index++) {
> > + item = array[index];
> > + if (!item) {
> > + if (gaps && n > 0)
> > + continue;
> > + break;
> > + }
> > + if (sysfs_streq(item, str))
> > + return index;
> > + }
> > +
> > + return -EINVAL;
> > +}
> > +
> > /**
> > * __sysfs_match_string - matches given string in an array
> > * @array: array of strings
> > @@ -770,21 +790,32 @@ EXPORT_SYMBOL(match_string);
> > */
> > int __sysfs_match_string(const char * const *array, size_t n, const char *str)
> > {
> > - const char *item;
> > - int index;
> > -
> > - for (index = 0; index < n; index++) {
> > - item = array[index];
> > - if (!item)
> > - break;
> > - if (sysfs_streq(item, str))
> > - return index;
> > - }
> > -
> > - return -EINVAL;
> > + return __sysfs_match_string_common(array, n, str, false);
> > }
>
> --
> With Best Regards,
> Andy Shevchenko