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