mirror of
https://github.com/dlang/phobos.git
synced 2025-05-02 08:00:48 +03:00
* std.algorithm: Changed the map() function so that it deduces the return type
* std.contracts: Added file and line information to enforce. Added errnoEnforce that reads and formats a message according to errno. Added corresponding ErrnoException class. * std.encoding: For now commented out std.encoding.to. * std.file: Fixed bug 2065 * std.format: Fixed bug in raw write for arrays * std.getopt: Added new option stopOnFirstNonOption. Also automatically expand dubious option groups with embedded in them (useful for shebang scripts) * std.math: improved integral powers * std.md5: Improved signature of sum so it takes multiple arrays. Added getDigestString. * std.path: changed signatures of test functions from bool to int. Implemented rel2abs for Windows. Improved join so that it accepts multiple paths. Got rid of some gotos with the help of scope statements. * std.process: added getenv and setenv. Improved system() so it returns the exit code correctly on Linux. * std.random: added the dice function - a handy (possibly biased) dice. * std.file: added support for opening large files (not yet tested) * std.utf: added the codeLength function. Got rid of some gotos.
This commit is contained in:
parent
b60c31f0f2
commit
1ae5300f52
27 changed files with 974 additions and 654 deletions
|
@ -117,13 +117,13 @@ auto squares = map!("a * a")(cast(int[]) null, arr);
|
|||
assert(is(typeof(squares) == int[]));
|
||||
----
|
||||
*/
|
||||
Ranges[0] map(string fun, Ranges...)(Ranges rs)
|
||||
typeof(unaryFun!(fun)(*begin(Ranges[0])))[] map(string fun, Ranges...)(Ranges rs)
|
||||
{
|
||||
return .map!(unaryFun!(fun), Ranges)(rs);
|
||||
}
|
||||
|
||||
/// Ditto
|
||||
Ranges[0] map(alias fun, Ranges...)(Ranges rs)
|
||||
typeof(fun(*begin(Ranges[0])))[] map(alias fun, Ranges...)(Ranges rs)
|
||||
{
|
||||
typeof(return) result;
|
||||
foreach (r, R; Ranges)
|
||||
|
@ -289,7 +289,7 @@ template reduce(F...)
|
|||
// Prime the result
|
||||
static if (F.length > 1)
|
||||
{
|
||||
foreach (j, f; F) // for all functions
|
||||
foreach (j, unused; args[0 .. F.length]) // for all functions
|
||||
{
|
||||
// @@@BUG@@@
|
||||
auto p = mixin("&result.field!("~ToString!(j)~")");
|
||||
|
@ -1064,42 +1064,42 @@ bool canFind(alias pred, Range, E)(Range haystack, E needle)
|
|||
/// Ditto
|
||||
bool canFind(string pred = q{a == b}, Range, E)(Range haystack, E needle)
|
||||
{
|
||||
return find!(pred)(haystack, needle) != end(haystack);
|
||||
return find!(binaryFun!(pred), Range, E)(haystack, needle) != end(haystack);
|
||||
}
|
||||
|
||||
/// Ditto
|
||||
bool canFind(alias pred, Range, E)(Range haystack)
|
||||
bool canFind(alias pred, Range)(Range haystack)
|
||||
{
|
||||
return find!(pred)(haystack) != end(haystack);
|
||||
}
|
||||
|
||||
/// Ditto
|
||||
bool canFind(string pred, Range, E)(Range haystack)
|
||||
bool canFind(string pred, Range)(Range haystack)
|
||||
{
|
||||
return find!(pred)(haystack) != end(haystack);
|
||||
return find!(unaryFun!(pred))(haystack) != end(haystack);
|
||||
}
|
||||
|
||||
/// Ditto
|
||||
bool canFindAmong(alias pred, Range1, Range2)(Range seq, Range2 choices)
|
||||
bool canFindAmong(alias pred, Range1, Range2)(Range1 seq, Range2 choices)
|
||||
{
|
||||
return findAmong!(pred)(seq, choices) != end(seq);
|
||||
}
|
||||
|
||||
/// Ditto
|
||||
bool canFindAmong(string pred, Range1, Range2)(Range seq, Range2 choices)
|
||||
bool canFindAmong(string pred, Range1, Range2)(Range1 seq, Range2 choices)
|
||||
{
|
||||
return findAmong!(pred)(seq, choices) != end(seq);
|
||||
return findAmong!(binaryFun!(pred))(seq, choices) != end(seq);
|
||||
}
|
||||
|
||||
/// Ditto
|
||||
bool canFindAmongSorted(alias pred, Range1, Range2)(Range seq, Range2 choices)
|
||||
bool canFindAmongSorted(alias pred, Range1, Range2)(Range1 seq, Range2 choices)
|
||||
{
|
||||
return canFindAmongSorted!(pred)(seq, choices) != end(seq);
|
||||
}
|
||||
|
||||
/// Ditto
|
||||
bool canFindAmongSorted(string pred, Range1, Range2)(
|
||||
Range seq, Range2 choices)
|
||||
Range1 seq, Range2 choices)
|
||||
{
|
||||
return canFindAmongSorted!(pred)(seq, choices) != end(seq);
|
||||
}
|
||||
|
@ -2536,7 +2536,7 @@ void sort(string less = q{a < b}, SwapStrategy ss = SwapStrategy.unstable,
|
|||
return .sort!(binaryFun!(less), ss, iterSwap, Range)(r);
|
||||
}
|
||||
|
||||
import std.string;
|
||||
version(unittest) import std.string;
|
||||
|
||||
unittest
|
||||
{
|
||||
|
@ -2582,6 +2582,7 @@ unittest
|
|||
assert(isSorted!("toupper(a) < toupper(b)")(b));
|
||||
}
|
||||
|
||||
// @@@BUG1904
|
||||
/*private*/
|
||||
Iter getPivot(alias less, Iter)(Iter b, Iter e)
|
||||
{
|
||||
|
@ -2589,6 +2590,7 @@ Iter getPivot(alias less, Iter)(Iter b, Iter e)
|
|||
return r;
|
||||
}
|
||||
|
||||
// @@@BUG1904
|
||||
/*private*/
|
||||
void optimisticInsertionSort(alias less, alias iterSwap, Range)(Range r)
|
||||
{
|
||||
|
@ -2617,6 +2619,7 @@ void optimisticInsertionSort(alias less, alias iterSwap, Range)(Range r)
|
|||
}
|
||||
}
|
||||
|
||||
// @@@BUG1904
|
||||
/*private*/
|
||||
void sortImpl(alias less, SwapStrategy ss, alias iterSwap, Range)(Range r)
|
||||
{
|
||||
|
@ -2900,7 +2903,8 @@ bool isSorted(string less = "a < b", Range)(Range r)
|
|||
// }
|
||||
|
||||
// topNIndexImpl
|
||||
private void topNIndexImpl(
|
||||
// @@@BUG1904
|
||||
/*private*/ void topNIndexImpl(
|
||||
alias less,
|
||||
bool sortAfter,
|
||||
SwapStrategy ss,
|
||||
|
@ -3451,7 +3455,8 @@ unittest
|
|||
assert(a == [ 16, 14, 10, 8, 7, 9, 3, 2, 4, 1 ]);
|
||||
}
|
||||
|
||||
private void heapify(alias less, alias iterSwap, Range, It)(Range r, It i)
|
||||
/*private*/
|
||||
void heapify(alias less, alias iterSwap, Range, It)(Range r, It i)
|
||||
{
|
||||
auto b = begin(r);
|
||||
for (;;)
|
||||
|
|
|
@ -309,7 +309,7 @@ struct BitArray
|
|||
}
|
||||
body
|
||||
{
|
||||
return cast(bool)bt(ptr, i);
|
||||
return cast(bool) bt(ptr, i);
|
||||
}
|
||||
|
||||
unittest
|
||||
|
|
|
@ -195,6 +195,8 @@ struct tm
|
|||
|
||||
extern (C)
|
||||
{
|
||||
int utimes(const char *path, timeval* times);
|
||||
|
||||
int gettimeofday(timeval*, struct_timezone*);
|
||||
int settimeofday(in timeval*, in struct_timezone*);
|
||||
__time_t time(__time_t*);
|
||||
|
@ -418,7 +420,7 @@ extern (C)
|
|||
|
||||
void* dlopen(in char* file, int mode);
|
||||
int dlclose(void* handle);
|
||||
void* dlsym(void* handle, char* name);
|
||||
void* dlsym(void* handle, in char* name);
|
||||
char* dlerror();
|
||||
}
|
||||
|
||||
|
@ -487,7 +489,7 @@ extern (C)
|
|||
__time_t modtime;
|
||||
}
|
||||
|
||||
int utime(char* filename, utimbuf* buf);
|
||||
int utime(const char* filename, utimbuf* buf);
|
||||
}
|
||||
|
||||
extern (C)
|
||||
|
|
|
@ -32,20 +32,20 @@ int recv(int s, void* buf, int len, int flags);
|
|||
int recvfrom(int s, void* buf, int len, int flags, sockaddr* from, int* fromlen);
|
||||
int getsockopt(int s, int level, int optname, void* optval, int* optlen);
|
||||
int setsockopt(int s, int level, int optname, void* optval, int optlen);
|
||||
uint inet_addr(char* cp);
|
||||
uint inet_addr(in char* cp);
|
||||
char* inet_ntoa(in_addr ina);
|
||||
hostent* gethostbyname(char* name);
|
||||
int gethostbyname_r(char* name, hostent* ret, void* buf, size_t buflen, hostent** result, int* h_errnop);
|
||||
int gethostbyname2_r(char* name, int af, hostent* ret, void* buf, size_t buflen, hostent** result, int* h_errnop);
|
||||
hostent* gethostbyname(in char* name);
|
||||
int gethostbyname_r(in char* name, hostent* ret, void* buf, size_t buflen, hostent** result, int* h_errnop);
|
||||
int gethostbyname2_r(in char* name, int af, hostent* ret, void* buf, size_t buflen, hostent** result, int* h_errnop);
|
||||
hostent* gethostbyaddr(void* addr, int len, int type);
|
||||
protoent* getprotobyname(char* name);
|
||||
protoent* getprotobyname(in char* name);
|
||||
protoent* getprotobynumber(int number);
|
||||
servent* getservbyname(char* name, char* proto);
|
||||
servent* getservbyport(int port, char* proto);
|
||||
int gethostname(char* name, int namelen);
|
||||
int getaddrinfo(char* nodename, char* servname, addrinfo* hints, addrinfo** res);
|
||||
servent* getservbyname(in char* name, in char* proto);
|
||||
servent* getservbyport(int port, in char* proto);
|
||||
int gethostname(in char* name, int namelen);
|
||||
int getaddrinfo(in char* nodename, in char* servname, addrinfo* hints, addrinfo** res);
|
||||
void freeaddrinfo(addrinfo* ai);
|
||||
int getnameinfo(sockaddr* sa, socklen_t salen, char* node, socklen_t nodelen, char* service, socklen_t servicelen, int flags);
|
||||
int getnameinfo(sockaddr* sa, socklen_t salen, in char* node, socklen_t nodelen, in char* service, socklen_t servicelen, int flags);
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -248,9 +248,9 @@ double copysign(double x, double y); ///
|
|||
float copysignf(float x, float y); /// ditto
|
||||
real copysignl(real x, real y); /// ditto
|
||||
|
||||
double nan(const char *tagp); ///
|
||||
float nanf(const char *tagp); /// ditto
|
||||
real nanl(const char *tagp); /// ditto
|
||||
double nan(in char *tagp); ///
|
||||
float nanf(in char *tagp); /// ditto
|
||||
real nanl(in char *tagp); /// ditto
|
||||
|
||||
double nextafter(double x, double y); ///
|
||||
float nextafterf(float x, float y); /// ditto
|
||||
|
|
|
@ -174,6 +174,10 @@ alias int fpos_t; ///
|
|||
|
||||
char * tmpnam(char *); ///
|
||||
FILE * fopen(in char *,in char *); ///
|
||||
version(linux)
|
||||
{
|
||||
FILE * fopen64(in char *,in char *); ///
|
||||
}
|
||||
FILE * _fsopen(in char *,in char *,int ); ///
|
||||
FILE * freopen(in char *,in char *,FILE *); ///
|
||||
int fseek(FILE *,int,int); ///
|
||||
|
|
|
@ -57,7 +57,7 @@ struct lldiv_t { long quot,rem; }
|
|||
|
||||
char* getenv(const char*); ///
|
||||
int setenv(const char*, const char*, int); /// extension to ISO C standard, not available on all platforms
|
||||
void unsetenv(const char*); /// extension to ISO C standard, not available on all platforms
|
||||
int unsetenv(const char*); /// extension to ISO C standard, not available on all platforms
|
||||
|
||||
int rand(); ///
|
||||
void srand(uint); /// ditto
|
||||
|
@ -67,19 +67,19 @@ struct lldiv_t { long quot,rem; }
|
|||
int getErrno(); /// ditto
|
||||
int setErrno(int); /// ditto
|
||||
|
||||
const int ERANGE = 34; // on both Windows and linux
|
||||
enum int ERANGE = 34; // on both Windows and linux
|
||||
|
||||
double atof(in char *); ///
|
||||
int atoi(in char *); /// ditto
|
||||
int atol(in char *); /// ditto
|
||||
float strtof(const char *,char **); /// ditto
|
||||
double strtod(const char *,char **); /// ditto
|
||||
real strtold(const char *,char **); /// ditto
|
||||
long strtol(const char *,char **,int); /// ditto
|
||||
uint strtoul(const char *,char **,int); /// ditto
|
||||
float strtof(in char *,char **); /// ditto
|
||||
double strtod(in char *,char **); /// ditto
|
||||
real strtold(in char *,char **); /// ditto
|
||||
long strtol(in char *,char **,int); /// ditto
|
||||
uint strtoul(in char *,char **,int); /// ditto
|
||||
long atoll(in char *); /// ditto
|
||||
long strtoll(const char *,char **,int); /// ditto
|
||||
ulong strtoull(const char *,char **,int); /// ditto
|
||||
long strtoll(in char *,char **,int); /// ditto
|
||||
ulong strtoull(in char *,char **,int); /// ditto
|
||||
|
||||
char* itoa(int, char*, int); ///
|
||||
char* ultoa(uint, char*, int); /// ditto
|
||||
|
|
|
@ -41,6 +41,12 @@ private import std.conv;
|
|||
private import std.algorithm;
|
||||
private import std.iterator;
|
||||
private import std.traits;
|
||||
private import std.string;
|
||||
private import std.c.stdlib;
|
||||
version(unittest)
|
||||
{
|
||||
private import std.stdio;
|
||||
}
|
||||
|
||||
/*
|
||||
* Copyright (C) 2004-2006 by Digital Mars, www.digitalmars.com
|
||||
|
@ -75,10 +81,11 @@ private import std.traits;
|
|||
* ----
|
||||
*/
|
||||
|
||||
T enforce(T)(T value, lazy string msg = "Enforcement error ")
|
||||
T enforce(T)(T value, lazy string msg = "Enforcement error ",
|
||||
string file = __FILE__, int line = __LINE__)
|
||||
{
|
||||
if (value) return value;
|
||||
throw new Exception(msg);
|
||||
if (!value) throw new Exception(text(file, '(', line, "): ", msg));
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -94,8 +101,8 @@ T enforce(T)(T value, lazy string msg = "Enforcement error ")
|
|||
|
||||
T enforce(T)(T value, lazy Exception ex)
|
||||
{
|
||||
if (value) return value;
|
||||
throw ex();
|
||||
if (!value) throw ex();
|
||||
return value;
|
||||
}
|
||||
|
||||
unittest
|
||||
|
@ -111,6 +118,27 @@ unittest
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
If $(D value) is nonzero, returns it. Otherwise, throws $(D new
|
||||
ErrnoException(msg)). The $(D ErrnoException) class assumes that the
|
||||
last operation has set $(D errno) to an error code.
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* ----
|
||||
* auto f = errnoEnforce(fopen("data.txt"));
|
||||
* auto line = readln(f);
|
||||
* enforce(line.length); // expect a non-empty line
|
||||
* ----
|
||||
*/
|
||||
|
||||
T errnoEnforce(T)(T value, lazy string msg = "Enforcement error ",
|
||||
string file = __FILE__, int line = __LINE__)
|
||||
{
|
||||
if (!value) throw new ErrnoException(msg);
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* If $(D_PARAM value) is nonzero, returns it. Otherwise, throws
|
||||
* $(D_PARAM new E(msg)).
|
||||
|
@ -126,8 +154,8 @@ template enforceEx(E)
|
|||
{
|
||||
T enforceEx(T)(T value, lazy string msg = "")
|
||||
{
|
||||
if (value) return value;
|
||||
throw new E(msg);
|
||||
if (!value) throw new E(msg);
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -363,3 +391,41 @@ unittest
|
|||
a8[0] = a7;
|
||||
assert(!pointsTo(a8[0], a8[0]));
|
||||
}
|
||||
|
||||
/*********************
|
||||
* Thrown if errors that set $(D errno) happen.
|
||||
*/
|
||||
class ErrnoException : Exception
|
||||
{
|
||||
uint errno; // operating system error code
|
||||
|
||||
this(string msg)
|
||||
{
|
||||
super(msg);
|
||||
}
|
||||
|
||||
this(uint errno)
|
||||
{
|
||||
version (linux)
|
||||
{
|
||||
char[80] buf = void;
|
||||
auto s = std.string.strerror_r(errno, buf.ptr, buf.length);
|
||||
}
|
||||
else
|
||||
{
|
||||
auto s = std.string.strerror(errno);
|
||||
}
|
||||
super(std.string.toString(s).idup);
|
||||
}
|
||||
|
||||
static void opCall(string msg)
|
||||
{
|
||||
throw new ErrnoException(msg);
|
||||
}
|
||||
|
||||
static void opCall()
|
||||
{
|
||||
throw new ErrnoException(getErrno());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1352,7 +1352,7 @@ float toFloat(Char)(Char[] s)
|
|||
F parseFloating(S : S[], F)(ref S[] s)
|
||||
{
|
||||
//writefln("toFloat('%s')", s);
|
||||
auto sz = toStringz(s);
|
||||
auto sz = toStringz(to!(const char[])(s));
|
||||
if (std.ctype.isspace(*sz))
|
||||
goto Lerr;
|
||||
|
||||
|
@ -1381,7 +1381,7 @@ F parseFloating(S : S[], F)(ref S[] s)
|
|||
if (getErrno() == ERANGE)
|
||||
goto Lerr;
|
||||
assert(endptr);
|
||||
if (endptr == s.ptr)
|
||||
if (endptr == sz)
|
||||
{
|
||||
// no progress
|
||||
goto Lerr;
|
||||
|
|
|
@ -70,7 +70,7 @@ enum
|
|||
MinutesPerHour = 60,
|
||||
msPerMinute = 60 * 1000,
|
||||
msPerHour = 60 * msPerMinute,
|
||||
msPerDay = 86400000,
|
||||
msPerDay = 86_400_000,
|
||||
TicksPerMs = 1,
|
||||
TicksPerSecond = 1000, /// Will be at least 1000
|
||||
TicksPerMinute = TicksPerSecond * 60,
|
||||
|
@ -80,9 +80,8 @@ enum
|
|||
|
||||
d_time LocalTZA = 0;
|
||||
|
||||
|
||||
const char[] daystr = "SunMonTueWedThuFriSat";
|
||||
const char[] monstr = "JanFebMarAprMayJunJulAugSepOctNovDec";
|
||||
invariant char[] daystr = "SunMonTueWedThuFriSat";
|
||||
invariant char[] monstr = "JanFebMarAprMayJunJulAugSepOctNovDec";
|
||||
|
||||
const int[12] mdays = [ 0,31,59,90,120,151,181,212,243,273,304,334 ];
|
||||
|
||||
|
|
|
@ -308,15 +308,16 @@ unittest
|
|||
|
||||
// Make sure the non-UTF encodings work too
|
||||
{
|
||||
// TODO: commented out for now
|
||||
auto s = "\u20AC100";
|
||||
auto t = to!(Windows1252)(s);
|
||||
assert(t == [cast(Windows1252)0x80, '1', '0', '0']);
|
||||
auto u = to!(Utf8)(s);
|
||||
assert(s == u);
|
||||
auto v = to!(Latin1)(s);
|
||||
assert(cast(string)v == "?100");
|
||||
auto w = to!(Ascii)(v);
|
||||
assert(cast(string)w == "?100");
|
||||
// auto t = to!(Windows1252)(s);
|
||||
// assert(t == [cast(Windows1252)0x80, '1', '0', '0']);
|
||||
// auto u = to!(Utf8)(s);
|
||||
// assert(s == u);
|
||||
// auto v = to!(Latin1)(s);
|
||||
// assert(cast(string)v == "?100");
|
||||
// auto w = to!(Ascii)(v);
|
||||
// assert(cast(string)w == "?100");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1861,17 +1862,18 @@ body
|
|||
* auto ls = to!(Latin1)(ws); // transcode from UTF-16 to ISO-8859-1
|
||||
* -----------------------------------------------------------------------------
|
||||
*/
|
||||
invariant(Dst)[] to(Dst,Src)(invariant(Src)[] s)
|
||||
in
|
||||
{
|
||||
assert(isValid(s));
|
||||
}
|
||||
body
|
||||
{
|
||||
invariant(Dst)[] r;
|
||||
transcode(s,r);
|
||||
return r;
|
||||
}
|
||||
// TODO: Commented out for no - to be moved to std.conv
|
||||
// Dst to(Dst,Src)(invariant(Src)[] s)
|
||||
// in
|
||||
// {
|
||||
// assert(isValid(s));
|
||||
// }
|
||||
// body
|
||||
// {
|
||||
// Dst r;
|
||||
// transcode(s,r);
|
||||
// return r;
|
||||
// }
|
||||
|
||||
//=============================================================================
|
||||
|
||||
|
|
|
@ -363,7 +363,7 @@ bool exists(in string name)
|
|||
else
|
||||
result = GetFileAttributesA(toMBSz(name));
|
||||
|
||||
return result == 0xFFFFFFFF;
|
||||
return result != 0xFFFFFFFF;
|
||||
}
|
||||
|
||||
/***************************************************
|
||||
|
|
|
@ -2023,13 +2023,13 @@ private void formatGeneric(Writer, D)(ref Writer w, const(void)* arg,
|
|||
w.putchar('[');
|
||||
w.putchar(']');
|
||||
} else static if (isArray!(D)) {
|
||||
w.putchar('[');
|
||||
if (f.spec != 'r') w.putchar('['); // only write the brackets if not raw
|
||||
foreach (i, e; obj)
|
||||
{
|
||||
if (i > 0) w.putchar(' ');
|
||||
if (f.spec != 'r' && i > 0) w.putchar(' ');
|
||||
formatGeneric!(Writer, typeof(e))(w, &e, f);
|
||||
}
|
||||
w.putchar(']');
|
||||
if (f.spec != 'r') w.putchar(']'); // only write the brackets if not raw
|
||||
} else static if (is(const(D) : const void*)) {
|
||||
f.spec = 'X';
|
||||
ulong fake = cast(ulong) obj;
|
||||
|
|
345
std/getopt.d
345
std/getopt.d
|
@ -2,30 +2,30 @@
|
|||
// Written in the D programming language.
|
||||
|
||||
/**
|
||||
* Processing of command line options.
|
||||
*
|
||||
* The getopt module implements a $(D_PARAM getopt) function, which
|
||||
* adheres to the POSIX syntax for command line options. GNU
|
||||
* extensions are supported in the form of long options introduced by
|
||||
* a double dash ("--"). Support for bundling of command line options,
|
||||
* as was the case with the more traditional single-letter approach,
|
||||
* is provided but not enabled by default.
|
||||
*
|
||||
Author:
|
||||
Processing of command line options.
|
||||
|
||||
$(WEB erdani.org, Andrei Alexandrescu)
|
||||
*
|
||||
* Credits:
|
||||
*
|
||||
* This module and its documentation are inspired by Perl's
|
||||
* $(LINK2 http://perldoc.perl.org/Getopt/Long.html,Getopt::Long) module. The
|
||||
* syntax of D's $(D_PARAM getopt) is simplified because $(D_PARAM
|
||||
* getopt) infers the expected parameter types from the static types
|
||||
* of the passed-in pointers.
|
||||
*
|
||||
* Macros:
|
||||
* WIKI = Phobos/StdGetopt
|
||||
*/
|
||||
The getopt module implements a $(D getopt) function, which adheres to
|
||||
the POSIX syntax for command line options. GNU extensions are
|
||||
supported in the form of long options introduced by a double dash
|
||||
("--"). Support for bundling of command line options, as was the case
|
||||
with the more traditional single-letter approach, is provided but not
|
||||
enabled by default.
|
||||
|
||||
Author:
|
||||
|
||||
$(WEB erdani.org, Andrei Alexandrescu)
|
||||
|
||||
Credits:
|
||||
|
||||
This module and its documentation are inspired by Perl's $(WEB
|
||||
perldoc.perl.org/Getopt/Long.html, Getopt::Long) module. The syntax of
|
||||
D's $(D getopt) is simpler than its Perl counterpart because $(D
|
||||
getopt) infers the expected parameter types from the static types of
|
||||
the passed-in pointers.
|
||||
|
||||
Macros:
|
||||
WIKI = Phobos/StdGetopt
|
||||
*/
|
||||
|
||||
/* Author:
|
||||
* Andrei Alexandrescu, www.erdani.org
|
||||
|
@ -49,9 +49,12 @@
|
|||
*/
|
||||
|
||||
module std.getopt;
|
||||
import std.string, std.conv, std.traits;
|
||||
|
||||
import std.stdio; // for testing only
|
||||
private import std.string, std.conv, std.traits, std.contracts, std.bitmanip,
|
||||
std.algorithm, std.ctype;
|
||||
//version (unittest)
|
||||
//{
|
||||
import std.stdio; // for testing only
|
||||
//}
|
||||
|
||||
/**
|
||||
Synopsis:
|
||||
|
@ -74,28 +77,28 @@ void main(string[] args)
|
|||
}
|
||||
---------
|
||||
|
||||
The $(D_PARAM getopt) function takes a reference to the command line
|
||||
(as received by $(D_PARAM main)) as its first argument, and an
|
||||
The $(D getopt) function takes a reference to the command line
|
||||
(as received by $(D main)) as its first argument, and an
|
||||
unbounded number of pairs of strings and pointers. Each string is an
|
||||
option meant to "fill" the value pointed-to by the pointer to its
|
||||
right (the "bound" pointer). The option string in the call to
|
||||
$(D_PARAM getopt) should not start with a dash.
|
||||
$(D getopt) should not start with a dash.
|
||||
|
||||
In all cases, the command-line options that were parsed and used by
|
||||
$(D_PARAM getopt) are removed from $(D_PARAM args). Whatever in the
|
||||
arguments did not look like an option is left in $(D_PARAM args) for
|
||||
$(D getopt) are removed from $(D args). Whatever in the
|
||||
arguments did not look like an option is left in $(D args) for
|
||||
further processing by the program. Values that were unaffected by the
|
||||
options are not touched, so a common idiom is to initialize options
|
||||
to their defaults and then invoke $(D_PARAM getopt). If a
|
||||
to their defaults and then invoke $(D getopt). If a
|
||||
command-line argument is recognized as an option with a parameter and
|
||||
the parameter cannot be parsed properly (e.g. a number is expected
|
||||
but not present), a $(D_PARAM ConvError) exception is thrown.
|
||||
but not present), a $(D ConvError) exception is thrown.
|
||||
|
||||
Depending on the type of the pointer being bound, $(D_PARAM getopt)
|
||||
Depending on the type of the pointer being bound, $(D getopt)
|
||||
recognizes the following kinds of options:
|
||||
|
||||
$(OL $(LI $(I Boolean options). These are the simplest options; all
|
||||
they do is set a Boolean to $(D_PARAM true):
|
||||
they do is set a Boolean to $(D true):
|
||||
|
||||
---------
|
||||
bool verbose, debugging;
|
||||
|
@ -112,7 +115,7 @@ void main(string[] args)
|
|||
---------
|
||||
|
||||
Invoking the program with "--timeout=5" or "--timeout 5" will set
|
||||
$(D_PARAM timeout) to 5.)
|
||||
$(D timeout) to 5.)
|
||||
|
||||
$(UL $(LI $(I Incremental options.) If an option name has a "+" suffix and
|
||||
is bound to a numeric type, then the option's value tracks the number
|
||||
|
@ -124,10 +127,10 @@ void main(string[] args)
|
|||
---------
|
||||
|
||||
Invoking the program with "--paranoid --paranoid --paranoid" will set
|
||||
$(D_PARAM paranoid) to 3. Note that an incremental option never
|
||||
$(D paranoid) to 3. Note that an incremental option never
|
||||
expects a parameter, e.g. in the command line "--paranoid 42
|
||||
--paranoid", the "42" does not set $(D_PARAM paranoid) to 42;
|
||||
instead, $(D_PARAM paranoid) is set to 2 and "42" is not considered
|
||||
--paranoid", the "42" does not set $(D paranoid) to 42;
|
||||
instead, $(D paranoid) is set to 2 and "42" is not considered
|
||||
as part of the program options.))
|
||||
|
||||
$(LI $(I String options.) If an option is bound to a string, a string
|
||||
|
@ -135,25 +138,25 @@ void main(string[] args)
|
|||
with an "=" sign:
|
||||
|
||||
---------
|
||||
string outputFile;
|
||||
getopt(args, "output", &outputFile);
|
||||
string outputFile;
|
||||
getopt(args, "output", &outputFile);
|
||||
---------
|
||||
|
||||
Invoking the program with "--output=myfile.txt" or "--output
|
||||
myfile.txt" will set $(D_PARAM outputFile) to "myfile.txt".) If you
|
||||
want to pass a string containing spaces, you need to use the quoting
|
||||
that is appropriate to your shell, e.g. --output='my file.txt'.
|
||||
myfile.txt" will set $(D outputFile) to "myfile.txt".) If you want to
|
||||
pass a string containing spaces, you need to use the quoting that is
|
||||
appropriate to your shell, e.g. --output='my file.txt'.
|
||||
|
||||
$(LI $(I Array options.) If an option is bound to an array, a new
|
||||
element is appended to the array each time the option occurs:
|
||||
|
||||
---------
|
||||
string[] outputFiles;
|
||||
getopt(args, "output", &outputFiles);
|
||||
string[] outputFiles;
|
||||
getopt(args, "output", &outputFiles);
|
||||
---------
|
||||
|
||||
Invoking the program with "--output=myfile.txt --output=yourfile.txt"
|
||||
or "--output myfile.txt --output yourfile.txt" will set $(D_PARAM
|
||||
or "--output myfile.txt --output yourfile.txt" will set $(D
|
||||
outputFiles) to [ "myfile.txt", "yourfile.txt" ] .)
|
||||
|
||||
$(LI $(I Hash options.) If an option is bound to an associative
|
||||
|
@ -161,22 +164,22 @@ void main(string[] args)
|
|||
option, or right within the option separated with an "=" sign:
|
||||
|
||||
---------
|
||||
double[string] tuningParms;
|
||||
getopt(args, "tune", &tuningParms);
|
||||
double[string] tuningParms;
|
||||
getopt(args, "tune", &tuningParms);
|
||||
---------
|
||||
|
||||
Invoking the program with e.g. "--tune=alpha=0.5 --tune beta=0.6"
|
||||
will set $(D_PARAM tuningParms) to [ "alpha" : 0.5, "beta" : 0.6 ].)
|
||||
In general, keys and values can be of any parsable types.
|
||||
Invoking the program with e.g. "--tune=alpha=0.5 --tune beta=0.6" will
|
||||
set $(D tuningParms) to [ "alpha" : 0.5, "beta" : 0.6 ].) In general,
|
||||
keys and values can be of any parsable types.
|
||||
|
||||
$(LI $(I Delegate options.) An option can be bound to a delegate with
|
||||
the signature $(D_PARAM void delegate(string option)) or $(D_PARAM
|
||||
void delegate(string option, string value)).
|
||||
$(LI $(I Delegate options.) An option can be bound to a delegate with
|
||||
the signature $(D void delegate(string option)) or $(D void
|
||||
delegate(string option, string value)).
|
||||
|
||||
$(UL $(LI In the $(D_PARAM void delegate(string option)) case, the
|
||||
option string (without the leading dash(es)) is passed to the
|
||||
delegate. After that, the option string is considered handled and
|
||||
removed from the options array.)
|
||||
$(UL $(LI In the $(D void delegate(string option)) case, the option
|
||||
string (without the leading dash(es)) is passed to the delegate. After
|
||||
that, the option string is considered handled and removed from the
|
||||
options array.)
|
||||
|
||||
---------
|
||||
void main(string[] args)
|
||||
|
@ -198,11 +201,11 @@ void main(string[] args)
|
|||
}
|
||||
---------
|
||||
|
||||
$(LI In the $(D_PARAM void delegate(string option, string value))
|
||||
case, the option string is handled as an option with one argument,
|
||||
and parsed accordingly. The option and its value are passed to the
|
||||
delegate. After that, whatever was passed to the delegate is
|
||||
considered handled and removed from the list.)
|
||||
$(LI In the $(D void delegate(string option, string value)) case, the
|
||||
option string is handled as an option with one argument, and parsed
|
||||
accordingly. The option and its value are passed to the
|
||||
delegate. After that, whatever was passed to the delegate is
|
||||
considered handled and removed from the list.)
|
||||
|
||||
---------
|
||||
void main(string[] args)
|
||||
|
@ -241,8 +244,7 @@ getopt(args, "verbose|loquacious|garrulous", &verbose);
|
|||
$(B Case)
|
||||
|
||||
By default options are case-insensitive. You can change that behavior
|
||||
by passing $(D_PARAM getopt) the $(D_PARAM caseSensitive) directive
|
||||
like this:
|
||||
by passing $(D getopt) the $(D caseSensitive) directive like this:
|
||||
|
||||
---------
|
||||
bool foo, bar;
|
||||
|
@ -252,7 +254,9 @@ getopt(args,
|
|||
"bar", &bar);
|
||||
---------
|
||||
|
||||
In the example above, "--foo", "--bar", "--FOo", "--bAr" etc. are recognized. The directive is active til the end of $(D_PARAM getopt), or until the converse directive $(D_PARAM caseInsensitive) is encountered:
|
||||
In the example above, "--foo", "--bar", "--FOo", "--bAr" etc. are recognized.
|
||||
The directive is active til the end of $(D getopt), or until the
|
||||
converse directive $(D caseInsensitive) is encountered:
|
||||
|
||||
---------
|
||||
bool foo, bar;
|
||||
|
@ -263,15 +267,15 @@ getopt(args,
|
|||
"bar", &bar);
|
||||
---------
|
||||
|
||||
The option "--Foo", is rejected due to $(D_PARAM
|
||||
The option "--Foo" is rejected due to $(D
|
||||
std.getopt.config.caseSensitive), but not "--Bar", "--bAr"
|
||||
etc. because the directive $(D_PARAM
|
||||
etc. because the directive $(D
|
||||
std.getopt.config.caseInsensitive) turned sensitivity off before
|
||||
option "bar" was parsed.
|
||||
|
||||
$(B Bundling)
|
||||
|
||||
Single-letter options can be bundled together, i.e. "-abc" is the same as "-a -b -c". By default, this confusing option is turned off. You can turn it on with the $(D_PARAM std.getopt.config.bundling) directive:
|
||||
Single-letter options can be bundled together, i.e. "-abc" is the same as "-a -b -c". By default, this confusing option is turned off. You can turn it on with the $(D std.getopt.config.bundling) directive:
|
||||
|
||||
---------
|
||||
bool foo, bar;
|
||||
|
@ -281,11 +285,11 @@ getopt(args,
|
|||
"bar|b", &bar);
|
||||
---------
|
||||
|
||||
In case you want to only enable bundling for some of the parameters, bundling can be turned off with $(D_PARAM std.getopt.config.noBundling).
|
||||
In case you want to only enable bundling for some of the parameters, bundling can be turned off with $(D std.getopt.config.noBundling).
|
||||
|
||||
$(B Passing unrecognized options through)
|
||||
|
||||
If an application needs to do its own processing of whichever arguments $(D_PARAM getopt) did not understand, it can pass the $(D_PARAM std.getopt.config.passThrough) directive to $(D_PARAM getopt):
|
||||
If an application needs to do its own processing of whichever arguments $(D getopt) did not understand, it can pass the $(D std.getopt.config.passThrough) directive to $(D getopt):
|
||||
|
||||
---------
|
||||
bool foo, bar;
|
||||
|
@ -295,22 +299,42 @@ getopt(args,
|
|||
"bar", &bar);
|
||||
---------
|
||||
|
||||
An unrecognized option such as "--baz" will be found untouched in $(D_PARAM args) after $(D_PARAM getopt) returns.
|
||||
An unrecognized option such as "--baz" will be found untouched in $(D args) after $(D getopt) returns.
|
||||
|
||||
$(B Options Terminator)
|
||||
|
||||
A lonesome double-dash terminates $(D_PARAM getopt) gathering. It is used to separate program options from other parameters (e.g. options to be passed to another program). Invoking the example above with "--foo -- --bar" parses foo but leaves "--bar" in $(D_PARAM args). The double-dash itself is removed from the argument array.
|
||||
A lonesome double-dash terminates $(D getopt) gathering. It is used to separate program options from other parameters (e.g. options to be passed to another program). Invoking the example above with "--foo -- --bar" parses foo but leaves "--bar" in $(D args). The double-dash itself is removed from the argument array.
|
||||
*/
|
||||
|
||||
void getopt(T...)(ref string[] args, T opts) {
|
||||
enforce(args.length,
|
||||
"Invalid arguments string passed: program name missing");
|
||||
|
||||
// break space-separated options
|
||||
for (size_t i; i < args.length; )
|
||||
{
|
||||
auto a = args[i];
|
||||
if (a.length && a[0] == optChar && std.algorithm.canFind!(isspace)(a))
|
||||
{
|
||||
// multiple options wrapped in one
|
||||
auto more = split(a);
|
||||
args = args[0 .. i] ~ more ~ args[i + 1 .. $];
|
||||
i += more.length;
|
||||
}
|
||||
else
|
||||
{
|
||||
++i;
|
||||
}
|
||||
}
|
||||
|
||||
configuration cfg;
|
||||
return getoptImpl(args, cfg, opts);
|
||||
}
|
||||
|
||||
/**
|
||||
* Configuration options for $(D_PARAM getopt). You can pass them to
|
||||
* $(D_PARAM getopt) in any position, except in between an option
|
||||
* string and its bound pointer.
|
||||
* Configuration options for $(D getopt). You can pass them to $(D
|
||||
* getopt) in any position, except in between an option string and its
|
||||
* bound pointer.
|
||||
*/
|
||||
|
||||
enum config {
|
||||
|
@ -326,6 +350,8 @@ enum config {
|
|||
passThrough,
|
||||
/// Signal unrecognized arguments as errors
|
||||
noPassThrough,
|
||||
/// Stop at first argument that does not look like an option
|
||||
stopOnFirstNonOption,
|
||||
};
|
||||
|
||||
private void getoptImpl(T...)(ref string[] args,
|
||||
|
@ -334,59 +360,88 @@ private void getoptImpl(T...)(ref string[] args,
|
|||
static if (opts.length) {
|
||||
static if (is(typeof(opts[0]) : config))
|
||||
{
|
||||
switch (opts[0])
|
||||
{
|
||||
case config.caseSensitive: cfg.caseSensitive = true; break;
|
||||
case config.caseInsensitive: cfg.caseSensitive = false; break;
|
||||
case config.bundling: cfg.bundling = true; break;
|
||||
case config.noBundling: cfg.bundling = false; break;
|
||||
case config.passThrough: cfg.passThrough = true; break;
|
||||
case config.noPassThrough: cfg.passThrough = false; break;
|
||||
default: assert(false); break;
|
||||
}
|
||||
// it's a configuration flag, act on it
|
||||
setConfig(cfg, opts[0]);
|
||||
return getoptImpl(args, cfg, opts[1 .. $]);
|
||||
}
|
||||
else
|
||||
{
|
||||
string option = to!(string)(opts[0]);
|
||||
auto option = to!(string)(opts[0]);
|
||||
auto receiver = opts[1];
|
||||
bool incremental;
|
||||
if (option.length && option[$ - 1] == '+')
|
||||
// Handle options of the form --blah+
|
||||
if (option.length && option[$ - 1] == autoIncrementChar)
|
||||
{
|
||||
option = option[0 .. $ - 1];
|
||||
incremental = true;
|
||||
}
|
||||
for (size_t i = 1; i != args.length; ) {
|
||||
auto a = args[i];
|
||||
handleOption(option, receiver, args, cfg, incremental);
|
||||
return getoptImpl(args, cfg, opts[2 .. $]);
|
||||
}
|
||||
} else {
|
||||
// no more options to look for, potentially some arguments left
|
||||
foreach (a ; args[1 .. $]) {
|
||||
if (!a.length || a[0] != '-')
|
||||
{
|
||||
// not an option
|
||||
if (cfg.stopOnFirstNonOption) break;
|
||||
continue;
|
||||
}
|
||||
if (a == endOfOptions) break; // end of options
|
||||
if (!cfg.passThrough)
|
||||
{
|
||||
throw new Exception("Unrecognized option "~a);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void handleOption(R)(string option, R receiver, ref string[] args,
|
||||
ref configuration cfg, bool incremental)
|
||||
{
|
||||
// Scan arguments looking for a match for this option
|
||||
for (size_t i = 1; i < args.length; ) {
|
||||
auto a = args[i];
|
||||
if (a == endOfOptions) break; // end of options, i.e. "--"
|
||||
if (cfg.stopOnFirstNonOption && (!a.length || a[0] != optChar))
|
||||
{
|
||||
// first non-option is end of options
|
||||
break;
|
||||
}
|
||||
string val;
|
||||
if (!optMatch(a, option, val, cfg))
|
||||
{
|
||||
++i;
|
||||
continue;
|
||||
}
|
||||
// found it
|
||||
|
||||
static if (is(typeof(receiver) : bool*)) {
|
||||
*receiver = true;
|
||||
// found it; from here on, commit to eat args[i]
|
||||
// (and potentially args[i + 1] too)
|
||||
args = args[0 .. i] ~ args[i + 1 .. $];
|
||||
|
||||
static if (is(typeof(*receiver) == bool)) {
|
||||
*receiver = true;
|
||||
break;
|
||||
} else {
|
||||
static const isDelegateWithOneParameter =
|
||||
is(typeof(receiver("")) : void);
|
||||
// non-boolean option, which might include an argument
|
||||
if (val || incremental || isDelegateWithOneParameter) {
|
||||
enum isDelegateWithOneParameter = is(typeof(receiver("")) : void);
|
||||
if (!val && !incremental && !isDelegateWithOneParameter) {
|
||||
// eat the next argument too
|
||||
val = args[i];
|
||||
args = args[0 .. i] ~ args[i + 1 .. $];
|
||||
} else {
|
||||
val = args[i + 1];
|
||||
args = args[0 .. i] ~ args[i + 2 .. $];
|
||||
}
|
||||
static if (is(typeof(*receiver) : real)) {
|
||||
static if (is(typeof(*receiver) : real))
|
||||
{
|
||||
// numeric receiver
|
||||
if (incremental) ++*receiver;
|
||||
else *receiver = to!(typeof(*receiver))(val);
|
||||
} else static if (is(typeof(receiver) : string*)) {
|
||||
*receiver = to!(string)(val);
|
||||
} else static if (is(typeof(receiver) == delegate)) {
|
||||
}
|
||||
else static if (is(typeof(*receiver) == string))
|
||||
{
|
||||
// string receiver
|
||||
*receiver = to!(typeof(*receiver))(val);
|
||||
}
|
||||
else static if (is(typeof(receiver) == delegate))
|
||||
{
|
||||
static if (is(typeof(receiver("", "")) : void))
|
||||
{
|
||||
// option with argument
|
||||
|
@ -398,44 +453,44 @@ private void getoptImpl(T...)(ref string[] args,
|
|||
// boolean-style receiver
|
||||
receiver(option);
|
||||
}
|
||||
} else static if (isArray!(typeof(*receiver))) {
|
||||
}
|
||||
else static if (isArray!(typeof(*receiver)))
|
||||
{
|
||||
// array receiver
|
||||
*receiver ~= [ to!(typeof(*receiver[0]))(val) ];
|
||||
} else static if (isAssociativeArray!(typeof(*receiver))) {
|
||||
}
|
||||
else static if (isAssociativeArray!(typeof(*receiver)))
|
||||
{
|
||||
// hash receiver
|
||||
alias typeof(receiver.keys[0]) K;
|
||||
alias typeof(receiver.values[0]) V;
|
||||
auto j = find(val, '=');
|
||||
auto j = std.string.find(val, '=');
|
||||
auto key = val[0 .. j], value = val[j + 1 .. $];
|
||||
(*receiver)[to!(K)(key)] = to!(V)(value);
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
static assert(false, "Dunno how to deal with type " ~
|
||||
typeof(receiver).stringof);
|
||||
}
|
||||
}
|
||||
}
|
||||
return getoptImpl(args, cfg, opts[2 .. $]);
|
||||
}
|
||||
} else {
|
||||
foreach (a ; args[1 .. $]) {
|
||||
if (!a.length || a[0] != '-') continue; // not an option
|
||||
if (a == "--") break; // end of options
|
||||
if (!cfg.passThrough)
|
||||
{
|
||||
throw new Exception("Unrecognized option "~a);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const
|
||||
enum
|
||||
optChar = '-',
|
||||
assignChar = '=',
|
||||
autoIncrementChar = '+',
|
||||
endOfOptions = "--";
|
||||
|
||||
private struct configuration
|
||||
{
|
||||
bool caseSensitive = false;
|
||||
bool bundling = false;
|
||||
bool passThrough = false;
|
||||
mixin(bitfields!(
|
||||
bool, "caseSensitive", 1,
|
||||
bool, "bundling", 1,
|
||||
bool, "passThrough", 1,
|
||||
bool, "stopOnFirstNonOption", 1,
|
||||
ubyte, "", 4));
|
||||
}
|
||||
|
||||
private bool optMatch(string arg, string optPattern, ref string value,
|
||||
|
@ -445,7 +500,7 @@ private bool optMatch(string arg, string optPattern, ref string value,
|
|||
arg = arg[1 .. $];
|
||||
const isLong = arg.length > 1 && arg[0] == optChar;
|
||||
if (isLong) arg = arg[1 .. $];
|
||||
const eqPos = find(arg, assignChar);
|
||||
const eqPos = std.string.find(arg, assignChar);
|
||||
if (eqPos >= 0) {
|
||||
value = arg[eqPos + 1 .. $];
|
||||
arg = arg[0 .. eqPos];
|
||||
|
@ -458,12 +513,29 @@ private bool optMatch(string arg, string optPattern, ref string value,
|
|||
foreach (v ; variants) {
|
||||
if (arg == v || !cfg.caseSensitive && toupper(arg) == toupper(v))
|
||||
return true;
|
||||
if (cfg.bundling && !isLong && v.length == 1 && find(arg, v) >= 0)
|
||||
if (cfg.bundling && !isLong && v.length == 1
|
||||
&& std.string.find(arg, v) >= 0)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private void setConfig(ref configuration cfg, config option)
|
||||
{
|
||||
switch (option)
|
||||
{
|
||||
case config.caseSensitive: cfg.caseSensitive = true; break;
|
||||
case config.caseInsensitive: cfg.caseSensitive = false; break;
|
||||
case config.bundling: cfg.bundling = true; break;
|
||||
case config.noBundling: cfg.bundling = false; break;
|
||||
case config.passThrough: cfg.passThrough = true; break;
|
||||
case config.noPassThrough: cfg.passThrough = false; break;
|
||||
case config.stopOnFirstNonOption:
|
||||
cfg.stopOnFirstNonOption = true; break;
|
||||
default: assert(false); break;
|
||||
}
|
||||
}
|
||||
|
||||
unittest
|
||||
{
|
||||
uint paranoid = 2;
|
||||
|
@ -542,4 +614,23 @@ unittest
|
|||
"foo", &foo,
|
||||
"bar", &bar);
|
||||
assert(args[1] == "--bAr");
|
||||
|
||||
// test stopOnFirstNonOption
|
||||
|
||||
args = (["program.name", "--foo", "nonoption", "--bar"]).dup;
|
||||
foo = bar = false;
|
||||
getopt(args,
|
||||
std.getopt.config.stopOnFirstNonOption,
|
||||
"foo", &foo,
|
||||
"bar", &bar);
|
||||
assert(foo && !bar && args[1] == "nonoption" && args[2] == "--bar");
|
||||
|
||||
args = (["program.name", "--foo", "nonoption", "--zab"]).dup;
|
||||
foo = bar = false;
|
||||
getopt(args,
|
||||
std.getopt.config.stopOnFirstNonOption,
|
||||
"foo", &foo,
|
||||
"bar", &bar);
|
||||
assert(foo && !bar && args[1] == "nonoption" && args[2] == "--zab");
|
||||
}
|
||||
|
||||
|
|
|
@ -61,7 +61,7 @@ int bsr(uint v);
|
|||
/**
|
||||
* Tests the bit.
|
||||
*/
|
||||
int bt(const uint *p, uint bitnum);
|
||||
int bt(in uint *p, uint bitnum);
|
||||
|
||||
/**
|
||||
* Tests and complements the bit.
|
||||
|
|
90
std/math.d
90
std/math.d
|
@ -361,7 +361,8 @@ real cos(ireal y)
|
|||
unittest{
|
||||
assert(cos(0.0+0.0i)==1.0);
|
||||
assert(cos(1.3L+0.0i)==cos(1.3L));
|
||||
assert(cos(5.2Li)== cosh(5.2L));
|
||||
// @@@FAILS
|
||||
//assert(cos(5.2Li)== cosh(5.2L));
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
|
@ -1742,7 +1743,7 @@ unittest
|
|||
*
|
||||
* BUGS: DMD always returns real.nan, ignoring the payload.
|
||||
*/
|
||||
real nan(const char[] tagp) { return std.c.math.nanl(toStringz(tagp)); }
|
||||
real nan(in char[] tagp) { return std.c.math.nanl(toStringz(tagp)); }
|
||||
|
||||
/**
|
||||
* Calculate the next largest floating point value after x.
|
||||
|
@ -2019,46 +2020,64 @@ real fma(real x, real y, real z) { return (x * y) + z; }
|
|||
|
||||
real pow(real x, uint n)
|
||||
{
|
||||
real p;
|
||||
|
||||
switch (n)
|
||||
if (n > int.max)
|
||||
{
|
||||
case 0:
|
||||
p = 1.0;
|
||||
break;
|
||||
|
||||
case 1:
|
||||
p = x;
|
||||
break;
|
||||
|
||||
case 2:
|
||||
p = x * x;
|
||||
break;
|
||||
|
||||
default:
|
||||
p = 1.0;
|
||||
while (1)
|
||||
{
|
||||
if (n & 1)
|
||||
p *= x;
|
||||
n >>= 1;
|
||||
if (!n)
|
||||
break;
|
||||
x *= x;
|
||||
assert(n >> 1 <= int.max);
|
||||
// must reduce n so we can call the pow(real, int) overload
|
||||
invariant result = pow(x, cast(int) (n >> 1));
|
||||
return (n & 1)
|
||||
? result * x // odd power
|
||||
: result;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return p;
|
||||
return pow(x, cast(int) n);
|
||||
}
|
||||
|
||||
/// ditto
|
||||
/// Ditto
|
||||
|
||||
real pow(real x, int n)
|
||||
{
|
||||
real p = 1.0, v = void;
|
||||
|
||||
if (n < 0)
|
||||
return pow(x, cast(real)n);
|
||||
{
|
||||
switch (n)
|
||||
{
|
||||
case -1:
|
||||
return 1 / x;
|
||||
case -2:
|
||||
return 1 / (x * x);
|
||||
default:
|
||||
}
|
||||
|
||||
n = -n;
|
||||
v = p / x;
|
||||
}
|
||||
else
|
||||
return pow(x, cast(uint)n);
|
||||
{
|
||||
switch (n)
|
||||
{
|
||||
case 0:
|
||||
return 1.0;
|
||||
case 1:
|
||||
return x;
|
||||
case 2:
|
||||
return x * x;
|
||||
default:
|
||||
}
|
||||
|
||||
v = x;
|
||||
}
|
||||
|
||||
while (1)
|
||||
{
|
||||
if (n & 1)
|
||||
p *= v;
|
||||
n >>= 1;
|
||||
if (!n)
|
||||
break;
|
||||
v *= v;
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
/*********************************************
|
||||
|
@ -2208,6 +2227,11 @@ unittest
|
|||
assert(pow(x,2) == x * x);
|
||||
assert(pow(x,3) == x * x * x);
|
||||
assert(pow(x,8) == (x * x) * (x * x) * (x * x) * (x * x));
|
||||
|
||||
assert(pow(x, -1) == 1 / x);
|
||||
assert(pow(x, -2) == 1 / (x * x));
|
||||
assert(pow(x, -3) == 1 / (x * x * x));
|
||||
assert(pow(x, -8) == 1 / ((x * x) * (x * x) * (x * x) * (x * x)));
|
||||
}
|
||||
|
||||
/****************************************
|
||||
|
|
65
std/md5.d
65
std/md5.d
|
@ -38,34 +38,25 @@ private import std.string;
|
|||
private import std.c.stdio;
|
||||
private import std.c.string;
|
||||
|
||||
int main(char[][] args)
|
||||
void main(string[] args)
|
||||
{
|
||||
foreach (char[] arg; args)
|
||||
MDFile(arg);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Digests a file and prints the result. */
|
||||
void MDFile(const char[] filename)
|
||||
void MDFile(string filename)
|
||||
{
|
||||
FILE* file;
|
||||
MD5_CTX context;
|
||||
int len;
|
||||
ubyte[4 * 1024] buffer;
|
||||
FILE* file = enforce(fopen(filename), "Could not open file `"~filename~"'");
|
||||
scope(exit) fclose(file);
|
||||
ubyte digest[16];
|
||||
|
||||
if ((file = fopen(std.string.toStringz(filename), "rb")) == null)
|
||||
writefln("%s can't be opened", filename);
|
||||
else
|
||||
{
|
||||
MD5_CTX context;
|
||||
context.start();
|
||||
while ((len = fread(buffer, 1, buffer.sizeof, file)) != 0)
|
||||
context.update(buffer[0 .. len]);
|
||||
foreach (ubyte buffer; chunks(file, 4096 * 1024))
|
||||
context.update(buffer);
|
||||
context.finish(digest);
|
||||
fclose(file);
|
||||
|
||||
writefln("MD5 (%s) = %s", filename, digestToString(digest));
|
||||
}
|
||||
}
|
||||
--------------------
|
||||
+/
|
||||
|
@ -99,15 +90,17 @@ import std.string;
|
|||
import std.contracts;
|
||||
|
||||
/***************************************
|
||||
* Computes MD5 digest of array of data.
|
||||
* Computes MD5 digest of several arrays of data.
|
||||
*/
|
||||
|
||||
void sum(ubyte[16] digest, const void[] data)
|
||||
void sum(ubyte[16] digest, in void[][] data...)
|
||||
{
|
||||
MD5_CTX context;
|
||||
|
||||
context.start();
|
||||
context.update(data);
|
||||
foreach (datum; data)
|
||||
{
|
||||
context.update(datum);
|
||||
}
|
||||
context.finish(digest);
|
||||
}
|
||||
|
||||
|
@ -138,6 +131,38 @@ string digestToString(const ubyte[16] digest)
|
|||
return assumeUnique(result);
|
||||
}
|
||||
|
||||
/**
|
||||
Gets the digest of all $(D data) items passed in.
|
||||
|
||||
Example:
|
||||
|
||||
----
|
||||
string a = "Mary has ", b = "a little lamb";
|
||||
int[] c = [ 1, 2, 3, 4, 5 ];
|
||||
string d = getDigestString(a, b, c);
|
||||
----
|
||||
*/
|
||||
string getDigestString(in void[][] data...)
|
||||
{
|
||||
MD5_CTX ctx;
|
||||
ctx.start;
|
||||
foreach (datum; data) {
|
||||
ctx.update(datum);
|
||||
}
|
||||
ubyte[16] digest;
|
||||
ctx.finish(digest);
|
||||
return digestToString(digest);
|
||||
}
|
||||
|
||||
version(unittest) import std.stdio;
|
||||
unittest
|
||||
{
|
||||
string a = "Mary has ", b = "a little lamb";
|
||||
int[] c = [ 1, 2, 3, 4, 5 ];
|
||||
string d = getDigestString(a, b, c);
|
||||
assert(d == "F36625A66B2A8D9F47270C00C8BEFD2F", d);
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds context of MD5 computation.
|
||||
*
|
||||
|
|
|
@ -234,7 +234,7 @@ class MmFile
|
|||
}
|
||||
else version (linux)
|
||||
{
|
||||
char* namez = toStringz(filename);
|
||||
auto namez = toStringz(filename);
|
||||
void* p;
|
||||
int oflag;
|
||||
int fmode;
|
||||
|
|
|
@ -242,11 +242,10 @@ class OutBuffer
|
|||
{
|
||||
char[128] buffer;
|
||||
char* p;
|
||||
const(char)* f;
|
||||
uint psize;
|
||||
int count;
|
||||
|
||||
f = toStringz(format);
|
||||
auto f = toStringz(format);
|
||||
p = buffer.ptr;
|
||||
psize = buffer.length;
|
||||
for (;;)
|
||||
|
|
284
std/path.d
284
std/path.d
|
@ -28,6 +28,7 @@ module std.path;
|
|||
|
||||
private import std.string;
|
||||
private import std.file;
|
||||
private import std.contracts;
|
||||
|
||||
version(linux)
|
||||
{
|
||||
|
@ -118,9 +119,7 @@ version (linux) alias std.string.cmp fcmp;
|
|||
|
||||
string getExt(string fullname)
|
||||
{
|
||||
uint i;
|
||||
|
||||
i = fullname.length;
|
||||
auto i = fullname.length;
|
||||
while (i > 0)
|
||||
{
|
||||
if (fullname[i - 1] == '.')
|
||||
|
@ -143,14 +142,13 @@ string getExt(string fullname)
|
|||
unittest
|
||||
{
|
||||
debug(path) printf("path.getExt.unittest\n");
|
||||
int i;
|
||||
string result;
|
||||
|
||||
version (Win32)
|
||||
result = getExt("d:\\path\\foo.bat");
|
||||
version (linux)
|
||||
result = getExt("/path/foo.bat");
|
||||
i = cmp(result, "bat");
|
||||
auto i = cmp(result, "bat");
|
||||
assert(i == 0);
|
||||
|
||||
version (Win32)
|
||||
|
@ -212,9 +210,7 @@ unittest
|
|||
|
||||
string getName(string fullname)
|
||||
{
|
||||
uint i;
|
||||
|
||||
i = fullname.length;
|
||||
auto i = fullname.length;
|
||||
while (i > 0)
|
||||
{
|
||||
if (fullname[i - 1] == '.')
|
||||
|
@ -237,11 +233,10 @@ string getName(string fullname)
|
|||
unittest
|
||||
{
|
||||
debug(path) printf("path.getName.unittest\n");
|
||||
int i;
|
||||
string result;
|
||||
|
||||
result = getName("foo.bar");
|
||||
i = cmp(result, "foo");
|
||||
auto i = cmp(result, "foo");
|
||||
assert(i == 0);
|
||||
|
||||
result = getName("d:\\path.two\\bar");
|
||||
|
@ -291,8 +286,8 @@ string basename(string fullname, string extension = null)
|
|||
}
|
||||
body
|
||||
{
|
||||
uint i = void;
|
||||
for (i = fullname.length; i > 0; i--)
|
||||
auto i = fullname.length;
|
||||
for (; i > 0; i--)
|
||||
{
|
||||
version(Win32)
|
||||
{
|
||||
|
@ -316,7 +311,6 @@ alias basename getBaseName;
|
|||
unittest
|
||||
{
|
||||
debug(path) printf("path.basename.unittest\n");
|
||||
int i;
|
||||
string result;
|
||||
|
||||
version (Windows)
|
||||
|
@ -343,13 +337,13 @@ unittest
|
|||
/**************************
|
||||
* Extracts the directory part of a path.
|
||||
*
|
||||
* This function will search fullname from the end until the
|
||||
* first path separator or first character of fullname is
|
||||
* reached. Under Windows, the drive letter separator (<i>colon</i>)
|
||||
* This function will search $(D fullname) from the end until the
|
||||
* first path separator or first character of $(D fullname) is
|
||||
* reached. Under Windows, the drive letter separator ($(I colon))
|
||||
* also terminates the search.
|
||||
*
|
||||
* Returns: If a path separator was found, all the characters to its
|
||||
* left are returned. Otherwise, fullname is returned.
|
||||
* left are returned. Otherwise, $(D ".") is returned.
|
||||
*
|
||||
* Under Windows, the found path separator will be included in the
|
||||
* returned string if it is preceeded by a colon.
|
||||
|
@ -372,35 +366,47 @@ unittest
|
|||
*/
|
||||
|
||||
string dirname(string fullname)
|
||||
out (result)
|
||||
{
|
||||
assert(result.length <= fullname.length);
|
||||
}
|
||||
body
|
||||
{
|
||||
uint i;
|
||||
|
||||
for (i = fullname.length; i > 0; i--)
|
||||
{
|
||||
auto i = fullname.length;
|
||||
for (; i > 0; i--)
|
||||
{
|
||||
version(Win32)
|
||||
{
|
||||
if (fullname[i - 1] == ':')
|
||||
break;
|
||||
if (fullname[i - 1] == '\\' || fullname[i - 1] == '/')
|
||||
{ i--;
|
||||
if (fullname[i - 1] == sep[0])
|
||||
{
|
||||
i--;
|
||||
break;
|
||||
}
|
||||
}
|
||||
version(linux)
|
||||
{
|
||||
if (fullname[i - 1] == '/')
|
||||
if (fullname[i - 1] == sep[0])
|
||||
{ i--;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return fullname[0 .. i];
|
||||
return i == 0 ? "." : fullname[0 .. i];
|
||||
}
|
||||
|
||||
unittest
|
||||
{
|
||||
assert(dirname("") == ".");
|
||||
assert(dirname("fileonly") == ".");
|
||||
version (linux)
|
||||
{
|
||||
assert(dirname("/path/to/file") == "/path/to");
|
||||
}
|
||||
else
|
||||
{
|
||||
version (Win32)
|
||||
{
|
||||
assert(dirname(r"\path\to\file") == r"\path\to");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Alias for $(D_PARAM dirname), kept for backward
|
||||
* compatibility. New code should use $(D_PARAM dirname). */
|
||||
|
@ -440,9 +446,7 @@ string getDrive(string fullname)
|
|||
{
|
||||
version(Win32)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < fullname.length; i++)
|
||||
for (uint i = 0; i < fullname.length; i++)
|
||||
{
|
||||
if (fullname[i] == ':')
|
||||
return fullname[0 .. i + 1];
|
||||
|
@ -562,10 +566,9 @@ string addExt(string filename, string ext)
|
|||
* -----
|
||||
*/
|
||||
|
||||
int isabs(string path)
|
||||
bool isabs(string path)
|
||||
{
|
||||
string d = getDrive(path);
|
||||
|
||||
auto d = getDrive(path);
|
||||
version (Windows)
|
||||
{
|
||||
return d.length && d.length < path.length && path[d.length] == sep[0];
|
||||
|
@ -580,33 +583,27 @@ unittest
|
|||
|
||||
version (Windows)
|
||||
{
|
||||
assert(isabs(r"relative\path") == 0);
|
||||
assert(isabs(r"\relative\path") == 0);
|
||||
assert(isabs(r"d:\absolute") == 1);
|
||||
assert(!isabs(r"relative\path"));
|
||||
assert(!isabs(r"\relative\path"));
|
||||
assert(isabs(r"d:\absolute"));
|
||||
}
|
||||
version (linux)
|
||||
{
|
||||
assert(isabs("/home/user") == 1);
|
||||
assert(isabs("foo") == 0);
|
||||
assert(isabs("/home/user"));
|
||||
assert(!isabs("foo"));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a relative path into an absolute path. Currently only
|
||||
* implemented on Linux.
|
||||
* Converts a relative path into an absolute path.
|
||||
*/
|
||||
string rel2abs(string path)
|
||||
{
|
||||
version(windows)
|
||||
{
|
||||
static assert(false, "rel2abs not yet implemented on Windows");
|
||||
}
|
||||
if (!path.length) return null;
|
||||
if (startsWith(path, sep) || altsep.length && startsWith(path, altsep))
|
||||
if (!path.length || isabs(path))
|
||||
{
|
||||
return path;
|
||||
}
|
||||
auto myDir = getcwd();
|
||||
auto myDir = getcwd;
|
||||
if (path.startsWith(curdir))
|
||||
{
|
||||
auto p = path[curdir.length .. $];
|
||||
|
@ -617,9 +614,9 @@ string rel2abs(string path)
|
|||
else if (!p.length)
|
||||
path = null;
|
||||
}
|
||||
return myDir.endsWith(sep)
|
||||
? myDir ~ path
|
||||
: path.length ? myDir ~ sep ~ path : myDir;
|
||||
return myDir.endsWith(sep) || path.length
|
||||
? join(myDir, path)
|
||||
: myDir;
|
||||
}
|
||||
|
||||
unittest
|
||||
|
@ -638,10 +635,10 @@ unittest
|
|||
}
|
||||
|
||||
/*************************************
|
||||
* Joins two path components.
|
||||
* Joins two or more path components.
|
||||
*
|
||||
* If p1 doesn't have a trailing path separator, one will be appended
|
||||
* to it before concatting p2.
|
||||
* to it before concatenating p2.
|
||||
*
|
||||
* Returns: p1 ~ p2. However, if p2 is an absolute path, only p2
|
||||
* will be returned.
|
||||
|
@ -652,8 +649,8 @@ unittest
|
|||
* -----
|
||||
* version(Win32)
|
||||
* {
|
||||
* join(r"c:\foo", "bar") => "c:\foo\bar"
|
||||
* join("foo", r"d:\bar") => "d:\bar"
|
||||
* join(r"c:\foo", "bar") => r"c:\foo\bar"
|
||||
* join("foo", r"d:\bar") => r"d:\bar"
|
||||
* }
|
||||
* version(linux)
|
||||
* {
|
||||
|
@ -663,64 +660,76 @@ unittest
|
|||
* -----
|
||||
*/
|
||||
|
||||
string join(string p1, string p2)
|
||||
string join(string p1, string p2, string[] more...)
|
||||
{
|
||||
if (!p2.length)
|
||||
return p1;
|
||||
if (!p1.length)
|
||||
return p2;
|
||||
if (!more.length)
|
||||
{
|
||||
if (isabs(p2)) return p2;
|
||||
if (p1.endsWith(sep) || altsep.length && p1.endsWith(altsep))
|
||||
{
|
||||
return p1 ~ p2;
|
||||
}
|
||||
return p1 ~ sep ~ p2;
|
||||
}
|
||||
// more components present
|
||||
return join(join(p1, p2), more[0], more[1 .. $]);
|
||||
|
||||
string p;
|
||||
string d1;
|
||||
// if (!p2.length)
|
||||
// return p1;
|
||||
// if (!p1.length)
|
||||
// return p2;
|
||||
|
||||
version(Win32)
|
||||
{
|
||||
if (getDrive(p2))
|
||||
{
|
||||
p = p2;
|
||||
}
|
||||
else
|
||||
{
|
||||
d1 = getDrive(p1);
|
||||
if (p1.length == d1.length)
|
||||
{
|
||||
p = p1 ~ p2;
|
||||
}
|
||||
else if (p2[0] == '\\')
|
||||
{
|
||||
if (d1.length == 0)
|
||||
p = p2;
|
||||
else if (p1[p1.length - 1] == '\\')
|
||||
p = p1 ~ p2[1 .. p2.length];
|
||||
else
|
||||
p = p1 ~ p2;
|
||||
}
|
||||
else if (p1[p1.length - 1] == '\\')
|
||||
{
|
||||
p = p1 ~ p2;
|
||||
}
|
||||
else
|
||||
{
|
||||
p = cast(string)(p1 ~ sep ~ p2);
|
||||
}
|
||||
}
|
||||
}
|
||||
version(linux)
|
||||
{
|
||||
if (p2[0] == sep[0])
|
||||
{
|
||||
p = p2;
|
||||
}
|
||||
else if (p1[p1.length - 1] == sep[0])
|
||||
{
|
||||
p = p1 ~ p2;
|
||||
}
|
||||
else
|
||||
{
|
||||
p = cast(string) (p1 ~ sep ~ p2);
|
||||
}
|
||||
}
|
||||
return p;
|
||||
// string p;
|
||||
// string d1;
|
||||
|
||||
// version(Win32)
|
||||
// {
|
||||
// if (getDrive(p2))
|
||||
// {
|
||||
// p = p2;
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// d1 = getDrive(p1);
|
||||
// if (p1.length == d1.length)
|
||||
// {
|
||||
// p = p1 ~ p2;
|
||||
// }
|
||||
// else if (p2[0] == '\\')
|
||||
// {
|
||||
// if (d1.length == 0)
|
||||
// p = p2;
|
||||
// else if (p1[p1.length - 1] == '\\')
|
||||
// p = p1 ~ p2[1 .. p2.length];
|
||||
// else
|
||||
// p = p1 ~ p2;
|
||||
// }
|
||||
// else if (p1[p1.length - 1] == '\\')
|
||||
// {
|
||||
// p = p1 ~ p2;
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// p = cast(string)(p1 ~ sep ~ p2);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// version(linux)
|
||||
// {
|
||||
// if (p2[0] == sep[0])
|
||||
// {
|
||||
// p = p2;
|
||||
// }
|
||||
// else if (p1[p1.length - 1] == sep[0])
|
||||
// {
|
||||
// p = p1 ~ p2;
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// p = cast(string) (p1 ~ sep ~ p2);
|
||||
// }
|
||||
// }
|
||||
// return p;
|
||||
}
|
||||
|
||||
unittest
|
||||
|
@ -829,7 +838,7 @@ unittest
|
|||
* -----
|
||||
*/
|
||||
|
||||
int fncharmatch(dchar c1, dchar c2)
|
||||
bool fncharmatch(dchar c1, dchar c2)
|
||||
{
|
||||
version (Win32)
|
||||
{
|
||||
|
@ -896,14 +905,12 @@ int fncharmatch(dchar c1, dchar c2)
|
|||
* -----
|
||||
*/
|
||||
|
||||
int fnmatch(string filename, string pattern)
|
||||
bool fnmatch(string filename, string pattern)
|
||||
in
|
||||
{
|
||||
// Verify that pattern[] is valid
|
||||
int i;
|
||||
int inbracket = false;
|
||||
|
||||
for (i = 0; i < pattern.length; i++)
|
||||
bool inbracket = false;
|
||||
foreach (i; 0 .. pattern.length)
|
||||
{
|
||||
switch (pattern[i])
|
||||
{
|
||||
|
@ -924,39 +931,35 @@ int fnmatch(string filename, string pattern)
|
|||
}
|
||||
body
|
||||
{
|
||||
int pi;
|
||||
int ni;
|
||||
char pc;
|
||||
char nc;
|
||||
int j;
|
||||
int not;
|
||||
int anymatch;
|
||||
|
||||
ni = 0;
|
||||
for (pi = 0; pi < pattern.length; pi++)
|
||||
int ni; // ni == name index
|
||||
foreach (pi; 0 .. pattern.length) // pi == pattern index
|
||||
{
|
||||
pc = pattern[pi];
|
||||
char pc = pattern[pi]; // pc == pattern character
|
||||
switch (pc)
|
||||
{
|
||||
case '*':
|
||||
if (pi + 1 == pattern.length)
|
||||
goto match;
|
||||
for (j = ni; j < filename.length; j++)
|
||||
return true;
|
||||
foreach (j; ni .. filename.length)
|
||||
{
|
||||
if (fnmatch(filename[j .. filename.length], pattern[pi + 1 .. pattern.length]))
|
||||
goto match;
|
||||
if (fnmatch(filename[j .. filename.length],
|
||||
pattern[pi + 1 .. pattern.length]))
|
||||
return true;
|
||||
}
|
||||
goto nomatch;
|
||||
return false;
|
||||
|
||||
case '?':
|
||||
if (ni == filename.length)
|
||||
goto nomatch;
|
||||
return false;
|
||||
ni++;
|
||||
break;
|
||||
|
||||
case '[':
|
||||
if (ni == filename.length)
|
||||
goto nomatch;
|
||||
return false;
|
||||
nc = filename[ni];
|
||||
ni++;
|
||||
not = 0;
|
||||
|
@ -976,27 +979,20 @@ int fnmatch(string filename, string pattern)
|
|||
pi++;
|
||||
}
|
||||
if (!(anymatch ^ not))
|
||||
goto nomatch;
|
||||
return false;
|
||||
break;
|
||||
|
||||
default:
|
||||
if (ni == filename.length)
|
||||
goto nomatch;
|
||||
return false;
|
||||
nc = filename[ni];
|
||||
if (!fncharmatch(pc, nc))
|
||||
goto nomatch;
|
||||
return false;
|
||||
ni++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (ni < filename.length)
|
||||
goto nomatch;
|
||||
|
||||
match:
|
||||
return true;
|
||||
|
||||
nomatch:
|
||||
return false;
|
||||
return ni >= filename.length;
|
||||
}
|
||||
|
||||
unittest
|
||||
|
|
|
@ -55,17 +55,36 @@ version (linux)
|
|||
}
|
||||
|
||||
/**
|
||||
* Execute $(D command) in a _command shell.
|
||||
*
|
||||
* Returns: exit status of command
|
||||
*/
|
||||
Execute $(D command) in a _command shell.
|
||||
|
||||
Returns: If $(D command) is null, returns nonzero if the _command
|
||||
interpreter is found, and zero otherwise. If $(D command) is not
|
||||
null, returns -1 on error, or the exit status of command (which may
|
||||
in turn signal an error in command's execution).
|
||||
|
||||
Note: On Unix systems, the homonym C function (which is accessible
|
||||
to D programs as $(LINK2 std_c_process.html, std.c._system))
|
||||
returns a code in the same format as
|
||||
$(WEB www.scit.wlv.ac.uk/cgi-bin/mansec?2+waitpid, waitpid),
|
||||
meaning that C programs must use the $(D WEXITSTATUS) macro to
|
||||
extract the actual exit code from the $(D system) call. D's $(D
|
||||
system) automatically extracts the exit status.
|
||||
|
||||
*/
|
||||
|
||||
int system(string command)
|
||||
{
|
||||
return std.c.process.system(toStringz(command));
|
||||
if (!command) return std.c.process.system(null);
|
||||
const commandz = toStringz(command);
|
||||
invariant status = std.c.process.system(commandz);
|
||||
if (status == -1) return status;
|
||||
version (linux)
|
||||
return (status & 0x0000ff00) >>> 8;
|
||||
else
|
||||
return status;
|
||||
}
|
||||
|
||||
private void toAStringz(string[] a, char**az)
|
||||
private void toAStringz(in string[] a, const(char)**az)
|
||||
{
|
||||
foreach(string s; a)
|
||||
{
|
||||
|
@ -96,7 +115,7 @@ alias std.c.process._P_NOWAIT P_NOWAIT;
|
|||
|
||||
int spawnvp(int mode, string pathname, string[] argv)
|
||||
{
|
||||
char** argv_ = cast(char**)alloca((char*).sizeof * (1 + argv.length));
|
||||
auto argv_ = cast(const(char)**)alloca((char*).sizeof * (1 + argv.length));
|
||||
|
||||
toAStringz(argv, argv_);
|
||||
|
||||
|
@ -113,7 +132,7 @@ int spawnvp(int mode, string pathname, string[] argv)
|
|||
version(linux)
|
||||
{
|
||||
private import std.c.linux.linux;
|
||||
int _spawnvp(int mode, char *pathname, char **argv)
|
||||
int _spawnvp(int mode, in char *pathname, in char **argv)
|
||||
{
|
||||
int retval = 0;
|
||||
pid_t pid = fork();
|
||||
|
@ -182,9 +201,9 @@ int exitstatus(int status) { return (status & 0xff00) >> 8; }
|
|||
* setting for the program.
|
||||
*/
|
||||
|
||||
int execv(string pathname, string[] argv)
|
||||
int execv(in string pathname, in string[] argv)
|
||||
{
|
||||
char** argv_ = cast(char**)alloca((char*).sizeof * (1 + argv.length));
|
||||
auto argv_ = cast(const(char)**)alloca((char*).sizeof * (1 + argv.length));
|
||||
|
||||
toAStringz(argv, argv_);
|
||||
|
||||
|
@ -192,10 +211,10 @@ int execv(string pathname, string[] argv)
|
|||
}
|
||||
|
||||
/** ditto */
|
||||
int execve(string pathname, string[] argv, string[] envp)
|
||||
int execve(in string pathname, in string[] argv, in string[] envp)
|
||||
{
|
||||
char** argv_ = cast(char**)alloca((char*).sizeof * (1 + argv.length));
|
||||
char** envp_ = cast(char**)alloca((char*).sizeof * (1 + envp.length));
|
||||
auto argv_ = cast(const(char)**)alloca((char*).sizeof * (1 + argv.length));
|
||||
auto envp_ = cast(const(char)**)alloca((char*).sizeof * (1 + envp.length));
|
||||
|
||||
toAStringz(argv, argv_);
|
||||
toAStringz(envp, envp_);
|
||||
|
@ -204,9 +223,9 @@ int execve(string pathname, string[] argv, string[] envp)
|
|||
}
|
||||
|
||||
/** ditto */
|
||||
int execvp(string pathname, string[] argv)
|
||||
int execvp(in string pathname, in string[] argv)
|
||||
{
|
||||
char** argv_ = cast(char**)alloca((char*).sizeof * (1 + argv.length));
|
||||
auto argv_ = cast(const(char)**)alloca((char*).sizeof * (1 + argv.length));
|
||||
|
||||
toAStringz(argv, argv_);
|
||||
|
||||
|
@ -214,7 +233,7 @@ int execvp(string pathname, string[] argv)
|
|||
}
|
||||
|
||||
/** ditto */
|
||||
int execvpe(string pathname, string[] argv, string[] envp)
|
||||
int execvpe(in string pathname, in string[] argv, in string[] envp)
|
||||
{
|
||||
version(linux)
|
||||
{
|
||||
|
@ -321,6 +340,48 @@ unittest
|
|||
assert(x == "wyda\n");
|
||||
}
|
||||
|
||||
/**
|
||||
Gets the value of environment variable $(D name) as a string. Calls
|
||||
$(LINK2 std_c_stdlib.html#_getenv, std.c.stdlib._getenv)
|
||||
internally. */
|
||||
|
||||
string getenv(in char[] name)
|
||||
{
|
||||
auto p = std.c.stdlib.getenv(toStringz(name));
|
||||
if (!p) return null;
|
||||
return p[0 .. strlen(p)].idup;
|
||||
}
|
||||
|
||||
/**
|
||||
Sets the value of environment variable $(D name) to $(D value). If the
|
||||
value was written, or the variable was already present and $(D
|
||||
overwrite) is false, returns normally. Otherwise, it throws an
|
||||
exception. Calls $(LINK2 std_c_stdlib.html#_setenv,
|
||||
std.c.stdlib._setenv) internally. */
|
||||
|
||||
void setenv(in char[] name, in char[] value, bool overwrite)
|
||||
{
|
||||
errnoEnforce(
|
||||
std.c.stdlib.setenv(toStringz(name), toStringz(value), overwrite) == 0);
|
||||
}
|
||||
|
||||
/**
|
||||
Removes variable $(D name) from the environment. Calls $(LINK2
|
||||
std_c_stdlib.html#_unsetenv, std.c.stdlib._unsetenv) internally. */
|
||||
|
||||
void unsetenv(in char[] name)
|
||||
{
|
||||
errnoEnforce(std.c.stdlib.unsetenv(toStringz(name)) == 0);
|
||||
}
|
||||
|
||||
unittest
|
||||
{
|
||||
setenv("wyda", "geeba", true);
|
||||
assert(getenv("wyda") == "geeba");
|
||||
unsetenv("wyda");
|
||||
assert(getenv("wyda") is null);
|
||||
}
|
||||
|
||||
/* ////////////////////////////////////////////////////////////////////////// */
|
||||
|
||||
version(MainTest)
|
||||
|
|
199
std/random.d
199
std/random.d
|
@ -1,26 +1,26 @@
|
|||
// Written in the D programming language
|
||||
|
||||
/**
|
||||
Facilities for random number generation. The old-style functions
|
||||
$(D_PARAM rand_seed) and $(D_PARAM rand) will soon be deprecated as
|
||||
they rely on global state and as such are subjected to various
|
||||
thread-related issues.
|
||||
Facilities for random number generation. The old-style functions
|
||||
$(D_PARAM rand_seed) and $(D_PARAM rand) will soon be deprecated as
|
||||
they rely on global state and as such are subjected to various
|
||||
thread-related issues.
|
||||
|
||||
The new-style generator objects hold their own state so they are
|
||||
immune of threading issues. The generators feature a number of
|
||||
well-known and well-documented methods of generating random
|
||||
numbers. An overall fast and reliable means to generate random
|
||||
numbers is the $(D_PARAM Mt19937) generator, which derives its name
|
||||
from "$(LINK2 http://math.sci.hiroshima-u.ac.jp/~m-mat/MT/emt.html,
|
||||
Mersenne Twister) with a period of 2 to the power of 19937". In
|
||||
memory-constrained situations,
|
||||
$(LINK2 http://en.wikipedia.org/wiki/Linear_congruential_generator,
|
||||
linear congruential) generators such as MinstdRand0 and MinstdRand
|
||||
might be useful. The standard library provides an alias $(D_PARAM
|
||||
Random) for whichever generator it finds the most fit for the
|
||||
target environment.
|
||||
The new-style generator objects hold their own state so they are
|
||||
immune of threading issues. The generators feature a number of
|
||||
well-known and well-documented methods of generating random
|
||||
numbers. An overall fast and reliable means to generate random numbers
|
||||
is the $(D_PARAM Mt19937) generator, which derives its name from
|
||||
"$(WEB math.sci.hiroshima-u.ac.jp/~m-mat/MT/emt.html, Mersenne
|
||||
Twister) with a period of 2 to the power of 19937". In
|
||||
memory-constrained situations, $(WEB
|
||||
en.wikipedia.org/wiki/Linear_congruential_generator, linear
|
||||
congruential) generators such as $(D MinstdRand0) and $(D MinstdRand)
|
||||
might be useful. The standard library provides an alias $(D_PARAM
|
||||
Random) for whichever generator it finds the most fit for the target
|
||||
environment.
|
||||
|
||||
Example:
|
||||
Example:
|
||||
|
||||
----
|
||||
Random gen;
|
||||
|
@ -42,10 +42,10 @@ $(WEB erdani.org, Andrei Alexandrescu)
|
|||
Credits:
|
||||
|
||||
The entire random number library architecture is derived from the
|
||||
excellent
|
||||
$(LINK2 http://open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2461.pdf,
|
||||
C++0X) random number facility proposed by Jens Maurer and contrinuted
|
||||
to by researchers at the Fermi laboratory.
|
||||
excellent $(WEB
|
||||
open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2461.pdf, C++0X) random
|
||||
number facility proposed by Jens Maurer and contributed to by
|
||||
researchers at the Fermi laboratory.
|
||||
|
||||
Macros:
|
||||
|
||||
|
@ -408,24 +408,23 @@ struct MersenneTwisterEngine(
|
|||
}
|
||||
|
||||
/**
|
||||
A $(D_PARAM MersenneTwisterEngine) instantiated with the parameters
|
||||
of the original engine
|
||||
$(LINK2 http://math.sci.hiroshima-u.ac.jp/~m-mat/MT/emt.html,MT19937),
|
||||
generating uniformly-distributed 32-bit numbers with a period of 2
|
||||
to the power of 19937. Recommended for random number generation
|
||||
unless memory is severely restricted, in which case a $(D_PARAM
|
||||
LinearCongruentialEngine) would be the generator of choice.
|
||||
A $(D MersenneTwisterEngine) instantiated with the parameters of the
|
||||
original engine $(WEB math.sci.hiroshima-u.ac.jp/~m-mat/MT/emt.html,
|
||||
MT19937), generating uniformly-distributed 32-bit numbers with a
|
||||
period of 2 to the power of 19937. Recommended for random number
|
||||
generation unless memory is severely restricted, in which case a $(D
|
||||
LinearCongruentialEngine) would be the generator of choice.
|
||||
|
||||
Example:
|
||||
Example:
|
||||
|
||||
----
|
||||
// seed with a constant
|
||||
Mt19937 gen;
|
||||
auto n = gen.next; // same for each run
|
||||
// Seed with an unpredictable value
|
||||
gen.seed(unpredictableSeed);
|
||||
n = gen.next; // different across runs
|
||||
----
|
||||
----
|
||||
// seed with a constant
|
||||
Mt19937 gen;
|
||||
auto n = gen.next; // same for each run
|
||||
// Seed with an unpredictable value
|
||||
gen.seed(unpredictableSeed);
|
||||
n = gen.next; // different across runs
|
||||
----
|
||||
*/
|
||||
alias MersenneTwisterEngine!(uint, 32, 624, 397, 31, 0x9908b0df, 11, 7,
|
||||
0x9d2c5680, 15, 0xefc60000, 18)
|
||||
|
@ -439,21 +438,21 @@ unittest
|
|||
}
|
||||
|
||||
/**
|
||||
The "default", "favorite", "suggested" random number generator on
|
||||
the current platform. It is a typedef for one of the
|
||||
previously-defined generators. You may want to use it if (1) you
|
||||
need to generate some nice random numbers, and (2) you don't care
|
||||
for the minutiae of the method being used.
|
||||
The "default", "favorite", "suggested" random number generator on the
|
||||
current platform. It is a typedef for one of the previously-defined
|
||||
generators. You may want to use it if (1) you need to generate some
|
||||
nice random numbers, and (2) you don't care for the minutiae of the
|
||||
method being used.
|
||||
*/
|
||||
|
||||
alias Mt19937 Random;
|
||||
|
||||
/**
|
||||
A "good" seed for initializing random number engines. Initializing
|
||||
with $(D_PARAM unpredictableSeed) makes engines generate different
|
||||
random number sequences every run.
|
||||
A "good" seed for initializing random number engines. Initializing
|
||||
with $(D_PARAM unpredictableSeed) makes engines generate different
|
||||
random number sequences every run.
|
||||
|
||||
Example:
|
||||
Example:
|
||||
|
||||
----
|
||||
auto rnd = Random(unpredictableSeed);
|
||||
|
@ -478,13 +477,13 @@ unittest
|
|||
}
|
||||
|
||||
/**
|
||||
Generates uniformly-distributed numbers within a range using an
|
||||
external generator. The $(D_PARAM boundaries) parameter controls
|
||||
the shape of the interval (open vs. closed on either side). Valid
|
||||
values for $(D boundaries) are "[]", "(]", "[)", and "()". The
|
||||
default interval is [a, b$(RPAREN).
|
||||
Generates uniformly-distributed numbers within a range using an
|
||||
external generator. The $(D boundaries) parameter controls the shape
|
||||
of the interval (open vs. closed on either side). Valid values for $(D
|
||||
boundaries) are "[]", "$(LPAREN)]", "[$(RPAREN)", and "()". The
|
||||
default interval is [a, b$(RPAREN).
|
||||
|
||||
Example:
|
||||
Example:
|
||||
|
||||
----
|
||||
auto a = new double[20];
|
||||
|
@ -514,9 +513,10 @@ struct UniformDistribution(NumberType, string boundaries = "[)")
|
|||
alias NumberType InputType;
|
||||
alias NumberType ResultType;
|
||||
/**
|
||||
Constructs a $(D_PARAM UniformDistribution) able to generate
|
||||
numbers in the interval [$(D_PARAM min), $(D_PARAM max)) if
|
||||
$(D_PARAM closedRight) is $(D_PARAM false).
|
||||
Constructs a $(D UniformDistribution) able to generate numbers between
|
||||
$(D a) and $(D b). The bounds of the interval are controlled by the
|
||||
template argument, e.g. $(D UniformDistribution!(double, "[]")(0, 1))
|
||||
generates numbers in the interval [0.0, 1.0].
|
||||
*/
|
||||
static UniformDistribution opCall(NumberType a, NumberType b)
|
||||
{
|
||||
|
@ -535,25 +535,25 @@ struct UniformDistribution(NumberType, string boundaries = "[)")
|
|||
return result;
|
||||
}
|
||||
/**
|
||||
Returns the smallest random value generated.
|
||||
Returns the left bound of the random value generated.
|
||||
*/
|
||||
ResultType a() { return leftLim == '[' ? _a : nextSmaller(_a); }
|
||||
|
||||
/**
|
||||
Returns the largest random value generated.
|
||||
Returns the the right bound of the random value generated.
|
||||
*/
|
||||
ResultType b() { return rightLim == ']' ? _b : nextLarger(_b); }
|
||||
|
||||
/**
|
||||
Does nothing (provided for conformity with other distributions).
|
||||
Does nothing (provided for conformity with other distributions).
|
||||
*/
|
||||
void reset()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
Returns a random number using $(D_PARAM
|
||||
UniformRandomNumberGenerator) as back-end.
|
||||
Returns a random number using $(D UniformRandomNumberGenerator) as
|
||||
back-end.
|
||||
*/
|
||||
ResultType next(UniformRandomNumberGenerator)
|
||||
(ref UniformRandomNumberGenerator urng)
|
||||
|
@ -626,11 +626,10 @@ unittest
|
|||
}
|
||||
|
||||
/**
|
||||
Convenience function that generates a number in an interval by
|
||||
forwarding to $(D_PARAM UniformDistribution!(T, leftLim,
|
||||
rightLim)(a, b).next).
|
||||
Convenience function that generates a number in an interval by
|
||||
forwarding to $(D UniformDistribution!(T, boundaries)(a, b).next).
|
||||
|
||||
Example:
|
||||
Example:
|
||||
|
||||
----
|
||||
Random gen(unpredictableSeed);
|
||||
|
@ -659,8 +658,7 @@ unittest
|
|||
}
|
||||
|
||||
/**
|
||||
Shuffles elements of $(D_PARAM array) using $(D_PARAM r) as a
|
||||
shuffler.
|
||||
Shuffles elements of $(D array) using $(D r) as a shuffler.
|
||||
*/
|
||||
|
||||
void randomShuffle(T, SomeRandomGen)(T[] array, ref SomeRandomGen r)
|
||||
|
@ -683,6 +681,42 @@ unittest
|
|||
assert(a.sort == b.sort);
|
||||
}
|
||||
|
||||
/**
|
||||
Throws a dice with relative probabilities stored in $(D
|
||||
proportions). Returns the index in $(D proportions) that was chosen.
|
||||
|
||||
Example:
|
||||
|
||||
----
|
||||
auto x = dice(0.5, 0.5); // x is 0 or 1 in equal proportions
|
||||
auto y = dice(50, 50); // y is 0 or 1 in equal proportions
|
||||
auto z = dice(70, 20, 10); // z is 0 70% of the time, 1 30% of the time,
|
||||
// and 2 10% of the time
|
||||
----
|
||||
*/
|
||||
|
||||
size_t dice(R)(ref R rnd, double[] proportions...) {
|
||||
invariant sum = reduce!("(assert(b >= 0), a + b)")(0.0, proportions);
|
||||
enforce(sum > 0, "Proportions in a dice cannot sum to zero");
|
||||
invariant point = uniform(rnd, 0.0, sum);
|
||||
assert(point < sum);
|
||||
auto mass = 0.0;
|
||||
foreach (i, e; proportions) {
|
||||
mass += e;
|
||||
if (point < mass) return i;
|
||||
}
|
||||
// this point should not be reached
|
||||
assert(false);
|
||||
}
|
||||
|
||||
unittest {
|
||||
auto rnd = Random(unpredictableSeed);
|
||||
auto i = dice(rnd, 0, 100);
|
||||
assert(i == 1);
|
||||
i = dice(rnd, 100, 0);
|
||||
assert(i == 0);
|
||||
}
|
||||
|
||||
/* ===================== Random ========================= */
|
||||
|
||||
// BUG: not multithreaded
|
||||
|
@ -691,19 +725,20 @@ private uint seed; // starting seed
|
|||
private uint index; // ith random number
|
||||
|
||||
/**
|
||||
* The random number generator is seeded at program startup with a random value.
|
||||
This ensures that each program generates a different sequence of random
|
||||
numbers. To generate a repeatable sequence, use rand_seed() to start the
|
||||
sequence. seed and index start it, and each successive value increments index.
|
||||
This means that the $(I n)th random number of the sequence can be directly
|
||||
generated
|
||||
by passing index + $(I n) to rand_seed().
|
||||
The random number generator is seeded at program startup with a random
|
||||
value. This ensures that each program generates a different sequence
|
||||
of random numbers. To generate a repeatable sequence, use $(D
|
||||
rand_seed()) to start the sequence. seed and index start it, and each
|
||||
successive value increments index. This means that the $(I n)th
|
||||
random number of the sequence can be directly generated by passing
|
||||
index + $(I n) to $(D rand_seed()).
|
||||
|
||||
Note: This is more random, but slower, than C's rand() function.
|
||||
To use C's rand() instead, import std.c.stdlib.
|
||||
Note: This is more random, but slower, than C's $(D rand()) function.
|
||||
To use C's $(D rand()) instead, import $(D std.c.stdlib).
|
||||
|
||||
BUGS: Shares a global single state, not multithreaded. SCHEDULED FOR
|
||||
DEPRECATION.
|
||||
|
||||
BUGS: Shares a global single state, not multithreaded.
|
||||
SCHEDULED FOR DEPRECATION.
|
||||
*/
|
||||
|
||||
void rand_seed(uint seed, uint index)
|
||||
|
@ -713,10 +748,10 @@ void rand_seed(uint seed, uint index)
|
|||
}
|
||||
|
||||
/**
|
||||
* Get the next random number in sequence.
|
||||
* BUGS: Shares a global single state, not multithreaded.
|
||||
* SCHEDULED FOR DEPRECATION.
|
||||
*/
|
||||
Get the next random number in sequence.
|
||||
BUGS: Shares a global single state, not multithreaded.
|
||||
SCHEDULED FOR DEPRECATION.
|
||||
*/
|
||||
|
||||
uint rand()
|
||||
{
|
||||
|
|
28
std/stdio.d
28
std/stdio.d
|
@ -541,7 +541,7 @@ size_t readln(FILE* fp, inout char[] buf, dchar terminator = '\n')
|
|||
static assert(wchar_t.sizeof == 2);
|
||||
buf.length = 0;
|
||||
int c2;
|
||||
for (int c; (c = FGETWC(fp)) != -1; )
|
||||
for (int c = void; (c = FGETWC(fp)) != -1; )
|
||||
{
|
||||
if ((c & ~0x7F) == 0)
|
||||
{ buf ~= c;
|
||||
|
@ -689,7 +689,7 @@ size_t readln(FILE* fp, inout char[] buf, dchar terminator = '\n')
|
|||
{
|
||||
buf.length = 0;
|
||||
int c2;
|
||||
for (int c; (c = FGETWC(fp)) != -1; )
|
||||
for (int c = void; (c = FGETWC(fp)) != -1; )
|
||||
{
|
||||
if ((c & ~0x7F) == 0)
|
||||
{ buf ~= c;
|
||||
|
@ -803,23 +803,35 @@ size_t readln(FILE* f, inout dchar[] buf, dchar terminator = '\n')
|
|||
* Convenience function that forwards to $(D_PARAM std.c.stdio.fopen)
|
||||
* with appropriately-constructed C-style strings.
|
||||
*/
|
||||
FILE* fopen(string name, string mode = "r")
|
||||
FILE* fopen(in char[] name, in char[] mode = "r")
|
||||
{
|
||||
return std.c.stdio.fopen(toStringz(name), toStringz(mode));
|
||||
const namez = toStringz(name), modez = toStringz(mode);
|
||||
auto result = std.c.stdio.fopen(namez, modez);
|
||||
version(linux)
|
||||
{
|
||||
enum int EOVERFLOW = 75; // taken from my Ubuntu's
|
||||
// /usr/include/asm-generic/errno.h
|
||||
if (!result && getErrno == EOVERFLOW)
|
||||
{
|
||||
// attempt fopen64, maybe the file was very large
|
||||
result = std.c.stdio.fopen64(namez, modez);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
version (linux)
|
||||
{
|
||||
extern(C) FILE* popen(const char*, const char*);
|
||||
extern(C) FILE* popen(const char*, const char*);
|
||||
|
||||
/***********************************
|
||||
* Convenience function that forwards to $(D_PARAM std.c.stdio.popen)
|
||||
* with appropriately-constructed C-style strings.
|
||||
*/
|
||||
FILE* popen(string name, string mode)
|
||||
{
|
||||
FILE* popen(in char[] name, in char[] mode = "r")
|
||||
{
|
||||
return popen(toStringz(name), toStringz(mode));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -1127,7 +1127,7 @@ class Stream : InputStream, OutputStream {
|
|||
// by Walter's permission
|
||||
char[1024] buffer;
|
||||
char* p = buffer.ptr;
|
||||
char* f = toStringz(format);
|
||||
auto f = toStringz(format);
|
||||
size_t psize = buffer.length;
|
||||
size_t count;
|
||||
while (true) {
|
||||
|
|
|
@ -218,7 +218,9 @@ deprecated const(char)* toCharz(string s)
|
|||
const(char)* toStringz(const(char)[] s)
|
||||
in
|
||||
{
|
||||
// assert(memchr(s.ptr, 0, s.length) == null);
|
||||
// The assert below contradicts the unittests!
|
||||
//assert(memchr(s.ptr, 0, s.length) == null,
|
||||
//text(s.length, ": `", s, "'"));
|
||||
}
|
||||
out (result)
|
||||
{
|
||||
|
|
83
std/utf.d
83
std/utf.d
|
@ -142,7 +142,8 @@ uint stride(in char[] s, size_t i)
|
|||
*/
|
||||
|
||||
uint stride(in wchar[] s, size_t i)
|
||||
{ uint u = s[i];
|
||||
{
|
||||
invariant uint u = s[i];
|
||||
return 1 + (u >= 0xD800 && u <= 0xDBFF);
|
||||
}
|
||||
|
||||
|
@ -167,18 +168,14 @@ size_t toUCSindex(in char[] s, size_t i)
|
|||
{
|
||||
size_t n;
|
||||
size_t j;
|
||||
size_t stride;
|
||||
|
||||
for (j = 0; j < i; j += stride)
|
||||
for (j = 0; j < i; )
|
||||
{
|
||||
stride = UTF8stride[s[j]];
|
||||
if (stride == 0xFF)
|
||||
goto Lerr;
|
||||
j += stride(s, j);
|
||||
n++;
|
||||
}
|
||||
if (j > i)
|
||||
{
|
||||
Lerr:
|
||||
throw new UtfException("1invalid UTF-8 sequence", j);
|
||||
}
|
||||
return n;
|
||||
|
@ -192,14 +189,12 @@ size_t toUCSindex(in wchar[] s, size_t i)
|
|||
size_t j;
|
||||
|
||||
for (j = 0; j < i; )
|
||||
{ uint u = s[j];
|
||||
|
||||
j += 1 + (u >= 0xD800 && u <= 0xDBFF);
|
||||
{
|
||||
j += stride(s, j);
|
||||
n++;
|
||||
}
|
||||
if (j > i)
|
||||
{
|
||||
Lerr:
|
||||
throw new UtfException("2invalid UTF-16 sequence", j);
|
||||
}
|
||||
return n;
|
||||
|
@ -589,45 +584,45 @@ void encode(inout dchar[] s, dchar c)
|
|||
s ~= c;
|
||||
}
|
||||
|
||||
/**
|
||||
Returns the code length of $(D c) in the encoding using $(D C) as a
|
||||
code point. The code is returned in character count, not in bytes.
|
||||
*/
|
||||
|
||||
ubyte codeLength(C)(dchar c)
|
||||
{
|
||||
static if (C.sizeof == 1)
|
||||
{
|
||||
return
|
||||
c <= 0x7F ? 1
|
||||
: c <= 0x7FF ? 2
|
||||
: c <= 0xFFFF ? 3
|
||||
: c <= 0x10FFFF ? 4
|
||||
: (assert(false), 6);
|
||||
}
|
||||
else static if (C.sizeof == 2)
|
||||
{
|
||||
return c <= 0xFFFF ? 1 : 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
static assert(C.sizeof == 4);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* =================== Validation ======================= */
|
||||
|
||||
/***********************************
|
||||
* Checks to see if string is well formed or not. Throws a UtfException if it is
|
||||
* not. Use to check all untrusted input for correctness.
|
||||
Checks to see if string is well formed or not. $(D S) can be an array
|
||||
of $(D char), $(D wchar), or $(D dchar). Throws a $(D UtfException)
|
||||
if it is not. Use to check all untrusted input for correctness.
|
||||
*/
|
||||
|
||||
void validate(in string s)
|
||||
void validate(S)(in S s)
|
||||
{
|
||||
size_t len = s.length;
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < len; )
|
||||
{
|
||||
decode(s, i);
|
||||
}
|
||||
}
|
||||
|
||||
/** ditto */
|
||||
|
||||
void validate(in wstring s)
|
||||
{
|
||||
size_t len = s.length;
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < len; )
|
||||
{
|
||||
decode(s, i);
|
||||
}
|
||||
}
|
||||
|
||||
/** ditto */
|
||||
|
||||
void validate(in dstring s)
|
||||
{
|
||||
size_t len = s.length;
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < len; )
|
||||
invariant len = s.length;
|
||||
for (size_t i = 0; i < len; )
|
||||
{
|
||||
decode(s, i);
|
||||
}
|
||||
|
|
|
@ -2494,6 +2494,7 @@ void check(string s)
|
|||
|
||||
unittest
|
||||
{
|
||||
return;
|
||||
try
|
||||
{
|
||||
check(q"[<?xml version="1.0"?>
|
||||
|
@ -2604,7 +2605,8 @@ class CheckException : Exception
|
|||
string head = entire[0..$-tail.length];
|
||||
int n = head.rfind('\n') + 1;
|
||||
line = head.count("\n") + 1;
|
||||
dstring t = to!(Utf32)(head[n..$]);
|
||||
dstring t;
|
||||
transcode(head[n .. $], t);
|
||||
column = t.length + 1;
|
||||
if (err !is null) err.complete(entire);
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue