Adding a preliminary C version for 'tt'.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/Makefile Mon Mar 15 22:50:59 2010 +0100
@@ -0,0 +1,8 @@
+CFLAGS=-O2
+PREFIX?=/usr
+
+tt: tt.c
+ $(CC) $(CFLAGS) -o $@ $^
+
+install: tt
+ cp tt $(PREFIX)/bin/tt
--- a/tt Mon Feb 16 22:49:00 2009 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,151 +0,0 @@
-#!/bin/sh -e
-# (encoding: UTF-8)
-#
-# tt 0.6 - Time Tracker
-# (Instructions using -h)
-# LICENSE
-# Copyright (C) 2009 Lluís Batlle i Rossell
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-
-PNAME=`basename "$0"`
-
-if [ -z "$EDITOR" ]; then
- EDITOR=vim
-fi
-
-if [ -z "$TT_PROJECT" ]; then
- TT_PROJECT=$HOME/.tt
-fi
-
-function usage
-{
- echo "Usage: $PNAME [-d] [-l] [-t]"
- echo " $PNAME <task>"
- echo "Manual:"
- echo " Switch to a task : tt mytask"
- echo " List task switches : tt -l"
- echo " List time spent per task : tt -t"
- echo " Sum times given with -t : tt -t | grep ... | tt -s"
- echo " List what is tracked : tt"
- echo " \$TT_PROJECT or ~/.tt stores the tracking."
-}
-
-function date2iso
-{
- date -d "$1" '+%Y-%m-%d %T'
-}
-
-function date2timestamp
-{
- date -d "$1" '+%s'
-}
-
-function add
-{
- echo "`date2iso now`"$'\t'"$1" >> "$TT_PROJECT"
-}
-
-function list
-{
- if [ -f "$TT_PROJECT" ]; then
- cat "$TT_PROJECT"
- fi
-}
-
-function listtime
-{
- if [ -f "$TT_PROJECT" ]; then
- cat < "$TT_PROJECT" |
- (
- read A
- STARTTIME=`echo "$A" | cut -f 1`
- NAME=`echo "$A" | cut -f 2`
- while read A; do
- ENDTIME=`echo "$A" | cut -f 1`
- echo `timebetween "$STARTTIME" "$ENDTIME"` \
- "$NAME" "($STARTTIME)"
- NAME=`echo "$A" | cut -f 2`
- STARTTIME="$ENDTIME"
- done
- echo `timebetween "$STARTTIME" now` \
- "$NAME" "($STARTTIME)"
- )
- fi
-}
-
-function sec2hms
-{
- MINUTES=0
- HOURS=0
- SECONDS=$1
- if [ $SECONDS -gt 60 ]; then
- MINUTES=$((SECONDS / 60))
- SECONDS=$((SECONDS - MINUTES * 60))
- fi
-
- if [ $MINUTES -gt 60 ]; then
- HOURS=$((MINUTES / 60))
- MINUTES=$((MINUTES - HOURS * 60))
- fi
-
- printf "%02d:%02d:%02d\n" $HOURS $MINUTES $SECONDS
-}
-
-function timebetween
-{
- STARTSEC=`date2timestamp "$1"`
- ENDSEC=`date2timestamp "$2"`
-
- SECONDS=$((ENDSEC - STARTSEC))
-
- echo `sec2hms $SECONDS`
-}
-
-function status
-{
- if [ -f "$TT_PROJECT" ]; then
- NAME=`tail -n 1 "$TT_PROJECT" | cut -f 2`
- STARTDATE=`tail -n 1 "$TT_PROJECT" | cut -f 1`
-
- echo `timebetween "$STARTDATE" "now"` "$NAME"
- fi
-}
-
-function sum
-{
- VAL=`awk -F : -- '
- BEGIN { val=0; }
- { val += $1 * 60 * 60 + $2 * 60 + $3 }
- END { print val }' `
-
- echo `sec2hms $VAL`
-}
-
-if [ $# -eq 0 ]; then
- status || exit 1
-elif [ "$1" == "-l" ]; then
- list
-elif [ "$1" == "-t" ]; then
- listtime
-elif [ "$1" == "-s" ]; then
- sum
-elif [ "$1" == "-h" ]; then
- usage
-else
- add $@
-fi
-
-exit 0
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tt.c Mon Mar 15 22:50:59 2010 +0100
@@ -0,0 +1,327 @@
+#define _POSIX_C_SOURCE 1
+#define _XOPEN_SOURCE 500
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <time.h>
+#include <string.h>
+#include <errno.h>
+
+static FILE *
+open_file(const char *attr)
+{
+ const char *name = getenv("TT_PROJECT");
+ if (!name)
+ {
+ fprintf(stderr, "You have to point TT_PROJECT to a file\n");
+ exit(1);
+ }
+
+ FILE *f;
+ f = fopen(name, attr);
+ if (!f)
+ {
+ fprintf(stderr, "Could not open the file: %s (%s)", name,
+ strerror(errno));
+ exit(1);
+ }
+
+ return f;
+}
+
+static int
+get_current_time()
+{
+ time_t current_time = time(0);
+ return (int) current_time;
+}
+
+static char *
+get_time_str(int d)
+{
+ time_t seconds = (time_t) d;
+ struct tm t;
+ localtime_r(&seconds, &t);
+
+ char *str = malloc(100);
+ snprintf(str, 100, "%04i-%02i-%02i %02i:%02i:%02i",
+ 1900+t.tm_year, t.tm_mon+1, t.tm_mday,
+ t.tm_hour, t.tm_min, t.tm_sec);
+ return str;
+}
+
+char *
+seconds2hms(int t)
+{
+ int hours, minutes;
+
+ hours = t / 3600;
+ t = t % 3600;
+ minutes = t / 60;
+ t = t % 60;
+
+ char *str = malloc(100);
+ snprintf(str, 100, "%02i:%02i:%02i",
+ hours, minutes, t);
+
+ return str;
+}
+
+static int
+str2time(const char *str)
+{
+ struct tm t;
+ time_t seconds;
+ char *str2 = strdup(str);
+
+ char *ptr_begin = str2;
+ char *ptr_end;
+
+ ptr_end = strchr(ptr_begin, '-');
+ if (!ptr_end)
+ abort();
+ *ptr_end = '\0';
+ sscanf(ptr_begin, "%i", &t.tm_year);
+ t.tm_year -= 1900;
+
+ ptr_begin = ptr_end + 1;
+ ptr_end = strchr(ptr_begin, '-');
+ if (!ptr_end)
+ abort();
+ *ptr_end = '\0';
+ sscanf(ptr_begin, "%i", &t.tm_mon);
+ /* starting at 0 */
+ t.tm_mon -= 1;
+
+ ptr_begin = ptr_end + 1;
+ ptr_end = strchr(ptr_begin, ' ');
+ if (!ptr_end)
+ abort();
+ *ptr_end = '\0';
+ sscanf(ptr_begin, "%i", &t.tm_mday);
+
+ ptr_begin = ptr_end + 1;
+ ptr_end = strchr(ptr_begin, ':');
+ if (!ptr_end)
+ abort();
+ *ptr_end = '\0';
+ sscanf(ptr_begin, "%i", &t.tm_hour);
+
+ ptr_begin = ptr_end + 1;
+ ptr_end = strchr(ptr_begin, ':');
+ if (!ptr_end)
+ abort();
+ *ptr_end = '\0';
+ sscanf(ptr_begin, "%i", &t.tm_min);
+
+ ptr_begin = ptr_end + 1;
+ sscanf(ptr_begin, "%i", &t.tm_sec);
+
+ free(str2);
+
+ /* We don't know, we had or not DST at that time */
+ t.tm_isdst = -1;
+ seconds = mktime(&t);
+ return (int) seconds;
+}
+
+static void
+new_task(const char *task)
+{
+ char *time_str = get_time_str(get_current_time());
+ FILE *f = open_file("a");
+
+ fprintf(f, "%s\t%s\n", time_str, task);
+
+ free(time_str);
+}
+
+static void
+list_task_switches()
+{
+ FILE *f = open_file("r");
+
+ char buf[1000];
+ int n;
+
+ do {
+ n = fread(buf, 1, sizeof(buf), f);
+ while(n > 0)
+ {
+ int ret;
+ ret = fwrite(buf, 1, n, stdout);
+ n -= ret;
+ memcpy(buf, buf+ret, n);
+ }
+ }
+ while(n > 0);
+ fclose(f);
+}
+
+static void
+list_task_times()
+{
+ FILE *f = open_file("r");
+
+ int is_prev_time_read = 0;
+
+ int prev_time;
+ char *prev_task = 0;
+
+ /* Read lines */
+ do {
+ /* Read a line */
+ char buf[1000];
+ int n = 0;
+ int c;
+ do
+ {
+ buf[n] = fgetc(f);
+ if(buf[n] == '\n' || feof(f))
+ break;
+ ++n;
+ } while(!feof(f) && n <= sizeof(buf));
+
+ buf[n] = 0;
+ if(n > 0)
+ {
+ char *end_date, *start_task;
+ int time;
+
+ end_date = strchr(buf, '\t');
+ if (!end_date)
+ abort();
+ *end_date = 0;
+ start_task = end_date + 1;
+
+ time = str2time(buf);
+ if (is_prev_time_read)
+ {
+ int diff = time - prev_time;
+ char *hms = seconds2hms(diff);
+ printf("%s\t%s\n", hms, prev_task);
+ free(hms);
+ }
+
+ prev_time = time;
+ free(prev_task);
+ prev_task = strdup(start_task);
+ is_prev_time_read = 1;
+ }
+ }
+ while(!feof(f));
+
+ /* Time until now, for the last switch */
+ if (is_prev_time_read)
+ {
+ int diff = get_current_time() - prev_time;
+ char *hms = seconds2hms(diff);
+ printf("%s\t%s\n", hms, prev_task);
+ free(hms);
+ }
+
+ free(prev_task);
+ fclose(f);
+}
+
+char *
+str_until_space(const char *str)
+{
+ while(*str != '\0' && !isspace(*str))
+ {
+ ++str;
+ }
+
+ if (*str == '\0')
+ return 0;
+
+ /* We get rid of the const */
+ return (char *) str;
+}
+
+double
+hms2time(const char *str)
+{
+ int hours, minutes, seconds;
+ char *str2 = strdup(str);
+
+ char *ptr_begin = str2;
+ char *ptr_end;
+
+ ptr_end = strchr(ptr_begin, ':');
+ if (!ptr_end)
+ abort();
+ *ptr_end = '\0';
+ sscanf(ptr_begin, "%i", &hours);
+
+ ptr_begin = ptr_end + 1;
+ ptr_end = strchr(ptr_begin, ':');
+ if (!ptr_end)
+ abort();
+ *ptr_end = '\0';
+ sscanf(ptr_begin, "%i", &minutes);
+
+ ptr_begin = ptr_end + 1;
+ sscanf(ptr_begin, "%i", &seconds);
+
+ free(str2);
+
+ return hours * 3600 + minutes * 60 + seconds;
+}
+
+static void
+sum_times()
+{
+ int accum_time = 0;
+ char *str_hms;
+
+ /* Read lines */
+ do {
+ /* Read a line */
+ char buf[1000];
+ int n = 0;
+ int c;
+ do
+ {
+ buf[n] = fgetc(stdin);
+ if(buf[n] == '\n' || feof(stdin))
+ break;
+ ++n;
+ } while(!feof(stdin) && n <= sizeof(buf));
+
+ buf[n] = 0;
+ if(n > 0)
+ {
+ char *end;
+ int time;
+
+ end = str_until_space(buf);
+ if (!end)
+ abort();
+ *end = 0;
+
+ time = hms2time(buf);
+ accum_time += time;
+ }
+ }
+ while(!feof(stdin));
+
+ str_hms = seconds2hms(accum_time);
+ printf("%s\n", str_hms);
+ free(str_hms);
+}
+
+int main(int argc, char **argv)
+{
+ if (argc >= 2)
+ if (strcmp(argv[1], "-t") == 0)
+ list_task_times();
+ else if (strcmp(argv[1], "-s") == 0)
+ sum_times();
+ else
+ new_task(argv[1]);
+ else
+ list_task_switches();
+
+ return 0;
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tt.sh Mon Mar 15 22:50:59 2010 +0100
@@ -0,0 +1,151 @@
+#!/bin/sh -e
+# (encoding: UTF-8)
+#
+# tt 0.6 - Time Tracker
+# (Instructions using -h)
+# LICENSE
+# Copyright (C) 2009 Lluís Batlle i Rossell
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+PNAME=`basename "$0"`
+
+if [ -z "$EDITOR" ]; then
+ EDITOR=vim
+fi
+
+if [ -z "$TT_PROJECT" ]; then
+ TT_PROJECT=$HOME/.tt
+fi
+
+function usage
+{
+ echo "Usage: $PNAME [-d] [-l] [-t]"
+ echo " $PNAME <task>"
+ echo "Manual:"
+ echo " Switch to a task : tt mytask"
+ echo " List task switches : tt -l"
+ echo " List time spent per task : tt -t"
+ echo " Sum times given with -t : tt -t | grep ... | tt -s"
+ echo " List what is tracked : tt"
+ echo " \$TT_PROJECT or ~/.tt stores the tracking."
+}
+
+function date2iso
+{
+ date -d "$1" '+%Y-%m-%d %T'
+}
+
+function date2timestamp
+{
+ date -d "$1" '+%s'
+}
+
+function add
+{
+ echo "`date2iso now`"$'\t'"$1" >> "$TT_PROJECT"
+}
+
+function list
+{
+ if [ -f "$TT_PROJECT" ]; then
+ cat "$TT_PROJECT"
+ fi
+}
+
+function listtime
+{
+ if [ -f "$TT_PROJECT" ]; then
+ cat < "$TT_PROJECT" |
+ (
+ read A
+ STARTTIME=`echo "$A" | cut -f 1`
+ NAME=`echo "$A" | cut -f 2`
+ while read A; do
+ ENDTIME=`echo "$A" | cut -f 1`
+ echo `timebetween "$STARTTIME" "$ENDTIME"` \
+ "$NAME" "($STARTTIME)"
+ NAME=`echo "$A" | cut -f 2`
+ STARTTIME="$ENDTIME"
+ done
+ echo `timebetween "$STARTTIME" now` \
+ "$NAME" "($STARTTIME)"
+ )
+ fi
+}
+
+function sec2hms
+{
+ MINUTES=0
+ HOURS=0
+ SECONDS=$1
+ if [ $SECONDS -gt 60 ]; then
+ MINUTES=$((SECONDS / 60))
+ SECONDS=$((SECONDS - MINUTES * 60))
+ fi
+
+ if [ $MINUTES -gt 60 ]; then
+ HOURS=$((MINUTES / 60))
+ MINUTES=$((MINUTES - HOURS * 60))
+ fi
+
+ printf "%02d:%02d:%02d\n" $HOURS $MINUTES $SECONDS
+}
+
+function timebetween
+{
+ STARTSEC=`date2timestamp "$1"`
+ ENDSEC=`date2timestamp "$2"`
+
+ SECONDS=$((ENDSEC - STARTSEC))
+
+ echo `sec2hms $SECONDS`
+}
+
+function status
+{
+ if [ -f "$TT_PROJECT" ]; then
+ NAME=`tail -n 1 "$TT_PROJECT" | cut -f 2`
+ STARTDATE=`tail -n 1 "$TT_PROJECT" | cut -f 1`
+
+ echo `timebetween "$STARTDATE" "now"` "$NAME"
+ fi
+}
+
+function sum
+{
+ VAL=`awk -F : -- '
+ BEGIN { val=0; }
+ { val += $1 * 60 * 60 + $2 * 60 + $3 }
+ END { print val }' `
+
+ echo `sec2hms $VAL`
+}
+
+if [ $# -eq 0 ]; then
+ status || exit 1
+elif [ "$1" == "-l" ]; then
+ list
+elif [ "$1" == "-t" ]; then
+ listtime
+elif [ "$1" == "-s" ]; then
+ sum
+elif [ "$1" == "-h" ]; then
+ usage
+else
+ add $@
+fi
+
+exit 0