Subversion Repositories tendra.SVN

Rev

Rev 2 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 7u83 1
/*
7 7u83 2
 * Copyright (c) 2002-2006 The TenDRA Project <http://www.tendra.org/>.
3
 * All rights reserved.
4
 *
5
 * Redistribution and use in source and binary forms, with or without
6
 * modification, are permitted provided that the following conditions are met:
7
 *
8
 * 1. Redistributions of source code must retain the above copyright notice,
9
 *    this list of conditions and the following disclaimer.
10
 * 2. Redistributions in binary form must reproduce the above copyright notice,
11
 *    this list of conditions and the following disclaimer in the documentation
12
 *    and/or other materials provided with the distribution.
13
 * 3. Neither the name of The TenDRA Project nor the names of its contributors
14
 *    may be used to endorse or promote products derived from this software
15
 *    without specific, prior written permission.
16
 *
17
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS
18
 * IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
19
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
20
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR
21
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22
 * EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
24
 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
25
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
26
 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
27
 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28
 *
29
 * $Id$
30
 */
31
/*
2 7u83 32
    		 Crown Copyright (c) 1997
7 7u83 33
 
2 7u83 34
    This TenDRA(r) Computer Program is subject to Copyright
35
    owned by the United Kingdom Secretary of State for Defence
36
    acting through the Defence Evaluation and Research Agency
37
    (DERA).  It is made available to Recipients with a
38
    royalty-free licence for its use, reproduction, transfer
39
    to other parties and amendment for any purpose not excluding
40
    product development provided that any such use et cetera
41
    shall be deemed to be acceptance of the following conditions:-
7 7u83 42
 
2 7u83 43
        (1) Its Recipients shall ensure that this Notice is
44
        reproduced upon any copies or amended versions of it;
7 7u83 45
 
2 7u83 46
        (2) Any amended version of it shall be clearly marked to
47
        show both the nature of and the organisation responsible
48
        for the relevant amendment or amendments;
7 7u83 49
 
2 7u83 50
        (3) Its onward transfer from a recipient to another
51
        party shall be deemed to be that party's acceptance of
52
        these conditions;
7 7u83 53
 
2 7u83 54
        (4) DERA gives no warranty or assurance as to its
55
        quality or suitability for any purpose and DERA accepts
56
        no liability whatsoever in relation to any use to which
57
        it may be put.
58
*/
59
 
60
 
61
#include "config.h"
62
#include <limits.h>
63
#include "c_types.h"
64
#include "id_ops.h"
65
#include "str_ops.h"
66
#include "type_ops.h"
67
#include "error.h"
68
#include "catalog.h"
69
#include "option.h"
70
#include "basetype.h"
71
#include "char.h"
72
#include "chktype.h"
73
#include "convert.h"
74
#include "literal.h"
75
#include "printf.h"
76
#include "typeid.h"
77
#include "ustring.h"
78
 
79
 
80
/*
81
    PRINTF AND SCANF FLAGS
82
 
83
    These values are used to indicate the various flags, field widths and
84
    precision used to modify printf and scanf format strings.
85
*/
86
 
7 7u83 87
#define PRINTF_NONE		((unsigned)0x0000)
88
#define PRINTF_THOUSAND		((unsigned)0x0001)
89
#define PRINTF_LEFT		((unsigned)0x0002)
90
#define PRINTF_SIGN		((unsigned)0x0004)
91
#define PRINTF_SPACE		((unsigned)0x0008)
92
#define PRINTF_ALT		((unsigned)0x0010)
93
#define PRINTF_ZERO		((unsigned)0x0020)
94
#define PRINTF_WIDTH		((unsigned)0x0040)
95
#define PRINTF_PREC		((unsigned)0x0080)
96
#define PRINTF_ERROR		((unsigned)0x0100)
97
#define PRINTF_FLAGS		((unsigned)0x003f)
98
#define PRINTF_ARITH		((unsigned)0x003d)
2 7u83 99
 
100
 
101
/*
102
    SKIP A NUMBER OF DIGITS FROM A STRING
103
 
104
    This routine skips a number of decimal digits from the string str.
105
    The first character and its character type are given by c and pc.
106
    The routine returns the first non-digit character, assigning the
107
    value read (or UINT_MAX if an overflow occurs) into pn.
108
*/
109
 
7 7u83 110
static unsigned long
111
read_width(STRING str, unsigned long c, int *pc, unsigned *pn)
2 7u83 112
{
7 7u83 113
	unsigned n = 0;
114
	unsigned m = 0;
115
	int overflow = 0;
116
	while (*pc == CHAR_SIMPLE && (c >= char_zero && c <= char_nine)) {
117
		n = 10 * n + (unsigned)(c - char_zero);
118
		if (n < m) {
119
			overflow = 1;
120
		}
121
		m = n;
122
		c = get_string_char(str, pc);
123
	}
124
	if (overflow) {
125
		n = UINT_MAX;
126
	}
127
	*pn = n;
128
	return (c);
2 7u83 129
}
130
 
131
 
132
/*
133
    READ A PRINTF ARGUMENT NUMBER
134
 
135
    In several places in a printf or scanf format string, a sequence of
136
    characters of the form 'n$' for a sequence of decimal digits n is
137
    used to indicate the nth, as opposed to the next, argument.  This
138
    routine checks for such sequences in the string str, returning n.
139
    margs gives the maximum value allowed for n, if n exceeds this value
140
    then it UINT_MAX is returned.  A value of 0 is returned if str does
141
    not have this form (note that the arguments are numbered from 1).
142
*/
143
 
7 7u83 144
static unsigned
145
read_arg_no(STRING str, unsigned margs)
2 7u83 146
{
7 7u83 147
	unsigned long tok = DEREF_ulong(str_simple_tok(str));
148
	int ch = CHAR_SIMPLE;
149
	unsigned long c = get_string_char(str, &ch);
150
	if (ch == CHAR_SIMPLE && (c >= char_zero && c <= char_nine)) {
151
		unsigned n = 0;
152
		c = read_width(str, c, &ch, &n);
153
		if (ch == CHAR_SIMPLE && c == char_dollar) {
154
			if (n > margs) {
155
				/* Argument number out of range */
156
				report(crt_loc, ERR_printf_arg_large(n));
157
				n = UINT_MAX;
158
			}
159
			if (n == 0) {
160
				/* Can't have argument zero */
161
				report(crt_loc, ERR_printf_arg_zero());
162
				n = 1;
163
			}
164
			return (n);
165
		}
2 7u83 166
	}
7 7u83 167
	COPY_ulong(str_simple_tok(str), tok);
168
	return (0);
2 7u83 169
}
170
 
171
 
172
/*
173
    CHECK A PRINTF OR SCANF FORMAT STRING
174
 
175
    This routine combines a printf or scanf format string corresponding to
176
    the type n, modified by the type modifier m.  flags gives any invalid
177
    format flags.
178
*/
179
 
7 7u83 180
static BUILTIN_TYPE
181
check_format(string s, BUILTIN_TYPE n, BUILTIN_TYPE m, unsigned flags)
2 7u83 182
{
7 7u83 183
	switch (m) {
184
	case ntype_sshort:
185
		/* 'h' modifier */
186
		switch (n) {
187
		case ntype_sint:
188
			n = ntype_sshort;
189
			break;
190
		case ntype_uint:
191
			n = ntype_ushort;
192
			break;
193
		default:
194
			flags |= PRINTF_ERROR;
195
			break;
196
		}
197
		break;
198
	case ntype_slong:
199
		/* 'l' modifier */
200
		switch (n) {
201
		case ntype_char:
202
			n = ntype_wchar_t;
203
			break;
204
		case ntype_uchar:
205
			n = ntype_none;
206
			break;
207
		case ntype_sint:
208
			n = ntype_slong;
209
			break;
210
		case ntype_uint:
211
			n = ntype_ulong;
212
			break;
213
		case ntype_float:
214
			n = ntype_double;
215
			break;
216
		default:
217
			flags |= PRINTF_ERROR;
218
			break;
219
		}
220
		break;
221
	case ntype_ldouble:
222
		/* 'L' modifier */
223
		switch (n) {
224
		case ntype_float:
225
			n = ntype_ldouble;
226
			break;
227
		case ntype_double:
228
			n = ntype_ldouble;
229
			break;
230
		default:
231
			flags |= PRINTF_ERROR;
232
			break;
233
		}
234
		break;
2 7u83 235
	}
7 7u83 236
 
237
	if (flags) {
238
		if (flags & PRINTF_ERROR) {
239
			report(crt_loc, ERR_printf_invalid(s));
240
			s[1] = s[2];
241
			s[2] = 0;
242
		}
243
		if (flags & PRINTF_FLAGS) {
244
			character t[8];
245
			string r = t;
246
			if (flags & PRINTF_THOUSAND) {
247
				*(r++) = char_single_quote;
248
			}
249
			if (flags & PRINTF_LEFT) {
250
				*(r++) = char_minus;
251
			}
252
			if (flags & PRINTF_SIGN) {
253
				*(r++) = char_plus;
254
			}
255
			if (flags & PRINTF_SPACE) {
256
				*(r++) = char_space;
257
			}
258
			if (flags & PRINTF_ALT) {
259
				*(r++) = char_hash;
260
			}
261
			if (flags & PRINTF_ZERO) {
262
				*(r++) = char_zero;
263
			}
264
			*r = 0;
265
			report(crt_loc, ERR_printf_flags(t, s));
266
		}
267
		if (flags & PRINTF_WIDTH) {
268
			report(crt_loc, ERR_printf_width(s));
269
		}
270
		if (flags & PRINTF_PREC) {
271
			report(crt_loc, ERR_printf_precision(s));
272
		}
2 7u83 273
	}
7 7u83 274
	return (n);
2 7u83 275
}
276
 
277
 
278
/*
279
    SET AN ARGUMENT TYPE
280
 
281
    This routine sets the nth argument of the list p to be t.  The elements
282
    of p are in reverse order and numbered from 1.  A zero value for n is
283
    equivalent to 'LENGTH_list ( p ) + 1'.  The state flag is used to keep
284
    track of whether numbered and unnumbered arguments are mixed.
285
*/
286
 
7 7u83 287
static LIST(TYPE)
288
set_printf_arg(LIST(TYPE) p, unsigned n, TYPE t, int *state)
2 7u83 289
{
7 7u83 290
	if (n == 0) {
291
		/* Simple case */
292
		if (*state == 2) {
293
			report(crt_loc, ERR_printf_arg_mix());
294
			*state = 3;
295
		} else {
296
			*state = 1;
297
		}
298
		CONS_type(t, p, p);
2 7u83 299
	} else {
7 7u83 300
		unsigned m = UINT_MAX;
301
		if (*state == 1) {
302
			report(crt_loc, ERR_printf_arg_mix());
303
			*state = 3;
304
		} else {
305
			*state = 2;
2 7u83 306
		}
7 7u83 307
		if (n != m) {
308
			/* Valid argument number */
309
			TYPE s;
310
			LIST(TYPE) q;
311
			m = LENGTH_list(p);
312
			while (m < n) {
313
				/* Add extra arguments if necessary */
314
				CONS_type(NULL_type, p, p);
315
				m++;
316
			}
317
			q = p;
318
			while (m > n) {
319
				/* Scan to nth argument */
320
				q = TAIL_list(q);
321
				m--;
322
			}
323
			s = DEREF_type(HEAD_list(q));
324
			if (!IS_NULL_type(s) && !EQ_type(s, t)) {
325
				/* Check for compatibility with previous type */
326
				ERROR err = NULL_err;
327
				t = check_compatible(s, t, 1, &err, 1);
328
				if (!IS_NULL_err(err)) {
329
					err = set_severity(err, OPT_whatever, 0);
330
					err = concat_error(err, ERR_printf_arg_compat(n));
331
					report(crt_loc, err);
332
				}
333
			}
334
			COPY_type(HEAD_list(q), t);
335
		}
2 7u83 336
	}
7 7u83 337
	return (p);
2 7u83 338
}
339
 
340
 
341
/*
342
    PRINTF AND SCANF ARGUMENT TYPES
343
 
344
    These variables give those printf and scanf argument types which are
345
    not built-in types or pointers to built-in types.
346
*/
347
 
7 7u83 348
static TYPE ptr_const_char = NULL_type;
349
static TYPE ptr_const_wchar_t = NULL_type;
350
static TYPE ptr_ptr_void = NULL_type;
351
static TYPE type_wint_t = NULL_type;
2 7u83 352
 
353
 
354
/*
355
    FIND A PRINTF ARGUMENT TYPE
356
 
357
    This routine reads a single printf argument type from the string
358
    str, adding it to the list p.  It is entered immediately after the
359
    '%' in the format string has been read.
360
*/
361
 
7 7u83 362
static LIST(TYPE)
363
add_printf_arg(STRING str, LIST(TYPE) p, unsigned margs, int *state)
2 7u83 364
{
7 7u83 365
	unsigned flag;
366
	character s[8];
367
	string r = s;
368
	unsigned long c;
369
	TYPE t = NULL_type;
370
	int ch = CHAR_SIMPLE;
371
	BUILTIN_TYPE n = ntype_none;
372
	unsigned flags = PRINTF_NONE;
2 7u83 373
 
7 7u83 374
	/* Read argument number */
375
	unsigned arg = read_arg_no(str, margs);
2 7u83 376
 
7 7u83 377
	/* Read flags */
378
	do {
379
		c = get_string_char(str, &ch);
380
		if (ch == CHAR_SIMPLE) {
381
			if (c == char_percent && flags == PRINTF_NONE &&
382
			    arg == 0) {
383
				/* Have precisely '%%' */
384
				return (p);
385
			}
386
			switch (c) {
387
			case char_single_quote:
388
				flag = PRINTF_THOUSAND;
389
				break;
390
			case char_minus:
391
				flag = PRINTF_LEFT;
392
				break;
393
			case char_plus:
394
				flag = PRINTF_SIGN;
395
				break;
396
			case char_space:
397
				flag = PRINTF_SPACE;
398
				break;
399
			case char_hash:
400
				flag = PRINTF_ALT;
401
				break;
402
			case char_zero:
403
				flag = PRINTF_ZERO;
404
				break;
405
			default:
406
				flag = PRINTF_NONE;
407
				break;
408
			}
409
			flags |= flag;
410
		} else {
411
			flag = PRINTF_NONE;
412
		}
413
	} while (flag != PRINTF_NONE);
2 7u83 414
 
7 7u83 415
	/* Read field width */
416
	if (ch == CHAR_SIMPLE) {
417
		if (c == char_asterix) {
418
			unsigned arg2 = read_arg_no(str, margs);
419
			p = set_printf_arg(p, arg2, type_sint, state);
420
			c = get_string_char(str, &ch);
421
			flags |= PRINTF_WIDTH;
422
		} else if (c >= char_zero && c <= char_nine) {
423
			unsigned v = 0;
424
			c = read_width(str, c, &ch, &v);
425
			flags |= PRINTF_WIDTH;
426
		}
2 7u83 427
	}
428
 
7 7u83 429
	/* Read precision */
430
	if (ch == CHAR_SIMPLE && c == char_dot) {
431
		c = get_string_char(str, &ch);
432
		if (ch == CHAR_SIMPLE) {
433
			if (c == char_asterix) {
434
				unsigned arg2 = read_arg_no(str, margs);
435
				p = set_printf_arg(p, arg2, type_sint, state);
436
				c = get_string_char(str, &ch);
437
			} else if (c >= char_zero && c <= char_nine) {
438
				unsigned v = 0;
439
				c = read_width(str, c, &ch, &v);
440
			}
441
		}
442
		flags |= PRINTF_PREC;
2 7u83 443
	}
444
 
7 7u83 445
	/* Read type modifier */
446
	*(r++) = char_percent;
447
	if (ch == CHAR_SIMPLE) {
448
		switch (c) {
449
		case char_h:
450
			n = ntype_sshort;
451
			break;
452
		case char_l:
453
			n = ntype_slong;
454
			break;
455
		case char_L:
456
			n = ntype_ldouble;
457
			break;
458
		}
459
		if (n != ntype_none) {
460
			*(r++) = (character)c;
461
			c = get_string_char(str, &ch);
462
		}
2 7u83 463
	}
464
 
7 7u83 465
	/* Read type specifier */
466
	r[0] = (character)c;
467
	r[1] = 0;
468
	if (ch == CHAR_SIMPLE) {
469
		switch (c) {
470
		case char_c:
471
			flags &= (PRINTF_ARITH | PRINTF_PREC);
472
			n = check_format(s, ntype_uchar, n, flags);
473
			if (n == ntype_none) {
474
				goto wint_lab;
475
			}
476
			break;
477
		case char_C:
478
			flags &= PRINTF_ARITH;
479
			n = check_format(s, ntype_none, n, flags);
480
wint_lab:
481
			t = type_wint_t;
482
			if (IS_NULL_type(t)) {
483
				t = find_std_type("wint_t", 0, 0);
484
				if (!IS_NULL_type(t)) {
485
					type_wint_t = t;
486
				} else {
487
					t = type_error;
488
				}
489
			}
490
			break;
491
		case char_d:
492
		case char_i:
493
			flags &= PRINTF_ALT;
494
			n = check_format(s, ntype_sint, n, flags);
495
			break;
496
		case char_o:
497
			flags &= (PRINTF_ALT | PRINTF_THOUSAND);
498
			n = check_format(s, ntype_uint, n, flags);
499
			break;
500
		case char_u:
501
			flags &= PRINTF_ALT;
502
			n = check_format(s, ntype_uint, n, flags);
503
			break;
504
		case char_x:
505
		case char_X:
506
			flags &= PRINTF_THOUSAND;
507
			n = check_format(s, ntype_uint, n, flags);
508
			break;
509
		case char_e:
510
		case char_E:
511
			flags &= PRINTF_THOUSAND;
512
			n = check_format(s, ntype_double, n, flags);
513
			break;
514
		case char_f:
515
		case char_g:
516
		case char_G:
517
			n = check_format(s, ntype_double, n, PRINTF_NONE);
518
			break;
519
		case char_s:
520
			flags &= PRINTF_ARITH;
521
			n = check_format(s, ntype_char, n, flags);
522
			if (n == ntype_char) {
523
				t = ptr_const_char;
2 7u83 524
			} else {
7 7u83 525
				t = ptr_const_wchar_t;
2 7u83 526
			}
7 7u83 527
			n = ntype_none;
528
			break;
529
		case char_S:
530
			flags &= PRINTF_ARITH;
531
			n = check_format(s, ntype_none, n, flags);
532
			t = ptr_const_wchar_t;
533
			break;
534
		case char_p:
535
			flags &= (PRINTF_ARITH | PRINTF_PREC);
536
			n = check_format(s, ntype_none, n, flags);
537
			t = type_void_star;
538
			break;
539
		case char_n:
540
			n = check_format(s, ntype_sint, n, flags);
541
			t = ptr_type_builtin[n];
542
			n = ntype_none;
543
			break;
544
		default:
545
			report(crt_loc, ERR_printf_unknown(s));
546
			t = type_error;
547
			n = ntype_none;
548
			break;
2 7u83 549
		}
7 7u83 550
		if (n != ntype_none) {
551
			t = type_builtin[n];
2 7u83 552
		}
7 7u83 553
	} else {
554
		report(crt_loc, ERR_printf_unknown(s));
555
		t = type_error;
2 7u83 556
	}
7 7u83 557
	if (!IS_NULL_type(t)) {
558
		t = arg_promote_type(t, KILL_err);
559
		p = set_printf_arg(p, arg, t, state);
560
	}
561
	return (p);
2 7u83 562
}
563
 
564
 
565
/*
566
    FIND A SCANF ARGUMENT TYPE
567
 
568
    This routine reads a single scanf argument type from the string
569
    str, adding it to the list p.  It is entered immediately after the
570
    '%' in the format string has been read.
571
*/
572
 
7 7u83 573
static LIST(TYPE)
574
add_scanf_arg(STRING str, LIST(TYPE) p, unsigned margs, int *state)
2 7u83 575
{
7 7u83 576
	character s[8];
577
	string r = s;
578
	int ignore = 0;
579
	unsigned long c;
580
	TYPE t = NULL_type;
581
	int ch = CHAR_SIMPLE;
582
	BUILTIN_TYPE n = ntype_none;
583
	unsigned flags = PRINTF_NONE;
2 7u83 584
 
7 7u83 585
	/* Read argument number */
586
	unsigned arg = read_arg_no(str, margs);
2 7u83 587
 
7 7u83 588
	/* Check for initial '*' */
589
	c = get_string_char(str, &ch);
590
	if (ch == CHAR_SIMPLE) {
591
		if (c == char_percent && arg == 0) {
592
			/* Have precisely '%%' */
593
			return (p);
594
		}
595
		if (c == char_asterix) {
596
			c = get_string_char(str, &ch);
597
			ignore = 1;
598
		}
2 7u83 599
	}
600
 
7 7u83 601
	/* Read field width */
602
	if (ch == CHAR_SIMPLE && (c >= char_zero && c <= char_nine)) {
603
		unsigned v = 0;
604
		c = read_width(str, c, &ch, &v);
605
		flags |= PRINTF_WIDTH;
2 7u83 606
	}
607
 
7 7u83 608
	/* Read type modifier */
609
	*(r++) = char_percent;
610
	if (ch == CHAR_SIMPLE) {
611
		switch (c) {
612
		case char_h:
613
			n = ntype_sshort;
614
			break;
615
		case char_l:
616
			n = ntype_slong;
617
			break;
618
		case char_L:
619
			n = ntype_ldouble;
620
			break;
2 7u83 621
		}
7 7u83 622
		if (n != ntype_none) {
623
			*(r++) = (character)c;
624
			c = get_string_char(str, &ch);
2 7u83 625
		}
626
	}
7 7u83 627
 
628
	/* Read type specifier */
629
	r[0] = (character)c;
630
	r[1] = 0;
631
	if (ch == CHAR_SIMPLE) {
632
		switch (c) {
633
		case char_c:
634
			n = check_format(s, ntype_char, n, PRINTF_NONE);
635
			break;
636
		case char_C:
637
			n = check_format(s, ntype_wchar_t, n, PRINTF_NONE);
638
			break;
639
		case char_d:
640
		case char_i:
641
			n = check_format(s, ntype_sint, n, PRINTF_NONE);
642
			break;
643
		case char_o:
644
		case char_u:
645
		case char_x:
646
		case char_X:
647
			n = check_format(s, ntype_uint, n, PRINTF_NONE);
648
			break;
649
		case char_e:
650
		case char_E:
651
		case char_f:
652
		case char_g:
653
		case char_G:
654
			n = check_format(s, ntype_float, n, PRINTF_NONE);
655
			break;
656
		case char_s:
657
			n = check_format(s, ntype_char, n, PRINTF_NONE);
658
			break;
659
		case char_open_square:
660
			c = get_string_char(str, &ch);
661
			if (ch == CHAR_SIMPLE && c == char_circum) {
662
				IGNORE get_string_char(str, &ch);
663
			}
664
			do {
665
				c = get_string_char(str, &ch);
666
				if (ch == CHAR_NONE) {
667
					report(crt_loc, ERR_printf_unterm(s));
668
					break;
669
				}
670
			} while (ch != CHAR_SIMPLE || c != char_close_square);
671
			r = ustrlit("%[...]");
672
			n = check_format(r, ntype_char, n, PRINTF_NONE);
673
			break;
674
		case char_S:
675
			n = check_format(s, ntype_wchar_t, n, PRINTF_NONE);
676
			break;
677
		case char_p:
678
			n = check_format(s, ntype_none, n, PRINTF_NONE);
679
			t = ptr_ptr_void;
680
			break;
681
		case char_n:
682
			if (ignore) {
683
				r = ustrlit("*");
684
				report(crt_loc, ERR_printf_flags(r, s));
685
			}
686
			n = check_format(s, ntype_sint, n, flags);
687
			break;
688
		default:
689
			report(crt_loc, ERR_printf_unknown(s));
690
			t = type_error;
691
			n = ntype_none;
692
			break;
693
		}
694
		if (n != ntype_none)t = ptr_type_builtin[n];
695
	} else {
696
		report(crt_loc, ERR_printf_unknown(s));
697
		t = type_error;
698
	}
699
	if (!IS_NULL_type(t) && !ignore) {
700
		p = set_printf_arg(p, arg, t, state);
701
	}
702
	return (p);
2 7u83 703
}
704
 
705
 
706
/*
707
    FIND PRINTF OR SCANF ARGUMENT TYPES
708
 
709
    This routine finds the list of arguments expected by a printf-like
710
    or scanf-like function with format string fmt.  margs gives the
711
    number argument number which may be specified using '%n$', and pf is
712
    the value returned by is_printf_type.
713
*/
714
 
7 7u83 715
LIST(TYPE)
716
find_printf_args(STRING str, unsigned margs, int pf)
2 7u83 717
{
7 7u83 718
	int state = 0;
719
	unsigned long c;
720
	int ch = CHAR_SIMPLE;
721
	LIST(TYPE) p = NULL_list(TYPE);
722
	ulong tok = DEREF_ulong(str_simple_tok(str));
723
	COPY_ulong(str_simple_tok(str), 0);
724
	while (c = get_string_char(str, &ch), ch != CHAR_NONE) {
725
		if (c == char_percent && ch == CHAR_SIMPLE) {
726
			if (pf & 1) {
727
				p = add_printf_arg(str, p, margs, &state);
728
			} else {
729
				p = add_scanf_arg(str, p, margs, &state);
730
			}
731
		}
2 7u83 732
	}
7 7u83 733
	if (state >= 2) {
734
		int reported = 0;
735
		LIST(TYPE) q = p;
736
		while (!IS_NULL_list(q)) {
737
			TYPE t = DEREF_type(HEAD_list(q));
738
			if (IS_NULL_type(t)) {
739
				/* No format string for given argument */
740
				if (!reported) {
741
					unsigned n = LENGTH_list(q);
742
					report(crt_loc, ERR_printf_arg_none(n));
743
					reported = 1;
744
				}
745
				COPY_type(HEAD_list(q), type_error);
746
			} else {
747
				reported = 0;
748
			}
749
			q = TAIL_list(q);
2 7u83 750
		}
751
	}
7 7u83 752
	COPY_ulong(str_simple_tok(str), tok);
753
	p = REVERSE_list(p);
754
	return (p);
2 7u83 755
}
756
 
757
 
758
/*
759
    PRINTF AND SCANF STRING TYPES
760
 
761
    Functions like printf and scanf are indicated by an argument with one
762
    of the following types, which equal 'const char *' or 'const wchar_t *'.
763
*/
764
 
7 7u83 765
TYPE type_printf = NULL_type;
766
TYPE type_scanf = NULL_type;
767
TYPE type_wprintf = NULL_type;
768
TYPE type_wscanf = NULL_type;
2 7u83 769
 
770
 
771
/*
772
    IS A TYPE A PRINTF OR SCANF STRING TYPE?
773
 
774
    This routine checks whether the type t is derived from one of the
775
    printf or scanf string types above.  It returns 1 for type_printf,
776
    2 for type_scanf, 3 for type_wprintf and 4 for type_wscanf.
777
*/
778
 
7 7u83 779
int
780
is_printf_type(TYPE t)
2 7u83 781
{
7 7u83 782
	IDENTIFIER tid = DEREF_id(type_name(t));
783
	if (!IS_NULL_id(tid)) {
784
		TYPE s = DEREF_type(id_class_name_etc_defn(tid));
785
		if (IS_type_ptr(s)) {
786
			if (EQ_type(s, type_printf)) {
787
				return (1);
788
			}
789
			if (EQ_type(s, type_scanf)) {
790
				return (2);
791
			}
792
			if (EQ_type(s, type_wprintf)) {
793
				return (3);
794
			}
795
			if (EQ_type(s, type_wscanf)) {
796
				return (4);
797
			}
798
		}
2 7u83 799
	}
7 7u83 800
	return (0);
2 7u83 801
}
802
 
803
 
804
/*
805
    INITIALISE PRINTF AND SCANF TYPES
806
 
807
    This routine initialises the printf and scanf strings.
808
*/
809
 
7 7u83 810
void
811
init_printf(void)
2 7u83 812
{
7 7u83 813
	TYPE c = qualify_type(type_char, cv_const, 0);
814
	TYPE w = qualify_type(type_wchar_t, cv_const, 0);
815
	MAKE_type_ptr(cv_none, c, type_printf);
816
	MAKE_type_ptr(cv_none, c, type_scanf);
817
	MAKE_type_ptr(cv_none, w, type_wprintf);
818
	MAKE_type_ptr(cv_none, w, type_wscanf);
819
	MAKE_type_ptr(cv_none, c, ptr_const_char);
820
	MAKE_type_ptr(cv_none, w, ptr_const_wchar_t);
821
	MAKE_type_ptr(cv_none, type_void_star, ptr_ptr_void);
822
	return;
2 7u83 823
}