1 /*
2 * Routines for dealing with tasks
3 *
4 * Copyright:
5 * (C) 1999 Craig Knudsen, cknudsen@cknudsen.com
6 * See accompanying file "COPYING".
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * as published by the Free Software Foundation; either version 2
11 * of the License, or (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the
20 * Free Software Foundation, Inc., 59 Temple Place,
21 * Suite 330, Boston, MA 02111-1307, USA
22 *
23 * History:
24 * 17-Apr-2005 Add support for subtracting a particular offset
25 * off of timers. (Russ Allbery)
26 * 09-Mar-2000 Added functions to allow for restoring to
27 * a previous state: taskMark(), taskMarkAll(),
28 * taskRestore(), taskRestoreAll()
29 * 25-Mar-1999 Lots of WIN32 patches made by
30 * Thomas Epperly <Thomas.Epperly@aspentech.com>
31 * 18-Mar-1999 Internationalization
32 * 11-Nov-1998 Added support for options
33 * 23-Apr-1998 Added new function: taskClearAll
34 * 22-Mar-1998 Added an extra argument to TaskGetAnnotationEntries
35 * for time offset.
36 * 15-Mar-1998 Debugged all malloc/free and found one place
37 * where free() was not called.
38 * 15-Mar-1998 Fixed bug that caused SIGSEGV. Only appeared
39 * if one more tasks (but not the last one) were
40 * deleted.
41 * 15-Mar-1998 Added new function: taskAddAnnotation
42 * 11-Mar-1998 Changed functions to K&R style
43 *
44 */
45
46
47 #include <stdio.h>
48 #include <stdlib.h>
49 #include <time.h>
50 #if HAVE_UNISTD_H
51 #include <unistd.h>
52 #endif
53 #ifdef WIN32
54 #include <io.h>
55 #else
56 #include <dirent.h>
57 #endif
58 #include <errno.h>
59 #include <stdlib.h>
60 #include <string.h>
61 #include <ctype.h>
62 #include <sys/types.h>
63 #include <sys/stat.h>
64 #include <fcntl.h>
65
66 #include "task.h"
67
68 #ifdef GTIMER_MEMDEBUG
69 #include "memdebug/memdebug.h"
70 #endif
71
72 // PV: Internationalization
73 #include "gtimeri18n.h"
74
75 static int num_tasks = 0;
76 static Task **tasks = NULL;
77 static int max_task = -1;
78 static int last_number = -1;
79
80
81 #ifdef WIN32
valid_name(filename)82 static int valid_name ( filename )
83 char *filename;
84 {
85 while ( *filename && isdigit ( *filename ) )
86 filename++;
87 return ( ! strcmp ( filename, ".task" ) );
88 }
89 #endif
90
91
92 /*
93 ** Add a task.
94 */
taskAdd(task)95 void taskAdd ( task )
96 Task *task;
97 {
98 int loop;
99 int new_max_task = 0;
100
101 new_max_task = max_task;
102
103 if ( task->number == -1 ) {
104 for ( loop = 0; loop < max_task && task->number < 0; loop++ ) {
105 if ( tasks[loop] == NULL )
106 task->number = loop;
107 }
108 if ( task->number < 0 )
109 task->number = ++max_task;
110 new_max_task = max_task;
111 } else if ( task->number > max_task ) {
112 new_max_task = task->number;
113 }
114
115 if ( tasks == NULL ) {
116 tasks = (Task **) malloc ( sizeof ( Task * ) * ( new_max_task + 1 ) );
117 for ( loop = 0; loop < new_max_task; loop++ )
118 tasks[loop] = NULL;
119 } else
120 tasks = (Task **) realloc ( tasks,
121 sizeof ( Task * ) * ( new_max_task + 1 ) );
122
123 for ( loop = max_task + 1; loop <= new_max_task; loop++ )
124 tasks[loop] = NULL;
125
126 max_task = new_max_task;
127
128 tasks[task->number] = task;
129 num_tasks++;
130 }
131
132
133
134 /*
135 ** Create a new task
136 */
taskCreate(name)137 Task *taskCreate ( name )
138 char *name;
139 {
140 Task *task;
141
142 task = (Task *) malloc ( sizeof ( Task ) );
143 memset ( task, '\0', sizeof ( Task ) );
144 task->name = (char *) malloc ( strlen ( name ) + 1 );
145 strcpy ( task->name, name );
146 time ( &task->created );
147 task->number = -1; /* not yet assigned */
148
149 return ( task );
150 }
151
152
153 /*
154 ** Mark the current time in a task. We can then use taskRestore()
155 ** to restore the state of the task to what it was when this function
156 ** was called.
157 */
taskMark(task,offset)158 void taskMark ( task, offset )
159 Task *task;
160 int offset;
161 {
162 int i;
163 int seconds;
164
165 for ( i = 0; i < task->num_entries; i++ ) {
166 task->entries[i]->marked_seconds = task->entries[i]->seconds;
167 }
168 if ( offset > 0 && task->num_entries > 0 ) {
169 seconds = task->entries[task->num_entries - 1]->marked_seconds;
170 seconds -= offset;
171 if ( seconds < 0 )
172 seconds = 0;
173 task->entries[task->num_entries - 1]->marked_seconds = seconds;
174 }
175 }
176
177
178 /*
179 ** Mark the current time in all tasks so that we can use taskRestoreAll()
180 ** to restore the state of all tasks to where they are right now.
181 ** NOTE: this is intended to be used only with the timing elements.
182 ** Other stuff like annotations doesn't apply here, but annotations shouldn't
183 ** be added during idle time anyhow...
184 */
taskMarkAll(offset)185 void taskMarkAll ( offset )
186 int offset;
187 {
188 int loop;
189
190 for ( loop = 0; loop <= max_task; loop++ ) {
191 if ( tasks[loop] ) {
192 taskMark ( tasks[loop], offset );
193 }
194 }
195 }
196
197
198 /*
199 ** Restore a task to its previous state when taskMark() was called.
200 ** This is intended to allow the application to bookmark the state
201 ** of a task and then return to it (as far as timing data goes).
202 */
taskRestore(task)203 void taskRestore ( task )
204 Task *task;
205 {
206 int i;
207
208 for ( i = 0; i < task->num_entries; i++ ) {
209 task->entries[i]->seconds = task->entries[i]->marked_seconds;
210 }
211 }
212
213
214
215 /*
216 ** Restore all tasks to where they were when taskRestoreAll()
217 ** was called.
218 */
taskRestoreAll()219 void taskRestoreAll ()
220 {
221 int loop;
222
223 for ( loop = 0; loop <= max_task; loop++ ) {
224 if ( tasks[loop] ) {
225 taskRestore ( tasks[loop] );
226 }
227 }
228 }
229
230
231
232 /*
233 ** Delete a task.
234 */
taskDelete(task,taskdir)235 int taskDelete ( task, taskdir )
236 Task *task;
237 char *taskdir;
238 {
239 char *path;
240
241 path = (char *) malloc ( strlen ( taskdir ) + 10 );
242 sprintf ( path, "%s/%d.task", taskdir, task->number );
243 unlink ( path );
244 sprintf ( path, "%s/%d.ann", taskdir, task->number );
245 unlink ( path );
246 free ( path );
247
248 tasks[task->number] = NULL;
249 num_tasks--;
250 taskFree ( task );
251
252 return ( 0 );
253 }
254
255
256
257 /*
258 ** Return the number of tasks currently loaded.
259 */
taskCount()260 int taskCount () {
261 return ( num_tasks );
262 }
263
264
265
266 /*
267 ** Get a task by number.
268 */
taskGet(number)269 Task *taskGet ( number )
270 int number;
271 {
272 return ( tasks[number] );
273 }
274
275
276 /*
277 ** Get first task.
278 */
taskGetFirst()279 Task *taskGetFirst () {
280 last_number = -1;
281 return ( taskGetNext() );
282 }
283
284
285 /*
286 ** Get next task.
287 */
taskGetNext()288 Task *taskGetNext () {
289 int loop;
290
291 if ( ! num_tasks )
292 return ( NULL );
293
294 for ( loop = last_number + 1; loop <= max_task; loop++ ) {
295 if ( tasks[loop] ) {
296 last_number = loop;
297 return ( tasks[loop] );
298 }
299 }
300
301 return ( NULL );
302 }
303
304
305
306 /*
307 ** Clear all tasks out of memory.
308 */
taskClearAll()309 void taskClearAll ()
310 {
311 int loop;
312
313 for ( loop = 0; loop <= max_task; loop++ ) {
314 if ( tasks[loop] ) {
315 taskFree ( tasks[loop] );
316 tasks[loop] = 0;
317 }
318 }
319 num_tasks = 0;
320 last_number = max_task = -1;
321 }
322
323
324 /*
325 ** Save a task to it's task file.
326 */
taskSave(task,taskdir)327 int taskSave ( task, taskdir )
328 Task *task;
329 char *taskdir;
330 {
331 char *path;
332 FILE *fp;
333 int loop;
334
335 path = (char *) malloc ( strlen ( taskdir ) + 10 );
336 sprintf ( path, "%s/%d.task", taskdir, task->number );
337
338 fp = fopen ( path, "w" );
339 if ( !fp ) {
340 free ( path );
341 return ( TASK_ERROR_SYSTEM_ERROR );
342 }
343
344 fprintf ( fp, "Format: 1.2\n" );
345 fprintf ( fp, "Name: %s\n", task->name );
346 fprintf ( fp, "Created: %u\n", (unsigned int)task->created );
347 fprintf ( fp, "Options: %u\n", task->options );
348 fprintf ( fp, "Project: %d\n", task->project_id );
349 fprintf ( fp, "Data:\n" );
350
351 for ( loop = 0; loop < task->num_entries; loop++ ) {
352 if ( task->entries[loop]->seconds )
353 fprintf ( fp, "%04d%02d%02d %d\n",
354 task->entries[loop]->year, task->entries[loop]->mon,
355 task->entries[loop]->mday, task->entries[loop]->seconds );
356 }
357
358 fclose ( fp );
359 free ( path );
360
361 return ( 0 );
362 }
363
364
365 /*
366 ** Save all tasks
367 */
taskSaveAll(taskdir)368 int taskSaveAll ( taskdir )
369 char *taskdir;
370 {
371 int loop;
372 int ret;
373
374 for ( loop = 0; loop <= max_task; loop++ ) {
375 if ( tasks[loop] ) {
376 ret = taskSave ( tasks[loop], taskdir );
377 if ( ret )
378 return ( ret );
379 }
380 }
381 return ( 0 );
382 }
383
384
385
386 /*
387 ** Free all resources of a task.
388 */
taskFree(task)389 void taskFree ( task )
390 Task *task;
391 {
392 int loop;
393 free ( task->name );
394 for ( loop = 0; loop < task->num_entries; loop++ )
395 free ( task->entries[loop] );
396 if ( task->entries )
397 free ( task->entries );
398 for ( loop = 0; loop < task->num_annotations; loop++ ) {
399 free ( task->annotations[loop]->text );
400 free ( task->annotations[loop] );
401 }
402 if ( task->annotations )
403 free ( task->annotations );
404 free ( task );
405 }
406
407
408
409 /*
410 ** Load a task from file.
411 */
taskLoad(path,task)412 int taskLoad ( path, task )
413 char *path;
414 Task **task;
415 {
416 FILE *fp;
417 int fd;
418 Task *newtask;
419 char line[512], *ptr, *ptr2, temp[10], *annfile, *anntext;
420 int len, created, number, options, project_id = -1;
421 TaskTimeEntry *entry;
422 TaskAnnotation *a;
423 struct stat buf;
424
425 fp = fopen ( path, "r" );
426 if ( !fp )
427 return ( TASK_ERROR_SYSTEM_ERROR );
428
429 for ( ptr = path + strlen ( path ) - 1; *ptr != '/' && ptr != path; ptr-- );
430 if ( *ptr == '/' )
431 ptr++;
432 sscanf ( ptr, "%d.task", &number );
433
434 fgets ( line, 512, fp );
435 len = strlen ( line );
436 if ( line[len-1] == '\n' )
437 line[len-1] = '\0';
438 if ( strcmp ( line, "Format: 1.0" ) && strcmp ( line, "Format: 1.1" ) &&
439 strcmp ( line, "Format: 1.2" ) ) {
440 fclose ( fp );
441 return ( TASK_ERROR_BAD_FILE );
442 }
443
444 newtask = (Task *) malloc ( sizeof ( Task ) );
445 memset ( newtask, '\0', sizeof ( Task ) );
446 newtask->number = number;
447 newtask->project_id = -1; /* no project */
448
449 while ( fgets ( line, 512, fp ) ) {
450 len = strlen ( line );
451 if ( line[len-1] == '\n' )
452 line[len-1] = '\0';
453 if ( strncmp ( line, "Name:", 5 ) == 0 ) {
454 ptr = line + 5;
455 if ( *ptr == ' ' )
456 ptr++;
457 newtask->name = (char *) malloc ( strlen ( ptr ) + 1 );
458 strcpy ( newtask->name, ptr );
459 } else if ( strncmp ( line, "Created:", 8 ) == 0 ) {
460 sscanf ( line + 8, "%d", &created );
461 newtask->created = (time_t) created;
462 } else if ( strncmp ( line, "Project:", 8 ) == 0 ) {
463 sscanf ( line + 8, "%d", &project_id );
464 newtask->project_id = project_id;
465 } else if ( strncmp ( line, "Options:", 8 ) == 0 ) {
466 sscanf ( line + 8, "%d", &options );
467 newtask->options = (unsigned int) options;
468 } else if ( strcmp ( line, "Data:" ) == 0 ) {
469 while ( fgets ( line, 512, fp ) ) {
470 entry = (TaskTimeEntry *) malloc ( sizeof ( TaskTimeEntry ) );
471 memset ( entry, '\0', sizeof ( TaskTimeEntry ) );
472 strncpy ( temp, line, 4 );
473 temp[4] = '\0';
474 entry->year = atoi ( temp );
475 strncpy ( temp, line + 4, 2 );
476 temp[2] = '\0';
477 entry->mon = atoi ( temp );
478 strncpy ( temp, line + 6, 2 );
479 temp[2] = '\0';
480 entry->mday = atoi ( temp );
481 entry->seconds = atoi ( line + 9 );
482 entry->marked_seconds = entry->seconds;
483 if ( ! newtask->entries )
484 newtask->entries = (TaskTimeEntry **) malloc (
485 sizeof ( TaskTimeEntry * ) );
486 else
487 newtask->entries = (TaskTimeEntry **) realloc ( newtask->entries,
488 sizeof ( TaskTimeEntry * ) * ( newtask->num_entries + 1 ) );
489 newtask->entries[newtask->num_entries] = entry;
490 newtask->num_entries++;
491 }
492 break;
493 } else {
494 fclose ( fp );
495 taskFree ( newtask );
496 return ( TASK_ERROR_BAD_FILE );
497 }
498 }
499 fclose ( fp );
500
501 /* now load annotations */
502 annfile = (char *) malloc ( strlen ( path ) + 1 );
503 strcpy ( annfile, path );
504 ptr = annfile + strlen ( annfile ) - 5;
505 if ( strcmp ( ptr, ".task" ) == 0 ) {
506 strcpy ( ptr, ".ann" );
507 if ( stat ( annfile, &buf ) == 0 ) {
508 fd = open ( annfile, O_RDONLY );
509 anntext = (char *) malloc ( buf.st_size + 1 );
510 read ( fd, anntext, buf.st_size );
511 anntext[buf.st_size] = '\0';
512 close ( fd );
513 ptr = strtok ( anntext, "\n" );
514 while ( ptr ) {
515 ptr2 = ptr;
516 while ( isdigit ( *ptr2 ) )
517 ptr2++;
518 if ( *ptr2 == ' ' ) {
519 *ptr2 = '\0';
520 a = (TaskAnnotation *) malloc ( sizeof ( TaskAnnotation ) );
521 memset ( a, '\0', sizeof ( TaskAnnotation ) );
522 a->text_time = atoi ( ptr );
523 ptr2++;
524 a->text = (char *) malloc ( strlen ( ptr2 ) + 1 );
525 strcpy ( a->text, ptr2 );
526 for ( ptr2 = a->text; *ptr2 != '\0'; ptr2++ )
527 if ( *ptr2 == '\r' )
528 *ptr2 = '\n';
529 if ( newtask->annotations == NULL ) {
530 newtask->annotations = (TaskAnnotation **) malloc (
531 sizeof ( TaskAnnotation * ) );
532 } else {
533 newtask->annotations = (TaskAnnotation **) realloc (
534 newtask->annotations,
535 ( newtask->num_annotations + 1 ) * sizeof ( TaskAnnotation * ) );
536 }
537 newtask->annotations[newtask->num_annotations] = a;
538 newtask->num_annotations++;
539 }
540 ptr = strtok ( NULL, "\n" );
541 }
542 free ( anntext );
543 }
544 }
545 free ( annfile );
546
547 taskAdd ( newtask );
548
549 *task = newtask;
550
551 return ( 0 );
552 }
553
554
555
taskLoadAll(taskdir)556 int taskLoadAll ( taskdir )
557 char *taskdir;
558 {
559 #ifdef WIN32
560 char *pattern;
561 Task *task;
562 long handle;
563 struct _finddata_t fdata;
564 pattern = malloc ( strlen ( taskdir ) + 8 );
565 (void) strcat ( strcpy ( pattern, taskdir ), "/*.task" );
566 if ( ( handle = _findfirst ( pattern, &fdata ) ) != -1 ) {
567 char *path = malloc ( strlen ( taskdir ) + _MAX_FNAME + 2 );
568 char *start = path + strlen ( taskdir ) + 1;
569 (void) strcat ( strcpy ( path, taskdir ), "/" );
570 do {
571 (void) strcpy ( start, fdata.name );
572 if ( valid_name ( fdata.name ) && !_access ( path, 4 ) ){
573 taskLoad ( path, &task );
574 }
575 } while ( !_findnext ( handle, &fdata ) );
576 _findclose ( handle );
577 free ( path );
578 }
579 else {
580 free ( pattern );
581 return ( TASK_ERROR_SYSTEM_ERROR );
582 }
583 free ( pattern );
584 #else
585 DIR *dir;
586 struct dirent *entry;
587 struct stat buf;
588 char *path, *ptr;
589 Task *task;
590
591 dir = opendir ( taskdir );
592 if ( ! dir )
593 return ( TASK_ERROR_SYSTEM_ERROR );
594 while ( ( entry = readdir ( dir ) ) ) {
595 path = (char *) malloc ( strlen ( taskdir ) + strlen ( entry->d_name )
596 + 2 );
597 sprintf ( path, "%s/%s", taskdir, entry->d_name );
598 if ( stat ( path, &buf ) == 0 ) {
599 for ( ptr = entry->d_name; isdigit ( *ptr ); ptr++ ) ;
600 if ( strcmp ( ptr, ".task" ) == 0 && S_ISREG ( buf.st_mode ) ) {
601 /* NOTE: add catching of errors here... */
602 taskLoad ( path, &task );
603 }
604 }
605 free ( path );
606 }
607
608 #endif
609 return ( 0 );
610 }
611
612
taskErrorString(task_error)613 char *taskErrorString ( task_error )
614 int task_error;
615 {
616 static char msg[256];
617
618 switch ( task_error ) {
619 case TASK_ERROR_SYSTEM_ERROR:
620 sprintf ( msg, gettext("System Error (%d)"), errno );
621 return ( msg );
622 case TASK_ERROR_BAD_FILE:
623 return ( gettext("Invalid task data file format") );
624 default:
625 sprintf ( msg, gettext("Unknown error (%d)"), task_error );
626 return ( msg );
627 }
628 }
629
630
631
632
taskGetTimeEntry(task,year,month,day)633 TaskTimeEntry *taskGetTimeEntry ( task, year, month, day )
634 Task *task;
635 int year, month, day;
636 {
637 int loop;
638 struct tm *tm;
639 time_t now;
640
641 if ( year < 100 ) {
642 time ( &now );
643 tm = localtime ( &now );
644 year += 1900 + ( tm->tm_year % 100 );
645 }
646
647 for ( loop = 0; loop < task->num_entries; loop++ ) {
648 if ( task->entries[loop]->year == year &&
649 task->entries[loop]->mon == month &&
650 task->entries[loop]->mday == day )
651 return ( task->entries[loop] );
652 }
653
654 return ( NULL );
655 }
656
657
658
659
taskNewTimeEntry(task,year,month,day)660 TaskTimeEntry *taskNewTimeEntry ( task, year, month, day )
661 Task *task;
662 int year, month, day;
663 {
664 struct tm *tm;
665 time_t now;
666 TaskTimeEntry *ret;
667
668 if ( year < 100 ) {
669 time ( &now );
670 tm = localtime ( &now );
671 year += 1900 + ( tm->tm_year % 100 );
672 }
673
674 ret = (TaskTimeEntry *) malloc ( sizeof ( TaskTimeEntry ) );
675
676 ret->year = year;
677 ret->mon = month;
678 ret->mday = day;
679 ret->seconds = 0;
680 ret->marked_seconds = 0;
681
682 if ( task->entries )
683 task->entries = (TaskTimeEntry **) realloc ( task->entries,
684 ( task->num_entries + 1 ) * ( sizeof ( TaskTimeEntry * ) ) );
685 else
686 task->entries = (TaskTimeEntry **) malloc ( ( task->num_entries + 1 )
687 * ( sizeof ( TaskTimeEntry * ) ) );
688 task->entries[task->num_entries] = ret;
689 task->num_entries++;
690
691 return ( ret );
692 }
693
694
695 /*
696 ** Get the options for the specified task.
697 */
taskGetOptions(task)698 unsigned int taskGetOptions ( task )
699 Task *task;
700 {
701 return task->options;
702 }
703
704
705 /*
706 ** Determine if the specified option is enabled.
707 */
taskOptionEnabled(task,option)708 unsigned int taskOptionEnabled ( task, option )
709 Task *task;
710 unsigned int option;
711 {
712 if ( option & task->options )
713 return 1;
714 else
715 return 0;
716 }
717
718
taskSetOption(task,option)719 void taskSetOption ( task, option )
720 Task *task;
721 unsigned int option;
722 {
723 task->options |= option;
724 }
725
taskUnsetOption(task,option)726 void taskUnsetOption ( task, option )
727 Task *task;
728 unsigned int option;
729 {
730 if ( taskOptionEnabled ( task, option ) )
731 task->options -= option;
732 }
733
734 /*
735 ** Add a task annotation to a task. Can be more than one line of
736 ** text. We will convert '\n' into '\r' before saving and then
737 ** back when loading.
738 ** Note: It gets saved immediately (not when taskSave is called)
739 */
taskAddAnnotation(task,taskdir,text)740 void taskAddAnnotation ( task, taskdir, text )
741 Task *task;
742 char *taskdir;
743 char *text;
744 {
745 char *ptr, *path, *newtext;
746 TaskAnnotation *a;
747 FILE *fp;
748
749 a = (TaskAnnotation *) malloc ( sizeof ( TaskAnnotation ) );
750 memset ( a, '\0', sizeof ( TaskAnnotation ) );
751 time ( &a->text_time );
752 a->text = (char *) malloc ( strlen ( text ) + 1 );
753 strcpy ( a->text, text );
754
755 if ( task->annotations == NULL ) {
756 task->annotations = (TaskAnnotation **) malloc (
757 sizeof ( TaskAnnotation * ) );
758 } else {
759 task->annotations = (TaskAnnotation **) realloc ( task->annotations,
760 ( task->num_annotations + 1 ) * sizeof ( TaskAnnotation * ) );
761 }
762 task->annotations[task->num_annotations] = a;
763 task->num_annotations++;
764
765 /* now save to file */
766 path = (char *) malloc ( strlen ( taskdir ) + 10 );
767 sprintf ( path, "%s/%d.ann", taskdir, task->number );
768 fp = fopen ( path, "a+" );
769 if ( fp ) {
770 newtext = (char *) malloc ( strlen ( text ) + 1 );
771 strcpy ( newtext, text );
772 for ( ptr = newtext; *ptr != '\0'; ptr++ )
773 if ( *ptr == '\n' )
774 *ptr = '\r';
775 fprintf ( fp, "%d %s\n", (int)a->text_time, newtext );
776 free ( newtext );
777 fclose ( fp );
778 }
779 free ( path );
780 }
781
782
783
784 /*
785 ** Get all annotations for the specified task on the specified day.
786 ** NOTE: Caller must free return value.
787 ** ??? Maybe we should take the midnight offset into consideration here ???
788 */
TaskGetAnnotationEntries(task,year,month,day,time_offset,num_ret)789 TaskAnnotation **TaskGetAnnotationEntries ( task, year, month, day,
790 time_offset, num_ret )
791 Task *task;
792 int year, month, day;
793 int time_offset;
794 int *num_ret;
795 {
796 TaskAnnotation **ret = NULL;
797 int loop = 0;
798 struct tm *tm;
799 int num = 0;
800 time_t then;
801
802 for ( loop = 0; loop < task->num_annotations; loop++ ) {
803 then = task->annotations[loop]->text_time - time_offset;
804 tm = localtime ( &then );
805 if ( tm->tm_year + 1900 == year &&
806 tm->tm_mon + 1 == month &&
807 tm->tm_mday == day ) {
808 if ( num ) {
809 ret = (TaskAnnotation **) realloc ( ret,
810 ( num + 1 ) * sizeof ( TaskAnnotation * ) );
811 } else {
812 ret = (TaskAnnotation **) malloc ( sizeof ( TaskAnnotation * ) );
813 }
814 ret[num] = task->annotations[loop];
815 num++;
816 }
817 }
818
819 *num_ret = num;
820 return ( ret );
821 }
822
823
824
825