timetracker

suckless timetracking
git clone https://tongong.net/git/timetracker.git
Log | Files | Refs | README

timetracker-save.c (4832B)


      1 #include <signal.h>
      2 #include <stdio.h>
      3 #include <stdlib.h>
      4 #include <string.h>
      5 #include <sys/stat.h>
      6 #include <sys/types.h>
      7 #include <time.h>
      8 #include <unistd.h>
      9 
     10 #define MAX_PROGRAM_NAME  30   /* longer program names get cut off */
     11 #define WRITE_INTERVAL    600  /* 10 minutes */
     12 
     13 #define FILENAME   "/timetracker/data" /* relative to $XDG_DATA_HOME */
     14 #define FILENAME2  "/.local/share/timetracker/data" /* relative to $HOME */
     15 
     16 
     17 /* returns path to data file; should be free()d */
     18 char * filelocation() {
     19     char *loc = NULL;
     20     char *xdg_data_home = getenv("XDG_DATA_HOME");
     21     if (xdg_data_home) {
     22         loc = malloc(strlen(xdg_data_home) + strlen(FILENAME) + 1);
     23         strcpy(loc, xdg_data_home);
     24         strcpy(loc + strlen(xdg_data_home), FILENAME);
     25     } else {
     26         char *xdg_home = getenv("HOME");
     27         loc = malloc(strlen(xdg_home) + strlen(FILENAME2) + 1);
     28         strcpy(loc, xdg_home);
     29         strcpy(loc + strlen(xdg_home), FILENAME2);
     30     }
     31     return loc;
     32 }
     33 
     34 
     35 /* creates .local/share/timetracker (or $XDG_DATA_HOME/timetracker) */
     36 /* assumes .local/share is already there */
     37 void createdatadir() {
     38     char * loc = filelocation();
     39     for (int i = strlen(loc) - 1; i >= 0; i--) {
     40         if (loc[i] == '/') {
     41             loc[i] = '\0';
     42             break;
     43         }
     44     }
     45     /* fails if directory exists already but that is no problem */
     46     mkdir(loc, 0777);
     47     free(loc);
     48 }
     49 
     50 
     51 struct program {
     52     char name[MAX_PROGRAM_NAME];
     53     int time;
     54 };
     55 
     56 char lastline[MAX_PROGRAM_NAME];
     57 time_t lasttime = 0;
     58 
     59 time_t writetime;
     60 
     61 struct program *programs = NULL;
     62 int programnum = 0; /* number of programs stored in the programs array */
     63 
     64 
     65 /* returns current time (this does not make sense but it is convenient) */
     66 /* this function was created to be able to add programs/write data file from
     67  * inside and outside the while loop in main(); the current solution with many
     68  * global variables is rather dirty but it works */
     69 time_t addprogram(_Bool forcewrite) {
     70     time_t newtime = time(NULL);
     71 
     72     if (lasttime) {
     73         /* is the program already in the list? (and where?) */
     74         int index = -1;
     75         for (int i = 0; i < programnum; i++) {
     76             if (!strcmp(lastline, programs[i].name)) {
     77                 index = i;
     78             }
     79         }
     80         if (index == -1) {
     81             /* extend/create list if necessary */
     82             if (programnum % 10 == 0) {
     83                 programs = realloc(programs, sizeof(struct program) *
     84                         (10 + programnum));
     85             }
     86             /* add new program to list */
     87             strncpy(programs[programnum].name, lastline, MAX_PROGRAM_NAME);
     88             programs[programnum].time = newtime - lasttime;
     89             programnum++;
     90         } else {
     91             /* update time for existing program */
     92             programs[index].time += newtime - lasttime;
     93         }
     94 
     95         if (writetime <= newtime || forcewrite) {
     96             /* write to data file */
     97             char *loc = filelocation();
     98             FILE *dataFile = fopen(loc, "a");;
     99             free(loc);
    100 
    101             fprintf(dataFile, "%d,", newtime);
    102             for (int i = 0; i < programnum - 1; i++) {
    103                 fprintf(dataFile, "%s:%d,", programs[i].name, programs[i].time);
    104             }
    105             fprintf(dataFile, "%s:%d\n", programs[programnum - 1].name, programs[programnum - 1].time);
    106             fclose(dataFile);
    107 
    108             /* reset everything */
    109             free(programs);
    110             programs = NULL;
    111             programnum = 0;
    112             writetime = newtime + WRITE_INTERVAL;
    113         }
    114     }
    115     return newtime;
    116 }
    117 
    118 
    119 /* cause getline() to throw error end return from main function */
    120 void exithandler(int dummy) {
    121     fclose(stdin);
    122 }
    123 
    124 
    125 int main() {
    126     createdatadir();
    127 
    128     signal(SIGHUP, exithandler);
    129     signal(SIGINT, exithandler);
    130     signal(SIGTERM, exithandler);
    131 
    132     /* ensures that no two timestamps in output file are identical */
    133     sleep(1);
    134 
    135     writetime = time(NULL) + WRITE_INTERVAL;
    136 
    137     size_t size = 0; /* i do not need this value but getline does */
    138     char *line = NULL; /* current line / program name */
    139     while (getline(&line, &size, stdin) != -1) {
    140         /* remove \n at the end of the line */
    141         line[strlen(line) - 1] = '\0';
    142         /* remove ":" and "," from program name because they would mess up
    143          * the output file */
    144         for (int i = 0; i < strlen(line); i++) {
    145             if (line[i] == ':' || line[i] == ',') line[i] = '-';
    146         }
    147 
    148         /* for the next iteration */
    149         lasttime = addprogram(0);
    150         strncpy(lastline, line, MAX_PROGRAM_NAME);
    151         lastline[MAX_PROGRAM_NAME - 1] = '\0';
    152     }
    153     free(line);
    154     addprogram(1);
    155 
    156     /* is this successful or unsuccessful? the program is meant to operate in
    157      * an infinite loop and be quit by sigterm */
    158     return 0;
    159 }