lib/iec_std_lib.h
changeset 711 8a1ba3db05b2
parent 709 bca119630cf6
child 712 58aadb212976
equal deleted inserted replaced
710:e9bb0ed80471 711:8a1ba3db05b2
    27  */
    27  */
    28 
    28 
    29 #include <limits.h>
    29 #include <limits.h>
    30 #include <float.h>
    30 #include <float.h>
    31 #include <math.h>
    31 #include <math.h>
    32 #include <time.h>
       
    33 #include <stdint.h>
    32 #include <stdint.h>
    34 #include <ctype.h>
    33 #include <ctype.h>
    35 
    34 
    36 #include <stdio.h>
    35 #include <stdio.h>
    37 #include <stdlib.h>
    36 #include <stdlib.h>
   222   ts.tv_nsec = (long int)((total_sec - ts.tv_sec)*1e9);
   221   ts.tv_nsec = (long int)((total_sec - ts.tv_sec)*1e9);
   223 
   222 
   224   return ts;
   223   return ts;
   225 }
   224 }
   226 
   225 
   227 #ifdef __MINGW32__
   226 #define EPOCH_YEAR 1970
   228 #define TIMEGM mktime
   227 #define SECONDS_PER_HOUR (60 * 60)
   229 #else
   228 #define SECONDS_PER_DAY (24 * SECONDS_PER_HOUR)
   230 #define TIMEGM timegm
   229 #define __isleap(year) \
   231 #endif
   230   ((year) % 4 == 0 && ((year) % 100 != 0 || (year) % 400 == 0))
       
   231 static const unsigned short int __mon_yday[2][13] =
       
   232 {
       
   233   /* Normal years.  */
       
   234   { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365},
       
   235   /* Leap years.  */
       
   236   { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366}
       
   237 };
       
   238 
       
   239 typedef struct {
       
   240 	int tm_sec;			/* Seconds.	[0-60] (1 leap second) */
       
   241 	int tm_min;			/* Minutes.	[0-59] */
       
   242 	int tm_hour;		/* Hours.	[0-23] */
       
   243 	int tm_day;			/* Day.		[1-31] */
       
   244 	int tm_mon;			/* Month.	[0-11] */
       
   245 	int tm_year;		/* Year	*/
       
   246 } tm;
       
   247 
       
   248 static inline tm convert_seconds_to_date_and_time(long int seconds) {
       
   249   tm dt;
       
   250   long int days, rem;
       
   251   days = seconds / SECONDS_PER_DAY;
       
   252   rem = seconds % SECONDS_PER_DAY;
       
   253   if (rem < 0) {
       
   254 	  rem += SECONDS_PER_DAY;
       
   255 	  days--;
       
   256   }
       
   257 
       
   258   // time of day
       
   259   dt.tm_hour = rem / SECONDS_PER_HOUR;
       
   260   rem %= SECONDS_PER_HOUR;
       
   261   dt.tm_min = rem / 60;
       
   262   dt.tm_sec = rem % 60;
       
   263 
       
   264   // date
       
   265   dt.tm_year = EPOCH_YEAR;
       
   266   while (days >= (rem = __isleap(dt.tm_year) ? 366 : 365)) {
       
   267 	  dt.tm_year++;
       
   268 	  days -= rem;
       
   269   }
       
   270   while (days < 0) {
       
   271 	  dt.tm_year--;
       
   272 	  days += __isleap(dt.tm_year) ? 366 : 365;
       
   273   }
       
   274   dt.tm_mon = 1;
       
   275   while (days > __mon_yday[__isleap(dt.tm_year)][dt.tm_mon]) {
       
   276 	  dt.tm_mon += 1;
       
   277   }
       
   278   dt.tm_day = days - __mon_yday[__isleap(dt.tm_year)][dt.tm_mon - 1] + 1;
       
   279 
       
   280   return dt;
       
   281 }
   232 
   282 
   233 static inline IEC_TIMESPEC __date_to_timespec(int day, int month, int year) {
   283 static inline IEC_TIMESPEC __date_to_timespec(int day, int month, int year) {
   234   IEC_TIMESPEC ts;
   284   IEC_TIMESPEC ts;
   235   struct tm broken_down_time;
   285   int a4, b4, a100, b100, a400, b400;
   236   time_t epoch_seconds;
   286   int yday;
   237 
   287   int intervening_leap_days;
   238   broken_down_time.tm_sec = 0;
   288 
   239   broken_down_time.tm_min = 0;
   289   if (month < 1 || month > 12)
   240   broken_down_time.tm_hour = 0;
   290 	 __iec_error();
   241   broken_down_time.tm_mday = day;  /* day of month, from 1 to 31 */
   291 
   242   broken_down_time.tm_mon = month - 1;   /* month since January, in the range 0 to 11 */
   292   yday = __mon_yday[__isleap(year)][month - 1] + day;
   243   broken_down_time.tm_year = year - 1900;  /* number of years since 1900 */
   293 
   244   broken_down_time.tm_isdst = -1; /* disable daylight savings time */
   294   if (yday > __mon_yday[__isleap(year)][month])
       
   295 	  __iec_error();
       
   296 
       
   297   a4 = (year >> 2) - ! (year & 3);
       
   298   b4 = (EPOCH_YEAR >> 2) - ! (EPOCH_YEAR & 3);
       
   299   a100 = a4 / 25 - (a4 % 25 < 0);
       
   300   b100 = b4 / 25 - (b4 % 25 < 0);
       
   301   a400 = a100 >> 2;
       
   302   b400 = b100 >> 2;
       
   303   intervening_leap_days = (a4 - b4) - (a100 - b100) + (a400 - b400);
   245   
   304   
   246   epoch_seconds = TIMEGM(&broken_down_time); /* determine number of seconds since the epoch, i.e. Jan 1st 1970 */
   305   ts.tv_sec = ((year - EPOCH_YEAR) * 365 + intervening_leap_days + yday - 1) * 24 * 60 * 60;
   247 
       
   248   if ((time_t)(-1) == epoch_seconds)
       
   249     __iec_error();
       
   250 
       
   251   ts.tv_sec = epoch_seconds;
       
   252   ts.tv_nsec = 0;
   306   ts.tv_nsec = 0;
   253 
   307 
   254   return ts;
   308   return ts;
   255 }
   309 }
   256 
   310 
   514     if(res.len > STR_MAX_LEN) res.len = STR_MAX_LEN;
   568     if(res.len > STR_MAX_LEN) res.len = STR_MAX_LEN;
   515     return res;
   569     return res;
   516 }
   570 }
   517 static inline STRING __date_to_string(DATE IN){
   571 static inline STRING __date_to_string(DATE IN){
   518     STRING res;
   572     STRING res;
   519     struct tm* broken_down_time;
   573     tm broken_down_time;
   520     time_t seconds;
       
   521     /* D#1984-06-25 */
   574     /* D#1984-06-25 */
       
   575     broken_down_time = convert_seconds_to_date_and_time(IN.tv_sec);
   522     res = __INIT_STRING;
   576     res = __INIT_STRING;
   523     seconds = IN.tv_sec;
   577     res.len = snprintf((char*)&res.body, STR_MAX_LEN, "D#%d-%2.2d-%2.2d",
   524     if (NULL == (broken_down_time = gmtime(&seconds))){ /* get the UTC (GMT) broken down time */
   578              broken_down_time.tm_year,
   525         __iec_error();
   579              broken_down_time.tm_mon,
   526         return (STRING){7,"D#ERROR"};
   580              broken_down_time.tm_day);
   527     }
       
   528     res.len = snprintf((char*)&res.body, STR_MAX_LEN, "D#%d-%2.2d-%2.2d", broken_down_time->tm_year + 1900, broken_down_time->tm_mon + 1, broken_down_time->tm_mday);
       
   529     if(res.len > STR_MAX_LEN) res.len = STR_MAX_LEN;
   581     if(res.len > STR_MAX_LEN) res.len = STR_MAX_LEN;
   530     return res;
   582     return res;
   531 }
   583 }
   532 static inline STRING __tod_to_string(TOD IN){
   584 static inline STRING __tod_to_string(TOD IN){
   533     STRING res;
   585     STRING res;
   534     struct tm* broken_down_time;
   586     tm broken_down_time;
   535     time_t seconds;
   587     time_t seconds;
   536     /* TOD#15:36:55.36 */
   588     /* TOD#15:36:55.36 */
       
   589     seconds = IN.tv_sec;
       
   590     if (seconds >= SECONDS_PER_DAY){
       
   591 		__iec_error();
       
   592 		return (STRING){9,"TOD#ERROR"};
       
   593 	}
       
   594     broken_down_time = convert_seconds_to_date_and_time(seconds);
   537     res = __INIT_STRING;
   595     res = __INIT_STRING;
   538     seconds = IN.tv_sec;
       
   539     if (NULL == (broken_down_time = gmtime(&seconds))){ /* get the UTC (GMT) broken down time */
       
   540         __iec_error();
       
   541         return (STRING){9,"TOD#ERROR"};
       
   542     }
       
   543     if(IN.tv_nsec == 0){
   596     if(IN.tv_nsec == 0){
   544         res.len = snprintf((char*)&res.body, STR_MAX_LEN, "TOD#%2.2d:%2.2d:%2.2d", broken_down_time->tm_hour, broken_down_time->tm_min, broken_down_time->tm_sec);
   597         res.len = snprintf((char*)&res.body, STR_MAX_LEN, "TOD#%2.2d:%2.2d:%2.2d",
       
   598                  broken_down_time.tm_hour,
       
   599                  broken_down_time.tm_min,
       
   600                  broken_down_time.tm_sec);
   545     }else{
   601     }else{
   546         res.len = snprintf((char*)&res.body, STR_MAX_LEN, "TOD#%2.2d:%2.2d:%09.6g", broken_down_time->tm_hour, broken_down_time->tm_min, (LREAL)broken_down_time->tm_sec + (LREAL)IN.tv_nsec / 1e9);
   602         res.len = snprintf((char*)&res.body, STR_MAX_LEN, "TOD#%2.2d:%2.2d:%09.6g",
       
   603                  broken_down_time.tm_hour,
       
   604                  broken_down_time.tm_min,
       
   605                  (LREAL)broken_down_time.tm_sec + (LREAL)IN.tv_nsec / 1e9);
   547     }
   606     }
   548     if(res.len > STR_MAX_LEN) res.len = STR_MAX_LEN;
   607     if(res.len > STR_MAX_LEN) res.len = STR_MAX_LEN;
   549     return res;
   608     return res;
   550 }
   609 }
   551 static inline STRING __dt_to_string(DT IN){
   610 static inline STRING __dt_to_string(DT IN){
   552     STRING res;
   611     STRING res;
   553     struct tm* broken_down_time;
   612     tm broken_down_time;
   554     time_t seconds;
   613     time_t seconds;
   555     /* DT#1984-06-25-15:36:55.36 */
   614     /* DT#1984-06-25-15:36:55.36 */
   556     seconds = IN.tv_sec;
   615     broken_down_time = convert_seconds_to_date_and_time(IN.tv_sec);
   557     if (NULL == (broken_down_time = gmtime(&seconds))){ /* get the UTC (GMT) broken down time */
       
   558         __iec_error();
       
   559         return (STRING){8,"DT#ERROR"};
       
   560     }
       
   561     if(IN.tv_nsec == 0){
   616     if(IN.tv_nsec == 0){
   562         res.len = snprintf((char*)&res.body, STR_MAX_LEN, "DT#%d-%2.2d-%2.2d-%2.2d:%2.2d:%2.2d",
   617         res.len = snprintf((char*)&res.body, STR_MAX_LEN, "DT#%d-%2.2d-%2.2d-%2.2d:%2.2d:%2.2d",
   563                  broken_down_time->tm_year + 1900,
   618                  broken_down_time.tm_year,
   564                  broken_down_time->tm_mon  + 1,
   619                  broken_down_time.tm_mon,
   565                  broken_down_time->tm_mday,
   620                  broken_down_time.tm_day,
   566                  broken_down_time->tm_hour,
   621                  broken_down_time.tm_hour,
   567                  broken_down_time->tm_min,
   622                  broken_down_time.tm_min,
   568                  broken_down_time->tm_sec);
   623                  broken_down_time.tm_sec);
   569     }else{
   624     }else{
   570         res.len = snprintf((char*)&res.body, STR_MAX_LEN, "DT#%d-%2.2d-%2.2d-%2.2d:%2.2d:%09.6g",
   625         res.len = snprintf((char*)&res.body, STR_MAX_LEN, "DT#%d-%2.2d-%2.2d-%2.2d:%2.2d:%09.6g",
   571                  broken_down_time->tm_year + 1900,
   626                  broken_down_time.tm_year,
   572                  broken_down_time->tm_mon  + 1,
   627                  broken_down_time.tm_mon,
   573                  broken_down_time->tm_mday,
   628                  broken_down_time.tm_day,
   574                  broken_down_time->tm_hour,
   629                  broken_down_time.tm_hour,
   575                  broken_down_time->tm_min,
   630                  broken_down_time.tm_min,
   576                  (LREAL)broken_down_time->tm_sec + ((LREAL)IN.tv_nsec / 1e9));
   631                  (LREAL)broken_down_time.tm_sec + ((LREAL)IN.tv_nsec / 1e9));
   577     }
   632     }
   578     if(res.len > STR_MAX_LEN) res.len = STR_MAX_LEN;
   633     if(res.len > STR_MAX_LEN) res.len = STR_MAX_LEN;
   579     return res;
   634     return res;
   580 }
   635 }
   581 
   636