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