itsv2agenda.c - ics2txt - convert icalendar .ics file to plain text Err bitreich.org 70 hgit clone git://bitreich.org/ics2txt git://enlrupgkhuxnvlhsf6lc3fziv5h2hhfrinws65d7roiv6bfj7d652fid.onion/ics2txt URL:git://bitreich.org/ics2txt git://enlrupgkhuxnvlhsf6lc3fziv5h2hhfrinws65d7roiv6bfj7d652fid.onion/ics2txt bitreich.org 70 1Log /scm/ics2txt/log.gph bitreich.org 70 1Files /scm/ics2txt/files.gph bitreich.org 70 1Refs /scm/ics2txt/refs.gph bitreich.org 70 1Tags /scm/ics2txt/tag bitreich.org 70 1README /scm/ics2txt/file/README.md.gph bitreich.org 70 i--- Err bitreich.org 70 itsv2agenda.c (5483B) Err bitreich.org 70 i--- Err bitreich.org 70 i 1 #include Err bitreich.org 70 i 2 #include Err bitreich.org 70 i 3 #include Err bitreich.org 70 i 4 #include Err bitreich.org 70 i 5 #include Err bitreich.org 70 i 6 #include Err bitreich.org 70 i 7 #include Err bitreich.org 70 i 8 #include Err bitreich.org 70 i 9 #include Err bitreich.org 70 i 10 #include "util.h" Err bitreich.org 70 i 11 Err bitreich.org 70 i 12 #ifndef __OpenBSD__ Err bitreich.org 70 i 13 #define pledge(...) 0 Err bitreich.org 70 i 14 #endif Err bitreich.org 70 i 15 Err bitreich.org 70 i 16 enum { Err bitreich.org 70 i 17 FIELD_TYPE, Err bitreich.org 70 i 18 FIELD_BEG, Err bitreich.org 70 i 19 FIELD_END, Err bitreich.org 70 i 20 FIELD_RECUR, Err bitreich.org 70 i 21 FIELD_OTHER, Err bitreich.org 70 i 22 FIELD_MAX = 128, Err bitreich.org 70 i 23 }; Err bitreich.org 70 i 24 Err bitreich.org 70 i 25 typedef struct { Err bitreich.org 70 i 26 struct tm beg, end; Err bitreich.org 70 i 27 char *fieldnames[FIELD_MAX]; Err bitreich.org 70 i 28 size_t fieldnum; Err bitreich.org 70 i 29 size_t linenum; Err bitreich.org 70 i 30 } AgendaCtx; Err bitreich.org 70 i 31 Err bitreich.org 70 i 32 static time_t flag_from = INT64_MIN; Err bitreich.org 70 i 33 static time_t flag_to = INT64_MAX; Err bitreich.org 70 i 34 Err bitreich.org 70 i 35 static void Err bitreich.org 70 i 36 print_date(struct tm *tm) Err bitreich.org 70 i 37 { Err bitreich.org 70 i 38 if (tm == NULL) { Err bitreich.org 70 i 39 fprintf(stdout, "%11s", ""); Err bitreich.org 70 i 40 } else { Err bitreich.org 70 i 41 char buf[128]; Err bitreich.org 70 i 42 if (strftime(buf, sizeof buf, "%Y-%m-%d", tm) == 0) Err bitreich.org 70 i 43 err(1, "strftime: %s", strerror(errno)); Err bitreich.org 70 i 44 fprintf(stdout, "%s ", buf); Err bitreich.org 70 i 45 } Err bitreich.org 70 i 46 } Err bitreich.org 70 i 47 Err bitreich.org 70 i 48 static void Err bitreich.org 70 i 49 print_time(struct tm *tm) Err bitreich.org 70 i 50 { Err bitreich.org 70 i 51 if (tm == NULL) { Err bitreich.org 70 i 52 fprintf(stdout, "%5s ", ""); Err bitreich.org 70 i 53 } else { Err bitreich.org 70 i 54 char buf[128]; Err bitreich.org 70 i 55 if (strftime(buf, sizeof buf, "%H:%M", tm) == 0) Err bitreich.org 70 i 56 err(1, "strftime: %s", strerror(errno)); Err bitreich.org 70 i 57 fprintf(stdout, "%5s ", buf); Err bitreich.org 70 i 58 } Err bitreich.org 70 i 59 } Err bitreich.org 70 i 60 Err bitreich.org 70 i 61 static void Err bitreich.org 70 i 62 print_header0(struct tm *old, struct tm *new) Err bitreich.org 70 i 63 { Err bitreich.org 70 i 64 int same; Err bitreich.org 70 i 65 Err bitreich.org 70 i 66 same = (old->tm_year == new->tm_year && old->tm_mon == new->tm_mon && Err bitreich.org 70 i 67 old->tm_mday == new->tm_mday); Err bitreich.org 70 i 68 print_date(same ? NULL : new); Err bitreich.org 70 i 69 print_time(new); Err bitreich.org 70 i 70 } Err bitreich.org 70 i 71 Err bitreich.org 70 i 72 static void Err bitreich.org 70 i 73 print_header1(struct tm *beg, struct tm *end) Err bitreich.org 70 i 74 { Err bitreich.org 70 i 75 int same; Err bitreich.org 70 i 76 Err bitreich.org 70 i 77 same = (beg->tm_year == end->tm_year && beg->tm_mon == end->tm_mon && Err bitreich.org 70 i 78 beg->tm_mday == end->tm_mday); Err bitreich.org 70 i 79 print_date(same ? NULL : end); Err bitreich.org 70 i 80 Err bitreich.org 70 i 81 same = (beg->tm_hour == end->tm_hour && beg->tm_min == end->tm_min); Err bitreich.org 70 i 82 print_time(same ? NULL : end); Err bitreich.org 70 i 83 } Err bitreich.org 70 i 84 Err bitreich.org 70 i 85 static void Err bitreich.org 70 i 86 print_headerN(void) Err bitreich.org 70 i 87 { Err bitreich.org 70 i 88 print_date(NULL); Err bitreich.org 70 i 89 print_time(NULL); Err bitreich.org 70 i 90 } Err bitreich.org 70 i 91 Err bitreich.org 70 i 92 static void Err bitreich.org 70 i 93 print_header(AgendaCtx *ctx, struct tm *beg, struct tm *end, size_t *num) Err bitreich.org 70 i 94 { Err bitreich.org 70 i 95 switch ((*num)++) { Err bitreich.org 70 i 96 case 0: Err bitreich.org 70 i 97 print_header0(&ctx->beg, beg); Err bitreich.org 70 i 98 break; Err bitreich.org 70 i 99 case 1: Err bitreich.org 70 i 100 print_header1(beg, end); Err bitreich.org 70 i 101 break; Err bitreich.org 70 i 102 default: Err bitreich.org 70 i 103 print_headerN(); Err bitreich.org 70 i 104 break; Err bitreich.org 70 i 105 } Err bitreich.org 70 i 106 } Err bitreich.org 70 i 107 Err bitreich.org 70 i 108 static void Err bitreich.org 70 i 109 unescape(char const *s, char *d) Err bitreich.org 70 i 110 { Err bitreich.org 70 i 111 for (; *s != '\0'; s++) { Err bitreich.org 70 i 112 if (*s == '\\') { Err bitreich.org 70 i 113 s++; Err bitreich.org 70 i 114 *d++ = (*s == 'n') ? '\n' : (*s == 't') ? ' ' : *s; Err bitreich.org 70 i 115 } else { Err bitreich.org 70 i 116 if (*s == '\\') Err bitreich.org 70 i 117 debug("s='%c'", *s); Err bitreich.org 70 i 118 *d++ = *s; Err bitreich.org 70 i 119 } Err bitreich.org 70 i 120 } Err bitreich.org 70 i 121 *d = '\0'; Err bitreich.org 70 i 122 } Err bitreich.org 70 i 123 Err bitreich.org 70 i 124 static void Err bitreich.org 70 i 125 print_row(AgendaCtx *ctx, char *s, struct tm *beg, struct tm *end, size_t *num) Err bitreich.org 70 i 126 { Err bitreich.org 70 i 127 unescape(s, s); Err bitreich.org 70 i 128 Err bitreich.org 70 i 129 print_header(ctx, beg, end, num); Err bitreich.org 70 i 130 for (size_t i, n = 0; *s != '\0'; s++) { Err bitreich.org 70 i 131 switch (*s) { Err bitreich.org 70 i 132 case '\n': Err bitreich.org 70 i 133 newline: Err bitreich.org 70 i 134 fputc('\n', stdout); Err bitreich.org 70 i 135 print_header(ctx, beg, end, num); Err bitreich.org 70 i 136 fputs(": ", stdout); Err bitreich.org 70 i 137 n = 0; Err bitreich.org 70 i 138 break; Err bitreich.org 70 i 139 case ' ': Err bitreich.org 70 i 140 case '\t': Err bitreich.org 70 i 141 i = strcspn(s + 1, " \t\n"); Err bitreich.org 70 i 142 if (n + i > 70) Err bitreich.org 70 i 143 goto newline; Err bitreich.org 70 i 144 fputc(' ', stdout); Err bitreich.org 70 i 145 n++; Err bitreich.org 70 i 146 break; Err bitreich.org 70 i 147 default: Err bitreich.org 70 i 148 fputc(*s, stdout); Err bitreich.org 70 i 149 n++; Err bitreich.org 70 i 150 } Err bitreich.org 70 i 151 } Err bitreich.org 70 i 152 fputc('\n', stdout); Err bitreich.org 70 i 153 } Err bitreich.org 70 i 154 Err bitreich.org 70 i 155 static void Err bitreich.org 70 i 156 print(AgendaCtx *ctx, char **fields) Err bitreich.org 70 i 157 { Err bitreich.org 70 i 158 struct tm beg = {0}, end = {0}; Err bitreich.org 70 i 159 time_t t; Err bitreich.org 70 i 160 char const *e; Err bitreich.org 70 i 161 Err bitreich.org 70 i 162 t = strtonum(fields[FIELD_BEG], INT64_MIN, INT64_MAX, &e); Err bitreich.org 70 i 163 if (e != NULL) Err bitreich.org 70 i 164 err(1, "start time %s is %s", fields[FIELD_BEG], e); Err bitreich.org 70 i 165 if (t > flag_to) Err bitreich.org 70 i 166 return; Err bitreich.org 70 i 167 localtime_r(&t, &beg); Err bitreich.org 70 i 168 Err bitreich.org 70 i 169 t = strtonum(fields[FIELD_END], INT64_MIN, INT64_MAX, &e); Err bitreich.org 70 i 170 if (e != NULL) Err bitreich.org 70 i 171 err(1, "end time %s is %s", fields[FIELD_END], e); Err bitreich.org 70 i 172 if (t < flag_from) Err bitreich.org 70 i 173 return; Err bitreich.org 70 i 174 localtime_r(&t, &end); Err bitreich.org 70 i 175 Err bitreich.org 70 i 176 fputc('\n', stdout); Err bitreich.org 70 i 177 for (size_t i = FIELD_OTHER, row = 0; i < ctx->fieldnum; i++) { Err bitreich.org 70 i 178 if (fields[i][strspn(fields[i], " \\n")] == '\0') Err bitreich.org 70 i 179 continue; Err bitreich.org 70 i 180 print_row(ctx, fields[i], &beg, &end, &row); Err bitreich.org 70 i 181 } Err bitreich.org 70 i 182 Err bitreich.org 70 i 183 ctx->beg = beg; Err bitreich.org 70 i 184 ctx->end = end; Err bitreich.org 70 i 185 } Err bitreich.org 70 i 186 Err bitreich.org 70 i 187 static void Err bitreich.org 70 i 188 tsv2agenda(FILE *fp) Err bitreich.org 70 i 189 { Err bitreich.org 70 i 190 AgendaCtx ctx = {0}; Err bitreich.org 70 i 191 char *line = NULL; Err bitreich.org 70 i 192 size_t sz1 = 0, sz2 = 0; Err bitreich.org 70 i 193 Err bitreich.org 70 i 194 if (ctx.linenum == 0) { Err bitreich.org 70 i 195 char *fields[FIELD_MAX]; Err bitreich.org 70 i 196 Err bitreich.org 70 i 197 ctx.linenum++; Err bitreich.org 70 i 198 getline(&line, &sz1, fp); Err bitreich.org 70 i 199 if (ferror(fp)) Err bitreich.org 70 i 200 err(1, "reading stdin: %s", strerror(errno)); Err bitreich.org 70 i 201 if (feof(fp)) Err bitreich.org 70 i 202 err(1, "empty input"); Err bitreich.org 70 i 203 strchomp(line); Err bitreich.org 70 i 204 ctx.fieldnum = strsplit(line, fields, FIELD_MAX, "\t"); Err bitreich.org 70 i 205 if (ctx.fieldnum == FIELD_MAX) Err bitreich.org 70 i 206 err(1, "line 1: too many fields"); Err bitreich.org 70 i 207 if (ctx.fieldnum < FIELD_OTHER) Err bitreich.org 70 i 208 err(1, "line 1: not enough input columns"); Err bitreich.org 70 i 209 if (strcasecmp(fields[0], "TYPE") != 0) Err bitreich.org 70 i 210 err(1, "line 1: 1st column is not \"TYPE\""); Err bitreich.org 70 i 211 if (strcasecmp(fields[1], "START") != 0) Err bitreich.org 70 i 212 err(1, "line 1: 2nd column is not \"START\""); Err bitreich.org 70 i 213 if (strcasecmp(fields[2], "END") != 0) Err bitreich.org 70 i 214 err(1, "line 1: 3rd column is not \"END\""); Err bitreich.org 70 i 215 if (strcasecmp(fields[3], "RECUR") != 0) Err bitreich.org 70 i 216 err(1, "line 1: 4th column is not \"RECUR\""); Err bitreich.org 70 i 217 Err bitreich.org 70 i 218 free(line); Err bitreich.org 70 i 219 line = NULL; Err bitreich.org 70 i 220 } Err bitreich.org 70 i 221 Err bitreich.org 70 i 222 for (;;) { Err bitreich.org 70 i 223 char *fields[FIELD_MAX]; Err bitreich.org 70 i 224 Err bitreich.org 70 i 225 ctx.linenum++; Err bitreich.org 70 i 226 getline(&line, &sz2, fp); Err bitreich.org 70 i 227 if (ferror(fp)) Err bitreich.org 70 i 228 err(1, "reading stdin: %s", strerror(errno)); Err bitreich.org 70 i 229 if (feof(fp)) Err bitreich.org 70 i 230 break; Err bitreich.org 70 i 231 Err bitreich.org 70 i 232 strchomp(line); Err bitreich.org 70 i 233 Err bitreich.org 70 i 234 if (strsplit(line, fields, FIELD_MAX, "\t") != ctx.fieldnum) Err bitreich.org 70 i 235 err(1, "line %zd: bad number of columns", Err bitreich.org 70 i 236 ctx.linenum, strerror(errno)); Err bitreich.org 70 i 237 Err bitreich.org 70 i 238 print(&ctx, fields); Err bitreich.org 70 i 239 } Err bitreich.org 70 i 240 fputc('\n', stdout); Err bitreich.org 70 i 241 Err bitreich.org 70 i 242 free(line); Err bitreich.org 70 i 243 line = NULL; Err bitreich.org 70 i 244 } Err bitreich.org 70 i 245 Err bitreich.org 70 i 246 static void Err bitreich.org 70 i 247 usage(void) Err bitreich.org 70 i 248 { Err bitreich.org 70 i 249 fprintf(stderr, "usage: %s [-f fromdate] [-t todate]\n", arg0); Err bitreich.org 70 i 250 exit(1); Err bitreich.org 70 i 251 } Err bitreich.org 70 i 252 Err bitreich.org 70 i 253 int Err bitreich.org 70 i 254 main(int argc, char **argv) Err bitreich.org 70 i 255 { Err bitreich.org 70 i 256 char c; Err bitreich.org 70 i 257 Err bitreich.org 70 i 258 if (pledge("stdio", "") < 0) Err bitreich.org 70 i 259 err(1, "pledge: %s", strerror(errno)); Err bitreich.org 70 i 260 Err bitreich.org 70 i 261 arg0 = *argv; Err bitreich.org 70 i 262 while ((c = getopt(argc, argv, "f:t:")) > 0) { Err bitreich.org 70 i 263 char const *e; Err bitreich.org 70 i 264 Err bitreich.org 70 i 265 switch (c) { Err bitreich.org 70 i 266 case 'f': Err bitreich.org 70 i 267 flag_from = strtonum(optarg, INT64_MIN, INT64_MAX, &e); Err bitreich.org 70 i 268 if (e != NULL) Err bitreich.org 70 i 269 err(1, "fromdate value %s is %s", optarg, e); Err bitreich.org 70 i 270 break; Err bitreich.org 70 i 271 case 't': Err bitreich.org 70 i 272 flag_to = strtonum(optarg, INT64_MIN, INT64_MAX, &e); Err bitreich.org 70 i 273 if (e != NULL) Err bitreich.org 70 i 274 err(1, "todate value %s is %s", optarg, e); Err bitreich.org 70 i 275 break; Err bitreich.org 70 i 276 default: Err bitreich.org 70 i 277 usage(); Err bitreich.org 70 i 278 } Err bitreich.org 70 i 279 } Err bitreich.org 70 i 280 argc -= optind; Err bitreich.org 70 i 281 argv += optind; Err bitreich.org 70 i 282 Err bitreich.org 70 i 283 tsv2agenda(stdin); Err bitreich.org 70 i 284 return 0; Err bitreich.org 70 i 285 } Err bitreich.org 70 .