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