About extensible prinf(3), a slightly long X-mas card

Matthew N. Dodd mdodd at FreeBSD.ORG
Sat Dec 17 09:57:44 PST 2005


On Fri, 16 Dec 2005, Poul-Henning Kamp wrote:
> If this proves useful, it'll stay in the tree and be part of 7.0 (no MFCs!)
> it people break out in bikesheds about it, it will not.

I'd rather leave the single letter specifiers and modifiers to the 
standards compliant printf and use something like %{foo} as the specifier 
for extensions.

I've re-arranged some of the internals to make this easier to implement, 
and stubbed out the parsing of the %{} formats.  I'm a little unsure what 
sort of errors to throw on extension lookup failure.

...

What are your feelings on implementing things in such a way that the 
compiler could use this same sort of extension plugin to perform type 
checking?

-------------- next part --------------
Index: include/printf.h
===================================================================
RCS file: /home/cvs/src/include/printf.h,v
retrieving revision 1.1
diff -u -u -r1.1 printf.h
--- include/printf.h	16 Dec 2005 18:56:38 -0000	1.1
+++ include/printf.h	17 Dec 2005 17:13:27 -0000
@@ -74,6 +74,7 @@
 	const char	*begin;
 	const char	*end;
 	void 		*arg[__PRINTFMAXARG];
+	struct arg_function *arg_fcn;
 };
 
 enum {
@@ -105,6 +106,12 @@
 struct __printf_io;
 typedef int printf_render(struct __printf_io *, const struct printf_info *, const void *const *);
 
+struct arg_function {
+	printf_arginfo_function	*arginfo;
+	printf_function		*gnurender;
+	printf_render		*render;
+};
+
 /* vprintf.c */
 extern const char __lowercase_hex[17];
 extern const char __uppercase_hex[17];
Index: lib/libc/stdio/xprintf.c
===================================================================
RCS file: /home/cvs/src/lib/libc/stdio/xprintf.c,v
retrieving revision 1.1
diff -u -u -r1.1 xprintf.c
--- lib/libc/stdio/xprintf.c	16 Dec 2005 18:56:38 -0000	1.1
+++ lib/libc/stdio/xprintf.c	17 Dec 2005 17:48:37 -0000
@@ -230,11 +230,7 @@
 /* table -------------------------------------------------------------*/
 
 /*lint -esym(785, printf_tbl) */
-static struct {
-	printf_arginfo_function	*arginfo;
-	printf_function		*gnurender;
-	printf_render		*render;
-} printf_tbl[256] = {
+struct arg_function printf_tbl[256] = {
 	['%'] = { __printf_arginfo_pct,		NULL,	__printf_render_pct },
 	['A'] = { __printf_arginfo_float,	NULL,	__printf_render_float },
 	['C'] = { __printf_arginfo_chr,		NULL,	__printf_render_chr },
@@ -429,13 +425,31 @@
 				pi->is_size = 1;
 				fmt++;
 				continue;
+			case '{':
+				/* Skip { */
+				pi->spec++;
+
+				/* Look for end brace. */
+				while (*fmt++ != '}')
+					;
+
+				/* No closing brace! */
+				if (*fmt == '\0')
+					abort();
+
+				/* len = pi->spec - fmt - 1 */
+				break;
 			default:
 				fmt++;
 				break;
 			}
-			if (printf_tbl[pi->spec].arginfo == NULL)
+
+			if (pi->arg_fcn == NULL)
+				pi->arg_fcn = &printf_tbl[pi->spec];
+
+			if (pi->arg_fcn->arginfo == NULL)
 				errx(1, "arginfo[%c] = NULL", pi->spec);
-			ch = printf_tbl[pi->spec].arginfo(
+			ch = pi->arg_fcn->arginfo(
 			    pi, __PRINTFMAXARG, &argt[nextarg]);
 			if (ch > 0)
 				pi->arg[0] = &args[nextarg];
@@ -540,14 +554,14 @@
 		if (pi->get_prec) 
 			pi->prec = args[pi->get_prec].intarg;
 		ret += __printf_puts(&io, pi->begin, pi->end - pi->begin);
-		if (printf_tbl[pi->spec].gnurender != NULL) {
+		if (pi->arg_fcn->gnurender != NULL) {
 			__printf_flush(&io);
 			pi->sofar = ret;
-			ret += printf_tbl[pi->spec].gnurender(
+			ret += pi->arg_fcn->gnurender(
 			    fp, pi, (const void *)pi->arg);
-		} else if (printf_tbl[pi->spec].render != NULL) {
+		} else if (pi->arg_fcn->render != NULL) {
 			pi->sofar = ret;
-			n = printf_tbl[pi->spec].render(
+			n = pi->arg_fcn->render(
 			    &io, pi, (const void *)pi->arg);
 			if (n < 0)
 				io.fp->_flags |= __SERR;


More information about the freebsd-current mailing list