3 * Copyright (C) Igor Sysoev
7 #include <ngx_config.h>
12 ngx_strlow(u_char
*dst
, u_char
*src
, size_t n
)
15 *dst
= ngx_tolower(*src
);
23 ngx_cpystrn(u_char
*dst
, u_char
*src
, size_t n
)
29 for ( /* void */ ; --n
; dst
++, src
++) {
44 ngx_pstrdup(ngx_pool_t
*pool
, ngx_str_t
*src
)
48 dst
= ngx_pnalloc(pool
, src
->len
);
53 ngx_memcpy(dst
, src
->data
, src
->len
);
61 * %[0][width][x][X]O off_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
75 * %v ngx_variable_value_t *
76 * %s null-terminated string
77 * %*s length and string
85 * %S null-teminated wchar string
91 ngx_sprintf(u_char
*buf
, const char *fmt
, ...)
97 p
= ngx_vsnprintf(buf
, /* STUB */ 65536, fmt
, args
);
105 ngx_snprintf(u_char
*buf
, size_t max
, const char *fmt
, ...)
111 p
= ngx_vsnprintf(buf
, max
, fmt
, args
);
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
132 ngx_uint_t width
, sign
, hexadecimal
, max_width
;
134 ngx_variable_value_t
*vv
;
135 static u_char hex
[] = "0123456789abcdef";
136 static u_char HEX
[] = "0123456789ABCDEF";
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
156 zero
= (u_char
) ((*++fmt
== '0') ? '0' : ' ');
163 p
= temp
+ NGX_INT64_LEN
;
165 while (*fmt
>= '0' && *fmt
<= '9') {
166 width
= width
* 10 + *fmt
++ - '0';
196 slen
= va_arg(args
, size_t);
211 v
= va_arg(args
, ngx_str_t
*);
214 len
= (buf
+ len
< last
) ? len
: (size_t) (last
- buf
);
216 buf
= ngx_cpymem(buf
, v
->data
, len
);
222 vv
= va_arg(args
, ngx_variable_value_t
*);
225 len
= (buf
+ len
< last
) ? len
: (size_t) (last
- buf
);
227 buf
= ngx_cpymem(buf
, vv
->data
, len
);
233 p
= va_arg(args
, u_char
*);
235 if (slen
== (size_t) -1) {
236 while (*p
&& buf
< last
) {
241 len
= (buf
+ slen
< last
) ? slen
: (size_t) (last
- buf
);
243 buf
= ngx_cpymem(buf
, p
, len
);
251 i64
= (int64_t) va_arg(args
, off_t
);
256 i64
= (int64_t) va_arg(args
, ngx_pid_t
);
261 i64
= (int64_t) va_arg(args
, time_t);
266 ms
= (ngx_msec_t
) va_arg(args
, ngx_msec_t
);
267 if ((ngx_msec_int_t
) ms
== -1) {
272 ui64
= (uint64_t) ms
;
278 i64
= (int64_t) va_arg(args
, ssize_t
);
280 ui64
= (uint64_t) va_arg(args
, size_t);
286 i64
= (int64_t) va_arg(args
, ngx_int_t
);
288 ui64
= (uint64_t) va_arg(args
, ngx_uint_t
);
292 width
= NGX_INT_T_LEN
;
299 i64
= (int64_t) va_arg(args
, int);
301 ui64
= (uint64_t) va_arg(args
, u_int
);
307 i64
= (int64_t) va_arg(args
, long);
309 ui64
= (uint64_t) va_arg(args
, u_long
);
315 i64
= (int64_t) va_arg(args
, int32_t);
317 ui64
= (uint64_t) va_arg(args
, uint32_t);
323 i64
= va_arg(args
, int64_t);
325 ui64
= va_arg(args
, uint64_t);
331 i64
= (int64_t) va_arg(args
, ngx_atomic_int_t
);
333 ui64
= (uint64_t) va_arg(args
, ngx_atomic_uint_t
);
337 width
= NGX_ATOMIC_T_LEN
;
344 i64
= (int64_t) va_arg(args
, rlim_t
);
350 ui64
= (uintptr_t) va_arg(args
, void *);
354 width
= NGX_PTR_SIZE
* 2;
358 d
= va_arg(args
, int);
359 *buf
++ = (u_char
) (d
& 0xff);
394 ui64
= (uint64_t) -i64
;
397 ui64
= (uint64_t) i64
;
401 if (hexadecimal
== 1) {
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) {
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
;
437 *--p
= (u_char
) (ui32
% 10 + '0');
438 } while (ui32
/= 10);
442 *--p
= (u_char
) (ui64
% 10 + '0');
443 } while (ui64
/= 10);
446 len
= (temp
+ NGX_INT64_LEN
) - p
;
448 while (len
++ < width
&& buf
< last
) {
452 len
= (temp
+ NGX_INT64_LEN
) - p
;
453 if (buf
+ len
> last
) {
457 buf
= ngx_cpymem(buf
, p
, len
);
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.
478 ngx_strcasecmp(u_char
*s1
, u_char
*s2
)
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
;
504 ngx_strncasecmp(u_char
*s1
, u_char
*s2
, size_t 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
;
533 ngx_strnstr(u_char
*s1
, char *s2
, size_t len
)
538 c2
= *(u_char
*) s2
++;
560 } while (ngx_strncmp(s1
, (u_char
*) s2
, n
) != 0);
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.
573 ngx_strstrn(u_char
*s1
, char *s2
, size_t n
)
577 c2
= *(u_char
*) s2
++;
589 } while (ngx_strncmp(s1
, (u_char
*) s2
, n
) != 0);
596 ngx_strcasestrn(u_char
*s1
, char *s2
, size_t n
)
600 c2
= (ngx_uint_t
) *s2
++;
601 c2
= (c2
>= 'A' && c2
<= 'Z') ? (c2
| 0x20) : c2
;
605 c1
= (ngx_uint_t
) *s1
++;
611 c1
= (c1
>= 'A' && c1
<= 'Z') ? (c1
| 0x20) : c1
;
615 } while (ngx_strncasecmp(s1
, (u_char
*) s2
, n
) != 0);
622 ngx_rstrncmp(u_char
*s1
, u_char
*s2
, size_t n
)
631 if (s1
[n
] != s2
[n
]) {
632 return s1
[n
] - s2
[n
];
645 ngx_rstrncasecmp(u_char
*s1
, u_char
*s2
, size_t n
)
657 if (c1
>= 'a' && c1
<= 'z') {
662 if (c2
>= 'a' && c2
<= 'z') {
680 ngx_memn2cmp(u_char
*s1
, u_char
*s2
, size_t n1
, size_t n2
)
694 m
= ngx_memcmp(s1
, s2
, n
);
705 ngx_atoi(u_char
*line
, size_t n
)
713 for (value
= 0; n
--; line
++) {
714 if (*line
< '0' || *line
> '9') {
718 value
= value
* 10 + (*line
- '0');
731 ngx_atosz(u_char
*line
, size_t n
)
739 for (value
= 0; n
--; line
++) {
740 if (*line
< '0' || *line
> '9') {
744 value
= value
* 10 + (*line
- '0');
757 ngx_atoof(u_char
*line
, size_t n
)
765 for (value
= 0; n
--; line
++) {
766 if (*line
< '0' || *line
> '9') {
770 value
= value
* 10 + (*line
- '0');
783 ngx_atotm(u_char
*line
, size_t n
)
791 for (value
= 0; n
--; line
++) {
792 if (*line
< '0' || *line
> '9') {
796 value
= value
* 10 + (*line
- '0');
809 ngx_hextoi(u_char
*line
, size_t n
)
818 for (value
= 0; n
--; line
++) {
821 if (ch
>= '0' && ch
<= '9') {
822 value
= value
* 16 + (ch
- '0');
826 c
= (u_char
) (ch
| 0x20);
828 if (c
>= 'a' && c
<= 'f') {
829 value
= value
* 16 + (c
- 'a' + 10);
846 ngx_hex_dump(u_char
*dst
, u_char
*src
, size_t len
)
848 static u_char hex
[] = "0123456789abcdef";
851 *dst
++ = hex
[*src
>> 4];
852 *dst
++ = hex
[*src
++ & 0xf];
860 ngx_encode_base64(ngx_str_t
*dst
, ngx_str_t
*src
)
864 static u_char basis64
[] =
865 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
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];
882 *d
++ = basis64
[(s
[0] >> 2) & 0x3f];
885 *d
++ = basis64
[(s
[0] & 3) << 4];
889 *d
++ = basis64
[((s
[0] & 3) << 4) | (s
[1] >> 4)];
890 *d
++ = basis64
[(s
[1] & 0x0f) << 2];
896 dst
->len
= d
- dst
->data
;
901 ngx_decode_base64(ngx_str_t
*dst
, ngx_str_t
*src
)
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
] == '=') {
930 if (basis64
[src
->data
[len
]] == 77) {
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]]);
952 *d
++ = (u_char
) (basis64
[s
[0]] << 2 | basis64
[s
[1]] >> 4);
956 *d
++ = (u_char
) (basis64
[s
[1]] << 4 | basis64
[s
[2]] >> 2);
959 dst
->len
= d
- dst
->data
;
966 * ngx_utf8_decode() decodes two and more bytes UTF sequences only
968 * 0x80 - 0x10ffff valid character
969 * 0x110000 - 0xfffffffd invalid sequence
970 * 0xfffffffe incomplete sequence
975 ngx_utf8_decode(u_char
**p
, size_t n
)
978 uint32_t u
, i
, valid
;
988 } else if (u
> 0xe0) {
994 } else if (u
> 0xc0) {
1018 u
= (u
<< 6) | (i
& 0x3f);
1032 ngx_utf8_length(u_char
*p
, size_t n
)
1039 for (len
= 0; p
< last
; len
++) {
1048 if (ngx_utf8_decode(&p
, n
) > 0x10ffff) {
1059 ngx_utf8_cpystrn(u_char
*dst
, u_char
*src
, size_t n
, size_t len
)
1087 if (ngx_utf8_decode(&next
, len
) > 0x10ffff) {
1094 while (src
< next
) {
1107 ngx_escape_uri(u_char
*dst
, u_char
*src
, size_t size
, ngx_uint_t type
)
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
};
1223 /* find the number of the characters to be escaped */
1227 for (i
= 0; i
< size
; i
++) {
1228 if (escape
[*src
>> 5] & (1 << (*src
& 0x1f))) {
1234 return (uintptr_t) n
;
1237 for (i
= 0; i
< size
; i
++) {
1238 if (escape
[*src
>> 5] & (1 << (*src
& 0x1f))) {
1240 *dst
++ = hex
[*src
>> 4];
1241 *dst
++ = hex
[*src
& 0xf];
1249 return (uintptr_t) dst
;
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
;
1276 && (type
& (NGX_UNESCAPE_URI
|NGX_UNESCAPE_REDIRECT
)))
1292 if (ch
>= '0' && ch
<= '9') {
1293 decoded
= (u_char
) (ch
- '0');
1294 state
= sw_quoted_second
;
1298 c
= (u_char
) (ch
| 0x20);
1299 if (c
>= 'a' && c
<= 'f') {
1300 decoded
= (u_char
) (c
- 'a' + 10);
1301 state
= sw_quoted_second
;
1305 /* the invalid quoted character */
1313 case sw_quoted_second
:
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) {
1326 *d
++ = '%'; *d
++ = *(s
- 2); *d
++ = *(s
- 1);
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
) {
1350 if (type
& NGX_UNESCAPE_REDIRECT
) {
1356 if (ch
> '%' && ch
< 0x7f) {
1361 *d
++ = '%'; *d
++ = *(s
- 2); *d
++ = *(s
- 1);
1370 /* the invalid quoted character */
1384 ngx_escape_html(u_char
*dst
, u_char
*src
, size_t size
)
1393 for (i
= 0; i
< size
; i
++) {
1397 len
+= sizeof("<") - 2;
1401 len
+= sizeof(">") - 2;
1405 len
+= sizeof("&") - 2;
1413 return (uintptr_t) len
;
1416 for (i
= 0; i
< size
; i
++) {
1422 *dst
++ = '&'; *dst
++ = 'l'; *dst
++ = 't'; *dst
++ = ';';
1426 *dst
++ = '&'; *dst
++ = 'g'; *dst
++ = 't'; *dst
++ = ';';
1430 *dst
++ = '&'; *dst
++ = 'a'; *dst
++ = 'm'; *dst
++ = 'p';
1440 return (uintptr_t) dst
;
1444 /* ngx_sort() is implemented as insertion sort because we need stable sort */
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
);
1457 for (p1
= (u_char
*) base
+ size
;
1458 p1
< (u_char
*) base
+ n
* size
;
1461 ngx_memcpy(p
, p1
, size
);
1464 p2
> (u_char
*) base
&& cmp(p2
- size
, p
) > 0;
1467 ngx_memcpy(p2
, p2
- size
, size
);
1470 ngx_memcpy(p2
, p
, size
);
1477 #if (NGX_MEMCPY_LIMIT)
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
);
1487 return memcpy(dst
, src
, n
);