tics2tsv - 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
---
tics2tsv (2949B)
---
1 #!/usr/bin/awk -f
2
3 function isleap(year)
4 {
5 return (year % 4 == 0) && (year % 100 != 0) || (year % 400 == 0)
6 }
7
8 function mdays(mon, year)
9 {
10 return (mon == 2) ? (28 + isleap(year)) : (30 + (mon + (mon > 7)) % 2)
11 }
12
13 function timegm(tm,
14 sec, mon, day)
15 {
16 sec = tm["sec"] + tm["min"] * 60 + tm["hour"] * 3600
17
18 day = tm["mday"] - 1
19
20 for (mon = tm["mon"] - 1; mon > 0; mon--)
21 day = day + mdays(mon, tm["year"])
22
23 # constants: x * 365 + x / 400 - x / 100 + x / 4
24 day = day + int(tm["year"] / 400) * 146097
25 day = day + int(tm["year"] % 400 / 100) * 36524
26 day = day + int(tm["year"] % 100 / 4) * 1461
27 day = day + int(tm["year"] % 4 / 1) * 365
28
29 return sec + (day - 719527) * 86400
30 }
31
32 function print_vevent(ev, fields,
33 i)
34 {
35 for (i = 1; i in fields; i++)
36 printf("%s%s", (i > 1 ? "\t" : ""), ev[fields[i]])
37 printf("\n")
38 }
39
40 function ical_parse_line(str, content, params,
41 i, eq)
42 {
43 if ((i = index(str, ":")) == 0)
44 return -1
45 content["value"] = substr(str, i + 1)
46 str = substr(str, 1, i - 1)
47
48 if ((i = index(str, ";")) == 0) {
49 content["name"] = str
50 return 0
51 }
52 content["name"] = substr(str, 1, i - 1)
53 str = substr(str, i + 1)
54
55 while ((i = index(str, ";")) > 0) {
56 if ((eq = index(str, "=")) == 0)
57 return -1
58 param[substr(str, 1, eq - 1)] = substr(str, eq + 1, i - 1)
59 str = substr(str, eq + 1)
60 }
61 if ((eq = index(str, "=")) == 0)
62 return -1
63 params[substr(str, 1, eq - 1)] = substr(str, eq + 1)
64 return 0
65 }
66
67 function ical_set_tz(tzid)
68 {
69 gsub("'", "", tzid)
70 cmd = "TZ='" tzid "' exec date +%z"
71 cmd | getline tzid
72 close(cmd)
73 TZ = substr(tzid, 1, 1) substr(tzid, 2, 2)*3600 + substr(tzid, 4, 2)*60
74 }
75
76 function ical_to_epoch(content, param,
77 tz, cmd)
78 {
79 if (param["TZID"])
80 ical_set_tz(param["TZID"])
81
82 tm["year"] = substr(content["value"], 1, 4)
83 tm["mon"] = substr(content["value"], 5, 2)
84 tm["mday"] = substr(content["value"], 7, 2)
85 tm["hour"] = substr(content["value"], 10, 2)
86 tm["min"] = substr(content["value"], 12, 2)
87 tm["sec"] = substr(content["value"], 14, 2)
88
89 return timegm(tm) + TZ
90 }
91
92 BEGIN {
93 split("DTSTART DTEND CATEGORIES LOCATION SUMMARY DESCRIPTION URL",
94 FIELDS, " ")
95 DT["DTSTART"] = DT["DTEND"] = DT["DUE"] = 1
96
97 # by default: "CATEGORIES" -> "cat", "LOCATION" -> "loc"...
98 translate["DTSTART"] = "beg"
99 translate["DTEND"] = "end"
100
101 for (i = 1; i in FIELDS; i++) {
102 if (!(s = translate[FIELDS[i]]))
103 s = tolower(substr(FIELDS[i], 1, 3))
104 printf("%s%s", (i > 1 ? "\t" : ""), s)
105 }
106 printf("\n")
107
108 FS = "[:;]"
109 }
110
111 {
112 gsub("\r", "")
113 gsub("\t", "\\\\t")
114 }
115
116 sub("^ ", "") {
117 content["value"] = content["value"] $0
118 next
119 }
120
121 {
122 delete content
123 delete param
124
125 if (ical_parse_line($0, content, params) < 0)
126 next
127
128 if (content["name"] == "TZID") {
129 ical_set_tz(content["value"])
130 } else if (DT[content["name"]]) {
131 vevent[content["name"]] = ical_to_epoch(content, params)
132 } else {
133 vevent[content["name"]] = content["value"]
134 }
135 }
136
137 /^END:VEVENT/ {
138 print_vevent(vevent, FIELDS)
139 delete vevent
140 next
141 }