xref: /dragonfly/lib/libc/stdio/xprintf.c (revision d1dea7aa13519a89e99562b6d70231396cc9b243)
1 /*-
2  * Copyright (c) 2005 Poul-Henning Kamp
3  * Copyright (c) 1990, 1993
4  *        The Regents of the University of California.  All rights reserved.
5  *
6  * This code is derived from software contributed to Berkeley by
7  * Chris Torek.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in the
16  *    documentation and/or other materials provided with the distribution.
17  * 3. Neither the name of the University nor the names of its contributors
18  *    may be used to endorse or promote products derived from this software
19  *    without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  *
33  * $FreeBSD: src/lib/libc/stdio/xprintf.c,v 1.8 2008/05/05 16:03:52 jhb Exp $
34  */
35 
36 #include "namespace.h"
37 #include <err.h>
38 #include <sys/types.h>
39 #include <stdio.h>
40 #include <stddef.h>
41 #include <stdlib.h>
42 #include <locale.h>
43 #include <stdint.h>
44 #include <assert.h>
45 #include <stdarg.h>
46 #include <string.h>
47 #include <wchar.h>
48 #include "un-namespace.h"
49 
50 #include "printf.h"
51 #include "priv_stdio.h"
52 
53 int __use_xprintf = -1;
54 
55 /* private stuff -----------------------------------------------------*/
56 
57 union arg {
58           int                           intarg;
59           long                          longarg;
60           intmax_t            intmaxarg;
61 #ifndef NO_FLOATING_POINT
62           double                        doublearg;
63           long double                   longdoublearg;
64 #endif
65           wint_t                        wintarg;
66           char                          *pchararg;
67           wchar_t                       *pwchararg;
68           void                          *pvoidarg;
69 };
70 
71 /*
72  * Macros for converting digits to letters and vice versa
73  */
74 #define   to_digit(c)         ((c) - '0')
75 #define   is_digit(c)         (((unsigned)to_digit(c)) <= 9)
76 
77 /* various globals ---------------------------------------------------*/
78 
79 const char __lowercase_hex[17] = "0123456789abcdef?";       /*lint !e784 */
80 const char __uppercase_hex[17] = "0123456789ABCDEF?";       /*lint !e784 */
81 
82 #define PADSIZE 16
83 static char blanks[PADSIZE] =
84            {' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' '};
85 static char zeroes[PADSIZE] =
86            {'0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0'};
87 
88 /* printing and padding functions ------------------------------------*/
89 
90 #define NIOV 8
91 
92 struct __printf_io {
93           FILE                *fp;
94           struct __suio       uio;
95           struct __siov       iov[NIOV];
96           struct __siov       *iovp;
97 };
98 
99 static void
__printf_init(struct __printf_io * io)100 __printf_init(struct __printf_io *io)
101 {
102 
103           io->uio.uio_iov = io->iovp = &io->iov[0];
104           io->uio.uio_resid = 0;
105           io->uio.uio_iovcnt = 0;
106 }
107 
108 void
__printf_flush(struct __printf_io * io)109 __printf_flush(struct __printf_io *io)
110 {
111 
112           __sfvwrite(io->fp, &io->uio);
113           __printf_init(io);
114 }
115 
116 int
__printf_puts(struct __printf_io * io,const void * ptr,int len)117 __printf_puts(struct __printf_io *io, const void *ptr, int len)
118 {
119 
120           if (io->fp->pub._flags & __SERR)
121                     return (0);
122           if (len == 0)
123                     return (0);
124           io->iovp->iov_base = __DECONST(void *, ptr);
125           io->iovp->iov_len = len;
126           io->uio.uio_resid += len;
127           io->iovp++;
128           io->uio.uio_iovcnt++;
129           if (io->uio.uio_iovcnt >= NIOV)
130                     __printf_flush(io);
131           return (len);
132 }
133 
134 int
__printf_pad(struct __printf_io * io,int howmany,int zero)135 __printf_pad(struct __printf_io *io, int howmany, int zero)
136 {
137           int n;
138           const char *with;
139           int ret = 0;
140 
141           if (zero)
142                     with = zeroes;
143           else
144                     with = blanks;
145 
146           if ((n = (howmany)) > 0) {
147                     while (n > PADSIZE) {
148                               ret += __printf_puts(io, with, PADSIZE);
149                               n -= PADSIZE;
150                     }
151                     ret += __printf_puts(io, with, n);
152           }
153           return (ret);
154 }
155 
156 int
__printf_out(struct __printf_io * io,const struct printf_info * pi,const void * ptr,int len)157 __printf_out(struct __printf_io *io, const struct printf_info *pi,
158                const void *ptr, int len)
159 {
160           int ret = 0;
161 
162           if ((!pi->left) && pi->width > len)
163                     ret += __printf_pad(io, pi->width - len, pi->pad == '0');
164           ret += __printf_puts(io, ptr, len);
165           if (pi->left && pi->width > len)
166                     ret += __printf_pad(io, pi->width - len, pi->pad == '0');
167           return (ret);
168 }
169 
170 
171 /* percent handling  -------------------------------------------------*/
172 
173 static int
__printf_arginfo_pct(const struct printf_info * pi __unused,size_t n __unused,int * argt __unused)174 __printf_arginfo_pct(const struct printf_info *pi __unused, size_t n __unused,
175                          int *argt __unused)
176 {
177 
178           return (0);
179 }
180 
181 static int
__printf_render_pct(struct __printf_io * io,const struct printf_info * pi __unused,const void * const * arg __unused)182 __printf_render_pct(struct __printf_io *io,
183                         const struct printf_info *pi __unused,
184                         const void *const *arg __unused)
185 {
186 
187           return (__printf_puts(io, "%", 1));
188 }
189 
190 /* 'n' ---------------------------------------------------------------*/
191 
192 static int
__printf_arginfo_n(const struct printf_info * pi __unused,size_t n,int * argt)193 __printf_arginfo_n(const struct printf_info *pi __unused, size_t n, int *argt)
194 {
195 
196           assert(n >= 1);
197           argt[0] = PA_POINTER;
198           return (1);
199 }
200 
201 /*
202  * This is a printf_render so that all output has been flushed before it
203  * gets called.
204  */
205 
206 static int
__printf_render_n(FILE * io __unused,const struct printf_info * pi,const void * const * arg)207 __printf_render_n(FILE *io __unused, const struct printf_info *pi,
208                       const void *const *arg)
209 {
210 
211           if (pi->is_char)
212                     **((signed char **)arg[0]) = (signed char)pi->sofar;
213           else if (pi->is_short)
214                     **((short **)arg[0]) = (short)pi->sofar;
215           else if (pi->is_long)
216                     **((long **)arg[0]) = pi->sofar;
217           else if (pi->is_long_double)
218                     **((long long **)arg[0]) = pi->sofar;
219           else if (pi->is_intmax)
220                     **((intmax_t **)arg[0]) = pi->sofar;
221           else if (pi->is_ptrdiff)
222                     **((ptrdiff_t **)arg[0]) = pi->sofar;
223           else if (pi->is_quad)
224                     **((quad_t **)arg[0]) = pi->sofar;
225           else if (pi->is_size)
226                     **((size_t **)arg[0]) = pi->sofar;
227           else
228                     **((int **)arg[0]) = pi->sofar;
229 
230           return (0);
231 }
232 
233 /* table -------------------------------------------------------------*/
234 
235 /*lint -esym(785, printf_tbl) */
236 static struct {
237           printf_arginfo_function       *arginfo;
238           printf_function               *gnurender;
239           printf_render                 *render;
240 } printf_tbl[256] = {
241           ['%'] = { __printf_arginfo_pct,                   NULL,     __printf_render_pct },
242           ['A'] = { __printf_arginfo_float,       NULL,     __printf_render_float },
243           ['C'] = { __printf_arginfo_chr,                   NULL,     __printf_render_chr },
244           ['E'] = { __printf_arginfo_float,       NULL,     __printf_render_float },
245           ['F'] = { __printf_arginfo_float,       NULL,     __printf_render_float },
246           ['G'] = { __printf_arginfo_float,       NULL,     __printf_render_float },
247           ['S'] = { __printf_arginfo_str,                   NULL,     __printf_render_str },
248           ['X'] = { __printf_arginfo_int,                   NULL,     __printf_render_int },
249           ['a'] = { __printf_arginfo_float,       NULL,     __printf_render_float },
250           ['c'] = { __printf_arginfo_chr,                   NULL,     __printf_render_chr },
251           ['d'] = { __printf_arginfo_int,                   NULL,     __printf_render_int },
252           ['e'] = { __printf_arginfo_float,       NULL,     __printf_render_float },
253           ['f'] = { __printf_arginfo_float,       NULL,     __printf_render_float },
254           ['g'] = { __printf_arginfo_float,       NULL,     __printf_render_float },
255           ['i'] = { __printf_arginfo_int,                   NULL,     __printf_render_int },
256           ['n'] = { __printf_arginfo_n,           __printf_render_n, NULL },
257           ['o'] = { __printf_arginfo_int,                   NULL,     __printf_render_int },
258           ['p'] = { __printf_arginfo_ptr,                   NULL,     __printf_render_ptr },
259           ['q'] = { __printf_arginfo_int,                   NULL,     __printf_render_int },
260           ['s'] = { __printf_arginfo_str,                   NULL,     __printf_render_str },
261           ['u'] = { __printf_arginfo_int,                   NULL,     __printf_render_int },
262           ['x'] = { __printf_arginfo_int,                   NULL,     __printf_render_int },
263 };
264 
265 
266 static int
__v2printf(FILE * fp,const char * fmt0,unsigned pct,va_list ap)267 __v2printf(FILE *fp, const char *fmt0, unsigned pct, va_list ap)
268 {
269           struct printf_info  *pi, *pil;
270           const char                    *fmt;
271           int                           ch;
272           struct printf_info  pia[pct + 10];
273           int                           argt[pct + 10];
274           union arg           args[pct + 10];
275           int                           nextarg;
276           int                           maxarg;
277           int                           ret = 0;
278           int                           n;
279           struct __printf_io  io;
280 
281           __printf_init(&io);
282           io.fp = fp;
283 
284           fmt = fmt0;
285           maxarg = 0;
286           nextarg = 1;
287           memset(argt, 0, sizeof argt);
288           for (pi = pia; ; pi++) {
289                     memset(pi, 0, sizeof *pi);
290                     pil = pi;
291                     if (*fmt == '\0')
292                               break;
293                     pil = pi + 1;
294                     pi->prec = -1;
295                     pi->pad = ' ';
296                     pi->begin = pi->end = fmt;
297                     while (*fmt != '\0' && *fmt != '%')
298                               pi->end = ++fmt;
299                     if (*fmt == '\0')
300                               break;
301                     fmt++;
302                     for (;;) {
303                               pi->spec = *fmt;
304                               switch (pi->spec) {
305                               case ' ':
306                                         /*-
307                                          * ``If the space and + flags both appear, the space
308                                          * flag will be ignored.''
309                                          *      -- ANSI X3J11
310                                          */
311                                         if (pi->showsign == 0)
312                                                   pi->showsign = ' ';
313                                         fmt++;
314                                         continue;
315                               case '#':
316                                         pi->alt = 1;
317                                         fmt++;
318                                         continue;
319                               case '.':
320                                         pi->prec = 0;
321                                         fmt++;
322                                         if (*fmt == '*') {
323                                                   fmt++;
324                                                   pi->get_prec = nextarg;
325                                                   argt[nextarg++] = PA_INT;
326                                                   continue;
327                                         }
328                                         while (*fmt != '\0' && is_digit(*fmt)) {
329                                                   pi->prec *= 10;
330                                                   pi->prec += to_digit(*fmt);
331                                                   fmt++;
332                                         }
333                                         continue;
334                               case '-':
335                                         pi->left = 1;
336                                         fmt++;
337                                         continue;
338                               case '+':
339                                         pi->showsign = '+';
340                                         fmt++;
341                                         continue;
342                               case '*':
343                                         fmt++;
344                                         pi->get_width = nextarg;
345                                         argt[nextarg++] = PA_INT;
346                                         continue;
347                               case '%':
348                                         fmt++;
349                                         break;
350                               case '\'':
351                                         pi->group = 1;
352                                         fmt++;
353                                         continue;
354                               case '0':
355                                         /*-
356                                          * ``Note that 0 is taken as a flag, not as the
357                                          * beginning of a field width.''
358                                          *      -- ANSI X3J11
359                                          */
360                                         pi->pad = '0';
361                                         fmt++;
362                                         continue;
363                               case '1': case '2': case '3':
364                               case '4': case '5': case '6':
365                               case '7': case '8': case '9':
366                                         n = 0;
367                                         while (*fmt != '\0' && is_digit(*fmt)) {
368                                                   n *= 10;
369                                                   n += to_digit(*fmt);
370                                                   fmt++;
371                                         }
372                                         if (*fmt == '$') {
373                                                   if (nextarg > maxarg)
374                                                             maxarg = nextarg;
375                                                   nextarg = n;
376                                                   fmt++;
377                                         } else {
378                                                   pi->width = n;
379                                         }
380                                         continue;
381                               case 'D':
382                               case 'O':
383                               case 'U':
384                                         pi->spec += ('a' - 'A');
385                                         pi->is_intmax = 0;
386                                         if (pi->is_long_double || pi->is_quad) {
387                                                   pi->is_long = 0;
388                                                   pi->is_long_double = 1;
389                                         } else {
390                                                   pi->is_long = 1;
391                                                   pi->is_long_double = 0;
392                                         }
393                                         fmt++;
394                                         break;
395                               case 'j':
396                                         pi->is_intmax = 1;
397                                         fmt++;
398                                         continue;
399                               case 'q':
400                                         pi->is_long = 0;
401                                         pi->is_quad = 1;
402                                         fmt++;
403                                         continue;
404                               case 'L':
405                                         pi->is_long_double = 1;
406                                         fmt++;
407                                         continue;
408                               case 'h':
409                                         fmt++;
410                                         if (*fmt == 'h') {
411                                                   fmt++;
412                                                   pi->is_char = 1;
413                                         } else {
414                                                   pi->is_short = 1;
415                                         }
416                                         continue;
417                               case 'l':
418                                         fmt++;
419                                         if (*fmt == 'l') {
420                                                   fmt++;
421                                                   pi->is_long_double = 1;
422                                                   pi->is_quad = 0;
423                                         } else {
424                                                   pi->is_quad = 0;
425                                                   pi->is_long = 1;
426                                         }
427                                         continue;
428                               case 't':
429                                         pi->is_ptrdiff = 1;
430                                         fmt++;
431                                         continue;
432                               case 'z':
433                                         pi->is_size = 1;
434                                         fmt++;
435                                         continue;
436                               default:
437                                         fmt++;
438                                         break;
439                               }
440                               if (printf_tbl[pi->spec].arginfo == NULL)
441                                         errx(1, "arginfo[%c] = NULL", pi->spec);
442                               ch = printf_tbl[pi->spec].arginfo(
443                                   pi, __PRINTFMAXARG, &argt[nextarg]);
444                               if (ch > 0)
445                                         pi->arg[0] = &args[nextarg];
446                               if (ch > 1)
447                                         pi->arg[1] = &args[nextarg + 1];
448                               nextarg += ch;
449                               break;
450                     }
451           }
452           if (nextarg > maxarg)
453                     maxarg = nextarg;
454 #if 0
455           fprintf(stderr, "fmt0 <%s>\n", fmt0);
456           fprintf(stderr, "pil %p\n", pil);
457 #endif
458           for (ch = 1; ch < maxarg; ch++) {
459 #if 0
460                     fprintf(stderr, "arg %d %x\n", ch, argt[ch]);
461 #endif
462                     switch(argt[ch]) {
463                     case PA_CHAR:
464                               args[ch].intarg = (char)va_arg(ap, int);
465                               break;
466                     case PA_INT:
467                               args[ch].intarg = va_arg(ap, int);
468                               break;
469                     case PA_INT | PA_FLAG_SHORT:
470                               args[ch].intarg = (short)va_arg(ap, int);
471                               break;
472                     case PA_INT | PA_FLAG_LONG:
473                               args[ch].longarg = va_arg(ap, long);
474                               break;
475                     case PA_INT | PA_FLAG_INTMAX:
476                               args[ch].intmaxarg = va_arg(ap, intmax_t);
477                               break;
478                     case PA_INT | PA_FLAG_QUAD:
479                               args[ch].intmaxarg = va_arg(ap, quad_t);
480                               break;
481                     case PA_INT | PA_FLAG_LONG_LONG:
482                               args[ch].intmaxarg = va_arg(ap, long long);
483                               break;
484                     case PA_INT | PA_FLAG_SIZE:
485                               args[ch].intmaxarg = va_arg(ap, size_t);
486                               break;
487                     case PA_INT | PA_FLAG_PTRDIFF:
488                               args[ch].intmaxarg = va_arg(ap, ptrdiff_t);
489                               break;
490                     case PA_WCHAR:
491                               args[ch].wintarg = va_arg(ap, wint_t);
492                               break;
493                     case PA_POINTER:
494                               args[ch].pvoidarg = va_arg(ap, void *);
495                               break;
496                     case PA_STRING:
497                               args[ch].pchararg = va_arg(ap, char *);
498                               break;
499                     case PA_WSTRING:
500                               args[ch].pwchararg = va_arg(ap, wchar_t *);
501                               break;
502                     case PA_DOUBLE:
503 #ifndef NO_FLOATING_POINT
504                               args[ch].doublearg = va_arg(ap, double);
505 #endif
506                               break;
507                     case PA_DOUBLE | PA_FLAG_LONG_DOUBLE:
508 #ifndef NO_FLOATING_POINT
509                               args[ch].longdoublearg = va_arg(ap, long double);
510 #endif
511                               break;
512                     default:
513                               errx(1, "argtype = %x (fmt = \"%s\")\n",
514                                   argt[ch], fmt0);
515                     }
516           }
517           for (pi = pia; pi < pil; pi++) {
518 #if 0
519                     fprintf(stderr, "pi %p", pi);
520                     fprintf(stderr, " spec '%c'", pi->spec);
521                     fprintf(stderr, " args %d",
522                         ((uintptr_t)pi->arg[0] - (uintptr_t)args) / sizeof args[0]);
523                     if (pi->width) fprintf(stderr, " width %d", pi->width);
524                     if (pi->pad) fprintf(stderr, " pad 0x%x", pi->pad);
525                     if (pi->left) fprintf(stderr, " left");
526                     if (pi->showsign) fprintf(stderr, " showsign");
527                     if (pi->prec != -1) fprintf(stderr, " prec %d", pi->prec);
528                     if (pi->is_char) fprintf(stderr, " char");
529                     if (pi->is_short) fprintf(stderr, " short");
530                     if (pi->is_long) fprintf(stderr, " long");
531                     if (pi->is_long_double) fprintf(stderr, " long_double");
532                     fprintf(stderr, "\n");
533                     fprintf(stderr, "\t\"%.*s\"\n", pi->end - pi->begin, pi->begin);
534 #endif
535                     if (pi->get_width) {
536                               pi->width = args[pi->get_width].intarg;
537                               /*-
538                                * ``A negative field width argument is taken as a
539                                * - flag followed by a positive field width.''
540                                *      -- ANSI X3J11
541                                * They don't exclude field widths read from args.
542                                */
543                               if (pi->width < 0) {
544                                         pi->left = 1;
545                                         pi->width = -pi->width;
546                               }
547                     }
548                     if (pi->get_prec)
549                               pi->prec = args[pi->get_prec].intarg;
550                     ret += __printf_puts(&io, pi->begin, pi->end - pi->begin);
551                     if (printf_tbl[pi->spec].gnurender != NULL) {
552                               __printf_flush(&io);
553                               pi->sofar = ret;
554                               ret += printf_tbl[pi->spec].gnurender(
555                                   fp, pi, (const void *)pi->arg);
556                     } else if (printf_tbl[pi->spec].render != NULL) {
557                               pi->sofar = ret;
558                               n = printf_tbl[pi->spec].render(
559                                   &io, pi, (const void *)pi->arg);
560                               if (n < 0)
561                                         io.fp->pub._flags |= __SERR;
562                               else
563                                         ret += n;
564                     } else if (pi->begin == pi->end)
565                               errx(1, "render[%c] = NULL", *fmt);
566           }
567           __printf_flush(&io);
568           return (ret);
569 }
570 
571 extern int          __fflush(FILE *fp);
572 
573 /*
574  * Helper function for `fprintf to unbuffered unix file': creates a
575  * temporary buffer.  We only work on write-only files; this avoids
576  * worries about ungetc buffers and so forth.
577  */
578 static int
__v3printf(FILE * fp,const char * fmt,int pct,va_list ap)579 __v3printf(FILE *fp, const char *fmt, int pct, va_list ap)
580 {
581           int ret;
582           FILE fake;
583           unsigned char buf[BUFSIZ];
584 
585           /* copy the important variables */
586           fake.pub._flags = fp->pub._flags & ~__SNBF;
587           fake.pub._fileno = fp->pub._fileno;
588           fake._cookie = fp->_cookie;
589           fake._write = fp->_write;
590           memcpy(WCIO_GET(&fake), WCIO_GET(fp), sizeof(struct wchar_io_data));
591 
592           /* set up the buffer */
593           fake._bf._base = fake.pub._p = buf;
594           fake._bf._size = fake.pub._w = sizeof(buf);
595           fake.pub._lbfsize = 0;        /* not actually used, but Just In Case */
596 
597           /* do the work, then copy any error status */
598           ret = __v2printf(&fake, fmt, pct, ap);
599           if (ret >= 0 && __fflush(&fake))
600                     ret = EOF;
601           if (fake.pub._flags & __SERR)
602                     fp->pub._flags |= __SERR;
603           return (ret);
604 }
605 
606 int
__xvprintf(FILE * fp,const char * fmt0,va_list ap)607 __xvprintf(FILE *fp, const char *fmt0, va_list ap)
608 {
609           unsigned u;
610           const char *p;
611 
612           /* Count number of '%' signs handling double '%' signs */
613           for (p = fmt0, u = 0; *p; p++) {
614                     if (*p != '%')
615                               continue;
616                     u++;
617                     if (p[1] == '%')
618                               p++;
619           }
620 
621           /* optimise fprintf(stderr) (and other unbuffered Unix files) */
622           if ((fp->pub._flags & (__SNBF|__SWR|__SRW)) == (__SNBF|__SWR) &&
623               fp->pub._fileno >= 0)
624                     return (__v3printf(fp, fmt0, u, ap));
625           else
626                     return (__v2printf(fp, fmt0, u, ap));
627 }
628 
629 /* extending ---------------------------------------------------------*/
630 
631 int
register_printf_function(int spec,printf_function * render,printf_arginfo_function * arginfo)632 register_printf_function(int spec, printf_function *render,
633                                printf_arginfo_function *arginfo)
634 {
635 
636           if (spec > 255 || spec < 0)
637                     return (-1);
638           printf_tbl[spec].gnurender = render;
639           printf_tbl[spec].arginfo = arginfo;
640           __use_xprintf = 1;
641           return (0);
642 }
643 
644 int
register_printf_render(int spec,printf_render * render,printf_arginfo_function * arginfo)645 register_printf_render(int spec, printf_render *render,
646                            printf_arginfo_function *arginfo)
647 {
648 
649           if (spec > 255 || spec < 0)
650                     return (-1);
651           printf_tbl[spec].render = render;
652           printf_tbl[spec].arginfo = arginfo;
653           __use_xprintf = 1;
654           return (0);
655 }
656 
657 int
register_printf_render_std(const unsigned char * specs)658 register_printf_render_std(const unsigned char *specs)
659 {
660 
661           for (; *specs != '\0'; specs++) {
662                     switch (*specs) {
663                     case 'H':
664                               register_printf_render(*specs,
665                                   __printf_render_hexdump,
666                                   __printf_arginfo_hexdump);
667                               break;
668                     case 'M':
669                               register_printf_render(*specs,
670                                   __printf_render_errno,
671                                   __printf_arginfo_errno);
672                               break;
673                     case 'Q':
674                               register_printf_render(*specs,
675                                   __printf_render_quote,
676                                   __printf_arginfo_quote);
677                               break;
678                     case 'T':
679                               register_printf_render(*specs,
680                                   __printf_render_time,
681                                   __printf_arginfo_time);
682                               break;
683                     case 'V':
684                               register_printf_render(*specs,
685                                   __printf_render_vis,
686                                   __printf_arginfo_vis);
687                               break;
688                     default:
689                               return (-1);
690                     }
691           }
692           return (0);
693 }
694