• source navigation  • diff markup  • identifier search  • freetext search  • 

Sources/ucode/lib.c

  1 /*
  2  * Copyright (C) 2020-2021 Jo-Philipp Wich <jo@mein.io>
  3  *
  4  * Permission to use, copy, modify, and/or distribute this software for any
  5  * purpose with or without fee is hereby granted, provided that the above
  6  * copyright notice and this permission notice appear in all copies.
  7  *
  8  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
  9  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 10  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 11  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 12  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 13  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 14  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 15  */
 16 
 17 #include <stdio.h>
 18 #include <stdlib.h>
 19 #include <stdarg.h>
 20 #include <string.h>
 21 #include <signal.h>
 22 #include <ctype.h>
 23 #include <errno.h>
 24 #include <math.h>
 25 #include <time.h>
 26 #include <dlfcn.h>
 27 #include <libgen.h>
 28 #include <unistd.h>
 29 #include <arpa/inet.h>
 30 #include <sys/stat.h>
 31 #include <sys/types.h>
 32 #include <sys/wait.h>
 33 #include <fnmatch.h>
 34 #include <assert.h>
 35 
 36 #include "ucode/lexer.h"
 37 #include "ucode/compiler.h"
 38 #include "ucode/vm.h"
 39 #include "ucode/lib.h"
 40 #include "ucode/source.h"
 41 
 42 static void
 43 format_context_line(uc_stringbuf_t *buf, const char *line, size_t off, bool compact)
 44 {
 45         unsigned padlen, i;
 46         const char *p;
 47 
 48         for (p = line, padlen = 0; *p != '\n' && *p != '\0'; p++) {
 49                 if (compact && (p - line) == (ptrdiff_t)off)
 50                         ucv_stringbuf_append(buf, "\033[22m");
 51 
 52                 switch (*p) {
 53                 case '\t':
 54                         ucv_stringbuf_append(buf, "    ");
 55                         if (p < line + off)
 56                                 padlen += 4;
 57                         break;
 58 
 59                 case '\r':
 60                 case '\v':
 61                         ucv_stringbuf_append(buf, " ");
 62                         if (p < line + off)
 63                                 padlen++;
 64                         break;
 65 
 66                 default:
 67                         ucv_stringbuf_addstr(buf, p, 1);
 68                         if (p < line + off)
 69                                 padlen++;
 70                 }
 71         }
 72 
 73         if (compact) {
 74                 ucv_stringbuf_append(buf, "\033[m\n");
 75 
 76                 return;
 77         }
 78 
 79         ucv_stringbuf_append(buf, "`\n  ");
 80 
 81         if (padlen < strlen("Near here ^")) {
 82                 for (i = 0; i < padlen; i++)
 83                         ucv_stringbuf_append(buf, " ");
 84 
 85                 ucv_stringbuf_append(buf, "^-- Near here\n");
 86         }
 87         else {
 88                 ucv_stringbuf_append(buf, "Near here ");
 89 
 90                 for (i = strlen("Near here "); i < padlen; i++)
 91                         ucv_stringbuf_append(buf, "-");
 92 
 93                 ucv_stringbuf_append(buf, "^\n");
 94         }
 95 }
 96 
 97 static char *
 98 source_filename(uc_source_t *src, uint32_t line)
 99 {
100         const char *name = src->filename ? basename(src->filename) : "[?]";
101         static char buf[sizeof("xxxxxxxxx.uc:0000000000")];
102         size_t len = strlen(name);
103 
104         if (len > 12)
105                 snprintf(buf, sizeof(buf), "...%s:%u", name + (len - 9), line);
106         else
107                 snprintf(buf, sizeof(buf), "%12s:%u", name, line);
108 
109         return buf;
110 }
111 
112 bool
113 uc_source_context_format(uc_stringbuf_t *buf, uc_source_t *src, size_t off, bool compact)
114 {
115         size_t len, rlen;
116         bool truncated;
117         char line[256];
118         long srcpos;
119         int eline;
120 
121         srcpos = ftell(src->fp);
122 
123         if (srcpos == -1)
124                 return false;
125 
126         fseek(src->fp, 0, SEEK_SET);
127 
128         truncated = false;
129         eline = 1;
130         rlen = 0;
131 
132         while (fgets(line, sizeof(line), src->fp)) {
133                 len = strlen(line);
134                 rlen += len;
135 
136                 if (rlen >= off) {
137                         if (compact)
138                                 ucv_stringbuf_printf(buf, "\033[2;40;97m%17s  %s",
139                                         source_filename(src, eline),
140                                         truncated ? "..." : "");
141                         else
142                                 ucv_stringbuf_printf(buf, "\n `%s",
143                                         truncated ? "..." : "");
144 
145                         format_context_line(buf, line, len - (rlen - off) + (truncated ? 3 : 0), compact);
146                         break;
147                 }
148 
149                 truncated = (len > 0 && line[len-1] != '\n');
150                 eline += !truncated;
151         }
152 
153         fseek(src->fp, srcpos, SEEK_SET);
154 
155         return true;
156 }
157 
158 bool
159 uc_error_context_format(uc_stringbuf_t *buf, uc_source_t *src, uc_value_t *stacktrace, size_t off)
160 {
161         uc_value_t *e, *fn, *file, *line, *byte;
162         const char *path;
163         size_t idx;
164 
165         for (idx = 0; idx < (stacktrace ? ucv_array_length(stacktrace) : 0); idx++) {
166                 e = ucv_array_get(stacktrace, idx);
167                 fn = ucv_object_get(e, "function", NULL);
168                 file = ucv_object_get(e, "filename", NULL);
169 
170                 if (idx == 0) {
171                         path = (file && strcmp(ucv_string_get(file), "[stdin]"))
172                                 ? ucv_string_get(file) : NULL;
173 
174                         if (path && fn)
175                                 ucv_stringbuf_printf(buf, "In %s(), file %s, ", ucv_string_get(fn), path);
176                         else if (fn)
177                                 ucv_stringbuf_printf(buf, "In %s(), ", ucv_string_get(fn));
178                         else if (path)
179                                 ucv_stringbuf_printf(buf, "In %s, ", path);
180                         else
181                                 ucv_stringbuf_append(buf, "In ");
182 
183                         ucv_stringbuf_printf(buf, "line %" PRId64 ", byte %" PRId64 ":\n",
184                                 ucv_int64_get(ucv_object_get(e, "line", NULL)),
185                                 ucv_int64_get(ucv_object_get(e, "byte", NULL)));
186                 }
187                 else {
188                         line = ucv_object_get(e, "line", NULL);
189                         byte = ucv_object_get(e, "byte", NULL);
190 
191                         ucv_stringbuf_printf(buf, "  called from %s%s (%s",
192                                 fn ? "function " : "anonymous function",
193                                 fn ? ucv_string_get(fn) : "",
194                                 file ? ucv_string_get(file) : "");
195 
196                         if (line && byte)
197                                 ucv_stringbuf_printf(buf, ":%" PRId64 ":%" PRId64 ")\n",
198                                         ucv_int64_get(line),
199                                         ucv_int64_get(byte));
200                         else
201                                 ucv_stringbuf_append(buf, "[C])\n");
202                 }
203         }
204 
205         return uc_source_context_format(buf, src, off, false);
206 }
207 
208 static char *uc_cast_string(uc_vm_t *vm, uc_value_t **v, bool *freeable) {
209         if (ucv_type(*v) == UC_STRING) {
210                 *freeable = false;
211 
212                 return _ucv_string_get(v);
213         }
214 
215         *freeable = true;
216 
217         return ucv_to_string(vm, *v);
218 }
219 
220 static void
221 uc_vm_ctx_push(uc_vm_t *vm)
222 {
223         uc_value_t *ctx = NULL;
224 
225         if (vm->callframes.count >= 2)
226                 ctx = vm->callframes.entries[vm->callframes.count - 2].ctx;
227 
228         uc_vm_stack_push(vm, ucv_get(ctx));
229 }
230 
231 static uc_value_t *
232 uc_print_common(uc_vm_t *vm, size_t nargs, FILE *fh)
233 {
234         uc_value_t *item;
235         size_t reslen = 0;
236         size_t len = 0;
237         size_t arridx;
238         char *p;
239 
240         for (arridx = 0; arridx < nargs; arridx++) {
241                 item = uc_fn_arg(arridx);
242 
243                 if (ucv_type(item) == UC_STRING) {
244                         len = ucv_string_length(item);
245                         reslen += fwrite(ucv_string_get(item), 1, len, fh);
246                 }
247                 else if (item != NULL) {
248                         p = ucv_to_string(vm, item);
249                         len = strlen(p);
250                         reslen += fwrite(p, 1, len, fh);
251                         free(p);
252                 }
253         }
254 
255         return ucv_int64_new(reslen);
256 }
257 
258 
259 static uc_value_t *
260 uc_print(uc_vm_t *vm, size_t nargs)
261 {
262         return uc_print_common(vm, nargs, vm->output);
263 }
264 
265 static uc_value_t *
266 uc_length(uc_vm_t *vm, size_t nargs)
267 {
268         uc_value_t *arg = uc_fn_arg(0);
269 
270         switch (ucv_type(arg)) {
271         case UC_OBJECT:
272                 return ucv_int64_new(ucv_object_length(arg));
273 
274         case UC_ARRAY:
275                 return ucv_int64_new(ucv_array_length(arg));
276 
277         case UC_STRING:
278                 return ucv_int64_new(ucv_string_length(arg));
279 
280         default:
281                 return NULL;
282         }
283 }
284 
285 static uc_value_t *
286 uc_index(uc_vm_t *vm, size_t nargs, bool right)
287 {
288         uc_value_t *stack = uc_fn_arg(0);
289         uc_value_t *needle = uc_fn_arg(1);
290         const char *sstr, *nstr, *p;
291         size_t arridx, len;
292         ssize_t ret = -1;
293 
294         switch (ucv_type(stack)) {
295         case UC_ARRAY:
296                 for (arridx = 0, len = ucv_array_length(stack); arridx < len; arridx++) {
297                         if (ucv_compare(I_EQ, ucv_array_get(stack, arridx), needle, NULL)) {
298                                 ret = (ssize_t)arridx;
299 
300                                 if (!right)
301                                         break;
302                         }
303                 }
304 
305                 return ucv_int64_new(ret);
306 
307         case UC_STRING:
308                 sstr = ucv_string_get(stack);
309                 nstr = needle ? ucv_string_get(needle) : NULL;
310                 len = needle ? strlen(nstr) : 0;
311 
312                 for (p = sstr; *p && len; p++) {
313                         if (!strncmp(p, nstr, len)) {
314                                 ret = (ssize_t)(p - sstr);
315 
316                                 if (!right)
317                                         break;
318                         }
319                 }
320 
321                 return ucv_int64_new(ret);
322 
323         default:
324                 return NULL;
325         }
326 }
327 
328 static uc_value_t *
329 uc_lindex(uc_vm_t *vm, size_t nargs)
330 {
331         return uc_index(vm, nargs, false);
332 }
333 
334 static uc_value_t *
335 uc_rindex(uc_vm_t *vm, size_t nargs)
336 {
337         return uc_index(vm, nargs, true);
338 }
339 
340 static uc_value_t *
341 uc_push(uc_vm_t *vm, size_t nargs)
342 {
343         uc_value_t *arr = uc_fn_arg(0);
344         uc_value_t *item = NULL;
345         size_t arridx;
346 
347         if (ucv_type(arr) != UC_ARRAY)
348                 return NULL;
349 
350         for (arridx = 1; arridx < nargs; arridx++) {
351                 item = uc_fn_arg(arridx);
352                 ucv_array_push(arr, ucv_get(item));
353         }
354 
355         return ucv_get(item);
356 }
357 
358 static uc_value_t *
359 uc_pop(uc_vm_t *vm, size_t nargs)
360 {
361         uc_value_t *arr = uc_fn_arg(0);
362 
363         return ucv_array_pop(arr);
364 }
365 
366 static uc_value_t *
367 uc_shift(uc_vm_t *vm, size_t nargs)
368 {
369         uc_value_t *arr = uc_fn_arg(0);
370 
371         return ucv_array_shift(arr);
372 }
373 
374 static uc_value_t *
375 uc_unshift(uc_vm_t *vm, size_t nargs)
376 {
377         uc_value_t *arr = uc_fn_arg(0);
378         uc_value_t *item = NULL;
379         size_t i;
380 
381         if (ucv_type(arr) != UC_ARRAY)
382                 return NULL;
383 
384         for (i = 1; i < nargs; i++) {
385                 item = uc_fn_arg(i);
386                 ucv_array_unshift(arr, ucv_get(item));
387         }
388 
389         return ucv_get(item);
390 }
391 
392 static uc_value_t *
393 uc_chr(uc_vm_t *vm, size_t nargs)
394 {
395         uc_value_t *rv = NULL;
396         size_t idx;
397         int64_t n;
398         char *str;
399 
400         if (!nargs)
401                 return ucv_string_new_length("", 0);
402 
403         str = xalloc(nargs);
404 
405         for (idx = 0; idx < nargs; idx++) {
406                 n = ucv_to_integer(uc_fn_arg(idx));
407 
408                 if (n < 0)
409                         n = 0;
410                 else if (n > 255)
411                         n = 255;
412 
413                 str[idx] = (char)n;
414         }
415 
416         rv = ucv_string_new_length(str, nargs);
417         free(str);
418 
419         return rv;
420 }
421 
422 static uc_value_t *
423 uc_die(uc_vm_t *vm, size_t nargs)
424 {
425         uc_value_t *msg = uc_fn_arg(0);
426         bool freeable = false;
427         char *s;
428 
429         s = msg ? uc_cast_string(vm, &msg, &freeable) : "Died";
430 
431         uc_vm_raise_exception(vm, EXCEPTION_USER, "%s", s);
432 
433         if (freeable)
434                 free(s);
435 
436         return NULL;
437 }
438 
439 static uc_value_t *
440 uc_exists(uc_vm_t *vm, size_t nargs)
441 {
442         uc_value_t *obj = uc_fn_arg(0);
443         uc_value_t *key = uc_fn_arg(1);
444         bool found, freeable;
445         char *k;
446 
447         if (ucv_type(obj) != UC_OBJECT)
448                 return ucv_boolean_new(false);
449 
450         k = uc_cast_string(vm, &key, &freeable);
451 
452         ucv_object_get(obj, k, &found);
453 
454         if (freeable)
455                 free(k);
456 
457         return ucv_boolean_new(found);
458 }
459 
460 static uc_value_t *
461 uc_exit(uc_vm_t *vm, size_t nargs)
462 {
463         int64_t n = ucv_to_integer(uc_fn_arg(0));
464 
465         vm->arg.s32 = (int32_t)n;
466         uc_vm_raise_exception(vm, EXCEPTION_EXIT, "Terminated");
467 
468         return NULL;
469 }
470 
471 static uc_value_t *
472 uc_getenv(uc_vm_t *vm, size_t nargs)
473 {
474         uc_value_t *key = uc_fn_arg(0);
475         char *k = ucv_string_get(key);
476         char *val = k ? getenv(k) : NULL;
477 
478         return val ? ucv_string_new(val) : NULL;
479 }
480 
481 static uc_value_t *
482 uc_filter(uc_vm_t *vm, size_t nargs)
483 {
484         uc_value_t *obj = uc_fn_arg(0);
485         uc_value_t *func = uc_fn_arg(1);
486         uc_value_t *rv, *arr;
487         size_t arridx, arrlen;
488 
489         if (ucv_type(obj) != UC_ARRAY)
490                 return NULL;
491 
492         arr = ucv_array_new(vm);
493 
494         for (arrlen = ucv_array_length(obj), arridx = 0; arridx < arrlen; arridx++) {
495                 uc_vm_ctx_push(vm);
496                 uc_vm_stack_push(vm, ucv_get(func));
497                 uc_vm_stack_push(vm, ucv_get(ucv_array_get(obj, arridx)));
498                 uc_vm_stack_push(vm, ucv_int64_new(arridx));
499                 uc_vm_stack_push(vm, ucv_get(obj));
500 
501                 if (uc_vm_call(vm, true, 3)) {
502                         ucv_put(arr);
503 
504                         return NULL;
505                 }
506 
507                 rv = uc_vm_stack_pop(vm);
508 
509                 if (ucv_is_truish(rv))
510                         ucv_array_push(arr, ucv_get(ucv_array_get(obj, arridx)));
511 
512                 ucv_put(rv);
513         }
514 
515         return arr;
516 }
517 
518 static uc_value_t *
519 uc_hex(uc_vm_t *vm, size_t nargs)
520 {
521         uc_value_t *val = uc_fn_arg(0);
522         char *e, *v;
523         int64_t n;
524 
525         v = ucv_string_get(val);
526 
527         if (!v || !isxdigit(*v))
528                 return ucv_double_new(NAN);
529 
530         n = strtoll(v, &e, 16);
531 
532         if (e == v || *e)
533                 return ucv_double_new(NAN);
534 
535         return ucv_int64_new(n);
536 }
537 
538 static uc_value_t *
539 uc_int(uc_vm_t *vm, size_t nargs)
540 {
541         int64_t n = ucv_to_integer(uc_fn_arg(0));
542 
543         if (errno == EINVAL || errno == ERANGE)
544                 return ucv_double_new(NAN);
545 
546         return ucv_int64_new(n);
547 }
548 
549 static uc_value_t *
550 uc_join(uc_vm_t *vm, size_t nargs)
551 {
552         uc_value_t *sep = uc_fn_arg(0);
553         uc_value_t *arr = uc_fn_arg(1);
554         size_t arrlen, arridx;
555         uc_stringbuf_t *buf;
556 
557         if (ucv_type(arr) != UC_ARRAY)
558                 return NULL;
559 
560         buf = ucv_stringbuf_new();
561 
562         for (arrlen = ucv_array_length(arr), arridx = 0; arridx < arrlen; arridx++) {
563                 if (arridx > 0)
564                         ucv_to_stringbuf(vm, buf, sep, false);
565 
566                 ucv_to_stringbuf(vm, buf, ucv_array_get(arr, arridx), false);
567         }
568 
569         return ucv_stringbuf_finish(buf);
570 }
571 
572 static uc_value_t *
573 uc_keys(uc_vm_t *vm, size_t nargs)
574 {
575         uc_value_t *obj = uc_fn_arg(0);
576         uc_value_t *arr = NULL;
577 
578         if (ucv_type(obj) != UC_OBJECT)
579                 return NULL;
580 
581         arr = ucv_array_new(vm);
582 
583         ucv_object_foreach(obj, key, val) {
584                 (void)val;
585                 ucv_array_push(arr, ucv_string_new(key));
586         }
587 
588         return arr;
589 }
590 
591 static uc_value_t *
592 uc_lc(uc_vm_t *vm, size_t nargs)
593 {
594         char *str = ucv_to_string(vm, uc_fn_arg(0));
595         uc_value_t *rv = NULL;
596         char *p;
597 
598         if (!str)
599                 return NULL;
600 
601         for (p = str; *p; p++)
602                 if (*p >= 'A' && *p <= 'Z')
603                         *p |= 32;
604 
605         rv = ucv_string_new(str);
606 
607         free(str);
608 
609         return rv;
610 }
611 
612 static uc_value_t *
613 uc_map(uc_vm_t *vm, size_t nargs)
614 {
615         uc_value_t *obj = uc_fn_arg(0);
616         uc_value_t *func = uc_fn_arg(1);
617         uc_value_t *arr, *rv;
618         size_t arridx, arrlen;
619 
620         if (ucv_type(obj) != UC_ARRAY)
621                 return NULL;
622 
623         arr = ucv_array_new(vm);
624 
625         for (arrlen = ucv_array_length(obj), arridx = 0; arridx < arrlen; arridx++) {
626                 uc_vm_ctx_push(vm);
627                 uc_vm_stack_push(vm, ucv_get(func));
628                 uc_vm_stack_push(vm, ucv_get(ucv_array_get(obj, arridx)));
629                 uc_vm_stack_push(vm, ucv_int64_new(arridx));
630                 uc_vm_stack_push(vm, ucv_get(obj));
631 
632                 if (uc_vm_call(vm, true, 3)) {
633                         ucv_put(arr);
634 
635                         return NULL;
636                 }
637 
638                 rv = uc_vm_stack_pop(vm);
639 
640                 ucv_array_push(arr, rv);
641         }
642 
643         return arr;
644 }
645 
646 static uc_value_t *
647 uc_ord(uc_vm_t *vm, size_t nargs)
648 {
649         uc_value_t *obj = uc_fn_arg(0);
650         uc_value_t *rv, *pos;
651         const char *str;
652         size_t i, len;
653         int64_t n;
654 
655         if (ucv_type(obj) != UC_STRING)
656                 return NULL;
657 
658         str = ucv_string_get(obj);
659         len = ucv_string_length(obj);
660 
661         if (nargs == 1)
662                 return str[0] ? ucv_int64_new((int64_t)str[0]) : NULL;
663 
664         rv = ucv_array_new(vm);
665 
666         for (i = 1; i < nargs; i++) {
667                 pos = uc_fn_arg(i);
668 
669                 if (ucv_type(pos) == UC_INTEGER) {
670                         n = ucv_int64_get(pos);
671 
672                         if (n < 0)
673                                 n += len;
674 
675                         if (n >= 0 && (uint64_t)n < len) {
676                                 ucv_array_push(rv, ucv_int64_new((int64_t)str[n]));
677                                 continue;
678                         }
679                 }
680 
681                 ucv_array_push(rv, NULL);
682         }
683 
684         return rv;
685 }
686 
687 static uc_value_t *
688 uc_type(uc_vm_t *vm, size_t nargs)
689 {
690         uc_value_t *v = uc_fn_arg(0);
691         uc_type_t t = ucv_type(v);
692 
693         switch (t) {
694         case UC_CFUNCTION:
695         case UC_FUNCTION:
696         case UC_CLOSURE:
697                 return ucv_string_new("function");
698 
699         case UC_INTEGER:
700                 return ucv_string_new("int");
701 
702         case UC_BOOLEAN:
703                 return ucv_string_new("bool");
704 
705         case UC_NULL:
706                 return NULL;
707 
708         default:
709                 return ucv_string_new(ucv_typename(v));
710         }
711 }
712 
713 static uc_value_t *
714 uc_reverse(uc_vm_t *vm, size_t nargs)
715 {
716         uc_value_t *obj = uc_fn_arg(0);
717         uc_value_t *rv = NULL;
718         size_t len, arridx;
719         const char *str;
720         char *dup, *p;
721 
722         if (ucv_type(obj) == UC_ARRAY) {
723                 rv = ucv_array_new(vm);
724 
725                 for (arridx = ucv_array_length(obj); arridx > 0; arridx--)
726                         ucv_array_push(rv, ucv_get(ucv_array_get(obj, arridx - 1)));
727         }
728         else if (ucv_type(obj) == UC_STRING) {
729                 len = ucv_string_length(obj);
730                 str = ucv_string_get(obj);
731                 p = dup = xalloc(len + 1);
732 
733                 while (len > 0)
734                         *p++ = str[--len];
735 
736                 rv = ucv_string_new(dup);
737 
738                 free(dup);
739         }
740 
741         return rv;
742 }
743 
744 
745 static struct {
746         uc_vm_t *vm;
747         bool ex;
748         uc_value_t *fn;
749 } sort_ctx;
750 
751 static int
752 default_cmp(uc_value_t *v1, uc_value_t *v2)
753 {
754         char *s1, *s2;
755         bool f1, f2;
756         int res;
757 
758         /* when both operands are numeric then compare numerically */
759         if ((ucv_type(v1) == UC_INTEGER || ucv_type(v1) == UC_DOUBLE) &&
760             (ucv_type(v2) == UC_INTEGER || ucv_type(v2) == UC_DOUBLE)) {
761                 ucv_compare(0, v1, v2, &res);
762 
763                 return res;
764         }
765 
766         /* otherwise convert both operands to strings and compare lexically */
767         s1 = uc_cast_string(sort_ctx.vm, &v1, &f1);
768         s2 = uc_cast_string(sort_ctx.vm, &v2, &f2);
769 
770         res = strcmp(s1, s2);
771 
772         if (f1) free(s1);
773         if (f2) free(s2);
774 
775         return res;
776 }
777 
778 static int
779 sort_fn(const void *k1, const void *k2)
780 {
781         uc_value_t *rv, *null = ucv_int64_new(0);
782         uc_value_t * const *v1 = k1;
783         uc_value_t * const *v2 = k2;
784         int res;
785 
786         if (!sort_ctx.fn)
787                 return default_cmp(*v1, *v2);
788 
789         if (sort_ctx.ex)
790                 return 0;
791 
792         uc_vm_ctx_push(sort_ctx.vm);
793         uc_vm_stack_push(sort_ctx.vm, ucv_get(sort_ctx.fn));
794         uc_vm_stack_push(sort_ctx.vm, ucv_get(*v1));
795         uc_vm_stack_push(sort_ctx.vm, ucv_get(*v2));
796 
797         if (uc_vm_call(sort_ctx.vm, true, 2)) {
798                 sort_ctx.ex = true;
799 
800                 return 0;
801         }
802 
803         rv = uc_vm_stack_pop(sort_ctx.vm);
804 
805         ucv_compare(0, rv, null, &res);
806 
807         ucv_put(null);
808         ucv_put(rv);
809 
810         return res;
811 }
812 
813 static uc_value_t *
814 uc_sort(uc_vm_t *vm, size_t nargs)
815 {
816         uc_value_t *arr = uc_fn_arg(0);
817         uc_value_t *fn = uc_fn_arg(1);
818 
819         if (ucv_type(arr) != UC_ARRAY)
820                 return NULL;
821 
822         sort_ctx.vm = vm;
823         sort_ctx.fn = fn;
824 
825         ucv_array_sort(arr, sort_fn);
826 
827         return sort_ctx.ex ? NULL : ucv_get(arr);
828 }
829 
830 static uc_value_t *
831 uc_splice(uc_vm_t *vm, size_t nargs)
832 {
833         uc_value_t *arr = uc_fn_arg(0);
834         int64_t ofs = ucv_to_integer(uc_fn_arg(1));
835         int64_t remlen = ucv_to_integer(uc_fn_arg(2));
836         size_t arrlen, addlen, idx;
837 
838         if (ucv_type(arr) != UC_ARRAY)
839                 return NULL;
840 
841         arrlen = ucv_array_length(arr);
842         addlen = nargs;
843 
844         if (addlen == 1) {
845                 ofs = 0;
846                 addlen = 0;
847                 remlen = arrlen;
848         }
849         else if (addlen == 2) {
850                 if (ofs < 0) {
851                         ofs = arrlen + ofs;
852 
853                         if (ofs < 0)
854                                 ofs = 0;
855                 }
856                 else if ((uint64_t)ofs > arrlen) {
857                         ofs = arrlen;
858                 }
859 
860                 addlen = 0;
861                 remlen = arrlen - ofs;
862         }
863         else {
864                 if (ofs < 0) {
865                         ofs = arrlen + ofs;
866 
867                         if (ofs < 0)
868                                 ofs = 0;
869                 }
870                 else if ((uint64_t)ofs > arrlen) {
871                         ofs = arrlen;
872                 }
873 
874                 if (remlen < 0) {
875                         remlen = arrlen - ofs + remlen;
876 
877                         if (remlen < 0)
878                                 remlen = 0;
879                 }
880                 else if ((uint64_t)remlen > arrlen - (uint64_t)ofs) {
881                         remlen = arrlen - ofs;
882                 }
883 
884                 addlen -= 3;
885         }
886 
887         if (addlen < (uint64_t)remlen) {
888                 ucv_array_delete(arr, ofs, remlen - addlen);
889         }
890         else if (addlen > (uint64_t)remlen) {
891                 for (idx = arrlen; idx > (uint64_t)ofs; idx--)
892                         ucv_array_set(arr, idx + addlen - remlen - 1,
893                                 ucv_get(ucv_array_get(arr, idx - 1)));
894         }
895 
896         for (idx = 0; idx < addlen; idx++)
897                 ucv_array_set(arr, ofs + idx,
898                         ucv_get(uc_fn_arg(3 + idx)));
899 
900         return ucv_get(arr);
901 }
902 
903 static uc_value_t *
904 uc_split(uc_vm_t *vm, size_t nargs)
905 {
906         uc_value_t *str = uc_fn_arg(0);
907         uc_value_t *sep = uc_fn_arg(1);
908         uc_value_t *arr = NULL;
909         const char *p, *sepstr, *splitstr;
910         int eflags = 0, res;
911         regmatch_t pmatch;
912         uc_regexp_t *re;
913         size_t seplen;
914 
915         if (!sep || ucv_type(str) != UC_STRING)
916                 return NULL;
917 
918         arr = ucv_array_new(vm);
919         splitstr = ucv_string_get(str);
920 
921         if (ucv_type(sep) == UC_REGEXP) {
922                 re = (uc_regexp_t *)sep;
923 
924                 while (true) {
925                         res = regexec(&re->regexp, splitstr, 1, &pmatch, eflags);
926 
927                         if (res == REG_NOMATCH)
928                                 break;
929 
930                         ucv_array_push(arr, ucv_string_new_length(splitstr, pmatch.rm_so));
931 
932                         splitstr += pmatch.rm_eo;
933                         eflags |= REG_NOTBOL;
934                 }
935 
936                 ucv_array_push(arr, ucv_string_new(splitstr));
937         }
938         else if (ucv_type(sep) == UC_STRING) {
939                 sepstr = ucv_string_get(sep);
940 
941                 for (p = splitstr, seplen = strlen(sepstr); *p; p++) {
942                         if (!strncmp(p, sepstr, seplen)) {
943                                 if (*sepstr || p > splitstr)
944                                         ucv_array_push(arr, ucv_string_new_length(splitstr, p - splitstr));
945 
946                                 splitstr = p + seplen;
947                                 p = splitstr - (*sepstr ? 1 : 0);
948                         }
949                 }
950 
951                 ucv_array_push(arr, ucv_string_new_length(splitstr, p - splitstr));
952         }
953         else {
954                 ucv_put(arr);
955 
956                 return NULL;
957         }
958 
959         return arr;
960 }
961 
962 static uc_value_t *
963 uc_substr(uc_vm_t *vm, size_t nargs)
964 {
965         uc_value_t *str = uc_fn_arg(0);
966         int64_t ofs = ucv_to_integer(uc_fn_arg(1));
967         int64_t sublen = ucv_to_integer(uc_fn_arg(2));
968         const char *p;
969         size_t len;
970 
971         if (ucv_type(str) != UC_STRING)
972                 return NULL;
973 
974         p = ucv_string_get(str);
975         len = ucv_string_length(str);
976 
977         switch (nargs) {
978         case 1:
979                 ofs = 0;
980                 sublen = len;
981 
982                 break;
983 
984         case 2:
985                 if (ofs < 0) {
986                         ofs = len + ofs;
987 
988                         if (ofs < 0)
989                                 ofs = 0;
990                 }
991                 else if ((uint64_t)ofs > len) {
992                         ofs = len;
993                 }
994 
995                 sublen = len - ofs;
996 
997                 break;
998 
999         default:
1000                 if (ofs < 0) {
1001                         ofs = len + ofs;
1002 
1003                         if (ofs < 0)
1004                                 ofs = 0;
1005                 }
1006                 else if ((uint64_t)ofs > len) {
1007                         ofs = len;
1008                 }
1009 
1010                 if (sublen < 0) {
1011                         sublen = len - ofs + sublen;
1012 
1013                         if (sublen < 0)
1014                                 sublen = 0;
1015                 }
1016                 else if ((uint64_t)sublen > len - (uint64_t)ofs) {
1017                         sublen = len - ofs;
1018                 }
1019 
1020                 break;
1021         }
1022 
1023         return ucv_string_new_length(p + ofs, sublen);
1024 }
1025 
1026 static uc_value_t *
1027 uc_time(uc_vm_t *vm, size_t nargs)
1028 {
1029         time_t t = time(NULL);
1030 
1031         return ucv_int64_new((int64_t)t);
1032 }
1033 
1034 static uc_value_t *
1035 uc_uc(uc_vm_t *vm, size_t nargs)
1036 {
1037         char *str = ucv_to_string(vm, uc_fn_arg(0));
1038         uc_value_t *rv = NULL;
1039         char *p;
1040 
1041         if (!str)
1042                 return NULL;
1043 
1044         for (p = str; *p; p++)
1045                 if (*p >= 'a' && *p <= 'z')
1046                         *p &= ~32;
1047 
1048         rv = ucv_string_new(str);
1049 
1050         free(str);
1051 
1052         return rv;
1053 }
1054 
1055 static uc_value_t *
1056 uc_uchr(uc_vm_t *vm, size_t nargs)
1057 {
1058         uc_value_t *rv = NULL;
1059         size_t idx, ulen;
1060         char *p, *str;
1061         int64_t n;
1062         int rem;
1063 
1064         for (idx = 0, ulen = 0; idx < nargs; idx++) {
1065                 n = ucv_to_integer(uc_fn_arg(idx));
1066 
1067                 if (errno == EINVAL || errno == ERANGE || n < 0 || n > 0x10FFFF)
1068                         ulen += 3;
1069                 else if (n <= 0x7F)
1070                         ulen++;
1071                 else if (n <= 0x7FF)
1072                         ulen += 2;
1073                 else if (n <= 0xFFFF)
1074                         ulen += 3;
1075                 else
1076                         ulen += 4;
1077         }
1078 
1079         str = xalloc(ulen);
1080 
1081         for (idx = 0, p = str, rem = ulen; idx < nargs; idx++) {
1082                 n = ucv_to_integer(uc_fn_arg(idx));
1083 
1084                 if (errno == EINVAL || errno == ERANGE || n < 0 || n > 0x10FFFF)
1085                         n = 0xFFFD;
1086 
1087                 if (!utf8enc(&p, &rem, n))
1088                         break;
1089         }
1090 
1091         rv = ucv_string_new_length(str, ulen);
1092 
1093         free(str);
1094 
1095         return rv;
1096 }
1097 
1098 static uc_value_t *
1099 uc_values(uc_vm_t *vm, size_t nargs)
1100 {
1101         uc_value_t *obj = uc_fn_arg(0);
1102         uc_value_t *arr;
1103 
1104         if (ucv_type(obj) != UC_OBJECT)
1105                 return NULL;
1106 
1107         arr = ucv_array_new(vm);
1108 
1109         ucv_object_foreach(obj, key, val) {
1110                 (void)key;
1111                 ucv_array_push(arr, ucv_get(val));
1112         }
1113 
1114         return arr;
1115 }
1116 
1117 static uc_value_t *
1118 uc_trim_common(uc_vm_t *vm, size_t nargs, bool start, bool end)
1119 {
1120         uc_value_t *str = uc_fn_arg(0);
1121         uc_value_t *chr = uc_fn_arg(1);
1122         const char *p, *c;
1123         size_t len;
1124 
1125         if (ucv_type(str) != UC_STRING ||
1126                 (chr != NULL && ucv_type(chr) != UC_STRING))
1127                 return NULL;
1128 
1129         c = ucv_string_get(chr);
1130         c = c ? c : " \t\r\n";
1131 
1132         p = ucv_string_get(str);
1133         len = ucv_string_length(str);
1134 
1135         if (start) {
1136                 while (*p) {
1137                         if (!strchr(c, *p))
1138                                 break;
1139 
1140                         p++;
1141                         len--;
1142                 }
1143         }
1144 
1145         if (end) {
1146                 while (len > 0) {
1147                         if (!strchr(c, p[len - 1]))
1148                                 break;
1149 
1150                         len--;
1151                 }
1152         }
1153 
1154         return ucv_string_new_length(p, len);
1155 }
1156 
1157 static uc_value_t *
1158 uc_trim(uc_vm_t *vm, size_t nargs)
1159 {
1160         return uc_trim_common(vm, nargs, true, true);
1161 }
1162 
1163 static uc_value_t *
1164 uc_ltrim(uc_vm_t *vm, size_t nargs)
1165 {
1166         return uc_trim_common(vm, nargs, true, false);
1167 }
1168 
1169 static uc_value_t *
1170 uc_rtrim(uc_vm_t *vm, size_t nargs)
1171 {
1172         return uc_trim_common(vm, nargs, false, true);
1173 }
1174 
1175 enum {
1176         FMT_F_ALT   = (1 << 0),
1177         FMT_F_ZERO  = (1 << 1),
1178         FMT_F_LEFT  = (1 << 2),
1179         FMT_F_SPACE = (1 << 3),
1180         FMT_F_SIGN  = (1 << 4),
1181         FMT_F_WIDTH = (1 << 5),
1182         FMT_F_PREC  = (1 << 6),
1183 };
1184 
1185 enum {
1186         FMT_C_NONE = (1 << 0),
1187         FMT_C_INT  = (1 << 1),
1188         FMT_C_UINT = (1 << 2),
1189         FMT_C_DBL  = (1 << 3),
1190         FMT_C_CHR  = (1 << 4),
1191         FMT_C_STR  = (1 << 5),
1192         FMT_C_JSON = (1 << 6),
1193 };
1194 
1195 static void
1196 uc_printf_common(uc_vm_t *vm, size_t nargs, uc_stringbuf_t *buf)
1197 {
1198         char *s, sfmt[sizeof("%#0- +0123456789.0123456789%")];
1199         uint32_t conv, flags, width, precision;
1200         uc_value_t *fmt = uc_fn_arg(0), *arg;
1201         const char *fstr, *last, *p, *cfmt;
1202         size_t argidx = 1, sfmtlen;
1203         uint64_t u;
1204         int64_t n;
1205         double d;
1206 
1207         if (ucv_type(fmt) == UC_STRING)
1208                 fstr = ucv_string_get(fmt);
1209         else
1210                 fstr = "";
1211 
1212         for (last = p = fstr; *p; p++) {
1213                 if (*p == '%') {
1214                         ucv_stringbuf_addstr(buf, last, p - last);
1215 
1216                         last = p++;
1217 
1218                         flags = 0;
1219                         width = 0;
1220                         precision = 0;
1221 
1222                         while (*p != '\0' && strchr("#0- +", *p)) {
1223                                 switch (*p++) {
1224                                 case '#': flags |= FMT_F_ALT;   break;
1225                                 case '': flags |= FMT_F_ZERO;  break;
1226                                 case '-': flags |= FMT_F_LEFT;  break;
1227                                 case ' ': flags |= FMT_F_SPACE; break;
1228                                 case '+': flags |= FMT_F_SIGN;  break;
1229                                 }
1230                         }
1231 
1232                         if (*p >= '1' && *p <= '9') {
1233                                 while (isdigit(*p))
1234                                         width = width * 10 + (*p++ - '');
1235 
1236                                 flags |= FMT_F_WIDTH;
1237                         }
1238 
1239                         if (*p == '.') {
1240                                 p++;
1241 
1242                                 if (*p == '-') {
1243                                         p++;
1244 
1245                                         while (isdigit(*p))
1246                                                 p++;
1247                                 }
1248                                 else {
1249                                         while (isdigit(*p))
1250                                                 precision = precision * 10 + (*p++ - '');
1251                                 }
1252 
1253                                 flags |= FMT_F_PREC;
1254                         }
1255 
1256                         switch (*p) {
1257                         case 'd':
1258                         case 'i':
1259                                 conv = FMT_C_INT;
1260                                 flags &= ~FMT_F_PREC;
1261                                 cfmt = PRId64;
1262                                 break;
1263 
1264                         case 'o':
1265                                 conv = FMT_C_UINT;
1266                                 flags &= ~FMT_F_PREC;
1267                                 cfmt = PRIo64;
1268                                 break;
1269 
1270                         case 'u':
1271                                 conv = FMT_C_UINT;
1272                                 flags &= ~FMT_F_PREC;
1273                                 cfmt = PRIu64;
1274                                 break;
1275 
1276                         case 'x':
1277                                 conv = FMT_C_UINT;
1278                                 flags &= ~FMT_F_PREC;
1279                                 cfmt = PRIx64;
1280                                 break;
1281 
1282                         case 'X':
1283                                 conv = FMT_C_UINT;
1284                                 flags &= ~FMT_F_PREC;
1285                                 cfmt = PRIX64;
1286                                 break;
1287 
1288                         case 'e':
1289                                 conv = FMT_C_DBL;
1290                                 cfmt = "e";
1291                                 break;
1292 
1293                         case 'E':
1294                                 conv = FMT_C_DBL;
1295                                 cfmt = "E";
1296                                 break;
1297 
1298                         case 'f':
1299                                 conv = FMT_C_DBL;
1300                                 cfmt = "f";
1301                                 break;
1302 
1303                         case 'F':
1304                                 conv = FMT_C_DBL;
1305                                 cfmt = "F";
1306                                 break;
1307 
1308                         case 'g':
1309                                 conv = FMT_C_DBL;
1310                                 cfmt = "g";
1311                                 break;
1312 
1313                         case 'G':
1314                                 conv = FMT_C_DBL;
1315                                 cfmt = "G";
1316                                 break;
1317 
1318                         case 'c':
1319                                 conv = FMT_C_CHR;
1320                                 flags &= ~FMT_F_PREC;
1321                                 cfmt = "c";
1322                                 break;
1323 
1324                         case 's':
1325                                 conv = FMT_C_STR;
1326                                 cfmt = "s";
1327                                 break;
1328 
1329                         case 'J':
1330                                 conv = FMT_C_JSON;
1331 
1332                                 if (flags & FMT_F_PREC) {
1333                                         flags &= ~FMT_F_PREC;
1334                                         precision++;
1335                                 }
1336 
1337                                 cfmt = "s";
1338                                 break;
1339 
1340                         case '%':
1341                                 conv = FMT_C_NONE;
1342                                 flags = 0;
1343                                 cfmt = "%";
1344                                 break;
1345 
1346                         case '\0':
1347                                 p--;
1348                                 /* fall through */
1349 
1350                         default:
1351                                 continue;
1352                         }
1353 
1354                         sfmtlen = 0;
1355                         sfmt[sfmtlen++] = '%';
1356 
1357                         if (flags & FMT_F_ALT)   sfmt[sfmtlen++] = '#';
1358                         if (flags & FMT_F_ZERO)  sfmt[sfmtlen++] = '';
1359                         if (flags & FMT_F_LEFT)  sfmt[sfmtlen++] = '-';
1360                         if (flags & FMT_F_SPACE) sfmt[sfmtlen++] = ' ';
1361                         if (flags & FMT_F_SIGN)  sfmt[sfmtlen++] = '+';
1362 
1363                         if (flags & FMT_F_WIDTH)
1364                                 sfmtlen += snprintf(&sfmt[sfmtlen], sizeof(sfmt) - sfmtlen, "%" PRIu32, width);
1365 
1366                         if (flags & FMT_F_PREC)
1367                                 sfmtlen += snprintf(&sfmt[sfmtlen], sizeof(sfmt) - sfmtlen, ".%" PRIu32, precision);
1368 
1369                         snprintf(&sfmt[sfmtlen], sizeof(sfmt) - sfmtlen, "%s", cfmt);
1370 
1371                         switch (conv) {
1372                         case FMT_C_NONE:
1373                                 ucv_stringbuf_addstr(buf, cfmt, strlen(cfmt));
1374                                 break;
1375 
1376                         case FMT_C_INT:
1377                                 arg = uc_fn_arg(argidx++);
1378                                 n = ucv_to_integer(arg);
1379 
1380                                 if (errno == ERANGE)
1381                                         n = (int64_t)ucv_to_unsigned(arg);
1382 
1383                                 ucv_stringbuf_printf(buf, sfmt, n);
1384                                 break;
1385 
1386                         case FMT_C_UINT:
1387                                 arg = uc_fn_arg(argidx++);
1388                                 u = ucv_to_unsigned(arg);
1389 
1390                                 if (errno == ERANGE)
1391                                         u = (uint64_t)ucv_to_integer(arg);
1392 
1393                                 ucv_stringbuf_printf(buf, sfmt, u);
1394                                 break;
1395 
1396                         case FMT_C_DBL:
1397                                 d = ucv_to_double(uc_fn_arg(argidx++));
1398                                 ucv_stringbuf_printf(buf, sfmt, d);
1399                                 break;
1400 
1401                         case FMT_C_CHR:
1402                                 n = ucv_to_integer(uc_fn_arg(argidx++));
1403                                 ucv_stringbuf_printf(buf, sfmt, (int)n);
1404                                 break;
1405 
1406                         case FMT_C_STR:
1407                                 arg = uc_fn_arg(argidx++);
1408 
1409                                 switch (ucv_type(arg)) {
1410                                 case UC_STRING:
1411                                         ucv_stringbuf_printf(buf, sfmt, ucv_string_get(arg));
1412                                         break;
1413 
1414                                 case UC_NULL:
1415                                         ucv_stringbuf_append(buf, "(null)");
1416                                         break;
1417 
1418                                 default:
1419                                         s = ucv_to_string(vm, arg);
1420                                         ucv_stringbuf_printf(buf, sfmt, s ? s : "(null)");
1421                                         free(s);
1422                                 }
1423 
1424                                 break;
1425 
1426                         case FMT_C_JSON:
1427                                 s = ucv_to_jsonstring_formatted(vm,
1428                                         uc_fn_arg(argidx++),
1429                                         precision > 0 ? (precision > 1 ? ' ' : '\t') : '\0',
1430                                         precision > 0 ? (precision > 1 ? precision - 1 : 1) : 0);
1431 
1432                                 ucv_stringbuf_printf(buf, sfmt, s ? s : "null");
1433                                 free(s);
1434                                 break;
1435                         }
1436 
1437                         last = p + 1;
1438                 }
1439         }
1440 
1441         ucv_stringbuf_addstr(buf, last, p - last);
1442 }
1443 
1444 static uc_value_t *
1445 uc_sprintf(uc_vm_t *vm, size_t nargs)
1446 {
1447         uc_stringbuf_t *buf = ucv_stringbuf_new();
1448 
1449         uc_printf_common(vm, nargs, buf);
1450 
1451         return ucv_stringbuf_finish(buf);
1452 }
1453 
1454 static uc_value_t *
1455 uc_printf(uc_vm_t *vm, size_t nargs)
1456 {
1457         uc_stringbuf_t *buf = xprintbuf_new();
1458         size_t len;
1459 
1460         uc_printf_common(vm, nargs, buf);
1461 
1462         len = fwrite(buf->buf, 1, printbuf_length(buf), vm->output);
1463 
1464         printbuf_free(buf);
1465 
1466         return ucv_int64_new(len);
1467 }
1468 
1469 static bool
1470 uc_require_so(uc_vm_t *vm, const char *path, uc_value_t **res)
1471 {
1472         void (*init)(uc_vm_t *, uc_value_t *);
1473         uc_value_t *scope;
1474         struct stat st;
1475         void *dlh;
1476 
1477         if (stat(path, &st))
1478                 return false;
1479 
1480         dlerror();
1481         dlh = dlopen(path, RTLD_LAZY|RTLD_LOCAL);
1482 
1483         if (!dlh) {
1484                 uc_vm_raise_exception(vm, EXCEPTION_RUNTIME,
1485                                       "Unable to dlopen file '%s': %s", path, dlerror());
1486 
1487                 return true;
1488         }
1489 
1490         *(void **)(&init) = dlsym(dlh, "uc_module_entry");
1491 
1492         if (!init) {
1493                 uc_vm_raise_exception(vm, EXCEPTION_RUNTIME,
1494                                       "Module '%s' provides no 'uc_module_entry' function", path);
1495 
1496                 return true;
1497         }
1498 
1499         scope = ucv_object_new(vm);
1500 
1501         init(vm, scope);
1502 
1503         *res = scope;
1504 
1505         return true;
1506 }
1507 
1508 static bool
1509 uc_require_ucode(uc_vm_t *vm, const char *path, uc_value_t *scope, uc_value_t **res)
1510 {
1511         uc_exception_type_t extype;
1512         uc_function_t *function;
1513         uc_value_t *prev_scope;
1514         uc_value_t *closure;
1515         uc_source_t *source;
1516         struct stat st;
1517         char *err;
1518 
1519         if (stat(path, &st))
1520                 return false;
1521 
1522         source = uc_source_new_file(path);
1523 
1524         if (!source) {
1525                 uc_vm_raise_exception(vm, EXCEPTION_RUNTIME,
1526                                       "Unable to open file '%s': %s", path, strerror(errno));
1527 
1528                 return true;
1529         }
1530 
1531         function = uc_compile(vm->config, source, &err);
1532 
1533         if (!function) {
1534                 uc_vm_raise_exception(vm, EXCEPTION_RUNTIME,
1535                                       "Unable to compile module '%s':\n%s", path, err);
1536 
1537                 uc_source_put(source);
1538                 free(err);
1539 
1540                 return true;
1541         }
1542 
1543         closure = ucv_closure_new(vm, function, false);
1544 
1545         uc_vm_stack_push(vm, closure);
1546 
1547         if (scope) {
1548                 prev_scope = ucv_get(uc_vm_scope_get(vm));
1549                 uc_vm_scope_set(vm, ucv_get(scope));
1550         }
1551 
1552         extype = uc_vm_call(vm, false, 0);
1553 
1554         if (scope)
1555                 uc_vm_scope_set(vm, prev_scope);
1556 
1557         if (extype == EXCEPTION_NONE)
1558                 *res = uc_vm_stack_pop(vm);
1559 
1560         uc_source_put(source);
1561 
1562         return true;
1563 }
1564 
1565 static bool
1566 uc_require_path(uc_vm_t *vm, const char *path_template, const char *name, uc_value_t **res)
1567 {
1568         uc_stringbuf_t *buf = xprintbuf_new();
1569         const char *p, *q, *last;
1570         uc_value_t *modtable;
1571         bool rv;
1572 
1573         modtable = ucv_property_get(uc_vm_scope_get(vm), "modules");
1574         *res = ucv_get(ucv_object_get(modtable, name, &rv));
1575 
1576         if (rv)
1577                 goto out;
1578 
1579         p = strchr(path_template, '*');
1580 
1581         if (!p)
1582                 goto out;
1583 
1584         ucv_stringbuf_addstr(buf, path_template, p - path_template);
1585 
1586         for (q = last = name;; q++) {
1587                 if (*q == '.' || *q == '\0') {
1588                         ucv_stringbuf_addstr(buf, last, q - last);
1589 
1590                         if (*q)
1591                                 ucv_stringbuf_append(buf, "/");
1592                         else
1593                                 ucv_stringbuf_addstr(buf, p + 1, strlen(p + 1));
1594 
1595                         if (*q == '\0')
1596                                 break;
1597 
1598                         last = q + 1;
1599                 }
1600                 else if (!isalnum(*q) && *q != '_') {
1601                         goto out;
1602                 }
1603         }
1604 
1605         if (!strcmp(p + 1, ".so"))
1606                 rv = uc_require_so(vm, buf->buf, res);
1607         else if (!strcmp(p + 1, ".uc"))
1608                 rv = uc_require_ucode(vm, buf->buf, NULL, res);
1609 
1610         if (rv)
1611                 ucv_object_add(modtable, name, ucv_get(*res));
1612 
1613 out:
1614         printbuf_free(buf);
1615 
1616         return rv;
1617 }
1618 
1619 static uc_value_t *
1620 uc_require(uc_vm_t *vm, size_t nargs)
1621 {
1622         uc_value_t *val = uc_fn_arg(0);
1623         uc_value_t *search, *se, *res;
1624         size_t arridx, arrlen;
1625         const char *name;
1626 
1627         if (ucv_type(val) != UC_STRING)
1628                 return NULL;
1629 
1630         name = ucv_string_get(val);
1631         search = ucv_property_get(uc_vm_scope_get(vm), "REQUIRE_SEARCH_PATH");
1632 
1633         if (ucv_type(search) != UC_ARRAY) {
1634                 uc_vm_raise_exception(vm, EXCEPTION_RUNTIME,
1635                                       "Global require search path not set");
1636 
1637                 return NULL;
1638         }
1639 
1640         for (arridx = 0, arrlen = ucv_array_length(search); arridx < arrlen; arridx++) {
1641                 se = ucv_array_get(search, arridx);
1642 
1643                 if (ucv_type(se) != UC_STRING)
1644                         continue;
1645 
1646                 if (uc_require_path(vm, ucv_string_get(se), name, &res))
1647                         return res;
1648         }
1649 
1650         uc_vm_raise_exception(vm, EXCEPTION_RUNTIME,
1651                               "No module named '%s' could be found", name);
1652 
1653         return NULL;
1654 }
1655 
1656 static uc_value_t *
1657 uc_iptoarr(uc_vm_t *vm, size_t nargs)
1658 {
1659         uc_value_t *ip = uc_fn_arg(0);
1660         uc_value_t *res;
1661         union {
1662                 uint8_t u8[4];
1663                 struct in_addr in;
1664                 struct in6_addr in6;
1665         } a;
1666         int i;
1667 
1668         if (ucv_type(ip) != UC_STRING)
1669                 return NULL;
1670 
1671         if (inet_pton(AF_INET6, ucv_string_get(ip), &a)) {
1672                 res = ucv_array_new(vm);
1673 
1674                 for (i = 0; i < 16; i++)
1675                         ucv_array_push(res, ucv_int64_new(a.in6.s6_addr[i]));
1676 
1677                 return res;
1678         }
1679         else if (inet_pton(AF_INET, ucv_string_get(ip), &a)) {
1680                 res = ucv_array_new(vm);
1681 
1682                 ucv_array_push(res, ucv_int64_new(a.u8[0]));
1683                 ucv_array_push(res, ucv_int64_new(a.u8[1]));
1684                 ucv_array_push(res, ucv_int64_new(a.u8[2]));
1685                 ucv_array_push(res, ucv_int64_new(a.u8[3]));
1686 
1687                 return res;
1688         }
1689 
1690         return NULL;
1691 }
1692 
1693 static int
1694 check_byte(uc_value_t *v)
1695 {
1696         int n;
1697 
1698         if (ucv_type(v) != UC_INTEGER)
1699                 return -1;
1700 
1701         n = ucv_int64_get(v);
1702 
1703         if (n < 0 || n > 255)
1704                 return -1;
1705 
1706         return n;
1707 }
1708 
1709 static uc_value_t *
1710 uc_arrtoip(uc_vm_t *vm, size_t nargs)
1711 {
1712         uc_value_t *arr = uc_fn_arg(0);
1713         union {
1714                 uint8_t u8[4];
1715                 struct in6_addr in6;
1716         } a;
1717         char buf[INET6_ADDRSTRLEN];
1718         int i, n;
1719 
1720         if (ucv_type(arr) != UC_ARRAY)
1721                 return NULL;
1722 
1723         switch (ucv_array_length(arr)) {
1724         case 4:
1725                 for (i = 0; i < 4; i++) {
1726                         n = check_byte(ucv_array_get(arr, i));
1727 
1728                         if (n < 0)
1729                                 return NULL;
1730 
1731                         a.u8[i] = n;
1732                 }
1733 
1734                 inet_ntop(AF_INET, &a, buf, sizeof(buf));
1735 
1736                 return ucv_string_new(buf);
1737 
1738         case 16:
1739                 for (i = 0; i < 16; i++) {
1740                         n = check_byte(ucv_array_get(arr, i));
1741 
1742                         if (n < 0)
1743                                 return NULL;
1744 
1745                         a.in6.s6_addr[i] = n;
1746                 }
1747 
1748                 inet_ntop(AF_INET6, &a, buf, sizeof(buf));
1749 
1750                 return ucv_string_new(buf);
1751 
1752         default:
1753                 return NULL;
1754         }
1755 }
1756 
1757 static uc_value_t *
1758 uc_match(uc_vm_t *vm, size_t nargs)
1759 {
1760         uc_value_t *subject = uc_fn_arg(0);
1761         uc_value_t *pattern = uc_fn_arg(1);
1762         uc_value_t *rv = NULL, *m;
1763         regmatch_t pmatch[10];
1764         int eflags = 0, res;
1765         uc_regexp_t *re;
1766         bool freeable;
1767         char *p;
1768         size_t i;
1769 
1770         if (ucv_type(pattern) != UC_REGEXP || !subject)
1771                 return NULL;
1772 
1773         p = uc_cast_string(vm, &subject, &freeable);
1774         re = (uc_regexp_t *)pattern;
1775 
1776         while (true) {
1777                 res = regexec(&re->regexp, p, ARRAY_SIZE(pmatch), pmatch, eflags);
1778 
1779                 if (res == REG_NOMATCH)
1780                         break;
1781 
1782                 m = ucv_array_new(vm);
1783 
1784                 for (i = 0; i < ARRAY_SIZE(pmatch) && pmatch[i].rm_so != -1; i++) {
1785                         ucv_array_push(m,
1786                                 ucv_string_new_length(p + pmatch[i].rm_so,
1787                                                       pmatch[i].rm_eo - pmatch[i].rm_so));
1788                 }
1789 
1790                 if (re->global) {
1791                         if (!rv)
1792                                 rv = ucv_array_new(vm);
1793 
1794                         ucv_array_push(rv, m);
1795 
1796                         p += pmatch[0].rm_eo;
1797                         eflags |= REG_NOTBOL;
1798                 }
1799                 else {
1800                         rv = m;
1801                         break;
1802                 }
1803         }
1804 
1805         if (freeable)
1806                 free(p);
1807 
1808         return rv;
1809 }
1810 
1811 static uc_value_t *
1812 uc_replace_cb(uc_vm_t *vm, uc_value_t *func,
1813               const char *subject, regmatch_t *pmatch, size_t plen,
1814               uc_stringbuf_t *resbuf)
1815 {
1816         uc_value_t *rv;
1817         size_t i;
1818 
1819         uc_vm_ctx_push(vm);
1820         uc_vm_stack_push(vm, ucv_get(func));
1821 
1822         for (i = 0; i < plen && pmatch[i].rm_so != -1; i++) {
1823                 uc_vm_stack_push(vm,
1824                         ucv_string_new_length(subject + pmatch[i].rm_so,
1825                                               pmatch[i].rm_eo - pmatch[i].rm_so));
1826         }
1827 
1828         if (uc_vm_call(vm, true, i))
1829                 return NULL;
1830 
1831         rv = uc_vm_stack_pop(vm);
1832 
1833         ucv_to_stringbuf(vm, resbuf, rv, false);
1834 
1835         ucv_put(rv);
1836 
1837         return NULL;
1838 }
1839 
1840 static void
1841 uc_replace_str(uc_vm_t *vm, uc_value_t *str,
1842                const char *subject, regmatch_t *pmatch, size_t plen,
1843                uc_stringbuf_t *resbuf)
1844 {
1845         bool esc = false;
1846         char *p, *r;
1847         uint8_t i;
1848 
1849         for (p = r = ucv_to_string(vm, str); *p; p++) {
1850                 if (esc) {
1851                         switch (*p) {
1852                         case '&':
1853                                 if (pmatch[0].rm_so != -1)
1854                                         ucv_stringbuf_addstr(resbuf,
1855                                                 subject + pmatch[0].rm_so,
1856                                                 pmatch[0].rm_eo - pmatch[0].rm_so);
1857                                 break;
1858 
1859                         case '`':
1860                                 if (pmatch[0].rm_so != -1)
1861                                         ucv_stringbuf_addstr(resbuf, subject, pmatch[0].rm_so);
1862                                 break;
1863 
1864                         case '\'':
1865                                 if (pmatch[0].rm_so != -1)
1866                                         ucv_stringbuf_addstr(resbuf,
1867                                                 subject + pmatch[0].rm_eo,
1868                                                 strlen(subject + pmatch[0].rm_eo));
1869                                 break;
1870 
1871                         case '1':
1872                         case '2':
1873                         case '3':
1874                         case '4':
1875                         case '5':
1876                         case '6':
1877                         case '7':
1878                         case '8':
1879                         case '9':
1880                                 i = *p - '';
1881                                 if (i < plen && pmatch[i].rm_so != -1) {
1882                                         ucv_stringbuf_addstr(resbuf,
1883                                                 subject + pmatch[i].rm_so,
1884                                                 pmatch[i].rm_eo - pmatch[i].rm_so);
1885                                 }
1886                                 else {
1887                                         ucv_stringbuf_append(resbuf, "$");
1888                                         ucv_stringbuf_addstr(resbuf, p, 1);
1889                                 }
1890                                 break;
1891 
1892                         case '$':
1893                                 ucv_stringbuf_append(resbuf, "$");
1894                                 break;
1895 
1896                         default:
1897                                 ucv_stringbuf_append(resbuf, "$");
1898                                 ucv_stringbuf_addstr(resbuf, p, 1);
1899                         }
1900 
1901                         esc = false;
1902                 }
1903                 else if (*p == '$') {
1904                         esc = true;
1905                 }
1906                 else {
1907                         ucv_stringbuf_addstr(resbuf, p, 1);
1908                 }
1909         }
1910 
1911         free(r);
1912 }
1913 
1914 static uc_value_t *
1915 uc_replace(uc_vm_t *vm, size_t nargs)
1916 {
1917         char *sb = NULL, *pt = NULL, *p, *l;
1918         uc_value_t *subject = uc_fn_arg(0);
1919         uc_value_t *pattern = uc_fn_arg(1);
1920         uc_value_t *replace = uc_fn_arg(2);
1921         bool sb_freeable, pt_freeable;
1922         uc_value_t *rv = NULL;
1923         uc_stringbuf_t *resbuf;
1924         regmatch_t pmatch[10];
1925         int eflags = 0, res;
1926         uc_regexp_t *re;
1927         size_t pl;
1928 
1929         if (!pattern || !subject || !replace)
1930                 return NULL;
1931 
1932         sb = uc_cast_string(vm, &subject, &sb_freeable);
1933         resbuf = ucv_stringbuf_new();
1934 
1935         if (ucv_type(pattern) == UC_REGEXP) {
1936                 re = (uc_regexp_t *)pattern;
1937                 p = sb;
1938 
1939                 while (true) {
1940                         res = regexec(&re->regexp, p, ARRAY_SIZE(pmatch), pmatch, eflags);
1941 
1942                         if (res == REG_NOMATCH)
1943                                 break;
1944 
1945                         ucv_stringbuf_addstr(resbuf, p, pmatch[0].rm_so);
1946 
1947                         if (ucv_is_callable(replace)) {
1948                                 rv = uc_replace_cb(vm, replace, p, pmatch, ARRAY_SIZE(pmatch), resbuf);
1949 
1950                                 if (rv) {
1951                                         if (sb_freeable)
1952                                                 free(sb);
1953 
1954                                         return rv;
1955                                 }
1956                         }
1957                         else {
1958                                 uc_replace_str(vm, replace, p, pmatch, ARRAY_SIZE(pmatch), resbuf);
1959                         }
1960 
1961                         p += pmatch[0].rm_eo;
1962 
1963                         if (re->global)
1964                                 eflags |= REG_NOTBOL;
1965                         else
1966                                 break;
1967                 }
1968 
1969                 ucv_stringbuf_addstr(resbuf, p, strlen(p));
1970         }
1971         else {
1972                 pt = uc_cast_string(vm, &pattern, &pt_freeable);
1973                 pl = strlen(pt);
1974 
1975                 for (l = p = sb; *p; p++) {
1976                         if (!strncmp(p, pt, pl)) {
1977                                 ucv_stringbuf_addstr(resbuf, l, p - l);
1978 
1979                                 pmatch[0].rm_so = p - l;
1980                                 pmatch[0].rm_eo = pmatch[0].rm_so + pl;
1981 
1982                                 if (ucv_is_callable(replace)) {
1983                                         rv = uc_replace_cb(vm, replace, l, pmatch, 1, resbuf);
1984 
1985                                         if (rv) {
1986                                                 if (sb_freeable)
1987                                                         free(sb);
1988 
1989                                                 if (pt_freeable)
1990                                                         free(pt);
1991 
1992                                                 return rv;
1993                                         }
1994                                 }
1995                                 else {
1996                                         uc_replace_str(vm, replace, l, pmatch, 1, resbuf);
1997                                 }
1998 
1999                                 l = p + pl;
2000                                 p += pl - 1;
2001                         }
2002                 }
2003 
2004                 ucv_stringbuf_addstr(resbuf, l, strlen(l));
2005 
2006                 if (pt_freeable)
2007                         free(pt);
2008         }
2009 
2010         if (sb_freeable)
2011                 free(sb);
2012 
2013         return ucv_stringbuf_finish(resbuf);
2014 }
2015 
2016 static uc_value_t *
2017 uc_json(uc_vm_t *vm, size_t nargs)
2018 {
2019         uc_value_t *rv, *src = uc_fn_arg(0);
2020         struct json_tokener *tok = NULL;
2021         enum json_tokener_error err;
2022         json_object *jso;
2023         const char *str;
2024         size_t len;
2025 
2026         if (ucv_type(src) != UC_STRING) {
2027                 uc_vm_raise_exception(vm, EXCEPTION_TYPE,
2028                                       "Passed value is not a string");
2029 
2030                 return NULL;
2031         }
2032 
2033         tok = xjs_new_tokener();
2034         str = ucv_string_get(src);
2035         len = ucv_string_length(src);
2036 
2037         /* NB: the len + 1 here is intentional to pass the terminating \0 byte
2038          * to the json-c parser. This is required to work-around upstream
2039          * issue #681 <https://github.com/json-c/json-c/issues/681> */
2040         jso = json_tokener_parse_ex(tok, str, len + 1);
2041         err = json_tokener_get_error(tok);
2042 
2043         if (err == json_tokener_continue) {
2044                 json_object_put(jso);
2045                 uc_vm_raise_exception(vm, EXCEPTION_SYNTAX,
2046                                       "Unexpected end of string in JSON data");
2047 
2048                 return NULL;
2049         }
2050         else if (err != json_tokener_success) {
2051                 json_object_put(jso);
2052                 uc_vm_raise_exception(vm, EXCEPTION_SYNTAX,
2053                                       "Failed to parse JSON string: %s",
2054                                       json_tokener_error_desc(err));
2055 
2056                 return NULL;
2057         }
2058         else if (json_tokener_get_parse_end(tok) < len) {
2059                 json_object_put(jso);
2060                 uc_vm_raise_exception(vm, EXCEPTION_SYNTAX,
2061                                       "Trailing garbage after JSON data");
2062 
2063                 return NULL;
2064         }
2065 
2066         json_tokener_free(tok);
2067 
2068         rv = ucv_from_json(vm, jso);
2069 
2070         json_object_put(jso);
2071 
2072         return rv;
2073 }
2074 
2075 static char *
2076 include_path(const char *curpath, const char *incpath)
2077 {
2078         char *dup, *res;
2079         int len;
2080 
2081         if (*incpath == '/')
2082                 return realpath(incpath, NULL);
2083 
2084         if (curpath) {
2085                 dup = strdup(curpath);
2086 
2087                 if (!dup)
2088                         return NULL;
2089 
2090                 len = asprintf(&res, "%s/%s", dirname(dup), incpath);
2091 
2092                 free(dup);
2093         }
2094         else {
2095                 len = asprintf(&res, "./%s", incpath);
2096         }
2097 
2098         if (len == -1)
2099                 return NULL;
2100 
2101         dup = realpath(res, NULL);
2102 
2103         free(res);
2104 
2105         return dup;
2106 }
2107 
2108 static uc_value_t *
2109 uc_include(uc_vm_t *vm, size_t nargs)
2110 {
2111         uc_value_t *path = uc_fn_arg(0);
2112         uc_value_t *scope = uc_fn_arg(1);
2113         uc_value_t *rv = NULL, *sc = NULL;
2114         uc_closure_t *closure = NULL;
2115         size_t i;
2116         char *p;
2117 
2118         if (ucv_type(path) != UC_STRING) {
2119                 uc_vm_raise_exception(vm, EXCEPTION_TYPE,
2120                                       "Passed filename is not a string");
2121 
2122                 return NULL;
2123         }
2124 
2125         if (scope && ucv_type(scope) != UC_OBJECT) {
2126                 uc_vm_raise_exception(vm, EXCEPTION_TYPE,
2127                                       "Passed scope value is not an object");
2128 
2129                 return NULL;
2130         }
2131 
2132         /* find calling closure */
2133         for (i = vm->callframes.count; i > 0; i--) {
2134                 closure = vm->callframes.entries[i - 1].closure;
2135 
2136                 if (closure)
2137                         break;
2138         }
2139 
2140         if (!closure)
2141                 return NULL;
2142 
2143         p = include_path(closure->function->program->source->filename, ucv_string_get(path));
2144 
2145         if (!p) {
2146                 uc_vm_raise_exception(vm, EXCEPTION_RUNTIME,
2147                                       "Include file not found");
2148 
2149                 return NULL;
2150         }
2151 
2152         if (ucv_prototype_get(scope)) {
2153                 sc = ucv_get(scope);
2154         }
2155         else if (scope) {
2156                 sc = ucv_object_new(vm);
2157 
2158                 ucv_object_foreach(scope, key, val)
2159                         ucv_object_add(sc, key, ucv_get(val));
2160 
2161                 ucv_prototype_set(sc, ucv_get(uc_vm_scope_get(vm)));
2162         }
2163         else {
2164                 sc = ucv_get(uc_vm_scope_get(vm));
2165         }
2166 
2167         if (uc_require_ucode(vm, p, sc, &rv))
2168                 ucv_put(rv);
2169 
2170         ucv_put(sc);
2171         free(p);
2172 
2173         return NULL;
2174 }
2175 
2176 static uc_value_t *
2177 uc_render(uc_vm_t *vm, size_t nargs)
2178 {
2179         uc_string_t *ustr = NULL;
2180         FILE *mem, *prev;
2181         size_t len = 0;
2182 
2183         mem = open_memstream((char **)&ustr, &len);
2184 
2185         if (!mem)
2186                 goto out;
2187 
2188         /* reserve space for uc_string_t header... */
2189         if (fseek(mem, sizeof(*ustr), SEEK_SET))
2190                 goto out;
2191 
2192         /* divert VM output to memory fd */
2193         prev = vm->output;
2194         vm->output = mem;
2195 
2196         /* execute include */
2197         (void) uc_include(vm, nargs);
2198 
2199         /* restore previous VM output */
2200         vm->output = prev;
2201         fclose(mem);
2202 
2203         /* update uc_string_t length */
2204         ustr->header.type = UC_STRING;
2205         ustr->header.refcount = 1;
2206         ustr->length = len - sizeof(*ustr);
2207 
2208         return &ustr->header;
2209 
2210 out:
2211         uc_vm_raise_exception(vm, EXCEPTION_RUNTIME,
2212                               "Unable to initialize output memory: %s",
2213                               strerror(errno));
2214 
2215         if (mem)
2216                 fclose(mem);
2217 
2218         free(ustr);
2219 
2220         return NULL;
2221 }
2222 
2223 static uc_value_t *
2224 uc_warn(uc_vm_t *vm, size_t nargs)
2225 {
2226         return uc_print_common(vm, nargs, stderr);
2227 }
2228 
2229 static uc_value_t *
2230 uc_system(uc_vm_t *vm, size_t nargs)
2231 {
2232         uc_value_t *cmdline = uc_fn_arg(0);
2233         uc_value_t *timeout = uc_fn_arg(1);
2234         const char **arglist, *fn;
2235         sigset_t sigmask, sigomask;
2236         struct timespec ts;
2237         size_t i, len;
2238         int64_t tms;
2239         pid_t cld;
2240         int rc;
2241 
2242         if (timeout && (ucv_type(timeout) != UC_INTEGER || ucv_int64_get(timeout) < 0)) {
2243                 uc_vm_raise_exception(vm, EXCEPTION_TYPE,
2244                                       "Invalid timeout specified");
2245 
2246                 return NULL;
2247         }
2248 
2249         switch (ucv_type(cmdline)) {
2250         case UC_STRING:
2251                 arglist = xalloc(sizeof(*arglist) * 4);
2252                 arglist[0] = xstrdup("/bin/sh");
2253                 arglist[1] = xstrdup("-c");
2254                 arglist[2] = ucv_to_string(vm, cmdline);
2255                 arglist[3] = NULL;
2256                 break;
2257 
2258         case UC_ARRAY:
2259                 len = ucv_array_length(cmdline);
2260 
2261                 if (len == 0) {
2262                         uc_vm_raise_exception(vm, EXCEPTION_TYPE,
2263                                               "Passed command array is empty");
2264 
2265                         return NULL;
2266                 }
2267 
2268                 arglist = xalloc(sizeof(*arglist) * (len + 1));
2269 
2270                 for (i = 0; i < len; i++)
2271                         arglist[i] = ucv_to_string(vm, ucv_array_get(cmdline, i));
2272 
2273                 arglist[i] = NULL;
2274 
2275                 break;
2276 
2277         default:
2278                 uc_vm_raise_exception(vm, EXCEPTION_TYPE,
2279                                       "Passed command is neither string nor array");
2280 
2281                 return NULL;
2282         }
2283 
2284         tms = timeout ? ucv_int64_get(timeout) : 0;
2285 
2286         if (tms > 0) {
2287                 sigemptyset(&sigmask);
2288                 sigaddset(&sigmask, SIGCHLD);
2289 
2290                 if (sigprocmask(SIG_BLOCK, &sigmask, &sigomask) < 0) {
2291                         fn = "sigprocmask";
2292                         goto fail;
2293                 }
2294         }
2295 
2296         cld = fork();
2297 
2298         switch (cld) {
2299         case -1:
2300                 fn = "fork";
2301                 goto fail;
2302 
2303         case 0:
2304                 execvp(arglist[0], (char * const *)arglist);
2305                 exit(-1);
2306 
2307                 break;
2308 
2309         default:
2310                 if (tms > 0) {
2311                         ts.tv_sec = tms / 1000;
2312                         ts.tv_nsec = (tms % 1000) * 1000000;
2313 
2314                         while (1) {
2315                                 if (sigtimedwait(&sigmask, NULL, &ts) < 0) {
2316                                         if (errno == EINTR)
2317                                                 continue;
2318 
2319                                         if (errno != EAGAIN) {
2320                                                 fn = "sigtimedwait";
2321                                                 goto fail;
2322                                         }
2323 
2324                                         kill(cld, SIGKILL);
2325                                 }
2326 
2327                                 break;
2328                         }
2329                 }
2330 
2331                 if (waitpid(cld, &rc, 0) < 0) {
2332                         fn = "waitpid";
2333                         goto fail;
2334                 }
2335 
2336                 if (tms > 0)
2337                         sigprocmask(SIG_SETMASK, &sigomask, NULL);
2338 
2339                 for (i = 0; arglist[i]; i++)
2340                         free((char *)arglist[i]);
2341 
2342                 free(arglist);
2343 
2344                 if (WIFEXITED(rc))
2345                         return ucv_int64_new(WEXITSTATUS(rc));
2346                 else if (WIFSIGNALED(rc))
2347                         return ucv_int64_new(-WTERMSIG(rc));
2348                 else if (WIFSTOPPED(rc))
2349                         return ucv_int64_new(-WSTOPSIG(rc));
2350 
2351                 return NULL;
2352         }
2353 
2354 fail:
2355         if (tms > 0)
2356                 sigprocmask(SIG_SETMASK, &sigomask, NULL);
2357 
2358         for (i = 0; arglist[i]; i++)
2359                 free((char *)arglist[i]);
2360 
2361         free(arglist);
2362 
2363         uc_vm_raise_exception(vm, EXCEPTION_RUNTIME,
2364                               "%s(): %s", fn, strerror(errno));
2365 
2366         return NULL;
2367 }
2368 
2369 static uc_value_t *
2370 uc_trace(uc_vm_t *vm, size_t nargs)
2371 {
2372         uc_value_t *level = uc_fn_arg(0);
2373         uint8_t prev_level;
2374 
2375         if (ucv_type(level) != UC_INTEGER) {
2376                 uc_vm_raise_exception(vm, EXCEPTION_TYPE, "Invalid level specified");
2377 
2378                 return NULL;
2379         }
2380 
2381         prev_level = vm->trace;
2382         vm->trace = ucv_int64_get(level);
2383 
2384         return ucv_int64_new(prev_level);
2385 }
2386 
2387 static uc_value_t *
2388 uc_proto(uc_vm_t *vm, size_t nargs)
2389 {
2390         uc_value_t *val = uc_fn_arg(0);
2391         uc_value_t *proto = NULL;
2392 
2393         if (nargs < 2)
2394                 return ucv_get(ucv_prototype_get(val));
2395 
2396         proto = uc_fn_arg(1);
2397 
2398         if (!ucv_prototype_set(val, proto))
2399                 uc_vm_raise_exception(vm, EXCEPTION_TYPE, "Passed value is neither a prototype, resource or object");
2400 
2401         ucv_get(proto);
2402 
2403         return ucv_get(val);
2404 }
2405 
2406 static uc_value_t *
2407 uc_sleep(uc_vm_t *vm, size_t nargs)
2408 {
2409         uc_value_t *duration = uc_fn_arg(0);
2410         struct timeval tv;
2411         int64_t ms;
2412 
2413         ms = ucv_to_integer(duration);
2414 
2415         if (errno != 0 || ms <= 0)
2416                 return ucv_boolean_new(false);
2417 
2418         tv.tv_sec = ms / 1000;
2419         tv.tv_usec = (ms % 1000) * 1000;
2420 
2421         select(0, NULL, NULL, NULL, &tv);
2422 
2423         return ucv_boolean_new(true);
2424 }
2425 
2426 static uc_value_t *
2427 uc_assert(uc_vm_t *vm, size_t nargs)
2428 {
2429         uc_value_t *cond = uc_fn_arg(0);
2430         uc_value_t *msg = uc_fn_arg(1);
2431         bool freeable = false;
2432         char *s;
2433 
2434         if (!ucv_is_truish(cond)) {
2435                 s = msg ? uc_cast_string(vm, &msg, &freeable) : "Assertion failed";
2436 
2437                 uc_vm_raise_exception(vm, EXCEPTION_USER, "%s", s);
2438 
2439                 if (freeable)
2440                         free(s);
2441 
2442                 return NULL;
2443         }
2444 
2445         return ucv_get(cond);
2446 }
2447 
2448 static uc_value_t *
2449 uc_regexp(uc_vm_t *vm, size_t nargs)
2450 {
2451         bool icase = false, newline = false, global = false, freeable;
2452         uc_value_t *source = uc_fn_arg(0);
2453         uc_value_t *flags = uc_fn_arg(1);
2454         uc_value_t *regex = NULL;
2455         char *p, *err = NULL;
2456 
2457         if (flags) {
2458                 if (ucv_type(flags) != UC_STRING) {
2459                         uc_vm_raise_exception(vm, EXCEPTION_TYPE, "Given flags argument is not a string");
2460 
2461                         return NULL;
2462                 }
2463 
2464                 for (p = ucv_string_get(flags); *p; p++) {
2465                         switch (*p) {
2466                         case 'i':
2467                                 icase = true;
2468                                 break;
2469 
2470                         case 's':
2471                                 newline = true;
2472                                 break;
2473 
2474                         case 'g':
2475                                 global = true;
2476                                 break;
2477 
2478                         default:
2479                                 uc_vm_raise_exception(vm, EXCEPTION_TYPE, "Unrecognized flag character '%c'", *p);
2480 
2481                                 return NULL;
2482                         }
2483                 }
2484         }
2485 
2486         p = uc_cast_string(vm, &source, &freeable);
2487         regex = ucv_regexp_new(p, icase, newline, global, &err);
2488 
2489         if (freeable)
2490                 free(p);
2491 
2492         if (err) {
2493                 uc_vm_raise_exception(vm, EXCEPTION_SYNTAX, "%s", err);
2494                 ucv_put(regex);
2495                 free(err);
2496 
2497                 return NULL;
2498         }
2499 
2500         return regex;
2501 }
2502 
2503 static uc_value_t *
2504 uc_wildcard(uc_vm_t *vm, size_t nargs)
2505 {
2506         uc_value_t *subject = uc_fn_arg(0);
2507         uc_value_t *pattern = uc_fn_arg(1);
2508         uc_value_t *icase = uc_fn_arg(2);
2509         int flags = 0, rv;
2510         bool freeable;
2511         char *s;
2512 
2513         if (!subject || ucv_type(pattern) != UC_STRING)
2514                 return NULL;
2515 
2516         if (ucv_is_truish(icase))
2517                 flags |= FNM_CASEFOLD;
2518 
2519         s = uc_cast_string(vm, &subject, &freeable);
2520         rv = fnmatch(ucv_string_get(pattern), s, flags);
2521 
2522         if (freeable)
2523                 free(s);
2524 
2525         return ucv_boolean_new(rv == 0);
2526 }
2527 
2528 static uc_value_t *
2529 uc_sourcepath(uc_vm_t *vm, size_t nargs)
2530 {
2531         uc_value_t *calldepth = uc_fn_arg(0);
2532         uc_value_t *dironly = uc_fn_arg(1);
2533         uc_value_t *rv = NULL;
2534         uc_callframe_t *frame;
2535         char *path = NULL;
2536         int64_t depth;
2537         size_t i;
2538 
2539         depth = ucv_to_integer(calldepth);
2540 
2541         if (errno)
2542                 depth = 0;
2543 
2544         for (i = vm->callframes.count; i > 0; i--) {
2545                 frame = &vm->callframes.entries[i - 1];
2546 
2547                 if (!frame->closure)
2548                         continue;
2549 
2550                 if (depth > 0) {
2551                         depth--;
2552                         continue;
2553                 }
2554 
2555                 path = realpath(frame->closure->function->program->source->filename, NULL);
2556                 break;
2557         }
2558 
2559         if (path) {
2560                 if (ucv_is_truish(dironly))
2561                         rv = ucv_string_new(dirname(path));
2562                 else
2563                         rv = ucv_string_new(path);
2564 
2565                 free(path);
2566         }
2567 
2568         return rv;
2569 }
2570 
2571 static uc_value_t *
2572 uc_min_max(uc_vm_t *vm, size_t nargs, int cmp)
2573 {
2574         uc_value_t *rv = NULL, *val;
2575         bool set = false;
2576         size_t i;
2577 
2578         for (i = 0; i < nargs; i++) {
2579                 val = uc_fn_arg(i);
2580 
2581                 if (!set || ucv_compare(cmp, val, rv, NULL)) {
2582                         set = true;
2583                         rv = val;
2584                 }
2585         }
2586 
2587         return ucv_get(rv);
2588 }
2589 
2590 static uc_value_t *
2591 uc_min(uc_vm_t *vm, size_t nargs)
2592 {
2593         return uc_min_max(vm, nargs, I_LT);
2594 }
2595 
2596 static uc_value_t *
2597 uc_max(uc_vm_t *vm, size_t nargs)
2598 {
2599         return uc_min_max(vm, nargs, I_GT);
2600 }
2601 
2602 
2603 /* -------------------------------------------------------------------------
2604  * The following base64 encoding and decoding routines are taken from
2605  * https://git.openwrt.org/?p=project/libubox.git;a=blob;f=base64.c
2606  * and modified for use in ucode.
2607  *
2608  * Original copyright and license statements below.
2609  */
2610 
2611 /*
2612  * base64 - libubox base64 functions
2613  *
2614  * Copyright (C) 2015 Felix Fietkau <nbd@openwrt.org>
2615  *
2616  * Permission to use, copy, modify, and/or distribute this software for any
2617  * purpose with or without fee is hereby granted, provided that the above
2618  * copyright notice and this permission notice appear in all copies.
2619  *
2620  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
2621  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
2622  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
2623  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
2624  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
2625  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
2626  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
2627  */
2628 
2629 /*      $OpenBSD: base64.c,v 1.7 2013/12/31 02:32:56 tedu Exp $ */
2630 
2631 /*
2632  * Copyright (c) 1996 by Internet Software Consortium.
2633  *
2634  * Permission to use, copy, modify, and distribute this software for any
2635  * purpose with or without fee is hereby granted, provided that the above
2636  * copyright notice and this permission notice appear in all copies.
2637  *
2638  * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
2639  * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
2640  * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
2641  * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
2642  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
2643  * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
2644  * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
2645  * SOFTWARE.
2646  */
2647 
2648 /*
2649  * Portions Copyright (c) 1995 by International Business Machines, Inc.
2650  *
2651  * International Business Machines, Inc. (hereinafter called IBM) grants
2652  * permission under its copyrights to use, copy, modify, and distribute this
2653  * Software with or without fee, provided that the above copyright notice and
2654  * all paragraphs of this notice appear in all copies, and that the name of IBM
2655  * not be used in connection with the marketing of any product incorporating
2656  * the Software or modifications thereof, without specific, written prior
2657  * permission.
2658  *
2659  * To the extent it has a right to do so, IBM grants an immunity from suit
2660  * under its patents, if any, for the use, sale or manufacture of products to
2661  * the extent that such products are used for performing Domain Name System
2662  * dynamic updates in TCP/IP networks by means of the Software.  No immunity is
2663  * granted for any product per se or for any other function of any product.
2664  *
2665  * THE SOFTWARE IS PROVIDED "AS IS", AND IBM DISCLAIMS ALL WARRANTIES,
2666  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
2667  * PARTICULAR PURPOSE.  IN NO EVENT SHALL IBM BE LIABLE FOR ANY SPECIAL,
2668  * DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER ARISING
2669  * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE, EVEN
2670  * IF IBM IS APPRISED OF THE POSSIBILITY OF SUCH DAMAGES.
2671  */
2672 
2673 /* skips all whitespace anywhere.
2674    converts characters, four at a time, starting at (or after)
2675    src from base - 64 numbers into three 8 bit bytes in the target area.
2676    it returns the number of data bytes stored at the target, or -1 on error.
2677  */
2678 
2679 static uc_value_t *
2680 uc_b64dec(uc_vm_t *vm, size_t nargs)
2681 {
2682         enum { BYTE1, BYTE2, BYTE3, BYTE4 } state;
2683         uc_value_t *str = uc_fn_arg(0);
2684         uc_stringbuf_t *buf;
2685         const char *src;
2686         unsigned int ch;
2687         uint8_t val;
2688         size_t off;
2689 
2690         if (ucv_type(str) != UC_STRING)
2691                 return NULL;
2692 
2693         buf = ucv_stringbuf_new();
2694         src = ucv_string_get(str);
2695         off = printbuf_length(buf);
2696 
2697         state = BYTE1;
2698 
2699         /* memset the last expected output char to pre-grow the output buffer */
2700         printbuf_memset(buf, off + (ucv_string_length(str) / 4) * 3, 0, 1);
2701 
2702         while ((ch = (unsigned char)*src++) != '\0') {
2703                 if (isspace(ch))        /* Skip whitespace anywhere. */
2704                         continue;
2705 
2706                 if (ch == '=')
2707                         break;
2708 
2709                 if (ch >= 'A' && ch <= 'Z')
2710                         val = ch - 'A';
2711                 else if (ch >= 'a' && ch <= 'z')
2712                         val = ch - 'a' + 26;
2713                 else if (ch >= '' && ch <= '9')
2714                         val = ch - '' + 52;
2715                 else if (ch == '+')
2716                         val = 62;
2717                 else if (ch == '/')
2718                         val = 63;
2719                 else
2720                         goto err;
2721 
2722                 switch (state) {
2723                 case BYTE1:
2724                         buf->buf[off] = val << 2;
2725                         state = BYTE2;
2726                         break;
2727 
2728                 case BYTE2:
2729                         buf->buf[off++] |= val >> 4;
2730                         buf->buf[off] = (val & 0x0f) << 4;
2731                         state = BYTE3;
2732                         break;
2733 
2734                 case BYTE3:
2735                         buf->buf[off++] |= val >> 2;
2736                         buf->buf[off] = (val & 0x03) << 6;
2737                         state = BYTE4;
2738                         break;
2739 
2740                 case BYTE4:
2741                         buf->buf[off++] |= val;
2742                         state = BYTE1;
2743                         break;
2744                 }
2745         }
2746 
2747         /*
2748          * We are done decoding Base-64 chars.  Let's see if we ended
2749          * on a byte boundary, and/or with erroneous trailing characters.
2750          */
2751 
2752         if (ch == '=') {                        /* We got a pad char. */
2753                 ch = (unsigned char)*src++;     /* Skip it, get next. */
2754                 switch (state) {
2755                 case BYTE1:             /* Invalid = in first position */
2756                 case BYTE2:             /* Invalid = in second position */
2757                         goto err;
2758 
2759                 case BYTE3:             /* Valid, means one byte of info */
2760                         /* Skip any number of spaces. */
2761                         for (; ch != '\0'; ch = (unsigned char)*src++)
2762                                 if (!isspace(ch))
2763                                         break;
2764                         /* Make sure there is another trailing = sign. */
2765                         if (ch != '=')
2766                                 goto err;
2767                         ch = (unsigned char)*src++;             /* Skip the = */
2768                         /* Fall through to "single trailing =" case. */
2769                         /* FALLTHROUGH */
2770 
2771                 case BYTE4:             /* Valid, means two bytes of info */
2772                         /*
2773                          * We know this char is an =.  Is there anything but
2774                          * whitespace after it?
2775                          */
2776                         for (; ch != '\0'; ch = (unsigned char)*src++)
2777                                 if (!isspace(ch))
2778                                         goto err;
2779 
2780                         /*
2781                          * Now make sure for cases BYTE3 and BYTE4 that the "extra"
2782                          * bits that slopped past the last full byte were
2783                          * zeros.  If we don't check them, they become a
2784                          * subliminal channel.
2785                          */
2786                         if (buf->buf[off] != 0)
2787                                 goto err;
2788                 }
2789         } else {
2790                 /*
2791                  * We ended by seeing the end of the string.  Make sure we
2792                  * have no partial bytes lying around.
2793                  */
2794                 if (state != BYTE1)
2795                         goto err;
2796         }
2797 
2798         /* Truncate buffer length to actual output length */
2799         buf->bpos = off;
2800 
2801         return ucv_stringbuf_finish(buf);
2802 
2803 err:
2804         printbuf_free(buf);
2805 
2806         return NULL;
2807 }
2808 
2809 static const char Base64[] =
2810         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
2811 
2812 static uc_value_t *
2813 uc_b64enc(uc_vm_t *vm, size_t nargs)
2814 {
2815         uc_value_t *str = uc_fn_arg(0);
2816         unsigned char input[3] = {0};
2817         uc_stringbuf_t *buf;
2818         const char *src;
2819         char output[4];
2820         size_t len, i;
2821 
2822         if (ucv_type(str) != UC_STRING)
2823                 return NULL;
2824 
2825         buf = ucv_stringbuf_new();
2826         src = ucv_string_get(str);
2827         len = ucv_string_length(str);
2828 
2829         while (2 < len) {
2830                 input[0] = (unsigned char)*src++;
2831                 input[1] = (unsigned char)*src++;
2832                 input[2] = (unsigned char)*src++;
2833                 len -= 3;
2834 
2835                 output[0] = Base64[input[0] >> 2];
2836                 output[1] = Base64[((input[0] & 0x03) << 4) + (input[1] >> 4)];
2837                 output[2] = Base64[((input[1] & 0x0f) << 2) + (input[2] >> 6)];
2838                 output[3] = Base64[input[2] & 0x3f];
2839 
2840                 ucv_stringbuf_addstr(buf, output, sizeof(output));
2841         }
2842 
2843         /* Now we worry about padding. */
2844         if (0 != len) {
2845                 /* Get what's left. */
2846                 input[0] = input[1] = input[2] = '\0';
2847                 for (i = 0; i < len; i++)
2848                         input[i] = *src++;
2849 
2850                 output[0] = Base64[input[0] >> 2];
2851                 output[1] = Base64[((input[0] & 0x03) << 4) + (input[1] >> 4)];
2852                 output[2] = (len == 1) ? '=' : Base64[((input[1] & 0x0f) << 2) + (input[2] >> 6)];
2853                 output[3] = '=';
2854 
2855                 ucv_stringbuf_addstr(buf, output, sizeof(output));
2856         }
2857 
2858         return ucv_stringbuf_finish(buf);
2859 }
2860 
2861 /* End of base64 code.
2862  * -------------------------------------------------------------------------
2863  */
2864 
2865 static unsigned long
2866 uc_uniq_ucv_hash(const void *k)
2867 {
2868         union { double d; int64_t i; uint64_t u; } conv;
2869         uc_value_t *uv = (uc_value_t *)k;
2870         unsigned int h;
2871         uint8_t *u8;
2872         size_t len;
2873 
2874         h = ucv_type(uv);
2875 
2876         switch (h) {
2877         case UC_STRING:
2878                 u8 = (uint8_t *)ucv_string_get(uv);
2879                 len = ucv_string_length(uv);
2880                 break;
2881 
2882         case UC_INTEGER:
2883                 conv.i = ucv_int64_get(uv);
2884 
2885                 if (errno == ERANGE) {
2886                         h *= 2;
2887                         conv.u = ucv_uint64_get(uv);
2888                 }
2889 
2890                 u8 = (uint8_t *)&conv.u;
2891                 len = sizeof(conv.u);
2892                 break;
2893 
2894         case UC_DOUBLE:
2895                 conv.d = ucv_double_get(uv);
2896 
2897                 u8 = (uint8_t *)&conv.u;
2898                 len = sizeof(conv.u);
2899                 break;
2900 
2901         default:
2902                 u8 = (uint8_t *)&uv;
2903                 len = sizeof(uv);
2904                 break;
2905         }
2906 
2907         while (len > 0) {
2908                 h = h * 129 + (*u8++) + LH_PRIME;
2909                 len--;
2910         }
2911 
2912         return h;
2913 }
2914 
2915 static int
2916 uc_uniq_ucv_equal(const void *k1, const void *k2)
2917 {
2918         uc_value_t *uv1 = (uc_value_t *)k1;
2919         uc_value_t *uv2 = (uc_value_t *)k2;
2920 
2921         if (!ucv_is_scalar(uv1) && !ucv_is_scalar(uv2))
2922                 return (uv1 == uv2);
2923 
2924         /* for the sake of array item uniqueness, treat two NaNs as equal */
2925         if (ucv_type(uv1) == UC_DOUBLE && ucv_type(uv2) == UC_DOUBLE &&
2926             isnan(ucv_double_get(uv1)) && isnan(ucv_double_get(uv2)))
2927             return true;
2928 
2929         return ucv_is_equal(uv1, uv2);
2930 }
2931 
2932 static uc_value_t *
2933 uc_uniq(uc_vm_t *vm, size_t nargs)
2934 {
2935         uc_value_t *list = uc_fn_arg(0);
2936         uc_value_t *uniq = NULL;
2937         struct lh_table *seen;
2938         unsigned long hash;
2939         uc_value_t *item;
2940         size_t i, len;
2941 
2942         if (ucv_type(list) != UC_ARRAY)
2943                 return NULL;
2944 
2945         seen = lh_table_new(16, NULL, uc_uniq_ucv_hash, uc_uniq_ucv_equal);
2946         uniq = ucv_array_new(vm);
2947 
2948         assert(seen && uniq);
2949 
2950         for (i = 0, len = ucv_array_length(list); i < len; i++) {
2951                 item = ucv_array_get(list, i);
2952                 hash = lh_get_hash(seen, item);
2953 
2954                 if (!lh_table_lookup_entry_w_hash(seen, item, hash)) {
2955                         lh_table_insert_w_hash(seen, item, NULL, hash, 0);
2956                         ucv_array_push(uniq, ucv_get(item));
2957                 }
2958         }
2959 
2960         lh_table_free(seen);
2961 
2962         return uniq;
2963 }
2964 
2965 
2966 const uc_function_list_t uc_stdlib_functions[] = {
2967         { "chr",                uc_chr },
2968         { "die",                uc_die },
2969         { "exists",             uc_exists },
2970         { "exit",               uc_exit },
2971         { "filter",             uc_filter },
2972         { "getenv",             uc_getenv },
2973         { "hex",                uc_hex },
2974         { "index",              uc_lindex },
2975         { "int",                uc_int },
2976         { "join",               uc_join },
2977         { "keys",               uc_keys },
2978         { "lc",                 uc_lc },
2979         { "length",             uc_length },
2980         { "ltrim",              uc_ltrim },
2981         { "map",                uc_map },
2982         { "ord",                uc_ord },
2983         { "pop",                uc_pop },
2984         { "print",              uc_print },
2985         { "push",               uc_push },
2986         { "reverse",    uc_reverse },
2987         { "rindex",             uc_rindex },
2988         { "rtrim",              uc_rtrim },
2989         { "shift",              uc_shift },
2990         { "sort",               uc_sort },
2991         { "splice",             uc_splice },
2992         { "split",              uc_split },
2993         { "substr",             uc_substr },
2994         { "time",               uc_time },
2995         { "trim",               uc_trim },
2996         { "type",               uc_type },
2997         { "uchr",               uc_uchr },
2998         { "uc",                 uc_uc },
2999         { "unshift",    uc_unshift },
3000         { "values",             uc_values },
3001         { "sprintf",    uc_sprintf },
3002         { "printf",             uc_printf },
3003         { "require",    uc_require },
3004         { "iptoarr",    uc_iptoarr },
3005         { "arrtoip",    uc_arrtoip },
3006         { "match",              uc_match },
3007         { "replace",    uc_replace },
3008         { "json",               uc_json },
3009         { "include",    uc_include },
3010         { "warn",               uc_warn },
3011         { "system",             uc_system },
3012         { "trace",              uc_trace },
3013         { "proto",              uc_proto },
3014         { "sleep",              uc_sleep },
3015         { "assert",             uc_assert },
3016         { "render",             uc_render },
3017         { "regexp",             uc_regexp },
3018         { "wildcard",   uc_wildcard },
3019         { "sourcepath", uc_sourcepath },
3020         { "min",                uc_min },
3021         { "max",                uc_max },
3022         { "b64dec",             uc_b64dec },
3023         { "b64enc",             uc_b64enc },
3024         { "uniq",               uc_uniq },
3025 };
3026 
3027 
3028 void
3029 uc_stdlib_load(uc_value_t *scope)
3030 {
3031         uc_function_list_register(scope, uc_stdlib_functions);
3032 }
3033 

This page was automatically generated by LXR 0.3.1.  •  OpenWrt