]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - lib/libc/stdio/xprintf.c
Add two missing eventhandler.h headers
[FreeBSD/FreeBSD.git] / lib / libc / stdio / xprintf.c
1 /*-
2  * SPDX-License-Identifier: BSD-3-Clause
3  *
4  * Copyright (c) 2005 Poul-Henning Kamp
5  * Copyright (c) 1990, 1993
6  *      The Regents of the University of California.  All rights reserved.
7  *
8  * This code is derived from software contributed to Berkeley by
9  * Chris Torek.
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
14  * 1. Redistributions of source code must retain the above copyright
15  *    notice, this list of conditions and the following disclaimer.
16  * 2. Redistributions in binary form must reproduce the above copyright
17  *    notice, this list of conditions and the following disclaimer in the
18  *    documentation and/or other materials provided with the distribution.
19  * 3. Neither the name of the University nor the names of its contributors
20  *    may be used to endorse or promote products derived from this software
21  *    without specific prior written permission.
22  *
23  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33  * SUCH DAMAGE.
34  *
35  * $FreeBSD$
36  */
37
38 #include "namespace.h"
39 #include <err.h>
40 #include <sys/types.h>
41 #include <stdio.h>
42 #include <stddef.h>
43 #include <stdlib.h>
44 #include <locale.h>
45 #include <stdint.h>
46 #include <assert.h>
47 #include <stdarg.h>
48 #include <namespace.h>
49 #include <string.h>
50 #include <wchar.h>
51 #include "un-namespace.h"
52
53 #include "local.h"
54 #include "printf.h"
55 #include "fvwrite.h"
56
57 int __use_xprintf = -1;
58
59 /* private stuff -----------------------------------------------------*/
60
61 union arg {
62         int                     intarg;
63         long                    longarg;
64         intmax_t                intmaxarg;
65 #ifndef NO_FLOATING_POINT
66         double                  doublearg;
67         long double             longdoublearg;
68 #endif
69         wint_t                  wintarg;
70         char                    *pchararg;
71         wchar_t                 *pwchararg;
72         void                    *pvoidarg;
73 };
74
75 /*
76  * Macros for converting digits to letters and vice versa
77  */
78 #define to_digit(c)     ((c) - '0')
79 #define is_digit(c)     (((unsigned)to_digit(c)) <= 9)
80
81 /* various globals ---------------------------------------------------*/
82
83 const char __lowercase_hex[17] = "0123456789abcdef?";   /*lint !e784 */
84 const char __uppercase_hex[17] = "0123456789ABCDEF?";   /*lint !e784 */
85
86 #define PADSIZE 16
87 static char blanks[PADSIZE] =
88          {' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' '};
89 static char zeroes[PADSIZE] =
90          {'0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0'};
91
92 /* printing and padding functions ------------------------------------*/
93
94 #define NIOV 8
95
96 struct __printf_io {
97         FILE            *fp;
98         struct __suio   uio;
99         struct __siov   iov[NIOV];
100         struct __siov   *iovp;
101 };
102
103 static void
104 __printf_init(struct __printf_io *io)
105 {
106
107         io->uio.uio_iov = io->iovp = &io->iov[0];
108         io->uio.uio_resid = 0;
109         io->uio.uio_iovcnt = 0;
110 }
111
112 void
113 __printf_flush(struct __printf_io *io)
114 {
115
116         __sfvwrite(io->fp, &io->uio);
117         __printf_init(io);
118 }
119
120 int
121 __printf_puts(struct __printf_io *io, const void *ptr, int len)
122 {
123
124
125         if (io->fp->_flags & __SERR)
126                 return (0);
127         if (len == 0)
128                 return (0);
129         io->iovp->iov_base = __DECONST(void *, ptr);
130         io->iovp->iov_len = len;
131         io->uio.uio_resid += len;
132         io->iovp++;
133         io->uio.uio_iovcnt++;
134         if (io->uio.uio_iovcnt >= NIOV)
135                 __printf_flush(io);
136         return (len);
137 }
138
139 int
140 __printf_pad(struct __printf_io *io, int howmany, int zero)
141 {
142         int n;
143         const char *with;
144         int ret = 0;
145
146         if (zero)
147                 with = zeroes;
148         else
149                 with = blanks;
150
151         if ((n = (howmany)) > 0) {
152                 while (n > PADSIZE) { 
153                         ret += __printf_puts(io, with, PADSIZE);
154                         n -= PADSIZE;
155                 }
156                 ret += __printf_puts(io, with, n);
157         }
158         return (ret);
159 }
160
161 int
162 __printf_out(struct __printf_io *io, const struct printf_info *pi, const void *ptr, int len)
163 {
164         int ret = 0;
165
166         if ((!pi->left) && pi->width > len)
167                 ret += __printf_pad(io, pi->width - len, pi->pad == '0');
168         ret += __printf_puts(io, ptr, len);
169         if (pi->left && pi->width > len)
170                 ret += __printf_pad(io, pi->width - len, pi->pad == '0');
171         return (ret);
172 }
173
174
175 /* percent handling  -------------------------------------------------*/
176
177 static int
178 __printf_arginfo_pct(const struct printf_info *pi __unused, size_t n __unused, int *argt __unused)
179 {
180
181         return (0);
182 }
183
184 static int
185 __printf_render_pct(struct __printf_io *io, const struct printf_info *pi __unused, 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, 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
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                                 continue;
380                         case 'D':
381                         case 'O':
382                         case 'U':
383                                 pi->spec += ('a' - 'A');
384                                 pi->is_intmax = 0;
385                                 if (pi->is_long_double || pi->is_quad) {
386                                         pi->is_long = 0;
387                                         pi->is_long_double = 1;
388                                 } else {
389                                         pi->is_long = 1;
390                                         pi->is_long_double = 0;
391                                 }
392                                 fmt++;
393                                 break;
394                         case 'j':
395                                 pi->is_intmax = 1;
396                                 fmt++;
397                                 continue;
398                         case 'q':
399                                 pi->is_long = 0;
400                                 pi->is_quad = 1;
401                                 fmt++;
402                                 continue;
403                         case 'L':
404                                 pi->is_long_double = 1;
405                                 fmt++;
406                                 continue;
407                         case 'h':
408                                 fmt++;
409                                 if (*fmt == 'h') {
410                                         fmt++;
411                                         pi->is_char = 1;
412                                 } else {
413                                         pi->is_short = 1;
414                                 }
415                                 continue;
416                         case 'l':
417                                 fmt++;
418                                 if (*fmt == 'l') {
419                                         fmt++;
420                                         pi->is_long_double = 1;
421                                         pi->is_quad = 0;
422                                 } else {
423                                         pi->is_quad = 0;
424                                         pi->is_long = 1;
425                                 }
426                                 continue;
427                         case 't':
428                                 pi->is_ptrdiff = 1;
429                                 fmt++;
430                                 continue;
431                         case 'z':
432                                 pi->is_size = 1;
433                                 fmt++;
434                                 continue;
435                         default:
436                                 fmt++;
437                                 break;
438                         }
439                         if (printf_tbl[pi->spec].arginfo == NULL)
440                                 errx(1, "arginfo[%c] = NULL", pi->spec);
441                         ch = printf_tbl[pi->spec].arginfo(
442                             pi, __PRINTFMAXARG, &argt[nextarg]);
443                         if (ch > 0)
444                                 pi->arg[0] = &args[nextarg];
445                         if (ch > 1)
446                                 pi->arg[1] = &args[nextarg + 1];
447                         nextarg += ch;
448                         break;
449                 }
450         }
451         if (nextarg > maxarg)
452                 maxarg = nextarg;
453 #if 0
454         fprintf(stderr, "fmt0 <%s>\n", fmt0);
455         fprintf(stderr, "pil %p\n", pil);
456 #endif
457         for (ch = 1; ch < maxarg; ch++) {
458 #if 0
459                 fprintf(stderr, "arg %d %x\n", ch, argt[ch]);
460 #endif
461                 switch(argt[ch]) {
462                 case PA_CHAR:
463                         args[ch].intarg = (char)va_arg (ap, int);
464                         break;
465                 case PA_INT:
466                         args[ch].intarg = va_arg (ap, int);
467                         break;
468                 case PA_INT | PA_FLAG_SHORT:
469                         args[ch].intarg = (short)va_arg (ap, int);
470                         break;
471                 case PA_INT | PA_FLAG_LONG:
472                         args[ch].longarg = va_arg (ap, long);
473                         break;
474                 case PA_INT | PA_FLAG_INTMAX:
475                         args[ch].intmaxarg = va_arg (ap, intmax_t);
476                         break;
477                 case PA_INT | PA_FLAG_QUAD:
478                         args[ch].intmaxarg = va_arg (ap, quad_t);
479                         break;
480                 case PA_INT | PA_FLAG_LONG_LONG:
481                         args[ch].intmaxarg = va_arg (ap, long long);
482                         break;
483                 case PA_INT | PA_FLAG_SIZE:
484                         args[ch].intmaxarg = va_arg (ap, size_t);
485                         break;
486                 case PA_INT | PA_FLAG_PTRDIFF:
487                         args[ch].intmaxarg = va_arg (ap, ptrdiff_t);
488                         break;
489                 case PA_WCHAR:
490                         args[ch].wintarg = va_arg (ap, wint_t);
491                         break;
492                 case PA_POINTER:
493                         args[ch].pvoidarg = va_arg (ap, void *);
494                         break;
495                 case PA_STRING:
496                         args[ch].pchararg = va_arg (ap, char *);
497                         break;
498                 case PA_WSTRING:
499                         args[ch].pwchararg = va_arg (ap, wchar_t *);
500                         break;
501                 case PA_DOUBLE:
502 #ifndef NO_FLOATING_POINT
503                         args[ch].doublearg = va_arg (ap, double);
504 #endif
505                         break;
506                 case PA_DOUBLE | PA_FLAG_LONG_DOUBLE:
507 #ifndef NO_FLOATING_POINT
508                         args[ch].longdoublearg = va_arg (ap, long double);
509 #endif
510                         break;
511                 default:
512                         errx(1, "argtype = %x (fmt = \"%s\")\n",
513                             argt[ch], fmt0);
514                 }
515         }
516         for (pi = pia; pi < pil; pi++) {
517 #if 0
518                 fprintf(stderr, "pi %p", pi);
519                 fprintf(stderr, " spec '%c'", pi->spec);
520                 fprintf(stderr, " args %d",
521                     ((uintptr_t)pi->arg[0] - (uintptr_t)args) / sizeof args[0]);
522                 if (pi->width) fprintf(stderr, " width %d", pi->width);
523                 if (pi->pad) fprintf(stderr, " pad 0x%x", pi->pad);
524                 if (pi->left) fprintf(stderr, " left");
525                 if (pi->showsign) fprintf(stderr, " showsign");
526                 if (pi->prec != -1) fprintf(stderr, " prec %d", pi->prec);
527                 if (pi->is_char) fprintf(stderr, " char");
528                 if (pi->is_short) fprintf(stderr, " short");
529                 if (pi->is_long) fprintf(stderr, " long");
530                 if (pi->is_long_double) fprintf(stderr, " long_double");
531                 fprintf(stderr, "\n");
532                 fprintf(stderr, "\t\"%.*s\"\n", pi->end - pi->begin, pi->begin);
533 #endif
534                 if (pi->get_width) {
535                         pi->width = args[pi->get_width].intarg;
536                         /*-
537                          * ``A negative field width argument is taken as a
538                          * - flag followed by a positive field width.''
539                          *      -- ANSI X3J11
540                          * They don't exclude field widths read from args.
541                          */
542                         if (pi->width < 0) {
543                                 pi->left = 1;
544                                 pi->width = -pi->width;
545                         }
546                 }
547                 if (pi->get_prec) 
548                         pi->prec = args[pi->get_prec].intarg;
549                 ret += __printf_puts(&io, pi->begin, pi->end - pi->begin);
550                 if (printf_tbl[pi->spec].gnurender != NULL) {
551                         __printf_flush(&io);
552                         pi->sofar = ret;
553                         ret += printf_tbl[pi->spec].gnurender(
554                             fp, pi, (const void *)pi->arg);
555                 } else if (printf_tbl[pi->spec].render != NULL) {
556                         pi->sofar = ret;
557                         n = printf_tbl[pi->spec].render(
558                             &io, pi, (const void *)pi->arg);
559                         if (n < 0)
560                                 io.fp->_flags |= __SERR;
561                         else
562                                 ret += n;
563                 } else if (pi->begin == pi->end)
564                         errx(1, "render[%c] = NULL", *fmt);
565         }
566         __printf_flush(&io);
567         return (ret);
568 }
569
570 extern int      __fflush(FILE *fp);
571
572 /*
573  * Helper function for `fprintf to unbuffered unix file': creates a
574  * temporary buffer.  We only work on write-only files; this avoids
575  * worries about ungetc buffers and so forth.
576  */
577 static int
578 __v3printf(FILE *fp, const char *fmt, int pct, va_list ap)
579 {
580         int ret;
581         FILE fake = FAKE_FILE;
582         unsigned char buf[BUFSIZ];
583
584         /* copy the important variables */
585         fake._flags = fp->_flags & ~__SNBF;
586         fake._file = fp->_file;
587         fake._cookie = fp->_cookie;
588         fake._write = fp->_write;
589         fake._orientation = fp->_orientation;
590         fake._mbstate = fp->_mbstate;
591
592         /* set up the buffer */
593         fake._bf._base = fake._p = buf;
594         fake._bf._size = fake._w = sizeof(buf);
595         fake._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._flags & __SERR)
602                 fp->_flags |= __SERR;
603         return (ret);
604 }
605
606 int
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->_flags & (__SNBF|__SWR|__SRW)) == (__SNBF|__SWR) &&
623             fp->_file >= 0)
624                 return (__v3printf(fp, fmt0, u, ap));
625         else
626                 return (__v2printf(fp, fmt0, u, ap));
627 }
628
629 /* extending ---------------------------------------------------------*/
630
631 int
632 register_printf_function(int spec, printf_function *render, printf_arginfo_function *arginfo)
633 {
634
635         if (spec > 255 || spec < 0)
636                 return (-1);
637         printf_tbl[spec].gnurender = render;
638         printf_tbl[spec].arginfo = arginfo;
639         __use_xprintf = 1;
640         return (0);
641 }
642
643 int
644 register_printf_render(int spec, printf_render *render, printf_arginfo_function *arginfo)
645 {
646
647         if (spec > 255 || spec < 0)
648                 return (-1);
649         printf_tbl[spec].render = render;
650         printf_tbl[spec].arginfo = arginfo;
651         __use_xprintf = 1;
652         return (0);
653 }
654
655 int
656 register_printf_render_std(const char *specs)
657 {
658
659         for (; *specs != '\0'; specs++) {
660                 switch (*specs) {
661                 case 'H':
662                         register_printf_render(*specs,
663                             __printf_render_hexdump,
664                             __printf_arginfo_hexdump);
665                         break;
666                 case 'M':
667                         register_printf_render(*specs,
668                             __printf_render_errno,
669                             __printf_arginfo_errno);
670                         break;
671                 case 'Q':
672                         register_printf_render(*specs,
673                             __printf_render_quote,
674                             __printf_arginfo_quote);
675                         break;
676                 case 'T':
677                         register_printf_render(*specs,
678                             __printf_render_time,
679                             __printf_arginfo_time);
680                         break;
681                 case 'V':
682                         register_printf_render(*specs,
683                             __printf_render_vis,
684                             __printf_arginfo_vis);
685                         break;
686                 default:
687                         return (-1);
688                 }
689         }
690         return (0);
691 }
692