nginx 0.7.8
[nginx-catap.git] / src / core / ngx_string.c
blob203cd3e3735a5354dd7f553348dab07f2d5f51d5
2 /*
3 * Copyright (C) Igor Sysoev
4 */
7 #include <ngx_config.h>
8 #include <ngx_core.h>
11 void
12 ngx_strlow(u_char *dst, u_char *src, size_t n)
14 while (n--) {
15 *dst = ngx_tolower(*src);
16 dst++;
17 src++;
22 u_char *
23 ngx_cpystrn(u_char *dst, u_char *src, size_t n)
25 if (n == 0) {
26 return dst;
29 for ( /* void */ ; --n; dst++, src++) {
30 *dst = *src;
32 if (*dst == '\0') {
33 return dst;
37 *dst = '\0';
39 return dst;
43 u_char *
44 ngx_pstrdup(ngx_pool_t *pool, ngx_str_t *src)
46 u_char *dst;
48 dst = ngx_pnalloc(pool, src->len);
49 if (dst == NULL) {
50 return NULL;
53 ngx_memcpy(dst, src->data, src->len);
55 return dst;
60 * supported formats:
61 * %[0][width][x][X]O off_t
62 * %[0][width]T time_t
63 * %[0][width][u][x|X]z ssize_t/size_t
64 * %[0][width][u][x|X]d int/u_int
65 * %[0][width][u][x|X]l long
66 * %[0][width|m][u][x|X]i ngx_int_t/ngx_uint_t
67 * %[0][width][u][x|X]D int32_t/uint32_t
68 * %[0][width][u][x|X]L int64_t/uint64_t
69 * %[0][width|m][u][x|X]A ngx_atomic_int_t/ngx_atomic_uint_t
70 * %P ngx_pid_t
71 * %M ngx_msec_t
72 * %r rlim_t
73 * %p void *
74 * %V ngx_str_t *
75 * %v ngx_variable_value_t *
76 * %s null-terminated string
77 * %*s length and string
78 * %Z '\0'
79 * %N '\n'
80 * %c char
81 * %% %
83 * reserved:
84 * %t ptrdiff_t
85 * %S null-teminated wchar string
86 * %C wchar
90 u_char * ngx_cdecl
91 ngx_sprintf(u_char *buf, const char *fmt, ...)
93 u_char *p;
94 va_list args;
96 va_start(args, fmt);
97 p = ngx_vsnprintf(buf, /* STUB */ 65536, fmt, args);
98 va_end(args);
100 return p;
104 u_char * ngx_cdecl
105 ngx_snprintf(u_char *buf, size_t max, const char *fmt, ...)
107 u_char *p;
108 va_list args;
110 va_start(args, fmt);
111 p = ngx_vsnprintf(buf, max, fmt, args);
112 va_end(args);
114 return p;
118 u_char *
119 ngx_vsnprintf(u_char *buf, size_t max, const char *fmt, va_list args)
121 u_char *p, zero, *last, temp[NGX_INT64_LEN + 1];
123 * really we need temp[NGX_INT64_LEN] only,
124 * but icc issues the warning
126 int d;
127 size_t len, slen;
128 uint32_t ui32;
129 int64_t i64;
130 uint64_t ui64;
131 ngx_msec_t ms;
132 ngx_uint_t width, sign, hexadecimal, max_width;
133 ngx_str_t *v;
134 ngx_variable_value_t *vv;
135 static u_char hex[] = "0123456789abcdef";
136 static u_char HEX[] = "0123456789ABCDEF";
138 if (max == 0) {
139 return buf;
142 last = buf + max;
144 while (*fmt && buf < last) {
147 * "buf < last" means that we could copy at least one character:
148 * the plain character, "%%", "%c", and minus without the checking
151 if (*fmt == '%') {
153 i64 = 0;
154 ui64 = 0;
156 zero = (u_char) ((*++fmt == '0') ? '0' : ' ');
157 width = 0;
158 sign = 1;
159 hexadecimal = 0;
160 max_width = 0;
161 slen = (size_t) -1;
163 p = temp + NGX_INT64_LEN;
165 while (*fmt >= '0' && *fmt <= '9') {
166 width = width * 10 + *fmt++ - '0';
170 for ( ;; ) {
171 switch (*fmt) {
173 case 'u':
174 sign = 0;
175 fmt++;
176 continue;
178 case 'm':
179 max_width = 1;
180 fmt++;
181 continue;
183 case 'X':
184 hexadecimal = 2;
185 sign = 0;
186 fmt++;
187 continue;
189 case 'x':
190 hexadecimal = 1;
191 sign = 0;
192 fmt++;
193 continue;
195 case '*':
196 slen = va_arg(args, size_t);
197 fmt++;
198 continue;
200 default:
201 break;
204 break;
208 switch (*fmt) {
210 case 'V':
211 v = va_arg(args, ngx_str_t *);
213 len = v->len;
214 len = (buf + len < last) ? len : (size_t) (last - buf);
216 buf = ngx_cpymem(buf, v->data, len);
217 fmt++;
219 continue;
221 case 'v':
222 vv = va_arg(args, ngx_variable_value_t *);
224 len = vv->len;
225 len = (buf + len < last) ? len : (size_t) (last - buf);
227 buf = ngx_cpymem(buf, vv->data, len);
228 fmt++;
230 continue;
232 case 's':
233 p = va_arg(args, u_char *);
235 if (slen == (size_t) -1) {
236 while (*p && buf < last) {
237 *buf++ = *p++;
240 } else {
241 len = (buf + slen < last) ? slen : (size_t) (last - buf);
243 buf = ngx_cpymem(buf, p, len);
246 fmt++;
248 continue;
250 case 'O':
251 i64 = (int64_t) va_arg(args, off_t);
252 sign = 1;
253 break;
255 case 'P':
256 i64 = (int64_t) va_arg(args, ngx_pid_t);
257 sign = 1;
258 break;
260 case 'T':
261 i64 = (int64_t) va_arg(args, time_t);
262 sign = 1;
263 break;
265 case 'M':
266 ms = (ngx_msec_t) va_arg(args, ngx_msec_t);
267 if ((ngx_msec_int_t) ms == -1) {
268 sign = 1;
269 i64 = -1;
270 } else {
271 sign = 0;
272 ui64 = (uint64_t) ms;
274 break;
276 case 'z':
277 if (sign) {
278 i64 = (int64_t) va_arg(args, ssize_t);
279 } else {
280 ui64 = (uint64_t) va_arg(args, size_t);
282 break;
284 case 'i':
285 if (sign) {
286 i64 = (int64_t) va_arg(args, ngx_int_t);
287 } else {
288 ui64 = (uint64_t) va_arg(args, ngx_uint_t);
291 if (max_width) {
292 width = NGX_INT_T_LEN;
295 break;
297 case 'd':
298 if (sign) {
299 i64 = (int64_t) va_arg(args, int);
300 } else {
301 ui64 = (uint64_t) va_arg(args, u_int);
303 break;
305 case 'l':
306 if (sign) {
307 i64 = (int64_t) va_arg(args, long);
308 } else {
309 ui64 = (uint64_t) va_arg(args, u_long);
311 break;
313 case 'D':
314 if (sign) {
315 i64 = (int64_t) va_arg(args, int32_t);
316 } else {
317 ui64 = (uint64_t) va_arg(args, uint32_t);
319 break;
321 case 'L':
322 if (sign) {
323 i64 = va_arg(args, int64_t);
324 } else {
325 ui64 = va_arg(args, uint64_t);
327 break;
329 case 'A':
330 if (sign) {
331 i64 = (int64_t) va_arg(args, ngx_atomic_int_t);
332 } else {
333 ui64 = (uint64_t) va_arg(args, ngx_atomic_uint_t);
336 if (max_width) {
337 width = NGX_ATOMIC_T_LEN;
340 break;
342 #if !(NGX_WIN32)
343 case 'r':
344 i64 = (int64_t) va_arg(args, rlim_t);
345 sign = 1;
346 break;
347 #endif
349 case 'p':
350 ui64 = (uintptr_t) va_arg(args, void *);
351 hexadecimal = 2;
352 sign = 0;
353 zero = '0';
354 width = NGX_PTR_SIZE * 2;
355 break;
357 case 'c':
358 d = va_arg(args, int);
359 *buf++ = (u_char) (d & 0xff);
360 fmt++;
362 continue;
364 case 'Z':
365 *buf++ = '\0';
366 fmt++;
368 continue;
370 case 'N':
371 #if (NGX_WIN32)
372 *buf++ = CR;
373 #endif
374 *buf++ = LF;
375 fmt++;
377 continue;
379 case '%':
380 *buf++ = '%';
381 fmt++;
383 continue;
385 default:
386 *buf++ = *fmt++;
388 continue;
391 if (sign) {
392 if (i64 < 0) {
393 *buf++ = '-';
394 ui64 = (uint64_t) -i64;
396 } else {
397 ui64 = (uint64_t) i64;
401 if (hexadecimal == 1) {
402 do {
404 /* the "(uint32_t)" cast disables the BCC's warning */
405 *--p = hex[(uint32_t) (ui64 & 0xf)];
407 } while (ui64 >>= 4);
409 } else if (hexadecimal == 2) {
410 do {
412 /* the "(uint32_t)" cast disables the BCC's warning */
413 *--p = HEX[(uint32_t) (ui64 & 0xf)];
415 } while (ui64 >>= 4);
417 } else if (ui64 <= NGX_MAX_UINT32_VALUE) {
420 * To divide 64-bit number and to find the remainder
421 * on the x86 platform gcc and icc call the libc functions
422 * [u]divdi3() and [u]moddi3(), they call another function
423 * in its turn. On FreeBSD it is the qdivrem() function,
424 * its source code is about 170 lines of the code.
425 * The glibc counterpart is about 150 lines of the code.
427 * For 32-bit numbers and some divisors gcc and icc use
428 * the inlined multiplication and shifts. For example,
429 * unsigned "i32 / 10" is compiled to
431 * (i32 * 0xCCCCCCCD) >> 35
434 ui32 = (uint32_t) ui64;
436 do {
437 *--p = (u_char) (ui32 % 10 + '0');
438 } while (ui32 /= 10);
440 } else {
441 do {
442 *--p = (u_char) (ui64 % 10 + '0');
443 } while (ui64 /= 10);
446 len = (temp + NGX_INT64_LEN) - p;
448 while (len++ < width && buf < last) {
449 *buf++ = zero;
452 len = (temp + NGX_INT64_LEN) - p;
453 if (buf + len > last) {
454 len = last - buf;
457 buf = ngx_cpymem(buf, p, len);
459 fmt++;
461 } else {
462 *buf++ = *fmt++;
466 return buf;
471 * We use ngx_strcasecmp()/ngx_strncasecmp() for 7-bit ASCII strings only,
472 * and implement our own ngx_strcasecmp()/ngx_strncasecmp()
473 * to avoid libc locale overhead. Besides, we use the ngx_uint_t's
474 * instead of the u_char's, because they are slightly faster.
477 ngx_int_t
478 ngx_strcasecmp(u_char *s1, u_char *s2)
480 ngx_uint_t c1, c2;
482 for ( ;; ) {
483 c1 = (ngx_uint_t) *s1++;
484 c2 = (ngx_uint_t) *s2++;
486 c1 = (c1 >= 'A' && c1 <= 'Z') ? (c1 | 0x20) : c1;
487 c2 = (c2 >= 'A' && c2 <= 'Z') ? (c2 | 0x20) : c2;
489 if (c1 == c2) {
491 if (c1) {
492 continue;
495 return 0;
498 return c1 - c2;
503 ngx_int_t
504 ngx_strncasecmp(u_char *s1, u_char *s2, size_t n)
506 ngx_uint_t c1, c2;
508 while (n) {
509 c1 = (ngx_uint_t) *s1++;
510 c2 = (ngx_uint_t) *s2++;
512 c1 = (c1 >= 'A' && c1 <= 'Z') ? (c1 | 0x20) : c1;
513 c2 = (c2 >= 'A' && c2 <= 'Z') ? (c2 | 0x20) : c2;
515 if (c1 == c2) {
517 if (c1) {
518 n--;
519 continue;
522 return 0;
525 return c1 - c2;
528 return 0;
532 u_char *
533 ngx_strnstr(u_char *s1, char *s2, size_t len)
535 u_char c1, c2;
536 size_t n;
538 c2 = *(u_char *) s2++;
540 n = ngx_strlen(s2);
542 do {
543 do {
544 if (len-- == 0) {
545 return NULL;
548 c1 = *s1++;
550 if (c1 == 0) {
551 return NULL;
554 } while (c1 != c2);
556 if (n > len) {
557 return NULL;
560 } while (ngx_strncmp(s1, (u_char *) s2, n) != 0);
562 return --s1;
567 * ngx_strstrn() and ngx_strcasestrn() are intended to search for static
568 * substring with known length in null-terminated string. The argument n
569 * must be length of the second substring - 1.
572 u_char *
573 ngx_strstrn(u_char *s1, char *s2, size_t n)
575 u_char c1, c2;
577 c2 = *(u_char *) s2++;
579 do {
580 do {
581 c1 = *s1++;
583 if (c1 == 0) {
584 return NULL;
587 } while (c1 != c2);
589 } while (ngx_strncmp(s1, (u_char *) s2, n) != 0);
591 return --s1;
595 u_char *
596 ngx_strcasestrn(u_char *s1, char *s2, size_t n)
598 ngx_uint_t c1, c2;
600 c2 = (ngx_uint_t) *s2++;
601 c2 = (c2 >= 'A' && c2 <= 'Z') ? (c2 | 0x20) : c2;
603 do {
604 do {
605 c1 = (ngx_uint_t) *s1++;
607 if (c1 == 0) {
608 return NULL;
611 c1 = (c1 >= 'A' && c1 <= 'Z') ? (c1 | 0x20) : c1;
613 } while (c1 != c2);
615 } while (ngx_strncasecmp(s1, (u_char *) s2, n) != 0);
617 return --s1;
621 ngx_int_t
622 ngx_rstrncmp(u_char *s1, u_char *s2, size_t n)
624 if (n == 0) {
625 return 0;
628 n--;
630 for ( ;; ) {
631 if (s1[n] != s2[n]) {
632 return s1[n] - s2[n];
635 if (n == 0) {
636 return 0;
639 n--;
644 ngx_int_t
645 ngx_rstrncasecmp(u_char *s1, u_char *s2, size_t n)
647 u_char c1, c2;
649 if (n == 0) {
650 return 0;
653 n--;
655 for ( ;; ) {
656 c1 = s1[n];
657 if (c1 >= 'a' && c1 <= 'z') {
658 c1 -= 'a' - 'A';
661 c2 = s2[n];
662 if (c2 >= 'a' && c2 <= 'z') {
663 c2 -= 'a' - 'A';
666 if (c1 != c2) {
667 return c1 - c2;
670 if (n == 0) {
671 return 0;
674 n--;
679 ngx_int_t
680 ngx_memn2cmp(u_char *s1, u_char *s2, size_t n1, size_t n2)
682 size_t n;
683 ngx_int_t m, z;
685 if (n1 <= n2) {
686 n = n1;
687 z = -1;
689 } else {
690 n = n2;
691 z = 1;
694 m = ngx_memcmp(s1, s2, n);
696 if (m || n1 == n2) {
697 return m;
700 return z;
704 ngx_int_t
705 ngx_atoi(u_char *line, size_t n)
707 ngx_int_t value;
709 if (n == 0) {
710 return NGX_ERROR;
713 for (value = 0; n--; line++) {
714 if (*line < '0' || *line > '9') {
715 return NGX_ERROR;
718 value = value * 10 + (*line - '0');
721 if (value < 0) {
722 return NGX_ERROR;
724 } else {
725 return value;
730 ssize_t
731 ngx_atosz(u_char *line, size_t n)
733 ssize_t value;
735 if (n == 0) {
736 return NGX_ERROR;
739 for (value = 0; n--; line++) {
740 if (*line < '0' || *line > '9') {
741 return NGX_ERROR;
744 value = value * 10 + (*line - '0');
747 if (value < 0) {
748 return NGX_ERROR;
750 } else {
751 return value;
756 off_t
757 ngx_atoof(u_char *line, size_t n)
759 off_t value;
761 if (n == 0) {
762 return NGX_ERROR;
765 for (value = 0; n--; line++) {
766 if (*line < '0' || *line > '9') {
767 return NGX_ERROR;
770 value = value * 10 + (*line - '0');
773 if (value < 0) {
774 return NGX_ERROR;
776 } else {
777 return value;
782 time_t
783 ngx_atotm(u_char *line, size_t n)
785 time_t value;
787 if (n == 0) {
788 return NGX_ERROR;
791 for (value = 0; n--; line++) {
792 if (*line < '0' || *line > '9') {
793 return NGX_ERROR;
796 value = value * 10 + (*line - '0');
799 if (value < 0) {
800 return NGX_ERROR;
802 } else {
803 return value;
808 ngx_int_t
809 ngx_hextoi(u_char *line, size_t n)
811 u_char c, ch;
812 ngx_int_t value;
814 if (n == 0) {
815 return NGX_ERROR;
818 for (value = 0; n--; line++) {
819 ch = *line;
821 if (ch >= '0' && ch <= '9') {
822 value = value * 16 + (ch - '0');
823 continue;
826 c = (u_char) (ch | 0x20);
828 if (c >= 'a' && c <= 'f') {
829 value = value * 16 + (c - 'a' + 10);
830 continue;
833 return NGX_ERROR;
836 if (value < 0) {
837 return NGX_ERROR;
839 } else {
840 return value;
845 u_char *
846 ngx_hex_dump(u_char *dst, u_char *src, size_t len)
848 static u_char hex[] = "0123456789abcdef";
850 while (len--) {
851 *dst++ = hex[*src >> 4];
852 *dst++ = hex[*src++ & 0xf];
855 return dst;
859 void
860 ngx_encode_base64(ngx_str_t *dst, ngx_str_t *src)
862 u_char *d, *s;
863 size_t len;
864 static u_char basis64[] =
865 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
867 len = src->len;
868 s = src->data;
869 d = dst->data;
871 while (len > 2) {
872 *d++ = basis64[(s[0] >> 2) & 0x3f];
873 *d++ = basis64[((s[0] & 3) << 4) | (s[1] >> 4)];
874 *d++ = basis64[((s[1] & 0x0f) << 2) | (s[2] >> 6)];
875 *d++ = basis64[s[2] & 0x3f];
877 s += 3;
878 len -= 3;
881 if (len) {
882 *d++ = basis64[(s[0] >> 2) & 0x3f];
884 if (len == 1) {
885 *d++ = basis64[(s[0] & 3) << 4];
886 *d++ = '=';
888 } else {
889 *d++ = basis64[((s[0] & 3) << 4) | (s[1] >> 4)];
890 *d++ = basis64[(s[1] & 0x0f) << 2];
893 *d++ = '=';
896 dst->len = d - dst->data;
900 ngx_int_t
901 ngx_decode_base64(ngx_str_t *dst, ngx_str_t *src)
903 size_t len;
904 u_char *d, *s;
905 static u_char basis64[] = {
906 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77,
907 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77,
908 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 62, 77, 77, 77, 63,
909 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 77, 77, 77, 77, 77, 77,
910 77, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
911 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 77, 77, 77, 77, 77,
912 77, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
913 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 77, 77, 77, 77, 77,
915 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77,
916 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77,
917 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77,
918 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77,
919 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77,
920 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77,
921 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77,
922 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77
925 for (len = 0; len < src->len; len++) {
926 if (src->data[len] == '=') {
927 break;
930 if (basis64[src->data[len]] == 77) {
931 return NGX_ERROR;
935 if (len % 4 == 1) {
936 return NGX_ERROR;
939 s = src->data;
940 d = dst->data;
942 while (len > 3) {
943 *d++ = (u_char) (basis64[s[0]] << 2 | basis64[s[1]] >> 4);
944 *d++ = (u_char) (basis64[s[1]] << 4 | basis64[s[2]] >> 2);
945 *d++ = (u_char) (basis64[s[2]] << 6 | basis64[s[3]]);
947 s += 4;
948 len -= 4;
951 if (len > 1) {
952 *d++ = (u_char) (basis64[s[0]] << 2 | basis64[s[1]] >> 4);
955 if (len > 2) {
956 *d++ = (u_char) (basis64[s[1]] << 4 | basis64[s[2]] >> 2);
959 dst->len = d - dst->data;
961 return NGX_OK;
966 * ngx_utf8_decode() decodes two and more bytes UTF sequences only
967 * the return values:
968 * 0x80 - 0x10ffff valid character
969 * 0x110000 - 0xfffffffd invalid sequence
970 * 0xfffffffe incomplete sequence
971 * 0xffffffff error
974 uint32_t
975 ngx_utf8_decode(u_char **p, size_t n)
977 size_t len;
978 uint32_t u, i, valid;
980 u = **p;
982 if (u > 0xf0) {
984 u &= 0x07;
985 valid = 0xffff;
986 len = 3;
988 } else if (u > 0xe0) {
990 u &= 0x0f;
991 valid = 0x7ff;
992 len = 2;
994 } else if (u > 0xc0) {
996 u &= 0x1f;
997 valid = 0x7f;
998 len = 1;
1000 } else {
1001 (*p)++;
1002 return 0xffffffff;
1005 if (n - 1 < len) {
1006 return 0xfffffffe;
1009 (*p)++;
1011 while (len) {
1012 i = *(*p)++;
1014 if (i < 0x80) {
1015 return 0xffffffff;
1018 u = (u << 6) | (i & 0x3f);
1020 len--;
1023 if (u > valid) {
1024 return u;
1027 return 0xffffffff;
1031 size_t
1032 ngx_utf8_length(u_char *p, size_t n)
1034 u_char c, *last;
1035 size_t len;
1037 last = p + n;
1039 for (len = 0; p < last; len++) {
1041 c = *p;
1043 if (c < 0x80) {
1044 p++;
1045 continue;
1048 if (ngx_utf8_decode(&p, n) > 0x10ffff) {
1049 /* invalid UTF-8 */
1050 return n;
1054 return len;
1058 u_char *
1059 ngx_utf8_cpystrn(u_char *dst, u_char *src, size_t n, size_t len)
1061 u_char c, *next;
1063 if (n == 0) {
1064 return dst;
1067 while (--n) {
1069 c = *src;
1070 *dst = c;
1072 if (c < 0x80) {
1074 if (c != '\0') {
1075 dst++;
1076 src++;
1077 len--;
1079 continue;
1082 return dst;
1085 next = src;
1087 if (ngx_utf8_decode(&next, len) > 0x10ffff) {
1088 /* invalid UTF-8 */
1089 break;
1092 len--;
1094 while (src < next) {
1095 *++dst = *++src;
1096 len--;
1100 *dst = '\0';
1102 return dst;
1106 uintptr_t
1107 ngx_escape_uri(u_char *dst, u_char *src, size_t size, ngx_uint_t type)
1109 ngx_uint_t i, n;
1110 uint32_t *escape;
1111 static u_char hex[] = "0123456789abcdef";
1113 /* " ", "#", "%", "?", %00-%1F, %7F-%FF */
1115 static uint32_t uri[] = {
1116 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
1118 /* ?>=< ;:98 7654 3210 /.-, +*)( '&%$ #"! */
1119 0x80000029, /* 1000 0000 0000 0000 0000 0000 0010 1001 */
1121 /* _^]\ [ZYX WVUT SRQP ONML KJIH GFED CBA@ */
1122 0x00000000, /* 0000 0000 0000 0000 0000 0000 0000 0000 */
1124 /* ~}| {zyx wvut srqp onml kjih gfed cba` */
1125 0x80000000, /* 1000 0000 0000 0000 0000 0000 0000 0000 */
1127 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
1128 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
1129 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
1130 0xffffffff /* 1111 1111 1111 1111 1111 1111 1111 1111 */
1133 /* " ", "#", "%", "+", "?", %00-%1F, %7F-%FF */
1135 static uint32_t args[] = {
1136 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
1138 /* ?>=< ;:98 7654 3210 /.-, +*)( '&%$ #"! */
1139 0x80000829, /* 1000 0000 0000 0000 0000 1000 0010 1001 */
1141 /* _^]\ [ZYX WVUT SRQP ONML KJIH GFED CBA@ */
1142 0x00000000, /* 0000 0000 0000 0000 0000 0000 0000 0000 */
1144 /* ~}| {zyx wvut srqp onml kjih gfed cba` */
1145 0x80000000, /* 1000 0000 0000 0000 0000 0000 0000 0000 */
1147 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
1148 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
1149 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
1150 0xffffffff /* 1111 1111 1111 1111 1111 1111 1111 1111 */
1153 /* " ", "#", """, "%", "'", %00-%1F, %7F-%FF */
1155 static uint32_t html[] = {
1156 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
1158 /* ?>=< ;:98 7654 3210 /.-, +*)( '&%$ #"! */
1159 0x000000ad, /* 0000 0000 0000 0000 0000 0000 1010 1101 */
1161 /* _^]\ [ZYX WVUT SRQP ONML KJIH GFED CBA@ */
1162 0x00000000, /* 0000 0000 0000 0000 0000 0000 0000 0000 */
1164 /* ~}| {zyx wvut srqp onml kjih gfed cba` */
1165 0x80000000, /* 1000 0000 0000 0000 0000 0000 0000 0000 */
1167 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
1168 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
1169 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
1170 0xffffffff /* 1111 1111 1111 1111 1111 1111 1111 1111 */
1173 /* " ", """, "%", "'", %00-%1F, %7F-%FF */
1175 static uint32_t refresh[] = {
1176 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
1178 /* ?>=< ;:98 7654 3210 /.-, +*)( '&%$ #"! */
1179 0x00000085, /* 0000 0000 0000 0000 0000 0000 1000 0101 */
1181 /* _^]\ [ZYX WVUT SRQP ONML KJIH GFED CBA@ */
1182 0x00000000, /* 0000 0000 0000 0000 0000 0000 0000 0000 */
1184 /* ~}| {zyx wvut srqp onml kjih gfed cba` */
1185 0x80000000, /* 1000 0000 0000 0000 0000 0000 0000 0000 */
1187 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
1188 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
1189 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
1190 0xffffffff /* 1111 1111 1111 1111 1111 1111 1111 1111 */
1193 /* " ", "%", %00-%1F */
1195 static uint32_t memcached[] = {
1196 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
1198 /* ?>=< ;:98 7654 3210 /.-, +*)( '&%$ #"! */
1199 0x00000021, /* 0000 0000 0000 0000 0000 0000 0010 0001 */
1201 /* _^]\ [ZYX WVUT SRQP ONML KJIH GFED CBA@ */
1202 0x00000000, /* 0000 0000 0000 0000 0000 0000 0000 0000 */
1204 /* ~}| {zyx wvut srqp onml kjih gfed cba` */
1205 0x00000000, /* 0000 0000 0000 0000 0000 0000 0000 0000 */
1207 0x00000000, /* 0000 0000 0000 0000 0000 0000 0000 0000 */
1208 0x00000000, /* 0000 0000 0000 0000 0000 0000 0000 0000 */
1209 0x00000000, /* 0000 0000 0000 0000 0000 0000 0000 0000 */
1210 0x00000000, /* 0000 0000 0000 0000 0000 0000 0000 0000 */
1213 /* mail_auth is the same as memcached */
1215 static uint32_t *map[] =
1216 { uri, args, html, refresh, memcached, memcached };
1219 escape = map[type];
1221 if (dst == NULL) {
1223 /* find the number of the characters to be escaped */
1225 n = 0;
1227 for (i = 0; i < size; i++) {
1228 if (escape[*src >> 5] & (1 << (*src & 0x1f))) {
1229 n++;
1231 src++;
1234 return (uintptr_t) n;
1237 for (i = 0; i < size; i++) {
1238 if (escape[*src >> 5] & (1 << (*src & 0x1f))) {
1239 *dst++ = '%';
1240 *dst++ = hex[*src >> 4];
1241 *dst++ = hex[*src & 0xf];
1242 src++;
1244 } else {
1245 *dst++ = *src++;
1249 return (uintptr_t) dst;
1253 void
1254 ngx_unescape_uri(u_char **dst, u_char **src, size_t size, ngx_uint_t type)
1256 u_char *d, *s, ch, c, decoded;
1257 enum {
1258 sw_usual = 0,
1259 sw_quoted,
1260 sw_quoted_second
1261 } state;
1263 d = *dst;
1264 s = *src;
1266 state = 0;
1267 decoded = 0;
1269 while (size--) {
1271 ch = *s++;
1273 switch (state) {
1274 case sw_usual:
1275 if (ch == '?'
1276 && (type & (NGX_UNESCAPE_URI|NGX_UNESCAPE_REDIRECT)))
1278 *d++ = ch;
1279 goto done;
1282 if (ch == '%') {
1283 state = sw_quoted;
1284 break;
1287 *d++ = ch;
1288 break;
1290 case sw_quoted:
1292 if (ch >= '0' && ch <= '9') {
1293 decoded = (u_char) (ch - '0');
1294 state = sw_quoted_second;
1295 break;
1298 c = (u_char) (ch | 0x20);
1299 if (c >= 'a' && c <= 'f') {
1300 decoded = (u_char) (c - 'a' + 10);
1301 state = sw_quoted_second;
1302 break;
1305 /* the invalid quoted character */
1307 state = sw_usual;
1309 *d++ = ch;
1311 break;
1313 case sw_quoted_second:
1315 state = sw_usual;
1317 if (ch >= '0' && ch <= '9') {
1318 ch = (u_char) ((decoded << 4) + ch - '0');
1320 if (type & NGX_UNESCAPE_REDIRECT) {
1321 if (ch > '%' && ch < 0x7f) {
1322 *d++ = ch;
1323 break;
1326 *d++ = '%'; *d++ = *(s - 2); *d++ = *(s - 1);
1328 break;
1331 *d++ = ch;
1333 break;
1336 c = (u_char) (ch | 0x20);
1337 if (c >= 'a' && c <= 'f') {
1338 ch = (u_char) ((decoded << 4) + c - 'a' + 10);
1340 if (type & NGX_UNESCAPE_URI) {
1341 if (ch == '?') {
1342 *d++ = ch;
1343 goto done;
1346 *d++ = ch;
1347 break;
1350 if (type & NGX_UNESCAPE_REDIRECT) {
1351 if (ch == '?') {
1352 *d++ = ch;
1353 goto done;
1356 if (ch > '%' && ch < 0x7f) {
1357 *d++ = ch;
1358 break;
1361 *d++ = '%'; *d++ = *(s - 2); *d++ = *(s - 1);
1362 break;
1365 *d++ = ch;
1367 break;
1370 /* the invalid quoted character */
1372 break;
1376 done:
1378 *dst = d;
1379 *src = s;
1383 uintptr_t
1384 ngx_escape_html(u_char *dst, u_char *src, size_t size)
1386 u_char ch;
1387 ngx_uint_t i, len;
1389 if (dst == NULL) {
1391 len = 0;
1393 for (i = 0; i < size; i++) {
1394 switch (*src++) {
1396 case '<':
1397 len += sizeof("&lt;") - 2;
1398 break;
1400 case '>':
1401 len += sizeof("&gt;") - 2;
1402 break;
1404 case '&':
1405 len += sizeof("&amp;") - 2;
1406 break;
1408 default:
1409 break;
1413 return (uintptr_t) len;
1416 for (i = 0; i < size; i++) {
1417 ch = *src++;
1419 switch (ch) {
1421 case '<':
1422 *dst++ = '&'; *dst++ = 'l'; *dst++ = 't'; *dst++ = ';';
1423 break;
1425 case '>':
1426 *dst++ = '&'; *dst++ = 'g'; *dst++ = 't'; *dst++ = ';';
1427 break;
1429 case '&':
1430 *dst++ = '&'; *dst++ = 'a'; *dst++ = 'm'; *dst++ = 'p';
1431 *dst++ = ';';
1432 break;
1434 default:
1435 *dst++ = ch;
1436 break;
1440 return (uintptr_t) dst;
1444 /* ngx_sort() is implemented as insertion sort because we need stable sort */
1446 void
1447 ngx_sort(void *base, size_t n, size_t size,
1448 ngx_int_t (*cmp)(const void *, const void *))
1450 u_char *p1, *p2, *p;
1452 p = ngx_alloc(size, ngx_cycle->log);
1453 if (p == NULL) {
1454 return;
1457 for (p1 = (u_char *) base + size;
1458 p1 < (u_char *) base + n * size;
1459 p1 += size)
1461 ngx_memcpy(p, p1, size);
1463 for (p2 = p1;
1464 p2 > (u_char *) base && cmp(p2 - size, p) > 0;
1465 p2 -= size)
1467 ngx_memcpy(p2, p2 - size, size);
1470 ngx_memcpy(p2, p, size);
1473 ngx_free(p);
1477 #if (NGX_MEMCPY_LIMIT)
1479 void *
1480 ngx_memcpy(void *dst, void *src, size_t n)
1482 if (n > NGX_MEMCPY_LIMIT) {
1483 ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0, "memcpy %uz bytes", n);
1484 ngx_debug_point();
1487 return memcpy(dst, src, n);
1490 #endif