1 // Written in the D programming language.
2 
3 /**
4 This package provides string formatting functionality using
5 `printf` style format strings.
6 
7 $(BOOKTABLE ,
8 $(TR $(TH Submodule) $(TH Function Name) $(TH Description))
9 $(TR
10     $(TD $(I package))
11     $(TD $(LREF format))
12     $(TD Converts its arguments according to a format string into a string.)
13 )
14 $(TR
15     $(TD $(I package))
16     $(TD $(LREF sformat))
17     $(TD Converts its arguments according to a format string into a buffer.)
18 )
19 $(TR
20     $(TD $(I package))
21     $(TD $(LREF FormatException))
22     $(TD Signals a problem while formatting.)
23 )
24 $(TR
25     $(TD $(MREF_ALTTEXT $(D write), std, format, write))
26     $(TD $(REF_ALTTEXT $(D formattedWrite), formattedWrite, std, format, write))
27     $(TD Converts its arguments according to a format string and writes
28          the result to an output range.)
29 )
30 $(TR
31     $(TD $(MREF_ALTTEXT $(D write), std, format, write))
32     $(TD $(REF_ALTTEXT $(D formatValue), formatValue, std, format, write))
33     $(TD Formats a value of any type according to a format specifier and
34          writes the result to an output range.)
35 )
36 $(TR
37     $(TD $(MREF_ALTTEXT $(D read), std, format, read))
38     $(TD $(REF_ALTTEXT $(D formattedRead), formattedRead, std, format, read))
39     $(TD Reads an input range according to a format string and stores the read
40          values into its arguments.)
41 )
42 $(TR
43     $(TD $(MREF_ALTTEXT $(D read), std, format, read))
44     $(TD $(REF_ALTTEXT $(D unformatValue), unformatValue, std, format, read))
45     $(TD Reads a value from the given input range and converts it according to
46          a format specifier.)
47 )
48 $(TR
49     $(TD $(MREF_ALTTEXT $(D spec), std, format, spec))
50     $(TD $(REF_ALTTEXT $(D FormatSpec), FormatSpec, std, format, spec))
51     $(TD A general handler for format strings.)
52 )
53 $(TR
54     $(TD $(MREF_ALTTEXT $(D spec), std, format, spec))
55     $(TD $(REF_ALTTEXT $(D singleSpec), singleSpec, std, format, spec))
56     $(TD Helper function that returns a `FormatSpec` for a single format specifier.)
57 ))
58 
59 Limitation: This package does not support localization, but
60     adheres to the rounding mode of the floating point unit, if
61     available.
62 
63 $(SECTION3 Format Strings)
64 
65 The functions contained in this package use $(I format strings). A
66 format string describes the layout of another string for reading or
67 writing purposes. A format string is composed of normal text
68 interspersed with $(I format specifiers). A format specifier starts
69 with a percentage sign $(B '%'), optionally followed by one or more
70 $(I parameters) and ends with a $(I format indicator). A format
71 indicator may be a simple $(I format character) or a $(I compound
72 indicator).
73 
74 $(I Format strings) are composed according to the following grammar:
75 
76 $(PRE
77 $(I FormatString):
78     $(I FormatStringItem) $(I FormatString)
79 $(I FormatStringItem):
80     $(I Character)
81     $(I FormatSpecifier)
82 $(I FormatSpecifier):
83     $(B '%') $(I Parameters) $(I FormatIndicator)
84 
85 $(I FormatIndicator):
86     $(I FormatCharacter)
87     $(I CompoundIndicator)
88 $(I FormatCharacter):
89     $(I see remark below)
90 $(I CompoundIndicator):
91     $(B '$(LPAREN)') $(I FormatString) $(B '%$(RPAREN)')
92     $(B '$(LPAREN)') $(I FormatString) $(B '%|') $(I Delimiter) $(B '%$(RPAREN)')
93 $(I Delimiter)
94     $(I empty)
95     $(I Character) $(I Delimiter)
96 
97 $(I Parameters):
98     $(I Position) $(I Flags) $(I Width) $(I Precision) $(I Separator)
99 $(I Position):
100     $(I empty)
101     $(I Integer) $(B '$')
102     $(I Integer) $(B ':') $(I Integer) $(B '$')
103     $(I Integer) $(B ':') $(B '$')
104 $(I Flags):
105     $(I empty)
106     $(I Flag) $(I Flags)
107 $(I Flag):
108     $(B '-')|$(B '+')|$(B ' ')|$(B '0')|$(B '#')|$(B '=')
109 $(I Width):
110     $(I OptionalPositionalInteger)
111 $(I Precision):
112     $(I empty)
113     $(B '.') $(I OptionalPositionalInteger)
114 $(I Separator):
115     $(I empty)
116     $(B ',') $(I OptionalInteger)
117     $(B ',') $(I OptionalInteger) $(B '?')
118 $(I OptionalInteger):
119     $(I empty)
120     $(I Integer)
121     $(B '*')
122 $(I OptionalPositionalInteger):
123     $(I OptionalInteger)
124     $(B '*') $(I Integer) $(B '$')
125 
126 $(I Character)
127     $(B '%%')
128     $(I AnyCharacterExceptPercent)
129 $(I Integer):
130     $(I NonZeroDigit) $(I Digits)
131 $(I Digits):
132     $(I empty)
133     $(I Digit) $(I Digits)
134 $(I NonZeroDigit):
135     $(B '1')|$(B '2')|$(B '3')|$(B '4')|$(B '5')|$(B '6')|$(B '7')|$(B '8')|$(B '9')
136 $(I Digit):
137     $(B '0')|$(B '1')|$(B '2')|$(B '3')|$(B '4')|$(B '5')|$(B '6')|$(B '7')|$(B '8')|$(B '9')
138 )
139 
140 Note: $(I FormatCharacter) is unspecified. It can be any character
141 that has no other purpose in this grammar, but it is
142 recommended to assign (lower- and uppercase) letters.
143 
144 Note: The $(I Parameters) of a $(I CompoundIndicator) are currently
145 limited to a $(B '-') flag.
146 
147 $(SECTION4 Format Indicator)
148 
149 The $(I format indicator) can either be a single character or an
150 expression surrounded by $(B %\() and $(B %\)). It specifies the
151 basic manner in which a value will be formatted and is the minimum
152 requirement to format a value.
153 
154 The following characters can be used as $(I format characters):
155 
156 $(BOOKTABLE ,
157    $(TR $(TH FormatCharacter) $(TH Semantics))
158    $(TR $(TD $(B 's'))
159         $(TD To be formatted in a human readable format.
160              Can be used with all types.))
161    $(TR $(TD $(B 'c'))
162         $(TD To be formatted as a character.))
163    $(TR $(TD $(B 'd'))
164         $(TD To be formatted as a signed decimal integer.))
165    $(TR $(TD $(B 'u'))
166         $(TD To be formatted as a decimal image of the underlying bit representation.))
167    $(TR $(TD $(B 'b'))
168         $(TD To be formatted as a binary image of the underlying bit representation.))
169    $(TR $(TD $(B 'o'))
170         $(TD To be formatted as an octal image of the underlying bit representation.))
171    $(TR $(TD $(B 'x') / $(B 'X'))
172         $(TD To be formatted as a hexadecimal image of the underlying bit representation.))
173    $(TR $(TD $(B 'e') / $(B 'E'))
174         $(TD To be formatted as a real number in decimal scientific notation.))
175    $(TR $(TD $(B 'f') / $(B 'F'))
176         $(TD To be formatted as a real number in decimal natural notation.))
177    $(TR $(TD $(B 'g') / $(B 'G'))
178         $(TD To be formatted as a real number in decimal short notation.
179              Depending on the number, a scientific notation or
180              a natural notation is used.))
181    $(TR $(TD $(B 'a') / $(B 'A'))
182         $(TD To be formatted as a real number in hexadecimal scientific notation.))
183    $(TR $(TD $(B 'r'))
184         $(TD To be formatted as raw bytes.
185              The output may not be printable and depends on endianness.))
186 )
187 
188 The $(I compound indicator) can be used to describe compound types
189 like arrays or structs in more detail. A compound type is enclosed
190 within $(B '%\(') and $(B '%\)'). The enclosed sub-format string is
191 applied to individual elements. The trailing portion of the
192 sub-format string following the specifier for the element is
193 interpreted as the delimiter, and is therefore omitted following the
194 last element. The $(B '%|') specifier may be used to explicitly
195 indicate the start of the delimiter, so that the preceding portion of
196 the string will be included following the last element.
197 
198 The $(I format string) inside of the $(I compound indicator) should
199 contain exactly one $(I format specifier) (two in case of associative
200 arrays), which specifies the formatting mode of the elements of the
201 compound type. This $(I format specifier) can be a $(I compound
202 indicator) itself.
203 
204 Note: Inside a $(I compound indicator), strings and characters are
205 escaped automatically. To avoid this behavior, use `"%-$(LPAREN)"`
206 instead of `"%$(LPAREN)"`.
207 
208 $(SECTION4 Flags)
209 
210 There are several flags that affect the outcome of the formatting.
211 
212 $(BOOKTABLE ,
213    $(TR $(TH Flag) $(TH Semantics))
214    $(TR $(TD $(B '-'))
215         $(TD When the formatted result is shorter then the value
216              given by the width parameter, the output is right
217              justified. With the $(B '-') flag this is changed
218              to left justification.
219 
220              There are two exceptions where the $(B '-') flag has a
221              different meaning: (1) with $(B 'r') it denotes to use little
222              endian and (2) in case of a compound indicator it means that
223              no special handling of the members is applied.))
224    $(TR $(TD $(B '='))
225         $(TD When the formatted result is shorter then the value
226              given by the width parameter, the output is centered.
227              If the central position is not possible it is moved slightly
228              to the right. In this case, if $(B '-') flag is present in
229              addition to the $(B '=') flag, it is moved slightly to the left.))
230    $(TR $(TD $(B '+') / $(B ' '))
231         $(TD Applies to numerical values. By default, positive numbers are not
232              formatted to include the `+` sign. With one of these two flags present,
233              positive numbers are preceded by a plus sign or a space.
234              When both flags are present, a plus sign is used.
235 
236              In case of $(B 'r'), a big endian format is used.))
237    $(TR $(TD $(B '0'))
238         $(TD Is applied to numerical values that are printed right justified.
239              If the zero flag is present, the space left to the number is
240              filled with zeros instead of spaces.))
241    $(TR $(TD $(B '#'))
242         $(TD Denotes that an alternative output must be used. This depends on the type
243              to be formatted and the $(I format character) used. See the
244              sections below for more information.))
245 )
246 
247 $(SECTION4 Width$(COMMA) Precision and Separator)
248 
249 The $(I width) parameter specifies the minimum width of the result.
250 
251 The meaning of $(I precision) depends on the format indicator. For
252 integers it denotes the minimum number of digits printed, for
253 real numbers it denotes the number of fractional digits and for
254 strings and compound types it denotes the maximum number of elements
255 that are included in the output.
256 
257 A $(I separator) is used for formatting numbers. If it is specified,
258 the output is divided into chunks of three digits, separated by a $(B
259 ','). The number of digits in a chunk can be given explicitly by
260 providing a number or a $(B '*') after the $(B ',').
261 
262 In all three cases the number of digits can be replaced by a $(B
263 '*'). In this scenario, the next argument is used as the number of
264 digits. If the argument is a negative number, the $(I precision) and
265 $(I separator) parameters are considered unspecified. For $(I width),
266 the absolute value is used and the $(B '-') flag is set.
267 
268 The $(I separator) can also be followed by a $(B '?'). In that case,
269 an additional argument is used to specify the symbol that should be
270 used to separate the chunks.
271 
272 $(SECTION4 Position)
273 
274 By default, the arguments are processed in the provided order. With
275 the $(I position) parameter it is possible to address arguments
276 directly. It is also possible to denote a series of arguments with
277 two numbers separated by $(B ':'), that are all processed in the same
278 way. The second number can be omitted. In that case the series ends
279 with the last argument.
280 
281 It's also possible to use positional arguments for $(I width), $(I
282 precision) and $(I separator) by adding a number and a $(B
283 '$(DOLLAR)') after the $(B '*').
284 
285 $(SECTION4 Types)
286 
287 This section describes the result of combining types with format
288 characters. It is organized in 2 subsections: a list of general
289 information regarding the formatting of types in the presence of
290 format characters and a table that contains details for every
291 available combination of type and format character.
292 
293 When formatting types, the following rules apply:
294 
295 $(UL
296   $(LI If the format character is upper case, the resulting string will
297        be formatted using upper case letters.)
298   $(LI The default precision for floating point numbers is 6 digits.)
299   $(LI Rounding of floating point numbers adheres to the rounding mode
300        of the floating point unit, if available.)
301   $(LI The floating point values `NaN` and `Infinity` are formatted as
302        `nan` and `inf`, possibly preceded by $(B '+') or $(B '-') sign.)
303   $(LI Formatting reals is only supported for 64 bit reals and 80 bit reals.
304        All other reals are cast to double before they are formatted. This will
305        cause the result to be `inf` for very large numbers.)
306   $(LI Characters and strings formatted with the $(B 's') format character
307        inside of compound types are surrounded by single and double quotes
308        and unprintable characters are escaped. To avoid this, a $(B '-')
309        flag can be specified for the compound specifier
310        $(LPAREN)e.g. `"%-$(LPAREN)%s%$(RPAREN)"` instead of `"%$(LPAREN)%s%$(RPAREN)"` $(RPAREN).)
311   $(LI Structs, unions, classes and interfaces are formatted by calling a
312        `toString` method if available.
313        See $(MREF_ALTTEXT $(D module std.format.write), std, format, write) for more
314        details.)
315   $(LI Only part of these combinations can be used for reading. See
316        $(MREF_ALTTEXT $(D module std.format.read), std, format, read) for more
317        detailed information.)
318 )
319 
320 This table contains descriptions for every possible combination of
321 type and format character:
322 
323 $(BOOKTABLE ,
324    $(TR $(THMINWIDTH Type) $(THMINWIDTH Format Character) $(TH Formatted as...))
325    $(TR $(MULTIROW_CELL 1, `null`)
326         $(TD $(B 's'))
327             $(TD `null`)
328    )
329    $(TR $(MULTIROW_CELL 3, `bool`)
330         $(TD $(B 's'))
331             $(TD `false` or `true`)
332    )
333    $(TR $(TD $(B 'b'), $(B 'd'), $(B 'o'), $(B 'u'), $(B 'x'), $(B 'X'))
334             $(TD As the integrals 0 or 1 with the same format character.
335 
336             $(I Please note, that $(B 'o') and $(B 'x') with $(B '#') flag
337             might produce unexpected results due to special handling of
338             the value 0.))
339    )
340    $(TR $(TD $(B 'r'))
341             $(TD `\0` or `\1`)
342    )
343    $(TR $(MULTIROW_CELL 4, $(I Integral))
344         $(TD $(B 's'), $(B 'd'))
345             $(TD A signed decimal number. The $(B '#') flag is ignored.)
346    )
347    $(TR $(TD $(B 'b'), $(B 'o'), $(B 'u'), $(B 'x'), $(B 'X'))
348             $(TD An unsigned binary, decimal, octal or hexadecimal number.
349 
350                  In case of $(B 'o') and $(B 'x'), the $(B '#') flag
351                  denotes that the number must be preceded by `0` and `0x`, with
352                  the exception of the value 0, where this does not apply. For
353                  $(B 'b') and $(B 'u') the $(B '#') flag has no effect.)
354    )
355    $(TR $(TD $(B 'e'), $(B 'E'), $(B 'f'), $(B 'F'), $(B 'g'), $(B 'G'), $(B 'a'), $(B 'A'))
356             $(TD As a floating point value with the same specifier.
357 
358                  Default precision is large enough to add all digits
359                  of the integral value.
360 
361                  In case of ($B 'a') and $(B 'A'), the integral digit can be
362                  any hexadecimal digit.
363                )
364    )
365    $(TR $(TD $(B 'r'))
366             $(TD Characters taken directly from the binary representation.)
367    )
368    $(TR $(MULTIROW_CELL 5, $(I Floating Point))
369         $(TD $(B 'e'), $(B 'E'))
370             $(TD Scientific notation: Exactly one integral digit followed by a dot
371                  and fractional digits, followed by the exponent.
372                  The exponent is formatted as $(B 'e') followed by
373                  a $(B '+') or $(B '-') sign, followed by at least
374                  two digits.
375 
376                  When there are no fractional digits and the $(B '#') flag
377                  is $(I not) present, the dot is omitted.)
378    )
379    $(TR $(TD $(B 'f'), $(B 'F'))
380             $(TD Natural notation: Integral digits followed by a dot and
381                  fractional digits.
382 
383                  When there are no fractional digits and the $(B '#') flag
384                  is $(I not) present, the dot is omitted.
385 
386                  $(I Please note: the difference between $(B 'f') and $(B 'F')
387                  is only visible for `NaN` and `Infinity`.))
388    )
389    $(TR $(TD $(B 's'), $(B 'g'), $(B 'G'))
390             $(TD Short notation: If the absolute value is larger than `10 ^^ precision`
391                  or smaller than `0.0001`, the scientific notation is used.
392                  If not, the natural notation is applied.
393 
394                  In both cases $(I precision) denotes the count of all digits, including
395                  the integral digits. Trailing zeros (including a trailing dot) are removed.
396 
397                  If $(B '#') flag is present, trailing zeros are not removed.)
398    )
399    $(TR $(TD $(B 'a'), $(B 'A'))
400             $(TD Hexadecimal scientific notation: `0x` followed by `1`
401                  (or `0` in case of value zero or denormalized number)
402                  followed by a dot, fractional digits in hexadecimal
403                  notation and an exponent. The exponent is build by `p`,
404                  followed by a sign and the exponent in $(I decimal) notation.
405 
406                  When there are no fractional digits and the $(B '#') flag
407                  is $(I not) present, the dot is omitted.)
408    )
409    $(TR $(TD $(B 'r'))
410             $(TD Characters taken directly from the binary representation.)
411    )
412    $(TR $(MULTIROW_CELL 3, $(I Character))
413         $(TD $(B 's'), $(B 'c'))
414             $(TD As the character.
415 
416                  Inside of a compound indicator $(B 's') is treated differently: The
417                  character is surrounded by single quotes and non printable
418                  characters are escaped. This can be avoided by preceding
419                  the compound indicator with a $(B '-') flag
420                  $(LPAREN)e.g. `"%-$(LPAREN)%s%$(RPAREN)"`$(RPAREN).)
421    )
422    $(TR $(TD $(B 'b'), $(B 'd'), $(B 'o'), $(B 'u'), $(B 'x'), $(B 'X'))
423             $(TD As the integral that represents the character.)
424    )
425    $(TR $(TD $(B 'r'))
426             $(TD Characters taken directly from the binary representation.)
427    )
428    $(TR $(MULTIROW_CELL 3, $(I String))
429         $(TD $(B 's'))
430             $(TD The sequence of characters that form the string.
431 
432                  Inside of a compound indicator the string is surrounded by double quotes
433                  and non printable characters are escaped. This can be avoided
434                  by preceding the compound indicator with a $(B '-') flag
435                  $(LPAREN)e.g. `"%-$(LPAREN)%s%$(RPAREN)"`$(RPAREN).)
436    )
437    $(TR $(TD $(B 'r'))
438             $(TD The sequence of characters, each formatted with $(B 'r').)
439    )
440    $(TR $(TD compound)
441             $(TD As an array of characters.)
442    )
443    $(TR $(MULTIROW_CELL 3, $(I Array))
444         $(TD $(B 's'))
445             $(TD When the elements are characters, the array is formatted as
446                  a string. In all other cases the array is surrounded by square brackets
447                  and the elements are separated by a comma and a space. If the elements
448                  are strings, they are surrounded by double quotes and non
449                  printable characters are escaped.)
450    )
451    $(TR $(TD $(B 'r'))
452             $(TD The sequence of the elements, each formatted with $(B 'r').)
453    )
454    $(TR $(TD compound)
455             $(TD The sequence of the elements, each formatted according to the specifications
456                  given inside of the compound specifier.)
457    )
458    $(TR $(MULTIROW_CELL 2, $(I Associative Array))
459         $(TD $(B 's'))
460             $(TD As a sequence of the elements in unpredictable order. The output is
461                  surrounded by square brackets. The elements are separated by a
462                  comma and a space. The elements are formatted as `key:value`.)
463    )
464    $(TR $(TD compound)
465             $(TD As a sequence of the elements in unpredictable order. Each element
466                  is formatted according to the specifications given inside of the
467                  compound specifier. The first specifier is used for formatting
468                  the key and the second specifier is used for formatting the value.
469                  The order can be changed with positional arguments. For example
470                  `"%(%2$s (%1$s), %)"` will write the value, followed by the key in
471                  parenthesis.)
472    )
473    $(TR $(MULTIROW_CELL 2, $(I Enum))
474         $(TD $(B 's'))
475             $(TD The name of the value. If the name is not available, the base value
476                  is used, preceeded by a cast.)
477    )
478    $(TR $(TD All, but $(B 's'))
479             $(TD Enums can be formatted with all format characters that can be used
480                  with the base value. In that case they are formatted like the base value.)
481    )
482    $(TR $(MULTIROW_CELL 3, $(I Input Range))
483         $(TD $(B 's'))
484             $(TD When the elements of the range are characters, they are written like a string.
485                  In all other cases, the elements are enclosed by square brackets and separated
486                  by a comma and a space.)
487    )
488    $(TR $(TD $(B 'r'))
489             $(TD The sequence of the elements, each formatted with $(B 'r').)
490    )
491    $(TR $(TD compound)
492             $(TD The sequence of the elements, each formatted according to the specifications
493                  given inside of the compound specifier.)
494    )
495    $(TR $(MULTIROW_CELL 1, $(I Struct))
496         $(TD $(B 's'))
497             $(TD When the struct has neither an applicable `toString`
498                  nor is an input range, it is formatted as follows:
499                  `StructType(field1, field2, ...)`.)
500    )
501    $(TR $(MULTIROW_CELL 1, $(I Class))
502         $(TD $(B 's'))
503             $(TD When the class has neither an applicable `toString`
504                  nor is an input range, it is formatted as the
505                  fully qualified name of the class.)
506    )
507    $(TR $(MULTIROW_CELL 1, $(I Union))
508         $(TD $(B 's'))
509             $(TD When the union has neither an applicable `toString`
510                  nor is an input range, it is formatted as its base name.)
511    )
512    $(TR $(MULTIROW_CELL 2, $(I Pointer))
513         $(TD $(B 's'))
514             $(TD A null pointer is formatted as 'null'. All other pointers are
515                  formatted as hexadecimal numbers with the format character $(B 'X').)
516    )
517    $(TR $(TD $(B 'x'), $(B 'X'))
518             $(TD Formatted as a hexadecimal number.)
519    )
520    $(TR $(MULTIROW_CELL 3, $(I SIMD vector))
521         $(TD $(B 's'))
522             $(TD The array is surrounded by square brackets
523                  and the elements are separated by a comma and a space.)
524    )
525    $(TR $(TD $(B 'r'))
526             $(TD The sequence of the elements, each formatted with $(B 'r').)
527    )
528    $(TR $(TD compound)
529             $(TD The sequence of the elements, each formatted according to the specifications
530                  given inside of the compound specifier.)
531    )
532    $(TR $(MULTIROW_CELL 1, $(I Delegate))
533         $(TD $(B 's'), $(B 'r'), compound)
534             $(TD As the `.stringof` of this delegate treated as a string.
535 
536                  $(I Please note: The implementation is currently buggy
537                  and its use is discouraged.))
538    )
539 )
540 
541 Copyright: Copyright The D Language Foundation 2000-2021.
542 
543 Macros:
544 SUBREF = $(REF_ALTTEXT $2, $2, std, format, $1)$(NBSP)
545 MULTIROW_CELL = <td rowspan="$1">$+</td>
546 THMINWIDTH = <th scope="col" width="20%">$0</th>
547 
548 License: $(HTTP boost.org/LICENSE_1_0.txt, Boost License 1.0).
549 
550 Authors: $(HTTP walterbright.com, Walter Bright), $(HTTP erdani.com,
551 Andrei Alexandrescu), and Kenji Hara
552 
553 Source: $(PHOBOSSRC std/format.d)
554  */
555 module std.format;
556 
557 /// Simple use:
558 @safe unittest
559 {
560     // Easiest way is to use `%s` everywhere:
561     assert(format("I got %s %s for %s euros.", 30, "eggs", 5.27) == "I got 30 eggs for 5.27 euros.");
562 
563     // Other format characters provide more control:
564     assert(format("I got %b %(%X%) for %f euros.", 30, "eggs", 5.27) == "I got 11110 65676773 for 5.270000 euros.");
565 }
566 
567 /// Compound specifiers allow formatting arrays and other compound types:
568 @safe unittest
569 {
570 /*
571 The trailing end of the sub-format string following the specifier for
572 each item is interpreted as the array delimiter, and is therefore
573 omitted following the last array item:
574  */
575     assert(format("My items are %(%s %).", [1,2,3]) == "My items are 1 2 3.");
576     assert(format("My items are %(%s, %).", [1,2,3]) == "My items are 1, 2, 3.");
577 
578 /*
579 The "%|" delimiter specifier may be used to indicate where the
580 delimiter begins, so that the portion of the format string prior to
581 it will be retained in the last array element:
582  */
583     assert(format("My items are %(-%s-%|, %).", [1,2,3]) == "My items are -1-, -2-, -3-.");
584 
585 /*
586 These compound format specifiers may be nested in the case of a
587 nested array argument:
588  */
589     auto mat = [[1, 2, 3],
590                 [4, 5, 6],
591                 [7, 8, 9]];
592 
593     assert(format("%(%(%d %) - %)", mat), "1 2 3 - 4 5 6 - 7 8 9");
594     assert(format("[%(%(%d %) - %)]", mat), "[1 2 3 - 4 5 6 - 7 8 9]");
595     assert(format("[%([%(%d %)]%| - %)]", mat), "[1 2 3] - [4 5 6] - [7 8 9]");
596 
597 /*
598 Strings and characters are escaped automatically inside compound
599 format specifiers. To avoid this behavior, use "%-(" instead of "%(":
600  */
601     assert(format("My friends are %s.", ["John", "Nancy"]) == `My friends are ["John", "Nancy"].`);
602     assert(format("My friends are %(%s, %).", ["John", "Nancy"]) == `My friends are "John", "Nancy".`);
603     assert(format("My friends are %-(%s, %).", ["John", "Nancy"]) == `My friends are John, Nancy.`);
604 }
605 
606 /// Using parameters:
607 @safe unittest
608 {
609     // Flags can be used to influence to outcome:
610     assert(format("%g != %+#g", 3.14, 3.14) == "3.14 != +3.14000");
611 
612     // Width and precision help to arrange the formatted result:
613     assert(format(">%10.2f<", 1234.56789) == ">   1234.57<");
614 
615     // Numbers can be grouped:
616     assert(format("%,4d", int.max) == "21,4748,3647");
617 
618     // It's possible to specify the position of an argument:
619     assert(format("%3$s %1$s", 3, 17, 5) == "5 3");
620 }
621 
622 /// Providing parameters as arguments:
623 @safe unittest
624 {
625     // Width as argument
626     assert(format(">%*s<", 10, "abc") == ">       abc<");
627 
628     // Precision as argument
629     assert(format(">%.*f<", 5, 123.2) == ">123.20000<");
630 
631     // Grouping as argument
632     assert(format("%,*d", 1, int.max) == "2,1,4,7,4,8,3,6,4,7");
633 
634     // Grouping separator as argument
635     assert(format("%,3?d", '_', int.max) == "2_147_483_647");
636 
637     // All at once
638     assert(format("%*.*,*?d", 20, 15, 6, '/', int.max) == "   000/002147/483647");
639 }
640 
641 public import std.format.read;
642 public import std.format.spec;
643 public import std.format.write;
644 
645 import std.exception : enforce;
646 import std.range.primitives : isInputRange;
647 import std.traits : CharTypeOf, isSomeChar, isSomeString, StringTypeOf;
648 import std.format.internal.write : hasToString;
649 
650 /**
651 Signals an issue encountered while formatting.
652  */
653 class FormatException : Exception
654 {
655     /// Generic constructor.
656     @safe @nogc pure nothrow
this()657     this()
658     {
659         super("format error");
660     }
661 
662     /**
663        Creates a new instance of `FormatException`.
664 
665        Params:
666            msg = message of the exception
667            fn = file name of the file where the exception was created (optional)
668            ln = line number of the file where the exception was created (optional)
669            next = for internal use, should always be null (optional)
670      */
671     @safe @nogc pure nothrow
672     this(string msg, string fn = __FILE__, size_t ln = __LINE__, Throwable next = null)
673     {
674         super(msg, fn, ln, next);
675     }
676 }
677 
678 ///
679 @safe unittest
680 {
681     import std.exception : assertThrown;
682 
683     assertThrown!FormatException(format("%d", "foo"));
684 }
685 
686 package alias enforceFmt = enforce!FormatException;
687 
688 // @@@DEPRECATED_[2.107.0]@@@
689 deprecated("formatElement was accidentally made public and will be removed in 2.107.0")
690 void formatElement(Writer, T, Char)(auto ref Writer w, T val, scope const ref FormatSpec!Char f)
691 if (is(StringTypeOf!T) && !hasToString!(T, Char) && !is(T == enum))
692 {
693     import std.format.internal.write : fe = formatElement;
694 
695     fe(w, val, f);
696 }
697 
698 // @@@DEPRECATED_[2.107.0]@@@
699 deprecated("formatElement was accidentally made public and will be removed in 2.107.0")
700 void formatElement(Writer, T, Char)(auto ref Writer w, T val, scope const ref FormatSpec!Char f)
701 if (is(CharTypeOf!T) && !is(T == enum))
702 {
703     import std.format.internal.write : fe = formatElement;
704 
705     fe(w, val, f);
706 }
707 
708 // @@@DEPRECATED_[2.107.0]@@@
709 deprecated("formatElement was accidentally made public and will be removed in 2.107.0")
710 void formatElement(Writer, T, Char)(auto ref Writer w, auto ref T val, scope const ref FormatSpec!Char f)
711 if ((!is(StringTypeOf!T) || hasToString!(T, Char)) && !is(CharTypeOf!T) || is(T == enum))
712 {
713     import std.format.internal.write : fe = formatElement;
714 
715     fe(w, val, f);
716 }
717 
718 // Like NullSink, but toString() isn't even called at all. Used to test the format string.
719 package struct NoOpSink
720 {
putNoOpSink721     void put(E)(scope const E) pure @safe @nogc nothrow {}
722 }
723 
724 // @@@DEPRECATED_[2.107.0]@@@
725 deprecated("unformatElement was accidentally made public and will be removed in 2.107.0")
unformatElement(T,Range,Char)726 T unformatElement(T, Range, Char)(ref Range input, scope const ref FormatSpec!Char spec)
727 if (isInputRange!Range)
728 {
729     import std.format.internal.read : ue = unformatElement;
730 
731     return ue(input, spec);
732 }
733 
734 // Used to check format strings are compatible with argument types
735 package(std) enum checkFormatException(alias fmt, Args...) =
736 {
737     import std.conv : text;
738 
739     try
740     {
741         auto n = .formattedWrite(NoOpSink(), fmt, Args.init);
742 
743         enforceFmt(n == Args.length, text("Orphan format arguments: args[", n, "..", Args.length, "]"));
744     }
745     catch (Exception e)
746         return e.msg;
747     return null;
748 }();
749 
750 /**
751 Converts its arguments according to a format string into a string.
752 
753 The second version of `format` takes the format string as template
754 argument. In this case, it is checked for consistency at
755 compile-time and produces slightly faster code, because the length of
756 the output buffer can be estimated in advance.
757 
758 Params:
759     fmt = a $(MREF_ALTTEXT format string, std,format)
760     args = a variadic list of arguments to be formatted
761     Char = character type of `fmt`
762     Args = a variadic list of types of the arguments
763 
764 Returns:
765     The formatted string.
766 
767 Throws:
768     A $(LREF FormatException) if formatting did not succeed.
769 
770 See_Also:
771     $(LREF sformat) for a variant, that tries to avoid garbage collection.
772  */
773 immutable(Char)[] format(Char, Args...)(in Char[] fmt, Args args)
774 if (isSomeChar!Char)
775 {
776     import std.array : appender;
777 
778     auto w = appender!(immutable(Char)[]);
779     auto n = formattedWrite(w, fmt, args);
version(all)780     version (all)
781     {
782         // In the future, this check will be removed to increase consistency
783         // with formattedWrite
784         import std.conv : text;
785         enforceFmt(n == args.length, text("Orphan format arguments: args[", n, "..", args.length, "]"));
786     }
787     return w.data;
788 }
789 
790 ///
791 @safe pure unittest
792 {
793     assert(format("Here are %d %s.", 3, "apples") == "Here are 3 apples.");
794 
795     assert("Increase: %7.2f %%".format(17.4285) == "Increase:   17.43 %");
796 }
797 
798 @safe pure unittest
799 {
800     import std.exception : assertCTFEable, assertThrown;
801 
802     assertCTFEable!(
803     {
804         assert(format("foo") == "foo");
805         assert(format("foo%%") == "foo%");
806         assert(format("foo%s", 'C') == "fooC");
807         assert(format("%s foo", "bar") == "bar foo");
808         assert(format("%s foo %s", "bar", "abc") == "bar foo abc");
809         assert(format("foo %d", -123) == "foo -123");
810         assert(format("foo %d", 123) == "foo 123");
811 
812         assertThrown!FormatException(format("foo %s"));
813         assertThrown!FormatException(format("foo %s", 123, 456));
814 
815         assert(format("hel%slo%s%s%s", "world", -138, 'c', true) == "helworldlo-138ctrue");
816     });
817 
818     assert(is(typeof(format("happy")) == string));
819     assert(is(typeof(format("happy"w)) == wstring));
820     assert(is(typeof(format("happy"d)) == dstring));
821 }
822 
823 // https://issues.dlang.org/show_bug.cgi?id=16661
824 @safe pure unittest
825 {
826     assert(format("%.2f"d, 0.4) == "0.40");
827     assert("%02d"d.format(1) == "01"d);
828 }
829 
830 @safe unittest
831 {
832     int i;
833     string s;
834 
835     s = format("hello world! %s %s %s%s%s", true, 57, 1_000_000_000, 'x', " foo");
836     assert(s == "hello world! true 57 1000000000x foo");
837 
838     s = format("%s %A %s", 1.67, -1.28, float.nan);
839     assert(s == "1.67 -0X1.47AE147AE147BP+0 nan", s);
840 
841     s = format("%x %X", 0x1234AF, 0xAFAFAFAF);
842     assert(s == "1234af AFAFAFAF");
843 
844     s = format("%b %o", 0x1234AF, 0xAFAFAFAF);
845     assert(s == "100100011010010101111 25753727657");
846 
847     s = format("%d %s", 0x1234AF, 0xAFAFAFAF);
848     assert(s == "1193135 2947526575");
849 }
850 
851 @safe unittest
852 {
853     import std.conv : octal;
854 
855     string s;
856     int i;
857 
858     s = format("%#06.*f", 2, 12.345);
859     assert(s == "012.35");
860 
861     s = format("%#0*.*f", 6, 2, 12.345);
862     assert(s == "012.35");
863 
864     s = format("%7.4g:", 12.678);
865     assert(s == "  12.68:");
866 
867     s = format("%7.4g:", 12.678L);
868     assert(s == "  12.68:");
869 
870     s = format("%04f|%05d|%#05x|%#5x", -4.0, -10, 1, 1);
871     assert(s == "-4.000000|-0010|0x001|  0x1");
872 
873     i = -10;
874     s = format("%d|%3d|%03d|%1d|%01.4f", i, i, i, i, cast(double) i);
875     assert(s == "-10|-10|-10|-10|-10.0000");
876 
877     i = -5;
878     s = format("%d|%3d|%03d|%1d|%01.4f", i, i, i, i, cast(double) i);
879     assert(s == "-5| -5|-05|-5|-5.0000");
880 
881     i = 0;
882     s = format("%d|%3d|%03d|%1d|%01.4f", i, i, i, i, cast(double) i);
883     assert(s == "0|  0|000|0|0.0000");
884 
885     i = 5;
886     s = format("%d|%3d|%03d|%1d|%01.4f", i, i, i, i, cast(double) i);
887     assert(s == "5|  5|005|5|5.0000");
888 
889     i = 10;
890     s = format("%d|%3d|%03d|%1d|%01.4f", i, i, i, i, cast(double) i);
891     assert(s == "10| 10|010|10|10.0000");
892 
893     s = format("%.0d", 0);
894     assert(s == "0");
895 
896     s = format("%.g", .34);
897     assert(s == "0.3");
898 
899     s = format("%.0g", .34);
900     assert(s == "0.3");
901 
902     s = format("%.2g", .34);
903     assert(s == "0.34");
904 
905     s = format("%0.0008f", 1e-08);
906     assert(s == "0.00000001");
907 
908     s = format("%0.0008f", 1e-05);
909     assert(s == "0.00001000");
910 
911     s = "helloworld";
912     string r;
913     r = format("%.2s", s[0 .. 5]);
914     assert(r == "he");
915     r = format("%.20s", s[0 .. 5]);
916     assert(r == "hello");
917     r = format("%8s", s[0 .. 5]);
918     assert(r == "   hello");
919 
920     byte[] arrbyte = new byte[4];
921     arrbyte[0] = 100;
922     arrbyte[1] = -99;
923     arrbyte[3] = 0;
924     r = format("%s", arrbyte);
925     assert(r == "[100, -99, 0, 0]");
926 
927     ubyte[] arrubyte = new ubyte[4];
928     arrubyte[0] = 100;
929     arrubyte[1] = 200;
930     arrubyte[3] = 0;
931     r = format("%s", arrubyte);
932     assert(r == "[100, 200, 0, 0]");
933 
934     short[] arrshort = new short[4];
935     arrshort[0] = 100;
936     arrshort[1] = -999;
937     arrshort[3] = 0;
938     r = format("%s", arrshort);
939     assert(r == "[100, -999, 0, 0]");
940 
941     ushort[] arrushort = new ushort[4];
942     arrushort[0] = 100;
943     arrushort[1] = 20_000;
944     arrushort[3] = 0;
945     r = format("%s", arrushort);
946     assert(r == "[100, 20000, 0, 0]");
947 
948     int[] arrint = new int[4];
949     arrint[0] = 100;
950     arrint[1] = -999;
951     arrint[3] = 0;
952     r = format("%s", arrint);
953     assert(r == "[100, -999, 0, 0]");
954 
955     long[] arrlong = new long[4];
956     arrlong[0] = 100;
957     arrlong[1] = -999;
958     arrlong[3] = 0;
959     r = format("%s", arrlong);
960     assert(r == "[100, -999, 0, 0]");
961 
962     ulong[] arrulong = new ulong[4];
963     arrulong[0] = 100;
964     arrulong[1] = 999;
965     arrulong[3] = 0;
966     r = format("%s", arrulong);
967     assert(r == "[100, 999, 0, 0]");
968 
969     string[] arr2 = new string[4];
970     arr2[0] = "hello";
971     arr2[1] = "world";
972     arr2[3] = "foo";
973     r = format("%s", arr2);
974     assert(r == `["hello", "world", "", "foo"]`);
975 
976     r = format("%.8d", 7);
977     assert(r == "00000007");
978     r = format("%.8x", 10);
979     assert(r == "0000000a");
980 
981     r = format("%-3d", 7);
982     assert(r == "7  ");
983 
984     r = format("%-1*d", 4, 3);
985     assert(r == "3   ");
986 
987     r = format("%*d", -3, 7);
988     assert(r == "7  ");
989 
990     r = format("%.*d", -3, 7);
991     assert(r == "7");
992 
993     r = format("%-1.*f", 2, 3.1415);
994     assert(r == "3.14");
995 
996     r = format("abc"c);
997     assert(r == "abc");
998 
999     //format() returns the same type as inputted.
1000     wstring wr;
1001     wr = format("def"w);
1002     assert(wr == "def"w);
1003 
1004     dstring dr;
1005     dr = format("ghi"d);
1006     assert(dr == "ghi"d);
1007 
1008     // Empty static character arrays work as well
1009     const char[0] cempty;
1010     assert(format("test%spath", cempty) == "testpath");
1011     const wchar[0] wempty;
1012     assert(format("test%spath", wempty) == "testpath");
1013     const dchar[0] dempty;
1014     assert(format("test%spath", dempty) == "testpath");
1015 
1016     void* p = () @trusted { return cast(void*) 0xDEADBEEF; } ();
1017     r = format("%s", p);
1018     assert(r == "DEADBEEF");
1019 
1020     r = format("%#x", 0xabcd);
1021     assert(r == "0xabcd");
1022     r = format("%#X", 0xABCD);
1023     assert(r == "0XABCD");
1024 
1025     r = format("%#o", octal!12345);
1026     assert(r == "012345");
1027     r = format("%o", 9);
1028     assert(r == "11");
1029     r = format("%#o", 0);   // https://issues.dlang.org/show_bug.cgi?id=15663
1030     assert(r == "0");
1031 
1032     r = format("%+d", 123);
1033     assert(r == "+123");
1034     r = format("%+d", -123);
1035     assert(r == "-123");
1036     r = format("% d", 123);
1037     assert(r == " 123");
1038     r = format("% d", -123);
1039     assert(r == "-123");
1040 
1041     r = format("%%");
1042     assert(r == "%");
1043 
1044     r = format("%d", true);
1045     assert(r == "1");
1046     r = format("%d", false);
1047     assert(r == "0");
1048 
1049     r = format("%d", 'a');
1050     assert(r == "97");
1051     wchar wc = 'a';
1052     r = format("%d", wc);
1053     assert(r == "97");
1054     dchar dc = 'a';
1055     r = format("%d", dc);
1056     assert(r == "97");
1057 
1058     byte b = byte.max;
1059     r = format("%x", b);
1060     assert(r == "7f");
1061     r = format("%x", ++b);
1062     assert(r == "80");
1063     r = format("%x", ++b);
1064     assert(r == "81");
1065 
1066     short sh = short.max;
1067     r = format("%x", sh);
1068     assert(r == "7fff");
1069     r = format("%x", ++sh);
1070     assert(r == "8000");
1071     r = format("%x", ++sh);
1072     assert(r == "8001");
1073 
1074     i = int.max;
1075     r = format("%x", i);
1076     assert(r == "7fffffff");
1077     r = format("%x", ++i);
1078     assert(r == "80000000");
1079     r = format("%x", ++i);
1080     assert(r == "80000001");
1081 
1082     r = format("%x", 10);
1083     assert(r == "a");
1084     r = format("%X", 10);
1085     assert(r == "A");
1086     r = format("%x", 15);
1087     assert(r == "f");
1088     r = format("%X", 15);
1089     assert(r == "F");
1090 
1091     Object c = null;
1092     r = () @trusted { return format("%s", c); } ();
1093     assert(r == "null");
1094 
1095     enum TestEnum
1096     {
1097         Value1, Value2
1098     }
1099     r = format("%s", TestEnum.Value2);
1100     assert(r == "Value2");
1101 
1102     immutable(char[5])[int] aa = ([3:"hello", 4:"betty"]);
1103     r = () @trusted { return format("%s", aa.values); } ();
1104     assert(r == `["hello", "betty"]` || r == `["betty", "hello"]`);
1105     r = format("%s", aa);
1106     assert(r == `[3:"hello", 4:"betty"]` || r == `[4:"betty", 3:"hello"]`);
1107 
1108     static const dchar[] ds = ['a','b'];
1109     for (int j = 0; j < ds.length; ++j)
1110     {
1111         r = format(" %d", ds[j]);
1112         if (j == 0)
1113             assert(r == " 97");
1114         else
1115             assert(r == " 98");
1116     }
1117 
1118     r = format(">%14d<, %s", 15, [1,2,3]);
1119     assert(r == ">            15<, [1, 2, 3]");
1120 
1121     assert(format("%8s", "bar") == "     bar");
1122     assert(format("%8s", "b\u00e9ll\u00f4") == "   b\u00e9ll\u00f4");
1123 }
1124 
1125 @safe unittest
1126 {
1127     import std.exception : assertCTFEable;
1128 
1129     assertCTFEable!(
1130     {
1131         auto tmp = format("%,d", 1000);
1132         assert(tmp == "1,000", "'" ~ tmp ~ "'");
1133 
1134         tmp = format("%,?d", 'z', 1234567);
1135         assert(tmp == "1z234z567", "'" ~ tmp ~ "'");
1136 
1137         tmp = format("%10,?d", 'z', 1234567);
1138         assert(tmp == " 1z234z567", "'" ~ tmp ~ "'");
1139 
1140         tmp = format("%11,2?d", 'z', 1234567);
1141         assert(tmp == " 1z23z45z67", "'" ~ tmp ~ "'");
1142 
1143         tmp = format("%11,*?d", 2, 'z', 1234567);
1144         assert(tmp == " 1z23z45z67", "'" ~ tmp ~ "'");
1145 
1146         tmp = format("%11,*d", 2, 1234567);
1147         assert(tmp == " 1,23,45,67", "'" ~ tmp ~ "'");
1148 
1149         tmp = format("%11,2d", 1234567);
1150         assert(tmp == " 1,23,45,67", "'" ~ tmp ~ "'");
1151     });
1152 }
1153 
1154 @safe unittest
1155 {
1156     auto tmp = format("%,f", 1000.0);
1157     assert(tmp == "1,000.000000", "'" ~ tmp ~ "'");
1158 
1159     tmp = format("%,f", 1234567.891011);
1160     assert(tmp == "1,234,567.891011", "'" ~ tmp ~ "'");
1161 
1162     tmp = format("%,f", -1234567.891011);
1163     assert(tmp == "-1,234,567.891011", "'" ~ tmp ~ "'");
1164 
1165     tmp = format("%,2f", 1234567.891011);
1166     assert(tmp == "1,23,45,67.891011", "'" ~ tmp ~ "'");
1167 
1168     tmp = format("%18,f", 1234567.891011);
1169     assert(tmp == "  1,234,567.891011", "'" ~ tmp ~ "'");
1170 
1171     tmp = format("%18,?f", '.', 1234567.891011);
1172     assert(tmp == "  1.234.567.891011", "'" ~ tmp ~ "'");
1173 
1174     tmp = format("%,?.3f", 'ä', 1234567.891011);
1175     assert(tmp == "1ä234ä567.891", "'" ~ tmp ~ "'");
1176 
1177     tmp = format("%,*?.3f", 1, 'ä', 1234567.891011);
1178     assert(tmp == "1ä2ä3ä4ä5ä6ä7.891", "'" ~ tmp ~ "'");
1179 
1180     tmp = format("%,4?.3f", '_', 1234567.891011);
1181     assert(tmp == "123_4567.891", "'" ~ tmp ~ "'");
1182 
1183     tmp = format("%12,3.3f", 1234.5678);
1184     assert(tmp == "   1,234.568", "'" ~ tmp ~ "'");
1185 
1186     tmp = format("%,e", 3.141592653589793238462);
1187     assert(tmp == "3.141593e+00", "'" ~ tmp ~ "'");
1188 
1189     tmp = format("%15,e", 3.141592653589793238462);
1190     assert(tmp == "   3.141593e+00", "'" ~ tmp ~ "'");
1191 
1192     tmp = format("%15,e", -3.141592653589793238462);
1193     assert(tmp == "  -3.141593e+00", "'" ~ tmp ~ "'");
1194 
1195     tmp = format("%.4,*e", 2, 3.141592653589793238462);
1196     assert(tmp == "3.1416e+00", "'" ~ tmp ~ "'");
1197 
1198     tmp = format("%13.4,*e", 2, 3.141592653589793238462);
1199     assert(tmp == "   3.1416e+00", "'" ~ tmp ~ "'");
1200 
1201     tmp = format("%,.0f", 3.14);
1202     assert(tmp == "3", "'" ~ tmp ~ "'");
1203 
1204     tmp = format("%3,g", 1_000_000.123456);
1205     assert(tmp == "1e+06", "'" ~ tmp ~ "'");
1206 
1207     tmp = format("%19,?f", '.', -1234567.891011);
1208     assert(tmp == "  -1.234.567.891011", "'" ~ tmp ~ "'");
1209 }
1210 
1211 // Test for multiple indexes
1212 @safe unittest
1213 {
1214     auto tmp = format("%2:5$s", 1, 2, 3, 4, 5);
1215     assert(tmp == "2345", tmp);
1216 }
1217 
1218 // https://issues.dlang.org/show_bug.cgi?id=18047
1219 @safe unittest
1220 {
1221     auto cmp = "     123,456";
1222     assert(cmp.length == 12, format("%d", cmp.length));
1223     auto tmp = format("%12,d", 123456);
1224     assert(tmp.length == 12, format("%d", tmp.length));
1225 
1226     assert(tmp == cmp, "'" ~ tmp ~ "'");
1227 }
1228 
1229 // https://issues.dlang.org/show_bug.cgi?id=17459
1230 @safe unittest
1231 {
1232     auto cmp = "100";
1233     auto tmp  = format("%0d", 100);
1234     assert(tmp == cmp, tmp);
1235 
1236     cmp = "0100";
1237     tmp  = format("%04d", 100);
1238     assert(tmp == cmp, tmp);
1239 
1240     cmp = "0,000,000,100";
1241     tmp  = format("%012,3d", 100);
1242     assert(tmp == cmp, tmp);
1243 
1244     cmp = "0,000,001,000";
1245     tmp = format("%012,3d", 1_000);
1246     assert(tmp == cmp, tmp);
1247 
1248     cmp = "0,000,100,000";
1249     tmp = format("%012,3d", 100_000);
1250     assert(tmp == cmp, tmp);
1251 
1252     cmp = "0,001,000,000";
1253     tmp = format("%012,3d", 1_000_000);
1254     assert(tmp == cmp, tmp);
1255 
1256     cmp = "0,100,000,000";
1257     tmp = format("%012,3d", 100_000_000);
1258     assert(tmp == cmp, tmp);
1259 }
1260 
1261 // https://issues.dlang.org/show_bug.cgi?id=17459
1262 @safe unittest
1263 {
1264     auto cmp = "100,000";
1265     auto tmp  = format("%06,d", 100_000);
1266     assert(tmp == cmp, tmp);
1267 
1268     cmp = "100,000";
1269     tmp  = format("%07,d", 100_000);
1270     assert(tmp == cmp, tmp);
1271 
1272     cmp = "0,100,000";
1273     tmp  = format("%08,d", 100_000);
1274     assert(tmp == cmp, tmp);
1275 }
1276 
1277 // https://issues.dlang.org/show_bug.cgi?id=20288
1278 @safe unittest
1279 {
1280     string s = format("%,.2f", double.nan);
1281     assert(s == "nan", s);
1282 
1283     s = format("%,.2F", double.nan);
1284     assert(s == "NAN", s);
1285 
1286     s = format("%,.2f", -double.nan);
1287     assert(s == "-nan", s);
1288 
1289     s = format("%,.2F", -double.nan);
1290     assert(s == "-NAN", s);
1291 
1292     string g = format("^%13s$", "nan");
1293     string h = "^          nan$";
1294     assert(g == h, "\ngot:" ~ g ~ "\nexp:" ~ h);
1295     string a = format("^%13,3.2f$", double.nan);
1296     string b = format("^%13,3.2F$", double.nan);
1297     string c = format("^%13,3.2f$", -double.nan);
1298     string d = format("^%13,3.2F$", -double.nan);
1299     assert(a == "^          nan$", "\ngot:'"~ a ~ "'\nexp:'^          nan$'");
1300     assert(b == "^          NAN$", "\ngot:'"~ b ~ "'\nexp:'^          NAN$'");
1301     assert(c == "^         -nan$", "\ngot:'"~ c ~ "'\nexp:'^         -nan$'");
1302     assert(d == "^         -NAN$", "\ngot:'"~ d ~ "'\nexp:'^         -NAN$'");
1303 
1304     a = format("^%-13,3.2f$", double.nan);
1305     b = format("^%-13,3.2F$", double.nan);
1306     c = format("^%-13,3.2f$", -double.nan);
1307     d = format("^%-13,3.2F$", -double.nan);
1308     assert(a == "^nan          $", "\ngot:'"~ a ~ "'\nexp:'^nan          $'");
1309     assert(b == "^NAN          $", "\ngot:'"~ b ~ "'\nexp:'^NAN          $'");
1310     assert(c == "^-nan         $", "\ngot:'"~ c ~ "'\nexp:'^-nan         $'");
1311     assert(d == "^-NAN         $", "\ngot:'"~ d ~ "'\nexp:'^-NAN         $'");
1312 
1313     a = format("^%+13,3.2f$", double.nan);
1314     b = format("^%+13,3.2F$", double.nan);
1315     c = format("^%+13,3.2f$", -double.nan);
1316     d = format("^%+13,3.2F$", -double.nan);
1317     assert(a == "^         +nan$", "\ngot:'"~ a ~ "'\nexp:'^         +nan$'");
1318     assert(b == "^         +NAN$", "\ngot:'"~ b ~ "'\nexp:'^         +NAN$'");
1319     assert(c == "^         -nan$", "\ngot:'"~ c ~ "'\nexp:'^         -nan$'");
1320     assert(d == "^         -NAN$", "\ngot:'"~ d ~ "'\nexp:'^         -NAN$'");
1321 
1322     a = format("^%-+13,3.2f$", double.nan);
1323     b = format("^%-+13,3.2F$", double.nan);
1324     c = format("^%-+13,3.2f$", -double.nan);
1325     d = format("^%-+13,3.2F$", -double.nan);
1326     assert(a == "^+nan         $", "\ngot:'"~ a ~ "'\nexp:'^+nan         $'");
1327     assert(b == "^+NAN         $", "\ngot:'"~ b ~ "'\nexp:'^+NAN         $'");
1328     assert(c == "^-nan         $", "\ngot:'"~ c ~ "'\nexp:'^-nan         $'");
1329     assert(d == "^-NAN         $", "\ngot:'"~ d ~ "'\nexp:'^-NAN         $'");
1330 
1331     a = format("^%- 13,3.2f$", double.nan);
1332     b = format("^%- 13,3.2F$", double.nan);
1333     c = format("^%- 13,3.2f$", -double.nan);
1334     d = format("^%- 13,3.2F$", -double.nan);
1335     assert(a == "^ nan         $", "\ngot:'"~ a ~ "'\nexp:'^ nan         $'");
1336     assert(b == "^ NAN         $", "\ngot:'"~ b ~ "'\nexp:'^ NAN         $'");
1337     assert(c == "^-nan         $", "\ngot:'"~ c ~ "'\nexp:'^-nan         $'");
1338     assert(d == "^-NAN         $", "\ngot:'"~ d ~ "'\nexp:'^-NAN         $'");
1339 }
1340 
1341 @safe unittest
1342 {
1343     struct S
1344     {
1345         int a;
1346 
toStringS1347         void toString(void delegate(const(char)[]) sink, string fmt)
1348         {
1349             auto spec = singleSpec(fmt);
1350             sink.formatValue(a, spec);
1351         }
1352     }
1353 
1354     S s = S(1);
1355     auto result = () @trusted { return format!"%5,3d"(s); } ();
1356     assert(result == "    1");
1357 }
1358 
1359 /// ditto
1360 typeof(fmt) format(alias fmt, Args...)(Args args)
1361 if (isSomeString!(typeof(fmt)))
1362 {
1363     import std.array : appender;
1364     import std.range.primitives : ElementEncodingType;
1365     import std.traits : Unqual;
1366 
1367     alias e = checkFormatException!(fmt, Args);
1368     alias Char = Unqual!(ElementEncodingType!(typeof(fmt)));
1369 
1370     static assert(!e, e);
1371     auto w = appender!(immutable(Char)[]);
1372 
1373     // no need to traverse the string twice during compile time
1374     if (!__ctfe)
1375     {
1376         enum len = guessLength!Char(fmt);
1377         w.reserve(len);
1378     }
1379     else
1380     {
1381         w.reserve(fmt.length);
1382     }
1383 
1384     formattedWrite(w, fmt, args);
1385     return w.data;
1386 }
1387 
1388 /// The format string can be checked at compile-time:
1389 @safe pure unittest
1390 {
1391     auto s = format!"%s is %s"("Pi", 3.14);
1392     assert(s == "Pi is 3.14");
1393 
1394     // This line doesn't compile, because 3.14 cannot be formatted with %d:
1395     // s = format!"%s is %d"("Pi", 3.14);
1396 }
1397 
1398 @safe pure unittest
1399 {
1400     string s;
1401     static assert(!__traits(compiles, {s = format!"%l"();}));     // missing arg
1402     static assert(!__traits(compiles, {s = format!""(404);}));    // surplus arg
1403     static assert(!__traits(compiles, {s = format!"%d"(4.03);})); // incompatible arg
1404 }
1405 
1406 // https://issues.dlang.org/show_bug.cgi?id=17381
1407 @safe pure unittest
1408 {
1409     static assert(!__traits(compiles, format!"%s"(1.5, 2)));
1410     static assert(!__traits(compiles, format!"%f"(1.5, 2)));
1411     static assert(!__traits(compiles, format!"%s"(1.5L, 2)));
1412     static assert(!__traits(compiles, format!"%f"(1.5L, 2)));
1413 }
1414 
1415 // called during compilation to guess the length of the
1416 // result of format
guessLength(Char,S)1417 private size_t guessLength(Char, S)(S fmtString)
1418 {
1419     import std.array : appender;
1420 
1421     size_t len;
1422     auto output = appender!(immutable(Char)[])();
1423     auto spec = FormatSpec!Char(fmtString);
1424     while (spec.writeUpToNextSpec(output))
1425     {
1426         // take a guess
1427         if (spec.width == 0 && (spec.precision == spec.UNSPECIFIED || spec.precision == spec.DYNAMIC))
1428         {
1429             switch (spec.spec)
1430             {
1431                 case 'c':
1432                     ++len;
1433                     break;
1434                 case 'd':
1435                 case 'x':
1436                 case 'X':
1437                     len += 3;
1438                     break;
1439                 case 'b':
1440                     len += 8;
1441                     break;
1442                 case 'f':
1443                 case 'F':
1444                     len += 10;
1445                     break;
1446                 case 's':
1447                 case 'e':
1448                 case 'E':
1449                 case 'g':
1450                 case 'G':
1451                     len += 12;
1452                     break;
1453                 default: break;
1454             }
1455 
1456             continue;
1457         }
1458 
1459         if ((spec.spec == 'e' || spec.spec == 'E' || spec.spec == 'g' ||
1460              spec.spec == 'G' || spec.spec == 'f' || spec.spec == 'F') &&
1461             spec.precision != spec.UNSPECIFIED && spec.precision != spec.DYNAMIC &&
1462             spec.width == 0
1463         )
1464         {
1465             len += spec.precision + 5;
1466             continue;
1467         }
1468 
1469         if (spec.width == spec.precision)
1470             len += spec.width;
1471         else if (spec.width > 0 && spec.width != spec.DYNAMIC &&
1472                  (spec.precision == spec.UNSPECIFIED || spec.width > spec.precision))
1473         {
1474             len += spec.width;
1475         }
1476         else if (spec.precision != spec.UNSPECIFIED && spec.precision > spec.width)
1477             len += spec.precision;
1478     }
1479     len += output.data.length;
1480     return len;
1481 }
1482 
1483 @safe pure
1484 unittest
1485 {
1486     assert(guessLength!char("%c") == 1);
1487     assert(guessLength!char("%d") == 3);
1488     assert(guessLength!char("%x") == 3);
1489     assert(guessLength!char("%b") == 8);
1490     assert(guessLength!char("%f") == 10);
1491     assert(guessLength!char("%s") == 12);
1492     assert(guessLength!char("%02d") == 2);
1493     assert(guessLength!char("%02d") == 2);
1494     assert(guessLength!char("%4.4d") == 4);
1495     assert(guessLength!char("%2.4f") == 4);
1496     assert(guessLength!char("%02d:%02d:%02d") == 8);
1497     assert(guessLength!char("%0.2f") == 7);
1498     assert(guessLength!char("%0*d") == 0);
1499 }
1500 
1501 /**
1502 Converts its arguments according to a format string into a buffer.
1503 The buffer has to be large enough to hold the formatted string.
1504 
1505 The second version of `sformat` takes the format string as a template
1506 argument. In this case, it is checked for consistency at
1507 compile-time.
1508 
1509 Params:
1510     buf = the buffer where the formatted string should go
1511     fmt = a $(MREF_ALTTEXT format string, std,format)
1512     args = a variadic list of arguments to be formatted
1513     Char = character type of `fmt`
1514     Args = a variadic list of types of the arguments
1515 
1516 Returns:
1517     A slice of `buf` containing the formatted string.
1518 
1519 Throws:
1520     A $(REF_ALTTEXT RangeError, RangeError, core, exception) if `buf`
1521     isn't large enough to hold the formatted string
1522     and a $(LREF FormatException) if formatting did not succeed.
1523 
1524 Note:
1525     In theory this function should be `@nogc`. But with the current
1526     implementation there are some cases where allocations occur:
1527 
1528     $(UL
1529     $(LI An exception is thrown.)
1530     $(LI A custom `toString` function of a compound type allocates.))
1531  */
sformat(Char,Args...)1532 char[] sformat(Char, Args...)(return scope char[] buf, scope const(Char)[] fmt, Args args)
1533 {
1534     import core.exception : RangeError;
1535     import std.range.primitives;
1536     import std.utf : encode;
1537 
1538     static struct Sink
1539     {
1540         char[] buf;
1541         size_t i;
1542         void put(dchar c)
1543         {
1544             char[4] enc;
1545             auto n = encode(enc, c);
1546 
1547             if (buf.length < i + n)
1548                 throw new RangeError(__FILE__, __LINE__);
1549 
1550             buf[i .. i + n] = enc[0 .. n];
1551             i += n;
1552         }
1553         void put(scope const(char)[] s)
1554         {
1555             if (buf.length < i + s.length)
1556                 throw new RangeError(__FILE__, __LINE__);
1557 
1558             buf[i .. i + s.length] = s[];
1559             i += s.length;
1560         }
1561         void put(scope const(wchar)[] s)
1562         {
1563             for (; !s.empty; s.popFront())
1564                 put(s.front);
1565         }
1566         void put(scope const(dchar)[] s)
1567         {
1568             for (; !s.empty; s.popFront())
1569                 put(s.front);
1570         }
1571     }
1572     auto sink = Sink(buf);
1573     auto n = formattedWrite(sink, fmt, args);
1574     version (all)
1575     {
1576         // In the future, this check will be removed to increase consistency
1577         // with formattedWrite
1578         import std.conv : text;
1579         enforceFmt(
1580             n == args.length,
1581             text("Orphan format arguments: args[", n, " .. ", args.length, "]")
1582         );
1583     }
1584     return buf[0 .. sink.i];
1585 }
1586 
1587 /// ditto
1588 char[] sformat(alias fmt, Args...)(char[] buf, Args args)
1589 if (isSomeString!(typeof(fmt)))
1590 {
1591     alias e = checkFormatException!(fmt, Args);
1592     static assert(!e, e);
1593     return .sformat(buf, fmt, args);
1594 }
1595 
1596 ///
1597 @safe pure unittest
1598 {
1599     char[20] buf;
1600     assert(sformat(buf[], "Here are %d %s.", 3, "apples") == "Here are 3 apples.");
1601 
1602     assert(buf[].sformat("Increase: %7.2f %%", 17.4285) == "Increase:   17.43 %");
1603 }
1604 
1605 /// The format string can be checked at compile-time:
1606 @safe pure unittest
1607 {
1608     char[20] buf;
1609 
1610     assert(sformat!"Here are %d %s."(buf[], 3, "apples") == "Here are 3 apples.");
1611 
1612     // This line doesn't compile, because 3.14 cannot be formatted with %d:
1613     // writeln(sformat!"Here are %d %s."(buf[], 3.14, "apples"));
1614 }
1615 
1616 // checking, what is implicitly and explicitly stated in the public unittest
1617 @safe unittest
1618 {
1619     import std.exception : assertThrown;
1620 
1621     char[20] buf;
1622     assertThrown!FormatException(sformat(buf[], "Here are %d %s.", 3.14, "apples"));
1623     assert(!__traits(compiles, sformat!"Here are %d %s."(buf[], 3.14, "apples")));
1624 }
1625 
1626 @safe unittest
1627 {
1628     import core.exception : RangeError;
1629     import std.exception : assertCTFEable, assertThrown;
1630 
1631     assertCTFEable!(
1632     {
1633         char[10] buf;
1634 
1635         assert(sformat(buf[], "foo") == "foo");
1636         assert(sformat(buf[], "foo%%") == "foo%");
1637         assert(sformat(buf[], "foo%s", 'C') == "fooC");
1638         assert(sformat(buf[], "%s foo", "bar") == "bar foo");
1639         () @trusted {
1640             assertThrown!RangeError(sformat(buf[], "%s foo %s", "bar", "abc"));
1641         } ();
1642         assert(sformat(buf[], "foo %d", -123) == "foo -123");
1643         assert(sformat(buf[], "foo %d", 123) == "foo 123");
1644 
1645         assertThrown!FormatException(sformat(buf[], "foo %s"));
1646         assertThrown!FormatException(sformat(buf[], "foo %s", 123, 456));
1647 
1648         assert(sformat(buf[], "%s %s %s", "c"c, "w"w, "d"d) == "c w d");
1649     });
1650 }
1651 
1652 @safe unittest // ensure that sformat avoids the GC
1653 {
1654     import core.memory : GC;
1655 
1656     const a = ["foo", "bar"];
1657     const u = () @trusted { return GC.stats().usedSize; } ();
1658     char[20] buf;
1659     sformat(buf, "%d", 123);
1660     sformat(buf, "%s", a);
1661     sformat(buf, "%s", 'c');
1662     const v = () @trusted { return GC.stats().usedSize; } ();
1663     assert(u == v);
1664 }
1665 
version(StdUnittest)1666 version (StdUnittest)
1667 private void formatReflectTest(T)(ref T val, string fmt, string formatted, string fn = __FILE__, size_t ln = __LINE__)
1668 {
1669     formatReflectTest(val, fmt, [formatted], fn, ln);
1670 }
1671 
version(StdUnittest)1672 version (StdUnittest)
1673 private void formatReflectTest(T)(ref T val, string fmt, string[] formatted, string fn = __FILE__, size_t ln = __LINE__)
1674 {
1675     import core.exception : AssertError;
1676     import std.algorithm.searching : canFind;
1677     import std.array : appender;
1678     import std.math.operations : isClose;
1679     import std.traits : FloatingPointTypeOf;
1680 
1681     auto w = appender!string();
1682     formattedWrite(w, fmt, val);
1683 
1684     auto input = w.data;
1685     enforce!AssertError(formatted.canFind(input), input, fn, ln);
1686 
1687     T val2;
1688     formattedRead(input, fmt, val2);
1689 
1690     static if (is(FloatingPointTypeOf!T))
1691         enforce!AssertError(isClose(val, val2), input, fn, ln);
1692     else
1693         enforce!AssertError(val == val2, input, fn, ln);
1694 }
1695 
1696 @safe unittest
1697 {
booleanTest()1698     void booleanTest()
1699     {
1700         auto b = true;
1701         formatReflectTest(b, "%s", `true`);
1702         formatReflectTest(b, "%b", `1`);
1703         formatReflectTest(b, "%o", `1`);
1704         formatReflectTest(b, "%d", `1`);
1705         formatReflectTest(b, "%u", `1`);
1706         formatReflectTest(b, "%x", `1`);
1707     }
1708 
integerTest()1709     void integerTest()
1710     {
1711         auto n = 127;
1712         formatReflectTest(n, "%s", `127`);
1713         formatReflectTest(n, "%b", `1111111`);
1714         formatReflectTest(n, "%o", `177`);
1715         formatReflectTest(n, "%d", `127`);
1716         formatReflectTest(n, "%u", `127`);
1717         formatReflectTest(n, "%x", `7f`);
1718     }
1719 
floatingTest()1720     void floatingTest()
1721     {
1722         auto f = 3.14;
1723         formatReflectTest(f, "%s", `3.14`);
1724         formatReflectTest(f, "%e", `3.140000e+00`);
1725         formatReflectTest(f, "%f", `3.140000`);
1726         formatReflectTest(f, "%g", `3.14`);
1727     }
1728 
charTest()1729     void charTest()
1730     {
1731         auto c = 'a';
1732         formatReflectTest(c, "%s", `a`);
1733         formatReflectTest(c, "%c", `a`);
1734         formatReflectTest(c, "%b", `1100001`);
1735         formatReflectTest(c, "%o", `141`);
1736         formatReflectTest(c, "%d", `97`);
1737         formatReflectTest(c, "%u", `97`);
1738         formatReflectTest(c, "%x", `61`);
1739     }
1740 
strTest()1741     void strTest()
1742     {
1743         auto s = "hello";
1744         formatReflectTest(s, "%s",              `hello`);
1745         formatReflectTest(s, "%(%c,%)",         `h,e,l,l,o`);
1746         formatReflectTest(s, "%(%s,%)",         `'h','e','l','l','o'`);
1747         formatReflectTest(s, "[%(<%c>%| $ %)]", `[<h> $ <e> $ <l> $ <l> $ <o>]`);
1748     }
1749 
daTest()1750     void daTest()
1751     {
1752         auto a = [1,2,3,4];
1753         formatReflectTest(a, "%s",              `[1, 2, 3, 4]`);
1754         formatReflectTest(a, "[%(%s; %)]",      `[1; 2; 3; 4]`);
1755         formatReflectTest(a, "[%(<%s>%| $ %)]", `[<1> $ <2> $ <3> $ <4>]`);
1756     }
1757 
saTest()1758     void saTest()
1759     {
1760         int[4] sa = [1,2,3,4];
1761         formatReflectTest(sa, "%s",              `[1, 2, 3, 4]`);
1762         formatReflectTest(sa, "[%(%s; %)]",      `[1; 2; 3; 4]`);
1763         formatReflectTest(sa, "[%(<%s>%| $ %)]", `[<1> $ <2> $ <3> $ <4>]`);
1764     }
1765 
aaTest()1766     void aaTest()
1767     {
1768         auto aa = [1:"hello", 2:"world"];
1769         formatReflectTest(aa, "%s",                    [`[1:"hello", 2:"world"]`, `[2:"world", 1:"hello"]`]);
1770         formatReflectTest(aa, "[%(%s->%s, %)]",        [`[1->"hello", 2->"world"]`, `[2->"world", 1->"hello"]`]);
1771         formatReflectTest(aa, "{%([%s=%(%c%)]%|; %)}", [`{[1=hello]; [2=world]}`, `{[2=world]; [1=hello]}`]);
1772     }
1773 
1774     import std.exception : assertCTFEable;
1775 
1776     assertCTFEable!(
1777     {
1778         booleanTest();
1779         integerTest();
1780         floatingTest();
1781         charTest();
1782         strTest();
1783         daTest();
1784         saTest();
1785         aaTest();
1786     });
1787 }
1788