From 3a33fa3c7921c69efbc9beaaa922452ba2eaf271 Mon Sep 17 00:00:00 2001 From: Sebastiano Tronto Date: Mon, 15 May 2023 18:28:45 +0200 Subject: Makefile fix --- sdep-0.2/sdep.c | 277 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 277 insertions(+) create mode 100644 sdep-0.2/sdep.c (limited to 'sdep-0.2/sdep.c') diff --git a/sdep-0.2/sdep.c b/sdep-0.2/sdep.c new file mode 100644 index 0000000..629387b --- /dev/null +++ b/sdep-0.2/sdep.c @@ -0,0 +1,277 @@ +/* See LICENSE file for copyright and license details. */ + +#include +#include +#include +#include + +/* + * Maximum number of characters in a line. The rest will be truncated. + * Change this if you need very long lines. + */ +#define MAXLEN 10000 + +/* + * Default date format. Anything that strftime(3) understands works, but + * it should determine a date completely up to the minute. + */ +static char *default_format = "%Y-%m-%d %H:%M"; + + +typedef struct Event Event; +typedef struct EventList EventList; +typedef struct EventNode EventNode; +typedef struct Options Options; + +struct Event{ + struct tm time; + char *text; +}; + +struct EventList { + EventNode *first; + EventNode *last; + int count; +}; + +struct EventNode { + Event ev; + EventNode *next; +}; + +struct Options { + struct tm from; + struct tm to; + char *format_in; + char *format_out; + char *separator; +}; + +static void add_event(struct tm, char *, EventList *); +static int compare_tm(const void *, const void *); +static int compare_event(const void *, const void *); +static Options default_op(void); +static int events_in_range(EventList *, Options, Event *); +static char *format_line(Event, Options, char *); +static int is_space(char); +static void read_input(Options, EventList *); +static Options read_op(int, char *[]); +static void str_copy(char *, char *, int); +static char *str_trim(char *); +static void write_output(Options, Event *, int); + + +static void +add_event(struct tm t, char *text, EventList *evlist) +{ + size_t l = strlen(text)+1; + EventNode *next = malloc(sizeof(EventNode)); + + next->ev.time = t; + next->ev.text = malloc(l); + str_copy(next->ev.text, text, l); + next->ev.text = str_trim(next->ev.text); + next->next = NULL; + + if (++evlist->count == 1) { + evlist->first = next; + evlist->last = next; + } else { + evlist->last->next = next; + evlist->last = next; + } +} + +static int +compare_tm(const void *v1, const void *v2) +{ + const struct tm *t1 = v1; + const struct tm *t2 = v2; + + if (t1->tm_year != t2->tm_year) + return t1->tm_year - t2->tm_year; + if (t1->tm_mon != t2->tm_mon) + return t1->tm_mon - t2->tm_mon; + if (t1->tm_mday != t2->tm_mday) + return t1->tm_mday - t2->tm_mday; + if (t1->tm_hour != t2->tm_hour) + return t1->tm_hour - t2->tm_hour; + return t1->tm_min - t2->tm_min; +} + +static int +compare_event(const void *v1, const void *v2) +{ + const Event *ev1 = v1; + const Event *ev2 = v2; + + return compare_tm(&ev1->time, &ev2->time); +} + +static Options +default_op(void) +{ + Options op; + time_t t_now = time(NULL); + struct tm *now = localtime(&t_now); + + op.format_in = malloc(MAXLEN); + op.format_out = malloc(MAXLEN); + op.separator = malloc(MAXLEN); + strcpy(op.format_in, default_format); + strcpy(op.format_out, default_format); + strcpy(op.separator, "\t"); + op.from = *now; + op.to = *now; + + return op; +} + +/* + * Saves the events in ev[] that happen between op->from and op->to in sel[] + * sorted by date and returns their number. + */ +static int +events_in_range(EventList *evlist, Options op, Event *sel) +{ + EventNode *i; + int n = 0; + + for (i = evlist->first; i != NULL; i = i->next) + if (compare_tm(&i->ev.time, &op.from) >= 0 && + compare_tm(&i->ev.time, &op.to) <= 0) + sel[n++] = i->ev; + + qsort(sel, n, sizeof(Event), compare_event); + + return n; +} + +static char * +format_line(Event ev, Options op, char *out) +{ + size_t l; + + strftime(out, MAXLEN, op.format_out, &ev.time); + l = strlen(out); + + str_copy(out+l, op.separator, MAXLEN - l); + l = strlen(out); + + str_copy(out+l, ev.text, MAXLEN - l); + + return out; +} + +static int +is_space(char c) +{ + return c == ' ' || c == '\t'; +} + +static void +read_input(Options op, EventList *evlist) +{ + struct tm t; + char line[MAXLEN], *text_ptr; + + while (fgets(line, MAXLEN, stdin) != NULL) + if ((text_ptr = strptime(line, op.format_in, &t)) != NULL) + add_event(t, text_ptr, evlist); +} + +static Options +read_op(int argc, char *argv[]) +{ + Options op = default_op(); + int i; + + /* Check for format specification. + * This changes the way other options are read */ + for (i = 1; i < argc; i++) { + if (argv[i][0] == '+') { + str_copy(op.format_in, &argv[i][1], MAXLEN); + str_copy(op.format_out, &argv[i][1], MAXLEN); + } + } + + for (i = 1; i < argc; i++) { + if (!strcmp(argv[i], "-v")) { + puts("sdep-"VERSION); + exit(0); + } else if (!strcmp(argv[i], "-d")) { + puts(default_format); + exit(0); + } else if (!strcmp(argv[i], "-s")) { + str_copy(op.separator, argv[++i], MAXLEN); + } else if (!strcmp(argv[i], "-f")) { + if (i+1 >= argc || + strptime(argv[i+1], op.format_in, &op.from) == NULL) + op.from.tm_year = -1000000000; /* Very large number */ + else + i++; + } else if (!strcmp(argv[i], "-t")) { + if (i+1 >= argc || + strptime(argv[i+1], op.format_in, &op.to) == NULL) + op.to.tm_year = 1000000000; /* Very small number */ + else + i++; + } else if (!strcmp(argv[i], "-w")) { + op.format_out = argv[++i]; + } else if (argv[i][0] != '+' && strlen(argv[i]) != 0) { + fprintf(stderr, "usage: sdep [-dv]"); + fprintf(stderr, " [+format] [-f [date]] [-t [date]]"); + fprintf(stderr, " [-w format] [-s string]\n"); + exit(1); + } + } + + return op; +} + +/* + * Copy up to n characters of the string str to dst and append '\0'. + * Suggested by NRK. + */ +static void +str_copy(char *dst, char *src, int n) +{ + if (memccpy(dst, src, '\0', n) == NULL) + dst[n-1] = '\0'; +} + +static char * +str_trim(char *t) +{ + char *s; + + for (s = &t[strlen(t)-1]; s != t && is_space(*s); *s = '\0', s--); + for (; *t != '\0' && is_space(*t); t++); + + return t; +} + +static void +write_output(Options op, Event *ev, int n) +{ + char outline[MAXLEN]; + int i; + + for (i = 0; i < n; i++) + printf("%s\n", format_line(ev[i], op, outline)); +} + +int +main(int argc, char *argv[]) +{ + Options op; + EventList evlist = {0}; + Event *selected; + + op = read_op(argc, argv); + read_input(op, &evlist); + selected = malloc(sizeof(Event) * evlist.count); + write_output(op, selected, events_in_range(&evlist, op, selected)); + + return 0; +} -- cgit v1.3