simplify and improve portability across mawk, gawk, nawk, busybox awk... - 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 24985c575e833254adb79215584947a601569ea1
 (DIR) parent c6606df0960a765824c000aeb54e21691bcc94bb
 (HTM) Author: Josuah Demangeon <me@josuah.net>
       Date:   Thu, 25 Jun 2020 21:11:17 +0200
       
       simplify and improve portability across mawk, gawk, nawk, busybox awk...
       
       Diffstat:
         M README                              |      33 +++++++++++++++----------------
         M ics2tsv                             |      32 ++++++++++++-------------------
         M tcal2tsv                            |      12 ++++++------
         M tsv2tcal                            |       4 ++--
       
       4 files changed, 36 insertions(+), 45 deletions(-)
       ---
 (DIR) diff --git a/README b/README
       @@ -1,7 +1,5 @@
       -ICS2TSV(1)                  General Commands Manual                 ICS2TSV(1)
       -
        NAME
       -     ics2tsv – convert ics file to simpler tsv or txt formats
       +     ics2txt – convert ics file to simpler tsv or txt formats
        
        SYNOPSIS
             ics2txt <file.ics >file.txt
       @@ -13,31 +11,34 @@ SYNOPSIS
             tsv2ics <file.tsv >file.ics
        
        DESCRIPTION
       -     ics2tsv is set of awk scripts to deal with iCal (.ics) format to publish,
       +     ics2txt is set of awk scripts to deal with iCal (.ics) format to publish,
             display and convert *.ics files, though a simple central TSV format.
        
             They all read from either stdin or the file passed as argument, and write
             to stdout.
        
       -     file.tsv files have one line per event, all with the following fields,
       -     separated by one tab:
       -      1. Begining (epoch)
       -      2. End (epoch)
       -      3. Category
       -      4. Location
       -      5. Summary
       -      6. Description
       +     file.tsv have one line per event, with the first line declaring fields
       +     order and presence, among:
       +      “beg”  Begining of event (epoch)
       +      “end”  End of event (epoch)
       +      “cat”  Category
       +      “loc”  Location
       +      “sum”  Summary
       +      “des”  Description
        
        EXAMPLES
       -     Convert a calendar from HTTP .ics to custom .txt sorted by beginning
       -     date:
       +     Convert a calendar from HTTP .ics to custom .txt sorted by start date:
                   curl $url.ics | ics2tsv | sort -n -k 1,1 | tsv2txt
        
             Convert a custom .txt format back to an .ics file and publish it:
                   tcal2tsv cal.txt | tsv2ics | ssh www@$host 'cat >/var/www/cal.ics'
        
             Split an file according to the category, saved as .tsv:
       -           tcal2tsv cal.txt | awk -F '\t' '{ f = $3".tsv"; print >>f }'
       +
       +     ics2tsv cal.txt | awk -F '\t' '
       +             NR == 1 { for (i = 1; i <= NF; i++) F[$i] = i; next }
       +             { print >>($F["cat"]".tsv") }
       +     ´
        
        SEE ALSO
             cal(1), calendar(1), date(1), sort(1)
       @@ -48,5 +49,3 @@ STANDARDS
        
        AUTHORS
             Josuah Demangeon <me@josuah.net>
       -
       -OpenBSD 6.6                      March 1, 2020                     OpenBSD 6.6
 (DIR) diff --git a/ics2tsv b/ics2tsv
       @@ -44,49 +44,41 @@ function ical_to_epoch(str, offset,
        function print_event(ev, fields,
                i)
        {
       -        for (i = 1; i <= fields["len"]; i++)
       +        for (i = 1; i in fields; 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, " ")
       +        split(FIELDS, fields, " ")
        
                # by default: "CATEGORIES" -> "cat", "LOCATION" -> "loc"...
                translate["DTSTART"] = "beg"
                translate["DTEND"] = "end"
        
       -        "date +%z" | getline offset_str
       +        "date +%z" | getline
                close("date +%z")
       -        hour = substr($0, 4, 2)
       -        min = substr($0, 6, 2)
       -        tzoffset = substr(zone, 3, 1) hour * 3600 + min * 60
       +        TZ = substr($0, 3, 1) substr($0, 4, 2)*3600 + substr($0, 6, 2)*60
        
                FS = "[:;]"
        
       -        for (i = 1; i <= fields["len"]; i++) {
       +        for (i = 1; i in fields; i++) {
                        if (!(s = translate[fields[i]]))
                                s = tolower(substr(fields[i], 1, 3))
                        printf("%s%s", (i > 1 ? "\t" : ""), s)
                }
       -
                printf("\n")
        }
        
       +/^ / {
       +        ev[type] = ev[type] substr($0, 2, length($0) - 1)
       +        next
       +}
       +
        {
       -        gsub("\r", "")
       -        gsub("\t", "\\\\t")
       -        gsub("^ *", "")
       -        gsub(" *$", "")
       -
       -        if (match($0, "^ ")) {
       -                ev[type] = ev[type] substr($0, 2, length($0) - 1)
       -        } else {
       -                type = $1
       -                i = index($0, ":")
       -                ev[type] = substr($0, i + 1, length($0) - i)
       -        }
       +        i = index($0, ":")
       +        ev[$1] = substr($0, i + 1, length($0) - i)
        }
        
        /^END:VEVENT/ {
 (DIR) diff --git a/tcal2tsv b/tcal2tsv
       @@ -42,9 +42,9 @@ function text_to_epoch(str, tz,
        
        BEGIN {
                FIELDS = "beg end cat loc sum des"
       -        fields["len"] = split(FIELDS, fields, " ")
       +        split(FIELDS, fields, " ")
        
       -        for (i = 1; i <= fields["len"]; i++) {
       +        for (i = 1; i in fields; i++) {
                        pos[fields[i]] = i
                        printf("%s%s", (i > 1 ? "\t" : ""), fields[i])
                }
       @@ -56,16 +56,16 @@ BEGIN {
        }
        
        /^TZ[+-]/ {
       -        TZOFFSET = substr($1, 3, 1) substr($0, 4, 2)*3600 + substr($0, 6, 2)*60
       +        TZ = substr($1, 3, 1) substr($0, 4, 2)*3600 + substr($0, 6, 2)*60
                while (getline && $0 ~ /^$/)
                        continue
        }
        
        /^[0-9]+-[0-9]+-[0-9]+/ {
                if ("beg" in ev)
       -                ev["end"] = text_to_epoch($0, TZOFFSET)
       +                ev["end"] = text_to_epoch($0, TZ)
                else
       -                ev["beg"] = text_to_epoch($0, TZOFFSET)
       +                ev["beg"] = text_to_epoch($0, TZ)
                next
        }
        
       @@ -78,7 +78,7 @@ BEGIN {
        }
        
        /^$/ {
       -        for (i = 1; i <= fields["len"]; i++)
       +        for (i = 1; i in fields; i++)
                        printf("%s%s", (i > 1 ? "\t" : ""), ev[fields[i]])
                printf("\n")
                delete ev
 (DIR) diff --git a/tsv2tcal b/tsv2tcal
       @@ -43,13 +43,13 @@ function gmtime(sec, tm)
        function localtime(sec, tm,
                tz, h, m)
        {
       -        return gmtime(sec + TZOFFSET, tm)
       +        return gmtime(sec + TZ, tm)
        }
        
        BEGIN {
                "date +%z" | getline tz
                close("date +%z")
       -        TZOFFSET = substr(tz, 1, 1) substr(tz, 2, 2)*3600 + substr(tz, 4, 2)*60
       +        TZ = substr(tz, 1, 1) substr(tz, 2, 2)*3600 + substr(tz, 4, 2)*60
        
                print("TZ" tz)