diff --git a/src/dmd/dmodule.d b/src/dmd/dmodule.d index aa7a6b422041..7170447a3092 100644 --- a/src/dmd/dmodule.d +++ b/src/dmd/dmodule.d @@ -943,7 +943,7 @@ extern (C++) final class Module : Package assert(prev); if (Module mprev = prev.isModule()) { - if (FileName.compare(srcname, mprev.srcfile.toChars()) != 0) + if (!FileName.equals(srcname, mprev.srcfile.toChars())) error(loc, "from file %s conflicts with another module %s from file %s", srcname, mprev.toChars(), mprev.srcfile.toChars()); else if (isRoot() && mprev.isRoot()) error(loc, "from file %s is specified twice on the command line", srcname); diff --git a/src/dmd/dmsc.d b/src/dmd/dmsc.d index 61265fb2418a..d632fce84489 100644 --- a/src/dmd/dmsc.d +++ b/src/dmd/dmsc.d @@ -98,7 +98,7 @@ void backend_init() exe = true; // EXE file only optimizations else if (params.exefile) // if writing out EXE file { size_t len = strlen(params.exefile); - if (len >= 4 && FileName.compare(params.exefile + len - 3, "exe") == 0) + if (len >= 4 && FileName.equals(params.exefile + len - 3, "exe")) exe = true; } } diff --git a/src/dmd/dsymbolsem.d b/src/dmd/dsymbolsem.d index 72e96f5a4294..5b9386b57c6e 100644 --- a/src/dmd/dsymbolsem.d +++ b/src/dmd/dsymbolsem.d @@ -1533,13 +1533,12 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor else ob.writestring("???"); ob.writeByte(')'); - for (size_t i = 0; i < imp.names.dim; i++) + foreach (i, name; imp.names) { if (i == 0) ob.writeByte(':'); else ob.writeByte(','); - Identifier name = imp.names[i]; Identifier _alias = imp.aliases[i]; if (!_alias) { diff --git a/src/dmd/mars.d b/src/dmd/mars.d index c737ad4d35c9..976bec522b37 100644 --- a/src/dmd/mars.d +++ b/src/dmd/mars.d @@ -878,11 +878,8 @@ private int tryMain(size_t argc, const(char)** argv) library = Library.factory(); library.setFilename(global.params.objdir, global.params.libname); // Add input object and input library files to output library - for (size_t i = 0; i < libmodules.dim; i++) - { - const(char)* p = libmodules[i]; + foreach (p; libmodules) library.addObject(p, null); - } } // Generate output files if (global.params.doJsonGeneration) @@ -2243,8 +2240,8 @@ private bool parseCommandLine(const ref Strings arguments, const size_t argc, re { static if (TARGET.Windows) { - const(char)* ext = FileName.ext(p); - if (ext && FileName.compare(ext, "exe") == 0) + const ext = FileName.ext(p); + if (ext && FileName.equals(ext, "exe")) { params.objname = p; continue; diff --git a/src/dmd/root/file.d b/src/dmd/root/file.d index c86cb3e94585..24ae49ec619d 100644 --- a/src/dmd/root/file.d +++ b/src/dmd/root/file.d @@ -194,8 +194,6 @@ nothrow: } else version (Windows) { - import dmd.root.filename: extendedPathThen; - DWORD size; DWORD numread; @@ -272,8 +270,6 @@ nothrow: } else version (Windows) { - import dmd.root.filename: extendedPathThen; - DWORD numwritten; // here because of the gotos const(char)* name = this.name.toChars(); // work around Windows file path length limitation diff --git a/src/dmd/root/filename.d b/src/dmd/root/filename.d index 34450e037e2a..61af71c09af2 100644 --- a/src/dmd/root/filename.d +++ b/src/dmd/root/filename.d @@ -21,12 +21,13 @@ import core.sys.windows.windows; import dmd.root.array; import dmd.root.file; import dmd.root.outbuffer; +import dmd.root.port; import dmd.root.rmem; import dmd.root.rootobject; +import dmd.utils; nothrow { -version (Windows) extern (C) int stricmp(const char*, const char*) pure; version (Windows) extern (Windows) DWORD GetFullPathNameW(LPCWSTR, DWORD, LPWSTR, LPWSTR*) @nogc; version (Windows) extern (Windows) void SetLastError(DWORD) @nogc; version (Windows) extern (C) char* getcwd(char* buffer, size_t maxlen); @@ -49,30 +50,25 @@ nothrow: this.str = mem.xstrdup(str); } - extern (C++) bool equals(const RootObject obj) const pure - { - return compare(obj) == 0; - } - + /// Compare two name according to the platform's rules (case sensitive or not) extern (C++) static bool equals(const(char)* name1, const(char)* name2) pure { - return compare(name1, name2) == 0; + return equals(name1.toDString, name2.toDString); } - extern (C++) int compare(const RootObject obj) const pure + /// Ditto + extern (D) static bool equals(const(char)[] name1, const(char)[] name2) pure { - return compare(str, (cast(FileName*)obj).str); - } + if (name1.length != name2.length) + return false; - extern (C++) static int compare(const(char)* name1, const(char)* name2) pure - { version (Windows) { - return stricmp(name1, name2); + return Port.memicmp(name1.ptr, name2.ptr, name1.length) == 0; } else { - return strcmp(name1, name2); + return name1 == name2; } } @@ -299,39 +295,66 @@ nothrow: return f; } + /** + Combine a `path` and a file `name` + + Params: + path = Path to append to + name = Name to append to path + + Returns: + The `\0` terminated string which is the combination of `path` and `name` + and a valid path. + */ extern (C++) static const(char)* combine(const(char)* path, const(char)* name) { - char* f; - size_t pathlen; - size_t namelen; - if (!path || !*path) - return cast(char*)name; - pathlen = strlen(path); - namelen = strlen(name); - f = cast(char*)mem.xmalloc(pathlen + 1 + namelen + 1); - memcpy(f, path, pathlen); + if (!path) + return name; + return combine(path.toDString, name.toDString).ptr; + } + + /// Ditto + extern(D) static const(char)[] combine(const(char)[] path, const(char)[] name) + { + if (!path.length) + return name; + + char* f = cast(char*)mem.xmalloc(path.length + 1 + name.length + 1); + memcpy(f, path.ptr, path.length); + bool trailingSlash = false; version (Posix) { - if (path[pathlen - 1] != '/') + if (path[$ - 1] != '/') { - f[pathlen] = '/'; - pathlen++; + f[path.length] = '/'; + trailingSlash = true; } } else version (Windows) { - if (path[pathlen - 1] != '\\' && path[pathlen - 1] != '/' && path[pathlen - 1] != ':') + if (path[$ - 1] != '\\' && path[$ - 1] != '/' && path[$ - 1] != ':') { - f[pathlen] = '\\'; - pathlen++; + f[path.length] = '\\'; + trailingSlash = true; } } else { assert(0); } - memcpy(f + pathlen, name, namelen + 1); - return f; + const len = path.length + trailingSlash; + memcpy(f + len, name.ptr, name.length); + // Note: At the moment `const(char)*` are being transitioned to + // `const(char)[]`. To avoid bugs crippling in, we `\0` terminate + // slices, but don't include it in the slice so `.ptr` can be used. + f[len + name.length] = '\0'; + return f[0 .. len + name.length]; + } + + unittest + { + assert(combine("foo"[], "bar"[]) == "foo/bar"); + assert(combine("foo/"[], "bar"[]) == "foo/bar"); } static const(char)* buildPath(const(char)* path, const(char)*[] names...) @@ -469,7 +492,7 @@ nothrow: return true; if (!e || !ext) return false; - return FileName.compare(e, ext) == 0; + return FileName.equals(e, ext); } /****************************** diff --git a/src/dmd/root/filename.h b/src/dmd/root/filename.h index e43313c439e4..c4b0089004f4 100644 --- a/src/dmd/root/filename.h +++ b/src/dmd/root/filename.h @@ -25,10 +25,7 @@ struct FileName { const char *str; FileName(const char *str); - bool equals(RootObject *obj); static bool equals(const char *name1, const char *name2); - int compare(RootObject *obj); - static int compare(const char *name1, const char *name2); static bool absolute(const char *name); static const char *toAbsolute(const char *name, const char *base = NULL); static const char *ext(const char *); diff --git a/src/dmd/root/outbuffer.d b/src/dmd/root/outbuffer.d index 1695f889e45d..dc61cf6510ec 100644 --- a/src/dmd/root/outbuffer.d +++ b/src/dmd/root/outbuffer.d @@ -85,11 +85,6 @@ struct OutBuffer offset += nbytes; } - extern (C++) void writebstring(char* string) nothrow - { - write(string, *string + 1); - } - extern (C++) void writestring(const(char)* string) nothrow { write(string, strlen(string)); diff --git a/src/dmd/root/outbuffer.h b/src/dmd/root/outbuffer.h index f5b3f27d2187..c9413acb4665 100644 --- a/src/dmd/root/outbuffer.h +++ b/src/dmd/root/outbuffer.h @@ -55,7 +55,6 @@ struct OutBuffer void setsize(size_t size); void reset(); void write(const void *data, d_size_t nbytes); - void writebstring(utf8_t *string); void writestring(const char *string); void prependstring(const char *string); void writenl(); // write newline diff --git a/src/dmd/root/port.d b/src/dmd/root/port.d index a4b03c63a3a5..1b893a1b218d 100644 --- a/src/dmd/root/port.d +++ b/src/dmd/root/port.d @@ -18,6 +18,8 @@ import core.stdc.string; import core.stdc.stdio; import core.stdc.stdlib; +nothrow @nogc: + private extern (C) { version(CRuntime_DigitalMars) __gshared extern const(char)* __locale_decpoint; @@ -34,7 +36,9 @@ private extern (C) extern (C++) struct Port { - static int memicmp(const char* s1, const char* s2, size_t n) + nothrow @nogc: + + static int memicmp(scope const char* s1, scope const char* s2, size_t n) pure { int result = 0; @@ -54,7 +58,7 @@ extern (C++) struct Port return result; } - static char* strupr(char* s) + static char* strupr(char* s) pure { char* t = s; @@ -67,7 +71,7 @@ extern (C++) struct Port return t; } - static bool isFloat32LiteralOutOfRange(const(char)* s) + static bool isFloat32LiteralOutOfRange(scope const(char)* s) { errno = 0; version (CRuntime_DigitalMars) @@ -90,7 +94,7 @@ extern (C++) struct Port return errno == ERANGE; } - static bool isFloat64LiteralOutOfRange(const(char)* s) + static bool isFloat64LiteralOutOfRange(scope const(char)* s) { errno = 0; version (CRuntime_DigitalMars) @@ -114,7 +118,7 @@ extern (C++) struct Port } // Little endian - static void writelongLE(uint value, void* buffer) + static void writelongLE(uint value, scope void* buffer) pure { auto p = cast(ubyte*)buffer; p[3] = cast(ubyte)(value >> 24); @@ -124,14 +128,14 @@ extern (C++) struct Port } // Little endian - static uint readlongLE(void* buffer) + static uint readlongLE(scope void* buffer) pure { auto p = cast(ubyte*)buffer; return (((((p[3] << 8) | p[2]) << 8) | p[1]) << 8) | p[0]; } // Big endian - static void writelongBE(uint value, void* buffer) + static void writelongBE(uint value, scope void* buffer) pure { auto p = cast(ubyte*)buffer; p[0] = cast(ubyte)(value >> 24); @@ -141,27 +145,27 @@ extern (C++) struct Port } // Big endian - static uint readlongBE(void* buffer) + static uint readlongBE(scope void* buffer) pure { auto p = cast(ubyte*)buffer; return (((((p[0] << 8) | p[1]) << 8) | p[2]) << 8) | p[3]; } // Little endian - static uint readwordLE(void* buffer) + static uint readwordLE(scope void* buffer) pure { auto p = cast(ubyte*)buffer; return (p[1] << 8) | p[0]; } // Big endian - static uint readwordBE(void* buffer) + static uint readwordBE(scope void* buffer) pure { auto p = cast(ubyte*)buffer; return (p[0] << 8) | p[1]; } - static void valcpy(void *dst, ulong val, size_t size) + static void valcpy(scope void *dst, ulong val, size_t size) pure { switch (size) { diff --git a/src/dmd/root/stringtable.d b/src/dmd/root/stringtable.d index c18496ef0361..2d9b1876c018 100644 --- a/src/dmd/root/stringtable.d +++ b/src/dmd/root/stringtable.d @@ -57,6 +57,12 @@ pure: { return cast(const(char)*)(&this + 1); } + + /// Returns: The content of this entry as a D slice + extern (D) inout(char)[] toString() inout + { + return (cast(inout(char)*)(&this + 1))[0 .. length]; + } } struct StringTable diff --git a/src/dmd/utils.d b/src/dmd/utils.d index bb6edab6ae6b..d02550cd02b5 100644 --- a/src/dmd/utils.d +++ b/src/dmd/utils.d @@ -21,6 +21,7 @@ import dmd.globals; import dmd.root.file; import dmd.root.filename; import dmd.root.outbuffer; +import dmd.root.rmem; /** @@ -170,3 +171,45 @@ extern(D) static bool iequals(const(char)[] s1, const(char)[] s2) } return true; } + +/** +Copy the content of `src` into a C-string ('\0' terminated) then call `dg` + +The intent of this function is to provide an allocation-less +way to call a C function using a D slice. +The function internally allocates a buffer if needed, but frees it on exit. + +Note: +The argument to `dg` is `scope`. To keep the data around after `dg` exits, +one has to copy it. + +Params: +src = Slice to use to call the C function +dg = Delegate to call afterwards + +Returns: +The return value of `T` +*/ +auto toCStringThen(alias dg)(const(char)[] src) nothrow +{ + const len = src.length + 1; + char[512] small = void; + scope ptr = (src.length < (small.length - 1)) + ? small[0 .. len] + : (cast(char*)mem.xmalloc(len))[0 .. len]; + scope (exit) + { + if (&ptr[0] != &small[0]) + mem.xfree(&ptr[0]); + } + ptr[0 .. src.length] = src[]; + ptr[src.length] = '\0'; + return dg(ptr); +} + +unittest +{ + assert("Hello world".toCStringThen!((v) => v == "Hello world\0")); + assert("Hello world\0".toCStringThen!((v) => v == "Hello world\0\0")); + assert(null.toCStringThen!((v) => v == "\0")); +} diff --git a/src/posix.mak b/src/posix.mak index 570e0c2283e7..2c1ae2220e70 100644 --- a/src/posix.mak +++ b/src/posix.mak @@ -473,7 +473,7 @@ unittest: $G/dmd-unittest ######## DMD as a library examples EXAMPLES=$(addprefix $G/examples/, avg impvisitor) -PARSER_SRCS=$(addsuffix .d, $(addprefix $D/,parse astbase parsetimevisitor transitivevisitor permissivevisitor strictvisitor)) +PARSER_SRCS=$(addsuffix .d, $(addprefix $D/,parse astbase parsetimevisitor transitivevisitor permissivevisitor strictvisitor utils)) $G/parser.a: $(PARSER_SRCS) $(LEXER_SRCS) $(ROOT_SRCS) $G/dmd $G/dmd.conf $(SRC_MAKE) CC="$(HOST_CXX)" $G/dmd -lib -of$@ $(MODEL_FLAG) -L-lstdc++ -J$G $(DFLAGS) $(PARSER_SRCS) $(LEXER_SRCS) $(ROOT_SRCS) diff --git a/src/win32.mak b/src/win32.mak index 1eeeb4a43408..ece7dacffa9f 100644 --- a/src/win32.mak +++ b/src/win32.mak @@ -172,7 +172,7 @@ LEXER_ROOT=$(ROOT)/array.d $(ROOT)/ctfloat.d $(ROOT)/file.d $(ROOT)/filename.d \ $(ROOT)/outbuffer.d $(ROOT)/port.d $(ROOT)/rmem.d $(ROOT)/rootobject.d \ $(ROOT)/stringtable.d $(ROOT)/hash.d -PARSER_SRCS=$D/astbase.d $D/parsetimevisitor.d $D/parse.d $D/transitivevisitor.d $D/permissivevisitor.d $D/strictvisitor.d +PARSER_SRCS=$D/astbase.d $D/parsetimevisitor.d $D/parse.d $D/transitivevisitor.d $D/permissivevisitor.d $D/strictvisitor.d $D/utils.d GLUE_SRCS=$D/irstate.d $D/toctype.d $D/glue.d $D/gluelayer.d $D/todt.d $D/tocsym.d $D/toir.d $D/dmsc.d \ $D/tocvdebug.d $D/s2ir.d $D/toobj.d $D/e2ir.d $D/objc_glue.d $D/eh.d $D/iasm.d $D/iasmdmd.d $D/iasmgcc.d