Introduction
Introduction Statistics Contact Development Disclaimer Help
ics2tsv.c - ics2txt - convert icalendar .ics file to plain text
git clone git://bitreich.org/ics2txt git://enlrupgkhuxnvlhsf6lc3fziv5h2hhfrinws…
Log
Files
Refs
Tags
README
---
ics2tsv.c (4611B)
---
1 #include <errno.h>
2 #include <stdio.h>
3 #include <stdlib.h>
4 #include <string.h>
5 #include <strings.h>
6 #include <time.h>
7 #include <unistd.h>
8 #include "ical.h"
9 #include "util.h"
10
11 #ifndef __OpenBSD__
12 #define pledge(...) 0
13 #endif
14
15 #define FIELDS_MAX 128
16
17 typedef struct Field Field;
18 typedef struct Block Block;
19
20 struct Field {
21 char *key;
22 char *value;
23 };
24
25 struct Block {
26 time_t beg, end;
27 char *fields[FIELDS_MAX];
28 };
29
30 static int flag_header = 1;
31 static char default_fields[] = "SUMMARY,DESCRIPTION,CATEGORIES,LOCATION";
32 static char *flag_sep = ",";
33 static char *flag_timefmt = NULL;
34 static char *flag_fields = default_fields;
35 static char *fields[FIELDS_MAX];
36 static Block block;
37
38 static int
39 fn_field_name(IcalParser *p, char *name)
40 {
41 (void)p;
42 (void)name;
43
44 return 0;
45 }
46
47 static int
48 fn_block_begin(IcalParser *p, char *name)
49 {
50 (void)p;
51 (void)name;
52
53 if (p->blocktype == ICAL_BLOCK_OTHER)
54 return 0;
55
56 memset(&block, 0, sizeof block);
57 return 0;
58 }
59
60 static int
61 fn_block_end(IcalParser *p, char *name)
62 {
63 (void)name;
64
65 if (p->blocktype == ICAL_BLOCK_OTHER)
66 return 0;
67 fputs(p->current->name, stdout);
68
69 /* printing dates with %s is much much slower than %lld */
70 if (flag_timefmt == NULL) {
71 printf("\t%lld\t%lld", block.beg, block.end);
72 } else {
73 char buf[128];
74 struct tm tm = {0};
75
76 localtime_r(&block.beg, &tm);
77 strftime(buf, sizeof buf, flag_timefmt, &tm);
78 printf("\t%s", buf);
79
80 localtime_r(&block.end, &tm);
81 strftime(buf, sizeof buf, flag_timefmt, &tm);
82 printf("\t%s", buf);
83 }
84
85 /* reserved for recurring events */
86 printf("\t%s", "(null)");
87
88 for (int i = 0; fields[i] != NULL; i++) {
89 fputc('\t', stdout);
90 if (block.fields[i] != NULL)
91 fputs(block.fields[i], stdout);
92 }
93 printf("\n");
94 return 0;
95 }
96
97 static int
98 fn_param_value(IcalParser *p, char *name, char *value)
99 {
100 (void)p;
101 (void)name;
102 (void)value;
103
104 return 0;
105 }
106
107 static int
108 fn_field_value(IcalParser *p, char *name, char *value)
109 {
110 static char *map[][2] = {
111 [ICAL_BLOCK_VEVENT] = { "DTSTART", "DTEND"…
112 [ICAL_BLOCK_VTODO] = { NULL, "DUE" },
113 [ICAL_BLOCK_VJOURNAL] = { "DTSTAMP", NULL …
114 [ICAL_BLOCK_VFREEBUSY] = { "DTSTART", "DTE…
115 [ICAL_BLOCK_VALARM] = { "DTSTART", NULL },
116 [ICAL_BLOCK_OTHER] = { NULL, NULL },
117 };
118 char *beg, *end;
119
120 /* fill the date fields */
121 beg = map[p->blocktype][0];
122 if (beg != NULL && strcasecmp(name, beg) == 0)
123 if (ical_get_time(p, value, &block.beg) != 0)
124 return -1;
125 end = map[p->blocktype][1];
126 if (end != NULL && strcasecmp(name, end) == 0)
127 if (ical_get_time(p, value, &block.end) != 0)
128 return -1;
129
130 /* fill text fields as requested with -o F1,F2... */
131 for (int i = 0; fields[i] != NULL; i++) {
132 if (strcasecmp(name, fields[i]) == 0) {
133 if (block.fields[i] == NULL) {
134 if ((block.fields[i] = strdup(value)) ==…
135 return ical_err(p, strerror(errn…
136 } else {
137 if (strappend(&block.fields[i], flag_sep…
138 strappend(&block.fields[i], value) =…
139 return ical_err(p, strerror(errn…
140 }
141 }
142 }
143
144 return 0;
145 }
146
147 static void
148 usage(void)
149 {
150 fprintf(stderr,"usage: %s [-1] [-f fields] [-s separator] [-t ti…
151 " [file...]\n", arg0);
152 exit(1);
153 }
154
155 int
156 main(int argc, char **argv)
157 {
158 IcalParser p = {0};
159 int c;
160
161 arg0 = *argv;
162
163 if (pledge("stdio rpath", "") < 0)
164 err(1, "pledge: %s", strerror(errno));
165
166 p.fn_field_name = fn_field_name;
167 p.fn_block_begin = fn_block_begin;
168 p.fn_block_end = fn_block_end;
169 p.fn_param_value = fn_param_value;
170 p.fn_field_value = fn_field_value;
171
172 while ((c = getopt(argc, argv, "01f:s:t:")) != -1) {
173 switch (c) {
174 case '0':
175 flag_header = 0;
176 break;
177 case '1':
178 flag_header = 1;
179 break;
180 case 'f':
181 flag_fields = optarg;
182 break;
183 case 's':
184 flag_sep = optarg;
185 break;
186 case 't':
187 flag_timefmt = optarg;
188 break;
189 case '?':
190 usage();
191 break;
192 }
193 }
194 argv += optind;
195 argc -= optind;
196
197 if (strsplit(flag_fields, fields, LEN(fields), ",") < 0)
198 err(1, "too many fields specified with -f flag");
199
200 if (flag_header) {
201 printf("%s\t%s\t%s\t%s", "TYPE", "START", "END", "RECUR"…
202 for (size_t i = 0; fields[i] != NULL; i++)
203 printf("\t%s", fields[i]);
204 fputc('\n', stdout);
205 }
206
207 if (*argv == NULL || strcmp(*argv, "-") == 0) {
208 debug("converting *stdin*");
209 if (ical_parse(&p, stdin) < 0)
210 err(1, "parsing *stdin*:%d: %s", p.linenum, p.er…
211 }
212 for (; *argv != NULL; argv++, argc--) {
213 FILE *fp;
214 debug("converting \"%s\"", *argv);
215 if ((fp = fopen(*argv, "r")) == NULL)
216 err(1, "opening %s: %s", *argv, strerror(errno));
217 if (ical_parse(&p, fp) < 0)
218 err(1, "parsing %s:%d: %s", *argv, p.linenum, p.…
219 fclose(fp);
220 }
221
222 return 0;
223 }
You are viewing proxied material from bitreich.org. The copyright of proxied material belongs to its original authors. Any comments or complaints in relation to proxied material should be directed to the original authors of the content concerned. Please see the disclaimer for more details.