/* * COPYRIGHT: LGPL, See LGPL.txt in the top level directory * PROJECT: ReactOS CRT library * FILE: lib/sdk/crt/time/strftime.c * PURPOSE: * PROGRAMER: */ #include static inline BOOL strftime_date(char *str, size_t *pos, size_t max, BOOL alternate, const struct tm *mstm, MSVCRT___lc_time_data *time_data) { char *format; SYSTEMTIME st; size_t ret; st.wYear = mstm->tm_year + 1900; st.wMonth = mstm->tm_mon + 1; st.wDayOfWeek = mstm->tm_wday; st.wDay = mstm->tm_mday; st.wHour = mstm->tm_hour; st.wMinute = mstm->tm_min; st.wSecond = mstm->tm_sec; st.wMilliseconds = 0; format = alternate ? time_data->str.names.date : time_data->str.names.short_date; ret = GetDateFormatA(time_data->lcid, 0, &st, format, NULL, 0); if(ret && retlcid, 0, &st, format, str+*pos, max-*pos); if(!ret) { *str = 0; *_errno() = EINVAL; return FALSE; }else if(ret > max-*pos) { *str = 0; *_errno() = ERANGE; return FALSE; } *pos += ret-1; return TRUE; } static inline BOOL strftime_time(char *str, size_t *pos, size_t max, const struct tm *mstm, MSVCRT___lc_time_data *time_data) { SYSTEMTIME st; size_t ret; st.wYear = mstm->tm_year + 1900; st.wMonth = mstm->tm_mon + 1; st.wDayOfWeek = mstm->tm_wday; st.wDay = mstm->tm_mday; st.wHour = mstm->tm_hour; st.wMinute = mstm->tm_min; st.wSecond = mstm->tm_sec; st.wMilliseconds = 0; ret = GetTimeFormatA(time_data->lcid, 0, &st, time_data->str.names.time, NULL, 0); if(ret && retlcid, 0, &st, time_data->str.names.time, str+*pos, max-*pos); if(!ret) { *str = 0; *_errno() = EINVAL; return FALSE; }else if(ret > max-*pos) { *str = 0; *_errno() = ERANGE; return FALSE; } *pos += ret-1; return TRUE; } static inline BOOL strftime_str(char *str, size_t *pos, size_t max, char *src) { size_t len = strlen(src); if(len > max-*pos) { *str = 0; *_errno() = ERANGE; return FALSE; } memcpy(str+*pos, src, len); *pos += len; return TRUE; } static inline BOOL strftime_int(char *str, size_t *pos, size_t max, int src, int prec, int l, int h) { size_t len; if(srch) { *str = 0; *_errno() = EINVAL; return FALSE; } len = _snprintf(str+*pos, max-*pos, "%0*d", prec, src); if(len == -1) { *str = 0; *_errno() = ERANGE; return FALSE; } *pos += len; return TRUE; } /********************************************************************* * _Strftime (MSVCRT.@) */ size_t CDECL _Strftime(char *str, size_t max, const char *format, const struct tm *mstm, MSVCRT___lc_time_data *time_data) { size_t ret, tmp; BOOL alternate; TRACE("(%p %ld %s %p %p)\n", str, max, format, mstm, time_data); if(!str || !format) { if(str && max) *str = 0; *_errno() = EINVAL; return 0; } if(!time_data) time_data = get_locinfo()->lc_time_curr; for(ret=0; *format && rettm_wday<0 || mstm->tm_wday>6) goto einval_error; if(!strftime_str(str, &ret, max, time_data->str.names.short_wday[mstm->tm_wday])) return 0; break; case 'A': if(mstm->tm_wday<0 || mstm->tm_wday>6) goto einval_error; if(!strftime_str(str, &ret, max, time_data->str.names.wday[mstm->tm_wday])) return 0; break; case 'b': if(mstm->tm_mon<0 || mstm->tm_mon>11) goto einval_error; if(!strftime_str(str, &ret, max, time_data->str.names.short_mon[mstm->tm_mon])) return 0; break; case 'B': if(mstm->tm_mon<0 || mstm->tm_mon>11) goto einval_error; if(!strftime_str(str, &ret, max, time_data->str.names.mon[mstm->tm_mon])) return 0; break; case 'd': if(!strftime_int(str, &ret, max, mstm->tm_mday, alternate ? 0 : 2, 0, 31)) return 0; break; case 'H': if(!strftime_int(str, &ret, max, mstm->tm_hour, alternate ? 0 : 2, 0, 23)) return 0; break; case 'I': tmp = mstm->tm_hour; if(tmp > 12) tmp -= 12; else if(!tmp) tmp = 12; if(!strftime_int(str, &ret, max, tmp, alternate ? 0 : 2, 1, 12)) return 0; break; case 'j': if(!strftime_int(str, &ret, max, mstm->tm_yday+1, alternate ? 0 : 3, 1, 366)) return 0; break; case 'm': if(!strftime_int(str, &ret, max, mstm->tm_mon+1, alternate ? 0 : 2, 1, 12)) return 0; break; case 'M': if(!strftime_int(str, &ret, max, mstm->tm_min, alternate ? 0 : 2, 0, 59)) return 0; break; case 'p': if(mstm->tm_hour<0 || mstm->tm_hour>23) goto einval_error; if(!strftime_str(str, &ret, max, mstm->tm_hour<12 ? time_data->str.names.am : time_data->str.names.pm)) return 0; break; case 'S': if(!strftime_int(str, &ret, max, mstm->tm_sec, alternate ? 0 : 2, 0, 59)) return 0; break; case 'w': if(!strftime_int(str, &ret, max, mstm->tm_wday, 0, 0, 6)) return 0; break; case 'y': if(!strftime_int(str, &ret, max, mstm->tm_year%100, alternate ? 0 : 2, 0, 99)) return 0; break; case 'Y': tmp = 1900+mstm->tm_year; if(!strftime_int(str, &ret, max, tmp, alternate ? 0 : 4, 0, 9999)) return 0; break; case 'z': case 'Z': _tzset(); if(_get_tzname(&tmp, str+ret, max-ret, mstm->tm_isdst ? 1 : 0)) return 0; ret += tmp; break; case 'U': case 'W': if(mstm->tm_wday<0 || mstm->tm_wday>6 || mstm->tm_yday<0 || mstm->tm_yday>365) goto einval_error; if(*format == 'U') tmp = mstm->tm_wday; else if(!mstm->tm_wday) tmp = 6; else tmp = mstm->tm_wday-1; tmp = mstm->tm_yday/7 + (tmp <= ((unsigned)mstm->tm_yday%7)); if(!strftime_int(str, &ret, max, tmp, alternate ? 0 : 2, 0, 53)) return 0; break; case '%': str[ret++] = '%'; break; default: WARN("unknown format %c\n", *format); goto einval_error; } } if(ret == max) { if(max) *str = 0; *_errno() = ERANGE; return 0; } str[ret] = 0; return ret; einval_error: *str = 0; *_errno() = EINVAL; return 0; } /********************************************************************* * strftime (MSVCRT.@) */ size_t CDECL strftime( char *str, size_t max, const char *format, const struct tm *mstm ) { return _Strftime(str, max, format, mstm, NULL); } /********************************************************************* * wcsftime (MSVCRT.@) */ size_t CDECL wcsftime( wchar_t *str, size_t max, const wchar_t *format, const struct tm *mstm ) { char *s, *fmt; size_t len; TRACE("%p %ld %s %p\n", str, max, debugstr_w(format), mstm ); len = WideCharToMultiByte( CP_ACP, 0, format, -1, NULL, 0, NULL, NULL ); if (!(fmt = malloc( len ))) return 0; WideCharToMultiByte( CP_ACP, 0, format, -1, fmt, len, NULL, NULL ); if ((s = malloc( max*4 ))) { if (!strftime( s, max*4, fmt, mstm )) s[0] = 0; len = MultiByteToWideChar( CP_ACP, 0, s, -1, str, max ); if (len) len--; free( s ); } else len = 0; free( fmt ); return len; }