1 #include "SGPStrings.h"
2 #include "Debug.h"
3
4 #include <string_theory/format>
5 #include <string_theory/string>
6
7 #if defined(__linux__) || defined(_WIN32)
8
9 #include <sys/types.h>
10
11
12 /* $OpenBSD: strlcpy.c,v 1.11 2006/05/05 15:27:38 millert Exp $ */
13
14 /*
15 * Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
16 *
17 * Permission to use, copy, modify, and distribute this software for any
18 * purpose with or without fee is hereby granted, provided that the above
19 * copyright notice and this permission notice appear in all copies.
20 *
21 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
22 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
23 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
24 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
25 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
26 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
27 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
28 */
29
30
31 /*
32 * Copy src to string dst of size siz. At most siz-1 characters
33 * will be copied. Always NUL terminates (unless siz == 0).
34 * Returns strlen(src); if retval >= siz, truncation occurred.
35 */
36 size_t
strlcpy(char * dst,const char * src,size_t siz)37 strlcpy(char *dst, const char *src, size_t siz)
38 {
39 char *d = dst;
40 const char *s = src;
41 size_t n = siz;
42
43 /* Copy as many bytes as will fit */
44 if (n != 0) {
45 while (--n != 0) {
46 if ((*d++ = *s++) == '\0')
47 break;
48 }
49 }
50
51 /* Not enough room in dst, add NUL and traverse rest of src */
52 if (n == 0) {
53 if (siz != 0)
54 *d = '\0'; /* NUL-terminate dst */
55 while (*s++)
56 ;
57 }
58
59 return(s - src - 1); /* count does not include NUL */
60 }
61
62 #endif
63
64
65 #ifdef _WIN32
66 #ifndef __MINGW32__
67
WINsnprintf(char * const s,size_t const n,const char * const fmt,...)68 int WINsnprintf(char* const s, size_t const n, const char* const fmt, ...)
69 {
70 va_list arg;
71 va_start(arg, fmt);
72 int const ret = _vsnprintf(s, n, fmt, arg);
73 va_end(arg);
74 if (n != 0) s[n - 1] = '\0'; // _vsnprintf() does not guarantee NUL termination
75 return ret;
76 }
77
78
79 #endif
80 #endif
81
82
st_fmt_printf_to_format(const ST::string & fmt_printf)83 ST::string st_fmt_printf_to_format(const ST::string& fmt_printf)
84 {
85 ST::utf32_buffer codepoints = fmt_printf.to_utf32();
86 ST::string fmt;
87 ST::string err;
88 ST::string param;
89 enum class Parse {
90 Literal,
91 ParamFlags,
92 ParamWidth,
93 ParamPrecision,
94 ParamPrecisionValue,
95 ParamLengthModifier,
96 ParamSpecifier,
97 } state = Parse::Literal;
98 for (char32_t c : codepoints)
99 {
100 if (state == Parse::Literal)
101 {
102 if (c == U'%')
103 {
104 param = "{"; // param start
105 state = Parse::ParamFlags;
106 continue;
107 }
108 if (c == U'{')
109 {
110 fmt += "{{"; // literal '{'
111 continue;
112 }
113 fmt += c; // literal
114 continue;
115 }
116 if (state == Parse::ParamFlags)
117 {
118 if (c == U'-')
119 {
120 param += '<';
121 continue;
122 }
123 if (c == U'+' || c == U'0' || c == U'#')
124 {
125 param += c;
126 continue;
127 }
128 if (c == U' ')
129 {
130 err = ST::format("param flag U+{04X} '{c}' is not supported", c, c);
131 break;
132 }
133 state = Parse::ParamWidth; // with the same codepoint
134 }
135 if (state == Parse::ParamWidth)
136 {
137 if (c >= U'0' && c <= U'9')
138 {
139 param += c;
140 continue;
141 }
142 if (c == U'*')
143 {
144 err = ST::format("param width U+{04X} '{c}' is not supported", c, c);
145 break;
146 }
147 state = Parse::ParamPrecision; // with the same codepoint
148 }
149 if (state == Parse::ParamPrecision)
150 {
151 if (c == U'.')
152 {
153 param += c;
154 state = Parse::ParamPrecisionValue;
155 continue;
156 }
157 state = Parse::ParamLengthModifier; // with the same codepoint
158 }
159 if (state == Parse::ParamPrecisionValue)
160 {
161 if (c >= U'0' && c <= U'9')
162 {
163 param += c;
164 continue;
165 }
166 state = Parse::ParamLengthModifier; // with the same codepoint
167 }
168 if (state == Parse::ParamLengthModifier)
169 {
170 if (c == U'h' || c == U'l' || c == U'j' || c == U'z' || c == U't' || c == U'L')
171 {
172 // ignore
173 continue;
174 }
175 state = Parse::ParamSpecifier; // with the same codepoint
176 }
177 if (state == Parse::ParamSpecifier)
178 {
179 if (c == U'%' && param == "{")
180 {
181 fmt += c; // literal '%'
182 state = Parse::Literal;
183 continue;
184 }
185 if (c == U'c' || c == U'o' || c == U'x' || c == U'X' || c == U'e' || c == U'E')
186 {
187 param += c;
188 param += '}';
189 fmt += param;
190 state = Parse::Literal;
191 continue;
192 }
193 if (c == U'f' || c == U'F')
194 {
195 param += "f}";
196 fmt += param;
197 state = Parse::Literal;
198 continue;
199 }
200 if (c == U'd' || c == U'i' || c == U'u')
201 {
202 param += "d}";
203 fmt += param;
204 state = Parse::Literal;
205 continue;
206 }
207 if (c == U's')
208 {
209 param += "}";
210 fmt += param;
211 state = Parse::Literal;
212 continue;
213 }
214 if (c == U'a' || c == U'A' || c == U'g' || c == U'G' || c == U'n' || c == U'p')
215 {
216 err = ST::format("param specifier U+{04X} '{c}' is not supported", c, c);
217 break;
218 }
219 }
220 err = ST::format("unexpected codepoint U+{04X} '{c}'", c, c);
221 break;
222 }
223 if (err.empty() && state != Parse::Literal)
224 {
225 err = ST::format("format param is incomplete '{}'", param);
226 }
227 if (!err.empty())
228 {
229 ST::string what = ST::format("{}: '{}' -> '{}'", err, fmt_printf, fmt);
230 throw ST::bad_format(what.c_str());
231 }
232 return fmt;
233 }
234
235
st_buffer_escape(const ST::char_buffer & buf)236 ST::string st_buffer_escape(const ST::char_buffer& buf)
237 {
238 ST::string escaped;
239 for (char c : buf)
240 {
241 escaped += ST::format("\\x{02X}", c);
242 }
243 return escaped;
244 }
245
246
st_buffer_escape(const ST::utf16_buffer & buf)247 ST::string st_buffer_escape(const ST::utf16_buffer& buf)
248 {
249 ST::string escaped;
250 for (char16_t c : buf)
251 {
252 escaped += ST::format("\\u{04X}", c);
253 }
254 return escaped;
255 }
256
257
st_buffer_escape(const ST::utf32_buffer & buf)258 ST::string st_buffer_escape(const ST::utf32_buffer& buf)
259 {
260 ST::string escaped;
261 for (char32_t c : buf)
262 {
263 escaped += ST::format("\\U{08X}", c);
264 }
265 return escaped;
266 }
267