Completed v1.0.0 functionality v1.0.0
authoralex <[email protected]>
Sat, 3 Sep 2022 18:10:29 +0000 (11:10 -0700)
committerAlex Joss <[email protected]>
Tue, 20 Sep 2022 05:55:47 +0000 (07:55 +0200)
-Added optional arg to --upcoming (default = 1W)
-changed duration to until
-added man page
-added some minor color/formatting to ls
-added bash completions

38 files changed:
.gitignore
Makefile.am
completions/ev [new file with mode: 0644]
configure.ac
inc/event.h
inc/opt.h
man/ev.1 [new file with mode: 0644]
src/add.c
src/args.c
src/copy.c
src/event.c [deleted file]
src/event/free.c [new file with mode: 0644]
src/event/init.c [new file with mode: 0644]
src/event/name.c [new file with mode: 0644]
src/event/parse.c [new file with mode: 0644]
src/event/period.c [new file with mode: 0644]
src/event/place.c [new file with mode: 0644]
src/event/serial.c [new file with mode: 0644]
src/event/time.c [new file with mode: 0644]
src/ls.c
src/opt/duration.c [deleted file]
src/opt/env.c
src/opt/filter.c
src/opt/global.c
src/opt/until.c [new file with mode: 0644]
src/rm.c
src/seek.c
src/usage.c
test/unit/Makefile.am
test/unit/add.tests.c
test/unit/args.tests.c
test/unit/event.tests.c
test/unit/ls.tests.c
test/unit/opt.tests.c
test/unit/postpone.tests.c
test/unit/rm.tests.c
test/unit/test_utils.c
test/unit/usage.tests.c [new file with mode: 0644]

index a7921fca72b08565b0c02806e4934dbdeb8bf2a9..24a31b4be81c64e691b559a74a31d1bb67818ed5 100644 (file)
@@ -1,6 +1,8 @@
 ev
 events
 
+!completions/ev
+
 # build objects
 *.o
 *.log
index 7b8e14c9439f35c11c9417bbbb8a325ed935130b..4ad2767fc495c95199491bd273363f38496a14f6 100644 (file)
@@ -16,7 +16,14 @@ ev_SOURCES = \
        src/copy.c \
        src/cut.c \
        src/defaults.c \
-       src/event.c \
+       src/event/free.c \
+       src/event/init.c \
+       src/event/name.c \
+       src/event/parse.c \
+       src/event/period.c \
+       src/event/place.c \
+       src/event/serial.c \
+       src/event/time.c \
        src/file/line.c \
        src/file/mv.c \
        src/file/open.c \
@@ -24,12 +31,12 @@ ev_SOURCES = \
        src/file/tmp.c \
        src/ls.c \
        src/main.c \
-       src/opt/duration.c \
        src/opt/env.c \
        src/opt/file.c \
        src/opt/filter.c \
        src/opt/global.c \
        src/opt/recur.c \
+       src/opt/until.c \
        src/postpone.c \
        src/prune.c \
        src/rm.c \
@@ -53,6 +60,11 @@ ev_SOURCES += \
        inc/seek.h \
        inc/usage.h
 
+man_MANS = man/ev.1
+
+bashcompletiondir = $(datadir)/bash-completion/completions
+dist_bashcompletion_SCRIPTS = completions/ev
+
 SUBDIRS = . test/unit
 
 unit:
diff --git a/completions/ev b/completions/ev
new file mode 100644 (file)
index 0000000..96991f8
--- /dev/null
@@ -0,0 +1,93 @@
+_ev() {
+       IFS=$'\n'
+       COMPREPLY=()
+       local commands=$'add\ndismiss\nls\npostpone\nprune\nrm'
+
+       declare -A options
+       options[--all]="--all"
+       options[-a]="-a"
+       options[--end-date]="--end-date"
+       options[-e]="-e"
+       options[--file]="--file"
+       options[-f]="-f"
+       options[--help]="--help"
+       options[-h]="-h"
+       options[--overdue]="--overdue"
+       options[-o]="-o"
+       options[--recurring]="--recurring"
+       options[-r]="-r"
+       options[--start-date]="--start-date"
+       options[-s]="-s"
+       options[--upcoming]="--upcoming"
+       options[-u]="-u"
+
+       # remove set args
+       for arg in "${COMP_WORDS[@]}"; do
+               case "$arg" in
+                       --all) unset options[-a] ;;
+                       --end-date) unset options[-e] ;;
+                       --file) unset options[-f] ;;
+                       --help) unset options[-h] ;;
+                       --overdue) unset options[-o] ;;
+                       --recurring) unset options[-r] ;;
+                       --start-date) unset options[-s] ;;
+                       --upcoming) unset options[-u] ;;
+
+                       -a) unset options[--all] ;;
+                       -e) unset options[--end-date] ;;
+                       -f) unset options[--file] ;;
+                       -h) unset options[--help] ;;
+                       -o) unset options[--overdue] ;;
+                       -r) unset options[--recurring] ;;
+                       -s) unset options[--start-date] ;;
+                       -u) unset options[--upcoming] ;;
+               esac
+               unset options[$arg]
+       done
+
+       opts=
+       for val in "${options[@]}"; do
+               opts+="$val"
+               opts+=$'\n'
+       done
+
+       echo "COMP_LINE: ${COMP_LINE}"
+
+       case "$3" in
+               add)
+                       local addformat="[NAME] [PLACE] [DATE]"
+                       compopt -o nosort
+                       COMPREPLY=("$addformat" "")
+                       ;;
+               dismiss)
+                       local dismissformat="[INDEX]"
+                       echo "$dismissformat"
+                       COMPREPLY=()
+                       ;;
+               ls) ;;
+               postpone)
+                       local postponeformat="[DATE] [INDEX] [PERIOD]"
+                       echo "$postponeformat"
+                       COMPREPLY=()
+                       ;;
+               prune) ;;
+               rm)
+                       local rmformat="[INDEX]"
+                       echo "$rmformat"
+                       COMPREPLY=()
+                       ;;
+               ev)
+                       COMPREPLY=($(compgen -W "${commands}" -- "$2"))
+                       COMPREPLY+=($(compgen -W "${opts}" -- "$2"))
+                       ;;
+               -e|--end-date|-s|--start-date)
+                       COMPREPLY=($(date +%Y-%m-%d))
+                       ;;
+               -r|--recurring|-u|--upcoming)
+                       local periodformat="1W"
+                       COMPREPLY=()
+                       ;;
+       esac
+} >> /tmp/ev.output
+
+complete -F _ev ev
index 10309343ed2b12decfec785003f57cc58c3bf346..1461b9dff6d6be716c32be29a217f64be0df36bc 100644 (file)
@@ -1,5 +1,5 @@
 AC_PREREQ([2.69])
-AC_INIT([ev], [0.0.0])
+AC_INIT([ev], [1.0.0])
 
 # Store build files not in main directory
 AC_CONFIG_AUX_DIR([build-aux])
@@ -50,14 +50,16 @@ AC_PROG_INSTALL
 # Checks for libraries.
 
 # Checks for header files.
-AC_CHECK_HEADERS([stdlib.h string.h])
+AC_CHECK_HEADERS([limits.h stdlib.h string.h unistd.h])
 
 # Checks for typedefs, structures, and compiler characteristics.
 AC_TYPE_SIZE_T
+AC_TYPE_SSIZE_T
 
 # Checks for library functions.
 AC_FUNC_MALLOC
-AC_CHECK_FUNCS([memset strdup strptime])
+AC_FUNC_MKTIME
+AC_CHECK_FUNCS([memmove memset setenv strchr strdup strptime strtoul tzset])
 
 AC_CONFIG_FILES([Makefile
                 test/unit/Makefile])
index ef64ed36c7fa11fc35ae33de8899c27fe9c08ebe..87670d9e77a104a64ae8b3903c1ca26380852bcb 100644 (file)
@@ -28,11 +28,10 @@ enum time_period {
 };
 
 struct event_options {
-       unsigned int duration;
-       enum time_period duration_period;
-       
        unsigned int recur;
        enum time_period recur_period;
+       
+       struct tm until;
 };
 
 struct event {
@@ -49,15 +48,17 @@ struct event_filter {
        time_t end;
 };
 
-int event_date_compare(const struct event*,time_t);
 void event_free(const struct event*);
 void event_init(struct event*);
 int event_name_set(struct event*, const char*);
+void event_options_init(struct event_options*);
 enum time_period event_options_period(char);
+char event_options_period_char(enum time_period);
 int event_parse(char*, size_t, struct event*);
 int event_place_set(struct event*, const char*);
 int event_serialize(char*, size_t, const struct event*);
-int event_time_set(struct event*, const char*);
+int event_time_compare(const struct tm*,time_t);
+int event_time_set(struct tm*, const char*);
 int event_within(struct event*, struct event_filter*);
 
 #endif
index 16f6a3aaaa9e055912e82062096fcd3e0b76a733..28018e030fa6a5b46d7bfe98a86e9e00f83ee5d1 100644 (file)
--- a/inc/opt.h
+++ b/inc/opt.h
@@ -17,13 +17,13 @@ struct options {
 
 extern struct options global_options;
 
-int opt_duration_set(const char*);
 int opt_event_filter_date_set(time_t*,const char*);
 int opt_event_filter_range_set(const char*, const char*);
 int opt_event_filter_set(const char*);
 int opt_file_set(const char*);
 void opt_global_init();
-int opt_recur_set(const char*);
 int opt_load_from_env();
+int opt_recur_set(const char*);
+int opt_until_set(const char*);
 
 #endif
diff --git a/man/ev.1 b/man/ev.1
new file mode 100644 (file)
index 0000000..53c1953
--- /dev/null
+++ b/man/ev.1
@@ -0,0 +1,183 @@
+.TH EV "1" "2022 September 13" "v0.0.0" "Events"
+
+.SH NAME
+ev \- human readable events organizer
+
+.SH SYNOPSIS
+.B ev
+[
+.I OPTIONS
+]... [
+.I COMMAND
+] [
+.I ARGS
+]...
+
+.SH DESCRIPTION
+.B ev
+is a tool for managing and organizing events in a human readable format.
+.PP
+It is intended to be easily parasable and able to be editted by hand.
+.PP
+Best used within 
+.BR git (1).
+
+If no COMMAND is specified, COMMAND defaults to ls.
+
+.SH COMMANDS
+.IP \(bu
+.B add
+.IP \(bu
+.B dismiss
+.IP \(bu
+.B ls
+.IP \(bu
+.B postpone
+.IP \(bu
+.B prune
+.IP \(bu
+.B rm
+
+.SH OPTIONS
+.TP
+\fB\-\-all\fR, \fB\-a\fR
+show all
+.TP
+\fB\-\-end\-date\fR, \fB\-e\fR
+ending date
+.TP
+\fB\-\-file\fR, \fB\-f\fR
+events file location
+.TP
+\fB\-\-help\fR, \fB\-h\fR
+show this help
+.TP
+\fB\-\-overdue\fR, \fB\-o\fR
+show only overdue events
+.TP
+\fB\-\-recurring\fR, \fB\-r\fR
+denote event as recurring
+.TP
+\fB\-\-start\-date\fR, \fB\-s\fR
+starting date
+.TP
+\fB\-\-upcoming\fR, \fB\-u\fR
+show only upcoming events
+
+.SH TIME PERIOD SPEC
+A couple of the commands require time period specifications. A time period specification consists of an unsigned integer and then a single character.
+.TP
+The following characters are accepted time periods:
+.IP \(bu
+Y: year
+.IP \(bu
+M: month
+.IP \(bu
+W: week
+.IP \(bu
+D: day
+.IP \(bu
+h: hour
+.IP \(bu
+m: minute
+.IP \(bu
+s: second
+
+.SH ENVIRONMENTAL VARIABLES
+
+.TP
+.I EVENTS_EVENT_FILTER
+Overrides date range.
+
+.TP
+.I EVENTS_FILE
+Overrides events file
+
+.TP
+.I EVENTS_RECUR
+Overrides recur value
+
+.TP
+.I EVENTS_UNTIL
+Overrides event recurruing until value.
+
+.SH EXAMPLES
+.TP
+get today's and overdue events
+.B ev
+
+.TP
+get today's and overdue events using file ~/.events
+.B EVENTS_FILE=~/.events ev
+
+.TP
+prune old events
+.B ev prune
+
+.TP
+dismiss 0th event
+.B ev dismiss 0
+
+.TP
+get events on 2022-09-01
+.B ev 2022-09-01
+
+.TP
+get upcoming events for the next month
+.B 
+ev --upcoming 1M
+
+.TP
+add recurring event
+.B
+ev add --recurring 1Y "Alex Birthday" "2023-01-24"
+
+.TP
+add event with 2 day duration
+.B
+ev add --duration 2D "Alex Birthday" "2023-01-24"
+
+.TP
+add event@location with time
+.B
+ev add "Roger Waters" "Chase Center" "2022-09-23 20:00:00"
+
+.TP
+delete event with name 'Test Event' on 2022-09-01
+.B
+ev rm "Test Event" 2022-09-01
+
+.TP
+deletes today's event in the 0th position
+.B
+ev rm 0
+
+.TP
+postpones event in the 1st position on 2022-09-01 by 1 day
+.B
+ev postpone 2022-09-01 1 1D
+
+.TP
+postpones event in the 0th position by 1 week
+.B
+ev postpone 0 1W
+
+.TP
+postpones event in the 0th position by 1 day
+.B
+ev postpone 0
+
+.SH "SEE ALSO"
+.BR git (1)
+
+.SH AUTHOR
+.B ev
+was written by
+Alex Joss
+.ME .
+See
+.UR https://\:infiniteadaptability.org/
+infiniteadaptability.org
+.UE
+for more information.
index df98e353df12252aa099be1fcfe1b18f86a1fb88..20a4228a56d4a0bf54414b92a7946aa9a75b7a66 100644 (file)
--- a/src/add.c
+++ b/src/add.c
@@ -3,6 +3,8 @@
 static int add_name_set(struct event*,const char*);
 static int add_place_set(struct event*,const char*);
 static int add_time_set(struct event*,const char*);
+static int handle_args(int,char**,struct event*);
+static int handle_options(struct event*);
 
 int add(int argc, char **argv) {
        struct event ev;
@@ -11,28 +13,8 @@ int add(int argc, char **argv) {
 
        event_init(&ev);
 
-       if(global_options.event_options.duration>0) {
-               ev.options.duration = global_options.event_options.duration;
-               ev.options.duration_period = global_options.event_options.duration_period;
-       }
-       
-       if(global_options.event_options.recur>0) {
-               ev.options.recur = global_options.event_options.recur;
-               ev.options.recur_period = global_options.event_options.recur_period;
-       }
-
-       switch(argc-optind) {
-               case 4:
-                       if(add_place_set(&ev,argv[optind+2])<0) { return EXIT_FAILURE; }
-               case 3:
-                       if(add_name_set(&ev,argv[optind+1])<0) { return EXIT_FAILURE; }
-                       if(add_time_set(&ev,argv[argc-1])<0) { return EXIT_FAILURE; }
-                       break;
-               default:
-                       fprintf(stderr,"invalid number of arguments\n");
-                       usage();
-                       return EXIT_FAILURE;
-       }
+       if(handle_options(&ev)<0) { return EXIT_FAILURE; }
+       if(handle_args(argc,argv,&ev)<0) { return EXIT_FAILURE; }
        
        strftime(timebuf,40,"%a, %d %b %Y %T %z",&(ev.datetime));
 
@@ -92,7 +74,7 @@ static int add_time_set(struct event *ev, const char *str) {
 
        if(NULL==str) { return -1; }
 
-       if(event_time_set(ev,str)<0) {
+       if(event_time_set(&(ev->datetime),str)<0) {
                fprintf(stderr,"invalid date format provided\n");
                usage();
                return -1; 
@@ -138,3 +120,40 @@ int add_to_file(struct event *to_add) {
 
        return 1;
 }
+
+int handle_args(int argc, char **argv, struct event *ev) {
+       assert(ev!=NULL);
+
+       switch(argc-optind) {
+               case 4:
+                       if(add_place_set(ev,argv[optind+2])<0) { return -1; }
+               case 3:
+                       if(add_name_set(ev,argv[optind+1])<0) { return -1; }
+                       if(add_time_set(ev,argv[argc-1])<0) { return -1; }
+                       break;
+               default:
+                       fprintf(stderr,"invalid number of arguments\n");
+                       usage();
+                       return -1;
+       }
+
+       return 1;
+}
+
+int handle_options(struct event *ev) {
+       struct tm *time;
+
+       if(global_options.event_options.recur>0) {
+               ev->options.recur = global_options.event_options.recur;
+               ev->options.recur_period = global_options.event_options.recur_period;
+       
+               if(global_options.event_filter.end>0) {
+                       time = localtime(&(global_options.event_filter.end));
+                       if(NULL==time) { return -1; }
+
+                       memcpy(&(ev->options.until),time,sizeof(struct tm));
+               }
+       }
+
+       return 1;
+}
index 21232ab6ce8818b51db49ab8a14f4bb8fa09d645..2fc32e3a757e7d0e653dae9e1b5459cb019c9e80 100644 (file)
@@ -2,14 +2,13 @@
 
 struct option long_options[] = {
        {"all", no_argument, 0, 'a'},
-       {"duration", required_argument, 0, 'd'},
        {"end-date", required_argument, 0, 'e'},
        {"file", required_argument, 0, 'f'},
-       {"interactive", no_argument, 0, 'i'},
+       {"help", no_argument, 0, 'h'},
        {"overdue", no_argument, 0, 'o'},
        {"recurring", required_argument, 0, 'r'},
        {"start-date", required_argument, 0, 's'},
-       {"upcoming", required_argument, 0, 'u'},
+       {"upcoming", optional_argument, 0, 'u'},
        {0,0,0,0}
 };
 
@@ -19,15 +18,12 @@ enum sub_command args(int argc, char **argv) {
        while(1) {
                int option_index = 0;
 
-               if((c = getopt_long(argc,argv,"ad:e:f:or:s:u:",long_options,&option_index))==-1) { break; }
+               if((c = getopt_long(argc,argv,"ae:f:hor:s:t:u::",long_options,&option_index))==-1) { break; }
 
                switch(c) {
                        case 'a':
                                if(opt_event_filter_set("all")<0) { goto fail; }
                                break;
-                       case 'd':
-                               if(opt_duration_set(optarg)<0) { goto fail; }
-                               break;
                        case 'e':
                                if(opt_event_filter_date_set(
                                        &(global_options.event_filter.end),
@@ -52,8 +48,14 @@ enum sub_command args(int argc, char **argv) {
                                        )<0) { goto fail; }
                                break;
                        case 'u':
-                               if(opt_event_filter_range_set("upcoming",optarg)<0) { goto fail; }
+                               if((NULL==optarg)&&(argv[optind]!=NULL)&&(argv[optind][0]!='-')) {
+                                       if(opt_event_filter_range_set("upcoming",argv[optind])<0) { goto fail; }
+                                       optind++;
+                               } else {
+                                       if(opt_event_filter_range_set("upcoming",optarg)<0) { goto fail; }
+                               }
                                break;
+                       case 'h':
                        case '?':
                        default:
                                goto fail;
index 0c3edc195e2437d0f3402b3e5862e7a87f2d5be6..1e2f80ebde4bc478e356e5cc73f9c364265d7cc3 100644 (file)
@@ -13,7 +13,7 @@ int copy(FILE *to, FILE *src, time_t until) {
 
                if(event_parse(buf,EVENT_SERIALIZE_MAX_LENGTH,&ev)<0) { return -1; }
                
-               if(event_date_compare(&ev,until)>0) {
+               if(event_time_compare(&(ev.datetime),until)>0) {
                        event_free(&ev);
                        if(fseek(src,-i,SEEK_CUR)!=0) { return -1; }
                        break;
diff --git a/src/event.c b/src/event.c
deleted file mode 100644 (file)
index 236d4d1..0000000
+++ /dev/null
@@ -1,420 +0,0 @@
-#include<event.h>
-
-static void event_options_init(struct event_options*);
-static char event_options_period_char(enum time_period period);
-static int event_parse_name(char*, size_t, struct event*);
-static int event_parse_options(char*, size_t, struct event*);
-static int event_parse_place(char*, size_t, struct event*);
-static int event_parse_time(char*, size_t, struct event*);
-static int event_serialize_name(char*, size_t, const struct event*);
-static int event_serialize_options(char*, size_t, const struct event*);
-static int event_serialize_place(char*, size_t, const struct event*);
-static int event_serialize_time(char*, size_t, const struct event*);
-
-int event_date_compare(const struct event *ev, time_t time) {
-       struct tm tm;
-       time_t event_time;
-       memcpy(&tm,&(ev->datetime),sizeof(struct tm));
-
-       event_time = mktime(&tm);
-
-       if(event_time>time) { return 1; }
-       if(event_time<time) { return -1; }
-       return 0;
-}
-
-void event_free(const struct event *p) {
-       if(p->name!=NULL) { free(p->name); }
-       if(p->place!=NULL) { free(p->place); }
-}
-
-void event_init(struct event *p) {
-       assert(p!=NULL);
-
-       event_options_init(&(p->options));
-
-       p->name = NULL;
-       p->place = NULL;
-       
-       memset(&(p->datetime),0,sizeof(struct tm));
-}
-
-static void event_options_init(struct event_options *p) {
-       assert(p!=NULL);
-
-       p->recur = 0;
-       p->recur_period = TIME_PERIOD_NONE;
-       
-       p->duration = 0;
-       p->duration_period = TIME_PERIOD_NONE;
-}
-
-enum time_period event_options_period(char period) {
-       switch(period) {
-               case 'Y':
-                       return TIME_PERIOD_YEAR;
-               case 'M':
-                       return TIME_PERIOD_MONTH;
-               case 'W':
-                       return TIME_PERIOD_WEEK;
-               case 'D':
-                       return TIME_PERIOD_DAY;
-               case 'h':
-                       return TIME_PERIOD_HOUR;
-               case 'm':
-                       return TIME_PERIOD_MINUTE;
-               case 's':
-                       return TIME_PERIOD_SECOND;
-               default:
-                       return TIME_PERIOD_NONE;
-       }
-}
-
-static char event_options_period_char(enum time_period period) {
-       switch(period) {
-               case TIME_PERIOD_SECOND:
-                       return 's';
-               case TIME_PERIOD_MINUTE:
-                       return 'm';
-               case TIME_PERIOD_HOUR:
-                       return 'h';
-               case TIME_PERIOD_DAY:
-                       return 'D';
-               case TIME_PERIOD_WEEK:
-                       return 'W';
-               case TIME_PERIOD_MONTH:
-                       return 'M';
-               case TIME_PERIOD_YEAR:
-                       return 'Y';
-               default:
-                       return '\0';
-       }
-}
-
-int event_name_set(struct event *ev, const char *name) {
-       size_t len;
-
-       if(ev->name!=NULL) { free(ev->name); }
-
-       ev->name = strdup(name);
-       if(ev->name==NULL) { return -1; }
-
-       len = strlen(ev->name);
-       len--;
-       if(ev->name[len]=='\n') {
-               ev->name[len] = '\0';
-       }
-
-       return 1;
-}
-
-int event_parse(char *buf, size_t buf_size, struct event *ev) {
-       event_init(ev);
-
-       if(event_parse_options(buf,buf_size,ev)<0) { return -1; }
-       if(event_parse_time(buf,buf_size,ev)<0) { return -1; }
-       if(event_parse_name(buf,buf_size,ev)<0) { return -1; }
-       if(event_parse_place(buf,buf_size,ev)<0) { return -1; }
-
-       return 1;
-}
-
-static int event_parse_name(char *buf, size_t buf_size, struct event *ev) {
-       const char escaped[] = "\"";
-       const char normal[] = ":";
-       const char *token;
-       char *p;
-
-       if(buf[0]=='"') {
-               token = escaped;
-       } else {
-               token = normal;
-       }
-
-       p = strtok(buf,token);
-       if(p!=NULL) {
-               if(event_name_set(ev,p)<0) { return -1; }
-       }
-
-       p = strtok(NULL,token);
-
-       /*
-        * fix string for if place is also escaped
-        */
-       if(token[0]!=':') {
-               if(p[1]=='\0') {
-                       p[1] = '"';
-               }
-               p++;
-       }
-
-       if(p!=NULL) {
-               memmove(buf,p,(buf_size - (p - buf)));
-       } else {
-               buf[0] = '\0';
-       }
-
-       return 1;
-}
-
-static int event_parse_options(char *buf, size_t buf_size, struct event *ev) {
-       char period;
-       char *options, *p;
-       size_t diff;
-
-       if(buf[0]!='[') { return 0; }
-
-       options = strtok(buf,"]");
-
-       diff = strlen(options)+1;
-
-       p = strtok(&(options[1]),",");
-       while(p!=NULL) {
-               if(memcmp(p,"duration",8)==0) {
-                       if(sscanf(
-                               p,
-                               "duration:%u%c",
-                               &(ev->options.duration),
-                               &period
-                               )!=2) {
-                               if(errno!=0) {
-                                       perror("sccanf");
-                                       return -1;
-                               }
-                       }
-                       ev->options.duration_period = event_options_period(period);
-               } else if(memcmp(p,"recur",5)==0) {
-                       if(sscanf(
-                               p,
-                               "recur:%u%c",
-                               &(ev->options.recur),
-                               &period
-                               )!=2) {
-                               if(errno!=0) {
-                                       perror("sccanf");
-                                       return -1;
-                               }
-                       }
-                       ev->options.recur_period = event_options_period(period);
-               } else { return -1; }
-
-               p = strtok(NULL,",");
-       }
-
-       memmove(buf,&(buf[diff]),(buf_size - diff));
-       return 1;
-}
-
-static int event_parse_place(char *buf, size_t buf_size, struct event *ev) {
-       const char escaped[] = "\"";
-       const char normal[] = ":";
-       const char *token;
-       char *p;
-
-       if(buf[0]=='"') {
-               token = escaped;
-       } else {
-               token = normal;
-       }
-
-       p = strtok(buf,token);
-       if(p!=NULL) {
-               if(event_place_set(ev,p)<0) { return -1; }
-       }
-
-       return 1;
-}
-
-static int event_parse_time(char *buf, size_t buf_size, struct event *ev) {
-       char *p;
-
-       if(buf[10]!=' ') {
-               buf[10] = '\0';
-               p = &(buf[11]);
-       } else if(buf[19]!=' ') {
-               buf[19] = '\0';
-               p = &(buf[20]);
-       } else {
-               buf[25] = '\0';
-               p = &(buf[26]);
-       }
-
-       if(event_time_set(ev,buf)<0) { return -1; }
-
-       memmove(buf,p,(buf_size - (p - buf)));
-
-       return 1;
-}
-
-int event_place_set(struct event *ev, const char *place) {
-       size_t len;
-
-       if(ev->place!=NULL) { free(ev->place); }
-
-       ev->place = strdup(place);
-       if(ev->place==NULL) { return -1; }
-
-       len = strlen(ev->place);
-       len--;
-       if(ev->place[len]=='\n') {
-               ev->place[len] = '\0';
-       }
-
-       return 1;
-}
-
-int event_serialize(char *buf, size_t buf_size, const struct event *ev) {
-       assert(buf!=NULL);
-
-       memset(buf,0,buf_size);
-
-       if(event_serialize_options(buf,buf_size,ev)<0) { return -1; }
-       if(event_serialize_time(buf,buf_size,ev)<0) { return -1; }
-       if(event_serialize_name(buf,buf_size,ev)<0) { return -1; }
-       if(event_serialize_place(buf,buf_size,ev)<0) { return -1; }
-
-       event_free(ev);
-
-       strcat(buf,"\n");
-
-       return 1;
-}
-
-static int event_serialize_name(char *buf, size_t buf_size, const struct event *ev) {
-       char *p;
-
-       if(NULL==ev->name) { return -1; }
-
-       if(strlen(buf)+strlen(ev->name)+2>buf_size) { return -1; }
-
-       strcat(buf,":");
-
-       p = strchr(ev->name,':');
-       if(p!=NULL) { strcat(buf,"\""); }
-
-       strcat(buf,ev->name);
-       
-       if(p!=NULL) { strcat(buf,"\""); }
-
-       return 1;
-}
-
-static int event_serialize_options(char *buf, size_t buf_size, const struct event *ev) {
-       size_t pos;
-
-       if(!((ev->options.duration>0)||(ev->options.recur>0))) { return 0; }
-
-       strcpy(buf,"[");
-       pos = 1;
-
-       if(ev->options.duration>0) {
-               if(sprintf(
-                       &(buf[pos]),
-                       "duration:%u%c",
-                       ev->options.duration,
-                       event_options_period_char(ev->options.duration_period)
-                       )<0) { return -1; }
-
-               if(ev->options.recur>0) {
-                       strcat(buf,",");
-               }
-
-               pos = strlen(buf);
-       }
-
-       if(ev->options.recur>0) {
-               if(sprintf(
-                       &(buf[pos]),
-                       "recur:%u%c",
-                       ev->options.recur,
-                       event_options_period_char(ev->options.recur_period)
-                       )<0) { return -1; }
-       }
-
-       strcat(buf,"]");
-
-       return 1;
-}
-
-static int event_serialize_place(char *buf, size_t buf_size, const struct event *ev) {
-       char *p;
-
-       assert(buf!=NULL);
-
-       if(NULL==ev->place) { return 0; }
-       
-       if(strlen(buf)+strlen(ev->place)+2>buf_size) { return -1; }
-
-       strcat(buf,":");
-       
-       p = strchr(ev->name,':');
-       if(p!=NULL) { strcat(buf,"\""); }
-
-       strcat(buf,ev->place);
-
-       if(p!=NULL) { strcat(buf,"\""); }
-
-       return 1;
-}
-
-static int event_serialize_time(char *buf, size_t buf_size, const struct event *ev) {
-       size_t len;
-
-       assert(buf!=NULL);
-
-       len = strlen(buf);
-       
-       if(ev->datetime.tm_sec==0 && ev->datetime.tm_min==0 && ev->datetime.tm_hour == 0) {
-               if(0==strftime(
-                       &(buf[len]), /* char *s */
-                       buf_size - len, /* size_t max */
-                       "%Y-%m-%d", /* const char *format */
-                       &(ev->datetime) /* const struct tm *tm */
-                       )) { return -1; }
-       } else {
-               if(0==strftime(
-                       &(buf[len]), /* char *s */
-                       buf_size - len, /* size_t max */
-                       "%Y-%m-%d %H:%M:%S %z", /* const char *format */
-                       &(ev->datetime) /* const struct tm *tm */
-                       )) { return -1; }
-       }
-
-       return 1;
-}
-
-int event_time_set(struct event *ev, const char *str) {
-       const char *p;
-
-       p = str;
-
-       memset(&(ev->datetime), 0, sizeof(struct tm));
-
-       /* minimum expected date format */
-       p = strptime(p,"%Y-%m-%d",&(ev->datetime));
-       if(NULL==p) { return -1; }
-       
-       /* attempt to get time information */
-       p = strptime(p,"%H:%M:%S",&(ev->datetime));
-
-       /* attempt to get timezone information */
-       if(p!=NULL) {
-               strptime(p,"%z",&(ev->datetime));
-       }
-
-       return 1;
-}
-
-int event_within(struct event *ev, struct event_filter *filter) {
-       struct tm tm;
-       time_t event_time;
-
-       memcpy(&tm,&(ev->datetime),sizeof(struct tm));
-
-       event_time = mktime(&tm);
-
-       if(filter->start>event_time) { return -1; }
-       if(filter->end<event_time) { return -1; }
-
-       return 1;
-}
diff --git a/src/event/free.c b/src/event/free.c
new file mode 100644 (file)
index 0000000..72ab2e7
--- /dev/null
@@ -0,0 +1,6 @@
+#include<event.h>
+
+void event_free(const struct event *p) {
+       if(p->name!=NULL) { free(p->name); }
+       if(p->place!=NULL) { free(p->place); }
+}
diff --git a/src/event/init.c b/src/event/init.c
new file mode 100644 (file)
index 0000000..1872152
--- /dev/null
@@ -0,0 +1,22 @@
+#include<event.h>
+
+void event_init(struct event *p) {
+       assert(p!=NULL);
+
+       event_options_init(&(p->options));
+
+       p->name = NULL;
+       p->place = NULL;
+       
+       memset(&(p->datetime),0,sizeof(struct tm));
+}
+
+void event_options_init(struct event_options *p) {
+       assert(p!=NULL);
+
+       p->recur = 0;
+       p->recur_period = TIME_PERIOD_NONE;
+       
+       memset(&(p->until),0,sizeof(struct tm));
+}
+
diff --git a/src/event/name.c b/src/event/name.c
new file mode 100644 (file)
index 0000000..ae20e91
--- /dev/null
@@ -0,0 +1,18 @@
+#include<event.h>
+
+int event_name_set(struct event *ev, const char *name) {
+       size_t len;
+
+       if(ev->name!=NULL) { free(ev->name); }
+
+       ev->name = strdup(name);
+       if(ev->name==NULL) { return -1; }
+
+       len = strlen(ev->name);
+       len--;
+       if(ev->name[len]=='\n') {
+               ev->name[len] = '\0';
+       }
+
+       return 1;
+}
diff --git a/src/event/parse.c b/src/event/parse.c
new file mode 100644 (file)
index 0000000..b1cf3d1
--- /dev/null
@@ -0,0 +1,133 @@
+#include<event.h>
+
+static int event_parse_name(char*, size_t, struct event*);
+static int event_parse_options(char*, size_t, struct event*);
+static int event_parse_place(char*, size_t, struct event*);
+static int event_parse_time(char*, size_t, struct event*);
+
+int event_parse(char *buf, size_t buf_size, struct event *ev) {
+       event_init(ev);
+
+       if(event_parse_options(buf,buf_size,ev)<0) { return -1; }
+       if(event_parse_time(buf,buf_size,ev)<0) { return -1; }
+       if(event_parse_name(buf,buf_size,ev)<0) { return -1; }
+       if(event_parse_place(buf,buf_size,ev)<0) { return -1; }
+
+       return 1;
+}
+
+static int event_parse_name(char *buf, size_t buf_size, struct event *ev) {
+       const char escaped[] = "\"";
+       const char normal[] = ":";
+       const char *token;
+       char *p;
+
+       if(buf[0]=='"') {
+               token = escaped;
+       } else {
+               token = normal;
+       }
+
+       p = strtok(buf,token);
+       if(p!=NULL) {
+               if(event_name_set(ev,p)<0) { return -1; }
+       }
+
+       p = strtok(NULL,token);
+
+       /*
+        * fix string for if place is also escaped
+        */
+       if(token[0]!=':') {
+               if(p[1]=='\0') {
+                       p[1] = '"';
+               }
+               p++;
+       }
+
+       if(p!=NULL) {
+               memmove(buf,p,(buf_size - (p - buf)));
+       } else {
+               buf[0] = '\0';
+       }
+
+       return 1;
+}
+
+static int event_parse_options(char *buf, size_t buf_size, struct event *ev) {
+       char period;
+       char *options, *p;
+       size_t diff;
+
+       if(buf[0]!='[') { return 0; }
+
+       options = strtok(buf,"]");
+
+       diff = strlen(options)+1;
+
+       p = strtok(&(options[1]),",");
+       while(p!=NULL) {
+               if(memcmp(p,"until:",6)==0) {
+                       if(event_time_set(&(ev->options.until),&(p[6]))<0) { return -1; }
+               } else if(memcmp(p,"recur",5)==0) {
+                       if(sscanf(
+                               p,
+                               "recur:%u%c",
+                               &(ev->options.recur),
+                               &period
+                               )!=2) {
+                               if(errno!=0) {
+                                       perror("sccanf");
+                                       return -1;
+                               }
+                       }
+                       ev->options.recur_period = event_options_period(period);
+               } else { return -1; }
+
+               p = strtok(NULL,",");
+       }
+
+       memmove(buf,&(buf[diff]),(buf_size - diff));
+       return 1;
+}
+
+static int event_parse_place(char *buf, size_t buf_size, struct event *ev) {
+       const char escaped[] = "\"";
+       const char normal[] = ":";
+       const char *token;
+       char *p;
+
+       if(buf[0]=='"') {
+               token = escaped;
+       } else {
+               token = normal;
+       }
+
+       p = strtok(buf,token);
+       if(p!=NULL) {
+               if(event_place_set(ev,p)<0) { return -1; }
+       }
+
+       return 1;
+}
+
+static int event_parse_time(char *buf, size_t buf_size, struct event *ev) {
+       char *p;
+
+       if(buf[10]!=' ') {
+               buf[10] = '\0';
+               p = &(buf[11]);
+       } else if(buf[19]!=' ') {
+               buf[19] = '\0';
+               p = &(buf[20]);
+       } else {
+               buf[25] = '\0';
+               p = &(buf[26]);
+       }
+
+       if(event_time_set(&(ev->datetime),buf)<0) { return -1; }
+
+       memmove(buf,p,(buf_size - (p - buf)));
+
+       return 1;
+}
diff --git a/src/event/period.c b/src/event/period.c
new file mode 100644 (file)
index 0000000..9a7b5dc
--- /dev/null
@@ -0,0 +1,43 @@
+#include<event.h>
+
+enum time_period event_options_period(char period) {
+       switch(period) {
+               case 'Y':
+                       return TIME_PERIOD_YEAR;
+               case 'M':
+                       return TIME_PERIOD_MONTH;
+               case 'W':
+                       return TIME_PERIOD_WEEK;
+               case 'D':
+                       return TIME_PERIOD_DAY;
+               case 'h':
+                       return TIME_PERIOD_HOUR;
+               case 'm':
+                       return TIME_PERIOD_MINUTE;
+               case 's':
+                       return TIME_PERIOD_SECOND;
+               default:
+                       return TIME_PERIOD_NONE;
+       }
+}
+
+char event_options_period_char(enum time_period period) {
+       switch(period) {
+               case TIME_PERIOD_SECOND:
+                       return 's';
+               case TIME_PERIOD_MINUTE:
+                       return 'm';
+               case TIME_PERIOD_HOUR:
+                       return 'h';
+               case TIME_PERIOD_DAY:
+                       return 'D';
+               case TIME_PERIOD_WEEK:
+                       return 'W';
+               case TIME_PERIOD_MONTH:
+                       return 'M';
+               case TIME_PERIOD_YEAR:
+                       return 'Y';
+               default:
+                       return '\0';
+       }
+}
diff --git a/src/event/place.c b/src/event/place.c
new file mode 100644 (file)
index 0000000..01f293c
--- /dev/null
@@ -0,0 +1,18 @@
+#include<event.h>
+
+int event_place_set(struct event *ev, const char *place) {
+       size_t len;
+
+       if(ev->place!=NULL) { free(ev->place); }
+
+       ev->place = strdup(place);
+       if(ev->place==NULL) { return -1; }
+
+       len = strlen(ev->place);
+       len--;
+       if(ev->place[len]=='\n') {
+               ev->place[len] = '\0';
+       }
+
+       return 1;
+}
diff --git a/src/event/serial.c b/src/event/serial.c
new file mode 100644 (file)
index 0000000..df20225
--- /dev/null
@@ -0,0 +1,123 @@
+#include<event.h>
+
+static int event_serialize_name(char*, size_t, const struct event*);
+static int event_serialize_options(char*, size_t, const struct event*);
+static int event_serialize_place(char*, size_t, const struct event*);
+static int event_serialize_time(char*, size_t, const struct tm*);
+
+int event_serialize(char *buf, size_t buf_size, const struct event *ev) {
+       assert(buf!=NULL);
+
+       memset(buf,0,buf_size);
+
+       if(event_serialize_options(buf,buf_size,ev)<0) { return -1; }
+       if(event_serialize_time(buf,buf_size,&(ev->datetime))<0) { return -1; }
+       if(event_serialize_name(buf,buf_size,ev)<0) { return -1; }
+       if(event_serialize_place(buf,buf_size,ev)<0) { return -1; }
+
+       event_free(ev);
+
+       strcat(buf,"\n");
+
+       return 1;
+}
+
+static int event_serialize_name(char *buf, size_t buf_size, const struct event *ev) {
+       char *p;
+
+       if(NULL==ev->name) { return -1; }
+
+       if(strlen(buf)+strlen(ev->name)+2>buf_size) { return -1; }
+
+       strcat(buf,":");
+
+       p = strchr(ev->name,':');
+       if(p!=NULL) { strcat(buf,"\""); }
+
+       strcat(buf,ev->name);
+       
+       if(p!=NULL) { strcat(buf,"\""); }
+
+       return 1;
+}
+
+static int event_serialize_options(char *buf, size_t buf_size, const struct event *ev) {
+       size_t pos;
+
+       if(!(ev->options.recur>0)) { return 0; }
+
+       strcpy(buf,"[");
+       pos = 1;
+
+       if(ev->options.recur>0) {
+               if(sprintf(
+                       &(buf[pos]),
+                       "recur:%u%c",
+                       ev->options.recur,
+                       event_options_period_char(ev->options.recur_period)
+                       )<0) { return -1; }
+               
+               if(event_time_compare(&(ev->options.until),0)>0) {
+                       strcat(buf,",until:");
+
+                       if(event_serialize_time(
+                               &(buf[pos]),
+                               buf_size,
+                               &(ev->options.until)
+                               )<0) { return -1; }
+
+                       pos = strlen(buf);
+               }
+       }
+
+       strcat(buf,"]");
+
+       return 1;
+}
+
+static int event_serialize_place(char *buf, size_t buf_size, const struct event *ev) {
+       char *p;
+
+       assert(buf!=NULL);
+
+       if(NULL==ev->place) { return 0; }
+       
+       if(strlen(buf)+strlen(ev->place)+2>buf_size) { return -1; }
+
+       strcat(buf,":");
+       
+       p = strchr(ev->name,':');
+       if(p!=NULL) { strcat(buf,"\""); }
+
+       strcat(buf,ev->place);
+
+       if(p!=NULL) { strcat(buf,"\""); }
+
+       return 1;
+}
+
+static int event_serialize_time(char *buf, size_t buf_size, const struct tm *datetime) {
+       size_t len;
+
+       assert(buf!=NULL);
+
+       len = strlen(buf);
+       
+       if(datetime->tm_sec==0 && datetime->tm_min==0 && datetime->tm_hour == 0) {
+               if(0==strftime(
+                       &(buf[len]), /* char *s */
+                       buf_size - len, /* size_t max */
+                       "%Y-%m-%d", /* const char *format */
+                       datetime /* const struct tm *tm */
+                       )) { return -1; }
+       } else {
+               if(0==strftime(
+                       &(buf[len]), /* char *s */
+                       buf_size - len, /* size_t max */
+                       "%Y-%m-%d %H:%M:%S %z", /* const char *format */
+                       datetime /* const struct tm *tm */
+                       )) { return -1; }
+       }
+
+       return 1;
+}
diff --git a/src/event/time.c b/src/event/time.c
new file mode 100644 (file)
index 0000000..1a46aaf
--- /dev/null
@@ -0,0 +1,51 @@
+#include<event.h>
+
+int event_time_compare(const struct tm *datetime, time_t time) {
+       struct tm tm;
+       time_t event_time;
+
+       assert(datetime!=NULL);
+
+       memcpy(&tm,datetime,sizeof(struct tm));
+       event_time = mktime(&tm);
+
+       if(event_time>time) { return 1; }
+       if(event_time<time) { return -1; }
+       return 0;
+}
+
+int event_time_set(struct tm *datetime, const char *str) {
+       const char *p;
+
+       p = str;
+
+       memset(datetime, 0, sizeof(struct tm));
+
+       /* minimum expected date format */
+       p = strptime(p,"%Y-%m-%d",datetime);
+       if(NULL==p) { return -1; }
+       
+       /* attempt to get time information */
+       p = strptime(p,"%H:%M:%S",datetime);
+
+       /* attempt to get timezone information */
+       if(p!=NULL) {
+               strptime(p,"%z",datetime);
+       }
+
+       return 1;
+}
+
+int event_within(struct event *ev, struct event_filter *filter) {
+       struct tm tm;
+       time_t event_time;
+
+       memcpy(&tm,&(ev->datetime),sizeof(struct tm));
+
+       event_time = mktime(&tm);
+
+       if(filter->start>event_time) { return -1; }
+       if(filter->end<event_time) { return -1; }
+
+       return 1;
+}
index ad07d9cbb48da82e1c56e978a6b58c4643efe138..52564f6c2bc9cd51cea1fa311a9efc31438d5efd 100644 (file)
--- a/src/ls.c
+++ b/src/ls.c
@@ -35,6 +35,10 @@ close:
 }
 
 static int event_print(struct event *ev) {
+       assert(ev!=NULL);
+
+       if(NULL==ev->name) { return -1; }
+
        char datebuf[20];
        if(
                (ev->datetime.tm_sec==0) &&
@@ -46,13 +50,17 @@ static int event_print(struct event *ev) {
                if(strftime(datebuf,20,"%Y-%m-%d %H:%M:%S",&(ev->datetime))!=19) { return -1; }
        }
 
-       if(fprintf(stdout,"%s\t",datebuf)<0) { return -1; }
+       if(fprintf(stdout,"%-20s\t",datebuf)<0) { return -1; }
        if(fprintf(stdout,"%s",ev->name)<0) { return -1; }
 
        if(ev->place!=NULL) {
                if(fprintf(stdout," @ %s",ev->place)<0) { return -1; }
        }
 
+       if(event_time_compare(&(ev->datetime),time(NULL))<1) {
+               if(fprintf(stdout," \x1B[31m[OVERDUE]\x1B[0m")<0) { return -1; }
+       }
+
        if(fprintf(stdout,"\n")<0) { return -1; }
 
        return 1;
diff --git a/src/opt/duration.c b/src/opt/duration.c
deleted file mode 100644 (file)
index 82c882e..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-#include<opt.h>
-
-int opt_duration_set(const char *p) {
-       unsigned int duration;
-       char c;
-       enum time_period period;
-
-       if(NULL==p) { return -1; }
-
-       if(sscanf(p,"%u%c",&duration,&c)!=2) {
-               fprintf(stderr,"invalid duration option value: %s\n",p);
-               return -1;
-       }
-
-       period = event_options_period(c);
-       if(TIME_PERIOD_NONE==period) {
-               fprintf(stderr,"invalid duration option value: %s\n",p);
-               return -1;
-       }
-
-       global_options.event_options.duration = duration;
-       global_options.event_options.duration_period = period;
-
-       return 1;
-}
index acf629842b6494002124f8a6d7a710386f38422e..041564100198bd332dccf8e5a083eb56b7b35f2e 100644 (file)
 int opt_load_from_env() {
        char *p;
 
-       CHECK_ENV("DURATION",opt_duration_set);
        CHECK_ENV("EVENT_FILTER",opt_event_filter_set);
        CHECK_ENV("FILE",opt_file_set);
        CHECK_ENV("RECUR",opt_recur_set);
+       CHECK_ENV("UNTIL",opt_until_set);
 
        return 1;
 }
index 60f6d7b69424a94e96b948e520f908bbb0df1158..b0e6e372d736908605845c93a1814f4144243807 100644 (file)
@@ -8,11 +8,11 @@ int opt_event_filter_date_set(time_t *to_set, const char *date_string) {
        assert(to_set!=NULL);
 
        /*
-        * This function uses the event_time_set(struct event *ev, const char *str)
+        * This function uses the event_time_set(struct tm *datetime, const char *str)
         * method for consistencies' sake.
         */
 
-       if(event_time_set(&ev,date_string)<0) {
+       if(event_time_set(&(ev.datetime),date_string)<0) {
                fprintf(stderr,"invalid date given: %s\n",date_string);
                return -1;
        }
@@ -24,7 +24,7 @@ int opt_event_filter_date_set(time_t *to_set, const char *date_string) {
 
 int opt_event_filter_range_set(const char *type, const char *arg) {
        if(strcmp(type,"upcoming")==0) {
-               if(opt_event_filter_range_set_upcoming(arg)<0) {
+               if(opt_event_filter_range_set_upcoming((NULL==arg)?"1W":arg)<0) {
                        fprintf(stderr,
                                "invalid time period given as argument to --upcoming option\n"
                        );
index 74bdd75cb288b5d63156806e775eb673c8be4634..3774c4f097920d2fcd6c8693ada5d085204607dd 100644 (file)
@@ -3,12 +3,8 @@
 void opt_global_init() {
        global_options.file = NULL;
 
-       global_options.event_options.duration = 0;
-       global_options.event_options.duration_period = TIME_PERIOD_NONE;
+       event_options_init(&(global_options.event_options));
 
-       global_options.event_options.recur = 0;
-       global_options.event_options.recur_period = TIME_PERIOD_NONE;
-       
        global_options.event_filter.start = 0;
        global_options.event_filter.end = 0;
 }
diff --git a/src/opt/until.c b/src/opt/until.c
new file mode 100644 (file)
index 0000000..49d1522
--- /dev/null
@@ -0,0 +1,18 @@
+#include<opt.h>
+
+int opt_until_set(const char *p) {
+       struct event ev;
+       
+       if(NULL==p) { return -1; }
+
+       event_init(&ev);
+
+       if(event_time_set(&(ev.datetime),p)<0) {
+               fprintf(stderr,"invalid until option value: %s\n",p);
+               return -1;
+       }
+
+       global_options.event_options.until = ev.datetime;
+
+       return 1;
+}
index 5bc2e7fb9dc28cbc85222fe35df4b7e776df265e..819996f6925b28c707bd4378639e389884dee65d 100644 (file)
--- a/src/rm.c
+++ b/src/rm.c
@@ -6,11 +6,13 @@ static int handle_args(int,char**,unsigned long int*, time_t *);
 static int check_need_readd(struct event *ev) {
        char buf[EVENT_SERIALIZE_MAX_LENGTH];
        char timebuf[40];
+       struct tm tm;
 
        assert(ev!=NULL);
 
        if(ev->options.recur==0) { return 1; }
 
+
        switch(ev->options.recur_period) {
                case TIME_PERIOD_YEAR:
                        ev->datetime.tm_year += ev->options.recur;
@@ -37,6 +39,11 @@ static int check_need_readd(struct event *ev) {
                        return -1;
        }
 
+       memcpy(&tm,&(ev->datetime),sizeof(struct tm));
+       if(event_time_compare(&(ev->options.until),0)>0) {
+               if(event_time_compare(&(ev->options.until),mktime(&tm))<0) { return 1; }
+       }
+
        strftime(timebuf,40,"%a, %d %b %Y %T %z",&(ev->datetime));
 
        if(snprintf(
index 837820267903cb0adbd5951db3cf22db42a20b2d..0166ef3f13f952d8880c9e24094ee1e1b38c8319 100644 (file)
@@ -11,7 +11,7 @@ int seek(FILE *fp, time_t time) {
        while((i = file_line_next(buf,EVENT_SERIALIZE_MAX_LENGTH,fp))>0) {
                if(event_parse(buf,EVENT_SERIALIZE_MAX_LENGTH,&ev)<0) { return -1; }
 
-               if(event_date_compare(&ev,time)>=0) {
+               if(event_time_compare(&(ev.datetime),time)>=0) {
                        event_free(&ev);
                        if(fseek(fp,-i,SEEK_CUR)!=0) { return -1; }
                        break;
index 4b6c9910a4618977c7e3c2a758c7152198417aa8..1b73693d6ad7ffffe3790f3a815c56d323a5d382 100644 (file)
@@ -1,5 +1,25 @@
 #include<usage.h>
 
+struct option_description {
+       const char *long_opt;
+       const char short_opt;
+       const char *description;
+};
+
+static struct option_description options[] = {
+       {"all",'a',"show all"},
+       {"end-date",'e',"ending date"},
+       {"file",'f',"events file location"},
+       {"help",'h',"show this help"},
+       {"overdue",'o',"show only overdue events"},
+       {"recurring",'r',"denote event as recurring"},
+       {"start-date",'s',"starting date"},
+       {"upcoming",'u',"show only upcoming events"},
+       {NULL,0,NULL}
+};
+
+static void usage_print_options();
+
 void usage() {
        fprintf(stderr,"Usage:\n");
        fprintf(stderr,"\tev [options] [command = 'ls'] [arg1, arg2, ..., argn]\n");
@@ -14,8 +34,27 @@ void usage() {
        fprintf(stderr,"\n");
 
        fprintf(stderr,"Options:\n");
+
+       usage_print_options();
+
        fprintf(stderr,"\n");
-       fprintf(stderr,"See `man ev` for more information\n");
+       fprintf(stderr,"See `man ev` for more information.\n");
 
        return;
 }
+
+static void usage_print_options() {
+       size_t i;
+
+       // NOTE: long options defined in src/args.c
+
+       i = 0;
+       while(
+               !((NULL==options[i].long_opt) &&
+               (0==options[i].short_opt) &&
+               (NULL==options[i].description))) {
+
+               fprintf(stderr,"\t--%s, -%c\t\t%s\n",options[i].long_opt,options[i].short_opt,options[i].description);
+               i++;
+       }
+}
index 50b3bc2dcc6450b89a6a61f905995a8e30b0a7e6..ba94b39e561cc955381b5592c9f9890f52fa4521 100644 (file)
@@ -6,13 +6,7 @@ EXTRA_DIST = \
        test_macros.h \
        test_utils.h
 
-if ENABLE_DEBUG
-else
-AM_CPPFLAGS += \
-       -DNDEBUG
-endif
-
-check_PROGRAMS = add.tests args.tests copy.tests cut.tests event.tests file.tests ls.tests opt.tests postpone.tests prune.tests rm.tests seek.tests
+check_PROGRAMS = add.tests args.tests copy.tests cut.tests event.tests file.tests ls.tests opt.tests postpone.tests prune.tests rm.tests seek.tests usage.tests
 TESTS = $(check_PROGRAMS)
 
 if ENABLE_MEMCHECK
@@ -22,13 +16,23 @@ endif
 
 common_SOURCES = \
        test_utils.c \
+       $(top_srcdir)/src/event/init.c \
        $(top_srcdir)/src/opt/global.c
 
+event_SOURCES = \
+       $(top_srcdir)/src/event/free.c \
+       $(top_srcdir)/src/event/name.c \
+       $(top_srcdir)/src/event/parse.c \
+       $(top_srcdir)/src/event/period.c \
+       $(top_srcdir)/src/event/place.c \
+       $(top_srcdir)/src/event/serial.c \
+       $(top_srcdir)/src/event/time.c
+       
 add_tests_SOURCES = \
        $(common_SOURCES) \
+       $(event_SOURCES) \
        add.tests.c \
        $(top_srcdir)/src/copy.c \
-       $(top_srcdir)/src/event.c \
        $(top_srcdir)/src/file/line.c \
        $(top_srcdir)/src/file/mv.c \
        $(top_srcdir)/src/file/open.c \
@@ -43,26 +47,27 @@ args_tests_SOURCES = \
        $(common_SOURCES) \
        args.tests.c \
        $(top_srcdir)/src/args.c \
-       $(top_srcdir)/src/event.c \
-       $(top_srcdir)/src/opt/duration.c \
+       $(top_srcdir)/src/event/period.c \
+       $(top_srcdir)/src/event/time.c \
        $(top_srcdir)/src/opt/file.c \
        $(top_srcdir)/src/opt/filter.c \
        $(top_srcdir)/src/opt/recur.c \
+       $(top_srcdir)/src/opt/until.c \
        $(top_srcdir)/src/usage.c
 
 copy_tests_SOURCES = \
        $(common_SOURCES) \
+       $(event_SOURCES) \
        copy.tests.c \
        $(top_srcdir)/src/copy.c \
-       $(top_srcdir)/src/event.c \
        $(top_srcdir)/src/file/line.c \
        $(top_srcdir)/src/file/tmp.c
 
 cut_tests_SOURCES = \
        $(common_SOURCES) \
+       $(event_SOURCES) \
        cut.tests.c \
        $(top_srcdir)/src/copy.c \
-       $(top_srcdir)/src/event.c \
        $(top_srcdir)/src/file/line.c \
        $(top_srcdir)/src/file/open.c \
        $(top_srcdir)/src/file/pipe.c \
@@ -73,8 +78,9 @@ cut_tests_CPPFLAGS = $(AM_CPPFLAGS) \
        -DCUT_SRC_FILE="$(top_srcdir)/src/cut.c"
 
 event_tests_SOURCES = \
-       event.tests.c \
-       $(top_srcdir)/src/event.c
+       $(common_SOURCES) \
+       $(event_SOURCES) \
+       event.tests.c
 
 file_tests_SOURCES = \
        $(common_SOURCES) \
@@ -87,23 +93,30 @@ file_tests_SOURCES = \
 
 ls_tests_SOURCES = \
        $(common_SOURCES) \
-       ls.tests.c
+       $(event_SOURCES) \
+       ls.tests.c \
+       $(top_srcdir)/src/file/line.c \
+       $(top_srcdir)/src/file/open.c
+
+ls_tests_CPPFLAGS = $(AM_CPPFLAGS) \
+       -DLS_SRC_FILE="$(top_srcdir)/src/ls.c"
 
 opt_tests_SOURCES = \
        $(common_SOURCES) \
        opt.tests.c \
-       $(top_srcdir)/src/event.c \
-       $(top_srcdir)/src/opt/duration.c \
+       $(top_srcdir)/src/event/period.c \
+       $(top_srcdir)/src/event/time.c \
        $(top_srcdir)/src/opt/filter.c \
-       $(top_srcdir)/src/opt/recur.c
+       $(top_srcdir)/src/opt/recur.c \
+       $(top_srcdir)/src/opt/until.c
 
 postpone_tests_SOURCES = \
        $(common_SOURCES) \
+       $(event_SOURCES) \
        postpone.tests.c \
        $(top_srcdir)/src/add.c \
        $(top_srcdir)/src/copy.c \
        $(top_srcdir)/src/cut.c \
-       $(top_srcdir)/src/event.c \
        $(top_srcdir)/src/file/line.c \
        $(top_srcdir)/src/file/mv.c \
        $(top_srcdir)/src/file/open.c \
@@ -117,8 +130,8 @@ postpone_tests_CPPFLAGS = $(AM_CPPFLAGS) \
 
 prune_tests_SOURCES = \
        $(common_SOURCES) \
+       $(event_SOURCES) \
        prune.tests.c \
-       $(top_srcdir)/src/event.c \
        $(top_srcdir)/src/file/line.c \
        $(top_srcdir)/src/file/mv.c \
        $(top_srcdir)/src/file/open.c \
@@ -129,11 +142,11 @@ prune_tests_SOURCES = \
 
 rm_tests_SOURCES = \
        $(common_SOURCES) \
+       $(event_SOURCES) \
        rm.tests.c \
        $(top_srcdir)/src/add.c \
        $(top_srcdir)/src/copy.c \
        $(top_srcdir)/src/cut.c \
-       $(top_srcdir)/src/event.c \
        $(top_srcdir)/src/file/line.c \
        $(top_srcdir)/src/file/mv.c \
        $(top_srcdir)/src/file/open.c \
@@ -147,7 +160,20 @@ rm_tests_CPPFLAGS = $(AM_CPPFLAGS) \
 
 seek_tests_SOURCES = \
        $(common_SOURCES) \
+       $(event_SOURCES) \
        seek.tests.c \
-       $(top_srcdir)/src/event.c \
        $(top_srcdir)/src/file/line.c \
        $(top_srcdir)/src/seek.c
+
+usage_tests_SOURCES = \
+       $(common_SOURCES) \
+       $(event_SOURCES) \
+       usage.tests.c \
+       $(top_srcdir)/src/opt/file.c \
+       $(top_srcdir)/src/opt/filter.c \
+       $(top_srcdir)/src/opt/recur.c \
+       $(top_srcdir)/src/opt/until.c
+
+usage_tests_CPPFLAGS = $(AM_CPPFLAGS) \
+       -DARGS_SRC_FILE="$(top_srcdir)/src/args.c" \
+       -DUSAGE_SRC_FILE="$(top_srcdir)/src/usage.c"
index 1d56e26671b05970a2447ba0266275721c5f68e6..b34370a193894a1bf3a15e174b53b4cd98844e5e 100644 (file)
@@ -12,10 +12,15 @@ static void add_place_set_basic_test();
 static void add_time_set_basic_test();
 static void add_to_file_basic_test();
 static void add_to_file_extensive_test();
+static void handle_args_basic_test();
+static void handle_options_basic_test();
 
 int main() {
        setup_env();
 
+       handle_args_basic_test();
+       handle_options_basic_test();
+
        add_name_set_basic_test();
        add_place_set_basic_test();
        add_time_set_basic_test();
@@ -180,3 +185,74 @@ static void add_to_file_extensive_test() {
                rounds++;
        }
 }
+
+static void handle_args_basic_test() {
+       struct event ev;
+
+       event_init(&ev);
+
+       char *args_with_place[] = {
+               "ev",
+               "add",
+               "event",
+               "place",
+               "2022-01-01",
+               NULL
+       };
+       assert(handle_args(0,args_with_place,&ev)==-1);
+       assert(handle_args(5,args_with_place,&ev)==1);
+       assert(strcmp(ev.name,"event")==0);
+       assert(strcmp(ev.place,"place")==0);
+       assert(mktime(&(ev.datetime))==1641024000);
+
+       char *args[] = {
+               "ev",
+               "add",
+               "event23",
+               "2020-01-01",
+               NULL
+       };
+
+       event_free(&ev);
+
+       event_init(&ev);
+
+       assert(handle_args(4,args,&ev)==1);
+       assert(strcmp(ev.name,"event23")==0);
+       assert(ev.place==NULL);
+       assert(mktime(&(ev.datetime))==1577865600);
+
+       event_free(&ev);
+}
+
+static void handle_options_basic_test() {
+       struct event ev;
+       struct tm dummy;
+
+       event_init(&ev);
+
+       memset(&dummy,0,sizeof(struct tm));
+
+       assert(1==handle_options(&ev));
+       assert(0==ev.options.recur);
+       assert(TIME_PERIOD_NONE==ev.options.recur_period);
+       assert(memcmp(&dummy,&(ev.options.until),sizeof(struct tm))==0);
+
+       global_options.event_filter.end = 1000;
+       
+       assert(1==handle_options(&ev));
+       assert(0==ev.options.recur);
+       assert(TIME_PERIOD_NONE==ev.options.recur_period);
+       assert(memcmp(&dummy,&(ev.options.until),sizeof(struct tm))==0);
+
+       global_options.event_options.recur = 1;
+       global_options.event_options.recur_period = TIME_PERIOD_DAY;
+       global_options.event_filter.end = 1600000000;
+
+       assert(1==handle_options(&ev));
+       assert(1==ev.options.recur);
+       assert(TIME_PERIOD_DAY==ev.options.recur_period);
+       assert(mktime(&(ev.options.until))==1600000000);
+
+       reset_env();
+}
index a517266ce6cd3bb0339e8cbf3208a3488205cbd6..41da3da98dd6ef9f03a4158418d738e6acf5d1de 100644 (file)
@@ -13,6 +13,7 @@ static void args_ls_end_date_basic_test();
 static void args_ls_overdue_basic_test();
 static void args_ls_start_date_basic_test();
 static void args_ls_upcoming_basic_test();
+static void args_ls_upcoming_optional_arg_test();
 static void args_order_test();
 static void args_postpone_basic_test();
 static void args_prune_basic_test();
@@ -51,6 +52,7 @@ static void args_basic_test() {
        args_ls_end_date_basic_test();
        args_ls_overdue_basic_test();
        args_ls_upcoming_basic_test();
+       args_ls_upcoming_optional_arg_test();
        args_ls_start_date_basic_test();
        args_postpone_basic_test();
        args_prune_basic_test();
@@ -75,17 +77,13 @@ static void args_long_opts_basic_test() {
        char *long_opts_args[] = {
                "ev",
                "add",
-               "--duration",
-               "1W",
                "--file",
                "/tmp/events.test2",
                "--recurring",
                "1Y",
                NULL
        };
-       assert(SUB_COMMAND_ADD==args(8,long_opts_args));
-       assert(global_options.event_options.duration==1);
-       assert(global_options.event_options.duration_period==TIME_PERIOD_WEEK);
+       assert(SUB_COMMAND_ADD==args(6,long_opts_args));
        assert(strcmp(global_options.file,"/tmp/events.test2")==0);
        assert(global_options.event_options.recur==1);
        assert(global_options.event_options.recur_period==TIME_PERIOD_YEAR);
@@ -249,33 +247,96 @@ static void args_ls_upcoming_basic_test() {
 
        reset_env();
 }
+       
+static void args_ls_upcoming_optional_arg_test() {
+       char *ls_upcoming_no_arg[] = {
+               "ev",
+               "ls",
+               "-u",
+               NULL
+       };
+       assert(SUB_COMMAND_LS==args(3,ls_upcoming_no_arg));
+       assert((time(NULL) - global_options.event_filter.start)<1);
+       assert((global_options.event_filter.end - global_options.event_filter.start)<(60*60*24*7+1));
+       optind = 0;
+
+       reset_env();
+
+       char *ls_upcoming_long_optional_arg[] = {
+               "ev",
+               "--upcoming",
+               NULL
+       };
+       assert(SUB_COMMAND_LS==args(2,ls_upcoming_long_optional_arg));
+       assert((time(NULL) - global_options.event_filter.start)<1);
+       assert((global_options.event_filter.end - global_options.event_filter.start)<(60*60*24*7+1));
+       optind = 0;
+
+       reset_env();
+       
+       char *ls_upcoming_short_optional_arg_fail[] = {
+               "ev",
+               "-u",
+               "ls",
+               NULL
+       };
+       assert(SUB_COMMAND_INVALID_ARGS==args(3,ls_upcoming_short_optional_arg_fail));
+       optind = 0;
+
+       reset_env();
+
+       char *ls_upcoming_long_optional_arg_fail[] = {
+               "ev",
+               "--upcoming",
+               "ls",
+               NULL
+       };
+       assert(SUB_COMMAND_INVALID_ARGS==args(3,ls_upcoming_long_optional_arg_fail));
+       optind = 0;
+
+       reset_env();
+
+       char *ls_upcoming_short_optional_arg[] = {
+               "ev",
+               "-u",
+               "1D",
+               "ls",
+               NULL
+       };
+
+       assert(SUB_COMMAND_LS==args(4,ls_upcoming_short_optional_arg));
+       assert((time(NULL) - global_options.event_filter.start)<1);
+       assert((global_options.event_filter.end - global_options.event_filter.start)<(60*60*24+1));
+       optind = 0;
+
+       reset_env();
+}
 
 static void args_order_test() {
        char *normal[] = {
                "ev",
                "add",
-               "--duration",
+               "--recur",
                "1W",
                NULL
        };
        assert(SUB_COMMAND_ADD==args(4,normal));
-       assert(global_options.event_options.duration==1);
-       assert(global_options.event_options.duration_period==TIME_PERIOD_WEEK);
+       assert(global_options.event_options.recur==1);
+       assert(global_options.event_options.recur_period==TIME_PERIOD_WEEK);
        optind = 0;
 
        reset_env();
 
        char *swapped[] = {
                "ev",
-               "--duration",
+               "--recur",
                "1W",
                "add",
                NULL
        };
        assert(SUB_COMMAND_ADD==args(4,swapped));
-       assert(global_options.event_options.duration==1);
-       assert(global_options.event_options.duration_period==TIME_PERIOD_WEEK);
-       optind = 0;
+       assert(global_options.event_options.recur==1);
+       assert(global_options.event_options.recur_period==TIME_PERIOD_WEEK);
        optind = 0;
        reset_env();
 }
@@ -314,17 +375,13 @@ static void args_short_opts_basic_test() {
        char *short_opts_args[] = {
                "ev",
                "add",
-               "-d",
-               "1m",
                "-f",
                "/tmp/events.test3",
                "-r",
                "1D",
                NULL
        };
-       assert(SUB_COMMAND_ADD==args(8,short_opts_args));
-       assert(global_options.event_options.duration==1);
-       assert(global_options.event_options.duration_period==TIME_PERIOD_MINUTE);
+       assert(SUB_COMMAND_ADD==args(6,short_opts_args));
        assert(strcmp(global_options.file,"/tmp/events.test3")==0);
        assert(global_options.event_options.recur==1);
        assert(global_options.event_options.recur_period==TIME_PERIOD_DAY);
index 3ea0f35baa881d37c6886d4c6eed089754665d53..09ef926acc6a9fe413f85eeca55c1b71a088b767 100644 (file)
@@ -1,19 +1,24 @@
+#include<test_utils.h>
+
 #include<event.h>
 
 int main();
-static void event_date_compare_basic_test();
 static void event_init_basic_test();
 static void event_name_set_basic_test();
 static void event_parse_basic_test();
 static void event_place_set_basic_test();
 static void event_serialize_basic_test();
 static void event_serialize_parse_exactness_test();
+static void event_time_compare_basic_test();
 static void event_time_set_basic_test();
+static void time_unset(struct tm*);
 
 int main() {
+       setup_env();
+
        event_init_basic_test();
 
-       event_date_compare_basic_test();
+       event_time_compare_basic_test();
        event_name_set_basic_test();
        event_parse_basic_test();
        event_place_set_basic_test();
@@ -21,57 +26,24 @@ int main() {
        event_serialize_parse_exactness_test();
        event_time_set_basic_test();
 
-       return EXIT_SUCCESS;
-}
-
-static void event_date_compare_basic_test() {
-       char timebuf[40];
-       struct event ev;
-       time_t timet;
-       struct tm *now, got;
-
-       event_init(&ev);
-
-       timet = time(NULL);
-       now = localtime(&timet);
-       
-       assert(strftime(timebuf,40,"%Y-%m-%d %H:%M:%S %z",now)==25);
-       assert(1==event_time_set(&ev,timebuf));
-
-       /* daylight savings time set here for some reason.
-        * resetting timet to be time set in ev...
-        */
-       memcpy(&got,&(ev.datetime),sizeof(struct tm));
-       timet = mktime(&got);
-
-       timet -= 1000;
-       assert(1==event_date_compare(&ev,timet));
-
-       timet += 2000;
-       assert(-1==event_date_compare(&ev,timet));
-
-       timet -= 1000;
-       assert(0==event_date_compare(&ev,timet));
+       clean_env();
 
-       event_free(&ev);
+       return EXIT_SUCCESS;
 }
 
 static void event_init_basic_test() {
        struct event ev;
-       struct tm dummy;
 
        event_init(&ev);
 
        assert(ev.name==NULL);
        assert(ev.place==NULL);
 
-       assert(ev.options.duration==0);
-       assert(ev.options.duration_period==TIME_PERIOD_NONE);
        assert(ev.options.recur==0);
        assert(ev.options.recur_period==TIME_PERIOD_NONE);
 
-       memset(&dummy, 0, sizeof(struct tm));
-       assert(memcmp(&(ev.datetime),&dummy,sizeof(struct tm))==0);
+       time_unset(&(ev.options.until));
+       time_unset(&(ev.datetime));
 
        event_free(&ev);
 }
@@ -98,10 +70,9 @@ static void event_parse_basic_test() {
        event_init(&ev1);
        char ex1[] = "2022-09-01:test event:test place";
        assert(event_parse(ex1,sizeof(ex1),&ev1)==1);
-       assert(ev1.options.duration==0);
-       assert(ev1.options.duration_period==TIME_PERIOD_NONE);
        assert(ev1.options.recur==0);
        assert(ev1.options.recur_period==TIME_PERIOD_NONE);
+       time_unset(&(ev1.options.until));
        assert(strcmp(ev1.name,"test event")==0);
        assert(strcmp(ev1.place,"test place")==0);
        assert(mktime(&(ev1.datetime))==1662019200);
@@ -109,10 +80,9 @@ static void event_parse_basic_test() {
        event_init(&ev2);
        char ex2[] = "2022-09-02:\"test: event2\":\"test: place2\"";
        assert(event_parse(ex2,sizeof(ex2),&ev2)==1);
-       assert(ev2.options.duration==0);
-       assert(ev2.options.duration_period==TIME_PERIOD_NONE);
        assert(ev2.options.recur==0);
        assert(ev2.options.recur_period==TIME_PERIOD_NONE);
+       time_unset(&(ev2.options.until));
        assert(strcmp(ev2.name,"test: event2")==0);
        assert(strcmp(ev2.place,"test: place2")==0);
        assert(mktime(&(ev2.datetime))==1662105600);
@@ -120,10 +90,9 @@ static void event_parse_basic_test() {
        event_init(&ev3);
        char ex3[] = "2022-09-03 09:30:00:test event3:test place3";
        assert(event_parse(ex3,sizeof(ex3),&ev3)==1);
-       assert(ev3.options.duration==0);
-       assert(ev3.options.duration_period==TIME_PERIOD_NONE);
        assert(ev3.options.recur==0);
        assert(ev3.options.recur_period==TIME_PERIOD_NONE);
+       time_unset(&(ev3.options.until));
        assert(strcmp(ev3.name,"test event3")==0);
        assert(strcmp(ev3.place,"test place3")==0);
        assert(mktime(&(ev3.datetime))==1662226200);
@@ -131,10 +100,9 @@ static void event_parse_basic_test() {
        event_init(&ev4);
        char ex4[] = "2022-09-04 09:30:00 -0700:test event4:test place4";
        assert(event_parse(ex4,sizeof(ex4),&ev4)==1);
-       assert(ev4.options.duration==0);
-       assert(ev4.options.duration_period==TIME_PERIOD_NONE);
        assert(ev4.options.recur==0);
        assert(ev4.options.recur_period==TIME_PERIOD_NONE);
+       time_unset(&(ev4.options.until));
        assert(strcmp(ev4.name,"test event4")==0);
        assert(strcmp(ev4.place,"test place4")==0);
        assert(mktime(&(ev4.datetime))==1662312600);
@@ -142,43 +110,39 @@ static void event_parse_basic_test() {
        event_init(&ev5);
        char ex5[] = "[recur:1M]2022-08-04:test event5:test place5";
        assert(event_parse(ex5,sizeof(ex5),&ev5)==1);
-       assert(ev5.options.duration==0);
-       assert(ev5.options.duration_period==TIME_PERIOD_NONE);
        assert(ev5.options.recur==1);
        assert(ev5.options.recur_period==TIME_PERIOD_MONTH);
+       time_unset(&(ev5.options.until));
        assert(strcmp(ev5.name,"test event5")==0);
        assert(strcmp(ev5.place,"test place5")==0);
        assert(mktime(&(ev5.datetime))==1659600000);
 
        event_init(&ev6);
-       char ex6[] = "[duration:1W]2022-06-05 09:30:00 -0700:test event6:test place6";
+       char ex6[] = "[recur:1W]2022-06-05 09:30:00 -0700:test event6:test place6";
        assert(event_parse(ex6,sizeof(ex6),&ev6)==1);
-       assert(ev6.options.duration==1);
-       assert(ev6.options.duration_period==TIME_PERIOD_WEEK);
-       assert(ev6.options.recur==0);
-       assert(ev6.options.recur_period==TIME_PERIOD_NONE);
+       assert(ev6.options.recur==1);
+       assert(ev6.options.recur_period==TIME_PERIOD_WEEK);
+       time_unset(&(ev6.options.until));
        assert(strcmp(ev6.name,"test event6")==0);
        assert(strcmp(ev6.place,"test place6")==0);
        assert(mktime(&(ev6.datetime))==1654450200);
 
        event_init(&ev7);
-       char ex7[] = "[recur:1W,duration:30m]2022-10-01 09:30:00 -0700:test event7:test place7";
+       char ex7[] = "[recur:1W,until:2022-11-01]2022-10-01 09:30:00 -0700:test event7:test place7";
        assert(event_parse(ex7,sizeof(ex7),&ev7)==1);
-       assert(ev7.options.duration==30);
-       assert(ev7.options.duration_period==TIME_PERIOD_MINUTE);
        assert(ev7.options.recur==1);
        assert(ev7.options.recur_period==TIME_PERIOD_WEEK);
+       assert(mktime(&(ev7.options.until))==1667289600);
        assert(strcmp(ev7.name,"test event7")==0);
        assert(strcmp(ev7.place,"test place7")==0);
        assert(mktime(&(ev7.datetime))==1664645400);
 
        event_init(&ev8);
-       char ex8[] = "[duration:30m,recur:1W]2022-10-01 09:30:00 -0700:test event8:test place8";
+       char ex8[] = "[until:2022-10-10,recur:1W]2022-10-01 09:30:00 -0700:test event8:test place8";
        assert(event_parse(ex8,sizeof(ex8),&ev8)==1);
-       assert(ev8.options.duration==30);
-       assert(ev8.options.duration_period==TIME_PERIOD_MINUTE);
        assert(ev8.options.recur==1);
        assert(ev8.options.recur_period==TIME_PERIOD_WEEK);
+       assert(mktime(&(ev8.options.until))==1665388800);
        assert(strcmp(ev8.name,"test event8")==0);
        assert(strcmp(ev8.place,"test place8")==0);
        assert(mktime(&(ev8.datetime))==1664645400);
@@ -186,10 +150,9 @@ static void event_parse_basic_test() {
        event_init(&ev9);
        char ex9[] = "2022-08-01:test";
        assert(event_parse(ex9,sizeof(ex9),&ev9)==1);
-       assert(ev9.options.duration==0);
-       assert(ev9.options.duration_period==TIME_PERIOD_NONE);
        assert(ev9.options.recur==0);
        assert(ev9.options.recur_period==TIME_PERIOD_NONE);
+       time_unset(&(ev9.options.until));
        assert(strcmp(ev9.name,"test")==0);
        assert(NULL==ev9.place);
        assert(mktime(&(ev9.datetime))==1659340800);
@@ -227,7 +190,7 @@ static void event_serialize_basic_test() {
 
        event_init(&ev);
 
-       assert(1==event_time_set(&ev,"2022-07-01 08:01:15 -0100"));
+       assert(1==event_time_set(&(ev.datetime),"2022-07-01 08:01:15 -0100"));
        assert(-1==event_serialize(buf,EVENT_SERIALIZE_MAX_LENGTH,&ev));
 
        assert(1==event_name_set(&ev,"event"));
@@ -235,57 +198,56 @@ static void event_serialize_basic_test() {
        assert(strcmp(buf,"2022-07-01 08:01:15 -0100:event\n")==0);
        
        event_init(&ev);
-       assert(1==event_time_set(&ev,"2022-07-01 08:01:15 -0100"));
+       assert(1==event_time_set(&(ev.datetime),"2022-07-01 08:01:15 -0100"));
        assert(1==event_name_set(&ev,"event"));
        assert(1==event_place_set(&ev,"place"));
        assert(1==event_serialize(buf,EVENT_SERIALIZE_MAX_LENGTH,&ev));
        assert(strcmp(buf,"2022-07-01 08:01:15 -0100:event:place\n")==0);
        
        event_init(&ev);
-       assert(1==event_time_set(&ev,"2022-07-01 08:01:15 -0100"));
+       assert(1==event_time_set(&(ev.datetime),"2022-07-01 08:01:15 -0100"));
        assert(1==event_name_set(&ev,"event: what?"));
        assert(1==event_place_set(&ev,"place: here"));
        assert(1==event_serialize(buf,EVENT_SERIALIZE_MAX_LENGTH,&ev));
        assert(strcmp(buf,"2022-07-01 08:01:15 -0100:\"event: what?\":\"place: here\"\n")==0);
 
        event_init(&ev);
-       assert(1==event_time_set(&ev,"2022-06-21"));
+       assert(1==event_time_set(&(ev.datetime),"2022-06-21"));
        assert(1==event_name_set(&ev,"event"));
        assert(1==event_place_set(&ev,"place"));
        assert(1==event_serialize(buf,EVENT_SERIALIZE_MAX_LENGTH,&ev));
        assert(strcmp(buf,"2022-06-21:event:place\n")==0);
 
        event_init(&ev);
-       assert(1==event_time_set(&ev,"2022-06-21"));
+       assert(1==event_time_set(&(ev.datetime),"2022-06-21"));
        assert(1==event_name_set(&ev,"event"));
        assert(1==event_place_set(&ev,"place"));
-       ev.options.duration = 30;
-       ev.options.duration_period = TIME_PERIOD_DAY;
+       ev.options.recur = 1;
+       ev.options.recur_period = TIME_PERIOD_DAY;
        assert(1==event_serialize(buf,EVENT_SERIALIZE_MAX_LENGTH,&ev));
-       assert(strcmp(buf,"[duration:30D]2022-06-21:event:place\n")==0);
+       assert(strcmp(buf,"[recur:1D]2022-06-21:event:place\n")==0);
        
        event_init(&ev);
-       assert(1==event_time_set(&ev,"2022-06-21"));
+       assert(1==event_time_set(&(ev.datetime),"2022-06-21"));
        assert(1==event_name_set(&ev,"event"));
        assert(1==event_place_set(&ev,"place"));
-       ev.options.duration = 30;
-       ev.options.duration_period = TIME_PERIOD_DAY;
        ev.options.recur = 1;
        ev.options.recur_period = TIME_PERIOD_YEAR;
+       assert(1==event_time_set(&(ev.options.until),"2024-01-01"));
        assert(1==event_serialize(buf,EVENT_SERIALIZE_MAX_LENGTH,&ev));
-       assert(strcmp(buf,"[duration:30D,recur:1Y]2022-06-21:event:place\n")==0);
+       assert(strcmp(buf,"[recur:1Y,until:2024-01-01]2022-06-21:event:place\n")==0);
 }
 
 static void event_serialize_parse_exactness_test() {
        struct event ev;
 
-       const char expected[] = "[duration:30D,recur:1Y]2000-01-01:event:test palaaec\n";
+       const char expected[] = "[recur:1Y,until:2000-02-01]2000-01-01:event:test palaaec\n";
        char buf[EVENT_SERIALIZE_MAX_LENGTH];
 
        memset(buf,0,EVENT_SERIALIZE_MAX_LENGTH);
        event_init(&ev);
 
-       assert(53==strlen(expected));
+       assert(57==strlen(expected));
        strcpy(buf,expected);
 
        assert(1==event_parse(buf,EVENT_SERIALIZE_MAX_LENGTH,&ev));
@@ -293,7 +255,39 @@ static void event_serialize_parse_exactness_test() {
        memset(buf,0,EVENT_SERIALIZE_MAX_LENGTH);
        assert(1==event_serialize(buf,EVENT_SERIALIZE_MAX_LENGTH,&ev));
 
-       assert(memcmp(expected,buf,53)==0);
+       assert(memcmp(expected,buf,57)==0);
+}
+
+static void event_time_compare_basic_test() {
+       char timebuf[40];
+       struct event ev;
+       time_t timet;
+       struct tm *now, got;
+
+       event_init(&ev);
+
+       timet = time(NULL);
+       now = localtime(&timet);
+       
+       assert(strftime(timebuf,40,"%Y-%m-%d %H:%M:%S %z",now)==25);
+       assert(1==event_time_set(&(ev.datetime),timebuf));
+
+       /* daylight savings time set here for some reason.
+        * resetting timet to be time set in ev...
+        */
+       memcpy(&got,&(ev.datetime),sizeof(struct tm));
+       timet = mktime(&got);
+
+       timet -= 1000;
+       assert(1==event_time_compare(&(ev.datetime),timet));
+
+       timet += 2000;
+       assert(-1==event_time_compare(&(ev.datetime),timet));
+
+       timet -= 1000;
+       assert(0==event_time_compare(&(ev.datetime),timet));
+
+       event_free(&ev);
 }
 
 static void event_time_set_basic_test() {
@@ -301,12 +295,12 @@ static void event_time_set_basic_test() {
 
        event_init(&ev);
 
-       assert(-1==event_time_set(&ev,"nota  date"));
+       assert(-1==event_time_set(&(ev.datetime),"nota  date"));
 
-       assert(-1==event_time_set(&ev,"99"));
-       assert(-1==event_time_set(&ev,"99-02"));
+       assert(-1==event_time_set(&(ev.datetime),"99"));
+       assert(-1==event_time_set(&(ev.datetime),"99-02"));
 
-       assert(1==event_time_set(&ev,"1999-02-28"));
+       assert(1==event_time_set(&(ev.datetime),"1999-02-28"));
        assert(ev.datetime.tm_sec==0);
        assert(ev.datetime.tm_min==0);
        assert(ev.datetime.tm_hour==0);
@@ -316,9 +310,9 @@ static void event_time_set_basic_test() {
        assert(ev.datetime.tm_wday==0);
        assert(ev.datetime.tm_yday==58);
        assert(ev.datetime.tm_isdst==0);
-       assert(ev.datetime.__tm_gmtoff==0);
+       assert(ev.datetime.tm_gmtoff==0);
 
-       assert(1==event_time_set(&ev,"1997-01-28 not a time"));
+       assert(1==event_time_set(&(ev.datetime),"1997-01-28 not a time"));
        assert(ev.datetime.tm_sec==0);
        assert(ev.datetime.tm_min==0);
        assert(ev.datetime.tm_hour==0);
@@ -328,9 +322,9 @@ static void event_time_set_basic_test() {
        assert(ev.datetime.tm_wday==2);
        assert(ev.datetime.tm_yday==27);
        assert(ev.datetime.tm_isdst==0);
-       assert(ev.datetime.__tm_gmtoff==0);
+       assert(ev.datetime.tm_gmtoff==0);
 
-       assert(1==event_time_set(&ev,"2002-05-24 121212"));
+       assert(1==event_time_set(&(ev.datetime),"2002-05-24 121212"));
        assert(ev.datetime.tm_sec==0);
        assert(ev.datetime.tm_min==0);
        assert(ev.datetime.tm_hour==12);
@@ -340,9 +334,9 @@ static void event_time_set_basic_test() {
        assert(ev.datetime.tm_wday==5);
        assert(ev.datetime.tm_yday==143);
        assert(ev.datetime.tm_isdst==0);
-       assert(ev.datetime.__tm_gmtoff==0);
+       assert(ev.datetime.tm_gmtoff==0);
        
-       assert(1==event_time_set(&ev,"2012-12-22 12:1212"));
+       assert(1==event_time_set(&(ev.datetime),"2012-12-22 12:1212"));
        assert(ev.datetime.tm_sec==0);
        assert(ev.datetime.tm_min==12);
        assert(ev.datetime.tm_hour==12);
@@ -352,9 +346,9 @@ static void event_time_set_basic_test() {
        assert(ev.datetime.tm_wday==6);
        assert(ev.datetime.tm_yday==356);
        assert(ev.datetime.tm_isdst==0);
-       assert(ev.datetime.__tm_gmtoff==0);
+       assert(ev.datetime.tm_gmtoff==0);
        
-       assert(1==event_time_set(&ev,"2022-01-24 09:19:55"));
+       assert(1==event_time_set(&(ev.datetime),"2022-01-24 09:19:55"));
        assert(ev.datetime.tm_sec==55);
        assert(ev.datetime.tm_min==19);
        assert(ev.datetime.tm_hour==9);
@@ -364,9 +358,9 @@ static void event_time_set_basic_test() {
        assert(ev.datetime.tm_wday==1);
        assert(ev.datetime.tm_yday==23);
        assert(ev.datetime.tm_isdst==0);
-       assert(ev.datetime.__tm_gmtoff==0);
+       assert(ev.datetime.tm_gmtoff==0);
        
-       assert(1==event_time_set(&ev,"2009-01-03 13:25:25 -0800"));
+       assert(1==event_time_set(&(ev.datetime),"2009-01-03 13:25:25 -0800"));
        assert(ev.datetime.tm_sec==25);
        assert(ev.datetime.tm_min==25);
        assert(ev.datetime.tm_hour==13);
@@ -376,5 +370,11 @@ static void event_time_set_basic_test() {
        assert(ev.datetime.tm_wday==6);
        assert(ev.datetime.tm_yday==2);
        assert(ev.datetime.tm_isdst==0);
-       assert(ev.datetime.__tm_gmtoff==-28800);
+       assert(ev.datetime.tm_gmtoff==-28800);
+}
+
+static void time_unset(struct tm *tm) {
+       struct tm dummy;
+       memset(&dummy, 0, sizeof(struct tm));
+       assert(memcmp(tm,&dummy,sizeof(struct tm))==0);
 }
index ec2b828aca50b1ad691fd66ee51a10c123cad274..61d4f93fd88472bba154d0e1f6c1497214aafc60 100644 (file)
@@ -2,8 +2,27 @@
 
 #include<ls.h>
 
+#include INCLUDE(LS_SRC_FILE)
+
 int main();
+static void event_print_basic_test();
 
 int main() {
+       event_print_basic_test();
+
        return EXIT_SUCCESS;
 }
+
+static void event_print_basic_test() {
+       struct event ev;
+
+       event_init(&ev);
+
+       assert(event_print(&ev)==-1);
+
+       assert(1==event_name_set(&ev,"test"));
+
+       assert(event_print(&ev)==1);
+
+       event_free(&ev);
+}
index 24e811080921da04369470741c968f14a3cb8605..0124f01b9fa8e29fd96da39794b360d502533c18 100644 (file)
@@ -3,43 +3,26 @@
 #include<opt.h>
 
 int main();
-static void opt_duration_set_basic_test();
 static void opt_event_filter_date_set_basic_test();
 static void opt_event_filter_range_set_basic_test();
 static void opt_event_filter_set_basic_test();
 static void opt_recur_set_basic_test();
+static void opt_until_set_basic_test();
 
 int main() {
        setup_env();
 
-       opt_duration_set_basic_test();
        opt_event_filter_date_set_basic_test();
        opt_event_filter_range_set_basic_test();
        opt_event_filter_set_basic_test();
        opt_recur_set_basic_test();
+       opt_until_set_basic_test();
 
        clean_env();
 
        return EXIT_SUCCESS;
 }
 
-static void opt_duration_set_basic_test() {
-       assert(-1==opt_duration_set(NULL));
-
-       assert(-1==opt_duration_set("notdsoifjaoisdjfoiasdj"));
-       assert(global_options.event_options.duration==0);
-       assert(global_options.event_options.duration_period==TIME_PERIOD_NONE);
-
-       assert(-1==opt_duration_set("1u"));
-       assert(global_options.event_options.duration==0);
-       assert(global_options.event_options.duration_period==TIME_PERIOD_NONE);
-
-       assert(1==opt_duration_set("1Y"));
-       assert(global_options.event_options.duration==1);
-       assert(global_options.event_options.duration_period==TIME_PERIOD_YEAR);
-
-       reset_env();
-}
 
 static void opt_event_filter_date_set_basic_test() {
        assert(-1==opt_event_filter_date_set(&(global_options.event_filter.start),"notadate"));
@@ -111,3 +94,14 @@ static void opt_recur_set_basic_test() {
 
        reset_env();
 }
+
+static void opt_until_set_basic_test() {
+       assert(-1==opt_until_set(NULL));
+
+       assert(-1==opt_until_set("notdsoifjaoisdjfoiasdj"));
+
+       assert(1==opt_until_set("2022-01-01"));
+       assert(mktime(&(global_options.event_options.until))==1641024000);
+
+       reset_env();
+}
index f54d95ead655ec91356f38aad7e8a8a8a18d48b2..64a2d5fc3a5553493f46dd3fd5ff705b44730117 100644 (file)
@@ -121,7 +121,7 @@ static void postpone_event_basic_test() {
        memset(buf,0,EVENT_SERIALIZE_MAX_LENGTH);
 
        assert(event_name_set(&ev,"test")==1);
-       assert(event_time_set(&ev,"2020-01-01")==1);
+       assert(event_time_set(&(ev.datetime),"2020-01-01")==1);
 
        postpone_offset_string = NULL;
        assert(postpone_event(&ev)==1);
index 1ceae1b62ca131cc4aba6d8c15f5b7d3a9aca4cd..4c10ced083badc8ce55ef280f3b0b88f5330376c 100644 (file)
@@ -6,6 +6,7 @@
 
 int main();
 static void check_need_readd_basic_test();
+static void check_need_readd_until_test();
 static void handle_args_basic_test();
 static void rm_basic_test();
 static void rm_dismiss_basic_test();
@@ -17,6 +18,7 @@ int main() {
 
        rm_basic_test();
        check_need_readd_basic_test();
+       check_need_readd_until_test();
        rm_dismiss_basic_test();
 
        clean_env();
@@ -37,7 +39,7 @@ static void check_need_readd_basic_test() {
        assert(fclose(src)==0);
 
        assert(event_name_set(&ev,"test")==1);
-       assert(event_time_set(&ev,"2000-01-01")==1);
+       assert(event_time_set(&(ev.datetime),"2000-01-01")==1);
 
        assert(1==check_need_readd(&ev));
 
@@ -66,6 +68,67 @@ static void check_need_readd_basic_test() {
        reset_env();
 }
 
+static void check_need_readd_until_test() {
+       char buf[EVENT_SERIALIZE_MAX_LENGTH];
+       struct event ev;
+       time_t target_timet;
+       struct tm *target;
+       FILE *src;
+
+       event_init(&ev);
+
+       src = fopen(global_options.file,"w");
+       assert(src!=NULL);
+
+       assert(event_name_set(&ev,"test until")==1);
+       assert(event_time_set(&(ev.datetime),"2020-01-01")==1);
+       
+       ev.options.recur = 1;
+       ev.options.recur_period = TIME_PERIOD_WEEK;
+       target_timet = 1580545370; // approx. 2020-02-01
+       target = localtime(&target_timet);
+       memcpy(&(ev.options.until),target,sizeof(struct tm));
+
+       assert(1==check_need_readd(&ev));
+
+       src = fopen(global_options.file,"r");
+       assert(src!=NULL);
+
+       memset(buf,0,EVENT_SERIALIZE_MAX_LENGTH);
+       assert(fread(buf,1,EVENT_SERIALIZE_MAX_LENGTH,src)==64);
+       assert(memcmp(buf,"[recur:1W,until:2020-02-01 00:22:50 -0800]2020-01-08:test until\n",64)==0);
+
+       assert(fclose(src)==0);
+
+       reset_env();
+       
+       src = fopen(global_options.file,"w");
+       assert(src!=NULL);
+
+       event_init(&ev);
+       
+       assert(event_name_set(&ev,"test2 until")==1);
+       assert(event_time_set(&(ev.datetime),"2020-01-01")==1);
+       ev.options.recur = 1;
+       ev.options.recur_period = TIME_PERIOD_YEAR;
+       memcpy(&(ev.options.until),target,sizeof(struct tm));
+
+       assert(1==check_need_readd(&ev));
+
+       src = fopen(global_options.file,"r");
+       assert(src!=NULL);
+       
+       memset(buf,0,EVENT_SERIALIZE_MAX_LENGTH);
+
+       assert(fread(buf,1,EVENT_SERIALIZE_MAX_LENGTH,src)==0);
+       assert(feof(src)!=0);
+       assert(fclose(src)==0);
+
+       event_free(&ev);
+
+       reset_env();
+}
+
 static void handle_args_basic_test() {
        unsigned long int offset;
        time_t start_time;
index 883e906cc48ed72787e621f3e58716f558abea96..cccc21df0f06f1926cc981b9f3821de04693aebb 100644 (file)
@@ -24,6 +24,9 @@ void reset_env() {
 }
 
 void setup_env() {
+       assert(setenv("TZ","America/Los_Angeles",1)==0);
+       tzset();
+
        srand(time(NULL));
 
        global_options.file = strdup(default_file);
diff --git a/test/unit/usage.tests.c b/test/unit/usage.tests.c
new file mode 100644 (file)
index 0000000..bc34ddd
--- /dev/null
@@ -0,0 +1,24 @@
+#include<test_utils.h>
+
+#include<usage.h>
+
+#include INCLUDE(ARGS_SRC_FILE)
+#include INCLUDE(USAGE_SRC_FILE)
+
+int main();
+static void args_usage_basic_test();
+
+int main() {
+       args_usage_basic_test();
+
+       return EXIT_SUCCESS;
+}
+
+static void args_usage_basic_test() {
+       size_t i = 0;
+
+       while(options[i].long_opt!=NULL) {
+               assert(strcmp(long_options[i].name,options[i].long_opt)==0);
+               i++;
+       }
+}