aboutsummaryrefslogtreecommitdiff
path: root/sdep-0.2/sdep.c
diff options
context:
space:
mode:
authorSebastiano Tronto <sebastiano@tronto.net>2023-05-15 18:28:45 +0200
committerSebastiano Tronto <sebastiano@tronto.net>2023-05-15 18:28:45 +0200
commit3a33fa3c7921c69efbc9beaaa922452ba2eaf271 (patch)
tree0d903c8d075752a1c4bf63eab783c702aa3557b6 /sdep-0.2/sdep.c
parent022d9c173d78c04ec2569a2394e2b04b81d60794 (diff)
downloadsdep-3a33fa3c7921c69efbc9beaaa922452ba2eaf271.tar.gz
sdep-3a33fa3c7921c69efbc9beaaa922452ba2eaf271.zip
Makefile fix
Diffstat (limited to 'sdep-0.2/sdep.c')
-rw-r--r--sdep-0.2/sdep.c277
1 files changed, 277 insertions, 0 deletions
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 @@
1/* See LICENSE file for copyright and license details. */
2
3#include <stdio.h>
4#include <stdlib.h>
5#include <string.h>
6#include <time.h>
7
8/*
9 * Maximum number of characters in a line. The rest will be truncated.
10 * Change this if you need very long lines.
11 */
12#define MAXLEN 10000
13
14/*
15 * Default date format. Anything that strftime(3) understands works, but
16 * it should determine a date completely up to the minute.
17 */
18static char *default_format = "%Y-%m-%d %H:%M";
19
20
21typedef struct Event Event;
22typedef struct EventList EventList;
23typedef struct EventNode EventNode;
24typedef struct Options Options;
25
26struct Event{
27 struct tm time;
28 char *text;
29};
30
31struct EventList {
32 EventNode *first;
33 EventNode *last;
34 int count;
35};
36
37struct EventNode {
38 Event ev;
39 EventNode *next;
40};
41
42struct Options {
43 struct tm from;
44 struct tm to;
45 char *format_in;
46 char *format_out;
47 char *separator;
48};
49
50static void add_event(struct tm, char *, EventList *);
51static int compare_tm(const void *, const void *);
52static int compare_event(const void *, const void *);
53static Options default_op(void);
54static int events_in_range(EventList *, Options, Event *);
55static char *format_line(Event, Options, char *);
56static int is_space(char);
57static void read_input(Options, EventList *);
58static Options read_op(int, char *[]);
59static void str_copy(char *, char *, int);
60static char *str_trim(char *);
61static void write_output(Options, Event *, int);
62
63
64static void
65add_event(struct tm t, char *text, EventList *evlist)
66{
67 size_t l = strlen(text)+1;
68 EventNode *next = malloc(sizeof(EventNode));
69
70 next->ev.time = t;
71 next->ev.text = malloc(l);
72 str_copy(next->ev.text, text, l);
73 next->ev.text = str_trim(next->ev.text);
74 next->next = NULL;
75
76 if (++evlist->count == 1) {
77 evlist->first = next;
78 evlist->last = next;
79 } else {
80 evlist->last->next = next;
81 evlist->last = next;
82 }
83}
84
85static int
86compare_tm(const void *v1, const void *v2)
87{
88 const struct tm *t1 = v1;
89 const struct tm *t2 = v2;
90
91 if (t1->tm_year != t2->tm_year)
92 return t1->tm_year - t2->tm_year;
93 if (t1->tm_mon != t2->tm_mon)
94 return t1->tm_mon - t2->tm_mon;
95 if (t1->tm_mday != t2->tm_mday)
96 return t1->tm_mday - t2->tm_mday;
97 if (t1->tm_hour != t2->tm_hour)
98 return t1->tm_hour - t2->tm_hour;
99 return t1->tm_min - t2->tm_min;
100}
101
102static int
103compare_event(const void *v1, const void *v2)
104{
105 const Event *ev1 = v1;
106 const Event *ev2 = v2;
107
108 return compare_tm(&ev1->time, &ev2->time);
109}
110
111static Options
112default_op(void)
113{
114 Options op;
115 time_t t_now = time(NULL);
116 struct tm *now = localtime(&t_now);
117
118 op.format_in = malloc(MAXLEN);
119 op.format_out = malloc(MAXLEN);
120 op.separator = malloc(MAXLEN);
121 strcpy(op.format_in, default_format);
122 strcpy(op.format_out, default_format);
123 strcpy(op.separator, "\t");
124 op.from = *now;
125 op.to = *now;
126
127 return op;
128}
129
130/*
131 * Saves the events in ev[] that happen between op->from and op->to in sel[]
132 * sorted by date and returns their number.
133 */
134static int
135events_in_range(EventList *evlist, Options op, Event *sel)
136{
137 EventNode *i;
138 int n = 0;
139
140 for (i = evlist->first; i != NULL; i = i->next)
141 if (compare_tm(&i->ev.time, &op.from) >= 0 &&
142 compare_tm(&i->ev.time, &op.to) <= 0)
143 sel[n++] = i->ev;
144
145 qsort(sel, n, sizeof(Event), compare_event);
146
147 return n;
148}
149
150static char *
151format_line(Event ev, Options op, char *out)
152{
153 size_t l;
154
155 strftime(out, MAXLEN, op.format_out, &ev.time);
156 l = strlen(out);
157
158 str_copy(out+l, op.separator, MAXLEN - l);
159 l = strlen(out);
160
161 str_copy(out+l, ev.text, MAXLEN - l);
162
163 return out;
164}
165
166static int
167is_space(char c)
168{
169 return c == ' ' || c == '\t';
170}
171
172static void
173read_input(Options op, EventList *evlist)
174{
175 struct tm t;
176 char line[MAXLEN], *text_ptr;
177
178 while (fgets(line, MAXLEN, stdin) != NULL)
179 if ((text_ptr = strptime(line, op.format_in, &t)) != NULL)
180 add_event(t, text_ptr, evlist);
181}
182
183static Options
184read_op(int argc, char *argv[])
185{
186 Options op = default_op();
187 int i;
188
189 /* Check for format specification.
190 * This changes the way other options are read */
191 for (i = 1; i < argc; i++) {
192 if (argv[i][0] == '+') {
193 str_copy(op.format_in, &argv[i][1], MAXLEN);
194 str_copy(op.format_out, &argv[i][1], MAXLEN);
195 }
196 }
197
198 for (i = 1; i < argc; i++) {
199 if (!strcmp(argv[i], "-v")) {
200 puts("sdep-"VERSION);
201 exit(0);
202 } else if (!strcmp(argv[i], "-d")) {
203 puts(default_format);
204 exit(0);
205 } else if (!strcmp(argv[i], "-s")) {
206 str_copy(op.separator, argv[++i], MAXLEN);
207 } else if (!strcmp(argv[i], "-f")) {
208 if (i+1 >= argc ||
209 strptime(argv[i+1], op.format_in, &op.from) == NULL)
210 op.from.tm_year = -1000000000; /* Very large number */
211 else
212 i++;
213 } else if (!strcmp(argv[i], "-t")) {
214 if (i+1 >= argc ||
215 strptime(argv[i+1], op.format_in, &op.to) == NULL)
216 op.to.tm_year = 1000000000; /* Very small number */
217 else
218 i++;
219 } else if (!strcmp(argv[i], "-w")) {
220 op.format_out = argv[++i];
221 } else if (argv[i][0] != '+' && strlen(argv[i]) != 0) {
222 fprintf(stderr, "usage: sdep [-dv]");
223 fprintf(stderr, " [+format] [-f [date]] [-t [date]]");
224 fprintf(stderr, " [-w format] [-s string]\n");
225 exit(1);
226 }
227 }
228
229 return op;
230}
231
232/*
233 * Copy up to n characters of the string str to dst and append '\0'.
234 * Suggested by NRK.
235 */
236static void
237str_copy(char *dst, char *src, int n)
238{
239 if (memccpy(dst, src, '\0', n) == NULL)
240 dst[n-1] = '\0';
241}
242
243static char *
244str_trim(char *t)
245{
246 char *s;
247
248 for (s = &t[strlen(t)-1]; s != t && is_space(*s); *s = '\0', s--);
249 for (; *t != '\0' && is_space(*t); t++);
250
251 return t;
252}
253
254static void
255write_output(Options op, Event *ev, int n)
256{
257 char outline[MAXLEN];
258 int i;
259
260 for (i = 0; i < n; i++)
261 printf("%s\n", format_line(ev[i], op, outline));
262}
263
264int
265main(int argc, char *argv[])
266{
267 Options op;
268 EventList evlist = {0};
269 Event *selected;
270
271 op = read_op(argc, argv);
272 read_input(op, &evlist);
273 selected = malloc(sizeof(Event) * evlist.count);
274 write_output(op, selected, events_in_range(&evlist, op, selected));
275
276 return 0;
277}

Generated with cgit - Back to sebastiano.tronto.net