/*
* Copyright (c) 2008-2024 Jonathan Schleifer <js@nil.im>
*
* All rights reserved.
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License version 3.0 only,
* as published by the Free Software Foundation.
*
* This program 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
* version 3.0 for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* version 3.0 along with this program. If not, see
* <https://www.gnu.org/licenses/>.
*/
#include "config.h"
#include <string.h>
#include <time.h>
#import "OFStrFTime.h"
#import "macros.h"
static const char weekDays[7][4] = {
"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
};
static const char monthNames[12][4] = {
"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct",
"Nov", "Dec"
};
size_t
_OFStrFTime(char *buffer, size_t bufferLen, const char *format, struct tm *tm,
short tz)
{
enum {
stateSearchConversionSpecifier,
stateInConversionSpecifier
} state = stateSearchConversionSpecifier;
size_t j, formatLen;
if (bufferLen == 0)
return 0;
formatLen = strlen(format);
j = 0;
for (size_t i = 0; i < formatLen; i++) {
switch (state) {
case stateSearchConversionSpecifier:
if (format[i] == '%')
state = stateInConversionSpecifier;
else {
if (j >= bufferLen)
return 0;
buffer[j++] = format[i];
}
break;
case stateInConversionSpecifier:;
const char *appendFormat;
unsigned int value = 0;
char append[5];
int appendLen;
switch (format[i]) {
case '%':
appendFormat = "%%";
break;
case 'a':
if (tm->tm_wday > 6)
return 0;
appendFormat = weekDays[tm->tm_wday];
break;
case 'b':
if (tm->tm_mon > 11)
return 0;
appendFormat = monthNames[tm->tm_mon];
break;
case 'd':
appendFormat = "%02u";
value = tm->tm_mday;
break;
case 'e':
appendFormat = "%2u";
value = tm->tm_mday;
break;
case 'H':
appendFormat = "%02u";
value = tm->tm_hour;
break;
case 'M':
appendFormat = "%02u";
value = tm->tm_min;
break;
case 'm':
appendFormat = "%02u";
value = tm->tm_mon + 1;
break;
case 'n':
appendFormat = "\n";
break;
case 'S':
appendFormat = "%02u";
value = tm->tm_sec;
break;
case 't':
appendFormat = "\t";
break;
case 'Y':
appendFormat = "%4u";
value = tm->tm_year + 1900;
break;
case 'y':
appendFormat = "%02u";
value = tm->tm_year;
while (value > 100)
value -= 100;
break;
case 'z':
if (tz == 0)
appendFormat = "Z";
else if (tz >= 0) {
appendFormat = "+%04u";
value = tz;
} else {
appendFormat = "-%04u";
value = -tz;
}
value = (value / 60) * 100 + (value % 60);
break;
default:
return 0;
}
appendLen = snprintf(append, sizeof(append),
appendFormat, value);
if (appendLen < 0 ||
(size_t)appendLen >= sizeof(append))
return 0;
if (bufferLen - j < (size_t)appendLen)
return 0;
memcpy(buffer + j, append, appendLen);
j += appendLen;
state = stateSearchConversionSpecifier;
}
}
if (j >= bufferLen)
return 0;
buffer[j] = 0;
return j;
}