xref: /unit/src/nxt_time_parse.c (revision 2140)
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_time_parse() parses a time string given in RFC822, RFC850, or ISOC
120Sigor@sysoev.ru  * formats and returns nxt_time_t value >= 0 on success or -1 on failure.
130Sigor@sysoev.ru  */
140Sigor@sysoev.ru 
150Sigor@sysoev.ru nxt_time_t
160Sigor@sysoev.ru nxt_time_parse(const u_char *p, size_t len)
170Sigor@sysoev.ru {
180Sigor@sysoev.ru     size_t            n;
190Sigor@sysoev.ru     u_char            c;
200Sigor@sysoev.ru     uint64_t          s;
210Sigor@sysoev.ru     nxt_int_t         yr, month, day, hour, min, sec;
220Sigor@sysoev.ru     nxt_uint_t        year, days;
230Sigor@sysoev.ru     const u_char      *end;
240Sigor@sysoev.ru 
25*2140Sandrew@digital-domain.net     static const nxt_int_t  mday[12] = {
260Sigor@sysoev.ru         31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
270Sigor@sysoev.ru     };
280Sigor@sysoev.ru 
290Sigor@sysoev.ru     enum {
300Sigor@sysoev.ru         RFC822 = 0,   /* "Mon, 28 Sep 1970 12:00:00"  */
310Sigor@sysoev.ru         RFC850,       /* "Monday, 28-Sep-70 12:00:00" */
320Sigor@sysoev.ru         ISOC,         /* "Mon Sep 28 12:00:00 1970"   */
330Sigor@sysoev.ru     } fmt;
340Sigor@sysoev.ru 
350Sigor@sysoev.ru     fmt = RFC822;
360Sigor@sysoev.ru     end = p + len;
370Sigor@sysoev.ru 
380Sigor@sysoev.ru     while (p < end) {
390Sigor@sysoev.ru         c = *p++;
400Sigor@sysoev.ru 
410Sigor@sysoev.ru         if (c == ',') {
420Sigor@sysoev.ru             break;
430Sigor@sysoev.ru         }
440Sigor@sysoev.ru 
450Sigor@sysoev.ru         if (c == ' ') {
460Sigor@sysoev.ru             fmt = ISOC;
470Sigor@sysoev.ru             break;
480Sigor@sysoev.ru         }
490Sigor@sysoev.ru     }
500Sigor@sysoev.ru 
510Sigor@sysoev.ru     while (p < end) {
520Sigor@sysoev.ru         if (*p != ' ') {
530Sigor@sysoev.ru             break;
540Sigor@sysoev.ru         }
550Sigor@sysoev.ru 
560Sigor@sysoev.ru         p++;
570Sigor@sysoev.ru     }
580Sigor@sysoev.ru 
590Sigor@sysoev.ru     if (nxt_slow_path(p + 18 > end)) {
600Sigor@sysoev.ru         /* Lesser than RFC850 "28-Sep-70 12:00:00" length. */
610Sigor@sysoev.ru         return -1;
620Sigor@sysoev.ru     }
630Sigor@sysoev.ru 
640Sigor@sysoev.ru     day = 0;
650Sigor@sysoev.ru 
660Sigor@sysoev.ru     if (fmt != ISOC) {
670Sigor@sysoev.ru         day = nxt_int_parse(p, 2);
680Sigor@sysoev.ru         if (nxt_slow_path(day <= 0)) {
690Sigor@sysoev.ru             return -1;
700Sigor@sysoev.ru         }
710Sigor@sysoev.ru         p += 2;
720Sigor@sysoev.ru 
730Sigor@sysoev.ru         if (*p == ' ') {
740Sigor@sysoev.ru             if (nxt_slow_path(p + 18 > end)) {
750Sigor@sysoev.ru                 /* Lesser than RFC822 " Sep 1970 12:00:00" length. */
760Sigor@sysoev.ru                 return -1;
770Sigor@sysoev.ru             }
780Sigor@sysoev.ru 
790Sigor@sysoev.ru             /* RFC822 */
800Sigor@sysoev.ru 
810Sigor@sysoev.ru         } else if (*p == '-') {
820Sigor@sysoev.ru             fmt = RFC850;
830Sigor@sysoev.ru 
840Sigor@sysoev.ru         } else {
850Sigor@sysoev.ru             return -1;
860Sigor@sysoev.ru         }
870Sigor@sysoev.ru 
880Sigor@sysoev.ru         p++;
890Sigor@sysoev.ru     }
900Sigor@sysoev.ru 
910Sigor@sysoev.ru     switch (*p) {
920Sigor@sysoev.ru 
930Sigor@sysoev.ru     case 'J':
940Sigor@sysoev.ru         month = p[1] == 'a' ? 0 : p[2] == 'n' ? 5 : 6;
950Sigor@sysoev.ru         break;
960Sigor@sysoev.ru 
970Sigor@sysoev.ru     case 'F':
980Sigor@sysoev.ru         month = 1;
990Sigor@sysoev.ru         break;
1000Sigor@sysoev.ru 
1010Sigor@sysoev.ru     case 'M':
1020Sigor@sysoev.ru         month = p[2] == 'r' ? 2 : 4;
1030Sigor@sysoev.ru         break;
1040Sigor@sysoev.ru 
1050Sigor@sysoev.ru     case 'A':
1060Sigor@sysoev.ru         month = p[1] == 'p' ? 3 : 7;
1070Sigor@sysoev.ru         break;
1080Sigor@sysoev.ru 
1090Sigor@sysoev.ru     case 'S':
1100Sigor@sysoev.ru         month = 8;
1110Sigor@sysoev.ru         break;
1120Sigor@sysoev.ru 
1130Sigor@sysoev.ru     case 'O':
1140Sigor@sysoev.ru         month = 9;
1150Sigor@sysoev.ru         break;
1160Sigor@sysoev.ru 
1170Sigor@sysoev.ru     case 'N':
1180Sigor@sysoev.ru         month = 10;
1190Sigor@sysoev.ru         break;
1200Sigor@sysoev.ru 
1210Sigor@sysoev.ru     case 'D':
1220Sigor@sysoev.ru         month = 11;
1230Sigor@sysoev.ru         break;
1240Sigor@sysoev.ru 
1250Sigor@sysoev.ru     default:
1260Sigor@sysoev.ru         return -1;
1270Sigor@sysoev.ru     }
1280Sigor@sysoev.ru 
1290Sigor@sysoev.ru     p += 3;
1300Sigor@sysoev.ru     yr = 0;
1310Sigor@sysoev.ru 
1320Sigor@sysoev.ru     switch (fmt) {
1330Sigor@sysoev.ru 
1340Sigor@sysoev.ru     case RFC822:
1350Sigor@sysoev.ru         if (nxt_slow_path(*p++ != ' ')) {
1360Sigor@sysoev.ru             return -1;
1370Sigor@sysoev.ru         }
1380Sigor@sysoev.ru 
1390Sigor@sysoev.ru         yr = nxt_int_parse(p, 4);
1400Sigor@sysoev.ru         if (nxt_slow_path(yr <= 0)) {
1410Sigor@sysoev.ru             return -1;
1420Sigor@sysoev.ru         }
1430Sigor@sysoev.ru         p += 4;
1440Sigor@sysoev.ru 
1450Sigor@sysoev.ru         break;
1460Sigor@sysoev.ru 
1470Sigor@sysoev.ru     case RFC850:
1480Sigor@sysoev.ru         if (nxt_slow_path(*p++ != '-')) {
1490Sigor@sysoev.ru             return -1;
1500Sigor@sysoev.ru         }
1510Sigor@sysoev.ru 
1520Sigor@sysoev.ru         yr = nxt_int_parse(p, 2);
1530Sigor@sysoev.ru         if (nxt_slow_path(yr <= 0)) {
1540Sigor@sysoev.ru             return -1;
1550Sigor@sysoev.ru         }
1560Sigor@sysoev.ru         p += 2;
1570Sigor@sysoev.ru 
1580Sigor@sysoev.ru         yr += (yr < 70) ? 2000 : 1900;
1590Sigor@sysoev.ru 
1600Sigor@sysoev.ru         break;
1610Sigor@sysoev.ru 
1620Sigor@sysoev.ru     default: /* ISOC */
1630Sigor@sysoev.ru         if (nxt_slow_path(*p++ != ' ')) {
1640Sigor@sysoev.ru             return -1;
1650Sigor@sysoev.ru         }
1660Sigor@sysoev.ru 
1670Sigor@sysoev.ru         if (p[0] != ' ') {
1680Sigor@sysoev.ru             n = 2;
1690Sigor@sysoev.ru 
1700Sigor@sysoev.ru             if (p[1] == ' ') {
1710Sigor@sysoev.ru                 n = 1;
1720Sigor@sysoev.ru             }
1730Sigor@sysoev.ru 
1740Sigor@sysoev.ru         } else {
1750Sigor@sysoev.ru             p++;
1760Sigor@sysoev.ru             n = 1;
1770Sigor@sysoev.ru         }
1780Sigor@sysoev.ru 
1790Sigor@sysoev.ru         day = nxt_int_parse(p, n);
1800Sigor@sysoev.ru         if (nxt_slow_path(day <= 0)) {
1810Sigor@sysoev.ru             return -1;
1820Sigor@sysoev.ru         }
1830Sigor@sysoev.ru         p += n;
1840Sigor@sysoev.ru 
1850Sigor@sysoev.ru         if (nxt_slow_path(p + 14 > end)) {
1860Sigor@sysoev.ru             /* Lesser than ISOC " 12:00:00 1970" length. */
1870Sigor@sysoev.ru             return -1;
1880Sigor@sysoev.ru         }
1890Sigor@sysoev.ru 
1900Sigor@sysoev.ru         break;
1910Sigor@sysoev.ru     }
1920Sigor@sysoev.ru 
1930Sigor@sysoev.ru     if (nxt_slow_path(*p++ != ' ')) {
1940Sigor@sysoev.ru         return -1;
1950Sigor@sysoev.ru     }
1960Sigor@sysoev.ru 
1970Sigor@sysoev.ru     hour = nxt_int_parse(p, 2);
1980Sigor@sysoev.ru     if (nxt_slow_path(hour < 0)) {
1990Sigor@sysoev.ru         return -1;
2000Sigor@sysoev.ru     }
2010Sigor@sysoev.ru     p += 2;
2020Sigor@sysoev.ru 
2030Sigor@sysoev.ru     if (nxt_slow_path(*p++ != ':')) {
2040Sigor@sysoev.ru         return -1;
2050Sigor@sysoev.ru     }
2060Sigor@sysoev.ru 
2070Sigor@sysoev.ru     min = nxt_int_parse(p, 2);
2080Sigor@sysoev.ru     if (nxt_slow_path(min < 0)) {
2090Sigor@sysoev.ru         return -1;
2100Sigor@sysoev.ru     }
2110Sigor@sysoev.ru     p += 2;
2120Sigor@sysoev.ru 
2130Sigor@sysoev.ru     if (nxt_slow_path(*p++ != ':')) {
2140Sigor@sysoev.ru         return -1;
2150Sigor@sysoev.ru     }
2160Sigor@sysoev.ru 
2170Sigor@sysoev.ru     sec = nxt_int_parse(p, 2);
2180Sigor@sysoev.ru     if (nxt_slow_path(sec < 0)) {
2190Sigor@sysoev.ru         return -1;
2200Sigor@sysoev.ru     }
2210Sigor@sysoev.ru 
2220Sigor@sysoev.ru     if (fmt == ISOC) {
2230Sigor@sysoev.ru         p += 2;
2240Sigor@sysoev.ru 
2250Sigor@sysoev.ru         if (nxt_slow_path(*p++ != ' ')) {
2260Sigor@sysoev.ru             return -1;
2270Sigor@sysoev.ru         }
2280Sigor@sysoev.ru 
2290Sigor@sysoev.ru         yr = nxt_int_parse(p, 4);
2300Sigor@sysoev.ru         if (nxt_slow_path(yr < 0)) {
2310Sigor@sysoev.ru             return -1;
2320Sigor@sysoev.ru         }
2330Sigor@sysoev.ru     }
2340Sigor@sysoev.ru 
2350Sigor@sysoev.ru     if (nxt_slow_path(hour > 23 || min > 59 || sec > 59)) {
2360Sigor@sysoev.ru         return -1;
2370Sigor@sysoev.ru     }
2380Sigor@sysoev.ru 
2390Sigor@sysoev.ru     year = yr;
2400Sigor@sysoev.ru 
2410Sigor@sysoev.ru     if (day == 29 && month == 1) {
2420Sigor@sysoev.ru 
2430Sigor@sysoev.ru         if (nxt_slow_path((year & 3) != 0)) {
2440Sigor@sysoev.ru             /* Not a leap year. */
2450Sigor@sysoev.ru             return -1;
2460Sigor@sysoev.ru         }
2470Sigor@sysoev.ru 
2480Sigor@sysoev.ru         if (nxt_slow_path((year % 100 == 0) && (year % 400) != 0)) {
2490Sigor@sysoev.ru             /* Not a leap year. */
2500Sigor@sysoev.ru             return -1;
2510Sigor@sysoev.ru         }
2520Sigor@sysoev.ru 
2530Sigor@sysoev.ru     } else if (nxt_slow_path(day > mday[(nxt_uint_t) month])) {
2540Sigor@sysoev.ru         return -1;
2550Sigor@sysoev.ru     }
2560Sigor@sysoev.ru 
2570Sigor@sysoev.ru     /*
2580Sigor@sysoev.ru      * Shift new year to March 1 and start months
2590Sigor@sysoev.ru      * from 1 (not 0), as required for Gauss' formula.
2600Sigor@sysoev.ru      */
2610Sigor@sysoev.ru 
2620Sigor@sysoev.ru     if (--month <= 0) {
2630Sigor@sysoev.ru         month += 12;
2640Sigor@sysoev.ru         year -= 1;
2650Sigor@sysoev.ru     }
2660Sigor@sysoev.ru 
2670Sigor@sysoev.ru     /* Gauss' formula for Gregorian days since March 1, 1 BCE. */
2680Sigor@sysoev.ru 
2690Sigor@sysoev.ru            /* Days in years including leap years since March 1, 1 BCE. */
2700Sigor@sysoev.ru     days = 365 * year + year / 4 - year / 100 + year / 400
2710Sigor@sysoev.ru 
2720Sigor@sysoev.ru            /* Days before the month. */
2730Sigor@sysoev.ru            + 367 * (nxt_uint_t) month / 12 - 30
2740Sigor@sysoev.ru 
2750Sigor@sysoev.ru            /* Days before the day. */
2760Sigor@sysoev.ru            + (nxt_uint_t) day - 1;
2770Sigor@sysoev.ru 
2780Sigor@sysoev.ru     /*
2790Sigor@sysoev.ru      * 719527 days were between March 1, 1 BCE and March 1, 1970,
2800Sigor@sysoev.ru      * 31 and 28 days were in January and February 1970.
2810Sigor@sysoev.ru      */
2820Sigor@sysoev.ru     days = days - 719527 + 31 + 28;
2830Sigor@sysoev.ru 
2840Sigor@sysoev.ru     s = (uint64_t) days * 86400
2852078Salx.manpages@gmail.com         + (nxt_uint_t) hour * 3600
2862078Salx.manpages@gmail.com         + (nxt_uint_t) min * 60
2872078Salx.manpages@gmail.com         + (nxt_uint_t) sec;
2880Sigor@sysoev.ru 
2890Sigor@sysoev.ru #if (NXT_TIME_T_SIZE <= 4)
2900Sigor@sysoev.ru 
2910Sigor@sysoev.ru     /* Y2038 */
2920Sigor@sysoev.ru 
293611Svbart@nginx.com     if (nxt_slow_path(s > 0x7FFFFFFF)) {
2940Sigor@sysoev.ru         return -1;
2950Sigor@sysoev.ru     }
2960Sigor@sysoev.ru 
2970Sigor@sysoev.ru #endif
2980Sigor@sysoev.ru 
2990Sigor@sysoev.ru     return (nxt_time_t) s;
3000Sigor@sysoev.ru }
3010Sigor@sysoev.ru 
3020Sigor@sysoev.ru 
3030Sigor@sysoev.ru /*
3040Sigor@sysoev.ru  * nxt_term_parse() parses term string given in format "200", "10m",
3050Sigor@sysoev.ru  * or "1d 1h" and returns nxt_int_t value >= 0 on success, -1 on failure,
3060Sigor@sysoev.ru  * and -2 on overflow.  The maximum valid value is 2^31 - 1 or about
3070Sigor@sysoev.ru  * 68 years in seconds or about 24 days in milliseconds.
3080Sigor@sysoev.ru  */
3090Sigor@sysoev.ru 
3100Sigor@sysoev.ru nxt_int_t
3110Sigor@sysoev.ru nxt_term_parse(const u_char *p, size_t len, nxt_bool_t seconds)
3120Sigor@sysoev.ru {
3130Sigor@sysoev.ru     u_char        c, ch;
3140Sigor@sysoev.ru     nxt_uint_t    val, term, scale, max;
3150Sigor@sysoev.ru     const u_char  *end;
3160Sigor@sysoev.ru 
3170Sigor@sysoev.ru     enum {
3180Sigor@sysoev.ru         st_first_digit = 0,
3190Sigor@sysoev.ru         st_digit,
3200Sigor@sysoev.ru         st_letter,
3210Sigor@sysoev.ru         st_space,
3220Sigor@sysoev.ru     } state;
3230Sigor@sysoev.ru 
3240Sigor@sysoev.ru     enum {
3250Sigor@sysoev.ru         st_start = 0,
3260Sigor@sysoev.ru         st_year,
3270Sigor@sysoev.ru         st_month,
3280Sigor@sysoev.ru         st_week,
3290Sigor@sysoev.ru         st_day,
3300Sigor@sysoev.ru         st_hour,
3310Sigor@sysoev.ru         st_min,
3320Sigor@sysoev.ru         st_sec,
3330Sigor@sysoev.ru         st_msec,
3340Sigor@sysoev.ru         st_last,
3350Sigor@sysoev.ru     } step;
3360Sigor@sysoev.ru 
3370Sigor@sysoev.ru     val = 0;
3380Sigor@sysoev.ru     term = 0;
3390Sigor@sysoev.ru     state = st_first_digit;
3400Sigor@sysoev.ru     step = seconds ? st_start : st_month;
3410Sigor@sysoev.ru 
3420Sigor@sysoev.ru     end = p + len;
3430Sigor@sysoev.ru 
3440Sigor@sysoev.ru     while (p < end) {
3450Sigor@sysoev.ru 
3460Sigor@sysoev.ru         ch = *p++;
3470Sigor@sysoev.ru 
3480Sigor@sysoev.ru         if (state == st_space) {
3490Sigor@sysoev.ru 
3500Sigor@sysoev.ru             if (ch == ' ') {
3510Sigor@sysoev.ru                 continue;
3520Sigor@sysoev.ru             }
3530Sigor@sysoev.ru 
3540Sigor@sysoev.ru             state = st_first_digit;
3550Sigor@sysoev.ru         }
3560Sigor@sysoev.ru 
3570Sigor@sysoev.ru         if (state != st_letter) {
3580Sigor@sysoev.ru 
3590Sigor@sysoev.ru             /* Values below '0' become >= 208. */
3600Sigor@sysoev.ru             c = ch - '0';
3610Sigor@sysoev.ru 
3620Sigor@sysoev.ru             if (c <= 9) {
3630Sigor@sysoev.ru                 val = val * 10 + c;
3640Sigor@sysoev.ru                 state = st_digit;
3650Sigor@sysoev.ru                 continue;
3660Sigor@sysoev.ru             }
3670Sigor@sysoev.ru 
3680Sigor@sysoev.ru             if (state == st_first_digit) {
3690Sigor@sysoev.ru                 return -1;
3700Sigor@sysoev.ru             }
3710Sigor@sysoev.ru 
3720Sigor@sysoev.ru             state = st_letter;
3730Sigor@sysoev.ru         }
3740Sigor@sysoev.ru 
3750Sigor@sysoev.ru         switch (ch) {
3760Sigor@sysoev.ru 
3770Sigor@sysoev.ru         case 'y':
3780Sigor@sysoev.ru             if (step > st_start) {
3790Sigor@sysoev.ru                 return -1;
3800Sigor@sysoev.ru             }
3810Sigor@sysoev.ru             step = st_year;
3820Sigor@sysoev.ru             max = NXT_INT32_T_MAX / (365 * 24 * 60 * 60);
3830Sigor@sysoev.ru             scale = 365 * 24 * 60 * 60;
3840Sigor@sysoev.ru             break;
3850Sigor@sysoev.ru 
3860Sigor@sysoev.ru         case 'M':
3870Sigor@sysoev.ru             if (step >= st_month) {
3880Sigor@sysoev.ru                 return -1;
3890Sigor@sysoev.ru             }
3900Sigor@sysoev.ru             step = st_month;
3910Sigor@sysoev.ru             max = NXT_INT32_T_MAX / (30 * 24 * 60 * 60);
3920Sigor@sysoev.ru             scale = 30 * 24 * 60 * 60;
3930Sigor@sysoev.ru             break;
3940Sigor@sysoev.ru 
3950Sigor@sysoev.ru         case 'w':
3960Sigor@sysoev.ru             if (step >= st_week) {
3970Sigor@sysoev.ru                 return -1;
3980Sigor@sysoev.ru             }
3990Sigor@sysoev.ru             step = st_week;
4000Sigor@sysoev.ru             max = NXT_INT32_T_MAX / (7 * 24 * 60 * 60);
4010Sigor@sysoev.ru             scale = 7 * 24 * 60 * 60;
4020Sigor@sysoev.ru             break;
4030Sigor@sysoev.ru 
4040Sigor@sysoev.ru         case 'd':
4050Sigor@sysoev.ru             if (step >= st_day) {
4060Sigor@sysoev.ru                 return -1;
4070Sigor@sysoev.ru             }
4080Sigor@sysoev.ru             step = st_day;
4090Sigor@sysoev.ru             max = NXT_INT32_T_MAX / (24 * 60 * 60);
4100Sigor@sysoev.ru             scale = 24 * 60 * 60;
4110Sigor@sysoev.ru             break;
4120Sigor@sysoev.ru 
4130Sigor@sysoev.ru         case 'h':
4140Sigor@sysoev.ru             if (step >= st_hour) {
4150Sigor@sysoev.ru                 return -1;
4160Sigor@sysoev.ru             }
4170Sigor@sysoev.ru             step = st_hour;
4180Sigor@sysoev.ru             max = NXT_INT32_T_MAX / (60 * 60);
4190Sigor@sysoev.ru             scale = 60 * 60;
4200Sigor@sysoev.ru             break;
4210Sigor@sysoev.ru 
4220Sigor@sysoev.ru         case 'm':
4230Sigor@sysoev.ru             if (p < end && *p == 's') {
4240Sigor@sysoev.ru                 if (seconds || step >= st_msec) {
4250Sigor@sysoev.ru                     return -1;
4260Sigor@sysoev.ru                 }
4270Sigor@sysoev.ru                 p++;
4280Sigor@sysoev.ru                 step = st_msec;
4290Sigor@sysoev.ru                 max = NXT_INT32_T_MAX;
4300Sigor@sysoev.ru                 scale = 1;
4310Sigor@sysoev.ru                 break;
4320Sigor@sysoev.ru             }
4330Sigor@sysoev.ru 
4340Sigor@sysoev.ru             if (step >= st_min) {
4350Sigor@sysoev.ru                 return -1;
4360Sigor@sysoev.ru             }
4370Sigor@sysoev.ru             step = st_min;
4380Sigor@sysoev.ru             max = NXT_INT32_T_MAX / 60;
4390Sigor@sysoev.ru             scale = 60;
4400Sigor@sysoev.ru             break;
4410Sigor@sysoev.ru 
4420Sigor@sysoev.ru         case 's':
4430Sigor@sysoev.ru             if (step >= st_sec) {
4440Sigor@sysoev.ru                 return -1;
4450Sigor@sysoev.ru             }
4460Sigor@sysoev.ru             step = st_sec;
4470Sigor@sysoev.ru             max = NXT_INT32_T_MAX;
4480Sigor@sysoev.ru             scale = 1;
4490Sigor@sysoev.ru             break;
4500Sigor@sysoev.ru 
4510Sigor@sysoev.ru         case ' ':
4520Sigor@sysoev.ru             if (step >= st_sec) {
4530Sigor@sysoev.ru                 return -1;
4540Sigor@sysoev.ru             }
4550Sigor@sysoev.ru             step = st_last;
4560Sigor@sysoev.ru             max = NXT_INT32_T_MAX;
4570Sigor@sysoev.ru             scale = 1;
4580Sigor@sysoev.ru             break;
4590Sigor@sysoev.ru 
4600Sigor@sysoev.ru         default:
4610Sigor@sysoev.ru             return -1;
4620Sigor@sysoev.ru         }
4630Sigor@sysoev.ru 
4640Sigor@sysoev.ru         if (!seconds && step != st_msec) {
4650Sigor@sysoev.ru             scale *= 1000;
4660Sigor@sysoev.ru             max /= 1000;
4670Sigor@sysoev.ru         }
4680Sigor@sysoev.ru 
4690Sigor@sysoev.ru         if (val > max) {
4700Sigor@sysoev.ru             return -2;
4710Sigor@sysoev.ru         }
4720Sigor@sysoev.ru 
4730Sigor@sysoev.ru         term += val * scale;
4740Sigor@sysoev.ru 
4750Sigor@sysoev.ru         if (term > NXT_INT32_T_MAX) {
4760Sigor@sysoev.ru             return -2;
4770Sigor@sysoev.ru         }
4780Sigor@sysoev.ru 
4790Sigor@sysoev.ru         val = 0;
4800Sigor@sysoev.ru 
4810Sigor@sysoev.ru         state = st_space;
4820Sigor@sysoev.ru     }
4830Sigor@sysoev.ru 
4840Sigor@sysoev.ru     if (!seconds) {
4850Sigor@sysoev.ru         val *= 1000;
4860Sigor@sysoev.ru     }
4870Sigor@sysoev.ru 
4880Sigor@sysoev.ru     return term + val;
4890Sigor@sysoev.ru }
490