- * Structure to represent \<numaddr_range\> token of the syntax.
- */
-struct numaddr_range {
- /**
- * Link to addrrange::ar_numaddr_ranges.
- */
- cfs_list_t nar_link;
- /**
- * List head for range_expr::re_link.
- */
- cfs_list_t nar_range_exprs;
-};
-
-/**
- * Structure to represent \<range_expr\> token of the syntax.
- */
-struct range_expr {
- /**
- * Link to numaddr_range::nar_range_exprs.
- */
- cfs_list_t re_link;
- __u32 re_lo;
- __u32 re_hi;
- __u32 re_stride;
-};
-
-int
-cfs_iswhite(char c)
-{
- switch (c) {
- case ' ':
- case '\t':
- case '\n':
- case '\r':
- return 1;
- default:
- break;
- }
- return 0;
-}
-
-/*
- * Extracts tokens from strings.
- *
- * Looks for \a delim in string \a next, sets \a res to point to
- * substring before the delimiter, sets \a next right after the found
- * delimiter.
- *
- * \retval 1 if \a res points to a string of non-whitespace characters
- * \retval 0 otherwise
- */
-static int
-gettok(struct lstr *next, char delim, struct lstr *res)
-{
- char *end;
-
- if (next->ls_str == NULL)
- return 0;
-
- /* skip leading white spaces */
- while (next->ls_len) {
- if (!cfs_iswhite(*next->ls_str))
- break;
- next->ls_str ++;
- next->ls_len --;
- }
- if (next->ls_len == 0)
- /* whitespaces only */
- return 0;
-
- if (*next->ls_str == delim)
- /* first non-writespace is the delimiter */
- return 0;
-
- res->ls_str = next->ls_str;
- end = memchr(next->ls_str, delim, next->ls_len);
- if (end == NULL) {
- /* there is no the delimeter in the string */
- end = next->ls_str + next->ls_len;
- next->ls_str = NULL;
- } else {
- next->ls_str = end + 1;
- next->ls_len -= (end - res->ls_str + 1);
- }
-
- /* skip ending whitespaces */
- while (--end != res->ls_str)
- if (!cfs_iswhite(*end))
- break;
-
- res->ls_len = end - res->ls_str + 1;
- return 1;
-}
-
-/**
- * Converts string to integer.
- *
- * Accepts decimal and hexadecimal number recordings.
- *
- * \retval 1 if first \a nob chars of \a str convert to decimal or
- * hexadecimal integer in the range [\a min, \a max]
- * \retval 0 otherwise
- */
-static int
-libcfs_str2num_check(const char *str, int nob, unsigned *num,
- unsigned min, unsigned max)
-{
- int n;
- char nstr[12];
-
- n = nob;
- if (sscanf(str, "%u%n", num, &n) != 1 || n != nob)
- if (sscanf(str, "0x%x%n", num, &n) != 1 || n != nob)
- if (sscanf(str, "0X%x%n", num, &n) != 1 || n != nob)
- return 0;
- sprintf(nstr, "%u", *num);
- if (n != strlen(nstr) || memcmp(nstr, str, n)) {
- sprintf(nstr, "0x%x", *num);
- if (n != strlen(nstr) || memcmp(nstr, str, n)) {
- sprintf(nstr, "0X%x", *num);
- if (n != strlen(nstr) || memcmp(nstr, str, n))
- return 0;
- }
- }
- if (*num < min || *num > max)
- return 0;
- return 1;
-}
-
-/**
- * Parses \<range_expr\> token of the syntax.
- *
- * \retval pointer to allocated range_expr and initialized
- * range_expr::re_lo, range_expr::re_hi and range_expr:re_stride if \a
- `* src parses to
- * \<number\> |
- * \<number\> '-' \<number\> |
- * \<number\> '-' \<number\> '/' \<number\>
- * \retval NULL othersize
- */
-static struct range_expr *
-parse_range_expr(struct lstr *src, unsigned min, unsigned max)
-{
- struct lstr tok;
- struct range_expr *expr;
-
- LIBCFS_ALLOC(expr, sizeof(struct range_expr));
- if (expr == NULL)
- return NULL;
-
- if (libcfs_str2num_check(src->ls_str, src->ls_len, &expr->re_lo,
- min, max)) {
- /* <number> is parsed */
- expr->re_hi = expr->re_lo;
- expr->re_stride = 1;
- return expr;
- }
-
- if (!gettok(src, '-', &tok))
- goto failed;
- if (!libcfs_str2num_check(tok.ls_str, tok.ls_len, &expr->re_lo,
- min, max))
- goto failed;
- /* <number> - */
- if (libcfs_str2num_check(src->ls_str, src->ls_len, &expr->re_hi,
- min, max)) {
- /* <number> - <number> is parsed */
- expr->re_stride = 1;
- return expr;
- }
-
- /* go to check <number> '-' <number> '/' <number> */
- if (gettok(src, '/', &tok)) {
- if (!libcfs_str2num_check(tok.ls_str, tok.ls_len,
- &expr->re_hi, min, max))
- goto failed;
- /* <number> - <number> / ... */
- if (libcfs_str2num_check(src->ls_str, src->ls_len,
- &expr->re_stride, min, max))
- /* <number> - <number> / <number> is parsed */
- return expr;
- }
-
-failed:
- LIBCFS_FREE(expr, sizeof(struct range_expr));
- return NULL;
-}
-
-/**
- * Parses \<expr_list\> token of the syntax.
- *
- * \retval 1 if \a str parses to '[' \<range_expr\> [ ',' \<range_expr\>] ']'
- * \retval 0 otherwise
- */
-static int
-parse_expr_list(struct lstr *str, cfs_list_t *list,
- unsigned min, unsigned max)
-{
- struct lstr res;
- struct range_expr *range;
-
- if (str->ls_str[0] != '[' || str->ls_str[str->ls_len - 1] != ']')
- return 0;
- str->ls_str ++;
- str->ls_len -= 2;
-
- while (str->ls_str) {
- if (gettok(str, ',', &res) == 0)
- return 0;
- range = parse_range_expr(&res, min, max);
- if (range == NULL)
- return 0;
- cfs_list_add_tail(&range->re_link, list);
- }
- return 1;
-}
-
-/**
- * Parses \<numaddr_range\> token of the syntax.
- *
- * \retval 1 if \a str parses to \<number\> | \<expr_list\>
- * \retval 0 otherwise
- */
-static int
-num_parse(char *str, int len,
- cfs_list_t *list, unsigned min, unsigned max)
-{
- __u32 num;
- struct lstr src;
- struct numaddr_range *numaddr;
-
- src.ls_str = str;
- src.ls_len = len;
-
- LIBCFS_ALLOC(numaddr, sizeof(struct numaddr_range));
- if (numaddr == NULL)
- return 0;
- cfs_list_add_tail(&numaddr->nar_link, list);
- CFS_INIT_LIST_HEAD(&numaddr->nar_range_exprs);
-
- if (libcfs_str2num_check(src.ls_str, src.ls_len, &num, min, max)) {
- /* <number> */
- struct range_expr *expr;
-
- LIBCFS_ALLOC(expr, sizeof(struct range_expr));
- if (expr == NULL)
- return 0;
-
- expr->re_lo = expr->re_hi = num;
- expr->re_stride = 1;
- cfs_list_add_tail(&expr->re_link, &numaddr->nar_range_exprs);
- return 1;
- }
-
- return parse_expr_list(&src, &numaddr->nar_range_exprs, min, max);
-}
-
-/**