PHP  
 PHP: Test and Code Coverage Analysis
downloads | QA | documentation | faq | getting help | mailing lists | reporting bugs | php.net sites | links | my php.net 
 

LCOV - code coverage report
Current view: top level - lcov_data/ext/date/lib - parse_iso_intervals.re (source / functions) Hit Total Coverage
Test: PHP Code Coverage Lines: 159 246 64.6 %
Date: 2014-07-29 Functions: 6 11 54.5 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :    +----------------------------------------------------------------------+
       3             :    | PHP Version 5                                                        |
       4             :    +----------------------------------------------------------------------+
       5             :    | Copyright (c) 1997-2013 The PHP Group                                |
       6             :    +----------------------------------------------------------------------+
       7             :    | This source file is subject to version 3.01 of the PHP license,      |
       8             :    | that is bundled with this package in the file LICENSE, and is        |
       9             :    | available through the world-wide-web at the following url:           |
      10             :    | http://www.php.net/license/3_01.txt                                  |
      11             :    | If you did not receive a copy of the PHP license and are unable to   |
      12             :    | obtain it through the world-wide-web, please send a note to          |
      13             :    | license@php.net so we can mail you a copy immediately.               |
      14             :    +----------------------------------------------------------------------+
      15             :    | Authors: Derick Rethans <derick@derickrethans.nl>                    |
      16             :    +----------------------------------------------------------------------+
      17             :  */
      18             : 
      19             : /* $Id$ */
      20             : 
      21             : #include "timelib.h"
      22             : 
      23             : #include <stdio.h>
      24             : #include <ctype.h>
      25             : 
      26             : #ifdef HAVE_STDLIB_H
      27             : #include <stdlib.h>
      28             : #endif
      29             : #ifdef HAVE_STRING_H
      30             : #include <string.h>
      31             : #else
      32             : #include <strings.h>
      33             : #endif
      34             : 
      35             : #if defined(_MSC_VER)
      36             : # define strtoll(s, f, b) _atoi64(s)
      37             : #elif !defined(HAVE_STRTOLL)
      38             : # if defined(HAVE_ATOLL)
      39             : #  define strtoll(s, f, b) atoll(s)
      40             : # else
      41             : #  define strtoll(s, f, b) strtol(s, f, b)
      42             : # endif
      43             : #endif
      44             : 
      45             : #define TIMELIB_UNSET   -99999
      46             : 
      47             : #define TIMELIB_SECOND  1
      48             : #define TIMELIB_MINUTE  2
      49             : #define TIMELIB_HOUR    3
      50             : #define TIMELIB_DAY     4
      51             : #define TIMELIB_MONTH   5
      52             : #define TIMELIB_YEAR    6
      53             : 
      54             : #define EOI      257
      55             : 
      56             : #define TIMELIB_PERIOD  260
      57             : #define TIMELIB_ISO_DATE 261
      58             : #define TIMELIB_ERROR   999
      59             : 
      60             : typedef unsigned char uchar;
      61             : 
      62             : #define   BSIZE    8192
      63             : 
      64             : #define   YYCTYPE      uchar
      65             : #define   YYCURSOR     cursor
      66             : #define   YYLIMIT      s->lim
      67             : #define   YYMARKER     s->ptr
      68             : #define   YYFILL(n)    return EOI;
      69             : 
      70             : #define   RET(i)       {s->cur = cursor; return i;}
      71             : 
      72             : #define timelib_string_free free
      73             : 
      74             : #define TIMELIB_INIT  s->cur = cursor; str = timelib_string(s); ptr = str
      75             : #define TIMELIB_DEINIT timelib_string_free(str)
      76             : 
      77             : #ifdef DEBUG_PARSER
      78             : #define DEBUG_OUTPUT(s) printf("%s\n", s);
      79             : #define YYDEBUG(s,c) { if (s != -1) { printf("state: %d ", s); printf("[%c]\n", c); } }
      80             : #else
      81             : #define DEBUG_OUTPUT(s)
      82             : #define YYDEBUG(s,c)
      83             : #endif
      84             : 
      85             : #include "timelib_structs.h"
      86             : 
      87             : typedef struct Scanner {
      88             :         int           fd;
      89             :         uchar        *lim, *str, *ptr, *cur, *tok, *pos;
      90             :         unsigned int  line, len;
      91             :         struct timelib_error_container *errors;
      92             : 
      93             :         struct timelib_time     *begin;
      94             :         struct timelib_time     *end;
      95             :         struct timelib_rel_time *period;
      96             :         int                      recurrences;
      97             : 
      98             :         int have_period;
      99             :         int have_recurrences;
     100             :         int have_date;
     101             :         int have_begin_date;
     102             :         int have_end_date;
     103             : } Scanner;
     104             : 
     105             : #define HOUR(a) (int)(a * 60)
     106             : 
     107           0 : static void add_warning(Scanner *s, char *error)
     108             : {
     109           0 :         s->errors->warning_count++;
     110           0 :         s->errors->warning_messages = realloc(s->errors->warning_messages, s->errors->warning_count * sizeof(timelib_error_message));
     111           0 :         s->errors->warning_messages[s->errors->warning_count - 1].position = s->tok ? s->tok - s->str : 0;
     112           0 :         s->errors->warning_messages[s->errors->warning_count - 1].character = s->tok ? *s->tok : 0;
     113           0 :         s->errors->warning_messages[s->errors->warning_count - 1].message = strdup(error);
     114           0 : }
     115             : 
     116          11 : static void add_error(Scanner *s, char *error)
     117             : {
     118          11 :         s->errors->error_count++;
     119          11 :         s->errors->error_messages = realloc(s->errors->error_messages, s->errors->error_count * sizeof(timelib_error_message));
     120          11 :         s->errors->error_messages[s->errors->error_count - 1].position = s->tok ? s->tok - s->str : 0;
     121          11 :         s->errors->error_messages[s->errors->error_count - 1].character = s->tok ? *s->tok : 0;
     122          11 :         s->errors->error_messages[s->errors->error_count - 1].message = strdup(error);
     123          11 : }
     124             : 
     125      175602 : static char *timelib_string(Scanner *s)
     126             : {
     127      175602 :         char *tmp = calloc(1, s->cur - s->tok + 1);
     128      175602 :         memcpy(tmp, s->tok, s->cur - s->tok);
     129             : 
     130      175602 :         return tmp;
     131             : }
     132             : 
     133      527434 : static timelib_sll timelib_get_nr(char **ptr, int max_length)
     134             : {
     135             :         char *begin, *end, *str;
     136      527434 :         timelib_sll tmp_nr = TIMELIB_UNSET;
     137      527434 :         int len = 0;
     138             : 
     139     1054918 :         while ((**ptr < '0') || (**ptr > '9')) {
     140          50 :                 if (**ptr == '\0') {
     141           0 :                         return TIMELIB_UNSET;
     142             :                 }
     143          50 :                 ++*ptr;
     144             :         }
     145      527434 :         begin = *ptr;
     146     1725275 :         while ((**ptr >= '0') && (**ptr <= '9') && len < max_length) {
     147      670407 :                 ++*ptr;
     148      670407 :                 ++len;
     149             :         }
     150      527434 :         end = *ptr;
     151      527434 :         str = calloc(1, end - begin + 1);
     152      527434 :         memcpy(str, begin, end - begin);
     153      527434 :         tmp_nr = strtoll(str, NULL, 10);
     154      527434 :         free(str);
     155      527434 :         return tmp_nr;
     156             : }
     157             : 
     158      527374 : static timelib_ull timelib_get_unsigned_nr(char **ptr, int max_length)
     159             : {
     160      527374 :         timelib_ull dir = 1;
     161             : 
     162     1054748 :         while (((**ptr < '0') || (**ptr > '9')) && (**ptr != '+') && (**ptr != '-')) {
     163           0 :                 if (**ptr == '\0') {
     164           0 :                         return TIMELIB_UNSET;
     165             :                 }
     166           0 :                 ++*ptr;
     167             :         }
     168             : 
     169     1054748 :         while (**ptr == '+' || **ptr == '-')
     170             :         {
     171           0 :                 if (**ptr == '-') {
     172           0 :                         dir *= -1;
     173             :                 }
     174           0 :                 ++*ptr;
     175             :         }
     176      527374 :         return dir * timelib_get_nr(ptr, max_length);
     177             : }
     178             : 
     179           0 : static long timelib_parse_tz_cor(char **ptr)
     180             : {
     181           0 :         char *begin = *ptr, *end;
     182             :         long  tmp;
     183             : 
     184           0 :         while (isdigit(**ptr) || **ptr == ':') {
     185           0 :                 ++*ptr;
     186             :         }
     187           0 :         end = *ptr;
     188           0 :         switch (end - begin) {
     189             :                 case 1:
     190             :                 case 2:
     191           0 :                         return HOUR(strtol(begin, NULL, 10));
     192             :                         break;
     193             :                 case 3:
     194             :                 case 4:
     195           0 :                         if (begin[1] == ':') {
     196           0 :                                 tmp = HOUR(strtol(begin, NULL, 10)) + strtol(begin + 2, NULL, 10);
     197           0 :                                 return tmp;
     198           0 :                         } else if (begin[2] == ':') {
     199           0 :                                 tmp = HOUR(strtol(begin, NULL, 10)) + strtol(begin + 3, NULL, 10);
     200           0 :                                 return tmp;
     201             :                         } else {
     202           0 :                                 tmp = strtol(begin, NULL, 10);
     203           0 :                                 return HOUR(tmp / 100) + tmp % 100;
     204             :                         }
     205             :                 case 5:
     206           0 :                         tmp = HOUR(strtol(begin, NULL, 10)) + strtol(begin + 3, NULL, 10);
     207           0 :                         return tmp;
     208             :         }
     209           0 :         return 0;
     210             : }
     211             : 
     212           0 : static void timelib_eat_spaces(char **ptr)
     213             : {
     214           0 :         while (**ptr == ' ' || **ptr == '\t') {
     215           0 :                 ++*ptr;
     216             :         }
     217           0 : }
     218             : 
     219           0 : static void timelib_eat_until_separator(char **ptr)
     220             : {
     221           0 :         while (strchr(" \t.,:;/-0123456789", **ptr) == NULL) {
     222           0 :                 ++*ptr;
     223             :         }
     224           0 : }
     225             : 
     226           0 : static long timelib_get_zone(char **ptr, int *dst, timelib_time *t, int *tz_not_found, const timelib_tzdb *tzdb)
     227             : {
     228           0 :         long retval = 0;
     229             : 
     230           0 :         *tz_not_found = 0;
     231             : 
     232           0 :         while (**ptr == ' ' || **ptr == '\t' || **ptr == '(') {
     233           0 :                 ++*ptr;
     234             :         }
     235           0 :         if ((*ptr)[0] == 'G' && (*ptr)[1] == 'M' && (*ptr)[2] == 'T' && ((*ptr)[3] == '+' || (*ptr)[3] == '-')) {
     236           0 :                 *ptr += 3;
     237             :         }
     238           0 :         if (**ptr == '+') {
     239           0 :                 ++*ptr;
     240           0 :                 t->is_localtime = 1;
     241           0 :                 t->zone_type = TIMELIB_ZONETYPE_OFFSET;
     242           0 :                 *tz_not_found = 0;
     243           0 :                 t->dst = 0;
     244             : 
     245           0 :                 retval = -1 * timelib_parse_tz_cor(ptr);
     246           0 :         } else if (**ptr == '-') {
     247           0 :                 ++*ptr;
     248           0 :                 t->is_localtime = 1;
     249           0 :                 t->zone_type = TIMELIB_ZONETYPE_OFFSET;
     250           0 :                 *tz_not_found = 0;
     251           0 :                 t->dst = 0;
     252             : 
     253           0 :                 retval = timelib_parse_tz_cor(ptr);
     254             :         }
     255           0 :         while (**ptr == ')') {
     256           0 :                 ++*ptr;
     257             :         }
     258           0 :         return retval;
     259             : }
     260             : 
     261             : #define timelib_split_free(arg) {       \
     262             :         int i;                         \
     263             :         for (i = 0; i < arg.c; i++) {  \
     264             :                 free(arg.v[i]);            \
     265             :         }                              \
     266             :         if (arg.v) {                   \
     267             :                 free(arg.v);               \
     268             :         }                              \
     269             : }
     270             : 
     271             : /* date parser's scan function too large for VC6 - VC7.x
     272             :    drop the optimization solves the problem */
     273             : #ifdef PHP_WIN32
     274             : #pragma optimize( "", off )
     275             : #endif
     276      351201 : static int scan(Scanner *s)
     277             : {
     278      351201 :         uchar *cursor = s->cur;
     279      351201 :         char *str, *ptr = NULL;
     280             :                 
     281             : std:
     282      526817 :         s->tok = cursor;
     283      526817 :         s->len = 0;
     284             : /*!re2c
     285             : 
     286             : /* */
     287             : any = [\000-\377];
     288             : number = [0-9]+;
     289             : 
     290             : hour24lz = [01][0-9] | "2"[0-4];
     291             : minutelz = [0-5][0-9];
     292             : monthlz = "0" [1-9] | "1" [0-2];
     293             : monthlzz = "0" [0-9] | "1" [0-2];
     294             : daylz   = "0" [1-9] | [1-2][0-9] | "3" [01];
     295             : daylzz  = "0" [0-9] | [1-2][0-9] | "3" [01];
     296             : secondlz = minutelz;
     297             : year4 = [0-9]{4};
     298             : weekofyear = "0"[1-9] | [1-4][0-9] | "5"[0-3];
     299             : 
     300             : space = [ \t]+;
     301             : datetimebasic  = year4 monthlz daylz "T" hour24lz minutelz secondlz "Z";
     302             : datetimeextended  = year4 "-" monthlz "-" daylz "T" hour24lz ':' minutelz ':' secondlz "Z";
     303             : period   = "P" (number "Y")? (number "M")? (number "W")? (number "D")? ("T" (number "H")? (number "M")? (number "S")?)?;
     304             : combinedrep = "P" year4 "-" monthlzz "-" daylzz "T" hour24lz ':' minutelz ':' secondlz;
     305             : 
     306             : recurrences = "R" number;
     307             : 
     308             : isoweekday       = year4 "-"? "W" weekofyear "-"? [0-7];
     309             : isoweek          = year4 "-"? "W" weekofyear;
     310             : 
     311             : */
     312             : 
     313             : /*!re2c
     314             :         /* so that vim highlights correctly */
     315             :         recurrences
     316             :         {
     317             :                 DEBUG_OUTPUT("recurrences");
     318           1 :                 TIMELIB_INIT;
     319           1 :                 ptr++;
     320           1 :                 s->recurrences = timelib_get_unsigned_nr((char **) &ptr, 9);
     321           1 :                 TIMELIB_DEINIT;
     322           1 :                 s->have_recurrences = 1;
     323           1 :                 return TIMELIB_PERIOD;
     324             :         }
     325             : 
     326             :         datetimebasic| datetimeextended
     327             :         {
     328             :                 timelib_time *current;
     329             : 
     330          13 :                 if (s->have_date || s->have_period) {
     331           3 :                         current = s->end;
     332           3 :                         s->have_end_date = 1;
     333             :                 } else {
     334           7 :                         current = s->begin;
     335           7 :                         s->have_begin_date = 1;
     336             :                 }
     337             :                 DEBUG_OUTPUT("datetimebasic | datetimeextended");
     338          10 :                 TIMELIB_INIT;
     339          10 :                 current->y = timelib_get_nr((char **) &ptr, 4);
     340          10 :                 current->m = timelib_get_nr((char **) &ptr, 2);
     341          10 :                 current->d = timelib_get_nr((char **) &ptr, 2);
     342          10 :                 current->h = timelib_get_nr((char **) &ptr, 2);
     343          10 :                 current->i = timelib_get_nr((char **) &ptr, 2);
     344          10 :                 current->s = timelib_get_nr((char **) &ptr, 2);
     345          10 :                 s->have_date = 1;
     346          10 :                 TIMELIB_DEINIT;
     347          10 :                 return TIMELIB_ISO_DATE;
     348             :         }
     349             : 
     350             :         period
     351             :         {
     352             :                 timelib_sll nr;
     353      175591 :                 int         in_time = 0;
     354             :                 DEBUG_OUTPUT("period");
     355      175591 :                 TIMELIB_INIT;
     356      175591 :                 ptr++;
     357             :                 do {
     358      527373 :                         if ( *ptr == 'T' ) {
     359        1297 :                                 in_time = 1;
     360        1297 :                                 ptr++;
     361             :                         }
     362      527373 :                         if ( *ptr == '\0' ) {
     363           0 :                                 add_error(s, "Missing expected time part");
     364           0 :                                 break;
     365             :                         }
     366             : 
     367      527373 :                         nr = timelib_get_unsigned_nr((char **) &ptr, 12);
     368      527373 :                         switch (*ptr) {
     369      174036 :                                 case 'Y': s->period->y = nr; break;
     370           0 :                                 case 'W': s->period->d = nr * 7; break;
     371      175536 :                                 case 'D': s->period->d = nr; break;
     372        1282 :                                 case 'H': s->period->h = nr; break;
     373        1246 :                                 case 'S': s->period->s = nr; break;
     374             :                                 case 'M': 
     375      175273 :                                         if (in_time) {
     376        1239 :                                                 s->period->i = nr;
     377             :                                         } else {
     378      174034 :                                                 s->period->m = nr; 
     379             :                                         }
     380      175273 :                                         break;
     381             :                                 default:
     382           0 :                                         add_error(s, "Undefined period specifier");
     383             :                                         break;
     384             :                         }
     385      527373 :                         ptr++;
     386      527373 :                 } while (!s->errors->error_count && *ptr);
     387      175591 :                 s->have_period = 1;
     388      175591 :                 TIMELIB_DEINIT;
     389      175591 :                 return TIMELIB_PERIOD;
     390             :         }
     391             : 
     392             :         combinedrep
     393             :         {
     394             :                 DEBUG_OUTPUT("combinedrep");
     395           0 :                 TIMELIB_INIT;
     396           0 :                 s->period->y = timelib_get_unsigned_nr((char **) &ptr, 4);
     397           0 :                 ptr++;
     398           0 :                 s->period->m = timelib_get_unsigned_nr((char **) &ptr, 2);
     399           0 :                 ptr++;
     400           0 :                 s->period->d = timelib_get_unsigned_nr((char **) &ptr, 2);
     401           0 :                 ptr++;
     402           0 :                 s->period->h = timelib_get_unsigned_nr((char **) &ptr, 2);
     403           0 :                 ptr++;
     404           0 :                 s->period->i = timelib_get_unsigned_nr((char **) &ptr, 2);
     405           0 :                 ptr++;
     406           0 :                 s->period->s = timelib_get_unsigned_nr((char **) &ptr, 2);
     407           0 :                 s->have_period = 1;
     408           0 :                 TIMELIB_DEINIT;
     409           0 :                 return TIMELIB_PERIOD;
     410             :         }
     411             : 
     412             :         [ .,\t/]
     413             :         {
     414           7 :                 goto std;
     415             :         }
     416             : 
     417             :         "\000"|"\n"
     418             :         {
     419      175599 :                 s->pos = cursor; s->line++;
     420      175599 :                 goto std;
     421             :         }
     422             : 
     423             :         any
     424             :         {
     425          10 :                 add_error(s, "Unexpected character");
     426          10 :                 goto std;
     427             :         }
     428             : */
     429             : }
     430             : #ifdef PHP_WIN32
     431             : #pragma optimize( "", on )
     432             : #endif
     433             : 
     434             : /*!max:re2c */
     435             : 
     436      175600 : void timelib_strtointerval(char *s, int len, 
     437             :                            timelib_time **begin, timelib_time **end, 
     438             :                                                    timelib_rel_time **period, int *recurrences, 
     439             :                                                    struct timelib_error_container **errors)
     440             : {
     441             :         Scanner in;
     442             :         int t;
     443      175600 :         char *e = s + len - 1;
     444             : 
     445      175600 :         memset(&in, 0, sizeof(in));
     446      175600 :         in.errors = malloc(sizeof(struct timelib_error_container));
     447      175600 :         in.errors->warning_count = 0;
     448      175600 :         in.errors->warning_messages = NULL;
     449      175600 :         in.errors->error_count = 0;
     450      175600 :         in.errors->error_messages = NULL;
     451             : 
     452      175600 :         if (len > 0) {
     453      351198 :                 while (isspace(*s) && s < e) {
     454           0 :                         s++;
     455             :                 }
     456      351198 :                 while (isspace(*e) && e > s) {
     457           0 :                         e--;
     458             :                 }
     459             :         }
     460      175600 :         if (e - s < 0) {
     461           1 :                 add_error(&in, "Empty string");
     462           1 :                 if (errors) {
     463           1 :                         *errors = in.errors;
     464             :                 } else {
     465           0 :                         timelib_error_container_dtor(in.errors);
     466             :                 }
     467           1 :                 return;
     468             :         }
     469      175599 :         e++;
     470             : 
     471             :         /* init cursor */
     472      175599 :         in.str = malloc((e - s) + YYMAXFILL);
     473      175599 :         memset(in.str, 0, (e - s) + YYMAXFILL);
     474      175599 :         memcpy(in.str, s, (e - s));
     475      175599 :         in.lim = in.str + (e - s) + YYMAXFILL;
     476      175599 :         in.cur = in.str;
     477             : 
     478             :         /* init value containers */
     479      175599 :         in.begin = timelib_time_ctor();
     480      175599 :         in.begin->y = TIMELIB_UNSET;
     481      175599 :         in.begin->d = TIMELIB_UNSET;
     482      175599 :         in.begin->m = TIMELIB_UNSET;
     483      175599 :         in.begin->h = TIMELIB_UNSET;
     484      175599 :         in.begin->i = TIMELIB_UNSET;
     485      175599 :         in.begin->s = TIMELIB_UNSET;
     486      175599 :         in.begin->f = 0;
     487      175599 :         in.begin->z = 0;
     488      175599 :         in.begin->dst = 0;
     489      175599 :         in.begin->is_localtime = 0;
     490      175599 :         in.begin->zone_type = TIMELIB_ZONETYPE_OFFSET;
     491             : 
     492      175599 :         in.end = timelib_time_ctor();
     493      175599 :         in.end->y = TIMELIB_UNSET;
     494      175599 :         in.end->d = TIMELIB_UNSET;
     495      175599 :         in.end->m = TIMELIB_UNSET;
     496      175599 :         in.end->h = TIMELIB_UNSET;
     497      175599 :         in.end->i = TIMELIB_UNSET;
     498      175599 :         in.end->s = TIMELIB_UNSET;
     499      175599 :         in.end->f = 0;
     500      175599 :         in.end->z = 0;
     501      175599 :         in.end->dst = 0;
     502      175599 :         in.end->is_localtime = 0;
     503      175599 :         in.end->zone_type = TIMELIB_ZONETYPE_OFFSET;
     504             : 
     505      175599 :         in.period = timelib_rel_time_ctor();
     506      175599 :         in.period->y = 0;
     507      175599 :         in.period->d = 0;
     508      175599 :         in.period->m = 0;
     509      175599 :         in.period->h = 0;
     510      175599 :         in.period->i = 0;
     511      175599 :         in.period->s = 0;
     512      175599 :         in.period->weekday = 0;
     513      175599 :         in.period->weekday_behavior = 0;
     514      175599 :         in.period->first_last_day_of = 0;
     515      175599 :         in.period->days = TIMELIB_UNSET;
     516             : 
     517      175599 :         in.recurrences = 1;
     518             : 
     519             :         do {
     520      351201 :                 t = scan(&in);
     521             : #ifdef DEBUG_PARSER
     522             :                 printf("%d\n", t);
     523             : #endif
     524      351201 :         } while(t != EOI);
     525             : 
     526      175599 :         free(in.str);
     527      175599 :         if (errors) {
     528      175599 :                 *errors = in.errors;
     529             :         } else {
     530           0 :                 timelib_error_container_dtor(in.errors);
     531             :         }
     532      175599 :         if (in.have_begin_date) {
     533           7 :                 *begin = in.begin;
     534             :         } else {
     535      175592 :                 timelib_time_dtor(in.begin);
     536             :         }
     537      175599 :         if (in.have_end_date) {
     538           3 :                 *end   = in.end;
     539             :         } else {
     540      175596 :                 timelib_time_dtor(in.end);
     541             :         }
     542      175599 :         if (in.have_period) {
     543      175591 :                 *period = in.period;
     544             :         } else {
     545           8 :                 timelib_rel_time_dtor(in.period);
     546             :         }
     547      175599 :         if (in.have_recurrences) {
     548           1 :                 *recurrences = in.recurrences;
     549             :         }
     550             : }
     551             : 
     552             : 
     553             : /*
     554             :  * vim: syntax=c
     555             :  */

Generated by: LCOV version 1.10

Generated at Tue, 29 Jul 2014 09:53:17 +0000 (13 hours ago)

Copyright © 2005-2014 The PHP Group
All rights reserved.