| 
									
										
										
										
											2013-01-16 12:28:37 +00:00
										 |  |  | /*  Part of SWI-Prolog
 | 
					
						
							| 
									
										
										
										
											2010-07-19 14:52:26 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     Author:        Jan Wielemaker | 
					
						
							| 
									
										
										
										
											2011-03-09 13:05:03 +00:00
										 |  |  |     E-mail:        J.Wielemaker@cs.vu.nl | 
					
						
							| 
									
										
										
										
											2010-07-19 14:52:26 +01:00
										 |  |  |     WWW:           http://www.swi-prolog.org
 | 
					
						
							| 
									
										
										
										
											2013-01-16 12:28:37 +00:00
										 |  |  |     Copyright (C): 1985-2012, University of Amsterdam | 
					
						
							| 
									
										
										
										
											2011-03-09 13:05:03 +00:00
										 |  |  | 			      VU University Amsterdam | 
					
						
							| 
									
										
										
										
											2010-07-19 14:52:26 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     This library is free software; you can redistribute it and/or | 
					
						
							|  |  |  |     modify it under the terms of the GNU Lesser General Public | 
					
						
							|  |  |  |     License as published by the Free Software Foundation; either | 
					
						
							|  |  |  |     version 2.1 of the License, or (at your option) any later version. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     This library is distributed in the hope that it will be useful, | 
					
						
							|  |  |  |     but WITHOUT ANY WARRANTY; without even the implied warranty of | 
					
						
							|  |  |  |     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU | 
					
						
							|  |  |  |     Lesser General Public License for more details. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     You should have received a copy of the GNU Lesser General Public | 
					
						
							|  |  |  |     License along with this library; if not, write to the Free Software | 
					
						
							| 
									
										
										
										
											2013-01-16 12:28:37 +00:00
										 |  |  |     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA | 
					
						
							| 
									
										
										
										
											2010-07-19 14:52:26 +01:00
										 |  |  | */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-01-16 12:28:37 +00:00
										 |  |  | #define __MINGW_USE_VC2005_COMPAT		/* Get Windows time_t as 64-bit */
 | 
					
						
							| 
									
										
										
										
											2010-07-19 14:52:26 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | #include "pl-incl.h"
 | 
					
						
							| 
									
										
										
										
											2013-11-15 01:10:25 +00:00
										 |  |  | #include <math.h>
 | 
					
						
							| 
									
										
										
										
											2010-07-19 14:52:26 +01:00
										 |  |  | #include "libtai/taia.h"
 | 
					
						
							|  |  |  | #include "libtai/caltime.h"
 | 
					
						
							|  |  |  | #include <stdio.h>
 | 
					
						
							|  |  |  | #include <ctype.h>
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-03-09 13:05:03 +00:00
										 |  |  | #if TIME_WITH_SYS_TIME
 | 
					
						
							|  |  |  | # include <sys/time.h>
 | 
					
						
							|  |  |  | # include <time.h>
 | 
					
						
							|  |  |  | #else
 | 
					
						
							|  |  |  | # if HAVE_SYS_TIME_H
 | 
					
						
							|  |  |  | #  include <sys/time.h>
 | 
					
						
							|  |  |  | # else
 | 
					
						
							|  |  |  | #  include <time.h>
 | 
					
						
							|  |  |  | # endif
 | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #if defined(__WINDOWS__) || defined (__CYGWIN__)
 | 
					
						
							| 
									
										
										
										
											2010-07-19 14:52:26 +01:00
										 |  |  | #define timezone _timezone
 | 
					
						
							| 
									
										
										
										
											2011-03-09 13:05:03 +00:00
										 |  |  | #ifndef HAVE_VAR_TIMEZONE
 | 
					
						
							|  |  |  | #define HAVE_VAR_TIMEZONE
 | 
					
						
							| 
									
										
										
										
											2010-07-20 13:42:35 +01:00
										 |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2010-07-19 14:52:26 +01:00
										 |  |  | #else
 | 
					
						
							|  |  |  | extern char *tzname[2]; | 
					
						
							|  |  |  | #ifdef HAVE_VAR_TIMEZONE
 | 
					
						
							|  |  |  | extern long timezone; | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #define TAI_UTC_OFFSET LL(4611686018427387914)
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 | 
					
						
							|  |  |  | struct ftm is a `floating' version of the system struct tm. | 
					
						
							|  |  |  | - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #define		HAS_STAMP	0x0001
 | 
					
						
							|  |  |  | #define		HAS_WYDAY	0x0002
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-01-16 12:28:37 +00:00
										 |  |  | #define		NO_UTC_OFFSET	0x7fffffff
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-07-19 14:52:26 +01:00
										 |  |  | typedef struct ftm | 
					
						
							|  |  |  | { struct	tm tm;			/* System time structure */ | 
					
						
							|  |  |  |   double	sec;			/* float version of tm.tm_sec */ | 
					
						
							|  |  |  |   int		utcoff;			/* offset to UTC (seconds) */ | 
					
						
							|  |  |  |   atom_t	tzname;			/* Name of timezone */ | 
					
						
							|  |  |  |   int		isdst;			/* Daylight saving time */ | 
					
						
							|  |  |  |   double	stamp;			/* Time stamp (sec since 1970-1-1) */ | 
					
						
							|  |  |  |   int		flags;			/* Filled fields */ | 
					
						
							|  |  |  | } ftm; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 | 
					
						
							|  |  |  | tz_offset() returns the offset from UTC in seconds. | 
					
						
							|  |  |  | - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void | 
					
						
							| 
									
										
										
										
											2011-07-09 09:15:52 -07:00
										 |  |  | do_tzset(void) | 
					
						
							| 
									
										
										
										
											2010-07-19 14:52:26 +01:00
										 |  |  | { static int done = FALSE; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if ( !done ) | 
					
						
							|  |  |  |   { tzset(); | 
					
						
							|  |  |  |     done = TRUE; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 | 
					
						
							|  |  |  | POSIX provides the variable  timezone,  providing   the  offset  of  the | 
					
						
							|  |  |  | current timezone WEST of GMT in seconds.   Some systems (FreeBSD) do not | 
					
						
							|  |  |  | provide that. Instead thet provide  tm_gmtoff   in  struct  tm, but this | 
					
						
							|  |  |  | value is EAST and includes the DST offset. | 
					
						
							|  |  |  | - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int | 
					
						
							| 
									
										
										
										
											2011-07-09 09:15:52 -07:00
										 |  |  | tz_offset(void) | 
					
						
							| 
									
										
										
										
											2010-07-19 14:52:26 +01:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2011-03-09 13:05:03 +00:00
										 |  |  | #ifdef HAVE_VAR_TIMEZONE
 | 
					
						
							| 
									
										
										
										
											2010-07-19 14:52:26 +01:00
										 |  |  |   do_tzset(); | 
					
						
							|  |  |  |   return timezone; | 
					
						
							|  |  |  | #else
 | 
					
						
							|  |  |  | #ifdef HAVE_STRUCT_TIME_TM_GMTOFF
 | 
					
						
							|  |  |  |   static int offset = -1; | 
					
						
							|  |  |  |   if ( offset == -1 ) | 
					
						
							|  |  |  |   { time_t t = time(NULL); | 
					
						
							|  |  |  |     struct tm tm; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-01-16 12:28:37 +00:00
										 |  |  |     PL_localtime_r(&t, &tm); | 
					
						
							| 
									
										
										
										
											2010-07-19 14:52:26 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     offset = -tm.tm_gmtoff; | 
					
						
							|  |  |  |     if ( tm.tm_isdst > 0 ) | 
					
						
							|  |  |  |       offset += 3600; | 
					
						
							|  |  |  |   /*Use to verify on systems where we know both.  In Western Europe the
 | 
					
						
							|  |  |  |     offset must be -3600, both in winter and summer.*/ | 
					
						
							|  |  |  |   /*Sdprintf("timezone offset = %d (must be %d)\n", offset, timezone);*/ | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   return offset; | 
					
						
							|  |  |  | #else
 | 
					
						
							|  |  |  | #error "Do not know how to get timezone info"
 | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static char * | 
					
						
							|  |  |  | tz_name(int dst) | 
					
						
							|  |  |  | { dst = (dst != 0); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   do_tzset(); | 
					
						
							|  |  |  |   return tzname[dst]; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static atom_t | 
					
						
							|  |  |  | tz_name_as_atom(int dst) | 
					
						
							|  |  |  | { static atom_t a[2]; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-01-16 12:28:37 +00:00
										 |  |  |   dst = (dst > 0);			/* 0 or 1 */ | 
					
						
							| 
									
										
										
										
											2010-07-19 14:52:26 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |   if ( !a[dst] ) | 
					
						
							|  |  |  |   { wchar_t wbuf[256]; | 
					
						
							|  |  |  |     const char *str = tz_name(dst); | 
					
						
							|  |  |  |     size_t n; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if ( (n = mbstowcs(wbuf, str, sizeof(wbuf)/sizeof(wbuf[0])-1)) != (size_t)-1 ) | 
					
						
							|  |  |  |     { a[dst] = PL_new_atom_wchars(n, wbuf); | 
					
						
							|  |  |  |     } else | 
					
						
							|  |  |  |     { a[dst] = PL_new_atom(str); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   return a[dst]; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 | 
					
						
							|  |  |  | unify_taia(): Unify a TAIA date as a Prolog double using the POSIX 1970 | 
					
						
							|  |  |  | origin; | 
					
						
							|  |  |  | - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  | static int | 
					
						
							|  |  |  | unify_taia(term_t t, struct taia *taia) | 
					
						
							|  |  |  | { double d = (double)((int64_t)taia->sec.x - TAI_UTC_OFFSET); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   d += taia->nano / 1e9; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   return PL_unify_float(t, d); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int | 
					
						
							|  |  |  | get_taia(term_t t, struct taia *taia, double *seconds) | 
					
						
							|  |  |  | { double d; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if ( PL_get_float(t, &d) ) | 
					
						
							|  |  |  |   { double fp, ip; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if ( seconds ) | 
					
						
							|  |  |  |       *seconds = d; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     fp = modf(d, &ip); | 
					
						
							|  |  |  |     if ( fp < 0 ) | 
					
						
							|  |  |  |     { fp += 1.0; | 
					
						
							|  |  |  |       ip -= 1.0; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     taia->sec.x = (int64_t)ip + TAI_UTC_OFFSET; | 
					
						
							|  |  |  |     taia->nano  = (long)(fp*1e9); | 
					
						
							|  |  |  |     taia->atto  = 0L; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return TRUE; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   return FALSE; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int | 
					
						
							|  |  |  | get_tz_arg(int i, term_t t, term_t a, atom_t *tz) | 
					
						
							|  |  |  | { GET_LD | 
					
						
							|  |  |  |   atom_t name; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   _PL_get_arg(i, t, a); | 
					
						
							| 
									
										
										
										
											2013-01-16 12:28:37 +00:00
										 |  |  |   if ( !PL_is_variable(a) ) | 
					
						
							|  |  |  |   { if ( !PL_get_atom_ex(a, &name) ) | 
					
						
							|  |  |  |       fail; | 
					
						
							|  |  |  |     if ( name != ATOM_minus ) | 
					
						
							|  |  |  |       *tz = name; | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2010-07-19 14:52:26 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |   succeed; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int | 
					
						
							|  |  |  | get_int_arg(int i, term_t t, term_t a, int *val) | 
					
						
							|  |  |  | { GET_LD | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   _PL_get_arg(i, t, a); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   return PL_get_integer_ex(a, val); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-01-16 12:28:37 +00:00
										 |  |  | static int | 
					
						
							|  |  |  | get_voff_arg(int i, term_t t, term_t a, int *val) | 
					
						
							|  |  |  | { GET_LD | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   _PL_get_arg(i, t, a); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if ( PL_is_variable(a) ) | 
					
						
							|  |  |  |   { *val = NO_UTC_OFFSET; | 
					
						
							|  |  |  |     return TRUE; | 
					
						
							|  |  |  |   } else | 
					
						
							|  |  |  |   { return PL_get_integer_ex(a, val); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-07-19 14:52:26 +01:00
										 |  |  | static int | 
					
						
							|  |  |  | get_float_arg(int i, term_t t, term_t a, double *val) | 
					
						
							|  |  |  | { GET_LD | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   _PL_get_arg(i, t, a); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   return PL_get_float_ex(a, val); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int | 
					
						
							| 
									
										
										
										
											2013-01-16 12:28:37 +00:00
										 |  |  | get_dst_arg(int i, term_t t, term_t a, int *val) | 
					
						
							| 
									
										
										
										
											2010-07-19 14:52:26 +01:00
										 |  |  | { GET_LD | 
					
						
							|  |  |  |   atom_t name; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   _PL_get_arg(i, t, a); | 
					
						
							|  |  |  |   if ( PL_get_atom(a, &name) ) | 
					
						
							|  |  |  |   { if ( name == ATOM_true ) | 
					
						
							|  |  |  |     { *val = TRUE; | 
					
						
							|  |  |  |       return TRUE; | 
					
						
							| 
									
										
										
										
											2013-01-16 12:28:37 +00:00
										 |  |  |     } else if ( name == ATOM_false ) | 
					
						
							| 
									
										
										
										
											2010-07-19 14:52:26 +01:00
										 |  |  |     { *val = FALSE; | 
					
						
							|  |  |  |       return TRUE; | 
					
						
							| 
									
										
										
										
											2013-01-16 12:28:37 +00:00
										 |  |  |     } else if ( name == ATOM_minus ) | 
					
						
							|  |  |  |     { *val = -1; | 
					
						
							|  |  |  |       return TRUE; | 
					
						
							| 
									
										
										
										
											2010-07-19 14:52:26 +01:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2013-01-16 12:28:37 +00:00
										 |  |  |   } else if ( PL_is_variable(a) ) | 
					
						
							|  |  |  |   { *val = -2; | 
					
						
							|  |  |  |     return TRUE; | 
					
						
							| 
									
										
										
										
											2010-07-19 14:52:26 +01:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   return PL_get_bool_ex(a, val);	/* generate an error */ | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int | 
					
						
							|  |  |  | get_ftm(term_t t, ftm *ftm) | 
					
						
							|  |  |  | { GET_LD | 
					
						
							| 
									
										
										
										
											2013-01-16 12:28:37 +00:00
										 |  |  |   term_t tmp = PL_new_term_ref(); | 
					
						
							|  |  |  |   int date9; | 
					
						
							| 
									
										
										
										
											2010-07-19 14:52:26 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-01-16 12:28:37 +00:00
										 |  |  |   memset(ftm, 0, sizeof(*ftm)); | 
					
						
							| 
									
										
										
										
											2010-07-19 14:52:26 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-01-16 12:28:37 +00:00
										 |  |  |   if ( (date9=PL_is_functor(t, FUNCTOR_date9)) ) | 
					
						
							|  |  |  |   { if ( get_int_arg  (1, t, tmp, &ftm->tm.tm_year) && | 
					
						
							| 
									
										
										
										
											2010-07-19 14:52:26 +01:00
										 |  |  | 	 get_int_arg  (2, t, tmp, &ftm->tm.tm_mon)  && | 
					
						
							|  |  |  | 	 get_int_arg  (3, t, tmp, &ftm->tm.tm_mday) && | 
					
						
							|  |  |  | 	 get_int_arg  (4, t, tmp, &ftm->tm.tm_hour) && | 
					
						
							|  |  |  | 	 get_int_arg  (5, t, tmp, &ftm->tm.tm_min)  && | 
					
						
							|  |  |  | 	 get_float_arg(6, t, tmp, &ftm->sec)	    && | 
					
						
							| 
									
										
										
										
											2013-01-16 12:28:37 +00:00
										 |  |  | 	 get_voff_arg (7, t, tmp, &ftm->utcoff)     && | 
					
						
							| 
									
										
										
										
											2010-07-19 14:52:26 +01:00
										 |  |  | 	 get_tz_arg   (8, t, tmp, &ftm->tzname)     && | 
					
						
							| 
									
										
										
										
											2013-01-16 12:28:37 +00:00
										 |  |  | 	 get_dst_arg  (9, t, tmp, &ftm->isdst) ) | 
					
						
							| 
									
										
										
										
											2010-07-19 14:52:26 +01:00
										 |  |  |     { double fp, ip; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-01-16 12:28:37 +00:00
										 |  |  |       ftm->tm.tm_isdst = (ftm->isdst == -2 ? -1 : ftm->isdst); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-07-19 14:52:26 +01:00
										 |  |  |     fixup: | 
					
						
							|  |  |  |       fp = modf(ftm->sec, &ip); | 
					
						
							|  |  |  |       if ( fp < 0.0 ) | 
					
						
							|  |  |  |       { fp += 1.0; | 
					
						
							|  |  |  | 	ip -= 1.0; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       ftm->tm.tm_sec = (int)ip; | 
					
						
							|  |  |  |       ftm->tm.tm_year -= 1900;		/* 1900 based */ | 
					
						
							|  |  |  |       ftm->tm.tm_mon--;			/* 0-based */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-01-16 12:28:37 +00:00
										 |  |  |       if ( ftm->utcoff == NO_UTC_OFFSET ) | 
					
						
							|  |  |  |       { if ( ftm->tm.tm_isdst < 0 )	/* unknown DST */ | 
					
						
							|  |  |  | 	{ int offset; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	  if ( mktime(&ftm->tm) == (time_t)-1 ) | 
					
						
							|  |  |  | 	    return PL_representation_error("dst"); | 
					
						
							|  |  |  | 	  ftm->flags |= HAS_WYDAY; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	  offset = tz_offset(); | 
					
						
							|  |  |  | 	  if ( ftm->tm.tm_isdst > 0 ) | 
					
						
							|  |  |  | 	    offset -= 3600; | 
					
						
							|  |  |  | 	  ftm->utcoff = offset; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	  if ( date9 ) /* variable */ | 
					
						
							|  |  |  | 	  { _PL_get_arg(7, t, tmp); | 
					
						
							|  |  |  | 	    if ( !PL_unify_integer(tmp, ftm->utcoff) ) | 
					
						
							|  |  |  | 	      return FALSE; | 
					
						
							|  |  |  | 	  } else | 
					
						
							|  |  |  | 	  { ftm->utcoff = offset; | 
					
						
							|  |  |  | 	  } | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if ( ftm->isdst == -2 ) | 
					
						
							|  |  |  | 	{ ftm->isdst = ftm->tm.tm_isdst; | 
					
						
							|  |  |  | 	  _PL_get_arg(9, t, tmp); | 
					
						
							|  |  |  | 	  if ( ftm->isdst < 0 ) | 
					
						
							|  |  |  | 	  { if ( !PL_unify_atom(tmp, ATOM_minus) ) | 
					
						
							|  |  |  | 	      return FALSE; | 
					
						
							|  |  |  | 	  } else | 
					
						
							|  |  |  | 	  { if ( !PL_unify_bool(tmp, ftm->isdst) ) | 
					
						
							|  |  |  | 	      return FALSE; | 
					
						
							|  |  |  | 	  } | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if ( !ftm->tzname ) | 
					
						
							|  |  |  | 	{ ftm->tzname = tz_name_as_atom(ftm->isdst); | 
					
						
							|  |  |  | 	  _PL_get_arg(8, t, tmp); | 
					
						
							|  |  |  | 	  if ( PL_is_variable(tmp) && | 
					
						
							|  |  |  | 	       !PL_unify_atom(tmp, ftm->tzname) ) | 
					
						
							|  |  |  | 	    return FALSE; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-07-19 14:52:26 +01:00
										 |  |  |       succeed; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } else if ( PL_is_functor(t, FUNCTOR_date3) ) | 
					
						
							| 
									
										
										
										
											2013-01-16 12:28:37 +00:00
										 |  |  |   { if ( get_int_arg  (1, t, tmp, &ftm->tm.tm_year) && | 
					
						
							| 
									
										
										
										
											2010-07-19 14:52:26 +01:00
										 |  |  | 	 get_int_arg  (2, t, tmp, &ftm->tm.tm_mon)  && | 
					
						
							|  |  |  | 	 get_int_arg  (3, t, tmp, &ftm->tm.tm_mday) ) | 
					
						
							| 
									
										
										
										
											2013-01-16 12:28:37 +00:00
										 |  |  |     { ftm->tm.tm_isdst = -1; | 
					
						
							|  |  |  |       ftm->utcoff = NO_UTC_OFFSET; | 
					
						
							| 
									
										
										
										
											2010-07-19 14:52:26 +01:00
										 |  |  |       goto fixup; | 
					
						
							| 
									
										
										
										
											2013-01-16 12:28:37 +00:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2010-07-19 14:52:26 +01:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-01-16 12:28:37 +00:00
										 |  |  |   return PL_error(NULL, 0, NULL, ERR_TYPE, ATOM_time, t); | 
					
						
							| 
									
										
										
										
											2010-07-19 14:52:26 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /** void cal_ftm(ftm *ftm, int required)
 | 
					
						
							|  |  |  |     compute missing fields from fmt | 
					
						
							|  |  |  | */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-07-09 09:15:52 -07:00
										 |  |  | static void | 
					
						
							| 
									
										
										
										
											2010-07-19 14:52:26 +01:00
										 |  |  | cal_ftm(ftm *ftm, int required) | 
					
						
							|  |  |  | { int missing = ftm->flags^required; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if ( missing )			/* we need something, so we always */ | 
					
						
							|  |  |  |   { struct caltime ct;			/* need the stamp */ | 
					
						
							|  |  |  |     struct tai tai; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     ct.date.year  = ftm->tm.tm_year+1900; | 
					
						
							|  |  |  |     ct.date.month = ftm->tm.tm_mon+1; | 
					
						
							|  |  |  |     ct.date.day   = ftm->tm.tm_mday; | 
					
						
							|  |  |  |     ct.hour       = ftm->tm.tm_hour; | 
					
						
							|  |  |  |     ct.minute     = ftm->tm.tm_min; | 
					
						
							|  |  |  |     ct.second     = ftm->tm.tm_sec; | 
					
						
							|  |  |  |     ct.offset     = -ftm->utcoff / 60;	/* TBD: make libtai speak seconds */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     caltime_tai(&ct, &tai); | 
					
						
							|  |  |  |     ftm->stamp  = (double)((int64_t)tai.x - TAI_UTC_OFFSET); | 
					
						
							|  |  |  |     ftm->stamp -= (double)ct.second; | 
					
						
							|  |  |  |     ftm->stamp += ftm->sec; | 
					
						
							|  |  |  |     ftm->flags |= HAS_STAMP; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if ( missing & HAS_WYDAY ) | 
					
						
							|  |  |  |     { caltime_utc(&ct, &tai, &ftm->tm.tm_wday, &ftm->tm.tm_yday); | 
					
						
							|  |  |  |       ftm->flags |= HAS_WYDAY; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static | 
					
						
							|  |  |  | PRED_IMPL("stamp_date_time", 3, stamp_date_time, 0) | 
					
						
							|  |  |  | { PRED_LD | 
					
						
							|  |  |  |   struct taia taia; | 
					
						
							|  |  |  |   term_t compound = A2; | 
					
						
							|  |  |  |   double argsec; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if ( get_taia(A1, &taia, &argsec) ) | 
					
						
							|  |  |  |   { struct caltime ct; | 
					
						
							|  |  |  |     int weekday, yearday; | 
					
						
							|  |  |  |     double sec; | 
					
						
							|  |  |  |     int utcoffset; | 
					
						
							|  |  |  |     int done = FALSE; | 
					
						
							|  |  |  |     atom_t alocal; | 
					
						
							|  |  |  |     atom_t tzatom = ATOM_minus; | 
					
						
							|  |  |  |     atom_t dstatom = ATOM_minus; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if ( PL_get_atom(A3, &alocal) ) | 
					
						
							|  |  |  |     { if ( alocal == ATOM_local ) | 
					
						
							|  |  |  |       { time_t unixt; | 
					
						
							|  |  |  | 	int64_t ut64; | 
					
						
							|  |  |  | 	struct tm tm; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	utcoffset = tz_offset(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ut64 = taia.sec.x - TAI_UTC_OFFSET; | 
					
						
							|  |  |  | 	unixt = (time_t) ut64; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if ( (int64_t)unixt == ut64 ) | 
					
						
							|  |  |  | 	{ double ip; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-01-16 12:28:37 +00:00
										 |  |  | 	  PL_localtime_r(&unixt, &tm); | 
					
						
							| 
									
										
										
										
											2010-07-19 14:52:26 +01:00
										 |  |  | 	  sec = (double)tm.tm_sec + modf(argsec, &ip); | 
					
						
							|  |  |  | 	  ct.date.year  = tm.tm_year+1900; | 
					
						
							|  |  |  | 	  ct.date.month = tm.tm_mon+1; | 
					
						
							|  |  |  | 	  ct.date.day   = tm.tm_mday; | 
					
						
							|  |  |  | 	  ct.hour       = tm.tm_hour; | 
					
						
							|  |  |  | 	  ct.minute     = tm.tm_min; | 
					
						
							|  |  |  | 	  tzatom = tz_name_as_atom(tm.tm_isdst); | 
					
						
							|  |  |  | 	  if ( tm.tm_isdst > 0 ) | 
					
						
							|  |  |  | 	  { utcoffset -= 3600; | 
					
						
							|  |  |  | 	    dstatom    = ATOM_true; | 
					
						
							|  |  |  | 	  } else | 
					
						
							|  |  |  | 	  { dstatom    = ATOM_false; | 
					
						
							|  |  |  | 	  } | 
					
						
							|  |  |  | 	  done = TRUE; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  |       } else if ( alocal == ATOM_utc ) | 
					
						
							|  |  |  |       { utcoffset = 0; | 
					
						
							|  |  |  | 	tzatom = alocal; | 
					
						
							|  |  |  |       } else | 
					
						
							|  |  |  |       { return PL_error(NULL, 0, NULL, ERR_DOMAIN, ATOM_timezone, A3); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     } else if ( !PL_get_integer_ex(A3, &utcoffset) ) | 
					
						
							|  |  |  |     { fail; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if ( !done ) | 
					
						
							|  |  |  |     { taia.sec.x -= utcoffset; | 
					
						
							|  |  |  |       caltime_utc(&ct, &taia.sec, &weekday, &yearday); | 
					
						
							|  |  |  |       sec = (double)ct.second+(double)taia.nano/1e9; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return PL_unify_term(compound, | 
					
						
							|  |  |  | 			 PL_FUNCTOR, FUNCTOR_date9, | 
					
						
							|  |  |  | 			   PL_LONG,  ct.date.year, | 
					
						
							|  |  |  | 			   PL_INT,   ct.date.month, | 
					
						
							|  |  |  | 			   PL_INT,   ct.date.day, | 
					
						
							|  |  |  | 			   PL_INT,   ct.hour, | 
					
						
							|  |  |  | 			   PL_INT,   ct.minute, | 
					
						
							|  |  |  | 			   PL_FLOAT, sec, | 
					
						
							|  |  |  | 			   PL_INT,   utcoffset, | 
					
						
							|  |  |  | 			   PL_ATOM,  tzatom, | 
					
						
							|  |  |  | 			   PL_ATOM,  dstatom); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 					/* time_stamp */ | 
					
						
							|  |  |  |   return PL_error(NULL, 0, NULL, ERR_TYPE, ATOM_float, A1); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static | 
					
						
							|  |  |  | PRED_IMPL("date_time_stamp", 2, date_time_stamp, 0) | 
					
						
							|  |  |  | { ftm ftm; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if ( !get_ftm(A1, &ftm) ) | 
					
						
							|  |  |  |     fail; | 
					
						
							|  |  |  |   cal_ftm(&ftm, HAS_STAMP); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   return PL_unify_float(A2, ftm.stamp); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		 /*******************************
 | 
					
						
							|  |  |  | 		 *	  GLIBC FUNCTIONS	* | 
					
						
							|  |  |  | 		 *******************************/ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 | 
					
						
							|  |  |  | These functions support strftime() %g, %G and   %V.  Code is copied from | 
					
						
							|  |  |  | glibc 2.3.5. As Glibc is LGPL, there are no license issues. | 
					
						
							|  |  |  | - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #ifndef __isleap
 | 
					
						
							|  |  |  | /* Nonzero if YEAR is a leap year (every 4 years,
 | 
					
						
							|  |  |  |    except every 100th isn't, and every 400th is).  */ | 
					
						
							|  |  |  | # define __isleap(year)	\
 | 
					
						
							|  |  |  |   ((year) % 4 == 0 && ((year) % 100 != 0 || (year) % 400 == 0)) | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* The number of days from the first day of the first ISO week of this
 | 
					
						
							|  |  |  |    year to the year day YDAY with week day WDAY.  ISO weeks start on | 
					
						
							|  |  |  |    Monday; the first ISO week has the year's first Thursday.  YDAY may | 
					
						
							|  |  |  |    be as small as YDAY_MINIMUM.  */ | 
					
						
							|  |  |  | #define ISO_WEEK_START_WDAY 1 /* Monday */
 | 
					
						
							|  |  |  | #define ISO_WEEK1_WDAY 4 /* Thursday */
 | 
					
						
							|  |  |  | #define YDAY_MINIMUM (-366)
 | 
					
						
							|  |  |  | #ifdef __GNUC__
 | 
					
						
							|  |  |  | __inline__ | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | static int | 
					
						
							|  |  |  | iso_week_days(int yday, int wday) | 
					
						
							|  |  |  | { /* Add enough to the first operand of % to make it nonnegative.  */ | 
					
						
							|  |  |  |   int big_enough_multiple_of_7 = (-YDAY_MINIMUM / 7 + 2) * 7; | 
					
						
							|  |  |  |   return (yday | 
					
						
							|  |  |  | 	  - (yday - wday + ISO_WEEK1_WDAY + big_enough_multiple_of_7) % 7 | 
					
						
							|  |  |  | 	  + ISO_WEEK1_WDAY - ISO_WEEK_START_WDAY); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		 /*******************************
 | 
					
						
							|  |  |  | 		 *	       ERRORS		* | 
					
						
							|  |  |  | 		 *******************************/ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int | 
					
						
							|  |  |  | fmt_domain_error(const char *key, int value) | 
					
						
							|  |  |  | { GET_LD | 
					
						
							|  |  |  |   term_t t = PL_new_term_ref(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   PL_put_integer(t, value); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   return PL_error(NULL, 0, NULL, ERR_DOMAIN, PL_new_atom(key), t); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int | 
					
						
							| 
									
										
										
										
											2011-03-09 13:05:03 +00:00
										 |  |  | fmt_not_implemented(int c) | 
					
						
							| 
									
										
										
										
											2010-07-19 14:52:26 +01:00
										 |  |  | { GET_LD | 
					
						
							|  |  |  |   term_t t = PL_new_term_ref(); | 
					
						
							| 
									
										
										
										
											2011-03-09 13:05:03 +00:00
										 |  |  |   char key[3]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   key[0] = '%'; | 
					
						
							|  |  |  |   key[1] = c; | 
					
						
							|  |  |  |   key[2] = 0; | 
					
						
							| 
									
										
										
										
											2010-07-19 14:52:26 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |   PL_put_atom_chars(t, key); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   return PL_error(NULL, 0, NULL, ERR_EXISTENCE, PL_new_atom("format"), t); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		 /*******************************
 | 
					
						
							|  |  |  | 		 *	    FORMATTING		* | 
					
						
							|  |  |  | 		 *******************************/ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #define OUT1DIGIT(fd, val) \
 | 
					
						
							|  |  |  | 	{ Sputcode('0'+(val)%10, fd); \ | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | #define OUT2DIGITS(fd, val) \
 | 
					
						
							|  |  |  | 	{ Sputcode('0'+((val)/10)%10, fd); \ | 
					
						
							|  |  |  | 	  Sputcode('0'+(val)%10, fd); \ | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | #define OUT3DIGITS(fd, val) \
 | 
					
						
							|  |  |  | 	{ Sputcode('0'+((val)/100)%10, fd); \ | 
					
						
							|  |  |  | 	  Sputcode('0'+((val)/10)%10, fd); \ | 
					
						
							|  |  |  | 	  Sputcode('0'+(val)%10, fd); \ | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | #define OUT2DIGITS_SPC(fd, val) \
 | 
					
						
							|  |  |  | 	{ Sputcode(((val)/10 == 0 ? ' ' : '0'+((val)/10)%10), fd); \ | 
					
						
							|  |  |  | 	  Sputcode('0'+(val)%10, fd); \ | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | #define OUTNUMBER(fd, fmt, val) \
 | 
					
						
							|  |  |  | 	{ Sfprintf(fd, fmt, val); \ | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | #define SUBFORMAT(f) \
 | 
					
						
							|  |  |  | 	{ format_time(fd, f, ftm, posix); \ | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | #define OUTCHR(fd, c) \
 | 
					
						
							| 
									
										
										
										
											2013-01-16 12:28:37 +00:00
										 |  |  | 	{ Sputcode(c, fd); \ | 
					
						
							| 
									
										
										
										
											2010-07-19 14:52:26 +01:00
										 |  |  | 	} | 
					
						
							|  |  |  | #define OUTSTR(str) \
 | 
					
						
							|  |  |  | 	{ Sfputs(str, fd); \ | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | #define OUTSTRA(str) \
 | 
					
						
							|  |  |  | 	{ foutstra(str, fd); \ | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | #define OUTATOM(a) \
 | 
					
						
							|  |  |  | 	{ writeAtomToStream(fd, a); \ | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void | 
					
						
							|  |  |  | foutstra(const char *str, IOSTREAM *fd) | 
					
						
							|  |  |  | { wchar_t wbuf[256]; | 
					
						
							|  |  |  |   size_t n; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if ( (n = mbstowcs(wbuf, str, sizeof(wbuf)/sizeof(wbuf[0])-1)) != (size_t)-1 ) | 
					
						
							|  |  |  |   { wchar_t *p; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     for(p=wbuf; n-- > 0; p++) | 
					
						
							|  |  |  |       Sputcode(*p, fd); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static const char *abbred_weekday[] = | 
					
						
							|  |  |  | { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" }; | 
					
						
							|  |  |  | static const char *weekday[] = | 
					
						
							|  |  |  | { "Sunday", "Monday", "Tuesday", "Wednesday", | 
					
						
							|  |  |  |   "Thursday", "Friday", "Saturday" }; | 
					
						
							|  |  |  | static const char *abbred_month[] = | 
					
						
							|  |  |  | { "Jan", "Feb", "Mar", "Apr", "May", "Jun", | 
					
						
							|  |  |  |   "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | static const char *month[] = | 
					
						
							|  |  |  | { "January", "February", "March", "April", "May", "June", | 
					
						
							|  |  |  |   "July", "August", "September", "October", "November", "December" | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #define NOARG (-1)
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int | 
					
						
							|  |  |  | format_time(IOSTREAM *fd, const wchar_t *format, ftm *ftm, int posix) | 
					
						
							|  |  |  | { wint_t c; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   while((c = *format++)) | 
					
						
							|  |  |  |   { int arg = NOARG; | 
					
						
							| 
									
										
										
										
											2011-03-09 13:05:03 +00:00
										 |  |  |     int altO = FALSE; | 
					
						
							| 
									
										
										
										
											2010-07-19 14:52:26 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     switch(c) | 
					
						
							|  |  |  |     { case '%': | 
					
						
							|  |  |  | 	arg = NOARG; | 
					
						
							|  |  |  |       fmt_next: | 
					
						
							|  |  |  | 	switch((c = *format++)) | 
					
						
							|  |  |  | 	{ case 'a':			/* %a: abbreviated weekday */ | 
					
						
							|  |  |  | 	  case 'A':			/* %A: weekday */ | 
					
						
							|  |  |  | 	  case 'b':			/* %b: abbreviated month */ | 
					
						
							|  |  |  | 	  case 'B':			/* %B: month */ | 
					
						
							|  |  |  | 	    if ( posix ) | 
					
						
							|  |  |  | 	    { const char *s; | 
					
						
							|  |  |  | 	      cal_ftm(ftm, HAS_STAMP|HAS_WYDAY); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	      switch( c ) | 
					
						
							|  |  |  | 	      { case 'a': | 
					
						
							|  |  |  | 		  s = abbred_weekday[ftm->tm.tm_wday]; | 
					
						
							|  |  |  | 		  break; | 
					
						
							|  |  |  | 		case 'A': | 
					
						
							|  |  |  | 		  s = weekday[ftm->tm.tm_wday]; | 
					
						
							|  |  |  | 		  break; | 
					
						
							|  |  |  | 		case 'b': | 
					
						
							|  |  |  | 		  s = abbred_month[ftm->tm.tm_mon]; | 
					
						
							|  |  |  | 		  break; | 
					
						
							|  |  |  | 		case 'B': | 
					
						
							|  |  |  | 		  s = month[ftm->tm.tm_mon]; | 
					
						
							|  |  |  | 		  break; | 
					
						
							|  |  |  | 		default: | 
					
						
							|  |  |  | 		  s = NULL; | 
					
						
							|  |  |  | 		  assert(0); | 
					
						
							|  |  |  | 	      } | 
					
						
							|  |  |  | 	      OUTSTR(s); | 
					
						
							|  |  |  | 	      break; | 
					
						
							|  |  |  | 	    } | 
					
						
							|  |  |  | 	    /*FALLTHROUGH*/ | 
					
						
							|  |  |  | 	  case 'c':			/* %c: default representation */ | 
					
						
							|  |  |  | 	  case 'p':			/* %p: AM/PM (locale) */ | 
					
						
							|  |  |  | 	  case 'P':			/* %P: am/pm (locale) */ | 
					
						
							|  |  |  | 	  case 'x':			/* %x: date in locale */ | 
					
						
							|  |  |  | 	  case 'X':			/* %X: time in locale */ | 
					
						
							|  |  |  | 	  case_b: | 
					
						
							|  |  |  | 	  { char fmt[3]; | 
					
						
							|  |  |  | 	    char buf[256]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	    fmt[0] = '%'; | 
					
						
							|  |  |  | 	    fmt[1] = (char)c; | 
					
						
							|  |  |  | 	    fmt[2] = EOS; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	    cal_ftm(ftm, HAS_STAMP|HAS_WYDAY); | 
					
						
							|  |  |  | 					/* conversion is not thread-safe under locale switch */ | 
					
						
							| 
									
										
										
										
											2013-01-16 12:28:37 +00:00
										 |  |  | 	    strftime(buf, sizeof(buf), fmt, &ftm->tm); | 
					
						
							| 
									
										
										
										
											2010-07-19 14:52:26 +01:00
										 |  |  | 	    OUTSTRA(buf); | 
					
						
							|  |  |  | 	    break; | 
					
						
							|  |  |  | 	  } | 
					
						
							|  |  |  | 	  case 'C':			/* (year/100) as a 2-digit int */ | 
					
						
							|  |  |  | 	  { int year = ftm->tm.tm_year+1900; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	    if ( year >= 0 && year < 10000 ) | 
					
						
							|  |  |  | 	    { int century = year/100; | 
					
						
							|  |  |  | 	      OUT2DIGITS(fd, century); | 
					
						
							|  |  |  | 	    } else | 
					
						
							|  |  |  | 	    { return fmt_domain_error("%C", year); | 
					
						
							|  |  |  | 	    } | 
					
						
							|  |  |  | 	    break; | 
					
						
							|  |  |  | 	  } | 
					
						
							|  |  |  | 	  case 'd':			/* day of the month */ | 
					
						
							|  |  |  | 	    OUT2DIGITS(fd, ftm->tm.tm_mday); | 
					
						
							|  |  |  | 	    break; | 
					
						
							|  |  |  | 	  case 'D':			/* %m/%d/%y */ | 
					
						
							|  |  |  | 	    SUBFORMAT(L"%m/%d/%y"); | 
					
						
							|  |  |  | 	    break; | 
					
						
							|  |  |  | 	  case 'e':			/* day of the month */ | 
					
						
							|  |  |  | 	    OUT2DIGITS_SPC(fd, ftm->tm.tm_mday); | 
					
						
							|  |  |  | 	    break; | 
					
						
							|  |  |  | 	  case 'E':			/* alternative format */ | 
					
						
							| 
									
										
										
										
											2011-03-09 13:05:03 +00:00
										 |  |  | 	    return fmt_not_implemented(c); | 
					
						
							| 
									
										
										
										
											2010-07-19 14:52:26 +01:00
										 |  |  | 	  case 'F':			/* ISO 8601 date format */ | 
					
						
							|  |  |  | 	    SUBFORMAT(L"%Y-%m-%d"); | 
					
						
							|  |  |  | 	    break; | 
					
						
							|  |  |  | 	  case 'G': | 
					
						
							|  |  |  | 	  case 'g': | 
					
						
							|  |  |  | 	  case 'V': | 
					
						
							|  |  |  | 	  { int year, days; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	    cal_ftm(ftm, HAS_STAMP|HAS_WYDAY); | 
					
						
							|  |  |  | 	    year = ftm->tm.tm_year+1900; | 
					
						
							|  |  |  | 	    days = iso_week_days(ftm->tm.tm_yday, ftm->tm.tm_wday); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	    if ( days < 0 ) | 
					
						
							|  |  |  | 	    { year--; | 
					
						
							|  |  |  | 	      days = iso_week_days(ftm->tm.tm_yday + (365 + __isleap (year)), | 
					
						
							|  |  |  | 				   ftm->tm.tm_wday); | 
					
						
							|  |  |  | 	    } else | 
					
						
							|  |  |  | 	    { int d = iso_week_days(ftm->tm.tm_yday - (365 + __isleap (year)), | 
					
						
							|  |  |  | 				    ftm->tm.tm_wday); | 
					
						
							|  |  |  | 	      if (0 <= d) | 
					
						
							|  |  |  | 	      { /* This ISO week belongs to the next year.  */ | 
					
						
							|  |  |  | 		year++; | 
					
						
							|  |  |  | 		days = d; | 
					
						
							|  |  |  | 	      } | 
					
						
							|  |  |  | 	    } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	    switch(c) | 
					
						
							|  |  |  | 	    { case 'g': | 
					
						
							|  |  |  | 		OUT2DIGITS(fd, (year % 100 + 100) % 100); | 
					
						
							|  |  |  | 		break; | 
					
						
							|  |  |  | 	      case 'G': | 
					
						
							|  |  |  | 		OUTNUMBER(fd, "%d", year); | 
					
						
							|  |  |  | 		break; | 
					
						
							|  |  |  | 	      case 'V': | 
					
						
							|  |  |  | 		OUT2DIGITS(fd, days/7+1); | 
					
						
							|  |  |  | 		break; | 
					
						
							|  |  |  | 	    } | 
					
						
							|  |  |  | 	    break; | 
					
						
							|  |  |  | 	  } | 
					
						
							|  |  |  | 	  case 'h':			/* Equivalent to %b. (SU) */ | 
					
						
							|  |  |  | 	    c = 'b'; | 
					
						
							|  |  |  | 	    goto case_b; | 
					
						
							|  |  |  | 	  case 'H':			/* 0..23 hours */ | 
					
						
							|  |  |  | 	    OUT2DIGITS(fd, ftm->tm.tm_hour); | 
					
						
							|  |  |  | 	    break; | 
					
						
							|  |  |  | 	  case 'I':			/* 01..12 hours */ | 
					
						
							|  |  |  | 	    OUT2DIGITS(fd, (ftm->tm.tm_hour)%12); | 
					
						
							|  |  |  | 	    break; | 
					
						
							|  |  |  | 	  case 'j':			/* yday (001..366) */ | 
					
						
							|  |  |  | 	    cal_ftm(ftm, HAS_WYDAY); | 
					
						
							|  |  |  | 	    OUT3DIGITS(fd, ftm->tm.tm_yday+1); | 
					
						
							|  |  |  | 	    break; | 
					
						
							|  |  |  | 	  case 'k':			/* 0..23 hours (leading space) */ | 
					
						
							|  |  |  | 	    OUT2DIGITS_SPC(fd, ftm->tm.tm_hour); | 
					
						
							|  |  |  | 	    break; | 
					
						
							|  |  |  | 	  case 'l':			/* 1..12 hours (leading space) */ | 
					
						
							|  |  |  | 	    OUT2DIGITS_SPC(fd, (ftm->tm.tm_hour)%12); | 
					
						
							|  |  |  | 	    break; | 
					
						
							|  |  |  | 	  case 'm':			/* 01..12 month  */ | 
					
						
							|  |  |  | 	    OUT2DIGITS(fd, ftm->tm.tm_mon+1); | 
					
						
							|  |  |  | 	    break; | 
					
						
							|  |  |  | 	  case 'M':			/* 00..59 minute  */ | 
					
						
							|  |  |  | 	    OUT2DIGITS(fd, ftm->tm.tm_min); | 
					
						
							|  |  |  | 	    break; | 
					
						
							|  |  |  | 	  case 'n':			/* newline */ | 
					
						
							|  |  |  | 	    OUTCHR(fd, '\n'); | 
					
						
							|  |  |  | 	    break; | 
					
						
							|  |  |  | 	  case 'O': | 
					
						
							| 
									
										
										
										
											2011-03-09 13:05:03 +00:00
										 |  |  | 	  case ':': | 
					
						
							|  |  |  | 	    if ( format[0] == 'z' ) | 
					
						
							|  |  |  | 	    { altO = TRUE; | 
					
						
							|  |  |  | 	      goto fmt_next; | 
					
						
							|  |  |  | 	    } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	    return fmt_not_implemented(c); | 
					
						
							| 
									
										
										
										
											2010-07-19 14:52:26 +01:00
										 |  |  | 	  case 'r':			/* The  time in a.m./p.m. notation */ | 
					
						
							|  |  |  | 	    SUBFORMAT(L"%I:%M:%S %p");	/* TBD: :-separator locale handling */ | 
					
						
							|  |  |  | 	    break; | 
					
						
							|  |  |  | 	  case 'R': | 
					
						
							|  |  |  | 	    SUBFORMAT(L"%H:%M"); | 
					
						
							|  |  |  | 	    break; | 
					
						
							|  |  |  | 	  case 'f':			/* Microseconds */ | 
					
						
							|  |  |  | 	  { int digits = (arg == NOARG ? 6 : arg); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	    if ( digits > 0 ) | 
					
						
							|  |  |  | 	    { double ip; | 
					
						
							|  |  |  | 	      char fmt[64]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	      cal_ftm(ftm, HAS_STAMP); | 
					
						
							|  |  |  | 	      Ssprintf(fmt, "%%0%dlld", digits); | 
					
						
							|  |  |  | 	      OUTNUMBER(fd, fmt, (long)(modf(ftm->stamp, &ip) * | 
					
						
							|  |  |  | 					pow(10, digits))); | 
					
						
							|  |  |  | 	    } | 
					
						
							|  |  |  | 	    break; | 
					
						
							|  |  |  | 	  } | 
					
						
							|  |  |  | 	  case 's':			/* Seconds since 1970 */ | 
					
						
							|  |  |  | 	    cal_ftm(ftm, HAS_STAMP); | 
					
						
							|  |  |  | 	    OUTNUMBER(fd, "%.0f", ftm->stamp); | 
					
						
							|  |  |  | 	    break; | 
					
						
							|  |  |  | 	  case 'S':			/* Seconds */ | 
					
						
							|  |  |  | 	    OUT2DIGITS(fd, ftm->tm.tm_sec); | 
					
						
							|  |  |  | 	    break; | 
					
						
							|  |  |  | 	  case 't':			/* tab */ | 
					
						
							|  |  |  | 	    OUTCHR(fd, '\t'); | 
					
						
							|  |  |  | 	    break; | 
					
						
							|  |  |  | 	  case 'T': | 
					
						
							|  |  |  | 	    SUBFORMAT(L"%H:%M:%S"); | 
					
						
							|  |  |  | 	    break; | 
					
						
							|  |  |  | 	  case 'u':			/* 1..7 weekday, mon=1 */ | 
					
						
							|  |  |  | 	  { int wday; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	    cal_ftm(ftm, HAS_WYDAY); | 
					
						
							|  |  |  | 	    wday = (ftm->tm.tm_wday - 1 + 7) % 7 + 1; | 
					
						
							|  |  |  | 	    OUT1DIGIT(fd, wday); | 
					
						
							|  |  |  | 	    break; | 
					
						
							|  |  |  | 	  } | 
					
						
							|  |  |  | 	  case 'U':			/* 00..53 weeknumber */ | 
					
						
							|  |  |  | 	  { int wk; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	    cal_ftm(ftm, HAS_WYDAY); | 
					
						
							|  |  |  | 	    wk = (ftm->tm.tm_yday - (ftm->tm.tm_yday - ftm->tm.tm_wday + 7) % 7 + 7) / 7; | 
					
						
							|  |  |  | 	    OUT2DIGITS(fd, wk); | 
					
						
							|  |  |  | 	    break; | 
					
						
							|  |  |  | 	  } | 
					
						
							|  |  |  | 	  case 'w':			/* 0..6 weekday */ | 
					
						
							|  |  |  | 	    cal_ftm(ftm, HAS_WYDAY); | 
					
						
							|  |  |  | 	    OUT1DIGIT(fd, ftm->tm.tm_wday); | 
					
						
							|  |  |  | 	    break; | 
					
						
							|  |  |  | 	  case 'W':			/* 00..53 monday-based week number */ | 
					
						
							|  |  |  | 	  { int wk; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	    cal_ftm(ftm, HAS_WYDAY); | 
					
						
							|  |  |  | 	    wk = (ftm->tm.tm_yday - (ftm->tm.tm_yday - ftm->tm.tm_wday + 8) % 7 + 7) / 7; | 
					
						
							|  |  |  | 	    OUT2DIGITS(fd, wk); | 
					
						
							|  |  |  | 	    break; | 
					
						
							|  |  |  | 	  } | 
					
						
							|  |  |  | 	  case 'y':			/* 00..99 (year) */ | 
					
						
							|  |  |  | 	    OUT2DIGITS(fd, (ftm->tm.tm_year+1900) % 100); | 
					
						
							|  |  |  | 	    break; | 
					
						
							|  |  |  | 	  case 'Y':			/* Year (decimal) */ | 
					
						
							|  |  |  | 	    OUTNUMBER(fd, "%d", ftm->tm.tm_year+1900); | 
					
						
							|  |  |  | 	    break; | 
					
						
							|  |  |  | 	  case 'z':			/* Time-zone as offset */ | 
					
						
							|  |  |  | 	  { int min = -ftm->utcoff/60; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	    if ( min >= 0 ) | 
					
						
							|  |  |  | 	    { OUTCHR(fd, '+'); | 
					
						
							|  |  |  | 	    } else | 
					
						
							|  |  |  | 	    { min = -min; | 
					
						
							|  |  |  | 	      OUTCHR(fd, '-'); | 
					
						
							|  |  |  | 	    } | 
					
						
							|  |  |  | 	    OUT2DIGITS(fd, min/60); | 
					
						
							| 
									
										
										
										
											2011-03-09 13:05:03 +00:00
										 |  |  | 	    if ( altO ) | 
					
						
							|  |  |  | 	      OUTCHR(fd, ':'); | 
					
						
							| 
									
										
										
										
											2010-07-19 14:52:26 +01:00
										 |  |  | 	    OUT2DIGITS(fd, min%60); | 
					
						
							|  |  |  | 	    break; | 
					
						
							|  |  |  | 	  } | 
					
						
							|  |  |  | 	  case 'Z':			/* Time-zone as name */ | 
					
						
							|  |  |  | 	    if ( ftm->tzname ) | 
					
						
							|  |  |  | 	    { OUTATOM(ftm->tzname); | 
					
						
							|  |  |  | 	    } else | 
					
						
							|  |  |  | 	    { OUTSTRA(tz_name(ftm->tm.tm_isdst)); | 
					
						
							|  |  |  | 	    } | 
					
						
							|  |  |  | 	    break; | 
					
						
							|  |  |  | 	  case '+': | 
					
						
							|  |  |  | 	    { char buf[26]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	      cal_ftm(ftm, HAS_WYDAY); | 
					
						
							| 
									
										
										
										
											2013-01-16 12:28:37 +00:00
										 |  |  | 	      PL_asctime_r(&ftm->tm, buf); | 
					
						
							| 
									
										
										
										
											2010-07-19 14:52:26 +01:00
										 |  |  | 	      buf[24] = EOS; | 
					
						
							|  |  |  | 	      OUTSTRA(buf); | 
					
						
							|  |  |  | 	    } | 
					
						
							|  |  |  | 	    break; | 
					
						
							|  |  |  | 	  case '%': | 
					
						
							|  |  |  | 	    OUTCHR(fd, '%'); | 
					
						
							|  |  |  | 	    break; | 
					
						
							|  |  |  | 	  default: | 
					
						
							|  |  |  | 	    if ( isdigit(c) ) | 
					
						
							|  |  |  | 	    { if ( arg == NOARG ) | 
					
						
							|  |  |  | 		arg = c - '0'; | 
					
						
							|  |  |  | 	      else | 
					
						
							|  |  |  | 		arg = arg*10+(c-'0'); | 
					
						
							|  |  |  | 	      goto fmt_next; | 
					
						
							| 
									
										
										
										
											2011-03-09 13:05:03 +00:00
										 |  |  | 	    } else | 
					
						
							|  |  |  | 	    { return fmt_not_implemented(c); | 
					
						
							| 
									
										
										
										
											2010-07-19 14:52:26 +01:00
										 |  |  | 	    } | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |       default: | 
					
						
							|  |  |  | 	OUTCHR(fd, c); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   return TRUE; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 | 
					
						
							|  |  |  | format_time(+Spec, +Format, +Stamp) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Issues: | 
					
						
							|  |  |  | 	* Localtime/DST | 
					
						
							|  |  |  | 	* Year is an int (not so bad) | 
					
						
							|  |  |  | 	* Portability | 
					
						
							|  |  |  | 	* Sub-second times | 
					
						
							|  |  |  | - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static  foreign_t | 
					
						
							|  |  |  | pl_format_time(term_t out, term_t format, term_t time, int posix) | 
					
						
							|  |  |  | { struct taia taia; | 
					
						
							|  |  |  |   struct caltime ct; | 
					
						
							|  |  |  |   struct ftm tb; | 
					
						
							|  |  |  |   int weekday, yearday; | 
					
						
							|  |  |  |   wchar_t *fmt; | 
					
						
							|  |  |  |   time_t unixt; | 
					
						
							|  |  |  |   int64_t ut64; | 
					
						
							|  |  |  |   size_t fmtlen; | 
					
						
							|  |  |  |   redir_context ctx; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if ( !PL_get_wchars(format, &fmtlen, &fmt, | 
					
						
							|  |  |  | 		      CVT_ATOM|CVT_STRING|CVT_LIST|CVT_EXCEPTION) ) | 
					
						
							|  |  |  |     fail; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   memset(&tb, 0, sizeof(tb)); | 
					
						
							|  |  |  |   if ( get_taia(time, &taia, &tb.stamp) ) | 
					
						
							|  |  |  |   { double ip; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     ut64 = taia.sec.x - TAI_UTC_OFFSET; | 
					
						
							|  |  |  |     unixt = (time_t) ut64; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if ( (int64_t)unixt == ut64 ) | 
					
						
							|  |  |  |     { tb.utcoff = tz_offset(); | 
					
						
							| 
									
										
										
										
											2013-01-16 12:28:37 +00:00
										 |  |  |       PL_localtime_r(&unixt, &tb.tm); | 
					
						
							| 
									
										
										
										
											2010-07-19 14:52:26 +01:00
										 |  |  |       tb.sec = (double)tb.tm.tm_sec + modf(tb.stamp, &ip); | 
					
						
							|  |  |  |       if ( tb.tm.tm_isdst > 0 ) | 
					
						
							|  |  |  |       { tb.utcoff -= 3600; | 
					
						
							|  |  |  | 	tb.isdst = TRUE; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       tb.tzname = tz_name_as_atom(tb.tm.tm_isdst); | 
					
						
							|  |  |  |       tb.flags  = HAS_STAMP|HAS_WYDAY; | 
					
						
							|  |  |  |     } else | 
					
						
							|  |  |  |     { caltime_utc(&ct, &taia.sec, &weekday, &yearday); | 
					
						
							|  |  |  |       tb.tm.tm_sec  = ct.second; | 
					
						
							|  |  |  |       tb.tm.tm_min  = ct.minute; | 
					
						
							|  |  |  |       tb.tm.tm_hour = ct.hour; | 
					
						
							|  |  |  |       tb.tm.tm_mday = ct.date.day; | 
					
						
							|  |  |  |       tb.tm.tm_mon  = ct.date.month - 1; | 
					
						
							|  |  |  |       tb.tm.tm_year = ct.date.year - 1900; | 
					
						
							|  |  |  |       tb.tm.tm_wday = weekday; | 
					
						
							|  |  |  |       tb.tm.tm_yday = yearday; | 
					
						
							|  |  |  |       tb.tzname     = ATOM_utc; | 
					
						
							|  |  |  |       tb.utcoff     = 0; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } else if ( !get_ftm(time, &tb) ) | 
					
						
							| 
									
										
										
										
											2013-01-16 12:28:37 +00:00
										 |  |  |   { return FALSE; | 
					
						
							| 
									
										
										
										
											2010-07-19 14:52:26 +01:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if ( !setupOutputRedirect(out, &ctx, FALSE) ) | 
					
						
							|  |  |  |     fail; | 
					
						
							|  |  |  |   if ( format_time(ctx.stream, fmt, &tb, posix) ) | 
					
						
							|  |  |  |     return closeOutputRedirect(&ctx);	/* takes care of I/O errors */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   discardOutputRedirect(&ctx); | 
					
						
							|  |  |  |   fail; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static | 
					
						
							|  |  |  | PRED_IMPL("format_time", 3, format_time3, 0) | 
					
						
							|  |  |  | { return pl_format_time(A1, A2, A3, FALSE); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static | 
					
						
							|  |  |  | PRED_IMPL("format_time", 4, format_time4, 0) | 
					
						
							|  |  |  | { PRED_LD | 
					
						
							|  |  |  |   int posix = FALSE; | 
					
						
							|  |  |  |   atom_t locale; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if ( !PL_get_atom_ex(A4, &locale) ) | 
					
						
							|  |  |  |     return FALSE; | 
					
						
							|  |  |  |   if ( locale == ATOM_posix ) | 
					
						
							|  |  |  |     posix = TRUE; | 
					
						
							|  |  |  |   else | 
					
						
							|  |  |  |     return PL_error(NULL, 0, NULL, ERR_DOMAIN, ATOM_locale, A4); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   return pl_format_time(A1, A2, A3, posix); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		 /*******************************
 | 
					
						
							|  |  |  | 		 *      PUBLISH PREDICATES	* | 
					
						
							|  |  |  | 		 *******************************/ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | BeginPredDefs(tai) | 
					
						
							|  |  |  |   PRED_DEF("stamp_date_time", 3, stamp_date_time, 0) | 
					
						
							|  |  |  |   PRED_DEF("date_time_stamp", 2, date_time_stamp, 0) | 
					
						
							|  |  |  |   PRED_DEF("format_time",     3, format_time3,    0) | 
					
						
							|  |  |  |   PRED_DEF("format_time",     4, format_time4,    0) | 
					
						
							|  |  |  | EndPredDefs |