simplify the tcal format a lot, and add a manpage for it - 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 fef052ed4c0f485f6c87b75555dc2df664bb602e
(DIR) parent 708175eee823de7ce8690d23f9a5adf1b0839a71
(HTM) Author: Josuah Demangeon <me@josuah.net>
Date: Wed, 24 Jun 2020 22:59:31 +0200
simplify the tcal format a lot, and add a manpage for it
Diffstat:
M Makefile | 28 ++++++++++++++++++++--------
M ics2tsv | 84 +++++++++++++++++++++----------
M tcal.5 | 67 +++++++++++++++++--------------
M tcal2tsv | 102 ++++++++++++++++---------------
M tsv2tcal | 74 ++++++++++++++-----------------
5 files changed, 201 insertions(+), 154 deletions(-)
---
(DIR) diff --git a/Makefile b/Makefile
@@ -1,11 +1,23 @@
-PREFIX = /usr/local
-BIN = ics2tsv tsv2tcal tcal2tsv tsv2ics ics2txt
-MAN1 = ics2txt.1
+NAME = ics2txt
+VERSION = 0.1
-all:
+BIN = ics2tsv tsv2tcal tcal2tsv tsv2ics ics2txt
+
+PREFIX = /usr/local
+MANPREFIX = ${PREFIX}/man
+
+all: ${BIN}
+
+clean:
+ rm -rf ${NAME}-${VERSION} *.gz
install:
- mkdir -p $(PREFIX)/bin
- cp $(BIN) $(PREFIX)/bin
- mkdir -p $(PREFIX)/share/man/man1
- cp $(MAN1) $(PREFIX)/share/man/man1
+ mkdir -p ${DESTDIR}$(PREFIX)/bin
+ cp $(BIN) ${DESTDIR}$(PREFIX)/bin
+ mkdir -p ${DESTDIR}$(MANPREFIX)/man1
+ cp *.1 ${DESTDIR}$(MANPREFIX)/man1
+
+dist: clean
+ mkdir -p ${NAME}-${VERSION}
+ cp -r README Makefile doc src ${BIN:=.c} ${NAME}-${VERSION}
+ tar -cf - ${NAME}-${VERSION} | gzip -c >${NAME}-${VERSION}.tar.gz
(DIR) diff --git a/ics2tsv b/ics2tsv
@@ -10,28 +10,53 @@ function mdays(mon, year)
return (mon == 2) ? (28 + isleap(year)) : (30 + (mon + (mon > 7)) % 2)
}
-function timegm(year, mon, mday, hour, min, sec)
+function maketime(tm,
+ sec, mon, day)
{
- while (--mon >= 1)
- mday += mdays(mon, year)
- while (--year >= 1970)
- mday += 365 + isleap(year)
- return (((((mday - 1) * 24) + hour) * 60) + min) * 60 + sec
+ sec = tm["sec"] + tm["min"] * 60 + tm["hour"] * 3600
+
+ day = tm["mday"] - 1
+
+ for (mon = tm["mon"] - 1; mon > 0; mon--)
+ day = day + mdays(mon, tm["year"])
+
+ # constants: x * 365 + x / 400 - x / 100 + x / 4
+ day = day + int(tm["year"] / 400) * 146097
+ day = day + int(tm["year"] % 400 / 100) * 36524
+ day = day + int(tm["year"] % 100 / 4) * 1461
+ day = day + int(tm["year"] % 4 / 1) * 365
+
+ return sec + (day - 719527) * 86400
}
-function date_ical(str, offset,
- year, mon, mday, hour, min)
+function ical_to_epoch(str, offset,
+ tm)
{
- year = substr(str, 1, 4)
- mon = substr(str, 5, 2)
- mday = substr(str, 7, 2)
- hour = substr(str, 10, 2)
- min = substr(str, 12, 2)
+ tm["year"] = substr(str, 1, 4)
+ tm["mon"] = substr(str, 5, 2)
+ tm["mday"] = substr(str, 7, 2)
+ tm["hour"] = substr(str, 10, 2)
+ tm["min"] = substr(str, 12, 2)
offset = (substr(str, 16, 1) == "Z" ? 0 : offset)
- return timegm(year, mon, mday, hour, min, 0) - offset
+ return maketime(tm) - offset
+}
+
+function print_event(ev, fields,
+ i)
+{
+ for (i = 1; i <= fields["len"]; i++)
+ printf("%s%s", (i > 1 ? "\t" : ""), ev[fields[i]])
+ printf("\n")
}
BEGIN {
+ FIELDS = "DTSTART DTEND CATEGORIES LOCATION SUMMARY DESCRIPTION"
+ fields["len"] = split(FIELDS, fields, " ")
+
+ # by default: "CATEGORIES" -> "cat", "LOCATION" -> "loc"...
+ translate["DTSTART"] = "beg"
+ translate["DTEND"] = "end"
+
"date +%z" | getline offset_str
close("date +%z")
hour = substr($0, 4, 2)
@@ -39,26 +64,33 @@ BEGIN {
tzoffset = substr(zone, 3, 1) hour * 3600 + min * 60
FS = "[:;]"
+
+ for (i = 1; i <= fields["len"]; i++) {
+ if (!(s = translate[fields[i]]))
+ s = tolower(substr(fields[i], 1, 3))
+ printf("%s%s", (i > 1 ? "\t" : ""), s)
+ }
+
+ printf("\n")
}
{
- gsub("\r", ""); gsub("\t", "\\\\t")
- gsub("^ *", ""); gsub(" *$", "")
+ gsub("\r", "")
+ gsub("\t", "\\\\t")
+ gsub("^ *", "")
+ gsub(" *$", "")
if (match($0, "^ ")) {
- event[type] = event[type] substr($0, 2, length($0) - 1)
+ ev[type] = ev[type] substr($0, 2, length($0) - 1)
} else {
type = $1
i = index($0, ":")
- event[type] = substr($0, i + 1, length($0) - i)
+ ev[type] = substr($0, i + 1, length($0) - i)
}
+}
- if ($0 ~ /^END:VEVENT/)
- printf("%d\t%d\t%s\t%s\t%s\t%s\n",
- date_ical(event["DTSTART"], offset),
- date_ical(event["DTEND"], offset),
- event["CATEGORIES"],
- event["LOCATION"],
- event["SUMMARY"],
- event["DESCRIPTION"])
+/^END:VEVENT/ {
+ ev["DTSTART"] = ical_to_epoch(ev["DTSTART"], offset)
+ ev["DTEND"] = ical_to_epoch(ev["DTEND"], offset)
+ print_event(ev, fields)
}
(DIR) diff --git a/tcal.5 b/tcal.5
@@ -6,52 +6,57 @@
.Sh NAME
.
.Nm tcal
-.Nd plaintext calendar event notation format
-.
-.
-.Sh SYNOPSIS
-.
-TZ+0300
+.Nd plaintext calendar for editing by hand on the go
.
.
.Sh DESCRIPTION
.
-The
-.Nm
-utility
-.
-.
+The first line contain
+.Dq TZ+HHMM
+with
+.Dq +HHMM
+as returned by
+.D1 $ date +%z .
.
-.Sh FILES
+.Pp
+Then empty line delimited event entries follow, with for each:
+One line with the start date, one line with the end date,
+formatted like:
+.Dq %Y-%m-%d %H:%M
.
+.Pp
+Then one line per attribute, each formatted with:
+optional space, attribute name, colon,
+optional space, and attribute content,
+end of line.
.
.
.Sh EXAMPLES
.
+.Bd -literal
+TZ+0200
+
+2020-06-28 00:00
+2020-06-05 00:00
+ loc: 950-0994, Chuo Ward, Niigata, Japan
+ sum: summer holidays
+
+2020-06-29 13:30
+2020-06-29 15:00
+ loc: online, irc.freenode.net, #bitreich-en
+ sum: bitreich irc invitation
+ des: at this moment like all other moment, everyone invited on IRC
+
+.Ed
.
.
.Sh SEE ALSO
.
-.Xr foobar 1
-.
-.
-.Sh STANDARDS
-.
-.
-.
-.Sh HISTORY
-.
+.Xr cal 1 ,
+.Xr calendar 1
.
.
.Sh AUTHORS
.
-.An <author-name>
-.Aq Mt <author-email>
-.
-.
-.Sh CAVEATS
-.
-.
-.
-.Sh BUGS
-.
+.An Josuah Demangeon
+.Aq Mt me@josuah.net
(DIR) diff --git a/tcal2tsv b/tcal2tsv
@@ -10,24 +10,45 @@ function mdays(mon, year)
return (mon == 2) ? (28 + isleap(year)) : (30 + (mon + (mon > 7)) % 2)
}
-function timegm(year, mon, mday, hour, min, sec)
+function maketime(tm,
+ sec, mon, day)
{
- while (--mon >= 1)
- mday += mdays(mon, year)
- while (--year >= 1970)
- mday += 365 + isleap(year)
- return (((((mday - 1) * 24) + hour) * 60) + min) * 60 + sec
+ sec = tm["sec"] + tm["min"] * 60 + tm["hour"] * 3600
+
+ day = tm["mday"] - 1
+
+ for (mon = tm["mon"] - 1; mon > 0; mon--)
+ day = day + mdays(mon, tm["year"])
+
+ # constants: x * 365 + x / 400 - x / 100 + x / 4
+ day = day + int(tm["year"] / 400) * 146097
+ day = day + int(tm["year"] % 400 / 100) * 36524
+ day = day + int(tm["year"] % 100 / 4) * 1461
+ day = day + int(tm["year"] % 4 / 1) * 365
+
+ return sec + (day - 719527) * 86400
}
-function date_text(str, offset,
- year, mon, mday, hour, min)
+function text_to_epoch(str, tz,
+ tm)
{
- year = substr(str, 1, 4)
- mon = substr(str, 6, 2)
- mday = substr(str, 9, 2)
- hour = substr(str, 12, 2)
- min = substr(str, 15, 2)
- return timegm(year, mon, mday, hour, min, 0) - offset
+ tm["year"] = substr(str, 1, 4)
+ tm["mon"] = substr(str, 6, 2)
+ tm["mday"] = substr(str, 9, 2)
+ tm["hour"] = substr(str, 12, 2)
+ tm["min"] = substr(str, 15, 2)
+ return maketime(tm) - tz
+}
+
+BEGIN {
+ FIELDS = "beg end cat loc sum des"
+ fields["len"] = split(FIELDS, fields, " ")
+
+ for (i = 1; i <= fields["len"]; i++) {
+ pos[fields[i]] = i
+ printf("%s%s", (i > 1 ? "\t" : ""), fields[i])
+ }
+ printf("\n")
}
{
@@ -35,47 +56,30 @@ function date_text(str, offset,
}
/^TZ[+-]/ {
- hour = substr($0, 4, 2)
- min = substr($0, 6, 2)
- tzoffset = substr(zone, 3, 1) hour * 3600 + min * 60
- next
+ TZOFFSET = substr($1, 3, 1) substr($0, 4, 2)*3600 + substr($0, 6, 2)*60
+ while (getline && $0 ~ /^$/)
+ continue
}
-/^[0-9]+-[0-9]+-[0-9]+ / {
- time = date_text($1 " " $2, tzoffset)
- row++
+/^[0-9]+-[0-9]+-[0-9]+/ {
+ if ("beg" in ev)
+ ev["end"] = text_to_epoch($0, TZOFFSET)
+ else
+ ev["beg"] = text_to_epoch($0, TZOFFSET)
+ next
}
/^ / {
- d = $0
- sub(/^ */, "", d)
- des = des " " d
+ tag = $1
+ sub("^ *[^ :]+: *", "")
+ sub(":$", "", tag)
+ ev[tag] = $0
+ next
}
/^$/ {
- if (beg)
- printf "%d\t%d\t%s\t%s\t%s\t%s\n", beg, end, cat, loc, sum, des
- beg = end = cat = loc = sum = des = ""
-}
-
-row == 1 {
- beg = time
- sum = $0
- sub(/^[^ ]+ +[^ ]+ +/, "", sum)
-}
-
-row == 2 {
- end = time
-
- line = $0
- sub(/^[^ ]+ +[^ ]+ +/, "", line)
-
- cat = line
- sub(/\].*/, "", cat)
- sub(/^\[/, "", cat)
-
- loc = line
- sub(/[^]]*\] */, "", loc)
-
- row = 0
+ for (i = 1; i <= fields["len"]; i++)
+ printf("%s%s", (i > 1 ? "\t" : ""), ev[fields[i]])
+ printf("\n")
+ delete ev
}
(DIR) diff --git a/tsv2tcal b/tsv2tcal
@@ -10,88 +10,82 @@ function mdays(mon, year)
return (mon == 2) ? (28 + isleap(year)) : (30 + (mon + (mon > 7)) % 2)
}
-# Split the time in seconds since epoch into a table, with fields
-# named as with gmtime(3): tm["year"], tm["mon"], tm["mday"],
-# tm["hour"], tm["min"], tm["sec"]
-function gmtime(sec, tm,
- s)
+function gmtime(sec, tm)
{
tm["year"] = 1970
while (sec >= (s = 86400 * (365 + isleap(tm["year"])))) {
tm["year"]++
sec -= s
}
-
tm["mon"] = 1
while (sec >= (s = 86400 * mdays(tm["mon"], tm["year"]))) {
tm["mon"]++
sec -= s
}
-
tm["mday"] = 1
while (sec >= (s = 86400)) {
tm["mday"]++
sec -= s
}
-
tm["hour"] = 0
while (sec >= 3600) {
tm["hour"]++
sec -= 3600
}
-
tm["min"] = 0
while (sec >= 60) {
tm["min"]++
sec -= 60
}
-
tm["sec"] = sec
}
-function print_fold(prefix, s, n)
+function localtime(sec, tm,
+ tz, h, m)
{
- while (s != "") {
- line = substr(s, 1, n)
- if (length(s) > n) sub(" +[^ \t\r\n]*$", "", line)
- print prefix line
- s = substr(s, length(line) + 2)
- }
+ return gmtime(sec + TZOFFSET, tm)
}
BEGIN {
- cmd = "date +%z"
- cmd | getline zone
- close(cmd)
+ "date +%z" | getline tz
+ close("date +%z")
+ TZOFFSET = substr(tz, 1, 1) substr(tz, 2, 2)*3600 + substr(tz, 4, 2)*60
- hour = substr(zone, 2, 2)
- min = substr(zone, 4, 2)
+ print("TZ" tz)
- offset = (substr(zone, 1, 1) "1") * (hour * 3600 + min * 60)
- print "TZ" zone
+ FS = "\t"
+}
+
+NR == 1 {
+ for (i = 1; i <= NF; i++)
+ name[i] = $i
+ next
}
{
- split($0, a, "\t")
- gmtime(a[1] + offset, beg)
- gmtime(a[2] + offset, end)
- cat = a[3]; loc = a[4]; sum = a[5]; des = a[6]
+ for (i = 1; i <= NF; i++)
+ ev[name[i]] = $i
+
+ print("")
- print ""
- printf "%04d-%02d-%02d %02d:%02d ",
- beg["year"], beg["mon"], beg["mday"], beg["hour"], beg["min"]
- print sum
+ localtime(ev["beg"] + offset, tm)
+ printf("%04d-%02d-%02d %02d:%02d\n",
+ tm["year"], tm["mon"], tm["mday"], tm["hour"], tm["min"])
+ delete ev["beg"]
- printf "%04d-%02d-%02d %02d:%02d ",
- end["year"], end["mon"], end["mday"], end["hour"], end["min"]
- print "[" cat "] " loc
+ localtime(ev["end"] + offset, tm)
+ printf("%04d-%02d-%02d %02d:%02d\n",
+ tm["year"], tm["mon"], tm["mday"], tm["hour"], tm["min"])
+ delete ev["end"]
+
+ for (i = 1; i <= NF; i++) {
+ if (name[i] in ev && ev[name[i]])
+ printf(" %s: %s\n", name[i], ev[name[i]])
+ }
- sub("^ *", "", des)
- sub(" *$", "", des)
- if (des)
- print_fold(" ", des, 80)
+ delete ev
}
END {
- print ""
+ print("")
}