2 * See LICENSE file for copyright and license details.
12 enum { after_last
= 25, dyn
= -1 };
13 enum week
{ Sun
, Mon
, Tue
, Wed
, Thu
, Fri
, Sat
, e_day
};
14 enum year
{ Jan
, Feb
, Mar
, Apr
, May
, Jun
, Jul
, Aug
, Sep
, Oct
, Nov
, Dec
, e_mon
};
33 /* function declarations */
34 static void usage(void);
35 static char *convert_timet_to_str(const time_t, const char);
36 static time_t convert_hour_min_timet(const int*);
37 static time_t adj_st(const int*, const time_t);
38 static time_t adj_end(const time_t, int);
39 static int accepted_task(Task
);
40 static void gather_info(size_t*, size_t*, size_t);
41 static Task
*create_acct(size_t, size_t*, size_t);
42 static Task_t
*create_rett(Task
*, size_t*);
43 static int validate_fixed(size_t*, size_t*, Task_t
*, Task
*);
44 static int validate_dyn(size_t*, Task_t
*, Task
*);
45 static void print_t(const char);
47 /* function implementations */
51 die("usage: splanner -[AaNnv]\noptions:\n \
52 -A print all tasks, 12-hour clock format.\n \
53 -a print all tasks.\n \
54 -N print all upcoming tasks, 12-hour clock format.\n \
55 -n print all upcoming tasks.\n \
60 convert_timet_to_str(const time_t input_time
, const char option
)
63 size_t result_size
= (size_t)32;
64 struct tm new_time
= *localtime(&input_time
);
66 result
= ecalloc(result_size
, sizeof(char));
67 if ((option
== 'A' || option
== 'N') && (new_time
.tm_hour
> 12)){
68 new_time
.tm_hour
= new_time
.tm_hour
- 12;
70 (void)snprintf(result
, result_size
, "%.2d:%.2d",
71 new_time
.tm_hour
, new_time
.tm_min
);
76 convert_hour_min_timet(const int *arr
)
78 const int hours
= arr
[0];
79 const int minutes
= arr
[1];
85 tmnow
= *localtime(&now
);
86 tmnow
.tm_hour
= hours
;
87 tmnow
.tm_min
= minutes
;
89 converted
= mktime(&tmnow
);
94 adj_st(const int *config_start_time_array
, time_t last_task_endtime
)
97 int config_hours
= config_start_time_array
[0];
99 if (config_hours
== (int)after_last
) {
100 result
= last_task_endtime
;
103 result
= convert_hour_min_timet(config_start_time_array
);
109 adj_end(const time_t start_time
, int duration
)
111 time_t returned_time
;
112 duration
= duration
* 60;
113 returned_time
= start_time
+ duration
;
114 return returned_time
;
118 accepted_task(Task tested_task
)
120 const time_t current_time
= time(NULL
);
121 const struct tm current_date
= *localtime(¤t_time
);
122 const int t_day
= current_date
.tm_wday
;
123 const int t_mon
= current_date
.tm_mon
;
126 ((tested_task
.day
== e_day
) &&
127 (tested_task
.mon
== e_mon
)) ||
129 (((int)tested_task
.day
== t_day
) &&
130 (tested_task
.mon
== e_mon
)) ||
132 (((int)tested_task
.day
== t_day
) &&
133 ((int)tested_task
.mon
== t_mon
))
142 gather_info(size_t *acctl
, size_t *fixedl
, size_t config_l
)
144 /* count accepted tasks */
145 /* count fixed tasks */
147 for (i
=0; i
<config_l
; i
++) {
148 if (accepted_task(config_tasks
[i
]) == 0) {
150 if (config_tasks
[i
].st
[0] < (int)after_last
) {
158 create_acct(size_t acctl
, size_t *tnmax
, size_t config_l
)
160 /* copy accepted from config_tasks */
161 /* set max task name length */
163 acct
= ecalloc(acctl
, sizeof(Task
));
168 for (i
=0; i
<config_l
; i
++){
169 if (accepted_task(config_tasks
[i
]) == 0) {
170 acct
[a
] = config_tasks
[i
];
171 if (strlen(acct
[a
].name
) > *tnmax
) {
172 *tnmax
= strlen(acct
[a
].name
);
181 create_rett(Task
*acct
, size_t *acctl
)
183 /* copy accepted tasks to returned Task_t array */
186 rett
= ecalloc(*acctl
, sizeof(Task_t
));
188 for (i
=0; i
<*acctl
; i
++) {
190 // rett[i].name = ecalloc(strlen(acct[i].name) + 1, sizeof(char));
191 memcpy(rett
[i
].name
, acct
[i
].name
, strlen(acct
[i
].name
) + 1);
193 /* create start time */
194 if (i
== 0) { /* first task has no previous end time task */
195 rett
[i
].st
= adj_st(acct
[i
].st
,0);
197 rett
[i
].st
= adj_st(acct
[i
].st
, rett
[i
-1].end
);
200 /* create end time */
201 rett
[i
].end
= adj_end(rett
[i
].st
, acct
[i
].dur
);
203 /* chech previous task if dynamic */
205 if ((acct
[i
-1].dur
== (int)dyn
) &&
206 (acct
[i
].st
[0] == (int)after_last
)){
207 die("[FAILED] %s (dyn) --> %s (dyn)\ndynamic duration must be followed by fixed task start time.", acct
[i
-1].name
, acct
[i
].name
);
209 if (acct
[i
-1].dur
== (int)dyn
) {
210 rett
[i
-1].end
= rett
[i
].st
;
214 /* last task duration */
215 rett
[(*acctl
)-1].end
= rett
[0].st
;
222 validate_fixed(size_t *fixedl
, size_t *acctl
, Task_t
*rett
, Task
*acct
)
229 int dsec
= dmin
* 60;
231 int fail
= 0; /* to print all found errors */
238 fixed
= ecalloc(*fixedl
, sizeof(Task
));
241 btwal
= (*fixedl
) - 1;
242 btwa
= ecalloc(btwal
, sizeof(int));
243 btwp
= ecalloc(btwal
, sizeof(int));
245 for (i
=0; i
<*acctl
; i
++){
246 if (acct
[i
].st
[0] < (int)after_last
) { /* fixed start */
251 btwa
[x
] = 0; /* start new btw 2 fixes */
255 } else { /* after last */
256 // btwa[x] += acct[i].dur;
257 btwa
[x
] += (rett
[i
+1].st
- rett
[i
].st
)/60;
261 tdur
+= (rett
[i
+1].st
- rett
[i
].st
)/60;
262 } else if (i
== (*acctl
)-1) {
263 tdur
+= (rett
[0].st
+ dsec
- rett
[i
].st
)/60;
267 /* show fixes tasks and possible duration between them */
268 // for (i=0; i<btwal; i++) {
270 // printf("%s -> %s %d\n", fixed[i].name, fixed[i+1].name, btwa[i]);
273 // printf("total need fix = %d\n", tfix);
275 /* calculate between each 2 fixed start times */
276 /* for each 2 calculate max duration between them */
277 for (i
=(size_t)1; i
<*fixedl
; i
++){
278 dfix
= difftime(convert_hour_min_timet(fixed
[i
].st
),
279 convert_hour_min_timet(fixed
[i
-1].st
) +
280 (fixed
[i
-1].dur
* 60)) / 60;
281 btwp
[i
-1] = (int)dfix
;
285 * calculate actual sum duration of between tasks *
286 * compare 2 arrays btwa & btwp fail if not equal *
287 for (i=0; i<btwal; i++) {
288 if (btwa[i] != btwp[i]) {
290 printf("[\033[33mfix\033[0m] \
291 tasks between [%s] and [%s]: possible = %d, actual = %d\n",
292 fixed[i].name,fixed[i+1].name,btwp[i], btwa[i]);
297 // TODO move all cases before btwa and btwp
298 // dynamic duration must be filled for checking
301 FAIL_IF (fixdie
== 1,"please fix tasks duration between fixed tasks");
302 // FAIL_IF (tdur != dmax, "Total duration must be 1400 min.");
304 /* calculate acctual duration */
305 // for (i=0; i<acctl; i++) {
307 // btwa[i] = (rett[i+1].st - rett[i].st)/60;
308 // } else if (i == acctl-1) {
309 // btwa[i] = (rett[0].st+dsec- rett[i].st)/60;
311 // printf("%d, ", btwa[i]);
314 // tfix += tduration;
316 /* XXX VALIDATION XXX */
317 /* copy fixed from accepted */
318 /* count acctual duration */
319 /* count total duration */
332 validate_dyn(size_t *acctl
, Task_t
*rett
, Task
*acct
)
335 * case 0: between 2 fixes and no dynamic -> less than possible
336 * case 1: dynamic duration is 0 or less
339 const int dmin
= 60 * 24;
340 const int dsec
= dmin
* 60;
341 time_t tduration
= 0;
342 int status
= 0; /* to print all found errors */
345 for (i
=0; i
<*acctl
; i
++) {
347 tduration
= (rett
[i
+1].st
- rett
[i
].st
)/60;
348 } else if (i
== (*acctl
)-1) {
349 tduration
= (rett
[0].st
+ dsec
- rett
[i
].st
)/60;
352 if ((tduration
<= 0) ||
353 (acct
[i
].dur
!= (int)dyn
&& (int)tduration
!= acct
[i
].dur
)) {
354 printf("[fix] %s duration is %ld min\n",
355 rett
[i
].name
, (long)tduration
);
363 print_t(const char print_m
)
374 const int dmin
= 60 * 24;
375 const int dsec
= dmin
* 60;
376 const time_t now_seconds
= time(NULL
);
377 size_t config_l
= LEN(config_tasks
);
378 time_t tduration
= 0;
380 acctl
= ecalloc((size_t)1, sizeof(size_t));
381 fixedl
= ecalloc((size_t)1, sizeof(size_t));
382 tnmax
= ecalloc((size_t)1, sizeof(size_t));
384 gather_info(acctl
, fixedl
, config_l
);
385 acct
= create_acct(*acctl
, tnmax
, config_l
);
386 rett
= create_rett(acct
, acctl
);
388 if (validate_dyn(acctl
, rett
, acct
) < 0)
389 die("validation dynamic");
391 if (validate_fixed(fixedl
, acctl
, rett
, acct
) < 0)
392 die("validation fixed");
394 for (i
=0; i
<*acctl
; i
++) {
395 st_str
= convert_timet_to_str(rett
[i
].st
, print_m
);
396 end_str
= convert_timet_to_str(rett
[i
].end
, print_m
);
399 tduration
= (rett
[i
+1].st
- rett
[i
].st
)/60;
400 } else if (i
== (*acctl
)-1) {
401 tduration
= (rett
[0].st
+ dsec
- rett
[i
].st
)/60;
404 if (print_m
== 'a' || print_m
== 'A') {
405 printf("%*s %s -> %s\t%ld\n",
412 } else if (print_m
== 'n' || print_m
== 'N' || print_m
== 's') {
413 if (rett
[i
].end
> now_seconds
){
414 printf("%*s %s -> %s\t%ld\n",
420 if (print_m
== 's') {
440 main(int argc
, char *argv
[])
443 if (pledge("stdio", NULL
) == -1)
445 #endif /* __OpenBSD__ */
448 } else if (argc
== 2) {
449 if (strcmp("-v", argv
[1]) == 0){
450 die("splanner-"VERSION
);
452 strcmp("-a", argv
[1]) == 0 ||
453 strcmp("-A", argv
[1]) == 0 ||
454 strcmp("-N", argv
[1]) == 0 ||
455 strcmp("-n", argv
[1]) == 0) {