Home
add a man page and a -1 flag - ics2txt - convert icalendar .ics file to plain text HTML git clone git://bitreich.org/ics2txt git://enlrupgkhuxnvlhsf6lc3fziv5h2hhfrinws65d7roiv6bfj7d652fid.onion/ics2txt DIR Log DIR Files DIR Refs DIR Tags DIR README --- DIR commit 4bcfcc3e64d33c6e67b3f6f6359e859d2ee0ff6b DIR parent 8894359aa6ad4ccc485901a8af9db03d1a2b4d5f HTML Author: Josuah Demangeon <me@josuah.net> Date: Sat, 19 Jun 2021 12:15:14 +0200 add a man page and a -1 flag Diffstat: M Makefile | 4 ++-- A ics2tsv.1 | 150 +++++++++++++++++++++++++++++++ M ics2tsv.c | 22 ++++++++++++++++++++-- 3 files changed, 172 insertions(+), 4 deletions(-) --- DIR diff --git a/Makefile b/Makefile @@ -11,7 +11,7 @@ SRC = ical.c base64.c util.c HDR = ical.h base64.h util.h OBJ = ${SRC:.c=.o} BIN = ics2tree ics2tsv -MAN1 = ics2txt.1 +MAN1 = ics2txt.1 ics2tsv.1 MAN5 = tcal.5 all: ${BIN} @@ -36,5 +36,5 @@ install: dist: clean mkdir -p ${NAME}-${VERSION} - cp -r README Makefile bin ${SRC} ${NAME}-${VERSION} + cp -r README Makefile bin ${MAN1} ${MAN5} ${SRC} ${NAME}-${VERSION} tar -cf - ${NAME}-${VERSION} | gzip -c >${NAME}-${VERSION}.tar.gz DIR diff --git a/ics2tsv.1 b/ics2tsv.1 @@ -0,0 +1,150 @@ +.Dd $Mdocdate: Mar 1 2020$ +.Dt ICS2TSV 1 +.Os +. +. +.Sh NAME +. +.Nm ics2tsv +.Nd convert an icalendar.ics file to tsv +. +. +.Sh SYNOPSIS +. +.Nm ics2tsv +.Op Fl 1 +.Op Fl f Ar fields +.Op Fl s Ar subsep +.Op Fl t Ar timefmt +.Ar [file.ics...] >file.tsv +. +.Sh DESCRIPTION +. +.Nm +is a converter that parse icalendar format and produces lines of output. +Every line represents an element delimited by +.Dq BEGIN: +and +.Dq END: +among +.Dq VEVENT , +.Dq VTODO , +.Dq VJOURNAL , +.Dq VFREEBUSY , +and +.Dq VALARM . +. +.Pp +The lines are filled with tab-delimited fields, with the first ones: +. +.Bl -enum +. +.It +Element type, as encountered after +.Dq BEGIN +and +.Dq END ; +. +.It +Start date, present for +.Dq VEVENT , +.Dq VJOURNAL , +.Dq VFREEBUSY , +and +.Dq VALARM +types. +. +.It +End date, present for +.Dq VEVENT , +.Dq VTODO , +.Dq VFREEBUSY , +and +.Dq VALARM +types. +. +.It +Reserved for future use. +. +.El +. +.Pp +And the other fields starting from +.Pq 5. +chosen by the +.Fl f +flag. +By default: +.Dq "CATEGORIES,LOCATION,SUMMARY,DESCRIPTION" . +. +.Bl -tag +. +.It Fl 1 +Show the name of the columns on the first line before the content. +. +.It Fl f Ar field1,field2,field3... +Chooses the fields from the icalendar to display, in this order, +separated by a comma +.Pq Sq \&, +and case-insensitive +. +.It Fl s Ar subsep +When there are multiple fields with the same value, they are +concatenated with +.Ar subsep +separator, by default a comma +.Pq Sq \&, . +. +.It Fl t Ar timefmt +Dates from 2nd and 3rd fields are formatted with a +.Xr strftime 3 +string +.Ar timeftm , +by default in seconds since 1970/01/01. +. +.El +. +. +.Sh EXAMPLES +. +Convert a calendar from HTTP +.Pa .ics +to custom +.Pa .txt +sorted by start date: +.Dl curl "$url.ics" | ics2tsv | sort -n -k 1,1 | tsv2tsv +. +.Pp +. +.Pp +Split an +.ics +file according to the category, saved as +.Pa .tsv : +.Bd -literal +ics2tsv -f CATEGORIES icalendar.ics | awk -F '\et' '{ print >>($6".tsv") }\' +.Ed +. +. +.Sh SEE ALSO +. +.Xr awk 1 , +.Xr cal 1 , +.Xr calendar 1 , +.Xr date 1 , +.Xr sort 1 +. +. +.Sh STANDARDS +. +.Rs +.%A Desruisseaux +.%D September 2009 +.%T Internet Calendaring and Scheduling Core Object Specification (iCalendar) +.%R RFC 5545 +.Re +. +. +.Sh AUTHORS +. +.An Josuah Demangeon Aq Mt me@josuah.net DIR diff --git a/ics2tsv.c b/ics2tsv.c @@ -24,6 +24,7 @@ struct Block { char *fields[FIELDS_MAX]; }; +static int flag_1 = 0; static char default_fields[] = "CATEGORIES,LOCATION,SUMMARY,DESCRIPTION"; static char *flag_s = ","; static char *flag_t = NULL; @@ -46,6 +47,9 @@ fn_block_begin(IcalParser *p, char *name) (void)p; (void)name; + if (p->blocktype == ICAL_BLOCK_OTHER) + return 0; + memset(&block, 0, sizeof block); return 0; } @@ -72,6 +76,9 @@ fn_block_end(IcalParser *p, char *name) printf("\t%s", buf); } + /* reserved for recurring events */ + printf("\t%s", "(null)"); + for (int i = 0; fields[i] != NULL; i++) { fputc('\t', stdout); if (block.fields[i] != NULL) @@ -134,7 +141,8 @@ fn_field_value(IcalParser *p, char *name, char *value) static void usage(void) { - fprintf(stderr, "usage: %s [-f fields] [-s subsep] [-t timefmt] [file...]", arg0); + fprintf(stderr,"usage: %s [-1] [-f fields] [-s subsep] [-t timefmt]" + " [file...]\n", arg0); exit(1); } @@ -153,8 +161,11 @@ main(int argc, char **argv) p.fn_param_value = fn_param_value; p.fn_field_value = fn_field_value; - while ((c = getopt(argc, argv, "f:s:t:")) != -1) { + while ((c = getopt(argc, argv, "1f:s:t:")) != -1) { switch (c) { + case '1': + flag_1 = 1; + break; case 'f': flag_f = optarg; break; @@ -179,6 +190,13 @@ main(int argc, char **argv) } while ((fields[i++] = strsep(&flag_f, ",")) != NULL); fields[i] = NULL; + if (flag_1) { + printf("%s\t%s\t%s", "TYPE", "BEG", "END"); + for (i = 0; fields[i] != NULL; i++) + printf("\t%s", fields[i]); + fputc('\n', stdout); + } + if (*argv == NULL || strcmp(*argv, "-") == 0) { debug("converting *stdin*"); if (ical_parse(&p, stdin) < 0)