LTP GCOV extension - code coverage report
Current view: directory - src - vstr_add_fmt.c
Test: Vstr coverage
Date: 2005-01-10 Instrumented lines: 810
Code covered: 100.0 % Executed lines: 810

       1                 : #define VSTR_ADD_FMT_C
       2                 : /*
       3                 :  *  Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004  James Antill
       4                 :  *
       5                 :  *  This library is free software; you can redistribute it and/or
       6                 :  *  modify it under the terms of the GNU Lesser General Public
       7                 :  *  License as published by the Free Software Foundation; either
       8                 :  *  version 2 of the License, or (at your option) any later version.
       9                 :  *
      10                 :  *  This library is distributed in the hope that it will be useful,
      11                 :  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
      12                 :  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      13                 :  *  Lesser General Public License for more details.
      14                 :  *
      15                 :  *  You should have received a copy of the GNU Lesser General Public
      16                 :  *  License along with this library; if not, write to the Free Software
      17                 :  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
      18                 :  *
      19                 :  *  email: james@and.org
      20                 : */
      21                 : /* this code is hacked from:
      22                 :  *   vsprintf in linux/lib -- by Lars Wirzenius <liw@iki.fi>
      23                 :  * He gave his permission for it to be released as LGPL.
      24                 :  * ... it's changed a lot since then. */
      25                 : /* functions for portable printf functionality in a vstr -- does C99 std. and
      26                 :  * custom format specifiers (registration via. vstr_fmt.c).
      27                 :  * Has a "portable" implementation of double printing */
      28                 : #include "main.h"
      29                 : 
      30                 : #if !USE_WIDE_CHAR_T
      31                 : # undef wchar_t
      32                 : # define wchar_t int /* doesn't matter ... fails out anyway */
      33                 : # undef wint_t
      34                 : # define wint_t  int /* doesn't matter ... fails out anyway */
      35                 : #endif
      36                 : 
      37                 : 
      38                 : 
      39                 : #define VSTR__ADD_FMT_ISDIGIT(x) (((x) >= '0') && ((x) <= '9'))
      40                 : 
      41                 : #define VSTR__ADD_FMT_CHAR2INT_1(x) ((x) - '0')
      42                 : #define VSTR__ADD_FMT_CHAR2INT_2(x, y) ((((x) - '0') * 10) + \
      43                 :                                          ((y) - '0'))
      44                 : 
      45                 : /* a very small number of digits is _by far_ the norm */
      46                 : #define VSTR__ADD_FMT_STRTOL(x) \
      47                 :  (VSTR__ADD_FMT_ISDIGIT((x)[1]) ? \
      48                 :   VSTR__ADD_FMT_ISDIGIT((x)[2]) ? strtol(x, (char **) &(x), 10) : \
      49                 :   ((x) += 2, VSTR__ADD_FMT_CHAR2INT_2((x)[-2], (x)[-1])) : \
      50                 :   ((x) += 1, VSTR__ADD_FMT_CHAR2INT_1((x)[-1])))
      51                 : 
      52                 : /* 1 byte for the base of the number, can go upto base 255 */
      53                 : #define BASE_MASK ((1 << 8) - 1)
      54                 : 
      55                 : #define ZEROPAD (1 << 8) /* pad with zero */
      56                 : #define SIGN (1 << 9) /* unsigned/signed */
      57                 : #define PLUS (1 << 10) /* show plus sign '+' */
      58                 : #define SPACE (1 << 11) /* space if plus */
      59                 : #define LEFT (1 << 12) /* left justified */
      60                 : #define SPECIAL (1 << 13) /* 0x */
      61                 : #define LARGE (1 << 14) /* use 'ABCDEF' instead of 'abcdef' */
      62                 : #define THOUSAND_SEP (1 << 15) /* split at grouping marks according to locale */
      63                 : #define ALT_DIGITS (1 << 16) /* does nothing in core code, can be used in
      64                 :                               * custom format specifiers */
      65                 : 
      66                 : #define PREC_USR (1 << 28) /* user specified precision */
      67                 : #define NUM_IS_ZERO (1 << 29) /* is the number zero */
      68                 : #define NUM_IS_NEGATIVE (1 << 30) /* is the number negative */
      69                 : 
      70                 : #define VSTR__FMT_ADD(x, y, z) vstr_add_buf((x), ((x)->len - pos_diff), y, z)
      71                 : #define VSTR__FMT_ADD_REP_CHR(x, y, z) \
      72                 :  vstr_add_rep_chr((x), ((x)->len - pos_diff), y, z)
      73                 : #define VSTR__FMT_ADD_GRPBASENUM(x, NB, y, z) \
      74                 :  vstr_sc_add_grpbasenum_buf((x), ((x)->len - pos_diff), NB, y, z)
      75                 : 
      76                 : /* deals well with INT_MIN */
      77                 : #define VSTR__FMT_S2U_NUM(unum, snum) do { \
      78                 :    ++snum; unum = -snum; ++unum; \
      79                 : } while (FALSE)
      80                 : #define VSTR__FMT_ABS_NUM(unum, snum) do { \
      81                 :  if (snum < 0) { \
      82                 :    spec->flags |= NUM_IS_NEGATIVE; \
      83                 :    VSTR__FMT_S2U_NUM(unum, snum); \
      84                 :  } else \
      85                 :    unum = snum; \
      86                 : } while (FALSE)
      87                 : 
      88                 : 
      89                 : /* functions for outputing thousands grouping ... */
      90                 : unsigned int vstr__add_fmt_grouping_mod(const char *grouping, unsigned int num)
      91           74755 : {
      92           74755 :   unsigned int tmp = 0;
      93                 : 
      94           74755 :   if (!*grouping)
      95           47020 :     return (num);
      96                 : 
      97        10895727 :   while (((unsigned char)*grouping < SCHAR_MAX) &&
      98                 :          ((tmp + *grouping) < num))
      99                 :   {
     100        10867992 :     tmp += *grouping;
     101        10867992 :     if (grouping[1])
     102           15882 :       ++grouping;
     103                 :   }
     104                 : 
     105           27735 :   return (num - tmp);
     106                 : }
     107                 : 
     108                 : size_t vstr__add_fmt_grouping_num_sz(Vstr_base *base,
     109                 :                                      unsigned int num_base, size_t len)
     110            4485 : {
     111            4485 :   size_t ret = 0;
     112            4485 :   int done = FALSE;
     113            4485 :   Vstr_locale *loc = base->conf->loc;
     114            4485 :   const char *grouping = vstr__loc_num_grouping(loc, num_base);
     115            4485 :   size_t sep_len = vstr__loc_num_sep_len(loc, num_base);
     116                 :   
     117           11514 :   while (len)
     118                 :   {
     119            7029 :     unsigned int num = vstr__add_fmt_grouping_mod(grouping, len);
     120                 : 
     121            7029 :     if (done)
     122            2726 :       ret += sep_len;
     123                 : 
     124            7029 :     ret += num;
     125            7029 :     assert(num <= len);
     126            7029 :     len -= num;
     127                 : 
     128            7029 :     done = TRUE;
     129                 :   }
     130                 : 
     131            4485 :   return (ret);
     132                 : }
     133                 : 
     134                 : 
     135                 : struct Vstr__fmt_spec
     136                 : {
     137                 :  union Vstr__fmt_sp_un
     138                 :  {
     139                 :   unsigned char data_c;
     140                 :   unsigned short data_s;
     141                 :   unsigned int data_i;
     142                 :   wint_t data_wint;
     143                 :   unsigned long data_l;
     144                 :   Vstr__unsigned_long_long data_L;
     145                 :   size_t data_sz;
     146                 :   uintmax_t data_m;
     147                 : 
     148                 :   double data_d;
     149                 :   long double data_Ld;
     150                 : 
     151                 :   void *data_ptr;
     152                 :  } u;
     153                 : 
     154                 :  ptrdiff_t data_t; /* NOTE: no uptrdiff_t, but need real ptrdiff_t for
     155                 :                     * custom formatters. So normal uintmax_t */
     156                 :  
     157                 :  unsigned char fmt_code;
     158                 :  int num_base;
     159                 :  unsigned int int_type;
     160                 :  unsigned int flags;
     161                 :  unsigned int field_width;
     162                 :  unsigned int precision;
     163                 : 
     164                 :  unsigned int main_param;
     165                 :  unsigned int field_width_param;
     166                 :  unsigned int precision_param;
     167                 : 
     168                 :  Vstr__fmt_usr_name_node *usr_spec;
     169                 : 
     170                 :  /* these two needed for double, not used elsewhere */
     171                 :  /* unsigned int precision_usr : 1; done with the PREC_USR flag */
     172                 :  unsigned int field_width_usr : 1; /* did the usr specify a field width */
     173                 :  unsigned int escape_usr : 1;  /* did the usr specify this escape */
     174                 : 
     175                 :  struct Vstr__fmt_spec *next;
     176                 : };
     177                 : 
     178                 : static int vstr__add_fmt_number(Vstr_base *base, size_t pos_diff,
     179                 :                                 struct Vstr__fmt_spec *spec)
     180          167655 : {
     181          167655 :   char sign = 0;
     182                 :   /* used to hold the actual number */
     183          167655 :   char buf_beg[BUF_NUM_TYPE_SZ(uintmax_t)];
     184          167655 :   char *buf = buf_beg + sizeof(buf_beg);
     185          167655 :   size_t i = 0;
     186          167655 :   size_t real_i = 0;
     187                 :   /* can't make array */
     188          167655 :   const char *chrs_base = "0123456789abcdefghijklmnopqrstuvwxyz";
     189          167655 :   const char *grouping = NULL;
     190          167655 :   unsigned char grp_num = 0;
     191          167655 :   const char *thou = NULL;
     192          167655 :   size_t thou_len = 0;
     193          167655 :   size_t max_p_i = 0;
     194          167655 :   unsigned int field_width = 0;
     195          167655 :   unsigned int precision = 1;
     196          167655 :   unsigned int wr_hex_0x = FALSE;
     197                 : 
     198          167655 :   if (spec->flags & PREC_USR)
     199           30912 :     precision = spec->precision;
     200                 : 
     201          167655 :   if (spec->field_width_usr)
     202           67031 :     field_width = spec->field_width;
     203                 :   
     204                 :   /* if the usr specified a precision the '0' flag is ignored */
     205          167655 :   if (spec->flags & PREC_USR)
     206           30912 :     spec->flags &= ~ZEROPAD;
     207                 :   
     208          167655 :   if (spec->flags & LARGE)
     209           12932 :     chrs_base = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
     210                 : 
     211          167655 :   if (spec->flags & LEFT)
     212           12013 :     spec->flags &= ~ZEROPAD;
     213                 : 
     214          167655 :   switch (spec->num_base)
     215                 :   {
     216                 :     case 10:
     217                 :     case 16:
     218                 :     case  8:
     219                 : 
     220          123387 :     ASSERT_NO_SWITCH_DEF();
     221                 :   }
     222                 :   
     223          167655 :   if (spec->flags & SIGN)
     224                 :   {
     225           25334 :     if (spec->flags & NUM_IS_NEGATIVE)
     226            6093 :       sign = '-';
     227                 :     else
     228                 :     {
     229           19241 :       if (spec->flags & PLUS)
     230            1870 :         sign = '+';
     231                 :       else
     232           17371 :         if (spec->flags & SPACE)
     233            2090 :           sign = ' ';
     234                 :         else
     235           15281 :           ++field_width;
     236                 :     }
     237                 :     
     238           25334 :     if (field_width) --field_width;
     239                 :   }
     240                 : 
     241          167655 :   grouping = vstr__loc_num_grouping(base->conf->loc, spec->num_base);
     242          167655 :   thou_len = vstr__loc_num_sep_len(base->conf->loc, spec->num_base);
     243          167655 :   thou     = vstr__loc_num_sep_ptr(base->conf->loc, spec->num_base);
     244                 : 
     245          167655 :   grp_num = *grouping;
     246          167655 :   if (!thou_len || (grp_num >= SCHAR_MAX) || (grp_num <= 0))
     247          153304 :     spec->flags &= ~THOUSAND_SEP; /* don't do it */
     248                 : 
     249          167655 :   switch (spec->int_type)
     250                 :   {
     251                 :     case VSTR_TYPE_FMT_UCHAR:
     252             170 :       VSTR__ADD_FMT_NUM(unsigned char, spec->u.data_c, spec->num_base);  break;
     253                 :     case VSTR_TYPE_FMT_USHORT:
     254             159 :       VSTR__ADD_FMT_NUM(unsigned short, spec->u.data_s, spec->num_base); break;
     255                 :     case VSTR_TYPE_FMT_UINT:
     256           92985 :       VSTR__ADD_FMT_NUM(unsigned int, spec->u.data_i, spec->num_base);   break;
     257                 :     case VSTR_TYPE_FMT_ULONG:
     258            5124 :       VSTR__ADD_FMT_NUM(unsigned long, spec->u.data_l, spec->num_base);  break;
     259                 :     case VSTR_TYPE_FMT_ULONG_LONG:
     260              66 :       VSTR__ADD_FMT_NUM(Vstr__unsigned_long_long, spec->u.data_L,
     261                 :                         spec->num_base);                                 break;
     262                 :     case VSTR_TYPE_FMT_SIZE_T:
     263             141 :       VSTR__ADD_FMT_NUM(size_t, spec->u.data_sz, spec->num_base);        break;
     264                 :       /* ptrdiff_t is actually promoted to intmax_t so that unsigned works */
     265                 :     case VSTR_TYPE_FMT_UINTMAX_T:
     266           69005 :       VSTR__ADD_FMT_NUM(uintmax_t, spec->u.data_m, spec->num_base);      break;
     267                 :     case VSTR_TYPE_FMT_PTR_VOID:
     268               5 :       VSTR__ADD_FMT_NUM(uintptr_t, (uintptr_t)spec->u.data_ptr, spec->num_base);
     269          123387 :     ASSERT_NO_SWITCH_DEF(); /* only valid types above */
     270                 :   }
     271                 :   
     272          167655 :   i = sizeof(buf_beg) - (buf - buf_beg);
     273                 :   
     274          167655 :   real_i = i;
     275          167655 :   if (spec->flags & THOUSAND_SEP)
     276            1601 :     real_i = vstr__add_fmt_grouping_num_sz(base, spec->num_base, i);
     277                 : 
     278          167655 :   if (spec->flags & SPECIAL)
     279                 :   {
     280           20415 :     if ((spec->num_base == 16) && !(spec->flags & NUM_IS_ZERO))
     281                 :     { /* only append 0x if it is a non-zero value, but not if precision == 0 */
     282            6495 :       wr_hex_0x = TRUE;
     283            6495 :       if (field_width) --field_width;
     284            6495 :       if (field_width) --field_width;
     285                 :     }
     286                 :     else
     287                 :     { /* hacky spec, if octal then we up the precision so that a 0 is printed as
     288                 :        * the first character, if there isn't a 0 there to start with
     289                 :        * -- even if num == 0 and precision == 0 */
     290           13920 :       if ((spec->num_base == 8) &&
     291                 :           (((spec->flags & NUM_IS_ZERO) && !precision) ||
     292                 :            (precision <= real_i)))
     293            5053 :         precision = real_i + 1;
     294                 :     }
     295                 :   }
     296                 :   
     297          167655 :   if (real_i > precision)
     298          130743 :     max_p_i = real_i;
     299                 :   else
     300           36912 :     max_p_i = precision;
     301                 :   
     302          167655 :   if (field_width < max_p_i)
     303          111246 :     field_width = 0;
     304                 :   else
     305           56409 :     field_width -= max_p_i;
     306                 :   
     307          167655 :   if (!(spec->flags & (ZEROPAD | LEFT)))
     308          112921 :     if (field_width > 0)
     309                 :     { /* right justify number, with spaces -- zeros done after sign/spacials */
     310            8673 :       if (!VSTR__FMT_ADD_REP_CHR(base, ' ', field_width))
     311              44 :         goto failed_alloc;
     312            8629 :       field_width = 0;
     313                 :     }
     314                 :   
     315          167611 :   if (sign)
     316           10032 :     if (!VSTR__FMT_ADD_REP_CHR(base, sign, 1))
     317               3 :       goto failed_alloc;
     318                 :   
     319          167608 :   if (spec->flags & SPECIAL)
     320                 :   {
     321           20382 :     if (wr_hex_0x)
     322                 :     {
     323            6489 :       if (!VSTR__FMT_ADD_REP_CHR(base, '0', 1))
     324               2 :         goto failed_alloc;
     325            6487 :       if (!VSTR__FMT_ADD_REP_CHR(base, chrs_base[33], 1))
     326               2 :         goto failed_alloc;
     327                 :     }
     328                 :   }
     329                 :   
     330          167604 :   if (!(spec->flags & LEFT))
     331          155591 :     if (field_width > 0)
     332                 :     { /* right justify number, with zeros */
     333            6368 :       assert(spec->flags & ZEROPAD);
     334            6368 :       if (!VSTR__FMT_ADD_REP_CHR(base, '0', field_width))
     335              16 :         goto failed_alloc;
     336            6352 :       field_width = 0;
     337                 :     }
     338                 :   
     339          167588 :   if (precision > real_i) /* make number the desired length */
     340                 :   {
     341           20314 :    if (!VSTR__FMT_ADD_REP_CHR(base, '0', precision - real_i))
     342              94 :      goto failed_alloc;
     343                 :   }
     344                 : 
     345          167494 :   if (i)
     346                 :   {
     347          159459 :     int ret = FALSE;
     348                 :     
     349                 :     /* output number */
     350          159459 :     if (spec->flags & THOUSAND_SEP)
     351            1419 :       ret = VSTR__FMT_ADD_GRPBASENUM(base, spec->num_base, buf, i);
     352                 :     else
     353          158040 :       ret = VSTR__FMT_ADD(base, buf, i);
     354                 :     
     355          159459 :     if (!ret)
     356             279 :       goto failed_alloc;
     357                 :   }
     358                 : 
     359          167215 :   if (field_width > 0)
     360                 :   {
     361            5131 :     assert(spec->flags & LEFT);
     362            5131 :     if (!VSTR__FMT_ADD_REP_CHR(base, ' ', field_width))
     363              55 :       goto failed_alloc;
     364                 :   }
     365                 : 
     366          167160 :   return (TRUE);
     367                 : 
     368                 :  failed_alloc:
     369             495 :   return (FALSE);
     370                 : }
     371                 : 
     372                 : void vstr__add_fmt_free_conf(Vstr_conf *conf)
     373            6057 : {
     374            6057 :   struct Vstr__fmt_spec *scan = conf->vstr__fmt_spec_make;
     375                 : 
     376           10019 :   assert(!conf->vstr__fmt_spec_list_beg && !conf->vstr__fmt_spec_list_beg);
     377                 : 
     378           11218 :   while (scan)
     379                 :   {
     380            5161 :     struct Vstr__fmt_spec *scan_next = scan->next;
     381            5161 :     VSTR__F(scan);
     382            5161 :     scan = scan_next;
     383                 :   }
     384                 : 
     385            6057 :   conf->vstr__fmt_spec_make = NULL;
     386                 : 
     387           61893 :   while (conf->fmt_usr_names)
     388                 :   {
     389           55836 :     Vstr__fmt_usr_name_node *tmp = conf->fmt_usr_names;
     390                 : 
     391           55836 :     vstr_fmt_del(conf, tmp->name_str);
     392                 :   }
     393                 : }
     394                 : 
     395                 : static int vstr__fmt_add_spec(Vstr_conf *conf)
     396            5763 : {
     397            5763 :   struct Vstr__fmt_spec *spec = NULL;
     398                 : 
     399            5763 :   if (!(spec = VSTR__MK(sizeof(struct Vstr__fmt_spec))))
     400              42 :     return (FALSE);
     401                 : 
     402            5721 :   assert(vstr_wrap_memset(spec, 0xeF, sizeof(struct Vstr__fmt_spec)));
     403                 : 
     404            5721 :   spec->next = conf->vstr__fmt_spec_make;
     405            5721 :   conf->vstr__fmt_spec_make = spec;
     406                 : 
     407            5721 :   return (TRUE);
     408                 : }
     409                 : 
     410                 : #define VSTR__FMT_MV_SPEC(conf, x) vstr__fmt_mv_spec(conf, spec, x, &params)
     411                 : static void vstr__fmt_mv_spec(Vstr_conf *conf, struct Vstr__fmt_spec *spec,
     412                 :                               int main_param, unsigned int *params)
     413         1513017 : {
     414         1513017 :   conf->vstr__fmt_spec_make = spec->next;
     415                 : 
     416         1513017 :   if (!conf->vstr__fmt_spec_list_beg)
     417                 :   {
     418          253504 :     conf->vstr__fmt_spec_list_end = spec;
     419          253504 :     conf->vstr__fmt_spec_list_beg = spec;
     420                 :   }
     421                 :   else
     422                 :   {
     423         1259513 :     conf->vstr__fmt_spec_list_end->next = spec;
     424         1259513 :     conf->vstr__fmt_spec_list_end = spec;
     425                 :   }
     426                 : 
     427         1513017 :   spec->next = NULL;
     428                 : 
     429                 :   /* increment if this counts towards users $x numbers */
     430         1513017 :   if (main_param && !spec->main_param)
     431          895695 :     spec->main_param = ++*params;
     432                 : }
     433                 : 
     434                 : # define VSTR__FMT_ANAL_ZERO 1 /* anally zero stuff that shouldn't really need
     435                 :                                 * it but seems to *sigh*/
     436                 : static void vstr__fmt_init_spec(struct Vstr__fmt_spec *spec)
     437         1513029 : {
     438         1513029 :   assert(spec);
     439                 : 
     440         1513029 :   if (VSTR__FMT_ANAL_ZERO)
     441                 :   {
     442         1513029 :     spec->u.data_ptr = NULL;
     443                 :   }
     444                 : 
     445         1513029 :   spec->fmt_code = 0;
     446         1513029 :   spec->num_base = 10;
     447         1513029 :   spec->int_type = VSTR_TYPE_FMT_UINT;
     448         1513029 :   spec->flags = 0;
     449                 : 
     450         1513029 :   if (VSTR__FMT_ANAL_ZERO)
     451                 :   {
     452         1513029 :     spec->precision = 0;
     453         1513029 :     spec->field_width = 0;
     454                 :   }
     455                 : 
     456         1513029 :   spec->main_param = 0;
     457         1513029 :   spec->field_width_param = 0;
     458         1513029 :   spec->precision_param = 0;
     459                 : 
     460         1513029 :   spec->usr_spec = NULL;
     461                 : 
     462         1513029 :   spec->field_width_usr = FALSE;
     463         1513029 :   spec->escape_usr = FALSE;
     464                 : }
     465                 : 
     466                 : /* must match with code in vstr_version.c */
     467                 : #if defined(VSTR_AUTOCONF_FMT_DBL_glibc)
     468                 : # include "vstr_dbl/vstr_add_fmt_dbl_glibc.c"
     469                 : #elif defined(VSTR_AUTOCONF_FMT_DBL_none)
     470                 : # include "vstr_dbl/vstr_add_fmt_dbl_none.c"
     471                 : #elif defined(VSTR_AUTOCONF_FMT_DBL_host)
     472                 : # include "vstr_dbl/vstr_add_fmt_dbl_host.c"
     473                 : #else
     474                 : # error "Please configure properly..."
     475                 : #endif
     476                 : 
     477                 : static int vstr__add_fmt_char(Vstr_base *base, size_t pos_diff,
     478                 :                               struct Vstr__fmt_spec *spec)
     479            5407 : {
     480            5407 :   if (spec->field_width > 0)
     481             214 :     --spec->field_width; /* account for char */
     482                 : 
     483            5407 :   if (spec->field_width_usr && !(spec->flags & LEFT))
     484             112 :     if (spec->field_width > 0)
     485                 :     {
     486             112 :       if (!VSTR__FMT_ADD_REP_CHR(base, ' ', spec->field_width))
     487               9 :         goto failed_alloc;
     488             103 :       spec->field_width_usr = FALSE;
     489                 :     }
     490                 : 
     491            5398 :   if (!VSTR__FMT_ADD_REP_CHR(base, spec->u.data_c, 1))
     492              10 :     goto failed_alloc;
     493                 : 
     494            5388 :   if (spec->field_width_usr && (spec->field_width > 0))
     495                 :   {
     496             101 :     if (!VSTR__FMT_ADD_REP_CHR(base, ' ', spec->field_width))
     497               9 :       goto failed_alloc;
     498                 :   }
     499                 : 
     500            5379 :   return (TRUE);
     501                 : 
     502                 :  failed_alloc:
     503              28 :   return (FALSE);
     504                 : }
     505                 : 
     506                 : #if USE_WIDE_CHAR_T
     507                 : static int vstr__add_fmt_wide_char(Vstr_base *base, size_t pos_diff,
     508                 :                                    struct Vstr__fmt_spec *spec)
     509             282 : {
     510             282 :   mbstate_t state;
     511             282 :   size_t len_mbs = 0;
     512             282 :   char *buf_mbs = NULL;
     513                 : 
     514             282 :   vstr_wrap_memset(&state, 0, sizeof(mbstate_t));
     515             282 :   len_mbs = wcrtomb(NULL, spec->u.data_wint, &state);
     516             282 :   if (len_mbs != (size_t)-1)
     517                 :   { /* stupid glibc only returns -1 when you pass a buf */
     518             282 :     len_mbs += wcrtomb(NULL, L'\0', &state);
     519                 : 
     520             282 :     if (!(buf_mbs = VSTR__MK(len_mbs)))
     521                 :     {
     522              31 :       base->conf->malloc_bad = TRUE;
     523              31 :       goto failed_alloc;
     524                 :     }
     525             251 :     vstr_wrap_memset(&state, 0, sizeof(mbstate_t));
     526             251 :     len_mbs = wcrtomb(buf_mbs, spec->u.data_wint, &state);
     527                 :   }
     528             251 :   if (len_mbs == (size_t)-1)
     529               4 :     goto failed_EILSEQ;
     530             247 :   len_mbs += wcrtomb(buf_mbs + len_mbs, L'\0', &state);
     531             247 :   --len_mbs; /* remove terminator */
     532                 : 
     533             247 :   if (spec->field_width > 0)
     534             128 :     --spec->field_width; /* account for char */
     535                 : 
     536             247 :   if (spec->field_width_usr && !(spec->flags & LEFT))
     537              73 :     if (spec->field_width > 0)
     538                 :     {
     539              73 :       if (!VSTR__FMT_ADD_REP_CHR(base, ' ', spec->field_width))
     540              10 :         goto C_failed_alloc_free_buf_mbs;
     541              63 :       spec->field_width_usr = FALSE;
     542                 :     }
     543                 : 
     544             237 :   if (!VSTR__FMT_ADD(base, buf_mbs, len_mbs))
     545               4 :     goto C_failed_alloc_free_buf_mbs;
     546                 : 
     547             233 :   if (spec->field_width_usr && (spec->field_width > 0))
     548                 :   {
     549              54 :     if (!VSTR__FMT_ADD_REP_CHR(base, ' ', spec->field_width))
     550              10 :       goto C_failed_alloc_free_buf_mbs;
     551                 :   }
     552                 : 
     553             223 :   VSTR__F(buf_mbs);
     554             223 :   return (TRUE);
     555                 : 
     556                 :  C_failed_alloc_free_buf_mbs:
     557                 :  failed_EILSEQ: /* FIXME: need a good way to see this */
     558              28 :   VSTR__F(buf_mbs);
     559                 :  failed_alloc:
     560              59 :   return (FALSE);
     561                 : }
     562                 : #else
     563                 : static int vstr__add_fmt_wide_char(Vstr_base *VSTR__ATTR_UNUSED(base),
     564                 :                                    size_t VSTR__ATTR_UNUSED(pos_diff),
     565                 :                                    struct Vstr__fmt_spec *
     566                 :                                    VSTR__ATTR_UNUSED(spec))
     567               1 : {
     568               1 :   assert(FALSE);
     569               1 :   return (FALSE);
     570                 : }
     571                 : #endif
     572                 : 
     573                 : static int vstr__add_fmt_cstr(Vstr_base *base, size_t pos_diff,
     574                 :                               struct Vstr__fmt_spec *spec)
     575          697628 : {
     576          697628 :   size_t len = 0;
     577          697628 :   const char *str = spec->u.data_ptr;
     578                 : 
     579          697628 :   if (!str)
     580                 :   {
     581              30 :     str = base->conf->loc->null_ref->ptr;
     582              30 :     len = base->conf->loc->null_len;
     583              30 :     if ((spec->flags & PREC_USR) && (len > spec->precision))
     584              10 :       len = spec->precision;
     585                 :   }
     586          697598 :   else if (spec->flags & PREC_USR)
     587          443956 :     len = strnlen(str, spec->precision);
     588                 :   else
     589          253642 :     len = strlen(str);
     590                 :   
     591          697628 :   if ((spec->flags & PREC_USR) && spec->field_width_usr &&
     592                 :       (spec->field_width > spec->precision))
     593              10 :     spec->field_width = spec->precision;
     594                 : 
     595          697628 :   if (spec->field_width_usr && !(spec->flags & LEFT))
     596           14281 :     if (spec->field_width > len)
     597                 :     {
     598           13568 :       if (!VSTR__FMT_ADD_REP_CHR(base, ' ', spec->field_width - len))
     599            2969 :         goto failed_alloc;
     600           10599 :       spec->field_width_usr = FALSE;
     601                 :     }
     602                 : 
     603          694659 :   if (!VSTR__FMT_ADD(base, str, len))
     604            1250 :     goto failed_alloc;
     605                 : 
     606          693409 :   if (spec->field_width_usr && (spec->field_width > len))
     607             101 :     if (!VSTR__FMT_ADD_REP_CHR(base, ' ', spec->field_width - len))
     608               9 :       goto failed_alloc;
     609                 : 
     610          693400 :   return (TRUE);
     611                 : 
     612                 :  failed_alloc:
     613            4228 :   return (FALSE);
     614                 : }
     615                 : 
     616                 : #if USE_WIDE_CHAR_T
     617                 : static int vstr__add_fmt_wide_cstr(Vstr_base *base, size_t pos_diff,
     618                 :                                    struct Vstr__fmt_spec *spec)
     619             357 : { /* note precision is number of wchar_t's allowed through, not bytes
     620                 :    * as in sprintf() */
     621             357 :   mbstate_t state;
     622             357 :   size_t len_mbs = 0;
     623             357 :   char *buf_mbs = NULL;
     624             357 :   const wchar_t *wstr = spec->u.data_ptr;
     625             357 :   const wchar_t *tmp  = NULL;
     626                 : 
     627             357 :   if (!wstr)
     628              12 :     return (vstr__add_fmt_cstr(base, pos_diff, spec));
     629                 :   
     630             345 :   tmp = wstr;
     631                 : 
     632             345 :   vstr_wrap_memset(&state, 0, sizeof(mbstate_t));
     633                 : 
     634             345 :   if (!(spec->flags & PREC_USR))
     635             325 :     spec->precision = UINT_MAX;
     636             345 :   len_mbs = wcsnrtombs(NULL, &tmp, spec->precision, 0, &state);
     637             345 :   if (len_mbs == (size_t)-1)
     638               4 :     goto failed_EILSEQ;
     639                 :   /* NULL when found end of input -- glibc doesn't do this when arg1 NULL
     640                 :    * if (!tmp)
     641                 :    *   ++len_mbs;
     642                 :    * else
     643                 :    */
     644                 :   { /* wcslen() > spec->precision */
     645             341 :     size_t tmp_mbs = wcrtomb(NULL, L'\0', &state);
     646                 : 
     647             341 :     if (tmp_mbs != (size_t)-1)
     648             341 :       len_mbs += tmp_mbs; /* include '\0' */
     649                 :   }
     650                 : 
     651             341 :   if (!(buf_mbs = VSTR__MK(len_mbs)))
     652                 :   {
     653              32 :     base->conf->malloc_bad = TRUE;
     654              32 :     goto failed_alloc;
     655                 :   }
     656             309 :   tmp = wstr;
     657             309 :   vstr_wrap_memset(&state, 0, sizeof(mbstate_t));
     658             309 :   len_mbs = wcsnrtombs(buf_mbs, &tmp, spec->precision, len_mbs, &state);
     659             309 :   if (tmp) /* wcslen() > spec->precision */
     660                 :   {
     661              16 :     size_t tmp_mbs = wcrtomb(buf_mbs + len_mbs, L'\0', &state);
     662              16 :     len_mbs += tmp_mbs - 1; /* ignore '\0' */
     663                 :   }
     664                 : 
     665             309 :   if ((spec->flags & PREC_USR) && spec->field_width_usr &&
     666                 :       (spec->field_width > spec->precision))
     667               8 :     spec->field_width = spec->precision;
     668                 : 
     669             309 :   if (spec->field_width_usr && !(spec->flags & LEFT))
     670              97 :     if (spec->field_width > len_mbs)
     671                 :     {
     672              93 :       if (!VSTR__FMT_ADD_REP_CHR(base, ' ', spec->field_width - len_mbs))
     673              10 :         goto S_failed_alloc_free_buf_mbs;
     674              83 :       spec->field_width_usr = FALSE;
     675                 :     }
     676                 : 
     677             299 :   if (!VSTR__FMT_ADD(base, buf_mbs, len_mbs))
     678               6 :     goto S_failed_alloc_free_buf_mbs;
     679                 : 
     680             293 :   if (spec->field_width_usr && (spec->field_width > len_mbs))
     681              54 :     if (!VSTR__FMT_ADD_REP_CHR(base, ' ', spec->field_width - len_mbs))
     682              10 :       goto S_failed_alloc_free_buf_mbs;
     683                 : 
     684             283 :   VSTR__F(buf_mbs);
     685             283 :   return (TRUE);
     686                 : 
     687                 :  S_failed_alloc_free_buf_mbs:
     688              26 :   VSTR__F(buf_mbs);
     689                 :  failed_alloc:
     690                 :  failed_EILSEQ: /* FIXME: */
     691              62 :   return (FALSE);
     692                 : }
     693                 : #else
     694                 : static int vstr__add_fmt_wide_cstr(Vstr_base *base,
     695                 :                                    size_t pos_diff,
     696                 :                                    struct Vstr__fmt_spec *spec)
     697               4 : {
     698               4 :   if (!spec->u.data_ptr)
     699               3 :     return (vstr__add_fmt_cstr(base, pos_diff, spec));
     700                 :   
     701               1 :   assert(FALSE);
     702               1 :   return (FALSE);
     703                 : }
     704                 : #endif
     705                 : 
     706                 : static
     707                 : struct Vstr__fmt_spec *
     708                 : vstr__add_fmt_usr_write_spec(Vstr_base *base, size_t orig_len, size_t pos_diff,
     709                 :                              struct Vstr__fmt_spec *spec, int sve_errno)
     710          210182 : {
     711          210182 :   struct Vstr__fmt_spec *last = NULL;
     712                 :   struct
     713                 :   {
     714                 :    Vstr_fmt_spec usr_spec;
     715                 :    void *params[VSTR__FMT_USR_SZ];
     716          210182 :   } dummy;
     717          210182 :   Vstr_fmt_spec *usr_spec = NULL;
     718          210182 :   unsigned int scan = 0;
     719          210182 :   int (*func)(Vstr_base *, size_t, struct Vstr_fmt_spec *) =
     720          210182 :     spec->usr_spec->func;
     721          210182 :   unsigned int *types = spec->usr_spec->types;
     722          210182 :   unsigned int sz     = spec->usr_spec->sz;
     723                 :   
     724          210182 :   assert(spec->escape_usr);
     725          210182 :   assert(spec->usr_spec);
     726                 : 
     727          210182 :   if (sz <= VSTR__FMT_USR_SZ)
     728          190237 :     usr_spec = &dummy.usr_spec;
     729                 :   else
     730                 :   {
     731           19945 :     if (!(usr_spec = VSTR__MK(sizeof(Vstr_fmt_spec) +
     732                 :                               (spec->usr_spec->sz * sizeof(void *)))))
     733              49 :       return (NULL);
     734                 :   }
     735                 : 
     736          210133 :   usr_spec->vstr_orig_len = orig_len;
     737          210133 :   usr_spec->name = spec->usr_spec->name_str;
     738                 : 
     739          210133 :   usr_spec->obj_precision = 0;
     740          210133 :   usr_spec->obj_field_width = 0;
     741                 : 
     742          210133 :   if ((usr_spec->fmt_precision = !!(spec->flags & PREC_USR)))
     743           45667 :     usr_spec->obj_precision = spec->precision;
     744          210133 :   if ((usr_spec->fmt_field_width =  spec->field_width_usr))
     745           60781 :     usr_spec->obj_field_width = spec->field_width;
     746                 : 
     747          210133 :   usr_spec->fmt_minus = !!(spec->flags & LEFT);
     748          210133 :   usr_spec->fmt_plus =  !!(spec->flags & PLUS);
     749          210133 :   usr_spec->fmt_space = !!(spec->flags & SPACE);
     750          210133 :   usr_spec->fmt_hash =  !!(spec->flags & SPECIAL);
     751          210133 :   usr_spec->fmt_zero =  !!(spec->flags & ZEROPAD);
     752          210133 :   usr_spec->fmt_quote = !!(spec->flags & THOUSAND_SEP);
     753          210133 :   usr_spec->fmt_I =     !!(spec->flags & ALT_DIGITS);
     754                 : 
     755          210133 :   if (!types[scan])
     756                 :   {
     757              35 :     assert(spec->escape_usr && !!spec->usr_spec);
     758                 : 
     759              35 :     last = spec;
     760              35 :     spec = spec->next;
     761                 :   }
     762                 : 
     763          611253 :   while (types[scan])
     764                 :   {
     765          401120 :     switch (types[scan])
     766                 :     {
     767                 :       case VSTR_TYPE_FMT_INT:
     768                 :       case VSTR_TYPE_FMT_UINT:
     769                 :       case VSTR_TYPE_FMT_LONG:
     770                 :       case VSTR_TYPE_FMT_ULONG:
     771                 :       case VSTR_TYPE_FMT_LONG_LONG:
     772                 :       case VSTR_TYPE_FMT_ULONG_LONG:
     773                 :       case VSTR_TYPE_FMT_SSIZE_T:
     774                 :       case VSTR_TYPE_FMT_SIZE_T:
     775                 :       case VSTR_TYPE_FMT_INTMAX_T:
     776                 :       case VSTR_TYPE_FMT_UINTMAX_T:
     777                 :       case VSTR_TYPE_FMT_DOUBLE:
     778                 :       case VSTR_TYPE_FMT_DOUBLE_LONG:
     779          239033 :         usr_spec->data_ptr[scan] = &spec->u;
     780          239033 :         break;
     781                 :       case VSTR_TYPE_FMT_PTRDIFF_T:
     782              48 :         ASSERT(spec->data_t == (ptrdiff_t)spec->u.data_m);
     783              48 :         usr_spec->data_ptr[scan] = &spec->data_t;
     784              48 :         break;
     785                 :         
     786                 :       case VSTR_TYPE_FMT_PTR_VOID:
     787                 :       case VSTR_TYPE_FMT_PTR_CHAR:
     788                 :       case VSTR_TYPE_FMT_PTR_WCHAR_T:
     789                 :       case VSTR_TYPE_FMT_PTR_SIGNED_CHAR:
     790                 :       case VSTR_TYPE_FMT_PTR_SHORT:
     791                 :       case VSTR_TYPE_FMT_PTR_INT:
     792                 :       case VSTR_TYPE_FMT_PTR_LONG:
     793                 :       case VSTR_TYPE_FMT_PTR_LONG_LONG:
     794                 :       case VSTR_TYPE_FMT_PTR_SSIZE_T:
     795                 :       case VSTR_TYPE_FMT_PTR_PTRDIFF_T:
     796                 :       case VSTR_TYPE_FMT_PTR_INTMAX_T:
     797          162029 :         usr_spec->data_ptr[scan] =  spec->u.data_ptr;
     798          162029 :         break;
     799                 :       case VSTR_TYPE_FMT_ERRNO:
     800              10 :         errno = sve_errno;
     801               2 :         ASSERT_NO_SWITCH_DEF();
     802                 :     }
     803          401120 :     assert(spec->escape_usr && (scan ? !spec->usr_spec : !!spec->usr_spec));
     804                 : 
     805          401120 :     ++scan;
     806          401120 :     last = spec;
     807          401120 :     spec = spec->next;
     808                 :   }
     809          210133 :   assert(!spec || !spec->escape_usr || spec->usr_spec);
     810          210133 :   usr_spec->data_ptr[scan] = NULL;
     811                 : 
     812          210133 :   if (!(*func)(base, base->len - pos_diff, usr_spec))
     813           23531 :     last = NULL;
     814                 :   
     815          210133 :   if (sz > VSTR__FMT_USR_SZ)
     816           19896 :     VSTR__F(usr_spec);
     817                 : 
     818          210133 :   return (last);
     819                 : }
     820                 : 
     821                 : #define VSTR__FMT_N_PTR(x, y) \
     822                 :      case x: do \
     823                 :        { \
     824                 :         y *len_curr = spec->u.data_ptr; \
     825                 :         *len_curr = len; \
     826                 :        } while (FALSE)
     827                 : 
     828                 : static int vstr__fmt_write_spec(Vstr_base *base, size_t pos_diff,
     829                 :                                 size_t orig_len, int sve_errno)
     830          253483 : {
     831          253483 :   struct Vstr__fmt_spec *const beg  = base->conf->vstr__fmt_spec_list_beg;
     832          253483 :   struct Vstr__fmt_spec *const end  = base->conf->vstr__fmt_spec_list_end;
     833          253483 :   struct Vstr__fmt_spec *      spec = base->conf->vstr__fmt_spec_list_beg;
     834                 : 
     835          253483 :   if (!end) /* invalid format... */
     836              22 :     return (TRUE);
     837                 :   
     838          253461 :   ASSERT(beg && end);
     839                 : 
     840                 :   /* allow vstr_add_vfmt() to be called form a usr cb */
     841          253461 :   base->conf->vstr__fmt_spec_list_beg = NULL;
     842          253461 :   base->conf->vstr__fmt_spec_list_end = NULL;
     843                 :   
     844         1475249 :   while (spec)
     845                 :   {
     846         1253947 :     if (spec->escape_usr)
     847                 :     {
     848          210182 :       if (!(spec = vstr__add_fmt_usr_write_spec(base, orig_len,
     849                 :                                                 pos_diff, spec, sve_errno)))
     850           23580 :         goto failed_user;
     851                 :     }
     852         1043765 :     else switch (spec->fmt_code)
     853                 :     {
     854                 :       case 'c':
     855            5407 :         if (!vstr__add_fmt_char(base, pos_diff, spec))
     856              28 :           goto failed_alloc;
     857             283 :         break;
     858                 : 
     859                 :       case 'C':
     860             283 :         if (!vstr__add_fmt_wide_char(base, pos_diff, spec))
     861              60 :           goto failed_alloc;
     862              19 :         break;
     863                 : 
     864                 :       case 'm':
     865              19 :         spec->u.data_ptr = strerror(sve_errno);
     866                 :       case 's':
     867          697613 :         if (!vstr__add_fmt_cstr(base, pos_diff, spec))
     868            4228 :           goto failed_alloc;
     869             361 :         break;
     870                 : 
     871                 :       case 'S':
     872             361 :         if (!vstr__add_fmt_wide_cstr(base, pos_diff, spec))
     873              63 :           goto failed_alloc;
     874          123388 :         break;
     875                 : 
     876                 :       case 'p': /* convert ptr to unsigned long and print */
     877                 :       {
     878          123388 :         assert(spec->int_type == VSTR_TYPE_FMT_PTR_VOID);
     879          123388 :         assert(!(spec->flags & SIGN));
     880                 :       }
     881                 :       /* FALLTHROUGH */
     882                 :       case 'd':
     883                 :       case 'i':
     884                 :       case 'u':
     885                 :       case 'X':
     886                 :       case 'x':
     887                 :       case 'o':
     888          167655 :         if (!vstr__add_fmt_number(base, pos_diff, spec))
     889             495 :           goto failed_alloc;
     890           27360 :         break;
     891                 : 
     892                 :       case 'n':
     893                 :       {
     894           27360 :         size_t len = (base->len - orig_len);
     895                 : 
     896           27360 :         switch (spec->int_type)
     897                 :         {
     898              10 :           VSTR__FMT_N_PTR(VSTR_TYPE_FMT_UCHAR, signed char);          break;
     899              10 :           VSTR__FMT_N_PTR(VSTR_TYPE_FMT_USHORT, short);               break;
     900           27290 :           VSTR__FMT_N_PTR(VSTR_TYPE_FMT_UINT, int);                   break;
     901              10 :           VSTR__FMT_N_PTR(VSTR_TYPE_FMT_ULONG, long);                 break;
     902              10 :           VSTR__FMT_N_PTR(VSTR_TYPE_FMT_ULONG_LONG, Vstr__long_long); break;
     903              10 :           VSTR__FMT_N_PTR(VSTR_TYPE_FMT_SIZE_T, ssize_t);             break;
     904              10 :           VSTR__FMT_N_PTR(VSTR_TYPE_FMT_UINTMAX_T, intmax_t);         break;
     905              10 :           VSTR__FMT_N_PTR(VSTR_TYPE_FMT_PTRDIFF_T, ptrdiff_t);
     906              10 :           ASSERT_NO_SWITCH_DEF();
     907                 :         }
     908                 :       }
     909          145086 :       break;
     910                 : 
     911                 :       case 'a':
     912                 :       case 'A':
     913                 :       case 'e':
     914                 :       case 'E':
     915                 :       case 'f':
     916                 :       case 'F':
     917                 :       case 'g':
     918                 :       case 'G':
     919          145086 :         assert(VSTR__FMT_ANAL_ZERO &&
     920                 :                (spec->field_width_usr || !spec->field_width));
     921          145086 :         assert(VSTR__FMT_ANAL_ZERO &&
     922                 :                ((spec->flags & PREC_USR) || !spec->precision));
     923          145086 :         if (!vstr__add_fmt_dbl(base, pos_diff, spec))
     924            3705 :           goto failed_alloc;
     925          911552 :         ASSERT_NO_SWITCH_DEF();
     926                 :     }
     927                 : 
     928         1221788 :     spec = spec->next;
     929                 :   }
     930                 : 
     931          221302 :   end->next = base->conf->vstr__fmt_spec_make;
     932          221302 :   base->conf->vstr__fmt_spec_make = beg;
     933                 : 
     934          221302 :   return (TRUE);
     935                 : 
     936                 :  failed_alloc:
     937                 :  failed_user:
     938           32159 :   end->next = base->conf->vstr__fmt_spec_make;
     939           32159 :   base->conf->vstr__fmt_spec_make = beg;
     940                 : 
     941           32159 :   return (FALSE);
     942                 : }
     943                 : 
     944                 : #undef VSTR__FMT_N_PTR
     945                 : #define VSTR__FMT_N_PTR(x, y) \
     946                 :           case x: \
     947                 :             u.data_ptr = va_arg(ap, y *)
     948                 : 
     949                 : #define VSTR__FMT_ARG_NUM(sT, asT, auT, memb)                           \
     950                 :     if (spec->flags & SIGN)                                             \
     951                 :     {                                                                   \
     952                 :       sT tmp = va_arg(ap, asT);                                         \
     953                 :       VSTR__FMT_ABS_NUM(u.memb, tmp);                                   \
     954                 :     }                                                                   \
     955                 :     else                                                                \
     956                 :       u.memb = va_arg(ap, auT);                                         \
     957                 :     if (!u.memb) spec->flags |= NUM_IS_ZERO;                            \
     958                 :     break
     959                 : 
     960                 : static int vstr__fmt_fillin_spec(Vstr_conf *conf, va_list ap, int have_dollars)
     961          253487 : {
     962          253487 :   struct Vstr__fmt_spec *beg = conf->vstr__fmt_spec_list_beg;
     963          253487 :   unsigned int count = 0;
     964          253487 :   unsigned int need_to_fin_now = FALSE;
     965                 : 
     966         1422676 :   while (beg)
     967                 :   {
     968         1169193 :     struct Vstr__fmt_spec *spec = NULL;
     969         1169193 :     int done = FALSE;
     970         1169193 :     union Vstr__fmt_sp_un u;
     971                 : 
     972         1169193 :     ++count;
     973         2228538 :     ASSERT(beg);
     974                 : 
     975         2681799 :     while (beg &&
     976                 :            !beg->field_width_param &&
     977                 :            !beg->precision_param &&
     978                 :            !beg->main_param)
     979         1512606 :       beg = beg->next;
     980                 :     
     981         1169193 :     ASSERT_RET(!(beg && need_to_fin_now), FALSE); /* incomplete spec */
     982                 : 
     983         1169189 :     spec = beg;
     984         1186158 :     while (spec)
     985                 :     {
     986          927836 :       if (count == spec->field_width_param)
     987                 :       {
     988           18152 :         int tmp_fw_p = 0;
     989           18152 :         if (!done) u.data_i = va_arg(ap, int);
     990           18152 :         done = TRUE;
     991                 : 
     992           18152 :         assert(spec->field_width_usr);
     993                 : 
     994           18152 :         tmp_fw_p = u.data_i;
     995           18152 :         if (tmp_fw_p < 0) /* negative field width == flag '-' */
     996                 :         {
     997             812 :           spec->flags |= LEFT;
     998             812 :           VSTR__FMT_S2U_NUM(spec->field_width, tmp_fw_p);
     999                 :         }
    1000                 :         else
    1001           17340 :           spec->field_width = tmp_fw_p;
    1002                 :         
    1003           18152 :         spec->field_width_param = 0;
    1004           18152 :         if (!have_dollars)
    1005           15064 :           break;
    1006                 :       }
    1007                 : 
    1008          912772 :       if (count == spec->precision_param)
    1009                 :       {
    1010             472 :         int tmp_fw_p = 0;
    1011             472 :         if (!done) u.data_i = va_arg(ap, int);
    1012             472 :         done = TRUE;
    1013                 : 
    1014             472 :         assert(spec->flags & PREC_USR);
    1015                 : 
    1016             472 :         tmp_fw_p = u.data_i;
    1017             472 :         if (tmp_fw_p < 0) /* negative precision == pretend one wasn't given */
    1018              20 :           spec->flags &= ~PREC_USR;
    1019                 :         else
    1020             452 :           spec->precision = tmp_fw_p;
    1021             472 :         spec->precision_param = 0;
    1022             472 :         if (!have_dollars)
    1023             442 :           break;
    1024                 :       }
    1025                 :       
    1026          912330 :       if (count == spec->main_param)
    1027                 :       {
    1028          898909 :         if (!done)
    1029          898634 :           switch (spec->fmt_code)
    1030                 :           {
    1031                 :             case 'c':
    1032            5432 :               u.data_c = va_arg(ap, int);
    1033            5432 :               break;
    1034                 : 
    1035                 :             case 'C':
    1036             477 :               u.data_wint = va_arg(ap, wint_t);
    1037             477 :               break;
    1038                 : 
    1039                 :             case 'm':
    1040          125227 :               break;
    1041                 : 
    1042                 :             case 's':
    1043          125227 :               u.data_ptr = va_arg(ap, char *);
    1044          125227 :               break;
    1045                 : 
    1046                 :             case 'S':
    1047             610 :               u.data_ptr = va_arg(ap, wchar_t *);
    1048             610 :               break;
    1049                 : 
    1050                 :             case 'd':
    1051                 :             case 'i':
    1052                 :             case 'u':
    1053                 :             case 'X':
    1054                 :             case 'x':
    1055                 :             case 'o':
    1056          411641 :               switch (spec->int_type)
    1057                 :               {                        
    1058                 :                 case VSTR_TYPE_FMT_UCHAR:
    1059             192 :                   VSTR__FMT_ARG_NUM(signed char, int, unsigned int, data_c);
    1060                 :                 case VSTR_TYPE_FMT_USHORT:
    1061             182 :                   VSTR__FMT_ARG_NUM(signed short, int, unsigned int, data_s);
    1062                 :                 case VSTR_TYPE_FMT_UINT:
    1063          138227 :                   VSTR__FMT_ARG_NUM(int, int, unsigned int, data_i);
    1064                 :                 case VSTR_TYPE_FMT_ULONG:
    1065           18267 :                   VSTR__FMT_ARG_NUM(long, long, unsigned long, data_l);
    1066                 :                 case VSTR_TYPE_FMT_ULONG_LONG:
    1067             209 :                   VSTR__FMT_ARG_NUM(Vstr__long_long, Vstr__long_long,
    1068                 :                                     Vstr__unsigned_long_long, data_L);
    1069                 :                 case VSTR_TYPE_FMT_SIZE_T:
    1070          148423 :                   VSTR__FMT_ARG_NUM(ssize_t, ssize_t, size_t, data_sz);
    1071                 :                 case VSTR_TYPE_FMT_UINTMAX_T:
    1072          105995 :                   VSTR__FMT_ARG_NUM(intmax_t, intmax_t, uintmax_t, data_m);
    1073                 :                   
    1074                 :                 case VSTR_TYPE_FMT_PTRDIFF_T:
    1075             146 :                   if (1)
    1076                 :                   { /* no unsigned type ... */
    1077                 :                     /* FIXME: volatile for bug in gcc-2.95.x */
    1078             146 :                     volatile ptrdiff_t ttmp = va_arg(ap, ptrdiff_t);
    1079             146 :                     volatile intmax_t jtmp = ttmp;
    1080                 : 
    1081             146 :                     spec->data_t = ttmp;
    1082             146 :                     VSTR__FMT_ABS_NUM(u.data_m, jtmp);
    1083                 :                   }
    1084             146 :                   if (!u.data_m) spec->flags |= NUM_IS_ZERO;
    1085             146 :                   spec->int_type = VSTR_TYPE_FMT_UINTMAX_T;
    1086                 : 
    1087             146 :                   ASSERT_NO_SWITCH_DEF();
    1088                 :               }
    1089          152064 :               break;
    1090                 :               
    1091                 :             case 'p':
    1092          152064 :               u.data_ptr = va_arg(ap, void *);
    1093          152064 :               break;
    1094                 :             
    1095                 :             case 'n':
    1096           41632 :               switch (spec->int_type)
    1097                 :               {
    1098              59 :                 VSTR__FMT_N_PTR(VSTR_TYPE_FMT_UCHAR, signed char);        break;
    1099              59 :                 VSTR__FMT_N_PTR(VSTR_TYPE_FMT_USHORT, short);             break;
    1100           41219 :                 VSTR__FMT_N_PTR(VSTR_TYPE_FMT_UINT, int);                 break;
    1101              59 :                 VSTR__FMT_N_PTR(VSTR_TYPE_FMT_ULONG, long);               break;
    1102              59 :                 VSTR__FMT_N_PTR(VSTR_TYPE_FMT_ULONG_LONG, Vstr__long_long);
    1103              59 :                 break;
    1104              59 :                 VSTR__FMT_N_PTR(VSTR_TYPE_FMT_SIZE_T, ssize_t);           break;
    1105              59 :                 VSTR__FMT_N_PTR(VSTR_TYPE_FMT_UINTMAX_T, intmax_t);       break;
    1106              59 :                 VSTR__FMT_N_PTR(VSTR_TYPE_FMT_PTRDIFF_T, ptrdiff_t);
    1107              59 :                 ASSERT_NO_SWITCH_DEF();
    1108                 :               }
    1109          161532 :               break;
    1110                 : 
    1111                 :             case 'a': /* print like [-]x.xxxpxx -- in hex using abcdef */
    1112                 :             case 'A': /* print like [-]x.xxxPxx -- in hex using ABCDEF */
    1113                 :             case 'e': /* print like [-]x.xxxexx */
    1114                 :             case 'E': /* use big E instead */
    1115                 :             case 'f': /* print like an int */
    1116                 :             case 'F': /* print like an int - upper case infinity/nan */
    1117                 :             case 'g': /* use the smallest of e and f */
    1118                 :             case 'G': /* use the smallest of E and F */
    1119          161532 :               if (spec->int_type == VSTR_TYPE_FMT_ULONG_LONG)
    1120           65846 :                 u.data_Ld = va_arg(ap, long double);
    1121                 :               else
    1122           95686 :                 u.data_d = va_arg(ap, double);
    1123                 :               
    1124           46384 :               ASSERT_NO_SWITCH_DEF();
    1125                 :           }
    1126          898909 :         done = TRUE;
    1127          898909 :         spec->u = u;
    1128          898909 :         spec->main_param = 0;
    1129                 :         
    1130          898909 :         if (!have_dollars)
    1131          895361 :           break;
    1132                 :       }
    1133                 :       
    1134           16969 :       spec = spec->next;
    1135                 :     }
    1136                 :     
    1137         1169189 :     if (!done)
    1138          253465 :       need_to_fin_now = 1;
    1139                 :   }
    1140                 :   
    1141          253483 :  return (TRUE);
    1142                 : }
    1143                 : #undef VSTR__FMT_N_PTR
    1144                 : #undef VSTR__FMT_ARG_NUM
    1145                 : 
    1146                 : static const char *vstr__add_fmt_usr_esc(Vstr_conf *conf,
    1147                 :                                          const char *fmt,
    1148                 :                                          struct Vstr__fmt_spec *spec,
    1149                 :                                          unsigned int *passed_params)
    1150          220465 : {
    1151          220465 :   unsigned int params = *passed_params;
    1152          220465 :   Vstr__fmt_usr_name_node *node = NULL;
    1153          220465 :   unsigned int have_i18n_args = spec->main_param;
    1154                 :   
    1155          220465 :   if ((node = vstr__fmt_usr_match(conf, fmt)))
    1156                 :   {
    1157          215772 :     unsigned int scan = 0;
    1158                 : 
    1159          215772 :     spec->usr_spec = node;
    1160                 : 
    1161          410753 :     while (TRUE)
    1162                 :     {
    1163          410753 :       int have_arg = TRUE;
    1164                 : 
    1165          410753 :       spec->escape_usr = TRUE;
    1166                 : 
    1167          410753 :       switch (node->types[scan])
    1168                 :       {
    1169                 :         case VSTR_TYPE_FMT_END:
    1170              35 :           spec->fmt_code = 0;
    1171              35 :           have_arg = FALSE;
    1172                 :           /* it's possible, but stupid, with i18n */
    1173              35 :           ASSERT(!scan && !spec->main_param);
    1174              35 :           spec->main_param = 0;
    1175              35 :           break;
    1176                 :         case VSTR_TYPE_FMT_INT:
    1177             538 :           spec->flags |= SIGN;
    1178             538 :           spec->fmt_code = 'd';
    1179             538 :           break;
    1180                 :         case VSTR_TYPE_FMT_UINT:
    1181           44024 :           spec->fmt_code = 'u';
    1182           44024 :           break;
    1183                 :         case VSTR_TYPE_FMT_LONG:
    1184              58 :           spec->int_type = VSTR_TYPE_FMT_ULONG;
    1185              58 :           spec->flags |= SIGN;
    1186              58 :           spec->fmt_code = 'd';
    1187              58 :           break;
    1188                 :         case VSTR_TYPE_FMT_ULONG:
    1189           13065 :           spec->int_type = VSTR_TYPE_FMT_ULONG;
    1190           13065 :           spec->fmt_code = 'u';
    1191           13065 :           break;
    1192                 :         case VSTR_TYPE_FMT_LONG_LONG:
    1193              57 :           spec->int_type = VSTR_TYPE_FMT_ULONG_LONG;
    1194              57 :           spec->flags |= SIGN;
    1195              57 :           spec->fmt_code = 'd';
    1196              57 :           break;
    1197                 :         case VSTR_TYPE_FMT_ULONG_LONG:
    1198              53 :           spec->int_type = VSTR_TYPE_FMT_ULONG_LONG;
    1199              53 :           spec->fmt_code = 'u';
    1200              53 :           break;
    1201                 :         case VSTR_TYPE_FMT_SSIZE_T:
    1202              56 :           spec->int_type = VSTR_TYPE_FMT_SIZE_T;
    1203              56 :           spec->flags |= SIGN;
    1204              56 :           spec->fmt_code = 'd';
    1205              56 :           break;
    1206                 :         case VSTR_TYPE_FMT_SIZE_T:
    1207          148194 :           spec->int_type = VSTR_TYPE_FMT_SIZE_T;
    1208          148194 :           spec->fmt_code = 'u';
    1209          148194 :           break;
    1210                 :         case VSTR_TYPE_FMT_PTRDIFF_T:
    1211              57 :           spec->int_type = VSTR_TYPE_FMT_PTRDIFF_T;
    1212              57 :           spec->flags |= SIGN;
    1213              57 :           spec->fmt_code = 'd';
    1214              57 :           break;
    1215                 :         case VSTR_TYPE_FMT_INTMAX_T:
    1216              58 :           spec->int_type = VSTR_TYPE_FMT_UINTMAX_T;
    1217              58 :           spec->flags |= SIGN;
    1218              58 :           spec->fmt_code = 'd';
    1219              58 :           break;
    1220                 :         case VSTR_TYPE_FMT_UINTMAX_T:
    1221           36972 :           spec->int_type = VSTR_TYPE_FMT_UINTMAX_T;
    1222           36972 :           spec->fmt_code = 'u';
    1223           36972 :           break;
    1224                 :         case VSTR_TYPE_FMT_DOUBLE:
    1225              60 :           spec->fmt_code = 'f';
    1226              60 :           break;
    1227                 :         case VSTR_TYPE_FMT_DOUBLE_LONG:
    1228              60 :           spec->int_type = VSTR_TYPE_FMT_ULONG_LONG;
    1229              60 :           spec->fmt_code = 'f';
    1230              60 :           break;
    1231                 :         case VSTR_TYPE_FMT_PTR_VOID:
    1232          152149 :           spec->fmt_code = 'p';
    1233          152149 :           break;
    1234                 :         case VSTR_TYPE_FMT_PTR_CHAR:
    1235             952 :           spec->fmt_code = 's';
    1236             952 :           break;
    1237                 :         case VSTR_TYPE_FMT_PTR_WCHAR_T:
    1238              57 :           spec->fmt_code = 'S';
    1239              57 :           break;
    1240                 :         case VSTR_TYPE_FMT_ERRNO:
    1241                 :           /* it's possible, but stupid, with i18n */
    1242              10 :           ASSERT(!spec->main_param);
    1243              10 :           spec->main_param = 0;
    1244              10 :           spec->fmt_code = 0;
    1245              10 :           have_arg = FALSE;
    1246              10 :           break;
    1247                 :           
    1248                 :         case VSTR_TYPE_FMT_PTR_SIGNED_CHAR:
    1249              52 :           spec->fmt_code = 'n'; spec->int_type = VSTR_TYPE_FMT_UCHAR;
    1250              52 :           break;
    1251                 :         case VSTR_TYPE_FMT_PTR_SHORT:
    1252              52 :           spec->fmt_code = 'n'; spec->int_type = VSTR_TYPE_FMT_USHORT;
    1253              52 :           break;
    1254                 :         case VSTR_TYPE_FMT_PTR_INT:
    1255           13946 :           spec->fmt_code = 'n'; spec->int_type = VSTR_TYPE_FMT_UINT;
    1256           13946 :           break;
    1257                 :         case VSTR_TYPE_FMT_PTR_LONG:
    1258              50 :           spec->fmt_code = 'n'; spec->int_type = VSTR_TYPE_FMT_ULONG;
    1259              50 :           break;
    1260                 :         case VSTR_TYPE_FMT_PTR_LONG_LONG:
    1261              50 :           spec->fmt_code = 'n'; spec->int_type = VSTR_TYPE_FMT_ULONG_LONG;
    1262              50 :           break;
    1263                 :         case VSTR_TYPE_FMT_PTR_SSIZE_T:
    1264              50 :           spec->fmt_code = 'n'; spec->int_type = VSTR_TYPE_FMT_SIZE_T;
    1265              50 :           break;
    1266                 :         case VSTR_TYPE_FMT_PTR_PTRDIFF_T:
    1267              49 :           spec->fmt_code = 'n'; spec->int_type = VSTR_TYPE_FMT_PTRDIFF_T;
    1268              49 :           break;
    1269                 :         case VSTR_TYPE_FMT_PTR_INTMAX_T:
    1270              49 :           spec->fmt_code = 'n'; spec->int_type = VSTR_TYPE_FMT_UINTMAX_T;
    1271                 :           
    1272              43 :           ASSERT_NO_SWITCH_DEF();
    1273                 :       }
    1274                 : 
    1275                 :       /* custom formatters have multiple args, they _must_ follow each other
    1276                 :        * so if the first is set, set the rest based off that */
    1277          410753 :       if (have_i18n_args && have_arg)
    1278            1788 :         spec->main_param = have_i18n_args++;
    1279          410753 :       VSTR__FMT_MV_SPEC(conf, have_arg);
    1280                 :       
    1281                 :       /* allow _END to be the only thing passed */
    1282          410753 :       if (!node->types[scan] || !node->types[++scan])
    1283          215726 :         break;
    1284                 : 
    1285          194992 :       if (!conf->vstr__fmt_spec_make && !vstr__fmt_add_spec(conf))
    1286              11 :         goto failed_alloc;
    1287          194981 :       spec = conf->vstr__fmt_spec_make;
    1288          194981 :       vstr__fmt_init_spec(spec);
    1289                 :     }
    1290                 : 
    1291          215761 :     *passed_params = params;
    1292                 : 
    1293          215761 :     return (fmt + node->name_len);
    1294                 :   }
    1295                 :   
    1296            4693 :   return (fmt);
    1297                 : 
    1298                 :  failed_alloc:
    1299              11 :   return (NULL);
    1300                 : }
    1301                 : 
    1302                 : static const char *vstr__add_fmt_spec(const char *fmt,
    1303                 :                                       struct Vstr__fmt_spec *spec,
    1304                 :                                       unsigned int *params,
    1305                 :                                       unsigned int *have_dollars)
    1306          704268 : {
    1307          704268 :   int tmp_num = 0;
    1308                 : 
    1309                 :   /* get i18n param number */
    1310          704268 :   if (VSTR__ADD_FMT_ISDIGIT(*fmt) && (*fmt != '0'))
    1311                 :   {
    1312           37133 :     tmp_num = VSTR__ADD_FMT_STRTOL(fmt);
    1313                 : 
    1314           37133 :     if (*fmt != '$')
    1315           33651 :       goto use_field_width;
    1316                 : 
    1317            3482 :     ++fmt;
    1318            3482 :     *have_dollars = TRUE;
    1319            3482 :     spec->main_param = tmp_num;
    1320                 :   }
    1321                 : 
    1322                 :   /* process flags */
    1323          862475 :   while (TRUE)
    1324                 :   {
    1325          862475 :     switch (*fmt)
    1326                 :     {
    1327           44242 :       case '-':  spec->flags |= LEFT;         break;
    1328           11339 :       case '+':  spec->flags |= PLUS;         break;
    1329            9423 :       case ' ':  spec->flags |= SPACE;        break;
    1330           38990 :       case '#':  spec->flags |= SPECIAL;      break;
    1331           69462 :       case '0':  spec->flags |= ZEROPAD;      break;
    1332           18337 :       case '\'': spec->flags |= THOUSAND_SEP; break;
    1333              65 :       case 'I':  spec->flags |= ALT_DIGITS;   break;
    1334                 : 
    1335                 :       default:
    1336          191858 :         goto got_flags;
    1337                 :     }
    1338          191858 :     ++fmt;
    1339                 :   }
    1340                 :  got_flags:
    1341                 :   
    1342                 :   /* get field width */
    1343          670617 :   if (VSTR__ADD_FMT_ISDIGIT(*fmt))
    1344                 :   {
    1345          108654 :     tmp_num = VSTR__ADD_FMT_STRTOL(fmt);
    1346                 : 
    1347                 :    use_field_width:
    1348          142305 :     spec->field_width_usr = TRUE;
    1349          142305 :     spec->field_width = tmp_num;
    1350          142305 :     ASSERT(tmp_num >= 0);
    1351                 :   }
    1352          561963 :   else if (*fmt == '*')
    1353                 :   {
    1354           18162 :     const char *dollar_start = fmt;
    1355                 : 
    1356           18162 :     spec->field_width_usr = TRUE;
    1357                 : 
    1358           18162 :     ++fmt;
    1359           18162 :     tmp_num = 0;
    1360           18162 :     if (VSTR__ADD_FMT_ISDIGIT(*fmt))
    1361            3088 :       tmp_num = VSTR__ADD_FMT_STRTOL(fmt);
    1362                 : 
    1363           18162 :     if (*fmt != '$')
    1364                 :     {
    1365           15074 :       fmt = dollar_start + 1;
    1366           15074 :       spec->field_width_param = ++*params;
    1367                 :     }
    1368                 :     else
    1369                 :     {
    1370            3088 :       ++fmt;
    1371            3088 :       spec->field_width_param = tmp_num;
    1372                 :     }
    1373                 :   }
    1374                 : 
    1375                 :   /* get the precision */
    1376          704268 :   if (*fmt == '.')
    1377                 :   {
    1378           79360 :     spec->flags |= PREC_USR;
    1379                 : 
    1380           79360 :     ++fmt;
    1381           79360 :     if (VSTR__ADD_FMT_ISDIGIT(*fmt))
    1382                 :     {
    1383           35750 :       tmp_num = VSTR__ADD_FMT_STRTOL(fmt);
    1384                 : 
    1385           35750 :       spec->precision = tmp_num;
    1386           35750 :       ASSERT(tmp_num >= 0);
    1387                 :     }
    1388           43610 :     else if (*fmt == '*')
    1389                 :     {
    1390             472 :       const char *dollar_start = fmt;
    1391             472 :       ++fmt;
    1392                 : 
    1393             472 :       tmp_num = 0;
    1394             472 :       if (VSTR__ADD_FMT_ISDIGIT(*fmt))
    1395              30 :         tmp_num = VSTR__ADD_FMT_STRTOL(fmt);
    1396                 : 
    1397             472 :       if (*fmt != '$')
    1398                 :       {
    1399             442 :         fmt = dollar_start + 1;
    1400             442 :         spec->precision_param = ++*params;
    1401                 :       }
    1402                 :       else
    1403                 :       {
    1404              30 :         ++fmt;
    1405              30 :         spec->precision_param = tmp_num;
    1406                 :       }
    1407                 :     }
    1408                 :   }
    1409                 : 
    1410          704268 :   return (fmt);
    1411                 : }
    1412                 : 
    1413                 : static size_t vstr__add_vfmt(Vstr_base *base, size_t pos, unsigned int userfmt,
    1414                 :                              const char *fmt, va_list ap)
    1415          253537 : {
    1416          253537 :   int sve_errno = errno;
    1417          253537 :   size_t start_pos = pos + 1;
    1418          253537 :   size_t orig_len = 0;
    1419          253537 :   size_t pos_diff = 0;
    1420          253537 :   unsigned int params = 0;
    1421          253537 :   unsigned int have_dollars = FALSE; /* have posix %2$d etc. stuff */
    1422          253537 :   unsigned char fmt_usr_escape = 0;
    1423          253537 :   unsigned int orig_malloc_bad = FALSE;
    1424                 :   
    1425          253537 :   ASSERT_RET(!(!base || !fmt || (pos > base->len)), 0);
    1426                 : 
    1427          253529 :   orig_len = base->len;
    1428                 :   
    1429                 :   /* so things can use this as a flag */
    1430          253529 :   orig_malloc_bad = base->conf->malloc_bad;
    1431          253529 :   base->conf->malloc_bad = FALSE;
    1432                 : 
    1433                 :   /* this will be correct as you add chars */
    1434          253529 :   pos_diff = base->len - pos;
    1435                 : 
    1436          253529 :   if (userfmt)
    1437          219209 :     fmt_usr_escape = base->conf->fmt_usr_escape;
    1438                 :   
    1439         1571566 :   while (*fmt)
    1440                 :   {
    1441         1318079 :     const char *fmt_orig = fmt;
    1442         1318079 :     struct Vstr__fmt_spec *spec = NULL;
    1443                 :     
    1444         1318079 :     if (!base->conf->vstr__fmt_spec_make && !vstr__fmt_add_spec(base->conf))
    1445              31 :       goto failed_alloc;
    1446                 :     
    1447         1318048 :     spec = base->conf->vstr__fmt_spec_make;
    1448         1318048 :     vstr__fmt_init_spec(spec);
    1449                 : 
    1450         1318048 :     assert(VSTR__FMT_ANAL_ZERO &&
    1451                 :            (spec->field_width_usr || !spec->field_width));
    1452         1318048 :     assert(VSTR__FMT_ANAL_ZERO &&
    1453                 :            ((spec->flags & PREC_USR) || !spec->precision));
    1454                 : 
    1455         1318048 :     if ((*fmt != '%') && (*fmt != fmt_usr_escape))
    1456                 :     {
    1457          613720 :       char *next_escape = strchr(fmt, '%');
    1458                 : 
    1459          613720 :       spec->fmt_code = 's';
    1460          613720 :       spec->u.data_ptr = (char *)fmt;
    1461                 : 
    1462          613720 :       if (fmt_usr_escape)
    1463                 :       { /* find first of the two escapes */
    1464          424416 :         char *next_usr_escape = strchr(fmt, fmt_usr_escape);
    1465          424416 :         if (next_usr_escape &&
    1466                 :             (!next_escape || (next_usr_escape < next_escape)))
    1467          169903 :           next_escape = next_usr_escape;
    1468                 :       }
    1469                 : 
    1470          613720 :       if (next_escape)
    1471                 :       {
    1472          465990 :         size_t len = next_escape - fmt;
    1473          465990 :         spec->precision = len;
    1474          465990 :         spec->flags |= PREC_USR;
    1475          465990 :         fmt = fmt + len;
    1476                 :       }
    1477                 :       else
    1478          147730 :         fmt = "";
    1479                 : 
    1480          613720 :       VSTR__FMT_MV_SPEC(base->conf, FALSE);
    1481                 : 
    1482          613720 :       continue;
    1483                 :     }
    1484                 : 
    1485          704328 :     if (fmt[0] == fmt[1])
    1486                 :     {
    1487              60 :       spec->u.data_c = fmt[0];
    1488              60 :       spec->fmt_code = 'c';
    1489              60 :       VSTR__FMT_MV_SPEC(base->conf, FALSE);
    1490              60 :       fmt += 2; /* skip escs */
    1491              60 :       continue;
    1492                 :     }
    1493          704268 :     assert(fmt_orig == fmt);
    1494          704268 :     ++fmt; /* skip esc */
    1495                 : 
    1496          704268 :     fmt = vstr__add_fmt_spec(fmt, spec, &params, &have_dollars);
    1497                 : 
    1498          704268 :     assert(VSTR__FMT_ANAL_ZERO &&
    1499                 :            (spec->field_width_usr || !spec->field_width));
    1500          704268 :     assert(VSTR__FMT_ANAL_ZERO &&
    1501                 :            ((spec->flags & PREC_USR) || !spec->precision));
    1502                 :     
    1503          704268 :     if (fmt_usr_escape && (*fmt_orig == fmt_usr_escape))
    1504                 :     {
    1505          220465 :       const char *fmt_end = vstr__add_fmt_usr_esc(base->conf, fmt,
    1506          220465 :                                                   spec, &params);
    1507                 :       
    1508          220465 :       if (!fmt_end)
    1509              11 :         goto failed_alloc;
    1510          220454 :       else if (fmt_end == fmt)
    1511                 :       {
    1512            4693 :         if (fmt_usr_escape == '%')
    1513            4685 :           goto vstr__fmt_sys_escapes;
    1514                 :         
    1515               8 :         assert(FALSE); /* $$ etc. is already done before here */
    1516           69554 :         fmt = ""; /* should end because we don't know if the types are
    1517                 :                    * screwed up */
    1518                 :       }
    1519                 :       else
    1520          215761 :         fmt = fmt_end;
    1521          215761 :       continue;
    1522                 :     }
    1523                 :     
    1524                 :    vstr__fmt_sys_escapes:
    1525                 :     /* get width of type */
    1526          488488 :     switch (*fmt)
    1527                 :     {
    1528                 :       case 'h':
    1529             399 :         ++fmt;
    1530             399 :         if (*fmt == 'h')
    1531                 :         {
    1532             205 :           ++fmt;
    1533             205 :           spec->int_type = VSTR_TYPE_FMT_UCHAR;
    1534                 :         }
    1535                 :         else
    1536             194 :           spec->int_type = VSTR_TYPE_FMT_USHORT;
    1537             194 :         break;
    1538                 :       case 'l':
    1539            6140 :         ++fmt;
    1540            6140 :         if (*fmt == 'l')
    1541                 :         {
    1542             135 :           ++fmt;
    1543             135 :           spec->int_type = VSTR_TYPE_FMT_ULONG_LONG;
    1544                 :         }
    1545                 :         else
    1546            6005 :           spec->int_type = VSTR_TYPE_FMT_ULONG;
    1547            6005 :         break;
    1548           65807 :       case 'L': ++fmt; spec->int_type = VSTR_TYPE_FMT_ULONG_LONG; break;
    1549             210 :       case 'z': ++fmt; spec->int_type = VSTR_TYPE_FMT_SIZE_T;     break;
    1550             115 :       case 't': ++fmt; spec->int_type = VSTR_TYPE_FMT_PTRDIFF_T;  break;
    1551           69005 :       case 'j': ++fmt; spec->int_type = VSTR_TYPE_FMT_UINTMAX_T;  break;
    1552                 : 
    1553                 :       default:
    1554          488488 :         break;
    1555                 :     }
    1556                 : 
    1557          488488 :     spec->fmt_code = *fmt;
    1558          488488 :     switch (*fmt)
    1559                 :     {
    1560                 :       case 'c':
    1561            5801 :         if (spec->int_type != VSTR_TYPE_FMT_ULONG) /* %lc == %C */
    1562            5440 :           break;
    1563                 :         /* FALL THROUGH */
    1564                 : 
    1565                 :       case 'C':
    1566             479 :         spec->fmt_code = 'C';
    1567             479 :         break;
    1568                 : 
    1569                 :       case 'm':
    1570              19 :         ASSERT(!spec->main_param); /* it's possible, but stupid, with i18n */
    1571              19 :         spec->main_param = 0;
    1572              19 :         break;
    1573                 : 
    1574                 :       case 's':
    1575          124746 :         if (spec->int_type != VSTR_TYPE_FMT_ULONG) /* %ls == %S */
    1576          124291 :           break;
    1577                 :         /* FALL THROUGH */
    1578                 : 
    1579                 :       case 'S':
    1580             569 :         spec->fmt_code = 'S';
    1581             569 :         break;
    1582                 : 
    1583                 :       case 'd':
    1584                 :       case 'i':
    1585           25687 :         spec->flags |= SIGN;
    1586                 :       case 'u':
    1587           25687 :         break;
    1588                 : 
    1589                 :       case 'X':
    1590           13223 :         spec->flags |= LARGE;
    1591                 :       case 'x':
    1592           26562 :         spec->num_base = 16;
    1593           26562 :         break;
    1594                 : 
    1595                 :       case 'o':
    1596           13157 :         spec->num_base = 8;
    1597           13157 :         break;
    1598                 : 
    1599                 :       case 'p':
    1600               5 :         spec->num_base = 16;
    1601               5 :         spec->int_type = VSTR_TYPE_FMT_PTR_VOID;
    1602               5 :         spec->flags |= SPECIAL;
    1603               5 :         break;
    1604                 : 
    1605                 :       case 'n':
    1606           80659 :         break;
    1607                 : 
    1608                 :       case 'A': /* print like [-]x.xxxPxx -- in hex using ABCDEF */
    1609                 :       case 'E': /* use big E instead */
    1610                 :       case 'F': /* print like an int - upper case infinity/nan */
    1611                 :       case 'G': /* use the smallest of E and F */
    1612           80659 :         spec->flags |= LARGE;
    1613                 :       case 'a': /* print like [-]x.xxxpxx -- in hex using abcdef */
    1614                 :       case 'e': /* print like [-]x.xxxexx */
    1615                 :       case 'f': /* print like an int */
    1616                 :       case 'g': /* use the smallest of e and f */
    1617           80659 :         break;
    1618                 : 
    1619                 :       default:
    1620               4 :         assert(FALSE);
    1621          151457 :         fmt = "";
    1622          151457 :         continue;
    1623                 :     }
    1624                 : 
    1625          488484 :     VSTR__FMT_MV_SPEC(base->conf, TRUE);
    1626          488484 :     ++fmt;
    1627                 :   }
    1628                 :   
    1629          253487 :   if (!vstr__fmt_fillin_spec(base->conf, ap, have_dollars))
    1630               4 :     goto failed_alloc;
    1631                 :   
    1632          253483 :   errno = sve_errno;
    1633          253483 :   if (!vstr__fmt_write_spec(base, pos_diff, orig_len, sve_errno))
    1634           32159 :     goto failed_write_spec;
    1635                 :   
    1636                 :   /* restore the original state of the bad malloc flag... */
    1637          221324 :   base->conf->malloc_bad = orig_malloc_bad;
    1638                 :   
    1639          221324 :   return (base->len - orig_len);
    1640                 : 
    1641                 :  failed_write_spec:
    1642                 : 
    1643           32159 :   if (base->len - orig_len)
    1644           20107 :     vstr_del(base, start_pos, base->len - orig_len);
    1645                 : 
    1646           20107 :   if (0) /* already done in write_spec */
    1647                 :   {
    1648                 :    failed_alloc:
    1649              46 :     if (base->conf->vstr__fmt_spec_list_end)
    1650              43 :       base->conf->vstr__fmt_spec_list_end->next = base->conf->vstr__fmt_spec_make;
    1651              46 :     base->conf->vstr__fmt_spec_make = base->conf->vstr__fmt_spec_list_beg;
    1652              46 :     base->conf->vstr__fmt_spec_list_beg = NULL;
    1653              46 :     base->conf->vstr__fmt_spec_list_end = NULL;
    1654                 :   }
    1655           32205 :   base->conf->malloc_bad |= orig_malloc_bad;
    1656                 : 
    1657           32205 :   return (0);
    1658                 : }
    1659                 : 
    1660                 : size_t vstr_add_vfmt(Vstr_base *base, size_t pos,
    1661                 :                         const char *fmt, va_list ap)
    1662           80713 : {
    1663           80713 :   return (vstr__add_vfmt(base, pos, TRUE,  fmt, ap));
    1664                 : }
    1665                 : 
    1666                 : size_t vstr_add_vsysfmt(Vstr_base *base, size_t pos,
    1667                 :                            const char *fmt, va_list ap)
    1668            5765 : {
    1669            5765 :   return (vstr__add_vfmt(base, pos, FALSE, fmt, ap));
    1670                 : }
    1671                 : 
    1672                 : size_t vstr_add_fmt(Vstr_base *base, size_t pos, const char *fmt, ...)
    1673          138504 : {
    1674          138504 :   size_t len = 0;
    1675          138504 :   va_list ap;
    1676                 :   
    1677          138504 :   va_start(ap, fmt);
    1678                 : 
    1679          138504 :   len =   vstr__add_vfmt(base, pos, TRUE,  fmt, ap);
    1680                 : 
    1681          138504 :   va_end(ap);
    1682                 : 
    1683          138504 :   return (len);
    1684                 : }
    1685                 : 
    1686                 : size_t vstr_add_sysfmt(Vstr_base *base, size_t pos, const char *fmt, ...)
    1687           28555 : {
    1688           28555 :   size_t len = 0;
    1689           28555 :   va_list ap;
    1690                 : 
    1691           28555 :   va_start(ap, fmt);
    1692                 : 
    1693           28555 :   len =   vstr__add_vfmt(base, pos, FALSE, fmt, ap);
    1694                 : 
    1695           28555 :   va_end(ap);
    1696                 : 
    1697           28555 :   return (len);
    1698                 : }
    1699                 : 

Generated by: LTP GCOV extension version 1.1