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
neos_strip(char * s)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
neos_rstrip(char * s)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
neos_lower(char * s)59 void neos_lower(char *s)
60 {
61 while(*s != 0) {
62 *s = tolower(*s);
63 s++;
64 }
65 }
66
67
string_init(STRING * str)68 void string_init (STRING *str)
69 {
70 str->buf = NULL;
71 str->len = 0;
72 str->max = 0;
73 }
74
string_clear(STRING * str)75 void string_clear (STRING *str)
76 {
77 if (str->buf != NULL)
78 free(str->buf);
79 string_init(str);
80 }
81
string_check_length(STRING * str,int l)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
string_set(STRING * str,const char * buf)111 NEOERR *string_set (STRING *str, const char *buf)
112 {
113 str->len = 0;
114 return nerr_pass (string_append (str, buf));
115 }
116
string_append(STRING * str,const char * buf)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
string_appendn(STRING * str,const char * buf,int l)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... */
string_appendvf(STRING * str,const char * fmt,va_list ap)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
string_appendf(STRING * str,const char * fmt,...)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
string_append_char(STRING * str,char c)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
string_array_init(STRING_ARRAY * arr)207 void string_array_init (STRING_ARRAY *arr)
208 {
209 arr->entries = NULL;
210 arr->count = 0;
211 arr->max = 0;
212 }
213
string_array_split(ULIST ** list,char * s,const char * sep,int max)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
string_array_clear(STRING_ARRAY * arr)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 */
vnisprintf_alloc(char ** buf,int start_size,const char * fmt,va_list ap)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
vnsprintf_alloc(int start_size,const char * fmt,va_list ap)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 */
visprintf_alloc(char ** buf,const char * fmt,va_list ap)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
vsprintf_alloc(const char * fmt,va_list ap)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 */
isprintf_alloc(char ** buf,const char * fmt,...)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
sprintf_alloc(const char * fmt,...)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... */
nsprintf_alloc(int start_size,const char * fmt,...)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
reg_search(const char * re,const char * str)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
string_readline(STRING * str,FILE * fp)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
neos_escape(UINT8 * buf,int buflen,char esc_char,const char * escape,char ** esc)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
neos_unescape(UINT8 * s,int buflen,char esc_char)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
repr_string_alloc(const char * s)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
is_reserved_char(char c)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
neos_js_escape(const char * in,char ** esc)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
neos_url_escape(const char * in,char ** esc,const char * other)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
neos_html_escape(const char * src,int slen,char ** out)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
neos_url_validate(const char * in,char ** esc)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
neos_var_escape(NEOS_ESCAPE context,const char * in,char ** esc)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