@@ -13,9 +13,11 @@ module dmd.chkformat;
13
13
// import core.stdc.stdio : printf, scanf;
14
14
import core.stdc.ctype : isdigit;
15
15
16
+ import dmd.cond;
16
17
import dmd.errors;
17
18
import dmd.expression;
18
19
import dmd.globals;
20
+ import dmd.identifier;
19
21
import dmd.mtype;
20
22
import dmd.target;
21
23
@@ -59,7 +61,7 @@ import dmd.target;
59
61
bool checkPrintfFormat (ref const Loc loc, scope const char [] format, scope Expression[] args, bool isVa_list)
60
62
{
61
63
// printf("checkPrintFormat('%.*s')\n", cast(int)format.length, format.ptr);
62
- size_t n = 0 ;
64
+ size_t n, gnu_m_count; // index in args / number of Format.GNU_m
63
65
for (size_t i = 0 ; i < format.length;)
64
66
{
65
67
if (format[i] != ' %' )
@@ -85,11 +87,17 @@ bool checkPrintfFormat(ref const Loc loc, scope const char[] format, scope Expre
85
87
continue ;
86
88
}
87
89
88
- Expression getNextArg ()
90
+ if (fmt == Format.GNU_m)
91
+ ++ gnu_m_count;
92
+
93
+ Expression getNextArg (ref bool skip)
89
94
{
90
95
if (n == args.length)
91
96
{
92
- deprecation(loc, " more format specifiers than %d arguments" , cast (int )n);
97
+ if (args.length < (n + 1 ) - gnu_m_count)
98
+ deprecation(loc, " more format specifiers than %zd arguments" , n);
99
+ else
100
+ skip = true ;
93
101
return null ;
94
102
}
95
103
return args[n++ ];
@@ -103,7 +111,10 @@ bool checkPrintfFormat(ref const Loc loc, scope const char[] format, scope Expre
103
111
104
112
if (widthStar)
105
113
{
106
- auto e = getNextArg();
114
+ bool skip;
115
+ auto e = getNextArg(skip);
116
+ if (skip)
117
+ continue ;
107
118
if (! e)
108
119
return true ;
109
120
auto t = e.type.toBasetype();
@@ -113,15 +124,21 @@ bool checkPrintfFormat(ref const Loc loc, scope const char[] format, scope Expre
113
124
114
125
if (precisionStar)
115
126
{
116
- auto e = getNextArg();
127
+ bool skip;
128
+ auto e = getNextArg(skip);
129
+ if (skip)
130
+ continue ;
117
131
if (! e)
118
132
return true ;
119
133
auto t = e.type.toBasetype();
120
134
if (t.ty != Tint32 && t.ty != Tuns32)
121
135
errorMsg(" precision " , slice, e, " int" , t);
122
136
}
123
137
124
- auto e = getNextArg();
138
+ bool skip;
139
+ auto e = getNextArg(skip);
140
+ if (skip)
141
+ continue ;
125
142
if (! e)
126
143
return true ;
127
144
auto t = e.type.toBasetype();
@@ -179,6 +196,7 @@ bool checkPrintfFormat(ref const Loc loc, scope const char[] format, scope Expre
179
196
errorMsg(null , slice, e, " ptrdiff_t" , t);
180
197
break ;
181
198
199
+ case Format.GNU_a: // Format.GNU_a is only for scanf
182
200
case Format.lg:
183
201
case Format.g: // double
184
202
if (t.ty != Tfloat64 && t.ty != Timaginary64)
@@ -260,6 +278,9 @@ bool checkPrintfFormat(ref const Loc loc, scope const char[] format, scope Expre
260
278
deprecation(loc, " format specifier `\" %.*s\" ` is invalid" , cast (int )slice.length, slice.ptr);
261
279
break ;
262
280
281
+ case Format.GNU_m:
282
+ break ; // not assert(0) because it may go through it if there are extra arguments
283
+
263
284
case Format.percent:
264
285
assert (0 );
265
286
}
@@ -439,15 +460,19 @@ bool checkScanfFormat(ref const Loc loc, scope const char[] format, scope Expres
439
460
if (! (t.ty == Tpointer && tnext.ty == Tfloat32))
440
461
errorMsg(null , slice, e, " float*" , t);
441
462
break ;
463
+
442
464
case Format.lg: // pointer to double
443
465
if (! (t.ty == Tpointer && tnext.ty == Tfloat64))
444
466
errorMsg(null , slice, e, " double*" , t);
445
467
break ;
468
+
446
469
case Format.Lg: // pointer to long double
447
470
if (! (t.ty == Tpointer && tnext.ty == Tfloat80))
448
471
errorMsg(null , slice, e, " real*" , t);
449
472
break ;
450
473
474
+ case Format.GNU_a:
475
+ case Format.GNU_m:
451
476
case Format.c:
452
477
case Format.s: // pointer to char string
453
478
if (! (t.ty == Tpointer && (tnext.ty == Tchar || tnext.ty == Tint8 || tnext.ty == Tuns8)))
@@ -493,9 +518,8 @@ private:
493
518
* Returns:
494
519
* Format
495
520
*/
496
- pure nothrow @safe
497
521
Format parseScanfFormatSpecifier (scope const char [] format, ref size_t idx,
498
- out bool asterisk)
522
+ out bool asterisk) nothrow pure @safe
499
523
{
500
524
auto i = idx;
501
525
assert (format[i] == ' %' );
@@ -583,9 +607,8 @@ Format parseScanfFormatSpecifier(scope const char[] format, ref size_t idx,
583
607
* Returns:
584
608
* Format
585
609
*/
586
- pure nothrow @safe
587
610
Format parsePrintfFormatSpecifier (scope const char [] format, ref size_t idx,
588
- out bool widthStar, out bool precisionStar)
611
+ out bool widthStar, out bool precisionStar) nothrow pure @safe
589
612
{
590
613
auto i = idx;
591
614
assert (format[i] == ' %' );
@@ -767,6 +790,8 @@ enum Format
767
790
jn, // pointer to intmax_t
768
791
zn, // pointer to size_t
769
792
tn, // pointer to ptrdiff_t
793
+ GNU_a, // GNU ext. : address to a string with no maximum size (scanf)
794
+ GNU_m, // GNU ext. : string corresponding to the error code in errno (printf) / length modifier (scanf)
770
795
percent, // %% (i.e. no argument)
771
796
error, // invalid format specification
772
797
}
@@ -785,9 +810,9 @@ enum Format
785
810
* Returns:
786
811
* Format
787
812
*/
788
- pure @safe nothrow
789
813
Format parseGenericFormatSpecifier (scope const char [] format,
790
- ref size_t idx, out char genSpecifier)
814
+ ref size_t idx, out char genSpecifier, bool useGNUExts =
815
+ findCondition(global.versionids, Identifier.idPool(" CRuntime_Glibc" ))) nothrow pure @trusted
791
816
{
792
817
const length = format.length;
793
818
@@ -859,13 +884,21 @@ Format parseGenericFormatSpecifier(scope const char[] format,
859
884
Format.u;
860
885
break ;
861
886
887
+ case ' a' :
888
+ if (useGNUExts)
889
+ {
890
+ // https://www.gnu.org/software/libc/manual/html_node/Dynamic-String-Input.html
891
+ specifier = Format.GNU_a;
892
+ break ;
893
+ }
894
+ goto case ;
895
+
862
896
case ' f' :
863
897
case ' F' :
864
898
case ' e' :
865
899
case ' E' :
866
900
case ' g' :
867
901
case ' G' :
868
- case ' a' :
869
902
case ' A' :
870
903
if (lm == ' L' )
871
904
specifier = Format.Lg;
@@ -910,6 +943,15 @@ Format parseGenericFormatSpecifier(scope const char[] format,
910
943
Format.n;
911
944
break ;
912
945
946
+ case ' m' :
947
+ if (useGNUExts)
948
+ {
949
+ // http://www.gnu.org/software/libc/manual/html_node/Other-Output-Conversions.html
950
+ specifier = Format.GNU_m;
951
+ break ;
952
+ }
953
+ goto default ;
954
+
913
955
default :
914
956
specifier = Format.error;
915
957
break ;
@@ -1075,7 +1117,8 @@ unittest
1075
1117
assert (idx == 2 );
1076
1118
1077
1119
idx = 0 ;
1078
- assert (parsePrintfFormatSpecifier(" %a" , idx, widthStar, precisionStar) == Format.g);
1120
+ Format g = parsePrintfFormatSpecifier(" %a" , idx, widthStar, precisionStar);
1121
+ assert (g == Format.g || g == Format.GNU_a);
1079
1122
assert (idx == 2 );
1080
1123
1081
1124
idx = 0 ;
@@ -1245,7 +1288,8 @@ unittest
1245
1288
assert (idx == 2 );
1246
1289
1247
1290
idx = 0 ;
1248
- assert (parseScanfFormatSpecifier(" %a" , idx, asterisk) == Format.g);
1291
+ g = parseScanfFormatSpecifier(" %a" , idx, asterisk);
1292
+ assert (g == Format.g || g == Format.GNU_a);
1249
1293
assert (idx == 2 );
1250
1294
1251
1295
idx = 0 ;
0 commit comments