aboutsummaryrefslogtreecommitdiffstats
path: root/libpatch_create_timestamp.c
blob: 54b6d91c576b11f800e96d25755d21b322b34ab1 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
/* See LICENSE file for copyright and license details. */
#include "common.h"


size_t
libpatch_create_timestamp(char *buf, size_t bufsize, const struct tm *tm,
                          uintmax_t subseconds, unsigned subseconds_decimals, 
                          unsigned frac, int zone, enum libpatch_style style)
{
	size_t guess, len, r;
	const char *fmt;

	frac = MIN(frac, subseconds_decimals);

	if (style == LIBPATCH_STYLE_COPIED) {
		fmt = "%a %b %e %T %Y";
		guess = sizeof("aaa bbb 00 00:00:00 0000");
	} else if (style == LIBPATCH_STYLE_UNIFIED) {
		fmt = "%Y-%m-%d %H:%M:%S";
		zone = 1;
		guess = sizeof("0000-00-00 00:00:00");
	} else {
		errno = EINVAL;
		return 0;
	}

	if (zone)
		guess += sizeof(" +0000");
	guess += (size_t)frac + (size_t)(frac > 0);

	if (!bufsize)
		return guess;

	while (subseconds_decimals != frac) {
		subseconds /= 10;
		subseconds_decimals -= 1;
	}

	len = strftime(buf, bufsize, fmt, tm);
	if (!len)
		return bufsize < guess ? guess : bufsize + 16U;

	if (frac) {
		if (len < bufsize)
			snprintf(&buf[len], bufsize - len, ".%0*ju", (int)frac, subseconds);
		len += (size_t)frac + (size_t)(frac > 0);
	}

	if (zone) {
		if (len < bufsize)
			return bufsize < len + 7U ? len + 7U : bufsize + 16U;
		len += r = strftime(&buf[len], bufsize - len, " %z", tm);
		if (!r)
			return bufsize < len + 7U ? len + 7U : bufsize + 16U;
	}

	return len + 1;
}