LCOV - code coverage report
Current view: top level - src/interfaces/ecpg/pgtypeslib - datetime.c (source / functions) Coverage Total Hit
Test: Code coverage Lines: 0.0 % 342 0
Test Date: 2026-01-26 10:56:24 Functions: 0.0 % 11 0
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            0 : PGTYPESdate_new(void)
      16              : {
      17            0 :         date       *result;
      18              : 
      19            0 :         result = (date *) pgtypes_alloc(sizeof(date));
      20              :         /* result can be NULL if we run out of memory */
      21            0 :         return result;
      22            0 : }
      23              : 
      24              : void
      25            0 : PGTYPESdate_free(date * d)
      26              : {
      27            0 :         free(d);
      28            0 : }
      29              : 
      30              : date
      31            0 : PGTYPESdate_from_timestamp(timestamp dt)
      32              : {
      33            0 :         date            dDate;
      34              : 
      35            0 :         dDate = 0;                                      /* suppress compiler warning */
      36              : 
      37            0 :         if (!TIMESTAMP_NOT_FINITE(dt))
      38              :         {
      39              :                 /* Microseconds to days */
      40            0 :                 dDate = (dt / USECS_PER_DAY);
      41            0 :         }
      42              : 
      43            0 :         return dDate;
      44            0 : }
      45              : 
      46              : date
      47            0 : PGTYPESdate_from_asc(char *str, char **endptr)
      48              : {
      49            0 :         date            dDate;
      50            0 :         fsec_t          fsec;
      51            0 :         struct tm       tt,
      52            0 :                            *tm = &tt;
      53            0 :         int                     dtype;
      54            0 :         int                     nf;
      55            0 :         char       *field[MAXDATEFIELDS];
      56            0 :         int                     ftype[MAXDATEFIELDS];
      57            0 :         char            lowstr[MAXDATELEN + MAXDATEFIELDS];
      58            0 :         char       *realptr;
      59            0 :         char      **ptr = (endptr != NULL) ? endptr : &realptr;
      60              : 
      61            0 :         bool            EuroDates = false;
      62              : 
      63            0 :         errno = 0;
      64            0 :         if (strlen(str) > MAXDATELEN)
      65              :         {
      66            0 :                 errno = PGTYPES_DATE_BAD_DATE;
      67            0 :                 return INT_MIN;
      68              :         }
      69              : 
      70            0 :         if (ParseDateTime(str, lowstr, field, ftype, &nf, ptr) != 0 ||
      71            0 :                 DecodeDateTime(field, ftype, nf, &dtype, tm, &fsec, EuroDates) != 0)
      72              :         {
      73            0 :                 errno = PGTYPES_DATE_BAD_DATE;
      74            0 :                 return INT_MIN;
      75              :         }
      76              : 
      77            0 :         switch (dtype)
      78              :         {
      79              :                 case DTK_DATE:
      80              :                         break;
      81              : 
      82              :                 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              :                 default:
      91            0 :                         errno = PGTYPES_DATE_BAD_DATE;
      92            0 :                         return INT_MIN;
      93              :         }
      94              : 
      95            0 :         dDate = (date2j(tm->tm_year, tm->tm_mon, tm->tm_mday) - date2j(2000, 1, 1));
      96              : 
      97            0 :         return dDate;
      98            0 : }
      99              : 
     100              : char *
     101            0 : PGTYPESdate_to_asc(date dDate)
     102              : {
     103            0 :         struct tm       tt,
     104            0 :                            *tm = &tt;
     105            0 :         char            buf[MAXDATELEN + 1];
     106            0 :         int                     DateStyle = 1;
     107            0 :         bool            EuroDates = false;
     108              : 
     109            0 :         j2date(dDate + date2j(2000, 1, 1), &(tm->tm_year), &(tm->tm_mon), &(tm->tm_mday));
     110            0 :         EncodeDateOnly(tm, DateStyle, buf, EuroDates);
     111            0 :         return pgtypes_strdup(buf);
     112            0 : }
     113              : 
     114              : void
     115            0 : PGTYPESdate_julmdy(date jd, int *mdy)
     116              : {
     117            0 :         int                     y,
     118              :                                 m,
     119              :                                 d;
     120              : 
     121            0 :         j2date((int) (jd + date2j(2000, 1, 1)), &y, &m, &d);
     122            0 :         mdy[0] = m;
     123            0 :         mdy[1] = d;
     124            0 :         mdy[2] = y;
     125            0 : }
     126              : 
     127              : void
     128            0 : PGTYPESdate_mdyjul(int *mdy, date * jdate)
     129              : {
     130              :         /* month is mdy[0] */
     131              :         /* day   is mdy[1] */
     132              :         /* year  is mdy[2] */
     133              : 
     134            0 :         *jdate = (date) (date2j(mdy[2], mdy[0], mdy[1]) - date2j(2000, 1, 1));
     135            0 : }
     136              : 
     137              : int
     138            0 : PGTYPESdate_dayofweek(date dDate)
     139              : {
     140              :         /*
     141              :          * Sunday:      0 Monday:          1 Tuesday:     2 Wednesday:   3 Thursday: 4
     142              :          * Friday:              5 Saturday:    6
     143              :          */
     144            0 :         return (int) (dDate + date2j(2000, 1, 1) + 1) % 7;
     145              : }
     146              : 
     147              : void
     148            0 : PGTYPESdate_today(date * d)
     149              : {
     150            0 :         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            0 : 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            0 :         union un_fmt_comb replace_val;
     204            0 :         int                     replace_type;
     205              : 
     206            0 :         int                     i;
     207            0 :         int                     dow;
     208            0 :         char       *start_pattern;
     209            0 :         struct tm       tm;
     210              : 
     211              :         /* copy the string over */
     212            0 :         strcpy(outbuf, fmtstring);
     213              : 
     214              :         /* get the date */
     215            0 :         j2date(dDate + date2j(2000, 1, 1), &(tm.tm_year), &(tm.tm_mon), &(tm.tm_mday));
     216            0 :         dow = PGTYPESdate_dayofweek(dDate);
     217              : 
     218            0 :         for (i = 0; mapping[i].format != NULL; i++)
     219              :         {
     220            0 :                 while ((start_pattern = strstr(outbuf, mapping[i].format)) != NULL)
     221              :                 {
     222            0 :                         switch (mapping[i].component)
     223              :                         {
     224              :                                 case PGTYPES_FMTDATE_DOW_LITERAL_SHORT:
     225            0 :                                         replace_val.str_val = pgtypes_date_weekdays_short[dow];
     226            0 :                                         replace_type = PGTYPES_TYPE_STRING_CONSTANT;
     227            0 :                                         break;
     228              :                                 case PGTYPES_FMTDATE_DAY_DIGITS_LZ:
     229            0 :                                         replace_val.uint_val = tm.tm_mday;
     230            0 :                                         replace_type = PGTYPES_TYPE_UINT_2_LZ;
     231            0 :                                         break;
     232              :                                 case PGTYPES_FMTDATE_MONTH_LITERAL_SHORT:
     233            0 :                                         replace_val.str_val = months[tm.tm_mon - 1];
     234            0 :                                         replace_type = PGTYPES_TYPE_STRING_CONSTANT;
     235            0 :                                         break;
     236              :                                 case PGTYPES_FMTDATE_MONTH_DIGITS_LZ:
     237            0 :                                         replace_val.uint_val = tm.tm_mon;
     238            0 :                                         replace_type = PGTYPES_TYPE_UINT_2_LZ;
     239            0 :                                         break;
     240              :                                 case PGTYPES_FMTDATE_YEAR_DIGITS_LONG:
     241            0 :                                         replace_val.uint_val = tm.tm_year;
     242            0 :                                         replace_type = PGTYPES_TYPE_UINT_4_LZ;
     243            0 :                                         break;
     244              :                                 case PGTYPES_FMTDATE_YEAR_DIGITS_SHORT:
     245            0 :                                         replace_val.uint_val = tm.tm_year % 100;
     246            0 :                                         replace_type = PGTYPES_TYPE_UINT_2_LZ;
     247            0 :                                         break;
     248              :                                 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            0 :                         }
     256            0 :                         switch (replace_type)
     257              :                         {
     258              :                                 case PGTYPES_TYPE_STRING_MALLOCED:
     259              :                                 case PGTYPES_TYPE_STRING_CONSTANT:
     260            0 :                                         memcpy(start_pattern, replace_val.str_val,
     261              :                                                    strlen(replace_val.str_val));
     262            0 :                                         if (replace_type == PGTYPES_TYPE_STRING_MALLOCED)
     263            0 :                                                 free(replace_val.str_val);
     264            0 :                                         break;
     265              :                                 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            0 :                                                                  "%u", replace_val.uint_val);
     273            0 :                                                 memcpy(start_pattern, t, strlen(t));
     274            0 :                                                 free(t);
     275            0 :                                         }
     276            0 :                                         break;
     277              :                                 case PGTYPES_TYPE_UINT_2_LZ:
     278              :                                         {
     279            0 :                                                 char       *t = pgtypes_alloc(PGTYPES_DATE_NUM_MAX_DIGITS);
     280              : 
     281            0 :                                                 if (!t)
     282            0 :                                                         return -1;
     283            0 :                                                 snprintf(t, PGTYPES_DATE_NUM_MAX_DIGITS,
     284            0 :                                                                  "%02u", replace_val.uint_val);
     285            0 :                                                 memcpy(start_pattern, t, strlen(t));
     286            0 :                                                 free(t);
     287            0 :                                         }
     288            0 :                                         break;
     289              :                                 case PGTYPES_TYPE_UINT_4_LZ:
     290              :                                         {
     291            0 :                                                 char       *t = pgtypes_alloc(PGTYPES_DATE_NUM_MAX_DIGITS);
     292              : 
     293            0 :                                                 if (!t)
     294            0 :                                                         return -1;
     295            0 :                                                 snprintf(t, PGTYPES_DATE_NUM_MAX_DIGITS,
     296            0 :                                                                  "%04u", replace_val.uint_val);
     297            0 :                                                 memcpy(start_pattern, t, strlen(t));
     298            0 :                                                 free(t);
     299            0 :                                         }
     300            0 :                                         break;
     301              :                                 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            0 :         }
     311            0 :         return 0;
     312            0 : }
     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            0 : 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            0 :         int                     token[3][2];
     337            0 :         int                     token_values[3] = {-1, -1, -1};
     338            0 :         const char *fmt_token_order;
     339            0 :         const char *fmt_ystart,
     340              :                            *fmt_mstart,
     341              :                            *fmt_dstart;
     342            0 :         unsigned int i;
     343            0 :         int                     reading_digit;
     344            0 :         int                     token_count;
     345            0 :         char       *str_copy;
     346            0 :         struct tm       tm;
     347              : 
     348            0 :         tm.tm_year = tm.tm_mon = tm.tm_mday = 0;        /* keep compiler quiet */
     349              : 
     350            0 :         if (!d || !str || !fmt)
     351              :         {
     352            0 :                 errno = PGTYPES_DATE_ERR_EARGS;
     353            0 :                 return -1;
     354              :         }
     355              : 
     356              :         /* analyze the fmt string */
     357            0 :         fmt_ystart = strstr(fmt, "yy");
     358            0 :         fmt_mstart = strstr(fmt, "mm");
     359            0 :         fmt_dstart = strstr(fmt, "dd");
     360              : 
     361            0 :         if (!fmt_ystart || !fmt_mstart || !fmt_dstart)
     362              :         {
     363            0 :                 errno = PGTYPES_DATE_ERR_EARGS;
     364            0 :                 return -1;
     365              :         }
     366              : 
     367            0 :         if (fmt_ystart < fmt_mstart)
     368              :         {
     369              :                 /* y m */
     370            0 :                 if (fmt_dstart < fmt_ystart)
     371              :                 {
     372              :                         /* d y m */
     373            0 :                         fmt_token_order = "dym";
     374            0 :                 }
     375            0 :                 else if (fmt_dstart > fmt_mstart)
     376              :                 {
     377              :                         /* y m d */
     378            0 :                         fmt_token_order = "ymd";
     379            0 :                 }
     380              :                 else
     381              :                 {
     382              :                         /* y d m */
     383            0 :                         fmt_token_order = "ydm";
     384              :                 }
     385            0 :         }
     386              :         else
     387              :         {
     388              :                 /* fmt_ystart > fmt_mstart */
     389              :                 /* m y */
     390            0 :                 if (fmt_dstart < fmt_mstart)
     391              :                 {
     392              :                         /* d m y */
     393            0 :                         fmt_token_order = "dmy";
     394            0 :                 }
     395            0 :                 else if (fmt_dstart > fmt_ystart)
     396              :                 {
     397              :                         /* m y d */
     398            0 :                         fmt_token_order = "myd";
     399            0 :                 }
     400              :                 else
     401              :                 {
     402              :                         /* m d y */
     403            0 :                         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            0 :         reading_digit = 1;
     419            0 :         for (i = 0; str[i]; i++)
     420              :         {
     421            0 :                 if (!isdigit((unsigned char) str[i]))
     422              :                 {
     423            0 :                         reading_digit = 0;
     424            0 :                         break;
     425              :                 }
     426            0 :         }
     427            0 :         if (reading_digit)
     428              :         {
     429            0 :                 int                     frag_length[3];
     430            0 :                 int                     target_pos;
     431              : 
     432            0 :                 i = strlen(str);
     433            0 :                 if (i != 8 && i != 6)
     434              :                 {
     435            0 :                         errno = PGTYPES_DATE_ERR_ENOSHORTDATE;
     436            0 :                         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            0 :                 str_copy = pgtypes_alloc(strlen(str) + 1 + 2);
     445            0 :                 if (!str_copy)
     446            0 :                         return -1;
     447              : 
     448              :                 /* determine length of the fragments */
     449            0 :                 if (i == 6)
     450              :                 {
     451            0 :                         frag_length[0] = 2;
     452            0 :                         frag_length[1] = 2;
     453            0 :                         frag_length[2] = 2;
     454            0 :                 }
     455              :                 else
     456              :                 {
     457            0 :                         if (fmt_token_order[0] == 'y')
     458              :                         {
     459            0 :                                 frag_length[0] = 4;
     460            0 :                                 frag_length[1] = 2;
     461            0 :                                 frag_length[2] = 2;
     462            0 :                         }
     463            0 :                         else if (fmt_token_order[1] == 'y')
     464              :                         {
     465            0 :                                 frag_length[0] = 2;
     466            0 :                                 frag_length[1] = 4;
     467            0 :                                 frag_length[2] = 2;
     468            0 :                         }
     469              :                         else
     470              :                         {
     471            0 :                                 frag_length[0] = 2;
     472            0 :                                 frag_length[1] = 2;
     473            0 :                                 frag_length[2] = 4;
     474              :                         }
     475              :                 }
     476            0 :                 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            0 :                 for (i = 0; i < 3; i++)
     484              :                 {
     485            0 :                         int                     start_pos = 0;
     486              : 
     487            0 :                         if (i >= 1)
     488            0 :                                 start_pos += frag_length[0];
     489            0 :                         if (i == 2)
     490            0 :                                 start_pos += frag_length[1];
     491              : 
     492            0 :                         strncpy(str_copy + target_pos, str + start_pos,
     493              :                                         frag_length[i]);
     494            0 :                         target_pos += frag_length[i];
     495            0 :                         if (i != 2)
     496              :                         {
     497            0 :                                 str_copy[target_pos] = ' ';
     498            0 :                                 target_pos++;
     499            0 :                         }
     500            0 :                 }
     501            0 :                 str_copy[target_pos] = '\0';
     502            0 :         }
     503              :         else
     504              :         {
     505            0 :                 str_copy = pgtypes_strdup(str);
     506            0 :                 if (!str_copy)
     507            0 :                         return -1;
     508              : 
     509              :                 /* convert the whole string to lower case */
     510            0 :                 for (i = 0; str_copy[i]; i++)
     511            0 :                         str_copy[i] = (char) pg_tolower((unsigned char) str_copy[i]);
     512              :         }
     513              : 
     514              :         /* look for numerical tokens */
     515            0 :         reading_digit = 0;
     516            0 :         token_count = 0;
     517            0 :         for (i = 0; i < strlen(str_copy); i++)
     518              :         {
     519            0 :                 if (!isdigit((unsigned char) str_copy[i]) && reading_digit)
     520              :                 {
     521              :                         /* the token is finished */
     522            0 :                         token[token_count][1] = i - 1;
     523            0 :                         reading_digit = 0;
     524            0 :                         token_count++;
     525            0 :                 }
     526            0 :                 else if (isdigit((unsigned char) str_copy[i]) && !reading_digit)
     527              :                 {
     528              :                         /* we have found a token */
     529            0 :                         token[token_count][0] = i;
     530            0 :                         reading_digit = 1;
     531            0 :                 }
     532            0 :         }
     533              : 
     534              :         /*
     535              :          * we're at the end of the input string, but maybe we are still reading a
     536              :          * number...
     537              :          */
     538            0 :         if (reading_digit)
     539              :         {
     540            0 :                 token[token_count][1] = i - 1;
     541            0 :                 token_count++;
     542            0 :         }
     543              : 
     544              : 
     545            0 :         if (token_count < 2)
     546              :         {
     547              :                 /*
     548              :                  * not all tokens found, no way to find 2 missing tokens with string
     549              :                  * matches
     550              :                  */
     551            0 :                 free(str_copy);
     552            0 :                 errno = PGTYPES_DATE_ERR_ENOSHORTDATE;
     553            0 :                 return -1;
     554              :         }
     555              : 
     556            0 :         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            0 :                 char       *month_lower_tmp = pgtypes_alloc(PGTYPES_DATE_MONTH_MAXLENGTH);
     563            0 :                 char       *start_pos;
     564            0 :                 int                     j;
     565            0 :                 int                     offset;
     566            0 :                 int                     found = 0;
     567            0 :                 char      **list;
     568              : 
     569            0 :                 if (!month_lower_tmp)
     570              :                 {
     571              :                         /* free variables we alloc'ed before */
     572            0 :                         free(str_copy);
     573            0 :                         return -1;
     574              :                 }
     575            0 :                 list = pgtypes_date_months;
     576            0 :                 for (i = 0; list[i]; i++)
     577              :                 {
     578            0 :                         for (j = 0; j < PGTYPES_DATE_MONTH_MAXLENGTH; j++)
     579              :                         {
     580            0 :                                 month_lower_tmp[j] = (char) pg_tolower((unsigned char) list[i][j]);
     581            0 :                                 if (!month_lower_tmp[j])
     582              :                                 {
     583              :                                         /* properly terminated */
     584            0 :                                         break;
     585              :                                 }
     586            0 :                         }
     587            0 :                         if ((start_pos = strstr(str_copy, month_lower_tmp)))
     588              :                         {
     589            0 :                                 offset = start_pos - str_copy;
     590              : 
     591              :                                 /*
     592              :                                  * sort the new token into the numeric tokens, shift them if
     593              :                                  * necessary
     594              :                                  */
     595            0 :                                 if (offset < token[0][0])
     596              :                                 {
     597            0 :                                         token[2][0] = token[1][0];
     598            0 :                                         token[2][1] = token[1][1];
     599            0 :                                         token[1][0] = token[0][0];
     600            0 :                                         token[1][1] = token[0][1];
     601            0 :                                         token_count = 0;
     602            0 :                                 }
     603            0 :                                 else if (offset < token[1][0])
     604              :                                 {
     605            0 :                                         token[2][0] = token[1][0];
     606            0 :                                         token[2][1] = token[1][1];
     607            0 :                                         token_count = 1;
     608            0 :                                 }
     609              :                                 else
     610            0 :                                         token_count = 2;
     611            0 :                                 token[token_count][0] = offset;
     612            0 :                                 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            0 :                                 token_values[token_count] = i + 1;
     619            0 :                                 found = 1;
     620            0 :                                 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            0 :                         if (list == pgtypes_date_months)
     629              :                         {
     630            0 :                                 if (list[i + 1] == NULL)
     631              :                                 {
     632            0 :                                         list = months;
     633            0 :                                         i = -1;
     634            0 :                                 }
     635            0 :                         }
     636            0 :                 }
     637            0 :                 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            0 :                 if (fmt_token_order[token_count] != 'm')
     657              :                 {
     658              :                         /* deal with the error later on */
     659            0 :                         token_values[token_count] = -1;
     660            0 :                 }
     661            0 :                 free(month_lower_tmp);
     662            0 :         }
     663              : 
     664              :         /* terminate the tokens with ASCII-0 and get their values */
     665            0 :         for (i = 0; i < 3; i++)
     666              :         {
     667            0 :                 *(str_copy + token[i][1] + 1) = '\0';
     668              :                 /* A month already has a value set, check for token_value == -1 */
     669            0 :                 if (token_values[i] == -1)
     670              :                 {
     671            0 :                         errno = 0;
     672            0 :                         token_values[i] = strtol(str_copy + token[i][0], (char **) NULL, 10);
     673              :                         /* strtol sets errno in case of an error */
     674            0 :                         if (errno)
     675            0 :                                 token_values[i] = -1;
     676            0 :                 }
     677            0 :                 if (fmt_token_order[i] == 'd')
     678            0 :                         tm.tm_mday = token_values[i];
     679            0 :                 else if (fmt_token_order[i] == 'm')
     680            0 :                         tm.tm_mon = token_values[i];
     681            0 :                 else if (fmt_token_order[i] == 'y')
     682            0 :                         tm.tm_year = token_values[i];
     683            0 :         }
     684            0 :         free(str_copy);
     685              : 
     686            0 :         if (tm.tm_mday < 1 || tm.tm_mday > 31)
     687              :         {
     688            0 :                 errno = PGTYPES_DATE_BAD_DAY;
     689            0 :                 return -1;
     690              :         }
     691              : 
     692            0 :         if (tm.tm_mon < 1 || tm.tm_mon > MONTHS_PER_YEAR)
     693              :         {
     694            0 :                 errno = PGTYPES_DATE_BAD_MONTH;
     695            0 :                 return -1;
     696              :         }
     697              : 
     698            0 :         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            0 :         if (tm.tm_mon == 2 && tm.tm_mday > 29)
     705              :         {
     706            0 :                 errno = PGTYPES_DATE_BAD_DAY;
     707            0 :                 return -1;
     708              :         }
     709              : 
     710            0 :         *d = date2j(tm.tm_year, tm.tm_mon, tm.tm_mday) - date2j(2000, 1, 1);
     711              : 
     712            0 :         return 0;
     713            0 : }
        

Generated by: LCOV version 2.3.2-1