changeset 16:79d22407a6be

a lot of refactoring
author markus schnalke <meillo@marmaro.de>
date Mon, 24 Feb 2014 21:11:38 +0100
parents 032af48d590b
children d18a3b2b76bd
files Makefile bday.c
diffstat 2 files changed, 197 insertions(+), 210 deletions(-) [+]
line wrap: on
line diff
--- a/Makefile	Mon Feb 24 17:46:57 2014 +0100
+++ b/Makefile	Mon Feb 24 21:11:38 2014 +0100
@@ -1,81 +1,53 @@
 # bday by meillo@marmaro.de
 
 
-NAME=bday
-VERSION = 0.1
-NV=${NAME}-${VERSION}
+VERSION = 0.2
 
-DOCS=COPYRIGHT COPYING ChangeLog TODO examples
+DOCS=COPYRIGHT COPYING ChangeLog
 
 # paths
-PREFIX = /usr
+PREFIX = /usr/local
 BINDIR = ${PREFIX}/bin
 MANDIR = ${PREFIX}/share/man
 
-SRC=bday.c
-OBJ=$(SRC:.c=.o)
-
 CFLAGS=-O2 -Wall
 
 all: build
-
-build: ${NAME}
+build: bday
 
-${NAME}: $(OBJ)
-	$(CC) $(LDFLAGS) $(OBJ) -o $@
-
-car: clean all
+bday: bday.o
+	$(CC) $(LDFLAGS) bday.o -o $@
 
 dist: build changelog
-	@mkdir -p ${NV}
-	@cp -rf ${NAME} ${SRC} ${NAME}.1 Makefile ${DOCS} ${NV}
-	@tar -czhof ${NV}.tar.gz ${NV}
-	@rm -rf ${NV}
-
-deb: dist
-	@mkdir -p Packages
-	@cp ${NV}.tar.gz Packages/
-	@( \
-		cd Packages/ ;\
-		tar -xzf ${NV}.tar.gz ;\
-		mv ${NV}.tar.gz ${NAME}_${VERSION}.orig.tar.gz ;\
-		cd ${NV}/ ;\
-		cp -r ../../debian/ . ;\
-		debuild -sa ;\
-	 )
+	@mkdir -p bday-${VERSION}
+	@cp bday bday.c bday.1 Makefile ${DOCS} bday-${VERSION}
+	@tar -czhf bday-${VERSION}.tar.gz bday-${VERSION}
+	@rm -rf bday-${VERSION}
 
 changelog:
 	@echo generating changelog from mercurial log
 	@hg log -v --style changelog > ChangeLog
 
 install:
-	@echo installing executable file to ${DESTDIR}${BINDIR}
-	@mkdir -p ${DESTDIR}${BINDIR}
-	@cp ${NAME} ${DESTDIR}${BINDIR}
-	@chmod 755 ${DESTDIR}${BINDIR}/${NAME}
-	@echo installing manual page to ${DESTDIR}${MANDIR}/man1
-	@mkdir -p ${DESTDIR}${MANDIR}/man1
-	@sed 's/VERSION/${VERSION}/g' < ${NAME}.1 > ${DESTDIR}${MANDIR}/man1/${NAME}.1
-	@chmod 644 ${DESTDIR}${MANDIR}/man1/${NAME}.1
+	@echo installing executable file to ${BINDIR}
+	@mkdir -p ${BINDIR}
+	@cp bday ${BINDIR}
+	@chmod 755 ${BINDIR}/bday
+	@echo installing manual page to ${MANDIR}/man1
+	@mkdir -p ${MANDIR}/man1
+	@sed 's/VERSION/${VERSION}/g' <bday.1 >${MANDIR}/man1/bday.1
+	@chmod 644 ${MANDIR}/man1/bday.1
 
 uninstall:
-	@echo removing executable file from ${DESTDIR}${BINDIR}
-	@rm -f ${DESTDIR}${BINDIR}/${NAME}
-	@echo removing manual page from ${DESTDIR}${MANDIR}/man1
-	@rm -f ${DESTDIR}${MANDIR}/man1/${NAME}.1
+	@echo removing executable file from ${BINDIR}
+	@rm -f ${BINDIR}/bday
+	@echo removing manual page from ${MANDIR}/man1
+	@rm -f ${MANDIR}/man1/bday.1
 
 
 clean:
 	rm -f *.o
-
 realclean: clean
-	rm -f ${NAME}
-
+	rm -f bday
 distclean: realclean
-	@rm -f ${NAME}-*.tar.gz ChangeLog
-
-debclean: distclean
-	@cd Packages/${NV}/ ; debuild clean ;
-
-
-.PHONY: all dist deb changelog clean distclean debclean build install uninstall
+	@rm -f bday-*.tar.gz ChangeLog
--- a/bday.c	Mon Feb 24 17:46:57 2014 +0100
+++ b/bday.c	Mon Feb 24 21:11:38 2014 +0100
@@ -26,21 +26,21 @@
 Input is read through standard input. For example: bday < ~/.birthdays
 The input (file) has to have the following format:
 
-text=date flags
+date flags text
 
 where:
-	date is yyyy-mm-dd
+	date is YYYY-MM-DD
 	flags is ONE or ZERO of
-		bd  for a birthday (default)
-		ann for an anniversary
-		ev  for an event
+		#ann for an anniversary
+		#ev  for an event
 	and zero or more of
-		w <n> to set the warn-in-advance time to n days
+		#w<n> to set the warn-in-advance time to n days
 			(don't include the brackets! :)
-		to <date>
-		for <days>
+		#to<date>
+		#for<days>
 			to specify the length of time taken by an
-			event, for example a holiday.
+			event, for example a holiday
+	separated by spaces.
 
 Lines preceeded by # are treated as comments.
 
@@ -69,16 +69,8 @@
 /* ========== Global constants and data types */
 
 
-/* month lengths etc */
-#define isleapyear(y) ((y)%4==0 && ((y)%100 != 0 || (y)%400 == 0))
-const unsigned MLENDAT[];
-#define mlen(m,y) (MLENDAT[(m)-1] != -1 ? MLENDAT[(m)-1] : (isleapyear((y)) ? 29 : 28))
-#define before(a,b) ((a).month < (b).month || ((a).month == (b).month && (a).day < (b).day))
-#define ydelta(a,b) ((int) (b).year - (a).year + before((a),(b)))
-
 /* -------- modifier flags */
 #define F_MTYPE 0x07
-#define F_TBIRTHDAY 1
 #define F_TANNIVERSARY 2
 #define F_TEVENT 3
 
@@ -88,8 +80,10 @@
 #define F_FORDAYS 0x16
 #define F_TODATE 0x24
 
-struct _ftable {char* txt; unsigned flag;};
-
+struct _ftable {
+	char* txt;
+	unsigned flag;
+};
 const struct _ftable FTABLE[];
 
 struct date {
@@ -105,33 +99,29 @@
 	int warn;
 };
 
-typedef int (*prnfunc)(const char *);
-
 /* ========== Global Variables */
 
 struct event *readlist(void);
 void gettoday(void);
 unsigned delta(struct date *);
 unsigned ddiff(struct date *D1, struct date *D2);
-void liststrings(struct event *evl, prnfunc outf);
+void liststrings(struct event *evl);
 char *tdelta(struct date *d);
 char *ttime(int yr, int mn, int wk, int dy);
-int skptok(int j, char *ptr);
+char *skptok(char *ptr);
 int evcmp(const void *e1, const void *e2);
 
 
 struct date today;
-int iDWarn = DEF_WARN;
+int def_warn = DEF_WARN;
 
-const unsigned MLENDAT[] = {31,-1,31,30,31,30,31,31,30,31,30,31};
 
 const struct _ftable FTABLE[] = {
-	{"bd", F_TBIRTHDAY},
-	{"ann",F_TANNIVERSARY},
-	{"ev", F_TEVENT},
-	{"w",  F_WTIME_P},
-	{"to", F_TODATE},
-	{"for", F_FORDAYS},
+	{"#ann",F_TANNIVERSARY},
+	{"#ev", F_TEVENT},
+	{"#w",  F_WTIME_P},
+	{"#to", F_TODATE},
+	{"#for", F_FORDAYS},
 	{NULL, 0}
 };
 
@@ -174,18 +164,60 @@
 
 /*
 like strcat(), but lets the buffer automagically grow :-)
-(needs local variable "size" with the buffer size)
 */
-#define append(where, what) do {                            \
-	if (strlen(what) > (size - strlen(where))) {          \
-		xrealloc(where, size + 128 + strlen(what));   \
-		size += 128 + strlen(what);                   \
-	}                                                     \
-	strcat(where, what);                                  \
-} while(0)
+int
+append(char *where, int size, char *what)
+{
+	if (strlen(what) > ((size) - strlen(where))) {
+		xrealloc(where, (size) + 128 + strlen(what));
+		size += 128 + strlen(what);
+	}
+	strcat(where, what);
+	return size;
+}
 
 /* ========== */
 
+
+int
+before(struct date a, struct date b)
+{
+	if (a.month < b.month) {
+		return 1;
+	} else if (a.month == b.month && a.day < b.day) {
+		return 1;
+	} else {
+		return 0;
+	}
+}
+
+int
+ydelta(struct date a, struct date b)
+{
+	return b.year - a.year + before(a, b);
+}
+
+/*
+returns the length of the given month
+*/
+int
+mlen(int month, int year)
+{
+	unsigned mlendat[] = {31,0,31,30,31,30,31,31,30,31,30,31};
+
+	if (mlendat[month - 1]) {
+		return mlendat[month - 1];
+	} else {
+		if (year%4==0 && (year%100!=0 || year%400==0)) {
+			return 29;
+		} else {
+			return 28;
+		}
+	}
+}
+
+
+
 /*
 returns delta(d) in days, weeks, months, etc
 the returned buffer is malloc()ed, do not forget to free() it
@@ -201,10 +233,10 @@
 	*buf = 0;
 	switch (delta(d)) {
 	case 0:
-		append(buf, "today");
+		size = append(buf, size, "TODAY");
 		return buf;
 	case 1:
-		append(buf, "tomorrow");
+		size = append(buf, size, "Tomorrow");
 		return buf;
 	default:
 		/* like delta(), we ignore the year */
@@ -224,9 +256,9 @@
 		wk = (dy / 7);
 		dy %= 7;
 
-		append(buf, "in ");
+		size = append(buf, size, "In ");
 		tmp = ttime(yr, mn, wk, dy);
-		append(buf, tmp);
+		size = append(buf, size, tmp);
 		free(tmp);
 
 		return buf;
@@ -237,66 +269,46 @@
 
 
 
-/*
 void
-donum(n,txt)
+donum(char *buf, int size, int n, char *txt, int *terms)
 {
-	if (n > 0) {
-		snprintf(tmp, sizeof(tmp), "%d", n);
-		append(buf, tmp);
-		append(buf, " " txt);
-		if (n != 1)
-			append(buf, "s");
-		terms--;
-		if (orgterms > 1) {
-			if (terms == 1)
-				append(buf, " and ");
-			else if (terms > 1)
-				append(buf, ", ");
-		}
+	char tmp[128];
+
+	if (n <= 0) {
+		return;
+	}
+	snprintf(tmp, sizeof(tmp), "%d", n);
+	size = append(buf, size, tmp);
+	size = append(buf, size, " ");
+	size = append(buf, size, txt);
+	if (n != 1) {
+		size = append(buf, size, "s");
+	}
+	if (--*terms == 1) {
+		size = append(buf, size, " and ");
+	} else if (*terms > 1) {
+		size = append(buf, size, ", ");
 	}
 }
-*/
-
-
-#define donum(n,txt) do {                       \
-	if (n > 0) {                              \
-		snprintf(tmp, sizeof(tmp), "%d", n);   \
-		append(buf, tmp);                      \
-		append(buf, " " txt);                  \
-		if (n != 1)                            \
-			append(buf, "s");                   \
-		terms--;                               \
-		if (orgterms > 1) {                    \
-			if (terms == 1)                     \
-				append(buf, " and ");            \
-			else if (terms > 1)                 \
-				append(buf, ", ");               \
-		}                                      \
-	}                                         \
-} while(0)
 
 
 /* returns allocated buffer, don't forget to free() */
 char *
 ttime(int yr, int mn, int wk, int dy)
 {
-	char *buf = xmalloc(128);
 	int size = 128;
-	int terms, orgterms;
-	char tmp[128];
+	char *buf = xmalloc(size);
+	int terms = (yr!=0) + (mn!=0) + (wk!=0) + (dy!=0);
 
-	*buf = 0; /* Initialize buffer */
-	terms = orgterms = (yr!=0) + (mn!=0) + (wk!=0) + (dy!=0);
+	*buf = '\0'; /* Initialize buffer */
 
-	donum(yr, "year");
-	donum(mn, "month");
-	donum(wk, "week");
-	donum(dy, "day");
+	donum(buf, size, yr, "year", &terms);
+	donum(buf, size, mn, "month", &terms);
+	donum(buf, size, wk, "week", &terms);
+	donum(buf, size, dy, "day", &terms);
 
 	return buf;
 }
-#undef donum
 
 
 
@@ -308,58 +320,60 @@
 the string to a function.
 */
 void
-liststrings(struct event *evl, prnfunc outf)
+liststrings(struct event *evl)
 {
 	int i,j;
 	char *buf, *tmp;
 	int size;
 
-	for (i = 0; evl[i].text != NULL; i++) {
-		buf = xmalloc(128);
+	for (i=0; evl[i].text; i++) {
+		size = 128;
+		buf = xmalloc(size);
 		*buf = '\0';
-		size = 128;
 
 		if (evl[i].warn == -1 && delta(&(evl[i].date))==0) {
-			 append(buf, evl[i].text);
+			 size = append(buf, size, evl[i].text);
 		} else if (evl[i].enddate.day == 0) {
+			
 			if (delta(&(evl[i].date)) <= evl[i].warn) {
-				append(buf, evl[i].text);
-				append(buf, " ");
 				tmp = tdelta(&(evl[i].date));
-				append(buf, tmp);
+				size = append(buf, size, tmp);
+				size = append(buf, size, ":  ");
+				size = append(buf, size, evl[i].text);
 				free(tmp);
 			}
 		} else {
 			if (delta(&(evl[i].date)) <= evl[i].warn) {
-				append(buf, evl[i].text);
-				append(buf, " for ");
-				/* +1 because, if the difference between two dates is one day,
-				   then the length of an event on those days is two days */
+				size = append(buf, size, evl[i].text);
+				size = append(buf, size, " for ");
+				/* +1 because, if the difference between
+				two dates is one day, then the length of
+				an event on those days is two days */
 				j = ddiff(&(evl[i].date),&(evl[i].enddate)) + 1;
 				tmp = ttime(0, 0, j/7, j%7);
-				append(buf, tmp);
+				size = append(buf, size, tmp);
 				free(tmp);
-				append(buf, " ");
+				size = append(buf, size, " ");
 				tmp = tdelta(&(evl[i].date));
-				append(buf, tmp);
+				size = append(buf, size, tmp);
 			} else if (delta(&(evl[i].enddate)) <= evl[i].warn) {
-				append(buf, evl[i].text);
-				append(buf, " ");
+				size = append(buf, size, evl[i].text);
+				size = append(buf, size, " ");
 				j = delta(&(evl[i].enddate));
 				if (j) {
-					append(buf, "for ");
+					size = append(buf, size, "for ");
 					tmp = ttime(0, 0, j/7, j%7);
-					append(buf, tmp);
+					size = append(buf, size, tmp);
 					free(tmp);
-					append(buf, " longer");
+					size = append(buf, size, " longer");
 				} else {
-					append(buf, "finishes today");
+					size = append(buf, size, "finishes today");
 				}
 			}
 		}
 		if (*buf) {
-			append(buf, ".");
-			outf(buf);
+			size = append(buf, size, ".");
+			puts(buf);
 		}
 		free(buf);
 	}
@@ -534,7 +548,7 @@
 	int i, j, k, l, d;
 	struct event *evl;
 	char buf[1024], buf2[1024];
-	char *ptr;
+	char *ptr, *cp;
 	unsigned flags;
 
 	/* initialise */
@@ -550,46 +564,48 @@
 		}
 
 		/* parse string in buf */
-		ptr = strrchr(buf, '='); /* allow '=' in text */
+
+		ptr = strchr(buf, ' ');  /* start of text */
 
 		/* not a valid line, so ignore it! Cool, huh? */
 		/* Attention: only recognizes lines without '=' */
-		if (ptr == NULL) {
-			fprintf(stderr, "WARNING: Invalid line in input:\n%s", buf);
+		if (!ptr) {
+			fprintf(stderr, "WARNING: Invalid input line:\n\t%s", buf);
 			i--;
 			continue;
 		}
 
-		*(ptr++) = 0;
+		*(ptr++) = '\0';
+		ptr[strlen(ptr)-1] = '\0';
 
-		j = sscanf(ptr, "%u-%u-%u", &(evl[i].date.year),
+		j = sscanf(buf, "%u-%u-%u", &(evl[i].date.year),
 				&(evl[i].date.month), &(evl[i].date.day));
-		/* ... unless it wasn't read, in which case set it to zero */
-		if (j==2) {
-			evl[i].date.year = 0;
+		if (j != 3) {
+			fprintf(stderr, "Error: Invalid date:\t%s\n", buf);
+			i--;
+			continue;
 		}
 
-
 		/* parse flags */
 
-		evl[i].warn = iDWarn;
+		evl[i].warn = def_warn;
 		evl[i].enddate.day = 0;
 		evl[i].enddate.month = 0;
 		evl[i].enddate.year = 0;
 
 		flags = 0;
 		j = 0;
-
-		while(j = skptok(j, ptr), ptr[j] != 0) {
-			for (k = 0; FTABLE[k].txt != NULL && strncmp(FTABLE[k].txt, ptr + j, strlen(FTABLE[k].txt)); k++) {
+		cp = skptok(ptr);
+		for (cp=ptr; *cp && *cp=='#'; cp=skptok(cp)) {
+			for (k = 0; FTABLE[k].txt && strncmp(FTABLE[k].txt, cp, strlen(FTABLE[k].txt)); k++) {
 			}
 
 			switch (FTABLE[k].flag) {
-			case F_WTIME_P: /* w <n> -- sets warning time */
-				sscanf(ptr + j, "w %u", &(evl[i].warn));
+			case F_WTIME_P: /* #w<n> -- sets warning time */
+				sscanf(cp, "#w%u", &(evl[i].warn));
 				break;
-			case F_FORDAYS: /* for <days> -- sets the duration of the event */
-				sscanf(ptr + j, "for %u", &d);
+			case F_FORDAYS: /* #for<days> -- sets the duration of the event */
+				sscanf(cp, "#for%u", &d);
 				evl[i].enddate=evl[i].date;
 				for (l = 1; l < d; l++) {
 					evl[i].enddate.day++;
@@ -603,8 +619,8 @@
 					}
 				}
 				break;
-			case F_TODATE: /* to <date> -- sets the end date of the event */
-				l = sscanf(ptr + j, "to %u-%u-%u", &(evl[i].enddate.year), &(evl[i].enddate.month), &(evl[i].enddate.day));
+			case F_TODATE: /* #to<date> -- sets the end date of the event */
+				l = sscanf(cp, "#to%u-%u-%u", &(evl[i].enddate.year), &(evl[i].enddate.month), &(evl[i].enddate.day));
 				if (l == 2) {
 					evl[i].enddate.year = 0;
 				}
@@ -621,34 +637,32 @@
 		/* construct event text */
 
 		switch(flags & F_MTYPE) {
-			case F_TBIRTHDAY:
 			default: /* assume it's a birthday */
-				if (evl[i].date.year != 0) {
-					int tmp_age = ydelta(evl[i].date, today);
-					if (tmp_age != 1) {
-						sprintf(buf2, "%s is %d years old", buf, tmp_age);
-					} else {
-						sprintf(buf2, "%s is %d year old", buf, tmp_age);
-					}
-				} else {
-					sprintf(buf2, "%s has a birthday", buf);
+				if (!evl[i].date.year) {
+					sprintf(buf2, "%s has a birthday", cp);
+					break;
 				}
+				int tmp_age = ydelta(evl[i].date, today);
+				sprintf(buf2, "%s is %d year%s old",
+				  cp, tmp_age, (tmp_age>1)?"s":"");
 				break;
 			case F_TANNIVERSARY:
-				if (evl[i].date.year != 0) {
-					sprintf(buf2, "%s %d years ago", buf, ydelta(evl[i].date, today));
+				if (evl[i].date.year) {
+					sprintf(buf2, "%s %d years ago",
+					  cp, ydelta(evl[i].date, today));
 				} else {
-					strcpy(buf2, buf);
+					strcpy(buf2, cp);
 				}
 				break;
 			case F_TEVENT:
-				/* if a year was specified, and this warning isn't for it, ignore! */
-				if ((evl[i].date.year != 0 && ydelta(evl[i].date, today) != 0)
-				    && (evl[i].enddate.year == 0 || ydelta(evl[i].enddate, today) != 0)) {
+				/* if a year was specified, and this
+				   warning isn't for it, ignore! */
+				if ((evl[i].date.year && ydelta(evl[i].date, today))
+				    && (!evl[i].enddate.year || ydelta(evl[i].enddate, today))) {
 					i--;
 					continue;
 				}
-				strcpy(buf2, buf);
+				strcpy(buf2, cp);
 				break;
 		}
 		evl[i].text = strdup(buf2);
@@ -671,13 +685,16 @@
 
 
 
-int
-skptok(int j, char *ptr)
+char *
+skptok(char *ptr)
 {
-	for (; ptr[j] != 0 &&  ptr[j] != ' ' && ptr[j] != '\t' ; j++);
-	for (; ptr[j] != 0 && (ptr[j] == ' ' || ptr[j] == '\t'); j++);
-
-	return j;
+	while (*ptr && (*ptr!=' ' && *ptr!='\t')) {
+		ptr++;
+	}
+	while (*ptr && (*ptr==' ' || *ptr=='\t')) {
+		ptr++;
+	}
+	return ptr;
 }
 
 
@@ -688,18 +705,16 @@
 int
 main(int argc, char *argv[])
 {
-	while (--argc > 0 && (*++argv)[0] == '-') {
+	while (--argc > 0 && **++argv == '-') {
 		if (strcmp(argv[0], "-W") == 0) {
 			/* TODO: catch if no value given */
-			iDWarn = atoi((++argv)[0]);
+			def_warn = atoi((++argv)[0]);
 			argc--;
 		} else {
 			fprintf(stderr, "unknown option %s\n", argv[0]);
 			exit(1);
 		}
 	}
-
-	liststrings(readlist(), puts);
-
+	liststrings(readlist());
 	return 0;
 }