let user choose extra fields to print and custom date formats - ics2txt - conve… | |
git clone git://bitreich.org/ics2txt git://enlrupgkhuxnvlhsf6lc3fziv5h2hhfrinws… | |
Log | |
Files | |
Refs | |
Tags | |
README | |
--- | |
commit 8894359aa6ad4ccc485901a8af9db03d1a2b4d5f | |
parent 65778fa74c2e72ca67a8dc4f6c1f0021f8ce2de4 | |
Author: Josuah Demangeon <[email protected]> | |
Date: Fri, 18 Jun 2021 08:58:21 +0200 | |
let user choose extra fields to print and custom date formats | |
Diffstat: | |
M ical.c | 2 +- | |
M ics2tsv.c | 111 ++++++++++++++++++++++++++++-… | |
M util.c | 8 +++----- | |
M util.h | 2 +- | |
4 files changed, 108 insertions(+), 15 deletions(-) | |
--- | |
diff --git a/ical.c b/ical.c | |
@@ -297,7 +297,7 @@ ical_getline(char **contentline, char **line, size_t *sz, F… | |
num++; | |
strchomp(*line); | |
- if (strappend(contentline, *line) < 0) | |
+ if (strappend(contentline, *line) == NULL) | |
return -1; | |
if ((c = fgetc(fp)) == EOF) | |
goto end; | |
diff --git a/ics2tsv.c b/ics2tsv.c | |
@@ -3,31 +3,49 @@ | |
#include <stdlib.h> | |
#include <string.h> | |
#include <strings.h> | |
+#include <time.h> | |
+#include <unistd.h> | |
#include "ical.h" | |
#include "util.h" | |
-#define FIELDS_MAX 64 | |
+#define FIELDS_MAX 128 | |
typedef struct Field Field; | |
typedef struct Block Block; | |
+struct Field { | |
+ char *key; | |
+ char *value; | |
+}; | |
+ | |
struct Block { | |
time_t beg, end; | |
char *fields[FIELDS_MAX]; | |
}; | |
-Block block; | |
+static char default_fields[] = "CATEGORIES,LOCATION,SUMMARY,DESCRIPTION"; | |
+static char *flag_s = ","; | |
+static char *flag_t = NULL; | |
+static char *flag_f = default_fields; | |
+static char *fields[FIELDS_MAX]; | |
+static Block block; | |
static int | |
fn_field_name(IcalParser *p, char *name) | |
{ | |
+ (void)p; | |
+ (void)name; | |
+ | |
return 0; | |
} | |
static int | |
fn_block_begin(IcalParser *p, char *name) | |
{ | |
+ (void)p; | |
+ (void)name; | |
+ | |
memset(&block, 0, sizeof block); | |
return 0; | |
} | |
@@ -35,9 +53,30 @@ fn_block_begin(IcalParser *p, char *name) | |
static int | |
fn_block_end(IcalParser *p, char *name) | |
{ | |
+ char buf[128]; | |
+ struct tm tm = {0}; | |
+ | |
+ (void)name; | |
+ | |
if (p->blocktype == ICAL_BLOCK_OTHER) | |
return 0; | |
- printf("%s\t%lld\t%lld", p->current->name, block.beg, block.end); | |
+ fputs(p->current->name, stdout); | |
+ | |
+ /* printing dates with %s is much much slower than %lld */ | |
+ if (flag_t == NULL) { | |
+ printf("\t%lld\t%lld", block.beg, block.end); | |
+ } else { | |
+ strftime(buf, sizeof buf, flag_t, gmtime_r(&block.beg, &tm)); | |
+ printf("\t%s", buf); | |
+ strftime(buf, sizeof buf, flag_t, gmtime_r(&block.end, &tm)); | |
+ printf("\t%s", buf); | |
+ } | |
+ | |
+ for (int i = 0; fields[i] != NULL; i++) { | |
+ fputc('\t', stdout); | |
+ if (block.fields[i] != NULL) | |
+ fputs(block.fields[i], stdout); | |
+ } | |
printf("\n"); | |
return 0; | |
} | |
@@ -45,13 +84,17 @@ fn_block_end(IcalParser *p, char *name) | |
static int | |
fn_param_value(IcalParser *p, char *name, char *value) | |
{ | |
+ (void)p; | |
+ (void)name; | |
+ (void)value; | |
+ | |
return 0; | |
} | |
static int | |
fn_field_value(IcalParser *p, char *name, char *value) | |
{ | |
- static char *fieldmap[][2] = { | |
+ static char *map[][2] = { | |
[ICAL_BLOCK_VEVENT] = { "DTSTART", "DTEND" }, | |
[ICAL_BLOCK_VTODO] = { NULL, "DUE" }, | |
[ICAL_BLOCK_VJOURNAL] = { "DTSTAMP", NULL }, | |
@@ -61,22 +104,48 @@ fn_field_value(IcalParser *p, char *name, char *value) | |
}; | |
char *beg, *end; | |
- beg = fieldmap[p->blocktype][0]; | |
+ /* fill the date fields */ | |
+ beg = map[p->blocktype][0]; | |
if (beg != NULL && strcasecmp(name, beg) == 0) | |
if (ical_get_time(p, value, &block.beg) != 0) | |
return -1; | |
- end = fieldmap[p->blocktype][1]; | |
+ end = map[p->blocktype][1]; | |
if (end != NULL && strcasecmp(name, end) == 0) | |
if (ical_get_time(p, value, &block.end) != 0) | |
return -1; | |
+ | |
+ /* fill text fields as requested with -o F1,F2... */ | |
+ for (int i = 0; fields[i] != NULL; i++) { | |
+ if (strcasecmp(name, fields[i]) == 0) { | |
+ if (block.fields[i] == NULL) { | |
+ if ((block.fields[i] = strdup(value)) == NULL) | |
+ return ical_err(p, strerror(errno)); | |
+ } else { | |
+ if (strappend(&block.fields[i], flag_s) == NUL… | |
+ strappend(&block.fields[i], value) == NULL) | |
+ return ical_err(p, strerror(errno)); | |
+ } | |
+ } | |
+ } | |
+ | |
return 0; | |
} | |
+static void | |
+usage(void) | |
+{ | |
+ fprintf(stderr, "usage: %s [-f fields] [-s subsep] [-t timefmt] [file.… | |
+ exit(1); | |
+} | |
+ | |
int | |
main(int argc, char **argv) | |
{ | |
IcalParser p = {0}; | |
- arg0 = *argv++; | |
+ size_t i; | |
+ int c; | |
+ | |
+ arg0 = *argv; | |
p.fn_field_name = fn_field_name; | |
p.fn_block_begin = fn_block_begin; | |
@@ -84,7 +153,33 @@ main(int argc, char **argv) | |
p.fn_param_value = fn_param_value; | |
p.fn_field_value = fn_field_value; | |
- if (*argv == NULL) { | |
+ while ((c = getopt(argc, argv, "f:s:t:")) != -1) { | |
+ switch (c) { | |
+ case 'f': | |
+ flag_f = optarg; | |
+ break; | |
+ case 's': | |
+ flag_s = optarg; | |
+ break; | |
+ case 't': | |
+ flag_t = optarg; | |
+ break; | |
+ case '?': | |
+ usage(); | |
+ break; | |
+ } | |
+ } | |
+ argv += optind; | |
+ argc -= optind; | |
+ | |
+ i = 0; | |
+ do { | |
+ if (i >= sizeof fields / sizeof *fields - 1) | |
+ err("too many fields specified with -o flag"); | |
+ } while ((fields[i++] = strsep(&flag_f, ",")) != NULL); | |
+ fields[i] = NULL; | |
+ | |
+ if (*argv == NULL || strcmp(*argv, "-") == 0) { | |
debug("converting *stdin*"); | |
if (ical_parse(&p, stdin) < 0) | |
err("parsing *stdin*:%d: %s", p.linenum, p.errmsg); | |
diff --git a/util.c b/util.c | |
@@ -110,7 +110,7 @@ strchomp(char *line) | |
line[--len] = '\0'; | |
} | |
-int | |
+char * | |
strappend(char **dp, char const *s) | |
{ | |
size_t dlen, slen; | |
@@ -118,13 +118,11 @@ strappend(char **dp, char const *s) | |
dlen = (*dp == NULL) ? 0 : strlen(*dp); | |
slen = strlen(s); | |
- | |
if ((mem = realloc(*dp, dlen + slen + 1)) == NULL) | |
- return -1; | |
+ return NULL; | |
*dp = mem; | |
- | |
memcpy(*dp + dlen, s, slen + 1); | |
- return 0; | |
+ return *dp; | |
} | |
/** memory **/ | |
diff --git a/util.h b/util.h | |
@@ -15,7 +15,7 @@ void debug(char const *fmt, ...); | |
size_t strlcpy(char *, char const *, size_t); | |
char *strsep(char **, char const *); | |
void strchomp(char *); | |
-int strappend(char **, char const *); | |
+char *strappend(char **, char const *); | |
size_t strlcat(char *, char const *, size_t); | |
/** memory **/ |