1 // Written in the D programming language.
2 
3 /** This module is used to manipulate _path strings.
4 
5     Authors:
6         Lars Tandle Kyllingstad,
7         $(WEB digitalmars.com, Walter Bright),
8         Grzegorz Adam Hankiewicz,
9         Thomas Kühne,
10         $(WEB erdani.org, Andrei Alexandrescu)
11     Copyright:
12         Copyright (c) 2000-2014, the authors. All rights reserved.
13     License:
14         $(WEB boost.org/LICENSE_1_0.txt, Boost License 1.0)
15     Source:
16         $(SARGONSRC src/sargon/_path/_setext.d)
17 */
18 
19 module sargon.path.setext;
20 
21 import std.path;
22 
23 import std.range;
24 import std.traits : isSomeChar;
25 import std.utf : byChar;
26 
27 import sargon.path.stripext;
28 
29 /** Algorithm that accepts a _path as an InputRange and a file extension as an InputRange,
30     and returns an InputRange that produces a char string containing the _path given
31     by $(D path), but where
32     the extension has been set to $(D ext).
33 
34     If the filename already has an extension, it is replaced. If not, the
35     extension is simply appended to the filename. Including a leading dot
36     in $(D ext) is optional.
37 
38     If the extension is empty, this function produces the equivalent of
39     $(LREF stripExtension) applied to path.
40 
41     The algorithm is lazy, does not allocate, does not throw, and is pure.
42 */
43 auto setExt(R1, R2)(R1 path, R2 ext)
44     if (isInputRange!R1 && isSomeChar!(ElementType!R1) &&
45         isInputRange!R2 && isSomeChar!(ElementType!R2))
46 {
47     return chain(path.stripExt().byChar(),
48                  "."[0 .. 1 - cast(size_t)(ext.empty || ext.front() == '.')].byChar(),
49                  ext.byChar());
50 }
51 
52 ///
53 unittest
54 {
55     import std.algorithm : copy;
56     import std.array : appender;
57 
58     auto buf = appender!(char[])();
59 
60     "file".setExt("ext").copy(&buf);
61     assert(buf.data == "file.ext");
62 }
63 
64 unittest
65 {
66     import std.internal.scopebuffer;
67     import std.stdio;
68     import std.path;
69     import std.array;
70     import std.algorithm;
71     import std.typetuple : TypeTuple;
72     import std.conv : to;
73 
74     void test(C1,C2)(const(C1)[] file, const(C2)[] ext, string expectedResult)
75     {
76         char[10] tmpbuf = void;
77         auto buf = ScopeBuffer!char(tmpbuf);
78         scope(exit) buf.free();
79 
80         buf.length = 0;
81         file.setExt(ext).byChar().copy(&buf);
82         assert(buf[] == expectedResult);
83     }
84 
85     auto testData = [
86         ["file", "ext", "file.ext"],
87         ["file", ".ext", "file.ext"],
88         ["file.", ".ext", "file.ext"],
89         ["file.", "ext", "file.ext"],
90         ["file.old", "new", "file.new"],
91         ["file", "", "file"],
92         ["file.exe", "", "file"]
93     ];
94 
95     foreach (S1; TypeTuple!(string, wstring, dstring))
96     {
97         foreach (S2; TypeTuple!(string, wstring, dstring))
98         {
99             foreach (testCase; testData)
100             {
101                 test(testCase[0].to!S1, testCase[1].to!S2, testCase[2]);
102             }
103         }
104     }
105 
106     auto abuf = appender!(char[])();
107     "file".setExt("ext").copy(&abuf);
108     assert(abuf.data == "file.ext");
109 }
110 
111 
112