Browse Source

opt: allow const arguments.

This need shows up most clearly with opt_usage_and_exit and gcc's
-Wwrite-strings, where string literals become "const char *".  Our
callbacks should take const void *: since we overload the arg field
already (to hold table size) it make sense to turn it into a proper
union.
Rusty Russell 15 years ago
parent
commit
e34192d580
5 changed files with 36 additions and 19 deletions
  1. 3 3
      ccan/opt/opt.c
  2. 15 11
      ccan/opt/opt.h
  3. 2 2
      ccan/opt/parse.c
  4. 13 0
      ccan/opt/test/compile_ok-const-arg.c
  5. 3 3
      ccan/opt/usage.c

+ 3 - 3
ccan/opt/opt.c

@@ -150,7 +150,7 @@ void _opt_register(const char *names, enum opt_type type,
 		   char *(*cb)(void *arg),
 		   char *(*cb_arg)(const char *optarg, void *arg),
 		   void (*show)(char buf[OPT_SHOW_LEN], const void *arg),
-		   void *arg, const char *desc)
+		   const void *arg, const char *desc)
 {
 	struct opt_table opt;
 	opt.names = names;
@@ -158,7 +158,7 @@ void _opt_register(const char *names, enum opt_type type,
 	opt.cb = cb;
 	opt.cb_arg = cb_arg;
 	opt.show = show;
-	opt.arg = arg;
+	opt.u.carg = arg;
 	opt.desc = desc;
 	check_opt(&opt);
 	add_opt(&opt);
@@ -183,7 +183,7 @@ void opt_register_table(const struct opt_table entry[], const char *desc)
 	}
 	/* We store the table length in arg ptr. */
 	if (desc)
-		opt_table[start].arg = (void *)(intptr_t)(opt_count - start);
+		opt_table[start].u.tlen = (opt_count - start);
 }
 
 /* Parse your arguments. */

+ 15 - 11
ccan/opt/opt.h

@@ -30,7 +30,7 @@ struct opt_table;
  *	OPT_WITH_ARG()
  */
 #define OPT_WITHOUT_ARG(names, cb, arg, desc)	\
-	{ (names), OPT_CB_NOARG((cb), (arg)), (desc) }
+	{ (names), OPT_CB_NOARG((cb), (arg)), { (arg) }, (desc) }
 
 /**
  * OPT_WITH_ARG() - macro for initializing long and short option (with arg)
@@ -65,7 +65,7 @@ struct opt_table;
  *	OPT_WITHOUT_ARG()
  */
 #define OPT_WITH_ARG(name, cb, show, arg, desc)	\
-	{ (name), OPT_CB_ARG((cb), (show), (arg)), (desc) }
+	{ (name), OPT_CB_ARG((cb), (show), (arg)), { (arg) }, (desc) }
 
 /**
  * OPT_SUBTABLE() - macro for including another table inside a table.
@@ -74,14 +74,15 @@ struct opt_table;
  */
 #define OPT_SUBTABLE(table, desc)					\
 	{ (const char *)(table), OPT_SUBTABLE,				\
-	sizeof(_check_is_entry(table)) ? NULL : NULL, NULL, NULL, NULL, (desc) }
+	  sizeof(_check_is_entry(table)) ? NULL : NULL, NULL, NULL,	\
+	  { NULL }, (desc) }
 
 /**
  * OPT_ENDTABLE - macro to create final entry in table.
  *
  * This must be the final element in the opt_table array.
  */
-#define OPT_ENDTABLE { NULL, OPT_END, NULL, NULL, NULL, NULL, NULL }
+#define OPT_ENDTABLE { NULL, OPT_END, NULL, NULL, NULL, { NULL }, NULL }
 
 /**
  * opt_register_table - register a table of options
@@ -127,7 +128,7 @@ void opt_register_table(const struct opt_table *table, const char *desc);
  * string and return false.
  */
 #define opt_register_noarg(names, cb, arg, desc)			\
-	_opt_register((names), OPT_CB_NOARG((cb), (arg)), (desc))
+	_opt_register((names), OPT_CB_NOARG((cb), (arg)), (arg), (desc))
 
 /**
  * opt_register_arg - register an option with an arguments
@@ -157,7 +158,7 @@ void opt_register_table(const struct opt_table *table, const char *desc);
  *	opt_register_arg("--explode|--boom", explode, NULL, NULL, opt_hidden);
  */
 #define opt_register_arg(names, cb, show, arg, desc)			\
-	_opt_register((names), OPT_CB_ARG((cb), (show), (arg)), (desc))
+	_opt_register((names), OPT_CB_ARG((cb), (show), (arg)), (arg), (desc))
 
 /**
  * opt_parse - parse arguments.
@@ -303,7 +304,11 @@ struct opt_table {
 	char *(*cb)(void *arg); /* OPT_NOARG */
 	char *(*cb_arg)(const char *optarg, void *arg); /* OPT_HASARG */
 	void (*show)(char buf[OPT_SHOW_LEN], const void *arg);
-	void *arg;
+	union {
+		const void *carg;
+		void *arg;
+		size_t tlen;
+	} u;
 	const char *desc;
 };
 
@@ -314,7 +319,7 @@ struct opt_table {
 		    char *(*)(typeof(*(arg))*),		\
 		    char *(*)(const typeof(*(arg))*),	\
 		    char *(*)(const void *)),		\
-	NULL, NULL, (arg)
+	NULL, NULL
 
 /* Resolves to the four parameters for arg callbacks. */
 #define OPT_CB_ARG(cb, show, arg)					\
@@ -324,15 +329,14 @@ struct opt_table {
 		    char *(*)(const char *, const typeof(*(arg))*),	\
 		    char *(*)(const char *, const void *)),		\
 	cast_if_type(void (*)(char buf[], const void *), (show), (show)+0, \
-		     void (*)(char buf[], const typeof(*(arg))*)),	\
-	(arg)
+		     void (*)(char buf[], const typeof(*(arg))*))
 
 /* Non-typesafe register function. */
 void _opt_register(const char *names, enum opt_type type,
 		   char *(*cb)(void *arg),
 		   char *(*cb_arg)(const char *optarg, void *arg),
 		   void (*show)(char buf[OPT_SHOW_LEN], const void *arg),
-		   void *arg, const char *desc);
+		   const void *arg, const char *desc);
 
 /* We use this to get typechecking for OPT_SUBTABLE */
 static inline int _check_is_entry(struct opt_table *e UNUSED) { return 0; }

+ 2 - 2
ccan/opt/parse.c

@@ -94,7 +94,7 @@ int parse_one(int *argc, char *argv[], unsigned *offset,
 		if (optarg)
 			return parse_err(errlog, argv[0], o, len,
 					 "doesn't allow an argument");
-		problem = opt_table[i].cb(opt_table[i].arg);
+		problem = opt_table[i].cb(opt_table[i].u.arg);
 	} else {
 		if (!optarg) {
 			/* Swallow any short options as optarg, eg -afile */
@@ -107,7 +107,7 @@ int parse_one(int *argc, char *argv[], unsigned *offset,
 		if (!optarg)
 			return parse_err(errlog, argv[0], o, len,
 					 "requires an argument");
-		problem = opt_table[i].cb_arg(optarg, opt_table[i].arg);
+		problem = opt_table[i].cb_arg(optarg, opt_table[i].u.arg);
 	}
 
 	if (problem) {

+ 13 - 0
ccan/opt/test/compile_ok-const-arg.c

@@ -0,0 +1,13 @@
+#include <ccan/opt/opt.h>
+#include <ccan/opt/opt.c>
+#include <ccan/opt/helpers.c>
+#include <ccan/opt/parse.c>
+#include <ccan/opt/usage.c>
+
+int main(int argc, char *argv[])
+{
+	opt_register_noarg("-v", opt_version_and_exit,
+			   (const char *)"1.2.3",
+			   (const char *)"Print version");
+	return 0;
+}

+ 3 - 3
ccan/opt/usage.c

@@ -32,8 +32,8 @@ char *opt_usage(const char *argv0, const char *extra)
 		extra = "";
 		for (i = 0; i < opt_count; i++) {
 			if (opt_table[i].cb == (void *)opt_usage_and_exit
-			    && opt_table[i].arg) {
-				extra = opt_table[i].arg;
+			    && opt_table[i].u.carg) {
+				extra = opt_table[i].u.carg;
 				break;
 			}
 		}
@@ -100,7 +100,7 @@ char *opt_usage(const char *argv0, const char *extra)
 		if (opt_table[i].show) {
 			char buf[OPT_SHOW_LEN + sizeof("...")];
 			strcpy(buf + OPT_SHOW_LEN, "...");
-			opt_table[i].show(buf, opt_table[i].arg);
+			opt_table[i].show(buf, opt_table[i].u.arg);
 			len += sprintf(p + len, " (default: %s)", buf);
 		}
 		p += len;