A C format string such as "%d bytes" depends on the machine when it holds a
type of the C library whose conversion differs from system to system. A translator writes
the conversion of a type of inttypes.h as <PRIuMAX>, for
instance "%<PRIuMAX> bytes", and msgfmt then stores the
string in pieces. The loader joins them with the conversion of the machine it runs on.
Catalogues with such strings have minor revision 1; this page is that part of the
format. Nothing here is in a revision 0 file.
Which strings use it: the message pairs that carry a c-format or
objc-format flag and hold a <PRI…> directive.
The segment table
At sysdep_segments_offset are n_sysdep_segments descriptors of
8 bytes: the length of a name, counting its NUL, and its
offset. Each name appears once, however many strings use it, and ends in
a NUL. The names the loader understands:
| Name | Meaning |
|---|---|
PRI, a conversion letter, then a width | The conversion specifier of the C library for an integer type of inttypes.h. The letter is d, i, o, u, x or X; the width is 8, 16, 32, 64, LEAST… or FAST… followed by a size, MAX or PTR. PRIuMAX is the one in the examples. |
I | The flag character I of the C library’s printf, when the library has it; otherwise an empty string. |
A name the loader does not know has no value, and the strings that use it are dropped. The loader also checks that every segment number in a pair is inside the table, that each name ends in a NUL, and that the last static piece of a string ends in one.
The string descriptors
At orig_sysdep_tab_offset and trans_sysdep_tab_offset are two
tables of n_sysdep_strings 32-bit numbers each. A number is the offset of a
descriptor, and the one in the first table belongs to the one in the second with the
same index. A descriptor is:
| Size | Field |
|---|---|
| 4 | offset: where the static pieces of the string are, one after another |
| 8 each | A segment pair: segsize, the number of bytes of the next static piece, and sysdepref, the number of the system-dependent segment to put after it. The last pair has sysdepref 0xFFFFFFFF, and its piece includes the NUL that ends the string. |
The string is rebuilt as the first static piece, the value of the first segment, the next static piece, and so on. The pieces are in the string area of the file and the descriptors can lie anywhere, since every offset is explicit.
The strings join the others for lookup: the loader gives them the numbers N, N + 1 and on, and adds them to its hash table in memory.
The plain expansions
So that readers that do not know revision 1 still find the strings,
msgfmt also writes each system-dependent pair, as ordinary pairs, expanded
for the two common ways the type is written (for PRIuMAX, llu
and lu). It adds one only if its original is not in the catalogue already.
The option --no-redundancy leaves them out.
Worked example
From msgfmt 1.0, for a header entry, the pair "%<PRIuMAX> bytes" →
"%<PRIuMAX> octets" and the pair “plain”, with the plain expansions left
in. The header is 48 bytes and starts DE 12 04 95 01 00 00 00: revision 1.
N is 4: the header entry, “plain”, and the two expansions %llu bytes and
%lu bytes.
| Offset | Value | Meaning |
|---|---|---|
0x1C | 1 | One system-dependent segment. |
0x20 | 0x8C | The segment table: length 8, offset 0x127, the name PRIuMAX and its NUL. |
0x24 | 1 | One system-dependent string pair. |
0x28 | 0x94 | The table of original descriptors: one number, 0x9C. |
0x2C | 0x98 | The table of translation descriptors: one number, 0xB0. |
0x9C | 0x12F; (1, 0); (7, 0xFFFFFFFF) | The original: static pieces at 0x12F, % (1 byte), then segment 0, PRIuMAX, then bytes and its NUL (7 bytes). |
0xB0 | 0x137; (1, 0); (8, 0xFFFFFFFF) | The translation: %, segment 0, then octets and its NUL (8 bytes). |
On a machine where PRIuMAX is llu, the original reads
%llu bytes, which is also one of the ordinary pairs. The hash table, of size
7 for 5 strings, holds only the four ordinary pairs.
Not described
Known, not yet covered
- Reference: the value of each segment name on each system (the
loader asks the C library for it), and the second way of expanding a type that
msgfmtuses for the plain pairs beyond thePRIuMAXexample (the writer’s source shows two rules; only the example was run). - Reference: what major revision 1 changes for the
Isegment, beyond the loader accepting it.