LCOV - code coverage report
Current view: top level - src/interfaces/ecpg/pgtypeslib - datetime.c (source / functions) Coverage Total Hit
Test: PostgreSQL 19devel Lines: 82.4 % 284 234
Test Date: 2026-03-03 14:15:12 Functions: 90.9 % 11 10
Legend: Lines:     hit not hit

            Line data    Source code
       1              : /* src/interfaces/ecpg/pgtypeslib/datetime.c */
       2              : 
       3              : #include "postgres_fe.h"
       4              : 
       5              : #include <time.h>
       6              : #include <ctype.h>
       7              : #include <limits.h>
       8              : 
       9              : #include "dt.h"
      10              : #include "pgtypes_date.h"
      11              : #include "pgtypes_error.h"
      12              : #include "pgtypeslib_extern.h"
      13              : 
      14              : date *
      15            2 : PGTYPESdate_new(void)
      16              : {
      17              :     date       *result;
      18              : 
      19            2 :     result = (date *) pgtypes_alloc(sizeof(date));
      20              :     /* result can be NULL if we run out of memory */
      21            2 :     return result;
      22              : }
      23              : 
      24              : void
      25            2 : PGTYPESdate_free(date * d)
      26              : {
      27            2 :     free(d);
      28            2 : }
      29              : 
      30              : date
      31           12 : PGTYPESdate_from_timestamp(timestamp dt)
      32              : {
      33              :     date        dDate;
      34              : 
      35           12 :     dDate = 0;                  /* suppress compiler warning */
      36              : 
      37           12 :     if (!TIMESTAMP_NOT_FINITE(dt))
      38              :     {
      39              :         /* Microseconds to days */
      40           12 :         dDate = (dt / USECS_PER_DAY);
      41              :     }
      42              : 
      43           12 :     return dDate;
      44              : }
      45              : 
      46              : date
      47          108 : PGTYPESdate_from_asc(char *str, char **endptr)
      48              : {
      49              :     date        dDate;
      50              :     fsec_t      fsec;
      51              :     struct tm   tt,
      52          108 :                *tm = &tt;
      53              :     int         dtype;
      54              :     int         nf;
      55              :     char       *field[MAXDATEFIELDS];
      56              :     int         ftype[MAXDATEFIELDS];
      57              :     char        lowstr[MAXDATELEN + MAXDATEFIELDS];
      58              :     char       *realptr;
      59          108 :     char      **ptr = (endptr != NULL) ? endptr : &realptr;
      60              : 
      61          108 :     bool        EuroDates = false;
      62              : 
      63          108 :     errno = 0;
      64          108 :     if (strlen(str) > MAXDATELEN)
      65              :     {
      66            0 :         errno = PGTYPES_DATE_BAD_DATE;
      67            0 :         return INT_MIN;
      68              :     }
      69              : 
      70          214 :     if (ParseDateTime(str, lowstr, field, ftype, &nf, ptr) != 0 ||
      71          106 :         DecodeDateTime(field, ftype, nf, &dtype, tm, &fsec, EuroDates) != 0)
      72              :     {
      73           10 :         errno = PGTYPES_DATE_BAD_DATE;
      74           10 :         return INT_MIN;
      75              :     }
      76              : 
      77           98 :     switch (dtype)
      78              :     {
      79           98 :         case DTK_DATE:
      80           98 :             break;
      81              : 
      82            0 :         case DTK_EPOCH:
      83            0 :             if (GetEpochTime(tm) < 0)
      84              :             {
      85            0 :                 errno = PGTYPES_DATE_BAD_DATE;
      86            0 :                 return INT_MIN;
      87              :             }
      88            0 :             break;
      89              : 
      90            0 :         default:
      91            0 :             errno = PGTYPES_DATE_BAD_DATE;
      92            0 :             return INT_MIN;
      93              :     }
      94              : 
      95           98 :     dDate = (date2j(tm->tm_year, tm->tm_mon, tm->tm_mday) - date2j(2000, 1, 1));
      96              : 
      97           98 :     return dDate;
      98              : }
      99              : 
     100              : char *
     101          190 : PGTYPESdate_to_asc(date dDate)
     102              : {
     103              :     struct tm   tt,
     104          190 :                *tm = &tt;
     105              :     char        buf[MAXDATELEN + 1];
     106          190 :     int         DateStyle = 1;
     107          190 :     bool        EuroDates = false;
     108              : 
     109          190 :     j2date(dDate + date2j(2000, 1, 1), &(tm->tm_year), &(tm->tm_mon), &(tm->tm_mday));
     110          190 :     EncodeDateOnly(tm, DateStyle, buf, EuroDates);
     111          190 :     return pgtypes_strdup(buf);
     112              : }
     113              : 
     114              : void
     115            2 : PGTYPESdate_julmdy(date jd, int *mdy)
     116              : {
     117              :     int         y,
     118              :                 m,
     119              :                 d;
     120              : 
     121            2 :     j2date((int) (jd + date2j(2000, 1, 1)), &y, &m, &d);
     122            2 :     mdy[0] = m;
     123            2 :     mdy[1] = d;
     124            2 :     mdy[2] = y;
     125            2 : }
     126              : 
     127              : void
     128            4 : PGTYPESdate_mdyjul(int *mdy, date * jdate)
     129              : {
     130              :     /* month is mdy[0] */
     131              :     /* day   is mdy[1] */
     132              :     /* year  is mdy[2] */
     133              : 
     134            4 :     *jdate = (date) (date2j(mdy[2], mdy[0], mdy[1]) - date2j(2000, 1, 1));
     135            4 : }
     136              : 
     137              : int
     138           36 : PGTYPESdate_dayofweek(date dDate)
     139              : {
     140              :     /*
     141              :      * Sunday:  0 Monday:      1 Tuesday:     2 Wednesday:   3 Thursday: 4
     142              :      * Friday:      5 Saturday:    6
     143              :      */
     144           36 :     return (int) (dDate + date2j(2000, 1, 1) + 1) % 7;
     145              : }
     146              : 
     147              : void
     148            0 : PGTYPESdate_today(date * d)
     149              : {
     150              :     struct tm   ts;
     151              : 
     152            0 :     GetCurrentDateTime(&ts);
     153            0 :     if (errno == 0)
     154            0 :         *d = date2j(ts.tm_year, ts.tm_mon, ts.tm_mday) - date2j(2000, 1, 1);
     155            0 : }
     156              : 
     157              : #define PGTYPES_DATE_NUM_MAX_DIGITS     20  /* should suffice for most
     158              :                                              * years... */
     159              : 
     160              : #define PGTYPES_FMTDATE_DAY_DIGITS_LZ       1   /* LZ means "leading zeroes" */
     161              : #define PGTYPES_FMTDATE_DOW_LITERAL_SHORT   2
     162              : #define PGTYPES_FMTDATE_MONTH_DIGITS_LZ     3
     163              : #define PGTYPES_FMTDATE_MONTH_LITERAL_SHORT 4
     164              : #define PGTYPES_FMTDATE_YEAR_DIGITS_SHORT   5
     165              : #define PGTYPES_FMTDATE_YEAR_DIGITS_LONG    6
     166              : 
     167              : int
     168           26 : PGTYPESdate_fmt_asc(date dDate, const char *fmtstring, char *outbuf)
     169              : {
     170              :     static struct
     171              :     {
     172              :         char       *format;
     173              :         int         component;
     174              :     }           mapping[] =
     175              :     {
     176              :         /*
     177              :          * format items have to be sorted according to their length, since the
     178              :          * first pattern that matches gets replaced by its value
     179              :          */
     180              :         {
     181              :             "ddd", PGTYPES_FMTDATE_DOW_LITERAL_SHORT
     182              :         },
     183              :         {
     184              :             "dd", PGTYPES_FMTDATE_DAY_DIGITS_LZ
     185              :         },
     186              :         {
     187              :             "mmm", PGTYPES_FMTDATE_MONTH_LITERAL_SHORT
     188              :         },
     189              :         {
     190              :             "mm", PGTYPES_FMTDATE_MONTH_DIGITS_LZ
     191              :         },
     192              :         {
     193              :             "yyyy", PGTYPES_FMTDATE_YEAR_DIGITS_LONG
     194              :         },
     195              :         {
     196              :             "yy", PGTYPES_FMTDATE_YEAR_DIGITS_SHORT
     197              :         },
     198              :         {
     199              :             NULL, 0
     200              :         }
     201              :     };
     202              : 
     203              :     union un_fmt_comb replace_val;
     204              :     int         replace_type;
     205              : 
     206              :     int         i;
     207              :     int         dow;
     208              :     char       *start_pattern;
     209              :     struct tm   tm;
     210              : 
     211              :     /* copy the string over */
     212           26 :     strcpy(outbuf, fmtstring);
     213              : 
     214              :     /* get the date */
     215           26 :     j2date(dDate + date2j(2000, 1, 1), &(tm.tm_year), &(tm.tm_mon), &(tm.tm_mday));
     216           26 :     dow = PGTYPESdate_dayofweek(dDate);
     217              : 
     218          182 :     for (i = 0; mapping[i].format != NULL; i++)
     219              :     {
     220          248 :         while ((start_pattern = strstr(outbuf, mapping[i].format)) != NULL)
     221              :         {
     222           92 :             switch (mapping[i].component)
     223              :             {
     224            8 :                 case PGTYPES_FMTDATE_DOW_LITERAL_SHORT:
     225            8 :                     replace_val.str_val = pgtypes_date_weekdays_short[dow];
     226            8 :                     replace_type = PGTYPES_TYPE_STRING_CONSTANT;
     227            8 :                     break;
     228           28 :                 case PGTYPES_FMTDATE_DAY_DIGITS_LZ:
     229           28 :                     replace_val.uint_val = tm.tm_mday;
     230           28 :                     replace_type = PGTYPES_TYPE_UINT_2_LZ;
     231           28 :                     break;
     232           12 :                 case PGTYPES_FMTDATE_MONTH_LITERAL_SHORT:
     233           12 :                     replace_val.str_val = months[tm.tm_mon - 1];
     234           12 :                     replace_type = PGTYPES_TYPE_STRING_CONSTANT;
     235           12 :                     break;
     236           16 :                 case PGTYPES_FMTDATE_MONTH_DIGITS_LZ:
     237           16 :                     replace_val.uint_val = tm.tm_mon;
     238           16 :                     replace_type = PGTYPES_TYPE_UINT_2_LZ;
     239           16 :                     break;
     240           16 :                 case PGTYPES_FMTDATE_YEAR_DIGITS_LONG:
     241           16 :                     replace_val.uint_val = tm.tm_year;
     242           16 :                     replace_type = PGTYPES_TYPE_UINT_4_LZ;
     243           16 :                     break;
     244           12 :                 case PGTYPES_FMTDATE_YEAR_DIGITS_SHORT:
     245           12 :                     replace_val.uint_val = tm.tm_year % 100;
     246           12 :                     replace_type = PGTYPES_TYPE_UINT_2_LZ;
     247           12 :                     break;
     248            0 :                 default:
     249              : 
     250              :                     /*
     251              :                      * should not happen, set something anyway
     252              :                      */
     253            0 :                     replace_val.str_val = " ";
     254            0 :                     replace_type = PGTYPES_TYPE_STRING_CONSTANT;
     255              :             }
     256           92 :             switch (replace_type)
     257              :             {
     258           20 :                 case PGTYPES_TYPE_STRING_MALLOCED:
     259              :                 case PGTYPES_TYPE_STRING_CONSTANT:
     260           20 :                     memcpy(start_pattern, replace_val.str_val,
     261           20 :                            strlen(replace_val.str_val));
     262           20 :                     if (replace_type == PGTYPES_TYPE_STRING_MALLOCED)
     263            0 :                         free(replace_val.str_val);
     264           20 :                     break;
     265            0 :                 case PGTYPES_TYPE_UINT:
     266              :                     {
     267            0 :                         char       *t = pgtypes_alloc(PGTYPES_DATE_NUM_MAX_DIGITS);
     268              : 
     269            0 :                         if (!t)
     270            0 :                             return -1;
     271            0 :                         snprintf(t, PGTYPES_DATE_NUM_MAX_DIGITS,
     272              :                                  "%u", replace_val.uint_val);
     273            0 :                         memcpy(start_pattern, t, strlen(t));
     274            0 :                         free(t);
     275              :                     }
     276            0 :                     break;
     277           56 :                 case PGTYPES_TYPE_UINT_2_LZ:
     278              :                     {
     279           56 :                         char       *t = pgtypes_alloc(PGTYPES_DATE_NUM_MAX_DIGITS);
     280              : 
     281           56 :                         if (!t)
     282            0 :                             return -1;
     283           56 :                         snprintf(t, PGTYPES_DATE_NUM_MAX_DIGITS,
     284              :                                  "%02u", replace_val.uint_val);
     285           56 :                         memcpy(start_pattern, t, strlen(t));
     286           56 :                         free(t);
     287              :                     }
     288           56 :                     break;
     289           16 :                 case PGTYPES_TYPE_UINT_4_LZ:
     290              :                     {
     291           16 :                         char       *t = pgtypes_alloc(PGTYPES_DATE_NUM_MAX_DIGITS);
     292              : 
     293           16 :                         if (!t)
     294            0 :                             return -1;
     295           16 :                         snprintf(t, PGTYPES_DATE_NUM_MAX_DIGITS,
     296              :                                  "%04u", replace_val.uint_val);
     297           16 :                         memcpy(start_pattern, t, strlen(t));
     298           16 :                         free(t);
     299              :                     }
     300           16 :                     break;
     301            0 :                 default:
     302              : 
     303              :                     /*
     304              :                      * doesn't happen (we set replace_type to
     305              :                      * PGTYPES_TYPE_STRING_CONSTANT in case of an error above)
     306              :                      */
     307            0 :                     break;
     308              :             }
     309              :         }
     310              :     }
     311           26 :     return 0;
     312              : }
     313              : 
     314              : 
     315              : /*
     316              :  * PGTYPESdate_defmt_asc
     317              :  *
     318              :  * function works as follows:
     319              :  *   - first we analyze the parameters
     320              :  *   - if this is a special case with no delimiters, add delimiters
     321              :  *   - find the tokens. First we look for numerical values. If we have found
     322              :  *     less than 3 tokens, we check for the months' names and thereafter for
     323              :  *     the abbreviations of the months' names.
     324              :  *   - then we see which parameter should be the date, the month and the
     325              :  *     year and from these values we calculate the date
     326              :  */
     327              : 
     328              : #define PGTYPES_DATE_MONTH_MAXLENGTH        20  /* probably even less  :-) */
     329              : int
     330           66 : PGTYPESdate_defmt_asc(date * d, const char *fmt, const char *str)
     331              : {
     332              :     /*
     333              :      * token[2] = { 4,6 } means that token 2 starts at position 4 and ends at
     334              :      * (including) position 6
     335              :      */
     336              :     int         token[3][2];
     337           66 :     int         token_values[3] = {-1, -1, -1};
     338              :     const char *fmt_token_order;
     339              :     const char *fmt_ystart,
     340              :                *fmt_mstart,
     341              :                *fmt_dstart;
     342              :     unsigned int i;
     343              :     int         reading_digit;
     344              :     int         token_count;
     345              :     char       *str_copy;
     346              :     struct tm   tm;
     347              : 
     348           66 :     tm.tm_year = tm.tm_mon = tm.tm_mday = 0;    /* keep compiler quiet */
     349              : 
     350           66 :     if (!d || !str || !fmt)
     351              :     {
     352            0 :         errno = PGTYPES_DATE_ERR_EARGS;
     353            0 :         return -1;
     354              :     }
     355              : 
     356              :     /* analyze the fmt string */
     357           66 :     fmt_ystart = strstr(fmt, "yy");
     358           66 :     fmt_mstart = strstr(fmt, "mm");
     359           66 :     fmt_dstart = strstr(fmt, "dd");
     360              : 
     361           66 :     if (!fmt_ystart || !fmt_mstart || !fmt_dstart)
     362              :     {
     363            2 :         errno = PGTYPES_DATE_ERR_EARGS;
     364            2 :         return -1;
     365              :     }
     366              : 
     367           64 :     if (fmt_ystart < fmt_mstart)
     368              :     {
     369              :         /* y m */
     370           14 :         if (fmt_dstart < fmt_ystart)
     371              :         {
     372              :             /* d y m */
     373            0 :             fmt_token_order = "dym";
     374              :         }
     375           14 :         else if (fmt_dstart > fmt_mstart)
     376              :         {
     377              :             /* y m d */
     378           14 :             fmt_token_order = "ymd";
     379              :         }
     380              :         else
     381              :         {
     382              :             /* y d m */
     383            0 :             fmt_token_order = "ydm";
     384              :         }
     385              :     }
     386              :     else
     387              :     {
     388              :         /* fmt_ystart > fmt_mstart */
     389              :         /* m y */
     390           50 :         if (fmt_dstart < fmt_mstart)
     391              :         {
     392              :             /* d m y */
     393           22 :             fmt_token_order = "dmy";
     394              :         }
     395           28 :         else if (fmt_dstart > fmt_ystart)
     396              :         {
     397              :             /* m y d */
     398            4 :             fmt_token_order = "myd";
     399              :         }
     400              :         else
     401              :         {
     402              :             /* m d y */
     403           24 :             fmt_token_order = "mdy";
     404              :         }
     405              :     }
     406              : 
     407              :     /*
     408              :      * handle the special cases where there is no delimiter between the
     409              :      * digits. If we see this:
     410              :      *
     411              :      * only digits, 6 or 8 bytes then it might be ddmmyy and ddmmyyyy (or
     412              :      * similar)
     413              :      *
     414              :      * we reduce it to a string with delimiters and continue processing
     415              :      */
     416              : 
     417              :     /* check if we have only digits */
     418           64 :     reading_digit = 1;
     419          236 :     for (i = 0; str[i]; i++)
     420              :     {
     421          218 :         if (!isdigit((unsigned char) str[i]))
     422              :         {
     423           46 :             reading_digit = 0;
     424           46 :             break;
     425              :         }
     426              :     }
     427           64 :     if (reading_digit)
     428              :     {
     429              :         int         frag_length[3];
     430              :         int         target_pos;
     431              : 
     432           18 :         i = strlen(str);
     433           18 :         if (i != 8 && i != 6)
     434              :         {
     435            2 :             errno = PGTYPES_DATE_ERR_ENOSHORTDATE;
     436            2 :             return -1;
     437              :         }
     438              :         /* okay, this really is the special case */
     439              : 
     440              :         /*
     441              :          * as long as the string, one additional byte for the terminator and 2
     442              :          * for the delimiters between the 3 fields
     443              :          */
     444           16 :         str_copy = pgtypes_alloc(strlen(str) + 1 + 2);
     445           16 :         if (!str_copy)
     446            0 :             return -1;
     447              : 
     448              :         /* determine length of the fragments */
     449           16 :         if (i == 6)
     450              :         {
     451            8 :             frag_length[0] = 2;
     452            8 :             frag_length[1] = 2;
     453            8 :             frag_length[2] = 2;
     454              :         }
     455              :         else
     456              :         {
     457            8 :             if (fmt_token_order[0] == 'y')
     458              :             {
     459            2 :                 frag_length[0] = 4;
     460            2 :                 frag_length[1] = 2;
     461            2 :                 frag_length[2] = 2;
     462              :             }
     463            6 :             else if (fmt_token_order[1] == 'y')
     464              :             {
     465            2 :                 frag_length[0] = 2;
     466            2 :                 frag_length[1] = 4;
     467            2 :                 frag_length[2] = 2;
     468              :             }
     469              :             else
     470              :             {
     471            4 :                 frag_length[0] = 2;
     472            4 :                 frag_length[1] = 2;
     473            4 :                 frag_length[2] = 4;
     474              :             }
     475              :         }
     476           16 :         target_pos = 0;
     477              : 
     478              :         /*
     479              :          * XXX: Here we could calculate the positions of the tokens and save
     480              :          * the for loop down there where we again check with isdigit() for
     481              :          * digits.
     482              :          */
     483           64 :         for (i = 0; i < 3; i++)
     484              :         {
     485           48 :             int         start_pos = 0;
     486              : 
     487           48 :             if (i >= 1)
     488           32 :                 start_pos += frag_length[0];
     489           48 :             if (i == 2)
     490           16 :                 start_pos += frag_length[1];
     491              : 
     492           48 :             strncpy(str_copy + target_pos, str + start_pos,
     493           48 :                     frag_length[i]);
     494           48 :             target_pos += frag_length[i];
     495           48 :             if (i != 2)
     496              :             {
     497           32 :                 str_copy[target_pos] = ' ';
     498           32 :                 target_pos++;
     499              :             }
     500              :         }
     501           16 :         str_copy[target_pos] = '\0';
     502              :     }
     503              :     else
     504              :     {
     505           46 :         str_copy = pgtypes_strdup(str);
     506           46 :         if (!str_copy)
     507            0 :             return -1;
     508              : 
     509              :         /* convert the whole string to lower case */
     510          888 :         for (i = 0; str_copy[i]; i++)
     511          842 :             str_copy[i] = (char) pg_tolower((unsigned char) str_copy[i]);
     512              :     }
     513              : 
     514              :     /* look for numerical tokens */
     515           62 :     reading_digit = 0;
     516           62 :     token_count = 0;
     517         1048 :     for (i = 0; i < strlen(str_copy); i++)
     518              :     {
     519          986 :         if (!isdigit((unsigned char) str_copy[i]) && reading_digit)
     520              :         {
     521              :             /* the token is finished */
     522          106 :             token[token_count][1] = i - 1;
     523          106 :             reading_digit = 0;
     524          106 :             token_count++;
     525              :         }
     526          880 :         else if (isdigit((unsigned char) str_copy[i]) && !reading_digit)
     527              :         {
     528              :             /* we have found a token */
     529          158 :             token[token_count][0] = i;
     530          158 :             reading_digit = 1;
     531              :         }
     532              :     }
     533              : 
     534              :     /*
     535              :      * we're at the end of the input string, but maybe we are still reading a
     536              :      * number...
     537              :      */
     538           62 :     if (reading_digit)
     539              :     {
     540           52 :         token[token_count][1] = i - 1;
     541           52 :         token_count++;
     542              :     }
     543              : 
     544              : 
     545           62 :     if (token_count < 2)
     546              :     {
     547              :         /*
     548              :          * not all tokens found, no way to find 2 missing tokens with string
     549              :          * matches
     550              :          */
     551            2 :         free(str_copy);
     552            2 :         errno = PGTYPES_DATE_ERR_ENOSHORTDATE;
     553            2 :         return -1;
     554              :     }
     555              : 
     556           60 :     if (token_count != 3)
     557              :     {
     558              :         /*
     559              :          * not all tokens found but we may find another one with string
     560              :          * matches by testing for the months names and months abbreviations
     561              :          */
     562           24 :         char       *month_lower_tmp = pgtypes_alloc(PGTYPES_DATE_MONTH_MAXLENGTH);
     563              :         char       *start_pos;
     564              :         int         j;
     565              :         int         offset;
     566           24 :         int         found = 0;
     567              :         char      **list;
     568              : 
     569           24 :         if (!month_lower_tmp)
     570              :         {
     571              :             /* free variables we alloc'ed before */
     572            0 :             free(str_copy);
     573            0 :             return -1;
     574              :         }
     575           24 :         list = pgtypes_date_months;
     576          368 :         for (i = 0; list[i]; i++)
     577              :         {
     578         2234 :             for (j = 0; j < PGTYPES_DATE_MONTH_MAXLENGTH; j++)
     579              :             {
     580         2234 :                 month_lower_tmp[j] = (char) pg_tolower((unsigned char) list[i][j]);
     581         2234 :                 if (!month_lower_tmp[j])
     582              :                 {
     583              :                     /* properly terminated */
     584          368 :                     break;
     585              :                 }
     586              :             }
     587          368 :             if ((start_pos = strstr(str_copy, month_lower_tmp)))
     588              :             {
     589           24 :                 offset = start_pos - str_copy;
     590              : 
     591              :                 /*
     592              :                  * sort the new token into the numeric tokens, shift them if
     593              :                  * necessary
     594              :                  */
     595           24 :                 if (offset < token[0][0])
     596              :                 {
     597           12 :                     token[2][0] = token[1][0];
     598           12 :                     token[2][1] = token[1][1];
     599           12 :                     token[1][0] = token[0][0];
     600           12 :                     token[1][1] = token[0][1];
     601           12 :                     token_count = 0;
     602              :                 }
     603           12 :                 else if (offset < token[1][0])
     604              :                 {
     605           12 :                     token[2][0] = token[1][0];
     606           12 :                     token[2][1] = token[1][1];
     607           12 :                     token_count = 1;
     608              :                 }
     609              :                 else
     610            0 :                     token_count = 2;
     611           24 :                 token[token_count][0] = offset;
     612           24 :                 token[token_count][1] = offset + strlen(month_lower_tmp) - 1;
     613              : 
     614              :                 /*
     615              :                  * the value is the index of the month in the array of months
     616              :                  * + 1 (January is month 0)
     617              :                  */
     618           24 :                 token_values[token_count] = i + 1;
     619           24 :                 found = 1;
     620           24 :                 break;
     621              :             }
     622              : 
     623              :             /*
     624              :              * evil[tm] hack: if we read the pgtypes_date_months and haven't
     625              :              * found a match, reset list to point to months (abbreviations)
     626              :              * and reset the counter variable i
     627              :              */
     628          344 :             if (list == pgtypes_date_months)
     629              :             {
     630          236 :                 if (list[i + 1] == NULL)
     631              :                 {
     632           12 :                     list = months;
     633           12 :                     i = -1;
     634              :                 }
     635              :             }
     636              :         }
     637           24 :         if (!found)
     638              :         {
     639            0 :             free(month_lower_tmp);
     640            0 :             free(str_copy);
     641            0 :             errno = PGTYPES_DATE_ERR_ENOTDMY;
     642            0 :             return -1;
     643              :         }
     644              : 
     645              :         /*
     646              :          * here we found a month. token[token_count] and
     647              :          * token_values[token_count] reflect the month's details.
     648              :          *
     649              :          * only the month can be specified with a literal. Here we can do a
     650              :          * quick check if the month is at the right position according to the
     651              :          * format string because we can check if the token that we expect to
     652              :          * be the month is at the position of the only token that already has
     653              :          * a value. If we wouldn't check here we could say "December 4 1990"
     654              :          * with a fmt string of "dd mm yy" for 12 April 1990.
     655              :          */
     656           24 :         if (fmt_token_order[token_count] != 'm')
     657              :         {
     658              :             /* deal with the error later on */
     659            0 :             token_values[token_count] = -1;
     660              :         }
     661           24 :         free(month_lower_tmp);
     662              :     }
     663              : 
     664              :     /* terminate the tokens with ASCII-0 and get their values */
     665          240 :     for (i = 0; i < 3; i++)
     666              :     {
     667          180 :         *(str_copy + token[i][1] + 1) = '\0';
     668              :         /* A month already has a value set, check for token_value == -1 */
     669          180 :         if (token_values[i] == -1)
     670              :         {
     671          156 :             errno = 0;
     672          156 :             token_values[i] = strtol(str_copy + token[i][0], (char **) NULL, 10);
     673              :             /* strtol sets errno in case of an error */
     674          156 :             if (errno)
     675            0 :                 token_values[i] = -1;
     676              :         }
     677          180 :         if (fmt_token_order[i] == 'd')
     678           60 :             tm.tm_mday = token_values[i];
     679          120 :         else if (fmt_token_order[i] == 'm')
     680           60 :             tm.tm_mon = token_values[i];
     681           60 :         else if (fmt_token_order[i] == 'y')
     682           60 :             tm.tm_year = token_values[i];
     683              :     }
     684           60 :     free(str_copy);
     685              : 
     686           60 :     if (tm.tm_mday < 1 || tm.tm_mday > 31)
     687              :     {
     688            2 :         errno = PGTYPES_DATE_BAD_DAY;
     689            2 :         return -1;
     690              :     }
     691              : 
     692           58 :     if (tm.tm_mon < 1 || tm.tm_mon > MONTHS_PER_YEAR)
     693              :     {
     694            2 :         errno = PGTYPES_DATE_BAD_MONTH;
     695            2 :         return -1;
     696              :     }
     697              : 
     698           56 :     if (tm.tm_mday == 31 && (tm.tm_mon == 4 || tm.tm_mon == 6 || tm.tm_mon == 9 || tm.tm_mon == 11))
     699              :     {
     700            0 :         errno = PGTYPES_DATE_BAD_DAY;
     701            0 :         return -1;
     702              :     }
     703              : 
     704           56 :     if (tm.tm_mon == 2 && tm.tm_mday > 29)
     705              :     {
     706            0 :         errno = PGTYPES_DATE_BAD_DAY;
     707            0 :         return -1;
     708              :     }
     709              : 
     710           56 :     *d = date2j(tm.tm_year, tm.tm_mon, tm.tm_mday) - date2j(2000, 1, 1);
     711              : 
     712           56 :     return 0;
     713              : }
        

Generated by: LCOV version 2.0-1