|  |  | 
|  | /* | 
|  | * Copyright (C) Igor Sysoev | 
|  | */ | 
|  |  | 
|  |  | 
|  | #include <ngx_config.h> | 
|  | #include <ngx_core.h> | 
|  |  | 
|  |  | 
|  | ssize_t | 
|  | ngx_parse_size(ngx_str_t *line) | 
|  | { | 
|  | u_char     last; | 
|  | size_t     len; | 
|  | ssize_t    size; | 
|  | ngx_int_t  scale; | 
|  |  | 
|  | len = line->len; | 
|  | last = line->data[len - 1]; | 
|  |  | 
|  | switch (last) { | 
|  | case 'K': | 
|  | case 'k': | 
|  | len--; | 
|  | scale = 1024; | 
|  | break; | 
|  |  | 
|  | case 'M': | 
|  | case 'm': | 
|  | len--; | 
|  | scale = 1024 * 1024; | 
|  | break; | 
|  |  | 
|  | default: | 
|  | scale = 1; | 
|  | } | 
|  |  | 
|  | size = ngx_atosz(line->data, len); | 
|  | if (size == NGX_ERROR) { | 
|  | return NGX_ERROR; | 
|  | } | 
|  |  | 
|  | size *= scale; | 
|  |  | 
|  | return size; | 
|  | } | 
|  |  | 
|  |  | 
|  | off_t | 
|  | ngx_parse_offset(ngx_str_t *line) | 
|  | { | 
|  | u_char     last; | 
|  | off_t      offset; | 
|  | size_t     len; | 
|  | ngx_int_t  scale; | 
|  |  | 
|  | len = line->len; | 
|  | last = line->data[len - 1]; | 
|  |  | 
|  | switch (last) { | 
|  | case 'K': | 
|  | case 'k': | 
|  | len--; | 
|  | scale = 1024; | 
|  | break; | 
|  |  | 
|  | case 'M': | 
|  | case 'm': | 
|  | len--; | 
|  | scale = 1024 * 1024; | 
|  | break; | 
|  |  | 
|  | case 'G': | 
|  | case 'g': | 
|  | len--; | 
|  | scale = 1024 * 1024 * 1024; | 
|  | break; | 
|  |  | 
|  | default: | 
|  | scale = 1; | 
|  | } | 
|  |  | 
|  | offset = ngx_atoof(line->data, len); | 
|  | if (offset == NGX_ERROR) { | 
|  | return NGX_ERROR; | 
|  | } | 
|  |  | 
|  | offset *= scale; | 
|  |  | 
|  | return offset; | 
|  | } | 
|  |  | 
|  |  | 
|  | ngx_int_t | 
|  | ngx_parse_time(ngx_str_t *line, ngx_int_t sec) | 
|  | { | 
|  | size_t       len; | 
|  | u_char      *start, last; | 
|  | ngx_int_t    value, total, scale; | 
|  | ngx_uint_t   max, i; | 
|  | enum { | 
|  | st_start = 0, | 
|  | st_year, | 
|  | st_month, | 
|  | st_week, | 
|  | st_day, | 
|  | st_hour, | 
|  | st_min, | 
|  | st_sec, | 
|  | st_msec, | 
|  | st_last | 
|  | } step; | 
|  |  | 
|  |  | 
|  | start = line->data; | 
|  | len = 0; | 
|  | total = 0; | 
|  | step = sec ? st_start : st_month; | 
|  |  | 
|  | for (i = 0; /* void */ ; i++) { | 
|  |  | 
|  | if (i < line->len) { | 
|  | if (line->data[i] != ' ') { | 
|  | len++; | 
|  | continue; | 
|  | } | 
|  |  | 
|  | if (line->data[i] == ' ' && len == 0) { | 
|  | start = &line->data[i + 1]; | 
|  | continue; | 
|  | } | 
|  | } | 
|  |  | 
|  | if (len == 0) { | 
|  | break; | 
|  | } | 
|  |  | 
|  | last = line->data[i - 1]; | 
|  |  | 
|  | switch (last) { | 
|  | case 'y': | 
|  | if (step > st_start) { | 
|  | return NGX_ERROR; | 
|  | } | 
|  | step = st_year; | 
|  | len--; | 
|  | max = 68; | 
|  | scale = 60 * 60 * 24 * 365; | 
|  | break; | 
|  |  | 
|  | case 'M': | 
|  | if (step > st_year) { | 
|  | return NGX_ERROR; | 
|  | } | 
|  | step = st_month; | 
|  | len--; | 
|  | max = 828; | 
|  | scale = 60 * 60 * 24 * 30; | 
|  | break; | 
|  |  | 
|  | case 'w': | 
|  | if (step > st_month) { | 
|  | return NGX_ERROR; | 
|  | } | 
|  | step = st_week; | 
|  | len--; | 
|  | max = 3550; | 
|  | scale = 60 * 60 * 24 * 7; | 
|  | break; | 
|  |  | 
|  | case 'd': | 
|  | if (step > st_week) { | 
|  | return NGX_ERROR; | 
|  | } | 
|  | step = st_day; | 
|  | len--; | 
|  | max = 24855; | 
|  | scale = 60 * 60 * 24; | 
|  | break; | 
|  |  | 
|  | case 'h': | 
|  | if (step > st_day) { | 
|  | return NGX_ERROR; | 
|  | } | 
|  | step = st_hour; | 
|  | len--; | 
|  | max = 596523; | 
|  | scale = 60 * 60; | 
|  | break; | 
|  |  | 
|  | case 'm': | 
|  | if (step > st_hour) { | 
|  | return NGX_ERROR; | 
|  | } | 
|  | step = st_min; | 
|  | len--; | 
|  | max = 35791394; | 
|  | scale = 60; | 
|  | break; | 
|  |  | 
|  | case 's': | 
|  | len--; | 
|  |  | 
|  | if (line->data[i - 2] == 'm') { | 
|  | if (sec || step > st_sec) { | 
|  | return NGX_ERROR; | 
|  | } | 
|  | step = st_msec; | 
|  | len--; | 
|  | max = 2147483647; | 
|  | scale = 1; | 
|  | break; | 
|  | } | 
|  |  | 
|  | if (step > st_min) { | 
|  | return NGX_ERROR; | 
|  | } | 
|  |  | 
|  | step = st_sec; | 
|  | max = 2147483647; | 
|  | scale = 1; | 
|  | break; | 
|  |  | 
|  | default: | 
|  | step = st_last; | 
|  | max = 2147483647; | 
|  | scale = 1; | 
|  | } | 
|  |  | 
|  | value = ngx_atoi(start, len); | 
|  | if (value == NGX_ERROR) { | 
|  | return NGX_ERROR; | 
|  | } | 
|  |  | 
|  | if (step != st_msec && !sec) { | 
|  | scale *= 1000; | 
|  | max /= 1000; | 
|  | } | 
|  |  | 
|  | if ((u_int) value > max) { | 
|  | return NGX_PARSE_LARGE_TIME; | 
|  | } | 
|  |  | 
|  | total += value * scale; | 
|  |  | 
|  | if ((u_int) total > 2147483647) { | 
|  | return NGX_PARSE_LARGE_TIME; | 
|  | } | 
|  |  | 
|  | if (i >= line->len) { | 
|  | break; | 
|  | } | 
|  |  | 
|  | len = 0; | 
|  | start = &line->data[i + 1]; | 
|  | } | 
|  |  | 
|  | return total; | 
|  | } |