@@ -295,39 +295,66 @@ nothrow:
295295 return f;
296296 }
297297
298+ /**
299+ Combine a `path` and a file `name`
300+
301+ Params:
302+ path = Path to append to
303+ name = Name to append to path
304+
305+ Returns:
306+ The `\0` terminated string which is the combination of `path` and `name`
307+ and a valid path.
308+ */
298309 extern (C++ ) static const (char )* combine(const (char )* path, const (char )* name)
299310 {
300- char * f;
301- size_t pathlen;
302- size_t namelen;
303- if (! path || ! * path)
304- return cast (char * )name;
305- pathlen = strlen(path);
306- namelen = strlen(name);
307- f = cast (char * )mem.xmalloc(pathlen + 1 + namelen + 1 );
308- memcpy(f, path, pathlen);
311+ if (! path)
312+ return name;
313+ return combine (path.toDString, name.toDString).ptr;
314+ }
315+
316+ // / Ditto
317+ extern (D ) static const (char )[] combine(const (char )[] path, const (char )[] name)
318+ {
319+ if (! path.length)
320+ return name;
321+
322+ char * f = cast (char * )mem.xmalloc(path.length + 1 + name.length + 1 );
323+ memcpy(f, path.ptr, path.length);
324+ bool trailingSlash = false ;
309325 version (Posix )
310326 {
311- if (path[pathlen - 1 ] != ' /' )
327+ if (path[$ - 1 ] != ' /' )
312328 {
313- f[pathlen ] = ' /' ;
314- pathlen ++ ;
329+ f[path.length ] = ' /' ;
330+ trailingSlash = true ;
315331 }
316332 }
317333 else version (Windows )
318334 {
319- if (path[pathlen - 1 ] != ' \\ ' && path[pathlen - 1 ] != ' /' && path[pathlen - 1 ] != ' :' )
335+ if (path[$ - 1 ] != ' \\ ' && path[$ - 1 ] != ' /' && path[$ - 1 ] != ' :' )
320336 {
321- f[pathlen ] = ' \\ ' ;
322- pathlen ++ ;
337+ f[path.length ] = ' \\ ' ;
338+ trailingSlash = true ;
323339 }
324340 }
325341 else
326342 {
327343 assert (0 );
328344 }
329- memcpy(f + pathlen, name, namelen + 1 );
330- return f;
345+ const len = path.length + trailingSlash;
346+ memcpy(f + len, name.ptr, name.length);
347+ // Note: At the moment `const(char)*` are being transitioned to
348+ // `const(char)[]`. To avoid bugs crippling in, we `\0` terminate
349+ // slices, but don't include it in the slice so `.ptr` can be used.
350+ f[len + name.length] = ' \0 ' ;
351+ return f[0 .. len + name.length];
352+ }
353+
354+ unittest
355+ {
356+ assert (combine(" foo" [], " bar" []) == " foo/bar" );
357+ assert (combine(" foo/" [], " bar" []) == " foo/bar" );
331358 }
332359
333360 static const (char )* buildPath (const (char )* path, const (char )* [] names... )
0 commit comments