aboutsummaryrefslogblamecommitdiffstats
path: root/get-contact-birthday.c
blob: 29be768c152c45e21086021c28ad2a1b4aed0c3a (plain) (tree)































































































































































                                                                                                                                       
/* See LICENSE file for copyright and license details. */
#include "common.h"

USAGE("[-n] contact-id ...");


static int
get_age(struct libcontacts_birthday *bday, const struct tm *now)
{
	int age = now->tm_year + 1900 - (int)bday->year;
	if (now->tm_mon + 1 < bday->month)
		age -= 1;
	else if (now->tm_mon + 1 == bday->month)
		age -= (now->tm_mday < bday->day);
	return age;
}

static void
print_birthdate(struct libcontacts_birthday *bday, const struct tm *now)
{
	int age;
	if (bday->year)
		printf("%04u-", bday->year);
	else
		printf("??""??""-");
	if (bday->month) {
		printf("(%02u)%.3s-", (unsigned)bday->month,
		       &"JanFebMarAprMayJunJulAugSepOctNovDec"[3 * ((bday->month - 1) % 12)]);
	} else {
		printf("(??"")??""?-");
	}
	if (bday->day)
		printf("%02u", (unsigned)bday->day);
	else
		printf("??");
	if ((bday->month - 1) % 12 == 1 && bday->day == 29) {
		bday->day -= bday->before_on_common;
		printf(" (%s on common years)", bday->before_on_common ? "(02)Feb-28" : "(03)Mar-01");
	}
	if (bday->year && bday->month && bday->day) {
		age = get_age(bday, now);
		printf(", %i %s old today", age, age == 1 ? "year" : "years");
	}
	printf("\n");
}

static void
print_birthday(struct libcontacts_birthday *bday, const struct tm *now)
{
	static const int days_in_month[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
	int next_year = 0, leap_year = 0, year, age, days = 0, y, m, d;
	struct tm when;
	if (now->tm_mon + 1 > bday->month)
		next_year = 1;
	else if (now->tm_mon + 1 == bday->month)
		next_year = (now->tm_mday > bday->day);
	if (bday->year) {
		printf("%04i-", now->tm_year + next_year + 1900);
	} else {
		printf("??""??""-");
	}
	year = now->tm_year + next_year + 1900;
	if (year % 4 == 0 && (year % 100 || year % 400 == 0))
		leap_year = 1;
	if (((bday->month - 1) % 12 == 1 && bday->day == 29) && leap_year) {
		if (bday->before_on_common) {
			bday->day -= 1;
		} else {
			bday->day = 1;
			bday->month += 1;
		}
	}
	printf("(%02u)%.3s-%02u (", (unsigned)bday->month % 12,
	       &"JanFebMarAprMayJunJulAugSepOctNovDec"[3 * ((bday->month - 1) % 12)], (unsigned)bday->day);
	when.tm_year = now->tm_year + next_year;
	when.tm_mon = (bday->month - 1) % 12;
	when.tm_mday = bday->day;
	if (bday->year) {
		age = get_age(bday, &when);
		printf("%i %s ", age, age == 1 ? "year" : "years");
	}
	if (when.tm_mon == now->tm_mon && when.tm_mday == now->tm_mday) {
		printf("today)\n");
	} else {
		y = now->tm_year;
		m = now->tm_mon;
		d = now->tm_mday;
		while (m != when.tm_mon || d > when.tm_mday) {
			days += days_in_month[m] - (d - 1);
			days += (m == 1 && y % 4 == 0 && (y % 100 || y % 400 == 0));
			d = 1;
			if (++m == 12) {
				y += 1;
				m = 0;
			}
		}
		days += when.tm_mday - d;
		printf("in %i %s)\n", days, days == 1 ? "day" : "days");
	}
	
}

int
main(int argc, char *argv[])
{
	int next = 0;
	struct passwd *user;
	struct libcontacts_contact contact;
	struct tm *now;
	time_t tim;
	int ret = 0;
	size_t i;

	ARGBEGIN {
	case 'n':
		next = 1;
		break;
	default:
		usage();
	} ARGEND;

	if (!argc)
		usage();

	for (i = 0; argv[i]; i++)
		if (!*argv[i] || strchr(argv[i], '/'))
			usage();

	errno = 0;
	user = getpwuid(getuid());
	if (!user)
		eprintf("getpwuid: %s\n", errno ? strerror(errno) : "user does not exist");

	tim = time(NULL);
	now = localtime(&tim);
	if (!now)
		eprintf("localtime:");

	for (; *argv; argv++) {
		if (libcontacts_load_contact(*argv, &contact, user)) {
			weprintf("libcontacts_load_contact %s: %s\n", *argv, errno ? strerror(errno) : "contact file is malformatted");
			ret = 1;
		} else {
			if (contact.birthday) {
				if (next) {
					print_birthday(contact.birthday, now);
				} else if (contact.birthday->month && contact.birthday->year) {
					if (argc > 1)
						printf("%s: ", *argv);
					print_birthdate(contact.birthday, now);
				}
			}
			libcontacts_contact_destroy(&contact);
		}
	}

	if (fflush(stdout) || ferror(stdout) || fclose(stdout))
		eprintf("printf:");
	return ret;
}