From 8f2d5e294fab3ed40694d231bf1b53c84081c212 Mon Sep 17 00:00:00 2001 From: Ivan Tham Date: Sat, 28 Nov 2015 21:08:54 +0800 Subject: [PATCH] Initial commit --- .gitignore | 30 ++++++++++++++ LICENSE | 21 ++++++++++ Makefile | 59 +++++++++++++++++++++++++++ README | 37 +++++++++++++++++ TODO | 9 +++++ arg.h | 40 +++++++++++++++++++ config.def.h | 22 ++++++++++ config.mk | 22 ++++++++++ spt.1 | 52 ++++++++++++++++++++++++ spt.c | 111 +++++++++++++++++++++++++++++++++++++++++++++++++++ 10 files changed, 403 insertions(+) create mode 100644 .gitignore create mode 100644 LICENSE create mode 100644 Makefile create mode 100644 README create mode 100644 TODO create mode 100644 arg.h create mode 100644 config.def.h create mode 100644 config.mk create mode 100644 spt.1 create mode 100644 spt.c diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..95c40ba --- /dev/null +++ b/.gitignore @@ -0,0 +1,30 @@ +# Object files +*.o +*.ko +*.obj +*.elf + +# Libraries +*.lib +*.a + +# Shared objects (inc. Windows DLLs) +*.dll +*.so +*.so.* +*.dylib + +# Executables +*.exe +*.out +*.app +*.i*86 +*.x86_64 +*.hex +/spt + +# vim +*.swp +*~ + +config.h diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..5f2f214 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT/X Consortium License + +© 2015 Ivan Tham + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the "Software"), +to deal in the Software without restriction, including without limitation +the rights to use, copy, modify, merge, publish, distribute, sublicense, +and/or sell copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..05e4894 --- /dev/null +++ b/Makefile @@ -0,0 +1,59 @@ +# spt - simple pomodoro timer +# See LICENSE file for copyright and license details. + +include config.mk + +SRC = spt.c +OBJ = ${SRC:.c=.o} + +all: options spt + +options: + @echo spt build options: + @echo "CFLAGS = ${CFLAGS}" + @echo "LDFLAGS = ${LDFLAGS}" + @echo "CC = ${CC}" + +.c.o: + @echo CC $< + @${CC} -c ${CFLAGS} $< + +${OBJ}: config.h config.mk + +config.h: + @echo creating $@ from config.def.h + @cp config.def.h $@ + +spt: ${OBJ} + @echo CC -o $@ + @${CC} -o $@ ${OBJ} ${LDFLAGS} + +clean: + @echo cleaning + @rm -f ${SRC:.c=} ${OBJ} spt-${VERSION}.tar.xz + +dist: clean + @echo creating dist tarball + @mkdir -p spt-${VERSION} + @cp -R LICENSE Makefile README config.mk config.def.h spt.info spt.1 ${SRC} spt-${VERSION} + @tar -cf spt-${VERSION}.tar spt-${VERSION} + @xz spt-${VERSION}.tar + @rm -rf spt-${VERSION} + +install: all + @echo installing executable file to ${DESTDIR}${PREFIX}/bin + @mkdir -p ${DESTDIR}${PREFIX}/bin + @cp -f spt ${DESTDIR}${PREFIX}/bin + @chmod 755 ${DESTDIR}${PREFIX}/bin/spt + @echo installing manual page to ${DESTDIR}${MANPREFIX}/man1 + @mkdir -p ${DESTDIR}${MANPREFIX}/man1 + @sed "s/VERSION/${VERSION}/g" < spt.1 > ${DESTDIR}${MANPREFIX}/man1/spt.1 + @chmod 644 ${DESTDIR}${MANPREFIX}/man1/spt.1 + +uninstall: + @echo removing executable file from ${DESTDIR}${PREFIX}/bin + @rm -f ${DESTDIR}${PREFIX}/bin/spt + @echo removing manual page from ${DESTDIR}${MANPREFIX}/man1 + @rm -f ${DESTDIR}${MANPREFIX}/man1/spt.1 + +.PHONY: all options clean dist install uninstall diff --git a/README b/README new file mode 100644 index 0000000..c98eb33 --- /dev/null +++ b/README @@ -0,0 +1,37 @@ +spt - simple pomodoro timer +=========================== +spt is a simple timer that uses the pomodoro technique that doubles your +efficiency. + + +Features +-------- +- Get the jobs done quicker than ever +- Keeps you free like a dog + + +Installation +------------ +Edit config.mk to match your local setup (spt is installed into the /usr/local +namespace by default). + +Afterwards enter the following command to build and install spt (if necessary +as root): + + make clean install + +See the man pages for additional details. + + +Configuration +------------- +The configuration of dwm is done by creating a custom config.h +and (re)compiling the source code. + + +Links +----- +http://pomodorotechnique.com/ + + +The project is licensed under the MIT license. diff --git a/TODO b/TODO new file mode 100644 index 0000000..09a1462 --- /dev/null +++ b/TODO @@ -0,0 +1,9 @@ +major +----- + - Add options to start and stop spt with only one process + +misc +---- + $ grep -n 'TODO' spt.c + +# vim:ft=markdown: diff --git a/arg.h b/arg.h new file mode 100644 index 0000000..3b0d22f --- /dev/null +++ b/arg.h @@ -0,0 +1,40 @@ +/* + * Copy me if you can. + * by 20h + */ + +#ifndef __ARG_H__ +#define __ARG_H__ + +extern char *argv0; + +#define USED(x) ((void)(x)) + +#define ARGBEGIN for (argv0 = *argv, argv++, argc--;\ + argv[0] && argv[0][1]\ + && argv[0][0] == '-';\ + argc--, argv++) {\ + char _argc;\ + char **_argv;\ + if (argv[0][1] == '-' && argv[0][2] == '\0') {\ + argv++;\ + argc--;\ + break;\ + }\ + for (argv[0]++, _argv = argv; argv[0][0];\ + argv[0]++) {\ + if (_argv != argv)\ + break;\ + _argc = argv[0][0];\ + switch (_argc) + +#define ARGEND }\ + USED(_argc);\ + }\ + USED(argv);\ + USED(argc); + +#define EARGF(x) ((argv[1] == NULL)? ((x), abort(), (char *)0) :\ + (argc--, argv++, argv[0])) + +#endif diff --git a/config.def.h b/config.def.h new file mode 100644 index 0000000..32e3774 --- /dev/null +++ b/config.def.h @@ -0,0 +1,22 @@ +/* See LICENSE file for copyright and license details. */ + +/* Notification */ +static char *notifycmd = "libnotify"; /* Use built-in libnotify if empty */ +static char *notifyext = ""; /* Notify with extra command (eg. play an alarm) */ + +/* + * This is the array which defines all the timer that will be used. + * It will be repeated after all of it is executed. + */ +static Timer timer[] = { + /* timer comment */ + { 1500, "Time to start working!"}, + { 300, "Time to start resting!"}, + { 1500, "Time to start working!"}, + { 300, "Time to start resting!"}, + { 1500, "Time to start working!"}, + { 300, "Time to start resting!"}, + { 1500, "Time to start working!"}, + { 300, "Time to start resting!"}, + { 900, "Time to take some nap!"}, +}; diff --git a/config.mk b/config.mk new file mode 100644 index 0000000..3fdff03 --- /dev/null +++ b/config.mk @@ -0,0 +1,22 @@ +# spt version +VERSION = 0.0 + +# Customize below to fit your system + +# paths +PREFIX = /usr/local +MANPREFIX = ${PREFIX}/share/man + +# includes and libs +INCS = -I. -I/usr/include \ + `pkg-config --cflags libnotify` +LIBS = -L/usr/lib \ + `pkg-config --libs libnotify` + +# flags +CPPFLAGS = -DVERSION=\"${VERSION}\" +CFLAGS += -g -std=c99 -pedantic -Wall -O0 ${INCS} ${CPPFLAGS} +LDFLAGS += -g ${LIBS} + +# compiler and linker +# CC = cc diff --git a/spt.1 b/spt.1 new file mode 100644 index 0000000..e672ef0 --- /dev/null +++ b/spt.1 @@ -0,0 +1,52 @@ +.TH SPT 1 spt\-VERSION +.SH NAME +spt \- simple pomodoro timer +.SH SYNOPSIS +.B spt +.RB [ \-e +.IR notifycmd ] +.RB [ \-n +.IR notifyext ] +.RB [ \-v ] +.SH DESCRIPTION +.B spt +is a simple timer that uses pomodoro technique with desktop notification to +double your efficiency. +.SH OPTIONS +.TP +.BI \-e " notifyext" +Execute +.I notifycmd +when timer starts ticking. +.TP +.BI \-n " notifycmd" +If +.IR empty , +do nothing. If +.IR libnotify , +use the default notification. If neither, it will use the command specified. +.TP +.BI \-v +Prints version information to stderr, then exits. +.SH TIMER +4 pomodoro timer +.RB ( "25 min." ) +with subsequent rests in between +.RB ( "5 min." ) +and +followed by a long rest +.RB ( "15 min." ) +.SH EXAMPLES +Use system notify_send and play a music without libnotify: +.RS +.B spt -e 'aplay alarm.wav' -n 'notify-send' +.RE +.SH AUTHOR +The author is not that important. A message from the author: +.TP +.I "Good luck and have a nice day!" +.SH LICENSE +See the LICENSE file for the terms of redistribution. +.SH BUGS +Bugs? You must be kidding; there is no bugs in this software. But if we +happened to be wrong, please report the bugs! diff --git a/spt.c b/spt.c new file mode 100644 index 0000000..40beaf4 --- /dev/null +++ b/spt.c @@ -0,0 +1,111 @@ +/* See LICENSE file for copyright and license details. */ +#include +#include +#include +#include +#include + +#include + +#include "arg.h" + +char *argv0; + +/* macros */ +#define LEN(a) (sizeof(a) / sizeof(a)[0]) + +typedef struct { + unsigned int tmr; + char *cmt; +} Timer; + +#include "config.h" + +/* function declarations */ +static void die(const char *errstr, ...); +static void spawn(char *); +static void notify_send(char *); +static void usage(void); + +/* functions implementations */ +void +die(const char *errstr, ...) +{ + va_list ap; + + va_start(ap, errstr); + vfprintf(stderr, errstr, ap); + va_end(ap); + exit(EXIT_FAILURE); +} + +void +spawn(char *cmd) +{ + if (fork() == 0) { + setsid(); + execvp("sh", (char *const []){"/bin/sh", "-c", cmd, 0}); + fprintf(stderr, "spt: execvp %s", cmd); + perror(" failed"); + exit(0); + } +} + +void +notify_send(char *cmt) +{ + if (!strcmp(notifycmd, "libnotify")) { /* use libnotify */ + notify_init("spt"); + NotifyNotification *n = notify_notification_new("spt", cmt, "dialog-information"); + notify_notification_show(n, NULL); + g_object_unref(G_OBJECT(n)); + notify_uninit(); + } else if (strcmp(notifycmd, "")) { + /* TODO(pickfire): merge this into spawn() */ + if (fork() == 0) { + setsid(); + execlp(notifycmd, "spt", cmt, NULL); + fprintf(stderr, "spt: execlp %s", notifycmd); + perror(" failed"); + exit(0); + } + } + + if (strcmp(notifyext, "")) /* extra commands to use */ + spawn(notifyext); +} + +void +usage(void) +{ + die("usage: %s [-e notifyext] [-n notifycmd] [-v]\n", argv0); +} + +int +main(int argc, char *argv[]) +{ + int i = 0; + + ARGBEGIN { + case 'e': + notifyext = EARGF(usage()); + break; + case 'n': + notifycmd = EARGF(usage()); + break; + case 'v': + die("spt " VERSION " © 2015 spt engineers, " + "see LICENSE for details\n"); + default: + usage(); + break; + } ARGEND; + +run: + notify_send(timer[i].cmt); + sleep(timer[i].tmr); + i + 1 >= LEN(timer) ? i = 0 : i++; /* i infinal loop */ + goto run; + + return 0; +}