blob: f513753a131f07bc02729d5a4c8bf496234cc029 [file] [log] [blame]
Igor Sysoev6de5c2c2002-08-06 16:39:45 +00001
Igor Sysoevd90282d2004-09-28 08:34:51 +00002/*
Igor Sysoevff8da912004-09-29 16:00:49 +00003 * Copyright (C) Igor Sysoev
Igor Sysoevd90282d2004-09-28 08:34:51 +00004 */
5
6
Igor Sysoev6de5c2c2002-08-06 16:39:45 +00007#include <ngx_config.h>
Igor Sysoevdc479b42003-03-20 16:09:44 +00008#include <ngx_core.h>
Igor Sysoev6de5c2c2002-08-06 16:39:45 +00009
10
Igor Sysoev74b7e5f2008-11-10 15:20:59 +000011static u_char *ngx_sprintf_num(u_char *buf, u_char *last, uint64_t ui64,
12 u_char zero, ngx_uint_t hexadecimal, ngx_uint_t width);
13
14
Igor Sysoev777b0192008-08-04 10:07:00 +000015void
16ngx_strlow(u_char *dst, u_char *src, size_t n)
17{
Igor Sysoev612ecb72009-11-02 17:12:09 +000018 while (n) {
Igor Sysoev777b0192008-08-04 10:07:00 +000019 *dst = ngx_tolower(*src);
20 dst++;
21 src++;
Igor Sysoev612ecb72009-11-02 17:12:09 +000022 n--;
Igor Sysoev777b0192008-08-04 10:07:00 +000023 }
24}
25
26
Igor Sysoevd039a2e2005-02-22 14:40:13 +000027u_char *
28ngx_cpystrn(u_char *dst, u_char *src, size_t n)
Igor Sysoev6de5c2c2002-08-06 16:39:45 +000029{
Igor Sysoev3d09c8d2003-05-06 17:03:16 +000030 if (n == 0) {
Igor Sysoev6de5c2c2002-08-06 16:39:45 +000031 return dst;
Igor Sysoev3d09c8d2003-05-06 17:03:16 +000032 }
Igor Sysoev6de5c2c2002-08-06 16:39:45 +000033
Igor Sysoev8e5f0ac2009-06-05 12:33:49 +000034 while (--n) {
Igor Sysoev6de5c2c2002-08-06 16:39:45 +000035 *dst = *src;
36
Igor Sysoev3d09c8d2003-05-06 17:03:16 +000037 if (*dst == '\0') {
Igor Sysoev6de5c2c2002-08-06 16:39:45 +000038 return dst;
Igor Sysoev3d09c8d2003-05-06 17:03:16 +000039 }
Igor Sysoev8e5f0ac2009-06-05 12:33:49 +000040
41 dst++;
42 src++;
Igor Sysoev6de5c2c2002-08-06 16:39:45 +000043 }
44
45 *dst = '\0';
46
47 return dst;
48}
Igor Sysoevdc479b42003-03-20 16:09:44 +000049
50
Igor Sysoevd039a2e2005-02-22 14:40:13 +000051u_char *
52ngx_pstrdup(ngx_pool_t *pool, ngx_str_t *src)
Igor Sysoev805d9db2005-02-03 19:33:37 +000053{
54 u_char *dst;
55
Igor Sysoev7f6b2ff2008-06-17 15:00:30 +000056 dst = ngx_pnalloc(pool, src->len);
Igor Sysoevc1571722005-03-19 12:38:37 +000057 if (dst == NULL) {
Igor Sysoev805d9db2005-02-03 19:33:37 +000058 return NULL;
59 }
60
61 ngx_memcpy(dst, src->data, src->len);
62
63 return dst;
64}
65
66
Igor Sysoevc0edbcc2004-10-21 15:34:38 +000067/*
68 * supported formats:
Igor Sysoev42b12b32004-12-02 18:40:46 +000069 * %[0][width][x][X]O off_t
Igor Sysoev1b735832004-11-11 14:07:14 +000070 * %[0][width]T time_t
71 * %[0][width][u][x|X]z ssize_t/size_t
72 * %[0][width][u][x|X]d int/u_int
73 * %[0][width][u][x|X]l long
74 * %[0][width|m][u][x|X]i ngx_int_t/ngx_uint_t
75 * %[0][width][u][x|X]D int32_t/uint32_t
76 * %[0][width][u][x|X]L int64_t/uint64_t
Igor Sysoev4a715592005-02-24 12:29:09 +000077 * %[0][width|m][u][x|X]A ngx_atomic_int_t/ngx_atomic_uint_t
Igor Sysoev503b9712010-05-12 13:12:31 +000078 * %[0][width][.width]f double, max valid number fits to %18.15f
Igor Sysoev1b735832004-11-11 14:07:14 +000079 * %P ngx_pid_t
Igor Sysoev208eed22005-10-07 13:30:52 +000080 * %M ngx_msec_t
Igor Sysoev1b735832004-11-11 14:07:14 +000081 * %r rlim_t
Igor Sysoev0d4b3722007-08-20 09:57:19 +000082 * %p void *
83 * %V ngx_str_t *
84 * %v ngx_variable_value_t *
Igor Sysoev1b735832004-11-11 14:07:14 +000085 * %s null-terminated string
Igor Sysoev79d9a042007-12-24 17:05:16 +000086 * %*s length and string
Igor Sysoev1b735832004-11-11 14:07:14 +000087 * %Z '\0'
Igor Sysoev85ef94b2005-06-23 13:41:06 +000088 * %N '\n'
Igor Sysoev1b735832004-11-11 14:07:14 +000089 * %c char
90 * %% %
Igor Sysoevc0edbcc2004-10-21 15:34:38 +000091 *
Igor Sysoev1b735832004-11-11 14:07:14 +000092 * reserved:
93 * %t ptrdiff_t
Igor Sysoev9262c612009-08-26 15:03:53 +000094 * %S null-terminated wchar string
Igor Sysoev1b735832004-11-11 14:07:14 +000095 * %C wchar
Igor Sysoevc0edbcc2004-10-21 15:34:38 +000096 */
97
Igor Sysoev1b735832004-11-11 14:07:14 +000098
Igor Sysoev4d656dc2005-03-22 16:02:46 +000099u_char * ngx_cdecl
Igor Sysoevd039a2e2005-02-22 14:40:13 +0000100ngx_sprintf(u_char *buf, const char *fmt, ...)
Igor Sysoevc0edbcc2004-10-21 15:34:38 +0000101{
Igor Sysoev1b735832004-11-11 14:07:14 +0000102 u_char *p;
103 va_list args;
Igor Sysoevc0edbcc2004-10-21 15:34:38 +0000104
Igor Sysoev1b735832004-11-11 14:07:14 +0000105 va_start(args, fmt);
Igor Sysoev4e1fe032009-04-27 12:51:33 +0000106 p = ngx_vslprintf(buf, (void *) -1, fmt, args);
Igor Sysoev1b735832004-11-11 14:07:14 +0000107 va_end(args);
Igor Sysoevc0edbcc2004-10-21 15:34:38 +0000108
Igor Sysoev1b735832004-11-11 14:07:14 +0000109 return p;
110}
111
112
Igor Sysoev4d656dc2005-03-22 16:02:46 +0000113u_char * ngx_cdecl
Igor Sysoevd039a2e2005-02-22 14:40:13 +0000114ngx_snprintf(u_char *buf, size_t max, const char *fmt, ...)
Igor Sysoev1b735832004-11-11 14:07:14 +0000115{
116 u_char *p;
117 va_list args;
118
119 va_start(args, fmt);
Igor Sysoev4e1fe032009-04-27 12:51:33 +0000120 p = ngx_vslprintf(buf, buf + max, fmt, args);
121 va_end(args);
122
123 return p;
124}
125
126
127u_char * ngx_cdecl
128ngx_slprintf(u_char *buf, u_char *last, const char *fmt, ...)
129{
130 u_char *p;
131 va_list args;
132
133 va_start(args, fmt);
134 p = ngx_vslprintf(buf, last, fmt, args);
Igor Sysoev1b735832004-11-11 14:07:14 +0000135 va_end(args);
136
137 return p;
138}
139
140
Igor Sysoevd039a2e2005-02-22 14:40:13 +0000141u_char *
Igor Sysoev4e1fe032009-04-27 12:51:33 +0000142ngx_vslprintf(u_char *buf, u_char *last, const char *fmt, va_list args)
Igor Sysoev1b735832004-11-11 14:07:14 +0000143{
Igor Sysoev4e1fe032009-04-27 12:51:33 +0000144 u_char *p, zero;
Igor Sysoevf42ed052007-07-17 09:23:23 +0000145 int d;
Igor Sysoev503b9712010-05-12 13:12:31 +0000146 double f, scale;
Igor Sysoev79d9a042007-12-24 17:05:16 +0000147 size_t len, slen;
Igor Sysoevf42ed052007-07-17 09:23:23 +0000148 int64_t i64;
149 uint64_t ui64;
150 ngx_msec_t ms;
Igor Sysoev612ecb72009-11-02 17:12:09 +0000151 ngx_uint_t width, sign, hex, max_width, frac_width, n;
Igor Sysoev0d4b3722007-08-20 09:57:19 +0000152 ngx_str_t *v;
153 ngx_variable_value_t *vv;
Igor Sysoev1b735832004-11-11 14:07:14 +0000154
Igor Sysoev1b735832004-11-11 14:07:14 +0000155 while (*fmt && buf < last) {
156
157 /*
158 * "buf < last" means that we could copy at least one character:
159 * the plain character, "%%", "%c", and minus without the checking
160 */
161
Igor Sysoevc0edbcc2004-10-21 15:34:38 +0000162 if (*fmt == '%') {
163
Igor Sysoev1b735832004-11-11 14:07:14 +0000164 i64 = 0;
165 ui64 = 0;
166
167 zero = (u_char) ((*++fmt == '0') ? '0' : ' ');
Igor Sysoevc0edbcc2004-10-21 15:34:38 +0000168 width = 0;
169 sign = 1;
Igor Sysoev74b7e5f2008-11-10 15:20:59 +0000170 hex = 0;
Igor Sysoevd039a2e2005-02-22 14:40:13 +0000171 max_width = 0;
Igor Sysoev74b7e5f2008-11-10 15:20:59 +0000172 frac_width = 0;
Igor Sysoev0bd32b72008-01-22 15:13:01 +0000173 slen = (size_t) -1;
Igor Sysoevc0edbcc2004-10-21 15:34:38 +0000174
Igor Sysoevc0edbcc2004-10-21 15:34:38 +0000175 while (*fmt >= '0' && *fmt <= '9') {
176 width = width * 10 + *fmt++ - '0';
177 }
178
179
180 for ( ;; ) {
181 switch (*fmt) {
182
183 case 'u':
184 sign = 0;
185 fmt++;
186 continue;
187
Igor Sysoevd43bee82004-11-20 19:52:20 +0000188 case 'm':
Igor Sysoevd039a2e2005-02-22 14:40:13 +0000189 max_width = 1;
Igor Sysoevd43bee82004-11-20 19:52:20 +0000190 fmt++;
191 continue;
192
Igor Sysoev1b735832004-11-11 14:07:14 +0000193 case 'X':
Igor Sysoev74b7e5f2008-11-10 15:20:59 +0000194 hex = 2;
Igor Sysoev1b735832004-11-11 14:07:14 +0000195 sign = 0;
196 fmt++;
197 continue;
198
Igor Sysoevc0edbcc2004-10-21 15:34:38 +0000199 case 'x':
Igor Sysoev74b7e5f2008-11-10 15:20:59 +0000200 hex = 1;
Igor Sysoev1b735832004-11-11 14:07:14 +0000201 sign = 0;
Igor Sysoevc0edbcc2004-10-21 15:34:38 +0000202 fmt++;
203 continue;
204
Igor Sysoev74b7e5f2008-11-10 15:20:59 +0000205 case '.':
206 fmt++;
207
208 while (*fmt >= '0' && *fmt <= '9') {
209 frac_width = frac_width * 10 + *fmt++ - '0';
210 }
211
212 break;
213
Igor Sysoev79d9a042007-12-24 17:05:16 +0000214 case '*':
Igor Sysoevfb424652008-01-24 15:18:17 +0000215 slen = va_arg(args, size_t);
Igor Sysoev79d9a042007-12-24 17:05:16 +0000216 fmt++;
217 continue;
218
Igor Sysoevc0edbcc2004-10-21 15:34:38 +0000219 default:
220 break;
221 }
222
223 break;
224 }
225
226
227 switch (*fmt) {
228
Igor Sysoev1b735832004-11-11 14:07:14 +0000229 case 'V':
Igor Sysoev0d4b3722007-08-20 09:57:19 +0000230 v = va_arg(args, ngx_str_t *);
Igor Sysoevc0edbcc2004-10-21 15:34:38 +0000231
Igor Sysoevf42ed052007-07-17 09:23:23 +0000232 len = v->len;
Igor Sysoev09c684b2005-11-09 17:25:55 +0000233 len = (buf + len < last) ? len : (size_t) (last - buf);
234
Igor Sysoevf42ed052007-07-17 09:23:23 +0000235 buf = ngx_cpymem(buf, v->data, len);
Igor Sysoev1b735832004-11-11 14:07:14 +0000236 fmt++;
Igor Sysoevc0edbcc2004-10-21 15:34:38 +0000237
Igor Sysoev1b735832004-11-11 14:07:14 +0000238 continue;
Igor Sysoevc0edbcc2004-10-21 15:34:38 +0000239
Igor Sysoev0d4b3722007-08-20 09:57:19 +0000240 case 'v':
241 vv = va_arg(args, ngx_variable_value_t *);
242
243 len = vv->len;
244 len = (buf + len < last) ? len : (size_t) (last - buf);
245
246 buf = ngx_cpymem(buf, vv->data, len);
247 fmt++;
248
249 continue;
250
Igor Sysoevc0edbcc2004-10-21 15:34:38 +0000251 case 's':
Igor Sysoev1b735832004-11-11 14:07:14 +0000252 p = va_arg(args, u_char *);
Igor Sysoevc0edbcc2004-10-21 15:34:38 +0000253
Igor Sysoev0bd32b72008-01-22 15:13:01 +0000254 if (slen == (size_t) -1) {
Igor Sysoev79d9a042007-12-24 17:05:16 +0000255 while (*p && buf < last) {
256 *buf++ = *p++;
257 }
258
259 } else {
Igor Sysoev16315762008-01-24 15:18:58 +0000260 len = (buf + slen < last) ? slen : (size_t) (last - buf);
261
262 buf = ngx_cpymem(buf, p, len);
Igor Sysoevc0edbcc2004-10-21 15:34:38 +0000263 }
Igor Sysoev79d9a042007-12-24 17:05:16 +0000264
Igor Sysoevc0edbcc2004-10-21 15:34:38 +0000265 fmt++;
266
267 continue;
268
Igor Sysoev1b735832004-11-11 14:07:14 +0000269 case 'O':
270 i64 = (int64_t) va_arg(args, off_t);
271 sign = 1;
272 break;
273
274 case 'P':
275 i64 = (int64_t) va_arg(args, ngx_pid_t);
276 sign = 1;
277 break;
278
279 case 'T':
280 i64 = (int64_t) va_arg(args, time_t);
281 sign = 1;
282 break;
283
Igor Sysoev208eed22005-10-07 13:30:52 +0000284 case 'M':
Igor Sysoev78452232005-10-12 13:50:36 +0000285 ms = (ngx_msec_t) va_arg(args, ngx_msec_t);
286 if ((ngx_msec_int_t) ms == -1) {
287 sign = 1;
288 i64 = -1;
289 } else {
290 sign = 0;
291 ui64 = (uint64_t) ms;
292 }
Igor Sysoev208eed22005-10-07 13:30:52 +0000293 break;
294
Igor Sysoev1b735832004-11-11 14:07:14 +0000295 case 'z':
296 if (sign) {
297 i64 = (int64_t) va_arg(args, ssize_t);
298 } else {
299 ui64 = (uint64_t) va_arg(args, size_t);
300 }
301 break;
302
303 case 'i':
304 if (sign) {
305 i64 = (int64_t) va_arg(args, ngx_int_t);
306 } else {
307 ui64 = (uint64_t) va_arg(args, ngx_uint_t);
308 }
Igor Sysoevd039a2e2005-02-22 14:40:13 +0000309
310 if (max_width) {
311 width = NGX_INT_T_LEN;
312 }
313
Igor Sysoev1b735832004-11-11 14:07:14 +0000314 break;
315
316 case 'd':
317 if (sign) {
318 i64 = (int64_t) va_arg(args, int);
319 } else {
320 ui64 = (uint64_t) va_arg(args, u_int);
321 }
322 break;
323
324 case 'l':
325 if (sign) {
326 i64 = (int64_t) va_arg(args, long);
327 } else {
328 ui64 = (uint64_t) va_arg(args, u_long);
329 }
330 break;
331
332 case 'D':
333 if (sign) {
334 i64 = (int64_t) va_arg(args, int32_t);
335 } else {
336 ui64 = (uint64_t) va_arg(args, uint32_t);
337 }
338 break;
339
340 case 'L':
341 if (sign) {
342 i64 = va_arg(args, int64_t);
343 } else {
344 ui64 = va_arg(args, uint64_t);
345 }
346 break;
347
Igor Sysoevd039a2e2005-02-22 14:40:13 +0000348 case 'A':
349 if (sign) {
350 i64 = (int64_t) va_arg(args, ngx_atomic_int_t);
351 } else {
Igor Sysoev4a715592005-02-24 12:29:09 +0000352 ui64 = (uint64_t) va_arg(args, ngx_atomic_uint_t);
Igor Sysoevd039a2e2005-02-22 14:40:13 +0000353 }
354
355 if (max_width) {
356 width = NGX_ATOMIC_T_LEN;
357 }
358
359 break;
360
Igor Sysoev74b7e5f2008-11-10 15:20:59 +0000361 case 'f':
Igor Sysoev503b9712010-05-12 13:12:31 +0000362 f = va_arg(args, double);
Igor Sysoev74b7e5f2008-11-10 15:20:59 +0000363
364 if (f < 0) {
365 *buf++ = '-';
366 f = -f;
367 }
368
369 ui64 = (int64_t) f;
370
371 buf = ngx_sprintf_num(buf, last, ui64, zero, 0, width);
372
373 if (frac_width) {
374
375 if (buf < last) {
376 *buf++ = '.';
377 }
378
379 scale = 1.0;
380
Igor Sysoev612ecb72009-11-02 17:12:09 +0000381 for (n = frac_width; n; n--) {
Igor Sysoev74b7e5f2008-11-10 15:20:59 +0000382 scale *= 10.0;
383 }
384
385 /*
386 * (int64_t) cast is required for msvc6:
387 * it can not convert uint64_t to double
388 */
Igor Sysoev50af4062010-05-12 13:13:11 +0000389 ui64 = (uint64_t) ((f - (int64_t) ui64) * scale + 0.5);
Igor Sysoev74b7e5f2008-11-10 15:20:59 +0000390
391 buf = ngx_sprintf_num(buf, last, ui64, '0', 0, frac_width);
392 }
393
394 fmt++;
395
396 continue;
397
Igor Sysoev1b735832004-11-11 14:07:14 +0000398#if !(NGX_WIN32)
399 case 'r':
400 i64 = (int64_t) va_arg(args, rlim_t);
401 sign = 1;
402 break;
403#endif
404
405 case 'p':
406 ui64 = (uintptr_t) va_arg(args, void *);
Igor Sysoev74b7e5f2008-11-10 15:20:59 +0000407 hex = 2;
Igor Sysoev1b735832004-11-11 14:07:14 +0000408 sign = 0;
409 zero = '0';
Igor Sysoevc2807ec2006-02-16 15:26:46 +0000410 width = NGX_PTR_SIZE * 2;
Igor Sysoev1b735832004-11-11 14:07:14 +0000411 break;
412
Igor Sysoev723e6cc2004-10-25 15:29:23 +0000413 case 'c':
Igor Sysoev1b735832004-11-11 14:07:14 +0000414 d = va_arg(args, int);
Igor Sysoev723e6cc2004-10-25 15:29:23 +0000415 *buf++ = (u_char) (d & 0xff);
416 fmt++;
417
418 continue;
419
Igor Sysoev1b735832004-11-11 14:07:14 +0000420 case 'Z':
421 *buf++ = '\0';
422 fmt++;
423
424 continue;
425
Igor Sysoev85ef94b2005-06-23 13:41:06 +0000426 case 'N':
427#if (NGX_WIN32)
428 *buf++ = CR;
429#endif
430 *buf++ = LF;
431 fmt++;
432
433 continue;
434
Igor Sysoevc0edbcc2004-10-21 15:34:38 +0000435 case '%':
436 *buf++ = '%';
437 fmt++;
438
439 continue;
440
441 default:
442 *buf++ = *fmt++;
443
444 continue;
445 }
446
Igor Sysoev1b735832004-11-11 14:07:14 +0000447 if (sign) {
448 if (i64 < 0) {
449 *buf++ = '-';
450 ui64 = (uint64_t) -i64;
Igor Sysoevc0edbcc2004-10-21 15:34:38 +0000451
Igor Sysoev1b735832004-11-11 14:07:14 +0000452 } else {
453 ui64 = (uint64_t) i64;
454 }
Igor Sysoevc0edbcc2004-10-21 15:34:38 +0000455 }
456
Igor Sysoev74b7e5f2008-11-10 15:20:59 +0000457 buf = ngx_sprintf_num(buf, last, ui64, zero, hex, width);
Igor Sysoevc0edbcc2004-10-21 15:34:38 +0000458
459 fmt++;
460
461 } else {
462 *buf++ = *fmt++;
463 }
464 }
465
Igor Sysoevc0edbcc2004-10-21 15:34:38 +0000466 return buf;
467}
468
469
Igor Sysoev74b7e5f2008-11-10 15:20:59 +0000470static u_char *
471ngx_sprintf_num(u_char *buf, u_char *last, uint64_t ui64, u_char zero,
472 ngx_uint_t hexadecimal, ngx_uint_t width)
473{
474 u_char *p, temp[NGX_INT64_LEN + 1];
475 /*
476 * we need temp[NGX_INT64_LEN] only,
477 * but icc issues the warning
478 */
479 size_t len;
480 uint32_t ui32;
481 static u_char hex[] = "0123456789abcdef";
482 static u_char HEX[] = "0123456789ABCDEF";
483
484 p = temp + NGX_INT64_LEN;
485
486 if (hexadecimal == 0) {
487
488 if (ui64 <= NGX_MAX_UINT32_VALUE) {
489
490 /*
491 * To divide 64-bit numbers and to find remainders
492 * on the x86 platform gcc and icc call the libc functions
493 * [u]divdi3() and [u]moddi3(), they call another function
494 * in its turn. On FreeBSD it is the qdivrem() function,
495 * its source code is about 170 lines of the code.
496 * The glibc counterpart is about 150 lines of the code.
497 *
498 * For 32-bit numbers and some divisors gcc and icc use
499 * a inlined multiplication and shifts. For example,
500 * unsigned "i32 / 10" is compiled to
501 *
502 * (i32 * 0xCCCCCCCD) >> 35
503 */
504
505 ui32 = (uint32_t) ui64;
506
507 do {
508 *--p = (u_char) (ui32 % 10 + '0');
509 } while (ui32 /= 10);
510
511 } else {
512 do {
513 *--p = (u_char) (ui64 % 10 + '0');
514 } while (ui64 /= 10);
515 }
516
517 } else if (hexadecimal == 1) {
518
519 do {
520
521 /* the "(uint32_t)" cast disables the BCC's warning */
522 *--p = hex[(uint32_t) (ui64 & 0xf)];
523
524 } while (ui64 >>= 4);
525
526 } else { /* hexadecimal == 2 */
527
528 do {
529
530 /* the "(uint32_t)" cast disables the BCC's warning */
531 *--p = HEX[(uint32_t) (ui64 & 0xf)];
532
533 } while (ui64 >>= 4);
534 }
535
536 /* zero or space padding */
537
538 len = (temp + NGX_INT64_LEN) - p;
539
540 while (len++ < width && buf < last) {
541 *buf++ = zero;
542 }
543
544 /* number safe copy */
545
546 len = (temp + NGX_INT64_LEN) - p;
547
548 if (buf + len > last) {
549 len = last - buf;
550 }
551
552 return ngx_cpymem(buf, p, len);
553}
554
555
Igor Sysoev722231f2007-02-14 18:51:19 +0000556/*
Igor Sysoev066e6322007-09-26 12:23:34 +0000557 * We use ngx_strcasecmp()/ngx_strncasecmp() for 7-bit ASCII strings only,
Igor Sysoev722231f2007-02-14 18:51:19 +0000558 * and implement our own ngx_strcasecmp()/ngx_strncasecmp()
559 * to avoid libc locale overhead. Besides, we use the ngx_uint_t's
560 * instead of the u_char's, because they are slightly faster.
561 */
562
563ngx_int_t
564ngx_strcasecmp(u_char *s1, u_char *s2)
565{
566 ngx_uint_t c1, c2;
567
568 for ( ;; ) {
569 c1 = (ngx_uint_t) *s1++;
570 c2 = (ngx_uint_t) *s2++;
571
Igor Sysoeve0f1d0a2009-09-11 13:57:50 +0000572 c1 = (c1 >= 'A' && c1 <= 'Z') ? (c1 | 0x20) : c1;
573 c2 = (c2 >= 'A' && c2 <= 'Z') ? (c2 | 0x20) : c2;
Igor Sysoev722231f2007-02-14 18:51:19 +0000574
575 if (c1 == c2) {
576
577 if (c1) {
578 continue;
579 }
580
581 return 0;
582 }
583
584 return c1 - c2;
585 }
586}
587
588
589ngx_int_t
590ngx_strncasecmp(u_char *s1, u_char *s2, size_t n)
591{
592 ngx_uint_t c1, c2;
593
594 while (n) {
595 c1 = (ngx_uint_t) *s1++;
596 c2 = (ngx_uint_t) *s2++;
597
Igor Sysoeve0f1d0a2009-09-11 13:57:50 +0000598 c1 = (c1 >= 'A' && c1 <= 'Z') ? (c1 | 0x20) : c1;
599 c2 = (c2 >= 'A' && c2 <= 'Z') ? (c2 | 0x20) : c2;
Igor Sysoev722231f2007-02-14 18:51:19 +0000600
601 if (c1 == c2) {
602
603 if (c1) {
604 n--;
605 continue;
606 }
607
608 return 0;
609 }
610
611 return c1 - c2;
612 }
613
614 return 0;
615}
616
617
Igor Sysoev35fe5fd2007-10-01 14:48:33 +0000618u_char *
619ngx_strnstr(u_char *s1, char *s2, size_t len)
620{
621 u_char c1, c2;
622 size_t n;
623
624 c2 = *(u_char *) s2++;
625
626 n = ngx_strlen(s2);
627
628 do {
629 do {
630 if (len-- == 0) {
631 return NULL;
632 }
633
634 c1 = *s1++;
635
636 if (c1 == 0) {
637 return NULL;
638 }
639
640 } while (c1 != c2);
641
642 if (n > len) {
643 return NULL;
644 }
645
646 } while (ngx_strncmp(s1, (u_char *) s2, n) != 0);
647
648 return --s1;
649}
650
651
Igor Sysoev66697022007-10-01 13:00:30 +0000652/*
653 * ngx_strstrn() and ngx_strcasestrn() are intended to search for static
654 * substring with known length in null-terminated string. The argument n
655 * must be length of the second substring - 1.
656 */
657
Igor Sysoev1bd98702007-09-26 19:25:52 +0000658u_char *
659ngx_strstrn(u_char *s1, char *s2, size_t n)
660{
661 u_char c1, c2;
662
663 c2 = *(u_char *) s2++;
664
665 do {
666 do {
667 c1 = *s1++;
668
669 if (c1 == 0) {
670 return NULL;
671 }
672
673 } while (c1 != c2);
674
675 } while (ngx_strncmp(s1, (u_char *) s2, n) != 0);
676
677 return --s1;
678}
679
680
681u_char *
682ngx_strcasestrn(u_char *s1, char *s2, size_t n)
683{
684 ngx_uint_t c1, c2;
685
686 c2 = (ngx_uint_t) *s2++;
Igor Sysoeve0f1d0a2009-09-11 13:57:50 +0000687 c2 = (c2 >= 'A' && c2 <= 'Z') ? (c2 | 0x20) : c2;
Igor Sysoev1bd98702007-09-26 19:25:52 +0000688
689 do {
690 do {
691 c1 = (ngx_uint_t) *s1++;
692
693 if (c1 == 0) {
694 return NULL;
695 }
696
Igor Sysoeve0f1d0a2009-09-11 13:57:50 +0000697 c1 = (c1 >= 'A' && c1 <= 'Z') ? (c1 | 0x20) : c1;
Igor Sysoev1bd98702007-09-26 19:25:52 +0000698
699 } while (c1 != c2);
700
701 } while (ngx_strncasecmp(s1, (u_char *) s2, n) != 0);
702
703 return --s1;
704}
705
706
Igor Sysoeva514d682009-04-04 17:31:54 +0000707/*
708 * ngx_strlcasestrn() is intended to search for static substring
709 * with known length in string until the argument last. The argument n
710 * must be length of the second substring - 1.
711 */
712
713u_char *
714ngx_strlcasestrn(u_char *s1, u_char *last, u_char *s2, size_t n)
715{
716 ngx_uint_t c1, c2;
717
718 c2 = (ngx_uint_t) *s2++;
Igor Sysoeve0f1d0a2009-09-11 13:57:50 +0000719 c2 = (c2 >= 'A' && c2 <= 'Z') ? (c2 | 0x20) : c2;
Igor Sysoeva514d682009-04-04 17:31:54 +0000720 last -= n;
721
722 do {
723 do {
Igor Sysoevd5ba36f2009-04-06 11:42:42 +0000724 if (s1 >= last) {
Igor Sysoeva514d682009-04-04 17:31:54 +0000725 return NULL;
726 }
727
728 c1 = (ngx_uint_t) *s1++;
729
Igor Sysoeve0f1d0a2009-09-11 13:57:50 +0000730 c1 = (c1 >= 'A' && c1 <= 'Z') ? (c1 | 0x20) : c1;
Igor Sysoeva514d682009-04-04 17:31:54 +0000731
732 } while (c1 != c2);
733
734 } while (ngx_strncasecmp(s1, s2, n) != 0);
735
736 return --s1;
737}
738
739
Igor Sysoevd039a2e2005-02-22 14:40:13 +0000740ngx_int_t
741ngx_rstrncmp(u_char *s1, u_char *s2, size_t n)
Igor Sysoev3d09c8d2003-05-06 17:03:16 +0000742{
743 if (n == 0) {
744 return 0;
745 }
746
747 n--;
748
749 for ( ;; ) {
750 if (s1[n] != s2[n]) {
Igor Sysoev10a543a2004-03-16 07:10:12 +0000751 return s1[n] - s2[n];
Igor Sysoev3d09c8d2003-05-06 17:03:16 +0000752 }
753
754 if (n == 0) {
755 return 0;
756 }
757
758 n--;
759 }
760}
761
762
Igor Sysoevd039a2e2005-02-22 14:40:13 +0000763ngx_int_t
764ngx_rstrncasecmp(u_char *s1, u_char *s2, size_t n)
Igor Sysoevc0edbcc2004-10-21 15:34:38 +0000765{
766 u_char c1, c2;
767
768 if (n == 0) {
769 return 0;
770 }
771
772 n--;
773
774 for ( ;; ) {
775 c1 = s1[n];
776 if (c1 >= 'a' && c1 <= 'z') {
777 c1 -= 'a' - 'A';
778 }
779
780 c2 = s2[n];
781 if (c2 >= 'a' && c2 <= 'z') {
782 c2 -= 'a' - 'A';
783 }
784
785 if (c1 != c2) {
786 return c1 - c2;
787 }
788
789 if (n == 0) {
790 return 0;
791 }
792
793 n--;
794 }
795}
796
797
Igor Sysoevd039a2e2005-02-22 14:40:13 +0000798ngx_int_t
Igor Sysoevec3cabd2007-01-12 21:58:02 +0000799ngx_memn2cmp(u_char *s1, u_char *s2, size_t n1, size_t n2)
Igor Sysoev37cc1652007-01-12 20:15:59 +0000800{
801 size_t n;
802 ngx_int_t m, z;
803
804 if (n1 <= n2) {
805 n = n1;
806 z = -1;
807
808 } else {
809 n = n2;
810 z = 1;
811 }
812
Igor Sysoevec3cabd2007-01-12 21:58:02 +0000813 m = ngx_memcmp(s1, s2, n);
Igor Sysoev37cc1652007-01-12 20:15:59 +0000814
815 if (m || n1 == n2) {
816 return m;
817 }
818
819 return z;
820}
821
822
823ngx_int_t
Igor Sysoev96e36ef2009-09-12 09:28:37 +0000824ngx_dns_strcmp(u_char *s1, u_char *s2)
825{
826 ngx_uint_t c1, c2;
827
828 for ( ;; ) {
829 c1 = (ngx_uint_t) *s1++;
830 c2 = (ngx_uint_t) *s2++;
831
832 c1 = (c1 >= 'A' && c1 <= 'Z') ? (c1 | 0x20) : c1;
833 c2 = (c2 >= 'A' && c2 <= 'Z') ? (c2 | 0x20) : c2;
834
835 if (c1 == c2) {
836
837 if (c1) {
838 continue;
839 }
840
841 return 0;
842 }
843
844 /* in ASCII '.' > '-', but we need '.' to be the lowest character */
845
846 c1 = (c1 == '.') ? ' ' : c1;
847 c2 = (c2 == '.') ? ' ' : c2;
848
849 return c1 - c2;
850 }
851}
852
853
854ngx_int_t
Igor Sysoevd039a2e2005-02-22 14:40:13 +0000855ngx_atoi(u_char *line, size_t n)
Igor Sysoevdc479b42003-03-20 16:09:44 +0000856{
Igor Sysoev10a543a2004-03-16 07:10:12 +0000857 ngx_int_t value;
Igor Sysoevdc479b42003-03-20 16:09:44 +0000858
Igor Sysoev3d09c8d2003-05-06 17:03:16 +0000859 if (n == 0) {
860 return NGX_ERROR;
861 }
862
Igor Sysoevdc479b42003-03-20 16:09:44 +0000863 for (value = 0; n--; line++) {
Igor Sysoev1d8d9ee2003-04-28 15:06:39 +0000864 if (*line < '0' || *line > '9') {
865 return NGX_ERROR;
866 }
Igor Sysoevdc479b42003-03-20 16:09:44 +0000867
Igor Sysoev1d8d9ee2003-04-28 15:06:39 +0000868 value = value * 10 + (*line - '0');
Igor Sysoevdc479b42003-03-20 16:09:44 +0000869 }
870
Igor Sysoev1d8d9ee2003-04-28 15:06:39 +0000871 if (value < 0) {
872 return NGX_ERROR;
Igor Sysoev18684bd2004-05-20 17:33:52 +0000873
874 } else {
875 return value;
876 }
877}
878
879
Igor Sysoevd2b687c2010-05-14 09:01:30 +0000880/* parse a fixed point number, e.g., ngx_atofp("10.5", 4, 2) returns 1050 */
881
882ngx_int_t
883ngx_atofp(u_char *line, size_t n, size_t point)
884{
885 ngx_int_t value;
886 ngx_uint_t dot;
887
888 if (n == 0) {
889 return NGX_ERROR;
890 }
891
892 dot = 0;
893
894 for (value = 0; n--; line++) {
895
896 if (point == 0) {
897 return NGX_ERROR;
898 }
899
900 if (*line == '.') {
901 if (dot) {
902 return NGX_ERROR;
903 }
904
905 dot = 1;
906 continue;
907 }
908
909 if (*line < '0' || *line > '9') {
910 return NGX_ERROR;
911 }
912
913 value = value * 10 + (*line - '0');
914 point -= dot;
915 }
916
917 while (point--) {
918 value = value * 10;
919 }
920
921 if (value < 0) {
922 return NGX_ERROR;
923
924 } else {
925 return value;
926 }
927}
928
929
Igor Sysoevc1571722005-03-19 12:38:37 +0000930ssize_t
931ngx_atosz(u_char *line, size_t n)
932{
933 ssize_t value;
934
935 if (n == 0) {
936 return NGX_ERROR;
937 }
938
939 for (value = 0; n--; line++) {
940 if (*line < '0' || *line > '9') {
941 return NGX_ERROR;
942 }
943
944 value = value * 10 + (*line - '0');
945 }
946
947 if (value < 0) {
948 return NGX_ERROR;
949
950 } else {
951 return value;
952 }
953}
954
955
956off_t
957ngx_atoof(u_char *line, size_t n)
958{
959 off_t value;
960
961 if (n == 0) {
962 return NGX_ERROR;
963 }
964
965 for (value = 0; n--; line++) {
966 if (*line < '0' || *line > '9') {
967 return NGX_ERROR;
968 }
969
970 value = value * 10 + (*line - '0');
971 }
972
973 if (value < 0) {
974 return NGX_ERROR;
975
976 } else {
977 return value;
978 }
979}
980
981
982time_t
983ngx_atotm(u_char *line, size_t n)
984{
985 time_t value;
986
987 if (n == 0) {
988 return NGX_ERROR;
989 }
990
991 for (value = 0; n--; line++) {
992 if (*line < '0' || *line > '9') {
993 return NGX_ERROR;
994 }
995
996 value = value * 10 + (*line - '0');
997 }
998
999 if (value < 0) {
1000 return NGX_ERROR;
1001
1002 } else {
1003 return value;
1004 }
1005}
1006
1007
Igor Sysoevd039a2e2005-02-22 14:40:13 +00001008ngx_int_t
1009ngx_hextoi(u_char *line, size_t n)
Igor Sysoev18684bd2004-05-20 17:33:52 +00001010{
Igor Sysoev066496a2006-10-16 12:21:17 +00001011 u_char c, ch;
Igor Sysoev18684bd2004-05-20 17:33:52 +00001012 ngx_int_t value;
1013
1014 if (n == 0) {
1015 return NGX_ERROR;
1016 }
1017
1018 for (value = 0; n--; line++) {
1019 ch = *line;
1020
1021 if (ch >= '0' && ch <= '9') {
1022 value = value * 16 + (ch - '0');
1023 continue;
1024 }
1025
Igor Sysoev066496a2006-10-16 12:21:17 +00001026 c = (u_char) (ch | 0x20);
Igor Sysoev18684bd2004-05-20 17:33:52 +00001027
Igor Sysoev066496a2006-10-16 12:21:17 +00001028 if (c >= 'a' && c <= 'f') {
1029 value = value * 16 + (c - 'a' + 10);
Igor Sysoev18684bd2004-05-20 17:33:52 +00001030 continue;
1031 }
1032
1033 return NGX_ERROR;
1034 }
1035
1036 if (value < 0) {
1037 return NGX_ERROR;
1038
Igor Sysoev1d8d9ee2003-04-28 15:06:39 +00001039 } else {
1040 return value;
1041 }
Igor Sysoevdc479b42003-03-20 16:09:44 +00001042}
1043
1044
Igor Sysoeva03fa362007-12-17 21:06:17 +00001045u_char *
1046ngx_hex_dump(u_char *dst, u_char *src, size_t len)
Igor Sysoev9cc1ace2003-11-04 22:12:39 +00001047{
Igor Sysoev10a543a2004-03-16 07:10:12 +00001048 static u_char hex[] = "0123456789abcdef";
Igor Sysoeve8732b02003-11-05 17:03:41 +00001049
Igor Sysoeva03fa362007-12-17 21:06:17 +00001050 while (len--) {
1051 *dst++ = hex[*src >> 4];
1052 *dst++ = hex[*src++ & 0xf];
Igor Sysoev74e95c22003-11-09 20:03:38 +00001053 }
1054
Igor Sysoeva03fa362007-12-17 21:06:17 +00001055 return dst;
Igor Sysoev9cc1ace2003-11-04 22:12:39 +00001056}
1057
1058
Igor Sysoevd039a2e2005-02-22 14:40:13 +00001059void
1060ngx_encode_base64(ngx_str_t *dst, ngx_str_t *src)
Igor Sysoev6deb0412004-07-30 17:05:14 +00001061{
1062 u_char *d, *s;
Igor Sysoev967fd632004-08-27 15:40:59 +00001063 size_t len;
Igor Sysoev6deb0412004-07-30 17:05:14 +00001064 static u_char basis64[] =
1065 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
1066
Igor Sysoev967fd632004-08-27 15:40:59 +00001067 len = src->len;
Igor Sysoeva7c4a2a2004-08-29 03:55:41 +00001068 s = src->data;
1069 d = dst->data;
Igor Sysoev6deb0412004-07-30 17:05:14 +00001070
Igor Sysoev967fd632004-08-27 15:40:59 +00001071 while (len > 2) {
1072 *d++ = basis64[(s[0] >> 2) & 0x3f];
1073 *d++ = basis64[((s[0] & 3) << 4) | (s[1] >> 4)];
1074 *d++ = basis64[((s[1] & 0x0f) << 2) | (s[2] >> 6)];
1075 *d++ = basis64[s[2] & 0x3f];
1076
1077 s += 3;
1078 len -= 3;
Igor Sysoev6deb0412004-07-30 17:05:14 +00001079 }
1080
Igor Sysoev967fd632004-08-27 15:40:59 +00001081 if (len) {
1082 *d++ = basis64[(s[0] >> 2) & 0x3f];
Igor Sysoev6deb0412004-07-30 17:05:14 +00001083
Igor Sysoev967fd632004-08-27 15:40:59 +00001084 if (len == 1) {
1085 *d++ = basis64[(s[0] & 3) << 4];
Igor Sysoev6deb0412004-07-30 17:05:14 +00001086 *d++ = '=';
1087
1088 } else {
Igor Sysoev967fd632004-08-27 15:40:59 +00001089 *d++ = basis64[((s[0] & 3) << 4) | (s[1] >> 4)];
1090 *d++ = basis64[(s[1] & 0x0f) << 2];
Igor Sysoev6deb0412004-07-30 17:05:14 +00001091 }
1092
1093 *d++ = '=';
1094 }
1095
1096 dst->len = d - dst->data;
Igor Sysoev6deb0412004-07-30 17:05:14 +00001097}
1098
1099
Igor Sysoevd039a2e2005-02-22 14:40:13 +00001100ngx_int_t
1101ngx_decode_base64(ngx_str_t *dst, ngx_str_t *src)
Igor Sysoev6deb0412004-07-30 17:05:14 +00001102{
Igor Sysoev967fd632004-08-27 15:40:59 +00001103 size_t len;
1104 u_char *d, *s;
Igor Sysoevb5c75dc2006-10-28 14:36:44 +00001105 static u_char basis64[] = {
1106 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77,
1107 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77,
1108 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 62, 77, 77, 77, 63,
1109 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 77, 77, 77, 77, 77, 77,
1110 77, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
1111 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 77, 77, 77, 77, 77,
1112 77, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
1113 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 77, 77, 77, 77, 77,
Igor Sysoev6deb0412004-07-30 17:05:14 +00001114
Igor Sysoevb5c75dc2006-10-28 14:36:44 +00001115 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77,
1116 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77,
1117 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77,
1118 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77,
1119 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77,
1120 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77,
1121 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77,
1122 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77
1123 };
Igor Sysoev967fd632004-08-27 15:40:59 +00001124
1125 for (len = 0; len < src->len; len++) {
1126 if (src->data[len] == '=') {
1127 break;
1128 }
1129
1130 if (basis64[src->data[len]] == 77) {
1131 return NGX_ERROR;
1132 }
1133 }
1134
1135 if (len % 4 == 1) {
1136 return NGX_ERROR;
1137 }
1138
Igor Sysoev6deb0412004-07-30 17:05:14 +00001139 s = src->data;
Igor Sysoeva7c4a2a2004-08-29 03:55:41 +00001140 d = dst->data;
Igor Sysoev6deb0412004-07-30 17:05:14 +00001141
Igor Sysoev967fd632004-08-27 15:40:59 +00001142 while (len > 3) {
Igor Sysoeva7c4a2a2004-08-29 03:55:41 +00001143 *d++ = (u_char) (basis64[s[0]] << 2 | basis64[s[1]] >> 4);
1144 *d++ = (u_char) (basis64[s[1]] << 4 | basis64[s[2]] >> 2);
1145 *d++ = (u_char) (basis64[s[2]] << 6 | basis64[s[3]]);
Igor Sysoev6deb0412004-07-30 17:05:14 +00001146
Igor Sysoev967fd632004-08-27 15:40:59 +00001147 s += 4;
1148 len -= 4;
Igor Sysoev6deb0412004-07-30 17:05:14 +00001149 }
1150
Igor Sysoev967fd632004-08-27 15:40:59 +00001151 if (len > 1) {
Igor Sysoeva7c4a2a2004-08-29 03:55:41 +00001152 *d++ = (u_char) (basis64[s[0]] << 2 | basis64[s[1]] >> 4);
Igor Sysoev967fd632004-08-27 15:40:59 +00001153 }
1154
1155 if (len > 2) {
Igor Sysoeva7c4a2a2004-08-29 03:55:41 +00001156 *d++ = (u_char) (basis64[s[1]] << 4 | basis64[s[2]] >> 2);
Igor Sysoev967fd632004-08-27 15:40:59 +00001157 }
1158
1159 dst->len = d - dst->data;
Igor Sysoev967fd632004-08-27 15:40:59 +00001160
Igor Sysoev6deb0412004-07-30 17:05:14 +00001161 return NGX_OK;
1162}
1163
1164
Igor Sysoevef809b82006-06-28 16:00:26 +00001165/*
Igor Sysoeva0898572008-07-29 14:41:34 +00001166 * ngx_utf8_decode() decodes two and more bytes UTF sequences only
Igor Sysoevef809b82006-06-28 16:00:26 +00001167 * the return values:
1168 * 0x80 - 0x10ffff valid character
Igor Sysoev96eaa052008-07-25 14:29:05 +00001169 * 0x110000 - 0xfffffffd invalid sequence
Igor Sysoevef809b82006-06-28 16:00:26 +00001170 * 0xfffffffe incomplete sequence
1171 * 0xffffffff error
1172 */
1173
1174uint32_t
Igor Sysoeva0898572008-07-29 14:41:34 +00001175ngx_utf8_decode(u_char **p, size_t n)
Igor Sysoevef809b82006-06-28 16:00:26 +00001176{
1177 size_t len;
1178 uint32_t u, i, valid;
1179
1180 u = **p;
1181
1182 if (u > 0xf0) {
1183
1184 u &= 0x07;
1185 valid = 0xffff;
1186 len = 3;
1187
1188 } else if (u > 0xe0) {
1189
1190 u &= 0x0f;
1191 valid = 0x7ff;
1192 len = 2;
1193
1194 } else if (u > 0xc0) {
1195
1196 u &= 0x1f;
1197 valid = 0x7f;
1198 len = 1;
1199
1200 } else {
1201 (*p)++;
1202 return 0xffffffff;
1203 }
1204
1205 if (n - 1 < len) {
1206 return 0xfffffffe;
1207 }
1208
1209 (*p)++;
1210
1211 while (len) {
1212 i = *(*p)++;
1213
1214 if (i < 0x80) {
1215 return 0xffffffff;
1216 }
1217
1218 u = (u << 6) | (i & 0x3f);
1219
1220 len--;
1221 }
1222
1223 if (u > valid) {
1224 return u;
1225 }
1226
1227 return 0xffffffff;
1228}
1229
1230
Igor Sysoevb145b062005-06-15 18:33:41 +00001231size_t
Igor Sysoeva0898572008-07-29 14:41:34 +00001232ngx_utf8_length(u_char *p, size_t n)
Igor Sysoevb145b062005-06-15 18:33:41 +00001233{
Igor Sysoev96eaa052008-07-25 14:29:05 +00001234 u_char c, *last;
1235 size_t len;
Igor Sysoevb145b062005-06-15 18:33:41 +00001236
Igor Sysoev96eaa052008-07-25 14:29:05 +00001237 last = p + n;
Igor Sysoevb145b062005-06-15 18:33:41 +00001238
Igor Sysoev96eaa052008-07-25 14:29:05 +00001239 for (len = 0; p < last; len++) {
1240
1241 c = *p;
Igor Sysoevb145b062005-06-15 18:33:41 +00001242
1243 if (c < 0x80) {
Igor Sysoev96eaa052008-07-25 14:29:05 +00001244 p++;
Igor Sysoevb145b062005-06-15 18:33:41 +00001245 continue;
1246 }
1247
Igor Sysoeva0898572008-07-29 14:41:34 +00001248 if (ngx_utf8_decode(&p, n) > 0x10ffff) {
1249 /* invalid UTF-8 */
Igor Sysoev96eaa052008-07-25 14:29:05 +00001250 return n;
Igor Sysoevb145b062005-06-15 18:33:41 +00001251 }
Igor Sysoevb145b062005-06-15 18:33:41 +00001252 }
1253
1254 return len;
1255}
1256
1257
Igor Sysoev5192b362005-07-08 14:34:20 +00001258u_char *
Igor Sysoeva0898572008-07-29 14:41:34 +00001259ngx_utf8_cpystrn(u_char *dst, u_char *src, size_t n, size_t len)
Igor Sysoev5192b362005-07-08 14:34:20 +00001260{
Igor Sysoev96eaa052008-07-25 14:29:05 +00001261 u_char c, *next;
Igor Sysoev5192b362005-07-08 14:34:20 +00001262
1263 if (n == 0) {
1264 return dst;
1265 }
1266
Igor Sysoev96eaa052008-07-25 14:29:05 +00001267 while (--n) {
Igor Sysoev5192b362005-07-08 14:34:20 +00001268
1269 c = *src;
1270 *dst = c;
1271
1272 if (c < 0x80) {
Igor Sysoev96eaa052008-07-25 14:29:05 +00001273
1274 if (c != '\0') {
1275 dst++;
1276 src++;
1277 len--;
1278
Igor Sysoev5192b362005-07-08 14:34:20 +00001279 continue;
1280 }
1281
1282 return dst;
1283 }
1284
Igor Sysoev96eaa052008-07-25 14:29:05 +00001285 next = src;
Igor Sysoev5192b362005-07-08 14:34:20 +00001286
Igor Sysoeva0898572008-07-29 14:41:34 +00001287 if (ngx_utf8_decode(&next, len) > 0x10ffff) {
1288 /* invalid UTF-8 */
Igor Sysoev96eaa052008-07-25 14:29:05 +00001289 break;
Igor Sysoev5192b362005-07-08 14:34:20 +00001290 }
1291
Igor Sysoev96eaa052008-07-25 14:29:05 +00001292 while (src < next) {
Igor Sysoevd8be48a2010-01-11 13:39:24 +00001293 *dst++ = *src++;
Igor Sysoev96eaa052008-07-25 14:29:05 +00001294 len--;
1295 }
Igor Sysoev5192b362005-07-08 14:34:20 +00001296 }
1297
1298 *dst = '\0';
1299
1300 return dst;
1301}
1302
1303
Igor Sysoevd039a2e2005-02-22 14:40:13 +00001304uintptr_t
1305ngx_escape_uri(u_char *dst, u_char *src, size_t size, ngx_uint_t type)
Igor Sysoevdc479b42003-03-20 16:09:44 +00001306{
Igor Sysoev612ecb72009-11-02 17:12:09 +00001307 ngx_uint_t n;
Igor Sysoevb5c75dc2006-10-28 14:36:44 +00001308 uint32_t *escape;
1309 static u_char hex[] = "0123456789abcdef";
Igor Sysoev1b735832004-11-11 14:07:14 +00001310
Igor Sysoevb5c75dc2006-10-28 14:36:44 +00001311 /* " ", "#", "%", "?", %00-%1F, %7F-%FF */
Igor Sysoev805d9db2005-02-03 19:33:37 +00001312
Igor Sysoevb5c75dc2006-10-28 14:36:44 +00001313 static uint32_t uri[] = {
1314 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
Igor Sysoevdc479b42003-03-20 16:09:44 +00001315
Igor Sysoevb5c75dc2006-10-28 14:36:44 +00001316 /* ?>=< ;:98 7654 3210 /.-, +*)( '&%$ #"! */
1317 0x80000029, /* 1000 0000 0000 0000 0000 0000 0010 1001 */
Igor Sysoevdc479b42003-03-20 16:09:44 +00001318
Igor Sysoevb5c75dc2006-10-28 14:36:44 +00001319 /* _^]\ [ZYX WVUT SRQP ONML KJIH GFED CBA@ */
1320 0x00000000, /* 0000 0000 0000 0000 0000 0000 0000 0000 */
Igor Sysoevdc479b42003-03-20 16:09:44 +00001321
Igor Sysoevb5c75dc2006-10-28 14:36:44 +00001322 /* ~}| {zyx wvut srqp onml kjih gfed cba` */
1323 0x80000000, /* 1000 0000 0000 0000 0000 0000 0000 0000 */
Igor Sysoev924bd792004-10-11 15:07:03 +00001324
Igor Sysoevb5c75dc2006-10-28 14:36:44 +00001325 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
1326 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
1327 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
1328 0xffffffff /* 1111 1111 1111 1111 1111 1111 1111 1111 */
1329 };
Igor Sysoev924bd792004-10-11 15:07:03 +00001330
Igor Sysoev170a54f2010-04-01 12:45:59 +00001331 /* " ", "#", "%", "&", "+", "?", %00-%1F, %7F-%FF */
Igor Sysoev805d9db2005-02-03 19:33:37 +00001332
Igor Sysoevb5c75dc2006-10-28 14:36:44 +00001333 static uint32_t args[] = {
1334 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
Igor Sysoev805d9db2005-02-03 19:33:37 +00001335
Igor Sysoevb5c75dc2006-10-28 14:36:44 +00001336 /* ?>=< ;:98 7654 3210 /.-, +*)( '&%$ #"! */
Igor Sysoev170a54f2010-04-01 12:45:59 +00001337 0x80000869, /* 1000 0000 0000 0000 0000 1000 0110 1001 */
Igor Sysoev805d9db2005-02-03 19:33:37 +00001338
Igor Sysoevb5c75dc2006-10-28 14:36:44 +00001339 /* _^]\ [ZYX WVUT SRQP ONML KJIH GFED CBA@ */
1340 0x00000000, /* 0000 0000 0000 0000 0000 0000 0000 0000 */
Igor Sysoev805d9db2005-02-03 19:33:37 +00001341
Igor Sysoevb5c75dc2006-10-28 14:36:44 +00001342 /* ~}| {zyx wvut srqp onml kjih gfed cba` */
1343 0x80000000, /* 1000 0000 0000 0000 0000 0000 0000 0000 */
Igor Sysoev805d9db2005-02-03 19:33:37 +00001344
Igor Sysoevb5c75dc2006-10-28 14:36:44 +00001345 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
1346 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
1347 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
1348 0xffffffff /* 1111 1111 1111 1111 1111 1111 1111 1111 */
1349 };
Igor Sysoev805d9db2005-02-03 19:33:37 +00001350
Igor Sysoevd4ff5612007-08-20 09:50:53 +00001351 /* " ", "#", """, "%", "'", %00-%1F, %7F-%FF */
Igor Sysoev805d9db2005-02-03 19:33:37 +00001352
Igor Sysoevb5c75dc2006-10-28 14:36:44 +00001353 static uint32_t html[] = {
1354 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
Igor Sysoev1b735832004-11-11 14:07:14 +00001355
Igor Sysoevb5c75dc2006-10-28 14:36:44 +00001356 /* ?>=< ;:98 7654 3210 /.-, +*)( '&%$ #"! */
Igor Sysoev049ae002007-07-13 09:35:51 +00001357 0x000000ad, /* 0000 0000 0000 0000 0000 0000 1010 1101 */
Igor Sysoev1b735832004-11-11 14:07:14 +00001358
Igor Sysoevb5c75dc2006-10-28 14:36:44 +00001359 /* _^]\ [ZYX WVUT SRQP ONML KJIH GFED CBA@ */
1360 0x00000000, /* 0000 0000 0000 0000 0000 0000 0000 0000 */
Igor Sysoev1b735832004-11-11 14:07:14 +00001361
Igor Sysoevb5c75dc2006-10-28 14:36:44 +00001362 /* ~}| {zyx wvut srqp onml kjih gfed cba` */
1363 0x80000000, /* 1000 0000 0000 0000 0000 0000 0000 0000 */
Igor Sysoev1b735832004-11-11 14:07:14 +00001364
Igor Sysoevb5c75dc2006-10-28 14:36:44 +00001365 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
1366 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
1367 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
1368 0xffffffff /* 1111 1111 1111 1111 1111 1111 1111 1111 */
1369 };
Igor Sysoev1b735832004-11-11 14:07:14 +00001370
Igor Sysoevd4ff5612007-08-20 09:50:53 +00001371 /* " ", """, "%", "'", %00-%1F, %7F-%FF */
Igor Sysoev1b735832004-11-11 14:07:14 +00001372
Igor Sysoev8662b6b2007-07-13 09:37:01 +00001373 static uint32_t refresh[] = {
1374 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
1375
1376 /* ?>=< ;:98 7654 3210 /.-, +*)( '&%$ #"! */
Igor Sysoevcc5484f2007-11-09 13:17:58 +00001377 0x00000085, /* 0000 0000 0000 0000 0000 0000 1000 0101 */
Igor Sysoev8662b6b2007-07-13 09:37:01 +00001378
1379 /* _^]\ [ZYX WVUT SRQP ONML KJIH GFED CBA@ */
1380 0x00000000, /* 0000 0000 0000 0000 0000 0000 0000 0000 */
1381
1382 /* ~}| {zyx wvut srqp onml kjih gfed cba` */
1383 0x80000000, /* 1000 0000 0000 0000 0000 0000 0000 0000 */
1384
1385 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
1386 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
1387 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
1388 0xffffffff /* 1111 1111 1111 1111 1111 1111 1111 1111 */
1389 };
1390
Igor Sysoevd4ff5612007-08-20 09:50:53 +00001391 /* " ", "%", %00-%1F */
Igor Sysoev3f707822007-07-22 19:18:59 +00001392
1393 static uint32_t memcached[] = {
1394 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
1395
1396 /* ?>=< ;:98 7654 3210 /.-, +*)( '&%$ #"! */
Igor Sysoevd4ff5612007-08-20 09:50:53 +00001397 0x00000021, /* 0000 0000 0000 0000 0000 0000 0010 0001 */
Igor Sysoev3f707822007-07-22 19:18:59 +00001398
1399 /* _^]\ [ZYX WVUT SRQP ONML KJIH GFED CBA@ */
1400 0x00000000, /* 0000 0000 0000 0000 0000 0000 0000 0000 */
1401
1402 /* ~}| {zyx wvut srqp onml kjih gfed cba` */
1403 0x00000000, /* 0000 0000 0000 0000 0000 0000 0000 0000 */
1404
1405 0x00000000, /* 0000 0000 0000 0000 0000 0000 0000 0000 */
1406 0x00000000, /* 0000 0000 0000 0000 0000 0000 0000 0000 */
1407 0x00000000, /* 0000 0000 0000 0000 0000 0000 0000 0000 */
1408 0x00000000, /* 0000 0000 0000 0000 0000 0000 0000 0000 */
1409 };
1410
Igor Sysoevd4ff5612007-08-20 09:50:53 +00001411 /* mail_auth is the same as memcached */
1412
1413 static uint32_t *map[] =
1414 { uri, args, html, refresh, memcached, memcached };
Igor Sysoev8662b6b2007-07-13 09:37:01 +00001415
1416
1417 escape = map[type];
Igor Sysoev1b735832004-11-11 14:07:14 +00001418
Igor Sysoev924bd792004-10-11 15:07:03 +00001419 if (dst == NULL) {
1420
1421 /* find the number of the characters to be escaped */
1422
Igor Sysoeve0f1d0a2009-09-11 13:57:50 +00001423 n = 0;
Igor Sysoev924bd792004-10-11 15:07:03 +00001424
Igor Sysoev612ecb72009-11-02 17:12:09 +00001425 while (size) {
Igor Sysoev924bd792004-10-11 15:07:03 +00001426 if (escape[*src >> 5] & (1 << (*src & 0x1f))) {
1427 n++;
1428 }
1429 src++;
Igor Sysoev612ecb72009-11-02 17:12:09 +00001430 size--;
Igor Sysoev924bd792004-10-11 15:07:03 +00001431 }
1432
Igor Sysoev805d9db2005-02-03 19:33:37 +00001433 return (uintptr_t) n;
Igor Sysoevdc479b42003-03-20 16:09:44 +00001434 }
1435
Igor Sysoev612ecb72009-11-02 17:12:09 +00001436 while (size) {
Igor Sysoev924bd792004-10-11 15:07:03 +00001437 if (escape[*src >> 5] & (1 << (*src & 0x1f))) {
1438 *dst++ = '%';
1439 *dst++ = hex[*src >> 4];
1440 *dst++ = hex[*src & 0xf];
1441 src++;
Igor Sysoevdc479b42003-03-20 16:09:44 +00001442
Igor Sysoev924bd792004-10-11 15:07:03 +00001443 } else {
1444 *dst++ = *src++;
1445 }
Igor Sysoev612ecb72009-11-02 17:12:09 +00001446 size--;
Igor Sysoevdc479b42003-03-20 16:09:44 +00001447 }
1448
Igor Sysoev805d9db2005-02-03 19:33:37 +00001449 return (uintptr_t) dst;
Igor Sysoevdc479b42003-03-20 16:09:44 +00001450}
Igor Sysoev0e5dc5c2005-11-15 13:30:52 +00001451
1452
1453void
Igor Sysoevae33d012006-01-17 20:04:32 +00001454ngx_unescape_uri(u_char **dst, u_char **src, size_t size, ngx_uint_t type)
Igor Sysoev0e5dc5c2005-11-15 13:30:52 +00001455{
1456 u_char *d, *s, ch, c, decoded;
1457 enum {
1458 sw_usual = 0,
1459 sw_quoted,
1460 sw_quoted_second
1461 } state;
1462
1463 d = *dst;
1464 s = *src;
1465
1466 state = 0;
1467 decoded = 0;
1468
1469 while (size--) {
1470
1471 ch = *s++;
1472
1473 switch (state) {
1474 case sw_usual:
Igor Sysoevf0a51cf2007-10-22 10:19:17 +00001475 if (ch == '?'
1476 && (type & (NGX_UNESCAPE_URI|NGX_UNESCAPE_REDIRECT)))
1477 {
Igor Sysoev0e5dc5c2005-11-15 13:30:52 +00001478 *d++ = ch;
1479 goto done;
1480 }
1481
1482 if (ch == '%') {
1483 state = sw_quoted;
1484 break;
1485 }
1486
1487 *d++ = ch;
1488 break;
1489
1490 case sw_quoted:
1491
1492 if (ch >= '0' && ch <= '9') {
1493 decoded = (u_char) (ch - '0');
1494 state = sw_quoted_second;
1495 break;
1496 }
1497
1498 c = (u_char) (ch | 0x20);
1499 if (c >= 'a' && c <= 'f') {
1500 decoded = (u_char) (c - 'a' + 10);
1501 state = sw_quoted_second;
1502 break;
1503 }
1504
Igor Sysoev24025022005-12-16 15:07:08 +00001505 /* the invalid quoted character */
Igor Sysoev0e5dc5c2005-11-15 13:30:52 +00001506
Igor Sysoev24025022005-12-16 15:07:08 +00001507 state = sw_usual;
1508
1509 *d++ = ch;
Igor Sysoev0e5dc5c2005-11-15 13:30:52 +00001510
1511 break;
1512
1513 case sw_quoted_second:
1514
Igor Sysoev24025022005-12-16 15:07:08 +00001515 state = sw_usual;
1516
Igor Sysoev0e5dc5c2005-11-15 13:30:52 +00001517 if (ch >= '0' && ch <= '9') {
1518 ch = (u_char) ((decoded << 4) + ch - '0');
1519
Igor Sysoevf0a51cf2007-10-22 10:19:17 +00001520 if (type & NGX_UNESCAPE_REDIRECT) {
Igor Sysoevae33d012006-01-17 20:04:32 +00001521 if (ch > '%' && ch < 0x7f) {
1522 *d++ = ch;
1523 break;
1524 }
1525
1526 *d++ = '%'; *d++ = *(s - 2); *d++ = *(s - 1);
1527
Igor Sysoev0e5dc5c2005-11-15 13:30:52 +00001528 break;
1529 }
1530
Igor Sysoevae33d012006-01-17 20:04:32 +00001531 *d++ = ch;
Igor Sysoev0e5dc5c2005-11-15 13:30:52 +00001532
1533 break;
1534 }
1535
1536 c = (u_char) (ch | 0x20);
1537 if (c >= 'a' && c <= 'f') {
1538 ch = (u_char) ((decoded << 4) + c - 'a' + 10);
1539
Igor Sysoevf0a51cf2007-10-22 10:19:17 +00001540 if (type & NGX_UNESCAPE_URI) {
1541 if (ch == '?') {
1542 *d++ = ch;
1543 goto done;
1544 }
1545
1546 *d++ = ch;
1547 break;
1548 }
1549
1550 if (type & NGX_UNESCAPE_REDIRECT) {
Igor Sysoevae33d012006-01-17 20:04:32 +00001551 if (ch == '?') {
1552 *d++ = ch;
1553 goto done;
1554 }
Igor Sysoev0e5dc5c2005-11-15 13:30:52 +00001555
Igor Sysoevae33d012006-01-17 20:04:32 +00001556 if (ch > '%' && ch < 0x7f) {
1557 *d++ = ch;
1558 break;
1559 }
1560
1561 *d++ = '%'; *d++ = *(s - 2); *d++ = *(s - 1);
Igor Sysoev0e5dc5c2005-11-15 13:30:52 +00001562 break;
1563 }
1564
Igor Sysoevae33d012006-01-17 20:04:32 +00001565 *d++ = ch;
Igor Sysoev0e5dc5c2005-11-15 13:30:52 +00001566
1567 break;
1568 }
1569
Igor Sysoev24025022005-12-16 15:07:08 +00001570 /* the invalid quoted character */
Igor Sysoev0e5dc5c2005-11-15 13:30:52 +00001571
1572 break;
1573 }
1574 }
1575
1576done:
1577
1578 *dst = d;
1579 *src = s;
1580}
Igor Sysoevd3283ff2005-12-05 13:18:09 +00001581
1582
Igor Sysoev1730c752007-09-27 09:36:50 +00001583uintptr_t
1584ngx_escape_html(u_char *dst, u_char *src, size_t size)
1585{
1586 u_char ch;
Igor Sysoev612ecb72009-11-02 17:12:09 +00001587 ngx_uint_t len;
Igor Sysoev1730c752007-09-27 09:36:50 +00001588
1589 if (dst == NULL) {
1590
1591 len = 0;
1592
Igor Sysoev612ecb72009-11-02 17:12:09 +00001593 while (size) {
Igor Sysoev1730c752007-09-27 09:36:50 +00001594 switch (*src++) {
1595
1596 case '<':
1597 len += sizeof("&lt;") - 2;
Igor Sysoevd3db9ea2007-10-09 18:42:00 +00001598 break;
Igor Sysoev1730c752007-09-27 09:36:50 +00001599
1600 case '>':
1601 len += sizeof("&gt;") - 2;
Igor Sysoevd3db9ea2007-10-09 18:42:00 +00001602 break;
Igor Sysoev1730c752007-09-27 09:36:50 +00001603
1604 case '&':
1605 len += sizeof("&amp;") - 2;
Igor Sysoevd3db9ea2007-10-09 18:42:00 +00001606 break;
Igor Sysoev1730c752007-09-27 09:36:50 +00001607
1608 default:
1609 break;
1610 }
Igor Sysoev612ecb72009-11-02 17:12:09 +00001611 size--;
Igor Sysoev1730c752007-09-27 09:36:50 +00001612 }
1613
1614 return (uintptr_t) len;
1615 }
1616
Igor Sysoev612ecb72009-11-02 17:12:09 +00001617 while (size) {
Igor Sysoev1730c752007-09-27 09:36:50 +00001618 ch = *src++;
1619
1620 switch (ch) {
1621
1622 case '<':
1623 *dst++ = '&'; *dst++ = 'l'; *dst++ = 't'; *dst++ = ';';
1624 break;
1625
1626 case '>':
1627 *dst++ = '&'; *dst++ = 'g'; *dst++ = 't'; *dst++ = ';';
1628 break;
1629
1630 case '&':
1631 *dst++ = '&'; *dst++ = 'a'; *dst++ = 'm'; *dst++ = 'p';
1632 *dst++ = ';';
1633 break;
1634
1635 default:
1636 *dst++ = ch;
1637 break;
1638 }
Igor Sysoev612ecb72009-11-02 17:12:09 +00001639 size--;
Igor Sysoev1730c752007-09-27 09:36:50 +00001640 }
1641
1642 return (uintptr_t) dst;
1643}
1644
1645
Igor Sysoev35921282007-05-21 14:05:23 +00001646/* ngx_sort() is implemented as insertion sort because we need stable sort */
1647
1648void
1649ngx_sort(void *base, size_t n, size_t size,
Igor Sysoevde8ec1e2008-03-24 13:04:02 +00001650 ngx_int_t (*cmp)(const void *, const void *))
Igor Sysoev35921282007-05-21 14:05:23 +00001651{
Igor Sysoev86341182008-03-23 19:58:54 +00001652 u_char *p1, *p2, *p;
1653
1654 p = ngx_alloc(size, ngx_cycle->log);
1655 if (p == NULL) {
1656 return;
1657 }
Igor Sysoev35921282007-05-21 14:05:23 +00001658
1659 for (p1 = (u_char *) base + size;
1660 p1 < (u_char *) base + n * size;
1661 p1 += size)
1662 {
Igor Sysoev86341182008-03-23 19:58:54 +00001663 ngx_memcpy(p, p1, size);
Igor Sysoev35921282007-05-21 14:05:23 +00001664
1665 for (p2 = p1;
Igor Sysoev86341182008-03-23 19:58:54 +00001666 p2 > (u_char *) base && cmp(p2 - size, p) > 0;
Igor Sysoev35921282007-05-21 14:05:23 +00001667 p2 -= size)
1668 {
1669 ngx_memcpy(p2, p2 - size, size);
1670 }
1671
Igor Sysoev86341182008-03-23 19:58:54 +00001672 ngx_memcpy(p2, p, size);
Igor Sysoev35921282007-05-21 14:05:23 +00001673 }
Igor Sysoev86341182008-03-23 19:58:54 +00001674
1675 ngx_free(p);
Igor Sysoev35921282007-05-21 14:05:23 +00001676}
1677
1678
Igor Sysoevd3283ff2005-12-05 13:18:09 +00001679#if (NGX_MEMCPY_LIMIT)
1680
1681void *
1682ngx_memcpy(void *dst, void *src, size_t n)
1683{
1684 if (n > NGX_MEMCPY_LIMIT) {
1685 ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0, "memcpy %uz bytes", n);
1686 ngx_debug_point();
1687 }
1688
1689 return memcpy(dst, src, n);
1690}
1691
1692#endif