calendar

BSD calendar reimplementation
git clone https://git.ce9e.org/calendar.git

commit
230e49bd4ff02c5f7436b9dc101256db351e552c
parent
cee0783c737a66ac477878ba3f99c81135de4e2a
Author
Tobias Bengfort <tobias.bengfort@posteo.de>
Date
2023-06-04 12:27
feature: ranges

Diffstat

M calendar.c 55 ++++++++++++++++++++++++++++++++++++++++++++++++++++---
M test.c 33 +++++++++++++++++++++++++++++++++

2 files changed, 85 insertions, 3 deletions


diff --git a/calendar.c b/calendar.c

@@ -25,6 +25,7 @@
   25    25  *     1999/06/15*	June 15 (usefull for birthdays)
   26    26  *     1999/05/Sun+2	second Sunday in May 1999
   27    27  *     1999/06/15+2	June 15 1999 and every second week since then
   -1    28  *     1999/06/15:1999/06/20	From June 15 1999 to June 20 1999
   28    29  *
   29    30  *     # removed formats (mostly alternative formats)
   30    31  *     Jun. 15	06/15
@@ -51,6 +52,9 @@ struct tpl {
   51    52 	int year;
   52    53 	int month;
   53    54 	int day;
   -1    55 	int end_year;
   -1    56 	int end_month;
   -1    57 	int end_day;
   54    58 	int repeat;
   55    59 	int weekday;  /* starting with sunday */
   56    60 	int nth_of_month;
@@ -81,6 +85,9 @@ struct tpl mktpl(void) {
   81    85 		.year=0,
   82    86 		.month=0,
   83    87 		.day=0,
   -1    88 		.end_year=0,
   -1    89 		.end_month=0,
   -1    90 		.end_day=0,
   84    91 		.repeat=0,
   85    92 		.weekday=0,
   86    93 		.nth_of_month=0,
@@ -141,11 +148,38 @@ bool date_comp(struct tm a, struct tm b) {
  141   148 }
  142   149 
  143   150 bool is_match(struct tpl tpl, struct tm date) {
   -1   151 	struct tm reference;
   -1   152 	time_t delta;
   -1   153 	int delta_days;
   -1   154 
   -1   155 	if (tpl.end_day) {
   -1   156 		if (tpl.day && tpl.month && tpl.year && tpl.end_month && tpl.end_year) {
   -1   157 			reference = mkdate(tpl.year, tpl.month, tpl.day);
   -1   158 			delta = difftime(mktime(&reference), mktime(&date));
   -1   159 			delta_days = delta / 60 / 60 / 24;
   -1   160 			if (delta_days > 0) {
   -1   161 				return false;
   -1   162 			}
   -1   163 
   -1   164 			reference = mkdate(tpl.end_year, tpl.end_month, tpl.end_day);
   -1   165 			delta = difftime(mktime(&reference), mktime(&date));
   -1   166 			delta_days = delta / 60 / 60 / 24;
   -1   167 			if (delta_days < 0) {
   -1   168 				return false;
   -1   169 			}
   -1   170 
   -1   171 			return true;
   -1   172 		} else {
   -1   173 			fprintf(stderr, "Error: incomplete range\n");
   -1   174 			exit(1);
   -1   175 		}
   -1   176 	}
   -1   177 
  144   178 	if (tpl.repeat) {
  145   179 		if (tpl.day && tpl.month && tpl.year) {
  146    -1 			struct tm reference = mkdate(tpl.year, tpl.month, tpl.day);
  147    -1 			time_t delta = difftime(mktime(&reference), mktime(&date));
  148    -1 			int delta_days = delta / 60 / 60 / 24;
   -1   180 			reference = mkdate(tpl.year, tpl.month, tpl.day);
   -1   181 			delta = difftime(mktime(&reference), mktime(&date));
   -1   182 			delta_days = delta / 60 / 60 / 24;
  149   183 			if (delta_days % (7 * tpl.repeat) != 0) {
  150   184 				return false;
  151   185 			}
@@ -268,6 +302,21 @@ struct tpl parse_date(char *s) {
  268   302 		if (!star) {
  269   303 			tpl.year = match.tm_year + 1900;
  270   304 		}
   -1   305 		if (strchr(s, ':')) {
   -1   306 			strtok(s, ":");
   -1   307 			char *s_n = strtok(NULL, "");
   -1   308 			if (s_n == NULL) {
   -1   309 				invalid_date(s);
   -1   310 				exit(1);
   -1   311 			} else if (strptime(s_n, "%Y/%m/%d", &match)) {
   -1   312 				tpl.end_month = match.tm_mon + 1;
   -1   313 				tpl.end_day = match.tm_mday;
   -1   314 				tpl.end_year = match.tm_year + 1900;
   -1   315 			} else {
   -1   316 				invalid_date(s);
   -1   317 				exit(1);
   -1   318 			}
   -1   319 		}
  271   320 		tpl.repeat = n;
  272   321 		return tpl;
  273   322 	} else if (strptime(s, "%m/%d", &match)) {

diff --git a/test.c b/test.c

@@ -171,6 +171,20 @@ char *test_parse_date_yyyymmdd_repeat(void) {
  171   171 	return 0;
  172   172 }
  173   173 
   -1   174 char *test_parse_date_range(void) {
   -1   175 	struct tpl actual = parse_date_mut("1999/03/01:2000/05/02");
   -1   176 	struct tpl expected = mktpl();
   -1   177 	expected.year = 1999;
   -1   178 	expected.month = 3;
   -1   179 	expected.day = 1;
   -1   180 	expected.end_year = 2000;
   -1   181 	expected.end_month = 5;
   -1   182 	expected.end_day = 2;
   -1   183 
   -1   184 	mu_assert("1999/03/01:2000/05/02", tpl_comp(actual, expected));
   -1   185 	return 0;
   -1   186 }
   -1   187 
  174   188 char *test_parse_date_weekday(void) {
  175   189 	struct tpl actual = parse_date_mut("Sat");
  176   190 	struct tpl expected = mktpl();
@@ -288,6 +302,23 @@ char *test_is_match_yyyymmdd_repeat(void) {
  288   302 	return 0;
  289   303 }
  290   304 
   -1   305 char *test_is_match_range(void) {
   -1   306 	struct tpl tpl = mktpl();
   -1   307 	tpl.year = 1999;
   -1   308 	tpl.month = 2;
   -1   309 	tpl.day = 13;
   -1   310 	tpl.end_year = 2000;
   -1   311 	tpl.end_month = 3;
   -1   312 	tpl.end_day = 15;
   -1   313 
   -1   314 	mu_assert("start does match", is_match(tpl, mkdate(1999, 2, 13)));
   -1   315 	mu_assert("end does match", is_match(tpl, mkdate(2000, 3, 15)));
   -1   316 	mu_assert("between does match", is_match(tpl, mkdate(1999, 8, 2)));
   -1   317 	mu_assert("before start does not match", !is_match(tpl, mkdate(1999, 2, 12)));
   -1   318 	mu_assert("after end does not match", !is_match(tpl, mkdate(2000, 3, 16)));
   -1   319 	return 0;
   -1   320 }
   -1   321 
  291   322 char *test_is_match_weekday(void) {
  292   323 	struct tpl tpl = mktpl();
  293   324 	tpl.weekday = 7;
@@ -400,6 +431,7 @@ int main(int argc, char **argv) {
  400   431 	mu_test("parses yyyy/mm/dd", test_parse_date_yyyymmdd);
  401   432 	mu_test("parses yyyy/mm/dd*", test_parse_date_yyyymmdd_star);
  402   433 	mu_test("parses yyyy/mm/dd+n", test_parse_date_yyyymmdd_repeat);
   -1   434 	mu_test("parses yyyy/mm/dd:yyyy/mm/dd", test_parse_date_range);
  403   435 	mu_test("parses weekday", test_parse_date_weekday);
  404   436 	mu_test("parses weekday+n", test_parse_date_weekday_with_nth_of_month);
  405   437 	mu_test("parses weekday-n", test_parse_date_weekday_with_nth_last_of_month);
@@ -413,6 +445,7 @@ int main(int argc, char **argv) {
  413   445 	mu_test("matches mm/dd", test_is_match_mmdd);
  414   446 	mu_test("matches yyyy/mm/dd", test_is_match_yyyymmdd);
  415   447 	mu_test("matches yyyy/mm/dd+n", test_is_match_yyyymmdd_repeat);
   -1   448 	mu_test("matches yyyy/mm/dd:yyyy/mm/dd", test_is_match_range);
  416   449 	mu_test("matches weekday", test_is_match_weekday);
  417   450 	mu_test("matches weekday+n", test_is_match_weekday_with_nth_of_month);
  418   451 	mu_test("matches weekday-n", test_is_match_weekday_with_nth_last_of_month);