filters: posix compliant rewrite of calendar filter
Rewrite of the awk calendar filter to make it posix compliant. Tested
with awk --posix (awk -V = GNU Awk 5.1.1). Also added some improvements
to readability and formatting.
This complements commit 3ef4a3ca05
("filters: try and make awk scripts
posix compliant").
Signed-off-by: Koni Marti <koni.marti@gmail.com>
Acked-by: Robin Jarry <robin@jarry.cc>
This commit is contained in:
parent
fb5558da81
commit
ab941ebc6a
1 changed files with 115 additions and 184 deletions
295
filters/calendar
295
filters/calendar
|
@ -9,38 +9,48 @@
|
||||||
|
|
||||||
BEGIN {
|
BEGIN {
|
||||||
UIDS[0];
|
UIDS[0];
|
||||||
|
|
||||||
people_attending[0];
|
people_attending[0];
|
||||||
people_partstat[0];
|
people_partstat[0];
|
||||||
people_rsvp[0];
|
people_rsvp[0];
|
||||||
|
|
||||||
# use a colon to separate the type of data line from the actual contents
|
# use a colon to separate the type of data line from the actual contents
|
||||||
FS = ":";
|
FS = ":";
|
||||||
|
}
|
||||||
|
|
||||||
method = ""
|
{
|
||||||
prodid = ""
|
# remove carriage return from every line
|
||||||
|
gsub(/\r/, "")
|
||||||
first = 0
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/^[ ]/ {
|
/^[ ]/ {
|
||||||
|
# this block deals with the continuation lines that start with a whitespace
|
||||||
|
#
|
||||||
|
line = $0
|
||||||
|
# remove trailing whitespaces
|
||||||
|
gsub(/^[ ]/, "", line)
|
||||||
|
|
||||||
# assumes continuation lines start with a space
|
# assumes continuation lines start with a space
|
||||||
if (indescription) {
|
if (indescription) {
|
||||||
entry = entry gensub("\r", "", "g", gensub("^[ ]", "", 1, $0));
|
entry = entry line
|
||||||
} else if (insummary) {
|
} else if (insummary) {
|
||||||
summary = summary gensub("\r", "", "g", gensub("^[ ]", "", 1, $0))
|
summary = summary line
|
||||||
} else if (inattendee) {
|
} else if (inattendee) {
|
||||||
attendee = attendee gensub("\r", "", "g", gensub("^[ ]", "", 1, $0))
|
attendee = attendee line
|
||||||
} else if (inorganizer) {
|
} else if (inorganizer) {
|
||||||
organizer = organizer gensub("\r", "", "g", gensub("^[ ]", "", 1, $0))
|
organizer = organizer line
|
||||||
} else if (inlocation) {
|
} else if (inlocation) {
|
||||||
location = location unescape(gensub("\r", "", "g", $0), 0);
|
location = location unescape(line, 0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/^BEGIN:VALARM/,/^END:VALARM/ {
|
||||||
|
next
|
||||||
|
}
|
||||||
|
|
||||||
/^BEGIN:VEVENT/ {
|
/^BEGIN:VEVENT/ {
|
||||||
# start of an event: initialize global values used for each event
|
# start of an event: initialize global values used for each event
|
||||||
date = "";
|
start_date = "";
|
||||||
|
end_date = "";
|
||||||
entry = ""
|
entry = ""
|
||||||
id = ""
|
id = ""
|
||||||
|
|
||||||
|
@ -49,7 +59,6 @@ BEGIN {
|
||||||
inattendee = 0
|
inattendee = 0
|
||||||
inorganizer = 0
|
inorganizer = 0
|
||||||
inlocation = 0
|
inlocation = 0
|
||||||
in_alarm = 0
|
|
||||||
|
|
||||||
location = ""
|
location = ""
|
||||||
status = ""
|
status = ""
|
||||||
|
@ -60,27 +69,11 @@ BEGIN {
|
||||||
rrend = ""
|
rrend = ""
|
||||||
rcount = ""
|
rcount = ""
|
||||||
intfreq = ""
|
intfreq = ""
|
||||||
|
idx = 0
|
||||||
|
|
||||||
delete people_attending;
|
delete people_attending;
|
||||||
delete people_partstat;
|
delete people_partstat;
|
||||||
delete people_rsvp;
|
delete people_rsvp;
|
||||||
|
|
||||||
if (first == 0) {
|
|
||||||
first = 1
|
|
||||||
if (method != "")
|
|
||||||
print " METHOD " method
|
|
||||||
if (prodid != "")
|
|
||||||
print " PRODID " prodid
|
|
||||||
print ""
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/^BEGIN:VALARM/ {
|
|
||||||
in_alarm = 1
|
|
||||||
}
|
|
||||||
|
|
||||||
/^END:VALARM/ {
|
|
||||||
in_alarm = 0
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/^[A-Z]/ {
|
/^[A-Z]/ {
|
||||||
|
@ -97,130 +90,99 @@ BEGIN {
|
||||||
inlocation = 0;
|
inlocation = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/^DTSTART;VALUE=DATE/ {
|
/^DTSTART[:;]/ {
|
||||||
date = datestring($2);
|
tz = get_value($0, "TZID=[^:;]*", "=")
|
||||||
|
start_date = datetimestring($2, tz);
|
||||||
}
|
}
|
||||||
|
|
||||||
/^DTEND;VALUE=DATE/ {
|
/^DTEND[:;]/ {
|
||||||
end_date = datestring($2);
|
tz = get_value($0, "TZID=[^:;]*", "=")
|
||||||
}
|
|
||||||
|
|
||||||
/^DTSTART[:;][^V]/ {
|
|
||||||
tz = "";
|
|
||||||
match($0, /TZID=([^:]*)/, a)
|
|
||||||
{
|
|
||||||
tz = a[1];
|
|
||||||
}
|
|
||||||
date = datetimestring($2, tz);
|
|
||||||
}
|
|
||||||
|
|
||||||
/^DTEND[:;][^V]/ {
|
|
||||||
tz = "";
|
|
||||||
match($0, /TZID=([^:]*)/, a)
|
|
||||||
{
|
|
||||||
tz = a[1];
|
|
||||||
}
|
|
||||||
end_date = datetimestring($2, tz);
|
end_date = datetimestring($2, tz);
|
||||||
}
|
}
|
||||||
|
|
||||||
/^RRULE:FREQ=(DAILY|WEEKLY|MONTHLY|YEARLY)/ {
|
/^RRULE[:]/ {
|
||||||
# TODO: handle BYDAY values for events that repeat weekly for multiple days
|
freq = get_value($0, "FREQ=[^:;]*", "=")
|
||||||
# (e.g. a "Gym" event)
|
interval = get_value($0, "INTERVAL=[^:;]*", "=")
|
||||||
|
rrend = get_value($0, "UNTIL=[^:;]*", "=")
|
||||||
# get the d, w, m or y value
|
rcount = get_value($0, "COUNT=[^:;]*", "=")
|
||||||
freq = tolower(gensub(/.*FREQ=(.).*/, "\\1", 1, $0))
|
intfreq = tolower(freq)
|
||||||
# get the interval, and use 1 if none specified
|
if (interval != "")
|
||||||
interval = $0 ~ /INTERVAL=/ ? gensub(/.*INTERVAL=([0-9]+).*/, "\\1", 1, $0) : 1
|
intfreq = " +" interval intfreq
|
||||||
# get the enddate of the rule and use "" if none specified
|
|
||||||
rrend = $0 ~ /UNTIL=/ ? datestring(gensub(/.*UNTIL=([0-9]{8}).*/, "\\1", 1, $0)) : ""
|
|
||||||
rcount = $0 ~ /COUNT=/ ? gensub(/.*COUNT=([0-9]+).*/, "\\1", 1, $0) : ""
|
|
||||||
# build the repetitor value
|
|
||||||
intfreq = " +" interval freq
|
|
||||||
}
|
|
||||||
|
|
||||||
/^DESCRIPTION/ {
|
|
||||||
if (!in_alarm) {
|
|
||||||
entry = entry gensub("\r", "", "g", gensub($1":", "", 1, $0));
|
|
||||||
indescription = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/^SUMMARY/ {
|
|
||||||
if (!in_alarm) {
|
|
||||||
summary = gensub("\r", "", "g", gensub($1":", "", 1, $0));
|
|
||||||
insummary = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/^UID/ {
|
|
||||||
if (!in_alarm) {
|
|
||||||
id = gensub("\r", "", "g", $2);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/^METHOD/ {
|
/^METHOD/ {
|
||||||
method = gensub("\r", "", "g", $2);
|
method = $2
|
||||||
}
|
}
|
||||||
|
|
||||||
/^PRODID/ {
|
/^UID/ {
|
||||||
prodid = gensub("\r", "", "g", $2);
|
id = $2
|
||||||
|
}
|
||||||
|
|
||||||
|
/^STATUS/ {
|
||||||
|
status = $2
|
||||||
|
}
|
||||||
|
|
||||||
|
/^DESCRIPTION/ {
|
||||||
|
entry = entry $2
|
||||||
|
indescription = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/^SUMMARY/ {
|
||||||
|
summary = $2
|
||||||
|
insummary = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/^ORGANIZER/ {
|
/^ORGANIZER/ {
|
||||||
organizer = gensub("\r", "", "g", $0);
|
organizer = $0
|
||||||
inorganizer = 1;
|
inorganizer = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/^LOCATION/ {
|
/^LOCATION/ {
|
||||||
location = unescape(gensub("\r", "", "g", $2), 0);
|
location = unescape($2, 0);
|
||||||
inlocation = 1;
|
inlocation = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/^STATUS/ {
|
|
||||||
status = gensub("\r", "", "g", $2);
|
|
||||||
}
|
|
||||||
|
|
||||||
/^ATTENDEE/ {
|
/^ATTENDEE/ {
|
||||||
attendee = gensub("\r", "", "g", $0);
|
attendee = $0
|
||||||
inattendee = 1;
|
inattendee = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/^END:VEVENT/ {
|
/^END:VEVENT/ {
|
||||||
#output event
|
#output event
|
||||||
|
if (method != "") {
|
||||||
|
printf "\n This is a meeting %s\n\n", method
|
||||||
|
}
|
||||||
|
fmt = " %-14s%s\n"
|
||||||
is_duplicate = (id in UIDS);
|
is_duplicate = (id in UIDS);
|
||||||
if(is_duplicate == 0) {
|
if(is_duplicate == 0) {
|
||||||
print "* SUMMARY " gensub("^[ ]+", "", "g", unescape(summary, 0))
|
printf fmt, "SUMMARY", unescape(summary, 0)
|
||||||
if(length(location))
|
if(location != "")
|
||||||
print " LOCATION " location
|
printf fmt, "LOCATION", location
|
||||||
if(organizer != "")
|
if(organizer != "")
|
||||||
print " ORGANIZER " organizer
|
printf fmt, "ORGANIZER", organizer
|
||||||
for (cn in people_attending) {
|
for (idx in people_attending) {
|
||||||
print " ATTENDEE " cn
|
printf fmt, "ATTENDEE [" idx "]", people_attending[idx]
|
||||||
partstat = people_partstat[cn]
|
partstat = people_partstat[idx]
|
||||||
if (partstat != "") {
|
if (partstat != "") {
|
||||||
print " STATUS " partstat
|
printf fmt, "", "STATUS\t" partstat
|
||||||
}
|
}
|
||||||
rsvp = people_rsvp[cn]
|
rsvp = people_rsvp[idx]
|
||||||
if (rsvp != "") {
|
if (rsvp != "") {
|
||||||
print " RSVP " rsvp
|
printf fmt, "", "RSVP\t" rsvp
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
print " START " date
|
printf fmt, "START", start_date
|
||||||
print " END " end_date
|
printf fmt, "END", end_date
|
||||||
|
|
||||||
if (intfreq != "") {
|
if (intfreq != "") {
|
||||||
print ""
|
printf "\n"fmt, "RECURRENCE", intfreq
|
||||||
print " RECURRENCE " intfreq
|
|
||||||
if (rcount != "")
|
if (rcount != "")
|
||||||
print " COUNTS " rcount
|
printf fmt, "COUNTS", rcount
|
||||||
if (rrend != "")
|
if (rrend != "")
|
||||||
print " END DATE " rrend
|
printf fmt, "END DATE", rrend
|
||||||
|
|
||||||
}
|
}
|
||||||
|
if(entry != "")
|
||||||
print ""
|
print "\n" unescape(entry, 1);
|
||||||
if(length(entry)>1)
|
|
||||||
print gensub("^[ ]+", "", "g", unescape(entry, 1));
|
|
||||||
UIDS[id] = 1;
|
UIDS[id] = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -228,101 +190,70 @@ BEGIN {
|
||||||
|
|
||||||
function unescape(input, preserve_newlines)
|
function unescape(input, preserve_newlines)
|
||||||
{
|
{
|
||||||
ret = gensub("\\\\,", ",", "g",
|
ret = input
|
||||||
gensub("\\\\;", ";", "g", input))
|
gsub(/\\,/, ",", ret)
|
||||||
|
gsub(/\\;/, ";", ret)
|
||||||
if (preserve_newlines)
|
if (preserve_newlines)
|
||||||
ret = gensub("\\\\n", "\n", "g", ret)
|
gsub(/\\n/, "\n", ret)
|
||||||
else
|
else
|
||||||
ret = gensub("\\\\n", " ", "g", ret)
|
gsub(/\\n/, " ", ret)
|
||||||
return ret
|
return ret
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function datetimestring(input, tz)
|
function datetimestring(input, tzInput)
|
||||||
{
|
{
|
||||||
spec = match(input, "([0-9]{4})([0-9]{2})([0-9]{2})T([0-9]{2})([0-9]{2})([0-9]{2}).*[\r]*", a);
|
timestr = input
|
||||||
year = a[1]
|
pos = index(timestr, "T")
|
||||||
month = a[2]
|
if (pos < 0) {
|
||||||
day = a[3]
|
return timestr
|
||||||
hour = a[4]
|
|
||||||
min = a[5]
|
|
||||||
sec = a[6]
|
|
||||||
|
|
||||||
stamp = mktime(year" "month" "day" "hour" "min" "sec);
|
|
||||||
|
|
||||||
if (input ~ /[0-9]{8}T[0-9]{6}Z/ ) {
|
|
||||||
tz = "UTC"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return strftime("%Y-%m-%d %a %H:%M", stamp)" "tz;
|
date = substr(timestr, 1, pos)
|
||||||
}
|
time = substr(timestr, pos+1, length(timestr))
|
||||||
|
|
||||||
|
year = substr(date, 1, 4)
|
||||||
|
month = substr(date, 5, 2)
|
||||||
|
day = substr(date, 7, 2)
|
||||||
|
|
||||||
function datestring(input)
|
hour = substr(time, 1, 2)
|
||||||
{
|
min = substr(time, 3, 2)
|
||||||
spec = gensub("([0-9]{4})([0-9]{2})([0-9]{2}).*[\r]*", "\\1 \\2 \\3 00 00 00", "g", input);
|
sec = substr(time, 5, 2)
|
||||||
|
|
||||||
stamp = mktime(spec);
|
return sprintf("%4d/%02d/%02d %02d:%02d:%02d %s", year, month, day, hour, min, sec, tzInput)
|
||||||
|
|
||||||
return strftime("%Y-%m-%d %a", stamp);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function add_attendee(attendee)
|
function add_attendee(attendee)
|
||||||
{
|
{
|
||||||
CN = find_full_name(attendee)
|
CN = find_full_name(attendee)
|
||||||
if (CN != "")
|
|
||||||
people_attending[CN] = 1;
|
|
||||||
|
|
||||||
if (CN != "") {
|
if (CN != "") {
|
||||||
match(attendee, /PARTSTAT=([^;]+)/, m)
|
idx = idx + 1
|
||||||
{
|
people_attending[idx] = CN;
|
||||||
people_partstat[CN] = m[1]
|
people_partstat[idx] = get_value(attendee, "PARTSTAT=[^;:]+", "=")
|
||||||
|
people_rsvp[idx] = get_value(attendee, "RSVP=[^;:]+", "=")
|
||||||
}
|
}
|
||||||
match(attendee, /RSVP=([^;]+)/, m)
|
|
||||||
{
|
|
||||||
people_rsvp[CN] = m[1]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function extract_email(line)
|
|
||||||
{
|
|
||||||
email = ""
|
|
||||||
match(line,/:[ ]*(mailto|MAILTO):([^;]+)/, m)
|
|
||||||
{
|
|
||||||
email = m[2]
|
|
||||||
}
|
|
||||||
return email
|
|
||||||
}
|
|
||||||
|
|
||||||
function extract_name(line)
|
|
||||||
{
|
|
||||||
name = ""
|
|
||||||
match(line,/CN="?([^;:"]+)/, m)
|
|
||||||
{
|
|
||||||
name = m[1]
|
|
||||||
}
|
|
||||||
return name
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function find_full_name(line)
|
function find_full_name(line)
|
||||||
{
|
{
|
||||||
name = extract_name(line)
|
name = get_value(line, "CN=[^;:]+", "=")
|
||||||
email = extract_email(line)
|
email = get_value(line, "(mailto|MAILTO):[^;]+", ":")
|
||||||
|
|
||||||
if (name == "") {
|
if (name == "") {
|
||||||
if (email == "") {
|
return sprintf("<%s>", email)
|
||||||
return ""
|
|
||||||
} else {
|
} else {
|
||||||
return name
|
return sprintf("%s <%s>", name, email)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (email == "")
|
function get_value(line, regexp, sep) {
|
||||||
return name
|
value = ""
|
||||||
|
match(line, regexp)
|
||||||
if (email == name)
|
{
|
||||||
return "<"email">"
|
z = split(substr(line,RSTART,RLENGTH),data,sep)
|
||||||
|
if (z > 1) {
|
||||||
return name" <"email">"
|
value = data[2]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return value
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue