142807Smsmith/*
242807Smsmith * lifted from fs/ncpfs/getopt.c
350477Speter *
442807Smsmith */
542807Smsmith#include <sys/cdefs.h>
642807Smsmith__FBSDID("$FreeBSD: releng/10.3/sys/contrib/rdma/krping/getopt.c 256829 2013-10-21 06:31:56Z np $");
742807Smsmith
842807Smsmith#include <sys/types.h>
942807Smsmith#include <linux/kernel.h>
1042807Smsmith#include <linux/string.h>
1186168Sfenner
1242807Smsmith#include "getopt.h"
1342807Smsmith
1442807Smsmith/**
1542807Smsmith *	krping_getopt - option parser
1642807Smsmith *	@caller: name of the caller, for error messages
1742807Smsmith *	@options: the options string
1842807Smsmith *	@opts: an array of &struct option entries controlling parser operations
1942807Smsmith *	@optopt: output; will contain the current option
2042807Smsmith *	@optarg: output; will contain the value (if one exists)
2142807Smsmith *	@flag: output; may be NULL; should point to a long for or'ing flags
2242807Smsmith *	@value: output; may be NULL; will be overwritten with the integer value
2385935Sobrien *		of the current argument.
2442807Smsmith *
2585935Sobrien *	Helper to parse options on the format used by mount ("a=b,c=d,e,f").
2642807Smsmith *	Returns opts->val if a matching entry in the 'opts' array is found,
2785935Sobrien *	0 when no more tokens are found, -1 if an error is encountered.
28162742Sjhb */
2942807Smsmithint krping_getopt(const char *caller, char **options,
3085935Sobrien		  const struct krping_option *opts, char **optopt,
3142807Smsmith		  char **optarg, unsigned long *value)
32162742Sjhb{
33162742Sjhb	char *token;
3442807Smsmith	char *val;
3542807Smsmith
3642807Smsmith	do {
3742807Smsmith		if ((token = strsep(options, ",")) == NULL)
3842807Smsmith			return 0;
3942807Smsmith	} while (*token == '\0');
4042807Smsmith	if (optopt)
4142807Smsmith		*optopt = token;
4242807Smsmith
4342807Smsmith	if ((val = strchr (token, '=')) != NULL) {
4442807Smsmith		*val++ = 0;
4542807Smsmith	}
4642807Smsmith	*optarg = val;
4742807Smsmith	for (; opts->name; opts++) {
4842807Smsmith		if (!strcmp(opts->name, token)) {
4942807Smsmith			if (!val) {
5042807Smsmith				if (opts->has_arg & OPT_NOPARAM) {
5142807Smsmith					return opts->val;
5242807Smsmith				}
5342807Smsmith				printk(KERN_INFO "%s: the %s option requires "
5442807Smsmith				       "an argument\n", caller, token);
5542807Smsmith				return -EINVAL;
5642807Smsmith			}
5742807Smsmith			if (opts->has_arg & OPT_INT) {
5842807Smsmith				char* v;
5942807Smsmith
6042807Smsmith				*value = simple_strtoul(val, &v, 0);
6142807Smsmith				if (!*v) {
6242807Smsmith					return opts->val;
6342807Smsmith				}
6442807Smsmith				printk(KERN_INFO "%s: invalid numeric value "
6542807Smsmith				       "in %s=%s\n", caller, token, val);
6642807Smsmith				return -EDOM;
6742807Smsmith			}
6842807Smsmith			if (opts->has_arg & OPT_STRING) {
6942807Smsmith				return opts->val;
7042807Smsmith			}
7142807Smsmith			printk(KERN_INFO "%s: unexpected argument %s to the "
7242807Smsmith			       "%s option\n", caller, val, token);
7342807Smsmith			return -EINVAL;
7442807Smsmith		}
7542807Smsmith	}
7642807Smsmith	printk(KERN_INFO "%s: Unrecognized option %s\n", caller, token);
7742807Smsmith	return -EOPNOTSUPP;
7842807Smsmith}
7942807Smsmith