10Sigor@sysoev.ru
20Sigor@sysoev.ru /*
30Sigor@sysoev.ru * Copyright (C) Igor Sysoev
40Sigor@sysoev.ru * Copyright (C) NGINX, Inc.
50Sigor@sysoev.ru */
60Sigor@sysoev.ru
70Sigor@sysoev.ru #include <nxt_main.h>
80Sigor@sysoev.ru
90Sigor@sysoev.ru
100Sigor@sysoev.ru /*
110Sigor@sysoev.ru * nxt_int_parse() returns size_t value >= 0 on success,
120Sigor@sysoev.ru * -1 on failure, and -2 on overflow.
130Sigor@sysoev.ru */
140Sigor@sysoev.ru
150Sigor@sysoev.ru nxt_int_t
nxt_int_parse(const u_char * p,size_t length)1610Sigor@sysoev.ru nxt_int_parse(const u_char *p, size_t length)
170Sigor@sysoev.ru {
180Sigor@sysoev.ru u_char c;
190Sigor@sysoev.ru nxt_uint_t val;
200Sigor@sysoev.ru
21*36Svbart@nginx.com static const nxt_uint_t cutoff = NXT_INT_T_MAX / 10;
22*36Svbart@nginx.com static const nxt_uint_t cutlim = NXT_INT_T_MAX % 10;
23*36Svbart@nginx.com
2410Sigor@sysoev.ru if (nxt_fast_path(length != 0)) {
250Sigor@sysoev.ru
260Sigor@sysoev.ru val = 0;
270Sigor@sysoev.ru
280Sigor@sysoev.ru do {
290Sigor@sysoev.ru c = *p++;
300Sigor@sysoev.ru
310Sigor@sysoev.ru /* Values below '0' become >= 208. */
320Sigor@sysoev.ru c = c - '0';
330Sigor@sysoev.ru
340Sigor@sysoev.ru if (nxt_slow_path(c > 9)) {
350Sigor@sysoev.ru return -1;
360Sigor@sysoev.ru }
370Sigor@sysoev.ru
38*36Svbart@nginx.com if (nxt_slow_path(val >= cutoff && (val > cutoff || c > cutlim))) {
390Sigor@sysoev.ru /* An overflow. */
400Sigor@sysoev.ru return -2;
410Sigor@sysoev.ru }
420Sigor@sysoev.ru
43*36Svbart@nginx.com val = val * 10 + c;
44*36Svbart@nginx.com
4510Sigor@sysoev.ru length--;
460Sigor@sysoev.ru
4710Sigor@sysoev.ru } while (length != 0);
480Sigor@sysoev.ru
490Sigor@sysoev.ru return val;
500Sigor@sysoev.ru }
510Sigor@sysoev.ru
520Sigor@sysoev.ru return -1;
530Sigor@sysoev.ru }
540Sigor@sysoev.ru
550Sigor@sysoev.ru
560Sigor@sysoev.ru /*
570Sigor@sysoev.ru * nxt_size_t_parse() returns size_t value >= 0 on success,
580Sigor@sysoev.ru * -1 on failure, and -2 on overflow.
590Sigor@sysoev.ru */
600Sigor@sysoev.ru
610Sigor@sysoev.ru ssize_t
nxt_size_t_parse(const u_char * p,size_t length)6210Sigor@sysoev.ru nxt_size_t_parse(const u_char *p, size_t length)
630Sigor@sysoev.ru {
640Sigor@sysoev.ru u_char c;
650Sigor@sysoev.ru size_t val;
660Sigor@sysoev.ru
67*36Svbart@nginx.com static const size_t cutoff = NXT_SIZE_T_MAX / 10;
68*36Svbart@nginx.com static const size_t cutlim = NXT_SIZE_T_MAX % 10;
69*36Svbart@nginx.com
7010Sigor@sysoev.ru if (nxt_fast_path(length != 0)) {
710Sigor@sysoev.ru
720Sigor@sysoev.ru val = 0;
730Sigor@sysoev.ru
740Sigor@sysoev.ru do {
750Sigor@sysoev.ru c = *p++;
760Sigor@sysoev.ru
770Sigor@sysoev.ru /* Values below '0' become >= 208. */
780Sigor@sysoev.ru c = c - '0';
790Sigor@sysoev.ru
800Sigor@sysoev.ru if (nxt_slow_path(c > 9)) {
810Sigor@sysoev.ru return -1;
820Sigor@sysoev.ru }
830Sigor@sysoev.ru
84*36Svbart@nginx.com if (nxt_slow_path(val >= cutoff && (val > cutoff || c > cutlim))) {
850Sigor@sysoev.ru /* An overflow. */
860Sigor@sysoev.ru return -2;
870Sigor@sysoev.ru }
880Sigor@sysoev.ru
89*36Svbart@nginx.com val = val * 10 + c;
90*36Svbart@nginx.com
9110Sigor@sysoev.ru length--;
920Sigor@sysoev.ru
9310Sigor@sysoev.ru } while (length != 0);
940Sigor@sysoev.ru
950Sigor@sysoev.ru return val;
960Sigor@sysoev.ru }
970Sigor@sysoev.ru
980Sigor@sysoev.ru return -1;
990Sigor@sysoev.ru }
1000Sigor@sysoev.ru
1010Sigor@sysoev.ru
1020Sigor@sysoev.ru /*
1030Sigor@sysoev.ru * nxt_size_parse() parses size string with optional K or M units and
1040Sigor@sysoev.ru * returns size_t value >= 0 on success, -1 on failure, and -2 on overflow.
1050Sigor@sysoev.ru */
1060Sigor@sysoev.ru
1070Sigor@sysoev.ru ssize_t
nxt_size_parse(const u_char * p,size_t length)10810Sigor@sysoev.ru nxt_size_parse(const u_char *p, size_t length)
1090Sigor@sysoev.ru {
110*36Svbart@nginx.com u_char unit;
111*36Svbart@nginx.com ssize_t val, max;
1120Sigor@sysoev.ru nxt_uint_t shift;
1130Sigor@sysoev.ru
11410Sigor@sysoev.ru if (nxt_fast_path(length != 0)) {
1150Sigor@sysoev.ru
11610Sigor@sysoev.ru length--;
1170Sigor@sysoev.ru
1180Sigor@sysoev.ru /* Upper case. */
11910Sigor@sysoev.ru unit = p[length] & ~0x20;
1200Sigor@sysoev.ru
1210Sigor@sysoev.ru switch (unit) {
1220Sigor@sysoev.ru
1230Sigor@sysoev.ru case 'G':
1240Sigor@sysoev.ru max = NXT_SIZE_T_MAX >> 30;
1250Sigor@sysoev.ru shift = 30;
1260Sigor@sysoev.ru break;
1270Sigor@sysoev.ru
1280Sigor@sysoev.ru case 'M':
1290Sigor@sysoev.ru max = NXT_SIZE_T_MAX >> 20;
1300Sigor@sysoev.ru shift = 20;
1310Sigor@sysoev.ru break;
1320Sigor@sysoev.ru
1330Sigor@sysoev.ru case 'K':
1340Sigor@sysoev.ru max = NXT_SIZE_T_MAX >> 10;
1350Sigor@sysoev.ru shift = 10;
1360Sigor@sysoev.ru break;
1370Sigor@sysoev.ru
1380Sigor@sysoev.ru default:
139*36Svbart@nginx.com return nxt_size_t_parse(p, length + 1);
1400Sigor@sysoev.ru }
1410Sigor@sysoev.ru
142*36Svbart@nginx.com val = nxt_size_t_parse(p, length);
1430Sigor@sysoev.ru
144*36Svbart@nginx.com if (nxt_fast_path(val >= 0)) {
1450Sigor@sysoev.ru
146*36Svbart@nginx.com if (nxt_slow_path(val > max)) {
147*36Svbart@nginx.com /* An overflow. */
148*36Svbart@nginx.com return -2;
149*36Svbart@nginx.com }
1500Sigor@sysoev.ru
151*36Svbart@nginx.com val <<= shift;
152*36Svbart@nginx.com }
1530Sigor@sysoev.ru
154*36Svbart@nginx.com return val;
1550Sigor@sysoev.ru }
1560Sigor@sysoev.ru
1570Sigor@sysoev.ru return -1;
1580Sigor@sysoev.ru }
1590Sigor@sysoev.ru
1600Sigor@sysoev.ru
1610Sigor@sysoev.ru /*
1620Sigor@sysoev.ru * nxt_off_t_parse() returns nxt_off_t value >= 0 on success,
1630Sigor@sysoev.ru * -1 on failure, and -2 on overflow.
1640Sigor@sysoev.ru */
1650Sigor@sysoev.ru
1660Sigor@sysoev.ru nxt_off_t
nxt_off_t_parse(const u_char * p,size_t length)16710Sigor@sysoev.ru nxt_off_t_parse(const u_char *p, size_t length)
1680Sigor@sysoev.ru {
1690Sigor@sysoev.ru u_char c;
1700Sigor@sysoev.ru nxt_uoff_t val;
1710Sigor@sysoev.ru
172*36Svbart@nginx.com static const nxt_uoff_t cutoff = NXT_OFF_T_MAX / 10;
173*36Svbart@nginx.com static const nxt_uoff_t cutlim = NXT_OFF_T_MAX % 10;
174*36Svbart@nginx.com
17510Sigor@sysoev.ru if (nxt_fast_path(length != 0)) {
1760Sigor@sysoev.ru
1770Sigor@sysoev.ru val = 0;
1780Sigor@sysoev.ru
1790Sigor@sysoev.ru do {
1800Sigor@sysoev.ru c = *p++;
1810Sigor@sysoev.ru
1820Sigor@sysoev.ru /* Values below '0' become >= 208. */
1830Sigor@sysoev.ru c = c - '0';
1840Sigor@sysoev.ru
1850Sigor@sysoev.ru if (nxt_slow_path(c > 9)) {
1860Sigor@sysoev.ru return -1;
1870Sigor@sysoev.ru }
1880Sigor@sysoev.ru
189*36Svbart@nginx.com if (nxt_slow_path(val >= cutoff && (val > cutoff || c > cutlim))) {
1900Sigor@sysoev.ru /* An overflow. */
1910Sigor@sysoev.ru return -2;
1920Sigor@sysoev.ru }
1930Sigor@sysoev.ru
194*36Svbart@nginx.com val = val * 10 + c;
195*36Svbart@nginx.com
19610Sigor@sysoev.ru length--;
1970Sigor@sysoev.ru
19810Sigor@sysoev.ru } while (length != 0);
1990Sigor@sysoev.ru
2000Sigor@sysoev.ru return val;
2010Sigor@sysoev.ru }
2020Sigor@sysoev.ru
2030Sigor@sysoev.ru return -1;
2040Sigor@sysoev.ru }
2050Sigor@sysoev.ru
2060Sigor@sysoev.ru
2070Sigor@sysoev.ru /*
2080Sigor@sysoev.ru * nxt_str_int_parse() returns nxt_int_t value >= 0 on success,
2090Sigor@sysoev.ru * -1 on failure, and -2 on overflow and also updates the 's' argument.
2100Sigor@sysoev.ru */
2110Sigor@sysoev.ru
2120Sigor@sysoev.ru nxt_int_t
nxt_str_int_parse(nxt_str_t * s)2130Sigor@sysoev.ru nxt_str_int_parse(nxt_str_t *s)
2140Sigor@sysoev.ru {
2150Sigor@sysoev.ru u_char c, *p;
21610Sigor@sysoev.ru size_t length;
2170Sigor@sysoev.ru nxt_uint_t val;
2180Sigor@sysoev.ru
219*36Svbart@nginx.com static const nxt_uint_t cutoff = NXT_INT_T_MAX / 10;
220*36Svbart@nginx.com static const nxt_uint_t cutlim = NXT_INT_T_MAX % 10;
221*36Svbart@nginx.com
22210Sigor@sysoev.ru length = s->length;
2230Sigor@sysoev.ru
22410Sigor@sysoev.ru if (nxt_slow_path(length == 0)) {
2250Sigor@sysoev.ru return -1;
2260Sigor@sysoev.ru }
2270Sigor@sysoev.ru
22810Sigor@sysoev.ru p = s->start;
2290Sigor@sysoev.ru val = 0;
2300Sigor@sysoev.ru
2310Sigor@sysoev.ru do {
2320Sigor@sysoev.ru c = *p;
2330Sigor@sysoev.ru
2340Sigor@sysoev.ru /* Values below '0' become >= 208. */
2350Sigor@sysoev.ru c = c - '0';
2360Sigor@sysoev.ru
2370Sigor@sysoev.ru if (c > 9) {
2380Sigor@sysoev.ru break;
2390Sigor@sysoev.ru }
2400Sigor@sysoev.ru
241*36Svbart@nginx.com if (nxt_slow_path(val >= cutoff && (val > cutoff || c > cutlim))) {
2420Sigor@sysoev.ru /* An overflow. */
2430Sigor@sysoev.ru return -2;
2440Sigor@sysoev.ru }
2450Sigor@sysoev.ru
246*36Svbart@nginx.com val = val * 10 + c;
247*36Svbart@nginx.com
2480Sigor@sysoev.ru p++;
24910Sigor@sysoev.ru length--;
2500Sigor@sysoev.ru
25110Sigor@sysoev.ru } while (length != 0);
2520Sigor@sysoev.ru
25310Sigor@sysoev.ru s->length = length;
25410Sigor@sysoev.ru s->start = p;
2550Sigor@sysoev.ru
2560Sigor@sysoev.ru return val;
2570Sigor@sysoev.ru }
2580Sigor@sysoev.ru
2590Sigor@sysoev.ru
2600Sigor@sysoev.ru /*
2610Sigor@sysoev.ru * nxt_number_parse() returns a double value >= 0 and updates the start
2620Sigor@sysoev.ru * argument on success, or returns -1 on failure or -2 on overflow.
2630Sigor@sysoev.ru */
2640Sigor@sysoev.ru
2650Sigor@sysoev.ru double
nxt_number_parse(const u_char ** start,const u_char * end)2660Sigor@sysoev.ru nxt_number_parse(const u_char **start, const u_char *end)
2670Sigor@sysoev.ru {
2680Sigor@sysoev.ru u_char c;
269*36Svbart@nginx.com nxt_bool_t overflow;
2700Sigor@sysoev.ru nxt_uint_t integral, frac, power;
2710Sigor@sysoev.ru const u_char *p;
2720Sigor@sysoev.ru
273*36Svbart@nginx.com static const nxt_uint_t cutoff = NXT_INT_T_MAX / 10;
274*36Svbart@nginx.com static const nxt_uint_t cutlim = NXT_INT_T_MAX % 10;
275*36Svbart@nginx.com
2760Sigor@sysoev.ru p = *start;
2770Sigor@sysoev.ru integral = 0;
2780Sigor@sysoev.ru
2790Sigor@sysoev.ru while (p < end) {
2800Sigor@sysoev.ru c = *p;
2810Sigor@sysoev.ru
2820Sigor@sysoev.ru if (c == '.') {
2830Sigor@sysoev.ru goto dot;
2840Sigor@sysoev.ru }
2850Sigor@sysoev.ru
2860Sigor@sysoev.ru /* Values below '0' become >= 208. */
2870Sigor@sysoev.ru c = c - '0';
2880Sigor@sysoev.ru
2890Sigor@sysoev.ru if (c > 9) {
2900Sigor@sysoev.ru break;
2910Sigor@sysoev.ru }
2920Sigor@sysoev.ru
293*36Svbart@nginx.com overflow = nxt_expect(0, (integral >= cutoff
294*36Svbart@nginx.com && (integral > cutoff || c > cutlim)));
2950Sigor@sysoev.ru
296*36Svbart@nginx.com if (overflow) {
2970Sigor@sysoev.ru return -2;
2980Sigor@sysoev.ru }
2990Sigor@sysoev.ru
300*36Svbart@nginx.com integral = integral * 10 + c;
301*36Svbart@nginx.com
3020Sigor@sysoev.ru p++;
3030Sigor@sysoev.ru }
3040Sigor@sysoev.ru
3050Sigor@sysoev.ru if (nxt_fast_path(p != *start)) {
3060Sigor@sysoev.ru *start = p;
3070Sigor@sysoev.ru return integral;
3080Sigor@sysoev.ru }
3090Sigor@sysoev.ru
3100Sigor@sysoev.ru /* No value. */
3110Sigor@sysoev.ru return -1;
3120Sigor@sysoev.ru
3130Sigor@sysoev.ru dot:
3140Sigor@sysoev.ru
3150Sigor@sysoev.ru if (nxt_slow_path(p == *start)) {
3160Sigor@sysoev.ru /* No leading digit before dot. */
3170Sigor@sysoev.ru return -1;
3180Sigor@sysoev.ru }
3190Sigor@sysoev.ru
3200Sigor@sysoev.ru frac = 0;
3210Sigor@sysoev.ru power = 1;
3220Sigor@sysoev.ru
3230Sigor@sysoev.ru for (p++; p < end; p++) {
3240Sigor@sysoev.ru c = *p;
3250Sigor@sysoev.ru
3260Sigor@sysoev.ru /* Values below '0' become >= 208. */
3270Sigor@sysoev.ru c = c - '0';
3280Sigor@sysoev.ru
3290Sigor@sysoev.ru if (c > 9) {
3300Sigor@sysoev.ru break;
3310Sigor@sysoev.ru }
3320Sigor@sysoev.ru
333*36Svbart@nginx.com overflow = nxt_expect(0, (frac >= cutoff && (frac > cutoff
334*36Svbart@nginx.com || c > cutlim))
335*36Svbart@nginx.com || power > cutoff);
336*36Svbart@nginx.com
337*36Svbart@nginx.com if (overflow) {
338*36Svbart@nginx.com return -2;
339*36Svbart@nginx.com }
340*36Svbart@nginx.com
3410Sigor@sysoev.ru frac = frac * 10 + c;
3420Sigor@sysoev.ru power *= 10;
3430Sigor@sysoev.ru }
3440Sigor@sysoev.ru
3450Sigor@sysoev.ru *start = p;
3460Sigor@sysoev.ru
3470Sigor@sysoev.ru return integral + (double) frac / power;
3480Sigor@sysoev.ru }
349