add a man page and a -1 flag - ics2txt - convert icalendar .ics file to plain text
(HTM) 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
(HTM) 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)