1 // Written in the D programming language.
2 
3 /**
4 This is a submodule of $(MREF std, format).
5 
6 It provides two functions for reading formatted input: $(LREF
7 unformatValue) and $(LREF formattedRead). The former reads a single
8 value. The latter reads several values at once and matches the
9 characters found between format specifiers.
10 
11 Parameters are ignored, except for the ones consisting of a single
12 $(B '*'). See $(LREF formattedRead) for more information.
13 
14 A space outside of a format specifier has a special meaning: it
15 matches any sequence of whitespace characters, not just a single
16 space.
17 
18 The following combinations of format characters and types are
19 available:
20 
21 $(BOOKTABLE ,
22 $(TR $(TH) $(TH s) $(TH c) $(TH d, u, b, o, x, X) $(TH e, E, f, g, G) $(TH r) $(TH compound))
23 $(TR $(TD `bool`) $(TD yes) $(TD $(MDASH)) $(TD yes) $(TD $(MDASH)) $(TD $(MDASH)) $(TD $(MDASH)))
24 $(TR $(TD `null`) $(TD yes) $(TD $(MDASH)) $(TD $(MDASH)) $(TD $(MDASH)) $(TD $(MDASH)) $(TD $(MDASH)))
25 $(TR $(TD $(I integer)) $(TD yes) $(TD $(MDASH)) $(TD yes) $(TD $(MDASH)) $(TD yes) $(TD $(MDASH)))
26 $(TR $(TD $(I floating point)) $(TD yes) $(TD $(MDASH)) $(TD $(MDASH)) $(TD yes) $(TD yes) $(TD $(MDASH)))
27 $(TR $(TD $(I character)) $(TD yes) $(TD yes) $(TD yes) $(TD $(MDASH)) $(TD $(MDASH)) $(TD $(MDASH)))
28 $(TR $(TD $(I string)) $(TD yes) $(TD $(MDASH)) $(TD $(MDASH)) $(TD $(MDASH)) $(TD $(MDASH)) $(TD yes))
29 $(TR $(TD $(I array)) $(TD yes) $(TD $(MDASH)) $(TD $(MDASH)) $(TD $(MDASH)) $(TD $(MDASH)) $(TD yes))
30 $(TR $(TD $(I associative array)) $(TD yes) $(TD $(MDASH)) $(TD $(MDASH)) $(TD $(MDASH)) $(TD $(MDASH)) $(TD yes))
31 )
32 
33 Below are highlighted examples on how these combinations are used
34 with $(LREF unformatValue), however, they apply for $(LREF
35 formattedRead) also
36 
37 Copyright: Copyright The D Language Foundation 2000-2013.
38 
39 License: $(HTTP boost.org/LICENSE_1_0.txt, Boost License 1.0).
40 
41 Authors: $(HTTP walterbright.com, Walter Bright), $(HTTP erdani.com,
42 Andrei Alexandrescu), and Kenji Hara
43 
44 Source: $(PHOBOSSRC std/format/read.d)
45  */
46 module std.format.read;
47 
48 /// Booleans
49 @safe pure unittest
50 {
51     import std.format.spec : singleSpec;
52 
53     auto str = "false";
54     auto spec = singleSpec("%s");
55     assert(str.unformatValue!bool(spec) == false);
56 
57     str = "1";
58     spec = singleSpec("%d");
59     assert(str.unformatValue!bool(spec) == true);
60 }
61 
62 /// Null values
63 @safe pure unittest
64 {
65     import std.format.spec : singleSpec;
66 
67     auto str = "null";
68     auto spec = singleSpec("%s");
69     assert(str.unformatValue!(typeof(null))(spec) == null);
70 }
71 
72 /// Integrals
73 @safe pure unittest
74 {
75     import std.format.spec : singleSpec;
76 
77     // signed decimal values
78     auto str = "123";
79     auto spec = singleSpec("%s");
80     assert(str.unformatValue!int(spec) == 123);
81 
82     // hexadecimal values
83     str = "ABC";
84     spec = singleSpec("%X");
85     assert(str.unformatValue!int(spec) == 2748);
86 
87     // octal values
88     str = "11610";
89     spec = singleSpec("%o");
90     assert(str.unformatValue!int(spec) == 5000);
91 
92     // raw read, depends on endianess
93     str = "\x75\x01";
94     spec = singleSpec("%r");
95     auto result = str.unformatValue!short(spec);
96     assert(result == 373 /* little endian */ || result == 29953 /* big endian */ );
97 }
98 
99 /// Floating point numbers
100 @safe pure unittest
101 {
102     import std.format.spec : singleSpec;
103     import std.math.operations : isClose;
104 
105     // natural notation
106     auto str = "123.456";
107     auto spec = singleSpec("%s");
108     assert(str.unformatValue!double(spec).isClose(123.456));
109 
110     // scientific notation
111     str = "1e17";
112     spec = singleSpec("%e");
113     assert(str.unformatValue!double(spec).isClose(1e17));
114 
115     // raw read, depends on endianess
116     str = "\x40\x00\x00\xBF";
117     spec = singleSpec("%r");
118     auto result = str.unformatValue!float(spec);
119     assert(isClose(result, -0.5) /* little endian */ || isClose(result, 2.0) /* big endian */ );
120 }
121 
122 /// Characters
123 @safe pure unittest
124 {
125     import std.format.spec : singleSpec;
126 
127     // only the first character is read
128     auto str = "abc";
129     auto spec = singleSpec("%s");
130     assert(str.unformatValue!char(spec) == 'a');
131 
132     // using a numerical format character treats the read number as unicode code point
133     str = "65";
134     spec = singleSpec("%d");
135     assert(str.unformatValue!char(spec) == 'A');
136 
137     str = "41";
138     spec = singleSpec("%x");
139     assert(str.unformatValue!char(spec) == 'A');
140 
141     str = "10003";
142     spec = singleSpec("%d");
143     assert(str.unformatValue!dchar(spec) == '✓');
144 }
145 
146 /// Arrays
147 @safe pure unittest
148 {
149     import std.format.spec : singleSpec;
150 
151     // string value
152     string str = "aaa";
153     auto spec = singleSpec("%s");
154     assert(str.unformatValue!(dchar[])(spec) == "aaa"d);
155 
156     // fixed size array with characters
157     str = "aaa";
158     spec = singleSpec("%s");
159     dchar[3] ret = ['a', 'a', 'a'];
160     assert(str.unformatValue!(dchar[3])(spec) == ret);
161 
162     // dynamic array
163     str = "[1, 2, 3, 4]";
164     spec = singleSpec("%s");
165     assert(str.unformatValue!(int[])(spec) == [1, 2, 3, 4]);
166 
167     // fixed size array with integers
168     str = "[1, 2, 3, 4]";
169     spec = singleSpec("%s");
170     int[4] ret2 = [1, 2, 3, 4];
171     assert(str.unformatValue!(int[4])(spec) == ret2);
172 
173     // compound specifiers can be used for more control
174     str = "1,2,3";
175     spec = singleSpec("%(%s,%)");
176     assert(str.unformatValue!(int[])(spec) == [1, 2, 3]);
177 
178     str = "cool";
179     spec = singleSpec("%(%c%)");
180     assert(str.unformatValue!(char[])(spec) == ['c', 'o', 'o', 'l']);
181 }
182 
183 /// Associative arrays
184 @safe pure unittest
185 {
186     import std.format.spec : singleSpec;
187 
188     // as single value
189     auto str = `["one": 1, "two": 2]`;
190     auto spec = singleSpec("%s");
191     assert(str.unformatValue!(int[string])(spec) == ["one": 1, "two": 2]);
192 
193     // with compound specifier for more control
194     str = "1/1, 2/4, 3/9";
195     spec = singleSpec("%(%d/%d%|, %)");
196     assert(str.unformatValue!(int[int])(spec) == [1: 1, 2: 4, 3: 9]);
197 }
198 
199 import std.format.spec : FormatSpec;
200 import std.format.internal.read;
201 import std.traits : isSomeString;
202 
203 /**
204 Reads an input range according to a format string and stores the read
205 values into its arguments.
206 
207 Format specifiers with format character $(B 'd'), $(B 'u') and $(B
208 'c') can take a $(B '*') parameter for skipping values.
209 
210 The second version of `formattedRead` takes the format string as
211 template argument. In this case, it is checked for consistency at
212 compile-time.
213 
214 Params:
215     r = an $(REF_ALTTEXT input range, isInputRange, std, range, primitives),
216         where the formatted input is read from
217     fmt = a $(MREF_ALTTEXT format string, std,format)
218     args = a variadic list of arguments where the read values are stored
219     Range = the type of the input range `r`
220     Char = the character type used for `fmt`
221     Args = a variadic list of types of the arguments
222 
223 Returns:
224     The number of variables filled. If the input range `r` ends early,
225     this number will be less than the number of variables provided.
226 
227 Throws:
228     A $(REF_ALTTEXT FormatException, FormatException, std, format)
229     if reading did not succeed.
230 
231 Note:
232     For backward compatibility the arguments `args` can be given as pointers
233     to that variable, but it is not recommended to do so, because this
234     option might be removed in the future.
235  */
formattedRead(Range,Char,Args...)236 uint formattedRead(Range, Char, Args...)(auto ref Range r, const(Char)[] fmt, auto ref Args args)
237 {
238     import std.format : enforceFmt;
239     import std.range.primitives : empty;
240     import std.traits : isPointer;
241     import std.typecons : isTuple;
242 
243     auto spec = FormatSpec!Char(fmt);
244     static if (!Args.length)
245     {
246         spec.readUpToNextSpec(r);
247         enforceFmt(spec.trailing.empty, "Trailing characters in formattedRead format string");
248         return 0;
249     }
250     else
251     {
252         enum hasPointer = isPointer!(typeof(args[0]));
253 
254         // The function below accounts for '*' == fields meant to be
255         // read and skipped
256         void skipUnstoredFields()
257         {
258             for (;;)
259             {
260                 spec.readUpToNextSpec(r);
261                 if (spec.width != spec.DYNAMIC) break;
262                 // must skip this field
263                 skipData(r, spec);
264             }
265         }
266 
267         skipUnstoredFields();
268         if (r.empty)
269         {
270             // Input is empty, nothing to read
271             return 0;
272         }
273 
274         static if (hasPointer)
275             alias A = typeof(*args[0]);
276         else
277             alias A = typeof(args[0]);
278 
279         static if (isTuple!A)
280         {
281             foreach (i, T; A.Types)
282             {
283                 static if (hasPointer)
284                     (*args[0])[i] = unformatValue!(T)(r, spec);
285                 else
286                     args[0][i] = unformatValue!(T)(r, spec);
287                 skipUnstoredFields();
288             }
289         }
290         else
291         {
292             static if (hasPointer)
293                 *args[0] = unformatValue!(A)(r, spec);
294             else
295                 args[0] = unformatValue!(A)(r, spec);
296         }
297         return 1 + formattedRead(r, spec.trailing, args[1 .. $]);
298     }
299 }
300 
301 /// ditto
302 uint formattedRead(alias fmt, Range, Args...)(auto ref Range r, auto ref Args args)
303 if (isSomeString!(typeof(fmt)))
304 {
305     import std.format : checkFormatException;
306 
307     alias e = checkFormatException!(fmt, Args);
308     static assert(!e, e);
309     return .formattedRead(r, fmt, args);
310 }
311 
312 ///
313 @safe pure unittest
314 {
315     string object;
316     char cmp;
317     int value;
318 
319     assert(formattedRead("angle < 36", "%s %c %d", object, cmp, value) == 3);
320     assert(object == "angle");
321     assert(cmp == '<');
322     assert(value == 36);
323 
324     // reading may end early:
325     assert(formattedRead("length >", "%s %c %d", object, cmp, value) == 2);
326     assert(object == "length");
327     assert(cmp == '>');
328     // value is not changed:
329     assert(value == 36);
330 }
331 
332 /// The format string can be checked at compile-time:
333 @safe pure unittest
334 {
335     string a;
336     int b;
337     double c;
338 
339     assert("hello!124:34.5".formattedRead!"%s!%s:%s"(a, b, c) == 3);
340     assert(a == "hello");
341     assert(b == 124);
342     assert(c == 34.5);
343 }
344 
345 /// Skipping values
346 @safe pure unittest
347 {
348     string item;
349     double amount;
350 
351     assert("orange: (12%) 15.25".formattedRead("%s: (%*d%%) %f", item, amount) == 2);
352     assert(item == "orange");
353     assert(amount == 15.25);
354 
355     // can also be used with tuples
356     import std.typecons : Tuple;
357 
358     Tuple!(int, float) t;
359     char[] line = "1 7643 2.125".dup;
360     formattedRead(line, "%s %*u %s", t);
361     assert(t[0] == 1 && t[1] == 2.125);
362 }
363 
364 @safe unittest
365 {
366     import std.math.operations : isClose;
367     import std.math.traits : isNaN;
368     import std.range.primitives : empty;
369 
370     string s = " 1.2 3.4 ";
371     double x, y, z;
372     assert(formattedRead(s, " %s %s %s ", x, y, z) == 2);
373     assert(s.empty);
374     assert(isClose(x, 1.2));
375     assert(isClose(y, 3.4));
376     assert(isNaN(z));
377 }
378 
379 // for backwards compatibility
380 @safe pure unittest
381 {
382     string s = "hello!124:34.5";
383     string a;
384     int b;
385     double c;
386     formattedRead(s, "%s!%s:%s", &a, &b, &c);
387     assert(a == "hello" && b == 124 && c == 34.5);
388 
389     // mix pointers and auto-ref
390     s = "world!200:42.25";
391     formattedRead(s, "%s!%s:%s", a, &b, &c);
392     assert(a == "world" && b == 200 && c == 42.25);
393 
394     s = "world1!201:42.5";
395     formattedRead(s, "%s!%s:%s", &a, &b, c);
396     assert(a == "world1" && b == 201 && c == 42.5);
397 
398     s = "world2!202:42.75";
399     formattedRead(s, "%s!%s:%s", a, b, &c);
400     assert(a == "world2" && b == 202 && c == 42.75);
401 }
402 
403 // for backwards compatibility
404 @safe pure unittest
405 {
406     import std.math.operations : isClose;
407     import std.math.traits : isNaN;
408     import std.range.primitives : empty;
409 
410     string s = " 1.2 3.4 ";
411     double x, y, z;
412     assert(formattedRead(s, " %s %s %s ", &x, &y, &z) == 2);
413     assert(s.empty);
414     assert(isClose(x, 1.2));
415     assert(isClose(y, 3.4));
416     assert(isNaN(z));
417 }
418 
419 @safe unittest
420 {
421     string s = "hello!124:34.5";
422     string a;
423     int b;
424     double c;
425     formattedRead(s, "%s!%s:%s", &a, &b, &c);
426     assert(a == "hello" && b == 124 && c == 34.5);
427 }
428 
429 @safe pure unittest
430 {
431     string line;
432 
433     bool f1;
434 
435     line = "true";
436     formattedRead(line, "%s", &f1);
437     assert(f1);
438 
439     line = "TrUE";
440     formattedRead(line, "%s", &f1);
441     assert(f1);
442 
443     line = "false";
444     formattedRead(line, "%s", &f1);
445     assert(!f1);
446 
447     line = "fALsE";
448     formattedRead(line, "%s", &f1);
449     assert(!f1);
450 
451     line = "1";
452     formattedRead(line, "%d", &f1);
453     assert(f1);
454 
455     line = "-1";
456     formattedRead(line, "%d", &f1);
457     assert(f1);
458 
459     line = "0";
460     formattedRead(line, "%d", &f1);
461     assert(!f1);
462 
463     line = "-0";
464     formattedRead(line, "%d", &f1);
465     assert(!f1);
466 }
467 
468 @safe pure unittest
469 {
470     union B
471     {
472         char[int.sizeof] untyped;
473         int typed;
474     }
475 
476     B b;
477     b.typed = 5;
478     char[] input = b.untyped[];
479     int witness;
480     formattedRead(input, "%r", &witness);
481     assert(witness == b.typed);
482 }
483 
484 @safe pure unittest
485 {
486     union A
487     {
488         char[float.sizeof] untyped;
489         float typed;
490     }
491 
492     A a;
493     a.typed = 5.5;
494     char[] input = a.untyped[];
495     float witness;
496     formattedRead(input, "%r", &witness);
497     assert(witness == a.typed);
498 }
499 
500 @safe pure unittest
501 {
502     import std.typecons : Tuple;
503 
504     char[] line = "1 2".dup;
505     int a, b;
506     formattedRead(line, "%s %s", &a, &b);
507     assert(a == 1 && b == 2);
508 
509     line = "10 2 3".dup;
510     formattedRead(line, "%d ", &a);
511     assert(a == 10);
512     assert(line == "2 3");
513 
514     Tuple!(int, float) t;
515     line = "1 2.125".dup;
516     formattedRead(line, "%d %g", &t);
517     assert(t[0] == 1 && t[1] == 2.125);
518 
519     line = "1 7643 2.125".dup;
520     formattedRead(line, "%s %*u %s", &t);
521     assert(t[0] == 1 && t[1] == 2.125);
522 }
523 
524 @safe pure unittest
525 {
526     string line;
527 
528     char c1, c2;
529 
530     line = "abc";
531     formattedRead(line, "%s%c", &c1, &c2);
532     assert(c1 == 'a' && c2 == 'b');
533     assert(line == "c");
534 }
535 
536 @safe pure unittest
537 {
538     string line;
539 
540     line = "[1,2,3]";
541     int[] s1;
542     formattedRead(line, "%s", &s1);
543     assert(s1 == [1,2,3]);
544 }
545 
546 @safe pure unittest
547 {
548     string line;
549 
550     line = "[1,2,3]";
551     int[] s1;
552     formattedRead(line, "[%(%s,%)]", &s1);
553     assert(s1 == [1,2,3]);
554 
555     line = `["hello", "world"]`;
556     string[] s2;
557     formattedRead(line, "[%(%s, %)]", &s2);
558     assert(s2 == ["hello", "world"]);
559 
560     line = "123 456";
561     int[] s3;
562     formattedRead(line, "%(%s %)", &s3);
563     assert(s3 == [123, 456]);
564 
565     line = "h,e,l,l,o; w,o,r,l,d";
566     string[] s4;
567     formattedRead(line, "%(%(%c,%); %)", &s4);
568     assert(s4 == ["hello", "world"]);
569 }
570 
571 @safe pure unittest
572 {
573     import std.exception : assertThrown;
574 
575     string line;
576 
577     int[4] sa1;
578     line = `[1,2,3,4]`;
579     formattedRead(line, "%s", &sa1);
580     assert(sa1 == [1,2,3,4]);
581 
582     int[4] sa2;
583     line = `[1,2,3]`;
584     assertThrown(formattedRead(line, "%s", &sa2));
585 
586     int[4] sa3;
587     line = `[1,2,3,4,5]`;
588     assertThrown(formattedRead(line, "%s", &sa3));
589 }
590 
591 @safe pure unittest
592 {
593     import std.exception : assertThrown;
594     import std.format : FormatException;
595 
596     string input;
597 
598     int[4] sa1;
599     input = `[1,2,3,4]`;
600     formattedRead(input, "[%(%s,%)]", &sa1);
601     assert(sa1 == [1,2,3,4]);
602 
603     int[4] sa2;
604     input = `[1,2,3]`;
605     assertThrown!FormatException(formattedRead(input, "[%(%s,%)]", &sa2));
606 }
607 
608 @safe pure unittest
609 {
610     string line;
611 
612     string s1, s2;
613 
614     line = "hello, world";
615     formattedRead(line, "%s", &s1);
616     assert(s1 == "hello, world", s1);
617 
618     line = "hello, world;yah";
619     formattedRead(line, "%s;%s", &s1, &s2);
620     assert(s1 == "hello, world", s1);
621     assert(s2 == "yah", s2);
622 
623     line = `['h','e','l','l','o']`;
624     string s3;
625     formattedRead(line, "[%(%s,%)]", &s3);
626     assert(s3 == "hello");
627 
628     line = `"hello"`;
629     string s4;
630     formattedRead(line, "\"%(%c%)\"", &s4);
631     assert(s4 == "hello");
632 }
633 
634 @safe pure unittest
635 {
636     string line;
637 
638     string[int] aa1;
639     line = `[1:"hello", 2:"world"]`;
640     formattedRead(line, "%s", &aa1);
641     assert(aa1 == [1:"hello", 2:"world"]);
642 
643     int[string] aa2;
644     line = `{"hello"=1; "world"=2}`;
645     formattedRead(line, "{%(%s=%s; %)}", &aa2);
646     assert(aa2 == ["hello":1, "world":2]);
647 
648     int[string] aa3;
649     line = `{[hello=1]; [world=2]}`;
650     formattedRead(line, "{%([%(%c%)=%s]%|; %)}", &aa3);
651     assert(aa3 == ["hello":1, "world":2]);
652 }
653 
654 // test rvalue using
655 @safe pure unittest
656 {
657     string[int] aa1;
658     formattedRead!("%s")(`[1:"hello", 2:"world"]`, aa1);
659     assert(aa1 == [1:"hello", 2:"world"]);
660 
661     int[string] aa2;
662     formattedRead(`{"hello"=1; "world"=2}`, "{%(%s=%s; %)}", aa2);
663     assert(aa2 == ["hello":1, "world":2]);
664 }
665 
666 /**
667 Reads a value from the given _input range and converts it according to a
668 format specifier.
669 
670 Params:
671     input = the $(REF_ALTTEXT input range, isInputRange, std, range, primitives),
672             to read from
673     spec = a $(MREF_ALTTEXT format string, std,format)
674     T = type to return
675     Range = the type of the input range `input`
676     Char = the character type used for `spec`
677 
678 Returns:
679     A value from `input` of type `T`.
680 
681 Throws:
682     A $(REF_ALTTEXT FormatException, FormatException, std, format)
683     if reading did not succeed.
684 
685 See_Also:
686     $(REF parse, std, conv) and $(REF to, std, conv)
687  */
unformatValue(T,Range,Char)688 T unformatValue(T, Range, Char)(ref Range input, scope const ref FormatSpec!Char spec)
689 {
690     return unformatValueImpl!T(input, spec);
691 }
692 
693 ///
694 @safe pure unittest
695 {
696     import std.format.spec : singleSpec;
697 
698     string s = "42";
699     auto spec = singleSpec("%s");
700     assert(unformatValue!int(s, spec) == 42);
701 }
702 
703 // https://issues.dlang.org/show_bug.cgi?id=7241
704 @safe pure unittest
705 {
706     string input = "a";
707     auto spec = FormatSpec!char("%s");
708     spec.readUpToNextSpec(input);
709     auto result = unformatValue!(dchar[1])(input, spec);
710     assert(result[0] == 'a');
711 }
712 
713 // https://issues.dlang.org/show_bug.cgi?id=20393
714 @safe pure unittest
715 {
716     import std.exception : assertThrown;
717     string str = "foo 12a-buzz";
718     string a, c;
719     int b;
720     assertThrown(formattedRead(str, "%s %d-%s", &a, &b, &c));
721 }
722 
723 // https://issues.dlang.org/show_bug.cgi?id=18051
724 @safe pure unittest
725 {
726     import std.format : format;
727 
728     enum Op { lt, gt, eq }
729 
730     auto s = format!"%s"(Op.lt);
731     Op op;
732     assert(formattedRead!"%s"(s, op) == 1);
733     assert(op == Op.lt);
734 }
735