tics2tsv - ics2txt - convert icalendar .ics file to plain text HTML 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 }