ev
events
+!completions/ev
+
# build objects
*.o
*.log
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 \
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 \
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:
--- /dev/null
+_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
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])
# 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])
};
struct event_options {
- unsigned int duration;
- enum time_period duration_period;
-
unsigned int recur;
enum time_period recur_period;
+
+ struct tm until;
};
struct event {
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
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
--- /dev/null
+.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.
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;
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));
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;
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;
+}
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}
};
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),
)<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;
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;
+++ /dev/null
-#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;
-}
--- /dev/null
+#include<event.h>
+
+void event_free(const struct event *p) {
+ if(p->name!=NULL) { free(p->name); }
+ if(p->place!=NULL) { free(p->place); }
+}
--- /dev/null
+#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));
+}
+
--- /dev/null
+#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;
+}
--- /dev/null
+#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;
+}
--- /dev/null
+#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';
+ }
+}
--- /dev/null
+#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;
+}
--- /dev/null
+#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;
+}
--- /dev/null
+#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;
+}
}
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) &&
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;
+++ /dev/null
-#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;
-}
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;
}
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;
}
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"
);
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;
}
--- /dev/null
+#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;
+}
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;
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(
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;
#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");
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++;
+ }
+}
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
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 \
$(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 \
-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) \
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 \
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 \
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 \
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"
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();
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();
+}
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();
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();
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);
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();
}
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);
+#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();
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);
}
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);
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);
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);
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);
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);
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);
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"));
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));
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() {
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);
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);
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);
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);
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);
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);
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);
}
#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);
+}
#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"));
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();
+}
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);
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();
rm_basic_test();
check_need_readd_basic_test();
+ check_need_readd_until_test();
rm_dismiss_basic_test();
clean_env();
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));
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;
}
void setup_env() {
+ assert(setenv("TZ","America/Los_Angeles",1)==0);
+ tzset();
+
srand(time(NULL));
global_options.file = strdup(default_file);
--- /dev/null
+#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++;
+ }
+}