Compare commits
10 Commits
750d450b75
...
3bf6fea43d
Author | SHA1 | Date | |
---|---|---|---|
3bf6fea43d | |||
8e4c37fe88 | |||
2e60c19b0a | |||
ed4d5cc798 | |||
a7d2a49931 | |||
7bef5ea855 | |||
28d6710c0a | |||
f69d56d91a | |||
8bdb19d0c0 | |||
58e0c8feb3 |
@ -49,6 +49,5 @@ This will run ctags on every commit.
|
|||||||
|
|
||||||
#### TODO
|
#### TODO
|
||||||
|
|
||||||
- real and automated unit testing
|
- improve and automate unit testing
|
||||||
- fix stack smashing bug (test file: failed_cal.ics)
|
|
||||||
- add cli argument that will not show ongoing events, only upcoming events
|
- add cli argument that will not show ongoing events, only upcoming events
|
||||||
|
42
src/Makefile
42
src/Makefile
@ -1,42 +0,0 @@
|
|||||||
CC = gcc
|
|
||||||
CFLAGS = -Wall -g -O0
|
|
||||||
LDFLAGS = -luuid
|
|
||||||
|
|
||||||
# List of all source files (assuming they're all in the same directory)
|
|
||||||
SRC_FILES = $(wildcard *.c)
|
|
||||||
|
|
||||||
# Generate a list of object files by replacing the .c extension with .o
|
|
||||||
OBJ_FILES = $(SRC_FILES:.c=.o)
|
|
||||||
|
|
||||||
EXECUTABLE = "icscli"
|
|
||||||
|
|
||||||
# linking
|
|
||||||
$(EXECUTABLE): $(OBJ_FILES)
|
|
||||||
$(CC) $(CFLAGS) $(OBJ_FILES) -o $(EXECUTABLE) $(LDFLAGS)
|
|
||||||
|
|
||||||
main.o: main.c
|
|
||||||
$(CC) $(CFLAGS) -c $<
|
|
||||||
|
|
||||||
# use implicit rule to compile C source files to object files
|
|
||||||
%.o: %.c %.h
|
|
||||||
$(CC) $(CFLAGS) -c $<
|
|
||||||
|
|
||||||
.PHONY:install
|
|
||||||
install: $(EXECUTABLE)
|
|
||||||
cp $(EXECUTABLE) /usr/local/bin/$(EXECUTABLE)
|
|
||||||
|
|
||||||
.PHONY:clean
|
|
||||||
clean:
|
|
||||||
-rm -vf $(EXECUTABLE) *.o
|
|
||||||
|
|
||||||
.PHONY:uninstall
|
|
||||||
uninstall:
|
|
||||||
-rm /usr/local/bin/$(EXECUTABLE)
|
|
||||||
|
|
||||||
.PHONY:test
|
|
||||||
test:
|
|
||||||
./$(EXECUTABLE)
|
|
||||||
@echo
|
|
||||||
./$(EXECUTABLE) -h
|
|
||||||
@echo
|
|
||||||
../tests/run_tests.sh
|
|
@ -5,6 +5,7 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
// buffer needs to contain a string with a strlen of 15 (format: "xxxxxxxxTxxxxxx")
|
// buffer needs to contain a string with a strlen of 15 (format: "xxxxxxxxTxxxxxx")
|
||||||
// or a strlen of 16 (format: "YYYYmmddTHHMMSSZ")
|
// or a strlen of 16 (format: "YYYYmmddTHHMMSSZ")
|
||||||
@ -15,35 +16,61 @@ void get_date(char buffer[]) {
|
|||||||
struct tm* my_tm_local = localtime (&my_unix_ts);
|
struct tm* my_tm_local = localtime (&my_unix_ts);
|
||||||
if (strlen (buffer) == 15) {
|
if (strlen (buffer) == 15) {
|
||||||
strftime (buffer, buffer_size, "%Y%m%dT%H%M%S", my_tm_local);
|
strftime (buffer, buffer_size, "%Y%m%dT%H%M%S", my_tm_local);
|
||||||
} else if (strlen(buffer) == 16) {
|
}
|
||||||
|
else if (strlen (buffer) == 16) {
|
||||||
strftime (buffer, buffer_size, "%Y%m%dT%H%M%SZ", my_tm_local);
|
strftime (buffer, buffer_size, "%Y%m%dT%H%M%SZ", my_tm_local);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 20230823T194138 -> 2023-08-23 19:41:38
|
// 20230823T194138 -> 2023-08-23 19:41:38
|
||||||
|
// 20230823T194138Z -> 2023-08-23 19:41:38
|
||||||
|
// 20241209 -> 2024-12-09
|
||||||
|
// caller has to free() the returned char array
|
||||||
|
char* pretty_date_time (char date_time[]) {
|
||||||
|
// need one more char in the char pointer for null-termination
|
||||||
|
int pdt_len = 20;
|
||||||
|
if (!strchr (date_time, 'T')) {
|
||||||
|
pdt_len = 11;
|
||||||
|
}
|
||||||
|
|
||||||
|
char* pretty_dt = malloc (pdt_len);
|
||||||
|
memset(pretty_dt, '\0', pdt_len);
|
||||||
|
int dt_counter = 0;
|
||||||
|
|
||||||
|
if (!strcmp(date_time, "")) {
|
||||||
|
return pretty_dt;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < (pdt_len-1); i++) {
|
||||||
|
if (i == 4 || i == 7) {
|
||||||
|
pretty_dt[i] = '-';
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (i == 13 || i == 16) {
|
||||||
|
pretty_dt[i] = ':';
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (date_time[dt_counter] == 'T') {
|
||||||
|
pretty_dt[i] = ' ';
|
||||||
|
} else {
|
||||||
|
pretty_dt[i] = date_time[dt_counter];
|
||||||
|
}
|
||||||
|
dt_counter++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// null-terminate string
|
||||||
|
pretty_dt[strlen(pretty_dt)] = '\0';
|
||||||
|
|
||||||
|
return pretty_dt;
|
||||||
|
}
|
||||||
|
|
||||||
void pretty_print_date_time (char date_time[]) {
|
void pretty_print_date_time (char date_time[]) {
|
||||||
// copy date_time because strtok will destroy it
|
char* pdt = pretty_date_time(date_time);
|
||||||
char date_time_copy[15] = "";
|
|
||||||
strcpy(date_time_copy, date_time);
|
|
||||||
|
|
||||||
char *date = strtok(date_time, "T");
|
printf("%s", pdt);
|
||||||
char *time = strtok(NULL, "T");
|
|
||||||
if (date == NULL) {
|
|
||||||
printf ("\nError: date points to NULL!\n");
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
printf ("%c%c%c%c-", date[0], date[1], date[2], date[3]);
|
|
||||||
printf ("%c%c-", date[4], date[5]);
|
|
||||||
printf ("%c%c", date[6], date[7]);
|
|
||||||
|
|
||||||
if (time != NULL) {
|
free(pdt);
|
||||||
printf (" %c%c:", time[0], time[1]);
|
|
||||||
printf ("%c%c:", time[2], time[3]);
|
|
||||||
printf ("%c%c", time[4], time[5]);
|
|
||||||
}
|
|
||||||
|
|
||||||
// put variable date_time back together
|
|
||||||
strcpy(date_time, date_time_copy);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void marshall_date_time (char date_time[]) {
|
void marshall_date_time (char date_time[]) {
|
||||||
@ -54,7 +81,8 @@ void marshall_date_time(char date_time[]) {
|
|||||||
if (date_time[i] != ':' && date_time[i] != '-') {
|
if (date_time[i] != ':' && date_time[i] != '-') {
|
||||||
if (date_time[i] == ' ') {
|
if (date_time[i] == ' ') {
|
||||||
transformed_string[j] = 'T';
|
transformed_string[j] = 'T';
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
transformed_string[j] = date_time[i];
|
transformed_string[j] = date_time[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -75,15 +103,18 @@ void print_end_date(char end_date[], char start_date[]) {
|
|||||||
if (strlen (end_date) == 8) {
|
if (strlen (end_date) == 8) {
|
||||||
if (time_difference == 86400) {
|
if (time_difference == 86400) {
|
||||||
return;
|
return;
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
printf (" - ");
|
printf (" - ");
|
||||||
end_uts -= 86400;
|
end_uts -= 86400;
|
||||||
char *end_date_minus_one = transform_unix_ts_to_date(end_uts);
|
char* end_date_minus_one =
|
||||||
|
transform_unix_ts_to_date (end_uts);
|
||||||
pretty_print_date_time (end_date_minus_one);
|
pretty_print_date_time (end_date_minus_one);
|
||||||
free (end_date_minus_one);
|
free (end_date_minus_one);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
// end_date is not an all day event
|
// end_date is not an all day event
|
||||||
|
|
||||||
char* end_date_chunk = strtok (end_date, "T");
|
char* end_date_chunk = strtok (end_date, "T");
|
||||||
@ -94,10 +125,13 @@ void print_end_date(char end_date[], char start_date[]) {
|
|||||||
|
|
||||||
// only print the end date if it is not the same as the start date
|
// only print the end date if it is not the same as the start date
|
||||||
if (strcmp (start_date_chunk, end_date_chunk) != 0) {
|
if (strcmp (start_date_chunk, end_date_chunk) != 0) {
|
||||||
printf("%c%c%c%c-", end_date_chunk[0], end_date_chunk[1], \
|
printf ("%c%c%c%c-", end_date_chunk[0],
|
||||||
end_date_chunk[2], end_date_chunk[3]);
|
end_date_chunk[1], end_date_chunk[2],
|
||||||
printf("%c%c-", end_date_chunk[4], end_date_chunk[5]);
|
end_date_chunk[3]);
|
||||||
printf("%c%c ", end_date_chunk[6], end_date_chunk[7]);
|
printf ("%c%c-", end_date_chunk[4],
|
||||||
|
end_date_chunk[5]);
|
||||||
|
printf ("%c%c ", end_date_chunk[6],
|
||||||
|
end_date_chunk[7]);
|
||||||
}
|
}
|
||||||
|
|
||||||
printf ("%c%c:", end_time_chunk[0], end_time_chunk[1]);
|
printf ("%c%c:", end_time_chunk[0], end_time_chunk[1]);
|
||||||
@ -138,7 +172,8 @@ char *get_tz() {
|
|||||||
if (bytes_read != -1) {
|
if (bytes_read != -1) {
|
||||||
// Null-terminate the string
|
// Null-terminate the string
|
||||||
timezone_path[bytes_read] = '\0';
|
timezone_path[bytes_read] = '\0';
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
perror ("readlink");
|
perror ("readlink");
|
||||||
exit (1);
|
exit (1);
|
||||||
}
|
}
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
|
|
||||||
void get_date(char buffer[]);
|
void get_date(char buffer[]);
|
||||||
char *get_tz();
|
char *get_tz();
|
||||||
|
char* pretty_date_time(char date_time[]);
|
||||||
void pretty_print_date_time(char date_time[]);
|
void pretty_print_date_time(char date_time[]);
|
||||||
void marshall_date_time(char date_time[]);
|
void marshall_date_time(char date_time[]);
|
||||||
void print_end_date(char end_date[], char start_date[]);
|
void print_end_date(char end_date[], char start_date[]);
|
||||||
|
5
src/meson.build
Normal file
5
src/meson.build
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
project('ics_cli', 'c')
|
||||||
|
|
||||||
|
executable('icscli', 'main.c', 'cli_arg_parsing.c', 'date_time_handling.c', 'insert_event.c', \
|
||||||
|
'list_handling.c', 'parse_ics.c', 'read_until_nl.c', 'read_until_string.c', 'seek_string_a.c', \
|
||||||
|
'string_handling.c', link_args : '-luuid', install: true, install_dir: '/usr/local/bin')
|
@ -1,16 +0,0 @@
|
|||||||
CC = gcc
|
|
||||||
CFLAGS = -Wall -g -O0
|
|
||||||
|
|
||||||
test_parse_ics_file:
|
|
||||||
$(CC) $(CFLAGS) test_parse_ics_file.c ../src/parse_ics.c ../src/string_handling.c ../src/list_handling.c ../src/date_time_handling.c ../src/read_until_string.c ../src/read_until_nl.c -o test_parse_ics_file.out
|
|
||||||
./test_parse_ics_file.out
|
|
||||||
|
|
||||||
test_print_upcoming:
|
|
||||||
$(CC) $(CFLAGS) test_print_upcoming.c ../src/parse_ics.c ../src/string_handling.c ../src/list_handling.c ../src/date_time_handling.c ../src/read_until_string.c ../src/read_until_nl.c -o test_print_upcoming.out
|
|
||||||
|
|
||||||
test_pretty_print_date_time:
|
|
||||||
$(CC) $(CFLAGS) test_pretty_print_date_time.c ../src/string_handling.c ../src/date_time_handling.c ../src/read_until_string.c ../src/read_until_nl.c -o test_pretty_print_date_time.out
|
|
||||||
|
|
||||||
.PHONY:clean
|
|
||||||
clean:
|
|
||||||
-rm -vf *.out
|
|
16
unit-tests/meson.build
Normal file
16
unit-tests/meson.build
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
project('ics_cli', 'c')
|
||||||
|
|
||||||
|
t1e = executable('test_print_upcoming', 'test_print_upcoming.c', '../src/parse_ics.c', '../src/string_handling.c', \
|
||||||
|
'../src/list_handling.c', '../src/date_time_handling.c', '../src/read_until_string.c', '../src/read_until_nl.c')
|
||||||
|
|
||||||
|
test('test print_upcoming', t1e)
|
||||||
|
|
||||||
|
t2e = executable('test_pretty_print_date_time', 'test_pretty_print_date_time.c', '../src/string_handling.c', \
|
||||||
|
'../src/date_time_handling.c', '../src/read_until_string.c', '../src/read_until_nl.c')
|
||||||
|
|
||||||
|
test('test pretty_print_date_time', t2e)
|
||||||
|
|
||||||
|
t3e = executable('test_parse_ics_file', 'test_parse_ics_file.c', '../src/parse_ics.c', '../src/string_handling.c', '../src/list_handling.c', \
|
||||||
|
'../src/date_time_handling.c', '../src/read_until_string.c', '../src/read_until_nl.c')
|
||||||
|
|
||||||
|
test('test parse_ics_file', t3e)
|
@ -6,7 +6,9 @@ int main() {
|
|||||||
// initialize empty list
|
// initialize empty list
|
||||||
struct event *head = NULL;
|
struct event *head = NULL;
|
||||||
|
|
||||||
parse_ics_file("../tests/calendar.ics", &head);
|
parse_ics_file("../../tests/calendar.ics", &head);
|
||||||
|
|
||||||
print_list(head);
|
parse_ics_file("../../tests/failed_cal.ics", &head);
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,38 @@
|
|||||||
#include "../src/date_time_handling.h"
|
#include "../src/date_time_handling.h"
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
int main() {
|
int main() {
|
||||||
|
// 1
|
||||||
|
char* pdt = pretty_date_time("20251215T080000Z");
|
||||||
|
|
||||||
|
assert(!strcmp(pdt, "2025-12-15 08:00:00"));
|
||||||
|
|
||||||
|
free(pdt);
|
||||||
|
|
||||||
|
// 2
|
||||||
|
char* pdt2 = pretty_date_time("20251215T080000");
|
||||||
|
|
||||||
|
assert(!strcmp(pdt2, "2025-12-15 08:00:00"));
|
||||||
|
|
||||||
|
free(pdt2);
|
||||||
|
|
||||||
|
// 3
|
||||||
|
char* pdt3 = pretty_date_time("");
|
||||||
|
|
||||||
|
assert(!strcmp(pdt3, ""));
|
||||||
|
|
||||||
|
free(pdt3);
|
||||||
|
|
||||||
|
// 4
|
||||||
|
char* pdt4 = pretty_date_time("20251215");
|
||||||
|
|
||||||
|
assert(!strcmp(pdt4, "2025-12-15"));
|
||||||
|
|
||||||
|
free(pdt4);
|
||||||
|
|
||||||
|
// 5
|
||||||
char current_date[] = "20240710T103000";
|
char current_date[] = "20240710T103000";
|
||||||
|
|
||||||
printf("current_date: %s\n", current_date);
|
printf("current_date: %s\n", current_date);
|
||||||
@ -11,4 +42,9 @@ int main() {
|
|||||||
|
|
||||||
printf("\n\ncurrent_date: %s\n", current_date);
|
printf("\n\ncurrent_date: %s\n", current_date);
|
||||||
printf("strlen(current_date): %ld\n", strlen(current_date));
|
printf("strlen(current_date): %ld\n", strlen(current_date));
|
||||||
|
|
||||||
|
pretty_print_date_time("20251215T080000Z");
|
||||||
|
printf("\n");
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -6,11 +6,19 @@ int main() {
|
|||||||
// initialize empty list
|
// initialize empty list
|
||||||
struct event *head = NULL;
|
struct event *head = NULL;
|
||||||
|
|
||||||
|
// 1
|
||||||
|
printf("\nTesting tests/failed_cal.ics:\n\n");
|
||||||
char *current_date = "20240710T113000";
|
char *current_date = "20240710T113000";
|
||||||
|
|
||||||
printf("DEBUG - current_date: %s\n\n", current_date);
|
printf("DEBUG - current_date: %s\n\n", current_date);
|
||||||
|
|
||||||
parse_ics_file("/home/bf/.local/share/evolution/calendar/system/calendar.ics", &head);
|
parse_ics_file("../../tests/failed_cal.ics", &head);
|
||||||
|
|
||||||
|
print_upcoming(head, current_date, 0);
|
||||||
|
|
||||||
|
// 2
|
||||||
|
printf("\nTesting tests/calendar.ics:\n\n");
|
||||||
|
parse_ics_file("../../tests/calendar.ics", &head);
|
||||||
|
|
||||||
print_upcoming(head, current_date, 0);
|
print_upcoming(head, current_date, 0);
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user