1 /* 2 * Copyright 2001-2004 Brandon Long 3 * All Rights Reserved. 4 * 5 * ClearSilver Templating System 6 * 7 * This code is made available under the terms of the ClearSilver License. 8 * http://www.clearsilver.net/license.hdf 9 * 10 */ 11 12 #include "cs_config.h" 13 14 #include <unistd.h> 15 #include <ctype.h> 16 #include <stdlib.h> 17 #include <stdio.h> 18 #include <string.h> 19 #include <stdarg.h> 20 #include <regex.h> 21 #include "neo_misc.h" 22 #include "neo_err.h" 23 #include "neo_str.h" 24 #include "ulist.h" 25 26 #ifndef va_copy 27 #ifdef __va_copy 28 # define va_copy(dest,src) __va_copy(dest,src) 29 #else 30 # define va_copy(dest,src) ((dest) = (src)) 31 #endif 32 #endif 33 34 char *neos_strip (char *s) 35 { 36 int x; 37 38 x = strlen(s) - 1; 39 while (x>=0 && isspace(s[x])) s[x--] = '\0'; 40 41 while (*s && isspace(*s)) s++; 42 43 return s; 44 } 45 46 char *neos_rstrip (char *s) 47 { 48 int n = strlen (s)-1; 49 50 while (n >= 0 && isspace(s[n])) 51 { 52 s[n] = '\0'; 53 n--; 54 } 55 56 return s; 57 } 58 59 void neos_lower(char *s) 60 { 61 while(*s != 0) { 62 *s = tolower(*s); 63 s++; 64 } 65 } 66 67 68 void string_init (STRING *str) 69 { 70 str->buf = NULL; 71 str->len = 0; 72 str->max = 0; 73 } 74 75 void string_clear (STRING *str) 76 { 77 if (str->buf != NULL) 78 free(str->buf); 79 string_init(str); 80 } 81 82 static NEOERR* string_check_length (STRING *str, int l) 83 { 84 if (str->buf == NULL) 85 { 86 if (l * 10 > 256) 87 str->max = l * 10; 88 else 89 str->max = 256; 90 str->buf = (char *) malloc (sizeof(char) * str->max); 91 if (str->buf == NULL) 92 return nerr_raise (NERR_NOMEM, "Unable to allocate render buf of size %d", 93 str->max); 94 /* ne_warn("Creating string %x at %d (%5.2fK)", str, str->max, (str->max / 1024.0)); */ 95 } 96 else if (str->len + l >= str->max) 97 { 98 do 99 { 100 str->max *= 2; 101 } while (str->len + l >= str->max); 102 str->buf = (char *) realloc (str->buf, sizeof(char) * str->max); 103 if (str->buf == NULL) 104 return nerr_raise (NERR_NOMEM, "Unable to allocate STRING buf of size %d", 105 str->max); 106 /* ne_warn("Growing string %x to %d (%5.2fK)", str, str->max, (str->max / 1024.0)); */ 107 } 108 return STATUS_OK; 109 } 110 111 NEOERR *string_set (STRING *str, const char *buf) 112 { 113 str->len = 0; 114 return nerr_pass (string_append (str, buf)); 115 } 116 117 NEOERR *string_append (STRING *str, const char *buf) 118 { 119 NEOERR *err; 120 int l; 121 122 l = strlen(buf); 123 err = string_check_length (str, l); 124 if (err != STATUS_OK) return nerr_pass (err); 125 strcpy(str->buf + str->len, buf); 126 str->len += l; 127 128 return STATUS_OK; 129 } 130 131 NEOERR *string_appendn (STRING *str, const char *buf, int l) 132 { 133 NEOERR *err; 134 135 err = string_check_length (str, l+1); 136 if (err != STATUS_OK) return nerr_pass (err); 137 memcpy(str->buf + str->len, buf, l); 138 str->len += l; 139 str->buf[str->len] = '\0'; 140 141 return STATUS_OK; 142 } 143 144 /* this is much more efficient with C99 snprintfs... */ 145 NEOERR *string_appendvf (STRING *str, const char *fmt, va_list ap) 146 { 147 NEOERR *err; 148 char buf[4096]; 149 int bl, size; 150 va_list tmp; 151 152 va_copy(tmp, ap); 153 /* determine length */ 154 size = sizeof (buf); 155 bl = vsnprintf (buf, size, fmt, tmp); 156 if (bl > -1 && bl < size) 157 return string_appendn (str, buf, bl); 158 159 /* Handle non-C99 snprintfs (requires extra malloc/free and copy) */ 160 if (bl == -1) 161 { 162 char *a_buf; 163 164 va_copy(tmp, ap); 165 a_buf = vnsprintf_alloc(size*2, fmt, tmp); 166 if (a_buf == NULL) 167 return nerr_raise(NERR_NOMEM, 168 "Unable to allocate memory for formatted string"); 169 err = string_append(str, a_buf); 170 free(a_buf); 171 return nerr_pass(err); 172 } 173 174 err = string_check_length (str, bl+1); 175 if (err != STATUS_OK) return nerr_pass (err); 176 va_copy(tmp, ap); 177 vsprintf (str->buf + str->len, fmt, tmp); 178 str->len += bl; 179 str->buf[str->len] = '\0'; 180 181 return STATUS_OK; 182 } 183 184 NEOERR *string_appendf (STRING *str, const char *fmt, ...) 185 { 186 NEOERR *err; 187 va_list ap; 188 189 va_start (ap, fmt); 190 err = string_appendvf (str, fmt, ap); 191 va_end (ap); 192 return nerr_pass(err); 193 } 194 195 NEOERR *string_append_char (STRING *str, char c) 196 { 197 NEOERR *err; 198 err = string_check_length (str, 1); 199 if (err != STATUS_OK) return nerr_pass (err); 200 str->buf[str->len] = c; 201 str->buf[str->len + 1] = '\0'; 202 str->len += 1; 203 204 return STATUS_OK; 205 } 206 207 void string_array_init (STRING_ARRAY *arr) 208 { 209 arr->entries = NULL; 210 arr->count = 0; 211 arr->max = 0; 212 } 213 214 NEOERR *string_array_split (ULIST **list, char *s, const char *sep, 215 int max) 216 { 217 NEOERR *err; 218 char *p, *n, *f; 219 int sl; 220 int x = 0; 221 222 if (sep[0] == '\0') 223 return nerr_raise (NERR_ASSERT, "separator must be at least one character"); 224 225 err = uListInit (list, 10, 0); 226 if (err) return nerr_pass(err); 227 228 sl = strlen(sep); 229 p = (sl == 1) ? strchr (s, sep[0]) : strstr (s, sep); 230 f = s; 231 while (p != NULL) 232 { 233 if (x >= max) break; 234 *p = '\0'; 235 n = strdup(f); 236 *p = sep[0]; 237 if (n) err = uListAppend (*list, n); 238 else err = nerr_raise(NERR_NOMEM, 239 "Unable to allocate memory to split %s", s); 240 if (err) goto split_err; 241 f = p+sl; 242 p = (sl == 1) ? strchr (f, sep[0]) : strstr (f, sep); 243 x++; 244 } 245 /* Handle remainder */ 246 n = strdup(f); 247 if (n) err = uListAppend (*list, n); 248 else err = nerr_raise(NERR_NOMEM, 249 "Unable to allocate memory to split %s", s); 250 if (err) goto split_err; 251 return STATUS_OK; 252 253 split_err: 254 uListDestroy(list, ULIST_FREE); 255 return err; 256 } 257 258 void string_array_clear (STRING_ARRAY *arr) 259 { 260 int x; 261 262 for (x = 0; x < arr->count; x++) 263 { 264 if (arr->entries[x] != NULL) free (arr->entries[x]); 265 arr->entries[x] = NULL; 266 } 267 free (arr->entries); 268 arr->entries = NULL; 269 arr->count = 0; 270 } 271 272 /* Mostly used by vprintf_alloc for non-C99 compliant snprintfs, 273 * this is like vsprintf_alloc except it takes a "suggested" size */ 274 int vnisprintf_alloc (char **buf, int start_size, const char *fmt, va_list ap) 275 { 276 int bl, size; 277 va_list tmp; 278 279 *buf = NULL; 280 size = start_size; 281 282 *buf = (char *) malloc (size * sizeof(char)); 283 if (*buf == NULL) return 0; 284 while (1) 285 { 286 va_copy(tmp, ap); 287 bl = vsnprintf (*buf, size, fmt, tmp); 288 if (bl > -1 && bl < size) 289 return bl; 290 if (bl > -1) 291 size = bl + 1; 292 else 293 size *= 2; 294 *buf = (char *) realloc (*buf, size * sizeof(char)); 295 if (*buf == NULL) return 0; 296 } 297 } 298 299 char *vnsprintf_alloc (int start_size, const char *fmt, va_list ap) 300 { 301 char *r; 302 vnisprintf_alloc(&r, start_size, fmt, ap); 303 return r; 304 } 305 306 /* This works better with a C99 compliant vsnprintf, but should work ok 307 * with versions that return a -1 if it overflows the buffer */ 308 int visprintf_alloc (char **buf, const char *fmt, va_list ap) 309 { 310 char ibuf[4096]; 311 int bl, size; 312 va_list tmp; 313 314 /* PPC doesn't like you re-using a va_list... and it might not be 315 * supposed to work at all */ 316 va_copy(tmp, ap); 317 318 size = sizeof (ibuf); 319 bl = vsnprintf (ibuf, sizeof (ibuf), fmt, tmp); 320 if (bl > -1 && bl < size) 321 { 322 *buf = (char *) calloc(bl+1, sizeof(char)); 323 if (*buf == NULL) return 0; 324 strncpy(*buf, ibuf, bl); 325 return bl; 326 } 327 328 if (bl > -1) 329 size = bl + 1; 330 else 331 size *= 2; 332 333 return vnisprintf_alloc(buf, size, fmt, ap); 334 } 335 336 char *vsprintf_alloc (const char *fmt, va_list ap) 337 { 338 char *r; 339 visprintf_alloc(&r, fmt, ap); 340 return r; 341 } 342 343 /* technically, sprintf's can have null values, so we need to be able to 344 * return a length also like real sprintf */ 345 int isprintf_alloc (char **buf, const char *fmt, ...) 346 { 347 va_list ap; 348 int r; 349 350 va_start (ap, fmt); 351 r = visprintf_alloc (buf, fmt, ap); 352 va_end (ap); 353 return r; 354 } 355 356 char *sprintf_alloc (const char *fmt, ...) 357 { 358 va_list ap; 359 char *r; 360 361 va_start (ap, fmt); 362 r = vsprintf_alloc (fmt, ap); 363 va_end (ap); 364 return r; 365 } 366 367 /* This is mostly just here for completeness, I doubt anyone would use 368 * this (its more efficient (time-wise) if start_size is bigger than the 369 * resulting string. Its less efficient than sprintf_alloc if we have a 370 * C99 snprintf and it doesn't fit in start_size. 371 * BTW: If you are really worried about the efficiency of these 372 * functions, maybe you shouldn't be using them in the first place... */ 373 char *nsprintf_alloc (int start_size, const char *fmt, ...) 374 { 375 va_list ap; 376 char *r; 377 378 va_start (ap, fmt); 379 r = vnsprintf_alloc (start_size, fmt, ap); 380 va_end (ap); 381 return r; 382 } 383 384 BOOL reg_search (const char *re, const char *str) 385 { 386 regex_t search_re; 387 int errcode; 388 char buf[256]; 389 390 if ((errcode = regcomp(&search_re, re, REG_ICASE | REG_EXTENDED | REG_NOSUB))) 391 { 392 regerror (errcode, &search_re, buf, sizeof(buf)); 393 ne_warn ("Unable to compile regex %s: %s", re, buf); 394 return FALSE; 395 } 396 errcode = regexec (&search_re, str, 0, NULL, 0); 397 regfree (&search_re); 398 if (errcode == 0) 399 return TRUE; 400 return FALSE; 401 } 402 403 NEOERR *string_readline (STRING *str, FILE *fp) 404 { 405 NEOERR *err; 406 407 /* minimum size for a readline is 256 above current position */ 408 err = string_check_length (str, str->len + 256); 409 if (err != STATUS_OK) return nerr_pass (err); 410 411 while (fgets(str->buf + str->len, str->max - str->len, fp) != NULL) 412 { 413 str->len = strlen(str->buf); 414 if (str->buf[str->len-1] == '\n') break; 415 err = string_check_length (str, str->len + 256); 416 if (err != STATUS_OK) return nerr_pass (err); 417 } 418 return STATUS_OK; 419 } 420 421 NEOERR* neos_escape(UINT8 *buf, int buflen, char esc_char, const char *escape, 422 char **esc) 423 { 424 int nl = 0; 425 int l = 0; 426 int x = 0; 427 char *s; 428 int match = 0; 429 430 while (l < buflen) 431 { 432 if (buf[l] == esc_char) 433 { 434 nl += 2; 435 } 436 else 437 { 438 x = 0; 439 while (escape[x]) 440 { 441 if (escape[x] == buf[l]) 442 { 443 nl +=2; 444 break; 445 } 446 x++; 447 } 448 } 449 nl++; 450 l++; 451 } 452 453 s = (char *) malloc (sizeof(char) * (nl + 1)); 454 if (s == NULL) 455 return nerr_raise (NERR_NOMEM, "Unable to allocate memory to escape %s", 456 buf); 457 458 nl = 0; l = 0; 459 while (l < buflen) 460 { 461 match = 0; 462 if (buf[l] == esc_char) 463 { 464 match = 1; 465 } 466 else 467 { 468 x = 0; 469 while (escape[x]) 470 { 471 if (escape[x] == buf[l]) 472 { 473 match = 1; 474 break; 475 } 476 x++; 477 } 478 } 479 if (match) 480 { 481 s[nl++] = esc_char; 482 s[nl++] = "0123456789ABCDEF"[buf[l] / 16]; 483 s[nl++] = "0123456789ABCDEF"[buf[l] % 16]; 484 l++; 485 } 486 else 487 { 488 s[nl++] = buf[l++]; 489 } 490 } 491 s[nl] = '\0'; 492 493 *esc = s; 494 return STATUS_OK; 495 } 496 497 UINT8 *neos_unescape (UINT8 *s, int buflen, char esc_char) 498 { 499 int i = 0, o = 0; 500 501 if (s == NULL) return s; 502 while (i < buflen) 503 { 504 if (s[i] == esc_char && (i+2 < buflen) && 505 isxdigit(s[i+1]) && isxdigit(s[i+2])) 506 { 507 UINT8 num; 508 num = (s[i+1] >= 'A') ? ((s[i+1] & 0xdf) - 'A') + 10 : (s[i+1] - '0'); 509 num *= 16; 510 num += (s[i+2] >= 'A') ? ((s[i+2] & 0xdf) - 'A') + 10 : (s[i+2] - '0'); 511 s[o++] = num; 512 i+=3; 513 } 514 else { 515 s[o++] = s[i++]; 516 } 517 } 518 if (i && o) s[o] = '\0'; 519 return s; 520 } 521 522 char *repr_string_alloc (const char *s) 523 { 524 int l,x,i; 525 int nl = 0; 526 char *rs; 527 528 if (s == NULL) 529 { 530 return strdup("NULL"); 531 } 532 533 l = strlen(s); 534 for (x = 0; x < l; x++) 535 { 536 if (isprint(s[x]) && s[x] != '"' && s[x] != '\\') 537 { 538 nl++; 539 } 540 else 541 { 542 if (s[x] == '\n' || s[x] == '\t' || s[x] == '\r' || s[x] == '"' || 543 s[x] == '\\') 544 { 545 nl += 2; 546 } 547 else nl += 4; 548 } 549 } 550 551 rs = (char *) malloc ((nl+3) * sizeof(char)); 552 if (rs == NULL) 553 return NULL; 554 555 i = 0; 556 rs[i++] = '"'; 557 for (x = 0; x < l; x++) 558 { 559 if (isprint(s[x]) && s[x] != '"' && s[x] != '\\') 560 { 561 rs[i++] = s[x]; 562 } 563 else 564 { 565 rs[i++] = '\\'; 566 switch (s[x]) 567 { 568 case '\n': 569 rs[i++] = 'n'; 570 break; 571 case '\t': 572 rs[i++] = 't'; 573 break; 574 case '\r': 575 rs[i++] = 'r'; 576 break; 577 case '"': 578 rs[i++] = '"'; 579 break; 580 case '\\': 581 rs[i++] = '\\'; 582 break; 583 default: 584 sprintf(&(rs[i]), "%03o", (s[x] & 0377)); 585 i += 3; 586 break; 587 } 588 } 589 } 590 rs[i++] = '"'; 591 rs[i] = '\0'; 592 return rs; 593 } 594 595 // List of all characters that must be escaped 596 // List based on http://www.blooberry.com/indexdot/html/topics/urlencoding.htm 597 static char EscapedChars[] = "$&+,/:;=?@ \"<>#%{}|\\^~[]`'"; 598 599 // Check if a single character needs to be escaped 600 static BOOL is_reserved_char(char c) 601 { 602 int i = 0; 603 604 if (c < 32 || c > 122) { 605 return TRUE; 606 } else { 607 while (EscapedChars[i]) { 608 if (c == EscapedChars[i]) { 609 return TRUE; 610 } 611 ++i; 612 } 613 } 614 return FALSE; 615 } 616 617 NEOERR *neos_js_escape (const char *in, char **esc) 618 { 619 int nl = 0; 620 int l = 0; 621 unsigned char *buf = (unsigned char *)in; 622 unsigned char *s; 623 624 while (buf[l]) 625 { 626 if (buf[l] == '/' || buf[l] == '"' || buf[l] == '\'' || 627 buf[l] == '\\' || buf[l] == '>' || buf[l] == '<' || 628 buf[l] == '&' || buf[l] == ';' || buf[l] < 32) 629 { 630 nl += 3; 631 } 632 nl++; 633 l++; 634 } 635 636 s = (unsigned char *) malloc (sizeof(unsigned char) * (nl + 1)); 637 if (s == NULL) 638 return nerr_raise (NERR_NOMEM, "Unable to allocate memory to escape %s", 639 buf); 640 641 nl = 0; l = 0; 642 while (buf[l]) 643 { 644 if (buf[l] == '/' || buf[l] == '"' || buf[l] == '\'' || 645 buf[l] == '\\' || buf[l] == '>' || buf[l] == '<' || 646 buf[l] == '&' || buf[l] == ';' || buf[l] < 32) 647 { 648 s[nl++] = '\\'; 649 s[nl++] = 'x'; 650 s[nl++] = "0123456789ABCDEF"[(buf[l] >> 4) & 0xF]; 651 s[nl++] = "0123456789ABCDEF"[buf[l] & 0xF]; 652 l++; 653 } 654 else 655 { 656 s[nl++] = buf[l++]; 657 } 658 } 659 s[nl] = '\0'; 660 661 *esc = (char *)s; 662 return STATUS_OK; 663 } 664 665 666 NEOERR *neos_url_escape (const char *in, char **esc, 667 const char *other) 668 { 669 int nl = 0; 670 int l = 0; 671 int x = 0; 672 unsigned char *buf = (unsigned char *)in; 673 unsigned char *uother = (unsigned char *)other; 674 unsigned char *s; 675 int match = 0; 676 677 while (buf[l]) 678 { 679 if (is_reserved_char(buf[l])) 680 { 681 nl += 2; 682 } 683 else if (uother) 684 { 685 x = 0; 686 while (uother[x]) 687 { 688 if (uother[x] == buf[l]) 689 { 690 nl +=2; 691 break; 692 } 693 x++; 694 } 695 } 696 nl++; 697 l++; 698 } 699 700 s = (unsigned char *) malloc (sizeof(unsigned char) * (nl + 1)); 701 if (s == NULL) 702 return nerr_raise (NERR_NOMEM, "Unable to allocate memory to escape %s", 703 buf); 704 705 nl = 0; l = 0; 706 while (buf[l]) 707 { 708 match = 0; 709 if (buf[l] == ' ') 710 { 711 s[nl++] = '+'; 712 l++; 713 } 714 else 715 { 716 if (is_reserved_char(buf[l])) 717 { 718 match = 1; 719 } 720 else if (uother) 721 { 722 x = 0; 723 while (uother[x]) 724 { 725 if (uother[x] == buf[l]) 726 { 727 match = 1; 728 break; 729 } 730 x++; 731 } 732 } 733 if (match) 734 { 735 s[nl++] = '%'; 736 s[nl++] = "0123456789ABCDEF"[buf[l] / 16]; 737 s[nl++] = "0123456789ABCDEF"[buf[l] % 16]; 738 l++; 739 } 740 else 741 { 742 s[nl++] = buf[l++]; 743 } 744 } 745 } 746 s[nl] = '\0'; 747 748 *esc = (char *)s; 749 return STATUS_OK; 750 } 751 752 NEOERR *neos_html_escape (const char *src, int slen, 753 char **out) 754 { 755 NEOERR *err = STATUS_OK; 756 STRING out_s; 757 int x; 758 char *ptr; 759 760 string_init(&out_s); 761 err = string_append (&out_s, ""); 762 if (err) return nerr_pass (err); 763 *out = NULL; 764 765 x = 0; 766 while (x < slen) 767 { 768 ptr = strpbrk(src + x, "&<>\"'\r"); 769 if (ptr == NULL || (ptr-src >= slen)) 770 { 771 err = string_appendn (&out_s, src + x, slen-x); 772 x = slen; 773 } 774 else 775 { 776 err = string_appendn (&out_s, src + x, (ptr - src) - x); 777 if (err != STATUS_OK) break; 778 x = ptr - src; 779 if (src[x] == '&') 780 err = string_append (&out_s, "&"); 781 else if (src[x] == '<') 782 err = string_append (&out_s, "<"); 783 else if (src[x] == '>') 784 err = string_append (&out_s, ">"); 785 else if (src[x] == '"') 786 err = string_append (&out_s, """); 787 else if (src[x] == '\'') 788 err = string_append (&out_s, "'"); 789 else if (src[x] != '\r') 790 err = nerr_raise (NERR_ASSERT, "src[x] == '%c'", src[x]); 791 x++; 792 } 793 if (err != STATUS_OK) break; 794 } 795 if (err) 796 { 797 string_clear (&out_s); 798 return nerr_pass (err); 799 } 800 *out = out_s.buf; 801 return STATUS_OK; 802 } 803 804 char *URL_PROTOCOLS[] = {"http://", "https://", "ftp://", "mailto:"}; 805 806 NEOERR *neos_url_validate (const char *in, char **esc) 807 { 808 NEOERR *err = STATUS_OK; 809 STRING out_s; 810 int valid = 0; 811 size_t i; 812 size_t inlen; 813 int num_protocols = sizeof(URL_PROTOCOLS) / sizeof(char*); 814 void* slashpos; 815 void* colonpos; 816 817 inlen = strlen(in); 818 819 /* 820 * <a href="//b:80"> or <a href="a/b:80"> are allowed by browsers 821 * and ":" is treated as part of the path, while 822 * <a href="www.google.com:80"> is an invalid url 823 * and ":" is treated as a scheme separator. 824 * 825 * Hence allow for ":" in the path part of a url (after /) 826 */ 827 slashpos = memchr(in, '/', inlen); 828 if (slashpos == NULL) { 829 i = inlen; 830 } 831 else { 832 i = (size_t)((char*)slashpos - in); 833 } 834 835 colonpos = memchr(in, ':', i); 836 837 if (colonpos == NULL) { 838 // no scheme in 'in': so this is a relative url 839 valid = 1; 840 } 841 else { 842 for (i = 0; i < num_protocols; i++) 843 { 844 if ((inlen >= strlen(URL_PROTOCOLS[i])) && 845 strncmp(in, URL_PROTOCOLS[i], strlen(URL_PROTOCOLS[i])) == 0) { 846 // 'in' starts with one of the allowed protocols 847 valid = 1; 848 break; 849 } 850 851 } 852 } 853 854 if (valid) 855 return neos_html_escape(in, inlen, esc); 856 857 // 'in' contains an unsupported scheme, replace with '#' 858 string_init(&out_s); 859 err = string_append (&out_s, "#"); 860 if (err) return nerr_pass (err); 861 862 *esc = out_s.buf; 863 return STATUS_OK; 864 865 } 866 867 NEOERR *neos_var_escape (NEOS_ESCAPE context, 868 const char *in, 869 char **esc) 870 { 871 872 /* Just dup and return if we do nothing. */ 873 if (context == NEOS_ESCAPE_NONE || 874 context == NEOS_ESCAPE_FUNCTION) 875 { 876 *esc = strdup(in); 877 return STATUS_OK; 878 } 879 880 /* Now we escape based on context. This is the order of precedence: 881 * url > script > style > html 882 */ 883 if (context & NEOS_ESCAPE_URL) 884 return nerr_pass(neos_url_escape(in, esc, NULL)); 885 else if (context & NEOS_ESCAPE_SCRIPT) 886 return nerr_pass(neos_js_escape(in, esc)); 887 else if (context & NEOS_ESCAPE_HTML) 888 return nerr_pass(neos_html_escape(in, strlen(in), esc)); 889 890 return nerr_raise(NERR_ASSERT, "unknown escape context supplied: %d", 891 context); 892 } 893