diff --git a/internal/adi.d b/internal/adi.d index 2c86cb972..9cc83da9d 100644 --- a/internal/adi.d +++ b/internal/adi.d @@ -1,13 +1,33 @@ //_ adi.d -// Copyright (c) 2000-2003 by Digital Mars -// All Rights Reserved -// www.digitalmars.com -// Written by Walter Bright + +/* + * Copyright (C) 2000-2005 by Digital Mars, www.digitalmars.com + * Written by Walter Bright + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, in both source and binary form, subject to the following + * restrictions: + * + * o The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * o Altered source versions must be plainly marked as such, and must not + * be misrepresented as being the original software. + * o This notice may not be removed or altered from any source + * distribution. + */ // Dynamic array property support routines //debug=adi; // uncomment to turn on debugging printf's +import std.stdio; import std.c.stdio; import std.c.stdlib; import std.string; @@ -20,6 +40,178 @@ struct Array void *ptr; } +/********************************************** + * Reverse array of chars. + * Handled separately because embedded multibyte encodings should not be + * reversed. + */ + +extern (C) long _adReverseChar(char[] a) +{ + if (a.length > 1) + { + char[6] tmp; + char* lo = a.ptr; + char* hi = &a[length - 1]; + + while (lo < hi) + { char clo = *lo; + char chi = *hi; + + if (clo <= 0x7F && chi <= 0x7F) + { + *lo = chi; + *hi = clo; + lo++; + hi--; + continue; + } + + int stridelo = std.utf.UTF8stride[clo]; + + int stridehi = 1; + while ((chi & 0xC0) == 0x80) + { + chi = *--hi; + stridehi++; + assert(hi >= lo); + } + if (lo == hi) + break; + + if (stridelo == stridehi) + { + + memcpy(tmp, lo, stridelo); + memcpy(lo, hi, stridelo); + memcpy(hi, tmp, stridelo); + lo += stridelo; + hi -= stridehi; + continue; + } + + /* Shift the whole array. This is woefully inefficient + */ + //writefln("stridelo = %d, stridehi = %d", stridelo, stridehi); + memcpy(tmp, hi, stridehi); + memcpy(hi + stridehi - stridelo, lo, stridelo); + memmove(lo + stridehi, lo + stridelo , hi - (lo + stridelo)); + memcpy(lo, tmp, stridehi); + + lo += stridehi; + hi -= stridelo; + } + } + return *cast(long*)(&a); +} + +unittest +{ + char[] a = "abcd"; + char[] r; + + r = a.dup.reverse; + //writefln(r); + assert(r == "dcba"); + + a = "a\u1235\u1234c"; + //writefln(a); + r = a.dup.reverse; + //writefln(r); + assert(r == "c\u1234\u1235a"); + + a = "ab\u1234c"; + //writefln(a); + r = a.dup.reverse; + //writefln(r); + assert(r == "c\u1234ba"); +} + + +/********************************************** + * Reverse array of wchars. + * Handled separately because embedded multiword encodings should not be + * reversed. + */ + +extern (C) long _adReverseWchar(wchar[] a) +{ + if (a.length > 1) + { + wchar[2] tmp; + wchar* lo = a.ptr; + wchar* hi = &a[length - 1]; + + while (lo < hi) + { wchar clo = *lo; + wchar chi = *hi; + + if ((clo < 0xD800 || clo > 0xDFFF) && + (chi < 0xD800 || chi > 0xDFFF)) + { + *lo = chi; + *hi = clo; + lo++; + hi--; + continue; + } + + int stridelo = 1 + (clo >= 0xD800 && clo <= 0xDBFF); + + int stridehi = 1; + if (chi >= 0xDC00 && chi <= 0xDFFF) + { + chi = *--hi; + stridehi++; + assert(hi >= lo); + } + if (lo == hi) + break; + + if (stridelo == stridehi) + { int tmp; + + assert(stridelo == 2); + assert(tmp.sizeof == 2 * (*lo).sizeof); + tmp = *cast(int*)lo; + *cast(int*)lo = *cast(int*)hi; + *cast(int*)hi = tmp; + lo += stridelo; + hi -= stridehi; + continue; + } + + /* Shift the whole array. This is woefully inefficient + */ + memcpy(tmp, hi, stridehi * wchar.sizeof); + memcpy(hi + stridehi - stridelo, lo, stridelo * wchar.sizeof); + memmove(lo + stridehi, lo + stridelo , (hi - (lo + stridelo)) * wchar.sizeof); + memcpy(lo, tmp, stridehi * wchar.sizeof); + + lo += stridehi; + hi -= stridelo; + } + } + return *cast(long*)(&a); +} + +unittest +{ + wchar[] a = "abcd"; + wchar[] r; + + r = a.dup.reverse; + assert(r == "dcba"); + + a = "a\U00012356\U00012346c"; + r = a.dup.reverse; + assert(r == "c\U00012346\U00012356a"); + + a = "ab\U00012345c"; + r = a.dup.reverse; + assert(r == "c\U00012345ba"); +} + /********************************************** * Support for array.reverse property. diff --git a/internal/minit.asm b/internal/minit.asm index d4d965bcf..bdf38f25b 100644 --- a/internal/minit.asm +++ b/internal/minit.asm @@ -14,6 +14,9 @@ else DATAGRP EQU DGROUP endif +public __nullext +__nullext equ 0 + extrn __moduleinfo_array:near ; These segments bracket FM, which contains the list of ModuleInfo pointers diff --git a/internal/object.d b/internal/object.d index f268e2a98..0aef7a993 100644 --- a/internal/object.d +++ b/internal/object.d @@ -305,3 +305,4 @@ class Error : Exception } } +//extern (C) int nullext = 0; diff --git a/internal/qsort2.d b/internal/qsort2.d new file mode 100644 index 000000000..21febcde9 --- /dev/null +++ b/internal/qsort2.d @@ -0,0 +1,68 @@ + +/* + * Placed into Public Domain + * written by Walter Bright + * www.digitalmars.com + * + * This is a public domain version of qsort.d. + * All it does is call C's qsort(), but runs a little slower since + * it needs to synchronize a global variable. + */ + + +//debug=qsort; + +import std.c.stdlib; + +struct Array +{ + size_t length; + void *ptr; +} + +private TypeInfo tiglobal; + +extern (C) int cmp(void* p1, void* p2) +{ + return tiglobal.compare(p1, p2); +} + +extern (C) long _adSort(Array a, TypeInfo ti) +{ + synchronized + { + tiglobal = ti; + std.c.stdlib.qsort(a.ptr, a.length, cast(size_t)ti.tsize(), &cmp); + } + return *cast(long*)(&a); +} + + + +unittest +{ + debug(qsort) printf("array.sort.unittest()\n"); + + int a[] = new int[10]; + + a[0] = 23; + a[1] = 1; + a[2] = 64; + a[3] = 5; + a[4] = 6; + a[5] = 5; + a[6] = 17; + a[7] = 3; + a[8] = 0; + a[9] = -1; + + a.sort; + + for (int i = 0; i < a.length - 1; i++) + { + //printf("i = %d", i); + //printf(" %d %d\n", a[i], a[i + 1]); + assert(a[i] <= a[i + 1]); + } +} + diff --git a/linux.mak b/linux.mak index 8e3507d45..37769a070 100644 --- a/linux.mak +++ b/linux.mak @@ -37,7 +37,7 @@ test.o : test.d $(DMD) -c test -g test : test.o libphobos.a - $(CC) -o $@ test.o libphobos.a -lpthread -g + $(CC) -o $@ test.o libphobos.a -lpthread -lm -g unittest : unittest.o libphobos.a $(CC) -o $@ unittest.o libphobos.a -lpthread -lm -g @@ -52,7 +52,7 @@ OBJS= asserterror.o deh2.o switch.o complex.o gcstats.o \ cast.o path.o string.o memset.o math.o mmfile.o \ outbuffer.o ctype.o regexp.o random.o linux.o \ stream.o switcherr.o array.o gc.o \ - qsort.o qsort2.o thread.o obj.o utf.o uri.o \ + qsort.o thread.o obj.o utf.o uri.o \ crc32.o conv.o arraycast.o errno.o alloca.o cmath2.o \ process.o syserror.o \ socket.o socketstream.o stdarg.o stdio.o format.o \ @@ -128,12 +128,13 @@ SRC_INT= \ internal/memset.d internal/arraycast.d internal/aaA.d internal/adi.d \ internal/dmain2.d internal/cast.d internal/qsort.d internal/deh2.d \ internal/cmath2.d internal/obj.d internal/mars.h internal/aApply.d \ - internal/object.d internal/trace.d + internal/object.d internal/trace.d internal/qsort2.d SRC_STD_WIN= std/windows/registry.d \ std/windows/iunknown.d -SRC_STD_C_WIN= std/c/windows/windows.d std/c/windows/com.d +SRC_STD_C_WIN= std/c/windows/windows.d std/c/windows/com.d \ + std/c/windows/winsock.d SRC_STD_C_LINUX= std/c/linux/linux.d std/c/linux/linuxextern.d diff --git a/phoboslicense.txt b/phoboslicense.txt index 04b5f7656..c75d03d2c 100644 --- a/phoboslicense.txt +++ b/phoboslicense.txt @@ -2,7 +2,7 @@ Unless otherwise marked within the file, each file in the source to the Phobos library is under the following license: /* - * Copyright (C) 2004 by Digital Mars, www.digitalmars.com + * Copyright (C) 2004-2005 by Digital Mars, www.digitalmars.com * Written by Walter Bright * * This software is provided 'as-is', without any express or implied diff --git a/std/c/linux/linux.d b/std/c/linux/linux.d index 516249220..6d7f4ab4a 100644 --- a/std/c/linux/linux.d +++ b/std/c/linux/linux.d @@ -251,3 +251,74 @@ extern(C) void seekdir(DIR* dir, off_t offset); } + +extern(C) +{ + private import std.intrinsic; + + + char* strerror(int errnum); + + int select(int nfds, fd_set* readfds, fd_set* writefds, fd_set* errorfds, timeval* timeout); + int fcntl(int s, int f, ...); + + + enum + { + EINTR = 4, + EINPROGRESS = 115, + } + + + const uint FD_SETSIZE = 1024; + //const uint NFDBITS = 8 * int.sizeof; // DMD 0.110: 8 * (int).sizeof is not an expression + const int NFDBITS = 32; + + + struct fd_set + { + int[FD_SETSIZE / NFDBITS] fds_bits; + alias fds_bits __fds_bits; + } + + + int FDELT(int d) + { + return d / NFDBITS; + } + + + int FDMASK(int d) + { + return 1 << (d % NFDBITS); + } + + + // Removes. + void FD_CLR(int fd, fd_set* set) + { + btr(cast(uint*)&set.fds_bits.ptr[FDELT(fd)], cast(uint)(fd % NFDBITS)); + } + + + // Tests. + int FD_ISSET(int fd, fd_set* set) + { + return bt(cast(uint*)&set.fds_bits.ptr[FDELT(fd)], cast(uint)(fd % NFDBITS)); + } + + + // Adds. + void FD_SET(int fd, fd_set* set) + { + bts(cast(uint*)&set.fds_bits.ptr[FDELT(fd)], cast(uint)(fd % NFDBITS)); + } + + + // Resets to zero. + void FD_ZERO(fd_set* set) + { + set.fds_bits[] = 0; + } +} + diff --git a/std/c/linux/socket.d b/std/c/linux/socket.d new file mode 100644 index 000000000..a7c1d295e --- /dev/null +++ b/std/c/linux/socket.d @@ -0,0 +1,382 @@ +/* + Written by Christopher E. Miller + Placed into public domain. +*/ + + +module std.c.linux.socket; + +private import std.stdint; + + +extern(C): + +alias int socklen_t; + +const int F_GETFL = 3; +const int F_SETFL = 4; +const int O_NONBLOCK = 0x800; + + +int socket(int af, int type, int protocol); +int bind(int s, sockaddr* name, int namelen); +int connect(int s, sockaddr* name, int namelen); +int listen(int s, int backlog); +int accept(int s, sockaddr* addr, int* addrlen); +int shutdown(int s, int how); +int getpeername(int s, sockaddr* name, int* namelen); +int getsockname(int s, sockaddr* name, int* namelen); +int send(int s, void* buf, int len, int flags); +int sendto(int s, void* buf, int len, int flags, sockaddr* to, int tolen); +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); +char* inet_ntoa(in_addr ina); +hostent* gethostbyname(char* name); +hostent* gethostbyaddr(void* addr, int len, int type); +protoent* getprotobyname(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); +void freeaddrinfo(addrinfo* ai); +int getnameinfo(sockaddr* sa, socklen_t salen, char* node, socklen_t nodelen, char* service, socklen_t servicelen, int flags); + + +enum: int +{ + AF_UNSPEC = 0, + AF_UNIX = 1, + AF_INET = 2, + AF_IPX = 4, + AF_APPLETALK = 5, + AF_INET6 = 10, + // ... + + PF_UNSPEC = AF_UNSPEC, + PF_UNIX = AF_UNIX, + PF_INET = AF_INET, + PF_IPX = AF_IPX, + PF_APPLETALK = AF_APPLETALK, + PF_INET6 = AF_INET6, +} + + +version(X86) +{ + enum: int + { + SOL_SOCKET = 1, + } +} +else +{ + // Different values on other platforms. + static assert(0); +} + + +enum: int +{ + SO_DEBUG = 1, + SO_BROADCAST = 6, + SO_REUSEADDR = 2, + SO_LINGER = 13, + SO_DONTLINGER = ~SO_LINGER, + SO_OOBINLINE = 10, + SO_SNDBUF = 7, + SO_RCVBUF = 8, + SO_ACCEPTCONN = 30, + SO_DONTROUTE = 5, + SO_TYPE = 3, + + TCP_NODELAY = 1, + + IP_MULTICAST_LOOP = 34, + IP_ADD_MEMBERSHIP = 35, + IP_DROP_MEMBERSHIP = 36, + + // ... + + IPV6_ADDRFORM = 1, + IPV6_PKTINFO = 2, + IPV6_HOPOPTS = 3, + IPV6_DSTOPTS = 4, + IPV6_RTHDR = 5, + IPV6_PKTOPTIONS = 6, + IPV6_CHECKSUM = 7, + IPV6_HOPLIMIT = 8, + IPV6_NEXTHOP = 9, + IPV6_AUTHHDR = 10, + IPV6_UNICAST_HOPS = 16, + IPV6_MULTICAST_IF = 17, + IPV6_MULTICAST_HOPS = 18, + IPV6_MULTICAST_LOOP = 19, + IPV6_JOIN_GROUP = 20, + IPV6_LEAVE_GROUP = 21, + IPV6_ROUTER_ALERT = 22, + IPV6_MTU_DISCOVER = 23, + IPV6_MTU = 24, + IPV6_RECVERR = 25, + IPV6_V6ONLY = 26, + IPV6_JOIN_ANYCAST = 27, + IPV6_LEAVE_ANYCAST = 28, + IPV6_IPSEC_POLICY = 34, + IPV6_XFRM_POLICY = 35, +} + + +struct linger +{ + int32_t l_onoff; + int32_t l_linger; +} + + +struct protoent +{ + char* p_name; + char** p_aliases; + int32_t p_proto; +} + + +struct servent +{ + char* s_name; + char** s_aliases; + int32_t s_port; + char* s_proto; +} + + +version(BigEndian) +{ + uint16_t htons(uint16_t x) + { + return x; + } + + + uint32_t htonl(uint32_t x) + { + return x; + } +} +else version(LittleEndian) +{ + private import std.intrinsic; + + + uint16_t htons(uint16_t x) + { + return (x >> 8) | (x << 8); + } + + + uint32_t htonl(uint32_t x) + { + return bswap(x); + } +} +else +{ + static assert(0); +} + + +uint16_t ntohs(uint16_t x) +{ + return htons(x); +} + + +uint32_t ntohl(uint32_t x) +{ + return htonl(x); +} + + +enum: int +{ + SOCK_STREAM = 1, + SOCK_DGRAM = 2, + SOCK_RAW = 3, + SOCK_RDM = 4, + SOCK_SEQPACKET = 5, +} + + +enum: int +{ + IPPROTO_IP = 0, + IPPROTO_ICMP = 1, + IPPROTO_IGMP = 2, + IPPROTO_GGP = 3, + IPPROTO_TCP = 6, + IPPROTO_PUP = 12, + IPPROTO_UDP = 17, + IPPROTO_IDP = 22, + IPPROTO_IPV6 = 41, + IPPROTO_ND = 77, + IPPROTO_RAW = 255, + + IPPROTO_MAX = 256, +} + + +enum: int +{ + MSG_OOB = 0x1, + MSG_PEEK = 0x2, + MSG_DONTROUTE = 0x4, +} + + +enum: int +{ + SD_RECEIVE = 0, + SD_SEND = 1, + SD_BOTH = 2, +} + + +enum: uint +{ + INADDR_ANY = 0, + INADDR_LOOPBACK = 0x7F000001, + INADDR_BROADCAST = 0xFFFFFFFF, + INADDR_NONE = 0xFFFFFFFF, + ADDR_ANY = INADDR_ANY, +} + + +enum: int +{ + AI_PASSIVE = 0x1, + AI_CANONNAME = 0x2, + AI_NUMERICHOST = 0x4, +} + + +union in_addr +{ + private union _S_un_t + { + private struct _S_un_b_t + { + uint8_t s_b1, s_b2, s_b3, s_b4; + } + _S_un_b_t S_un_b; + + private struct _S_un_w_t + { + uint16_t s_w1, s_w2; + } + _S_un_w_t S_un_w; + + uint32_t S_addr; + } + _S_un_t S_un; + + uint32_t s_addr; + + struct + { + uint8_t s_net, s_host; + + union + { + uint16_t s_imp; + + struct + { + uint8_t s_lh, s_impno; + } + } + } +} + + +union in6_addr +{ + private union _in6_u_t + { + uint8_t[16] u6_addr8; + uint16_t[8] u6_addr16; + uint32_t[4] u6_addr32; + } + _in6_u_t in6_u; + + uint8_t[16] s6_addr8; + uint16_t[8] s6_addr16; + uint32_t[4] s6_addr32; +} + + +const in6_addr IN6ADDR_ANY = { s6_addr8: [0] }; +const in6_addr IN6ADDR_LOOPBACK = { s6_addr8: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1] }; +//alias IN6ADDR_ANY IN6ADDR_ANY_INIT; +//alias IN6ADDR_LOOPBACK IN6ADDR_LOOPBACK_INIT; + +const uint INET_ADDRSTRLEN = 16; +const uint INET6_ADDRSTRLEN = 46; + + +struct sockaddr +{ + int16_t sa_family; + ubyte[14] sa_data; +} + + +struct sockaddr_in +{ + int16_t sin_family = AF_INET; + uint16_t sin_port; + in_addr sin_addr; + ubyte[8] sin_zero; +} + + +struct sockaddr_in6 +{ + int16_t sin6_family = AF_INET6; + uint16_t sin6_port; + uint32_t sin6_flowinfo; + in6_addr sin6_addr; + uint32_t sin6_scope_id; +} + + +struct addrinfo +{ + int32_t ai_flags; + int32_t ai_family; + int32_t ai_socktype; + int32_t ai_protocol; + size_t ai_addrlen; + char* ai_canonname; + sockaddr* ai_addr; + addrinfo* ai_next; +} + + +struct hostent +{ + char* h_name; + char** h_aliases; + int32_t h_addrtype; + int32_t h_length; + char** h_addr_list; + + + char* h_addr() + { + return h_addr_list[0]; + } +} + diff --git a/std/c/windows/winsock.d b/std/c/windows/winsock.d new file mode 100644 index 000000000..aced43a4c --- /dev/null +++ b/std/c/windows/winsock.d @@ -0,0 +1,539 @@ +/* + Written by Christopher E. Miller + Placed into public domain. +*/ + + +module std.c.windows.winsock; + +private import std.stdint; +private import std.c.windows.windows; + + +extern(Windows): + +alias UINT SOCKET; +alias int socklen_t; + +const SOCKET INVALID_SOCKET = cast(SOCKET)~0; +const int SOCKET_ERROR = -1; + +const int WSADESCRIPTION_LEN = 256; +const int WSASYS_STATUS_LEN = 128; + +struct WSADATA +{ + WORD wVersion; + WORD wHighVersion; + char szDescription[WSADESCRIPTION_LEN + 1]; + char szSystemStatus[WSASYS_STATUS_LEN + 1]; + USHORT iMaxSockets; + USHORT iMaxUdpDg; + char* lpVendorInfo; +} +alias WSADATA* LPWSADATA; + + +const int IOCPARM_MASK = 0x7F; +const int IOC_IN = cast(int)0x80000000; +const int FIONBIO = cast(int)(IOC_IN | ((UINT.sizeof & IOCPARM_MASK) << 16) | (102 << 8) | 126); + + +int WSAStartup(WORD wVersionRequested, LPWSADATA lpWSAData); +int WSACleanup(); +SOCKET socket(int af, int type, int protocol); +int ioctlsocket(SOCKET s, int cmd, uint* argp); +int bind(SOCKET s, sockaddr* name, int namelen); +int connect(SOCKET s, sockaddr* name, int namelen); +int listen(SOCKET s, int backlog); +SOCKET accept(SOCKET s, sockaddr* addr, int* addrlen); +int closesocket(SOCKET s); +int shutdown(SOCKET s, int how); +int getpeername(SOCKET s, sockaddr* name, int* namelen); +int getsockname(SOCKET s, sockaddr* name, int* namelen); +int send(SOCKET s, void* buf, int len, int flags); +int sendto(SOCKET s, void* buf, int len, int flags, sockaddr* to, int tolen); +int recv(SOCKET s, void* buf, int len, int flags); +int recvfrom(SOCKET s, void* buf, int len, int flags, sockaddr* from, int* fromlen); +int getsockopt(SOCKET s, int level, int optname, void* optval, int* optlen); +int setsockopt(SOCKET s, int level, int optname, void* optval, int optlen); +uint inet_addr(char* cp); +int select(int nfds, fd_set* readfds, fd_set* writefds, fd_set* errorfds, timeval* timeout); +char* inet_ntoa(in_addr ina); +hostent* gethostbyname(char* name); +hostent* gethostbyaddr(void* addr, int len, int type); +protoent* getprotobyname(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); +void freeaddrinfo(addrinfo* ai); +int getnameinfo(sockaddr* sa, socklen_t salen, char* host, DWORD hostlen, char* serv, DWORD servlen, int flags); + +enum: int +{ + WSAEWOULDBLOCK = 10035, + WSAEINTR = 10004, + WSAHOST_NOT_FOUND = 11001, +} + +int WSAGetLastError(); + + +enum: int +{ + AF_UNSPEC = 0, + + AF_UNIX = 1, + AF_INET = 2, + AF_IMPLINK = 3, + AF_PUP = 4, + AF_CHAOS = 5, + AF_NS = 6, + AF_IPX = AF_NS, + AF_ISO = 7, + AF_OSI = AF_ISO, + AF_ECMA = 8, + AF_DATAKIT = 9, + AF_CCITT = 10, + AF_SNA = 11, + AF_DECnet = 12, + AF_DLI = 13, + AF_LAT = 14, + AF_HYLINK = 15, + AF_APPLETALK = 16, + AF_NETBIOS = 17, + AF_VOICEVIEW = 18, + AF_FIREFOX = 19, + AF_UNKNOWN1 = 20, + AF_BAN = 21, + AF_ATM = 22, + AF_INET6 = 23, + AF_CLUSTER = 24, + AF_12844 = 25, + AF_IRDA = 26, + AF_NETDES = 28, + + AF_MAX = 29, + + + PF_UNSPEC = AF_UNSPEC, + + PF_UNIX = AF_UNIX, + PF_INET = AF_INET, + PF_IMPLINK = AF_IMPLINK, + PF_PUP = AF_PUP, + PF_CHAOS = AF_CHAOS, + PF_NS = AF_NS, + PF_IPX = AF_IPX, + PF_ISO = AF_ISO, + PF_OSI = AF_OSI, + PF_ECMA = AF_ECMA, + PF_DATAKIT = AF_DATAKIT, + PF_CCITT = AF_CCITT, + PF_SNA = AF_SNA, + PF_DECnet = AF_DECnet, + PF_DLI = AF_DLI, + PF_LAT = AF_LAT, + PF_HYLINK = AF_HYLINK, + PF_APPLETALK = AF_APPLETALK, + PF_VOICEVIEW = AF_VOICEVIEW, + PF_FIREFOX = AF_FIREFOX, + PF_UNKNOWN1 = AF_UNKNOWN1, + PF_BAN = AF_BAN, + PF_INET6 = AF_INET6, + + PF_MAX = AF_MAX, +} + + +enum: int +{ + SOL_SOCKET = 0xFFFF, +} + + +enum: int +{ + SO_DEBUG = 0x0001, + SO_ACCEPTCONN = 0x0002, + SO_REUSEADDR = 0x0004, + SO_KEEPALIVE = 0x0008, + SO_DONTROUTE = 0x0010, + SO_BROADCAST = 0x0020, + SO_USELOOPBACK = 0x0040, + SO_LINGER = 0x0080, + SO_DONTLINGER = ~SO_LINGER, + SO_OOBINLINE = 0x0100, + SO_SNDBUF = 0x1001, + SO_RCVBUF = 0x1002, + SO_SNDLOWAT = 0x1003, + SO_RCVLOWAT = 0x1004, + SO_SNDTIMEO = 0x1005, + SO_RCVTIMEO = 0x1006, + SO_ERROR = 0x1007, + SO_TYPE = 0x1008, + SO_EXCLUSIVEADDRUSE = ~SO_REUSEADDR, + + TCP_NODELAY = 1, + + IP_MULTICAST_LOOP = 0x4, + IP_ADD_MEMBERSHIP = 0x5, + IP_DROP_MEMBERSHIP = 0x6, + + IPV6_UNICAST_HOPS = 4, + IPV6_MULTICAST_IF = 9, + IPV6_MULTICAST_HOPS = 10, + IPV6_MULTICAST_LOOP = 11, + IPV6_ADD_MEMBERSHIP = 12, + IPV6_DROP_MEMBERSHIP = 13, + IPV6_JOIN_GROUP = IPV6_ADD_MEMBERSHIP, + IPV6_LEAVE_GROUP = IPV6_DROP_MEMBERSHIP, +} + + +const uint FD_SETSIZE = 64; + + +struct fd_set +{ + UINT fd_count; + SOCKET[FD_SETSIZE] fd_array; +} + + +// Removes. +void FD_CLR(SOCKET fd, fd_set* set) +{ + uint c = set.fd_count; + SOCKET* start = set.fd_array.ptr; + SOCKET* stop = start + c; + + for(; start != stop; start++) + { + if(*start == fd) + goto found; + } + return; //not found + + found: + for(++start; start != stop; start++) + { + *(start - 1) = *start; + } + + set.fd_count = c - 1; +} + + +// Tests. +int FD_ISSET(SOCKET fd, fd_set* set) +{ + SOCKET* start = set.fd_array.ptr; + SOCKET* stop = start + set.fd_count; + + for(; start != stop; start++) + { + if(*start == fd) + return true; + } + return false; +} + + +// Adds. +void FD_SET(SOCKET fd, fd_set* set) +{ + uint c = set.fd_count; + set.fd_array.ptr[c] = fd; + set.fd_count = c + 1; +} + + +// Resets to zero. +void FD_ZERO(fd_set* set) +{ + set.fd_count = 0; +} + + +struct linger +{ + USHORT l_onoff; + USHORT l_linger; +} + + +struct protoent +{ + char* p_name; + char** p_aliases; + SHORT p_proto; +} + + +struct servent +{ + char* s_name; + char** s_aliases; + SHORT s_port; + char* s_proto; +} + + +/+ +union in6_addr +{ + private union _u_t + { + BYTE[16] Byte; + WORD[8] Word; + } + _u_t u; +} + + +struct in_addr6 +{ + BYTE[16] s6_addr; +} ++/ + + +version(BigEndian) +{ + uint16_t htons(uint16_t x) + { + return x; + } + + + uint32_t htonl(uint32_t x) + { + return x; + } +} +else version(LittleEndian) +{ + private import std.intrinsic; + + + uint16_t htons(uint16_t x) + { + return (x >> 8) | (x << 8); + } + + + uint32_t htonl(uint32_t x) + { + return bswap(x); + } +} +else +{ + static assert(0); +} + + +uint16_t ntohs(uint16_t x) +{ + return htons(x); +} + + +uint32_t ntohl(uint32_t x) +{ + return htonl(x); +} + + +enum: int +{ + SOCK_STREAM = 1, + SOCK_DGRAM = 2, + SOCK_RAW = 3, + SOCK_RDM = 4, + SOCK_SEQPACKET = 5, +} + + +enum: int +{ + IPPROTO_IP = 0, + IPPROTO_ICMP = 1, + IPPROTO_IGMP = 2, + IPPROTO_GGP = 3, + IPPROTO_TCP = 6, + IPPROTO_PUP = 12, + IPPROTO_UDP = 17, + IPPROTO_IDP = 22, + IPPROTO_IPV6 = 41, + IPPROTO_ND = 77, + IPPROTO_RAW = 255, + + IPPROTO_MAX = 256, +} + + +enum: int +{ + MSG_OOB = 0x1, + MSG_PEEK = 0x2, + MSG_DONTROUTE = 0x4, +} + + +enum: int +{ + SD_RECEIVE = 0, + SD_SEND = 1, + SD_BOTH = 2, +} + + +enum: uint +{ + INADDR_ANY = 0, + INADDR_LOOPBACK = 0x7F000001, + INADDR_BROADCAST = 0xFFFFFFFF, + INADDR_NONE = 0xFFFFFFFF, + ADDR_ANY = INADDR_ANY, +} + + +enum: int +{ + AI_PASSIVE = 0x1, + AI_CANONNAME = 0x2, + AI_NUMERICHOST = 0x4, +} + + +struct timeval +{ + int32_t tv_sec; + int32_t tv_usec; +} + + +union in_addr +{ + private union _S_un_t + { + private struct _S_un_b_t + { + uint8_t s_b1, s_b2, s_b3, s_b4; + } + _S_un_b_t S_un_b; + + private struct _S_un_w_t + { + uint16_t s_w1, s_w2; + } + _S_un_w_t S_un_w; + + uint32_t S_addr; + } + _S_un_t S_un; + + uint32_t s_addr; + + struct + { + uint8_t s_net, s_host; + + union + { + uint16_t s_imp; + + struct + { + uint8_t s_lh, s_impno; + } + } + } +} + + +union in6_addr +{ + private union _in6_u_t + { + uint8_t[16] u6_addr8; + uint16_t[8] u6_addr16; + uint32_t[4] u6_addr32; + } + _in6_u_t in6_u; + + uint8_t[16] s6_addr8; + uint16_t[8] s6_addr16; + uint32_t[4] s6_addr32; + + alias s6_addr8 s6_addr; +} + + +const in6_addr IN6ADDR_ANY = { s6_addr8: [0] }; +const in6_addr IN6ADDR_LOOPBACK = { s6_addr8: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1] }; +//alias IN6ADDR_ANY IN6ADDR_ANY_INIT; +//alias IN6ADDR_LOOPBACK IN6ADDR_LOOPBACK_INIT; + +const uint INET_ADDRSTRLEN = 16; +const uint INET6_ADDRSTRLEN = 46; + + +struct sockaddr +{ + int16_t sa_family; + ubyte[14] sa_data; +} + + +struct sockaddr_in +{ + int16_t sin_family = AF_INET; + uint16_t sin_port; + in_addr sin_addr; + ubyte[8] sin_zero; +} + + +struct sockaddr_in6 +{ + int16_t sin6_family = AF_INET6; + uint16_t sin6_port; + uint32_t sin6_flowinfo; + in6_addr sin6_addr; + uint32_t sin6_scope_id; +} + + +struct addrinfo +{ + int32_t ai_flags; + int32_t ai_family; + int32_t ai_socktype; + int32_t ai_protocol; + size_t ai_addrlen; + char* ai_canonname; + sockaddr* ai_addr; + addrinfo* ai_next; +} + + +struct hostent +{ + char* h_name; + char** h_aliases; + int16_t h_addrtype; + int16_t h_length; + char** h_addr_list; + + + char* h_addr() + { + return h_addr_list[0]; + } +} + diff --git a/std/ctype.d b/std/ctype.d index 2e33d67a1..f7bc85812 100644 --- a/std/ctype.d +++ b/std/ctype.d @@ -1,8 +1,26 @@ -// Written by Walter Bright -// Copyright (c) 2001-2004 Digital Mars -// All Rights Reserved -// www.digitalmars.com +/* + * Copyright (C) 2004-2005 by Digital Mars, www.digitalmars.com + * Written by Walter Bright + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, in both source and binary form, subject to the following + * restrictions: + * + * o The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * o Altered source versions must be plainly marked as such, and must not + * be misrepresented as being the original software. + * o This notice may not be removed or altered from any source + * distribution. + */ // Simple ASCII char classification functions diff --git a/std/format.d b/std/format.d index e773ddf5f..da6f126fc 100644 --- a/std/format.d +++ b/std/format.d @@ -731,7 +731,14 @@ unittest assert(s == "hello world! true 57 1000000000x foo"); s = std.string.format(1.67, " %A ", -1.28, float.nan); - assert(s == "1.67 -0X1.47AE147AE147BP+0 nan"); + /* The host C library is used to format floats. + * C99 doesn't specify what the hex digit before the decimal point + * is for %A. + */ + version (linux) + assert(s == "1.67 -0XA.3D70A3D70A3D8P-3 nan"); + else + assert(s == "1.67 -0X1.47AE147AE147BP+0 nan"); s = std.string.format("%x %X", 0x1234AF, 0xAFAFAFAF); assert(s == "1234af AFAFAFAF"); diff --git a/std/moduleinit.d b/std/moduleinit.d index 1edb72df8..db53dea7d 100644 --- a/std/moduleinit.d +++ b/std/moduleinit.d @@ -102,7 +102,8 @@ void _moduleCtor2(ModuleInfo[] mi, int skip) ModuleInfo m = mi[i]; debug printf("\tmodule[%d] = '%p'\n", i, m); - if (!m) continue; + if (!m) + continue; debug printf("\tmodule[%d] = '%.*s'\n", i, m.name); if (m.flags & MIctordone) continue; @@ -171,6 +172,9 @@ extern (C) void _moduleUnitTests() { ModuleInfo m = _moduleinfo_array[i]; + if (!m) + continue; + debug printf("\tmodule[%d] = '%.*s'\n", i, m.name); if (m.unitTest) { diff --git a/std/regexp.d b/std/regexp.d index fa4e42f26..14991dff2 100644 --- a/std/regexp.d +++ b/std/regexp.d @@ -2,7 +2,7 @@ // Regular Expressions /* - * Copyright (C) 2000-2004 by Digital Mars, www.digitalmars.com + * Copyright (C) 2000-2005 by Digital Mars, www.digitalmars.com * Written by Walter Bright * * This software is provided 'as-is', without any express or implied @@ -117,9 +117,9 @@ class RegExp private: - uint src; // current source index in input[] - uint src_start; // starting index for match in input[] - uint p; // position of parser in pattern[] + size_t src; // current source index in input[] + size_t src_start; // starting index for match in input[] + size_t p; // position of parser in pattern[] regmatch_t gmatch; // match for the entire regular expression // (serves as storage for pmatch[0]) @@ -138,8 +138,8 @@ enum : ubyte REend, // end of program REchar, // single character REichar, // single character, case insensitive - REwchar, // single wide character - REiwchar, // single wide character, case insensitive + REdchar, // single UCS character + REidchar, // single wide character, case insensitive REanychar, // any character REanystar, // ".*" REstring, // string of characters @@ -172,7 +172,7 @@ enum : ubyte }; // BUG: should this include '$'? -private int isword(rchar c) { return isalnum(c) || c == '_'; } +private int isword(dchar c) { return isalnum(c) || c == '_'; } private uint inf = ~0u; @@ -185,10 +185,10 @@ public void compile(rchar[] pattern, rchar[] attributes) //printf("RegExp.compile('%.*s', '%.*s')\n", pattern, attributes); this.attributes = 0; - for (uint i = 0; i < attributes.length; i++) + foreach (rchar c; attributes) { REA att; - switch (attributes[i]) + switch (c) { case 'g': att = REA.global; break; case 'i': att = REA.ignoreCase; break; @@ -236,7 +236,8 @@ public void compile(rchar[] pattern, rchar[] attributes) } /******************************************** - * Split string[] into an array of strings, using the regular expression as the separator. + * Split string[] into an array of strings, using the regular + * expression as the separator. * Returns: * array of slices into string[] */ @@ -341,7 +342,7 @@ unittest * -1 no match */ -public int search(rchar[] string) +public int find(rchar[] string) { int i; @@ -353,15 +354,17 @@ public int search(rchar[] string) return i; } +deprecated alias find search; + unittest { - debug(regexp) printf("regexp.search.unittest()\n"); + debug(regexp) printf("regexp.find.unittest()\n"); int i; RegExp r = new RegExp("abc", null); - i = r.search("xabcy"); + i = r.find("xabcy"); assert(i == 1); - i = r.search("cba"); + i = r.find("cba"); assert(i == -1); } @@ -553,7 +556,7 @@ public int test() public int test(char[] string, int startindex) { - rchar firstc; + char firstc; uint si; input = string; @@ -564,7 +567,7 @@ public int test(char[] string, int startindex) { return 0; // fail } - debug(regexp) printProgram(program); + //debug(regexp) printProgram(program); // First character optimization firstc = 0; @@ -598,7 +601,7 @@ public int test(char[] string, int startindex) { pmatch[0].rm_so = si; pmatch[0].rm_eo = src; - debug(regexp) printf("start = %d, end = %d\n", gmatch.rm_so, gmatch.rm_eo); + //debug(regexp) printf("start = %d, end = %d\n", gmatch.rm_so, gmatch.rm_eo); return 1; } // If possible match must start at beginning, we are done @@ -615,7 +618,7 @@ public int test(char[] string, int startindex) } if (si == input.length) break; - debug(regexp) printf("Starting new try: '%.*s'\n", input[si + 1 .. input.length]); + //debug(regexp) printf("Starting new try: '%.*s'\n", input[si + 1 .. input.length]); } return 0; // no match } @@ -633,7 +636,7 @@ int chr(inout uint si, rchar c) void printProgram(ubyte[] prog) { - debug(regexp) + //debug(regexp) { uint pc; uint len; @@ -660,14 +663,14 @@ void printProgram(ubyte[] prog) pc += 1 + char.sizeof; break; - case REwchar: - printf("\tREwchar '%c'\n", *cast(wchar *)&prog[pc + 1]); - pc += 1 + wchar.sizeof; + case REdchar: + printf("\tREdchar '%c'\n", *cast(dchar *)&prog[pc + 1]); + pc += 1 + dchar.sizeof; break; - case REiwchar: - printf("\tREiwchar '%c'\n", *cast(wchar *)&prog[pc + 1]); - pc += 1 + wchar.sizeof; + case REidchar: + printf("\tREidchar '%c'\n", *cast(dchar *)&prog[pc + 1]); + pc += 1 + dchar.sizeof; break; case REanychar: @@ -898,21 +901,21 @@ int trymatch(int pc, int pcend) pc += 1 + char.sizeof; break; - case REwchar: - debug(regexp) printf("\tREwchar '%c', src = '%c'\n", *(cast(wchar *)&program[pc + 1]), input[src]); + case REdchar: + debug(regexp) printf("\tREdchar '%c', src = '%c'\n", *(cast(dchar *)&program[pc + 1]), input[src]); if (src == input.length) goto Lnomatch; - if (*(cast(wchar *)&program[pc + 1]) != input[src]) + if (*(cast(dchar *)&program[pc + 1]) != input[src]) goto Lnomatch; src++; - pc += 1 + wchar.sizeof; + pc += 1 + dchar.sizeof; break; - case REiwchar: - debug(regexp) printf("\tREiwchar '%c', src = '%c'\n", *(cast(wchar *)&program[pc + 1]), input[src]); + case REidchar: + debug(regexp) printf("\tREidchar '%c', src = '%c'\n", *(cast(dchar *)&program[pc + 1]), input[src]); if (src == input.length) goto Lnomatch; - c1 = *(cast(wchar *)&program[pc + 1]); + c1 = *(cast(dchar *)&program[pc + 1]); c2 = input[src]; if (c1 != c2) { @@ -924,7 +927,7 @@ int trymatch(int pc, int pcend) goto Lnomatch; } src++; - pc += 1 + wchar.sizeof; + pc += 1 + dchar.sizeof; break; case REanychar: @@ -1479,7 +1482,7 @@ int parsePiece() p++; if (p == plength) goto Lerr; - if (pattern[p] == '}') // {n,} + if (pattern[p] == /*{*/ '}') // {n,} { m = inf; goto Lnm; } @@ -1494,7 +1497,7 @@ int parsePiece() if (p == plength) goto Lerr; } while (isdigit(pattern[p])); - if (pattern[p] != '}') + if (pattern[p] != /*{*/ '}') goto Lerr; goto Lnm; @@ -1694,10 +1697,10 @@ int parseAtom() break; } } - if (c & ~0xFF) + if (c >= 0x80) { - // Convert to wchar opcode - op = (op == REchar) ? REwchar : REiwchar; + // Convert to dchar opcode + op = (op == REchar) ? REdchar : REidchar; buf.write(op); buf.write(c); } @@ -1927,7 +1930,7 @@ int parseRange() (cast(ushort *)&buf.data[offset])[1] = cast(ushort)r.maxb; if (attributes & REA.ignoreCase) { - // BUG: what about wchar? + // BUG: what about dchar? r.setbitmax(0x7F); for (c = 'a'; c <= 'z'; c++) { @@ -1981,7 +1984,7 @@ body if (p == pattern.length) goto Lretc; c = pattern[p]; - // Note: we are deliberately not allowing wchar letters + // Note: we are deliberately not allowing dchar letters if (!(('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z'))) { Lcerr: @@ -2095,8 +2098,8 @@ void optimize() case REeol: case REchar: case REichar: - case REwchar: - case REiwchar: + case REdchar: + case REidchar: case REstring: case REistring: case REtestbit: @@ -2184,8 +2187,8 @@ int starrchars(Range r, ubyte[] prog) } return 1; - case REwchar: - case REiwchar: + case REdchar: + case REidchar: return 1; case REanychar: @@ -2503,3 +2506,196 @@ private static rchar[] replace3(rchar[] format, rchar[] input, regmatch_t[] pmat } +/**************************************************** + * Search str for regular expression pattern. + * If match, return a RegExp for the match. + * If no match, return null. + */ + +RegExp search(char[] str, char[] pattern, char[] attributes = null) +{ + RegExp r = new RegExp(pattern, attributes); + + if (r.test(str)) + { + } + else + { delete r; + r = null; + } + return r; +} + + +/****************************************************** + * Search str for pattern, replace occurrences with format. + */ + +char[] sub(char[] str, char[] pattern, char[] format, char[] attributes = null) +{ + RegExp r = new RegExp(pattern, attributes); + char[] result = r.replace(str, format); + delete r; + return result; +} + +unittest +{ + debug(regexp) printf("regexp.sub.unittest\n"); + + char[] r = sub("hello", "ll", "ss"); + assert(r == "hesso"); +} + +/******************************************************* + * Search str for pattern, replace occurrences with string + * returned from dg. + */ + +char[] sub(char[] str, char[] pattern, char[] delegate(RegExp) dg, char[] attributes = null) +{ + RegExp r = new RegExp(pattern, attributes); + rchar[] result; + int lastindex; + int offset; + + result = str; + lastindex = 0; + offset = 0; + while (r.test(str, lastindex)) + { + int so = r.pmatch[0].rm_so; + int eo = r.pmatch[0].rm_eo; + + rchar[] replacement = dg(r); + result = replaceSlice(result, result[offset + so .. offset + eo], replacement); + + if (r.attributes & RegExp.REA.global) + { + offset += replacement.length - (eo - so); + + if (lastindex == eo) + lastindex++; // always consume some source + else + lastindex = eo; + } + else + break; + } + delete r; + + return result; +} + +unittest +{ + debug(regexp) printf("regexp.sub.unittest\n"); + + char[] foo(RegExp r) { return "ss"; } + + char[] r = sub("hello", "ll", delegate char[](RegExp r) { return "ss"; }); + assert(r == "hesso"); +} + + +/************************************************* + * Search string[] for match with pattern[]. + * Returns: + * >=0 index of match + * -1 no match + */ + +int find(rchar[] string, char[] pattern, char[] attributes = null) +{ + int i = -1; + + RegExp r = new RegExp(pattern, attributes); + if (r.test(string)) + { + i = r.pmatch[0].rm_so; + } + delete r; + return i; +} + +unittest +{ + debug(regexp) printf("regexp.find.unittest\n"); + + int i; + i = find("xabcy", "abc"); + assert(i == 1); + i = find("cba", "abc"); + assert(i == -1); +} + + + +/************************************************* + * Search string[] for last match with pattern[]. + * Returns: + * >=0 index of match + * -1 no match + */ + +int rfind(rchar[] string, char[] pattern, char[] attributes = null) +{ + int i = -1; + int lastindex = 0; + + RegExp r = new RegExp(pattern, attributes); + while (r.test(string, lastindex)) + { int eo = r.pmatch[0].rm_eo; + i = r.pmatch[0].rm_so; + if (lastindex == eo) + lastindex++; // always consume some source + else + lastindex = eo; + } + delete r; + return i; +} + +unittest +{ + int i; + + debug(regexp) printf("regexp.rfind.unittest\n"); + i = rfind("abcdefcdef", "c"); + assert(i == 6); + i = rfind("abcdefcdef", "cd"); + assert(i == 6); + i = rfind("abcdefcdef", "x"); + assert(i == -1); + i = rfind("abcdefcdef", "xy"); + assert(i == -1); + i = rfind("abcdefcdef", ""); + assert(i == 10); +} + + +/******************************************** + * Split string[] into an array of strings, using the regular + * expression as the separator. + * Returns: + * array of slices into string[] + */ + +char[][] split(char[] string, char[] pattern, char[] attributes = null) +{ + RegExp r = new RegExp(pattern, attributes); + char[][] result = r.split(string); + delete r; + return result; +} + +unittest +{ + debug(regexp) printf("regexp.split.unittest()\n"); + char[][] result; + + result = split("ab", "a*"); + assert(result.length == 2); + assert(result[0] == ""); + assert(result[1] == "b"); +} diff --git a/std/socket.d b/std/socket.d index 397c9ebe2..efd9dce5b 100644 --- a/std/socket.d +++ b/std/socket.d @@ -1,5 +1,5 @@ /* - Copyright (C) 2004 Christopher E. Miller + Copyright (C) 2004-2005 Christopher E. Miller This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages @@ -17,13 +17,17 @@ be misrepresented as being the original software. 3. This notice may not be removed or altered from any source distribution. + + socket.d 1.3 + Jan 2005 + + Thanks to Benjamin Herr for his assistance. */ -// socket.d 1.2 -// Apr 2004 - module std.socket; +private import std.string, std.stdint, std.c.stdlib; + version(linux) { @@ -32,228 +36,68 @@ version(linux) version(Win32) { - typedef uint socket_t = ~0u; -} -else version(BsdSockets) -{ - typedef int socket_t = -1; -} -else -{ - static assert(0); // No socket support yet -} -const socket_t INVALID_SOCKET = socket_t.init; -const int SOCKET_ERROR = -1; - - -private: - -import std.string, std.stdint, std.c.stdlib; - - -version(Win32) -{ - import std.c.windows.windows; + private import std.c.windows.windows, std.c.windows.winsock; + private alias std.c.windows.winsock.timeval _ctimeval; + + typedef SOCKET socket_t = INVALID_SOCKET; + private const int _SOCKET_ERROR = SOCKET_ERROR; - extern(Windows) + private int _lasterr() { - const int WSADESCRIPTION_LEN = 256; - const int WSASYS_STATUS_LEN = 128; - - struct WSADATA - { - WORD wVersion; - WORD wHighVersion; - char szDescription[WSADESCRIPTION_LEN+1]; - char szSystemStatus[WSASYS_STATUS_LEN+1]; - ushort iMaxSockets; - ushort iMaxUdpDg; - char* lpVendorInfo; - } - alias WSADATA* LPWSADATA; - - - const int IOCPARM_MASK = 0x7f; - const int IOC_IN = cast(int)0x80000000; - const int FIONBIO = cast(int)(IOC_IN | ((uint.sizeof & IOCPARM_MASK) << 16) | (102 << 8) | 126); - const int SOL_SOCKET = 0xFFFF; - const int SO_TYPE = 0x1008; - - - int WSAStartup(WORD wVersionRequested, LPWSADATA lpWSAData); - int WSACleanup(); - socket_t socket(int af, int type, int protocol); - int ioctlsocket(socket_t s, int cmd, uint* argp); - int getsockopt(socket_t s, int level, int optname, char* optval, int* optlen); - uint inet_addr(char* cp); - int bind(socket_t s, sockaddr* name, int namelen); - int connect(socket_t s, sockaddr* name, int namelen); - int listen(socket_t s, int backlog); - socket_t accept(socket_t s, sockaddr* addr, int* addrlen); - int closesocket(socket_t s); - int shutdown(socket_t s, int how); - int getpeername(socket_t s, sockaddr* name, int* namelen); - int getsockname(socket_t s, sockaddr* name, int* namelen); - int send(socket_t s, void* buf, int len, int flags); - int sendto(socket_t s, void* buf, int len, int flags, sockaddr* to, int tolen); - int recv(socket_t s, void* buf, int len, int flags); - int recvfrom(socket_t s, void* buf, int len, int flags, sockaddr* from, int* fromlen); - int select(int nfds, fd_set* readfds, fd_set* writefds, fd_set* errorfds, timeval* timeout); - //int __WSAFDIsSet(socket_t s, fd_set* fds); - int getsockopt(socket_t s, int level, int optname, void* optval, int* optlen); - int setsockopt(socket_t s, int level, int optname, void* optval, int optlen); - char* inet_ntoa(uint ina); - hostent* gethostbyname(char* name); - hostent* gethostbyaddr(void* addr, int len, int type); - - - const int WSAEWOULDBLOCK = 10035; - const int WSAEINTR = 10004; - - int WSAGetLastError(); + return WSAGetLastError(); } } else version(BsdSockets) { - extern(C) + version(linux) { - const int F_GETFL = 3; - const int F_SETFL = 4; - const int O_NONBLOCK = 0x4000; - const int SOL_SOCKET = 0xFFFF; - const int SO_TYPE = 0x1008; - - - socket_t socket(int af, int type, int protocol); - int fcntl(socket_t s, int f, ...); - int getsockopt(socket_t s, int level, int optname, char* optval, int* optlen); - uint inet_addr(char* cp); - int bind(socket_t s, sockaddr* name, int namelen); - int connect(socket_t s, sockaddr* name, int namelen); - int listen(socket_t s, int backlog); - socket_t accept(socket_t s, sockaddr* addr, int* addrlen); - int close(socket_t s); - int shutdown(socket_t s, int how); - int getpeername(socket_t s, sockaddr* name, int* namelen); - int getsockname(socket_t s, sockaddr* name, int* namelen); - int send(socket_t s, void* buf, int len, int flags); - int sendto(socket_t s, void* buf, int len, int flags, sockaddr* to, int tolen); - int recv(socket_t s, void* buf, int len, int flags); - int recvfrom(socket_t s, void* buf, int len, int flags, sockaddr* from, int* fromlen); - int select(int nfds, fd_set* readfds, fd_set* writefds, fd_set* errorfds, timeval* timeout); - int getsockopt(socket_t s, int level, int optname, void* optval, int* optlen); - int setsockopt(socket_t s, int level, int optname, void* optval, int optlen); - char* inet_ntoa(uint ina); - hostent* gethostbyname(char* name); - hostent* gethostbyaddr(void* addr, int len, int type); - - - const int EINTR = 4; - version(linux) - { - const int EINPROGRESS = 115; //EWOULDBLOCK - - - import std.c.linux.linux; //for getErrno - } - else - { - static assert(0); - } - } -} - - -//transparent -struct fd_set -{ -} - - -struct sockaddr -{ - ushort sa_family; - char[14] sa_data = [0]; -} - - -struct hostent -{ - char* h_name; - char** h_aliases; - version(Win32) - { - short h_addrtype; - short h_length; - } - else version(BsdSockets) - { - int h_addrtype; - int h_length; - } - char** h_addr_list; - - - char* h_addr() - { - return h_addr_list[0]; - } -} - - -version(BigEndian) -{ - uint16_t htons(uint16_t x) - { - return x; + private import std.c.linux.linux, std.c.linux.socket; + private alias std.c.linux.linux.timeval _ctimeval; } - - uint32_t htonl(uint32_t x) - { - return x; - } -} -else version(LittleEndian) -{ - import std.intrinsic; + typedef int32_t socket_t = -1; + private const int _SOCKET_ERROR = -1; - uint16_t htons(uint16_t x) + private int _lasterr() { - return (x >> 8) | (x << 8); - } - - - uint32_t htonl(uint32_t x) - { - return bswap(x); + return getErrno(); } } else { - static assert(0); + static assert(0); // No socket support yet. } -uint16_t ntohs(uint16_t x) -{ - return htons(x); -} - - -uint32_t ntohl(uint32_t x) -{ - return htonl(x); -} - - -public: class SocketException: Exception { - this(char[] msg) + int errorCode; // Platform-specific error code. + + + this(char[] msg, int err = 0) { + errorCode = err; + + version(linux) + { + if(errorCode > 0) + { + char* cs; + size_t len; + + cs = strerror(errorCode); + len = strlen(cs); + + if(cs[len - 1] == '\n') + len--; + if(cs[len - 1] == '\r') + len--; + msg = msg ~ ": " ~ cs[0 .. len]; + } + } + super(msg); } } @@ -264,8 +108,13 @@ static this() version(Win32) { WSADATA wd; - if(WSAStartup(0x0101, &wd)) - throw new SocketException("Unable to initialize socket library."); + + // Winsock will still load if an older version is present. + // The version is just a request. + int val; + val = WSAStartup(0x2020, &wd); + if(val) // Request Winsock 2.2 for IPv6. + throw new SocketException("Unable to initialize socket library", val); } } @@ -279,109 +128,221 @@ static ~this() } -version(Win32) +enum AddressFamily: int { - enum AddressFamily: int - { - UNSPEC = 0, - UNIX = 1, - INET = 2, - IPX = 6, - APPLETALK = 16, - //INET6 = ? // Need Windows XP ? - } -} -else version(BsdSockets) -{ - enum AddressFamily: int - { - UNSPEC = 0, - UNIX = 1, - INET = 2, - IPX = 4, - APPLETALK = 5, - //INET6 = 10, - } + UNSPEC = AF_UNSPEC, + UNIX = AF_UNIX, + INET = AF_INET, + IPX = AF_IPX, + APPLETALK = AF_APPLETALK, + INET6 = AF_INET6, } enum SocketType: int { - STREAM = 1, - DGRAM = 2, - RAW = 3, - RDM = 4, - SEQPACKET = 5, + STREAM = SOCK_STREAM, + DGRAM = SOCK_DGRAM, + RAW = SOCK_RAW, + RDM = SOCK_RDM, + SEQPACKET = SOCK_SEQPACKET, } enum ProtocolType: int { - IP = 0, - ICMP = 1, - IGMP = 2, - GGP = 3, - TCP = 6, - PUP = 12, - UDP = 17, - IDP = 22, + IP = IPPROTO_IP, + ICMP = IPPROTO_ICMP, + IGMP = IPPROTO_IGMP, + GGP = IPPROTO_GGP, + TCP = IPPROTO_TCP, + PUP = IPPROTO_PUP, + UDP = IPPROTO_UDP, + IDP = IPPROTO_IDP, + IPV6 = IPPROTO_IPV6, } -class AddressException: Exception +class Protocol { - this(char[] msg) + ProtocolType type; + char[] name; + char[][] aliases; + + + void populate(protoent* proto) { - super(msg); + type = cast(ProtocolType)proto.p_proto; + name = std.string.toString(proto.p_name).dup; + + int i; + for(i = 0;; i++) + { + if(!proto.p_aliases[i]) + break; + } + + if(i) + { + aliases = new char[][i]; + for(i = 0; i != aliases.length; i++) + { + aliases[i] = std.string.toString(proto.p_aliases[i]).dup; + } + } + else + { + aliases = null; + } + } + + + bit getProtocolByName(char[] name) + { + protoent* proto; + proto = getprotobyname(toStringz(name)); + if(!proto) + return false; + populate(proto); + return true; + } + + + // Same as getprotobynumber(). + bit getProtocolByType(ProtocolType type) + { + protoent* proto; + proto = getprotobynumber(type); + if(!proto) + return false; + populate(proto); + return true; } } -abstract class Address +unittest { - protected sockaddr* name(); - protected int nameLen(); - AddressFamily addressFamily(); - char[] toString(); + Protocol proto = new Protocol; + assert(proto.getProtocolByType(ProtocolType.TCP)); + printf("About protocol TCP:\n\tName: %.*s\n", proto.name); + foreach(char[] s; proto.aliases) + { + printf("\tAlias: %.*s\n", s); + } } -class UnknownAddress: Address +class Service { - protected: - sockaddr sa; + char[] name; + char[][] aliases; + ushort port; + char[] protocolName; - sockaddr* name() + void populate(servent* serv) { - return &sa; + name = std.string.toString(serv.s_name).dup; + port = ntohs(serv.s_port); + protocolName = std.string.toString(serv.s_proto).dup; + + int i; + for(i = 0;; i++) + { + if(!serv.s_aliases[i]) + break; + } + + if(i) + { + aliases = new char[][i]; + for(i = 0; i != aliases.length; i++) + { + aliases[i] = std.string.toString(serv.s_aliases[i]).dup; + } + } + else + { + aliases = null; + } } - int nameLen() + bit getServiceByName(char[] name, char[] protocolName) { - return sa.sizeof; + servent* serv; + serv = getservbyname(toStringz(name), toStringz(protocolName)); + if(!serv) + return false; + populate(serv); + return true; } - public: - AddressFamily addressFamily() + // Any protocol name will be matched. + bit getServiceByName(char[] name) { - return cast(AddressFamily)sa.sa_family; + servent* serv; + serv = getservbyname(toStringz(name), null); + if(!serv) + return false; + populate(serv); + return true; } - char[] toString() + bit getServiceByPort(ushort port, char[] protocolName) { - return "Unknown"; + servent* serv; + serv = getservbyport(port, toStringz(protocolName)); + if(!serv) + return false; + populate(serv); + return true; + } + + + // Any protocol name will be matched. + bit getServiceByPort(ushort port) + { + servent* serv; + serv = getservbyport(port, null); + if(!serv) + return false; + populate(serv); + return true; + } +} + + +unittest +{ + Service serv = new Service; + if(serv.getServiceByName("epmap", "tcp")) + { + printf("About service epmap:\n\tService: %.*s\n\tPort: %d\n\tProtocol: %.*s\n", + serv.name, serv.port, serv.protocolName); + foreach(char[] s; serv.aliases) + { + printf("\tAlias: %.*s\n", s); + } + } + else + { + printf("No service for epmap.\n"); } } class HostException: Exception { - this(char[] msg) + int errorCode; + + + this(char[] msg, int err = 0) { + errorCode = err; super(msg); } } @@ -391,13 +352,13 @@ class InternetHost { char[] name; char[][] aliases; - uint[] addrList; + uint32_t[] addrList; - protected void validHostent(hostent* he) + void validHostent(hostent* he) { if(he.h_addrtype != cast(int)AddressFamily.INET || he.h_length != 4) - throw new HostException("Address family mismatch."); + throw new HostException("Address family mismatch", _lasterr()); } @@ -406,7 +367,7 @@ class InternetHost int i; char* p; - name = std.string.toString(he.h_name); + name = std.string.toString(he.h_name).dup; for(i = 0;; i++) { @@ -420,7 +381,7 @@ class InternetHost aliases = new char[][i]; for(i = 0; i != aliases.length; i++) { - aliases[i] = std.string.toString(he.h_aliases[i]); + aliases[i] = std.string.toString(he.h_aliases[i]).dup; } } else @@ -437,10 +398,10 @@ class InternetHost if(i) { - addrList = new uint[i]; + addrList = new uint32_t[i]; for(i = 0; i != addrList.length; i++) { - addrList[i] = ntohl(*(cast(uint*)he.h_addr_list[i])); + addrList[i] = ntohl(*(cast(uint32_t*)he.h_addr_list[i])); } } else @@ -511,16 +472,59 @@ unittest } +class AddressException: Exception +{ + this(char[] msg) + { + super(msg); + } +} + + +abstract class Address +{ + protected sockaddr* name(); + protected int nameLen(); + AddressFamily addressFamily(); + char[] toString(); +} + + +class UnknownAddress: Address +{ + protected: + sockaddr sa; + + + sockaddr* name() + { + return &sa; + } + + + int nameLen() + { + return sa.sizeof; + } + + + public: + AddressFamily addressFamily() + { + return cast(AddressFamily)sa.sa_family; + } + + + char[] toString() + { + return "Unknown"; + } +} + + class InternetAddress: Address { protected: - struct sockaddr_in - { - ushort sin_family = cast(ushort)AddressFamily.INET; - ushort sin_port; - uint sin_addr; //in_addr - char[8] sin_zero = [0]; - } sockaddr_in sin; @@ -542,14 +546,14 @@ class InternetAddress: Address public: - const uint ADDR_ANY = 0; - const uint ADDR_NONE = cast(uint)-1; + const uint ADDR_ANY = INADDR_ANY; + const uint ADDR_NONE = INADDR_NONE; const ushort PORT_ANY = 0; AddressFamily addressFamily() { - return AddressFamily.INET; + return cast(AddressFamily)AddressFamily.INET; } @@ -561,7 +565,7 @@ class InternetAddress: Address uint addr() { - return ntohl(sin.sin_addr); + return ntohl(sin.sin_addr.s_addr); } @@ -574,24 +578,25 @@ class InternetAddress: Address { InternetHost ih = new InternetHost; if(!ih.getHostByName(addr)) - throw new AddressException("Invalid internet address."); + //throw new AddressException("Invalid internet address"); + throw new AddressException("Unable to resolve host '" ~ addr ~ "'"); uiaddr = ih.addrList[0]; } - sin.sin_addr = htonl(uiaddr); + sin.sin_addr.s_addr = htonl(uiaddr); sin.sin_port = htons(port); } this(uint addr, ushort port) { - sin.sin_addr = htonl(addr); + sin.sin_addr.s_addr = htonl(addr); sin.sin_port = htons(port); } this(ushort port) { - sin.sin_addr = 0; //any, "0.0.0.0" + sin.sin_addr.s_addr = 0; //any, "0.0.0.0" sin.sin_port = htons(port); } @@ -632,31 +637,32 @@ unittest class SocketAcceptException: SocketException { - this(char[] msg) + this(char[] msg, int err = 0) { - super(msg); + super(msg, err); } } enum SocketShutdown: int { - RECEIVE = 0, - SEND = 1, - BOTH = 2, + RECEIVE = SD_RECEIVE, + SEND = SD_SEND, + BOTH = SD_RECEIVE, } enum SocketFlags: int { - NONE = 0, - OOB = 0x1, //out of band - PEEK = 0x02, //only for receiving - DONTROUTE = 0x04, //only for sending + NONE = 0, + + OOB = MSG_OOB, //out of band + PEEK = MSG_PEEK, //only for receiving + DONTROUTE = MSG_DONTROUTE, //only for sending } -struct timeval +extern(C) struct timeval { // D interface int seconds; @@ -675,7 +681,7 @@ struct timeval class SocketSet { private: - uint nbytes; //Win32: excludes uint.sizeof "count" + uint nbytes; // Win32: excludes uint.sizeof "count". byte* buf; @@ -698,33 +704,24 @@ class SocketSet return cast(socket_t*)(buf + uint.sizeof); } } - else version(linux) + else version(BsdSockets) { - import std.intrinsic; + int maxfd = -1; - uint nfdbits; - - - uint fdelt(socket_t s) + socket_t* first() { - return cast(uint)s / nfdbits; - } - - - uint fdmask(socket_t s) - { - return 1 << cast(uint)s % nfdbits; - } - - - uint* first() - { - return cast(uint*)buf; + return cast(socket_t*)buf; } } + fd_set* _fd_set() + { + return cast(fd_set*)buf; + } + + public: this(uint max) { @@ -734,37 +731,19 @@ class SocketSet buf = new byte[nbytes + uint.sizeof]; count = 0; } - else version(linux) + else version(BsdSockets) { - if(max <= 32) - nbytes = 32 * uint.sizeof; - else - nbytes = max * uint.sizeof; - buf = new byte[nbytes]; - nfdbits = nbytes * 8; - //clear(); //new initializes to 0 - } - else - { - static assert(0); + nbytes = max / NFDBITS * socket_t.sizeof; + if(max % NFDBITS) + nbytes += socket_t.sizeof; + buf = new byte[nbytes]; // new initializes to 0. } } this() { - version(Win32) - { - this(64); - } - else version(linux) - { - this(32); - } - else - { - static assert(0); - } + this(FD_SETSIZE); } @@ -774,40 +753,35 @@ class SocketSet { count = 0; } - else version(linux) + else version(BsdSockets) { + maxfd = -1; buf[0 .. nbytes] = 0; } - else - { - static assert(0); - } } void add(socket_t s) in { + // Make sure too many sockets don't get added. version(Win32) { - assert(count < max); //added too many sockets; specify a higher max in the constructor + assert(count < max); + } + else version(BsdSockets) + { + assert(FDELT(s) < nbytes / socket_t.sizeof); } } body { - version(Win32) + FD_SET(s, _fd_set); + + version(BsdSockets) { - uint c = count; - first[c] = s; - count = c + 1; - } - else version(linux) - { - bts(cast(uint*)&first[fdelt(s)], cast(uint)s % nfdbits); - } - else - { - static assert(0); + if(s > maxfd) + maxfd = s; } } @@ -820,35 +794,7 @@ class SocketSet void remove(socket_t s) { - version(Win32) - { - uint c = count; - socket_t* start = first; - socket_t* stop = start + c; - - for(; start != stop; start++) - { - if(*start == s) - goto found; - } - return; //not found - - found: - for(++start; start != stop; start++) - { - *(start - 1) = *start; - } - - count = c - 1; - } - else version(linux) - { - btr(cast(uint*)&first[fdelt(s)], cast(uint)s % nfdbits); - } - else - { - static assert(0); - } + FD_CLR(s, _fd_set); } @@ -860,26 +806,7 @@ class SocketSet int isSet(socket_t s) { - version(Win32) - { - socket_t* start = first; - socket_t* stop = start + count; - - for(; start != stop; start++) - { - if(*start == s) - return true; - } - return false; - } - else version(linux) - { - return bt(cast(uint*)&first[fdelt(s)], cast(uint)s % nfdbits); - } - else - { - static assert(0); - } + return FD_ISSET(s, _fd_set); } @@ -889,33 +816,72 @@ class SocketSet } - uint max() //max sockets that can be added, like FD_SETSIZE + // Max sockets that can be added, like FD_SETSIZE. + uint max() { - return nbytes / socket_t.sizeof; + version(Win32) + { + return nbytes / socket_t.sizeof; + } + else version(BsdSockets) + { + return nbytes / socket_t.sizeof * NFDBITS; + } + else + { + static assert(0); + } } fd_set* toFd_set() { - return cast(fd_set*)buf; + return _fd_set; + } + + + int selectn() + { + version(Win32) + { + return 0; + } + else version(BsdSockets) + { + return maxfd + 1; + } } } enum SocketOptionLevel: int { - SOCKET = 0xFFFF, //different source 1 - IP = 0, - TCP = 6, - UDP = 17, + SOCKET = SOL_SOCKET, + IP = ProtocolType.IP, + ICMP = ProtocolType.ICMP, + IGMP = ProtocolType.IGMP, + GGP = ProtocolType.GGP, + TCP = ProtocolType.TCP, + PUP = ProtocolType.PUP, + UDP = ProtocolType.UDP, + IDP = ProtocolType.IDP, + IPV6 = ProtocolType.IPV6, } -struct linger +extern(C) struct linger { // D interface - ushort on; - ushort time; + version(Win32) + { + uint16_t on; + uint16_t time; + } + else version(BsdSockets) + { + int32_t on; + int32_t time; + } // C interface deprecated @@ -926,45 +892,26 @@ struct linger } -version(Win32) +enum SocketOption: int { - enum SocketOption: int - { - DEBUG = 0x1, - BROADCAST = 0x20, - REUSEADDR = 0x4, - LINGER = 0x80, - OOBINLINE = 0x100, - SNDBUF = 0x1001, - RCVBUF = 0x1002, - KEEPALIVE = 0x8, - DONTROUTE = 0x10, - - // SocketOptionLevel.TCP: - TCP_NODELAY = 1, - } -} -else version(linux) -{ - enum SocketOption: int - { - DEBUG = 1, - BROADCAST = 6, - REUSEADDR = 2, - LINGER = 13, - OOBINLINE = 10, - SNDBUF = 7, - RCVBUF = 8, - ACCEPTCONN = 30, - DONTROUTE = 5, - - // SocketOptionLevel.TCP: - TCP_NODELAY = 1, - } -} -else -{ - static assert(0); + DEBUG = SO_DEBUG, + BROADCAST = SO_BROADCAST, + REUSEADDR = SO_REUSEADDR, + LINGER = SO_LINGER, + OOBINLINE = SO_OOBINLINE, + SNDBUF = SO_SNDBUF, + RCVBUF = SO_RCVBUF, + DONTROUTE = SO_DONTROUTE, + + // SocketOptionLevel.TCP: + TCP_NODELAY = .TCP_NODELAY, + + // SocketOptionLevel.IPV6: + IPV6_UNICAST_HOPS = .IPV6_UNICAST_HOPS, + IPV6_MULTICAST_IF = .IPV6_MULTICAST_IF, + IPV6_MULTICAST_LOOP = .IPV6_MULTICAST_LOOP, + IPV6_JOIN_GROUP = .IPV6_JOIN_GROUP, + IPV6_LEAVE_GROUP = .IPV6_LEAVE_GROUP, } @@ -978,18 +925,18 @@ class Socket bit _blocking = false; - this(socket_t sock) + // For use with accepting(). + protected this() { - this.sock = sock; } public: this(AddressFamily af, SocketType type, ProtocolType protocol) { - sock = socket(af, type, protocol); - if(sock == sock.init) - throw new SocketException("Unable to create socket."); + sock = cast(socket_t)socket(af, type, protocol); + if(sock == socket_t.init) + throw new SocketException("Unable to create socket", _lasterr()); _family = af; } @@ -1002,27 +949,30 @@ class Socket } + this(AddressFamily af, SocketType type, char[] protocolName) + { + protoent* proto; + proto = getprotobyname(toStringz(protocolName)); + if(!proto) + throw new SocketException("Unable to find the protocol", _lasterr()); + this(af, type, cast(ProtocolType)proto.p_proto); + } + + ~this() { close(); } - //get underlying socket handle - socket_t handle() + // Get underlying socket handle. + socket_t handle() // getter { return sock; } - override char[] toString() - { - return "Socket"; - } - - - //getter - bit blocking() + bit blocking() // getter { version(Win32) { @@ -1035,67 +985,71 @@ class Socket } - //setter - void blocking(bit byes) + void blocking(bit byes) // setter { version(Win32) { uint num = !byes; - if(SOCKET_ERROR == ioctlsocket(sock, FIONBIO, &num)) + if(_SOCKET_ERROR == ioctlsocket(sock, FIONBIO, &num)) goto err; _blocking = byes; } else version(BsdSockets) { - int x = fcntl(handle, F_GETFL, 0); + int x = fcntl(sock, F_GETFL, 0); + if(-1 == x) + goto err; if(byes) x &= ~O_NONBLOCK; else x |= O_NONBLOCK; - if(SOCKET_ERROR == fcntl(sock, F_SETFL, x)) + if(-1 == fcntl(sock, F_SETFL, x)) goto err; } - return; //success + return; // Success. err: - throw new SocketException("Unable to set socket blocking."); + throw new SocketException("Unable to set socket blocking", _lasterr()); } - AddressFamily addressFamily() + AddressFamily addressFamily() // getter { return _family; } - bit isAlive() + bit isAlive() // getter { int type, typesize = type.sizeof; - return !getsockopt(sock, SOL_SOCKET, SO_TYPE, cast(char*)type, &typesize); + return !getsockopt(sock, SOL_SOCKET, SO_TYPE, cast(char*)&type, &typesize); } void bind(Address addr) { - if(SOCKET_ERROR == .bind(sock, addr.name(), addr.nameLen())) - throw new SocketException("Unable to bind socket."); + if(_SOCKET_ERROR == .bind(sock, addr.name(), addr.nameLen())) + throw new SocketException("Unable to bind socket", _lasterr()); } void connect(Address to) { - if(SOCKET_ERROR == .connect(sock, to.name(), to.nameLen())) + if(_SOCKET_ERROR == .connect(sock, to.name(), to.nameLen())) { + int err; + err = _lasterr(); + if(!blocking) { version(Win32) { - if(WSAEWOULDBLOCK == WSAGetLastError()) + if(WSAEWOULDBLOCK == err) return; } else version(linux) { - if(EINPROGRESS == getErrno()) + if(EINPROGRESS == err) return; } else @@ -1103,7 +1057,7 @@ class Socket static assert(0); } } - throw new SocketException("Unable to connect socket."); + throw new SocketException("Unable to connect socket", err); } } @@ -1111,20 +1065,45 @@ class Socket //need to bind() first void listen(int backlog) { - if(SOCKET_ERROR == .listen(sock, backlog)) - throw new SocketException("Unable to listen on socket."); + if(_SOCKET_ERROR == .listen(sock, backlog)) + throw new SocketException("Unable to listen on socket", _lasterr()); + } + + + // Override to use a derived class. + // The returned socket's handle must not be set. + protected Socket accepting() + { + return new Socket; } Socket accept() { - socket_t newsock = .accept(sock, null, null); - if(INVALID_SOCKET == newsock) - throw new SocketAcceptException("Unable to accept socket connection."); - Socket newSocket = new Socket(newsock); - version(Win32) - newSocket._blocking = _blocking; //inherits blocking mode - newSocket._family = _family; //same family + socket_t newsock; + //newsock = cast(socket_t).accept(sock, null, null); // DMD 0.101 error: found '(' when expecting ';' following 'statement + alias .accept topaccept; + newsock = cast(socket_t)topaccept(sock, null, null); + if(socket_t.init == newsock) + throw new SocketAcceptException("Unable to accept socket connection", _lasterr()); + + Socket newSocket; + try + { + newSocket = accepting(); + assert(newSocket.sock == socket_t.init); + + newSocket.sock = newsock; + version(Win32) + newSocket._blocking = _blocking; //inherits blocking mode + newSocket._family = _family; //same family + } + catch(Object o) + { + _close(newsock); + throw o; + } + return newSocket; } @@ -1135,9 +1114,7 @@ class Socket } - //calling shutdown() before this is recommended - //for connection-oriented sockets - void close() + private static void _close(socket_t sock) { version(Win32) { @@ -1147,7 +1124,15 @@ class Socket { .close(sock); } - sock = sock.init; + } + + + //calling shutdown() before this is recommended + //for connection-oriented sockets + void close() + { + _close(sock); + sock = socket_t.init; } @@ -1156,7 +1141,7 @@ class Socket Address result; switch(_family) { - case AddressFamily.INET: + case cast(AddressFamily)AddressFamily.INET: result = new InternetAddress; break; @@ -1167,12 +1152,22 @@ class Socket } + // Returns the local machine's host name. Idea from mango. + static char[] hostName() // getter + { + char[256] result; // Host names are limited to 255 chars. + if(_SOCKET_ERROR == .gethostname(result, result.length)) + throw new SocketException("Unable to obtain host name", _lasterr()); + return std.string.toString(cast(char*)result).dup; + } + + Address remoteAddress() { Address addr = newFamilyObject(); int nameLen = addr.nameLen(); - if(SOCKET_ERROR == .getpeername(sock, addr.name(), &nameLen)) - throw new SocketException("Unable to obtain remote socket address."); + if(_SOCKET_ERROR == .getpeername(sock, addr.name(), &nameLen)) + throw new SocketException("Unable to obtain remote socket address", _lasterr()); assert(addr.addressFamily() == _family); return addr; } @@ -1182,14 +1177,14 @@ class Socket { Address addr = newFamilyObject(); int nameLen = addr.nameLen(); - if(SOCKET_ERROR == .getsockname(sock, addr.name(), &nameLen)) - throw new SocketException("Unable to obtain local socket address."); + if(_SOCKET_ERROR == .getsockname(sock, addr.name(), &nameLen)) + throw new SocketException("Unable to obtain local socket address", _lasterr()); assert(addr.addressFamily() == _family); return addr; } - const int ERROR = SOCKET_ERROR; + const int ERROR = _SOCKET_ERROR; //returns number of bytes actually sent, or -1 on error @@ -1292,30 +1287,44 @@ class Socket int getOption(SocketOptionLevel level, SocketOption option, void[] result) { int len = result.length; - if(SOCKET_ERROR == .getsockopt(sock, cast(int)level, cast(int)option, result, &len)) - throw new SocketException("Unable to get socket option."); + if(_SOCKET_ERROR == .getsockopt(sock, cast(int)level, cast(int)option, result, &len)) + throw new SocketException("Unable to get socket option", _lasterr()); return len; } // Common case for integer and boolean options. - int getOption(SocketOptionLevel level, SocketOption option, out int result) + int getOption(SocketOptionLevel level, SocketOption option, out int32_t result) { - return getOption(level, option, (&result)[0 .. int.sizeof]); + return getOption(level, option, (&result)[0 .. 1]); + } + + + int getOption(SocketOptionLevel level, SocketOption option, out linger result) + { + //return getOption(cast(SocketOptionLevel)SocketOptionLevel.SOCKET, SocketOption.LINGER, (&result)[0 .. 1]); + return getOption(level, option, (&result)[0 .. 1]); } void setOption(SocketOptionLevel level, SocketOption option, void[] value) { - if(SOCKET_ERROR == .setsockopt(sock, cast(int)level, cast(int)option, value, value.length)) - throw new SocketException("Unable to set socket option."); + if(_SOCKET_ERROR == .setsockopt(sock, cast(int)level, cast(int)option, value, value.length)) + throw new SocketException("Unable to set socket option", _lasterr()); } // Common case for integer and boolean options. - void setOption(SocketOptionLevel level, SocketOption option, int value) + void setOption(SocketOptionLevel level, SocketOption option, int32_t value) { - setOption(level, option, (&value)[0 .. int.sizeof]); + setOption(level, option, (&value)[0 .. 1]); + } + + + void setOption(SocketOptionLevel level, SocketOption option, linger value) + { + //setOption(cast(SocketOptionLevel)SocketOptionLevel.SOCKET, SocketOption.LINGER, (&value)[0 .. 1]); + setOption(level, option, (&value)[0 .. 1]); } @@ -1341,31 +1350,64 @@ class Socket body { fd_set* fr, fw, fe; + int n = 0; version(Win32) { - //Windows has a problem with empty fd_set's that aren't null + // Windows has a problem with empty fd_set`s that aren't null. fr = (checkRead && checkRead.count()) ? checkRead.toFd_set() : null; fw = (checkWrite && checkWrite.count()) ? checkWrite.toFd_set() : null; fe = (checkError && checkError.count()) ? checkError.toFd_set() : null; } else { - fr = checkRead ? checkRead.toFd_set() : null; - fw = checkWrite ? checkWrite.toFd_set() : null; - fe = checkError ? checkError.toFd_set() : null; + if(checkRead) + { + fr = checkRead.toFd_set(); + n = checkRead.selectn(); + } + else + { + fr = null; + } + + if(checkWrite) + { + fw = checkWrite.toFd_set(); + int _n; + _n = checkWrite.selectn(); + if(_n > n) + n = _n; + } + else + { + fw = null; + } + + if(checkError) + { + fe = checkError.toFd_set(); + int _n; + _n = checkError.selectn(); + if(_n > n) + n = _n; + } + else + { + fe = null; + } } - int result = .select(cast(int)(socket_t.max - 1), fr, fw, fe, tv); + int result = .select(n, fr, fw, fe, cast(_ctimeval*)tv); version(Win32) { - if(SOCKET_ERROR == result && WSAGetLastError() == WSAEINTR) + if(_SOCKET_ERROR == result && WSAGetLastError() == WSAEINTR) return -1; } else version(linux) { - if(SOCKET_ERROR == result && getErrno() == EINTR) + if(_SOCKET_ERROR == result && getErrno() == EINTR) return -1; } else @@ -1373,8 +1415,8 @@ class Socket static assert(0); } - if(SOCKET_ERROR == result) - throw new SocketException("Socket select error."); + if(_SOCKET_ERROR == result) + throw new SocketException("Socket select error", _lasterr()); return result; } @@ -1408,16 +1450,22 @@ class Socket class TcpSocket: Socket { + this(AddressFamily family) + { + super(family, SocketType.STREAM, ProtocolType.TCP); + } + + this() { - super(AddressFamily.INET, SocketType.STREAM, ProtocolType.TCP); + this(cast(AddressFamily)AddressFamily.INET); } //shortcut - this(InternetAddress connectTo) + this(Address connectTo) { - this(); + this(connectTo.addressFamily()); connect(connectTo); } } @@ -1425,9 +1473,15 @@ class TcpSocket: Socket class UdpSocket: Socket { + this(AddressFamily family) + { + super(family, SocketType.DGRAM, ProtocolType.UDP); + } + + this() { - super(AddressFamily.INET, SocketType.DGRAM, ProtocolType.UDP); + this(cast(AddressFamily)AddressFamily.INET); } } diff --git a/std/string.d b/std/string.d index dbec30dfe..2da0fd6dd 100644 --- a/std/string.d +++ b/std/string.d @@ -893,33 +893,66 @@ unittest /******************************************** - * Capitalize first character of string. + * Capitalize first character of string, convert rest of string + * to lower case. */ char[] capitalize(char[] s) { - if (s.length) - { - char c = s[0]; - if ('a' <= c && c <= 'z') - { char[] r = new char[s.length]; - r[] = s; - s = r; - s[0] = c - (cast(char)'a' - 'A'); + int changed; + int i; + char[] r = s; + + changed = 0; + + foreach (size_t i, dchar c; s) + { dchar c2; + + if (i == 0) + { + c2 = std.uni.toUniUpper(c); + if (c != c2) + { + changed = 1; + r = null; + } } + else + { + c2 = std.uni.toUniLower(c); + if (c != c2) + { + if (!changed) + { changed = 1; + r = s[0 .. i].dup; + } + } + } + if (changed) + std.utf.encode(r, c2); } - return s; + return r; } + unittest { - debug(string) printf("string.capitalize.unittest\n"); + debug(string) printf("string.toupper.capitalize\n"); - char[] s1 = "foL"; + char[] s1 = "FoL"; char[] s2; s2 = capitalize(s1); - assert(cmp(s2, "FoL") == 0); + assert(cmp(s2, "Fol") == 0); + assert(s2 !== s1); + + s2 = capitalize(s1[0 .. 2]); + assert(cmp(s2, "Fo") == 0); + assert(s2.ptr == s1.ptr); + + s1 = "fOl"; + s2 = capitalize(s1); + assert(cmp(s2, "Fol") == 0); assert(s2 !== s1); } @@ -951,7 +984,7 @@ char[] capwords(char[] s) case '\v': if (inword) { - r ~= s[istart .. i]; + r ~= capitalize(s[istart .. i]); inword = 0; } break; @@ -969,35 +1002,7 @@ char[] capwords(char[] s) } if (inword) { - r ~= s[istart .. i]; - } - - // Go back through r and capitalize the words - inword = 0; - for (i = 0; i < r.length; i++) - { - char c = r[i]; - - if (c >= 'A' && c <= 'Z') - { - if (inword == 1) - { - c += cast(char)'a' - 'A'; - r[i] = c; - } - inword = 1; - } - else if (c >= 'a' && c <= 'z') - { - if (inword == 0) - { - c -= cast(char)'a' - 'A'; - r[i] = c; - } - inword = 1; - } - else - inword = 0; + r ~= capitalize(s[istart .. i]); } return r; @@ -1012,8 +1017,51 @@ unittest char[] s2; s2 = capwords(s1); - //printf("s2 = '%.*s'\n", s2); - assert(cmp(s2, "Foo Abc(Ad)* (Q Ptt") == 0); + //writefln("s2 = '%s'", s2); + assert(cmp(s2, "Foo Abc(ad)* (q Ptt") == 0); +} + +/******************************************** + * Return a string that consists of s[] repeated n times. + */ + +char[] repeat(char[] s, size_t n) +{ + if (n == 0) + return null; + if (n == 1) + return s; + char[] r = new char[n * s.length]; + if (s.length == 1) + r[] = s[0]; + else + { size_t len = s.length; + + for (size_t i = 0; i < n * len; i += len) + { + r[i .. i + len] = s[]; + } + } + return r; +} + + +unittest +{ + debug(string) printf("string.repeat.unittest\n"); + + char[] s; + + s = repeat("1234", 0); + assert(s is null); + s = repeat("1234", 1); + assert(cmp(s, "1234") == 0); + s = repeat("1234", 2); + assert(cmp(s, "12341234") == 0); + s = repeat("1", 4); + assert(cmp(s, "1111") == 0); + s = repeat(null, 4); + assert(s is null); } @@ -1433,6 +1481,7 @@ char[] strip(char[] s) unittest { + debug(string) printf("string.strip.unittest\n"); char[] s; int i; @@ -1441,6 +1490,117 @@ unittest assert(i == 0); } +/******************************************* + * Returns s[] sans trailing delimiter[], if any. + * If delimiter[] is null, removes trailing CR, LF, or CRLF, if any. + */ + +char[] chomp(char[] s, char[] delimiter = null) +{ + if (delimiter is null) + { size_t len = s.length; + + if (len) + { char c = s[len - 1]; + + if (c == '\r') // if ends in CR + len--; + else if (c == '\n') // if ends in LF + { + len--; + if (len && s[len - 1] == '\r') + len--; // remove CR-LF + } + } + return s[0 .. len]; + } + else if (s.length >= delimiter.length) + { + if (s[length - delimiter.length .. length] == delimiter) + return s[0 .. length - delimiter.length]; + } + return s; +} + +unittest +{ + debug(string) printf("string.chomp.unittest\n"); + char[] s; + + s = chomp(null); + assert(s is null); + s = chomp("hello"); + assert(s == "hello"); + s = chomp("hello\n"); + assert(s == "hello"); + s = chomp("hello\r"); + assert(s == "hello"); + s = chomp("hello\r\n"); + assert(s == "hello"); + s = chomp("hello\n\r"); + assert(s == "hello\n"); + s = chomp("hello\n\n"); + assert(s == "hello\n"); + s = chomp("hello\r\r"); + assert(s == "hello\r"); + s = chomp("hello\nxxx\n"); + assert(s == "hello\nxxx"); + + s = chomp(null, null); + assert(s is null); + s = chomp("hello", "o"); + assert(s == "hell"); + s = chomp("hello", "p"); + assert(s == "hello"); + s = chomp("hello", null); + assert(s == "hello"); + s = chomp("hello", "llo"); + assert(s == "he"); +} + + +/*********************************************** + * Returns s[] sans trailing character, if there is one. + * If last two characters are CR-LF, then both are removed. + */ + +char[] chop(char[] s) +{ size_t len = s.length; + + if (len) + { + if (len >= 2 && s[len - 1] == '\n' && s[len - 2] == '\r') + return s[0 .. len - 2]; + + // If we're in a tail of a UTF-8 sequence, back up + while ((s[len - 1] & 0xC0) == 0x80) + { + len--; + if (len == 0) + throw new std.utf.UtfError("invalid UTF sequence", 0); + } + + return s[0 .. len - 1]; + } + return s; +} + + +unittest +{ + debug(string) printf("string.chop.unittest\n"); + char[] s; + + s = chop(null); + assert(s is null); + s = chop("hello"); + assert(s == "hell"); + s = chop("hello\r\n"); + assert(s == "hello"); + s = chop("hello\n\r"); + assert(s == "hello\n"); +} + /******************************************* * Left justify, right justify, or center string @@ -1658,9 +1818,9 @@ unittest * Count up all instances of sub[] in s[]. */ -int count(char[] s, char[] sub) +size_t count(char[] s, char[] sub) { - int i; + size_t i; int j; int count = 0; @@ -1748,19 +1908,29 @@ unittest /************************************ * Construct translation table for translate(). + * BUG: only works with ASCII */ char[] maketrans(char[] from, char[] to) in { assert(from.length == to.length); + assert(from.length <= 128); + foreach (char c; from) + { + assert(c <= 0x7F); + } + foreach (char c; to) + { + assert(c <= 0x7F); + } } body { char[] t = new char[256]; int i; - for (i = 0; i < 256; i++) + for (i = 0; i < t.length; i++) t[i] = cast(char)i; for (i = 0; i < from.length; i++) @@ -1772,6 +1942,7 @@ char[] maketrans(char[] from, char[] to) /****************************************** * Translate characters in s[] using table created by maketrans(). * Delete chars in delchars[]. + * BUG: only works with ASCII */ char[] translate(char[] s, char[] transtab, char[] delchars) @@ -1782,29 +1953,27 @@ char[] translate(char[] s, char[] transtab, char[] delchars) body { char[] r; - int i; int count; bit[256] deltab; deltab[] = false; - for (i = 0; i < delchars.length; i++) + foreach (char c; delchars) { - deltab[delchars[i]] = true; + deltab[c] = true; } count = 0; - for (i = 0; i < s.length; i++) + foreach (char c; s) { - if (!deltab[s[i]]) + if (!deltab[c]) count++; //printf("s[%d] = '%c', count = %d\n", i, s[i], count); } r = new char[count]; count = 0; - for (i = 0; i < s.length; i++) - { char c = s[i]; - + foreach (char c; s) + { if (!deltab[c]) { r[count] = transtab[c]; @@ -2294,3 +2463,477 @@ unittest assert(i == 0); } + +/*********************************************** + * See if character c is in the pattern. + */ + +int inPattern(dchar c, char[] pattern) +{ + int result = 0; + int range = 0; + dchar lastc; + + foreach (size_t i, dchar p; pattern) + { + if (p == '^' && i == 0) + { result = 1; + if (i + 1 == pattern.length) + return (c == p); // or should this be an error? + } + else if (range) + { + range = 0; + if (lastc <= c && c <= p || c == p) + return result ^ 1; + } + else if (p == '-' && i > result && i + 1 < pattern.length) + { + range = 1; + continue; + } + else if (c == p) + return result ^ 1; + lastc = p; + } + return result; +} + + +unittest +{ + debug(string) printf("std.string.inPattern.unittest\n"); + + int i; + + i = inPattern('x', "x"); + assert(i == 1); + i = inPattern('x', "y"); + assert(i == 0); + i = inPattern('x', cast(char[])null); + assert(i == 0); + i = inPattern('x', "^y"); + assert(i == 1); + i = inPattern('x', "yxxy"); + assert(i == 1); + i = inPattern('x', "^yxxy"); + assert(i == 0); + i = inPattern('x', "^abcd"); + assert(i == 1); + i = inPattern('^', "^^"); + assert(i == 0); + i = inPattern('^', "^"); + assert(i == 1); + i = inPattern('^', "a^"); + assert(i == 1); + i = inPattern('x', "a-z"); + assert(i == 1); + i = inPattern('x', "A-Z"); + assert(i == 0); + i = inPattern('x', "^a-z"); + assert(i == 0); + i = inPattern('x', "^A-Z"); + assert(i == 1); + i = inPattern('-', "a-"); + assert(i == 1); + i = inPattern('-', "^A-"); + assert(i == 0); + i = inPattern('a', "z-a"); + assert(i == 1); + i = inPattern('z', "z-a"); + assert(i == 1); + i = inPattern('x', "z-a"); + assert(i == 0); +} + + +/*********************************************** + * See if character c is in the intersection of the patterns. + */ + +int inPattern(dchar c, char[][] patterns) +{ int result; + + foreach (char[] pattern; patterns) + { + if (!inPattern(c, pattern)) + { result = 0; + break; + } + result = 1; + } + return result; +} + + +/******************************************** + * Count characters in s that match pattern. + */ + +size_t countchars(char[] s, char[] pattern) +{ + size_t count; + + foreach (dchar c; s) + { + count += inPattern(c, pattern); + } + return count; +} + + +unittest +{ + debug(string) printf("std.string.count.unittest\n"); + + size_t c; + + c = countchars("abc", "a-c"); + assert(c == 3); + c = countchars("hello world", "or"); + assert(c == 3); +} + + +/******************************************** + * Return string that is s with all characters removed that match pattern. + */ + +char[] removechars(char[] s, char[] pattern) +{ + char[] r = s; + int changed; + size_t j; + + foreach (size_t i, dchar c; s) + { + if (!inPattern(c, pattern)) + { + if (changed) + { + if (r is s) + r = s[0 .. j].dup; + std.utf.encode(r, c); + } + } + else if (!changed) + { changed = 1; + j = i; + } + } + if (changed && r is s) + r = s[0 .. j].dup; + return r; +} + + +unittest +{ + debug(string) printf("std.string.remove.unittest\n"); + + char[] r; + + r = removechars("abc", "a-c"); + assert(r is null); + r = removechars("hello world", "or"); + assert(r == "hell wld"); + r = removechars("hello world", "d"); + assert(r == "hello worl"); +} + + +/*************************************************** + * Return string where sequences of a character from pattern + * are replaced with a single instance of that character. + * If pattern is null, it defaults to all characters. + */ + +char[] squeeze(char[] s, char[] pattern = null) +{ + char[] r = s; + dchar lastc; + size_t lasti; + int run; + int changed; + + foreach (size_t i, dchar c; s) + { + if (run && lastc == c) + { + changed = 1; + } + else if (pattern is null || inPattern(c, pattern)) + { + run = 1; + if (changed) + { if (r is s) + r = s[0 .. lasti].dup; + std.utf.encode(r, c); + } + else + lasti = i + std.utf.stride(s, i); + lastc = c; + } + else + { + run = 0; + if (changed) + { if (r is s) + r = s[0 .. lasti].dup; + std.utf.encode(r, c); + } + } + } + if (changed) + { + if (r is s) + r = s[0 .. lasti]; + } + return r; +} + + +unittest +{ + debug(string) printf("std.string.squeeze.unittest\n"); + char[] s,r; + + r = squeeze("hello"); + //writefln("r = '%s'", r); + assert(r == "helo"); + s = "abcd"; + r = squeeze(s); + assert(r is s); + s = "xyzz"; + r = squeeze(s); + assert(r.ptr == s.ptr); // should just be a slice + r = squeeze("hello goodbyee", "oe"); + assert(r == "hello godbye"); +} + + +/********************************************** + * Return string that is the 'successor' to s. + * If the rightmost character is a-zA-Z0-9, it is incremented within + * its case or digits. If it generates a carry, the process is + * repeated with the one to its immediate left. + */ + +char[] succ(char[] s) +{ + if (s.length && isalnum(s[length - 1])) + { + char[] r = s.dup; + size_t i = r.length - 1; + + while (1) + { dchar c = s[i]; + dchar carry; + + switch (c) + { + case '9': + c = '0'; + carry = '1'; + goto Lcarry; + case 'z': + case 'Z': + c -= 'Z' - 'A'; + carry = c; + Lcarry: + r[i] = c; + if (i == 0) + { + char[] t = new char[r.length + 1]; + t[0] = carry; + t[1 .. length] = r[]; + return t; + } + i--; + break; + + default: + if (std.ctype.isalnum(c)) + r[i]++; + return r; + } + } + } + return s; +} + +unittest +{ + debug(string) printf("std.string.succ.unittest\n"); + + char[] r; + + r = succ(null); + assert(r is null); + r = succ("!@#$%"); + assert(r == "!@#$%"); + r = succ("1"); + assert(r == "2"); + r = succ("9"); + assert(r == "10"); + r = succ("999"); + assert(r == "1000"); + r = succ("zz99"); + assert(r == "aaa00"); +} + + +/*********************************************** + * Translate characters in from[] to characters in to[]. + */ + +char[] tr(char[] str, char[] from, char[] to, char[] modifiers = null) +{ + int mod_c; + int mod_d; + int mod_s; + + foreach (char c; modifiers) + { + switch (c) + { + case 'c': mod_c = 1; break; // complement + case 'd': mod_d = 1; break; // delete unreplaced chars + case 's': mod_s = 1; break; // squeeze duplicated replaced chars + } + } + + if (to is null && !mod_d) + to = from; + + char[] result = new char[str.length]; + result.length = 0; + int m; + dchar lastc; + + foreach (dchar c; str) + { dchar lastf; + dchar lastt; + dchar newc; + int n = 0; + + for (size_t i = 0; i < from.length; ) + { + dchar f = std.utf.decode(from, i); + //writefln("\tf = '%s', c = '%s', lastf = '%x', '%x', i = %d, %d", f, c, lastf, dchar.init, i, from.length); + if (f == '-' && lastf != dchar.init && i < from.length) + { + dchar nextf = std.utf.decode(from, i); + //writefln("\tlastf = '%s', c = '%s', nextf = '%s'", lastf, c, nextf); + if (lastf <= c && c <= nextf) + { + n += c - lastf - 1; + if (mod_c) + goto Lnotfound; + goto Lfound; + } + n += nextf - lastf; + lastf = lastf.init; + continue; + } + + if (c == f) + { if (mod_c) + goto Lnotfound; + goto Lfound; + } + lastf = f; + n++; + } + if (!mod_c) + goto Lnotfound; + n = 0; // consider it 'found' at position 0 + + Lfound: + + // Find the nth character in to[] + //writefln("\tc = '%s', n = %d", c, n); + dchar nextt; + for (size_t i = 0; i < to.length; ) + { dchar t = std.utf.decode(to, i); + if (t == '-' && lastt != dchar.init && i < to.length) + { + nextt = std.utf.decode(to, i); + //writefln("\tlastt = '%s', c = '%s', nextt = '%s', n = %d", lastt, c, nextt, n); + n -= nextt - lastt; + if (n < 0) + { + newc = nextt + n + 1; + goto Lnewc; + } + lastt = dchar.init; + continue; + } + if (n == 0) + { newc = t; + goto Lnewc; + } + lastt = t; + nextt = t; + n--; + } + if (mod_d) + continue; + newc = nextt; + + Lnewc: + if (mod_s && m && newc == lastc) + continue; + std.utf.encode(result, newc); + m = 1; + lastc = newc; + continue; + + Lnotfound: + std.utf.encode(result, c); + lastc = c; + m = 0; + } + return result; +} + +unittest +{ + debug(string) printf("std.string.tr.unittest\n"); + + char[] r; + //writefln("r = '%s'", r); + + r = tr("abcdef", "cd", "CD"); + assert(r == "abCDef"); + + r = tr("abcdef", "b-d", "B-D"); + assert(r == "aBCDef"); + + r = tr("abcdefgh", "b-dh", "B-Dx"); + assert(r == "aBCDefgx"); + + r = tr("abcdefgh", "b-dh", "B-CDx"); + assert(r == "aBCDefgx"); + + r = tr("abcdefgh", "b-dh", "B-BCDx"); + assert(r == "aBCDefgx"); + + r = tr("abcdef", "ef", "*", "c"); + assert(r == "****ef"); + + r = tr("abcdef", "ef", "", "d"); + assert(r == "abcd"); + + r = tr("hello goodbye", "lo", null, "s"); + assert(r == "helo godbye"); + + r = tr("hello goodbye", "lo", "x", "s"); + assert(r == "hex gxdbye"); + + r = tr("14-Jul-87", "a-zA-Z", " ", "cs"); + assert(r == " Jul "); + + r = tr("Abc", "AAA", "XYZ"); + assert(r == "Xbc"); +} diff --git a/std/uri.d b/std/uri.d index f37c6f1da..bb9095de2 100644 --- a/std/uri.d +++ b/std/uri.d @@ -1,5 +1,5 @@ /* - * Copyright (C) 2000-2004 by Digital Mars, www.digitalmars.com + * Copyright (C) 2004-2005 by Digital Mars, www.digitalmars.com * Written by Walter Bright * * This software is provided 'as-is', without any express or implied @@ -8,7 +8,8 @@ * * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it - * freely, subject to the following restrictions: + * freely, in both source and binary form, subject to the following + * restrictions: * * o The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software @@ -20,7 +21,6 @@ * distribution. */ - module std.uri; //debug=uri; // uncomment to turn on debugging printf's diff --git a/std/utf.d b/std/utf.d index 64b5e5401..49f67afb4 100644 --- a/std/utf.d +++ b/std/utf.d @@ -327,6 +327,7 @@ unittest catch (UtfError u) { i = 23; + delete u; } assert(i == 23); } diff --git a/unittest.d b/unittest.d index 0e78f02e0..ead22ce92 100644 --- a/unittest.d +++ b/unittest.d @@ -1,8 +1,26 @@ -// Copyright (c) 1999-2003 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// www.digitalmars.com +/* + * Copyright (C) 1999-2005 by Digital Mars, www.digitalmars.com + * Written by Walter Bright + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, in both source and binary form, subject to the following + * restrictions: + * + * o The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * o Altered source versions must be plainly marked as such, and must not + * be misrepresented as being the original software. + * o This notice may not be removed or altered from any source + * distribution. + */ // This test program pulls in all the library modules in order // to run the unit tests on them. diff --git a/win32.mak b/win32.mak index fca186c51..b75c441f0 100644 --- a/win32.mak +++ b/win32.mak @@ -60,7 +60,7 @@ OBJS= asserterror.obj deh.obj switch.obj complex.obj gcstats.obj \ cast.obj syserror.obj path.obj string.obj memset.obj math.obj \ outbuffer.obj ctype.obj regexp.obj random.obj windows.obj \ stream.obj switcherr.obj com.obj array.obj gc.obj mmfile.obj \ - qsort.obj qsort.2.d math2.obj date.obj dateparse.obj thread.obj obj.obj \ + qsort.obj math2.obj date.obj dateparse.obj thread.obj obj.obj \ iunknown.obj crc32.obj conv.obj arraycast.obj utf.obj uri.obj \ Czlib.obj Dzlib.obj zip.obj process.obj registry.obj recls.obj \ socket.obj socketstream.obj loader.obj stdarg.obj format.obj stdio.obj \ @@ -119,14 +119,16 @@ SRC_INT= \ internal\memset.d internal\arraycast.d internal\aaA.d internal\adi.d \ internal\dmain2.d internal\cast.d internal\qsort.d internal\deh2.d \ internal\cmath2.d internal\obj.d internal\mars.h internal\aApply.d \ - internal\object.d internal\trace.d + internal\object.d internal\trace.d internal\qsort2.d SRC_STD_WIN= std\windows\registry.d \ std\windows\iunknown.d -SRC_STD_C_WIN= std\c\windows\windows.d std\c\windows\com.d +SRC_STD_C_WIN= std\c\windows\windows.d std\c\windows\com.d \ + std\c\windows\winsock.d -SRC_STD_C_LINUX= std\c\linux\linux.d std\c\linux\linuxextern.d +SRC_STD_C_LINUX= std\c\linux\linux.d std\c\linux\linuxextern.d \ + std\c\linux\socket.d SRC_ETC=