xref: /unit/src/nxt_parse.c (revision 36:a71e28f0fb03)
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