#include #include #include #include #include /* * * sleep.c - plots a sleep diary * version 0.2 * (c) 2001 Steve G Parker (steve@steve-parker.org) * * * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * */ /* 2 data files: Could be 0+ entries in sleep for 1 in date, or vice-versa. # NB: Need to check this is true! But there is only one diary entry per day. sleep.dat=try sleep wake diary.dat=date overall feel comments pints, time-started drinking (eg, 22 00) Comments are allowed if "#" starts the line. Anything after the end of the line is also a comment. eg sleep.dat: 11 May 00 30 11 May 01 00 11 May 08 00 # went to bed 0:30am, slept 1-8am 12 May 01 30 12 May 01 30 12 May 09 00 eg diary.dat: Fri 11 May 3 2 22 00 # felt 3/5 on Fri 11 May, had 2 pints at 10pm This is one line # This is "how did you feel?" This is another ... # This is other comments. Sat 12 May 1 Woke up OK Felt lousy rest of the day */ #define MAXLINE 600 // the longest line allowed in the sleep.dat file #define MAXENTRY 300 // the longest item allowed. #define RATIO 0.33 // ratio of minutes to pixels; 0.25 = 4minutes:1 pixel (works OK) #define MAXENTRIES 300 // the max. no. of lines in sleep.dat int stats[3][MAXENTRIES]; #define ACT_TRY 0 // These are for the #define ACT_SLEEP 1 // stats array #define ACT_WAKE 2 // above. struct tod { int dom; char mon[5]; int h; int m; }; struct sleep_struct { struct tod try; struct tod sleep; struct tod wake; }; struct diary_struct { int dom; char dow[5]; char mon[5]; int overall; int pints; int pintsh, pintsm; char how_feel[MAXENTRY]; char comments[MAXENTRY]; }; void sgp(int i) { printf("Debug: %d\n", i); ; } void todo() { // printf("

Todo:

\n"); } void krqsort(int v[], int left, int right) { /* qsort from K&R; renamed from qsort as glibc already has a qsort */ int i, last, x, y; if (left>=right) return; x=(left+right)/2; y=v[left]; v[left]=v[x]; v[x]=y; last=left; for (i=left+1; i <= right; i++) if (v[i] < v[left]) { last++; y=v[last]; v[last]=v[i]; v[i]=y; } y=v[left]; v[left]=v[last]; v[last]=y; krqsort(v, left, last-1); krqsort(v, last+1, right); } void sort_stats(int idx) { int i; for (i=0; i<3; i++) { /* Sort stats[i] */ krqsort(stats[i], 0, idx); } } void m2mh(int min, char *s) { int m,h; m=(min % 60); h=(min / 60); sprintf(s, "%02d : %02d", h, m); } void show_stats(int idx) { int i,j,c,mode; char t[10]; /* // This shows the raw data, be it sorted or unsorted. printf("\n"); for (i=0; i<3; i++) { printf(""); for (j=0; j<=idx; j++) { printf("", stats[i][j]); } printf("\n"); } printf("
%d
\n"); */ printf("\n"); printf("\n"); m2mh(stats[ACT_TRY][0], t); printf("", t); m2mh(stats[ACT_TRY][idx], t); printf("", t); // calc mean here for (i=0; i<=idx; i++) { c+=stats[ACT_TRY][i]; } c=(c/idx); m2mh(c, t); printf("", t); // calc mode here if ((idx%2) == 1) mode=stats[ACT_TRY][idx/2]; else { c=idx/2; // this rounds up... mode=(stats[ACT_TRY][c] + stats[ACT_TRY][c+1]) /2; } m2mh(mode, t); printf("\n", t); m2mh(stats[ACT_SLEEP][0], t); printf("", t); m2mh(stats[ACT_SLEEP][idx], t); printf("", t); // calc mean here for (i=0; i<=idx; i++) { c+=stats[ACT_SLEEP][i]; } c=(c/idx); m2mh(c, t); printf("", t); if ((idx%2) == 1) mode=stats[ACT_SLEEP][idx/2]; else { c=idx/2; // this rounds up... mode=(stats[ACT_SLEEP][c] + stats[ACT_SLEEP][c+1]) /2; } m2mh(mode, t); printf("\n", t); m2mh(stats[2][0], t); printf("", t); m2mh(stats[2][idx], t); printf("", t); // calc mean here for (i=0; i<=idx; i++) { c+=stats[ACT_WAKE][i]; } c=(c/idx); m2mh(c, t); printf("", t); if ((idx%2) == 1) mode=stats[ACT_WAKE][idx/2]; else { c=idx/2; // this rounds up... mode=(stats[ACT_WAKE][c] + stats[ACT_WAKE][c+1]) /2; } m2mh(mode, t); printf("\n", t); printf("
StatsMinMaxMeanMode
Trying%s%s%s%s
Sleeping%s%s%s%s
Awake%s%s%s%s
\n"); } void cat_file(char *filename) { FILE *myfile=fopen(filename, "r"); char *buf=(char*)malloc(256); while (fgets(buf, 255, myfile)!=NULL) printf("%s", buf); fclose(myfile); free(buf); } void html_header() { cat_file("header"); } void html_footer() { cat_file("footer"); } void end_line(struct diary_struct *d, int h, int m) { if ((h==24) && (m==0)) { printf("%d%s%s\n", d->overall, d->how_feel, d->comments); } } int show_tod(int h1, int m1, int h, int m, char *s) { int res, width; int min1, min2; /* Note: 00:00 is the start of the day; 24:00 is the end! */ min1=(h1*60)+m1; min2=(h*60)+m; res=min2-min1; width=res*RATIO; //printf("%-6s: %02d:%02d until %02d:%02d\n", s, h1, m1, h, m); if ( (width>0) && (h!=99) && (m!=99) ) printf("\"%s", s, width, s, h1, m1, h, m); //printf("\nshow_tod=%d (%s)\n", res, s); return res; } int show_drink(int left, int pints, int h, int m) { int start, finish, finish_today, duration, sober, width; start=h*60 + m; finish=start+(pints*2*60); if (finish > (24 * 60)) finish_today=(24 * 60); else finish_today=finish; duration = finish_today-start; width=left * RATIO; if (left>0) { printf("\"drink\"", width); } sober=(24 * 60) - left - duration; width=sober * RATIO; if (sober>0) { printf("", width); } width=duration * RATIO; if (duration>0) { printf("\"drink\"", width); } printf("
\n"); if (finish != finish_today) left = finish - (24 * 60); else left=0; return left; } void parse_diary(char *d, struct diary_struct *diary) { sscanf(d, "%s %d %s %d %d %d %d\n", &diary->dow, &diary->dom, &diary->mon, &diary->overall, &diary->pints, &diary->pintsh, &diary->pintsm); } void parse_sleep(char *s, struct sleep_struct *sleep) { sscanf(s, "%d %s %d %d %d %s %d %d %d %s %d %d %d\n", &sleep->try.dom, &sleep->try.mon, &sleep->try.h, &sleep->try.m, &sleep->sleep.dom, &sleep->sleep.mon, &sleep->sleep.h, &sleep->sleep.m, &sleep->wake.dom, &sleep->wake.mon, &sleep->wake.h, &sleep->wake.m); } int getdelim(char *s, unsigned int lim, char delim, FILE *stream) { int c,i=0; while (--lim > 0 && (c=getc(stream)) != EOF && c != delim) s[i++] = c; if (c == delim) s[i++] = c; s[i]='\0'; return i; } int getline(char *s, FILE *stream) { /* Get the next non-comment line */ int res; s[0]='#'; while (s[0]=='#') { res=getdelim(s, MAXLINE, '\n', stream); } return res; } int getsleep(struct sleep_struct *s, FILE *stream) { char l[MAXLINE]; int res; res=getline(l, stream); if (res>0) { parse_sleep(l, s); } return res; } int getdiary(struct diary_struct *d, FILE *stream) { struct diary_struct *diary; char l1[MAXLINE]; char l2[MAXLINE]; int res; res=getline(l1, stream); if (res>0) { res=getline(l2, stream); if (res>0) { strcpy(d->how_feel, l2); d->how_feel[strlen(d->how_feel)-1]='\0'; // chomp res=getline(l2, stream); if (res>0) { strcpy(d->comments, l2); d->comments[strlen(d->comments)-1]='\0'; // chomp parse_diary(l1, d); } } } return res; } int same_day(struct sleep_struct *s, struct diary_struct *d) { /* returns : 0 if the days do not match 1 if the try entry matches the diary OR'ed with 2 if the sleep entry matches the diary OR'ed with 4 if the wake entry matches the diary */ int res=0; if ( (s->try.dom==d->dom) && (!strcmp(s->try.mon, d->mon)) ) res+=1; /* else printf("try.dom=%d, d.dom=%d; try.mon=%s, d.mon=%s\n", s->try.dom, d->dom, s->try.mon, d->mon); */ if ( (s->sleep.dom==d->dom) && (!strcmp(s->sleep.mon, d->mon)) ) res+=2; /* else printf("sleep.dom=%d, d.dom=%d; sleep.mon=%s, d.mon=%s\n", s->sleep.dom, d->dom, s->sleep.mon, d->mon); */ if ( (s->wake.dom==d->dom) && (!strcmp(s->wake.mon, d->mon)) ) res+=4; /* else printf("wake.dom=%d, d.dom=%d; wake.mon=%s, d.mon=%s\n", s->wake.dom, d->dom, s->wake.mon, d->mon); */ return res; } main() { FILE *sleep_dat; FILE *diary_dat; char s[MAXLINE]; char d[MAXLINE]; char bgcolor[20]; struct diary_struct *diary; struct sleep_struct *sleep; struct sleep_struct *newsleep; int same, more_records=1; int h,m; int drink_left=0; int firsttoday; int idx=-1; // int counter=0; int activity=ACT_WAKE; // This assumes that the first entry is "try", which it must be, really. sleep_dat=fopen("sleep.dat", "r"); diary_dat=fopen("diary.dat", "r"); sleep =malloc(sizeof(struct sleep_struct)); newsleep=malloc(sizeof(struct sleep_struct)); diary =malloc(sizeof(struct diary_struct)); html_header(); todo(); printf("\n"); same=(24 * 60 * RATIO)+2; // I know it's bad, but I'm using a variable temporarily before it's assigned... // Also, Konqueror doesn't like it if we round down, so we add 1. 2 to be safe. printf("\n", same); getsleep(sleep, sleep_dat); while (getdiary(diary, diary_dat)>0) { firsttoday=1; if ( (!strcmp(diary->dow, "Fri")) || (!strcmp(diary->dow, "Sat")) ) sprintf(bgcolor, "silver"); else sprintf(bgcolor, "aqua"); printf("
DateSleep1-5How FeelComments
%s %d %s", bgcolor, diary->dow, diary->dom, diary->mon); drink_left=show_drink(drink_left, diary->pints, diary->pintsh, diary->pintsm); same=same_day(sleep,diary); //printf("Today is %s %d %s - ", diary->dow, diary->dom, diary->mon); //printf("%s (%s)\n", diary->how_feel, diary->comments); // printf("sleep->try=%d %s @ %02d:%02d\n", sleep->try.dom, sleep->try.mon, sleep->try.h, sleep->try.m); while (same>0) { same=same_day(sleep,diary); //printf("Entering loop... same=%d\n", same); if ((same & 1) == 1) { if (activity!=ACT_TRY) { /* We were awake before now; update the statistics. */ idx++; //if (idx>=0) stats[ACT_WAKE][idx]+=counter; stats[ACT_TRY][idx]=0; //counter=0; } activity=ACT_TRY; if ((same & 2) == 2) { /* Slept same day; calculate it! */ h=sleep->sleep.h; m=sleep->sleep.m; } else { h=24; m=0; } if (firsttoday) { stats[ACT_WAKE][idx-1]+=show_tod(0,0,sleep->try.h, sleep->try.m, "wake"); end_line(diary, sleep->try.h, sleep->try.m); } stats[ACT_TRY][idx]+=show_tod(sleep->try.h, sleep->try.m, h, m, "try"); end_line(diary, h, m); firsttoday=0; } if ((same & 2) == 2) { if (activity!=ACT_SLEEP) { /* We were trying before now; update the statistics. */ //stats[ACT_TRY][idx]+=counter; //printf("\nTRY=%d\n", counter); stats[ACT_SLEEP][idx]=0; //counter=0; } activity=ACT_SLEEP; if ((same & 4) == 4) { /* Woke same day; calculate it! */ h=sleep->wake.h; m=sleep->wake.m; } else { h=24; m=0; } if (firsttoday) { stats[ACT_TRY][idx]+=show_tod(0,0,sleep->sleep.h, sleep->sleep.m, "try"); end_line(diary, sleep->sleep.h, sleep->sleep.m); } stats[ACT_SLEEP][idx]+=show_tod(sleep->sleep.h, sleep->sleep.m, h, m, "sleep"); end_line(diary, h, m); firsttoday=0; } if ((more_records>0) && ((same & 4)== 4)) { // printf("getting newsleep...\n"); more_records=getsleep(newsleep, sleep_dat); // have to quit if no more sleep entries ... same=same_day(newsleep,diary); // printf("new same=%d\n", same); /* I've completed the current sleep record, so I'm awake. (records go try->sleep->wake) If I stay awake for the rest of the day, then draw an "awake" (transparent) bar until midnight. But if I try to sleep during the same day, the "awake" bar is shorter... We know that same & 4 == 4 in this if{} statement. */ if (more_records==0) { same=0; newsleep->try.h=newsleep->try.m=newsleep->sleep.h=newsleep->sleep.m=newsleep->wake.h=newsleep->wake.m=0; } if ((same & 1) == 1) { /* We try to sleep today */ h=newsleep->try.h; m=newsleep->try.m; } else { h=24; m=0; } if (activity!=ACT_WAKE) { /* We were asleep before now; update the statistics. */ //stats[ACT_SLEEP][idx]+=counter; stats[ACT_WAKE][idx]=0; //counter=0; } activity=ACT_WAKE; // printf("Note Here: same=%d\n", same); if (firsttoday) { stats[ACT_TRY][idx]+=show_tod(0,0,sleep->wake.h, sleep->wake.m, "sleep"); end_line(diary, sleep->wake.h, sleep->wake.m); } stats[ACT_WAKE][idx]+=show_tod(sleep->wake.h, sleep->wake.m, h, m, "wake"); end_line(diary, h, m); firsttoday=0; //printf("a) sleep->try=%d %s @ %02d:%02d\n", sleep->try.dom, sleep->try.mon, sleep->try.h, sleep->try.m); // printf("BTW: sleep->wake.dom=%d\n", sleep->wake.dom); // printf("Copying newsleep to sleep...\n"); //printf("b) sleep->try=%d %s @ %02d:%02d\n", sleep->try.dom, sleep->try.mon, sleep->try.h, sleep->try.m); // This doesn't seem to be working! memcpy(sleep, newsleep, sizeof(struct sleep_struct)); //same=1)) { // same=0; // } //bcopy(newsleep, sleep, sizeof(sleep)); //printf("c) sleep->try=%d %s @ %02d:%02d\n", sleep->try.dom, sleep->try.mon, sleep->try.h, sleep->try.m); } else same=0; } // while same } // while getdiary printf("
\n"); //show_stats(idx); sort_stats(idx); show_stats(idx); html_footer(); fclose(sleep_dat); fclose(diary_dat); free(sleep); free(newsleep); free(diary); }