Branch data Line data Source code
1 : : /*
2 : : string functions
3 : : */
4 : : #include <stdlib.h>
5 : : #include <stdio.h>
6 : : #include <string.h>
7 : : #include <stdarg.h>
8 : : #include <assert.h>
9 : : #include <ctype.h>
10 : : #include <wchar.h>
11 : : #include <wctype.h>
12 : : #include <sys/types.h>
13 : : #include <errno.h>
14 : :
15 : : #include "flisp.h"
16 : :
17 : : #if !defined(_OS_WINDOWS_)
18 : : #include <sys/time.h>
19 : : #endif /* !_OS_WINDOWS_ */
20 : :
21 : : #undef JL_DLLEXPORT /* avoid conflicting definition */
22 : : #include "utf8proc.h"
23 : :
24 : : #ifdef __cplusplus
25 : : extern "C" {
26 : : #endif
27 : :
28 : 12186140 : value_t fl_stringp(fl_context_t *fl_ctx, value_t *args, uint32_t nargs)
29 : : {
30 : 12186140 : argcount(fl_ctx, "string?", nargs, 1);
31 [ + + ]: 12186140 : return fl_isstring(fl_ctx, args[0]) ? fl_ctx->T : fl_ctx->F;
32 : : }
33 : :
34 : 48 : value_t fl_string_count(fl_context_t *fl_ctx, value_t *args, uint32_t nargs)
35 : : {
36 : 48 : size_t start = 0;
37 [ + - - + ]: 48 : if (nargs < 1 || nargs > 3)
38 : 0 : argcount(fl_ctx, "string.count", nargs, 1);
39 [ - + ]: 48 : if (!fl_isstring(fl_ctx, args[0]))
40 : 0 : type_error(fl_ctx, "string.count", "string", args[0]);
41 : 48 : size_t len = cv_len((cvalue_t*)ptr(args[0]));
42 : 48 : size_t stop = len;
43 [ - + ]: 48 : if (nargs > 1) {
44 : 0 : start = tosize(fl_ctx, args[1], "string.count");
45 [ # # ]: 0 : if (start > len)
46 : 0 : bounds_error(fl_ctx, "string.count", args[0], args[1]);
47 [ # # ]: 0 : if (nargs > 2) {
48 : 0 : stop = tosize(fl_ctx, args[2], "string.count");
49 [ # # ]: 0 : if (stop > len)
50 : 0 : bounds_error(fl_ctx, "string.count", args[0], args[2]);
51 [ # # ]: 0 : if (stop <= start)
52 : 0 : return fixnum(0);
53 : : }
54 : : }
55 : 48 : char *str = (char*)cvalue_data(args[0]);
56 : 48 : return size_wrap(fl_ctx, u8_charnum(str+start, stop-start));
57 : : }
58 : :
59 : : extern value_t fl_buffer(fl_context_t *fl_ctx, value_t *args, uint32_t nargs);
60 : : extern value_t stream_to_string(fl_context_t *fl_ctx, value_t *ps);
61 : :
62 : 1356090 : value_t fl_string(fl_context_t *fl_ctx, value_t *args, uint32_t nargs)
63 : : {
64 [ + + + + ]: 1356090 : if (nargs == 1 && fl_isstring(fl_ctx, args[0]))
65 : 1280 : return args[0];
66 : 1354810 : value_t arg, buf = fl_buffer(fl_ctx, NULL, 0);
67 : 1354810 : fl_gc_handle(fl_ctx, &buf);
68 : 1354810 : ios_t *s = value2c(ios_t*,buf);
69 : : uint32_t i;
70 : 1354810 : value_t oldpr = symbol_value(fl_ctx->printreadablysym);
71 : 1354810 : value_t oldpp = symbol_value(fl_ctx->printprettysym);
72 : 1354810 : set(fl_ctx->printreadablysym, fl_ctx->F);
73 : 1354810 : set(fl_ctx->printprettysym, fl_ctx->F);
74 [ + + ]: 3675440 : FOR_ARGS(i,0,arg,args) {
75 : 2320640 : fl_print(fl_ctx, s, args[i]);
76 : : }
77 : 1354810 : set(fl_ctx->printreadablysym, oldpr);
78 : 1354810 : set(fl_ctx->printprettysym, oldpp);
79 : 1354810 : value_t outp = stream_to_string(fl_ctx, &buf);
80 : 1354810 : fl_free_gc_handles(fl_ctx, 1);
81 : 1354810 : return outp;
82 : : }
83 : :
84 : 27402 : value_t fl_string_sub(fl_context_t *fl_ctx, value_t *args, uint32_t nargs)
85 : : {
86 [ + + ]: 27402 : if (nargs != 2)
87 : 13936 : argcount(fl_ctx, "string.sub", nargs, 3);
88 : 27402 : char *s = tostring(fl_ctx, args[0], "string.sub");
89 : 27402 : size_t len = cv_len((cvalue_t*)ptr(args[0]));
90 : : size_t i1, i2;
91 : 27402 : i1 = tosize(fl_ctx, args[1], "string.sub");
92 [ - + ]: 27402 : if (i1 > len)
93 : 0 : bounds_error(fl_ctx, "string.sub", args[0], args[1]);
94 [ + + ]: 27402 : if (nargs == 3) {
95 : 13936 : i2 = tosize(fl_ctx, args[2], "string.sub");
96 [ - + ]: 13936 : if (i2 > len)
97 : 0 : bounds_error(fl_ctx, "string.sub", args[0], args[2]);
98 : : }
99 : : else {
100 : 13466 : i2 = len;
101 : : }
102 [ + + ]: 27402 : if (i2 <= i1)
103 : 1138 : return cvalue_string(fl_ctx, 0);
104 : 26264 : value_t ns = cvalue_string(fl_ctx, i2-i1);
105 : 26264 : s = (char*)cvalue_data(args[0]); // reload after alloc
106 : 26264 : memcpy(cv_data((cvalue_t*)ptr(ns)), &s[i1], i2-i1);
107 : 26264 : return ns;
108 : : }
109 : :
110 : 188040 : value_t fl_string_char(fl_context_t *fl_ctx, value_t *args, uint32_t nargs)
111 : : {
112 : 188040 : argcount(fl_ctx, "string.char", nargs, 2);
113 : 188040 : char *s = tostring(fl_ctx, args[0], "string.char");
114 : 188040 : size_t len = cv_len((cvalue_t*)ptr(args[0]));
115 : 188040 : size_t i = tosize(fl_ctx, args[1], "string.char");
116 [ - + ]: 188040 : if (i >= len)
117 : 0 : bounds_error(fl_ctx, "string.char", args[0], args[1]);
118 : 188040 : size_t sl = u8_seqlen(&s[i]);
119 [ + - - + ]: 188040 : if (sl > len || i > len-sl)
120 : 0 : bounds_error(fl_ctx, "string.char", args[0], args[1]);
121 : 188040 : return mk_wchar(fl_ctx, u8_nextchar(s, &i));
122 : : }
123 : :
124 : 4383580 : static value_t mem_find_byte(fl_context_t *fl_ctx, char *s, char c, size_t start, size_t len)
125 : : {
126 : 4383580 : char *p = (char*)memchr(s+start, c, len-start);
127 [ + + ]: 4383580 : if (p == NULL)
128 : 2078020 : return fl_ctx->F;
129 : 2305540 : return size_wrap(fl_ctx, (size_t)(p - s));
130 : : }
131 : :
132 : 4395540 : value_t fl_string_find(fl_context_t *fl_ctx, value_t *args, uint32_t nargs)
133 : : {
134 : : char cbuf[8];
135 : 4395540 : size_t start = 0;
136 [ + + ]: 4395540 : if (nargs == 3)
137 : 4356 : start = tosize(fl_ctx, args[2], "string.find");
138 : : else
139 : 4391180 : argcount(fl_ctx, "string.find", nargs, 2);
140 : 4395540 : char *s = tostring(fl_ctx, args[0], "string.find");
141 : 4395540 : size_t len = cv_len((cvalue_t*)ptr(args[0]));
142 [ - + ]: 4395540 : if (start > len)
143 : 0 : bounds_error(fl_ctx, "string.find", args[0], args[2]);
144 : : char *needle; size_t needlesz;
145 : :
146 : 4395540 : value_t v = args[1];
147 : 4395540 : cprim_t *cp = (cprim_t*)ptr(v);
148 [ + + + - ]: 4395540 : if (iscprim(v) && cp_class(cp) == fl_ctx->wchartype) {
149 : 4390840 : uint32_t c = *(uint32_t*)cp_data(cp);
150 [ + + ]: 4390840 : if (c <= 0x7f)
151 : 4383580 : return mem_find_byte(fl_ctx, s, (char)c, start, len);
152 : 7260 : needlesz = u8_toutf8(cbuf, sizeof(cbuf), &c, 1);
153 : 7260 : needle = cbuf;
154 : : }
155 [ - + - - ]: 4712 : else if (iscprim(v) && cp_class(cp) == fl_ctx->bytetype) {
156 : 0 : return mem_find_byte(fl_ctx, s, *(char*)cp_data(cp), start, len);
157 : : }
158 [ + - ]: 4712 : else if (fl_isstring(fl_ctx, v)) {
159 : 4712 : cvalue_t *cv = (cvalue_t*)ptr(v);
160 : 4712 : needlesz = cv_len(cv);
161 : 4712 : needle = (char*)cv_data(cv);
162 : : }
163 : : else {
164 : 0 : type_error(fl_ctx, "string.find", "string", args[1]);
165 : : }
166 [ + + ]: 11972 : if (needlesz > len-start)
167 : 1114 : return fl_ctx->F;
168 [ - + ]: 10858 : else if (needlesz == 1)
169 : 0 : return mem_find_byte(fl_ctx, s, needle[0], start, len);
170 [ - + ]: 10858 : else if (needlesz == 0)
171 : 0 : return size_wrap(fl_ctx, start);
172 : : size_t i;
173 [ + + ]: 167290 : for(i=start; i < len-needlesz+1; i++) {
174 [ + + ]: 159246 : if (s[i] == needle[0]) {
175 [ + + ]: 3366 : if (!memcmp(&s[i+1], needle+1, needlesz-1))
176 : 2814 : return size_wrap(fl_ctx, i);
177 : : }
178 : : }
179 : 8044 : return fl_ctx->F;
180 : : }
181 : :
182 : 20370 : value_t fl_string_inc(fl_context_t *fl_ctx, value_t *args, uint32_t nargs)
183 : : {
184 [ + - - + ]: 20370 : if (nargs < 2 || nargs > 3)
185 : 0 : argcount(fl_ctx, "string.inc", nargs, 2);
186 : 20370 : char *s = tostring(fl_ctx, args[0], "string.inc");
187 : 20370 : size_t len = cv_len((cvalue_t*)ptr(args[0]));
188 : 20370 : size_t i = tosize(fl_ctx, args[1], "string.inc");
189 : 20370 : size_t cnt = 1;
190 [ + + ]: 20370 : if (nargs == 3)
191 : 13498 : cnt = tosize(fl_ctx, args[2], "string.inc");
192 [ + + ]: 40884 : while (cnt--) {
193 [ - + ]: 20514 : if (i >= len)
194 : 0 : bounds_error(fl_ctx, "string.inc", args[0], args[1]);
195 [ - + - - : 20514 : (void)(isutf(s[++i]) || isutf(s[++i]) || isutf(s[++i]) || ++i);
- - - - ]
196 : : }
197 : 20370 : return size_wrap(fl_ctx, i);
198 : : }
199 : :
200 : 120272 : value_t fl_string_dec(fl_context_t *fl_ctx, value_t *args, uint32_t nargs)
201 : : {
202 [ + - - + ]: 120272 : if (nargs < 2 || nargs > 3)
203 : 0 : argcount(fl_ctx, "string.dec", nargs, 2);
204 : 120272 : char *s = tostring(fl_ctx, args[0], "string.dec");
205 : 120272 : size_t len = cv_len((cvalue_t*)ptr(args[0]));
206 : 120272 : size_t i = tosize(fl_ctx, args[1], "string.dec");
207 : 120272 : size_t cnt = 1;
208 [ - + ]: 120272 : if (nargs == 3)
209 : 0 : cnt = tosize(fl_ctx, args[2], "string.dec");
210 : : // note: i is allowed to start at index len
211 [ - + ]: 120272 : if (i > len)
212 : 0 : bounds_error(fl_ctx, "string.dec", args[0], args[1]);
213 [ + + ]: 240544 : while (cnt--) {
214 [ - + ]: 120272 : if (i == 0)
215 : 0 : bounds_error(fl_ctx, "string.dec", args[0], args[1]);
216 [ - + - - : 120272 : (void)(isutf(s[--i]) || isutf(s[--i]) || isutf(s[--i]) || --i);
- - - - ]
217 : : }
218 : 120272 : return size_wrap(fl_ctx, i);
219 : : }
220 : :
221 : 120272 : static unsigned long get_radix_arg(fl_context_t *fl_ctx, value_t arg, char *fname)
222 : : {
223 : 120272 : unsigned long radix = (unsigned long)tosize(fl_ctx, arg, fname);
224 [ + - - + ]: 120272 : if (radix < 2 || radix > 36)
225 : 0 : lerrorf(fl_ctx, fl_ctx->ArgError, "%s: invalid radix", fname);
226 : 120272 : return radix;
227 : : }
228 : :
229 : 0 : value_t fl_numbertostring(fl_context_t *fl_ctx, value_t *args, uint32_t nargs)
230 : : {
231 [ # # # # ]: 0 : if (nargs < 1 || nargs > 2)
232 : 0 : argcount(fl_ctx, "number->string", nargs, 2);
233 : 0 : value_t n = args[0];
234 : 0 : int neg = 0;
235 : : uint64_t num;
236 [ # # ]: 0 : if (isfixnum(n)) num = numval(n);
237 [ # # ]: 0 : else if (!iscprim(n)) type_error(fl_ctx, "number->string", "integer", n);
238 : 0 : else num = conv_to_uint64(cp_data((cprim_t*)ptr(n)),
239 : 0 : cp_numtype((cprim_t*)ptr(n)));
240 [ # # ]: 0 : if (numval(fl_compare(fl_ctx, args[0],fixnum(0))) < 0) {
241 : 0 : num = -num;
242 : 0 : neg = 1;
243 : : }
244 : 0 : unsigned long radix = 10;
245 [ # # ]: 0 : if (nargs == 2)
246 : 0 : radix = get_radix_arg(fl_ctx, args[1], "number->string");
247 : : char buf[128];
248 : 0 : char *str = uint2str(buf, sizeof(buf), num, radix);
249 [ # # # # ]: 0 : if (neg && str > &buf[0])
250 : 0 : *(--str) = '-';
251 : 0 : return string_from_cstr(fl_ctx, str);
252 : : }
253 : :
254 : 120272 : value_t fl_stringtonumber(fl_context_t *fl_ctx, value_t *args, uint32_t nargs)
255 : : {
256 [ + - - + ]: 120272 : if (nargs < 1 || nargs > 2)
257 : 0 : argcount(fl_ctx, "string->number", nargs, 2);
258 : 120272 : char *str = tostring(fl_ctx, args[0], "string->number");
259 : : value_t n;
260 : 120272 : unsigned long radix = 0;
261 [ + - ]: 120272 : if (nargs == 2)
262 : 120272 : radix = get_radix_arg(fl_ctx, args[1], "string->number");
263 [ + + ]: 120272 : if (!isnumtok_base(fl_ctx, str, &n, (int)radix))
264 : 72 : return fl_ctx->F;
265 : 120200 : return n;
266 : : }
267 : :
268 : 0 : value_t fl_string_isutf8(fl_context_t *fl_ctx, value_t *args, uint32_t nargs)
269 : : {
270 : 0 : argcount(fl_ctx, "string.isutf8", nargs, 1);
271 : 0 : char *s = tostring(fl_ctx, args[0], "string.isutf8");
272 : 0 : size_t len = cv_len((cvalue_t*)ptr(args[0]));
273 [ # # ]: 0 : return u8_isvalid(s, len) ? fl_ctx->T : fl_ctx->F;
274 : : }
275 : :
276 : : static const builtinspec_t stringfunc_info[] = {
277 : : { "string", fl_string },
278 : : { "string?", fl_stringp },
279 : : { "string.count", fl_string_count },
280 : : { "string.sub", fl_string_sub },
281 : : { "string.find", fl_string_find },
282 : : { "string.char", fl_string_char },
283 : : { "string.inc", fl_string_inc },
284 : : { "string.dec", fl_string_dec },
285 : : { "string.isutf8", fl_string_isutf8 },
286 : :
287 : : { "number->string", fl_numbertostring },
288 : : { "string->number", fl_stringtonumber },
289 : :
290 : : { NULL, NULL }
291 : : };
292 : :
293 : 30 : void stringfuncs_init(fl_context_t *fl_ctx)
294 : : {
295 : 30 : assign_global_builtins(fl_ctx, stringfunc_info);
296 : 30 : }
297 : :
298 : : #ifdef __cplusplus
299 : : }
300 : : #endif
|