about summary refs log tree commit diff
path: root/stdio-common/printf-parse.h
blob: 362cce1ead04827436cd2c933c5dee3cf6fe1c20 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
/* Internal header for parsing printf format strings.
   Copyright (C) 1995-2022 Free Software Foundation, Inc.
   This file is part of th GNU C Library.

   The GNU C Library is free software; you can redistribute it and/or
   modify it under the terms of the GNU Lesser General Public
   License as published by the Free Software Foundation; either
   version 2.1 of the License, or (at your option) any later version.

   The GNU C Library is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   Lesser General Public License for more details.

   You should have received a copy of the GNU Lesser General Public
   License along with the GNU C Library; if not, see
   <https://www.gnu.org/licenses/>.  */

#include <printf.h>
#include <stdint.h>
#include <stddef.h>
#include <string.h>
#include <wchar.h>


struct printf_spec
  {
    /* Information parsed from the format spec.  */
    struct printf_info info;

    /* Pointers into the format string for the end of this format
       spec and the next (or to the end of the string if no more).  */
    const UCHAR_T *end_of_fmt, *next_fmt;

    /* Position of arguments for precision and width, or -1 if `info' has
       the constant value.  */
    int prec_arg, width_arg;

    int data_arg;		/* Position of data argument.  */
    int data_arg_type;		/* Type of first argument.  */
    /* Number of arguments consumed by this format specifier.  */
    size_t ndata_args;
    /* Size of the parameter for PA_USER type.  */
    int size;
  };


/* The various kinds off arguments that can be passed to printf.  */
union printf_arg
  {
    wchar_t pa_wchar;
    int pa_int;
    long int pa_long_int;
    long long int pa_long_long_int;
    unsigned int pa_u_int;
    unsigned long int pa_u_long_int;
    unsigned long long int pa_u_long_long_int;
    double pa_double;
    long double pa_long_double;
#if __HAVE_FLOAT128_UNLIKE_LDBL
    _Float128 pa_float128;
#endif
    const char *pa_string;
    const wchar_t *pa_wstring;
    void *pa_pointer;
    void *pa_user;
  };


#ifndef DONT_NEED_READ_INT
/* Read a simple integer from a string and update the string pointer.
   It is assumed that the first character is a digit.  */
static int
read_int (const UCHAR_T * *pstr)
{
  int retval = **pstr - L_('0');

  while (ISDIGIT (*++(*pstr)))
    if (retval >= 0)
      {
	if (INT_MAX / 10 < retval)
	  retval = -1;
	else
	  {
	    int digit = **pstr - L_('0');

	    retval *= 10;
	    if (INT_MAX - digit < retval)
	      retval = -1;
	    else
	      retval += digit;
	  }
      }

  return retval;
}
#endif


/* Find the next spec in FORMAT, or the end of the string.  Returns
   a pointer into FORMAT, to a '%' or a '\0'.  */
__extern_always_inline const unsigned char *
__find_specmb (const unsigned char *format)
{
  return (const unsigned char *) __strchrnul ((const char *) format, '%');
}

__extern_always_inline const unsigned int *
__find_specwc (const unsigned int *format)
{
  return (const unsigned int *) __wcschrnul ((const wchar_t *) format, L'%');
}


/* FORMAT must point to a '%' at the beginning of a spec.  Fills in *SPEC
   with the parsed details.  POSN is the number of arguments already
   consumed.  At most MAXTYPES - POSN types are filled in TYPES.  Return
   the number of args consumed by this spec; *MAX_REF_ARG is updated so it
   remains the highest argument index used.  */
extern size_t __parse_one_specmb (const unsigned char *format, size_t posn,
				  struct printf_spec *spec,
				  size_t *max_ref_arg) attribute_hidden;

extern size_t __parse_one_specwc (const unsigned int *format, size_t posn,
				  struct printf_spec *spec,
				  size_t *max_ref_arg) attribute_hidden;



/* This variable is defined in reg-modifier.c.  */
struct printf_modifier_record;
extern struct printf_modifier_record **__printf_modifier_table
     attribute_hidden;

/* Handle registered modifiers.  */
extern int __handle_registered_modifier_mb (const unsigned char **format,
					    struct printf_info *info)
     attribute_hidden;
extern int __handle_registered_modifier_wc (const unsigned int **format,
					    struct printf_info *info)
     attribute_hidden;