- Inspired by Python's formatting facility, {fmt} provides a safe replacement
- for the printf
family of functions. Errors in format strings,
- which are a common source of vulnerabilities in C, are reported at
- compile time. For example:
-
-
fmt::format("{:d}", "I am not a number");
-
- will give a compile-time error because d
is not a valid
- format specifier for strings. APIs like
- fmt::format
prevent buffer overflow errors via
- automatic memory management.
-
-→ Learn more
-- Formatting of most standard types, including all containers, dates, - and times is supported out-of-the-box. For example: - -
fmt::print("{}", std::vector{1, 2, 3});
-
- prints the vector in a JSON-like format:
-
- [1, 2, 3]
-
- You can make your own types formattable and even make compile-time
- checks work for them.
-
-→ Learn more
-
- {fmt} can be anywhere from tens of percent to 20-30 times faster than
- iostreams and sprintf
, especially for numeric formatting.
-
-
-
-
-
- The library minimizes dynamic memory allocations and can optionally
- compile format strings to optimal code.
-
- {fmt} provides portable Unicode support on major operating systems
- with UTF-8 and char
strings. For example:
-
-
fmt::print("Слава Україні!");
-
- will be printed correctly on Linux, macOS, and even Windows console,
- irrespective of the codepages.
-
-- The default is locale-independent, but you can opt into localized - formatting and {fmt} makes it work with Unicode, addressing issues in the - standard libary. -
-
- The library makes extensive use of type erasure to achieve fast
- compilation. fmt/base.h
provides a subset of the API with
- minimal include dependencies and enough functionality to replace
- all uses of *printf
.
-
- Code using {fmt} is usually several times faster to compile than the
- equivalent iostreams code, and while printf
compiles faster
- still, the gap is narrowing.
-
- Type erasure is also used to prevent template bloat, resulting in compact
- per-call binary code. For example, a call to fmt::print
with
- a single argument is just a few
- instructions, comparable to printf
despite adding
- runtime safety, and much smaller than the equivalent iostreams code.
-
- The library itself has small binary footprint and some components such as - floating-point formatting can be disabled to make it even smaller for - resource-constrained devices. -
-- {fmt} has a small self-contained codebase with the core consisting of - just three headers and no external dependencies. -
-- The library is highly portable and requires only a minimal subset of - C++11 features which are available in GCC 4.8, Clang 3.4, MSVC 19.0 - (2015) and later. Newer compiler and standard library features are used - if available, and enable additional functionality. -
-- Where possible, the output of formatting functions is consistent across - platforms. -
- -- {fmt} is in the top hundred open-source C++ libraries on GitHub and has - hundreds of - all-time contributors. -
-- The library is distributed under a permissive MIT - license and is - relied upon by many open-source projects, including Blender, PyTorch, - Apple's FoundationDB, Windows Terminal, MongoDB, and others. -
-replacement_field ::= "{" [arg_id] [":" (format_spec | chrono_format_spec)] "}"
-arg_id ::= integer | identifier
-integer ::= digit+
-digit ::= "0"..."9"
-identifier ::= id_start id_continue*
-id_start ::= "a"..."z" | "A"..."Z" | "_"
-id_continue ::= id_start | digit
-
-
-In less formal terms, the replacement field can start with an *arg_id* that
-specifies the argument whose value is to be formatted and inserted into the
-output instead of the replacement field. The *arg_id* is optionally followed
-by a *format_spec*, which is preceded by a colon `':'`. These specify a
-non-default format for the replacement value.
-
-See also the [Format Specification
-Mini-Language](#format-specification-mini-language) section.
-
-If the numerical arg_ids in a format string are 0, 1, 2, ... in sequence,
-they can all be omitted (not just some) and the numbers 0, 1, 2, ... will be
-automatically inserted in that order.
-
-Named arguments can be referred to by their names or indices.
-
-Some simple format string examples:
-
-```c++
-"First, thou shalt count to {0}" // References the first argument
-"Bring me a {}" // Implicitly references the first argument
-"From {} to {}" // Same as "From {0} to {1}"
-```
-
-The *format_spec* field contains a specification of how the value should
-be presented, including such details as field width, alignment, padding,
-decimal precision and so on. Each value type can define its own
-"formatting mini-language" or interpretation of the *format_spec*.
-
-Most built-in types support a common formatting mini-language, which is
-described in the next section.
-
-A *format_spec* field can also include nested replacement fields in
-certain positions within it. These nested replacement fields can contain
-only an argument id; format specifications are not allowed. This allows
-the formatting of a value to be dynamically specified.
-
-See the [Format Examples](#format-examples) section for some examples.
-
-## Format Specification Mini-Language
-
-"Format specifications" are used within replacement fields contained within a
-format string to define how individual values are presented. Each formattable
-type may define how the format specification is to be interpreted.
-
-Most built-in types implement the following options for format
-specifications, although some of the formatting options are only
-supported by the numeric types.
-
-The general form of a *standard format specifier* is:
-
-
-format_spec ::= [[fill]align][sign]["#"]["0"][width]["." precision]["L"][type]
-fill ::= <a character other than '{' or '}'>
-align ::= "<" | ">" | "^"
-sign ::= "+" | "-" | " "
-width ::= integer | "{" [arg_id] "}"
-precision ::= integer | "{" [arg_id] "}"
-type ::= "a" | "A" | "b" | "B" | "c" | "d" | "e" | "E" | "f" | "F" |
- "g" | "G" | "o" | "p" | "s" | "x" | "X" | "?"
-
-
-The *fill* character can be any Unicode code point other than `'{'` or `'}'`.
-The presence of a fill character is signaled by the character following it,
-which must be one of the alignment options. If the second character of
-*format_spec* is not a valid alignment option, then it is assumed that both
-the fill character and the alignment option are absent.
-
-The meaning of the various alignment options is as follows:
-
-Option | -Meaning | -
---|---|
'<' |
- - Forces the field to be left-aligned within the available space (this is the - default for most objects). - | -
'>' |
- - Forces the field to be right-aligned within the available space (this is - the default for numbers). - | -
'^' |
- Forces the field to be centered within the available space. | -
Option | -Meaning | -
---|---|
'+' |
- - Indicates that a sign should be used for both nonnegative as well as - negative numbers. - | -
'-' |
- - Indicates that a sign should be used only for negative numbers (this is the - default behavior). - | -
space | -- Indicates that a leading space should be used on nonnegative numbers, and a - minus sign on negative numbers. - | -
Type | -Meaning | -
---|---|
's' |
- - String format. This is the default type for strings and may be omitted. - | -
'?' |
- Debug format. The string is quoted and special characters escaped. | -
none | -The same as 's' . |
-
Type | -Meaning | -
---|---|
'c' |
- - Character format. This is the default type for characters and may be - omitted. - | -
'?' |
- Debug format. The character is quoted and special characters escaped. | -
none | -The same as 'c' . |
-
Type | -Meaning | -
---|---|
'b' |
-
- Binary format. Outputs the number in base 2. Using the '#'
- option with this type adds the prefix "0b" to the output value.
- |
-
'B' |
-
- Binary format. Outputs the number in base 2. Using the '#'
- option with this type adds the prefix "0B" to the output value.
- |
-
'c' |
- Character format. Outputs the number as a character. | -
'd' |
- Decimal integer. Outputs the number in base 10. | -
'o' |
- Octal format. Outputs the number in base 8. | -
'x' |
-
- Hex format. Outputs the number in base 16, using lower-case letters for the
- digits above 9. Using the '#' option with this type adds the
- prefix "0x" to the output value.
- |
-
'X' |
-
- Hex format. Outputs the number in base 16, using upper-case letters for the
- digits above 9. Using the '#' option with this type adds the
- prefix "0X" to the output value.
- |
-
none | -The same as 'd' . |
-
Type | -Meaning | -
---|---|
'a' |
-
- Hexadecimal floating point format. Prints the number in base 16 with
- prefix "0x" and lower-case letters for digits above 9.
- Uses 'p' to indicate the exponent.
- |
-
'A' |
-
- Same as 'a' except it uses upper-case letters for the
- prefix, digits above 9 and to indicate the exponent.
- |
-
'e' |
- - Exponent notation. Prints the number in scientific notation using - the letter 'e' to indicate the exponent. - | -
'E' |
-
- Exponent notation. Same as 'e' except it uses an
- upper-case 'E' as the separator character.
- |
-
'f' |
- Fixed point. Displays the number as a fixed-point number. | -
'F' |
-
- Fixed point. Same as 'f' , but converts nan
- to NAN and inf to INF .
- |
-
'g' |
-
- General format. For a given precision A precision of |
-
'G' |
-
- General format. Same as 'g' except switches to
- 'E' if the number gets too large. The representations of
- infinity and NaN are uppercased, too.
- |
-
none | -
- Similar to 'g' , except that the default precision is as
- high as needed to represent the particular value.
- |
-
Type | -Meaning | -
---|---|
'p' |
- - Pointer format. This is the default type for pointers and may be omitted. - | -
none | -The same as 'p' . |
-
chrono_format_spec ::= [[fill]align][width]["." precision][chrono_specs]
-chrono_specs ::= conversion_spec |
- chrono_specs (conversion_spec | literal_char)
-conversion_spec ::= "%" [padding_modifier] [locale_modifier] chrono_type
-literal_char ::= <a character other than '{', '}' or '%'>
-padding_modifier ::= "-" | "_" | "0"
-locale_modifier ::= "E" | "O"
-chrono_type ::= "a" | "A" | "b" | "B" | "c" | "C" | "d" | "D" | "e" |
- "F" | "g" | "G" | "h" | "H" | "I" | "j" | "m" | "M" |
- "n" | "p" | "q" | "Q" | "r" | "R" | "S" | "t" | "T" |
- "u" | "U" | "V" | "w" | "W" | "x" | "X" | "y" | "Y" |
- "z" | "Z" | "%"
-
-
-Literal chars are copied unchanged to the output. Precision is valid only
-for `std::chrono::duration` types with a floating-point representation type.
-
-The available presentation types (*chrono_type*) are:
-
-Type | -Meaning | -
---|---|
'a' |
-
- The abbreviated weekday name, e.g. "Sat". If the value does not contain a
- valid weekday, an exception of type format_error is thrown.
- |
-
'A' |
-
- The full weekday name, e.g. "Saturday". If the value does not contain a
- valid weekday, an exception of type format_error is thrown.
- |
-
'b' |
-
- The abbreviated month name, e.g. "Nov". If the value does not contain a
- valid month, an exception of type format_error is thrown.
- |
-
'B' |
-
- The full month name, e.g. "November". If the value does not contain a valid
- month, an exception of type format_error is thrown.
- |
-
'c' |
-
- The date and time representation, e.g. "Sat Nov 12 22:04:00 1955". The
- modified command %Ec produces the locale's alternate date and
- time representation.
- |
-
'C' |
-
- The year divided by 100 using floored division, e.g. "19". If the result
- is a single decimal digit, it is prefixed with 0. The modified command
- %EC produces the locale's alternative representation of the
- century.
- |
-
'd' |
-
- The day of month as a decimal number. If the result is a single decimal
- digit, it is prefixed with 0. The modified command %Od
- produces the locale's alternative representation.
- |
-
'D' |
- Equivalent to %m/%d/%y , e.g. "11/12/55". |
-
'e' |
-
- The day of month as a decimal number. If the result is a single decimal
- digit, it is prefixed with a space. The modified command %Oe
- produces the locale's alternative representation.
- |
-
'F' |
- Equivalent to %Y-%m-%d , e.g. "1955-11-12". |
-
'g' |
- - The last two decimal digits of the ISO week-based year. If the result is a - single digit it is prefixed by 0. - | -
'G' |
- - The ISO week-based year as a decimal number. If the result is less than - four digits it is left-padded with 0 to four digits. - | -
'h' |
- Equivalent to %b , e.g. "Nov". |
-
'H' |
-
- The hour (24-hour clock) as a decimal number. If the result is a single
- digit, it is prefixed with 0. The modified command %OH
- produces the locale's alternative representation.
- |
-
'I' |
-
- The hour (12-hour clock) as a decimal number. If the result is a single
- digit, it is prefixed with 0. The modified command %OI
- produces the locale's alternative representation.
- |
-
'j' |
- - If the type being formatted is a specialization of duration, the decimal - number of days without padding. Otherwise, the day of the year as a decimal - number. Jan 1 is 001. If the result is less than three digits, it is - left-padded with 0 to three digits. - | -
'm' |
-
- The month as a decimal number. Jan is 01. If the result is a single digit,
- it is prefixed with 0. The modified command %Om produces the
- locale's alternative representation.
- |
-
'M' |
-
- The minute as a decimal number. If the result is a single digit, it
- is prefixed with 0. The modified command %OM produces the
- locale's alternative representation.
- |
-
'n' |
- A new-line character. | -
'p' |
- The AM/PM designations associated with a 12-hour clock. | -
'q' |
- The duration's unit suffix. | -
'Q' |
-
- The duration's numeric value (as if extracted via .count() ).
- |
-
'r' |
- The 12-hour clock time, e.g. "10:04:00 PM". | -
'R' |
- Equivalent to %H:%M , e.g. "22:04". |
-
'S' |
-
- Seconds as a decimal number. If the number of seconds is less than 10, the
- result is prefixed with 0. If the precision of the input cannot be exactly
- represented with seconds, then the format is a decimal floating-point number
- with a fixed format and a precision matching that of the precision of the
- input (or to a microseconds precision if the conversion to floating-point
- decimal seconds cannot be made within 18 fractional digits). The character
- for the decimal point is localized according to the locale. The modified
- command %OS produces the locale's alternative representation.
- |
-
't' |
- A horizontal-tab character. | -
'T' |
- Equivalent to %H:%M:%S . |
-
'u' |
-
- The ISO weekday as a decimal number (1-7), where Monday is 1. The modified
- command %Ou produces the locale's alternative representation.
- |
-
'U' |
-
- The week number of the year as a decimal number. The first Sunday of the
- year is the first day of week 01. Days of the same year prior to that are
- in week 00. If the result is a single digit, it is prefixed with 0.
- The modified command %OU produces the locale's alternative
- representation.
- |
-
'V' |
-
- The ISO week-based week number as a decimal number. If the result is a
- single digit, it is prefixed with 0. The modified command %OV
- produces the locale's alternative representation.
- |
-
'w' |
-
- The weekday as a decimal number (0-6), where Sunday is 0. The modified
- command %Ow produces the locale's alternative representation.
- |
-
'W' |
-
- The week number of the year as a decimal number. The first Monday of the
- year is the first day of week 01. Days of the same year prior to that are
- in week 00. If the result is a single digit, it is prefixed with 0.
- The modified command %OW produces the locale's alternative
- representation.
- |
-
'x' |
-
- The date representation, e.g. "11/12/55". The modified command
- %Ex produces the locale's alternate date representation.
- |
-
'X' |
-
- The time representation, e.g. "10:04:00". The modified command
- %EX produces the locale's alternate time representation.
- |
-
'y' |
-
- The last two decimal digits of the year. If the result is a single digit
- it is prefixed by 0. The modified command %Oy produces the
- locale's alternative representation. The modified command %Ey
- produces the locale's alternative representation of offset from
- %EC (year only).
- |
-
'Y' |
-
- The year as a decimal number. If the result is less than four digits it is
- left-padded with 0 to four digits. The modified command %EY
- produces the locale's alternative full year representation.
- |
-
'z' |
-
- The offset from UTC in the ISO 8601:2004 format. For example -0430 refers
- to 4 hours 30 minutes behind UTC. If the offset is zero, +0000 is used.
- The modified commands %Ez and %Oz insert a
- : between the hours and minutes: -04:30. If the offset
- information is not available, an exception of type
- format_error is thrown.
- |
-
'Z' |
-
- The time zone abbreviation. If the time zone abbreviation is not available,
- an exception of type format_error is thrown.
- |
-
'%' |
- A % character. | -
range_format_spec ::= ["n"][range_type][range_underlying_spec]
-
-
-The `'n'` option formats the range without the opening and closing brackets.
-
-The available presentation types for `range_type` are:
-
-| Type | Meaning |
-|--------|------------------------------------------------------------|
-| none | Default format. |
-| `'s'` | String format. The range is formatted as a string. |
-| `'?s'` | Debug format. The range is formatted as an escaped string. |
-
-If `range_type` is `'s'` or `'?s'`, the range element type must be a character
-type. The `'n'` option and `range_underlying_spec` are mutually exclusive with
-`'s'` and `'?s'`.
-
-The `range_underlying_spec` is parsed based on the formatter of the range's
-element type.
-
-By default, a range of characters or strings is printed escaped and quoted.
-But if any `range_underlying_spec` is provided (even if it is empty), then the
-characters or strings are printed according to the provided specification.
-
-Examples:
-
-```c++
-fmt::print("{}", std::vector{10, 20, 30});
-// Output: [10, 20, 30]
-fmt::print("{::#x}", std::vector{10, 20, 30});
-// Output: [0xa, 0x14, 0x1e]
-fmt::print("{}", std::vector{'h', 'e', 'l', 'l', 'o'});
-// Output: ['h', 'e', 'l', 'l', 'o']
-fmt::print("{:n}", std::vector{'h', 'e', 'l', 'l', 'o'});
-// Output: 'h', 'e', 'l', 'l', 'o'
-fmt::print("{:s}", std::vector{'h', 'e', 'l', 'l', 'o'});
-// Output: "hello"
-fmt::print("{:?s}", std::vector{'h', 'e', 'l', 'l', 'o', '\n'});
-// Output: "hello\n"
-fmt::print("{::}", std::vector{'h', 'e', 'l', 'l', 'o'});
-// Output: [h, e, l, l, o]
-fmt::print("{::d}", std::vector{'h', 'e', 'l', 'l', 'o'});
-// Output: [104, 101, 108, 108, 111]
-```
-
-## Format Examples
-
-This section contains examples of the format syntax and comparison with
-the printf formatting.
-
-In most of the cases the syntax is similar to the printf formatting,
-with the addition of the `{}` and with `:` used instead of `%`. For
-example, `"%03.2f"` can be translated to `"{:03.2f}"`.
-
-The new format syntax also supports new and different options, shown in
-the following examples.
-
-Accessing arguments by position:
-
-```c++
-fmt::format("{0}, {1}, {2}", 'a', 'b', 'c');
-// Result: "a, b, c"
-fmt::format("{}, {}, {}", 'a', 'b', 'c');
-// Result: "a, b, c"
-fmt::format("{2}, {1}, {0}", 'a', 'b', 'c');
-// Result: "c, b, a"
-fmt::format("{0}{1}{0}", "abra", "cad"); // arguments' indices can be repeated
-// Result: "abracadabra"
-```
-
-Aligning the text and specifying a width:
-
-```c++
-fmt::format("{:<30}", "left aligned");
-// Result: "left aligned "
-fmt::format("{:>30}", "right aligned");
-// Result: " right aligned"
-fmt::format("{:^30}", "centered");
-// Result: " centered "
-fmt::format("{:*^30}", "centered"); // use '*' as a fill char
-// Result: "***********centered***********"
-```
-
-Dynamic width:
-
-```c++
-fmt::format("{:<{}}", "left aligned", 30);
-// Result: "left aligned "
-```
-
-Dynamic precision:
-
-```c++
-fmt::format("{:.{}f}", 3.14, 1);
-// Result: "3.1"
-```
-
-Replacing `%+f`, `%-f`, and `% f` and specifying a sign:
-
-```c++
-fmt::format("{:+f}; {:+f}", 3.14, -3.14); // show it always
-// Result: "+3.140000; -3.140000"
-fmt::format("{: f}; {: f}", 3.14, -3.14); // show a space for positive numbers
-// Result: " 3.140000; -3.140000"
-fmt::format("{:-f}; {:-f}", 3.14, -3.14); // show only the minus -- same as '{:f}; {:f}'
-// Result: "3.140000; -3.140000"
-```
-
-Replacing `%x` and `%o` and converting the value to different bases:
-
-```c++
-fmt::format("int: {0:d}; hex: {0:x}; oct: {0:o}; bin: {0:b}", 42);
-// Result: "int: 42; hex: 2a; oct: 52; bin: 101010"
-// with 0x or 0 or 0b as prefix:
-fmt::format("int: {0:d}; hex: {0:#x}; oct: {0:#o}; bin: {0:#b}", 42);
-// Result: "int: 42; hex: 0x2a; oct: 052; bin: 0b101010"
-```
-
-Padded hex byte with prefix and always prints both hex characters:
-
-```c++
-fmt::format("{:#04x}", 0);
-// Result: "0x00"
-```
-
-Box drawing using Unicode fill:
-
-```c++
-fmt::print(
- "┌{0:─^{2}}┐\n"
- "│{1: ^{2}}│\n"
- "└{0:─^{2}}┘\n", "", "Hello, world!", 20);
-```
-
-prints:
-
-```
-┌────────────────────┐
-│ Hello, world! │
-└────────────────────┘
-```
-
-Using type-specific formatting:
-
-```c++
-#include ' if tag == 'pre' else ''
- if n.text:
- out += escape_html(n.text)
- out += doxyxml2html(n)
- out += '
' if tag == 'pre' else ''
- out += '' + tag + '>' if tag else ''
- if n.tail:
- out += n.tail
- return out
-
-def convert_template_params(node: et.Element) -> Optional[List[Definition]]:
- templateparamlist = node.find('templateparamlist')
- if templateparamlist is None:
- return None
- params = []
- for param_node in templateparamlist.findall('param'):
- name = param_node.find('declname')
- param = Definition(name.text if name is not None else '', 'param')
- param.type = param_node.find('type').text
- params.append(param)
- return params
-
-def get_description(node: et.Element) -> List[et.Element]:
- return node.findall('briefdescription/para') + \
- node.findall('detaileddescription/para')
-
-def normalize_type(type: str) -> str:
- type = type.replace('< ', '<').replace(' >', '>')
- return type.replace(' &', '&').replace(' *', '*')
-
-def convert_type(type: et.Element) -> str:
- if type is None:
- return None
- result = type.text if type.text else ''
- for ref in type:
- result += ref.text
- if ref.tail:
- result += ref.tail
- result += type.tail.strip()
- return normalize_type(result)
-
-def convert_params(func: et.Element) -> Definition:
- params = []
- for p in func.findall('param'):
- d = Definition(p.find('declname').text, 'param')
- d.type = convert_type(p.find('type'))
- params.append(d)
- return params
-
-def convert_return_type(d: Definition, node: et.Element) -> None:
- d.trailing_return_type = None
- if d.type == 'auto' or d.type == 'constexpr auto':
- parts = node.find('argsstring').text.split(' -> ')
- if len(parts) > 1:
- d.trailing_return_type = normalize_type(parts[1])
-
-def render_param(param: Definition) -> str:
- return param.type + (f' {param.name}' if len(param.name) > 0 else '')
-
-def render_decl(d: Definition) -> None:
- text = ''
- if d.id is not None:
- text += f'\n'
- text += ''
-
- text += ''
- if d.template_params is not None:
- text += 'template <'
- text += ', '.join([render_param(p) for p in d.template_params])
- text += '>\n'
- text += ''
-
- text += ''
- end = ';'
- if d.kind == 'function' or d.kind == 'variable':
- text += d.type + ' ' if len(d.type) > 0 else ''
- elif d.kind == 'typedef':
- text += 'using '
- elif d.kind == 'define':
- end = ''
- else:
- text += d.kind + ' '
- text += d.name
-
- if d.params is not None:
- params = ', '.join([
- (p.type + ' ' if p.type else '') + p.name for p in d.params])
- text += '(' + escape_html(params) + ')'
- if d.trailing_return_type:
- text += ' -⁠> ' + escape_html(d.trailing_return_type)
- elif d.kind == 'typedef':
- text += ' = ' + escape_html(d.type)
-
- text += end
- text += ''
- text += '
\n'
- if d.id is not None:
- text += f'\n'
- return text
-
-class CxxHandler(BaseHandler):
- def __init__(self, **kwargs: Any) -> None:
- super().__init__(handler='cxx', **kwargs)
-
- headers = [
- 'args.h', 'base.h', 'chrono.h', 'color.h', 'compile.h', 'format.h',
- 'os.h', 'ostream.h', 'printf.h', 'ranges.h', 'std.h', 'xchar.h'
- ]
-
- # Run doxygen.
- cmd = ['doxygen', '-']
- support_dir = Path(__file__).parents[3]
- top_dir = os.path.dirname(support_dir)
- include_dir = os.path.join(top_dir, 'include', 'fmt')
- self._ns2doxyxml = {}
- build_dir = os.path.join(top_dir, 'build')
- os.makedirs(build_dir, exist_ok=True)
- self._doxyxml_dir = os.path.join(build_dir, 'doxyxml')
- p = Popen(cmd, stdin=PIPE, stdout=PIPE, stderr=STDOUT)
- _, _ = p.communicate(input=r'''
- PROJECT_NAME = fmt
- GENERATE_XML = YES
- GENERATE_LATEX = NO
- GENERATE_HTML = NO
- INPUT = {0}
- XML_OUTPUT = {1}
- QUIET = YES
- AUTOLINK_SUPPORT = NO
- MACRO_EXPANSION = YES
- PREDEFINED = _WIN32=1 \
- __linux__=1 \
- FMT_ENABLE_IF(...)= \
- FMT_USE_USER_DEFINED_LITERALS=1 \
- FMT_USE_ALIAS_TEMPLATES=1 \
- FMT_USE_NONTYPE_TEMPLATE_ARGS=1 \
- FMT_API= \
- "FMT_BEGIN_NAMESPACE=namespace fmt {{" \
- "FMT_END_NAMESPACE=}}" \
- "FMT_DOC=1"
- '''.format(
- ' '.join([os.path.join(include_dir, h) for h in headers]),
- self._doxyxml_dir).encode('utf-8'))
- if p.returncode != 0:
- raise CalledProcessError(p.returncode, cmd)
-
- # Merge all file-level XMLs into one to simplify search.
- self._file_doxyxml = None
- for h in headers:
- filename = h.replace(".h", "_8h.xml")
- with open(os.path.join(self._doxyxml_dir, filename)) as f:
- doxyxml = et.parse(f)
- if self._file_doxyxml is None:
- self._file_doxyxml = doxyxml
- continue
- root = self._file_doxyxml.getroot()
- for node in doxyxml.getroot():
- root.append(node)
-
- def collect_compound(self, identifier: str,
- cls: List[et.Element]) -> Definition:
- '''Collect a compound definition such as a struct.'''
- path = os.path.join(self._doxyxml_dir, cls[0].get('refid') + '.xml')
- with open(path) as f:
- xml = et.parse(f)
- node = xml.find('compounddef')
- d = Definition(identifier, node=node)
- d.template_params = convert_template_params(node)
- d.desc = get_description(node)
- d.members = []
- for m in node.findall('sectiondef[@kind="public-attrib"]/memberdef') + \
- node.findall('sectiondef[@kind="public-func"]/memberdef'):
- name = m.find('name').text
- # Doxygen incorrectly classifies members of private unnamed unions as
- # public members of the containing class.
- if name.endswith('_'):
- continue
- desc = get_description(m)
- if len(desc) == 0:
- continue
- kind = m.get('kind')
- member = Definition(name if name else '', kind=kind, is_member=True)
- type = m.find('type').text
- member.type = type if type else ''
- if kind == 'function':
- member.params = convert_params(m)
- convert_return_type(member, m)
- member.template_params = None
- member.desc = desc
- d.members.append(member)
- return d
-
- def collect(self, identifier: str, config: Mapping[str, Any]) -> Definition:
- qual_name = 'fmt::' + identifier
-
- param_str = None
- paren = qual_name.find('(')
- if paren > 0:
- qual_name, param_str = qual_name[:paren], qual_name[paren + 1:-1]
-
- colons = qual_name.rfind('::')
- namespace, name = qual_name[:colons], qual_name[colons + 2:]
-
- # Load XML.
- doxyxml = self._ns2doxyxml.get(namespace)
- if doxyxml is None:
- path = f'namespace{namespace.replace("::", "_1_1")}.xml'
- with open(os.path.join(self._doxyxml_dir, path)) as f:
- doxyxml = et.parse(f)
- self._ns2doxyxml[namespace] = doxyxml
-
- nodes = doxyxml.findall(
- f"compounddef/sectiondef/memberdef/name[.='{name}']/..")
- if len(nodes) == 0:
- nodes = self._file_doxyxml.findall(
- f"compounddef/sectiondef/memberdef/name[.='{name}']/..")
- candidates = []
- for node in nodes:
- # Process a function or a typedef.
- params = None
- d = Definition(name, node=node)
- if d.kind == 'function':
- params = convert_params(node)
- node_param_str = ', '.join([p.type for p in params])
- if param_str and param_str != node_param_str:
- candidates.append(f'{name}({node_param_str})')
- continue
- elif d.kind == 'define':
- params = []
- for p in node.findall('param'):
- param = Definition(p.find('defname').text, kind='param')
- param.type = None
- params.append(param)
- d.type = convert_type(node.find('type'))
- d.template_params = convert_template_params(node)
- d.params = params
- convert_return_type(d, node)
- d.desc = get_description(node)
- return d
-
- cls = doxyxml.findall(f"compounddef/innerclass[.='{qual_name}']")
- if not cls:
- raise Exception(f'Cannot find {identifier}. Candidates: {candidates}')
- return self.collect_compound(identifier, cls)
-
- def render(self, d: Definition, config: dict) -> str:
- if d.id is not None:
- self.do_heading('', 0, id=d.id)
- text = '