xref: /unit/src/nxt_time_parse.c (revision 0)
1*0Sigor@sysoev.ru 
2*0Sigor@sysoev.ru /*
3*0Sigor@sysoev.ru  * Copyright (C) Igor Sysoev
4*0Sigor@sysoev.ru  * Copyright (C) NGINX, Inc.
5*0Sigor@sysoev.ru  */
6*0Sigor@sysoev.ru 
7*0Sigor@sysoev.ru #include <nxt_main.h>
8*0Sigor@sysoev.ru 
9*0Sigor@sysoev.ru 
10*0Sigor@sysoev.ru /*
11*0Sigor@sysoev.ru  * nxt_time_parse() parses a time string given in RFC822, RFC850, or ISOC
12*0Sigor@sysoev.ru  * formats and returns nxt_time_t value >= 0 on success or -1 on failure.
13*0Sigor@sysoev.ru  */
14*0Sigor@sysoev.ru 
15*0Sigor@sysoev.ru nxt_time_t
16*0Sigor@sysoev.ru nxt_time_parse(const u_char *p, size_t len)
17*0Sigor@sysoev.ru {
18*0Sigor@sysoev.ru     size_t            n;
19*0Sigor@sysoev.ru     u_char            c;
20*0Sigor@sysoev.ru     uint64_t          s;
21*0Sigor@sysoev.ru     nxt_int_t         yr, month, day, hour, min, sec;
22*0Sigor@sysoev.ru     nxt_uint_t        year, days;
23*0Sigor@sysoev.ru     const u_char      *end;
24*0Sigor@sysoev.ru 
25*0Sigor@sysoev.ru     static nxt_int_t  mday[12] = {
26*0Sigor@sysoev.ru         31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
27*0Sigor@sysoev.ru     };
28*0Sigor@sysoev.ru 
29*0Sigor@sysoev.ru     enum {
30*0Sigor@sysoev.ru         RFC822 = 0,   /* "Mon, 28 Sep 1970 12:00:00"  */
31*0Sigor@sysoev.ru         RFC850,       /* "Monday, 28-Sep-70 12:00:00" */
32*0Sigor@sysoev.ru         ISOC,         /* "Mon Sep 28 12:00:00 1970"   */
33*0Sigor@sysoev.ru     } fmt;
34*0Sigor@sysoev.ru 
35*0Sigor@sysoev.ru     fmt = RFC822;
36*0Sigor@sysoev.ru     end = p + len;
37*0Sigor@sysoev.ru 
38*0Sigor@sysoev.ru     while (p < end) {
39*0Sigor@sysoev.ru         c = *p++;
40*0Sigor@sysoev.ru 
41*0Sigor@sysoev.ru         if (c == ',') {
42*0Sigor@sysoev.ru             break;
43*0Sigor@sysoev.ru         }
44*0Sigor@sysoev.ru 
45*0Sigor@sysoev.ru         if (c == ' ') {
46*0Sigor@sysoev.ru             fmt = ISOC;
47*0Sigor@sysoev.ru             break;
48*0Sigor@sysoev.ru         }
49*0Sigor@sysoev.ru     }
50*0Sigor@sysoev.ru 
51*0Sigor@sysoev.ru     while (p < end) {
52*0Sigor@sysoev.ru         if (*p != ' ') {
53*0Sigor@sysoev.ru             break;
54*0Sigor@sysoev.ru         }
55*0Sigor@sysoev.ru 
56*0Sigor@sysoev.ru         p++;
57*0Sigor@sysoev.ru     }
58*0Sigor@sysoev.ru 
59*0Sigor@sysoev.ru     if (nxt_slow_path(p + 18 > end)) {
60*0Sigor@sysoev.ru         /* Lesser than RFC850 "28-Sep-70 12:00:00" length. */
61*0Sigor@sysoev.ru         return -1;
62*0Sigor@sysoev.ru     }
63*0Sigor@sysoev.ru 
64*0Sigor@sysoev.ru     day = 0;
65*0Sigor@sysoev.ru 
66*0Sigor@sysoev.ru     if (fmt != ISOC) {
67*0Sigor@sysoev.ru         day = nxt_int_parse(p, 2);
68*0Sigor@sysoev.ru         if (nxt_slow_path(day <= 0)) {
69*0Sigor@sysoev.ru             return -1;
70*0Sigor@sysoev.ru         }
71*0Sigor@sysoev.ru         p += 2;
72*0Sigor@sysoev.ru 
73*0Sigor@sysoev.ru         if (*p == ' ') {
74*0Sigor@sysoev.ru             if (nxt_slow_path(p + 18 > end)) {
75*0Sigor@sysoev.ru                 /* Lesser than RFC822 " Sep 1970 12:00:00" length. */
76*0Sigor@sysoev.ru                 return -1;
77*0Sigor@sysoev.ru             }
78*0Sigor@sysoev.ru 
79*0Sigor@sysoev.ru             /* RFC822 */
80*0Sigor@sysoev.ru 
81*0Sigor@sysoev.ru         } else if (*p == '-') {
82*0Sigor@sysoev.ru             fmt = RFC850;
83*0Sigor@sysoev.ru 
84*0Sigor@sysoev.ru         } else {
85*0Sigor@sysoev.ru             return -1;
86*0Sigor@sysoev.ru         }
87*0Sigor@sysoev.ru 
88*0Sigor@sysoev.ru         p++;
89*0Sigor@sysoev.ru     }
90*0Sigor@sysoev.ru 
91*0Sigor@sysoev.ru     switch (*p) {
92*0Sigor@sysoev.ru 
93*0Sigor@sysoev.ru     case 'J':
94*0Sigor@sysoev.ru         month = p[1] == 'a' ? 0 : p[2] == 'n' ? 5 : 6;
95*0Sigor@sysoev.ru         break;
96*0Sigor@sysoev.ru 
97*0Sigor@sysoev.ru     case 'F':
98*0Sigor@sysoev.ru         month = 1;
99*0Sigor@sysoev.ru         break;
100*0Sigor@sysoev.ru 
101*0Sigor@sysoev.ru     case 'M':
102*0Sigor@sysoev.ru         month = p[2] == 'r' ? 2 : 4;
103*0Sigor@sysoev.ru         break;
104*0Sigor@sysoev.ru 
105*0Sigor@sysoev.ru     case 'A':
106*0Sigor@sysoev.ru         month = p[1] == 'p' ? 3 : 7;
107*0Sigor@sysoev.ru         break;
108*0Sigor@sysoev.ru 
109*0Sigor@sysoev.ru     case 'S':
110*0Sigor@sysoev.ru         month = 8;
111*0Sigor@sysoev.ru         break;
112*0Sigor@sysoev.ru 
113*0Sigor@sysoev.ru     case 'O':
114*0Sigor@sysoev.ru         month = 9;
115*0Sigor@sysoev.ru         break;
116*0Sigor@sysoev.ru 
117*0Sigor@sysoev.ru     case 'N':
118*0Sigor@sysoev.ru         month = 10;
119*0Sigor@sysoev.ru         break;
120*0Sigor@sysoev.ru 
121*0Sigor@sysoev.ru     case 'D':
122*0Sigor@sysoev.ru         month = 11;
123*0Sigor@sysoev.ru         break;
124*0Sigor@sysoev.ru 
125*0Sigor@sysoev.ru     default:
126*0Sigor@sysoev.ru         return -1;
127*0Sigor@sysoev.ru     }
128*0Sigor@sysoev.ru 
129*0Sigor@sysoev.ru     p += 3;
130*0Sigor@sysoev.ru     yr = 0;
131*0Sigor@sysoev.ru 
132*0Sigor@sysoev.ru     switch (fmt) {
133*0Sigor@sysoev.ru 
134*0Sigor@sysoev.ru     case RFC822:
135*0Sigor@sysoev.ru         if (nxt_slow_path(*p++ != ' ')) {
136*0Sigor@sysoev.ru             return -1;
137*0Sigor@sysoev.ru         }
138*0Sigor@sysoev.ru 
139*0Sigor@sysoev.ru         yr = nxt_int_parse(p, 4);
140*0Sigor@sysoev.ru         if (nxt_slow_path(yr <= 0)) {
141*0Sigor@sysoev.ru             return -1;
142*0Sigor@sysoev.ru         }
143*0Sigor@sysoev.ru         p += 4;
144*0Sigor@sysoev.ru 
145*0Sigor@sysoev.ru         break;
146*0Sigor@sysoev.ru 
147*0Sigor@sysoev.ru     case RFC850:
148*0Sigor@sysoev.ru         if (nxt_slow_path(*p++ != '-')) {
149*0Sigor@sysoev.ru             return -1;
150*0Sigor@sysoev.ru         }
151*0Sigor@sysoev.ru 
152*0Sigor@sysoev.ru         yr = nxt_int_parse(p, 2);
153*0Sigor@sysoev.ru         if (nxt_slow_path(yr <= 0)) {
154*0Sigor@sysoev.ru             return -1;
155*0Sigor@sysoev.ru         }
156*0Sigor@sysoev.ru         p += 2;
157*0Sigor@sysoev.ru 
158*0Sigor@sysoev.ru         yr += (yr < 70) ? 2000 : 1900;
159*0Sigor@sysoev.ru 
160*0Sigor@sysoev.ru         break;
161*0Sigor@sysoev.ru 
162*0Sigor@sysoev.ru     default: /* ISOC */
163*0Sigor@sysoev.ru         if (nxt_slow_path(*p++ != ' ')) {
164*0Sigor@sysoev.ru             return -1;
165*0Sigor@sysoev.ru         }
166*0Sigor@sysoev.ru 
167*0Sigor@sysoev.ru         if (p[0] != ' ') {
168*0Sigor@sysoev.ru             n = 2;
169*0Sigor@sysoev.ru 
170*0Sigor@sysoev.ru             if (p[1] == ' ') {
171*0Sigor@sysoev.ru                 n = 1;
172*0Sigor@sysoev.ru             }
173*0Sigor@sysoev.ru 
174*0Sigor@sysoev.ru         } else {
175*0Sigor@sysoev.ru             p++;
176*0Sigor@sysoev.ru             n = 1;
177*0Sigor@sysoev.ru         }
178*0Sigor@sysoev.ru 
179*0Sigor@sysoev.ru         day = nxt_int_parse(p, n);
180*0Sigor@sysoev.ru         if (nxt_slow_path(day <= 0)) {
181*0Sigor@sysoev.ru             return -1;
182*0Sigor@sysoev.ru         }
183*0Sigor@sysoev.ru         p += n;
184*0Sigor@sysoev.ru 
185*0Sigor@sysoev.ru         if (nxt_slow_path(p + 14 > end)) {
186*0Sigor@sysoev.ru             /* Lesser than ISOC " 12:00:00 1970" length. */
187*0Sigor@sysoev.ru             return -1;
188*0Sigor@sysoev.ru         }
189*0Sigor@sysoev.ru 
190*0Sigor@sysoev.ru         break;
191*0Sigor@sysoev.ru     }
192*0Sigor@sysoev.ru 
193*0Sigor@sysoev.ru     if (nxt_slow_path(*p++ != ' ')) {
194*0Sigor@sysoev.ru         return -1;
195*0Sigor@sysoev.ru     }
196*0Sigor@sysoev.ru 
197*0Sigor@sysoev.ru     hour = nxt_int_parse(p, 2);
198*0Sigor@sysoev.ru     if (nxt_slow_path(hour < 0)) {
199*0Sigor@sysoev.ru         return -1;
200*0Sigor@sysoev.ru     }
201*0Sigor@sysoev.ru     p += 2;
202*0Sigor@sysoev.ru 
203*0Sigor@sysoev.ru     if (nxt_slow_path(*p++ != ':')) {
204*0Sigor@sysoev.ru         return -1;
205*0Sigor@sysoev.ru     }
206*0Sigor@sysoev.ru 
207*0Sigor@sysoev.ru     min = nxt_int_parse(p, 2);
208*0Sigor@sysoev.ru     if (nxt_slow_path(min < 0)) {
209*0Sigor@sysoev.ru         return -1;
210*0Sigor@sysoev.ru     }
211*0Sigor@sysoev.ru     p += 2;
212*0Sigor@sysoev.ru 
213*0Sigor@sysoev.ru     if (nxt_slow_path(*p++ != ':')) {
214*0Sigor@sysoev.ru         return -1;
215*0Sigor@sysoev.ru     }
216*0Sigor@sysoev.ru 
217*0Sigor@sysoev.ru     sec = nxt_int_parse(p, 2);
218*0Sigor@sysoev.ru     if (nxt_slow_path(sec < 0)) {
219*0Sigor@sysoev.ru         return -1;
220*0Sigor@sysoev.ru     }
221*0Sigor@sysoev.ru 
222*0Sigor@sysoev.ru     if (fmt == ISOC) {
223*0Sigor@sysoev.ru         p += 2;
224*0Sigor@sysoev.ru 
225*0Sigor@sysoev.ru         if (nxt_slow_path(*p++ != ' ')) {
226*0Sigor@sysoev.ru             return -1;
227*0Sigor@sysoev.ru         }
228*0Sigor@sysoev.ru 
229*0Sigor@sysoev.ru         yr = nxt_int_parse(p, 4);
230*0Sigor@sysoev.ru         if (nxt_slow_path(yr < 0)) {
231*0Sigor@sysoev.ru             return -1;
232*0Sigor@sysoev.ru         }
233*0Sigor@sysoev.ru     }
234*0Sigor@sysoev.ru 
235*0Sigor@sysoev.ru     if (nxt_slow_path(hour > 23 || min > 59 || sec > 59)) {
236*0Sigor@sysoev.ru         return -1;
237*0Sigor@sysoev.ru     }
238*0Sigor@sysoev.ru 
239*0Sigor@sysoev.ru     year = yr;
240*0Sigor@sysoev.ru 
241*0Sigor@sysoev.ru     if (day == 29 && month == 1) {
242*0Sigor@sysoev.ru 
243*0Sigor@sysoev.ru         if (nxt_slow_path((year & 3) != 0)) {
244*0Sigor@sysoev.ru             /* Not a leap year. */
245*0Sigor@sysoev.ru             return -1;
246*0Sigor@sysoev.ru         }
247*0Sigor@sysoev.ru 
248*0Sigor@sysoev.ru         if (nxt_slow_path((year % 100 == 0) && (year % 400) != 0)) {
249*0Sigor@sysoev.ru             /* Not a leap year. */
250*0Sigor@sysoev.ru             return -1;
251*0Sigor@sysoev.ru         }
252*0Sigor@sysoev.ru 
253*0Sigor@sysoev.ru     } else if (nxt_slow_path(day > mday[(nxt_uint_t) month])) {
254*0Sigor@sysoev.ru         return -1;
255*0Sigor@sysoev.ru     }
256*0Sigor@sysoev.ru 
257*0Sigor@sysoev.ru     /*
258*0Sigor@sysoev.ru      * Shift new year to March 1 and start months
259*0Sigor@sysoev.ru      * from 1 (not 0), as required for Gauss' formula.
260*0Sigor@sysoev.ru      */
261*0Sigor@sysoev.ru 
262*0Sigor@sysoev.ru     if (--month <= 0) {
263*0Sigor@sysoev.ru         month += 12;
264*0Sigor@sysoev.ru         year -= 1;
265*0Sigor@sysoev.ru     }
266*0Sigor@sysoev.ru 
267*0Sigor@sysoev.ru     /* Gauss' formula for Gregorian days since March 1, 1 BCE. */
268*0Sigor@sysoev.ru 
269*0Sigor@sysoev.ru            /* Days in years including leap years since March 1, 1 BCE. */
270*0Sigor@sysoev.ru     days = 365 * year + year / 4 - year / 100 + year / 400
271*0Sigor@sysoev.ru 
272*0Sigor@sysoev.ru            /* Days before the month. */
273*0Sigor@sysoev.ru            + 367 * (nxt_uint_t) month / 12 - 30
274*0Sigor@sysoev.ru 
275*0Sigor@sysoev.ru            /* Days before the day. */
276*0Sigor@sysoev.ru            + (nxt_uint_t) day - 1;
277*0Sigor@sysoev.ru 
278*0Sigor@sysoev.ru     /*
279*0Sigor@sysoev.ru      * 719527 days were between March 1, 1 BCE and March 1, 1970,
280*0Sigor@sysoev.ru      * 31 and 28 days were in January and February 1970.
281*0Sigor@sysoev.ru      */
282*0Sigor@sysoev.ru     days = days - 719527 + 31 + 28;
283*0Sigor@sysoev.ru 
284*0Sigor@sysoev.ru     s = (uint64_t) days * 86400
285*0Sigor@sysoev.ru          + (nxt_uint_t) hour * 3600
286*0Sigor@sysoev.ru          + (nxt_uint_t) min * 60
287*0Sigor@sysoev.ru          + (nxt_uint_t) sec;
288*0Sigor@sysoev.ru 
289*0Sigor@sysoev.ru #if (NXT_TIME_T_SIZE <= 4)
290*0Sigor@sysoev.ru 
291*0Sigor@sysoev.ru     /* Y2038 */
292*0Sigor@sysoev.ru 
293*0Sigor@sysoev.ru     if (nxt_slow_path(s > 0x7fffffff)) {
294*0Sigor@sysoev.ru         return -1;
295*0Sigor@sysoev.ru     }
296*0Sigor@sysoev.ru 
297*0Sigor@sysoev.ru #endif
298*0Sigor@sysoev.ru 
299*0Sigor@sysoev.ru     return (nxt_time_t) s;
300*0Sigor@sysoev.ru }
301*0Sigor@sysoev.ru 
302*0Sigor@sysoev.ru 
303*0Sigor@sysoev.ru /*
304*0Sigor@sysoev.ru  * nxt_term_parse() parses term string given in format "200", "10m",
305*0Sigor@sysoev.ru  * or "1d 1h" and returns nxt_int_t value >= 0 on success, -1 on failure,
306*0Sigor@sysoev.ru  * and -2 on overflow.  The maximum valid value is 2^31 - 1 or about
307*0Sigor@sysoev.ru  * 68 years in seconds or about 24 days in milliseconds.
308*0Sigor@sysoev.ru  */
309*0Sigor@sysoev.ru 
310*0Sigor@sysoev.ru nxt_int_t
311*0Sigor@sysoev.ru nxt_term_parse(const u_char *p, size_t len, nxt_bool_t seconds)
312*0Sigor@sysoev.ru {
313*0Sigor@sysoev.ru     u_char        c, ch;
314*0Sigor@sysoev.ru     nxt_uint_t    val, term, scale, max;
315*0Sigor@sysoev.ru     const u_char  *end;
316*0Sigor@sysoev.ru 
317*0Sigor@sysoev.ru     enum {
318*0Sigor@sysoev.ru         st_first_digit = 0,
319*0Sigor@sysoev.ru         st_digit,
320*0Sigor@sysoev.ru         st_letter,
321*0Sigor@sysoev.ru         st_space,
322*0Sigor@sysoev.ru     } state;
323*0Sigor@sysoev.ru 
324*0Sigor@sysoev.ru     enum {
325*0Sigor@sysoev.ru         st_start = 0,
326*0Sigor@sysoev.ru         st_year,
327*0Sigor@sysoev.ru         st_month,
328*0Sigor@sysoev.ru         st_week,
329*0Sigor@sysoev.ru         st_day,
330*0Sigor@sysoev.ru         st_hour,
331*0Sigor@sysoev.ru         st_min,
332*0Sigor@sysoev.ru         st_sec,
333*0Sigor@sysoev.ru         st_msec,
334*0Sigor@sysoev.ru         st_last,
335*0Sigor@sysoev.ru     } step;
336*0Sigor@sysoev.ru 
337*0Sigor@sysoev.ru     val = 0;
338*0Sigor@sysoev.ru     term = 0;
339*0Sigor@sysoev.ru     state = st_first_digit;
340*0Sigor@sysoev.ru     step = seconds ? st_start : st_month;
341*0Sigor@sysoev.ru 
342*0Sigor@sysoev.ru     end = p + len;
343*0Sigor@sysoev.ru 
344*0Sigor@sysoev.ru     while (p < end) {
345*0Sigor@sysoev.ru 
346*0Sigor@sysoev.ru         ch = *p++;
347*0Sigor@sysoev.ru 
348*0Sigor@sysoev.ru         if (state == st_space) {
349*0Sigor@sysoev.ru 
350*0Sigor@sysoev.ru             if (ch == ' ') {
351*0Sigor@sysoev.ru                 continue;
352*0Sigor@sysoev.ru             }
353*0Sigor@sysoev.ru 
354*0Sigor@sysoev.ru             state = st_first_digit;
355*0Sigor@sysoev.ru         }
356*0Sigor@sysoev.ru 
357*0Sigor@sysoev.ru         if (state != st_letter) {
358*0Sigor@sysoev.ru 
359*0Sigor@sysoev.ru             /* Values below '0' become >= 208. */
360*0Sigor@sysoev.ru             c = ch - '0';
361*0Sigor@sysoev.ru 
362*0Sigor@sysoev.ru             if (c <= 9) {
363*0Sigor@sysoev.ru                 val = val * 10 + c;
364*0Sigor@sysoev.ru                 state = st_digit;
365*0Sigor@sysoev.ru                 continue;
366*0Sigor@sysoev.ru             }
367*0Sigor@sysoev.ru 
368*0Sigor@sysoev.ru             if (state == st_first_digit) {
369*0Sigor@sysoev.ru                 return -1;
370*0Sigor@sysoev.ru             }
371*0Sigor@sysoev.ru 
372*0Sigor@sysoev.ru             state = st_letter;
373*0Sigor@sysoev.ru         }
374*0Sigor@sysoev.ru 
375*0Sigor@sysoev.ru         switch (ch) {
376*0Sigor@sysoev.ru 
377*0Sigor@sysoev.ru         case 'y':
378*0Sigor@sysoev.ru             if (step > st_start) {
379*0Sigor@sysoev.ru                 return -1;
380*0Sigor@sysoev.ru             }
381*0Sigor@sysoev.ru             step = st_year;
382*0Sigor@sysoev.ru             max = NXT_INT32_T_MAX / (365 * 24 * 60 * 60);
383*0Sigor@sysoev.ru             scale = 365 * 24 * 60 * 60;
384*0Sigor@sysoev.ru             break;
385*0Sigor@sysoev.ru 
386*0Sigor@sysoev.ru         case 'M':
387*0Sigor@sysoev.ru             if (step >= st_month) {
388*0Sigor@sysoev.ru                 return -1;
389*0Sigor@sysoev.ru             }
390*0Sigor@sysoev.ru             step = st_month;
391*0Sigor@sysoev.ru             max = NXT_INT32_T_MAX / (30 * 24 * 60 * 60);
392*0Sigor@sysoev.ru             scale = 30 * 24 * 60 * 60;
393*0Sigor@sysoev.ru             break;
394*0Sigor@sysoev.ru 
395*0Sigor@sysoev.ru         case 'w':
396*0Sigor@sysoev.ru             if (step >= st_week) {
397*0Sigor@sysoev.ru                 return -1;
398*0Sigor@sysoev.ru             }
399*0Sigor@sysoev.ru             step = st_week;
400*0Sigor@sysoev.ru             max = NXT_INT32_T_MAX / (7 * 24 * 60 * 60);
401*0Sigor@sysoev.ru             scale = 7 * 24 * 60 * 60;
402*0Sigor@sysoev.ru             break;
403*0Sigor@sysoev.ru 
404*0Sigor@sysoev.ru         case 'd':
405*0Sigor@sysoev.ru             if (step >= st_day) {
406*0Sigor@sysoev.ru                 return -1;
407*0Sigor@sysoev.ru             }
408*0Sigor@sysoev.ru             step = st_day;
409*0Sigor@sysoev.ru             max = NXT_INT32_T_MAX / (24 * 60 * 60);
410*0Sigor@sysoev.ru             scale = 24 * 60 * 60;
411*0Sigor@sysoev.ru             break;
412*0Sigor@sysoev.ru 
413*0Sigor@sysoev.ru         case 'h':
414*0Sigor@sysoev.ru             if (step >= st_hour) {
415*0Sigor@sysoev.ru                 return -1;
416*0Sigor@sysoev.ru             }
417*0Sigor@sysoev.ru             step = st_hour;
418*0Sigor@sysoev.ru             max = NXT_INT32_T_MAX / (60 * 60);
419*0Sigor@sysoev.ru             scale = 60 * 60;
420*0Sigor@sysoev.ru             break;
421*0Sigor@sysoev.ru 
422*0Sigor@sysoev.ru         case 'm':
423*0Sigor@sysoev.ru             if (p < end && *p == 's') {
424*0Sigor@sysoev.ru                 if (seconds || step >= st_msec) {
425*0Sigor@sysoev.ru                     return -1;
426*0Sigor@sysoev.ru                 }
427*0Sigor@sysoev.ru                 p++;
428*0Sigor@sysoev.ru                 step = st_msec;
429*0Sigor@sysoev.ru                 max = NXT_INT32_T_MAX;
430*0Sigor@sysoev.ru                 scale = 1;
431*0Sigor@sysoev.ru                 break;
432*0Sigor@sysoev.ru             }
433*0Sigor@sysoev.ru 
434*0Sigor@sysoev.ru             if (step >= st_min) {
435*0Sigor@sysoev.ru                 return -1;
436*0Sigor@sysoev.ru             }
437*0Sigor@sysoev.ru             step = st_min;
438*0Sigor@sysoev.ru             max = NXT_INT32_T_MAX / 60;
439*0Sigor@sysoev.ru             scale = 60;
440*0Sigor@sysoev.ru             break;
441*0Sigor@sysoev.ru 
442*0Sigor@sysoev.ru         case 's':
443*0Sigor@sysoev.ru             if (step >= st_sec) {
444*0Sigor@sysoev.ru                 return -1;
445*0Sigor@sysoev.ru             }
446*0Sigor@sysoev.ru             step = st_sec;
447*0Sigor@sysoev.ru             max = NXT_INT32_T_MAX;
448*0Sigor@sysoev.ru             scale = 1;
449*0Sigor@sysoev.ru             break;
450*0Sigor@sysoev.ru 
451*0Sigor@sysoev.ru         case ' ':
452*0Sigor@sysoev.ru             if (step >= st_sec) {
453*0Sigor@sysoev.ru                 return -1;
454*0Sigor@sysoev.ru             }
455*0Sigor@sysoev.ru             step = st_last;
456*0Sigor@sysoev.ru             max = NXT_INT32_T_MAX;
457*0Sigor@sysoev.ru             scale = 1;
458*0Sigor@sysoev.ru             break;
459*0Sigor@sysoev.ru 
460*0Sigor@sysoev.ru         default:
461*0Sigor@sysoev.ru             return -1;
462*0Sigor@sysoev.ru         }
463*0Sigor@sysoev.ru 
464*0Sigor@sysoev.ru         if (!seconds && step != st_msec) {
465*0Sigor@sysoev.ru             scale *= 1000;
466*0Sigor@sysoev.ru             max /= 1000;
467*0Sigor@sysoev.ru         }
468*0Sigor@sysoev.ru 
469*0Sigor@sysoev.ru         if (val > max) {
470*0Sigor@sysoev.ru             return -2;
471*0Sigor@sysoev.ru         }
472*0Sigor@sysoev.ru 
473*0Sigor@sysoev.ru         term += val * scale;
474*0Sigor@sysoev.ru 
475*0Sigor@sysoev.ru         if (term > NXT_INT32_T_MAX) {
476*0Sigor@sysoev.ru             return -2;
477*0Sigor@sysoev.ru         }
478*0Sigor@sysoev.ru 
479*0Sigor@sysoev.ru         val = 0;
480*0Sigor@sysoev.ru 
481*0Sigor@sysoev.ru         state = st_space;
482*0Sigor@sysoev.ru     }
483*0Sigor@sysoev.ru 
484*0Sigor@sysoev.ru     if (!seconds) {
485*0Sigor@sysoev.ru         val *= 1000;
486*0Sigor@sysoev.ru     }
487*0Sigor@sysoev.ru 
488*0Sigor@sysoev.ru     return term + val;
489*0Sigor@sysoev.ru }
490