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; 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(nargs - i); 475 ucv_array_unshift(arr, ucv_get(item)); 476 } 477 478 return (nargs > 1) ? ucv_get(uc_fn_arg(nargs - 1)) : NULL; 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_slice(uc_vm_t *vm, size_t nargs) 1023 { 1024 uc_value_t *arr = uc_fn_arg(0); 1025 uc_value_t *sv = uc_fn_arg(1); 1026 uc_value_t *ev = uc_fn_arg(2); 1027 uc_value_t *res = NULL; 1028 int64_t off, end; 1029 size_t len; 1030 1031 if (ucv_type(arr) != UC_ARRAY) 1032 return NULL; 1033 1034 len = ucv_array_length(arr); 1035 off = sv ? ucv_to_integer(sv) : 0; 1036 end = ev ? ucv_to_integer(ev) : (int64_t)len; 1037 1038 if (off < 0) { 1039 off = len + off; 1040 1041 if (off < 0) 1042 off = 0; 1043 } 1044 else if ((uint64_t)off > len) { 1045 off = len; 1046 } 1047 1048 if (end < 0) { 1049 end = len + end; 1050 1051 if (end < 0) 1052 end = 0; 1053 } 1054 else if ((uint64_t)end > len) { 1055 end = len; 1056 } 1057 1058 res = ucv_array_new(vm); 1059 1060 while (off < end) 1061 ucv_array_push(res, ucv_get(ucv_array_get(arr, off++))); 1062 1063 return res; 1064 } 1065 1066 static uc_value_t * 1067 uc_split(uc_vm_t *vm, size_t nargs) 1068 { 1069 uc_value_t *str = uc_fn_arg(0); 1070 uc_value_t *sep = uc_fn_arg(1); 1071 uc_value_t *lim = uc_fn_arg(2); 1072 uc_value_t *arr = NULL; 1073 const char *p, *sepstr, *splitstr; 1074 size_t seplen, splitlen, limit; 1075 int eflags = 0, res; 1076 regmatch_t pmatch; 1077 uc_regexp_t *re; 1078 1079 if (!sep || ucv_type(str) != UC_STRING) 1080 return NULL; 1081 1082 arr = ucv_array_new(vm); 1083 splitlen = ucv_string_length(str); 1084 p = splitstr = ucv_string_get(str); 1085 limit = lim ? ucv_uint64_get(lim) : SIZE_MAX; 1086 1087 if (limit == 0) 1088 goto out; 1089 1090 if (ucv_type(sep) == UC_REGEXP) { 1091 re = (uc_regexp_t *)sep; 1092 1093 while (limit > 1) { 1094 res = regexec(&re->regexp, splitstr, 1, &pmatch, eflags); 1095 1096 if (res == REG_NOMATCH) 1097 break; 1098 1099 if (pmatch.rm_so != pmatch.rm_eo) { 1100 ucv_array_push(arr, ucv_string_new_length(splitstr, pmatch.rm_so)); 1101 splitstr += pmatch.rm_eo; 1102 } 1103 else if (*splitstr) { 1104 ucv_array_push(arr, ucv_string_new_length(splitstr, 1)); 1105 splitstr++; 1106 } 1107 else { 1108 goto out; 1109 } 1110 1111 eflags |= REG_NOTBOL; 1112 limit--; 1113 } 1114 1115 ucv_array_push(arr, ucv_string_new(splitstr)); 1116 } 1117 else if (ucv_type(sep) == UC_STRING) { 1118 sepstr = ucv_string_get(sep); 1119 seplen = ucv_string_length(sep); 1120 1121 if (splitlen == 0) { 1122 ucv_array_push(arr, ucv_string_new_length("", 0)); 1123 } 1124 else if (seplen == 0) { 1125 while (limit > 1 && splitlen > 0) { 1126 ucv_array_push(arr, ucv_string_new_length(p, 1)); 1127 1128 limit--; 1129 splitlen--; 1130 p++; 1131 } 1132 1133 if (splitlen > 0) 1134 ucv_array_push(arr, ucv_string_new_length(p, splitlen)); 1135 } 1136 else { 1137 while (limit > 1 && splitlen >= seplen) { 1138 if (!memcmp(p, sepstr, seplen)) { 1139 ucv_array_push(arr, ucv_string_new_length(splitstr, p - splitstr)); 1140 1141 p = splitstr = p + seplen; 1142 splitlen -= seplen; 1143 limit--; 1144 continue; 1145 } 1146 1147 splitlen--; 1148 p++; 1149 } 1150 1151 ucv_array_push(arr, ucv_string_new_length(splitstr, p - splitstr + splitlen)); 1152 } 1153 } 1154 else { 1155 ucv_put(arr); 1156 1157 return NULL; 1158 } 1159 1160 out: 1161 return arr; 1162 } 1163 1164 static uc_value_t * 1165 uc_substr(uc_vm_t *vm, size_t nargs) 1166 { 1167 uc_value_t *str = uc_fn_arg(0); 1168 int64_t ofs = ucv_to_integer(uc_fn_arg(1)); 1169 int64_t sublen = ucv_to_integer(uc_fn_arg(2)); 1170 const char *p; 1171 size_t len; 1172 1173 if (ucv_type(str) != UC_STRING) 1174 return NULL; 1175 1176 p = ucv_string_get(str); 1177 len = ucv_string_length(str); 1178 1179 switch (nargs) { 1180 case 1: 1181 ofs = 0; 1182 sublen = len; 1183 1184 break; 1185 1186 case 2: 1187 if (ofs < 0) { 1188 ofs = len + ofs; 1189 1190 if (ofs < 0) 1191 ofs = 0; 1192 } 1193 else if ((uint64_t)ofs > len) { 1194 ofs = len; 1195 } 1196 1197 sublen = len - ofs; 1198 1199 break; 1200 1201 default: 1202 if (ofs < 0) { 1203 ofs = len + ofs; 1204 1205 if (ofs < 0) 1206 ofs = 0; 1207 } 1208 else if ((uint64_t)ofs > len) { 1209 ofs = len; 1210 } 1211 1212 if (sublen < 0) { 1213 sublen = len - ofs + sublen; 1214 1215 if (sublen < 0) 1216 sublen = 0; 1217 } 1218 else if ((uint64_t)sublen > len - (uint64_t)ofs) { 1219 sublen = len - ofs; 1220 } 1221 1222 break; 1223 } 1224 1225 return ucv_string_new_length(p + ofs, sublen); 1226 } 1227 1228 static uc_value_t * 1229 uc_time(uc_vm_t *vm, size_t nargs) 1230 { 1231 time_t t = time(NULL); 1232 1233 return ucv_int64_new((int64_t)t); 1234 } 1235 1236 static uc_value_t * 1237 uc_uc(uc_vm_t *vm, size_t nargs) 1238 { 1239 char *str = ucv_to_string(vm, uc_fn_arg(0)); 1240 uc_value_t *rv = NULL; 1241 char *p; 1242 1243 if (!str) 1244 return NULL; 1245 1246 for (p = str; *p; p++) 1247 if (*p >= 'a' && *p <= 'z') 1248 *p &= ~32; 1249 1250 rv = ucv_string_new(str); 1251 1252 free(str); 1253 1254 return rv; 1255 } 1256 1257 static uc_value_t * 1258 uc_uchr(uc_vm_t *vm, size_t nargs) 1259 { 1260 uc_value_t *rv = NULL; 1261 size_t idx, ulen; 1262 char *p, *str; 1263 int64_t n; 1264 int rem; 1265 1266 for (idx = 0, ulen = 0; idx < nargs; idx++) { 1267 n = ucv_to_integer(uc_fn_arg(idx)); 1268 1269 if (errno == EINVAL || errno == ERANGE || n < 0 || n > 0x10FFFF) 1270 ulen += 3; 1271 else if (n <= 0x7F) 1272 ulen++; 1273 else if (n <= 0x7FF) 1274 ulen += 2; 1275 else if (n <= 0xFFFF) 1276 ulen += 3; 1277 else 1278 ulen += 4; 1279 } 1280 1281 str = xalloc(ulen); 1282 1283 for (idx = 0, p = str, rem = ulen; idx < nargs; idx++) { 1284 n = ucv_to_integer(uc_fn_arg(idx)); 1285 1286 if (errno == EINVAL || errno == ERANGE || n < 0 || n > 0x10FFFF) 1287 n = 0xFFFD; 1288 1289 if (!utf8enc(&p, &rem, n)) 1290 break; 1291 } 1292 1293 rv = ucv_string_new_length(str, ulen); 1294 1295 free(str); 1296 1297 return rv; 1298 } 1299 1300 static uc_value_t * 1301 uc_values(uc_vm_t *vm, size_t nargs) 1302 { 1303 uc_value_t *obj = uc_fn_arg(0); 1304 uc_value_t *arr; 1305 1306 if (ucv_type(obj) != UC_OBJECT) 1307 return NULL; 1308 1309 arr = ucv_array_new(vm); 1310 1311 ucv_object_foreach(obj, key, val) { 1312 (void)key; 1313 ucv_array_push(arr, ucv_get(val)); 1314 } 1315 1316 return arr; 1317 } 1318 1319 static uc_value_t * 1320 uc_trim_common(uc_vm_t *vm, size_t nargs, bool start, bool end) 1321 { 1322 uc_value_t *str = uc_fn_arg(0); 1323 uc_value_t *chr = uc_fn_arg(1); 1324 const char *p, *c; 1325 size_t len; 1326 1327 if (ucv_type(str) != UC_STRING || 1328 (chr != NULL && ucv_type(chr) != UC_STRING)) 1329 return NULL; 1330 1331 c = ucv_string_get(chr); 1332 c = c ? c : " \t\r\n"; 1333 1334 p = ucv_string_get(str); 1335 len = ucv_string_length(str); 1336 1337 if (start) { 1338 while (*p) { 1339 if (!strchr(c, *p)) 1340 break; 1341 1342 p++; 1343 len--; 1344 } 1345 } 1346 1347 if (end) { 1348 while (len > 0) { 1349 if (!strchr(c, p[len - 1])) 1350 break; 1351 1352 len--; 1353 } 1354 } 1355 1356 return ucv_string_new_length(p, len); 1357 } 1358 1359 static uc_value_t * 1360 uc_trim(uc_vm_t *vm, size_t nargs) 1361 { 1362 return uc_trim_common(vm, nargs, true, true); 1363 } 1364 1365 static uc_value_t * 1366 uc_ltrim(uc_vm_t *vm, size_t nargs) 1367 { 1368 return uc_trim_common(vm, nargs, true, false); 1369 } 1370 1371 static uc_value_t * 1372 uc_rtrim(uc_vm_t *vm, size_t nargs) 1373 { 1374 return uc_trim_common(vm, nargs, false, true); 1375 } 1376 1377 enum { 1378 FMT_F_ALT = (1 << 0), 1379 FMT_F_ZERO = (1 << 1), 1380 FMT_F_LEFT = (1 << 2), 1381 FMT_F_SPACE = (1 << 3), 1382 FMT_F_SIGN = (1 << 4), 1383 FMT_F_WIDTH = (1 << 5), 1384 FMT_F_PREC = (1 << 6), 1385 }; 1386 1387 enum { 1388 FMT_C_NONE = (1 << 0), 1389 FMT_C_INT = (1 << 1), 1390 FMT_C_UINT = (1 << 2), 1391 FMT_C_DBL = (1 << 3), 1392 FMT_C_CHR = (1 << 4), 1393 FMT_C_STR = (1 << 5), 1394 FMT_C_JSON = (1 << 6), 1395 }; 1396 1397 static void 1398 uc_printf_common(uc_vm_t *vm, size_t nargs, uc_stringbuf_t *buf) 1399 { 1400 char *s, sfmt[sizeof("%#0- +0123456789.0123456789%")]; 1401 uint32_t conv, flags, width, precision; 1402 uc_value_t *fmt = uc_fn_arg(0), *arg; 1403 const char *fstr, *last, *p, *cfmt; 1404 size_t argidx = 1, argpos, sfmtlen; 1405 uint64_t u; 1406 int64_t n; 1407 double d; 1408 1409 if (ucv_type(fmt) == UC_STRING) 1410 fstr = ucv_string_get(fmt); 1411 else 1412 fstr = ""; 1413 1414 for (last = p = fstr; *p; p++) { 1415 if (*p == '%') { 1416 ucv_stringbuf_addstr(buf, last, p - last); 1417 1418 last = p++; 1419 1420 flags = 0; 1421 width = 0; 1422 precision = 0; 1423 1424 argpos = argidx; 1425 1426 if (*p >= '1' && *p <= '9') { 1427 while (isdigit(*p)) 1428 width = width * 10 + (*p++ - ''); 1429 1430 /* if a dollar sign follows, this is an argument index */ 1431 if (*p == '$') { 1432 argpos = width; 1433 width = 0; 1434 p++; 1435 } 1436 1437 /* otherwise skip to parsing precision, flags can't possibly follow */ 1438 else { 1439 flags |= FMT_F_WIDTH; 1440 goto parse_precision; 1441 } 1442 } 1443 1444 while (*p != '\0' && strchr("#0- +", *p)) { 1445 switch (*p++) { 1446 case '#': flags |= FMT_F_ALT; break; 1447 case '': flags |= FMT_F_ZERO; break; 1448 case '-': flags |= FMT_F_LEFT; break; 1449 case ' ': flags |= FMT_F_SPACE; break; 1450 case '+': flags |= FMT_F_SIGN; break; 1451 } 1452 } 1453 1454 if (*p >= '1' && *p <= '9') { 1455 while (isdigit(*p)) 1456 width = width * 10 + (*p++ - ''); 1457 1458 flags |= FMT_F_WIDTH; 1459 } 1460 1461 parse_precision: 1462 if (*p == '.') { 1463 p++; 1464 1465 if (*p == '-') { 1466 p++; 1467 1468 while (isdigit(*p)) 1469 p++; 1470 } 1471 else { 1472 while (isdigit(*p)) 1473 precision = precision * 10 + (*p++ - ''); 1474 } 1475 1476 flags |= FMT_F_PREC; 1477 } 1478 1479 switch (*p) { 1480 case 'd': 1481 case 'i': 1482 conv = FMT_C_INT; 1483 flags &= ~FMT_F_PREC; 1484 cfmt = PRId64; 1485 break; 1486 1487 case 'o': 1488 conv = FMT_C_UINT; 1489 flags &= ~FMT_F_PREC; 1490 cfmt = PRIo64; 1491 break; 1492 1493 case 'u': 1494 conv = FMT_C_UINT; 1495 flags &= ~FMT_F_PREC; 1496 cfmt = PRIu64; 1497 break; 1498 1499 case 'x': 1500 conv = FMT_C_UINT; 1501 flags &= ~FMT_F_PREC; 1502 cfmt = PRIx64; 1503 break; 1504 1505 case 'X': 1506 conv = FMT_C_UINT; 1507 flags &= ~FMT_F_PREC; 1508 cfmt = PRIX64; 1509 break; 1510 1511 case 'e': 1512 conv = FMT_C_DBL; 1513 cfmt = "e"; 1514 break; 1515 1516 case 'E': 1517 conv = FMT_C_DBL; 1518 cfmt = "E"; 1519 break; 1520 1521 case 'f': 1522 conv = FMT_C_DBL; 1523 cfmt = "f"; 1524 break; 1525 1526 case 'F': 1527 conv = FMT_C_DBL; 1528 cfmt = "F"; 1529 break; 1530 1531 case 'g': 1532 conv = FMT_C_DBL; 1533 cfmt = "g"; 1534 break; 1535 1536 case 'G': 1537 conv = FMT_C_DBL; 1538 cfmt = "G"; 1539 break; 1540 1541 case 'c': 1542 conv = FMT_C_CHR; 1543 flags &= ~FMT_F_PREC; 1544 cfmt = "c"; 1545 break; 1546 1547 case 's': 1548 conv = FMT_C_STR; 1549 flags &= ~FMT_F_ZERO; 1550 cfmt = "s"; 1551 break; 1552 1553 case 'J': 1554 conv = FMT_C_JSON; 1555 1556 if (flags & FMT_F_PREC) { 1557 flags &= ~FMT_F_PREC; 1558 precision++; 1559 } 1560 1561 cfmt = "s"; 1562 break; 1563 1564 case '%': 1565 conv = FMT_C_NONE; 1566 flags = 0; 1567 cfmt = "%"; 1568 break; 1569 1570 case '\0': 1571 p--; 1572 /* fall through */ 1573 1574 default: 1575 continue; 1576 } 1577 1578 sfmtlen = 0; 1579 sfmt[sfmtlen++] = '%'; 1580 1581 if (flags & FMT_F_ALT) sfmt[sfmtlen++] = '#'; 1582 if (flags & FMT_F_ZERO) sfmt[sfmtlen++] = ''; 1583 if (flags & FMT_F_LEFT) sfmt[sfmtlen++] = '-'; 1584 if (flags & FMT_F_SPACE) sfmt[sfmtlen++] = ' '; 1585 if (flags & FMT_F_SIGN) sfmt[sfmtlen++] = '+'; 1586 1587 if (flags & FMT_F_WIDTH) 1588 sfmtlen += snprintf(&sfmt[sfmtlen], sizeof(sfmt) - sfmtlen, "%" PRIu32, width); 1589 1590 if (flags & FMT_F_PREC) 1591 sfmtlen += snprintf(&sfmt[sfmtlen], sizeof(sfmt) - sfmtlen, ".%" PRIu32, precision); 1592 1593 snprintf(&sfmt[sfmtlen], sizeof(sfmt) - sfmtlen, "%s", cfmt); 1594 1595 switch (conv) { 1596 case FMT_C_NONE: 1597 ucv_stringbuf_addstr(buf, cfmt, strlen(cfmt)); 1598 break; 1599 1600 case FMT_C_INT: 1601 argidx++; 1602 arg = uc_fn_arg(argpos); 1603 n = ucv_to_integer(arg); 1604 1605 if (errno == ERANGE) 1606 n = (int64_t)ucv_to_unsigned(arg); 1607 1608 ucv_stringbuf_printf(buf, sfmt, n); 1609 break; 1610 1611 case FMT_C_UINT: 1612 argidx++; 1613 arg = uc_fn_arg(argpos); 1614 u = ucv_to_unsigned(arg); 1615 1616 if (errno == ERANGE) 1617 u = (uint64_t)ucv_to_integer(arg); 1618 1619 ucv_stringbuf_printf(buf, sfmt, u); 1620 break; 1621 1622 case FMT_C_DBL: 1623 argidx++; 1624 d = ucv_to_double(uc_fn_arg(argpos)); 1625 ucv_stringbuf_printf(buf, sfmt, d); 1626 break; 1627 1628 case FMT_C_CHR: 1629 argidx++; 1630 n = ucv_to_integer(uc_fn_arg(argpos)); 1631 ucv_stringbuf_printf(buf, sfmt, (int)n); 1632 break; 1633 1634 case FMT_C_STR: 1635 argidx++; 1636 arg = uc_fn_arg(argpos); 1637 1638 switch (ucv_type(arg)) { 1639 case UC_STRING: 1640 ucv_stringbuf_printf(buf, sfmt, ucv_string_get(arg)); 1641 break; 1642 1643 case UC_NULL: 1644 ucv_stringbuf_append(buf, "(null)"); 1645 break; 1646 1647 default: 1648 s = ucv_to_string(vm, arg); 1649 ucv_stringbuf_printf(buf, sfmt, s ? s : "(null)"); 1650 free(s); 1651 } 1652 1653 break; 1654 1655 case FMT_C_JSON: 1656 argidx++; 1657 s = ucv_to_jsonstring_formatted(vm, 1658 uc_fn_arg(argpos), 1659 precision > 0 ? (precision > 1 ? ' ' : '\t') : '\0', 1660 precision > 0 ? (precision > 1 ? precision - 1 : 1) : 0); 1661 1662 ucv_stringbuf_printf(buf, sfmt, s ? s : "null"); 1663 free(s); 1664 break; 1665 } 1666 1667 last = p + 1; 1668 } 1669 } 1670 1671 ucv_stringbuf_addstr(buf, last, p - last); 1672 } 1673 1674 static uc_value_t * 1675 uc_sprintf(uc_vm_t *vm, size_t nargs) 1676 { 1677 uc_stringbuf_t *buf = ucv_stringbuf_new(); 1678 1679 uc_printf_common(vm, nargs, buf); 1680 1681 return ucv_stringbuf_finish(buf); 1682 } 1683 1684 static uc_value_t * 1685 uc_printf(uc_vm_t *vm, size_t nargs) 1686 { 1687 uc_stringbuf_t *buf = xprintbuf_new(); 1688 size_t len; 1689 1690 uc_printf_common(vm, nargs, buf); 1691 1692 len = fwrite(buf->buf, 1, printbuf_length(buf), vm->output); 1693 1694 printbuf_free(buf); 1695 1696 return ucv_int64_new(len); 1697 } 1698 1699 static bool 1700 uc_require_so(uc_vm_t *vm, const char *path, uc_value_t **res) 1701 { 1702 void (*init)(uc_vm_t *, uc_value_t *); 1703 uc_value_t *scope; 1704 struct stat st; 1705 void *dlh; 1706 1707 if (stat(path, &st)) 1708 return false; 1709 1710 dlerror(); 1711 dlh = dlopen(path, RTLD_LAZY|RTLD_LOCAL); 1712 1713 if (!dlh) { 1714 uc_vm_raise_exception(vm, EXCEPTION_RUNTIME, 1715 "Unable to dlopen file '%s': %s", path, dlerror()); 1716 1717 return true; 1718 } 1719 1720 *(void **)(&init) = dlsym(dlh, "uc_module_entry"); 1721 1722 if (!init) { 1723 uc_vm_raise_exception(vm, EXCEPTION_RUNTIME, 1724 "Module '%s' provides no 'uc_module_entry' function", path); 1725 1726 return true; 1727 } 1728 1729 scope = ucv_object_new(vm); 1730 1731 init(vm, scope); 1732 1733 *res = scope; 1734 1735 return true; 1736 } 1737 1738 static uc_value_t * 1739 uc_loadfile(uc_vm_t *vm, size_t nargs); 1740 1741 static uc_value_t * 1742 uc_callfunc(uc_vm_t *vm, size_t nargs); 1743 1744 static bool 1745 uc_require_ucode(uc_vm_t *vm, const char *path, uc_value_t *scope, uc_value_t **res, bool raw_mode) 1746 { 1747 uc_parse_config_t config = *vm->config, *prev_config = vm->config; 1748 uc_value_t *closure; 1749 struct stat st; 1750 1751 if (stat(path, &st)) 1752 return false; 1753 1754 config.raw_mode = raw_mode; 1755 vm->config = &config; 1756 1757 uc_vm_stack_push(vm, ucv_string_new(path)); 1758 1759 closure = uc_loadfile(vm, 1); 1760 1761 ucv_put(uc_vm_stack_pop(vm)); 1762 1763 if (closure) { 1764 uc_vm_stack_push(vm, closure); 1765 uc_vm_stack_push(vm, NULL); 1766 uc_vm_stack_push(vm, scope); 1767 1768 *res = uc_callfunc(vm, 3); 1769 1770 uc_vm_stack_pop(vm); 1771 uc_vm_stack_pop(vm); 1772 uc_vm_stack_pop(vm); 1773 } 1774 1775 vm->config = prev_config; 1776 1777 return true; 1778 } 1779 1780 static bool 1781 uc_require_path(uc_vm_t *vm, const char *path_template, const char *name, uc_value_t **res, bool so_only) 1782 { 1783 uc_stringbuf_t *buf = xprintbuf_new(); 1784 const char *p, *q, *last; 1785 uc_value_t *modtable; 1786 bool rv; 1787 1788 modtable = ucv_property_get(uc_vm_scope_get(vm), "modules"); 1789 *res = ucv_get(ucv_object_get(modtable, name, &rv)); 1790 1791 if (rv) 1792 goto out; 1793 1794 p = strchr(path_template, '*'); 1795 1796 if (!p) 1797 goto out; 1798 1799 ucv_stringbuf_addstr(buf, path_template, p - path_template); 1800 1801 for (q = last = name;; q++) { 1802 if (*q == '.' || *q == '\0') { 1803 ucv_stringbuf_addstr(buf, last, q - last); 1804 1805 if (*q) 1806 ucv_stringbuf_append(buf, "/"); 1807 else 1808 ucv_stringbuf_addstr(buf, p + 1, strlen(p + 1)); 1809 1810 if (*q == '\0') 1811 break; 1812 1813 last = q + 1; 1814 } 1815 else if (!isalnum(*q) && *q != '_') { 1816 goto out; 1817 } 1818 } 1819 1820 if (!strcmp(p + 1, ".so")) 1821 rv = uc_require_so(vm, buf->buf, res); 1822 else if (!strcmp(p + 1, ".uc") && !so_only) 1823 rv = uc_require_ucode(vm, buf->buf, NULL, res, true); 1824 1825 if (rv) 1826 ucv_object_add(modtable, name, ucv_get(*res)); 1827 1828 out: 1829 printbuf_free(buf); 1830 1831 return rv; 1832 } 1833 1834 uc_value_t * 1835 uc_require_library(uc_vm_t *vm, uc_value_t *nameval, bool so_only) 1836 { 1837 uc_value_t *search, *se, *res; 1838 size_t arridx, arrlen; 1839 const char *name; 1840 1841 if (ucv_type(nameval) != UC_STRING) 1842 return NULL; 1843 1844 name = ucv_string_get(nameval); 1845 search = ucv_property_get(uc_vm_scope_get(vm), "REQUIRE_SEARCH_PATH"); 1846 1847 if (ucv_type(search) != UC_ARRAY) { 1848 uc_vm_raise_exception(vm, EXCEPTION_RUNTIME, 1849 "Global require search path not set"); 1850 1851 return NULL; 1852 } 1853 1854 for (arridx = 0, arrlen = ucv_array_length(search); arridx < arrlen; arridx++) { 1855 se = ucv_array_get(search, arridx); 1856 1857 if (ucv_type(se) != UC_STRING) 1858 continue; 1859 1860 if (uc_require_path(vm, ucv_string_get(se), name, &res, so_only)) 1861 return res; 1862 } 1863 1864 uc_vm_raise_exception(vm, EXCEPTION_RUNTIME, 1865 "No module named '%s' could be found", name); 1866 1867 return NULL; 1868 } 1869 1870 static uc_value_t * 1871 uc_require(uc_vm_t *vm, size_t nargs) 1872 { 1873 return uc_require_library(vm, uc_fn_arg(0), false); 1874 } 1875 1876 static uc_value_t * 1877 uc_iptoarr(uc_vm_t *vm, size_t nargs) 1878 { 1879 uc_value_t *ip = uc_fn_arg(0); 1880 uc_value_t *res; 1881 union { 1882 uint8_t u8[4]; 1883 struct in_addr in; 1884 struct in6_addr in6; 1885 } a; 1886 int i; 1887 1888 if (ucv_type(ip) != UC_STRING) 1889 return NULL; 1890 1891 if (inet_pton(AF_INET6, ucv_string_get(ip), &a)) { 1892 res = ucv_array_new(vm); 1893 1894 for (i = 0; i < 16; i++) 1895 ucv_array_push(res, ucv_int64_new(a.in6.s6_addr[i])); 1896 1897 return res; 1898 } 1899 else if (inet_pton(AF_INET, ucv_string_get(ip), &a)) { 1900 res = ucv_array_new(vm); 1901 1902 ucv_array_push(res, ucv_int64_new(a.u8[0])); 1903 ucv_array_push(res, ucv_int64_new(a.u8[1])); 1904 ucv_array_push(res, ucv_int64_new(a.u8[2])); 1905 ucv_array_push(res, ucv_int64_new(a.u8[3])); 1906 1907 return res; 1908 } 1909 1910 return NULL; 1911 } 1912 1913 static int 1914 check_byte(uc_value_t *v) 1915 { 1916 int n; 1917 1918 if (ucv_type(v) != UC_INTEGER) 1919 return -1; 1920 1921 n = ucv_int64_get(v); 1922 1923 if (n < 0 || n > 255) 1924 return -1; 1925 1926 return n; 1927 } 1928 1929 static uc_value_t * 1930 uc_arrtoip(uc_vm_t *vm, size_t nargs) 1931 { 1932 uc_value_t *arr = uc_fn_arg(0); 1933 union { 1934 uint8_t u8[4]; 1935 struct in6_addr in6; 1936 } a; 1937 char buf[INET6_ADDRSTRLEN]; 1938 int i, n; 1939 1940 if (ucv_type(arr) != UC_ARRAY) 1941 return NULL; 1942 1943 switch (ucv_array_length(arr)) { 1944 case 4: 1945 for (i = 0; i < 4; i++) { 1946 n = check_byte(ucv_array_get(arr, i)); 1947 1948 if (n < 0) 1949 return NULL; 1950 1951 a.u8[i] = n; 1952 } 1953 1954 inet_ntop(AF_INET, &a, buf, sizeof(buf)); 1955 1956 return ucv_string_new(buf); 1957 1958 case 16: 1959 for (i = 0; i < 16; i++) { 1960 n = check_byte(ucv_array_get(arr, i)); 1961 1962 if (n < 0) 1963 return NULL; 1964 1965 a.in6.s6_addr[i] = n; 1966 } 1967 1968 inet_ntop(AF_INET6, &a, buf, sizeof(buf)); 1969 1970 return ucv_string_new(buf); 1971 1972 default: 1973 return NULL; 1974 } 1975 } 1976 1977 static uc_value_t * 1978 uc_match(uc_vm_t *vm, size_t nargs) 1979 { 1980 uc_value_t *subject = uc_fn_arg(0); 1981 uc_value_t *pattern = uc_fn_arg(1); 1982 uc_value_t *rv = NULL, *m; 1983 regmatch_t *pmatch = NULL; 1984 int eflags = 0, res; 1985 uc_regexp_t *re; 1986 bool freeable; 1987 char *p; 1988 size_t i; 1989 1990 if (ucv_type(pattern) != UC_REGEXP || !subject) 1991 return NULL; 1992 1993 re = (uc_regexp_t *)pattern; 1994 1995 pmatch = calloc(1 + re->regexp.re_nsub, sizeof(regmatch_t)); 1996 1997 if (!pmatch) 1998 return NULL; 1999 2000 p = uc_cast_string(vm, &subject, &freeable); 2001 2002 while (true) { 2003 res = regexec(&re->regexp, p, 1 + re->regexp.re_nsub, pmatch, eflags); 2004 2005 if (res == REG_NOMATCH) 2006 break; 2007 2008 m = ucv_array_new(vm); 2009 2010 for (i = 0; i < 1 + re->regexp.re_nsub; i++) { 2011 if (pmatch[i].rm_so != -1) 2012 ucv_array_push(m, 2013 ucv_string_new_length(p + pmatch[i].rm_so, 2014 pmatch[i].rm_eo - pmatch[i].rm_so)); 2015 else 2016 ucv_array_push(m, NULL); 2017 } 2018 2019 if (re->global) { 2020 if (!rv) 2021 rv = ucv_array_new(vm); 2022 2023 ucv_array_push(rv, m); 2024 2025 if (pmatch[0].rm_so != pmatch[0].rm_eo) 2026 p += pmatch[0].rm_eo; 2027 else if (*p) 2028 p++; 2029 else 2030 break; 2031 2032 eflags |= REG_NOTBOL; 2033 } 2034 else { 2035 rv = m; 2036 break; 2037 } 2038 } 2039 2040 free(pmatch); 2041 2042 if (freeable) 2043 free(p); 2044 2045 return rv; 2046 } 2047 2048 static void 2049 uc_replace_cb(uc_vm_t *vm, uc_value_t *func, 2050 const char *subject, regmatch_t *pmatch, size_t plen, 2051 uc_stringbuf_t *resbuf) 2052 { 2053 uc_value_t *rv; 2054 size_t i; 2055 2056 uc_vm_ctx_push(vm); 2057 uc_vm_stack_push(vm, ucv_get(func)); 2058 2059 for (i = 0; i < plen; i++) { 2060 if (pmatch[i].rm_so != -1) 2061 uc_vm_stack_push(vm, 2062 ucv_string_new_length(subject + pmatch[i].rm_so, 2063 pmatch[i].rm_eo - pmatch[i].rm_so)); 2064 else 2065 uc_vm_stack_push(vm, NULL); 2066 } 2067 2068 if (uc_vm_call(vm, true, i) == EXCEPTION_NONE) { 2069 rv = uc_vm_stack_pop(vm); 2070 2071 ucv_to_stringbuf(vm, resbuf, rv, false); 2072 2073 ucv_put(rv); 2074 } 2075 } 2076 2077 static void 2078 uc_replace_str(uc_vm_t *vm, uc_value_t *str, 2079 const char *subject, regmatch_t *pmatch, size_t plen, 2080 uc_stringbuf_t *resbuf) 2081 { 2082 bool esc = false; 2083 char *p, *r; 2084 uint8_t i; 2085 2086 for (p = r = ucv_to_string(vm, str); *p; p++) { 2087 if (esc) { 2088 switch (*p) { 2089 case '&': 2090 if (pmatch[0].rm_so != -1) 2091 ucv_stringbuf_addstr(resbuf, 2092 subject + pmatch[0].rm_so, 2093 pmatch[0].rm_eo - pmatch[0].rm_so); 2094 break; 2095 2096 case '`': 2097 if (pmatch[0].rm_so != -1) 2098 ucv_stringbuf_addstr(resbuf, subject, pmatch[0].rm_so); 2099 break; 2100 2101 case '\'': 2102 if (pmatch[0].rm_so != -1) 2103 ucv_stringbuf_addstr(resbuf, 2104 subject + pmatch[0].rm_eo, 2105 strlen(subject + pmatch[0].rm_eo)); 2106 break; 2107 2108 case '1': 2109 case '2': 2110 case '3': 2111 case '4': 2112 case '5': 2113 case '6': 2114 case '7': 2115 case '8': 2116 case '9': 2117 i = *p - ''; 2118 if (i < plen && pmatch[i].rm_so != -1) { 2119 ucv_stringbuf_addstr(resbuf, 2120 subject + pmatch[i].rm_so, 2121 pmatch[i].rm_eo - pmatch[i].rm_so); 2122 } 2123 else { 2124 ucv_stringbuf_append(resbuf, "$"); 2125 ucv_stringbuf_addstr(resbuf, p, 1); 2126 } 2127 break; 2128 2129 case '$': 2130 ucv_stringbuf_append(resbuf, "$"); 2131 break; 2132 2133 default: 2134 ucv_stringbuf_append(resbuf, "$"); 2135 ucv_stringbuf_addstr(resbuf, p, 1); 2136 } 2137 2138 esc = false; 2139 } 2140 else if (*p == '$') { 2141 esc = true; 2142 } 2143 else { 2144 ucv_stringbuf_addstr(resbuf, p, 1); 2145 } 2146 } 2147 2148 free(r); 2149 } 2150 2151 static uc_value_t * 2152 uc_replace(uc_vm_t *vm, size_t nargs) 2153 { 2154 char *sb = NULL, *pt = NULL, *p, *l; 2155 uc_value_t *subject = uc_fn_arg(0); 2156 uc_value_t *pattern = uc_fn_arg(1); 2157 uc_value_t *replace = uc_fn_arg(2); 2158 uc_value_t *limitval = uc_fn_arg(3); 2159 bool sb_freeable, pt_freeable; 2160 regmatch_t *pmatch = NULL; 2161 size_t pl, nmatch, limit; 2162 uc_regexp_t *re = NULL; 2163 uc_stringbuf_t *resbuf; 2164 int eflags = 0, res; 2165 2166 if (!pattern || !subject || !replace) 2167 return NULL; 2168 2169 nmatch = 1; 2170 2171 if (ucv_type(pattern) == UC_REGEXP) { 2172 re = (uc_regexp_t *)pattern; 2173 nmatch += re->regexp.re_nsub; 2174 } 2175 2176 pmatch = calloc(nmatch, sizeof(regmatch_t)); 2177 2178 if (!pmatch) 2179 return NULL; 2180 2181 sb = uc_cast_string(vm, &subject, &sb_freeable); 2182 resbuf = ucv_stringbuf_new(); 2183 limit = limitval ? ucv_uint64_get(limitval) : SIZE_MAX; 2184 2185 if (re) { 2186 p = sb; 2187 2188 while (limit > 0) { 2189 res = regexec(&re->regexp, p, nmatch, pmatch, eflags); 2190 2191 if (res == REG_NOMATCH) 2192 break; 2193 2194 ucv_stringbuf_addstr(resbuf, p, pmatch[0].rm_so); 2195 2196 if (ucv_is_callable(replace)) 2197 uc_replace_cb(vm, replace, p, pmatch, nmatch, resbuf); 2198 else 2199 uc_replace_str(vm, replace, p, pmatch, nmatch, resbuf); 2200 2201 if (pmatch[0].rm_so != pmatch[0].rm_eo) 2202 p += pmatch[0].rm_eo; 2203 else if (*p) 2204 ucv_stringbuf_addstr(resbuf, p++, 1); 2205 else 2206 break; 2207 2208 if (re->global) 2209 eflags |= REG_NOTBOL; 2210 else 2211 break; 2212 2213 limit--; 2214 } 2215 2216 ucv_stringbuf_addstr(resbuf, p, strlen(p)); 2217 } 2218 else { 2219 pt = uc_cast_string(vm, &pattern, &pt_freeable); 2220 pl = strlen(pt); 2221 2222 l = p = sb; 2223 2224 while (limit > 0) { 2225 if (pl == 0 || !strncmp(p, pt, pl)) { 2226 ucv_stringbuf_addstr(resbuf, l, p - l); 2227 2228 pmatch[0].rm_so = p - l; 2229 pmatch[0].rm_eo = pmatch[0].rm_so + pl; 2230 2231 if (ucv_is_callable(replace)) 2232 uc_replace_cb(vm, replace, l, pmatch, 1, resbuf); 2233 else 2234 uc_replace_str(vm, replace, l, pmatch, 1, resbuf); 2235 2236 if (pl) { 2237 l = p + pl; 2238 p += pl - 1; 2239 } 2240 else { 2241 l = p; 2242 } 2243 2244 limit--; 2245 } 2246 2247 if (!*p++) 2248 break; 2249 } 2250 2251 ucv_stringbuf_addstr(resbuf, l, strlen(l)); 2252 2253 if (pt_freeable) 2254 free(pt); 2255 } 2256 2257 free(pmatch); 2258 2259 if (sb_freeable) 2260 free(sb); 2261 2262 return ucv_stringbuf_finish(resbuf); 2263 } 2264 2265 static struct json_tokener * 2266 uc_json_from_object(uc_vm_t *vm, uc_value_t *obj, json_object **jso) 2267 { 2268 bool trail = false, eof = false; 2269 enum json_tokener_error err; 2270 struct json_tokener *tok; 2271 uc_value_t *rfn, *rbuf; 2272 uc_stringbuf_t *buf; 2273 2274 rfn = ucv_property_get(obj, "read"); 2275 2276 if (!ucv_is_callable(rfn)) { 2277 uc_vm_raise_exception(vm, EXCEPTION_TYPE, 2278 "Input object does not implement read() method"); 2279 2280 return NULL; 2281 } 2282 2283 tok = xjs_new_tokener(); 2284 2285 while (true) { 2286 uc_vm_stack_push(vm, ucv_get(obj)); 2287 uc_vm_stack_push(vm, ucv_get(rfn)); 2288 uc_vm_stack_push(vm, ucv_int64_new(1024)); 2289 2290 if (uc_vm_call(vm, true, 1) != EXCEPTION_NONE) { 2291 json_tokener_free(tok); 2292 2293 return NULL; 2294 } 2295 2296 rbuf = uc_vm_stack_pop(vm); 2297 2298 /* check EOF */ 2299 eof = (rbuf == NULL || (ucv_type(rbuf) == UC_STRING && ucv_string_length(rbuf) == 0)); 2300 2301 /* on EOF, stop parsing unless trailing garbage was detected which handled below */ 2302 if (eof && !trail) { 2303 ucv_put(rbuf); 2304 2305 /* Didn't parse a complete object yet, possibly a non-delimitted atomic value 2306 such as `null`, `true` etc. - nudge parser by sending final zero byte. 2307 See json-c issue #681 <https://github.com/json-c/json-c/issues/681> */ 2308 if (json_tokener_get_error(tok) == json_tokener_continue) 2309 *jso = json_tokener_parse_ex(tok, "\0", 1); 2310 2311 break; 2312 } 2313 2314 if (trail || *jso) { 2315 uc_vm_raise_exception(vm, EXCEPTION_SYNTAX, 2316 "Trailing garbage after JSON data"); 2317 2318 json_tokener_free(tok); 2319 ucv_put(rbuf); 2320 2321 return NULL; 2322 } 2323 2324 if (ucv_type(rbuf) != UC_STRING) { 2325 buf = xprintbuf_new(); 2326 ucv_to_stringbuf_formatted(vm, buf, rbuf, 0, '\0', 0); 2327 2328 *jso = json_tokener_parse_ex(tok, buf->buf, printbuf_length(buf)); 2329 2330 trail = (json_tokener_get_error(tok) == json_tokener_success && 2331 json_tokener_get_parse_end(tok) < (size_t)printbuf_length(buf)); 2332 2333 printbuf_free(buf); 2334 } 2335 else { 2336 *jso = json_tokener_parse_ex(tok, ucv_string_get(rbuf), ucv_string_length(rbuf)); 2337 2338 trail = (json_tokener_get_error(tok) == json_tokener_success && 2339 json_tokener_get_parse_end(tok) < ucv_string_length(rbuf)); 2340 } 2341 2342 ucv_put(rbuf); 2343 2344 err = json_tokener_get_error(tok); 2345 2346 if (err != json_tokener_success && err != json_tokener_continue) 2347 break; 2348 } 2349 2350 return tok; 2351 } 2352 2353 static struct json_tokener * 2354 uc_json_from_string(uc_vm_t *vm, uc_value_t *str, json_object **jso) 2355 { 2356 struct json_tokener *tok = xjs_new_tokener(); 2357 size_t i; 2358 char *p; 2359 2360 /* NB: the len + 1 here is intentional to pass the terminating \0 byte 2361 * to the json-c parser. This is required to work-around upstream 2362 * issue #681 <https://github.com/json-c/json-c/issues/681> */ 2363 *jso = json_tokener_parse_ex(tok, ucv_string_get(str), ucv_string_length(str) + 1); 2364 2365 if (json_tokener_get_error(tok) == json_tokener_success) { 2366 p = ucv_string_get(str); 2367 2368 for (i = json_tokener_get_parse_end(tok); i < ucv_string_length(str); i++) { 2369 if (!isspace(p[i])) { 2370 uc_vm_raise_exception(vm, EXCEPTION_SYNTAX, 2371 "Trailing garbage after JSON data"); 2372 2373 2374 json_tokener_free(tok); 2375 2376 return NULL; 2377 } 2378 } 2379 } 2380 2381 return tok; 2382 } 2383 2384 static uc_value_t * 2385 uc_json(uc_vm_t *vm, size_t nargs) 2386 { 2387 uc_value_t *rv = NULL, *src = uc_fn_arg(0); 2388 struct json_tokener *tok = NULL; 2389 enum json_tokener_error err; 2390 json_object *jso = NULL; 2391 2392 switch (ucv_type(src)) { 2393 case UC_STRING: 2394 tok = uc_json_from_string(vm, src, &jso); 2395 break; 2396 2397 case UC_RESOURCE: 2398 case UC_OBJECT: 2399 case UC_ARRAY: 2400 tok = uc_json_from_object(vm, src, &jso); 2401 break; 2402 2403 default: 2404 uc_vm_raise_exception(vm, EXCEPTION_TYPE, 2405 "Passed value is neither a string nor an object"); 2406 } 2407 2408 if (!tok) 2409 goto out; 2410 2411 err = json_tokener_get_error(tok); 2412 2413 if (err == json_tokener_continue) { 2414 uc_vm_raise_exception(vm, EXCEPTION_SYNTAX, 2415 "Unexpected end of string in JSON data"); 2416 2417 goto out; 2418 } 2419 else if (err != json_tokener_success) { 2420 uc_vm_raise_exception(vm, EXCEPTION_SYNTAX, 2421 "Failed to parse JSON string: %s", 2422 json_tokener_error_desc(err)); 2423 2424 goto out; 2425 } 2426 2427 rv = ucv_from_json(vm, jso); 2428 2429 out: 2430 if (tok) 2431 json_tokener_free(tok); 2432 2433 json_object_put(jso); 2434 2435 return rv; 2436 } 2437 2438 static char * 2439 include_path(const char *curpath, const char *incpath) 2440 { 2441 char *dup, *res; 2442 int len; 2443 2444 if (*incpath == '/') 2445 return realpath(incpath, NULL); 2446 2447 dup = curpath ? strrchr(curpath, '/') : NULL; 2448 2449 if (dup) 2450 len = asprintf(&res, "%.*s/%s", (int)(dup - curpath), curpath, incpath); 2451 else 2452 len = asprintf(&res, "./%s", incpath); 2453 2454 if (len == -1) 2455 return NULL; 2456 2457 dup = realpath(res, NULL); 2458 2459 free(res); 2460 2461 return dup; 2462 } 2463 2464 static uc_value_t * 2465 uc_include_common(uc_vm_t *vm, size_t nargs, bool raw_mode) 2466 { 2467 uc_value_t *path = uc_fn_arg(0); 2468 uc_value_t *scope = uc_fn_arg(1); 2469 uc_value_t *rv = NULL, *sc = NULL; 2470 uc_closure_t *closure = NULL; 2471 size_t i; 2472 char *p; 2473 2474 if (ucv_type(path) != UC_STRING) { 2475 uc_vm_raise_exception(vm, EXCEPTION_TYPE, 2476 "Passed filename is not a string"); 2477 2478 return NULL; 2479 } 2480 2481 if (scope && ucv_type(scope) != UC_OBJECT) { 2482 uc_vm_raise_exception(vm, EXCEPTION_TYPE, 2483 "Passed scope value is not an object"); 2484 2485 return NULL; 2486 } 2487 2488 /* find calling closure */ 2489 for (i = vm->callframes.count; i > 0; i--) { 2490 closure = vm->callframes.entries[i - 1].closure; 2491 2492 if (closure) 2493 break; 2494 } 2495 2496 if (!closure) 2497 return NULL; 2498 2499 p = include_path(uc_program_function_source(closure->function)->runpath, ucv_string_get(path)); 2500 2501 if (!p) { 2502 uc_vm_raise_exception(vm, EXCEPTION_RUNTIME, 2503 "Include file not found"); 2504 2505 return NULL; 2506 } 2507 2508 if (ucv_prototype_get(scope)) { 2509 sc = ucv_get(scope); 2510 } 2511 else if (scope) { 2512 sc = ucv_object_new(vm); 2513 2514 ucv_object_foreach(scope, key, val) 2515 ucv_object_add(sc, key, ucv_get(val)); 2516 2517 ucv_prototype_set(sc, ucv_get(uc_vm_scope_get(vm))); 2518 } 2519 else { 2520 sc = ucv_get(uc_vm_scope_get(vm)); 2521 } 2522 2523 if (uc_require_ucode(vm, p, sc, &rv, raw_mode)) 2524 ucv_put(rv); 2525 2526 ucv_put(sc); 2527 free(p); 2528 2529 return NULL; 2530 } 2531 2532 static uc_value_t * 2533 uc_include(uc_vm_t *vm, size_t nargs) 2534 { 2535 return uc_include_common(vm, nargs, vm->config && vm->config->raw_mode); 2536 } 2537 2538 static uc_value_t * 2539 uc_render(uc_vm_t *vm, size_t nargs) 2540 { 2541 uc_string_t hdr = { .header = { .type = UC_STRING, .refcount = 1 } }; 2542 uc_string_t *ustr = NULL; 2543 FILE *mem, *prev; 2544 size_t len = 0; 2545 2546 mem = open_memstream((char **)&ustr, &len); 2547 2548 if (!mem) 2549 goto out; 2550 2551 /* reserve space for uc_string_t header... */ 2552 if (fwrite(&hdr, 1, sizeof(hdr), mem) != sizeof(hdr)) 2553 goto out; 2554 2555 /* divert VM output to memory fd */ 2556 prev = vm->output; 2557 vm->output = mem; 2558 2559 /* execute function */ 2560 if (ucv_is_callable(uc_fn_arg(0))) 2561 (void) uc_vm_call(vm, false, nargs - 1); 2562 2563 /* execute include */ 2564 else 2565 (void) uc_include_common(vm, nargs, false); 2566 2567 /* restore previous VM output */ 2568 vm->output = prev; 2569 fclose(mem); 2570 2571 /* update uc_string_t length */ 2572 ustr->length = len - sizeof(*ustr); 2573 2574 return &ustr->header; 2575 2576 out: 2577 uc_vm_raise_exception(vm, EXCEPTION_RUNTIME, 2578 "Unable to initialize output memory: %s", 2579 strerror(errno)); 2580 2581 if (mem) 2582 fclose(mem); 2583 2584 free(ustr); 2585 2586 return NULL; 2587 } 2588 2589 static uc_value_t * 2590 uc_warn(uc_vm_t *vm, size_t nargs) 2591 { 2592 return uc_print_common(vm, nargs, stderr); 2593 } 2594 2595 #ifdef __APPLE__ 2596 /* 2597 * sigtimedwait() implementation based on 2598 * https://comp.unix.programmer.narkive.com/rEDH0sPT/sigtimedwait-implementation 2599 * and 2600 * https://github.com/wahern/lunix/blob/master/src/unix.c 2601 */ 2602 static void 2603 sigtimedwait_consume_signal(int signo) 2604 { 2605 } 2606 2607 static int 2608 sigtimedwait(const sigset_t *set, siginfo_t *info, const struct timespec *timeout) 2609 { 2610 struct timespec elapsed = { 0, 0 }, sleep, rem; 2611 sigset_t pending, unblock, omask; 2612 struct sigaction sa, osa; 2613 int signo; 2614 bool lt; 2615 2616 while (true) { 2617 sigemptyset(&pending); 2618 sigpending(&pending); 2619 2620 for (signo = 1; signo < NSIG; signo++) { 2621 if (!sigismember(set, signo) || !sigismember(&pending, signo)) 2622 continue; 2623 2624 sa.sa_handler = sigtimedwait_consume_signal; 2625 sa.sa_flags = 0; 2626 sigfillset(&sa.sa_mask); 2627 2628 sigaction(signo, &sa, &osa); 2629 2630 sigemptyset(&unblock); 2631 sigaddset(&unblock, signo); 2632 sigprocmask(SIG_UNBLOCK, &unblock, &omask); 2633 sigprocmask(SIG_SETMASK, &omask, NULL); 2634 2635 sigaction(signo, &osa, NULL); 2636 2637 if (info) { 2638 memset(info, 0, sizeof(*info)); 2639 info->si_signo = signo; 2640 } 2641 2642 return signo; 2643 } 2644 2645 sleep.tv_sec = 0; 2646 sleep.tv_nsec = 200000000L; /* 2/10th second */ 2647 rem = sleep; 2648 2649 if (nanosleep(&sleep, &rem) == 0) { 2650 elapsed.tv_sec += sleep.tv_sec; 2651 elapsed.tv_nsec += sleep.tv_nsec; 2652 2653 if (elapsed.tv_nsec > 1000000000) { 2654 elapsed.tv_sec++; 2655 elapsed.tv_nsec -= 1000000000; 2656 } 2657 } 2658 else if (errno == EINTR) { 2659 sleep.tv_sec -= rem.tv_sec; 2660 sleep.tv_nsec -= rem.tv_nsec; 2661 2662 if (sleep.tv_nsec < 0) { 2663 sleep.tv_sec--; 2664 sleep.tv_nsec += 1000000000; 2665 } 2666 2667 elapsed.tv_sec += sleep.tv_sec; 2668 elapsed.tv_nsec += sleep.tv_nsec; 2669 2670 if (elapsed.tv_nsec > 1000000000) { 2671 elapsed.tv_sec++; 2672 elapsed.tv_nsec -= 1000000000; 2673 } 2674 } 2675 else { 2676 return errno; 2677 } 2678 2679 lt = timeout 2680 ? ((elapsed.tv_sec == timeout->tv_sec) 2681 ? (elapsed.tv_nsec < timeout->tv_nsec) 2682 : (elapsed.tv_sec < timeout->tv_sec)) 2683 : true; 2684 2685 if (!lt) 2686 break; 2687 } 2688 2689 errno = EAGAIN; 2690 2691 return -1; 2692 } 2693 2694 #endif 2695 2696 static uc_value_t * 2697 uc_system(uc_vm_t *vm, size_t nargs) 2698 { 2699 uc_value_t *cmdline = uc_fn_arg(0); 2700 uc_value_t *timeout = uc_fn_arg(1); 2701 const char **arglist, *fn; 2702 sigset_t sigmask, sigomask; 2703 struct timespec ts; 2704 size_t i, len; 2705 int64_t tms; 2706 pid_t cld; 2707 int rc; 2708 2709 if (timeout && (ucv_type(timeout) != UC_INTEGER || ucv_int64_get(timeout) < 0)) { 2710 uc_vm_raise_exception(vm, EXCEPTION_TYPE, 2711 "Invalid timeout specified"); 2712 2713 return NULL; 2714 } 2715 2716 switch (ucv_type(cmdline)) { 2717 case UC_STRING: 2718 arglist = xalloc(sizeof(*arglist) * 4); 2719 arglist[0] = xstrdup("/bin/sh"); 2720 arglist[1] = xstrdup("-c"); 2721 arglist[2] = ucv_to_string(vm, cmdline); 2722 arglist[3] = NULL; 2723 break; 2724 2725 case UC_ARRAY: 2726 len = ucv_array_length(cmdline); 2727 2728 if (len == 0) { 2729 uc_vm_raise_exception(vm, EXCEPTION_TYPE, 2730 "Passed command array is empty"); 2731 2732 return NULL; 2733 } 2734 2735 arglist = xalloc(sizeof(*arglist) * (len + 1)); 2736 2737 for (i = 0; i < len; i++) 2738 arglist[i] = ucv_to_string(vm, ucv_array_get(cmdline, i)); 2739 2740 arglist[i] = NULL; 2741 2742 break; 2743 2744 default: 2745 uc_vm_raise_exception(vm, EXCEPTION_TYPE, 2746 "Passed command is neither string nor array"); 2747 2748 return NULL; 2749 } 2750 2751 tms = timeout ? ucv_int64_get(timeout) : 0; 2752 2753 if (tms > 0) { 2754 sigemptyset(&sigmask); 2755 sigaddset(&sigmask, SIGCHLD); 2756 2757 if (sigprocmask(SIG_BLOCK, &sigmask, &sigomask) < 0) { 2758 fn = "sigprocmask"; 2759 goto fail; 2760 } 2761 } 2762 2763 cld = fork(); 2764 2765 switch (cld) { 2766 case -1: 2767 fn = "fork"; 2768 goto fail; 2769 2770 case 0: 2771 execvp(arglist[0], (char * const *)arglist); 2772 exit(-1); 2773 2774 break; 2775 2776 default: 2777 if (tms > 0) { 2778 ts.tv_sec = tms / 1000; 2779 ts.tv_nsec = (tms % 1000) * 1000000; 2780 2781 while (1) { 2782 if (sigtimedwait(&sigmask, NULL, &ts) < 0) { 2783 if (errno == EINTR) 2784 continue; 2785 2786 if (errno != EAGAIN) { 2787 fn = "sigtimedwait"; 2788 goto fail; 2789 } 2790 2791 kill(cld, SIGKILL); 2792 } 2793 2794 break; 2795 } 2796 } 2797 2798 while (waitpid(cld, &rc, 0) < 0) { 2799 if (errno == EINTR) 2800 continue; 2801 2802 fn = "waitpid"; 2803 goto fail; 2804 } 2805 2806 if (tms > 0) 2807 sigprocmask(SIG_SETMASK, &sigomask, NULL); 2808 2809 for (i = 0; arglist[i]; i++) 2810 free((char *)arglist[i]); 2811 2812 free(arglist); 2813 2814 if (WIFEXITED(rc)) 2815 return ucv_int64_new(WEXITSTATUS(rc)); 2816 else if (WIFSIGNALED(rc)) 2817 return ucv_int64_new(-WTERMSIG(rc)); 2818 else if (WIFSTOPPED(rc)) 2819 return ucv_int64_new(-WSTOPSIG(rc)); 2820 2821 return NULL; 2822 } 2823 2824 fail: 2825 if (tms > 0) 2826 sigprocmask(SIG_SETMASK, &sigomask, NULL); 2827 2828 for (i = 0; arglist[i]; i++) 2829 free((char *)arglist[i]); 2830 2831 free(arglist); 2832 2833 uc_vm_raise_exception(vm, EXCEPTION_RUNTIME, 2834 "%s(): %s", fn, strerror(errno)); 2835 2836 return NULL; 2837 } 2838 2839 static uc_value_t * 2840 uc_trace(uc_vm_t *vm, size_t nargs) 2841 { 2842 uc_value_t *level = uc_fn_arg(0); 2843 uint8_t prev_level; 2844 2845 if (ucv_type(level) != UC_INTEGER) { 2846 uc_vm_raise_exception(vm, EXCEPTION_TYPE, "Invalid level specified"); 2847 2848 return NULL; 2849 } 2850 2851 prev_level = vm->trace; 2852 vm->trace = ucv_int64_get(level); 2853 2854 return ucv_int64_new(prev_level); 2855 } 2856 2857 static uc_value_t * 2858 uc_proto(uc_vm_t *vm, size_t nargs) 2859 { 2860 uc_value_t *val = uc_fn_arg(0); 2861 uc_value_t *proto = NULL; 2862 2863 if (nargs < 2) 2864 return ucv_get(ucv_prototype_get(val)); 2865 2866 proto = uc_fn_arg(1); 2867 2868 if (!ucv_prototype_set(val, proto)) 2869 uc_vm_raise_exception(vm, EXCEPTION_TYPE, "Passed value is neither a prototype, resource or object"); 2870 2871 ucv_get(proto); 2872 2873 return ucv_get(val); 2874 } 2875 2876 static uc_value_t * 2877 uc_sleep(uc_vm_t *vm, size_t nargs) 2878 { 2879 uc_value_t *duration = uc_fn_arg(0); 2880 struct timeval tv; 2881 int64_t ms; 2882 2883 ms = ucv_to_integer(duration); 2884 2885 if (errno != 0 || ms <= 0) 2886 return ucv_boolean_new(false); 2887 2888 tv.tv_sec = ms / 1000; 2889 tv.tv_usec = (ms % 1000) * 1000; 2890 2891 select(0, NULL, NULL, NULL, &tv); 2892 2893 return ucv_boolean_new(true); 2894 } 2895 2896 static uc_value_t * 2897 uc_assert(uc_vm_t *vm, size_t nargs) 2898 { 2899 uc_value_t *cond = uc_fn_arg(0); 2900 uc_value_t *msg = uc_fn_arg(1); 2901 bool freeable = false; 2902 char *s; 2903 2904 if (!ucv_is_truish(cond)) { 2905 s = msg ? uc_cast_string(vm, &msg, &freeable) : "Assertion failed"; 2906 2907 uc_vm_raise_exception(vm, EXCEPTION_USER, "%s", s); 2908 2909 if (freeable) 2910 free(s); 2911 2912 return NULL; 2913 } 2914 2915 return ucv_get(cond); 2916 } 2917 2918 static uc_value_t * 2919 uc_regexp(uc_vm_t *vm, size_t nargs) 2920 { 2921 bool icase = false, newline = false, global = false, freeable; 2922 uc_value_t *source = uc_fn_arg(0); 2923 uc_value_t *flags = uc_fn_arg(1); 2924 uc_value_t *regex = NULL; 2925 char *p, *err = NULL; 2926 2927 if (flags) { 2928 if (ucv_type(flags) != UC_STRING) { 2929 uc_vm_raise_exception(vm, EXCEPTION_TYPE, "Given flags argument is not a string"); 2930 2931 return NULL; 2932 } 2933 2934 for (p = ucv_string_get(flags); *p; p++) { 2935 switch (*p) { 2936 case 'i': 2937 icase = true; 2938 break; 2939 2940 case 's': 2941 newline = true; 2942 break; 2943 2944 case 'g': 2945 global = true; 2946 break; 2947 2948 default: 2949 uc_vm_raise_exception(vm, EXCEPTION_TYPE, "Unrecognized flag character '%c'", *p); 2950 2951 return NULL; 2952 } 2953 } 2954 } 2955 2956 p = uc_cast_string(vm, &source, &freeable); 2957 regex = ucv_regexp_new(p, icase, newline, global, &err); 2958 2959 if (freeable) 2960 free(p); 2961 2962 if (err) { 2963 uc_vm_raise_exception(vm, EXCEPTION_SYNTAX, "%s", err); 2964 ucv_put(regex); 2965 free(err); 2966 2967 return NULL; 2968 } 2969 2970 return regex; 2971 } 2972 2973 static uc_value_t * 2974 uc_wildcard(uc_vm_t *vm, size_t nargs) 2975 { 2976 uc_value_t *subject = uc_fn_arg(0); 2977 uc_value_t *pattern = uc_fn_arg(1); 2978 uc_value_t *icase = uc_fn_arg(2); 2979 int flags = 0, rv; 2980 bool freeable; 2981 char *s; 2982 2983 if (!subject || ucv_type(pattern) != UC_STRING) 2984 return NULL; 2985 2986 if (ucv_is_truish(icase)) 2987 flags |= FNM_CASEFOLD; 2988 2989 s = uc_cast_string(vm, &subject, &freeable); 2990 rv = fnmatch(ucv_string_get(pattern), s, flags); 2991 2992 if (freeable) 2993 free(s); 2994 2995 return ucv_boolean_new(rv == 0); 2996 } 2997 2998 static uc_value_t * 2999 uc_sourcepath(uc_vm_t *vm, size_t nargs) 3000 { 3001 uc_value_t *calldepth = uc_fn_arg(0); 3002 uc_value_t *dironly = uc_fn_arg(1); 3003 uc_value_t *rv = NULL; 3004 uc_callframe_t *frame; 3005 char *path = NULL; 3006 int64_t depth; 3007 size_t i; 3008 3009 depth = ucv_to_integer(calldepth); 3010 3011 if (errno) 3012 depth = 0; 3013 3014 for (i = vm->callframes.count; i > 0; i--) { 3015 frame = &vm->callframes.entries[i - 1]; 3016 3017 if (!frame->closure) 3018 continue; 3019 3020 if (depth > 0) { 3021 depth--; 3022 continue; 3023 } 3024 3025 path = realpath(uc_program_function_source(frame->closure->function)->runpath, NULL); 3026 break; 3027 } 3028 3029 if (path) { 3030 if (ucv_is_truish(dironly)) 3031 rv = ucv_string_new(dirname(path)); 3032 else 3033 rv = ucv_string_new(path); 3034 3035 free(path); 3036 } 3037 3038 return rv; 3039 } 3040 3041 static uc_value_t * 3042 uc_min_max(uc_vm_t *vm, size_t nargs, int cmp) 3043 { 3044 uc_value_t *rv = NULL, *val; 3045 bool set = false; 3046 size_t i; 3047 3048 for (i = 0; i < nargs; i++) { 3049 val = uc_fn_arg(i); 3050 3051 if (!set || ucv_compare(cmp, val, rv, NULL)) { 3052 set = true; 3053 rv = val; 3054 } 3055 } 3056 3057 return ucv_get(rv); 3058 } 3059 3060 static uc_value_t * 3061 uc_min(uc_vm_t *vm, size_t nargs) 3062 { 3063 return uc_min_max(vm, nargs, I_LT); 3064 } 3065 3066 static uc_value_t * 3067 uc_max(uc_vm_t *vm, size_t nargs) 3068 { 3069 return uc_min_max(vm, nargs, I_GT); 3070 } 3071 3072 3073 /* ------------------------------------------------------------------------- 3074 * The following base64 encoding and decoding routines are taken from 3075 * https://git.openwrt.org/?p=project/libubox.git;a=blob;f=base64.c 3076 * and modified for use in ucode. 3077 * 3078 * Original copyright and license statements below. 3079 */ 3080 3081 /* 3082 * base64 - libubox base64 functions 3083 * 3084 * Copyright (C) 2015 Felix Fietkau <nbd@openwrt.org> 3085 * 3086 * Permission to use, copy, modify, and/or distribute this software for any 3087 * purpose with or without fee is hereby granted, provided that the above 3088 * copyright notice and this permission notice appear in all copies. 3089 * 3090 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 3091 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 3092 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 3093 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 3094 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 3095 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 3096 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 3097 */ 3098 3099 /* $OpenBSD: base64.c,v 1.7 2013/12/31 02:32:56 tedu Exp $ */ 3100 3101 /* 3102 * Copyright (c) 1996 by Internet Software Consortium. 3103 * 3104 * Permission to use, copy, modify, and distribute this software for any 3105 * purpose with or without fee is hereby granted, provided that the above 3106 * copyright notice and this permission notice appear in all copies. 3107 * 3108 * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS 3109 * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES 3110 * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE 3111 * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL 3112 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR 3113 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS 3114 * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS 3115 * SOFTWARE. 3116 */ 3117 3118 /* 3119 * Portions Copyright (c) 1995 by International Business Machines, Inc. 3120 * 3121 * International Business Machines, Inc. (hereinafter called IBM) grants 3122 * permission under its copyrights to use, copy, modify, and distribute this 3123 * Software with or without fee, provided that the above copyright notice and 3124 * all paragraphs of this notice appear in all copies, and that the name of IBM 3125 * not be used in connection with the marketing of any product incorporating 3126 * the Software or modifications thereof, without specific, written prior 3127 * permission. 3128 * 3129 * To the extent it has a right to do so, IBM grants an immunity from suit 3130 * under its patents, if any, for the use, sale or manufacture of products to 3131 * the extent that such products are used for performing Domain Name System 3132 * dynamic updates in TCP/IP networks by means of the Software. No immunity is 3133 * granted for any product per se or for any other function of any product. 3134 * 3135 * THE SOFTWARE IS PROVIDED "AS IS", AND IBM DISCLAIMS ALL WARRANTIES, 3136 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 3137 * PARTICULAR PURPOSE. IN NO EVENT SHALL IBM BE LIABLE FOR ANY SPECIAL, 3138 * DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER ARISING 3139 * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE, EVEN 3140 * IF IBM IS APPRISED OF THE POSSIBILITY OF SUCH DAMAGES. 3141 */ 3142 3143 /* skips all whitespace anywhere. 3144 converts characters, four at a time, starting at (or after) 3145 src from base - 64 numbers into three 8 bit bytes in the target area. 3146 it returns the number of data bytes stored at the target, or -1 on error. 3147 */ 3148 3149 static uc_value_t * 3150 uc_b64dec(uc_vm_t *vm, size_t nargs) 3151 { 3152 enum { BYTE1, BYTE2, BYTE3, BYTE4 } state; 3153 uc_value_t *str = uc_fn_arg(0); 3154 uc_stringbuf_t *buf; 3155 const char *src; 3156 unsigned int ch; 3157 uint8_t val; 3158 size_t off; 3159 3160 if (ucv_type(str) != UC_STRING) 3161 return NULL; 3162 3163 buf = ucv_stringbuf_new(); 3164 src = ucv_string_get(str); 3165 off = printbuf_length(buf); 3166 3167 state = BYTE1; 3168 3169 /* memset the last expected output char to pre-grow the output buffer */ 3170 printbuf_memset(buf, off + (ucv_string_length(str) / 4) * 3, 0, 1); 3171 3172 while ((ch = (unsigned char)*src++) != '\0') { 3173 if (isspace(ch)) /* Skip whitespace anywhere. */ 3174 continue; 3175 3176 if (ch == '=') 3177 break; 3178 3179 if (ch >= 'A' && ch <= 'Z') 3180 val = ch - 'A'; 3181 else if (ch >= 'a' && ch <= 'z') 3182 val = ch - 'a' + 26; 3183 else if (ch >= '' && ch <= '9') 3184 val = ch - '' + 52; 3185 else if (ch == '+') 3186 val = 62; 3187 else if (ch == '/') 3188 val = 63; 3189 else 3190 goto err; 3191 3192 switch (state) { 3193 case BYTE1: 3194 buf->buf[off] = val << 2; 3195 state = BYTE2; 3196 break; 3197 3198 case BYTE2: 3199 buf->buf[off++] |= val >> 4; 3200 buf->buf[off] = (val & 0x0f) << 4; 3201 state = BYTE3; 3202 break; 3203 3204 case BYTE3: 3205 buf->buf[off++] |= val >> 2; 3206 buf->buf[off] = (val & 0x03) << 6; 3207 state = BYTE4; 3208 break; 3209 3210 case BYTE4: 3211 buf->buf[off++] |= val; 3212 state = BYTE1; 3213 break; 3214 } 3215 } 3216 3217 /* 3218 * We are done decoding Base-64 chars. Let's see if we ended 3219 * on a byte boundary, and/or with erroneous trailing characters. 3220 */ 3221 3222 if (ch == '=') { /* We got a pad char. */ 3223 ch = (unsigned char)*src++; /* Skip it, get next. */ 3224 switch (state) { 3225 case BYTE1: /* Invalid = in first position */ 3226 case BYTE2: /* Invalid = in second position */ 3227 goto err; 3228 3229 case BYTE3: /* Valid, means one byte of info */ 3230 /* Skip any number of spaces. */ 3231 for (; ch != '\0'; ch = (unsigned char)*src++) 3232 if (!isspace(ch)) 3233 break; 3234 /* Make sure there is another trailing = sign. */ 3235 if (ch != '=') 3236 goto err; 3237 ch = (unsigned char)*src++; /* Skip the = */ 3238 /* Fall through to "single trailing =" case. */ 3239 /* FALLTHROUGH */ 3240 3241 case BYTE4: /* Valid, means two bytes of info */ 3242 /* 3243 * We know this char is an =. Is there anything but 3244 * whitespace after it? 3245 */ 3246 for (; ch != '\0'; ch = (unsigned char)*src++) 3247 if (!isspace(ch)) 3248 goto err; 3249 3250 /* 3251 * Now make sure for cases BYTE3 and BYTE4 that the "extra" 3252 * bits that slopped past the last full byte were 3253 * zeros. If we don't check them, they become a 3254 * subliminal channel. 3255 */ 3256 if (buf->buf[off] != 0) 3257 goto err; 3258 } 3259 } else { 3260 /* 3261 * We ended by seeing the end of the string. Make sure we 3262 * have no partial bytes lying around. 3263 */ 3264 if (state != BYTE1) 3265 goto err; 3266 } 3267 3268 /* Truncate buffer length to actual output length */ 3269 buf->bpos = off; 3270 3271 return ucv_stringbuf_finish(buf); 3272 3273 err: 3274 printbuf_free(buf); 3275 3276 return NULL; 3277 } 3278 3279 static const char Base64[] = 3280 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; 3281 3282 static uc_value_t * 3283 uc_b64enc(uc_vm_t *vm, size_t nargs) 3284 { 3285 uc_value_t *str = uc_fn_arg(0); 3286 unsigned char input[3] = {0}; 3287 uc_stringbuf_t *buf; 3288 const char *src; 3289 char output[4]; 3290 size_t len, i; 3291 3292 if (ucv_type(str) != UC_STRING) 3293 return NULL; 3294 3295 buf = ucv_stringbuf_new(); 3296 src = ucv_string_get(str); 3297 len = ucv_string_length(str); 3298 3299 while (2 < len) { 3300 input[0] = (unsigned char)*src++; 3301 input[1] = (unsigned char)*src++; 3302 input[2] = (unsigned char)*src++; 3303 len -= 3; 3304 3305 output[0] = Base64[input[0] >> 2]; 3306 output[1] = Base64[((input[0] & 0x03) << 4) + (input[1] >> 4)]; 3307 output[2] = Base64[((input[1] & 0x0f) << 2) + (input[2] >> 6)]; 3308 output[3] = Base64[input[2] & 0x3f]; 3309 3310 ucv_stringbuf_addstr(buf, output, sizeof(output)); 3311 } 3312 3313 /* Now we worry about padding. */ 3314 if (0 != len) { 3315 /* Get what's left. */ 3316 input[0] = input[1] = input[2] = '\0'; 3317 for (i = 0; i < len; i++) 3318 input[i] = *src++; 3319 3320 output[0] = Base64[input[0] >> 2]; 3321 output[1] = Base64[((input[0] & 0x03) << 4) + (input[1] >> 4)]; 3322 output[2] = (len == 1) ? '=' : Base64[((input[1] & 0x0f) << 2) + (input[2] >> 6)]; 3323 output[3] = '='; 3324 3325 ucv_stringbuf_addstr(buf, output, sizeof(output)); 3326 } 3327 3328 return ucv_stringbuf_finish(buf); 3329 } 3330 3331 /* End of base64 code. 3332 * ------------------------------------------------------------------------- 3333 */ 3334 3335 static unsigned long 3336 uc_uniq_ucv_hash(const void *k) 3337 { 3338 union { double d; int64_t i; uint64_t u; } conv; 3339 uc_value_t *uv = (uc_value_t *)k; 3340 unsigned int h; 3341 uint8_t *u8; 3342 size_t len; 3343 3344 h = ucv_type(uv); 3345 3346 switch (h) { 3347 case UC_STRING: 3348 u8 = (uint8_t *)ucv_string_get(uv); 3349 len = ucv_string_length(uv); 3350 break; 3351 3352 case UC_INTEGER: 3353 conv.i = ucv_int64_get(uv); 3354 3355 if (errno == ERANGE) { 3356 h *= 2; 3357 conv.u = ucv_uint64_get(uv); 3358 } 3359 3360 u8 = (uint8_t *)&conv.u; 3361 len = sizeof(conv.u); 3362 break; 3363 3364 case UC_DOUBLE: 3365 conv.d = ucv_double_get(uv); 3366 3367 u8 = (uint8_t *)&conv.u; 3368 len = sizeof(conv.u); 3369 break; 3370 3371 default: 3372 u8 = (uint8_t *)&uv; 3373 len = sizeof(uv); 3374 break; 3375 } 3376 3377 while (len > 0) { 3378 h = h * 129 + (*u8++) + LH_PRIME; 3379 len--; 3380 } 3381 3382 return h; 3383 } 3384 3385 static int 3386 uc_uniq_ucv_equal(const void *k1, const void *k2) 3387 { 3388 uc_value_t *uv1 = (uc_value_t *)k1; 3389 uc_value_t *uv2 = (uc_value_t *)k2; 3390 3391 if (!ucv_is_scalar(uv1) && !ucv_is_scalar(uv2)) 3392 return (uv1 == uv2); 3393 3394 /* for the sake of array item uniqueness, treat two NaNs as equal */ 3395 if (ucv_type(uv1) == UC_DOUBLE && ucv_type(uv2) == UC_DOUBLE && 3396 isnan(ucv_double_get(uv1)) && isnan(ucv_double_get(uv2))) 3397 return true; 3398 3399 return ucv_is_equal(uv1, uv2); 3400 } 3401 3402 static uc_value_t * 3403 uc_uniq(uc_vm_t *vm, size_t nargs) 3404 { 3405 uc_value_t *list = uc_fn_arg(0); 3406 uc_value_t *uniq = NULL; 3407 struct lh_table *seen; 3408 unsigned long hash; 3409 uc_value_t *item; 3410 size_t i, len; 3411 3412 if (ucv_type(list) != UC_ARRAY) 3413 return NULL; 3414 3415 seen = lh_table_new(16, NULL, uc_uniq_ucv_hash, uc_uniq_ucv_equal); 3416 uniq = ucv_array_new(vm); 3417 3418 assert(seen && uniq); 3419 3420 for (i = 0, len = ucv_array_length(list); i < len; i++) { 3421 item = ucv_array_get(list, i); 3422 hash = lh_get_hash(seen, item); 3423 3424 if (!lh_table_lookup_entry_w_hash(seen, item, hash)) { 3425 lh_table_insert_w_hash(seen, item, NULL, hash, 0); 3426 ucv_array_push(uniq, ucv_get(item)); 3427 } 3428 } 3429 3430 lh_table_free(seen); 3431 3432 return uniq; 3433 } 3434 3435 static uc_value_t * 3436 uc_gettime_common(uc_vm_t *vm, size_t nargs, bool local) 3437 { 3438 uc_value_t *ts = uc_fn_arg(0), *res; 3439 time_t t = ts ? (time_t)ucv_to_integer(ts) : time(NULL); 3440 struct tm *tm = (local ? localtime : gmtime)(&t); 3441 3442 if (!tm) 3443 return NULL; 3444 3445 res = ucv_object_new(vm); 3446 3447 ucv_object_add(res, "sec", ucv_int64_new(tm->tm_sec)); 3448 ucv_object_add(res, "min", ucv_int64_new(tm->tm_min)); 3449 ucv_object_add(res, "hour", ucv_int64_new(tm->tm_hour)); 3450 ucv_object_add(res, "mday", ucv_int64_new(tm->tm_mday)); 3451 ucv_object_add(res, "mon", ucv_int64_new(tm->tm_mon + 1)); 3452 ucv_object_add(res, "year", ucv_int64_new(tm->tm_year + 1900)); 3453 ucv_object_add(res, "wday", ucv_int64_new(tm->tm_wday ? tm->tm_wday : 7)); 3454 ucv_object_add(res, "yday", ucv_int64_new(tm->tm_yday + 1)); 3455 ucv_object_add(res, "isdst", ucv_int64_new(tm->tm_isdst)); 3456 3457 return res; 3458 } 3459 3460 static uc_value_t * 3461 uc_localtime(uc_vm_t *vm, size_t nargs) 3462 { 3463 return uc_gettime_common(vm, nargs, true); 3464 } 3465 3466 static uc_value_t * 3467 uc_gmtime(uc_vm_t *vm, size_t nargs) 3468 { 3469 return uc_gettime_common(vm, nargs, false); 3470 } 3471 3472 static uc_value_t * 3473 uc_mktime_common(uc_vm_t *vm, size_t nargs, bool local) 3474 { 3475 #define FIELD(name, required) \ 3476 { #name, required, offsetof(struct tm, tm_##name) } 3477 3478 const struct { 3479 const char *name; 3480 bool required; 3481 size_t off; 3482 } fields[] = { 3483 FIELD(sec, false), 3484 FIELD(min, false), 3485 FIELD(hour, false), 3486 FIELD(mday, true), 3487 FIELD(mon, true), 3488 FIELD(year, true), 3489 FIELD(isdst, false) 3490 }; 3491 3492 uc_value_t *to = uc_fn_arg(0), *v; 3493 struct tm tm = { 0 }; 3494 bool exists; 3495 time_t t; 3496 size_t i; 3497 3498 if (ucv_type(to) != UC_OBJECT) 3499 return NULL; 3500 3501 for (i = 0; i < ARRAY_SIZE(fields); i++) { 3502 v = ucv_object_get(to, fields[i].name, &exists); 3503 3504 if (!exists && fields[i].required) 3505 return NULL; 3506 3507 *(int *)((char *)&tm + fields[i].off) = (int)ucv_to_integer(v); 3508 } 3509 3510 if (tm.tm_mon > 0) 3511 tm.tm_mon--; 3512 3513 if (tm.tm_year >= 1900) 3514 tm.tm_year -= 1900; 3515 3516 t = (local ? mktime : timegm)(&tm); 3517 3518 return (t != (time_t)-1) ? ucv_int64_new((int64_t)t) : NULL; 3519 } 3520 3521 static uc_value_t * 3522 uc_timelocal(uc_vm_t *vm, size_t nargs) 3523 { 3524 return uc_mktime_common(vm, nargs, true); 3525 } 3526 3527 static uc_value_t * 3528 uc_timegm(uc_vm_t *vm, size_t nargs) 3529 { 3530 return uc_mktime_common(vm, nargs, false); 3531 } 3532 3533 static uc_value_t * 3534 uc_clock(uc_vm_t *vm, size_t nargs) 3535 { 3536 clockid_t id = ucv_is_truish(uc_fn_arg(0)) ? CLOCK_MONOTONIC : CLOCK_REALTIME; 3537 struct timespec ts; 3538 uc_value_t *res; 3539 3540 if (clock_gettime(id, &ts) == -1) 3541 return NULL; 3542 3543 res = ucv_array_new(vm); 3544 3545 ucv_array_set(res, 0, ucv_int64_new((int64_t)ts.tv_sec)); 3546 ucv_array_set(res, 1, ucv_int64_new((int64_t)ts.tv_nsec)); 3547 3548 return res; 3549 } 3550 3551 static uc_value_t * 3552 uc_hexenc(uc_vm_t *vm, size_t nargs) 3553 { 3554 const char *hex = "0123456789abcdef"; 3555 uc_value_t *input = uc_fn_arg(0); 3556 uc_stringbuf_t *buf; 3557 size_t off, len; 3558 uint8_t byte; 3559 3560 if (!input) 3561 return NULL; 3562 3563 buf = ucv_stringbuf_new(); 3564 off = printbuf_length(buf); 3565 3566 ucv_to_stringbuf(vm, buf, input, false); 3567 3568 len = printbuf_length(buf) - off; 3569 3570 /* memset the last expected output char to grow the output buffer */ 3571 printbuf_memset(buf, off + len * 2, 0, 1); 3572 3573 /* translate string into hex back to front to reuse the same buffer */ 3574 while (len > 0) { 3575 byte = buf->buf[--len + off]; 3576 buf->buf[off + len * 2 + 0] = hex[byte / 16]; 3577 buf->buf[off + len * 2 + 1] = hex[byte % 16]; 3578 } 3579 3580 /* do not include sentinel `\0` in string length */ 3581 buf->bpos--; 3582 3583 return ucv_stringbuf_finish(buf); 3584 } 3585 3586 static inline uint8_t 3587 hexval(unsigned char c, bool lo) 3588 { 3589 return ((c > '9') ? (c - 'a') + 10 : c - '') << (lo ? 0 : 4); 3590 } 3591 3592 static uc_value_t * 3593 uc_hexdec(uc_vm_t *vm, size_t nargs) 3594 { 3595 uc_value_t *input = uc_fn_arg(0); 3596 uc_value_t *skip = uc_fn_arg(1); 3597 size_t len, off, n, i; 3598 uc_stringbuf_t *buf; 3599 unsigned char *p; 3600 const char *s; 3601 3602 if (ucv_type(input) != UC_STRING) 3603 return NULL; 3604 3605 if (skip && ucv_type(skip) != UC_STRING) 3606 return NULL; 3607 3608 p = (unsigned char *)ucv_string_get(input); 3609 len = ucv_string_length(input); 3610 3611 s = skip ? (const char *)ucv_string_get(skip) : " \t\n"; 3612 3613 for (i = 0, n = 0; i < len; i++) { 3614 if (isxdigit(p[i])) 3615 n++; 3616 else if (!s || !strchr(s, p[i])) 3617 return NULL; 3618 } 3619 3620 if (n & 1) 3621 return NULL; 3622 3623 buf = ucv_stringbuf_new(); 3624 off = printbuf_length(buf); 3625 3626 /* preallocate the output buffer */ 3627 printbuf_memset(buf, off, 0, n / 2 + 1); 3628 3629 for (i = 0, n = 0; i < len; i++) { 3630 if (!isxdigit(p[i])) 3631 continue; 3632 3633 buf->buf[off + (n >> 1)] |= hexval(p[i] | 32, n & 1); 3634 n++; 3635 } 3636 3637 /* do not include sentinel `\0` in string length */ 3638 buf->bpos--; 3639 3640 return ucv_stringbuf_finish(buf); 3641 } 3642 3643 static uc_value_t * 3644 uc_gc(uc_vm_t *vm, size_t nargs) 3645 { 3646 uc_value_t *operation = uc_fn_arg(0); 3647 uc_value_t *argument = uc_fn_arg(1); 3648 const char *op = NULL; 3649 uc_weakref_t *ref; 3650 int64_t n; 3651 3652 if (operation != NULL && ucv_type(operation) != UC_STRING) 3653 return NULL; 3654 3655 op = ucv_string_get(operation); 3656 3657 if (!op || !strcmp(op, "collect")) { 3658 ucv_gc(vm); 3659 3660 return ucv_boolean_new(true); 3661 } 3662 else if (!strcmp(op, "start")) { 3663 n = argument ? ucv_int64_get(argument) : 0; 3664 3665 if (errno || n < 0 || n > 0xFFFF) 3666 return NULL; 3667 3668 if (n == 0) 3669 n = GC_DEFAULT_INTERVAL; 3670 3671 return ucv_boolean_new(uc_vm_gc_start(vm, n)); 3672 } 3673 else if (!strcmp(op, "stop")) { 3674 return ucv_boolean_new(uc_vm_gc_stop(vm)); 3675 } 3676 else if (!strcmp(op, "count")) { 3677 for (n = 0, ref = vm->values.next; ref != &vm->values; ref = ref->next) 3678 n++; 3679 3680 return ucv_uint64_new(n); 3681 } 3682 3683 return NULL; 3684 } 3685 3686 static void 3687 uc_compile_parse_config(uc_parse_config_t *config, uc_value_t *spec) 3688 { 3689 uc_value_t *v, *p; 3690 size_t i, j; 3691 bool found; 3692 3693 struct { 3694 const char *key; 3695 bool *flag; 3696 uc_search_path_t *path; 3697 } fields[] = { 3698 { "lstrip_blocks", &config->lstrip_blocks, NULL }, 3699 { "trim_blocks", &config->trim_blocks, NULL }, 3700 { "strict_declarations", &config->strict_declarations, NULL }, 3701 { "raw_mode", &config->raw_mode, NULL }, 3702 { "module_search_path", NULL, &config->module_search_path }, 3703 { "force_dynlink_list", NULL, &config->force_dynlink_list } 3704 }; 3705 3706 for (i = 0; i < ARRAY_SIZE(fields); i++) { 3707 v = ucv_object_get(spec, fields[i].key, &found); 3708 3709 if (!found) 3710 continue; 3711 3712 if (fields[i].flag) { 3713 *fields[i].flag = ucv_is_truish(v); 3714 } 3715 else if (fields[i].path) { 3716 fields[i].path->count = 0; 3717 fields[i].path->entries = NULL; 3718 3719 for (j = 0; j < ucv_array_length(v); j++) { 3720 p = ucv_array_get(v, j); 3721 3722 if (ucv_type(p) != UC_STRING) 3723 continue; 3724 3725 uc_vector_push(fields[i].path, ucv_string_get(p)); 3726 } 3727 } 3728 } 3729 } 3730 3731 static uc_value_t * 3732 uc_load_common(uc_vm_t *vm, size_t nargs, uc_source_t *source) 3733 { 3734 uc_parse_config_t conf = *vm->config; 3735 uc_program_t *program; 3736 uc_value_t *closure; 3737 char *err = NULL; 3738 3739 uc_compile_parse_config(&conf, uc_fn_arg(1)); 3740 3741 program = uc_compile(&conf, source, &err); 3742 closure = program ? ucv_closure_new(vm, uc_program_entry(program), false) : NULL; 3743 3744 uc_program_put(program); 3745 3746 if (!vm->config || conf.module_search_path.entries != vm->config->module_search_path.entries) 3747 uc_vector_clear(&conf.module_search_path); 3748 3749 if (!vm->config || conf.force_dynlink_list.entries != vm->config->force_dynlink_list.entries) 3750 uc_vector_clear(&conf.force_dynlink_list); 3751 3752 if (!closure) { 3753 uc_error_message_indent(&err); 3754 3755 if (source->buffer) 3756 uc_vm_raise_exception(vm, EXCEPTION_RUNTIME, 3757 "Unable to compile source string:\n\n%s", err); 3758 else 3759 uc_vm_raise_exception(vm, EXCEPTION_RUNTIME, 3760 "Unable to compile source file '%s':\n\n%s", source->filename, err); 3761 } 3762 3763 uc_source_put(source); 3764 free(err); 3765 3766 return closure; 3767 } 3768 3769 static uc_value_t * 3770 uc_loadstring(uc_vm_t *vm, size_t nargs) 3771 { 3772 uc_value_t *code = uc_fn_arg(0); 3773 uc_source_t *source; 3774 size_t len; 3775 char *s; 3776 3777 if (ucv_type(code) == UC_STRING) { 3778 len = ucv_string_length(code); 3779 s = xalloc(len); 3780 memcpy(s, ucv_string_get(code), len); 3781 } 3782 else { 3783 s = ucv_to_string(vm, code); 3784 len = strlen(s); 3785 } 3786 3787 source = uc_source_new_buffer("[loadstring argument]", s, len); 3788 3789 if (!source) { 3790 uc_vm_raise_exception(vm, EXCEPTION_RUNTIME, 3791 "Unable to allocate source buffer: %s", 3792 strerror(errno)); 3793 3794 return NULL; 3795 } 3796 3797 return uc_load_common(vm, nargs, source); 3798 } 3799 3800 static uc_value_t * 3801 uc_loadfile(uc_vm_t *vm, size_t nargs) 3802 { 3803 uc_value_t *path = uc_fn_arg(0); 3804 uc_source_t *source; 3805 3806 if (ucv_type(path) != UC_STRING) 3807 return NULL; 3808 3809 source = uc_source_new_file(ucv_string_get(path)); 3810 3811 if (!source) { 3812 uc_vm_raise_exception(vm, EXCEPTION_RUNTIME, 3813 "Unable to open source file %s: %s", 3814 ucv_string_get(path), strerror(errno)); 3815 3816 return NULL; 3817 } 3818 3819 return uc_load_common(vm, nargs, source); 3820 } 3821 3822 static uc_value_t * 3823 uc_callfunc(uc_vm_t *vm, size_t nargs) 3824 { 3825 size_t argoff = vm->stack.count - nargs, i; 3826 uc_value_t *fn_scope, *prev_scope, *res; 3827 uc_value_t *fn = uc_fn_arg(0); 3828 uc_value_t *this = uc_fn_arg(1); 3829 uc_value_t *scope = uc_fn_arg(2); 3830 3831 if (!ucv_is_callable(fn)) 3832 return NULL; 3833 3834 if (scope && ucv_type(scope) != UC_OBJECT) 3835 return NULL; 3836 3837 if (ucv_prototype_get(scope)) { 3838 fn_scope = ucv_get(scope); 3839 } 3840 else if (scope) { 3841 fn_scope = ucv_object_new(vm); 3842 3843 ucv_object_foreach(scope, k, v) 3844 ucv_object_add(fn_scope, k, ucv_get(v)); 3845 3846 ucv_prototype_set(fn_scope, ucv_get(uc_vm_scope_get(vm))); 3847 } 3848 else { 3849 fn_scope = NULL; 3850 } 3851 3852 uc_vm_stack_push(vm, ucv_get(this)); 3853 uc_vm_stack_push(vm, ucv_get(fn)); 3854 3855 for (i = 3; i < nargs; i++) 3856 uc_vm_stack_push(vm, ucv_get(vm->stack.entries[3 + argoff++])); 3857 3858 if (fn_scope) { 3859 prev_scope = ucv_get(uc_vm_scope_get(vm)); 3860 uc_vm_scope_set(vm, fn_scope); 3861 } 3862 3863 if (uc_vm_call(vm, true, i - 3) == EXCEPTION_NONE) 3864 res = uc_vm_stack_pop(vm); 3865 else 3866 res = NULL; 3867 3868 if (fn_scope) 3869 uc_vm_scope_set(vm, prev_scope); 3870 3871 return res; 3872 } 3873 3874 3875 const uc_function_list_t uc_stdlib_functions[] = { 3876 { "chr", uc_chr }, 3877 { "die", uc_die }, 3878 { "exists", uc_exists }, 3879 { "exit", uc_exit }, 3880 { "filter", uc_filter }, 3881 { "getenv", uc_getenv }, 3882 { "hex", uc_hex }, 3883 { "index", uc_lindex }, 3884 { "int", uc_int }, 3885 { "join", uc_join }, 3886 { "keys", uc_keys }, 3887 { "lc", uc_lc }, 3888 { "length", uc_length }, 3889 { "ltrim", uc_ltrim }, 3890 { "map", uc_map }, 3891 { "ord", uc_ord }, 3892 { "pop", uc_pop }, 3893 { "print", uc_print }, 3894 { "push", uc_push }, 3895 { "reverse", uc_reverse }, 3896 { "rindex", uc_rindex }, 3897 { "rtrim", uc_rtrim }, 3898 { "shift", uc_shift }, 3899 { "sort", uc_sort }, 3900 { "splice", uc_splice }, 3901 { "slice", uc_slice }, 3902 { "split", uc_split }, 3903 { "substr", uc_substr }, 3904 { "time", uc_time }, 3905 { "trim", uc_trim }, 3906 { "type", uc_type }, 3907 { "uchr", uc_uchr }, 3908 { "uc", uc_uc }, 3909 { "unshift", uc_unshift }, 3910 { "values", uc_values }, 3911 { "sprintf", uc_sprintf }, 3912 { "printf", uc_printf }, 3913 { "require", uc_require }, 3914 { "iptoarr", uc_iptoarr }, 3915 { "arrtoip", uc_arrtoip }, 3916 { "match", uc_match }, 3917 { "replace", uc_replace }, 3918 { "json", uc_json }, 3919 { "include", uc_include }, 3920 { "warn", uc_warn }, 3921 { "system", uc_system }, 3922 { "trace", uc_trace }, 3923 { "proto", uc_proto }, 3924 { "sleep", uc_sleep }, 3925 { "assert", uc_assert }, 3926 { "render", uc_render }, 3927 { "regexp", uc_regexp }, 3928 { "wildcard", uc_wildcard }, 3929 { "sourcepath", uc_sourcepath }, 3930 { "min", uc_min }, 3931 { "max", uc_max }, 3932 { "b64dec", uc_b64dec }, 3933 { "b64enc", uc_b64enc }, 3934 { "uniq", uc_uniq }, 3935 { "localtime", uc_localtime }, 3936 { "gmtime", uc_gmtime }, 3937 { "timelocal", uc_timelocal }, 3938 { "timegm", uc_timegm }, 3939 { "clock", uc_clock }, 3940 { "hexdec", uc_hexdec }, 3941 { "hexenc", uc_hexenc }, 3942 { "gc", uc_gc }, 3943 { "loadstring", uc_loadstring }, 3944 { "loadfile", uc_loadfile }, 3945 { "call", uc_callfunc }, 3946 }; 3947 3948 3949 void 3950 uc_stdlib_load(uc_value_t *scope) 3951 { 3952 uc_function_list_register(scope, uc_stdlib_functions); 3953 } 3954 3955 uc_cfn_ptr_t 3956 uc_stdlib_function(const char *name) 3957 { 3958 size_t i; 3959 3960 for (i = 0; i < ARRAY_SIZE(uc_stdlib_functions); i++) 3961 if (!strcmp(uc_stdlib_functions[i].name, name)) 3962 return uc_stdlib_functions[i].func; 3963 3964 return NULL; 3965 } 3966
This page was automatically generated by LXR 0.3.1. • OpenWrt