1#include "config.h"
2#include "ntp_calendar.h"
3
4#include <stdlib.h>
5#include <errno.h>
6
7#include "ntp_types.h"
8#include "ntp_fp.h"
9#include "vint64ops.h"
10
11/*
12 * If we're called with 1 arg, it's a u_long timestamp.
13 * If we're called with 3 args, we're expecting YYYY MM DD,
14 *   and MM must be 6 or 12, and DD must be 28,
15 * If we're called with 2 args, we're expecting YYYY MM, and
16 *   MM mst be 6 or 12, and we assume DD is 28.
17 */
18
19char *progname;
20static const char *MONTHS[] =
21                { "January", "February", "March", "April", "May", "June",
22		  "July", "August", "September", "October", "November",
23		  "December" };
24
25void usage(void);
26
27void
28usage(void)
29{
30	printf("Usage:\n");
31	printf(" %s nnnnnn\n", progname);
32	printf(" %s YYYY [6|12]\n", progname);
33	printf(" %s YYYY [6|12] 28\n", progname);
34
35	return;
36}
37
38
39int
40main(
41	int	argc,		/* command line options */
42	char	**argv		/* poiniter to list of tokens */
43	)
44{
45	int err = 0;
46	vint64 expires;
47	unsigned int year = 0;
48	unsigned int mon = 0;
49	unsigned int dom = 0;
50	int scount;
51	char *ep;
52	struct calendar cal = {0};
53
54	progname = argv[0];
55
56	switch(argc) {
57	 case 2:	/* 1 arg, must be a string of digits */
58		expires = strtouv64(argv[1], &ep, 10);
59
60		if (0 == *ep) {
61			ntpcal_ntp64_to_date(&cal, &expires);
62
63			printf("%02u %s %04u %02u:%02u:%02u\n"
64				, cal.monthday
65				, MONTHS[cal.month - 1]
66				, cal.year
67				, cal.hour
68				, cal.minute
69				, cal.second
70				);
71
72			exit(0);
73		} else {
74			printf("1 arg, but not a string of digits: <%s>\n",
75				argv[1]);
76			err = 1;
77		}
78		break;
79		;;
80	 case 3:	/* 2 args, must be YY MM, where MM is 6 or 12 */
81		dom = 28;
82		scount = sscanf(argv[1], "%u", &year);
83		if (1 == scount) {
84			// printf("2 args: year %u\n", year);
85		} else {
86			printf("2 args, but #1 is not a string of digits: <%s>\n", argv[1]);
87			err = 1;
88		}
89
90		scount = sscanf(argv[2], "%u", &mon);
91		if (1 == scount) {
92			if (6 == mon || 12 == mon) {
93				// printf("2 args: month %u\n", mon);
94			} else {
95				printf("2 arg, but #2 is not 6 or 12: <%d>\n", mon);
96				err = 1;
97			}
98		} else {
99			printf("2 arg, but #2 is not a string of digits: <%s>\n", argv[2]);
100			err = 1;
101		}
102
103		break;
104		;;
105	 case 4:	/* 3 args, YY MM DD, where MM is 6 or 12, DD is 28 */
106		scount = sscanf(argv[1], "%u", &year);
107		if (1 == scount) {
108			// printf("3 args: year %u\n", year);
109		} else {
110			printf("3 args, but #1 is not a string of digits: <%s>\n", argv[1]);
111			err = 1;
112		}
113
114		scount = sscanf(argv[2], "%u", &mon);
115		if (1 == scount) {
116			if (6 == mon || 12 == mon) {
117				// printf("3 args: month %u\n", mon);
118			} else {
119				printf("3 arg, but #2 is not 6 or 12: <%d>\n", mon);
120				err = 1;
121			}
122		} else {
123			printf("3 arg, but #2 is not a string of digits: <%s>\n", argv[2]);
124			err = 1;
125		}
126
127		scount = sscanf(argv[3], "%u", &dom);
128		if (1 == scount) {
129			if (28 == dom) {
130				// printf("3 args: dom %u\n", dom);
131			} else {
132				printf("3 arg, but #3 is not 28: <%d>\n", dom);
133				err = 1;
134			}
135		} else {
136			printf("3 arg, but #3 is not a string of digits: <%s>\n", argv[2]);
137			err = 1;
138		}
139
140		break;
141		;;
142	 default:
143		err = 1;
144		break;
145		;;
146	}
147
148	if (err) {
149		usage();
150		exit(err);
151	}
152
153	cal.year = year;
154	cal.month = mon;
155	cal.monthday = dom;
156	cal.hour = 0;
157	cal.minute = 0;
158	cal.second = 0;
159
160	printf("%u ", ntpcal_date_to_ntp(&cal));
161
162	printf("%02d %s %04d "
163		, cal.monthday
164		, MONTHS[cal.month - 1]
165		, cal.year
166		);
167	printf("\n");
168
169	exit(err);
170}
171
172#if 0
173
174
175void
176test_DateGivenMonthDay(void) {
177	// 2010-06-24 12:50:00
178	struct calendar input = {2010, 0, 6, 24, 12, 50, 0};
179
180	u_long expected = 3486372600UL; // This is the timestamp above.
181
182	TEST_ASSERT_EQUAL_UINT(expected, caltontp(&input));
183}
184
185void
186test_DateGivenYearDay(void) {
187	// 2010-06-24 12:50:00
188	// This is the 175th day of 2010.
189	struct calendar input = {2010, 175, 0, 0, 12, 50, 0};
190
191	u_long expected = 3486372600UL; // This is the timestamp above.
192
193	TEST_ASSERT_EQUAL_UINT(expected, caltontp(&input));
194}
195
196void
197test_DateLeapYear(void) {
198	// 2012-06-24 12:00:00
199	// This is the 176th day of 2012 (since 2012 is a leap year).
200	struct calendar inputYd = {2012, 176, 0, 0, 12, 00, 00};
201	struct calendar inputMd = {2012, 0, 6, 24, 12, 00, 00};
202
203	u_long expected = 3549528000UL;
204
205	TEST_ASSERT_EQUAL_UINT(expected, caltontp(&inputYd));
206	TEST_ASSERT_EQUAL_UINT(expected, caltontp(&inputMd));
207}
208
209void
210test_WraparoundDateIn2036(void) {
211	// 2036-02-07 06:28:16
212	// This is (one) wrapping boundary where we go from ULONG_MAX to 0.
213	struct calendar input = {2036, 0, 2, 7, 6, 28, 16};
214
215	u_long expected = 0UL;
216
217	TEST_ASSERT_EQUAL_UINT(expected, caltontp(&input));
218}
219
220#endif
221