Subversion Repositories tendra.SVN

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

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