timekeeper

My first (abandoned unfinished) web application for time tracking
git clone git://jacobedwards.org/timekeeper
Log | Files | Refs | README

times.c (4238B)


      1 #include <assert.h>
      2 
      3 #define const
      4 
      5 #include <sys/types.h>
      6 #include <err.h>
      7 #include <stdarg.h>
      8 #include <stdint.h>
      9 #include <stdlib.h>
     10 #include <time.h>
     11 
     12 #include <kcgi.h>
     13 #include <kcgihtml.h>
     14 #include <sqlbox.h>
     15 
     16 #include "util.h"
     17 #include "stmt.h"
     18 #include "page.h"
     19 
     20 #include "times.h"
     21 
     22 char *timefields[] = {
     23 	[StartTime] = "start",
     24 	[BreakStartTime] = "startbreak",
     25 	[BreakEndTime] = "endbreak",
     26 	[EndTime] = "end"
     27 };
     28 
     29 enum time_flag timeflagmap[] = {
     30 	StartTimeFlag,
     31 	BreakStartTimeFlag,
     32 	BreakEndTimeFlag,
     33 	EndTimeFlag
     34 }; 
     35 
     36 int
     37 settime(struct pagedata *pd, char *hash, enum time_field f, time_t time)
     38 {
     39 	static enum StmtID map[] = {
     40 		[StartTime] = StmtStartTime,
     41 		[BreakStartTime] = StmtStartBreakTime,
     42 		[BreakEndTime] = StmtEndBreakTime,
     43 		[EndTime] = StmtEndTime
     44 	};
     45 
     46 	struct sqlbox_parm ps[] = {
     47 		{ .sparm = hash, .type = SQLBOX_PARM_STRING },
     48 		{ .iparm = time, .type = SQLBOX_PARM_INT },
     49 		{ .sparm = hash, .type = SQLBOX_PARM_STRING },
     50 		{ .sparm = hash, .type = SQLBOX_PARM_STRING }
     51 	};
     52 
     53 	assert(f >= StartTime && f <= EndTime);
     54 
     55 	if (!time)
     56 		return SQLBOX_CODE_ERROR;
     57 	if (f == StartTime) {
     58 		return sqlbox_exec(pd->db, pd->dbid, map[f],
     59 		    Len(ps) - 1, ps, 0) != SQLBOX_CODE_OK;
     60 	}
     61 	return sqlbox_exec(pd->db, pd->dbid, map[f],
     62 	    Len(ps) - 1, ps + 1, 0) != SQLBOX_CODE_OK;
     63 }
     64 
     65 int
     66 deletetime(struct pagedata *pd, char *hash, size_t entry)
     67 {
     68 	struct sqlbox_parm params[] = {
     69 		{ .sparm = hash, .type = SQLBOX_PARM_STRING },
     70 		{ .iparm = entry, .type = SQLBOX_PARM_INT }
     71 	};
     72 
     73 	return sqlbox_exec(pd->db, pd->dbid, StmtDeleteTime,
     74 	    Len(params), params, 0) != SQLBOX_CODE_OK;
     75 }
     76 
     77 int
     78 breaktime(struct pagedata *pd, char *hash)
     79 {
     80 	struct sqlbox_parm ps[] = {
     81 		{ .sparm = hash, .type = SQLBOX_PARM_STRING },
     82 		{ .sparm = hash, .type = SQLBOX_PARM_STRING }
     83 	};
     84 
     85 	return sqlbox_exec(pd->db, pd->dbid, StmtBreakTime,
     86 	    Len(ps), ps, 0) != SQLBOX_CODE_OK;
     87 }
     88 
     89 void
     90 freetimesheet(struct timesheet *ts)
     91 {
     92 	if (!ts)
     93 		return;
     94 
     95 	freetimesheet(ts->next);
     96 	free(ts);
     97 }
     98 
     99 struct timesheet *
    100 newtimesheet(void)
    101 {
    102 	return calloc(1, sizeof(struct timesheet));
    103 }
    104 
    105 struct timesheet *
    106 inserttimesheet(struct timesheet *ts, struct timesheet *list)
    107 {
    108 	if (ts) {
    109 		ts->prev = list;
    110 		ts->next = list->next;
    111 		list->next = ts;
    112 	}
    113 	return ts;
    114 } 
    115 
    116 void
    117 timesheet_set(struct timesheet *ts, enum time_field f, time_t v)
    118 {
    119 	assert(f >= StartTime && f <= EndTime);
    120 	ts->times[f] = v;
    121 	ts->set |= timeflagmap[f];
    122 }
    123 
    124 int
    125 gettimes(struct pagedata *pd, char *hash, int period, struct timesheet **rtimes)
    126 {
    127 	static unsigned int nreturn = 6;
    128 	size_t stmtid;
    129 	struct sqlbox_parm p[] = {
    130 		{ .sparm = hash, .type = SQLBOX_PARM_STRING },
    131 		{ .iparm = period, .type = (period <= 0 ? SQLBOX_PARM_NULL : SQLBOX_PARM_INT) },
    132 	};
    133 	struct sqlbox_parmset *r;
    134 	struct timesheet *times, *oldtime, *time;
    135 	unsigned int i;
    136 
    137 	stmtid = sqlbox_prepare_bind(pd->db, pd->dbid,
    138 	    period < 0 ? StmtGetTimes : StmtGetTimePeriod,
    139 	    period < 0 ? 1 : 2, p, 0);
    140 	if (stmtid == 0)
    141 		err(1, "prepare bind");
    142 
    143 	times = oldtime = NULL;
    144 	while ((r = sqlbox_step(pd->db, stmtid)) &&
    145 	    !(!r->psz && r->code == SQLBOX_CODE_OK)) {
    146 		assert(r->psz == nreturn);
    147 		oldtime = time;
    148 		time = newtimesheet();
    149 		if (!time) {
    150 			freetimesheet(times);
    151 			return 1;
    152 		}
    153 		if (!times)
    154 			times = time;
    155 		else if (oldtime)
    156 			inserttimesheet(time, oldtime);
    157 
    158 		for (i = 0; i < nreturn; ++i) {
    159 			switch (r->ps[i].type) {
    160 			case SQLBOX_PARM_NULL:
    161 				break;
    162 			case SQLBOX_PARM_INT:
    163 				if (i == 0)
    164 					time->period = r->ps[i].iparm;
    165 				else if (i == 1)
    166 					time->entry = r->ps[i].iparm;
    167 				else
    168 					timesheet_set(time, i - (nreturn - 4), r->ps[i].iparm);
    169 				break;
    170 			default:
    171 				err(1, "This is a stmt.c bug");
    172 			}
    173 		}
    174 		assert(i >= (nreturn - 4));
    175 	}
    176 
    177 	if (!sqlbox_finalise(pd->db, stmtid)) {
    178 		free(times);
    179 		err(1, "finalise");
    180 	}
    181 
    182 	*rtimes = times;
    183 	return 0;
    184 }
    185 
    186 time_t
    187 getduration(struct timesheet *ts)
    188 {
    189 	time_t s, e, o;
    190 
    191 	assert(ts->set & StartTimeFlag);
    192 
    193 	o = 0;
    194 	s = ts->times[StartTime];
    195 	if (ts->set & EndTimeFlag)
    196 		e = ts->times[EndTime];
    197 	else
    198 		e = time(NULL);
    199 
    200 	if (ts->set & BreakStartTimeFlag) {
    201 		if (ts->set & BreakEndTimeFlag)
    202 			o = ts->times[BreakEndTime] - ts->times[BreakStartTime];
    203 		else
    204 			e = ts->times[BreakStartTime];
    205 	}
    206 
    207 	return e - s - o;
    208 }