994f99348382a9fb56335fb539352d5dd75f6b05
[gnulib.git] / lib / vasnprintf.c
1 /* vsprintf with automatic memory allocation.
2    Copyright (C) 1999, 2002-2003 Free Software Foundation, Inc.
3
4    This program is free software; you can redistribute it and/or modify
5    it under the terms of the GNU General Public License as published by
6    the Free Software Foundation; either version 2, or (at your option)
7    any later version.
8
9    This program is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12    GNU General Public License for more details.
13
14    You should have received a copy of the GNU General Public License along
15    with this program; if not, write to the Free Software Foundation,
16    Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
17
18 /* Tell glibc's <stdio.h> to provide a prototype for snprintf().
19    This must come before <config.h> because <config.h> may include
20    <features.h>, and once <features.h> has been included, it's too late.  */
21 #ifndef _GNU_SOURCE
22 # define _GNU_SOURCE    1
23 #endif
24
25 #ifdef HAVE_CONFIG_H
26 # include <config.h>
27 #endif
28 #include <alloca.h>
29
30 /* Specification.  */
31 #include "vasnprintf.h"
32
33 #include <stdio.h>      /* snprintf(), sprintf() */
34 #include <stdlib.h>     /* abort(), malloc(), realloc(), free() */
35 #include <string.h>     /* memcpy(), strlen() */
36 #include <errno.h>      /* errno */
37 #include <limits.h>     /* CHAR_BIT */
38 #include <float.h>      /* DBL_MAX_EXP, LDBL_MAX_EXP */
39 #include "printf-parse.h"
40
41 /* For those losing systems which don't have 'alloca' we have to add
42    some additional code emulating it.  */ 
43 #ifdef HAVE_ALLOCA 
44 # define freea(p) /* nothing */
45 #else
46 # define alloca(n) malloc (n) 
47 # define freea(p) free (p) 
48 #endif
49
50 char *
51 vasnprintf (char *resultbuf, size_t *lengthp, const char *format, va_list args)
52 {
53   char_directives d;
54   arguments a;
55
56   if (printf_parse (format, &d, &a) < 0)
57     {
58       errno = EINVAL;
59       return NULL;
60     }
61
62 #define CLEANUP() \
63   free (d.dir);                                                         \
64   if (a.arg)                                                            \
65     free (a.arg);
66
67   if (printf_fetchargs (args, &a) < 0)
68     {
69       CLEANUP ();
70       errno = EINVAL;
71       return NULL;
72     }
73
74   {
75     char *buf =
76       (char *) alloca (7 + d.max_width_length + d.max_precision_length + 6);
77     const char *cp;
78     unsigned int i;
79     char_directive *dp;
80     /* Output string accumulator.  */
81     char *result;
82     size_t allocated;
83     size_t length;
84
85     if (resultbuf != NULL)
86       {
87         result = resultbuf;
88         allocated = *lengthp;
89       }
90     else
91       {
92         result = NULL;
93         allocated = 0;
94       }
95     length = 0;
96     /* Invariants:
97        result is either == resultbuf or == NULL or malloc-allocated.
98        If length > 0, then result != NULL.  */
99
100 #define ENSURE_ALLOCATION(needed) \
101     if ((needed) > allocated)                                           \
102       {                                                                 \
103         char *memory;                                                   \
104                                                                         \
105         allocated = (allocated > 0 ? 2 * allocated : 12);               \
106         if ((needed) > allocated)                                       \
107           allocated = (needed);                                         \
108         if (result == resultbuf || result == NULL)                      \
109           memory = (char *) malloc (allocated);                         \
110         else                                                            \
111           memory = (char *) realloc (result, allocated);                \
112                                                                         \
113         if (memory == NULL)                                             \
114           {                                                             \
115             if (!(result == resultbuf || result == NULL))               \
116               free (result);                                            \
117             freea (buf);                                                \
118             CLEANUP ();                                                 \
119             errno = ENOMEM;                                             \
120             return NULL;                                                \
121           }                                                             \
122         if (result == resultbuf && length > 0)                          \
123           memcpy (memory, result, length);                              \
124         result = memory;                                                \
125       }
126
127     for (cp = format, i = 0, dp = &d.dir[0]; ; cp = dp->dir_end, i++, dp++)
128       {
129         if (cp != dp->dir_start)
130           {
131             size_t n = dp->dir_start - cp;
132
133             ENSURE_ALLOCATION (length + n);
134             memcpy (result + length, cp, n);
135             length += n;
136           }
137         if (i == d.count)
138           break;
139
140         /* Execute a single directive.  */
141         if (dp->conversion == '%')
142           {
143             if (!(dp->arg_index < 0))
144               abort ();
145             ENSURE_ALLOCATION (length + 1);
146             result[length] = '%';
147             length += 1;
148           }
149         else
150           {
151             if (!(dp->arg_index >= 0))
152               abort ();
153
154             if (dp->conversion == 'n')
155               {
156                 switch (a.arg[dp->arg_index].type)
157                   {
158                   case TYPE_COUNT_SCHAR_POINTER:
159                     *a.arg[dp->arg_index].a.a_count_schar_pointer = length;
160                     break;
161                   case TYPE_COUNT_SHORT_POINTER:
162                     *a.arg[dp->arg_index].a.a_count_short_pointer = length;
163                     break;
164                   case TYPE_COUNT_INT_POINTER:
165                     *a.arg[dp->arg_index].a.a_count_int_pointer = length;
166                     break;
167                   case TYPE_COUNT_LONGINT_POINTER:
168                     *a.arg[dp->arg_index].a.a_count_longint_pointer = length;
169                     break;
170 #ifdef HAVE_LONG_LONG
171                   case TYPE_COUNT_LONGLONGINT_POINTER:
172                     *a.arg[dp->arg_index].a.a_count_longlongint_pointer = length;
173                     break;
174 #endif
175                   default:
176                     abort ();
177                   }
178               }
179             else
180               {
181                 arg_type type = a.arg[dp->arg_index].type;
182                 char *p;
183                 unsigned int prefix_count;
184                 int prefixes[2];
185 #if !HAVE_SNPRINTF
186                 unsigned int tmp_length;
187                 char tmpbuf[700];
188                 char *tmp;
189
190                 /* Allocate a temporary buffer of sufficient size for calling
191                    sprintf.  */
192                 {
193                   unsigned int width;
194                   unsigned int precision;
195
196                   width = 0;
197                   if (dp->width_start != dp->width_end)
198                     {
199                       if (dp->width_arg_index >= 0)
200                         {
201                           int arg;
202
203                           if (!(a.arg[dp->width_arg_index].type == TYPE_INT))
204                             abort ();
205                           arg = a.arg[dp->width_arg_index].a.a_int;
206                           width = (arg < 0 ? -arg : arg);
207                         }
208                       else
209                         {
210                           const char *digitp = dp->width_start;
211
212                           do
213                             width = width * 10 + (*digitp++ - '0');
214                           while (digitp != dp->width_end);
215                         }
216                     }
217
218                   precision = 6;
219                   if (dp->precision_start != dp->precision_end)
220                     {
221                       if (dp->precision_arg_index >= 0)
222                         {
223                           int arg;
224
225                           if (!(a.arg[dp->precision_arg_index].type == TYPE_INT))
226                             abort ();
227                           arg = a.arg[dp->precision_arg_index].a.a_int;
228                           precision = (arg < 0 ? 0 : arg);
229                         }
230                       else
231                         {
232                           const char *digitp = dp->precision_start + 1;
233
234                           precision = 0;
235                           do
236                             precision = precision * 10 + (*digitp++ - '0');
237                           while (digitp != dp->precision_end);
238                         }
239                     }
240
241                   switch (dp->conversion)
242                     {
243
244                     case 'd': case 'i': case 'u':
245 # ifdef HAVE_LONG_LONG
246                       if (type == TYPE_LONGLONGINT || type == TYPE_ULONGLONGINT)
247                         tmp_length =
248                           (unsigned int) (sizeof (unsigned long long) * CHAR_BIT
249                                           * 0.30103 /* binary -> decimal */
250                                           * 2 /* estimate for FLAG_GROUP */
251                                          )
252                           + 1 /* turn floor into ceil */
253                           + 1; /* account for leading sign */
254                       else
255 # endif
256                       if (type == TYPE_LONGINT || type == TYPE_ULONGINT)
257                         tmp_length =
258                           (unsigned int) (sizeof (unsigned long) * CHAR_BIT
259                                           * 0.30103 /* binary -> decimal */
260                                           * 2 /* estimate for FLAG_GROUP */
261                                          )
262                           + 1 /* turn floor into ceil */
263                           + 1; /* account for leading sign */
264                       else
265                         tmp_length =
266                           (unsigned int) (sizeof (unsigned int) * CHAR_BIT
267                                           * 0.30103 /* binary -> decimal */
268                                           * 2 /* estimate for FLAG_GROUP */
269                                          )
270                           + 1 /* turn floor into ceil */
271                           + 1; /* account for leading sign */
272                       break;
273
274                     case 'o':
275 # ifdef HAVE_LONG_LONG
276                       if (type == TYPE_LONGLONGINT || type == TYPE_ULONGLONGINT)
277                         tmp_length =
278                           (unsigned int) (sizeof (unsigned long long) * CHAR_BIT
279                                           * 0.333334 /* binary -> octal */
280                                          )
281                           + 1 /* turn floor into ceil */
282                           + 1; /* account for leading sign */
283                       else
284 # endif
285                       if (type == TYPE_LONGINT || type == TYPE_ULONGINT)
286                         tmp_length =
287                           (unsigned int) (sizeof (unsigned long) * CHAR_BIT
288                                           * 0.333334 /* binary -> octal */
289                                          )
290                           + 1 /* turn floor into ceil */
291                           + 1; /* account for leading sign */
292                       else
293                         tmp_length =
294                           (unsigned int) (sizeof (unsigned int) * CHAR_BIT
295                                           * 0.333334 /* binary -> octal */
296                                          )
297                           + 1 /* turn floor into ceil */
298                           + 1; /* account for leading sign */
299                       break;
300
301                     case 'x': case 'X':
302 # ifdef HAVE_LONG_LONG
303                       if (type == TYPE_LONGLONGINT || type == TYPE_ULONGLONGINT)
304                         tmp_length =
305                           (unsigned int) (sizeof (unsigned long long) * CHAR_BIT
306                                           * 0.25 /* binary -> hexadecimal */
307                                          )
308                           + 1 /* turn floor into ceil */
309                           + 2; /* account for leading sign or alternate form */
310                       else
311 # endif
312                       if (type == TYPE_LONGINT || type == TYPE_ULONGINT)
313                         tmp_length =
314                           (unsigned int) (sizeof (unsigned long) * CHAR_BIT
315                                           * 0.25 /* binary -> hexadecimal */
316                                          )
317                           + 1 /* turn floor into ceil */
318                           + 2; /* account for leading sign or alternate form */
319                       else
320                         tmp_length =
321                           (unsigned int) (sizeof (unsigned int) * CHAR_BIT
322                                           * 0.25 /* binary -> hexadecimal */
323                                          )
324                           + 1 /* turn floor into ceil */
325                           + 2; /* account for leading sign or alternate form */
326                       break;
327
328                     case 'f': case 'F':
329 # ifdef HAVE_LONG_DOUBLE
330                       if (type == TYPE_LONGDOUBLE)
331                         tmp_length =
332                           (unsigned int) (LDBL_MAX_EXP
333                                           * 0.30103 /* binary -> decimal */
334                                           * 2 /* estimate for FLAG_GROUP */
335                                          )
336                           + 1 /* turn floor into ceil */
337                           + precision
338                           + 10; /* sign, decimal point etc. */
339                       else
340 # endif
341                         tmp_length =
342                           (unsigned int) (DBL_MAX_EXP
343                                           * 0.30103 /* binary -> decimal */
344                                           * 2 /* estimate for FLAG_GROUP */
345                                          )
346                           + 1 /* turn floor into ceil */
347                           + precision
348                           + 10; /* sign, decimal point etc. */
349                       break;
350
351                     case 'e': case 'E': case 'g': case 'G':
352                     case 'a': case 'A':
353                       tmp_length =
354                         precision
355                         + 12; /* sign, decimal point, exponent etc. */
356                       break;
357
358                     case 'c':
359 # ifdef HAVE_WINT_T
360                       if (type == TYPE_WIDE_CHAR)
361                         tmp_length = MB_CUR_MAX;
362                       else
363 # endif
364                         tmp_length = 1;
365                       break;
366
367                     case 's':
368 # ifdef HAVE_WCHAR_T
369                       if (type == TYPE_WIDE_STRING)
370                         tmp_length =
371                           wcslen (a.arg[dp->arg_index].a.a_wide_string)
372                           * MB_CUR_MAX;
373                       else
374 # endif
375                         tmp_length = strlen (a.arg[dp->arg_index].a.a_string);
376                       break;
377
378                     case 'p':
379                       tmp_length =
380                         (unsigned int) (sizeof (void *) * CHAR_BIT
381                                         * 0.25 /* binary -> hexadecimal */
382                                        )
383                           + 1 /* turn floor into ceil */
384                           + 2; /* account for leading 0x */
385                       break;
386
387                     default:
388                       abort ();
389                     }
390
391                   if (tmp_length < width)
392                     tmp_length = width;
393
394                   tmp_length++; /* account for trailing NUL */
395                 }
396
397                 if (tmp_length <= sizeof (tmpbuf))
398                   tmp = tmpbuf;
399                 else
400                   {
401                     tmp = (char *) malloc (tmp_length);
402                     if (tmp == NULL)
403                       {
404                         /* Out of memory.  */
405                         if (!(result == resultbuf || result == NULL))
406                           free (result);
407                         freea (buf);
408                         CLEANUP ();
409                         errno = ENOMEM;
410                         return NULL;
411                       }
412                   }
413 #endif
414
415                 /* Construct the format string for calling snprintf or
416                    sprintf.  */
417                 p = buf;
418                 *p++ = '%';
419                 if (dp->flags & FLAG_GROUP)
420                   *p++ = '\'';
421                 if (dp->flags & FLAG_LEFT)
422                   *p++ = '-';
423                 if (dp->flags & FLAG_SHOWSIGN)
424                   *p++ = '+';
425                 if (dp->flags & FLAG_SPACE)
426                   *p++ = ' ';
427                 if (dp->flags & FLAG_ALT)
428                   *p++ = '#';
429                 if (dp->flags & FLAG_ZERO)
430                   *p++ = '0';
431                 if (dp->width_start != dp->width_end)
432                   {
433                     size_t n = dp->width_end - dp->width_start;
434                     memcpy (p, dp->width_start, n);
435                     p += n;
436                   }
437                 if (dp->precision_start != dp->precision_end)
438                   {
439                     size_t n = dp->precision_end - dp->precision_start;
440                     memcpy (p, dp->precision_start, n);
441                     p += n;
442                   }
443
444                 switch (type)
445                   {
446 #ifdef HAVE_LONG_LONG
447                   case TYPE_LONGLONGINT:
448                   case TYPE_ULONGLONGINT:
449                     *p++ = 'l';
450                     /*FALLTHROUGH*/
451 #endif
452                   case TYPE_LONGINT:
453                   case TYPE_ULONGINT:
454 #ifdef HAVE_WINT_T
455                   case TYPE_WIDE_CHAR:
456 #endif
457 #ifdef HAVE_WCHAR_T
458                   case TYPE_WIDE_STRING:
459 #endif
460                     *p++ = 'l';
461                     break;
462 #ifdef HAVE_LONG_DOUBLE
463                   case TYPE_LONGDOUBLE:
464                     *p++ = 'L';
465                     break;
466 #endif
467                   default:
468                     break;
469                   }
470                 *p = dp->conversion;
471 #if HAVE_SNPRINTF
472                 p[1] = '%';
473                 p[2] = 'n';
474                 p[3] = '\0';
475 #else
476                 p[1] = '\0';
477 #endif
478
479                 /* Construct the arguments for calling snprintf or sprintf.  */
480                 prefix_count = 0;
481                 if (dp->width_arg_index >= 0)
482                   {
483                     if (!(a.arg[dp->width_arg_index].type == TYPE_INT))
484                       abort ();
485                     prefixes[prefix_count++] = a.arg[dp->width_arg_index].a.a_int;
486                   }
487                 if (dp->precision_arg_index >= 0)
488                   {
489                     if (!(a.arg[dp->precision_arg_index].type == TYPE_INT))
490                       abort ();
491                     prefixes[prefix_count++] = a.arg[dp->precision_arg_index].a.a_int;
492                   }
493
494 #if HAVE_SNPRINTF
495                 /* Prepare checking whether snprintf returns the count
496                    via %n.  */
497                 ENSURE_ALLOCATION (length + 1);
498                 result[length] = '\0';
499 #endif
500
501                 for (;;)
502                   {
503                     size_t maxlen;
504                     int count;
505                     int retcount;
506
507                     maxlen = allocated - length;
508                     count = -1;
509                     retcount = 0;
510
511 #if HAVE_SNPRINTF
512 #define SNPRINTF_BUF(arg) \
513                     switch (prefix_count)                                   \
514                       {                                                     \
515                       case 0:                                               \
516                         retcount = snprintf (result + length, maxlen, buf,  \
517                                              arg, &count);                  \
518                         break;                                              \
519                       case 1:                                               \
520                         retcount = snprintf (result + length, maxlen, buf,  \
521                                              prefixes[0], arg, &count);     \
522                         break;                                              \
523                       case 2:                                               \
524                         retcount = snprintf (result + length, maxlen, buf,  \
525                                              prefixes[0], prefixes[1], arg, \
526                                              &count);                       \
527                         break;                                              \
528                       default:                                              \
529                         abort ();                                           \
530                       }
531 #else
532 #define SNPRINTF_BUF(arg) \
533                     switch (prefix_count)                                   \
534                       {                                                     \
535                       case 0:                                               \
536                         count = sprintf (tmp, buf, arg);                    \
537                         break;                                              \
538                       case 1:                                               \
539                         count = sprintf (tmp, buf, prefixes[0], arg);       \
540                         break;                                              \
541                       case 2:                                               \
542                         count = sprintf (tmp, buf, prefixes[0], prefixes[1],\
543                                          arg);                              \
544                         break;                                              \
545                       default:                                              \
546                         abort ();                                           \
547                       }
548 #endif
549
550                     switch (type)
551                       {
552                       case TYPE_SCHAR:
553                         {
554                           int arg = a.arg[dp->arg_index].a.a_schar;
555                           SNPRINTF_BUF (arg);
556                         }
557                         break;
558                       case TYPE_UCHAR:
559                         {
560                           unsigned int arg = a.arg[dp->arg_index].a.a_uchar;
561                           SNPRINTF_BUF (arg);
562                         }
563                         break;
564                       case TYPE_SHORT:
565                         {
566                           int arg = a.arg[dp->arg_index].a.a_short;
567                           SNPRINTF_BUF (arg);
568                         }
569                         break;
570                       case TYPE_USHORT:
571                         {
572                           unsigned int arg = a.arg[dp->arg_index].a.a_ushort;
573                           SNPRINTF_BUF (arg);
574                         }
575                         break;
576                       case TYPE_INT:
577                         {
578                           int arg = a.arg[dp->arg_index].a.a_int;
579                           SNPRINTF_BUF (arg);
580                         }
581                         break;
582                       case TYPE_UINT:
583                         {
584                           unsigned int arg = a.arg[dp->arg_index].a.a_uint;
585                           SNPRINTF_BUF (arg);
586                         }
587                         break;
588                       case TYPE_LONGINT:
589                         {
590                           long int arg = a.arg[dp->arg_index].a.a_longint;
591                           SNPRINTF_BUF (arg);
592                         }
593                         break;
594                       case TYPE_ULONGINT:
595                         {
596                           unsigned long int arg = a.arg[dp->arg_index].a.a_ulongint;
597                           SNPRINTF_BUF (arg);
598                         }
599                         break;
600 #ifdef HAVE_LONG_LONG
601                       case TYPE_LONGLONGINT:
602                         {
603                           long long int arg = a.arg[dp->arg_index].a.a_longlongint;
604                           SNPRINTF_BUF (arg);
605                         }
606                         break;
607                       case TYPE_ULONGLONGINT:
608                         {
609                           unsigned long long int arg = a.arg[dp->arg_index].a.a_ulonglongint;
610                           SNPRINTF_BUF (arg);
611                         }
612                         break;
613 #endif
614                       case TYPE_DOUBLE:
615                         {
616                           double arg = a.arg[dp->arg_index].a.a_double;
617                           SNPRINTF_BUF (arg);
618                         }
619                         break;
620 #ifdef HAVE_LONG_DOUBLE
621                       case TYPE_LONGDOUBLE:
622                         {
623                           long double arg = a.arg[dp->arg_index].a.a_longdouble;
624                           SNPRINTF_BUF (arg);
625                         }
626                         break;
627 #endif
628                       case TYPE_CHAR:
629                         {
630                           int arg = a.arg[dp->arg_index].a.a_char;
631                           SNPRINTF_BUF (arg);
632                         }
633                         break;
634 #ifdef HAVE_WINT_T
635                       case TYPE_WIDE_CHAR:
636                         {
637                           wint_t arg = a.arg[dp->arg_index].a.a_wide_char;
638                           SNPRINTF_BUF (arg);
639                         }
640                         break;
641 #endif
642                       case TYPE_STRING:
643                         {
644                           const char *arg = a.arg[dp->arg_index].a.a_string;
645                           SNPRINTF_BUF (arg);
646                         }
647                         break;
648 #ifdef HAVE_WCHAR_T
649                       case TYPE_WIDE_STRING:
650                         {
651                           const wchar_t *arg = a.arg[dp->arg_index].a.a_wide_string;
652                           SNPRINTF_BUF (arg);
653                         }
654                         break;
655 #endif
656                       case TYPE_POINTER:
657                         {
658                           void *arg = a.arg[dp->arg_index].a.a_pointer;
659                           SNPRINTF_BUF (arg);
660                         }
661                         break;
662                       default:
663                         abort ();
664                       }
665
666 #if HAVE_SNPRINTF
667                     /* Portability: Not all implementations of snprintf()
668                        are ISO C 99 compliant.  Determine the number of
669                        bytes that snprintf() has produced or would have
670                        produced.  */
671                     if (count >= 0)
672                       {
673                         /* Verify that snprintf() has NUL-terminated its
674                            result.  */
675                         if (count < maxlen && result[length + count] != '\0')
676                           abort ();
677                         /* Portability hack.  */
678                         if (retcount > count)
679                           count = retcount;
680                       }
681                     else
682                       {
683                         /* snprintf() doesn't understand the '%n'
684                            directive.  */
685                         if (p[1] != '\0')
686                           {
687                             /* Don't use the '%n' directive; instead, look
688                                at the snprintf() return value.  */
689                             p[1] = '\0';
690                             continue;
691                           }
692                         count = retcount;
693                       }
694 #endif
695
696                     /* Attempt to handle failure.  */
697                     if (count < 0)
698                       {
699                         if (!(result == resultbuf || result == NULL))
700                           free (result);
701                         freea (buf);
702                         CLEANUP ();
703                         errno = EINVAL;
704                         return NULL;
705                       }
706
707 #if !HAVE_SNPRINTF
708                     if (count >= tmp_length)
709                       /* tmp_length was incorrectly calculated - fix the
710                          code above!  */
711                       abort ();
712 #endif
713
714                     /* Make room for the result.  */
715                     if (count >= maxlen)
716                       {
717                         /* Need at least count bytes.  But allocate
718                            proportionally, to avoid looping eternally if
719                            snprintf() reports a too small count.  */
720                         size_t n = length + count;
721
722                         if (n < 2 * allocated)
723                           n = 2 * allocated;
724
725                         ENSURE_ALLOCATION (n);
726 #if HAVE_SNPRINTF
727                         continue;
728 #endif
729                       }
730
731 #if HAVE_SNPRINTF
732                     /* The snprintf() result did fit.  */
733 #else
734                     /* Append the sprintf() result.  */
735                     memcpy (result + length, tmp, count);
736                     if (tmp != tmpbuf)
737                       free (tmp);
738 #endif
739
740                     length += count;
741                     break;
742                   }
743               }
744           }
745       }
746
747     /* Add the final NUL.  */
748     ENSURE_ALLOCATION (length + 1);
749     result[length] = '\0';
750
751     if (result != resultbuf && length + 1 < allocated)
752       {
753         /* Shrink the allocated memory if possible.  */
754         char *memory;
755
756         memory = (char *) realloc (result, length + 1);
757         if (memory != NULL)
758           result = memory;
759       }
760
761     freea (buf);
762     CLEANUP ();
763     *lengthp = length;
764     return result;
765   }
766 }