• 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 "json-c-compat.h"
 37 
 38 #include "ucode/lexer.h"
 39 #include "ucode/compiler.h"
 40 #include "ucode/vm.h"
 41 #include "ucode/lib.h"
 42 #include "ucode/source.h"
 43 #include "ucode/program.h"
 44 
 45 static void
 46 format_context_line(uc_stringbuf_t *buf, const char *line, size_t off, bool compact)
 47 {
 48         unsigned padlen, i;
 49         const char *p;
 50 
 51         for (p = line, padlen = 0; *p != '\n' && *p != '\0'; p++) {
 52                 if (compact && (p - line) == (ptrdiff_t)off)
 53                         ucv_stringbuf_append(buf, "\033[22m");
 54 
 55                 switch (*p) {
 56                 case '\t':
 57                         ucv_stringbuf_append(buf, "    ");
 58                         if (p < line + off)
 59                                 padlen += 4;
 60                         break;
 61 
 62                 case '\r':
 63                 case '\v':
 64                         ucv_stringbuf_append(buf, " ");
 65                         if (p < line + off)
 66                                 padlen++;
 67                         break;
 68 
 69                 default:
 70                         ucv_stringbuf_addstr(buf, p, 1);
 71                         if (p < line + off)
 72                                 padlen++;
 73                 }
 74         }
 75 
 76         if (compact) {
 77                 ucv_stringbuf_append(buf, "\033[m\n");
 78 
 79                 return;
 80         }
 81 
 82         ucv_stringbuf_append(buf, "`\n  ");
 83 
 84         if (padlen < strlen("Near here ^")) {
 85                 for (i = 0; i < padlen; i++)
 86                         ucv_stringbuf_append(buf, " ");
 87 
 88                 ucv_stringbuf_append(buf, "^-- Near here\n");
 89         }
 90         else {
 91                 ucv_stringbuf_append(buf, "Near here ");
 92 
 93                 for (i = strlen("Near here "); i < padlen; i++)
 94                         ucv_stringbuf_append(buf, "-");
 95 
 96                 ucv_stringbuf_append(buf, "^\n");
 97         }
 98 }
 99 
100 static char *
101 source_filename(uc_source_t *src, uint32_t line)
102 {
103         const char *name = src->filename ? basename(src->filename) : "[?]";
104         static char buf[sizeof("xxxxxxxxx.uc:0000000000")];
105         size_t len = strlen(name);
106 
107         if (len > 12)
108                 snprintf(buf, sizeof(buf), "...%s:%u", name + (len - 9), line);
109         else
110                 snprintf(buf, sizeof(buf), "%12s:%u", name, line);
111 
112         return buf;
113 }
114 
115 bool
116 uc_source_context_format(uc_stringbuf_t *buf, uc_source_t *src, size_t off, bool compact)
117 {
118         size_t len, rlen;
119         bool truncated;
120         char line[256];
121         long srcpos;
122         int eline;
123 
124         srcpos = ftell(src->fp);
125 
126         if (srcpos == -1)
127                 return false;
128 
129         fseek(src->fp, 0, SEEK_SET);
130 
131         truncated = false;
132         eline = 1;
133         rlen = 0;
134 
135         while (fgets(line, sizeof(line), src->fp)) {
136                 len = strlen(line);
137                 rlen += len;
138 
139                 if (rlen >= off) {
140                         if (compact)
141                                 ucv_stringbuf_printf(buf, "\033[2;40;97m%17s  %s",
142                                         source_filename(src, eline),
143                                         truncated ? "..." : "");
144                         else
145                                 ucv_stringbuf_printf(buf, "\n `%s",
146                                         truncated ? "..." : "");
147 
148                         format_context_line(buf, line, len - (rlen - off) + (truncated ? 3 : 0), compact);
149                         break;
150                 }
151 
152                 truncated = (len > 0 && line[len-1] != '\n');
153                 eline += !truncated;
154         }
155 
156         fseek(src->fp, srcpos, SEEK_SET);
157 
158         return true;
159 }
160 
161 bool
162 uc_error_context_format(uc_stringbuf_t *buf, uc_source_t *src, uc_value_t *stacktrace, size_t off)
163 {
164         uc_value_t *e, *fn, *file, *line, *byte;
165         const char *path;
166         size_t idx;
167 
168         for (idx = 0; idx < (stacktrace ? ucv_array_length(stacktrace) : 0); idx++) {
169                 e = ucv_array_get(stacktrace, idx);
170                 fn = ucv_object_get(e, "function", NULL);
171                 file = ucv_object_get(e, "filename", NULL);
172 
173                 if (idx == 0) {
174                         path = (file && strcmp(ucv_string_get(file), "[stdin]"))
175                                 ? ucv_string_get(file) : NULL;
176 
177                         if (path && fn)
178                                 ucv_stringbuf_printf(buf, "In %s(), file %s, ", ucv_string_get(fn), path);
179                         else if (fn)
180                                 ucv_stringbuf_printf(buf, "In %s(), ", ucv_string_get(fn));
181                         else if (path)
182                                 ucv_stringbuf_printf(buf, "In %s, ", path);
183                         else
184                                 ucv_stringbuf_append(buf, "In ");
185 
186                         ucv_stringbuf_printf(buf, "line %" PRId64 ", byte %" PRId64 ":\n",
187                                 ucv_int64_get(ucv_object_get(e, "line", NULL)),
188                                 ucv_int64_get(ucv_object_get(e, "byte", NULL)));
189                 }
190                 else {
191                         line = ucv_object_get(e, "line", NULL);
192                         byte = ucv_object_get(e, "byte", NULL);
193 
194                         ucv_stringbuf_printf(buf, "  called from %s%s (%s",
195                                 fn ? "function " : "anonymous function",
196                                 fn ? ucv_string_get(fn) : "",
197                                 file ? ucv_string_get(file) : "");
198 
199                         if (line && byte)
200                                 ucv_stringbuf_printf(buf, ":%" PRId64 ":%" PRId64 ")\n",
201                                         ucv_int64_get(line),
202                                         ucv_int64_get(byte));
203                         else
204                                 ucv_stringbuf_append(buf, "[C])\n");
205                 }
206         }
207 
208         return uc_source_context_format(buf, src, off, false);
209 }
210 
211 void
212 uc_error_message_indent(char **msg) {
213         uc_stringbuf_t *buf = xprintbuf_new();
214         char *s, *p, *nl;
215         size_t len;
216 
217         if (!msg || !*msg)
218                 return;
219 
220         s = *msg;
221         len = strlen(s);
222 
223         while (len > 0 && s[len-1] == '\n')
224                 s[--len] = 0;
225 
226         for (p = s, nl = strchr(p, '\n'); p != NULL;
227              p = nl ? nl + 1 : NULL, nl = p ? strchr(p, '\n') : NULL)
228         {
229                 if (!nl)
230                         ucv_stringbuf_printf(buf, "  | %s", p);
231                 else if (nl != p)
232                         ucv_stringbuf_printf(buf, "  | %.*s\n", (int)(nl - p), p);
233                 else
234                         ucv_stringbuf_append(buf, "  |\n");
235         }
236 
237         ucv_stringbuf_append(buf, "\n");
238 
239         *msg = buf->buf;
240 
241         free(buf);
242         free(s);
243 }
244 
245 static char *uc_cast_string(uc_vm_t *vm, uc_value_t **v, bool *freeable) {
246         if (ucv_type(*v) == UC_STRING) {
247                 *freeable = false;
248 
249                 return _ucv_string_get(v);
250         }
251 
252         *freeable = true;
253 
254         return ucv_to_string(vm, *v);
255 }
256 
257 static void
258 uc_vm_ctx_push(uc_vm_t *vm)
259 {
260         uc_value_t *ctx = NULL;
261 
262         if (vm->callframes.count >= 2)
263                 ctx = vm->callframes.entries[vm->callframes.count - 2].ctx;
264 
265         uc_vm_stack_push(vm, ucv_get(ctx));
266 }
267 
268 static uc_value_t *
269 uc_print_common(uc_vm_t *vm, size_t nargs, FILE *fh)
270 {
271         uc_value_t *item;
272         size_t reslen = 0;
273         size_t len = 0;
274         size_t arridx;
275         char *p;
276 
277         for (arridx = 0; arridx < nargs; arridx++) {
278                 item = uc_fn_arg(arridx);
279 
280                 if (ucv_type(item) == UC_STRING) {
281                         len = ucv_string_length(item);
282                         reslen += fwrite(ucv_string_get(item), 1, len, fh);
283                 }
284                 else if (item != NULL) {
285                         p = ucv_to_string(vm, item);
286                         len = strlen(p);
287                         reslen += fwrite(p, 1, len, fh);
288                         free(p);
289                 }
290         }
291 
292         return ucv_int64_new(reslen);
293 }
294 
295 
296 static uc_value_t *
297 uc_print(uc_vm_t *vm, size_t nargs)
298 {
299         return uc_print_common(vm, nargs, vm->output);
300 }
301 
302 static uc_value_t *
303 uc_length(uc_vm_t *vm, size_t nargs)
304 {
305         uc_value_t *arg = uc_fn_arg(0);
306 
307         switch (ucv_type(arg)) {
308         case UC_OBJECT:
309                 return ucv_int64_new(ucv_object_length(arg));
310 
311         case UC_ARRAY:
312                 return ucv_int64_new(ucv_array_length(arg));
313 
314         case UC_STRING:
315                 return ucv_int64_new(ucv_string_length(arg));
316 
317         default:
318                 return NULL;
319         }
320 }
321 
322 static int
323 uc_uniq_ucv_equal(const void *k1, const void *k2);
324 
325 static uc_value_t *
326 uc_index(uc_vm_t *vm, size_t nargs, bool right)
327 {
328         uc_value_t *stack = uc_fn_arg(0);
329         uc_value_t *needle = uc_fn_arg(1);
330         const char *sstr, *nstr, *p;
331         size_t arridx, slen, nlen;
332         ssize_t ret = -1;
333 
334         switch (ucv_type(stack)) {
335         case UC_ARRAY:
336                 if (right) {
337                         for (arridx = ucv_array_length(stack); arridx > 0; arridx--) {
338                                 if (uc_uniq_ucv_equal(ucv_array_get(stack, arridx - 1), needle)) {
339                                         ret = (ssize_t)(arridx - 1);
340                                         break;
341                                 }
342                         }
343                 }
344                 else {
345                         for (arridx = 0, slen = ucv_array_length(stack); arridx < slen; arridx++) {
346                                 if (uc_uniq_ucv_equal(ucv_array_get(stack, arridx), needle)) {
347                                         ret = (ssize_t)arridx;
348                                         break;
349                                 }
350                         }
351                 }
352 
353                 return ucv_int64_new(ret);
354 
355         case UC_STRING:
356                 if (ucv_type(needle) == UC_STRING) {
357                         sstr = ucv_string_get(stack);
358                         slen = ucv_string_length(stack);
359                         nstr = ucv_string_get(needle);
360                         nlen = ucv_string_length(needle);
361 
362                         if (slen == nlen) {
363                                 if (memcmp(sstr, nstr, nlen) == 0)
364                                         ret = 0;
365                         }
366                         else if (slen > nlen) {
367                                 if (right) {
368                                         p = sstr + slen - nlen;
369 
370                                         do {
371                                                 if (memcmp(p, nstr, nlen) == 0) {
372                                                         ret = (ssize_t)(p - sstr);
373                                                         break;
374                                                 }
375                                         }
376                                         while (--p != sstr);
377                                 }
378                                 else {
379                                         p = (const char *)memmem(sstr, slen, nstr, nlen);
380 
381                                         if (p)
382                                                 ret = (ssize_t)(p - sstr);
383                                 }
384                         }
385                 }
386 
387                 return ucv_int64_new(ret);
388 
389         default:
390                 return NULL;
391         }
392 }
393 
394 static uc_value_t *
395 uc_lindex(uc_vm_t *vm, size_t nargs)
396 {
397         return uc_index(vm, nargs, false);
398 }
399 
400 static uc_value_t *
401 uc_rindex(uc_vm_t *vm, size_t nargs)
402 {
403         return uc_index(vm, nargs, true);
404 }
405 
406 static bool
407 assert_mutable_array(uc_vm_t *vm, uc_value_t *val)
408 {
409         if (ucv_type(val) != UC_ARRAY)
410                 return false;
411 
412         if (ucv_is_constant(val)) {
413                 uc_vm_raise_exception(vm, EXCEPTION_TYPE,
414                                       "%s value is immutable",
415                                       ucv_typename(val));
416 
417                 return false;
418         }
419 
420         return true;
421 }
422 
423 static uc_value_t *
424 uc_push(uc_vm_t *vm, size_t nargs)
425 {
426         uc_value_t *arr = uc_fn_arg(0);
427         uc_value_t *item = NULL;
428         size_t arridx;
429 
430         if (!assert_mutable_array(vm, arr))
431                 return NULL;
432 
433         for (arridx = 1; arridx < nargs; arridx++) {
434                 item = uc_fn_arg(arridx);
435                 ucv_array_push(arr, ucv_get(item));
436         }
437 
438         return ucv_get(item);
439 }
440 
441 static uc_value_t *
442 uc_pop(uc_vm_t *vm, size_t nargs)
443 {
444         uc_value_t *arr = uc_fn_arg(0);
445 
446         if (!assert_mutable_array(vm, arr))
447                 return NULL;
448 
449         return ucv_array_pop(arr);
450 }
451 
452 static uc_value_t *
453 uc_shift(uc_vm_t *vm, size_t nargs)
454 {
455         uc_value_t *arr = uc_fn_arg(0);
456 
457         if (!assert_mutable_array(vm, arr))
458                 return NULL;
459 
460         return ucv_array_shift(arr);
461 }
462 
463 static uc_value_t *
464 uc_unshift(uc_vm_t *vm, size_t nargs)
465 {
466         uc_value_t *arr = uc_fn_arg(0);
467         uc_value_t *item = NULL;
468         size_t i;
469 
470         if (!assert_mutable_array(vm, arr))
471                 return NULL;
472 
473         for (i = 1; i < nargs; i++) {
474                 item = uc_fn_arg(i);
475                 ucv_array_unshift(arr, ucv_get(item));
476         }
477 
478         return ucv_get(item);
479 }
480 
481 static uc_value_t *
482 uc_chr(uc_vm_t *vm, size_t nargs)
483 {
484         uc_value_t *rv = NULL;
485         size_t idx;
486         int64_t n;
487         char *str;
488 
489         if (!nargs)
490                 return ucv_string_new_length("", 0);
491 
492         str = xalloc(nargs);
493 
494         for (idx = 0; idx < nargs; idx++) {
495                 n = ucv_to_integer(uc_fn_arg(idx));
496 
497                 if (n < 0)
498                         n = 0;
499                 else if (n > 255)
500                         n = 255;
501 
502                 str[idx] = (char)n;
503         }
504 
505         rv = ucv_string_new_length(str, nargs);
506         free(str);
507 
508         return rv;
509 }
510 
511 static uc_value_t *
512 uc_die(uc_vm_t *vm, size_t nargs)
513 {
514         uc_value_t *msg = uc_fn_arg(0);
515         bool freeable = false;
516         char *s;
517 
518         s = msg ? uc_cast_string(vm, &msg, &freeable) : "Died";
519 
520         uc_vm_raise_exception(vm, EXCEPTION_USER, "%s", s);
521 
522         if (freeable)
523                 free(s);
524 
525         return NULL;
526 }
527 
528 static uc_value_t *
529 uc_exists(uc_vm_t *vm, size_t nargs)
530 {
531         uc_value_t *obj = uc_fn_arg(0);
532         uc_value_t *key = uc_fn_arg(1);
533         bool found, freeable;
534         char *k;
535 
536         if (ucv_type(obj) != UC_OBJECT)
537                 return ucv_boolean_new(false);
538 
539         k = uc_cast_string(vm, &key, &freeable);
540 
541         ucv_object_get(obj, k, &found);
542 
543         if (freeable)
544                 free(k);
545 
546         return ucv_boolean_new(found);
547 }
548 
549 static uc_value_t *
550 uc_exit(uc_vm_t *vm, size_t nargs)
551 {
552         int64_t n = ucv_to_integer(uc_fn_arg(0));
553 
554         vm->arg.s32 = (int32_t)n;
555         uc_vm_raise_exception(vm, EXCEPTION_EXIT, "Terminated");
556 
557         return NULL;
558 }
559 
560 static uc_value_t *
561 uc_getenv(uc_vm_t *vm, size_t nargs)
562 {
563         uc_value_t *key = uc_fn_arg(0), *rv = NULL;
564         extern char **environ;
565         char *k, *v;
566 
567         if (!key) {
568                 rv = ucv_object_new(vm);
569 
570                 while (*environ) {
571                         v = strchr(*environ, '=');
572 
573                         if (v) {
574                                 xasprintf(&k, "%.*s", (int)(v - *environ), *environ);
575                                 ucv_object_add(rv, k, ucv_string_new(v + 1));
576                                 free(k);
577                         }
578 
579                         environ++;
580                 }
581         }
582         else if (ucv_type(key) == UC_STRING) {
583                 k = ucv_string_get(key);
584                 v = getenv(k);
585 
586                 if (v)
587                         rv = ucv_string_new(v);
588         }
589 
590         return rv;
591 }
592 
593 static uc_value_t *
594 uc_filter(uc_vm_t *vm, size_t nargs)
595 {
596         uc_value_t *obj = uc_fn_arg(0);
597         uc_value_t *func = uc_fn_arg(1);
598         uc_value_t *rv, *arr;
599         size_t arridx, arrlen;
600 
601         if (ucv_type(obj) != UC_ARRAY)
602                 return NULL;
603 
604         arr = ucv_array_new(vm);
605 
606         for (arrlen = ucv_array_length(obj), arridx = 0; arridx < arrlen; arridx++) {
607                 uc_vm_ctx_push(vm);
608                 uc_vm_stack_push(vm, ucv_get(func));
609                 uc_vm_stack_push(vm, ucv_get(ucv_array_get(obj, arridx)));
610                 uc_vm_stack_push(vm, ucv_int64_new(arridx));
611                 uc_vm_stack_push(vm, ucv_get(obj));
612 
613                 if (uc_vm_call(vm, true, 3)) {
614                         ucv_put(arr);
615 
616                         return NULL;
617                 }
618 
619                 rv = uc_vm_stack_pop(vm);
620 
621                 if (ucv_is_truish(rv))
622                         ucv_array_push(arr, ucv_get(ucv_array_get(obj, arridx)));
623 
624                 ucv_put(rv);
625         }
626 
627         return arr;
628 }
629 
630 static uc_value_t *
631 uc_hex(uc_vm_t *vm, size_t nargs)
632 {
633         uc_value_t *val = uc_fn_arg(0);
634         char *e, *v;
635         int64_t n;
636 
637         v = ucv_string_get(val);
638 
639         if (!v || !isxdigit(*v))
640                 return ucv_double_new(NAN);
641 
642         n = strtoll(v, &e, 16);
643 
644         if (e == v || *e)
645                 return ucv_double_new(NAN);
646 
647         return ucv_int64_new(n);
648 }
649 
650 static uc_value_t *
651 uc_int(uc_vm_t *vm, size_t nargs)
652 {
653         uc_value_t *val = uc_fn_arg(0);
654         uc_value_t *base = uc_fn_arg(1);
655         char *e, *v;
656         int64_t n;
657 
658         if (ucv_type(val) == UC_STRING) {
659                 errno = 0;
660                 v = ucv_string_get(val);
661                 n = strtoll(v, &e, base ? ucv_int64_get(base) : 10);
662 
663                 if (e == v)
664                         return ucv_double_new(NAN);
665         }
666         else {
667                 n = ucv_to_integer(val);
668         }
669 
670         if (errno == EINVAL || errno == ERANGE)
671                 return ucv_double_new(NAN);
672 
673         return ucv_int64_new(n);
674 }
675 
676 static uc_value_t *
677 uc_join(uc_vm_t *vm, size_t nargs)
678 {
679         uc_value_t *sep = uc_fn_arg(0);
680         uc_value_t *arr = uc_fn_arg(1);
681         size_t arrlen, arridx;
682         uc_stringbuf_t *buf;
683 
684         if (ucv_type(arr) != UC_ARRAY)
685                 return NULL;
686 
687         buf = ucv_stringbuf_new();
688 
689         for (arrlen = ucv_array_length(arr), arridx = 0; arridx < arrlen; arridx++) {
690                 if (arridx > 0)
691                         ucv_to_stringbuf(vm, buf, sep, false);
692 
693                 ucv_to_stringbuf(vm, buf, ucv_array_get(arr, arridx), false);
694         }
695 
696         return ucv_stringbuf_finish(buf);
697 }
698 
699 static uc_value_t *
700 uc_keys(uc_vm_t *vm, size_t nargs)
701 {
702         uc_value_t *obj = uc_fn_arg(0);
703         uc_value_t *arr = NULL;
704 
705         if (ucv_type(obj) != UC_OBJECT)
706                 return NULL;
707 
708         arr = ucv_array_new(vm);
709 
710         ucv_object_foreach(obj, key, val) {
711                 (void)val;
712                 ucv_array_push(arr, ucv_string_new(key));
713         }
714 
715         return arr;
716 }
717 
718 static uc_value_t *
719 uc_lc(uc_vm_t *vm, size_t nargs)
720 {
721         char *str = ucv_to_string(vm, uc_fn_arg(0));
722         uc_value_t *rv = NULL;
723         char *p;
724 
725         if (!str)
726                 return NULL;
727 
728         for (p = str; *p; p++)
729                 if (*p >= 'A' && *p <= 'Z')
730                         *p |= 32;
731 
732         rv = ucv_string_new(str);
733 
734         free(str);
735 
736         return rv;
737 }
738 
739 static uc_value_t *
740 uc_map(uc_vm_t *vm, size_t nargs)
741 {
742         uc_value_t *obj = uc_fn_arg(0);
743         uc_value_t *func = uc_fn_arg(1);
744         uc_value_t *arr, *rv;
745         size_t arridx, arrlen;
746 
747         if (ucv_type(obj) != UC_ARRAY)
748                 return NULL;
749 
750         arr = ucv_array_new(vm);
751 
752         for (arrlen = ucv_array_length(obj), arridx = 0; arridx < arrlen; arridx++) {
753                 uc_vm_ctx_push(vm);
754                 uc_vm_stack_push(vm, ucv_get(func));
755                 uc_vm_stack_push(vm, ucv_get(ucv_array_get(obj, arridx)));
756                 uc_vm_stack_push(vm, ucv_int64_new(arridx));
757                 uc_vm_stack_push(vm, ucv_get(obj));
758 
759                 if (uc_vm_call(vm, true, 3)) {
760                         ucv_put(arr);
761 
762                         return NULL;
763                 }
764 
765                 rv = uc_vm_stack_pop(vm);
766 
767                 ucv_array_push(arr, rv);
768         }
769 
770         return arr;
771 }
772 
773 static uc_value_t *
774 uc_ord(uc_vm_t *vm, size_t nargs)
775 {
776         uc_value_t *obj = uc_fn_arg(0);
777         const char *str;
778         int64_t n = 0;
779         size_t len;
780 
781         if (ucv_type(obj) != UC_STRING)
782                 return NULL;
783 
784         str = ucv_string_get(obj);
785         len = ucv_string_length(obj);
786 
787         if (nargs > 1) {
788                 n = ucv_int64_get(uc_fn_arg(1));
789 
790                 if (errno == EINVAL)
791                         return NULL;
792 
793                 if (n < 0)
794                         n += len;
795         }
796 
797         if (n < 0 || (uint64_t)n >= len)
798                 return NULL;
799 
800         return ucv_int64_new((uint8_t)str[n]);
801 }
802 
803 static uc_value_t *
804 uc_type(uc_vm_t *vm, size_t nargs)
805 {
806         uc_value_t *v = uc_fn_arg(0);
807         uc_type_t t = ucv_type(v);
808 
809         switch (t) {
810         case UC_CFUNCTION:
811         case UC_CLOSURE:
812                 return ucv_string_new("function");
813 
814         case UC_INTEGER:
815                 return ucv_string_new("int");
816 
817         case UC_BOOLEAN:
818                 return ucv_string_new("bool");
819 
820         case UC_NULL:
821                 return NULL;
822 
823         default:
824                 return ucv_string_new(ucv_typename(v));
825         }
826 }
827 
828 static uc_value_t *
829 uc_reverse(uc_vm_t *vm, size_t nargs)
830 {
831         uc_value_t *obj = uc_fn_arg(0);
832         uc_value_t *rv = NULL;
833         size_t len, arridx;
834         const char *str;
835         char *dup, *p;
836 
837         if (ucv_type(obj) == UC_ARRAY) {
838                 if (!assert_mutable_array(vm, obj))
839                         return NULL;
840 
841                 rv = ucv_array_new(vm);
842 
843                 for (arridx = ucv_array_length(obj); arridx > 0; arridx--)
844                         ucv_array_push(rv, ucv_get(ucv_array_get(obj, arridx - 1)));
845         }
846         else if (ucv_type(obj) == UC_STRING) {
847                 len = ucv_string_length(obj);
848                 str = ucv_string_get(obj);
849                 p = dup = xalloc(len + 1);
850 
851                 while (len > 0)
852                         *p++ = str[--len];
853 
854                 rv = ucv_string_new(dup);
855 
856                 free(dup);
857         }
858 
859         return rv;
860 }
861 
862 
863 static struct {
864         uc_vm_t *vm;
865         bool ex;
866         uc_value_t *fn;
867 } sort_ctx;
868 
869 static int
870 default_cmp(uc_value_t *v1, uc_value_t *v2)
871 {
872         char *s1, *s2;
873         bool f1, f2;
874         int res;
875 
876         /* when both operands are numeric then compare numerically */
877         if ((ucv_type(v1) == UC_INTEGER || ucv_type(v1) == UC_DOUBLE) &&
878             (ucv_type(v2) == UC_INTEGER || ucv_type(v2) == UC_DOUBLE)) {
879                 ucv_compare(0, v1, v2, &res);
880 
881                 return res;
882         }
883 
884         /* otherwise convert both operands to strings and compare lexically */
885         s1 = uc_cast_string(sort_ctx.vm, &v1, &f1);
886         s2 = uc_cast_string(sort_ctx.vm, &v2, &f2);
887 
888         res = strcmp(s1, s2);
889 
890         if (f1) free(s1);
891         if (f2) free(s2);
892 
893         return res;
894 }
895 
896 static int
897 sort_fn(const void *k1, const void *k2)
898 {
899         uc_value_t *rv, *null = ucv_int64_new(0);
900         uc_value_t * const *v1 = k1;
901         uc_value_t * const *v2 = k2;
902         int res;
903 
904         if (!sort_ctx.fn)
905                 return default_cmp(*v1, *v2);
906 
907         if (sort_ctx.ex)
908                 return 0;
909 
910         uc_vm_ctx_push(sort_ctx.vm);
911         uc_vm_stack_push(sort_ctx.vm, ucv_get(sort_ctx.fn));
912         uc_vm_stack_push(sort_ctx.vm, ucv_get(*v1));
913         uc_vm_stack_push(sort_ctx.vm, ucv_get(*v2));
914 
915         if (uc_vm_call(sort_ctx.vm, true, 2)) {
916                 sort_ctx.ex = true;
917 
918                 return 0;
919         }
920 
921         rv = uc_vm_stack_pop(sort_ctx.vm);
922 
923         ucv_compare(0, rv, null, &res);
924 
925         ucv_put(null);
926         ucv_put(rv);
927 
928         return res;
929 }
930 
931 static uc_value_t *
932 uc_sort(uc_vm_t *vm, size_t nargs)
933 {
934         uc_value_t *arr = uc_fn_arg(0);
935         uc_value_t *fn = uc_fn_arg(1);
936 
937         if (!assert_mutable_array(vm, arr))
938                 return NULL;
939 
940         sort_ctx.vm = vm;
941         sort_ctx.fn = fn;
942 
943         ucv_array_sort(arr, sort_fn);
944 
945         return sort_ctx.ex ? NULL : ucv_get(arr);
946 }
947 
948 static uc_value_t *
949 uc_splice(uc_vm_t *vm, size_t nargs)
950 {
951         uc_value_t *arr = uc_fn_arg(0);
952         int64_t ofs = ucv_to_integer(uc_fn_arg(1));
953         int64_t remlen = ucv_to_integer(uc_fn_arg(2));
954         size_t arrlen, addlen, idx;
955 
956         if (!assert_mutable_array(vm, arr))
957                 return NULL;
958 
959         arrlen = ucv_array_length(arr);
960         addlen = nargs;
961 
962         if (addlen == 1) {
963                 ofs = 0;
964                 addlen = 0;
965                 remlen = arrlen;
966         }
967         else if (addlen == 2) {
968                 if (ofs < 0) {
969                         ofs = arrlen + ofs;
970 
971                         if (ofs < 0)
972                                 ofs = 0;
973                 }
974                 else if ((uint64_t)ofs > arrlen) {
975                         ofs = arrlen;
976                 }
977 
978                 addlen = 0;
979                 remlen = arrlen - ofs;
980         }
981         else {
982                 if (ofs < 0) {
983                         ofs = arrlen + ofs;
984 
985                         if (ofs < 0)
986                                 ofs = 0;
987                 }
988                 else if ((uint64_t)ofs > arrlen) {
989                         ofs = arrlen;
990                 }
991 
992                 if (remlen < 0) {
993                         remlen = arrlen - ofs + remlen;
994 
995                         if (remlen < 0)
996                                 remlen = 0;
997                 }
998                 else if ((uint64_t)remlen > arrlen - (uint64_t)ofs) {
999                         remlen = arrlen - ofs;
1000                 }
1001 
1002                 addlen -= 3;
1003         }
1004 
1005         if (addlen < (uint64_t)remlen) {
1006                 ucv_array_delete(arr, ofs, remlen - addlen);
1007         }
1008         else if (addlen > (uint64_t)remlen) {
1009                 for (idx = arrlen; idx > (uint64_t)ofs; idx--)
1010                         ucv_array_set(arr, idx + addlen - remlen - 1,
1011                                 ucv_get(ucv_array_get(arr, idx - 1)));
1012         }
1013 
1014         for (idx = 0; idx < addlen; idx++)
1015                 ucv_array_set(arr, ofs + idx,
1016                         ucv_get(uc_fn_arg(3 + idx)));
1017 
1018         return ucv_get(arr);
1019 }
1020 
1021 static uc_value_t *
1022 uc_split(uc_vm_t *vm, size_t nargs)
1023 {
1024         uc_value_t *str = uc_fn_arg(0);
1025         uc_value_t *sep = uc_fn_arg(1);
1026         uc_value_t *lim = uc_fn_arg(2);
1027         uc_value_t *arr = NULL;
1028         const char *p, *sepstr, *splitstr;
1029         size_t seplen, splitlen, limit;
1030         int eflags = 0, res;
1031         regmatch_t pmatch;
1032         uc_regexp_t *re;
1033 
1034         if (!sep || ucv_type(str) != UC_STRING)
1035                 return NULL;
1036 
1037         arr = ucv_array_new(vm);
1038         splitlen = ucv_string_length(str);
1039         p = splitstr = ucv_string_get(str);
1040         limit = lim ? ucv_uint64_get(lim) : SIZE_MAX;
1041 
1042         if (limit == 0)
1043                 goto out;
1044 
1045         if (ucv_type(sep) == UC_REGEXP) {
1046                 re = (uc_regexp_t *)sep;
1047 
1048                 while (limit > 1) {
1049                         res = regexec(&re->regexp, splitstr, 1, &pmatch, eflags);
1050 
1051                         if (res == REG_NOMATCH)
1052                                 break;
1053 
1054                         if (pmatch.rm_so != pmatch.rm_eo) {
1055                                 ucv_array_push(arr, ucv_string_new_length(splitstr, pmatch.rm_so));
1056                                 splitstr += pmatch.rm_eo;
1057                         }
1058                         else if (*splitstr) {
1059                                 ucv_array_push(arr, ucv_string_new_length(splitstr, 1));
1060                                 splitstr++;
1061                         }
1062                         else {
1063                                 goto out;
1064                         }
1065 
1066                         eflags |= REG_NOTBOL;
1067                         limit--;
1068                 }
1069 
1070                 ucv_array_push(arr, ucv_string_new(splitstr));
1071         }
1072         else if (ucv_type(sep) == UC_STRING) {
1073                 sepstr = ucv_string_get(sep);
1074                 seplen = ucv_string_length(sep);
1075 
1076                 if (splitlen == 0) {
1077                         ucv_array_push(arr, ucv_string_new_length("", 0));
1078                 }
1079                 else if (seplen == 0) {
1080                         while (limit > 1 && splitlen > 0) {
1081                                 ucv_array_push(arr, ucv_string_new_length(p, 1));
1082 
1083                                 limit--;
1084                                 splitlen--;
1085                                 p++;
1086                         }
1087 
1088                         if (splitlen > 0)
1089                                 ucv_array_push(arr, ucv_string_new_length(p, splitlen));
1090                 }
1091                 else {
1092                         while (limit > 1 && splitlen >= seplen) {
1093                                 if (!memcmp(p, sepstr, seplen)) {
1094                                         ucv_array_push(arr, ucv_string_new_length(splitstr, p - splitstr));
1095 
1096                                         p = splitstr = p + seplen;
1097                                         splitlen -= seplen;
1098                                         limit--;
1099                                         continue;
1100                                 }
1101 
1102                                 splitlen--;
1103                                 p++;
1104                         }
1105 
1106                         ucv_array_push(arr, ucv_string_new_length(splitstr, p - splitstr + splitlen));
1107                 }
1108         }
1109         else {
1110                 ucv_put(arr);
1111 
1112                 return NULL;
1113         }
1114 
1115 out:
1116         return arr;
1117 }
1118 
1119 static uc_value_t *
1120 uc_substr(uc_vm_t *vm, size_t nargs)
1121 {
1122         uc_value_t *str = uc_fn_arg(0);
1123         int64_t ofs = ucv_to_integer(uc_fn_arg(1));
1124         int64_t sublen = ucv_to_integer(uc_fn_arg(2));
1125         const char *p;
1126         size_t len;
1127 
1128         if (ucv_type(str) != UC_STRING)
1129                 return NULL;
1130 
1131         p = ucv_string_get(str);
1132         len = ucv_string_length(str);
1133 
1134         switch (nargs) {
1135         case 1:
1136                 ofs = 0;
1137                 sublen = len;
1138 
1139                 break;
1140 
1141         case 2:
1142                 if (ofs < 0) {
1143                         ofs = len + ofs;
1144 
1145                         if (ofs < 0)
1146                                 ofs = 0;
1147                 }
1148                 else if ((uint64_t)ofs > len) {
1149                         ofs = len;
1150                 }
1151 
1152                 sublen = len - ofs;
1153 
1154                 break;
1155 
1156         default:
1157                 if (ofs < 0) {
1158                         ofs = len + ofs;
1159 
1160                         if (ofs < 0)
1161                                 ofs = 0;
1162                 }
1163                 else if ((uint64_t)ofs > len) {
1164                         ofs = len;
1165                 }
1166 
1167                 if (sublen < 0) {
1168                         sublen = len - ofs + sublen;
1169 
1170                         if (sublen < 0)
1171                                 sublen = 0;
1172                 }
1173                 else if ((uint64_t)sublen > len - (uint64_t)ofs) {
1174                         sublen = len - ofs;
1175                 }
1176 
1177                 break;
1178         }
1179 
1180         return ucv_string_new_length(p + ofs, sublen);
1181 }
1182 
1183 static uc_value_t *
1184 uc_time(uc_vm_t *vm, size_t nargs)
1185 {
1186         time_t t = time(NULL);
1187 
1188         return ucv_int64_new((int64_t)t);
1189 }
1190 
1191 static uc_value_t *
1192 uc_uc(uc_vm_t *vm, size_t nargs)
1193 {
1194         char *str = ucv_to_string(vm, uc_fn_arg(0));
1195         uc_value_t *rv = NULL;
1196         char *p;
1197 
1198         if (!str)
1199                 return NULL;
1200 
1201         for (p = str; *p; p++)
1202                 if (*p >= 'a' && *p <= 'z')
1203                         *p &= ~32;
1204 
1205         rv = ucv_string_new(str);
1206 
1207         free(str);
1208 
1209         return rv;
1210 }
1211 
1212 static uc_value_t *
1213 uc_uchr(uc_vm_t *vm, size_t nargs)
1214 {
1215         uc_value_t *rv = NULL;
1216         size_t idx, ulen;
1217         char *p, *str;
1218         int64_t n;
1219         int rem;
1220 
1221         for (idx = 0, ulen = 0; idx < nargs; idx++) {
1222                 n = ucv_to_integer(uc_fn_arg(idx));
1223 
1224                 if (errno == EINVAL || errno == ERANGE || n < 0 || n > 0x10FFFF)
1225                         ulen += 3;
1226                 else if (n <= 0x7F)
1227                         ulen++;
1228                 else if (n <= 0x7FF)
1229                         ulen += 2;
1230                 else if (n <= 0xFFFF)
1231                         ulen += 3;
1232                 else
1233                         ulen += 4;
1234         }
1235 
1236         str = xalloc(ulen);
1237 
1238         for (idx = 0, p = str, rem = ulen; idx < nargs; idx++) {
1239                 n = ucv_to_integer(uc_fn_arg(idx));
1240 
1241                 if (errno == EINVAL || errno == ERANGE || n < 0 || n > 0x10FFFF)
1242                         n = 0xFFFD;
1243 
1244                 if (!utf8enc(&p, &rem, n))
1245                         break;
1246         }
1247 
1248         rv = ucv_string_new_length(str, ulen);
1249 
1250         free(str);
1251 
1252         return rv;
1253 }
1254 
1255 static uc_value_t *
1256 uc_values(uc_vm_t *vm, size_t nargs)
1257 {
1258         uc_value_t *obj = uc_fn_arg(0);
1259         uc_value_t *arr;
1260 
1261         if (ucv_type(obj) != UC_OBJECT)
1262                 return NULL;
1263 
1264         arr = ucv_array_new(vm);
1265 
1266         ucv_object_foreach(obj, key, val) {
1267                 (void)key;
1268                 ucv_array_push(arr, ucv_get(val));
1269         }
1270 
1271         return arr;
1272 }
1273 
1274 static uc_value_t *
1275 uc_trim_common(uc_vm_t *vm, size_t nargs, bool start, bool end)
1276 {
1277         uc_value_t *str = uc_fn_arg(0);
1278         uc_value_t *chr = uc_fn_arg(1);
1279         const char *p, *c;
1280         size_t len;
1281 
1282         if (ucv_type(str) != UC_STRING ||
1283                 (chr != NULL && ucv_type(chr) != UC_STRING))
1284                 return NULL;
1285 
1286         c = ucv_string_get(chr);
1287         c = c ? c : " \t\r\n";
1288 
1289         p = ucv_string_get(str);
1290         len = ucv_string_length(str);
1291 
1292         if (start) {
1293                 while (*p) {
1294                         if (!strchr(c, *p))
1295                                 break;
1296 
1297                         p++;
1298                         len--;
1299                 }
1300         }
1301 
1302         if (end) {
1303                 while (len > 0) {
1304                         if (!strchr(c, p[len - 1]))
1305                                 break;
1306 
1307                         len--;
1308                 }
1309         }
1310 
1311         return ucv_string_new_length(p, len);
1312 }
1313 
1314 static uc_value_t *
1315 uc_trim(uc_vm_t *vm, size_t nargs)
1316 {
1317         return uc_trim_common(vm, nargs, true, true);
1318 }
1319 
1320 static uc_value_t *
1321 uc_ltrim(uc_vm_t *vm, size_t nargs)
1322 {
1323         return uc_trim_common(vm, nargs, true, false);
1324 }
1325 
1326 static uc_value_t *
1327 uc_rtrim(uc_vm_t *vm, size_t nargs)
1328 {
1329         return uc_trim_common(vm, nargs, false, true);
1330 }
1331 
1332 enum {
1333         FMT_F_ALT   = (1 << 0),
1334         FMT_F_ZERO  = (1 << 1),
1335         FMT_F_LEFT  = (1 << 2),
1336         FMT_F_SPACE = (1 << 3),
1337         FMT_F_SIGN  = (1 << 4),
1338         FMT_F_WIDTH = (1 << 5),
1339         FMT_F_PREC  = (1 << 6),
1340 };
1341 
1342 enum {
1343         FMT_C_NONE = (1 << 0),
1344         FMT_C_INT  = (1 << 1),
1345         FMT_C_UINT = (1 << 2),
1346         FMT_C_DBL  = (1 << 3),
1347         FMT_C_CHR  = (1 << 4),
1348         FMT_C_STR  = (1 << 5),
1349         FMT_C_JSON = (1 << 6),
1350 };
1351 
1352 static void
1353 uc_printf_common(uc_vm_t *vm, size_t nargs, uc_stringbuf_t *buf)
1354 {
1355         char *s, sfmt[sizeof("%#0- +0123456789.0123456789%")];
1356         uint32_t conv, flags, width, precision;
1357         uc_value_t *fmt = uc_fn_arg(0), *arg;
1358         const char *fstr, *last, *p, *cfmt;
1359         size_t argidx = 1, argpos, sfmtlen;
1360         uint64_t u;
1361         int64_t n;
1362         double d;
1363 
1364         if (ucv_type(fmt) == UC_STRING)
1365                 fstr = ucv_string_get(fmt);
1366         else
1367                 fstr = "";
1368 
1369         for (last = p = fstr; *p; p++) {
1370                 if (*p == '%') {
1371                         ucv_stringbuf_addstr(buf, last, p - last);
1372 
1373                         last = p++;
1374 
1375                         flags = 0;
1376                         width = 0;
1377                         precision = 0;
1378 
1379                         argpos = argidx;
1380 
1381                         if (*p >= '1' && *p <= '9') {
1382                                 while (isdigit(*p))
1383                                         width = width * 10 + (*p++ - '');
1384 
1385                                 /* if a dollar sign follows, this is an argument index */
1386                                 if (*p == '$') {
1387                                         argpos = width;
1388                                         width = 0;
1389                                         p++;
1390                                 }
1391 
1392                                 /* otherwise skip to parsing precision, flags can't possibly follow */
1393                                 else {
1394                                         flags |= FMT_F_WIDTH;
1395                                         goto parse_precision;
1396                                 }
1397                         }
1398 
1399                         while (*p != '\0' && strchr("#0- +", *p)) {
1400                                 switch (*p++) {
1401                                 case '#': flags |= FMT_F_ALT;   break;
1402                                 case '': flags |= FMT_F_ZERO;  break;
1403                                 case '-': flags |= FMT_F_LEFT;  break;
1404                                 case ' ': flags |= FMT_F_SPACE; break;
1405                                 case '+': flags |= FMT_F_SIGN;  break;
1406                                 }
1407                         }
1408 
1409                         if (*p >= '1' && *p <= '9') {
1410                                 while (isdigit(*p))
1411                                         width = width * 10 + (*p++ - '');
1412 
1413                                 flags |= FMT_F_WIDTH;
1414                         }
1415 
1416 parse_precision:
1417                         if (*p == '.') {
1418                                 p++;
1419 
1420                                 if (*p == '-') {
1421                                         p++;
1422 
1423                                         while (isdigit(*p))
1424                                                 p++;
1425                                 }
1426                                 else {
1427                                         while (isdigit(*p))
1428                                                 precision = precision * 10 + (*p++ - '');
1429                                 }
1430 
1431                                 flags |= FMT_F_PREC;
1432                         }
1433 
1434                         switch (*p) {
1435                         case 'd':
1436                         case 'i':
1437                                 conv = FMT_C_INT;
1438                                 flags &= ~FMT_F_PREC;
1439                                 cfmt = PRId64;
1440                                 break;
1441 
1442                         case 'o':
1443                                 conv = FMT_C_UINT;
1444                                 flags &= ~FMT_F_PREC;
1445                                 cfmt = PRIo64;
1446                                 break;
1447 
1448                         case 'u':
1449                                 conv = FMT_C_UINT;
1450                                 flags &= ~FMT_F_PREC;
1451                                 cfmt = PRIu64;
1452                                 break;
1453 
1454                         case 'x':
1455                                 conv = FMT_C_UINT;
1456                                 flags &= ~FMT_F_PREC;
1457                                 cfmt = PRIx64;
1458                                 break;
1459 
1460                         case 'X':
1461                                 conv = FMT_C_UINT;
1462                                 flags &= ~FMT_F_PREC;
1463                                 cfmt = PRIX64;
1464                                 break;
1465 
1466                         case 'e':
1467                                 conv = FMT_C_DBL;
1468                                 cfmt = "e";
1469                                 break;
1470 
1471                         case 'E':
1472                                 conv = FMT_C_DBL;
1473                                 cfmt = "E";
1474                                 break;
1475 
1476                         case 'f':
1477                                 conv = FMT_C_DBL;
1478                                 cfmt = "f";
1479                                 break;
1480 
1481                         case 'F':
1482                                 conv = FMT_C_DBL;
1483                                 cfmt = "F";
1484                                 break;
1485 
1486                         case 'g':
1487                                 conv = FMT_C_DBL;
1488                                 cfmt = "g";
1489                                 break;
1490 
1491                         case 'G':
1492                                 conv = FMT_C_DBL;
1493                                 cfmt = "G";
1494                                 break;
1495 
1496                         case 'c':
1497                                 conv = FMT_C_CHR;
1498                                 flags &= ~FMT_F_PREC;
1499                                 cfmt = "c";
1500                                 break;
1501 
1502                         case 's':
1503                                 conv = FMT_C_STR;
1504                                 flags &= ~FMT_F_ZERO;
1505                                 cfmt = "s";
1506                                 break;
1507 
1508                         case 'J':
1509                                 conv = FMT_C_JSON;
1510 
1511                                 if (flags & FMT_F_PREC) {
1512                                         flags &= ~FMT_F_PREC;
1513                                         precision++;
1514                                 }
1515 
1516                                 cfmt = "s";
1517                                 break;
1518 
1519                         case '%':
1520                                 conv = FMT_C_NONE;
1521                                 flags = 0;
1522                                 cfmt = "%";
1523                                 break;
1524 
1525                         case '\0':
1526                                 p--;
1527                                 /* fall through */
1528 
1529                         default:
1530                                 continue;
1531                         }
1532 
1533                         sfmtlen = 0;
1534                         sfmt[sfmtlen++] = '%';
1535 
1536                         if (flags & FMT_F_ALT)   sfmt[sfmtlen++] = '#';
1537                         if (flags & FMT_F_ZERO)  sfmt[sfmtlen++] = '';
1538                         if (flags & FMT_F_LEFT)  sfmt[sfmtlen++] = '-';
1539                         if (flags & FMT_F_SPACE) sfmt[sfmtlen++] = ' ';
1540                         if (flags & FMT_F_SIGN)  sfmt[sfmtlen++] = '+';
1541 
1542                         if (flags & FMT_F_WIDTH)
1543                                 sfmtlen += snprintf(&sfmt[sfmtlen], sizeof(sfmt) - sfmtlen, "%" PRIu32, width);
1544 
1545                         if (flags & FMT_F_PREC)
1546                                 sfmtlen += snprintf(&sfmt[sfmtlen], sizeof(sfmt) - sfmtlen, ".%" PRIu32, precision);
1547 
1548                         snprintf(&sfmt[sfmtlen], sizeof(sfmt) - sfmtlen, "%s", cfmt);
1549 
1550                         switch (conv) {
1551                         case FMT_C_NONE:
1552                                 ucv_stringbuf_addstr(buf, cfmt, strlen(cfmt));
1553                                 break;
1554 
1555                         case FMT_C_INT:
1556                                 argidx++;
1557                                 arg = uc_fn_arg(argpos);
1558                                 n = ucv_to_integer(arg);
1559 
1560                                 if (errno == ERANGE)
1561                                         n = (int64_t)ucv_to_unsigned(arg);
1562 
1563                                 ucv_stringbuf_printf(buf, sfmt, n);
1564                                 break;
1565 
1566                         case FMT_C_UINT:
1567                                 argidx++;
1568                                 arg = uc_fn_arg(argpos);
1569                                 u = ucv_to_unsigned(arg);
1570 
1571                                 if (errno == ERANGE)
1572                                         u = (uint64_t)ucv_to_integer(arg);
1573 
1574                                 ucv_stringbuf_printf(buf, sfmt, u);
1575                                 break;
1576 
1577                         case FMT_C_DBL:
1578                                 argidx++;
1579                                 d = ucv_to_double(uc_fn_arg(argpos));
1580                                 ucv_stringbuf_printf(buf, sfmt, d);
1581                                 break;
1582 
1583                         case FMT_C_CHR:
1584                                 argidx++;
1585                                 n = ucv_to_integer(uc_fn_arg(argpos));
1586                                 ucv_stringbuf_printf(buf, sfmt, (int)n);
1587                                 break;
1588 
1589                         case FMT_C_STR:
1590                                 argidx++;
1591                                 arg = uc_fn_arg(argpos);
1592 
1593                                 switch (ucv_type(arg)) {
1594                                 case UC_STRING:
1595                                         ucv_stringbuf_printf(buf, sfmt, ucv_string_get(arg));
1596                                         break;
1597 
1598                                 case UC_NULL:
1599                                         ucv_stringbuf_append(buf, "(null)");
1600                                         break;
1601 
1602                                 default:
1603                                         s = ucv_to_string(vm, arg);
1604                                         ucv_stringbuf_printf(buf, sfmt, s ? s : "(null)");
1605                                         free(s);
1606                                 }
1607 
1608                                 break;
1609 
1610                         case FMT_C_JSON:
1611                                 argidx++;
1612                                 s = ucv_to_jsonstring_formatted(vm,
1613                                         uc_fn_arg(argpos),
1614                                         precision > 0 ? (precision > 1 ? ' ' : '\t') : '\0',
1615                                         precision > 0 ? (precision > 1 ? precision - 1 : 1) : 0);
1616 
1617                                 ucv_stringbuf_printf(buf, sfmt, s ? s : "null");
1618                                 free(s);
1619                                 break;
1620                         }
1621 
1622                         last = p + 1;
1623                 }
1624         }
1625 
1626         ucv_stringbuf_addstr(buf, last, p - last);
1627 }
1628 
1629 static uc_value_t *
1630 uc_sprintf(uc_vm_t *vm, size_t nargs)
1631 {
1632         uc_stringbuf_t *buf = ucv_stringbuf_new();
1633 
1634         uc_printf_common(vm, nargs, buf);
1635 
1636         return ucv_stringbuf_finish(buf);
1637 }
1638 
1639 static uc_value_t *
1640 uc_printf(uc_vm_t *vm, size_t nargs)
1641 {
1642         uc_stringbuf_t *buf = xprintbuf_new();
1643         size_t len;
1644 
1645         uc_printf_common(vm, nargs, buf);
1646 
1647         len = fwrite(buf->buf, 1, printbuf_length(buf), vm->output);
1648 
1649         printbuf_free(buf);
1650 
1651         return ucv_int64_new(len);
1652 }
1653 
1654 static bool
1655 uc_require_so(uc_vm_t *vm, const char *path, uc_value_t **res)
1656 {
1657         void (*init)(uc_vm_t *, uc_value_t *);
1658         uc_value_t *scope;
1659         struct stat st;
1660         void *dlh;
1661 
1662         if (stat(path, &st))
1663                 return false;
1664 
1665         dlerror();
1666         dlh = dlopen(path, RTLD_LAZY|RTLD_LOCAL);
1667 
1668         if (!dlh) {
1669                 uc_vm_raise_exception(vm, EXCEPTION_RUNTIME,
1670                                       "Unable to dlopen file '%s': %s", path, dlerror());
1671 
1672                 return true;
1673         }
1674 
1675         *(void **)(&init) = dlsym(dlh, "uc_module_entry");
1676 
1677         if (!init) {
1678                 uc_vm_raise_exception(vm, EXCEPTION_RUNTIME,
1679                                       "Module '%s' provides no 'uc_module_entry' function", path);
1680 
1681                 return true;
1682         }
1683 
1684         scope = ucv_object_new(vm);
1685 
1686         init(vm, scope);
1687 
1688         *res = scope;
1689 
1690         return true;
1691 }
1692 
1693 static uc_value_t *
1694 uc_loadfile(uc_vm_t *vm, size_t nargs);
1695 
1696 static uc_value_t *
1697 uc_callfunc(uc_vm_t *vm, size_t nargs);
1698 
1699 static bool
1700 uc_require_ucode(uc_vm_t *vm, const char *path, uc_value_t *scope, uc_value_t **res, bool raw_mode)
1701 {
1702         uc_parse_config_t config = *vm->config, *prev_config = vm->config;
1703         uc_value_t *closure;
1704         struct stat st;
1705 
1706         if (stat(path, &st))
1707                 return false;
1708 
1709         config.raw_mode = raw_mode;
1710         vm->config = &config;
1711 
1712         uc_vm_stack_push(vm, ucv_string_new(path));
1713 
1714         closure = uc_loadfile(vm, 1);
1715 
1716         ucv_put(uc_vm_stack_pop(vm));
1717 
1718         if (closure) {
1719                 uc_vm_stack_push(vm, closure);
1720                 uc_vm_stack_push(vm, NULL);
1721                 uc_vm_stack_push(vm, scope);
1722 
1723                 *res = uc_callfunc(vm, 3);
1724 
1725                 uc_vm_stack_pop(vm);
1726                 uc_vm_stack_pop(vm);
1727                 uc_vm_stack_pop(vm);
1728         }
1729 
1730         vm->config = prev_config;
1731 
1732         return true;
1733 }
1734 
1735 static bool
1736 uc_require_path(uc_vm_t *vm, const char *path_template, const char *name, uc_value_t **res, bool so_only)
1737 {
1738         uc_stringbuf_t *buf = xprintbuf_new();
1739         const char *p, *q, *last;
1740         uc_value_t *modtable;
1741         bool rv;
1742 
1743         modtable = ucv_property_get(uc_vm_scope_get(vm), "modules");
1744         *res = ucv_get(ucv_object_get(modtable, name, &rv));
1745 
1746         if (rv)
1747                 goto out;
1748 
1749         p = strchr(path_template, '*');
1750 
1751         if (!p)
1752                 goto out;
1753 
1754         ucv_stringbuf_addstr(buf, path_template, p - path_template);
1755 
1756         for (q = last = name;; q++) {
1757                 if (*q == '.' || *q == '\0') {
1758                         ucv_stringbuf_addstr(buf, last, q - last);
1759 
1760                         if (*q)
1761                                 ucv_stringbuf_append(buf, "/");
1762                         else
1763                                 ucv_stringbuf_addstr(buf, p + 1, strlen(p + 1));
1764 
1765                         if (*q == '\0')
1766                                 break;
1767 
1768                         last = q + 1;
1769                 }
1770                 else if (!isalnum(*q) && *q != '_') {
1771                         goto out;
1772                 }
1773         }
1774 
1775         if (!strcmp(p + 1, ".so"))
1776                 rv = uc_require_so(vm, buf->buf, res);
1777         else if (!strcmp(p + 1, ".uc") && !so_only)
1778                 rv = uc_require_ucode(vm, buf->buf, NULL, res, true);
1779 
1780         if (rv)
1781                 ucv_object_add(modtable, name, ucv_get(*res));
1782 
1783 out:
1784         printbuf_free(buf);
1785 
1786         return rv;
1787 }
1788 
1789 uc_value_t *
1790 uc_require_library(uc_vm_t *vm, uc_value_t *nameval, bool so_only)
1791 {
1792         uc_value_t *search, *se, *res;
1793         size_t arridx, arrlen;
1794         const char *name;
1795 
1796         if (ucv_type(nameval) != UC_STRING)
1797                 return NULL;
1798 
1799         name = ucv_string_get(nameval);
1800         search = ucv_property_get(uc_vm_scope_get(vm), "REQUIRE_SEARCH_PATH");
1801 
1802         if (ucv_type(search) != UC_ARRAY) {
1803                 uc_vm_raise_exception(vm, EXCEPTION_RUNTIME,
1804                                       "Global require search path not set");
1805 
1806                 return NULL;
1807         }
1808 
1809         for (arridx = 0, arrlen = ucv_array_length(search); arridx < arrlen; arridx++) {
1810                 se = ucv_array_get(search, arridx);
1811 
1812                 if (ucv_type(se) != UC_STRING)
1813                         continue;
1814 
1815                 if (uc_require_path(vm, ucv_string_get(se), name, &res, so_only))
1816                         return res;
1817         }
1818 
1819         uc_vm_raise_exception(vm, EXCEPTION_RUNTIME,
1820                               "No module named '%s' could be found", name);
1821 
1822         return NULL;
1823 }
1824 
1825 static uc_value_t *
1826 uc_require(uc_vm_t *vm, size_t nargs)
1827 {
1828         return uc_require_library(vm, uc_fn_arg(0), false);
1829 }
1830 
1831 static uc_value_t *
1832 uc_iptoarr(uc_vm_t *vm, size_t nargs)
1833 {
1834         uc_value_t *ip = uc_fn_arg(0);
1835         uc_value_t *res;
1836         union {
1837                 uint8_t u8[4];
1838                 struct in_addr in;
1839                 struct in6_addr in6;
1840         } a;
1841         int i;
1842 
1843         if (ucv_type(ip) != UC_STRING)
1844                 return NULL;
1845 
1846         if (inet_pton(AF_INET6, ucv_string_get(ip), &a)) {
1847                 res = ucv_array_new(vm);
1848 
1849                 for (i = 0; i < 16; i++)
1850                         ucv_array_push(res, ucv_int64_new(a.in6.s6_addr[i]));
1851 
1852                 return res;
1853         }
1854         else if (inet_pton(AF_INET, ucv_string_get(ip), &a)) {
1855                 res = ucv_array_new(vm);
1856 
1857                 ucv_array_push(res, ucv_int64_new(a.u8[0]));
1858                 ucv_array_push(res, ucv_int64_new(a.u8[1]));
1859                 ucv_array_push(res, ucv_int64_new(a.u8[2]));
1860                 ucv_array_push(res, ucv_int64_new(a.u8[3]));
1861 
1862                 return res;
1863         }
1864 
1865         return NULL;
1866 }
1867 
1868 static int
1869 check_byte(uc_value_t *v)
1870 {
1871         int n;
1872 
1873         if (ucv_type(v) != UC_INTEGER)
1874                 return -1;
1875 
1876         n = ucv_int64_get(v);
1877 
1878         if (n < 0 || n > 255)
1879                 return -1;
1880 
1881         return n;
1882 }
1883 
1884 static uc_value_t *
1885 uc_arrtoip(uc_vm_t *vm, size_t nargs)
1886 {
1887         uc_value_t *arr = uc_fn_arg(0);
1888         union {
1889                 uint8_t u8[4];
1890                 struct in6_addr in6;
1891         } a;
1892         char buf[INET6_ADDRSTRLEN];
1893         int i, n;
1894 
1895         if (ucv_type(arr) != UC_ARRAY)
1896                 return NULL;
1897 
1898         switch (ucv_array_length(arr)) {
1899         case 4:
1900                 for (i = 0; i < 4; i++) {
1901                         n = check_byte(ucv_array_get(arr, i));
1902 
1903                         if (n < 0)
1904                                 return NULL;
1905 
1906                         a.u8[i] = n;
1907                 }
1908 
1909                 inet_ntop(AF_INET, &a, buf, sizeof(buf));
1910 
1911                 return ucv_string_new(buf);
1912 
1913         case 16:
1914                 for (i = 0; i < 16; i++) {
1915                         n = check_byte(ucv_array_get(arr, i));
1916 
1917                         if (n < 0)
1918                                 return NULL;
1919 
1920                         a.in6.s6_addr[i] = n;
1921                 }
1922 
1923                 inet_ntop(AF_INET6, &a, buf, sizeof(buf));
1924 
1925                 return ucv_string_new(buf);
1926 
1927         default:
1928                 return NULL;
1929         }
1930 }
1931 
1932 static uc_value_t *
1933 uc_match(uc_vm_t *vm, size_t nargs)
1934 {
1935         uc_value_t *subject = uc_fn_arg(0);
1936         uc_value_t *pattern = uc_fn_arg(1);
1937         uc_value_t *rv = NULL, *m;
1938         regmatch_t *pmatch = NULL;
1939         int eflags = 0, res;
1940         uc_regexp_t *re;
1941         bool freeable;
1942         char *p;
1943         size_t i;
1944 
1945         if (ucv_type(pattern) != UC_REGEXP || !subject)
1946                 return NULL;
1947 
1948         re = (uc_regexp_t *)pattern;
1949 
1950         pmatch = calloc(1 + re->regexp.re_nsub, sizeof(regmatch_t));
1951 
1952         if (!pmatch)
1953                 return NULL;
1954 
1955         p = uc_cast_string(vm, &subject, &freeable);
1956 
1957         while (true) {
1958                 res = regexec(&re->regexp, p, 1 + re->regexp.re_nsub, pmatch, eflags);
1959 
1960                 if (res == REG_NOMATCH)
1961                         break;
1962 
1963                 m = ucv_array_new(vm);
1964 
1965                 for (i = 0; i < 1 + re->regexp.re_nsub; i++) {
1966                         if (pmatch[i].rm_so != -1)
1967                                 ucv_array_push(m,
1968                                         ucv_string_new_length(p + pmatch[i].rm_so,
1969                                                               pmatch[i].rm_eo - pmatch[i].rm_so));
1970                         else
1971                                 ucv_array_push(m, NULL);
1972                 }
1973 
1974                 if (re->global) {
1975                         if (!rv)
1976                                 rv = ucv_array_new(vm);
1977 
1978                         ucv_array_push(rv, m);
1979 
1980                         if (pmatch[0].rm_so != pmatch[0].rm_eo)
1981                                 p += pmatch[0].rm_eo;
1982                         else if (*p)
1983                                 p++;
1984                         else
1985                                 break;
1986 
1987                         eflags |= REG_NOTBOL;
1988                 }
1989                 else {
1990                         rv = m;
1991                         break;
1992                 }
1993         }
1994 
1995         free(pmatch);
1996 
1997         if (freeable)
1998                 free(p);
1999 
2000         return rv;
2001 }
2002 
2003 static void
2004 uc_replace_cb(uc_vm_t *vm, uc_value_t *func,
2005               const char *subject, regmatch_t *pmatch, size_t plen,
2006               uc_stringbuf_t *resbuf)
2007 {
2008         uc_value_t *rv;
2009         size_t i;
2010 
2011         uc_vm_ctx_push(vm);
2012         uc_vm_stack_push(vm, ucv_get(func));
2013 
2014         for (i = 0; i < plen; i++) {
2015                 if (pmatch[i].rm_so != -1)
2016                         uc_vm_stack_push(vm,
2017                                 ucv_string_new_length(subject + pmatch[i].rm_so,
2018                                                       pmatch[i].rm_eo - pmatch[i].rm_so));
2019                 else
2020                         uc_vm_stack_push(vm, NULL);
2021         }
2022 
2023         if (uc_vm_call(vm, true, i) == EXCEPTION_NONE) {
2024                 rv = uc_vm_stack_pop(vm);
2025 
2026                 ucv_to_stringbuf(vm, resbuf, rv, false);
2027 
2028                 ucv_put(rv);
2029         }
2030 }
2031 
2032 static void
2033 uc_replace_str(uc_vm_t *vm, uc_value_t *str,
2034                const char *subject, regmatch_t *pmatch, size_t plen,
2035                uc_stringbuf_t *resbuf)
2036 {
2037         bool esc = false;
2038         char *p, *r;
2039         uint8_t i;
2040 
2041         for (p = r = ucv_to_string(vm, str); *p; p++) {
2042                 if (esc) {
2043                         switch (*p) {
2044                         case '&':
2045                                 if (pmatch[0].rm_so != -1)
2046                                         ucv_stringbuf_addstr(resbuf,
2047                                                 subject + pmatch[0].rm_so,
2048                                                 pmatch[0].rm_eo - pmatch[0].rm_so);
2049                                 break;
2050 
2051                         case '`':
2052                                 if (pmatch[0].rm_so != -1)
2053                                         ucv_stringbuf_addstr(resbuf, subject, pmatch[0].rm_so);
2054                                 break;
2055 
2056                         case '\'':
2057                                 if (pmatch[0].rm_so != -1)
2058                                         ucv_stringbuf_addstr(resbuf,
2059                                                 subject + pmatch[0].rm_eo,
2060                                                 strlen(subject + pmatch[0].rm_eo));
2061                                 break;
2062 
2063                         case '1':
2064                         case '2':
2065                         case '3':
2066                         case '4':
2067                         case '5':
2068                         case '6':
2069                         case '7':
2070                         case '8':
2071                         case '9':
2072                                 i = *p - '';
2073                                 if (i < plen && pmatch[i].rm_so != -1) {
2074                                         ucv_stringbuf_addstr(resbuf,
2075                                                 subject + pmatch[i].rm_so,
2076                                                 pmatch[i].rm_eo - pmatch[i].rm_so);
2077                                 }
2078                                 else {
2079                                         ucv_stringbuf_append(resbuf, "$");
2080                                         ucv_stringbuf_addstr(resbuf, p, 1);
2081                                 }
2082                                 break;
2083 
2084                         case '$':
2085                                 ucv_stringbuf_append(resbuf, "$");
2086                                 break;
2087 
2088                         default:
2089                                 ucv_stringbuf_append(resbuf, "$");
2090                                 ucv_stringbuf_addstr(resbuf, p, 1);
2091                         }
2092 
2093                         esc = false;
2094                 }
2095                 else if (*p == '$') {
2096                         esc = true;
2097                 }
2098                 else {
2099                         ucv_stringbuf_addstr(resbuf, p, 1);
2100                 }
2101         }
2102 
2103         free(r);
2104 }
2105 
2106 static uc_value_t *
2107 uc_replace(uc_vm_t *vm, size_t nargs)
2108 {
2109         char *sb = NULL, *pt = NULL, *p, *l;
2110         uc_value_t *subject = uc_fn_arg(0);
2111         uc_value_t *pattern = uc_fn_arg(1);
2112         uc_value_t *replace = uc_fn_arg(2);
2113         uc_value_t *limitval = uc_fn_arg(3);
2114         bool sb_freeable, pt_freeable;
2115         regmatch_t *pmatch = NULL;
2116         size_t pl, nmatch, limit;
2117         uc_regexp_t *re = NULL;
2118         uc_stringbuf_t *resbuf;
2119         int eflags = 0, res;
2120 
2121         if (!pattern || !subject || !replace)
2122                 return NULL;
2123 
2124         nmatch = 1;
2125 
2126         if (ucv_type(pattern) == UC_REGEXP) {
2127                 re = (uc_regexp_t *)pattern;
2128                 nmatch += re->regexp.re_nsub;
2129         }
2130 
2131         pmatch = calloc(nmatch, sizeof(regmatch_t));
2132 
2133         if (!pmatch)
2134                 return NULL;
2135 
2136         sb = uc_cast_string(vm, &subject, &sb_freeable);
2137         resbuf = ucv_stringbuf_new();
2138         limit = limitval ? ucv_uint64_get(limitval) : SIZE_MAX;
2139 
2140         if (re) {
2141                 p = sb;
2142 
2143                 while (limit > 0) {
2144                         res = regexec(&re->regexp, p, nmatch, pmatch, eflags);
2145 
2146                         if (res == REG_NOMATCH)
2147                                 break;
2148 
2149                         ucv_stringbuf_addstr(resbuf, p, pmatch[0].rm_so);
2150 
2151                         if (ucv_is_callable(replace))
2152                                 uc_replace_cb(vm, replace, p, pmatch, nmatch, resbuf);
2153                         else
2154                                 uc_replace_str(vm, replace, p, pmatch, nmatch, resbuf);
2155 
2156                         if (pmatch[0].rm_so != pmatch[0].rm_eo)
2157                                 p += pmatch[0].rm_eo;
2158                         else if (*p)
2159                                 ucv_stringbuf_addstr(resbuf, p++, 1);
2160                         else
2161                                 break;
2162 
2163                         if (re->global)
2164                                 eflags |= REG_NOTBOL;
2165                         else
2166                                 break;
2167 
2168                         limit--;
2169                 }
2170 
2171                 ucv_stringbuf_addstr(resbuf, p, strlen(p));
2172         }
2173         else {
2174                 pt = uc_cast_string(vm, &pattern, &pt_freeable);
2175                 pl = strlen(pt);
2176 
2177                 l = p = sb;
2178 
2179                 while (limit > 0) {
2180                         if (pl == 0 || !strncmp(p, pt, pl)) {
2181                                 ucv_stringbuf_addstr(resbuf, l, p - l);
2182 
2183                                 pmatch[0].rm_so = p - l;
2184                                 pmatch[0].rm_eo = pmatch[0].rm_so + pl;
2185 
2186                                 if (ucv_is_callable(replace))
2187                                         uc_replace_cb(vm, replace, l, pmatch, 1, resbuf);
2188                                 else
2189                                         uc_replace_str(vm, replace, l, pmatch, 1, resbuf);
2190 
2191                                 if (pl) {
2192                                         l = p + pl;
2193                                         p += pl - 1;
2194                                 }
2195                                 else {
2196                                         l = p;
2197                                 }
2198 
2199                                 limit--;
2200                         }
2201 
2202                         if (!*p++)
2203                                 break;
2204                 }
2205 
2206                 ucv_stringbuf_addstr(resbuf, l, strlen(l));
2207 
2208                 if (pt_freeable)
2209                         free(pt);
2210         }
2211 
2212         free(pmatch);
2213 
2214         if (sb_freeable)
2215                 free(sb);
2216 
2217         return ucv_stringbuf_finish(resbuf);
2218 }
2219 
2220 static struct json_tokener *
2221 uc_json_from_object(uc_vm_t *vm, uc_value_t *obj, json_object **jso)
2222 {
2223         bool trail = false, eof = false;
2224         enum json_tokener_error err;
2225         struct json_tokener *tok;
2226         uc_value_t *rfn, *rbuf;
2227         uc_stringbuf_t *buf;
2228 
2229         rfn = ucv_property_get(obj, "read");
2230 
2231         if (!ucv_is_callable(rfn)) {
2232                 uc_vm_raise_exception(vm, EXCEPTION_TYPE,
2233                                       "Input object does not implement read() method");
2234 
2235                 return NULL;
2236         }
2237 
2238         tok = xjs_new_tokener();
2239 
2240         while (true) {
2241                 uc_vm_stack_push(vm, ucv_get(obj));
2242                 uc_vm_stack_push(vm, ucv_get(rfn));
2243                 uc_vm_stack_push(vm, ucv_int64_new(1024));
2244 
2245                 if (uc_vm_call(vm, true, 1) != EXCEPTION_NONE) {
2246                         json_tokener_free(tok);
2247 
2248                         return NULL;
2249                 }
2250 
2251                 rbuf = uc_vm_stack_pop(vm);
2252 
2253                 /* check EOF */
2254                 eof = (rbuf == NULL || (ucv_type(rbuf) == UC_STRING && ucv_string_length(rbuf) == 0));
2255 
2256                 /* on EOF, stop parsing unless trailing garbage was detected which handled below */
2257                 if (eof && !trail) {
2258                         ucv_put(rbuf);
2259 
2260                         /* Didn't parse a complete object yet, possibly a non-delimitted atomic value
2261                            such as `null`, `true` etc. - nudge parser by sending final zero byte.
2262                            See json-c issue #681 <https://github.com/json-c/json-c/issues/681> */
2263                         if (json_tokener_get_error(tok) == json_tokener_continue)
2264                                 *jso = json_tokener_parse_ex(tok, "\0", 1);
2265 
2266                         break;
2267                 }
2268 
2269                 if (trail || *jso) {
2270                         uc_vm_raise_exception(vm, EXCEPTION_SYNTAX,
2271                                               "Trailing garbage after JSON data");
2272 
2273                         json_tokener_free(tok);
2274                         ucv_put(rbuf);
2275 
2276                         return NULL;
2277                 }
2278 
2279                 if (ucv_type(rbuf) != UC_STRING) {
2280                         buf = xprintbuf_new();
2281                         ucv_to_stringbuf_formatted(vm, buf, rbuf, 0, '\0', 0);
2282 
2283                         *jso = json_tokener_parse_ex(tok, buf->buf, printbuf_length(buf));
2284 
2285                         trail = (json_tokener_get_error(tok) == json_tokener_success &&
2286                                  json_tokener_get_parse_end(tok) < (size_t)printbuf_length(buf));
2287 
2288                         printbuf_free(buf);
2289                 }
2290                 else {
2291                         *jso = json_tokener_parse_ex(tok, ucv_string_get(rbuf), ucv_string_length(rbuf));
2292 
2293                         trail = (json_tokener_get_error(tok) == json_tokener_success &&
2294                                  json_tokener_get_parse_end(tok) < ucv_string_length(rbuf));
2295                 }
2296 
2297                 ucv_put(rbuf);
2298 
2299                 err = json_tokener_get_error(tok);
2300 
2301                 if (err != json_tokener_success && err != json_tokener_continue)
2302                         break;
2303         }
2304 
2305         return tok;
2306 }
2307 
2308 static struct json_tokener *
2309 uc_json_from_string(uc_vm_t *vm, uc_value_t *str, json_object **jso)
2310 {
2311         struct json_tokener *tok = xjs_new_tokener();
2312 
2313         /* NB: the len + 1 here is intentional to pass the terminating \0 byte
2314          * to the json-c parser. This is required to work-around upstream
2315          * issue #681 <https://github.com/json-c/json-c/issues/681> */
2316         *jso = json_tokener_parse_ex(tok, ucv_string_get(str), ucv_string_length(str) + 1);
2317 
2318         if (json_tokener_get_error(tok) == json_tokener_success &&
2319             json_tokener_get_parse_end(tok) < ucv_string_length(str)) {
2320                 uc_vm_raise_exception(vm, EXCEPTION_SYNTAX,
2321                                       "Trailing garbage after JSON data");
2322 
2323                 json_tokener_free(tok);
2324 
2325                 return NULL;
2326         }
2327 
2328         return tok;
2329 }
2330 
2331 static uc_value_t *
2332 uc_json(uc_vm_t *vm, size_t nargs)
2333 {
2334         uc_value_t *rv = NULL, *src = uc_fn_arg(0);
2335         struct json_tokener *tok = NULL;
2336         enum json_tokener_error err;
2337         json_object *jso = NULL;
2338 
2339         switch (ucv_type(src)) {
2340         case UC_STRING:
2341                 tok = uc_json_from_string(vm, src, &jso);
2342                 break;
2343 
2344         case UC_RESOURCE:
2345         case UC_OBJECT:
2346         case UC_ARRAY:
2347                 tok = uc_json_from_object(vm, src, &jso);
2348                 break;
2349 
2350         default:
2351                 uc_vm_raise_exception(vm, EXCEPTION_TYPE,
2352                                       "Passed value is neither a string nor an object");
2353         }
2354 
2355         if (!tok)
2356                 goto out;
2357 
2358         err = json_tokener_get_error(tok);
2359 
2360         if (err == json_tokener_continue) {
2361                 uc_vm_raise_exception(vm, EXCEPTION_SYNTAX,
2362                                       "Unexpected end of string in JSON data");
2363 
2364                 goto out;
2365         }
2366         else if (err != json_tokener_success) {
2367                 uc_vm_raise_exception(vm, EXCEPTION_SYNTAX,
2368                                       "Failed to parse JSON string: %s",
2369                                       json_tokener_error_desc(err));
2370 
2371                 goto out;
2372         }
2373 
2374         rv = ucv_from_json(vm, jso);
2375 
2376 out:
2377         if (tok)
2378                 json_tokener_free(tok);
2379 
2380         json_object_put(jso);
2381 
2382         return rv;
2383 }
2384 
2385 static char *
2386 include_path(const char *curpath, const char *incpath)
2387 {
2388         char *dup, *res;
2389         int len;
2390 
2391         if (*incpath == '/')
2392                 return realpath(incpath, NULL);
2393 
2394         dup = curpath ? strrchr(curpath, '/') : NULL;
2395 
2396         if (dup)
2397                 len = asprintf(&res, "%.*s/%s", (int)(dup - curpath), curpath, incpath);
2398         else
2399                 len = asprintf(&res, "./%s", incpath);
2400 
2401         if (len == -1)
2402                 return NULL;
2403 
2404         dup = realpath(res, NULL);
2405 
2406         free(res);
2407 
2408         return dup;
2409 }
2410 
2411 static uc_value_t *
2412 uc_include_common(uc_vm_t *vm, size_t nargs, bool raw_mode)
2413 {
2414         uc_value_t *path = uc_fn_arg(0);
2415         uc_value_t *scope = uc_fn_arg(1);
2416         uc_value_t *rv = NULL, *sc = NULL;
2417         uc_closure_t *closure = NULL;
2418         size_t i;
2419         char *p;
2420 
2421         if (ucv_type(path) != UC_STRING) {
2422                 uc_vm_raise_exception(vm, EXCEPTION_TYPE,
2423                                       "Passed filename is not a string");
2424 
2425                 return NULL;
2426         }
2427 
2428         if (scope && ucv_type(scope) != UC_OBJECT) {
2429                 uc_vm_raise_exception(vm, EXCEPTION_TYPE,
2430                                       "Passed scope value is not an object");
2431 
2432                 return NULL;
2433         }
2434 
2435         /* find calling closure */
2436         for (i = vm->callframes.count; i > 0; i--) {
2437                 closure = vm->callframes.entries[i - 1].closure;
2438 
2439                 if (closure)
2440                         break;
2441         }
2442 
2443         if (!closure)
2444                 return NULL;
2445 
2446         p = include_path(uc_program_function_source(closure->function)->runpath, ucv_string_get(path));
2447 
2448         if (!p) {
2449                 uc_vm_raise_exception(vm, EXCEPTION_RUNTIME,
2450                                       "Include file not found");
2451 
2452                 return NULL;
2453         }
2454 
2455         if (ucv_prototype_get(scope)) {
2456                 sc = ucv_get(scope);
2457         }
2458         else if (scope) {
2459                 sc = ucv_object_new(vm);
2460 
2461                 ucv_object_foreach(scope, key, val)
2462                         ucv_object_add(sc, key, ucv_get(val));
2463 
2464                 ucv_prototype_set(sc, ucv_get(uc_vm_scope_get(vm)));
2465         }
2466         else {
2467                 sc = ucv_get(uc_vm_scope_get(vm));
2468         }
2469 
2470         if (uc_require_ucode(vm, p, sc, &rv, raw_mode))
2471                 ucv_put(rv);
2472 
2473         ucv_put(sc);
2474         free(p);
2475 
2476         return NULL;
2477 }
2478 
2479 static uc_value_t *
2480 uc_include(uc_vm_t *vm, size_t nargs)
2481 {
2482         return uc_include_common(vm, nargs, vm->config && vm->config->raw_mode);
2483 }
2484 
2485 static uc_value_t *
2486 uc_render(uc_vm_t *vm, size_t nargs)
2487 {
2488         uc_string_t hdr = { .header = { .type = UC_STRING, .refcount = 1 } };
2489         uc_string_t *ustr = NULL;
2490         FILE *mem, *prev;
2491         size_t len = 0;
2492 
2493         mem = open_memstream((char **)&ustr, &len);
2494 
2495         if (!mem)
2496                 goto out;
2497 
2498         /* reserve space for uc_string_t header... */
2499         if (fwrite(&hdr, 1, sizeof(hdr), mem) != sizeof(hdr))
2500                 goto out;
2501 
2502         /* divert VM output to memory fd */
2503         prev = vm->output;
2504         vm->output = mem;
2505 
2506         /* execute function */
2507         if (ucv_is_callable(uc_fn_arg(0)))
2508                 (void) uc_vm_call(vm, false, nargs - 1);
2509 
2510         /* execute include */
2511         else
2512                 (void) uc_include_common(vm, nargs, false);
2513 
2514         /* restore previous VM output */
2515         vm->output = prev;
2516         fclose(mem);
2517 
2518         /* update uc_string_t length */
2519         ustr->length = len - sizeof(*ustr);
2520 
2521         return &ustr->header;
2522 
2523 out:
2524         uc_vm_raise_exception(vm, EXCEPTION_RUNTIME,
2525                               "Unable to initialize output memory: %s",
2526                               strerror(errno));
2527 
2528         if (mem)
2529                 fclose(mem);
2530 
2531         free(ustr);
2532 
2533         return NULL;
2534 }
2535 
2536 static uc_value_t *
2537 uc_warn(uc_vm_t *vm, size_t nargs)
2538 {
2539         return uc_print_common(vm, nargs, stderr);
2540 }
2541 
2542 #ifdef __APPLE__
2543 /*
2544  * sigtimedwait() implementation based on
2545  * https://comp.unix.programmer.narkive.com/rEDH0sPT/sigtimedwait-implementation
2546  * and
2547  * https://github.com/wahern/lunix/blob/master/src/unix.c
2548  */
2549 static void
2550 sigtimedwait_consume_signal(int signo)
2551 {
2552 }
2553 
2554 static int
2555 sigtimedwait(const sigset_t *set, siginfo_t *info, const struct timespec *timeout)
2556 {
2557         struct timespec elapsed = { 0, 0 }, sleep, rem;
2558         sigset_t pending, unblock, omask;
2559         struct sigaction sa, osa;
2560         int signo;
2561         bool lt;
2562 
2563         while (true) {
2564                 sigemptyset(&pending);
2565                 sigpending(&pending);
2566 
2567                 for (signo = 1; signo < NSIG; signo++) {
2568                         if (!sigismember(set, signo) || !sigismember(&pending, signo))
2569                                 continue;
2570 
2571                         sa.sa_handler = sigtimedwait_consume_signal;
2572                         sa.sa_flags = 0;
2573                         sigfillset(&sa.sa_mask);
2574 
2575                         sigaction(signo, &sa, &osa);
2576 
2577                         sigemptyset(&unblock);
2578                         sigaddset(&unblock, signo);
2579                         sigprocmask(SIG_UNBLOCK, &unblock, &omask);
2580                         sigprocmask(SIG_SETMASK, &omask, NULL);
2581 
2582                         sigaction(signo, &osa, NULL);
2583 
2584                         if (info) {
2585                                 memset(info, 0, sizeof(*info));
2586                                 info->si_signo = signo;
2587                         }
2588 
2589                         return signo;
2590                 }
2591 
2592                 sleep.tv_sec = 0;
2593                 sleep.tv_nsec = 200000000L; /* 2/10th second */
2594                 rem = sleep;
2595 
2596                 if (nanosleep(&sleep, &rem) == 0) {
2597                         elapsed.tv_sec += sleep.tv_sec;
2598                         elapsed.tv_nsec += sleep.tv_nsec;
2599 
2600                         if (elapsed.tv_nsec > 1000000000) {
2601                                 elapsed.tv_sec++;
2602                                 elapsed.tv_nsec -= 1000000000;
2603                         }
2604                 }
2605                 else if (errno == EINTR) {
2606                         sleep.tv_sec -= rem.tv_sec;
2607                         sleep.tv_nsec -= rem.tv_nsec;
2608 
2609                         if (sleep.tv_nsec < 0) {
2610                                 sleep.tv_sec--;
2611                                 sleep.tv_nsec += 1000000000;
2612                         }
2613 
2614                         elapsed.tv_sec += sleep.tv_sec;
2615                         elapsed.tv_nsec += sleep.tv_nsec;
2616 
2617                         if (elapsed.tv_nsec > 1000000000) {
2618                                 elapsed.tv_sec++;
2619                                 elapsed.tv_nsec -= 1000000000;
2620                         }
2621                 }
2622                 else {
2623                         return errno;
2624                 }
2625 
2626                 lt = timeout
2627                         ? ((elapsed.tv_sec == timeout->tv_sec)
2628                                 ? (elapsed.tv_nsec < timeout->tv_nsec)
2629                                 : (elapsed.tv_sec < timeout->tv_sec))
2630                         : true;
2631 
2632                 if (!lt)
2633                         break;
2634         }
2635 
2636         errno = EAGAIN;
2637 
2638         return -1;
2639 }
2640 
2641 #endif
2642 
2643 static uc_value_t *
2644 uc_system(uc_vm_t *vm, size_t nargs)
2645 {
2646         uc_value_t *cmdline = uc_fn_arg(0);
2647         uc_value_t *timeout = uc_fn_arg(1);
2648         const char **arglist, *fn;
2649         sigset_t sigmask, sigomask;
2650         struct timespec ts;
2651         size_t i, len;
2652         int64_t tms;
2653         pid_t cld;
2654         int rc;
2655 
2656         if (timeout && (ucv_type(timeout) != UC_INTEGER || ucv_int64_get(timeout) < 0)) {
2657                 uc_vm_raise_exception(vm, EXCEPTION_TYPE,
2658                                       "Invalid timeout specified");
2659 
2660                 return NULL;
2661         }
2662 
2663         switch (ucv_type(cmdline)) {
2664         case UC_STRING:
2665                 arglist = xalloc(sizeof(*arglist) * 4);
2666                 arglist[0] = xstrdup("/bin/sh");
2667                 arglist[1] = xstrdup("-c");
2668                 arglist[2] = ucv_to_string(vm, cmdline);
2669                 arglist[3] = NULL;
2670                 break;
2671 
2672         case UC_ARRAY:
2673                 len = ucv_array_length(cmdline);
2674 
2675                 if (len == 0) {
2676                         uc_vm_raise_exception(vm, EXCEPTION_TYPE,
2677                                               "Passed command array is empty");
2678 
2679                         return NULL;
2680                 }
2681 
2682                 arglist = xalloc(sizeof(*arglist) * (len + 1));
2683 
2684                 for (i = 0; i < len; i++)
2685                         arglist[i] = ucv_to_string(vm, ucv_array_get(cmdline, i));
2686 
2687                 arglist[i] = NULL;
2688 
2689                 break;
2690 
2691         default:
2692                 uc_vm_raise_exception(vm, EXCEPTION_TYPE,
2693                                       "Passed command is neither string nor array");
2694 
2695                 return NULL;
2696         }
2697 
2698         tms = timeout ? ucv_int64_get(timeout) : 0;
2699 
2700         if (tms > 0) {
2701                 sigemptyset(&sigmask);
2702                 sigaddset(&sigmask, SIGCHLD);
2703 
2704                 if (sigprocmask(SIG_BLOCK, &sigmask, &sigomask) < 0) {
2705                         fn = "sigprocmask";
2706                         goto fail;
2707                 }
2708         }
2709 
2710         cld = fork();
2711 
2712         switch (cld) {
2713         case -1:
2714                 fn = "fork";
2715                 goto fail;
2716 
2717         case 0:
2718                 execvp(arglist[0], (char * const *)arglist);
2719                 exit(-1);
2720 
2721                 break;
2722 
2723         default:
2724                 if (tms > 0) {
2725                         ts.tv_sec = tms / 1000;
2726                         ts.tv_nsec = (tms % 1000) * 1000000;
2727 
2728                         while (1) {
2729                                 if (sigtimedwait(&sigmask, NULL, &ts) < 0) {
2730                                         if (errno == EINTR)
2731                                                 continue;
2732 
2733                                         if (errno != EAGAIN) {
2734                                                 fn = "sigtimedwait";
2735                                                 goto fail;
2736                                         }
2737 
2738                                         kill(cld, SIGKILL);
2739                                 }
2740 
2741                                 break;
2742                         }
2743                 }
2744 
2745                 while (waitpid(cld, &rc, 0) < 0) {
2746                         if (errno == EINTR)
2747                                 continue;
2748 
2749                         fn = "waitpid";
2750                         goto fail;
2751                 }
2752 
2753                 if (tms > 0)
2754                         sigprocmask(SIG_SETMASK, &sigomask, NULL);
2755 
2756                 for (i = 0; arglist[i]; i++)
2757                         free((char *)arglist[i]);
2758 
2759                 free(arglist);
2760 
2761                 if (WIFEXITED(rc))
2762                         return ucv_int64_new(WEXITSTATUS(rc));
2763                 else if (WIFSIGNALED(rc))
2764                         return ucv_int64_new(-WTERMSIG(rc));
2765                 else if (WIFSTOPPED(rc))
2766                         return ucv_int64_new(-WSTOPSIG(rc));
2767 
2768                 return NULL;
2769         }
2770 
2771 fail:
2772         if (tms > 0)
2773                 sigprocmask(SIG_SETMASK, &sigomask, NULL);
2774 
2775         for (i = 0; arglist[i]; i++)
2776                 free((char *)arglist[i]);
2777 
2778         free(arglist);
2779 
2780         uc_vm_raise_exception(vm, EXCEPTION_RUNTIME,
2781                               "%s(): %s", fn, strerror(errno));
2782 
2783         return NULL;
2784 }
2785 
2786 static uc_value_t *
2787 uc_trace(uc_vm_t *vm, size_t nargs)
2788 {
2789         uc_value_t *level = uc_fn_arg(0);
2790         uint8_t prev_level;
2791 
2792         if (ucv_type(level) != UC_INTEGER) {
2793                 uc_vm_raise_exception(vm, EXCEPTION_TYPE, "Invalid level specified");
2794 
2795                 return NULL;
2796         }
2797 
2798         prev_level = vm->trace;
2799         vm->trace = ucv_int64_get(level);
2800 
2801         return ucv_int64_new(prev_level);
2802 }
2803 
2804 static uc_value_t *
2805 uc_proto(uc_vm_t *vm, size_t nargs)
2806 {
2807         uc_value_t *val = uc_fn_arg(0);
2808         uc_value_t *proto = NULL;
2809 
2810         if (nargs < 2)
2811                 return ucv_get(ucv_prototype_get(val));
2812 
2813         proto = uc_fn_arg(1);
2814 
2815         if (!ucv_prototype_set(val, proto))
2816                 uc_vm_raise_exception(vm, EXCEPTION_TYPE, "Passed value is neither a prototype, resource or object");
2817 
2818         ucv_get(proto);
2819 
2820         return ucv_get(val);
2821 }
2822 
2823 static uc_value_t *
2824 uc_sleep(uc_vm_t *vm, size_t nargs)
2825 {
2826         uc_value_t *duration = uc_fn_arg(0);
2827         struct timeval tv;
2828         int64_t ms;
2829 
2830         ms = ucv_to_integer(duration);
2831 
2832         if (errno != 0 || ms <= 0)
2833                 return ucv_boolean_new(false);
2834 
2835         tv.tv_sec = ms / 1000;
2836         tv.tv_usec = (ms % 1000) * 1000;
2837 
2838         select(0, NULL, NULL, NULL, &tv);
2839 
2840         return ucv_boolean_new(true);
2841 }
2842 
2843 static uc_value_t *
2844 uc_assert(uc_vm_t *vm, size_t nargs)
2845 {
2846         uc_value_t *cond = uc_fn_arg(0);
2847         uc_value_t *msg = uc_fn_arg(1);
2848         bool freeable = false;
2849         char *s;
2850 
2851         if (!ucv_is_truish(cond)) {
2852                 s = msg ? uc_cast_string(vm, &msg, &freeable) : "Assertion failed";
2853 
2854                 uc_vm_raise_exception(vm, EXCEPTION_USER, "%s", s);
2855 
2856                 if (freeable)
2857                         free(s);
2858 
2859                 return NULL;
2860         }
2861 
2862         return ucv_get(cond);
2863 }
2864 
2865 static uc_value_t *
2866 uc_regexp(uc_vm_t *vm, size_t nargs)
2867 {
2868         bool icase = false, newline = false, global = false, freeable;
2869         uc_value_t *source = uc_fn_arg(0);
2870         uc_value_t *flags = uc_fn_arg(1);
2871         uc_value_t *regex = NULL;
2872         char *p, *err = NULL;
2873 
2874         if (flags) {
2875                 if (ucv_type(flags) != UC_STRING) {
2876                         uc_vm_raise_exception(vm, EXCEPTION_TYPE, "Given flags argument is not a string");
2877 
2878                         return NULL;
2879                 }
2880 
2881                 for (p = ucv_string_get(flags); *p; p++) {
2882                         switch (*p) {
2883                         case 'i':
2884                                 icase = true;
2885                                 break;
2886 
2887                         case 's':
2888                                 newline = true;
2889                                 break;
2890 
2891                         case 'g':
2892                                 global = true;
2893                                 break;
2894 
2895                         default:
2896                                 uc_vm_raise_exception(vm, EXCEPTION_TYPE, "Unrecognized flag character '%c'", *p);
2897 
2898                                 return NULL;
2899                         }
2900                 }
2901         }
2902 
2903         p = uc_cast_string(vm, &source, &freeable);
2904         regex = ucv_regexp_new(p, icase, newline, global, &err);
2905 
2906         if (freeable)
2907                 free(p);
2908 
2909         if (err) {
2910                 uc_vm_raise_exception(vm, EXCEPTION_SYNTAX, "%s", err);
2911                 ucv_put(regex);
2912                 free(err);
2913 
2914                 return NULL;
2915         }
2916 
2917         return regex;
2918 }
2919 
2920 static uc_value_t *
2921 uc_wildcard(uc_vm_t *vm, size_t nargs)
2922 {
2923         uc_value_t *subject = uc_fn_arg(0);
2924         uc_value_t *pattern = uc_fn_arg(1);
2925         uc_value_t *icase = uc_fn_arg(2);
2926         int flags = 0, rv;
2927         bool freeable;
2928         char *s;
2929 
2930         if (!subject || ucv_type(pattern) != UC_STRING)
2931                 return NULL;
2932 
2933         if (ucv_is_truish(icase))
2934                 flags |= FNM_CASEFOLD;
2935 
2936         s = uc_cast_string(vm, &subject, &freeable);
2937         rv = fnmatch(ucv_string_get(pattern), s, flags);
2938 
2939         if (freeable)
2940                 free(s);
2941 
2942         return ucv_boolean_new(rv == 0);
2943 }
2944 
2945 static uc_value_t *
2946 uc_sourcepath(uc_vm_t *vm, size_t nargs)
2947 {
2948         uc_value_t *calldepth = uc_fn_arg(0);
2949         uc_value_t *dironly = uc_fn_arg(1);
2950         uc_value_t *rv = NULL;
2951         uc_callframe_t *frame;
2952         char *path = NULL;
2953         int64_t depth;
2954         size_t i;
2955 
2956         depth = ucv_to_integer(calldepth);
2957 
2958         if (errno)
2959                 depth = 0;
2960 
2961         for (i = vm->callframes.count; i > 0; i--) {
2962                 frame = &vm->callframes.entries[i - 1];
2963 
2964                 if (!frame->closure)
2965                         continue;
2966 
2967                 if (depth > 0) {
2968                         depth--;
2969                         continue;
2970                 }
2971 
2972                 path = realpath(uc_program_function_source(frame->closure->function)->runpath, NULL);
2973                 break;
2974         }
2975 
2976         if (path) {
2977                 if (ucv_is_truish(dironly))
2978                         rv = ucv_string_new(dirname(path));
2979                 else
2980                         rv = ucv_string_new(path);
2981 
2982                 free(path);
2983         }
2984 
2985         return rv;
2986 }
2987 
2988 static uc_value_t *
2989 uc_min_max(uc_vm_t *vm, size_t nargs, int cmp)
2990 {
2991         uc_value_t *rv = NULL, *val;
2992         bool set = false;
2993         size_t i;
2994 
2995         for (i = 0; i < nargs; i++) {
2996                 val = uc_fn_arg(i);
2997 
2998                 if (!set || ucv_compare(cmp, val, rv, NULL)) {
2999                         set = true;
3000                         rv = val;
3001                 }
3002         }
3003 
3004         return ucv_get(rv);
3005 }
3006 
3007 static uc_value_t *
3008 uc_min(uc_vm_t *vm, size_t nargs)
3009 {
3010         return uc_min_max(vm, nargs, I_LT);
3011 }
3012 
3013 static uc_value_t *
3014 uc_max(uc_vm_t *vm, size_t nargs)
3015 {
3016         return uc_min_max(vm, nargs, I_GT);
3017 }
3018 
3019 
3020 /* -------------------------------------------------------------------------
3021  * The following base64 encoding and decoding routines are taken from
3022  * https://git.openwrt.org/?p=project/libubox.git;a=blob;f=base64.c
3023  * and modified for use in ucode.
3024  *
3025  * Original copyright and license statements below.
3026  */
3027 
3028 /*
3029  * base64 - libubox base64 functions
3030  *
3031  * Copyright (C) 2015 Felix Fietkau <nbd@openwrt.org>
3032  *
3033  * Permission to use, copy, modify, and/or distribute this software for any
3034  * purpose with or without fee is hereby granted, provided that the above
3035  * copyright notice and this permission notice appear in all copies.
3036  *
3037  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
3038  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
3039  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
3040  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
3041  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
3042  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
3043  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
3044  */
3045 
3046 /*      $OpenBSD: base64.c,v 1.7 2013/12/31 02:32:56 tedu Exp $ */
3047 
3048 /*
3049  * Copyright (c) 1996 by Internet Software Consortium.
3050  *
3051  * Permission to use, copy, modify, and distribute this software for any
3052  * purpose with or without fee is hereby granted, provided that the above
3053  * copyright notice and this permission notice appear in all copies.
3054  *
3055  * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
3056  * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
3057  * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
3058  * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
3059  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
3060  * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
3061  * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
3062  * SOFTWARE.
3063  */
3064 
3065 /*
3066  * Portions Copyright (c) 1995 by International Business Machines, Inc.
3067  *
3068  * International Business Machines, Inc. (hereinafter called IBM) grants
3069  * permission under its copyrights to use, copy, modify, and distribute this
3070  * Software with or without fee, provided that the above copyright notice and
3071  * all paragraphs of this notice appear in all copies, and that the name of IBM
3072  * not be used in connection with the marketing of any product incorporating
3073  * the Software or modifications thereof, without specific, written prior
3074  * permission.
3075  *
3076  * To the extent it has a right to do so, IBM grants an immunity from suit
3077  * under its patents, if any, for the use, sale or manufacture of products to
3078  * the extent that such products are used for performing Domain Name System
3079  * dynamic updates in TCP/IP networks by means of the Software.  No immunity is
3080  * granted for any product per se or for any other function of any product.
3081  *
3082  * THE SOFTWARE IS PROVIDED "AS IS", AND IBM DISCLAIMS ALL WARRANTIES,
3083  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
3084  * PARTICULAR PURPOSE.  IN NO EVENT SHALL IBM BE LIABLE FOR ANY SPECIAL,
3085  * DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER ARISING
3086  * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE, EVEN
3087  * IF IBM IS APPRISED OF THE POSSIBILITY OF SUCH DAMAGES.
3088  */
3089 
3090 /* skips all whitespace anywhere.
3091    converts characters, four at a time, starting at (or after)
3092    src from base - 64 numbers into three 8 bit bytes in the target area.
3093    it returns the number of data bytes stored at the target, or -1 on error.
3094  */
3095 
3096 static uc_value_t *
3097 uc_b64dec(uc_vm_t *vm, size_t nargs)
3098 {
3099         enum { BYTE1, BYTE2, BYTE3, BYTE4 } state;
3100         uc_value_t *str = uc_fn_arg(0);
3101         uc_stringbuf_t *buf;
3102         const char *src;
3103         unsigned int ch;
3104         uint8_t val;
3105         size_t off;
3106 
3107         if (ucv_type(str) != UC_STRING)
3108                 return NULL;
3109 
3110         buf = ucv_stringbuf_new();
3111         src = ucv_string_get(str);
3112         off = printbuf_length(buf);
3113 
3114         state = BYTE1;
3115 
3116         /* memset the last expected output char to pre-grow the output buffer */
3117         printbuf_memset(buf, off + (ucv_string_length(str) / 4) * 3, 0, 1);
3118 
3119         while ((ch = (unsigned char)*src++) != '\0') {
3120                 if (isspace(ch))        /* Skip whitespace anywhere. */
3121                         continue;
3122 
3123                 if (ch == '=')
3124                         break;
3125 
3126                 if (ch >= 'A' && ch <= 'Z')
3127                         val = ch - 'A';
3128                 else if (ch >= 'a' && ch <= 'z')
3129                         val = ch - 'a' + 26;
3130                 else if (ch >= '' && ch <= '9')
3131                         val = ch - '' + 52;
3132                 else if (ch == '+')
3133                         val = 62;
3134                 else if (ch == '/')
3135                         val = 63;
3136                 else
3137                         goto err;
3138 
3139                 switch (state) {
3140                 case BYTE1:
3141                         buf->buf[off] = val << 2;
3142                         state = BYTE2;
3143                         break;
3144 
3145                 case BYTE2:
3146                         buf->buf[off++] |= val >> 4;
3147                         buf->buf[off] = (val & 0x0f) << 4;
3148                         state = BYTE3;
3149                         break;
3150 
3151                 case BYTE3:
3152                         buf->buf[off++] |= val >> 2;
3153                         buf->buf[off] = (val & 0x03) << 6;
3154                         state = BYTE4;
3155                         break;
3156 
3157                 case BYTE4:
3158                         buf->buf[off++] |= val;
3159                         state = BYTE1;
3160                         break;
3161                 }
3162         }
3163 
3164         /*
3165          * We are done decoding Base-64 chars.  Let's see if we ended
3166          * on a byte boundary, and/or with erroneous trailing characters.
3167          */
3168 
3169         if (ch == '=') {                        /* We got a pad char. */
3170                 ch = (unsigned char)*src++;     /* Skip it, get next. */
3171                 switch (state) {
3172                 case BYTE1:             /* Invalid = in first position */
3173                 case BYTE2:             /* Invalid = in second position */
3174                         goto err;
3175 
3176                 case BYTE3:             /* Valid, means one byte of info */
3177                         /* Skip any number of spaces. */
3178                         for (; ch != '\0'; ch = (unsigned char)*src++)
3179                                 if (!isspace(ch))
3180                                         break;
3181                         /* Make sure there is another trailing = sign. */
3182                         if (ch != '=')
3183                                 goto err;
3184                         ch = (unsigned char)*src++;             /* Skip the = */
3185                         /* Fall through to "single trailing =" case. */
3186                         /* FALLTHROUGH */
3187 
3188                 case BYTE4:             /* Valid, means two bytes of info */
3189                         /*
3190                          * We know this char is an =.  Is there anything but
3191                          * whitespace after it?
3192                          */
3193                         for (; ch != '\0'; ch = (unsigned char)*src++)
3194                                 if (!isspace(ch))
3195                                         goto err;
3196 
3197                         /*
3198                          * Now make sure for cases BYTE3 and BYTE4 that the "extra"
3199                          * bits that slopped past the last full byte were
3200                          * zeros.  If we don't check them, they become a
3201                          * subliminal channel.
3202                          */
3203                         if (buf->buf[off] != 0)
3204                                 goto err;
3205                 }
3206         } else {
3207                 /*
3208                  * We ended by seeing the end of the string.  Make sure we
3209                  * have no partial bytes lying around.
3210                  */
3211                 if (state != BYTE1)
3212                         goto err;
3213         }
3214 
3215         /* Truncate buffer length to actual output length */
3216         buf->bpos = off;
3217 
3218         return ucv_stringbuf_finish(buf);
3219 
3220 err:
3221         printbuf_free(buf);
3222 
3223         return NULL;
3224 }
3225 
3226 static const char Base64[] =
3227         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
3228 
3229 static uc_value_t *
3230 uc_b64enc(uc_vm_t *vm, size_t nargs)
3231 {
3232         uc_value_t *str = uc_fn_arg(0);
3233         unsigned char input[3] = {0};
3234         uc_stringbuf_t *buf;
3235         const char *src;
3236         char output[4];
3237         size_t len, i;
3238 
3239         if (ucv_type(str) != UC_STRING)
3240                 return NULL;
3241 
3242         buf = ucv_stringbuf_new();
3243         src = ucv_string_get(str);
3244         len = ucv_string_length(str);
3245 
3246         while (2 < len) {
3247                 input[0] = (unsigned char)*src++;
3248                 input[1] = (unsigned char)*src++;
3249                 input[2] = (unsigned char)*src++;
3250                 len -= 3;
3251 
3252                 output[0] = Base64[input[0] >> 2];
3253                 output[1] = Base64[((input[0] & 0x03) << 4) + (input[1] >> 4)];
3254                 output[2] = Base64[((input[1] & 0x0f) << 2) + (input[2] >> 6)];
3255                 output[3] = Base64[input[2] & 0x3f];
3256 
3257                 ucv_stringbuf_addstr(buf, output, sizeof(output));
3258         }
3259 
3260         /* Now we worry about padding. */
3261         if (0 != len) {
3262                 /* Get what's left. */
3263                 input[0] = input[1] = input[2] = '\0';
3264                 for (i = 0; i < len; i++)
3265                         input[i] = *src++;
3266 
3267                 output[0] = Base64[input[0] >> 2];
3268                 output[1] = Base64[((input[0] & 0x03) << 4) + (input[1] >> 4)];
3269                 output[2] = (len == 1) ? '=' : Base64[((input[1] & 0x0f) << 2) + (input[2] >> 6)];
3270                 output[3] = '=';
3271 
3272                 ucv_stringbuf_addstr(buf, output, sizeof(output));
3273         }
3274 
3275         return ucv_stringbuf_finish(buf);
3276 }
3277 
3278 /* End of base64 code.
3279  * -------------------------------------------------------------------------
3280  */
3281 
3282 static unsigned long
3283 uc_uniq_ucv_hash(const void *k)
3284 {
3285         union { double d; int64_t i; uint64_t u; } conv;
3286         uc_value_t *uv = (uc_value_t *)k;
3287         unsigned int h;
3288         uint8_t *u8;
3289         size_t len;
3290 
3291         h = ucv_type(uv);
3292 
3293         switch (h) {
3294         case UC_STRING:
3295                 u8 = (uint8_t *)ucv_string_get(uv);
3296                 len = ucv_string_length(uv);
3297                 break;
3298 
3299         case UC_INTEGER:
3300                 conv.i = ucv_int64_get(uv);
3301 
3302                 if (errno == ERANGE) {
3303                         h *= 2;
3304                         conv.u = ucv_uint64_get(uv);
3305                 }
3306 
3307                 u8 = (uint8_t *)&conv.u;
3308                 len = sizeof(conv.u);
3309                 break;
3310 
3311         case UC_DOUBLE:
3312                 conv.d = ucv_double_get(uv);
3313 
3314                 u8 = (uint8_t *)&conv.u;
3315                 len = sizeof(conv.u);
3316                 break;
3317 
3318         default:
3319                 u8 = (uint8_t *)&uv;
3320                 len = sizeof(uv);
3321                 break;
3322         }
3323 
3324         while (len > 0) {
3325                 h = h * 129 + (*u8++) + LH_PRIME;
3326                 len--;
3327         }
3328 
3329         return h;
3330 }
3331 
3332 static int
3333 uc_uniq_ucv_equal(const void *k1, const void *k2)
3334 {
3335         uc_value_t *uv1 = (uc_value_t *)k1;
3336         uc_value_t *uv2 = (uc_value_t *)k2;
3337 
3338         if (!ucv_is_scalar(uv1) && !ucv_is_scalar(uv2))
3339                 return (uv1 == uv2);
3340 
3341         /* for the sake of array item uniqueness, treat two NaNs as equal */
3342         if (ucv_type(uv1) == UC_DOUBLE && ucv_type(uv2) == UC_DOUBLE &&
3343             isnan(ucv_double_get(uv1)) && isnan(ucv_double_get(uv2)))
3344             return true;
3345 
3346         return ucv_is_equal(uv1, uv2);
3347 }
3348 
3349 static uc_value_t *
3350 uc_uniq(uc_vm_t *vm, size_t nargs)
3351 {
3352         uc_value_t *list = uc_fn_arg(0);
3353         uc_value_t *uniq = NULL;
3354         struct lh_table *seen;
3355         unsigned long hash;
3356         uc_value_t *item;
3357         size_t i, len;
3358 
3359         if (ucv_type(list) != UC_ARRAY)
3360                 return NULL;
3361 
3362         seen = lh_table_new(16, NULL, uc_uniq_ucv_hash, uc_uniq_ucv_equal);
3363         uniq = ucv_array_new(vm);
3364 
3365         assert(seen && uniq);
3366 
3367         for (i = 0, len = ucv_array_length(list); i < len; i++) {
3368                 item = ucv_array_get(list, i);
3369                 hash = lh_get_hash(seen, item);
3370 
3371                 if (!lh_table_lookup_entry_w_hash(seen, item, hash)) {
3372                         lh_table_insert_w_hash(seen, item, NULL, hash, 0);
3373                         ucv_array_push(uniq, ucv_get(item));
3374                 }
3375         }
3376 
3377         lh_table_free(seen);
3378 
3379         return uniq;
3380 }
3381 
3382 static uc_value_t *
3383 uc_gettime_common(uc_vm_t *vm, size_t nargs, bool local)
3384 {
3385         uc_value_t *ts = uc_fn_arg(0), *res;
3386         time_t t = ts ? (time_t)ucv_to_integer(ts) : time(NULL);
3387         struct tm *tm = (local ? localtime : gmtime)(&t);
3388 
3389         if (!tm)
3390                 return NULL;
3391 
3392         res = ucv_object_new(vm);
3393 
3394         ucv_object_add(res, "sec", ucv_int64_new(tm->tm_sec));
3395         ucv_object_add(res, "min", ucv_int64_new(tm->tm_min));
3396         ucv_object_add(res, "hour", ucv_int64_new(tm->tm_hour));
3397         ucv_object_add(res, "mday", ucv_int64_new(tm->tm_mday));
3398         ucv_object_add(res, "mon", ucv_int64_new(tm->tm_mon + 1));
3399         ucv_object_add(res, "year", ucv_int64_new(tm->tm_year + 1900));
3400         ucv_object_add(res, "wday", ucv_int64_new(tm->tm_wday ? tm->tm_wday : 7));
3401         ucv_object_add(res, "yday", ucv_int64_new(tm->tm_yday + 1));
3402         ucv_object_add(res, "isdst", ucv_int64_new(tm->tm_isdst));
3403 
3404         return res;
3405 }
3406 
3407 static uc_value_t *
3408 uc_localtime(uc_vm_t *vm, size_t nargs)
3409 {
3410         return uc_gettime_common(vm, nargs, true);
3411 }
3412 
3413 static uc_value_t *
3414 uc_gmtime(uc_vm_t *vm, size_t nargs)
3415 {
3416         return uc_gettime_common(vm, nargs, false);
3417 }
3418 
3419 static uc_value_t *
3420 uc_mktime_common(uc_vm_t *vm, size_t nargs, bool local)
3421 {
3422 #define FIELD(name, required) \
3423         { #name, required, offsetof(struct tm, tm_##name) }
3424 
3425         const struct {
3426                 const char *name;
3427                 bool required;
3428                 size_t off;
3429         } fields[] = {
3430                 FIELD(sec, false),
3431                 FIELD(min, false),
3432                 FIELD(hour, false),
3433                 FIELD(mday, true),
3434                 FIELD(mon, true),
3435                 FIELD(year, true),
3436                 FIELD(isdst, false)
3437         };
3438 
3439         uc_value_t *to = uc_fn_arg(0), *v;
3440         struct tm tm = { 0 };
3441         bool exists;
3442         time_t t;
3443         size_t i;
3444 
3445         if (ucv_type(to) != UC_OBJECT)
3446                 return NULL;
3447 
3448         for (i = 0; i < ARRAY_SIZE(fields); i++) {
3449                 v = ucv_object_get(to, fields[i].name, &exists);
3450 
3451                 if (!exists && fields[i].required)
3452                         return NULL;
3453 
3454                 *(int *)((char *)&tm + fields[i].off) = (int)ucv_to_integer(v);
3455         }
3456 
3457         if (tm.tm_mon > 0)
3458                 tm.tm_mon--;
3459 
3460         if (tm.tm_year >= 1900)
3461                 tm.tm_year -= 1900;
3462 
3463         t = (local ? mktime : timegm)(&tm);
3464 
3465         return (t != (time_t)-1) ? ucv_int64_new((int64_t)t) : NULL;
3466 }
3467 
3468 static uc_value_t *
3469 uc_timelocal(uc_vm_t *vm, size_t nargs)
3470 {
3471         return uc_mktime_common(vm, nargs, true);
3472 }
3473 
3474 static uc_value_t *
3475 uc_timegm(uc_vm_t *vm, size_t nargs)
3476 {
3477         return uc_mktime_common(vm, nargs, false);
3478 }
3479 
3480 static uc_value_t *
3481 uc_clock(uc_vm_t *vm, size_t nargs)
3482 {
3483         clockid_t id = ucv_is_truish(uc_fn_arg(0)) ? CLOCK_MONOTONIC : CLOCK_REALTIME;
3484         struct timespec ts;
3485         uc_value_t *res;
3486 
3487         if (clock_gettime(id, &ts) == -1)
3488                 return NULL;
3489 
3490         res = ucv_array_new(vm);
3491 
3492         ucv_array_set(res, 0, ucv_int64_new((int64_t)ts.tv_sec));
3493         ucv_array_set(res, 1, ucv_int64_new((int64_t)ts.tv_nsec));
3494 
3495         return res;
3496 }
3497 
3498 static uc_value_t *
3499 uc_hexenc(uc_vm_t *vm, size_t nargs)
3500 {
3501         const char *hex = "0123456789abcdef";
3502         uc_value_t *input = uc_fn_arg(0);
3503         uc_stringbuf_t *buf;
3504         size_t off, len;
3505         uint8_t byte;
3506 
3507         if (!input)
3508                 return NULL;
3509 
3510         buf = ucv_stringbuf_new();
3511         off = printbuf_length(buf);
3512 
3513         ucv_to_stringbuf(vm, buf, input, false);
3514 
3515         len = printbuf_length(buf) - off;
3516 
3517         /* memset the last expected output char to grow the output buffer */
3518         printbuf_memset(buf, off + len * 2, 0, 1);
3519 
3520         /* translate string into hex back to front to reuse the same buffer */
3521         while (len > 0) {
3522                 byte = buf->buf[--len + off];
3523                 buf->buf[off + len * 2 + 0] = hex[byte / 16];
3524                 buf->buf[off + len * 2 + 1] = hex[byte % 16];
3525         }
3526 
3527         /* do not include sentinel `\0` in string length */
3528         buf->bpos--;
3529 
3530         return ucv_stringbuf_finish(buf);
3531 }
3532 
3533 static inline uint8_t
3534 hexval(unsigned char c, bool lo)
3535 {
3536         return ((c > '9') ? (c - 'a') + 10 : c - '') << (lo ? 0 : 4);
3537 }
3538 
3539 static uc_value_t *
3540 uc_hexdec(uc_vm_t *vm, size_t nargs)
3541 {
3542         uc_value_t *input = uc_fn_arg(0);
3543         uc_value_t *skip = uc_fn_arg(1);
3544         size_t len, off, n, i;
3545         uc_stringbuf_t *buf;
3546         unsigned char *p;
3547         const char *s;
3548 
3549         if (ucv_type(input) != UC_STRING)
3550                 return NULL;
3551 
3552         if (skip && ucv_type(skip) != UC_STRING)
3553                 return NULL;
3554 
3555         p = (unsigned char *)ucv_string_get(input);
3556         len = ucv_string_length(input);
3557 
3558         s = skip ? (const char *)ucv_string_get(skip) : " \t\n";
3559 
3560         for (i = 0, n = 0; i < len; i++) {
3561                 if (isxdigit(p[i]))
3562                         n++;
3563                 else if (!s || !strchr(s, p[i]))
3564                         return NULL;
3565         }
3566 
3567         if (n & 1)
3568                 return NULL;
3569 
3570         buf = ucv_stringbuf_new();
3571         off = printbuf_length(buf);
3572 
3573         /* preallocate the output buffer */
3574         printbuf_memset(buf, off, 0, n / 2 + 1);
3575 
3576         for (i = 0, n = 0; i < len; i++) {
3577                 if (!isxdigit(p[i]))
3578                         continue;
3579 
3580                 buf->buf[off + (n >> 1)] |= hexval(p[i] | 32, n & 1);
3581                 n++;
3582         }
3583 
3584         /* do not include sentinel `\0` in string length */
3585         buf->bpos--;
3586 
3587         return ucv_stringbuf_finish(buf);
3588 }
3589 
3590 static uc_value_t *
3591 uc_gc(uc_vm_t *vm, size_t nargs)
3592 {
3593         uc_value_t *operation = uc_fn_arg(0);
3594         uc_value_t *argument = uc_fn_arg(1);
3595         const char *op = NULL;
3596         uc_weakref_t *ref;
3597         int64_t n;
3598 
3599         if (operation != NULL && ucv_type(operation) != UC_STRING)
3600                 return NULL;
3601 
3602         op = ucv_string_get(operation);
3603 
3604         if (!op || !strcmp(op, "collect")) {
3605                 ucv_gc(vm);
3606 
3607                 return ucv_boolean_new(true);
3608         }
3609         else if (!strcmp(op, "start")) {
3610                 n = argument ? ucv_int64_get(argument) : 0;
3611 
3612                 if (errno || n < 0 || n > 0xFFFF)
3613                         return NULL;
3614 
3615                 if (n == 0)
3616                         n = GC_DEFAULT_INTERVAL;
3617 
3618                 return ucv_boolean_new(uc_vm_gc_start(vm, n));
3619         }
3620         else if (!strcmp(op, "stop")) {
3621                 return ucv_boolean_new(uc_vm_gc_stop(vm));
3622         }
3623         else if (!strcmp(op, "count")) {
3624                 for (n = 0, ref = vm->values.next; ref != &vm->values; ref = ref->next)
3625                         n++;
3626 
3627                 return ucv_uint64_new(n);
3628         }
3629 
3630         return NULL;
3631 }
3632 
3633 static void
3634 uc_compile_parse_config(uc_parse_config_t *config, uc_value_t *spec)
3635 {
3636         uc_value_t *v, *p;
3637         size_t i, j;
3638         bool found;
3639 
3640         struct {
3641                 const char *key;
3642                 bool *flag;
3643                 uc_search_path_t *path;
3644         } fields[] = {
3645                 { "lstrip_blocks",       &config->lstrip_blocks,       NULL },
3646                 { "trim_blocks",         &config->trim_blocks,         NULL },
3647                 { "strict_declarations", &config->strict_declarations, NULL },
3648                 { "raw_mode",            &config->raw_mode,            NULL },
3649                 { "module_search_path",  NULL, &config->module_search_path  },
3650                 { "force_dynlink_list",  NULL, &config->force_dynlink_list  }
3651         };
3652 
3653         for (i = 0; i < ARRAY_SIZE(fields); i++) {
3654                 v = ucv_object_get(spec, fields[i].key, &found);
3655 
3656                 if (!found)
3657                         continue;
3658 
3659                 if (fields[i].flag) {
3660                         *fields[i].flag = ucv_is_truish(v);
3661                 }
3662                 else if (fields[i].path) {
3663                         fields[i].path->count = 0;
3664                         fields[i].path->entries = NULL;
3665 
3666                         for (j = 0; j < ucv_array_length(v); j++) {
3667                                 p = ucv_array_get(v, j);
3668 
3669                                 if (ucv_type(p) != UC_STRING)
3670                                         continue;
3671 
3672                                 uc_vector_push(fields[i].path, ucv_string_get(p));
3673                         }
3674                 }
3675         }
3676 }
3677 
3678 static uc_value_t *
3679 uc_load_common(uc_vm_t *vm, size_t nargs, uc_source_t *source)
3680 {
3681         uc_parse_config_t conf = *vm->config;
3682         uc_program_t *program;
3683         uc_value_t *closure;
3684         char *err = NULL;
3685 
3686         uc_compile_parse_config(&conf, uc_fn_arg(1));
3687 
3688         program = uc_compile(&conf, source, &err);
3689         closure = program ? ucv_closure_new(vm, uc_program_entry(program), false) : NULL;
3690 
3691         uc_program_put(program);
3692 
3693         if (!vm->config || conf.module_search_path.entries != vm->config->module_search_path.entries)
3694                 uc_vector_clear(&conf.module_search_path);
3695 
3696         if (!vm->config || conf.force_dynlink_list.entries != vm->config->force_dynlink_list.entries)
3697                 uc_vector_clear(&conf.force_dynlink_list);
3698 
3699         if (!closure) {
3700                 uc_error_message_indent(&err);
3701 
3702                 if (source->buffer)
3703                         uc_vm_raise_exception(vm, EXCEPTION_RUNTIME,
3704                                 "Unable to compile source string:\n\n%s", err);
3705                 else
3706                         uc_vm_raise_exception(vm, EXCEPTION_RUNTIME,
3707                                 "Unable to compile source file '%s':\n\n%s", source->filename, err);
3708         }
3709 
3710         uc_source_put(source);
3711         free(err);
3712 
3713         return closure;
3714 }
3715 
3716 static uc_value_t *
3717 uc_loadstring(uc_vm_t *vm, size_t nargs)
3718 {
3719         uc_value_t *code = uc_fn_arg(0);
3720         uc_source_t *source;
3721         size_t len;
3722         char *s;
3723 
3724         if (ucv_type(code) == UC_STRING) {
3725                 len = ucv_string_length(code);
3726                 s = xalloc(len);
3727                 memcpy(s, ucv_string_get(code), len);
3728         }
3729         else {
3730                 s = ucv_to_string(vm, code);
3731                 len = strlen(s);
3732         }
3733 
3734         source = uc_source_new_buffer("[loadstring argument]", s, len);
3735 
3736         if (!source) {
3737                 uc_vm_raise_exception(vm, EXCEPTION_RUNTIME,
3738                         "Unable to allocate source buffer: %s",
3739                         strerror(errno));
3740 
3741                 return NULL;
3742         }
3743 
3744         return uc_load_common(vm, nargs, source);
3745 }
3746 
3747 static uc_value_t *
3748 uc_loadfile(uc_vm_t *vm, size_t nargs)
3749 {
3750         uc_value_t *path = uc_fn_arg(0);
3751         uc_source_t *source;
3752 
3753         if (ucv_type(path) != UC_STRING)
3754                 return NULL;
3755 
3756         source = uc_source_new_file(ucv_string_get(path));
3757 
3758         if (!source) {
3759                 uc_vm_raise_exception(vm, EXCEPTION_RUNTIME,
3760                         "Unable to open source file %s: %s",
3761                         ucv_string_get(path), strerror(errno));
3762 
3763                 return NULL;
3764         }
3765 
3766         return uc_load_common(vm, nargs, source);
3767 }
3768 
3769 static uc_value_t *
3770 uc_callfunc(uc_vm_t *vm, size_t nargs)
3771 {
3772         size_t argoff = vm->stack.count - nargs, i;
3773         uc_value_t *fn_scope, *prev_scope, *res;
3774         uc_value_t *fn = uc_fn_arg(0);
3775         uc_value_t *this = uc_fn_arg(1);
3776         uc_value_t *scope = uc_fn_arg(2);
3777 
3778         if (!ucv_is_callable(fn))
3779                 return NULL;
3780 
3781         if (scope && ucv_type(scope) != UC_OBJECT)
3782                 return NULL;
3783 
3784         if (ucv_prototype_get(scope)) {
3785                 fn_scope = ucv_get(scope);
3786         }
3787         else if (scope) {
3788                 fn_scope = ucv_object_new(vm);
3789 
3790                 ucv_object_foreach(scope, k, v)
3791                         ucv_object_add(fn_scope, k, ucv_get(v));
3792 
3793                 ucv_prototype_set(fn_scope, ucv_get(uc_vm_scope_get(vm)));
3794         }
3795         else {
3796                 fn_scope = NULL;
3797         }
3798 
3799         uc_vm_stack_push(vm, ucv_get(this));
3800         uc_vm_stack_push(vm, ucv_get(fn));
3801 
3802         for (i = 3; i < nargs; i++)
3803                 uc_vm_stack_push(vm, ucv_get(vm->stack.entries[3 + argoff++]));
3804 
3805         if (fn_scope) {
3806                 prev_scope = ucv_get(uc_vm_scope_get(vm));
3807                 uc_vm_scope_set(vm, fn_scope);
3808         }
3809 
3810         if (uc_vm_call(vm, true, i - 3) == EXCEPTION_NONE)
3811                 res = uc_vm_stack_pop(vm);
3812         else
3813                 res = NULL;
3814 
3815         if (fn_scope)
3816                 uc_vm_scope_set(vm, prev_scope);
3817 
3818         return res;
3819 }
3820 
3821 
3822 const uc_function_list_t uc_stdlib_functions[] = {
3823         { "chr",                uc_chr },
3824         { "die",                uc_die },
3825         { "exists",             uc_exists },
3826         { "exit",               uc_exit },
3827         { "filter",             uc_filter },
3828         { "getenv",             uc_getenv },
3829         { "hex",                uc_hex },
3830         { "index",              uc_lindex },
3831         { "int",                uc_int },
3832         { "join",               uc_join },
3833         { "keys",               uc_keys },
3834         { "lc",                 uc_lc },
3835         { "length",             uc_length },
3836         { "ltrim",              uc_ltrim },
3837         { "map",                uc_map },
3838         { "ord",                uc_ord },
3839         { "pop",                uc_pop },
3840         { "print",              uc_print },
3841         { "push",               uc_push },
3842         { "reverse",    uc_reverse },
3843         { "rindex",             uc_rindex },
3844         { "rtrim",              uc_rtrim },
3845         { "shift",              uc_shift },
3846         { "sort",               uc_sort },
3847         { "splice",             uc_splice },
3848         { "split",              uc_split },
3849         { "substr",             uc_substr },
3850         { "time",               uc_time },
3851         { "trim",               uc_trim },
3852         { "type",               uc_type },
3853         { "uchr",               uc_uchr },
3854         { "uc",                 uc_uc },
3855         { "unshift",    uc_unshift },
3856         { "values",             uc_values },
3857         { "sprintf",    uc_sprintf },
3858         { "printf",             uc_printf },
3859         { "require",    uc_require },
3860         { "iptoarr",    uc_iptoarr },
3861         { "arrtoip",    uc_arrtoip },
3862         { "match",              uc_match },
3863         { "replace",    uc_replace },
3864         { "json",               uc_json },
3865         { "include",    uc_include },
3866         { "warn",               uc_warn },
3867         { "system",             uc_system },
3868         { "trace",              uc_trace },
3869         { "proto",              uc_proto },
3870         { "sleep",              uc_sleep },
3871         { "assert",             uc_assert },
3872         { "render",             uc_render },
3873         { "regexp",             uc_regexp },
3874         { "wildcard",   uc_wildcard },
3875         { "sourcepath", uc_sourcepath },
3876         { "min",                uc_min },
3877         { "max",                uc_max },
3878         { "b64dec",             uc_b64dec },
3879         { "b64enc",             uc_b64enc },
3880         { "uniq",               uc_uniq },
3881         { "localtime",  uc_localtime },
3882         { "gmtime",             uc_gmtime },
3883         { "timelocal",  uc_timelocal },
3884         { "timegm",             uc_timegm },
3885         { "clock",              uc_clock },
3886         { "hexdec",             uc_hexdec },
3887         { "hexenc",             uc_hexenc },
3888         { "gc",                 uc_gc },
3889         { "loadstring", uc_loadstring },
3890         { "loadfile",   uc_loadfile },
3891         { "call",               uc_callfunc },
3892 };
3893 
3894 
3895 void
3896 uc_stdlib_load(uc_value_t *scope)
3897 {
3898         uc_function_list_register(scope, uc_stdlib_functions);
3899 }
3900 
3901 uc_cfn_ptr_t
3902 uc_stdlib_function(const char *name)
3903 {
3904         size_t i;
3905 
3906         for (i = 0; i < ARRAY_SIZE(uc_stdlib_functions); i++)
3907                 if (!strcmp(uc_stdlib_functions[i].name, name))
3908                         return uc_stdlib_functions[i].func;
3909 
3910         return NULL;
3911 }
3912 

This page was automatically generated by LXR 0.3.1.  •  OpenWrt