Adding a preliminary C version for 'tt'.
authorLluís Batlle <viriketo@gmail.com>
Mon, 15 Mar 2010 22:50:59 +0100
changeset 7 e31e7826bc3f
parent 6 0e75c4869729
child 8 37880a37c066
Adding a preliminary C version for 'tt'.
Makefile
tt
tt.c
tt.sh
--- /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