xref: /openbsd/gnu/usr.bin/gcc/gcc/c-format.c (revision e8f4cb76)
1c87b03e5Sespie /* Check calls to formatted I/O functions (-Wformat).
2c87b03e5Sespie    Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000,
3c87b03e5Sespie    2001, 2002 Free Software Foundation, Inc.
4c87b03e5Sespie 
5c87b03e5Sespie This file is part of GCC.
6c87b03e5Sespie 
7c87b03e5Sespie GCC is free software; you can redistribute it and/or modify it under
8c87b03e5Sespie the terms of the GNU General Public License as published by the Free
9c87b03e5Sespie Software Foundation; either version 2, or (at your option) any later
10c87b03e5Sespie version.
11c87b03e5Sespie 
12c87b03e5Sespie GCC is distributed in the hope that it will be useful, but WITHOUT ANY
13c87b03e5Sespie WARRANTY; without even the implied warranty of MERCHANTABILITY or
14c87b03e5Sespie FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
15c87b03e5Sespie for more details.
16c87b03e5Sespie 
17c87b03e5Sespie You should have received a copy of the GNU General Public License
18c87b03e5Sespie along with GCC; see the file COPYING.  If not, write to the Free
19c87b03e5Sespie Software Foundation, 59 Temple Place - Suite 330, Boston, MA
20c87b03e5Sespie 02111-1307, USA.  */
21c87b03e5Sespie 
22c87b03e5Sespie #include "config.h"
23c87b03e5Sespie #include "system.h"
24c87b03e5Sespie #include "tree.h"
25c87b03e5Sespie #include "flags.h"
26c87b03e5Sespie #include "toplev.h"
27c87b03e5Sespie #include "c-common.h"
289d1607cfSmiod #include "ggc.h"
29c87b03e5Sespie #include "intl.h"
30c87b03e5Sespie #include "diagnostic.h"
31c87b03e5Sespie #include "langhooks.h"
32c87b03e5Sespie 
33c87b03e5Sespie /* Set format warning options according to a -Wformat=n option.  */
34c87b03e5Sespie 
35c87b03e5Sespie void
set_Wformat(setting)36c87b03e5Sespie set_Wformat (setting)
37c87b03e5Sespie      int setting;
38c87b03e5Sespie {
39c87b03e5Sespie   warn_format = setting;
40c87b03e5Sespie   warn_format_y2k = setting;
41c87b03e5Sespie   warn_format_extra_args = setting;
42c87b03e5Sespie   warn_format_zero_length = setting;
43c87b03e5Sespie   if (setting != 1)
44c87b03e5Sespie     {
45c87b03e5Sespie       warn_format_nonliteral = setting;
46c87b03e5Sespie       warn_format_security = setting;
47c87b03e5Sespie     }
48c87b03e5Sespie   /* Make sure not to disable -Wnonnull if -Wformat=0 is specified.  */
49c87b03e5Sespie   if (setting)
50c87b03e5Sespie     warn_nonnull = setting;
51c87b03e5Sespie }
52c87b03e5Sespie 
53c87b03e5Sespie 
54c87b03e5Sespie /* Handle attributes associated with format checking.  */
55c87b03e5Sespie 
56c87b03e5Sespie /* This must be in the same order as format_types, with format_type_error
57c87b03e5Sespie    last.  */
58d9f573dfSespie enum format_type { printf_format_type, kprintf_format_type, syslog_format_type, scanf_format_type,
59c87b03e5Sespie 		   strftime_format_type, strfmon_format_type,
60c87b03e5Sespie 		   format_type_error };
61c87b03e5Sespie 
62c87b03e5Sespie typedef struct function_format_info
63c87b03e5Sespie {
64c87b03e5Sespie   enum format_type format_type;	/* type of format (printf, scanf, etc.) */
65c87b03e5Sespie   unsigned HOST_WIDE_INT format_num;	/* number of format argument */
66c87b03e5Sespie   unsigned HOST_WIDE_INT first_arg_num;	/* number of first arg (zero for varargs) */
67c87b03e5Sespie } function_format_info;
68c87b03e5Sespie 
69c87b03e5Sespie static bool decode_format_attr		PARAMS ((tree,
70c87b03e5Sespie 						 function_format_info *, int));
71c87b03e5Sespie static enum format_type decode_format_type	PARAMS ((const char *));
72c87b03e5Sespie 
73c87b03e5Sespie /* Handle a "format" attribute; arguments as in
74c87b03e5Sespie    struct attribute_spec.handler.  */
75c87b03e5Sespie tree
handle_format_attribute(node,name,args,flags,no_add_attrs)76c87b03e5Sespie handle_format_attribute (node, name, args, flags, no_add_attrs)
77c87b03e5Sespie      tree *node;
78c87b03e5Sespie      tree name ATTRIBUTE_UNUSED;
79c87b03e5Sespie      tree args;
80c87b03e5Sespie      int flags;
81c87b03e5Sespie      bool *no_add_attrs;
82c87b03e5Sespie {
83c87b03e5Sespie   tree type = *node;
84c87b03e5Sespie   function_format_info info;
85c87b03e5Sespie   tree argument;
86c87b03e5Sespie   unsigned HOST_WIDE_INT arg_num;
87c87b03e5Sespie 
88c87b03e5Sespie   if (!decode_format_attr (args, &info, 0))
89c87b03e5Sespie     {
90c87b03e5Sespie       *no_add_attrs = true;
91c87b03e5Sespie       return NULL_TREE;
92c87b03e5Sespie     }
93c87b03e5Sespie 
94c87b03e5Sespie   /* If a parameter list is specified, verify that the format_num
95c87b03e5Sespie      argument is actually a string, in case the format attribute
96c87b03e5Sespie      is in error.  */
97c87b03e5Sespie   argument = TYPE_ARG_TYPES (type);
98c87b03e5Sespie   if (argument)
99c87b03e5Sespie     {
100c87b03e5Sespie       for (arg_num = 1; argument != 0 && arg_num != info.format_num;
101c87b03e5Sespie 	   ++arg_num, argument = TREE_CHAIN (argument))
102c87b03e5Sespie 	;
103c87b03e5Sespie 
104c87b03e5Sespie       if (! argument
105c87b03e5Sespie 	  || TREE_CODE (TREE_VALUE (argument)) != POINTER_TYPE
106c87b03e5Sespie 	  || (TYPE_MAIN_VARIANT (TREE_TYPE (TREE_VALUE (argument)))
107c87b03e5Sespie 	      != char_type_node))
108c87b03e5Sespie 	{
109c87b03e5Sespie 	  if (!(flags & (int) ATTR_FLAG_BUILT_IN))
110c87b03e5Sespie 	    error ("format string arg not a string type");
111c87b03e5Sespie 	  *no_add_attrs = true;
112c87b03e5Sespie 	  return NULL_TREE;
113c87b03e5Sespie 	}
114c87b03e5Sespie 
115c87b03e5Sespie       else if (info.first_arg_num != 0)
116c87b03e5Sespie 	{
117c87b03e5Sespie 	  /* Verify that first_arg_num points to the last arg,
118c87b03e5Sespie 	     the ...  */
119c87b03e5Sespie 	  while (argument)
120c87b03e5Sespie 	    arg_num++, argument = TREE_CHAIN (argument);
121c87b03e5Sespie 
122c87b03e5Sespie 	  if (arg_num != info.first_arg_num)
123c87b03e5Sespie 	    {
124c87b03e5Sespie 	      if (!(flags & (int) ATTR_FLAG_BUILT_IN))
125c87b03e5Sespie 		error ("args to be formatted is not '...'");
126c87b03e5Sespie 	      *no_add_attrs = true;
127c87b03e5Sespie 	      return NULL_TREE;
128c87b03e5Sespie 	    }
129c87b03e5Sespie 	}
130c87b03e5Sespie     }
131c87b03e5Sespie 
132c87b03e5Sespie   if (info.format_type == strftime_format_type && info.first_arg_num != 0)
133c87b03e5Sespie     {
134c87b03e5Sespie       error ("strftime formats cannot format arguments");
135c87b03e5Sespie       *no_add_attrs = true;
136c87b03e5Sespie       return NULL_TREE;
137c87b03e5Sespie     }
138c87b03e5Sespie 
139c87b03e5Sespie   return NULL_TREE;
140c87b03e5Sespie }
141c87b03e5Sespie 
142c87b03e5Sespie 
143c87b03e5Sespie /* Handle a "format_arg" attribute; arguments as in
144c87b03e5Sespie    struct attribute_spec.handler.  */
145c87b03e5Sespie tree
handle_format_arg_attribute(node,name,args,flags,no_add_attrs)146c87b03e5Sespie handle_format_arg_attribute (node, name, args, flags, no_add_attrs)
147c87b03e5Sespie      tree *node;
148c87b03e5Sespie      tree name ATTRIBUTE_UNUSED;
149c87b03e5Sespie      tree args;
150c87b03e5Sespie      int flags;
151c87b03e5Sespie      bool *no_add_attrs;
152c87b03e5Sespie {
153c87b03e5Sespie   tree type = *node;
154c87b03e5Sespie   tree format_num_expr = TREE_VALUE (args);
155c87b03e5Sespie   unsigned HOST_WIDE_INT format_num;
156c87b03e5Sespie   unsigned HOST_WIDE_INT arg_num;
157c87b03e5Sespie   tree argument;
158c87b03e5Sespie 
159c87b03e5Sespie   /* Strip any conversions from the first arg number and verify it
160c87b03e5Sespie      is a constant.  */
161c87b03e5Sespie   while (TREE_CODE (format_num_expr) == NOP_EXPR
162c87b03e5Sespie 	 || TREE_CODE (format_num_expr) == CONVERT_EXPR
163c87b03e5Sespie 	 || TREE_CODE (format_num_expr) == NON_LVALUE_EXPR)
164c87b03e5Sespie     format_num_expr = TREE_OPERAND (format_num_expr, 0);
165c87b03e5Sespie 
166c87b03e5Sespie   if (TREE_CODE (format_num_expr) != INTEGER_CST
167c87b03e5Sespie       || TREE_INT_CST_HIGH (format_num_expr) != 0)
168c87b03e5Sespie     {
169c87b03e5Sespie       error ("format string has invalid operand number");
170c87b03e5Sespie       *no_add_attrs = true;
171c87b03e5Sespie       return NULL_TREE;
172c87b03e5Sespie     }
173c87b03e5Sespie 
174c87b03e5Sespie   format_num = TREE_INT_CST_LOW (format_num_expr);
175c87b03e5Sespie 
176c87b03e5Sespie   /* If a parameter list is specified, verify that the format_num
177c87b03e5Sespie      argument is actually a string, in case the format attribute
178c87b03e5Sespie      is in error.  */
179c87b03e5Sespie   argument = TYPE_ARG_TYPES (type);
180c87b03e5Sespie   if (argument)
181c87b03e5Sespie     {
182c87b03e5Sespie       for (arg_num = 1; argument != 0 && arg_num != format_num;
183c87b03e5Sespie 	   ++arg_num, argument = TREE_CHAIN (argument))
184c87b03e5Sespie 	;
185c87b03e5Sespie 
186c87b03e5Sespie       if (! argument
187c87b03e5Sespie 	  || TREE_CODE (TREE_VALUE (argument)) != POINTER_TYPE
188c87b03e5Sespie 	  || (TYPE_MAIN_VARIANT (TREE_TYPE (TREE_VALUE (argument)))
189c87b03e5Sespie 	      != char_type_node))
190c87b03e5Sespie 	{
191c87b03e5Sespie 	  if (!(flags & (int) ATTR_FLAG_BUILT_IN))
192c87b03e5Sespie 	    error ("format string arg not a string type");
193c87b03e5Sespie 	  *no_add_attrs = true;
194c87b03e5Sespie 	  return NULL_TREE;
195c87b03e5Sespie 	}
196c87b03e5Sespie     }
197c87b03e5Sespie 
198c87b03e5Sespie   if (TREE_CODE (TREE_TYPE (type)) != POINTER_TYPE
199c87b03e5Sespie       || (TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (type)))
200c87b03e5Sespie 	  != char_type_node))
201c87b03e5Sespie     {
202c87b03e5Sespie       if (!(flags & (int) ATTR_FLAG_BUILT_IN))
203c87b03e5Sespie 	error ("function does not return string type");
204c87b03e5Sespie       *no_add_attrs = true;
205c87b03e5Sespie       return NULL_TREE;
206c87b03e5Sespie     }
207c87b03e5Sespie 
208c87b03e5Sespie   return NULL_TREE;
209c87b03e5Sespie }
210c87b03e5Sespie 
211c87b03e5Sespie 
212c87b03e5Sespie /* Decode the arguments to a "format" attribute into a function_format_info
213c87b03e5Sespie    structure.  It is already known that the list is of the right length.
214c87b03e5Sespie    If VALIDATED_P is true, then these attributes have already been validated
215c87b03e5Sespie    and this function will abort if they are erroneous; if false, it
216c87b03e5Sespie    will give an error message.  Returns true if the attributes are
217c87b03e5Sespie    successfully decoded, false otherwise.  */
218c87b03e5Sespie 
219c87b03e5Sespie static bool
decode_format_attr(args,info,validated_p)220c87b03e5Sespie decode_format_attr (args, info, validated_p)
221c87b03e5Sespie      tree args;
222c87b03e5Sespie      function_format_info *info;
223c87b03e5Sespie      int validated_p;
224c87b03e5Sespie {
225c87b03e5Sespie   tree format_type_id = TREE_VALUE (args);
226c87b03e5Sespie   tree format_num_expr = TREE_VALUE (TREE_CHAIN (args));
227c87b03e5Sespie   tree first_arg_num_expr
228c87b03e5Sespie     = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (args)));
229c87b03e5Sespie 
230c87b03e5Sespie   if (TREE_CODE (format_type_id) != IDENTIFIER_NODE)
231c87b03e5Sespie     {
232c87b03e5Sespie       if (validated_p)
233c87b03e5Sespie 	abort ();
234c87b03e5Sespie       error ("unrecognized format specifier");
235c87b03e5Sespie       return false;
236c87b03e5Sespie     }
237c87b03e5Sespie   else
238c87b03e5Sespie     {
239c87b03e5Sespie       const char *p = IDENTIFIER_POINTER (format_type_id);
240c87b03e5Sespie 
241c87b03e5Sespie       info->format_type = decode_format_type (p);
242c87b03e5Sespie 
243c87b03e5Sespie       if (info->format_type == format_type_error)
244c87b03e5Sespie 	{
245c87b03e5Sespie 	  if (validated_p)
246c87b03e5Sespie 	    abort ();
247c87b03e5Sespie 	  warning ("`%s' is an unrecognized format function type", p);
248c87b03e5Sespie 	  return false;
249c87b03e5Sespie 	}
250c87b03e5Sespie     }
251c87b03e5Sespie 
252c87b03e5Sespie   /* Strip any conversions from the string index and first arg number
253c87b03e5Sespie      and verify they are constants.  */
254c87b03e5Sespie   while (TREE_CODE (format_num_expr) == NOP_EXPR
255c87b03e5Sespie 	 || TREE_CODE (format_num_expr) == CONVERT_EXPR
256c87b03e5Sespie 	 || TREE_CODE (format_num_expr) == NON_LVALUE_EXPR)
257c87b03e5Sespie     format_num_expr = TREE_OPERAND (format_num_expr, 0);
258c87b03e5Sespie 
259c87b03e5Sespie   while (TREE_CODE (first_arg_num_expr) == NOP_EXPR
260c87b03e5Sespie 	 || TREE_CODE (first_arg_num_expr) == CONVERT_EXPR
261c87b03e5Sespie 	 || TREE_CODE (first_arg_num_expr) == NON_LVALUE_EXPR)
262c87b03e5Sespie     first_arg_num_expr = TREE_OPERAND (first_arg_num_expr, 0);
263c87b03e5Sespie 
264c87b03e5Sespie   if (TREE_CODE (format_num_expr) != INTEGER_CST
265c87b03e5Sespie       || TREE_INT_CST_HIGH (format_num_expr) != 0
266c87b03e5Sespie       || TREE_CODE (first_arg_num_expr) != INTEGER_CST
267c87b03e5Sespie       || TREE_INT_CST_HIGH (first_arg_num_expr) != 0)
268c87b03e5Sespie     {
269c87b03e5Sespie       if (validated_p)
270c87b03e5Sespie 	abort ();
271c87b03e5Sespie       error ("format string has invalid operand number");
272c87b03e5Sespie       return false;
273c87b03e5Sespie     }
274c87b03e5Sespie 
275c87b03e5Sespie   info->format_num = TREE_INT_CST_LOW (format_num_expr);
276c87b03e5Sespie   info->first_arg_num = TREE_INT_CST_LOW (first_arg_num_expr);
277c87b03e5Sespie   if (info->first_arg_num != 0 && info->first_arg_num <= info->format_num)
278c87b03e5Sespie     {
279c87b03e5Sespie       if (validated_p)
280c87b03e5Sespie 	abort ();
281c87b03e5Sespie       error ("format string arg follows the args to be formatted");
282c87b03e5Sespie       return false;
283c87b03e5Sespie     }
284c87b03e5Sespie 
285c87b03e5Sespie   return true;
286c87b03e5Sespie }
287c87b03e5Sespie 
288c87b03e5Sespie /* Check a call to a format function against a parameter list.  */
289c87b03e5Sespie 
290c87b03e5Sespie /* The meaningfully distinct length modifiers for format checking recognized
291c87b03e5Sespie    by GCC.  */
292c87b03e5Sespie enum format_lengths
293c87b03e5Sespie {
294c87b03e5Sespie   FMT_LEN_none,
295c87b03e5Sespie   FMT_LEN_hh,
296c87b03e5Sespie   FMT_LEN_h,
297c87b03e5Sespie   FMT_LEN_l,
298c87b03e5Sespie   FMT_LEN_ll,
299c87b03e5Sespie   FMT_LEN_L,
300c87b03e5Sespie   FMT_LEN_z,
301c87b03e5Sespie   FMT_LEN_t,
302c87b03e5Sespie   FMT_LEN_j,
303c87b03e5Sespie   FMT_LEN_MAX
304c87b03e5Sespie };
305c87b03e5Sespie 
306c87b03e5Sespie 
307c87b03e5Sespie /* The standard versions in which various format features appeared.  */
308c87b03e5Sespie enum format_std_version
309c87b03e5Sespie {
310c87b03e5Sespie   STD_C89,
311c87b03e5Sespie   STD_C94,
312c87b03e5Sespie   STD_C9L, /* C99, but treat as C89 if -Wno-long-long.  */
313c87b03e5Sespie   STD_C99,
314c87b03e5Sespie   STD_EXT
315c87b03e5Sespie };
316c87b03e5Sespie 
317c87b03e5Sespie /* The C standard version C++ is treated as equivalent to
318c87b03e5Sespie    or inheriting from, for the purpose of format features supported.  */
319c87b03e5Sespie #define CPLUSPLUS_STD_VER	STD_C94
320c87b03e5Sespie /* The C standard version we are checking formats against when pedantic.  */
321c87b03e5Sespie #define C_STD_VER		((int)(c_language == clk_cplusplus	  \
322c87b03e5Sespie 				 ? CPLUSPLUS_STD_VER			  \
323c87b03e5Sespie 				 : (flag_isoc99				  \
324c87b03e5Sespie 				    ? STD_C99				  \
325c87b03e5Sespie 				    : (flag_isoc94 ? STD_C94 : STD_C89))))
326c87b03e5Sespie /* The name to give to the standard version we are warning about when
327c87b03e5Sespie    pedantic.  FEATURE_VER is the version in which the feature warned out
328c87b03e5Sespie    appeared, which is higher than C_STD_VER.  */
329c87b03e5Sespie #define C_STD_NAME(FEATURE_VER) (c_language == clk_cplusplus	\
330c87b03e5Sespie 				 ? "ISO C++"			\
331c87b03e5Sespie 				 : ((FEATURE_VER) == STD_EXT	\
332c87b03e5Sespie 				    ? "ISO C"			\
333c87b03e5Sespie 				    : "ISO C90"))
334c87b03e5Sespie /* Adjust a C standard version, which may be STD_C9L, to account for
335c87b03e5Sespie    -Wno-long-long.  Returns other standard versions unchanged.  */
336c87b03e5Sespie #define ADJ_STD(VER)		((int)((VER) == STD_C9L			      \
337c87b03e5Sespie 				       ? (warn_long_long ? STD_C99 : STD_C89) \
338c87b03e5Sespie 				       : (VER)))
339c87b03e5Sespie 
340c87b03e5Sespie /* Flags that may apply to a particular kind of format checked by GCC.  */
341c87b03e5Sespie enum
342c87b03e5Sespie {
343c87b03e5Sespie   /* This format converts arguments of types determined by the
344c87b03e5Sespie      format string.  */
345c87b03e5Sespie   FMT_FLAG_ARG_CONVERT = 1,
346c87b03e5Sespie   /* The scanf allocation 'a' kludge applies to this format kind.  */
347c87b03e5Sespie   FMT_FLAG_SCANF_A_KLUDGE = 2,
348c87b03e5Sespie   /* A % during parsing a specifier is allowed to be a modified % rather
349c87b03e5Sespie      that indicating the format is broken and we are out-of-sync.  */
350c87b03e5Sespie   FMT_FLAG_FANCY_PERCENT_OK = 4,
351c87b03e5Sespie   /* With $ operand numbers, it is OK to reference the same argument more
352c87b03e5Sespie      than once.  */
353c87b03e5Sespie   FMT_FLAG_DOLLAR_MULTIPLE = 8,
354c87b03e5Sespie   /* This format type uses $ operand numbers (strfmon doesn't).  */
355c87b03e5Sespie   FMT_FLAG_USE_DOLLAR = 16,
356c87b03e5Sespie   /* Zero width is bad in this type of format (scanf).  */
357c87b03e5Sespie   FMT_FLAG_ZERO_WIDTH_BAD = 32,
358c87b03e5Sespie   /* Empty precision specification is OK in this type of format (printf).  */
359c87b03e5Sespie   FMT_FLAG_EMPTY_PREC_OK = 64,
360c87b03e5Sespie   /* Gaps are allowed in the arguments with $ operand numbers if all
361c87b03e5Sespie      arguments are pointers (scanf).  */
362c87b03e5Sespie   FMT_FLAG_DOLLAR_GAP_POINTER_OK = 128
363c87b03e5Sespie   /* Not included here: details of whether width or precision may occur
364c87b03e5Sespie      (controlled by width_char and precision_char); details of whether
365c87b03e5Sespie      '*' can be used for these (width_type and precision_type); details
366c87b03e5Sespie      of whether length modifiers can occur (length_char_specs).  */
367c87b03e5Sespie };
368c87b03e5Sespie 
369c87b03e5Sespie 
370c87b03e5Sespie /* Structure describing a length modifier supported in format checking, and
371c87b03e5Sespie    possibly a doubled version such as "hh".  */
372c87b03e5Sespie typedef struct
373c87b03e5Sespie {
374c87b03e5Sespie   /* Name of the single-character length modifier.  */
375c87b03e5Sespie   const char *const name;
376c87b03e5Sespie   /* Index into a format_char_info.types array.  */
377c87b03e5Sespie   const enum format_lengths index;
378c87b03e5Sespie   /* Standard version this length appears in.  */
379c87b03e5Sespie   const enum format_std_version std;
380c87b03e5Sespie   /* Same, if the modifier can be repeated, or NULL if it can't.  */
381c87b03e5Sespie   const char *const double_name;
382c87b03e5Sespie   const enum format_lengths double_index;
383c87b03e5Sespie   const enum format_std_version double_std;
384c87b03e5Sespie } format_length_info;
385c87b03e5Sespie 
386c87b03e5Sespie 
387c87b03e5Sespie /* Structure describing the combination of a conversion specifier
388c87b03e5Sespie    (or a set of specifiers which act identically) and a length modifier.  */
389c87b03e5Sespie typedef struct
390c87b03e5Sespie {
391c87b03e5Sespie   /* The standard version this combination of length and type appeared in.
392c87b03e5Sespie      This is only relevant if greater than those for length and type
393c87b03e5Sespie      individually; otherwise it is ignored.  */
394c87b03e5Sespie   enum format_std_version std;
395c87b03e5Sespie   /* The name to use for the type, if different from that generated internally
396c87b03e5Sespie      (e.g., "signed size_t").  */
397c87b03e5Sespie   const char *name;
398c87b03e5Sespie   /* The type itself.  */
399c87b03e5Sespie   tree *type;
400c87b03e5Sespie } format_type_detail;
401c87b03e5Sespie 
402c87b03e5Sespie 
403c87b03e5Sespie /* Macros to fill out tables of these.  */
404c87b03e5Sespie #define BADLEN	{ 0, NULL, NULL }
405c87b03e5Sespie #define NOLENGTHS	{ BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }
406c87b03e5Sespie 
407c87b03e5Sespie 
408c87b03e5Sespie /* Structure describing a format conversion specifier (or a set of specifiers
409c87b03e5Sespie    which act identically), and the length modifiers used with it.  */
4109d1607cfSmiod typedef struct format_char_info
411c87b03e5Sespie {
412c87b03e5Sespie   const char *const format_chars;
413c87b03e5Sespie   const int pointer_count;
414c87b03e5Sespie   const enum format_std_version std;
415c87b03e5Sespie   /* Types accepted for each length modifier.  */
416c87b03e5Sespie   const format_type_detail types[FMT_LEN_MAX];
417c87b03e5Sespie   /* List of other modifier characters allowed with these specifiers.
418c87b03e5Sespie      This lists flags, and additionally "w" for width, "p" for precision
419c87b03e5Sespie      (right precision, for strfmon), "#" for left precision (strfmon),
420c87b03e5Sespie      "a" for scanf "a" allocation extension (not applicable in C99 mode),
421c87b03e5Sespie      "*" for scanf suppression, and "E" and "O" for those strftime
422c87b03e5Sespie      modifiers.  */
423c87b03e5Sespie   const char *const flag_chars;
424c87b03e5Sespie   /* List of additional flags describing these conversion specifiers.
425c87b03e5Sespie      "c" for generic character pointers being allowed, "2" for strftime
426c87b03e5Sespie      two digit year formats, "3" for strftime formats giving two digit
427c87b03e5Sespie      years in some locales, "4" for "2" which becomes "3" with an "E" modifier,
428c87b03e5Sespie      "o" if use of strftime "O" is a GNU extension beyond C99,
429c87b03e5Sespie      "W" if the argument is a pointer which is dereferenced and written into,
430c87b03e5Sespie      "R" if the argument is a pointer which is dereferenced and read from,
431c87b03e5Sespie      "i" for printf integer formats where the '0' flag is ignored with
432c87b03e5Sespie      precision, and "[" for the starting character of a scanf scanset.  */
433c87b03e5Sespie   const char *const flags2;
4349d1607cfSmiod   /* If this format conversion character consumes more than one argument,
4359d1607cfSmiod      CHAIN points to information about the next argument.  For later
4369d1607cfSmiod      arguments, only POINTER_COUNT, TYPES, and the "c", "R", and "W" flags
4379d1607cfSmiod      in FLAGS2 are used.  */
4389d1607cfSmiod   const struct format_char_info *chain;
439c87b03e5Sespie } format_char_info;
440c87b03e5Sespie 
441c87b03e5Sespie 
442c87b03e5Sespie /* Structure describing a flag accepted by some kind of format.  */
443c87b03e5Sespie typedef struct
444c87b03e5Sespie {
445c87b03e5Sespie   /* The flag character in question (0 for end of array).  */
446c87b03e5Sespie   const int flag_char;
447c87b03e5Sespie   /* Zero if this entry describes the flag character in general, or a
448c87b03e5Sespie      nonzero character that may be found in flags2 if it describes the
449c87b03e5Sespie      flag when used with certain formats only.  If the latter, only
450c87b03e5Sespie      the first such entry found that applies to the current conversion
451c87b03e5Sespie      specifier is used; the values of `name' and `long_name' it supplies
452c87b03e5Sespie      will be used, if non-NULL and the standard version is higher than
453c87b03e5Sespie      the unpredicated one, for any pedantic warning.  For example, 'o'
454c87b03e5Sespie      for strftime formats (meaning 'O' is an extension over C99).  */
455c87b03e5Sespie   const int predicate;
456c87b03e5Sespie   /* Nonzero if the next character after this flag in the format should
457c87b03e5Sespie      be skipped ('=' in strfmon), zero otherwise.  */
458c87b03e5Sespie   const int skip_next_char;
459c87b03e5Sespie   /* The name to use for this flag in diagnostic messages.  For example,
460c87b03e5Sespie      N_("`0' flag"), N_("field width").  */
461c87b03e5Sespie   const char *const name;
462c87b03e5Sespie   /* Long name for this flag in diagnostic messages; currently only used for
463c87b03e5Sespie      "ISO C does not support ...".  For example, N_("the `I' printf flag").  */
464c87b03e5Sespie   const char *const long_name;
465c87b03e5Sespie   /* The standard version in which it appeared.  */
466c87b03e5Sespie   const enum format_std_version std;
467c87b03e5Sespie } format_flag_spec;
468c87b03e5Sespie 
469c87b03e5Sespie 
470c87b03e5Sespie /* Structure describing a combination of flags that is bad for some kind
471c87b03e5Sespie    of format.  */
472c87b03e5Sespie typedef struct
473c87b03e5Sespie {
474c87b03e5Sespie   /* The first flag character in question (0 for end of array).  */
475c87b03e5Sespie   const int flag_char1;
476c87b03e5Sespie   /* The second flag character.  */
477c87b03e5Sespie   const int flag_char2;
478c87b03e5Sespie   /* Nonzero if the message should say that the first flag is ignored with
479c87b03e5Sespie      the second, zero if the combination should simply be objected to.  */
480c87b03e5Sespie   const int ignored;
481c87b03e5Sespie   /* Zero if this entry applies whenever this flag combination occurs,
482c87b03e5Sespie      a nonzero character from flags2 if it only applies in some
483c87b03e5Sespie      circumstances (e.g. 'i' for printf formats ignoring 0 with precision).  */
484c87b03e5Sespie   const int predicate;
485c87b03e5Sespie } format_flag_pair;
486c87b03e5Sespie 
487c87b03e5Sespie 
488c87b03e5Sespie /* Structure describing a particular kind of format processed by GCC.  */
489c87b03e5Sespie typedef struct
490c87b03e5Sespie {
491c87b03e5Sespie   /* The name of this kind of format, for use in diagnostics.  Also
492c87b03e5Sespie      the name of the attribute (without preceding and following __).  */
493c87b03e5Sespie   const char *const name;
494c87b03e5Sespie   /* Specifications of the length modifiers accepted; possibly NULL.  */
495c87b03e5Sespie   const format_length_info *const length_char_specs;
496c87b03e5Sespie   /* Details of the conversion specification characters accepted.  */
497c87b03e5Sespie   const format_char_info *const conversion_specs;
498c87b03e5Sespie   /* String listing the flag characters that are accepted.  */
499c87b03e5Sespie   const char *const flag_chars;
500c87b03e5Sespie   /* String listing modifier characters (strftime) accepted.  May be NULL.  */
501c87b03e5Sespie   const char *const modifier_chars;
502c87b03e5Sespie   /* Details of the flag characters, including pseudo-flags.  */
503c87b03e5Sespie   const format_flag_spec *const flag_specs;
504c87b03e5Sespie   /* Details of bad combinations of flags.  */
505c87b03e5Sespie   const format_flag_pair *const bad_flag_pairs;
506c87b03e5Sespie   /* Flags applicable to this kind of format.  */
507c87b03e5Sespie   const int flags;
508c87b03e5Sespie   /* Flag character to treat a width as, or 0 if width not used.  */
509c87b03e5Sespie   const int width_char;
510c87b03e5Sespie   /* Flag character to treat a left precision (strfmon) as,
511c87b03e5Sespie      or 0 if left precision not used.  */
512c87b03e5Sespie   const int left_precision_char;
513c87b03e5Sespie   /* Flag character to treat a precision (for strfmon, right precision) as,
514c87b03e5Sespie      or 0 if precision not used.  */
515c87b03e5Sespie   const int precision_char;
516c87b03e5Sespie   /* If a flag character has the effect of suppressing the conversion of
517c87b03e5Sespie      an argument ('*' in scanf), that flag character, otherwise 0.  */
518c87b03e5Sespie   const int suppression_char;
519c87b03e5Sespie   /* Flag character to treat a length modifier as (ignored if length
520c87b03e5Sespie      modifiers not used).  Need not be placed in flag_chars for conversion
521c87b03e5Sespie      specifiers, but is used to check for bad combinations such as length
522c87b03e5Sespie      modifier with assignment suppression in scanf.  */
523c87b03e5Sespie   const int length_code_char;
524c87b03e5Sespie   /* Pointer to type of argument expected if '*' is used for a width,
525c87b03e5Sespie      or NULL if '*' not used for widths.  */
526c87b03e5Sespie   tree *const width_type;
527c87b03e5Sespie   /* Pointer to type of argument expected if '*' is used for a precision,
528c87b03e5Sespie      or NULL if '*' not used for precisions.  */
529c87b03e5Sespie   tree *const precision_type;
530c87b03e5Sespie } format_kind_info;
531c87b03e5Sespie 
532c87b03e5Sespie 
533c87b03e5Sespie /* Structure describing details of a type expected in format checking,
534c87b03e5Sespie    and the type to check against it.  */
535c87b03e5Sespie typedef struct format_wanted_type
536c87b03e5Sespie {
537c87b03e5Sespie   /* The type wanted.  */
538c87b03e5Sespie   tree wanted_type;
539c87b03e5Sespie   /* The name of this type to use in diagnostics.  */
540c87b03e5Sespie   const char *wanted_type_name;
541c87b03e5Sespie   /* The level of indirection through pointers at which this type occurs.  */
542c87b03e5Sespie   int pointer_count;
543c87b03e5Sespie   /* Whether, when pointer_count is 1, to allow any character type when
544c87b03e5Sespie      pedantic, rather than just the character or void type specified.  */
545c87b03e5Sespie   int char_lenient_flag;
546c87b03e5Sespie   /* Whether the argument, dereferenced once, is written into and so the
547c87b03e5Sespie      argument must not be a pointer to a const-qualified type.  */
548c87b03e5Sespie   int writing_in_flag;
549cd3be6e5Savsm   /* If the argument is to be written into and is an array, should the
550cd3be6e5Savsm      width specifier be equal to the size of the array, or one less
551cd3be6e5Savsm      (to accommodate a NULL being placed at the end) */
552cd3be6e5Savsm   int size_equals_width;
553c87b03e5Sespie   /* Whether the argument, dereferenced once, is read from and so
554c87b03e5Sespie      must not be a NULL pointer.  */
555c87b03e5Sespie   int reading_from_flag;
556c87b03e5Sespie   /* If warnings should be of the form "field precision is not type int",
557c87b03e5Sespie      the name to use (in this case "field precision"), otherwise NULL,
558c87b03e5Sespie      for "%s format, %s arg" type messages.  If (in an extension), this
559c87b03e5Sespie      is a pointer type, wanted_type_name should be set to include the
560c87b03e5Sespie      terminating '*' characters of the type name to give a correct
561c87b03e5Sespie      message.  */
562c87b03e5Sespie   const char *name;
563c87b03e5Sespie   /* The actual parameter to check against the wanted type.  */
564c87b03e5Sespie   tree param;
565cd3be6e5Savsm   /* Field width of type */
566cd3be6e5Savsm   int field_width;
567c87b03e5Sespie   /* The argument number of that parameter.  */
568c87b03e5Sespie   int arg_num;
569c87b03e5Sespie   /* The next type to check for this format conversion, or NULL if none.  */
570c87b03e5Sespie   struct format_wanted_type *next;
571c87b03e5Sespie } format_wanted_type;
572c87b03e5Sespie 
573c87b03e5Sespie 
574c87b03e5Sespie static const format_length_info printf_length_specs[] =
575c87b03e5Sespie {
576c87b03e5Sespie   { "h", FMT_LEN_h, STD_C89, "hh", FMT_LEN_hh, STD_C99 },
577c87b03e5Sespie   { "l", FMT_LEN_l, STD_C89, "ll", FMT_LEN_ll, STD_C9L },
578c87b03e5Sespie   { "q", FMT_LEN_ll, STD_EXT, NULL, 0, 0 },
579c87b03e5Sespie   { "L", FMT_LEN_L, STD_C89, NULL, 0, 0 },
580c87b03e5Sespie   { "z", FMT_LEN_z, STD_C99, NULL, 0, 0 },
581c87b03e5Sespie   { "Z", FMT_LEN_z, STD_EXT, NULL, 0, 0 },
582c87b03e5Sespie   { "t", FMT_LEN_t, STD_C99, NULL, 0, 0 },
583c87b03e5Sespie   { "j", FMT_LEN_j, STD_C99, NULL, 0, 0 },
584c87b03e5Sespie   { NULL, 0, 0, NULL, 0, 0 }
585c87b03e5Sespie };
586c87b03e5Sespie 
587d9f573dfSespie static const format_length_info kprintf_length_specs[] =
588d9f573dfSespie {
589d9f573dfSespie   { "h", FMT_LEN_h, STD_C89, NULL, 0, 0 },
5904cfed757Scloder   { "l", FMT_LEN_l, STD_C89, "ll", FMT_LEN_ll, STD_C9L },
5914cfed757Scloder   { "q", FMT_LEN_ll, STD_EXT, NULL, 0, 0 },
5929d1607cfSmiod   { "z", FMT_LEN_z, STD_C99, NULL, 0, 0 },
59328ffa5e4Smiod   { "t", FMT_LEN_t, STD_C99, NULL, 0, 0 },
594d9f573dfSespie   { NULL, 0, 0, NULL, 0, 0 }
595d9f573dfSespie };
596d9f573dfSespie 
597c87b03e5Sespie 
598c87b03e5Sespie /* This differs from printf_length_specs only in that "Z" is not accepted.  */
599c87b03e5Sespie static const format_length_info scanf_length_specs[] =
600c87b03e5Sespie {
601c87b03e5Sespie   { "h", FMT_LEN_h, STD_C89, "hh", FMT_LEN_hh, STD_C99 },
602c87b03e5Sespie   { "l", FMT_LEN_l, STD_C89, "ll", FMT_LEN_ll, STD_C9L },
603c87b03e5Sespie   { "q", FMT_LEN_ll, STD_EXT, NULL, 0, 0 },
604c87b03e5Sespie   { "L", FMT_LEN_L, STD_C89, NULL, 0, 0 },
605c87b03e5Sespie   { "z", FMT_LEN_z, STD_C99, NULL, 0, 0 },
606c87b03e5Sespie   { "t", FMT_LEN_t, STD_C99, NULL, 0, 0 },
607c87b03e5Sespie   { "j", FMT_LEN_j, STD_C99, NULL, 0, 0 },
608c87b03e5Sespie   { NULL, 0, 0, NULL, 0, 0 }
609c87b03e5Sespie };
610c87b03e5Sespie 
611c87b03e5Sespie 
612c87b03e5Sespie /* All tables for strfmon use STD_C89 everywhere, since -pedantic warnings
613c87b03e5Sespie    make no sense for a format type not part of any C standard version.  */
614c87b03e5Sespie static const format_length_info strfmon_length_specs[] =
615c87b03e5Sespie {
616c87b03e5Sespie   /* A GNU extension.  */
617c87b03e5Sespie   { "L", FMT_LEN_L, STD_C89, NULL, 0, 0 },
618c87b03e5Sespie   { NULL, 0, 0, NULL, 0, 0 }
619c87b03e5Sespie };
620c87b03e5Sespie 
621c87b03e5Sespie static const format_flag_spec printf_flag_specs[] =
622c87b03e5Sespie {
623c87b03e5Sespie   { ' ',  0, 0, N_("` ' flag"),        N_("the ` ' printf flag"),              STD_C89 },
624c87b03e5Sespie   { '+',  0, 0, N_("`+' flag"),        N_("the `+' printf flag"),              STD_C89 },
625c87b03e5Sespie   { '#',  0, 0, N_("`#' flag"),        N_("the `#' printf flag"),              STD_C89 },
626c87b03e5Sespie   { '0',  0, 0, N_("`0' flag"),        N_("the `0' printf flag"),              STD_C89 },
627c87b03e5Sespie   { '-',  0, 0, N_("`-' flag"),        N_("the `-' printf flag"),              STD_C89 },
628c87b03e5Sespie   { '\'', 0, 0, N_("`'' flag"),        N_("the `'' printf flag"),              STD_EXT },
629c87b03e5Sespie   { 'I',  0, 0, N_("`I' flag"),        N_("the `I' printf flag"),              STD_EXT },
630c87b03e5Sespie   { 'w',  0, 0, N_("field width"),     N_("field width in printf format"),     STD_C89 },
631c87b03e5Sespie   { 'p',  0, 0, N_("precision"),       N_("precision in printf format"),       STD_C89 },
632c87b03e5Sespie   { 'L',  0, 0, N_("length modifier"), N_("length modifier in printf format"), STD_C89 },
633c87b03e5Sespie   { 0, 0, 0, NULL, NULL, 0 }
634c87b03e5Sespie };
635c87b03e5Sespie 
636c87b03e5Sespie 
637c87b03e5Sespie static const format_flag_pair printf_flag_pairs[] =
638c87b03e5Sespie {
639c87b03e5Sespie   { ' ', '+', 1, 0   },
640c87b03e5Sespie   { '0', '-', 1, 0   },
641c87b03e5Sespie   { '0', 'p', 1, 'i' },
642c87b03e5Sespie   { 0, 0, 0, 0 }
643c87b03e5Sespie };
644c87b03e5Sespie 
645c87b03e5Sespie 
646c87b03e5Sespie static const format_flag_spec scanf_flag_specs[] =
647c87b03e5Sespie {
648c87b03e5Sespie   { '*',  0, 0, N_("assignment suppression"), N_("the assignment suppression scanf feature"), STD_C89 },
649c87b03e5Sespie   { 'a',  0, 0, N_("`a' flag"),               N_("the `a' scanf flag"),                       STD_EXT },
650c87b03e5Sespie   { 'w',  0, 0, N_("field width"),            N_("field width in scanf format"),              STD_C89 },
651c87b03e5Sespie   { 'L',  0, 0, N_("length modifier"),        N_("length modifier in scanf format"),          STD_C89 },
652c87b03e5Sespie   { '\'', 0, 0, N_("`'' flag"),               N_("the `'' scanf flag"),                       STD_EXT },
653c87b03e5Sespie   { 'I',  0, 0, N_("`I' flag"),               N_("the `I' scanf flag"),                       STD_EXT },
654c87b03e5Sespie   { 0, 0, 0, NULL, NULL, 0 }
655c87b03e5Sespie };
656c87b03e5Sespie 
657c87b03e5Sespie 
658c87b03e5Sespie static const format_flag_pair scanf_flag_pairs[] =
659c87b03e5Sespie {
660c87b03e5Sespie   { '*', 'L', 0, 0 },
661c87b03e5Sespie   { 0, 0, 0, 0 }
662c87b03e5Sespie };
663c87b03e5Sespie 
664c87b03e5Sespie 
665c87b03e5Sespie static const format_flag_spec strftime_flag_specs[] =
666c87b03e5Sespie {
667c87b03e5Sespie   { '_', 0,   0, N_("`_' flag"),     N_("the `_' strftime flag"),          STD_EXT },
668c87b03e5Sespie   { '-', 0,   0, N_("`-' flag"),     N_("the `-' strftime flag"),          STD_EXT },
669c87b03e5Sespie   { '0', 0,   0, N_("`0' flag"),     N_("the `0' strftime flag"),          STD_EXT },
670c87b03e5Sespie   { '^', 0,   0, N_("`^' flag"),     N_("the `^' strftime flag"),          STD_EXT },
671c87b03e5Sespie   { '#', 0,   0, N_("`#' flag"),     N_("the `#' strftime flag"),          STD_EXT },
672c87b03e5Sespie   { 'w', 0,   0, N_("field width"),  N_("field width in strftime format"), STD_EXT },
673c87b03e5Sespie   { 'E', 0,   0, N_("`E' modifier"), N_("the `E' strftime modifier"),      STD_C99 },
674c87b03e5Sespie   { 'O', 0,   0, N_("`O' modifier"), N_("the `O' strftime modifier"),      STD_C99 },
675c87b03e5Sespie   { 'O', 'o', 0, NULL,               N_("the `O' modifier"),               STD_EXT },
676c87b03e5Sespie   { 0, 0, 0, NULL, NULL, 0 }
677c87b03e5Sespie };
678c87b03e5Sespie 
679c87b03e5Sespie 
680c87b03e5Sespie static const format_flag_pair strftime_flag_pairs[] =
681c87b03e5Sespie {
682c87b03e5Sespie   { 'E', 'O', 0, 0 },
683c87b03e5Sespie   { '_', '-', 0, 0 },
684c87b03e5Sespie   { '_', '0', 0, 0 },
685c87b03e5Sespie   { '-', '0', 0, 0 },
686c87b03e5Sespie   { '^', '#', 0, 0 },
687c87b03e5Sespie   { 0, 0, 0, 0 }
688c87b03e5Sespie };
689c87b03e5Sespie 
690c87b03e5Sespie 
691c87b03e5Sespie static const format_flag_spec strfmon_flag_specs[] =
692c87b03e5Sespie {
693c87b03e5Sespie   { '=',  0, 1, N_("fill character"),  N_("fill character in strfmon format"),  STD_C89 },
694c87b03e5Sespie   { '^',  0, 0, N_("`^' flag"),        N_("the `^' strfmon flag"),              STD_C89 },
695c87b03e5Sespie   { '+',  0, 0, N_("`+' flag"),        N_("the `+' strfmon flag"),              STD_C89 },
696c87b03e5Sespie   { '(',  0, 0, N_("`(' flag"),        N_("the `(' strfmon flag"),              STD_C89 },
697c87b03e5Sespie   { '!',  0, 0, N_("`!' flag"),        N_("the `!' strfmon flag"),              STD_C89 },
698c87b03e5Sespie   { '-',  0, 0, N_("`-' flag"),        N_("the `-' strfmon flag"),              STD_C89 },
699c87b03e5Sespie   { 'w',  0, 0, N_("field width"),     N_("field width in strfmon format"),     STD_C89 },
700c87b03e5Sespie   { '#',  0, 0, N_("left precision"),  N_("left precision in strfmon format"),  STD_C89 },
701c87b03e5Sespie   { 'p',  0, 0, N_("right precision"), N_("right precision in strfmon format"), STD_C89 },
702c87b03e5Sespie   { 'L',  0, 0, N_("length modifier"), N_("length modifier in strfmon format"), STD_C89 },
703c87b03e5Sespie   { 0, 0, 0, NULL, NULL, 0 }
704c87b03e5Sespie };
705c87b03e5Sespie 
706c87b03e5Sespie static const format_flag_pair strfmon_flag_pairs[] =
707c87b03e5Sespie {
708c87b03e5Sespie   { '+', '(', 0, 0 },
709c87b03e5Sespie   { 0, 0, 0, 0 }
710c87b03e5Sespie };
711c87b03e5Sespie 
712c87b03e5Sespie 
713c87b03e5Sespie #define T_I	&integer_type_node
714c87b03e5Sespie #define T89_I	{ STD_C89, NULL, T_I }
715c87b03e5Sespie #define T_L	&long_integer_type_node
716c87b03e5Sespie #define T89_L	{ STD_C89, NULL, T_L }
717c87b03e5Sespie #define T_LL	&long_long_integer_type_node
718c87b03e5Sespie #define T9L_LL	{ STD_C9L, NULL, T_LL }
719c87b03e5Sespie #define TEX_LL	{ STD_EXT, NULL, T_LL }
720c87b03e5Sespie #define T_S	&short_integer_type_node
721c87b03e5Sespie #define T89_S	{ STD_C89, NULL, T_S }
722c87b03e5Sespie #define T_UI	&unsigned_type_node
723c87b03e5Sespie #define T89_UI	{ STD_C89, NULL, T_UI }
724c87b03e5Sespie #define T_UL	&long_unsigned_type_node
725c87b03e5Sespie #define T89_UL	{ STD_C89, NULL, T_UL }
726c87b03e5Sespie #define T_ULL	&long_long_unsigned_type_node
727c87b03e5Sespie #define T9L_ULL	{ STD_C9L, NULL, T_ULL }
728c87b03e5Sespie #define TEX_ULL	{ STD_EXT, NULL, T_ULL }
729c87b03e5Sespie #define T_US	&short_unsigned_type_node
730c87b03e5Sespie #define T89_US	{ STD_C89, NULL, T_US }
731c87b03e5Sespie #define T_F	&float_type_node
732c87b03e5Sespie #define T89_F	{ STD_C89, NULL, T_F }
733c87b03e5Sespie #define T99_F	{ STD_C99, NULL, T_F }
734c87b03e5Sespie #define T_D	&double_type_node
735c87b03e5Sespie #define T89_D	{ STD_C89, NULL, T_D }
736c87b03e5Sespie #define T99_D	{ STD_C99, NULL, T_D }
737c87b03e5Sespie #define T_LD	&long_double_type_node
738c87b03e5Sespie #define T89_LD	{ STD_C89, NULL, T_LD }
739c87b03e5Sespie #define T99_LD	{ STD_C99, NULL, T_LD }
740c87b03e5Sespie #define T_C	&char_type_node
741c87b03e5Sespie #define T89_C	{ STD_C89, NULL, T_C }
742c87b03e5Sespie #define T_SC	&signed_char_type_node
743c87b03e5Sespie #define T99_SC	{ STD_C99, NULL, T_SC }
744c87b03e5Sespie #define T_UC	&unsigned_char_type_node
745c87b03e5Sespie #define T99_UC	{ STD_C99, NULL, T_UC }
746c87b03e5Sespie #define T_V	&void_type_node
747c87b03e5Sespie #define T89_V	{ STD_C89, NULL, T_V }
748c87b03e5Sespie #define T_W	&wchar_type_node
749c87b03e5Sespie #define T94_W	{ STD_C94, "wchar_t", T_W }
750c87b03e5Sespie #define TEX_W	{ STD_EXT, "wchar_t", T_W }
751c87b03e5Sespie #define T_WI	&wint_type_node
752c87b03e5Sespie #define T94_WI	{ STD_C94, "wint_t", T_WI }
753c87b03e5Sespie #define TEX_WI	{ STD_EXT, "wint_t", T_WI }
754c87b03e5Sespie #define T_ST    &size_type_node
755c87b03e5Sespie #define T99_ST	{ STD_C99, "size_t", T_ST }
756c87b03e5Sespie #define T_SST   &signed_size_type_node
757c87b03e5Sespie #define T99_SST	{ STD_C99, "signed size_t", T_SST }
758c87b03e5Sespie #define T_PD    &ptrdiff_type_node
759c87b03e5Sespie #define T99_PD	{ STD_C99, "ptrdiff_t", T_PD }
760c87b03e5Sespie #define T_UPD   &unsigned_ptrdiff_type_node
761c87b03e5Sespie #define T99_UPD	{ STD_C99, "unsigned ptrdiff_t", T_UPD }
762c87b03e5Sespie #define T_IM    &intmax_type_node
763c87b03e5Sespie #define T99_IM	{ STD_C99, "intmax_t", T_IM }
764c87b03e5Sespie #define T_UIM   &uintmax_type_node
765c87b03e5Sespie #define T99_UIM	{ STD_C99, "uintmax_t", T_UIM }
766c87b03e5Sespie 
767c87b03e5Sespie static const format_char_info print_char_table[] =
768c87b03e5Sespie {
769c87b03e5Sespie   /* C89 conversion specifiers.  */
7709d1607cfSmiod   { "di",  0, STD_C89, { T89_I,   T99_SC,  T89_S,   T89_L,   T9L_LL,  TEX_LL,  T99_SST, T99_PD,  T99_IM  }, "-wp0 +'I", "i",  NULL },
7719d1607cfSmiod   { "oxX", 0, STD_C89, { T89_UI,  T99_UC,  T89_US,  T89_UL,  T9L_ULL, TEX_ULL, T99_ST,  T99_UPD, T99_UIM }, "-wp0#",    "i",  NULL },
7729d1607cfSmiod   { "u",   0, STD_C89, { T89_UI,  T99_UC,  T89_US,  T89_UL,  T9L_ULL, TEX_ULL, T99_ST,  T99_UPD, T99_UIM }, "-wp0'I",   "i",  NULL },
7739d1607cfSmiod   { "fgG", 0, STD_C89, { T89_D,   BADLEN,  BADLEN,  T99_D,   BADLEN,  T89_LD,  BADLEN,  BADLEN,  BADLEN  }, "-wp0 +#'", "",   NULL },
7749d1607cfSmiod   { "eE",  0, STD_C89, { T89_D,   BADLEN,  BADLEN,  T99_D,   BADLEN,  T89_LD,  BADLEN,  BADLEN,  BADLEN  }, "-wp0 +#",  "",   NULL },
7759d1607cfSmiod   { "c",   0, STD_C89, { T89_I,   BADLEN,  BADLEN,  T94_WI,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN  }, "-w",       "",   NULL },
7769d1607cfSmiod   { "s",   1, STD_C89, { T89_C,   BADLEN,  BADLEN,  T94_W,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN  }, "-wp",      "cR", NULL },
7779d1607cfSmiod   { "p",   1, STD_C89, { T89_V,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN  }, "-w",       "c",  NULL },
7789d1607cfSmiod   { "n",   1, STD_C89, { T89_I,   T99_SC,  T89_S,   T89_L,   T9L_LL,  BADLEN,  T99_SST, T99_PD,  T99_IM  }, "",         "W",  NULL },
779c87b03e5Sespie   /* C99 conversion specifiers.  */
7809d1607cfSmiod   { "F",   0, STD_C99, { T99_D,   BADLEN,  BADLEN,  T99_D,   BADLEN,  T99_LD,  BADLEN,  BADLEN,  BADLEN  }, "-wp0 +#'", "",   NULL },
7819d1607cfSmiod   { "aA",  0, STD_C99, { T99_D,   BADLEN,  BADLEN,  T99_D,   BADLEN,  T99_LD,  BADLEN,  BADLEN,  BADLEN  }, "-wp0 +#",  "",   NULL },
782c87b03e5Sespie   /* X/Open conversion specifiers.  */
7839d1607cfSmiod   { "C",   0, STD_EXT, { TEX_WI,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN  }, "-w",       "",   NULL },
7849d1607cfSmiod   { "S",   1, STD_EXT, { TEX_W,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN  }, "-wp",      "R",  NULL },
785c87b03e5Sespie   /* GNU conversion specifiers.  */
7869d1607cfSmiod   { "m",   0, STD_EXT, { T89_V,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN  }, "-wp",      "",   NULL },
7879d1607cfSmiod   { NULL,  0, 0, NOLENGTHS, NULL, NULL, NULL }
788c87b03e5Sespie };
789c87b03e5Sespie 
790d9f573dfSespie static const format_char_info kprint_char_table[] =
791d9f573dfSespie {
792d9f573dfSespie   /* C89 conversion specifiers.  */
79328ffa5e4Smiod   { "di",  0, STD_C89, { T89_I,   BADLEN,  T89_S,   T89_L,   T9L_LL,  BADLEN,  T99_SST, T99_PD,  BADLEN  }, "-wp0 +'I", "i",  NULL },
79428ffa5e4Smiod   { "oxX", 0, STD_C89, { T89_UI,  BADLEN,  T89_US,  T89_UL,  T9L_ULL, BADLEN,  T99_ST,  T99_UPD, BADLEN  }, "-wp0#",    "i",  NULL },
79528ffa5e4Smiod   { "u",   0, STD_C89, { T89_UI,  BADLEN,  T89_US,  T89_UL,  T9L_ULL, BADLEN,  T99_ST,  T99_UPD, BADLEN  }, "-wp0'I",   "i",  NULL },
7969d1607cfSmiod   { "c",   0, STD_C89, { T89_I,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN  }, "-w",       "",   NULL },
7979d1607cfSmiod   { "s",   1, STD_C89, { T89_C,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN  }, "-wp",      "cR", NULL },
7989d1607cfSmiod   { "p",   1, STD_C89, { T89_V,   BADLEN,  BADLEN,  T89_UL,  T9L_LL,  BADLEN,  BADLEN,  BADLEN,  BADLEN  }, "-wp0",     "c",  NULL },
799d9f573dfSespie /* Kernel bitmap formatting */
8009d1607cfSmiod   { "b",   0, STD_C89, { T89_I,   BADLEN,  T89_S,   T89_L,   T9L_LL,  BADLEN,  T99_SST, BADLEN,  BADLEN }, "",		"",   kprint_char_table + 8 },
8019d1607cfSmiod   { NULL,  0, 0, NOLENGTHS, NULL, NULL, NULL },
8029d1607cfSmiod /* Kernel bitmap formatting, second part - similar to "s" except for types[] */
8039d1607cfSmiod   { "b",   1, STD_C89, { T89_C,   BADLEN,  T89_C,   T89_C,   T89_C,   BADLEN,  T89_C,   BADLEN,  BADLEN  }, NULL,       "cR", NULL },
804d9f573dfSespie };
805d9f573dfSespie 
806d9f573dfSespie static const format_char_info syslog_char_table[] =
807d9f573dfSespie {
808d9f573dfSespie   /* C89 conversion specifiers.  */
8099d1607cfSmiod   { "di",  0, STD_C89, { T89_I,   T99_SC,  T89_S,   T89_L,   T9L_LL,  TEX_LL,  T99_SST, T99_PD,  T99_IM  }, "-wp0 +'I", "i",  NULL },
8109d1607cfSmiod   { "oxX", 0, STD_C89, { T89_UI,  T99_UC,  T89_US,  T89_UL,  T9L_ULL, TEX_ULL, T99_ST,  T99_UPD, T99_UIM }, "-wp0#",    "i",  NULL },
8119d1607cfSmiod   { "u",   0, STD_C89, { T89_UI,  T99_UC,  T89_US,  T89_UL,  T9L_ULL, TEX_ULL, T99_ST,  T99_UPD, T99_UIM }, "-wp0'I",   "i",  NULL },
8129d1607cfSmiod   { "fgG", 0, STD_C89, { T89_D,   BADLEN,  BADLEN,  T99_D,   BADLEN,  T89_LD,  BADLEN,  BADLEN,  BADLEN  }, "-wp0 +#'", "",   NULL },
8139d1607cfSmiod   { "eE",  0, STD_C89, { T89_D,   BADLEN,  BADLEN,  T99_D,   BADLEN,  T89_LD,  BADLEN,  BADLEN,  BADLEN  }, "-wp0 +#",  "",   NULL },
8149d1607cfSmiod   { "c",   0, STD_C89, { T89_I,   BADLEN,  BADLEN,  T94_WI,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN  }, "-w",       "",   NULL },
8159d1607cfSmiod   { "s",   1, STD_C89, { T89_C,   BADLEN,  BADLEN,  T94_W,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN  }, "-wp",      "cR", NULL },
8169d1607cfSmiod   { "p",   1, STD_C89, { T89_V,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN  }, "-w",       "c",  NULL },
8179d1607cfSmiod   { "n",   1, STD_C89, { T89_I,   T99_SC,  T89_S,   T89_L,   T9L_LL,  BADLEN,  T99_SST, T99_PD,  T99_IM  }, "",         "W",  NULL },
818d9f573dfSespie   /* C99 conversion specifiers.  */
8199d1607cfSmiod   { "F",   0, STD_C99, { T99_D,   BADLEN,  BADLEN,  T99_D,   BADLEN,  T99_LD,  BADLEN,  BADLEN,  BADLEN  }, "-wp0 +#'", "",   NULL },
8209d1607cfSmiod   { "aA",  0, STD_C99, { T99_D,   BADLEN,  BADLEN,  T99_D,   BADLEN,  T99_LD,  BADLEN,  BADLEN,  BADLEN  }, "-wp0 +#",  "",   NULL },
821d9f573dfSespie   /* X/Open conversion specifiers.  */
8229d1607cfSmiod   { "C",   0, STD_EXT, { TEX_WI,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN  }, "-w",       "",   NULL },
8239d1607cfSmiod   { "S",   1, STD_EXT, { TEX_W,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN  }, "-wp",      "R",  NULL },
8249d1607cfSmiod   { "m",   0, STD_C89, { T89_V,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN  }, "-wp",      "",   NULL },
8259d1607cfSmiod   { NULL,  0, 0, NOLENGTHS, NULL, NULL, NULL }
826d9f573dfSespie };
827d9f573dfSespie 
828c87b03e5Sespie static const format_char_info scan_char_table[] =
829c87b03e5Sespie {
830c87b03e5Sespie   /* C89 conversion specifiers.  */
8319d1607cfSmiod   { "di",    1, STD_C89, { T89_I,   T99_SC,  T89_S,   T89_L,   T9L_LL,  TEX_LL,  T99_SST, T99_PD,  T99_IM  }, "*w'I", "W",   NULL },
8329d1607cfSmiod   { "u",     1, STD_C89, { T89_UI,  T99_UC,  T89_US,  T89_UL,  T9L_ULL, TEX_ULL, T99_ST,  T99_UPD, T99_UIM }, "*w'I", "W",   NULL },
8339d1607cfSmiod   { "oxX",   1, STD_C89, { T89_UI,  T99_UC,  T89_US,  T89_UL,  T9L_ULL, TEX_ULL, T99_ST,  T99_UPD, T99_UIM }, "*w",   "W",   NULL },
8349d1607cfSmiod   { "efgEG", 1, STD_C89, { T89_F,   BADLEN,  BADLEN,  T89_D,   BADLEN,  T89_LD,  BADLEN,  BADLEN,  BADLEN  }, "*w'",  "W",   NULL },
8359d1607cfSmiod   { "c",     1, STD_C89, { T89_C,   BADLEN,  BADLEN,  T94_W,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN  }, "*w",   "cW",  NULL },
8369d1607cfSmiod   { "s",     1, STD_C89, { T89_C,   BADLEN,  BADLEN,  T94_W,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN  }, "*aw",  "cW",  NULL },
8379d1607cfSmiod   { "[",     1, STD_C89, { T89_C,   BADLEN,  BADLEN,  T94_W,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN  }, "*aw",  "cW[", NULL },
8389d1607cfSmiod   { "p",     2, STD_C89, { T89_V,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN  }, "*w",   "W",   NULL },
8399d1607cfSmiod   { "n",     1, STD_C89, { T89_I,   T99_SC,  T89_S,   T89_L,   T9L_LL,  BADLEN,  T99_SST, T99_PD,  T99_IM  }, "",     "W",   NULL },
840c87b03e5Sespie   /* C99 conversion specifiers.  */
8419d1607cfSmiod   { "FaA",   1, STD_C99, { T99_F,   BADLEN,  BADLEN,  T99_D,   BADLEN,  T99_LD,  BADLEN,  BADLEN,  BADLEN  }, "*w'",  "W",   NULL },
842c87b03e5Sespie   /* X/Open conversion specifiers.  */
8439d1607cfSmiod   { "C",     1, STD_EXT, { TEX_W,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN  }, "*w",   "W",   NULL },
8449d1607cfSmiod   { "S",     1, STD_EXT, { TEX_W,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN  }, "*aw",  "W",   NULL },
8459d1607cfSmiod   { NULL, 0, 0, NOLENGTHS, NULL, NULL, NULL }
846c87b03e5Sespie };
847c87b03e5Sespie 
848c87b03e5Sespie static const format_char_info time_char_table[] =
849c87b03e5Sespie {
850c87b03e5Sespie   /* C89 conversion specifiers.  */
8519d1607cfSmiod   { "ABZab",		0, STD_C89, NOLENGTHS, "^#",     "",   NULL },
8529d1607cfSmiod   { "cx", 		0, STD_C89, NOLENGTHS, "E",      "3",  NULL },
8539d1607cfSmiod   { "HIMSUWdmw",	0, STD_C89, NOLENGTHS, "-_0Ow",  "",   NULL },
8549d1607cfSmiod   { "j",		0, STD_C89, NOLENGTHS, "-_0Ow",  "o",  NULL },
8559d1607cfSmiod   { "p",		0, STD_C89, NOLENGTHS, "#",      "",   NULL },
8569d1607cfSmiod   { "X",		0, STD_C89, NOLENGTHS, "E",      "",   NULL },
8579d1607cfSmiod   { "y", 		0, STD_C89, NOLENGTHS, "EO-_0w", "4",  NULL },
8589d1607cfSmiod   { "Y",		0, STD_C89, NOLENGTHS, "-_0EOw", "o",  NULL },
8599d1607cfSmiod   { "%",		0, STD_C89, NOLENGTHS, "",       "",   NULL },
860c87b03e5Sespie   /* C99 conversion specifiers.  */
8619d1607cfSmiod   { "C",		0, STD_C99, NOLENGTHS, "-_0EOw", "o",  NULL },
8629d1607cfSmiod   { "D", 		0, STD_C99, NOLENGTHS, "",       "2",  NULL },
8639d1607cfSmiod   { "eVu",		0, STD_C99, NOLENGTHS, "-_0Ow",  "",   NULL },
8649d1607cfSmiod   { "FRTnrt",		0, STD_C99, NOLENGTHS, "",       "",   NULL },
8659d1607cfSmiod   { "g", 		0, STD_C99, NOLENGTHS, "O-_0w",  "2o", NULL },
8669d1607cfSmiod   { "G",		0, STD_C99, NOLENGTHS, "-_0Ow",  "o",  NULL },
8679d1607cfSmiod   { "h",		0, STD_C99, NOLENGTHS, "^#",     "",   NULL },
8689d1607cfSmiod   { "z",		0, STD_C99, NOLENGTHS, "O",      "o",  NULL },
869c87b03e5Sespie   /* GNU conversion specifiers.  */
8709d1607cfSmiod   { "kls",		0, STD_EXT, NOLENGTHS, "-_0Ow",  "",   NULL },
8719d1607cfSmiod   { "P",		0, STD_EXT, NOLENGTHS, "",       "",   NULL },
8729d1607cfSmiod   { NULL,		0, 0, NOLENGTHS, NULL, NULL, NULL }
873c87b03e5Sespie };
874c87b03e5Sespie 
875c87b03e5Sespie static const format_char_info monetary_char_table[] =
876c87b03e5Sespie {
8779d1607cfSmiod   { "in", 0, STD_C89, { T89_D, BADLEN, BADLEN, BADLEN, BADLEN, T89_LD, BADLEN, BADLEN, BADLEN }, "=^+(!-w#p", "", NULL },
8789d1607cfSmiod   { NULL, 0, 0, NOLENGTHS, NULL, NULL, NULL }
879c87b03e5Sespie };
880c87b03e5Sespie 
881c87b03e5Sespie 
882c87b03e5Sespie /* This must be in the same order as enum format_type.  */
883c87b03e5Sespie static const format_kind_info format_types[] =
884c87b03e5Sespie {
885c87b03e5Sespie   { "printf",   printf_length_specs,  print_char_table, " +#0-'I", NULL,
886c87b03e5Sespie     printf_flag_specs, printf_flag_pairs,
887c87b03e5Sespie     FMT_FLAG_ARG_CONVERT|FMT_FLAG_DOLLAR_MULTIPLE|FMT_FLAG_USE_DOLLAR|FMT_FLAG_EMPTY_PREC_OK,
888c87b03e5Sespie     'w', 0, 'p', 0, 'L',
889c87b03e5Sespie     &integer_type_node, &integer_type_node
890c87b03e5Sespie   },
891d9f573dfSespie   { "kprintf",   kprintf_length_specs,  kprint_char_table, " +#0-'I", NULL,
892d9f573dfSespie     printf_flag_specs, printf_flag_pairs,
893*e8f4cb76Sguenther     FMT_FLAG_ARG_CONVERT|FMT_FLAG_EMPTY_PREC_OK,
894d9f573dfSespie     'w', 0, 'p', 0, 'L',
895d9f573dfSespie     &integer_type_node, &integer_type_node
896d9f573dfSespie   },
897d9f573dfSespie   { "syslog",   printf_length_specs,  syslog_char_table, " +#0-'I", NULL,
898d9f573dfSespie     printf_flag_specs, printf_flag_pairs,
899d9f573dfSespie     FMT_FLAG_ARG_CONVERT|FMT_FLAG_DOLLAR_MULTIPLE|FMT_FLAG_USE_DOLLAR|FMT_FLAG_EMPTY_PREC_OK,
900d9f573dfSespie     'w', 0, 'p', 0, 'L',
901d9f573dfSespie     &integer_type_node, &integer_type_node
902d9f573dfSespie   },
903c87b03e5Sespie   { "scanf",    scanf_length_specs,   scan_char_table,  "*'I", NULL,
904c87b03e5Sespie     scanf_flag_specs, scanf_flag_pairs,
905c87b03e5Sespie     FMT_FLAG_ARG_CONVERT|FMT_FLAG_SCANF_A_KLUDGE|FMT_FLAG_USE_DOLLAR|FMT_FLAG_ZERO_WIDTH_BAD|FMT_FLAG_DOLLAR_GAP_POINTER_OK,
906c87b03e5Sespie     'w', 0, 0, '*', 'L',
907c87b03e5Sespie     NULL, NULL
908c87b03e5Sespie   },
909c87b03e5Sespie   { "strftime", NULL,                 time_char_table,  "_-0^#", "EO",
910c87b03e5Sespie     strftime_flag_specs, strftime_flag_pairs,
911c87b03e5Sespie     FMT_FLAG_FANCY_PERCENT_OK, 'w', 0, 0, 0, 0,
912c87b03e5Sespie     NULL, NULL
913c87b03e5Sespie   },
914c87b03e5Sespie   { "strfmon",  strfmon_length_specs, monetary_char_table, "=^+(!-", NULL,
915c87b03e5Sespie     strfmon_flag_specs, strfmon_flag_pairs,
916c87b03e5Sespie     FMT_FLAG_ARG_CONVERT, 'w', '#', 'p', 0, 'L',
917c87b03e5Sespie     NULL, NULL
918c87b03e5Sespie   }
919c87b03e5Sespie };
920c87b03e5Sespie 
921c87b03e5Sespie 
922c87b03e5Sespie /* Structure detailing the results of checking a format function call
923c87b03e5Sespie    where the format expression may be a conditional expression with
924c87b03e5Sespie    many leaves resulting from nested conditional expressions.  */
925c87b03e5Sespie typedef struct
926c87b03e5Sespie {
927c87b03e5Sespie   /* Number of leaves of the format argument that could not be checked
928c87b03e5Sespie      as they were not string literals.  */
929c87b03e5Sespie   int number_non_literal;
930c87b03e5Sespie   /* Number of leaves of the format argument that were null pointers or
931c87b03e5Sespie      string literals, but had extra format arguments.  */
932c87b03e5Sespie   int number_extra_args;
933c87b03e5Sespie   /* Number of leaves of the format argument that were null pointers or
934c87b03e5Sespie      string literals, but had extra format arguments and used $ operand
935c87b03e5Sespie      numbers.  */
936c87b03e5Sespie   int number_dollar_extra_args;
937c87b03e5Sespie   /* Number of leaves of the format argument that were wide string
938c87b03e5Sespie      literals.  */
939c87b03e5Sespie   int number_wide;
940c87b03e5Sespie   /* Number of leaves of the format argument that were empty strings.  */
941c87b03e5Sespie   int number_empty;
942c87b03e5Sespie   /* Number of leaves of the format argument that were unterminated
943c87b03e5Sespie      strings.  */
944c87b03e5Sespie   int number_unterminated;
945c87b03e5Sespie   /* Number of leaves of the format argument that were not counted above.  */
946c87b03e5Sespie   int number_other;
947c87b03e5Sespie } format_check_results;
948c87b03e5Sespie 
949c87b03e5Sespie typedef struct
950c87b03e5Sespie {
951c87b03e5Sespie   format_check_results *res;
952c87b03e5Sespie   function_format_info *info;
953c87b03e5Sespie   tree params;
954c87b03e5Sespie   int *status;
955c87b03e5Sespie } format_check_context;
956c87b03e5Sespie 
957c87b03e5Sespie static void check_format_info	PARAMS ((int *, function_format_info *, tree));
958c87b03e5Sespie static void check_format_arg	PARAMS ((void *, tree, unsigned HOST_WIDE_INT));
959c87b03e5Sespie static void check_format_info_main PARAMS ((int *, format_check_results *,
960c87b03e5Sespie 					    function_format_info *,
961c87b03e5Sespie 					    const char *, int, tree,
962c87b03e5Sespie 					    unsigned HOST_WIDE_INT));
963c87b03e5Sespie static void status_warning PARAMS ((int *, const char *, ...))
964c87b03e5Sespie      ATTRIBUTE_PRINTF_2;
965c87b03e5Sespie 
966c87b03e5Sespie static void init_dollar_format_checking		PARAMS ((int, tree));
967c87b03e5Sespie static int maybe_read_dollar_number		PARAMS ((int *, const char **, int,
968c87b03e5Sespie 							 tree, tree *,
969c87b03e5Sespie 							 const format_kind_info *));
970c87b03e5Sespie static void finish_dollar_format_checking	PARAMS ((int *, format_check_results *, int));
971c87b03e5Sespie 
972c87b03e5Sespie static const format_flag_spec *get_flag_spec	PARAMS ((const format_flag_spec *,
973c87b03e5Sespie 							 int, const char *));
974c87b03e5Sespie 
975f15b70e2Savsm static void check_format_types	PARAMS ((int *, format_wanted_type *, bool));
976c87b03e5Sespie 
977c87b03e5Sespie /* Decode a format type from a string, returning the type, or
978c87b03e5Sespie    format_type_error if not valid, in which case the caller should print an
979c87b03e5Sespie    error message.  */
980c87b03e5Sespie static enum format_type
decode_format_type(s)981c87b03e5Sespie decode_format_type (s)
982c87b03e5Sespie      const char *s;
983c87b03e5Sespie {
984c87b03e5Sespie   int i;
985c87b03e5Sespie   int slen;
986c87b03e5Sespie   slen = strlen (s);
987c87b03e5Sespie   for (i = 0; i < (int) format_type_error; i++)
988c87b03e5Sespie     {
989c87b03e5Sespie       int alen;
990c87b03e5Sespie       if (!strcmp (s, format_types[i].name))
991c87b03e5Sespie 	break;
992c87b03e5Sespie       alen = strlen (format_types[i].name);
993c87b03e5Sespie       if (slen == alen + 4 && s[0] == '_' && s[1] == '_'
994c87b03e5Sespie 	  && s[slen - 1] == '_' && s[slen - 2] == '_'
995c87b03e5Sespie 	  && !strncmp (s + 2, format_types[i].name, alen))
996c87b03e5Sespie 	break;
997c87b03e5Sespie     }
998c87b03e5Sespie   return ((enum format_type) i);
999c87b03e5Sespie }
1000c87b03e5Sespie 
1001c87b03e5Sespie 
1002c87b03e5Sespie /* Check the argument list of a call to printf, scanf, etc.
1003c87b03e5Sespie    ATTRS are the attributes on the function type.
1004c87b03e5Sespie    PARAMS is the list of argument values.  Also, if -Wmissing-format-attribute,
1005c87b03e5Sespie    warn for calls to vprintf or vscanf in functions with no such format
1006c87b03e5Sespie    attribute themselves.  */
1007c87b03e5Sespie 
1008c87b03e5Sespie void
check_function_format(status,attrs,params)1009c87b03e5Sespie check_function_format (status, attrs, params)
1010c87b03e5Sespie      int *status;
1011c87b03e5Sespie      tree attrs;
1012c87b03e5Sespie      tree params;
1013c87b03e5Sespie {
1014c87b03e5Sespie   tree a;
1015c87b03e5Sespie 
1016c87b03e5Sespie   /* See if this function has any format attributes.  */
1017c87b03e5Sespie   for (a = attrs; a; a = TREE_CHAIN (a))
1018c87b03e5Sespie     {
1019c87b03e5Sespie       if (is_attribute_p ("format", TREE_PURPOSE (a)))
1020c87b03e5Sespie 	{
1021c87b03e5Sespie 	  /* Yup; check it.  */
1022c87b03e5Sespie 	  function_format_info info;
1023c87b03e5Sespie 	  decode_format_attr (TREE_VALUE (a), &info, 1);
1024c87b03e5Sespie 	  check_format_info (status, &info, params);
1025c87b03e5Sespie 	  if (warn_missing_format_attribute && info.first_arg_num == 0
1026c87b03e5Sespie 	      && (format_types[info.format_type].flags
1027c87b03e5Sespie 		  & (int) FMT_FLAG_ARG_CONVERT))
1028c87b03e5Sespie 	    {
1029c87b03e5Sespie 	      tree c;
1030c87b03e5Sespie 	      for (c = TYPE_ATTRIBUTES (TREE_TYPE (current_function_decl));
1031c87b03e5Sespie 		   c;
1032c87b03e5Sespie 		   c = TREE_CHAIN (c))
1033c87b03e5Sespie 		if (is_attribute_p ("format", TREE_PURPOSE (c))
1034c87b03e5Sespie 		    && (decode_format_type (IDENTIFIER_POINTER
1035c87b03e5Sespie 					    (TREE_VALUE (TREE_VALUE (c))))
1036c87b03e5Sespie 			== info.format_type))
1037c87b03e5Sespie 		  break;
1038c87b03e5Sespie 	      if (c == NULL_TREE)
1039c87b03e5Sespie 		{
1040c87b03e5Sespie 		  /* Check if the current function has a parameter to which
1041c87b03e5Sespie 		     the format attribute could be attached; if not, it
1042c87b03e5Sespie 		     can't be a candidate for a format attribute, despite
1043c87b03e5Sespie 		     the vprintf-like or vscanf-like call.  */
1044c87b03e5Sespie 		  tree args;
1045c87b03e5Sespie 		  for (args = DECL_ARGUMENTS (current_function_decl);
1046c87b03e5Sespie 		       args != 0;
1047c87b03e5Sespie 		       args = TREE_CHAIN (args))
1048c87b03e5Sespie 		    {
1049c87b03e5Sespie 		      if (TREE_CODE (TREE_TYPE (args)) == POINTER_TYPE
1050c87b03e5Sespie 			  && (TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (args)))
1051c87b03e5Sespie 			      == char_type_node))
1052c87b03e5Sespie 			break;
1053c87b03e5Sespie 		    }
1054c87b03e5Sespie 		  if (args != 0)
1055c87b03e5Sespie 		    warning ("function might be possible candidate for `%s' format attribute",
1056c87b03e5Sespie 			     format_types[info.format_type].name);
1057c87b03e5Sespie 		}
1058c87b03e5Sespie 	    }
1059c87b03e5Sespie 	}
1060c87b03e5Sespie     }
1061c87b03e5Sespie }
1062c87b03e5Sespie 
1063c87b03e5Sespie /* This function replaces `warning' inside the printf format checking
1064c87b03e5Sespie    functions.  If the `status' parameter is non-NULL, then it is
1065c87b03e5Sespie    dereferenced and set to 1 whenever a warning is caught.  Otherwise
1066c87b03e5Sespie    it warns as usual by replicating the innards of the warning
1067c87b03e5Sespie    function from diagnostic.c.  */
1068c87b03e5Sespie static void
status_warning(int * status,const char * msgid,...)1069c87b03e5Sespie status_warning VPARAMS ((int *status, const char *msgid, ...))
1070c87b03e5Sespie {
1071c87b03e5Sespie   diagnostic_info diagnostic ;
1072c87b03e5Sespie 
1073c87b03e5Sespie   VA_OPEN (ap, msgid);
1074c87b03e5Sespie   VA_FIXEDARG (ap, int *, status);
1075c87b03e5Sespie   VA_FIXEDARG (ap, const char *, msgid);
1076c87b03e5Sespie 
1077c87b03e5Sespie   if (status)
1078c87b03e5Sespie     *status = 1;
1079c87b03e5Sespie   else
1080c87b03e5Sespie     {
1081c87b03e5Sespie       /* This duplicates the warning function behavior.  */
1082c87b03e5Sespie       diagnostic_set_info (&diagnostic, _(msgid), &ap, input_filename, lineno,
1083c87b03e5Sespie                            DK_WARNING);
1084c87b03e5Sespie       report_diagnostic (&diagnostic);
1085c87b03e5Sespie     }
1086c87b03e5Sespie 
1087c87b03e5Sespie   VA_CLOSE (ap);
1088c87b03e5Sespie }
1089c87b03e5Sespie 
1090c87b03e5Sespie /* Variables used by the checking of $ operand number formats.  */
1091c87b03e5Sespie static char *dollar_arguments_used = NULL;
1092c87b03e5Sespie static char *dollar_arguments_pointer_p = NULL;
1093c87b03e5Sespie static int dollar_arguments_alloc = 0;
1094c87b03e5Sespie static int dollar_arguments_count;
1095c87b03e5Sespie static int dollar_first_arg_num;
1096c87b03e5Sespie static int dollar_max_arg_used;
1097c87b03e5Sespie static int dollar_format_warned;
1098c87b03e5Sespie 
1099c87b03e5Sespie /* Initialize the checking for a format string that may contain $
1100c87b03e5Sespie    parameter number specifications; we will need to keep track of whether
1101c87b03e5Sespie    each parameter has been used.  FIRST_ARG_NUM is the number of the first
1102c87b03e5Sespie    argument that is a parameter to the format, or 0 for a vprintf-style
1103c87b03e5Sespie    function; PARAMS is the list of arguments starting at this argument.  */
1104c87b03e5Sespie 
1105c87b03e5Sespie static void
init_dollar_format_checking(first_arg_num,params)1106c87b03e5Sespie init_dollar_format_checking (first_arg_num, params)
1107c87b03e5Sespie      int first_arg_num;
1108c87b03e5Sespie      tree params;
1109c87b03e5Sespie {
1110c87b03e5Sespie   tree oparams = params;
1111c87b03e5Sespie 
1112c87b03e5Sespie   dollar_first_arg_num = first_arg_num;
1113c87b03e5Sespie   dollar_arguments_count = 0;
1114c87b03e5Sespie   dollar_max_arg_used = 0;
1115c87b03e5Sespie   dollar_format_warned = 0;
1116c87b03e5Sespie   if (first_arg_num > 0)
1117c87b03e5Sespie     {
1118c87b03e5Sespie       while (params)
1119c87b03e5Sespie 	{
1120c87b03e5Sespie 	  dollar_arguments_count++;
1121c87b03e5Sespie 	  params = TREE_CHAIN (params);
1122c87b03e5Sespie 	}
1123c87b03e5Sespie     }
1124c87b03e5Sespie   if (dollar_arguments_alloc < dollar_arguments_count)
1125c87b03e5Sespie     {
1126c87b03e5Sespie       if (dollar_arguments_used)
1127c87b03e5Sespie 	free (dollar_arguments_used);
1128c87b03e5Sespie       if (dollar_arguments_pointer_p)
1129c87b03e5Sespie 	free (dollar_arguments_pointer_p);
1130c87b03e5Sespie       dollar_arguments_alloc = dollar_arguments_count;
1131c87b03e5Sespie       dollar_arguments_used = xmalloc (dollar_arguments_alloc);
1132c87b03e5Sespie       dollar_arguments_pointer_p = xmalloc (dollar_arguments_alloc);
1133c87b03e5Sespie     }
1134c87b03e5Sespie   if (dollar_arguments_alloc)
1135c87b03e5Sespie     {
1136c87b03e5Sespie       memset (dollar_arguments_used, 0, dollar_arguments_alloc);
1137c87b03e5Sespie       if (first_arg_num > 0)
1138c87b03e5Sespie 	{
1139c87b03e5Sespie 	  int i = 0;
1140c87b03e5Sespie 	  params = oparams;
1141c87b03e5Sespie 	  while (params)
1142c87b03e5Sespie 	    {
1143c87b03e5Sespie 	      dollar_arguments_pointer_p[i] = (TREE_CODE (TREE_TYPE (TREE_VALUE (params)))
1144c87b03e5Sespie 					       == POINTER_TYPE);
1145c87b03e5Sespie 	      params = TREE_CHAIN (params);
1146c87b03e5Sespie 	      i++;
1147c87b03e5Sespie 	    }
1148c87b03e5Sespie 	}
1149c87b03e5Sespie     }
1150c87b03e5Sespie }
1151c87b03e5Sespie 
1152c87b03e5Sespie 
1153c87b03e5Sespie /* Look for a decimal number followed by a $ in *FORMAT.  If DOLLAR_NEEDED
1154c87b03e5Sespie    is set, it is an error if one is not found; otherwise, it is OK.  If
1155c87b03e5Sespie    such a number is found, check whether it is within range and mark that
1156c87b03e5Sespie    numbered operand as being used for later checking.  Returns the operand
1157c87b03e5Sespie    number if found and within range, zero if no such number was found and
1158c87b03e5Sespie    this is OK, or -1 on error.  PARAMS points to the first operand of the
1159c87b03e5Sespie    format; PARAM_PTR is made to point to the parameter referred to.  If
1160c87b03e5Sespie    a $ format is found, *FORMAT is updated to point just after it.  */
1161c87b03e5Sespie 
1162c87b03e5Sespie static int
maybe_read_dollar_number(status,format,dollar_needed,params,param_ptr,fki)1163c87b03e5Sespie maybe_read_dollar_number (status, format, dollar_needed, params, param_ptr,
1164c87b03e5Sespie 			  fki)
1165c87b03e5Sespie      int *status;
1166c87b03e5Sespie      const char **format;
1167c87b03e5Sespie      int dollar_needed;
1168c87b03e5Sespie      tree params;
1169c87b03e5Sespie      tree *param_ptr;
1170c87b03e5Sespie      const format_kind_info *fki;
1171c87b03e5Sespie {
1172c87b03e5Sespie   int argnum;
1173c87b03e5Sespie   int overflow_flag;
1174c87b03e5Sespie   const char *fcp = *format;
1175c87b03e5Sespie   if (! ISDIGIT (*fcp))
1176c87b03e5Sespie     {
1177c87b03e5Sespie       if (dollar_needed)
1178c87b03e5Sespie 	{
1179c87b03e5Sespie 	  status_warning (status, "missing $ operand number in format");
1180c87b03e5Sespie 	  return -1;
1181c87b03e5Sespie 	}
1182c87b03e5Sespie       else
1183c87b03e5Sespie 	return 0;
1184c87b03e5Sespie     }
1185c87b03e5Sespie   argnum = 0;
1186c87b03e5Sespie   overflow_flag = 0;
1187c87b03e5Sespie   while (ISDIGIT (*fcp))
1188c87b03e5Sespie     {
1189c87b03e5Sespie       int nargnum;
1190c87b03e5Sespie       nargnum = 10 * argnum + (*fcp - '0');
1191c87b03e5Sespie       if (nargnum < 0 || nargnum / 10 != argnum)
1192c87b03e5Sespie 	overflow_flag = 1;
1193c87b03e5Sespie       argnum = nargnum;
1194c87b03e5Sespie       fcp++;
1195c87b03e5Sespie     }
1196c87b03e5Sespie   if (*fcp != '$')
1197c87b03e5Sespie     {
1198c87b03e5Sespie       if (dollar_needed)
1199c87b03e5Sespie 	{
1200c87b03e5Sespie 	  status_warning (status, "missing $ operand number in format");
1201c87b03e5Sespie 	  return -1;
1202c87b03e5Sespie 	}
1203c87b03e5Sespie       else
1204c87b03e5Sespie 	return 0;
1205c87b03e5Sespie     }
1206c87b03e5Sespie   *format = fcp + 1;
1207c87b03e5Sespie   if (pedantic && !dollar_format_warned)
1208c87b03e5Sespie     {
1209c87b03e5Sespie       status_warning (status,
1210c87b03e5Sespie 		      "%s does not support %%n$ operand number formats",
1211c87b03e5Sespie 		      C_STD_NAME (STD_EXT));
1212c87b03e5Sespie       dollar_format_warned = 1;
1213c87b03e5Sespie     }
1214c87b03e5Sespie   if (overflow_flag || argnum == 0
1215c87b03e5Sespie       || (dollar_first_arg_num && argnum > dollar_arguments_count))
1216c87b03e5Sespie     {
1217c87b03e5Sespie       status_warning (status, "operand number out of range in format");
1218c87b03e5Sespie       return -1;
1219c87b03e5Sespie     }
1220c87b03e5Sespie   if (argnum > dollar_max_arg_used)
1221c87b03e5Sespie     dollar_max_arg_used = argnum;
1222c87b03e5Sespie   /* For vprintf-style functions we may need to allocate more memory to
1223c87b03e5Sespie      track which arguments are used.  */
1224c87b03e5Sespie   while (dollar_arguments_alloc < dollar_max_arg_used)
1225c87b03e5Sespie     {
1226c87b03e5Sespie       int nalloc;
1227c87b03e5Sespie       nalloc = 2 * dollar_arguments_alloc + 16;
1228c87b03e5Sespie       dollar_arguments_used = xrealloc (dollar_arguments_used, nalloc);
1229c87b03e5Sespie       dollar_arguments_pointer_p = xrealloc (dollar_arguments_pointer_p,
1230c87b03e5Sespie 					     nalloc);
1231c87b03e5Sespie       memset (dollar_arguments_used + dollar_arguments_alloc, 0,
1232c87b03e5Sespie 	      nalloc - dollar_arguments_alloc);
1233c87b03e5Sespie       dollar_arguments_alloc = nalloc;
1234c87b03e5Sespie     }
1235c87b03e5Sespie   if (!(fki->flags & (int) FMT_FLAG_DOLLAR_MULTIPLE)
1236c87b03e5Sespie       && dollar_arguments_used[argnum - 1] == 1)
1237c87b03e5Sespie     {
1238c87b03e5Sespie       dollar_arguments_used[argnum - 1] = 2;
1239c87b03e5Sespie       status_warning (status,
1240c87b03e5Sespie 		      "format argument %d used more than once in %s format",
1241c87b03e5Sespie 		      argnum, fki->name);
1242c87b03e5Sespie     }
1243c87b03e5Sespie   else
1244c87b03e5Sespie     dollar_arguments_used[argnum - 1] = 1;
1245c87b03e5Sespie   if (dollar_first_arg_num)
1246c87b03e5Sespie     {
1247c87b03e5Sespie       int i;
1248c87b03e5Sespie       *param_ptr = params;
1249c87b03e5Sespie       for (i = 1; i < argnum && *param_ptr != 0; i++)
1250c87b03e5Sespie 	*param_ptr = TREE_CHAIN (*param_ptr);
1251c87b03e5Sespie 
1252c87b03e5Sespie       if (*param_ptr == 0)
1253c87b03e5Sespie 	{
1254c87b03e5Sespie 	  /* This case shouldn't be caught here.  */
1255c87b03e5Sespie 	  abort ();
1256c87b03e5Sespie 	}
1257c87b03e5Sespie     }
1258c87b03e5Sespie   else
1259c87b03e5Sespie     *param_ptr = 0;
1260c87b03e5Sespie   return argnum;
1261c87b03e5Sespie }
1262c87b03e5Sespie 
1263c87b03e5Sespie 
1264c87b03e5Sespie /* Finish the checking for a format string that used $ operand number formats
1265c87b03e5Sespie    instead of non-$ formats.  We check for unused operands before used ones
1266c87b03e5Sespie    (a serious error, since the implementation of the format function
1267c87b03e5Sespie    can't know what types to pass to va_arg to find the later arguments).
1268c87b03e5Sespie    and for unused operands at the end of the format (if we know how many
1269c87b03e5Sespie    arguments the format had, so not for vprintf).  If there were operand
1270c87b03e5Sespie    numbers out of range on a non-vprintf-style format, we won't have reached
1271c87b03e5Sespie    here.  If POINTER_GAP_OK, unused arguments are OK if all arguments are
1272c87b03e5Sespie    pointers.  */
1273c87b03e5Sespie 
1274c87b03e5Sespie static void
finish_dollar_format_checking(status,res,pointer_gap_ok)1275c87b03e5Sespie finish_dollar_format_checking (status, res, pointer_gap_ok)
1276c87b03e5Sespie      int *status;
1277c87b03e5Sespie      format_check_results *res;
1278c87b03e5Sespie      int pointer_gap_ok;
1279c87b03e5Sespie {
1280c87b03e5Sespie   int i;
1281c87b03e5Sespie   bool found_pointer_gap = false;
1282c87b03e5Sespie   for (i = 0; i < dollar_max_arg_used; i++)
1283c87b03e5Sespie     {
1284c87b03e5Sespie       if (!dollar_arguments_used[i])
1285c87b03e5Sespie 	{
1286c87b03e5Sespie 	  if (pointer_gap_ok && (dollar_first_arg_num == 0
1287c87b03e5Sespie 				 || dollar_arguments_pointer_p[i]))
1288c87b03e5Sespie 	    found_pointer_gap = true;
1289c87b03e5Sespie 	  else
1290c87b03e5Sespie 	    status_warning (status, "format argument %d unused before used argument %d in $-style format",
1291c87b03e5Sespie 			    i + 1, dollar_max_arg_used);
1292c87b03e5Sespie 	}
1293c87b03e5Sespie     }
1294c87b03e5Sespie   if (found_pointer_gap
1295c87b03e5Sespie       || (dollar_first_arg_num
1296c87b03e5Sespie 	  && dollar_max_arg_used < dollar_arguments_count))
1297c87b03e5Sespie     {
1298c87b03e5Sespie       res->number_other--;
1299c87b03e5Sespie       res->number_dollar_extra_args++;
1300c87b03e5Sespie     }
1301c87b03e5Sespie }
1302c87b03e5Sespie 
1303c87b03e5Sespie 
1304c87b03e5Sespie /* Retrieve the specification for a format flag.  SPEC contains the
1305c87b03e5Sespie    specifications for format flags for the applicable kind of format.
1306c87b03e5Sespie    FLAG is the flag in question.  If PREDICATES is NULL, the basic
1307c87b03e5Sespie    spec for that flag must be retrieved and this function aborts if
1308c87b03e5Sespie    it cannot be found.  If PREDICATES is not NULL, it is a string listing
1309c87b03e5Sespie    possible predicates for the spec entry; if an entry predicated on any
1310c87b03e5Sespie    of these is found, it is returned, otherwise NULL is returned.  */
1311c87b03e5Sespie 
1312c87b03e5Sespie static const format_flag_spec *
get_flag_spec(spec,flag,predicates)1313c87b03e5Sespie get_flag_spec (spec, flag, predicates)
1314c87b03e5Sespie      const format_flag_spec *spec;
1315c87b03e5Sespie      int flag;
1316c87b03e5Sespie      const char *predicates;
1317c87b03e5Sespie {
1318c87b03e5Sespie   int i;
1319c87b03e5Sespie   for (i = 0; spec[i].flag_char != 0; i++)
1320c87b03e5Sespie     {
1321c87b03e5Sespie       if (spec[i].flag_char != flag)
1322c87b03e5Sespie 	continue;
1323c87b03e5Sespie       if (predicates != NULL)
1324c87b03e5Sespie 	{
1325c87b03e5Sespie 	  if (spec[i].predicate != 0
1326c87b03e5Sespie 	      && strchr (predicates, spec[i].predicate) != 0)
1327c87b03e5Sespie 	    return &spec[i];
1328c87b03e5Sespie 	}
1329c87b03e5Sespie       else if (spec[i].predicate == 0)
1330c87b03e5Sespie 	return &spec[i];
1331c87b03e5Sespie     }
1332c87b03e5Sespie   if (predicates == NULL)
1333c87b03e5Sespie     abort ();
1334c87b03e5Sespie   else
1335c87b03e5Sespie     return NULL;
1336c87b03e5Sespie }
1337c87b03e5Sespie 
1338c87b03e5Sespie 
1339c87b03e5Sespie /* Check the argument list of a call to printf, scanf, etc.
1340c87b03e5Sespie    INFO points to the function_format_info structure.
1341c87b03e5Sespie    PARAMS is the list of argument values.  */
1342c87b03e5Sespie 
1343c87b03e5Sespie static void
check_format_info(status,info,params)1344c87b03e5Sespie check_format_info (status, info, params)
1345c87b03e5Sespie      int *status;
1346c87b03e5Sespie      function_format_info *info;
1347c87b03e5Sespie      tree params;
1348c87b03e5Sespie {
1349c87b03e5Sespie   format_check_context format_ctx;
1350c87b03e5Sespie   unsigned HOST_WIDE_INT arg_num;
1351c87b03e5Sespie   tree format_tree;
1352c87b03e5Sespie   format_check_results res;
1353c87b03e5Sespie   /* Skip to format argument.  If the argument isn't available, there's
1354c87b03e5Sespie      no work for us to do; prototype checking will catch the problem.  */
1355c87b03e5Sespie   for (arg_num = 1; ; ++arg_num)
1356c87b03e5Sespie     {
1357c87b03e5Sespie       if (params == 0)
1358c87b03e5Sespie 	return;
1359c87b03e5Sespie       if (arg_num == info->format_num)
1360c87b03e5Sespie 	break;
1361c87b03e5Sespie       params = TREE_CHAIN (params);
1362c87b03e5Sespie     }
1363c87b03e5Sespie   format_tree = TREE_VALUE (params);
1364c87b03e5Sespie   params = TREE_CHAIN (params);
1365c87b03e5Sespie   if (format_tree == 0)
1366c87b03e5Sespie     return;
1367c87b03e5Sespie 
1368c87b03e5Sespie   res.number_non_literal = 0;
1369c87b03e5Sespie   res.number_extra_args = 0;
1370c87b03e5Sespie   res.number_dollar_extra_args = 0;
1371c87b03e5Sespie   res.number_wide = 0;
1372c87b03e5Sespie   res.number_empty = 0;
1373c87b03e5Sespie   res.number_unterminated = 0;
1374c87b03e5Sespie   res.number_other = 0;
1375c87b03e5Sespie 
1376c87b03e5Sespie   format_ctx.res = &res;
1377c87b03e5Sespie   format_ctx.info = info;
1378c87b03e5Sespie   format_ctx.params = params;
1379c87b03e5Sespie   format_ctx.status = status;
1380c87b03e5Sespie 
1381c87b03e5Sespie   check_function_arguments_recurse (check_format_arg, &format_ctx,
1382c87b03e5Sespie 				    format_tree, arg_num);
1383c87b03e5Sespie 
1384c87b03e5Sespie   if (res.number_non_literal > 0)
1385c87b03e5Sespie     {
1386c87b03e5Sespie       /* Functions taking a va_list normally pass a non-literal format
1387c87b03e5Sespie 	 string.  These functions typically are declared with
1388c87b03e5Sespie 	 first_arg_num == 0, so avoid warning in those cases.  */
1389c87b03e5Sespie       if (!(format_types[info->format_type].flags & (int) FMT_FLAG_ARG_CONVERT))
1390c87b03e5Sespie 	{
1391c87b03e5Sespie 	  /* For strftime-like formats, warn for not checking the format
1392c87b03e5Sespie 	     string; but there are no arguments to check.  */
1393c87b03e5Sespie 	  if (warn_format_nonliteral)
1394c87b03e5Sespie 	    status_warning (status, "format not a string literal, format string not checked");
1395c87b03e5Sespie 	}
1396c87b03e5Sespie       else if (info->first_arg_num != 0)
1397c87b03e5Sespie 	{
1398c87b03e5Sespie 	  /* If there are no arguments for the format at all, we may have
1399c87b03e5Sespie 	     printf (foo) which is likely to be a security hole.  */
1400c87b03e5Sespie 	  while (arg_num + 1 < info->first_arg_num)
1401c87b03e5Sespie 	    {
1402c87b03e5Sespie 	      if (params == 0)
1403c87b03e5Sespie 		break;
1404c87b03e5Sespie 	      params = TREE_CHAIN (params);
1405c87b03e5Sespie 	      ++arg_num;
1406c87b03e5Sespie 	    }
1407c87b03e5Sespie 	  if (params == 0 && (warn_format_nonliteral || warn_format_security))
1408c87b03e5Sespie 	    status_warning (status, "format not a string literal and no format arguments");
1409c87b03e5Sespie 	  else if (warn_format_nonliteral)
1410c87b03e5Sespie 	    status_warning (status, "format not a string literal, argument types not checked");
1411c87b03e5Sespie 	}
1412c87b03e5Sespie     }
1413c87b03e5Sespie 
1414c87b03e5Sespie   /* If there were extra arguments to the format, normally warn.  However,
1415c87b03e5Sespie      the standard does say extra arguments are ignored, so in the specific
1416c87b03e5Sespie      case where we have multiple leaves (conditional expressions or
1417c87b03e5Sespie      ngettext) allow extra arguments if at least one leaf didn't have extra
1418c87b03e5Sespie      arguments, but was otherwise OK (either non-literal or checked OK).
1419c87b03e5Sespie      If the format is an empty string, this should be counted similarly to the
1420c87b03e5Sespie      case of extra format arguments.  */
1421c87b03e5Sespie   if (res.number_extra_args > 0 && res.number_non_literal == 0
1422c87b03e5Sespie       && res.number_other == 0 && warn_format_extra_args)
1423c87b03e5Sespie     status_warning (status, "too many arguments for format");
1424c87b03e5Sespie   if (res.number_dollar_extra_args > 0 && res.number_non_literal == 0
1425c87b03e5Sespie       && res.number_other == 0 && warn_format_extra_args)
1426c87b03e5Sespie     status_warning (status, "unused arguments in $-style format");
1427c87b03e5Sespie   if (res.number_empty > 0 && res.number_non_literal == 0
1428c87b03e5Sespie       && res.number_other == 0 && warn_format_zero_length)
1429c87b03e5Sespie     status_warning (status, "zero-length %s format string",
1430c87b03e5Sespie 		    format_types[info->format_type].name);
1431c87b03e5Sespie 
1432c87b03e5Sespie   if (res.number_wide > 0)
1433c87b03e5Sespie     status_warning (status, "format is a wide character string");
1434c87b03e5Sespie 
1435c87b03e5Sespie   if (res.number_unterminated > 0)
1436c87b03e5Sespie     status_warning (status, "unterminated format string");
1437c87b03e5Sespie }
1438c87b03e5Sespie 
1439c87b03e5Sespie /* Callback from check_function_arguments_recurse to check a
1440c87b03e5Sespie    format string.  FORMAT_TREE is the format parameter.  ARG_NUM
1441c87b03e5Sespie    is the number of the format argument.  CTX points to a
1442c87b03e5Sespie    format_check_context.  */
1443c87b03e5Sespie 
1444c87b03e5Sespie static void
check_format_arg(ctx,format_tree,arg_num)1445c87b03e5Sespie check_format_arg (ctx, format_tree, arg_num)
1446c87b03e5Sespie      void *ctx;
1447c87b03e5Sespie      tree format_tree;
1448c87b03e5Sespie      unsigned HOST_WIDE_INT arg_num;
1449c87b03e5Sespie {
1450c87b03e5Sespie   format_check_context *format_ctx = ctx;
1451c87b03e5Sespie   format_check_results *res = format_ctx->res;
1452c87b03e5Sespie   function_format_info *info = format_ctx->info;
1453c87b03e5Sespie   tree params = format_ctx->params;
1454c87b03e5Sespie   int *status = format_ctx->status;
1455c87b03e5Sespie 
1456c87b03e5Sespie   int format_length;
1457c87b03e5Sespie   HOST_WIDE_INT offset;
1458c87b03e5Sespie   const char *format_chars;
1459c87b03e5Sespie   tree array_size = 0;
1460c87b03e5Sespie   tree array_init;
1461c87b03e5Sespie 
1462c87b03e5Sespie   if (integer_zerop (format_tree))
1463c87b03e5Sespie     {
1464c87b03e5Sespie       /* Skip to first argument to check, so we can see if this format
1465c87b03e5Sespie 	 has any arguments (it shouldn't).  */
1466c87b03e5Sespie       while (arg_num + 1 < info->first_arg_num)
1467c87b03e5Sespie 	{
1468c87b03e5Sespie 	  if (params == 0)
1469c87b03e5Sespie 	    return;
1470c87b03e5Sespie 	  params = TREE_CHAIN (params);
1471c87b03e5Sespie 	  ++arg_num;
1472c87b03e5Sespie 	}
1473c87b03e5Sespie 
1474c87b03e5Sespie       if (params == 0)
1475c87b03e5Sespie 	res->number_other++;
1476c87b03e5Sespie       else
1477c87b03e5Sespie 	res->number_extra_args++;
1478c87b03e5Sespie 
1479c87b03e5Sespie       return;
1480c87b03e5Sespie     }
1481c87b03e5Sespie 
1482c87b03e5Sespie   offset = 0;
1483c87b03e5Sespie   if (TREE_CODE (format_tree) == PLUS_EXPR)
1484c87b03e5Sespie     {
1485c87b03e5Sespie       tree arg0, arg1;
1486c87b03e5Sespie 
1487c87b03e5Sespie       arg0 = TREE_OPERAND (format_tree, 0);
1488c87b03e5Sespie       arg1 = TREE_OPERAND (format_tree, 1);
1489c87b03e5Sespie       STRIP_NOPS (arg0);
1490c87b03e5Sespie       STRIP_NOPS (arg1);
1491c87b03e5Sespie       if (TREE_CODE (arg1) == INTEGER_CST)
1492c87b03e5Sespie 	format_tree = arg0;
1493c87b03e5Sespie       else if (TREE_CODE (arg0) == INTEGER_CST)
1494c87b03e5Sespie 	{
1495c87b03e5Sespie 	  format_tree = arg1;
1496c87b03e5Sespie 	  arg1 = arg0;
1497c87b03e5Sespie 	}
1498c87b03e5Sespie       else
1499c87b03e5Sespie 	{
1500c87b03e5Sespie 	  res->number_non_literal++;
1501c87b03e5Sespie 	  return;
1502c87b03e5Sespie 	}
1503c87b03e5Sespie       if (!host_integerp (arg1, 0)
1504c87b03e5Sespie 	  || (offset = tree_low_cst (arg1, 0)) < 0)
1505c87b03e5Sespie 	{
1506c87b03e5Sespie 	  res->number_non_literal++;
1507c87b03e5Sespie 	  return;
1508c87b03e5Sespie 	}
1509c87b03e5Sespie     }
1510c87b03e5Sespie   if (TREE_CODE (format_tree) != ADDR_EXPR)
1511c87b03e5Sespie     {
1512c87b03e5Sespie       res->number_non_literal++;
1513c87b03e5Sespie       return;
1514c87b03e5Sespie     }
1515c87b03e5Sespie   format_tree = TREE_OPERAND (format_tree, 0);
1516c87b03e5Sespie   if (TREE_CODE (format_tree) == VAR_DECL
1517c87b03e5Sespie       && TREE_CODE (TREE_TYPE (format_tree)) == ARRAY_TYPE
1518c87b03e5Sespie       && (array_init = decl_constant_value (format_tree)) != format_tree
1519c87b03e5Sespie       && TREE_CODE (array_init) == STRING_CST)
1520c87b03e5Sespie     {
1521c87b03e5Sespie       /* Extract the string constant initializer.  Note that this may include
1522c87b03e5Sespie 	 a trailing NUL character that is not in the array (e.g.
1523c87b03e5Sespie 	 const char a[3] = "foo";).  */
1524c87b03e5Sespie       array_size = DECL_SIZE_UNIT (format_tree);
1525c87b03e5Sespie       format_tree = array_init;
1526c87b03e5Sespie     }
1527c87b03e5Sespie   if (TREE_CODE (format_tree) != STRING_CST)
1528c87b03e5Sespie     {
1529c87b03e5Sespie       res->number_non_literal++;
1530c87b03e5Sespie       return;
1531c87b03e5Sespie     }
1532c87b03e5Sespie   if (TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (format_tree))) != char_type_node)
1533c87b03e5Sespie     {
1534c87b03e5Sespie       res->number_wide++;
1535c87b03e5Sespie       return;
1536c87b03e5Sespie     }
1537c87b03e5Sespie   format_chars = TREE_STRING_POINTER (format_tree);
1538c87b03e5Sespie   format_length = TREE_STRING_LENGTH (format_tree);
1539c87b03e5Sespie   if (array_size != 0)
1540c87b03e5Sespie     {
1541c87b03e5Sespie       /* Variable length arrays can't be initialized.  */
1542c87b03e5Sespie       if (TREE_CODE (array_size) != INTEGER_CST)
1543c87b03e5Sespie 	abort ();
1544c87b03e5Sespie       if (host_integerp (array_size, 0))
1545c87b03e5Sespie 	{
1546c87b03e5Sespie 	  HOST_WIDE_INT array_size_value = TREE_INT_CST_LOW (array_size);
1547c87b03e5Sespie 	  if (array_size_value > 0
1548c87b03e5Sespie 	      && array_size_value == (int) array_size_value
1549c87b03e5Sespie 	      && format_length > array_size_value)
1550c87b03e5Sespie 	    format_length = array_size_value;
1551c87b03e5Sespie 	}
1552c87b03e5Sespie     }
1553c87b03e5Sespie   if (offset)
1554c87b03e5Sespie     {
1555c87b03e5Sespie       if (offset >= format_length)
1556c87b03e5Sespie 	{
1557c87b03e5Sespie 	  res->number_non_literal++;
1558c87b03e5Sespie 	  return;
1559c87b03e5Sespie 	}
1560c87b03e5Sespie       format_chars += offset;
1561c87b03e5Sespie       format_length -= offset;
1562c87b03e5Sespie     }
1563c87b03e5Sespie   if (format_length < 1)
1564c87b03e5Sespie     {
1565c87b03e5Sespie       res->number_unterminated++;
1566c87b03e5Sespie       return;
1567c87b03e5Sespie     }
1568c87b03e5Sespie   if (format_length == 1)
1569c87b03e5Sespie     {
1570c87b03e5Sespie       res->number_empty++;
1571c87b03e5Sespie       return;
1572c87b03e5Sespie     }
1573c87b03e5Sespie   if (format_chars[--format_length] != 0)
1574c87b03e5Sespie     {
1575c87b03e5Sespie       res->number_unterminated++;
1576c87b03e5Sespie       return;
1577c87b03e5Sespie     }
1578c87b03e5Sespie 
1579c87b03e5Sespie   /* Skip to first argument to check.  */
1580c87b03e5Sespie   while (arg_num + 1 < info->first_arg_num)
1581c87b03e5Sespie     {
1582c87b03e5Sespie       if (params == 0)
1583c87b03e5Sespie 	return;
1584c87b03e5Sespie       params = TREE_CHAIN (params);
1585c87b03e5Sespie       ++arg_num;
1586c87b03e5Sespie     }
1587c87b03e5Sespie   /* Provisionally increment res->number_other; check_format_info_main
1588c87b03e5Sespie      will decrement it if it finds there are extra arguments, but this way
1589c87b03e5Sespie      need not adjust it for every return.  */
1590c87b03e5Sespie   res->number_other++;
1591c87b03e5Sespie   check_format_info_main (status, res, info, format_chars, format_length,
1592c87b03e5Sespie 			  params, arg_num);
1593c87b03e5Sespie }
1594c87b03e5Sespie 
1595c87b03e5Sespie 
1596c87b03e5Sespie /* Do the main part of checking a call to a format function.  FORMAT_CHARS
1597c87b03e5Sespie    is the NUL-terminated format string (which at this point may contain
1598c87b03e5Sespie    internal NUL characters); FORMAT_LENGTH is its length (excluding the
1599c87b03e5Sespie    terminating NUL character).  ARG_NUM is one less than the number of
1600c87b03e5Sespie    the first format argument to check; PARAMS points to that format
1601c87b03e5Sespie    argument in the list of arguments.  */
1602c87b03e5Sespie 
1603c87b03e5Sespie static void
check_format_info_main(status,res,info,format_chars,format_length,params,arg_num)1604c87b03e5Sespie check_format_info_main (status, res, info, format_chars, format_length,
1605c87b03e5Sespie 			params, arg_num)
1606c87b03e5Sespie      int *status;
1607c87b03e5Sespie      format_check_results *res;
1608c87b03e5Sespie      function_format_info *info;
1609c87b03e5Sespie      const char *format_chars;
1610c87b03e5Sespie      int format_length;
1611c87b03e5Sespie      tree params;
1612c87b03e5Sespie      unsigned HOST_WIDE_INT arg_num;
1613c87b03e5Sespie {
1614c87b03e5Sespie   const char *orig_format_chars = format_chars;
1615c87b03e5Sespie   tree first_fillin_param = params;
1616c87b03e5Sespie 
1617c87b03e5Sespie   const format_kind_info *fki = &format_types[info->format_type];
1618c87b03e5Sespie   const format_flag_spec *flag_specs = fki->flag_specs;
1619c87b03e5Sespie   const format_flag_pair *bad_flag_pairs = fki->bad_flag_pairs;
1620c87b03e5Sespie 
1621c87b03e5Sespie   /* -1 if no conversions taking an operand have been found; 0 if one has
1622c87b03e5Sespie      and it didn't use $; 1 if $ formats are in use.  */
1623c87b03e5Sespie   int has_operand_number = -1;
1624c87b03e5Sespie 
1625c87b03e5Sespie   init_dollar_format_checking (info->first_arg_num, first_fillin_param);
1626c87b03e5Sespie 
1627c87b03e5Sespie   while (1)
1628c87b03e5Sespie     {
1629c87b03e5Sespie       int i;
1630c87b03e5Sespie       int suppressed = FALSE;
1631c87b03e5Sespie       const char *length_chars = NULL;
1632c87b03e5Sespie       enum format_lengths length_chars_val = FMT_LEN_none;
1633c87b03e5Sespie       enum format_std_version length_chars_std = STD_C89;
1634c87b03e5Sespie       int format_char;
1635c87b03e5Sespie       tree cur_param;
1636c87b03e5Sespie       tree wanted_type;
1637c87b03e5Sespie       int main_arg_num = 0;
1638c87b03e5Sespie       tree main_arg_params = 0;
1639c87b03e5Sespie       enum format_std_version wanted_type_std;
1640c87b03e5Sespie       const char *wanted_type_name;
1641c87b03e5Sespie       format_wanted_type width_wanted_type;
1642c87b03e5Sespie       format_wanted_type precision_wanted_type;
1643c87b03e5Sespie       format_wanted_type main_wanted_type;
1644c87b03e5Sespie       format_wanted_type *first_wanted_type = NULL;
1645c87b03e5Sespie       format_wanted_type *last_wanted_type = NULL;
1646c87b03e5Sespie       const format_length_info *fli = NULL;
1647c87b03e5Sespie       const format_char_info *fci = NULL;
1648c87b03e5Sespie       char flag_chars[256];
1649cd3be6e5Savsm       int field_width = 0;
1650c87b03e5Sespie       int aflag = 0;
16519d1607cfSmiod       const char *format_start = format_chars;
1652c87b03e5Sespie       if (*format_chars == 0)
1653c87b03e5Sespie 	{
1654c87b03e5Sespie 	  if (format_chars - orig_format_chars != format_length)
1655c87b03e5Sespie 	    status_warning (status, "embedded `\\0' in format");
1656c87b03e5Sespie 	  if (info->first_arg_num != 0 && params != 0
1657c87b03e5Sespie 	      && has_operand_number <= 0)
1658c87b03e5Sespie 	    {
1659c87b03e5Sespie 	      res->number_other--;
1660c87b03e5Sespie 	      res->number_extra_args++;
1661c87b03e5Sespie 	    }
1662c87b03e5Sespie 	  if (has_operand_number > 0)
1663c87b03e5Sespie 	    finish_dollar_format_checking (status, res, fki->flags & (int) FMT_FLAG_DOLLAR_GAP_POINTER_OK);
1664c87b03e5Sespie 	  return;
1665c87b03e5Sespie 	}
1666c87b03e5Sespie       if (*format_chars++ != '%')
1667c87b03e5Sespie 	continue;
1668c87b03e5Sespie       if (*format_chars == 0)
1669c87b03e5Sespie 	{
1670c87b03e5Sespie 	  status_warning (status, "spurious trailing `%%' in format");
1671c87b03e5Sespie 	  continue;
1672c87b03e5Sespie 	}
1673c87b03e5Sespie       if (*format_chars == '%')
1674c87b03e5Sespie 	{
1675c87b03e5Sespie 	  ++format_chars;
1676c87b03e5Sespie 	  continue;
1677c87b03e5Sespie 	}
1678c87b03e5Sespie       flag_chars[0] = 0;
1679c87b03e5Sespie 
1680c87b03e5Sespie       if ((fki->flags & (int) FMT_FLAG_USE_DOLLAR) && has_operand_number != 0)
1681c87b03e5Sespie 	{
1682c87b03e5Sespie 	  /* Possibly read a $ operand number at the start of the format.
1683c87b03e5Sespie 	     If one was previously used, one is required here.  If one
1684c87b03e5Sespie 	     is not used here, we can't immediately conclude this is a
1685c87b03e5Sespie 	     format without them, since it could be printf %m or scanf %*.  */
1686c87b03e5Sespie 	  int opnum;
1687c87b03e5Sespie 	  opnum = maybe_read_dollar_number (status, &format_chars, 0,
1688c87b03e5Sespie 					    first_fillin_param,
1689c87b03e5Sespie 					    &main_arg_params, fki);
1690c87b03e5Sespie 	  if (opnum == -1)
1691c87b03e5Sespie 	    return;
1692c87b03e5Sespie 	  else if (opnum > 0)
1693c87b03e5Sespie 	    {
1694c87b03e5Sespie 	      has_operand_number = 1;
1695c87b03e5Sespie 	      main_arg_num = opnum + info->first_arg_num - 1;
1696c87b03e5Sespie 	    }
1697c87b03e5Sespie 	}
1698c87b03e5Sespie 
1699c87b03e5Sespie       /* Read any format flags, but do not yet validate them beyond removing
1700c87b03e5Sespie 	 duplicates, since in general validation depends on the rest of
1701c87b03e5Sespie 	 the format.  */
1702c87b03e5Sespie       while (*format_chars != 0
1703c87b03e5Sespie 	     && strchr (fki->flag_chars, *format_chars) != 0)
1704c87b03e5Sespie 	{
1705c87b03e5Sespie 	  const format_flag_spec *s = get_flag_spec (flag_specs,
1706c87b03e5Sespie 						     *format_chars, NULL);
1707c87b03e5Sespie 	  if (strchr (flag_chars, *format_chars) != 0)
1708c87b03e5Sespie 	    {
1709c87b03e5Sespie 	      status_warning (status, "repeated %s in format", _(s->name));
1710c87b03e5Sespie 	    }
1711c87b03e5Sespie 	  else
1712c87b03e5Sespie 	    {
1713c87b03e5Sespie 	      i = strlen (flag_chars);
1714c87b03e5Sespie 	      flag_chars[i++] = *format_chars;
1715c87b03e5Sespie 	      flag_chars[i] = 0;
1716c87b03e5Sespie 	    }
1717c87b03e5Sespie 	  if (s->skip_next_char)
1718c87b03e5Sespie 	    {
1719c87b03e5Sespie 	      ++format_chars;
1720c87b03e5Sespie 	      if (*format_chars == 0)
1721c87b03e5Sespie 		{
1722c87b03e5Sespie 		  status_warning (status, "missing fill character at end of strfmon format");
1723c87b03e5Sespie 		  return;
1724c87b03e5Sespie 		}
1725c87b03e5Sespie 	    }
1726c87b03e5Sespie 	  ++format_chars;
1727c87b03e5Sespie 	}
1728c87b03e5Sespie 
1729c87b03e5Sespie       /* Read any format width, possibly * or *m$.  */
1730c87b03e5Sespie       if (fki->width_char != 0)
1731c87b03e5Sespie 	{
1732c87b03e5Sespie 	  if (fki->width_type != NULL && *format_chars == '*')
1733c87b03e5Sespie 	    {
1734c87b03e5Sespie 	      i = strlen (flag_chars);
1735c87b03e5Sespie 	      flag_chars[i++] = fki->width_char;
1736c87b03e5Sespie 	      flag_chars[i] = 0;
1737c87b03e5Sespie 	      /* "...a field width...may be indicated by an asterisk.
1738c87b03e5Sespie 		 In this case, an int argument supplies the field width..."  */
1739c87b03e5Sespie 	      ++format_chars;
1740c87b03e5Sespie 	      if (has_operand_number != 0)
1741c87b03e5Sespie 		{
1742c87b03e5Sespie 		  int opnum;
1743c87b03e5Sespie 		  opnum = maybe_read_dollar_number (status, &format_chars,
1744c87b03e5Sespie 						    has_operand_number == 1,
1745c87b03e5Sespie 						    first_fillin_param,
1746c87b03e5Sespie 						    &params, fki);
1747c87b03e5Sespie 		  if (opnum == -1)
1748c87b03e5Sespie 		    return;
1749c87b03e5Sespie 		  else if (opnum > 0)
1750c87b03e5Sespie 		    {
1751c87b03e5Sespie 		      has_operand_number = 1;
1752c87b03e5Sespie 		      arg_num = opnum + info->first_arg_num - 1;
1753c87b03e5Sespie 		    }
1754c87b03e5Sespie 		  else
1755c87b03e5Sespie 		    has_operand_number = 0;
1756c87b03e5Sespie 		}
1757c87b03e5Sespie 	      if (info->first_arg_num != 0)
1758c87b03e5Sespie 		{
1759c87b03e5Sespie 		  if (params == 0)
1760c87b03e5Sespie 		    {
1761c87b03e5Sespie 		      status_warning (status, "too few arguments for format");
1762c87b03e5Sespie 		      return;
1763c87b03e5Sespie 		    }
1764c87b03e5Sespie 		  cur_param = TREE_VALUE (params);
1765c87b03e5Sespie 		  if (has_operand_number <= 0)
1766c87b03e5Sespie 		    {
1767c87b03e5Sespie 		      params = TREE_CHAIN (params);
1768c87b03e5Sespie 		      ++arg_num;
1769c87b03e5Sespie 		    }
1770c87b03e5Sespie 		  width_wanted_type.wanted_type = *fki->width_type;
1771c87b03e5Sespie 		  width_wanted_type.wanted_type_name = NULL;
1772c87b03e5Sespie 		  width_wanted_type.pointer_count = 0;
1773c87b03e5Sespie 		  width_wanted_type.char_lenient_flag = 0;
1774c87b03e5Sespie 		  width_wanted_type.writing_in_flag = 0;
1775c87b03e5Sespie 		  width_wanted_type.reading_from_flag = 0;
1776c87b03e5Sespie 		  width_wanted_type.name = _("field width");
1777c87b03e5Sespie 		  width_wanted_type.param = cur_param;
1778c87b03e5Sespie 		  width_wanted_type.arg_num = arg_num;
1779c87b03e5Sespie 		  width_wanted_type.next = NULL;
1780c87b03e5Sespie 		  if (last_wanted_type != 0)
1781c87b03e5Sespie 		    last_wanted_type->next = &width_wanted_type;
1782c87b03e5Sespie 		  if (first_wanted_type == 0)
1783c87b03e5Sespie 		    first_wanted_type = &width_wanted_type;
1784c87b03e5Sespie 		  last_wanted_type = &width_wanted_type;
1785c87b03e5Sespie 		}
1786c87b03e5Sespie 	    }
1787c87b03e5Sespie 	  else
1788c87b03e5Sespie 	    {
1789c87b03e5Sespie 	      /* Possibly read a numeric width.  If the width is zero,
1790c87b03e5Sespie 		 we complain if appropriate.  */
1791c87b03e5Sespie 	      int non_zero_width_char = FALSE;
1792cd3be6e5Savsm 	      unsigned int found_width = 0;
1793cd3be6e5Savsm 	      char format_num_str[32];
1794cd3be6e5Savsm 
1795cd3be6e5Savsm 	      format_num_str[0] = '\0';
1796c87b03e5Sespie 	      while (ISDIGIT (*format_chars))
1797c87b03e5Sespie 		{
1798cd3be6e5Savsm 		  if (found_width < (sizeof(format_num_str)-2))
1799cd3be6e5Savsm 		    {
1800cd3be6e5Savsm 		      format_num_str[found_width++] = *format_chars;
1801cd3be6e5Savsm                       format_num_str[found_width] = '\0';
1802cd3be6e5Savsm 		    }
1803c87b03e5Sespie 		  if (*format_chars != '0')
1804c87b03e5Sespie 		    non_zero_width_char = TRUE;
1805c87b03e5Sespie 		  ++format_chars;
1806c87b03e5Sespie 		}
1807cd3be6e5Savsm 
1808cd3be6e5Savsm 	      if (found_width > 0 && !non_zero_width_char &&
1809c87b03e5Sespie 		  (fki->flags & (int) FMT_FLAG_ZERO_WIDTH_BAD))
1810c87b03e5Sespie 		status_warning (status, "zero width in %s format",
1811c87b03e5Sespie 				fki->name);
1812cd3be6e5Savsm 	      if (found_width > 0)
1813c87b03e5Sespie 		{
1814cd3be6e5Savsm 		  field_width  = atoi(format_num_str);
1815c87b03e5Sespie 		  i = strlen (flag_chars);
1816c87b03e5Sespie 		  flag_chars[i++] = fki->width_char;
1817c87b03e5Sespie 		  flag_chars[i] = 0;
1818c87b03e5Sespie 		}
1819c87b03e5Sespie 	    }
1820c87b03e5Sespie 	}
1821c87b03e5Sespie 
1822c87b03e5Sespie       /* Read any format left precision (must be a number, not *).  */
1823c87b03e5Sespie       if (fki->left_precision_char != 0 && *format_chars == '#')
1824c87b03e5Sespie 	{
1825c87b03e5Sespie 	  ++format_chars;
1826c87b03e5Sespie 	  i = strlen (flag_chars);
1827c87b03e5Sespie 	  flag_chars[i++] = fki->left_precision_char;
1828c87b03e5Sespie 	  flag_chars[i] = 0;
1829c87b03e5Sespie 	  if (!ISDIGIT (*format_chars))
1830c87b03e5Sespie 	    status_warning (status, "empty left precision in %s format",
1831c87b03e5Sespie 			    fki->name);
1832c87b03e5Sespie 	  while (ISDIGIT (*format_chars))
1833c87b03e5Sespie 	    ++format_chars;
1834c87b03e5Sespie 	}
1835c87b03e5Sespie 
1836c87b03e5Sespie       /* Read any format precision, possibly * or *m$.  */
1837c87b03e5Sespie       if (fki->precision_char != 0 && *format_chars == '.')
1838c87b03e5Sespie 	{
1839c87b03e5Sespie 	  ++format_chars;
1840c87b03e5Sespie 	  i = strlen (flag_chars);
1841c87b03e5Sespie 	  flag_chars[i++] = fki->precision_char;
1842c87b03e5Sespie 	  flag_chars[i] = 0;
1843c87b03e5Sespie 	  if (fki->precision_type != NULL && *format_chars == '*')
1844c87b03e5Sespie 	    {
1845c87b03e5Sespie 	      /* "...a...precision...may be indicated by an asterisk.
1846c87b03e5Sespie 		 In this case, an int argument supplies the...precision."  */
1847c87b03e5Sespie 	      ++format_chars;
1848c87b03e5Sespie 	      if (has_operand_number != 0)
1849c87b03e5Sespie 		{
1850c87b03e5Sespie 		  int opnum;
1851c87b03e5Sespie 		  opnum = maybe_read_dollar_number (status, &format_chars,
1852c87b03e5Sespie 						    has_operand_number == 1,
1853c87b03e5Sespie 						    first_fillin_param,
1854c87b03e5Sespie 						    &params, fki);
1855c87b03e5Sespie 		  if (opnum == -1)
1856c87b03e5Sespie 		    return;
1857c87b03e5Sespie 		  else if (opnum > 0)
1858c87b03e5Sespie 		    {
1859c87b03e5Sespie 		      has_operand_number = 1;
1860c87b03e5Sespie 		      arg_num = opnum + info->first_arg_num - 1;
1861c87b03e5Sespie 		    }
1862c87b03e5Sespie 		  else
1863c87b03e5Sespie 		    has_operand_number = 0;
1864c87b03e5Sespie 		}
1865c87b03e5Sespie 	      if (info->first_arg_num != 0)
1866c87b03e5Sespie 		{
1867c87b03e5Sespie 		  if (params == 0)
1868c87b03e5Sespie 		    {
1869c87b03e5Sespie 		      status_warning (status, "too few arguments for format");
1870c87b03e5Sespie 		      return;
1871c87b03e5Sespie 		    }
1872c87b03e5Sespie 		  cur_param = TREE_VALUE (params);
1873c87b03e5Sespie 		  if (has_operand_number <= 0)
1874c87b03e5Sespie 		    {
1875c87b03e5Sespie 		      params = TREE_CHAIN (params);
1876c87b03e5Sespie 		      ++arg_num;
1877c87b03e5Sespie 		    }
1878c87b03e5Sespie 		  precision_wanted_type.wanted_type = *fki->precision_type;
1879c87b03e5Sespie 		  precision_wanted_type.wanted_type_name = NULL;
1880c87b03e5Sespie 		  precision_wanted_type.pointer_count = 0;
1881c87b03e5Sespie 		  precision_wanted_type.char_lenient_flag = 0;
1882c87b03e5Sespie 		  precision_wanted_type.writing_in_flag = 0;
1883c87b03e5Sespie 		  precision_wanted_type.reading_from_flag = 0;
1884c87b03e5Sespie 		  precision_wanted_type.name = _("field precision");
1885c87b03e5Sespie 		  precision_wanted_type.param = cur_param;
1886c87b03e5Sespie 		  precision_wanted_type.arg_num = arg_num;
1887c87b03e5Sespie 		  precision_wanted_type.next = NULL;
1888c87b03e5Sespie 		  if (last_wanted_type != 0)
1889c87b03e5Sespie 		    last_wanted_type->next = &precision_wanted_type;
1890c87b03e5Sespie 		  if (first_wanted_type == 0)
1891c87b03e5Sespie 		    first_wanted_type = &precision_wanted_type;
1892c87b03e5Sespie 		  last_wanted_type = &precision_wanted_type;
1893c87b03e5Sespie 		}
1894c87b03e5Sespie 	    }
1895c87b03e5Sespie 	  else
1896c87b03e5Sespie 	    {
1897c87b03e5Sespie 	      if (!(fki->flags & (int) FMT_FLAG_EMPTY_PREC_OK)
1898c87b03e5Sespie 		  && !ISDIGIT (*format_chars))
1899c87b03e5Sespie 		status_warning (status, "empty precision in %s format",
1900c87b03e5Sespie 				fki->name);
1901c87b03e5Sespie 	      while (ISDIGIT (*format_chars))
1902c87b03e5Sespie 		++format_chars;
1903c87b03e5Sespie 	    }
1904c87b03e5Sespie 	}
1905c87b03e5Sespie 
1906c87b03e5Sespie       /* Read any length modifier, if this kind of format has them.  */
1907c87b03e5Sespie       fli = fki->length_char_specs;
1908c87b03e5Sespie       length_chars = NULL;
1909c87b03e5Sespie       length_chars_val = FMT_LEN_none;
1910c87b03e5Sespie       length_chars_std = STD_C89;
1911c87b03e5Sespie       if (fli)
1912c87b03e5Sespie 	{
1913c87b03e5Sespie 	  while (fli->name != 0 && fli->name[0] != *format_chars)
1914c87b03e5Sespie 	    fli++;
1915c87b03e5Sespie 	  if (fli->name != 0)
1916c87b03e5Sespie 	    {
1917c87b03e5Sespie 	      format_chars++;
1918c87b03e5Sespie 	      if (fli->double_name != 0 && fli->name[0] == *format_chars)
1919c87b03e5Sespie 		{
1920c87b03e5Sespie 		  format_chars++;
1921c87b03e5Sespie 		  length_chars = fli->double_name;
1922c87b03e5Sespie 		  length_chars_val = fli->double_index;
1923c87b03e5Sespie 		  length_chars_std = fli->double_std;
1924c87b03e5Sespie 		}
1925c87b03e5Sespie 	      else
1926c87b03e5Sespie 		{
1927c87b03e5Sespie 		  length_chars = fli->name;
1928c87b03e5Sespie 		  length_chars_val = fli->index;
1929c87b03e5Sespie 		  length_chars_std = fli->std;
1930c87b03e5Sespie 		}
1931c87b03e5Sespie 	      i = strlen (flag_chars);
1932c87b03e5Sespie 	      flag_chars[i++] = fki->length_code_char;
1933c87b03e5Sespie 	      flag_chars[i] = 0;
1934c87b03e5Sespie 	    }
1935c87b03e5Sespie 	  if (pedantic)
1936c87b03e5Sespie 	    {
1937c87b03e5Sespie 	      /* Warn if the length modifier is non-standard.  */
1938c87b03e5Sespie 	      if (ADJ_STD (length_chars_std) > C_STD_VER)
1939c87b03e5Sespie 		status_warning (status, "%s does not support the `%s' %s length modifier",
1940c87b03e5Sespie 				C_STD_NAME (length_chars_std), length_chars,
1941c87b03e5Sespie 				fki->name);
1942c87b03e5Sespie 	    }
1943c87b03e5Sespie 	}
1944c87b03e5Sespie 
1945c87b03e5Sespie       /* Read any modifier (strftime E/O).  */
1946c87b03e5Sespie       if (fki->modifier_chars != NULL)
1947c87b03e5Sespie 	{
1948c87b03e5Sespie 	  while (*format_chars != 0
1949c87b03e5Sespie 		 && strchr (fki->modifier_chars, *format_chars) != 0)
1950c87b03e5Sespie 	    {
1951c87b03e5Sespie 	      if (strchr (flag_chars, *format_chars) != 0)
1952c87b03e5Sespie 		{
1953c87b03e5Sespie 		  const format_flag_spec *s = get_flag_spec (flag_specs,
1954c87b03e5Sespie 							     *format_chars, NULL);
1955c87b03e5Sespie 		  status_warning (status, "repeated %s in format", _(s->name));
1956c87b03e5Sespie 		}
1957c87b03e5Sespie 	      else
1958c87b03e5Sespie 		{
1959c87b03e5Sespie 		  i = strlen (flag_chars);
1960c87b03e5Sespie 		  flag_chars[i++] = *format_chars;
1961c87b03e5Sespie 		  flag_chars[i] = 0;
1962c87b03e5Sespie 		}
1963c87b03e5Sespie 	      ++format_chars;
1964c87b03e5Sespie 	    }
1965c87b03e5Sespie 	}
1966c87b03e5Sespie 
1967c87b03e5Sespie       /* Handle the scanf allocation kludge.  */
1968c87b03e5Sespie       if (fki->flags & (int) FMT_FLAG_SCANF_A_KLUDGE)
1969c87b03e5Sespie 	{
1970c87b03e5Sespie 	  if (*format_chars == 'a' && !flag_isoc99)
1971c87b03e5Sespie 	    {
1972c87b03e5Sespie 	      if (format_chars[1] == 's' || format_chars[1] == 'S'
1973c87b03e5Sespie 		  || format_chars[1] == '[')
1974c87b03e5Sespie 		{
1975c87b03e5Sespie 		  /* `a' is used as a flag.  */
1976c87b03e5Sespie 		  i = strlen (flag_chars);
1977c87b03e5Sespie 		  flag_chars[i++] = 'a';
1978c87b03e5Sespie 		  flag_chars[i] = 0;
1979c87b03e5Sespie 		  format_chars++;
1980c87b03e5Sespie 		}
1981c87b03e5Sespie 	    }
1982c87b03e5Sespie 	}
1983c87b03e5Sespie 
1984c87b03e5Sespie       format_char = *format_chars;
1985c87b03e5Sespie       if (format_char == 0
1986c87b03e5Sespie 	  || (!(fki->flags & (int) FMT_FLAG_FANCY_PERCENT_OK)
1987c87b03e5Sespie 	      && format_char == '%'))
1988c87b03e5Sespie 	{
1989c87b03e5Sespie 	  status_warning (status, "conversion lacks type at end of format");
1990c87b03e5Sespie 	  continue;
1991c87b03e5Sespie 	}
1992c87b03e5Sespie       format_chars++;
1993c87b03e5Sespie       fci = fki->conversion_specs;
1994c87b03e5Sespie       while (fci->format_chars != 0
1995c87b03e5Sespie 	     && strchr (fci->format_chars, format_char) == 0)
1996c87b03e5Sespie 	  ++fci;
1997c87b03e5Sespie       if (fci->format_chars == 0)
1998c87b03e5Sespie 	{
1999c87b03e5Sespie           if (ISGRAPH(format_char))
2000c87b03e5Sespie 	    status_warning (status, "unknown conversion type character `%c' in format",
2001c87b03e5Sespie 		     format_char);
2002c87b03e5Sespie 	  else
2003c87b03e5Sespie 	    status_warning (status, "unknown conversion type character 0x%x in format",
2004c87b03e5Sespie 		     format_char);
2005c87b03e5Sespie 	  continue;
2006c87b03e5Sespie 	}
2007c87b03e5Sespie       if (pedantic)
2008c87b03e5Sespie 	{
2009c87b03e5Sespie 	  if (ADJ_STD (fci->std) > C_STD_VER)
2010c87b03e5Sespie 	    status_warning (status, "%s does not support the `%%%c' %s format",
2011c87b03e5Sespie 			    C_STD_NAME (fci->std), format_char, fki->name);
2012c87b03e5Sespie 	}
2013c87b03e5Sespie 
2014c87b03e5Sespie       /* Validate the individual flags used, removing any that are invalid.  */
2015c87b03e5Sespie       {
2016c87b03e5Sespie 	int d = 0;
2017c87b03e5Sespie 	for (i = 0; flag_chars[i] != 0; i++)
2018c87b03e5Sespie 	  {
2019c87b03e5Sespie 	    const format_flag_spec *s = get_flag_spec (flag_specs,
2020c87b03e5Sespie 						       flag_chars[i], NULL);
2021c87b03e5Sespie 	    flag_chars[i - d] = flag_chars[i];
2022c87b03e5Sespie 	    if (flag_chars[i] == fki->length_code_char)
2023c87b03e5Sespie 	      continue;
2024c87b03e5Sespie 	    if (strchr (fci->flag_chars, flag_chars[i]) == 0)
2025c87b03e5Sespie 	      {
2026c87b03e5Sespie 		status_warning (status, "%s used with `%%%c' %s format",
2027c87b03e5Sespie 				_(s->name), format_char, fki->name);
2028c87b03e5Sespie 		d++;
2029c87b03e5Sespie 		continue;
2030c87b03e5Sespie 	      }
2031c87b03e5Sespie 	    if (pedantic)
2032c87b03e5Sespie 	      {
2033c87b03e5Sespie 		const format_flag_spec *t;
2034c87b03e5Sespie 		if (ADJ_STD (s->std) > C_STD_VER)
2035c87b03e5Sespie 		  status_warning (status, "%s does not support %s",
2036c87b03e5Sespie 				  C_STD_NAME (s->std), _(s->long_name));
2037c87b03e5Sespie 		t = get_flag_spec (flag_specs, flag_chars[i], fci->flags2);
2038c87b03e5Sespie 		if (t != NULL && ADJ_STD (t->std) > ADJ_STD (s->std))
2039c87b03e5Sespie 		  {
2040c87b03e5Sespie 		    const char *long_name = (t->long_name != NULL
2041c87b03e5Sespie 					     ? t->long_name
2042c87b03e5Sespie 					     : s->long_name);
2043c87b03e5Sespie 		    if (ADJ_STD (t->std) > C_STD_VER)
2044c87b03e5Sespie 		      status_warning (status, "%s does not support %s with the `%%%c' %s format",
2045c87b03e5Sespie 				      C_STD_NAME (t->std), _(long_name),
2046c87b03e5Sespie 				      format_char, fki->name);
2047c87b03e5Sespie 		  }
2048c87b03e5Sespie 	      }
2049c87b03e5Sespie 	  }
2050c87b03e5Sespie 	flag_chars[i - d] = 0;
2051c87b03e5Sespie       }
2052c87b03e5Sespie 
2053c87b03e5Sespie       if ((fki->flags & (int) FMT_FLAG_SCANF_A_KLUDGE)
2054c87b03e5Sespie 	  && strchr (flag_chars, 'a') != 0)
2055c87b03e5Sespie 	aflag = 1;
2056c87b03e5Sespie 
2057c87b03e5Sespie       if (fki->suppression_char
2058c87b03e5Sespie 	  && strchr (flag_chars, fki->suppression_char) != 0)
2059c87b03e5Sespie 	suppressed = 1;
2060c87b03e5Sespie 
2061c87b03e5Sespie       /* Validate the pairs of flags used.  */
2062c87b03e5Sespie       for (i = 0; bad_flag_pairs[i].flag_char1 != 0; i++)
2063c87b03e5Sespie 	{
2064c87b03e5Sespie 	  const format_flag_spec *s, *t;
2065c87b03e5Sespie 	  if (strchr (flag_chars, bad_flag_pairs[i].flag_char1) == 0)
2066c87b03e5Sespie 	    continue;
2067c87b03e5Sespie 	  if (strchr (flag_chars, bad_flag_pairs[i].flag_char2) == 0)
2068c87b03e5Sespie 	    continue;
2069c87b03e5Sespie 	  if (bad_flag_pairs[i].predicate != 0
2070c87b03e5Sespie 	      && strchr (fci->flags2, bad_flag_pairs[i].predicate) == 0)
2071c87b03e5Sespie 	    continue;
2072c87b03e5Sespie 	  s = get_flag_spec (flag_specs, bad_flag_pairs[i].flag_char1, NULL);
2073c87b03e5Sespie 	  t = get_flag_spec (flag_specs, bad_flag_pairs[i].flag_char2, NULL);
2074c87b03e5Sespie 	  if (bad_flag_pairs[i].ignored)
2075c87b03e5Sespie 	    {
2076c87b03e5Sespie 	      if (bad_flag_pairs[i].predicate != 0)
2077c87b03e5Sespie 		status_warning (status, "%s ignored with %s and `%%%c' %s format",
2078c87b03e5Sespie 				_(s->name), _(t->name), format_char,
2079c87b03e5Sespie 				fki->name);
2080c87b03e5Sespie 	      else
2081c87b03e5Sespie 		status_warning (status, "%s ignored with %s in %s format",
2082c87b03e5Sespie 				_(s->name), _(t->name), fki->name);
2083c87b03e5Sespie 	    }
2084c87b03e5Sespie 	  else
2085c87b03e5Sespie 	    {
2086c87b03e5Sespie 	      if (bad_flag_pairs[i].predicate != 0)
2087c87b03e5Sespie 		status_warning (status, "use of %s and %s together with `%%%c' %s format",
2088c87b03e5Sespie 				_(s->name), _(t->name), format_char,
2089c87b03e5Sespie 				fki->name);
2090c87b03e5Sespie 	      else
2091c87b03e5Sespie 		status_warning (status, "use of %s and %s together in %s format",
2092c87b03e5Sespie 				_(s->name), _(t->name), fki->name);
2093c87b03e5Sespie 	    }
2094c87b03e5Sespie 	}
2095c87b03e5Sespie 
2096c87b03e5Sespie       /* Give Y2K warnings.  */
2097c87b03e5Sespie       if (warn_format_y2k)
2098c87b03e5Sespie 	{
2099c87b03e5Sespie 	  int y2k_level = 0;
2100c87b03e5Sespie 	  if (strchr (fci->flags2, '4') != 0)
2101c87b03e5Sespie 	    if (strchr (flag_chars, 'E') != 0)
2102c87b03e5Sespie 	      y2k_level = 3;
2103c87b03e5Sespie 	    else
2104c87b03e5Sespie 	      y2k_level = 2;
2105c87b03e5Sespie 	  else if (strchr (fci->flags2, '3') != 0)
2106c87b03e5Sespie 	    y2k_level = 3;
2107c87b03e5Sespie 	  else if (strchr (fci->flags2, '2') != 0)
2108c87b03e5Sespie 	    y2k_level = 2;
2109c87b03e5Sespie 	  if (y2k_level == 3)
2110c87b03e5Sespie 	    status_warning (status, "`%%%c' yields only last 2 digits of year in some locales",
2111c87b03e5Sespie 			    format_char);
2112c87b03e5Sespie 	  else if (y2k_level == 2)
2113c87b03e5Sespie 	    status_warning (status, "`%%%c' yields only last 2 digits of year", format_char);
2114c87b03e5Sespie 	}
2115c87b03e5Sespie 
2116c87b03e5Sespie       if (strchr (fci->flags2, '[') != 0)
2117c87b03e5Sespie 	{
2118c87b03e5Sespie 	  /* Skip over scan set, in case it happens to have '%' in it.  */
2119c87b03e5Sespie 	  if (*format_chars == '^')
2120c87b03e5Sespie 	    ++format_chars;
2121c87b03e5Sespie 	  /* Find closing bracket; if one is hit immediately, then
2122c87b03e5Sespie 	     it's part of the scan set rather than a terminator.  */
2123c87b03e5Sespie 	  if (*format_chars == ']')
2124c87b03e5Sespie 	    ++format_chars;
2125c87b03e5Sespie 	  while (*format_chars && *format_chars != ']')
2126c87b03e5Sespie 	    ++format_chars;
2127c87b03e5Sespie 	  if (*format_chars != ']')
2128c87b03e5Sespie 	    /* The end of the format string was reached.  */
2129c87b03e5Sespie 	    status_warning (status, "no closing `]' for `%%[' format");
2130c87b03e5Sespie 	}
2131c87b03e5Sespie 
2132c87b03e5Sespie       wanted_type = 0;
2133c87b03e5Sespie       wanted_type_name = 0;
2134c87b03e5Sespie       if (fki->flags & (int) FMT_FLAG_ARG_CONVERT)
2135c87b03e5Sespie 	{
2136c87b03e5Sespie 	  wanted_type = (fci->types[length_chars_val].type
2137c87b03e5Sespie 			 ? *fci->types[length_chars_val].type : 0);
2138c87b03e5Sespie 	  wanted_type_name = fci->types[length_chars_val].name;
2139c87b03e5Sespie 	  wanted_type_std = fci->types[length_chars_val].std;
2140c87b03e5Sespie 	  if (wanted_type == 0)
2141c87b03e5Sespie 	    {
2142c87b03e5Sespie 	      status_warning (status, "use of `%s' length modifier with `%c' type character",
2143c87b03e5Sespie 			      length_chars, format_char);
2144c87b03e5Sespie 	      /* Heuristic: skip one argument when an invalid length/type
2145c87b03e5Sespie 		 combination is encountered.  */
2146c87b03e5Sespie 	      arg_num++;
2147c87b03e5Sespie 	      if (params == 0)
2148c87b03e5Sespie 		{
2149c87b03e5Sespie 		  status_warning (status, "too few arguments for format");
2150c87b03e5Sespie 		  return;
2151c87b03e5Sespie 		}
2152c87b03e5Sespie 	      params = TREE_CHAIN (params);
2153c87b03e5Sespie 	      continue;
2154c87b03e5Sespie 	    }
2155c87b03e5Sespie 	  else if (pedantic
2156c87b03e5Sespie 		   /* Warn if non-standard, provided it is more non-standard
2157c87b03e5Sespie 		      than the length and type characters that may already
2158c87b03e5Sespie 		      have been warned for.  */
2159c87b03e5Sespie 		   && ADJ_STD (wanted_type_std) > ADJ_STD (length_chars_std)
2160c87b03e5Sespie 		   && ADJ_STD (wanted_type_std) > ADJ_STD (fci->std))
2161c87b03e5Sespie 	    {
2162c87b03e5Sespie 	      if (ADJ_STD (wanted_type_std) > C_STD_VER)
2163c87b03e5Sespie 		status_warning (status, "%s does not support the `%%%s%c' %s format",
2164c87b03e5Sespie 				C_STD_NAME (wanted_type_std), length_chars,
2165c87b03e5Sespie 				format_char, fki->name);
2166c87b03e5Sespie 	    }
2167c87b03e5Sespie 	}
2168c87b03e5Sespie 
2169c87b03e5Sespie       /* Finally. . .check type of argument against desired type!  */
2170c87b03e5Sespie       if (info->first_arg_num == 0)
2171c87b03e5Sespie 	continue;
2172c87b03e5Sespie       if ((fci->pointer_count == 0 && wanted_type == void_type_node)
2173c87b03e5Sespie 	  || suppressed)
2174c87b03e5Sespie 	{
2175c87b03e5Sespie 	  if (main_arg_num != 0)
2176c87b03e5Sespie 	    {
2177c87b03e5Sespie 	      if (suppressed)
2178c87b03e5Sespie 		status_warning (status, "operand number specified with suppressed assignment");
2179c87b03e5Sespie 	      else
2180c87b03e5Sespie 		status_warning (status, "operand number specified for format taking no argument");
2181c87b03e5Sespie 	    }
2182c87b03e5Sespie 	}
2183c87b03e5Sespie       else
2184c87b03e5Sespie 	{
21859d1607cfSmiod 	  format_wanted_type *wanted_type_ptr;
21869d1607cfSmiod 
2187c87b03e5Sespie 	  if (main_arg_num != 0)
2188c87b03e5Sespie 	    {
2189c87b03e5Sespie 	      arg_num = main_arg_num;
2190c87b03e5Sespie 	      params = main_arg_params;
2191c87b03e5Sespie 	    }
2192c87b03e5Sespie 	  else
2193c87b03e5Sespie 	    {
2194c87b03e5Sespie 	      ++arg_num;
2195c87b03e5Sespie 	      if (has_operand_number > 0)
2196c87b03e5Sespie 		{
2197c87b03e5Sespie 		  status_warning (status, "missing $ operand number in format");
2198c87b03e5Sespie 		  return;
2199c87b03e5Sespie 		}
2200c87b03e5Sespie 	      else
2201c87b03e5Sespie 		has_operand_number = 0;
22029d1607cfSmiod 	    }
22039d1607cfSmiod 
22049d1607cfSmiod 	  wanted_type_ptr = &main_wanted_type;
22059d1607cfSmiod 	  while (fci)
22069d1607cfSmiod 	    {
2207c87b03e5Sespie 	      if (params == 0)
2208c87b03e5Sespie 		{
2209c87b03e5Sespie 		  status_warning (status, "too few arguments for format");
2210c87b03e5Sespie 		  return;
2211c87b03e5Sespie 		}
22129d1607cfSmiod 
2213c87b03e5Sespie 	      cur_param = TREE_VALUE (params);
2214c87b03e5Sespie 	      params = TREE_CHAIN (params);
22159d1607cfSmiod 
22169d1607cfSmiod 	      wanted_type_ptr->wanted_type = wanted_type;
22179d1607cfSmiod 	      wanted_type_ptr->wanted_type_name = wanted_type_name;
22189d1607cfSmiod 	      wanted_type_ptr->pointer_count = fci->pointer_count + aflag;
22199d1607cfSmiod 	      wanted_type_ptr->char_lenient_flag = 0;
22209d1607cfSmiod 	      wanted_type_ptr->field_width = field_width;
2221c87b03e5Sespie 	      if (strchr (fci->flags2, 'c') != 0)
22229d1607cfSmiod 		wanted_type_ptr->char_lenient_flag = 1;
22239d1607cfSmiod 	      wanted_type_ptr->writing_in_flag = 0;
22249d1607cfSmiod 	      wanted_type_ptr->reading_from_flag = 0;
2225cd3be6e5Savsm 	      if (strchr (fci->format_chars, 'c') != 0)
22269d1607cfSmiod 		wanted_type_ptr->size_equals_width = 1;
2227cd3be6e5Savsm 	      else
22289d1607cfSmiod 		wanted_type_ptr->size_equals_width = 0;
2229c87b03e5Sespie 	      if (aflag)
22309d1607cfSmiod 		wanted_type_ptr->writing_in_flag = 1;
2231c87b03e5Sespie 	      else
2232c87b03e5Sespie 		{
2233c87b03e5Sespie 		  if (strchr (fci->flags2, 'W') != 0)
22349d1607cfSmiod 		    wanted_type_ptr->writing_in_flag = 1;
2235c87b03e5Sespie 		  if (strchr (fci->flags2, 'R') != 0)
22369d1607cfSmiod 		    wanted_type_ptr->reading_from_flag = 1;
2237c87b03e5Sespie 		}
22389d1607cfSmiod 	      wanted_type_ptr->name = NULL;
22399d1607cfSmiod 	      wanted_type_ptr->param = cur_param;
22409d1607cfSmiod 	      wanted_type_ptr->arg_num = arg_num;
22419d1607cfSmiod 	      wanted_type_ptr->next = NULL;
2242c87b03e5Sespie 	      if (last_wanted_type != 0)
22439d1607cfSmiod 		last_wanted_type->next = wanted_type_ptr;
2244c87b03e5Sespie 	      if (first_wanted_type == 0)
22459d1607cfSmiod 		first_wanted_type = wanted_type_ptr;
22469d1607cfSmiod 	      last_wanted_type = wanted_type_ptr;
22479d1607cfSmiod 
22489d1607cfSmiod 	      fci = fci->chain;
22499d1607cfSmiod 	      if (fci)
22509d1607cfSmiod 		{
22519d1607cfSmiod 		  wanted_type_ptr = ggc_alloc (sizeof (format_wanted_type));
22529d1607cfSmiod 		  arg_num++;
22539d1607cfSmiod 		  wanted_type = *fci->types[length_chars_val].type;
22549d1607cfSmiod 		  wanted_type_name = fci->types[length_chars_val].name;
22559d1607cfSmiod 		}
22569d1607cfSmiod 	    }
2257c87b03e5Sespie 	}
2258c87b03e5Sespie 
2259f15b70e2Savsm       if (first_wanted_type != 0) {
22609d1607cfSmiod         bool apply_bounded = format_chars > format_start
22619d1607cfSmiod 	  && (format_chars[-1] == 's' || format_chars[-1] == 'c');
2262f15b70e2Savsm 	check_format_types (status, first_wanted_type, apply_bounded);
2263f15b70e2Savsm       }
2264c87b03e5Sespie 
22659d1607cfSmiod #if 0 /* no ggc_free() in gcc3 */
22669d1607cfSmiod       if (main_wanted_type.next != NULL)
22679d1607cfSmiod 	{
22689d1607cfSmiod 	  format_wanted_type *wanted_type_ptr = main_wanted_type.next;
22699d1607cfSmiod 	  while (wanted_type_ptr)
22709d1607cfSmiod 	    {
22719d1607cfSmiod 	      format_wanted_type *next = wanted_type_ptr->next;
22729d1607cfSmiod 	      ggc_free (wanted_type_ptr);
22739d1607cfSmiod 	      wanted_type_ptr = next;
22749d1607cfSmiod 	    }
22759d1607cfSmiod 	}
22769d1607cfSmiod #endif
2277c87b03e5Sespie     }
2278c87b03e5Sespie }
2279c87b03e5Sespie 
2280c87b03e5Sespie 
2281c87b03e5Sespie /* Check the argument types from a single format conversion (possibly
2282c87b03e5Sespie    including width and precision arguments).  */
2283c87b03e5Sespie static void
check_format_types(status,types,apply_bounded)2284f15b70e2Savsm check_format_types (status, types, apply_bounded)
2285c87b03e5Sespie      int *status;
2286c87b03e5Sespie      format_wanted_type *types;
2287f15b70e2Savsm      bool apply_bounded;
2288c87b03e5Sespie {
2289c87b03e5Sespie   for (; types != 0; types = types->next)
2290c87b03e5Sespie     {
2291c87b03e5Sespie       tree cur_param;
2292c87b03e5Sespie       tree cur_type;
2293c87b03e5Sespie       tree orig_cur_type;
2294c87b03e5Sespie       tree wanted_type;
2295c87b03e5Sespie       int arg_num;
2296c87b03e5Sespie       int i;
2297c87b03e5Sespie       int char_type_flag;
2298c87b03e5Sespie       cur_param = types->param;
2299c87b03e5Sespie       cur_type = TREE_TYPE (cur_param);
2300c87b03e5Sespie       if (cur_type == error_mark_node)
2301c87b03e5Sespie 	continue;
2302c87b03e5Sespie       char_type_flag = 0;
2303c87b03e5Sespie       wanted_type = types->wanted_type;
2304c87b03e5Sespie       arg_num = types->arg_num;
2305c87b03e5Sespie 
2306c87b03e5Sespie       /* The following should not occur here.  */
2307c87b03e5Sespie       if (wanted_type == 0)
2308c87b03e5Sespie 	abort ();
2309c87b03e5Sespie       if (wanted_type == void_type_node && types->pointer_count == 0)
2310c87b03e5Sespie 	abort ();
2311c87b03e5Sespie 
2312c87b03e5Sespie       if (types->pointer_count == 0)
2313c87b03e5Sespie 	wanted_type = (*lang_hooks.types.type_promotes_to) (wanted_type);
2314c87b03e5Sespie 
2315c87b03e5Sespie       STRIP_NOPS (cur_param);
2316c87b03e5Sespie 
2317c87b03e5Sespie       /* Check the types of any additional pointer arguments
2318c87b03e5Sespie 	 that precede the "real" argument.  */
2319c87b03e5Sespie       for (i = 0; i < types->pointer_count; ++i)
2320c87b03e5Sespie 	{
2321c87b03e5Sespie 	  if (TREE_CODE (cur_type) == POINTER_TYPE)
2322c87b03e5Sespie 	    {
2323c87b03e5Sespie 	      cur_type = TREE_TYPE (cur_type);
2324c87b03e5Sespie 	      if (cur_type == error_mark_node)
2325c87b03e5Sespie 		break;
2326c87b03e5Sespie 
2327c87b03e5Sespie 	      /* Check for writing through a NULL pointer.  */
2328c87b03e5Sespie 	      if (types->writing_in_flag
2329c87b03e5Sespie 		  && i == 0
2330c87b03e5Sespie 		  && cur_param != 0
2331c87b03e5Sespie 		  && integer_zerop (cur_param))
2332c87b03e5Sespie 		status_warning (status,
2333c87b03e5Sespie 				"writing through null pointer (arg %d)",
2334c87b03e5Sespie 				arg_num);
2335c87b03e5Sespie 
2336c87b03e5Sespie 	      /* Check for reading through a NULL pointer.  */
2337c87b03e5Sespie 	      if (types->reading_from_flag
2338c87b03e5Sespie 		  && i == 0
2339c87b03e5Sespie 		  && cur_param != 0
2340c87b03e5Sespie 		  && integer_zerop (cur_param))
2341c87b03e5Sespie 		status_warning (status,
2342c87b03e5Sespie 				"reading through null pointer (arg %d)",
2343c87b03e5Sespie 				arg_num);
2344c87b03e5Sespie 
2345c87b03e5Sespie 	      if (cur_param != 0 && TREE_CODE (cur_param) == ADDR_EXPR)
2346c87b03e5Sespie 		cur_param = TREE_OPERAND (cur_param, 0);
2347c87b03e5Sespie 	      else
2348c87b03e5Sespie 		cur_param = 0;
2349c87b03e5Sespie 
2350cd3be6e5Savsm 	      /* Test static string bounds for sscan if -Wbounded is on as well */
2351f15b70e2Savsm 	      if (warn_bounded && apply_bounded
2352cd3be6e5Savsm 		  && types->writing_in_flag
2353cd3be6e5Savsm 		  && i == 0
2354cd3be6e5Savsm 		  && cur_param != 0
2355cd3be6e5Savsm 		  && COMPLETE_TYPE_P (TREE_TYPE (cur_param))
2356cd3be6e5Savsm 		  && TREE_CODE (TREE_TYPE (cur_param)) == ARRAY_TYPE
2357cd3be6e5Savsm 		  && TREE_CODE (TREE_TYPE (TREE_TYPE (cur_param))) == INTEGER_TYPE)
2358cd3be6e5Savsm 		{
2359cd3be6e5Savsm 		  tree array_size_expr = TYPE_MAX_VALUE (TYPE_DOMAIN (TREE_TYPE (cur_param)));
2360cd3be6e5Savsm 		  if (array_size_expr != 0 && types->field_width > 0)
2361cd3be6e5Savsm 		    {
2362f15b70e2Savsm                       int f = types->size_equals_width ? 0 : 1;
2363cd3be6e5Savsm 		      int array_size = TREE_INT_CST_LOW (array_size_expr) + 1;
2364cd3be6e5Savsm 		      if (array_size < (types->field_width + f))
2365f15b70e2Savsm 			warning ("Array size (%d) smaller than format string size (%d) (arg %d)",
2366f15b70e2Savsm 				 array_size, types->field_width + f, arg_num);
2367cd3be6e5Savsm 		    }
2368cd3be6e5Savsm 		}
2369cd3be6e5Savsm 
2370c87b03e5Sespie 	      /* See if this is an attempt to write into a const type with
2371c87b03e5Sespie 		 scanf or with printf "%n".  Note: the writing in happens
2372c87b03e5Sespie 		 at the first indirection only, if for example
2373c87b03e5Sespie 		 void * const * is passed to scanf %p; passing
2374c87b03e5Sespie 		 const void ** is simply passing an incompatible type.  */
2375c87b03e5Sespie 	      if (types->writing_in_flag
2376c87b03e5Sespie 		  && i == 0
2377c87b03e5Sespie 		  && (TYPE_READONLY (cur_type)
2378c87b03e5Sespie 		      || (cur_param != 0
2379c87b03e5Sespie 			  && (TREE_CODE_CLASS (TREE_CODE (cur_param)) == 'c'
2380c87b03e5Sespie 			      || (DECL_P (cur_param)
2381c87b03e5Sespie 				  && TREE_READONLY (cur_param))))))
2382c87b03e5Sespie 		status_warning (status, "writing into constant object (arg %d)", arg_num);
2383c87b03e5Sespie 
2384c87b03e5Sespie 	      /* If there are extra type qualifiers beyond the first
2385c87b03e5Sespie 		 indirection, then this makes the types technically
2386c87b03e5Sespie 		 incompatible.  */
2387c87b03e5Sespie 	      if (i > 0
2388c87b03e5Sespie 		  && pedantic
2389c87b03e5Sespie 		  && (TYPE_READONLY (cur_type)
2390c87b03e5Sespie 		      || TYPE_VOLATILE (cur_type)
2391c87b03e5Sespie 		      || TYPE_RESTRICT (cur_type)))
2392c87b03e5Sespie 		status_warning (status, "extra type qualifiers in format argument (arg %d)",
2393c87b03e5Sespie 			 arg_num);
2394c87b03e5Sespie 
2395c87b03e5Sespie 	    }
2396c87b03e5Sespie 	  else
2397c87b03e5Sespie 	    {
2398c87b03e5Sespie 	      if (types->pointer_count == 1)
2399c87b03e5Sespie 		status_warning (status, "format argument is not a pointer (arg %d)", arg_num);
2400c87b03e5Sespie 	      else
2401c87b03e5Sespie 		status_warning (status, "format argument is not a pointer to a pointer (arg %d)", arg_num);
2402c87b03e5Sespie 	      break;
2403c87b03e5Sespie 	    }
2404c87b03e5Sespie 	}
2405c87b03e5Sespie 
2406c87b03e5Sespie       if (i < types->pointer_count)
2407c87b03e5Sespie 	continue;
2408c87b03e5Sespie 
2409c87b03e5Sespie       orig_cur_type = cur_type;
2410c87b03e5Sespie       cur_type = TYPE_MAIN_VARIANT (cur_type);
2411c87b03e5Sespie 
2412c87b03e5Sespie       /* Check whether the argument type is a character type.  This leniency
2413c87b03e5Sespie 	 only applies to certain formats, flagged with 'c'.
2414c87b03e5Sespie       */
2415c87b03e5Sespie       if (types->char_lenient_flag)
2416c87b03e5Sespie 	char_type_flag = (cur_type == char_type_node
2417c87b03e5Sespie 			  || cur_type == signed_char_type_node
2418c87b03e5Sespie 			  || cur_type == unsigned_char_type_node);
2419c87b03e5Sespie 
2420c87b03e5Sespie       /* Check the type of the "real" argument, if there's a type we want.  */
2421c87b03e5Sespie       if (wanted_type == cur_type)
2422c87b03e5Sespie 	continue;
2423c87b03e5Sespie       /* If we want `void *', allow any pointer type.
2424c87b03e5Sespie 	 (Anything else would already have got a warning.)
2425c87b03e5Sespie 	 With -pedantic, only allow pointers to void and to character
2426c87b03e5Sespie 	 types.  */
2427c87b03e5Sespie       if (wanted_type == void_type_node
2428c87b03e5Sespie 	  && (!pedantic || (i == 1 && char_type_flag)))
2429c87b03e5Sespie 	continue;
2430c87b03e5Sespie       /* Don't warn about differences merely in signedness, unless
2431c87b03e5Sespie 	 -pedantic.  With -pedantic, warn if the type is a pointer
2432c87b03e5Sespie 	 target and not a character type, and for character types at
2433c87b03e5Sespie 	 a second level of indirection.  */
2434c87b03e5Sespie       if (TREE_CODE (wanted_type) == INTEGER_TYPE
2435c87b03e5Sespie 	  && TREE_CODE (cur_type) == INTEGER_TYPE
2436c87b03e5Sespie 	  && (! pedantic || i == 0 || (i == 1 && char_type_flag))
2437c87b03e5Sespie 	  && (TREE_UNSIGNED (wanted_type)
2438c87b03e5Sespie 	      ? wanted_type == c_common_unsigned_type (cur_type)
2439c87b03e5Sespie 	      : wanted_type == c_common_signed_type (cur_type)))
2440c87b03e5Sespie 	continue;
2441c87b03e5Sespie       /* Likewise, "signed char", "unsigned char" and "char" are
2442c87b03e5Sespie 	 equivalent but the above test won't consider them equivalent.  */
2443c87b03e5Sespie       if (wanted_type == char_type_node
2444c87b03e5Sespie 	  && (! pedantic || i < 2)
2445c87b03e5Sespie 	  && char_type_flag)
2446c87b03e5Sespie 	continue;
2447c87b03e5Sespie       /* Now we have a type mismatch.  */
2448c87b03e5Sespie       {
2449c87b03e5Sespie 	const char *this;
2450c87b03e5Sespie 	const char *that;
2451c87b03e5Sespie 
2452c87b03e5Sespie 	this = IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (wanted_type)));
2453c87b03e5Sespie 	that = 0;
2454c87b03e5Sespie 	if (TYPE_NAME (orig_cur_type) != 0
2455c87b03e5Sespie 	    && TREE_CODE (orig_cur_type) != INTEGER_TYPE
2456c87b03e5Sespie 	    && !(TREE_CODE (orig_cur_type) == POINTER_TYPE
2457c87b03e5Sespie 		 && TREE_CODE (TREE_TYPE (orig_cur_type)) == INTEGER_TYPE))
2458c87b03e5Sespie 	  {
2459c87b03e5Sespie 	    if (TREE_CODE (TYPE_NAME (orig_cur_type)) == TYPE_DECL
2460c87b03e5Sespie 		&& DECL_NAME (TYPE_NAME (orig_cur_type)) != 0)
2461c87b03e5Sespie 	      that = IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (orig_cur_type)));
2462c87b03e5Sespie 	    else
2463c87b03e5Sespie 	      that = IDENTIFIER_POINTER (TYPE_NAME (orig_cur_type));
2464c87b03e5Sespie 	  }
2465c87b03e5Sespie 
2466c87b03e5Sespie 	/* A nameless type can't possibly match what the format wants.
2467c87b03e5Sespie 	   So there will be a warning for it.
2468c87b03e5Sespie 	   Make up a string to describe vaguely what it is.  */
2469c87b03e5Sespie 	if (that == 0)
2470c87b03e5Sespie 	  {
2471c87b03e5Sespie 	    if (TREE_CODE (orig_cur_type) == POINTER_TYPE)
2472c87b03e5Sespie 	      that = _("pointer");
2473c87b03e5Sespie 	    else
2474c87b03e5Sespie 	      that = _("different type");
2475c87b03e5Sespie 	  }
2476c87b03e5Sespie 
2477c87b03e5Sespie 	/* Make the warning better in case of mismatch of int vs long.  */
2478c87b03e5Sespie 	if (TREE_CODE (orig_cur_type) == INTEGER_TYPE
2479c87b03e5Sespie 	    && TREE_CODE (wanted_type) == INTEGER_TYPE
2480c87b03e5Sespie 	    && TYPE_PRECISION (orig_cur_type) == TYPE_PRECISION (wanted_type)
2481c87b03e5Sespie 	    && TYPE_NAME (orig_cur_type) != 0
2482c87b03e5Sespie 	    && TREE_CODE (TYPE_NAME (orig_cur_type)) == TYPE_DECL)
2483c87b03e5Sespie 	  that = IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (orig_cur_type)));
2484c87b03e5Sespie 
2485c87b03e5Sespie 	if (strcmp (this, that) != 0)
2486c87b03e5Sespie 	  {
2487c87b03e5Sespie 	    /* There may be a better name for the format, e.g. size_t,
2488c87b03e5Sespie 	       but we should allow for programs with a perverse typedef
2489c87b03e5Sespie 	       making size_t something other than what the compiler
2490c87b03e5Sespie 	       thinks.  */
2491c87b03e5Sespie 	    if (types->wanted_type_name != 0
2492c87b03e5Sespie 		&& strcmp (types->wanted_type_name, that) != 0)
2493c87b03e5Sespie 	      this = types->wanted_type_name;
2494c87b03e5Sespie 	    if (types->name != 0)
2495c87b03e5Sespie 	      status_warning (status, "%s is not type %s (arg %d)", types->name, this,
2496c87b03e5Sespie 		       arg_num);
2497c87b03e5Sespie 	    else
2498c87b03e5Sespie 	      status_warning (status, "%s format, %s arg (arg %d)", this, that, arg_num);
2499c87b03e5Sespie 	  }
2500c87b03e5Sespie       }
2501c87b03e5Sespie     }
2502c87b03e5Sespie }
2503