2 Helper functions for working with $(I C strings).
4 This module is intended to provide fast, safe and garbage free
5 way to work with $(I C strings).
7 Copyright: Denis Shelomovskij 2013-2014
9 License: $(HTTP boost.org/LICENSE_1_0.txt, Boost License 1.0).
11 Authors: Denis Shelomovskij
14 COREREF = $(HTTP dlang.org/phobos/core_$1.html#$2, $(D core.$1.$2))
16 module std.internal.cstring;
23 import core.stdc.stdlib : free;
24 import core.sys.posix.stdlib : setenv;
25 import std.exception : enforce;
27 void setEnvironment(in char[] name, in char[] value)
28 { enforce(setenv(name.tempCString(), value.tempCString(), 1) != -1); }
33 import core.sys.windows.windows : SetEnvironmentVariableW;
34 import std.exception : enforce;
36 void setEnvironment(in char[] name, in char[] value)
37 { enforce(SetEnvironmentVariableW(name.tempCStringW(), value.tempCStringW())); }
45 @property inout(C)[] asArray(C)(inout C* cstr) pure nothrow @nogc @trusted
53 return cstr[0 .. length];
57 Creates temporary 0-terminated $(I C string) with copy of passed text.
60 To = character type of returned C string
61 str = string or input range to be converted
65 The value returned is implicitly convertible to $(D const To*) and
66 has two properties: $(D ptr) to access $(I C string) as $(D const To*)
67 and $(D buffPtr) to access it as $(D To*).
69 The value returned can be indexed by [] to access it as an array.
71 The temporary $(I C string) is valid unless returned object is destroyed.
72 Thus if returned object is assigned to a variable the temporary is
73 valid unless the variable goes out of scope. If returned object isn't
74 assigned to a variable it will be destroyed at the end of creating
78 For small strings tempCString will use stack allocated buffer,
79 for large strings (approximately 250 characters and more) it will
80 allocate temporary one using C's $(D malloc).
83 This function is intended to be used in function call expression (like
84 $(D strlen(str.tempCString()))). Incorrect usage of this function may
85 lead to memory corruption.
86 See $(RED WARNING) in $(B Examples) section.
89 auto tempCString(To = char, From)(From str)
90 if (isSomeChar!To && (isInputRange!From || isSomeString!From) &&
91 isSomeChar!(ElementEncodingType!From))
94 alias CF = Unqual!(ElementEncodingType!From);
96 enum To* useStack = () @trusted { return cast(To*) size_t.max; }();
107 @property inout(To)* buffPtr() inout pure
109 return _ptr == useStack ? _buff.ptr : _ptr;
112 @property const(To)* ptr() const pure
117 const(To)[] opIndex() const pure
119 return buffPtr[0 .. _length];
124 if (_ptr != useStack)
126 import core.stdc.stdlib : free;
133 size_t _length; // length of the string
136 enum buffLength = 16 / To.sizeof; // smaller size to trigger reallocations
140 enum buffLength = 256 / To.sizeof; // production size
143 To[buffLength] _buff; // the 'small string optimization'
145 static Res trustedVoidInit() { Res res = void; return res; }
148 Res res = Res.trustedVoidInit(); // expensive to fill _buff[]
150 // Note: res._ptr can't point to res._buff as structs are movable.
153 bool p_is_onstack = true;
156 static To[] trustedRealloc(To[] buf, size_t i, To[] res, size_t strLength, bool res_is_onstack)
157 @trusted @nogc nothrow
159 pragma(inline, false); // because it's rarely called
161 import core.exception : onOutOfMemoryError;
162 import core.stdc.stdlib : malloc, realloc;
163 import core.stdc.string : memcpy;
167 size_t newlen = res.length * 3 / 2;
168 if (newlen <= strLength)
169 newlen = strLength + 1; // +1 for terminating 0
170 auto ptr = cast(To*) malloc(newlen * To.sizeof);
172 onOutOfMemoryError();
173 memcpy(ptr, res.ptr, i * To.sizeof);
174 return ptr[0 .. newlen];
178 if (buf.length >= size_t.max / (2 * To.sizeof))
179 onOutOfMemoryError();
180 const newlen = buf.length * 3 / 2;
181 auto ptr = cast(To*) realloc(buf.ptr, newlen * To.sizeof);
183 onOutOfMemoryError();
184 return ptr[0 .. newlen];
189 static if (hasLength!From)
191 strLength = str.length;
193 import std.utf : byUTF;
194 static if (isSomeString!From)
196 auto r = cast(const(CF)[])str; // because inout(CF) causes problems with byUTF
197 if (r is null) // Bugzilla 14980
206 foreach (const c; byUTF!(Unqual!To)(r))
208 if (i + 1 == q.length)
210 p = trustedRealloc(p, i, res._buff, strLength, p_is_onstack);
211 p_is_onstack = false;
218 res._ptr = p_is_onstack ? useStack : &p[0];
223 nothrow @nogc @system unittest
225 import core.stdc.string;
230 assert(strlen(str.tempCString()) == 3);
233 auto tmp = str.tempCString();
234 assert(strlen(tmp) == 3); // or `tmp.ptr`, or `tmp.buffPtr`
236 // $(RED WARNING): $(RED Incorrect usage)
237 auto pInvalid1 = str.tempCString().ptr;
238 const char* pInvalid2 = str.tempCString();
239 // Both pointers refer to invalid memory here as
240 // returned values aren't assigned to a variable and
241 // both primary expressions are ended.
244 @safe nothrow @nogc unittest
246 assert("abc".tempCString().asArray == "abc");
247 assert("abc"d.tempCString().ptr.asArray == "abc");
248 assert("abc".tempCString!wchar().buffPtr.asArray == "abc"w);
250 import std.utf : byChar, byWchar;
252 assert(tempCString(abc[].byChar).buffPtr.asArray == abc);
253 assert(tempCString(abc[].byWchar).buffPtr.asArray == abc);
254 assert(tempCString(abc[].byChar)[] == abc);
258 nothrow @nogc @safe unittest
260 const(char[]) str = null;
261 auto res = tempCString(str);
262 const char* ptr = res;
267 alias tempCStringW = tempCString!(wchar, const(char)[]);