1 /*******************************************************************************
2 
3     Module for conversion between strings in C and D. Needed for C library
4     bindings.
5 
6     Usage:
7 
8     ---
9 
10         mstring text;
11 
12         char* cText = StringC.toCString(text);
13         mstring text = StringC.toDString(cText);
14 
15     ---
16 
17     FIXME: the functions here are not memory safe, they need to be re-written to
18     accept ref char[].
19 
20     Copyright:
21         Copyright (c) 2009-2016 dunnhumby Germany GmbH.
22         All rights reserved.
23 
24     License:
25         Boost Software License Version 1.0. See LICENSE_BOOST.txt for details.
26         Alternatively, this file may be distributed under the terms of the Tango
27         3-Clause BSD License (see LICENSE_BSD.txt for details).
28 
29 *******************************************************************************/
30 
31 module ocean.text.util.StringC;
32 
33 import ocean.core.Buffer;
34 import ocean.meta.types.Qualifiers;
35 
36 import core.stdc.string: strlen;
37 import core.stdc.wchar_: wcslen;
38 import core.stdc.stddef: wchar_t;
39 
40 
41 /*******************************************************************************
42 
43     Class containing the string conversion functions
44 
45 *******************************************************************************/
46 
47 class StringC
48 {
49     /***************************************************************************
50 
51         Wide character type alias (platform dependent)
52 
53      **************************************************************************/
54 
55     public alias wchar_t Wchar;
56 
57     /***************************************************************************
58 
59         Null terminators
60 
61      **************************************************************************/
62 
63     public static immutable char  Term  = '\0';
64     public static immutable Wchar Wterm = '\0';
65 
66     /***************************************************************************
67 
68         Converts str to a C string, that is, if a null terminator is not
69         present then it is appended to the original string. A pointer to the
70         string is returned.
71 
72         Params:
73             str = input string
74 
75         Returns:
76             C compatible (null terminated) string
77 
78     ***************************************************************************/
79 
80     public static char* toCString ( ref mstring str )
81     {
82         return typeof(this).toCString(*(cast(Buffer!(char)*)&str));
83     }
84 
85     /***************************************************************************
86 
87         Converts str to a C string, that is, if a null terminator is not
88         present then it is appended to the original string. A pointer to the
89         string is returned.
90 
91         Params:
92             str = input string buffer
93 
94         Returns:
95             C compatible (null terminated) string
96 
97     ***************************************************************************/
98 
99     public static char* toCString ( ref Buffer!(char) str )
100     {
101         if (!str.length || !!*str[str.length - 1])
102         {
103             str.length = str.length + 1;
104             str[str.length - 1] = StringC.Term;
105         }
106 
107         return str[].ptr;
108     }
109 
110     /***************************************************************************
111 
112         Converts str to a D string: str is sliced from the beginning up to its
113         null terminator.
114 
115         Params:
116             str = C compatible input string (pointer to the first character of
117                 the null terminated string)
118 
119         Returns:
120             D compatible (non-null terminated) string
121 
122     ***************************************************************************/
123 
124     public static inout(char)[] toDString ( inout(char)* str )
125     {
126         return str ? str[0 .. strlen(str)] : null;
127     }
128 
129     /***************************************************************************
130 
131         Converts str to a D string: str is sliced from the beginning up to its
132         null terminator.
133 
134         Params:
135             str = C compatible input string (pointer to the first character of
136                 the null terminated string)
137 
138         Returns:
139             D compatible (non-null terminated) string
140 
141     ***************************************************************************/
142 
143     public static inout(Wchar)[] toDString ( inout(Wchar)* str )
144     {
145         return str ? str[0 .. wcslen(str)] : null;
146     }
147 }
148 
149 version (unittest)
150 {
151     import ocean.core.Test;
152 }
153 
154 unittest
155 {
156     mstring str;
157 
158     str = "".dup;
159     test!("!is")(StringC.toCString(str), null);
160     test!("==")(str, "\0");
161 
162     str = "Already null-terminated\0".dup;
163     StringC.toCString(str);
164     test!("==")(str, "Already null-terminated\0");
165 
166     str = "Regular D string".dup;
167     StringC.toCString(str);
168     test!("==")(str, "Regular D string\0");
169 
170     test!("==")(StringC.toDString(cast(char *)null), "");
171 
172     str = "Hello\0".dup;
173     test!("==")(StringC.toDString(str.ptr), "Hello");
174 
175     // String literals are null terminated
176     istring r1 = StringC.toDString("Hello".ptr);
177     test!("==")(r1, "Hello");
178     const(char)* const_empty = "".ptr;
179     test(const_empty !is null);
180     cstring r2 = StringC.toDString(const_empty);
181     test!("is")(const_empty, r2.ptr);
182 
183     Buffer!(char) buff;
184     buff = "Regular D string".dup;
185     StringC.toCString(buff);
186     test!("==")(buff[], "Regular D string\0");
187 }