#!/usr/bin/env dub
/+ dub.sdl:
name "autological_binfmt_magic_match"
targetPath "build"
dflags "-preview=in" "-preview=dip1000"
buildType "checked" {
buildOptions "optimize" "inline" "debugInfo"
}
+/
/**
* `binfmt_misc` registration strings, parsed and evaluated the way the kernel does.
*
* `fs/binfmt_misc.c` turns a line of the form
*
* :name:type:offset:magic:mask:interpreter:flags
*
* into a predicate over the first bytes of a file. This program implements that
* predicate — including the `\xNN` escaping of `magic`/`mask` and the
* mask-is-optional rule — and evaluates a small registration table against a
* set of specimen buffers, so the *dispatch* half of the catalog's thesis is
* executable rather than described.
*
* The registrations included are the ones the catalog argues about:
*
* - `qemu-aarch64` — the canonical `E_MACHINE`-masked ELF rule, and the
* reason the `F` (fix binary) flag exists: without it the interpreter is
* resolved in the mount namespace of the *process being executed*, so a
* container without the interpreter inside it cannot run foreign binaries.
* - `self` — magic at **offset 68**, which is a field SQLite has
* promised never to interpret (see `sqlite-header-probe.d`). This is the
* whole dispatch story for SELF: no new format, one kernel rule.
* - `jar` — `PK\x03\x04` at offset 0, the rule that made GIFAR
* interesting, because a JAR is located by its *footer* while `binfmt_misc`
* matches on its *header*.
*
* If `/proc/sys/fs/binfmt_misc` is mounted and readable, the program also parses
* the host's live registrations through the same code, which is the honest test:
* the parser either handles what the kernel actually emitted, or it does not.
*
* Companions:
* docs/research/autological-artifacts/binfmt-misc.md
* docs/research/autological-artifacts/self-selfdb/index.md
* docs/research/autological-artifacts/parser-differentials.md
*
* Run with: `dub run --single binfmt-magic-match.d`
*
* Portability: the parser and matcher are pure `std` and run everywhere; the
* live-registration read is Linux-only and prints a `SKIP:` line elsewhere (or
* when `binfmt_misc` is not mounted), still exiting 0.
*/
module (module) autological_binfmt_magic_matchbinfmt_misc registration strings, parsed and evaluated the way the kernel does.
fs/binfmt_misc.c turns a line of the form
:name:type:offset:magic:mask:interpreter:flags
into a predicate over the first bytes of a file. This program implements that
predicate — including the \xNN escaping of magic/mask and the
mask-is-optional rule — and evaluates a small registration table against a
set of specimen buffers, so the dispatch half of the catalog's thesis is
executable rather than described.
The registrations included are the ones the catalog argues about:
qemu-aarch64 — the canonical E_MACHINE-masked ELF rule, and the
reason the F (fix binary) flag exists: without it the interpreter is
resolved in the mount namespace of the process being executed, so a
container without the interpreter inside it cannot run foreign binaries.
self — magic at offset 68, which is a field SQLite has
promised never to interpret (see sqlite-header-probe.d). This is the
whole dispatch story for SELF: no new format, one kernel rule.
jar — PK\x03\x04 at offset 0, the rule that made GIFAR
interesting, because a JAR is located by its footer while binfmt_misc
matches on its header.
If /proc/sys/fs/binfmt_misc is mounted and readable, the program also parses
the host's live registrations through the same code, which is the honest test:
the parser either handles what the kernel actually emitted, or it does not.
Companions
docs/research/autological-artifacts/binfmt-misc.md
docs/research/autological-artifacts/self-selfdb/index.md
docs/research/autological-artifacts/parser-differentials.md
Run with: dub run --single binfmt-magic-match.d
Portability
the parser and matcher are pure std and run everywhere; the
live-registration read is Linux-only and prints a SKIP: line elsewhere (or
when binfmt_misc is not mounted), still exiting 0.
autological_binfmt_magic_match;
import (package) stdstd.(module) std.algorithmThis package implements generic algorithms oriented towards the processing of
sequences. Sequences processed by these functions define range-based
interfaces. See also Reference on ranges and
tutorial on ranges.
Algorithms are categorized into the following submodules:
Submodule Functions
| Searching |
all
any
balancedParens
boyerMooreFinder
canFind
commonPrefix
count
countUntil
endsWith
find
findAdjacent
findAmong
findSkip
findSplit
findSplitAfter
findSplitBefore
minCount
maxCount
minElement
maxElement
minIndex
maxIndex
minPos
maxPos
skipOver
startsWith
until
|
| Comparison |
among
castSwitch
clamp
cmp
either
equal
isPermutation
isSameLength
levenshteinDistance
levenshteinDistanceAndPath
max
min
mismatch
predSwitch
|
| Iteration |
cache
cacheBidirectional
chunkBy
cumulativeFold
each
filter
filterBidirectional
fold
group
joiner
map
mean
permutations
reduce
splitWhen
splitter
substitute
sum
uniq
|
| Sorting |
completeSort
isPartitioned
isSorted
isStrictlyMonotonic
ordered
strictlyOrdered
makeIndex
merge
multiSort
nextEvenPermutation
nextPermutation
nthPermutation
partialSort
partition
partition3
schwartzSort
sort
topN
topNCopy
topNIndex
|
| Set operations (setops) |
cartesianProduct
largestPartialIntersection
largestPartialIntersectionWeighted
multiwayMerge
multiwayUnion
setDifference
setIntersection
setSymmetricDifference
|
| Mutation |
bringToFront
copy
fill
initializeAll
move
moveAll
moveSome
moveEmplace
moveEmplaceAll
moveEmplaceSome
remove
reverse
strip
stripLeft
stripRight
swap
swapRanges
uninitializedFill
|
Many functions in this package are parameterized with a predicate.
The predicate may be any suitable callable type
(a function, a delegate, a functor, or a lambda), or a
compile-time string. The string may consist of any legal D
expression that uses the symbol a (for unary functions) or the
symbols a and b (for binary functions). These names will NOT
interfere with other homonym symbols in user code because they are
evaluated in a different context. The default for all binary
comparison predicates is "a == b" for unordered operations and
"a < b" for ordered operations.
Example
int[] a = ...;
static bool greater(int a, int b)
{
return a > b;
}
sort!greater(a); // predicate as alias
sort!((a, b) => a > b)(a); // predicate as a lambda.
sort!"a > b"(a); // predicate as string
// (no ambiguity with array name)
sort(a); // no predicate, "a < b" is implicit
Source
std/algorithm/package.d
algorithm : (alias template) autological_binfmt_magic_match.filter = std.algorithm.iteration.filter(alias predicate) if (is(typeof(unaryFun!predicate)))``filter!(predicate)(range) returns a new range containing only elements x in range for
which predicate(x) returns true.
The predicate is passed to unaryFun, and can be either a string, or
any callable that can be executed via pred(element).
filter, (alias template) autological_binfmt_magic_match.map = std.algorithm.iteration.map(fun...) if (fun.length >= 1)Implements the homonym function (also known as transform) present
in many languages of functional flavor. The call ``map!(fun)(range)
returns a range of which elements are obtained by applying fun(a)
left to right for all elements a in range. The original ranges are
not changed. Evaluation is done lazily.
map, (alias template) autological_binfmt_magic_match.startsWith = std.algorithm.searching.startsWith(alias pred = (a, b) => a == b, Range, Needles...)(Range doesThisStart, Needles withOneOfThese) if (isInputRange!Range && (Needles.length > 1) && allSatisfy!(canTestStartsWith!(pred, Range), Needles))Checks whether the given
input range starts with (one
of) the given needle(s) or, if no needles are given,
if its front element fulfils predicate pred.
For more information about pred see find.
startsWith;
import (package) stdstd.(module) std.arrayFunctions and types that manipulate built-in arrays and associative arrays.
This module provides all kinds of functions to create, manipulate or convert arrays:
Function Name Description
| array |
Returns a copy of the input in a newly allocated dynamic array.
|
| appender |
Returns a new Appender or RefAppender initialized with a given array.
|
| assocArray |
Returns a newly allocated associative array from a range/ranges of keys and values.
|
| byPair |
Construct a range iterating over an associative array by key/value tuples.
|
| insertInPlace |
Inserts into an existing array at a given position.
|
| join |
Concatenates a range of ranges into one array.
|
| minimallyInitializedArray |
Returns a new array of type T.
|
| replace |
Returns a new array with all occurrences of a certain subrange replaced.
|
| replaceFirst |
Returns a new array with the first occurrence of a certain subrange replaced.
|
| replaceInPlace |
Replaces all occurrences of a certain subrange and puts the result into a given array.
|
| replaceInto |
Replaces all occurrences of a certain subrange and puts the result into an output range.
|
| replaceLast |
Returns a new array with the last occurrence of a certain subrange replaced.
|
| replaceSlice |
Returns a new array with a given slice replaced.
|
| replicate |
Creates a new array out of several copies of an input array or range.
|
| sameHead |
Checks if the initial segments of two arrays refer to the same
place in memory.
|
| sameTail |
Checks if the final segments of two arrays refer to the same place
in memory.
|
| split |
Eagerly split a range or string into an array.
|
| staticArray |
Creates a new static array from given data.
|
| uninitializedArray |
Returns a new array of type T without initializing its elements.
|
Source
std/array.d
array : (alias template) autological_binfmt_magic_match.array = std.array.array(Range)(Range r) if (isIterable!Range && !isAutodecodableString!Range && !isInfinite!Range)Allocates an array and initializes it with copies of the elements
of range r.
Narrow strings are handled as follows:
If autodecoding is turned on (default), then they are handled as a separate overload.
If autodecoding is turned off, then this is equivalent to duplicating the array.
array, (alias template) autological_binfmt_magic_match.split = std.array.split(S)(S s) if (isSomeString!S)Eagerly splits range into an array, using sep as the delimiter.
When no delimiter is provided, strings are split into an array of words,
using whitespace as delimiter.
Runs of whitespace are merged together (no empty words are produced).
The range must be a forward range.
The separator can be a value of the same type as the elements in range
or it can be another forward range.
split;
import (package) stdstd.(module) std.convA one-stop shop for converting values from one type to another.
Category Functions Generic asOriginalType castFrom parse to toChars bitCast Strings text wtext dtext writeText writeWText writeDText hexString Numeric octal roundTo signed unsigned Exceptions ConvException ConvOverflowException
Source
std/conv.d
conv : (alias template) autological_binfmt_magic_match.text = std.conv.text(T...)(T args) if (T.length > 0)Convenience functions for converting one or more arguments
of any type into text (the three character widths).
text, (alias template) autological_binfmt_magic_match.to = std.conv.to(T)The to template converts a value from one type to another.
The source type is deduced and the target type must be specified, for example the
expression to`!int(42.0)` converts the number 42 from
`double` to `int`. The conversion is "safe", i.e.,
it checks for overflow; to!int(4.2e10) would throw the
ConvOverflowException exception. Overflow checks are only
inserted when necessary, e.g., ``to!double(42) does not do
any checking because any int fits in a double.
Conversions from string to numeric types differ from the C equivalents
atoi() and atol() by checking for overflow and not allowing whitespace.
For conversion of strings to signed types, the grammar recognized is:
Integer:
Sign UnsignedInteger
UnsignedInteger
Sign:
+
-
For conversion to unsigned types, the grammar recognized is:
UnsignedInteger:
DecimalDigit
DecimalDigit UnsignedInteger
to;
import (package) stdstd.(module) std.fileUtilities for manipulating files and scanning directories. Functions
in this module handle files as a unit, e.g., read or write one file
at a time. For opening files and manipulating them via handles refer
to module std.stdio.
Category Functions General exists isDir isFile isSymlink rename thisExePath Directories chdir dirEntries getcwd mkdir mkdirRecurse rmdir rmdirRecurse tempDir Files append copy read readText remove slurp write Symlinks symlink readLink Attributes attrIsDir attrIsFile attrIsSymlink getAttributes getLinkAttributes getSize setAttributes Timestamp getTimes getTimesWin setTimes timeLastModified timeLastAccessed timeStatusChanged Other DirEntry FileException PreserveAttributes SpanMode getAvailableDiskSpace
Source
std/file.d
file : (alias template) autological_binfmt_magic_match.dirEntries = std.file.dirEntries(bool useDIP1000 = dip1000Enabled)(string path, SpanMode mode, bool followSymlink = true)Returns an input range
of DirEntry that lazily iterates a given directory,
also provides two ways of foreach iteration. The iteration variable can be of
type string if only the name is needed, or DirEntry
if additional details are needed. The span mode dictates how the
directory is traversed. The name of each iterated directory entry
contains the absolute or relative path (depending on pathname).
Note
The order of returned directory entries is as it is provided by the
operating system / filesystem, and may not follow any particular sorting.
Example
// Iterate a directory in depth
foreach (string name; dirEntries("destroy/me", SpanMode.depth))
{
remove(name);
}
// Iterate the current directory in breadth
foreach (string name; dirEntries("", SpanMode.breadth))
{
writeln(name);
}
// Iterate a directory and get detailed info about it
foreach (DirEntry e; dirEntries("dmd-testing", SpanMode.breadth))
{
writeln(e.name, "\t", e.size);
}
// Iterate over all *.d files in current directory and all its subdirectories
auto dFiles = dirEntries("", SpanMode.depth).filter!(f => f.name.endsWith(".d"));
foreach (d; dFiles)
writeln(d.name);
// Hook it up with std.parallelism to compile them all in parallel:
foreach (d; parallel(dFiles, 1)) //passes by 1 file to each thread
{
string cmd = "dmd -c " ~ d.name;
writeln(cmd);
std.process.executeShell(cmd);
}
// Iterate over all D source files in current directory and all its
// subdirectories
auto dFiles = dirEntries("","*.{d,di}",SpanMode.depth);
foreach (d; dFiles)
writeln(d.name);
To handle subdirectories with denied read permission, use SpanMode.shallow:
void scan(string path)
{
foreach (DirEntry entry; dirEntries(path, SpanMode.shallow))
{
try
{
writeln(entry.name);
if (entry.isDir)
scan(entry.name);
}
catch (FileException fe) { continue; } // ignore
}
}
scan("");
dirEntries, (alias template) autological_binfmt_magic_match.exists = std.file.exists(R)(R name) if (isSomeFiniteCharInputRange!R && !isConvertibleToString!R)Determine whether the given file (or directory) exists.
exists, (alias template) autological_binfmt_magic_match.isDir = std.file.isDir(R)(R name) if (isSomeFiniteCharInputRange!R && !isConvertibleToString!R)Returns whether the given file is a directory.
isDir, (alias template) autological_binfmt_magic_match.readText = std.file.readText(S = string, R)(auto ref R name) if (isSomeString!S && (isSomeFiniteCharInputRange!R || is(StringTypeOf!R)))Reads and validates (using validate) a text file. S can be
an array of any character type. However, no width or endian conversions are
performed. So, if the width or endianness of the characters in the given
file differ from the width or endianness of the element type of S, then
validation will fail.
readText, (enum) std.file.SpanModeDictates directory spanning policy for dirEntries (see below).
Examples
import std.algorithm.comparison : equal;
import std.algorithm.iteration : map;
import std.algorithm.sorting : sort;
import std.array : array;
import std.path : buildPath, relativePath;
auto root = deleteme ~ "root";
scope(exit) root.rmdirRecurse;
root.mkdir;
root.buildPath("animals").mkdir;
root.buildPath("animals", "cat").mkdir;
alias removeRoot = (return scope e) => e.relativePath(root);
assert(root.dirEntries(SpanMode.depth).map!removeRoot.equal(
[buildPath("animals", "cat"), "animals"]));
assert(root.dirEntries(SpanMode.breadth).map!removeRoot.equal(
["animals", buildPath("animals", "cat")]));
root.buildPath("plants").mkdir;
assert(root.dirEntries(SpanMode.shallow).array.sort.map!removeRoot.equal(
["animals", "plants"]));
SpanMode;
import (package) stdstd.(module) std.stdioCategory Symbols File handles _popen File isFileHandle openNetwork stderr stdin stdout Reading chunks lines readf readfln readln Writing toFile write writef writefln writeln Misc KeepTerminator LockType StdioException
Standard I/O functions that extend core.stdc.stdio. core.stdc.stdio
is publically imported when importing std.stdio.
There are three layers of I/O:
The lowest layer is the operating system layer. The two main schemes are Windows and Posix.
C's stdio.h which unifies the two operating system schemes.
std.stdio, this module, unifies the various stdio.h implementations into
a high level package for D programs.
Source
std/stdio.d
stdio : (alias template) autological_binfmt_magic_match.writefln = std.stdio.writefln(alias fmt, A...)(A args) if (isSomeString!(typeof(fmt)))Equivalent to writef(fmt, args, '\n').
writefln, (alias template) autological_binfmt_magic_match.writeln = std.stdio.writeln(T...)(T args)Equivalent to write(args, '\n'). Calling writeln without
arguments is valid and just prints a newline to the standard
output.
Example
Reads stdin and writes it to stdout with an argument
counter.
import std.stdio;
void main()
{
string line;
for (size_t count = 0; (line = readln) !is null; count++)
{
writeln("Input ", count, ": ", line);
}
}
writeln;
import (package) stdstd.(module) std.stringString handling functions.
Category Functions Searching column indexOf indexOfAny indexOfNeither lastIndexOf lastIndexOfAny lastIndexOfNeither Comparison isNumeric Mutation capitalize Pruning and Filling center chomp chompPrefix chop detabber detab entab entabber leftJustify outdent rightJustify strip stripLeft stripRight wrap Substitution abbrev soundex soundexer succ tr translate Miscellaneous assumeUTF fromStringz lineSplitter representation splitLines toStringz Objects of types string, wstring, and dstring are value types and cannot be mutated element-by-element. For using mutation during building strings, use char[], wchar[], or dchar[]. The xxxstring types are preferable because they don't exhibit undesired aliasing, thus making code more robust.
The following functions are publicly imported:
Module Functions Publicly imported functions std.algorithm cmp, std,algorithm,comparison count, std,algorithm,searching endsWith, std,algorithm,searching startsWith, std,algorithm,searching std.array join, std,array replace, std,array replaceInPlace, std,array split, std,array empty, std,array std.format format, std,format sformat, std,format std.uni icmp, std,uni toLower, std,uni toLowerInPlace, std,uni toUpper, std,uni toUpperInPlace, std,uni There is a rich set of functions for string handling defined in other modules. Functions related to Unicode and ASCII are found in std.uni and std.ascii, respectively. Other functions that have a wider generality than just strings can be found in std.algorithm and std.range.
Source
std/string.d
string : (alias template) autological_binfmt_magic_match.representation = std.string.representation(Char)(Char[] s) if (isSomeChar!Char)Returns the representation of a string, which has the same type
as the string except the character type is replaced by ubyte,
ushort, or uint depending on the character width.
representation, (alias template) autological_binfmt_magic_match.strip = std.string.strip(Range)(Range str) if (isSomeString!Range || isRandomAccessRange!Range && hasLength!Range && hasSlicing!Range && !isConvertibleToString!Range && isSomeChar!(ElementEncodingType!Range))Strips both leading and trailing whitespace (as defined by
isWhite) or as specified in the second argument.
strip;
/++
A parsed `binfmt_misc` registration.
`type` is `M` for magic-and-mask matching or `E` for an extension match; only
`M` participates in the byte-level dispatch this catalog cares about, and the
kernel rejects a non-empty `offset`/`magic` for `E` rules.
+/
struct (struct) autological_binfmt_magic_match.RegistrationA parsed binfmt_misc registration.
type is M for magic-and-mask matching or E for an extension match; only
M participates in the byte-level dispatch this catalog cares about, and the
kernel rejects a non-empty offset/magic for E rules.
Registration
{
(alias) object.string = stringstring (field) string autological_binfmt_magic_match.Registration.namename;
char (field) char autological_binfmt_magic_match.Registration.typetype; // 'M' (magic) or 'E' (extension)
(alias) object.size_t = ulongsize_t (field) ulong autological_binfmt_magic_match.Registration.offsetoffset;
immutable(ubyte)[] (field) immutable(ubyte)[] autological_binfmt_magic_match.Registration.magicmagic;
immutable(ubyte)[] (field) immutable(ubyte)[] autological_binfmt_magic_match.Registration.maskmask; // empty == all-0xff, i.e. literal
(alias) object.string = stringstring (field) string autological_binfmt_magic_match.Registration.interpreterinterpreter;
(alias) object.string = stringstring (field) string autological_binfmt_magic_match.Registration.flagsflags;
/// True when the `F` flag is set — the interpreter is opened at registration
/// time and held, so the rule survives a mount-namespace change.
bool bool autological_binfmt_magic_match.Registration.fixBinary() const pure nothrow @nogc @safeTrue when the F flag is set — the interpreter is opened at registration
time and held, so the rule survives a mount-namespace change.
fixBinary() const @safe pure nothrow @nogc => (field) string autological_binfmt_magic_match.Registration.flagsflags.bool autological_binfmt_magic_match.hasFlag(in string flags, char f) pure nothrow @nogc @safeCase-sensitive flag membership.
hasFlag('F');
/// True when the `P` flag is set — `argv[0]` is preserved and the original
/// path is passed as an extra argument.
bool bool autological_binfmt_magic_match.Registration.preserveArgv0() const pure nothrow @nogc @safeTrue when the P flag is set — argv[0] is preserved and the original
path is passed as an extra argument.
preserveArgv0() const @safe pure nothrow @nogc => (field) string autological_binfmt_magic_match.Registration.flagsflags.bool autological_binfmt_magic_match.hasFlag(in string flags, char f) pure nothrow @nogc @safeCase-sensitive flag membership.
hasFlag('P');
/// True when the `C` flag is set — credentials are computed from the binary
/// rather than the interpreter, which implies `O`.
bool bool autological_binfmt_magic_match.Registration.credentialsFromBinary() const pure nothrow @nogc @safeTrue when the C flag is set — credentials are computed from the binary
rather than the interpreter, which implies O.
credentialsFromBinary() const @safe pure nothrow @nogc => (field) string autological_binfmt_magic_match.Registration.flagsflags.bool autological_binfmt_magic_match.hasFlag(in string flags, char f) pure nothrow @nogc @safeCase-sensitive flag membership.
hasFlag('C');
/// True when the `O` flag is set — the binary is opened and its descriptor
/// passed to the interpreter as `/dev/fd/N`.
bool bool autological_binfmt_magic_match.Registration.openBinary() const pure nothrow @nogc @safeTrue when the O flag is set — the binary is opened and its descriptor
passed to the interpreter as /dev/fd/N.
openBinary() const @safe pure nothrow @nogc => (field) string autological_binfmt_magic_match.Registration.flagsflags.bool autological_binfmt_magic_match.hasFlag(in string flags, char f) pure nothrow @nogc @safeCase-sensitive flag membership.
hasFlag('O');
}
/// Case-sensitive flag membership.
private bool bool autological_binfmt_magic_match.hasFlag(in string flags, char f) pure nothrow @nogc @safeCase-sensitive flag membership.
hasFlag(in (alias) object.string = stringstring (parameter) const(string) flagsflags, char (parameter) char ff) @safe pure nothrow @nogc
{
foreach ((parameter) immutable(char) cc; (parameter) const(string) flagsflags)
if ((local variable) immutable(char) cc == (parameter) char ff)
return true;
return false;
}
/++
Decodes the `\xNN` escaping the kernel accepts in `magic` and `mask`.
The kernel's own decoder handles `\x` hex pairs and passes everything else
through literally; a lone backslash is not special. Anything that is not a valid
hex pair after `\x` is a malformed registration, and the kernel returns `EINVAL`
rather than guessing.
+/
immutable(ubyte)[] immutable(ubyte)[] autological_binfmt_magic_match.unescape(string s) pure @safeDecodes the \xNN escaping the kernel accepts in magic and mask.
The kernel's own decoder handles \x hex pairs and passes everything else
through literally; a lone backslash is not special. Anything that is not a valid
hex pair after \x is a malformed registration, and the kernel returns EINVAL
rather than guessing.
unescape((alias) object.string = stringstring (parameter) string ss) @safe pure
{
ubyte[] (local variable) ubyte[] out_out_;
(alias) object.size_t = ulongsize_t (local variable) ulong ii;
while ((local variable) ulong ii < (parameter) string ss.(field) ulong string.lengthlength)
{
if ((parameter) string ss[(local variable) ulong ii] == '\\' && (local variable) ulong ii + 3 < (parameter) string ss.(field) ulong string.lengthlength && (parameter) string ss[(local variable) ulong ii + 1] == 'x')
{
(local variable) ubyte[] out_out_ ~= (parameter) string ss[(local variable) ulong ii + 2 .. (local variable) ulong ii + 4].ubyte std.conv.to!ubyte.to!(string, int)(string __param_0, int __param_1) pure @safeThe to template converts a value from one type to another.
The source type is deduced and the target type must be specified, for example the
expression to`!int(42.0)` converts the number 42 from
`double` to `int`. The conversion is "safe", i.e.,
it checks for overflow; to!int(4.2e10) would throw the
ConvOverflowException exception. Overflow checks are only
inserted when necessary, e.g., ``to!double(42) does not do
any checking because any int fits in a double.
Conversions from string to numeric types differ from the C equivalents
atoi() and atol() by checking for overflow and not allowing whitespace.
For conversion of strings to signed types, the grammar recognized is:
Integer:
Sign UnsignedInteger
UnsignedInteger
Sign:
+
-
For conversion to unsigned types, the grammar recognized is:
UnsignedInteger:
DecimalDigit
DecimalDigit UnsignedInteger
Examples
Converting a value to its own type (useful mostly for generic code)
simply returns its argument.
int a = 42;
int b = to!int(a);
double c = to!double(3.14); // c is double with value 3.14
Converting among numeric types is a safe way to cast them around.
Conversions from floating-point types to integral types allow loss of
precision (the fractional part of a floating-point number). The
conversion is truncating towards zero, the same way a cast would
truncate. (To round a floating point value when casting to an
integral, use roundTo.)
import std.exception : assertThrown;
int a = 420;
assert(to!long(a) == a);
assertThrown!ConvOverflowException(to!byte(a));
assert(to!int(4.2e6) == 4200000);
assertThrown!ConvOverflowException(to!uint(-3.14));
assert(to!uint(3.14) == 3);
assert(to!uint(3.99) == 3);
assert(to!int(-3.99) == -3);
When converting strings to numeric types, note that D hexadecimal and binary
literals are not handled. Neither the prefixes that indicate the base, nor the
horizontal bar used to separate groups of digits are recognized. This also
applies to the suffixes that indicate the type.
To work around this, you can specify a radix for conversions involving numbers.
auto str = to!string(42, 16);
assert(str == "2A");
auto i = to!int(str, 16);
assert(i == 42);
Conversions from integral types to floating-point types always
succeed, but might lose accuracy. The largest integers with a
predecessor representable in floating-point format are 2^24-1 for
float, 2^53-1 for double, and 2^64-1 for real (when
real is 80-bit, e.g. on Intel machines).
// 2^24 - 1, largest proper integer representable as float
int a = 16_777_215;
assert(to!int(to!float(a)) == a);
assert(to!int(to!float(-a)) == -a);
Conversion from string types to char types enforces the input
to consist of a single code point, and said code point must
fit in the target type. Otherwise, ConvException is thrown.
import std.exception : assertThrown;
assert(to!char("a") == 'a');
assertThrown(to!char("ñ")); // 'ñ' does not fit into a char
assert(to!wchar("ñ") == 'ñ');
assertThrown(to!wchar("😃")); // '😃' does not fit into a wchar
assert(to!dchar("😃") == '😃');
// Using wstring or dstring as source type does not affect the result
assert(to!char("a"w) == 'a');
assert(to!char("a"d) == 'a');
// Two code points cannot be converted to a single one
assertThrown(to!char("ab"));
Converting an array to another array type works by converting each
element in turn. Associative arrays can be converted to associative
arrays as long as keys and values can in turn be converted.
import std.string : split;
int[] a = [1, 2, 3];
auto b = to!(float[])(a);
assert(b == [1.0f, 2, 3]);
string str = "1 2 3 4 5 6";
auto numbers = to!(double[])(split(str));
assert(numbers == [1.0, 2, 3, 4, 5, 6]);
int[string] c;
c["a"] = 1;
c["b"] = 2;
auto d = to!(double[wstring])(c);
assert(d["a"w] == 1 && d["b"w] == 2);
Conversions operate transitively, meaning that they work on arrays and
associative arrays of any complexity.
This conversion works because to`!short` applies to an `int`, to!wstring
applies to a string, to`!string` applies to a `double`, and
to!(double[]) applies to an int[]. The conversion might throw an
exception because ``to!short might fail the range check.
int[string][double[int[]]] a;
auto b = to!(short[wstring][string[double[]]])(a);
Object-to-object conversions by dynamic casting throw exception when
the source is non-null and the target is null.
import std.exception : assertThrown;
// Testing object conversions
class A {}
class B : A {}
class C : A {}
A a1 = new A, a2 = new B, a3 = new C;
assert(to!B(a2) is a2);
assert(to!C(a3) is a3);
assertThrown!ConvException(to!B(a3));
Stringize conversion from all types is supported.
String to string conversion works for any two string types having
(char, wchar, dchar) character widths and any
combination of qualifiers (mutable, const, or immutable).
Converts array (other than strings) to string.
Each element is converted by calling ``to!T.
Associative array to string conversion.
Each element is converted by calling ``to!T.
Object to string conversion calls toString against the object or
returns "null" if the object is null.
Struct to string conversion calls toString against the struct if
it is defined.
For structs that do not define toString, the conversion to string
produces the list of fields.
Enumerated types are converted to strings as their symbolic names.
Boolean values are converted to "true" or "false".
char, wchar, dchar to a string type.
Unsigned or signed integers to strings.
: Convert integral value to string in radix radix.
radix must be a value from 2 to 36.
value is treated as a signed value only if radix is 10.
The characters A through Z are used to represent values 10 through 36
and their case is determined by the letterCase parameter.
All floating point types to all string types.
Pointer to string conversions convert the pointer to a size_t value.
If pointer is char*, treat it as C-style strings.
In that case, this function is @system.
See formatValue on how toString should be defined.
// Conversion representing dynamic/static array with string
long[] a = [ 1, 3, 5 ];
assert(to!string(a) == "[1, 3, 5]");
// Conversion representing associative array with string
int[string] associativeArray = ["0":1, "1":2];
assert(to!string(associativeArray) == `["0":1, "1":2]` ||
to!string(associativeArray) == `["1":2, "0":1]`);
// char* to string conversion
assert(to!string(cast(char*) null) == "");
assert(to!string("foo\0".ptr) == "foo");
// Conversion reinterpreting void array to string
auto w = "abcx"w;
const(void)[] b = w;
assert(b.length == 8);
auto c = to!(wchar[])(b);
assert(c == "abcx");
Strings can be converted to enum types. The enum member with the same name as the
input string is returned. The comparison is case-sensitive.
A ConvException is thrown if the enum does not have the specified member.
import std.exception : assertThrown;
enum E { a, b, c }
assert(to!E("a") == E.a);
assert(to!E("b") == E.b);
assertThrown!ConvException(to!E("A"));
to!ubyte(16);
(local variable) ulong ii += 4;
}
else
{
(local variable) ubyte[] out_out_ ~= cast(ubyte) (parameter) string ss[(local variable) ulong ii];
(local variable) ulong ii++;
}
}
return (local variable) ubyte[] out_out_.immutable(ubyte)[] object.idup!ubyte(ubyte[] a) pure nothrow @property @safeProvide the .idup array property, which creates an immutable duplicate.
idup;
}
/++
Parses one registration line.
The delimiter is whatever character follows the leading colon in the kernel's
grammar; every real-world registration uses `:`, and that is what is assumed
here. Throws on a field count the kernel would reject.
+/
(struct) autological_binfmt_magic_match.RegistrationA parsed binfmt_misc registration.
type is M for magic-and-mask matching or E for an extension match; only
M participates in the byte-level dispatch this catalog cares about, and the
kernel rejects a non-empty offset/magic for E rules.
Registration autological_binfmt_magic_match.Registration autological_binfmt_magic_match.parse(string line) pure @safeParses one registration line.
The delimiter is whatever character follows the leading colon in the kernel's
grammar; every real-world registration uses :, and that is what is assumed
here. Throws on a field count the kernel would reject.
parse((alias) object.string = stringstring (parameter) string lineline) @safe pure
{
const (local variable) const(string[]) fieldsfields = (parameter) string lineline.string std.string.strip!string(string str) pure nothrow @nogc @safeStrips both leading and trailing whitespace (as defined by
isWhite) or as specified in the second argument.
Examples
import std.uni : lineSep, paraSep;
assert(strip(" hello world ") ==
"hello world");
assert(strip("\n\t\v\rhello world\n\t\v\r") ==
"hello world");
assert(strip("hello world") ==
"hello world");
assert(strip([lineSep] ~ "hello world" ~ [lineSep]) ==
"hello world");
assert(strip([paraSep] ~ "hello world" ~ [paraSep]) ==
"hello world");
strip.string[] std.array.split!(string, string)(string range, string sep) pure nothrow @safesplit(":");
// A leading ':' produces an empty first field, so a well-formed line has 8.
if ((local variable) const(string[]) fieldsfields.(field) ulong const(string[]).lengthlength != 8)
throw new (class) object.ExceptionThe base class of all errors that are safe to catch and handle.
In principle, only thrown objects derived from this class are safe to catch
inside a catch block. Thrown objects not derived from Exception
represent runtime errors that should not be caught, as certain runtime
guarantees may not hold, making it unsafe to continue program execution.
Examples
bool gotCaught;
try
{
throw new Exception("msg");
}
catch (Exception e)
{
gotCaught = true;
assert(e.msg == "msg");
}
assert(gotCaught);
Exception("expected 8 ':'-separated fields, got " ~ (local variable) const(string[]) fieldsfields.(field) ulong const(string[]).lengthlength.string std.conv.text!ulong(ulong __param_0) pure nothrow @safeConvenience functions for converting one or more arguments
of any type into text (the three character widths).
text ~ ": " ~ (parameter) string lineline);
(struct) autological_binfmt_magic_match.RegistrationA parsed binfmt_misc registration.
type is M for magic-and-mask matching or E for an extension match; only
M participates in the byte-level dispatch this catalog cares about, and the
kernel rejects a non-empty offset/magic for E rules.
Registration (local variable) autological_binfmt_magic_match.Registration rr;
(local variable) autological_binfmt_magic_match.Registration rr.(field) string autological_binfmt_magic_match.Registration.namename = (local variable) const(string[]) fieldsfields[1];
(local variable) autological_binfmt_magic_match.Registration rr.(field) char autological_binfmt_magic_match.Registration.typetype = (local variable) const(string[]) fieldsfields[2].(field) ulong const(string).lengthlength ? (local variable) const(string[]) fieldsfields[2][0] : 'M';
(local variable) autological_binfmt_magic_match.Registration rr.(field) ulong autological_binfmt_magic_match.Registration.offsetoffset = (local variable) const(string[]) fieldsfields[3].(field) ulong const(string).lengthlength ? (local variable) const(string[]) fieldsfields[3].ulong std.conv.to!ulong.to!string(string __param_0) pure @safeThe to template converts a value from one type to another.
The source type is deduced and the target type must be specified, for example the
expression to`!int(42.0)` converts the number 42 from
`double` to `int`. The conversion is "safe", i.e.,
it checks for overflow; to!int(4.2e10) would throw the
ConvOverflowException exception. Overflow checks are only
inserted when necessary, e.g., ``to!double(42) does not do
any checking because any int fits in a double.
Conversions from string to numeric types differ from the C equivalents
atoi() and atol() by checking for overflow and not allowing whitespace.
For conversion of strings to signed types, the grammar recognized is:
Integer:
Sign UnsignedInteger
UnsignedInteger
Sign:
+
-
For conversion to unsigned types, the grammar recognized is:
UnsignedInteger:
DecimalDigit
DecimalDigit UnsignedInteger
Examples
Converting a value to its own type (useful mostly for generic code)
simply returns its argument.
int a = 42;
int b = to!int(a);
double c = to!double(3.14); // c is double with value 3.14
Converting among numeric types is a safe way to cast them around.
Conversions from floating-point types to integral types allow loss of
precision (the fractional part of a floating-point number). The
conversion is truncating towards zero, the same way a cast would
truncate. (To round a floating point value when casting to an
integral, use roundTo.)
import std.exception : assertThrown;
int a = 420;
assert(to!long(a) == a);
assertThrown!ConvOverflowException(to!byte(a));
assert(to!int(4.2e6) == 4200000);
assertThrown!ConvOverflowException(to!uint(-3.14));
assert(to!uint(3.14) == 3);
assert(to!uint(3.99) == 3);
assert(to!int(-3.99) == -3);
When converting strings to numeric types, note that D hexadecimal and binary
literals are not handled. Neither the prefixes that indicate the base, nor the
horizontal bar used to separate groups of digits are recognized. This also
applies to the suffixes that indicate the type.
To work around this, you can specify a radix for conversions involving numbers.
auto str = to!string(42, 16);
assert(str == "2A");
auto i = to!int(str, 16);
assert(i == 42);
Conversions from integral types to floating-point types always
succeed, but might lose accuracy. The largest integers with a
predecessor representable in floating-point format are 2^24-1 for
float, 2^53-1 for double, and 2^64-1 for real (when
real is 80-bit, e.g. on Intel machines).
// 2^24 - 1, largest proper integer representable as float
int a = 16_777_215;
assert(to!int(to!float(a)) == a);
assert(to!int(to!float(-a)) == -a);
Conversion from string types to char types enforces the input
to consist of a single code point, and said code point must
fit in the target type. Otherwise, ConvException is thrown.
import std.exception : assertThrown;
assert(to!char("a") == 'a');
assertThrown(to!char("ñ")); // 'ñ' does not fit into a char
assert(to!wchar("ñ") == 'ñ');
assertThrown(to!wchar("😃")); // '😃' does not fit into a wchar
assert(to!dchar("😃") == '😃');
// Using wstring or dstring as source type does not affect the result
assert(to!char("a"w) == 'a');
assert(to!char("a"d) == 'a');
// Two code points cannot be converted to a single one
assertThrown(to!char("ab"));
Converting an array to another array type works by converting each
element in turn. Associative arrays can be converted to associative
arrays as long as keys and values can in turn be converted.
import std.string : split;
int[] a = [1, 2, 3];
auto b = to!(float[])(a);
assert(b == [1.0f, 2, 3]);
string str = "1 2 3 4 5 6";
auto numbers = to!(double[])(split(str));
assert(numbers == [1.0, 2, 3, 4, 5, 6]);
int[string] c;
c["a"] = 1;
c["b"] = 2;
auto d = to!(double[wstring])(c);
assert(d["a"w] == 1 && d["b"w] == 2);
Conversions operate transitively, meaning that they work on arrays and
associative arrays of any complexity.
This conversion works because to`!short` applies to an `int`, to!wstring
applies to a string, to`!string` applies to a `double`, and
to!(double[]) applies to an int[]. The conversion might throw an
exception because ``to!short might fail the range check.
int[string][double[int[]]] a;
auto b = to!(short[wstring][string[double[]]])(a);
Object-to-object conversions by dynamic casting throw exception when
the source is non-null and the target is null.
import std.exception : assertThrown;
// Testing object conversions
class A {}
class B : A {}
class C : A {}
A a1 = new A, a2 = new B, a3 = new C;
assert(to!B(a2) is a2);
assert(to!C(a3) is a3);
assertThrown!ConvException(to!B(a3));
Stringize conversion from all types is supported.
String to string conversion works for any two string types having
(char, wchar, dchar) character widths and any
combination of qualifiers (mutable, const, or immutable).
Converts array (other than strings) to string.
Each element is converted by calling ``to!T.
Associative array to string conversion.
Each element is converted by calling ``to!T.
Object to string conversion calls toString against the object or
returns "null" if the object is null.
Struct to string conversion calls toString against the struct if
it is defined.
For structs that do not define toString, the conversion to string
produces the list of fields.
Enumerated types are converted to strings as their symbolic names.
Boolean values are converted to "true" or "false".
char, wchar, dchar to a string type.
Unsigned or signed integers to strings.
: Convert integral value to string in radix radix.
radix must be a value from 2 to 36.
value is treated as a signed value only if radix is 10.
The characters A through Z are used to represent values 10 through 36
and their case is determined by the letterCase parameter.
All floating point types to all string types.
Pointer to string conversions convert the pointer to a size_t value.
If pointer is char*, treat it as C-style strings.
In that case, this function is @system.
See formatValue on how toString should be defined.
// Conversion representing dynamic/static array with string
long[] a = [ 1, 3, 5 ];
assert(to!string(a) == "[1, 3, 5]");
// Conversion representing associative array with string
int[string] associativeArray = ["0":1, "1":2];
assert(to!string(associativeArray) == `["0":1, "1":2]` ||
to!string(associativeArray) == `["1":2, "0":1]`);
// char* to string conversion
assert(to!string(cast(char*) null) == "");
assert(to!string("foo\0".ptr) == "foo");
// Conversion reinterpreting void array to string
auto w = "abcx"w;
const(void)[] b = w;
assert(b.length == 8);
auto c = to!(wchar[])(b);
assert(c == "abcx");
Strings can be converted to enum types. The enum member with the same name as the
input string is returned. The comparison is case-sensitive.
A ConvException is thrown if the enum does not have the specified member.
import std.exception : assertThrown;
enum E { a, b, c }
assert(to!E("a") == E.a);
assert(to!E("b") == E.b);
assertThrown!ConvException(to!E("A"));
to!(alias) object.size_t = ulongsize_t : 0;
(local variable) autological_binfmt_magic_match.Registration rr.(field) immutable(ubyte)[] autological_binfmt_magic_match.Registration.magicmagic = immutable(ubyte)[] autological_binfmt_magic_match.unescape(string s) pure @safeDecodes the \xNN escaping the kernel accepts in magic and mask.
The kernel's own decoder handles \x hex pairs and passes everything else
through literally; a lone backslash is not special. Anything that is not a valid
hex pair after \x is a malformed registration, and the kernel returns EINVAL
rather than guessing.
unescape((local variable) const(string[]) fieldsfields[4]);
(local variable) autological_binfmt_magic_match.Registration rr.(field) immutable(ubyte)[] autological_binfmt_magic_match.Registration.maskmask = immutable(ubyte)[] autological_binfmt_magic_match.unescape(string s) pure @safeDecodes the \xNN escaping the kernel accepts in magic and mask.
The kernel's own decoder handles \x hex pairs and passes everything else
through literally; a lone backslash is not special. Anything that is not a valid
hex pair after \x is a malformed registration, and the kernel returns EINVAL
rather than guessing.
unescape((local variable) const(string[]) fieldsfields[5]);
(local variable) autological_binfmt_magic_match.Registration rr.(field) string autological_binfmt_magic_match.Registration.interpreterinterpreter = (local variable) const(string[]) fieldsfields[6];
(local variable) autological_binfmt_magic_match.Registration rr.(field) string autological_binfmt_magic_match.Registration.flagsflags = (local variable) const(string[]) fieldsfields[7];
return (local variable) autological_binfmt_magic_match.Registration rr;
}
/++
The kernel's match predicate, transcribed.
Two properties are worth naming because they shape what can be dispatched:
`offset` is a *fixed* position — there is no search — and the comparison is
`(byte & mask) == (magic & mask)` bytewise, so a mask makes a rule tolerant of
fields that vary between otherwise identical binaries (an ELF's `e_machine`
being the archetype).
+/
bool bool autological_binfmt_magic_match.matches(in autological_binfmt_magic_match.Registration r, in ubyte[] buf) pure nothrow @nogc @safeThe kernel's match predicate, transcribed.
Two properties are worth naming because they shape what can be dispatched:
offset is a fixed position — there is no search — and the comparison is
(byte & mask) == (magic & mask) bytewise, so a mask makes a rule tolerant of
fields that vary between otherwise identical binaries (an ELF's e_machine
being the archetype).
matches(in (struct) autological_binfmt_magic_match.RegistrationA parsed binfmt_misc registration.
type is M for magic-and-mask matching or E for an extension match; only
M participates in the byte-level dispatch this catalog cares about, and the
kernel rejects a non-empty offset/magic for E rules.
Registration (parameter) const(autological_binfmt_magic_match.Registration) rr, in ubyte[] (parameter) const(ubyte[]) bufbuf) @safe pure nothrow @nogc
{
if ((parameter) const(autological_binfmt_magic_match.Registration) rr.(field) char autological_binfmt_magic_match.Registration.typetype != 'M')
return false; // extension rules do not look at bytes
if ((parameter) const(autological_binfmt_magic_match.Registration) rr.(field) ulong autological_binfmt_magic_match.Registration.offsetoffset + (parameter) const(autological_binfmt_magic_match.Registration) rr.(field) immutable(ubyte)[] autological_binfmt_magic_match.Registration.magicmagic.(field) ulong const(immutable(ubyte)[]).lengthlength > (parameter) const(ubyte[]) bufbuf.(field) ulong const(ubyte[]).lengthlength)
return false;
foreach ((parameter) ulong ii, (parameter) immutable(ubyte) mm; (parameter) const(autological_binfmt_magic_match.Registration) rr.(field) immutable(ubyte)[] autological_binfmt_magic_match.Registration.magicmagic)
{
const (local variable) const(int) maskmask = (parameter) const(autological_binfmt_magic_match.Registration) rr.(field) immutable(ubyte)[] autological_binfmt_magic_match.Registration.maskmask.(field) ulong const(immutable(ubyte)[]).lengthlength > (local variable) ulong ii ? (parameter) const(autological_binfmt_magic_match.Registration) rr.(field) immutable(ubyte)[] autological_binfmt_magic_match.Registration.maskmask[(local variable) ulong ii] : 0xff;
if (((parameter) const(ubyte[]) bufbuf[(parameter) const(autological_binfmt_magic_match.Registration) rr.(field) ulong autological_binfmt_magic_match.Registration.offsetoffset + (local variable) ulong ii] & (local variable) const(int) maskmask) != ((local variable) immutable(ubyte) mm & (local variable) const(int) maskmask))
return false;
}
return true;
}
/// A named specimen buffer.
struct (struct) autological_binfmt_magic_match.SpecimenA named specimen buffer.
Specimen
{
(alias) object.string = stringstring (field) string autological_binfmt_magic_match.Specimen.labellabel;
immutable(ubyte)[] (field) immutable(ubyte)[] autological_binfmt_magic_match.Specimen.bytesbytes;
}
/// A 64-bit little-endian ELF header with `e_machine` set to `EM_AARCH64` (183).
immutable(ubyte)[] immutable(ubyte)[] autological_binfmt_magic_match.aarch64Elf() pure @safeA 64-bit little-endian ELF header with e_machine set to EM_AARCH64 (183).
aarch64Elf() @safe pure
{
auto (local variable) ubyte[] bb = new ubyte[64];
(local variable) ubyte[] bb[0 .. 4] = [0x7f, 'E', 'L', 'F'];
(local variable) ubyte[] bb[4] = 2; // ELFCLASS64
(local variable) ubyte[] bb[5] = 1; // ELFDATA2LSB
(local variable) ubyte[] bb[6] = 1; // EV_CURRENT
(local variable) ubyte[] bb[16] = 2; // ET_EXEC
(local variable) ubyte[] bb[18] = 183; // e_machine = EM_AARCH64, little-endian
return (local variable) ubyte[] bb.immutable(ubyte)[] object.idup!ubyte(ubyte[] a) pure nothrow @property @safeProvide the .idup array property, which creates an immutable duplicate.
idup;
}
/// The same header, but `e_machine` = `EM_X86_64` (62) — the mask must reject it.
immutable(ubyte)[] immutable(ubyte)[] autological_binfmt_magic_match.x86Elf() pure @safeThe same header, but e_machine = EM_X86_64 (62) — the mask must reject it.
x86Elf() @safe pure
{
auto (local variable) ubyte[] bb = cast(ubyte[]) immutable(ubyte)[] autological_binfmt_magic_match.aarch64Elf() pure @safeA 64-bit little-endian ELF header with e_machine set to EM_AARCH64 (183).
aarch64Elf().ubyte[] object.dup!ubyte(const(ubyte)[] a) pure nothrow @property @safedup;
(local variable) ubyte[] bb[18] = 62;
return (local variable) ubyte[] bb.immutable(ubyte)[] object.idup!ubyte(ubyte[] a) pure nothrow @property @safeProvide the .idup array property, which creates an immutable duplicate.
idup;
}
/// A SQLite header whose `application_id` at offset 68 reads `SELF`.
immutable(ubyte)[] immutable(ubyte)[] autological_binfmt_magic_match.selfDb() pure @safeA SQLite header whose application_id at offset 68 reads SELF.
selfDb() @safe pure
{
auto (local variable) ubyte[] bb = new ubyte[100];
(local variable) ubyte[] bb[0 .. 16] = "SQLite format 3\0".immutable(ubyte)[] std.string.representation!(immutable(char))(string s) pure nothrow @nogc @safeReturns the representation of a string, which has the same type
as the string except the character type is replaced by ubyte,
ushort, or uint depending on the character width.
Examples
string s = "hello";
static assert(is(typeof(representation(s)) == immutable(ubyte)[]));
assert(representation(s) is cast(immutable(ubyte)[]) s);
assert(representation(s) == [0x68, 0x65, 0x6c, 0x6c, 0x6f]);
representation;
(local variable) ubyte[] bb[16] = 0x10; // page size 4096
(local variable) ubyte[] bb[68 .. 72] = "SELF".immutable(ubyte)[] std.string.representation!(immutable(char))(string s) pure nothrow @nogc @safeReturns the representation of a string, which has the same type
as the string except the character type is replaced by ubyte,
ushort, or uint depending on the character width.
Examples
string s = "hello";
static assert(is(typeof(representation(s)) == immutable(ubyte)[]));
assert(representation(s) is cast(immutable(ubyte)[]) s);
assert(representation(s) == [0x68, 0x65, 0x6c, 0x6c, 0x6f]);
representation;
return (local variable) ubyte[] bb.immutable(ubyte)[] object.idup!ubyte(ubyte[] a) pure nothrow @property @safeProvide the .idup array property, which creates an immutable duplicate.
idup;
}
/// An ordinary SQLite database — same magic at 0, nothing at 68.
immutable(ubyte)[] immutable(ubyte)[] autological_binfmt_magic_match.plainDb() pure @safeAn ordinary SQLite database — same magic at 0, nothing at 68.
plainDb() @safe pure
{
auto (local variable) ubyte[] bb = cast(ubyte[]) immutable(ubyte)[] autological_binfmt_magic_match.selfDb() pure @safeA SQLite header whose application_id at offset 68 reads SELF.
selfDb().ubyte[] object.dup!ubyte(const(ubyte)[] a) pure nothrow @property @safedup;
(local variable) ubyte[] bb[68 .. 72] = [0, 0, 0, 0];
return (local variable) ubyte[] bb.immutable(ubyte)[] object.idup!ubyte(ubyte[] a) pure nothrow @property @safeProvide the .idup array property, which creates an immutable duplicate.
idup;
}
/// A ZIP/JAR: local file header magic at offset 0.
immutable(ubyte)[] immutable(ubyte)[] autological_binfmt_magic_match.jar() pure @safeA ZIP/JAR: local file header magic at offset 0.
jar() @safe pure
{
immutable(ubyte)[] (local variable) immutable(ubyte)[] zz = [0x50, 0x4b, 0x03, 0x04, 0x14, 0x00, 0x00, 0x00];
return (local variable) immutable(ubyte)[] zz;
}
int int D main()main()
{
// Real-shaped registrations. The qemu rule is the standard one shipped by
// `qemu-user-static`; the mask lets every other ELF header field vary.
const (local variable) const(autological_binfmt_magic_match.Registration[]) tabletable = [
autological_binfmt_magic_match.Registration autological_binfmt_magic_match.parse(string line) pure @safeParses one registration line.
The delimiter is whatever character follows the leading colon in the kernel's
grammar; every real-world registration uses :, and that is what is assumed
here. Throws on a field count the kernel would reject.
parse(":qemu-aarch64:M::\\x7fELF\\x02\\x01\\x01\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00" ~
"\\x02\\x00\\xb7\\x00:" ~
"\\xff\\xff\\xff\\xff\\xff\\xfe\\xfe\\x00\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff" ~
"\\xfe\\xff\\xff\\xff:/usr/bin/qemu-aarch64-static:FPO"),
autological_binfmt_magic_match.Registration autological_binfmt_magic_match.parse(string line) pure @safeParses one registration line.
The delimiter is whatever character follows the leading colon in the kernel's
grammar; every real-world registration uses :, and that is what is assumed
here. Throws on a field count the kernel would reject.
parse(":self:M:68:SELF::/usr/bin/self-exec:F"),
autological_binfmt_magic_match.Registration autological_binfmt_magic_match.parse(string line) pure @safeParses one registration line.
The delimiter is whatever character follows the leading colon in the kernel's
grammar; every real-world registration uses :, and that is what is assumed
here. Throws on a field count the kernel would reject.
parse(":jar:M::PK\\x03\\x04::/usr/bin/jarwrapper:"),
autological_binfmt_magic_match.Registration autological_binfmt_magic_match.parse(string line) pure @safeParses one registration line.
The delimiter is whatever character follows the leading colon in the kernel's
grammar; every real-world registration uses :, and that is what is assumed
here. Throws on a field count the kernel would reject.
parse(":python-ext:E::py::/usr/bin/python3:"),
];
const (local variable) const(autological_binfmt_magic_match.Specimen[]) specimensspecimens = [
(struct) autological_binfmt_magic_match.SpecimenA named specimen buffer.
Specimen("aarch64 ELF", immutable(ubyte)[] autological_binfmt_magic_match.aarch64Elf() pure @safeA 64-bit little-endian ELF header with e_machine set to EM_AARCH64 (183).
aarch64Elf()),
(struct) autological_binfmt_magic_match.SpecimenA named specimen buffer.
Specimen("x86-64 ELF", immutable(ubyte)[] autological_binfmt_magic_match.x86Elf() pure @safeThe same header, but e_machine = EM_X86_64 (62) — the mask must reject it.
x86Elf()),
(struct) autological_binfmt_magic_match.SpecimenA named specimen buffer.
Specimen("SELF database", immutable(ubyte)[] autological_binfmt_magic_match.selfDb() pure @safeA SQLite header whose application_id at offset 68 reads SELF.
selfDb()),
(struct) autological_binfmt_magic_match.SpecimenA named specimen buffer.
Specimen("plain SQLite db", immutable(ubyte)[] autological_binfmt_magic_match.plainDb() pure @safeAn ordinary SQLite database — same magic at 0, nothing at 68.
plainDb()),
(struct) autological_binfmt_magic_match.SpecimenA named specimen buffer.
Specimen("JAR / ZIP", immutable(ubyte)[] autological_binfmt_magic_match.jar() pure @safeA ZIP/JAR: local file header magic at offset 0.
jar()),
];
void std.stdio.writeln!string(string __param_0) @safeEquivalent to write(args, '\n'). Calling writeln without
arguments is valid and just prints a newline to the standard
output.
Example
Reads stdin and writes it to stdout with an argument
counter.
import std.stdio;
void main()
{
string line;
for (size_t count = 0; (line = readln) !is null; count++)
{
writeln("Input ", count, ": ", line);
}
}
writeln("Registrations parsed from their kernel wire form:");
void std.stdio.writeln!()() @safeEquivalent to write(args, '\n'). Calling writeln without
arguments is valid and just prints a newline to the standard
output.
Example
Reads stdin and writes it to stdout with an argument
counter.
import std.stdio;
void main()
{
string line;
for (size_t count = 0; (line = readln) !is null; count++)
{
writeln("Input ", count, ": ", line);
}
}
writeln;
foreach ((parameter) const(autological_binfmt_magic_match.Registration) rr; (local variable) const(autological_binfmt_magic_match.Registration[]) tabletable)
{
void std.stdio.writefln!(char, string, const(char), const(ulong), ulong, string, string)(in char[] fmt, string __param_1, const(char) __param_2, const(ulong) __param_3, ulong __param_4, string __param_5, string __param_6) @safeEquivalent to writef(fmt, args, '\n').
writefln(" %-14s type=%s offset=%-3s magic=%s bytes mask=%s flags=%s",
(local variable) const(autological_binfmt_magic_match.Registration) rr.(field) string autological_binfmt_magic_match.Registration.namename, (local variable) const(autological_binfmt_magic_match.Registration) rr.(field) char autological_binfmt_magic_match.Registration.typetype, (local variable) const(autological_binfmt_magic_match.Registration) rr.(field) ulong autological_binfmt_magic_match.Registration.offsetoffset, (local variable) const(autological_binfmt_magic_match.Registration) rr.(field) immutable(ubyte)[] autological_binfmt_magic_match.Registration.magicmagic.(field) ulong const(immutable(ubyte)[]).lengthlength,
(local variable) const(autological_binfmt_magic_match.Registration) rr.(field) immutable(ubyte)[] autological_binfmt_magic_match.Registration.maskmask.(field) ulong const(immutable(ubyte)[]).lengthlength ? (local variable) const(autological_binfmt_magic_match.Registration) rr.(field) immutable(ubyte)[] autological_binfmt_magic_match.Registration.maskmask.(field) ulong const(immutable(ubyte)[]).lengthlength.string std.conv.text!ulong(ulong __param_0) pure nothrow @safeConvenience functions for converting one or more arguments
of any type into text (the three character widths).
text ~ " bytes" : "none (literal)",
(local variable) const(autological_binfmt_magic_match.Registration) rr.(field) string autological_binfmt_magic_match.Registration.flagsflags.(field) ulong const(string).lengthlength ? (local variable) const(autological_binfmt_magic_match.Registration) rr.(field) string autological_binfmt_magic_match.Registration.flagsflags : "(none)");
void std.stdio.writefln!(char, string, string, string, string, string)(in char[] fmt, string __param_1, string __param_2, string __param_3, string __param_4, string __param_5) @safeEquivalent to writef(fmt, args, '\n').
writefln(" interpreter %s%s%s%s%s", (local variable) const(autological_binfmt_magic_match.Registration) rr.(field) string autological_binfmt_magic_match.Registration.interpreterinterpreter,
(local variable) const(autological_binfmt_magic_match.Registration) rr.bool autological_binfmt_magic_match.Registration.fixBinary() const pure nothrow @nogc @safeTrue when the F flag is set — the interpreter is opened at registration
time and held, so the rule survives a mount-namespace change.
fixBinary ? " [F: interpreter pinned at registration — works inside containers]" : "",
(local variable) const(autological_binfmt_magic_match.Registration) rr.bool autological_binfmt_magic_match.Registration.preserveArgv0() const pure nothrow @nogc @safeTrue when the P flag is set — argv[0] is preserved and the original
path is passed as an extra argument.
preserveArgv0 ? " [P: argv[0] preserved]" : "",
(local variable) const(autological_binfmt_magic_match.Registration) rr.bool autological_binfmt_magic_match.Registration.openBinary() const pure nothrow @nogc @safeTrue when the O flag is set — the binary is opened and its descriptor
passed to the interpreter as /dev/fd/N.
openBinary ? " [O: binary passed as /dev/fd/N]" : "",
(local variable) const(autological_binfmt_magic_match.Registration) rr.bool autological_binfmt_magic_match.Registration.credentialsFromBinary() const pure nothrow @nogc @safeTrue when the C flag is set — credentials are computed from the binary
rather than the interpreter, which implies O.
credentialsFromBinary ? " [C: credentials from the binary]" : "");
}
void std.stdio.writeln!()() @safeEquivalent to write(args, '\n'). Calling writeln without
arguments is valid and just prints a newline to the standard
output.
Example
Reads stdin and writes it to stdout with an argument
counter.
import std.stdio;
void main()
{
string line;
for (size_t count = 0; (line = readln) !is null; count++)
{
writeln("Input ", count, ": ", line);
}
}
writeln;
void std.stdio.writeln!string(string __param_0) @safeEquivalent to write(args, '\n'). Calling writeln without
arguments is valid and just prints a newline to the standard
output.
Example
Reads stdin and writes it to stdout with an argument
counter.
import std.stdio;
void main()
{
string line;
for (size_t count = 0; (line = readln) !is null; count++)
{
writeln("Input ", count, ": ", line);
}
}
writeln("Match matrix — which rule claims which specimen:");
void std.stdio.writeln!()() @safeEquivalent to write(args, '\n'). Calling writeln without
arguments is valid and just prints a newline to the standard
output.
Example
Reads stdin and writes it to stdout with an argument
counter.
import std.stdio;
void main()
{
string line;
for (size_t count = 0; (line = readln) !is null; count++)
{
writeln("Input ", count, ": ", line);
}
}
writeln;
void std.stdio.writefln!(char, string, string)(in char[] fmt, string __param_1, string __param_2) @safeEquivalent to writef(fmt, args, '\n').
writefln(" %-18s | %s", "specimen",
(local variable) const(autological_binfmt_magic_match.Registration[]) tabletable.autological_binfmt_magic_match.main.MapResult!(__lambda_L274_C20, const(Registration)[]) autological_binfmt_magic_match.main.map!(const(autological_binfmt_magic_match.Registration)[])(const(autological_binfmt_magic_match.Registration)[] r) pure nothrow @nogc @safeImplements the homonym function (also known as transform) present
in many languages of functional flavor. The call ``map!(fun)(range)
returns a range of which elements are obtained by applying fun(a)
left to right for all elements a in range. The original ranges are
not changed. Evaluation is done lazily.
Examples
import std.algorithm.comparison : equal;
import std.range : chain, only;
auto squares =
chain(only(1, 2, 3, 4), only(5, 6)).map!(a => a * a);
assert(equal(squares, only(1, 4, 9, 16, 25, 36)));
Multiple functions can be passed to map. In that case, the
element type of map is a tuple containing one element for each
function.
auto sums = [2, 4, 6, 8];
auto products = [1, 4, 9, 16];
size_t i = 0;
foreach (result; [ 1, 2, 3, 4 ].map!("a + a", "a * a"))
{
assert(result[0] == sums[i]);
assert(result[1] == products[i]);
++i;
}
You may alias map with some function(s) to a symbol and use
it separately:
import std.algorithm.comparison : equal;
import std.conv : to;
alias stringize = map!(to!string);
assert(equal(stringize([ 1, 2, 3, 4 ]), [ "1", "2", "3", "4" ]));
map!(r => pad(r.name, 14)).string[] std.array.array!(autological_binfmt_magic_match.main.MapResult!(__lambda_L274_C20, const(Registration)[]))(autological_binfmt_magic_match.main.MapResult!(__lambda_L274_C20, const(Registration)[]) r) pure @safeAllocates an array and initializes it with copies of the elements
of range r.
Narrow strings are handled as follows:
If autodecoding is turned on (default), then they are handled as a separate overload.
If autodecoding is turned off, then this is equivalent to duplicating the array.
array.string autological_binfmt_magic_match.joinWith(string[] parts, string sep) pure @safejoin under a name that does not collide with the std.array overload set.
joinWith(" "));
void std.stdio.writefln!(char, string, string)(in char[] fmt, string __param_1, string __param_2) @safeEquivalent to writef(fmt, args, '\n').
writefln(" %-18s-+-%s", "------------------",
(local variable) const(autological_binfmt_magic_match.Registration[]) tabletable.autological_binfmt_magic_match.main.MapResult!(__lambda_L276_C20, const(Registration)[]) autological_binfmt_magic_match.main.map!(const(autological_binfmt_magic_match.Registration)[])(const(autological_binfmt_magic_match.Registration)[] r) pure nothrow @nogc @safeImplements the homonym function (also known as transform) present
in many languages of functional flavor. The call ``map!(fun)(range)
returns a range of which elements are obtained by applying fun(a)
left to right for all elements a in range. The original ranges are
not changed. Evaluation is done lazily.
Examples
import std.algorithm.comparison : equal;
import std.range : chain, only;
auto squares =
chain(only(1, 2, 3, 4), only(5, 6)).map!(a => a * a);
assert(equal(squares, only(1, 4, 9, 16, 25, 36)));
Multiple functions can be passed to map. In that case, the
element type of map is a tuple containing one element for each
function.
auto sums = [2, 4, 6, 8];
auto products = [1, 4, 9, 16];
size_t i = 0;
foreach (result; [ 1, 2, 3, 4 ].map!("a + a", "a * a"))
{
assert(result[0] == sums[i]);
assert(result[1] == products[i]);
++i;
}
You may alias map with some function(s) to a symbol and use
it separately:
import std.algorithm.comparison : equal;
import std.conv : to;
alias stringize = map!(to!string);
assert(equal(stringize([ 1, 2, 3, 4 ]), [ "1", "2", "3", "4" ]));
map!(_ => "--------------").string[] std.array.array!(autological_binfmt_magic_match.main.MapResult!(__lambda_L276_C20, const(Registration)[]))(autological_binfmt_magic_match.main.MapResult!(__lambda_L276_C20, const(Registration)[]) r) pure @safeAllocates an array and initializes it with copies of the elements
of range r.
Narrow strings are handled as follows:
If autodecoding is turned on (default), then they are handled as a separate overload.
If autodecoding is turned off, then this is equivalent to duplicating the array.
array.string autological_binfmt_magic_match.joinWith(string[] parts, string sep) pure @safejoin under a name that does not collide with the std.array overload set.
joinWith("-"));
foreach ((parameter) const(autological_binfmt_magic_match.Specimen) ss; (local variable) const(autological_binfmt_magic_match.Specimen[]) specimensspecimens)
void std.stdio.writefln!(char, string, string)(in char[] fmt, string __param_1, string __param_2) @safeEquivalent to writef(fmt, args, '\n').
writefln(" %-18s | %s", (local variable) const(autological_binfmt_magic_match.Specimen) ss.(field) string autological_binfmt_magic_match.Specimen.labellabel,
(local variable) const(autological_binfmt_magic_match.Registration[]) tabletable.autological_binfmt_magic_match.main.MapResult!(__lambda_L279_C24, const(Registration)[]) autological_binfmt_magic_match.main.map!(const(autological_binfmt_magic_match.Registration)[])(const(autological_binfmt_magic_match.Registration)[] r) pure nothrow @nogc @safeImplements the homonym function (also known as transform) present
in many languages of functional flavor. The call ``map!(fun)(range)
returns a range of which elements are obtained by applying fun(a)
left to right for all elements a in range. The original ranges are
not changed. Evaluation is done lazily.
Examples
import std.algorithm.comparison : equal;
import std.range : chain, only;
auto squares =
chain(only(1, 2, 3, 4), only(5, 6)).map!(a => a * a);
assert(equal(squares, only(1, 4, 9, 16, 25, 36)));
Multiple functions can be passed to map. In that case, the
element type of map is a tuple containing one element for each
function.
auto sums = [2, 4, 6, 8];
auto products = [1, 4, 9, 16];
size_t i = 0;
foreach (result; [ 1, 2, 3, 4 ].map!("a + a", "a * a"))
{
assert(result[0] == sums[i]);
assert(result[1] == products[i]);
++i;
}
You may alias map with some function(s) to a symbol and use
it separately:
import std.algorithm.comparison : equal;
import std.conv : to;
alias stringize = map!(to!string);
assert(equal(stringize([ 1, 2, 3, 4 ]), [ "1", "2", "3", "4" ]));
map!(r => pad(matches(r, s.bytes) ? " ✓" : "", 14)).string[] std.array.array!(autological_binfmt_magic_match.main.MapResult!(__lambda_L279_C24, const(Registration)[]))(autological_binfmt_magic_match.main.MapResult!(__lambda_L279_C24, const(Registration)[]) r) pure @safeAllocates an array and initializes it with copies of the elements
of range r.
Narrow strings are handled as follows:
If autodecoding is turned on (default), then they are handled as a separate overload.
If autodecoding is turned off, then this is equivalent to duplicating the array.
array.string autological_binfmt_magic_match.joinWith(string[] parts, string sep) pure @safejoin under a name that does not collide with the std.array overload set.
joinWith(" "));
void std.stdio.writeln!()() @safeEquivalent to write(args, '\n'). Calling writeln without
arguments is valid and just prints a newline to the standard
output.
Example
Reads stdin and writes it to stdout with an argument
counter.
import std.stdio;
void main()
{
string line;
for (size_t count = 0; (line = readln) !is null; count++)
{
writeln("Input ", count, ": ", line);
}
}
writeln;
void std.stdio.writeln!string(string __param_0) @safeEquivalent to write(args, '\n'). Calling writeln without
arguments is valid and just prints a newline to the standard
output.
Example
Reads stdin and writes it to stdout with an argument
counter.
import std.stdio;
void main()
{
string line;
for (size_t count = 0; (line = readln) !is null; count++)
{
writeln("Input ", count, ": ", line);
}
}
writeln("Read the `x86-64 ELF` row against the `aarch64 ELF` row: the two buffers");
void std.stdio.writeln!string(string __param_0) @safeEquivalent to write(args, '\n'). Calling writeln without
arguments is valid and just prints a newline to the standard
output.
Example
Reads stdin and writes it to stdout with an argument
counter.
import std.stdio;
void main()
{
string line;
for (size_t count = 0; (line = readln) !is null; count++)
{
writeln("Input ", count, ": ", line);
}
}
writeln("differ in exactly one byte (`e_machine`), and the mask is what turns that");
void std.stdio.writeln!string(string __param_0) @safeEquivalent to write(args, '\n'). Calling writeln without
arguments is valid and just prints a newline to the standard
output.
Example
Reads stdin and writes it to stdout with an argument
counter.
import std.stdio;
void main()
{
string line;
for (size_t count = 0; (line = readln) !is null; count++)
{
writeln("Input ", count, ": ", line);
}
}
writeln("byte into the decision. Read the `SELF database` row against `plain SQLite`:");
void std.stdio.writeln!string(string __param_0) @safeEquivalent to write(args, '\n'). Calling writeln without
arguments is valid and just prints a newline to the standard
output.
Example
Reads stdin and writes it to stdout with an argument
counter.
import std.stdio;
void main()
{
string line;
for (size_t count = 0; (line = readln) !is null; count++)
{
writeln("Input ", count, ": ", line);
}
}
writeln("same magic at offset 0, different byte at offset 68 — a format the kernel");
void std.stdio.writeln!string(string __param_0) @safeEquivalent to write(args, '\n'). Calling writeln without
arguments is valid and just prints a newline to the standard
output.
Example
Reads stdin and writes it to stdout with an argument
counter.
import std.stdio;
void main()
{
string line;
for (size_t count = 0; (line = readln) !is null; count++)
{
writeln("Input ", count, ": ", line);
}
}
writeln("can dispatch without SQLite knowing dispatch exists.");
void std.stdio.writeln!()() @safeEquivalent to write(args, '\n'). Calling writeln without
arguments is valid and just prints a newline to the standard
output.
Example
Reads stdin and writes it to stdout with an argument
counter.
import std.stdio;
void main()
{
string line;
for (size_t count = 0; (line = readln) !is null; count++)
{
writeln("Input ", count, ": ", line);
}
}
writeln;
// The honest test: run the same parser over whatever this host has registered.
enum (constant) string autological_binfmt_magic_match.main.procDir = "/proc/sys/fs/binfmt_misc"procDir = "/proc/sys/fs/binfmt_misc";
version (linuxlinux)
{
if (!(constant) string autological_binfmt_magic_match.main.procDir = "/proc/sys/fs/binfmt_misc"procDir.bool std.file.exists!string(string name) nothrow @nogc @safeDetermine whether the given file (or directory) exists.
exists || !(constant) string autological_binfmt_magic_match.main.procDir = "/proc/sys/fs/binfmt_misc"procDir.bool std.file.isDir!string(string name) @property @safeReturns whether the given file is a directory.
isDir)
{
void std.stdio.writeln!string(string __param_0) @safeEquivalent to write(args, '\n'). Calling writeln without
arguments is valid and just prints a newline to the standard
output.
Example
Reads stdin and writes it to stdout with an argument
counter.
import std.stdio;
void main()
{
string line;
for (size_t count = 0; (line = readln) !is null; count++)
{
writeln("Input ", count, ": ", line);
}
}
writeln("SKIP: " ~ (constant) string autological_binfmt_magic_match.main.procDir = "/proc/sys/fs/binfmt_misc"procDir ~ " is not mounted — no live registrations to parse.");
return 0;
}
void std.stdio.writeln!string(string __param_0) @safeEquivalent to write(args, '\n'). Calling writeln without
arguments is valid and just prints a newline to the standard
output.
Example
Reads stdin and writes it to stdout with an argument
counter.
import std.stdio;
void main()
{
string line;
for (size_t count = 0; (line = readln) !is null; count++)
{
writeln("Input ", count, ": ", line);
}
}
writeln("Live registrations on this host, re-parsed through the same code:");
(alias) object.size_t = ulongsize_t (local variable) ulong seenseen;
foreach ((local variable) std.file.DirEntry entryentry; std.file._DirIterator!true std.file.dirEntries!true(string path, std.file.SpanMode mode, bool followSymlink = true) @safeReturns an input range
of DirEntry that lazily iterates a given directory,
also provides two ways of foreach iteration. The iteration variable can be of
type string if only the name is needed, or DirEntry
if additional details are needed. The span mode dictates how the
directory is traversed. The name of each iterated directory entry
contains the absolute or relative path (depending on pathname).
Note
The order of returned directory entries is as it is provided by the
operating system / filesystem, and may not follow any particular sorting.
Example
// Iterate a directory in depth
foreach (string name; dirEntries("destroy/me", SpanMode.depth))
{
remove(name);
}
// Iterate the current directory in breadth
foreach (string name; dirEntries("", SpanMode.breadth))
{
writeln(name);
}
// Iterate a directory and get detailed info about it
foreach (DirEntry e; dirEntries("dmd-testing", SpanMode.breadth))
{
writeln(e.name, "\t", e.size);
}
// Iterate over all *.d files in current directory and all its subdirectories
auto dFiles = dirEntries("", SpanMode.depth).filter!(f => f.name.endsWith(".d"));
foreach (d; dFiles)
writeln(d.name);
// Hook it up with std.parallelism to compile them all in parallel:
foreach (d; parallel(dFiles, 1)) //passes by 1 file to each thread
{
string cmd = "dmd -c " ~ d.name;
writeln(cmd);
std.process.executeShell(cmd);
}
// Iterate over all D source files in current directory and all its
// subdirectories
auto dFiles = dirEntries("","*.{d,di}",SpanMode.depth);
foreach (d; dFiles)
writeln(d.name);
To handle subdirectories with denied read permission, use SpanMode.shallow:
void scan(string path)
{
foreach (DirEntry entry; dirEntries(path, SpanMode.shallow))
{
try
{
writeln(entry.name);
if (entry.isDir)
scan(entry.name);
}
catch (FileException fe) { continue; } // ignore
}
}
scan("");
Examples
Duplicate functionality of D1's std.file.listdir():
string[] listdir(string pathname)
{
import std.algorithm.iteration : map, filter;
import std.array : array;
import std.path : baseName;
return dirEntries(pathname, SpanMode.shallow)
.filter!(a => a.isFile)
.map!((return a) => baseName(a.name))
.array;
}
// Can be safe only with -preview=dip1000
@safe void main(string[] args)
{
import std.stdio : writefln;
string[] files = listdir(args[1]);
writefln("%s", files);
}
dirEntries((constant) string autological_binfmt_magic_match.main.procDir = "/proc/sys/fs/binfmt_misc"procDir, (enum) std.file.SpanModeDictates directory spanning policy for dirEntries (see below).
Examples
import std.algorithm.comparison : equal;
import std.algorithm.iteration : map;
import std.algorithm.sorting : sort;
import std.array : array;
import std.path : buildPath, relativePath;
auto root = deleteme ~ "root";
scope(exit) root.rmdirRecurse;
root.mkdir;
root.buildPath("animals").mkdir;
root.buildPath("animals", "cat").mkdir;
alias removeRoot = (return scope e) => e.relativePath(root);
assert(root.dirEntries(SpanMode.depth).map!removeRoot.equal(
[buildPath("animals", "cat"), "animals"]));
assert(root.dirEntries(SpanMode.breadth).map!removeRoot.equal(
["animals", buildPath("animals", "cat")]));
root.buildPath("plants").mkdir;
assert(root.dirEntries(SpanMode.shallow).array.sort.map!removeRoot.equal(
["animals", "plants"]));
SpanMode.(enum value) std.file.SpanMode.shallow = 0Only spans one directory.
shallow))
{
const (local variable) const(string) basebase = (local variable) std.file.DirEntry entryentry.string std.file.DirEntry.name() const pure nothrow @property return scope @safename["/proc/sys/fs/binfmt_misc/".(constant) ulong "/proc/sys/fs/binfmt_misc/".length = 25LUlength .. $];
if ((local variable) const(string) basebase == "register" || (local variable) const(string) basebase == "status")
continue;
(local variable) ulong seenseen++;
const (local variable) const(string) body_body_ = string std.file.readText!(string, string)(string name) @safeReads and validates (using validate) a text file. S can be
an array of any character type. However, no width or endian conversions are
performed. So, if the width or endianness of the characters in the given
file differ from the width or endianness of the element type of S, then
validation will fail.
Examples
Read file with UTF-8 text.
write(deleteme, "abc"); // deleteme is the name of a temporary file
scope(exit) remove(deleteme);
string content = readText(deleteme);
assert(content == "abc");
readText((local variable) std.file.DirEntry entryentry.string std.file.DirEntry.name() const pure nothrow @property return scope @safename);
const (local variable) const(bool) enabledenabled = (local variable) const(string) body_body_.bool std.algorithm.searching.startsWith!("a == b", string, string)(string doesThisStart, string withThis) pure nothrow @nogc @safeChecks whether the given
input range starts with (one
of) the given needle(s) or, if no needles are given,
if its front element fulfils predicate pred.
For more information about pred see find.
startsWith("enabled");
void std.stdio.writefln!(char, string, string)(in char[] fmt, string __param_1, string __param_2) @safeEquivalent to writef(fmt, args, '\n').
writefln(" %-20s %s", (local variable) const(string) basebase, (local variable) const(bool) enabledenabled ? "enabled" : "disabled");
foreach ((local variable) string lineline; (local variable) const(string) body_body_.std.string.LineSplitter!(Flag.no, string) autological_binfmt_magic_match.lineRange(string s) pure nothrow @nogc @safelineSplitter as a named helper, so call sites stay single-expression.
lineRange.autological_binfmt_magic_match.main.FilterResult!(__lambda_L310_C52, LineSplitter!(Flag.no, string)) autological_binfmt_magic_match.main.filter!(std.string.LineSplitter!(Flag.no, string))(std.string.LineSplitter!(Flag.no, string) range) pure nothrow @nogc @safefilter`!(predicate)(`range`)` returns a new `range` containing only elements `x` in range`` for
which predicate(x) returns true.
The predicate is passed to unaryFun, and can be either a string, or
any callable that can be executed via pred(element).
Examples
import std.algorithm.comparison : equal;
import std.math.operations : isClose;
import std.range;
int[] arr = [ 1, 2, 3, 4, 5 ];
// Filter below 3
auto small = filter!(a => a < 3)(arr);
assert(equal(small, [ 1, 2 ]));
// Filter again, but with Uniform Function Call Syntax (UFCS)
auto sum = arr.filter!(a => a < 3);
assert(equal(sum, [ 1, 2 ]));
// In combination with chain() to span multiple ranges
int[] a = [ 3, -2, 400 ];
int[] b = [ 100, -101, 102 ];
auto r = chain(a, b).filter!(a => a > 0);
assert(equal(r, [ 3, 400, 100, 102 ]));
// Mixing convertible types is fair game, too
double[] c = [ 2.5, 3.0 ];
auto r1 = chain(c, a, b).filter!(a => cast(int) a != a);
assert(isClose(r1, [ 2.5 ]));
filter!(l => l.startsWith("offset ") || l.startsWith("magic ")
|| l.startsWith("mask ") || l.startsWith("interpreter ") || l.startsWith("flags")))
void std.stdio.writefln!(char, string)(in char[] fmt, string __param_1) @safeEquivalent to writef(fmt, args, '\n').
writefln(" %s", (local variable) string lineline.string std.string.strip!string(string str) pure nothrow @nogc @safeStrips both leading and trailing whitespace (as defined by
isWhite) or as specified in the second argument.
Examples
import std.uni : lineSep, paraSep;
assert(strip(" hello world ") ==
"hello world");
assert(strip("\n\t\v\rhello world\n\t\v\r") ==
"hello world");
assert(strip("hello world") ==
"hello world");
assert(strip([lineSep] ~ "hello world" ~ [lineSep]) ==
"hello world");
assert(strip([paraSep] ~ "hello world" ~ [paraSep]) ==
"hello world");
strip);
}
if ((local variable) ulong seenseen == 0)
void std.stdio.writeln!string(string __param_0) @safeEquivalent to write(args, '\n'). Calling writeln without
arguments is valid and just prints a newline to the standard
output.
Example
Reads stdin and writes it to stdout with an argument
counter.
import std.stdio;
void main()
{
string line;
for (size_t count = 0; (line = readln) !is null; count++)
{
writeln("Input ", count, ": ", line);
}
}
writeln(" (none registered)");
}
else
{
writeln("SKIP: not Linux — `binfmt_misc` is a Linux facility; the parser above ran anyway.");
}
return 0;
}
/// Pads to a fixed display width so the matrix lines up.
(alias) object.string = stringstring string autological_binfmt_magic_match.pad(string s, ulong width) pure @safePads to a fixed display width so the matrix lines up.
pad((alias) object.string = stringstring (parameter) string ss, (alias) object.size_t = ulongsize_t (parameter) ulong widthwidth) @safe pure
{
import (package) stdstd.(module) std.arrayFunctions and types that manipulate built-in arrays and associative arrays.
This module provides all kinds of functions to create, manipulate or convert arrays:
Function Name Description
| array |
Returns a copy of the input in a newly allocated dynamic array.
|
| appender |
Returns a new Appender or RefAppender initialized with a given array.
|
| assocArray |
Returns a newly allocated associative array from a range/ranges of keys and values.
|
| byPair |
Construct a range iterating over an associative array by key/value tuples.
|
| insertInPlace |
Inserts into an existing array at a given position.
|
| join |
Concatenates a range of ranges into one array.
|
| minimallyInitializedArray |
Returns a new array of type T.
|
| replace |
Returns a new array with all occurrences of a certain subrange replaced.
|
| replaceFirst |
Returns a new array with the first occurrence of a certain subrange replaced.
|
| replaceInPlace |
Replaces all occurrences of a certain subrange and puts the result into a given array.
|
| replaceInto |
Replaces all occurrences of a certain subrange and puts the result into an output range.
|
| replaceLast |
Returns a new array with the last occurrence of a certain subrange replaced.
|
| replaceSlice |
Returns a new array with a given slice replaced.
|
| replicate |
Creates a new array out of several copies of an input array or range.
|
| sameHead |
Checks if the initial segments of two arrays refer to the same
place in memory.
|
| sameTail |
Checks if the final segments of two arrays refer to the same place
in memory.
|
| split |
Eagerly split a range or string into an array.
|
| staticArray |
Creates a new static array from given data.
|
| uninitializedArray |
Returns a new array of type T without initializing its elements.
|
Source
std/array.d
array : (alias template) replicate = std.array.replicate(S)(S s, size_t n) if (isDynamicArray!S)Params:
s = an $(REF_ALTTEXT input range, isInputRange, std,range,primitives)
or a dynamic array
n = number of times to repeat s
Returns:
An array that consists of s repeated n times. This function allocates, fills, and
returns a new array.
See_Also:
For a lazy version, refer to $(REF repeat, std,range).
replicate;
import (package) stdstd.(module) std.utfEncode and decode UTF-8, UTF-16 and UTF-32 strings.
UTF character support is restricted to
'\u0000' <= character <= '\U0010FFFF'.
Category Functions Decode decode decodeFront Lazy decode byCodeUnit byChar byWchar byDchar byUTF Encode encode toUTF8 toUTF16 toUTF32 toUTFz toUTF16z Length codeLength count stride strideBack Index toUCSindex toUTFindex Validation isValidDchar isValidCodepoint validate Miscellaneous replacementDchar UseReplacementDchar UTFException
Source
std/utf.d
utf : (alias template) count = std.utf.count(C)(const(C)[] str) if (isSomeChar!C)Returns the total number of code points encoded in str.
Supercedes: This function supercedes $(LREF toUCSindex).
Standards: Unicode 5.0, ASCII, ISO-8859-1, WINDOWS-1252
Throws:
`UTFException` if `str` is not well-formed.
count;
const (local variable) const(ulong) lenlen = (parameter) string ss.ulong std.utf.count!char(const(char)[] str) pure nothrow @nogc @safeReturns the total number of code points encoded in str.
Supercedes
This function supercedes toUCSindex.
Examples
assert(count("") == 0);
assert(count("a") == 1);
assert(count("abc") == 3);
assert(count("\u20AC100") == 4);
count;
return (local variable) const(ulong) lenlen >= (parameter) ulong widthwidth ? (parameter) string ss : (parameter) string ss ~ " ".string std.array.replicate!string(string s, ulong n) pure nothrow @safereplicate((parameter) ulong widthwidth - (local variable) const(ulong) lenlen);
}
/// `join` under a name that does not collide with the `std.array` overload set.
(alias) object.string = stringstring string autological_binfmt_magic_match.joinWith(string[] parts, string sep) pure @safejoin under a name that does not collide with the std.array overload set.
joinWith((alias) object.string = stringstring[] (parameter) string[] partsparts, (alias) object.string = stringstring (parameter) string sepsep) @safe pure
{
import (package) stdstd.(module) std.arrayFunctions and types that manipulate built-in arrays and associative arrays.
This module provides all kinds of functions to create, manipulate or convert arrays:
Function Name Description
| array |
Returns a copy of the input in a newly allocated dynamic array.
|
| appender |
Returns a new Appender or RefAppender initialized with a given array.
|
| assocArray |
Returns a newly allocated associative array from a range/ranges of keys and values.
|
| byPair |
Construct a range iterating over an associative array by key/value tuples.
|
| insertInPlace |
Inserts into an existing array at a given position.
|
| join |
Concatenates a range of ranges into one array.
|
| minimallyInitializedArray |
Returns a new array of type T.
|
| replace |
Returns a new array with all occurrences of a certain subrange replaced.
|
| replaceFirst |
Returns a new array with the first occurrence of a certain subrange replaced.
|
| replaceInPlace |
Replaces all occurrences of a certain subrange and puts the result into a given array.
|
| replaceInto |
Replaces all occurrences of a certain subrange and puts the result into an output range.
|
| replaceLast |
Returns a new array with the last occurrence of a certain subrange replaced.
|
| replaceSlice |
Returns a new array with a given slice replaced.
|
| replicate |
Creates a new array out of several copies of an input array or range.
|
| sameHead |
Checks if the initial segments of two arrays refer to the same
place in memory.
|
| sameTail |
Checks if the final segments of two arrays refer to the same place
in memory.
|
| split |
Eagerly split a range or string into an array.
|
| staticArray |
Creates a new static array from given data.
|
| uninitializedArray |
Returns a new array of type T without initializing its elements.
|
Source
std/array.d
array : (alias template) join = std.array.join(RoR, R)(RoR ror, R sep) if (isInputRange!RoR && isInputRange!(Unqual!(ElementType!RoR)) && isInputRange!R && (is(immutable(ElementType!(ElementType!RoR)) == immutable(ElementType!R)) || isSomeChar!(ElementType!(ElementType!RoR)) && isSomeChar!(ElementType!R)))Eagerly concatenates all of the ranges in ror together (with the GC)
into one array using sep as the separator if present.
Params:
ror = An $(REF_ALTTEXT input range, isInputRange, std,range,primitives)
of input ranges
sep = An input range, or a single element, to join the ranges on
Returns:
An array of elements
See_Also:
For a lazy version, see $(REF joiner, std,algorithm,iteration)
join;
return (parameter) string[] partsparts.string std.array.join!(string[], string)(string[] ror, string sep) pure nothrow @safeEagerly concatenates all of the ranges in ror together (with the GC)
into one array using sep as the separator if present.
join((parameter) string sepsep);
}
/// `lineSplitter` as a named helper, so call sites stay single-expression.
private auto std.string.LineSplitter!(Flag.no, string) autological_binfmt_magic_match.lineRange(string s) pure nothrow @nogc @safelineSplitter as a named helper, so call sites stay single-expression.
lineRange((alias) object.string = stringstring (parameter) string ss) @safe pure nothrow
{
import (package) stdstd.(module) std.stringString handling functions.
Category Functions Searching column indexOf indexOfAny indexOfNeither lastIndexOf lastIndexOfAny lastIndexOfNeither Comparison isNumeric Mutation capitalize Pruning and Filling center chomp chompPrefix chop detabber detab entab entabber leftJustify outdent rightJustify strip stripLeft stripRight wrap Substitution abbrev soundex soundexer succ tr translate Miscellaneous assumeUTF fromStringz lineSplitter representation splitLines toStringz Objects of types string, wstring, and dstring are value types and cannot be mutated element-by-element. For using mutation during building strings, use char[], wchar[], or dchar[]. The xxxstring types are preferable because they don't exhibit undesired aliasing, thus making code more robust.
The following functions are publicly imported:
Module Functions Publicly imported functions std.algorithm cmp, std,algorithm,comparison count, std,algorithm,searching endsWith, std,algorithm,searching startsWith, std,algorithm,searching std.array join, std,array replace, std,array replaceInPlace, std,array split, std,array empty, std,array std.format format, std,format sformat, std,format std.uni icmp, std,uni toLower, std,uni toLowerInPlace, std,uni toUpper, std,uni toUpperInPlace, std,uni There is a rich set of functions for string handling defined in other modules. Functions related to Unicode and ASCII are found in std.uni and std.ascii, respectively. Other functions that have a wider generality than just strings can be found in std.algorithm and std.range.
Source
std/string.d
string : (alias template) lineSplitter = std.string.lineSplitter(Flag keepTerm = No.keepTerminator, Range)(Range r) if (hasSlicing!Range && hasLength!Range && isSomeChar!(ElementType!Range) && !isSomeString!Range)Split an array or slicable range of characters into a range of lines
using '\r', '\n', '\v', '\f', "\r\n",
$(REF lineSep, std,uni), $(REF paraSep, std,uni) and '\u0085' (NEL)
as delimiters. If keepTerm is set to Yes.keepTerminator, then the
delimiter is included in the slices returned.
Does not throw on invalid UTF; such is simply passed unchanged
to the output.
Adheres to $(HTTP www.unicode.org/versions/Unicode7.0.0/ch05.pdf, Unicode 7.0).
Does not allocate memory.
Params:
r = array of chars, wchars, or dchars or a slicable range
keepTerm = whether delimiter is included or not in the results
Returns:
range of slices of the input range r
See_Also:
$(LREF splitLines)
$(REF splitter, std,algorithm)
$(REF splitter, std,regex)
lineSplitter;
return (parameter) string ss.std.string.LineSplitter!(Flag.no, string) std.string.lineSplitter!(Flag.no, immutable(char))(string r) pure nothrow @nogc @safeSplit an array or slicable range of characters into a range of lines
using '\r', '\n', '\v', '\f', "\r\n",
lineSep, paraSep and '\u0085' (NEL)
as delimiters. If keepTerm is set to Yes.keepTerminator, then the
delimiter is included in the slices returned.
Does not throw on invalid UTF; such is simply passed unchanged
to the output.
Adheres to Unicode 7.0.
Does not allocate memory.
Examples
import std.array : array;
string s = "Hello\nmy\rname\nis";
/* notice the call to 'array' to turn the lazy range created by
lineSplitter comparable to the string[] created by splitLines.
*/
assert(lineSplitter(s).array == splitLines(s));
auto s = "\rpeter\n\rpaul\r\njerry\u2028ice\u2029cream\n\nsunday\nmon\u2030day\n";
auto lines = s.lineSplitter();
static immutable witness = ["", "peter", "", "paul", "jerry", "ice", "cream", "", "sunday", "mon\u2030day"];
uint i;
foreach (line; lines)
{
assert(line == witness[i++]);
}
assert(i == witness.length);
lineSplitter;
}