3 * Copyright (c) 2006 Luke Dunstan <infidel@users.sourceforge.net>
4 * Partly based on code by David Kashtan, Validus Medical Systems
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the "Software"),
8 * to deal in the Software without restriction, including without limitation
9 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 * and/or sell copies of the Software, and to permit persons to whom the
11 * Software is furnished to do so, subject to the following conditions:
13 * The above copyright notice and this permission notice shall be included
14 * in all copies or substantial portions of the Software.
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22 * DEALINGS IN THE SOFTWARE.
26 * This file provides various functions that are available on desktop Windows
27 * but not on Windows CE
31 /* Level 4 warnings caused by windows.h */
32 #pragma warning(disable : 4214) // nonstandard extension used : bit field types other than int
33 #pragma warning(disable : 4115) // named type definition in parentheses
34 #pragma warning(disable : 4201) // nonstandard extension used : nameless struct/union
35 #pragma warning(disable : 4514) // unreferenced inline function has been removed
36 #pragma warning(disable : 4244) // conversion from 'int ' to 'unsigned short ', possible loss of data
37 #pragma warning(disable : 4100) // unreferenced formal parameter
43 #include "compat_wince.h"
46 static WCHAR *to_wide_string(LPCSTR pStr)
53 nwide = MultiByteToWideChar(CP_ACP, 0, pStr, -1, NULL, 0);
56 buf = malloc(nwide * sizeof(WCHAR));
58 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
61 if(MultiByteToWideChar(CP_ACP, 0, pStr, -1, buf, nwide) == 0) {
68 FILE *fdopen(int handle, const char *mode)
70 WCHAR *wmode = to_wide_string(mode);
74 result = _wfdopen((void *)handle, wmode);
82 * Time conversion constants
84 #define FT_EPOCH (116444736000000000i64)
85 #define FT_TICKS (10000000i64)
88 * Convert a FILETIME to a time_t
90 static time_t convert_FILETIME_to_time_t(FILETIME *File_Time)
95 * Convert the FILETIME structure to 100nSecs since 1601 (as a 64-bit value)
97 Temp = (((__int64)File_Time->dwHighDateTime) << 32) + (__int64)File_Time->dwLowDateTime;
99 * Convert to seconds from 1970
101 return((time_t)((Temp - FT_EPOCH) / FT_TICKS));
105 * Convert a FILETIME to a tm structure
107 static struct tm *Convert_FILETIME_To_tm(FILETIME *File_Time)
109 SYSTEMTIME System_Time;
110 static struct tm tm = {0};
111 static const short Day_Of_Year_By_Month[12] = {(short)(0),
114 (short)(31 + 28 + 31),
115 (short)(31 + 28 + 31 + 30),
116 (short)(31 + 28 + 31 + 30 + 31),
117 (short)(31 + 28 + 31 + 30 + 31 + 30),
118 (short)(31 + 28 + 31 + 30 + 31 + 30 + 31),
119 (short)(31 + 28 + 31 + 30 + 31 + 30 + 31 + 31),
120 (short)(31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30),
121 (short)(31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31),
122 (short)(31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30)};
126 * Turn the FILETIME into a SYSTEMTIME
128 FileTimeToSystemTime(File_Time, &System_Time);
130 * Use SYSTEMTIME to fill in the tm structure
132 tm.tm_sec = System_Time.wSecond;
133 tm.tm_min = System_Time.wMinute;
134 tm.tm_hour = System_Time.wHour;
135 tm.tm_mday = System_Time.wDay;
136 tm.tm_mon = System_Time.wMonth - 1;
137 tm.tm_year = System_Time.wYear - 1900;
138 tm.tm_wday = System_Time.wDayOfWeek;
139 tm.tm_yday = Day_Of_Year_By_Month[tm.tm_mon] + tm.tm_mday - 1;
140 if (tm.tm_mon >= 2) {
142 * Check for leap year (every 4 years but not every 100 years but every 400 years)
144 if ((System_Time.wYear % 4) == 0) {
148 if ((System_Time.wYear % 100) == 0) {
152 if ((System_Time.wYear % 400) == 0) {
154 * It is a 400th year: It is a leap year
160 * It is not a 100th year: It is a leap year
170 * Convert a time_t to a FILETIME
172 static void Convert_time_t_To_FILETIME(time_t Time, FILETIME *File_Time)
177 * Use 64-bit calculation to convert seconds since 1970 to
178 * 100nSecs since 1601
180 Temp = ((__int64)Time * FT_TICKS) + FT_EPOCH;
182 * Put it into the FILETIME structure
184 File_Time->dwLowDateTime = (DWORD)Temp;
185 File_Time->dwHighDateTime = (DWORD)(Temp >> 32);
189 * Convert a tm structure to a FILETIME
191 static FILETIME *Convert_tm_To_FILETIME(struct tm *tm)
193 SYSTEMTIME System_Time;
194 static FILETIME File_Time = {0};
197 * Use the tm structure to fill in a SYSTEM
199 System_Time.wYear = tm->tm_year + 1900;
200 System_Time.wMonth = tm->tm_mon + 1;
201 System_Time.wDayOfWeek = tm->tm_wday;
202 System_Time.wDay = tm->tm_mday;
203 System_Time.wHour = tm->tm_hour;
204 System_Time.wMinute = tm->tm_min;
205 System_Time.wSecond = tm->tm_sec;
206 System_Time.wMilliseconds = 0;
208 * Convert it to a FILETIME and return it
210 SystemTimeToFileTime(&System_Time, &File_Time);
215 /************************************************************************/
217 /* Errno emulation: There is no errno on Windows/CE and we need */
218 /* to make it per-thread. So we have a function */
219 /* that returns a pointer to the errno for the */
220 /* current thread. */
222 /* If there is ONLY the main thread then we can */
223 /* quickly return some static storage. */
225 /* If we have multiple threads running, we use */
226 /* Thread-Local Storage to hold the pointer */
228 /************************************************************************/
231 * Function pointer for returning errno pointer
233 static int *Initialize_Errno(void);
234 int *(*__WinCE_Errno_Pointer_Function)(void) = Initialize_Errno;
237 * Static errno storage for the main thread
239 static int Errno_Storage = 0;
242 * Thread-Local storage slot for errno
244 static int TLS_Errno_Slot = 0xffffffff;
247 * Number of threads we have running and critical section protection
248 * for manipulating it
250 static int Number_Of_Threads = 0;
251 static CRITICAL_SECTION Number_Of_Threads_Critical_Section;
254 * For the main thread only -- return the errno pointer
256 static int *Get_Main_Thread_Errno(void)
258 return &Errno_Storage;
262 * When there is more than one thread -- return the errno pointer
264 static int *Get_Thread_Errno(void)
266 return (int *)TlsGetValue(TLS_Errno_Slot);
270 * Initialize a thread's errno
272 static void Initialize_Thread_Errno(int *Errno_Pointer)
275 * Make sure we have a slot
277 if (TLS_Errno_Slot == 0xffffffff) {
281 TLS_Errno_Slot = (int)TlsAlloc();
282 if (TLS_Errno_Slot == 0xffffffff) ExitProcess(3);
285 * We can safely check for 0 threads, because
286 * only the main thread will be initializing
287 * at this point. Make sure the critical
288 * section that protects the number of threads
291 if (Number_Of_Threads == 0)
292 InitializeCriticalSection(&Number_Of_Threads_Critical_Section);
294 * Store the errno pointer
296 if (TlsSetValue(TLS_Errno_Slot, (LPVOID)Errno_Pointer) == 0) ExitProcess(3);
298 * Bump the number of threads
300 EnterCriticalSection(&Number_Of_Threads_Critical_Section);
302 if (Number_Of_Threads > 1) {
304 * We have threads other than the main thread:
305 * Use thread-local storage
307 __WinCE_Errno_Pointer_Function = Get_Thread_Errno;
309 LeaveCriticalSection(&Number_Of_Threads_Critical_Section);
313 * Initialize errno emulation on Windows/CE (Main thread)
315 static int *Initialize_Errno(void)
318 * Initialize the main thread's errno in thread-local storage
320 Initialize_Thread_Errno(&Errno_Storage);
322 * Set the errno function to be the one that returns the
323 * main thread's errno
325 __WinCE_Errno_Pointer_Function = Get_Main_Thread_Errno;
327 * Return the main thread's errno
329 return &Errno_Storage;
333 * Initialize errno emulation on Windows/CE (New thread)
335 void __WinCE_Errno_New_Thread(int *Errno_Pointer)
337 Initialize_Thread_Errno(Errno_Pointer);
341 * Note that a thread has exited
343 void __WinCE_Errno_Thread_Exit(void)
346 * Decrease the number of threads
348 EnterCriticalSection(&Number_Of_Threads_Critical_Section);
350 if (Number_Of_Threads <= 1) {
352 * We only have the main thread
354 __WinCE_Errno_Pointer_Function = Get_Main_Thread_Errno;
356 LeaveCriticalSection(&Number_Of_Threads_Critical_Section);
363 return "(strerror not implemented)";
366 #define FT_EPOCH (116444736000000000i64)
367 #define FT_TICKS (10000000i64)
370 _wstat(const WCHAR *path, struct _stat *buffer)
372 WIN32_FIND_DATA data;
376 /* Fail if wildcard characters are specified */
377 if (wcscspn(path, L"?*") != wcslen(path))
380 handle = FindFirstFile(path, &data);
381 if (handle == INVALID_HANDLE_VALUE) {
382 errno = GetLastError();
387 /* Found: Convert the file times */
388 buffer->st_mtime = convert_FILETIME_to_time_t(&data.ftLastWriteTime);
389 if (data.ftLastAccessTime.dwLowDateTime || data.ftLastAccessTime.dwHighDateTime)
390 buffer->st_atime = convert_FILETIME_to_time_t(&data.ftLastAccessTime);
392 buffer->st_atime = buffer->st_mtime;
393 if (data.ftCreationTime.dwLowDateTime || data.ftCreationTime.dwHighDateTime)
394 buffer->st_ctime = convert_FILETIME_to_time_t(&data.ftCreationTime);
396 buffer->st_ctime = buffer->st_mtime;
398 /* Convert the file modes */
399 buffer->st_mode = (unsigned short)((data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ? (S_IFDIR | S_IEXEC) : S_IFREG);
400 buffer->st_mode |= (data.dwFileAttributes & FILE_ATTRIBUTE_READONLY) ? S_IREAD : (S_IREAD | S_IWRITE);
401 if((p = wcsrchr(path, L'.')) != NULL) {
403 if (_wcsicmp(p, L".exe") == 0)
404 buffer->st_mode |= S_IEXEC;
406 buffer->st_mode |= (buffer->st_mode & 0700) >> 3;
407 buffer->st_mode |= (buffer->st_mode & 0700) >> 6;
408 /* Set the other information */
409 buffer->st_nlink = 1;
410 buffer->st_size = (unsigned long int)data.nFileSizeLow;
413 buffer->st_ino = 0 /*data.dwOID ?*/;
416 return 0; /* success */
420 * Helper function for cemodule -- do an fstat() operation on a Win32 File Handle
423 _fstat(int handle, struct _stat *st)
425 BY_HANDLE_FILE_INFORMATION Data;
428 * Get the file information
430 if (!GetFileInformationByHandle((HANDLE)handle, &Data)) {
434 errno = GetLastError();
438 * Found: Convert the file times
440 st->st_mtime=(time_t)((*(__int64*)&Data.ftLastWriteTime-FT_EPOCH)/FT_TICKS);
441 if(Data.ftLastAccessTime.dwLowDateTime || Data.ftLastAccessTime.dwHighDateTime)
442 st->st_atime=(time_t)((*(__int64*)&Data.ftLastAccessTime-FT_EPOCH)/FT_TICKS);
444 st->st_atime=st->st_mtime ;
445 if(Data.ftCreationTime.dwLowDateTime || Data.ftCreationTime.dwHighDateTime )
446 st->st_ctime=(time_t)((*(__int64*)&Data.ftCreationTime-FT_EPOCH)/FT_TICKS);
448 st->st_ctime=st->st_mtime ;
450 * Convert the file modes
452 st->st_mode = (unsigned short)((Data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ? (S_IFDIR | S_IEXEC) : S_IFREG);
453 st->st_mode |= (Data.dwFileAttributes & FILE_ATTRIBUTE_READONLY) ? S_IREAD : (S_IREAD | S_IWRITE);
454 st->st_mode |= (st->st_mode & 0700) >> 3;
455 st->st_mode |= (st->st_mode & 0700) >> 6;
457 * Set the other information
460 st->st_size=(unsigned long int)Data.nFileSizeLow;
471 int _wopen(const wchar_t *filename, int oflag, ...)
473 DWORD Access, ShareMode, CreationDisposition;
475 static int Modes[4] = {0, (GENERIC_READ | GENERIC_WRITE), GENERIC_READ, GENERIC_WRITE};
478 * Calculate the CreateFile arguments
480 Access = Modes[oflag & O_MODE_MASK];
481 ShareMode = (oflag & O_EXCL) ? 0 : (FILE_SHARE_READ | FILE_SHARE_WRITE);
483 CreationDisposition = (oflag & O_CREAT) ? CREATE_ALWAYS : TRUNCATE_EXISTING;
485 CreationDisposition = (oflag & O_CREAT) ? CREATE_NEW : OPEN_EXISTING;
487 Handle = CreateFileW(filename, Access, ShareMode, NULL, CreationDisposition, FILE_ATTRIBUTE_NORMAL, NULL);
492 if (Handle == INVALID_HANDLE_VALUE) {
493 errno = GetLastError();
494 if ((errno == ERROR_ALREADY_EXISTS) || (errno == ERROR_FILE_EXISTS))
495 errno = ERROR_ALREADY_EXISTS;
507 if(CloseHandle((HANDLE)handle))
509 errno = GetLastError();
514 _write(int handle, const void *buffer, unsigned int count)
516 DWORD numwritten = 0;
517 if(!WriteFile((HANDLE)handle, buffer, count, &numwritten, NULL)) {
518 errno = GetLastError();
525 _read(int handle, void *buffer, unsigned int count)
528 if(!ReadFile((HANDLE)handle, buffer, count, &numread, NULL)) {
529 errno = GetLastError();
536 _lseek(int handle, long offset, int origin)
546 dwMoveMethod = FILE_BEGIN;
549 dwMoveMethod = FILE_CURRENT;
552 dwMoveMethod = FILE_END;
555 result = SetFilePointer((HANDLE)handle, offset, NULL, dwMoveMethod);
556 if(result == 0xFFFFFFFF) {
557 errno = GetLastError();
564 _wmkdir(const wchar_t *dirname)
566 if(!CreateDirectoryW(dirname, NULL)) {
567 errno = GetLastError();
574 _wremove(const wchar_t *filename)
576 if(!DeleteFileW(filename)) {
577 errno = GetLastError();
584 _wrename(const wchar_t *oldname, const wchar_t *newname)
586 if(!MoveFileW(oldname, newname)) {
587 errno = GetLastError();
594 _wgetcwd(wchar_t *buffer, int maxlen)
597 WCHAR wszPath[MAX_PATH + 1];
600 if(!GetModuleFileNameW(NULL, wszPath, MAX_PATH + 1)) {
601 errno = GetLastError();
604 /* Remove the filename part of the path to leave the directory */
605 p = wcsrchr(wszPath, L'\\');
610 result = _wcsdup(wszPath);
611 else if(wcslen(wszPath) + 1 > (size_t)maxlen) {
613 errno = ERROR_INSUFFICIENT_BUFFER;
615 wcsncpy(buffer, wszPath, maxlen);
616 buffer[maxlen - 1] = L'\0';
623 * The missing "C" runtime gmtime() function
625 struct tm *gmtime(const time_t *TimeP)
630 * Deal with null time pointer
632 if (!TimeP) return(NULL);
634 * time_t -> FILETIME -> tm
636 Convert_time_t_To_FILETIME(*TimeP, &File_Time);
637 return(Convert_FILETIME_To_tm(&File_Time));
641 * The missing "C" runtime localtime() function
643 struct tm *localtime(const time_t *TimeP)
645 FILETIME File_Time, Local_File_Time;
648 * Deal with null time pointer
650 if (!TimeP) return(NULL);
652 * time_t -> FILETIME -> Local FILETIME -> tm
654 Convert_time_t_To_FILETIME(*TimeP, &File_Time);
655 FileTimeToLocalFileTime(&File_Time, &Local_File_Time);
656 return(Convert_FILETIME_To_tm(&Local_File_Time));
660 * The missing "C" runtime mktime() function
662 time_t mktime(struct tm *tm)
664 FILETIME *Local_File_Time;
668 * tm -> Local FILETIME -> FILETIME -> time_t
670 Local_File_Time = Convert_tm_To_FILETIME(tm);
671 LocalFileTimeToFileTime(Local_File_Time, &File_Time);
672 return(convert_FILETIME_to_time_t(&File_Time));
676 * Missing "C" runtime time() function
678 time_t time(time_t *TimeP)
680 SYSTEMTIME System_Time;
685 * Get the current system time
687 GetSystemTime(&System_Time);
689 * SYSTEMTIME -> FILETIME -> time_t
691 SystemTimeToFileTime(&System_Time, &File_Time);
692 Result = convert_FILETIME_to_time_t(&File_Time);
696 if (TimeP) *TimeP = Result;
700 static char Standard_Name[32] = "GMT";
701 static char Daylight_Name[32] = "GMT";
702 char *tzname[2] = {Standard_Name, Daylight_Name};
708 TIME_ZONE_INFORMATION Info;
712 * Get our current timezone information
714 Result = GetTimeZoneInformation(&Info);
717 * We are on standard time
719 case TIME_ZONE_ID_STANDARD:
723 * We are on daylight savings time
725 case TIME_ZONE_ID_DAYLIGHT:
729 * We don't know the timezone information (leave it GMT)
734 * Extract the timezone information
736 timezone = Info.Bias * 60;
737 if (Info.StandardName[0])
738 WideCharToMultiByte(CP_ACP, 0, Info.StandardName, -1, Standard_Name, sizeof(Standard_Name) - 1, NULL, NULL);
739 if (Info.DaylightName[0])
740 WideCharToMultiByte(CP_ACP, 0, Info.DaylightName, -1, Daylight_Name, sizeof(Daylight_Name) - 1, NULL, NULL);
743 /*** strftime() from newlib libc/time/strftime.c ***/
746 * Sane snprintf(). Acts like snprintf(), but never return -1 or the
747 * value bigger than supplied buffer.
750 Snprintf(char *buf, size_t buflen, const char *fmt, ...)
759 n = _vsnprintf(buf, buflen, fmt, ap);
762 if (n < 0 || n > (int) buflen - 1) {
770 #define snprintf Snprintf
772 /* from libc/include/_ansi.h */
774 #define _DEFUN(name, arglist, args) name(args)
776 /* from libc/time/local.h */
779 #define _tzname tzname
780 #define isleap(y) ((((y) % 4) == 0 && ((y) % 100) != 0) || ((y) % 400) == 0)
781 #define YEAR_BASE 1900
782 #define SECSPERMIN 60L
783 #define MINSPERHOUR 60L
784 #define HOURSPERDAY 24L
785 #define SECSPERHOUR (SECSPERMIN * MINSPERHOUR)
789 * Original Author: G. Haley
790 * Additions from: Eric Blake
792 * Places characters into the array pointed to by s as controlled by the string
793 * pointed to by format. If the total number of resulting characters including
794 * the terminating null character is not more than maxsize, returns the number
795 * of characters placed into the array pointed to by s (not including the
796 * terminating null character); otherwise zero is returned and the contents of
797 * the array indeterminate.
802 <<strftime>>---flexible calendar time formatter
809 size_t strftime(char *<[s]>, size_t <[maxsize]>,
810 const char *<[format]>, const struct tm *<[timp]>);
814 size_t strftime(<[s]>, <[maxsize]>, <[format]>, <[timp]>)
821 <<strftime>> converts a <<struct tm>> representation of the time (at
822 <[timp]>) into a null-terminated string, starting at <[s]> and occupying
823 no more than <[maxsize]> characters.
825 You control the format of the output using the string at <[format]>.
826 <<*<[format]>>> can contain two kinds of specifications: text to be
827 copied literally into the formatted string, and time conversion
828 specifications. Time conversion specifications are two- and
829 three-character sequences beginning with `<<%>>' (use `<<%%>>' to
830 include a percent sign in the output). Each defined conversion
831 specification selects only the specified field(s) of calendar time
832 data from <<*<[timp]>>>, and converts it to a string in one of the
837 A three-letter abbreviation for the day of the week. [tm_wday]
840 The full name for the day of the week, one of `<<Sunday>>',
841 `<<Monday>>', `<<Tuesday>>', `<<Wednesday>>', `<<Thursday>>',
842 `<<Friday>>', or `<<Saturday>>'. [tm_wday]
845 A three-letter abbreviation for the month name. [tm_mon]
848 The full name of the month, one of `<<January>>', `<<February>>',
849 `<<March>>', `<<April>>', `<<May>>', `<<June>>', `<<July>>',
850 `<<August>>', `<<September>>', `<<October>>', `<<November>>',
851 `<<December>>'. [tm_mon]
854 A string representing the complete date and time, in the form
855 `<<"%a %b %e %H:%M:%S %Y">>' (example "Mon Apr 01 13:13:13
856 1992"). [tm_sec, tm_min, tm_hour, tm_mday, tm_mon, tm_year, tm_wday]
859 The century, that is, the year divided by 100 then truncated. For
860 4-digit years, the result is zero-padded and exactly two characters;
861 but for other years, there may a negative sign or more digits. In
862 this way, `<<%C%y>>' is equivalent to `<<%Y>>'. [tm_year]
865 The day of the month, formatted with two digits (from `<<01>>' to
869 A string representing the date, in the form `<<"%m/%d/%y">>'.
870 [tm_mday, tm_mon, tm_year]
873 The day of the month, formatted with leading space if single digit
874 (from `<<1>>' to `<<31>>'). [tm_mday]
877 In some locales, the E modifier selects alternative representations of
878 certain modifiers <<x>>. But in the "C" locale supported by newlib,
879 it is ignored, and treated as %<<x>>.
882 A string representing the ISO 8601:2000 date format, in the form
883 `<<"%Y-%m-%d">>'. [tm_mday, tm_mon, tm_year]
886 The last two digits of the week-based year, see specifier %G (from
887 `<<00>>' to `<<99>>'). [tm_year, tm_wday, tm_yday]
890 The week-based year. In the ISO 8601:2000 calendar, week 1 of the year
891 includes January 4th, and begin on Mondays. Therefore, if January 1st,
892 2nd, or 3rd falls on a Sunday, that day and earlier belong to the last
893 week of the previous year; and if December 29th, 30th, or 31st falls
894 on Monday, that day and later belong to week 1 of the next year. For
895 consistency with %Y, it always has at least four characters.
896 Example: "%G" for Saturday 2nd January 1999 gives "1998", and for
897 Tuesday 30th December 1997 gives "1998". [tm_year, tm_wday, tm_yday]
900 A three-letter abbreviation for the month name (synonym for
904 The hour (on a 24-hour clock), formatted with two digits (from
905 `<<00>>' to `<<23>>'). [tm_hour]
908 The hour (on a 12-hour clock), formatted with two digits (from
909 `<<01>>' to `<<12>>'). [tm_hour]
912 The count of days in the year, formatted with three digits
913 (from `<<001>>' to `<<366>>'). [tm_yday]
916 The hour (on a 24-hour clock), formatted with leading space if single
917 digit (from `<<0>>' to `<<23>>'). Non-POSIX extension. [tm_hour]
920 The hour (on a 12-hour clock), formatted with leading space if single
921 digit (from `<<1>>' to `<<12>>'). Non-POSIX extension. [tm_hour]
924 The month number, formatted with two digits (from `<<01>>' to `<<12>>').
928 The minute, formatted with two digits (from `<<00>>' to `<<59>>'). [tm_min]
931 A newline character (`<<\n>>').
934 In some locales, the O modifier selects alternative digit characters
935 for certain modifiers <<x>>. But in the "C" locale supported by newlib, it
936 is ignored, and treated as %<<x>>.
939 Either `<<AM>>' or `<<PM>>' as appropriate. [tm_hour]
942 The 12-hour time, to the second. Equivalent to "%I:%M:%S %p". [tm_sec,
946 The 24-hour time, to the minute. Equivalent to "%H:%M". [tm_min, tm_hour]
949 The second, formatted with two digits (from `<<00>>' to `<<60>>'). The
950 value 60 accounts for the occasional leap second. [tm_sec]
953 A tab character (`<<\t>>').
956 The 24-hour time, to the second. Equivalent to "%H:%M:%S". [tm_sec,
960 The weekday as a number, 1-based from Monday (from `<<1>>' to
964 The week number, where weeks start on Sunday, week 1 contains the first
965 Sunday in a year, and earlier days are in week 0. Formatted with two
966 digits (from `<<00>>' to `<<53>>'). See also <<%W>>. [tm_wday, tm_yday]
969 The week number, where weeks start on Monday, week 1 contains January 4th,
970 and earlier days are in the previous year. Formatted with two digits
971 (from `<<01>>' to `<<53>>'). See also <<%G>>. [tm_year, tm_wday, tm_yday]
974 The weekday as a number, 0-based from Sunday (from `<<0>>' to `<<6>>').
978 The week number, where weeks start on Monday, week 1 contains the first
979 Monday in a year, and earlier days are in week 0. Formatted with two
980 digits (from `<<00>>' to `<<53>>'). [tm_wday, tm_yday]
983 A string representing the complete date, equivalent to "%m/%d/%y".
984 [tm_mon, tm_mday, tm_year]
987 A string representing the full time of day (hours, minutes, and
988 seconds), equivalent to "%H:%M:%S". [tm_sec, tm_min, tm_hour]
991 The last two digits of the year (from `<<00>>' to `<<99>>'). [tm_year]
994 The full year, equivalent to <<%C%y>>. It will always have at least four
995 characters, but may have more. The year is accurate even when tm_year
996 added to the offset of 1900 overflows an int. [tm_year]
999 The offset from UTC. The format consists of a sign (negative is west of
1000 Greewich), two characters for hour, then two characters for minutes
1001 (-hhmm or +hhmm). If tm_isdst is negative, the offset is unknown and no
1002 output is generated; if it is zero, the offset is the standard offset for
1003 the current time zone; and if it is positive, the offset is the daylight
1004 savings offset for the current timezone. The offset is determined from
1005 the TZ environment variable, as if by calling tzset(). [tm_isdst]
1008 The time zone name. If tm_isdst is negative, no output is generated.
1009 Otherwise, the time zone name is based on the TZ environment variable,
1010 as if by calling tzset(). [tm_isdst]
1013 A single character, `<<%>>'.
1017 When the formatted time takes up no more than <[maxsize]> characters,
1018 the result is the length of the formatted string. Otherwise, if the
1019 formatting operation was abandoned due to lack of room, the result is
1020 <<0>>, and the string starting at <[s]> corresponds to just those
1021 parts of <<*<[format]>>> that could be completely filled in within the
1025 ANSI C requires <<strftime>>, but does not specify the contents of
1026 <<*<[s]>>> when the formatted string would require more than
1027 <[maxsize]> characters. Unrecognized specifiers and fields of
1028 <<timp>> that are out of range cause undefined results. Since some
1029 formats expand to 0 bytes, it is wise to set <<*<[s]>>> to a nonzero
1030 value beforehand to distinguish between failure and an empty string.
1031 This implementation does not support <<s>> being NULL, nor overlapping
1032 <<s>> and <<format>>.
1034 <<strftime>> requires no supporting OS subroutines.
1037 static _CONST int dname_len[7] =
1038 {6, 6, 7, 9, 8, 6, 8};
1040 static _CONST char *_CONST dname[7] =
1041 {"Sunday", "Monday", "Tuesday", "Wednesday",
1042 "Thursday", "Friday", "Saturday"};
1044 static _CONST int mname_len[12] =
1045 {7, 8, 5, 5, 3, 4, 4, 6, 9, 7, 8, 8};
1047 static _CONST char *_CONST mname[12] =
1048 {"January", "February", "March", "April",
1049 "May", "June", "July", "August", "September", "October", "November",
1052 /* Using the tm_year, tm_wday, and tm_yday components of TIM_P, return
1053 -1, 0, or 1 as the adjustment to add to the year for the ISO week
1054 numbering used in "%g%G%V", avoiding overflow. */
1056 _DEFUN (iso_year_adjust, (tim_p),
1057 _CONST struct tm *tim_p)
1059 /* Account for fact that tm_year==0 is year 1900. */
1060 int leap = isleap (tim_p->tm_year + (YEAR_BASE
1061 - (tim_p->tm_year < 0 ? 0 : 2000)));
1063 /* Pack the yday, wday, and leap year into a single int since there are so
1064 many disparate cases. */
1065 #define PACK(yd, wd, lp) (((yd) << 4) + (wd << 1) + (lp))
1066 switch (PACK (tim_p->tm_yday, tim_p->tm_wday, leap))
1068 case PACK (0, 5, 0): /* Jan 1 is Fri, not leap. */
1069 case PACK (0, 6, 0): /* Jan 1 is Sat, not leap. */
1070 case PACK (0, 0, 0): /* Jan 1 is Sun, not leap. */
1071 case PACK (0, 5, 1): /* Jan 1 is Fri, leap year. */
1072 case PACK (0, 6, 1): /* Jan 1 is Sat, leap year. */
1073 case PACK (0, 0, 1): /* Jan 1 is Sun, leap year. */
1074 case PACK (1, 6, 0): /* Jan 2 is Sat, not leap. */
1075 case PACK (1, 0, 0): /* Jan 2 is Sun, not leap. */
1076 case PACK (1, 6, 1): /* Jan 2 is Sat, leap year. */
1077 case PACK (1, 0, 1): /* Jan 2 is Sun, leap year. */
1078 case PACK (2, 0, 0): /* Jan 3 is Sun, not leap. */
1079 case PACK (2, 0, 1): /* Jan 3 is Sun, leap year. */
1080 return -1; /* Belongs to last week of previous year. */
1081 case PACK (362, 1, 0): /* Dec 29 is Mon, not leap. */
1082 case PACK (363, 1, 1): /* Dec 29 is Mon, leap year. */
1083 case PACK (363, 1, 0): /* Dec 30 is Mon, not leap. */
1084 case PACK (363, 2, 0): /* Dec 30 is Tue, not leap. */
1085 case PACK (364, 1, 1): /* Dec 30 is Mon, leap year. */
1086 case PACK (364, 2, 1): /* Dec 30 is Tue, leap year. */
1087 case PACK (364, 1, 0): /* Dec 31 is Mon, not leap. */
1088 case PACK (364, 2, 0): /* Dec 31 is Tue, not leap. */
1089 case PACK (364, 3, 0): /* Dec 31 is Wed, not leap. */
1090 case PACK (365, 1, 1): /* Dec 31 is Mon, leap year. */
1091 case PACK (365, 2, 1): /* Dec 31 is Tue, leap year. */
1092 case PACK (365, 3, 1): /* Dec 31 is Wed, leap year. */
1093 return 1; /* Belongs to first week of next year. */
1095 return 0; /* Belongs to specified year. */
1100 _DEFUN (strftime, (s, maxsize, format, tim_p),
1103 _CONST char *format _AND
1104 _CONST struct tm *tim_p)
1111 while (*format && *format != '%')
1113 if (count < maxsize - 1)
1114 s[count++] = *format++;
1119 if (*format == '\0')
1123 if (*format == 'E' || *format == 'O')
1129 for (i = 0; i < 3; i++)
1131 if (count < maxsize - 1)
1133 dname[tim_p->tm_wday][i];
1139 for (i = 0; i < dname_len[tim_p->tm_wday]; i++)
1141 if (count < maxsize - 1)
1143 dname[tim_p->tm_wday][i];
1150 for (i = 0; i < 3; i++)
1152 if (count < maxsize - 1)
1154 mname[tim_p->tm_mon][i];
1160 for (i = 0; i < mname_len[tim_p->tm_mon]; i++)
1162 if (count < maxsize - 1)
1164 mname[tim_p->tm_mon][i];
1171 /* Length is not known because of %C%y, so recurse. */
1172 size_t adjust = strftime (&s[count], maxsize - count,
1173 "%a %b %e %H:%M:%S %C%y", tim_p);
1182 /* Examples of (tm_year + YEAR_BASE) that show how %Y == %C%y
1185 2147485547 21474855 47
1197 -2147481748 -21474817 48
1199 Be careful of both overflow and sign adjustment due to the
1200 asymmetric range of years.
1202 int neg = tim_p->tm_year < -YEAR_BASE;
1203 int century = tim_p->tm_year >= 0
1204 ? tim_p->tm_year / 100 + YEAR_BASE / 100
1205 : abs (tim_p->tm_year + YEAR_BASE) / 100;
1206 count += snprintf (&s[count], maxsize - count, "%s%.*d",
1207 neg ? "-" : "", 2 - neg, century);
1208 if (count >= maxsize)
1214 if (count < maxsize - 2)
1216 sprintf (&s[count], *format == 'd' ? "%.2d" : "%2d",
1226 if (count < maxsize - 8)
1228 sprintf (&s[count], "%.2d/%.2d/%.2d",
1229 tim_p->tm_mon + 1, tim_p->tm_mday,
1230 tim_p->tm_year >= 0 ? tim_p->tm_year % 100
1231 : abs (tim_p->tm_year + YEAR_BASE) % 100);
1239 /* Length is not known because of %C%y, so recurse. */
1240 size_t adjust = strftime (&s[count], maxsize - count,
1241 "%C%y-%m-%d", tim_p);
1249 if (count < maxsize - 2)
1251 /* Be careful of both overflow and negative years, thanks to
1252 the asymmetric range of years. */
1253 int adjust = iso_year_adjust (tim_p);
1254 int year = tim_p->tm_year >= 0 ? tim_p->tm_year % 100
1255 : abs (tim_p->tm_year + YEAR_BASE) % 100;
1256 if (adjust < 0 && tim_p->tm_year <= -YEAR_BASE)
1258 else if (adjust > 0 && tim_p->tm_year < -YEAR_BASE)
1260 sprintf (&s[count], "%.2d",
1261 ((year + adjust) % 100 + 100) % 100);
1269 /* See the comments for 'C' and 'Y'; this is a variable length
1270 field. Although there is no requirement for a minimum number
1271 of digits, we use 4 for consistency with 'Y'. */
1272 int neg = tim_p->tm_year < -YEAR_BASE;
1273 int adjust = iso_year_adjust (tim_p);
1274 int century = tim_p->tm_year >= 0
1275 ? tim_p->tm_year / 100 + YEAR_BASE / 100
1276 : abs (tim_p->tm_year + YEAR_BASE) / 100;
1277 int year = tim_p->tm_year >= 0 ? tim_p->tm_year % 100
1278 : abs (tim_p->tm_year + YEAR_BASE) % 100;
1279 if (adjust < 0 && tim_p->tm_year <= -YEAR_BASE)
1281 else if (adjust > 0 && neg)
1289 else if (year == 100)
1294 count += snprintf (&s[count], maxsize - count, "%s%.*d%.2d",
1295 neg ? "-" : "", 2 - neg, century, year);
1296 if (count >= maxsize)
1302 if (count < maxsize - 2)
1304 sprintf (&s[count], *format == 'k' ? "%2d" : "%.2d",
1313 if (count < maxsize - 2)
1315 if (tim_p->tm_hour == 0 ||
1316 tim_p->tm_hour == 12)
1323 sprintf (&s[count], *format == 'I' ? "%.2d" : "%2d",
1324 tim_p->tm_hour % 12);
1332 if (count < maxsize - 3)
1334 sprintf (&s[count], "%.3d",
1335 tim_p->tm_yday + 1);
1342 if (count < maxsize - 2)
1344 sprintf (&s[count], "%.2d",
1352 if (count < maxsize - 2)
1354 sprintf (&s[count], "%.2d",
1362 if (count < maxsize - 1)
1368 if (count < maxsize - 2)
1370 if (tim_p->tm_hour < 12)
1381 if (count < maxsize - 11)
1383 if (tim_p->tm_hour == 0 ||
1384 tim_p->tm_hour == 12)
1391 sprintf (&s[count], "%.2d", tim_p->tm_hour % 12);
1395 sprintf (&s[count], "%.2d",
1399 sprintf (&s[count], "%.2d",
1403 if (tim_p->tm_hour < 12)
1414 if (count < maxsize - 5)
1416 sprintf (&s[count], "%.2d:%.2d", tim_p->tm_hour, tim_p->tm_min);
1423 if (count < maxsize - 2)
1425 sprintf (&s[count], "%.2d",
1433 if (count < maxsize - 1)
1440 if (count < maxsize - 8)
1442 sprintf (&s[count], "%.2d:%.2d:%.2d", tim_p->tm_hour,
1443 tim_p->tm_min, tim_p->tm_sec);
1450 if (count < maxsize - 1)
1452 if (tim_p->tm_wday == 0)
1455 s[count++] = '0' + tim_p->tm_wday;
1461 if (count < maxsize - 2)
1463 sprintf (&s[count], "%.2d",
1464 (tim_p->tm_yday + 7 -
1465 tim_p->tm_wday) / 7);
1472 if (count < maxsize - 2)
1474 int adjust = iso_year_adjust (tim_p);
1475 int wday = (tim_p->tm_wday) ? tim_p->tm_wday - 1 : 6;
1476 int week = (tim_p->tm_yday + 10 - wday) / 7;
1479 else if (adjust < 0)
1480 /* Previous year has 53 weeks if current year starts on
1481 Fri, and also if current year starts on Sat and
1482 previous year was leap year. */
1483 week = 52 + (4 >= (wday - tim_p->tm_yday
1484 - isleap (tim_p->tm_year
1486 - (tim_p->tm_year < 0
1488 sprintf (&s[count], "%.2d", week);
1495 if (count < maxsize - 1)
1496 s[count++] = '0' + tim_p->tm_wday;
1501 if (count < maxsize - 2)
1503 int wday = (tim_p->tm_wday) ? tim_p->tm_wday - 1 : 6;
1504 sprintf (&s[count], "%.2d",
1505 (tim_p->tm_yday + 7 - wday) / 7);
1512 if (count < maxsize - 2)
1514 /* Be careful of both overflow and negative years, thanks to
1515 the asymmetric range of years. */
1516 int year = tim_p->tm_year >= 0 ? tim_p->tm_year % 100
1517 : abs (tim_p->tm_year + YEAR_BASE) % 100;
1518 sprintf (&s[count], "%.2d", year);
1526 /* Length is not known because of %C%y, so recurse. */
1527 size_t adjust = strftime (&s[count], maxsize - count,
1537 if (tim_p->tm_isdst >= 0)
1539 if (count < maxsize - 5)
1542 __tzinfo_type *tz = __gettzinfo ();
1544 /* The sign of this is exactly opposite the envvar TZ. We
1545 could directly use the global _timezone for tm_isdst==0,
1546 but have to use __tzrule for daylight savings. */
1547 offset = -tz->__tzrule[tim_p->tm_isdst > 0].offset;
1549 sprintf (&s[count], "%+03ld%.2ld", offset / SECSPERHOUR,
1550 labs (offset / SECSPERMIN) % 60L);
1559 if (tim_p->tm_isdst >= 0)
1563 size = strlen(_tzname[tim_p->tm_isdst > 0]);
1564 for (i = 0; i < size; i++)
1566 if (count < maxsize - 1)
1567 s[count++] = _tzname[tim_p->tm_isdst > 0][i];
1578 if (count < maxsize - 1)