(root)/
glibc-2.38/
stdio-common/
vfprintf-process-arg.c
       1  /* Argument-processing fragment for vfprintf.
       2     Copyright (C) 1991-2023 Free Software Foundation, Inc.
       3     This file is part of the GNU C Library.
       4  
       5     The GNU C 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.1 of the License, or (at your option) any later version.
       9  
      10     The GNU C 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 the GNU C Library; if not, see
      17     <https://www.gnu.org/licenses/>.  */
      18  
      19  /* This file is included twice from vfprintf-internal.c, for standard
      20     and GNU-style positional (%N$) arguments.  Before that,
      21     process_arg_int etc. macros have to be defined to extract one
      22     argument of the appropriate type, in addition to the file-specific
      23     macros in vfprintf-internal.c.  */
      24  
      25  {
      26    /* Start real work.  We know about all flags and modifiers and
      27       now process the wanted format specifier.  */
      28  LABEL (form_percent):
      29    /* Write a literal "%".  */
      30    Xprintf_buffer_putc (buf, L_('%'));
      31    break;
      32  
      33  LABEL (form_integer):
      34    /* Signed decimal integer.  */
      35    base = 10;
      36  
      37    if (is_longlong)
      38      {
      39        long long int signed_number = process_arg_long_long_int ();
      40        is_negative = signed_number < 0;
      41        number.longlong = is_negative ? (- signed_number) : signed_number;
      42  
      43        goto LABEL (longlong_number);
      44      }
      45    else
      46      {
      47        long int signed_number;
      48        if (is_long_num)
      49          signed_number = process_arg_long_int ();
      50        else if (is_char)
      51          signed_number = (signed char) process_arg_unsigned_int ();
      52        else if (!is_short)
      53          signed_number = process_arg_int ();
      54        else
      55          signed_number = (short int) process_arg_unsigned_int ();
      56  
      57        is_negative = signed_number < 0;
      58        number.word = is_negative ? (- signed_number) : signed_number;
      59  
      60        goto LABEL (number);
      61      }
      62    /* NOTREACHED */
      63  
      64  LABEL (form_unsigned):
      65    /* Unsigned decimal integer.  */
      66    base = 10;
      67    goto LABEL (unsigned_number);
      68    /* NOTREACHED */
      69  
      70  LABEL (form_octal):
      71    /* Unsigned octal integer.  */
      72    base = 8;
      73    goto LABEL (unsigned_number);
      74    /* NOTREACHED */
      75  
      76  LABEL (form_hexa):
      77    /* Unsigned hexadecimal integer.  */
      78    base = 16;
      79    goto LABEL (unsigned_number);
      80    /* NOTREACHED */
      81  
      82  LABEL (form_binary):
      83    /* Unsigned binary integer.  */
      84    base = 2;
      85    goto LABEL (unsigned_number);
      86    /* NOTREACHED */
      87  
      88  LABEL (unsigned_number):      /* Unsigned number of base BASE.  */
      89  
      90    /* ISO specifies the `+' and ` ' flags only for signed
      91       conversions.  */
      92    is_negative = 0;
      93    showsign = 0;
      94    space = 0;
      95  
      96    if (is_longlong)
      97      {
      98        number.longlong = process_arg_unsigned_long_long_int ();
      99  
     100        LABEL (longlong_number):
     101        if (prec < 0)
     102          /* Supply a default precision if none was given.  */
     103          prec = 1;
     104        else
     105          /* We have to take care for the '0' flag.  If a precision
     106             is given it must be ignored.  */
     107          pad = L_(' ');
     108  
     109        /* If the precision is 0 and the number is 0 nothing has to
     110           be written for the number, except for the 'o' format in
     111           alternate form.  */
     112        if (prec == 0 && number.longlong == 0)
     113          {
     114            string = workend;
     115            if (base == 8 && alt)
     116              *--string = L_('0');
     117          }
     118        else
     119          /* Put the number in WORK.  */
     120          string = _itoa (number.longlong, workend, base, spec == L_('X'));
     121        /* Simplify further test for num != 0.  */
     122        number.word = number.longlong != 0;
     123      }
     124    else
     125      {
     126        if (is_long_num)
     127          number.word = process_arg_unsigned_long_int ();
     128        else if (is_char)
     129          number.word = (unsigned char) process_arg_unsigned_int ();
     130        else if (!is_short)
     131          number.word = process_arg_unsigned_int ();
     132        else
     133          number.word = (unsigned short int) process_arg_unsigned_int ();
     134  
     135        LABEL (number):
     136        if (prec < 0)
     137          /* Supply a default precision if none was given.  */
     138          prec = 1;
     139        else
     140          /* We have to take care for the '0' flag.  If a precision
     141             is given it must be ignored.  */
     142          pad = L_(' ');
     143  
     144        /* If the precision is 0 and the number is 0 nothing has to
     145           be written for the number, except for the 'o' format in
     146           alternate form.  */
     147        if (prec == 0 && number.word == 0)
     148          {
     149            string = workend;
     150            if (base == 8 && alt)
     151              *--string = L_('0');
     152          }
     153        else
     154          /* Put the number in WORK.  */
     155          string = _itoa_word (number.word, workend, base,
     156                               spec == L_('X'));
     157      }
     158  
     159    /* Grouping is also used for outdigits translation.  */
     160    struct grouping_iterator iter;
     161    bool number_slow_path = group || (use_outdigits && base == 10);
     162    if (group)
     163      __grouping_iterator_init (&iter, LC_NUMERIC, _NL_CURRENT_LOCALE,
     164                                workend - string);
     165    else if (use_outdigits && base == 10)
     166      __grouping_iterator_init_none (&iter, workend - string);
     167  
     168    int number_length;
     169  #ifndef COMPILE_WPRINTF
     170    if (use_outdigits && base == 10)
     171      number_length = __translated_number_width (_NL_CURRENT_LOCALE,
     172                                                 string, workend);
     173    else
     174      number_length = workend - string;
     175    if (group)
     176      number_length += iter.separators * strlen (thousands_sep);
     177  #else
     178    number_length = workend - string;
     179    /* All wide separators have length 1.  */
     180    if (group && thousands_sep != L'\0')
     181      number_length += iter.separators;
     182  #endif
     183  
     184    /* The marker comes right before the number, but is not subject
     185       to grouping.  */
     186    bool octal_marker = (prec <= number_length && number.word != 0
     187                         && alt && base == 8);
     188  
     189    /* At this point prec_inc is the additional bytes required for the
     190       specified precision.  It is 0 if the precision would not have
     191       required additional bytes i.e. the number of input digits is more
     192       than the precision.  It is greater than zero if the precision is
     193       more than the number of digits without grouping (precision only
     194       considers digits).  */
     195    unsigned int prec_inc = MAX (0, prec - (workend - string));
     196  
     197    if (!left)
     198      {
     199        width -= number_length + prec_inc;
     200  
     201        if (number.word != 0 && alt && (base == 16 || base == 2))
     202          /* Account for 0X, 0x, 0B or 0b hex or binary marker.  */
     203          width -= 2;
     204  
     205        if (octal_marker)
     206          --width;
     207  
     208        if (is_negative || showsign || space)
     209          --width;
     210  
     211        if (pad == L_(' '))
     212          {
     213            Xprintf_buffer_pad (buf, L_(' '), width);
     214            width = 0;
     215          }
     216  
     217        if (is_negative)
     218          Xprintf_buffer_putc (buf, L_('-'));
     219        else if (showsign)
     220          Xprintf_buffer_putc (buf, L_('+'));
     221        else if (space)
     222          Xprintf_buffer_putc (buf, L_(' '));
     223  
     224        if (number.word != 0 && alt && (base == 16 || base == 2))
     225          {
     226            Xprintf_buffer_putc (buf, L_('0'));
     227            Xprintf_buffer_putc (buf, spec);
     228          }
     229  
     230        width += prec_inc;
     231        Xprintf_buffer_pad (buf, L_('0'), width);
     232  
     233        if (octal_marker)
     234          Xprintf_buffer_putc (buf, L_('0'));
     235  
     236        if (number_slow_path)
     237          group_number (buf, &iter, string, workend, thousands_sep,
     238                        use_outdigits && base == 10);
     239        else
     240          Xprintf_buffer_write (buf, string, workend - string);
     241  
     242        break;
     243      }
     244    else
     245      {
     246        /* Perform left justification adjustments.  */
     247  
     248        if (is_negative)
     249          {
     250            Xprintf_buffer_putc (buf, L_('-'));
     251            --width;
     252          }
     253        else if (showsign)
     254          {
     255            Xprintf_buffer_putc (buf, L_('+'));
     256            --width;
     257          }
     258        else if (space)
     259          {
     260            Xprintf_buffer_putc (buf, L_(' '));
     261            --width;
     262          }
     263  
     264        if (number.word != 0 && alt && (base == 16 || base == 2))
     265          {
     266            Xprintf_buffer_putc (buf, L_('0'));
     267            Xprintf_buffer_putc (buf, spec);
     268            width -= 2;
     269          }
     270  
     271        if (octal_marker)
     272  	--width;
     273  
     274        /* Adjust the width by subtracting the number of bytes
     275           required to represent the number with grouping characters
     276  	 (NUMBER_LENGTH) and any additional bytes required for
     277  	 precision.  */
     278        width -= number_length + prec_inc;
     279  
     280        Xprintf_buffer_pad (buf, L_('0'), prec_inc);
     281  
     282        if (octal_marker)
     283          Xprintf_buffer_putc (buf, L_('0'));
     284  
     285        if (number_slow_path)
     286          group_number (buf, &iter, string, workend, thousands_sep,
     287                        use_outdigits && base == 10);
     288        else
     289          Xprintf_buffer_write (buf, string, workend - string);
     290  
     291        Xprintf_buffer_pad (buf, L_(' '), width);
     292        break;
     293      }
     294  
     295  LABEL (form_pointer):
     296    /* Generic pointer.  */
     297    {
     298      const void *ptr = process_arg_pointer ();
     299      if (ptr != NULL)
     300        {
     301          /* If the pointer is not NULL, write it as a %#x spec.  */
     302          base = 16;
     303          number.word = (unsigned long int) ptr;
     304          is_negative = 0;
     305          alt = 1;
     306          group = 0;
     307          spec = L_('x');
     308          goto LABEL (number);
     309        }
     310      else
     311        {
     312          /* Write "(nil)" for a nil pointer.  */
     313          string = (CHAR_T *) L_("(nil)");
     314          /* Make sure the full string "(nil)" is printed.  */
     315          if (prec < 5)
     316            prec = 5;
     317          /* This is a wide string iff compiling wprintf.  */
     318          is_long = sizeof (CHAR_T) > 1;
     319          goto LABEL (print_string);
     320        }
     321    }
     322    /* NOTREACHED */
     323  
     324  LABEL (form_number):
     325    if ((mode_flags & PRINTF_FORTIFY) != 0)
     326      {
     327        if (! readonly_format)
     328          {
     329            extern int __readonly_area (const void *, size_t)
     330              attribute_hidden;
     331            readonly_format
     332              = __readonly_area (format, ((STR_LEN (format) + 1)
     333                                          * sizeof (CHAR_T)));
     334          }
     335        if (readonly_format < 0)
     336          __libc_fatal ("*** %n in writable segment detected ***\n");
     337      }
     338    /* Answer the count of characters written.  */
     339    void *ptrptr = process_arg_pointer ();
     340    unsigned int written = Xprintf_buffer_done (buf);
     341    if (is_longlong)
     342      *(long long int *) ptrptr = written;
     343    else if (is_long_num)
     344      *(long int *) ptrptr = written;
     345    else if (is_char)
     346      *(char *) ptrptr = written;
     347    else if (!is_short)
     348      *(int *) ptrptr = written;
     349    else
     350      *(short int *) ptrptr = written;
     351    break;
     352  
     353  LABEL (form_strerror):
     354    /* Print description of error ERRNO.  */
     355    if (alt)
     356      string = (CHAR_T *) __get_errname (save_errno);
     357    else
     358      string = (CHAR_T *) __strerror_r (save_errno, (char *) work_buffer,
     359                                        WORK_BUFFER_SIZE * sizeof (CHAR_T));
     360    if (string == NULL)
     361      {
     362        /* Print as a decimal number. */
     363        base = 10;
     364        is_negative = save_errno < 0;
     365        number.word = save_errno;
     366        if (is_negative)
     367          number.word = -number.word;
     368        goto LABEL (number);
     369      }
     370    else
     371      {
     372        is_long = 0;  /* This is no wide-char string.  */
     373        goto LABEL (print_string);
     374      }
     375  
     376  LABEL (form_character):
     377    /* Character.  */
     378    if (is_long)
     379      goto LABEL (form_wcharacter);
     380    --width;  /* Account for the character itself.  */
     381    if (!left)
     382      Xprintf_buffer_pad (buf, L_(' '), width);
     383  #ifdef COMPILE_WPRINTF
     384    __wprintf_buffer_putc (buf, __btowc ((unsigned char) /* Promoted. */
     385                                         process_arg_int ()));
     386  #else
     387    __printf_buffer_putc (buf, (unsigned char) /* Promoted.  */
     388                          process_arg_int ());
     389  #endif
     390    if (left)
     391      Xprintf_buffer_pad (buf, L_(' '), width);
     392    break;
     393  
     394  LABEL (form_string):
     395    {
     396      size_t len;
     397  
     398      /* The string argument could in fact be `char *' or `wchar_t *'.
     399         But this should not make a difference here.  */
     400  #ifdef COMPILE_WPRINTF
     401      string = (CHAR_T *) process_arg_wstring ();
     402  #else
     403      string = (CHAR_T *) process_arg_string ();
     404  #endif
     405      /* Entry point for printing other strings.  */
     406      LABEL (print_string):
     407  
     408      if (string == NULL)
     409        {
     410          /* Write "(null)" if there's space.  */
     411          if (prec == -1 || prec >= (int) array_length (null) - 1)
     412            {
     413              string = (CHAR_T *) null;
     414              len = array_length (null) - 1;
     415            }
     416          else
     417            {
     418              string = (CHAR_T *) L"";
     419              len = 0;
     420            }
     421        }
     422      else if (!is_long && spec != L_('S'))
     423        {
     424  #ifdef COMPILE_WPRINTF
     425          outstring_converted_wide_string (buf, (const char *) string,
     426                                           prec, width, left);
     427          /* The padding has already been written.  */
     428          break;
     429  #else
     430          if (prec != -1)
     431            /* Search for the end of the string, but don't search past
     432               the length (in bytes) specified by the precision.  */
     433            len = __strnlen (string, prec);
     434          else
     435            len = strlen (string);
     436  #endif
     437        }
     438      else
     439        {
     440  #ifdef COMPILE_WPRINTF
     441          if (prec != -1)
     442            /* Search for the end of the string, but don't search past
     443               the length specified by the precision.  */
     444            len = __wcsnlen (string, prec);
     445          else
     446            len = __wcslen (string);
     447  #else
     448          outstring_converted_wide_string (buf, (const wchar_t *) string,
     449                                           prec, width, left);
     450          /* The padding has already been written.  */
     451          break;
     452  #endif
     453        }
     454  
     455      if ((width -= len) < 0)
     456        {
     457          Xprintf_buffer_write (buf, string, len);
     458          break;
     459        }
     460  
     461      if (!left)
     462        Xprintf_buffer_pad (buf, L_(' '), width);
     463      Xprintf_buffer_write (buf, string, len);
     464      if (left)
     465        Xprintf_buffer_pad (buf, L_(' '), width);
     466    }
     467    break;
     468  
     469  #ifdef COMPILE_WPRINTF
     470  LABEL (form_wcharacter):
     471    {
     472      /* Wide character.  */
     473      --width;
     474      if (!left)
     475        Xprintf_buffer_pad (buf, L_(' '), width);
     476      Xprintf_buffer_putc (buf, process_arg_wchar_t ());
     477      if (left)
     478        Xprintf_buffer_pad (buf, L_(' '), width);
     479    }
     480    break;
     481  
     482  #else /* !COMPILE_WPRINTF */
     483  LABEL (form_wcharacter):
     484    {
     485      /* Wide character.  */
     486      char wcbuf[MB_LEN_MAX];
     487      mbstate_t mbstate;
     488      size_t len;
     489  
     490      memset (&mbstate, '\0', sizeof (mbstate_t));
     491      len = __wcrtomb (wcbuf, process_arg_wchar_t (), &mbstate);
     492      if (len == (size_t) -1)
     493        {
     494          /* Something went wrong during the conversion.  Bail out.  */
     495          __printf_buffer_mark_failed (buf);
     496          goto all_done;
     497        }
     498      width -= len;
     499      if (!left)
     500        Xprintf_buffer_pad (buf, L_(' '), width);
     501      Xprintf_buffer_write (buf, wcbuf, len);
     502      if (left)
     503        Xprintf_buffer_pad (buf, L_(' '), width);
     504    }
     505    break;
     506  #endif /* !COMPILE_WPRINTF */
     507  }