scc

A fork of https://git.simple-cc.org/scc/ for Qute

git clone https://git.8pit.net/scc.git

  1#include <string.h>
  2#include <time.h>
  3
  4#include "../libc.h"
  5
  6#undef strftime
  7
  8static char *days[] = {
  9	"Sunday",   "Monday", "Tuesday",  "Wednesday",
 10	"Thursday", "Friday", "Saturday",
 11};
 12
 13static char *months[] = {
 14	"January",   "February", "March",    "April",
 15	"May",       "June",     "July",     "August",
 16	"September", "October",  "November", "December"
 17};
 18
 19static char *am_pm[] = {"AM", "PM"};
 20
 21static int
 22first(int day, int year)
 23{
 24	int ny;
 25
 26	ny = _newyear(year);
 27	if (ny == day)
 28		return 0;
 29	if (day - ny < 0)
 30		return 7 - (ny - day);
 31	return day - ny;
 32}
 33
 34static int
 35weeknum(const struct tm *tm, int day)
 36{
 37	int fday, val;
 38
 39	fday = first(day, tm->tm_year);
 40	if (tm->tm_yday < fday) {
 41		val = 0;
 42	} else {
 43		val = tm->tm_yday - fday;
 44		val /= 7;
 45		val++;
 46	}
 47	return val;
 48}
 49
 50static int
 51isoyear(const struct tm *tm)
 52{
 53	int monday;
 54
 55	if (tm->tm_yday < 7) {
 56		monday = first(THU, tm->tm_year) - 3;
 57		if (tm->tm_yday < monday)
 58			return tm->tm_year - 1;
 59	} else if (tm->tm_yday > 357) {
 60		monday = first(THU, tm->tm_year + 1) - 3;
 61		if (tm->tm_mday >= (31 + monday))
 62			return tm->tm_year + 1;
 63	}
 64	return tm->tm_year;
 65}
 66
 67static int
 68isoweek(const struct tm *tm)
 69{
 70	int year, monday, yday, val;
 71
 72	year = isoyear(tm);
 73	monday = first(THU, year) - 3;
 74	yday = tm->tm_yday;
 75	if (year > tm->tm_year)
 76		yday = tm->tm_mday - 31 + monday;
 77	else if (year < tm->tm_year)
 78		yday = _daysyear(year) + yday;
 79	val = yday - monday;
 80	val /= 7;
 81	val++;
 82	return val;
 83}
 84
 85static int
 86isoday(const struct tm *tm)
 87{
 88	if (tm->tm_wday == 0)
 89		return 7;
 90	return tm->tm_wday;
 91}
 92
 93static size_t
 94sval(char *s, size_t siz, char **strs, int abrev, int idx, int max)
 95{
 96	char *str;
 97	size_t len;
 98
 99	if (siz == 0)
100		return 0;
101
102	if (idx < 0 || idx >= max) {
103		*s = '?';
104		return 1;
105	}
106
107	str = strs[idx];
108	len = (!abrev) ? strlen(str) : 3;
109	if (len > siz)
110		len = siz;
111
112	memcpy(s, str, len);
113	return len;
114}
115
116static size_t
117dval(char *s, size_t siz, int prec, int fill, int val)
118{
119	char *t;
120	int n;
121	static char digits[] = "0123456789";
122
123	if (siz == 0)
124		return 0;
125
126	if (prec > siz)
127		prec = siz;
128
129	if (val < 0) {
130		*s = '?';
131		return 1;
132	}
133
134	n = prec;
135	do {
136		s[--n] = digits[val % 10];
137		val /= 10;
138	} while (n > 0 && val > 0);
139
140	while (n > 0)
141		s[--n] = fill;
142
143	return prec;
144}
145
146static size_t
147timezone(char *s, size_t siz, const struct tm * restrict tm)
148{
149	size_t n;
150	long off = tm->tm_gmtoff;
151
152	if (off >= 0) {
153		*s = '+';
154	} else {
155		*s = '-';
156		off = -off;
157	}
158
159	n = 1;
160	n += dval(s + n, siz-n, 2, '0', off / 3600);
161	n += dval(s + n, siz-n, 2, '0', (off % 3600) / 60);
162
163	return n;
164}
165
166size_t
167strftime(char *restrict s, size_t maxsize,
168	 const char *restrict format, const struct tm *restrict timeptr)
169{
170	int ch, abrev, val, fill, width;
171	size_t n, inc;
172	char *tfmt, *begin;
173
174	begin = s;
175	for (n = maxsize; (ch = *format++) && n > 0; s += inc, n -= inc) {
176		if (ch != '%') {
177			*s = ch;
178			inc = 1;
179			continue;
180		}
181
182		abrev = 0;
183		fill = '0';
184		width = 2;
185
186		if (*format == 'E' || *format == 'O')
187			format++;
188
189		switch (*format++) {
190		case 'a':
191			abrev = 1;
192		case 'A':
193			inc = sval(s, n, days, abrev, timeptr->tm_wday, 7);
194			break;
195		case 'h':
196		case 'b':
197			abrev = 1;
198		case 'B':
199			inc = sval(s, n, months, abrev, timeptr->tm_mon, 12);
200			break;
201		case 'c':
202			tfmt = "%a %b %e %T %Y";
203			goto recursive;
204		case 'C':
205			val = (timeptr->tm_year + 1900) / 100;
206			goto number;
207		case 'd':
208			val = timeptr->tm_mday;
209			goto number;
210		case 'D':
211			tfmt = "%m/%d/%y";
212			goto recursive;
213		case 'e':
214			fill = ' ';
215			val = timeptr->tm_mday;
216			goto number;
217		case 'F':
218			tfmt = "%Y-%m-%d";
219			goto recursive;
220		case 'g':
221			val = isoyear(timeptr);
222			goto number;
223		case 'G':
224			val = isoyear(timeptr);
225			val += 1900;
226			width = 4;
227			goto number;
228		case 'H':
229			val = timeptr->tm_hour;
230			goto number;
231		case 'I':
232			val = timeptr->tm_hour;
233			if (val == 0)
234				val = 12;
235			if (val > 12)
236				val -= 12;
237			goto number;
238		case 'j':
239			width = 3;
240			val = timeptr->tm_yday+1;
241			goto number;
242		case 'm':
243			val = timeptr->tm_mon+1;
244			goto number;
245		case 'M':
246			val = timeptr->tm_min;
247			goto number;
248		case 'n':
249			val = '\n';
250			goto character;
251		case 'p':
252			inc = sval(s, n, am_pm, 0, timeptr->tm_hour > 12, 2);
253			break;
254		case 'r':
255			tfmt = "%I:%M:%S %p";
256			goto recursive;
257		case 'R':
258			tfmt = "%H:%M";
259			goto recursive;
260		case 'S':
261			val = timeptr->tm_sec;
262			goto number;
263		case 't':
264			val = '\t';
265			goto character;
266		case 'u':
267			width = 1;
268			val = isoday(timeptr);
269			goto number;
270		case 'U':
271			val = weeknum(timeptr, SUN);
272			goto number;
273		case 'V':
274			val = isoweek(timeptr);
275			goto number;
276		case 'w':
277			width = 1;
278			val = timeptr->tm_wday;
279			goto number;
280		case 'W':
281			val = weeknum(timeptr, MON);
282			goto number;
283		case 'X':
284		case 'T':
285			tfmt = "%H:%M:%S";
286			goto recursive;
287		case 'x':
288			tfmt = "%m/%d/%y";
289			goto recursive;
290		case 'y':
291			val = timeptr->tm_year%100;
292			goto number;
293		case 'Y':
294			width = 4;
295			val = 1900 + timeptr->tm_year;
296			goto number;
297		case 'z':
298			inc = timezone(s, n, timeptr);
299			break;
300		case 'Z':
301			inc = strlen(timeptr->tm_zone);
302			if (inc > n)
303				inc = n;
304			memcpy(s, timeptr->tm_zone, inc);
305			break;
306		case '\0':
307			inc = 0;
308			--format;
309			break;
310		case '%':
311			val = '%';
312		character:
313			*s = val;
314			inc = 1;
315			break;
316		number:
317			inc = dval(s, n, width, fill, val);
318			break;
319		recursive:
320			inc = strftime(s, n+1, tfmt, timeptr);
321			break;
322		}
323	}
324
325	n = s - begin;
326	if (n == maxsize)
327		return 0;
328	*s = '\0';
329
330	return n;
331}